import Network.DNS.Message
import Network.DNS.Named
import Network.DNS.Named.Config
+import Network.DNS.Named.Responder
import Network.DNS.Named.Zone
import Network.Socket
+import System.IO.Unsafe
main :: IO ()
main = runNamed cnf zoneFor
}
zoneFor :: DomainName -> Maybe Zone
- zoneFor = const Nothing -- FIXME
\ No newline at end of file
+ zoneFor name
+ | name `isInZone` zone = Just zone
+ | otherwise = Nothing
+
+ zone :: Zone
+ zone = Zone {
+ zoneName = mkDN "cielonegro.org."
+ , zoneResponders = [ wrapResponder' $
+ do name <- getQueryName
+ if name == mkDN "ns.cielonegro.org." then
+ respond ResourceRecord {
+ rrName = name
+ , rrType = A
+ , rrClass = IN
+ , rrTTL = 9600
+ , rrData = inetAddr "127.0.0.1"
+ }
+ else
+ fail "FIXME: we want to throw NameError but we can't for now"
+ ]
+ , zoneIsAuthoritative = True
+ }
+
+ wrapResponder' :: Responder A IN () -> SomeResponder
+ wrapResponder' = wrapResponder
+
+
+inetAddr :: String -> HostAddress
+inetAddr = unsafePerformIO . inet_addr
, HS(..)
, mkDomainName
+ , mkDN
+ , isZoneOf
+
, wrapQuestion
, wrapRecord
)
import Data.IntMap (IntMap)
import qualified Data.IntSet as IS
import Data.IntSet (IntSet)
+import Data.List
import qualified Data.Map as M
import Data.Map (Map)
import Data.Word
unconsLabel (DN (x:xs)) = (x, DN xs)
unconsLabel x = error ("Illegal use of unconsLabel: " ++ show x)
+isZoneOf :: DomainName -> DomainName -> Bool
+isZoneOf (DN a) (DN b) = a `isSuffixOf` b
+
mkDomainName :: String -> DomainName
mkDomainName = DN . mkLabels [] . notEmpty
where
-> mkLabels (C8.pack l : soFar) rest
_ -> error ("Illegal domain name: " ++ xs)
+mkDN :: String -> DomainName
+mkDN = mkDomainName
+
class (Show rc, Eq rc, Typeable rc) => RecordClass rc where
rcToInt :: rc -> Int
-- 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
+ return $ do mapM_ addAnswer $ concat results
+ unless (zoneIsAuthoritative zone) $
+ unauthorise
validateQuery :: Message -> ResponseCode
import Network.DNS.Named.Sanity
-data ResponderState qt qc
+data (QueryType qt, QueryClass qc) => ResponderState qt qc
= ResponderState {
rsQuestion :: !(Question qt qc)
, rsAnswers :: ![SomeRR]
}
deriving Typeable
-instance (RecordType qt dt, RecordClass qc) => Monad (Responder qt qc) where
+instance (QueryType qt, QueryClass qc) => Monad (Responder qt qc) where
return a = Responder $ \ s -> return (a, s)
m >>= k = Responder $ \ s -> do (a, s') <- unR m s
unR (k a) s'
fail err = Responder $ \ _ -> fail err
-instance (RecordType qt dt, RecordClass qc) => MonadIO (Responder qt qc) where
+instance (QueryType qt, QueryClass qc) => MonadIO (Responder qt qc) where
liftIO m = Responder $ \ s -> do a <- m
return (a, s)
Just m
-> runResponder q m
-getQuestion :: (RecordType qt dt, RecordClass qc) => Responder qt qc (Question qt qc)
+getQuestion :: (QueryType qt, QueryClass qc) => Responder qt qc (Question qt qc)
getQuestion = Responder $ \ s ->
return (rsQuestion s, s)
-getQueryName :: (RecordType qt dt, RecordClass qc) => Responder qt qc DomainName
+getQueryName :: (QueryType qt, QueryClass qc) => Responder qt qc DomainName
getQueryName = liftM qName getQuestion
respond :: ( SaneAnswerType qt at, SaneAnswerClass qc ac
, QueryType qt, RecordType at dt
- , RecordClass qc, RecordClass ac
+ , QueryClass qc, RecordClass ac
) =>
ResourceRecord at ac dt
-> Responder qt qc ()
data SomeResponder
= forall qt qc. (Typeable qt, Typeable qc) => SomeResponder (Responder qt qc ())
-wrapResponder :: (RecordType qt dt, RecordClass qc) =>
+wrapResponder :: (QueryType qt, QueryClass qc) =>
Responder qt qc a
-> SomeResponder
wrapResponder m
( Zone(..)
, ZoneFinder(..)
+ , isInZone
+
, defaultRootZone
)
where
data Zone
= Zone {
- zoneName :: !DomainName
- , zoneResponders :: ![SomeResponder]
+ zoneName :: !DomainName
+ , zoneResponders :: ![SomeResponder]
+ , zoneIsAuthoritative :: !Bool
}
class ZoneFinder a where
findZone = (fmap (fromMaybe defaultRootZone) .)
+isInZone :: DomainName -> Zone -> Bool
+isInZone name zone = zoneName zone `isZoneOf` name
+
+
defaultRootZone :: Zone
defaultRootZone
= Zone {
- zoneName = mkDomainName "."
- , zoneResponders = [] -- FIXME
+ zoneName = mkDomainName "."
+ , zoneResponders = [] -- FIXME
+ , zoneIsAuthoritative = False
}