diff --git a/pdns/slavecommunicator.cc b/pdns/slavecommunicator.cc index 9d9433411df5..492ac412b9cc 100644 --- a/pdns/slavecommunicator.cc +++ b/pdns/slavecommunicator.cc @@ -66,43 +66,21 @@ void CommunicatorClass::addSuckRequest(const string &domain, const string &maste void CommunicatorClass::suck(const string &domain,const string &remote) { L<(P.getBackend()); // copy of the same UeberBackend - NSEC3PARAMRecordContent ns3pr, hadNs3pr; - bool narrow, hadNarrow=false; DNSSECKeeper dk (B); // reuse our backend for DNSSECKeeper - bool dnssecZone = false; - bool haveNSEC3=false; - if(dk.isSecuredZone(domain)) { - dnssecZone=true; - haveNSEC3=dk.getNSEC3PARAM(domain, &ns3pr, &narrow); - if (haveNSEC3) { - hadNs3pr = ns3pr; - hadNarrow = narrow; - } - } - - const bool hadNSEC3 = haveNSEC3; - const bool hadPresigned = dk.isPresigned(domain); - const bool hadDnssecZone = dnssecZone; if(!B->getDomainInfo(domain, di) || !di.backend) { // di.backend and B are mostly identical L< nsset, qnames; - - ComboAddress raddr(remote, 53); - string tsigkeyname, tsigalgorithm, tsigsecret; if(dk.getTSIGForAccess(domain, remote, &tsigkeyname)) { @@ -133,7 +111,7 @@ void CommunicatorClass::suck(const string &domain,const string &remote) vector localaddr; ComboAddress laddr; - + if(B->getDomainMetadata(domain, "AXFR-SOURCE", localaddr) && !localaddr.empty()) { try { laddr = ComboAddress(localaddr[0]); @@ -144,18 +122,39 @@ void CommunicatorClass::suck(const string &domain,const string &remote) return; } } else { - laddr.sin4.sin_family = 0; + laddr.sin4.sin_family = 0; + } + + bool hadDnssecZone = false; + bool hadPresigned = false; + bool hadNSEC3 = false; + NSEC3PARAMRecordContent ns3pr, hadNs3pr; + bool isNarrow, hadNarrow=false; + + if(dk.isSecuredZone(domain)) { + hadDnssecZone=true; + hadPresigned=dk.isPresigned(domain); + if (dk.getNSEC3PARAM(domain, &ns3pr, &isNarrow)) { + hadNSEC3 = true; + hadNs3pr = ns3pr; + hadNarrow = isNarrow; + } } - AXFRRetriever retriever(raddr, domain.c_str(), tsigkeyname, tsigalgorithm, tsigsecret, - (laddr.sin4.sin_family == 0) ? NULL : &laddr); + bool isDnssecZone = false; + bool isPresigned = false; + bool isNSEC3 = false; + bool optOutFlag = false; - bool gotPresigned = false; - bool gotNSEC3 = false; - bool gotOptOutFlag = false; + bool first=true; + bool firstNSEC3=true; unsigned int soa_serial = 0; + set nsset, qnames, secured; vector rrs; - set secured; + + ComboAddress raddr(remote, 53); + AXFRRetriever retriever(raddr, domain.c_str(), tsigkeyname, tsigalgorithm, tsigsecret, (laddr.sin4.sin_family == 0) ? NULL : &laddr); + Resolver::res_t recs; while(retriever.getChunk(recs)) { if(first) { L<qtype.getCode() == QType::OPT || i->qtype.getCode() == QType::TSIG) // ignore EDNS0 & TSIG continue; - if(!endsOn(i->qname, domain)) { + if(!endsOn(i->qname, domain)) { L<qname<<"'|"<qtype.getName()<<" during AXFR of zone '"<qtype.getCode() == QType::NSEC3PARAM) { - ns3pr = NSEC3PARAMRecordContent(i->content); - narrow = false; - dnssecZone = haveNSEC3 = gotPresigned = gotNSEC3 = true; - continue; - } else if (i->qtype.getCode() == QType::NSEC3) { - dnssecZone = gotPresigned = true; - NSEC3RecordContent ns3rc(i->content); - gotOptOutFlag = ns3rc.d_flags & 1; - if (ns3rc.d_set.count(QType::NS) && !pdns_iequals(i->qname, domain)) - secured.insert(toLower(makeRelative(i->qname, domain))); - continue; - } else if (i->qtype.getCode() == QType::NSEC) { - dnssecZone = gotPresigned = true; - continue; - } - - if(i->qtype.getCode() == QType::SOA) { - if(soa_serial != 0) - continue; //skip the last SOA - SOAData sd; - fillSOAData(i->content,sd); - soa_serial = sd.serial; + vector out; + if(!pdl || !pdl->axfrfilter(raddr, domain, *i, out)) { + out.push_back(*i); } - i->domain_id=domain_id; + BOOST_FOREACH(DNSResourceRecord& rr, out) { + switch(rr.qtype.getCode()) { + case QType::NSEC3PARAM: { + ns3pr = NSEC3PARAMRecordContent(rr.content); + isDnssecZone = isNSEC3 = true; + isNarrow = false; + continue; + } + case QType::NSEC3: { + NSEC3RecordContent ns3rc(rr.content); + if (firstNSEC3) { + isDnssecZone = isPresigned = true; + firstNSEC3 = false; + } else if (optOutFlag != (ns3rc.d_flags & 1)) + throw AhuException("Zones with a mixture of Opt-Out NSEC3 RRs and non-Opt-Out NSEC3 RRs are not supported."); + optOutFlag = ns3rc.d_flags & 1; + if (ns3rc.d_set.count(QType::NS) && !pdns_iequals(rr.qname, domain)) + secured.insert(toLower(makeRelative(rr.qname, domain))); + continue; + } + case QType::NSEC: { + isDnssecZone = isPresigned = true; + continue; + } + case QType::SOA: { + if(soa_serial != 0) + continue; //skip the last SOA + SOAData sd; + fillSOAData(rr.content,sd); + soa_serial = sd.serial; + break; + } + case QType::NS: { + if(!pdns_iequals(rr.qname, domain)) + nsset.insert(rr.qname); + break; + } + default: + break; + } -#if 0 - if(i->qtype.getCode()>=60000) - throw DBException("Database can't store unknown record type "+lexical_cast(i->qtype.getCode()-1024)); -#endif + qnames.insert(rr.qname); - vector out; - if(pdl && pdl->axfrfilter(raddr, domain, *i, out)) { - BOOST_FOREACH(const DNSResourceRecord& rr, out) { - rrs.push_back(rr); - } - } else { - rrs.push_back(*i); + rr.domain_id=domain_id; + rrs.push_back(rr); } } } + if(isNSEC3) { + ns3pr.d_flags = optOutFlag ? 1 : 0; + } + - BOOST_FOREACH(const DNSResourceRecord& rr, rrs) { - if(rr.qtype.getCode() == QType::NS && !pdns_iequals(rr.qname, domain)) - nsset.insert(rr.qname); - qnames.insert(rr.qname); + if(!isPresigned) { + DNSSECKeeper::keyset_t keys = dk.getKeys(domain); + if(!keys.empty()) { + isDnssecZone = true; + isNSEC3 = hadNSEC3; + ns3pr = hadNs3pr; + optOutFlag = (hadNs3pr.d_flags & 1); + isNarrow = hadNarrow; + } } - if(dnssecZone) { - if(!haveNSEC3) + + if(isDnssecZone) { + if(!isNSEC3) L<startTransaction(domain, domain_id); L<startTransaction(domain, domain_id); + + // update the presigned flag and NSEC3PARAM + if (isDnssecZone) { + // update presigned if there was a change + if (isPresigned && !hadPresigned) { + // zone is now presigned + dk.setPresigned(domain); + } else if (hadPresigned && !isPresigned) { + // zone is no longer presigned + dk.unsetPresigned(domain); + } + // update NSEC3PARAM + if (isNSEC3) { + // zone is NSEC3, only update if there was a change + if (!hadNSEC3 || (hadNarrow != isNarrow) || + (ns3pr.d_algorithm != hadNs3pr.d_algorithm) || + (ns3pr.d_flags != hadNs3pr.d_flags) || + (ns3pr.d_iterations != hadNs3pr.d_iterations) || + (ns3pr.d_salt != hadNs3pr.d_salt)) { + dk.setNSEC3PARAM(domain, ns3pr, isNarrow); + } + } else if (hadNSEC3 ) { + // zone is no longer NSEC3 + dk.unsetNSEC3PARAM(domain); + } + } else if (hadDnssecZone) { + // zone is no longer signed + if (hadPresigned) { + // remove presigned + dk.unsetPresigned(domain); + } + if (hadNSEC3) { + // unset NSEC3PARAM + dk.unsetNSEC3PARAM(domain); + } + } bool doent=true; uint32_t maxent = ::arg().asNum("max-ent-entries"); string ordername, shorter; - set nonterm, rrterm; + set rrterm, nonterm; + BOOST_FOREACH(DNSResourceRecord& rr, rrs) { + if(!isPresigned) { + if (rr.qtype.getCode() == QType::RRSIG) + continue; + if(isDnssecZone && rr.qtype.getCode() == QType::DNSKEY && !::arg().mustDo("direct-dnskey")) + continue; + } + // Figure out auth and ents rr.auth=true; shorter=rr.qname; rrterm.clear(); do { if(doent) { - if (!qnames.count(shorter) && !nonterm.count(shorter) && !rrterm.count(shorter)) + if (!qnames.count(shorter)) rrterm.insert(shorter); } - if(nsset.count(shorter) && rr.qtype.getCode() != QType::DS) { + if(nsset.count(shorter) && rr.qtype.getCode() != QType::DS) rr.auth=false; - break; - } + if (pdns_iequals(shorter, domain)) // stop at apex break; }while(chopOff(shorter)); - // Insert ents for auth rrs - if(doent && rr.auth) { - nonterm.insert(rrterm.begin(), rrterm.end()); + // Insert ents + if(doent && !rrterm.empty()) { + //bool auth; + if (!rr.auth && rr.qtype.getCode() == QType::NS) { + if (isNSEC3) + ordername=toLower(toBase32Hex(hashQNameWithSalt(ns3pr.d_iterations, ns3pr.d_salt, rr.qname))); + //auth=(!isNSEC3 || !optOutFlag || secured.count(ordername)); + } //else + //auth=rr.auth; + + BOOST_FOREACH(const string nt, rrterm){ + if (!nonterm.count(nt)) + nonterm.insert(nt); + } + if(nonterm.size() > maxent) { - L<feedRecord(rr, &ordername); } else di.backend->feedRecord(rr); @@ -300,44 +371,14 @@ void CommunicatorClass::suck(const string &domain,const string &remote) // Insert empty non-terminals if(doent && !nonterm.empty()) { - if (haveNSEC3) { - di.backend->feedEnts3(domain_id, domain, nonterm, ns3pr.d_iterations, ns3pr.d_salt, narrow); + if (isNSEC3) { + di.backend->feedEnts3(domain_id, domain, nonterm, ns3pr.d_iterations, ns3pr.d_salt, isNarrow); } else di.backend->feedEnts(domain_id, nonterm); } - // now we also need to update the presigned flag and NSEC3PARAM - // for the zone - if (gotPresigned) { - if (!hadDnssecZone && !hadPresigned) { - // zone is now presigned - dk.setPresigned(domain); - } - - if (hadPresigned || !hadDnssecZone) - { - // this is a presigned zone, update NSEC3PARAM - if (gotNSEC3) { - ns3pr.d_flags = gotOptOutFlag ? 1 : 0; - // only update if there was a change - if (!hadNSEC3 || (narrow != hadNarrow) || - (ns3pr.d_algorithm != hadNs3pr.d_algorithm) || - (ns3pr.d_flags != hadNs3pr.d_flags) || - (ns3pr.d_iterations != hadNs3pr.d_iterations) || - (ns3pr.d_salt != hadNs3pr.d_salt)) { - dk.setNSEC3PARAM(domain, ns3pr, narrow); - } - } else if (hadNSEC3) { - dk.unsetNSEC3PARAM(domain); - } - } - } else if (hadPresigned) { - // zone is no longer presigned - dk.unsetPresigned(domain); - dk.unsetNSEC3PARAM(domain); - } - di.backend->commitTransaction(); + transaction = false; di.backend->setFresh(domain_id); PC.purge(domain+"$"); @@ -348,35 +389,35 @@ void CommunicatorClass::suck(const string &domain,const string &remote) } catch(DBException &re) { L<abortTransaction(); } } catch(MOADNSException &re) { L<abortTransaction(); } } catch(std::exception &re) { L<abortTransaction(); } } catch(ResolverException &re) { L<abortTransaction(); } } catch(AhuException &ae) { L<abortTransaction(); }