1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103
|
-- | 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
|