通过SOCKS代理通过TcpClient / Sockets连接到HTTPS URL时是否需要CONNECT请求?

时间:2019-01-28 02:37:35

标签: .net proxy tcpclient webrequest socks

我正在尝试通过TcpClient通过SOCKS5代理连接到www.google.com:443,但是对于为什么我的CONNECT请求在被代理挂起时感到困惑。在通过SOCKS5代理连接之前,下面提供的代码可以正常工作(如果使用常规HTTP代理,则可以正常工作)。

Public Sub SocksProxyTest(proxy As String, proxyPort As String)
    Const host As String = "www.google.com"
    Const hostPort As Integer = 443

    Dim buffer As Byte() = New Byte(2047) {}
    Dim bytes As Integer
    Dim client As TcpClient = New TcpClient(proxy, proxyPort)

    Dim stream As NetworkStream = client.GetStream()

    Debug.Print("negotiating socks5 connection")
    Using br = New BinaryReader(stream, Encoding.[Default], True) 
        Dim ip = Dns.GetHostAddresses(host)(0)

        Dim auth As Byte() = New Byte() {&H5, &H1, &H0}
        Debug.Print(">> " & String.Join(" ", auth.Select(Function(b) "&H" & b.ToString("X2"))))
        stream.Write(auth, 0, auth.Length)

        Dim result As Byte() = br.ReadBytes(2)
        Debug.Print("<< &H" & result(1).ToString("X2"))

        Dim data As Byte() = {&H5, &H1, &H0, &H1, &H0, &H0, &H0, &H0, get_port_bytes(hostPort)(0), get_port_bytes(hostPort)(1)}
        For i As Integer = 0 To 4 - 1
            data(i + 4) = ip.GetAddressBytes()(i)
        Next
        Debug.Print(">> " & String.Join(" ", data.Select(Function(b) "&H" & b.ToString("X2"))))

        stream.Write(data, 0, data.Length)
        stream.Flush()

        result = br.ReadBytes(10)
        Debug.Print("<< &H" & result(1).ToString("X2"))

        br.Close()
    End Using
    Debug.Print("negotiated socks5 connection")

    Debug.Print("sending tunnel request")
    Dim tunnelRequest As Byte() = Encoding.UTF8.GetBytes(String.Format("CONNECT {0}:{1}  HTTP/1.1{2}Host: {0}{2}{2}", host, hostPort, vbCrLf))
    stream.Write(tunnelRequest, 0, tunnelRequest.Length)
    stream.Flush()

    bytes = stream.Read(buffer, 0, buffer.Length)
    Console.Write(Encoding.UTF8.GetString(buffer, 0, bytes))

    Dim sslStream As SslStream = New SslStream(stream)
    sslStream.AuthenticateAsClient(host)

    Debug.Print("sending web request")
    Dim request As Byte() = Encoding.UTF8.GetBytes(String.Format("GET https://{0}/  HTTP/1.1" & vbCrLf & "Host: {0}" & vbCrLf & vbCrLf, host))
    sslStream.Write(request, 0, request.Length)
    sslStream.Flush()

    Do
        bytes = sslStream.Read(buffer, 0, buffer.Length)
        Debug.Print(Encoding.UTF8.GetString(buffer, 0, bytes))
    Loop While bytes <> 0

    client.Close()
End Sub

1 个答案:

答案 0 :(得分:0)

您为什么要发送CONNECT请求?该动词仅在通过HTTP代理连接时使用,而在通过SOCKS代理连接时使用。

由于您没有将SOCKS代理连接到HTTP代理,因此完全摆脱了CONNECT请求,因此它不属于这里。只需让SOCKS代理直接连接到目标主机即可(FYI,在SOCKS v4a和v5中,您可以并且应该将目标主机名发送到代理,并让它为您解析IP,DON “请自己解决,否则您可能会得到错误的IP,甚至遇到解析失败的情况。”

一旦代理服务器连接到目标主机,就可以根据需要与目标主机正常通信,就像您已经直接连接到目标主机一样。

请尝试以下类似操作:

Public Sub SocksProxyTest(proxy As String, proxyPort As String)
    Const host As String = "www.google.com"
    Const hostPort As Integer = 443

    Dim buffer As Byte() = New Byte(2047) {}
    Dim bytes As Integer
    Dim client As TcpClient = New TcpClient(proxy, proxyPort)

    Dim stream As NetworkStream = client.GetStream()

    Debug.Print("negotiating socks5 connection")
    Using br = New BinaryReader(stream, Encoding.[Default], True)
        Dim auth As Byte() = New Byte() {&H5, &H1, &H0}
        Debug.Print(">> " & String.Join(" ", auth.Select(Function(b) "&H" & b.ToString("X2"))))
        stream.Write(auth, 0, auth.Length)

        Dim result As Byte() = br.ReadBytes(2)
        Debug.Print("<< &H" & result(1).ToString("X2"))

        If result(1) <> &H0 Then
            client.Close()
            Exit Sub
        End If

        Dim host_bytes As Byte() = Encoding.ASCII.GetBytes(host)
        Dim port_bytes As Byte() = get_port_bytes(hostPort)

        Dim data As Byte() = New Byte(7 + host_bytes.Length) {}
        data(0) = &H5
        data(1) = &H1
        data(2) = &H0
        data(3) = &H3
        data(4) = CByte(host_bytes.Length)
        host_bytes.CopyTo(data, 5)
        port_bytes.CopyTo(data, 5 + host_bytes.Length)
        Debug.Print(">> " & String.Join(" ", data.Select(Function(b) "&H" & b.ToString("X2"))))

        stream.Write(data, 0, data.Length)
        stream.Flush()

        result = br.ReadBytes(4)
        Debug.Print("<< &H" & result(1).ToString("X2"))

        If result(1) <> &H0 Then
            client.Close()
            Exit Sub
        End If

        Select result(3)
            Case &H1
                br.ReadBytes(4)
            Case &H3
                br.ReadBytes(br.ReadByte())
            Case &H4
                br.ReadBytes(16)
        End Select
        br.ReadBytes(2)

        br.Close()
    End Using
    Debug.Print("negotiated socks5 connection")

    Dim sslStream As SslStream = New SslStream(stream)
    sslStream.AuthenticateAsClient(host)

    Debug.Print("sending web request")
    Dim request As Byte() = Encoding.UTF8.GetBytes(String.Format("GET / HTTP/1.1" & vbCrLf & "Host: {0}" & vbCrLf & "Connection: close" & vbCrLf & vbCrLf, host))
    sslStream.Write(request, 0, request.Length)
    sslStream.Flush()

    Do
        bytes = sslStream.Read(buffer, 0, buffer.Length)
        Debug.Print(Encoding.UTF8.GetString(buffer, 0, bytes))
    Loop While bytes <> 0

    client.Close()
End Sub