Example #1
0
 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)
Example #2
0
 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
Example #3
0
 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
Example #4
0
    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