From af58bfcb00e7ebdd0c0f48d2f15df17ab3b2b8d7 Mon Sep 17 00:00:00 2001 From: Roopesh Chander Date: Thu, 8 Nov 2018 15:44:13 +0530 Subject: [PATCH] Move logic to extension: Refactor PacketTunnelOptionsGenerator into a PacketTunnelSettingsGenerator Signed-off-by: Roopesh Chander --- WireGuard/WireGuard.xcodeproj/project.pbxproj | 8 +- ...ft => PacketTunnelSettingsGenerator.swift} | 101 +++++++++++------- 2 files changed, 67 insertions(+), 42 deletions(-) rename WireGuard/WireGuardNetworkExtension/{PacketTunnelOptionsGenerator.swift => PacketTunnelSettingsGenerator.swift} (57%) diff --git a/WireGuard/WireGuard.xcodeproj/project.pbxproj b/WireGuard/WireGuard.xcodeproj/project.pbxproj index b45f089..8576fb1 100644 --- a/WireGuard/WireGuard.xcodeproj/project.pbxproj +++ b/WireGuard/WireGuard.xcodeproj/project.pbxproj @@ -42,7 +42,7 @@ 6FDEF8082187442100D8FBF6 /* WgQuickConfigFileWriter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6FDEF8072187442100D8FBF6 /* WgQuickConfigFileWriter.swift */; }; 6FF4AC1F211EC472002C96EB /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 6FF4AC1E211EC472002C96EB /* Assets.xcassets */; }; 6FF4AC22211EC472002C96EB /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 6FF4AC20211EC472002C96EB /* LaunchScreen.storyboard */; }; - 6FFA5D8921942F320001E2F7 /* PacketTunnelOptionsGenerator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F5D0C472183C6A3000F85AD /* PacketTunnelOptionsGenerator.swift */; }; + 6FFA5D8921942F320001E2F7 /* PacketTunnelSettingsGenerator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F5D0C472183C6A3000F85AD /* PacketTunnelSettingsGenerator.swift */; }; 6FFA5D8E2194370D0001E2F7 /* Configuration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F7774E72172020C006A79B3 /* Configuration.swift */; }; 6FFA5D8F2194370D0001E2F7 /* IPAddressRange.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F7774E9217229DB006A79B3 /* IPAddressRange.swift */; }; 6FFA5D902194370D0001E2F7 /* Endpoint.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F693A552179E556008551C1 /* Endpoint.swift */; }; @@ -91,7 +91,7 @@ 6F5D0C1F218352EF000F85AD /* WireGuardNetworkExtension.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = WireGuardNetworkExtension.entitlements; sourceTree = ""; }; 6F5D0C3421839E37000F85AD /* WireGuardNetworkExtension-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "WireGuardNetworkExtension-Bridging-Header.h"; sourceTree = ""; }; 6F5D0C442183BCDA000F85AD /* PacketTunnelOptionKey.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PacketTunnelOptionKey.swift; sourceTree = ""; }; - 6F5D0C472183C6A3000F85AD /* PacketTunnelOptionsGenerator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PacketTunnelOptionsGenerator.swift; sourceTree = ""; }; + 6F5D0C472183C6A3000F85AD /* PacketTunnelSettingsGenerator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PacketTunnelSettingsGenerator.swift; sourceTree = ""; }; 6F628C3C217F09E9003482A3 /* TunnelViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TunnelViewModel.swift; sourceTree = ""; }; 6F628C3E217F3413003482A3 /* DNSServer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DNSServer.swift; sourceTree = ""; }; 6F628C40217F47DB003482A3 /* TunnelDetailTableViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TunnelDetailTableViewController.swift; sourceTree = ""; }; @@ -156,7 +156,7 @@ isa = PBXGroup; children = ( 6F5D0C1C218352EF000F85AD /* PacketTunnelProvider.swift */, - 6F5D0C472183C6A3000F85AD /* PacketTunnelOptionsGenerator.swift */, + 6F5D0C472183C6A3000F85AD /* PacketTunnelSettingsGenerator.swift */, 6F5D0C1421832391000F85AD /* DNSResolver.swift */, 6F5D0C1E218352EF000F85AD /* Info.plist */, 6F5D0C1F218352EF000F85AD /* WireGuardNetworkExtension.entitlements */, @@ -497,7 +497,7 @@ 6FFA5D9321943BC90001E2F7 /* DNSResolver.swift in Sources */, 6FFA5D912194370D0001E2F7 /* DNSServer.swift in Sources */, 6F5D0C462183C0B4000F85AD /* PacketTunnelOptionKey.swift in Sources */, - 6FFA5D8921942F320001E2F7 /* PacketTunnelOptionsGenerator.swift in Sources */, + 6FFA5D8921942F320001E2F7 /* PacketTunnelSettingsGenerator.swift in Sources */, 6F5D0C1D218352EF000F85AD /* PacketTunnelProvider.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/WireGuard/WireGuardNetworkExtension/PacketTunnelOptionsGenerator.swift b/WireGuard/WireGuardNetworkExtension/PacketTunnelSettingsGenerator.swift similarity index 57% rename from WireGuard/WireGuardNetworkExtension/PacketTunnelOptionsGenerator.swift rename to WireGuard/WireGuardNetworkExtension/PacketTunnelSettingsGenerator.swift index 3eabde7..d26d802 100644 --- a/WireGuard/WireGuardNetworkExtension/PacketTunnelOptionsGenerator.swift +++ b/WireGuard/WireGuardNetworkExtension/PacketTunnelSettingsGenerator.swift @@ -3,29 +3,30 @@ import Foundation import Network +import NetworkExtension -class PacketTunnelOptionsGenerator { - static func generateOptions(from tc: TunnelConfiguration, - withResolvedEndpoints resolvedEndpoints: [Endpoint?]) -> [String: NSObject] { - var options: [String: NSObject] = [:] +class PacketTunnelSettingsGenerator { - // Interface name + let tunnelConfiguration: TunnelConfiguration + let resolvedEndpoints: [Endpoint?] - options[.interfaceName] = tc.interface.name as NSObject - - // WireGuard settings + init(tunnelConfiguration: TunnelConfiguration, resolvedEndpoints: [Endpoint?]) { + self.tunnelConfiguration = tunnelConfiguration + self.resolvedEndpoints = resolvedEndpoints + } + func generateWireGuardSettings() -> String { var wgSettings = "" - let privateKey = tc.interface.privateKey.hexEncodedString() + let privateKey = tunnelConfiguration.interface.privateKey.hexEncodedString() wgSettings.append("private_key=\(privateKey)\n") - if let listenPort = tc.interface.listenPort { + if let listenPort = tunnelConfiguration.interface.listenPort { wgSettings.append("listen_port=\(listenPort)\n") } - if (tc.peers.count > 0) { + if (tunnelConfiguration.peers.count > 0) { wgSettings.append("replace_peers=true\n") } - assert(tc.peers.count == resolvedEndpoints.count) - for (i, peer) in tc.peers.enumerated() { + assert(tunnelConfiguration.peers.count == resolvedEndpoints.count) + for (i, peer) in tunnelConfiguration.peers.enumerated() { wgSettings.append("public_key=\(peer.publicKey.hexEncodedString())\n") if let preSharedKey = peer.preSharedKey { wgSettings.append("preshared_key=\(preSharedKey.hexEncodedString())\n") @@ -43,8 +44,10 @@ class PacketTunnelOptionsGenerator { } } } + return wgSettings + } - options[.wireguardSettings] = wgSettings as NSObject + func generateNetworkSettings() -> NEPacketTunnelNetworkSettings { // Remote address @@ -67,15 +70,22 @@ class PacketTunnelOptionsGenerator { } } - options[.remoteAddress] = remoteAddress as NSObject + let networkSettings = NEPacketTunnelNetworkSettings(tunnelRemoteAddress: remoteAddress) // DNS - options[.dnsServers] = tc.interface.dns.map { $0.stringRepresentation() } as NSObject + let dnsServerStrings = tunnelConfiguration.interface.dns.map { $0.stringRepresentation() } + networkSettings.dnsSettings = NEDNSSettings(servers: dnsServerStrings) // MTU - options[.mtu] = NSNumber(value: tc.interface.mtu ?? 0) // 0 implies auto-MTU + let mtu = tunnelConfiguration.interface.mtu ?? 0 + if (mtu == 0) { + // 0 imples automatic MTU, where we set overhead as 80 bytes, which is the worst case for WireGuard + networkSettings.tunnelOverheadBytes = 80 + } else { + networkSettings.mtu = NSNumber(value: mtu) + } // Addresses from interface addresses @@ -85,22 +95,16 @@ class PacketTunnelOptionsGenerator { var ipv6Addresses: [String] = [] var ipv6NetworkPrefixLengths: [NSNumber] = [] - for addressRange in tc.interface.addresses { + for addressRange in tunnelConfiguration.interface.addresses { if (addressRange.address is IPv4Address) { ipv4Addresses.append("\(addressRange.address)") - ipv4SubnetMasks.append(ipv4SubnetMaskString(of: addressRange)) + ipv4SubnetMasks.append(PacketTunnelSettingsGenerator.ipv4SubnetMaskString(of: addressRange)) } else if (addressRange.address is IPv6Address) { ipv6Addresses.append("\(addressRange.address)") ipv6NetworkPrefixLengths.append(NSNumber(value: addressRange.networkPrefixLength)) } } - options[.ipv4Addresses] = ipv4Addresses as NSObject - options[.ipv4SubnetMasks] = ipv4SubnetMasks as NSObject - - options[.ipv6Addresses] = ipv6Addresses as NSObject - options[.ipv6NetworkPrefixLengths] = ipv6NetworkPrefixLengths as NSObject - // Included routes from AllowedIPs var ipv4IncludedRouteAddresses: [String] = [] @@ -109,11 +113,11 @@ class PacketTunnelOptionsGenerator { var ipv6IncludedRouteAddresses: [String] = [] var ipv6IncludedRouteNetworkPrefixLengths: [NSNumber] = [] - for peer in tc.peers { + for peer in tunnelConfiguration.peers { for addressRange in peer.allowedIPs { if (addressRange.address is IPv4Address) { ipv4IncludedRouteAddresses.append("\(addressRange.address)") - ipv4IncludedRouteSubnetMasks.append(ipv4SubnetMaskString(of: addressRange)) + ipv4IncludedRouteSubnetMasks.append(PacketTunnelSettingsGenerator.ipv4SubnetMaskString(of: addressRange)) } else if (addressRange.address is IPv6Address) { ipv6IncludedRouteAddresses.append("\(addressRange.address)") ipv6IncludedRouteNetworkPrefixLengths.append(NSNumber(value: addressRange.networkPrefixLength)) @@ -121,12 +125,6 @@ class PacketTunnelOptionsGenerator { } } - options[.ipv4IncludedRouteAddresses] = ipv4IncludedRouteAddresses as NSObject - options[.ipv4IncludedRouteSubnetMasks] = ipv4IncludedRouteSubnetMasks as NSObject - - options[.ipv6IncludedRouteAddresses] = ipv6IncludedRouteAddresses as NSObject - options[.ipv6IncludedRouteNetworkPrefixLengths] = ipv6IncludedRouteNetworkPrefixLengths as NSObject - // Excluded routes from endpoints var ipv4ExcludedRouteAddresses: [String] = [] @@ -149,13 +147,40 @@ class PacketTunnelOptionsGenerator { } } - options[.ipv4ExcludedRouteAddresses] = ipv4ExcludedRouteAddresses as NSObject - options[.ipv4ExcludedRouteSubnetMasks] = ipv4ExcludedRouteSubnetMasks as NSObject + // Apply IPv4 settings - options[.ipv6ExcludedRouteAddresses] = ipv6ExcludedRouteAddresses as NSObject - options[.ipv6ExcludedRouteNetworkPrefixLengths] = ipv6ExcludedRouteNetworkPrefixLengths as NSObject + 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 - return options + // Apply IPv6 settings + + /* Big fat ugly hack for broken iOS networking stack: the smallest prefix that will have + * any effect on iOS is a /120, so we clamp everything above to /120. This is potentially + * very bad, if various network parameters were actually relying on that subnet being + * intentionally small. TODO: talk about this with upstream iOS devs. + */ + let ipv6Settings = NEIPv6Settings(addresses: ipv6Addresses, networkPrefixLengths: ipv6NetworkPrefixLengths.map { NSNumber(value: min(120, $0.intValue)) }) + assert(ipv6IncludedRouteAddresses.count == ipv6IncludedRouteNetworkPrefixLengths.count) + ipv6Settings.includedRoutes = zip(ipv6IncludedRouteAddresses, ipv6IncludedRouteNetworkPrefixLengths).map { + NEIPv6Route(destinationAddress: $0.0, networkPrefixLength: $0.1) + } + assert(ipv6ExcludedRouteAddresses.count == ipv6ExcludedRouteNetworkPrefixLengths.count) + ipv6Settings.excludedRoutes = zip(ipv6ExcludedRouteAddresses, ipv6ExcludedRouteNetworkPrefixLengths).map { + NEIPv6Route(destinationAddress: $0.0, networkPrefixLength: $0.1) + } + networkSettings.ipv6Settings = ipv6Settings + + // Done + + return networkSettings } static func ipv4SubnetMaskString(of addressRange: IPAddressRange) -> String {