diff options
Diffstat (limited to 'app/BahnhofDNS.hs')
| -rw-r--r-- | app/BahnhofDNS.hs | 59 |
1 files changed, 59 insertions, 0 deletions
diff --git a/app/BahnhofDNS.hs b/app/BahnhofDNS.hs new file mode 100644 index 0000000..2111aa0 --- /dev/null +++ b/app/BahnhofDNS.hs @@ -0,0 +1,59 @@ + +module Main where + +import Data.ByteString +import Data.Text +import Data.Text.Encoding as TSE +import Network.DNS +import Network.Socket +import Util + +main :: IO () +main = do -- general structure like sample code at https://book.realworldhaskell.org/read/sockets-and-syslog.html (for UDP server) + staticData <- readData + addr : _ <- getAddrInfo (Just defaultHints { addrSocketType = Datagram, addrFamily = AF_INET6, addrFlags = [AI_PASSIVE] }) Nothing (Just "5300") + sckt <- openSocket addr + bind sckt (addrAddress addr) + putStrLn "Starting DNS server (listening on port 5300)" + procMessages staticData sckt + where + procMessages staticData sckt = do + (m,ad) <- receiveFrom sckt -- Network.DNS + + sendTo sckt (response m) ad + procMessages staticData sckt + where + response m = encode $ case (question m) of + (Question qh TXT) : _ -> queryAnswer (uid m) qh + _ -> m -- ping back question without answering it + -- no other way to generate empty responses without providing a question in this library? + + queryAnswer oid qh = case maybeAnswer qh of + Just answer -> responseTXT oid (Question qh TXT) (TSE.encodeUtf8 answer) + Nothing -> responseEmpty oid (Question qh TXT) + + uid msg = identifier (header msg) + maybeAnswer qh = case queryFromQuestionHead qh of + (q, "RIL100") -> lookupCode (Ril100 q) (ril100map staticData) + (q, "LEITPUNKT") -> lookupName q (leitpunktMap staticData) + >>= (`lookupCode` (ril100map staticData)) + (_, _) -> Nothing + +queryFromQuestionHead :: ByteString -> (Text, String) +queryFromQuestionHead q = case splt of + quest : questType : _ -- here we could add enforcement that we only query the intended namespace and not arbitrary subspaces (nsst.ril100.a.b.c.d.e.…) + -> (quest, Data.Text.unpack questType) + _ -> (Data.Text.empty, "") -- side question: is a query without a dot even a legal DNS query? + where + splt = splitOn dot (toUpper $ TSE.decodeUtf8 q) + dot = Data.Text.pack "." + +responseEmpty :: Identifier -> Question -> DNSMessage +responseEmpty idt q = makeResponse idt q [] + +responseTXT :: Identifier -> Question -> ByteString -> DNSMessage +responseTXT idt q txt = makeResponse idt q [ans] + where + dom = qname q + ans = ResourceRecord dom TXT classIN 604800 (RD_TXT txt) + |
