Skip to content

Commit

Permalink
feat(netxlite): implements NS queries
Browse files Browse the repository at this point in the history
This diff has been extracted from bassosimone/websteps-illustrated@eb0bf38.

See ooni/probe#2096.

While there, skip the broken tests caused by issue
ooni/probe#2098.
  • Loading branch information
bassosimone committed May 16, 2022
1 parent c1b06a2 commit 85892bf
Show file tree
Hide file tree
Showing 26 changed files with 859 additions and 75 deletions.
1 change: 1 addition & 0 deletions internal/cmd/apitool/main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ func init() {
}

func TestCheck(t *testing.T) {
t.Skip("see https://github.com/ooni/probe/issues/2098")
*mode = "check"
main()
}
Expand Down
5 changes: 5 additions & 0 deletions internal/cmd/jafar/uncensored/uncensored.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,11 @@ func (c *Client) LookupHTTPS(ctx context.Context, domain string) (*model.HTTPSSv
return nil, errors.New("not implemented")
}

// LookupNS implements model.Resolver.LookupNS.
func (c *Client) LookupNS(ctx context.Context, domain string) ([]*net.NS, error) {
return nil, errors.New("not implemented")
}

// Network implements Resolver.Network
func (c *Client) Network() string {
return c.dnsClient.Network()
Expand Down
4 changes: 4 additions & 0 deletions internal/cmd/oohelper/internal/fake_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,10 @@ func (c FakeResolver) LookupHTTPS(ctx context.Context, domain string) (*model.HT
return nil, errors.New("not implemented")
}

func (c FakeResolver) LookupNS(ctx context.Context, domain string) ([]*net.NS, error) {
return nil, errors.New("not implemented")
}

var _ model.Resolver = FakeResolver{}

type FakeTransport struct {
Expand Down
4 changes: 4 additions & 0 deletions internal/cmd/oohelperd/internal/webconnectivity/fake_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,10 @@ func (c FakeResolver) LookupHTTPS(ctx context.Context, domain string) (*model.HT
return nil, errors.New("not implemented")
}

func (c FakeResolver) LookupNS(ctx context.Context, domain string) ([]*net.NS, error) {
return nil, errors.New("not implemented")
}

var _ model.Resolver = FakeResolver{}

type FakeTransport struct {
Expand Down
10 changes: 9 additions & 1 deletion internal/engine/internal/sessionresolver/sessionresolver.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import (
"errors"
"fmt"
"math/rand"
"net"
"net/url"
"sync"
"time"
Expand Down Expand Up @@ -110,9 +111,16 @@ func (r *Resolver) Stats() string {
return fmt.Sprintf("sessionresolver: %s", string(data))
}

var errNotImplemented = errors.New("not implemented")

// LookupHTTPS implements Resolver.LookupHTTPS.
func (r *Resolver) LookupHTTPS(ctx context.Context, domain string) (*model.HTTPSSvc, error) {
return nil, errors.New("not implemented")
return nil, errNotImplemented
}

// LookupNS implements Resolver.LookupNS.
func (r *Resolver) LookupNS(ctx context.Context, domain string) ([]*net.NS, error) {
return nil, errNotImplemented
}

// ErrLookupHost indicates that LookupHost failed.
Expand Down
24 changes: 24 additions & 0 deletions internal/engine/internal/sessionresolver/sessionresolver_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -343,3 +343,27 @@ func TestShouldSkipWithProxyWorks(t *testing.T) {
}
}
}

func TestUnimplementedFunctions(t *testing.T) {
t.Run("LookupHTTPS", func(t *testing.T) {
r := &Resolver{}
https, err := r.LookupHTTPS(context.Background(), "dns.google")
if !errors.Is(err, errNotImplemented) {
t.Fatal("unexpected error", err)
}
if https != nil {
t.Fatal("expected nil result")
}
})

t.Run("LookupNS", func(t *testing.T) {
r := &Resolver{}
ns, err := r.LookupNS(context.Background(), "dns.google")
if !errors.Is(err, errNotImplemented) {
t.Fatal("unexpected error", err)
}
if len(ns) > 0 {
t.Fatal("expected empty result")
}
})
}
2 changes: 1 addition & 1 deletion internal/engine/netx/resolver/cache.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ func (r *CacheResolver) LookupHost(
if err != nil {
return nil, err
}
if r.ReadOnly == false {
if !r.ReadOnly {
r.Set(hostname, entry)
}
return entry, nil
Expand Down
18 changes: 5 additions & 13 deletions internal/engine/netx/resolver/cache_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,11 @@ import (
"testing"

"github.com/ooni/probe-cli/v3/internal/engine/netx/resolver"
"github.com/ooni/probe-cli/v3/internal/model"
)

func TestCacheFailure(t *testing.T) {
expected := errors.New("mocked error")
var r model.Resolver = resolver.FakeResolver{
Err: expected,
}
r := resolver.NewFakeResolverWithExplicitError(expected)
cache := &resolver.CacheResolver{Resolver: r}
addrs, err := cache.LookupHost(context.Background(), "www.google.com")
if !errors.Is(err, expected) {
Expand All @@ -28,9 +25,8 @@ func TestCacheFailure(t *testing.T) {
}

func TestCacheHitSuccess(t *testing.T) {
var r model.Resolver = resolver.FakeResolver{
Err: errors.New("mocked error"),
}
expected := errors.New("mocked error")
r := resolver.NewFakeResolverWithExplicitError(expected)
cache := &resolver.CacheResolver{Resolver: r}
cache.Set("dns.google.com", []string{"8.8.8.8"})
addrs, err := cache.LookupHost(context.Background(), "dns.google.com")
Expand All @@ -43,9 +39,7 @@ func TestCacheHitSuccess(t *testing.T) {
}

func TestCacheMissSuccess(t *testing.T) {
var r model.Resolver = resolver.FakeResolver{
Result: []string{"8.8.8.8"},
}
r := resolver.NewFakeResolverWithResult([]string{"8.8.8.8"})
cache := &resolver.CacheResolver{Resolver: r}
addrs, err := cache.LookupHost(context.Background(), "dns.google.com")
if err != nil {
Expand All @@ -60,9 +54,7 @@ func TestCacheMissSuccess(t *testing.T) {
}

func TestCacheReadonlySuccess(t *testing.T) {
var r model.Resolver = resolver.FakeResolver{
Result: []string{"8.8.8.8"},
}
r := resolver.NewFakeResolverWithResult([]string{"8.8.8.8"})
cache := &resolver.CacheResolver{Resolver: r, ReadOnly: true}
addrs, err := cache.LookupHost(context.Background(), "dns.google.com")
if err != nil {
Expand Down
91 changes: 49 additions & 42 deletions internal/engine/netx/resolver/fake_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,10 @@ import (
"net"
"time"

"github.com/ooni/probe-cli/v3/internal/atomicx"
"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/ooni/probe-cli/v3/internal/runtimex"
)

type FakeDialer struct {
Expand Down Expand Up @@ -108,48 +110,53 @@ func (fe FakeEncoder) Encode(domain string, qtype uint16, padding bool) ([]byte,
return fe.Data, fe.Err
}

type FakeResolver struct {
NumFailures *atomicx.Int64
Err error
Result []string
}

func NewFakeResolverThatFails() FakeResolver {
return FakeResolver{NumFailures: &atomicx.Int64{}, Err: errNotFound}
}

func NewFakeResolverWithResult(r []string) FakeResolver {
return FakeResolver{NumFailures: &atomicx.Int64{}, Result: r}
}

var errNotFound = &net.DNSError{
Err: "no such host",
}

func (c FakeResolver) LookupHost(ctx context.Context, hostname string) ([]string, error) {
time.Sleep(10 * time.Microsecond)
if c.Err != nil {
if c.NumFailures != nil {
c.NumFailures.Add(1)
}
return nil, c.Err
func NewFakeResolverThatFails() model.Resolver {
return NewFakeResolverWithExplicitError(netxlite.ErrOODNSNoSuchHost)
}

func NewFakeResolverWithExplicitError(err error) model.Resolver {
runtimex.PanicIfNil(err, "passed nil error")
return &mocks.Resolver{
MockLookupHost: func(ctx context.Context, domain string) ([]string, error) {
return nil, err
},
MockNetwork: func() string {
return "fake"
},
MockAddress: func() string {
return ""
},
MockCloseIdleConnections: func() {
// nothing
},
MockLookupHTTPS: func(ctx context.Context, domain string) (*model.HTTPSSvc, error) {
return nil, errors.New("not implemented")
},
MockLookupNS: func(ctx context.Context, domain string) ([]*net.NS, error) {
return nil, errors.New("not implemented")
},
}
return c.Result, nil
}

func (c FakeResolver) Network() string {
return "fake"
}

func (c FakeResolver) Address() string {
return ""
}

func (c FakeResolver) CloseIdleConnections() {}

func (c FakeResolver) LookupHTTPS(
ctx context.Context, domain string) (*model.HTTPSSvc, error) {
return nil, errors.New("not implemented")
func NewFakeResolverWithResult(r []string) model.Resolver {
return &mocks.Resolver{
MockLookupHost: func(ctx context.Context, domain string) ([]string, error) {
return r, nil
},
MockNetwork: func() string {
return "fake"
},
MockAddress: func() string {
return ""
},
MockCloseIdleConnections: func() {
// nothing
},
MockLookupHTTPS: func(ctx context.Context, domain string) (*model.HTTPSSvc, error) {
return nil, errors.New("not implemented")
},
MockLookupNS: func(ctx context.Context, domain string) ([]*net.NS, error) {
return nil, errors.New("not implemented")
},
}
}

var _ model.Resolver = FakeResolver{}
12 changes: 4 additions & 8 deletions internal/engine/netx/resolver/saver_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,8 @@ func TestSaverResolverFailure(t *testing.T) {
expected := errors.New("no such host")
saver := &trace.Saver{}
reso := resolver.SaverResolver{
Resolver: resolver.FakeResolver{
Err: expected,
},
Saver: saver,
Resolver: resolver.NewFakeResolverWithExplicitError(expected),
Saver: saver,
}
addrs, err := reso.LookupHost(context.Background(), "www.google.com")
if !errors.Is(err, expected) {
Expand Down Expand Up @@ -65,10 +63,8 @@ func TestSaverResolverSuccess(t *testing.T) {
expected := []string{"8.8.8.8", "8.8.4.4"}
saver := &trace.Saver{}
reso := resolver.SaverResolver{
Resolver: resolver.FakeResolver{
Result: expected,
},
Saver: saver,
Resolver: resolver.NewFakeResolverWithResult(expected),
Saver: saver,
}
addrs, err := reso.LookupHost(context.Background(), "www.google.com")
if err != nil {
Expand Down
1 change: 1 addition & 0 deletions internal/engine/probeservices/checkreportid_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
)

func TestCheckReportIDWorkingAsIntended(t *testing.T) {
t.Skip("see https://github.com/ooni/probe/issues/2098")
client := probeservices.Client{
APIClientTemplate: httpx.APIClientTemplate{
BaseURL: "https://ams-pg.ooni.org/",
Expand Down
14 changes: 10 additions & 4 deletions internal/model/mocks/dnsdecoder.go
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
package mocks

import (
"net"

"github.com/miekg/dns"
"github.com/ooni/probe-cli/v3/internal/model"
)

// DNSDecoder allows mocking dnsx.DNSDecoder.
type DNSDecoder struct {
MockDecodeLookupHost func(qtype uint16, reply []byte, queryID uint16) ([]string, error)

MockDecodeHTTPS func(reply []byte, queryID uint16) (*model.HTTPSSvc, error)

MockDecodeReply func(reply []byte) (*dns.Msg, error)
MockDecodeHTTPS func(reply []byte, queryID uint16) (*model.HTTPSSvc, error)
MockDecodeNS func(reply []byte, queryID uint16) ([]*net.NS, error)
MockDecodeReply func(reply []byte) (*dns.Msg, error)
}

// DecodeLookupHost calls MockDecodeLookupHost.
Expand All @@ -24,6 +25,11 @@ func (e *DNSDecoder) DecodeHTTPS(reply []byte, queryID uint16) (*model.HTTPSSvc,
return e.MockDecodeHTTPS(reply, queryID)
}

// DecodeNS calls MockDecodeNS.
func (e *DNSDecoder) DecodeNS(reply []byte, queryID uint16) ([]*net.NS, error) {
return e.MockDecodeNS(reply, queryID)
}

// DecodeReply calls MockDecodeReply.
func (e *DNSDecoder) DecodeReply(reply []byte) (*dns.Msg, error) {
return e.MockDecodeReply(reply)
Expand Down
17 changes: 17 additions & 0 deletions internal/model/mocks/dnsdecoder_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package mocks

import (
"errors"
"net"
"testing"

"github.com/miekg/dns"
Expand Down Expand Up @@ -41,6 +42,22 @@ func TestDNSDecoder(t *testing.T) {
}
})

t.Run("DecodeNS", func(t *testing.T) {
expected := errors.New("mocked error")
e := &DNSDecoder{
MockDecodeNS: func(reply []byte, queryID uint16) ([]*net.NS, error) {
return nil, expected
},
}
out, err := e.DecodeNS(make([]byte, 17), dns.Id())
if !errors.Is(err, expected) {
t.Fatal("unexpected err", err)
}
if out != nil {
t.Fatal("unexpected out")
}
})

t.Run("DecodeReply", func(t *testing.T) {
expected := errors.New("mocked error")
e := &DNSDecoder{
Expand Down
7 changes: 7 additions & 0 deletions internal/model/mocks/resolver.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package mocks

import (
"context"
"net"

"github.com/ooni/probe-cli/v3/internal/model"
)
Expand All @@ -13,6 +14,7 @@ type Resolver struct {
MockAddress func() string
MockCloseIdleConnections func()
MockLookupHTTPS func(ctx context.Context, domain string) (*model.HTTPSSvc, error)
MockLookupNS func(ctx context.Context, domain string) ([]*net.NS, error)
}

// LookupHost calls MockLookupHost.
Expand All @@ -39,3 +41,8 @@ func (r *Resolver) CloseIdleConnections() {
func (r *Resolver) LookupHTTPS(ctx context.Context, domain string) (*model.HTTPSSvc, error) {
return r.MockLookupHTTPS(ctx, domain)
}

// LookupNS calls MockLookupNS.
func (r *Resolver) LookupNS(ctx context.Context, domain string) ([]*net.NS, error) {
return r.MockLookupNS(ctx, domain)
}
Loading

0 comments on commit 85892bf

Please sign in to comment.