VPN: Bring up the tunnel
The app figures out all settings and passes them in the 'options' parameter of startTunnel(). The network extension just takes them as is and just plugs the supplied values into the right places. Signed-off-by: Roopesh Chander <roop@roopc.net>
This commit is contained in:
parent
a08e08fe2e
commit
793bf63989
|
@ -0,0 +1,30 @@
|
|||
// SPDX-License-Identifier: MIT
|
||||
// Copyright © 2018 WireGuard LLC. All rights reserved.
|
||||
|
||||
import Foundation
|
||||
|
||||
enum PacketTunnelOptionKey: String {
|
||||
|
||||
case interfaceName, wireguardSettings, remoteAddress, dnsServers, mtu,
|
||||
|
||||
// IPv4 settings
|
||||
ipv4Addresses, ipv4SubnetMasks,
|
||||
ipv4IncludedRouteAddresses, ipv4IncludedRouteSubnetMasks,
|
||||
ipv4ExcludedRouteAddresses, ipv4ExcludedRouteSubnetMasks,
|
||||
|
||||
// IPv6 settings
|
||||
ipv6Addresses, ipv6NetworkPrefixLengths,
|
||||
ipv6IncludedRouteAddresses, ipv6IncludedRouteNetworkPrefixLengths,
|
||||
ipv6ExcludedRouteAddresses, ipv6ExcludedRouteNetworkPrefixLengths
|
||||
}
|
||||
|
||||
extension Dictionary where Key == String {
|
||||
subscript(key: PacketTunnelOptionKey) -> Value? {
|
||||
get {
|
||||
return self[key.rawValue]
|
||||
}
|
||||
set(value) {
|
||||
self[key.rawValue] = value
|
||||
}
|
||||
}
|
||||
}
|
|
@ -10,6 +10,9 @@
|
|||
6F5D0C1521832391000F85AD /* DNSResolver.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F5D0C1421832391000F85AD /* DNSResolver.swift */; };
|
||||
6F5D0C1D218352EF000F85AD /* PacketTunnelProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F5D0C1C218352EF000F85AD /* PacketTunnelProvider.swift */; };
|
||||
6F5D0C22218352EF000F85AD /* WireGuardNetworkExtension.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = 6F5D0C1A218352EF000F85AD /* WireGuardNetworkExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
|
||||
6F5D0C452183BCDA000F85AD /* PacketTunnelOptionKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F5D0C442183BCDA000F85AD /* PacketTunnelOptionKey.swift */; };
|
||||
6F5D0C462183C0B4000F85AD /* PacketTunnelOptionKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F5D0C442183BCDA000F85AD /* PacketTunnelOptionKey.swift */; };
|
||||
6F5D0C482183C6A3000F85AD /* PacketTunnelOptionsGenerator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F5D0C472183C6A3000F85AD /* PacketTunnelOptionsGenerator.swift */; };
|
||||
6F628C3D217F09E9003482A3 /* TunnelViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F628C3C217F09E9003482A3 /* TunnelViewModel.swift */; };
|
||||
6F628C3F217F3413003482A3 /* DNSServer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F628C3E217F3413003482A3 /* DNSServer.swift */; };
|
||||
6F628C41217F47DB003482A3 /* TunnelDetailTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F628C40217F47DB003482A3 /* TunnelDetailTableViewController.swift */; };
|
||||
|
@ -69,6 +72,8 @@
|
|||
6F5D0C1E218352EF000F85AD /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
6F5D0C1F218352EF000F85AD /* WireGuardNetworkExtension.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = WireGuardNetworkExtension.entitlements; sourceTree = "<group>"; };
|
||||
6F5D0C3421839E37000F85AD /* WireGuardNetworkExtension-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "WireGuardNetworkExtension-Bridging-Header.h"; sourceTree = "<group>"; };
|
||||
6F5D0C442183BCDA000F85AD /* PacketTunnelOptionKey.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PacketTunnelOptionKey.swift; sourceTree = "<group>"; };
|
||||
6F5D0C472183C6A3000F85AD /* PacketTunnelOptionsGenerator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PacketTunnelOptionsGenerator.swift; sourceTree = "<group>"; };
|
||||
6F628C3C217F09E9003482A3 /* TunnelViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TunnelViewModel.swift; sourceTree = "<group>"; };
|
||||
6F628C3E217F3413003482A3 /* DNSServer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DNSServer.swift; sourceTree = "<group>"; };
|
||||
6F628C40217F47DB003482A3 /* TunnelDetailTableViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TunnelDetailTableViewController.swift; sourceTree = "<group>"; };
|
||||
|
@ -127,6 +132,14 @@
|
|||
path = WireGuardNetworkExtension;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
6F5D0C432183B4A4000F85AD /* Shared */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
6F5D0C442183BCDA000F85AD /* PacketTunnelOptionKey.swift */,
|
||||
);
|
||||
path = Shared;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
6F6899A32180445A0012E523 /* Crypto */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
|
@ -183,6 +196,7 @@
|
|||
children = (
|
||||
6F7774EE21722D97006A79B3 /* TunnelsManager.swift */,
|
||||
6F5D0C1421832391000F85AD /* DNSResolver.swift */,
|
||||
6F5D0C472183C6A3000F85AD /* PacketTunnelOptionsGenerator.swift */,
|
||||
);
|
||||
path = VPN;
|
||||
sourceTree = "<group>";
|
||||
|
@ -190,6 +204,7 @@
|
|||
6FF4AC0B211EC46F002C96EB = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
6F5D0C432183B4A4000F85AD /* Shared */,
|
||||
6FF4AC16211EC46F002C96EB /* WireGuard */,
|
||||
6F5D0C1B218352EF000F85AD /* WireGuardNetworkExtension */,
|
||||
6FF4AC15211EC46F002C96EB /* Products */,
|
||||
|
@ -362,6 +377,7 @@
|
|||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
6F5D0C462183C0B4000F85AD /* PacketTunnelOptionKey.swift in Sources */,
|
||||
6F5D0C1D218352EF000F85AD /* PacketTunnelProvider.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
|
@ -374,8 +390,10 @@
|
|||
6F7774E421718281006A79B3 /* TunnelsListTableViewController.swift in Sources */,
|
||||
6F7774EF21722D97006A79B3 /* TunnelsManager.swift in Sources */,
|
||||
6F5D0C1521832391000F85AD /* DNSResolver.swift in Sources */,
|
||||
6F5D0C482183C6A3000F85AD /* PacketTunnelOptionsGenerator.swift in Sources */,
|
||||
6F693A562179E556008551C1 /* Endpoint.swift in Sources */,
|
||||
6F6899A62180447E0012E523 /* x25519.c in Sources */,
|
||||
6F5D0C452183BCDA000F85AD /* PacketTunnelOptionKey.swift in Sources */,
|
||||
6F7774E2217181B1006A79B3 /* AppDelegate.swift in Sources */,
|
||||
6F628C3F217F3413003482A3 /* DNSServer.swift in Sources */,
|
||||
6F628C3D217F09E9003482A3 /* TunnelViewModel.swift in Sources */,
|
||||
|
|
|
@ -0,0 +1,180 @@
|
|||
// SPDX-License-Identifier: MIT
|
||||
// Copyright © 2018 WireGuard LLC. All rights reserved.
|
||||
|
||||
import Foundation
|
||||
import Network
|
||||
|
||||
class PacketTunnelOptionsGenerator {
|
||||
static func generateOptions(from tc: TunnelConfiguration,
|
||||
withResolvedEndpoints resolvedEndpoints: [Endpoint?]) -> [String:NSObject] {
|
||||
var options: [String:NSObject] = [:]
|
||||
|
||||
// Interface name
|
||||
|
||||
options[.interfaceName] = tc.interface.name as NSObject
|
||||
|
||||
// WireGuard settings
|
||||
|
||||
var wgSettings = ""
|
||||
let privateKey = tc.interface.privateKey.hexEncodedString()
|
||||
wgSettings.append("private_key=\(privateKey)\n")
|
||||
if let listenPort = tc.interface.listenPort {
|
||||
wgSettings.append("listen_port=\(listenPort)\n")
|
||||
}
|
||||
if (tc.peers.count > 0) {
|
||||
wgSettings.append("replace_peers=true\n")
|
||||
}
|
||||
assert(tc.peers.count == resolvedEndpoints.count)
|
||||
for (i, peer) in tc.peers.enumerated() {
|
||||
wgSettings.append("public_key=\(peer.publicKey.hexEncodedString())\n")
|
||||
if let preSharedKey = peer.preSharedKey {
|
||||
wgSettings.append("preshared_key=\(preSharedKey.hexEncodedString())\n")
|
||||
}
|
||||
if let endpoint = resolvedEndpoints[i] {
|
||||
if case .name(_, _) = endpoint.host { assert(false, "Endpoint is not resolved") }
|
||||
wgSettings.append("endpoint=\(endpoint.stringRepresentation())\n")
|
||||
}
|
||||
let persistentKeepAlive = peer.persistentKeepAlive ?? 0
|
||||
wgSettings.append("persistent_keepalive_interval=\(persistentKeepAlive)\n")
|
||||
if (!peer.allowedIPs.isEmpty) {
|
||||
wgSettings.append("replace_allowed_ips=true\n")
|
||||
for ip in peer.allowedIPs {
|
||||
wgSettings.append("allowed_ip=\(ip.stringRepresentation())\n")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
options[.wireguardSettings] = wgSettings as NSObject
|
||||
|
||||
// Remote address
|
||||
|
||||
let remoteAddress: String
|
||||
if let firstEndpoint = resolvedEndpoints.compactMap({ $0 }).first {
|
||||
switch (firstEndpoint.host) {
|
||||
case .ipv4(let address):
|
||||
remoteAddress = "\(address)"
|
||||
case .ipv6(let address):
|
||||
remoteAddress = "\(address)"
|
||||
default:
|
||||
fatalError("Endpoint must be resolved")
|
||||
}
|
||||
} else {
|
||||
// We don't have any peer with an endpoint
|
||||
remoteAddress = ""
|
||||
}
|
||||
|
||||
options[.remoteAddress] = remoteAddress as NSObject
|
||||
|
||||
// DNS
|
||||
|
||||
options[.dnsServers] = tc.interface.dns.map { $0.stringRepresentation() } as NSObject
|
||||
|
||||
// MTU
|
||||
|
||||
options[.mtu] = NSNumber(value: tc.interface.mtu ?? 0) // 0 implies auto-MTU
|
||||
|
||||
// Addresses from interface addresses
|
||||
|
||||
var ipv4Addresses: [String] = []
|
||||
var ipv4SubnetMasks: [String] = []
|
||||
|
||||
var ipv6Addresses: [String] = []
|
||||
var ipv6NetworkPrefixLengths: [NSNumber] = []
|
||||
|
||||
for addressRange in tc.interface.addresses {
|
||||
if (addressRange.address is IPv4Address) {
|
||||
ipv4Addresses.append("\(addressRange.address)")
|
||||
ipv4SubnetMasks.append(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] = []
|
||||
var ipv4IncludedRouteSubnetMasks: [String] = []
|
||||
|
||||
var ipv6IncludedRouteAddresses: [String] = []
|
||||
var ipv6IncludedRouteNetworkPrefixLengths: [NSNumber] = []
|
||||
|
||||
for peer in tc.peers {
|
||||
for addressRange in peer.allowedIPs {
|
||||
if (addressRange.address is IPv4Address) {
|
||||
ipv4IncludedRouteAddresses.append("\(addressRange.address)")
|
||||
ipv4IncludedRouteSubnetMasks.append(ipv4SubnetMaskString(of: addressRange))
|
||||
} else if (addressRange.address is IPv6Address) {
|
||||
ipv6IncludedRouteAddresses.append("\(addressRange.address)")
|
||||
ipv6IncludedRouteNetworkPrefixLengths.append(NSNumber(value: addressRange.networkPrefixLength))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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] = []
|
||||
var ipv4ExcludedRouteSubnetMasks: [String] = []
|
||||
|
||||
var ipv6ExcludedRouteAddresses: [String] = []
|
||||
var ipv6ExcludedRouteNetworkPrefixLengths: [NSNumber] = []
|
||||
|
||||
for endpoint in resolvedEndpoints {
|
||||
guard let endpoint = endpoint else { continue }
|
||||
switch (endpoint.host) {
|
||||
case .ipv4(let address):
|
||||
ipv4ExcludedRouteAddresses.append("\(address)")
|
||||
ipv4ExcludedRouteSubnetMasks.append("255.255.255.255") // A single IPv4 address
|
||||
case .ipv6(let address):
|
||||
ipv6ExcludedRouteAddresses.append("\(address)")
|
||||
ipv6ExcludedRouteNetworkPrefixLengths.append(NSNumber(value: UInt8(128))) // A single IPv6 address
|
||||
default:
|
||||
fatalError()
|
||||
}
|
||||
}
|
||||
|
||||
options[.ipv4ExcludedRouteAddresses] = ipv4ExcludedRouteAddresses as NSObject
|
||||
options[.ipv4ExcludedRouteSubnetMasks] = ipv4ExcludedRouteSubnetMasks as NSObject
|
||||
|
||||
options[.ipv6ExcludedRouteAddresses] = ipv6ExcludedRouteAddresses as NSObject
|
||||
options[.ipv6ExcludedRouteNetworkPrefixLengths] = ipv6ExcludedRouteNetworkPrefixLengths as NSObject
|
||||
|
||||
return options
|
||||
}
|
||||
|
||||
static func ipv4SubnetMaskString(of addressRange: IPAddressRange) -> String {
|
||||
var n: UInt8 = addressRange.networkPrefixLength
|
||||
assert(n <= 32)
|
||||
var components: [UInt8] = []
|
||||
while (n >= 8) {
|
||||
components.append(255)
|
||||
n = n - 8
|
||||
}
|
||||
if (n > 0) {
|
||||
components.append(((1 << n) - 1) << (8 - n))
|
||||
}
|
||||
while (components.count < 4) {
|
||||
components.append(0)
|
||||
}
|
||||
assert(components.count == 4)
|
||||
return components.map { String($0) }.joined(separator: ".")
|
||||
}
|
||||
}
|
||||
|
||||
private extension Data {
|
||||
func hexEncodedString() -> String {
|
||||
return self.map { String(format: "%02x", $0) }.joined()
|
||||
}
|
||||
}
|
|
@ -277,7 +277,9 @@ class TunnelContainer: NSObject {
|
|||
s.startObservingTunnelStatus()
|
||||
let session = (s.tunnelProvider.connection as! NETunnelProviderSession)
|
||||
do {
|
||||
try session.startTunnel(options: [:]) // TODO: Provide options
|
||||
let tunnelOptions = PacketTunnelOptionsGenerator.generateOptions(
|
||||
from: tunnelConfiguration, withResolvedEndpoints: endpoints)
|
||||
try session.startTunnel(options: tunnelOptions)
|
||||
} catch (let error) {
|
||||
os_log("Failed to activate tunnel: %{public}@", log: OSLog.default, type: .debug, "\(error)")
|
||||
s.onActive = nil
|
||||
|
|
|
@ -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)
|
||||
override func startTunnel(options: [String: NSObject]?,
|
||||
completionHandler startTunnelCompletionHandler: @escaping (Error?) -> Void) {
|
||||
os_log("Starting tunnel", log: OSLog.default, 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 }
|
||||
|
||||
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) }
|
||||
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)
|
||||
}
|
||||
assert(ipv6ExcludedRouteAddresses.count == ipv6ExcludedRouteNetworkPrefixLengths.count)
|
||||
ipv6Settings.excludedRoutes = zip(ipv6ExcludedRouteAddresses, ipv6ExcludedRouteNetworkPrefixLengths).map {
|
||||
NEIPv6Route(destinationAddress: $0.0, networkPrefixLength: $0.1)
|
||||
}
|
||||
networkSettings.ipv6Settings = ipv6Settings
|
||||
|
||||
newSettings.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
|
||||
}
|
||||
|
||||
if let dns = config.providerConfiguration?[PCKeys.dns.rawValue] as? String {
|
||||
newSettings.dnsSettings = NEDNSSettings(servers: dns.commaSeparatedToArray())
|
||||
}
|
||||
|
||||
if let mtu = config.providerConfiguration![PCKeys.mtu.rawValue] as? NSNumber, mtu.intValue > 0 {
|
||||
newSettings.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 }
|
||||
|
|
Loading…
Reference in New Issue