fix views

This commit is contained in:
anlicheng 2025-08-05 14:06:35 +08:00
parent ed45954127
commit 1e74de12aa
10 changed files with 332 additions and 96 deletions

View File

@ -0,0 +1,75 @@
//
// NetworkInterface.swift
// punchnet
//
// Created by on 2025/8/3.
//
//
// NetworkInterface.swift
// Tun
//
// Created by on 2024/1/19.
//
import Foundation
public struct NetworkInterface {
public let name: String
public let ip: String
public let netmask: String
}
public struct NetworkInterfaceManager {
/**
, (let name: String let ip: String let netmask: String)
*/
public static func getInterfaces() -> [NetworkInterface] {
var interfaces: [NetworkInterface] = []
// Get list of all interfaces on the local machine:
var ifaddr : UnsafeMutablePointer<ifaddrs>? = nil
if getifaddrs(&ifaddr) == 0 {
// For each interface ...
var ptr = ifaddr
while( ptr != nil) {
let flags = Int32(ptr!.pointee.ifa_flags)
var addr = ptr!.pointee.ifa_addr.pointee
// Check for running IPv4, IPv6 interfaces. Skip the loopback interface.
if (flags & (IFF_UP|IFF_RUNNING|IFF_LOOPBACK)) == (IFF_UP|IFF_RUNNING) {
if addr.sa_family == UInt8(AF_INET) || addr.sa_family == UInt8(AF_INET6) {
var mask = ptr!.pointee.ifa_netmask.pointee
// Convert interface address to a human readable string:
let zero = CChar(0)
var hostname = [CChar](repeating: zero, count: Int(NI_MAXHOST))
var netmask = [CChar](repeating: zero, count: Int(NI_MAXHOST))
if (getnameinfo(&addr, socklen_t(addr.sa_len), &hostname, socklen_t(hostname.count),
nil, socklen_t(0), NI_NUMERICHOST) == 0) {
let address = String(cString: hostname)
let name = ptr!.pointee.ifa_name!
let ifname = String(cString: name)
if (getnameinfo(&mask, socklen_t(mask.sa_len), &netmask, socklen_t(netmask.count), nil, socklen_t(0), NI_NUMERICHOST) == 0) {
let netmaskIP = String(cString: netmask)
interfaces.append(NetworkInterface(name: ifname, ip: address, netmask: netmaskIP))
}
}
}
}
ptr = ptr!.pointee.ifa_next
}
freeifaddrs(ifaddr)
}
return interfaces
}
}

View File

