Parse IPv6 enpdoints properly (#294)
* Fix incorrect parsing of IPv6 address in endpoint * Use better names for space-based regex extensions
This commit is contained in:
parent
31db8ebb9d
commit
7659057888
|
@ -21,6 +21,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
- OpenVPN: Prioritize server configuration over client (standard behavior).
|
- OpenVPN: Prioritize server configuration over client (standard behavior).
|
||||||
|
- IPv6 endpoints are parsed improperly. [#293](https://github.com/passepartoutvpn/tunnelkit/issues/293)
|
||||||
- Fix abandoned MockVPN. [#285](https://github.com/passepartoutvpn/tunnelkit/pull/285)
|
- Fix abandoned MockVPN. [#285](https://github.com/passepartoutvpn/tunnelkit/pull/285)
|
||||||
|
|
||||||
## 5.0.0 (2022-09-23)
|
## 5.0.0 (2022-09-23)
|
||||||
|
|
|
@ -24,9 +24,14 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
import __TunnelKitUtils
|
||||||
|
|
||||||
/// Represents an endpoint.
|
/// Represents an endpoint.
|
||||||
public struct Endpoint: RawRepresentable, Codable, Equatable, CustomStringConvertible {
|
public struct Endpoint: RawRepresentable, Codable, Equatable, CustomStringConvertible {
|
||||||
|
|
||||||
|
// XXX: simplistic match
|
||||||
|
private static let rx = NSRegularExpression("^([0-9A-Fa-f\\.:]+):(UDP[46]?|TCP[46]?):(\\d+)$")
|
||||||
|
|
||||||
public let address: String
|
public let address: String
|
||||||
|
|
||||||
public let proto: EndpointProtocol
|
public let proto: EndpointProtocol
|
||||||
|
@ -68,7 +73,7 @@ public struct Endpoint: RawRepresentable, Codable, Equatable, CustomStringConver
|
||||||
// MARK: RawRepresentable
|
// MARK: RawRepresentable
|
||||||
|
|
||||||
public init?(rawValue: String) {
|
public init?(rawValue: String) {
|
||||||
let components = rawValue.components(separatedBy: ":")
|
let components = Self.rx.groups(in: rawValue)
|
||||||
guard components.count == 3 else {
|
guard components.count == 3 else {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -313,16 +313,16 @@ extension OpenVPN {
|
||||||
// MARK: Unsupported
|
// MARK: Unsupported
|
||||||
|
|
||||||
// check blocks first
|
// check blocks first
|
||||||
Regex.connection.enumerateComponents(in: line) { (_) in
|
Regex.connection.enumerateSpacedComponents(in: line) { (_) in
|
||||||
unsupportedError = ConfigurationError.unsupportedConfiguration(option: "<connection> blocks")
|
unsupportedError = ConfigurationError.unsupportedConfiguration(option: "<connection> blocks")
|
||||||
}
|
}
|
||||||
Regex.fragment.enumerateComponents(in: line) { (_) in
|
Regex.fragment.enumerateSpacedComponents(in: line) { (_) in
|
||||||
unsupportedError = ConfigurationError.unsupportedConfiguration(option: "fragment")
|
unsupportedError = ConfigurationError.unsupportedConfiguration(option: "fragment")
|
||||||
}
|
}
|
||||||
Regex.connectionProxy.enumerateComponents(in: line) { (_) in
|
Regex.connectionProxy.enumerateSpacedComponents(in: line) { (_) in
|
||||||
unsupportedError = ConfigurationError.unsupportedConfiguration(option: "proxy: \"\(line)\"")
|
unsupportedError = ConfigurationError.unsupportedConfiguration(option: "proxy: \"\(line)\"")
|
||||||
}
|
}
|
||||||
Regex.externalFiles.enumerateComponents(in: line) { (_) in
|
Regex.externalFiles.enumerateSpacedComponents(in: line) { (_) in
|
||||||
unsupportedError = ConfigurationError.unsupportedConfiguration(option: "external file: \"\(line)\"")
|
unsupportedError = ConfigurationError.unsupportedConfiguration(option: "external file: \"\(line)\"")
|
||||||
}
|
}
|
||||||
if line.contains("mtu") || line.contains("mssfix") {
|
if line.contains("mtu") || line.contains("mssfix") {
|
||||||
|
@ -332,7 +332,7 @@ extension OpenVPN {
|
||||||
// MARK: Continuation
|
// MARK: Continuation
|
||||||
|
|
||||||
var isContinuation = false
|
var isContinuation = false
|
||||||
Regex.continuation.enumerateArguments(in: line) {
|
Regex.continuation.enumerateSpacedArguments(in: line) {
|
||||||
isContinuation = ($0.first == "2")
|
isContinuation = ($0.first == "2")
|
||||||
}
|
}
|
||||||
guard !isContinuation else {
|
guard !isContinuation else {
|
||||||
|
@ -343,7 +343,7 @@ extension OpenVPN {
|
||||||
|
|
||||||
if unsupportedError == nil {
|
if unsupportedError == nil {
|
||||||
if currentBlockName == nil {
|
if currentBlockName == nil {
|
||||||
Regex.blockBegin.enumerateComponents(in: line) {
|
Regex.blockBegin.enumerateSpacedComponents(in: line) {
|
||||||
isHandled = true
|
isHandled = true
|
||||||
let tag = $0.first!
|
let tag = $0.first!
|
||||||
let from = tag.index(after: tag.startIndex)
|
let from = tag.index(after: tag.startIndex)
|
||||||
|
@ -353,7 +353,7 @@ extension OpenVPN {
|
||||||
currentBlock = []
|
currentBlock = []
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Regex.blockEnd.enumerateComponents(in: line) {
|
Regex.blockEnd.enumerateSpacedComponents(in: line) {
|
||||||
isHandled = true
|
isHandled = true
|
||||||
let tag = $0.first!
|
let tag = $0.first!
|
||||||
let from = tag.index(tag.startIndex, offsetBy: 2)
|
let from = tag.index(tag.startIndex, offsetBy: 2)
|
||||||
|
@ -399,14 +399,14 @@ extension OpenVPN {
|
||||||
|
|
||||||
// MARK: General
|
// MARK: General
|
||||||
|
|
||||||
Regex.cipher.enumerateArguments(in: line) {
|
Regex.cipher.enumerateSpacedArguments(in: line) {
|
||||||
isHandled = true
|
isHandled = true
|
||||||
guard let rawValue = $0.first else {
|
guard let rawValue = $0.first else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
optCipher = Cipher(rawValue: rawValue.uppercased())
|
optCipher = Cipher(rawValue: rawValue.uppercased())
|
||||||
}
|
}
|
||||||
Regex.dataCiphers.enumerateArguments(in: line) {
|
Regex.dataCiphers.enumerateSpacedArguments(in: line) {
|
||||||
isHandled = true
|
isHandled = true
|
||||||
guard let rawValue = $0.first else {
|
guard let rawValue = $0.first else {
|
||||||
return
|
return
|
||||||
|
@ -420,14 +420,14 @@ extension OpenVPN {
|
||||||
optDataCiphers?.append(cipher)
|
optDataCiphers?.append(cipher)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Regex.dataCiphersFallback.enumerateArguments(in: line) {
|
Regex.dataCiphersFallback.enumerateSpacedArguments(in: line) {
|
||||||
isHandled = true
|
isHandled = true
|
||||||
guard let rawValue = $0.first else {
|
guard let rawValue = $0.first else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
optDataCiphersFallback = Cipher(rawValue: rawValue.uppercased())
|
optDataCiphersFallback = Cipher(rawValue: rawValue.uppercased())
|
||||||
}
|
}
|
||||||
Regex.auth.enumerateArguments(in: line) {
|
Regex.auth.enumerateSpacedArguments(in: line) {
|
||||||
isHandled = true
|
isHandled = true
|
||||||
guard let rawValue = $0.first else {
|
guard let rawValue = $0.first else {
|
||||||
return
|
return
|
||||||
|
@ -437,7 +437,7 @@ extension OpenVPN {
|
||||||
unsupportedError = ConfigurationError.unsupportedConfiguration(option: "auth \(rawValue)")
|
unsupportedError = ConfigurationError.unsupportedConfiguration(option: "auth \(rawValue)")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Regex.compLZO.enumerateArguments(in: line) {
|
Regex.compLZO.enumerateSpacedArguments(in: line) {
|
||||||
isHandled = true
|
isHandled = true
|
||||||
optCompressionFraming = .compLZO
|
optCompressionFraming = .compLZO
|
||||||
|
|
||||||
|
@ -455,7 +455,7 @@ extension OpenVPN {
|
||||||
optCompressionAlgorithm = (arg == "no") ? .disabled : .LZO
|
optCompressionAlgorithm = (arg == "no") ? .disabled : .LZO
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Regex.compress.enumerateArguments(in: line) {
|
Regex.compress.enumerateSpacedArguments(in: line) {
|
||||||
isHandled = true
|
isHandled = true
|
||||||
optCompressionFraming = .compress
|
optCompressionFraming = .compress
|
||||||
|
|
||||||
|
@ -485,28 +485,28 @@ extension OpenVPN {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Regex.keyDirection.enumerateArguments(in: line) {
|
Regex.keyDirection.enumerateSpacedArguments(in: line) {
|
||||||
isHandled = true
|
isHandled = true
|
||||||
guard let arg = $0.first, let value = Int(arg) else {
|
guard let arg = $0.first, let value = Int(arg) else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
optKeyDirection = StaticKey.Direction(rawValue: value)
|
optKeyDirection = StaticKey.Direction(rawValue: value)
|
||||||
}
|
}
|
||||||
Regex.ping.enumerateArguments(in: line) {
|
Regex.ping.enumerateSpacedArguments(in: line) {
|
||||||
isHandled = true
|
isHandled = true
|
||||||
guard let arg = $0.first else {
|
guard let arg = $0.first else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
optKeepAliveSeconds = TimeInterval(arg)
|
optKeepAliveSeconds = TimeInterval(arg)
|
||||||
}
|
}
|
||||||
Regex.pingRestart.enumerateArguments(in: line) {
|
Regex.pingRestart.enumerateSpacedArguments(in: line) {
|
||||||
isHandled = true
|
isHandled = true
|
||||||
guard let arg = $0.first else {
|
guard let arg = $0.first else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
optKeepAliveTimeoutSeconds = TimeInterval(arg)
|
optKeepAliveTimeoutSeconds = TimeInterval(arg)
|
||||||
}
|
}
|
||||||
Regex.keepAlive.enumerateArguments(in: line) {
|
Regex.keepAlive.enumerateSpacedArguments(in: line) {
|
||||||
isHandled = true
|
isHandled = true
|
||||||
guard let ping = $0.first, let pingRestart = $0.last else {
|
guard let ping = $0.first, let pingRestart = $0.last else {
|
||||||
return
|
return
|
||||||
|
@ -514,14 +514,14 @@ extension OpenVPN {
|
||||||
optKeepAliveSeconds = TimeInterval(ping)
|
optKeepAliveSeconds = TimeInterval(ping)
|
||||||
optKeepAliveTimeoutSeconds = TimeInterval(pingRestart)
|
optKeepAliveTimeoutSeconds = TimeInterval(pingRestart)
|
||||||
}
|
}
|
||||||
Regex.renegSec.enumerateArguments(in: line) {
|
Regex.renegSec.enumerateSpacedArguments(in: line) {
|
||||||
isHandled = true
|
isHandled = true
|
||||||
guard let arg = $0.first else {
|
guard let arg = $0.first else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
optRenegotiateAfterSeconds = TimeInterval(arg)
|
optRenegotiateAfterSeconds = TimeInterval(arg)
|
||||||
}
|
}
|
||||||
Regex.xorMask.enumerateArguments(in: line) {
|
Regex.xorMask.enumerateSpacedArguments(in: line) {
|
||||||
isHandled = true
|
isHandled = true
|
||||||
if $0.count != 2 {
|
if $0.count != 2 {
|
||||||
return
|
return
|
||||||
|
@ -531,7 +531,7 @@ extension OpenVPN {
|
||||||
|
|
||||||
// MARK: Client
|
// MARK: Client
|
||||||
|
|
||||||
Regex.proto.enumerateArguments(in: line) {
|
Regex.proto.enumerateSpacedArguments(in: line) {
|
||||||
isHandled = true
|
isHandled = true
|
||||||
guard let str = $0.first else {
|
guard let str = $0.first else {
|
||||||
return
|
return
|
||||||
|
@ -541,14 +541,14 @@ extension OpenVPN {
|
||||||
unsupportedError = ConfigurationError.unsupportedConfiguration(option: "proto \(str)")
|
unsupportedError = ConfigurationError.unsupportedConfiguration(option: "proto \(str)")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Regex.port.enumerateArguments(in: line) {
|
Regex.port.enumerateSpacedArguments(in: line) {
|
||||||
isHandled = true
|
isHandled = true
|
||||||
guard let str = $0.first else {
|
guard let str = $0.first else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
optDefaultPort = UInt16(str)
|
optDefaultPort = UInt16(str)
|
||||||
}
|
}
|
||||||
Regex.remote.enumerateArguments(in: line) {
|
Regex.remote.enumerateSpacedArguments(in: line) {
|
||||||
isHandled = true
|
isHandled = true
|
||||||
guard let hostname = $0.first else {
|
guard let hostname = $0.first else {
|
||||||
return
|
return
|
||||||
|
@ -569,51 +569,51 @@ extension OpenVPN {
|
||||||
// replace private data
|
// replace private data
|
||||||
strippedLine = strippedComponents.joined(separator: " ")
|
strippedLine = strippedComponents.joined(separator: " ")
|
||||||
}
|
}
|
||||||
Regex.eku.enumerateComponents(in: line) { (_) in
|
Regex.eku.enumerateSpacedComponents(in: line) { (_) in
|
||||||
isHandled = true
|
isHandled = true
|
||||||
optChecksEKU = true
|
optChecksEKU = true
|
||||||
}
|
}
|
||||||
Regex.remoteRandom.enumerateComponents(in: line) { (_) in
|
Regex.remoteRandom.enumerateSpacedComponents(in: line) { (_) in
|
||||||
isHandled = true
|
isHandled = true
|
||||||
optRandomizeEndpoint = true
|
optRandomizeEndpoint = true
|
||||||
}
|
}
|
||||||
Regex.remoteRandomHostname.enumerateComponents(in: line) { _ in
|
Regex.remoteRandomHostname.enumerateSpacedComponents(in: line) { _ in
|
||||||
isHandled = true
|
isHandled = true
|
||||||
optRandomizeHostnames = true
|
optRandomizeHostnames = true
|
||||||
}
|
}
|
||||||
Regex.mtu.enumerateArguments(in: line) {
|
Regex.mtu.enumerateSpacedArguments(in: line) {
|
||||||
isHandled = true
|
isHandled = true
|
||||||
guard let str = $0.first else {
|
guard let str = $0.first else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
optMTU = Int(str)
|
optMTU = Int(str)
|
||||||
}
|
}
|
||||||
Regex.authUserPass.enumerateComponents(in: line) { _ in
|
Regex.authUserPass.enumerateSpacedComponents(in: line) { _ in
|
||||||
isHandled = true
|
isHandled = true
|
||||||
authUserPass = true
|
authUserPass = true
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: Server
|
// MARK: Server
|
||||||
|
|
||||||
Regex.authToken.enumerateArguments(in: line) {
|
Regex.authToken.enumerateSpacedArguments(in: line) {
|
||||||
optAuthToken = $0[0]
|
optAuthToken = $0[0]
|
||||||
}
|
}
|
||||||
Regex.peerId.enumerateArguments(in: line) {
|
Regex.peerId.enumerateSpacedArguments(in: line) {
|
||||||
optPeerId = UInt32($0[0])
|
optPeerId = UInt32($0[0])
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: Routing
|
// MARK: Routing
|
||||||
|
|
||||||
Regex.topology.enumerateArguments(in: line) {
|
Regex.topology.enumerateSpacedArguments(in: line) {
|
||||||
optTopology = $0.first
|
optTopology = $0.first
|
||||||
}
|
}
|
||||||
Regex.ifconfig.enumerateArguments(in: line) {
|
Regex.ifconfig.enumerateSpacedArguments(in: line) {
|
||||||
optIfconfig4Arguments = $0
|
optIfconfig4Arguments = $0
|
||||||
}
|
}
|
||||||
Regex.ifconfig6.enumerateArguments(in: line) {
|
Regex.ifconfig6.enumerateSpacedArguments(in: line) {
|
||||||
optIfconfig6Arguments = $0
|
optIfconfig6Arguments = $0
|
||||||
}
|
}
|
||||||
Regex.route.enumerateArguments(in: line) {
|
Regex.route.enumerateSpacedArguments(in: line) {
|
||||||
let routeEntryArguments = $0
|
let routeEntryArguments = $0
|
||||||
|
|
||||||
let address = routeEntryArguments[0]
|
let address = routeEntryArguments[0]
|
||||||
|
@ -624,7 +624,7 @@ extension OpenVPN {
|
||||||
}
|
}
|
||||||
optRoutes4.append((address, mask, gateway))
|
optRoutes4.append((address, mask, gateway))
|
||||||
}
|
}
|
||||||
Regex.route6.enumerateArguments(in: line) {
|
Regex.route6.enumerateSpacedArguments(in: line) {
|
||||||
let routeEntryArguments = $0
|
let routeEntryArguments = $0
|
||||||
|
|
||||||
let destinationComponents = routeEntryArguments[0].components(separatedBy: "/")
|
let destinationComponents = routeEntryArguments[0].components(separatedBy: "/")
|
||||||
|
@ -642,10 +642,10 @@ extension OpenVPN {
|
||||||
}
|
}
|
||||||
optRoutes6.append((destination, prefix, gateway))
|
optRoutes6.append((destination, prefix, gateway))
|
||||||
}
|
}
|
||||||
Regex.gateway.enumerateArguments(in: line) {
|
Regex.gateway.enumerateSpacedArguments(in: line) {
|
||||||
optGateway4Arguments = $0
|
optGateway4Arguments = $0
|
||||||
}
|
}
|
||||||
Regex.dns.enumerateArguments(in: line) {
|
Regex.dns.enumerateSpacedArguments(in: line) {
|
||||||
guard $0.count == 2 else {
|
guard $0.count == 2 else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -654,13 +654,13 @@ extension OpenVPN {
|
||||||
}
|
}
|
||||||
optDNSServers?.append($0[1])
|
optDNSServers?.append($0[1])
|
||||||
}
|
}
|
||||||
Regex.domain.enumerateArguments(in: line) {
|
Regex.domain.enumerateSpacedArguments(in: line) {
|
||||||
guard $0.count == 2 else {
|
guard $0.count == 2 else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
optDomain = $0[1]
|
optDomain = $0[1]
|
||||||
}
|
}
|
||||||
Regex.domainSearch.enumerateArguments(in: line) {
|
Regex.domainSearch.enumerateSpacedArguments(in: line) {
|
||||||
guard $0.count == 2 else {
|
guard $0.count == 2 else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -669,7 +669,7 @@ extension OpenVPN {
|
||||||
}
|
}
|
||||||
optSearchDomains?.append($0[1])
|
optSearchDomains?.append($0[1])
|
||||||
}
|
}
|
||||||
Regex.proxy.enumerateArguments(in: line) {
|
Regex.proxy.enumerateSpacedArguments(in: line) {
|
||||||
if $0.count == 2 {
|
if $0.count == 2 {
|
||||||
guard let url = URL(string: $0[1]) else {
|
guard let url = URL(string: $0[1]) else {
|
||||||
unsupportedError = ConfigurationError.malformed(option: "dhcp-option PROXY_AUTO_CONFIG_URL has malformed URL")
|
unsupportedError = ConfigurationError.malformed(option: "dhcp-option PROXY_AUTO_CONFIG_URL has malformed URL")
|
||||||
|
@ -693,14 +693,14 @@ extension OpenVPN {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Regex.proxyBypass.enumerateArguments(in: line) {
|
Regex.proxyBypass.enumerateSpacedArguments(in: line) {
|
||||||
guard !$0.isEmpty else {
|
guard !$0.isEmpty else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
optProxyBypass = $0
|
optProxyBypass = $0
|
||||||
optProxyBypass?.removeFirst()
|
optProxyBypass?.removeFirst()
|
||||||
}
|
}
|
||||||
Regex.redirectGateway.enumerateArguments(in: line) {
|
Regex.redirectGateway.enumerateSpacedArguments(in: line) {
|
||||||
|
|
||||||
// redirect IPv4 by default
|
// redirect IPv4 by default
|
||||||
optRedirectGateway = [.def1]
|
optRedirectGateway = [.def1]
|
||||||
|
@ -712,7 +712,7 @@ extension OpenVPN {
|
||||||
optRedirectGateway?.insert(opt)
|
optRedirectGateway?.insert(opt)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Regex.routeNoPull.enumerateComponents(in: line) { _ in
|
Regex.routeNoPull.enumerateSpacedComponents(in: line) { _ in
|
||||||
optRouteNoPull = true
|
optRouteNoPull = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -30,8 +30,25 @@ extension NSRegularExpression {
|
||||||
try! self.init(pattern: pattern, options: [])
|
try! self.init(pattern: pattern, options: [])
|
||||||
}
|
}
|
||||||
|
|
||||||
public func enumerateComponents(in string: String, using block: ([String]) -> Void) {
|
public func groups(in string: String) -> [String] {
|
||||||
enumerateMatches(in: string, options: [], range: NSMakeRange(0, string.count)) { (result, flags, stop) in
|
var results: [String] = []
|
||||||
|
enumerateMatches(in: string, options: [], range: NSMakeRange(0, string.count)) { result, flags, stop in
|
||||||
|
guard let result = result else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for i in 0..<numberOfCaptureGroups {
|
||||||
|
let subrange = result.range(at: i + 1)
|
||||||
|
let match = (string as NSString).substring(with: subrange)
|
||||||
|
results.append(match)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return results
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension NSRegularExpression {
|
||||||
|
public func enumerateSpacedComponents(in string: String, using block: ([String]) -> Void) {
|
||||||
|
enumerateMatches(in: string, options: [], range: NSMakeRange(0, string.count)) { result, flags, stop in
|
||||||
guard let range = result?.range else {
|
guard let range = result?.range else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -41,8 +58,8 @@ extension NSRegularExpression {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public func enumerateArguments(in string: String, using block: ([String]) -> Void) {
|
public func enumerateSpacedArguments(in string: String, using block: ([String]) -> Void) {
|
||||||
enumerateComponents(in: string) { (tokens) in
|
enumerateSpacedComponents(in: string) { (tokens) in
|
||||||
var args = tokens
|
var args = tokens
|
||||||
args.removeFirst()
|
args.removeFirst()
|
||||||
block(args)
|
block(args)
|
||||||
|
|
|
@ -0,0 +1,64 @@
|
||||||
|
//
|
||||||
|
// ParsingTests.swift
|
||||||
|
// TunnelKitCoreTests
|
||||||
|
//
|
||||||
|
// Created by Davide De Rosa on 10/25/22.
|
||||||
|
// Copyright (c) 2022 Davide De Rosa. All rights reserved.
|
||||||
|
//
|
||||||
|
// https://github.com/passepartoutvpn
|
||||||
|
//
|
||||||
|
// This file is part of TunnelKit.
|
||||||
|
//
|
||||||
|
// TunnelKit is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// TunnelKit is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with TunnelKit. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
//
|
||||||
|
|
||||||
|
import XCTest
|
||||||
|
@testable import TunnelKitCore
|
||||||
|
|
||||||
|
class ParsingTests: XCTestCase {
|
||||||
|
|
||||||
|
override func setUp() {
|
||||||
|
// Put setup code here. This method is called before the invocation of each test method in the class.
|
||||||
|
}
|
||||||
|
|
||||||
|
override func tearDown() {
|
||||||
|
// Put teardown code here. This method is called after the invocation of each test method in the class.
|
||||||
|
}
|
||||||
|
|
||||||
|
func testEndpointV4() {
|
||||||
|
let ipAddress = "1.2.3.4"
|
||||||
|
let socketType = "TCP"
|
||||||
|
let port = 1194
|
||||||
|
guard let endpoint = Endpoint(rawValue: "\(ipAddress):\(socketType):\(port)") else {
|
||||||
|
XCTFail()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
XCTAssertEqual(endpoint.address, ipAddress)
|
||||||
|
XCTAssertEqual(endpoint.proto.socketType.rawValue, socketType)
|
||||||
|
XCTAssertEqual(endpoint.proto.port, UInt16(port))
|
||||||
|
}
|
||||||
|
|
||||||
|
func testEndpointV6() {
|
||||||
|
let ipAddress = "2607:f0d0:1002:51::4"
|
||||||
|
let socketType = "TCP"
|
||||||
|
let port = 1194
|
||||||
|
guard let endpoint = Endpoint(rawValue: "\(ipAddress):\(socketType):\(port)") else {
|
||||||
|
XCTFail()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
XCTAssertEqual(endpoint.address, ipAddress)
|
||||||
|
XCTAssertEqual(endpoint.proto.socketType.rawValue, socketType)
|
||||||
|
XCTAssertEqual(endpoint.proto.port, UInt16(port))
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue