TunnelsManager: account for no or many endpoints

This commit is contained in:
Jason A. Donenfeld 2018-11-05 06:23:26 +01:00
parent bf6b2b6cb1
commit 145b524954
3 changed files with 20 additions and 22 deletions

View File

@ -21,8 +21,6 @@ class ErrorPresenter {
return ("Unable to remove tunnel", "Internal error")
// TunnelActivationError
case TunnelActivationError.noEndpoint:
return ("Endpoint missing", "There must be at least one peer with an endpoint")
case TunnelActivationError.dnsResolutionFailed:
return ("DNS resolution failure", "One or more endpoint domains could not be resolved")
case TunnelActivationError.tunnelActivationFailed:

View File

@ -48,19 +48,23 @@ class PacketTunnelOptionsGenerator {
// Remote address
let remoteAddress: String
if let firstEndpoint = resolvedEndpoints.compactMap({ $0 }).first {
switch (firstEndpoint.host) {
/* iOS requires a tunnel endpoint, whereas in WireGuard it's valid for
* a tunnel to have no endpoint, or for there to be many endpoints, in
* which case, displaying a single one in settings doesn't really
* make sense. So, we fill it in with this placeholder, which is not
* a valid IP address that will actually route over the Internet.
*/
var remoteAddress: String = "0.0.0.0"
let endpointsCompact = resolvedEndpoints.compactMap({ $0 })
if endpointsCompact.count == 1 {
switch (endpointsCompact.first!.host) {
case .ipv4(let address):
remoteAddress = "\(address)"
case .ipv6(let address):
remoteAddress = "\(address)"
default:
fatalError("Endpoint must be resolved")
break
}
} else {
// We don't have any peer with an endpoint
remoteAddress = ""
}
options[.remoteAddress] = remoteAddress as NSObject

View File

@ -13,7 +13,6 @@ protocol TunnelsManagerDelegate: class {
}
enum TunnelActivationError: Error {
case noEndpoint
case dnsResolutionFailed
case tunnelActivationFailed
case attemptingActivationWhenAnotherTunnelIsBusy(otherTunnelStatus: TunnelStatus)
@ -214,14 +213,20 @@ extension NETunnelProviderProtocol {
self.init()
let appId = Bundle.main.bundleIdentifier!
let firstValidEndpoint = tunnelConfiguration.peers.first(where: { $0.endpoint != nil })?.endpoint
providerBundleIdentifier = "\(appId).network-extension"
providerConfiguration = [
"tunnelConfiguration": serializedTunnelConfiguration,
"tunnelConfigurationVersion": 1
]
serverAddress = firstValidEndpoint?.stringRepresentation() ?? "Unspecified"
let endpoints = tunnelConfiguration.peers.compactMap({$0.endpoint})
if endpoints.count == 1 {
serverAddress = endpoints.first!.stringRepresentation()
} else if endpoints.isEmpty {
serverAddress = "Unspecified"
} else {
serverAddress = "Multiple endpoints"
}
username = tunnelConfiguration.interface.name
}
@ -262,15 +267,6 @@ class TunnelContainer: NSObject {
guard let tunnelConfiguration = tunnelConfiguration() else { fatalError() }
let endpoints = tunnelConfiguration.peers.map { $0.endpoint }
// Ensure there's a tunner server address we can give to iOS
guard (endpoints.contains(where: { $0 != nil })) else {
DispatchQueue.main.async { [weak self] in
self?.status = .inactive
completionHandler(TunnelActivationError.noEndpoint)
}
return
}
// Resolve DNS and start the tunnel
let dnsResolver = DNSResolver(endpoints: endpoints)
let resolvedEndpoints = dnsResolver.resolveWithoutNetworkRequests()