Требуется ли запрос CONNECT при подключении к URL-адресу HTTPS через TcpClient / Sockets через прокси-сервер SOCKS? - PullRequest
0 голосов
/ 28 января 2019

Я пытаюсь подключиться к www.google.com:443 через прокси SOCKS5 через TcpClient, но не понимаю, почему мой запрос 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 голосов
/ 30 января 2019

Почему вы вообще отправляете запрос CONNECT?Этот глагол используется только при подключении через прокси-сервер HTTP, но вместо этого вы подключаетесь через прокси-сервер SOCKS.

Поскольку вы не подключаете прокси-сервер SOCKS к прокси-серверу HTTP, полностью избавьтесь от запроса CONNECT, это не принадлежит здесь.Просто попросите, чтобы прокси-сервер SOCKS подключился напрямую к целевому хосту (и к вашему сведению, в 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
...