-
Notifications
You must be signed in to change notification settings - Fork 420
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Showing
10 changed files
with
285 additions
and
3 deletions.
There are no files selected for viewing
Submodule 3rd-prebuilt
updated
12 files
Submodule amneziawg-apple
updated
135 files
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
import HevSocks5Tunnel | ||
|
||
public enum Socks5Tunnel { | ||
|
||
private static var tunnelFileDescriptor: Int32? { | ||
var ctlInfo = ctl_info() | ||
withUnsafeMutablePointer(to: &ctlInfo.ctl_name) { | ||
$0.withMemoryRebound(to: CChar.self, capacity: MemoryLayout.size(ofValue: $0.pointee)) { | ||
_ = strcpy($0, "com.apple.net.utun_control") | ||
} | ||
} | ||
for fd: Int32 in 0...1024 { | ||
var addr = sockaddr_ctl() | ||
var ret: Int32 = -1 | ||
var len = socklen_t(MemoryLayout.size(ofValue: addr)) | ||
withUnsafeMutablePointer(to: &addr) { | ||
$0.withMemoryRebound(to: sockaddr.self, capacity: 1) { | ||
ret = getpeername(fd, $0, &len) | ||
} | ||
} | ||
if ret != 0 || addr.sc_family != AF_SYSTEM { | ||
continue | ||
} | ||
if ctlInfo.ctl_id == 0 { | ||
ret = ioctl(fd, CTLIOCGINFO, &ctlInfo) | ||
if ret != 0 { | ||
continue | ||
} | ||
} | ||
if addr.sc_id == ctlInfo.ctl_id { | ||
return fd | ||
} | ||
} | ||
return nil | ||
} | ||
|
||
private static var interfaceName: String? { | ||
guard let tunnelFileDescriptor = self.tunnelFileDescriptor else { | ||
return nil | ||
} | ||
var buffer = [UInt8](repeating: 0, count: Int(IFNAMSIZ)) | ||
return buffer.withUnsafeMutableBufferPointer { mutableBufferPointer in | ||
guard let baseAddress = mutableBufferPointer.baseAddress else { | ||
return nil | ||
} | ||
var ifnameSize = socklen_t(IFNAMSIZ) | ||
let result = getsockopt( | ||
tunnelFileDescriptor, | ||
2 /* SYSPROTO_CONTROL */, | ||
2 /* UTUN_OPT_IFNAME */, | ||
baseAddress, | ||
&ifnameSize | ||
) | ||
if result == 0 { | ||
return String(cString: baseAddress) | ||
} else { | ||
return nil | ||
} | ||
} | ||
} | ||
|
||
@discardableResult | ||
public static func run(withConfig filePath: String) -> Int32 { | ||
guard let fileDescriptor = self.tunnelFileDescriptor else { | ||
fatalError("Get tunnel file descriptor failed.") | ||
} | ||
return hev_socks5_tunnel_main(filePath.cString(using: .utf8), fileDescriptor) | ||
} | ||
|
||
public static func quit() { | ||
hev_socks5_tunnel_quit() | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,159 @@ | ||
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) | ||
|
||
setTunnelNetworkSettings(settings) { [weak self] error in | ||
if let error { | ||
completionHandler(error) | ||
return | ||
} | ||
|
||
// Launch xray | ||
self?.setupAndStartXray(configData: xrayConfigData) { xrayError in | ||
if let xrayError { | ||
completionHandler(xrayError) | ||
return | ||
} | ||
|
||
// Launch hevSocks | ||
self?.setupAndRunTun2socks(configData: xrayConfigData, | ||
completionHandler: completionHandler) | ||
} | ||
} | ||
} | ||
|
||
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, | ||
completionHandler: @escaping (Error?) -> Void) { | ||
var port = 10808 | ||
var address = "::1" | ||
|
||
let jsonDict = try? JSONSerialization.jsonObject(with: configData, options: []) as? [String: Any] | ||
|
||
guard let jsonDict else { | ||
xrayLog(.error, message: "Can't parse address and port for hevSocks") | ||
completionHandler(XrayErrors.cantParseListenAndPort) | ||
return | ||
} | ||
|
||
// Xray listen and port should be the same as port and address in hevSocks | ||
if let inbounds = jsonDict["inbounds"] as? [[String: Any]], let inbound = inbounds.first { | ||
if let listen = inbound["listen"] as? String { | ||
address = listen | ||
address.removeAll { $0 == "[" || $0 == "]" } | ||
} | ||
if let portFromConfig = inbound["port"] as? Int { | ||
port = portFromConfig | ||
} | ||
} | ||
|
||
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) | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.