-- Hoogle documentation, generated by Haddock
-- See Hoogle, http://www.haskell.org/hoogle/

-- | DNS library in Haskell
--   
--   A thread-safe DNS library for both clients and servers written in pure
--   Haskell.
@package dns
@version 4.2.0

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

-- | Raw data format for resource records.
data ResourceRecord
ResourceRecord :: !Domain -> !TYPE -> !CLASS -> !TTL -> !RData -> ResourceRecord

-- | Name
[rrname] :: ResourceRecord -> !Domain

-- | Resource record type
[rrtype] :: ResourceRecord -> !TYPE

-- | Resource record class
[rrclass] :: ResourceRecord -> !CLASS

-- | Time to live
[rrttl] :: ResourceRecord -> !TTL

-- | Resource data
[rdata] :: ResourceRecord -> !RData

-- | Type alias for resource records in the answer section.
type Answers = [ResourceRecord]

-- | Type alias for resource records in the answer section.
type AuthorityRecords = [ResourceRecord]

-- | Type for resource records in the additional section.
type AdditionalRecords = [ResourceRecord]

-- | This type holds the presentation form of fully-qualified DNS
--   domain names encoded as ASCII A-labels, with '.' separators between
--   labels. Non-printing characters are escaped as \DDD (a
--   backslash, followed by three decimal digits). The special characters:
--    ", $, (, ), ;, @, and \ are escaped by prepending a
--   backslash. The trailing '.' is optional on input, but is recommended,
--   and is always added when decoding from wire form.
--   
--   The encoding of domain names to wire form, e.g. for
--   transmission in a query, requires the input encodings to be valid,
--   otherwise a DecodeError may be thrown. Domain names received in
--   wire form in DNS messages are escaped to this presentation form as
--   part of decoding the DNSMessage.
--   
--   This form is ASCII-only. Any conversion between A-label
--   ByteStrings, and U-label Text happens at whatever
--   layer maps user input to DNS names, or presents friendly DNS
--   names to the user. Not all users can read all scripts, and
--   applications that default to U-label form should ideally give the user
--   a choice to see the A-label form. Examples:
--   
--   
--   www.example.org.           -- Ordinary DNS name.
--   _25._tcp.mx1.example.net.  -- TLSA RR initial labels have _ prefixes.
--   \001.exotic.example.       -- First label is Ctrl-A!
--   just\.one\.label.example.  -- First label is "just.one.label"
--   
type Domain = ByteString

-- | Resource record class.
type CLASS = Word16

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

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

-- | Types for resource records.
data TYPE

-- | IPv4 address
pattern A :: TYPE

-- | An authoritative name serve
pattern NS :: TYPE

-- | The canonical name for an alias
pattern CNAME :: TYPE

-- | Marks the start of a zone of authority
pattern SOA :: TYPE

-- | A null RR (EXPERIMENTAL)
pattern NULL :: TYPE

-- | A domain name pointer
pattern PTR :: TYPE

-- | Mail exchange
pattern MX :: TYPE

-- | Text strings
pattern TXT :: TYPE

-- | IPv6 Address
pattern AAAA :: TYPE

-- | Server Selection (RFC2782)
pattern SRV :: TYPE

-- | DNAME (RFC6672)
pattern DNAME :: TYPE

-- | OPT (RFC6891)
pattern OPT :: TYPE

-- | Delegation Signer (RFC4034)
pattern DS :: TYPE

-- | RRSIG (RFC4034)
pattern RRSIG :: TYPE

-- | NSEC (RFC4034)
pattern NSEC :: TYPE

-- | DNSKEY (RFC4034)
pattern DNSKEY :: TYPE

-- | NSEC3 (RFC5155)
pattern NSEC3 :: TYPE

-- | NSEC3PARAM (RFC5155)
pattern NSEC3PARAM :: TYPE

-- | TLSA (RFC6698)
pattern TLSA :: TYPE

-- | Child DS (RFC7344)
pattern CDS :: TYPE

-- | DNSKEY(s) the Child wants reflected in DS (RFC7344)
pattern CDNSKEY :: TYPE

-- | Child-To-Parent Synchronization (RFC7477)
pattern CSYNC :: TYPE

-- | Zone transfer (RFC5936)
pattern AXFR :: TYPE

-- | A request for all records the server/cache has available
pattern ANY :: TYPE

-- | Certification Authority Authorization (RFC6844)
pattern CAA :: TYPE

-- | From type to number.
fromTYPE :: TYPE -> Word16

-- | From number to type.
toTYPE :: Word16 -> TYPE

-- | Raw data format for each type.
data RData

-- | IPv4 address
RD_A :: IPv4 -> RData

-- | An authoritative name serve
RD_NS :: Domain -> RData

-- | The canonical name for an alias
RD_CNAME :: Domain -> RData

-- | Marks the start of a zone of authority
RD_SOA :: Domain -> Mailbox -> Word32 -> Word32 -> Word32 -> Word32 -> Word32 -> RData

-- | NULL RR (EXPERIMENTAL, RFC1035).
RD_NULL :: ByteString -> RData

-- | A domain name pointer
RD_PTR :: Domain -> RData

-- | Mail exchange
RD_MX :: Word16 -> Domain -> RData

-- | Text strings
RD_TXT :: ByteString -> RData

-- | Responsible Person (RFC1183)
RD_RP :: Mailbox -> Domain -> RData

-- | IPv6 Address
RD_AAAA :: IPv6 -> RData

-- | Server Selection (RFC2782)
RD_SRV :: Word16 -> Word16 -> Word16 -> Domain -> RData

-- | DNAME (RFC6672)
RD_DNAME :: Domain -> RData

-- | OPT (RFC6891)
RD_OPT :: [OData] -> RData

-- | Delegation Signer (RFC4034)
RD_DS :: Word16 -> Word8 -> Word8 -> ByteString -> RData

-- | DNSSEC signature
RD_RRSIG :: RD_RRSIG -> RData

-- | DNSSEC denial of existence NSEC record
RD_NSEC :: Domain -> [TYPE] -> RData

-- | DNSKEY (RFC4034)
RD_DNSKEY :: Word16 -> Word8 -> Word8 -> ByteString -> RData

-- | DNSSEC hashed denial of existence (RFC5155)
RD_NSEC3 :: Word8 -> Word8 -> Word16 -> ByteString -> ByteString -> [TYPE] -> RData

-- | NSEC3 zone parameters (RFC5155)
RD_NSEC3PARAM :: Word8 -> Word8 -> Word16 -> ByteString -> RData

-- | TLSA (RFC6698)
RD_TLSA :: Word8 -> Word8 -> Word8 -> ByteString -> RData

-- | Child DS (RFC7344)
RD_CDS :: Word16 -> Word8 -> Word8 -> ByteString -> RData

-- | Child DNSKEY (RFC7344)
RD_CDNSKEY :: Word16 -> Word8 -> Word8 -> ByteString -> RData

-- | CAA (RFC 6844) RD_CSYNC
RD_CAA :: Word8 -> CI ByteString -> ByteString -> RData

-- | Unknown resource data
UnknownRData :: ByteString -> RData

-- | RRSIG representation.
--   
--   As noted in Section 3.1.5 of RFC 4034 the RRsig inception and
--   expiration times use serial number arithmetic. As a result these
--   timestamps are not pure values, their meaning is
--   time-dependent! They depend on the present time and are both at most
--   approximately +/-68 years from the present. This ambiguity is not a
--   problem because cached RRSIG records should only persist a few days,
--   signature lifetimes should be *much* shorter than 68 years, and key
--   rotation should result any misconstrued 136-year-old signatures fail
--   to validate. This also means that the interpretation of a time that is
--   exactly half-way around the clock at now +/-0x80000000 is not
--   important, the signature should never be valid.
--   
--   The upshot for us is that we need to convert these *impure* relative
--   values to pure absolute values at the moment they are received from
--   from the network (or read from files, ... in some impure I/O context),
--   and convert them back to 32-bit values when encoding. Therefore, the
--   constructor takes absolute 64-bit representations of the inception and
--   expiration times.
--   
--   The dnsTime function performs the requisite conversion.
data RD_RRSIG
RDREP_RRSIG :: !TYPE -> !Word8 -> !Word8 -> !Word32 -> !Int64 -> !Int64 -> !Word16 -> !Domain -> !ByteString -> RD_RRSIG

