use uTLS to parrot TLS handshake

Let's try to wrap the TLS library used by the standard http client with uTLS. The goal is to avoid having a very distinctive tls signature during the initial handshake, since this can be very easily detected (and blocked).

We are going to use https://github.com/refraction-networking/utls

First, have a look at the examples - we can use Roller (but we want to reuse the roller).

For that, we can use a custom DialTLSContext, see: https://pkg.go.dev/net/http#Transport.DialTLSContext

So, we identify the point in which we instantiate the http client in bonafide: https://0xacab.org/leap/bitmask-vpn/-/blob/main/pkg/vpn/bonafide/bonafide.go#L102

And in there we create a function that returns the wrapped net.Conn and any error. inside that func we pass the uTLS client:

client := &http.Client{
    Jar: cookieJar,
    Transport: &http.Transport{
        DialTLSContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
            // Note that hardcoding the address is not necessary here. Only
            // do that if you want to ignore the DNS lookup that already
            // happened behind the scenes.

            tcpConn, err := (&net.Dialer{}).DialContext(ctx, network, addr) 
            if err != nil {
                return nil, err
            }
            config := tls.Config{ServerName: "www.stackoverflow.com"}
            tlsConn := tls.UClient(tcpConn, &config, tls.HelloChrome_Auto)

            err = tlsConn.Handshake()
            if err != nil {
                return nil, fmt.Errorf("uTlsConn.Handshake() error: %w", err)
            }

            return tlsConn, nil
        },
    },
}
Edited by atanarjuat tfr