Skip to content

Commit

Permalink
Merge pull request #418 from ivpn/task/update-tunnelkit-2
Browse files Browse the repository at this point in the history
Update TunnelKit package
  • Loading branch information
jurajhilje authored Apr 22, 2024
2 parents d80bc5f + 2a7400f commit 1332351
Show file tree
Hide file tree
Showing 7 changed files with 184 additions and 69 deletions.
6 changes: 5 additions & 1 deletion IVPNClient.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,7 @@
828E9C95231E5780001E1FCF /* Data+Ext.swift in Sources */ = {isa = PBXBuildFile; fileRef = 828E9C94231E5780001E1FCF /* Data+Ext.swift */; };
828E9C96231E5780001E1FCF /* Data+Ext.swift in Sources */ = {isa = PBXBuildFile; fileRef = 828E9C94231E5780001E1FCF /* Data+Ext.swift */; };
8290195F243CB27500777B6E /* ControlPanelView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8290195E243CB27500777B6E /* ControlPanelView.swift */; };
8292D0FC2B45AEE8001EA123 /* TunnelKit+Ext.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8292D0FB2B45AEE8001EA123 /* TunnelKit+Ext.swift */; };
8292E19B21748B0500123538 /* UserDefaults+Ext.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825A43FC215CCFE70076131F /* UserDefaults+Ext.swift */; };
8292E1A72174C10700123538 /* Peer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8292E1A62174C10700123538 /* Peer.swift */; };
8292E1A92174C11600123538 /* Interface.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8292E1A82174C11600123538 /* Interface.swift */; };
Expand Down Expand Up @@ -588,6 +589,7 @@
828D8A6C258245AD00CB0E5B /* TwoFactorViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TwoFactorViewController.swift; sourceTree = "<group>"; };
828E9C94231E5780001E1FCF /* Data+Ext.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Data+Ext.swift"; sourceTree = "<group>"; };
8290195E243CB27500777B6E /* ControlPanelView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ControlPanelView.swift; sourceTree = "<group>"; };
8292D0FB2B45AEE8001EA123 /* TunnelKit+Ext.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "TunnelKit+Ext.swift"; sourceTree = "<group>"; };
8292E1A62174C10700123538 /* Peer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Peer.swift; sourceTree = "<group>"; };
8292E1A82174C11600123538 /* Interface.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Interface.swift; sourceTree = "<group>"; };
8292E1AA2174C12200123538 /* Tunnel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Tunnel.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -1156,6 +1158,7 @@
82CE598F25ED3C7A0078099D /* URL+Ext.swift */,
82B329CA29F7C9F400F3ED9B /* UIWindow+Ext.swift */,
822BC6892A7CF3A700C733DF /* Decodable+Ext.swift */,
8292D0FB2B45AEE8001EA123 /* TunnelKit+Ext.swift */,
);
path = Extensions;
sourceTree = "<group>";
Expand Down Expand Up @@ -2259,6 +2262,7 @@
8277F1CD22118D08007C6F15 /* ProofsViewModel.swift in Sources */,
8269CAC32264962F00CF488A /* AntiTrackerViewController.swift in Sources */,
82E5449224EE584E006DEF8D /* UIImageView+Ext.swift in Sources */,
8292D0FC2B45AEE8001EA123 /* TunnelKit+Ext.swift in Sources */,
82E81AE72449C44F00D81FB7 /* PaymentComponentView.swift in Sources */,
8232FBF62240E40F006B81D2 /* Error+Ext.swift in Sources */,
820203932186EE0E00D756AA /* WireGuardSettingsViewController.swift in Sources */,
Expand Down Expand Up @@ -3464,7 +3468,7 @@
repositoryURL = "https://github.com/passepartoutvpn/tunnelkit";
requirement = {
kind = exactVersion;
version = 4.1.0;
version = 6.2.0;
};
};
829F5FC529A13CAE009E1AD3 /* XCRemoteSwiftPackageReference "KeychainAccess" */ = {
Expand Down
4 changes: 4 additions & 0 deletions IVPNClient/Config/Config.swift
Original file line number Diff line number Diff line change
Expand Up @@ -109,4 +109,8 @@ struct Config {
return value
}

// MARK: Log files

static let maxBytes = 100000

}
25 changes: 4 additions & 21 deletions IVPNClient/Managers/VPNManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -398,32 +398,15 @@ class VPNManager {
}

