The Resolver
interface reproduces the standard net.Resolver
but allows us to make a custom implementation on top of any Lookuper
.
We provide three mechanisms to create a Resolver
:
SystemResolver()
/SystemResolverWithDialer()
as shortcuts for allocating a standard*net.Resolver{}
.NewResolver()
returning aResolver
using the givenLookuper{}
- and
NewRootResolver()
returning aResolver
using iterative lookup.
The Lookuper
interface is centred on Resolver
, making simple INET
queries.
type Lookuper interface {
Lookup(ctx context.Context, qName string, qType uint16) (*dns.Msg, error)
}
type LookuperFunc func(ctx context.Context, qName string, qType uint16) (*dns.Msg, error)
Additionally we can use any function implementing the same signature as LookuperFunc
,
which returns a type implementing Lookuper
and Exchanger
using the given function.
The Exchanger
interface is an alternative to Lookuper
but taking pre-assembled
*dns.Msg{}
queries.
type Exchanger interface {
Exchange(ctx context.Context, msg *dns.Msg) (*dns.Msg, error)
}
type ExchangerFunc func(ctx context.Context, msg *dns.Msg) (*dns.Msg, error)
Additionally we can use any function implementing the same signature as ExchangerFunc
,
which returns a type implementing Lookuper
and Exchanger
using the
given function.
The client.Client
interface represents ExchangeContext()
of *dns.Client to perform a *dns.Msg{} against the specified server.
type Client interface {
ExchangeContext(ctx context.Context, req *dns.Msg, server string) (*dns.Msg, time.Duration, error)
}
type ExchangeFunc func(ctx context.Context, req *dns.Msg, server string) (*dns.Msg, time.Duration, error)
type Unwrapper interface {
Unwrap() *dns.Client
}
Additionally we can use any function implementing the same signature as client.ExchangeFunc
, which returns a type implementing client.Client
using the given functions.
Client
s are advised to also implement Unwrapper
to access the underlying *dns.Client{}
.
We use the standard *net.DNSError{} for all our errors, but also provide errors.MsgAsError()
and errors.ErrorAsMsg()
to convert back and forth between the errors we emit and an equivalent *dns.Msg.
server.Handler
implements a dns.Handler on top of a Lookuper
or Exchanger
.
client.NewDefaultClient()
can be used to get a plain UDP
*dns.Client{}
with an optional message size.
The client.Auto
Client distinguishes requests by server protocol and retries truncated UDP requests as TCP.
client.Auto
uses udp://
, tcp://
and tls://
server prefixes for protocol specific and uses UDP
followed by a TCP
retry if no prefix is specified.
client.NoAAAA
is a Client Middleware that removes all AAAA
entries, to be used on systems were IPv6 isn't fully functional.
client.SingleFlight
is a Client Middleware that implements a barrier to catch identical queries, with a small caching period. Only the req.Id
is ignored when comparing requests, and it operates per-server.
client.WorkerPool
is a Client Middleware that implements a barrier limiting
the number of exchange calls that can happen in parallel. It's ideally
use behind a SingleFlight Client.
reflect.Client
implements logging middleware if front of a client.Client
.
The RootLookuper
implements an iterative Lookuper
/Exchanger
, supporting an optional custom client.Client
.
SingleLookuper
implements a forwarding Lookuper
/Exchanger
passing requests as-is to a client.Client
.
MultiLookuper
implements a parallel Lookuper
/Exchanger
that will pass the request to multiple Lookuper
/Exchanger
instances and return the first response.
SingleFlight
implements a Lookuper
/Exchanger
barrier to hold identical requests at
the same time, before passing them over to another.
reflect.Lookuper
implements logging middleware in front of a Lookuper
or Exchanger
.
For convenience we provide shortcuts to create forwarding Lookuper
s to well known recursive resolvers.
NewGoogleLookuper()
using8.8.8.8
,NewGoogleLookuper2()
using8.8.4.4
,NewCloudflareLookuper()
using1.1.1.1
,NewQuad9Lookuper()
using9.9.9.9
,- and
NewQuad9Lookuper6()
using Quad9's2620:fe::f3
.
reflect.Lookuper
and reflect.Client
allow us to hook a dynamically enabled logging layer with an optional tracing ID, using the darvaza.org/slog.Logger
interface.