refactor: continue to simplify engine/netx (#769)

The objective of this diff is to simplify the code inside engine/netx
while moving more bits of code inside netxlite.

See https://github.com/ooni/probe/issues/2121
This commit is contained in:
Simone Basso
2022-05-31 08:11:07 +02:00
committed by GitHub
parent 3265bc670a
commit e4f10eeac2
24 changed files with 312 additions and 344 deletions
+51
View File
@@ -7,11 +7,62 @@ package netxlite
//
import (
"context"
"net"
"github.com/ooni/probe-cli/v3/internal/model"
"github.com/ooni/probe-cli/v3/internal/runtimex"
)
// BogonResolver is a bogon aware resolver. When a bogon is encountered in
// a reply, this resolver will return ErrDNSBogon.
type BogonResolver struct {
Resolver model.Resolver
}
var _ model.Resolver = &BogonResolver{}
// LookupHost implements Resolver.LookupHost
func (r *BogonResolver) LookupHost(ctx context.Context, hostname string) ([]string, error) {
addrs, err := r.Resolver.LookupHost(ctx, hostname)
if err != nil {
return nil, err
}
for _, addr := range addrs {
if IsBogon(addr) {
return nil, ErrDNSBogon
}
}
return addrs, nil
}
// LookupHTTPS implements Resolver.LookupHTTPS
func (r *BogonResolver) LookupHTTPS(ctx context.Context, hostname string) (*model.HTTPSSvc, error) {
// TODO(bassosimone): decide whether we want to implement this method or not
return nil, ErrNoDNSTransport
}
// LookupNS implements Resolver.LookupNS
func (r *BogonResolver) LookupNS(ctx context.Context, hostname string) ([]*net.NS, error) {
// TODO(bassosimone): decide whether we want to implement this method or not
return nil, ErrNoDNSTransport
}
// Network implements Resolver.Network
func (r *BogonResolver) Network() string {
return r.Resolver.Network()
}
// Address implements Resolver.Address
func (r *BogonResolver) Address() string {
return r.Resolver.Address()
}
// CloseIdleConnections implements Resolver.CloseIdleConnections
func (r *BogonResolver) CloseIdleConnections() {
r.Resolver.CloseIdleConnections()
}
// IsBogon returns whether an IP address is bogon. Passing to this
// function a non-IP address causes it to return true.
func IsBogon(address string) bool {
+135 -1
View File
@@ -1,6 +1,140 @@
package netxlite
import "testing"
import (
"context"
"errors"
"testing"
"github.com/google/go-cmp/cmp"
"github.com/ooni/probe-cli/v3/internal/model/mocks"
)
func TestBogonResolver(t *testing.T) {
t.Run("LookupHost", func(t *testing.T) {
t.Run("with failure", func(t *testing.T) {
expected := errors.New("mocked")
reso := &BogonResolver{
Resolver: &mocks.Resolver{
MockLookupHost: func(ctx context.Context, domain string) ([]string, error) {
return nil, expected
},
},
}
ctx := context.Background()
addrs, err := reso.LookupHost(ctx, "dns.google")
if !errors.Is(err, expected) {
t.Fatal("unexpected err", err)
}
if len(addrs) > 0 {
t.Fatal("expected no addrs")
}
})
t.Run("with success and no bogon", func(t *testing.T) {
expected := []string{"8.8.8.8", "149.112.112.112"}
reso := &BogonResolver{
Resolver: &mocks.Resolver{
MockLookupHost: func(ctx context.Context, domain string) ([]string, error) {
return expected, nil
},
},
}
ctx := context.Background()
addrs, err := reso.LookupHost(ctx, "dns.google")
if err != nil {
t.Fatal(err)
}
if diff := cmp.Diff(expected, addrs); diff != "" {
t.Fatal(diff)
}
})
t.Run("with success and bogon", func(t *testing.T) {
reso := &BogonResolver{
Resolver: &mocks.Resolver{
MockLookupHost: func(ctx context.Context, domain string) ([]string, error) {
return []string{"8.8.8.8", "10.34.34.35", "149.112.112.112"}, nil
},
},
}
ctx := context.Background()
addrs, err := reso.LookupHost(ctx, "dns.google")
if !errors.Is(err, ErrDNSBogon) {
t.Fatal("unexpected err", err)
}
if len(addrs) > 0 {
t.Fatal("expected no addrs")
}
})
})
t.Run("LookupHTTPS", func(t *testing.T) {
ctx := context.Background()
reso := &BogonResolver{}
https, err := reso.LookupHTTPS(ctx, "dns.google")
if !errors.Is(err, ErrNoDNSTransport) {
t.Fatal("unexpected err", err)
}
if https != nil {
t.Fatal("expected nil https here")
}
})
t.Run("LookupNS", func(t *testing.T) {
ctx := context.Background()
reso := &BogonResolver{}
ns, err := reso.LookupNS(ctx, "dns.google")
if !errors.Is(err, ErrNoDNSTransport) {
t.Fatal("unexpected err", err)
}
if len(ns) > 0 {
t.Fatal("expected empty ns here")
}
})
t.Run("Network", func(t *testing.T) {
expected := "antani"
reso := &BogonResolver{
Resolver: &mocks.Resolver{
MockNetwork: func() string {
return expected
},
},
}
if reso.Network() != expected {
t.Fatal("unexpected network")
}
})
t.Run("Address", func(t *testing.T) {
expected := "antani"
reso := &BogonResolver{
Resolver: &mocks.Resolver{
MockAddress: func() string {
return expected
},
},
}
if reso.Address() != expected {
t.Fatal("unexpected address")
}
})
t.Run("CloseIdleConnections", func(t *testing.T) {
var called bool
reso := &BogonResolver{
Resolver: &mocks.Resolver{
MockCloseIdleConnections: func() {
called = true
},
},
}
reso.CloseIdleConnections()
if !called {
t.Fatal("not called")
}
})
}
func TestIsBogon(t *testing.T) {
if IsBogon("antani") != true {
+1
View File
@@ -20,6 +20,7 @@ var (
type (
DialerResolver = dialerResolver
DialerLogger = dialerLogger
HTTPTransportWrapper = httpTransportConnectionsCloser
HTTPTransportLogger = httpTransportLogger
ErrorWrapperDialer = dialerErrWrapper
ErrorWrapperQUICListener = quicListenerErrWrapper