From 145b524954be564c7a7cb97ac26072d02498b3c3 Mon Sep 17 00:00:00 2001 From: "Jason A. Donenfeld" Date: Mon, 5 Nov 2018 06:23:26 +0100 Subject: [PATCH] TunnelsManager: account for no or many endpoints --- .../WireGuard/UI/iOS/ErrorPresenter.swift | 2 -- .../VPN/PacketTunnelOptionsGenerator.swift | 18 +++++++++------ WireGuard/WireGuard/VPN/TunnelsManager.swift | 22 ++++++++----------- 3 files changed, 20 insertions(+), 22 deletions(-) diff --git a/WireGuard/WireGuard/UI/iOS/ErrorPresenter.swift b/WireGuard/WireGuard/UI/iOS/ErrorPresenter.swift index 95b5503..d9a66dd 100644 --- a/WireGuard/WireGuard/UI/iOS/ErrorPresenter.swift +++ b/WireGuard/WireGuard/UI/iOS/ErrorPresenter.swift @@ -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: diff --git a/WireGuard/WireGuard/VPN/PacketTunnelOptionsGenerator.swift b/WireGuard/WireGuard/VPN/PacketTunnelOptionsGenerator.swift index 35d4bb7..3eabde7 100644 --- a/WireGuard/WireGuard/VPN/PacketTunnelOptionsGenerator.swift +++ b/WireGuard/WireGuard/VPN/PacketTunnelOptionsGenerator.swift @@ -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 diff --git a/WireGuard/WireGuard/VPN/TunnelsManager.swift b/WireGuard/WireGuard/VPN/TunnelsManager.swift index f2d02d4..d0c0dc1 100644 --- a/WireGuard/WireGuard/VPN/TunnelsManager.swift +++ b/WireGuard/WireGuard/VPN/TunnelsManager.swift @@ -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()