From accd0ccccdc46698541fb56eaf3284bf8fa50b73 Mon Sep 17 00:00:00 2001 From: Simone Basso Date: Fri, 22 Sep 2023 13:32:22 +0200 Subject: [PATCH] feat(enginenetx): use the new HTTPSDialer (#1295) This commit refactors how we construct the *Network used by the OONI engine so that the HTTPSTransport we use relies on the new HTTPSDialer as opposed to using netxlite's TLS dialing facilities. This new HTTPSDialer has been specifically written to integrate TCP and TLS dialing and facilitate circumvention. The current implementation uses a "null" policy which makes it roughly equivalent to the previous behavior, at least functionally, tough we are now doing a variation of happy eyeballs where to try to ~aggressively dial more connections as we see that previous connections fail to dial. Specifically, if a TLS connection has not succeded within 300 milliseconds (probably a low value?), then we attempt dialing with another available IP address. The new code documents extensively what we are doing and some current limitations, including references to the tracking issues. This also diff fixes two issues we discovered when integrating the HTTPSDialer with the rest of OONI Probe: 1. https://github.com/ooni/probe-cli/pull/1295#issuecomment-1731231178 2. https://github.com/ooni/probe-cli/pull/1295#issuecomment-1731243994 While there, use `log.Log` more frequently in testing to interpret what is going wrong. Part of https://github.com/ooni/probe/issues/2531 --- .../enginenetx/httpsdialer_internal_test.go | 2 +- internal/enginenetx/httpsdialer_test.go | 52 ++++++++++++++++++- internal/enginenetx/httpsdialercore.go | 31 +++++------ internal/enginenetx/network.go | 52 +++++++++++++++++-- internal/enginenetx/network_test.go | 21 ++++---- internal/model/netx.go | 26 ++++++++-- internal/netxlite/dialer.go | 2 +- internal/netxlite/dnsovergetaddrinfo.go | 2 +- internal/netxlite/netx.go | 6 +-- internal/netxlite/quic.go | 2 +- internal/netxlite/resolvercore.go | 20 +++---- internal/netxlite/resolvercore_test.go | 30 +++++------ internal/netxlite/tls.go | 2 +- internal/netxlite/udp.go | 2 +- internal/netxlite/utls.go | 2 +- pkg/oonimkall/session_integration_test.go | 2 + 16 files changed, 184 insertions(+), 70 deletions(-) diff --git a/internal/enginenetx/httpsdialer_internal_test.go b/internal/enginenetx/httpsdialer_internal_test.go index 3b240113d7..4077f9c0f1 100644 --- a/internal/enginenetx/httpsdialer_internal_test.go +++ b/internal/enginenetx/httpsdialer_internal_test.go @@ -20,10 +20,10 @@ func TestHTTPSDialerTacticsEmitter(t *testing.T) { hd := &HTTPSDialer{ idGenerator: &atomic.Int64{}, logger: model.DiscardLogger, + netx: &netxlite.Netx{Underlying: nil}, // nil means: use netxlite's singleton policy: &HTTPSDialerNullPolicy{}, resolver: netxlite.NewStdlibResolver(model.DiscardLogger), rootCAs: netxlite.NewMozillaCertPool(), - unet: &netxlite.DefaultTProxy{}, wg: &sync.WaitGroup{}, } diff --git a/internal/enginenetx/httpsdialer_test.go b/internal/enginenetx/httpsdialer_test.go index 78d5894201..b3b4c18411 100644 --- a/internal/enginenetx/httpsdialer_test.go +++ b/internal/enginenetx/httpsdialer_test.go @@ -2,7 +2,9 @@ package enginenetx_test import ( "context" + "crypto/x509" "encoding/json" + "net/url" "testing" "time" @@ -10,6 +12,7 @@ import ( "github.com/google/go-cmp/cmp" "github.com/ooni/netem" "github.com/ooni/probe-cli/v3/internal/enginenetx" + "github.com/ooni/probe-cli/v3/internal/mocks" "github.com/ooni/probe-cli/v3/internal/netemx" "github.com/ooni/probe-cli/v3/internal/netxlite" "github.com/ooni/probe-cli/v3/internal/runtimex" @@ -63,7 +66,7 @@ func (st *httpsDialerCancelingContextStatsTracker) OnSuccess(tactic *enginenetx. } } -func TestHTTPSDialerWAI(t *testing.T) { +func TestHTTPSDialerNetemQA(t *testing.T) { // testcase is a test case implemented by this function type testcase struct { // name is the name of the test case @@ -383,10 +386,10 @@ func TestHTTPSDialerWAI(t *testing.T) { // create the TLS dialer dialer := enginenetx.NewHTTPSDialer( log.Log, + netx, tc.policy, resolver, tc.stats, - unet, ) defer dialer.CloseIdleConnections() @@ -603,3 +606,48 @@ func TestHTTPSDialerTactic(t *testing.T) { } }) } + +func TestHTTPSDialerHostNetworkQA(t *testing.T) { + t.Run("HTTPSDialerNullPolicy allows connecting to https://127.0.0.1/ using a custom CA", func(t *testing.T) { + ca := netem.MustNewCA() + server := testingx.MustNewHTTPServerTLS( + testingx.HTTPHandlerBlockpage451(), + ca, + "server.local", + ) + defer server.Close() + + tproxy := &netxlite.DefaultTProxy{} + + // The resolver we're creating here reproduces the test case described by + // https://github.com/ooni/probe-cli/pull/1295#issuecomment-1731243994 + resolver := netxlite.MaybeWrapWithBogonResolver(true, netxlite.NewStdlibResolver(log.Log)) + + httpsDialer := enginenetx.NewHTTPSDialer( + log.Log, + &netxlite.Netx{Underlying: &mocks.UnderlyingNetwork{ + MockDefaultCertPool: func() *x509.CertPool { + return ca.DefaultCertPool() // just override the CA + }, + MockDialTimeout: tproxy.DialTimeout, + MockDialContext: tproxy.DialContext, + MockListenTCP: tproxy.ListenTCP, + MockListenUDP: tproxy.ListenUDP, + MockGetaddrinfoLookupANY: tproxy.GetaddrinfoLookupANY, + MockGetaddrinfoResolverNetwork: tproxy.GetaddrinfoResolverNetwork, + }}, + &enginenetx.HTTPSDialerNullPolicy{}, + resolver, + &enginenetx.HTTPSDialerNullStatsTracker{}, + ) + + URL := runtimex.Try1(url.Parse(server.URL)) + + ctx := context.Background() + tlsConn, err := httpsDialer.DialTLSContext(ctx, "tcp", URL.Host) + if err != nil { + t.Fatal(err) + } + tlsConn.Close() + }) +} diff --git a/internal/enginenetx/httpsdialercore.go b/internal/enginenetx/httpsdialercore.go index e410d69b73..189acc2005 100644 --- a/internal/enginenetx/httpsdialercore.go +++ b/internal/enginenetx/httpsdialercore.go @@ -113,6 +113,9 @@ type HTTPSDialer struct { // logger is the logger to use. logger model.Logger + // netx is the [*netxlite.Netx] to use. + netx *netxlite.Netx + // policy defines the dialing policy to use. policy HTTPSDialerPolicy @@ -125,9 +128,6 @@ type HTTPSDialer struct { // stats tracks what happens while dialing. stats HTTPSDialerStatsTracker - // unet is the underlying network. - unet model.UnderlyingNetwork - // wg is the wait group for knowing when all goroutines // started in the background joined (for testing). wg *sync.WaitGroup @@ -139,22 +139,22 @@ type HTTPSDialer struct { // // - logger is the logger to use for logging; // +// - netx is the [*netxlite.Netx] to use; +// // - policy defines the dialer policy; // // - resolver is the resolver to use; // -// - stats tracks what happens while we're dialing; -// -// - unet is the underlying network to use. +// - stats tracks what happens while we're dialing. // // The returned [*HTTPSDialer] would use the underlying network's // DefaultCertPool to create and cache the cert pool to use. func NewHTTPSDialer( logger model.Logger, + netx *netxlite.Netx, policy HTTPSDialerPolicy, resolver model.Resolver, stats HTTPSDialerStatsTracker, - unet model.UnderlyingNetwork, ) *HTTPSDialer { return &HTTPSDialer{ idGenerator: &atomic.Int64{}, @@ -162,11 +162,11 @@ func NewHTTPSDialer( Prefix: "HTTPSDialer: ", Logger: logger, }, + netx: netx, policy: policy, resolver: resolver, - rootCAs: unet.DefaultCertPool(), + rootCAs: netx.MaybeCustomUnderlyingNetwork().Get().DefaultCertPool(), stats: stats, - unet: unet, wg: &sync.WaitGroup{}, } } @@ -205,12 +205,16 @@ func (hd *HTTPSDialer) DialTLSContext(ctx context.Context, network string, endpo ctx, cancel := context.WithCancel(ctx) defer cancel() + // See https://github.com/ooni/probe-cli/pull/1295#issuecomment-1731243994 for context + // on why here we MUST make sure we short-circuit IP addresses. + resoWithShortCircuit := &netxlite.ResolverShortCircuitIPAddr{Resolver: hd.resolver} + logger := &logx.PrefixLogger{ Prefix: fmt.Sprintf("[#%d] ", hd.idGenerator.Add(1)), Logger: hd.logger, } ol := logx.NewOperationLogger(logger, "LookupTactics: %s", net.JoinHostPort(hostname, port)) - tactics, err := hd.policy.LookupTactics(ctx, hostname, port, hd.resolver) + tactics, err := hd.policy.LookupTactics(ctx, hostname, port, resoWithShortCircuit) if err != nil { ol.Stop(err) return nil, err @@ -332,12 +336,9 @@ func (hd *HTTPSDialer) dialTLS( // tell the tactic that we're starting hd.stats.OnStarting(tactic) - // create a network abstraction using the underlying network - netx := &netxlite.Netx{Underlying: hd.unet} - // create dialer and establish TCP connection ol := logx.NewOperationLogger(logger, "TCPConnect %s", tactic.Endpoint) - dialer := netx.NewDialerWithoutResolver(logger) + dialer := hd.netx.NewDialerWithoutResolver(logger) tcpConn, err := dialer.DialContext(ctx, "tcp", tactic.Endpoint) ol.Stop(err) @@ -363,7 +364,7 @@ func (hd *HTTPSDialer) dialTLS( tlsConfig.ServerName, tlsConfig.NextProtos, ) - thx := netx.NewTLSHandshakerStdlib(logger) + thx := hd.netx.NewTLSHandshakerStdlib(logger) tlsConn, err := thx.Handshake(ctx, tcpConn, tlsConfig) ol.Stop(err) diff --git a/internal/enginenetx/network.go b/internal/enginenetx/network.go index a26b6f9570..e7a24121c5 100644 --- a/internal/enginenetx/network.go +++ b/internal/enginenetx/network.go @@ -72,14 +72,58 @@ func NewNetwork( proxyURL *url.URL, resolver model.Resolver, ) *Network { + // Create a dialer ONLY used for dialing unencrypted TCP connections. The common use + // case of this Network is to dial encrypted connections. For this reason, here it is + // reasonably fine to use the legacy sequential dialer implemented in netxlite. dialer := netxlite.NewDialerWithResolver(logger, resolver) - handshaker := netxlite.NewTLSHandshakerStdlib(logger) - tlsDialer := netxlite.NewTLSDialer(dialer, handshaker) + + // Create a TLS dialer ONLY used for dialing TLS connections. This dialer will use + // happy-eyeballs and possibly custom policies for dialing TLS connections. + // + // Additionally, please note the following limitations (to be overcome through + // future refactoring of this func): + // + // - for now, we're using a "null" policy that does happy eyeballs but otherwise + // does not use beacons or other TLS handshake tricks; + // + // - for now, we're using a "null" stats tracker, meaning we don't track stats. + httpsDialer := NewHTTPSDialer( + logger, + &netxlite.Netx{Underlying: nil}, // nil means using netxlite's singleton + &HTTPSDialerNullPolicy{}, + resolver, + &HTTPSDialerNullStatsTracker{}, + ) + + // Here we're creating a "new style" HTTPS transport, which has less + // restrictions compared to the "old style" one. + // + // Note that: + // + // - we're enabling compression, which is desiredable since this transport + // is not made for measuring and compression is good(TM); + // + // - if proxyURL is nil, the proxy option is equivalent to disabling + // the proxy, otherwise it means that we're using the ooni/oohttp library + // to dial for proxies, which has some restrictions. + // + // In particular, the returned transport uses dialer for dialing with + // cleartext proxies (e.g., socks5 and http) and httpsDialer for dialing + // with encrypted proxies (e.g., https). After this has happened, + // the code currently falls back to using the standard library's tls + // client code for establishing TLS connections over the proxy. The main + // implication here is that we're not using our custom mozilla CA for + // validating TLS certificates, rather we're using the system's cert store. + // + // Fixing this issue is TODO(https://github.com/ooni/probe/issues/2536). txp := netxlite.NewHTTPTransportWithOptions( - logger, dialer, tlsDialer, + logger, dialer, httpsDialer, netxlite.HTTPTransportOptionDisableCompression(false), - netxlite.HTTPTransportOptionProxyURL(proxyURL), // nil implies "no proxy" + netxlite.HTTPTransportOptionProxyURL(proxyURL), ) + + // Make sure we count the bytes sent and received as part of the session txp = bytecounter.WrapHTTPTransport(txp, counter) + return &Network{txp} } diff --git a/internal/enginenetx/network_test.go b/internal/enginenetx/network_test.go index f37b4fccca..855c6f515c 100644 --- a/internal/enginenetx/network_test.go +++ b/internal/enginenetx/network_test.go @@ -13,7 +13,6 @@ import ( "github.com/ooni/probe-cli/v3/internal/enginenetx" "github.com/ooni/probe-cli/v3/internal/kvstore" "github.com/ooni/probe-cli/v3/internal/measurexlite" - "github.com/ooni/probe-cli/v3/internal/model" "github.com/ooni/probe-cli/v3/internal/netemx" "github.com/ooni/probe-cli/v3/internal/netxlite" "github.com/ooni/probe-cli/v3/internal/testingsocks5" @@ -29,9 +28,9 @@ func TestNetworkQA(t *testing.T) { txp := enginenetx.NewNetwork( bytecounter.New(), &kvstore.Memory{}, - model.DiscardLogger, + log.Log, nil, - netxlite.NewStdlibResolver(model.DiscardLogger), + netxlite.NewStdlibResolver(log.Log), ) client := txp.NewHTTPClient() resp, err := client.Get("https://www.example.com/") @@ -66,13 +65,13 @@ func TestNetworkQA(t *testing.T) { txp := enginenetx.NewNetwork( bytecounter.New(), &kvstore.Memory{}, - model.DiscardLogger, + log.Log, &url.URL{ Scheme: "socks5", Host: net.JoinHostPort(env.ClientStack.IPAddress(), "9050"), Path: "/", }, - netxlite.NewStdlibResolver(model.DiscardLogger), + netxlite.NewStdlibResolver(log.Log), ) client := txp.NewHTTPClient() @@ -135,13 +134,13 @@ func TestNetworkQA(t *testing.T) { txp := enginenetx.NewNetwork( bytecounter.New(), &kvstore.Memory{}, - model.DiscardLogger, + log.Log, &url.URL{ Scheme: "http", Host: net.JoinHostPort(env.ClientStack.IPAddress(), "8080"), Path: "/", }, - netxlite.NewStdlibResolver(model.DiscardLogger), + netxlite.NewStdlibResolver(log.Log), ) client := txp.NewHTTPClient() @@ -206,13 +205,13 @@ func TestNetworkQA(t *testing.T) { txp := enginenetx.NewNetwork( bytecounter.New(), &kvstore.Memory{}, - model.DiscardLogger, + log.Log, &url.URL{ Scheme: "https", Host: net.JoinHostPort(env.ClientStack.IPAddress(), "4443"), Path: "/", }, - netxlite.NewStdlibResolver(model.DiscardLogger), + netxlite.NewStdlibResolver(log.Log), ) client := txp.NewHTTPClient() @@ -261,9 +260,9 @@ func TestNetworkQA(t *testing.T) { txp := enginenetx.NewNetwork( bytecounter.New(), &kvstore.Memory{}, - model.DiscardLogger, + log.Log, nil, - netxlite.NewStdlibResolver(model.DiscardLogger), + netxlite.NewStdlibResolver(log.Log), ) client := txp.NewHTTPClient() if client.Jar == nil { diff --git a/internal/model/netx.go b/internal/model/netx.go index aedf579587..f6f4bc78ff 100644 --- a/internal/model/netx.go +++ b/internal/model/netx.go @@ -133,8 +133,17 @@ type DialerWrapper interface { // SimpleDialer establishes network connections. type SimpleDialer interface { - // DialContext behaves like net.Dialer.DialContext. - DialContext(ctx context.Context, network, address string) (net.Conn, error) + // DialContext creates a new TCP/UDP connection like [net.DialContext] would do. + // + // The endpoint is an endpoint like the ones accepted by [net.DialContext]. For example, + // x.org:443, 130.192.91.211:443 and [::1]:443. Note that IPv6 addrs are quoted. + // + // This function MUST gracefully handle the case where the endpoint contains an IPv4 + // or IPv6 address by skipping DNS resolution and directly using the endpoint. + // + // See https://github.com/ooni/probe-cli/pull/1295#issuecomment-1731243994 for more + // details on why DialContext MUST do that. + DialContext(ctx context.Context, network, endpoint string) (net.Conn, error) } // Dialer is a SimpleDialer with the possibility of closing open connections. @@ -258,7 +267,9 @@ type QUICDialer interface { // Resolver performs domain name resolutions. type Resolver interface { - // LookupHost behaves like net.Resolver.LookupHost. + // LookupHost resolves the given hostname to IP addreses. This function SHOULD handle the + // case in which hostname is an IP address by returning a 1-element list containing the hostname, + // for consistency with [net.Resolver] behaviour. LookupHost(ctx context.Context, hostname string) (addrs []string, err error) // Network returns the resolver type. It should be one of: @@ -315,6 +326,15 @@ type TLSDialer interface { // DialTLSContext dials a TLS connection. This method will always return // to you a oohttp.TLSConn, so you can always safely cast to it. + // + // The endpoint is an endpoint like the ones accepted by [net.DialContext]. For example, + // x.org:443, 130.192.91.211:443 and [::1]:443. Note that IPv6 addrs are quoted. + // + // This function MUST gracefully handle the case where the endpoint contains an IPv4 + // or IPv6 address by skipping DNS resolution and directly using the endpoint. + // + // See https://github.com/ooni/probe-cli/pull/1295#issuecomment-1731243994 for more + // details on why DialTLSContext MUST do that. DialTLSContext(ctx context.Context, network, address string) (net.Conn, error) } diff --git a/internal/netxlite/dialer.go b/internal/netxlite/dialer.go index 6a0ff6133b..f85ed64763 100644 --- a/internal/netxlite/dialer.go +++ b/internal/netxlite/dialer.go @@ -33,7 +33,7 @@ func NewDialerWithStdlibResolver(dl model.DebugLogger) model.Dialer { // that we can implement the legacy [netx] package. New code MUST NOT // use this functionality, which we'd like to remove ASAP. func (netx *Netx) NewDialerWithResolver(dl model.DebugLogger, r model.Resolver, w ...model.DialerWrapper) model.Dialer { - return WrapDialer(dl, r, &dialerSystem{provider: netx.maybeCustomUnderlyingNetwork()}, w...) + return WrapDialer(dl, r, &dialerSystem{provider: netx.MaybeCustomUnderlyingNetwork()}, w...) } // NewDialerWithResolver is equivalent to creating an empty [*Netx] diff --git a/internal/netxlite/dnsovergetaddrinfo.go b/internal/netxlite/dnsovergetaddrinfo.go index e5a94c92aa..9ad4195fd4 100644 --- a/internal/netxlite/dnsovergetaddrinfo.go +++ b/internal/netxlite/dnsovergetaddrinfo.go @@ -28,7 +28,7 @@ type dnsOverGetaddrinfoTransport struct { } func (netx *Netx) newDNSOverGetaddrinfoTransport() model.DNSTransport { - return &dnsOverGetaddrinfoTransport{provider: netx.maybeCustomUnderlyingNetwork()} + return &dnsOverGetaddrinfoTransport{provider: netx.MaybeCustomUnderlyingNetwork()} } // NewDNSOverGetaddrinfoTransport creates a new dns-over-getaddrinfo transport. diff --git a/internal/netxlite/netx.go b/internal/netxlite/netx.go index ae45f8ef5d..b1c431ebbc 100644 --- a/internal/netxlite/netx.go +++ b/internal/netxlite/netx.go @@ -20,12 +20,12 @@ type Netx struct { var _ model.MeasuringNetwork = &Netx{} -// maybeCustomUnderlyingNetwork wraps the [model.UnderlyingNetwork] using a [*MaybeCustomUnderlyingNetwork]. -func (netx *Netx) maybeCustomUnderlyingNetwork() *MaybeCustomUnderlyingNetwork { +// MaybeCustomUnderlyingNetwork wraps the [model.UnderlyingNetwork] using a [*MaybeCustomUnderlyingNetwork]. +func (netx *Netx) MaybeCustomUnderlyingNetwork() *MaybeCustomUnderlyingNetwork { return &MaybeCustomUnderlyingNetwork{netx.Underlying} } // ListenTCP creates a new listening TCP socket using the given address. func (netx *Netx) ListenTCP(network string, addr *net.TCPAddr) (net.Listener, error) { - return netx.maybeCustomUnderlyingNetwork().Get().ListenTCP(network, addr) + return netx.MaybeCustomUnderlyingNetwork().Get().ListenTCP(network, addr) } diff --git a/internal/netxlite/quic.go b/internal/netxlite/quic.go index df6fb39c0d..41eda13fb5 100644 --- a/internal/netxlite/quic.go +++ b/internal/netxlite/quic.go @@ -29,7 +29,7 @@ func (netx *Netx) NewQUICDialerWithResolver(listener model.UDPListener, logger m resolver model.Resolver, wrappers ...model.QUICDialerWrapper) (outDialer model.QUICDialer) { baseDialer := &quicDialerQUICGo{ UDPListener: listener, - provider: netx.maybeCustomUnderlyingNetwork(), + provider: netx.MaybeCustomUnderlyingNetwork(), } return wrapQUICDialer(logger, resolver, baseDialer, wrappers...) } diff --git a/internal/netxlite/resolvercore.go b/internal/netxlite/resolvercore.go index 8ebfaf3f04..93f3b93081 100644 --- a/internal/netxlite/resolvercore.go +++ b/internal/netxlite/resolvercore.go @@ -114,7 +114,7 @@ func NewParallelUDPResolver(logger model.DebugLogger, dialer model.Dialer, addre func WrapResolver(logger model.DebugLogger, resolver model.Resolver) model.Resolver { return &resolverIDNA{ Resolver: &resolverLogger{ - Resolver: &resolverShortCircuitIPAddr{ + Resolver: &ResolverShortCircuitIPAddr{ Resolver: &resolverErrWrapper{ Resolver: resolver, }, @@ -283,22 +283,22 @@ func (r *resolverIDNA) LookupNS( return r.Resolver.LookupNS(ctx, host) } -// resolverShortCircuitIPAddr recognizes when the input hostname is an +// ResolverShortCircuitIPAddr recognizes when the input hostname is an // IP address and returns it immediately to the caller. -type resolverShortCircuitIPAddr struct { +type ResolverShortCircuitIPAddr struct { Resolver model.Resolver } -var _ model.Resolver = &resolverShortCircuitIPAddr{} +var _ model.Resolver = &ResolverShortCircuitIPAddr{} -func (r *resolverShortCircuitIPAddr) LookupHost(ctx context.Context, hostname string) ([]string, error) { +func (r *ResolverShortCircuitIPAddr) LookupHost(ctx context.Context, hostname string) ([]string, error) { if net.ParseIP(hostname) != nil { return []string{hostname}, nil } return r.Resolver.LookupHost(ctx, hostname) } -func (r *resolverShortCircuitIPAddr) LookupHTTPS(ctx context.Context, hostname string) (*model.HTTPSSvc, error) { +func (r *ResolverShortCircuitIPAddr) LookupHTTPS(ctx context.Context, hostname string) (*model.HTTPSSvc, error) { if net.ParseIP(hostname) != nil { https := &model.HTTPSSvc{} if isIPv6(hostname) { @@ -311,15 +311,15 @@ func (r *resolverShortCircuitIPAddr) LookupHTTPS(ctx context.Context, hostname s return r.Resolver.LookupHTTPS(ctx, hostname) } -func (r *resolverShortCircuitIPAddr) Network() string { +func (r *ResolverShortCircuitIPAddr) Network() string { return r.Resolver.Network() } -func (r *resolverShortCircuitIPAddr) Address() string { +func (r *ResolverShortCircuitIPAddr) Address() string { return r.Resolver.Address() } -func (r *resolverShortCircuitIPAddr) CloseIdleConnections() { +func (r *ResolverShortCircuitIPAddr) CloseIdleConnections() { r.Resolver.CloseIdleConnections() } @@ -327,7 +327,7 @@ func (r *resolverShortCircuitIPAddr) CloseIdleConnections() { // function that only works with domain names. var ErrDNSIPAddress = errors.New("ooresolver: expected domain, found IP address") -func (r *resolverShortCircuitIPAddr) LookupNS( +func (r *ResolverShortCircuitIPAddr) LookupNS( ctx context.Context, hostname string) ([]*net.NS, error) { if net.ParseIP(hostname) != nil { return nil, ErrDNSIPAddress diff --git a/internal/netxlite/resolvercore_test.go b/internal/netxlite/resolvercore_test.go index 55b6f291df..ef86d41fa8 100644 --- a/internal/netxlite/resolvercore_test.go +++ b/internal/netxlite/resolvercore_test.go @@ -23,7 +23,7 @@ func typeCheckForSystemResolver(t *testing.T, resolver model.Resolver, logger mo if loggerReso.Logger != logger { t.Fatal("invalid logger") } - shortCircuit := loggerReso.Resolver.(*resolverShortCircuitIPAddr) + shortCircuit := loggerReso.Resolver.(*ResolverShortCircuitIPAddr) errWrapper := shortCircuit.Resolver.(*resolverErrWrapper) reso := errWrapper.Resolver.(*resolverSystem) txpErrWrapper := reso.t.(*dnsTransportErrWrapper) @@ -43,7 +43,7 @@ func TestNewSerialUDPResolver(t *testing.T) { if logger.Logger != log.Log { t.Fatal("invalid logger") } - shortCircuit := logger.Resolver.(*resolverShortCircuitIPAddr) + shortCircuit := logger.Resolver.(*ResolverShortCircuitIPAddr) errWrapper := shortCircuit.Resolver.(*resolverErrWrapper) serio := errWrapper.Resolver.(*SerialResolver) txp := serio.Transport().(*dnsTransportErrWrapper) @@ -61,7 +61,7 @@ func TestNewParallelUDPResolver(t *testing.T) { if logger.Logger != log.Log { t.Fatal("invalid logger") } - shortCircuit := logger.Resolver.(*resolverShortCircuitIPAddr) + shortCircuit := logger.Resolver.(*ResolverShortCircuitIPAddr) errWrapper := shortCircuit.Resolver.(*resolverErrWrapper) para := errWrapper.Resolver.(*ParallelResolver) txp := para.Transport().(*dnsTransportErrWrapper) @@ -78,7 +78,7 @@ func TestNewParallelDNSOverHTTPSResolver(t *testing.T) { if logger.Logger != log.Log { t.Fatal("invalid logger") } - shortCircuit := logger.Resolver.(*resolverShortCircuitIPAddr) + shortCircuit := logger.Resolver.(*ResolverShortCircuitIPAddr) errWrapper := shortCircuit.Resolver.(*resolverErrWrapper) para := errWrapper.Resolver.(*ParallelResolver) txp := para.Transport().(*dnsTransportErrWrapper) @@ -736,7 +736,7 @@ func TestResolverIDNA(t *testing.T) { func TestResolverShortCircuitIPAddr(t *testing.T) { t.Run("LookupHost", func(t *testing.T) { t.Run("with IP addr", func(t *testing.T) { - r := &resolverShortCircuitIPAddr{ + r := &ResolverShortCircuitIPAddr{ Resolver: &mocks.Resolver{ MockLookupHost: func(ctx context.Context, domain string) ([]string, error) { return nil, errors.New("mocked error") @@ -754,7 +754,7 @@ func TestResolverShortCircuitIPAddr(t *testing.T) { }) t.Run("with domain", func(t *testing.T) { - r := &resolverShortCircuitIPAddr{ + r := &ResolverShortCircuitIPAddr{ Resolver: &mocks.Resolver{ MockLookupHost: func(ctx context.Context, domain string) ([]string, error) { return nil, errors.New("mocked error") @@ -774,7 +774,7 @@ func TestResolverShortCircuitIPAddr(t *testing.T) { t.Run("LookupHTTPS", func(t *testing.T) { t.Run("with IPv4 addr", func(t *testing.T) { - r := &resolverShortCircuitIPAddr{ + r := &ResolverShortCircuitIPAddr{ Resolver: &mocks.Resolver{ MockLookupHTTPS: func(ctx context.Context, domain string) (*model.HTTPSSvc, error) { return nil, errors.New("mocked error") @@ -792,7 +792,7 @@ func TestResolverShortCircuitIPAddr(t *testing.T) { }) t.Run("with IPv6 addr", func(t *testing.T) { - r := &resolverShortCircuitIPAddr{ + r := &ResolverShortCircuitIPAddr{ Resolver: &mocks.Resolver{ MockLookupHTTPS: func(ctx context.Context, domain string) (*model.HTTPSSvc, error) { return nil, errors.New("mocked error") @@ -810,7 +810,7 @@ func TestResolverShortCircuitIPAddr(t *testing.T) { }) t.Run("with domain", func(t *testing.T) { - r := &resolverShortCircuitIPAddr{ + r := &ResolverShortCircuitIPAddr{ Resolver: &mocks.Resolver{ MockLookupHTTPS: func(ctx context.Context, domain string) (*model.HTTPSSvc, error) { return nil, errors.New("mocked error") @@ -830,7 +830,7 @@ func TestResolverShortCircuitIPAddr(t *testing.T) { t.Run("LookupNS", func(t *testing.T) { t.Run("with IPv4 addr", func(t *testing.T) { - r := &resolverShortCircuitIPAddr{ + r := &ResolverShortCircuitIPAddr{ Resolver: &mocks.Resolver{ MockLookupNS: func(ctx context.Context, domain string) ([]*net.NS, error) { return nil, errors.New("mocked error") @@ -848,7 +848,7 @@ func TestResolverShortCircuitIPAddr(t *testing.T) { }) t.Run("with IPv6 addr", func(t *testing.T) { - r := &resolverShortCircuitIPAddr{ + r := &ResolverShortCircuitIPAddr{ Resolver: &mocks.Resolver{ MockLookupNS: func(ctx context.Context, domain string) ([]*net.NS, error) { return nil, errors.New("mocked error") @@ -866,7 +866,7 @@ func TestResolverShortCircuitIPAddr(t *testing.T) { }) t.Run("with domain", func(t *testing.T) { - r := &resolverShortCircuitIPAddr{ + r := &ResolverShortCircuitIPAddr{ Resolver: &mocks.Resolver{ MockLookupNS: func(ctx context.Context, domain string) ([]*net.NS, error) { return nil, errors.New("mocked error") @@ -890,7 +890,7 @@ func TestResolverShortCircuitIPAddr(t *testing.T) { return "x" }, } - reso := &resolverShortCircuitIPAddr{child} + reso := &ResolverShortCircuitIPAddr{child} if reso.Network() != "x" { t.Fatal("invalid result") } @@ -902,7 +902,7 @@ func TestResolverShortCircuitIPAddr(t *testing.T) { return "x" }, } - reso := &resolverShortCircuitIPAddr{child} + reso := &ResolverShortCircuitIPAddr{child} if reso.Address() != "x" { t.Fatal("invalid result") } @@ -915,7 +915,7 @@ func TestResolverShortCircuitIPAddr(t *testing.T) { called = true }, } - reso := &resolverShortCircuitIPAddr{child} + reso := &ResolverShortCircuitIPAddr{child} reso.CloseIdleConnections() if !called { t.Fatal("not called") diff --git a/internal/netxlite/tls.go b/internal/netxlite/tls.go index 7045ef463b..14df796eca 100644 --- a/internal/netxlite/tls.go +++ b/internal/netxlite/tls.go @@ -157,7 +157,7 @@ type TLSConn = model.TLSConn // NewTLSHandshakerStdlib implements [model.MeasuringNetwork]. func (netx *Netx) NewTLSHandshakerStdlib(logger model.DebugLogger) model.TLSHandshaker { return newTLSHandshakerLogger( - &tlsHandshakerConfigurable{provider: netx.maybeCustomUnderlyingNetwork()}, + &tlsHandshakerConfigurable{provider: netx.MaybeCustomUnderlyingNetwork()}, logger, ) } diff --git a/internal/netxlite/udp.go b/internal/netxlite/udp.go index 957b092b97..170d2e479f 100644 --- a/internal/netxlite/udp.go +++ b/internal/netxlite/udp.go @@ -9,7 +9,7 @@ import ( // NewUDPListener creates a new UDPListener using the underlying // [*Netx] structure to create listening UDP sockets. func (netx *Netx) NewUDPListener() model.UDPListener { - return &udpListenerErrWrapper{&udpListenerStdlib{provider: netx.maybeCustomUnderlyingNetwork()}} + return &udpListenerErrWrapper{&udpListenerStdlib{provider: netx.MaybeCustomUnderlyingNetwork()}} } // NewUDPListener is equivalent to creating an empty [*Netx] diff --git a/internal/netxlite/utls.go b/internal/netxlite/utls.go index b339e1cf1e..5b988dc096 100644 --- a/internal/netxlite/utls.go +++ b/internal/netxlite/utls.go @@ -20,7 +20,7 @@ import ( func (netx *Netx) NewTLSHandshakerUTLS(logger model.DebugLogger, id *utls.ClientHelloID) model.TLSHandshaker { return newTLSHandshakerLogger(&tlsHandshakerConfigurable{ NewConn: newUTLSConnFactory(id), - provider: netx.maybeCustomUnderlyingNetwork(), + provider: netx.MaybeCustomUnderlyingNetwork(), }, logger) } diff --git a/pkg/oonimkall/session_integration_test.go b/pkg/oonimkall/session_integration_test.go index ab1bf45b30..5f77217cbc 100644 --- a/pkg/oonimkall/session_integration_test.go +++ b/pkg/oonimkall/session_integration_test.go @@ -11,6 +11,7 @@ import ( "testing" "time" + "github.com/apex/log" "github.com/ooni/probe-cli/v3/internal/enginelocate" "github.com/ooni/probe-cli/v3/internal/model" "github.com/ooni/probe-cli/v3/pkg/oonimkall" @@ -19,6 +20,7 @@ import ( func NewSessionForTestingWithAssetsDir(assetsDir string) (*oonimkall.Session, error) { return oonimkall.NewSession(&oonimkall.SessionConfig{ AssetsDir: assetsDir, + Logger: log.Log, ProbeServicesURL: "https://ams-pg-test.ooni.org/", SoftwareName: "oonimkall-test", SoftwareVersion: "0.1.0",