-- |
-- Module      : Net.DNSBase.Resolver.Internal.Encoding
-- Description : TBD
-- Copyright   : (c) Viktor Dukhovni, 2026
-- License     : BSD-3-Clause
-- Maintainer  : ietf-dane@dukhovni.org
-- Stability   : unstable
{-# LANGUAGE RecordWildCards #-}

module Net.DNSBase.Resolver.Internal.Encoding
    ( encodeQuestion
    , encodeQuestionLP
    ) where

import Net.DNSBase.EDNS.Internal.Option
import Net.DNSBase.Encode.Internal.State
import Net.DNSBase.Internal.Domain
import Net.DNSBase.Internal.EDNS
import Net.DNSBase.Internal.Error
import Net.DNSBase.Internal.Flags
import Net.DNSBase.Internal.Message
import Net.DNSBase.Internal.RData
import Net.DNSBase.Internal.Util
import Net.DNSBase.Resolver.Internal.Types

makeEDNS :: EDNS -> QueryControls -> Maybe EDNS
makeEDNS :: EDNS -> QueryControls -> Maybe EDNS
makeEDNS EDNS{[EdnsOption]
Word8
Word16
ednsVersion :: Word8
ednsUdpSize :: Word16
ednsOptions :: [EdnsOption]
ednsOptions :: EDNS -> [EdnsOption]
ednsUdpSize :: EDNS -> Word16
ednsVersion :: EDNS -> Word8
..} QueryControls
ctl
    | QueryControls
EdnsDisabled <- QueryControls
ctl = Maybe EDNS
forall a. Maybe a
Nothing
    | Word8
ver <- case QueryControls
ctl of { EdnsVersion Word8
vn -> Word8
vn; QueryControls
_ -> Word8
ednsVersion }
    , Word16
udp <- case QueryControls
ctl of { EdnsUdpSize Word16
sz -> Word16
sz; QueryControls
_ -> Word16
ednsUdpSize }
    , [EdnsOption]
opt <- case QueryControls
ctl of { EdnsOptionCtl OptionCtl -> OptionCtl
optf -> (OptionCtl -> OptionCtl) -> [EdnsOption] -> [EdnsOption]
applyOptionCtl OptionCtl -> OptionCtl
optf [EdnsOption]
ednsOptions }
      = EDNS -> Maybe EDNS
forall a. a -> Maybe a
Just (EDNS -> Maybe EDNS) -> EDNS -> Maybe EDNS
forall a b. (a -> b) -> a -> b
$ Word8 -> Word16 -> [EdnsOption] -> EDNS
EDNS Word8
ver Word16
udp [EdnsOption]
opt


_encodeQuestion :: (forall s. QueryID
                -> DNSFlags
                -> Maybe EDNS
                -> DnsTriple
                -> SPut s RData)
                -> QueryID
                -> QueryControls
                -> DnsTriple
                -> Either DNSError ByteString
_encodeQuestion :: (forall s.
 Word16 -> DNSFlags -> Maybe EDNS -> DnsTriple -> SPut s RData)
-> Word16
-> QueryControls
-> DnsTriple
-> Either DNSError ByteString
_encodeQuestion forall s.
Word16 -> DNSFlags -> Maybe EDNS -> DnsTriple -> SPut s RData
f = \Word16
qid QueryControls
qctl DnsTriple
q ->
    let flg :: DNSFlags
flg = QueryControls -> DNSFlags
makeQueryFlags QueryControls
qctl
        medns :: Maybe EDNS
medns = EDNS -> QueryControls -> Maybe EDNS
makeEDNS EDNS
defaultEDNS QueryControls
qctl
     in case (forall s. SPut s RData)
-> Either (EncodeErr (Maybe RData)) ByteString
forall r.
ErrorContext r =>
(forall s. SPut s r) -> Either (EncodeErr (Maybe r)) ByteString
encodeCompressed ((forall s. SPut s RData)
 -> Either (EncodeErr (Maybe RData)) ByteString)
-> (forall s. SPut s RData)
-> Either (EncodeErr (Maybe RData)) ByteString
forall a b. (a -> b) -> a -> b
$ Word16 -> DNSFlags -> Maybe EDNS -> DnsTriple -> SPutM s RData ()
forall s.
Word16 -> DNSFlags -> Maybe EDNS -> DnsTriple -> SPut s RData
f Word16
qid DNSFlags
flg Maybe EDNS
medns DnsTriple
q of
        Left EncodeErr (Maybe RData)
err -> DNSError -> Either DNSError ByteString
forall a b. a -> Either a b
Left (DNSError -> Either DNSError ByteString)
-> DNSError -> Either DNSError ByteString
forall a b. (a -> b) -> a -> b
$ EncodeContext -> DNSError
EncodeError (EncodeContext -> DNSError) -> EncodeContext -> DNSError
forall a b. (a -> b) -> a -> b
$ EncodeErr (Maybe RData) -> EncodeContext
forall r.
(Typeable r, Show r, Eq r) =>
EncodeErr r -> EncodeContext
EncodeContext EncodeErr (Maybe RData)
err
        Right ByteString
enc -> ByteString -> Either DNSError ByteString
forall a b. b -> Either a b
Right ByteString
enc


-- | Encode a DNS question for UDP using the provided 'QueryID', producing either a DNS error
-- if the encoding failed, or a 'ByteString' consisting of the wire-form DNS request.
--
-- The 'Net.DNSBase.Resolver.QueryControls' parameter can be used to modify the default values of various
-- DNS flags, as well as to configure EDNS version, UDP size, and options, or to disable
-- EDNS entirely.
--
-- The caller is responsible for generating the 'QueryID' via a securely seeded
-- CSPRNG.
encodeQuestion :: QueryID       -- ^ Crypto random request id
               -> QueryControls -- ^ Query flag and EDNS overrides
               -> DnsTriple     -- ^ Query name type and class
               -> Either DNSError ByteString
encodeQuestion :: Word16 -> QueryControls -> DnsTriple -> Either DNSError ByteString
encodeQuestion = (forall s.
 Word16 -> DNSFlags -> Maybe EDNS -> DnsTriple -> SPut s RData)
-> Word16
-> QueryControls
-> DnsTriple
-> Either DNSError ByteString
_encodeQuestion ((forall s.
  Word16 -> DNSFlags -> Maybe EDNS -> DnsTriple -> SPut s RData)
 -> Word16
 -> QueryControls
 -> DnsTriple
 -> Either DNSError ByteString)
-> (forall s.
    Word16 -> DNSFlags -> Maybe EDNS -> DnsTriple -> SPut s RData)
-> Word16
-> QueryControls
-> DnsTriple
-> Either DNSError ByteString
forall a b. (a -> b) -> a -> b
$ Word16 -> DNSFlags -> Maybe EDNS -> DnsTriple -> SPut s RData
forall s.
Word16 -> DNSFlags -> Maybe EDNS -> DnsTriple -> SPut s RData
putRequest

-- | Encode a DNS question for TCP using the provided 'QueryID', producing either a DNS error
-- if the encoding failed, or a 'ByteString' consisting of the wire-form DNS request with
-- a 2-octet unsigned integral length prefix in network byte order.
--
-- The 'Net.DNSBase.Resolver.QueryControls' parameter can be used to modify the default values of various
-- DNS flags, as well as to configure EDNS version, UDP size, and options, or to disable
-- EDNS entirely.
--
-- The caller is responsible for generating the 'QueryID' via a securely seeded
-- CSPRNG.
encodeQuestionLP :: QueryID
                 -> QueryControls
                 -> DnsTriple
                 -> Either DNSError ByteString
encodeQuestionLP :: Word16 -> QueryControls -> DnsTriple -> Either DNSError ByteString
encodeQuestionLP = (forall s.
 Word16 -> DNSFlags -> Maybe EDNS -> DnsTriple -> SPut s RData)
-> Word16
-> QueryControls
-> DnsTriple
-> Either DNSError ByteString
_encodeQuestion ((forall s.
  Word16 -> DNSFlags -> Maybe EDNS -> DnsTriple -> SPut s RData)
 -> Word16
 -> QueryControls
 -> DnsTriple
 -> Either DNSError ByteString)
-> (forall s.
    Word16 -> DNSFlags -> Maybe EDNS -> DnsTriple -> SPut s RData)
-> Word16
-> QueryControls
-> DnsTriple
-> Either DNSError ByteString
forall a b. (a -> b) -> a -> b
$ SPutM s RData () -> SPutM s RData ()
forall r s a. ErrorContext r => SPutM s r a -> SPutM s r a
passLen (SPutM s RData () -> SPutM s RData ())
-> (Word16
    -> DNSFlags -> Maybe EDNS -> DnsTriple -> SPutM s RData ())
-> Word16
-> DNSFlags
-> Maybe EDNS
-> DnsTriple
-> SPutM s RData ()
forall e f a b c d.
(e -> f) -> (a -> b -> c -> d -> e) -> a -> b -> c -> d -> f
`compose4` Word16 -> DNSFlags -> Maybe EDNS -> DnsTriple -> SPutM s RData ()
forall s.
Word16 -> DNSFlags -> Maybe EDNS -> DnsTriple -> SPut s RData
putRequest