providerConfiguration is now a WgQuickConfig
Signed-off-by: Eric Kuck <eric@bluelinelabs.com>
This commit is contained in:
parent
accf60b82f
commit
1fecd8eb6c
|
@ -186,11 +186,8 @@ extension NETunnelProviderProtocol {
|
|||
|
||||
private func migrateFromConfigurationV1() {
|
||||
guard let serializedTunnelConfiguration = providerConfiguration?["tunnelConfiguration"] as? Data else { return }
|
||||
guard let configuration = try? JSONDecoder().decode(LegacyTunnelConfiguration.self, from: serializedTunnelConfiguration) else { return }
|
||||
guard let tunnelConfigData = try? JSONEncoder().encode(configuration.migrated) else { return }
|
||||
guard let tunnelConfigDictionary = try? JSONSerialization.jsonObject(with: tunnelConfigData, options: .allowFragments) else { return }
|
||||
|
||||
providerConfiguration = [Keys.wgQuickConfig.rawValue: tunnelConfigDictionary]
|
||||
guard let configuration = try? JSONDecoder().decode(LegacyTunnelConfiguration.self, from: serializedTunnelConfiguration) else { return }
|
||||
providerConfiguration = [Keys.wgQuickConfig.rawValue: configuration.migrated.asWgQuickConfig()]
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -12,30 +12,6 @@ struct DNSServer {
|
|||
}
|
||||
}
|
||||
|
||||
extension DNSServer: Codable {
|
||||
public func encode(to encoder: Encoder) throws {
|
||||
var container = encoder.singleValueContainer()
|
||||
try container.encode(stringRepresentation)
|
||||
}
|
||||
|
||||
public init(from decoder: Decoder) throws {
|
||||
let values = try decoder.singleValueContainer()
|
||||
let addressString = try values.decode(String.self)
|
||||
|
||||
if let address = IPv4Address(addressString) {
|
||||
self.address = address
|
||||
} else if let address = IPv6Address(addressString) {
|
||||
self.address = address
|
||||
} else {
|
||||
throw DecodingError.invalidData
|
||||
}
|
||||
}
|
||||
|
||||
enum DecodingError: Error {
|
||||
case invalidData
|
||||
}
|
||||
}
|
||||
|
||||
extension DNSServer {
|
||||
var stringRepresentation: String {
|
||||
return "\(address)"
|
||||
|
|
|
@ -14,26 +14,6 @@ struct Endpoint {
|
|||
}
|
||||
}
|
||||
|
||||
extension Endpoint: Codable {
|
||||
init(from decoder: Decoder) throws {
|
||||
let container = try decoder.singleValueContainer()
|
||||
let endpointString = try container.decode(String.self)
|
||||
guard let endpoint = Endpoint(from: endpointString) else {
|
||||
throw DecodingError.invalidData
|
||||
}
|
||||
self = endpoint
|
||||
}
|
||||
|
||||
func encode(to encoder: Encoder) throws {
|
||||
var container = encoder.singleValueContainer()
|
||||
try container.encode(stringRepresentation)
|
||||
}
|
||||
|
||||
enum DecodingError: Error {
|
||||
case invalidData
|
||||
}
|
||||
}
|
||||
|
||||
extension Endpoint {
|
||||
var stringRepresentation: String {
|
||||
switch host {
|
||||
|
|
|
@ -52,22 +52,3 @@ extension IPAddressRange {
|
|||
return (address, networkPrefixLength)
|
||||
}
|
||||
}
|
||||
|
||||
extension IPAddressRange: Codable {
|
||||
public func encode(to encoder: Encoder) throws {
|
||||
var container = encoder.singleValueContainer()
|
||||
try container.encode(stringRepresentation)
|
||||
}
|
||||
|
||||
public init(from decoder: Decoder) throws {
|
||||
let values = try decoder.singleValueContainer()
|
||||
let addressString = try values.decode(String.self)
|
||||
guard let parsed = IPAddressRange.parseAddressString(addressString) else { throw DecodingError.invalidData }
|
||||
address = parsed.0
|
||||
networkPrefixLength = parsed.1
|
||||
}
|
||||
|
||||
enum DecodingError: Error {
|
||||
case invalidData
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,56 +4,18 @@
|
|||
import Foundation
|
||||
|
||||
struct InterfaceConfiguration {
|
||||
var name: String
|
||||
var name: String?
|
||||
var privateKey: Data
|
||||
var addresses = [IPAddressRange]()
|
||||
var listenPort: UInt16?
|
||||
var mtu: UInt16?
|
||||
var dns = [DNSServer]()
|
||||
|
||||
init(name: String, privateKey: Data) {
|
||||
init(name: String?, privateKey: Data) {
|
||||
self.name = name
|
||||
self.privateKey = privateKey
|
||||
if name.isEmpty {
|
||||
fatalError("Empty name")
|
||||
}
|
||||
if privateKey.count != TunnelConfiguration.keyLength {
|
||||
fatalError("Invalid private key")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension InterfaceConfiguration: Codable {
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case name = "Name"
|
||||
case privateKey = "PrivateKey"
|
||||
case addresses = "Address"
|
||||
case listenPort = "ListenPort"
|
||||
case mtu = "MTU"
|
||||
case dns = "DNS"
|
||||
}
|
||||
|
||||
init(from decoder: Decoder) throws {
|
||||
let values = try decoder.container(keyedBy: CodingKeys.self)
|
||||
name = try values.decode(String.self, forKey: .name)
|
||||
privateKey = try Data(base64Encoded: values.decode(String.self, forKey: .privateKey))!
|
||||
addresses = try values.decode([IPAddressRange].self, forKey: .addresses)
|
||||
listenPort = try? values.decode(UInt16.self, forKey: .listenPort)
|
||||
mtu = try? values.decode(UInt16.self, forKey: .mtu)
|
||||
dns = try values.decode([DNSServer].self, forKey: .dns)
|
||||
}
|
||||
|
||||
func encode(to encoder: Encoder) throws {
|
||||
var container = encoder.container(keyedBy: CodingKeys.self)
|
||||
try container.encode(name, forKey: .name)
|
||||
try container.encode(privateKey.base64EncodedString(), forKey: .privateKey)
|
||||
try container.encode(addresses, forKey: .addresses)
|
||||
if let listenPort = listenPort {
|
||||
try container.encode(listenPort, forKey: .listenPort)
|
||||
}
|
||||
if let mtu = mtu {
|
||||
try container.encode(mtu, forKey: .mtu)
|
||||
}
|
||||
try container.encode(dns, forKey: .dns)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,42 +25,3 @@ struct PeerConfiguration {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension PeerConfiguration: Codable {
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case publicKey = "PublicKey"
|
||||
case preSharedKey = "PreSharedKey"
|
||||
case allowedIPs = "AllowedIPs"
|
||||
case endpoint = "Endpoint"
|
||||
case persistentKeepAlive = "PersistentKeepAlive"
|
||||
}
|
||||
|
||||
init(from decoder: Decoder) throws {
|
||||
let values = try decoder.container(keyedBy: CodingKeys.self)
|
||||
publicKey = try Data(base64Encoded: values.decode(String.self, forKey: .publicKey))!
|
||||
if let base64PreSharedKey = try? values.decode(Data.self, forKey: .preSharedKey) {
|
||||
preSharedKey = Data(base64Encoded: base64PreSharedKey)
|
||||
} else {
|
||||
preSharedKey = nil
|
||||
}
|
||||
allowedIPs = try values.decode([IPAddressRange].self, forKey: .allowedIPs)
|
||||
endpoint = try? values.decode(Endpoint.self, forKey: .endpoint)
|
||||
persistentKeepAlive = try? values.decode(UInt16.self, forKey: .persistentKeepAlive)
|
||||
}
|
||||
|
||||
func encode(to encoder: Encoder) throws {
|
||||
var container = encoder.container(keyedBy: CodingKeys.self)
|
||||
try container.encode(publicKey.base64EncodedString(), forKey: .publicKey)
|
||||
if let preSharedKey = preSharedKey {
|
||||
try container.encode(preSharedKey.base64EncodedString(), forKey: .preSharedKey)
|
||||
}
|
||||
|
||||
try container.encode(allowedIPs, forKey: .allowedIPs)
|
||||
if let endpoint = endpoint {
|
||||
try container.encode(endpoint, forKey: .endpoint)
|
||||
}
|
||||
if let persistentKeepAlive = persistentKeepAlive {
|
||||
try container.encode(persistentKeepAlive, forKey: .persistentKeepAlive)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,23 +20,3 @@ final class TunnelConfiguration {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension TunnelConfiguration: Codable {
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case interface = "Interface"
|
||||
case peers = "Peer"
|
||||
}
|
||||
|
||||
convenience init(from decoder: Decoder) throws {
|
||||
let values = try decoder.container(keyedBy: CodingKeys.self)
|
||||
let interface = try values.decode(InterfaceConfiguration.self, forKey: .interface)
|
||||
let peers = try values.decode([PeerConfiguration].self, forKey: .peers)
|
||||
self.init(interface: interface, peers: peers)
|
||||
}
|
||||
|
||||
func encode(to encoder: Encoder) throws {
|
||||
var container = encoder.container(keyedBy: CodingKeys.self)
|
||||
try container.encode(interface, forKey: .interface)
|
||||
try container.encode(peers, forKey: .peers)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,38 +3,21 @@
|
|||
|
||||
import NetworkExtension
|
||||
|
||||
private var tunnelNameKey: Void?
|
||||
|
||||
extension NETunnelProviderProtocol {
|
||||
|
||||
enum Keys: String {
|
||||
case wgQuickConfig = "WgQuickConfigV1"
|
||||
}
|
||||
|
||||
var tunnelConfiguration: TunnelConfiguration? {
|
||||
migrateConfigurationIfNeeded()
|
||||
|
||||
let tunnelConfigurationData: Data?
|
||||
if let configurationDictionary = providerConfiguration?[Keys.wgQuickConfig.rawValue] {
|
||||
tunnelConfigurationData = try? JSONSerialization.data(withJSONObject: configurationDictionary, options: [])
|
||||
} else {
|
||||
tunnelConfigurationData = nil
|
||||
}
|
||||
|
||||
guard tunnelConfigurationData != nil else { return nil }
|
||||
return try? JSONDecoder().decode(TunnelConfiguration.self, from: tunnelConfigurationData!)
|
||||
case wgQuickConfig = "WgQuickConfig"
|
||||
}
|
||||
|
||||
convenience init?(tunnelConfiguration: TunnelConfiguration) {
|
||||
assert(!tunnelConfiguration.interface.name.isEmpty)
|
||||
|
||||
guard let tunnelConfigData = try? JSONEncoder().encode(tunnelConfiguration) else { return nil }
|
||||
guard let tunnelConfigDictionary = try? JSONSerialization.jsonObject(with: tunnelConfigData, options: .allowFragments) else { return nil }
|
||||
|
||||
self.init()
|
||||
|
||||
|
||||
let appId = Bundle.main.bundleIdentifier!
|
||||
providerBundleIdentifier = "\(appId).network-extension"
|
||||
providerConfiguration = [ Keys.wgQuickConfig.rawValue: tunnelConfigDictionary ]
|
||||
|
||||
providerConfiguration = [Keys.wgQuickConfig.rawValue: tunnelConfiguration.asWgQuickConfig()]
|
||||
|
||||
let endpoints = tunnelConfiguration.peers.compactMap { $0.endpoint }
|
||||
if endpoints.count == 1 {
|
||||
serverAddress = endpoints[0].stringRepresentation
|
||||
|
@ -43,13 +26,14 @@ extension NETunnelProviderProtocol {
|
|||
} else {
|
||||
serverAddress = "Multiple endpoints"
|
||||
}
|
||||
|
||||
username = tunnelConfiguration.interface.name
|
||||
}
|
||||
|
||||
func hasTunnelConfiguration(tunnelConfiguration otherTunnelConfiguration: TunnelConfiguration) -> Bool {
|
||||
guard let serializedThisTunnelConfiguration = try? JSONEncoder().encode(tunnelConfiguration) else { return false }
|
||||
guard let serializedOtherTunnelConfiguration = try? JSONEncoder().encode(otherTunnelConfiguration) else { return false }
|
||||
return serializedThisTunnelConfiguration == serializedOtherTunnelConfiguration
|
||||
|
||||
func tunnelConfiguration(name: String?) -> TunnelConfiguration? {
|
||||
migrateConfigurationIfNeeded()
|
||||
guard let serializedConfig = providerConfiguration?[Keys.wgQuickConfig.rawValue] as? String else { return nil }
|
||||
return try? TunnelConfiguration(serializedConfig, name: name)
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -3,14 +3,14 @@
|
|||
|
||||
import Foundation
|
||||
|
||||
class WgQuickConfigFileParser {
|
||||
|
||||
extension TunnelConfiguration {
|
||||
|
||||
enum ParserState {
|
||||
case inInterfaceSection
|
||||
case inPeerSection
|
||||
case notInASection
|
||||
}
|
||||
|
||||
|
||||
enum ParseError: Error {
|
||||
case invalidLine(_ line: String.SubSequence)
|
||||
case noInterface
|
||||
|
@ -19,19 +19,17 @@ class WgQuickConfigFileParser {
|
|||
case multiplePeersWithSamePublicKey
|
||||
case invalidPeer
|
||||
}
|
||||
|
||||
|
||||
//swiftlint:disable:next cyclomatic_complexity function_body_length
|
||||
static func parse(_ text: String, name: String) throws -> TunnelConfiguration {
|
||||
assert(!name.isEmpty)
|
||||
|
||||
convenience init(_ wgQuickConfig: String, name: String?) throws {
|
||||
var interfaceConfiguration: InterfaceConfiguration?
|
||||
var peerConfigurations = [PeerConfiguration]()
|
||||
|
||||
let lines = text.split(separator: "\n")
|
||||
|
||||
|
||||
let lines = wgQuickConfig.split(separator: "\n")
|
||||
|
||||
var parserState = ParserState.notInASection
|
||||
var attributes = [String: String]()
|
||||
|
||||
|
||||
for (lineIndex, line) in lines.enumerated() {
|
||||
var trimmedLine: String
|
||||
if let commentRange = line.range(of: "#") {
|
||||
|
@ -39,12 +37,12 @@ class WgQuickConfigFileParser {
|
|||
} else {
|
||||
trimmedLine = String(line)
|
||||
}
|
||||
|
||||
|
||||
trimmedLine = trimmedLine.trimmingCharacters(in: .whitespaces)
|
||||
|
||||
|
||||
guard !trimmedLine.isEmpty else { continue }
|
||||
let lowercasedLine = line.lowercased()
|
||||
|
||||
|
||||
if let equalsIndex = line.firstIndex(of: "=") {
|
||||
// Line contains an attribute
|
||||
let key = line[..<equalsIndex].trimmingCharacters(in: .whitespaces).lowercased()
|
||||
|
@ -58,21 +56,21 @@ class WgQuickConfigFileParser {
|
|||
} else if lowercasedLine != "[interface]" && lowercasedLine != "[peer]" {
|
||||
throw ParseError.invalidLine(line)
|
||||
}
|
||||
|
||||
|
||||
let isLastLine = lineIndex == lines.count - 1
|
||||
|
||||
|
||||
if isLastLine || lowercasedLine == "[interface]" || lowercasedLine == "[peer]" {
|
||||
// Previous section has ended; process the attributes collected so far
|
||||
if parserState == .inInterfaceSection {
|
||||
guard let interface = collate(interfaceAttributes: attributes, name: name) else { throw ParseError.invalidInterface }
|
||||
guard let interface = TunnelConfiguration.collate(interfaceAttributes: attributes, name: name) else { throw ParseError.invalidInterface }
|
||||
guard interfaceConfiguration == nil else { throw ParseError.multipleInterfaces }
|
||||
interfaceConfiguration = interface
|
||||
} else if parserState == .inPeerSection {
|
||||
guard let peer = collate(peerAttributes: attributes) else { throw ParseError.invalidPeer }
|
||||
guard let peer = TunnelConfiguration.collate(peerAttributes: attributes) else { throw ParseError.invalidPeer }
|
||||
peerConfigurations.append(peer)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if lowercasedLine == "[interface]" {
|
||||
parserState = .inInterfaceSection
|
||||
attributes.removeAll()
|
||||
|
@ -81,23 +79,61 @@ class WgQuickConfigFileParser {
|
|||
attributes.removeAll()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
let peerPublicKeysArray = peerConfigurations.map { $0.publicKey }
|
||||
let peerPublicKeysSet = Set<Data>(peerPublicKeysArray)
|
||||
if peerPublicKeysArray.count != peerPublicKeysSet.count {
|
||||
throw ParseError.multiplePeersWithSamePublicKey
|
||||
}
|
||||
|
||||
|
||||
if let interfaceConfiguration = interfaceConfiguration {
|
||||
let tunnelConfiguration = TunnelConfiguration(interface: interfaceConfiguration, peers: peerConfigurations)
|
||||
return tunnelConfiguration
|
||||
self.init(interface: interfaceConfiguration, peers: peerConfigurations)
|
||||
} else {
|
||||
throw ParseError.noInterface
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func asWgQuickConfig() -> String {
|
||||
var output = "[Interface]\n"
|
||||
output.append("PrivateKey = \(interface.privateKey.base64EncodedString())\n")
|
||||
if let listenPort = interface.listenPort {
|
||||
output.append("ListenPort = \(listenPort)\n")
|
||||
}
|
||||
if !interface.addresses.isEmpty {
|
||||
let addressString = interface.addresses.map { $0.stringRepresentation }.joined(separator: ", ")
|
||||
output.append("Address = \(addressString)\n")
|
||||
}
|
||||
if !interface.dns.isEmpty {
|
||||
let dnsString = interface.dns.map { $0.stringRepresentation }.joined(separator: ", ")
|
||||
output.append("DNS = \(dnsString)\n")
|
||||
}
|
||||
if let mtu = interface.mtu {
|
||||
output.append("MTU = \(mtu)\n")
|
||||
}
|
||||
|
||||
for peer in peers {
|
||||
output.append("\n[Peer]\n")
|
||||
output.append("PublicKey = \(peer.publicKey.base64EncodedString())\n")
|
||||
if let preSharedKey = peer.preSharedKey {
|
||||
output.append("PresharedKey = \(preSharedKey.base64EncodedString())\n")
|
||||
}
|
||||
if !peer.allowedIPs.isEmpty {
|
||||
let allowedIPsString = peer.allowedIPs.map { $0.stringRepresentation }.joined(separator: ", ")
|
||||
output.append("AllowedIPs = \(allowedIPsString)\n")
|
||||
}
|
||||
if let endpoint = peer.endpoint {
|
||||
output.append("Endpoint = \(endpoint.stringRepresentation)\n")
|
||||
}
|
||||
if let persistentKeepAlive = peer.persistentKeepAlive {
|
||||
output.append("PersistentKeepalive = \(persistentKeepAlive)\n")
|
||||
}
|
||||
}
|
||||
|
||||
return output
|
||||
}
|
||||
|
||||
//swiftlint:disable:next cyclomatic_complexity
|
||||
private static func collate(interfaceAttributes attributes: [String: String], name: String) -> InterfaceConfiguration? {
|
||||
private static func collate(interfaceAttributes attributes: [String: String], name: String?) -> InterfaceConfiguration? {
|
||||
// required wg fields
|
||||
guard let privateKeyString = attributes["privatekey"] else { return nil }
|
||||
guard let privateKey = Data(base64Encoded: privateKeyString), privateKey.count == TunnelConfiguration.keyLength else { return nil }
|
||||
|
@ -130,7 +166,7 @@ class WgQuickConfigFileParser {
|
|||
}
|
||||
return interface
|
||||
}
|
||||
|
||||
|
||||
//swiftlint:disable:next cyclomatic_complexity
|
||||
private static func collate(peerAttributes attributes: [String: String]) -> PeerConfiguration? {
|
||||
// required wg fields
|
||||
|
@ -160,5 +196,5 @@ class WgQuickConfigFileParser {
|
|||
}
|
||||
return peer
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -20,6 +20,9 @@
|
|||
5F4541B221CBFAEE00994C13 /* String+ArrayConversion.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F4541B121CBFAEE00994C13 /* String+ArrayConversion.swift */; };
|
||||
5F9696AA21CD6AE6008063FE /* LegacyConfigMigration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F9696A921CD6AE6008063FE /* LegacyConfigMigration.swift */; };
|
||||
5F9696AB21CD6AE6008063FE /* LegacyConfigMigration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F9696A921CD6AE6008063FE /* LegacyConfigMigration.swift */; };
|
||||
5F9696AE21CD6F72008063FE /* String+ArrayConversion.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F4541B121CBFAEE00994C13 /* String+ArrayConversion.swift */; };
|
||||
5F9696B021CD7128008063FE /* TunnelConfiguration+WgQuickConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F9696AF21CD7128008063FE /* TunnelConfiguration+WgQuickConfig.swift */; };
|
||||
5F9696B121CD7128008063FE /* TunnelConfiguration+WgQuickConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F9696AF21CD7128008063FE /* TunnelConfiguration+WgQuickConfig.swift */; };
|
||||
5FF7B96221CC95DE00A7DD74 /* InterfaceConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FF7B96121CC95DE00A7DD74 /* InterfaceConfiguration.swift */; };
|
||||
5FF7B96321CC95DE00A7DD74 /* InterfaceConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FF7B96121CC95DE00A7DD74 /* InterfaceConfiguration.swift */; };
|
||||
5FF7B96521CC95FA00A7DD74 /* PeerConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FF7B96421CC95FA00A7DD74 /* PeerConfiguration.swift */; };
|
||||
|
@ -35,7 +38,6 @@
|
|||
6F628C41217F47DB003482A3 /* TunnelDetailTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F628C40217F47DB003482A3 /* TunnelDetailTableViewController.swift */; };
|
||||
6F6899A62180447E0012E523 /* x25519.c in Sources */ = {isa = PBXBuildFile; fileRef = 6F6899A52180447E0012E523 /* x25519.c */; };
|
||||
6F6899A8218044FC0012E523 /* Curve25519.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F6899A7218044FC0012E523 /* Curve25519.swift */; };
|
||||
6F6899AC218099F00012E523 /* WgQuickConfigFileParser.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F6899AB218099F00012E523 /* WgQuickConfigFileParser.swift */; };
|
||||
6F693A562179E556008551C1 /* Endpoint.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F693A552179E556008551C1 /* Endpoint.swift */; };
|
||||
6F7774E1217181B1006A79B3 /* MainViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F7774DF217181B1006A79B3 /* MainViewController.swift */; };
|
||||
6F7774E2217181B1006A79B3 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F7774E0217181B1006A79B3 /* AppDelegate.swift */; };
|
||||
|
@ -58,7 +60,6 @@
|
|||
6FDEF80021863C0100D8FBF6 /* ioapi.c in Sources */ = {isa = PBXBuildFile; fileRef = 6FDEF7FF21863C0100D8FBF6 /* ioapi.c */; };
|
||||
6FDEF802218646BA00D8FBF6 /* ZipArchive.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6FDEF801218646B900D8FBF6 /* ZipArchive.swift */; };
|
||||
6FDEF806218725D200D8FBF6 /* SettingsTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6FDEF805218725D200D8FBF6 /* SettingsTableViewController.swift */; };
|
||||
6FDEF8082187442100D8FBF6 /* WgQuickConfigFileWriter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6FDEF8072187442100D8FBF6 /* WgQuickConfigFileWriter.swift */; };
|
||||
6FE1765621C90BBE002690EA /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 6FE1765421C90BBE002690EA /* Localizable.strings */; };
|
||||
6FE1765A21C90E87002690EA /* LocalizationHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6FE1765921C90E87002690EA /* LocalizationHelper.swift */; };
|
||||
6FE254FB219C10800028284D /* ZipImporter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6FE254FA219C10800028284D /* ZipImporter.swift */; };
|
||||
|
@ -125,6 +126,7 @@
|
|||
5F4541AD21C7704300994C13 /* NEVPNStatus+CustomStringConvertible.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NEVPNStatus+CustomStringConvertible.swift"; sourceTree = "<group>"; };
|
||||
5F4541B121CBFAEE00994C13 /* String+ArrayConversion.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "String+ArrayConversion.swift"; sourceTree = "<group>"; };
|
||||
5F9696A921CD6AE6008063FE /* LegacyConfigMigration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LegacyConfigMigration.swift; sourceTree = "<group>"; };
|
||||
5F9696AF21CD7128008063FE /* TunnelConfiguration+WgQuickConfig.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "TunnelConfiguration+WgQuickConfig.swift"; sourceTree = "<group>"; };
|
||||
5FF7B96121CC95DE00A7DD74 /* InterfaceConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InterfaceConfiguration.swift; sourceTree = "<group>"; };
|
||||
5FF7B96421CC95FA00A7DD74 /* PeerConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PeerConfiguration.swift; sourceTree = "<group>"; };
|
||||
6F5A2B4421AFDE020081EDD8 /* FileManager+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "FileManager+Extension.swift"; sourceTree = "<group>"; };
|
||||
|
@ -144,7 +146,6 @@
|
|||
6F6899A42180447E0012E523 /* x25519.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = x25519.h; sourceTree = "<group>"; };
|
||||
6F6899A52180447E0012E523 /* x25519.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = x25519.c; sourceTree = "<group>"; };
|
||||
6F6899A7218044FC0012E523 /* Curve25519.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Curve25519.swift; sourceTree = "<group>"; };
|
||||
6F6899AB218099F00012E523 /* WgQuickConfigFileParser.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WgQuickConfigFileParser.swift; sourceTree = "<group>"; };
|
||||
6F693A552179E556008551C1 /* Endpoint.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Endpoint.swift; sourceTree = "<group>"; };
|
||||
6F7774DF217181B1006A79B3 /* MainViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MainViewController.swift; sourceTree = "<group>"; };
|
||||
6F7774E0217181B1006A79B3 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
||||
|
@ -170,7 +171,6 @@
|
|||
6FDEF7FF21863C0100D8FBF6 /* ioapi.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ioapi.c; sourceTree = "<group>"; };
|
||||
6FDEF801218646B900D8FBF6 /* ZipArchive.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ZipArchive.swift; sourceTree = "<group>"; };
|
||||
6FDEF805218725D200D8FBF6 /* SettingsTableViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SettingsTableViewController.swift; sourceTree = "<group>"; };
|
||||
6FDEF8072187442100D8FBF6 /* WgQuickConfigFileWriter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WgQuickConfigFileWriter.swift; sourceTree = "<group>"; };
|
||||
6FE1765521C90BBE002690EA /* Base */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = Base; path = WireGuard/Base.lproj/Localizable.strings; sourceTree = "<group>"; };
|
||||
6FE1765921C90E87002690EA /* LocalizationHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocalizationHelper.swift; sourceTree = "<group>"; };
|
||||
6FE254FA219C10800028284D /* ZipImporter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ZipImporter.swift; sourceTree = "<group>"; };
|
||||
|
@ -258,6 +258,8 @@
|
|||
6FFA5D942194454A0001E2F7 /* NETunnelProviderProtocol+Extension.swift */,
|
||||
6F5A2B4421AFDE020081EDD8 /* FileManager+Extension.swift */,
|
||||
5F9696A921CD6AE6008063FE /* LegacyConfigMigration.swift */,
|
||||
5F4541B121CBFAEE00994C13 /* String+ArrayConversion.swift */,
|
||||
5F9696AF21CD7128008063FE /* TunnelConfiguration+WgQuickConfig.swift */,
|
||||
);
|
||||
path = Shared;
|
||||
sourceTree = "<group>";
|
||||
|
@ -272,15 +274,6 @@
|
|||
path = Crypto;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
6F6899AA218099D00012E523 /* ConfigFile */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
6F6899AB218099F00012E523 /* WgQuickConfigFileParser.swift */,
|
||||
6FDEF8072187442100D8FBF6 /* WgQuickConfigFileWriter.swift */,
|
||||
);
|
||||
path = ConfigFile;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
6F7774DD217181B1006A79B3 /* UI */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
|
@ -298,7 +291,6 @@
|
|||
6F7774E0217181B1006A79B3 /* AppDelegate.swift */,
|
||||
6F919EC2218A2AE90023B400 /* ErrorPresenter.swift */,
|
||||
5F45417C21C1B23600994C13 /* UITableViewCell+Reuse.swift */,
|
||||
5F4541B121CBFAEE00994C13 /* String+ArrayConversion.swift */,
|
||||
);
|
||||
path = iOS;
|
||||
sourceTree = "<group>";
|
||||
|
@ -416,7 +408,6 @@
|
|||
children = (
|
||||
6F919ED3218C65C50023B400 /* Resources */,
|
||||
6F6899A32180445A0012E523 /* Crypto */,
|
||||
6F6899AA218099D00012E523 /* ConfigFile */,
|
||||
6F7774DD217181B1006A79B3 /* UI */,
|
||||
6F7774ED21722D0C006A79B3 /* Tunnel */,
|
||||
6FDEF7E72186320E00D8FBF6 /* ZipArchive */,
|
||||
|
@ -664,9 +655,11 @@
|
|||
6FF3527121C240160008484E /* Logger.swift in Sources */,
|
||||
6F5A2B4621AFDED40081EDD8 /* FileManager+Extension.swift in Sources */,
|
||||
6FFA5DA021958ECC0001E2F7 /* ErrorNotifier.swift in Sources */,
|
||||
5F9696B121CD7128008063FE /* TunnelConfiguration+WgQuickConfig.swift in Sources */,
|
||||
6FFA5D96219446380001E2F7 /* NETunnelProviderProtocol+Extension.swift in Sources */,
|
||||
6FFA5D8E2194370D0001E2F7 /* TunnelConfiguration.swift in Sources */,
|
||||
5FF7B96621CC95FA00A7DD74 /* PeerConfiguration.swift in Sources */,
|
||||
5F9696AE21CD6F72008063FE /* String+ArrayConversion.swift in Sources */,
|
||||
6FFA5D8F2194370D0001E2F7 /* IPAddressRange.swift in Sources */,
|
||||
6FFA5D902194370D0001E2F7 /* Endpoint.swift in Sources */,
|
||||
5FF7B96321CC95DE00A7DD74 /* InterfaceConfiguration.swift in Sources */,
|
||||
|
@ -685,7 +678,6 @@
|
|||
6FE1765A21C90E87002690EA /* LocalizationHelper.swift in Sources */,
|
||||
6FF3527221C2616C0008484E /* ringlogger.c in Sources */,
|
||||
6FF3527321C2616C0008484E /* Logger.swift in Sources */,
|
||||
6F6899AC218099F00012E523 /* WgQuickConfigFileParser.swift in Sources */,
|
||||
6F7774E421718281006A79B3 /* TunnelsListTableViewController.swift in Sources */,
|
||||
6F7774EF21722D97006A79B3 /* TunnelsManager.swift in Sources */,
|
||||
5F45417D21C1B23600994C13 /* UITableViewCell+Reuse.swift in Sources */,
|
||||
|
@ -710,7 +702,6 @@
|
|||
5F9696AA21CD6AE6008063FE /* LegacyConfigMigration.swift in Sources */,
|
||||
6F5A2B4821AFF49A0081EDD8 /* FileManager+Extension.swift in Sources */,
|
||||
5F45418C21C2D48200994C13 /* TunnelEditKeyValueCell.swift in Sources */,
|
||||
6FDEF8082187442100D8FBF6 /* WgQuickConfigFileWriter.swift in Sources */,
|
||||
6FE254FB219C10800028284D /* ZipImporter.swift in Sources */,
|
||||
6F7774EA217229DB006A79B3 /* IPAddressRange.swift in Sources */,
|
||||
5F4541AE21C7704300994C13 /* NEVPNStatus+CustomStringConvertible.swift in Sources */,
|
||||
|
@ -718,6 +709,7 @@
|
|||
6FDEF7FB21863B6100D8FBF6 /* unzip.c in Sources */,
|
||||
6F6899A8218044FC0012E523 /* Curve25519.swift in Sources */,
|
||||
5F4541A021C2D6B700994C13 /* TunnelListCell.swift in Sources */,
|
||||
5F9696B021CD7128008063FE /* TunnelConfiguration+WgQuickConfig.swift in Sources */,
|
||||
6F628C41217F47DB003482A3 /* TunnelDetailTableViewController.swift in Sources */,
|
||||
6F61F1EB21B937EF00483816 /* WireGuardResult.swift in Sources */,
|
||||
6F7774F321774263006A79B3 /* TunnelEditTableViewController.swift in Sources */,
|
||||
|
|
|
@ -1,46 +0,0 @@
|
|||
// SPDX-License-Identifier: MIT
|
||||
// Copyright © 2018 WireGuard LLC. All Rights Reserved.
|
||||
|
||||
import UIKit
|
||||
|
||||
class WgQuickConfigFileWriter {
|
||||
static func writeConfigFile(from configuration: TunnelConfiguration) -> Data? {
|
||||
let interface = configuration.interface
|
||||
var output = "[Interface]\n"
|
||||
output.append("PrivateKey = \(interface.privateKey.base64EncodedString())\n")
|
||||
if let listenPort = interface.listenPort {
|
||||
output.append("ListenPort = \(listenPort)\n")
|
||||
}
|
||||
if !interface.addresses.isEmpty {
|
||||
let addressString = interface.addresses.map { $0.stringRepresentation }.joined(separator: ", ")
|
||||
output.append("Address = \(addressString)\n")
|
||||
}
|
||||
if !interface.dns.isEmpty {
|
||||
let dnsString = interface.dns.map { $0.stringRepresentation }.joined(separator: ", ")
|
||||
output.append("DNS = \(dnsString)\n")
|
||||
}
|
||||
if let mtu = interface.mtu {
|
||||
output.append("MTU = \(mtu)\n")
|
||||
}
|
||||
|
||||
for peer in configuration.peers {
|
||||
output.append("\n[Peer]\n")
|
||||
output.append("PublicKey = \(peer.publicKey.base64EncodedString())\n")
|
||||
if let preSharedKey = peer.preSharedKey {
|
||||
output.append("PresharedKey = \(preSharedKey.base64EncodedString())\n")
|
||||
}
|
||||
if !peer.allowedIPs.isEmpty {
|
||||
let allowedIPsString = peer.allowedIPs.map { $0.stringRepresentation }.joined(separator: ", ")
|
||||
output.append("AllowedIPs = \(allowedIPsString)\n")
|
||||
}
|
||||
if let endpoint = peer.endpoint {
|
||||
output.append("Endpoint = \(endpoint.stringRepresentation)\n")
|
||||
}
|
||||
if let persistentKeepAlive = peer.persistentKeepAlive {
|
||||
output.append("PersistentKeepalive = \(persistentKeepAlive)\n")
|
||||
}
|
||||
}
|
||||
|
||||
return output.data(using: .utf8)
|
||||
}
|
||||
}
|
|
@ -38,7 +38,7 @@ class MockTunnels {
|
|||
|
||||
let tunnelProviderManager = NETunnelProviderManager()
|
||||
tunnelProviderManager.protocolConfiguration = NETunnelProviderProtocol(tunnelConfiguration: tunnelConfiguration)
|
||||
tunnelProviderManager.localizedDescription = tunnelName
|
||||
tunnelProviderManager.localizedDescription = (tunnelConfiguration).interface.name
|
||||
tunnelProviderManager.isEnabled = true
|
||||
|
||||
return tunnelProviderManager
|
||||
|
|
|
@ -43,9 +43,9 @@ class TunnelsManager {
|
|||
}
|
||||
|
||||
let tunnelManagers = managers ?? []
|
||||
tunnelManagers.forEach {
|
||||
if ($0.protocolConfiguration as? NETunnelProviderProtocol)?.migrateConfigurationIfNeeded() == true {
|
||||
$0.saveToPreferences { _ in }
|
||||
tunnelManagers.forEach { tunnelManager in
|
||||
if (tunnelManager.protocolConfiguration as? NETunnelProviderProtocol)?.migrateConfigurationIfNeeded() == true {
|
||||
tunnelManager.saveToPreferences { _ in }
|
||||
}
|
||||
}
|
||||
completionHandler(.success(TunnelsManager(tunnelProviders: tunnelManagers)))
|
||||
|
@ -54,7 +54,7 @@ class TunnelsManager {
|
|||
}
|
||||
|
||||
func add(tunnelConfiguration: TunnelConfiguration, activateOnDemandSetting: ActivateOnDemandSetting = ActivateOnDemandSetting.defaultSetting, completionHandler: @escaping (WireGuardResult<TunnelContainer>) -> Void) {
|
||||
let tunnelName = tunnelConfiguration.interface.name
|
||||
let tunnelName = tunnelConfiguration.interface.name ?? ""
|
||||
if tunnelName.isEmpty {
|
||||
completionHandler(.failure(TunnelsManagerError.tunnelNameEmpty))
|
||||
return
|
||||
|
@ -67,7 +67,7 @@ class TunnelsManager {
|
|||
|
||||
let tunnelProviderManager = NETunnelProviderManager()
|
||||
tunnelProviderManager.protocolConfiguration = NETunnelProviderProtocol(tunnelConfiguration: tunnelConfiguration)
|
||||
tunnelProviderManager.localizedDescription = tunnelName
|
||||
tunnelProviderManager.localizedDescription = (tunnelConfiguration).interface.name
|
||||
tunnelProviderManager.isEnabled = true
|
||||
|
||||
activateOnDemandSetting.apply(on: tunnelProviderManager)
|
||||
|
@ -107,7 +107,7 @@ class TunnelsManager {
|
|||
}
|
||||
|
||||
func modify(tunnel: TunnelContainer, tunnelConfiguration: TunnelConfiguration, activateOnDemandSetting: ActivateOnDemandSetting, completionHandler: @escaping (TunnelsManagerError?) -> Void) {
|
||||
let tunnelName = tunnelConfiguration.interface.name
|
||||
let tunnelName = tunnelConfiguration.interface.name ?? ""
|
||||
if tunnelName.isEmpty {
|
||||
completionHandler(TunnelsManagerError.tunnelNameEmpty)
|
||||
return
|
||||
|
@ -123,12 +123,10 @@ class TunnelsManager {
|
|||
tunnel.name = tunnelName
|
||||
}
|
||||
|
||||
let shouldRestartIfActive = !((tunnelProviderManager.protocolConfiguration as? NETunnelProviderProtocol)?.hasTunnelConfiguration(tunnelConfiguration: tunnelConfiguration) ?? false)
|
||||
|
||||
tunnelProviderManager.protocolConfiguration = NETunnelProviderProtocol(tunnelConfiguration: tunnelConfiguration)
|
||||
tunnelProviderManager.localizedDescription = tunnelName
|
||||
tunnelProviderManager.localizedDescription = (tunnelConfiguration).interface.name
|
||||
tunnelProviderManager.isEnabled = true
|
||||
|
||||
|
||||
let isActivatingOnDemand = !tunnelProviderManager.isOnDemandEnabled && activateOnDemandSetting.isActivateOnDemandEnabled
|
||||
activateOnDemandSetting.apply(on: tunnelProviderManager)
|
||||
|
||||
|
@ -148,12 +146,10 @@ class TunnelsManager {
|
|||
}
|
||||
self.tunnelsListDelegate?.tunnelModified(at: self.tunnels.firstIndex(of: tunnel)!)
|
||||
|
||||
if shouldRestartIfActive {
|
||||
if tunnel.status == .active || tunnel.status == .activating || tunnel.status == .reasserting {
|
||||
// Turn off the tunnel, and then turn it back on, so the changes are made effective
|
||||
tunnel.status = .restarting
|
||||
(tunnel.tunnelProvider.connection as? NETunnelProviderSession)?.stopTunnel()
|
||||
}
|
||||
if tunnel.status == .active || tunnel.status == .activating || tunnel.status == .reasserting {
|
||||
// Turn off the tunnel, and then turn it back on, so the changes are made effective
|
||||
tunnel.status = .restarting
|
||||
(tunnel.tunnelProvider.connection as? NETunnelProviderSession)?.stopTunnel()
|
||||
}
|
||||
|
||||
if isActivatingOnDemand {
|
||||
|
@ -353,7 +349,7 @@ class TunnelContainer: NSObject {
|
|||
private var lastTunnelConnectionStatus: NEVPNStatus?
|
||||
|
||||
var tunnelConfiguration: TunnelConfiguration? {
|
||||
return (tunnelProvider.protocolConfiguration as? NETunnelProviderProtocol)?.tunnelConfiguration
|
||||
return (tunnelProvider.protocolConfiguration as? NETunnelProviderProtocol)?.tunnelConfiguration(name: tunnelProvider.localizedDescription)
|
||||
}
|
||||
|
||||
var activateOnDemandSetting: ActivateOnDemandSetting {
|
||||
|
|
|
@ -101,7 +101,7 @@ class QRScanViewController: UIViewController {
|
|||
}
|
||||
|
||||
func scanDidComplete(withCode code: String) {
|
||||
let scannedTunnelConfiguration = try? WgQuickConfigFileParser.parse(code, name: "Scanned")
|
||||
let scannedTunnelConfiguration = try? TunnelConfiguration(code, name: "Scanned")
|
||||
guard let tunnelConfiguration = scannedTunnelConfiguration else {
|
||||
scanDidEncounterError(title: tr("alertScanQRCodeInvalidQRCodeTitle"), message: tr("alertScanQRCodeInvalidQRCodeMessage"))
|
||||
return
|
||||
|
|
|
@ -180,7 +180,7 @@ class TunnelsListTableViewController: UIViewController {
|
|||
} else /* if (url.pathExtension == "conf") -- we assume everything else is a conf */ {
|
||||
let fileBaseName = url.deletingPathExtension().lastPathComponent.trimmingCharacters(in: .whitespacesAndNewlines)
|
||||
if let fileContents = try? String(contentsOf: url),
|
||||
let tunnelConfiguration = try? WgQuickConfigFileParser.parse(fileContents, name: fileBaseName) {
|
||||
let tunnelConfiguration = try? TunnelConfiguration(fileContents, name: fileBaseName) {
|
||||
tunnelsManager.add(tunnelConfiguration: tunnelConfiguration) { [weak self] result in
|
||||
if let error = result.error {
|
||||
ErrorPresenter.showErrorAlert(error: error, from: self, onPresented: completionHandler)
|
||||
|
|
|
@ -22,8 +22,8 @@ class ZipExporter {
|
|||
var inputsToArchiver: [(fileName: String, contents: Data)] = []
|
||||
var lastTunnelName: String = ""
|
||||
for tunnelConfiguration in tunnelConfigurations {
|
||||
if let contents = WgQuickConfigFileWriter.writeConfigFile(from: tunnelConfiguration) {
|
||||
let name = tunnelConfiguration.interface.name
|
||||
if let contents = tunnelConfiguration.asWgQuickConfig().data(using: .utf8) {
|
||||
let name = tunnelConfiguration.interface.name ?? ""
|
||||
if name.isEmpty || name == lastTunnelName { continue }
|
||||
inputsToArchiver.append((fileName: "\(name).conf", contents: contents))
|
||||
lastTunnelName = name
|
||||
|
|
|
@ -43,12 +43,8 @@ class ZipImporter {
|
|||
if index > 0 && file == unarchivedFiles[index - 1] {
|
||||
continue
|
||||
}
|
||||
guard let fileContents = String(data: file.contents, encoding: .utf8) else {
|
||||
continue
|
||||
}
|
||||
guard let tunnelConfig = try? WgQuickConfigFileParser.parse(fileContents, name: file.fileBaseName) else {
|
||||
continue
|
||||
}
|
||||
guard let fileContents = String(data: file.contents, encoding: .utf8) else { continue }
|
||||
guard let tunnelConfig = try? TunnelConfiguration(fileContents, name: file.fileBaseName) else { continue }
|
||||
configs[index] = tunnelConfig
|
||||
}
|
||||
DispatchQueue.main.async { completion(.success(configs)) }
|
||||
|
|
|
@ -29,7 +29,7 @@ class PacketTunnelProvider: NEPacketTunnelProvider {
|
|||
let errorNotifier = ErrorNotifier(activationAttemptId: activationAttemptId, tunnelProvider: self)
|
||||
|
||||
guard let tunnelProviderProtocol = protocolConfiguration as? NETunnelProviderProtocol,
|
||||
let tunnelConfiguration = tunnelProviderProtocol.tunnelConfiguration else {
|
||||
let tunnelConfiguration = tunnelProviderProtocol.tunnelConfiguration(name: nil) else {
|
||||
errorNotifier.notify(PacketTunnelProviderError.savedProtocolConfigurationIsInvalid)
|
||||
startTunnelCompletionHandler(PacketTunnelProviderError.savedProtocolConfigurationIsInvalid)
|
||||
return
|
||||
|
@ -132,7 +132,6 @@ class PacketTunnelProvider: NEPacketTunnelProvider {
|
|||
if err == -EADDRINUSE && listenPort != nil {
|
||||
let endpointString = packetTunnelSettingsGenerator.endpointUapiConfiguration(currentListenPort: 0)
|
||||
_ = endpointString.withGoString { return wgSetConfig(handle, $0) }
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue