diff options
-rw-r--r-- | Sources/WireGuardKit/IPAddressRange.swift | 48 | ||||
-rw-r--r-- | Sources/WireGuardKit/PacketTunnelSettingsGenerator.swift | 37 |
2 files changed, 67 insertions, 18 deletions
diff --git a/Sources/WireGuardKit/IPAddressRange.swift b/Sources/WireGuardKit/IPAddressRange.swift index 67c3955..ecb888e 100644 --- a/Sources/WireGuardKit/IPAddressRange.swift +++ b/Sources/WireGuardKit/IPAddressRange.swift @@ -64,4 +64,52 @@ extension IPAddressRange { return (address, networkPrefixLength) } + + public func subnetMask() -> IPAddress { + if address is IPv4Address { + let mask = networkPrefixLength > 0 ? ~UInt32(0) << (32 - networkPrefixLength) : UInt32(0) + let bytes = Data([ + UInt8(truncatingIfNeeded: mask >> 24), + UInt8(truncatingIfNeeded: mask >> 16), + UInt8(truncatingIfNeeded: mask >> 8), + UInt8(truncatingIfNeeded: mask >> 0) + ]) + return IPv4Address(bytes)! + } + if address is IPv6Address { + var bytes = Data(repeating: 0, count: 16) + for i in 0..<Int(networkPrefixLength/8) { + bytes[i] = 0xff + } + let nibble = networkPrefixLength % 32 + if nibble != 0 { + let mask = ~UInt32(0) << (32 - nibble) + let i = Int(networkPrefixLength / 32 * 4) + bytes[i + 0] = UInt8(truncatingIfNeeded: mask >> 24) + bytes[i + 1] = UInt8(truncatingIfNeeded: mask >> 16) + bytes[i + 2] = UInt8(truncatingIfNeeded: mask >> 8) + bytes[i + 3] = UInt8(truncatingIfNeeded: mask >> 0) + } + return IPv6Address(bytes)! + } + fatalError() + } + + public func maskedAddress() -> IPAddress { + let subnet = subnetMask().rawValue + var masked = Data(address.rawValue) + if subnet.count != masked.count { + fatalError() + } + for i in 0..<subnet.count { + masked[i] &= subnet[i] + } + if subnet.count == 4 { + return IPv4Address(masked)! + } + if subnet.count == 16 { + return IPv6Address(masked)! + } + fatalError() + } } diff --git a/Sources/WireGuardKit/PacketTunnelSettingsGenerator.swift b/Sources/WireGuardKit/PacketTunnelSettingsGenerator.swift index 2d8cda1..7baa7cc 100644 --- a/Sources/WireGuardKit/PacketTunnelSettingsGenerator.swift +++ b/Sources/WireGuardKit/PacketTunnelSettingsGenerator.swift @@ -113,38 +113,26 @@ class PacketTunnelSettingsGenerator { networkSettings.mtu = NSNumber(value: mtu) } - let (ipv4Routes, ipv6Routes) = routes() + let (ipv4Addresses, ipv6Addresses) = addresses() let (ipv4IncludedRoutes, ipv6IncludedRoutes) = includedRoutes() - let ipv4Settings = NEIPv4Settings(addresses: ipv4Routes.map { $0.destinationAddress }, subnetMasks: ipv4Routes.map { $0.destinationSubnetMask }) + let ipv4Settings = NEIPv4Settings(addresses: ipv4Addresses.map { $0.destinationAddress }, subnetMasks: ipv4Addresses.map { $0.destinationSubnetMask }) ipv4Settings.includedRoutes = ipv4IncludedRoutes networkSettings.ipv4Settings = ipv4Settings - let ipv6Settings = NEIPv6Settings(addresses: ipv6Routes.map { $0.destinationAddress }, networkPrefixLengths: ipv6Routes.map { $0.destinationNetworkPrefixLength }) + let ipv6Settings = NEIPv6Settings(addresses: ipv6Addresses.map { $0.destinationAddress }, networkPrefixLengths: ipv6Addresses.map { $0.destinationNetworkPrefixLength }) ipv6Settings.includedRoutes = ipv6IncludedRoutes networkSettings.ipv6Settings = ipv6Settings return networkSettings } - private func ipv4SubnetMaskString(of addressRange: IPAddressRange) -> String { - let length: UInt8 = addressRange.networkPrefixLength - assert(length <= 32) - var octets: [UInt8] = [0, 0, 0, 0] - let subnetMask: UInt32 = length > 0 ? ~UInt32(0) << (32 - length) : UInt32(0) - octets[0] = UInt8(truncatingIfNeeded: subnetMask >> 24) - octets[1] = UInt8(truncatingIfNeeded: subnetMask >> 16) - octets[2] = UInt8(truncatingIfNeeded: subnetMask >> 8) - octets[3] = UInt8(truncatingIfNeeded: subnetMask) - return octets.map { String($0) }.joined(separator: ".") - } - - private func routes() -> ([NEIPv4Route], [NEIPv6Route]) { + private func addresses() -> ([NEIPv4Route], [NEIPv6Route]) { var ipv4Routes = [NEIPv4Route]() var ipv6Routes = [NEIPv6Route]() for addressRange in tunnelConfiguration.interface.addresses { if addressRange.address is IPv4Address { - ipv4Routes.append(NEIPv4Route(destinationAddress: "\(addressRange.address)", subnetMask: ipv4SubnetMaskString(of: addressRange))) + ipv4Routes.append(NEIPv4Route(destinationAddress: "\(addressRange.address)", subnetMask: "\(addressRange.subnetMask())")) } else if addressRange.address is IPv6Address { /* 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 @@ -160,10 +148,23 @@ class PacketTunnelSettingsGenerator { private func includedRoutes() -> ([NEIPv4Route], [NEIPv6Route]) { var ipv4IncludedRoutes = [NEIPv4Route]() var ipv6IncludedRoutes = [NEIPv6Route]() + + for addressRange in tunnelConfiguration.interface.addresses { + if addressRange.address is IPv4Address { + let route = NEIPv4Route(destinationAddress: "\(addressRange.maskedAddress())", subnetMask: "\(addressRange.subnetMask())") + route.gatewayAddress = "\(addressRange.address)" + ipv4IncludedRoutes.append(route) + } else if addressRange.address is IPv6Address { + let route = NEIPv6Route(destinationAddress: "\(addressRange.maskedAddress())", networkPrefixLength: NSNumber(value: addressRange.networkPrefixLength)) + route.gatewayAddress = "\(addressRange.address)" + ipv6IncludedRoutes.append(route) + } + } + for peer in tunnelConfiguration.peers { for addressRange in peer.allowedIPs { if addressRange.address is IPv4Address { - ipv4IncludedRoutes.append(NEIPv4Route(destinationAddress: "\(addressRange.address)", subnetMask: ipv4SubnetMaskString(of: addressRange))) + ipv4IncludedRoutes.append(NEIPv4Route(destinationAddress: "\(addressRange.address)", subnetMask: "\(addressRange.subnetMask())")) } else if addressRange.address is IPv6Address { ipv6IncludedRoutes.append(NEIPv6Route(destinationAddress: "\(addressRange.address)", networkPrefixLength: NSNumber(value: addressRange.networkPrefixLength))) } |