diff --git a/DESIGN.md b/DESIGN.md index 1c654d2..7468bc6 100644 --- a/DESIGN.md +++ b/DESIGN.md @@ -2,7 +2,7 @@ | Author | Simone Basso | |--------------|--------------| -| Last-Updated | 2019-10-29 | +| Last-Updated | 2019-10-30 | | Status | approved | ## Introduction @@ -215,7 +215,7 @@ The `ConfigureDNS` method will behave exactly like the `ConfigureDNS` method of `netx.Resolver` (see below). ```Go -func (c *Client) SetResolver(r model.DNSResolver) error +func (c *Client) SetResolver(r model.DNSResolver) ``` Also `SetResolver` is described below. @@ -324,7 +324,7 @@ func (d *Dialer) ForceSpecificSNI(sni string) error ``` ```Go -func (d *Dialer) SetResolver(r model.DNSResolver) error +func (d *Dialer) SetResolver(r model.DNSResolver) ``` `SetCABundle` and `ForceSpecificSNI` behave exactly like the same @@ -372,6 +372,16 @@ The arguments have the same meaning of `ConfigureDNS` and the will return an interface replacement for `net.Resolver` as described below. +The `ChainResolvers` function allows to chain a fallback +resolver to a primary resolver, so that the former is used +whenever the latter fails: + +```Go +func ChainResolvers( + primary, fallback model.DNSResolver +) model.DNSResolver +``` + ### The github.com/ooni/netx/x package This is for experimental stuff. diff --git a/httpx/httpx_test.go b/httpx/httpx_test.go index 56992b7..c789a74 100644 --- a/httpx/httpx_test.go +++ b/httpx/httpx_test.go @@ -2,11 +2,11 @@ package httpx_test import ( "io/ioutil" + "net" "testing" "github.com/ooni/netx/handlers" "github.com/ooni/netx/httpx" - "github.com/ooni/netx/x/nervousresolver" ) func TestIntegration(t *testing.T) { @@ -30,7 +30,7 @@ func TestIntegration(t *testing.T) { func TestIntegrationSetResolver(t *testing.T) { client := httpx.NewClient(handlers.NoHandler) defer client.Transport.CloseIdleConnections() - client.SetResolver(nervousresolver.Default) + client.SetResolver(new(net.Resolver)) resp, err := client.HTTPClient.Get("https://www.google.com") if err != nil { t.Fatal(err) diff --git a/internal/internal.go b/internal/internal.go index 1ee9734..8c23101 100644 --- a/internal/internal.go +++ b/internal/internal.go @@ -15,6 +15,7 @@ import ( "github.com/ooni/netx/internal/dialer" "github.com/ooni/netx/internal/httptransport" "github.com/ooni/netx/internal/resolver" + "github.com/ooni/netx/internal/resolver/chainresolver" "github.com/ooni/netx/model" "golang.org/x/net/http2" ) @@ -293,3 +294,9 @@ func (t *HTTPTransport) CloseIdleConnections() { tr.CloseIdleConnections() } } + +// ChainResolvers chains a primary and a secondary resolver such that +// we can fallback to the secondary if primary is broken. +func ChainResolvers(primary, secondary model.DNSResolver) model.DNSResolver { + return chainresolver.New(primary, secondary) +} diff --git a/internal/internal_test.go b/internal/internal_test.go index 263370f..281defc 100644 --- a/internal/internal_test.go +++ b/internal/internal_test.go @@ -12,6 +12,8 @@ import ( "time" "github.com/ooni/netx/handlers" + "github.com/ooni/netx/internal/resolver/brokenresolver" + "github.com/ooni/netx/internal/resolver/systemresolver" ) func TestIntegrationDial(t *testing.T) { @@ -263,6 +265,20 @@ func TestIntegration(t *testing.T) { client.CloseIdleConnections() } +func TestIntegrationChainResolvers(t *testing.T) { + dialer := NewDialer(time.Now(), handlers.NoHandler) + resolver := ChainResolvers( + brokenresolver.New(), + systemresolver.New(new(net.Resolver)), + ) + dialer.SetResolver(resolver) + conn, err := dialer.Dial("tcp", "www.google.com:80") + if err != nil { + t.Fatal(err) + } + defer conn.Close() +} + func TestIntegrationFailure(t *testing.T) { client := &http.Client{ Transport: NewHTTPTransport( diff --git a/internal/resolver/brokenresolver/brokenresolver.go b/internal/resolver/brokenresolver/brokenresolver.go new file mode 100644 index 0000000..92c8ac0 --- /dev/null +++ b/internal/resolver/brokenresolver/brokenresolver.go @@ -0,0 +1,44 @@ +// Package brokenresolver is a broken resolver +package brokenresolver + +import ( + "context" + "net" +) + +// Resolver is a broken resolver. +type Resolver struct{} + +// New creates a new broken Resolver instance. +func New() *Resolver { + return &Resolver{} +} + +var errNotFound = &net.DNSError{ + Err: "no such host", +} + +// LookupAddr returns the name of the provided IP address +func (c *Resolver) LookupAddr(ctx context.Context, addr string) ([]string, error) { + return nil, errNotFound +} + +// LookupCNAME returns the canonical name of a host +func (c *Resolver) LookupCNAME(ctx context.Context, host string) (string, error) { + return "", errNotFound +} + +// LookupHost returns the IP addresses of a host +func (c *Resolver) LookupHost(ctx context.Context, hostname string) ([]string, error) { + return nil, errNotFound +} + +// LookupMX returns the MX records of a specific name +func (c *Resolver) LookupMX(ctx context.Context, name string) ([]*net.MX, error) { + return nil, errNotFound +} + +// LookupNS returns the NS records of a specific name +func (c *Resolver) LookupNS(ctx context.Context, name string) ([]*net.NS, error) { + return nil, errNotFound +} diff --git a/internal/resolver/brokenresolver/brokenresolver_test.go b/internal/resolver/brokenresolver/brokenresolver_test.go new file mode 100644 index 0000000..9a7c935 --- /dev/null +++ b/internal/resolver/brokenresolver/brokenresolver_test.go @@ -0,0 +1,61 @@ +package brokenresolver + +import ( + "context" + "testing" +) + +func TestLookupAddr(t *testing.T) { + client := New() + names, err := client.LookupAddr(context.Background(), "8.8.8.8") + if err == nil { + t.Fatal("expected an error here") + } + if names != nil { + t.Fatal("expected nil here") + } +} + +func TestLookupCNAME(t *testing.T) { + client := New() + cname, err := client.LookupCNAME(context.Background(), "www.ooni.io") + if err == nil { + t.Fatal("expected an error here") + } + if cname != "" { + t.Fatal("expected empty string here") + } +} + +func TestLookupHost(t *testing.T) { + client := New() + addrs, err := client.LookupHost(context.Background(), "www.google.com") + if err == nil { + t.Fatal("expected an error here") + } + if addrs != nil { + t.Fatal("expected nil here") + } +} + +func TestLookupMX(t *testing.T) { + client := New() + records, err := client.LookupMX(context.Background(), "ooni.io") + if err == nil { + t.Fatal("expected an error here") + } + if records != nil { + t.Fatal("expected nil here") + } +} + +func TestLookupNS(t *testing.T) { + client := New() + records, err := client.LookupNS(context.Background(), "ooni.io") + if err == nil { + t.Fatal("expected an error here") + } + if records != nil { + t.Fatal("expected nil here") + } +} diff --git a/internal/resolver/chainresolver/chainresolver.go b/internal/resolver/chainresolver/chainresolver.go new file mode 100644 index 0000000..8845e60 --- /dev/null +++ b/internal/resolver/chainresolver/chainresolver.go @@ -0,0 +1,68 @@ +// Package chainresolver allows to chain two resolvers +package chainresolver + +import ( + "context" + "net" + + "github.com/ooni/netx/model" +) + +// Resolver is a chain resolver. +type Resolver struct { + primary model.DNSResolver + secondary model.DNSResolver +} + +// New creates a new chain Resolver instance. +func New(primary, secondary model.DNSResolver) *Resolver { + return &Resolver{ + primary: primary, + secondary: secondary, + } +} + +// LookupAddr returns the name of the provided IP address +func (c *Resolver) LookupAddr(ctx context.Context, addr string) ([]string, error) { + names, err := c.primary.LookupAddr(ctx, addr) + if err != nil { + names, err = c.secondary.LookupAddr(ctx, addr) + } + return names, err +} + +// LookupCNAME returns the canonical name of a host +func (c *Resolver) LookupCNAME(ctx context.Context, host string) (string, error) { + cname, err := c.primary.LookupCNAME(ctx, host) + if err != nil { + cname, err = c.secondary.LookupCNAME(ctx, host) + } + return cname, err +} + +// LookupHost returns the IP addresses of a host +func (c *Resolver) LookupHost(ctx context.Context, hostname string) ([]string, error) { + addrs, err := c.primary.LookupHost(ctx, hostname) + if err != nil { + addrs, err = c.secondary.LookupHost(ctx, hostname) + } + return addrs, err +} + +// LookupMX returns the MX records of a specific name +func (c *Resolver) LookupMX(ctx context.Context, name string) ([]*net.MX, error) { + records, err := c.primary.LookupMX(ctx, name) + if err != nil { + records, err = c.secondary.LookupMX(ctx, name) + } + return records, err +} + +// LookupNS returns the NS records of a specific name +func (c *Resolver) LookupNS(ctx context.Context, name string) ([]*net.NS, error) { + records, err := c.primary.LookupNS(ctx, name) + if err != nil { + records, err = c.secondary.LookupNS(ctx, name) + } + return records, err +} diff --git a/internal/resolver/chainresolver/chainresolver_test.go b/internal/resolver/chainresolver/chainresolver_test.go new file mode 100644 index 0000000..9efe2c0 --- /dev/null +++ b/internal/resolver/chainresolver/chainresolver_test.go @@ -0,0 +1,64 @@ +package chainresolver + +import ( + "context" + "net" + "testing" + + "github.com/ooni/netx/internal/resolver/brokenresolver" +) + +func TestLookupAddr(t *testing.T) { + client := New(brokenresolver.New(), new(net.Resolver)) + names, err := client.LookupAddr(context.Background(), "8.8.8.8") + if err != nil { + t.Fatal(err) + } + if names == nil { + t.Fatal("expect non nil return value here") + } +} + +func TestLookupCNAME(t *testing.T) { + client := New(brokenresolver.New(), new(net.Resolver)) + cname, err := client.LookupCNAME(context.Background(), "www.ooni.io") + if err != nil { + t.Fatal(err) + } + if cname == "" { + t.Fatal("expect non empty return value here") + } +} + +func TestLookupHost(t *testing.T) { + client := New(brokenresolver.New(), new(net.Resolver)) + addrs, err := client.LookupHost(context.Background(), "www.google.com") + if err != nil { + t.Fatal(err) + } + if addrs == nil { + t.Fatal("expect non nil return value here") + } +} + +func TestLookupMX(t *testing.T) { + client := New(brokenresolver.New(), new(net.Resolver)) + records, err := client.LookupMX(context.Background(), "ooni.io") + if err != nil { + t.Fatal(err) + } + if records == nil { + t.Fatal("expect non nil return value here") + } +} + +func TestLookupNS(t *testing.T) { + client := New(brokenresolver.New(), new(net.Resolver)) + records, err := client.LookupNS(context.Background(), "ooni.io") + if err != nil { + t.Fatal(err) + } + if records == nil { + t.Fatal("expect non nil return value here") + } +} diff --git a/internal/resolver/ooniresolver/ooniresolver_test.go b/internal/resolver/ooniresolver/ooniresolver_test.go index 6fb89a7..76677ab 100644 --- a/internal/resolver/ooniresolver/ooniresolver_test.go +++ b/internal/resolver/ooniresolver/ooniresolver_test.go @@ -26,23 +26,23 @@ func TestGettingTransport(t *testing.T) { func TestLookupAddr(t *testing.T) { client := New(newtransport()) - addrs, err := client.LookupAddr(context.Background(), "130.192.91.211") + names, err := client.LookupAddr(context.Background(), "8.8.8.8") if err == nil { t.Fatal("expected an error here") } - for _, addr := range addrs { - t.Log(addr) + if names != nil { + t.Fatal("expected nil result here") } } func TestLookupCNAME(t *testing.T) { client := New(newtransport()) - addrs, err := client.LookupCNAME(context.Background(), "www.ooni.io") + cname, err := client.LookupCNAME(context.Background(), "www.ooni.io") if err == nil { t.Fatal("expected an error here") } - for _, addr := range addrs { - t.Log(addr) + if cname != "" { + t.Fatal("expected empty result here") } } @@ -100,8 +100,8 @@ func TestLookupHost(t *testing.T) { if err != nil { t.Fatal(err) } - for _, addr := range addrs { - t.Log(addr) + if addrs == nil { + t.Fatal("expected non-nil result here") } } @@ -112,29 +112,29 @@ func TestLookupNonexistent(t *testing.T) { t.Fatal("expected an error here") } if addrs != nil { - t.Fatal("expeced nil addr here") + t.Fatal("expected nil addr here") } } func TestLookupMX(t *testing.T) { client := New(newtransport()) - addrs, err := client.LookupMX(context.Background(), "ooni.io") + records, err := client.LookupMX(context.Background(), "ooni.io") if err == nil { t.Fatal("expected an error here") } - for _, addr := range addrs { - t.Log(addr) + if records != nil { + t.Fatal("expected nil result here") } } func TestLookupNS(t *testing.T) { client := New(newtransport()) - addrs, err := client.LookupNS(context.Background(), "ooni.io") + records, err := client.LookupNS(context.Background(), "ooni.io") if err == nil { t.Fatal("expected an error here") } - for _, addr := range addrs { - t.Log(addr) + if records != nil { + t.Fatal("expected nil result here") } } diff --git a/internal/resolver/parentresolver/parentresolver_test.go b/internal/resolver/parentresolver/parentresolver_test.go index 0d9c974..a53a132 100644 --- a/internal/resolver/parentresolver/parentresolver_test.go +++ b/internal/resolver/parentresolver/parentresolver_test.go @@ -13,23 +13,23 @@ import ( func TestLookupAddr(t *testing.T) { client := New(new(net.Resolver)) - addrs, err := client.LookupAddr(context.Background(), "130.192.91.211") - if err == nil { - t.Fatal("expected an error here") + names, err := client.LookupAddr(context.Background(), "8.8.8.8") + if err != nil { + t.Fatal(err) } - for _, addr := range addrs { - t.Log(addr) + if names == nil { + t.Fatal("expected non-nil result here") } } func TestLookupCNAME(t *testing.T) { client := New(new(net.Resolver)) - addrs, err := client.LookupCNAME(context.Background(), "www.ooni.io") + cname, err := client.LookupCNAME(context.Background(), "www.ooni.io") if err != nil { t.Fatal(err) } - for _, addr := range addrs { - t.Log(addr) + if cname == "" { + t.Fatal("expected non-empty result here") } } @@ -101,22 +101,22 @@ func TestLookupHostBogon(t *testing.T) { func TestLookupMX(t *testing.T) { client := New(new(net.Resolver)) - addrs, err := client.LookupMX(context.Background(), "ooni.io") + records, err := client.LookupMX(context.Background(), "ooni.io") if err != nil { t.Fatal(err) } - for _, addr := range addrs { - t.Log(addr) + if records == nil { + t.Fatal("expected non-nil result here") } } func TestLookupNS(t *testing.T) { client := New(new(net.Resolver)) - addrs, err := client.LookupNS(context.Background(), "ooni.io") + records, err := client.LookupNS(context.Background(), "ooni.io") if err != nil { t.Fatal(err) } - for _, addr := range addrs { - t.Log(addr) + if records == nil { + t.Fatal("expected non-nil result here") } } diff --git a/internal/resolver/systemresolver/systemresolver_test.go b/internal/resolver/systemresolver/systemresolver_test.go index 3f804b7..191882c 100644 --- a/internal/resolver/systemresolver/systemresolver_test.go +++ b/internal/resolver/systemresolver/systemresolver_test.go @@ -41,23 +41,23 @@ func TestCanQuery(t *testing.T) { func TestLookupAddr(t *testing.T) { client := New(new(net.Resolver)) - addrs, err := client.LookupAddr(context.Background(), "130.192.91.211") - if err == nil { - t.Fatal("expected an error here") + names, err := client.LookupAddr(context.Background(), "8.8.8.8") + if err != nil { + t.Fatal(err) } - for _, addr := range addrs { - t.Log(addr) + if names == nil { + t.Fatal("expected non-nil result here") } } func TestLookupCNAME(t *testing.T) { client := New(new(net.Resolver)) - addrs, err := client.LookupCNAME(context.Background(), "www.ooni.io") + name, err := client.LookupCNAME(context.Background(), "www.ooni.io") if err != nil { t.Fatal(err) } - for _, addr := range addrs { - t.Log(addr) + if name == "" { + t.Fatal("expected non-empty result here") } } @@ -67,29 +67,29 @@ func TestLookupHost(t *testing.T) { if err != nil { t.Fatal(err) } - for _, addr := range addrs { - t.Log(addr) + if addrs == nil { + t.Fatal("expected non-nil result here") } } func TestLookupMX(t *testing.T) { client := New(new(net.Resolver)) - addrs, err := client.LookupMX(context.Background(), "ooni.io") + records, err := client.LookupMX(context.Background(), "ooni.io") if err != nil { t.Fatal(err) } - for _, addr := range addrs { - t.Log(addr) + if records == nil { + t.Fatal("expected non-nil result here") } } func TestLookupNS(t *testing.T) { client := New(new(net.Resolver)) - addrs, err := client.LookupNS(context.Background(), "ooni.io") + records, err := client.LookupNS(context.Background(), "ooni.io") if err != nil { t.Fatal(err) } - for _, addr := range addrs { - t.Log(addr) + if records == nil { + t.Fatal("expected non-nil result here") } } diff --git a/netx.go b/netx.go index 501fa44..308478c 100644 --- a/netx.go +++ b/netx.go @@ -121,3 +121,9 @@ func (d *Dialer) SetCABundle(path string) error { func (d *Dialer) ForceSpecificSNI(sni string) error { return d.dialer.ForceSpecificSNI(sni) } + +// ChainResolvers chains a primary and a secondary resolver such that +// we can fallback to the secondary if primary is broken. +func ChainResolvers(primary, secondary model.DNSResolver) model.DNSResolver { + return internal.ChainResolvers(primary, secondary) +} diff --git a/netx_test.go b/netx_test.go index c20759d..a38dba0 100644 --- a/netx_test.go +++ b/netx_test.go @@ -4,11 +4,12 @@ import ( "context" "crypto/x509" "errors" + "net" "testing" "github.com/ooni/netx" "github.com/ooni/netx/handlers" - "github.com/ooni/netx/x/nervousresolver" + "github.com/ooni/netx/internal/resolver/brokenresolver" ) func TestIntegrationDialer(t *testing.T) { @@ -38,7 +39,7 @@ func TestIntegrationDialer(t *testing.T) { func TestIntegrationDialerWithSetResolver(t *testing.T) { dialer := netx.NewDialer(handlers.NoHandler) - dialer.SetResolver(nervousresolver.Default) + dialer.SetResolver(new(net.Resolver)) conn, err := dialer.Dial("tcp", "www.google.com:80") if err != nil { t.Fatal(err) @@ -113,3 +114,18 @@ func TestForceSpecificSNI(t *testing.T) { t.Fatal("expected nil conn here") } } + +func TestChainResolvers(t *testing.T) { + fallback, err := netx.NewResolver(handlers.NoHandler, "udp", "1.1.1.1:53") + if err != nil { + t.Fatal(err) + } + dialer := netx.NewDialer(handlers.NoHandler) + resolver := netx.ChainResolvers(brokenresolver.New(), fallback) + dialer.SetResolver(resolver) + conn, err := dialer.Dial("tcp", "www.google.com:80") + if err != nil { + t.Fatal(err) + } + defer conn.Close() +} diff --git a/x/nervousresolver/nervousresolver.go b/x/nervousresolver/nervousresolver.go deleted file mode 100644 index 4509937..0000000 --- a/x/nervousresolver/nervousresolver.go +++ /dev/null @@ -1,141 +0,0 @@ -// Package nervousresolver contains OONI's nervous resolver -// that reacts to errors and performs actions. -// -// This package is still experimental. See LookupHost docs for -// an overview of what we're doing here. -package nervousresolver - -import ( - "context" - "fmt" - "net" - "sync/atomic" - "time" - - "github.com/m-lab/go/rtx" - "github.com/ooni/netx/handlers" - "github.com/ooni/netx/internal" - "github.com/ooni/netx/internal/transactionid" - "github.com/ooni/netx/model" - "github.com/ooni/netx/internal/resolver/bogondetector" - "github.com/ooni/netx/x/scoreboard" -) - -// Resolver is OONI's nervous resolver. -type Resolver struct { - bogonsCount int64 - primary model.DNSResolver - secondary model.DNSResolver -} - -// New creates a new OONI nervous resolver instance. -func New(primary, secondary model.DNSResolver) *Resolver { - return &Resolver{ - primary: primary, - secondary: secondary, - } -} - -// LookupAddr returns the name of the provided IP address -func (c *Resolver) LookupAddr(ctx context.Context, addr string) ([]string, error) { - return c.primary.LookupAddr(ctx, addr) -} - -// LookupCNAME returns the canonical name of a host -func (c *Resolver) LookupCNAME(ctx context.Context, host string) (cname string, err error) { - return c.primary.LookupCNAME(ctx, host) -} - -type bogonLookup struct { - Addresses []string - Comment string - Hostname string -} - -// LookupHost returns the IP addresses of a host. -// -// This code in particular checks whether the first DNS reply is -// reasonable and, if not, it will query a secondary resolver. -// -// The general idea here is that the first resolver is hopefully -// getaddrinfo and the secondary resolver is DoH/DoT. -// -// The code in here is an initial, experimental implementation of a -// design document on which we're working with Vinicius Fortuna, -// Jigsaw, aimed at significantly improving OONI measurements quality. -// -// TODO(bassosimone): integrate more ideas from the design doc. -func (c *Resolver) LookupHost(ctx context.Context, hostname string) ([]string, error) { - addrs, err := c.primary.LookupHost(ctx, hostname) - if err != nil { - return c.secondary.LookupHost(ctx, hostname) - } - for _, addr := range addrs { - if bogondetector.Check(addr) == true { - return c.detectedBogon(ctx, hostname, addrs) - } - } - return addrs, err -} - -func (c *Resolver) detectedBogon( - ctx context.Context, hostname string, addrs []string, -) ([]string, error) { - atomic.AddInt64(&c.bogonsCount, 1) - root := model.ContextMeasurementRootOrDefault(ctx) - durationSinceBeginning := time.Now().Sub(root.Beginning) - root.X.Scoreboard.AddDNSBogonInfo(scoreboard.DNSBogonInfo{ - Addresses: addrs, - DurationSinceBeginning: durationSinceBeginning, - Domain: hostname, - FallbackPlan: "ignore_and_retry_with_doh", - }) - value := bogonLookup{ - Addresses: addrs, - Comment: "detected bogon DNS reply; retry using DoH resolver", - Hostname: hostname, - } - // TODO(bassosimone): because this is a PoC, I'm using the - // extension event model. I believe there should be a specific - // first class event emitted when we see a bogon, tho. - root.Handler.OnMeasurement(model.Measurement{ - Extension: &model.ExtensionEvent{ - DurationSinceBeginning: durationSinceBeginning, - Key: fmt.Sprintf("%T", value), - Severity: "WARN", - TransactionID: transactionid.ContextTransactionID(ctx), - Value: value, - }, - }) - return c.secondary.LookupHost(ctx, hostname) -} - -// LookupMX returns the MX records of a specific name -func (c *Resolver) LookupMX(ctx context.Context, name string) ([]*net.MX, error) { - return c.primary.LookupMX(ctx, name) -} - -// LookupNS returns the NS records of a specific name -func (c *Resolver) LookupNS(ctx context.Context, name string) ([]*net.NS, error) { - return c.primary.LookupNS(ctx, name) -} - -// Default is the default nervous resolver -var Default *Resolver - -func init() { - system, err := internal.NewResolver( - time.Time{}, handlers.NoHandler, - "system", "", - ) - rtx.PanicOnError(err, "internal.NewResolver #1 failed") - // TODO(bassosimone): because this is a PoC, I'm using for - // now the address of Cloudflare. We should probably configure - // this when integrating in probe-engine. - overhttps, err := internal.NewResolver( - time.Time{}, handlers.NoHandler, - "doh", "https://1.1.1.1/dns-query", - ) - rtx.PanicOnError(err, "internal.NewResolver #2 failed") - Default = New(system, overhttps) -} diff --git a/x/nervousresolver/nervousresolver_test.go b/x/nervousresolver/nervousresolver_test.go deleted file mode 100644 index d63e75d..0000000 --- a/x/nervousresolver/nervousresolver_test.go +++ /dev/null @@ -1,130 +0,0 @@ -package nervousresolver - -import ( - "context" - "errors" - "net" - "testing" -) - -func TestIntegrationBogon(t *testing.T) { - resolver := New( - &fakeresolverbogon{ - Resolver: new(net.Resolver), - reply: []string{"10.10.11.10"}, - }, - new(net.Resolver), - ) - addrs, err := resolver.LookupHost(context.Background(), "www.kernel.org") - if err != nil { - t.Fatal(err) - } - if len(addrs) < 1 { - t.Fatal("expected an address here") - } - if resolver.bogonsCount != 1 { - t.Fatal("unexpected number of bogons seen") - } -} - -func TestIntegrationMixed(t *testing.T) { - resolver := New( - &fakeresolverbogon{ - Resolver: new(net.Resolver), - reply: []string{"10.10.11.10", "8.8.8.8"}, - }, - new(net.Resolver), - ) - addrs, err := resolver.LookupHost(context.Background(), "www.kernel.org") - if err != nil { - t.Fatal(err) - } - if len(addrs) < 1 { - t.Fatal("expected an address here") - } - if resolver.bogonsCount != 1 { - t.Fatal("unexpected number of bogons seen") - } -} - -func TestIntegrationGood(t *testing.T) { - resolver := New( - &fakeresolverbogon{ - Resolver: new(net.Resolver), - reply: []string{"8.8.8.8"}, - }, - new(net.Resolver), - ) - addrs, err := resolver.LookupHost(context.Background(), "www.kernel.org") - if err != nil { - t.Fatal(err) - } - if len(addrs) < 1 { - t.Fatal("expected an address here") - } - if resolver.bogonsCount != 0 { - t.Fatal("unexpected number of bogons seen") - } -} - -func TestIntegrationAnotherError(t *testing.T) { - resolver := New( - &fakeresolverbogon{ - Resolver: new(net.Resolver), - err: errors.New("mocked error"), - }, - new(net.Resolver), - ) - addrs, err := resolver.LookupHost(context.Background(), "www.kernel.org") - if err != nil { - t.Fatal(err) - } - if len(addrs) < 1 { - t.Fatal("expected an address here") - } - if resolver.bogonsCount != 0 { - t.Fatal("unexpected number of bogons seen") - } -} - -func TestOtherLookupMethods(t *testing.T) { - // quick because I'm just composing - resolver := New(new(net.Resolver), new(net.Resolver)) - ctx := context.Background() - t.Run("Addr", func(t *testing.T) { - names, err := resolver.LookupAddr(ctx, "8.8.8.8") - if names == nil || err != nil { - t.Fatal("unexpected result") - } - }) - t.Run("CNAME", func(t *testing.T) { - name, err := resolver.LookupCNAME(ctx, "google.com") - if name == "" || err != nil { - t.Fatal("unexpected result") - } - }) - t.Run("MX", func(t *testing.T) { - records, err := resolver.LookupMX(ctx, "google.com") - if records == nil || err != nil { - t.Fatal("unexpected result") - } - }) - t.Run("NS", func(t *testing.T) { - records, err := resolver.LookupNS(ctx, "google.com") - if records == nil || err != nil { - t.Fatal("unexpected result") - } - }) -} - -type fakeresolverbogon struct { - *net.Resolver - err error - reply []string -} - -func (c *fakeresolverbogon) LookupHost( - ctx context.Context, hostname string, -) ([]string, error) { - return c.reply, c.err -}