2018-08-23 08:19:25 +00:00
//
2018-08-23 10:07:55 +00:00
// T u n n e l K i t P r o v i d e r + C o n f i g u r a t i o n . s w i f t
// T u n n e l K i t
2018-08-23 08:19:25 +00:00
//
// C r e a t e d b y D a v i d e D e R o s a o n 1 0 / 2 3 / 1 7 .
2019-03-09 10:44:18 +00:00
// C o p y r i g h t ( c ) 2 0 1 9 D a v i d e D e R o s a . A l l r i g h t s r e s e r v e d .
2018-08-27 18:30:09 +00:00
//
// h t t p s : / / g i t h u b . c o m / k e e s h u x
//
// T h i s f i l e i s p a r t o f T u n n e l K i t .
//
// T u n n e l K i t i s f r e e s o f t w a r e : y o u c a n r e d i s t r i b u t e i t a n d / o r m o d i f y
// i t u n d e r t h e t e r m s o f t h e G N U G e n e r a l P u b l i c L i c e n s e a s p u b l i s h e d b y
// t h e F r e e S o f t w a r e F o u n d a t i o n , e i t h e r v e r s i o n 3 o f t h e L i c e n s e , o r
// ( a t y o u r o p t i o n ) a n y l a t e r v e r s i o n .
//
// T u n n e l K i t i s d i s t r i b u t e d i n t h e h o p e t h a t i t w i l l b e u s e f u l ,
// b u t W I T H O U T A N Y W A R R A N T Y ; w i t h o u t e v e n t h e i m p l i e d w a r r a n t y o f
// M E R C H A N T A B I L I T Y o r F I T N E S S F O R A P A R T I C U L A R P U R P O S E . S e e t h e
// G N U G e n e r a l P u b l i c L i c e n s e f o r m o r e d e t a i l s .
//
// Y o u s h o u l d h a v e r e c e i v e d a c o p y o f t h e G N U G e n e r a l P u b l i c L i c e n s e
// a l o n g w i t h T u n n e l K i t . I f n o t , s e e < h t t p : / / w w w . g n u . o r g / l i c e n s e s / > .
//
// T h i s f i l e i n c o r p o r a t e s w o r k c o v e r e d b y t h e f o l l o w i n g c o p y r i g h t a n d
// p e r m i s s i o n n o t i c e :
//
// C o p y r i g h t ( c ) 2 0 1 8 - P r e s e n t P r i v a t e I n t e r n e t A c c e s s
//
// P e r m i s s i o n i s h e r e b y g r a n t e d , f r e e o f c h a r g e , t o a n y p e r s o n o b t a i n i n g a c o p y o f t h i s s o f t w a r e a n d a s s o c i a t e d d o c u m e n t a t i o n f i l e s ( t h e " S o f t w a r e " ) , t o d e a l i n t h e S o f t w a r e w i t h o u t r e s t r i c t i o n , i n c l u d i n g w i t h o u t l i m i t a t i o n t h e r i g h t s t o u s e , c o p y , m o d i f y , m e r g e , p u b l i s h , d i s t r i b u t e , s u b l i c e n s e , a n d / o r s e l l c o p i e s o f t h e S o f t w a r e , a n d t o p e r m i t p e r s o n s t o w h o m t h e S o f t w a r e i s f u r n i s h e d t o d o s o , s u b j e c t t o t h e f o l l o w i n g c o n d i t i o n s :
//
// T h e a b o v e c o p y r i g h t n o t i c e a n d t h i s p e r m i s s i o n n o t i c e s h a l l b e i n c l u d e d i n a l l c o p i e s o r s u b s t a n t i a l p o r t i o n s o f t h e S o f t w a r e .
//
// T H E S O F T W A R E I S P R O V I D E D " A S I S " , W I T H O U T W A R R A N T Y O F A N Y K I N D , E X P R E S S O R I M P L I E D , I N C L U D I N G B U T N O T L I M I T E D T O T H E W A R R A N T I E S O F M E R C H A N T A B I L I T Y , F I T N E S S F O R A P A R T I C U L A R P U R P O S E A N D N O N I N F R I N G E M E N T . I N N O E V E N T S H A L L T H E A U T H O R S O R C O P Y R I G H T H O L D E R S B E L I A B L E F O R A N Y C L A I M , D A M A G E S O R O T H E R L I A B I L I T Y , W H E T H E R I N A N A C T I O N O F C O N T R A C T , T O R T O R O T H E R W I S E , A R I S I N G F R O M , O U T O F O R I N C O N N E C T I O N W I T H T H E S O F T W A R E O R T H E U S E O R O T H E R D E A L I N G S I N T H E S O F T W A R E .
//
2018-08-23 08:19:25 +00:00
//
import Foundation
import NetworkExtension
import SwiftyBeaver
private let log = SwiftyBeaver . self
2018-08-23 10:07:55 +00:00
extension TunnelKitProvider {
2018-08-23 08:19:25 +00:00
// MARK: C o n f i g u r a t i o n
2018-08-23 10:07:55 +00:00
// / T h e w a y t o c r e a t e a ` T u n n e l K i t P r o v i d e r . C o n f i g u r a t i o n ` o b j e c t f o r t h e t u n n e l p r o f i l e .
2018-08-23 08:19:25 +00:00
public struct ConfigurationBuilder {
2018-10-26 09:07:46 +00:00
// / : n o d o c :
public static let defaults = Configuration (
prefersResolvedAddresses : false ,
resolvedAddresses : nil ,
2019-04-04 09:54:59 +00:00
endpointProtocols : nil ,
2018-10-26 09:07:46 +00:00
mtu : 1250 ,
2019-04-04 11:55:06 +00:00
sessionConfiguration : SessionProxy . ConfigurationBuilder ( ) . build ( ) ,
2018-10-26 09:07:46 +00:00
shouldDebug : false ,
2019-03-21 16:46:52 +00:00
debugLogFormat : nil ,
masksPrivateData : true
2018-10-26 09:07:46 +00:00
)
2018-08-23 08:19:25 +00:00
// / P r e f e r s r e s o l v e d a d d r e s s e s o v e r D N S r e s o l u t i o n . ` r e s o l v e d A d d r e s s e s ` m u s t b e s e t a n d n o n - e m p t y . D e f a u l t i s ` f a l s e ` .
// /
// / - S e e a l s o : ` f a l l b a c k S e r v e r A d d r e s s e s `
public var prefersResolvedAddresses : Bool
// / R e s o l v e d a d d r e s s e s i n c a s e D N S f a i l s o r ` p r e f e r s R e s o l v e d A d d r e s s e s ` i s ` t r u e ` .
public var resolvedAddresses : [ String ] ?
2018-08-24 10:33:52 +00:00
// / T h e M T U o f t h e l i n k .
public var mtu : Int
2018-08-23 08:19:25 +00:00
2018-10-25 06:33:40 +00:00
// / T h e s e s s i o n c o n f i g u r a t i o n .
public var sessionConfiguration : SessionProxy . Configuration
2018-10-18 09:36:02 +00:00
2018-08-23 08:19:25 +00:00
// MARK: D e b u g g i n g
2018-10-25 18:38:00 +00:00
// / E n a b l e s d e b u g g i n g .
2018-08-23 08:19:25 +00:00
public var shouldDebug : Bool
// / O p t i o n a l d e b u g l o g f o r m a t ( S w i f t y B e a v e r f o r m a t ) .
public var debugLogFormat : String ?
2019-03-21 16:46:52 +00:00
// / M a s k p r i v a t e d a t a i n d e b u g l o g ( d e f a u l t i s ` t r u e ` ) .
2019-03-21 18:31:25 +00:00
public var masksPrivateData : Bool ?
2019-03-21 16:46:52 +00:00
2018-08-23 08:19:25 +00:00
// MARK: B u i l d i n g
/* *
Default initializer .
2018-10-05 15:35:40 +00:00
- Parameter ca : The CA certificate .
2018-08-23 08:19:25 +00:00
*/
2018-10-25 06:33:40 +00:00
public init ( sessionConfiguration : SessionProxy . Configuration ) {
2018-10-26 09:07:46 +00:00
prefersResolvedAddresses = ConfigurationBuilder . defaults . prefersResolvedAddresses
2018-08-23 08:19:25 +00:00
resolvedAddresses = nil
2018-10-26 09:07:46 +00:00
mtu = ConfigurationBuilder . defaults . mtu
2018-10-25 06:33:40 +00:00
self . sessionConfiguration = sessionConfiguration
2018-10-26 09:07:46 +00:00
shouldDebug = ConfigurationBuilder . defaults . shouldDebug
debugLogFormat = ConfigurationBuilder . defaults . debugLogFormat
2019-03-21 16:46:52 +00:00
masksPrivateData = ConfigurationBuilder . defaults . masksPrivateData
2018-08-23 08:19:25 +00:00
}
fileprivate init ( providerConfiguration : [ String : Any ] ) throws {
let S = Configuration . Keys . self
2018-10-26 09:07:46 +00:00
prefersResolvedAddresses = providerConfiguration [ S . prefersResolvedAddresses ] as ? Bool ? ? ConfigurationBuilder . defaults . prefersResolvedAddresses
2018-10-25 06:33:40 +00:00
resolvedAddresses = providerConfiguration [ S . resolvedAddresses ] as ? [ String ]
2018-10-26 09:07:46 +00:00
mtu = providerConfiguration [ S . mtu ] as ? Int ? ? ConfigurationBuilder . defaults . mtu
2018-10-25 06:33:40 +00:00
//
2018-10-05 15:35:40 +00:00
guard let caPEM = providerConfiguration [ S . ca ] as ? String else {
2018-10-21 10:58:36 +00:00
throw ProviderConfigurationError . parameter ( name : " protocolConfiguration.providerConfiguration[ \( S . ca ) ] " )
2018-08-23 08:19:25 +00:00
}
2018-10-25 06:33:40 +00:00
2019-04-04 09:06:00 +00:00
var sessionConfigurationBuilder = SessionProxy . ConfigurationBuilder ( )
2019-04-07 06:16:09 +00:00
if let cipherAlgorithm = providerConfiguration [ S . cipherAlgorithm ] as ? String {
sessionConfigurationBuilder . cipher = SessionProxy . Cipher ( rawValue : cipherAlgorithm )
}
if let digestAlgorithm = providerConfiguration [ S . digestAlgorithm ] as ? String {
sessionConfigurationBuilder . digest = SessionProxy . Digest ( rawValue : digestAlgorithm )
}
2018-08-30 23:39:39 +00:00
if let compressionFramingValue = providerConfiguration [ S . compressionFraming ] as ? Int , let compressionFraming = SessionProxy . CompressionFraming ( rawValue : compressionFramingValue ) {
2018-10-25 06:33:40 +00:00
sessionConfigurationBuilder . compressionFraming = compressionFraming
2018-08-30 09:05:34 +00:00
} else {
2018-10-26 09:07:46 +00:00
sessionConfigurationBuilder . compressionFraming = ConfigurationBuilder . defaults . sessionConfiguration . compressionFraming
2018-08-30 09:05:34 +00:00
}
2019-03-19 11:04:42 +00:00
if let compressionAlgorithmValue = providerConfiguration [ S . compressionAlgorithm ] as ? Int , let compressionAlgorithm = SessionProxy . CompressionAlgorithm ( rawValue : compressionAlgorithmValue ) {
sessionConfigurationBuilder . compressionAlgorithm = compressionAlgorithm
} else {
sessionConfigurationBuilder . compressionAlgorithm = ConfigurationBuilder . defaults . sessionConfiguration . compressionAlgorithm
}
2019-04-07 06:16:09 +00:00
sessionConfigurationBuilder . ca = CryptoContainer ( pem : caPEM )
if let clientPEM = providerConfiguration [ S . clientCertificate ] as ? String {
guard let keyPEM = providerConfiguration [ S . clientKey ] as ? String else {
throw ProviderConfigurationError . parameter ( name : " protocolConfiguration.providerConfiguration[ \( S . clientKey ) ] " )
}
sessionConfigurationBuilder . clientCertificate = CryptoContainer ( pem : clientPEM )
sessionConfigurationBuilder . clientKey = CryptoContainer ( pem : keyPEM )
}
2018-09-19 20:22:35 +00:00
if let tlsWrapData = providerConfiguration [ S . tlsWrap ] as ? Data {
do {
2018-10-25 06:33:40 +00:00
sessionConfigurationBuilder . tlsWrap = try SessionProxy . TLSWrap . deserialized ( tlsWrapData )
2018-09-19 20:22:35 +00:00
} catch {
2018-10-21 10:58:36 +00:00
throw ProviderConfigurationError . parameter ( name : " protocolConfiguration.providerConfiguration[ \( S . tlsWrap ) ] " )
2018-09-19 20:22:35 +00:00
}
}
2019-03-25 09:17:47 +00:00
sessionConfigurationBuilder . keepAliveInterval = providerConfiguration [ S . keepAlive ] as ? TimeInterval ? ? ConfigurationBuilder . defaults . sessionConfiguration . keepAliveInterval
sessionConfigurationBuilder . renegotiatesAfter = providerConfiguration [ S . renegotiatesAfter ] as ? TimeInterval ? ? ConfigurationBuilder . defaults . sessionConfiguration . renegotiatesAfter
2019-04-04 09:06:00 +00:00
guard let endpointProtocolsStrings = providerConfiguration [ S . endpointProtocols ] as ? [ String ] , ! endpointProtocolsStrings . isEmpty else {
throw ProviderConfigurationError . parameter ( name : " protocolConfiguration.providerConfiguration[ \( S . endpointProtocols ) ] is nil or empty " )
}
sessionConfigurationBuilder . endpointProtocols = try endpointProtocolsStrings . map {
guard let ep = EndpointProtocol ( rawValue : $0 ) else {
throw ProviderConfigurationError . parameter ( name : " protocolConfiguration.providerConfiguration[ \( S . endpointProtocols ) ] has a badly formed element " )
}
return ep
}
2019-03-25 23:36:36 +00:00
sessionConfigurationBuilder . checksEKU = providerConfiguration [ S . checksEKU ] as ? Bool ? ? ConfigurationBuilder . defaults . sessionConfiguration . checksEKU
2019-03-25 09:17:47 +00:00
sessionConfigurationBuilder . randomizeEndpoint = providerConfiguration [ S . randomizeEndpoint ] as ? Bool ? ? ConfigurationBuilder . defaults . sessionConfiguration . randomizeEndpoint
2019-04-03 11:44:33 +00:00
sessionConfigurationBuilder . usesPIAPatches = providerConfiguration [ S . usesPIAPatches ] as ? Bool ? ? ConfigurationBuilder . defaults . sessionConfiguration . usesPIAPatches
2019-04-07 06:16:09 +00:00
sessionConfigurationBuilder . dnsServers = providerConfiguration [ S . dnsServers ] as ? [ String ]
sessionConfigurationBuilder . searchDomain = providerConfiguration [ S . searchDomain ] as ? String
2019-04-12 06:02:56 +00:00
if let proxyString = providerConfiguration [ S . httpProxy ] as ? String {
guard let proxy = Proxy ( rawValue : proxyString ) else {
throw ProviderConfigurationError . parameter ( name : " protocolConfiguration.providerConfiguration[ \( S . httpProxy ) ] has a badly formed element " )
}
sessionConfigurationBuilder . httpProxy = proxy
}
if let proxyString = providerConfiguration [ S . httpsProxy ] as ? String {
guard let proxy = Proxy ( rawValue : proxyString ) else {
throw ProviderConfigurationError . parameter ( name : " protocolConfiguration.providerConfiguration[ \( S . httpsProxy ) ] has a badly formed element " )
}
sessionConfigurationBuilder . httpsProxy = proxy
}
2019-04-13 17:03:27 +00:00
sessionConfigurationBuilder . proxyBypassDomains = providerConfiguration [ S . proxyBypassDomains ] as ? [ String ]
2018-10-25 06:33:40 +00:00
sessionConfiguration = sessionConfigurationBuilder . build ( )
2018-08-23 08:19:25 +00:00
2019-03-21 16:46:52 +00:00
shouldDebug = providerConfiguration [ S . debug ] as ? Bool ? ? ConfigurationBuilder . defaults . shouldDebug
2018-08-23 08:19:25 +00:00
if shouldDebug {
debugLogFormat = providerConfiguration [ S . debugLogFormat ] as ? String
}
2019-03-21 16:46:52 +00:00
masksPrivateData = providerConfiguration [ S . masksPrivateData ] as ? Bool ? ? ConfigurationBuilder . defaults . masksPrivateData
2018-08-23 08:19:25 +00:00
guard ! prefersResolvedAddresses || ! ( resolvedAddresses ? . isEmpty ? ? true ) else {
2018-10-21 10:58:36 +00:00
throw ProviderConfigurationError . parameter ( name : " protocolConfiguration.providerConfiguration[ \( S . prefersResolvedAddresses ) ] is true but no [ \( S . resolvedAddresses ) ] " )
2018-08-23 08:19:25 +00:00
}
}
/* *
2018-08-23 10:07:55 +00:00
Builds a ` TunnelKitProvider . Configuration ` object that will connect to the provided endpoint .
2018-08-23 08:19:25 +00:00
2018-08-23 10:07:55 +00:00
- Returns : A ` TunnelKitProvider . Configuration ` object with this builder and the additional method parameters .
2018-08-23 08:19:25 +00:00
*/
public func build ( ) -> Configuration {
return Configuration (
prefersResolvedAddresses : prefersResolvedAddresses ,
resolvedAddresses : resolvedAddresses ,
2019-04-04 09:54:59 +00:00
endpointProtocols : nil ,
2018-08-23 08:19:25 +00:00
mtu : mtu ,
2018-10-25 06:33:40 +00:00
sessionConfiguration : sessionConfiguration ,
2018-08-23 08:19:25 +00:00
shouldDebug : shouldDebug ,
2019-03-21 16:46:52 +00:00
debugLogFormat : shouldDebug ? debugLogFormat : nil ,
masksPrivateData : masksPrivateData
2018-08-23 08:19:25 +00:00
)
}
}
2018-08-23 10:07:55 +00:00
// / O f f e r s a b r i d g e b e t w e e n t h e a b s t r a c t ` T u n n e l K i t P r o v i d e r . C o n f i g u r a t i o n B u i l d e r ` a n d a c o n c r e t e ` N E T u n n e l P r o v i d e r P r o t o c o l ` p r o f i l e .
2018-09-04 20:18:24 +00:00
public struct Configuration : Codable {
2018-08-23 08:19:25 +00:00
struct Keys {
static let appGroup = " AppGroup "
static let prefersResolvedAddresses = " PrefersResolvedAddresses "
static let resolvedAddresses = " ResolvedAddresses "
2018-10-25 06:33:40 +00:00
static let mtu = " MTU "
// MARK: S e s s i o n C o n f i g u r a t i o n
2018-08-23 08:19:25 +00:00
static let cipherAlgorithm = " CipherAlgorithm "
static let digestAlgorithm = " DigestAlgorithm "
2019-04-07 06:16:09 +00:00
static let compressionFraming = " CompressionFraming "
static let compressionAlgorithm = " CompressionAlgorithm "
2018-08-23 08:19:25 +00:00
static let ca = " CA "
2018-08-23 15:42:49 +00:00
static let clientCertificate = " ClientCertificate "
static let clientKey = " ClientKey "
2018-09-19 20:22:35 +00:00
static let tlsWrap = " TLSWrap "
2018-09-07 20:13:40 +00:00
static let keepAlive = " KeepAlive "
2019-04-04 09:06:00 +00:00
static let endpointProtocols = " EndpointProtocols "
2018-08-23 08:19:25 +00:00
static let renegotiatesAfter = " RenegotiatesAfter "
2019-03-25 23:36:36 +00:00
static let checksEKU = " ChecksEKU "
2018-10-25 06:33:40 +00:00
2019-03-25 09:17:47 +00:00
static let randomizeEndpoint = " RandomizeEndpoint "
2019-04-03 11:44:33 +00:00
static let usesPIAPatches = " UsesPIAPatches "
2019-04-07 06:16:09 +00:00
static let dnsServers = " DNSServers "
static let searchDomain = " SearchDomain "
2019-04-12 06:02:56 +00:00
static let httpProxy = " HTTPProxy "
static let httpsProxy = " HTTPSProxy "
2019-04-13 17:03:27 +00:00
static let proxyBypassDomains = " ProxyBypassDomains "
2018-10-25 06:33:40 +00:00
// MARK: D e b u g g i n g
2018-10-18 09:36:02 +00:00
2018-08-23 08:19:25 +00:00
static let debug = " Debug "
static let debugLogFormat = " DebugLogFormat "
2019-03-21 16:46:52 +00:00
static let masksPrivateData = " MasksPrivateData "
2018-08-23 08:19:25 +00:00
}
2018-08-23 10:07:55 +00:00
// / - S e e a l s o : ` T u n n e l K i t P r o v i d e r . C o n f i g u r a t i o n B u i l d e r . p r e f e r s R e s o l v e d A d d r e s s e s `
2018-08-23 08:19:25 +00:00
public let prefersResolvedAddresses : Bool
2018-08-23 10:07:55 +00:00
// / - S e e a l s o : ` T u n n e l K i t P r o v i d e r . C o n f i g u r a t i o n B u i l d e r . r e s o l v e d A d d r e s s e s `
2018-08-23 08:19:25 +00:00
public let resolvedAddresses : [ String ] ?
2019-04-04 09:54:59 +00:00
// / - S e e a l s o : ` S e s s i o n P r o x y . C o n f i g u r a t i o n . e n d p o i n t P r o t o c o l s `
@ available ( * , deprecated )
public var endpointProtocols : [ EndpointProtocol ] ?
2018-08-23 10:07:55 +00:00
// / - S e e a l s o : ` T u n n e l K i t P r o v i d e r . C o n f i g u r a t i o n B u i l d e r . m t u `
2018-08-24 10:33:52 +00:00
public let mtu : Int
2018-08-23 08:19:25 +00:00
2018-10-25 06:33:40 +00:00
// / - S e e a l s o : ` T u n n e l K i t P r o v i d e r . C o n f i g u r a t i o n B u i l d e r . s e s s i o n C o n f i g u r a t i o n `
public let sessionConfiguration : SessionProxy . Configuration
2018-10-18 09:36:02 +00:00
2018-08-23 10:07:55 +00:00
// / - S e e a l s o : ` T u n n e l K i t P r o v i d e r . C o n f i g u r a t i o n B u i l d e r . s h o u l d D e b u g `
2018-08-23 08:19:25 +00:00
public let shouldDebug : Bool
2018-08-23 10:07:55 +00:00
// / - S e e a l s o : ` T u n n e l K i t P r o v i d e r . C o n f i g u r a t i o n B u i l d e r . d e b u g L o g F o r m a t `
2018-08-23 08:19:25 +00:00
public let debugLogFormat : String ?
2019-03-21 16:46:52 +00:00
// / - S e e a l s o : ` T u n n e l K i t P r o v i d e r . C o n f i g u r a t i o n B u i l d e r . m a s k s P r i v a t e D a t a `
2019-03-21 18:31:25 +00:00
public let masksPrivateData : Bool ?
2019-03-21 16:46:52 +00:00
2018-08-23 08:19:25 +00:00
// MARK: S h o r t c u t s
2018-10-25 19:02:22 +00:00
2018-10-25 18:38:00 +00:00
static let debugLogFilename = " debug.log "
2019-03-27 23:04:35 +00:00
static let lastErrorKey = " TunnelKitLastError "
fileprivate static let dataCountKey = " TunnelKitDataCount "
2018-10-25 19:02:22 +00:00
2018-10-24 17:28:15 +00:00
/* *
Returns the URL of the latest debug log .
- Parameter in : The app group where to locate the log file .
- Returns : The URL of the debug log , if any .
*/
public func urlForLog ( in appGroup : String ) -> URL ? {
2018-10-25 18:38:00 +00:00
guard shouldDebug else {
2018-08-23 08:19:25 +00:00
return nil
}
2018-10-24 17:21:44 +00:00
guard let parentURL = FileManager . default . containerURL ( forSecurityApplicationGroupIdentifier : appGroup ) else {
return nil
}
2018-10-25 18:38:00 +00:00
return parentURL . appendingPathComponent ( Configuration . debugLogFilename )
2018-10-24 17:21:44 +00:00
}
2018-10-24 17:28:15 +00:00
/* *
Returns the content of the latest debug log .
- Parameter in : The app group where to locate the log file .
- Returns : The content of the debug log , if any .
*/
public func existingLog ( in appGroup : String ) -> String ? {
2018-10-24 17:21:44 +00:00
guard let url = urlForLog ( in : appGroup ) else {
return nil
}
return try ? String ( contentsOf : url )
2018-08-23 08:19:25 +00:00
}
2018-10-25 19:02:22 +00:00
/* *
Returns the last error reported by the tunnel , if any .
- Parameter in : The app group where to locate the error key .
- Returns : The last tunnel error , if any .
*/
public func lastError ( in appGroup : String ) -> ProviderError ? {
guard let rawValue = UserDefaults ( suiteName : appGroup ) ? . string ( forKey : Configuration . lastErrorKey ) else {
return nil
}
return ProviderError ( rawValue : rawValue )
}
/* *
Clear the last error status .
- Parameter in : The app group where to locate the error key .
*/
public func clearLastError ( in appGroup : String ) {
UserDefaults ( suiteName : appGroup ) ? . removeObject ( forKey : Configuration . lastErrorKey )
}
2019-03-27 23:04:35 +00:00
/* *
Returns the most recent ( received , sent ) count in bytes .
- Parameter in : The app group where to locate the count pair .
- Returns : The bytes count pair , if any .
*/
public func dataCount ( in appGroup : String ) -> ( Int , Int ) ? {
guard let rawValue = UserDefaults ( suiteName : appGroup ) ? . dataCountArray else {
return nil
}
guard rawValue . count = = 2 else {
return nil
}
return ( rawValue [ 0 ] , rawValue [ 1 ] )
}
2018-08-23 08:19:25 +00:00
// MARK: A P I
2018-09-06 22:23:25 +00:00
/* *
Parses the app group from a provider configuration map .
- Parameter from : The map to parse .
- Returns : The parsed app group .
- 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 {
2018-10-21 10:58:36 +00:00
throw ProviderConfigurationError . parameter ( name : " protocolConfiguration.providerConfiguration[ \( Keys . appGroup ) ] " )
2018-09-06 22:23:25 +00:00
}
return appGroup
}
2018-08-23 08:19:25 +00:00
/* *
2018-08-23 10:07:55 +00:00
Parses a new ` TunnelKitProvider . Configuration ` object from a provider configuration map .
2018-08-23 08:19:25 +00:00
- Parameter from : The map to parse .
2018-08-23 10:07:55 +00:00
- Returns : The parsed ` TunnelKitProvider . Configuration ` object .
2018-08-23 08:19:25 +00:00
- 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 ( )
}
/* *
Returns a dictionary representation of this configuration for use with ` NETunnelProviderProtocol . providerConfiguration ` .
2018-09-06 22:23:25 +00:00
- Parameter appGroup : The name of the app group in which the tunnel extension lives in .
2018-08-23 08:19:25 +00:00
- Returns : The dictionary representation of ` self ` .
*/
2018-09-06 22:23:25 +00:00
public func generatedProviderConfiguration ( appGroup : String ) -> [ String : Any ] {
2018-08-23 08:19:25 +00:00
let S = Keys . self
2019-04-04 09:06:00 +00:00
guard let ca = sessionConfiguration . ca else {
fatalError ( " No sessionConfiguration.ca set " )
}
guard let endpointProtocols = sessionConfiguration . endpointProtocols else {
fatalError ( " No sessionConfiguration.endpointProtocols set " )
}
2018-08-23 08:19:25 +00:00
var dict : [ String : Any ] = [
S . appGroup : appGroup ,
S . prefersResolvedAddresses : prefersResolvedAddresses ,
2019-04-04 09:06:00 +00:00
S . ca : ca . pem ,
S . endpointProtocols : endpointProtocols . map { $0 . rawValue } ,
2018-08-23 08:19:25 +00:00
S . mtu : mtu ,
2019-03-21 18:31:25 +00:00
S . debug : shouldDebug
2018-08-23 08:19:25 +00:00
]
2019-04-04 11:01:32 +00:00
if let cipher = sessionConfiguration . cipher {
dict [ S . cipherAlgorithm ] = cipher . rawValue
}
if let digest = sessionConfiguration . digest {
dict [ S . digestAlgorithm ] = digest . rawValue
}
if let compressionFraming = sessionConfiguration . compressionFraming {
dict [ S . compressionFraming ] = compressionFraming . rawValue
}
if let compressionAlgorithm = sessionConfiguration . compressionAlgorithm {
dict [ S . compressionAlgorithm ] = compressionAlgorithm . rawValue
2019-04-04 09:06:00 +00:00
}
2018-10-25 06:33:40 +00:00
if let clientCertificate = sessionConfiguration . clientCertificate {
2018-08-23 15:42:49 +00:00
dict [ S . clientCertificate ] = clientCertificate . pem
}
2018-10-25 06:33:40 +00:00
if let clientKey = sessionConfiguration . clientKey {
2018-08-23 15:42:49 +00:00
dict [ S . clientKey ] = clientKey . pem
}
2018-10-25 06:33:40 +00:00
if let tlsWrapData = sessionConfiguration . tlsWrap ? . serialized ( ) {
2018-09-19 20:22:35 +00:00
dict [ S . tlsWrap ] = tlsWrapData
}
2018-10-25 06:33:40 +00:00
if let keepAliveSeconds = sessionConfiguration . keepAliveInterval {
2018-09-07 20:13:40 +00:00
dict [ S . keepAlive ] = keepAliveSeconds
}
2018-10-25 06:33:40 +00:00
if let renegotiatesAfterSeconds = sessionConfiguration . renegotiatesAfter {
2018-08-23 08:19:25 +00:00
dict [ S . renegotiatesAfter ] = renegotiatesAfterSeconds
}
2019-03-25 23:36:36 +00:00
if let checksEKU = sessionConfiguration . checksEKU {
dict [ S . checksEKU ] = checksEKU
}
2019-04-04 09:06:00 +00:00
if let randomizeEndpoint = sessionConfiguration . randomizeEndpoint {
dict [ S . randomizeEndpoint ] = randomizeEndpoint
}
if let usesPIAPatches = sessionConfiguration . usesPIAPatches {
dict [ S . usesPIAPatches ] = usesPIAPatches
}
2019-03-03 09:51:36 +00:00
if let dnsServers = sessionConfiguration . dnsServers {
dict [ S . dnsServers ] = dnsServers
}
2019-04-03 11:44:33 +00:00
if let searchDomain = sessionConfiguration . searchDomain {
dict [ S . searchDomain ] = searchDomain
}
2019-04-12 06:02:56 +00:00
if let httpProxy = sessionConfiguration . httpProxy {
dict [ S . httpProxy ] = httpProxy . rawValue
}
if let httpsProxy = sessionConfiguration . httpsProxy {
dict [ S . httpsProxy ] = httpsProxy . rawValue
}
2019-04-13 17:03:27 +00:00
if let proxyBypassDomains = sessionConfiguration . proxyBypassDomains {
dict [ S . proxyBypassDomains ] = proxyBypassDomains
}
2019-04-04 09:06:00 +00:00
//
if let resolvedAddresses = resolvedAddresses {
dict [ S . resolvedAddresses ] = resolvedAddresses
2019-04-03 11:44:33 +00:00
}
2018-08-23 08:19:25 +00:00
if let debugLogFormat = debugLogFormat {
dict [ S . debugLogFormat ] = debugLogFormat
}
2019-03-21 18:31:25 +00:00
if let masksPrivateData = masksPrivateData {
dict [ S . masksPrivateData ] = masksPrivateData
}
2018-08-23 08:19:25 +00:00
return dict
}
/* *
Generates a ` NETunnelProviderProtocol ` from this configuration .
- Parameter bundleIdentifier : The provider bundle identifier required to locate the tunnel extension .
2018-09-06 22:23:25 +00:00
- Parameter appGroup : The name of the app group in which the tunnel extension lives in .
2018-10-05 17:13:59 +00:00
- Parameter credentials : The optional credentials to authenticate with .
2018-08-23 08:19:25 +00:00
- Returns : The generated ` NETunnelProviderProtocol ` object .
2018-10-05 17:13:59 +00:00
- Throws : ` ProviderError . credentials ` if unable to store ` credentials . password ` to the ` appGroup ` keychain .
2018-08-23 08:19:25 +00:00
*/
2019-04-09 18:41:48 +00:00
public func generatedTunnelProtocol ( withBundleIdentifier bundleIdentifier : String , appGroup : String , credentials : SessionProxy . Credentials ? = nil ) throws -> NETunnelProviderProtocol {
2018-08-23 08:19:25 +00:00
let protocolConfiguration = NETunnelProviderProtocol ( )
protocolConfiguration . providerBundleIdentifier = bundleIdentifier
2019-04-09 18:41:48 +00:00
protocolConfiguration . serverAddress = sessionConfiguration . hostname ? ? resolvedAddresses ? . first
2018-10-05 17:13:59 +00:00
if let username = credentials ? . username , let password = credentials ? . password {
2018-10-05 15:45:05 +00:00
let keychain = Keychain ( group : appGroup )
do {
try keychain . set ( password : password , for : username , label : Bundle . main . bundleIdentifier )
} catch _ {
2018-10-21 10:58:36 +00:00
throw ProviderConfigurationError . credentials ( details : " keychain.set() " )
2018-10-05 15:45:05 +00:00
}
protocolConfiguration . username = username
protocolConfiguration . passwordReference = try ? keychain . passwordReference ( for : username )
}
2018-09-06 22:23:25 +00:00
protocolConfiguration . providerConfiguration = generatedProviderConfiguration ( appGroup : appGroup )
2018-08-23 08:19:25 +00:00
return protocolConfiguration
}
func print ( appVersion : String ? ) {
2019-04-04 09:06:00 +00:00
guard let endpointProtocols = sessionConfiguration . endpointProtocols else {
fatalError ( " No sessionConfiguration.endpointProtocols set " )
}
2018-08-23 08:19:25 +00:00
if let appVersion = appVersion {
log . info ( " App version: \( appVersion ) " )
}
2018-09-11 08:48:55 +00:00
log . info ( " \t Protocols: \( endpointProtocols ) " )
2019-04-04 11:01:32 +00:00
log . info ( " \t Cipher: \( sessionConfiguration . fallbackCipher ) " )
log . info ( " \t Digest: \( sessionConfiguration . fallbackDigest ) " )
log . info ( " \t Compression framing: \( sessionConfiguration . fallbackCompressionFraming ) " )
2019-04-04 09:06:00 +00:00
if let compressionAlgorithm = sessionConfiguration . compressionAlgorithm , compressionAlgorithm != . disabled {
log . info ( " \t Compression algorithm: \( compressionAlgorithm ) " )
} else {
log . info ( " \t Compression algorithm: disabled " )
}
2018-10-25 06:33:40 +00:00
if let _ = sessionConfiguration . clientCertificate {
2018-09-11 08:48:55 +00:00
log . info ( " \t Client verification: enabled " )
2018-08-23 15:42:49 +00:00
} else {
2018-09-11 08:48:55 +00:00
log . info ( " \t Client verification: disabled " )
2018-08-23 15:42:49 +00:00
}
2019-04-04 09:06:00 +00:00
if let tlsWrap = sessionConfiguration . tlsWrap {
log . info ( " \t TLS wrapping: \( tlsWrap . strategy ) " )
2019-03-19 11:04:42 +00:00
} else {
2019-04-04 09:06:00 +00:00
log . info ( " \t TLS wrapping: disabled " )
2019-03-19 11:04:42 +00:00
}
2018-10-25 06:33:40 +00:00
if let keepAliveSeconds = sessionConfiguration . keepAliveInterval , keepAliveSeconds > 0 {
2018-09-11 08:48:55 +00:00
log . info ( " \t Keep-alive: \( keepAliveSeconds ) seconds " )
2018-09-07 20:13:40 +00:00
} else {
2018-09-28 06:39:31 +00:00
log . info ( " \t Keep-alive: never " )
2018-09-07 20:13:40 +00:00
}
2018-10-25 06:33:40 +00:00
if let renegotiatesAfterSeconds = sessionConfiguration . renegotiatesAfter , renegotiatesAfterSeconds > 0 {
2018-09-11 08:48:55 +00:00
log . info ( " \t Renegotiation: \( renegotiatesAfterSeconds ) seconds " )
2018-08-23 08:19:25 +00:00
} else {
2018-09-11 08:48:55 +00:00
log . info ( " \t Renegotiation: never " )
2018-08-23 08:19:25 +00:00
}
2019-04-04 09:06:00 +00:00
if sessionConfiguration . checksEKU ? ? false {
log . info ( " \t Server EKU verification: enabled " )
2018-09-19 20:22:35 +00:00
} else {
2019-04-04 09:06:00 +00:00
log . info ( " \t Server EKU verification: disabled " )
}
if sessionConfiguration . randomizeEndpoint ? ? false {
log . info ( " \t Randomize endpoint: true " )
2018-09-19 20:22:35 +00:00
}
2019-03-03 09:51:36 +00:00
if let dnsServers = sessionConfiguration . dnsServers {
2019-04-04 09:06:00 +00:00
log . info ( " \t DNS servers: \( dnsServers . maskedDescription ) " )
2019-03-03 09:51:36 +00:00
}
2019-04-03 11:44:33 +00:00
if let searchDomain = sessionConfiguration . searchDomain {
2019-04-04 09:06:00 +00:00
log . info ( " \t Search domain: \( searchDomain . maskedDescription ) " )
2019-03-25 09:17:47 +00:00
}
2019-04-12 06:02:56 +00:00
if let httpProxy = sessionConfiguration . httpProxy {
log . info ( " \t HTTP proxy: \( httpProxy . maskedDescription ) " )
}
if let httpsProxy = sessionConfiguration . httpsProxy {
log . info ( " \t HTTPS proxy: \( httpsProxy . maskedDescription ) " )
}
2019-04-13 17:03:27 +00:00
if let proxyBypassDomains = sessionConfiguration . proxyBypassDomains {
log . info ( " \t Proxy bypass domains: \( proxyBypassDomains . maskedDescription ) " )
}
2019-04-04 09:06:00 +00:00
log . info ( " \t MTU: \( mtu ) " )
2018-09-11 08:48:55 +00:00
log . info ( " \t Debug: \( shouldDebug ) " )
2019-03-21 18:40:37 +00:00
log . info ( " \t Masks private data: \( masksPrivateData ? ? true ) " )
2018-08-23 08:19:25 +00:00
}
}
}
// MARK: M o d i f i c a t i o n
2019-04-04 09:06:00 +00:00
extension TunnelKitProvider . Configuration {
2018-08-23 08:19:25 +00:00
/* *
2018-08-23 10:07:55 +00:00
Returns a ` TunnelKitProvider . ConfigurationBuilder ` to use this configuration as a starting point for a new one .
2018-08-23 08:19:25 +00:00
2018-08-23 10:07:55 +00:00
- Returns : An editable ` TunnelKitProvider . ConfigurationBuilder ` initialized with this configuration .
2018-08-23 08:19:25 +00:00
*/
2018-08-23 10:07:55 +00:00
public func builder ( ) -> TunnelKitProvider . ConfigurationBuilder {
2018-10-25 06:33:40 +00:00
var builder = TunnelKitProvider . ConfigurationBuilder ( sessionConfiguration : sessionConfiguration )
2019-04-11 13:29:53 +00:00
builder . prefersResolvedAddresses = prefersResolvedAddresses
builder . resolvedAddresses = resolvedAddresses
2018-08-23 08:19:25 +00:00
builder . mtu = mtu
builder . shouldDebug = shouldDebug
2018-09-05 14:17:10 +00:00
builder . debugLogFormat = debugLogFormat
2019-04-11 13:29:53 +00:00
builder . masksPrivateData = masksPrivateData
2018-08-23 08:19:25 +00:00
return builder
}
}
2018-09-04 20:18:24 +00:00
2019-03-27 23:04:35 +00:00
// / : n o d o c :
public extension UserDefaults {
2019-03-30 19:16:04 +00:00
@objc var dataCountArray : [ Int ] ? {
2019-03-27 23:04:35 +00:00
get {
return array ( forKey : TunnelKitProvider . Configuration . dataCountKey ) as ? [ Int ]
}
set {
set ( newValue , forKey : TunnelKitProvider . Configuration . dataCountKey )
}
}
2019-03-30 19:16:04 +00:00
func removeDataCountArray ( ) {
2019-03-27 23:04:35 +00:00
removeObject ( forKey : TunnelKitProvider . Configuration . dataCountKey )
}
}