X-Git-Url: http://git.cielonegro.org/gitweb.cgi?a=blobdiff_plain;f=Network%2FDNS%2FNamed.hs;h=dbe8e71c2865f135ac93d41d2439e3f4bf16d0e5;hb=d24a461f09bd10e3fe148e3b6b86c8e861b09a43;hp=13297e8ae2fbbb2bf31051255ebe23ecd8bb5d8b;hpb=5d250da422c01c7aab948ebdda5ef618f18e0f39;p=haskell-dns.git diff --git a/Network/DNS/Named.hs b/Network/DNS/Named.hs index 13297e8..dbe8e71 100644 --- a/Network/DNS/Named.hs +++ b/Network/DNS/Named.hs @@ -1,10 +1,5 @@ module Network.DNS.Named - ( ZoneFinder(..) - , Zone(..) - - , runNamed - - , defaultRootZone + ( runNamed ) where @@ -19,34 +14,12 @@ import Network.Socket import qualified Network.Socket.ByteString as NB import Network.DNS.Message import Network.DNS.Named.Config +import Network.DNS.Named.Responder +import Network.DNS.Named.ResponseBuilder +import Network.DNS.Named.Zone import System.Posix.Signals -class ZoneFinder a where - findZone :: a -> DomainName -> IO Zone - -instance ZoneFinder (DomainName -> Zone) where - findZone = (return .) - -instance ZoneFinder (DomainName -> IO Zone) where - findZone = id - -instance ZoneFinder (DomainName -> Maybe Zone) where - findZone = ((return . fromMaybe defaultRootZone) .) - -instance ZoneFinder (DomainName -> IO (Maybe Zone)) where - findZone = (fmap (fromMaybe defaultRootZone) .) - - -data Zone - = Zone { - zoneName :: !DomainName - } - -defaultRootZone :: Zone -defaultRootZone = error "FIXME: defaultRootZone is not implemented yet" - - runNamed :: ZoneFinder zf => Config -> zf -> IO () runNamed cnf zf = withSocketsDo $ @@ -75,24 +48,98 @@ runNamed cnf zf = do msg <- evaluate $ unpackMessage packet msg' <- handleMessage msg `onException` - NB.sendTo so (packMessage $ makeServerFailure msg) cameFrom - _sent <- NB.sendTo so (packMessage $ msg' ) cameFrom + do let servfail = mkErrorReply ServerFailure msg + NB.sendTo so (packMessage (Just 512) servfail) cameFrom + _sent <- NB.sendTo so (packMessage (Just 512) msg') cameFrom return () handleMessage :: Message -> IO Message handleMessage msg - = fail (show msg) -- FIXME + = case validateQuery msg of + NoError + -> do builders <- mapM handleQuestion $ msgQuestions msg + + let builder = foldl (>>) (return ()) builders + msg' = runBuilder msg builder + + return msg' + + err -> return $ mkErrorReply err msg + + handleQuestion :: SomeQ -> IO (Builder ()) + handleQuestion (SomeQ q) + = do zone <- findZone zf (qName q) + -- FIXME: this is merely a bogus implementation. + -- It considers no additional or authoritative sections. + results <- mapM (runResponder' q) (zoneResponders zone) + return $ do mapM_ addAnswer $ concat results + unless (zoneIsAuthoritative zone) $ + unauthorise -packMessage :: Message -> BS.ByteString -packMessage = BS.concat . LBS.toChunks . encode +validateQuery :: Message -> ResponseCode +validateQuery = validateHeader . msgHeader + where + validateHeader :: Header -> ResponseCode + validateHeader hdr + | hdMessageType hdr /= Query = NotImplemented + | hdOpcode hdr /= StandardQuery = NotImplemented + | otherwise = NoError + + +packMessage :: Maybe Int -> Message -> BS.ByteString +packMessage limM = BS.concat . LBS.toChunks . truncateMsg + where + truncateMsg :: Message -> LBS.ByteString + truncateMsg msg + = let packet = encode msg + needTrunc = fromMaybe False $ + do lim <- limM + return $ fromIntegral (LBS.length packet) > lim + in + if needTrunc then + truncateMsg $ trunc' msg + else + packet + + trunc' :: Message -> Message + trunc' msg + | notNull $ msgAdditionals msg + = msg { + msgAdditionals = truncList $ msgAdditionals msg + } + | notNull $ msgAuthorities msg + = msg { + msgHeader = setTruncFlag $ msgHeader msg + , msgAuthorities = truncList $ msgAuthorities msg + } + | notNull $ msgAnswers msg + = msg { + msgHeader = setTruncFlag $ msgHeader msg + , msgAnswers = truncList $ msgAnswers msg + } + | notNull $ msgQuestions msg + = msg { + msgHeader = setTruncFlag $ msgHeader msg + , msgQuestions = truncList $ msgQuestions msg + } + | otherwise + = error ("packMessage: You are already skinny and need no diet: " ++ show msg) + + setTruncFlag :: Header -> Header + setTruncFlag hdr = hdr { hdIsTruncated = True } + + notNull :: [a] -> Bool + notNull = not . null + + truncList :: [a] -> [a] + truncList xs = take (length xs - 1) xs unpackMessage :: BS.ByteString -> Message unpackMessage = decode . LBS.fromChunks . return - -makeServerFailure :: Message -> Message -makeServerFailure msg +mkErrorReply :: ResponseCode -> Message -> Message +mkErrorReply err msg = let header = msgHeader msg msg' = msg { msgHeader = header { @@ -100,7 +147,7 @@ makeServerFailure msg , hdIsAuthoritativeAnswer = False , hdIsTruncated = False , hdIsRecursionAvailable = False - , hdResponseCode = ServerFailure + , hdResponseCode = err } } in