-- | RRtype of RRset signed
[rrsigType] :: RD_RRSIG -> !TYPE

-- | DNSKEY algorithm
[rrsigKeyAlg] :: RD_RRSIG -> !Word8

-- | Number of labels signed
[rrsigNumLabels] :: RD_RRSIG -> !Word8

-- | Maximum origin TTL
[rrsigTTL] :: RD_RRSIG -> !Word32

-- | Time last valid
[rrsigExpiration] :: RD_RRSIG -> !Int64

-- | Time first valid
[rrsigInception] :: RD_RRSIG -> !Int64

-- | Signing key tag
[rrsigKeyTag] :: RD_RRSIG -> !Word16

-- | Signing domain
[rrsigZone] :: RD_RRSIG -> !Domain

-- | Opaque signature
[rrsigValue] :: RD_RRSIG -> !ByteString

-- | Given a 32-bit circle-arithmetic DNS time, and the current absolute
--   epoch time, return the epoch time corresponding to the DNS timestamp.
dnsTime :: Word32 -> Int64 -> Int64

-- | DNS message format for queries and replies.
data DNSMessage
DNSMessage :: !DNSHeader -> EDNSheader -> [Question] -> Answers -> AuthorityRecords -> AdditionalRecords -> DNSMessage

-- | Header with extended RCODE
[header] :: DNSMessage -> !DNSHeader

-- | EDNS pseudo-header
[ednsHeader] :: DNSMessage -> EDNSheader

-- | The question for the name server
[question] :: DNSMessage -> [Question]

-- | RRs answering the question
[answer] :: DNSMessage -> Answers

-- | RRs pointing toward an authority
[authority] :: DNSMessage -> AuthorityRecords

-- | RRs holding additional information
[additional] :: DNSMessage -> AdditionalRecords

-- | Construct a complete query DNSMessage, by combining the
--   defaultQuery template with the specified Identifier, and
--   Question. The QueryControls can be mempty to
--   leave all header and EDNS settings at their default values, or some
--   combination of overrides. A default set of overrides can be enabled
--   via the resolvQueryControls field of ResolvConf.
--   Per-query overrides are possible by using loookupRawCtl.
makeQuery :: Identifier -> Question -> QueryControls -> DNSMessage

-- | A query template with QueryControls overrides applied, with
--   just the Question and query Identifier remaining to be
--   filled in.
makeEmptyQuery :: QueryControls -> DNSMessage

-- | A DNSMessage template for queries with default settings for the
--   message DNSHeader and EDNSheader. This is the initial
--   query message state, before customization via QueryControls.
defaultQuery :: DNSMessage

-- | Query controls form a Monoid, as with function composition, the
--   left-most value has the last say. The Monoid is generated by
--   two sets of combinators, one that controls query-related DNS header
--   flags, and another that controls EDNS features.
--   
--   The header flag controls are: rdFlag, adFlag and
--   cdFlag.
--   
--   The EDNS feature controls are: doFlag, ednsEnabled,
--   ednsSetVersion, ednsSetUdpSize and
--   ednsSetOptions. When EDNS is disabled, all the other
--   EDNS-related controls have no effect.
--   
--   Example: Disable DNSSEC checking on the server, and request
--   signatures and NSEC records, perhaps for your own independent
--   validation. The UDP buffer size is set large, for use with a local
--   loopback nameserver on the same host.
--   
--   
--   >>> :{
--   mconcat [ adFlag FlagClear
--           , cdFlag FlagSet
--           , doFlag FlagSet
--           , ednsSetUdpSize (Just 8192) -- IPv4 loopback server?
--           ]
--   :}
--   ad:0,cd:1,edns.udpsize:8192,edns.dobit:1
--   
--   
--   Example: Use EDNS version 1 (yet to be specified), request
--   nameserver ids from the server, and indicate a client subnet of
--   "192.0.2.1/24".
--   
--   
--   >>> :set -XOverloadedStrings
--   
--   >>> let emptyNSID = ""
--   
--   >>> let mask = 24
--   
--   >>> let ipaddr = read "192.0.2.1"
--   
--   >>> :{
--   mconcat [ ednsSetVersion (Just 1)
--           , ednsSetOptions (ODataAdd [OD_NSID emptyNSID])
--           , ednsSetOptions (ODataAdd [OD_ClientSubnet mask 0 ipaddr])
--           ]
--   :}
--   edns.version:1,edns.options:[NSID,ClientSubnet]
--   
data QueryControls

-- | Generator of QueryControls that adjusts the RD bit.
--   
--   
--   >>> rdFlag FlagClear
--   rd:0
--   
rdFlag :: FlagOp -> QueryControls

-- | Generator of QueryControls that adjusts the AD bit.
--   
--   
--   >>> adFlag FlagSet
--   ad:1
--   
adFlag :: FlagOp -> QueryControls

-- | Generator of QueryControls that adjusts the CD bit.
--   
--   
--   >>> cdFlag FlagSet
--   cd:1
--   
cdFlag :: FlagOp -> QueryControls

-- | Generator of QueryControls that adjusts the EDNS
--   DnssecOk (DO) bit.
--   
--   
--   >>> doFlag FlagSet
--   edns.dobit:1
--   
doFlag :: FlagOp -> QueryControls

-- | Generator of QueryControls that enables or disables EDNS
--   support. When EDNS is disabled, the rest of the EDNS controls
--   are ignored.
--   
--   
--   >>> ednsHeader $ makeEmptyQuery $ ednsEnabled FlagClear <> doFlag FlagSet
--   NoEDNS
--   
ednsEnabled :: FlagOp -> QueryControls

-- | Generator of QueryControls that adjusts the EDNS
--   version. A value of Nothing makes no changes, while Just
--   v sets the EDNS version to v.
--   
--   
--   >>> ednsSetVersion (Just 1)
--   edns.version:1
--   
ednsSetVersion :: Maybe Word8 -> QueryControls

-- | Generator of QueryControls that adjusts the EDNS UDP
--   buffer size. A value of Nothing makes no changes, while
--   Just n sets the EDNS UDP buffer size to n.
--   
--   
--   >>> ednsSetUdpSize (Just 2048)
--   edns.udpsize:2048
--   
ednsSetUdpSize :: Maybe Word16 -> QueryControls

-- | Generator of QueryControls that adjusts the list of EDNS
--   options.
--   
--   
--   >>> :set -XOverloadedStrings
--   
--   >>> ednsSetOptions (ODataAdd [OD_NSID ""])
--   edns.options:[NSID]
--   
ednsSetOptions :: ODataOp -> QueryControls

-- | Boolean flag operations. These form a Monoid. When combined via
--   mappend, as with function composition, the left-most value has
--   the last say.
--   
--   
--   >>> mempty :: FlagOp
--   FlagKeep
--   
--   >>> FlagSet <> mempty
--   FlagSet
--   
--   >>> FlagClear <> FlagSet <> mempty
--   FlagClear
--   
--   >>> FlagReset <> FlagClear <> FlagSet <> mempty
--   FlagReset
--   
data FlagOp

-- | Set the flag to 1
FlagSet :: FlagOp

-- | Clear the flag to 0
FlagClear :: FlagOp

-- | Reset the flag to its default value
FlagReset :: FlagOp

-- | Leave the flag unchanged
FlagKeep :: FlagOp

-- | The default EDNS Option list is empty. We define two operations, one
--   to prepend a list of options, and another to set a specific list of
--   options.
data ODataOp

-- | Add the specified options to the list.
ODataAdd :: [OData] -> ODataOp

-- | Set the option list as specified.
ODataSet :: [OData] -> ODataOp

-- | Default response. When responding to EDNS queries, the response must
--   either be an EDNS response, or else FormatErr must be returned. The
--   default response message has EDNS disabled (ednsHeader set to
--   NoEDNS), it should be updated as appropriate.
--   
--   Do not explicitly add OPT RRs to the additional section, instead let
--   the encoder compute and add the OPT record based on the EDNS
--   pseudo-header.
--   
--   The RCODE in the DNSHeader should be set to the
--   appropriate 12-bit extended value, which will be split between the
--   primary header and EDNS OPT record during message encoding (low 4 bits
--   in DNS header, high 8 bits in EDNS OPT record). See EDNSheader
--   for more details.
defaultResponse :: DNSMessage

