dns 2.0.8 → 2.0.9
raw patch · 7 files changed
+99/−21 lines, 7 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
+ Network.DNS.Decode: receiveVC :: Socket -> IO DNSMessage
+ Network.DNS.Encode: encodeVC :: ByteString -> ByteString
Files
- Changelog +2/−0
- Network/DNS/Decode.hs +16/−1
- Network/DNS/Encode.hs +6/−0
- Network/DNS/Internal.hs +2/−3
- Network/DNS/Lookup.hs +13/−6
- Network/DNS/Resolver.hs +59/−10
- dns.cabal +1/−1
Changelog view
@@ -1,3 +1,5 @@+2.0.9+ - Implemented TCP fallback after a truncated UDP response. [#46](https://github.com/kazu-yamamoto/dns/pull/46) 2.0.8 - Better handling of encoding and decoding the "root" domain ".". [#45](https://github.com/kazu-yamamoto/dns/pull/45) 2.0.7
Network/DNS/Decode.hs view
@@ -4,6 +4,7 @@ decode , decodeMany , receive+ , receiveVC ) where import Control.Applicative (many)@@ -15,8 +16,9 @@ import qualified Data.ByteString as B import qualified Data.ByteString.Char8 as BS import qualified Data.ByteString.Lazy as BL-import Data.Conduit (($$), Source)+import Data.Conduit (($$), ($$+), ($$+-), (=$), Source) import Data.Conduit.Network (sourceSocket)+import qualified Data.Conduit.Binary as CB import Data.IP (IP(..), toIPv4, toIPv6b) import Data.Typeable (Typeable) import Data.Word (Word16)@@ -42,6 +44,19 @@ receive :: Socket -> IO DNSMessage receive = receiveDNSFormat . sourceSocket++-- | Receive and parse a single virtual-circuit (TCP) response. It+-- is up to the caller to implement any desired timeout. This+-- (and the other response decoding functions) may throw ParseError+-- when the server response is incomplete or malformed.++receiveVC :: Socket -> IO DNSMessage+receiveVC sock = runResourceT $ do+ (src, lenbytes) <- sourceSocket sock $$+ CB.take 2+ let len = case (map fromIntegral $ BL.unpack lenbytes) of+ hi:lo:[] -> 256 * hi + lo+ _ -> 0+ src $$+- CB.isolate len =$ sinkSGet decodeResponse >>= return . fst ----------------------------------------------------------------
Network/DNS/Encode.hs view
@@ -2,6 +2,7 @@ module Network.DNS.Encode ( encode+ , encodeVC , composeQuery , composeQueryAD ) where@@ -60,6 +61,11 @@ encode :: DNSMessage -> ByteString encode msg = runSPut (encodeDNSMessage msg)++encodeVC :: ByteString -> ByteString+encodeVC query =+ let len = BB.toLazyByteString $ BB.int16BE $ fromIntegral $ BL.length query+ in len <> query ----------------------------------------------------------------
Network/DNS/Internal.hs view
@@ -115,9 +115,8 @@ -- | The name server was unable to process this query due to a -- problem with the name server. | ServerFailure- -- | Meaningful only for responses from an authoritative name- -- server, this code signifies that the- -- domain name referenced in the query does not exist.+ -- | This code signifies that the domain name referenced in the+ -- query does not exist. | NameError -- | The name server does not support the requested kind of query. | NotImplemented
Network/DNS/Lookup.hs view
@@ -373,8 +373,9 @@ ---------------------------------------------------------------- --- | Look up all \'SRV\' records for the given hostname. A SRV record--- comprises four fields,+-- | 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) --@@ -391,12 +392,18 @@ -- -- Examples: ----- >>> let hostname = Data.ByteString.Char8.pack "_sip._tcp.cisco.com"+-- >>> let q = Data.ByteString.Char8.pack "_xmpp-server._tcp.jabber.ietf.org" -- >>> -- >>> rs <- makeResolvSeed defaultResolvConf--- >>> withResolver rs $ \resolver -> lookupSRV resolver hostname--- Right [(1,0,5060,"vcsgw.cisco.com.")]---+-- >>> withResolver rs $ \resolver -> lookupSRV resolver q+-- Right [(5,0,5269,"jabber.ietf.org.")]++-- Though the "jabber.ietf.orgs" SRV record may prove reasonably stable, as+-- with anything else published in DNS it is subject to change. Also, this+-- example only works when connected to the Internet. Perhaps the above+-- example should be displayed in a format that is not recognized as a test+-- by "doctest".+ lookupSRV :: Resolver -> Domain -> IO (Either DNSError [(Int,Int,Int,Domain)]) lookupSRV rlv dom = do erds <- DNS.lookup rlv dom SRV
Network/DNS/Resolver.hs view
@@ -28,8 +28,11 @@ import Network.DNS.Encode import Network.DNS.Internal import qualified Data.ByteString.Char8 as BS-import Network.Socket (HostName, Socket, SocketType(Datagram), close, socket, connect)-import Network.Socket (AddrInfoFlag(..), AddrInfo(..), SockAddr(..), PortNumber(..), defaultHints, getAddrInfo)+import Network.Socket (HostName, Socket, SocketType(Stream, Datagram))+import Network.Socket (AddrInfoFlag(..), AddrInfo(..), SockAddr(..))+import Network.Socket (Family(AF_INET, AF_INET6), PortNumber(..))+import Network.Socket (close, socket, connect, getPeerName, getAddrInfo)+import Network.Socket (defaultHints, defaultProtocol) import Prelude hiding (lookup) import System.Random (getStdRandom, randomR) import System.Timeout (timeout)@@ -267,10 +270,14 @@ lookupAuth = lookupSection authority --- | Look up a name and return the entire DNS Response. Sample output--- is included below, however it is /not/ tested -- the sequence--- number is unpredictable (it has to be!).+-- | Look up a name and return the entire DNS Response. If the+-- initial UDP query elicits a truncated answer, the query is+-- retried over TCP. The TCP retry may extend the total time+-- taken by one more timeout beyond timeout * tries. --+-- Sample output is included below, however it is /not/ tested+-- the sequence number is unpredictable (it has to be!).+-- -- The example code: -- -- @@@ -310,10 +317,30 @@ lookupRaw :: Resolver -> Domain -> TYPE -> IO (Either DNSError DNSMessage) lookupRaw = lookupRawInternal receive False +-- | Same as lookupRaw, but the query sets the AD bit, which solicits the+-- the authentication status in the server reply. In most applications+-- (other than diagnostic tools) that want authenticated data It is+-- unwise to trust the AD bit in the responses of non-local servers, this+-- interface should in most cases only be used with a loopback resolver.+-- lookupRawAD :: Resolver -> Domain -> TYPE -> IO (Either DNSError DNSMessage) lookupRawAD = lookupRawInternal receive True -+-- Lookup loop, we try UDP until we get a response. If the response+-- is truncated, we try TCP once, with no further UDP retries.+-- EDNS0 support would significantly reduce the need for TCP retries.+--+-- For now, we optimize for low latency high-availability caches+-- (e.g. running on a loopback interface), where TCP is cheap+-- enough. We could attempt to complete the TCP lookup within the+-- original time budget of the truncated UDP query, by wrapping both+-- within a a single 'timeout' thereby staying within the original+-- time budget, but it seems saner to give TCP a full opportunity to+-- return results. TCP latency after a truncated UDP reply will be+-- atypical.+--+-- Future improvements might also include support for TCP on the+-- initial query, and of course support for multiple nameservers. lookupRawInternal :: (Socket -> IO DNSMessage)@@ -342,15 +369,37 @@ Nothing -> loop query checkSeqno (cnt + 1) False Just res -> do let valid = checkSeqno res- if valid then- return $ Right res- else- loop query checkSeqno (cnt + 1) False+ case valid of+ False -> loop query checkSeqno (cnt + 1) False+ True | False <- trunCation $ flags $ header res+ -> return $ Right res+ _ -> tcpRetry query sock = dnsSock rlv tm = dnsTimeout rlv retry = dnsRetry rlv q = makeQuestion dom typ check seqno res = identifier (header res) == seqno+ tcpRetry query = do+ peer <- getPeerName sock+ bracket (tcpOpen peer)+ (maybe (return ()) close)+ (tcpLookup query peer)+ tcpOpen peer = do+ case (peer) of+ SockAddrInet _ _ ->+ socket AF_INET Stream defaultProtocol >>= return . Just+ SockAddrInet6 _ _ _ _ ->+ socket AF_INET6 Stream defaultProtocol >>= return . Just+ _ -> return Nothing -- Only IPv4 and IPv6 are possible+ tcpLookup _ _ Nothing = return $ Left ServerFailure -- can't happen+ tcpLookup query peer (Just vc) = do+ response <- timeout tm $ do+ connect vc $ peer+ sendAll vc $ encodeVC query+ receiveVC vc+ case response of+ Nothing -> return $ Left TimeoutExpired+ Just res -> return $ Right res #if mingw32_HOST_OS == 1 -- Windows does not support sendAll in Network.ByteString.Lazy.
dns.cabal view
@@ -1,5 +1,5 @@ Name: dns-Version: 2.0.8+Version: 2.0.9 Author: Kazu Yamamoto <kazu@iij.ad.jp> Maintainer: Kazu Yamamoto <kazu@iij.ad.jp> License: BSD3