簡體   English   中英

使用 UTLS 和 HTTP 1.1 請求時通過代理連接

[英]Connect via Proxy while using UTLS and HTTP 1.1 Request

我正在嘗試使用隨機 TLS 指紋連接到主機。 我正在使用https://github.com/refraction-networking/utls (請參閱我在https://github.com/refraction-networking/utls/issues/42 上創建的問題)

我現在的問題是,如何在打開該連接時使用 HTTP 或 SOCKS5 代理?

我現在使用的代碼是:

package main

import (
    "bufio"
    "fmt"
    "log"
    "net"
    "net/http"
    "net/http/httputil"
    "net/url"
    "time"

    "github.com/refraction-networking/utls"
)


var (
    dialTimeout   = time.Duration(15) * time.Second
)

var requestHostname = "google.com"
var requestAddr = "172.217.22.110:443"


// this example generates a randomized fingeprint, then re-uses it in a follow-up connection
func HttpGetConsistentRandomized(hostname string, addr , uri string) (*http.Response, error) {
    config := tls.Config{ServerName: hostname}
    tcpConn, err := net.DialTimeout("tcp", addr, dialTimeout)
    if err != nil {
        return nil, fmt.Errorf("net.DialTimeout error: %+v", err)
    }
    uTlsConn := tls.UClient(tcpConn, &config, tls.HelloRandomized)
    defer uTlsConn.Close()
    err = uTlsConn.Handshake()
    if err != nil {
        return nil, fmt.Errorf("uTlsConn.Handshake() error: %+v", err)
    }
    uTlsConn.Close()

    // At this point uTlsConn.ClientHelloID holds a seed that was used to generate
    // randomized fingerprint. Now we can establish second connection with same fp
    tcpConn2, err := net.DialTimeout("tcp", addr, dialTimeout)
    if err != nil {
        return nil, fmt.Errorf("net.DialTimeout error: %+v", err)
    }
    uTlsConn2 := tls.UClient(tcpConn2, &config, uTlsConn.ClientHelloID)
    defer uTlsConn2.Close()
    err = uTlsConn2.Handshake()
    if err != nil {
        return nil, fmt.Errorf("uTlsConn.Handshake() error: %+v", err)
    }

    return httpGetOverConn(uTlsConn2, uTlsConn2.HandshakeState.ServerHello.AlpnProtocol, uri)
}

func main() {
    var response *http.Response
    var err error

    response, err = HttpGetConsistentRandomized(requestHostname, requestAddr, "/2.0/ssocookie")
    if err != nil {
        fmt.Printf("#> HttpGetConsistentRandomized() failed: %+v\n", err)
    } else {
        //fmt.Printf("#> HttpGetConsistentRandomized() response: %+s\n", httputil.DumpResponse(response,true))
        dump, err := httputil.DumpResponse(response, true)
        if err != nil {
            log.Fatal(err)
        }

        fmt.Printf("%+s\n", dump)
    }
    return
}

func httpGetOverConn(conn net.Conn, alpn string, uri string) (*http.Response, error) {

    req := &http.Request{
        Method: "GET",
        URL:    &url.URL{Host: "www." + requestHostname  + uri},
        Header: make(http.Header),
        Host:   "www." + requestHostname,
    }

        req.Proto = "HTTP/1.1"
        req.ProtoMajor = 1
        req.ProtoMinor = 1

        err := req.Write(conn)
        if err != nil {
            return nil, err
        }
        return http.ReadResponse(bufio.NewReader(conn), req)
}

正如 Steffen 所說,你必須先創建一個代理撥號器,撥號代理創建一個 net.Conn,然后在創建 uTLS 客戶端時使用該 net.Conn,然后再握手。 為簡潔起見,您的自定義 dialTLS 函數如下所示:

import (
    "crypto/tls"
    "net"
    "net/url"    

    "github.com/magisterquis/connectproxy"
    "golang.org/x/net/proxy"
    utls "github.com/refraction-networking/utls"
)

var proxyString = "http://127.0.0.1:8080"
                                                                          
dialTLS := func(network, addr string, _ *tls.Config) (net.Conn, error) {
    proxyURI, _ := url.Parse(proxyString)

    switch proxyURI.Scheme {                                                       
    case "socks5":                                                                 
            proxyDialer, err = proxy.SOCKS5("tcp", proxyString, nil, proxy.Direct)
    case "http":                                                          
            proxyDialer, err = connectproxy.New(proxyURI, proxy.Direct)            
    }   

    conn, err := proxyDialer.Dial("tcp", addr)
    uconn := utls.UClient(conn, cfg, &utls.HelloRandomizedALPN) 

    ...
} 

兩個建議:

  1. 如果您打算通過 HTTP CONNECT 代理進行隧道傳輸,請使用上面引用的“connectproxy”模塊。
  2. 讓自己的生活更輕松,看看 Tor 的Meek 可插拔傳輸源 有一個“utls.go”模塊可以為您處理所有事情,包括根據協商的 ALPN 協議設置 http 或 http2 傳輸。 它僅支持 SOCKS,但您可以輕松調整它以處理 HTTP 代理。

HTTP 代理和 SOCKS 代理在 TCP 連接后進行一些初始代理特定的握手。 握手完成后,它們提供一個普通的 TCP 套接字,然后可用於進行 TLS 握手等。因此,您只需要替換您的

tcpConn, err := net.DialTimeout("tcp", addr, dialTimeout)

使用代理特定的方法來設置 TCP 連接。 這可以通過在x/net/proxy使用SOCKS5創建適當的 Dialer 或使用 HTTP CONNECT 方法在connectproxy 中完成的類似方法來完成。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM