{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE PatternSynonyms #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE CPP #-}

-- | Data types for DNS Query and Response.
--   For more information, see <http://www.ietf.org/rfc/rfc1035>.

module Network.DNS.Types (
  -- * Resource Records
    ResourceRecord (..)
  -- ** Types
  , Domain
  , CLASS
  , classIN
  , TTL
  -- ** Resource Record Types
  , TYPE (
    A
  , NS
  , CNAME
  , SOA
  , NULL
  , PTR
  , MX
  , TXT
  , AAAA
  , SRV
  , DNAME
  , OPT
  , DS
  , RRSIG
  , NSEC
  , DNSKEY
  , NSEC3
  , NSEC3PARAM
  , TLSA
  , CDS
  , CDNSKEY
  , CSYNC
  , ANY
  )
  , fromTYPE
  , toTYPE
  -- ** Resource Data
  , RData (..)
  -- * DNS Message
  , DNSMessage (..)
  , defaultQuery
  , defaultResponse
  , DNSFormat
  -- ** DNS Header
  , DNSHeader (..)
  , Identifier
  , QorR (..)
  , DNSFlags (..)
  , OPCODE (..)
  , RCODE (
    NoErr
  , FormatErr
  , ServFail
  , NameErr
  , NotImpl
  , Refused
  , YXDomain
  , YXRRSet
  , NXRRSet
  , NotAuth
  , NotZone
  , BadOpt
  )
  , fromRCODE
  , toRCODE
  , fromRCODEforHeader
  , toRCODEforHeader
  -- ** DNS Body
  , Question (..)
  -- * DNS Error
  , DNSError (..)
  -- * EDNS0
  , EDNS0
  , defaultEDNS0
  , maxUdpSize
  , minUdpSize
  -- ** Accessors
  , udpSize
  , extRCODE
  , dnssecOk
  , options
  -- ** Converters
  , fromEDNS0
  , toEDNS0
  -- * EDNS0 option data
  , OData (..)
  , OptCode (
    ClientSubnet
  )
  , fromOptCode
  , toOptCode
  -- * Other types
  , Mailbox
  ) where

import Control.Exception (Exception, IOException)
import qualified Data.ByteString.Base64 as B64 (encode)
import qualified Data.ByteString.Char8 as BS
import qualified Data.ByteString.Builder as L
import qualified Data.ByteString.Lazy as L
import Data.IP (IP, IPv4, IPv6)

import Network.DNS.Imports

----------------------------------------------------------------

-- | Type for domain.
type Domain = ByteString

-- | Type for a mailbox encoded on the wire as a DNS name, but the first label
-- is conceptually the user name, and sometimes has contains internal periods
-- that are not label separators. Therefore, in mailboxes \@ is used as the
-- separator between the first and second labels.
type Mailbox = ByteString

----------------------------------------------------------------

#if __GLASGOW_HASKELL__ >= 802
-- | Types for resource records.
newtype TYPE = TYPE {
    -- | From type to number.
    TYPE -> Word16
fromTYPE :: Word16
  } deriving (TYPE -> TYPE -> Bool
(TYPE -> TYPE -> Bool) -> (TYPE -> TYPE -> Bool) -> Eq TYPE
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: TYPE -> TYPE -> Bool
$c/= :: TYPE -> TYPE -> Bool
== :: TYPE -> TYPE -> Bool
$c== :: TYPE -> TYPE -> Bool
Eq, Eq TYPE
Eq TYPE
-> (TYPE -> TYPE -> Ordering)
-> (TYPE -> TYPE -> Bool)
-> (TYPE -> TYPE -> Bool)
-> (TYPE -> TYPE -> Bool)
-> (TYPE -> TYPE -> Bool)
-> (TYPE -> TYPE -> TYPE)
-> (TYPE -> TYPE -> TYPE)
-> Ord TYPE
TYPE -> TYPE -> Bool
TYPE -> TYPE -> Ordering
TYPE -> TYPE -> TYPE
forall a.
Eq a
-> (a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
min :: TYPE -> TYPE -> TYPE
$cmin :: TYPE -> TYPE -> TYPE
max :: TYPE -> TYPE -> TYPE
$cmax :: TYPE -> TYPE -> TYPE
>= :: TYPE -> TYPE -> Bool
$c>= :: TYPE -> TYPE -> Bool
> :: TYPE -> TYPE -> Bool
$c> :: TYPE -> TYPE -> Bool
<= :: TYPE -> TYPE -> Bool
$c<= :: TYPE -> TYPE -> Bool
< :: TYPE -> TYPE -> Bool
$c< :: TYPE -> TYPE -> Bool
compare :: TYPE -> TYPE -> Ordering
$ccompare :: TYPE -> TYPE -> Ordering
$cp1Ord :: Eq TYPE
Ord)

-- https://www.iana.org/assignments/dns-parameters/dns-parameters.xhtml#dns-parameters-4

-- | IPv4 address
pattern A :: TYPE
pattern $bA :: TYPE
$mA :: forall r. TYPE -> (Void# -> r) -> (Void# -> r) -> r
A          = TYPE   1
-- | An authoritative name serve
pattern NS :: TYPE
pattern $bNS :: TYPE
$mNS :: forall r. TYPE -> (Void# -> r) -> (Void# -> r) -> r
NS         = TYPE   2
-- | The canonical name for an alias
pattern CNAME :: TYPE
pattern $bCNAME :: TYPE
$mCNAME :: forall r. TYPE -> (Void# -> r) -> (Void# -> r) -> r
CNAME      = TYPE   5
-- | Marks the start of a zone of authority
pattern SOA :: TYPE
pattern $bSOA :: TYPE
$mSOA :: forall r. TYPE -> (Void# -> r) -> (Void# -> r) -> r
SOA        = TYPE   6
-- | A null RR (EXPERIMENTAL)
pattern NULL :: TYPE
pattern $bNULL :: TYPE
$mNULL :: forall r. TYPE -> (Void# -> r) -> (Void# -> r) -> r
NULL       = TYPE  10
-- | A domain name pointer
pattern PTR :: TYPE
pattern $bPTR :: TYPE
$mPTR :: forall r. TYPE -> (Void# -> r) -> (Void# -> r) -> r
PTR        = TYPE  12
-- | Mail exchange
pattern MX :: TYPE
pattern $bMX :: TYPE
$mMX :: forall r. TYPE -> (Void# -> r) -> (Void# -> r) -> r
MX         = TYPE  15
-- | Text strings
pattern TXT :: TYPE
pattern $bTXT :: TYPE
$mTXT :: forall r. TYPE -> (Void# -> r) -> (Void# -> r) -> r
TXT        = TYPE  16
-- | IPv6 Address
pattern AAAA :: TYPE
pattern $bAAAA :: TYPE
$mAAAA :: forall r. TYPE -> (Void# -> r) -> (Void# -> r) -> r
AAAA       = TYPE  28
-- | Server Selection (RFC2782)
pattern SRV :: TYPE
pattern $bSRV :: TYPE
$mSRV :: forall r. TYPE -> (Void# -> r) -> (Void# -> r) -> r
SRV        = TYPE  33
-- | DNAME (RFC6672)
pattern DNAME :: TYPE
pattern $bDNAME :: TYPE
$mDNAME :: forall r. TYPE -> (Void# -> r) -> (Void# -> r) -> r
DNAME      = TYPE  39 -- RFC 6672
-- | OPT (RFC6891)
pattern OPT :: TYPE
pattern $bOPT :: TYPE
$mOPT :: forall r. TYPE -> (Void# -> r) -> (Void# -> r) -> r
OPT        = TYPE  41 -- RFC 6891
-- | Delegation Signer (RFC4034)
pattern DS :: TYPE
pattern $bDS :: TYPE
$mDS :: forall r. TYPE -> (Void# -> r) -> (Void# -> r) -> r
DS         = TYPE  43 -- RFC 4034
-- | RRSIG (RFC4034)
pattern RRSIG :: TYPE
pattern $bRRSIG :: TYPE
$mRRSIG :: forall r. TYPE -> (Void# -> r) -> (Void# -> r) -> r
RRSIG      = TYPE  46 -- RFC 4034
-- | NSEC (RFC4034)
pattern NSEC :: TYPE
pattern $bNSEC :: TYPE
$mNSEC :: forall r. TYPE -> (Void# -> r) -> (Void# -> r) -> r
NSEC       = TYPE  47 -- RFC 4034
-- | DNSKEY (RFC4034)
pattern DNSKEY :: TYPE
pattern $bDNSKEY :: TYPE
$mDNSKEY :: forall r. TYPE -> (Void# -> r) -> (Void# -> r) -> r
DNSKEY     = TYPE  48 -- RFC 4034
-- | NSEC3 (RFC5155)
pattern NSEC3 :: TYPE
pattern $bNSEC3 :: TYPE
$mNSEC3 :: forall r. TYPE -> (Void# -> r) -> (Void# -> r) -> r
NSEC3      = TYPE  50 -- RFC 5155
-- | NSEC3PARAM (RFC5155)
pattern NSEC3PARAM :: TYPE
pattern $bNSEC3PARAM :: TYPE
$mNSEC3PARAM :: forall r. TYPE -> (Void# -> r) -> (Void# -> r) -> r
NSEC3PARAM = TYPE  51 -- RFC 5155
-- | TLSA (RFC6698)
pattern TLSA :: TYPE
pattern $bTLSA :: TYPE
$mTLSA :: forall r. TYPE -> (Void# -> r) -> (Void# -> r) -> r
TLSA       = TYPE  52 -- RFC 6698
-- | Child DS (RFC7344)
pattern CDS :: TYPE
pattern $bCDS :: TYPE
$mCDS :: forall r. TYPE -> (Void# -> r) -> (Void# -> r) -> r
CDS        = TYPE  59 -- RFC 7344
-- | DNSKEY(s) the Child wants reflected in DS (RFC7344)
pattern CDNSKEY :: TYPE
pattern $bCDNSKEY :: TYPE
$mCDNSKEY :: forall r. TYPE -> (Void# -> r) -> (Void# -> r) -> r
CDNSKEY    = TYPE  60 -- RFC 7344
-- | Child-To-Parent Synchronization (RFC7477)
pattern CSYNC :: TYPE
pattern $bCSYNC :: TYPE
$mCSYNC :: forall r. TYPE -> (Void# -> r) -> (Void# -> r) -> r
CSYNC      = TYPE  62 -- RFC 7477
-- | A request for all records the server/cache has available
pattern ANY :: TYPE
pattern $bANY :: TYPE
$mANY :: forall r. TYPE -> (Void# -> r) -> (Void# -> r) -> r
ANY        = TYPE 255

instance Show TYPE where
    show :: TYPE -> String
show TYPE
A          = String
"A"
    show TYPE
NS         = String
"NS"
    show TYPE
CNAME      = String
"CNAME"
    show TYPE
SOA        = String
"SOA"
    show TYPE
NULL       = String
"NULL"
    show TYPE
PTR        = String
"PTR"
    show TYPE
MX         = String
"MX"
    show TYPE
TXT        = String
"TXT"
    show TYPE
AAAA       = String
"AAAA"
    show TYPE
SRV        = String
"SRV"
    show TYPE
DNAME      = String
"DNAME"
    show TYPE
OPT        = String
"OPT"
    show TYPE
DS         = String
"DS"
    show TYPE
RRSIG      = String
"RRSIG"
    show TYPE
NSEC       = String
"NSEC"
    show TYPE
DNSKEY     = String
"DNSKEY"
    show TYPE
NSEC3      = String
"NSEC3"
    show TYPE
NSEC3PARAM = String
"NSEC3PARAM"
    show TYPE
TLSA       = String
"TLSA"
    show TYPE
CDS        = String
"CDS"
    show TYPE
CDNSKEY    = String
"CDNSKEY"
    show TYPE
CSYNC      = String
"CSYNC"
    show TYPE
ANY        = String
"ANY"
    show TYPE
x          = String
"TYPE " String -> ShowS
forall a. [a] -> [a] -> [a]
++ (Word16 -> String
forall a. Show a => a -> String
show (Word16 -> String) -> Word16 -> String
forall a b. (a -> b) -> a -> b
$ TYPE -> Word16
fromTYPE TYPE
x)

-- | From number to type.
toTYPE :: Word16 -> TYPE
toTYPE :: Word16 -> TYPE
toTYPE = Word16 -> TYPE
TYPE
#else
-- | Types for resource records.
data TYPE = A          -- ^ IPv4 address
          | NS         -- ^ An authoritative name serve
          | CNAME      -- ^ The canonical name for an alias
          | SOA        -- ^ Marks the start of a zone of authority
          | NULL       -- ^ A null RR (EXPERIMENTAL)
          | PTR        -- ^ A domain name pointer
          | MX         -- ^ Mail exchange
          | TXT        -- ^ Text strings
          | AAAA       -- ^ IPv6 Address
          | SRV        -- ^ Server Selection (RFC2782)
          | DNAME      -- ^ DNAME (RFC6672)
          | OPT        -- ^ OPT (RFC6891)
          | DS         -- ^ Delegation Signer (RFC4034)
          | RRSIG      -- ^ RRSIG (RFC4034)
          | NSEC       -- ^ NSEC (RFC4034)
          | DNSKEY     -- ^ DNSKEY (RFC4034)
          | NSEC3      -- ^ NSEC3 (RFC5155)
          | NSEC3PARAM -- ^ NSEC3PARAM (RFC5155)
          | TLSA       -- ^ TLSA (RFC6698)
          | CDS        -- ^ Child DS (RFC7344)
          | CDNSKEY    -- ^ DNSKEY(s) the Child wants reflected in DS (RFC7344)
          | CSYNC      -- ^ Child-To-Parent Synchronization (RFC7477)
          | ANY        -- ^ A request for all records the server/cache
                       --   has available
          | UnknownTYPE Word16  -- ^ Unknown type
          deriving (Eq, Ord, Show, Read)

-- | From type to number.
fromTYPE :: TYPE -> Word16
fromTYPE A          =  1
fromTYPE NS         =  2
fromTYPE CNAME      =  5
fromTYPE SOA        =  6
fromTYPE NULL       = 10
fromTYPE PTR        = 12
fromTYPE MX         = 15
fromTYPE TXT        = 16
fromTYPE AAAA       = 28
fromTYPE SRV        = 33
fromTYPE DNAME      = 39
fromTYPE OPT        = 41
fromTYPE DS         = 43
fromTYPE RRSIG      = 46
fromTYPE NSEC       = 47
fromTYPE DNSKEY     = 48
fromTYPE NSEC3      = 50
fromTYPE NSEC3PARAM = 51
fromTYPE TLSA       = 52
fromTYPE CDS        = 59
fromTYPE CDNSKEY    = 60
fromTYPE CSYNC      = 62
fromTYPE ANY        = 255
fromTYPE (UnknownTYPE x) = x

-- | From number to type.
toTYPE :: Word16 -> TYPE
toTYPE  1 = A
toTYPE  2 = NS
toTYPE  5 = CNAME
toTYPE  6 = SOA
toTYPE 10 = NULL
toTYPE 12 = PTR
toTYPE 15 = MX
toTYPE 16 = TXT
toTYPE 28 = AAAA
toTYPE 33 = SRV
toTYPE 39 = DNAME
toTYPE 41 = OPT
toTYPE 43 = DS
toTYPE 46 = RRSIG
toTYPE 47 = NSEC
toTYPE 48 = DNSKEY
toTYPE 50 = NSEC3
toTYPE 51 = NSEC3PARAM
toTYPE 52 = TLSA
toTYPE 59 = CDS
toTYPE 60 = CDNSKEY
toTYPE 62 = CSYNC
toTYPE 255 = ANY
toTYPE x   = UnknownTYPE x
#endif

----------------------------------------------------------------

-- | An enumeration of all possible DNS errors that can occur.
data DNSError =
    -- | The sequence number of the answer doesn't match our query. This
    --   could indicate foul play.
    SequenceNumberMismatch
    -- | The number of retries for the request was exceeded.
  | RetryLimitExceeded
    -- | TCP fallback request timed out.
  | TimeoutExpired
    -- | The answer has the correct sequence number, but returned an
    --   unexpected RDATA format.
  | UnexpectedRDATA
    -- | The domain for query is illegal.
  | IllegalDomain
    -- | The name server was unable to interpret the query.
  | FormatError
    -- | The name server was unable to process this query due to a
    --   problem with the name server.
  | ServerFailure
    -- | This code signifies that the domain name referenced in the
    --   query does not exist.
  | NameError
    -- | The name server does not support the requested kind of query.
  | NotImplemented
    -- | The name server refuses to perform the specified operation for
    --   policy reasons.  For example, a name
    --   server may not wish to provide the
    --   information to the particular requester,
    --   or a name server may not wish to perform
    --   a particular operation (e.g., zone transfer) for particular data.
  | OperationRefused
    -- | The server detected a malformed OPT RR.
  | BadOptRecord
    -- | Configuration is wrong.
  | BadConfiguration
    -- | Network failure.
  | NetworkFailure IOException
    -- | Error is unknown
  | DecodeError String
  | UnknownDNSError
  deriving (DNSError -> DNSError -> Bool
(DNSError -> DNSError -> Bool)
-> (DNSError -> DNSError -> Bool) -> Eq DNSError
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: DNSError -> DNSError -> Bool
$c/= :: DNSError -> DNSError -> Bool
== :: DNSError -> DNSError -> Bool
$c== :: DNSError -> DNSError -> Bool
Eq, Int -> DNSError -> ShowS
[DNSError] -> ShowS
DNSError -> String
(Int -> DNSError -> ShowS)
-> (DNSError -> String) -> ([DNSError] -> ShowS) -> Show DNSError
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [DNSError] -> ShowS
$cshowList :: [DNSError] -> ShowS
show :: DNSError -> String
$cshow :: DNSError -> String
showsPrec :: Int -> DNSError -> ShowS
$cshowsPrec :: Int -> DNSError -> ShowS
Show, Typeable)

instance Exception DNSError

-- | Raw data format for DNS Query and Response.
data DNSMessage = DNSMessage {
    DNSMessage -> DNSHeader
header     :: DNSHeader        -- ^ Header
  , DNSMessage -> [Question]
question   :: [Question]       -- ^ The question for the name server
  , DNSMessage -> [ResourceRecord]
answer     :: [ResourceRecord] -- ^ RRs answering the question
  , DNSMessage -> [ResourceRecord]
authority  :: [ResourceRecord] -- ^ RRs pointing toward an authority
  , DNSMessage -> [ResourceRecord]
additional :: [ResourceRecord] -- ^ RRs holding additional information
  } deriving (DNSMessage -> DNSMessage -> Bool
(DNSMessage -> DNSMessage -> Bool)
-> (DNSMessage -> DNSMessage -> Bool) -> Eq DNSMessage
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: DNSMessage -> DNSMessage -> Bool
$c/= :: DNSMessage -> DNSMessage -> Bool
== :: DNSMessage -> DNSMessage -> Bool
$c== :: DNSMessage -> DNSMessage -> Bool
Eq, Int -> DNSMessage -> ShowS
[DNSMessage] -> ShowS
DNSMessage -> String
(Int -> DNSMessage -> ShowS)
-> (DNSMessage -> String)
-> ([DNSMessage] -> ShowS)
-> Show DNSMessage
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [DNSMessage] -> ShowS
$cshowList :: [DNSMessage] -> ShowS
show :: DNSMessage -> String
$cshow :: DNSMessage -> String
showsPrec :: Int -> DNSMessage -> ShowS
$cshowsPrec :: Int -> DNSMessage -> ShowS
Show)

{-# DEPRECATED DNSFormat "Use DNSMessage instead" #-}
-- | For backward compatibility.
type DNSFormat = DNSMessage

-- | An identifier assigned by the program that
--   generates any kind of query.
type Identifier = Word16

-- | Raw data format for the header of DNS Query and Response.
data DNSHeader = DNSHeader {
    DNSHeader -> Word16
identifier :: Identifier -- ^ An identifier.
  , DNSHeader -> DNSFlags
flags      :: DNSFlags   -- ^ The second 16bit word.
  } deriving (DNSHeader -> DNSHeader -> Bool
(DNSHeader -> DNSHeader -> Bool)
-> (DNSHeader -> DNSHeader -> Bool) -> Eq DNSHeader
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: DNSHeader -> DNSHeader -> Bool
$c/= :: DNSHeader -> DNSHeader -> Bool
== :: DNSHeader -> DNSHeader -> Bool
$c== :: DNSHeader -> DNSHeader -> Bool
Eq, Int -> DNSHeader -> ShowS
[DNSHeader] -> ShowS
DNSHeader -> String
(Int -> DNSHeader -> ShowS)
-> (DNSHeader -> String)
-> ([DNSHeader] -> ShowS)
-> Show DNSHeader
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [DNSHeader] -> ShowS
$cshowList :: [DNSHeader] -> ShowS
show :: DNSHeader -> String
$cshow :: DNSHeader -> String
showsPrec :: Int -> DNSHeader -> ShowS
$cshowsPrec :: Int -> DNSHeader -> ShowS
Show)

-- | Raw data format for the flags of DNS Query and Response.
data DNSFlags = DNSFlags {
    DNSFlags -> QorR
qOrR         :: QorR   -- ^ Query or response.
  , DNSFlags -> OPCODE
opcode       :: OPCODE -- ^ Kind of query.
  , DNSFlags -> Bool
authAnswer   :: Bool   -- ^ Authoritative Answer - this bit is valid in responses,
                           -- and specifies that the responding name server is an
                           -- authority for the domain name in question section.
  , DNSFlags -> Bool
trunCation   :: Bool   -- ^ TrunCation - specifies that this message was truncated
                           -- due to length greater than that permitted on the
                           -- transmission channel.
  , DNSFlags -> Bool
recDesired   :: Bool   -- ^ Recursion Desired - this bit may be set in a query and
                           -- is copied into the response.  If RD is set, it directs
                           -- the name server to pursue the query recursively.
                           -- Recursive query support is optional.
  , DNSFlags -> Bool
recAvailable :: Bool   -- ^ Recursion Available - this be is set or cleared in a
                           -- response, and denotes whether recursive query support is
                           -- available in the name server.

  , DNSFlags -> RCODE
rcode        :: RCODE  -- ^ Response code.
  , DNSFlags -> Bool
authenData   :: Bool   -- ^ Authentic Data (RFC4035).
  } deriving (DNSFlags -> DNSFlags -> Bool
(DNSFlags -> DNSFlags -> Bool)
-> (DNSFlags -> DNSFlags -> Bool) -> Eq DNSFlags
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: DNSFlags -> DNSFlags -> Bool
$c/= :: DNSFlags -> DNSFlags -> Bool
== :: DNSFlags -> DNSFlags -> Bool
$c== :: DNSFlags -> DNSFlags -> Bool
Eq, Int -> DNSFlags -> ShowS
[DNSFlags] -> ShowS
DNSFlags -> String
(Int -> DNSFlags -> ShowS)
-> (DNSFlags -> String) -> ([DNSFlags] -> ShowS) -> Show DNSFlags
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [DNSFlags] -> ShowS
$cshowList :: [DNSFlags] -> ShowS
show :: DNSFlags -> String
$cshow :: DNSFlags -> String
showsPrec :: Int -> DNSFlags -> ShowS
$cshowsPrec :: Int -> DNSFlags -> ShowS
Show)

----------------------------------------------------------------

-- | Query or response.
data QorR = QR_Query    -- ^ Query.
          | QR_Response -- ^ Response.
          deriving (QorR -> QorR -> Bool
(QorR -> QorR -> Bool) -> (QorR -> QorR -> Bool) -> Eq QorR
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: QorR -> QorR -> Bool
$c/= :: QorR -> QorR -> Bool
== :: QorR -> QorR -> Bool
$c== :: QorR -> QorR -> Bool
Eq, Int -> QorR -> ShowS
[QorR] -> ShowS
QorR -> String
(Int -> QorR -> ShowS)
-> (QorR -> String) -> ([QorR] -> ShowS) -> Show QorR
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [QorR] -> ShowS
$cshowList :: [QorR] -> ShowS
show :: QorR -> String
$cshow :: QorR -> String
showsPrec :: Int -> QorR -> ShowS
$cshowsPrec :: Int -> QorR -> ShowS
Show, Int -> QorR
QorR -> Int
QorR -> [QorR]
QorR -> QorR
QorR -> QorR -> [QorR]
QorR -> QorR -> QorR -> [QorR]
(QorR -> QorR)
-> (QorR -> QorR)
-> (Int -> QorR)
-> (QorR -> Int)
-> (QorR -> [QorR])
-> (QorR -> QorR -> [QorR])
-> (QorR -> QorR -> [QorR])
-> (QorR -> QorR -> QorR -> [QorR])
-> Enum QorR
forall a.
(a -> a)
-> (a -> a)
-> (Int -> a)
-> (a -> Int)
-> (a -> [a])
-> (a -> a -> [a])
-> (a -> a -> [a])
-> (a -> a -> a -> [a])
-> Enum a
enumFromThenTo :: QorR -> QorR -> QorR -> [QorR]
$cenumFromThenTo :: QorR -> QorR -> QorR -> [QorR]
enumFromTo :: QorR -> QorR -> [QorR]
$cenumFromTo :: QorR -> QorR -> [QorR]
enumFromThen :: QorR -> QorR -> [QorR]
$cenumFromThen :: QorR -> QorR -> [QorR]
enumFrom :: QorR -> [QorR]
$cenumFrom :: QorR -> [QorR]
fromEnum :: QorR -> Int
$cfromEnum :: QorR -> Int
toEnum :: Int -> QorR
$ctoEnum :: Int -> QorR
pred :: QorR -> QorR
$cpred :: QorR -> QorR
succ :: QorR -> QorR
$csucc :: QorR -> QorR
Enum, QorR
QorR -> QorR -> Bounded QorR
forall a. a -> a -> Bounded a
maxBound :: QorR
$cmaxBound :: QorR
minBound :: QorR
$cminBound :: QorR
Bounded)

-- | Kind of query.
data OPCODE
  = OP_STD -- ^ A standard query.
  | OP_INV -- ^ An inverse query.
  | OP_SSR -- ^ A server status request.
  deriving (OPCODE -> OPCODE -> Bool
(OPCODE -> OPCODE -> Bool)
-> (OPCODE -> OPCODE -> Bool) -> Eq OPCODE
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: OPCODE -> OPCODE -> Bool
$c/= :: OPCODE -> OPCODE -> Bool
== :: OPCODE -> OPCODE -> Bool
$c== :: OPCODE -> OPCODE -> Bool
Eq, Int -> OPCODE -> ShowS
[OPCODE] -> ShowS
OPCODE -> String
(Int -> OPCODE -> ShowS)
-> (OPCODE -> String) -> ([OPCODE] -> ShowS) -> Show OPCODE
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [OPCODE] -> ShowS
$cshowList :: [OPCODE] -> ShowS
show :: OPCODE -> String
$cshow :: OPCODE -> String
showsPrec :: Int -> OPCODE -> ShowS
$cshowsPrec :: Int -> OPCODE -> ShowS
Show, Int -> OPCODE
OPCODE -> Int
OPCODE -> [OPCODE]
OPCODE -> OPCODE
OPCODE -> OPCODE -> [OPCODE]
OPCODE -> OPCODE -> OPCODE -> [OPCODE]
(OPCODE -> OPCODE)
-> (OPCODE -> OPCODE)
-> (Int -> OPCODE)
-> (OPCODE -> Int)
-> (OPCODE -> [OPCODE])
-> (OPCODE -> OPCODE -> [OPCODE])
-> (OPCODE -> OPCODE -> [OPCODE])
-> (OPCODE -> OPCODE -> OPCODE -> [OPCODE])
-> Enum OPCODE
forall a.
(a -> a)
-> (a -> a)
-> (Int -> a)
-> (a -> Int)
-> (a -> [a])
-> (a -> a -> [a])
-> (a -> a -> [a])
-> (a -> a -> a -> [a])
-> Enum a
enumFromThenTo :: OPCODE -> OPCODE -> OPCODE -> [OPCODE]
$cenumFromThenTo :: OPCODE -> OPCODE -> OPCODE -> [OPCODE]
enumFromTo :: OPCODE -> OPCODE -> [OPCODE]
$cenumFromTo :: OPCODE -> OPCODE -> [OPCODE]
enumFromThen :: OPCODE -> OPCODE -> [OPCODE]
$cenumFromThen :: OPCODE -> OPCODE -> [OPCODE]
enumFrom :: OPCODE -> [OPCODE]
$cenumFrom :: OPCODE -> [OPCODE]
fromEnum :: OPCODE -> Int
$cfromEnum :: OPCODE -> Int
toEnum :: Int -> OPCODE
$ctoEnum :: Int -> OPCODE
pred :: OPCODE -> OPCODE
$cpred :: OPCODE -> OPCODE
succ :: OPCODE -> OPCODE
$csucc :: OPCODE -> OPCODE
Enum, OPCODE
OPCODE -> OPCODE -> Bounded OPCODE
forall a. a -> a -> Bounded a
maxBound :: OPCODE
$cmaxBound :: OPCODE
minBound :: OPCODE
$cminBound :: OPCODE
Bounded)

----------------------------------------------------------------

#if __GLASGOW_HASKELL__ >= 802
-- | Response code including EDNS0's 12bit ones.
newtype RCODE = RCODE {
    -- | From rcode to number.
    RCODE -> Word16
fromRCODE :: Word16
  } deriving (RCODE -> RCODE -> Bool
(RCODE -> RCODE -> Bool) -> (RCODE -> RCODE -> Bool) -> Eq RCODE
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: RCODE -> RCODE -> Bool
$c/= :: RCODE -> RCODE -> Bool
== :: RCODE -> RCODE -> Bool
$c== :: RCODE -> RCODE -> Bool
Eq)

-- | Provide an Enum instance for backwards compatibility
instance Enum RCODE where
    fromEnum :: RCODE -> Int
fromEnum = Word16 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word16 -> Int) -> (RCODE -> Word16) -> RCODE -> Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. RCODE -> Word16
fromRCODE
    toEnum :: Int -> RCODE
toEnum = Word16 -> RCODE
RCODE (Word16 -> RCODE) -> (Int -> Word16) -> Int -> RCODE
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> Word16
forall a b. (Integral a, Num b) => a -> b
fromIntegral

-- | No error condition.
pattern NoErr     :: RCODE
pattern $bNoErr :: RCODE
$mNoErr :: forall r. RCODE -> (Void# -> r) -> (Void# -> r) -> r
NoErr      = RCODE  0
-- | Format error - The name server was
--   unable to interpret the query.
pattern FormatErr :: RCODE
pattern $bFormatErr :: RCODE
$mFormatErr :: forall r. RCODE -> (Void# -> r) -> (Void# -> r) -> r
FormatErr  = RCODE  1
-- | Server failure - The name server was
--   unable to process this query due to a
--   problem with the name server.
pattern ServFail  :: RCODE
pattern $bServFail :: RCODE
$mServFail :: forall r. RCODE -> (Void# -> r) -> (Void# -> r) -> r
ServFail   = RCODE  2
-- | Name Error - Meaningful only for
--   responses from an authoritative name
--   server, this code signifies that the
--   domain name referenced in the query does
--   not exist.
pattern NameErr   :: RCODE
pattern $bNameErr :: RCODE
$mNameErr :: forall r. RCODE -> (Void# -> r) -> (Void# -> r) -> r
NameErr    = RCODE  3
-- | Not Implemented - The name server does
--   not support the requested kind of query.
pattern NotImpl   :: RCODE
pattern $bNotImpl :: RCODE
$mNotImpl :: forall r. RCODE -> (Void# -> r) -> (Void# -> r) -> r
NotImpl    = RCODE  4
-- | Refused - The name server refuses to
--   perform the specified operation for
--   policy reasons.  For example, a name
--   server may not wish to provide the
--   information to the particular requester,
--   or a name server may not wish to perform
--   a particular operation (e.g., zone
--   transfer) for particular data.
pattern Refused   :: RCODE
pattern $bRefused :: RCODE
$mRefused :: forall r. RCODE -> (Void# -> r) -> (Void# -> r) -> r
Refused    = RCODE  5
-- | YXDomain - Dynamic update response, a pre-requisite domain that should not
-- exist, does exist.
pattern YXDomain :: RCODE
pattern $bYXDomain :: RCODE
$mYXDomain :: forall r. RCODE -> (Void# -> r) -> (Void# -> r) -> r
YXDomain  = RCODE 6
-- | YXRRSet - Dynamic update response, a pre-requisite RRSet that should not
-- exist, does exist.
pattern YXRRSet  :: RCODE
pattern $bYXRRSet :: RCODE
$mYXRRSet :: forall r. RCODE -> (Void# -> r) -> (Void# -> r) -> r
YXRRSet   = RCODE 7
-- | NXRRSet - Dynamic update response, a pre-requisite RRSet that should
-- exist, does not exist.
pattern NXRRSet  :: RCODE
pattern $bNXRRSet :: RCODE
$mNXRRSet :: forall r. RCODE -> (Void# -> r) -> (Void# -> r) -> r
NXRRSet   = RCODE 8
-- | NotAuth - Dynamic update response, the server is not authoritative for the
-- zone named in the Zone Section.
pattern NotAuth  :: RCODE
pattern $bNotAuth :: RCODE
$mNotAuth :: forall r. RCODE -> (Void# -> r) -> (Void# -> r) -> r
NotAuth   = RCODE 9
-- | NotZone - Dynamic update response, a name used in the Prerequisite or
-- Update Section is not within the zone denoted by the Zone Section.
pattern NotZone  :: RCODE
pattern $bNotZone :: RCODE
$mNotZone :: forall r. RCODE -> (Void# -> r) -> (Void# -> r) -> r
NotZone   = RCODE 10
-- | Bad OPT Version (RFC 6891) or TSIG Signature Failure (RFC2845).
pattern BadOpt    :: RCODE
pattern $bBadOpt :: RCODE
$mBadOpt :: forall r. RCODE -> (Void# -> r) -> (Void# -> r) -> r
BadOpt     = RCODE 16

-- | Use https://tools.ietf.org/html/rfc2929#section-2.3 names for DNS RCODEs
instance Show RCODE where
    show :: RCODE -> String
show RCODE
NoErr     = String
"NoError"
    show RCODE
FormatErr = String
"FormErr"
    show RCODE
ServFail  = String
"ServFail"
    show RCODE
NameErr   = String
"NXDomain"
    show RCODE
NotImpl   = String
"NotImp"
    show RCODE
Refused   = String
"Refused"
    show RCODE
YXDomain  = String
"YXDomain"
    show RCODE
YXRRSet   = String
"YXRRSet"
    show RCODE
NotAuth   = String
"NotAuth"
    show RCODE
NotZone   = String
"NotZone"
    show RCODE
BadOpt    = String
"BADVERS"
    show RCODE
x         = String
"RCODE " String -> ShowS
forall a. [a] -> [a] -> [a]
++ (Word16 -> String
forall a. Show a => a -> String
show (Word16 -> String) -> Word16 -> String
forall a b. (a -> b) -> a -> b
$ RCODE -> Word16
fromRCODE RCODE
x)

-- | From number to rcode.
toRCODE :: Word16 -> RCODE
toRCODE :: Word16 -> RCODE
toRCODE = Word16 -> RCODE
RCODE

-- | From rcode to number for header (4bits only).
fromRCODEforHeader :: RCODE -> Word16
fromRCODEforHeader :: RCODE -> Word16
fromRCODEforHeader (RCODE Word16
w) = Word16
w Word16 -> Word16 -> Word16
forall a. Bits a => a -> a -> a
.&. Word16
0x0f

-- | From number in header to rcode (4bits only).
toRCODEforHeader :: Word16 -> RCODE
toRCODEforHeader :: Word16 -> RCODE
toRCODEforHeader Word16
w = Word16 -> RCODE
RCODE (Word16
w Word16 -> Word16 -> Word16
forall a. Bits a => a -> a -> a
.&. Word16
0x0f)
#else
-- | Response code.
data RCODE
  = NoErr     -- ^ No error condition.
  | FormatErr -- ^ Format error - The name server was
              --   unable to interpret the query.
  | ServFail  -- ^ Server failure - The name server was
              --   unable to process this query due to a
              --   problem with the name server.
  | NameErr   -- ^ Name Error - Meaningful only for
              --   responses from an authoritative name
              --   server, this code signifies that the
              --   domain name referenced in the query does
              --   not exist.
  | NotImpl   -- ^ Not Implemented - The name server does
              --   not support the requested kind of query.
  | Refused   -- ^ Refused - The name server refuses to
              --   perform the specified operation for
              --   policy reasons.  For example, a name
              --   server may not wish to provide the
              --   information to the particular requester,
              --   or a name server may not wish to perform
              --   a particular operation (e.g., zone
              --   transfer) for particular data.
  | YXDomain  -- ^ Dynamic update response, a pre-requisite
              --   domain that should not exist, does exist.
  | YXRRSet   -- ^ Dynamic update response, a pre-requisite
              --   RRSet that should not exist, does exist.
  | NXRRSet   -- ^ Dynamic update response, a pre-requisite
              --   RRSet that should exist, does not exist.
  | NotAuth   -- ^ Dynamic update response, the server is not
              --   authoritative for the zone named in the Zone Section.
  | NotZone   -- ^ Dynamic update response, a name used in the
              --   Prerequisite or Update Section is not within the zone
              --   denoted by the Zone Section.
  | BadOpt    -- ^ Bad OPT Version (RFC 6891) or TSIG Signature
              --   Failure (RFC2845).
  | UnknownRCODE Word16
  deriving (Eq, Ord, Show)

-- | From rcode to number.
fromRCODE :: RCODE -> Word16
fromRCODE NoErr     =  0
fromRCODE FormatErr =  1
fromRCODE ServFail  =  2
fromRCODE NameErr   =  3
fromRCODE NotImpl   =  4
fromRCODE Refused   =  5
fromRCODE YXDomain  =  6
fromRCODE YXRRSet   =  7
fromRCODE NXRRSet   =  8
fromRCODE NotAuth   =  9
fromRCODE NotZone   = 10
fromRCODE BadOpt    = 16
fromRCODE (UnknownRCODE x) = x

-- | From number to rcode.
toRCODE :: Word16 -> RCODE
toRCODE  0 = NoErr
toRCODE  1 = FormatErr
toRCODE  2 = ServFail
toRCODE  3 = NameErr
toRCODE  4 = NotImpl
toRCODE  5 = Refused
toRCODE  6 = YXDomain
toRCODE  7 = YXRRSet
toRCODE  8 = NXRRSet
toRCODE  9 = NotAuth
toRCODE 10 = NotZone
toRCODE 16 = BadOpt
toRCODE  x = UnknownRCODE x

-- | From rcode to number for header (4bits only).
fromRCODEforHeader :: RCODE -> Word16
fromRCODEforHeader rc = fromRCODE rc .&. 0x0f

-- | From number in header to rcode (4bits only).
toRCODEforHeader :: Word16 -> RCODE
toRCODEforHeader w = toRCODE (w .&. 0x0f)
#endif

----------------------------------------------------------------

-- XXX: The Question really should also include the CLASS
--
-- | Raw data format for DNS questions.
data Question = Question {
    Question -> Domain
qname  :: Domain -- ^ A domain name
  , Question -> TYPE
qtype  :: TYPE   -- ^ The type of the query
  } deriving (Question -> Question -> Bool
(Question -> Question -> Bool)
-> (Question -> Question -> Bool) -> Eq Question
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Question -> Question -> Bool
$c/= :: Question -> Question -> Bool
== :: Question -> Question -> Bool
$c== :: Question -> Question -> Bool
Eq, Int -> Question -> ShowS
[Question] -> ShowS
Question -> String
(Int -> Question -> ShowS)
-> (Question -> String) -> ([Question] -> ShowS) -> Show Question
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Question] -> ShowS
$cshowList :: [Question] -> ShowS
show :: Question -> String
$cshow :: Question -> String
showsPrec :: Int -> Question -> ShowS
$cshowsPrec :: Int -> Question -> ShowS
Show)

----------------------------------------------------------------

-- | Resource record class.
type CLASS = Word16

-- | Resource record class for the Internet.
classIN :: CLASS
classIN :: Word16
classIN = Word16
1

-- | Time to live in second.
type TTL = Word32

-- | Raw data format for resource records.
data ResourceRecord = ResourceRecord {
    ResourceRecord -> Domain
rrname  :: Domain -- ^ Name
  , ResourceRecord -> TYPE
rrtype  :: TYPE   -- ^ Resource record type
  , ResourceRecord -> Word16
rrclass :: CLASS  -- ^ Resource record class
  , ResourceRecord -> TTL
rrttl   :: TTL    -- ^ Time to live
  , ResourceRecord -> RData
rdata   :: RData  -- ^ Resource data
  } deriving (ResourceRecord -> ResourceRecord -> Bool
(ResourceRecord -> ResourceRecord -> Bool)
-> (ResourceRecord -> ResourceRecord -> Bool) -> Eq ResourceRecord
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: ResourceRecord -> ResourceRecord -> Bool
$c/= :: ResourceRecord -> ResourceRecord -> Bool
== :: ResourceRecord -> ResourceRecord -> Bool
$c== :: ResourceRecord -> ResourceRecord -> Bool
Eq,Int -> ResourceRecord -> ShowS
[ResourceRecord] -> ShowS
ResourceRecord -> String
(Int -> ResourceRecord -> ShowS)
-> (ResourceRecord -> String)
-> ([ResourceRecord] -> ShowS)
-> Show ResourceRecord
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [ResourceRecord] -> ShowS
$cshowList :: [ResourceRecord] -> ShowS
show :: ResourceRecord -> String
$cshow :: ResourceRecord -> String
showsPrec :: Int -> ResourceRecord -> ShowS
$cshowsPrec :: Int -> ResourceRecord -> ShowS
Show)

-- | Raw data format for each type.
data RData = RD_A IPv4           -- ^ IPv4 address
           | RD_NS Domain        -- ^ An authoritative name serve
           | RD_CNAME Domain     -- ^ The canonical name for an alias
           | RD_SOA Domain Mailbox Word32 Word32 Word32 Word32 Word32
                                 -- ^ Marks the start of a zone of authority
           | RD_NULL             -- ^ A null RR (EXPERIMENTAL).
                                 -- Anything can be in a NULL record,
                                 -- for now we just drop this data.
           | RD_PTR Domain       -- ^ A domain name pointer
           | RD_MX Word16 Domain -- ^ Mail exchange
           | RD_TXT ByteString   -- ^ Text strings
           | RD_AAAA IPv6        -- ^ IPv6 Address
           | RD_SRV Word16 Word16 Word16 Domain
                                 -- ^ Server Selection (RFC2782)
           | RD_DNAME Domain     -- ^ DNAME (RFC6672)
           | RD_OPT [OData]      -- ^ OPT (RFC6891)
           | RD_DS Word16 Word8 Word8 ByteString -- ^ Delegation Signer (RFC4034)
           --RD_RRSIG
           --RD_NSEC
           | RD_DNSKEY Word16 Word8 Word8 ByteString
                                 -- ^ DNSKEY (RFC4034)
           --RD_NSEC3
           | RD_NSEC3PARAM Word8 Word8 Word16 ByteString
           | RD_TLSA Word8 Word8 Word8 ByteString
                                 -- ^ TLSA (RFC6698)
           --RD_CDS
           --RD_CDNSKEY
           --RD_CSYNC
           | UnknownRData ByteString   -- ^ Unknown resource data
    deriving (RData -> RData -> Bool
(RData -> RData -> Bool) -> (RData -> RData -> Bool) -> Eq RData
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: RData -> RData -> Bool
$c/= :: RData -> RData -> Bool
== :: RData -> RData -> Bool
$c== :: RData -> RData -> Bool
Eq, Eq RData
Eq RData
-> (RData -> RData -> Ordering)
-> (RData -> RData -> Bool)
-> (RData -> RData -> Bool)
-> (RData -> RData -> Bool)
-> (RData -> RData -> Bool)
-> (RData -> RData -> RData)
-> (RData -> RData -> RData)
-> Ord RData
RData -> RData -> Bool
RData -> RData -> Ordering
RData -> RData -> RData
forall a.
Eq a
-> (a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
min :: RData -> RData -> RData
$cmin :: RData -> RData -> RData
max :: RData -> RData -> RData
$cmax :: RData -> RData -> RData
>= :: RData -> RData -> Bool
$c>= :: RData -> RData -> Bool
> :: RData -> RData -> Bool
$c> :: RData -> RData -> Bool
<= :: RData -> RData -> Bool
$c<= :: RData -> RData -> Bool
< :: RData -> RData -> Bool
$c< :: RData -> RData -> Bool
compare :: RData -> RData -> Ordering
$ccompare :: RData -> RData -> Ordering
$cp1Ord :: Eq RData
Ord)

instance Show RData where
  show :: RData -> String
show (RD_NS Domain
dom) = Domain -> String
BS.unpack Domain
dom
  show (RD_MX Word16
prf Domain
dom) = Word16 -> String
forall a. Show a => a -> String
show Word16
prf String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
" " String -> ShowS
forall a. [a] -> [a] -> [a]
++ Domain -> String
BS.unpack Domain
dom
  show (RD_CNAME Domain
dom) = Domain -> String
BS.unpack Domain
dom
  show (RD_DNAME Domain
dom) = Domain -> String
BS.unpack Domain
dom
  show (RD_A IPv4
a) = IPv4 -> String
forall a. Show a => a -> String
show IPv4
a
  show (RD_AAAA IPv6
aaaa) = IPv6 -> String
forall a. Show a => a -> String
show IPv6
aaaa
  show (RD_TXT Domain
txt) = Domain -> String
BS.unpack Domain
txt
  show (RD_SOA Domain
mn Domain
mr TTL
serial TTL
refresh TTL
retry TTL
expire TTL
mi) = Domain -> String
BS.unpack Domain
mn String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
" " String -> ShowS
forall a. [a] -> [a] -> [a]
++ Domain -> String
BS.unpack Domain
mr String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
" " String -> ShowS
forall a. [a] -> [a] -> [a]
++
                                                       TTL -> String
forall a. Show a => a -> String
show TTL
serial String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
" " String -> ShowS
forall a. [a] -> [a] -> [a]
++ TTL -> String
forall a. Show a => a -> String
show TTL
refresh String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
" " String -> ShowS
forall a. [a] -> [a] -> [a]
++
                                                       TTL -> String
forall a. Show a => a -> String
show TTL
retry String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
" " String -> ShowS
forall a. [a] -> [a] -> [a]
++ TTL -> String
forall a. Show a => a -> String
show TTL
expire String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
" " String -> ShowS
forall a. [a] -> [a] -> [a]
++ TTL -> String
forall a. Show a => a -> String
show TTL
mi
  show (RD_PTR Domain
dom) = Domain -> String
BS.unpack Domain
dom
  show (RD_SRV Word16
pri Word16
wei Word16
prt Domain
dom) = Word16 -> String
forall a. Show a => a -> String
show Word16
pri String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
" " String -> ShowS
forall a. [a] -> [a] -> [a]
++ Word16 -> String
forall a. Show a => a -> String
show Word16
wei String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
" " String -> ShowS
forall a. [a] -> [a] -> [a]
++ Word16 -> String
forall a. Show a => a -> String
show Word16
prt String -> ShowS
forall a. [a] -> [a] -> [a]
++ Domain -> String
BS.unpack Domain
dom
  show (RD_OPT [OData]
od) = [OData] -> String
forall a. Show a => a -> String
show [OData]
od
  show (UnknownRData Domain
is) = Domain -> String
forall a. Show a => a -> String
show Domain
is
  show (RD_TLSA Word8
use Word8
sel Word8
mtype Domain
dgst) = Word8 -> String
forall a. Show a => a -> String
show Word8
use String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
" " String -> ShowS
forall a. [a] -> [a] -> [a]
++ Word8 -> String
forall a. Show a => a -> String
show Word8
sel String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
" " String -> ShowS
forall a. [a] -> [a] -> [a]
++ Word8 -> String
forall a. Show a => a -> String
show Word8
mtype String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
" " String -> ShowS
forall a. [a] -> [a] -> [a]
++ Domain -> String
hexencode Domain
dgst
  show (RD_DS Word16
t Word8
a Word8
dt Domain
dv) = Word16 -> String
forall a. Show a => a -> String
show Word16
t String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
" " String -> ShowS
forall a. [a] -> [a] -> [a]
++ Word8 -> String
forall a. Show a => a -> String
show Word8
a String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
" " String -> ShowS
forall a. [a] -> [a] -> [a]
++ Word8 -> String
forall a. Show a => a -> String
show Word8
dt String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
" " String -> ShowS
forall a. [a] -> [a] -> [a]
++ Domain -> String
hexencode Domain
dv
  show RData
RD_NULL = String
"NULL"
  show (RD_DNSKEY Word16
f Word8
p Word8
a Domain
k) = Word16 -> String
forall a. Show a => a -> String
show Word16
f String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
" " String -> ShowS
forall a. [a] -> [a] -> [a]
++ Word8 -> String
forall a. Show a => a -> String
show Word8
p String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
" " String -> ShowS
forall a. [a] -> [a] -> [a]
++ Word8 -> String
forall a. Show a => a -> String
show Word8
a String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
" " String -> ShowS
forall a. [a] -> [a] -> [a]
++ Domain -> String
b64encode Domain
k
  show (RD_NSEC3PARAM Word8
h Word8
f Word16
i Domain
s) = Word8 -> String
forall a. Show a => a -> String
show Word8
h String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
" " String -> ShowS
forall a. [a] -> [a] -> [a]
++ Word8 -> String
forall a. Show a => a -> String
show Word8
f String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
" " String -> ShowS
forall a. [a] -> [a] -> [a]
++ Word16 -> String
forall a. Show a => a -> String
show Word16
i String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
" " String -> ShowS
forall a. [a] -> [a] -> [a]
++ Domain -> String
showSalt Domain
s
    where
      showSalt :: Domain -> String
showSalt Domain
""    = String
"-"
      showSalt Domain
salt  = Domain -> String
hexencode Domain
salt

hexencode :: ByteString -> String
hexencode :: Domain -> String
hexencode = Domain -> String
BS.unpack (Domain -> String) -> (Domain -> Domain) -> Domain -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> Domain
L.toStrict (ByteString -> Domain)
-> (Domain -> ByteString) -> Domain -> Domain
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Builder -> ByteString
L.toLazyByteString (Builder -> ByteString)
-> (Domain -> Builder) -> Domain -> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Domain -> Builder
L.byteStringHex

b64encode :: ByteString -> String
b64encode :: Domain -> String
b64encode = Domain -> String
BS.unpack (Domain -> String) -> (Domain -> Domain) -> Domain -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Domain -> Domain
B64.encode

----------------------------------------------------------------

-- | Default query.
defaultQuery :: DNSMessage
defaultQuery :: DNSMessage
defaultQuery = DNSMessage :: DNSHeader
-> [Question]
-> [ResourceRecord]
-> [ResourceRecord]
-> [ResourceRecord]
-> DNSMessage
DNSMessage {
    header :: DNSHeader
header = DNSHeader :: Word16 -> DNSFlags -> DNSHeader
DNSHeader {
       identifier :: Word16
identifier = Word16
0
     , flags :: DNSFlags
flags = DNSFlags :: QorR
-> OPCODE
-> Bool
-> Bool
-> Bool
-> Bool
-> RCODE
-> Bool
-> DNSFlags
DNSFlags {
           qOrR :: QorR
qOrR         = QorR
QR_Query
         , opcode :: OPCODE
opcode       = OPCODE
OP_STD
         , authAnswer :: Bool
authAnswer   = Bool
False
         , trunCation :: Bool
trunCation   = Bool
False
         , recDesired :: Bool
recDesired   = Bool
True
         , recAvailable :: Bool
recAvailable = Bool
False
         , rcode :: RCODE
rcode        = RCODE
NoErr
         , authenData :: Bool
authenData   = Bool
False
         }
     }
  , question :: [Question]
question   = []
  , answer :: [ResourceRecord]
answer     = []
  , authority :: [ResourceRecord]
authority  = []
  , additional :: [ResourceRecord]
additional = []
  }

-- | Default response.
defaultResponse :: DNSMessage
defaultResponse :: DNSMessage
defaultResponse =
  let hd :: DNSHeader
hd = DNSMessage -> DNSHeader
header DNSMessage
defaultQuery
      flg :: DNSFlags
flg = DNSHeader -> DNSFlags
flags DNSHeader
hd
  in  DNSMessage
defaultQuery {
        header :: DNSHeader
header = DNSHeader
hd {
          flags :: DNSFlags
flags = DNSFlags
flg {
              qOrR :: QorR
qOrR = QorR
QR_Response
            , authAnswer :: Bool
authAnswer = Bool
True
            , recAvailable :: Bool
recAvailable = Bool
True
            , authenData :: Bool
authenData = Bool
False
            }
        }
      }

----------------------------------------------------------------
-- EDNS0 (RFC 6891)
----------------------------------------------------------------

-- | EDNS0 infromation defined in RFC 6891.
data EDNS0 = EDNS0 {
    -- | UDP payload size.
    EDNS0 -> Word16
udpSize  :: Word16
    -- | Extended RCODE.
  , EDNS0 -> RCODE
extRCODE :: RCODE
    -- | Is DNSSEC OK?
  , EDNS0 -> Bool
dnssecOk :: Bool
    -- | EDNS0 option data.
  , EDNS0 -> [OData]
options  :: [OData]
  } deriving (EDNS0 -> EDNS0 -> Bool
(EDNS0 -> EDNS0 -> Bool) -> (EDNS0 -> EDNS0 -> Bool) -> Eq EDNS0
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: EDNS0 -> EDNS0 -> Bool
$c/= :: EDNS0 -> EDNS0 -> Bool
== :: EDNS0 -> EDNS0 -> Bool
$c== :: EDNS0 -> EDNS0 -> Bool
Eq, Int -> EDNS0 -> ShowS
[EDNS0] -> ShowS
EDNS0 -> String
(Int -> EDNS0 -> ShowS)
-> (EDNS0 -> String) -> ([EDNS0] -> ShowS) -> Show EDNS0
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [EDNS0] -> ShowS
$cshowList :: [EDNS0] -> ShowS
show :: EDNS0 -> String
$cshow :: EDNS0 -> String
showsPrec :: Int -> EDNS0 -> ShowS
$cshowsPrec :: Int -> EDNS0 -> ShowS
Show)

#if __GLASGOW_HASKELL__ >= 802
-- | Default information for EDNS0.
--
-- >>> defaultEDNS0
-- EDNS0 {udpSize = 4096, extRCODE = NoError, dnssecOk = False, options = []}
#else
-- | Default information for EDNS0.
--
-- >>> defaultEDNS0
-- EDNS0 {udpSize = 4096, extRCODE = NoErr, dnssecOk = False, options = []}
#endif
defaultEDNS0 :: EDNS0
defaultEDNS0 :: EDNS0
defaultEDNS0 = Word16 -> RCODE -> Bool -> [OData] -> EDNS0
EDNS0 Word16
4096 RCODE
NoErr Bool
False []

-- | Maximum UDP size. If 'udpSize' of 'EDNS0' is larger than this,
--   'fromEDNS0' uses this value instead.
--
-- >>> maxUdpSize
-- 16384
maxUdpSize :: Word16
maxUdpSize :: Word16
maxUdpSize = Word16
16384

-- | Minimum UDP size. If 'udpSize' of 'EDNS0' is smaller than this,
--   'fromEDNS0' uses this value instead.
--
-- >>> minUdpSize
-- 512
minUdpSize :: Word16
minUdpSize :: Word16
minUdpSize = Word16
512

-- | Generating a resource record for the additional section based on EDNS0.
-- 'DNSFlags' is not generated.
-- Just set the same 'RCODE' to 'DNSFlags'.
fromEDNS0 :: EDNS0 -> ResourceRecord
fromEDNS0 :: EDNS0 -> ResourceRecord
fromEDNS0 EDNS0
edns = Domain -> TYPE -> Word16 -> TTL -> RData -> ResourceRecord
ResourceRecord Domain
name' TYPE
type' Word16
class' TTL
ttl' RData
rdata'
  where
    name' :: Domain
name'  = Domain
"."
    type' :: TYPE
type'  = TYPE
OPT
    class' :: Word16
class' = Word16
maxUdpSize Word16 -> Word16 -> Word16
forall a. Ord a => a -> a -> a
`min` (Word16
minUdpSize Word16 -> Word16 -> Word16
forall a. Ord a => a -> a -> a
`max` EDNS0 -> Word16
udpSize EDNS0
edns)
    ttl0' :: TTL
ttl0'   = Word16 -> TTL
forall a b. (Integral a, Num b) => a -> b
fromIntegral (RCODE -> Word16
fromRCODE (EDNS0 -> RCODE
extRCODE EDNS0
edns) Word16 -> Word16 -> Word16
forall a. Bits a => a -> a -> a
.&. Word16
0x0ff0) TTL -> Int -> TTL
forall a. Bits a => a -> Int -> a
`shiftL` Int
20
    ttl' :: TTL
ttl'
      | EDNS0 -> Bool
dnssecOk EDNS0
edns = TTL
ttl0' TTL -> Int -> TTL
forall a. Bits a => a -> Int -> a
`setBit` Int
15
      | Bool
otherwise     = TTL
ttl0'
    rdata' :: RData
rdata' = [OData] -> RData
RD_OPT ([OData] -> RData) -> [OData] -> RData
forall a b. (a -> b) -> a -> b
$ EDNS0 -> [OData]
options EDNS0
edns

-- | Generating EDNS0 information from the OPT RR.
toEDNS0 :: DNSFlags -> ResourceRecord -> Maybe EDNS0
toEDNS0 :: DNSFlags -> ResourceRecord -> Maybe EDNS0
toEDNS0 DNSFlags
flgs (ResourceRecord Domain
"." TYPE
OPT Word16
udpsiz TTL
ttl' (RD_OPT [OData]
opts)) =
    EDNS0 -> Maybe EDNS0
forall a. a -> Maybe a
Just (EDNS0 -> Maybe EDNS0) -> EDNS0 -> Maybe EDNS0
forall a b. (a -> b) -> a -> b
$ Word16 -> RCODE -> Bool -> [OData] -> EDNS0
EDNS0 Word16
udpsiz (Word16 -> RCODE
toRCODE Word16
erc) Bool
secok [OData]
opts
  where
    lp :: Word16
lp = RCODE -> Word16
fromRCODEforHeader (RCODE -> Word16) -> RCODE -> Word16
forall a b. (a -> b) -> a -> b
$ DNSFlags -> RCODE
rcode DNSFlags
flgs
    up :: TTL
up = TTL -> Int -> TTL
forall a. Bits a => a -> Int -> a
shiftR (TTL
ttl' TTL -> TTL -> TTL
forall a. Bits a => a -> a -> a
.&. TTL
0xff000000) Int
20
    erc :: Word16
erc = TTL -> Word16
forall a b. (Integral a, Num b) => a -> b
fromIntegral TTL
up Word16 -> Word16 -> Word16
forall a. Bits a => a -> a -> a
.|. Word16
lp
    secok :: Bool
secok = TTL
ttl' TTL -> Int -> Bool
forall a. Bits a => a -> Int -> Bool
`testBit` Int
15
toEDNS0 DNSFlags
_ ResourceRecord
_ = Maybe EDNS0
forall a. Maybe a
Nothing

----------------------------------------------------------------

#if __GLASGOW_HASKELL__ >= 802
-- | EDNS0 Option Code (RFC 6891).
newtype OptCode = OptCode {
    -- | From option code to number.
    OptCode -> Word16
fromOptCode :: Word16
  } deriving (OptCode -> OptCode -> Bool
(OptCode -> OptCode -> Bool)
-> (OptCode -> OptCode -> Bool) -> Eq OptCode
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: OptCode -> OptCode -> Bool
$c/= :: OptCode -> OptCode -> Bool
== :: OptCode -> OptCode -> Bool
$c== :: OptCode -> OptCode -> Bool
Eq,Eq OptCode
Eq OptCode
-> (OptCode -> OptCode -> Ordering)
-> (OptCode -> OptCode -> Bool)
-> (OptCode -> OptCode -> Bool)
-> (OptCode -> OptCode -> Bool)
-> (OptCode -> OptCode -> Bool)
-> (OptCode -> OptCode -> OptCode)
-> (OptCode -> OptCode -> OptCode)
-> Ord OptCode
OptCode -> OptCode -> Bool
OptCode -> OptCode -> Ordering
OptCode -> OptCode -> OptCode
forall a.
Eq a
-> (a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
min :: OptCode -> OptCode -> OptCode
$cmin :: OptCode -> OptCode -> OptCode
max :: OptCode -> OptCode -> OptCode
$cmax :: OptCode -> OptCode -> OptCode
>= :: OptCode -> OptCode -> Bool
$c>= :: OptCode -> OptCode -> Bool
> :: OptCode -> OptCode -> Bool
$c> :: OptCode -> OptCode -> Bool
<= :: OptCode -> OptCode -> Bool
$c<= :: OptCode -> OptCode -> Bool
< :: OptCode -> OptCode -> Bool
$c< :: OptCode -> OptCode -> Bool
compare :: OptCode -> OptCode -> Ordering
$ccompare :: OptCode -> OptCode -> Ordering
$cp1Ord :: Eq OptCode
Ord)

-- | Client subnet (RFC7871)
pattern ClientSubnet :: OptCode
pattern $bClientSubnet :: OptCode
$mClientSubnet :: forall r. OptCode -> (Void# -> r) -> (Void# -> r) -> r
ClientSubnet = OptCode 8

instance Show OptCode where
    show :: OptCode -> String
show OptCode
ClientSubnet = String
"ClientSubnet"
    show OptCode
x            = String
"OptCode " String -> ShowS
forall a. [a] -> [a] -> [a]
++ (Word16 -> String
forall a. Show a => a -> String
show (Word16 -> String) -> Word16 -> String
forall a b. (a -> b) -> a -> b
$ OptCode -> Word16
fromOptCode OptCode
x)

-- | From number to option code.
toOptCode :: Word16 -> OptCode
toOptCode :: Word16 -> OptCode
toOptCode = Word16 -> OptCode
OptCode
#else
-- | Option Code (RFC 6891).
data OptCode = ClientSubnet          -- ^ Client subnet (RFC7871)
             | UnknownOptCode Word16 -- ^ Unknown option code
    deriving (Eq, Ord, Show)

-- | From option code to number.
fromOptCode :: OptCode -> Word16
fromOptCode ClientSubnet = 8
fromOptCode (UnknownOptCode x) = x

-- | From number to option code.
toOptCode :: Word16 -> OptCode
toOptCode 8 = ClientSubnet
toOptCode x = UnknownOptCode x
#endif

----------------------------------------------------------------

-- | Optional resource data.
data OData = OD_ClientSubnet Word8 Word8 IP   -- ^ Client subnet (RFC7871)
           | UnknownOData OptCode ByteString  -- ^ Unknown optional type
    deriving (OData -> OData -> Bool
(OData -> OData -> Bool) -> (OData -> OData -> Bool) -> Eq OData
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: OData -> OData -> Bool
$c/= :: OData -> OData -> Bool
== :: OData -> OData -> Bool
$c== :: OData -> OData -> Bool
Eq,Int -> OData -> ShowS
[OData] -> ShowS
OData -> String
(Int -> OData -> ShowS)
-> (OData -> String) -> ([OData] -> ShowS) -> Show OData
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [OData] -> ShowS
$cshowList :: [OData] -> ShowS
show :: OData -> String
$cshow :: OData -> String
showsPrec :: Int -> OData -> ShowS
$cshowsPrec :: Int -> OData -> ShowS
Show,Eq OData
Eq OData
-> (OData -> OData -> Ordering)
-> (OData -> OData -> Bool)
-> (OData -> OData -> Bool)
-> (OData -> OData -> Bool)
-> (OData -> OData -> Bool)
-> (OData -> OData -> OData)
-> (OData -> OData -> OData)
-> Ord OData
OData -> OData -> Bool
OData -> OData -> Ordering
OData -> OData -> OData
forall a.
Eq a
-> (a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
min :: OData -> OData -> OData
$cmin :: OData -> OData -> OData
max :: OData -> OData -> OData
$cmax :: OData -> OData -> OData
>= :: OData -> OData -> Bool
$c>= :: OData -> OData -> Bool
> :: OData -> OData -> Bool
$c> :: OData -> OData -> Bool
<= :: OData -> OData -> Bool
$c<= :: OData -> OData -> Bool
< :: OData -> OData -> Bool
$c< :: OData -> OData -> Bool
compare :: OData -> OData -> Ordering
$ccompare :: OData -> OData -> Ordering
$cp1Ord :: Eq OData
Ord)