packages feed

dnsbase-1.0.0.0: tests/message.hs

{-# LANGUAGE
    OverloadedStrings
  , TemplateHaskell
  #-}
module Main (main) where

import qualified Data.Base16.Types as B16
import qualified Data.ByteString.Base16 as B16
import qualified Data.ByteString as B
import qualified System.Exit as Sys

import Net.DNSBase.Domain
import Net.DNSBase.Message
import Net.DNSBase.Flags
import Net.DNSBase.EDNS
import Net.DNSBase.EDNS.Option
import Net.DNSBase.EDNS.Option.NSID
import Net.DNSBase.Opcode
import Net.DNSBase.RCODE
import Net.DNSBase.RR
import Net.DNSBase.RRCLASS
import Net.DNSBase.RRTYPE
import Net.DNSBase.RData
import Net.DNSBase.RData.A
import Net.DNSBase.RData.SRV


check :: (Show a, Eq a)
      => Either a B.ByteString
      -> Either a B.ByteString
      -> IO ()
check actual wanted = do
    if actual == wanted
    then pure ()
    else do putStrLn $ "Wanted: " ++ show wanted
            putStrLn $ "Actual: " ++ show actual
            Sys.exitWith $ Sys.ExitFailure 1

-- | Encode a query with given features via the request encoder.
mkReq :: Domain
      -> RRTYPE
      -> DNSFlags
      -> Maybe EDNS
      -> Either (EncodeErr (Maybe RData)) B.ByteString
mkReq qname qtype flags edns =
    fmap (B16.extractBase16 . B16.encodeBase16')
    $ encodeVerbatim
    $ putRequest 0xbeef flags edns (DnsTriple qname qtype IN)


-- | Encode a query with given features via the generic encoder.
mkQuery :: Domain
        -> RRTYPE
        -> RCODE
        -> DNSFlags
        -> Maybe EDNS
        -> Either (EncodeErr (Maybe RData)) B.ByteString
mkQuery qname qtype rc flags edns =
    fmap (B16.extractBase16 . B16.encodeBase16')
    $ encodeVerbatim
    $ putMessage
    $ DNSMessage 0xbeef Query rc flags edns
                 [DnsTriple qname qtype IN]
                 [] [] []

-- | Create a response message with given features and name compression
mkAnswer :: Domain
         -> RRTYPE
         -> RCODE
         -> DNSFlags
         -> Maybe EDNS
         -> [RR]
         -> [RR]
         -> [RR]
         -> Either (EncodeErr (Maybe RData)) B.ByteString
mkAnswer qname qtype rc flags edns an ns ar =
    fmap (B16.extractBase16 . B16.encodeBase16')
    $ encodeCompressed
    $ putMessage
    $ DNSMessage 0xbeef Query rc (QRflag <> flags) edns
                 [DnsTriple qname qtype IN]
                 an ns ar


main :: IO ()
main = do
    let rdad = RDflag <> ADflag
    -- Minimal legacy query
    check (mkReq $$(dnLit8 "example.com") MX rdad Nothing) $
        Right $ "beef0120"         -- header
             <> "00010000"         -- qdcount, ancount
             <> "00000000"         -- nscount, arcount
             <> "076578616d706c65" -- "example."
             <> "03636f6d00"       -- "com."
             <> "000f0001"         -- MX IN

    -- Minimal EDNS query
    check (mkReq $$(dnLit8 "example.com") MX rdad (Just defaultEDNS)) $
        Right $ "beef0120"         -- header
             <> "00010000"         -- qdcount, ancount
             <> "00000001"         -- nscount, arcount
             <> "076578616d706c65" -- "example."
             <> "03636f6d00"       -- "com."
             <> "000f0001"         -- MX IN
             <> "000029"           -- . OPT
             <> "0578"             -- buffer size 1400
             <> "0000"             -- extRCODE=0 ednsVERSION=0
             <> "00000000"         -- Flags=0x0000, RDLEN=0

    -- EDNS with NSID option
    let nsid = EdnsOption $ O_NSID ""
        edns = defaultEDNS { ednsOptions = [nsid] }
        dord = DOflag <> RDflag
    check (mkReq $$(dnLit8 "example.com") MX dord (Just edns)) $
        Right $ "beef0100"         -- header
             <> "00010000"         -- qdcount, ancount
             <> "00000001"         -- nscount, arcount
             <> "076578616d706c65" -- "example."
             <> "03636f6d00"       -- "com."
             <> "000f0001"         -- MX IN
             <> "000029"           -- . OPT
             <> "0578"             -- buffer size 1400
             <> "0000"             -- extRCODE=0 ednsVERSION=0
             <> "80000004"         -- Flags=DO, RDLEN=4
             <> "00030000"         -- NSID, length 0

    -- Extended rcode with EDNS disabled
    check (mkReq $$(dnLit8 "example.com") MX (rdad <> DOflag) Nothing) $
        Left EDNSRequired

    -- Extended flags with EDNS disabled
    check (mkQuery $$(dnLit8 "example.com") MX BADVERS rdad Nothing) $
        Left EDNSRequired

    -- Extended RCODE and flags with EDNS enabled
    check (mkQuery $$(dnLit8 "example.com") MX BADVERS (rdad <> DOflag) (Just defaultEDNS)) $
        Right $ "beef0120"         -- header
             <> "00010000"         -- qdcount, ancount
             <> "00000001"         -- nscount, arcount
             <> "076578616d706c65" -- "example."
             <> "03636f6d00"       -- "com."
             <> "000f0001"         -- MX IN
             <> "000029"           -- . OPT
             <> "0578"             -- buffer size 1400
             <> "0100"             -- extRCODE=1 ednsVERSION=0
             <> "80000000"         -- Flags=0x8000, RDLEN=0

    -- EDNS answer with name compression
    let rdraad = RDflag <> RAflag <> ADflag
    check (mkAnswer $$(dnLit8 "example.com") MX NOERROR rdraad (Just defaultEDNS)
           [ RR $$(dnLit8 "example.com") IN 300
                $ RData $ T_MX 10 $$(dnLit8 "mx1.example.com")
           , RR $$(dnLit8 "example.com") IN 300
                $ RData $ T_MX 10 $$(dnLit8 "mx2.example.com") ]
           []
           [ RR $$(dnLit8 "mx1.example.com") IN 300
                $ RData $ T_A "192.0.2.1"
           , RR $$(dnLit8 "mx2.example.com") IN 300
                $ RData $ T_A "192.0.2.2" ]
        ) $
        Right $ "beef81a0"         -- 0. header
             <> "00010002"         -- 4. qdcount, ancount
             <> "00000003"         -- 8. nscount, arcount
             --
             <> "076578616d706c65" -- 12. "example."
             <> "03636f6d00"       -- 20. "com."
             <> "000f0001"         -- 25. MX IN
             --
             <> "c00c"             -- 29. "example.com" compressed
             <> "000f0001"         -- 31. MX IN
             <> "0000012c"         -- 35. TTL = 300
             <> "0008"             -- 39. RDLEN = 8
             <> "000a"             -- 41. pref = 10
             <> "036d7831c00c"     -- 43. exch = "mx1.example.com" compressed
             --
             <> "c00c"             -- 49. "example.com" compressed
             <> "000f0001"         -- 51. MX IN
             <> "0000012c"         -- 55. TTL = 300
             <> "0008"             -- 59. RDLEN = 8
             <> "000a"             -- 61. pref = 10
             <> "036d7832c00c"     -- 63. exch = "mx2.example.com" compressed
             --
             <> "000029"           -- 69. . OPT
             <> "0578"             -- 72. buffer size 1400
             <> "0000"             -- 74. extRCODE=0 ednsVERSION=0
             <> "00000000"         -- 76. Flags=0x0000, RDLEN=0
             --
             <> "c02b"             -- 80. "mx1.example.com" compressed
             <> "00010001"         -- 82. A IN
             <> "0000012c"         -- 86. TTL = 300
             <> "0004"             -- 90. RDLEN = 4
             <> "c0000201"         -- 92. 192.0.2.1
             --
             <> "c03f"             -- 96. "mx2.example.com" compressed
             <> "00010001"         -- 98. A IN
             <> "0000012c"         -- 102. TTL = 300
             <> "0004"             -- 106. RDLEN = 4
             <> "c0000202"         -- 108. 192.0.2.2