feat(netxlite): implement LookupHTTPS (#514)
This new API call performs DNS lookups for HTTPS records. Part of https://github.com/ooni/probe/issues/1733 and diff has been extracted from https://github.com/ooni/probe-cli/pull/506.
This commit is contained in:
parent
c6b69cbee8
commit
8b9fe1a160
13 changed files with 621 additions and 24 deletions
|
|
@ -134,6 +134,17 @@ func TestResolverSystem(t *testing.T) {
|
|||
}
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("LookupHTTPS", func(t *testing.T) {
|
||||
r := &resolverSystem{}
|
||||
https, err := r.LookupHTTPS(context.Background(), "x.org")
|
||||
if !errors.Is(err, ErrNoDNSTransport) {
|
||||
t.Fatal("not the error we expected")
|
||||
}
|
||||
if https != nil {
|
||||
t.Fatal("expected nil result")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestResolverLogger(t *testing.T) {
|
||||
|
|
@ -206,6 +217,80 @@ func TestResolverLogger(t *testing.T) {
|
|||
}
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("LookupHTTPS", 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 := &HTTPSSvc{
|
||||
ALPN: []string{"h3"},
|
||||
IPv4: []string{"1.1.1.1"},
|
||||
}
|
||||
r := &resolverLogger{
|
||||
Logger: lo,
|
||||
Resolver: &mocks.Resolver{
|
||||
MockLookupHTTPS: func(ctx context.Context, domain string) (*HTTPSSvc, error) {
|
||||
return expected, nil
|
||||
},
|
||||
MockNetwork: func() string {
|
||||
return "system"
|
||||
},
|
||||
MockAddress: func() string {
|
||||
return ""
|
||||
},
|
||||
},
|
||||
}
|
||||
https, err := r.LookupHTTPS(context.Background(), "dns.google")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if diff := cmp.Diff(expected, https); 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{
|
||||
MockLookupHTTPS: func(ctx context.Context, domain string) (*HTTPSSvc, error) {
|
||||
return nil, expected
|
||||
},
|
||||
MockNetwork: func() string {
|
||||
return "system"
|
||||
},
|
||||
MockAddress: func() string {
|
||||
return ""
|
||||
},
|
||||
},
|
||||
}
|
||||
https, err := r.LookupHTTPS(context.Background(), "dns.google")
|
||||
if !errors.Is(err, expected) {
|
||||
t.Fatal("not the error we expected", err)
|
||||
}
|
||||
if https != nil {
|
||||
t.Fatal("expected nil addr here")
|
||||
}
|
||||
if count != 2 {
|
||||
t.Fatal("unexpected count")
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
func TestResolverIDNA(t *testing.T) {
|
||||
|
|
@ -249,6 +334,51 @@ func TestResolverIDNA(t *testing.T) {
|
|||
}
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("LookupHTTPS", func(t *testing.T) {
|
||||
t.Run("with valid IDNA in input", func(t *testing.T) {
|
||||
expected := &HTTPSSvc{
|
||||
ALPN: []string{"h3"},
|
||||
IPv4: []string{"1.1.1.1"},
|
||||
IPv6: []string{},
|
||||
}
|
||||
r := &resolverIDNA{
|
||||
Resolver: &mocks.Resolver{
|
||||
MockLookupHTTPS: func(ctx context.Context, domain string) (*HTTPSSvc, error) {
|
||||
if domain != "xn--d1acpjx3f.xn--p1ai" {
|
||||
return nil, errors.New("passed invalid domain")
|
||||
}
|
||||
return expected, nil
|
||||
},
|
||||
},
|
||||
}
|
||||
ctx := context.Background()
|
||||
https, err := r.LookupHTTPS(ctx, "яндекс.рф")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if diff := cmp.Diff(expected, https); diff != "" {
|
||||
t.Fatal(diff)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("with invalid punycode", func(t *testing.T) {
|
||||
r := &resolverIDNA{Resolver: &mocks.Resolver{
|
||||
MockLookupHTTPS: func(ctx context.Context, domain string) (*HTTPSSvc, error) {
|
||||
return nil, errors.New("should not happen")
|
||||
},
|
||||
}}
|
||||
// See https://www.farsightsecurity.com/blog/txt-record/punycode-20180711/
|
||||
ctx := context.Background()
|
||||
https, err := r.LookupHTTPS(ctx, "xn--0000h")
|
||||
if err == nil || !strings.HasPrefix(err.Error(), "idna: invalid label") {
|
||||
t.Fatal("not the error we expected")
|
||||
}
|
||||
if https != nil {
|
||||
t.Fatal("expected no response here")
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
func TestResolverShortCircuitIPAddr(t *testing.T) {
|
||||
|
|
@ -292,22 +422,43 @@ func TestResolverShortCircuitIPAddr(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestNullResolver(t *testing.T) {
|
||||
r := &nullResolver{}
|
||||
ctx := context.Background()
|
||||
addrs, err := r.LookupHost(ctx, "dns.google")
|
||||
if !errors.Is(err, ErrNoResolver) {
|
||||
t.Fatal("not the error we expected", err)
|
||||
}
|
||||
if addrs != nil {
|
||||
t.Fatal("expected nil addr")
|
||||
}
|
||||
if r.Network() != "null" {
|
||||
t.Fatal("invalid network")
|
||||
}
|
||||
if r.Address() != "" {
|
||||
t.Fatal("invalid address")
|
||||
}
|
||||
r.CloseIdleConnections() // for coverage
|
||||
t.Run("LookupHost", func(t *testing.T) {
|
||||
r := &nullResolver{}
|
||||
ctx := context.Background()
|
||||
addrs, err := r.LookupHost(ctx, "dns.google")
|
||||
if !errors.Is(err, ErrNoResolver) {
|
||||
t.Fatal("not the error we expected", err)
|
||||
}
|
||||
if addrs != nil {
|
||||
t.Fatal("expected nil addr")
|
||||
}
|
||||
if r.Network() != "null" {
|
||||
t.Fatal("invalid network")
|
||||
}
|
||||
if r.Address() != "" {
|
||||
t.Fatal("invalid address")
|
||||
}
|
||||
r.CloseIdleConnections() // for coverage
|
||||
})
|
||||
|
||||
t.Run("LookupHTTPS", func(t *testing.T) {
|
||||
r := &nullResolver{}
|
||||
ctx := context.Background()
|
||||
addrs, err := r.LookupHTTPS(ctx, "dns.google")
|
||||
if !errors.Is(err, ErrNoResolver) {
|
||||
t.Fatal("not the error we expected", err)
|
||||
}
|
||||
if addrs != nil {
|
||||
t.Fatal("expected nil addr")
|
||||
}
|
||||
if r.Network() != "null" {
|
||||
t.Fatal("invalid network")
|
||||
}
|
||||
if r.Address() != "" {
|
||||
t.Fatal("invalid address")
|
||||
}
|
||||
r.CloseIdleConnections() // for coverage
|
||||
})
|
||||
}
|
||||
|
||||
func TestResolverErrWrapper(t *testing.T) {
|
||||
|
|
@ -393,4 +544,46 @@ func TestResolverErrWrapper(t *testing.T) {
|
|||
t.Fatal("not called")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("LookupHTTPS", func(t *testing.T) {
|
||||
t.Run("on success", func(t *testing.T) {
|
||||
expected := &HTTPSSvc{
|
||||
ALPN: []string{"h3"},
|
||||
}
|
||||
reso := &resolverErrWrapper{
|
||||
Resolver: &mocks.Resolver{
|
||||
MockLookupHTTPS: func(ctx context.Context, domain string) (*HTTPSSvc, error) {
|
||||
return expected, nil
|
||||
},
|
||||
},
|
||||
}
|
||||
ctx := context.Background()
|
||||
https, err := reso.LookupHTTPS(ctx, "")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if diff := cmp.Diff(expected, https); diff != "" {
|
||||
t.Fatal(diff)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("on failure", func(t *testing.T) {
|
||||
expected := io.EOF
|
||||
reso := &resolverErrWrapper{
|
||||
Resolver: &mocks.Resolver{
|
||||
MockLookupHTTPS: func(ctx context.Context, domain string) (*HTTPSSvc, error) {
|
||||
return nil, expected
|
||||
},
|
||||
},
|
||||
}
|
||||
ctx := context.Background()
|
||||
https, err := reso.LookupHTTPS(ctx, "")
|
||||
if err == nil || err.Error() != errorsx.FailureEOFError {
|
||||
t.Fatal("unexpected err", err)
|
||||
}
|
||||
if https != nil {
|
||||
t.Fatal("unexpected addrs")
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue