fix(nextlite): wrap DNSDecoder errors (#962)

The simplest fix is to wrap such errors in dnsdecoder.go.

Fixes https://github.com/ooni/probe/issues/2317.
This commit is contained in:
Simone Basso 2022-09-14 13:47:20 +02:00 committed by GitHub
parent 550b602a00
commit 7ee9f096d1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 65 additions and 16 deletions

View File

@ -23,17 +23,22 @@ var (
ErrDNSIsQuery = errors.New("ooresolver: expected response but received query") ErrDNSIsQuery = errors.New("ooresolver: expected response but received query")
) )
// dnsDecoderWrapError ensures we wrap the returned errors
func dnsDecoderWrapError(err error) error {
return MaybeNewErrWrapper(ClassifyResolverError, ResolveOperation, err)
}
// DecodeResponse implements model.DNSDecoder.DecodeResponse. // DecodeResponse implements model.DNSDecoder.DecodeResponse.
func (d *DNSDecoderMiekg) DecodeResponse(data []byte, query model.DNSQuery) (model.DNSResponse, error) { func (d *DNSDecoderMiekg) DecodeResponse(data []byte, query model.DNSQuery) (model.DNSResponse, error) {
reply := &dns.Msg{} reply := &dns.Msg{}
if err := reply.Unpack(data); err != nil { if err := reply.Unpack(data); err != nil {
return nil, err return nil, dnsDecoderWrapError(err)
} }
if !reply.Response { if !reply.Response {
return nil, ErrDNSIsQuery return nil, dnsDecoderWrapError(ErrDNSIsQuery)
} }
if reply.Id != query.ID() { if reply.Id != query.ID() {
return nil, ErrDNSReplyWithWrongQueryID return nil, dnsDecoderWrapError(ErrDNSReplyWithWrongQueryID)
} }
resp := &dnsResponse{ resp := &dnsResponse{
bytes: data, bytes: data,
@ -77,20 +82,20 @@ func (r *dnsResponse) rcodeToError() error {
case dns.RcodeSuccess: case dns.RcodeSuccess:
return nil return nil
case dns.RcodeNameError: case dns.RcodeNameError:
return ErrOODNSNoSuchHost return dnsDecoderWrapError(ErrOODNSNoSuchHost)
case dns.RcodeRefused: case dns.RcodeRefused:
return ErrOODNSRefused return dnsDecoderWrapError(ErrOODNSRefused)
case dns.RcodeServerFailure: case dns.RcodeServerFailure:
return ErrOODNSServfail return dnsDecoderWrapError(ErrOODNSServfail)
default: default:
return ErrOODNSMisbehaving return dnsDecoderWrapError(ErrOODNSMisbehaving)
} }
} }
// DecodeHTTPS implements model.DNSResponse.DecodeHTTPS. // DecodeHTTPS implements model.DNSResponse.DecodeHTTPS.
func (r *dnsResponse) DecodeHTTPS() (*model.HTTPSSvc, error) { func (r *dnsResponse) DecodeHTTPS() (*model.HTTPSSvc, error) {
if err := r.rcodeToError(); err != nil { if err := r.rcodeToError(); err != nil {
return nil, err return nil, err // error already wrapped
} }
out := &model.HTTPSSvc{ out := &model.HTTPSSvc{
ALPN: []string{}, // ensure it's not nil ALPN: []string{}, // ensure it's not nil
@ -117,7 +122,7 @@ func (r *dnsResponse) DecodeHTTPS() (*model.HTTPSSvc, error) {
} }
} }
if len(out.IPv4) <= 0 && len(out.IPv6) <= 0 { if len(out.IPv4) <= 0 && len(out.IPv6) <= 0 {
return nil, ErrOODNSNoAnswer return nil, dnsDecoderWrapError(ErrOODNSNoAnswer)
} }
return out, nil return out, nil
} }
@ -125,7 +130,7 @@ func (r *dnsResponse) DecodeHTTPS() (*model.HTTPSSvc, error) {
// DecodeLookupHost implements model.DNSResponse.DecodeLookupHost. // DecodeLookupHost implements model.DNSResponse.DecodeLookupHost.
func (r *dnsResponse) DecodeLookupHost() ([]string, error) { func (r *dnsResponse) DecodeLookupHost() ([]string, error) {
if err := r.rcodeToError(); err != nil { if err := r.rcodeToError(); err != nil {
return nil, err return nil, err // error already wrapped
} }
var addrs []string var addrs []string
for _, answer := range r.msg.Answer { for _, answer := range r.msg.Answer {
@ -143,7 +148,7 @@ func (r *dnsResponse) DecodeLookupHost() ([]string, error) {
} }
} }
if len(addrs) <= 0 { if len(addrs) <= 0 {
return nil, ErrOODNSNoAnswer return nil, dnsDecoderWrapError(ErrOODNSNoAnswer)
} }
return addrs, nil return addrs, nil
} }
@ -151,7 +156,7 @@ func (r *dnsResponse) DecodeLookupHost() ([]string, error) {
// DecodeNS implements model.DNSResponse.DecodeNS. // DecodeNS implements model.DNSResponse.DecodeNS.
func (r *dnsResponse) DecodeNS() ([]*net.NS, error) { func (r *dnsResponse) DecodeNS() ([]*net.NS, error) {
if err := r.rcodeToError(); err != nil { if err := r.rcodeToError(); err != nil {
return nil, err return nil, err // error already wrapped
} }
out := []*net.NS{} out := []*net.NS{}
for _, answer := range r.msg.Answer { for _, answer := range r.msg.Answer {
@ -161,7 +166,7 @@ func (r *dnsResponse) DecodeNS() ([]*net.NS, error) {
} }
} }
if len(out) < 1 { if len(out) < 1 {
return nil, ErrOODNSNoAnswer return nil, dnsDecoderWrapError(ErrOODNSNoAnswer)
} }
return out, nil return out, nil
} }
@ -169,7 +174,7 @@ func (r *dnsResponse) DecodeNS() ([]*net.NS, error) {
// DecodeCNAME implements model.DNSResponse.DecodeCNAME. // DecodeCNAME implements model.DNSResponse.DecodeCNAME.
func (r *dnsResponse) DecodeCNAME() (string, error) { func (r *dnsResponse) DecodeCNAME() (string, error) {
if err := r.rcodeToError(); err != nil { if err := r.rcodeToError(); err != nil {
return "", err return "", err // error already wrapped
} }
for _, answer := range r.msg.Answer { for _, answer := range r.msg.Answer {
switch avalue := answer.(type) { switch avalue := answer.(type) {
@ -177,7 +182,7 @@ func (r *dnsResponse) DecodeCNAME() (string, error) {
return avalue.Target, nil return avalue.Target, nil
} }
} }
return "", ErrOODNSNoAnswer return "", dnsDecoderWrapError(ErrOODNSNoAnswer)
} }
var _ model.DNSDecoder = &DNSDecoderMiekg{} var _ model.DNSDecoder = &DNSDecoderMiekg{}

View File

@ -12,14 +12,22 @@ import (
"github.com/ooni/probe-cli/v3/internal/runtimex" "github.com/ooni/probe-cli/v3/internal/runtimex"
) )
func dnsDecoderErrorIsWrapped(err error) bool {
var errwrapper *ErrWrapper
return errors.As(err, &errwrapper)
}
func TestDNSDecoderMiekg(t *testing.T) { func TestDNSDecoderMiekg(t *testing.T) {
t.Run("DecodeResponse", func(t *testing.T) { t.Run("DecodeResponse", func(t *testing.T) {
t.Run("UnpackError", func(t *testing.T) { t.Run("UnpackError", func(t *testing.T) {
d := &DNSDecoderMiekg{} d := &DNSDecoderMiekg{}
resp, err := d.DecodeResponse(nil, &mocks.DNSQuery{}) resp, err := d.DecodeResponse(nil, &mocks.DNSQuery{})
if err == nil || err.Error() != "dns: overflow unpacking uint16" { if err == nil || err.Error() != "unknown_failure: dns: overflow unpacking uint16" {
t.Fatal("unexpected error", err) t.Fatal("unexpected error", err)
} }
if !dnsDecoderErrorIsWrapped(err) {
t.Fatal("unwrapped error", err)
}
if resp != nil { if resp != nil {
t.Fatal("expected nil resp here") t.Fatal("expected nil resp here")
} }
@ -33,6 +41,9 @@ func TestDNSDecoderMiekg(t *testing.T) {
if !errors.Is(err, ErrDNSIsQuery) { if !errors.Is(err, ErrDNSIsQuery) {
t.Fatal("unexpected err", err) t.Fatal("unexpected err", err)
} }
if !dnsDecoderErrorIsWrapped(err) {
t.Fatal("unwrapped error", err)
}
if resp != nil { if resp != nil {
t.Fatal("expected nil resp here") t.Fatal("expected nil resp here")
} }
@ -53,6 +64,9 @@ func TestDNSDecoderMiekg(t *testing.T) {
if !errors.Is(err, ErrDNSReplyWithWrongQueryID) { if !errors.Is(err, ErrDNSReplyWithWrongQueryID) {
t.Fatal("unexpected error", err) t.Fatal("unexpected error", err)
} }
if !dnsDecoderErrorIsWrapped(err) {
t.Fatal("unwrapped error", err)
}
if resp != nil { if resp != nil {
t.Fatal("expected nil resp here") t.Fatal("expected nil resp here")
} }
@ -163,6 +177,9 @@ func TestDNSDecoderMiekg(t *testing.T) {
if !errors.Is(err, io.err) { if !errors.Is(err, io.err) {
t.Fatal("unexpected err", err) t.Fatal("unexpected err", err)
} }
if err != nil && !dnsDecoderErrorIsWrapped(err) {
t.Fatal("unwrapped error", err)
}
}) })
} }
}) })
@ -187,6 +204,9 @@ func TestDNSDecoderMiekg(t *testing.T) {
if !errors.Is(err, ErrOODNSRefused) { if !errors.Is(err, ErrOODNSRefused) {
t.Fatal("unexpected err", err) t.Fatal("unexpected err", err)
} }
if !dnsDecoderErrorIsWrapped(err) {
t.Fatal("unwrapped error", err)
}
if https != nil { if https != nil {
t.Fatal("expected nil https result") t.Fatal("expected nil https result")
} }
@ -210,6 +230,9 @@ func TestDNSDecoderMiekg(t *testing.T) {
if !errors.Is(err, ErrOODNSNoAnswer) { if !errors.Is(err, ErrOODNSNoAnswer) {
t.Fatal("unexpected err", err) t.Fatal("unexpected err", err)
} }
if !dnsDecoderErrorIsWrapped(err) {
t.Fatal("unwrapped error", err)
}
if https != nil { if https != nil {
t.Fatal("expected nil https results") t.Fatal("expected nil https results")
} }
@ -268,6 +291,9 @@ func TestDNSDecoderMiekg(t *testing.T) {
if !errors.Is(err, ErrOODNSRefused) { if !errors.Is(err, ErrOODNSRefused) {
t.Fatal("unexpected err", err) t.Fatal("unexpected err", err)
} }
if !dnsDecoderErrorIsWrapped(err) {
t.Fatal("unwrapped error", err)
}
if len(ns) > 0 { if len(ns) > 0 {
t.Fatal("expected empty ns result") t.Fatal("expected empty ns result")
} }
@ -291,6 +317,9 @@ func TestDNSDecoderMiekg(t *testing.T) {
if !errors.Is(err, ErrOODNSNoAnswer) { if !errors.Is(err, ErrOODNSNoAnswer) {
t.Fatal("unexpected err", err) t.Fatal("unexpected err", err)
} }
if !dnsDecoderErrorIsWrapped(err) {
t.Fatal("unwrapped error", err)
}
if len(ns) > 0 { if len(ns) > 0 {
t.Fatal("expected empty ns results") t.Fatal("expected empty ns results")
} }
@ -343,6 +372,9 @@ func TestDNSDecoderMiekg(t *testing.T) {
if !errors.Is(err, ErrOODNSRefused) { if !errors.Is(err, ErrOODNSRefused) {
t.Fatal("unexpected err", err) t.Fatal("unexpected err", err)
} }
if !dnsDecoderErrorIsWrapped(err) {
t.Fatal("unwrapped error", err)
}
if len(addrs) > 0 { if len(addrs) > 0 {
t.Fatal("expected empty addrs result") t.Fatal("expected empty addrs result")
} }
@ -366,6 +398,9 @@ func TestDNSDecoderMiekg(t *testing.T) {
if !errors.Is(err, ErrOODNSNoAnswer) { if !errors.Is(err, ErrOODNSNoAnswer) {
t.Fatal("unexpected err", err) t.Fatal("unexpected err", err)
} }
if !dnsDecoderErrorIsWrapped(err) {
t.Fatal("unwrapped error", err)
}
if len(addrs) > 0 { if len(addrs) > 0 {
t.Fatal("expected empty ns results") t.Fatal("expected empty ns results")
} }
@ -456,6 +491,9 @@ func TestDNSDecoderMiekg(t *testing.T) {
if !errors.Is(err, ErrOODNSNoAnswer) { if !errors.Is(err, ErrOODNSNoAnswer) {
t.Fatal("not the error we expected", err) t.Fatal("not the error we expected", err)
} }
if !dnsDecoderErrorIsWrapped(err) {
t.Fatal("unwrapped error", err)
}
if len(addrs) > 0 { if len(addrs) > 0 {
t.Fatal("expected no addrs here") t.Fatal("expected no addrs here")
} }
@ -482,6 +520,9 @@ func TestDNSDecoderMiekg(t *testing.T) {
if !errors.Is(err, ErrOODNSNoAnswer) { if !errors.Is(err, ErrOODNSNoAnswer) {
t.Fatal("not the error we expected", err) t.Fatal("not the error we expected", err)
} }
if !dnsDecoderErrorIsWrapped(err) {
t.Fatal("unwrapped error", err)
}
if len(addrs) > 0 { if len(addrs) > 0 {
t.Fatal("expected no addrs here") t.Fatal("expected no addrs here")
} }
@ -532,6 +573,9 @@ func TestDNSDecoderMiekg(t *testing.T) {
if !errors.Is(err, ErrOODNSNoAnswer) { if !errors.Is(err, ErrOODNSNoAnswer) {
t.Fatal("unexpected err", err) t.Fatal("unexpected err", err)
} }
if !dnsDecoderErrorIsWrapped(err) {
t.Fatal("unwrapped error", err)
}
if cname != "" { if cname != "" {
t.Fatal("expected empty cname result") t.Fatal("expected empty cname result")
} }