2 PowerDNS Versatile Database Driven Nameserver
3 Copyright (C) 2002-2012 PowerDNS.COM BV
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License version 2
7 as published by the Free Software Foundation
9 Additionally, the license of this program contains a special
10 exception which allows to distribute the program in binary form when
11 it is linked against OpenSSL.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 #include "packetcache.hh"
24 #include "dnssecinfra.hh"
25 #include "dnsseckeeper.hh"
30 #include <sys/types.h>
33 #include "tcpreceiver.hh"
35 #include <boost/foreach.hpp>
39 #include "ueberbackend.hh"
40 #include "dnspacket.hh"
41 #include "nameserver.hh"
42 #include "distributor.hh"
45 #include "arguments.hh"
47 #include "packethandler.hh"
49 #include "resolver.hh"
50 #include "communicator.hh"
51 #include "namespaces.hh"
52 #include "signingpipe.hh"
53 extern PacketCache PC
;
58 \brief This file implements the tcpreceiver that receives and answers questions over TCP/IP
61 pthread_mutex_t
TCPNameserver::s_plock
= PTHREAD_MUTEX_INITIALIZER
;
62 Semaphore
*TCPNameserver::d_connectionroom_sem
;
63 PacketHandler
*TCPNameserver::s_P
;
64 int TCPNameserver::s_timeout
;
65 NetmaskGroup
TCPNameserver::d_ng
;
67 void TCPNameserver::go()
69 L
<<Logger::Error
<<"Creating backend connection for TCP"<<endl
;
72 s_P
=new PacketHandler
;
74 catch(PDNSException
&ae
) {
75 L
<<Logger::Error
<<Logger::NTLog
<<"TCP server is unable to launch backends - will try again when questions come in"<<endl
;
76 L
<<Logger::Error
<<"TCP server is unable to launch backends - will try again when questions come in: "<<ae
.reason
<<endl
;
78 pthread_create(&d_tid
, 0, launcher
, static_cast<void *>(this));
81 void *TCPNameserver::launcher(void *data
)
83 static_cast<TCPNameserver
*>(data
)->thread();
87 // throws PDNSException if things didn't go according to plan, returns 0 if really 0 bytes were read
88 int readnWithTimeout(int fd
, void* buffer
, unsigned int n
, bool throwOnEOF
=true)
91 char *ptr
= (char*)buffer
;
94 ret
=read(fd
, ptr
, bytes
);
97 ret
=waitForData(fd
, 5);
99 throw NetworkError("Waiting for data read");
101 throw NetworkError("Timeout reading data");
105 throw NetworkError("Reading data: "+stringerror());
108 if(!throwOnEOF
&& n
== bytes
)
111 throw NetworkError("Did not fulfill read from TCP due to EOF");
121 void writenWithTimeout(int fd
, const void *buffer
, unsigned int n
)
123 unsigned int bytes
=n
;
124 const char *ptr
= (char*)buffer
;
127 ret
=write(fd
, ptr
, bytes
);
130 ret
=waitForRWData(fd
, false, 5, 0);
132 throw NetworkError("Waiting for data write");
134 throw NetworkError("Timeout writing data");
138 throw NetworkError("Writing data: "+stringerror());
141 throw NetworkError("Did not fulfill TCP write due to EOF");
149 void connectWithTimeout(int fd
, struct sockaddr
* remote
, size_t socklen
)
152 Utility::socklen_t len
=sizeof(err
);
154 if((err
=connect(fd
, remote
, socklen
))<0 && errno
!=EINPROGRESS
)
155 throw NetworkError("connect: "+stringerror());
160 err
=waitForRWData(fd
, false, 5, 0);
162 throw NetworkError("Timeout connecting to remote");
164 throw NetworkError("Error connecting to remote");
166 if(getsockopt(fd
, SOL_SOCKET
,SO_ERROR
,(char *)&err
,&len
)<0)
167 throw NetworkError("Error connecting to remote: "+stringerror()); // Solaris
170 throw NetworkError("Error connecting to remote: "+string(strerror(err
)));
176 void TCPNameserver::sendPacket(shared_ptr
<DNSPacket
> p
, int outsock
)
179 /* Query statistics */
180 if(p
->qtype
.getCode()!=QType::AXFR
&& p
->qtype
.getCode()!=QType::IXFR
) {
182 if(p
->d
.rcode
==RCode::NXDomain
)
183 S
.ringAccount("nxdomain-queries",p
->qdomain
+"/"+p
->qtype
.getName());
184 } else if(p
->isEmpty()) {
185 S
.ringAccount("unauth-queries",p
->qdomain
+"/"+p
->qtype
.getName());
186 S
.ringAccount("remotes-unauth",p
->getRemote());
190 uint16_t len
=htons(p
->getString().length());
191 string
buffer((const char*)&len
, 2);
192 buffer
.append(p
->getString());
193 writenWithTimeout(outsock
, buffer
.c_str(), buffer
.length());
197 void TCPNameserver::getQuestion(int fd
, char *mesg
, int pktlen
, const ComboAddress
&remote
)
200 readnWithTimeout(fd
, mesg
, pktlen
);
202 catch(NetworkError
& ae
) {
203 throw NetworkError("Error reading DNS data from TCP client "+remote
.toString()+": "+ae
.what());
206 static void proxyQuestion(shared_ptr
<DNSPacket
> packet
)
208 int sock
=socket(AF_INET
, SOCK_STREAM
, 0);
210 Utility::setCloseOnExec(sock
);
212 throw NetworkError("Error making TCP connection socket to recursor: "+stringerror());
214 Utility::setNonBlocking(sock
);
217 parseService(::arg()["recursor"],st
);
220 ComboAddress
recursor(st
.host
, st
.port
);
221 connectWithTimeout(sock
, (struct sockaddr
*)&recursor
, recursor
.getSocklen());
222 const string
&buffer
=packet
->getString();
224 uint16_t len
=htons(buffer
.length()), slen
;
226 writenWithTimeout(sock
, &len
, 2);
227 writenWithTimeout(sock
, buffer
.c_str(), buffer
.length());
229 readnWithTimeout(sock
, &len
, 2);
233 readnWithTimeout(sock
, answer
, len
);
236 writenWithTimeout(packet
->getSocket(), &slen
, 2);
238 writenWithTimeout(packet
->getSocket(), answer
, len
);
240 catch(NetworkError
& ae
) {
242 throw NetworkError("While proxying a question to recursor "+st
.host
+": " +ae
.what());
248 void *TCPNameserver::doConnection(void *data
)
250 shared_ptr
<DNSPacket
> packet
;
251 // Fix gcc-4.0 error (on AMD64)
252 int fd
=(int)(long)data
; // gotta love C (generates a harmless warning on opteron)
253 pthread_detach(pthread_self());
254 Utility::setNonBlocking(fd
);
258 DLOG(L
<<"TCP Connection accepted on fd "<<fd
<<endl
);
259 bool logDNSQueries
= ::arg().mustDo("log-dns-queries");
262 socklen_t remotelen
=sizeof(remote
);
263 if(getpeername(fd
, (struct sockaddr
*)&remote
, &remotelen
) < 0) {
264 L
<<Logger::Error
<<"Received question from socket which had no remote address, dropping ("<<stringerror()<<")"<<endl
;
269 if(!readnWithTimeout(fd
, &pktlen
, 2, false))
272 pktlen
=ntohs(pktlen
);
274 // this check will always be false *if* no one touches
275 // the mesg array. pktlen can be maximum of 65535 as
276 // it is 2 byte unsigned variable. In getQuestion, we
277 // write to 0 up to pktlen-1 so 65535 is just right.
279 // do not remove this check as it will catch if someone
280 // decreases the mesg buffer size for some reason.
281 if(pktlen
>sizeof(mesg
)) {
282 L
<<Logger::Error
<<"Received an overly large question from "<<remote
.toString()<<", dropping"<<endl
;
286 getQuestion(fd
, mesg
, pktlen
, remote
);
287 S
.inc("tcp-queries");
289 packet
=shared_ptr
<DNSPacket
>(new DNSPacket
);
290 packet
->setRemote(&remote
);
292 packet
->setSocket(fd
);
293 if(packet
->parse(mesg
, pktlen
)<0)
296 if(packet
->qtype
.getCode()==QType::AXFR
) {
297 if(doAXFR(packet
->qdomain
, packet
, fd
))
298 S
.inc("tcp-answers");
302 if(packet
->qtype
.getCode()==QType::IXFR
) {
303 if(doIXFR(packet
, fd
))
304 S
.inc("tcp-answers");
308 shared_ptr
<DNSPacket
> reply
;
309 shared_ptr
<DNSPacket
> cached
= shared_ptr
<DNSPacket
>(new DNSPacket
);
312 if(packet
->hasEDNSSubnet())
313 remote
= packet
->getRemote() + "<-" + packet
->getRealRemote().toString();
315 remote
= packet
->getRemote();
316 L
<< Logger::Notice
<<"TCP Remote "<< remote
<<" wants '" << packet
->qdomain
<<"|"<<packet
->qtype
.getName() <<
317 "', do = " <<packet
->d_dnssecOk
<<", bufsize = "<< packet
->getMaxReplyLen()<<": ";
321 if(!packet
->d
.rd
&& packet
->couldBeCached() && PC
.get(packet
.get(), cached
.get(), false)) { // short circuit - does the PacketCache recognize this question?
323 L
<<"packetcache HIT"<<endl
;
324 cached
->setRemote(&packet
->d_remote
);
325 cached
->d
.id
=packet
->d
.id
;
326 cached
->d
.rd
=packet
->d
.rd
; // copy in recursion desired bit
327 cached
->commitD(); // commit d to the packet inlined
329 sendPacket(cached
, fd
); // presigned, don't do it again
330 S
.inc("tcp-answers");
334 L
<<"packetcache MISS"<<endl
;
338 L
<<Logger::Error
<<"TCP server is without backend connections, launching"<<endl
;
339 s_P
=new PacketHandler
;
343 reply
=shared_ptr
<DNSPacket
>(s_P
->questionOrRecurse(packet
.get(), &shouldRecurse
)); // we really need to ask the backend :-)
346 proxyQuestion(packet
);
351 if(!reply
) // unable to write an answer?
354 S
.inc("tcp-answers");
355 sendPacket(reply
, fd
);
358 catch(DBException
&e
) {
363 L
<<Logger::Error
<<"TCP Connection Thread unable to answer a question because of a backend error, cycling"<<endl
;
365 catch(PDNSException
&ae
) {
368 s_P
= 0; // on next call, backend will be recycled
369 L
<<Logger::Error
<<"TCP nameserver had error, cycling backend: "<<ae
.reason
<<endl
;
371 catch(NetworkError
&e
) {
372 L
<<Logger::Info
<<"TCP Connection Thread died because of network error: "<<e
.what()<<endl
;
375 catch(std::exception
&e
) {
376 L
<<Logger::Error
<<"TCP Connection Thread died because of STL error: "<<e
.what()<<endl
;
380 L
<< Logger::Error
<< "TCP Connection Thread caught unknown exception." << endl
;
382 d_connectionroom_sem
->post();
383 Utility::closesocket(fd
);
389 // call this method with s_plock held!
390 bool TCPNameserver::canDoAXFR(shared_ptr
<DNSPacket
> q
)
392 if(::arg().mustDo("disable-axfr"))
395 if(q
->d_havetsig
) { // if you have one, it must be good
396 TSIGRecordContent trc
;
397 string keyname
, secret
;
398 if(!checkForCorrectTSIG(q
.get(), s_P
->getBackend(), &keyname
, &secret
, &trc
))
403 if(!dk
.TSIGGrantsAccess(q
->qdomain
, keyname
, trc
.d_algoName
)) {
404 L
<<Logger::Error
<<"AXFR '"<<q
->qdomain
<<"' denied: key with name '"<<keyname
<<"' and algorithm '"<<trc
.d_algoName
<<"' does not grant access to zone"<<endl
;
408 L
<<Logger::Warning
<<"AXFR of domain '"<<q
->qdomain
<<"' allowed: TSIG signed request with authorized key '"<<keyname
<<"' and algorithm '"<<trc
.d_algoName
<<"'"<<endl
;
413 // cerr<<"checking allow-axfr-ips"<<endl;
414 if(!(::arg()["allow-axfr-ips"].empty()) && d_ng
.match( (ComboAddress
*) &q
->d_remote
)) {
415 L
<<Logger::Warning
<<"AXFR of domain '"<<q
->qdomain
<<"' allowed: client IP "<<q
->getRemote()<<" is in allow-axfr-ips"<<endl
;
421 // cerr<<"doing per-zone-axfr-acls"<<endl;
423 sd
.db
=(DNSBackend
*)-1;
424 if(s_P
->getBackend()->getSOA(q
->qdomain
,sd
)) {
425 // cerr<<"got backend and SOA"<<endl;
428 B
->getDomainMetadata(q
->qdomain
, "ALLOW-AXFR-FROM", acl
);
429 for (vector
<string
>::const_iterator i
= acl
.begin(); i
!= acl
.end(); ++i
) {
430 // cerr<<"matching against "<<*i<<endl;
431 if(pdns_iequals(*i
, "AUTO-NS")) {
432 // cerr<<"AUTO-NS magic please!"<<endl;
434 DNSResourceRecord rr
;
437 B
->lookup(QType(QType::NS
),q
->qdomain
);
439 nsset
.insert(rr
.content
);
440 for(set
<string
>::const_iterator j
=nsset
.begin();j
!=nsset
.end();++j
) {
441 vector
<string
> nsips
=fns
.lookup(*j
, B
);
442 for(vector
<string
>::const_iterator k
=nsips
.begin();k
!=nsips
.end();++k
) {
443 // cerr<<"got "<<*k<<" from AUTO-NS"<<endl;
444 if(*k
== q
->getRemote())
446 // cerr<<"got AUTO-NS hit"<<endl;
447 L
<<Logger::Warning
<<"AXFR of domain '"<<q
->qdomain
<<"' allowed: client IP "<<q
->getRemote()<<" is in NSset"<<endl
;
455 Netmask nm
= Netmask(*i
);
456 if(nm
.match( (ComboAddress
*) &q
->d_remote
))
458 L
<<Logger::Warning
<<"AXFR of domain '"<<q
->qdomain
<<"' allowed: client IP "<<q
->getRemote()<<" is in per-domain ACL"<<endl
;
459 // cerr<<"hit!"<<endl;
466 extern CommunicatorClass Communicator
;
468 if(Communicator
.justNotified(q
->qdomain
, q
->getRemote())) { // we just notified this ip
469 L
<<Logger::Warning
<<"Approved AXFR of '"<<q
->qdomain
<<"' from recently notified slave "<<q
->getRemote()<<endl
;
473 L
<<Logger::Error
<<"AXFR of domain '"<<q
->qdomain
<<"' denied: client IP "<<q
->getRemote()<<" has no permission"<<endl
;
485 DNSResourceRecord
makeDNSRRFromSOAData(const SOAData
& sd
)
487 DNSResourceRecord soa
;
489 soa
.qtype
=QType::SOA
;
490 soa
.content
=serializeSOAData(sd
);
492 soa
.domain_id
=sd
.domain_id
;
494 soa
.d_place
=DNSResourceRecord::ANSWER
;
498 shared_ptr
<DNSPacket
> getFreshAXFRPacket(shared_ptr
<DNSPacket
> q
)
500 shared_ptr
<DNSPacket
> ret
= shared_ptr
<DNSPacket
>(q
->replyPacket());
501 ret
->setCompress(false);
502 ret
->d_dnssecOk
=false; // RFC 5936, 2.2.5
509 /** do the actual zone transfer. Return 0 in case of error, 1 in case of success */
510 int TCPNameserver::doAXFR(const string
&target
, shared_ptr
<DNSPacket
> q
, int outsock
)
512 bool noAXFRBecauseOfNSEC3Narrow
=false;
513 NSEC3PARAMRecordContent ns3pr
;
515 bool NSEC3Zone
=false;
518 dk
.clearCaches(target
);
519 bool securedZone
= dk
.isSecuredZone(target
);
520 bool presignedZone
= dk
.isPresigned(target
);
522 if(dk
.getNSEC3PARAM(target
, &ns3pr
, &narrow
)) {
525 L
<<Logger::Error
<<"Not doing AXFR of an NSEC3 narrow zone.."<<endl
;
526 noAXFRBecauseOfNSEC3Narrow
=true;
530 shared_ptr
<DNSPacket
> outpacket
= getFreshAXFRPacket(q
);
532 outpacket
->d_dnssecOk
=true; // RFC 5936, 2.2.5 'SHOULD'
534 if(noAXFRBecauseOfNSEC3Narrow
) {
535 L
<<Logger::Error
<<"AXFR of domain '"<<target
<<"' denied to "<<q
->getRemote()<<endl
;
536 outpacket
->setRcode(RCode::Refused
);
537 // FIXME: should actually figure out if we are auth over a zone, and send out 9 if we aren't
538 sendPacket(outpacket
,outsock
);
542 L
<<Logger::Error
<<"AXFR of domain '"<<target
<<"' initiated by "<<q
->getRemote()<<endl
;
545 sd
.db
=(DNSBackend
*)-1; // force uncached answer
548 DLOG(L
<<"Looking for SOA"<<endl
); // find domain_id via SOA and list complete domain. No SOA, no AXFR
550 L
<<Logger::Error
<<"TCP server is without backend connections in doAXFR, launching"<<endl
;
551 s_P
=new PacketHandler
;
554 if(!s_P
->getBackend()->getSOA(target
, sd
) || !canDoAXFR(q
)) {
555 L
<<Logger::Error
<<"AXFR of domain '"<<target
<<"' failed: not authoritative"<<endl
;
556 outpacket
->setRcode(9); // 'NOTAUTH'
557 sendPacket(outpacket
,outsock
);
563 sd
.db
=(DNSBackend
*)-1; // force uncached answer
564 if(!db
.getSOA(target
, sd
)) {
565 L
<<Logger::Error
<<"AXFR of domain '"<<target
<<"' failed: not authoritative in second instance"<<endl
;
566 outpacket
->setRcode(9); // 'NOTAUTH'
567 sendPacket(outpacket
,outsock
);
571 if(!sd
.db
|| sd
.db
==(DNSBackend
*)-1) {
572 L
<<Logger::Error
<<"Error determining backend for domain '"<<target
<<"' trying to serve an AXFR"<<endl
;
573 outpacket
->setRcode(RCode::ServFail
);
574 sendPacket(outpacket
,outsock
);
578 TSIGRecordContent trc
;
579 string tsigkeyname
, tsigsecret
;
581 q
->getTSIGDetails(&trc
, &tsigkeyname
, 0);
583 if(!tsigkeyname
.empty()) {
584 string tsig64
, algorithm
;
586 s_P
->getBackend()->getTSIGKey(tsigkeyname
, &algorithm
, &tsig64
);
587 B64Decode(tsig64
, tsigsecret
);
591 UeberBackend signatureDB
;
593 // SOA *must* go out first, our signing pipe might reorder
594 DLOG(L
<<"Sending out SOA"<<endl
);
595 DNSResourceRecord soa
= makeDNSRRFromSOAData(sd
);
596 outpacket
->addRecord(soa
);
597 editSOA(dk
, sd
.qname
, outpacket
.get());
599 set
<string
, CIStringCompare
> authSet
;
600 authSet
.insert(target
);
601 addRRSigs(dk
, signatureDB
, authSet
, outpacket
->getRRS());
604 if(!tsigkeyname
.empty())
605 outpacket
->setTSIGDetails(trc
, tsigkeyname
, tsigsecret
, trc
.d_mac
); // first answer is 'normal'
607 sendPacket(outpacket
, outsock
);
609 trc
.d_mac
= outpacket
->d_trc
.d_mac
;
610 outpacket
= getFreshAXFRPacket(q
);
612 ChunkedSigningPipe
csp(target
, securedZone
, "", ::arg().asNum("signing-threads", 1));
614 typedef map
<string
, NSECXEntry
> nsecxrepo_t
;
615 nsecxrepo_t nsecxrepo
;
617 // this is where the DNSKEYs go in
619 DNSSECKeeper::keyset_t keys
= dk
.getKeys(target
);
621 DNSResourceRecord rr
;
624 rr
.ttl
= sd
.default_ttl
;
625 rr
.auth
= 1; // please sign!
627 BOOST_FOREACH(const DNSSECKeeper::keyset_t::value_type
& value
, keys
) {
628 rr
.qtype
= QType(QType::DNSKEY
);
629 rr
.content
= value
.first
.getDNSKEY().getZoneRepresentation();
630 string keyname
= NSEC3Zone
? hashQNameWithSalt(ns3pr
.d_iterations
, ns3pr
.d_salt
, rr
.qname
) : labelReverse(rr
.qname
);
631 NSECXEntry
& ne
= nsecxrepo
[keyname
];
633 ne
.d_set
.insert(rr
.qtype
.getCode());
634 ne
.d_ttl
= sd
.default_ttl
;
638 if(::arg().mustDo("direct-dnskey")) {
639 sd
.db
->lookup(QType(QType::DNSKEY
), target
, NULL
, sd
.domain_id
);
640 while(sd
.db
->get(rr
)) {
641 rr
.ttl
= sd
.default_ttl
;
648 if(NSEC3Zone
) { // now stuff in the NSEC3PARAM
649 flags
= ns3pr
.d_flags
;
650 rr
.qtype
= QType(QType::NSEC3PARAM
);
652 rr
.content
= ns3pr
.getZoneRepresentation();
653 ns3pr
.d_flags
= flags
;
654 string keyname
= hashQNameWithSalt(ns3pr
.d_iterations
, ns3pr
.d_salt
, rr
.qname
);
655 NSECXEntry
& ne
= nsecxrepo
[keyname
];
657 ne
.d_set
.insert(rr
.qtype
.getCode());
661 // now start list zone
662 if(!(sd
.db
->list(target
, sd
.domain_id
))) {
663 L
<<Logger::Error
<<"Backend signals error condition"<<endl
;
664 outpacket
->setRcode(2); // 'SERVFAIL'
665 sendPacket(outpacket
,outsock
);
670 const bool rectify
= !(presignedZone
|| ::arg().mustDo("disable-axfr-rectify"));
671 set
<string
> qnames
, nsset
, terms
;
672 vector
<DNSResourceRecord
> rrs
;
674 while(sd
.db
->get(rr
)) {
675 if(endsOn(rr
.qname
, target
)) {
677 if (rr
.qtype
.getCode()) {
678 qnames
.insert(rr
.qname
);
679 if(rr
.qtype
.getCode() == QType::NS
&& !pdns_iequals(rr
.qname
, target
))
680 nsset
.insert(rr
.qname
);
682 // remove existing ents
688 L
<<Logger::Warning
<<"Zone '"<<target
<<"' contains out-of-zone data '"<<rr
.qname
<<"'|"<<rr
.qtype
.getName()<<"', ignoring"<<endl
;
695 BOOST_FOREACH(DNSResourceRecord
&rr
, rrs
) {
697 if (rr
.qtype
.getCode() != QType::NS
|| !pdns_iequals(rr
.qname
, target
)) {
698 string
shorter(rr
.qname
);
700 if (pdns_iequals(shorter
, target
)) // apex is always auth
702 if(nsset
.count(shorter
) && !(pdns_iequals(rr
.qname
, shorter
) && rr
.qtype
.getCode() == QType::DS
))
704 } while(chopOff(shorter
));
710 // ents are only required for NSEC3 zones
711 uint32_t maxent
= ::arg().asNum("max-ent-entries");
712 map
<string
,bool> nonterm
;
713 BOOST_FOREACH(DNSResourceRecord
&rr
, rrs
) {
714 string
shorter(rr
.qname
);
715 while(!pdns_iequals(shorter
, target
) && chopOff(shorter
)) {
716 if(!qnames
.count(shorter
)) {
718 L
<<Logger::Warning
<<"Zone '"<<target
<<"' has too many empty non terminals."<<endl
;
721 if (!nonterm
.count(shorter
)) {
722 nonterm
.insert(pair
<string
, bool>(shorter
, rr
.auth
));
725 nonterm
[shorter
]=true;
730 pair
<string
,bool> nt
;
731 BOOST_FOREACH(nt
, nonterm
) {
732 DNSResourceRecord rr
;
735 rr
.auth
=(nt
.second
|| !ns3pr
.d_flags
);
742 /* now write all other records */
750 BOOST_FOREACH(DNSResourceRecord
&rr
, rrs
) {
751 if (rr
.qtype
.getCode() == QType::RRSIG
) {
752 RRSIGRecordContent
rrc(rr
.content
);
753 if(presignedZone
&& rrc
.d_type
== QType::NSEC3
)
754 ns3rrs
.insert(fromBase32Hex(makeRelative(rr
.qname
, target
)));
758 // only skip the DNSKEY if direct-dnskey is enabled, to avoid changing behaviour
759 // when it is not enabled.
760 if(::arg().mustDo("direct-dnskey") && rr
.qtype
.getCode() == QType::DNSKEY
)
764 if(securedZone
&& (rr
.auth
|| rr
.qtype
.getCode() == QType::NS
)) {
765 if (NSEC3Zone
|| rr
.qtype
.getCode()) {
766 keyname
= NSEC3Zone
? hashQNameWithSalt(ns3pr
.d_iterations
, ns3pr
.d_salt
, rr
.qname
) : labelReverse(rr
.qname
);
767 NSECXEntry
& ne
= nsecxrepo
[keyname
];
768 ne
.d_ttl
= sd
.default_ttl
;
769 ne
.d_auth
= (ne
.d_auth
|| rr
.auth
|| (NSEC3Zone
&& (!ns3pr
.d_flags
|| (presignedZone
&& ns3pr
.d_flags
))));
770 if (rr
.qtype
.getCode()) {
771 ne
.d_set
.insert(rr
.qtype
.getCode());
776 if (!rr
.qtype
.getCode())
777 continue; // skip empty non-terminals
779 if(rr
.qtype
.getCode() == QType::SOA
)
780 continue; // skip SOA - would indicate end of AXFR
784 outpacket
->getRRS() = csp
.getChunk();
785 if(!outpacket
->getRRS().empty()) {
786 if(!tsigkeyname
.empty())
787 outpacket
->setTSIGDetails(trc
, tsigkeyname
, tsigsecret
, trc
.d_mac
, true);
788 sendPacket(outpacket
, outsock
);
789 trc
.d_mac
=outpacket
->d_trc
.d_mac
;
790 outpacket
=getFreshAXFRPacket(q
);
798 udiff=dt.udiffNoReset();
799 cerr<<"Starting NSEC: "<<csp.d_signed/(udiff/1000000.0)<<" sigs/s, "<<csp.d_signed<<" / "<<udiff/1000000.0<<endl;
800 cerr<<"Outstanding: "<<csp.d_outstanding<<", "<<csp.d_queued - csp.d_signed << endl;
801 cerr<<"Ready for consumption: "<<csp.getReady()<<endl;
805 for(nsecxrepo_t::const_iterator iter
= nsecxrepo
.begin(); iter
!= nsecxrepo
.end(); ++iter
) {
806 if(iter
->second
.d_auth
&& (!presignedZone
|| !ns3pr
.d_flags
|| ns3rrs
.count(iter
->first
))) {
807 NSEC3RecordContent n3rc
;
808 n3rc
.d_set
= iter
->second
.d_set
;
809 if (n3rc
.d_set
.size() && (n3rc
.d_set
.size() != 1 || !n3rc
.d_set
.count(QType::NS
)))
810 n3rc
.d_set
.insert(QType::RRSIG
);
811 n3rc
.d_salt
=ns3pr
.d_salt
;
812 n3rc
.d_flags
= ns3pr
.d_flags
;
813 n3rc
.d_iterations
= ns3pr
.d_iterations
;
814 n3rc
.d_algorithm
= 1; // SHA1, fixed in PowerDNS for now
815 nsecxrepo_t::const_iterator inext
= iter
;
817 if(inext
== nsecxrepo
.end())
818 inext
= nsecxrepo
.begin();
819 while((!inext
->second
.d_auth
|| (presignedZone
&& ns3pr
.d_flags
&& !ns3rrs
.count(inext
->first
))) && inext
!= iter
)
822 if(inext
== nsecxrepo
.end())
823 inext
= nsecxrepo
.begin();
825 n3rc
.d_nexthash
= inext
->first
;
826 rr
.qname
= dotConcat(toBase32Hex(iter
->first
), sd
.qname
);
828 rr
.ttl
= sd
.default_ttl
;
829 rr
.content
= n3rc
.getZoneRepresentation();
830 rr
.qtype
= QType::NSEC3
;
831 rr
.d_place
= DNSResourceRecord::ANSWER
;
835 outpacket
->getRRS() = csp
.getChunk();
836 if(!outpacket
->getRRS().empty()) {
837 if(!tsigkeyname
.empty())
838 outpacket
->setTSIGDetails(trc
, tsigkeyname
, tsigsecret
, trc
.d_mac
, true);
839 sendPacket(outpacket
, outsock
);
840 trc
.d_mac
=outpacket
->d_trc
.d_mac
;
841 outpacket
=getFreshAXFRPacket(q
);
850 else for(nsecxrepo_t::const_iterator iter
= nsecxrepo
.begin(); iter
!= nsecxrepo
.end(); ++iter
) {
851 NSECRecordContent nrc
;
852 nrc
.d_set
= iter
->second
.d_set
;
853 nrc
.d_set
.insert(QType::RRSIG
);
854 nrc
.d_set
.insert(QType::NSEC
);
855 if(boost::next(iter
) != nsecxrepo
.end()) {
856 nrc
.d_next
= labelReverse(boost::next(iter
)->first
);
859 nrc
.d_next
=labelReverse(nsecxrepo
.begin()->first
);
861 rr
.qname
= labelReverse(iter
->first
);
863 rr
.ttl
= sd
.default_ttl
;
864 rr
.content
= nrc
.getZoneRepresentation();
865 rr
.qtype
= QType::NSEC
;
866 rr
.d_place
= DNSResourceRecord::ANSWER
;
870 outpacket
->getRRS() = csp
.getChunk();
871 if(!outpacket
->getRRS().empty()) {
872 if(!tsigkeyname
.empty())
873 outpacket
->setTSIGDetails(trc
, tsigkeyname
, tsigsecret
, trc
.d_mac
, true);
874 sendPacket(outpacket
, outsock
);
875 trc
.d_mac
=outpacket
->d_trc
.d_mac
;
876 outpacket
=getFreshAXFRPacket(q
);
885 udiff=dt.udiffNoReset();
886 cerr<<"Flushing pipe: "<<csp.d_signed/(udiff/1000000.0)<<" sigs/s, "<<csp.d_signed<<" / "<<udiff/1000000.0<<endl;
887 cerr<<"Outstanding: "<<csp.d_outstanding<<", "<<csp.d_queued - csp.d_signed << endl;
888 cerr<<"Ready for consumption: "<<csp.getReady()<<endl;
891 outpacket
->getRRS() = csp
.getChunk(true); // flush the pipe
892 if(!outpacket
->getRRS().empty()) {
893 if(!tsigkeyname
.empty())
894 outpacket
->setTSIGDetails(trc
, tsigkeyname
, tsigsecret
, trc
.d_mac
, true); // first answer is 'normal'
895 sendPacket(outpacket
, outsock
);
896 trc
.d_mac
=outpacket
->d_trc
.d_mac
;
897 outpacket
=getFreshAXFRPacket(q
);
903 udiff
=dt
.udiffNoReset();
905 L
<<Logger::Info
<<"Done signing: "<<csp
.d_signed
/(udiff
/1000000.0)<<" sigs/s, "<<endl
;
907 DLOG(L
<<"Done writing out records"<<endl
);
908 /* and terminate with yet again the SOA record */
909 outpacket
=getFreshAXFRPacket(q
);
910 outpacket
->addRecord(soa
);
911 editSOA(dk
, sd
.qname
, outpacket
.get());
912 if(!tsigkeyname
.empty())
913 outpacket
->setTSIGDetails(trc
, tsigkeyname
, tsigsecret
, trc
.d_mac
, true);
915 sendPacket(outpacket
, outsock
);
917 DLOG(L
<<"last packet - close"<<endl
);
918 L
<<Logger::Error
<<"AXFR of domain '"<<target
<<"' to "<<q
->getRemote()<<" finished"<<endl
;
923 int TCPNameserver::doIXFR(shared_ptr
<DNSPacket
> q
, int outsock
)
925 shared_ptr
<DNSPacket
> outpacket
=getFreshAXFRPacket(q
);
927 outpacket
->d_dnssecOk
=true; // RFC 5936, 2.2.5 'SHOULD'
930 NSEC3PARAMRecordContent ns3pr
;
933 dk
.clearCaches(q
->qdomain
);
934 bool securedZone
= dk
.isSecuredZone(q
->qdomain
);
935 if(dk
.getNSEC3PARAM(q
->qdomain
, &ns3pr
, &narrow
)) {
937 L
<<Logger::Error
<<"Not doing IXFR of an NSEC3 narrow zone."<<endl
;
938 L
<<Logger::Error
<<"IXFR of domain '"<<q
->qdomain
<<"' denied to "<<q
->getRemote()<<endl
;
939 outpacket
->setRcode(RCode::Refused
);
940 sendPacket(outpacket
,outsock
);
946 MOADNSParser
mdp(q
->getString());
947 for(MOADNSParser::answers_t::const_iterator i
=mdp
.d_answers
.begin(); i
!= mdp
.d_answers
.end(); ++i
) {
948 const DNSRecord
*rr
= &i
->first
;
949 if (rr
->d_type
== QType::SOA
&& rr
->d_place
== DNSRecord::Nameserver
) {
951 stringtok(parts
, rr
->d_content
->getZoneRepresentation());
952 if (parts
.size() >= 3) {
953 serial
=atoi(parts
[2].c_str());
955 L
<<Logger::Error
<<"No serial in IXFR query"<<endl
;
956 outpacket
->setRcode(RCode::FormErr
);
957 sendPacket(outpacket
,outsock
);
961 L
<<Logger::Error
<<"Additional records in IXFR query"<<endl
;
962 outpacket
->setRcode(RCode::FormErr
);
963 sendPacket(outpacket
,outsock
);
968 L
<<Logger::Error
<<"IXFR of domain '"<<q
->qdomain
<<"' initiated by "<<q
->getRemote()<<" with serial "<<serial
<<endl
;
971 sd
.db
=(DNSBackend
*)-1; // force uncached answer
974 DLOG(L
<<"Looking for SOA"<<endl
); // find domain_id via SOA and list complete domain. No SOA, no IXFR
976 L
<<Logger::Error
<<"TCP server is without backend connections in doIXFR, launching"<<endl
;
977 s_P
=new PacketHandler
;
980 if(!s_P
->getBackend()->getSOA(q
->qdomain
, sd
)) {
981 L
<<Logger::Error
<<"IXFR of domain '"<<q
->qdomain
<<"' failed: not authoritative"<<endl
;
982 outpacket
->setRcode(9); // 'NOTAUTH'
983 sendPacket(outpacket
,outsock
);
988 string target
= q
->qdomain
;
991 sd
.db
=(DNSBackend
*)-1; // force uncached answer
992 if(!db
.getSOA(target
, sd
)) {
993 L
<<Logger::Error
<<"IXFR of domain '"<<target
<<"' failed: not authoritative in second instance"<<endl
;
994 outpacket
->setRcode(9); // 'NOTAUTH'
995 sendPacket(outpacket
,outsock
);
999 if(!sd
.db
|| sd
.db
==(DNSBackend
*)-1) {
1000 L
<<Logger::Error
<<"Error determining backend for domain '"<<target
<<"' trying to serve an IXFR"<<endl
;
1001 outpacket
->setRcode(RCode::ServFail
);
1002 sendPacket(outpacket
,outsock
);
1005 if (!rfc1982LessThan(serial
, sd
.serial
)) {
1006 TSIGRecordContent trc
;
1007 string tsigkeyname
, tsigsecret
;
1009 q
->getTSIGDetails(&trc
, &tsigkeyname
, 0);
1011 if(!tsigkeyname
.empty()) {
1012 string tsig64
, algorithm
;
1014 s_P
->getBackend()->getTSIGKey(tsigkeyname
, &algorithm
, &tsig64
);
1015 B64Decode(tsig64
, tsigsecret
);
1018 UeberBackend signatureDB
;
1020 // SOA *must* go out first, our signing pipe might reorder
1021 DLOG(L
<<"Sending out SOA"<<endl
);
1022 DNSResourceRecord soa
= makeDNSRRFromSOAData(sd
);
1023 outpacket
->addRecord(soa
);
1024 editSOA(dk
, sd
.qname
, outpacket
.get());
1026 set
<string
, CIStringCompare
> authSet
;
1027 authSet
.insert(target
);
1028 addRRSigs(dk
, signatureDB
, authSet
, outpacket
->getRRS());
1031 if(!tsigkeyname
.empty())
1032 outpacket
->setTSIGDetails(trc
, tsigkeyname
, tsigsecret
, trc
.d_mac
); // first answer is 'normal'
1034 sendPacket(outpacket
, outsock
);
1036 L
<<Logger::Error
<<"IXFR of domain '"<<target
<<"' to "<<q
->getRemote()<<" finished"<<endl
;
1041 L
<<Logger::Error
<<"IXFR fallback to AXFR for domain '"<<target
<<"' our serial "<<sd
.serial
<<endl
;
1042 return doAXFR(q
->qdomain
, q
, outsock
);
1045 TCPNameserver::~TCPNameserver()
1047 delete d_connectionroom_sem
;
1050 TCPNameserver::TCPNameserver()
1052 // sem_init(&d_connectionroom_sem,0,::arg().asNum("max-tcp-connections"));
1053 d_connectionroom_sem
= new Semaphore( ::arg().asNum( "max-tcp-connections" ));
1056 vector
<string
>locals
;
1057 stringtok(locals
,::arg()["local-address"]," ,");
1059 vector
<string
>locals6
;
1060 stringtok(locals6
,::arg()["local-ipv6"]," ,");
1062 if(locals
.empty() && locals6
.empty())
1063 throw PDNSException("No local address specified");
1065 d_ng
.toMasks(::arg()["allow-axfr-ips"] );
1067 signal(SIGPIPE
,SIG_IGN
);
1069 for(vector
<string
>::const_iterator laddr
=locals
.begin();laddr
!=locals
.end();++laddr
) {
1070 int s
=socket(AF_INET
,SOCK_STREAM
,0);
1073 throw PDNSException("Unable to acquire TCP socket: "+stringerror());
1075 Utility::setCloseOnExec(s
);
1077 ComboAddress
local(*laddr
, ::arg().asNum("local-port"));
1080 if(setsockopt(s
,SOL_SOCKET
,SO_REUSEADDR
,(char*)&tmp
,sizeof tmp
)<0) {
1081 L
<<Logger::Error
<<"Setsockopt failed"<<endl
;
1085 if(::bind(s
, (sockaddr
*)&local
, local
.getSocklen())<0) {
1087 if( errno
== EADDRNOTAVAIL
&& ! ::arg().mustDo("local-address-nonexist-fail") ) {
1088 L
<<Logger::Error
<<"IPv4 Address " << *laddr
<< " does not exist on this server - skipping TCP bind" << endl
;
1091 L
<<Logger::Error
<<"binding to TCP socket " << *laddr
<< ": "<<strerror(errno
)<<endl
;
1092 throw PDNSException("Unable to bind to TCP socket");
1097 L
<<Logger::Error
<<"TCP server bound to "<<local
.toStringWithPort()<<endl
;
1098 d_sockets
.push_back(s
);
1100 memset(&pfd
, 0, sizeof(pfd
));
1102 pfd
.events
= POLLIN
;
1104 d_prfds
.push_back(pfd
);
1108 for(vector
<string
>::const_iterator laddr
=locals6
.begin();laddr
!=locals6
.end();++laddr
) {
1109 int s
=socket(AF_INET6
,SOCK_STREAM
,0);
1112 throw PDNSException("Unable to acquire TCPv6 socket: "+stringerror());
1114 Utility::setCloseOnExec(s
);
1116 ComboAddress
local(*laddr
, ::arg().asNum("local-port"));
1119 if(setsockopt(s
,SOL_SOCKET
,SO_REUSEADDR
,(char*)&tmp
,sizeof tmp
)<0) {
1120 L
<<Logger::Error
<<"Setsockopt failed"<<endl
;
1123 if(setsockopt(s
, IPPROTO_IPV6
, IPV6_V6ONLY
, &tmp
, sizeof(tmp
)) < 0) {
1124 L
<<Logger::Error
<<"Failed to set IPv6 socket to IPv6 only, continuing anyhow: "<<strerror(errno
)<<endl
;
1126 if(bind(s
, (const sockaddr
*)&local
, local
.getSocklen())<0) {
1128 if( errno
== EADDRNOTAVAIL
&& ! ::arg().mustDo("local-ipv6-nonexist-fail") ) {
1129 L
<<Logger::Error
<<"IPv6 Address " << *laddr
<< " does not exist on this server - skipping TCP bind" << endl
;
1132 L
<<Logger::Error
<<"binding to TCPv6 socket" << *laddr
<< ": "<<strerror(errno
)<<endl
;
1133 throw PDNSException("Unable to bind to TCPv6 socket");
1138 L
<<Logger::Error
<<"TCPv6 server bound to "<<local
.toStringWithPort()<<endl
; // this gets %eth0 right
1139 d_sockets
.push_back(s
);
1142 memset(&pfd
, 0, sizeof(pfd
));
1144 pfd
.events
= POLLIN
;
1146 d_prfds
.push_back(pfd
);
1152 //! Start of TCP operations thread, we launch a new thread for each incoming TCP question
1153 void TCPNameserver::thread()
1158 struct sockaddr_in remote
;
1159 Utility::socklen_t addrlen
=sizeof(remote
);
1161 int ret
=poll(&d_prfds
[0], d_prfds
.size(), -1); // blocks, forever if need be
1166 BOOST_FOREACH(const struct pollfd
& pfd
, d_prfds
) {
1167 if(pfd
.revents
== POLLIN
) {
1169 addrlen
=sizeof(remote
);
1171 if((fd
=accept(sock
, (sockaddr
*)&remote
, &addrlen
))<0) {
1172 L
<<Logger::Error
<<"TCP question accept error: "<<strerror(errno
)<<endl
;
1175 L
<<Logger::Error
<<Logger::NTLog
<<"TCP handler out of filedescriptors, exiting, won't recover from this"<<endl
;
1181 d_connectionroom_sem
->wait(); // blocks if no connections are available
1184 d_connectionroom_sem
->getValue( &room
);
1186 L
<<Logger::Warning
<<Logger::NTLog
<<"Limit of simultaneous TCP connections reached - raise max-tcp-connections"<<endl
;
1188 if(pthread_create(&tid
, 0, &doConnection
, reinterpret_cast<void*>(fd
))) {
1189 L
<<Logger::Error
<<"Error creating thread: "<<stringerror()<<endl
;
1190 d_connectionroom_sem
->post();
1197 catch(PDNSException
&AE
) {
1198 L
<<Logger::Error
<<"TCP Nameserver thread dying because of fatal error: "<<AE
.reason
<<endl
;
1201 L
<<Logger::Error
<<"TCPNameserver dying because of an unexpected fatal error"<<endl
;
1203 exit(1); // take rest of server with us