-- | Construct a query response DNSMessage.
makeResponse :: Identifier -> Question -> Answers -> DNSMessage

-- | Raw data format for the header of DNS Query and Response.
data DNSHeader
DNSHeader :: !Identifier -> !DNSFlags -> DNSHeader

-- | Query or reply identifier.
[identifier] :: DNSHeader -> !Identifier

-- | Flags, OPCODE, and RCODE
[flags] :: DNSHeader -> !DNSFlags

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

-- | Raw data format for the flags of DNS Query and Response.
data DNSFlags
DNSFlags :: !QorR -> !OPCODE -> !Bool -> !Bool -> !Bool -> !Bool -> !RCODE -> !Bool -> !Bool -> DNSFlags

-- | Query or response.
[qOrR] :: DNSFlags -> !QorR

-- | Kind of query.
[opcode] :: DNSFlags -> !OPCODE

-- | AA (Authoritative Answer) bit - this bit is valid in responses, and
--   specifies that the responding name server is an authority for the
--   domain name in question section.
[authAnswer] :: DNSFlags -> !Bool

-- | TC (Truncated Response) bit - specifies that this message was
--   truncated due to length greater than that permitted on the
--   transmission channel.
[trunCation] :: DNSFlags -> !Bool

-- | RD (Recursion Desired) bit - 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.
[recDesired] :: DNSFlags -> !Bool

-- | RA (Recursion Available) bit - this be is set or cleared in a
--   response, and denotes whether recursive query support is available in
--   the name server.
[recAvailable] :: DNSFlags -> !Bool

-- | The full 12-bit extended RCODE when EDNS is in use. Should always be
--   zero in well-formed requests. When decoding replies, the high eight
--   bits from any EDNS response are combined with the 4-bit RCODE from the
--   DNS header. When encoding replies, if no EDNS OPT record is provided,
--   RCODE values > 15 are mapped to FormatErr.
[rcode] :: DNSFlags -> !RCODE

-- | AD (Authenticated Data) bit - (RFC4035, Section 3.2.3).
[authenData] :: DNSFlags -> !Bool

-- | CD (Checking Disabled) bit - (RFC4035, Section 3.2.2).
[chkDisable] :: DNSFlags -> !Bool

-- | Query or response.
data QorR

-- | Query.
QR_Query :: QorR

-- | Response.
QR_Response :: QorR

-- | Default DNSFlags record suitable for making recursive queries.
--   By default the RD bit is set, and the AD and CD bits are cleared.
defaultDNSFlags :: DNSFlags

-- | Kind of query.
data OPCODE

-- | A standard query.
OP_STD :: OPCODE

-- | An inverse query (inverse queries are deprecated).
OP_INV :: OPCODE

-- | A server status request.
OP_SSR :: OPCODE

-- | A zone change notification (RFC1996)
OP_NOTIFY :: OPCODE

-- | An update request (RFC2136)
OP_UPDATE :: OPCODE

-- | Convert the internal representation of a DNS OPCODE to its 16-bit
--   numeric value.
fromOPCODE :: OPCODE -> Word16

-- | Convert a 16-bit DNS OPCODE number to its internal representation
toOPCODE :: Word16 -> Maybe OPCODE

-- | EDNS extended 12-bit response code. Non-EDNS messages use only the low
--   4 bits. With EDNS this stores the combined error code from the DNS
--   header and and the EDNS psuedo-header. See EDNSheader for more
--   detail.
data RCODE

-- | No error condition.
pattern NoErr :: RCODE

-- | Format error - The name server was unable to interpret the query.
pattern FormatErr :: RCODE

-- | Server failure - The name server was unable to process this query due
--   to a problem with the name server.
pattern ServFail :: RCODE

-- | 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

-- | Not Implemented - The name server does not support the requested kind
--   of query.
pattern NotImpl :: RCODE

-- | 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

-- | YXDomain - Dynamic update response, a pre-requisite domain that should
--   not exist, does exist.
pattern YXDomain :: RCODE

-- | YXRRSet - Dynamic update response, a pre-requisite RRSet that should
--   not exist, does exist.
pattern YXRRSet :: RCODE

-- | NXRRSet - Dynamic update response, a pre-requisite RRSet that should
--   exist, does not exist.
pattern NXRRSet :: RCODE

-- | NotAuth - Dynamic update response, the server is not authoritative for
--   the zone named in the Zone Section.
pattern NotAuth :: RCODE

-- | 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

-- | Bad OPT Version (BADVERS, RFC 6891).
pattern BadVers :: RCODE

-- | Key not recognized [RFC2845]
pattern BadKey :: RCODE

-- | Signature out of time window [RFC2845]
pattern BadTime :: RCODE

-- | Bad TKEY Mode [RFC2930]
pattern BadMode :: RCODE

-- | Duplicate key name [RFC2930]
pattern BadName :: RCODE

-- | Algorithm not supported [RFC2930]
pattern BadAlg :: RCODE

-- | Bad Truncation [RFC4635]
pattern BadTrunc :: RCODE

-- | Bad/missing Server Cookie [RFC7873]
pattern BadCookie :: RCODE

-- | Malformed (peer) EDNS message, no RCODE available. This is not an
--   RCODE that can be sent by a peer. It lies outside the 12-bit range
--   expressible via EDNS. The low 12-bits are chosen to coincide with
--   FormatErr. When an EDNS message is malformed, and we're unable
--   to extract the extended RCODE, the header rcode is set to
--   BadRCODE.
pattern BadRCODE :: RCODE

-- | Convert an RCODE to its numeric value.
fromRCODE :: RCODE -> Word16

-- | Convert a numeric value to a corresponding RCODE. The behaviour
--   is undefined for values outside the range [0 .. 0xFFF] since
--   the EDNS extended RCODE is a 12-bit value. Values in the range
--   [0xF01 .. 0xFFF] are reserved for private use.
toRCODE :: Word16 -> RCODE

-- | Data type representing the optional EDNS pseudo-header of a
--   DNSMessage When a single well-formed OPT
--   ResourceRecord was present in the message's additional section,
--   it is decoded to an EDNS record and and stored in the message
--   ednsHeader field. The corresponding OPT RR is then
--   removed from the additional section.
--   
--   When the constructor is NoEDNS, no EDNS OPT record was
--   present in the message additional section. When InvalidEDNS,
--   the message holds either a malformed OPT record or more than one OPT
--   record, which can still be found in (have not been removed from) the
--   message additional section.
--   
--   The EDNS OPT record augments the message error status with an 8-bit
--   field that forms 12-bit extended RCODE when combined with the 4-bit
--   RCODE from the unextended DNS header. In EDNS messages it is essential
--   to not use just the bare 4-bit RCODE from the original DNS
--   header. Therefore, in order to avoid potential misinterpretation of
--   the response RCODE, when the OPT record is decoded, the upper
--   eight bits of the error status are automatically combined with the
--   rcode of the message header, so that there is only one place in
--   which to find the full 12-bit result. Therefore, the decoded
--   EDNS pseudo-header, does not hold any error status bits.
--   
--   The reverse process occurs when encoding messages. The low four bits
--   of the message header rcode are encoded into the wire-form DNS
--   header, while the upper eight bits are encoded as part of the OPT
--   record. In DNS responses with an rcode larger than 15, EDNS
--   extensions SHOULD be enabled by providing a value for
--   ednsHeader with a constructor of EDNSheader. If EDNS is
--   not enabled in such a message, in order to avoid truncation of
--   RCODE values that don't fit in the non-extended DNS header, the
--   encoded wire-form RCODE is set to FormatErr.
--   
--   When encoding messages for transmission, the ednsHeader is used
--   to generate the additional OPT record. Do not add explicit
--   OPT records to the aditional section, configure EDNS via the
--   EDNSheader instead.
--   
--   
--   >>> let getopts eh = mapEDNS eh ednsOptions []
--   
--   >>> let optsin     = [OD_ClientSubnet 24 0 $ read "192.0.2.1"]
--   
--   >>> let masked     = [OD_ClientSubnet 24 0 $ read "192.0.2.0"]
--   
--   >>> let message    = makeEmptyQuery $ ednsSetOptions $ ODataSet optsin
--   
--   >>> let optsout    = getopts. ednsHeader <$> (decode $ encode message)
--   
--   >>> optsout       == Right masked
--   True
--   
data EDNSheader

-- | A valid EDNS message
EDNSheader :: EDNS -> EDNSheader

-- | A valid non-EDNS message
NoEDNS :: EDNSheader

-- | Multiple or bad additional OPT RRs
InvalidEDNS :: EDNSheader

-- | Return the second argument for EDNS messages, otherwise the third.
ifEDNS :: EDNSheader -> a -> a -> a

-- | Return the output of a function applied to the EDNS pseudo-header if
--   EDNS is enabled, otherwise return a default value.
mapEDNS :: EDNSheader -> (EDNS -> a) -> a -> a

-- | EDNS information defined in RFC 6891.
data EDNS
EDNS :: !Word8 -> !Word16 -> !Bool -> ![OData] -> EDNS

-- | EDNS version, presently only version 0 is defined.
[ednsVersion] :: EDNS -> !Word8

-- | Supported UDP payload size.
[ednsUdpSize] :: EDNS -> !Word16

-- | Request DNSSEC replies (with RRSIG and NSEC records as as appropriate)
--   from the server. Generally, not needed (except for diagnostic
--   purposes) unless the signatures will be validated. Just setting the
--   AD bit in the query and checking it in the response is
--   sufficient (but often subject to man-in-the-middle forgery) if all
--   that's wanted is whether the server validated the response.
[ednsDnssecOk] :: EDNS -> !Bool

-- | EDNS options (e.g. OD_NSID, OD_ClientSubnet, ...)
[ednsOptions] :: EDNS -> ![OData]

-- | The default EDNS pseudo-header for queries. The UDP buffer size is set
--   to 1216 bytes, which should result in replies that fit into the 1280
--   byte IPv6 minimum MTU. Since IPv6 only supports fragmentation at the
--   source, and even then not all gateways forward IPv6 pre-fragmented
--   IPv6 packets, it is best to keep DNS packet sizes below this limit
--   when using IPv6 nameservers. A larger value may be practical when
--   using IPv4 exclusively.
--   
--   
--   defaultEDNS = EDNS
--       { ednsVersion = 0      -- The default EDNS version is 0
--       , ednsUdpSize = 1232   -- IPv6-safe UDP MTU (RIPE recommendation)
--       , ednsDnssecOk = False -- We don't do DNSSEC validation
--       , ednsOptions = []     -- No EDNS options by default
--       }
--   
defaultEDNS :: EDNS

-- | Maximum UDP size that can be advertised. If the ednsUdpSize of
--   EDNS is larger, then this value is sent instead. This value is
--   likely to work only for local nameservers on the loopback network.
--   Servers may enforce a smaller limit.
--   
--   
--   >>> maxUdpSize
--   16384
--   
maxUdpSize :: Word16

-- | Minimum UDP size to advertise. If ednsUdpSize of EDNS is
--   smaller, then this value is sent instead.
--   
--   
--   >>> minUdpSize
--   512
--   
minUdpSize :: Word16

-- | RData formats for a few EDNS options, and an opaque catchall
data OData

-- | Name Server Identifier (RFC5001). Bidirectional, empty from client.
--   (opaque octet-string). May contain binary data, which MUST be empty in
--   queries.
OD_NSID :: ByteString -> OData

-- | DNSSEC Algorithm Understood (RFC6975). Client to server. (array of
--   8-bit numbers). Lists supported DNSKEY algorithms.
OD_DAU :: [Word8] -> OData

-- | DS Hash Understood (RFC6975). Client to server. (array of 8-bit
--   numbers). Lists supported DS hash algorithms.
OD_DHU :: [Word8] -> OData

-- | NSEC3 Hash Understood (RFC6975). Client to server. (array of 8-bit
--   numbers). Lists supported NSEC3 hash algorithms.
OD_N3U :: [Word8] -> OData

-- | Client subnet (RFC7871). Bidirectional. (source bits, scope bits,
--   address). The address is masked and truncated when encoding queries.
--   The address is zero-padded when decoding. Invalid input encodings
--   result in an OD_ECSgeneric value instead.
OD_ClientSubnet :: Word8 -> Word8 -> IP -> OData

-- | Unsupported or malformed IP client subnet option. Bidirectional.
--   (address family, source bits, scope bits, opaque address).
OD_ECSgeneric :: Word16 -> Word8 -> Word8 -> ByteString -> OData

-- | Generic EDNS option. (numeric OptCode, opaque content)
UnknownOData :: Word16 -> ByteString -> OData

-- | EDNS Option Code (RFC 6891).
data OptCode

-- | Client subnet (RFC7871)
pattern ClientSubnet :: OptCode

-- | DNSSEC algorithm support (RFC6974, section 3)
pattern DAU :: OptCode
pattern DHU :: OptCode
pattern N3U :: OptCode

-- | NSID (RFC5001, section 2.3)
pattern NSID :: OptCode

-- | From option code to number.
fromOptCode :: OptCode -> Word16

-- | From number to option code.
toOptCode :: Word16 -> OptCode

-- | Raw data format for DNS questions.
data Question
Question :: Domain -> TYPE -> Question

-- | A domain name
[qname] :: Question -> Domain

-- | The type of the query
[qtype] :: Question -> TYPE

-- | 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 :: DNSError

-- | The question section of the response doesn't match our query. This
--   could indicate foul play.
QuestionMismatch :: DNSError

-- | A zone tranfer, i.e., a request of type AXFR, was attempted with the
--   "lookup" interface. Zone transfer is different enough from "normal"
--   requests that it requires a different interface.
InvalidAXFRLookup :: DNSError

-- | The number of retries for the request was exceeded.
RetryLimitExceeded :: DNSError

-- | TCP fallback request timed out.
TimeoutExpired :: DNSError

-- | The answer has the correct sequence number, but returned an unexpected
--   RDATA format.
UnexpectedRDATA :: DNSError

-- | The domain for query is illegal.
IllegalDomain :: DNSError

-- | The name server was unable to interpret the query.
FormatError :: DNSError

-- | The name server was unable to process this query due to a problem with
--   the name server.
ServerFailure :: DNSError

-- | This code signifies that the domain name referenced in the query does
--   not exist.
NameError :: DNSError

-- | The name server does not support the requested kind of query.
NotImplemented :: DNSError

-- | 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 :: DNSError

-- | The server does not support the OPT RR version or content
BadOptRecord :: DNSError

-- | Configuration is wrong.
BadConfiguration :: DNSError

-- | Network failure.
NetworkFailure :: IOException -> DNSError

-- | Error is unknown
DecodeError :: String -> DNSError
UnknownDNSError :: DNSError

-- | Type for a mailbox encoded on the wire as a DNS name, but the first
--   label is conceptually the local part of an email address, and may
--   contain internal periods that are not label separators. Therefore, in
--   mailboxes @ is used as the separator between the first and second
--   labels, and any '.' characters in the first label are not escaped. The
--   encoding is otherwise the same as Domain above. This is most
--   commonly seen in the rname of SOA records, and is also
--   employed in the mbox-dname field of RP records. On
--   input, if there is no unescaped @ character in the Mailbox, it
--   is reparsed with '.' as the first label separator. Thus the
--   traditional format with all labels separated by dots is also accepted,
--   but decoding from wire form always uses @ between the first label and
--   the domain-part of the address. Examples:
--   
--   
--   hostmaster@example.org.  -- First label is simply hostmaster
--   john.smith@examle.com.   -- First label is john.smith
--   
type Mailbox = ByteString

