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
handleMessage msg
= case validateQuery msg of
NoError
- -> fail "FIXME: not impl" -- msgQuestions msg
+ -> 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 [SomeRR]
+ handleQuestion :: SomeQ -> IO (Builder ())
handleQuestion (SomeQ q)
- = do zone <- findZone zf (qName q)
- results <- mapM (runResponder' q) (zoneResponders zone)
- return $ concat results
+ = 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 $ mapM_ addAnswer $ concat results
validateQuery :: Message -> ResponseCode
--- /dev/null
+module Network.DNS.Named.ResponseBuilder
+ ( Builder
+
+ , runBuilder
+
+ , unauthorise
+ , addAnswer
+ , addAuthority
+ , addAdditional
+ )
+ where
+
+import Control.Monad
+import Network.DNS.Message
+
+
+newtype Builder a = B { unB :: Message -> (a, Message) }
+
+instance Monad Builder where
+ return a = B $ \ s -> (a, s)
+ m >>= k = B $ \ s -> let (a, s') = unB m s
+ in
+ unB (k a) s'
+ fail err = B $ error err
+
+
+runBuilder :: Message -> Builder () -> Message
+runBuilder query builder
+ = let initialReply = query {
+ msgAnswers = []
+ , msgAuthorities = []
+ , msgAdditionals = []
+ }
+ modHeader' = modifyHeader $
+ \ h -> h {
+ hdMessageType = Response
+ , hdIsAuthoritativeAnswer = True
+ , hdIsTruncated = False
+ , hdIsRecursionAvailable = False
+ , hdResponseCode = NoError
+ }
+ (_, result) = unB (modHeader' >> builder) initialReply
+ in
+ result
+
+get :: (Message -> a) -> Builder a
+get f = B $ \ s -> (f s, s)
+
+modify :: (Message -> Message) -> Builder ()
+modify f = B $ \ s -> ((), f s)
+
+modifyHeader :: (Header -> Header) -> Builder ()
+modifyHeader f
+ = modify $ \ s -> s { msgHeader = f (msgHeader s) }
+
+addAnswer :: SomeRR -> Builder ()
+addAnswer rr
+ = do anss <- get msgAnswers
+ unless (any (== rr) anss)
+ $ modify $ \ s ->
+ s { msgAnswers = msgAnswers s ++ [rr] }
+
+addAuthority :: SomeRR -> Builder ()
+addAuthority rr
+ = do anss <- get msgAnswers
+ aths <- get msgAuthorities
+ unless (any (== rr) anss || any (== rr) aths)
+ $ modify $ \ s ->
+ s { msgAuthorities = msgAuthorities s ++ [rr] }
+
+addAdditional :: SomeRR -> Builder ()
+addAdditional rr
+ = do anss <- get msgAnswers
+ aths <- get msgAuthorities
+ adds <- get msgAdditionals
+ unless (any (== rr) anss || any (== rr) aths || any (== rr) adds)
+ $ modify $ \ s ->
+ s { msgAdditionals = msgAdditionals s ++ [rr] }
+
+unauthorise :: Builder ()
+unauthorise = modifyHeader (\ h -> h { hdIsAuthoritativeAnswer = False })