Extend PUSH_REPLY parsing
- Topology - Routes Use the less confusing defaultGateway vs gatewayAddress.
This commit is contained in:
parent
5bf7813d56
commit
b0d264889c
|
@ -459,7 +459,7 @@ extension TunnelKitProvider: SessionProxyDelegate {
|
||||||
log.info("Returned ifconfig parameters:")
|
log.info("Returned ifconfig parameters:")
|
||||||
log.info("\tRemote: \(remoteAddress)")
|
log.info("\tRemote: \(remoteAddress)")
|
||||||
log.info("\tLocal: \(reply.address)/\(reply.addressMask)")
|
log.info("\tLocal: \(reply.address)/\(reply.addressMask)")
|
||||||
log.info("\tGateway: \(reply.gatewayAddress)")
|
log.info("\tGateway: \(reply.defaultGateway)")
|
||||||
log.info("\tDNS: \(reply.dnsServers)")
|
log.info("\tDNS: \(reply.dnsServers)")
|
||||||
|
|
||||||
bringNetworkUp(remoteAddress: remoteAddress, reply: reply) { (error) in
|
bringNetworkUp(remoteAddress: remoteAddress, reply: reply) { (error) in
|
||||||
|
@ -493,10 +493,17 @@ extension TunnelKitProvider: SessionProxyDelegate {
|
||||||
|
|
||||||
// route all traffic to VPN
|
// route all traffic to VPN
|
||||||
let defaultRoute = NEIPv4Route.default()
|
let defaultRoute = NEIPv4Route.default()
|
||||||
defaultRoute.gatewayAddress = reply.gatewayAddress
|
defaultRoute.gatewayAddress = reply.defaultGateway
|
||||||
|
|
||||||
|
var routes: [NEIPv4Route] = [defaultRoute]
|
||||||
|
for r in reply.routes {
|
||||||
|
let ipv4Route = NEIPv4Route(destinationAddress: r.destination, subnetMask: r.mask)
|
||||||
|
ipv4Route.gatewayAddress = r.gateway ?? reply.defaultGateway
|
||||||
|
routes.append(ipv4Route)
|
||||||
|
}
|
||||||
|
|
||||||
let ipv4Settings = NEIPv4Settings(addresses: [reply.address], subnetMasks: [reply.addressMask])
|
let ipv4Settings = NEIPv4Settings(addresses: [reply.address], subnetMasks: [reply.addressMask])
|
||||||
ipv4Settings.includedRoutes = [defaultRoute]
|
ipv4Settings.includedRoutes = routes
|
||||||
ipv4Settings.excludedRoutes = []
|
ipv4Settings.excludedRoutes = []
|
||||||
|
|
||||||
let dnsSettings = NEDNSSettings(servers: reply.dnsServers)
|
let dnsSettings = NEDNSSettings(servers: reply.dnsServers)
|
||||||
|
|
|
@ -47,7 +47,10 @@ public protocol SessionReply {
|
||||||
var addressMask: String { get }
|
var addressMask: String { get }
|
||||||
|
|
||||||
/// The address of the default gateway.
|
/// The address of the default gateway.
|
||||||
var gatewayAddress: String { get }
|
var defaultGateway: String { get }
|
||||||
|
|
||||||
|
/// The additional routes.
|
||||||
|
var routes: [SessionProxy.Route] { get }
|
||||||
|
|
||||||
/// The DNS servers set up for this session.
|
/// The DNS servers set up for this session.
|
||||||
var dnsServers: [String] { get }
|
var dnsServers: [String] { get }
|
||||||
|
@ -57,9 +60,42 @@ extension SessionProxy {
|
||||||
|
|
||||||
// XXX: parsing is very optimistic
|
// XXX: parsing is very optimistic
|
||||||
|
|
||||||
|
/// Represents a route in the routing table.
|
||||||
|
public struct Route {
|
||||||
|
|
||||||
|
/// 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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
struct PushReply: SessionReply {
|
struct PushReply: SessionReply {
|
||||||
|
private enum Topology: String {
|
||||||
|
case net30
|
||||||
|
|
||||||
|
case p2p
|
||||||
|
|
||||||
|
case subnet
|
||||||
|
}
|
||||||
|
|
||||||
|
private static let topologyRegexp = try! NSRegularExpression(pattern: "topology (net30|p2p|subnet)", options: [])
|
||||||
|
|
||||||
private static let ifconfigRegexp = try! NSRegularExpression(pattern: "ifconfig [\\d\\.]+ [\\d\\.]+", options: [])
|
private static let ifconfigRegexp = try! NSRegularExpression(pattern: "ifconfig [\\d\\.]+ [\\d\\.]+", options: [])
|
||||||
|
|
||||||
|
private static let gatewayRegexp = try! NSRegularExpression(pattern: "route-gateway [\\d\\.]+", options: [])
|
||||||
|
|
||||||
|
private static let routeRegexp = try! NSRegularExpression(pattern: "route [\\d\\.]+( [\\d\\.]+){0,2}", options: [])
|
||||||
|
|
||||||
private static let dnsRegexp = try! NSRegularExpression(pattern: "dhcp-option DNS [\\d\\.]+", options: [])
|
private static let dnsRegexp = try! NSRegularExpression(pattern: "dhcp-option DNS [\\d\\.]+", options: [])
|
||||||
|
|
||||||
private static let authTokenRegexp = try! NSRegularExpression(pattern: "auth-token [a-zA-Z0-9/=+]+", options: [])
|
private static let authTokenRegexp = try! NSRegularExpression(pattern: "auth-token [a-zA-Z0-9/=+]+", options: [])
|
||||||
|
@ -70,7 +106,9 @@ extension SessionProxy {
|
||||||
|
|
||||||
let addressMask: String
|
let addressMask: String
|
||||||
|
|
||||||
let gatewayAddress: String
|
let defaultGateway: String
|
||||||
|
|
||||||
|
let routes: [Route]
|
||||||
|
|
||||||
let dnsServers: [String]
|
let dnsServers: [String]
|
||||||
|
|
||||||
|
@ -83,22 +121,84 @@ extension SessionProxy {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var ifconfigComponents: [String]?
|
var optTopologyComponents: [String]?
|
||||||
var dnsServers = [String]()
|
var optIfconfigComponents: [String]?
|
||||||
|
var optGatewayComponents: [String]?
|
||||||
|
|
||||||
|
let address: String
|
||||||
|
let addressMask: String
|
||||||
|
let defaultGateway: String
|
||||||
|
var routes: [Route] = []
|
||||||
|
var dnsServers: [String] = []
|
||||||
var authToken: String?
|
var authToken: String?
|
||||||
var peerId: UInt32?
|
var peerId: UInt32?
|
||||||
|
|
||||||
|
// MARK: Routing
|
||||||
|
|
||||||
|
PushReply.topologyRegexp.enumerateMatches(in: message, options: [], range: NSMakeRange(0, message.count)) { (result, flags, _) in
|
||||||
|
guard let range = result?.range else { return }
|
||||||
|
|
||||||
|
let match = (message as NSString).substring(with: range)
|
||||||
|
optTopologyComponents = match.components(separatedBy: " ")
|
||||||
|
}
|
||||||
|
guard let topologyComponents = optTopologyComponents, topologyComponents.count == 2 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: topologyComponents[1]) else {
|
||||||
|
fatalError("Bad topology regexp, accepted unrecognized value: \(topologyComponents[1])")
|
||||||
|
}
|
||||||
|
|
||||||
PushReply.ifconfigRegexp.enumerateMatches(in: message, options: [], range: NSMakeRange(0, message.count)) { (result, flags, _) in
|
PushReply.ifconfigRegexp.enumerateMatches(in: message, options: [], range: NSMakeRange(0, message.count)) { (result, flags, _) in
|
||||||
guard let range = result?.range else { return }
|
guard let range = result?.range else { return }
|
||||||
|
|
||||||
let match = (message as NSString).substring(with: range)
|
let match = (message as NSString).substring(with: range)
|
||||||
ifconfigComponents = match.components(separatedBy: " ")
|
optIfconfigComponents = match.components(separatedBy: " ")
|
||||||
}
|
}
|
||||||
|
guard let ifconfigComponents = optIfconfigComponents, ifconfigComponents.count == 3 else {
|
||||||
guard let addresses = ifconfigComponents, addresses.count >= 2 else {
|
|
||||||
throw SessionError.malformedPushReply
|
throw SessionError.malformedPushReply
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PushReply.gatewayRegexp.enumerateMatches(in: message, options: [], range: NSMakeRange(0, message.count)) { (result, flags, _) in
|
||||||
|
guard let range = result?.range else { return }
|
||||||
|
|
||||||
|
let match = (message as NSString).substring(with: range)
|
||||||
|
optGatewayComponents = match.components(separatedBy: " ")
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// 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 gatewayComponents = optGatewayComponents, gatewayComponents.count == 2 else {
|
||||||
|
throw SessionError.malformedPushReply
|
||||||
|
}
|
||||||
|
address = ifconfigComponents[1]
|
||||||
|
addressMask = ifconfigComponents[2]
|
||||||
|
defaultGateway = gatewayComponents[1]
|
||||||
|
|
||||||
|
default:
|
||||||
|
address = ifconfigComponents[1]
|
||||||
|
addressMask = "255.255.255.255"
|
||||||
|
defaultGateway = ifconfigComponents[2]
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: DNS
|
||||||
|
|
||||||
PushReply.dnsRegexp.enumerateMatches(in: message, options: [], range: NSMakeRange(0, message.count)) { (result, flags, _) in
|
PushReply.dnsRegexp.enumerateMatches(in: message, options: [], range: NSMakeRange(0, message.count)) { (result, flags, _) in
|
||||||
guard let range = result?.range else { return }
|
guard let range = result?.range else { return }
|
||||||
|
|
||||||
|
@ -108,6 +208,32 @@ extension SessionProxy {
|
||||||
dnsServers.append(dnsEntryComponents[2])
|
dnsServers.append(dnsEntryComponents[2])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MARK: Routes
|
||||||
|
|
||||||
|
PushReply.routeRegexp.enumerateMatches(in: message, options: [], range: NSMakeRange(0, message.count)) { (result, flags, _) in
|
||||||
|
guard let range = result?.range else { return }
|
||||||
|
|
||||||
|
let match = (message as NSString).substring(with: range)
|
||||||
|
let routeEntryComponents = match.components(separatedBy: " ")
|
||||||
|
|
||||||
|
let destination = routeEntryComponents[1]
|
||||||
|
let mask: String?
|
||||||
|
let gateway: String?
|
||||||
|
if routeEntryComponents.count > 2 {
|
||||||
|
mask = routeEntryComponents[2]
|
||||||
|
} else {
|
||||||
|
mask = nil
|
||||||
|
}
|
||||||
|
if routeEntryComponents.count > 3 {
|
||||||
|
gateway = routeEntryComponents[3]
|
||||||
|
} else {
|
||||||
|
gateway = defaultGateway
|
||||||
|
}
|
||||||
|
routes.append(Route(destination, mask, gateway))
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: Authentication
|
||||||
|
|
||||||
PushReply.authTokenRegexp.enumerateMatches(in: message, options: [], range: NSMakeRange(0, message.count)) { (result, flags, _) in
|
PushReply.authTokenRegexp.enumerateMatches(in: message, options: [], range: NSMakeRange(0, message.count)) { (result, flags, _) in
|
||||||
guard let range = result?.range else { return }
|
guard let range = result?.range else { return }
|
||||||
|
|
||||||
|
@ -130,10 +256,11 @@ extension SessionProxy {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
address = addresses[1]
|
self.address = address
|
||||||
addressMask = "255.255.255.255"
|
self.addressMask = addressMask
|
||||||
gatewayAddress = addresses[2]
|
self.defaultGateway = defaultGateway
|
||||||
self.dnsServers = dnsServers
|
self.dnsServers = dnsServers
|
||||||
|
self.routes = routes
|
||||||
self.authToken = authToken
|
self.authToken = authToken
|
||||||
self.peerId = peerId
|
self.peerId = peerId
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue