From bbeac78d266ec764e66fd1b3fe77ed0ee6085e71 Mon Sep 17 00:00:00 2001 From: Ruakij Date: Mon, 2 Aug 2021 11:28:21 +0200 Subject: [PATCH] Initial script --- daemon.py | 102 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 102 insertions(+) create mode 100755 daemon.py diff --git a/daemon.py b/daemon.py new file mode 100755 index 0000000..20dae36 --- /dev/null +++ b/daemon.py @@ -0,0 +1,102 @@ +#!/usr/bin/python3 + +import os, subprocess, socket, datetime, getopt, sys, re, atexit, logging as log + +import dns.flags +import dns.message +import dns.rdataclass +import dns.rdatatype +import dns.name + +from typing import cast + + +def main(args): + setupLogging(True) + log.debug("Logging started") + + s = setupSocket('172.17.0.1', 53) + + startListen(s) + +def setupSocket(address, port): + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + s.bind((address, port)) + return s + +def startListen(s): + log.debug('Now listening') + while True: + (address, dmsg) = receiveFromWire(s) + + if handleQuery(s, address, dmsg) != True: + continue + +def receiveFromWire(s): + (wire, address) = s.recvfrom(512) + dmsg = dns.message.from_wire(wire) + return (address, dmsg) + +def handleQuery(s, address, dmsg): + log.info(f'{address[0]} |\tGot query') + + opcode = dmsg.opcode() + if opcode != dns.opcode.NOTIFY: + log.error(f"{address[0]} |\tExpected opcode=NOTIFY, but was {dns.opcode.to_text(opcode)}") + makeResponseWithRCode(s, address, dmsg, dns.rcode.REFUSED) + return False + + rcode = dmsg.rcode() + if rcode != dns.rcode.NOERROR: + log.error(f"{address[0]} |\tExpected rcode=NOERROR, but was {dns.rcode.to_text(rcode)}") + makeResponseWithRCode(s, address, dmsg, dns.rcode.FORMERR) + return False + + #flags = dmsg.flags + #if flags != dns.flags.AA: + # print('Expected flags=AA, but was', dns.flags.to_text(flags)) + # continue + + if len(dmsg.question) != 1: + log.error(f'{address[0]} |\tExpected question-len=1, but was {len(dmsg.question)}') + makeResponseWithRCode(s, address, dmsg, dns.rcode.FORMERR) + return False + + # Check record in question + record = dmsg.question[0] + + r_datatype = record.rdtype; + if r_datatype != dns.rdatatype.SOA: + log.error(f'{address[0]} |\tExpected record to be SOA, but was {r_datatype}') + makeResponseWithRCode(s, address, dmsg, dns.rcode.FORMERR) + return False + + log.info(f'{address[0]} |\tNOTIFY for {record.name}') + + response = dns.message.make_response(dmsg) # type: dns.message.Message + response.flags |= dns.flags.AA + sendResponse(s, address, response) + log.debug(f'{address[0]} |\tSent response') + + return True + +def makeResponseWithRCode(socket, address, dmsg, rcode): + response = dns.message.make_response(dmsg) # type: dns.message.Message + response.set_rcode(rcode) + sendResponse(socket, address, response) + +def sendResponse(socket, address, response): + wire = response.to_wire(cast(dns.name.Name, response)) + socket.sendto(wire, address) + +def setupLogging(verbose: bool): + level = log.INFO + format = '%(asctime)s %(levelname)s:\t%(message)s' + + if verbose: + level = log.DEBUG + + log.basicConfig(stream=sys.stdout, format=format, level=level) + +if __name__ == "__main__": + sys.exit(main(sys.argv))