amnezia-client/client/platforms/ios/PacketTunnelProvider+Xray.swift
2025-02-12 18:55:49 +01:00

353 lines
13 KiB
Swift

//import Foundation
//import NetworkExtension
//import WireGuardKitGo
//
//enum XrayErrors: Error {
// case noXrayConfig
// case xrayConfigIsWrong
// case cantSaveXrayConfig
// case cantParseListenAndPort
// case cantSaveHevSocksConfig
//}
//
//extension Constants {
// static let cachesDirectory: URL = {
// if let cachesDirectoryURL = FileManager.default.urls(for: .cachesDirectory,
// in: .userDomainMask).first {
// return cachesDirectoryURL
// } else {
// fatalError("Unable to retrieve caches directory.")
// }
// }()
//}
//
//extension PacketTunnelProvider {
// func startXray(completionHandler: @escaping (Error?) -> Void) {
//
// // Xray configuration
// guard let protocolConfiguration = self.protocolConfiguration as? NETunnelProviderProtocol,
// let providerConfiguration = protocolConfiguration.providerConfiguration,
// let configData = providerConfiguration[Constants.xrayConfigKey] as? Data else {
// xrayLog(.error, message: "Can't get xray configuration")
// completionHandler(XrayErrors.noXrayConfig)
// return
// }
//
// // Tunnel settings
// let ipv6Enabled = false
// let hideVPNIcon = false
//
// let settings = NEPacketTunnelNetworkSettings(tunnelRemoteAddress: "254.1.1.1")
// settings.mtu = 9000
//
// settings.ipv4Settings = {
// let settings = NEIPv4Settings(addresses: ["198.18.0.1"], subnetMasks: ["255.255.0.0"])
// settings.includedRoutes = [NEIPv4Route.default()]
// return settings
// }()
//
// settings.ipv6Settings = {
// guard ipv6Enabled else {
// return nil
// }
// let settings = NEIPv6Settings(addresses: ["fd6e:a81b:704f:1211::1"], networkPrefixLengths: [64])
// settings.includedRoutes = [NEIPv6Route.default()]
// if hideVPNIcon {
// settings.excludedRoutes = [NEIPv6Route(destinationAddress: "::", networkPrefixLength: 128)]
// }
// return settings
// }()
//
// do {
// let xrayConfig = try JSONDecoder().decode(XrayConfig.self,
// from: configData)
//
// var dnsArray = [String]()
// if let dns1 = xrayConfig.dns1 {
// dnsArray.append(dns1)
// }
// if let dns2 = xrayConfig.dns2 {
// dnsArray.append(dns2)
// }
//
// settings.dnsSettings = !dnsArray.isEmpty
// ? NEDNSSettings(servers: dnsArray)
// : NEDNSSettings(servers: ["1.1.1.1"])
//
// let xrayConfigData = xrayConfig.config.data(using: .utf8)
//
// guard let xrayConfigData else {
// xrayLog(.error, message: "Can't encode config to data")
// completionHandler(XrayErrors.xrayConfigIsWrong)
// return
// }
//
// let jsonDict = try JSONSerialization.jsonObject(with: xrayConfigData,
// options: []) as? [String: Any]
//
// guard var jsonDict else {
// xrayLog(.error, message: "Can't parse address and port for hevSocks")
// completionHandler(XrayErrors.cantParseListenAndPort)
// return
// }
//
// let port = 10808
// let address = "::1"
//
// if var inboundsArray = jsonDict["inbounds"] as? [[String: Any]], !inboundsArray.isEmpty {
// inboundsArray[0]["port"] = port
// inboundsArray[0]["listen"] = address
// jsonDict["inbounds"] = inboundsArray
// }
//
// let updatedData = try JSONSerialization.data(withJSONObject: jsonDict, options: [])
//
// setTunnelNetworkSettings(settings) { [weak self] error in
// if let error {
// completionHandler(error)
// return
// }
//
// // Launch xray
// self?.setupAndStartXray(configData: updatedData) { xrayError in
// if let xrayError {
// completionHandler(xrayError)
// return
// }
//
// // Launch hevSocks
// self?.setupAndRunTun2socks(configData: updatedData,
// address: address,
// port: port,
// completionHandler: completionHandler)
// }
// }
// } catch {
// completionHandler(error)
// return
// }
// }
//
// func stopXray(completionHandler: () -> Void) {
// Socks5Tunnel.quit()
// LibXrayStopXray()
// completionHandler()
// }
//
// private func setupAndStartXray(configData: Data,
// completionHandler: @escaping (Error?) -> Void) {
// let path = Constants.cachesDirectory.appendingPathComponent("config.json", isDirectory: false).path
// guard FileManager.default.createFile(atPath: path, contents: configData) else {
// xrayLog(.error, message: "Can't save xray configuration")
// completionHandler(XrayErrors.cantSaveXrayConfig)
// return
// }
//
// LibXrayRunXray(nil,
// path,
// Int64.max)
//
// completionHandler(nil)
// xrayLog(.info, message: "Xray started")
// }
//
// private func setupAndRunTun2socks(configData: Data,
// address: String,
// port: Int,
// completionHandler: @escaping (Error?) -> Void) {
// let config = """
// tunnel:
// mtu: 9000
// socks5:
// port: \(port)
// address: \(address)
// udp: 'udp'
// misc:
// task-stack-size: 20480
// connect-timeout: 5000
// read-write-timeout: 60000
// log-file: stderr
// log-level: error
// limit-nofile: 65535
// """
//
// let configurationFilePath = Constants.cachesDirectory.appendingPathComponent("config.yml", isDirectory: false).path
// guard FileManager.default.createFile(atPath: configurationFilePath, contents: config.data(using: .utf8)!) else {
// xrayLog(.info, message: "Cant save hevSocks configuration")
// completionHandler(XrayErrors.cantSaveHevSocksConfig)
// return
// }
//
// DispatchQueue.global().async {
// xrayLog(.info, message: "Hev socks started")
// completionHandler(nil)
// Socks5Tunnel.run(withConfig: configurationFilePath)
// }
// }
//}
import Foundation
import NetworkExtension
import WireGuardKitGo
enum XrayErrors: Error {
case noXrayConfig
case cantSaveXrayConfig
case cantParseListenAndPort
case cantSaveHevSocksConfig
}
extension Constants {
static let cachesDirectory: URL = {
if let cachesDirectoryURL = FileManager.default.urls(for: .cachesDirectory,
in: .userDomainMask).first {
return cachesDirectoryURL
} else {
fatalError("Unable to retrieve caches directory.")
}
}()
}
extension PacketTunnelProvider {
func startXray(completionHandler: @escaping (Error?) -> Void) {
// Xray configuration
guard let protocolConfiguration = self.protocolConfiguration as? NETunnelProviderProtocol,
let providerConfiguration = protocolConfiguration.providerConfiguration,
let xrayConfigData = providerConfiguration[Constants.xrayConfigKey] as? Data else {
xrayLog(.error, message: "Can't get xray configuration")
completionHandler(XrayErrors.noXrayConfig)
return
}
// Tunnel settings
let ipv6Enabled = true
let hideVPNIcon = false
let settings = NEPacketTunnelNetworkSettings(tunnelRemoteAddress: "254.1.1.1")
settings.mtu = 9000
settings.ipv4Settings = {
let settings = NEIPv4Settings(addresses: ["198.18.0.1"], subnetMasks: ["255.255.0.0"])
settings.includedRoutes = [NEIPv4Route.default()]
return settings
}()
settings.ipv6Settings = {
guard ipv6Enabled else {
return nil
}
let settings = NEIPv6Settings(addresses: ["fd6e:a81b:704f:1211::1"], networkPrefixLengths: [64])
settings.includedRoutes = [NEIPv6Route.default()]
if hideVPNIcon {
settings.excludedRoutes = [NEIPv6Route(destinationAddress: "::", networkPrefixLength: 128)]
}
return settings
}()
let dns = ["8.8.4.4","1.1.1.1"]
settings.dnsSettings = NEDNSSettings(servers: dns)
do {
let port = 10808
let address = "::1"
let jsonDict = try JSONSerialization.jsonObject(with: xrayConfigData,
options: []) as? [String: Any]
guard var jsonDict else {
xrayLog(.error, message: "Can't parse address and port for hevSocks")
completionHandler(XrayErrors.cantParseListenAndPort)
return
}
if var inboundsArray = jsonDict["inbounds"] as? [[String: Any]], !inboundsArray.isEmpty {
inboundsArray[0]["port"] = port
inboundsArray[0]["listen"] = address
jsonDict["inbounds"] = inboundsArray
}
let updatedData = try JSONSerialization.data(withJSONObject: jsonDict, options: [])
setTunnelNetworkSettings(settings) { [weak self] error in
if let error {
completionHandler(error)
return
}
// Launch xray
self?.setupAndStartXray(configData: updatedData) { xrayError in
if let xrayError {
completionHandler(xrayError)
return
}
// Launch hevSocks
self?.setupAndRunTun2socks(configData: updatedData,
address: address,
port: port,
completionHandler: completionHandler)
}
}
} catch {
completionHandler(error)
return
}
}
func stopXray(completionHandler: () -> Void) {
Socks5Tunnel.quit()
LibXrayStopXray()
completionHandler()
}
private func setupAndStartXray(configData: Data,
completionHandler: @escaping (Error?) -> Void) {
let path = Constants.cachesDirectory.appendingPathComponent("config.json", isDirectory: false).path
guard FileManager.default.createFile(atPath: path, contents: configData) else {
xrayLog(.error, message: "Can't save xray configuration")
completionHandler(XrayErrors.cantSaveXrayConfig)
return
}
LibXrayRunXray(nil,
path,
Int64.max)
completionHandler(nil)
xrayLog(.info, message: "Xray started")
}
private func setupAndRunTun2socks(configData: Data,
address: String,
port: Int,
completionHandler: @escaping (Error?) -> Void) {
let config = """
tunnel:
mtu: 9000
socks5:
port: \(port)
address: \(address)
udp: 'udp'
misc:
task-stack-size: 20480
connect-timeout: 5000
read-write-timeout: 60000
log-file: stderr
log-level: error
limit-nofile: 65535
"""
let configurationFilePath = Constants.cachesDirectory.appendingPathComponent("config.yml", isDirectory: false).path
guard FileManager.default.createFile(atPath: configurationFilePath, contents: config.data(using: .utf8)!) else {
xrayLog(.info, message: "Cant save hevSocks configuration")
completionHandler(XrayErrors.cantSaveHevSocksConfig)
return
}
DispatchQueue.global().async {
xrayLog(.info, message: "Hev socks started")
completionHandler(nil)
Socks5Tunnel.run(withConfig: configurationFilePath)
}
}
}