def run(self): while self.alive: req = self.server.dequeuereq() if req is not None: pkt, sender = req resp = self.server.handle(pkt) if resp is None: resp = proto.responsefor(pkt, proto.SERVFAIL) sender.send(resp)
def handle(self, query, pkt): resp = zone.handle(self, query, pkt) if not "internal" in pkt.flags: if resp is None: resp = proto.responsefor(pkt) soa = zone.handle(self, rec.rrhead(self.origin, "SOA"), pkt) resp.aulist += soa.anlist resp.rescode = proto.NXDOMAIN else: resolver.resolvecnames(resp, self.aurecres) nsrecs = zone.handle(self, rec.rrhead(self.origin, "NS"), pkt) if nsrecs is not None: resp.aulist += nsrecs.anlist for rr in nsrecs.anlist: resolver.resolveadditional(resp, rr, self.aurecres) else: if resp is None: return None resp.setflags(["auth"]) return resp
def resolve(self, packet): res = proto.responsefor(packet) for q in packet.qlist: name = q.name rtype = q.rtype while True: cis = self.getcached(name, rtype) if isinstance(cis, nxdmark): if len(packet.qlist) == 1: res.rescode = proto.NXDOMAIN res.aulist = cis.auth return res continue if len(cis) == 0: cics = self.getcached(name, "CNAME") if isinstance(cics, nxdmark): break if len(cics) > 0: self.addcached(res, cics) name = cics[0][0].data["priname"] continue break if len(cis) == 0: tres = self.dolookup(name, rtype) if isinstance(tres, nxdmark) and len(packet.qlist) == 1: res.rescode = proto.NXDOMAIN res.aulist = tres.auth return res if tres is None and len(packet.qlist) == 1: res.rescode = proto.SERVFAIL return res if tres is not None and tres.rescode == 0: res.merge(tres) else: self.addcached(res, cis) return res
def handle(self, query, pkt, origin): resp = proto.responsefor(pkt) if pkt.opcode == proto.QUERY: rrset = self.db.lookup(query.name) if rrset is None and query.name in origin: rrset = self.db.lookup(query.name - origin) if rrset is None: return None rootify(rrset, origin) resp.anlist = [rr for rr in rrset if rr.head.rtype == query.rtype or rr.head.istype("CNAME")] return resp if pkt.opcode == proto.UPDATE: logger.debug("got DDNS request") if len(pkt.qlist) != 1 or not pkt.qlist[0].istype("SOA"): resp.rescode = proto.FORMERR return resp if pkt.qlist[0].name != origin: resp.rescode = proto.NOTAUTH return resp # Check prerequisites for rr in pkt.anlist: if rr.ttl != 0: resp.rescode = proto.FORMERR return resp if rr.head.name not in origin: resp.rescode = proto.NOTZONE return resp myname = rr.head.name - origin rrset = self.db.lookup(myname) if rr.head.rclass == rec.CLASSANY: if rr.data is not None: resp.rescode = proto.FORMERR return resp if rr.head.rtype == proto.QTANY: if rrset is None: resp.rescode = proto.NXDOMAIN return resp else: if rrset is not None: for rr2 in rrset: if rr2.head.name == myname and rr.head.rtype == rr2.head.rtype: break else: resp.rescode = proto.NXRRSET return resp elif rr.head.rclass == rec.CLASSNONE: if rr.data is not None: resp.rescode = proto.FORMERR return resp if rr.head.rtype == proto.QTANY: if rrset is not None: resp.rescode = proto.YXDOMAIN return resp else: if rrset is not None: for rr2 in rrset: if rr2.head.name == myname and rr.head.rtype == rr2.head.rtype: resp.rescode = proto.YXRRSET return resp elif rr.head.rclass == rec.CLASSIN: if rrset is not None: for rr2 in rrset: if rr2.head.name == myname and rr.head.rtype == rr2.head.rtype and rr.data == rr2.data: break else: resp.rescode = proto.NXRRSET return resp else: resp.rescode = FORMERR return resp # Check for permission if not self.doddns: resp.rescode = proto.REFUSED return resp if type(self.authkeys) == list: if pkt.tsigctx is None: resp.rescode = proto.REFUSED return resp if pkt.tsigctx.error != 0: resp.rescode = proto.NOTAUTH return resp if pkt.tsigctx.key not in self.authkeys: resp.rescode = proto.REFUSED return resp elif type(self.authkeys) == None: authorized = True # Do precheck on updates for rr in pkt.aulist: if rr.head.name not in origin: resp.rescode = proto.NOTZONE return resp if rr.head.rclass == rec.CLASSIN: if rr.head.rtype == proto.QTANY or rr.data is None: resp.rescode = proto.FORMERR return resp elif rr.head.rclass == rec.CLASSANY: if rr.data is not None: resp.rescode = proto.FORMERR return resp elif rr.head.rclass == rec.CLASSNONE: if rr.head.rtype == proto.QTANY or rr.ttl != 0 or rr.data is None: resp.rescode = proto.FORMERR return resp else: resp.rescode = proto.FORMERR return resp # Perform updates for rr in pkt.aulist: myname = rr.head.name - origin if rr.head.rclass == rec.CLASSIN: logger.info("adding rr (%s)", rr) self.db.addrr(myname, rr) elif rr.head.rclass == rec.CLASSANY: if rr.head.rtype == proto.QTANY: logger.info("removing rrset (%s)", rr.head.name) self.db.rmname(myname) else: logger.info("removing rrset (%s, %s)", rr.head.name, rr.head.rtype) self.db.rmrtype(myname, rr.head.rtype) elif rr.head.rclass == rec.CLASSNONE: logger.info("removing rr (%s)", rr) rrset = self.db.lookup(myname) changed = False if rrset is not None: for rr2 in rrset: if rr2.head == rr.head and rr2.data == rr.data: rrset.remove(rr2) changed = True self.db.set(myname, rrset) return resp resp.rescode = proto.NOTIMP return resp