From: Kees Monshouwer Date: Sun, 3 Mar 2013 20:56:49 +0000 (+0100) Subject: improve IXFR to AXFR fallback X-Git-Tag: rec-3.6.0-rc1~257^2 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=6e59a58062cad0043aa36e35997b454f16c28b2f;p=pdns improve IXFR to AXFR fallback --- diff --git a/pdns/tcpreceiver.cc b/pdns/tcpreceiver.cc index 7d3b705c9..0aa570bdf 100644 --- a/pdns/tcpreceiver.cc +++ b/pdns/tcpreceiver.cc @@ -286,9 +286,15 @@ void *TCPNameserver::doConnection(void *data) if(packet->parse(mesg, pktlen)<0) break; - if(packet->qtype.getCode()==QType::AXFR || packet->qtype.getCode()==QType::IXFR ) { - if(doAXFR(packet->qdomain, packet, fd)) - S.inc("tcp-answers"); + if(packet->qtype.getCode()==QType::AXFR) { + if(doAXFR(packet->qdomain, packet, fd)) + S.inc("tcp-answers"); + continue; + } + + if(packet->qtype.getCode()==QType::IXFR) { + if(doIXFR(packet, fd)) + S.inc("tcp-answers"); continue; } @@ -834,6 +840,130 @@ int TCPNameserver::doAXFR(const string &target, shared_ptr q, int out return 1; } +int TCPNameserver::doIXFR(shared_ptr q, int outsock) +{ + shared_ptr outpacket=getFreshAXFRPacket(q); + if(q->d_dnssecOk) + outpacket->d_dnssecOk=true; // RFC 5936, 2.2.5 'SHOULD' + + DNSSECKeeper dk; + NSEC3PARAMRecordContent ns3pr; + bool narrow; + bool NSEC3Zone=false; + + dk.clearCaches(q->qdomain); + bool securedZone = dk.isSecuredZone(q->qdomain); + if(dk.getNSEC3PARAM(q->qdomain, &ns3pr, &narrow)) { + NSEC3Zone=true; + if(narrow) { + L<qdomain<<"' denied to "<getRemote()<setRcode(RCode::Refused); + sendPacket(outpacket,outsock); + return 0; + } + } + + uint32_t serial = 0; + MOADNSParser mdp(q->getString()); + for(MOADNSParser::answers_t::const_iterator i=mdp.d_answers.begin(); i != mdp.d_answers.end(); ++i) { + const DNSRecord *rr = &i->first; + if (rr->d_type == QType::SOA && rr->d_place == DNSRecord::Nameserver) { + vectorparts; + stringtok(parts, rr->d_content->getZoneRepresentation()); + if (parts.size() >= 3) { + serial=atoi(parts[2].c_str()); + } else { + L<setRcode(RCode::FormErr); + sendPacket(outpacket,outsock); + return 0; + } + } else { + L<setRcode(RCode::FormErr); + sendPacket(outpacket,outsock); + return 0; + } + } + + L<qdomain<<"' initiated by "<getRemote()<<" with serial "<getBackend()->getSOA(q->qdomain, sd)) { + L<qdomain<<"' failed: not authoritative"<setRcode(9); // 'NOTAUTH' + sendPacket(outpacket,outsock); + return 0; + } + } + + string target = q->qdomain; + + UeberBackend db; + sd.db=(DNSBackend *)-1; // force uncached answer + if(!db.getSOA(target, sd)) { + L<setRcode(9); // 'NOTAUTH' + sendPacket(outpacket,outsock); + return 0; + } + + if(!sd.db || sd.db==(DNSBackend *)-1) { + L<setRcode(RCode::ServFail); + sendPacket(outpacket,outsock); + return 0; + } + if (!rfc1982LessThan(serial, sd.serial)) { + TSIGRecordContent trc; + string tsigkeyname, tsigsecret; + + q->getTSIGDetails(&trc, &tsigkeyname, 0); + + if(!tsigkeyname.empty()) { + string tsig64, algorithm; + Lock l(&s_plock); + s_P->getBackend()->getTSIGKey(tsigkeyname, &algorithm, &tsig64); + B64Decode(tsig64, tsigsecret); + } + + UeberBackend signatureDB; + + // SOA *must* go out first, our signing pipe might reorder + DLOG(L<<"Sending out SOA"<addRecord(soa); + editSOA(dk, sd.qname, outpacket.get()); + if(securedZone) { + set authSet; + authSet.insert(target); + addRRSigs(dk, signatureDB, authSet, outpacket->getRRS()); + } + + if(!tsigkeyname.empty()) + outpacket->setTSIGDetails(trc, tsigkeyname, tsigsecret, trc.d_mac); // first answer is 'normal' + + sendPacket(outpacket, outsock); + + L<getRemote()<<" finished"<qdomain, q, outsock); +} + TCPNameserver::~TCPNameserver() { delete d_connectionroom_sem; diff --git a/pdns/tcpreceiver.hh b/pdns/tcpreceiver.hh index b58a474d4..d26b1b619 100644 --- a/pdns/tcpreceiver.hh +++ b/pdns/tcpreceiver.hh @@ -53,6 +53,7 @@ private: static int readLength(int fd, ComboAddress *remote); static void getQuestion(int fd, char *mesg, int pktlen, const ComboAddress& remote); static int doAXFR(const string &target, boost::shared_ptr q, int outsock); + static int doIXFR(boost::shared_ptr q, int outsock); static bool canDoAXFR(boost::shared_ptr q); static void *doConnection(void *data); static void *launcher(void *data);