1 module Network.DNS.Named.Zone
21 import qualified Data.Map as M
25 import Network.DNS.Message
26 import Network.DNS.DomainMap
29 class ZoneFinder a where
30 findZone :: a -> DomainName -> IO (Maybe SomeZone)
32 instance ZoneFinder (DomainMap SomeZone) where
33 findZone = (return .) . flip nearest
35 instance ZoneFinder (IO (DomainMap SomeZone)) where
36 findZone = flip (fmap . nearest)
38 instance ZoneFinder (DomainMap (IO SomeZone)) where
40 = do let getZoneM = nearest n m
42 Just getZone -> liftM Just getZone
43 Nothing -> return Nothing
45 instance ZoneFinder (DomainName -> IO (Maybe SomeZone)) where
49 fromZones :: [SomeZone] -> DomainMap SomeZone
50 fromZones = fromList . map toPair
52 toPair z = (zoneName z, z)
56 zoneName :: a -> DomainName
57 getRecordNames :: a -> IO [DomainName]
58 getRecordsForName :: a -> DomainName -> IO [SomeRR]
61 data SomeZone = forall a. Zone a => SomeZone a
63 instance Zone SomeZone where
64 zoneName (SomeZone a) = zoneName a
65 getRecordNames (SomeZone a) = getRecordNames a
66 getRecordsForName (SomeZone a) = getRecordsForName a
72 , ezRecordNames :: !(IO [DomainName])
73 , ezRecordsForName :: !(DomainName -> IO [SomeRR])
75 instance Zone ExternalZone where
77 getRecordNames = ezRecordNames
78 getRecordsForName = ezRecordsForName
84 , dzRecords :: !(IO (Map DomainName [SomeRR]))
86 instance Zone DynamicZone where
88 getRecordNames = liftM M.keys . dzRecords
89 getRecordsForName = flip (fmap . (fromMaybe [] .) . M.lookup) . dzRecords
95 , szRecords :: !(Map DomainName [SomeRR])
99 instance Zone StaticZone where
101 getRecordNames = return . M.keys . szRecords
102 getRecordsForName = ((return . fromMaybe []) .) . flip M.lookup . szRecords
105 fromRecords :: [SomeRR] -> Map DomainName [SomeRR]
106 fromRecords = foldl ins M.empty
109 = case M.lookup (rrName rr) m of
111 -> M.insert (rrName rr) (l ++ [SomeRR rr]) m
113 -> M.insert (rrName rr) [SomeRR rr] m
116 isInZone :: Zone z => DomainName -> z -> Bool
117 isInZone name zone = zoneName zone `isZoneOf` name
120 wrapZone :: Zone z => z -> SomeZone
124 isAuthoritativeZone :: Zone z => z -> IO Bool
125 isAuthoritativeZone z
126 = do let q = Question {
129 , qClass = IN -- Should we consider any classes other than the Internet?
137 getRecords :: (QueryType qt, QueryClass qc, Zone z) =>
142 | cast (qType q) == Just AXFR
146 = do rs <- getRecordsForName z (qName q)
147 return $ filterRecords q rs
151 | qName q == zoneName z
152 = do names <- getRecordNames z
153 (soaM, rs) <- liftM (spitSOA . concat) $ mapM (getRecordsForName z) names
155 Just soa -> return ([soa] ++ rs ++ [soa])
160 spitSOA :: [SomeRR] -> (Maybe SomeRR, [SomeRR])
161 spitSOA xs = (findSOA xs, collectNonSOA xs)
163 findSOA :: [SomeRR] -> Maybe SomeRR
165 findSOA (SomeRR x : xs)
166 | typeOf (rrType x) == typeOf SOA = Just (SomeRR x)
167 | otherwise = findSOA xs
169 collectNonSOA :: [SomeRR] -> [SomeRR]
170 collectNonSOA [] = []
171 collectNonSOA (SomeRR x : xs)
172 | typeOf (rrType x) == typeOf SOA = collectNonSOA xs
173 | otherwise = SomeRR x : collectNonSOA xs
176 filterRecords :: (QueryType qt, QueryClass qc) =>
180 filterRecords q = filter predicate
183 = predForType rr && predForClass rr
185 predForType (SomeRR rr)
186 | typeOf (qType q) == typeOf ANY
189 | typeOf (qType q) == typeOf MAILB
190 = typeOf (rrType rr) == typeOf MR ||
191 typeOf (rrType rr) == typeOf MB ||
192 typeOf (rrType rr) == typeOf MG ||
193 typeOf (rrType rr) == typeOf MINFO
196 = typeOf (rrType rr) == typeOf (qType q) ||
197 typeOf (rrType rr) == typeOf CNAME
199 predForClass (SomeRR rr)
200 | typeOf (qClass q) == typeOf ANY
204 = typeOf (rrClass rr) == typeOf (qClass q)