feat: clearly indicate which resolver we're using (#885)
See what we documented at https://github.com/ooni/spec/pull/257 Reference issue: https://github.com/ooni/probe/issues/2238 See also the related ooni/spec PR: https://github.com/ooni/spec/pull/257 See also https://github.com/ooni/probe/issues/2237 While there, bump webconnectivity@v0.5 version because this change has an impact onto the generated data format. The drop in coverage is unavoidable because we've written some tests for `measurex` to ensure we deal with DNS resolvers and transport names correctly depending on the splitting policy we use. (However, `measurex` is only used for the `tor` experiment and, per the step-by-step design document, new experiments should use `measurexlite` instead, so this is hopefully fine(TM).) While there, fix a broken integration test that does not run in `-short` mode.
This commit is contained in:
parent
c3964e43b3
commit
8a0c062844
|
@ -29,7 +29,18 @@ func TestCreateAll(t *testing.T) {
|
||||||
exp := builder.NewExperiment()
|
exp := builder.NewExperiment()
|
||||||
good := (exp.Name() == name)
|
good := (exp.Name() == name)
|
||||||
if !good {
|
if !good {
|
||||||
t.Fatal("unexpected experiment name")
|
// We have introduced the concept of versioned experiments in
|
||||||
|
// https://github.com/ooni/probe-cli/pull/882. This works like
|
||||||
|
// in brew: we append @vX.Y to the experiment name. So, here
|
||||||
|
// we're stripping the version specification and retry.
|
||||||
|
index := strings.Index(name, "@")
|
||||||
|
if index >= 0 {
|
||||||
|
name = name[:index]
|
||||||
|
if good := (exp.Name() == name); good {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
t.Fatal("unexpected experiment name", exp.Name(), name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,7 +36,7 @@ func (m *Measurer) ExperimentName() string {
|
||||||
|
|
||||||
// ExperimentVersion implements model.ExperimentMeasurer.
|
// ExperimentVersion implements model.ExperimentMeasurer.
|
||||||
func (m *Measurer) ExperimentVersion() string {
|
func (m *Measurer) ExperimentVersion() string {
|
||||||
return "0.5.1"
|
return "0.5.2"
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run implements model.ExperimentMeasurer.
|
// Run implements model.ExperimentMeasurer.
|
||||||
|
|
|
@ -11,6 +11,7 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/ooni/probe-cli/v3/internal/model"
|
"github.com/ooni/probe-cli/v3/internal/model"
|
||||||
|
"github.com/ooni/probe-cli/v3/internal/tracex"
|
||||||
)
|
)
|
||||||
|
|
||||||
// WrapDNSXRoundTripper creates a new DNSXRoundTripper that
|
// WrapDNSXRoundTripper creates a new DNSXRoundTripper that
|
||||||
|
@ -42,7 +43,7 @@ func (txp *dnsxRoundTripperDB) RoundTrip(
|
||||||
response, err := txp.DNSTransport.RoundTrip(ctx, query)
|
response, err := txp.DNSTransport.RoundTrip(ctx, query)
|
||||||
finished := time.Since(txp.begin).Seconds()
|
finished := time.Since(txp.begin).Seconds()
|
||||||
txp.db.InsertIntoDNSRoundTrip(&DNSRoundTripEvent{
|
txp.db.InsertIntoDNSRoundTrip(&DNSRoundTripEvent{
|
||||||
Network: txp.DNSTransport.Network(),
|
Network: tracex.ResolverNetworkAdaptNames(txp.DNSTransport.Network()),
|
||||||
Address: txp.DNSTransport.Address(),
|
Address: txp.DNSTransport.Address(),
|
||||||
Query: txp.maybeQueryBytes(query),
|
Query: txp.maybeQueryBytes(query),
|
||||||
Started: started,
|
Started: started,
|
||||||
|
|
47
internal/measurex/dnsx_test.go
Normal file
47
internal/measurex/dnsx_test.go
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
package measurex
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/miekg/dns"
|
||||||
|
"github.com/ooni/probe-cli/v3/internal/model/mocks"
|
||||||
|
"github.com/ooni/probe-cli/v3/internal/netxlite"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestDNSXModifiesStdlibTransportName(t *testing.T) {
|
||||||
|
// See https://github.com/ooni/spec/pull/257 for more information.
|
||||||
|
child := netxlite.NewDNSOverGetaddrinfoTransport()
|
||||||
|
mx := NewMeasurerWithDefaultSettings()
|
||||||
|
dbout := &MeasurementDB{}
|
||||||
|
txp := mx.WrapDNSXRoundTripper(dbout, child)
|
||||||
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
|
cancel() // we want to fail immediately
|
||||||
|
query := &mocks.DNSQuery{
|
||||||
|
MockDomain: func() string {
|
||||||
|
return "dns.google"
|
||||||
|
},
|
||||||
|
MockType: func() uint16 {
|
||||||
|
return dns.TypeANY
|
||||||
|
},
|
||||||
|
MockBytes: func() ([]byte, error) {
|
||||||
|
return []byte{}, nil
|
||||||
|
},
|
||||||
|
MockID: func() uint16 {
|
||||||
|
return 1453
|
||||||
|
},
|
||||||
|
}
|
||||||
|
_, _ = txp.RoundTrip(ctx, query)
|
||||||
|
measurement := dbout.AsMeasurement()
|
||||||
|
var good int
|
||||||
|
for _, rtinfo := range measurement.DNSRoundTrip {
|
||||||
|
network := rtinfo.Network
|
||||||
|
if network != netxlite.StdlibResolverSystem {
|
||||||
|
t.Fatal("unexpected network", network)
|
||||||
|
}
|
||||||
|
good++
|
||||||
|
}
|
||||||
|
if good < 1 {
|
||||||
|
t.Fatal("no good entry seen")
|
||||||
|
}
|
||||||
|
}
|
|
@ -13,6 +13,7 @@ import (
|
||||||
|
|
||||||
"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/ooni/probe-cli/v3/internal/netxlite"
|
||||||
|
"github.com/ooni/probe-cli/v3/internal/tracex"
|
||||||
)
|
)
|
||||||
|
|
||||||
// WrapResolver creates a new Resolver that saves events into the WritableDB.
|
// WrapResolver creates a new Resolver that saves events into the WritableDB.
|
||||||
|
@ -105,7 +106,7 @@ func (r *resolverDB) LookupHost(ctx context.Context, domain string) ([]string, e
|
||||||
func (r *resolverDB) saveLookupResults(domain string, started, finished float64,
|
func (r *resolverDB) saveLookupResults(domain string, started, finished float64,
|
||||||
err error, addrs []string, qtype string) {
|
err error, addrs []string, qtype string) {
|
||||||
ev := &DNSLookupEvent{
|
ev := &DNSLookupEvent{
|
||||||
Network: r.Resolver.Network(),
|
Network: tracex.ResolverNetworkAdaptNames(r.Resolver.Network()),
|
||||||
Address: r.Resolver.Address(),
|
Address: r.Resolver.Address(),
|
||||||
Failure: NewFailure(err),
|
Failure: NewFailure(err),
|
||||||
Domain: domain,
|
Domain: domain,
|
||||||
|
@ -158,7 +159,7 @@ func (r *resolverDB) LookupHTTPS(ctx context.Context, domain string) (*model.HTT
|
||||||
https, err := r.Resolver.LookupHTTPS(ctx, domain)
|
https, err := r.Resolver.LookupHTTPS(ctx, domain)
|
||||||
finished := time.Since(r.begin).Seconds()
|
finished := time.Since(r.begin).Seconds()
|
||||||
ev := &DNSLookupEvent{
|
ev := &DNSLookupEvent{
|
||||||
Network: r.Resolver.Network(),
|
Network: tracex.ResolverNetworkAdaptNames(r.Resolver.Network()),
|
||||||
Address: r.Resolver.Address(),
|
Address: r.Resolver.Address(),
|
||||||
Domain: domain,
|
Domain: domain,
|
||||||
QueryType: "HTTPS",
|
QueryType: "HTTPS",
|
||||||
|
|
58
internal/measurex/resolver_test.go
Normal file
58
internal/measurex/resolver_test.go
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
package measurex
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/ooni/probe-cli/v3/internal/model"
|
||||||
|
"github.com/ooni/probe-cli/v3/internal/netxlite"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestResolverModifiesStdlibResolverName(t *testing.T) {
|
||||||
|
// See https://github.com/ooni/spec/pull/257 for more information.
|
||||||
|
|
||||||
|
t.Run("for LookupHost", func(t *testing.T) {
|
||||||
|
child := netxlite.NewStdlibResolver(model.DiscardLogger)
|
||||||
|
mx := NewMeasurerWithDefaultSettings()
|
||||||
|
dbout := &MeasurementDB{}
|
||||||
|
txp := mx.WrapResolver(dbout, child)
|
||||||
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
|
cancel() // we want to fail immediately
|
||||||
|
_, _ = txp.LookupHost(ctx, "dns.google")
|
||||||
|
measurement := dbout.AsMeasurement()
|
||||||
|
var good int
|
||||||
|
for _, rtinfo := range measurement.LookupHost {
|
||||||
|
network := rtinfo.Network
|
||||||
|
if network != netxlite.StdlibResolverSystem {
|
||||||
|
t.Fatal("unexpected network", network)
|
||||||
|
}
|
||||||
|
good++
|
||||||
|
}
|
||||||
|
if good < 1 {
|
||||||
|
t.Fatal("no good entry seen")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("for LookupHTTPS", func(t *testing.T) {
|
||||||
|
child := netxlite.NewStdlibResolver(model.DiscardLogger)
|
||||||
|
mx := NewMeasurerWithDefaultSettings()
|
||||||
|
dbout := &MeasurementDB{}
|
||||||
|
txp := mx.WrapResolver(dbout, child)
|
||||||
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
|
cancel() // we want to fail immediately
|
||||||
|
_, _ = txp.LookupHTTPS(ctx, "dns.google")
|
||||||
|
measurement := dbout.AsMeasurement()
|
||||||
|
var good int
|
||||||
|
for _, rtinfo := range measurement.LookupHTTPSSvc {
|
||||||
|
network := rtinfo.Network
|
||||||
|
if network != netxlite.StdlibResolverSystem {
|
||||||
|
t.Fatal("unexpected network", network)
|
||||||
|
}
|
||||||
|
good++
|
||||||
|
}
|
||||||
|
if good < 1 {
|
||||||
|
t.Fatal("no good entry seen")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
|
@ -301,8 +301,12 @@ func TestNewWrappedResolvers(t *testing.T) {
|
||||||
if resolvert.tx != trace {
|
if resolvert.tx != trace {
|
||||||
t.Fatal("invalid trace")
|
t.Fatal("invalid trace")
|
||||||
}
|
}
|
||||||
if resolver.Network() != "system" {
|
switch network := resolver.Network(); network {
|
||||||
t.Fatal("unexpected resolver network")
|
case netxlite.StdlibResolverGetaddrinfo,
|
||||||
|
netxlite.StdlibResolverGolangNetResolver:
|
||||||
|
// ok
|
||||||
|
default:
|
||||||
|
t.Fatal("unexpected resolver network", network)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,6 +24,11 @@ type dnsOverGetaddrinfoTransport struct {
|
||||||
testableLookupANY func(ctx context.Context, domain string) ([]string, string, error)
|
testableLookupANY func(ctx context.Context, domain string) ([]string, string, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewDNSOverGetaddrinfoTransport creates a new dns-over-getaddrinfo transport.
|
||||||
|
func NewDNSOverGetaddrinfoTransport() model.DNSTransport {
|
||||||
|
return &dnsOverGetaddrinfoTransport{}
|
||||||
|
}
|
||||||
|
|
||||||
var _ model.DNSTransport = &dnsOverGetaddrinfoTransport{}
|
var _ model.DNSTransport = &dnsOverGetaddrinfoTransport{}
|
||||||
|
|
||||||
func (txp *dnsOverGetaddrinfoTransport) RoundTrip(
|
func (txp *dnsOverGetaddrinfoTransport) RoundTrip(
|
||||||
|
|
|
@ -47,7 +47,7 @@
|
||||||
//
|
//
|
||||||
// 1. establishing a TCP connection;
|
// 1. establishing a TCP connection;
|
||||||
//
|
//
|
||||||
// 2. performing a domain name resolution with the "system" resolver
|
// 2. performing a domain name resolution with the "stdlib" resolver
|
||||||
// (i.e., getaddrinfo on Unix) or custom DNS transports (e.g., DoT, DoH);
|
// (i.e., getaddrinfo on Unix) or custom DNS transports (e.g., DoT, DoH);
|
||||||
//
|
//
|
||||||
// 3. performing the TLS handshake;
|
// 3. performing the TLS handshake;
|
||||||
|
|
|
@ -2,6 +2,23 @@ package netxlite
|
||||||
|
|
||||||
import "errors"
|
import "errors"
|
||||||
|
|
||||||
|
// Name of the resolver we use when we link with libc and use getaddrinfo directly.
|
||||||
|
//
|
||||||
|
// See https://github.com/ooni/spec/pull/257 for more info.
|
||||||
|
const StdlibResolverGetaddrinfo = "getaddrinfo"
|
||||||
|
|
||||||
|
// Name of the resolver we use when we don't link with libc and use net.Resolver.
|
||||||
|
//
|
||||||
|
// See https://github.com/ooni/spec/pull/257 for more info.
|
||||||
|
const StdlibResolverGolangNetResolver = "golang_net_resolver"
|
||||||
|
|
||||||
|
// Legacy name of the resolver we use when we're don't know whether we're using
|
||||||
|
// getaddrinfo, but we're using net.Resolver, and we're splitting the answer
|
||||||
|
// in two A and AAAA queries. Eventually will become deprecated.
|
||||||
|
//
|
||||||
|
// See https://github.com/ooni/spec/pull/257 for more info.
|
||||||
|
const StdlibResolverSystem = "system"
|
||||||
|
|
||||||
// ErrGetaddrinfo represents a getaddrinfo failure.
|
// ErrGetaddrinfo represents a getaddrinfo failure.
|
||||||
type ErrGetaddrinfo struct {
|
type ErrGetaddrinfo struct {
|
||||||
// Err is the error proper.
|
// Err is the error proper.
|
||||||
|
|
|
@ -28,10 +28,13 @@ import (
|
||||||
// been used to implement the getaddrinfo resolver.
|
// been used to implement the getaddrinfo resolver.
|
||||||
//
|
//
|
||||||
// This is the CGO_ENABLED=1 implementation of this function, which
|
// This is the CGO_ENABLED=1 implementation of this function, which
|
||||||
// always returns the string "system", because in this scenario
|
// always returns the string [StdlibResolverGetaddrinfo], because in this scenario
|
||||||
// we are actually calling the getaddrinfo libc function.
|
// we are actually calling the getaddrinfo libc function.
|
||||||
|
//
|
||||||
|
// See https://github.com/ooni/spec/pull/257 for more information on how
|
||||||
|
// we evolved our naming of the "stdlib" resolver over time.
|
||||||
func getaddrinfoResolverNetwork() string {
|
func getaddrinfoResolverNetwork() string {
|
||||||
return "system"
|
return StdlibResolverGetaddrinfo
|
||||||
}
|
}
|
||||||
|
|
||||||
// getaddrinfoLookupANY attempts to perform an ANY lookup using getaddrinfo.
|
// getaddrinfoLookupANY attempts to perform an ANY lookup using getaddrinfo.
|
||||||
|
|
|
@ -11,13 +11,16 @@ import (
|
||||||
// been used to implement the getaddrinfo resolver.
|
// been used to implement the getaddrinfo resolver.
|
||||||
//
|
//
|
||||||
// This is the CGO_ENABLED=0 implementation of this function, which
|
// This is the CGO_ENABLED=0 implementation of this function, which
|
||||||
// always returns the string "go", because in this scenario we are actually
|
// always returns the string [StdlibResolverGolangNetResolver], because in this scenario
|
||||||
// using whatever resolver is used under the hood by the stdlib.
|
// we are actually using whatever resolver is used under the hood by the stdlib.
|
||||||
//
|
//
|
||||||
// See https://github.com/ooni/probe/issues/2029#issuecomment-1140805266
|
// See https://github.com/ooni/probe/issues/2029#issuecomment-1140805266
|
||||||
// for an explanation of why calling this resolver "netgo" is wrong.
|
// for an explanation of why calling this resolver "netgo" was wrong.
|
||||||
|
//
|
||||||
|
// See https://github.com/ooni/spec/pull/257 for additional documentation
|
||||||
|
// regarding using "golang_net_resolver" instead of "go".
|
||||||
func getaddrinfoResolverNetwork() string {
|
func getaddrinfoResolverNetwork() string {
|
||||||
return "go"
|
return StdlibResolverGolangNetResolver
|
||||||
}
|
}
|
||||||
|
|
||||||
// getaddrinfoLookupANY attempts to perform an ANY lookup using getaddrinfo.
|
// getaddrinfoLookupANY attempts to perform an ANY lookup using getaddrinfo.
|
||||||
|
|
|
@ -20,11 +20,11 @@ import (
|
||||||
|
|
||||||
// ErrNoDNSTransport is the error returned when you attempt to perform
|
// ErrNoDNSTransport is the error returned when you attempt to perform
|
||||||
// a DNS operation that requires a custom DNSTransport (e.g., DNSOverHTTPSTransport)
|
// a DNS operation that requires a custom DNSTransport (e.g., DNSOverHTTPSTransport)
|
||||||
// but you are using the "system" resolver instead.
|
// but you are using the "stdlib" resolver instead.
|
||||||
var ErrNoDNSTransport = errors.New("operation requires a DNS transport")
|
var ErrNoDNSTransport = errors.New("operation requires a DNS transport")
|
||||||
|
|
||||||
// NewStdlibResolver creates a new Resolver by combining WrapResolver
|
// NewStdlibResolver creates a new Resolver by combining WrapResolver
|
||||||
// with an internal "system" resolver type. The list of optional wrappers
|
// with an internal "stdlib" resolver type. The list of optional wrappers
|
||||||
// allow to wrap the underlying getaddrinfo transport. Any nil wrapper
|
// allow to wrap the underlying getaddrinfo transport. Any nil wrapper
|
||||||
// will be silently ignored by the code that performs the wrapping.
|
// will be silently ignored by the code that performs the wrapping.
|
||||||
func NewStdlibResolver(logger model.DebugLogger, wrappers ...model.DNSTransportWrapper) model.Resolver {
|
func NewStdlibResolver(logger model.DebugLogger, wrappers ...model.DNSTransportWrapper) model.Resolver {
|
||||||
|
@ -45,7 +45,7 @@ func NewParallelDNSOverHTTPSResolver(logger model.DebugLogger, URL string) model
|
||||||
// implies, this function returns an unwrapped resolver.
|
// implies, this function returns an unwrapped resolver.
|
||||||
func NewUnwrappedStdlibResolver(wrappers ...model.DNSTransportWrapper) model.Resolver {
|
func NewUnwrappedStdlibResolver(wrappers ...model.DNSTransportWrapper) model.Resolver {
|
||||||
return &resolverSystem{
|
return &resolverSystem{
|
||||||
t: WrapDNSTransport(&dnsOverGetaddrinfoTransport{}, wrappers...),
|
t: WrapDNSTransport(NewDNSOverGetaddrinfoTransport(), wrappers...),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -347,7 +347,7 @@ func TestResolverLogger(t *testing.T) {
|
||||||
return expected, nil
|
return expected, nil
|
||||||
},
|
},
|
||||||
MockNetwork: func() string {
|
MockNetwork: func() string {
|
||||||
return "system"
|
return StdlibResolverGetaddrinfo
|
||||||
},
|
},
|
||||||
MockAddress: func() string {
|
MockAddress: func() string {
|
||||||
return ""
|
return ""
|
||||||
|
@ -381,7 +381,7 @@ func TestResolverLogger(t *testing.T) {
|
||||||
return nil, expected
|
return nil, expected
|
||||||
},
|
},
|
||||||
MockNetwork: func() string {
|
MockNetwork: func() string {
|
||||||
return "system"
|
return StdlibResolverGetaddrinfo
|
||||||
},
|
},
|
||||||
MockAddress: func() string {
|
MockAddress: func() string {
|
||||||
return ""
|
return ""
|
||||||
|
@ -420,7 +420,7 @@ func TestResolverLogger(t *testing.T) {
|
||||||
return expected, nil
|
return expected, nil
|
||||||
},
|
},
|
||||||
MockNetwork: func() string {
|
MockNetwork: func() string {
|
||||||
return "system"
|
return StdlibResolverGetaddrinfo
|
||||||
},
|
},
|
||||||
MockAddress: func() string {
|
MockAddress: func() string {
|
||||||
return ""
|
return ""
|
||||||
|
@ -454,7 +454,7 @@ func TestResolverLogger(t *testing.T) {
|
||||||
return nil, expected
|
return nil, expected
|
||||||
},
|
},
|
||||||
MockNetwork: func() string {
|
MockNetwork: func() string {
|
||||||
return "system"
|
return StdlibResolverGetaddrinfo
|
||||||
},
|
},
|
||||||
MockAddress: func() string {
|
MockAddress: func() string {
|
||||||
return ""
|
return ""
|
||||||
|
@ -509,7 +509,7 @@ func TestResolverLogger(t *testing.T) {
|
||||||
return expected, nil
|
return expected, nil
|
||||||
},
|
},
|
||||||
MockNetwork: func() string {
|
MockNetwork: func() string {
|
||||||
return "system"
|
return StdlibResolverGetaddrinfo
|
||||||
},
|
},
|
||||||
MockAddress: func() string {
|
MockAddress: func() string {
|
||||||
return ""
|
return ""
|
||||||
|
@ -543,7 +543,7 @@ func TestResolverLogger(t *testing.T) {
|
||||||
return nil, expected
|
return nil, expected
|
||||||
},
|
},
|
||||||
MockNetwork: func() string {
|
MockNetwork: func() string {
|
||||||
return "system"
|
return StdlibResolverGetaddrinfo
|
||||||
},
|
},
|
||||||
MockAddress: func() string {
|
MockAddress: func() string {
|
||||||
return ""
|
return ""
|
||||||
|
|
|
@ -10,6 +10,7 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/ooni/probe-cli/v3/internal/model"
|
"github.com/ooni/probe-cli/v3/internal/model"
|
||||||
|
"github.com/ooni/probe-cli/v3/internal/netxlite"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ResolverSaver is a resolver that saves events.
|
// ResolverSaver is a resolver that saves events.
|
||||||
|
@ -42,7 +43,7 @@ func (r *ResolverSaver) LookupHost(ctx context.Context, hostname string) ([]stri
|
||||||
r.Saver.Write(&EventResolveStart{&EventValue{
|
r.Saver.Write(&EventResolveStart{&EventValue{
|
||||||
Address: r.Resolver.Address(),
|
Address: r.Resolver.Address(),
|
||||||
Hostname: hostname,
|
Hostname: hostname,
|
||||||
Proto: r.Resolver.Network(),
|
Proto: r.Network(),
|
||||||
Time: start,
|
Time: start,
|
||||||
}})
|
}})
|
||||||
addrs, err := r.Resolver.LookupHost(ctx, hostname)
|
addrs, err := r.Resolver.LookupHost(ctx, hostname)
|
||||||
|
@ -53,14 +54,29 @@ func (r *ResolverSaver) LookupHost(ctx context.Context, hostname string) ([]stri
|
||||||
Duration: stop.Sub(start),
|
Duration: stop.Sub(start),
|
||||||
Err: NewFailureStr(err),
|
Err: NewFailureStr(err),
|
||||||
Hostname: hostname,
|
Hostname: hostname,
|
||||||
Proto: r.Resolver.Network(),
|
Proto: r.Network(),
|
||||||
Time: stop,
|
Time: stop,
|
||||||
}})
|
}})
|
||||||
return addrs, err
|
return addrs, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ResolverNetworkAdaptNames makes sure we map the [netxlite.StdlibResolverGolangNetResolver] and
|
||||||
|
// [netxlite.StdlibResolverGetaddrinfo] resolver names to [netxlite.StdlibResolverSystem]. You MUST
|
||||||
|
// call this function when your resolver splits the "stdlib" resolver results into two fake AAAA
|
||||||
|
// and A queries rather than faking a single ANY query.
|
||||||
|
//
|
||||||
|
// See https://github.com/ooni/spec/pull/257 for more information.
|
||||||
|
func ResolverNetworkAdaptNames(input string) string {
|
||||||
|
switch input {
|
||||||
|
case netxlite.StdlibResolverGetaddrinfo, netxlite.StdlibResolverGolangNetResolver:
|
||||||
|
return netxlite.StdlibResolverSystem
|
||||||
|
default:
|
||||||
|
return input
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (r *ResolverSaver) Network() string {
|
func (r *ResolverSaver) Network() string {
|
||||||
return r.Resolver.Network()
|
return ResolverNetworkAdaptNames(r.Resolver.Network())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *ResolverSaver) Address() string {
|
func (r *ResolverSaver) Address() string {
|
||||||
|
@ -112,7 +128,7 @@ func (txp *DNSTransportSaver) RoundTrip(
|
||||||
txp.Saver.Write(&EventDNSRoundTripStart{&EventValue{
|
txp.Saver.Write(&EventDNSRoundTripStart{&EventValue{
|
||||||
Address: txp.DNSTransport.Address(),
|
Address: txp.DNSTransport.Address(),
|
||||||
DNSQuery: dnsMaybeQueryBytes(query),
|
DNSQuery: dnsMaybeQueryBytes(query),
|
||||||
Proto: txp.DNSTransport.Network(),
|
Proto: txp.Network(),
|
||||||
Time: start,
|
Time: start,
|
||||||
}})
|
}})
|
||||||
response, err := txp.DNSTransport.RoundTrip(ctx, query)
|
response, err := txp.DNSTransport.RoundTrip(ctx, query)
|
||||||
|
@ -123,14 +139,14 @@ func (txp *DNSTransportSaver) RoundTrip(
|
||||||
DNSResponse: dnsMaybeResponseBytes(response),
|
DNSResponse: dnsMaybeResponseBytes(response),
|
||||||
Duration: stop.Sub(start),
|
Duration: stop.Sub(start),
|
||||||
Err: NewFailureStr(err),
|
Err: NewFailureStr(err),
|
||||||
Proto: txp.DNSTransport.Network(),
|
Proto: txp.Network(),
|
||||||
Time: stop,
|
Time: stop,
|
||||||
}})
|
}})
|
||||||
return response, err
|
return response, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (txp *DNSTransportSaver) Network() string {
|
func (txp *DNSTransportSaver) Network() string {
|
||||||
return txp.DNSTransport.Network()
|
return ResolverNetworkAdaptNames(txp.DNSTransport.Network())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (txp *DNSTransportSaver) Address() string {
|
func (txp *DNSTransportSaver) Address() string {
|
||||||
|
|
|
@ -9,6 +9,7 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/miekg/dns"
|
||||||
"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/model/mocks"
|
||||||
"github.com/ooni/probe-cli/v3/internal/netxlite"
|
"github.com/ooni/probe-cli/v3/internal/netxlite"
|
||||||
|
@ -75,7 +76,7 @@ func TestResolverSaver(t *testing.T) {
|
||||||
reso := saver.WrapResolver(newFakeResolverWithResult(expected))
|
reso := saver.WrapResolver(newFakeResolverWithResult(expected))
|
||||||
addrs, err := reso.LookupHost(context.Background(), "www.google.com")
|
addrs, err := reso.LookupHost(context.Background(), "www.google.com")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal("expected nil error here")
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
if !reflect.DeepEqual(addrs, expected) {
|
if !reflect.DeepEqual(addrs, expected) {
|
||||||
t.Fatal("not the result we expected")
|
t.Fatal("not the result we expected")
|
||||||
|
@ -112,19 +113,56 @@ func TestResolverSaver(t *testing.T) {
|
||||||
t.Fatal("the saved time is wrong")
|
t.Fatal("the saved time is wrong")
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
t.Run("with stdlib resolver there's correct .Network remapping", func(t *testing.T) {
|
||||||
|
saver := &Saver{}
|
||||||
|
reso := saver.WrapResolver(netxlite.NewStdlibResolver(model.DiscardLogger))
|
||||||
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
|
cancel() // immediately fail the operation
|
||||||
|
_, _ = reso.LookupHost(ctx, "www.google.com")
|
||||||
|
// basically, we just want to ensure that the engine name is converted
|
||||||
|
ev := saver.Read()
|
||||||
|
if len(ev) != 2 {
|
||||||
|
t.Fatal("expected number of events")
|
||||||
|
}
|
||||||
|
if ev[0].Value().Proto != netxlite.StdlibResolverSystem {
|
||||||
|
t.Fatal("unexpected Proto")
|
||||||
|
}
|
||||||
|
if ev[1].Value().Proto != netxlite.StdlibResolverSystem {
|
||||||
|
t.Fatal("unexpected Proto")
|
||||||
|
}
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("Network", func(t *testing.T) {
|
t.Run("Network", func(t *testing.T) {
|
||||||
saver := &Saver{}
|
t.Run("when using a custom resolver", func(t *testing.T) {
|
||||||
child := &mocks.Resolver{
|
saver := &Saver{}
|
||||||
MockNetwork: func() string {
|
child := &mocks.Resolver{
|
||||||
return "x"
|
MockNetwork: func() string {
|
||||||
},
|
return "x"
|
||||||
}
|
},
|
||||||
reso := saver.WrapResolver(child)
|
}
|
||||||
if reso.Network() != "x" {
|
reso := saver.WrapResolver(child)
|
||||||
t.Fatal("unexpected result")
|
if reso.Network() != "x" {
|
||||||
}
|
t.Fatal("unexpected result")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("when using the stdlib resolver", func(t *testing.T) {
|
||||||
|
child := netxlite.NewStdlibResolver(model.DiscardLogger)
|
||||||
|
switch network := child.Network(); network {
|
||||||
|
case netxlite.StdlibResolverGetaddrinfo,
|
||||||
|
netxlite.StdlibResolverGolangNetResolver:
|
||||||
|
// ok
|
||||||
|
default:
|
||||||
|
t.Fatal("unexpected child resolver network", network)
|
||||||
|
}
|
||||||
|
saver := &Saver{}
|
||||||
|
reso := saver.WrapResolver(child)
|
||||||
|
if network := reso.Network(); network != netxlite.StdlibResolverSystem {
|
||||||
|
t.Fatal("unexpected wrapped resolver network", network)
|
||||||
|
}
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("Address", func(t *testing.T) {
|
t.Run("Address", func(t *testing.T) {
|
||||||
|
@ -326,19 +364,70 @@ func TestDNSTransportSaver(t *testing.T) {
|
||||||
t.Fatal("the saved time is wrong")
|
t.Fatal("the saved time is wrong")
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
t.Run("with getaddrinfo transport there's correct .Network remapping", func(t *testing.T) {
|
||||||
|
saver := &Saver{}
|
||||||
|
reso := saver.WrapDNSTransport(netxlite.NewDNSOverGetaddrinfoTransport())
|
||||||
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
|
cancel() // immediately fail the operation
|
||||||
|
query := &mocks.DNSQuery{
|
||||||
|
MockBytes: func() ([]byte, error) {
|
||||||
|
return []byte{}, nil
|
||||||
|
},
|
||||||
|
MockType: func() uint16 {
|
||||||
|
return dns.TypeANY
|
||||||
|
},
|
||||||
|
MockID: func() uint16 {
|
||||||
|
return 1453
|
||||||
|
},
|
||||||
|
MockDomain: func() string {
|
||||||
|
return "dns.google"
|
||||||
|
},
|
||||||
|
}
|
||||||
|
_, _ = reso.RoundTrip(ctx, query)
|
||||||
|
// basically, we just want to ensure that the engine name is converted
|
||||||
|
ev := saver.Read()
|
||||||
|
if len(ev) != 2 {
|
||||||
|
t.Fatal("expected number of events")
|
||||||
|
}
|
||||||
|
if ev[0].Value().Proto != netxlite.StdlibResolverSystem {
|
||||||
|
t.Fatal("unexpected Proto")
|
||||||
|
}
|
||||||
|
if ev[1].Value().Proto != netxlite.StdlibResolverSystem {
|
||||||
|
t.Fatal("unexpected Proto")
|
||||||
|
}
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("Network", func(t *testing.T) {
|
t.Run("Network", func(t *testing.T) {
|
||||||
saver := &Saver{}
|
t.Run("with custom child transport", func(t *testing.T) {
|
||||||
child := &mocks.DNSTransport{
|
saver := &Saver{}
|
||||||
MockNetwork: func() string {
|
child := &mocks.DNSTransport{
|
||||||
return "x"
|
MockNetwork: func() string {
|
||||||
},
|
return "x"
|
||||||
}
|
},
|
||||||
txp := saver.WrapDNSTransport(child)
|
}
|
||||||
if txp.Network() != "x" {
|
txp := saver.WrapDNSTransport(child)
|
||||||
t.Fatal("unexpected result")
|
if txp.Network() != "x" {
|
||||||
}
|
t.Fatal("unexpected result")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("when using the stdlib resolver", func(t *testing.T) {
|
||||||
|
child := netxlite.NewDNSOverGetaddrinfoTransport()
|
||||||
|
switch network := child.Network(); network {
|
||||||
|
case netxlite.StdlibResolverGetaddrinfo,
|
||||||
|
netxlite.StdlibResolverGolangNetResolver:
|
||||||
|
// ok
|
||||||
|
default:
|
||||||
|
t.Fatal("unexpected child resolver network", network)
|
||||||
|
}
|
||||||
|
saver := &Saver{}
|
||||||
|
reso := saver.WrapDNSTransport(child)
|
||||||
|
if network := reso.Network(); network != netxlite.StdlibResolverSystem {
|
||||||
|
t.Fatal("unexpected wrapped resolver network", network)
|
||||||
|
}
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("Address", func(t *testing.T) {
|
t.Run("Address", func(t *testing.T) {
|
||||||
|
@ -429,3 +518,45 @@ func newFakeResolverWithResult(r []string) model.Resolver {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestResolverNetworkAdaptNames(t *testing.T) {
|
||||||
|
type args struct {
|
||||||
|
input string
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
args args
|
||||||
|
want string
|
||||||
|
}{{
|
||||||
|
name: "with StdlibResolverGetaddrinfo",
|
||||||
|
args: args{
|
||||||
|
input: netxlite.StdlibResolverGetaddrinfo,
|
||||||
|
},
|
||||||
|
want: netxlite.StdlibResolverSystem,
|
||||||
|
}, {
|
||||||
|
name: "with StdlibResolverGolangNetResolver",
|
||||||
|
args: args{
|
||||||
|
input: netxlite.StdlibResolverGolangNetResolver,
|
||||||
|
},
|
||||||
|
want: netxlite.StdlibResolverSystem,
|
||||||
|
}, {
|
||||||
|
name: "with StdlibResolverSystem",
|
||||||
|
args: args{
|
||||||
|
input: netxlite.StdlibResolverSystem,
|
||||||
|
},
|
||||||
|
want: netxlite.StdlibResolverSystem,
|
||||||
|
}, {
|
||||||
|
name: "with any other name",
|
||||||
|
args: args{
|
||||||
|
input: "doh",
|
||||||
|
},
|
||||||
|
want: "doh",
|
||||||
|
}}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
if got := ResolverNetworkAdaptNames(tt.args.input); got != tt.want {
|
||||||
|
t.Errorf("ResolverNetworkAdaptNames() = %v, want %v", got, tt.want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -25,7 +25,7 @@ Index:
|
||||||
|
|
||||||
- [chapter04](chapter04) shows how to establish QUIC sessions;
|
- [chapter04](chapter04) shows how to establish QUIC sessions;
|
||||||
|
|
||||||
- [chapter05](chapter05) is about the "system" DNS resolver;
|
- [chapter05](chapter05) is about the "stdlib" DNS resolver;
|
||||||
|
|
||||||
- [chapter06](chapter06) discusses custom DNS-over-UDP resolvers;
|
- [chapter06](chapter06) discusses custom DNS-over-UDP resolvers;
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,13 @@
|
||||||
|
|
||||||
# Chapter I: Using the "system" DNS resolver
|
# Chapter I: Using the "stdlib" DNS resolver
|
||||||
|
|
||||||
In this chapter we will write together a `main.go` file that
|
In this chapter we will write together a `main.go` file that
|
||||||
uses the "system" DNS resolver to lookup domain names.
|
uses the "stdlib" DNS resolver to lookup domain names.
|
||||||
|
|
||||||
The "system" resolver is the one used by `getaddrinfo` on Unix.
|
The "stdlib" resolver is `getaddrinfo` on Unix. If we're compiled with
|
||||||
|
`CGO_ENABLED=1`, we use the `getaddrinfo` stdlib call directly. Otherwise,
|
||||||
|
we use the `net.Resolver` resolver, which may or may not use
|
||||||
|
`getaddrinfo` (or equivalent stdlib calls) under the hood.
|
||||||
|
|
||||||
(This file is auto-generated from the corresponding source file,
|
(This file is auto-generated from the corresponding source file,
|
||||||
so make sure you don't edit it manually.)
|
so make sure you don't edit it manually.)
|
||||||
|
@ -114,4 +117,4 @@ should cause a timeout error, because the timeout is ridicolously small.
|
||||||
|
|
||||||
## Conclusions
|
## Conclusions
|
||||||
|
|
||||||
We have seen how to use the "system" DNS resolver.
|
We have seen how to use the "stdlib" DNS resolver.
|
||||||
|
|
|
@ -1,11 +1,14 @@
|
||||||
// -=-=- StartHere -=-=-
|
// -=-=- StartHere -=-=-
|
||||||
//
|
//
|
||||||
// # Chapter I: Using the "system" DNS resolver
|
// # Chapter I: Using the "stdlib" DNS resolver
|
||||||
//
|
//
|
||||||
// In this chapter we will write together a `main.go` file that
|
// In this chapter we will write together a `main.go` file that
|
||||||
// uses the "system" DNS resolver to lookup domain names.
|
// uses the "stdlib" DNS resolver to lookup domain names.
|
||||||
//
|
//
|
||||||
// The "system" resolver is the one used by `getaddrinfo` on Unix.
|
// The "stdlib" resolver is `getaddrinfo` on Unix. If we're compiled with
|
||||||
|
// `CGO_ENABLED=1`, we use the `getaddrinfo` stdlib call directly. Otherwise,
|
||||||
|
// we use the `net.Resolver` resolver, which may or may not use
|
||||||
|
// `getaddrinfo` (or equivalent stdlib calls) under the hood.
|
||||||
//
|
//
|
||||||
// (This file is auto-generated from the corresponding source file,
|
// (This file is auto-generated from the corresponding source file,
|
||||||
// so make sure you don't edit it manually.)
|
// so make sure you don't edit it manually.)
|
||||||
|
@ -115,4 +118,4 @@ func fatal(err error) {
|
||||||
//
|
//
|
||||||
// ## Conclusions
|
// ## Conclusions
|
||||||
//
|
//
|
||||||
// We have seen how to use the "system" DNS resolver.
|
// We have seen how to use the "stdlib" DNS resolver.
|
||||||
|
|
Loading…
Reference in New Issue
Block a user