feat(netxlite): implements NS queries (#734)
This diff has been extracted from eb0bf38957.
See https://github.com/ooni/probe/issues/2096.
While there, skip the broken tests caused by issue
https://github.com/ooni/probe/issues/2098.
This commit is contained in:
parent
c1b06a2d09
commit
ce052b665e
26 changed files with 859 additions and 75 deletions
|
|
@ -4,6 +4,7 @@ import (
|
|||
"context"
|
||||
"errors"
|
||||
"io"
|
||||
"net"
|
||||
"strings"
|
||||
"sync"
|
||||
"testing"
|
||||
|
|
@ -166,6 +167,17 @@ func TestResolverSystem(t *testing.T) {
|
|||
t.Fatal("expected nil result")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("LookupNS", func(t *testing.T) {
|
||||
r := &resolverSystem{}
|
||||
ns, err := r.LookupNS(context.Background(), "x.org")
|
||||
if !errors.Is(err, ErrNoDNSTransport) {
|
||||
t.Fatal("not the error we expected")
|
||||
}
|
||||
if ns != nil {
|
||||
t.Fatal("expected nil result")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestResolverLogger(t *testing.T) {
|
||||
|
|
@ -312,6 +324,94 @@ func TestResolverLogger(t *testing.T) {
|
|||
})
|
||||
})
|
||||
|
||||
t.Run("CloseIdleConnections", func(t *testing.T) {
|
||||
var called bool
|
||||
child := &mocks.Resolver{
|
||||
MockCloseIdleConnections: func() {
|
||||
called = true
|
||||
},
|
||||
}
|
||||
reso := &resolverLogger{
|
||||
Resolver: child,
|
||||
Logger: model.DiscardLogger,
|
||||
}
|
||||
reso.CloseIdleConnections()
|
||||
if !called {
|
||||
t.Fatal("not called")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("LookupNS", func(t *testing.T) {
|
||||
t.Run("with success", func(t *testing.T) {
|
||||
var count int
|
||||
lo := &mocks.Logger{
|
||||
MockDebugf: func(format string, v ...interface{}) {
|
||||
count++
|
||||
},
|
||||
}
|
||||
expected := []*net.NS{{
|
||||
Host: "ns1.zdns.google.",
|
||||
}}
|
||||
r := &resolverLogger{
|
||||
Logger: lo,
|
||||
Resolver: &mocks.Resolver{
|
||||
MockLookupNS: func(ctx context.Context, domain string) ([]*net.NS, error) {
|
||||
return expected, nil
|
||||
},
|
||||
MockNetwork: func() string {
|
||||
return "system"
|
||||
},
|
||||
MockAddress: func() string {
|
||||
return ""
|
||||
},
|
||||
},
|
||||
}
|
||||
ns, err := r.LookupNS(context.Background(), "dns.google")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if diff := cmp.Diff(expected, ns); diff != "" {
|
||||
t.Fatal(diff)
|
||||
}
|
||||
if count != 2 {
|
||||
t.Fatal("unexpected count")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("with failure", func(t *testing.T) {
|
||||
var count int
|
||||
lo := &mocks.Logger{
|
||||
MockDebugf: func(format string, v ...interface{}) {
|
||||
count++
|
||||
},
|
||||
}
|
||||
expected := errors.New("mocked error")
|
||||
r := &resolverLogger{
|
||||
Logger: lo,
|
||||
Resolver: &mocks.Resolver{
|
||||
MockLookupNS: func(ctx context.Context, domain string) ([]*net.NS, error) {
|
||||
return nil, expected
|
||||
},
|
||||
MockNetwork: func() string {
|
||||
return "system"
|
||||
},
|
||||
MockAddress: func() string {
|
||||
return ""
|
||||
},
|
||||
},
|
||||
}
|
||||
ns, err := r.LookupNS(context.Background(), "dns.google")
|
||||
if !errors.Is(err, expected) {
|
||||
t.Fatal("not the error we expected", err)
|
||||
}
|
||||
if ns != nil {
|
||||
t.Fatal("expected nil addr here")
|
||||
}
|
||||
if count != 2 {
|
||||
t.Fatal("unexpected count")
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
func TestResolverIDNA(t *testing.T) {
|
||||
|
|
@ -424,6 +524,63 @@ func TestResolverIDNA(t *testing.T) {
|
|||
t.Fatal("invalid address")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("CloseIdleConnections", func(t *testing.T) {
|
||||
var called bool
|
||||
child := &mocks.Resolver{
|
||||
MockCloseIdleConnections: func() {
|
||||
called = true
|
||||
},
|
||||
}
|
||||
reso := &resolverIDNA{child}
|
||||
reso.CloseIdleConnections()
|
||||
if !called {
|
||||
t.Fatal("not called")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("LookupNS", func(t *testing.T) {
|
||||
t.Run("with valid IDNA in input", func(t *testing.T) {
|
||||
expected := []*net.NS{{
|
||||
Host: "ns1.zdns.google.",
|
||||
}}
|
||||
r := &resolverIDNA{
|
||||
Resolver: &mocks.Resolver{
|
||||
MockLookupNS: func(ctx context.Context, domain string) ([]*net.NS, error) {
|
||||
if domain != "xn--d1acpjx3f.xn--p1ai" {
|
||||
return nil, errors.New("passed invalid domain")
|
||||
}
|
||||
return expected, nil
|
||||
},
|
||||
},
|
||||
}
|
||||
ctx := context.Background()
|
||||
ns, err := r.LookupNS(ctx, "яндекс.рф")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if diff := cmp.Diff(expected, ns); diff != "" {
|
||||
t.Fatal(diff)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("with invalid punycode", func(t *testing.T) {
|
||||
r := &resolverIDNA{Resolver: &mocks.Resolver{
|
||||
MockLookupNS: func(ctx context.Context, domain string) ([]*net.NS, error) {
|
||||
return nil, errors.New("should not happen")
|
||||
},
|
||||
}}
|
||||
// See https://www.farsightsecurity.com/blog/txt-record/punycode-20180711/
|
||||
ctx := context.Background()
|
||||
ns, err := r.LookupNS(ctx, "xn--0000h")
|
||||
if err == nil || !strings.HasPrefix(err.Error(), "idna: invalid label") {
|
||||
t.Fatal("not the error we expected")
|
||||
}
|
||||
if ns != nil {
|
||||
t.Fatal("expected no response here")
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
func TestResolverShortCircuitIPAddr(t *testing.T) {
|
||||
|
|
@ -520,6 +677,100 @@ func TestResolverShortCircuitIPAddr(t *testing.T) {
|
|||
}
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("LookupNS", func(t *testing.T) {
|
||||
t.Run("with IPv4 addr", func(t *testing.T) {
|
||||
r := &resolverShortCircuitIPAddr{
|
||||
Resolver: &mocks.Resolver{
|
||||
MockLookupNS: func(ctx context.Context, domain string) ([]*net.NS, error) {
|
||||
return nil, errors.New("mocked error")
|
||||
},
|
||||
},
|
||||
}
|
||||
ctx := context.Background()
|
||||
ns, err := r.LookupNS(ctx, "8.8.8.8")
|
||||
if !errors.Is(err, ErrDNSIPAddress) {
|
||||
t.Fatal("unexpected error", err)
|
||||
}
|
||||
if len(ns) > 0 {
|
||||
t.Fatal("invalid result")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("with IPv6 addr", func(t *testing.T) {
|
||||
r := &resolverShortCircuitIPAddr{
|
||||
Resolver: &mocks.Resolver{
|
||||
MockLookupNS: func(ctx context.Context, domain string) ([]*net.NS, error) {
|
||||
return nil, errors.New("mocked error")
|
||||
},
|
||||
},
|
||||
}
|
||||
ctx := context.Background()
|
||||
ns, err := r.LookupNS(ctx, "::1")
|
||||
if !errors.Is(err, ErrDNSIPAddress) {
|
||||
t.Fatal("unexpected error", err)
|
||||
}
|
||||
if len(ns) > 0 {
|
||||
t.Fatal("invalid result")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("with domain", func(t *testing.T) {
|
||||
r := &resolverShortCircuitIPAddr{
|
||||
Resolver: &mocks.Resolver{
|
||||
MockLookupNS: func(ctx context.Context, domain string) ([]*net.NS, error) {
|
||||
return nil, errors.New("mocked error")
|
||||
},
|
||||
},
|
||||
}
|
||||
ctx := context.Background()
|
||||
ns, err := r.LookupNS(ctx, "dns.google")
|
||||
if err == nil || err.Error() != "mocked error" {
|
||||
t.Fatal("not the error we expected", err)
|
||||
}
|
||||
if len(ns) > 0 {
|
||||
t.Fatal("invalid result")
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("Network", func(t *testing.T) {
|
||||
child := &mocks.Resolver{
|
||||
MockNetwork: func() string {
|
||||
return "x"
|
||||
},
|
||||
}
|
||||
reso := &resolverShortCircuitIPAddr{child}
|
||||
if reso.Network() != "x" {
|
||||
t.Fatal("invalid result")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("Address", func(t *testing.T) {
|
||||
child := &mocks.Resolver{
|
||||
MockAddress: func() string {
|
||||
return "x"
|
||||
},
|
||||
}
|
||||
reso := &resolverShortCircuitIPAddr{child}
|
||||
if reso.Address() != "x" {
|
||||
t.Fatal("invalid result")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("CloseIdleConnections", func(t *testing.T) {
|
||||
var called bool
|
||||
child := &mocks.Resolver{
|
||||
MockCloseIdleConnections: func() {
|
||||
called = true
|
||||
},
|
||||
}
|
||||
reso := &resolverShortCircuitIPAddr{child}
|
||||
reso.CloseIdleConnections()
|
||||
if !called {
|
||||
t.Fatal("not called")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestIsIPv6(t *testing.T) {
|
||||
|
|
@ -592,6 +843,18 @@ func TestNullResolver(t *testing.T) {
|
|||
}
|
||||
r.CloseIdleConnections() // for coverage
|
||||
})
|
||||
|
||||
t.Run("LookupNS", func(t *testing.T) {
|
||||
r := &nullResolver{}
|
||||
ctx := context.Background()
|
||||
ns, err := r.LookupNS(ctx, "dns.google")
|
||||
if !errors.Is(err, ErrNoResolver) {
|
||||
t.Fatal("unexpected error", err)
|
||||
}
|
||||
if len(ns) > 0 {
|
||||
t.Fatal("unexpected result")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestResolverErrWrapper(t *testing.T) {
|
||||
|
|
@ -719,4 +982,46 @@ func TestResolverErrWrapper(t *testing.T) {
|
|||
}
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("LookupNS", func(t *testing.T) {
|
||||
t.Run("on success", func(t *testing.T) {
|
||||
expected := []*net.NS{{
|
||||
Host: "antani.local.",
|
||||
}}
|
||||
reso := &resolverErrWrapper{
|
||||
Resolver: &mocks.Resolver{
|
||||
MockLookupNS: func(ctx context.Context, domain string) ([]*net.NS, error) {
|
||||
return expected, nil
|
||||
},
|
||||
},
|
||||
}
|
||||
ctx := context.Background()
|
||||
ns, err := reso.LookupNS(ctx, "antani.local")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if diff := cmp.Diff(expected, ns); diff != "" {
|
||||
t.Fatal(diff)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("on failure", func(t *testing.T) {
|
||||
expected := io.EOF
|
||||
reso := &resolverErrWrapper{
|
||||
Resolver: &mocks.Resolver{
|
||||
MockLookupNS: func(ctx context.Context, domain string) ([]*net.NS, error) {
|
||||
return nil, expected
|
||||
},
|
||||
},
|
||||
}
|
||||
ctx := context.Background()
|
||||
ns, err := reso.LookupNS(ctx, "")
|
||||
if err == nil || err.Error() != FailureEOFError {
|
||||
t.Fatal("unexpected err", err)
|
||||
}
|
||||
if len(ns) > 0 {
|
||||
t.Fatal("unexpected addrs")
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue