-- | DNS message decoders. -- -- When in doubt, use the 'decodeAt' or 'decodeManyAt' functions, which -- correctly handle /circle-arithmetic/ DNS timestamps, e.g., in @RRSIG@ -- resource records. The 'decode', and 'decodeMany' functions are only -- appropriate in pure contexts when the current time is not available, and -- @RRSIG@ records are not expected or desired. -- -- The 'decodeMany' and 'decodeManyAt' functions decode a buffer holding one or -- more messages, each preceded by 16-bit length in network byte order. This -- encoding is generally only appropriate for DNS TCP, and because TCP does not -- preserve message boundaries, the decode is prepared to return a trailing -- message fragment to be completed and retried when more input arrives from -- network. -- module Network.DNS.Decode ( -- * Decoding a single DNS message decodeAt , decode -- * Decoding multple length-encoded DNS messages, -- e.g., from TCP traffic. , decodeManyAt , decodeMany ) where import qualified Data.ByteString as B import Network.DNS.Decode.Parsers import Network.DNS.Imports import Network.DNS.StateBinary import Network.DNS.Types.Internal ---------------------------------------------------------------- -- | Decode an input buffer containing a single encoded DNS message. If the -- input buffer has excess content beyond the end of the message an error is -- returned. DNS /circle-arithmetic/ timestamps (e.g. in RRSIG records) are -- interpreted at the supplied epoch time. -- decodeAt :: Int64 -- ^ current epoch time -> ByteString -- ^ encoded input buffer -> Either DNSError DNSMessage -- ^ decoded message or error decodeAt t bs = fst <$> runSGetAt t (fitSGet (B.length bs) getResponse) bs -- | Decode an input buffer containing a single encoded DNS message. If the -- input buffer has excess content beyond the end of the message an error is -- returned. DNS /circle-arithmetic/ timestamps (e.g. in RRSIG records) are -- interpreted based on a nominal time in the year 2073 chosen to maximize -- the time range for which this gives correct translations of 32-bit epoch -- times to absolute 64-bit epoch times. This will yield incorrect results -- starting circa 2141. -- decode :: ByteString -- ^ encoded input buffer -> Either DNSError DNSMessage -- ^ decoded message or error decode bs = fst <$> runSGet (fitSGet (B.length bs) getResponse) bs -- | Decode a buffer containing multiple encoded DNS messages each preceded by -- a 16-bit length in network byte order. Any left-over bytes of a partial -- message after the last complete message are returned as the second element -- of the result tuple. DNS /circle-arithmetic/ timestamps (e.g. in RRSIG -- records) are interpreted at the supplied epoch time. -- decodeManyAt :: Int64 -- ^ current epoch time -> ByteString -- ^ encoded input buffer -> Either DNSError ([DNSMessage], ByteString) -- ^ decoded messages and left-over partial message -- or error if any complete message fails to parse. decodeManyAt t bs = decodeMParse (decodeAt t) bs -- | Decode a buffer containing multiple encoded DNS messages each preceded by -- a 16-bit length in network byte order. Any left-over bytes of a partial -- message after the last complete message are returned as the second element -- of the result tuple. DNS /circle-arithmetic/ timestamps (e.g. in RRSIG -- records) are interpreted based on a nominal time in the year 2078 chosen to -- give correct dates for DNS timestamps over a 136 year time range from the -- date the root zone was signed on the 15th of July 2010 until the 21st of -- August in 2146. Outside this date range the output is off by some non-zero -- multiple 2\^32 seconds. -- decodeMany :: ByteString -- ^ encoded input buffer -> Either DNSError ([DNSMessage], ByteString) -- ^ decoded messages and left-over partial message -- or error if any complete message fails to parse. decodeMany bs = decodeMParse decode bs -- | Decode multiple messages using the given parser. -- decodeMParse :: (ByteString -> Either DNSError DNSMessage) -- ^ message decoder -> ByteString -- ^ enoded input buffer -> Either DNSError ([DNSMessage], ByteString) -- ^ decoded messages and left-over partial message -- or error if any complete message fails to parse. decodeMParse decoder bs = do ((bss, _), leftovers) <- runSGetWithLeftovers lengthEncoded bs msgs <- mapM decoder bss return (msgs, leftovers) where -- Read a list of length-encoded bytestrings lengthEncoded :: SGet [ByteString] lengthEncoded = many $ getInt16 >>= getNByteString