Merge branch 'manager-subspec'
This commit is contained in:
commit
5ab86d22bc
10
.jazzy.yaml
10
.jazzy.yaml
|
@ -43,6 +43,16 @@ custom_categories:
|
|||
- NETunnelInterface
|
||||
- NEUDPSocket
|
||||
- NSNotification
|
||||
- name: Manager
|
||||
children:
|
||||
- VPN
|
||||
- VPNProvider
|
||||
- MockVPNProvider
|
||||
- StandardVPNProvider
|
||||
- VPNConfiguration
|
||||
- NetworkExtensionVPNConfiguration
|
||||
- VPNStatus
|
||||
- NSNotification
|
||||
- name: Protocols/OpenVPN
|
||||
children:
|
||||
- OpenVPN
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
//
|
||||
// AppDelegate.swift
|
||||
// BasicTunnel-iOS
|
||||
// Demo
|
||||
//
|
||||
// Created by Davide De Rosa on 2/11/17.
|
||||
// Copyright (c) 2018 Davide De Rosa. All rights reserved.
|
||||
// Copyright (c) 2020 Davide De Rosa. All rights reserved.
|
||||
//
|
||||
// https://github.com/keeshux
|
||||
//
|
||||
|
@ -22,18 +22,6 @@
|
|||
// You should have received a copy of the GNU General Public License
|
||||
// along with TunnelKit. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// This file incorporates work covered by the following copyright and
|
||||
// permission notice:
|
||||
//
|
||||
// Copyright (c) 2018-Present Private Internet Access
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import NetworkExtension
|
||||
|
|
|
@ -1,11 +1,9 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="14269.14" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="BYZ-38-t0r">
|
||||
<device id="retina4_7" orientation="portrait">
|
||||
<adaptation id="fullscreen"/>
|
||||
</device>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="16097" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="BYZ-38-t0r">
|
||||
<device id="retina4_7" orientation="portrait" appearance="light"/>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14252.5"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="16087"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<scenes>
|
||||
|
@ -22,40 +20,35 @@
|
|||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" textAlignment="natural" minimumFontSize="17" clearButtonMode="always" translatesAutoresizingMaskIntoConstraints="NO" id="bc6-yT-aty">
|
||||
<rect key="frame" x="20" y="190" width="335" height="30"/>
|
||||
<nil key="textColor"/>
|
||||
<rect key="frame" x="20" y="182" width="335" height="34"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="14"/>
|
||||
<textInputTraits key="textInputTraits" autocorrectionType="no" spellCheckingType="no" keyboardType="alphabet" secureTextEntry="YES"/>
|
||||
</textField>
|
||||
<textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" textAlignment="natural" minimumFontSize="17" clearButtonMode="always" translatesAutoresizingMaskIntoConstraints="NO" id="ONL-vF-iUY">
|
||||
<rect key="frame" x="20" y="40" width="335" height="30"/>
|
||||
<nil key="textColor"/>
|
||||
<rect key="frame" x="20" y="20" width="335" height="34"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="14"/>
|
||||
<textInputTraits key="textInputTraits" autocorrectionType="no" spellCheckingType="no" keyboardType="alphabet"/>
|
||||
</textField>
|
||||
<textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" textAlignment="natural" minimumFontSize="17" clearButtonMode="always" translatesAutoresizingMaskIntoConstraints="NO" id="dQS-Ma-dYP">
|
||||
<rect key="frame" x="20" y="140" width="335" height="30"/>
|
||||
<nil key="textColor"/>
|
||||
<rect key="frame" x="20" y="128" width="335" height="34"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="14"/>
|
||||
<textInputTraits key="textInputTraits" autocorrectionType="no" spellCheckingType="no" keyboardType="alphabet"/>
|
||||
</textField>
|
||||
<textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" textAlignment="natural" minimumFontSize="17" clearButtonMode="always" translatesAutoresizingMaskIntoConstraints="NO" id="XwE-sE-aPN">
|
||||
<rect key="frame" x="20" y="90" width="245" height="30"/>
|
||||
<nil key="textColor"/>
|
||||
<rect key="frame" x="20" y="74" width="245" height="34"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="14"/>
|
||||
<textInputTraits key="textInputTraits" autocorrectionType="no" spellCheckingType="no" keyboardType="alphabet"/>
|
||||
</textField>
|
||||
<textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" textAlignment="natural" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="7LH-tE-it9">
|
||||
<rect key="frame" x="275" y="90" width="80" height="30"/>
|
||||
<rect key="frame" x="275" y="74" width="80" height="34"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="80" id="aWP-Ug-b9B"/>
|
||||
</constraints>
|
||||
<nil key="textColor"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="14"/>
|
||||
<textInputTraits key="textInputTraits"/>
|
||||
</textField>
|
||||
<button opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="249" contentHorizontalAlignment="left" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Teo-8d-LYJ">
|
||||
<rect key="frame" x="20" y="240" width="276" height="70"/>
|
||||
<rect key="frame" x="20" y="236" width="276" height="70"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="48"/>
|
||||
<state key="normal" title="Connect"/>
|
||||
<connections>
|
||||
|
@ -63,19 +56,19 @@
|
|||
</connections>
|
||||
</button>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="TCP" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="sA4-W9-jxo">
|
||||
<rect key="frame" x="312" y="240" width="37.5" height="24"/>
|
||||
<rect key="frame" x="312" y="236" width="37.5" height="24"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="20"/>
|
||||
<nil key="textColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" contentHorizontalAlignment="center" contentVerticalAlignment="center" translatesAutoresizingMaskIntoConstraints="NO" id="WZf-S5-SqC">
|
||||
<rect key="frame" x="306" y="279" width="51" height="31"/>
|
||||
<rect key="frame" x="306" y="275" width="51" height="31"/>
|
||||
<connections>
|
||||
<action selector="tcpClicked:" destination="BYZ-38-t0r" eventType="valueChanged" id="ZJI-Jw-pow"/>
|
||||
</connections>
|
||||
</switch>
|
||||
<button opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="249" contentHorizontalAlignment="left" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="6dU-fF-FSg">
|
||||
<rect key="frame" x="20" y="310" width="335" height="41"/>
|
||||
<rect key="frame" x="20" y="306" width="335" height="41"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="24"/>
|
||||
<state key="normal" title="See log"/>
|
||||
<connections>
|
||||
|
@ -83,13 +76,13 @@
|
|||
</connections>
|
||||
</button>
|
||||
<textView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" editable="NO" textAlignment="natural" translatesAutoresizingMaskIntoConstraints="NO" id="UNN-CR-rdr">
|
||||
<rect key="frame" x="20" y="371" width="335" height="276"/>
|
||||
<rect key="frame" x="20" y="367" width="335" height="280"/>
|
||||
<color key="backgroundColor" cocoaTouchSystemColor="groupTableViewBackgroundColor"/>
|
||||
<fontDescription key="fontDescription" name="CourierNewPSMT" family="Courier New" pointSize="17"/>
|
||||
<textInputTraits key="textInputTraits" autocapitalizationType="sentences"/>
|
||||
</textView>
|
||||
</subviews>
|
||||
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
|
||||
<constraints>
|
||||
<constraint firstItem="UNN-CR-rdr" firstAttribute="top" secondItem="6dU-fF-FSg" secondAttribute="bottom" constant="20" id="03h-H3-dSN"/>
|
||||
<constraint firstItem="7LH-tE-it9" firstAttribute="centerY" secondItem="XwE-sE-aPN" secondAttribute="centerY" id="0wJ-c9-Gcy"/>
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
//
|
||||
// ViewController.swift
|
||||
// BasicTunnel-iOS
|
||||
// Demo
|
||||
//
|
||||
// Created by Davide De Rosa on 2/11/17.
|
||||
// Copyright (c) 2018 Davide De Rosa. All rights reserved.
|
||||
// Copyright (c) 2020 Davide De Rosa. All rights reserved.
|
||||
//
|
||||
// https://github.com/keeshux
|
||||
//
|
||||
|
@ -22,95 +22,13 @@
|
|||
// You should have received a copy of the GNU General Public License
|
||||
// along with TunnelKit. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// This file incorporates work covered by the following copyright and
|
||||
// permission notice:
|
||||
//
|
||||
// Copyright (c) 2018-Present Private Internet Access
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import NetworkExtension
|
||||
import TunnelKit
|
||||
|
||||
private let ca = OpenVPN.CryptoContainer(pem: """
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIFqzCCBJOgAwIBAgIJAKZ7D5Yv87qDMA0GCSqGSIb3DQEBDQUAMIHoMQswCQYD
|
||||
VQQGEwJVUzELMAkGA1UECBMCQ0ExEzARBgNVBAcTCkxvc0FuZ2VsZXMxIDAeBgNV
|
||||
BAoTF1ByaXZhdGUgSW50ZXJuZXQgQWNjZXNzMSAwHgYDVQQLExdQcml2YXRlIElu
|
||||
dGVybmV0IEFjY2VzczEgMB4GA1UEAxMXUHJpdmF0ZSBJbnRlcm5ldCBBY2Nlc3Mx
|
||||
IDAeBgNVBCkTF1ByaXZhdGUgSW50ZXJuZXQgQWNjZXNzMS8wLQYJKoZIhvcNAQkB
|
||||
FiBzZWN1cmVAcHJpdmF0ZWludGVybmV0YWNjZXNzLmNvbTAeFw0xNDA0MTcxNzM1
|
||||
MThaFw0zNDA0MTIxNzM1MThaMIHoMQswCQYDVQQGEwJVUzELMAkGA1UECBMCQ0Ex
|
||||
EzARBgNVBAcTCkxvc0FuZ2VsZXMxIDAeBgNVBAoTF1ByaXZhdGUgSW50ZXJuZXQg
|
||||
QWNjZXNzMSAwHgYDVQQLExdQcml2YXRlIEludGVybmV0IEFjY2VzczEgMB4GA1UE
|
||||
AxMXUHJpdmF0ZSBJbnRlcm5ldCBBY2Nlc3MxIDAeBgNVBCkTF1ByaXZhdGUgSW50
|
||||
ZXJuZXQgQWNjZXNzMS8wLQYJKoZIhvcNAQkBFiBzZWN1cmVAcHJpdmF0ZWludGVy
|
||||
bmV0YWNjZXNzLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAPXD
|
||||
L1L9tX6DGf36liA7UBTy5I869z0UVo3lImfOs/GSiFKPtInlesP65577nd7UNzzX
|
||||
lH/P/CnFPdBWlLp5ze3HRBCc/Avgr5CdMRkEsySL5GHBZsx6w2cayQ2EcRhVTwWp
|
||||
cdldeNO+pPr9rIgPrtXqT4SWViTQRBeGM8CDxAyTopTsobjSiYZCF9Ta1gunl0G/
|
||||
8Vfp+SXfYCC+ZzWvP+L1pFhPRqzQQ8k+wMZIovObK1s+nlwPaLyayzw9a8sUnvWB
|
||||
/5rGPdIYnQWPgoNlLN9HpSmsAcw2z8DXI9pIxbr74cb3/HSfuYGOLkRqrOk6h4RC
|
||||
OfuWoTrZup1uEOn+fw8CAwEAAaOCAVQwggFQMB0GA1UdDgQWBBQv63nQ/pJAt5tL
|
||||
y8VJcbHe22ZOsjCCAR8GA1UdIwSCARYwggESgBQv63nQ/pJAt5tLy8VJcbHe22ZO
|
||||
sqGB7qSB6zCB6DELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNBMRMwEQYDVQQHEwpM
|
||||
b3NBbmdlbGVzMSAwHgYDVQQKExdQcml2YXRlIEludGVybmV0IEFjY2VzczEgMB4G
|
||||
A1UECxMXUHJpdmF0ZSBJbnRlcm5ldCBBY2Nlc3MxIDAeBgNVBAMTF1ByaXZhdGUg
|
||||
SW50ZXJuZXQgQWNjZXNzMSAwHgYDVQQpExdQcml2YXRlIEludGVybmV0IEFjY2Vz
|
||||
czEvMC0GCSqGSIb3DQEJARYgc2VjdXJlQHByaXZhdGVpbnRlcm5ldGFjY2Vzcy5j
|
||||
b22CCQCmew+WL/O6gzAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBDQUAA4IBAQAn
|
||||
a5PgrtxfwTumD4+3/SYvwoD66cB8IcK//h1mCzAduU8KgUXocLx7QgJWo9lnZ8xU
|
||||
ryXvWab2usg4fqk7FPi00bED4f4qVQFVfGfPZIH9QQ7/48bPM9RyfzImZWUCenK3
|
||||
7pdw4Bvgoys2rHLHbGen7f28knT2j/cbMxd78tQc20TIObGjo8+ISTRclSTRBtyC
|
||||
GohseKYpTS9himFERpUgNtefvYHbn70mIOzfOJFTVqfrptf9jXa9N8Mpy3ayfodz
|
||||
1wiqdteqFXkTYoSDctgKMiZ6GdocK9nMroQipIQtpnwd4yBDWIyC6Bvlkrq5TQUt
|
||||
YDQ8z9v+DMO6iwyIDRiU
|
||||
-----END CERTIFICATE-----
|
||||
""")
|
||||
private let appGroup = "group.com.algoritmico.ios.demo.BasicTunnel"
|
||||
|
||||
extension ViewController {
|
||||
private static let appGroup = "group.com.algoritmico.ios.demo.BasicTunnel"
|
||||
|
||||
private static let tunnelIdentifier = "com.algoritmico.ios.demo.BasicTunnel.Extension"
|
||||
|
||||
private func makeProtocol() -> NETunnelProviderProtocol {
|
||||
let server = textServer.text!
|
||||
let domain = textDomain.text!
|
||||
|
||||
let hostname = ((domain == "") ? server : [server, domain].joined(separator: "."))
|
||||
let port = UInt16(textPort.text!)!
|
||||
let credentials = OpenVPN.Credentials(textUsername.text!, textPassword.text!)
|
||||
|
||||
var sessionBuilder = OpenVPN.ConfigurationBuilder()
|
||||
sessionBuilder.ca = ca
|
||||
sessionBuilder.cipher = .aes128cbc
|
||||
sessionBuilder.digest = .sha1
|
||||
sessionBuilder.compressionFraming = .compLZO
|
||||
sessionBuilder.renegotiatesAfter = nil
|
||||
sessionBuilder.hostname = hostname
|
||||
let socketType: SocketType = switchTCP.isOn ? .tcp : .udp
|
||||
sessionBuilder.endpointProtocols = [EndpointProtocol(socketType, port)]
|
||||
sessionBuilder.usesPIAPatches = true
|
||||
var builder = OpenVPNTunnelProvider.ConfigurationBuilder(sessionConfiguration: sessionBuilder.build())
|
||||
builder.mtu = 1350
|
||||
builder.shouldDebug = true
|
||||
builder.masksPrivateData = false
|
||||
|
||||
let configuration = builder.build()
|
||||
return try! configuration.generatedTunnelProtocol(
|
||||
withBundleIdentifier: ViewController.tunnelIdentifier,
|
||||
appGroup: ViewController.appGroup,
|
||||
credentials: credentials
|
||||
)
|
||||
}
|
||||
}
|
||||
private let tunnelIdentifier = "com.algoritmico.ios.demo.BasicTunnel.Extension"
|
||||
|
||||
class ViewController: UIViewController, URLSessionDataDelegate {
|
||||
@IBOutlet var textUsername: UITextField!
|
||||
|
@ -129,160 +47,78 @@ class ViewController: UIViewController, URLSessionDataDelegate {
|
|||
|
||||
@IBOutlet var textLog: UITextView!
|
||||
|
||||
//
|
||||
|
||||
var currentManager: NETunnelProviderManager?
|
||||
|
||||
var status = NEVPNStatus.invalid
|
||||
private let vpn = StandardVPNProvider(bundleIdentifier: tunnelIdentifier)
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
|
||||
textServer.text = "germany"
|
||||
textDomain.text = "privateinternetaccess.com"
|
||||
textPort.text = "1198"
|
||||
textServer.text = "es"
|
||||
textDomain.text = "lazerpenguin.com"
|
||||
textPort.text = "443"
|
||||
switchTCP.isOn = false
|
||||
textUsername.text = "myusername"
|
||||
textPassword.text = "mypassword"
|
||||
textUsername.text = ""
|
||||
textPassword.text = ""
|
||||
|
||||
NotificationCenter.default.addObserver(self,
|
||||
selector: #selector(VPNStatusDidChange(notification:)),
|
||||
name: .NEVPNStatusDidChange,
|
||||
object: nil)
|
||||
NotificationCenter.default.addObserver(
|
||||
self,
|
||||
selector: #selector(VPNStatusDidChange(notification:)),
|
||||
name: VPN.didChangeStatus,
|
||||
object: nil
|
||||
)
|
||||
|
||||
reloadCurrentManager(nil)
|
||||
vpn.prepare(completionHandler: nil)
|
||||
|
||||
//
|
||||
|
||||
testFetchRef()
|
||||
}
|
||||
|
||||
@IBAction func connectionClicked(_ sender: Any) {
|
||||
let block = {
|
||||
switch (self.status) {
|
||||
case .invalid, .disconnected:
|
||||
self.connect()
|
||||
|
||||
case .connected, .connecting:
|
||||
self.disconnect()
|
||||
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if (status == .invalid) {
|
||||
reloadCurrentManager({ (error) in
|
||||
block()
|
||||
})
|
||||
}
|
||||
else {
|
||||
block()
|
||||
switch vpn.status {
|
||||
case .disconnected:
|
||||
connect()
|
||||
|
||||
case .connected, .connecting, .disconnecting:
|
||||
disconnect()
|
||||
}
|
||||
}
|
||||
|
||||
@IBAction func tcpClicked(_ sender: Any) {
|
||||
if switchTCP.isOn {
|
||||
textPort.text = "502"
|
||||
} else {
|
||||
textPort.text = "1198"
|
||||
}
|
||||
}
|
||||
|
||||
func connect() {
|
||||
configureVPN({ (manager) in
|
||||
return self.makeProtocol()
|
||||
}, completionHandler: { (error) in
|
||||
let server = textServer.text!
|
||||
let domain = textDomain.text!
|
||||
let hostname = ((domain == "") ? server : [server, domain].joined(separator: "."))
|
||||
let port = UInt16(textPort.text!)!
|
||||
let socketType: SocketType = switchTCP.isOn ? .tcp : .udp
|
||||
|
||||
let credentials = OpenVPN.Credentials(textUsername.text!, textPassword.text!)
|
||||
let cfg = Configuration.make(hostname: hostname, port: port, socketType: socketType)
|
||||
let proto = try! cfg.generatedTunnelProtocol(
|
||||
withBundleIdentifier: tunnelIdentifier,
|
||||
appGroup: appGroup,
|
||||
credentials: credentials
|
||||
)
|
||||
let neCfg = NetworkExtensionVPNConfiguration(protocolConfiguration: proto, onDemandRules: [])
|
||||
vpn.reconnect(configuration: neCfg) { (error) in
|
||||
if let error = error {
|
||||
print("configure error: \(error)")
|
||||
return
|
||||
}
|
||||
let session = self.currentManager?.connection as! NETunnelProviderSession
|
||||
do {
|
||||
try session.startTunnel()
|
||||
} catch let e {
|
||||
print("error starting tunnel: \(e)")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func disconnect() {
|
||||
configureVPN({ (manager) in
|
||||
return nil
|
||||
}, completionHandler: { (error) in
|
||||
self.currentManager?.connection.stopVPNTunnel()
|
||||
})
|
||||
vpn.disconnect(completionHandler: nil)
|
||||
}
|
||||
|
||||
@IBAction func displayLog() {
|
||||
guard let vpn = currentManager?.connection as? NETunnelProviderSession else {
|
||||
return
|
||||
}
|
||||
try? vpn.sendProviderMessage(OpenVPNTunnelProvider.Message.requestLog.data) { (data) in
|
||||
guard let data = data, let log = String(data: data, encoding: .utf8) else {
|
||||
return
|
||||
}
|
||||
vpn.requestDebugLog(fallback: { "" }) { (log) in
|
||||
self.textLog.text = log
|
||||
}
|
||||
}
|
||||
|
||||
func configureVPN(_ configure: @escaping (NETunnelProviderManager) -> NETunnelProviderProtocol?, completionHandler: @escaping (Error?) -> Void) {
|
||||
reloadCurrentManager { (error) in
|
||||
if let error = error {
|
||||
print("error reloading preferences: \(error)")
|
||||
completionHandler(error)
|
||||
return
|
||||
}
|
||||
|
||||
let manager = self.currentManager!
|
||||
if let protocolConfiguration = configure(manager) {
|
||||
manager.protocolConfiguration = protocolConfiguration
|
||||
}
|
||||
manager.isEnabled = true
|
||||
|
||||
manager.saveToPreferences { (error) in
|
||||
if let error = error {
|
||||
print("error saving preferences: \(error)")
|
||||
completionHandler(error)
|
||||
return
|
||||
}
|
||||
print("saved preferences")
|
||||
self.reloadCurrentManager(completionHandler)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func reloadCurrentManager(_ completionHandler: ((Error?) -> Void)?) {
|
||||
NETunnelProviderManager.loadAllFromPreferences { (managers, error) in
|
||||
if let error = error {
|
||||
completionHandler?(error)
|
||||
return
|
||||
}
|
||||
|
||||
var manager: NETunnelProviderManager?
|
||||
|
||||
for m in managers! {
|
||||
if let p = m.protocolConfiguration as? NETunnelProviderProtocol {
|
||||
if (p.providerBundleIdentifier == ViewController.tunnelIdentifier) {
|
||||
manager = m
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (manager == nil) {
|
||||
manager = NETunnelProviderManager()
|
||||
}
|
||||
|
||||
self.currentManager = manager
|
||||
self.status = manager!.connection.status
|
||||
self.updateButton()
|
||||
completionHandler?(nil)
|
||||
}
|
||||
}
|
||||
|
||||
func updateButton() {
|
||||
switch status {
|
||||
switch vpn.status {
|
||||
case .connected, .connecting:
|
||||
buttonConnection.setTitle("Disconnect", for: .normal)
|
||||
|
||||
|
@ -291,19 +127,11 @@ class ViewController: UIViewController, URLSessionDataDelegate {
|
|||
|
||||
case .disconnecting:
|
||||
buttonConnection.setTitle("Disconnecting", for: .normal)
|
||||
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
@objc private func VPNStatusDidChange(notification: NSNotification) {
|
||||
guard let status = currentManager?.connection.status else {
|
||||
print("VPNStatusDidChange")
|
||||
return
|
||||
}
|
||||
print("VPNStatusDidChange: \(status.rawValue)")
|
||||
self.status = status
|
||||
print("VPNStatusDidChange: \(vpn.status)")
|
||||
updateButton()
|
||||
}
|
||||
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
//
|
||||
// AppDelegate.swift
|
||||
// BasicTunnel-macOS
|
||||
// Demo
|
||||
//
|
||||
// Created by Davide De Rosa on 10/15/17.
|
||||
// Copyright (c) 2018 Davide De Rosa. All rights reserved.
|
||||
// Copyright (c) 2020 Davide De Rosa. All rights reserved.
|
||||
//
|
||||
// https://github.com/keeshux
|
||||
//
|
||||
|
@ -22,18 +22,6 @@
|
|||
// You should have received a copy of the GNU General Public License
|
||||
// along with TunnelKit. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// This file incorporates work covered by the following copyright and
|
||||
// permission notice:
|
||||
//
|
||||
// Copyright (c) 2018-Present Private Internet Access
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
//
|
||||
|
||||
import Cocoa
|
||||
import SwiftyBeaver
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
<key>LSMinimumSystemVersion</key>
|
||||
<string>$(MACOSX_DEPLOYMENT_TARGET)</string>
|
||||
<key>NSHumanReadableCopyright</key>
|
||||
<string>Copyright (c) 2018 Davide De Rosa. All rights reserved.</string>
|
||||
<string>Copyright (c) 2020 Davide De Rosa. All rights reserved.</string>
|
||||
<key>NSMainStoryboardFile</key>
|
||||
<string>Main</string>
|
||||
<key>NSPrincipalClass</key>
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
//
|
||||
// ViewController.swift
|
||||
// BasicTunnel-macOS
|
||||
// Demo
|
||||
//
|
||||
// Created by Davide De Rosa on 10/15/17.
|
||||
// Copyright (c) 2018 Davide De Rosa. All rights reserved.
|
||||
// Copyright (c) 2020 Davide De Rosa. All rights reserved.
|
||||
//
|
||||
// https://github.com/keeshux
|
||||
//
|
||||
|
@ -22,96 +22,14 @@
|
|||
// You should have received a copy of the GNU General Public License
|
||||
// along with TunnelKit. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// This file incorporates work covered by the following copyright and
|
||||
// permission notice:
|
||||
//
|
||||
// Copyright (c) 2018-Present Private Internet Access
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
//
|
||||
|
||||
import Cocoa
|
||||
import NetworkExtension
|
||||
import TunnelKit
|
||||
|
||||
private let ca = OpenVPN.CryptoContainer(pem: """
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIFqzCCBJOgAwIBAgIJAKZ7D5Yv87qDMA0GCSqGSIb3DQEBDQUAMIHoMQswCQYD
|
||||
VQQGEwJVUzELMAkGA1UECBMCQ0ExEzARBgNVBAcTCkxvc0FuZ2VsZXMxIDAeBgNV
|
||||
BAoTF1ByaXZhdGUgSW50ZXJuZXQgQWNjZXNzMSAwHgYDVQQLExdQcml2YXRlIElu
|
||||
dGVybmV0IEFjY2VzczEgMB4GA1UEAxMXUHJpdmF0ZSBJbnRlcm5ldCBBY2Nlc3Mx
|
||||
IDAeBgNVBCkTF1ByaXZhdGUgSW50ZXJuZXQgQWNjZXNzMS8wLQYJKoZIhvcNAQkB
|
||||
FiBzZWN1cmVAcHJpdmF0ZWludGVybmV0YWNjZXNzLmNvbTAeFw0xNDA0MTcxNzM1
|
||||
MThaFw0zNDA0MTIxNzM1MThaMIHoMQswCQYDVQQGEwJVUzELMAkGA1UECBMCQ0Ex
|
||||
EzARBgNVBAcTCkxvc0FuZ2VsZXMxIDAeBgNVBAoTF1ByaXZhdGUgSW50ZXJuZXQg
|
||||
QWNjZXNzMSAwHgYDVQQLExdQcml2YXRlIEludGVybmV0IEFjY2VzczEgMB4GA1UE
|
||||
AxMXUHJpdmF0ZSBJbnRlcm5ldCBBY2Nlc3MxIDAeBgNVBCkTF1ByaXZhdGUgSW50
|
||||
ZXJuZXQgQWNjZXNzMS8wLQYJKoZIhvcNAQkBFiBzZWN1cmVAcHJpdmF0ZWludGVy
|
||||
bmV0YWNjZXNzLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAPXD
|
||||
L1L9tX6DGf36liA7UBTy5I869z0UVo3lImfOs/GSiFKPtInlesP65577nd7UNzzX
|
||||
lH/P/CnFPdBWlLp5ze3HRBCc/Avgr5CdMRkEsySL5GHBZsx6w2cayQ2EcRhVTwWp
|
||||
cdldeNO+pPr9rIgPrtXqT4SWViTQRBeGM8CDxAyTopTsobjSiYZCF9Ta1gunl0G/
|
||||
8Vfp+SXfYCC+ZzWvP+L1pFhPRqzQQ8k+wMZIovObK1s+nlwPaLyayzw9a8sUnvWB
|
||||
/5rGPdIYnQWPgoNlLN9HpSmsAcw2z8DXI9pIxbr74cb3/HSfuYGOLkRqrOk6h4RC
|
||||
OfuWoTrZup1uEOn+fw8CAwEAAaOCAVQwggFQMB0GA1UdDgQWBBQv63nQ/pJAt5tL
|
||||
y8VJcbHe22ZOsjCCAR8GA1UdIwSCARYwggESgBQv63nQ/pJAt5tLy8VJcbHe22ZO
|
||||
sqGB7qSB6zCB6DELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNBMRMwEQYDVQQHEwpM
|
||||
b3NBbmdlbGVzMSAwHgYDVQQKExdQcml2YXRlIEludGVybmV0IEFjY2VzczEgMB4G
|
||||
A1UECxMXUHJpdmF0ZSBJbnRlcm5ldCBBY2Nlc3MxIDAeBgNVBAMTF1ByaXZhdGUg
|
||||
SW50ZXJuZXQgQWNjZXNzMSAwHgYDVQQpExdQcml2YXRlIEludGVybmV0IEFjY2Vz
|
||||
czEvMC0GCSqGSIb3DQEJARYgc2VjdXJlQHByaXZhdGVpbnRlcm5ldGFjY2Vzcy5j
|
||||
b22CCQCmew+WL/O6gzAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBDQUAA4IBAQAn
|
||||
a5PgrtxfwTumD4+3/SYvwoD66cB8IcK//h1mCzAduU8KgUXocLx7QgJWo9lnZ8xU
|
||||
ryXvWab2usg4fqk7FPi00bED4f4qVQFVfGfPZIH9QQ7/48bPM9RyfzImZWUCenK3
|
||||
7pdw4Bvgoys2rHLHbGen7f28knT2j/cbMxd78tQc20TIObGjo8+ISTRclSTRBtyC
|
||||
GohseKYpTS9himFERpUgNtefvYHbn70mIOzfOJFTVqfrptf9jXa9N8Mpy3ayfodz
|
||||
1wiqdteqFXkTYoSDctgKMiZ6GdocK9nMroQipIQtpnwd4yBDWIyC6Bvlkrq5TQUt
|
||||
YDQ8z9v+DMO6iwyIDRiU
|
||||
-----END CERTIFICATE-----
|
||||
""")
|
||||
private let appGroup = "DTDYD63ZX9.group.com.algoritmico.macos.demo.BasicTunnel"
|
||||
|
||||
extension ViewController {
|
||||
private static let appGroup = "DTDYD63ZX9.group.com.algoritmico.macos.demo.BasicTunnel"
|
||||
|
||||
private static let tunnelIdentifier = "com.algoritmico.macos.demo.BasicTunnel.Extension"
|
||||
|
||||
private func makeProtocol() -> NETunnelProviderProtocol {
|
||||
let server = textServer.stringValue
|
||||
let domain = textDomain.stringValue
|
||||
|
||||
let hostname = ((domain == "") ? server : [server, domain].joined(separator: "."))
|
||||
let port = UInt16(textPort.stringValue)!
|
||||
let credentials = OpenVPN.Credentials(textUsername.stringValue, textPassword.stringValue)
|
||||
|
||||
var sessionBuilder = OpenVPN.ConfigurationBuilder()
|
||||
sessionBuilder.ca = ca
|
||||
sessionBuilder.cipher = .aes128cbc
|
||||
sessionBuilder.digest = .sha1
|
||||
sessionBuilder.compressionFraming = .compLZO
|
||||
sessionBuilder.renegotiatesAfter = nil
|
||||
sessionBuilder.hostname = hostname
|
||||
// let socketType: SocketType = isTCP ? .tcp : .udp
|
||||
let socketType: SocketType = .udp
|
||||
sessionBuilder.endpointProtocols = [EndpointProtocol(socketType, port)]
|
||||
sessionBuilder.usesPIAPatches = true
|
||||
var builder = OpenVPNTunnelProvider.ConfigurationBuilder(sessionConfiguration: sessionBuilder.build())
|
||||
builder.mtu = 1350
|
||||
builder.shouldDebug = true
|
||||
builder.masksPrivateData = false
|
||||
|
||||
let configuration = builder.build()
|
||||
return try! configuration.generatedTunnelProtocol(
|
||||
withBundleIdentifier: ViewController.tunnelIdentifier,
|
||||
appGroup: ViewController.appGroup,
|
||||
credentials: credentials
|
||||
)
|
||||
}
|
||||
}
|
||||
private let tunnelIdentifier = "com.algoritmico.macos.demo.BasicTunnel.Extension"
|
||||
|
||||
class ViewController: NSViewController {
|
||||
@IBOutlet var textUsername: NSTextField!
|
||||
|
@ -126,139 +44,67 @@ class ViewController: NSViewController {
|
|||
|
||||
@IBOutlet var buttonConnection: NSButton!
|
||||
|
||||
var currentManager: NETunnelProviderManager?
|
||||
|
||||
var status = NEVPNStatus.invalid
|
||||
|
||||
private let vpn = StandardVPNProvider(bundleIdentifier: tunnelIdentifier)
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
|
||||
textServer.stringValue = "germany"
|
||||
textDomain.stringValue = "privateinternetaccess.com"
|
||||
textPort.stringValue = "1198"
|
||||
textUsername.stringValue = "myusername"
|
||||
textPassword.stringValue = "mypassword"
|
||||
textServer.stringValue = "es"
|
||||
textDomain.stringValue = "lazerpenguin.com"
|
||||
textPort.stringValue = "443"
|
||||
textUsername.stringValue = ""
|
||||
textPassword.stringValue = ""
|
||||
|
||||
NotificationCenter.default.addObserver(
|
||||
self,
|
||||
selector: #selector(VPNStatusDidChange(notification:)),
|
||||
name: .NEVPNStatusDidChange,
|
||||
name: VPN.didChangeStatus,
|
||||
object: nil
|
||||
)
|
||||
|
||||
reloadCurrentManager(nil)
|
||||
|
||||
//
|
||||
vpn.prepare(completionHandler: nil)
|
||||
|
||||
testFetchRef()
|
||||
}
|
||||
|
||||
@IBAction func connectionClicked(_ sender: Any) {
|
||||
let block = {
|
||||
switch (self.status) {
|
||||
case .invalid, .disconnected:
|
||||
self.connect()
|
||||
|
||||
case .connected, .connecting:
|
||||
self.disconnect()
|
||||
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if (status == .invalid) {
|
||||
reloadCurrentManager({ (error) in
|
||||
block()
|
||||
})
|
||||
}
|
||||
else {
|
||||
block()
|
||||
switch vpn.status {
|
||||
case .disconnected:
|
||||
connect()
|
||||
|
||||
case .connected, .connecting, .disconnecting:
|
||||
disconnect()
|
||||
}
|
||||
}
|
||||
|
||||
func connect() {
|
||||
configureVPN({ (manager) in
|
||||
return self.makeProtocol()
|
||||
}, completionHandler: { (error) in
|
||||
let server = textServer.stringValue
|
||||
let domain = textDomain.stringValue
|
||||
let hostname = ((domain == "") ? server : [server, domain].joined(separator: "."))
|
||||
let port = UInt16(textPort.stringValue)!
|
||||
|
||||
let credentials = OpenVPN.Credentials(textUsername.stringValue, textPassword.stringValue)
|
||||
let cfg = Configuration.make(hostname: hostname, port: port, socketType: .udp)
|
||||
let proto = try! cfg.generatedTunnelProtocol(
|
||||
withBundleIdentifier: tunnelIdentifier,
|
||||
appGroup: appGroup,
|
||||
credentials: credentials
|
||||
)
|
||||
let neCfg = NetworkExtensionVPNConfiguration(protocolConfiguration: proto, onDemandRules: [])
|
||||
vpn.reconnect(configuration: neCfg) { (error) in
|
||||
if let error = error {
|
||||
print("configure error: \(error)")
|
||||
return
|
||||
}
|
||||
let session = self.currentManager?.connection as! NETunnelProviderSession
|
||||
do {
|
||||
try session.startTunnel()
|
||||
} catch let e {
|
||||
print("error starting tunnel: \(e)")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func disconnect() {
|
||||
configureVPN({ (manager) in
|
||||
return nil
|
||||
}, completionHandler: { (error) in
|
||||
self.currentManager?.connection.stopVPNTunnel()
|
||||
})
|
||||
vpn.disconnect(completionHandler: nil)
|
||||
}
|
||||
|
||||
func configureVPN(_ configure: @escaping (NETunnelProviderManager) -> NETunnelProviderProtocol?, completionHandler: @escaping (Error?) -> Void) {
|
||||
reloadCurrentManager { (error) in
|
||||
if let error = error {
|
||||
print("error reloading preferences: \(error)")
|
||||
completionHandler(error)
|
||||
return
|
||||
}
|
||||
|
||||
let manager = self.currentManager!
|
||||
if let protocolConfiguration = configure(manager) {
|
||||
manager.protocolConfiguration = protocolConfiguration
|
||||
}
|
||||
manager.isEnabled = true
|
||||
|
||||
manager.saveToPreferences { (error) in
|
||||
if let error = error {
|
||||
print("error saving preferences: \(error)")
|
||||
completionHandler(error)
|
||||
return
|
||||
}
|
||||
print("saved preferences")
|
||||
self.reloadCurrentManager(completionHandler)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func reloadCurrentManager(_ completionHandler: ((Error?) -> Void)?) {
|
||||
NETunnelProviderManager.loadAllFromPreferences { (managers, error) in
|
||||
if let error = error {
|
||||
completionHandler?(error)
|
||||
return
|
||||
}
|
||||
|
||||
var manager: NETunnelProviderManager?
|
||||
|
||||
for m in managers! {
|
||||
if let p = m.protocolConfiguration as? NETunnelProviderProtocol {
|
||||
if (p.providerBundleIdentifier == ViewController.tunnelIdentifier) {
|
||||
manager = m
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (manager == nil) {
|
||||
manager = NETunnelProviderManager()
|
||||
}
|
||||
|
||||
self.currentManager = manager
|
||||
self.status = manager!.connection.status
|
||||
self.updateButton()
|
||||
completionHandler?(nil)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func updateButton() {
|
||||
switch status {
|
||||
switch vpn.status {
|
||||
case .connected, .connecting:
|
||||
buttonConnection.title = "Disconnect"
|
||||
|
||||
|
@ -267,22 +113,14 @@ class ViewController: NSViewController {
|
|||
|
||||
case .disconnecting:
|
||||
buttonConnection.title = "Disconnecting"
|
||||
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
@objc private func VPNStatusDidChange(notification: NSNotification) {
|
||||
guard let status = currentManager?.connection.status else {
|
||||
print("VPNStatusDidChange")
|
||||
return
|
||||
}
|
||||
print("VPNStatusDidChange: \(status.rawValue)")
|
||||
self.status = status
|
||||
print("VPNStatusDidChange: \(vpn.status)")
|
||||
updateButton()
|
||||
}
|
||||
|
||||
|
||||
private func testFetchRef() {
|
||||
// let keychain = Keychain(group: ViewController.APP_GROUP)
|
||||
// let username = "foo"
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
//
|
||||
// PacketTunnelProvider.swift
|
||||
// BasicTunnelExtension-iOS
|
||||
// Demo
|
||||
//
|
||||
// Created by Davide De Rosa on 9/15/17.
|
||||
// Copyright (c) 2018 Davide De Rosa. All rights reserved.
|
||||
// Copyright (c) 2020 Davide De Rosa. All rights reserved.
|
||||
//
|
||||
// https://github.com/keeshux
|
||||
//
|
||||
|
@ -22,18 +22,6 @@
|
|||
// You should have received a copy of the GNU General Public License
|
||||
// along with TunnelKit. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// This file incorporates work covered by the following copyright and
|
||||
// permission notice:
|
||||
//
|
||||
// Copyright (c) 2018-Present Private Internet Access
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
//
|
||||
|
||||
import TunnelKit
|
||||
|
||||
|
|
|
@ -30,6 +30,6 @@
|
|||
<string>$(PRODUCT_MODULE_NAME).PacketTunnelProvider</string>
|
||||
</dict>
|
||||
<key>NSHumanReadableCopyright</key>
|
||||
<string>Copyright (c) 2018 Davide De Rosa. All rights reserved.</string>
|
||||
<string>Copyright (c) 2020 Davide De Rosa. All rights reserved.</string>
|
||||
</dict>
|
||||
</plist>
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
//
|
||||
// PacketTunnelProvider.swift
|
||||
// BasicTunnelExtension-macOS
|
||||
// Demo
|
||||
//
|
||||
// Created by Davide De Rosa on 10/15/17.
|
||||
// Copyright (c) 2018 Davide De Rosa. All rights reserved.
|
||||
// Copyright (c) 2020 Davide De Rosa. All rights reserved.
|
||||
//
|
||||
// https://github.com/keeshux
|
||||
//
|
||||
|
@ -22,18 +22,6 @@
|
|||
// You should have received a copy of the GNU General Public License
|
||||
// along with TunnelKit. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// This file incorporates work covered by the following copyright and
|
||||
// permission notice:
|
||||
//
|
||||
// Copyright (c) 2018-Present Private Internet Access
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
//
|
||||
|
||||
import TunnelKit
|
||||
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
0EAC574724943B5D00D0FCE0 /* Configuration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EAC574624943B5D00D0FCE0 /* Configuration.swift */; };
|
||||
0EAC574824943B5D00D0FCE0 /* Configuration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EAC574624943B5D00D0FCE0 /* Configuration.swift */; };
|
||||
0EB39FE91F7424F80023AFFC /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EB39FE81F7424F80023AFFC /* AppDelegate.swift */; };
|
||||
0EB39FEB1F7424F80023AFFC /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EB39FEA1F7424F80023AFFC /* ViewController.swift */; };
|
||||
0EB39FEE1F7424F80023AFFC /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 0EB39FEC1F7424F80023AFFC /* Main.storyboard */; };
|
||||
|
@ -71,6 +73,7 @@
|
|||
/* End PBXCopyFilesBuildPhase section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
0EAC574624943B5D00D0FCE0 /* Configuration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Configuration.swift; sourceTree = "<group>"; };
|
||||
0EB39FE61F7424F80023AFFC /* BasicTunnel-iOS.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "BasicTunnel-iOS.app"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
0EB39FE81F7424F80023AFFC /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
||||
0EB39FEA1F7424F80023AFFC /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = "<group>"; };
|
||||
|
@ -147,6 +150,14 @@
|
|||
/* End PBXFrameworksBuildPhase section */
|
||||
|
||||
/* Begin PBXGroup section */
|
||||
0EAC574524943B3500D0FCE0 /* Shared */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
0EAC574624943B5D00D0FCE0 /* Configuration.swift */,
|
||||
);
|
||||
path = Shared;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
0EB39FC41F7424580023AFFC = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
|
@ -154,6 +165,7 @@
|
|||
0EB39FFD1F7425140023AFFC /* BasicTunnelExtension-iOS */,
|
||||
0EB6EEB81F92D417005F6221 /* BasicTunnel-macOS */,
|
||||
0EB6EECC1F92D43D005F6221 /* BasicTunnelExtension-macOS */,
|
||||
0EAC574524943B3500D0FCE0 /* Shared */,
|
||||
0EB39FCE1F7424580023AFFC /* Products */,
|
||||
B850E57E641AD1B37E79BAB5 /* Frameworks */,
|
||||
94C1D7B5B11C6CCE74B21D93 /* Pods */,
|
||||
|
@ -541,8 +553,6 @@
|
|||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputFileListPaths = (
|
||||
);
|
||||
inputPaths = (
|
||||
"${PODS_ROOT}/Target Support Files/Pods-macOS-BasicTunnel-macOS/Pods-macOS-BasicTunnel-macOS-frameworks.sh",
|
||||
"${PODS_ROOT}/OpenSSL-Apple/frameworks/MacOSX/openssl.framework",
|
||||
|
@ -550,8 +560,6 @@
|
|||
"${BUILT_PRODUCTS_DIR}/TunnelKit-macOS/TunnelKit.framework",
|
||||
);
|
||||
name = "[CP] Embed Pods Frameworks";
|
||||
outputFileListPaths = (
|
||||
);
|
||||
outputPaths = (
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/openssl.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SwiftyBeaver.framework",
|
||||
|
@ -567,8 +575,6 @@
|
|||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputFileListPaths = (
|
||||
);
|
||||
inputPaths = (
|
||||
"${PODS_ROOT}/Target Support Files/Pods-iOS-BasicTunnel-iOS/Pods-iOS-BasicTunnel-iOS-frameworks.sh",
|
||||
"${PODS_ROOT}/OpenSSL-Apple/frameworks/iPhone/openssl.framework",
|
||||
|
@ -576,8 +582,6 @@
|
|||
"${BUILT_PRODUCTS_DIR}/TunnelKit-iOS/TunnelKit.framework",
|
||||
);
|
||||
name = "[CP] Embed Pods Frameworks";
|
||||
outputFileListPaths = (
|
||||
);
|
||||
outputPaths = (
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/openssl.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SwiftyBeaver.framework",
|
||||
|
@ -639,6 +643,7 @@
|
|||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
0EAC574724943B5D00D0FCE0 /* Configuration.swift in Sources */,
|
||||
0EB39FEB1F7424F80023AFFC /* ViewController.swift in Sources */,
|
||||
0EB39FE91F7424F80023AFFC /* AppDelegate.swift in Sources */,
|
||||
);
|
||||
|
@ -656,6 +661,7 @@
|
|||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
0EAC574824943B5D00D0FCE0 /* Configuration.swift in Sources */,
|
||||
0EB6EEBC1F92D417005F6221 /* ViewController.swift in Sources */,
|
||||
0EB6EEBA1F92D417005F6221 /* AppDelegate.swift in Sources */,
|
||||
);
|
||||
|
|
|
@ -6,6 +6,7 @@ abstract_target 'iOS' do
|
|||
|
||||
target 'BasicTunnelExtension-iOS' do
|
||||
pod 'TunnelKit', :path => '..'
|
||||
pod 'TunnelKit/Manager', :path => '..'
|
||||
end
|
||||
target 'BasicTunnel-iOS' do
|
||||
end
|
||||
|
@ -16,6 +17,7 @@ abstract_target 'macOS' do
|
|||
|
||||
target 'BasicTunnelExtension-macOS' do
|
||||
pod 'TunnelKit', :path => '..'
|
||||
pod 'TunnelKit/Manager', :path => '..'
|
||||
end
|
||||
target 'BasicTunnel-macOS' do
|
||||
end
|
||||
|
|
|
@ -1,20 +1,23 @@
|
|||
PODS:
|
||||
- OpenSSL-Apple (1.1.0j.2)
|
||||
- SwiftyBeaver (1.7.0)
|
||||
- TunnelKit (2.0.0):
|
||||
- TunnelKit/Protocols/OpenVPN (= 2.0.0)
|
||||
- TunnelKit/AppExtension (2.0.0):
|
||||
- OpenSSL-Apple (1.1.1g.6)
|
||||
- SwiftyBeaver (1.9.1)
|
||||
- TunnelKit (2.3.0):
|
||||
- TunnelKit/Protocols/OpenVPN (= 2.3.0)
|
||||
- TunnelKit/AppExtension (2.3.0):
|
||||
- SwiftyBeaver
|
||||
- TunnelKit/Core
|
||||
- TunnelKit/Core (2.0.0):
|
||||
- OpenSSL-Apple (~> 1.1.0j.2)
|
||||
- TunnelKit/Core (2.3.0):
|
||||
- SwiftyBeaver
|
||||
- TunnelKit/Protocols/OpenVPN (2.0.0):
|
||||
- TunnelKit/Manager (2.3.0):
|
||||
- SwiftyBeaver
|
||||
- TunnelKit/Protocols/OpenVPN (2.3.0):
|
||||
- OpenSSL-Apple (~> 1.1.1g.6)
|
||||
- TunnelKit/AppExtension
|
||||
- TunnelKit/Core
|
||||
|
||||
DEPENDENCIES:
|
||||
- TunnelKit (from `..`)
|
||||
- TunnelKit/Manager (from `..`)
|
||||
|
||||
SPEC REPOS:
|
||||
https://github.com/cocoapods/specs.git:
|
||||
|
@ -26,10 +29,10 @@ EXTERNAL SOURCES:
|
|||
:path: ".."
|
||||
|
||||
SPEC CHECKSUMS:
|
||||
OpenSSL-Apple: e88e1eb314acb4a05e2348069790c4aa49f6d319
|
||||
SwiftyBeaver: 4cc0080d2e23f980652e28978db11a5c9da39165
|
||||
TunnelKit: 821c15bb87aafae69eb8c63e4cc46d883fff8797
|
||||
OpenSSL-Apple: c9c1b9c5b2b1fc4e1758fc5f0836b58ae7fd8183
|
||||
SwiftyBeaver: a1f5691458561414bcfab51874b2b7445451602b
|
||||
TunnelKit: a4fa4ecc6fc2b9fa74c38609c0e8fc4441d9672e
|
||||
|
||||
PODFILE CHECKSUM: f66dfaaa92a8d04ab2743f3caeab0ac9f9f25859
|
||||
PODFILE CHECKSUM: 67d7cb3c3db58264711361062345c3b7831e510e
|
||||
|
||||
COCOAPODS: 1.6.1
|
||||
COCOAPODS: 1.9.1
|
||||
|
|
|
@ -0,0 +1,188 @@
|
|||
//
|
||||
// Configuration.swift
|
||||
// Demo
|
||||
//
|
||||
// Created by Davide De Rosa on 6/13/20.
|
||||
// Copyright (c) 2020 Davide De Rosa. All rights reserved.
|
||||
//
|
||||
// https://github.com/keeshux
|
||||
//
|
||||
// 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 Foundation
|
||||
import TunnelKit
|
||||
|
||||
struct Configuration {
|
||||
static let ca = OpenVPN.CryptoContainer(pem: """
|
||||
-----BEGIN CERTIFICATE-----
|
||||
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
|
||||
-----END CERTIFICATE-----
|
||||
""")
|
||||
|
||||
static let clientCertificate = OpenVPN.CryptoContainer(pem: """
|
||||
-----BEGIN CERTIFICATE-----
|
||||
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
|
||||
-----END CERTIFICATE-----
|
||||
""")
|
||||
|
||||
static let clientKey = OpenVPN.CryptoContainer(pem: """
|
||||
-----BEGIN PRIVATE KEY-----
|
||||
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
|
||||
1LXZrtjAB4U+/F7um6YyAavpHYq9hg==
|
||||
-----END PRIVATE KEY-----
|
||||
""")
|
||||
|
||||
static func make(hostname: String, port: UInt16, socketType: SocketType) -> OpenVPNTunnelProvider.Configuration {
|
||||
var sessionBuilder = OpenVPN.ConfigurationBuilder()
|
||||
sessionBuilder.ca = ca
|
||||
sessionBuilder.cipher = .aes128cbc
|
||||
sessionBuilder.digest = .sha1
|
||||
sessionBuilder.compressionFraming = .compLZO
|
||||
sessionBuilder.renegotiatesAfter = nil
|
||||
sessionBuilder.hostname = hostname
|
||||
sessionBuilder.endpointProtocols = [EndpointProtocol(socketType, port)]
|
||||
sessionBuilder.clientCertificate = clientCertificate
|
||||
sessionBuilder.clientKey = clientKey
|
||||
var builder = OpenVPNTunnelProvider.ConfigurationBuilder(sessionConfiguration: sessionBuilder.build())
|
||||
builder.mtu = 1350
|
||||
builder.shouldDebug = true
|
||||
builder.masksPrivateData = false
|
||||
return builder.build()
|
||||
}
|
||||
}
|
|
@ -153,6 +153,15 @@ There are no physical network implementations (e.g. UDP or TCP) in this module.
|
|||
|
||||
Provides a layer on top of the NetworkExtension framework. Most importantly, bridges native [NWUDPSession][ne-udp] and [NWTCPConnection][ne-tcp] to an abstract `GenericSocket` interface, thus making a multi-protocol VPN dramatically easier to manage.
|
||||
|
||||
### Manager
|
||||
|
||||
This subspec includes convenient classes to control the VPN tunnel from your app without the NetworkExtension headaches. Have a look at `VPNProvider` implementations:
|
||||
|
||||
- `MockVPNProvider` (default, useful to test on simulator)
|
||||
- `StandardVPNProvider`
|
||||
|
||||
Set `VPN.shared` to either of them at app launch time.
|
||||
|
||||
### Protocols/OpenVPN
|
||||
|
||||
Here you will find the low-level entities on top of which an OpenVPN connection is established. Code is mixed Swift and Obj-C, most of it is not exposed to consumers. The module depends on OpenSSL.
|
||||
|
|
|
@ -33,6 +33,13 @@ Pod::Spec.new do |s|
|
|||
p.dependency "TunnelKit/Core"
|
||||
end
|
||||
|
||||
s.subspec "Manager" do |p|
|
||||
p.source_files = "TunnelKit/Sources/Manager/**/*.swift"
|
||||
p.frameworks = "NetworkExtension"
|
||||
|
||||
p.dependency "SwiftyBeaver"
|
||||
end
|
||||
|
||||
s.subspec "Protocols" do |t|
|
||||
t.subspec "OpenVPN" do |p|
|
||||
p.source_files = "TunnelKit/Sources/Protocols/OpenVPN/**/*.{h,m,swift}"
|
||||
|
|
|
@ -168,6 +168,18 @@
|
|||
0E7F3F6B246ABA0F006BE77F /* IPHeader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E7F3F69246ABA0F006BE77F /* IPHeader.swift */; };
|
||||
0EA82A282190B220007960EB /* TunnelKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0E3251C51F95770D00C108D9 /* TunnelKit.framework */; };
|
||||
0EA82A3E2190B2BC007960EB /* pia-2048.pem in Resources */ = {isa = PBXBuildFile; fileRef = 0E749F612178911C00BB2701 /* pia-2048.pem */; };
|
||||
0EAC57372494277A00D0FCE0 /* StandardVPNProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EAC57312494277A00D0FCE0 /* StandardVPNProvider.swift */; };
|
||||
0EAC57382494277A00D0FCE0 /* StandardVPNProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EAC57312494277A00D0FCE0 /* StandardVPNProvider.swift */; };
|
||||
0EAC57392494277A00D0FCE0 /* MockVPNProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EAC57322494277A00D0FCE0 /* MockVPNProvider.swift */; };
|
||||
0EAC573A2494277A00D0FCE0 /* MockVPNProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EAC57322494277A00D0FCE0 /* MockVPNProvider.swift */; };
|
||||
0EAC573B2494277A00D0FCE0 /* VPNStatus.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EAC57332494277A00D0FCE0 /* VPNStatus.swift */; };
|
||||
0EAC573C2494277A00D0FCE0 /* VPNStatus.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EAC57332494277A00D0FCE0 /* VPNStatus.swift */; };
|
||||
0EAC573D2494277A00D0FCE0 /* VPNConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EAC57342494277A00D0FCE0 /* VPNConfiguration.swift */; };
|
||||
0EAC573E2494277A00D0FCE0 /* VPNConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EAC57342494277A00D0FCE0 /* VPNConfiguration.swift */; };
|
||||
0EAC573F2494277A00D0FCE0 /* VPNProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EAC57352494277A00D0FCE0 /* VPNProvider.swift */; };
|
||||
0EAC57402494277A00D0FCE0 /* VPNProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EAC57352494277A00D0FCE0 /* VPNProvider.swift */; };
|
||||
0EAC57412494277A00D0FCE0 /* VPN.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EAC57362494277A00D0FCE0 /* VPN.swift */; };
|
||||
0EAC57422494277A00D0FCE0 /* VPN.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EAC57362494277A00D0FCE0 /* VPN.swift */; };
|
||||
0ECAF84A246697DA00D8266A /* TunnelKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0E17D7F91F730D9F009EE129 /* TunnelKit.framework */; };
|
||||
0ECAF84B246697DA00D8266A /* TunnelKit.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 0E17D7F91F730D9F009EE129 /* TunnelKit.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
||||
0ECC60D82254981A0020BEAC /* ConfigurationError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0ECC60D72254981A0020BEAC /* ConfigurationError.swift */; };
|
||||
|
@ -424,6 +436,12 @@
|
|||
0E85A25B202CCA3D0059E9F9 /* TunnelKitHost.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = TunnelKitHost.entitlements; sourceTree = "<group>"; };
|
||||
0EA82A232190B220007960EB /* TunnelKitTests-macOS.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "TunnelKitTests-macOS.xctest"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
0EA82A272190B220007960EB /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
0EAC57312494277A00D0FCE0 /* StandardVPNProvider.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StandardVPNProvider.swift; sourceTree = "<group>"; };
|
||||
0EAC57322494277A00D0FCE0 /* MockVPNProvider.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MockVPNProvider.swift; sourceTree = "<group>"; };
|
||||
0EAC57332494277A00D0FCE0 /* VPNStatus.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VPNStatus.swift; sourceTree = "<group>"; };
|
||||
0EAC57342494277A00D0FCE0 /* VPNConfiguration.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VPNConfiguration.swift; sourceTree = "<group>"; };
|
||||
0EAC57352494277A00D0FCE0 /* VPNProvider.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VPNProvider.swift; sourceTree = "<group>"; };
|
||||
0EAC57362494277A00D0FCE0 /* VPN.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VPN.swift; sourceTree = "<group>"; };
|
||||
0EB03E0E2290CF52006D03A0 /* module.modulemap */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = "sourcecode.module-map"; path = module.modulemap; sourceTree = "<group>"; };
|
||||
0ECC60D72254981A0020BEAC /* ConfigurationError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConfigurationError.swift; sourceTree = "<group>"; };
|
||||
0ECEB1132252C8E900E9E551 /* tunnelbear.enc.8.ovpn */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = tunnelbear.enc.8.ovpn; sourceTree = "<group>"; };
|
||||
|
@ -618,6 +636,7 @@
|
|||
0EE2F9DD22918DA100F56F49 /* AppExtension */,
|
||||
0EFEB4292006D3C800F81029 /* Core */,
|
||||
0E23B41922982AF800304C30 /* Extra */,
|
||||
0EAC57302494277A00D0FCE0 /* Manager */,
|
||||
0E23B3E022982AF800304C30 /* Protocols */,
|
||||
);
|
||||
path = Sources;
|
||||
|
@ -800,6 +819,19 @@
|
|||
path = "TunnelKitTests-iOS";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
0EAC57302494277A00D0FCE0 /* Manager */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
0EAC57322494277A00D0FCE0 /* MockVPNProvider.swift */,
|
||||
0EAC57312494277A00D0FCE0 /* StandardVPNProvider.swift */,
|
||||
0EAC57362494277A00D0FCE0 /* VPN.swift */,
|
||||
0EAC57342494277A00D0FCE0 /* VPNConfiguration.swift */,
|
||||
0EAC57352494277A00D0FCE0 /* VPNProvider.swift */,
|
||||
0EAC57332494277A00D0FCE0 /* VPNStatus.swift */,
|
||||
);
|
||||
path = Manager;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
0EE2F9DD22918DA100F56F49 /* AppExtension */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
|
@ -1410,12 +1442,14 @@
|
|||
files = (
|
||||
0EE2F974229163C900F56F49 /* Proxy.swift in Sources */,
|
||||
0EFEB4732006D3C800F81029 /* LinkInterface.swift in Sources */,
|
||||
0EAC573B2494277A00D0FCE0 /* VPNStatus.swift in Sources */,
|
||||
0E23B48922982AF800304C30 /* PacketStream.m in Sources */,
|
||||
0E23B3DE229749C600304C30 /* LinkProducer.swift in Sources */,
|
||||
0E23B42722982AF800304C30 /* CryptoAEAD.m in Sources */,
|
||||
0EE2F9F222918DA100F56F49 /* NETunnelInterface.swift in Sources */,
|
||||
0E23B46722982AF800304C30 /* Authenticator.swift in Sources */,
|
||||
0E23B43922982AF800304C30 /* OpenVPNError.swift in Sources */,
|
||||
0EAC573F2494277A00D0FCE0 /* VPNProvider.swift in Sources */,
|
||||
0E23B44F22982AF800304C30 /* OpenVPNTunnelProvider+Interaction.swift in Sources */,
|
||||
0E23B46D22982AF800304C30 /* StaticKey.swift in Sources */,
|
||||
0E23B49F22982AF800304C30 /* minilzo.c in Sources */,
|
||||
|
@ -1432,6 +1466,7 @@
|
|||
0E12B29E21449ADB00B4BAE9 /* NSRegularExpression+Shortcuts.swift in Sources */,
|
||||
0EE2F9F822918DA100F56F49 /* NWUDPSessionState+Description.swift in Sources */,
|
||||
0EE2F9AC2291853D00F56F49 /* Session.swift in Sources */,
|
||||
0EAC57412494277A00D0FCE0 /* VPN.swift in Sources */,
|
||||
0E23B48122982AF800304C30 /* ControlPacket.m in Sources */,
|
||||
0EFEB4622006D3C800F81029 /* SecureRandom.swift in Sources */,
|
||||
0E011F7D2196D97200BA59EE /* EndpointProtocol.swift in Sources */,
|
||||
|
@ -1479,9 +1514,12 @@
|
|||
0E23B45722982AF800304C30 /* NETCPLink.swift in Sources */,
|
||||
0E23B45322982AF800304C30 /* ConnectionStrategy.swift in Sources */,
|
||||
0E011F7A2196D93600BA59EE /* SocketType.swift in Sources */,
|
||||
0EAC57392494277A00D0FCE0 /* MockVPNProvider.swift in Sources */,
|
||||
0E23B45922982AF800304C30 /* OpenVPNTunnelProvider.swift in Sources */,
|
||||
0EFEB45A2006D3C800F81029 /* TunnelInterface.swift in Sources */,
|
||||
0EAC57372494277A00D0FCE0 /* StandardVPNProvider.swift in Sources */,
|
||||
0E23B47322982AF800304C30 /* MSS.m in Sources */,
|
||||
0EAC573D2494277A00D0FCE0 /* VPNConfiguration.swift in Sources */,
|
||||
0E23B45D22982AF800304C30 /* ProtocolMacros.swift in Sources */,
|
||||
0EE2FA0022918DA100F56F49 /* MemoryDestination.swift in Sources */,
|
||||
);
|
||||
|
@ -1493,12 +1531,14 @@
|
|||
files = (
|
||||
0EE2F975229163C900F56F49 /* Proxy.swift in Sources */,
|
||||
0EFEB4A12006D7F300F81029 /* LinkInterface.swift in Sources */,
|
||||
0EAC573C2494277A00D0FCE0 /* VPNStatus.swift in Sources */,
|
||||
0E23B48A22982AF800304C30 /* PacketStream.m in Sources */,
|
||||
0E23B3DF229749C600304C30 /* LinkProducer.swift in Sources */,
|
||||
0E23B42822982AF800304C30 /* CryptoAEAD.m in Sources */,
|
||||
0EE2F9F322918DA100F56F49 /* NETunnelInterface.swift in Sources */,
|
||||
0E23B46822982AF800304C30 /* Authenticator.swift in Sources */,
|
||||
0E23B43A22982AF800304C30 /* OpenVPNError.swift in Sources */,
|
||||
0EAC57402494277A00D0FCE0 /* VPNProvider.swift in Sources */,
|
||||
0E23B45022982AF800304C30 /* OpenVPNTunnelProvider+Interaction.swift in Sources */,
|
||||
0E23B46E22982AF800304C30 /* StaticKey.swift in Sources */,
|
||||
0E23B4A022982AF800304C30 /* minilzo.c in Sources */,
|
||||
|
@ -1515,6 +1555,7 @@
|
|||
0E12B29F21449ADB00B4BAE9 /* NSRegularExpression+Shortcuts.swift in Sources */,
|
||||
0EE2F9F922918DA100F56F49 /* NWUDPSessionState+Description.swift in Sources */,
|
||||
0EE2F9AD2291853D00F56F49 /* Session.swift in Sources */,
|
||||
0EAC57422494277A00D0FCE0 /* VPN.swift in Sources */,
|
||||
0E23B48222982AF800304C30 /* ControlPacket.m in Sources */,
|
||||
0E011F7E2196D97200BA59EE /* EndpointProtocol.swift in Sources */,
|
||||
0EE2F9F122918DA100F56F49 /* NETCPSocket.swift in Sources */,
|
||||
|
@ -1562,9 +1603,12 @@
|
|||
0E23B45822982AF800304C30 /* NETCPLink.swift in Sources */,
|
||||
0E23B45422982AF800304C30 /* ConnectionStrategy.swift in Sources */,
|
||||
0EFEB49D2006D7F300F81029 /* IOInterface.swift in Sources */,
|
||||
0EAC573A2494277A00D0FCE0 /* MockVPNProvider.swift in Sources */,
|
||||
0E23B45A22982AF800304C30 /* OpenVPNTunnelProvider.swift in Sources */,
|
||||
0E011F7B2196D93600BA59EE /* SocketType.swift in Sources */,
|
||||
0EAC57382494277A00D0FCE0 /* StandardVPNProvider.swift in Sources */,
|
||||
0E23B47422982AF800304C30 /* MSS.m in Sources */,
|
||||
0EAC573E2494277A00D0FCE0 /* VPNConfiguration.swift in Sources */,
|
||||
0E23B45E22982AF800304C30 /* ProtocolMacros.swift in Sources */,
|
||||
0EE2FA0122918DA100F56F49 /* MemoryDestination.swift in Sources */,
|
||||
);
|
||||
|
|
|
@ -44,7 +44,7 @@ private let log = SwiftyBeaver.self
|
|||
public class InterfaceObserver: NSObject {
|
||||
|
||||
/// A change in Wi-Fi state occurred.
|
||||
public static let didDetectWifiChange = NSNotification.Name("InterfaceObserverDidDetectWifiChange")
|
||||
public static let didDetectWifiChange = Notification.Name("InterfaceObserverDidDetectWifiChange")
|
||||
|
||||
private var queue: DispatchQueue?
|
||||
|
||||
|
|
|
@ -0,0 +1,86 @@
|
|||
//
|
||||
// MockVPNProvider.swift
|
||||
// TunnelKit
|
||||
//
|
||||
// Created by Davide De Rosa on 6/15/18.
|
||||
// Copyright (c) 2020 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 Foundation
|
||||
|
||||
/// :nodoc:
|
||||
public class MockVPNProvider: VPNProvider {
|
||||
public let isPrepared: Bool = true
|
||||
|
||||
public private(set) var isEnabled: Bool = false
|
||||
|
||||
public private(set) var status: VPNStatus = .disconnected
|
||||
|
||||
public func prepare(completionHandler: (() -> Void)?) {
|
||||
NotificationCenter.default.post(name: VPN.didPrepare, object: nil)
|
||||
completionHandler?()
|
||||
}
|
||||
|
||||
public func install(configuration: VPNConfiguration, completionHandler: ((Error?) -> Void)?) {
|
||||
isEnabled = true
|
||||
completionHandler?(nil)
|
||||
}
|
||||
|
||||
public func connect(completionHandler: ((Error?) -> Void)?) {
|
||||
isEnabled = true
|
||||
status = .connected
|
||||
NotificationCenter.default.post(name: VPN.didChangeStatus, object: self)
|
||||
completionHandler?(nil)
|
||||
}
|
||||
|
||||
public func disconnect(completionHandler: ((Error?) -> Void)?) {
|
||||
isEnabled = false
|
||||
status = .disconnected
|
||||
NotificationCenter.default.post(name: VPN.didChangeStatus, object: self)
|
||||
completionHandler?(nil)
|
||||
}
|
||||
|
||||
public func reconnect(configuration: VPNConfiguration, completionHandler: ((Error?) -> Void)?) {
|
||||
isEnabled = true
|
||||
status = .connected
|
||||
NotificationCenter.default.post(name: VPN.didChangeStatus, object: self)
|
||||
completionHandler?(nil)
|
||||
}
|
||||
|
||||
public func uninstall(completionHandler: (() -> Void)?) {
|
||||
isEnabled = false
|
||||
status = .disconnected
|
||||
NotificationCenter.default.post(name: VPN.didChangeStatus, object: self)
|
||||
completionHandler?()
|
||||
}
|
||||
|
||||
public func requestDebugLog(fallback: (() -> String)?, completionHandler: @escaping (String) -> Void) {
|
||||
let log = [String](repeating: "lorem ipsum", count: 1000).joined(separator: " ")
|
||||
completionHandler(log)
|
||||
}
|
||||
|
||||
public func requestBytesCount(completionHandler: @escaping ((UInt, UInt)?) -> Void) {
|
||||
completionHandler((0, 0))
|
||||
}
|
||||
|
||||
public func requestServerConfiguration(completionHandler: @escaping (Any?) -> Void) {
|
||||
completionHandler(nil)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,317 @@
|
|||
//
|
||||
// StandardVPNProvider.swift
|
||||
// TunnelKit
|
||||
//
|
||||
// Created by Davide De Rosa on 6/15/18.
|
||||
// Copyright (c) 2020 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 Foundation
|
||||
import NetworkExtension
|
||||
|
||||
/// :nodoc:
|
||||
public class StandardVPNProvider: VPNProvider {
|
||||
private let bundleIdentifier: String
|
||||
|
||||
private var manager: NETunnelProviderManager?
|
||||
|
||||
private var lastNotifiedStatus: VPNStatus?
|
||||
|
||||
public init(bundleIdentifier: String) {
|
||||
self.bundleIdentifier = bundleIdentifier
|
||||
|
||||
let nc = NotificationCenter.default
|
||||
nc.addObserver(self, selector: #selector(vpnDidUpdate(_:)), name: .NEVPNStatusDidChange, object: nil)
|
||||
nc.addObserver(self, selector: #selector(vpnDidReinstall(_:)), name: .NEVPNConfigurationChange, object: nil)
|
||||
}
|
||||
|
||||
deinit {
|
||||
NotificationCenter.default.removeObserver(self)
|
||||
}
|
||||
|
||||
// MARK: VPNProvider
|
||||
|
||||
public var isPrepared: Bool {
|
||||
return manager != nil
|
||||
}
|
||||
|
||||
public var isEnabled: Bool {
|
||||
guard let manager = manager else {
|
||||
return false
|
||||
}
|
||||
return manager.isEnabled && manager.isOnDemandEnabled
|
||||
}
|
||||
|
||||
public var status: VPNStatus {
|
||||
guard let neStatus = manager?.connection.status else {
|
||||
return .disconnected
|
||||
}
|
||||
switch neStatus {
|
||||
case .connected:
|
||||
return .connected
|
||||
|
||||
case .connecting, .reasserting:
|
||||
return .connecting
|
||||
|
||||
case .disconnecting:
|
||||
return .disconnecting
|
||||
|
||||
case .disconnected, .invalid:
|
||||
return .disconnected
|
||||
|
||||
@unknown default:
|
||||
return .disconnected
|
||||
}
|
||||
}
|
||||
|
||||
public func prepare(completionHandler: (() -> Void)?) {
|
||||
find(with: bundleIdentifier) {
|
||||
self.manager = $0
|
||||
NotificationCenter.default.post(name: VPN.didPrepare, object: nil)
|
||||
completionHandler?()
|
||||
}
|
||||
}
|
||||
|
||||
public func install(configuration: VPNConfiguration, completionHandler: ((Error?) -> Void)?) {
|
||||
guard let configuration = configuration as? NetworkExtensionVPNConfiguration else {
|
||||
fatalError("Not a NetworkExtensionVPNConfiguration")
|
||||
}
|
||||
find(with: bundleIdentifier) {
|
||||
guard let manager = $0 else {
|
||||
completionHandler?(nil)
|
||||
return
|
||||
}
|
||||
self.manager = manager
|
||||
manager.protocolConfiguration = configuration.protocolConfiguration
|
||||
manager.onDemandRules = configuration.onDemandRules
|
||||
manager.isOnDemandEnabled = true
|
||||
manager.isEnabled = true
|
||||
manager.saveToPreferences { (error) in
|
||||
guard error == nil else {
|
||||
manager.isOnDemandEnabled = false
|
||||
manager.isEnabled = false
|
||||
completionHandler?(error)
|
||||
return
|
||||
}
|
||||
manager.loadFromPreferences { (error) in
|
||||
completionHandler?(error)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public func connect(completionHandler: ((Error?) -> Void)?) {
|
||||
do {
|
||||
try manager?.connection.startVPNTunnel()
|
||||
completionHandler?(nil)
|
||||
} catch let e {
|
||||
completionHandler?(e)
|
||||
}
|
||||
}
|
||||
|
||||
public func disconnect(completionHandler: ((Error?) -> Void)?) {
|
||||
guard let manager = manager else {
|
||||
completionHandler?(nil)
|
||||
return
|
||||
}
|
||||
manager.connection.stopVPNTunnel()
|
||||
manager.isOnDemandEnabled = false
|
||||
manager.isEnabled = false
|
||||
manager.saveToPreferences(completionHandler: completionHandler)
|
||||
}
|
||||
|
||||
public func reconnect(configuration: VPNConfiguration, completionHandler: ((Error?) -> Void)?) {
|
||||
guard let configuration = configuration as? NetworkExtensionVPNConfiguration else {
|
||||
fatalError("Not a NetworkExtensionVPNConfiguration")
|
||||
}
|
||||
install(configuration: configuration) { (error) in
|
||||
guard error == nil else {
|
||||
completionHandler?(nil)
|
||||
return
|
||||
}
|
||||
let connectBlock = {
|
||||
self.connect(completionHandler: completionHandler)
|
||||
}
|
||||
if self.status != .disconnected {
|
||||
self.manager?.connection.stopVPNTunnel()
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 2.0, execute: connectBlock)
|
||||
} else {
|
||||
connectBlock()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public func uninstall(completionHandler: (() -> Void)?) {
|
||||
find(with: bundleIdentifier) { (manager) in
|
||||
guard let manager = manager else {
|
||||
completionHandler?()
|
||||
return
|
||||
}
|
||||
manager.connection.stopVPNTunnel()
|
||||
manager.removeFromPreferences { (error) in
|
||||
self.manager = nil
|
||||
completionHandler?()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public func requestDebugLog(fallback: (() -> String)?, completionHandler: @escaping (String) -> Void) {
|
||||
guard status != .disconnected else {
|
||||
completionHandler(fallback?() ?? "")
|
||||
return
|
||||
}
|
||||
findAndRequestDebugLog { (recent) in
|
||||
DispatchQueue.main.async {
|
||||
guard let recent = recent else {
|
||||
completionHandler(fallback?() ?? "")
|
||||
return
|
||||
}
|
||||
completionHandler(recent)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public func requestBytesCount(completionHandler: @escaping ((UInt, UInt)?) -> Void) {
|
||||
find(with: bundleIdentifier) {
|
||||
self.manager = $0
|
||||
guard let session = self.manager?.connection as? NETunnelProviderSession else {
|
||||
DispatchQueue.main.async {
|
||||
completionHandler(nil)
|
||||
}
|
||||
return
|
||||
}
|
||||
do {
|
||||
try session.sendProviderMessage(OpenVPNTunnelProvider.Message.dataCount.data) { (data) in
|
||||
guard let data = data, data.count == 16 else {
|
||||
DispatchQueue.main.async {
|
||||
completionHandler(nil)
|
||||
}
|
||||
return
|
||||
}
|
||||
let bytesIn: UInt = data.subdata(in: 0..<8).withUnsafeBytes { $0.load(as: UInt.self) }
|
||||
let bytesOut: UInt = data.subdata(in: 8..<16).withUnsafeBytes { $0.load(as: UInt.self) }
|
||||
DispatchQueue.main.async {
|
||||
completionHandler((bytesIn, bytesOut))
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
DispatchQueue.main.async {
|
||||
completionHandler(nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public func requestServerConfiguration(completionHandler: @escaping (Any?) -> Void) {
|
||||
find(with: bundleIdentifier) {
|
||||
self.manager = $0
|
||||
guard let session = self.manager?.connection as? NETunnelProviderSession else {
|
||||
DispatchQueue.main.async {
|
||||
completionHandler(nil)
|
||||
}
|
||||
return
|
||||
}
|
||||
do {
|
||||
try session.sendProviderMessage(OpenVPNTunnelProvider.Message.serverConfiguration.data) { (data) in
|
||||
guard let data = data, let cfg = try? JSONDecoder().decode(OpenVPN.Configuration.self, from: data) else {
|
||||
DispatchQueue.main.async {
|
||||
completionHandler(nil)
|
||||
}
|
||||
return
|
||||
}
|
||||
DispatchQueue.main.async {
|
||||
completionHandler(cfg)
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
DispatchQueue.main.async {
|
||||
completionHandler(nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: Helpers
|
||||
|
||||
private func find(with bundleIdentifier: String, completionHandler: @escaping (NETunnelProviderManager?) -> Void) {
|
||||
NETunnelProviderManager.loadAllFromPreferences { (managers, error) in
|
||||
guard error == nil else {
|
||||
completionHandler(nil)
|
||||
return
|
||||
}
|
||||
let manager = managers?.first {
|
||||
guard let ptm = $0.protocolConfiguration as? NETunnelProviderProtocol else {
|
||||
return false
|
||||
}
|
||||
return (ptm.providerBundleIdentifier == bundleIdentifier)
|
||||
}
|
||||
completionHandler(manager ?? NETunnelProviderManager())
|
||||
}
|
||||
}
|
||||
|
||||
private func findAndRequestDebugLog(completionHandler: @escaping (String?) -> Void) {
|
||||
find(with: bundleIdentifier) {
|
||||
self.manager = $0
|
||||
guard let session = self.manager?.connection as? NETunnelProviderSession else {
|
||||
completionHandler(nil)
|
||||
return
|
||||
}
|
||||
StandardVPNProvider.requestDebugLog(session: session, completionHandler: completionHandler)
|
||||
}
|
||||
}
|
||||
|
||||
private static func requestDebugLog(session: NETunnelProviderSession, completionHandler: @escaping (String?) -> Void) {
|
||||
do {
|
||||
try session.sendProviderMessage(OpenVPNTunnelProvider.Message.requestLog.data) { (data) in
|
||||
guard let data = data, !data.isEmpty else {
|
||||
completionHandler(nil)
|
||||
return
|
||||
}
|
||||
let newestLog = String(data: data, encoding: .utf8)
|
||||
completionHandler(newestLog)
|
||||
}
|
||||
} catch {
|
||||
completionHandler(nil)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: Notifications
|
||||
|
||||
@objc private func vpnDidUpdate(_ notification: Notification) {
|
||||
// guard let connection = notification.object as? NETunnelProviderSession else {
|
||||
// return
|
||||
// }
|
||||
// log.debug("VPN status did change: \(connection.status.rawValue)")
|
||||
|
||||
let status = self.status
|
||||
if let last = lastNotifiedStatus {
|
||||
guard status != last else {
|
||||
return
|
||||
}
|
||||
}
|
||||
lastNotifiedStatus = status
|
||||
|
||||
NotificationCenter.default.post(name: VPN.didChangeStatus, object: self)
|
||||
}
|
||||
|
||||
@objc private func vpnDidReinstall(_ notification: Notification) {
|
||||
NotificationCenter.default.post(name: VPN.didReinstall, object: self)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
//
|
||||
// VPN.swift
|
||||
// TunnelKit
|
||||
//
|
||||
// Created by Davide De Rosa on 6/12/18.
|
||||
// Copyright (c) 2020 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 Foundation
|
||||
|
||||
/// Wrapper for shared access to VPN-related objects.
|
||||
public class VPN {
|
||||
|
||||
/// The VPN became ready to use.
|
||||
public static let didPrepare = Notification.Name("VPNDidPrepare")
|
||||
|
||||
/// The VPN did change status.
|
||||
public static let didChangeStatus = Notification.Name("VPNDidChangeStatus")
|
||||
|
||||
/// The VPN profile did (re)install.
|
||||
public static let didReinstall = Notification.Name("VPNDidReinstall")
|
||||
|
||||
/// A singleton `VPNProvider` instance (default is a `MockVPNProvider`). Make sure to set this on app launch.
|
||||
public static var shared: VPNProvider = MockVPNProvider()
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
//
|
||||
// VPNConfiguration.swift
|
||||
// TunnelKit
|
||||
//
|
||||
// Created by Davide De Rosa on 9/18/18.
|
||||
// Copyright (c) 2020 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 Foundation
|
||||
import NetworkExtension
|
||||
|
||||
/// Generic marker for objects able to configure a `VPNProvider`.
|
||||
public protocol VPNConfiguration {
|
||||
}
|
||||
|
||||
/// A `VPNConfiguration` built on top of NetworkExtension entities.
|
||||
public struct NetworkExtensionVPNConfiguration: VPNConfiguration {
|
||||
|
||||
/// The `NETunnelProviderProtocol` object embedding tunnel configuration.
|
||||
public let protocolConfiguration: NETunnelProviderProtocol
|
||||
|
||||
/// The on-demand rules to establish.
|
||||
public let onDemandRules: [NEOnDemandRule]
|
||||
|
||||
/// :nodoc:
|
||||
public init(protocolConfiguration: NETunnelProviderProtocol, onDemandRules: [NEOnDemandRule]) {
|
||||
self.protocolConfiguration = protocolConfiguration
|
||||
self.onDemandRules = onDemandRules
|
||||
}
|
||||
}
|
|
@ -0,0 +1,107 @@
|
|||
//
|
||||
// VPNProvider.swift
|
||||
// TunnelKit
|
||||
//
|
||||
// Created by Davide De Rosa on 9/6/18.
|
||||
// Copyright (c) 2020 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 Foundation
|
||||
|
||||
/// Helps controlling a VPN without messing with underlying implementations.
|
||||
public protocol VPNProvider: class {
|
||||
|
||||
/// `true` if the VPN is ready for use.
|
||||
var isPrepared: Bool { get }
|
||||
|
||||
/// `true` if the associated VPN profile is enabled.
|
||||
var isEnabled: Bool { get }
|
||||
|
||||
/// The status of the VPN.
|
||||
var status: VPNStatus { get }
|
||||
|
||||
/**
|
||||
Prepares the VPN for use.
|
||||
|
||||
- Postcondition: The VPN is ready to use and `isPrepared` becomes `true`.
|
||||
- Parameter completionHandler: The completion handler.
|
||||
- Seealso: `isPrepared`
|
||||
*/
|
||||
func prepare(completionHandler: (() -> Void)?)
|
||||
|
||||
/**
|
||||
Installs the VPN profile.
|
||||
|
||||
- Parameter configuration: The `VPNConfiguration` to install.
|
||||
- Parameter completionHandler: The completion handler with an optional error.
|
||||
*/
|
||||
func install(configuration: VPNConfiguration, completionHandler: ((Error?) -> Void)?)
|
||||
|
||||
/**
|
||||
Connects to the VPN.
|
||||
|
||||
- Parameter completionHandler: The completion handler with an optional error.
|
||||
*/
|
||||
func connect(completionHandler: ((Error?) -> Void)?)
|
||||
|
||||
/**
|
||||
Disconnects from the VPN.
|
||||
|
||||
- Parameter completionHandler: The completion handler with an optional error.
|
||||
*/
|
||||
func disconnect(completionHandler: ((Error?) -> Void)?)
|
||||
|
||||
/**
|
||||
Reconnects to the VPN.
|
||||
|
||||
- Parameter configuration: The `VPNConfiguration` to install.
|
||||
- Parameter completionHandler: The completion handler with an optional error.
|
||||
*/
|
||||
func reconnect(configuration: VPNConfiguration, completionHandler: ((Error?) -> Void)?)
|
||||
|
||||
/**
|
||||
Uninstalls the VPN profile.
|
||||
|
||||
- Parameter completionHandler: The completion handler.
|
||||
*/
|
||||
func uninstall(completionHandler: (() -> Void)?)
|
||||
|
||||
/**
|
||||
Request a debug log from the VPN.
|
||||
|
||||
- Parameter fallback: The block resolving to a fallback `String` if no debug log is available.
|
||||
- Parameter completionHandler: The completion handler with the debug log.
|
||||
*/
|
||||
func requestDebugLog(fallback: (() -> String)?, completionHandler: @escaping (String) -> Void)
|
||||
|
||||
/**
|
||||
Requests the current received/sent bytes count from the VPN.
|
||||
|
||||
- Parameter completionHandler: The completion handler with an optional received/sent bytes count.
|
||||
*/
|
||||
func requestBytesCount(completionHandler: @escaping ((UInt, UInt)?) -> Void)
|
||||
|
||||
/**
|
||||
Requests the server configuration from the VPN.
|
||||
|
||||
- Parameter completionHandler: The completion handler with an optional configuration object.
|
||||
*/
|
||||
func requestServerConfiguration(completionHandler: @escaping (Any?) -> Void)
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
//
|
||||
// VPNStatus.swift
|
||||
// TunnelKit
|
||||
//
|
||||
// Created by Davide De Rosa on 9/18/18.
|
||||
// Copyright (c) 2020 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 Foundation
|
||||
|
||||
/// Status of a `VPNProvider`.
|
||||
public enum VPNStatus: String {
|
||||
|
||||
/// VPN is connected.
|
||||
case connected
|
||||
|
||||
/// VPN is attempting a connection.
|
||||
case connecting
|
||||
|
||||
/// VPN is disconnected.
|
||||
case disconnected
|
||||
|
||||
/// VPN is completing a disconnection.
|
||||
case disconnecting
|
||||
}
|
Loading…
Reference in New Issue