@ -0,0 +1,164 @@
//
// PacketTunnelProvider.swift
// punchnet
//
// Created by on 2025/8/3.
//
//
// PacketTunnelProvider.swift
// Tun
//
// Created by on 2024/1/17.
//
import NetworkExtension
import Punchnet
class PacketTunnelProvider: NEPacketTunnelProvider {
var context: SDLContext?
override func startTunnel(options: [String : NSObject]?, completionHandler: @escaping (Error?) -> Void) {
// host: "192.168.0.101", port: 1265
guard let options else {
return
}
//
guard self.context == nil else {
return
}
// let token = options["token"] as! String
let installed_channel = options["installed_channel"] as! String
let superIp = options["super_ip"] as! String
let superPort = options["super_port"] as! Int
let stunServersStr = options["stun_servers"] as! String
let stunServers = stunServersStr.split(separator: ";").compactMap { server -> SDLConfiguration.StunServer? in
let parts = server.split(separator: ":", maxSplits: 2)
guard parts.count == 2 else {
return nil
}
let ports = parts[1].split(separator: ",", maxSplits: 2)
guard ports.count == 2, let port1 = Int(String(ports[0])), let port2 = Int(String(ports[1])) else {
return nil
}
return .init(host: String(parts[0]), ports: [port1, port2])
}
guard stunServers.count >= 2 else {
NSLog("stunServers配置错误")
return
}
let config = SDLConfiguration(version: 1,
installedChannel: installed_channel,
superHost: superIp,
superPort: superPort,
stunServers: stunServers,
clientId: SDLContext.getUUID(),
token: "")
//
let rsaCipher = try! CCRSACipher(keySize: 1024)
let aesChiper = CCAESChiper()
Task {
do {
self.context = SDLContext(provider: self, config: config, rsaCipher: rsaCipher, aesCipher: aesChiper, logger: SDLLogger(level: .warning))
try await self.context?.start()
completionHandler(nil)
} catch let err {
completionHandler(err)
}
}
}
override func stopTunnel(with reason: NEProviderStopReason, completionHandler: @escaping () -> Void) {
// Add code here to start the process of stopping the tunnel.
Task {
await self.context?.stop()
self.context = nil
}
completionHandler()
}
override func handleAppMessage(_ messageData: Data, completionHandler: ((Data?) -> Void)?) {
// Add code here to handle the message.
if let handler = completionHandler {
handler(messageData)
}
}
override func sleep(completionHandler: @escaping () -> Void) {
// Add code here to get ready to sleep.
completionHandler()
}
override func wake() {
// Add code here to wake up.
}
}
// ip
extension PacketTunnelProvider {
public static var viaInterface: NetworkInterface? = {
let interfaces = NetworkInterfaceManager.getInterfaces()
return interfaces.first {$0.name == "en0"}
}()
struct CCRSACipher: RSACipher {
var pubKey: String
let privateKeyDER: Data
init(keySize: Int) throws {
let (privateKey, publicKey) = try Self.loadKeys(keySize: keySize)
let privKeyStr = SwKeyConvert.PrivateKey.derToPKCS1PEM(privateKey)
self.pubKey = SwKeyConvert.PublicKey.derToPKCS8PEM(publicKey)
self.privateKeyDER = try SwKeyConvert.PrivateKey.pemToPKCS1DER(privKeyStr)
}
public func decode(data: Data) throws -> Data {
let tag = Data()
let (decryptedData, _) = try CC.RSA.decrypt(data, derKey: self.privateKeyDER, tag: tag, padding: .pkcs1, digest: .none)
return decryptedData
}
private static func loadKeys(keySize: Int) throws -> (Data, Data) {
if let privateKey = UserDefaults.standard.data(forKey: "privateKey"),
let publicKey = UserDefaults.standard.data(forKey: "publicKey") {
return (privateKey, publicKey)
} else {
let (privateKey, publicKey) = try CC.RSA.generateKeyPair(keySize)
UserDefaults.standard.setValue(privateKey, forKey: "privateKey")
UserDefaults.standard.setValue(publicKey, forKey: "publicKey")
return (privateKey, publicKey)
}
}
}
struct CCAESChiper: AESCipher {
func decypt(aesKey: Data, data: Data) throws -> Data {
let ivData = Data(aesKey.prefix(16))
return try CC.crypt(.decrypt, blockMode: .cbc, algorithm: .aes, padding: .pkcs7Padding, data: data, key: aesKey, iv: ivData)
}
func encrypt(aesKey: Data, data: Data) throws -> Data {
let ivData = Data(aesKey.prefix(16))
return try CC.crypt(.encrypt, blockMode: .cbc, algorithm: .aes, padding: .pkcs7Padding, data: data, key: aesKey, iv: ivData)
}
}
}

View File

@ -7,6 +7,7 @@
objects = {
/* Begin PBXBuildFile section */
C82EA7472E3FAA5A00DA5B3C /* Punchnet in Frameworks */ = {isa = PBXBuildFile; productRef = C82EA7462E3FAA5A00DA5B3C /* Punchnet */; };
C8A77F2A2DD1E77B00195617 /* NetworkExtension.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C8A77F292DD1E77B00195617 /* NetworkExtension.framework */; };
C8A77F322DD1E77B00195617 /* Tun.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = C8A77F272DD1E77B00195617 /* Tun.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
C8A77F792DD1E93900195617 /* NIO in Frameworks */ = {isa = PBXBuildFile; productRef = C8A77F782DD1E93900195617 /* NIO */; };
@ -14,8 +15,6 @@
C8A77F7D2DD1E93900195617 /* NIOCore in Frameworks */ = {isa = PBXBuildFile; productRef = C8A77F7C2DD1E93900195617 /* NIOCore */; };
C8A77F7F2DD1E93900195617 /* NIOEmbedded in Frameworks */ = {isa = PBXBuildFile; productRef = C8A77F7E2DD1E93900195617 /* NIOEmbedded */; };
C8A77F812DD1E93900195617 /* NIOFoundationCompat in Frameworks */ = {isa = PBXBuildFile; productRef = C8A77F802DD1E93900195617 /* NIOFoundationCompat */; };
C8A77F832DD1E98B00195617 /* NIO in Frameworks */ = {isa = PBXBuildFile; productRef = C8A77F822DD1E98B00195617 /* NIO */; };
C8A77F852DD1E99300195617 /* NIOCore in Frameworks */ = {isa = PBXBuildFile; productRef = C8A77F842DD1E99300195617 /* NIOCore */; };
C8A77F882DD1EA0200195617 /* SwiftProtobuf in Frameworks */ = {isa = PBXBuildFile; productRef = C8A77F872DD1EA0200195617 /* SwiftProtobuf */; };
C8A77F8A2DD1EA0200195617 /* SwiftProtobufPluginLibrary in Frameworks */ = {isa = PBXBuildFile; productRef = C8A77F892DD1EA0200195617 /* SwiftProtobufPluginLibrary */; };
/* End PBXBuildFile section */
@ -143,10 +142,9 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
C8A77F852DD1E99300195617 /* NIOCore in Frameworks */,
C8A77F2A2DD1E77B00195617 /* NetworkExtension.framework in Frameworks */,
C8A77F8A2DD1EA0200195617 /* SwiftProtobufPluginLibrary in Frameworks */,
C8A77F832DD1E98B00195617 /* NIO in Frameworks */,
C82EA7472E3FAA5A00DA5B3C /* Punchnet in Frameworks */,
C8A77F882DD1EA0200195617 /* SwiftProtobuf in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
@ -280,10 +278,9 @@
);
name = Tun;
packageProductDependencies = (
C8A77F822DD1E98B00195617 /* NIO */,
C8A77F842DD1E99300195617 /* NIOCore */,
C8A77F872DD1EA0200195617 /* SwiftProtobuf */,
C8A77F892DD1EA0200195617 /* SwiftProtobufPluginLibrary */,
C82EA7462E3FAA5A00DA5B3C /* Punchnet */,
);
productName = Tun;
productReference = C8A77F272DD1E77B00195617 /* Tun.appex */;
@ -325,8 +322,7 @@
mainGroup = C8A77EEA2DD1E6D000195617;
minimizedProjectReferenceProxies = 1;
packageReferences = (
C8A77F772DD1E93900195617 /* XCLocalSwiftPackageReference "../../packages/swift-nio" */,
C8A77F862DD1EA0200195617 /* XCLocalSwiftPackageReference "../../packages/swift-protobuf" */,
C82EA7452E3FAA5A00DA5B3C /* XCRemoteSwiftPackageReference "swiftlib_sdlan" */,
);
preferredProjectObjectVersion = 77;
productRefGroup = C8A77EF42DD1E6D000195617 /* Products */;
@ -475,7 +471,7 @@
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
MACOSX_DEPLOYMENT_TARGET = 15.2;
MACOSX_DEPLOYMENT_TARGET = 14.6;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
ONLY_ACTIVE_ARCH = YES;
@ -532,7 +528,7 @@
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
MACOSX_DEPLOYMENT_TARGET = 15.2;
MACOSX_DEPLOYMENT_TARGET = 14.6;
MTL_ENABLE_DEBUG_INFO = NO;
MTL_FAST_MATH = YES;
SDKROOT = macosx;
@ -561,7 +557,7 @@
"$(inherited)",
"@executable_path/../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 14.0;
MACOSX_DEPLOYMENT_TARGET = 14.6;
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.jihe.punchnet;
PRODUCT_NAME = "$(TARGET_NAME)";
@ -593,7 +589,7 @@
"$(inherited)",
"@executable_path/../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 14.0;
MACOSX_DEPLOYMENT_TARGET = 14.6;
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.jihe.punchnet;
PRODUCT_NAME = "$(TARGET_NAME)";
@ -612,7 +608,7 @@
CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_TEAM = PF3QG837XS;
GENERATE_INFOPLIST_FILE = YES;
MACOSX_DEPLOYMENT_TARGET = 14.0;
MACOSX_DEPLOYMENT_TARGET = 14.6;
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.jihe.punchnetTests;
PRODUCT_NAME = "$(TARGET_NAME)";
@ -630,7 +626,7 @@
CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_TEAM = PF3QG837XS;
GENERATE_INFOPLIST_FILE = YES;
MACOSX_DEPLOYMENT_TARGET = 14.0;
MACOSX_DEPLOYMENT_TARGET = 14.6;
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.jihe.punchnetTests;
PRODUCT_NAME = "$(TARGET_NAME)";
@ -647,6 +643,7 @@
CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_TEAM = PF3QG837XS;
GENERATE_INFOPLIST_FILE = YES;
MACOSX_DEPLOYMENT_TARGET = 14.6;
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.jihe.punchnetUITests;
PRODUCT_NAME = "$(TARGET_NAME)";
@ -663,6 +660,7 @@
CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_TEAM = PF3QG837XS;
GENERATE_INFOPLIST_FILE = YES;
MACOSX_DEPLOYMENT_TARGET = 14.6;
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.jihe.punchnetUITests;
PRODUCT_NAME = "$(TARGET_NAME)";
@ -691,6 +689,7 @@
"@executable_path/../Frameworks",
"@executable_path/../../../../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 14.6;
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.jihe.punchnet.tun;
PRODUCT_NAME = "$(TARGET_NAME)";
@ -721,6 +720,7 @@
"@executable_path/../Frameworks",
"@executable_path/../../../../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 14.6;
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.jihe.punchnet.tun;
PRODUCT_NAME = "$(TARGET_NAME)";
@ -782,18 +782,23 @@
};
/* End XCConfigurationList section */
/* Begin XCLocalSwiftPackageReference section */
C8A77F772DD1E93900195617 /* XCLocalSwiftPackageReference "../../packages/swift-nio" */ = {
isa = XCLocalSwiftPackageReference;
relativePath = "../../packages/swift-nio";
/* Begin XCRemoteSwiftPackageReference section */
C82EA7452E3FAA5A00DA5B3C /* XCRemoteSwiftPackageReference "swiftlib_sdlan" */ = {
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://gitea.s5s8.com/anlicheng/swiftlib_sdlan.git";
requirement = {
kind = exactVersion;
version = 2.2.0;
};
};
C8A77F862DD1EA0200195617 /* XCLocalSwiftPackageReference "../../packages/swift-protobuf" */ = {
isa = XCLocalSwiftPackageReference;
relativePath = "../../packages/swift-protobuf";
};
/* End XCLocalSwiftPackageReference section */
/* End XCRemoteSwiftPackageReference section */
/* Begin XCSwiftPackageProductDependency section */
C82EA7462E3FAA5A00DA5B3C /* Punchnet */ = {
isa = XCSwiftPackageProductDependency;
package = C82EA7452E3FAA5A00DA5B3C /* XCRemoteSwiftPackageReference "swiftlib_sdlan" */;
productName = Punchnet;
};
C8A77F782DD1E93900195617 /* NIO */ = {
isa = XCSwiftPackageProductDependency;
productName = NIO;
@ -814,16 +819,6 @@
isa = XCSwiftPackageProductDependency;
productName = NIOFoundationCompat;
};
C8A77F822DD1E98B00195617 /* NIO */ = {
isa = XCSwiftPackageProductDependency;
package = C8A77F772DD1E93900195617 /* XCLocalSwiftPackageReference "../../packages/swift-nio" */;
productName = NIO;
};
C8A77F842DD1E99300195617 /* NIOCore */ = {
isa = XCSwiftPackageProductDependency;
package = C8A77F772DD1E93900195617 /* XCLocalSwiftPackageReference "../../packages/swift-nio" */;
productName = NIOCore;
};
C8A77F872DD1EA0200195617 /* SwiftProtobuf */ = {
isa = XCSwiftPackageProductDependency;
productName = SwiftProtobuf;

View File

@ -1,13 +1,13 @@
{
"originHash" : "fc5ff56467a09054cad310ea04e2207caefea4e4c42012fbd995ed64d089417b",
"originHash" : "2c771b2bd4bccdc5777d69cc734485452a1e854c0123ba591d596b3f580f4cb8",
"pins" : [
{
"identity" : "swift-atomics",
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-atomics.git",
"state" : {
"revision" : "cd142fd2f64be2100422d658e7411e39489da985",
"version" : "1.2.0"
"revision" : "b601256eab081c0f92f059e12818ac1d4f178ff7",
"version" : "1.3.0"
}
},
{
@ -15,8 +15,26 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-collections.git",
"state" : {
"revision" : "671108c96644956dddcd89dd59c203dcdb36cec7",
"version" : "1.1.4"
"revision" : "8c0c0a8b49e080e54e5e328cc552821ff07cd341",
"version" : "1.2.1"
}
},
{
"identity" : "swift-nio",
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-nio.git",
"state" : {
"revision" : "a5fea865badcb1c993c85b0f0e8d05a4bd2270fb",
"version" : "2.85.0"
}
},
{
"identity" : "swift-protobuf",
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-protobuf.git",
"state" : {
"revision" : "102a647b573f60f73afdce5613a51d71349fe507",
"version" : "1.30.0"
}
},
{
@ -24,8 +42,17 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-system.git",
"state" : {
"revision" : "a34201439c74b53f0fd71ef11741af7e7caf01e1",
"version" : "1.4.2"
"revision" : "b63d24d465e237966c3f59f47dcac6c70fb0bca3",
"version" : "1.6.1"
}
},
{
"identity" : "swiftlib_sdlan",
"kind" : "remoteSourceControl",
"location" : "https://gitea.s5s8.com/anlicheng/swiftlib_sdlan.git",
"state" : {
"revision" : "2c05d71dbe3684e51e9de55910619156ebe360c6",
"version" : "2.2.0"
}
}
],

View File

@ -1,30 +0,0 @@
//
// Config.swift
// punchnet
//
// Created by on 2025/5/14.
//
import Foundation
enum PunchnetError: Error {
case dnsUnreachable
}
struct PunchnetConfig {
static let server = "punchnet.aioe.tech"
static let port = 18083
static func getOptions() throws -> [String:NSObject] {
var options: [String: NSObject] = [:]
if let ip = DNSResolver.resolveAddrInfos(PunchnetConfig.server).first {
options["super_ip"] = ip as NSObject
} else {
throw PunchnetError.dnsUnreachable
}
return options
}
}

View File

@ -15,4 +15,29 @@ struct SystemConfig {
//
static let installedChannel = "MacAppStore"
// super
//static let superHost = "118.178.229.213"
static let superHost = "punchnet.aioe.tech"
static let superPort = 18083
// stun
static let stunServers = "118.178.229.213:1265,1266;118.178.229.213:1265,1266"
static func getOptions(token: String) -> [String:NSObject]? {
guard let superIp = DNSResolver.resolveAddrInfos(superHost).first else {
return nil
}
return [
"version:": version as NSObject,
"installed_channel": installedChannel as NSObject,
"token": token as NSObject,
"super_ip": superIp as NSObject,
"super_port": superPort as NSObject,
"stun_servers": stunServers as NSObject
]
}
}

View File

@ -32,10 +32,7 @@ class VPNManager: ObservableObject {
try await manager.loadFromPreferences()
self.addVPNStatusObserver(manager)
var configOptions = try PunchnetConfig.getOptions()
configOptions.merge(options, uniquingKeysWith: {$1})
try manager.connection.startVPNTunnel(options: configOptions)
try manager.connection.startVPNTunnel(options: options)
}
// vpn

View File

@ -9,7 +9,6 @@ import Foundation
import SwiftUI
struct AbortView: View {
struct AlertShow: Identifiable {
enum ShowContent {
case error(String)

View File

@ -9,8 +9,7 @@ import SwiftUI
import SwiftData
import Combine
struct ContentView: View {
struct IndexView: View {
@AppStorage("token") private var token: String = ""
@State private var showToken: Bool = false
@ -191,24 +190,13 @@ struct ContentView: View {
case .connected:
try await vpnManager.disableVpn()
case .disconnected:
/*
if self.token.isEmpty {
self.showAlert = true
return
}
*/
//print("use port: \(vpnManager.noticePort as NSObject)")
try await vpnManager.enableVpn(options: [
"version:": SystemConfig.version as NSObject,
"installed_channel": SystemConfig.installedChannel as NSObject,
"token": self.token as NSObject
])
try await vpnManager.enableVpn(options: SystemConfig.getOptions(token: self.token)!)
}
}
}
#Preview {
ContentView()
IndexView()
//.modelContainer(for: Item.self, inMemory: true)
}

View File

@ -35,7 +35,7 @@ struct punchnetApp: App {
var body: some Scene {
WindowGroup(id: "mainWindow") {
ContentView()
IndexView()
.frame(minWidth: 300, maxWidth: 300, minHeight: 500, maxHeight: 500)
.onAppear {
//
@ -94,11 +94,7 @@ struct punchnetApp: App {
switch self.vpnManager.vpnStatus {
case .disconnected:
Task {
try await vpnManager.enableVpn(options: [
"version:": SystemConfig.version as NSObject,
"installed_channel": SystemConfig.installedChannel as NSObject,
"token": token as NSObject
])
try await vpnManager.enableVpn(options: SystemConfig.getOptions(token: self.token)!)
}
case .connected:
Task {