-- | DNS message encoder.
--   
--   Note: DNS is a client library, and its focus is on
--   sending queries, and receiving replies.
--   Thefore, while this module is reasonably adept at query generation,
--   building a DNS server with this module requires additional work to
--   handle message size limits, correct UDP truncation, proper EDNS
--   negotiation, and so on. Support for server-side DNS is at best
--   rudimentary.
--   
--   For sending queries, in most cases you should be using one of the
--   functions from Lookup and LookupRaw, or lastly, if you
--   want to handle the network reads and writes for yourself (with your
--   own code for UDP retries, TCP fallback, EDNS fallback, ...), then
--   perhaps encodeQuestion (letting DNS do the lookups for
--   you in an async thread is likely much simpler).
module Network.DNS.Encode

-- | Encode a DNSMessage for transmission over UDP. For transmission
--   over TCP encapsulate the result via encodeVC, or use
--   sendVC, which handles this internally. If any
--   ResourceRecord in the message contains incorrectly encoded
--   Domain name ByteStrings, this function may raise a
--   DecodeError.
encode :: DNSMessage -> ByteString

-- | 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

-- | 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 -> ByteString -> Either DNSError DNSMessage

-- | 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 -> Either DNSError DNSMessage

-- | 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 -> ByteString -> Either DNSError ([DNSMessage], ByteString)

-- | 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 -> Either DNSError ([DNSMessage], ByteString)

module Network.DNS.IO

-- | Receive and decode a single DNSMessage from a UDP
--   Socket, throwing away the client address. Messages longer than
--   maxUdpSize are silently truncated, but this should not occur in
--   practice, since we cap the advertised EDNS UDP buffer size limit at
--   the same value. A DNSError is raised if I/O or message decoding
--   fails.
receive :: Socket -> IO DNSMessage

-- | Receive and decode a single DNSMessage from a UDP
--   Socket. Messages longer than maxUdpSize are silently
--   truncated, but this should not occur in practice, since we cap the
--   advertised EDNS UDP buffer size limit at the same value. A
--   DNSError is raised if I/O or message decoding fails.
receiveFrom :: Socket -> IO (DNSMessage, SockAddr)

-- | Receive and decode a single DNSMesage from a virtual-circuit
--   (TCP). It is up to the caller to implement any desired timeout. An
--   DNSError is raised if I/O or message decoding fails.
receiveVC :: Socket -> IO DNSMessage

-- | Send an encoded DNSMessage datagram over UDP. The message
--   length is implicit in the size of the UDP datagram. With TCP you must
--   use sendVC, because TCP does not have message boundaries, and
--   each message needs to be prepended with an explicit length. The socket
--   must be explicitly connected to the destination nameserver.
send :: Socket -> ByteString -> IO ()

-- | Send an encoded DNSMessage datagram over UDP to a given
--   address. The message length is implicit in the size of the UDP
--   datagram. With TCP you must use sendVC, because TCP does not
--   have message boundaries, and each message needs to be prepended with
--   an explicit length.
sendTo :: Socket -> ByteString -> SockAddr -> IO ()

-- | Send a single encoded DNSMessage over TCP. An explicit length
--   is prepended to the encoded buffer before transmission. If you want to
--   send a batch of multiple encoded messages back-to-back over a single
--   TCP connection, and then loop to collect the results, use
--   encodeVC to prefix each message with a length, and then use
--   sendAll to send a concatenated batch of the resulting
--   encapsulated messages.
sendVC :: Socket -> ByteString -> IO ()

-- | Send one or more encoded DNSMessage buffers over TCP, each
--   allready encapsulated with an explicit length prefix (perhaps via
--   encodeVC) and then concatenated into a single buffer. DO NOT
--   use sendAll with UDP.
sendAll :: Socket -> ByteString -> IO ()

-- | The encoded DNSMessage has the specified request ID. The
--   default values of the RD, AD, CD and DO flag bits, as well as various
--   EDNS features, can be adjusted via the QueryControls parameter.
--   
--   The caller is responsible for generating the ID via a securely seeded
--   CSPRNG.
encodeQuestion :: Identifier -> Question -> QueryControls -> ByteString

-- | Encapsulate an encoded DNSMessage buffer for transmission over
--   a TCP virtual circuit. With TCP the buffer needs to start with an
--   explicit length (the length is implicit with UDP).
encodeVC :: ByteString -> ByteString

-- | Compose a response with a single IPv4 RRset. If the query had an EDNS
--   pseudo-header, a suitable EDNS pseudo-header must be added to the
--   response message, or else a FormatErr response must be sent.
--   The response TTL defaults to 300 seconds, and should be updated (to
--   the same value across all the RRs) if some other TTL value is more
--   appropriate.
responseA :: Identifier -> Question -> [IPv4] -> DNSMessage

-- | Compose a response with a single IPv6 RRset. If the query had an EDNS
--   pseudo-header, a suitable EDNS pseudo-header must be added to the
--   response message, or else a FormatErr response must be sent.
--   The response TTL defaults to 300 seconds, and should be updated (to
--   the same value across all the RRs) if some other TTL value is more
--   appropriate.
responseAAAA :: Identifier -> Question -> [IPv6] -> DNSMessage

-- | Resolver related data types.
module Network.DNS.Resolver

-- | Type for resolver configuration. Use defaultResolvConf to
--   create a new value.
--   
--   An example to use Google's public DNS cache instead of resolv.conf:
--   
--   
--   >>> let conf = defaultResolvConf { resolvInfo = RCHostName "8.8.8.8" }
--   
--   
--   An example to use multiple Google's public DNS cache concurrently:
--   
--   
--   >>> let conf = defaultResolvConf { resolvInfo = RCHostNames ["8.8.8.8","8.8.4.4"], resolvConcurrent = True }
--   
--   
--   An example to disable EDNS:
--   
--   
--   >>> let conf = defaultResolvConf { resolvQueryControls = ednsEnabled FlagClear }
--   
--   
--   An example to enable query result caching:
--   
--   
--   >>> let conf = defaultResolvConf { resolvCache = Just defaultCacheConf }
--   
--   
--   An example to disable requesting recursive service.
--   
--   
--   >>> let conf = defaultResolvConf { resolvQueryControls = rdFlag FlagClear }
--   
--   
--   An example to set the AD bit in all queries by default.
--   
--   
--   >>> let conf = defaultResolvConf { resolvQueryControls = adFlag FlagSet }
--   
--   
--   An example to set the both the AD and CD bits in all queries by
--   default.
--   
--   
--   >>> let conf = defaultResolvConf { resolvQueryControls = adFlag FlagSet <> cdFlag FlagSet }
--   
--   
--   An example with an EDNS buffer size of 1216 bytes, which is more
--   robust with IPv6, and the DO bit set to request DNSSEC responses.
--   
--   
--   >>> let conf = defaultResolvConf { resolvQueryControls = ednsSetUdpSize (Just 1216) <> doFlag FlagSet }
--   
data ResolvConf

-- | Return a default ResolvConf:
--   
--   
--   
- resolvInfo is RCFilePath "/etc/resolv.conf".
--   
- resolvTimeout is 3,000,000 micro seconds.
--   
- resolvRetry is 3.
--   
- resolvConcurrent is False.
--   
- resolvCache is Nothing.
--   
- resolvQueryControls is an empty set of overrides.
--   
defaultResolvConf :: ResolvConf

-- | Server information.
resolvInfo :: ResolvConf -> FileOrNumericHost

-- | Timeout in micro seconds.
resolvTimeout :: ResolvConf -> Int

-- | The number of retries including the first try.
resolvRetry :: ResolvConf -> Int

-- | Concurrent queries if multiple DNS servers are specified.
resolvConcurrent :: ResolvConf -> Bool

-- | Cache configuration.
resolvCache :: ResolvConf -> Maybe CacheConf

-- | Overrides for the default flags used for queries via resolvers that
--   use this configuration.
resolvQueryControls :: ResolvConf -> QueryControls

-- | The type to specify a cache server.
data FileOrNumericHost

-- | A path for "resolv.conf" where one or more IP addresses of DNS servers
--   should be found on Unix. Default DNS servers are automatically
--   detected on Windows regardless of the value of the file name.
RCFilePath :: FilePath -> FileOrNumericHost

-- | A numeric IP address. Warning: host names are invalid.
RCHostName :: HostName -> FileOrNumericHost

-- | Numeric IP addresses. Warning: host names are invalid.
RCHostNames :: [HostName] -> FileOrNumericHost

