在 Swift 中测量绕过socks5代理的服务器阵列的 ping

问题描述 投票:0回答:1

使用 xRay VPN 核心 (LibXray)。连接到 VPN 时尝试 ping 我的代理服务器列表。需要绕过 VPN 检查从设备到 IP 地址的 tcp ping(就像未连接一样)。

在 xRayConfiguration 中制定直接路由规则,仅根据 ping 需求进行连接,并在使用套接字测量连接到它时 - 不准确,但我猜它离事实不远了:

import Network

class TCPSocks5Ping {
    //local socks5 proxy 
    private let proxyHost: NWEndpoint.Host
    private let proxyPort: NWEndpoint.Port
    //ping destination server
    private let destinationHost: NWEndpoint.Host
    private let destinationPort: NWEndpoint.Port
    private let queue: DispatchQueue
    private let destinationHostString: String
    
    init(proxyHost: String, proxyPort: UInt16, destinationHost: String, destinationPort: UInt16, queue: DispatchQueue) {
        self.proxyHost = NWEndpoint.Host(proxyHost)
        self.proxyPort = NWEndpoint.Port(integerLiteral: proxyPort)
        self.destinationHost = NWEndpoint.Host(destinationHost)
        self.destinationPort = NWEndpoint.Port(integerLiteral: destinationPort)
        self.destinationHostString = destinationHost
        self.queue = queue
    }

    func ping(completion: @escaping (TimeInterval?, Error?) -> Void) {
        let connection = NWConnection(host: proxyHost, port: proxyPort, using: .tcp)
        
        connection.stateUpdateHandler = { state in
            switch state {
            case .waiting(let error):
                print("Connection: Waiting - \(error.localizedDescription)")
                completion(nil, error)
            case .ready:
                print("Connection: Ready")
                self.socks5Handshake(connection: connection, completion: completion)
            case .failed(let error):
                print("Connection: Failed - \(error.localizedDescription)")
                completion(nil, error)
            default:
                break
            }
        }
        
        connection.start(queue: queue)
    }
    
    private func socks5Handshake(connection: NWConnection, completion: @escaping (TimeInterval?, Error?) -> Void) {
        let socks5InitData = Data([0x05, 0x01, 0x00])  // SOCKS5, 1 method, no authentication
        connection.send(content: socks5InitData, completion: .contentProcessed({ error in
            if let error = error {
                print("SOCKS5 Init Error: \(error.localizedDescription)")
                completion(nil, error)
                return
            }
            connection.receive(minimumIncompleteLength: 2, maximumLength: 2) { data, _, _, error in
                if let error = error {
                    print("SOCKS5 Init Receive Error: \(error.localizedDescription)")
                    completion(nil, error)
                    return
                }
                if let data = data, data.count == 2, data[0] == 0x05, data[1] == 0x00 {
                    print("SOCKS5 Init Successful")
                    self.connectThroughSocks5(connection: connection, completion: completion)
                } else {
                    print("SOCKS5 Init Failed: Invalid response data")
                    completion(nil, NSError(domain: "SOCKS5InitFailed", code: -1, userInfo: nil))
                }
            }
        }))
    }
    
    private func connectThroughSocks5(connection: NWConnection, completion: @escaping (TimeInterval?, Error?) -> Void) {
        let destinationAddress = self.destinationHostString
        guard let destinationAddressData = destinationAddress.data(using: .utf8) else {
            print("Invalid Destination Host")
            completion(nil, NSError(domain: "InvalidDestinationHost", code: -1, userInfo: nil))
            return
        }
        
        var connectData = Data([0x05, 0x01, 0x00, 0x03])  // SOCKS5, CONNECT, reserved, domain name
        connectData.append(UInt8(destinationAddressData.count))  // domain name length
        connectData.append(destinationAddressData)  // domain name
        connectData.append(UInt8(destinationPort.rawValue >> 8))  // port high byte
        connectData.append(UInt8(destinationPort.rawValue & 0xFF))  // port low byte
        
        connection.send(content: connectData, completion: .contentProcessed({ error in
            if let error = error {
                print("SOCKS5 Connect Error: \(error.localizedDescription)")
                completion(nil, error)
                return
            }
            connection.receive(minimumIncompleteLength: 10, maximumLength: 10) { data, _, _, error in
                if let error = error {
                    print("SOCKS5 Connect Receive Error: \(error.localizedDescription)")
                    completion(nil, error)
                    return
                }
                if let data = data, data.count >= 10, data[1] == 0x00 {
                    print("SOCKS5 Connect Successful")
                    self.sendHTTPRequest(final: false, connection: connection, completion: completion)
                } else {
                    print("SOCKS5 Connect Failed: Invalid response data")
                    completion(nil, NSError(domain: "SOCKS5ConnectFailed", code: -1, userInfo: nil))
                }
            }
        }))
    }
    
    private func sendHTTPRequest(final: Bool, connection: NWConnection, completion: @escaping (TimeInterval?, Error?) -> Void) {
        let httpRequest = "HEAD / HTTP /1.1\r\nHost: \(self.destinationHost)\r\nConnection: close\r\n\r\n"
        guard let pingData = httpRequest.data(using: .utf8) else {
            print("Invalid HTTP Request")
            completion(nil, NSError(domain: "InvalidHTTPRequest", code: -1, userInfo: nil))
            return
        }
        
        var startTime: DispatchTime?
        if final {
            startTime = DispatchTime.now()
        }
        
        connection.send(content: pingData, completion: .contentProcessed { error in
            if let error = error {
                print("HTTP Request Send Error: \(error.localizedDescription)")
                completion(nil, error)
                return
            }
            
            connection.receive(minimumIncompleteLength: 1, maximumLength: 1024) { data, _, _, error in
                if final {
                    let endTime = DispatchTime.now()
                    connection.cancel()
                    if let error = error {
                        print("HTTP Request Receive Error: \(error.localizedDescription)")
                        completion(nil, error)
                        return
                    }
                    if let _ = data {
                        guard let startTime else { return }
                        let duration = Double((endTime.uptimeNanoseconds - startTime.uptimeNanoseconds) / 1_000_000)
                        completion(duration, nil)
                    } else {
                        completion(nil, NSError(domain: "HTTPRequestFailed", code: -1, userInfo: nil))
                    }
                } else {
                    self.sendHTTPRequest(final: true, connection: connection, completion: completion)
                }
            }
        })
    }
}

尝试直接连接到 proxyHost 和 proxyPort - 也不起作用。 尝试仅使用“PING”等词发送请求。

我想知道是否有人可以提供帮助,因为我很绝望。

swift ping x-ray socks5
1个回答
0
投票

声明 NWParameters 的实例

let parameters = NWParameters(tls: nil, tcp: .init())

设置首选NoProxies

parameters.preferNoProxies = true

使用参数启动连接

connection = NWConnection(to: endpoint, using: parameters)
© www.soinside.com 2019 - 2024. All rights reserved.