fix(geolocate): always use netxlite functionality (#976)
This change ensures that, in turn, we're able to "remote" all the traffic generated by the `geolocate` package, rather than missing some bits of it that were still using the standard library and caused _some_ geolocations to geolocate as the local host rather than as the remote host. Extracted from https://github.com/ooni/probe-cli/pull/969, where we tested this functionality. Closes https://github.com/ooni/probe/issues/1383 (which was long overdue). Part of https://github.com/ooni/probe/issues/2340, because it allows us to make progress with that.
This commit is contained in:
parent
86ffd6a0c4
commit
57a3919d2a
|
@ -15,6 +15,7 @@ func cloudflareIPLookup(
|
||||||
httpClient *http.Client,
|
httpClient *http.Client,
|
||||||
logger model.Logger,
|
logger model.Logger,
|
||||||
userAgent string,
|
userAgent string,
|
||||||
|
resolver model.Resolver,
|
||||||
) (string, error) {
|
) (string, error) {
|
||||||
data, err := (&httpx.APIClientTemplate{
|
data, err := (&httpx.APIClientTemplate{
|
||||||
BaseURL: "https://www.cloudflare.com",
|
BaseURL: "https://www.cloudflare.com",
|
||||||
|
|
|
@ -8,6 +8,7 @@ import (
|
||||||
|
|
||||||
"github.com/apex/log"
|
"github.com/apex/log"
|
||||||
"github.com/ooni/probe-cli/v3/internal/model"
|
"github.com/ooni/probe-cli/v3/internal/model"
|
||||||
|
"github.com/ooni/probe-cli/v3/internal/netxlite"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestIPLookupWorksUsingcloudlflare(t *testing.T) {
|
func TestIPLookupWorksUsingcloudlflare(t *testing.T) {
|
||||||
|
@ -16,6 +17,7 @@ func TestIPLookupWorksUsingcloudlflare(t *testing.T) {
|
||||||
http.DefaultClient,
|
http.DefaultClient,
|
||||||
log.Log,
|
log.Log,
|
||||||
model.HTTPHeaderUserAgent,
|
model.HTTPHeaderUserAgent,
|
||||||
|
netxlite.NewStdlibResolver(model.DiscardLogger),
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
|
|
|
@ -90,7 +90,9 @@ func NewTask(config Config) *Task {
|
||||||
probeIPLookupper: ipLookupClient(config),
|
probeIPLookupper: ipLookupClient(config),
|
||||||
probeASNLookupper: mmdbLookupper{},
|
probeASNLookupper: mmdbLookupper{},
|
||||||
resolverASNLookupper: mmdbLookupper{},
|
resolverASNLookupper: mmdbLookupper{},
|
||||||
resolverIPLookupper: resolverLookupClient{},
|
resolverIPLookupper: resolverLookupClient{
|
||||||
|
Resolver: config.Resolver,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,7 @@ func invalidIPLookup(
|
||||||
httpClient *http.Client,
|
httpClient *http.Client,
|
||||||
logger model.Logger,
|
logger model.Logger,
|
||||||
userAgent string,
|
userAgent string,
|
||||||
|
resolver model.Resolver,
|
||||||
) (string, error) {
|
) (string, error) {
|
||||||
return "invalid IP", nil
|
return "invalid IP", nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,6 +27,7 @@ var (
|
||||||
type lookupFunc func(
|
type lookupFunc func(
|
||||||
ctx context.Context, client *http.Client,
|
ctx context.Context, client *http.Client,
|
||||||
logger model.Logger, userAgent string,
|
logger model.Logger, userAgent string,
|
||||||
|
resolver model.Resolver,
|
||||||
) (string, error)
|
) (string, error)
|
||||||
|
|
||||||
type method struct {
|
type method struct {
|
||||||
|
@ -89,7 +90,7 @@ func (c ipLookupClient) doWithCustomFunc(
|
||||||
txp := netxlite.NewHTTPTransportWithResolver(c.Logger, c.Resolver)
|
txp := netxlite.NewHTTPTransportWithResolver(c.Logger, c.Resolver)
|
||||||
clnt := &http.Client{Transport: txp}
|
clnt := &http.Client{Transport: txp}
|
||||||
defer clnt.CloseIdleConnections()
|
defer clnt.CloseIdleConnections()
|
||||||
ip, err := fn(ctx, clnt, c.Logger, c.UserAgent)
|
ip, err := fn(ctx, clnt, c.Logger, c.UserAgent, c.Resolver)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return model.DefaultProbeIP, err
|
return model.DefaultProbeIP, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,8 @@ package geolocate
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"net"
|
|
||||||
|
"github.com/ooni/probe-cli/v3/internal/model"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -16,7 +17,9 @@ type dnsResolver interface {
|
||||||
LookupHost(ctx context.Context, host string) (addrs []string, err error)
|
LookupHost(ctx context.Context, host string) (addrs []string, err error)
|
||||||
}
|
}
|
||||||
|
|
||||||
type resolverLookupClient struct{}
|
type resolverLookupClient struct {
|
||||||
|
Resolver model.Resolver
|
||||||
|
}
|
||||||
|
|
||||||
func (rlc resolverLookupClient) do(ctx context.Context, r dnsResolver) (string, error) {
|
func (rlc resolverLookupClient) do(ctx context.Context, r dnsResolver) (string, error) {
|
||||||
var ips []string
|
var ips []string
|
||||||
|
@ -31,5 +34,5 @@ func (rlc resolverLookupClient) do(ctx context.Context, r dnsResolver) (string,
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rlc resolverLookupClient) LookupResolverIP(ctx context.Context) (ip string, err error) {
|
func (rlc resolverLookupClient) LookupResolverIP(ctx context.Context) (ip string, err error) {
|
||||||
return rlc.do(ctx, &net.Resolver{})
|
return rlc.do(ctx, rlc.Resolver)
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,10 +4,16 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/ooni/probe-cli/v3/internal/model"
|
||||||
|
"github.com/ooni/probe-cli/v3/internal/netxlite"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestLookupResolverIP(t *testing.T) {
|
func TestLookupResolverIP(t *testing.T) {
|
||||||
addr, err := (resolverLookupClient{}).LookupResolverIP(context.Background())
|
rlc := resolverLookupClient{
|
||||||
|
Resolver: netxlite.NewStdlibResolver(model.DiscardLogger),
|
||||||
|
}
|
||||||
|
addr, err := rlc.LookupResolverIP(context.Background())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -26,7 +32,9 @@ func (bhl brokenHostLookupper) LookupHost(ctx context.Context, host string) ([]s
|
||||||
|
|
||||||
func TestLookupResolverIPFailure(t *testing.T) {
|
func TestLookupResolverIPFailure(t *testing.T) {
|
||||||
expected := errors.New("mocked error")
|
expected := errors.New("mocked error")
|
||||||
rlc := resolverLookupClient{}
|
rlc := resolverLookupClient{
|
||||||
|
Resolver: netxlite.NewStdlibResolver(model.DiscardLogger),
|
||||||
|
}
|
||||||
addr, err := rlc.do(context.Background(), brokenHostLookupper{
|
addr, err := rlc.do(context.Background(), brokenHostLookupper{
|
||||||
err: expected,
|
err: expected,
|
||||||
})
|
})
|
||||||
|
@ -39,7 +47,9 @@ func TestLookupResolverIPFailure(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestLookupResolverIPNoAddressReturned(t *testing.T) {
|
func TestLookupResolverIPNoAddressReturned(t *testing.T) {
|
||||||
rlc := resolverLookupClient{}
|
rlc := resolverLookupClient{
|
||||||
|
Resolver: netxlite.NewStdlibResolver(model.DiscardLogger),
|
||||||
|
}
|
||||||
addr, err := rlc.do(context.Background(), brokenHostLookupper{})
|
addr, err := rlc.do(context.Background(), brokenHostLookupper{})
|
||||||
if !errors.Is(err, ErrNoIPAddressReturned) {
|
if !errors.Is(err, ErrNoIPAddressReturned) {
|
||||||
t.Fatalf("not the error we expected: %+v", err)
|
t.Fatalf("not the error we expected: %+v", err)
|
||||||
|
|
|
@ -2,43 +2,51 @@ package geolocate
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/ooni/probe-cli/v3/internal/model"
|
"github.com/ooni/probe-cli/v3/internal/model"
|
||||||
|
"github.com/ooni/probe-cli/v3/internal/netxlite"
|
||||||
"github.com/pion/stun"
|
"github.com/pion/stun"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TODO(bassosimone): we should modify the stun code to use
|
|
||||||
// the session resolver rather than using its own.
|
|
||||||
//
|
|
||||||
// See https://github.com/ooni/probe/issues/1383.
|
|
||||||
|
|
||||||
type stunClient interface {
|
type stunClient interface {
|
||||||
Close() error
|
Close() error
|
||||||
Start(m *stun.Message, h stun.Handler) error
|
Start(m *stun.Message, h stun.Handler) error
|
||||||
}
|
}
|
||||||
|
|
||||||
type stunConfig struct {
|
type stunConfig struct {
|
||||||
Dial func(network string, address string) (stunClient, error)
|
Dialer model.Dialer // optional
|
||||||
Endpoint string
|
Endpoint string
|
||||||
Logger model.Logger
|
Logger model.Logger
|
||||||
|
NewClient func(conn net.Conn) (stunClient, error) // optional
|
||||||
|
Resolver model.Resolver
|
||||||
}
|
}
|
||||||
|
|
||||||
func stunDialer(network string, address string) (stunClient, error) {
|
func stunNewClient(conn net.Conn) (stunClient, error) {
|
||||||
return stun.Dial(network, address)
|
return stun.NewClient(conn)
|
||||||
}
|
}
|
||||||
|
|
||||||
func stunIPLookup(ctx context.Context, config stunConfig) (string, error) {
|
func stunIPLookup(ctx context.Context, config stunConfig) (string, error) {
|
||||||
config.Logger.Debugf("STUNIPLookup: start using %s", config.Endpoint)
|
config.Logger.Debugf("STUNIPLookup: start using %s", config.Endpoint)
|
||||||
ip, err := func() (string, error) {
|
ip, err := func() (string, error) {
|
||||||
dial := config.Dial
|
dialer := config.Dialer
|
||||||
if dial == nil {
|
if dialer == nil {
|
||||||
dial = stunDialer
|
dialer = netxlite.NewDialerWithResolver(config.Logger, config.Resolver)
|
||||||
}
|
}
|
||||||
clnt, err := dial("udp", config.Endpoint)
|
conn, err := dialer.DialContext(ctx, "udp", config.Endpoint)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return model.DefaultProbeIP, err
|
return model.DefaultProbeIP, err
|
||||||
}
|
}
|
||||||
|
newClient := config.NewClient
|
||||||
|
if newClient == nil {
|
||||||
|
newClient = stunNewClient
|
||||||
|
}
|
||||||
|
clnt, err := newClient(conn)
|
||||||
|
if err != nil {
|
||||||
|
conn.Close()
|
||||||
|
return model.DefaultProbeIP, err
|
||||||
|
}
|
||||||
defer clnt.Close()
|
defer clnt.Close()
|
||||||
message := stun.MustBuild(stun.TransactionID, stun.BindingRequest)
|
message := stun.MustBuild(stun.TransactionID, stun.BindingRequest)
|
||||||
errch, ipch := make(chan error, 1), make(chan string, 1)
|
errch, ipch := make(chan error, 1), make(chan string, 1)
|
||||||
|
@ -78,10 +86,12 @@ func stunEkigaIPLookup(
|
||||||
httpClient *http.Client,
|
httpClient *http.Client,
|
||||||
logger model.Logger,
|
logger model.Logger,
|
||||||
userAgent string,
|
userAgent string,
|
||||||
|
resolver model.Resolver,
|
||||||
) (string, error) {
|
) (string, error) {
|
||||||
return stunIPLookup(ctx, stunConfig{
|
return stunIPLookup(ctx, stunConfig{
|
||||||
Endpoint: "stun.ekiga.net:3478",
|
Endpoint: "stun.ekiga.net:3478",
|
||||||
Logger: logger,
|
Logger: logger,
|
||||||
|
Resolver: resolver,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -90,9 +100,11 @@ func stunGoogleIPLookup(
|
||||||
httpClient *http.Client,
|
httpClient *http.Client,
|
||||||
logger model.Logger,
|
logger model.Logger,
|
||||||
userAgent string,
|
userAgent string,
|
||||||
|
resolver model.Resolver,
|
||||||
) (string, error) {
|
) (string, error) {
|
||||||
return stunIPLookup(ctx, stunConfig{
|
return stunIPLookup(ctx, stunConfig{
|
||||||
Endpoint: "stun.l.google.com:19302",
|
Endpoint: "stun.l.google.com:19302",
|
||||||
Logger: logger,
|
Logger: logger,
|
||||||
|
Resolver: resolver,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,8 @@ import (
|
||||||
|
|
||||||
"github.com/apex/log"
|
"github.com/apex/log"
|
||||||
"github.com/ooni/probe-cli/v3/internal/model"
|
"github.com/ooni/probe-cli/v3/internal/model"
|
||||||
|
"github.com/ooni/probe-cli/v3/internal/model/mocks"
|
||||||
|
"github.com/ooni/probe-cli/v3/internal/netxlite"
|
||||||
"github.com/pion/stun"
|
"github.com/pion/stun"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -19,6 +21,7 @@ func TestSTUNIPLookupCanceledContext(t *testing.T) {
|
||||||
ip, err := stunIPLookup(ctx, stunConfig{
|
ip, err := stunIPLookup(ctx, stunConfig{
|
||||||
Endpoint: "stun.ekiga.net:3478",
|
Endpoint: "stun.ekiga.net:3478",
|
||||||
Logger: log.Log,
|
Logger: log.Log,
|
||||||
|
Resolver: netxlite.NewStdlibResolver(model.DiscardLogger),
|
||||||
})
|
})
|
||||||
if !errors.Is(err, context.Canceled) {
|
if !errors.Is(err, context.Canceled) {
|
||||||
t.Fatalf("not the error we expected: %+v", err)
|
t.Fatalf("not the error we expected: %+v", err)
|
||||||
|
@ -32,9 +35,11 @@ func TestSTUNIPLookupDialFailure(t *testing.T) {
|
||||||
expected := errors.New("mocked error")
|
expected := errors.New("mocked error")
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
ip, err := stunIPLookup(ctx, stunConfig{
|
ip, err := stunIPLookup(ctx, stunConfig{
|
||||||
Dial: func(network, address string) (stunClient, error) {
|
Dialer: &mocks.Dialer{
|
||||||
|
MockDialContext: func(ctx context.Context, network, address string) (net.Conn, error) {
|
||||||
return nil, expected
|
return nil, expected
|
||||||
},
|
},
|
||||||
|
},
|
||||||
Endpoint: "stun.ekiga.net:3478",
|
Endpoint: "stun.ekiga.net:3478",
|
||||||
Logger: log.Log,
|
Logger: log.Log,
|
||||||
})
|
})
|
||||||
|
@ -70,11 +75,17 @@ func TestSTUNIPLookupStartReturnsError(t *testing.T) {
|
||||||
expected := errors.New("mocked error")
|
expected := errors.New("mocked error")
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
ip, err := stunIPLookup(ctx, stunConfig{
|
ip, err := stunIPLookup(ctx, stunConfig{
|
||||||
Dial: func(network, address string) (stunClient, error) {
|
Dialer: &mocks.Dialer{
|
||||||
return MockableSTUNClient{StartErr: expected}, nil
|
MockDialContext: func(ctx context.Context, network, address string) (net.Conn, error) {
|
||||||
|
conn := &mocks.Conn{}
|
||||||
|
return conn, nil
|
||||||
|
},
|
||||||
},
|
},
|
||||||
Endpoint: "stun.ekiga.net:3478",
|
Endpoint: "stun.ekiga.net:3478",
|
||||||
Logger: log.Log,
|
Logger: log.Log,
|
||||||
|
NewClient: func(conn net.Conn) (stunClient, error) {
|
||||||
|
return MockableSTUNClient{StartErr: expected}, nil
|
||||||
|
},
|
||||||
})
|
})
|
||||||
if !errors.Is(err, expected) {
|
if !errors.Is(err, expected) {
|
||||||
t.Fatalf("not the error we expected: %+v", err)
|
t.Fatalf("not the error we expected: %+v", err)
|
||||||
|
@ -88,13 +99,19 @@ func TestSTUNIPLookupStunEventContainsError(t *testing.T) {
|
||||||
expected := errors.New("mocked error")
|
expected := errors.New("mocked error")
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
ip, err := stunIPLookup(ctx, stunConfig{
|
ip, err := stunIPLookup(ctx, stunConfig{
|
||||||
Dial: func(network, address string) (stunClient, error) {
|
Dialer: &mocks.Dialer{
|
||||||
|
MockDialContext: func(ctx context.Context, network, address string) (net.Conn, error) {
|
||||||
|
conn := &mocks.Conn{}
|
||||||
|
return conn, nil
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Endpoint: "stun.ekiga.net:3478",
|
||||||
|
Logger: log.Log,
|
||||||
|
NewClient: func(conn net.Conn) (stunClient, error) {
|
||||||
return MockableSTUNClient{Event: stun.Event{
|
return MockableSTUNClient{Event: stun.Event{
|
||||||
Error: expected,
|
Error: expected,
|
||||||
}}, nil
|
}}, nil
|
||||||
},
|
},
|
||||||
Endpoint: "stun.ekiga.net:3478",
|
|
||||||
Logger: log.Log,
|
|
||||||
})
|
})
|
||||||
if !errors.Is(err, expected) {
|
if !errors.Is(err, expected) {
|
||||||
t.Fatalf("not the error we expected: %+v", err)
|
t.Fatalf("not the error we expected: %+v", err)
|
||||||
|
@ -107,13 +124,19 @@ func TestSTUNIPLookupStunEventContainsError(t *testing.T) {
|
||||||
func TestSTUNIPLookupCannotDecodeMessage(t *testing.T) {
|
func TestSTUNIPLookupCannotDecodeMessage(t *testing.T) {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
ip, err := stunIPLookup(ctx, stunConfig{
|
ip, err := stunIPLookup(ctx, stunConfig{
|
||||||
Dial: func(network, address string) (stunClient, error) {
|
Dialer: &mocks.Dialer{
|
||||||
|
MockDialContext: func(ctx context.Context, network, address string) (net.Conn, error) {
|
||||||
|
conn := &mocks.Conn{}
|
||||||
|
return conn, nil
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Endpoint: "stun.ekiga.net:3478",
|
||||||
|
Logger: log.Log,
|
||||||
|
NewClient: func(conn net.Conn) (stunClient, error) {
|
||||||
return MockableSTUNClient{Event: stun.Event{
|
return MockableSTUNClient{Event: stun.Event{
|
||||||
Message: &stun.Message{},
|
Message: &stun.Message{},
|
||||||
}}, nil
|
}}, nil
|
||||||
},
|
},
|
||||||
Endpoint: "stun.ekiga.net:3478",
|
|
||||||
Logger: log.Log,
|
|
||||||
})
|
})
|
||||||
if !errors.Is(err, stun.ErrAttributeNotFound) {
|
if !errors.Is(err, stun.ErrAttributeNotFound) {
|
||||||
t.Fatalf("not the error we expected: %+v", err)
|
t.Fatalf("not the error we expected: %+v", err)
|
||||||
|
@ -129,6 +152,7 @@ func TestIPLookupWorksUsingSTUNEkiga(t *testing.T) {
|
||||||
http.DefaultClient,
|
http.DefaultClient,
|
||||||
log.Log,
|
log.Log,
|
||||||
model.HTTPHeaderUserAgent,
|
model.HTTPHeaderUserAgent,
|
||||||
|
netxlite.NewStdlibResolver(model.DiscardLogger),
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
|
@ -144,6 +168,7 @@ func TestIPLookupWorksUsingSTUNGoogle(t *testing.T) {
|
||||||
http.DefaultClient,
|
http.DefaultClient,
|
||||||
log.Log,
|
log.Log,
|
||||||
model.HTTPHeaderUserAgent,
|
model.HTTPHeaderUserAgent,
|
||||||
|
netxlite.NewStdlibResolver(model.DiscardLogger),
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
|
|
|
@ -19,6 +19,7 @@ func ubuntuIPLookup(
|
||||||
httpClient *http.Client,
|
httpClient *http.Client,
|
||||||
logger model.Logger,
|
logger model.Logger,
|
||||||
userAgent string,
|
userAgent string,
|
||||||
|
resolver model.Resolver,
|
||||||
) (string, error) {
|
) (string, error) {
|
||||||
data, err := (&httpx.APIClientTemplate{
|
data, err := (&httpx.APIClientTemplate{
|
||||||
BaseURL: "https://geoip.ubuntu.com/",
|
BaseURL: "https://geoip.ubuntu.com/",
|
||||||
|
|
|
@ -10,6 +10,7 @@ import (
|
||||||
|
|
||||||
"github.com/apex/log"
|
"github.com/apex/log"
|
||||||
"github.com/ooni/probe-cli/v3/internal/model"
|
"github.com/ooni/probe-cli/v3/internal/model"
|
||||||
|
"github.com/ooni/probe-cli/v3/internal/netxlite"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestUbuntuParseError(t *testing.T) {
|
func TestUbuntuParseError(t *testing.T) {
|
||||||
|
@ -23,6 +24,7 @@ func TestUbuntuParseError(t *testing.T) {
|
||||||
}},
|
}},
|
||||||
log.Log,
|
log.Log,
|
||||||
model.HTTPHeaderUserAgent,
|
model.HTTPHeaderUserAgent,
|
||||||
|
netxlite.NewStdlibResolver(model.DiscardLogger),
|
||||||
)
|
)
|
||||||
if err == nil || !strings.HasPrefix(err.Error(), "XML syntax error") {
|
if err == nil || !strings.HasPrefix(err.Error(), "XML syntax error") {
|
||||||
t.Fatalf("not the error we expected: %+v", err)
|
t.Fatalf("not the error we expected: %+v", err)
|
||||||
|
@ -38,6 +40,7 @@ func TestIPLookupWorksUsingUbuntu(t *testing.T) {
|
||||||
http.DefaultClient,
|
http.DefaultClient,
|
||||||
log.Log,
|
log.Log,
|
||||||
model.HTTPHeaderUserAgent,
|
model.HTTPHeaderUserAgent,
|
||||||
|
netxlite.NewStdlibResolver(model.DiscardLogger),
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
|
|
Loading…
Reference in New Issue
Block a user