enable utls for websteps (#442)
This diff enables `websteps` to use uTLS for TLS parroting. It integrates the `oohttp.StdlibTransport` wrapper which uses the `ooni/oohttp` fork. `oohttp` supports TLS-like connections like `utls.Conn`. As a prototype, the testhelper and `websteps` code now uses the `utls.HelloChrome_Auto` fingerprint, i.e. the simulated TLS fingerprint of the Google Chrome browser. It is a further contribution for my GSoC project. Reference issue: https://github.com/ooni/probe/issues/1733
This commit is contained in:
@@ -9,9 +9,9 @@ import (
|
||||
"net/url"
|
||||
"sync"
|
||||
|
||||
"github.com/apex/log"
|
||||
"github.com/lucas-clemente/quic-go"
|
||||
"github.com/lucas-clemente/quic-go/http3"
|
||||
oohttp "github.com/ooni/oohttp"
|
||||
"github.com/ooni/probe-cli/v3/internal/engine/netx/quicdialer"
|
||||
"github.com/ooni/probe-cli/v3/internal/errorsx"
|
||||
"github.com/ooni/probe-cli/v3/internal/netxlite"
|
||||
@@ -53,8 +53,8 @@ func NewQUICDialerResolver(resolver netxlite.Resolver) netxlite.QUICContextDiale
|
||||
return dialer
|
||||
}
|
||||
|
||||
// NewSingleH3Transport creates an http3.RoundTripper
|
||||
func NewSingleH3Transport(qsess quic.EarlySession, tlscfg *tls.Config, qcfg *quic.Config) *http3.RoundTripper {
|
||||
// NewSingleH3Transport creates an http3.RoundTripper.
|
||||
func NewSingleH3Transport(qsess quic.EarlySession, tlscfg *tls.Config, qcfg *quic.Config) http.RoundTripper {
|
||||
transport := &http3.RoundTripper{
|
||||
DisableCompression: true,
|
||||
TLSClientConfig: tlscfg,
|
||||
@@ -64,16 +64,33 @@ func NewSingleH3Transport(qsess quic.EarlySession, tlscfg *tls.Config, qcfg *qui
|
||||
return transport
|
||||
}
|
||||
|
||||
// NewSingleTransport determines the appropriate HTTP Transport from the ALPN
|
||||
func NewSingleTransport(conn net.Conn) (transport http.RoundTripper) {
|
||||
// NewSingleTransport creates a new HTTP transport with a single-use dialer.
|
||||
func NewSingleTransport(conn net.Conn) http.RoundTripper {
|
||||
singledialer := &SingleDialer{conn: &conn}
|
||||
transport = http.DefaultTransport.(*http.Transport).Clone()
|
||||
transport.(*http.Transport).DialContext = singledialer.DialContext
|
||||
transport.(*http.Transport).DialTLSContext = singledialer.DialContext
|
||||
transport.(*http.Transport).DisableCompression = true
|
||||
transport.(*http.Transport).MaxConnsPerHost = 1
|
||||
transport := newBaseTransport()
|
||||
transport.DialContext = singledialer.DialContext
|
||||
transport.DialTLSContext = singledialer.DialContext
|
||||
return transport
|
||||
}
|
||||
|
||||
transport = &netxlite.HTTPTransportLogger{Logger: log.Log, HTTPTransport: transport.(*http.Transport)}
|
||||
// NewSingleTransport creates a new HTTP transport with a custom dialer and handshaker.
|
||||
func NewTransportWithDialer(dialer netxlite.Dialer, tlsConfig *tls.Config, handshaker netxlite.TLSHandshaker) http.RoundTripper {
|
||||
transport := newBaseTransport()
|
||||
transport.DialContext = dialer.DialContext
|
||||
transport.DialTLSContext = (&netxlite.TLSDialer{
|
||||
Config: tlsConfig,
|
||||
Dialer: dialer,
|
||||
TLSHandshaker: handshaker,
|
||||
}).DialTLSContext
|
||||
return transport
|
||||
}
|
||||
|
||||
// newBaseTransport creates a new HTTP transport with the default dialer.
|
||||
func newBaseTransport() (transport *oohttp.StdlibTransport) {
|
||||
base := oohttp.DefaultTransport.(*oohttp.Transport).Clone()
|
||||
base.DisableCompression = true
|
||||
base.MaxConnsPerHost = 1
|
||||
transport = &oohttp.StdlibTransport{Transport: base}
|
||||
return transport
|
||||
}
|
||||
|
||||
|
||||
@@ -1,16 +1,23 @@
|
||||
package websteps
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"net"
|
||||
|
||||
"github.com/ooni/probe-cli/v3/internal/netxlite"
|
||||
utls "gitlab.com/yawning/utls.git"
|
||||
)
|
||||
|
||||
// TLSDo performs the TLS check.
|
||||
func TLSDo(conn net.Conn, hostname string) (*tls.Conn, error) {
|
||||
tlsConn := tls.Client(conn, &tls.Config{
|
||||
func TLSDo(ctx context.Context, conn net.Conn, hostname string) (net.Conn, error) {
|
||||
tlsConf := &tls.Config{
|
||||
ServerName: hostname,
|
||||
NextProtos: []string{"h2", "http/1.1"},
|
||||
})
|
||||
err := tlsConn.Handshake()
|
||||
}
|
||||
h := &netxlite.TLSHandshakerConfigurable{
|
||||
NewConn: netxlite.NewConnUTLS(&utls.HelloChrome_Auto),
|
||||
}
|
||||
tlsConn, _, err := h.Handshake(ctx, conn, tlsConf)
|
||||
return tlsConn, err
|
||||
}
|
||||
|
||||
@@ -241,7 +241,7 @@ func (m *Measurer) measureEndpointHTTPS(ctx context.Context, URL *url.URL, endpo
|
||||
defer conn.Close()
|
||||
|
||||
// TLS handshake step
|
||||
tlsconn, err := TLSDo(conn, URL.Hostname())
|
||||
tlsconn, err := TLSDo(ctx, conn, URL.Hostname())
|
||||
endpointMeasurement.TLSHandshake = &TLSHandshakeMeasurement{
|
||||
Failure: archival.NewFailure(err),
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user