diff --git a/CHANGELOG.md b/CHANGELOG.md index 61e52bc..37282f5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## Unreleased + +### Changed + +- Make `hostname` optional and pick `resolvedAddresses` if nil. + ## 1.6.1 (2019-04-07) ### Fixed diff --git a/TunnelKit/Sources/AppExtension/ConnectionStrategy.swift b/TunnelKit/Sources/AppExtension/ConnectionStrategy.swift index fbe09de..a98f8ae 100644 --- a/TunnelKit/Sources/AppExtension/ConnectionStrategy.swift +++ b/TunnelKit/Sources/AppExtension/ConnectionStrategy.swift @@ -42,7 +42,7 @@ import SwiftyBeaver private let log = SwiftyBeaver.self class ConnectionStrategy { - private let hostname: String + private let hostname: String? private let prefersResolvedAddresses: Bool @@ -52,15 +52,17 @@ class ConnectionStrategy { private var currentProtocolIndex = 0 - init(hostname: String, configuration: TunnelKitProvider.Configuration) { - precondition(!configuration.prefersResolvedAddresses || !(configuration.resolvedAddresses?.isEmpty ?? true)) - - self.hostname = hostname - prefersResolvedAddresses = configuration.prefersResolvedAddresses + init(configuration: TunnelKitProvider.Configuration) { + hostname = configuration.sessionConfiguration.hostname + prefersResolvedAddresses = (hostname == nil) || configuration.prefersResolvedAddresses resolvedAddresses = configuration.resolvedAddresses - + if prefersResolvedAddresses { + guard !(resolvedAddresses?.isEmpty ?? true) else { + fatalError("Either hostname or resolved addresses provided") + } + } guard var endpointProtocols = configuration.sessionConfiguration.endpointProtocols else { - fatalError("No endpoints defined") + fatalError("No endpoints provided") } if configuration.sessionConfiguration.randomizeEndpoint ?? false { endpointProtocols.shuffle() @@ -92,6 +94,11 @@ class ConnectionStrategy { } // fall back to DNS + guard let hostname = hostname else { + log.error("DNS resolution unavailable: no hostname provided!") + completionHandler(nil, TunnelKitProvider.ProviderError.dnsFailure) + return + } log.debug("DNS resolve hostname: \(hostname.maskedDescription)") DNSResolver.resolve(hostname, timeout: timeout, queue: queue) { (addresses, error) in diff --git a/TunnelKit/Sources/AppExtension/TunnelKitProvider+Configuration.swift b/TunnelKit/Sources/AppExtension/TunnelKitProvider+Configuration.swift index 794cd12..f05fec9 100644 --- a/TunnelKit/Sources/AppExtension/TunnelKitProvider+Configuration.swift +++ b/TunnelKit/Sources/AppExtension/TunnelKitProvider+Configuration.swift @@ -466,7 +466,7 @@ extension TunnelKitProvider { - Returns: The generated `NETunnelProviderProtocol` object. - Throws: `ProviderError.credentials` if unable to store `credentials.password` to the `appGroup` keychain. */ - public func generatedTunnelProtocol(withBundleIdentifier bundleIdentifier: String, appGroup: String, hostname: String, credentials: SessionProxy.Credentials? = nil) throws -> NETunnelProviderProtocol { + public func generatedTunnelProtocol(withBundleIdentifier bundleIdentifier: String, appGroup: String, hostname: String?, credentials: SessionProxy.Credentials? = nil) throws -> NETunnelProviderProtocol { let protocolConfiguration = NETunnelProviderProtocol() protocolConfiguration.providerBundleIdentifier = bundleIdentifier diff --git a/TunnelKit/Sources/AppExtension/TunnelKitProvider.swift b/TunnelKit/Sources/AppExtension/TunnelKitProvider.swift index b20ed6d..dfd42ff 100644 --- a/TunnelKit/Sources/AppExtension/TunnelKitProvider.swift +++ b/TunnelKit/Sources/AppExtension/TunnelKitProvider.swift @@ -123,7 +123,6 @@ open class TunnelKitProvider: NEPacketTunnelProvider { open override func startTunnel(options: [String : NSObject]? = nil, completionHandler: @escaping (Error?) -> Void) { // required configuration - let hostname: String do { guard let tunnelProtocol = protocolConfiguration as? NETunnelProviderProtocol else { throw ProviderConfigurationError.parameter(name: "protocolConfiguration") @@ -134,9 +133,17 @@ open class TunnelKitProvider: NEPacketTunnelProvider { guard let providerConfiguration = tunnelProtocol.providerConfiguration else { throw ProviderConfigurationError.parameter(name: "protocolConfiguration.providerConfiguration") } - hostname = serverAddress try appGroup = Configuration.appGroup(from: providerConfiguration) try cfg = Configuration.parsed(from: providerConfiguration) + + // inject serverAddress into sessionConfiguration.hostname + if !serverAddress.isEmpty { + var sessionBuilder = cfg.sessionConfiguration.builder() + sessionBuilder.hostname = serverAddress + var cfgBuilder = cfg.builder() + cfgBuilder.sessionConfiguration = sessionBuilder.build() + cfg = cfgBuilder.build() + } } catch let e { var message: String? if let te = e as? ProviderConfigurationError { @@ -162,7 +169,7 @@ open class TunnelKitProvider: NEPacketTunnelProvider { credentials = nil } - strategy = ConnectionStrategy(hostname: hostname, configuration: cfg) + strategy = ConnectionStrategy(configuration: cfg) if let content = cfg.existingLog(in: appGroup) { var existingLog = content.components(separatedBy: "\n")