func getOpenVPNLog(completion: @escaping (String?) -> Void) {
guard let session = openvpnManager?.connection as? NETunnelProviderSession else {
completion(nil)
return
}
let maxBytes = UInt64(Config.maxBytes)

do {
try session.sendProviderMessage(OpenVPNProvider.Message.requestLog.data) { data in
guard let data = data, !data.isEmpty else {
completion(nil)
return
}

guard let newestLog = String(data: data, encoding: .utf8), !newestLog.isEmpty else {
completion(nil)
return
}

completion(newestLog)
return
}
} catch {
guard let url = FileManager.openvpnLogTextFileURL else {
completion(nil)
return
}

completion(nil)
let lines = url.trailingLines(bytes: maxBytes)
completion(lines.joined(separator: "\n"))
}

func getWireGuardLog(completion: @escaping (String?) -> Void) {
Expand Down
5 changes: 5 additions & 0 deletions IVPNClient/Utilities/Extensions/FileManager+Extension.swift
Original file line number Diff line number Diff line change
Expand Up @@ -54,10 +54,15 @@ extension FileManager {
return sharedFolderURL?.appendingPathComponent("WireGuard.log")
}

static var openvpnLogTextFileURL: URL? {
return sharedFolderURL?.appendingPathComponent("Tunnel.log")
}

static func deleteFile(at url: URL) -> Bool {
do {
try FileManager.default.removeItem(at: url)
} catch {
log(.error, message: error.localizedDescription)
return false
}
return true
Expand Down
82 changes: 35 additions & 47 deletions IVPNClient/Utilities/Extensions/NETunnelProviderProtocol+Ext.swift
Original file line number Diff line number Diff line change
Expand Up @@ -33,66 +33,54 @@ extension NETunnelProviderProtocol {
// MARK: OpenVPN

static func makeOpenVPNProtocol(settings: ConnectionSettings, accessDetails: AccessDetails) -> NETunnelProviderProtocol {
guard let host = getHost() else {
return NETunnelProviderProtocol()
}
var proto = NETunnelProviderProtocol()

let username = accessDetails.username
let socketType: SocketType = settings.protocolType() == "TCP" ? .tcp : .udp
let credentials = OpenVPN.Credentials(username, KeyChain.vpnPassword ?? "")
let staticKey = OpenVPN.StaticKey.init(file: OpenVPNConf.tlsAuth, direction: OpenVPN.StaticKey.Direction.client)
let port = UInt16(getPort(settings: settings))

var sessionBuilder = OpenVPN.ConfigurationBuilder()
sessionBuilder.ca = OpenVPN.CryptoContainer(pem: OpenVPNConf.caCert)
sessionBuilder.cipher = .aes256cbc
sessionBuilder.compressionFraming = .disabled
sessionBuilder.endpointProtocols = [EndpointProtocol(socketType, port)]
sessionBuilder.hostname = host.host
sessionBuilder.tlsWrap = OpenVPN.TLSWrap.init(strategy: .auth, key: staticKey!)

if let dnsServers = openVPNdnsServers(), !dnsServers.isEmpty, dnsServers != [""] {
sessionBuilder.dnsServers = dnsServers
log(.info, message: "DNS server: \(dnsServers)")

switch DNSProtocolType.preferred() {
case .doh:
sessionBuilder.dnsProtocol = .https
sessionBuilder.dnsHTTPSURL = URL.init(string: DNSProtocolType.getServerURL(address: UserDefaults.shared.customDNS))
case .dot:
sessionBuilder.dnsProtocol = .tls
sessionBuilder.dnsTLSServerName = DNSProtocolType.getServerName(address: UserDefaults.shared.customDNS)
default:
sessionBuilder.dnsProtocol = .plain
}
guard let host = getHost() else {
return proto
}

var builder = OpenVPNProvider.ConfigurationBuilder(sessionConfiguration: sessionBuilder.build())
builder.shouldDebug = true
builder.debugLogFormat = "$Dyyyy-MM-dd HH:mm:ss$d $L $M"
builder.masksPrivateData = true
let credentials = OpenVPN.Credentials(accessDetails.username, KeyChain.vpnPassword ?? "")

let configuration = builder.build()
let keychain = Keychain(group: Config.appGroup)
_ = try? keychain.set(password: credentials.password, for: credentials.username, context: Config.openvpnTunnelProvider)
let proto = try! configuration.generatedTunnelProtocol(
withBundleIdentifier: Config.openvpnTunnelProvider,
let params = OpenVPN.Config.Parameters(
title: Config.openvpnTunnelTitle,
appGroup: Config.appGroup,
context: Config.openvpnTunnelProvider,
credentials: credentials
hostname: host.host,
port: UInt16(getPort(settings: settings)),
socketType: settings.protocolType() == "TCP" ? .tcp : .udp,
dnsServers: openVPNdnsServers(),
dnsProtocol: DNSProtocolType.preferred(),
customDNS: UserDefaults.shared.customDNS
)
proto.disconnectOnSleep = !UserDefaults.shared.keepAlive

var cfg = OpenVPN.Config.make(params: params)
cfg.username = credentials.username

let keychain = Keychain(group: Config.appGroup)
var passwordReference = Data()
do {
passwordReference = try keychain.set(password: credentials.password, for: credentials.username, context: Config.openvpnTunnelProvider)
} catch {
log(.error, message: "Keychain failure: \(error)")
}

var extra = NetworkExtensionExtra()
extra.passwordReference = passwordReference

do {
proto = try cfg.asTunnelProtocol(withBundleIdentifier: Config.openvpnTunnelProvider, extra: extra)
} catch {
log(.error, message: "Keychain failure: \(error)")
}

if #available(iOS 15.1, *) {
if #available(iOS 16, *) { } else {
proto.includeAllNetworks = UserDefaults.shared.killSwitch
}
}

if #available(iOS 14.2, *) {
proto.includeAllNetworks = disableLanAccess()
proto.excludeLocalNetworks = !disableLanAccess()
}
proto.includeAllNetworks = disableLanAccess()
proto.excludeLocalNetworks = !disableLanAccess()
proto.disconnectOnSleep = !UserDefaults.shared.keepAlive

return proto
}
Expand Down
82 changes: 82 additions & 0 deletions IVPNClient/Utilities/Extensions/TunnelKit+Ext.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
//
// TunnelKit+Ext.swift
// IVPN iOS app
// https://github.com/ivpn/ios-app
//
// Created by Juraj Hilje on 2024-01-03.
// Copyright (c) 2024 IVPN Limited.
//
// This file is part of the IVPN iOS app.
//
// The IVPN iOS app 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.
//
// The IVPN iOS app 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 the IVPN iOS app. If not, see <https://www.gnu.org/licenses/>.
//

import Foundation
import TunnelKitCore
import TunnelKitOpenVPN

extension OpenVPN {

struct Config {

struct Parameters {
let title: String
let appGroup: String
let hostname: String
let port: UInt16
let socketType: SocketType
let dnsServers: [String]?
let dnsProtocol: DNSProtocolType
let customDNS: String
}

static func make(params: Parameters) -> OpenVPN.ProviderConfiguration {
let tlsKey = OpenVPN.StaticKey(file: OpenVPNConf.tlsAuth, direction: .client)!

var builder = OpenVPN.ConfigurationBuilder()
builder.ca = OpenVPN.CryptoContainer(pem: OpenVPNConf.caCert)
builder.cipher = .aes256cbc
builder.compressionFraming = .disabled
builder.remotes = [Endpoint(params.hostname, EndpointProtocol(params.socketType, params.port))]
builder.tlsWrap = TLSWrap(strategy: .auth, key: tlsKey)
builder.routingPolicies = [.IPv4, .IPv6]

if let dnsServers = params.dnsServers, !dnsServers.isEmpty, dnsServers != [""] {
builder.dnsServers = dnsServers

switch params.dnsProtocol {
case .doh:
builder.dnsProtocol = .https
builder.dnsHTTPSURL = URL.init(string: DNSProtocolType.getServerURL(address: params.customDNS))
case .dot:
builder.dnsProtocol = .tls
builder.dnsTLSServerName = DNSProtocolType.getServerName(address: params.customDNS)
default:
builder.dnsProtocol = .plain
}
}

let cfg = builder.build()

var configuration = OpenVPN.ProviderConfiguration(params.title, appGroup: params.appGroup, configuration: cfg)
configuration.shouldDebug = true
configuration.debugLogFormat = "$Dyyyy-MM-dd HH:mm:ss$d $L $M"
configuration.masksPrivateData = true
configuration.debugLogPath = FileManager.openvpnLogTextFileURL?.lastPathComponent

return configuration
}

}

}
49 changes: 49 additions & 0 deletions IVPNClient/Utilities/Extensions/URL+Ext.swift
Original file line number Diff line number Diff line change
Expand Up @@ -43,4 +43,53 @@ extension URL {
return ""
}

func trailingContent(bytes: UInt64) -> String {
var file: FileHandle?

defer {
try? file?.close()
}

do {
file = try FileHandle(forReadingFrom: self)

guard let size = try file?.seekToEnd() else {
log(.error, message: "Cannot seek")
return ""
}

var offset: UInt64
if bytes < size {
offset = size - bytes
} else {
offset = 0
}

try file?.seek(toOffset: offset)

guard let data = try file?.readToEnd() else {
log(.error, message: "No data")
return ""
}

guard let string = String(data: data, encoding: .utf8) else {
log(.error, message: "Cannot encode string")
return ""
}

return string
} catch {
log(.error, message: "Error while reading file: \(error)")
return ""
}
}

func trailingLines(bytes: UInt64) -> [String] {
return trailingContent(bytes: bytes)
.components(separatedBy: "\n")
.filter {
!$0.isEmpty
}
}

}

0 comments on commit 1332351

Please sign in to comment.