415
DNSResourceRecord makeDNSRRFromSOAData(const SOAData& sd)
417
DNSResourceRecord soa;
419
soa.qtype=QType::SOA;
420
soa.content=serializeSOAData(sd);
422
soa.domain_id=sd.domain_id;
424
soa.d_place=DNSResourceRecord::ANSWER;
428
shared_ptr<DNSPacket> getFreshAXFRPacket(shared_ptr<DNSPacket> q)
430
shared_ptr<DNSPacket> ret = shared_ptr<DNSPacket>(q->replyPacket());
431
ret->setCompress(false);
432
ret->d_dnssecOk=false; // RFC 5936, 2.2.5
362
438
/** do the actual zone transfer. Return 0 in case of error, 1 in case of success */
363
439
int TCPNameserver::doAXFR(const string &target, shared_ptr<DNSPacket> q, int outsock)
365
shared_ptr<DNSPacket> outpacket;
441
bool noAXFRBecauseOfNSEC3Narrow=false;
442
NSEC3PARAMRecordContent ns3pr;
444
bool NSEC3Zone=false;
447
bool securedZone = dk.isSecuredZone(target);
448
if(dk.getNSEC3PARAM(target, &ns3pr, &narrow)) {
451
L<<Logger::Error<<"Not doing AXFR of an NSEC3 narrow zone.."<<endl;
452
noAXFRBecauseOfNSEC3Narrow=true;
456
shared_ptr<DNSPacket> outpacket= getFreshAXFRPacket(q);
458
outpacket->d_dnssecOk=true; // RFC 5936, 2.2.5 'SHOULD'
460
if(!canDoAXFR(q) || noAXFRBecauseOfNSEC3Narrow) {
367
461
L<<Logger::Error<<"AXFR of domain '"<<target<<"' denied to "<<q->getRemote()<<endl;
369
outpacket=shared_ptr<DNSPacket>(q->replyPacket());
370
462
outpacket->setRcode(RCode::Refused);
371
463
// FIXME: should actually figure out if we are auth over a zone, and send out 9 if we aren't
372
464
sendPacket(outpacket,outsock);
375
468
L<<Logger::Error<<"AXFR of domain '"<<target<<"' initiated by "<<q->getRemote()<<endl;
376
outpacket=shared_ptr<DNSPacket>(q->replyPacket());
378
DNSResourceRecord soa;
379
DNSResourceRecord rr;
382
471
sd.db=(DNSBackend *)-1; // force uncached answer
384
473
Lock l(&s_plock);
386
// find domain_id via SOA and list complete domain. No SOA, no AXFR
388
DLOG(L<<"Looking for SOA"<<endl);
474
DLOG(L<<"Looking for SOA"<<endl); // find domain_id via SOA and list complete domain. No SOA, no AXFR
390
476
L<<Logger::Error<<"TCP server is without backend connections in doAXFR, launching"<<endl;
391
477
s_P=new PacketHandler;
394
if(!s_P->getBackend()->getSOA(target,sd)) {
480
if(!s_P->getBackend()->getSOA(target, sd)) {
395
481
L<<Logger::Error<<"AXFR of domain '"<<target<<"' failed: not authoritative"<<endl;
396
482
outpacket->setRcode(9); // 'NOTAUTH'
397
483
sendPacket(outpacket,outsock);
402
PacketHandler P; // now open up a database connection, we'll need it
404
489
sd.db=(DNSBackend *)-1; // force uncached answer
405
if(!P.getBackend()->getSOA(target, sd)) {
406
L<<Logger::Error<<"AXFR of domain '"<<target<<"' failed: not authoritative in second instance"<<endl;
490
if(!db.getSOA(target, sd)) {
491
L<<Logger::Error<<"AXFR of domain '"<<target<<"' failed: not authoritative in second instance"<<endl;
407
492
outpacket->setRcode(9); // 'NOTAUTH'
408
493
sendPacket(outpacket,outsock);
413
soa.qtype=QType::SOA;
414
soa.content=serializeSOAData(sd);
416
soa.domain_id=sd.domain_id;
417
soa.d_place=DNSResourceRecord::ANSWER;
419
497
if(!sd.db || sd.db==(DNSBackend *)-1) {
420
498
L<<Logger::Error<<"Error determining backend for domain '"<<target<<"' trying to serve an AXFR"<<endl;
421
499
outpacket->setRcode(RCode::ServFail);
422
500
sendPacket(outpacket,outsock);
426
DLOG(L<<"Issuing list command - opening dedicated database connection"<<endl);
428
DNSBackend *B=sd.db; // get the RIGHT backend
431
if(!(B->list(target, sd.domain_id))) {
504
TSIGRecordContent trc;
505
string tsigkeyname, tsigsecret;
507
q->getTSIGDetails(&trc, &tsigkeyname, 0);
509
if(!tsigkeyname.empty()) {
510
string tsig64, algorithm;
512
s_P->getBackend()->getTSIGKey(tsigkeyname, &algorithm, &tsig64);
513
B64Decode(tsig64, tsigsecret);
517
UeberBackend signatureDB;
519
// SOA *must* go out first, our signing pipe might reorder
520
DLOG(L<<"Sending out SOA"<<endl);
521
DNSResourceRecord soa = makeDNSRRFromSOAData(sd);
522
outpacket->addRecord(soa);
523
editSOA(dk, sd.qname, outpacket.get());
525
addRRSigs(dk, signatureDB, target, outpacket->getRRS());
527
if(!tsigkeyname.empty())
528
outpacket->setTSIGDetails(trc, tsigkeyname, tsigsecret, trc.d_mac); // first answer is 'normal'
530
sendPacket(outpacket, outsock);
532
trc.d_mac = outpacket->d_trc.d_mac;
533
outpacket = getFreshAXFRPacket(q);
535
ChunkedSigningPipe csp(target, securedZone, "", ::arg().asNum("signing-threads"));
537
typedef map<string, NSECXEntry> nsecxrepo_t;
538
nsecxrepo_t nsecxrepo;
540
// this is where the DNSKEYs go in
542
DNSSECKeeper::keyset_t keys = dk.getKeys(target);
544
DNSResourceRecord rr;
546
BOOST_FOREACH(const DNSSECKeeper::keyset_t::value_type& value, keys) {
548
rr.qtype = QType(QType::DNSKEY);
549
rr.ttl = sd.default_ttl;
550
rr.auth = 1; // please sign!
551
rr.content = value.first.getDNSKEY().getZoneRepresentation();
552
string keyname = NSEC3Zone ? hashQNameWithSalt(ns3pr.d_iterations, ns3pr.d_salt, rr.qname) : labelReverse(rr.qname);
553
NSECXEntry& ne = nsecxrepo[keyname];
555
ne.d_set.insert(rr.qtype.getCode());
560
if(NSEC3Zone) { // now stuff in the NSEC3PARAM
561
rr.qtype = QType(QType::NSEC3PARAM);
563
rr.content = ns3pr.getZoneRepresentation();
565
string keyname = hashQNameWithSalt(ns3pr.d_iterations, ns3pr.d_salt, rr.qname);
566
NSECXEntry& ne = nsecxrepo[keyname];
568
ne.d_set.insert(rr.qtype.getCode());
572
// now start list zone
573
if(!(sd.db->list(target, sd.domain_id))) {
432
574
L<<Logger::Error<<"Backend signals error condition"<<endl;
433
575
outpacket->setRcode(2); // 'SERVFAIL'
434
576
sendPacket(outpacket,outsock);
437
/* write first part of answer */
439
DLOG(L<<"Sending out SOA"<<endl);
440
outpacket->addRecord(soa); // AXFR format begins and ends with a SOA record, so we add one
441
sendPacket(outpacket, outsock);
443
580
/* now write all other records */
446
int chunk=100; // FIXME: this should probably be autosizing
447
if(::arg().mustDo("strict-rfc-axfrs"))
450
outpacket=shared_ptr<DNSPacket>(q->replyPacket());
451
outpacket->setCompress(false);
454
if(rr.qtype.getCode()==6)
586
while(sd.db->get(rr)) {
588
if(securedZone && (rr.auth || rr.qtype.getCode() == QType::NS || rr.qtype.getCode() == QType::DS)) { // this is probably NSEC specific, NSEC3 is different
589
keyname = NSEC3Zone ? hashQNameWithSalt(ns3pr.d_iterations, ns3pr.d_salt, rr.qname) : labelReverse(rr.qname);
590
NSECXEntry& ne = nsecxrepo[keyname];
591
ne.d_set.insert(rr.qtype.getCode());
594
if(rr.qtype.getCode() == QType::SOA)
455
595
continue; // skip SOA - would indicate end of AXFR
457
outpacket->addRecord(rr);
459
if(!((++count)%chunk)) {
599
outpacket->getRRS() = csp.getChunk();
600
if(!outpacket->getRRS().empty()) {
601
if(!tsigkeyname.empty())
602
outpacket->setTSIGDetails(trc, tsigkeyname, tsigsecret, trc.d_mac, true);
603
sendPacket(outpacket, outsock);
604
trc.d_mac=outpacket->d_trc.d_mac;
605
outpacket=getFreshAXFRPacket(q);
612
unsigned int udiff=dt.udiffNoReset();
614
cerr<<"Starting NSEC: "<<csp.d_signed/(udiff/1000000.0)<<" sigs/s, "<<csp.d_signed<<" / "<<udiff/1000000.0<<endl;
615
cerr<<"Outstanding: "<<csp.d_outstanding<<", "<<csp.d_queued - csp.d_signed << endl;
616
cerr<<"Ready for consumption: "<<csp.getReady()<<endl;
620
for(nsecxrepo_t::const_iterator iter = nsecxrepo.begin(); iter != nsecxrepo.end(); ++iter) {
621
NSEC3RecordContent n3rc;
622
n3rc.d_set = iter->second.d_set;
623
n3rc.d_set.insert(QType::RRSIG);
624
n3rc.d_salt=ns3pr.d_salt;
626
n3rc.d_iterations = ns3pr.d_iterations;
627
n3rc.d_algorithm = 1; // SHA1, fixed in PowerDNS for now
628
if(boost::next(iter) != nsecxrepo.end()) {
629
n3rc.d_nexthash = boost::next(iter)->first;
632
n3rc.d_nexthash=nsecxrepo.begin()->first;
634
rr.qname = dotConcat(toLower(toBase32Hex(iter->first)), sd.qname);
636
rr.ttl = iter->second.d_ttl;
637
rr.content = n3rc.getZoneRepresentation();
638
rr.qtype = QType::NSEC3;
639
rr.d_place = DNSResourceRecord::ANSWER;
643
outpacket->getRRS() = csp.getChunk();
644
if(!outpacket->getRRS().empty()) {
645
if(!tsigkeyname.empty())
646
outpacket->setTSIGDetails(trc, tsigkeyname, tsigsecret, trc.d_mac, true);
647
sendPacket(outpacket, outsock);
648
trc.d_mac=outpacket->d_trc.d_mac;
649
outpacket=getFreshAXFRPacket(q);
657
else for(nsecxrepo_t::const_iterator iter = nsecxrepo.begin(); iter != nsecxrepo.end(); ++iter) {
658
NSECRecordContent nrc;
659
nrc.d_set = iter->second.d_set;
660
nrc.d_set.insert(QType::RRSIG);
661
nrc.d_set.insert(QType::NSEC);
662
if(boost::next(iter) != nsecxrepo.end()) {
663
nrc.d_next = labelReverse(boost::next(iter)->first);
666
nrc.d_next=labelReverse(nsecxrepo.begin()->first);
668
rr.qname = labelReverse(iter->first);
670
rr.ttl = iter->second.d_ttl;
671
rr.content = nrc.getZoneRepresentation();
672
rr.qtype = QType::NSEC;
673
rr.d_place = DNSResourceRecord::ANSWER;
678
outpacket->getRRS() = csp.getChunk();
679
if(!outpacket->getRRS().empty()) {
680
if(!tsigkeyname.empty())
681
outpacket->setTSIGDetails(trc, tsigkeyname, tsigsecret, trc.d_mac, true);
682
sendPacket(outpacket, outsock);
683
trc.d_mac=outpacket->d_trc.d_mac;
684
outpacket=getFreshAXFRPacket(q);
692
udiff=dt.udiffNoReset();
694
cerr<<"Flushing pipe: "<<csp.d_signed/(udiff/1000000.0)<<" sigs/s, "<<csp.d_signed<<" / "<<udiff/1000000.0<<endl;
695
cerr<<"Outstanding: "<<csp.d_outstanding<<", "<<csp.d_queued - csp.d_signed << endl;
696
cerr<<"Ready for consumption: "<<csp.getReady()<<endl;
699
outpacket->getRRS() = csp.getChunk(true); // flush the pipe
700
if(!outpacket->getRRS().empty()) {
701
if(!tsigkeyname.empty())
702
outpacket->setTSIGDetails(trc, tsigkeyname, tsigsecret, trc.d_mac, true); // first answer is 'normal'
462
703
sendPacket(outpacket, outsock);
464
outpacket=shared_ptr<DNSPacket>(q->replyPacket());
465
outpacket->setCompress(false);
466
// FIXME: Subsequent messages SHOULD NOT have a question section, though the final message MAY.
704
trc.d_mac=outpacket->d_trc.d_mac;
705
outpacket=getFreshAXFRPacket(q);
470
sendPacket(outpacket, outsock);
711
udiff=dt.udiffNoReset();
713
L<<Logger::Info<<"Done signing: "<<csp.d_signed/(udiff/1000000.0)<<" sigs/s, "<<endl;
473
715
DLOG(L<<"Done writing out records"<<endl);
474
716
/* and terminate with yet again the SOA record */
475
outpacket=shared_ptr<DNSPacket>(q->replyPacket());
717
outpacket=getFreshAXFRPacket(q);
476
718
outpacket->addRecord(soa);
719
editSOA(dk, sd.qname, outpacket.get());
720
if(!tsigkeyname.empty())
721
outpacket->setTSIGDetails(trc, tsigkeyname, tsigsecret, trc.d_mac, true);
477
723
sendPacket(outpacket, outsock);
478
725
DLOG(L<<"last packet - close"<<endl);
479
726
L<<Logger::Error<<"AXFR of domain '"<<target<<"' to "<<q->getRemote()<<" finished"<<endl;