]> gitweb @ CieloNegro.org - haskell-dns.git/commitdiff
AAAA support
authorPHO <pho@cielonegro.org>
Thu, 28 May 2009 05:18:25 +0000 (14:18 +0900)
committerPHO <pho@cielonegro.org>
Thu, 28 May 2009 05:18:25 +0000 (14:18 +0900)
DNSUnitTest.hs
ExampleDNSServer.hs
Network/DNS/Message.hs
Network/DNS/Named.hs
Network/Socket/IsString.hs [new file with mode: 0644]
dns.cabal

index c3975a4252c044e3bf45e6e70a79847a7006dd13..a77b049a40343cab60e89dbbc1f4170f7fbe229e 100644 (file)
@@ -2,8 +2,7 @@ import           Data.Binary
 import qualified Data.ByteString.Lazy as LBS
 import           Data.Word
 import           Network.DNS.Message
-import           Network.Socket
-import           System.IO.Unsafe
+import           Network.Socket.IsString ()
 import           Test.HUnit
 
 
@@ -27,7 +26,7 @@ messages = [ ( [ 0x22, 0x79, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00
                              }
                , msgQuestions   = [ wrapQuestion $
                                     Question {
-                                      qName  = mkDomainName "mail.cielonegro.org."
+                                      qName  = "mail.cielonegro.org."
                                     , qType  = CNAME
                                     , qClass = IN
                                     }
@@ -62,36 +61,36 @@ messages = [ ( [ 0x22, 0x79, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00
                              }
                , msgQuestions   = [ wrapQuestion $
                                     Question {
-                                      qName  = mkDomainName "mail.cielonegro.org."
+                                      qName  = "mail.cielonegro.org."
                                     , qType  = CNAME
                                     , qClass = IN
                                     }
                                   ]
                , msgAnswers     = [ wrapRecord $
                                     ResourceRecord {
-                                      rrName  = mkDomainName "mail.cielonegro.org."
+                                      rrName  = "mail.cielonegro.org."
                                     , rrType  = CNAME
                                     , rrClass = IN
                                     , rrTTL   = 86400
-                                    , rrData  = mkDomainName "nem.cielonegro.org."
+                                    , rrData  = "nem.cielonegro.org."
                                     }
                                   ]
                , msgAuthorities = [ wrapRecord $
                                     ResourceRecord {
-                                      rrName  = mkDomainName "cielonegro.org."
+                                      rrName  = "cielonegro.org."
                                     , rrType  = NS
                                     , rrClass = IN
                                     , rrTTL   = 3600
-                                    , rrData  = mkDomainName "nem.cielonegro.org."
+                                    , rrData  = "nem.cielonegro.org."
                                     }
                                   ]
                , msgAdditionals = [ wrapRecord $
                                     ResourceRecord {
-                                      rrName  = mkDomainName "nem.cielonegro.org."
+                                      rrName  = "nem.cielonegro.org."
                                     , rrType  = A
                                     , rrClass = IN
                                     , rrTTL   = 3600
-                                    , rrData  = unsafePerformIO (inet_addr "219.94.130.139")
+                                    , rrData  = "219.94.130.139"
                                     }
                                   ]
                }
@@ -114,7 +113,7 @@ messages = [ ( [ 0x22, 0x79, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00
                              }
                , msgQuestions   = [ wrapQuestion $
                                     Question {
-                                      qName  = mkDomainName "cielonegro.org."
+                                      qName  = "cielonegro.org."
                                     , qType  = SOA
                                     , qClass = IN
                                     }
@@ -152,20 +151,20 @@ messages = [ ( [ 0x22, 0x79, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00
                              }
                , msgQuestions   = [ wrapQuestion $
                                     Question {
-                                      qName  = mkDomainName "cielonegro.org."
+                                      qName  = "cielonegro.org."
                                     , qType  = SOA
                                     , qClass = IN
                                     }
                                   ]
                , msgAnswers     = [ wrapRecord $
                                     ResourceRecord {
-                                      rrName  = mkDomainName "cielonegro.org."
+                                      rrName  = "cielonegro.org."
                                     , rrType  = SOA
                                     , rrClass = IN
                                     , rrTTL   = 3600
                                     , rrData  = SOAFields {
-                                                  soaMasterNameServer   = mkDomainName "nem.cielonegro.org."
-                                                , soaResponsibleMailbox = mkDomainName "root.nem.cielonegro.org."
+                                                  soaMasterNameServer   = "nem.cielonegro.org."
+                                                , soaResponsibleMailbox = "root.nem.cielonegro.org."
                                                 , soaSerialNumber       = 2008022148
                                                 , soaRefreshInterval    = 3600
                                                 , soaRetryInterval      = 900
@@ -176,20 +175,20 @@ messages = [ ( [ 0x22, 0x79, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00
                                   ]
                , msgAuthorities = [ wrapRecord $
                                     ResourceRecord {
-                                      rrName  = mkDomainName "cielonegro.org."
+                                      rrName  = "cielonegro.org."
                                     , rrType  = NS
                                     , rrClass = IN
                                     , rrTTL   = 3600
-                                    , rrData  = mkDomainName "nem.cielonegro.org."
+                                    , rrData  = "nem.cielonegro.org."
                                     }
                                   ]
                , msgAdditionals = [ wrapRecord $
                                     ResourceRecord {
-                                      rrName  = mkDomainName "nem.cielonegro.org."
+                                      rrName  = "nem.cielonegro.org."
                                     , rrType  = A
                                     , rrClass = IN
                                     , rrTTL   = 3600
-                                    , rrData  = unsafePerformIO (inet_addr "219.94.130.139")
+                                    , rrData  = "219.94.130.139"
                                     }
                                   ]
                }
index 428f261856dd892fa8d8a2862996239eb8b91f9d..75b261aa9effb9349a6f4e7d9a0f75fd557b5803 100644 (file)
@@ -2,8 +2,7 @@ import           Network.DNS.Message
 import           Network.DNS.Named
 import           Network.DNS.Named.Config
 import           Network.DNS.Named.Zone
-import           Network.Socket
-import           System.IO.Unsafe
+import           Network.Socket.IsString ()
 
 main :: IO ()
 main = runNamed cnf (return . findZone)
@@ -21,55 +20,66 @@ main = runNamed cnf (return . findZone)
 
       zone :: Zone
       zone = Zone {
-               zoneName = mkDN "cielonegro.org."
+               zoneName = "cielonegro.org."
              , zoneSOA  = Just SOAFields {
-                            soaMasterNameServer   = mkDN "ns.cielonegro.org."
-                          , soaResponsibleMailbox = mkDN "root.ns.cielonegro.org."
+                            soaMasterNameServer   = "ns.cielonegro.org."
+                          , soaResponsibleMailbox = "root.ns.cielonegro.org."
                           , soaSerialNumber       = 2008022148
                           , soaRefreshInterval    = 3600
                           , soaRetryInterval      = 900
                           , soaExpirationLimit    = 3600000
                           , soaMinimumTTL         = 3600
                           }
-             , zoneRecordNames = return [ mkDN "ns.cielonegro.org."
-                                        , mkDN "www.cielonegro.org."
-                                        , mkDN "git.cielonegro.org."
+             , zoneRecordNames = return [ "ns.cielonegro.org."
+                                        , "www.cielonegro.org."
+                                        , "git.cielonegro.org."
                                         ]
              , zoneResponder   = return . responder
              }
 
       responder :: DomainName -> [SomeRR]
       responder name
-          | name == mkDN "ns.cielonegro.org."
+          | name == "ns.cielonegro.org."
               = [ wrapRecord ResourceRecord {
                                    rrName  = name
                                  , rrType  = A
                                  , rrClass = IN
                                  , rrTTL   = 9600
-                                 , rrData  = inetAddr "127.0.0.1"
+                                 , rrData  = "127.0.0.1"
+                                 }
+                , wrapRecord ResourceRecord {
+                                   rrName  = name
+                                 , rrType  = AAAA
+                                 , rrClass = IN
+                                 , rrTTL   = 9600
+                                 , rrData  = "::1"
                                  }
                 ]
-          | name == mkDN "www.cielonegro.org."
+          | name == "www.cielonegro.org."
               = [ wrapRecord ResourceRecord {
                                    rrName  = name
                                  , rrType  = A
                                  , rrClass = IN
                                  , rrTTL   = 9600
-                                 , rrData  = inetAddr "127.0.0.2"
+                                 , rrData  = "127.0.0.2"
+                                 }
+                , wrapRecord ResourceRecord {
+                                   rrName  = name
+                                 , rrType  = AAAA
+                                 , rrClass = IN
+                                 , rrTTL   = 9600
+                                 , rrData  = "fe80::216:cbff:fe39:56a4"
                                  }
                 ]
-          | name == mkDN "git.cielonegro.org."
+          | name == "git.cielonegro.org."
               = [ wrapRecord ResourceRecord {
                                    rrName  = name
                                  , rrType  = CNAME
                                  , rrClass = IN
                                  , rrTTL   = 9600
-                                 , rrData  = mkDN "www.cielonegro.org."
+                                 , rrData  = "www.cielonegro.org."
                                  }
                 ]
           | otherwise
               = [] -- This means NXDOMAIN.
 
-
-inetAddr :: String -> HostAddress
-inetAddr = unsafePerformIO . inet_addr
index 9713dd2a707ed66d8776458733401346d7eb2e72..db5016096df79dc83788770b21de2aa014d60f1e 100644 (file)
@@ -23,6 +23,7 @@ module Network.DNS.Message
     , SomeRR(..)
 
     , A(..)
+    , AAAA(..)
     , NS(..)
     , MD(..)
     , MF(..)
@@ -50,7 +51,6 @@ module Network.DNS.Message
     , HS(..)
 
     , mkDomainName
-    , mkDN
     , rootName
     , isRootName
     , consLabel
@@ -73,6 +73,7 @@ import           Data.Binary.Strict.BitGet as BG
 import qualified Data.ByteString as BS
 import qualified Data.ByteString.Char8 as C8 hiding (ByteString)
 import qualified Data.ByteString.Lazy as LBS
+import           Data.String
 import           Data.Typeable
 import qualified Data.IntMap as IM
 import           Data.IntMap (IntMap)
@@ -219,6 +220,9 @@ getSomeQC = do n <- liftM fromIntegral U.getWord16be
 newtype DomainName  = DN [DomainLabel] deriving (Eq, Show, Ord, Typeable)
 type DomainLabel    = BS.ByteString
 
+instance IsString DomainName where
+    fromString = mkDomainName
+
 rootName :: DomainName
 rootName = DN [BS.empty]
 
@@ -252,9 +256,6 @@ mkDomainName = DN . mkLabels [] . notEmpty
                                 -> 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
@@ -529,6 +530,20 @@ instance RecordType A HostAddress where
     putRecordData _ = P.putWord32be
     getRecordData _ = U.getWord32be
 
+data AAAA = AAAA deriving (Show, Eq, Typeable)
+instance RecordType AAAA HostAddress6 where
+    rtToInt       _ = 28
+    putRecordData _ = \ (a, b, c, d) ->
+                      do P.putWord32be a
+                         P.putWord32be b
+                         P.putWord32be c
+                         P.putWord32be d
+    getRecordData _ = do a <- U.getWord32be
+                         b <- U.getWord32be
+                         c <- U.getWord32be
+                         d <- U.getWord32be
+                         return (a, b, c, d)
+
 data NS = NS deriving (Show, Eq, Typeable)
 instance RecordType NS DomainName where
     rtToInt       _ = 2
@@ -847,6 +862,7 @@ instance Enum ResponseCode where
 defaultRTTable :: IntMap SomeRT
 defaultRTTable = IM.fromList $ map toPair $
                  [ SomeRT A
+                 , SomeRT AAAA
                  , SomeRT NS
                  , SomeRT MD
                  , SomeRT MF
index 3d0a6dc7841096ca1803fac1bb0a5c4ef32d6273..57570cfffdc87a39de49cf065571198e08144f9e 100644 (file)
@@ -42,6 +42,7 @@ runNamed cnf findZone
       udpListen :: AddrInfo -> IO ()
       udpListen ai
           = do so <- socket (addrFamily ai) Datagram defaultProtocol
+               setSocketOption so ReuseAddr 1
                bindSocket so (addrAddress ai)
                udpLoop so
 
@@ -54,6 +55,7 @@ runNamed cnf findZone
       tcpListen :: AddrInfo -> IO ()
       tcpListen ai
           = do so <- socket (addrFamily ai) Stream defaultProtocol
+               setSocketOption so ReuseAddr 1
                bindSocket so (addrAddress ai)
                listen so 255
                tcpLoop so
@@ -167,31 +169,46 @@ runNamed cnf findZone
               Just name
                   -> do allRecords <- zoneResponder zone name
 
-                        let filtered = filterRecords (SomeQ q') allRecords
-                            q'       = Question {
-                                         qName  = name
-                                       , qType  = A
-                                       , qClass = IN
-                                       }
-                        return filtered
+                        let rA = filterRecords (SomeQ qA) allRecords
+                            rB = filterRecords (SomeQ qB) allRecords
+                            qA = Question {
+                                   qName  = name
+                                 , qType  = A
+                                 , qClass = IN
+                                 }
+                            qB = Question {
+                                   qName  = name
+                                 , qType  = AAAA
+                                 , qClass = IN
+                                 }
+                        return (rA ++ rB)
 
       filterRecords :: SomeQ -> [SomeRR] -> [SomeRR]
-      filterRecords (SomeQ q)
-          | Just (qType  q) == cast ANY &&
-            Just (qClass q) == cast ANY    = id
-          | Just (qType  q) == cast ANY    = filter matchClass
-          | Just (qClass q) == cast ANY    = filter matchType
-          | otherwise                      = filter matchBoth
+      filterRecords (SomeQ q) = filter predicate
           where
-            matchClass (SomeRR rr)
-                = Just (qClass q) == cast (rrClass rr)
+            predicate rr
+                = predForType rr && predForClass rr
 
-            matchType (SomeRR rr)
-                = Just (qType  q) == cast (rrType  rr) ||
-                  Just CNAME      == cast (rrType  rr)
+            predForType (SomeRR rr)
+                | typeOf (qType q) == typeOf ANY
+                    = True
 
-            matchBoth rr
-                = matchType rr && matchClass rr
+                | typeOf (qType q) == typeOf MAILB
+                    = typeOf (rrType rr) == typeOf MR ||
+                      typeOf (rrType rr) == typeOf MB ||
+                      typeOf (rrType rr) == typeOf MG ||
+                      typeOf (rrType rr) == typeOf MINFO
+
+                | otherwise
+                    = typeOf (rrType rr) == typeOf (qType q) ||
+                      typeOf (rrType rr) == typeOf CNAME
+
+            predForClass (SomeRR rr)
+                | typeOf (qClass q) == typeOf ANY
+                    = True
+
+                | otherwise
+                    = typeOf (rrClass rr) == typeOf (qClass q)
 
       handleAXFR :: SomeQ -> Zone -> IO (Builder ())
       handleAXFR (SomeQ q) zone
diff --git a/Network/Socket/IsString.hs b/Network/Socket/IsString.hs
new file mode 100644 (file)
index 0000000..6ea9f8c
--- /dev/null
@@ -0,0 +1,37 @@
+module Network.Socket.IsString () where
+
+import Data.String
+import Network.Socket
+import System.IO.Unsafe
+
+instance IsString HostAddress where
+    fromString str
+        = let hint = defaultHints {
+                                addrFlags  = [AI_NUMERICHOST]
+                              , addrFamily = AF_INET
+                              }
+              ret  = unsafePerformIO $
+                     getAddrInfo (Just hint) (Just str) Nothing
+          in
+            case ret of
+              []     -> error (str ++ " seems not to be a valid IPv4 address")
+              (x:xs) -> case addrAddress x of
+                          SockAddrInet _ addr
+                              -> addr
+                          _   -> error ("getAddrInfo (" ++ str ++ ") returned a strange result: " ++ show (x:xs))
+
+instance IsString HostAddress6 where
+    fromString str
+        = let hint = defaultHints {
+                                 addrFlags  = [AI_NUMERICHOST]
+                               , addrFamily = AF_INET6
+                               }
+              ret  = unsafePerformIO $
+                     getAddrInfo (Just hint) (Just str) Nothing
+          in
+            case ret of
+              []     -> error (str ++ " seems not to be a valid IPv6 address")
+              (x:xs) -> case addrAddress x of
+                          SockAddrInet6 _ _ addr _
+                              -> addr
+                          _   -> error ("getAddrInfo (" ++ str ++ ") returned a strange result: " ++ show (x:xs))
index cbe24359e8e26237be07b8284e8fe01cfc8f1cc6..2ecda6609a172f3d3b49a5d6865def4c755f6bec 100644 (file)
--- a/dns.cabal
+++ b/dns.cabal
@@ -35,6 +35,7 @@ Library
         Network.DNS.Named.Zone
         Network.DNS.Packer
         Network.DNS.Unpacker
+        Network.Socket.IsString
 
     Extensions:
         DeriveDataTypeable, ExistentialQuantification,
@@ -61,7 +62,7 @@ Executable DNSUnitTest
     Extensions:
         DeriveDataTypeable, ExistentialQuantification,
         FlexibleInstances, FunctionalDependencies,
-        MultiParamTypeClasses, ScopedTypeVariables,
+        MultiParamTypeClasses, OverloadedStrings, ScopedTypeVariables,
         TypeSynonymInstances, UndecidableInstances,
         IncoherentInstances
 
@@ -80,7 +81,7 @@ Executable ExampleDNSServer
     Extensions:
         DeriveDataTypeable, ExistentialQuantification,
         FlexibleInstances, FunctionalDependencies,
-        MultiParamTypeClasses, ScopedTypeVariables,
+        MultiParamTypeClasses, OverloadedStrings, ScopedTypeVariables,
         TypeSynonymInstances, UndecidableInstances,
         IncoherentInstances