Compare commits

...

4 Commits

Author SHA1 Message Date
Kazu Yamamoto
bab7c9cb60 adding smart constructors 2022-09-08 16:10:59 +09:00
Kazu Yamamoto
3b406912b7 updating doc 2022-09-08 14:16:22 +09:00
Kazu Yamamoto
95f80e2777 adding resourceDataType method 2022-09-08 14:11:42 +09:00
Kazu Yamamoto
339ebb4931 brushing up exports 2022-09-07 15:26:37 +09:00
5 changed files with 162 additions and 23 deletions

View File

@ -22,6 +22,7 @@ module Network.DNS.Types (
, PTR
, MX
, TXT
, RP
, AAAA
, SRV
, DNAME
@ -43,8 +44,7 @@ module Network.DNS.Types (
, fromTYPE
, toTYPE
-- ** Resource Data
, RData
, ResourceData
, ResourceData(..)
, RD_A(..)
, RD_NS(..)
, RD_CNAME(..)
@ -68,9 +68,37 @@ module Network.DNS.Types (
, RD_CDS(..)
, RD_CDNSKEY(..)
, RD_Unknown(..)
-- *** RData
, RData(..)
, toRData
, fromRData
, dnsTime
, rdataType
, SGet
, SPut
-- *** Smart constructors
, rd_a
, rd_ns
, rd_cname
, rd_soa
, rd_null
, rd_ptr
, rd_mx
, rd_txt
, rd_rp
, rd_aaaa
, rd_srv
, rd_dname
, rd_opt
, rd_ds
, rd_rrsig
, rd_nsec
, rd_dnskey
, rd_nsec3
, rd_nsec3param
, rd_tlsa
, rd_cds
, rd_cdnskey
, rd_unknown
-- * DNS Message
, DNSMessage (..)
-- ** Query
@ -160,6 +188,9 @@ module Network.DNS.Types (
, DNSError (..)
-- * Other types
, Mailbox
-- * Other functions
, dnsTime
) where
import Network.DNS.Types.Internal
import Network.DNS.StateBinary

View File

@ -146,4 +146,4 @@ switch NSEC3PARAM l = toRData <$> decodeResourceData (Proxy :: Proxy RD_NSEC3PAR
switch TLSA l = toRData <$> decodeResourceData (Proxy :: Proxy RD_TLSA) l
switch CDS l = toRData <$> decodeResourceData (Proxy :: Proxy RD_CDS) l
switch CDNSKEY l = toRData <$> decodeResourceData (Proxy :: Proxy RD_CDNSKEY) l
switch _ _ = undefined
switch typ l = toRData <$> RD_Unknown typ <$> getNByteString l

View File

@ -21,17 +21,21 @@ import Network.DNS.Types.EDNS
---------------------------------------------------------------
class (Typeable a, Eq a, Show a) => ResourceData a where
resourceDataType :: a -> TYPE
encodeResourceData :: a -> SPut
decodeResourceData :: proxy a -> Int -> SGet a
copyResourceData :: a -> a
---------------------------------------------------------------
-- | A type to uniform 'ResourceData' 'a'.
data RData = forall a . (Typeable a, Eq a, Show a, ResourceData a) => RData a
-- | Extracting the original type.
fromRData :: Typeable a => RData -> Maybe a
fromRData (RData x) = cast x
-- | Wrapping the original type with 'RData'.
toRData :: (Typeable a, ResourceData a) => a -> RData
toRData = RData
@ -41,12 +45,17 @@ instance Show RData where
instance Eq RData where
x@(RData xi) == y@(RData yi) = typeOf x == typeOf y && Just xi == cast yi
-- | Getting 'TYPE' of 'RData'.
rdataType :: RData -> TYPE
rdataType (RData x) = resourceDataType x
---------------------------------------------------------------
-- | IPv4 Address (RFC1035)
newtype RD_A = RD_A IPv4 deriving Eq
instance ResourceData RD_A where
resourceDataType = \_ -> A
encodeResourceData = \(RD_A ipv4) -> mconcat $ map putInt8 (fromIPv4 ipv4)
decodeResourceData = \_ _ -> RD_A . toIPv4 <$> getNBytes 4
copyResourceData x = x
@ -54,12 +63,16 @@ instance ResourceData RD_A where
instance Show RD_A where
show (RD_A ipv4) = show ipv4
rd_a :: IPv4 -> RData
rd_a ipv4 = toRData $ RD_A ipv4
----------------------------------------------------------------
-- | An authoritative name serve (RFC1035)
newtype RD_NS = RD_NS Domain deriving (Eq)
instance ResourceData RD_NS where
resourceDataType = \_ -> NS
encodeResourceData = \(RD_NS d) -> putDomain d
decodeResourceData = \_ _ -> RD_NS <$> getDomain
copyResourceData (RD_NS dom) = RD_NS $ B.copy dom
@ -67,12 +80,16 @@ instance ResourceData RD_NS where
instance Show RD_NS where
show (RD_NS d) = showDomain d
rd_ns :: Domain -> RData
rd_ns d = toRData $ RD_NS d
----------------------------------------------------------------
-- | The canonical name for an alias (RFC1035)
newtype RD_CNAME = RD_CNAME Domain deriving (Eq)
instance ResourceData RD_CNAME where
resourceDataType = \_ -> CNAME
encodeResourceData = \(RD_CNAME d) -> putDomain d
decodeResourceData = \_ _ -> RD_CNAME <$> getDomain
copyResourceData (RD_CNAME dom) = RD_CNAME $ B.copy dom
@ -80,6 +97,9 @@ instance ResourceData RD_CNAME where
instance Show RD_CNAME where
show (RD_CNAME d) = showDomain d
rd_cname :: Domain -> RData
rd_cname d = toRData $ RD_CNAME d
----------------------------------------------------------------
-- | Marks the start of a zone of authority (RFC1035)
@ -94,6 +114,7 @@ data RD_SOA = RD_SOA {
} deriving (Eq)
instance ResourceData RD_SOA where
resourceDataType = \_ -> SOA
encodeResourceData = \RD_SOA{..} ->
mconcat [ putDomain soaMname
, putMailbox soaRname
@ -124,12 +145,16 @@ instance Show RD_SOA where
++ show soaExpire ++ " "
++ show soaMinimum
rd_soa :: Domain -> Mailbox -> Word32 -> Word32 -> Word32 -> Word32 -> Word32 -> RData
rd_soa a b c d e f g = toRData $ RD_SOA a b c d e f g
----------------------------------------------------------------
-- | NULL RR (EXPERIMENTAL, RFC1035).
newtype RD_NULL = RD_NULL ByteString deriving (Eq)
instance ResourceData RD_NULL where
resourceDataType = \_ -> NULL
encodeResourceData = \(RD_NULL bytes) -> putByteString bytes
decodeResourceData = \_ len -> RD_NULL <$> getNByteString len
copyResourceData (RD_NULL bytes) = RD_NULL $ B.copy bytes
@ -137,12 +162,16 @@ instance ResourceData RD_NULL where
instance Show RD_NULL where
show (RD_NULL bytes) = showOpaque bytes
rd_null :: ByteString -> RData
rd_null x = toRData $ RD_NULL x
----------------------------------------------------------------
-- | A domain name pointer (RFC1035)
newtype RD_PTR = RD_PTR Domain deriving (Eq)
instance ResourceData RD_PTR where
resourceDataType = \_ -> PTR
encodeResourceData = \(RD_PTR d) -> putDomain d
decodeResourceData = \_ _ -> RD_PTR <$> getDomain
copyResourceData (RD_PTR dom) = RD_PTR $ B.copy dom
@ -150,6 +179,9 @@ instance ResourceData RD_PTR where
instance Show RD_PTR where
show (RD_PTR d) = showDomain d
rd_ptr :: Domain -> RData
rd_ptr d = toRData $ RD_PTR d
----------------------------------------------------------------
-- | Mail exchange (RFC1035)
@ -159,6 +191,7 @@ data RD_MX = RD_MX {
} deriving (Eq)
instance ResourceData RD_MX where
resourceDataType = \_ -> MX
encodeResourceData = \RD_MX{..} ->
mconcat [ put16 mxPreference
, putDomain mxExchange
@ -169,12 +202,16 @@ instance ResourceData RD_MX where
instance Show RD_MX where
show RD_MX{..} = show mxPreference ++ " " ++ showDomain mxExchange
rd_mx :: Word16 -> Domain -> RData
rd_mx a b = toRData $ RD_MX a b
----------------------------------------------------------------
-- | Text strings (RFC1035)
newtype RD_TXT = RD_TXT ByteString deriving (Eq)
instance ResourceData RD_TXT where
resourceDataType = \_ -> TXT
encodeResourceData = \(RD_TXT txt0) -> putTXT txt0
where
putTXT txt = let (!h, !t) = BS.splitAt 255 txt
@ -204,12 +241,16 @@ instance Show RD_TXT where
(q10, r10) = divMod r100 10
in intToDigit q100 : intToDigit q10 : intToDigit r10 : s
rd_txt :: ByteString -> RData
rd_txt x = toRData $ RD_TXT x
----------------------------------------------------------------
-- | Responsible Person (RFC1183)
data RD_RP = RD_RP Mailbox Domain deriving (Eq)
instance ResourceData RD_RP where
resourceDataType = \_ -> RP
encodeResourceData = \(RD_RP mbox d) -> putMailbox mbox <> putDomain d
decodeResourceData = \_ _ -> RD_RP <$> getMailbox <*> getDomain
copyResourceData (RD_RP mbox dname) = RD_RP (B.copy mbox) (B.copy dname)
@ -218,12 +259,16 @@ instance Show RD_RP where
show (RD_RP mbox d) =
showDomain mbox ++ " " ++ showDomain d
rd_rp :: Mailbox -> Domain -> RData
rd_rp a b = toRData $ RD_RP a b
----------------------------------------------------------------
-- | IPv6 Address (RFC3596)
newtype RD_AAAA = RD_AAAA IPv6 deriving (Eq)
instance ResourceData RD_AAAA where
resourceDataType = \_ -> AAAA
encodeResourceData = \(RD_AAAA ipv6) -> mconcat $ map putInt8 (fromIPv6b ipv6)
decodeResourceData = \_ _ -> RD_AAAA . toIPv6b <$> getNBytes 16
copyResourceData x = x
@ -231,6 +276,9 @@ instance ResourceData RD_AAAA where
instance Show RD_AAAA where
show (RD_AAAA ipv6) = show ipv6
rd_aaaa :: IPv6 -> RData
rd_aaaa ipv6 = toRData $ RD_AAAA ipv6
----------------------------------------------------------------
-- | Server Selection (RFC2782)
@ -242,6 +290,7 @@ data RD_SRV = RD_SRV {
} deriving (Eq)
instance ResourceData RD_SRV where
resourceDataType = \_ -> SRV
encodeResourceData = \RD_SRV{..} ->
mconcat [ put16 srvPriority
, put16 srvWeight
@ -260,12 +309,16 @@ instance Show RD_SRV where
++ show srvPort ++ " "
++ BS.unpack srvTarget
rd_srv :: Word16 -> Word16 -> Word16 -> Domain -> RData
rd_srv a b c d = toRData $ RD_SRV a b c d
----------------------------------------------------------------
-- | DNAME (RFC6672)
newtype RD_DNAME = RD_DNAME Domain deriving (Eq)
instance ResourceData RD_DNAME where
resourceDataType = \_ -> DNAME
encodeResourceData = \(RD_DNAME d) -> putDomain d
decodeResourceData = \_ _ -> RD_DNAME <$> getDomain
copyResourceData (RD_DNAME dom) = RD_DNAME $ B.copy dom
@ -273,12 +326,16 @@ instance ResourceData RD_DNAME where
instance Show RD_DNAME where
show (RD_DNAME d) = showDomain d
rd_dname :: Domain -> RData
rd_dname d = toRData $ RD_DNAME d
----------------------------------------------------------------
-- | OPT (RFC6891)
newtype RD_OPT = RD_OPT [OData] deriving (Eq)
instance ResourceData RD_OPT where
resourceDataType = \_ -> OPT
encodeResourceData = \(RD_OPT options) -> mconcat $ fmap putOData options
decodeResourceData = \_ len ->
RD_OPT <$> sGetMany "EDNS option" len getoption
@ -292,6 +349,9 @@ instance ResourceData RD_OPT where
instance Show RD_OPT where
show (RD_OPT options) = show options
rd_opt :: [OData] -> RData
rd_opt x = toRData $ RD_OPT x
----------------------------------------------------------------
-- | TLSA (RFC6698)
@ -303,6 +363,7 @@ data RD_TLSA = RD_TLSA {
} deriving (Eq)
instance ResourceData RD_TLSA where
resourceDataType = \_ -> TLSA
encodeResourceData = \RD_TLSA{..} ->
mconcat [ put8 tlsaUsage
, put8 tlsaSelector
@ -323,15 +384,22 @@ instance Show RD_TLSA where
++ show tlsaMatchingType ++ " "
++ _b16encode tlsaAssocData
rd_tlsa :: Word8 -> Word8 -> Word8 -> ByteString -> RData
rd_tlsa a b c d = toRData $ RD_TLSA a b c d
----------------------------------------------------------------
-- | Unknown resource data
newtype RD_Unknown = RD_Unknown ByteString deriving (Eq, Show)
data RD_Unknown = RD_Unknown TYPE ByteString deriving (Eq, Show)
instance ResourceData RD_Unknown where
encodeResourceData = \(RD_Unknown bytes) -> putByteString bytes
decodeResourceData = \_ len -> RD_Unknown <$> getNByteString len
copyResourceData (RD_Unknown x) = RD_Unknown $ B.copy x
resourceDataType = \(RD_Unknown typ _) -> typ
encodeResourceData = \(RD_Unknown _ bytes) -> putByteString bytes
decodeResourceData = undefined -- never used
copyResourceData (RD_Unknown t x) = RD_Unknown t $ B.copy x
rd_unknown :: TYPE -> ByteString -> RData
rd_unknown a b = toRData $ RD_Unknown a b
----------------------------------------------------------------

View File

@ -12,6 +12,14 @@ module Network.DNS.Types.Sec (
, RD_CDNSKEY(..)
, getTYPE
, dnsTime
, rd_rrsig
, rd_ds
, rd_nsec
, rd_dnskey
, rd_nsec3
, rd_nsec3param
, rd_cds
, rd_cdnskey
) where
import qualified Data.ByteString.Char8 as BS
@ -61,6 +69,7 @@ data RD_RRSIG = RD_RRSIG {
} deriving (Eq, Ord)
instance ResourceData RD_RRSIG where
resourceDataType = \_ -> RRSIG
encodeResourceData = \RD_RRSIG{..} ->
mconcat [ put16 $ fromTYPE rrsigType
, put8 rrsigKeyAlg
@ -119,6 +128,9 @@ instance Show RD_RRSIG where
fmt = [ H.Format_Year4, H.Format_Month2, H.Format_Day2
, H.Format_Hour, H.Format_Minute, H.Format_Second ]
rd_rrsig :: TYPE -> Word8 -> Word8 -> Word32 -> Int64 -> Int64 -> Word16 -> Domain -> ByteString -> RData
rd_rrsig a b c d e f g h i = toRData $ RD_RRSIG a b c d e f g h i
----------------------------------------------------------------
-- | Delegation Signer (RFC4034)
@ -130,6 +142,7 @@ data RD_DS = RD_DS {
} deriving (Eq)
instance ResourceData RD_DS where
resourceDataType = \_ -> DS
encodeResourceData = \RD_DS{..} ->
mconcat [ put16 dsKeyTag
, put8 dsAlgorithm
@ -149,6 +162,9 @@ instance Show RD_DS where
++ show dsDigestType ++ " "
++ _b16encode dsDigest
rd_ds :: Word16 -> Word8 -> Word8 -> ByteString -> RData
rd_ds a b c d = toRData $ RD_DS a b c d
----------------------------------------------------------------
-- | DNSSEC denial of existence NSEC record
@ -158,6 +174,7 @@ data RD_NSEC = RD_NSEC {
} deriving (Eq)
instance ResourceData RD_NSEC where
resourceDataType = \_ -> NSEC
encodeResourceData = \RD_NSEC{..} ->
putDomain nsecNextDomain <> putNsecTypes nsecTypes
decodeResourceData = \_ len -> do
@ -172,6 +189,9 @@ instance Show RD_NSEC where
show RD_NSEC{..} =
unwords $ showDomain nsecNextDomain : map show nsecTypes
rd_nsec :: Domain -> [TYPE] -> RData
rd_nsec a b = toRData $ RD_NSEC a b
----------------------------------------------------------------
-- | DNSKEY (RFC4034)
@ -183,6 +203,7 @@ data RD_DNSKEY = RD_DNSKEY {
} deriving (Eq)
instance ResourceData RD_DNSKEY where
resourceDataType = \_ -> DNSKEY
encodeResourceData = \RD_DNSKEY{..} ->
mconcat [ put16 dnskeyFlags
, put8 dnskeyProtocol
@ -204,6 +225,9 @@ instance Show RD_DNSKEY where
++ show dnskeyAlgorithm ++ " "
++ _b64encode dnskeyPublicKey
rd_dnskey :: Word16 -> Word8 -> Word8 -> ByteString -> RData
rd_dnskey a b c d = toRData $ RD_DNSKEY a b c d
----------------------------------------------------------------
-- | DNSSEC hashed denial of existence (RFC5155)
@ -217,6 +241,7 @@ data RD_NSEC3 = RD_NSEC3 {
} deriving (Eq)
instance ResourceData RD_NSEC3 where
resourceDataType = \_ -> NSEC3
encodeResourceData = \RD_NSEC3{..} ->
mconcat [ put8 nsec3HashAlgorithm
, put8 nsec3Flags
@ -247,6 +272,9 @@ instance Show RD_NSEC3 where
: _b32encode nsec3NextHashedOwnerName
: map show nsec3Types
rd_nsec3 :: Word8 -> Word8 -> Word16 -> ByteString -> ByteString -> [TYPE] -> RData
rd_nsec3 a b c d e f = toRData $ RD_NSEC3 a b c d e f
----------------------------------------------------------------
-- | NSEC3 zone parameters (RFC5155)
@ -258,6 +286,7 @@ data RD_NSEC3PARAM = RD_NSEC3PARAM {
} deriving (Eq)
instance ResourceData RD_NSEC3PARAM where
resourceDataType = \_ -> NSEC3PARAM
encodeResourceData = \RD_NSEC3PARAM{..} ->
mconcat [ put8 nsec3paramHashAlgorithm
, put8 nsec3paramFlags
@ -278,12 +307,16 @@ instance Show RD_NSEC3PARAM where
++ show nsec3paramIterations ++ " "
++ showSalt nsec3paramSalt
rd_nsec3param :: Word8 -> Word8 -> Word16 -> ByteString -> RData
rd_nsec3param a b c d = toRData $ RD_NSEC3PARAM a b c d
----------------------------------------------------------------
-- | Child DS (RFC7344)
newtype RD_CDS = RD_CDS RD_DS deriving (Eq)
instance ResourceData RD_CDS where
resourceDataType = \_ -> CDS
encodeResourceData = \(RD_CDS ds) -> encodeResourceData ds
decodeResourceData = \_ len -> RD_CDS <$> decodeResourceData (Proxy :: Proxy RD_DS) len
copyResourceData = \(RD_CDS ds) -> RD_CDS $ copyResourceData ds
@ -291,12 +324,16 @@ instance ResourceData RD_CDS where
instance Show RD_CDS where
show (RD_CDS ds) = show ds
rd_cds :: Word16 -> Word8 -> Word8 -> ByteString -> RData
rd_cds a b c d = toRData $ RD_CDS $ RD_DS a b c d
----------------------------------------------------------------
-- | Child DNSKEY (RFC7344)
newtype RD_CDNSKEY = RD_CDNSKEY RD_DNSKEY deriving (Eq)
instance ResourceData RD_CDNSKEY where
resourceDataType = \_ -> CDNSKEY
encodeResourceData = \(RD_CDNSKEY dnskey) -> encodeResourceData dnskey
decodeResourceData = \_ len -> RD_CDNSKEY <$> decodeResourceData (Proxy :: Proxy RD_DNSKEY) len
copyResourceData = \(RD_CDNSKEY dnskey) -> RD_CDNSKEY $ copyResourceData dnskey
@ -304,6 +341,9 @@ instance ResourceData RD_CDNSKEY where
instance Show RD_CDNSKEY where
show (RD_CDNSKEY dnskey) = show dnskey
rd_cdnskey :: Word16 -> Word8 -> Word8 -> ByteString -> RData
rd_cdnskey a b c d = toRData $ RD_CDNSKEY $ RD_DNSKEY a b c d
----------------------------------------------------------------
getTYPE :: SGet TYPE

View File

@ -104,20 +104,20 @@ genResourceRecord = frequency
mkRData :: Domain -> TYPE -> Gen RData
mkRData dom typ =
case typ of
A -> toRData <$> (RD_A <$> genIPv4)
AAAA -> toRData <$> (RD_AAAA <$> genIPv6)
NS -> toRData <$> pure (RD_NS dom)
TXT -> toRData <$> (RD_TXT <$> genTextString)
MX -> toRData <$> (RD_MX <$> genWord16 <*> genDomain)
CNAME -> toRData <$> pure (RD_CNAME dom)
SOA -> toRData <$> (RD_SOA dom <$> genMailbox <*> genWord32 <*> genWord32 <*> genWord32 <*> genWord32 <*> genWord32)
PTR -> toRData <$> (RD_PTR <$> genDomain)
SRV -> toRData <$> (RD_SRV <$> genWord16 <*> genWord16 <*> genWord16 <*> genDomain)
DNAME -> toRData <$> (RD_DNAME <$> genDomain)
DS -> toRData <$> (RD_DS <$> genWord16 <*> genWord8 <*> genWord8 <*> genByteString)
NSEC -> toRData <$> (RD_NSEC <$> genDomain <*> genNsecTypes)
NSEC3 -> toRData <$> genNSEC3
TLSA -> toRData <$> (RD_TLSA <$> genWord8 <*> genWord8 <*> genWord8 <*> genByteString)
A -> rd_a <$> genIPv4
AAAA -> rd_aaaa <$> genIPv6
NS -> pure $ rd_ns dom
TXT -> rd_txt <$> genTextString
MX -> rd_mx <$> genWord16 <*> genDomain
CNAME -> pure $ rd_cname dom
SOA -> rd_soa dom <$> genMailbox <*> genWord32 <*> genWord32 <*> genWord32 <*> genWord32 <*> genWord32
PTR -> rd_ptr <$> genDomain
SRV -> rd_srv <$> genWord16 <*> genWord16 <*> genWord16 <*> genDomain
DNAME -> rd_dname <$> genDomain
DS -> rd_ds <$> genWord16 <*> genWord8 <*> genWord8 <*> genByteString
NSEC -> rd_nsec <$> genDomain <*> genNsecTypes
NSEC3 -> genNSEC3
TLSA -> rd_tlsa <$> genWord8 <*> genWord8 <*> genWord8 <*> genByteString
_ -> pure . toRData . RD_TXT $ "Unhandled type " <> BS.pack (show typ)
where
@ -127,7 +127,7 @@ mkRData dom typ =
iter <- elements [0..100]
salt <- elements ["", "AB"]
hash <- B.pack <$> replicateM hlen genWord8
RD_NSEC3 alg flgs iter salt hash <$> genNsecTypes
rd_nsec3 alg flgs iter salt hash <$> genNsecTypes
genTextString = do
len <- elements [0, 1, 63, 255, 256, 511, 512, 1023, 1024]
B.pack <$> replicateM len genWord8