-- | -- Module : Net.DNSBase.Internal.EDNS -- Description : TBD -- Copyright : (c) Viktor Dukhovni, 2026 -- License : BSD-3-Clause -- Maintainer : ietf-dane@dukhovni.org -- Stability : unstable module Net.DNSBase.Internal.EDNS ( -- * Fixed portion of EDNS(0) OPT pseudo-RR EDNS(..) , defaultEDNS , maxUdpSize , minUdpSize ) where import Net.DNSBase.EDNS.Internal.Option import Net.DNSBase.Internal.Util ---------------------------------------------------------------- -- EDNS (RFC 6891, EDNS(0)) ---------------------------------------------------------------- -- | Data type representing extension fields of a version @0@ -- [EDNS](https://tools.ietf.org/html/rfc6891) message. When a single EDNS(0) -- @OPT@ pseudo-RR is present in the additional section of a DNS message, it is -- processed as an @EDNS(0)@ extension header. The @OPT@ pseudo-RR@ is then -- elided from the additional section of the decoded message. -- -- The EDNS @OPT@ pseudo-RR augments the message error status with an 8-bit -- field that together with the 4-bit @RCODE@ from the unextended DNS header -- forms the full 12-bit extended @RCODE@. In order to avoid potential -- misinterpretation of the response @RCODE@, when the OPT record is decoded, -- the upper eight bits of the error status are combined with the @RCODE@ of -- the basic message header to form a single 12-bit result. The decoded 'EDNS' -- pseudo-header, omits the extended @RCODE@ bits, they are instead found in -- the upper eight bits of the message @RCODE@. -- -- Likewise, when decoding EDNS messages the extension flags are folded into -- the upper 16-bits of an extended 32-bit @flags@ field in the message header. -- Consequently, the 'EDNS' extension header record needs no extension @RCODE@ -- or @flags@ fields. -- -- The reverse process occurs when encoding messages. The low four bits of the -- message header @RCODE@ are encoded into the basic DNS header, while the -- upper eight bits are encoded as part of the EDNS @OPT@ pseudo-RR. -- Similarly, the high 16 bits of the flags are also encoded in the @OPT@ -- pseudo-RR. Encoding of messages with an @RCODE@ larger than 15 or any -- extension flags set fails unless EDNS is enabled. -- -- When encoding messages for transmission, the 'EDNS' extension header is used -- to generate the additional OPT record. Do not add explicit @OPT@ records to -- the additional section, instead configure EDNS via the message 'Net.DNSBase.Message.ednsHeader' -- field. -- -- The fixed part of an @OPT@ pseudo-RR is structured as follows -- ([RFC891 6.1.2](<https://tools.ietf.org/html/rfc6891#section-6.1.2>)): -- -- > +------------+--------------+------------------------------+ -- > | Field Name | Field Type | Description | -- > +------------+--------------+------------------------------+ -- > | NAME | domain name | MUST be 0 (root domain) | -- > | TYPE | u_int16_t | OPT (41) | -- > | CLASS | u_int16_t | requestor's UDP payload size | -- > | TTL | u_int32_t | extended RCODE and flags | -- > | RDLEN | u_int16_t | length of all RDATA | -- > | RDATA | octet stream | {attribute,value} pairs | -- > +------------+--------------+------------------------------+ -- -- The extended RCODE and flags, which OPT stores in the RR Time to Live -- (TTL) field, are structured as follows -- ([RFC6891 6.1.3](<https://tools.ietf.org/html/rfc6891#section-6.1.3>)): -- -- > +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ -- > | EXTENDED-RCODE | VERSION | -- > +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ -- > | DO| Z | -- > +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ -- data EDNS = EDNS { -- | EDNS version, presently only version 0 is defined. EDNS -> Word8 ednsVersion :: {-# UNPACK #-} Word8 -- | Supported UDP payload size. , EDNS -> Word16 ednsUdpSize :: {-# UNPACK #-} Word16 -- | EDNS options (e.g. 'Net.DNSBase.EDNS.Option.NSID.O_nsid', ...), corresponding to the (attribute, -- value) pairs in the RDATA field of the @OPT@ psuedo-RR. , EDNS -> [EdnsOption] ednsOptions :: [EdnsOption] } deriving (EDNS -> EDNS -> Bool (EDNS -> EDNS -> Bool) -> (EDNS -> EDNS -> Bool) -> Eq EDNS forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a $c== :: EDNS -> EDNS -> Bool == :: EDNS -> EDNS -> Bool $c/= :: EDNS -> EDNS -> Bool /= :: EDNS -> EDNS -> Bool Eq, Int -> EDNS -> ShowS [EDNS] -> ShowS EDNS -> String (Int -> EDNS -> ShowS) -> (EDNS -> String) -> ([EDNS] -> ShowS) -> Show EDNS forall a. (Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a $cshowsPrec :: Int -> EDNS -> ShowS showsPrec :: Int -> EDNS -> ShowS $cshow :: EDNS -> String show :: EDNS -> String $cshowList :: [EDNS] -> ShowS showList :: [EDNS] -> ShowS Show) -- | The default EDNS pseudo-header for queries. In accordance -- with the recommendation in -- [RFC9715, Appedix A](https://datatracker.ietf.org/doc/html/rfc9715#appendix-A-3) -- the UDP buffer size defaults to 1400 bytes, this should result -- in replies that fit into both the IPv4 and IPv6 MTU in typical -- Internet-connected networks. -- -- A small minority of IPv6 networks are rumoured to have smaller -- MTUs of around 1280 bytes, and the corresponding DNS UDP size -- might then be 1232 bytes. -- -- Since this library is a stub resolver, it is expected that the -- configured iterative resolvers are "near" enough to not require -- pessimistic UDP size limits. With a loopback conenction to a -- local resolver it may even make sense to set the UDP size limit -- at the 16KB maximum. -- -- There is no single best value for the buffer size, too large -- risks fragmentation issues, while too small risks TCP fallback -- which is more costly and may fail. -- -- @ -- defaultEDNS = EDNS -- { ednsVersion = 0 -- The default EDNS version is 0 -- , ednsUdpSize = 1400 -- RFC9715 recommended value -- , ednsOptions = [] -- No EDNS options by default -- } -- @ -- defaultEDNS :: EDNS defaultEDNS :: EDNS defaultEDNS = EDNS { ednsVersion :: Word8 ednsVersion = Word8 0 -- ^ The default EDNS version is 0 , ednsUdpSize :: Word16 ednsUdpSize = Word16 1400 -- ^ IPv6-safe UDP MTU , ednsOptions :: [EdnsOption] ednsOptions = [] -- ^ No EDNS options by default } -- | Maximum UDP size that can be advertised. If the 'ednsUdpSize' of 'EDNS' -- is larger, then this value is sent instead. This value is likely to work -- only for local nameservers on the loopback network. Servers generally -- enforce a smaller limit. -- -- >>> maxUdpSize -- 16384 maxUdpSize :: Word16 maxUdpSize :: Word16 maxUdpSize = Word16 16384 -- | Minimum UDP size to advertise. If 'ednsUdpSize' of 'EDNS' is smaller, -- then this value is sent instead. -- -- >>> minUdpSize -- 512 minUdpSize :: Word16 minUdpSize :: Word16 minUdpSize = Word16 512