diff options
Diffstat (limited to '')
-rw-r--r-- | WireGuard/WireGuardNetworkExtension/PacketTunnelProvider.swift | 143 |
1 files changed, 74 insertions, 69 deletions
diff --git a/WireGuard/WireGuardNetworkExtension/PacketTunnelProvider.swift b/WireGuard/WireGuardNetworkExtension/PacketTunnelProvider.swift index 1480abc..c5ad766 100644 --- a/WireGuard/WireGuardNetworkExtension/PacketTunnelProvider.swift +++ b/WireGuard/WireGuardNetworkExtension/PacketTunnelProvider.swift @@ -6,7 +6,9 @@ import NetworkExtension import os.log enum PacketTunnelProviderError: Error { - case tunnelSetupFailed + case invalidOptions + case couldNotStartWireGuard + case coultNotSetNetworkSettings } /// A packet tunnel provider object. @@ -17,81 +19,100 @@ class PacketTunnelProvider: NEPacketTunnelProvider { private var wgHandle: Int32? private var wgContext: WireGuardContext? - private var config: NETunnelProviderProtocol { - return self.protocolConfiguration as! NETunnelProviderProtocol // swiftlint:disable:this force_cast - } - - private var interfaceName: String { - return config.providerConfiguration![PCKeys.title.rawValue]! as! String // swiftlint:disable:this force_cast - } - - private var settings: String { - return config.providerConfiguration![PCKeys.settings.rawValue]! as! String // swiftlint:disable:this force_cast - } - // MARK: NEPacketTunnelProvider /// Begin the process of establishing the tunnel. - override func startTunnel(options: [String: NSObject]?, completionHandler startTunnelCompletionHandler: @escaping (Error?) -> Void) { - os_log("Starting tunnel", log: Log.general, type: .info) - - let validatedEndpoints = (config.providerConfiguration?[PCKeys.endpoints.rawValue] as? String ?? "").commaSeparatedToArray().compactMap { try? Endpoint(endpointString: String($0)) }.compactMap {$0} - let validatedAddresses = (config.providerConfiguration?[PCKeys.addresses.rawValue] as? String ?? "").commaSeparatedToArray().compactMap { try? CIDRAddress(stringRepresentation: String($0)) }.compactMap { $0 } + override func startTunnel(options: [String: NSObject]?, + completionHandler startTunnelCompletionHandler: @escaping (Error?) -> Void) { + os_log("Starting tunnel", log: OSLog.default, type: .info) - guard let firstEndpoint = validatedEndpoints.first else { - startTunnelCompletionHandler(PacketTunnelProviderError.tunnelSetupFailed) + guard let options = options else { + startTunnelCompletionHandler(PacketTunnelProviderError.invalidOptions) return } + guard let interfaceName = options[.interfaceName] as? String, + let wireguardSettings = options[.wireguardSettings] as? String, + let remoteAddress = options[.remoteAddress] as? String, + let dnsServers = options[.dnsServers] as? [String], + let mtu = options[.mtu] as? NSNumber, + + // IPv4 settings + let ipv4Addresses = options[.ipv4Addresses] as? [String], + let ipv4SubnetMasks = options[.ipv4SubnetMasks] as? [String], + let ipv4IncludedRouteAddresses = options[.ipv4IncludedRouteAddresses] as? [String], + let ipv4IncludedRouteSubnetMasks = options[.ipv4IncludedRouteSubnetMasks] as? [String], + let ipv4ExcludedRouteAddresses = options[.ipv4ExcludedRouteAddresses] as? [String], + let ipv4ExcludedRouteSubnetMasks = options[.ipv4ExcludedRouteSubnetMasks] as? [String], + + // IPv6 settings + let ipv6Addresses = options[.ipv6Addresses] as? [String], + let ipv6NetworkPrefixLengths = options[.ipv6NetworkPrefixLengths] as? [NSNumber], + let ipv6IncludedRouteAddresses = options[.ipv6IncludedRouteAddresses] as? [String], + let ipv6IncludedRouteNetworkPrefixLengths = options[.ipv6IncludedRouteNetworkPrefixLengths] as? [NSNumber], + let ipv6ExcludedRouteAddresses = options[.ipv6ExcludedRouteAddresses] as? [String], + let ipv6ExcludedRouteNetworkPrefixLengths = options[.ipv6ExcludedRouteNetworkPrefixLengths] as? [NSNumber] + + else { + startTunnelCompletionHandler(PacketTunnelProviderError.invalidOptions) + return + } + configureLogger() wgContext = WireGuardContext(packetFlow: self.packetFlow) - let handle = connect(interfaceName: interfaceName, settings: settings) + let handle = connect(interfaceName: interfaceName, settings: wireguardSettings, mtu: mtu.uint16Value) if handle < 0 { - startTunnelCompletionHandler(PacketTunnelProviderError.tunnelSetupFailed) + startTunnelCompletionHandler(PacketTunnelProviderError.couldNotStartWireGuard) return } wgHandle = handle - // We use the first endpoint for the ipAddress - let newSettings = NEPacketTunnelNetworkSettings(tunnelRemoteAddress: firstEndpoint.ipAddress) - newSettings.tunnelOverheadBytes = 80 + // Network settings + let networkSettings = NEPacketTunnelNetworkSettings(tunnelRemoteAddress: remoteAddress) // IPv4 settings - let validatedIPv4Addresses = validatedAddresses.filter { $0.addressType == .IPv4} - if validatedIPv4Addresses.count > 0 { - let ipv4Settings = NEIPv4Settings(addresses: validatedIPv4Addresses.map { $0.ipAddress }, subnetMasks: validatedIPv4Addresses.map { $0.subnetString }) - ipv4Settings.includedRoutes = [NEIPv4Route.default()] - ipv4Settings.excludedRoutes = validatedEndpoints.filter { $0.addressType == .IPv4}.map { - NEIPv4Route(destinationAddress: $0.ipAddress, subnetMask: "255.255.255.255")} - - newSettings.ipv4Settings = ipv4Settings + let ipv4Settings = NEIPv4Settings(addresses: ipv4Addresses, subnetMasks: ipv4SubnetMasks) + assert(ipv4IncludedRouteAddresses.count == ipv4IncludedRouteSubnetMasks.count) + ipv4Settings.includedRoutes = zip(ipv4IncludedRouteAddresses, ipv4IncludedRouteSubnetMasks).map { + NEIPv4Route(destinationAddress: $0.0, subnetMask: $0.1) + } + assert(ipv4ExcludedRouteAddresses.count == ipv4ExcludedRouteSubnetMasks.count) + ipv4Settings.excludedRoutes = zip(ipv4ExcludedRouteAddresses, ipv4ExcludedRouteSubnetMasks).map { + NEIPv4Route(destinationAddress: $0.0, subnetMask: $0.1) } + networkSettings.ipv4Settings = ipv4Settings // IPv6 settings - let validatedIPv6Addresses = validatedAddresses.filter { $0.addressType == .IPv6} - if validatedIPv6Addresses.count > 0 { - let ipv6Settings = NEIPv6Settings(addresses: validatedIPv6Addresses.map { $0.ipAddress }, networkPrefixLengths: validatedIPv6Addresses.map { NSNumber(value: $0.subnet) }) - ipv6Settings.includedRoutes = [NEIPv6Route.default()] - ipv6Settings.excludedRoutes = validatedEndpoints.filter { $0.addressType == .IPv6 }.map { NEIPv6Route(destinationAddress: $0.ipAddress, networkPrefixLength: 128) } - - newSettings.ipv6Settings = ipv6Settings + let ipv6Settings = NEIPv6Settings(addresses: ipv6Addresses, networkPrefixLengths: ipv6NetworkPrefixLengths) + assert(ipv6IncludedRouteAddresses.count == ipv6IncludedRouteNetworkPrefixLengths.count) + ipv6Settings.includedRoutes = zip(ipv6IncludedRouteAddresses, ipv6IncludedRouteNetworkPrefixLengths).map { + NEIPv6Route(destinationAddress: $0.0, networkPrefixLength: $0.1) } - - if let dns = config.providerConfiguration?[PCKeys.dns.rawValue] as? String { - newSettings.dnsSettings = NEDNSSettings(servers: dns.commaSeparatedToArray()) + assert(ipv6ExcludedRouteAddresses.count == ipv6ExcludedRouteNetworkPrefixLengths.count) + ipv6Settings.excludedRoutes = zip(ipv6ExcludedRouteAddresses, ipv6ExcludedRouteNetworkPrefixLengths).map { + NEIPv6Route(destinationAddress: $0.0, networkPrefixLength: $0.1) } - - if let mtu = config.providerConfiguration![PCKeys.mtu.rawValue] as? NSNumber, mtu.intValue > 0 { - newSettings.mtu = mtu + networkSettings.ipv6Settings = ipv6Settings + + // DNS + networkSettings.dnsSettings = NEDNSSettings(servers: dnsServers) + + // MTU + if (mtu == 0) { + // 0 imples automatic MTU, where we set overhead as 95 bytes, + // 80 for WireGuard and the 15 to make sure WireGuard's padding will work. + networkSettings.tunnelOverheadBytes = 95 + } else { + networkSettings.mtu = mtu } - setTunnelNetworkSettings(newSettings) { (error) in + setTunnelNetworkSettings(networkSettings) { (error) in if let error = error { - os_log("Error setting network settings: %s", log: Log.general, type: .error, error.localizedDescription) - startTunnelCompletionHandler(PacketTunnelProviderError.tunnelSetupFailed) + os_log("Error setting network settings: %s", log: OSLog.default, type: .error, error.localizedDescription) + startTunnelCompletionHandler(PacketTunnelProviderError.coultNotSetNetworkSettings) } else { startTunnelCompletionHandler(nil /* No errors */) } @@ -100,7 +121,7 @@ class PacketTunnelProvider: NEPacketTunnelProvider { /// Begin the process of stopping the tunnel. override func stopTunnel(with reason: NEProviderStopReason, completionHandler: @escaping () -> Void) { - os_log("Stopping tunnel", log: Log.general, type: .info) + os_log("Stopping tunnel", log: OSLog.default, type: .info) if let handle = wgHandle { wgTurnOff(handle) } @@ -108,22 +129,6 @@ class PacketTunnelProvider: NEPacketTunnelProvider { completionHandler() } - /// Handle IPC messages from the app. - override func handleAppMessage(_ messageData: Data, completionHandler: ((Data?) -> Void)?) { - let responseData: Data? - - let message = ExtensionMessage(messageData) - - switch message { - case ExtensionMessage.requestVersion: - responseData = (wgVersion().flatMap { String(cString: $0) } ?? "").data(using: .utf8) - default: - responseData = nil - } - - completionHandler?(responseData) - } - private func configureLogger() { wgSetLogger { (level, tagCStr, msgCStr) in let logType: OSLogType @@ -139,14 +144,14 @@ class PacketTunnelProvider: NEPacketTunnelProvider { } let tag = (tagCStr != nil) ? String(cString: tagCStr!) : "" let msg = (msgCStr != nil) ? String(cString: msgCStr!) : "" - os_log("wg log: %{public}s: %{public}s", log: Log.general, type: logType, tag, msg) + os_log("wg log: %{public}s: %{public}s", log: OSLog.default, type: logType, tag, msg) } } - private func connect(interfaceName: String, settings: String) -> Int32 { // swiftlint:disable:this cyclomatic_complexity + private func connect(interfaceName: String, settings: String, mtu: UInt16) -> Int32 { // swiftlint:disable:this cyclomatic_complexity return withStringsAsGoStrings(interfaceName, settings) { (nameGoStr, settingsGoStr) -> Int32 in return withUnsafeMutablePointer(to: &wgContext) { (wgCtxPtr) -> Int32 in - return wgTurnOn(nameGoStr, settingsGoStr, { (wgCtxPtr, buf, len) -> Int in + return wgTurnOn(nameGoStr, settingsGoStr, mtu, { (wgCtxPtr, buf, len) -> Int in autoreleasepool { // read_fn: Read from the TUN interface and pass it on to WireGuard guard let wgCtxPtr = wgCtxPtr else { return 0 } |