refactor: DNSTransport I/Os DNS messages (#760)
This diff refactors the DNSTransport model to receive in input a DNSQuery and return in output a DNSResponse. The design of DNSQuery and DNSResponse takes into account the use case of a transport using getaddrinfo, meaning that we don't need to serialize and deserialize messages when using getaddrinfo. The current codebase does not use a getaddrinfo transport, but I wrote one such a transport in the Websteps Winter 2021 prototype (https://github.com/bassosimone/websteps-illustrated/). The design conversation that lead to producing this diff is https://github.com/ooni/probe/issues/2099
This commit is contained in:
@@ -1,36 +1,20 @@
|
||||
package mocks
|
||||
|
||||
import (
|
||||
"net"
|
||||
//
|
||||
// Mocks for model.DNSDecoder
|
||||
//
|
||||
|
||||
"github.com/miekg/dns"
|
||||
import (
|
||||
"github.com/ooni/probe-cli/v3/internal/model"
|
||||
)
|
||||
|
||||
// DNSDecoder allows mocking dnsx.DNSDecoder.
|
||||
// DNSDecoder allows mocking model.DNSDecoder.
|
||||
type DNSDecoder struct {
|
||||
MockDecodeLookupHost func(qtype uint16, reply []byte, queryID uint16) ([]string, 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)
|
||||
MockDecodeResponse func(data []byte, query model.DNSQuery) (model.DNSResponse, error)
|
||||
}
|
||||
|
||||
// DecodeLookupHost calls MockDecodeLookupHost.
|
||||
func (e *DNSDecoder) DecodeLookupHost(qtype uint16, reply []byte, queryID uint16) ([]string, error) {
|
||||
return e.MockDecodeLookupHost(qtype, reply, queryID)
|
||||
}
|
||||
var _ model.DNSDecoder = &DNSDecoder{}
|
||||
|
||||
// DecodeHTTPS calls MockDecodeHTTPS.
|
||||
func (e *DNSDecoder) DecodeHTTPS(reply []byte, queryID uint16) (*model.HTTPSSvc, error) {
|
||||
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)
|
||||
func (e *DNSDecoder) DecodeResponse(data []byte, query model.DNSQuery) (model.DNSResponse, error) {
|
||||
return e.MockDecodeResponse(data, query)
|
||||
}
|
||||
|
||||
@@ -2,70 +2,20 @@ package mocks
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net"
|
||||
"testing"
|
||||
|
||||
"github.com/miekg/dns"
|
||||
"github.com/ooni/probe-cli/v3/internal/model"
|
||||
)
|
||||
|
||||
func TestDNSDecoder(t *testing.T) {
|
||||
t.Run("DecodeLookupHost", func(t *testing.T) {
|
||||
t.Run("DecodeResponse", func(t *testing.T) {
|
||||
expected := errors.New("mocked error")
|
||||
e := &DNSDecoder{
|
||||
MockDecodeLookupHost: func(qtype uint16, reply []byte, queryID uint16) ([]string, error) {
|
||||
MockDecodeResponse: func(reply []byte, query model.DNSQuery) (model.DNSResponse, error) {
|
||||
return nil, expected
|
||||
},
|
||||
}
|
||||
out, err := e.DecodeLookupHost(dns.TypeA, make([]byte, 17), dns.Id())
|
||||
if !errors.Is(err, expected) {
|
||||
t.Fatal("unexpected err", err)
|
||||
}
|
||||
if out != nil {
|
||||
t.Fatal("unexpected out")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("DecodeHTTPS", func(t *testing.T) {
|
||||
expected := errors.New("mocked error")
|
||||
e := &DNSDecoder{
|
||||
MockDecodeHTTPS: func(reply []byte, queryID uint16) (*model.HTTPSSvc, error) {
|
||||
return nil, expected
|
||||
},
|
||||
}
|
||||
out, err := e.DecodeHTTPS(make([]byte, 17), dns.Id())
|
||||
if !errors.Is(err, expected) {
|
||||
t.Fatal("unexpected err", err)
|
||||
}
|
||||
if out != nil {
|
||||
t.Fatal("unexpected out")
|
||||
}
|
||||
})
|
||||
|
||||
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{
|
||||
MockDecodeReply: func(reply []byte) (*dns.Msg, error) {
|
||||
return nil, expected
|
||||
},
|
||||
}
|
||||
out, err := e.DecodeReply(make([]byte, 17))
|
||||
out, err := e.DecodeResponse(make([]byte, 17), &DNSQuery{})
|
||||
if !errors.Is(err, expected) {
|
||||
t.Fatal("unexpected err", err)
|
||||
}
|
||||
|
||||
@@ -1,11 +1,19 @@
|
||||
package mocks
|
||||
|
||||
// DNSEncoder allows mocking dnsx.DNSEncoder.
|
||||
//
|
||||
// Mocks for model.DNSEncoder.
|
||||
//
|
||||
|
||||
import "github.com/ooni/probe-cli/v3/internal/model"
|
||||
|
||||
// DNSEncoder allows mocking model.DNSEncoder.
|
||||
type DNSEncoder struct {
|
||||
MockEncode func(domain string, qtype uint16, padding bool) ([]byte, uint16, error)
|
||||
MockEncode func(domain string, qtype uint16, padding bool) model.DNSQuery
|
||||
}
|
||||
|
||||
var _ model.DNSEncoder = &DNSEncoder{}
|
||||
|
||||
// Encode calls MockEncode.
|
||||
func (e *DNSEncoder) Encode(domain string, qtype uint16, padding bool) ([]byte, uint16, error) {
|
||||
func (e *DNSEncoder) Encode(domain string, qtype uint16, padding bool) model.DNSQuery {
|
||||
return e.MockEncode(domain, qtype, padding)
|
||||
}
|
||||
|
||||
@@ -5,24 +5,46 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/miekg/dns"
|
||||
"github.com/ooni/probe-cli/v3/internal/model"
|
||||
)
|
||||
|
||||
func TestDNSEncoder(t *testing.T) {
|
||||
t.Run("Encode", func(t *testing.T) {
|
||||
expected := errors.New("mocked error")
|
||||
queryID := dns.Id()
|
||||
e := &DNSEncoder{
|
||||
MockEncode: func(domain string, qtype uint16, padding bool) ([]byte, uint16, error) {
|
||||
return nil, 0, expected
|
||||
MockEncode: func(domain string, qtype uint16, padding bool) model.DNSQuery {
|
||||
return &DNSQuery{
|
||||
MockDomain: func() string {
|
||||
return dns.Fqdn(domain) // do what an implementation MUST do
|
||||
},
|
||||
MockType: func() uint16 {
|
||||
return qtype
|
||||
},
|
||||
MockBytes: func() ([]byte, error) {
|
||||
return nil, expected
|
||||
},
|
||||
MockID: func() uint16 {
|
||||
return queryID
|
||||
},
|
||||
}
|
||||
},
|
||||
}
|
||||
out, queryID, err := e.Encode("dns.google", dns.TypeA, true)
|
||||
query := e.Encode("dns.google", dns.TypeA, true)
|
||||
if query.Domain() != "dns.google." {
|
||||
t.Fatal("invalid domain")
|
||||
}
|
||||
if query.Type() != dns.TypeA {
|
||||
t.Fatal("invalid type")
|
||||
}
|
||||
out, err := query.Bytes()
|
||||
if !errors.Is(err, expected) {
|
||||
t.Fatal("unexpected err", err)
|
||||
}
|
||||
if out != nil {
|
||||
t.Fatal("unexpected out")
|
||||
}
|
||||
if queryID != 0 {
|
||||
if query.ID() != queryID {
|
||||
t.Fatal("unexpected queryID")
|
||||
}
|
||||
})
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
package mocks
|
||||
|
||||
//
|
||||
// Mocks for model.DNSQuery.
|
||||
//
|
||||
|
||||
import "github.com/ooni/probe-cli/v3/internal/model"
|
||||
|
||||
// DNSQuery allocks mocking model.DNSQuery.
|
||||
type DNSQuery struct {
|
||||
MockDomain func() string
|
||||
MockType func() uint16
|
||||
MockBytes func() ([]byte, error)
|
||||
MockID func() uint16
|
||||
}
|
||||
|
||||
func (q *DNSQuery) Domain() string {
|
||||
return q.MockDomain()
|
||||
}
|
||||
|
||||
func (q *DNSQuery) Type() uint16 {
|
||||
return q.MockType()
|
||||
}
|
||||
|
||||
func (q *DNSQuery) Bytes() ([]byte, error) {
|
||||
return q.MockBytes()
|
||||
}
|
||||
|
||||
func (q *DNSQuery) ID() uint16 {
|
||||
return q.MockID()
|
||||
}
|
||||
|
||||
var _ model.DNSQuery = &DNSQuery{}
|
||||
@@ -0,0 +1,62 @@
|
||||
package mocks
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"testing"
|
||||
|
||||
"github.com/miekg/dns"
|
||||
)
|
||||
|
||||
func TestDNSQuery(t *testing.T) {
|
||||
t.Run("Domain", func(t *testing.T) {
|
||||
expected := "dns.google."
|
||||
q := &DNSQuery{
|
||||
MockDomain: func() string {
|
||||
return expected
|
||||
},
|
||||
}
|
||||
if q.Domain() != expected {
|
||||
t.Fatal("invalid domain")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("Type", func(t *testing.T) {
|
||||
expected := dns.TypeAAAA
|
||||
q := &DNSQuery{
|
||||
MockType: func() uint16 {
|
||||
return expected
|
||||
},
|
||||
}
|
||||
if q.Type() != expected {
|
||||
t.Fatal("invalid type")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("Bytes", func(t *testing.T) {
|
||||
expected := []byte{0xde, 0xea, 0xad, 0xbe, 0xef}
|
||||
q := &DNSQuery{
|
||||
MockBytes: func() ([]byte, error) {
|
||||
return expected, nil
|
||||
},
|
||||
}
|
||||
out, err := q.Bytes()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !bytes.Equal(expected, out) {
|
||||
t.Fatal("invalid bytes")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("ID", func(t *testing.T) {
|
||||
expected := dns.Id()
|
||||
q := &DNSQuery{
|
||||
MockID: func() uint16 {
|
||||
return expected
|
||||
},
|
||||
}
|
||||
if q.ID() != expected {
|
||||
t.Fatal("invalid id")
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package mocks
|
||||
|
||||
//
|
||||
// Mocks for model.DNSResponse
|
||||
//
|
||||
|
||||
import (
|
||||
"net"
|
||||
|
||||
"github.com/ooni/probe-cli/v3/internal/model"
|
||||
)
|
||||
|
||||
// DNSResponse allows mocking model.DNSResponse.
|
||||
type DNSResponse struct {
|
||||
MockQuery func() model.DNSQuery
|
||||
MockBytes func() []byte
|
||||
MockRcode func() int
|
||||
MockDecodeHTTPS func() (*model.HTTPSSvc, error)
|
||||
MockDecodeLookupHost func() ([]string, error)
|
||||
MockDecodeNS func() ([]*net.NS, error)
|
||||
}
|
||||
|
||||
var _ model.DNSResponse = &DNSResponse{}
|
||||
|
||||
func (r *DNSResponse) Query() model.DNSQuery {
|
||||
return r.MockQuery()
|
||||
}
|
||||
|
||||
func (r *DNSResponse) Bytes() []byte {
|
||||
return r.MockBytes()
|
||||
}
|
||||
|
||||
func (r *DNSResponse) Rcode() int {
|
||||
return r.MockRcode()
|
||||
}
|
||||
|
||||
func (r *DNSResponse) DecodeHTTPS() (*model.HTTPSSvc, error) {
|
||||
return r.MockDecodeHTTPS()
|
||||
}
|
||||
|
||||
func (r *DNSResponse) DecodeLookupHost() ([]string, error) {
|
||||
return r.MockDecodeLookupHost()
|
||||
}
|
||||
|
||||
func (r *DNSResponse) DecodeNS() ([]*net.NS, error) {
|
||||
return r.MockDecodeNS()
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
package mocks
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"net"
|
||||
"testing"
|
||||
|
||||
"github.com/miekg/dns"
|
||||
"github.com/ooni/probe-cli/v3/internal/model"
|
||||
)
|
||||
|
||||
func TestDNSResponse(t *testing.T) {
|
||||
t.Run("Query", func(t *testing.T) {
|
||||
qid := dns.Id()
|
||||
query := &DNSQuery{
|
||||
MockID: func() uint16 {
|
||||
return qid
|
||||
},
|
||||
}
|
||||
resp := &DNSResponse{
|
||||
MockQuery: func() model.DNSQuery {
|
||||
return query
|
||||
},
|
||||
}
|
||||
out := resp.Query()
|
||||
if out.ID() != query.ID() {
|
||||
t.Fatal("invalid query")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("Bytes", func(t *testing.T) {
|
||||
expected := []byte{0xde, 0xea, 0xad, 0xbe, 0xef}
|
||||
resp := &DNSResponse{
|
||||
MockBytes: func() []byte {
|
||||
return expected
|
||||
},
|
||||
}
|
||||
out := resp.Bytes()
|
||||
if !bytes.Equal(expected, out) {
|
||||
t.Fatal("invalid bytes")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("Rcode", func(t *testing.T) {
|
||||
expected := dns.RcodeBadAlg
|
||||
resp := &DNSResponse{
|
||||
MockRcode: func() int {
|
||||
return expected
|
||||
},
|
||||
}
|
||||
out := resp.Rcode()
|
||||
if out != expected {
|
||||
t.Fatal("invalid rcode")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("DecodeLookupHost", func(t *testing.T) {
|
||||
expected := errors.New("mocked error")
|
||||
r := &DNSResponse{
|
||||
MockDecodeLookupHost: func() ([]string, error) {
|
||||
return nil, expected
|
||||
},
|
||||
}
|
||||
out, err := r.DecodeLookupHost()
|
||||
if !errors.Is(err, expected) {
|
||||
t.Fatal("unexpected err", err)
|
||||
}
|
||||
if out != nil {
|
||||
t.Fatal("unexpected out")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("DecodeHTTPS", func(t *testing.T) {
|
||||
expected := errors.New("mocked error")
|
||||
r := &DNSResponse{
|
||||
MockDecodeHTTPS: func() (*model.HTTPSSvc, error) {
|
||||
return nil, expected
|
||||
},
|
||||
}
|
||||
out, err := r.DecodeHTTPS()
|
||||
if !errors.Is(err, expected) {
|
||||
t.Fatal("unexpected err", err)
|
||||
}
|
||||
if out != nil {
|
||||
t.Fatal("unexpected out")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("DecodeNS", func(t *testing.T) {
|
||||
expected := errors.New("mocked error")
|
||||
r := &DNSResponse{
|
||||
MockDecodeNS: func() ([]*net.NS, error) {
|
||||
return nil, expected
|
||||
},
|
||||
}
|
||||
out, err := r.DecodeNS()
|
||||
if !errors.Is(err, expected) {
|
||||
t.Fatal("unexpected err", err)
|
||||
}
|
||||
if out != nil {
|
||||
t.Fatal("unexpected out")
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -1,10 +1,14 @@
|
||||
package mocks
|
||||
|
||||
import "context"
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/ooni/probe-cli/v3/internal/model"
|
||||
)
|
||||
|
||||
// DNSTransport allows mocking dnsx.DNSTransport.
|
||||
type DNSTransport struct {
|
||||
MockRoundTrip func(ctx context.Context, query []byte) ([]byte, error)
|
||||
MockRoundTrip func(ctx context.Context, query model.DNSQuery) (model.DNSResponse, error)
|
||||
|
||||
MockRequiresPadding func() bool
|
||||
|
||||
@@ -15,8 +19,10 @@ type DNSTransport struct {
|
||||
MockCloseIdleConnections func()
|
||||
}
|
||||
|
||||
var _ model.DNSTransport = &DNSTransport{}
|
||||
|
||||
// RoundTrip calls MockRoundTrip.
|
||||
func (txp *DNSTransport) RoundTrip(ctx context.Context, query []byte) ([]byte, error) {
|
||||
func (txp *DNSTransport) RoundTrip(ctx context.Context, query model.DNSQuery) (model.DNSResponse, error) {
|
||||
return txp.MockRoundTrip(ctx, query)
|
||||
}
|
||||
|
||||
|
||||
@@ -6,17 +6,18 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/ooni/probe-cli/v3/internal/atomicx"
|
||||
"github.com/ooni/probe-cli/v3/internal/model"
|
||||
)
|
||||
|
||||
func TestDNSTransport(t *testing.T) {
|
||||
t.Run("RoundTrip", func(t *testing.T) {
|
||||
expected := errors.New("mocked error")
|
||||
txp := &DNSTransport{
|
||||
MockRoundTrip: func(ctx context.Context, query []byte) ([]byte, error) {
|
||||
MockRoundTrip: func(ctx context.Context, query model.DNSQuery) (model.DNSResponse, error) {
|
||||
return nil, expected
|
||||
},
|
||||
}
|
||||
resp, err := txp.RoundTrip(context.Background(), make([]byte, 16))
|
||||
resp, err := txp.RoundTrip(context.Background(), &DNSQuery{})
|
||||
if !errors.Is(err, expected) {
|
||||
t.Fatal("not the error we expected", err)
|
||||
}
|
||||
|
||||
+65
-55
@@ -1,5 +1,9 @@
|
||||
package model
|
||||
|
||||
//
|
||||
// Network extensions
|
||||
//
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
@@ -9,74 +13,81 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/lucas-clemente/quic-go"
|
||||
"github.com/miekg/dns"
|
||||
)
|
||||
|
||||
//
|
||||
// Network extensions
|
||||
//
|
||||
// DNSResponse is a parsed DNS response ready for further processing.
|
||||
type DNSResponse interface {
|
||||
// Query is the query associated with this response.
|
||||
Query() DNSQuery
|
||||
|
||||
// The DNSDecoder decodes DNS replies.
|
||||
// Bytes returns the bytes from which we parsed the query.
|
||||
Bytes() []byte
|
||||
|
||||
// Rcode returns the response's Rcode.
|
||||
Rcode() int
|
||||
|
||||
// DecodeHTTPS returns information gathered from all the HTTPS
|
||||
// records found inside of this response.
|
||||
DecodeHTTPS() (*HTTPSSvc, error)
|
||||
|
||||
// DecodeLookupHost returns the addresses in the response matching
|
||||
// the original query type (one of A and AAAA).
|
||||
DecodeLookupHost() ([]string, error)
|
||||
|
||||
// DecodeNS returns all the NS entries in this response.
|
||||
DecodeNS() ([]*net.NS, error)
|
||||
}
|
||||
|
||||
// The DNSDecoder decodes DNS responses.
|
||||
type DNSDecoder interface {
|
||||
// DecodeLookupHost decodes an A or AAAA reply.
|
||||
//
|
||||
// Arguments:
|
||||
//
|
||||
// - qtype is the query type (e.g., dns.TypeAAAA)
|
||||
//
|
||||
// - data contains the reply bytes read from a DNSTransport
|
||||
//
|
||||
// - queryID is the original query ID
|
||||
//
|
||||
// Returns:
|
||||
//
|
||||
// - on success, a list of IP addrs inside the reply and a nil error
|
||||
//
|
||||
// - on failure, a nil list and an error.
|
||||
//
|
||||
// Note that this function will return an error if there is no
|
||||
// IP address inside of the reply.
|
||||
DecodeLookupHost(qtype uint16, data []byte, queryID uint16) ([]string, error)
|
||||
|
||||
// DecodeHTTPS is like DecodeLookupHost but decodes an HTTPS reply.
|
||||
//
|
||||
// The argument is the reply as read by the DNSTransport.
|
||||
//
|
||||
// On success, this function returns an HTTPSSvc structure and
|
||||
// a nil error. On failure, the HTTPSSvc pointer is nil and
|
||||
// the error points to the error that occurred.
|
||||
//
|
||||
// This function will return an error if the HTTPS reply does not
|
||||
// contain at least a valid ALPN entry. It will not return
|
||||
// an error, though, when there are no IPv4/IPv6 hints in the reply.
|
||||
DecodeHTTPS(data []byte, queryID uint16) (*HTTPSSvc, error)
|
||||
|
||||
// DecodeNS is like DecodeHTTPS but for NS queries.
|
||||
DecodeNS(data []byte, queryID uint16) ([]*net.NS, error)
|
||||
|
||||
// DecodeReply decodes a DNS reply message.
|
||||
// DecodeResponse decodes a DNS response message.
|
||||
//
|
||||
// Arguments:
|
||||
//
|
||||
// - data is the raw reply
|
||||
//
|
||||
// This function fails if we cannot parse data as a DNS
|
||||
// message or the message is not a reply.
|
||||
// message or the message is not a response.
|
||||
//
|
||||
// If you use this function, remember that:
|
||||
// Regarding the returned response, remember that the Rcode
|
||||
// MAY still be nonzero (this method does not treat a nonzero
|
||||
// Rcode as an error when parsing the response).
|
||||
DecodeResponse(data []byte, query DNSQuery) (DNSResponse, error)
|
||||
}
|
||||
|
||||
// DNSQuery is an encoded DNS query ready to be sent using a DNSTransport.
|
||||
type DNSQuery interface {
|
||||
// Domain is the domain we're querying for.
|
||||
Domain() string
|
||||
|
||||
// Type is the query type.
|
||||
Type() uint16
|
||||
|
||||
// Bytes serializes the query to bytes. This function may fail if we're not
|
||||
// able to correctly encode the domain into a query message.
|
||||
//
|
||||
// 1. the Rcode MAY be nonzero;
|
||||
//
|
||||
// 2. the replyID MAY NOT match the original query ID.
|
||||
//
|
||||
// That is, this is a very basic parsing method.
|
||||
DecodeReply(data []byte) (*dns.Msg, error)
|
||||
// The value returned by this function WILL be memoized after the first call,
|
||||
// so you SHOULD create a new DNSQuery if you need to retry a query.
|
||||
Bytes() ([]byte, error)
|
||||
|
||||
// ID returns the query ID.
|
||||
ID() uint16
|
||||
}
|
||||
|
||||
// The DNSEncoder encodes DNS queries to bytes
|
||||
type DNSEncoder interface {
|
||||
// Encode transforms its arguments into a serialized DNS query.
|
||||
//
|
||||
// Every time you call Encode, you get a new DNSQuery value
|
||||
// using a query ID selected at random.
|
||||
//
|
||||
// Serialization to bytes is lazy to acommodate DNS transports that
|
||||
// do not need to serialize and send bytes, e.g., getaddrinfo.
|
||||
//
|
||||
// You serialize to bytes using DNSQuery.Bytes. This operation MAY fail
|
||||
// if the domain name cannot be packed into a DNS message (e.g., it is
|
||||
// too long to fit into the message).
|
||||
//
|
||||
// Arguments:
|
||||
//
|
||||
// - domain is the domain for the query (e.g., x.org);
|
||||
@@ -85,16 +96,15 @@ type DNSEncoder interface {
|
||||
//
|
||||
// - padding is whether to add padding to the query.
|
||||
//
|
||||
// On success, this function returns a valid byte array, the queryID, and
|
||||
// a nil error. On failure, we have a non-nil error, a nil arrary and a zero
|
||||
// query ID.
|
||||
Encode(domain string, qtype uint16, padding bool) ([]byte, uint16, error)
|
||||
// This function will transform the domain into an FQDN is it's not
|
||||
// already expressed in the FQDN format.
|
||||
Encode(domain string, qtype uint16, padding bool) DNSQuery
|
||||
}
|
||||
|
||||
// DNSTransport represents an abstract DNS transport.
|
||||
type DNSTransport interface {
|
||||
// RoundTrip sends a DNS query and receives the reply.
|
||||
RoundTrip(ctx context.Context, query []byte) (reply []byte, err error)
|
||||
RoundTrip(ctx context.Context, query DNSQuery) (DNSResponse, error)
|
||||
|
||||
// RequiresPadding returns whether this transport needs padding.
|
||||
RequiresPadding() bool
|
||||
|
||||
Reference in New Issue
Block a user