refactor: move tls handshaker to netxlite (#400)

Part of https://github.com/ooni/probe/issues/1505
This commit is contained in:
Simone Basso 2021-06-25 11:07:26 +02:00 committed by GitHub
parent b8428b302f
commit 6b7d270bda
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 182 additions and 172 deletions

View File

@ -56,7 +56,7 @@ func TestWorkingAsIntended(t *testing.T) {
Client: http.DefaultClient, Client: http.DefaultClient,
Dialer: new(net.Dialer), Dialer: new(net.Dialer),
MaxAcceptableBody: 1 << 24, MaxAcceptableBody: 1 << 24,
Resolver: netxlite.ResolverSystem{}, Resolver: &netxlite.ResolverSystem{},
} }
srv := httptest.NewServer(handler) srv := httptest.NewServer(handler)
defer srv.Close() defer srv.Close()

View File

@ -34,8 +34,8 @@ func newDialManager(ndt7URL string, logger model.Logger, userAgent string) dialM
} }
func (mgr dialManager) dialWithTestName(ctx context.Context, testName string) (*websocket.Conn, error) { func (mgr dialManager) dialWithTestName(ctx context.Context, testName string) (*websocket.Conn, error) {
var reso resolver.Resolver = netxlite.ResolverSystem{} var reso resolver.Resolver = &netxlite.ResolverSystem{}
reso = netxlite.ResolverLogger{Resolver: reso, Logger: mgr.logger} reso = &netxlite.ResolverLogger{Resolver: reso, Logger: mgr.logger}
dlr := dialer.New(&dialer.Config{ dlr := dialer.New(&dialer.Config{
ContextByteCounting: true, ContextByteCounting: true,
Logger: mgr.logger, Logger: mgr.logger,

View File

@ -14,6 +14,7 @@ import (
"github.com/ooni/probe-cli/v3/internal/engine/legacy/netx/modelx" "github.com/ooni/probe-cli/v3/internal/engine/legacy/netx/modelx"
"github.com/ooni/probe-cli/v3/internal/engine/netx/dialer" "github.com/ooni/probe-cli/v3/internal/engine/netx/dialer"
"github.com/ooni/probe-cli/v3/internal/engine/netx/tlsdialer" "github.com/ooni/probe-cli/v3/internal/engine/netx/tlsdialer"
"github.com/ooni/probe-cli/v3/internal/netxlite"
) )
// Dialer performs measurements while dialing. // Dialer performs measurements while dialing.
@ -107,9 +108,7 @@ func newTLSDialer(d dialer.Dialer, config *tls.Config) tlsdialer.TLSDialer {
Dialer: d, Dialer: d,
TLSHandshaker: tlsdialer.EmitterTLSHandshaker{ TLSHandshaker: tlsdialer.EmitterTLSHandshaker{
TLSHandshaker: tlsdialer.ErrorWrapperTLSHandshaker{ TLSHandshaker: tlsdialer.ErrorWrapperTLSHandshaker{
TLSHandshaker: tlsdialer.TimeoutTLSHandshaker{ TLSHandshaker: &netxlite.TLSHandshakerStdlib{},
TLSHandshaker: tlsdialer.SystemTLSHandshaker{},
},
}, },
}, },
} }

View File

@ -159,7 +159,7 @@ func resolverWrapTransport(txp resolver.RoundTripper) resolver.EmitterResolver {
} }
func newResolverSystem() resolver.EmitterResolver { func newResolverSystem() resolver.EmitterResolver {
return resolverWrapResolver(netxlite.ResolverSystem{}) return resolverWrapResolver(&netxlite.ResolverSystem{})
} }
func newResolverUDP(dialer resolver.Dialer, address string) resolver.EmitterResolver { func newResolverUDP(dialer resolver.Dialer, address string) resolver.EmitterResolver {

View File

@ -115,7 +115,7 @@ var defaultCertPool *x509.CertPool = tlsx.NewDefaultCertPool()
// NewResolver creates a new resolver from the specified config // NewResolver creates a new resolver from the specified config
func NewResolver(config Config) Resolver { func NewResolver(config Config) Resolver {
if config.BaseResolver == nil { if config.BaseResolver == nil {
config.BaseResolver = netxlite.ResolverSystem{} config.BaseResolver = &netxlite.ResolverSystem{}
} }
var r Resolver = config.BaseResolver var r Resolver = config.BaseResolver
r = resolver.AddressResolver{Resolver: r} r = resolver.AddressResolver{Resolver: r}
@ -134,7 +134,7 @@ func NewResolver(config Config) Resolver {
} }
r = resolver.ErrorWrapperResolver{Resolver: r} r = resolver.ErrorWrapperResolver{Resolver: r}
if config.Logger != nil { if config.Logger != nil {
r = netxlite.ResolverLogger{Logger: config.Logger, Resolver: r} r = &netxlite.ResolverLogger{Logger: config.Logger, Resolver: r}
} }
if config.ResolveSaver != nil { if config.ResolveSaver != nil {
r = resolver.SaverResolver{Resolver: r, Saver: config.ResolveSaver} r = resolver.SaverResolver{Resolver: r, Saver: config.ResolveSaver}
@ -176,8 +176,7 @@ func NewTLSDialer(config Config) TLSDialer {
if config.Dialer == nil { if config.Dialer == nil {
config.Dialer = NewDialer(config) config.Dialer = NewDialer(config)
} }
var h tlsHandshaker = tlsdialer.SystemTLSHandshaker{} var h tlsHandshaker = &netxlite.TLSHandshakerStdlib{}
h = tlsdialer.TimeoutTLSHandshaker{TLSHandshaker: h}
h = tlsdialer.ErrorWrapperTLSHandshaker{TLSHandshaker: h} h = tlsdialer.ErrorWrapperTLSHandshaker{TLSHandshaker: h}
if config.Logger != nil { if config.Logger != nil {
h = tlsdialer.LoggingTLSHandshaker{Logger: config.Logger, TLSHandshaker: h} h = tlsdialer.LoggingTLSHandshaker{Logger: config.Logger, TLSHandshaker: h}
@ -318,7 +317,7 @@ func NewDNSClientWithOverrides(config Config, URL, hostOverride, SNIOverride,
} }
switch resolverURL.Scheme { switch resolverURL.Scheme {
case "system": case "system":
c.Resolver = netxlite.ResolverSystem{} c.Resolver = &netxlite.ResolverSystem{}
return c, nil return c, nil
case "https": case "https":
config.TLSConfig.NextProtos = []string{"h2", "http/1.1"} config.TLSConfig.NextProtos = []string{"h2", "http/1.1"}

View File

@ -32,7 +32,7 @@ func TestNewResolverVanilla(t *testing.T) {
if !ok { if !ok {
t.Fatal("not the resolver we expected") t.Fatal("not the resolver we expected")
} }
_, ok = ar.Resolver.(netxlite.ResolverSystem) _, ok = ar.Resolver.(*netxlite.ResolverSystem)
if !ok { if !ok {
t.Fatal("not the resolver we expected") t.Fatal("not the resolver we expected")
} }
@ -82,7 +82,7 @@ func TestNewResolverWithBogonFilter(t *testing.T) {
if !ok { if !ok {
t.Fatal("not the resolver we expected") t.Fatal("not the resolver we expected")
} }
_, ok = ar.Resolver.(netxlite.ResolverSystem) _, ok = ar.Resolver.(*netxlite.ResolverSystem)
if !ok { if !ok {
t.Fatal("not the resolver we expected") t.Fatal("not the resolver we expected")
} }
@ -96,7 +96,7 @@ func TestNewResolverWithLogging(t *testing.T) {
if !ok { if !ok {
t.Fatal("not the resolver we expected") t.Fatal("not the resolver we expected")
} }
lr, ok := ir.Resolver.(netxlite.ResolverLogger) lr, ok := ir.Resolver.(*netxlite.ResolverLogger)
if !ok { if !ok {
t.Fatal("not the resolver we expected") t.Fatal("not the resolver we expected")
} }
@ -111,7 +111,7 @@ func TestNewResolverWithLogging(t *testing.T) {
if !ok { if !ok {
t.Fatal("not the resolver we expected") t.Fatal("not the resolver we expected")
} }
_, ok = ar.Resolver.(netxlite.ResolverSystem) _, ok = ar.Resolver.(*netxlite.ResolverSystem)
if !ok { if !ok {
t.Fatal("not the resolver we expected") t.Fatal("not the resolver we expected")
} }
@ -141,7 +141,7 @@ func TestNewResolverWithSaver(t *testing.T) {
if !ok { if !ok {
t.Fatal("not the resolver we expected") t.Fatal("not the resolver we expected")
} }
_, ok = ar.Resolver.(netxlite.ResolverSystem) _, ok = ar.Resolver.(*netxlite.ResolverSystem)
if !ok { if !ok {
t.Fatal("not the resolver we expected") t.Fatal("not the resolver we expected")
} }
@ -170,7 +170,7 @@ func TestNewResolverWithReadWriteCache(t *testing.T) {
if !ok { if !ok {
t.Fatal("not the resolver we expected") t.Fatal("not the resolver we expected")
} }
_, ok = ar.Resolver.(netxlite.ResolverSystem) _, ok = ar.Resolver.(*netxlite.ResolverSystem)
if !ok { if !ok {
t.Fatal("not the resolver we expected") t.Fatal("not the resolver we expected")
} }
@ -204,7 +204,7 @@ func TestNewResolverWithPrefilledReadonlyCache(t *testing.T) {
if !ok { if !ok {
t.Fatal("not the resolver we expected") t.Fatal("not the resolver we expected")
} }
_, ok = ar.Resolver.(netxlite.ResolverSystem) _, ok = ar.Resolver.(*netxlite.ResolverSystem)
if !ok { if !ok {
t.Fatal("not the resolver we expected") t.Fatal("not the resolver we expected")
} }
@ -235,11 +235,7 @@ func TestNewTLSDialerVanilla(t *testing.T) {
if !ok { if !ok {
t.Fatal("not the TLSHandshaker we expected") t.Fatal("not the TLSHandshaker we expected")
} }
tth, ok := ewth.TLSHandshaker.(tlsdialer.TimeoutTLSHandshaker) if _, ok := ewth.TLSHandshaker.(*netxlite.TLSHandshakerStdlib); !ok {
if !ok {
t.Fatal("not the TLSHandshaker we expected")
}
if _, ok := tth.TLSHandshaker.(tlsdialer.SystemTLSHandshaker); !ok {
t.Fatal("not the TLSHandshaker we expected") t.Fatal("not the TLSHandshaker we expected")
} }
} }
@ -268,11 +264,7 @@ func TestNewTLSDialerWithConfig(t *testing.T) {
if !ok { if !ok {
t.Fatal("not the TLSHandshaker we expected") t.Fatal("not the TLSHandshaker we expected")
} }
tth, ok := ewth.TLSHandshaker.(tlsdialer.TimeoutTLSHandshaker) if _, ok := ewth.TLSHandshaker.(*netxlite.TLSHandshakerStdlib); !ok {
if !ok {
t.Fatal("not the TLSHandshaker we expected")
}
if _, ok := tth.TLSHandshaker.(tlsdialer.SystemTLSHandshaker); !ok {
t.Fatal("not the TLSHandshaker we expected") t.Fatal("not the TLSHandshaker we expected")
} }
} }
@ -311,11 +303,7 @@ func TestNewTLSDialerWithLogging(t *testing.T) {
if !ok { if !ok {
t.Fatal("not the TLSHandshaker we expected") t.Fatal("not the TLSHandshaker we expected")
} }
tth, ok := ewth.TLSHandshaker.(tlsdialer.TimeoutTLSHandshaker) if _, ok := ewth.TLSHandshaker.(*netxlite.TLSHandshakerStdlib); !ok {
if !ok {
t.Fatal("not the TLSHandshaker we expected")
}
if _, ok := tth.TLSHandshaker.(tlsdialer.SystemTLSHandshaker); !ok {
t.Fatal("not the TLSHandshaker we expected") t.Fatal("not the TLSHandshaker we expected")
} }
} }
@ -355,11 +343,7 @@ func TestNewTLSDialerWithSaver(t *testing.T) {
if !ok { if !ok {
t.Fatal("not the TLSHandshaker we expected") t.Fatal("not the TLSHandshaker we expected")
} }
tth, ok := ewth.TLSHandshaker.(tlsdialer.TimeoutTLSHandshaker) if _, ok := ewth.TLSHandshaker.(*netxlite.TLSHandshakerStdlib); !ok {
if !ok {
t.Fatal("not the TLSHandshaker we expected")
}
if _, ok := tth.TLSHandshaker.(tlsdialer.SystemTLSHandshaker); !ok {
t.Fatal("not the TLSHandshaker we expected") t.Fatal("not the TLSHandshaker we expected")
} }
} }
@ -392,11 +376,7 @@ func TestNewTLSDialerWithNoTLSVerifyAndConfig(t *testing.T) {
if !ok { if !ok {
t.Fatal("not the TLSHandshaker we expected") t.Fatal("not the TLSHandshaker we expected")
} }
tth, ok := ewth.TLSHandshaker.(tlsdialer.TimeoutTLSHandshaker) if _, ok := ewth.TLSHandshaker.(*netxlite.TLSHandshakerStdlib); !ok {
if !ok {
t.Fatal("not the TLSHandshaker we expected")
}
if _, ok := tth.TLSHandshaker.(tlsdialer.SystemTLSHandshaker); !ok {
t.Fatal("not the TLSHandshaker we expected") t.Fatal("not the TLSHandshaker we expected")
} }
} }
@ -431,11 +411,7 @@ func TestNewTLSDialerWithNoTLSVerifyAndNoConfig(t *testing.T) {
if !ok { if !ok {
t.Fatal("not the TLSHandshaker we expected") t.Fatal("not the TLSHandshaker we expected")
} }
tth, ok := ewth.TLSHandshaker.(tlsdialer.TimeoutTLSHandshaker) if _, ok := ewth.TLSHandshaker.(*netxlite.TLSHandshakerStdlib); !ok {
if !ok {
t.Fatal("not the TLSHandshaker we expected")
}
if _, ok := tth.TLSHandshaker.(tlsdialer.SystemTLSHandshaker); !ok {
t.Fatal("not the TLSHandshaker we expected") t.Fatal("not the TLSHandshaker we expected")
} }
} }
@ -472,7 +448,7 @@ func TestNewWithTLSDialer(t *testing.T) {
tlsDialer := tlsdialer.TLSDialer{ tlsDialer := tlsdialer.TLSDialer{
Config: new(tls.Config), Config: new(tls.Config),
Dialer: netx.FakeDialer{Err: expected}, Dialer: netx.FakeDialer{Err: expected},
TLSHandshaker: tlsdialer.SystemTLSHandshaker{}, TLSHandshaker: &netxlite.TLSHandshakerStdlib{},
} }
txp := netx.NewHTTPTransport(netx.Config{ txp := netx.NewHTTPTransport(netx.Config{
TLSDialer: tlsDialer, TLSDialer: tlsDialer,
@ -598,7 +574,7 @@ func TestNewDNSClientSystemResolver(t *testing.T) {
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
if _, ok := dnsclient.Resolver.(netxlite.ResolverSystem); !ok { if _, ok := dnsclient.Resolver.(*netxlite.ResolverSystem); !ok {
t.Fatal("not the resolver we expected") t.Fatal("not the resolver we expected")
} }
dnsclient.CloseIdleConnections() dnsclient.CloseIdleConnections()
@ -610,7 +586,7 @@ func TestNewDNSClientEmpty(t *testing.T) {
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
if _, ok := dnsclient.Resolver.(netxlite.ResolverSystem); !ok { if _, ok := dnsclient.Resolver.(*netxlite.ResolverSystem); !ok {
t.Fatal("not the resolver we expected") t.Fatal("not the resolver we expected")
} }
dnsclient.CloseIdleConnections() dnsclient.CloseIdleConnections()

View File

@ -11,7 +11,7 @@ import (
func TestChainLookupHost(t *testing.T) { func TestChainLookupHost(t *testing.T) {
r := resolver.ChainResolver{ r := resolver.ChainResolver{
Primary: resolver.NewFakeResolverThatFails(), Primary: resolver.NewFakeResolverThatFails(),
Secondary: netxlite.ResolverSystem{}, Secondary: &netxlite.ResolverSystem{},
} }
if r.Address() != "" { if r.Address() != "" {
t.Fatal("invalid address") t.Fatal("invalid address")

View File

@ -19,7 +19,7 @@ func testresolverquick(t *testing.T, reso resolver.Resolver) {
if testing.Short() { if testing.Short() {
t.Skip("skip test in short mode") t.Skip("skip test in short mode")
} }
reso = netxlite.ResolverLogger{Logger: log.Log, Resolver: reso} reso = &netxlite.ResolverLogger{Logger: log.Log, Resolver: reso}
addrs, err := reso.LookupHost(context.Background(), "dns.google.com") addrs, err := reso.LookupHost(context.Background(), "dns.google.com")
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
@ -45,7 +45,7 @@ func testresolverquickidna(t *testing.T, reso resolver.Resolver) {
t.Skip("skip test in short mode") t.Skip("skip test in short mode")
} }
reso = resolver.IDNAResolver{ reso = resolver.IDNAResolver{
netxlite.ResolverLogger{Logger: log.Log, Resolver: reso}, &netxlite.ResolverLogger{Logger: log.Log, Resolver: reso},
} }
addrs, err := reso.LookupHost(context.Background(), "яндекс.рф") addrs, err := reso.LookupHost(context.Background(), "яндекс.рф")
if err != nil { if err != nil {
@ -57,7 +57,7 @@ func testresolverquickidna(t *testing.T, reso resolver.Resolver) {
} }
func TestNewResolverSystem(t *testing.T) { func TestNewResolverSystem(t *testing.T) {
reso := netxlite.ResolverSystem{} reso := &netxlite.ResolverSystem{}
testresolverquick(t, reso) testresolverquick(t, reso)
testresolverquickidna(t, reso) testresolverquickidna(t, reso)
} }

View File

@ -8,6 +8,7 @@ import (
"github.com/apex/log" "github.com/apex/log"
"github.com/ooni/probe-cli/v3/internal/engine/netx/tlsdialer" "github.com/ooni/probe-cli/v3/internal/engine/netx/tlsdialer"
"github.com/ooni/probe-cli/v3/internal/netxlite"
) )
func TestTLSDialerSuccess(t *testing.T) { func TestTLSDialerSuccess(t *testing.T) {
@ -17,7 +18,7 @@ func TestTLSDialerSuccess(t *testing.T) {
log.SetLevel(log.DebugLevel) log.SetLevel(log.DebugLevel)
dialer := tlsdialer.TLSDialer{Dialer: new(net.Dialer), dialer := tlsdialer.TLSDialer{Dialer: new(net.Dialer),
TLSHandshaker: tlsdialer.LoggingTLSHandshaker{ TLSHandshaker: tlsdialer.LoggingTLSHandshaker{
TLSHandshaker: tlsdialer.SystemTLSHandshaker{}, TLSHandshaker: &netxlite.TLSHandshakerStdlib{},
Logger: log.Log, Logger: log.Log,
}, },
} }

View File

@ -12,6 +12,7 @@ import (
"github.com/ooni/probe-cli/v3/internal/engine/netx/errorx" "github.com/ooni/probe-cli/v3/internal/engine/netx/errorx"
"github.com/ooni/probe-cli/v3/internal/engine/netx/tlsdialer" "github.com/ooni/probe-cli/v3/internal/engine/netx/tlsdialer"
"github.com/ooni/probe-cli/v3/internal/engine/netx/trace" "github.com/ooni/probe-cli/v3/internal/engine/netx/trace"
"github.com/ooni/probe-cli/v3/internal/netxlite"
) )
func TestSaverTLSHandshakerSuccessWithReadWrite(t *testing.T) { func TestSaverTLSHandshakerSuccessWithReadWrite(t *testing.T) {
@ -25,7 +26,7 @@ func TestSaverTLSHandshakerSuccessWithReadWrite(t *testing.T) {
Config: &tls.Config{NextProtos: nextprotos}, Config: &tls.Config{NextProtos: nextprotos},
Dialer: dialer.New(&dialer.Config{ReadWriteSaver: saver}, &net.Resolver{}), Dialer: dialer.New(&dialer.Config{ReadWriteSaver: saver}, &net.Resolver{}),
TLSHandshaker: tlsdialer.SaverTLSHandshaker{ TLSHandshaker: tlsdialer.SaverTLSHandshaker{
TLSHandshaker: tlsdialer.SystemTLSHandshaker{}, TLSHandshaker: &netxlite.TLSHandshakerStdlib{},
Saver: saver, Saver: saver,
}, },
} }
@ -118,7 +119,7 @@ func TestSaverTLSHandshakerSuccess(t *testing.T) {
Config: &tls.Config{NextProtos: nextprotos}, Config: &tls.Config{NextProtos: nextprotos},
Dialer: new(net.Dialer), Dialer: new(net.Dialer),
TLSHandshaker: tlsdialer.SaverTLSHandshaker{ TLSHandshaker: tlsdialer.SaverTLSHandshaker{
TLSHandshaker: tlsdialer.SystemTLSHandshaker{}, TLSHandshaker: &netxlite.TLSHandshakerStdlib{},
Saver: saver, Saver: saver,
}, },
} }
@ -183,7 +184,7 @@ func TestSaverTLSHandshakerHostnameError(t *testing.T) {
tlsdlr := tlsdialer.TLSDialer{ tlsdlr := tlsdialer.TLSDialer{
Dialer: new(net.Dialer), Dialer: new(net.Dialer),
TLSHandshaker: tlsdialer.SaverTLSHandshaker{ TLSHandshaker: tlsdialer.SaverTLSHandshaker{
TLSHandshaker: tlsdialer.SystemTLSHandshaker{}, TLSHandshaker: &netxlite.TLSHandshakerStdlib{},
Saver: saver, Saver: saver,
}, },
} }
@ -216,7 +217,7 @@ func TestSaverTLSHandshakerInvalidCertError(t *testing.T) {
tlsdlr := tlsdialer.TLSDialer{ tlsdlr := tlsdialer.TLSDialer{
Dialer: new(net.Dialer), Dialer: new(net.Dialer),
TLSHandshaker: tlsdialer.SaverTLSHandshaker{ TLSHandshaker: tlsdialer.SaverTLSHandshaker{
TLSHandshaker: tlsdialer.SystemTLSHandshaker{}, TLSHandshaker: &netxlite.TLSHandshakerStdlib{},
Saver: saver, Saver: saver,
}, },
} }
@ -249,7 +250,7 @@ func TestSaverTLSHandshakerAuthorityError(t *testing.T) {
tlsdlr := tlsdialer.TLSDialer{ tlsdlr := tlsdialer.TLSDialer{
Dialer: new(net.Dialer), Dialer: new(net.Dialer),
TLSHandshaker: tlsdialer.SaverTLSHandshaker{ TLSHandshaker: tlsdialer.SaverTLSHandshaker{
TLSHandshaker: tlsdialer.SystemTLSHandshaker{}, TLSHandshaker: &netxlite.TLSHandshakerStdlib{},
Saver: saver, Saver: saver,
}, },
} }
@ -283,7 +284,7 @@ func TestSaverTLSHandshakerNoTLSVerify(t *testing.T) {
Config: &tls.Config{InsecureSkipVerify: true}, Config: &tls.Config{InsecureSkipVerify: true},
Dialer: new(net.Dialer), Dialer: new(net.Dialer),
TLSHandshaker: tlsdialer.SaverTLSHandshaker{ TLSHandshaker: tlsdialer.SaverTLSHandshaker{
TLSHandshaker: tlsdialer.SystemTLSHandshaker{}, TLSHandshaker: &netxlite.TLSHandshakerStdlib{},
Saver: saver, Saver: saver,
}, },
} }

View File

@ -22,42 +22,6 @@ type TLSHandshaker interface {
net.Conn, tls.ConnectionState, error) net.Conn, tls.ConnectionState, error)
} }
// SystemTLSHandshaker is the system TLS handshaker.
type SystemTLSHandshaker struct{}
// Handshake implements Handshaker.Handshake
func (h SystemTLSHandshaker) Handshake(
ctx context.Context, conn net.Conn, config *tls.Config,
) (net.Conn, tls.ConnectionState, error) {
tlsconn := tls.Client(conn, config)
if err := tlsconn.Handshake(); err != nil {
return nil, tls.ConnectionState{}, err
}
return tlsconn, tlsconn.ConnectionState(), nil
}
// TimeoutTLSHandshaker is a TLSHandshaker with timeout
type TimeoutTLSHandshaker struct {
TLSHandshaker
HandshakeTimeout time.Duration // default: 10 second
}
// Handshake implements Handshaker.Handshake
func (h TimeoutTLSHandshaker) Handshake(
ctx context.Context, conn net.Conn, config *tls.Config,
) (net.Conn, tls.ConnectionState, error) {
timeout := 10 * time.Second
if h.HandshakeTimeout != 0 {
timeout = h.HandshakeTimeout
}
if err := conn.SetDeadline(time.Now().Add(timeout)); err != nil {
return nil, tls.ConnectionState{}, err
}
tlsconn, connstate, err := h.TLSHandshaker.Handshake(ctx, conn, config)
conn.SetDeadline(time.Time{})
return tlsconn, connstate, err
}
// ErrorWrapperTLSHandshaker wraps the returned error to be an OONI error // ErrorWrapperTLSHandshaker wraps the returned error to be an OONI error
type ErrorWrapperTLSHandshaker struct { type ErrorWrapperTLSHandshaker struct {
TLSHandshaker TLSHandshaker

View File

@ -13,10 +13,11 @@ import (
"github.com/ooni/probe-cli/v3/internal/engine/legacy/netx/modelx" "github.com/ooni/probe-cli/v3/internal/engine/legacy/netx/modelx"
"github.com/ooni/probe-cli/v3/internal/engine/netx/errorx" "github.com/ooni/probe-cli/v3/internal/engine/netx/errorx"
"github.com/ooni/probe-cli/v3/internal/engine/netx/tlsdialer" "github.com/ooni/probe-cli/v3/internal/engine/netx/tlsdialer"
"github.com/ooni/probe-cli/v3/internal/netxlite"
) )
func TestSystemTLSHandshakerEOFError(t *testing.T) { func TestSystemTLSHandshakerEOFError(t *testing.T) {
h := tlsdialer.SystemTLSHandshaker{} h := &netxlite.TLSHandshakerStdlib{}
conn, _, err := h.Handshake(context.Background(), tlsdialer.EOFConn{}, &tls.Config{ conn, _, err := h.Handshake(context.Background(), tlsdialer.EOFConn{}, &tls.Config{
ServerName: "x.org", ServerName: "x.org",
}) })
@ -28,63 +29,6 @@ func TestSystemTLSHandshakerEOFError(t *testing.T) {
} }
} }
func TestTimeoutTLSHandshakerSetDeadlineError(t *testing.T) {
h := tlsdialer.TimeoutTLSHandshaker{
TLSHandshaker: tlsdialer.SystemTLSHandshaker{},
HandshakeTimeout: 200 * time.Millisecond,
}
expected := errors.New("mocked error")
conn, _, err := h.Handshake(
context.Background(), &tlsdialer.FakeConn{SetDeadlineError: expected},
new(tls.Config))
if !errors.Is(err, expected) {
t.Fatal("not the error that we expected")
}
if conn != nil {
t.Fatal("expected nil con here")
}
}
func TestTimeoutTLSHandshakerEOFError(t *testing.T) {
h := tlsdialer.TimeoutTLSHandshaker{
TLSHandshaker: tlsdialer.SystemTLSHandshaker{},
HandshakeTimeout: 200 * time.Millisecond,
}
conn, _, err := h.Handshake(
context.Background(), tlsdialer.EOFConn{}, &tls.Config{ServerName: "x.org"})
if !errors.Is(err, io.EOF) {
t.Fatal("not the error that we expected")
}
if conn != nil {
t.Fatal("expected nil con here")
}
}
func TestTimeoutTLSHandshakerCallsSetDeadline(t *testing.T) {
h := tlsdialer.TimeoutTLSHandshaker{
TLSHandshaker: tlsdialer.SystemTLSHandshaker{},
HandshakeTimeout: 200 * time.Millisecond,
}
underlying := &SetDeadlineConn{}
conn, _, err := h.Handshake(
context.Background(), underlying, &tls.Config{ServerName: "x.org"})
if !errors.Is(err, io.EOF) {
t.Fatal("not the error that we expected")
}
if conn != nil {
t.Fatal("expected nil con here")
}
if len(underlying.deadlines) != 2 {
t.Fatal("SetDeadline not called twice")
}
if underlying.deadlines[0].Before(time.Now()) {
t.Fatal("the first SetDeadline call was incorrect")
}
if !underlying.deadlines[1].IsZero() {
t.Fatal("the second SetDeadline call was incorrect")
}
}
type SetDeadlineConn struct { type SetDeadlineConn struct {
tlsdialer.EOFConn tlsdialer.EOFConn
deadlines []time.Time deadlines []time.Time
@ -179,7 +123,7 @@ func TestTLSDialerFailureDialing(t *testing.T) {
} }
func TestTLSDialerFailureHandshaking(t *testing.T) { func TestTLSDialerFailureHandshaking(t *testing.T) {
rec := &RecorderTLSHandshaker{TLSHandshaker: tlsdialer.SystemTLSHandshaker{}} rec := &RecorderTLSHandshaker{TLSHandshaker: &netxlite.TLSHandshakerStdlib{}}
dialer := tlsdialer.TLSDialer{ dialer := tlsdialer.TLSDialer{
Dialer: tlsdialer.EOFConnDialer{}, Dialer: tlsdialer.EOFConnDialer{},
TLSHandshaker: rec, TLSHandshaker: rec,
@ -198,7 +142,7 @@ func TestTLSDialerFailureHandshaking(t *testing.T) {
} }
func TestTLSDialerFailureHandshakingOverrideSNI(t *testing.T) { func TestTLSDialerFailureHandshakingOverrideSNI(t *testing.T) {
rec := &RecorderTLSHandshaker{TLSHandshaker: tlsdialer.SystemTLSHandshaker{}} rec := &RecorderTLSHandshaker{TLSHandshaker: &netxlite.TLSHandshakerStdlib{}}
dialer := tlsdialer.TLSDialer{ dialer := tlsdialer.TLSDialer{
Config: &tls.Config{ Config: &tls.Config{
ServerName: "x.org", ServerName: "x.org",
@ -235,7 +179,7 @@ func TestDialTLSContextGood(t *testing.T) {
dialer := tlsdialer.TLSDialer{ dialer := tlsdialer.TLSDialer{
Config: &tls.Config{ServerName: "google.com"}, Config: &tls.Config{ServerName: "google.com"},
Dialer: new(net.Dialer), Dialer: new(net.Dialer),
TLSHandshaker: tlsdialer.SystemTLSHandshaker{}, TLSHandshaker: &netxlite.TLSHandshakerStdlib{},
} }
conn, err := dialer.DialTLSContext(context.Background(), "tcp", "google.com:443") conn, err := dialer.DialTLSContext(context.Background(), "tcp", "google.com:443")
if err != nil { if err != nil {
@ -252,9 +196,8 @@ func TestDialTLSContextTimeout(t *testing.T) {
Config: &tls.Config{ServerName: "google.com"}, Config: &tls.Config{ServerName: "google.com"},
Dialer: new(net.Dialer), Dialer: new(net.Dialer),
TLSHandshaker: tlsdialer.ErrorWrapperTLSHandshaker{ TLSHandshaker: tlsdialer.ErrorWrapperTLSHandshaker{
TLSHandshaker: tlsdialer.TimeoutTLSHandshaker{ TLSHandshaker: &netxlite.TLSHandshakerStdlib{
TLSHandshaker: tlsdialer.SystemTLSHandshaker{}, Timeout: 10 * time.Microsecond,
HandshakeTimeout: 10 * time.Microsecond,
}, },
}, },
} }

View File

@ -15,25 +15,25 @@ type Resolver interface {
// ResolverSystem is the system resolver. // ResolverSystem is the system resolver.
type ResolverSystem struct{} type ResolverSystem struct{}
var _ Resolver = ResolverSystem{} var _ Resolver = &ResolverSystem{}
// LookupHost implements Resolver.LookupHost. // LookupHost implements Resolver.LookupHost.
func (r ResolverSystem) LookupHost(ctx context.Context, hostname string) ([]string, error) { func (r *ResolverSystem) LookupHost(ctx context.Context, hostname string) ([]string, error) {
return net.DefaultResolver.LookupHost(ctx, hostname) return net.DefaultResolver.LookupHost(ctx, hostname)
} }
// Network implements Resolver.Network. // Network implements Resolver.Network.
func (r ResolverSystem) Network() string { func (r *ResolverSystem) Network() string {
return "system" return "system"
} }
// Address implements Resolver.Address. // Address implements Resolver.Address.
func (r ResolverSystem) Address() string { func (r *ResolverSystem) Address() string {
return "" return ""
} }
// DefaultResolver is the resolver we use by default. // DefaultResolver is the resolver we use by default.
var DefaultResolver = ResolverSystem{} var DefaultResolver = &ResolverSystem{}
// ResolverLogger is a resolver that emits events // ResolverLogger is a resolver that emits events
type ResolverLogger struct { type ResolverLogger struct {
@ -41,10 +41,10 @@ type ResolverLogger struct {
Logger Logger Logger Logger
} }
var _ Resolver = ResolverLogger{} var _ Resolver = &ResolverLogger{}
// LookupHost returns the IP addresses of a host // LookupHost returns the IP addresses of a host
func (r ResolverLogger) LookupHost(ctx context.Context, hostname string) ([]string, error) { func (r *ResolverLogger) LookupHost(ctx context.Context, hostname string) ([]string, error) {
r.Logger.Debugf("resolve %s...", hostname) r.Logger.Debugf("resolve %s...", hostname)
start := time.Now() start := time.Now()
addrs, err := r.Resolver.LookupHost(ctx, hostname) addrs, err := r.Resolver.LookupHost(ctx, hostname)
@ -62,7 +62,7 @@ type resolverNetworker interface {
} }
// Network implements Resolver.Network. // Network implements Resolver.Network.
func (r ResolverLogger) Network() string { func (r *ResolverLogger) Network() string {
if rn, ok := r.Resolver.(resolverNetworker); ok { if rn, ok := r.Resolver.(resolverNetworker); ok {
return rn.Network() return rn.Network()
} }
@ -74,7 +74,7 @@ type resolverAddresser interface {
} }
// Address implements Resolver.Address. // Address implements Resolver.Address.
func (r ResolverLogger) Address() string { func (r *ResolverLogger) Address() string {
if ra, ok := r.Resolver.(resolverAddresser); ok { if ra, ok := r.Resolver.(resolverAddresser); ok {
return ra.Address() return ra.Address()
} }

View File

@ -0,0 +1,46 @@
package netxlite
import (
"context"
"crypto/tls"
"net"
"time"
)
// TLSHandshaker is the generic TLS handshaker.
type TLSHandshaker interface {
// Handshake creates a new TLS connection from the given connection and
// the given config. This function DOES NOT take ownership of the connection
// and it's your responsibility to close it on failure.
Handshake(ctx context.Context, conn net.Conn, config *tls.Config) (
net.Conn, tls.ConnectionState, error)
}
// TLSHandshakerStdlib is the stdlib's TLS handshaker.
type TLSHandshakerStdlib struct {
// Timeout is the timeout imposed on the TLS handshake. If zero
// or negative, we will use default timeout of 10 seconds.
Timeout time.Duration
}
var _ TLSHandshaker = &TLSHandshakerStdlib{}
// Handshake implements Handshaker.Handshake
func (h *TLSHandshakerStdlib) Handshake(
ctx context.Context, conn net.Conn, config *tls.Config,
) (net.Conn, tls.ConnectionState, error) {
timeout := h.Timeout
if timeout <= 0 {
timeout = 10 * time.Second
}
defer conn.SetDeadline(time.Time{})
conn.SetDeadline(time.Now().Add(timeout))
tlsconn := tls.Client(conn, config)
if err := tlsconn.Handshake(); err != nil {
return nil, tls.ConnectionState{}, err
}
return tlsconn, tlsconn.ConnectionState(), nil
}
// DefaultTLSHandshaker is the default TLS handshaker.
var DefaultTLSHandshaker = &TLSHandshakerStdlib{}

View File

@ -0,0 +1,81 @@
package netxlite
import (
"context"
"crypto/tls"
"io"
"net"
"net/http"
"net/http/httptest"
"net/url"
"testing"
"time"
"github.com/ooni/probe-cli/v3/internal/netxmocks"
)
func TestTLSHandshakerStdlibWithError(t *testing.T) {
var times []time.Time
h := &TLSHandshakerStdlib{}
tcpConn := &netxmocks.Conn{
MockWrite: func(b []byte) (int, error) {
return 0, io.EOF
},
MockSetDeadline: func(t time.Time) error {
times = append(times, t)
return nil
},
}
ctx := context.Background()
conn, _, err := h.Handshake(ctx, tcpConn, &tls.Config{
ServerName: "x.org",
})
if err != io.EOF {
t.Fatal("not the error that we expected")
}
if conn != nil {
t.Fatal("expected nil con here")
}
if len(times) != 2 {
t.Fatal("expected two time entries")
}
if !times[0].After(time.Now()) {
t.Fatal("timeout not in the future")
}
if !times[1].IsZero() {
t.Fatal("did not clear timeout on exit")
}
}
func TestTLSHandshakerStdlibSuccess(t *testing.T) {
handler := http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
rw.WriteHeader(200)
})
srvr := httptest.NewTLSServer(handler)
defer srvr.Close()
URL, err := url.Parse(srvr.URL)
if err != nil {
t.Fatal(err)
}
conn, err := net.Dial("tcp", URL.Host)
if err != nil {
t.Fatal(err)
}
defer conn.Close()
handshaker := &TLSHandshakerStdlib{}
ctx := context.Background()
config := &tls.Config{
InsecureSkipVerify: true,
MinVersion: tls.VersionTLS13,
MaxVersion: tls.VersionTLS13,
ServerName: URL.Hostname(),
}
tlsConn, connState, err := handshaker.Handshake(ctx, conn, config)
if err != nil {
t.Fatal(err)
}
defer tlsConn.Close()
if connState.Version != tls.VersionTLS13 {
t.Fatal("unexpected TLS version")
}
}