-- | A numeric IP address and port number. Warning: host names are
--   invalid.
RCHostPort :: HostName -> PortNumber -> FileOrNumericHost

-- | Cache configuration for responses.
data CacheConf

-- | Default cache configuration.
--   
--   
--   >>> defaultCacheConf
--   CacheConf {maximumTTL = 300, pruningDelay = 10}
--   
defaultCacheConf :: CacheConf

-- | If RR's TTL is higher than this value, this value is used instead.
maximumTTL :: CacheConf -> TTL

-- | Cache pruning interval in seconds.
pruningDelay :: CacheConf -> Int

-- | Intermediate abstract data type for resolvers. IP address information
--   of DNS servers is generated according to resolvInfo internally.
--   This value can be safely reused for withResolver.
--   
--   The naming is confusing for historical reasons.
data ResolvSeed

-- | Make a ResolvSeed from a ResolvConf.
--   
--   Examples:
--   
--   
--   >>> rs <- makeResolvSeed defaultResolvConf
--   
makeResolvSeed :: ResolvConf -> IO ResolvSeed

-- | Abstract data type of DNS Resolver. This includes newly seeded
--   identifier generators for all specified DNS servers and a cache
--   database.
data Resolver

-- | Giving a thread-safe Resolver to the function of the second
--   argument.
withResolver :: ResolvSeed -> (Resolver -> IO a) -> IO a

-- | Giving thread-safe Resolvers to the function of the second
--   argument. For each Resolver, multiple lookups must be done
--   sequentially. Resolvers can be used concurrently.

-- | Deprecated: Use withResolver with resolvConcurrent set to True
withResolvers :: [ResolvSeed] -> ([Resolver] -> IO a) -> IO a

module Network.DNS.LookupRaw

-- | Look up resource records of a specified type for a domain, collecting
--   the results from the ANSWER section of the response. See the
--   documentation of lookupRaw to understand the concrete behavior.
--   Cache is used if resolvCache is Just.
--   
--   Example:
--   
--   
--   >>> rs <- makeResolvSeed defaultResolvConf
--   
--   >>> withResolver rs $ \resolver -> lookup resolver "www.example.com" A
--   Right [93.184.216.34]
--   
lookup :: Resolver -> Domain -> TYPE -> IO (Either DNSError [RData])

-- | Look up resource records of a specified type for a domain, collecting
--   the results from the AUTHORITY section of the response. See the
--   documentation of lookupRaw to understand the concrete behavior.
--   Cache is used even if resolvCache is Just.
lookupAuth :: Resolver -> Domain -> TYPE -> IO (Either DNSError [RData])

