dns 1.3.0 → 1.4.0
raw patch · 6 files changed
+161/−12 lines, 6 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
+ Network.DNS.Resolver: RCHostPort :: HostName -> PortNumber -> FileOrNumericHost
+ Network.DNS.Utils: normalize :: Domain -> Domain
+ Network.DNS.Utils: normalizeCase :: Domain -> Domain
+ Network.DNS.Utils: normalizeRoot :: Domain -> Domain
Files
- Network/DNS.hs +5/−0
- Network/DNS/Lookup.hs +4/−4
- Network/DNS/Resolver.hs +12/−6
- Network/DNS/StateBinary.hs +1/−1
- Network/DNS/Utils.hs +137/−0
- dns.cabal +2/−1
Network/DNS.hs view
@@ -20,6 +20,10 @@ -- you may need to use the 'lookup', 'lookupAuth', or 'lookupRaw' -- functions. + , module Network.DNS.Utils+ -- | The "Network.DNS.Utils" module contains utility functions used+ -- for processing DNS data.+ , module Network.DNS.Types -- | All of the types that the other modules use. @@ -34,6 +38,7 @@ import Network.DNS.Lookup import Network.DNS.Resolver+import Network.DNS.Utils import Network.DNS.Types import Network.DNS.Decode import Network.DNS.Encode
Network/DNS/Lookup.hs view
@@ -112,11 +112,11 @@ -- -- Examples: ----- >>> let hostname = Data.ByteString.Char8.pack "www.mew.org"+-- >>> let hostname = Data.ByteString.Char8.pack "www.wide.ad.jp" -- >>> -- >>> rs <- makeResolvSeed defaultResolvConf -- >>> withResolver rs $ \resolver -> lookupAAAA resolver hostname--- Right [2001:240:11e:c00:00:00:00:101]+-- Right [2001:200:dff:fff1:216:3eff:fe4b:651c] -- lookupAAAA :: Resolver -> Domain -> IO (Either DNSError [IPv6]) lookupAAAA rlv dom = do@@ -177,12 +177,12 @@ -- Examples: -- -- >>> import Data.List (sort)--- >>> let hostname = Data.ByteString.Char8.pack "iij.ad.jp"+-- >>> let hostname = Data.ByteString.Char8.pack "wide.ad.jp" -- >>> -- >>> rs <- makeResolvSeed defaultResolvConf -- >>> ips <- withResolver rs $ \resolver -> lookupAviaMX resolver hostname -- >>> fmap sort ips--- Right [202.232.30.70,202.232.30.144]+-- Right [133.138.10.34,203.178.136.49] -- -- Since there is more than one result, it is necessary to sort the -- list in order to check for equality.
Network/DNS/Resolver.hs view
@@ -28,7 +28,7 @@ import Network.DNS.Encode import Network.DNS.Internal import Network.Socket (HostName, Socket, SocketType(Datagram), sClose, socket, connect)-import Network.Socket (AddrInfoFlag(..), AddrInfo(..), defaultHints, getAddrInfo)+import Network.Socket (AddrInfoFlag(..), AddrInfo(..), SockAddr(..), PortNumber(..), defaultHints, getAddrInfo) import Prelude hiding (lookup) import System.Random (getStdRandom, randomR) import System.Timeout (timeout)@@ -55,6 +55,7 @@ -- data FileOrNumericHost = RCFilePath FilePath -- ^ A path for \"resolv.conf\" | RCHostName HostName -- ^ A numeric IP address+ | RCHostPort HostName PortNumber -- ^ A numeric IP address and port number -- | Type for resolver configuration. The easiest way to construct a -- @ResolvConf@ object is to modify the 'defaultResolvConf'.@@ -129,14 +130,15 @@ <*> pure (resolvBufsize conf) where addr = case resolvInfo conf of- RCHostName numhost -> makeAddrInfo numhost- RCFilePath file -> toAddr <$> readFile file >>= makeAddrInfo+ RCHostName numhost -> makeAddrInfo numhost Nothing+ RCHostPort numhost mport -> makeAddrInfo numhost $ Just mport+ RCFilePath file -> toAddr <$> readFile file >>= \i -> makeAddrInfo i Nothing toAddr cs = let l:_ = filter ("nameserver" `isPrefixOf`) $ lines cs in extract l extract = reverse . dropWhile isSpace . reverse . dropWhile isSpace . drop 11 -makeAddrInfo :: HostName -> IO AddrInfo-makeAddrInfo addr = do+makeAddrInfo :: HostName -> Maybe PortNumber -> IO AddrInfo+makeAddrInfo addr mport = do proto <- getProtocolNumber "udp" let hints = defaultHints { addrFlags = [AI_ADDRCONFIG, AI_NUMERICHOST, AI_PASSIVE]@@ -144,7 +146,11 @@ , addrProtocol = proto } a:_ <- getAddrInfo (Just hints) (Just addr) (Just "domain")- return a+ let connectPort = case addrAddress a of+ SockAddrInet pn ha -> SockAddrInet (maybe pn id mport) ha+ SockAddrInet6 pn fi ha sid -> SockAddrInet6 (maybe pn id mport) fi ha sid+ unix -> unix + return $ a { addrAddress = connectPort } ----------------------------------------------------------------
Network/DNS/StateBinary.hs view
@@ -7,7 +7,7 @@ import Control.Monad.State (State, StateT) import qualified Control.Monad.State as ST import Control.Monad.Trans.Resource (ResourceT)-import qualified Data.Attoparsec as A+import qualified Data.Attoparsec.ByteString as A import qualified Data.Attoparsec.ByteString.Lazy as AL import qualified Data.Attoparsec.Types as T import Data.ByteString (ByteString)
+ Network/DNS/Utils.hs view
@@ -0,0 +1,137 @@+-- | Miscellaneous utility functions for processing DNS data.+--+module Network.DNS.Utils (+ normalize+ , normalizeCase+ , normalizeRoot+ ) where++import qualified Data.ByteString.Char8 as BS (+ append+ , last+ , map+ , null+ , pack )+import Data.Char ( toLower )++import Network.DNS.Types ( Domain )+++-- | 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 ( empty )+-- >>> normalize BS.empty+-- "."+--+normalize :: Domain -> Domain+normalize = normalizeCase . normalizeRoot+++-- | 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 ( empty )+-- >>> normalizeCase BS.empty+-- ""+--+normalizeCase :: Domain -> Domain+normalizeCase = BS.map toLower+++-- | 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 ( empty )+-- >>> normalizeRoot BS.empty+-- "."+--+normalizeRoot :: Domain -> Domain+normalizeRoot d+ | BS.null d = trailing_dot+ | BS.last d == '.' = d+ | otherwise = d `BS.append` trailing_dot+ where+ trailing_dot = BS.pack "."
dns.cabal view
@@ -1,5 +1,5 @@ Name: dns-Version: 1.3.0+Version: 1.4.0 Author: Kazu Yamamoto <kazu@iij.ad.jp> Maintainer: Kazu Yamamoto <kazu@iij.ad.jp> License: BSD3@@ -18,6 +18,7 @@ Exposed-Modules: Network.DNS Network.DNS.Lookup Network.DNS.Resolver+ Network.DNS.Utils Network.DNS.Types Network.DNS.Encode Network.DNS.Decode