| Copyright | (c) IIJ Innovation Institute Inc. 2009 (c) Viktor Dukhovni 2020-2026 |
|---|---|
| License | BSD-3-Clause |
| Maintainer | ietf-dane@dukhovni.org |
| Stability | unstable |
| Safe Haskell | None |
| Language | GHC2024 |
Net.DNSBase.Resolver
Description
The resolver is built in three stages:
ResolverConfcarries the caller's choices: nameserver source, per-attempt timeout, retry budget, defaultQueryControls, and any user-registered RR-type or EDNS option codecs. Build one by adjusting fields ofdefaultResolvConf.makeResolvSeedturns aResolverConfinto aResolvSeed: nameserver hostnames are resolved to addresses, and the user's codec registrations are merged with the library's built-in defaults. The seed is immutable and safe to share across threads.withResolverproduces a per-threadResolverhandle from a shared seed. AResolvercarries thread-local mutable state (a CSPRNG for query IDs) and must not be shared between threads — programs that issue queries concurrently should callwithResolveronce per worker thread.
A minimal example:
main :: IO ()
main = do
seed <- makeResolvSeed defaultResolvConf >>= either throwIO pure
withResolver seed \ r ->
lookupA r $$(dnLit8 "example.com") >>= \ case
Left e -> throwIO e
Right a -> print aThe codec set baked into the seed can be extended at
conf-build time via registerRRtype / registerEdnsOption
(new RR-type or EDNS-option codecs) and the four
extendRRwithType extendRRwithValue
extendEdnsOptionWithType / extendEdnsOptionWithValue
combinators (extensions onto codecs that admit them). See
Net.DNSBase.Extensible for worked examples.
Synopsis
- data ResolverConf
- defaultResolvConf :: ResolverConf
- setResolverConfTimeout :: Int -> ResolverConf -> ResolverConf
- setResolverConfRetries :: Int -> ResolverConf -> ResolverConf
- setResolverConfQueryControls :: QueryControls -> ResolverConf -> ResolverConf
- setResolverConfSource :: NameserverConf -> ResolverConf -> ResolverConf
- data NameserverConf
- data NameserverSpec = NameserverSpec {}
- data ResolvSeed
- makeResolvSeed :: ResolverConf -> IO (Either DNSError ResolvSeed)
- data Resolver
- withResolver :: ResolvSeed -> (Resolver -> IO a) -> IO a
- data RRtypeNames
- confTypeNames :: Maybe ResolvSeed -> RRtypeNames
- rrtypeLookup :: ByteString -> RRtypeNames -> Maybe RRTYPE
- data QueryControls where
- pattern EdnsDisabled :: QueryControls
- pattern EdnsEnabled :: QueryControls
- pattern EdnsOptionCtl :: (OptionCtl -> OptionCtl) -> QueryControls
- pattern EdnsUdpSize :: Word16 -> QueryControls
- pattern EdnsVersion :: Word8 -> QueryControls
- pattern QctlFlags :: (FlagOps -> FlagOps) -> QueryControls
- data EdnsControls
- class TypeExtensible a v where
- type TypeExtensionArg a b
- extendByType :: forall t b -> (t ~ a, TypeExtensionArg t b) => v -> v
- class (Typeable a, Eq a, Ord a, Show a, Presentable a) => KnownRData a where
- type RDataExtensionVal a
- rdataExtensionVal :: forall b -> b ~ a => RDataExtensionVal a
- rdType :: forall b -> b ~ a => RRTYPE
- rdTypePres :: forall b -> b ~ a => Builder -> Builder
- rdDecode :: forall b -> b ~ a => RDataExtensionVal a -> Int -> SGet RData
- rdEncode :: a -> SPut s RData
- cnEncode :: a -> SPut s RData
- registerRRtype :: forall a -> KnownRData a => ResolverConf -> ResolverConf
- extendRRwithType :: forall t -> (KnownRData t, TypeExtensible t (RDataExtensionVal t)) => forall b -> TypeExtensionArg t b => ResolverConf -> ResolverConf
- extendRRwithValue :: forall t -> (KnownRData t, ValueExtensible t (RDataExtensionVal t)) => forall b. ValueExtensionArg t b => b -> ResolverConf -> ResolverConf
- class (Typeable a, Eq a, Show a, Presentable a) => KnownEdnsOption a where
- type OptionExtensionVal a
- optionExtensionVal :: forall b -> b ~ a => OptionExtensionVal a
- optNum :: forall b -> b ~ a => OptNum
- optPres :: forall b -> b ~ a => Builder -> Builder
- optEncode :: forall s r. (Typeable r, Eq r, Show r) => a -> SPut s r
- optDecode :: forall b -> b ~ a => OptionExtensionVal b -> Int -> SGet EdnsOption
- registerEdnsOption :: forall a -> KnownEdnsOption a => ResolverConf -> ResolverConf
- extendEdnsOptionWithType :: forall t -> (KnownEdnsOption t, TypeExtensible t (OptionExtensionVal t)) => forall b -> TypeExtensionArg t b => ResolverConf -> ResolverConf
- extendEdnsOptionWithValue :: forall t -> (KnownEdnsOption t, ValueExtensible t (OptionExtensionVal t)) => forall b. ValueExtensionArg t b => b -> ResolverConf -> ResolverConf
- type DNSIO = ExceptT DNSError IO
- runDNSIO :: DNSIO a -> IO (Either DNSError a)
- liftDNS :: IO (Either DNSError a) -> DNSIO a
Resolver configuration
data ResolverConf Source #
User-supplied resolver configuration. Carries the caller's
choices: where nameservers come from, the per-attempt timeout
and retry budget, default QueryControls, and any
user-registered RR-type / EDNS option codecs. Built-in defaults
are not stored here — they are merged into the effective
configuration only when makeResolvSeed produces a ResolvSeed.
defaultResolvConf :: ResolverConf Source #
Default resolver configuration, with nameserver list from
/etc/resolv.conf and no user-registered codec extensions.
setResolverConfTimeout :: Int -> ResolverConf -> ResolverConf Source #
setResolverConfRetries :: Int -> ResolverConf -> ResolverConf Source #
data NameserverConf Source #
Configuration file name, or explicit list of addresses/hostnames.
Constructors
| SourceFile FilePath | |
| HostList (NonEmpty NameserverSpec) |
data NameserverSpec Source #
Nameserver address string or hostname, with optional port.
Constructors
| NameserverSpec | |
Fields | |
Resolver seed
data ResolvSeed Source #
Resolved, immutable resolver state built by makeResolvSeed
from a ResolverConf. Combines the user's choices with the
library's built-in defaults: resolved nameserver addresses,
and the effective RR-type and EDNS-option codec maps with
user-registered code points overriding the library defaults
(except at a small set of protected code points, where
attempted user overrides are silently ignored).
A ResolvSeed is safe to share across threads; each query-issuing
thread should call withResolver on the same seed to obtain its
own per-thread Resolver handle.
makeResolvSeed :: ResolverConf -> IO (Either DNSError ResolvSeed) Source #
Build a ResolvSeed from a ResolverConf. The seed is
immutable and safely shared across threads; each thread then
calls withResolver to obtain its own Resolver.
The configured nameservers are resolved to socket addresses,
and the user's codec registrations (from registerRRtype,
extendRRwithType and registerEdnsOption) are combined with the
library's built-in codec set. At each RR-type or EDNS option
code point, the user-registered codec takes precedence over the
library default — except at a small set of protected code
points (e.g. the SVCB mandatory key), where any attempted
user override is silently ignored.
Returns if the configured nameservers cannot be
resolved or the configuration file cannot be parsed.Left err
Example:
>>>seed <- makeResolvSeed defaultResolvConf >>= either throwIO pure
Resolver instance
Internal DNS Resolver handle, obtained via withResolver.
Must not be used concurrently in multiple threads.
withResolver :: ResolvSeed -> (Resolver -> IO a) -> IO a Source #
Provide a Resolver to the supplied action. Concurrent use of a
single Resolver is not supported: the handle carries internal
mutable state and the library makes no soundness guarantees if it
is shared across threads. Programs that issue queries from
multiple threads must call withResolver once per worker thread
(typically inside forkIO) to obtain a separate handle. The
ResolvSeed itself is immutable and is the right object to share
across threads.
The action runs in plain IO; DNS-protocol errors from individual
lookups appear in the return shape of each
lookup function inside the action. This function does not itself
produce or propagate Either DNSError aDNSErrors.
Look up RRTYPE by name.
data RRtypeNames Source #
Mapping from RRTYPE name to RRTYPE code.
confTypeNames :: Maybe ResolvSeed -> RRtypeNames Source #
Construct a map of type names to RRTYPE from a given
ResolvSeed value. This will include both the names of all
the registered known types and the names of all known RRtypes,
whether implemented or not.
The map is is not cached, compute it once and reuse for repeated queries.
rrtypeLookup :: ByteString -> RRtypeNames -> Maybe RRTYPE Source #
Attempt to find an RRTYPE' by name. The lookup map can be constructed
via confTypeNames, and should be reused for multiple lookups when
possible.
- The input name is not case-senstive.
- Names of the form
TYPEnum (with num the type number) are supported, and return the correspondingRRTYPE.
Controls.
Query controls.
data QueryControls where Source #
Query controls consisting of an endomorphism over FlagOps to modify
DNS flag bits, and an EdnsControls structure to configure EDNS
behavior.
Constitutes a Monoid with left-biased mappend operation
Bundled Patterns
| pattern EdnsDisabled :: QueryControls | Disable EDNS for this query. When EDNS is disabled, the OPT
pseudo-RR is omitted from the outgoing query and the other
EDNS-related tweaks ( |
| pattern EdnsEnabled :: QueryControls | Enable EDNS for this query, overriding the resolver default if it had EDNS disabled. The OPT pseudo-RR is included in the outgoing query. |
| pattern EdnsOptionCtl | Carry a per-call modification of the OPT pseudo-RR's EDNS
option list as an endomorphism
let noEcs = EdnsOptionCtl
$ optCtlAdd [ EdnsOption
$ O_ECS 0 0 (IPv4 (toIPv4 [0,0,0,0])) ]
in lookupAnswers rslv noEcs IN A $$(dnLit8 "example.org")
|
Fields
| |
| pattern EdnsUdpSize | Override the maximum UDP payload size the client advertises
to the server for this query. The value is clamped to the
|
Fields
| |
| pattern EdnsVersion | Override the EDNS version advertised in the OPT pseudo-RR
for this query. Only version |
Fields
| |
| pattern QctlFlags | Apply the requested DNS flag operation, setting or clearing the requested flag bits, or restoring defaults. |
Fields
| |
Instances
| Monoid QueryControls Source # | |
Defined in Net.DNSBase.Resolver.Internal.Types Methods mempty :: QueryControls # mappend :: QueryControls -> QueryControls -> QueryControls # mconcat :: [QueryControls] -> QueryControls # | |
| Semigroup QueryControls Source # | |
Defined in Net.DNSBase.Resolver.Internal.Types Methods (<>) :: QueryControls -> QueryControls -> QueryControls # sconcat :: NonEmpty QueryControls -> QueryControls # stimes :: Integral b => b -> QueryControls -> QueryControls # | |
| Show QueryControls Source # | |
Defined in Net.DNSBase.Resolver.Internal.Types Methods showsPrec :: Int -> QueryControls -> ShowS # show :: QueryControls -> String # showList :: [QueryControls] -> ShowS # | |
data EdnsControls Source #
EDNS query controls. When EDNS is disabled via ednsEnabled FlagClear,
all the other EDNS-related overrides have no effect. Semigroup append is
left-biased
Instances
| Monoid EdnsControls Source # | |
Defined in Net.DNSBase.Resolver.Internal.Types Methods mempty :: EdnsControls # mappend :: EdnsControls -> EdnsControls -> EdnsControls # mconcat :: [EdnsControls] -> EdnsControls # | |
| Semigroup EdnsControls Source # | |
Defined in Net.DNSBase.Resolver.Internal.Types Methods (<>) :: EdnsControls -> EdnsControls -> EdnsControls # sconcat :: NonEmpty EdnsControls -> EdnsControls # stimes :: Integral b => b -> EdnsControls -> EdnsControls # | |
| Show EdnsControls Source # | |
Defined in Net.DNSBase.Resolver.Internal.Types Methods showsPrec :: Int -> EdnsControls -> ShowS # show :: EdnsControls -> String # showList :: [EdnsControls] -> ShowS # | |
Extending the codec set.
The resolver knows about a set of RR-type and EDNS-option
codecs at conf-build time. registerRRtype and
registerEdnsOption install a fresh codec entry at the
type's default extension value; the four
extendRRwithType extendRRwithValue
extendEdnsOptionWithType / extendEdnsOptionWithValue
combinators fold typed or value-driven extensions onto an
already-extensible codec's existing entry. See
Net.DNSBase.Extensible for worked examples and the design
behind the two extension flavours.
User registrations take precedence over the library's
built-in codec set, except at a small number of protected
code points (e.g. the SVCB mandatory key), where attempted
user additions are silently ignored.
class TypeExtensible a v where Source #
RR-data or EDNS-option types whose codec admits a type-driven extension. See Adding a custom RR type for an example of this mechanism in use, and Writing a type-driven extensible codec for the steps to implement a type-driven extensible codec of your own.
Associated Types
type TypeExtensionArg a b Source #
Constraint a caller's extension type b must satisfy.
Methods
extendByType :: forall t b -> (t ~ a, TypeExtensionArg t b) => v -> v Source #
Fold a caller's extension type b into the existing
codec context value of type v.
class (Typeable a, Eq a, Ord a, Show a, Presentable a) => KnownRData a where Source #
Abstract DNS Resource Record (type-specific) data.
The decoding, encoding and presentation functions are responsible for just
the value, presentation of the associated RR type defaults to the built-in
names, for novel types override rdTypePres.
The Show instance is typically derived, and will output the type
constructor (its output strives to produce syntactically valid Haskell
values), in contrast with Presentable which produces RFC-standard
presentation forms.
Associated Types
type RDataExtensionVal a Source #
The codec-consumed extension value for type a. Defaults
to (). Types with non-trivial extension data (SVCB and
HTTPS, which carry the SvcParam decoder map) supply their
own associated-type definition.
type RDataExtensionVal a = ()
Methods
rdataExtensionVal :: forall b -> b ~ a => RDataExtensionVal a Source #
The library's built-in starting RDataExtensionVal for type
a. Used as the baseline when the library installs its
built-in registration for a, and as the starting point
when the user extends the codec for a. For
types the class default applies.RDataExtensionVal a ~ ()
default rdataExtensionVal :: RDataExtensionVal a ~ () => forall b -> b ~ a => RDataExtensionVal a Source #
rdType :: forall b -> b ~ a => RRTYPE Source #
rdTypePres :: forall b -> b ~ a => Builder -> Builder Source #
rdDecode :: forall b -> b ~ a => RDataExtensionVal a -> Int -> SGet RData Source #
Instances
registerRRtype :: forall a -> KnownRData a => ResolverConf -> ResolverConf Source #
Register a decoder for an RR-type.
If the RR's data type is itself extensible, you can
use extendRRwithType or extendRRwithValue to
apply additional extensions on top.
The registration takes precedence over the library's built-in codec at the same RR-type code, except at protected code points (e.g. RR-type 0 and 65535, or the OPT pseudo-RR), where the registration is silently ignored.
extendRRwithType :: forall t -> (KnownRData t, TypeExtensible t (RDataExtensionVal t)) => forall b -> TypeExtensionArg t b => ResolverConf -> ResolverConf Source #
Extend the registered codec of a type-extensible RR type t
with an additional typed extension b. If t is not yet
known it is automatically registered, in either case extendByType
is then applied to the existing decoder state to fold in b.
This is how one adds an extra SvcParam-key decoder for SVCB and/or HTTPS records.
conf
& extendRRwithType T_svcb MyParamType
& extendRRwithType T_https MyParamTypeextendRRwithValue :: forall t -> (KnownRData t, ValueExtensible t (RDataExtensionVal t)) => forall b. ValueExtensionArg t b => b -> ResolverConf -> ResolverConf Source #
Extend the registered codec for RR type t with a
caller-supplied value v, whose type satisfies t's
ValueExtensionArg constraint. Parallel to
extendRRwithType, but for instances whose extension table
is keyed by runtime data rather than user-supplied types.
class (Typeable a, Eq a, Show a, Presentable a) => KnownEdnsOption a where Source #
EDNS option class with conversion to/from opaque EdnsOption form.
Associated Types
type OptionExtensionVal a Source #
The codec-consumed extension value for option type a.
Defaults to (). Options with a non-trivial extension
(currently only O_ede, whose extension carries the
info-code name registry) supply their own associated-type
definition.
type OptionExtensionVal a = ()
Methods
optionExtensionVal :: forall b -> b ~ a => OptionExtensionVal a Source #
The library's built-in starting OptionExtensionVal for option
type a. Used as the baseline when the library installs
its built-in registration for a, and as the starting
point when the user extends the codec for a. For
options the class default applies.OptionExtensionVal a ~ ()
default optionExtensionVal :: OptionExtensionVal a ~ () => forall b -> b ~ a => OptionExtensionVal a Source #
optNum :: forall b -> b ~ a => OptNum Source #
The EDNS option number
optPres :: forall b -> b ~ a => Builder -> Builder Source #
CPS option number presentation form builder. Most useful for new option values not yet known to the library.
Encoder of option data to wire form
Arguments
| :: forall b -> b ~ a | |
| => OptionExtensionVal b | Its extension value |
| -> Int | The encoded data length |
| -> SGet EdnsOption |
Decoder from wire form
Instances
| KnownEdnsOption O_ecs Source # | |||||
Defined in Net.DNSBase.EDNS.Option.ECS Associated Types
Methods optionExtensionVal :: forall b -> b ~ O_ecs => OptionExtensionVal O_ecs Source # optNum :: forall b -> b ~ O_ecs => OptNum Source # optPres :: forall b -> b ~ O_ecs => Builder -> Builder Source # optEncode :: forall s r. (Typeable r, Eq r, Show r) => O_ecs -> SPut s r Source # optDecode :: forall b -> b ~ O_ecs => OptionExtensionVal b -> Int -> SGet EdnsOption Source # | |||||
| KnownEdnsOption O_ede Source # | |||||
Defined in Net.DNSBase.EDNS.Option.EDE Associated Types
Methods optionExtensionVal :: forall b -> b ~ O_ede => OptionExtensionVal O_ede Source # optNum :: forall b -> b ~ O_ede => OptNum Source # optPres :: forall b -> b ~ O_ede => Builder -> Builder Source # optEncode :: forall s r. (Typeable r, Eq r, Show r) => O_ede -> SPut s r Source # optDecode :: forall b -> b ~ O_ede => OptionExtensionVal b -> Int -> SGet EdnsOption Source # | |||||
| KnownEdnsOption O_nsid Source # | |||||
Defined in Net.DNSBase.EDNS.Option.NSID Associated Types
Methods optionExtensionVal :: forall b -> b ~ O_nsid => OptionExtensionVal O_nsid Source # optNum :: forall b -> b ~ O_nsid => OptNum Source # optPres :: forall b -> b ~ O_nsid => Builder -> Builder Source # optEncode :: forall s r. (Typeable r, Eq r, Show r) => O_nsid -> SPut s r Source # optDecode :: forall b -> b ~ O_nsid => OptionExtensionVal b -> Int -> SGet EdnsOption Source # | |||||
| KnownEdnsOption O_dau Source # | |||||
Defined in Net.DNSBase.EDNS.Option.Secalgs Associated Types
Methods optionExtensionVal :: forall b -> b ~ O_dau => OptionExtensionVal O_dau Source # optNum :: forall b -> b ~ O_dau => OptNum Source # optPres :: forall b -> b ~ O_dau => Builder -> Builder Source # optEncode :: forall s r. (Typeable r, Eq r, Show r) => O_dau -> SPut s r Source # optDecode :: forall b -> b ~ O_dau => OptionExtensionVal b -> Int -> SGet EdnsOption Source # | |||||
| KnownEdnsOption O_dhu Source # | |||||
Defined in Net.DNSBase.EDNS.Option.Secalgs Associated Types
Methods optionExtensionVal :: forall b -> b ~ O_dhu => OptionExtensionVal O_dhu Source # optNum :: forall b -> b ~ O_dhu => OptNum Source # optPres :: forall b -> b ~ O_dhu => Builder -> Builder Source # optEncode :: forall s r. (Typeable r, Eq r, Show r) => O_dhu -> SPut s r Source # optDecode :: forall b -> b ~ O_dhu => OptionExtensionVal b -> Int -> SGet EdnsOption Source # | |||||
| KnownEdnsOption O_n3u Source # | |||||
Defined in Net.DNSBase.EDNS.Option.Secalgs Associated Types
Methods optionExtensionVal :: forall b -> b ~ O_n3u => OptionExtensionVal O_n3u Source # optNum :: forall b -> b ~ O_n3u => OptNum Source # optPres :: forall b -> b ~ O_n3u => Builder -> Builder Source # optEncode :: forall s r. (Typeable r, Eq r, Show r) => O_n3u -> SPut s r Source # optDecode :: forall b -> b ~ O_n3u => OptionExtensionVal b -> Int -> SGet EdnsOption Source # | |||||
| Nat16 n => KnownEdnsOption (OpaqueOption n) Source # | |||||
Defined in Net.DNSBase.EDNS.Internal.Option.Opaque Associated Types
Methods optionExtensionVal :: forall b -> b ~ OpaqueOption n => OptionExtensionVal (OpaqueOption n) Source # optNum :: forall b -> b ~ OpaqueOption n => OptNum Source # optPres :: forall b -> b ~ OpaqueOption n => Builder -> Builder Source # optEncode :: forall s r. (Typeable r, Eq r, Show r) => OpaqueOption n -> SPut s r Source # optDecode :: forall b -> b ~ OpaqueOption n => OptionExtensionVal b -> Int -> SGet EdnsOption Source # | |||||
registerEdnsOption :: forall a -> KnownEdnsOption a => ResolverConf -> ResolverConf Source #
Register an EDNS option decoder.
If the EDNS option's data type is itself extensible, you can
use extendEdnsOptionWithType or extendEdnsOptionWithValue to
apply additional extensions on top.
The registration takes precedence over the library's built-in
decoder at the same option code (if any) after the merge step
in makeResolvSeed.
extendEdnsOptionWithType :: forall t -> (KnownEdnsOption t, TypeExtensible t (OptionExtensionVal t)) => forall b -> TypeExtensionArg t b => ResolverConf -> ResolverConf Source #
Extend the registered decoder for a type-extensible EDNS option
type t with an additional typed extension b. If t is not
yet present in the resolver configuration, it is first registered,
in either case extendByType is then applied fold in b.
This is the EDNS-option-side parallel to extendRRwithType.
extendEdnsOptionWithValue :: forall t -> (KnownEdnsOption t, ValueExtensible t (OptionExtensionVal t)) => forall b. ValueExtensionArg t b => b -> ResolverConf -> ResolverConf Source #
Extend the registered codec for EDNS option type t with
a caller-supplied value v, whose type satisfies t's
ValueExtensionArg constraint. The EDNS-option-side
parallel to extendRRwithValue. This is the canonical way
to add an EDE info-code → friendly-name mapping:
conf
& extendEdnsOptionWithValue O_ede (33, "Frobnicated")
& extendEdnsOptionWithValue O_ede (34, "Bogosity")Chained-composition opt-in
The primary API (e.g. makeResolvSeed, lookupAnswers) returns
: each call's error half is explicit
at the type level and the user's surrounding code stays in plain
IO (Either DNSError a)IO. For programs that prefer transformer-style composition of
many DNS calls with short-circuit error handling, DNSIO is a thin
alias for ; ExceptT DNSError IOrunDNSIO and liftDNS
convert between the two forms.
type DNSIO = ExceptT DNSError IO Source #
An opt-in monad for chaining multiple DNS operations with
short-circuit error handling. The primary public API uses plain
; IO (Either DNSError a)DNSIO is a thin wrapper around
for users who prefer transformer-style
composition. Convert between the two forms with ExceptT DNSError IOrunDNSIO and
liftDNS.