Merge branch 'manager-subspec'
This commit is contained in:
commit
5ab86d22bc
10
.jazzy.yaml
10
.jazzy.yaml
|
@ -43,6 +43,16 @@ custom_categories:
|
||||||
- NETunnelInterface
|
- NETunnelInterface
|
||||||
- NEUDPSocket
|
- NEUDPSocket
|
||||||
- NSNotification
|
- NSNotification
|
||||||
|
- name: Manager
|
||||||
|
children:
|
||||||
|
- VPN
|
||||||
|
- VPNProvider
|
||||||
|
- MockVPNProvider
|
||||||
|
- StandardVPNProvider
|
||||||
|
- VPNConfiguration
|
||||||
|
- NetworkExtensionVPNConfiguration
|
||||||
|
- VPNStatus
|
||||||
|
- NSNotification
|
||||||
- name: Protocols/OpenVPN
|
- name: Protocols/OpenVPN
|
||||||
children:
|
children:
|
||||||
- OpenVPN
|
- OpenVPN
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
//
|
//
|
||||||
// AppDelegate.swift
|
// AppDelegate.swift
|
||||||
// BasicTunnel-iOS
|
// Demo
|
||||||
//
|
//
|
||||||
// Created by Davide De Rosa on 2/11/17.
|
// 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
|
// https://github.com/keeshux
|
||||||
//
|
//
|
||||||
|
@ -22,18 +22,6 @@
|
||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with TunnelKit. If not, see <http://www.gnu.org/licenses/>.
|
// 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 UIKit
|
||||||
import NetworkExtension
|
import NetworkExtension
|
||||||
|
|
|
@ -1,11 +1,9 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?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">
|
<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">
|
<device id="retina4_7" orientation="portrait" appearance="light"/>
|
||||||
<adaptation id="fullscreen"/>
|
|
||||||
</device>
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<deployment identifier="iOS"/>
|
<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"/>
|
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
<scenes>
|
<scenes>
|
||||||
|
@ -22,40 +20,35 @@
|
||||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||||
<subviews>
|
<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">
|
<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"/>
|
<rect key="frame" x="20" y="182" width="335" height="34"/>
|
||||||
<nil key="textColor"/>
|
|
||||||
<fontDescription key="fontDescription" type="system" pointSize="14"/>
|
<fontDescription key="fontDescription" type="system" pointSize="14"/>
|
||||||
<textInputTraits key="textInputTraits" autocorrectionType="no" spellCheckingType="no" keyboardType="alphabet" secureTextEntry="YES"/>
|
<textInputTraits key="textInputTraits" autocorrectionType="no" spellCheckingType="no" keyboardType="alphabet" secureTextEntry="YES"/>
|
||||||
</textField>
|
</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">
|
<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"/>
|
<rect key="frame" x="20" y="20" width="335" height="34"/>
|
||||||
<nil key="textColor"/>
|
|
||||||
<fontDescription key="fontDescription" type="system" pointSize="14"/>
|
<fontDescription key="fontDescription" type="system" pointSize="14"/>
|
||||||
<textInputTraits key="textInputTraits" autocorrectionType="no" spellCheckingType="no" keyboardType="alphabet"/>
|
<textInputTraits key="textInputTraits" autocorrectionType="no" spellCheckingType="no" keyboardType="alphabet"/>
|
||||||
</textField>
|
</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">
|
<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"/>
|
<rect key="frame" x="20" y="128" width="335" height="34"/>
|
||||||
<nil key="textColor"/>
|
|
||||||
<fontDescription key="fontDescription" type="system" pointSize="14"/>
|
<fontDescription key="fontDescription" type="system" pointSize="14"/>
|
||||||
<textInputTraits key="textInputTraits" autocorrectionType="no" spellCheckingType="no" keyboardType="alphabet"/>
|
<textInputTraits key="textInputTraits" autocorrectionType="no" spellCheckingType="no" keyboardType="alphabet"/>
|
||||||
</textField>
|
</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">
|
<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"/>
|
<rect key="frame" x="20" y="74" width="245" height="34"/>
|
||||||
<nil key="textColor"/>
|
|
||||||
<fontDescription key="fontDescription" type="system" pointSize="14"/>
|
<fontDescription key="fontDescription" type="system" pointSize="14"/>
|
||||||
<textInputTraits key="textInputTraits" autocorrectionType="no" spellCheckingType="no" keyboardType="alphabet"/>
|
<textInputTraits key="textInputTraits" autocorrectionType="no" spellCheckingType="no" keyboardType="alphabet"/>
|
||||||
</textField>
|
</textField>
|
||||||
<textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" textAlignment="natural" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="7LH-tE-it9">
|
<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>
|
<constraints>
|
||||||
<constraint firstAttribute="width" constant="80" id="aWP-Ug-b9B"/>
|
<constraint firstAttribute="width" constant="80" id="aWP-Ug-b9B"/>
|
||||||
</constraints>
|
</constraints>
|
||||||
<nil key="textColor"/>
|
|
||||||
<fontDescription key="fontDescription" type="system" pointSize="14"/>
|
<fontDescription key="fontDescription" type="system" pointSize="14"/>
|
||||||
<textInputTraits key="textInputTraits"/>
|
<textInputTraits key="textInputTraits"/>
|
||||||
</textField>
|
</textField>
|
||||||
<button opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="249" contentHorizontalAlignment="left" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Teo-8d-LYJ">
|
<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"/>
|
<fontDescription key="fontDescription" type="system" pointSize="48"/>
|
||||||
<state key="normal" title="Connect"/>
|
<state key="normal" title="Connect"/>
|
||||||
<connections>
|
<connections>
|
||||||
|
@ -63,19 +56,19 @@
|
||||||
</connections>
|
</connections>
|
||||||
</button>
|
</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">
|
<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"/>
|
<fontDescription key="fontDescription" type="system" pointSize="20"/>
|
||||||
<nil key="textColor"/>
|
<nil key="textColor"/>
|
||||||
<nil key="highlightedColor"/>
|
<nil key="highlightedColor"/>
|
||||||
</label>
|
</label>
|
||||||
<switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" contentHorizontalAlignment="center" contentVerticalAlignment="center" translatesAutoresizingMaskIntoConstraints="NO" id="WZf-S5-SqC">
|
<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>
|
<connections>
|
||||||
<action selector="tcpClicked:" destination="BYZ-38-t0r" eventType="valueChanged" id="ZJI-Jw-pow"/>
|
<action selector="tcpClicked:" destination="BYZ-38-t0r" eventType="valueChanged" id="ZJI-Jw-pow"/>
|
||||||
</connections>
|
</connections>
|
||||||
</switch>
|
</switch>
|
||||||
<button opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="249" contentHorizontalAlignment="left" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="6dU-fF-FSg">
|
<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"/>
|
<fontDescription key="fontDescription" type="system" pointSize="24"/>
|
||||||
<state key="normal" title="See log"/>
|
<state key="normal" title="See log"/>
|
||||||
<connections>
|
<connections>
|
||||||
|
@ -83,13 +76,13 @@
|
||||||
</connections>
|
</connections>
|
||||||
</button>
|
</button>
|
||||||
<textView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" editable="NO" textAlignment="natural" translatesAutoresizingMaskIntoConstraints="NO" id="UNN-CR-rdr">
|
<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"/>
|
<color key="backgroundColor" cocoaTouchSystemColor="groupTableViewBackgroundColor"/>
|
||||||
<fontDescription key="fontDescription" name="CourierNewPSMT" family="Courier New" pointSize="17"/>
|
<fontDescription key="fontDescription" name="CourierNewPSMT" family="Courier New" pointSize="17"/>
|
||||||
<textInputTraits key="textInputTraits" autocapitalizationType="sentences"/>
|
<textInputTraits key="textInputTraits" autocapitalizationType="sentences"/>
|
||||||
</textView>
|
</textView>
|
||||||
</subviews>
|
</subviews>
|
||||||
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
<color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
|
||||||
<constraints>
|
<constraints>
|
||||||
<constraint firstItem="UNN-CR-rdr" firstAttribute="top" secondItem="6dU-fF-FSg" secondAttribute="bottom" constant="20" id="03h-H3-dSN"/>
|
<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"/>
|
<constraint firstItem="7LH-tE-it9" firstAttribute="centerY" secondItem="XwE-sE-aPN" secondAttribute="centerY" id="0wJ-c9-Gcy"/>
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
//
|
//
|
||||||
// ViewController.swift
|
// ViewController.swift
|
||||||
// BasicTunnel-iOS
|
// Demo
|
||||||
//
|
//
|
||||||
// Created by Davide De Rosa on 2/11/17.
|
// 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
|
// https://github.com/keeshux
|
||||||
//
|
//
|
||||||
|
@ -22,95 +22,13 @@
|
||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with TunnelKit. If not, see <http://www.gnu.org/licenses/>.
|
// 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 UIKit
|
||||||
import NetworkExtension
|
|
||||||
import TunnelKit
|
import TunnelKit
|
||||||
|
|
||||||
private let ca = OpenVPN.CryptoContainer(pem: """
|
private let appGroup = "group.com.algoritmico.ios.demo.BasicTunnel"
|
||||||
-----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-----
|
|
||||||
""")
|
|
||||||
|
|
||||||
extension ViewController {
|
private let tunnelIdentifier = "com.algoritmico.ios.demo.BasicTunnel.Extension"
|
||||||
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
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class ViewController: UIViewController, URLSessionDataDelegate {
|
class ViewController: UIViewController, URLSessionDataDelegate {
|
||||||
@IBOutlet var textUsername: UITextField!
|
@IBOutlet var textUsername: UITextField!
|
||||||
|
@ -129,160 +47,78 @@ class ViewController: UIViewController, URLSessionDataDelegate {
|
||||||
|
|
||||||
@IBOutlet var textLog: UITextView!
|
@IBOutlet var textLog: UITextView!
|
||||||
|
|
||||||
//
|
private let vpn = StandardVPNProvider(bundleIdentifier: tunnelIdentifier)
|
||||||
|
|
||||||
var currentManager: NETunnelProviderManager?
|
|
||||||
|
|
||||||
var status = NEVPNStatus.invalid
|
|
||||||
|
|
||||||
override func viewDidLoad() {
|
override func viewDidLoad() {
|
||||||
super.viewDidLoad()
|
super.viewDidLoad()
|
||||||
|
|
||||||
textServer.text = "germany"
|
textServer.text = "es"
|
||||||
textDomain.text = "privateinternetaccess.com"
|
textDomain.text = "lazerpenguin.com"
|
||||||
textPort.text = "1198"
|
textPort.text = "443"
|
||||||
switchTCP.isOn = false
|
switchTCP.isOn = false
|
||||||
textUsername.text = "myusername"
|
textUsername.text = ""
|
||||||
textPassword.text = "mypassword"
|
textPassword.text = ""
|
||||||
|
|
||||||
NotificationCenter.default.addObserver(self,
|
NotificationCenter.default.addObserver(
|
||||||
selector: #selector(VPNStatusDidChange(notification:)),
|
self,
|
||||||
name: .NEVPNStatusDidChange,
|
selector: #selector(VPNStatusDidChange(notification:)),
|
||||||
object: nil)
|
name: VPN.didChangeStatus,
|
||||||
|
object: nil
|
||||||
|
)
|
||||||
|
|
||||||
reloadCurrentManager(nil)
|
vpn.prepare(completionHandler: nil)
|
||||||
|
|
||||||
//
|
|
||||||
|
|
||||||
testFetchRef()
|
testFetchRef()
|
||||||
}
|
}
|
||||||
|
|
||||||
@IBAction func connectionClicked(_ sender: Any) {
|
@IBAction func connectionClicked(_ sender: Any) {
|
||||||
let block = {
|
switch vpn.status {
|
||||||
switch (self.status) {
|
case .disconnected:
|
||||||
case .invalid, .disconnected:
|
connect()
|
||||||
self.connect()
|
|
||||||
|
case .connected, .connecting, .disconnecting:
|
||||||
case .connected, .connecting:
|
disconnect()
|
||||||
self.disconnect()
|
|
||||||
|
|
||||||
default:
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (status == .invalid) {
|
|
||||||
reloadCurrentManager({ (error) in
|
|
||||||
block()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
block()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@IBAction func tcpClicked(_ sender: Any) {
|
@IBAction func tcpClicked(_ sender: Any) {
|
||||||
if switchTCP.isOn {
|
|
||||||
textPort.text = "502"
|
|
||||||
} else {
|
|
||||||
textPort.text = "1198"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func connect() {
|
func connect() {
|
||||||
configureVPN({ (manager) in
|
let server = textServer.text!
|
||||||
return self.makeProtocol()
|
let domain = textDomain.text!
|
||||||
}, completionHandler: { (error) in
|
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 {
|
if let error = error {
|
||||||
print("configure error: \(error)")
|
print("configure error: \(error)")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
let session = self.currentManager?.connection as! NETunnelProviderSession
|
}
|
||||||
do {
|
|
||||||
try session.startTunnel()
|
|
||||||
} catch let e {
|
|
||||||
print("error starting tunnel: \(e)")
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func disconnect() {
|
func disconnect() {
|
||||||
configureVPN({ (manager) in
|
vpn.disconnect(completionHandler: nil)
|
||||||
return nil
|
|
||||||
}, completionHandler: { (error) in
|
|
||||||
self.currentManager?.connection.stopVPNTunnel()
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@IBAction func displayLog() {
|
@IBAction func displayLog() {
|
||||||
guard let vpn = currentManager?.connection as? NETunnelProviderSession else {
|
vpn.requestDebugLog(fallback: { "" }) { (log) in
|
||||||
return
|
|
||||||
}
|
|
||||||
try? vpn.sendProviderMessage(OpenVPNTunnelProvider.Message.requestLog.data) { (data) in
|
|
||||||
guard let data = data, let log = String(data: data, encoding: .utf8) else {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
self.textLog.text = log
|
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() {
|
func updateButton() {
|
||||||
switch status {
|
switch vpn.status {
|
||||||
case .connected, .connecting:
|
case .connected, .connecting:
|
||||||
buttonConnection.setTitle("Disconnect", for: .normal)
|
buttonConnection.setTitle("Disconnect", for: .normal)
|
||||||
|
|
||||||
|
@ -291,19 +127,11 @@ class ViewController: UIViewController, URLSessionDataDelegate {
|
||||||
|
|
||||||
case .disconnecting:
|
case .disconnecting:
|
||||||
buttonConnection.setTitle("Disconnecting", for: .normal)
|
buttonConnection.setTitle("Disconnecting", for: .normal)
|
||||||
|
|
||||||
default:
|
|
||||||
break
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc private func VPNStatusDidChange(notification: NSNotification) {
|
@objc private func VPNStatusDidChange(notification: NSNotification) {
|
||||||
guard let status = currentManager?.connection.status else {
|
print("VPNStatusDidChange: \(vpn.status)")
|
||||||
print("VPNStatusDidChange")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
print("VPNStatusDidChange: \(status.rawValue)")
|
|
||||||
self.status = status
|
|
||||||
updateButton()
|
updateButton()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
//
|
//
|
||||||
// AppDelegate.swift
|
// AppDelegate.swift
|
||||||
// BasicTunnel-macOS
|
// Demo
|
||||||
//
|
//
|
||||||
// Created by Davide De Rosa on 10/15/17.
|
// 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
|
// https://github.com/keeshux
|
||||||
//
|
//
|
||||||
|
@ -22,18 +22,6 @@
|
||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with TunnelKit. If not, see <http://www.gnu.org/licenses/>.
|
// 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 Cocoa
|
||||||
import SwiftyBeaver
|
import SwiftyBeaver
|
||||||
|
|
|
@ -25,7 +25,7 @@
|
||||||
<key>LSMinimumSystemVersion</key>
|
<key>LSMinimumSystemVersion</key>
|
||||||
<string>$(MACOSX_DEPLOYMENT_TARGET)</string>
|
<string>$(MACOSX_DEPLOYMENT_TARGET)</string>
|
||||||
<key>NSHumanReadableCopyright</key>
|
<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>
|
<key>NSMainStoryboardFile</key>
|
||||||
<string>Main</string>
|
<string>Main</string>
|
||||||
<key>NSPrincipalClass</key>
|
<key>NSPrincipalClass</key>
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
//
|
//
|
||||||
// ViewController.swift
|
// ViewController.swift
|
||||||
// BasicTunnel-macOS
|
// Demo
|
||||||
//
|
//
|
||||||
// Created by Davide De Rosa on 10/15/17.
|
// 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
|
// https://github.com/keeshux
|
||||||
//
|
//
|
||||||
|
@ -22,96 +22,14 @@
|
||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with TunnelKit. If not, see <http://www.gnu.org/licenses/>.
|
// 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 Cocoa
|
||||||
import NetworkExtension
|
import NetworkExtension
|
||||||
import TunnelKit
|
import TunnelKit
|
||||||
|
|
||||||
private let ca = OpenVPN.CryptoContainer(pem: """
|
private let appGroup = "DTDYD63ZX9.group.com.algoritmico.macos.demo.BasicTunnel"
|
||||||
-----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-----
|
|
||||||
""")
|
|
||||||
|
|
||||||
extension ViewController {
|
private let tunnelIdentifier = "com.algoritmico.macos.demo.BasicTunnel.Extension"
|
||||||
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
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class ViewController: NSViewController {
|
class ViewController: NSViewController {
|
||||||
@IBOutlet var textUsername: NSTextField!
|
@IBOutlet var textUsername: NSTextField!
|
||||||
|
@ -126,139 +44,67 @@ class ViewController: NSViewController {
|
||||||
|
|
||||||
@IBOutlet var buttonConnection: NSButton!
|
@IBOutlet var buttonConnection: NSButton!
|
||||||
|
|
||||||
var currentManager: NETunnelProviderManager?
|
private let vpn = StandardVPNProvider(bundleIdentifier: tunnelIdentifier)
|
||||||
|
|
||||||
var status = NEVPNStatus.invalid
|
|
||||||
|
|
||||||
override func viewDidLoad() {
|
override func viewDidLoad() {
|
||||||
super.viewDidLoad()
|
super.viewDidLoad()
|
||||||
|
|
||||||
textServer.stringValue = "germany"
|
textServer.stringValue = "es"
|
||||||
textDomain.stringValue = "privateinternetaccess.com"
|
textDomain.stringValue = "lazerpenguin.com"
|
||||||
textPort.stringValue = "1198"
|
textPort.stringValue = "443"
|
||||||
textUsername.stringValue = "myusername"
|
textUsername.stringValue = ""
|
||||||
textPassword.stringValue = "mypassword"
|
textPassword.stringValue = ""
|
||||||
|
|
||||||
NotificationCenter.default.addObserver(
|
NotificationCenter.default.addObserver(
|
||||||
self,
|
self,
|
||||||
selector: #selector(VPNStatusDidChange(notification:)),
|
selector: #selector(VPNStatusDidChange(notification:)),
|
||||||
name: .NEVPNStatusDidChange,
|
name: VPN.didChangeStatus,
|
||||||
object: nil
|
object: nil
|
||||||
)
|
)
|
||||||
|
|
||||||
reloadCurrentManager(nil)
|
vpn.prepare(completionHandler: nil)
|
||||||
|
|
||||||
//
|
|
||||||
|
|
||||||
testFetchRef()
|
testFetchRef()
|
||||||
}
|
}
|
||||||
|
|
||||||
@IBAction func connectionClicked(_ sender: Any) {
|
@IBAction func connectionClicked(_ sender: Any) {
|
||||||
let block = {
|
switch vpn.status {
|
||||||
switch (self.status) {
|
case .disconnected:
|
||||||
case .invalid, .disconnected:
|
connect()
|
||||||
self.connect()
|
|
||||||
|
case .connected, .connecting, .disconnecting:
|
||||||
case .connected, .connecting:
|
disconnect()
|
||||||
self.disconnect()
|
|
||||||
|
|
||||||
default:
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (status == .invalid) {
|
|
||||||
reloadCurrentManager({ (error) in
|
|
||||||
block()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
block()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func connect() {
|
func connect() {
|
||||||
configureVPN({ (manager) in
|
let server = textServer.stringValue
|
||||||
return self.makeProtocol()
|
let domain = textDomain.stringValue
|
||||||
}, completionHandler: { (error) in
|
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 {
|
if let error = error {
|
||||||
print("configure error: \(error)")
|
print("configure error: \(error)")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
let session = self.currentManager?.connection as! NETunnelProviderSession
|
}
|
||||||
do {
|
|
||||||
try session.startTunnel()
|
|
||||||
} catch let e {
|
|
||||||
print("error starting tunnel: \(e)")
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func disconnect() {
|
func disconnect() {
|
||||||
configureVPN({ (manager) in
|
vpn.disconnect(completionHandler: nil)
|
||||||
return nil
|
|
||||||
}, completionHandler: { (error) in
|
|
||||||
self.currentManager?.connection.stopVPNTunnel()
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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() {
|
func updateButton() {
|
||||||
switch status {
|
switch vpn.status {
|
||||||
case .connected, .connecting:
|
case .connected, .connecting:
|
||||||
buttonConnection.title = "Disconnect"
|
buttonConnection.title = "Disconnect"
|
||||||
|
|
||||||
|
@ -267,22 +113,14 @@ class ViewController: NSViewController {
|
||||||
|
|
||||||
case .disconnecting:
|
case .disconnecting:
|
||||||
buttonConnection.title = "Disconnecting"
|
buttonConnection.title = "Disconnecting"
|
||||||
|
|
||||||
default:
|
|
||||||
break
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc private func VPNStatusDidChange(notification: NSNotification) {
|
@objc private func VPNStatusDidChange(notification: NSNotification) {
|
||||||
guard let status = currentManager?.connection.status else {
|
print("VPNStatusDidChange: \(vpn.status)")
|
||||||
print("VPNStatusDidChange")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
print("VPNStatusDidChange: \(status.rawValue)")
|
|
||||||
self.status = status
|
|
||||||
updateButton()
|
updateButton()
|
||||||
}
|
}
|
||||||
|
|
||||||
private func testFetchRef() {
|
private func testFetchRef() {
|
||||||
// let keychain = Keychain(group: ViewController.APP_GROUP)
|
// let keychain = Keychain(group: ViewController.APP_GROUP)
|
||||||
// let username = "foo"
|
// let username = "foo"
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
//
|
//
|
||||||
// PacketTunnelProvider.swift
|
// PacketTunnelProvider.swift
|
||||||
// BasicTunnelExtension-iOS
|
// Demo
|
||||||
//
|
//
|
||||||
// Created by Davide De Rosa on 9/15/17.
|
// 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
|
// https://github.com/keeshux
|
||||||
//
|
//
|
||||||
|
@ -22,18 +22,6 @@
|
||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with TunnelKit. If not, see <http://www.gnu.org/licenses/>.
|
// 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
|
import TunnelKit
|
||||||
|
|
||||||
|
|
|
@ -30,6 +30,6 @@
|
||||||
<string>$(PRODUCT_MODULE_NAME).PacketTunnelProvider</string>
|
<string>$(PRODUCT_MODULE_NAME).PacketTunnelProvider</string>
|
||||||
</dict>
|
</dict>
|
||||||
<key>NSHumanReadableCopyright</key>
|
<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>
|
</dict>
|
||||||
</plist>
|
</plist>
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
//
|
//
|
||||||
// PacketTunnelProvider.swift
|
// PacketTunnelProvider.swift
|
||||||
// BasicTunnelExtension-macOS
|
// Demo
|
||||||
//
|
//
|
||||||
// Created by Davide De Rosa on 10/15/17.
|
// 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
|
// https://github.com/keeshux
|
||||||
//
|
//
|
||||||
|
@ -22,18 +22,6 @@
|
||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with TunnelKit. If not, see <http://www.gnu.org/licenses/>.
|
// 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
|
import TunnelKit
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,8 @@
|
||||||
objects = {
|
objects = {
|
||||||
|
|
||||||
/* Begin PBXBuildFile section */
|
/* 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 */; };
|
0EB39FE91F7424F80023AFFC /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EB39FE81F7424F80023AFFC /* AppDelegate.swift */; };
|
||||||
0EB39FEB1F7424F80023AFFC /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EB39FEA1F7424F80023AFFC /* ViewController.swift */; };
|
0EB39FEB1F7424F80023AFFC /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EB39FEA1F7424F80023AFFC /* ViewController.swift */; };
|
||||||
0EB39FEE1F7424F80023AFFC /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 0EB39FEC1F7424F80023AFFC /* Main.storyboard */; };
|
0EB39FEE1F7424F80023AFFC /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 0EB39FEC1F7424F80023AFFC /* Main.storyboard */; };
|
||||||
|
@ -71,6 +73,7 @@
|
||||||
/* End PBXCopyFilesBuildPhase section */
|
/* End PBXCopyFilesBuildPhase section */
|
||||||
|
|
||||||
/* Begin PBXFileReference 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; };
|
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>"; };
|
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>"; };
|
0EB39FEA1F7424F80023AFFC /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = "<group>"; };
|
||||||
|
@ -147,6 +150,14 @@
|
||||||
/* End PBXFrameworksBuildPhase section */
|
/* End PBXFrameworksBuildPhase section */
|
||||||
|
|
||||||
/* Begin PBXGroup section */
|
/* Begin PBXGroup section */
|
||||||
|
0EAC574524943B3500D0FCE0 /* Shared */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
0EAC574624943B5D00D0FCE0 /* Configuration.swift */,
|
||||||
|
);
|
||||||
|
path = Shared;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
0EB39FC41F7424580023AFFC = {
|
0EB39FC41F7424580023AFFC = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
@ -154,6 +165,7 @@
|
||||||
0EB39FFD1F7425140023AFFC /* BasicTunnelExtension-iOS */,
|
0EB39FFD1F7425140023AFFC /* BasicTunnelExtension-iOS */,
|
||||||
0EB6EEB81F92D417005F6221 /* BasicTunnel-macOS */,
|
0EB6EEB81F92D417005F6221 /* BasicTunnel-macOS */,
|
||||||
0EB6EECC1F92D43D005F6221 /* BasicTunnelExtension-macOS */,
|
0EB6EECC1F92D43D005F6221 /* BasicTunnelExtension-macOS */,
|
||||||
|
0EAC574524943B3500D0FCE0 /* Shared */,
|
||||||
0EB39FCE1F7424580023AFFC /* Products */,
|
0EB39FCE1F7424580023AFFC /* Products */,
|
||||||
B850E57E641AD1B37E79BAB5 /* Frameworks */,
|
B850E57E641AD1B37E79BAB5 /* Frameworks */,
|
||||||
94C1D7B5B11C6CCE74B21D93 /* Pods */,
|
94C1D7B5B11C6CCE74B21D93 /* Pods */,
|
||||||
|
@ -541,8 +553,6 @@
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
);
|
);
|
||||||
inputFileListPaths = (
|
|
||||||
);
|
|
||||||
inputPaths = (
|
inputPaths = (
|
||||||
"${PODS_ROOT}/Target Support Files/Pods-macOS-BasicTunnel-macOS/Pods-macOS-BasicTunnel-macOS-frameworks.sh",
|
"${PODS_ROOT}/Target Support Files/Pods-macOS-BasicTunnel-macOS/Pods-macOS-BasicTunnel-macOS-frameworks.sh",
|
||||||
"${PODS_ROOT}/OpenSSL-Apple/frameworks/MacOSX/openssl.framework",
|
"${PODS_ROOT}/OpenSSL-Apple/frameworks/MacOSX/openssl.framework",
|
||||||
|
@ -550,8 +560,6 @@
|
||||||
"${BUILT_PRODUCTS_DIR}/TunnelKit-macOS/TunnelKit.framework",
|
"${BUILT_PRODUCTS_DIR}/TunnelKit-macOS/TunnelKit.framework",
|
||||||
);
|
);
|
||||||
name = "[CP] Embed Pods Frameworks";
|
name = "[CP] Embed Pods Frameworks";
|
||||||
outputFileListPaths = (
|
|
||||||
);
|
|
||||||
outputPaths = (
|
outputPaths = (
|
||||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/openssl.framework",
|
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/openssl.framework",
|
||||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SwiftyBeaver.framework",
|
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SwiftyBeaver.framework",
|
||||||
|
@ -567,8 +575,6 @@
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
);
|
);
|
||||||
inputFileListPaths = (
|
|
||||||
);
|
|
||||||
inputPaths = (
|
inputPaths = (
|
||||||
"${PODS_ROOT}/Target Support Files/Pods-iOS-BasicTunnel-iOS/Pods-iOS-BasicTunnel-iOS-frameworks.sh",
|
"${PODS_ROOT}/Target Support Files/Pods-iOS-BasicTunnel-iOS/Pods-iOS-BasicTunnel-iOS-frameworks.sh",
|
||||||
"${PODS_ROOT}/OpenSSL-Apple/frameworks/iPhone/openssl.framework",
|
"${PODS_ROOT}/OpenSSL-Apple/frameworks/iPhone/openssl.framework",
|
||||||
|
@ -576,8 +582,6 @@
|
||||||
"${BUILT_PRODUCTS_DIR}/TunnelKit-iOS/TunnelKit.framework",
|
"${BUILT_PRODUCTS_DIR}/TunnelKit-iOS/TunnelKit.framework",
|
||||||
);
|
);
|
||||||
name = "[CP] Embed Pods Frameworks";
|
name = "[CP] Embed Pods Frameworks";
|
||||||
outputFileListPaths = (
|
|
||||||
);
|
|
||||||
outputPaths = (
|
outputPaths = (
|
||||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/openssl.framework",
|
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/openssl.framework",
|
||||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SwiftyBeaver.framework",
|
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SwiftyBeaver.framework",
|
||||||
|
@ -639,6 +643,7 @@
|
||||||
isa = PBXSourcesBuildPhase;
|
isa = PBXSourcesBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
|
0EAC574724943B5D00D0FCE0 /* Configuration.swift in Sources */,
|
||||||
0EB39FEB1F7424F80023AFFC /* ViewController.swift in Sources */,
|
0EB39FEB1F7424F80023AFFC /* ViewController.swift in Sources */,
|
||||||
0EB39FE91F7424F80023AFFC /* AppDelegate.swift in Sources */,
|
0EB39FE91F7424F80023AFFC /* AppDelegate.swift in Sources */,
|
||||||
);
|
);
|
||||||
|
@ -656,6 +661,7 @@
|
||||||
isa = PBXSourcesBuildPhase;
|
isa = PBXSourcesBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
|
0EAC574824943B5D00D0FCE0 /* Configuration.swift in Sources */,
|
||||||
0EB6EEBC1F92D417005F6221 /* ViewController.swift in Sources */,
|
0EB6EEBC1F92D417005F6221 /* ViewController.swift in Sources */,
|
||||||
0EB6EEBA1F92D417005F6221 /* AppDelegate.swift in Sources */,
|
0EB6EEBA1F92D417005F6221 /* AppDelegate.swift in Sources */,
|
||||||
);
|
);
|
||||||
|
|
|
@ -6,6 +6,7 @@ abstract_target 'iOS' do
|
||||||
|
|
||||||
target 'BasicTunnelExtension-iOS' do
|
target 'BasicTunnelExtension-iOS' do
|
||||||
pod 'TunnelKit', :path => '..'
|
pod 'TunnelKit', :path => '..'
|
||||||
|
pod 'TunnelKit/Manager', :path => '..'
|
||||||
end
|
end
|
||||||
target 'BasicTunnel-iOS' do
|
target 'BasicTunnel-iOS' do
|
||||||
end
|
end
|
||||||
|
@ -16,6 +17,7 @@ abstract_target 'macOS' do
|
||||||
|
|
||||||
target 'BasicTunnelExtension-macOS' do
|
target 'BasicTunnelExtension-macOS' do
|
||||||
pod 'TunnelKit', :path => '..'
|
pod 'TunnelKit', :path => '..'
|
||||||
|
pod 'TunnelKit/Manager', :path => '..'
|
||||||
end
|
end
|
||||||
target 'BasicTunnel-macOS' do
|
target 'BasicTunnel-macOS' do
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,20 +1,23 @@
|
||||||
PODS:
|
PODS:
|
||||||
- OpenSSL-Apple (1.1.0j.2)
|
- OpenSSL-Apple (1.1.1g.6)
|
||||||
- SwiftyBeaver (1.7.0)
|
- SwiftyBeaver (1.9.1)
|
||||||
- TunnelKit (2.0.0):
|
- TunnelKit (2.3.0):
|
||||||
- TunnelKit/Protocols/OpenVPN (= 2.0.0)
|
- TunnelKit/Protocols/OpenVPN (= 2.3.0)
|
||||||
- TunnelKit/AppExtension (2.0.0):
|
- TunnelKit/AppExtension (2.3.0):
|
||||||
- SwiftyBeaver
|
- SwiftyBeaver
|
||||||
- TunnelKit/Core
|
- TunnelKit/Core
|
||||||
- TunnelKit/Core (2.0.0):
|
- TunnelKit/Core (2.3.0):
|
||||||
- OpenSSL-Apple (~> 1.1.0j.2)
|
|
||||||
- SwiftyBeaver
|
- 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/AppExtension
|
||||||
- TunnelKit/Core
|
- TunnelKit/Core
|
||||||
|
|
||||||
DEPENDENCIES:
|
DEPENDENCIES:
|
||||||
- TunnelKit (from `..`)
|
- TunnelKit (from `..`)
|
||||||
|
- TunnelKit/Manager (from `..`)
|
||||||
|
|
||||||
SPEC REPOS:
|
SPEC REPOS:
|
||||||
https://github.com/cocoapods/specs.git:
|
https://github.com/cocoapods/specs.git:
|
||||||
|
@ -26,10 +29,10 @@ EXTERNAL SOURCES:
|
||||||
:path: ".."
|
:path: ".."
|
||||||
|
|
||||||
SPEC CHECKSUMS:
|
SPEC CHECKSUMS:
|
||||||
OpenSSL-Apple: e88e1eb314acb4a05e2348069790c4aa49f6d319
|
OpenSSL-Apple: c9c1b9c5b2b1fc4e1758fc5f0836b58ae7fd8183
|
||||||
SwiftyBeaver: 4cc0080d2e23f980652e28978db11a5c9da39165
|
SwiftyBeaver: a1f5691458561414bcfab51874b2b7445451602b
|
||||||
TunnelKit: 821c15bb87aafae69eb8c63e4cc46d883fff8797
|
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.
|
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
|
### 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.
|
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"
|
p.dependency "TunnelKit/Core"
|
||||||
end
|
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|
|
s.subspec "Protocols" do |t|
|
||||||
t.subspec "OpenVPN" do |p|
|
t.subspec "OpenVPN" do |p|
|
||||||
p.source_files = "TunnelKit/Sources/Protocols/OpenVPN/**/*.{h,m,swift}"
|
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 */; };
|
0E7F3F6B246ABA0F006BE77F /* IPHeader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E7F3F69246ABA0F006BE77F /* IPHeader.swift */; };
|
||||||
0EA82A282190B220007960EB /* TunnelKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0E3251C51F95770D00C108D9 /* TunnelKit.framework */; };
|
0EA82A282190B220007960EB /* TunnelKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0E3251C51F95770D00C108D9 /* TunnelKit.framework */; };
|
||||||
0EA82A3E2190B2BC007960EB /* pia-2048.pem in Resources */ = {isa = PBXBuildFile; fileRef = 0E749F612178911C00BB2701 /* pia-2048.pem */; };
|
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 */; };
|
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, ); }; };
|
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 */; };
|
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>"; };
|
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; };
|
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>"; };
|
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>"; };
|
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>"; };
|
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>"; };
|
0ECEB1132252C8E900E9E551 /* tunnelbear.enc.8.ovpn */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = tunnelbear.enc.8.ovpn; sourceTree = "<group>"; };
|
||||||
|
@ -618,6 +636,7 @@
|
||||||
0EE2F9DD22918DA100F56F49 /* AppExtension */,
|
0EE2F9DD22918DA100F56F49 /* AppExtension */,
|
||||||
0EFEB4292006D3C800F81029 /* Core */,
|
0EFEB4292006D3C800F81029 /* Core */,
|
||||||
0E23B41922982AF800304C30 /* Extra */,
|
0E23B41922982AF800304C30 /* Extra */,
|
||||||
|
0EAC57302494277A00D0FCE0 /* Manager */,
|
||||||
0E23B3E022982AF800304C30 /* Protocols */,
|
0E23B3E022982AF800304C30 /* Protocols */,
|
||||||
);
|
);
|
||||||
path = Sources;
|
path = Sources;
|
||||||
|
@ -800,6 +819,19 @@
|
||||||
path = "TunnelKitTests-iOS";
|
path = "TunnelKitTests-iOS";
|
||||||
sourceTree = "<group>";
|
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 */ = {
|
0EE2F9DD22918DA100F56F49 /* AppExtension */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
@ -1410,12 +1442,14 @@
|
||||||
files = (
|
files = (
|
||||||
0EE2F974229163C900F56F49 /* Proxy.swift in Sources */,
|
0EE2F974229163C900F56F49 /* Proxy.swift in Sources */,
|
||||||
0EFEB4732006D3C800F81029 /* LinkInterface.swift in Sources */,
|
0EFEB4732006D3C800F81029 /* LinkInterface.swift in Sources */,
|
||||||
|
0EAC573B2494277A00D0FCE0 /* VPNStatus.swift in Sources */,
|
||||||
0E23B48922982AF800304C30 /* PacketStream.m in Sources */,
|
0E23B48922982AF800304C30 /* PacketStream.m in Sources */,
|
||||||
0E23B3DE229749C600304C30 /* LinkProducer.swift in Sources */,
|
0E23B3DE229749C600304C30 /* LinkProducer.swift in Sources */,
|
||||||
0E23B42722982AF800304C30 /* CryptoAEAD.m in Sources */,
|
0E23B42722982AF800304C30 /* CryptoAEAD.m in Sources */,
|
||||||
0EE2F9F222918DA100F56F49 /* NETunnelInterface.swift in Sources */,
|
0EE2F9F222918DA100F56F49 /* NETunnelInterface.swift in Sources */,
|
||||||
0E23B46722982AF800304C30 /* Authenticator.swift in Sources */,
|
0E23B46722982AF800304C30 /* Authenticator.swift in Sources */,
|
||||||
0E23B43922982AF800304C30 /* OpenVPNError.swift in Sources */,
|
0E23B43922982AF800304C30 /* OpenVPNError.swift in Sources */,
|
||||||
|
0EAC573F2494277A00D0FCE0 /* VPNProvider.swift in Sources */,
|
||||||
0E23B44F22982AF800304C30 /* OpenVPNTunnelProvider+Interaction.swift in Sources */,
|
0E23B44F22982AF800304C30 /* OpenVPNTunnelProvider+Interaction.swift in Sources */,
|
||||||
0E23B46D22982AF800304C30 /* StaticKey.swift in Sources */,
|
0E23B46D22982AF800304C30 /* StaticKey.swift in Sources */,
|
||||||
0E23B49F22982AF800304C30 /* minilzo.c in Sources */,
|
0E23B49F22982AF800304C30 /* minilzo.c in Sources */,
|
||||||
|
@ -1432,6 +1466,7 @@
|
||||||
0E12B29E21449ADB00B4BAE9 /* NSRegularExpression+Shortcuts.swift in Sources */,
|
0E12B29E21449ADB00B4BAE9 /* NSRegularExpression+Shortcuts.swift in Sources */,
|
||||||
0EE2F9F822918DA100F56F49 /* NWUDPSessionState+Description.swift in Sources */,
|
0EE2F9F822918DA100F56F49 /* NWUDPSessionState+Description.swift in Sources */,
|
||||||
0EE2F9AC2291853D00F56F49 /* Session.swift in Sources */,
|
0EE2F9AC2291853D00F56F49 /* Session.swift in Sources */,
|
||||||
|
0EAC57412494277A00D0FCE0 /* VPN.swift in Sources */,
|
||||||
0E23B48122982AF800304C30 /* ControlPacket.m in Sources */,
|
0E23B48122982AF800304C30 /* ControlPacket.m in Sources */,
|
||||||
0EFEB4622006D3C800F81029 /* SecureRandom.swift in Sources */,
|
0EFEB4622006D3C800F81029 /* SecureRandom.swift in Sources */,
|
||||||
0E011F7D2196D97200BA59EE /* EndpointProtocol.swift in Sources */,
|
0E011F7D2196D97200BA59EE /* EndpointProtocol.swift in Sources */,
|
||||||
|
@ -1479,9 +1514,12 @@
|
||||||
0E23B45722982AF800304C30 /* NETCPLink.swift in Sources */,
|
0E23B45722982AF800304C30 /* NETCPLink.swift in Sources */,
|
||||||
0E23B45322982AF800304C30 /* ConnectionStrategy.swift in Sources */,
|
0E23B45322982AF800304C30 /* ConnectionStrategy.swift in Sources */,
|
||||||
0E011F7A2196D93600BA59EE /* SocketType.swift in Sources */,
|
0E011F7A2196D93600BA59EE /* SocketType.swift in Sources */,
|
||||||
|
0EAC57392494277A00D0FCE0 /* MockVPNProvider.swift in Sources */,
|
||||||
0E23B45922982AF800304C30 /* OpenVPNTunnelProvider.swift in Sources */,
|
0E23B45922982AF800304C30 /* OpenVPNTunnelProvider.swift in Sources */,
|
||||||
0EFEB45A2006D3C800F81029 /* TunnelInterface.swift in Sources */,
|
0EFEB45A2006D3C800F81029 /* TunnelInterface.swift in Sources */,
|
||||||
|
0EAC57372494277A00D0FCE0 /* StandardVPNProvider.swift in Sources */,
|
||||||
0E23B47322982AF800304C30 /* MSS.m in Sources */,
|
0E23B47322982AF800304C30 /* MSS.m in Sources */,
|
||||||
|
0EAC573D2494277A00D0FCE0 /* VPNConfiguration.swift in Sources */,
|
||||||
0E23B45D22982AF800304C30 /* ProtocolMacros.swift in Sources */,
|
0E23B45D22982AF800304C30 /* ProtocolMacros.swift in Sources */,
|
||||||
0EE2FA0022918DA100F56F49 /* MemoryDestination.swift in Sources */,
|
0EE2FA0022918DA100F56F49 /* MemoryDestination.swift in Sources */,
|
||||||
);
|
);
|
||||||
|
@ -1493,12 +1531,14 @@
|
||||||
files = (
|
files = (
|
||||||
0EE2F975229163C900F56F49 /* Proxy.swift in Sources */,
|
0EE2F975229163C900F56F49 /* Proxy.swift in Sources */,
|
||||||
0EFEB4A12006D7F300F81029 /* LinkInterface.swift in Sources */,
|
0EFEB4A12006D7F300F81029 /* LinkInterface.swift in Sources */,
|
||||||
|
0EAC573C2494277A00D0FCE0 /* VPNStatus.swift in Sources */,
|
||||||
0E23B48A22982AF800304C30 /* PacketStream.m in Sources */,
|
0E23B48A22982AF800304C30 /* PacketStream.m in Sources */,
|
||||||
0E23B3DF229749C600304C30 /* LinkProducer.swift in Sources */,
|
0E23B3DF229749C600304C30 /* LinkProducer.swift in Sources */,
|
||||||
0E23B42822982AF800304C30 /* CryptoAEAD.m in Sources */,
|
0E23B42822982AF800304C30 /* CryptoAEAD.m in Sources */,
|
||||||
0EE2F9F322918DA100F56F49 /* NETunnelInterface.swift in Sources */,
|
0EE2F9F322918DA100F56F49 /* NETunnelInterface.swift in Sources */,
|
||||||
0E23B46822982AF800304C30 /* Authenticator.swift in Sources */,
|
0E23B46822982AF800304C30 /* Authenticator.swift in Sources */,
|
||||||
0E23B43A22982AF800304C30 /* OpenVPNError.swift in Sources */,
|
0E23B43A22982AF800304C30 /* OpenVPNError.swift in Sources */,
|
||||||
|
0EAC57402494277A00D0FCE0 /* VPNProvider.swift in Sources */,
|
||||||
0E23B45022982AF800304C30 /* OpenVPNTunnelProvider+Interaction.swift in Sources */,
|
0E23B45022982AF800304C30 /* OpenVPNTunnelProvider+Interaction.swift in Sources */,
|
||||||
0E23B46E22982AF800304C30 /* StaticKey.swift in Sources */,
|
0E23B46E22982AF800304C30 /* StaticKey.swift in Sources */,
|
||||||
0E23B4A022982AF800304C30 /* minilzo.c in Sources */,
|
0E23B4A022982AF800304C30 /* minilzo.c in Sources */,
|
||||||
|
@ -1515,6 +1555,7 @@
|
||||||
0E12B29F21449ADB00B4BAE9 /* NSRegularExpression+Shortcuts.swift in Sources */,
|
0E12B29F21449ADB00B4BAE9 /* NSRegularExpression+Shortcuts.swift in Sources */,
|
||||||
0EE2F9F922918DA100F56F49 /* NWUDPSessionState+Description.swift in Sources */,
|
0EE2F9F922918DA100F56F49 /* NWUDPSessionState+Description.swift in Sources */,
|
||||||
0EE2F9AD2291853D00F56F49 /* Session.swift in Sources */,
|
0EE2F9AD2291853D00F56F49 /* Session.swift in Sources */,
|
||||||
|
0EAC57422494277A00D0FCE0 /* VPN.swift in Sources */,
|
||||||
0E23B48222982AF800304C30 /* ControlPacket.m in Sources */,
|
0E23B48222982AF800304C30 /* ControlPacket.m in Sources */,
|
||||||
0E011F7E2196D97200BA59EE /* EndpointProtocol.swift in Sources */,
|
0E011F7E2196D97200BA59EE /* EndpointProtocol.swift in Sources */,
|
||||||
0EE2F9F122918DA100F56F49 /* NETCPSocket.swift in Sources */,
|
0EE2F9F122918DA100F56F49 /* NETCPSocket.swift in Sources */,
|
||||||
|
@ -1562,9 +1603,12 @@
|
||||||
0E23B45822982AF800304C30 /* NETCPLink.swift in Sources */,
|
0E23B45822982AF800304C30 /* NETCPLink.swift in Sources */,
|
||||||
0E23B45422982AF800304C30 /* ConnectionStrategy.swift in Sources */,
|
0E23B45422982AF800304C30 /* ConnectionStrategy.swift in Sources */,
|
||||||
0EFEB49D2006D7F300F81029 /* IOInterface.swift in Sources */,
|
0EFEB49D2006D7F300F81029 /* IOInterface.swift in Sources */,
|
||||||
|
0EAC573A2494277A00D0FCE0 /* MockVPNProvider.swift in Sources */,
|
||||||
0E23B45A22982AF800304C30 /* OpenVPNTunnelProvider.swift in Sources */,
|
0E23B45A22982AF800304C30 /* OpenVPNTunnelProvider.swift in Sources */,
|
||||||
0E011F7B2196D93600BA59EE /* SocketType.swift in Sources */,
|
0E011F7B2196D93600BA59EE /* SocketType.swift in Sources */,
|
||||||
|
0EAC57382494277A00D0FCE0 /* StandardVPNProvider.swift in Sources */,
|
||||||
0E23B47422982AF800304C30 /* MSS.m in Sources */,
|
0E23B47422982AF800304C30 /* MSS.m in Sources */,
|
||||||
|
0EAC573E2494277A00D0FCE0 /* VPNConfiguration.swift in Sources */,
|
||||||
0E23B45E22982AF800304C30 /* ProtocolMacros.swift in Sources */,
|
0E23B45E22982AF800304C30 /* ProtocolMacros.swift in Sources */,
|
||||||
0EE2FA0122918DA100F56F49 /* MemoryDestination.swift in Sources */,
|
0EE2FA0122918DA100F56F49 /* MemoryDestination.swift in Sources */,
|
||||||
);
|
);
|
||||||
|
|
|
@ -44,7 +44,7 @@ private let log = SwiftyBeaver.self
|
||||||
public class InterfaceObserver: NSObject {
|
public class InterfaceObserver: NSObject {
|
||||||
|
|
||||||
/// A change in Wi-Fi state occurred.
|
/// 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?
|
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