From 35fe50c367907ba0c2978b8d5b5d45de38a98982 Mon Sep 17 00:00:00 2001 From: Bert Hubert Date: Wed, 21 Apr 2010 09:46:15 +0000 Subject: [PATCH] rip out old, but efficient and highly tuned but scary packethandler code, replace by much cleaner variant with dnssec guts un-ifdef up the actual signing stuff in dnspacket.cc. crashes violently on the first DNSSEC query now! git-svn-id: svn://svn.powerdns.com/pdns/trunk/pdns@1561 d19b8d6e-7fed-0310-83ef-9ca221ded41b --- pdns/dnspacket.cc | 4 - pdns/packethandler.cc | 686 ++++++++++++++++++++++++++++-------------- pdns/packethandler.hh | 14 + 3 files changed, 476 insertions(+), 228 deletions(-) diff --git a/pdns/dnspacket.cc b/pdns/dnspacket.cc index cdc9b501c..23de32293 100644 --- a/pdns/dnspacket.cc +++ b/pdns/dnspacket.cc @@ -364,7 +364,6 @@ void DNSPacket::wrapup(void) pos->content="."; shared_ptr drc(DNSRecordContent::mastermake(pos->qtype.getCode(), 1, pos->content)); -#if 0 if(d_dnssecOk) { if(pos != d_rrs.begin() && (signQType != pos->qtype.getCode() || signQName != pos->qname)) { addSignature(::arg()["key-repository"], signQName, wildcardQName, signQType, signTTL, signPlace, toSign, pw); @@ -377,7 +376,6 @@ void DNSPacket::wrapup(void) if(pos->auth) toSign.push_back(drc); } -#endif pw.startRecord(pos->qname, pos->qtype.getCode(), pos->ttl, 1, (DNSPacketWriter::Place)pos->d_place); drc->toPacket(pw); @@ -394,12 +392,10 @@ void DNSPacket::wrapup(void) break; } } -#if 0 if(d_dnssecOk && !(d_tcp && d_rrs.rbegin()->qtype.getCode() == QType::SOA && d_rrs.rbegin()->priority == 1234)) { cerr<<"Last signature.. "<priority<<", "<qtype.getCode()<<", "<< d_rrs.size()< #include #include +#include +#include +#include "dnssecinfra.hh" +#include "dnsseckeeper.hh" #include "dns.hh" #include "dnsbackend.hh" #include "ueberbackend.hh" @@ -192,6 +196,45 @@ int PacketHandler::doFancyRecords(DNSPacket *p, DNSPacket *r, string &target) return 0; } +/** This catches version requests. Returns 1 if it was handled, 0 if it wasn't */ +int PacketHandler::doDNSKEYRequest(DNSPacket *p, DNSPacket *r) +{ + DNSResourceRecord rr; + DNSSECKeeper dk(::arg()["key-repository"]); + + if(p->qtype.getCode()!=QType::DNSKEY) + return false; + + bool haveOne=false; + DNSSECPrivateKey dpk; + + + if(dk.haveKSKFor(p->qdomain, &dpk)) { + rr.qtype=QType::DNSKEY; + rr.ttl=3600; + rr.qname=p->qdomain; + rr.content=dpk.getDNSKEY().getZoneRepresentation(); + + r->addRecord(rr); + haveOne=true; + } + + DNSSECKeeper::zskset_t zskset = dk.getZSKsFor(p->qdomain); + BOOST_FOREACH(DNSSECKeeper::zskset_t::value_type value, zskset) { + rr.qtype=QType::DNSKEY; + rr.ttl=3600; + rr.qname=p->qdomain; + rr.content=value.first.getDNSKEY().getZoneRepresentation(); + + r->addRecord(rr); + haveOne=true; + } + + + return haveOne; +} + + /** This catches version requests. Returns 1 if it was handled, 0 if it wasn't */ int PacketHandler::doVersionRequest(DNSPacket *p, DNSPacket *r, string &target) { @@ -237,6 +280,43 @@ bool PacketHandler::getAuth(DNSPacket *p, SOAData *sd, const string &target, int return false; } +vector PacketHandler::getBestReferralNS(DNSPacket *p, SOAData& sd, const string &target) +{ + vector ret; + DNSResourceRecord rr; + string subdomain(target); + do { + B.lookup(QType(QType::NS), subdomain, p, sd.domain_id); + while(B.get(rr)) { + if(!rr.auth) + ret.push_back(rr); + } + if(!ret.empty()) + return ret; + } while( chopOff( subdomain ) ); // 'www.powerdns.org' -> 'powerdns.org' -> 'org' -> '' + return ret; +} + +vector PacketHandler::getBestWildcard(DNSPacket *p, SOAData& sd, const string &target) +{ + vector ret; + DNSResourceRecord rr; + string subdomain(target); + while( chopOff( subdomain )) { + B.lookup(QType(QType::ANY), "*."+subdomain, p, sd.domain_id); + while(B.get(rr)) { + if(rr.qtype == p->qtype ||rr.qtype.getCode() == QType::CNAME ) + ret.push_back(rr); + } + + if(!ret.empty()) + return ret; + } + + return ret; +} + + /** returns 1 in case of a straight match, 2 in case of a wildcard CNAME (groan), 0 in case of no hit */ int PacketHandler::doWildcardRecords(DNSPacket *p, DNSPacket *r, string &target) { @@ -353,6 +433,111 @@ int PacketHandler::doAdditionalProcessingAndDropAA(DNSPacket *p, DNSPacket *r) return 1; } + +void PacketHandler::emitNSEC(const std::string& begin, const std::string& end, const std::string& toNSEC, DNSPacket *r, int mode) +{ + cerr<<"We should emit '"<addRecord(rr); +} + +/* mode 0 = no error -> an NSEC that starts with 'target', in authority section + mode 1 = NXDOMAIN -> an NSEC from auth to first + a covering NSEC + mode 2 = ANY or direct NSEC request -> an NSEC that starts with 'target' + mode 3 = a covering NSEC in the authority section (like 1, except for first) +*/ + +void PacketHandler::addNSEC(DNSPacket *p, DNSPacket *r, const string& target, const string& auth, int mode) +{ + cerr<<"Should add NSEC covering '"<getBeforeAndAfterNames(sd.domain_id, target, before, after); + cerr<<"Done calling"<getBeforeAndAfterNames(sd.domain_id, auth, before, after); + emitNSEC(auth, after, auth, r, mode); + } + + if(mode == 3) + emitNSEC(before, after, target, r, mode); + + return; +} + +bool PacketHandler::doDNSSECProcessing(DNSPacket *p, DNSPacket *r) +{ + if(!p->d_dnssecOk) + return false; + + vector arrs=r->getAnswerRecords(); + if(arrs.empty()) + return false; + + cerr<<"Have arrs "< crrs; + + for(vector::const_iterator i=arrs.begin(); + i!=arrs.end(); ++i) + crrs.push_back(**i); + + // we now have a copy, push_back on packet might reallocate! + + for(vector::const_iterator i=crrs.begin(); + i!=crrs.end(); + ++i) { + if(i->d_place!=DNSResourceRecord::ANSWER) + continue; + + B.lookup(QType(QType::RRSIG),i->qname,p); + DNSResourceRecord rr; + while(B.get(rr)) { + rr.d_place=DNSResourceRecord::ANSWER; + if(splitField(rr.content, ' ').first==i->qtype.getName()) + r->addRecord(rr); + } + } + + return false; +} + /* returns 1 if everything is done & ready, 0 if the search should continue, 2 if a 'NO-ERROR' response should be generated */ int PacketHandler::makeCanonic(DNSPacket *p, DNSPacket *r, string &target) { @@ -376,11 +561,18 @@ int PacketHandler::makeCanonic(DNSPacket *p, DNSPacket *r, string &target) bool shortcut=p->qtype.getCode()!=QType::SOA && p->qtype.getCode()!=QType::ANY; int hits=0; bool relevantNS=false; - + bool sawDS=false; + bool crossedZoneCut = false; while(B.get(rr)) { if(rr.qtype.getCode() == QType::NS && p->qtype.getCode() != QType::NS) { // possible retargeting relevantNS=true; } + + if(rr.qtype.getCode()==QType::DS && p->qtype.getCode() == QType::NS && p->d_dnssecOk) { + sawDS = true; + r->addRecord(rr); + } + if(rr.qtype.getCode()!=QType::NS || p->qtype.getCode()==QType::NS) hits++; if(!rfound && rr.qtype.getCode()==QType::CNAME) { @@ -389,11 +581,24 @@ int PacketHandler::makeCanonic(DNSPacket *p, DNSPacket *r, string &target) target=rr.content; // for retargeting } if(shortcut && !found && rr.qtype==p->qtype) { + if(!rr.auth) { + + } + rfound=true; r->addRecord(rr); } } - if(!numloops && hits && !relevantNS && !found && !rfound && shortcut ) { // we found matching qnames but not a qtype + + if(crossedZoneCut) { + cerr<<"Should return NS records, and this A/AAAA record in the additional section.."<qtype.getCode() == QType::NS && p->d_dnssecOk && rfound) { + addNSEC(p, r, p->qdomain, "", 2); // make it 'official' that we have no DS + } + + if(hits && !relevantNS && !found && !rfound && shortcut ) { // XXX FIXME !numloops. we found matching qnames but not a qtype DLOG(L<<"Found matching qname, but not the qtype"<qdomain, p); + + DNSResourceRecord rr; + + typedef map > > records_t; + records_t records; + + NSECRecordContent nrc; + nrc.d_set.insert(QType::RRSIG); + nrc.d_set.insert(QType::NSEC); + + while(B.get(rr)) { + if(!rr.auth) + continue; + + // this needs to deal with the 'prio' mismatch! + if(rr.qtype.getCode()==QType::MX || rr.qtype.getCode() == QType::SRV) { + rr.content = lexical_cast(rr.priority) + " " + rr.content; + } + + if(!rr.content.empty() && rr.qtype.getCode()==QType::TXT && rr.content[0]!='"') { + rr.content="\""+rr.content+"\""; + } + if(rr.content.empty()) // empty contents confuse the MOADNS setup + rr.content="."; + shared_ptr drc(DNSRecordContent::mastermake(rr.qtype.getCode(), 1, rr.content)); + + records[rr.qtype.getCode()].push_back(drc); + nrc.d_set.insert(rr.qtype.getCode()); + } + + // now get the fucking NSEC too.. + + SOAData sd; + sd.db=(DNSBackend *)-1; // force uncached answer + getAuth(p, &sd, p->qdomain, 0); + + string before,after; + sd.db->getBeforeAndAfterNames(sd.domain_id, p->qdomain, before, after); + + nrc.d_next=after; + + rr.qname=p->qdomain; + rr.ttl=3600; + rr.qtype=QType::NSEC; + rr.content=nrc.getZoneRepresentation(); + + records[QType::NSEC].push_back(shared_ptr(DNSRecordContent::mastermake(rr.qtype.getCode(), 1, rr.content))); + + // ok, the NSEC is in.. + + cerr<<"Have "<qdomain; + rr.ttl = 3600; + rr.auth = 0; // please don't sign this! + rr.d_place = DNSResourceRecord::ANSWER; + rr.qtype = QType::RRSIG; + + BOOST_FOREACH(records_t::value_type& iter, records) { + RRSIGRecordContent rrc; + for(int ksk =0 ; ksk < 2; ++ksk) { + getRRSIGForRRSET(::arg()["key-repository"], p->qdomain, iter.first, 3600, iter.second, rrc, ksk); + rr.content=rrc.getZoneRepresentation(); + r->addRecord(rr); + if(iter.first != QType::DNSKEY) + break; + } + } +} + +void PacketHandler::makeNXDomain(DNSPacket* p, DNSPacket* r, const std::string& target, SOAData& sd) +{ + DNSResourceRecord rr; + rr.qname=sd.qname; + rr.qtype=QType::SOA; + rr.content=serializeSOAData(sd); + rr.ttl=sd.ttl; + rr.domain_id=sd.domain_id; + rr.d_place=DNSResourceRecord::AUTHORITY; + r->addRecord(rr); + + if(p->d_dnssecOk) + addNSEC(p, r, target, sd.qname, 1); + r->setRcode(RCode::NXDomain); + S.ringAccount("nxdomain-queries",p->qdomain+"/"+p->qtype.getName()); +} + +void PacketHandler::makeNOError(DNSPacket* p, DNSPacket* r, const std::string& target, SOAData& sd) +{ + DNSResourceRecord rr; + rr.qname=sd.qname; + rr.qtype=QType::SOA; + rr.content=serializeSOAData(sd); + rr.ttl=sd.ttl; + rr.domain_id=sd.domain_id; + rr.d_place=DNSResourceRecord::AUTHORITY; + r->addRecord(rr); + + if(p->d_dnssecOk) + addNSEC(p, r, target, sd.qname, 0); + + S.ringAccount("noerror-queries",p->qdomain+"/"+p->qtype.getName()); +} + + +bool PacketHandler::addDSforNS(DNSPacket* p, DNSPacket* r, SOAData& sd, const string& dsname) +{ + B.lookup(QType(QType::DS), dsname, p, sd.domain_id); + DNSResourceRecord rr; + bool gotOne=false; + while(B.get(rr)) { + gotOne=true; + rr.d_place = DNSResourceRecord::AUTHORITY; + r->addRecord(rr); + } + return gotOne; +} + +bool PacketHandler::tryReferral(DNSPacket *p, DNSPacket*r, SOAData& sd, const string &target) +{ + vector rrset = getBestReferralNS(p, sd, target); + if(rrset.empty()) + return false; + + cerr<<"The best NS is: "<qname<addRecord(rr); + } + r->setA(false); + + if(!addDSforNS(p, r, sd, rrset.begin()->qname)) + addNSEC(p, r, rrset.begin()->qname, sd.qname, 0); + + return true; +} + +void PacketHandler::completeANYRecords(DNSPacket *p, DNSPacket*r, SOAData& sd, const string &target) +{ + if(!p->d_dnssecOk) + cerr<<"Need to add all the RRSIGs too for '"< rrset = getBestWildcard(p, sd, target); + if(rrset.empty()) + return false; + + cerr<<"The best wildcard match: "<qname<qdomain; + cerr<<"\tadding '"<addRecord(rr); + } + + if(p->d_dnssecOk) { + addNSEC(p, r, p->qdomain, sd.qname, 3); + } + return true; +} + + //! Called by the Distributor to ask a question. Returns 0 in case of an error DNSPacket *PacketHandler::questionOrRecurse(DNSPacket *p, bool *shouldRecurse) { @@ -571,20 +955,19 @@ DNSPacket *PacketHandler::questionOrRecurse(DNSPacket *p, bool *shouldRecurse) string subdomain=""; string soa; int retargetcount=0; - bool noSameLevelNS; + + vector rrset; + bool weDone=0, weRedirected=0, weHaveUnauth=0; DNSPacket *r=0; try { DLOG(L << Logger::Notice<<"Remote "<< p->remote.toString() <<" wants a type " << p->qtype.getName() << " ("<qtype.getCode()<<") about '"<qdomain << "'" << endl); -// XXX FIXME Find out why this isn't working! -#ifndef WIN32 if(p->d.qr) { // QR bit from dns packet (thanks RA from N) L<getRemote()<<", dropping"<qdomain<<"' "<qtype.getName()<<" from "<getRemote()<qdomain<<"' "<qtype.getName()<<" from "<getRemote()<replyPacket(); // generate an empty reply packet if(p->d.rd && d_doRecursion && DP->recurseFor(p)) // make sure we set ra if rd was set, and we'll do it @@ -644,6 +1027,9 @@ DNSPacket *PacketHandler::questionOrRecurse(DNSPacket *p, bool *shouldRecurse) string target=p->qdomain; bool noCache=false; + if(doDNSKEYRequest(p,r)) + goto sendit; + if(doVersionRequest(p,r,target)) // catch version.bind requests goto sendit; @@ -652,275 +1038,127 @@ DNSPacket *PacketHandler::questionOrRecurse(DNSPacket *p, bool *shouldRecurse) else if(p->qclass!=1) // we only know about IN, so we don't find anything goto sendit; - int mret; - retargeted:; - if(retargetcount++>10) { - L< 10) { // XXX FIXME, retargetcount++? r->setRcode(RCode::ServFail); - goto sendit; + return r; } - mret=makeCanonic(p, r, target); // traverse CNAME chain until we have a useful record (may actually give the correct answer!) - DLOG(L<clearRecords(); - } - if(d_doFancyRecords) { // MBOXFW, URL <- fake records, emulated with MX and A - DLOG(L<<"There is some data, but not of the correct type, checking fancy records"<setRcode(RCode::ServFail); - goto sendit; + if(!getAuth(p, &sd, target, 0)) { + r->setA(false); + if(::arg().mustDo("send-root-referral")) { + DLOG(L<setRcode(RCode::ServFail); // 'sorry' } - if(mret == 2) { - DLOG(L<<"There is some data, but not of the correct type, adding SOA for NXRECORDSET"<addRecord(rr); - if(mret == 2) goto sendit; } - } - - if(mret == 1) - goto sendit; // this might be the end of it (client requested a CNAME, or we found the answer already) - // now ready to start the real direct search - - if(p->qtype.getCode()==QType::SOA || p->qtype.getCode()==QType::ANY) { // this is special + // we know we have authority - if(B.getSOA(target,sd,p)) { - rr.qname=target; + if(p->qtype.getCode() == QType::SOA) { + rr.qname=sd.qname; rr.qtype=QType::SOA; rr.content=serializeSOAData(sd); rr.ttl=sd.ttl; rr.domain_id=sd.domain_id; rr.d_place=DNSResourceRecord::ANSWER; r->addRecord(rr); - if(p->qtype.getCode()==QType::SOA) { // we are done goto sendit; } - } - } - noSameLevelNS=true; - if(p->qtype.getCode()!=QType::SOA) { // regular direct lookup - B.lookup(QType(QType::ANY), target,p); - - while(B.get(rr)) { - if(rr.qtype.getCode()==QType::SOA) // skip any direct SOA responses as they may be different - continue; - if(rr.qtype==p->qtype || p->qtype.getCode()==QType::ANY ) { - DLOG(L<<"Found a direct answer: "<qtype.getCode()==QType::ANY && (rr.qtype.getCode()==QType::URL || rr.qtype.getCode()==QType::CURL)) { - rr.content=::arg()["urlredirector"]; - rr.qtype=QType::A; - rr.qname=target; - } - - r->addRecord(rr); // and add - } - else - if(rr.qtype.getCode()==QType::NS) - noSameLevelNS=false; - } - - if(p->qtype.getCode()==QType::ANY) { - if(d_doFancyRecords) { - int res=findMboxFW(p,r,target); - if(res<0) - L<0) { - DLOG(L<qtype.getCode() == QType::NSEC && p->d_dnssecOk) { + addNSEC(p, r, target, "", 2); // only NSEC please goto sendit; } - else - noSameLevelNS = false; // who knows.. this probably closes ticket 224. this code is a mess - // not found yet, try wildcards (we only try here in case of recursion - we should check before we hand off) - - if(mret != 2 && p->d.rd && d_doRecursion && d_doWildcards) { - int res=doWildcardRecords(p,r,target); - if(res) { // had a result - // FIXME: wildCard may retarget us in the future - if(res==1) // had a straight result - goto sendit; - if(res==2) - goto retargeted; + // this TRUMPS a cname! + if(p->qtype.getCode() == QType::RRSIG && p->d_dnssecOk) { + synthesiseRRSIGs(p, r); goto sendit; } + + // see what we get.. + B.lookup(QType(QType::ANY), target, p, sd.domain_id); + rrset.clear(); + weDone=weRedirected=weHaveUnauth=0; + + while(B.get(rr)) { + if((p->qtype.getCode() == QType::ANY || rr.qtype == p->qtype) && rr.auth) + weDone=1; + if((rr.qtype == p->qtype || rr.qtype.getCode() == QType::NS) && !rr.auth) + weHaveUnauth=1; + + if(rr.qtype.getCode() == QType::CNAME && p->qtype.getCode() != QType::CNAME) + weRedirected=1; + rrset.push_back(rr); } - // RECURSION CUT-OUT! + cerr<<"After first ANY query: weDone="<d.rd && d_doRecursion && !weAuth) { - if(DP->recurseFor(p)) { - *shouldRecurse=true; - delete r; - return 0; + if(rrset.empty()) { + // try wildcards, and if they don't work, go look for NS records + cerr<<"Found nothing in the ANY, but let's try the NS set"<d.rd || target==p->qdomain) { // only servfail if we didn't follow a CNAME - DLOG(L<getRemote()<< (p->d.rd ? " (recursion was desired)" : "") <setA(false); - if(::arg().mustDo("send-root-referral")) { - DLOG(L<setRcode(RCode::ServFail); // 'sorry' - } - } - else if(!p->d.rd) { - if(::arg().mustDo("send-root-referral")) { // addresses ticket 223 - DLOG(L<qdomain+"/"+p->qtype.getName()); - S.ringAccount("remotes-unauth",p->getRemote()); + if(weRedirected) { + BOOST_FOREACH(rr, rrset) { + if(rr.qtype.getCode() == QType::CNAME) { + r->addRecord(rr); + target = rr.content; + retargetcount++; + goto retargeted; } - else { - DLOG(L<qdomain && !found) { // don't strip data if we've been retargeted! - DLOG(L<clearRecords(); // we need to start out with an empty slate } - found=true; - rr.d_place=DNSResourceRecord::AUTHORITY; // this for the authority section + else if(weDone) { + BOOST_FOREACH(rr, rrset) { + if((p->qtype.getCode() == QType::ANY || rr.qtype == p->qtype) && rr.auth) r->addRecord(rr); } - if(found || (!subdomain.empty() && subdomain[0]=='.')) { // this catches '..' - r->setA(false); // send out an NS referral, which should be unauth - break; - } - }while((pos=subdomain.find("."))!=string::npos); - - if(!found) { - // try wildcards then - if(d_doWildcards) { - int res=doWildcardRecords(p,r,target); - - if(res==1) // had a straight result - goto sendit; - if(res==2) - goto retargeted; - } - // we have authority but no answer, so we add the SOA for negative caching - rr.qname=sd.qname; - rr.qtype=QType::SOA; - rr.content=serializeSOAData(sd); - rr.ttl=sd.ttl; - rr.domain_id=sd.domain_id; - rr.d_place=DNSResourceRecord::AUTHORITY; - r->addRecord(rr); - - - // need to send NXDOMAIN if there are 0 records for whatever type for target - - B.lookup("ANY",target,p); - while(B.get(rr)) - found=true; - - if(!found) { - SOAData sd2; - if(B.getSOA(target,sd2,p)) // is there a SOA perhaps? (which may not appear in an ANY query) - found=true; + if(p->qtype.getCode() == QType::ANY) { + completeANYRecords(p, r, sd, target); } - if(!found) { - if(d_logDNSDetails) - L<getRemote() <<" for '"<qtype.getName()<<")"<setRcode(RCode::NXDomain); - S.ringAccount("nxdomain-queries",p->qdomain+"/"+p->qtype.getName()); + goto sendit; } - else { - if(d_logDNSDetails) - L<getRemote() <<" for '"<qtype.getName()<<"), other types do exist"<qdomain+"/"+p->qtype.getName()); + else if(weHaveUnauth) { + cerr<<"Have unauth data, so need to hunt for best NS records"<wrapup(); // needed for inserting in cache - if(!noCache) - noCache = !p->couldBeCached(); + // doDNSSECProcessing(p, r); + r->wrapup(); // needed for inserting in cache if(!noCache) { PC.insert(p,r); // in the packet cache } diff --git a/pdns/packethandler.hh b/pdns/packethandler.hh index b89b5fcac..9f141db3f 100644 --- a/pdns/packethandler.hh +++ b/pdns/packethandler.hh @@ -89,9 +89,23 @@ private: int findUrl(DNSPacket *p, DNSPacket *r, string &target); int doFancyRecords(DNSPacket *p, DNSPacket *r, string &target); int doVersionRequest(DNSPacket *p, DNSPacket *r, string &target); + int doDNSKEYRequest(DNSPacket *p, DNSPacket *r); bool getAuth(DNSPacket *p, SOAData *sd, const string &target, int *zoneId); bool getTLDAuth(DNSPacket *p, SOAData *sd, const string &target, int *zoneId); int doAdditionalProcessingAndDropAA(DNSPacket *p, DNSPacket *r); + bool doDNSSECProcessing(DNSPacket* p, DNSPacket *r); + void addNSEC(DNSPacket *p, DNSPacket* r, const string &target, const std::string& auth, int mode); + void emitNSEC(const std::string& before, const std::string& after, const std::string& toNSEC, DNSPacket *r, int mode); + void synthesiseRRSIGs(DNSPacket* p, DNSPacket* r); + void makeNXDomain(DNSPacket* p, DNSPacket* r, const std::string& target, SOAData& sd); + void makeNOError(DNSPacket* p, DNSPacket* r, const std::string& target, SOAData& sd); + vector getBestReferralNS(DNSPacket *p, SOAData& sd, const string &target); + bool tryReferral(DNSPacket *p, DNSPacket*r, SOAData& sd, const string &target); + + vector getBestWildcard(DNSPacket *p, SOAData& sd, const string &target); + bool tryWildcard(DNSPacket *p, DNSPacket*r, SOAData& sd, string &target, bool& retargeted); + bool addDSforNS(DNSPacket* p, DNSPacket* r, SOAData& sd, const string& dsname); + void completeANYRecords(DNSPacket *p, DNSPacket*r, SOAData& sd, const string &target); static int s_count; bool d_doFancyRecords; -- 2.40.0