Parse PUSH_REPLY options in OptionsBundle
- auth-token - peer-id - Routing Reorganize options by semantic. Reuse OptionsBundle in PushReply.
This commit is contained in:
parent
b9b9c4db60
commit
9876c81de5
@ -463,9 +463,9 @@ extension TunnelKitProvider: SessionProxyDelegate {
|
||||
|
||||
log.info("Returned ifconfig parameters:")
|
||||
log.info("\tRemote: \(remoteAddress.maskedDescription)")
|
||||
log.info("\tIPv4: \(reply.ipv4?.description ?? "not configured")")
|
||||
log.info("\tIPv6: \(reply.ipv6?.description ?? "not configured")")
|
||||
log.info("\tDNS: \(reply.dnsServers.map { $0.maskedDescription })")
|
||||
log.info("\tIPv4: \(reply.options.ipv4?.description ?? "not configured")")
|
||||
log.info("\tIPv6: \(reply.options.ipv6?.description ?? "not configured")")
|
||||
log.info("\tDNS: \(reply.options.dnsServers.map { $0.maskedDescription })")
|
||||
|
||||
bringNetworkUp(remoteAddress: remoteAddress, reply: reply) { (error) in
|
||||
if let error = error {
|
||||
@ -477,7 +477,7 @@ extension TunnelKitProvider: SessionProxyDelegate {
|
||||
|
||||
log.info("Tunnel interface is now UP")
|
||||
|
||||
proxy.setTunnel(tunnel: NETunnelInterface(impl: self.packetFlow, isIPv6: reply.ipv6 != nil))
|
||||
proxy.setTunnel(tunnel: NETunnelInterface(impl: self.packetFlow, isIPv6: reply.options.ipv6 != nil))
|
||||
|
||||
self.pendingStartHandler?(nil)
|
||||
self.pendingStartHandler = nil
|
||||
@ -502,7 +502,7 @@ extension TunnelKitProvider: SessionProxyDelegate {
|
||||
|
||||
// route all traffic to VPN
|
||||
var ipv4Settings: NEIPv4Settings?
|
||||
if let ipv4 = reply.ipv4 {
|
||||
if let ipv4 = reply.options.ipv4 {
|
||||
let defaultRoute = NEIPv4Route.default()
|
||||
defaultRoute.gatewayAddress = ipv4.defaultGateway
|
||||
|
||||
@ -519,7 +519,7 @@ extension TunnelKitProvider: SessionProxyDelegate {
|
||||
}
|
||||
|
||||
var ipv6Settings: NEIPv6Settings?
|
||||
if let ipv6 = reply.ipv6 {
|
||||
if let ipv6 = reply.options.ipv6 {
|
||||
let defaultRoute = NEIPv6Route.default()
|
||||
defaultRoute.gatewayAddress = ipv6.defaultGateway
|
||||
|
||||
@ -535,7 +535,7 @@ extension TunnelKitProvider: SessionProxyDelegate {
|
||||
ipv6Settings?.excludedRoutes = []
|
||||
}
|
||||
|
||||
let dnsSettings = NEDNSSettings(servers: cfg.sessionConfiguration.dnsServers ?? reply.dnsServers)
|
||||
let dnsSettings = NEDNSSettings(servers: cfg.sessionConfiguration.dnsServers ?? reply.options.dnsServers)
|
||||
|
||||
let newSettings = NEPacketTunnelNetworkSettings(tunnelRemoteAddress: remoteAddress)
|
||||
newSettings.ipv4Settings = ipv4Settings
|
||||
|
@ -30,9 +30,9 @@ import __TunnelKitNative
|
||||
private let log = SwiftyBeaver.self
|
||||
|
||||
public struct OptionsBundle {
|
||||
private struct Regex {
|
||||
struct Regex {
|
||||
|
||||
// shared
|
||||
// MARK: General
|
||||
|
||||
static let cipher = NSRegularExpression("^cipher +[^,\\s]+")
|
||||
|
||||
@ -42,6 +42,8 @@ public struct OptionsBundle {
|
||||
|
||||
static let compress = NSRegularExpression("^compress.*")
|
||||
|
||||
static let keyDirection = NSRegularExpression("^key-direction +\\d")
|
||||
|
||||
static let ping = NSRegularExpression("^ping +\\d+")
|
||||
|
||||
static let renegSec = NSRegularExpression("^reneg-sec +\\d+")
|
||||
@ -50,19 +52,7 @@ public struct OptionsBundle {
|
||||
|
||||
static let blockEnd = NSRegularExpression("^<\\/[\\w\\-]+>")
|
||||
|
||||
static let keyDirection = NSRegularExpression("^key-direction +\\d")
|
||||
|
||||
static let gateway = NSRegularExpression("route-gateway [\\d\\.]+")
|
||||
|
||||
static let route = NSRegularExpression("route [\\d\\.]+( [\\d\\.]+){0,2}")
|
||||
|
||||
static let route6 = NSRegularExpression("route-ipv6 [\\da-fA-F:]+/\\d+( [\\da-fA-F:]+){0,2}")
|
||||
|
||||
static let dns = NSRegularExpression("^dhcp-option +DNS6? +[\\d\\.a-fA-F:]+")
|
||||
|
||||
static let remoteRandom = NSRegularExpression("^remote-random")
|
||||
|
||||
// client
|
||||
// MARK: Client
|
||||
|
||||
static let proto = NSRegularExpression("^proto +(udp6?|tcp6?)")
|
||||
|
||||
@ -72,19 +62,31 @@ public struct OptionsBundle {
|
||||
|
||||
static let eku = NSRegularExpression("^remote-cert-tls +server")
|
||||
|
||||
// server
|
||||
static let remoteRandom = NSRegularExpression("^remote-random")
|
||||
|
||||
static let topology = NSRegularExpression("topology (net30|p2p|subnet)")
|
||||
// MARK: Server
|
||||
|
||||
static let ifconfig = NSRegularExpression("ifconfig [\\d\\.]+ [\\d\\.]+")
|
||||
static let authToken = NSRegularExpression("^auth-token +[a-zA-Z0-9/=+]+")
|
||||
|
||||
static let ifconfig6 = NSRegularExpression("ifconfig-ipv6 [\\da-fA-F:]+/\\d+ [\\da-fA-F:]+")
|
||||
static let peerId = NSRegularExpression("^peer-id +[0-9]+")
|
||||
|
||||
static let authToken = NSRegularExpression("auth-token [a-zA-Z0-9/=+]+")
|
||||
// MARK: Routing
|
||||
|
||||
static let peerId = NSRegularExpression("peer-id [0-9]+")
|
||||
static let topology = NSRegularExpression("^topology +(net30|p2p|subnet)")
|
||||
|
||||
// unsupported
|
||||
static let ifconfig = NSRegularExpression("^ifconfig +[\\d\\.]+ [\\d\\.]+")
|
||||
|
||||
static let ifconfig6 = NSRegularExpression("^ifconfig-ipv6 +[\\da-fA-F:]+/\\d+ [\\da-fA-F:]+")
|
||||
|
||||
static let route = NSRegularExpression("^route +[\\d\\.]+( +[\\d\\.]+){0,2}")
|
||||
|
||||
static let route6 = NSRegularExpression("^route-ipv6 +[\\da-fA-F:]+/\\d+( +[\\da-fA-F:]+){0,2}")
|
||||
|
||||
static let gateway = NSRegularExpression("^route-gateway +[\\d\\.]+")
|
||||
|
||||
static let dns = NSRegularExpression("^dhcp-option +DNS6? +[\\d\\.a-fA-F:]+")
|
||||
|
||||
// MARK: Unsupported
|
||||
|
||||
// static let fragment = NSRegularExpression("^fragment +\\d+")
|
||||
static let fragment = NSRegularExpression("^fragment")
|
||||
@ -96,15 +98,19 @@ public struct OptionsBundle {
|
||||
static let connection = NSRegularExpression("^<connection>")
|
||||
}
|
||||
|
||||
private enum Topology: String {
|
||||
case net30
|
||||
|
||||
case p2p
|
||||
|
||||
case subnet
|
||||
}
|
||||
|
||||
public let strippedLines: [String]?
|
||||
|
||||
public let warning: OptionsError?
|
||||
|
||||
//
|
||||
|
||||
public let hostname: String?
|
||||
|
||||
public let remotes: [(String, UInt16, SocketType)]
|
||||
// MARK: General
|
||||
|
||||
public let cipher: SessionProxy.Cipher?
|
||||
|
||||
@ -120,27 +126,43 @@ public struct OptionsBundle {
|
||||
|
||||
public let clientKey: CryptoContainer?
|
||||
|
||||
public let checksEKU: Bool
|
||||
public let tlsWrap: SessionProxy.TLSWrap?
|
||||
|
||||
public let keepAliveSeconds: TimeInterval?
|
||||
|
||||
public let renegotiateAfterSeconds: TimeInterval?
|
||||
|
||||
public let tlsWrap: SessionProxy.TLSWrap?
|
||||
// MARK: Client
|
||||
|
||||
public let dnsServers: [String]
|
||||
public let hostname: String?
|
||||
|
||||
public let remotes: [(String, UInt16, SocketType)]
|
||||
|
||||
public let checksEKU: Bool
|
||||
|
||||
public let randomizeEndpoint: Bool
|
||||
|
||||
// MARK: Server
|
||||
|
||||
public let authToken: String?
|
||||
|
||||
public let peerId: UInt32?
|
||||
|
||||
// MARK: Routing
|
||||
|
||||
public let ipv4: IPv4Settings?
|
||||
|
||||
public let ipv6: IPv6Settings?
|
||||
|
||||
public let dnsServers: [String]
|
||||
|
||||
public init(from lines: [String], returnsStripped: Bool = false) throws {
|
||||
var optStrippedLines: [String]? = returnsStripped ? [] : nil
|
||||
var optWarning: OptionsError?
|
||||
var unsupportedError: OptionsError?
|
||||
var currentBlockName: String?
|
||||
var currentBlock: [String] = []
|
||||
|
||||
var optHostname: String?
|
||||
var optDefaultProto: SocketType?
|
||||
var optDefaultPort: UInt16?
|
||||
var optRemotes: [(String, UInt16?, SocketType?)] = []
|
||||
var optCipher: SessionProxy.Cipher?
|
||||
var optDigest: SessionProxy.Digest?
|
||||
var optCompressionFraming: SessionProxy.CompressionFraming?
|
||||
@ -148,16 +170,30 @@ public struct OptionsBundle {
|
||||
var optCA: CryptoContainer?
|
||||
var optClientCertificate: CryptoContainer?
|
||||
var optClientKey: CryptoContainer?
|
||||
var optChecksEKU: Bool?
|
||||
var optKeepAliveSeconds: TimeInterval?
|
||||
var optRenegotiateAfterSeconds: TimeInterval?
|
||||
var optKeyDirection: StaticKey.Direction?
|
||||
var optTLSKeyLines: [Substring]?
|
||||
var optTLSStrategy: SessionProxy.TLSWrap.Strategy?
|
||||
var optDnsServers: [String] = []
|
||||
var optKeepAliveSeconds: TimeInterval?
|
||||
var optRenegotiateAfterSeconds: TimeInterval?
|
||||
//
|
||||
var optHostname: String?
|
||||
var optDefaultProto: SocketType?
|
||||
var optDefaultPort: UInt16?
|
||||
var optRemotes: [(String, UInt16?, SocketType?)] = [] // address, port, socket
|
||||
var optChecksEKU: Bool?
|
||||
var optRandomizeEndpoint: Bool?
|
||||
var currentBlockName: String?
|
||||
var currentBlock: [String] = []
|
||||
//
|
||||
var optAuthToken: String?
|
||||
var optPeerId: UInt32?
|
||||
//
|
||||
var optTopology: String?
|
||||
var optIfconfig4Arguments: [String]?
|
||||
var optIfconfig6Arguments: [String]?
|
||||
var optGateway4Arguments: [String]?
|
||||
var optGateway6Arguments: [String]?
|
||||
var optRoutes4: [(String, String, String?)] = [] // address, netmask, gateway
|
||||
var optRoutes6: [(String, UInt8, String?)] = [] // destination, prefix, gateway
|
||||
var optDNSServers: [String] = []
|
||||
|
||||
log.verbose("Configuration file:")
|
||||
for line in lines {
|
||||
@ -171,10 +207,26 @@ public struct OptionsBundle {
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: Unsupported
|
||||
|
||||
// check blocks first
|
||||
Regex.connection.enumerateComponents(in: line) { (_) in
|
||||
unsupportedError = OptionsError.unsupportedConfiguration(option: "<connection> blocks")
|
||||
}
|
||||
Regex.fragment.enumerateComponents(in: line) { (_) in
|
||||
unsupportedError = OptionsError.unsupportedConfiguration(option: "fragment")
|
||||
}
|
||||
Regex.proxy.enumerateComponents(in: line) { (_) in
|
||||
unsupportedError = OptionsError.unsupportedConfiguration(option: "proxy: \"\(line)\"")
|
||||
}
|
||||
Regex.externalFiles.enumerateComponents(in: line) { (_) in
|
||||
unsupportedError = OptionsError.unsupportedConfiguration(option: "external file: \"\(line)\"")
|
||||
}
|
||||
if line.contains("mtu") || line.contains("mssfix") {
|
||||
isHandled = true
|
||||
}
|
||||
|
||||
// MARK: Inline content
|
||||
|
||||
if unsupportedError == nil {
|
||||
if currentBlockName == nil {
|
||||
@ -232,47 +284,8 @@ public struct OptionsBundle {
|
||||
continue
|
||||
}
|
||||
|
||||
Regex.eku.enumerateComponents(in: line) { (_) in
|
||||
optChecksEKU = true
|
||||
}
|
||||
Regex.proto.enumerateArguments(in: line) {
|
||||
isHandled = true
|
||||
guard let str = $0.first else {
|
||||
return
|
||||
}
|
||||
optDefaultProto = SocketType(protoString: str)
|
||||
if optDefaultProto == nil {
|
||||
unsupportedError = OptionsError.unsupportedConfiguration(option: "proto \(str)")
|
||||
}
|
||||
}
|
||||
Regex.port.enumerateArguments(in: line) {
|
||||
isHandled = true
|
||||
guard let str = $0.first else {
|
||||
return
|
||||
}
|
||||
optDefaultPort = UInt16(str)
|
||||
}
|
||||
Regex.remote.enumerateArguments(in: line) {
|
||||
isHandled = true
|
||||
guard let hostname = $0.first else {
|
||||
return
|
||||
}
|
||||
var port: UInt16?
|
||||
var proto: SocketType?
|
||||
var strippedComponents = ["remote", "<hostname>"]
|
||||
if $0.count > 1 {
|
||||
port = UInt16($0[1])
|
||||
strippedComponents.append($0[1])
|
||||
}
|
||||
if $0.count > 2 {
|
||||
proto = SocketType(protoString: $0[2])
|
||||
strippedComponents.append($0[2])
|
||||
}
|
||||
optRemotes.append((hostname, port, proto))
|
||||
// MARK: General
|
||||
|
||||
// replace private data
|
||||
strippedLine = strippedComponents.joined(separator: " ")
|
||||
}
|
||||
Regex.cipher.enumerateArguments(in: line) {
|
||||
isHandled = true
|
||||
guard let rawValue = $0.first else {
|
||||
@ -349,29 +362,111 @@ public struct OptionsBundle {
|
||||
}
|
||||
optRenegotiateAfterSeconds = TimeInterval(arg)
|
||||
}
|
||||
|
||||
// MARK: Client
|
||||
|
||||
Regex.proto.enumerateArguments(in: line) {
|
||||
isHandled = true
|
||||
guard let str = $0.first else {
|
||||
return
|
||||
}
|
||||
optDefaultProto = SocketType(protoString: str)
|
||||
if optDefaultProto == nil {
|
||||
unsupportedError = OptionsError.unsupportedConfiguration(option: "proto \(str)")
|
||||
}
|
||||
}
|
||||
Regex.port.enumerateArguments(in: line) {
|
||||
isHandled = true
|
||||
guard let str = $0.first else {
|
||||
return
|
||||
}
|
||||
optDefaultPort = UInt16(str)
|
||||
}
|
||||
Regex.remote.enumerateArguments(in: line) {
|
||||
isHandled = true
|
||||
guard let hostname = $0.first else {
|
||||
return
|
||||
}
|
||||
var port: UInt16?
|
||||
var proto: SocketType?
|
||||
var strippedComponents = ["remote", "<hostname>"]
|
||||
if $0.count > 1 {
|
||||
port = UInt16($0[1])
|
||||
strippedComponents.append($0[1])
|
||||
}
|
||||
if $0.count > 2 {
|
||||
proto = SocketType(protoString: $0[2])
|
||||
strippedComponents.append($0[2])
|
||||
}
|
||||
optRemotes.append((hostname, port, proto))
|
||||
|
||||
// replace private data
|
||||
strippedLine = strippedComponents.joined(separator: " ")
|
||||
}
|
||||
Regex.eku.enumerateComponents(in: line) { (_) in
|
||||
optChecksEKU = true
|
||||
}
|
||||
Regex.remoteRandom.enumerateComponents(in: line) { (_) in
|
||||
optRandomizeEndpoint = true
|
||||
}
|
||||
|
||||
// MARK: Server
|
||||
|
||||
Regex.authToken.enumerateArguments(in: line) {
|
||||
optAuthToken = $0[0]
|
||||
}
|
||||
|
||||
Regex.peerId.enumerateArguments(in: line) {
|
||||
optPeerId = UInt32($0[0])
|
||||
}
|
||||
|
||||
// MARK: Routing
|
||||
|
||||
Regex.topology.enumerateArguments(in: line) {
|
||||
optTopology = $0.first
|
||||
}
|
||||
Regex.ifconfig.enumerateArguments(in: line) {
|
||||
optIfconfig4Arguments = $0
|
||||
}
|
||||
Regex.ifconfig6.enumerateArguments(in: line) {
|
||||
optIfconfig6Arguments = $0
|
||||
}
|
||||
Regex.route.enumerateArguments(in: line) {
|
||||
let routeEntryArguments = $0
|
||||
|
||||
let address = routeEntryArguments[0]
|
||||
let mask = (routeEntryArguments.count > 1) ? routeEntryArguments[1] : "255.255.255.255"
|
||||
let gateway = (routeEntryArguments.count > 2) ? routeEntryArguments[2] : nil // defaultGateway4
|
||||
optRoutes4.append((address, mask, gateway))
|
||||
}
|
||||
Regex.route6.enumerateArguments(in: line) {
|
||||
let routeEntryArguments = $0
|
||||
|
||||
let destinationComponents = routeEntryArguments[0].components(separatedBy: "/")
|
||||
guard destinationComponents.count == 2 else {
|
||||
return
|
||||
}
|
||||
guard let prefix = UInt8(destinationComponents[1]) else {
|
||||
return
|
||||
}
|
||||
|
||||
let destination = destinationComponents[0]
|
||||
let gateway = (routeEntryArguments.count > 1) ? routeEntryArguments[1] : nil // defaultGateway6
|
||||
optRoutes6.append((destination, prefix, gateway))
|
||||
}
|
||||
Regex.gateway.enumerateArguments(in: line) {
|
||||
optGateway4Arguments = $0
|
||||
}
|
||||
Regex.dns.enumerateArguments(in: line) {
|
||||
isHandled = true
|
||||
guard $0.count == 2 else {
|
||||
return
|
||||
}
|
||||
optDnsServers.append($0[1])
|
||||
}
|
||||
Regex.remoteRandom.enumerateComponents(in: line) { (_) in
|
||||
optRandomizeEndpoint = true
|
||||
}
|
||||
Regex.fragment.enumerateComponents(in: line) { (_) in
|
||||
unsupportedError = OptionsError.unsupportedConfiguration(option: "fragment")
|
||||
}
|
||||
Regex.proxy.enumerateComponents(in: line) { (_) in
|
||||
unsupportedError = OptionsError.unsupportedConfiguration(option: "proxy: \"\(line)\"")
|
||||
}
|
||||
Regex.externalFiles.enumerateComponents(in: line) { (_) in
|
||||
unsupportedError = OptionsError.unsupportedConfiguration(option: "external file: \"\(line)\"")
|
||||
}
|
||||
if line.contains("mtu") || line.contains("mssfix") {
|
||||
isHandled = true
|
||||
optDNSServers.append($0[1])
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
if let error = unsupportedError {
|
||||
throw error
|
||||
}
|
||||
@ -382,6 +477,39 @@ public struct OptionsBundle {
|
||||
strippedLines = optStrippedLines
|
||||
warning = optWarning
|
||||
|
||||
// MARK: General
|
||||
|
||||
cipher = optCipher
|
||||
digest = optDigest
|
||||
compressionFraming = optCompressionFraming
|
||||
compressionAlgorithm = optCompressionAlgorithm
|
||||
ca = optCA
|
||||
clientCertificate = optClientCertificate
|
||||
clientKey = optClientKey
|
||||
|
||||
if let keyLines = optTLSKeyLines, let strategy = optTLSStrategy {
|
||||
let optKey: StaticKey?
|
||||
switch strategy {
|
||||
case .auth:
|
||||
optKey = StaticKey(lines: keyLines, direction: optKeyDirection)
|
||||
|
||||
case .crypt:
|
||||
optKey = StaticKey(lines: keyLines, direction: .client)
|
||||
}
|
||||
if let key = optKey {
|
||||
tlsWrap = SessionProxy.TLSWrap(strategy: strategy, key: key)
|
||||
} else {
|
||||
tlsWrap = nil
|
||||
}
|
||||
} else {
|
||||
tlsWrap = nil
|
||||
}
|
||||
|
||||
keepAliveSeconds = optKeepAliveSeconds
|
||||
renegotiateAfterSeconds = optRenegotiateAfterSeconds
|
||||
|
||||
// MARK: Client
|
||||
|
||||
optDefaultProto = optDefaultProto ?? .udp
|
||||
optDefaultPort = optDefaultPort ?? 1194
|
||||
if !optRemotes.isEmpty {
|
||||
@ -407,36 +535,94 @@ public struct OptionsBundle {
|
||||
remotes = []
|
||||
}
|
||||
|
||||
cipher = optCipher
|
||||
digest = optDigest
|
||||
compressionFraming = optCompressionFraming
|
||||
compressionAlgorithm = optCompressionAlgorithm
|
||||
ca = optCA
|
||||
clientCertificate = optClientCertificate
|
||||
clientKey = optClientKey
|
||||
checksEKU = optChecksEKU ?? false
|
||||
keepAliveSeconds = optKeepAliveSeconds
|
||||
renegotiateAfterSeconds = optRenegotiateAfterSeconds
|
||||
dnsServers = optDnsServers
|
||||
randomizeEndpoint = optRandomizeEndpoint ?? false
|
||||
|
||||
if let keyLines = optTLSKeyLines, let strategy = optTLSStrategy {
|
||||
let optKey: StaticKey?
|
||||
switch strategy {
|
||||
case .auth:
|
||||
optKey = StaticKey(lines: keyLines, direction: optKeyDirection)
|
||||
// MARK: Server
|
||||
|
||||
case .crypt:
|
||||
optKey = StaticKey(lines: keyLines, direction: .client)
|
||||
authToken = optAuthToken
|
||||
peerId = optPeerId
|
||||
|
||||
// MARK: Routing
|
||||
|
||||
//
|
||||
// excerpts from OpenVPN manpage
|
||||
//
|
||||
// "--ifconfig l rn":
|
||||
//
|
||||
// Set TUN/TAP adapter parameters. l is the IP address of the local VPN endpoint. For TUN devices in point-to-point mode, rn is the IP address of
|
||||
// the remote VPN endpoint. For TAP devices, or TUN devices used with --topology subnet, rn is the subnet mask of the virtual network segment which
|
||||
// is being created or connected to.
|
||||
//
|
||||
// "--topology mode":
|
||||
//
|
||||
// Note: Using --topology subnet changes the interpretation of the arguments of --ifconfig to mean "address netmask", no longer "local remote".
|
||||
//
|
||||
if let ifconfig4Arguments = optIfconfig4Arguments {
|
||||
guard ifconfig4Arguments.count == 2 else {
|
||||
throw SessionError.malformedPushReply
|
||||
}
|
||||
if let key = optKey {
|
||||
tlsWrap = SessionProxy.TLSWrap(strategy: strategy, key: key)
|
||||
|
||||
let address4: String
|
||||
let addressMask4: String
|
||||
let defaultGateway4: String
|
||||
|
||||
let topology = Topology(rawValue: optTopology ?? "") ?? .net30
|
||||
switch topology {
|
||||
case .subnet:
|
||||
|
||||
// default gateway required when topology is subnet
|
||||
guard let gateway4Arguments = optGateway4Arguments, gateway4Arguments.count == 1 else {
|
||||
throw SessionError.malformedPushReply
|
||||
}
|
||||
address4 = ifconfig4Arguments[0]
|
||||
addressMask4 = ifconfig4Arguments[1]
|
||||
defaultGateway4 = gateway4Arguments[0]
|
||||
|
||||
default:
|
||||
address4 = ifconfig4Arguments[0]
|
||||
addressMask4 = "255.255.255.255"
|
||||
defaultGateway4 = ifconfig4Arguments[1]
|
||||
}
|
||||
let routes4 = optRoutes4.map { IPv4Settings.Route($0.0, $0.1, $0.2 ?? defaultGateway4) }
|
||||
|
||||
ipv4 = IPv4Settings(
|
||||
address: address4,
|
||||
addressMask: addressMask4,
|
||||
defaultGateway: defaultGateway4,
|
||||
routes: routes4
|
||||
)
|
||||
} else {
|
||||
tlsWrap = nil
|
||||
ipv4 = nil
|
||||
}
|
||||
|
||||
if let ifconfig6Arguments = optIfconfig6Arguments {
|
||||
guard ifconfig6Arguments.count == 2 else {
|
||||
throw SessionError.malformedPushReply
|
||||
}
|
||||
let address6Components = ifconfig6Arguments[0].components(separatedBy: "/")
|
||||
guard address6Components.count == 2 else {
|
||||
throw SessionError.malformedPushReply
|
||||
}
|
||||
guard let addressPrefix6 = UInt8(address6Components[1]) else {
|
||||
throw SessionError.malformedPushReply
|
||||
}
|
||||
|
||||
let address6 = address6Components[0]
|
||||
let defaultGateway6 = ifconfig6Arguments[1]
|
||||
let routes6 = optRoutes6.map { IPv6Settings.Route($0.0, $0.1, $0.2 ?? defaultGateway6) }
|
||||
|
||||
ipv6 = IPv6Settings(
|
||||
address: address6,
|
||||
addressPrefixLength: addressPrefix6,
|
||||
defaultGateway: defaultGateway6,
|
||||
routes: routes6
|
||||
)
|
||||
} else {
|
||||
tlsWrap = nil
|
||||
ipv6 = nil
|
||||
}
|
||||
|
||||
dnsServers = optDNSServers
|
||||
}
|
||||
|
||||
private static func normalizeEncryptedPEMBlock(block: inout [String]) {
|
||||
@ -453,6 +639,104 @@ public struct OptionsBundle {
|
||||
}
|
||||
}
|
||||
|
||||
/// Encapsulates the IPv4 settings for the tunnel.
|
||||
public struct IPv4Settings: CustomStringConvertible {
|
||||
|
||||
/// Represents an IPv4 route in the routing table.
|
||||
public struct Route: CustomStringConvertible {
|
||||
|
||||
/// The destination host or subnet.
|
||||
public let destination: String
|
||||
|
||||
/// The address mask.
|
||||
public let mask: String
|
||||
|
||||
/// The address of the gateway (uses default gateway if not set).
|
||||
public let gateway: String?
|
||||
|
||||
fileprivate init(_ destination: String, _ mask: String?, _ gateway: String?) {
|
||||
self.destination = destination
|
||||
self.mask = mask ?? "255.255.255.255"
|
||||
self.gateway = gateway
|
||||
}
|
||||
|
||||
// MARK: CustomStringConvertible
|
||||
|
||||
/// :nodoc:
|
||||
public var description: String {
|
||||
return "{\(destination.maskedDescription)/\(mask) \(gateway?.maskedDescription ?? "default")}"
|
||||
}
|
||||
}
|
||||
|
||||
/// The address.
|
||||
let address: String
|
||||
|
||||
/// The address mask.
|
||||
let addressMask: String
|
||||
|
||||
/// The address of the default gateway.
|
||||
let defaultGateway: String
|
||||
|
||||
/// The additional routes.
|
||||
let routes: [Route]
|
||||
|
||||
// MARK: CustomStringConvertible
|
||||
|
||||
/// :nodoc:
|
||||
public var description: String {
|
||||
return "addr \(address.maskedDescription) netmask \(addressMask) gw \(defaultGateway.maskedDescription) routes \(routes.map { $0.maskedDescription })"
|
||||
}
|
||||
}
|
||||
|
||||
/// Encapsulates the IPv6 settings for the tunnel.
|
||||
public struct IPv6Settings: CustomStringConvertible {
|
||||
|
||||
/// Represents an IPv6 route in the routing table.
|
||||
public struct Route: CustomStringConvertible {
|
||||
|
||||
/// The destination host or subnet.
|
||||
public let destination: String
|
||||
|
||||
/// The address prefix length.
|
||||
public let prefixLength: UInt8
|
||||
|
||||
/// The address of the gateway (uses default gateway if not set).
|
||||
public let gateway: String?
|
||||
|
||||
fileprivate init(_ destination: String, _ prefixLength: UInt8?, _ gateway: String?) {
|
||||
self.destination = destination
|
||||
self.prefixLength = prefixLength ?? 3
|
||||
self.gateway = gateway
|
||||
}
|
||||
|
||||
// MARK: CustomStringConvertible
|
||||
|
||||
/// :nodoc:
|
||||
public var description: String {
|
||||
return "{\(destination.maskedDescription)/\(prefixLength) \(gateway?.maskedDescription ?? "default")}"
|
||||
}
|
||||
}
|
||||
|
||||
/// The address.
|
||||
public let address: String
|
||||
|
||||
/// The address prefix length.
|
||||
public let addressPrefixLength: UInt8
|
||||
|
||||
/// The address of the default gateway.
|
||||
public let defaultGateway: String
|
||||
|
||||
/// The additional routes.
|
||||
public let routes: [Route]
|
||||
|
||||
// MARK: CustomStringConvertible
|
||||
|
||||
/// :nodoc:
|
||||
public var description: String {
|
||||
return "addr \(address.maskedDescription)/\(addressPrefixLength) gw \(defaultGateway.maskedDescription) routes \(routes.map { $0.maskedDescription })"
|
||||
}
|
||||
}
|
||||
|
||||
private extension SocketType {
|
||||
init?(protoString: String) {
|
||||
var str = protoString
|
||||
|
@ -37,133 +37,11 @@
|
||||
|
||||
import Foundation
|
||||
|
||||
/// Encapsulates the IPv4 settings for the tunnel.
|
||||
public struct IPv4Settings: CustomStringConvertible {
|
||||
|
||||
/// Represents an IPv4 route in the routing table.
|
||||
public struct Route: CustomStringConvertible {
|
||||
|
||||
/// The destination host or subnet.
|
||||
public let destination: String
|
||||
|
||||
/// The address mask.
|
||||
public let mask: String
|
||||
|
||||
/// The address of the gateway (uses default gateway if not set).
|
||||
public let gateway: String?
|
||||
|
||||
fileprivate init(_ destination: String, _ mask: String?, _ gateway: String?) {
|
||||
self.destination = destination
|
||||
self.mask = mask ?? "255.255.255.255"
|
||||
self.gateway = gateway
|
||||
}
|
||||
|
||||
// MARK: CustomStringConvertible
|
||||
|
||||
/// :nodoc:
|
||||
public var description: String {
|
||||
return "{\(destination.maskedDescription)/\(mask) \(gateway?.maskedDescription ?? "default")}"
|
||||
}
|
||||
}
|
||||
|
||||
/// The address.
|
||||
let address: String
|
||||
|
||||
/// The address mask.
|
||||
let addressMask: String
|
||||
|
||||
/// The address of the default gateway.
|
||||
let defaultGateway: String
|
||||
|
||||
/// The additional routes.
|
||||
let routes: [Route]
|
||||
|
||||
// MARK: CustomStringConvertible
|
||||
|
||||
/// :nodoc:
|
||||
public var description: String {
|
||||
return "addr \(address.maskedDescription) netmask \(addressMask) gw \(defaultGateway.maskedDescription) routes \(routes.map { $0.maskedDescription })"
|
||||
}
|
||||
}
|
||||
|
||||
/// Encapsulates the IPv6 settings for the tunnel.
|
||||
public struct IPv6Settings: CustomStringConvertible {
|
||||
|
||||
/// Represents an IPv6 route in the routing table.
|
||||
public struct Route: CustomStringConvertible {
|
||||
|
||||
/// The destination host or subnet.
|
||||
public let destination: String
|
||||
|
||||
/// The address prefix length.
|
||||
public let prefixLength: UInt8
|
||||
|
||||
/// The address of the gateway (uses default gateway if not set).
|
||||
public let gateway: String?
|
||||
|
||||
fileprivate init(_ destination: String, _ prefixLength: UInt8?, _ gateway: String?) {
|
||||
self.destination = destination
|
||||
self.prefixLength = prefixLength ?? 3
|
||||
self.gateway = gateway
|
||||
}
|
||||
|
||||
// MARK: CustomStringConvertible
|
||||
|
||||
/// :nodoc:
|
||||
public var description: String {
|
||||
return "{\(destination.maskedDescription)/\(prefixLength) \(gateway?.maskedDescription ?? "default")}"
|
||||
}
|
||||
}
|
||||
|
||||
/// The address.
|
||||
public let address: String
|
||||
|
||||
/// The address prefix length.
|
||||
public let addressPrefixLength: UInt8
|
||||
|
||||
/// The address of the default gateway.
|
||||
public let defaultGateway: String
|
||||
|
||||
/// The additional routes.
|
||||
public let routes: [Route]
|
||||
|
||||
// MARK: CustomStringConvertible
|
||||
|
||||
/// :nodoc:
|
||||
public var description: String {
|
||||
return "addr \(address.maskedDescription)/\(addressPrefixLength) gw \(defaultGateway.maskedDescription) routes \(routes.map { $0.maskedDescription })"
|
||||
}
|
||||
}
|
||||
|
||||
/// Groups the parsed reply of a successfully started session.
|
||||
public protocol SessionReply {
|
||||
|
||||
/// The IPv4 settings.
|
||||
var ipv4: IPv4Settings? { get }
|
||||
|
||||
/// The IPv6 settings.
|
||||
var ipv6: IPv6Settings? { get }
|
||||
|
||||
/// The DNS servers set up for this session.
|
||||
var dnsServers: [String] { get }
|
||||
|
||||
/// The optional compression framing.
|
||||
var compressionFraming: SessionProxy.CompressionFraming? { get }
|
||||
|
||||
/// The optional compression algorithm.
|
||||
var compressionAlgorithm: SessionProxy.CompressionAlgorithm? { get }
|
||||
|
||||
/// The optional keep-alive interval.
|
||||
var ping: Int? { get }
|
||||
|
||||
/// The optional authentication token.
|
||||
var authToken: String? { get }
|
||||
|
||||
/// The optional 24-bit peer-id.
|
||||
var peerId: UInt32? { get }
|
||||
|
||||
/// The negotiated cipher if any (NCP).
|
||||
var cipher: SessionProxy.Cipher? { get }
|
||||
/// The returned options.
|
||||
var options: OptionsBundle { get }
|
||||
}
|
||||
|
||||
extension SessionProxy {
|
||||
@ -171,61 +49,11 @@ extension SessionProxy {
|
||||
// XXX: parsing is very optimistic
|
||||
|
||||
struct PushReply: SessionReply, CustomStringConvertible {
|
||||
private enum Topology: String {
|
||||
case net30
|
||||
|
||||
case p2p
|
||||
|
||||
case subnet
|
||||
}
|
||||
|
||||
private static let prefix = "PUSH_REPLY,"
|
||||
|
||||
private struct Regex {
|
||||
static let topology = NSRegularExpression("topology (net30|p2p|subnet)")
|
||||
|
||||
static let ifconfig = NSRegularExpression("ifconfig [\\d\\.]+ [\\d\\.]+")
|
||||
|
||||
static let ifconfig6 = NSRegularExpression("ifconfig-ipv6 [\\da-fA-F:]+/\\d+ [\\da-fA-F:]+")
|
||||
|
||||
static let gateway = NSRegularExpression("route-gateway [\\d\\.]+")
|
||||
|
||||
static let route = NSRegularExpression("route [\\d\\.]+( [\\d\\.]+){0,2}")
|
||||
|
||||
static let route6 = NSRegularExpression("route-ipv6 [\\da-fA-F:]+/\\d+( [\\da-fA-F:]+){0,2}")
|
||||
|
||||
static let dns = NSRegularExpression("dhcp-option DNS6? [\\d\\.a-fA-F:]+")
|
||||
|
||||
static let comp = NSRegularExpression("comp(ress|-lzo)[ \\w]*")
|
||||
|
||||
static let ping = NSRegularExpression("ping \\d+")
|
||||
|
||||
static let authToken = NSRegularExpression("auth-token [a-zA-Z0-9/=+]+")
|
||||
|
||||
static let peerId = NSRegularExpression("peer-id [0-9]+")
|
||||
|
||||
static let cipher = NSRegularExpression("cipher [^,\\s]+")
|
||||
}
|
||||
|
||||
private let original: String
|
||||
|
||||
let ipv4: IPv4Settings?
|
||||
|
||||
let ipv6: IPv6Settings?
|
||||
|
||||
let dnsServers: [String]
|
||||
|
||||
let compressionFraming: SessionProxy.CompressionFraming?
|
||||
|
||||
let compressionAlgorithm: SessionProxy.CompressionAlgorithm?
|
||||
|
||||
let ping: Int?
|
||||
|
||||
let authToken: String?
|
||||
|
||||
let peerId: UInt32?
|
||||
|
||||
let cipher: SessionProxy.Cipher?
|
||||
let options: OptionsBundle
|
||||
|
||||
init?(message: String) throws {
|
||||
guard message.hasPrefix(PushReply.prefix) else {
|
||||
@ -236,224 +64,15 @@ extension SessionProxy {
|
||||
}
|
||||
original = String(message[prefixIndex...])
|
||||
|
||||
var optTopologyArguments: [String]?
|
||||
var optIfconfig4Arguments: [String]?
|
||||
var optGateway4Arguments: [String]?
|
||||
let address4: String
|
||||
let addressMask4: String
|
||||
let defaultGateway4: String
|
||||
var routes4: [IPv4Settings.Route] = []
|
||||
|
||||
var optIfconfig6Arguments: [String]?
|
||||
|
||||
var dnsServers: [String] = []
|
||||
var compressionFraming: SessionProxy.CompressionFraming?
|
||||
var compressionAlgorithm: SessionProxy.CompressionAlgorithm?
|
||||
var ping: Int?
|
||||
var authToken: String?
|
||||
var peerId: UInt32?
|
||||
var cipher: SessionProxy.Cipher?
|
||||
|
||||
// MARK: Routing (IPv4)
|
||||
|
||||
Regex.topology.enumerateArguments(in: message) {
|
||||
optTopologyArguments = $0
|
||||
}
|
||||
guard let topologyArguments = optTopologyArguments, topologyArguments.count == 1 else {
|
||||
throw SessionError.malformedPushReply
|
||||
}
|
||||
|
||||
// assumes "topology" to be always pushed to clients, even when not explicitly set (defaults to net30)
|
||||
guard let topology = Topology(rawValue: topologyArguments[0]) else {
|
||||
fatalError("Bad topology regexp, accepted unrecognized value: \(topologyArguments[0])")
|
||||
}
|
||||
|
||||
Regex.ifconfig.enumerateArguments(in: message) {
|
||||
optIfconfig4Arguments = $0
|
||||
}
|
||||
guard let ifconfig4Arguments = optIfconfig4Arguments, ifconfig4Arguments.count == 2 else {
|
||||
throw SessionError.malformedPushReply
|
||||
}
|
||||
|
||||
Regex.gateway.enumerateArguments(in: message) {
|
||||
optGateway4Arguments = $0
|
||||
}
|
||||
|
||||
//
|
||||
// excerpts from OpenVPN manpage
|
||||
//
|
||||
// "--ifconfig l rn":
|
||||
//
|
||||
// Set TUN/TAP adapter parameters. l is the IP address of the local VPN endpoint. For TUN devices in point-to-point mode, rn is the IP address of
|
||||
// the remote VPN endpoint. For TAP devices, or TUN devices used with --topology subnet, rn is the subnet mask of the virtual network segment which
|
||||
// is being created or connected to.
|
||||
//
|
||||
// "--topology mode":
|
||||
//
|
||||
// Note: Using --topology subnet changes the interpretation of the arguments of --ifconfig to mean "address netmask", no longer "local remote".
|
||||
//
|
||||
switch topology {
|
||||
case .subnet:
|
||||
|
||||
// default gateway required when topology is subnet
|
||||
guard let gateway4Arguments = optGateway4Arguments, gateway4Arguments.count == 1 else {
|
||||
throw SessionError.malformedPushReply
|
||||
}
|
||||
address4 = ifconfig4Arguments[0]
|
||||
addressMask4 = ifconfig4Arguments[1]
|
||||
defaultGateway4 = gateway4Arguments[0]
|
||||
|
||||
default:
|
||||
address4 = ifconfig4Arguments[0]
|
||||
addressMask4 = "255.255.255.255"
|
||||
defaultGateway4 = ifconfig4Arguments[1]
|
||||
}
|
||||
|
||||
Regex.route.enumerateArguments(in: message) {
|
||||
let routeEntryArguments = $0
|
||||
|
||||
let address = routeEntryArguments[0]
|
||||
let mask: String?
|
||||
let gateway: String?
|
||||
if routeEntryArguments.count > 1 {
|
||||
mask = routeEntryArguments[1]
|
||||
} else {
|
||||
mask = nil
|
||||
}
|
||||
if routeEntryArguments.count > 2 {
|
||||
gateway = routeEntryArguments[2]
|
||||
} else {
|
||||
gateway = defaultGateway4
|
||||
}
|
||||
routes4.append(IPv4Settings.Route(address, mask, gateway))
|
||||
}
|
||||
|
||||
ipv4 = IPv4Settings(
|
||||
address: address4,
|
||||
addressMask: addressMask4,
|
||||
defaultGateway: defaultGateway4,
|
||||
routes: routes4
|
||||
)
|
||||
|
||||
// MARK: Routing (IPv6)
|
||||
|
||||
Regex.ifconfig6.enumerateArguments(in: message) {
|
||||
optIfconfig6Arguments = $0
|
||||
}
|
||||
if let ifconfig6Arguments = optIfconfig6Arguments, ifconfig6Arguments.count == 2 {
|
||||
let address6Components = ifconfig6Arguments[0].components(separatedBy: "/")
|
||||
guard address6Components.count == 2 else {
|
||||
throw SessionError.malformedPushReply
|
||||
}
|
||||
guard let addressPrefix6 = UInt8(address6Components[1]) else {
|
||||
throw SessionError.malformedPushReply
|
||||
}
|
||||
let address6 = address6Components[0]
|
||||
let defaultGateway6 = ifconfig6Arguments[1]
|
||||
|
||||
var routes6: [IPv6Settings.Route] = []
|
||||
Regex.route6.enumerateArguments(in: message) {
|
||||
let routeEntryArguments = $0
|
||||
|
||||
let destinationComponents = routeEntryArguments[0].components(separatedBy: "/")
|
||||
guard destinationComponents.count == 2 else {
|
||||
// throw SessionError.malformedPushReply
|
||||
return
|
||||
}
|
||||
guard let prefix = UInt8(destinationComponents[1]) else {
|
||||
// throw SessionError.malformedPushReply
|
||||
return
|
||||
}
|
||||
|
||||
let destination = destinationComponents[0]
|
||||
let gateway: String?
|
||||
if routeEntryArguments.count > 1 {
|
||||
gateway = routeEntryArguments[1]
|
||||
} else {
|
||||
gateway = defaultGateway6
|
||||
}
|
||||
routes6.append(IPv6Settings.Route(destination, prefix, gateway))
|
||||
}
|
||||
|
||||
ipv6 = IPv6Settings(
|
||||
address: address6,
|
||||
addressPrefixLength: addressPrefix6,
|
||||
defaultGateway: defaultGateway6,
|
||||
routes: routes6
|
||||
)
|
||||
} else {
|
||||
ipv6 = nil
|
||||
}
|
||||
|
||||
// MARK: DNS
|
||||
|
||||
Regex.dns.enumerateArguments(in: message) {
|
||||
dnsServers.append($0[1])
|
||||
}
|
||||
|
||||
// MARK: Compression
|
||||
|
||||
Regex.comp.enumerateComponents(in: message) {
|
||||
switch $0[0] {
|
||||
case "comp-lzo":
|
||||
compressionFraming = .compLZO
|
||||
if ($0.count == 2) && ($0[1] == "no") {
|
||||
compressionAlgorithm = .disabled
|
||||
} else {
|
||||
compressionAlgorithm = .LZO
|
||||
}
|
||||
|
||||
case "compress":
|
||||
compressionFraming = .compress
|
||||
if $0.count == 1 {
|
||||
compressionAlgorithm = .disabled
|
||||
} else if ($0.count == 2) && ($0[1] == "lzo") {
|
||||
compressionAlgorithm = .LZO
|
||||
} else {
|
||||
compressionAlgorithm = .other
|
||||
}
|
||||
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: Keep-alive
|
||||
|
||||
Regex.ping.enumerateArguments(in: message) {
|
||||
ping = Int($0[0])
|
||||
}
|
||||
|
||||
// MARK: Authentication
|
||||
|
||||
Regex.authToken.enumerateArguments(in: message) {
|
||||
authToken = $0[0]
|
||||
}
|
||||
|
||||
Regex.peerId.enumerateArguments(in: message) {
|
||||
peerId = UInt32($0[0])
|
||||
}
|
||||
|
||||
// MARK: NCP
|
||||
|
||||
Regex.cipher.enumerateArguments(in: message) {
|
||||
cipher = SessionProxy.Cipher(rawValue: $0[0].uppercased())
|
||||
}
|
||||
|
||||
self.dnsServers = dnsServers
|
||||
self.compressionFraming = compressionFraming
|
||||
self.compressionAlgorithm = compressionAlgorithm
|
||||
self.ping = ping
|
||||
self.authToken = authToken
|
||||
self.peerId = peerId
|
||||
self.cipher = cipher
|
||||
let lines = original.components(separatedBy: ",")
|
||||
options = try OptionsBundle(from: lines)
|
||||
}
|
||||
|
||||
// MARK: CustomStringConvertible
|
||||
|
||||
var description: String {
|
||||
let stripped = NSMutableString(string: original)
|
||||
Regex.authToken.replaceMatches(
|
||||
OptionsBundle.Regex.authToken.replaceMatches(
|
||||
in: stripped,
|
||||
options: [],
|
||||
range: NSMakeRange(0, stripped.length),
|
||||
|
@ -86,7 +86,7 @@ public class SessionProxy {
|
||||
|
||||
private var keepAliveInterval: TimeInterval? {
|
||||
let interval: TimeInterval?
|
||||
if let negInterval = pushReply?.ping, negInterval > 0 {
|
||||
if let negInterval = pushReply?.options.keepAliveSeconds, negInterval > 0 {
|
||||
interval = TimeInterval(negInterval)
|
||||
} else if let cfgInterval = configuration.keepAliveInterval, cfgInterval > 0.0 {
|
||||
interval = cfgInterval
|
||||
@ -276,7 +276,7 @@ public class SessionProxy {
|
||||
- Seealso: `canRebindLink()`.
|
||||
*/
|
||||
public func rebindLink(_ link: LinkInterface) {
|
||||
guard let _ = pushReply?.peerId else {
|
||||
guard let _ = pushReply?.options.peerId else {
|
||||
log.warning("Session doesn't support link rebinding!")
|
||||
return
|
||||
}
|
||||
@ -666,7 +666,7 @@ public class SessionProxy {
|
||||
negotiationKey.controlState = .preAuth
|
||||
|
||||
do {
|
||||
authenticator = try Authenticator(credentials?.username, pushReply?.authToken ?? credentials?.password)
|
||||
authenticator = try Authenticator(credentials?.username, pushReply?.options.authToken ?? credentials?.password)
|
||||
try authenticator?.putAuth(into: negotiationKey.tls)
|
||||
} catch let e {
|
||||
deferStop(.shutdown, e)
|
||||
@ -919,7 +919,7 @@ public class SessionProxy {
|
||||
reply = optionalReply
|
||||
log.debug("Received PUSH_REPLY: \"\(reply.maskedDescription)\"")
|
||||
|
||||
if let framing = reply.compressionFraming, let compression = reply.compressionAlgorithm {
|
||||
if let framing = reply.options.compressionFraming, let compression = reply.options.compressionAlgorithm {
|
||||
switch compression {
|
||||
case .disabled:
|
||||
break
|
||||
@ -1036,18 +1036,18 @@ public class SessionProxy {
|
||||
log.debug("Set up encryption")
|
||||
}
|
||||
|
||||
let pushedFraming = pushReply.compressionFraming
|
||||
let pushedFraming = pushReply.options.compressionFraming
|
||||
if let negFraming = pushedFraming {
|
||||
log.info("\tNegotiated compression framing: \(negFraming)")
|
||||
}
|
||||
let pushedCompression = pushReply.compressionAlgorithm
|
||||
let pushedCompression = pushReply.options.compressionAlgorithm
|
||||
if let negCompression = pushedCompression {
|
||||
log.info("\tNegotiated compression algorithm: \(negCompression)")
|
||||
}
|
||||
if let negPing = pushReply.ping {
|
||||
if let negPing = pushReply.options.keepAliveSeconds {
|
||||
log.info("\tNegotiated keep-alive: \(negPing) seconds")
|
||||
}
|
||||
let pushedCipher = pushReply.cipher
|
||||
let pushedCipher = pushReply.options.cipher
|
||||
if let negCipher = pushedCipher {
|
||||
log.info("\tNegotiated cipher: \(negCipher.rawValue)")
|
||||
}
|
||||
@ -1069,7 +1069,7 @@ public class SessionProxy {
|
||||
negotiationKey.dataPath = DataPath(
|
||||
encrypter: bridge.encrypter(),
|
||||
decrypter: bridge.decrypter(),
|
||||
peerId: pushReply.peerId ?? PacketPeerIdDisabled,
|
||||
peerId: pushReply.options.peerId ?? PacketPeerIdDisabled,
|
||||
compressionFraming: (pushedFraming ?? configuration.compressionFraming).native,
|
||||
compressionAlgorithm: (pushedCompression ?? configuration.compressionAlgorithm ?? .disabled).native,
|
||||
maxPackets: link?.packetBufferSize ?? 200,
|
||||
|
@ -28,11 +28,11 @@ import XCTest
|
||||
|
||||
private extension SessionReply {
|
||||
func debug() {
|
||||
print("Compression framing: \(compressionFraming?.description ?? "none")")
|
||||
print("Compression algorithm: \(compressionAlgorithm?.description ?? "none")")
|
||||
print("IPv4: \(ipv4?.description ?? "none")")
|
||||
print("IPv6: \(ipv6?.description ?? "none")")
|
||||
print("DNS: \(dnsServers)")
|
||||
print("Compression framing: \(options.compressionFraming?.description ?? "none")")
|
||||
print("Compression algorithm: \(options.compressionAlgorithm?.description ?? "none")")
|
||||
print("IPv4: \(options.ipv4?.description ?? "none")")
|
||||
print("IPv6: \(options.ipv6?.description ?? "none")")
|
||||
print("DNS: \(options.dnsServers)")
|
||||
}
|
||||
}
|
||||
|
||||
@ -51,10 +51,10 @@ class PushTests: XCTestCase {
|
||||
let reply = try! SessionProxy.PushReply(message: msg)!
|
||||
reply.debug()
|
||||
|
||||
XCTAssertEqual(reply.ipv4?.address, "10.5.10.6")
|
||||
XCTAssertEqual(reply.ipv4?.addressMask, "255.255.255.255")
|
||||
XCTAssertEqual(reply.ipv4?.defaultGateway, "10.5.10.5")
|
||||
XCTAssertEqual(reply.dnsServers, ["209.222.18.222", "209.222.18.218"])
|
||||
XCTAssertEqual(reply.options.ipv4?.address, "10.5.10.6")
|
||||
XCTAssertEqual(reply.options.ipv4?.addressMask, "255.255.255.255")
|
||||
XCTAssertEqual(reply.options.ipv4?.defaultGateway, "10.5.10.5")
|
||||
XCTAssertEqual(reply.options.dnsServers, ["209.222.18.222", "209.222.18.218"])
|
||||
}
|
||||
|
||||
func testSubnet() {
|
||||
@ -62,10 +62,10 @@ class PushTests: XCTestCase {
|
||||
let reply = try! SessionProxy.PushReply(message: msg)!
|
||||
reply.debug()
|
||||
|
||||
XCTAssertEqual(reply.ipv4?.address, "10.8.0.2")
|
||||
XCTAssertEqual(reply.ipv4?.addressMask, "255.255.255.0")
|
||||
XCTAssertEqual(reply.ipv4?.defaultGateway, "10.8.0.1")
|
||||
XCTAssertEqual(reply.dnsServers, ["8.8.8.8", "4.4.4.4"])
|
||||
XCTAssertEqual(reply.options.ipv4?.address, "10.8.0.2")
|
||||
XCTAssertEqual(reply.options.ipv4?.addressMask, "255.255.255.0")
|
||||
XCTAssertEqual(reply.options.ipv4?.defaultGateway, "10.8.0.1")
|
||||
XCTAssertEqual(reply.options.dnsServers, ["8.8.8.8", "4.4.4.4"])
|
||||
}
|
||||
|
||||
func testRoute() {
|
||||
@ -73,7 +73,7 @@ class PushTests: XCTestCase {
|
||||
let reply = try! SessionProxy.PushReply(message: msg)!
|
||||
reply.debug()
|
||||
|
||||
let route = reply.ipv4!.routes.first!
|
||||
let route = reply.options.ipv4!.routes.first!
|
||||
|
||||
XCTAssertEqual(route.destination, "192.168.0.0")
|
||||
XCTAssertEqual(route.mask, "255.255.255.0")
|
||||
@ -85,13 +85,13 @@ class PushTests: XCTestCase {
|
||||
let reply = try! SessionProxy.PushReply(message: msg)!
|
||||
reply.debug()
|
||||
|
||||
XCTAssertEqual(reply.ipv4?.address, "10.8.0.2")
|
||||
XCTAssertEqual(reply.ipv4?.addressMask, "255.255.255.0")
|
||||
XCTAssertEqual(reply.ipv4?.defaultGateway, "10.8.0.1")
|
||||
XCTAssertEqual(reply.ipv6?.address, "fe80::601:30ff:feb7:ec01")
|
||||
XCTAssertEqual(reply.ipv6?.addressPrefixLength, 64)
|
||||
XCTAssertEqual(reply.ipv6?.defaultGateway, "fe80::601:30ff:feb7:dc02")
|
||||
XCTAssertEqual(reply.dnsServers, ["2001:4860:4860::8888", "2001:4860:4860::8844"])
|
||||
XCTAssertEqual(reply.options.ipv4?.address, "10.8.0.2")
|
||||
XCTAssertEqual(reply.options.ipv4?.addressMask, "255.255.255.0")
|
||||
XCTAssertEqual(reply.options.ipv4?.defaultGateway, "10.8.0.1")
|
||||
XCTAssertEqual(reply.options.ipv6?.address, "fe80::601:30ff:feb7:ec01")
|
||||
XCTAssertEqual(reply.options.ipv6?.addressPrefixLength, 64)
|
||||
XCTAssertEqual(reply.options.ipv6?.defaultGateway, "fe80::601:30ff:feb7:dc02")
|
||||
XCTAssertEqual(reply.options.dnsServers, ["2001:4860:4860::8888", "2001:4860:4860::8844"])
|
||||
}
|
||||
|
||||
func testCompressionFraming() {
|
||||
@ -99,7 +99,7 @@ class PushTests: XCTestCase {
|
||||
let reply = try! SessionProxy.PushReply(message: msg)!
|
||||
reply.debug()
|
||||
|
||||
XCTAssertEqual(reply.compressionFraming, .compLZO)
|
||||
XCTAssertEqual(reply.options.compressionFraming, .compLZO)
|
||||
}
|
||||
|
||||
func testCompression() {
|
||||
@ -108,28 +108,28 @@ class PushTests: XCTestCase {
|
||||
|
||||
reply = try! SessionProxy.PushReply(message: msg.appending(",comp-lzo no"))!
|
||||
reply.debug()
|
||||
XCTAssertEqual(reply.compressionFraming, .compLZO)
|
||||
XCTAssertEqual(reply.compressionAlgorithm, .disabled)
|
||||
XCTAssertEqual(reply.options.compressionFraming, .compLZO)
|
||||
XCTAssertEqual(reply.options.compressionAlgorithm, .disabled)
|
||||
|
||||
reply = try! SessionProxy.PushReply(message: msg.appending(",comp-lzo"))!
|
||||
reply.debug()
|
||||
XCTAssertEqual(reply.compressionFraming, .compLZO)
|
||||
XCTAssertEqual(reply.compressionAlgorithm, .LZO)
|
||||
XCTAssertEqual(reply.options.compressionFraming, .compLZO)
|
||||
XCTAssertEqual(reply.options.compressionAlgorithm, .LZO)
|
||||
|
||||
reply = try! SessionProxy.PushReply(message: msg.appending(",comp-lzo yes"))!
|
||||
reply.debug()
|
||||
XCTAssertEqual(reply.compressionFraming, .compLZO)
|
||||
XCTAssertEqual(reply.compressionAlgorithm, .LZO)
|
||||
XCTAssertEqual(reply.options.compressionFraming, .compLZO)
|
||||
XCTAssertEqual(reply.options.compressionAlgorithm, .LZO)
|
||||
|
||||
reply = try! SessionProxy.PushReply(message: msg.appending(",compress"))!
|
||||
reply.debug()
|
||||
XCTAssertEqual(reply.compressionFraming, .compress)
|
||||
XCTAssertEqual(reply.compressionAlgorithm, .disabled)
|
||||
XCTAssertEqual(reply.options.compressionFraming, .compress)
|
||||
XCTAssertEqual(reply.options.compressionAlgorithm, .disabled)
|
||||
|
||||
reply = try! SessionProxy.PushReply(message: msg.appending(",compress lz4"))!
|
||||
reply.debug()
|
||||
XCTAssertEqual(reply.compressionFraming, .compress)
|
||||
XCTAssertEqual(reply.compressionAlgorithm, .other)
|
||||
XCTAssertEqual(reply.options.compressionFraming, .compress)
|
||||
XCTAssertEqual(reply.options.compressionAlgorithm, .other)
|
||||
}
|
||||
|
||||
func testNCP() {
|
||||
@ -137,7 +137,7 @@ class PushTests: XCTestCase {
|
||||
let reply = try! SessionProxy.PushReply(message: msg)!
|
||||
reply.debug()
|
||||
|
||||
XCTAssertEqual(reply.cipher, .aes256gcm)
|
||||
XCTAssertEqual(reply.options.cipher, .aes256gcm)
|
||||
}
|
||||
|
||||
func testNCPTrailing() {
|
||||
@ -145,7 +145,7 @@ class PushTests: XCTestCase {
|
||||
let reply = try! SessionProxy.PushReply(message: msg)!
|
||||
reply.debug()
|
||||
|
||||
XCTAssertEqual(reply.cipher, .aes256gcm)
|
||||
XCTAssertEqual(reply.options.cipher, .aes256gcm)
|
||||
}
|
||||
|
||||
func testPing() {
|
||||
@ -153,6 +153,6 @@ class PushTests: XCTestCase {
|
||||
let reply = try! SessionProxy.PushReply(message: msg)!
|
||||
reply.debug()
|
||||
|
||||
XCTAssertEqual(reply.ping, 10)
|
||||
XCTAssertEqual(reply.options.keepAliveSeconds, 10)
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user