From 80d99cab6c58eaced3f4ba243ed22e24c81ca078 Mon Sep 17 00:00:00 2001 From: Davide De Rosa Date: Sun, 3 Jan 2021 09:48:48 +0100 Subject: [PATCH] Refactor legacy parsing of provider configuration Leverage Codable implementation of OpenVPN*.Configuration --- TunnelKit.xcodeproj/project.pbxproj | 6 +- TunnelKit/Sources/Core/Utils.swift | 17 + .../OpenVPNTunnelProvider+Configuration.swift | 424 +----------------- .../Protocols/OpenVPN/Configuration.swift | 95 ++++ 4 files changed, 133 insertions(+), 409 deletions(-) diff --git a/TunnelKit.xcodeproj/project.pbxproj b/TunnelKit.xcodeproj/project.pbxproj index 392fc6c..c38662c 100644 --- a/TunnelKit.xcodeproj/project.pbxproj +++ b/TunnelKit.xcodeproj/project.pbxproj @@ -750,12 +750,12 @@ 0E23B3F722982AF800304C30 /* AppExtension */ = { isa = PBXGroup; children = ( - 0E23B3F822982AF800304C30 /* OpenVPNTunnelProvider+Interaction.swift */, - 0E23B3F922982AF800304C30 /* NEUDPLink.swift */, 0E23B3FA22982AF800304C30 /* ConnectionStrategy.swift */, - 0E23B3FB22982AF800304C30 /* OpenVPNTunnelProvider+Configuration.swift */, 0E23B3FC22982AF800304C30 /* NETCPLink.swift */, + 0E23B3F922982AF800304C30 /* NEUDPLink.swift */, 0E23B3FD22982AF800304C30 /* OpenVPNTunnelProvider.swift */, + 0E23B3FB22982AF800304C30 /* OpenVPNTunnelProvider+Configuration.swift */, + 0E23B3F822982AF800304C30 /* OpenVPNTunnelProvider+Interaction.swift */, ); path = AppExtension; sourceTree = ""; diff --git a/TunnelKit/Sources/Core/Utils.swift b/TunnelKit/Sources/Core/Utils.swift index 2250425..49d4b7a 100644 --- a/TunnelKit/Sources/Core/Utils.swift +++ b/TunnelKit/Sources/Core/Utils.swift @@ -42,3 +42,20 @@ public extension DispatchQueue { asyncAfter(deadline: .now() + after, execute: block) } } + +/// :nodoc: +func fromDictionary(_ type: T.Type, _ dictionary: [String: Any]) throws -> T { + let data = try JSONSerialization.data(withJSONObject: dictionary, options: .fragmentsAllowed) + return try JSONDecoder().decode(T.self, from: data) +} + +/// :nodoc: +public extension Encodable { + func asDictionary() throws -> [String: Any] { + let data = try JSONEncoder().encode(self) + guard let dictionary = try JSONSerialization.jsonObject(with: data, options: .fragmentsAllowed) as? [String: Any] else { + fatalError("JSONSerialization failed to encode") + } + return dictionary + } +} diff --git a/TunnelKit/Sources/Protocols/OpenVPN/AppExtension/OpenVPNTunnelProvider+Configuration.swift b/TunnelKit/Sources/Protocols/OpenVPN/AppExtension/OpenVPNTunnelProvider+Configuration.swift index ceb7130..29acc8b 100644 --- a/TunnelKit/Sources/Protocols/OpenVPN/AppExtension/OpenVPNTunnelProvider+Configuration.swift +++ b/TunnelKit/Sources/Protocols/OpenVPN/AppExtension/OpenVPNTunnelProvider+Configuration.swift @@ -41,6 +41,9 @@ import SwiftyBeaver private let log = SwiftyBeaver.self extension OpenVPNTunnelProvider { + private struct ExtraKeys { + static let appGroup = "appGroup" + } // MARK: Configuration @@ -100,24 +103,6 @@ extension OpenVPNTunnelProvider { versionIdentifier = ConfigurationBuilder.defaults.versionIdentifier } - fileprivate init(providerConfiguration: [String: Any]) throws { - let S = Configuration.Keys.self - - sessionConfiguration = try OpenVPN.Configuration.with(providerConfiguration: providerConfiguration) - prefersResolvedAddresses = providerConfiguration[S.prefersResolvedAddresses] as? Bool ?? ConfigurationBuilder.defaults.prefersResolvedAddresses - resolvedAddresses = providerConfiguration[S.resolvedAddresses] as? [String] - shouldDebug = providerConfiguration[S.debug] as? Bool ?? ConfigurationBuilder.defaults.shouldDebug - if shouldDebug { - debugLogFormat = providerConfiguration[S.debugLogFormat] as? String - } - masksPrivateData = providerConfiguration[S.masksPrivateData] as? Bool ?? ConfigurationBuilder.defaults.masksPrivateData - versionIdentifier = providerConfiguration[S.versionIdentifier] as? String ?? ConfigurationBuilder.defaults.versionIdentifier - - guard !prefersResolvedAddresses || !(resolvedAddresses?.isEmpty ?? true) else { - throw ProviderConfigurationError.parameter(name: "protocolConfiguration.providerConfiguration[\(S.prefersResolvedAddresses)] is true but no [\(S.resolvedAddresses)]") - } - } - /** Builds a `OpenVPNTunnelProvider.Configuration` object that will connect to the provided endpoint. @@ -138,79 +123,6 @@ extension OpenVPNTunnelProvider { /// Offers a bridge between the abstract `OpenVPNTunnelProvider.ConfigurationBuilder` and a concrete `NETunnelProviderProtocol` profile. public struct Configuration: Codable { - struct Keys { - static let appGroup = "AppGroup" - - static let versionIdentifier = "VersionIdentifier" - - // MARK: SessionConfiguration - - static let cipherAlgorithm = "CipherAlgorithm" - - static let digestAlgorithm = "DigestAlgorithm" - - static let compressionFraming = "CompressionFraming" - - static let compressionAlgorithm = "CompressionAlgorithm" - - static let ca = "CA" - - static let clientCertificate = "ClientCertificate" - - static let clientKey = "ClientKey" - - static let tlsWrap = "TLSWrap" - - static let tlsSecurityLevel = "TLSSecurityLevel" - - static let keepAlive = "KeepAlive" - - static let keepAliveTimeout = "KeepAliveTimeout" - - static let endpointProtocols = "EndpointProtocols" - - static let renegotiatesAfter = "RenegotiatesAfter" - - static let checksEKU = "ChecksEKU" - - static let checksSANHost = "checksSANHost" - - static let sanHost = "sanHost" - - static let randomizeEndpoint = "RandomizeEndpoint" - - static let usesPIAPatches = "UsesPIAPatches" - - static let mtu = "MTU" - - static let dnsServers = "DNSServers" - - static let searchDomains = "SearchDomains" - - static let httpProxy = "HTTPProxy" - - static let httpsProxy = "HTTPSProxy" - - static let proxyAutoConfigurationURL = "ProxyAutoConfigurationURL" - - static let proxyBypassDomains = "ProxyBypassDomains" - - static let routingPolicies = "RoutingPolicies" - - // MARK: Customization - - static let prefersResolvedAddresses = "PrefersResolvedAddresses" - - static let resolvedAddresses = "ResolvedAddresses" - - // MARK: Debugging - - static let debug = "Debug" - - static let debugLogFormat = "DebugLogFormat" - - static let masksPrivateData = "MasksPrivateData" - } /// - Seealso: `OpenVPNTunnelProvider.ConfigurationBuilder.sessionConfiguration` public let sessionConfiguration: OpenVPN.Configuration @@ -318,8 +230,8 @@ extension OpenVPNTunnelProvider { - Throws: `ProviderError.configuration` if `providerConfiguration` does not contain an app group. */ public static func appGroup(from providerConfiguration: [String: Any]) throws -> String { - guard let appGroup = providerConfiguration[Keys.appGroup] as? String else { - throw ProviderConfigurationError.parameter(name: "protocolConfiguration.providerConfiguration[\(Keys.appGroup)]") + guard let appGroup = providerConfiguration[ExtraKeys.appGroup] as? String else { + throw ProviderConfigurationError.parameter(name: "protocolConfiguration.providerConfiguration[\(ExtraKeys.appGroup)]") } return appGroup } @@ -332,10 +244,13 @@ extension OpenVPNTunnelProvider { - Throws: `ProviderError.configuration` if `providerConfiguration` is incomplete. */ public static func parsed(from providerConfiguration: [String: Any]) throws -> Configuration { - let builder = try ConfigurationBuilder(providerConfiguration: providerConfiguration) - return builder.build() + let cfg = try fromDictionary(OpenVPNTunnelProvider.Configuration.self, providerConfiguration) + guard !cfg.prefersResolvedAddresses || !(cfg.resolvedAddresses?.isEmpty ?? true) else { + throw ProviderConfigurationError.parameter(name: "protocolConfiguration.providerConfiguration[prefersResolvedAddresses] is true but no [resolvedAddresses]") + } + return cfg } - + /** Returns a dictionary representation of this configuration for use with `NETunnelProviderProtocol.providerConfiguration`. @@ -343,36 +258,14 @@ extension OpenVPNTunnelProvider { - Returns: The dictionary representation of `self`. */ public func generatedProviderConfiguration(appGroup: String) -> [String: Any] { - let S = Keys.self - - guard let ca = sessionConfiguration.ca else { - fatalError("No sessionConfiguration.ca set") + do { + var dict = try asDictionary() + dict[ExtraKeys.appGroup] = appGroup + return dict + } catch let e { + log.error("Unable to encode OpenVPN.Configuration: \(e)") } - guard let endpointProtocols = sessionConfiguration.endpointProtocols else { - fatalError("No sessionConfiguration.endpointProtocols set") - } - - var dict: [String: Any] = [ - S.appGroup: appGroup, - S.prefersResolvedAddresses: prefersResolvedAddresses, - S.ca: ca.pem, - S.endpointProtocols: endpointProtocols.map { $0.rawValue }, - S.debug: shouldDebug - ] - sessionConfiguration.store(to: &dict) - if let resolvedAddresses = resolvedAddresses { - dict[S.resolvedAddresses] = resolvedAddresses - } - if let debugLogFormat = debugLogFormat { - dict[S.debugLogFormat] = debugLogFormat - } - if let masksPrivateData = masksPrivateData { - dict[S.masksPrivateData] = masksPrivateData - } - if let versionIdentifier = versionIdentifier { - dict[S.versionIdentifier] = versionIdentifier - } - return dict + return [:] } /** @@ -451,284 +344,3 @@ public extension UserDefaults { removeObject(forKey: OpenVPNTunnelProvider.Configuration.dataCountKey) } } - -// MARK: OpenVPN configuration - -private extension OpenVPN.Configuration { - static func with(providerConfiguration: [String: Any]) throws -> OpenVPN.Configuration { - let S = OpenVPNTunnelProvider.Configuration.Keys.self - let E = OpenVPNTunnelProvider.ProviderConfigurationError.self - - guard let caPEM = providerConfiguration[S.ca] as? String else { - throw E.parameter(name: "protocolConfiguration.providerConfiguration[\(S.ca)]") - } - guard let endpointProtocolsStrings = providerConfiguration[S.endpointProtocols] as? [String], !endpointProtocolsStrings.isEmpty else { - throw E.parameter(name: "protocolConfiguration.providerConfiguration[\(S.endpointProtocols)] is nil or empty") - } - - var builder = OpenVPNTunnelProvider.ConfigurationBuilder.defaults.sessionConfiguration.builder() - - builder.ca = OpenVPN.CryptoContainer(pem: caPEM) - builder.endpointProtocols = try endpointProtocolsStrings.map { - guard let ep = EndpointProtocol(rawValue: $0) else { - throw E.parameter(name: "protocolConfiguration.providerConfiguration[\(S.endpointProtocols)] has a badly formed element") - } - return ep - } - - if let cipherAlgorithm = providerConfiguration[S.cipherAlgorithm] as? String { - builder.cipher = OpenVPN.Cipher(rawValue: cipherAlgorithm) - } - if let digestAlgorithm = providerConfiguration[S.digestAlgorithm] as? String { - builder.digest = OpenVPN.Digest(rawValue: digestAlgorithm) - } - if let compressionFramingValue = providerConfiguration[S.compressionFraming] as? Int, let compressionFraming = OpenVPN.CompressionFraming(rawValue: compressionFramingValue) { - builder.compressionFraming = compressionFraming - } - if let compressionAlgorithmValue = providerConfiguration[S.compressionAlgorithm] as? Int, let compressionAlgorithm = OpenVPN.CompressionAlgorithm(rawValue: compressionAlgorithmValue) { - builder.compressionAlgorithm = compressionAlgorithm - } - if let clientPEM = providerConfiguration[S.clientCertificate] as? String { - guard let keyPEM = providerConfiguration[S.clientKey] as? String else { - throw E.parameter(name: "protocolConfiguration.providerConfiguration[\(S.clientKey)]") - } - builder.clientCertificate = OpenVPN.CryptoContainer(pem: clientPEM) - builder.clientKey = OpenVPN.CryptoContainer(pem: keyPEM) - } - if let tlsWrapData = providerConfiguration[S.tlsWrap] as? Data { - do { - builder.tlsWrap = try OpenVPN.TLSWrap.deserialized(tlsWrapData) - } catch { - throw E.parameter(name: "protocolConfiguration.providerConfiguration[\(S.tlsWrap)]") - } - } - if let tlsSecurityLevel = providerConfiguration[S.tlsSecurityLevel] as? Int { - builder.tlsSecurityLevel = tlsSecurityLevel - } - if let keepAliveInterval = providerConfiguration[S.keepAlive] as? TimeInterval { - builder.keepAliveInterval = keepAliveInterval - } - if let keepAliveTimeout = providerConfiguration[S.keepAliveTimeout] as? TimeInterval { - builder.keepAliveTimeout = keepAliveTimeout - } - if let renegotiatesAfter = providerConfiguration[S.renegotiatesAfter] as? TimeInterval { - builder.renegotiatesAfter = renegotiatesAfter - } - if let checksEKU = providerConfiguration[S.checksEKU] as? Bool { - builder.checksEKU = checksEKU - } - if let checksSANHost = providerConfiguration[S.checksSANHost] as? Bool { - builder.checksSANHost = checksSANHost - } - if let sanHost = providerConfiguration[S.sanHost] as? String { - builder.sanHost = sanHost - } - if let randomizeEndpoint = providerConfiguration[S.randomizeEndpoint] as? Bool { - builder.randomizeEndpoint = randomizeEndpoint - } - if let usesPIAPatches = providerConfiguration[S.usesPIAPatches] as? Bool { - builder.usesPIAPatches = usesPIAPatches - } - if let mtu = providerConfiguration[S.mtu] as? Int { - builder.mtu = mtu - } - if let dnsServers = providerConfiguration[S.dnsServers] as? [String] { - builder.dnsServers = dnsServers - } - if let searchDomains = providerConfiguration[S.searchDomains] as? [String] { - builder.searchDomains = searchDomains - } - if let proxyString = providerConfiguration[S.httpProxy] as? String { - guard let proxy = Proxy(rawValue: proxyString) else { - throw E.parameter(name: "protocolConfiguration.providerConfiguration[\(S.httpProxy)] has a badly formed element") - } - builder.httpProxy = proxy - } - if let proxyString = providerConfiguration[S.httpsProxy] as? String { - guard let proxy = Proxy(rawValue: proxyString) else { - throw E.parameter(name: "protocolConfiguration.providerConfiguration[\(S.httpsProxy)] has a badly formed element") - } - builder.httpsProxy = proxy - } - if let proxyAutoConfigurationURLString = providerConfiguration[S.proxyAutoConfigurationURL] as? String, let proxyAutoConfigurationURL = URL(string: proxyAutoConfigurationURLString) { - builder.proxyAutoConfigurationURL = proxyAutoConfigurationURL - } - if let proxyBypassDomains = providerConfiguration[S.proxyBypassDomains] as? [String] { - builder.proxyBypassDomains = proxyBypassDomains - } - if let routingPoliciesStrings = providerConfiguration[S.routingPolicies] as? [String] { - builder.routingPolicies = try routingPoliciesStrings.map { - guard let policy = OpenVPN.RoutingPolicy(rawValue: $0) else { - throw E.parameter(name: "protocolConfiguration.providerConfiguration[\(S.routingPolicies)] has a badly formed element") - } - return policy - } - } - return builder.build() - } - - func store(to dict: inout [String: Any]) { - let S = OpenVPNTunnelProvider.Configuration.Keys.self - - if let cipher = cipher { - dict[S.cipherAlgorithm] = cipher.rawValue - } - if let digest = digest { - dict[S.digestAlgorithm] = digest.rawValue - } - if let compressionFraming = compressionFraming { - dict[S.compressionFraming] = compressionFraming.rawValue - } - if let compressionAlgorithm = compressionAlgorithm { - dict[S.compressionAlgorithm] = compressionAlgorithm.rawValue - } - if let clientCertificate = clientCertificate { - dict[S.clientCertificate] = clientCertificate.pem - } - if let clientKey = clientKey { - dict[S.clientKey] = clientKey.pem - } - if let tlsWrapData = tlsWrap?.serialized() { - dict[S.tlsWrap] = tlsWrapData - } - if let tlsSecurityLevel = tlsSecurityLevel { - dict[S.tlsSecurityLevel] = tlsSecurityLevel - } - if let keepAliveSeconds = keepAliveInterval { - dict[S.keepAlive] = keepAliveSeconds - } - if let keepAliveTimeoutSeconds = keepAliveTimeout { - dict[S.keepAliveTimeout] = keepAliveTimeoutSeconds - } - if let renegotiatesAfterSeconds = renegotiatesAfter { - dict[S.renegotiatesAfter] = renegotiatesAfterSeconds - } - if let checksEKU = checksEKU { - dict[S.checksEKU] = checksEKU - } - if let checksSANHost = checksSANHost { - dict[S.checksSANHost] = checksSANHost - } - if let sanHost = sanHost { - dict[S.sanHost] = sanHost - } - if let randomizeEndpoint = randomizeEndpoint { - dict[S.randomizeEndpoint] = randomizeEndpoint - } - if let usesPIAPatches = usesPIAPatches { - dict[S.usesPIAPatches] = usesPIAPatches - } - if let mtu = mtu { - dict[S.mtu] = mtu - } - if let dnsServers = dnsServers { - dict[S.dnsServers] = dnsServers - } - if let searchDomains = searchDomains { - dict[S.searchDomains] = searchDomains - } - if let httpProxy = httpProxy { - dict[S.httpProxy] = httpProxy.rawValue - } - if let httpsProxy = httpsProxy { - dict[S.httpsProxy] = httpsProxy.rawValue - } - if let proxyAutoConfigurationURL = proxyAutoConfigurationURL { - dict[S.proxyAutoConfigurationURL] = proxyAutoConfigurationURL.absoluteString - } - if let proxyBypassDomains = proxyBypassDomains { - dict[S.proxyBypassDomains] = proxyBypassDomains - } - if let routingPolicies = routingPolicies { - dict[S.routingPolicies] = routingPolicies.map { $0.rawValue } - } - } - - func print() { - guard let endpointProtocols = endpointProtocols else { - fatalError("No sessionConfiguration.endpointProtocols set") - } - log.info("\tProtocols: \(endpointProtocols)") - log.info("\tCipher: \(fallbackCipher)") - log.info("\tDigest: \(fallbackDigest)") - log.info("\tCompression framing: \(fallbackCompressionFraming)") - if let compressionAlgorithm = compressionAlgorithm, compressionAlgorithm != .disabled { - log.info("\tCompression algorithm: \(compressionAlgorithm)") - } else { - log.info("\tCompression algorithm: disabled") - } - if let _ = clientCertificate { - log.info("\tClient verification: enabled") - } else { - log.info("\tClient verification: disabled") - } - if let tlsWrap = tlsWrap { - log.info("\tTLS wrapping: \(tlsWrap.strategy)") - } else { - log.info("\tTLS wrapping: disabled") - } - if let tlsSecurityLevel = tlsSecurityLevel { - log.info("\tTLS security level: \(tlsSecurityLevel)") - } else { - log.info("\tTLS security level: default") - } - if let keepAliveSeconds = keepAliveInterval, keepAliveSeconds > 0 { - log.info("\tKeep-alive interval: \(keepAliveSeconds) seconds") - } else { - log.info("\tKeep-alive interval: never") - } - if let keepAliveTimeoutSeconds = keepAliveTimeout, keepAliveTimeoutSeconds > 0 { - log.info("\tKeep-alive timeout: \(keepAliveTimeoutSeconds) seconds") - } else { - log.info("\tKeep-alive timeout: never") - } - if let renegotiatesAfterSeconds = renegotiatesAfter, renegotiatesAfterSeconds > 0 { - log.info("\tRenegotiation: \(renegotiatesAfterSeconds) seconds") - } else { - log.info("\tRenegotiation: never") - } - if checksEKU ?? false { - log.info("\tServer EKU verification: enabled") - } else { - log.info("\tServer EKU verification: disabled") - } - if checksSANHost ?? false { - log.info("\tHost SAN verification: enabled (\(sanHost ?? "-"))") - } else { - log.info("\tHost SAN verification: disabled") - } - if randomizeEndpoint ?? false { - log.info("\tRandomize endpoint: true") - } - if let routingPolicies = routingPolicies { - log.info("\tGateway: \(routingPolicies.map { $0.rawValue })") - } else { - log.info("\tGateway: not configured") - } - if let dnsServers = dnsServers, !dnsServers.isEmpty { - log.info("\tDNS: \(dnsServers.maskedDescription)") - } else { - log.info("\tDNS: not configured") - } - if let searchDomains = searchDomains, !searchDomains.isEmpty { - log.info("\tSearch domains: \(searchDomains.maskedDescription)") - } - if let httpProxy = httpProxy { - log.info("\tHTTP proxy: \(httpProxy.maskedDescription)") - } - if let httpsProxy = httpsProxy { - log.info("\tHTTPS proxy: \(httpsProxy.maskedDescription)") - } - if let proxyAutoConfigurationURL = proxyAutoConfigurationURL { - log.info("\tPAC: \(proxyAutoConfigurationURL)") - } - if let proxyBypassDomains = proxyBypassDomains { - log.info("\tProxy bypass domains: \(proxyBypassDomains.maskedDescription)") - } - if let mtu = mtu { - log.info("\tMTU: \(mtu)") - } else { - log.info("\tMTU: default") - } - } -} diff --git a/TunnelKit/Sources/Protocols/OpenVPN/Configuration.swift b/TunnelKit/Sources/Protocols/OpenVPN/Configuration.swift index 43de035..3b94188 100644 --- a/TunnelKit/Sources/Protocols/OpenVPN/Configuration.swift +++ b/TunnelKit/Sources/Protocols/OpenVPN/Configuration.swift @@ -35,6 +35,9 @@ // import Foundation +import SwiftyBeaver + +private let log = SwiftyBeaver.self extension OpenVPN { @@ -506,3 +509,95 @@ extension OpenVPN.Configuration { return builder } } + +// MARK: Encoding + +extension OpenVPN.Configuration { + func print() { + guard let endpointProtocols = endpointProtocols else { + fatalError("No sessionConfiguration.endpointProtocols set") + } + log.info("\tProtocols: \(endpointProtocols)") + log.info("\tCipher: \(fallbackCipher)") + log.info("\tDigest: \(fallbackDigest)") + log.info("\tCompression framing: \(fallbackCompressionFraming)") + if let compressionAlgorithm = compressionAlgorithm, compressionAlgorithm != .disabled { + log.info("\tCompression algorithm: \(compressionAlgorithm)") + } else { + log.info("\tCompression algorithm: disabled") + } + if let _ = clientCertificate { + log.info("\tClient verification: enabled") + } else { + log.info("\tClient verification: disabled") + } + if let tlsWrap = tlsWrap { + log.info("\tTLS wrapping: \(tlsWrap.strategy)") + } else { + log.info("\tTLS wrapping: disabled") + } + if let tlsSecurityLevel = tlsSecurityLevel { + log.info("\tTLS security level: \(tlsSecurityLevel)") + } else { + log.info("\tTLS security level: default") + } + if let keepAliveSeconds = keepAliveInterval, keepAliveSeconds > 0 { + log.info("\tKeep-alive interval: \(keepAliveSeconds) seconds") + } else { + log.info("\tKeep-alive interval: never") + } + if let keepAliveTimeoutSeconds = keepAliveTimeout, keepAliveTimeoutSeconds > 0 { + log.info("\tKeep-alive timeout: \(keepAliveTimeoutSeconds) seconds") + } else { + log.info("\tKeep-alive timeout: never") + } + if let renegotiatesAfterSeconds = renegotiatesAfter, renegotiatesAfterSeconds > 0 { + log.info("\tRenegotiation: \(renegotiatesAfterSeconds) seconds") + } else { + log.info("\tRenegotiation: never") + } + if checksEKU ?? false { + log.info("\tServer EKU verification: enabled") + } else { + log.info("\tServer EKU verification: disabled") + } + if checksSANHost ?? false { + log.info("\tHost SAN verification: enabled (\(sanHost ?? "-"))") + } else { + log.info("\tHost SAN verification: disabled") + } + if randomizeEndpoint ?? false { + log.info("\tRandomize endpoint: true") + } + if let routingPolicies = routingPolicies { + log.info("\tGateway: \(routingPolicies.map { $0.rawValue })") + } else { + log.info("\tGateway: not configured") + } + if let dnsServers = dnsServers, !dnsServers.isEmpty { + log.info("\tDNS: \(dnsServers.maskedDescription)") + } else { + log.info("\tDNS: not configured") + } + if let searchDomains = searchDomains, !searchDomains.isEmpty { + log.info("\tSearch domains: \(searchDomains.maskedDescription)") + } + if let httpProxy = httpProxy { + log.info("\tHTTP proxy: \(httpProxy.maskedDescription)") + } + if let httpsProxy = httpsProxy { + log.info("\tHTTPS proxy: \(httpsProxy.maskedDescription)") + } + if let proxyAutoConfigurationURL = proxyAutoConfigurationURL { + log.info("\tPAC: \(proxyAutoConfigurationURL)") + } + if let proxyBypassDomains = proxyBypassDomains { + log.info("\tProxy bypass domains: \(proxyBypassDomains.maskedDescription)") + } + if let mtu = mtu { + log.info("\tMTU: \(mtu)") + } else { + log.info("\tMTU: default") + } + } +}