-- | Look up a name and return the entire DNS Response.
--   
--   For a given DNS server, the queries are done:
--   
--   
--   
- A new UDP socket bound to a new local port is created and a new
--   identifier is created atomically from the cryptographically secure
--   pseudo random number generator for the target DNS server. Then UDP
--   queries are tried with the limitation of resolvRetry (use EDNS
--   if specifiecd). If it appears that the target DNS server does not
--   support EDNS, it falls back to traditional queries.
--   
- If the response is truncated, a new TCP socket bound to a new
--   local port is created. Then exactly one TCP query is retried.
--   
--   
--   If multiple DNS servers are specified ResolvConf ('RCHostNames
--   ') or found (RCFilePath), either sequential lookup or
--   concurrent lookup is carried out:
--   
--   
--   
- In sequential lookup (resolvConcurrent is False), the query
--   procedure above is processed in the order of the DNS servers
--   sequentially until a successful response is received.
--   
- In concurrent lookup (resolvConcurrent is True), the query
--   procedure above is processed for each DNS server concurrently. The
--   first received response is accepted even if it is an error.
--   
--   
--   Cache is not used even if resolvCache is Just.
--   
--   The example code:
--   
--   
--   rs <- makeResolvSeed defaultResolvConf
--   withResolver rs $ \resolver -> lookupRaw resolver "www.example.com" A
--   
--   
--   
--   And the (formatted) expected output:
--   
--   
--   Right (DNSMessage
--           { header = DNSHeader
--                        { identifier = 1,
--                          flags = DNSFlags
--                                    { qOrR = QR_Response,
--                                      opcode = OP_STD,
--                                      authAnswer = False,
--                                      trunCation = False,
--                                      recDesired = True,
--                                      recAvailable = True,
--                                      rcode = NoErr,
--                                      authenData = False
--                                    },
--                        },
--             question = [Question { qname = "www.example.com.",
--                                    qtype = A}],
--             answer = [ResourceRecord {rrname = "www.example.com.",
--                                       rrtype = A,
--                                       rrttl = 800,
--                                       rdlen = 4,
--                                       rdata = 93.184.216.119}],
--             authority = [],
--             additional = []})
--   
--   
--   
--   AXFR requests cannot be performed with this interface.
--   
--   
--   >>> rs <- makeResolvSeed defaultResolvConf
--   
--   >>> withResolver rs $ \resolver -> lookupRaw resolver "mew.org" AXFR
--   Left InvalidAXFRLookup
--   
lookupRaw :: Resolver -> Domain -> TYPE -> IO (Either DNSError DNSMessage)

-- | Similar to lookupRaw, but the default values of the RD, AD, CD
--   and DO flag bits, as well as various EDNS features, can be adjusted
--   via the QueryControls parameter.
lookupRawCtl :: Resolver -> Domain -> TYPE -> QueryControls -> IO (Either DNSError DNSMessage)

-- | Similar to lookupRawCtl, but the recv action can be replaced
--   with something other than receive. For example, in an
--   environment where frequent retrieval of the current time is a
--   performance issue, you can pass the time from outside instead of
--   having receive retrieve the current time.
lookupRawCtlRecv :: Resolver -> Domain -> TYPE -> QueryControls -> (Socket -> IO DNSMessage) -> IO (Either DNSError DNSMessage)

-- | Messages with a non-error RCODE are passed to the supplied function
--   for processing. Other messages are translated to DNSError
--   instances.
--   
--   Note that NameError is not a lookup error. The lookup is
--   successful, bearing the sad news that the requested domain does not
--   exist. NameError responses may return a meaningful AD bit, may
--   contain useful data in the authority section, and even initial CNAME
--   records that lead to the ultimately non-existent domain. Applications
--   that wish to process the content of NameError (NXDomain)
--   messages will need to implement their own RCODE handling.
fromDNSMessage :: DNSMessage -> (DNSMessage -> a) -> Either DNSError a

-- | Simple, high-level DNS lookup functions for clients.
--   
--   All of the lookup functions necessary run in IO since they interact
--   with the network. The return types are similar, but differ in what can
--   be returned from a successful lookup.
--   
--   We can think of the return type as either "what I asked for" or "an
--   error". For example, the lookupA function, if successful, will
--   return a list of IPv4. The lookupMX function will
--   instead return a list of (Domain,Int) pairs,
--   where each pair represents a hostname and its associated priority.
--   
--   The order of multiple results may not be consistent between lookups.
--   If you require consistent results, apply sort to the returned
--   list.
--   
--   The errors that can occur are the same for all lookups. Namely:
--   
--   
--   
- Timeout
--   
- Wrong sequence number (foul play?)
--   
- Unexpected data in the response
--   
--   
--   If an error occurs, you should be able to pattern match on the
--   DNSError constructor to determine which of these is the case.
--   
--   Note: A result of "no records" is not considered an error. If
--   you perform, say, an 'AAAA' lookup for a domain with no such records,
--   the "success" result would be Right [].
--   
--   We perform a successful lookup of "www.example.com":
--   
--   
--   >>> let hostname = Data.ByteString.Char8.pack "www.example.com"
--   
--   >>> 
--   
--   >>> rs <- makeResolvSeed defaultResolvConf
--   
--   >>> withResolver rs $ \resolver -> lookupA resolver hostname
--   Right [93.184.216.34]
--   
--   
--   The only error that we can easily cause is a timeout. We do this by
--   creating and utilizing a ResolvConf which has a timeout of one
--   millisecond and a very limited number of retries:
--   
--   
--   >>> let hostname2 = Data.ByteString.Char8.pack "www.example.com"
--   
--   >>> let badrc = defaultResolvConf { resolvTimeout = 0, resolvRetry = 1 }
--   
--   >>> 
--   
--   >>> rs2 <- makeResolvSeed badrc
--   
--   >>> withResolver rs2 $ \resolver -> lookupA resolver hostname2
--   Left RetryLimitExceeded
--   
--   
--   As is the convention, successful results will always be wrapped in a
--   Right while errors will be wrapped in a Left.
--   
--   For convenience, you may wish to enable GHC's OverloadedStrings
--   extension. This will allow you to avoid calling pack on each
--   domain name. See
--   https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/glasgow_exts.html#overloaded-string-literals
--   for more information. In the following examples, we assuem this
--   extension is enabled.
--   
--   All lookup functions eventually call lookupRaw. See its
--   documentation to understand the concrete lookup behavior.
module Network.DNS.Lookup

-- | Look up all 'A' records for the given hostname.
--   
--   A straightforward example:
--   
--   
--   >>> rs <- makeResolvSeed defaultResolvConf
--   
--   >>> withResolver rs $ \resolver -> lookupA resolver "192.0.2.1.nip.io"
--   Right [192.0.2.1]
--   
--   
--   This function will also follow a CNAME and resolve its target if one
--   exists for the queried hostname:
--   
--   
--   >>> rs2 <- makeResolvSeed defaultResolvConf
--   
--   >>> withResolver rs2 $ \resolver -> lookupA resolver "www.kame.net"
--   Right [210.155.141.200]
--   
lookupA :: Resolver -> Domain -> IO (Either DNSError [IPv4])

-- | Look up all (IPv6) 'AAAA' records for the given hostname.
--   
--   Examples:
--   
--   
--   >>> rs <- makeResolvSeed defaultResolvConf
--   
--   >>> withResolver rs $ \resolver -> lookupAAAA resolver "www.wide.ad.jp"
--   Right [2001:200:0:180c:20c:29ff:fec9:9d61]
--   
lookupAAAA :: Resolver -> Domain -> IO (Either DNSError [IPv6])

-- | Look up all 'MX' records for the given hostname. Two parts constitute
--   an MX record: a hostname , and an integer priority. We therefore
--   return each record as a (Domain, Int).
--   
--   In this first example, we look up the MX for the domain "example.com".
--   It has an RFC7505 NULL MX (to prevent a deluge of spam from examples
--   posted on the internet).
--   
--   
--   >>> rs <- makeResolvSeed defaultResolvConf
--   
--   >>> withResolver rs $ \resolver -> lookupMX resolver "example.com"
--   Right [(".",0)]
--   
--   
--   The domain "mew.org" does however have a single MX:
--   
--   
--   >>> rs2 <- makeResolvSeed defaultResolvConf
--   
--   >>> withResolver rs2 $ \resolver -> lookupMX resolver "mew.org"
--   Right [("mail.mew.org.",10)]
--   
--   
--   Also note that all hostnames are returned with a trailing dot to
--   indicate the DNS root.
--   
--   However the MX host itself has no need for an MX record, so its MX
--   RRset is empty. But, "no results" is still a successful result.
--   
--   
--   >>> rs3 <- makeResolvSeed defaultResolvConf
--   
--   >>> withResolver rs3 $ \resolver -> lookupMX resolver "mail.mew.org"
--   Right []
--   
lookupMX :: Resolver -> Domain -> IO (Either DNSError [(Domain, Int)])

-- | Look up all 'MX' records for the given hostname, and then resolve
--   their hostnames to IPv4 addresses by calling lookupA. The
--   priorities are not retained.
--   
--   Examples:
--   
--   
--   >>> import Data.List (sort)
--   
--   >>> rs <- makeResolvSeed defaultResolvConf
--   
--   >>> ips <- withResolver rs $ \resolver -> lookupAviaMX resolver "wide.ad.jp"
--   
--   >>> fmap sort ips
--   Right [203.178.136.30]
--   
--   
--   Since there is more than one result, it is necessary to sort the list
--   in order to check for equality.
lookupAviaMX :: Resolver -> Domain -> IO (Either DNSError [IPv4])

-- | Look up all 'MX' records for the given hostname, and then resolve
--   their hostnames to IPv6 addresses by calling lookupAAAA. The
--   priorities are not retained.
lookupAAAAviaMX :: Resolver -> Domain -> IO (Either DNSError [IPv6])

-- | Look up all 'NS' records for the given hostname. The results are taken
--   from the ANSWER section of the response (as opposed to AUTHORITY). For
--   details, see e.g. http://www.zytrax.com/books/dns/ch15/.
--   
--   There will typically be more than one name server for a domain. It is
--   therefore extra important to sort the results if you prefer them to be
--   at all deterministic.
--   
--   Examples:
--   
--   
--   >>> import Data.List (sort)
--   
--   >>> rs <- makeResolvSeed defaultResolvConf
--   
--   >>> ns <- withResolver rs $ \resolver -> lookupNS resolver "mew.org"
--   
--   >>> fmap sort ns
--   Right ["ns1.mew.org.","ns2.mew.org."]
--   
lookupNS :: Resolver -> Domain -> IO (Either DNSError [Domain])

-- | Look up all 'NS' records for the given hostname. The results are taken
--   from the AUTHORITY section of the response and not the usual ANSWER
--   (use lookupNS for that). For details, see e.g.
--   http://www.zytrax.com/books/dns/ch15/.
--   
--   There will typically be more than one name server for a domain. It is
--   therefore extra important to sort the results if you prefer them to be
--   at all deterministic.
--   
--   For an example, we can look up the nameservers for "example.com" from
--   one of the root servers, a.gtld-servers.net, the IP address of which
--   was found beforehand:
--   
--   
--   >>> import Data.List (sort)
--   
--   >>> let ri = RCHostName "192.5.6.30" -- a.gtld-servers.net
--   
--   >>> let rc = defaultResolvConf { resolvInfo = ri }
--   
--   >>> rs <- makeResolvSeed rc
--   
--   >>> ns <- withResolver rs $ \resolver -> lookupNSAuth resolver "example.com"
--   
--   >>> fmap sort ns
--   Right ["a.iana-servers.net.","b.iana-servers.net."]
--   
lookupNSAuth :: Resolver -> Domain -> IO (Either DNSError [Domain])

-- | Look up all 'TXT' records for the given hostname. The results are
--   free-form ByteStrings.
--   
--   Two common uses for 'TXT' records are
--   http://en.wikipedia.org/wiki/Sender_Policy_Framework and
--   http://en.wikipedia.org/wiki/DomainKeys_Identified_Mail. As an
--   example, we find the SPF record for "mew.org":
--   
--   
--   >>> rs <- makeResolvSeed defaultResolvConf
--   
--   >>> withResolver rs $ \resolver -> lookupTXT resolver "mew.org"
--   Right ["v=spf1 +mx -all"]
--   
lookupTXT :: Resolver -> Domain -> IO (Either DNSError [ByteString])

-- | Look up the 'SOA' record for the given domain. The result 7-tuple
--   consists of the 'mname', 'rname', 'serial', 'refresh', 'retry',
--   'expire' and 'minimum' fields of the SOA record.
--   
--   An @ separator is used between the first and second labels of the
--   'rname' field. Since 'rname' is an email address, it often contains
--   periods within its first label. Presently, the trailing period is not
--   removed from the domain part of the 'rname', but this may change in
--   the future. Users should be prepared to remove any trailing period
--   before using the 'rname` as a contact email address.
--   
--   
--   >>> rs <- makeResolvSeed defaultResolvConf
--   
--   >>> soa <- withResolver rs $ \resolver -> lookupSOA resolver "mew.org"
--   
--   >>> map (\ (mn, rn, _, _, _, _, _) -> (mn, rn)) <$> soa
--   Right [("ns1.mew.org.","kazu@mew.org.")]
--   
lookupSOA :: Resolver -> Domain -> IO (Either DNSError [(Domain, Mailbox, Word32, Word32, Word32, Word32, Word32)])

-- | Look up all 'PTR' records for the given hostname. To perform a reverse
--   lookup on an IP address, you must first reverse its octets and then
--   append the suffix ".in-addr.arpa."
--   
--   We look up the PTR associated with the IP address 210.130.137.80,
--   i.e., 80.137.130.210.in-addr.arpa:
--   
--   
--   >>> rs <- makeResolvSeed defaultResolvConf
--   
--   >>> withResolver rs $ \resolver -> lookupPTR resolver "180.2.232.202.in-addr.arpa"
--   Right ["www.iij.ad.jp."]
--   
--   
--   The lookupRDNS function is more suited to this particular task.
lookupPTR :: Resolver -> Domain -> IO (Either DNSError [Domain])

-- | Convenient wrapper around lookupPTR to perform a reverse lookup
--   on a single IP address.
--   
--   We repeat the example from lookupPTR, except now we pass the IP
--   address directly:
--   
--   
--   >>> rs <- makeResolvSeed defaultResolvConf
--   
--   >>> withResolver rs $ \resolver -> lookupRDNS resolver "202.232.2.180"
--   Right ["www.iij.ad.jp."]
--   
lookupRDNS :: Resolver -> Domain -> IO (Either DNSError [Domain])

-- | Look up all 'SRV' records for the given hostname. SRV records consist
--   (see https://tools.ietf.org/html/rfc2782) of the following four
--   fields:
--   
--   
--   
- Priority (lower is more-preferred)
--   
- Weight (relative frequency with which to use this record amongst
--   all results with the same priority)
--   
- Port (the port on which the service is offered)
--   
- Target (the hostname on which the service is offered)
--   
--   
--   The first three are integral, and the target is another DNS hostname.
--   We therefore return a four-tuple (Int,Int,Int,Domain).
--   
--   Examples:
--   
--   
--   >>> rs <- makeResolvSeed defaultResolvConf
--   
--   >>> withResolver rs $ \resolver -> lookupSRV resolver "_xmpp-server._tcp.jabber.ietf.org"
--   Right [(5,0,5269,"_dc-srv.6661af51975d._xmpp-server._tcp.jabber.ietf.org.")]
--   
lookupSRV :: Resolver -> Domain -> IO (Either DNSError [(Word16, Word16, Word16, Domain)])

-- | Miscellaneous utility functions for processing DNS data.
module Network.DNS.Utils

-- | Perform both normalizeCase and normalizeRoot on the
--   given Domain. When comparing DNS names taken from user input,
--   this is often necessary to avoid unexpected results.
--   
--   Examples:
--   
--   
--   >>> let domain1 = BS.pack "ExAmPlE.COM"
--   
--   >>> let domain2 = BS.pack "example.com."
--   
--   >>> domain1 == domain2
--   False
--   
--   >>> normalize domain1 == normalize domain2
--   True
--   
--   
--   The normalize function should be idempotent:
--   
--   
--   >>> normalize (normalize domain1) == normalize domain1
--   True
--   
--   
--   Ensure that we don't crash on the empty Domain:
--   
--   
--   >>> import qualified Data.ByteString.Char8 as BS
--   
--   >>> normalize BS.empty
--   "."
--   
normalize :: Domain -> Domain

-- | Normalize the case of the given DNS name for comparisons.
--   
--   According to RFC #1035, "For all parts of the DNS that are part of the
--   official protocol, all comparisons between character strings (e.g.,
--   labels, domain names, etc.) are done in a case-insensitive manner."
--   This function chooses to lowercase its argument, but that should be
--   treated as an implementation detail if at all possible.
--   
--   Examples:
--   
--   
--   >>> let domain1 = BS.pack "ExAmPlE.COM"
--   
--   >>> let domain2 = BS.pack "exAMPle.com"
--   
--   >>> domain1 == domain2
--   False
--   
--   >>> normalizeCase domain1 == normalizeCase domain2
--   True
--   
--   
--   The normalizeCase function should be idempotent:
--   
--   
--   >>> normalizeCase (normalizeCase domain2) == normalizeCase domain2
--   True
--   
--   
--   Ensure that we don't crash on the empty Domain:
--   
--   
--   >>> import qualified Data.ByteString.Char8 as BS
--   
--   >>> normalizeCase BS.empty
--   ""
--   
normalizeCase :: Domain -> Domain

-- | Normalize the given name by appending a trailing dot (the DNS root) if
--   one does not already exist.
--   
--   Warning: this does not produce an equivalent DNS name! However, users
--   are often unaware of the effect that the absence of the root will
--   have. In user interface design, it may therefore be wise to act as if
--   the user supplied the trailing dot during comparisons.
--   
--   Per RFC #1034,
--   
--   "Since a complete domain name ends with the root label, this leads to
--   a printed form which ends in a dot. We use this property to
--   distinguish between:
--   
--   
--   
- a character string which represents a complete domain name (often
--   called 'absolute'). For example, 'poneria.ISI.EDU.'
--   
- a character string that represents the starting labels of a domain
--   name which is incomplete, and should be completed by local software
--   using knowledge of the local domain (often called 'relative'). For
--   example, 'poneria' used in the ISI.EDU domain.
--   
--   
--   Relative names are either taken relative to a well known origin, or to
--   a list of domains used as a search list. Relative names appear mostly
--   at the user interface, where their interpretation varies from
--   implementation to implementation, and in master files, where they are
--   relative to a single origin domain name."
--   
--   Examples:
--   
--   
--   >>> let domain1 = BS.pack "example.com"
--   
--   >>> let domain2 = BS.pack "example.com."
--   
--   >>> domain1 == domain2
--   False
--   
--   >>> normalizeRoot domain1 == normalizeRoot domain2
--   True
--   
--   
--   The normalizeRoot function should be idempotent:
--   
--   
--   >>> normalizeRoot (normalizeRoot domain1) == normalizeRoot domain1
--   True
--   
--   
--   Ensure that we don't crash on the empty Domain:
--   
--   
--   >>> import qualified Data.ByteString.Char8 as BS
--   
--   >>> normalizeRoot BS.empty
--   "."
--   
normalizeRoot :: Domain -> Domain

-- | Split a domain name in A-label form into its initial label and the
--   rest of the domain. Returns an error if the initial label is
--   malformed. When no more labels remain, the initial label will satisfy
--   null.
--   
--   This also decodes any escaped characters in the initial label, which
--   may therefore contain whitespace, binary data, or unescaped internal
--   dots. To reconstruct the original domain, the initial label may
--   sometimes require correct escaping of special characters.
--   
--   
Examples
--   
--   
--   >>> import Data.ByteString.Char8 as BS
--   
--   >>> splitDomain $ BS.pack "abc\\.def.xyz"
--   Right ("abc.def","xyz")
--   
--   
--   
--   >>> splitDomain $ BS.pack ".abc.def.xyz"
--   Left (DecodeError "invalid domain: .abc.def.xyz")
--   
splitDomain :: Domain -> Either DNSError (ByteString, Domain)

-- | Split a Mailbox in A-label form into its initial label
--   ByteString (the localpart of the email address) and the
--   remaining Domain (the domainpart of the email address,
--   with a possible trailing .). Returns an error if the
--   initial label is malformed. When no more labels remain, the initial
--   label will satisfy null. The remaining labels can be obtained
--   by applying splitDomain the returned domain part.
--   
--   This also decodes any escaped characters in the initial label, which
--   may therefore contain whitespace, binary data, or unescaped internal
--   dots. To reconstruct the original mailbox, the initial label may
--   sometimes require correct escaping of special characters.
--   
--   
Example
--   
--   
--   >>> import Data.ByteString.Char8 as BS
--   
--   >>> splitMailbox $ BS.pack "Joe.Admin@example.com."
--   Right ("Joe.Admin","example.com.")
--   
splitMailbox :: Mailbox -> Either DNSError (ByteString, Domain)

-- | A thread-safe DNS library for both clients and servers written in pure
--   Haskell. The Network.DNS module re-exports all other exposed modules
--   for convenience. Applications will most likely use the high-level
--   interface, while library/daemon authors may need to use the
--   lower-level one. EDNS and TCP fallback are supported.
--   
--   Examples:
--   
--   
--   >>> :set -XOverloadedStrings
--   
--   >>> rs <- makeResolvSeed defaultResolvConf
--   
--   >>> withResolver rs $ \resolver -> lookupA resolver "192.0.2.1.nip.io"
--   Right [192.0.2.1]
--   
module Network.DNS
