module Network.DNS.RBL.Host ( Host(..), host ) where import Text.Parsec ( (<|>), char, try ) import Text.Parsec.String ( Parser ) import Network.DNS.RBL.Domain.Domain ( Domain(..), domain ) import Network.DNS.RBL.Pretty ( Pretty(..) ) import Network.DNS.RBL.Reversible ( Reversible(..) ) -- | This type helps clarify some murkiness in the DNS \"domain\" name -- specification. In RFC1034, it is acknowledged that a domain name -- input with a trailing \".\" will represent an absolute domain -- name (i.e. with respect to the DNS root). However, the grammar in -- RFC1035 disallows a trailing dot. -- -- This makes some sense: within the DNS, everything knows its -- position in the tree. The relative/absolute distinction only -- makes sense on the client side, where a user's resolver might -- decide to append some suffix to a relative -- request. Unfortunately, that's where we live. So we have to deal -- with the possibility of having a trailing dot at the end of any -- domain name. -- data Host = HostRelative Domain | HostAbsolute Domain deriving (Eq, Show) instance Pretty Host where pretty_show (HostRelative d) = pretty_show d pretty_show (HostAbsolute d) = (pretty_show d) ++ "." -- | Parse a 'Host'. This is what we'll be using to read user -- input, since it supports both relative and absolute domain names -- (unlike the implicitly-absolute 'Domain'). -- -- ==== _Examples_ -- -- >>> import Text.Parsec ( parse, parseTest ) -- -- We can really parse the root now! -- -- >>> parseTest host "." -- HostAbsolute DomainRoot -- -- But multiple dots aren't (only the first): -- -- >>> pretty_print $ parse host "" ".." -- . -- -- We can also optionally have a trailing dot at the end of a -- non-empty name: -- -- >>> pretty_print $ parse host "" "www.example.com" -- www.example.com -- -- >>> pretty_print $ parse host "" "www.example.com." -- www.example.com. -- -- A \"relative root\" can also be parsed, letting the user's -- resolver deal with it: -- -- >>> parseTest host "" -- HostRelative DomainRoot -- host :: Parser Host host = try absolute <|> relative where absolute :: Parser Host absolute = do d <- domain _ <- char '.' return $ HostAbsolute d relative :: Parser Host relative = fmap HostRelative domain instance Reversible Host where -- | Reverse the labels of this 'Host' in preparation for making a -- lookup (using the DNS library). We need to reverse the labels -- (the stuff between the dots) whether we're looking up a host or a -- name. -- -- ==== _Examples_ -- -- >>> import Text.Parsec ( parse ) -- -- >>> let (Right r) = parse host "" "1.2.3.4" -- >>> pretty_print $ backwards r -- 4.3.2.1 -- -- >>> let (Right r) = parse host "" "new.www.example.com" -- >>> pretty_print $ backwards r -- com.example.www.new -- backwards (HostRelative d) = HostRelative $ backwards d backwards (HostAbsolute d) = HostAbsolute $ backwards d