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
25 #include <boost/algorithm/string.hpp>
26 #include "auth-packetcache.hh"
28 #include "threadname.hh"
29 #include "dnssecinfra.hh"
30 #include "dnsseckeeper.hh"
35 #include <sys/types.h>
36 #include <netinet/tcp.h>
39 #include "tcpreceiver.hh"
45 #include "ueberbackend.hh"
46 #include "dnspacket.hh"
47 #include "nameserver.hh"
48 #include "distributor.hh"
51 #include "arguments.hh"
53 #include "common_startup.hh"
54 #include "packethandler.hh"
56 #include "resolver.hh"
57 #include "communicator.hh"
58 #include "namespaces.hh"
59 #include "signingpipe.hh"
60 #include "stubresolver.hh"
61 extern AuthPacketCache PC
;
66 \brief This file implements the tcpreceiver that receives and answers questions over TCP/IP
69 pthread_mutex_t
TCPNameserver::s_plock
= PTHREAD_MUTEX_INITIALIZER
;
70 Semaphore
*TCPNameserver::d_connectionroom_sem
;
71 PacketHandler
*TCPNameserver::s_P
;
72 NetmaskGroup
TCPNameserver::d_ng
;
73 size_t TCPNameserver::d_maxTransactionsPerConn
;
74 size_t TCPNameserver::d_maxConnectionsPerClient
;
75 unsigned int TCPNameserver::d_idleTimeout
;
76 unsigned int TCPNameserver::d_maxConnectionDuration
;
77 std::mutex
TCPNameserver::s_clientsCountMutex
;
78 std::map
<ComboAddress
,size_t,ComboAddress::addressOnlyLessThan
> TCPNameserver::s_clientsCount
;
80 void TCPNameserver::go()
82 g_log
<<Logger::Error
<<"Creating backend connection for TCP"<<endl
;
85 s_P
=new PacketHandler
;
87 catch(PDNSException
&ae
) {
88 g_log
<<Logger::Error
<<"TCP server is unable to launch backends - will try again when questions come in: "<<ae
.reason
<<endl
;
90 pthread_create(&d_tid
, 0, launcher
, static_cast<void *>(this));
93 void *TCPNameserver::launcher(void *data
)
95 static_cast<TCPNameserver
*>(data
)->thread();
99 // throws PDNSException if things didn't go according to plan, returns 0 if really 0 bytes were read
100 static int readnWithTimeout(int fd
, void* buffer
, unsigned int n
, unsigned int idleTimeout
, bool throwOnEOF
=true, unsigned int totalTimeout
=0)
102 unsigned int bytes
=n
;
103 char *ptr
= (char*)buffer
;
106 unsigned int remainingTotal
= totalTimeout
;
111 ret
=read(fd
, ptr
, bytes
);
114 ret
=waitForData(fd
, (totalTimeout
== 0 || idleTimeout
<= remainingTotal
) ? idleTimeout
: remainingTotal
);
116 throw NetworkError("Waiting for data read");
118 throw NetworkError("Timeout reading data");
122 throw NetworkError("Reading data: "+stringerror());
125 if(!throwOnEOF
&& n
== bytes
)
128 throw NetworkError("Did not fulfill read from TCP due to EOF");
134 time_t now
= time(NULL
);
135 unsigned int elapsed
= now
- start
;
136 if (elapsed
>= remainingTotal
) {
137 throw NetworkError("Timeout while reading data");
140 remainingTotal
-= elapsed
;
147 static void writenWithTimeout(int fd
, const void *buffer
, unsigned int n
, unsigned int idleTimeout
)
149 unsigned int bytes
=n
;
150 const char *ptr
= (char*)buffer
;
153 ret
=write(fd
, ptr
, bytes
);
156 ret
=waitForRWData(fd
, false, idleTimeout
, 0);
158 throw NetworkError("Waiting for data write");
160 throw NetworkError("Timeout writing data");
164 throw NetworkError("Writing data: "+stringerror());
167 throw NetworkError("Did not fulfill TCP write due to EOF");
175 void connectWithTimeout(int fd
, struct sockaddr
* remote
, size_t socklen
)
178 Utility::socklen_t len
=sizeof(err
);
180 if((err
=connect(fd
, remote
, socklen
))<0 && errno
!=EINPROGRESS
)
181 throw NetworkError("connect: "+stringerror());
186 err
=waitForRWData(fd
, false, 5, 0);
188 throw NetworkError("Timeout connecting to remote");
190 throw NetworkError("Error connecting to remote");
192 if(getsockopt(fd
, SOL_SOCKET
,SO_ERROR
,(char *)&err
,&len
)<0)
193 throw NetworkError("Error connecting to remote: "+stringerror()); // Solaris
196 throw NetworkError("Error connecting to remote: "+string(strerror(err
)));
202 void TCPNameserver::sendPacket(shared_ptr
<DNSPacket
> p
, int outsock
)
204 g_rs
.submitResponse(*p
, false);
206 uint16_t len
=htons(p
->getString().length());
207 string
buffer((const char*)&len
, 2);
208 buffer
.append(p
->getString());
209 writenWithTimeout(outsock
, buffer
.c_str(), buffer
.length(), d_idleTimeout
);
213 void TCPNameserver::getQuestion(int fd
, char *mesg
, int pktlen
, const ComboAddress
&remote
, unsigned int totalTime
)
216 readnWithTimeout(fd
, mesg
, pktlen
, d_idleTimeout
, true, totalTime
);
218 catch(NetworkError
& ae
) {
219 throw NetworkError("Error reading DNS data from TCP client "+remote
.toString()+": "+ae
.what());
222 static void incTCPAnswerCount(const ComboAddress
& remote
)
224 S
.inc("tcp-answers");
225 if(remote
.sin4
.sin_family
== AF_INET6
)
226 S
.inc("tcp6-answers");
228 S
.inc("tcp4-answers");
231 static bool maxConnectionDurationReached(unsigned int maxConnectionDuration
, time_t start
, unsigned int& remainingTime
)
233 if (maxConnectionDuration
) {
234 time_t elapsed
= time(NULL
) - start
;
235 if (elapsed
>= maxConnectionDuration
) {
238 remainingTime
= maxConnectionDuration
- elapsed
;
243 void TCPNameserver::decrementClientCount(const ComboAddress
& remote
)
245 if (d_maxConnectionsPerClient
) {
246 std::lock_guard
<std::mutex
> lock(s_clientsCountMutex
);
247 s_clientsCount
[remote
]--;
248 if (s_clientsCount
[remote
] == 0) {
249 s_clientsCount
.erase(remote
);
254 void *TCPNameserver::doConnection(void *data
)
256 setThreadName("pdns/tcpConnect");
257 shared_ptr
<DNSPacket
> packet
;
258 // Fix gcc-4.0 error (on AMD64)
259 int fd
=(int)(long)data
; // gotta love C (generates a harmless warning on opteron)
261 socklen_t remotelen
=sizeof(remote
);
262 size_t transactions
= 0;
264 if (d_maxConnectionDuration
) {
268 pthread_detach(pthread_self());
269 if(getpeername(fd
, (struct sockaddr
*)&remote
, &remotelen
) < 0) {
270 g_log
<<Logger::Warning
<<"Received question from socket which had no remote address, dropping ("<<stringerror()<<")"<<endl
;
271 d_connectionroom_sem
->post();
275 catch(const PDNSException
& e
) {
276 g_log
<<Logger::Error
<<"Error closing TCP socket: "<<e
.reason
<<endl
;
284 scoped_array
<char> mesg(new char[mesgsize
]);
286 DLOG(g_log
<<"TCP Connection accepted on fd "<<fd
<<endl
);
287 bool logDNSQueries
= ::arg().mustDo("log-dns-queries");
289 unsigned int remainingTime
= 0;
291 if (d_maxTransactionsPerConn
&& transactions
> d_maxTransactionsPerConn
) {
292 g_log
<< Logger::Notice
<<"TCP Remote "<< remote
<<" exceeded the number of transactions per connection, dropping.";
295 if (maxConnectionDurationReached(d_maxConnectionDuration
, start
, remainingTime
)) {
296 g_log
<< Logger::Notice
<<"TCP Remote "<< remote
<<" exceeded the maximum TCP connection duration, dropping.";
301 if(!readnWithTimeout(fd
, &pktlen
, 2, d_idleTimeout
, false, remainingTime
))
304 pktlen
=ntohs(pktlen
);
306 // this check will always be false *if* no one touches
307 // the mesg array. pktlen can be maximum of 65535 as
308 // it is 2 byte unsigned variable. In getQuestion, we
309 // write to 0 up to pktlen-1 so 65535 is just right.
311 // do not remove this check as it will catch if someone
312 // decreases the mesg buffer size for some reason.
313 if(pktlen
> mesgsize
) {
314 g_log
<<Logger::Warning
<<"Received an overly large question from "<<remote
.toString()<<", dropping"<<endl
;
318 if (maxConnectionDurationReached(d_maxConnectionDuration
, start
, remainingTime
)) {
319 g_log
<< Logger::Notice
<<"TCP Remote "<< remote
<<" exceeded the maximum TCP connection duration, dropping.";
323 getQuestion(fd
, mesg
.get(), pktlen
, remote
, remainingTime
);
324 S
.inc("tcp-queries");
325 if(remote
.sin4
.sin_family
== AF_INET6
)
326 S
.inc("tcp6-queries");
328 S
.inc("tcp4-queries");
330 packet
=shared_ptr
<DNSPacket
>(new DNSPacket(true));
331 packet
->setRemote(&remote
);
333 packet
->setSocket(fd
);
334 if(packet
->parse(mesg
.get(), pktlen
)<0)
337 if(packet
->qtype
.getCode()==QType::AXFR
) {
338 if(doAXFR(packet
->qdomain
, packet
, fd
))
339 incTCPAnswerCount(remote
);
343 if(packet
->qtype
.getCode()==QType::IXFR
) {
344 if(doIXFR(packet
, fd
))
345 incTCPAnswerCount(remote
);
349 shared_ptr
<DNSPacket
> reply
;
350 shared_ptr
<DNSPacket
> cached
= shared_ptr
<DNSPacket
>(new DNSPacket(false));
353 if(packet
->hasEDNSSubnet())
354 remote_text
= packet
->getRemote().toString() + "<-" + packet
->getRealRemote().toString();
356 remote_text
= packet
->getRemote().toString();
357 g_log
<< Logger::Notice
<<"TCP Remote "<< remote_text
<<" wants '" << packet
->qdomain
<<"|"<<packet
->qtype
.getName() <<
358 "', do = " <<packet
->d_dnssecOk
<<", bufsize = "<< packet
->getMaxReplyLen()<<": ";
362 if(packet
->couldBeCached() && PC
.get(packet
.get(), cached
.get())) { // short circuit - does the PacketCache recognize this question?
364 g_log
<<"packetcache HIT"<<endl
;
365 cached
->setRemote(&packet
->d_remote
);
366 cached
->d
.id
=packet
->d
.id
;
367 cached
->d
.rd
=packet
->d
.rd
; // copy in recursion desired bit
368 cached
->commitD(); // commit d to the packet inlined
370 sendPacket(cached
, fd
); // presigned, don't do it again
374 g_log
<<"packetcache MISS"<<endl
;
379 g_log
<<Logger::Error
<<"TCP server is without backend connections, launching"<<endl
;
380 s_P
=new PacketHandler
;
383 reply
=shared_ptr
<DNSPacket
>(s_P
->doQuestion(packet
.get())); // we really need to ask the backend :-)
386 if(!reply
) // unable to write an answer?
389 sendPacket(reply
, fd
);
392 catch(PDNSException
&ae
) {
395 s_P
= 0; // on next call, backend will be recycled
396 g_log
<<Logger::Error
<<"TCP nameserver had error, cycling backend: "<<ae
.reason
<<endl
;
398 catch(NetworkError
&e
) {
399 g_log
<<Logger::Info
<<"TCP Connection Thread died because of network error: "<<e
.what()<<endl
;
402 catch(std::exception
&e
) {
403 g_log
<<Logger::Error
<<"TCP Connection Thread died because of STL error: "<<e
.what()<<endl
;
407 g_log
<< Logger::Error
<< "TCP Connection Thread caught unknown exception." << endl
;
409 d_connectionroom_sem
->post();
414 catch(const PDNSException
& e
) {
415 g_log
<<Logger::Error
<<"Error closing TCP socket: "<<e
.reason
<<endl
;
417 decrementClientCount(remote
);
423 // call this method with s_plock held!
424 bool TCPNameserver::canDoAXFR(shared_ptr
<DNSPacket
> q
)
426 if(::arg().mustDo("disable-axfr"))
429 if(q
->d_havetsig
) { // if you have one, it must be good
430 TSIGRecordContent trc
;
433 if(!q
->checkForCorrectTSIG(s_P
->getBackend(), &keyname
, &secret
, &trc
)) {
436 getTSIGHashEnum(trc
.d_algoName
, q
->d_tsig_algo
);
437 if (q
->d_tsig_algo
== TSIG_GSS
) {
438 GssContext
gssctx(keyname
);
439 if (!gssctx
.getPeerPrincipal(q
->d_peer_principal
)) {
440 g_log
<<Logger::Warning
<<"Failed to extract peer principal from GSS context with keyname '"<<keyname
<<"'"<<endl
;
445 DNSSECKeeper
dk(s_P
->getBackend());
447 if (q
->d_tsig_algo
== TSIG_GSS
) {
448 vector
<string
> princs
;
449 s_P
->getBackend()->getDomainMetadata(q
->qdomain
, "GSS-ALLOW-AXFR-PRINCIPAL", princs
);
450 for(const std::string
& princ
: princs
) {
451 if (q
->d_peer_principal
== princ
) {
452 g_log
<<Logger::Warning
<<"AXFR of domain '"<<q
->qdomain
<<"' allowed: TSIG signed request with authorized principal '"<<q
->d_peer_principal
<<"' and algorithm 'gss-tsig'"<<endl
;
456 g_log
<<Logger::Warning
<<"AXFR of domain '"<<q
->qdomain
<<"' denied: TSIG signed request with principal '"<<q
->d_peer_principal
<<"' and algorithm 'gss-tsig' is not permitted"<<endl
;
460 if(!dk
.TSIGGrantsAccess(q
->qdomain
, keyname
)) {
461 g_log
<<Logger::Error
<<"AXFR '"<<q
->qdomain
<<"' denied: key with name '"<<keyname
<<"' and algorithm '"<<getTSIGAlgoName(q
->d_tsig_algo
)<<"' does not grant access to zone"<<endl
;
465 g_log
<<Logger::Warning
<<"AXFR of domain '"<<q
->qdomain
<<"' allowed: TSIG signed request with authorized key '"<<keyname
<<"' and algorithm '"<<getTSIGAlgoName(q
->d_tsig_algo
)<<"'"<<endl
;
470 // cerr<<"checking allow-axfr-ips"<<endl;
471 if(!(::arg()["allow-axfr-ips"].empty()) && d_ng
.match( (ComboAddress
*) &q
->d_remote
)) {
472 g_log
<<Logger::Warning
<<"AXFR of domain '"<<q
->qdomain
<<"' allowed: client IP "<<q
->getRemote()<<" is in allow-axfr-ips"<<endl
;
478 // cerr<<"doing per-zone-axfr-acls"<<endl;
480 if(s_P
->getBackend()->getSOAUncached(q
->qdomain
,sd
)) {
481 // cerr<<"got backend and SOA"<<endl;
484 s_P
->getBackend()->getDomainMetadata(q
->qdomain
, "ALLOW-AXFR-FROM", acl
);
485 for (vector
<string
>::const_iterator i
= acl
.begin(); i
!= acl
.end(); ++i
) {
486 // cerr<<"matching against "<<*i<<endl;
487 if(pdns_iequals(*i
, "AUTO-NS")) {
488 // cerr<<"AUTO-NS magic please!"<<endl;
490 DNSResourceRecord rr
;
493 B
->lookup(QType(QType::NS
),q
->qdomain
);
495 nsset
.insert(DNSName(rr
.content
));
496 for(const auto & j
: nsset
) {
497 vector
<string
> nsips
=fns
.lookup(j
, s_P
->getBackend(),q
->qdomain
);
498 for(vector
<string
>::const_iterator k
=nsips
.begin();k
!=nsips
.end();++k
) {
499 // cerr<<"got "<<*k<<" from AUTO-NS"<<endl;
500 if(*k
== q
->getRemote().toString())
502 // cerr<<"got AUTO-NS hit"<<endl;
503 g_log
<<Logger::Warning
<<"AXFR of domain '"<<q
->qdomain
<<"' allowed: client IP "<<q
->getRemote()<<" is in NSset"<<endl
;
511 Netmask nm
= Netmask(*i
);
512 if(nm
.match( (ComboAddress
*) &q
->d_remote
))
514 g_log
<<Logger::Warning
<<"AXFR of domain '"<<q
->qdomain
<<"' allowed: client IP "<<q
->getRemote()<<" is in per-domain ACL"<<endl
;
515 // cerr<<"hit!"<<endl;
522 extern CommunicatorClass Communicator
;
524 if(Communicator
.justNotified(q
->qdomain
, q
->getRemote().toString())) { // we just notified this ip
525 g_log
<<Logger::Warning
<<"Approved AXFR of '"<<q
->qdomain
<<"' from recently notified slave "<<q
->getRemote()<<endl
;
529 g_log
<<Logger::Error
<<"AXFR of domain '"<<q
->qdomain
<<"' denied: client IP "<<q
->getRemote()<<" has no permission"<<endl
;
541 shared_ptr
<DNSPacket
> getFreshAXFRPacket(shared_ptr
<DNSPacket
> q
)
543 shared_ptr
<DNSPacket
> ret
= shared_ptr
<DNSPacket
>(q
->replyPacket());
544 ret
->setCompress(false);
545 ret
->d_dnssecOk
=false; // RFC 5936, 2.2.5
552 /** do the actual zone transfer. Return 0 in case of error, 1 in case of success */
553 int TCPNameserver::doAXFR(const DNSName
&target
, shared_ptr
<DNSPacket
> q
, int outsock
)
555 shared_ptr
<DNSPacket
> outpacket
= getFreshAXFRPacket(q
);
557 outpacket
->d_dnssecOk
=true; // RFC 5936, 2.2.5 'SHOULD'
559 g_log
<<Logger::Error
<<"AXFR of domain '"<<target
<<"' initiated by "<<q
->getRemote()<<endl
;
561 // determine if zone exists and AXFR is allowed using existing backend before spawning a new backend.
565 DLOG(g_log
<<"Looking for SOA"<<endl
); // find domain_id via SOA and list complete domain. No SOA, no AXFR
567 g_log
<<Logger::Error
<<"TCP server is without backend connections in doAXFR, launching"<<endl
;
568 s_P
=new PacketHandler
;
571 // canDoAXFR does all the ACL checks, and has the if(disable-axfr) shortcut, call it first.
573 g_log
<<Logger::Error
<<"AXFR of domain '"<<target
<<"' failed: "<<q
->getRemote()<<" may not request AXFR"<<endl
;
574 outpacket
->setRcode(RCode::NotAuth
);
575 sendPacket(outpacket
,outsock
);
579 if(!s_P
->getBackend()->getSOAUncached(target
, sd
)) {
580 g_log
<<Logger::Error
<<"AXFR of domain '"<<target
<<"' failed: not authoritative"<<endl
;
581 outpacket
->setRcode(RCode::NotAuth
);
582 sendPacket(outpacket
,outsock
);
588 if(!db
.getSOAUncached(target
, sd
)) {
589 g_log
<<Logger::Error
<<"AXFR of domain '"<<target
<<"' failed: not authoritative in second instance"<<endl
;
590 outpacket
->setRcode(RCode::NotAuth
);
591 sendPacket(outpacket
,outsock
);
595 DNSSECKeeper
dk(&db
);
596 dk
.clearCaches(target
);
597 bool securedZone
= dk
.isSecuredZone(target
);
598 bool presignedZone
= dk
.isPresigned(target
);
600 bool noAXFRBecauseOfNSEC3Narrow
=false;
601 NSEC3PARAMRecordContent ns3pr
;
603 bool NSEC3Zone
=false;
604 if(securedZone
&& dk
.getNSEC3PARAM(target
, &ns3pr
, &narrow
)) {
607 g_log
<<Logger::Error
<<"Not doing AXFR of an NSEC3 narrow zone '"<<target
<<"' for "<<q
->getRemote()<<endl
;
608 noAXFRBecauseOfNSEC3Narrow
=true;
612 if(noAXFRBecauseOfNSEC3Narrow
) {
613 g_log
<<Logger::Error
<<"AXFR of domain '"<<target
<<"' denied to "<<q
->getRemote()<<endl
;
614 outpacket
->setRcode(RCode::Refused
);
615 // FIXME: should actually figure out if we are auth over a zone, and send out 9 if we aren't
616 sendPacket(outpacket
,outsock
);
620 TSIGRecordContent trc
;
624 bool haveTSIGDetails
= q
->getTSIGDetails(&trc
, &tsigkeyname
);
626 if(haveTSIGDetails
&& !tsigkeyname
.empty()) {
628 DNSName algorithm
=trc
.d_algoName
; // FIXME400: check
629 if (algorithm
== DNSName("hmac-md5.sig-alg.reg.int"))
630 algorithm
= DNSName("hmac-md5");
631 if (algorithm
!= DNSName("gss-tsig")) {
632 if(!db
.getTSIGKey(tsigkeyname
, &algorithm
, &tsig64
)) {
633 g_log
<<Logger::Error
<<"TSIG key '"<<tsigkeyname
<<"' for domain '"<<target
<<"' not found"<<endl
;
636 if (B64Decode(tsig64
, tsigsecret
) == -1) {
637 g_log
<<Logger::Error
<<"Unable to Base-64 decode TSIG key '"<<tsigkeyname
<<"' for domain '"<<target
<<"'"<<endl
;
644 // SOA *must* go out first, our signing pipe might reorder
645 DLOG(g_log
<<"Sending out SOA"<<endl
);
646 DNSZoneRecord soa
= makeEditedDNSZRFromSOAData(dk
, sd
);
647 outpacket
->addRecord(soa
);
648 if(securedZone
&& !presignedZone
) {
649 set
<DNSName
> authSet
;
650 authSet
.insert(target
);
651 addRRSigs(dk
, db
, authSet
, outpacket
->getRRS());
654 if(haveTSIGDetails
&& !tsigkeyname
.empty())
655 outpacket
->setTSIGDetails(trc
, tsigkeyname
, tsigsecret
, trc
.d_mac
); // first answer is 'normal'
657 sendPacket(outpacket
, outsock
);
659 trc
.d_mac
= outpacket
->d_trc
.d_mac
;
660 outpacket
= getFreshAXFRPacket(q
);
662 ChunkedSigningPipe
csp(target
, (securedZone
&& !presignedZone
), ::arg().asNum("signing-threads", 1));
664 typedef map
<DNSName
, NSECXEntry
, CanonDNSNameCompare
> nsecxrepo_t
;
665 nsecxrepo_t nsecxrepo
;
667 // this is where the DNSKEYs go in
669 DNSSECKeeper::keyset_t keys
= dk
.getKeys(target
);
673 zrr
.dr
.d_name
= target
;
674 zrr
.dr
.d_ttl
= sd
.default_ttl
;
675 zrr
.auth
= 1; // please sign!
677 string publishCDNSKEY
, publishCDS
;
678 dk
.getFromMeta(q
->qdomain
, "PUBLISH-CDNSKEY", publishCDNSKEY
);
679 dk
.getFromMeta(q
->qdomain
, "PUBLISH-CDS", publishCDS
);
680 vector
<DNSZoneRecord
> cds
, cdnskey
;
681 DNSSECKeeper::keyset_t entryPoints
= dk
.getEntryPoints(q
->qdomain
);
682 set
<uint32_t> entryPointIds
;
683 for (auto const& value
: entryPoints
)
684 entryPointIds
.insert(value
.second
.id
);
686 for(const DNSSECKeeper::keyset_t::value_type
& value
: keys
) {
687 zrr
.dr
.d_type
= QType::DNSKEY
;
688 zrr
.dr
.d_content
= std::make_shared
<DNSKEYRecordContent
>(value
.first
.getDNSKEY());
689 DNSName keyname
= NSEC3Zone
? DNSName(toBase32Hex(hashQNameWithSalt(ns3pr
, zrr
.dr
.d_name
))) : zrr
.dr
.d_name
;
690 NSECXEntry
& ne
= nsecxrepo
[keyname
];
692 ne
.d_set
.set(zrr
.dr
.d_type
);
693 ne
.d_ttl
= sd
.default_ttl
;
696 // generate CDS and CDNSKEY records
697 if(entryPointIds
.count(value
.second
.id
) > 0){
698 if(publishCDNSKEY
== "1") {
699 zrr
.dr
.d_type
=QType::CDNSKEY
;
700 zrr
.dr
.d_content
= std::make_shared
<DNSKEYRecordContent
>(value
.first
.getDNSKEY());
701 cdnskey
.push_back(zrr
);
704 if(!publishCDS
.empty()){
705 zrr
.dr
.d_type
=QType::CDS
;
706 vector
<string
> digestAlgos
;
707 stringtok(digestAlgos
, publishCDS
, ", ");
708 for(auto const &digestAlgo
: digestAlgos
) {
709 zrr
.dr
.d_content
=std::make_shared
<DSRecordContent
>(makeDSFromDNSKey(target
, value
.first
.getDNSKEY(), pdns_stou(digestAlgo
)));
716 if(::arg().mustDo("direct-dnskey")) {
717 sd
.db
->lookup(QType(QType::DNSKEY
), target
, NULL
, sd
.domain_id
);
718 while(sd
.db
->get(zrr
)) {
719 zrr
.dr
.d_ttl
= sd
.default_ttl
;
726 if(NSEC3Zone
) { // now stuff in the NSEC3PARAM
727 flags
= ns3pr
.d_flags
;
728 zrr
.dr
.d_type
= QType::NSEC3PARAM
;
730 zrr
.dr
.d_content
= std::make_shared
<NSEC3PARAMRecordContent
>(ns3pr
);
731 ns3pr
.d_flags
= flags
;
732 DNSName keyname
= DNSName(toBase32Hex(hashQNameWithSalt(ns3pr
, zrr
.dr
.d_name
)));
733 NSECXEntry
& ne
= nsecxrepo
[keyname
];
735 ne
.d_set
.set(zrr
.dr
.d_type
);
739 // now start list zone
740 if(!(sd
.db
->list(target
, sd
.domain_id
))) {
741 g_log
<<Logger::Error
<<"Backend signals error condition"<<endl
;
742 outpacket
->setRcode(RCode::ServFail
);
743 sendPacket(outpacket
,outsock
);
748 const bool rectify
= !(presignedZone
|| ::arg().mustDo("disable-axfr-rectify"));
749 set
<DNSName
> qnames
, nsset
, terms
;
750 vector
<DNSZoneRecord
> zrrs
;
752 // Add the CDNSKEY and CDS records we created earlier
753 for (auto const &synth_zrr
: cds
)
754 zrrs
.push_back(synth_zrr
);
756 for (auto const &synth_zrr
: cdnskey
)
757 zrrs
.push_back(synth_zrr
);
759 while(sd
.db
->get(zrr
)) {
760 zrr
.dr
.d_name
.makeUsLowerCase();
761 if(zrr
.dr
.d_name
.isPartOf(target
)) {
762 if (zrr
.dr
.d_type
== QType::ALIAS
&& ::arg().mustDo("outgoing-axfr-expand-alias")) {
763 vector
<DNSZoneRecord
> ips
;
764 int ret1
= stubDoResolve(getRR
<ALIASRecordContent
>(zrr
.dr
)->d_content
, QType::A
, ips
);
765 int ret2
= stubDoResolve(getRR
<ALIASRecordContent
>(zrr
.dr
)->d_content
, QType::AAAA
, ips
);
766 if(ret1
!= RCode::NoError
|| ret2
!= RCode::NoError
) {
767 g_log
<<Logger::Error
<<"Error resolving for ALIAS "<<zrr
.dr
.d_content
->getZoneRepresentation()<<", aborting AXFR"<<endl
;
768 outpacket
->setRcode(RCode::ServFail
);
769 sendPacket(outpacket
,outsock
);
772 for(const auto& ip
: ips
) {
773 zrr
.dr
.d_type
= ip
.dr
.d_type
;
774 zrr
.dr
.d_content
= ip
.dr
.d_content
;
782 qnames
.insert(zrr
.dr
.d_name
);
783 if(zrr
.dr
.d_type
== QType::NS
&& zrr
.dr
.d_name
!=target
)
784 nsset
.insert(zrr
.dr
.d_name
);
786 // remove existing ents
793 g_log
<<Logger::Warning
<<"Zone '"<<target
<<"' contains out-of-zone data '"<<zrr
.dr
.d_name
<<"|"<<DNSRecordContent::NumberToType(zrr
.dr
.d_type
)<<"', ignoring"<<endl
;
797 // Group records by name and type, signpipe stumbles over interrupted rrsets
798 if(securedZone
&& !presignedZone
) {
799 sort(zrrs
.begin(), zrrs
.end(), [](const DNSZoneRecord
& a
, const DNSZoneRecord
& b
) {
800 return tie(a
.dr
.d_name
, a
.dr
.d_type
) < tie(b
.dr
.d_name
, b
.dr
.d_type
);
806 for(DNSZoneRecord
&loopZRR
: zrrs
) {
808 if (loopZRR
.dr
.d_type
!= QType::NS
|| loopZRR
.dr
.d_name
!=target
) {
809 DNSName
shorter(loopZRR
.dr
.d_name
);
811 if (shorter
==target
) // apex is always auth
813 if(nsset
.count(shorter
) && !(loopZRR
.dr
.d_name
==shorter
&& loopZRR
.dr
.d_type
== QType::DS
)) {
817 } while(shorter
.chopOff());
822 // ents are only required for NSEC3 zones
823 uint32_t maxent
= ::arg().asNum("max-ent-entries");
824 set
<DNSName
> nsec3set
, nonterm
;
825 for (auto &loopZRR
: zrrs
) {
827 DNSName shorter
= loopZRR
.dr
.d_name
;
828 if (shorter
!= target
&& shorter
.chopOff() && shorter
!= target
) {
830 if(nsset
.count(shorter
)) {
834 } while(shorter
.chopOff() && shorter
!= target
);
836 shorter
= loopZRR
.dr
.d_name
;
837 if(!skip
&& (loopZRR
.dr
.d_type
!= QType::NS
|| !ns3pr
.d_flags
)) {
839 if(!nsec3set
.count(shorter
)) {
840 nsec3set
.insert(shorter
);
842 } while(shorter
!= target
&& shorter
.chopOff());
846 for(DNSZoneRecord
&loopZRR
: zrrs
) {
847 DNSName
shorter(loopZRR
.dr
.d_name
);
848 while(shorter
!= target
&& shorter
.chopOff()) {
849 if(!qnames
.count(shorter
) && !nonterm
.count(shorter
) && nsec3set
.count(shorter
)) {
851 g_log
<<Logger::Warning
<<"Zone '"<<target
<<"' has too many empty non terminals."<<endl
;
854 nonterm
.insert(shorter
);
860 for(const auto& nt
: nonterm
) {
861 DNSZoneRecord tempRR
;
863 tempRR
.dr
.d_type
=QType::ENT
;
865 zrrs
.push_back(tempRR
);
871 /* now write all other records */
878 for(DNSZoneRecord
&loopZRR
: zrrs
) {
879 if (!presignedZone
&& loopZRR
.dr
.d_type
== QType::RRSIG
)
882 // only skip the DNSKEY, CDNSKEY and CDS if direct-dnskey is enabled, to avoid changing behaviour
883 // when it is not enabled.
884 if(::arg().mustDo("direct-dnskey") && (loopZRR
.dr
.d_type
== QType::DNSKEY
|| loopZRR
.dr
.d_type
== QType::CDNSKEY
|| loopZRR
.dr
.d_type
== QType::CDS
))
888 if(securedZone
&& (loopZRR
.auth
|| loopZRR
.dr
.d_type
== QType::NS
)) {
889 if (NSEC3Zone
|| loopZRR
.dr
.d_type
) {
890 if (presignedZone
&& NSEC3Zone
&& loopZRR
.dr
.d_type
== QType::RRSIG
&& getRR
<RRSIGRecordContent
>(loopZRR
.dr
)->d_type
== QType::NSEC3
) {
891 keyname
= loopZRR
.dr
.d_name
.makeRelative(sd
.qname
);
893 keyname
= NSEC3Zone
? DNSName(toBase32Hex(hashQNameWithSalt(ns3pr
, loopZRR
.dr
.d_name
))) : loopZRR
.dr
.d_name
;
895 NSECXEntry
& ne
= nsecxrepo
[keyname
];
896 ne
.d_ttl
= sd
.default_ttl
;
897 ne
.d_auth
= (ne
.d_auth
|| loopZRR
.auth
|| (NSEC3Zone
&& (!ns3pr
.d_flags
)));
898 if (loopZRR
.dr
.d_type
&& loopZRR
.dr
.d_type
!= QType::RRSIG
) {
899 ne
.d_set
.set(loopZRR
.dr
.d_type
);
904 if (!loopZRR
.dr
.d_type
)
905 continue; // skip empty non-terminals
907 if(loopZRR
.dr
.d_type
== QType::SOA
)
908 continue; // skip SOA - would indicate end of AXFR
910 if(csp
.submit(loopZRR
)) {
912 outpacket
->getRRS() = csp
.getChunk();
913 if(!outpacket
->getRRS().empty()) {
914 if(haveTSIGDetails
&& !tsigkeyname
.empty())
915 outpacket
->setTSIGDetails(trc
, tsigkeyname
, tsigsecret
, trc
.d_mac
, true);
916 sendPacket(outpacket
, outsock
);
917 trc
.d_mac
=outpacket
->d_trc
.d_mac
;
918 outpacket
=getFreshAXFRPacket(q
);
926 udiff=dt.udiffNoReset();
927 cerr<<"Starting NSEC: "<<csp.d_signed/(udiff/1000000.0)<<" sigs/s, "<<csp.d_signed<<" / "<<udiff/1000000.0<<endl;
928 cerr<<"Outstanding: "<<csp.d_outstanding<<", "<<csp.d_queued - csp.d_signed << endl;
929 cerr<<"Ready for consumption: "<<csp.getReady()<<endl;
933 for(nsecxrepo_t::const_iterator iter
= nsecxrepo
.begin(); iter
!= nsecxrepo
.end(); ++iter
) {
934 if(iter
->second
.d_auth
) {
935 NSEC3RecordContent n3rc
;
936 n3rc
.set(iter
->second
.d_set
);
937 const auto numberOfTypesSet
= n3rc
.numberOfTypesSet();
938 if (numberOfTypesSet
!= 0 && (numberOfTypesSet
!= 1 || !n3rc
.isSet(QType::NS
))) {
939 n3rc
.set(QType::RRSIG
);
941 n3rc
.d_salt
= ns3pr
.d_salt
;
942 n3rc
.d_flags
= ns3pr
.d_flags
;
943 n3rc
.d_iterations
= ns3pr
.d_iterations
;
944 n3rc
.d_algorithm
= DNSSECKeeper::SHA1
; // SHA1, fixed in PowerDNS for now
945 nsecxrepo_t::const_iterator inext
= iter
;
947 if(inext
== nsecxrepo
.end())
948 inext
= nsecxrepo
.begin();
949 while(!inext
->second
.d_auth
&& inext
!= iter
)
952 if(inext
== nsecxrepo
.end())
953 inext
= nsecxrepo
.begin();
955 n3rc
.d_nexthash
= fromBase32Hex(inext
->first
.toStringNoDot());
956 zrr
.dr
.d_name
= iter
->first
+sd
.qname
;
958 zrr
.dr
.d_ttl
= sd
.default_ttl
;
959 zrr
.dr
.d_content
= std::make_shared
<NSEC3RecordContent
>(std::move(n3rc
));
960 zrr
.dr
.d_type
= QType::NSEC3
;
961 zrr
.dr
.d_place
= DNSResourceRecord::ANSWER
;
963 if(csp
.submit(zrr
)) {
965 outpacket
->getRRS() = csp
.getChunk();
966 if(!outpacket
->getRRS().empty()) {
967 if(haveTSIGDetails
&& !tsigkeyname
.empty())
968 outpacket
->setTSIGDetails(trc
, tsigkeyname
, tsigsecret
, trc
.d_mac
, true);
969 sendPacket(outpacket
, outsock
);
970 trc
.d_mac
=outpacket
->d_trc
.d_mac
;
971 outpacket
=getFreshAXFRPacket(q
);
980 else for(nsecxrepo_t::const_iterator iter
= nsecxrepo
.begin(); iter
!= nsecxrepo
.end(); ++iter
) {
981 NSECRecordContent nrc
;
982 nrc
.set(iter
->second
.d_set
);
983 nrc
.set(QType::RRSIG
);
984 nrc
.set(QType::NSEC
);
986 if(boost::next(iter
) != nsecxrepo
.end())
987 nrc
.d_next
= boost::next(iter
)->first
;
989 nrc
.d_next
=nsecxrepo
.begin()->first
;
990 zrr
.dr
.d_name
= iter
->first
;
992 zrr
.dr
.d_ttl
= sd
.default_ttl
;
993 zrr
.dr
.d_content
= std::make_shared
<NSECRecordContent
>(std::move(nrc
));
994 zrr
.dr
.d_type
= QType::NSEC
;
995 zrr
.dr
.d_place
= DNSResourceRecord::ANSWER
;
997 if(csp
.submit(zrr
)) {
999 outpacket
->getRRS() = csp
.getChunk();
1000 if(!outpacket
->getRRS().empty()) {
1001 if(haveTSIGDetails
&& !tsigkeyname
.empty())
1002 outpacket
->setTSIGDetails(trc
, tsigkeyname
, tsigsecret
, trc
.d_mac
, true);
1003 sendPacket(outpacket
, outsock
);
1004 trc
.d_mac
=outpacket
->d_trc
.d_mac
;
1005 outpacket
=getFreshAXFRPacket(q
);
1014 udiff=dt.udiffNoReset();
1015 cerr<<"Flushing pipe: "<<csp.d_signed/(udiff/1000000.0)<<" sigs/s, "<<csp.d_signed<<" / "<<udiff/1000000.0<<endl;
1016 cerr<<"Outstanding: "<<csp.d_outstanding<<", "<<csp.d_queued - csp.d_signed << endl;
1017 cerr<<"Ready for consumption: "<<csp.getReady()<<endl;
1020 outpacket
->getRRS() = csp
.getChunk(true); // flush the pipe
1021 if(!outpacket
->getRRS().empty()) {
1022 if(haveTSIGDetails
&& !tsigkeyname
.empty())
1023 outpacket
->setTSIGDetails(trc
, tsigkeyname
, tsigsecret
, trc
.d_mac
, true); // first answer is 'normal'
1024 sendPacket(outpacket
, outsock
);
1025 trc
.d_mac
=outpacket
->d_trc
.d_mac
;
1026 outpacket
=getFreshAXFRPacket(q
);
1032 udiff
=dt
.udiffNoReset();
1034 g_log
<<Logger::Info
<<"Done signing: "<<csp
.d_signed
/(udiff
/1000000.0)<<" sigs/s, "<<endl
;
1036 DLOG(g_log
<<"Done writing out records"<<endl
);
1037 /* and terminate with yet again the SOA record */
1038 outpacket
=getFreshAXFRPacket(q
);
1039 outpacket
->addRecord(soa
);
1040 if(haveTSIGDetails
&& !tsigkeyname
.empty())
1041 outpacket
->setTSIGDetails(trc
, tsigkeyname
, tsigsecret
, trc
.d_mac
, true);
1043 sendPacket(outpacket
, outsock
);
1045 DLOG(g_log
<<"last packet - close"<<endl
);
1046 g_log
<<Logger::Error
<<"AXFR of domain '"<<target
<<"' to "<<q
->getRemote()<<" finished"<<endl
;
1051 int TCPNameserver::doIXFR(shared_ptr
<DNSPacket
> q
, int outsock
)
1053 shared_ptr
<DNSPacket
> outpacket
=getFreshAXFRPacket(q
);
1055 outpacket
->d_dnssecOk
=true; // RFC 5936, 2.2.5 'SHOULD'
1057 uint32_t serial
= 0;
1058 MOADNSParser
mdp(false, q
->getString());
1059 for(MOADNSParser::answers_t::const_iterator i
=mdp
.d_answers
.begin(); i
!= mdp
.d_answers
.end(); ++i
) {
1060 const DNSRecord
*rr
= &i
->first
;
1061 if (rr
->d_type
== QType::SOA
&& rr
->d_place
== DNSResourceRecord::AUTHORITY
) {
1062 vector
<string
>parts
;
1063 stringtok(parts
, rr
->d_content
->getZoneRepresentation());
1064 if (parts
.size() >= 3) {
1066 serial
=pdns_stou(parts
[2]);
1068 catch(const std::out_of_range
& oor
) {
1069 g_log
<<Logger::Error
<<"Invalid serial in IXFR query"<<endl
;
1070 outpacket
->setRcode(RCode::FormErr
);
1071 sendPacket(outpacket
,outsock
);
1075 g_log
<<Logger::Error
<<"No serial in IXFR query"<<endl
;
1076 outpacket
->setRcode(RCode::FormErr
);
1077 sendPacket(outpacket
,outsock
);
1080 } else if (rr
->d_type
!= QType::TSIG
&& rr
->d_type
!= QType::OPT
) {
1081 g_log
<<Logger::Error
<<"Additional records in IXFR query, type: "<<QType(rr
->d_type
).getName()<<endl
;
1082 outpacket
->setRcode(RCode::FormErr
);
1083 sendPacket(outpacket
,outsock
);
1088 g_log
<<Logger::Error
<<"IXFR of domain '"<<q
->qdomain
<<"' initiated by "<<q
->getRemote()<<" with serial "<<serial
<<endl
;
1090 // determine if zone exists and AXFR is allowed using existing backend before spawning a new backend.
1094 DLOG(g_log
<<"Looking for SOA"<<endl
); // find domain_id via SOA and list complete domain. No SOA, no IXFR
1096 g_log
<<Logger::Error
<<"TCP server is without backend connections in doIXFR, launching"<<endl
;
1097 s_P
=new PacketHandler
;
1100 // canDoAXFR does all the ACL checks, and has the if(disable-axfr) shortcut, call it first.
1101 if(!canDoAXFR(q
) || !s_P
->getBackend()->getSOAUncached(q
->qdomain
, sd
)) {
1102 g_log
<<Logger::Error
<<"IXFR of domain '"<<q
->qdomain
<<"' failed: not authoritative"<<endl
;
1103 outpacket
->setRcode(RCode::NotAuth
);
1104 sendPacket(outpacket
,outsock
);
1110 NSEC3PARAMRecordContent ns3pr
;
1113 dk
.clearCaches(q
->qdomain
);
1114 bool securedZone
= dk
.isSecuredZone(q
->qdomain
);
1115 if(dk
.getNSEC3PARAM(q
->qdomain
, &ns3pr
, &narrow
)) {
1117 g_log
<<Logger::Error
<<"Not doing IXFR of an NSEC3 narrow zone."<<endl
;
1118 g_log
<<Logger::Error
<<"IXFR of domain '"<<q
->qdomain
<<"' denied to "<<q
->getRemote()<<endl
;
1119 outpacket
->setRcode(RCode::Refused
);
1120 sendPacket(outpacket
,outsock
);
1125 DNSName target
= q
->qdomain
;
1128 if(!db
.getSOAUncached(target
, sd
)) {
1129 g_log
<<Logger::Error
<<"IXFR of domain '"<<target
<<"' failed: not authoritative in second instance"<<endl
;
1130 outpacket
->setRcode(RCode::NotAuth
);
1131 sendPacket(outpacket
,outsock
);
1135 if (!rfc1982LessThan(serial
, calculateEditSOA(sd
.serial
, dk
, sd
.qname
))) {
1136 TSIGRecordContent trc
;
1137 DNSName tsigkeyname
;
1140 bool haveTSIGDetails
= q
->getTSIGDetails(&trc
, &tsigkeyname
);
1142 if(haveTSIGDetails
&& !tsigkeyname
.empty()) {
1144 DNSName algorithm
=trc
.d_algoName
; // FIXME400: was toLowerCanonic, compare output
1145 if (algorithm
== DNSName("hmac-md5.sig-alg.reg.int"))
1146 algorithm
= DNSName("hmac-md5");
1148 if(!s_P
->getBackend()->getTSIGKey(tsigkeyname
, &algorithm
, &tsig64
)) {
1149 g_log
<<Logger::Error
<<"TSIG key '"<<tsigkeyname
<<"' for domain '"<<target
<<"' not found"<<endl
;
1152 if (B64Decode(tsig64
, tsigsecret
) == -1) {
1153 g_log
<<Logger::Error
<<"Unable to Base-64 decode TSIG key '"<<tsigkeyname
<<"' for domain '"<<target
<<"'"<<endl
;
1158 UeberBackend signatureDB
;
1160 // SOA *must* go out first, our signing pipe might reorder
1161 DLOG(g_log
<<"Sending out SOA"<<endl
);
1162 DNSZoneRecord soa
= makeEditedDNSZRFromSOAData(dk
, sd
);
1163 outpacket
->addRecord(soa
);
1165 set
<DNSName
> authSet
;
1166 authSet
.insert(target
);
1167 addRRSigs(dk
, signatureDB
, authSet
, outpacket
->getRRS());
1170 if(haveTSIGDetails
&& !tsigkeyname
.empty())
1171 outpacket
->setTSIGDetails(trc
, tsigkeyname
, tsigsecret
, trc
.d_mac
); // first answer is 'normal'
1173 sendPacket(outpacket
, outsock
);
1175 g_log
<<Logger::Error
<<"IXFR of domain '"<<target
<<"' to "<<q
->getRemote()<<" finished"<<endl
;
1180 g_log
<<Logger::Error
<<"IXFR fallback to AXFR for domain '"<<target
<<"' our serial "<<sd
.serial
<<endl
;
1181 return doAXFR(q
->qdomain
, q
, outsock
);
1184 TCPNameserver::~TCPNameserver()
1186 delete d_connectionroom_sem
;
1189 TCPNameserver::TCPNameserver()
1191 d_maxTransactionsPerConn
= ::arg().asNum("max-tcp-transactions-per-conn");
1192 d_idleTimeout
= ::arg().asNum("tcp-idle-timeout");
1193 d_maxConnectionDuration
= ::arg().asNum("max-tcp-connection-duration");
1194 d_maxConnectionsPerClient
= ::arg().asNum("max-tcp-connections-per-client");
1196 // sem_init(&d_connectionroom_sem,0,::arg().asNum("max-tcp-connections"));
1197 d_connectionroom_sem
= new Semaphore( ::arg().asNum( "max-tcp-connections" ));
1199 vector
<string
>locals
;
1200 stringtok(locals
,::arg()["local-address"]," ,");
1202 vector
<string
>locals6
;
1203 stringtok(locals6
,::arg()["local-ipv6"]," ,");
1205 if(locals
.empty() && locals6
.empty())
1206 throw PDNSException("No local address specified");
1208 d_ng
.toMasks(::arg()["allow-axfr-ips"] );
1210 signal(SIGPIPE
,SIG_IGN
);
1212 for(vector
<string
>::const_iterator laddr
=locals
.begin();laddr
!=locals
.end();++laddr
) {
1213 int s
=socket(AF_INET
,SOCK_STREAM
,0);
1216 throw PDNSException("Unable to acquire TCP socket: "+stringerror());
1220 ComboAddress
local(*laddr
, ::arg().asNum("local-port"));
1223 if(setsockopt(s
,SOL_SOCKET
,SO_REUSEADDR
,(char*)&tmp
,sizeof tmp
)<0) {
1224 g_log
<<Logger::Error
<<"Setsockopt failed"<<endl
;
1228 if (::arg().asNum("tcp-fast-open") > 0) {
1230 int fastOpenQueueSize
= ::arg().asNum("tcp-fast-open");
1231 if (setsockopt(s
, IPPROTO_TCP
, TCP_FASTOPEN
, &fastOpenQueueSize
, sizeof fastOpenQueueSize
) < 0) {
1232 g_log
<<Logger::Error
<<"Failed to enable TCP Fast Open for listening socket: "<<strerror(errno
)<<endl
;
1235 g_log
<<Logger::Warning
<<"TCP Fast Open configured but not supported for listening socket"<<endl
;
1239 if( ::arg().mustDo("non-local-bind") )
1240 Utility::setBindAny(AF_INET
, s
);
1242 if(::bind(s
, (sockaddr
*)&local
, local
.getSocklen())<0) {
1244 if( errno
== EADDRNOTAVAIL
&& ! ::arg().mustDo("local-address-nonexist-fail") ) {
1245 g_log
<<Logger::Error
<<"IPv4 Address " << *laddr
<< " does not exist on this server - skipping TCP bind" << endl
;
1248 g_log
<<Logger::Error
<<"Unable to bind to TCP socket " << *laddr
<< ": "<<strerror(errno
)<<endl
;
1249 throw PDNSException("Unable to bind to TCP socket");
1254 g_log
<<Logger::Error
<<"TCP server bound to "<<local
.toStringWithPort()<<endl
;
1255 d_sockets
.push_back(s
);
1257 memset(&pfd
, 0, sizeof(pfd
));
1259 pfd
.events
= POLLIN
;
1261 d_prfds
.push_back(pfd
);
1264 for(vector
<string
>::const_iterator laddr
=locals6
.begin();laddr
!=locals6
.end();++laddr
) {
1265 int s
=socket(AF_INET6
,SOCK_STREAM
,0);
1268 throw PDNSException("Unable to acquire TCPv6 socket: "+stringerror());
1272 ComboAddress
local(*laddr
, ::arg().asNum("local-port"));
1275 if(setsockopt(s
,SOL_SOCKET
,SO_REUSEADDR
,(char*)&tmp
,sizeof tmp
)<0) {
1276 g_log
<<Logger::Error
<<"Setsockopt failed"<<endl
;
1280 if (::arg().asNum("tcp-fast-open") > 0) {
1282 int fastOpenQueueSize
= ::arg().asNum("tcp-fast-open");
1283 if (setsockopt(s
, IPPROTO_TCP
, TCP_FASTOPEN
, &fastOpenQueueSize
, sizeof fastOpenQueueSize
) < 0) {
1284 g_log
<<Logger::Error
<<"Failed to enable TCP Fast Open for listening socket: "<<strerror(errno
)<<endl
;
1287 g_log
<<Logger::Warning
<<"TCP Fast Open configured but not supported for listening socket"<<endl
;
1291 if( ::arg().mustDo("non-local-bind") )
1292 Utility::setBindAny(AF_INET6
, s
);
1293 if(setsockopt(s
, IPPROTO_IPV6
, IPV6_V6ONLY
, &tmp
, sizeof(tmp
)) < 0) {
1294 g_log
<<Logger::Error
<<"Failed to set IPv6 socket to IPv6 only, continuing anyhow: "<<strerror(errno
)<<endl
;
1296 if(bind(s
, (const sockaddr
*)&local
, local
.getSocklen())<0) {
1298 if( errno
== EADDRNOTAVAIL
&& ! ::arg().mustDo("local-ipv6-nonexist-fail") ) {
1299 g_log
<<Logger::Error
<<"IPv6 Address " << *laddr
<< " does not exist on this server - skipping TCP bind" << endl
;
1302 g_log
<<Logger::Error
<<"Unable to bind to TCPv6 socket" << *laddr
<< ": "<<strerror(errno
)<<endl
;
1303 throw PDNSException("Unable to bind to TCPv6 socket");
1308 g_log
<<Logger::Error
<<"TCPv6 server bound to "<<local
.toStringWithPort()<<endl
; // this gets %eth0 right
1309 d_sockets
.push_back(s
);
1312 memset(&pfd
, 0, sizeof(pfd
));
1314 pfd
.events
= POLLIN
;
1316 d_prfds
.push_back(pfd
);
1321 //! Start of TCP operations thread, we launch a new thread for each incoming TCP question
1322 void TCPNameserver::thread()
1324 setThreadName("pdns/tcpnameser");
1328 ComboAddress remote
;
1329 Utility::socklen_t addrlen
=remote
.getSocklen();
1331 int ret
=poll(&d_prfds
[0], d_prfds
.size(), -1); // blocks, forever if need be
1336 for(const pollfd
& pfd
: d_prfds
) {
1337 if(pfd
.revents
& POLLIN
) {
1339 remote
.sin4
.sin_family
= AF_INET6
;
1340 addrlen
=remote
.getSocklen();
1342 if((fd
=accept(sock
, (sockaddr
*)&remote
, &addrlen
))<0) {
1343 g_log
<<Logger::Error
<<"TCP question accept error: "<<strerror(errno
)<<endl
;
1346 g_log
<<Logger::Error
<<"TCP handler out of filedescriptors, exiting, won't recover from this"<<endl
;
1351 if (d_maxConnectionsPerClient
) {
1352 std::lock_guard
<std::mutex
> lock(s_clientsCountMutex
);
1353 if (s_clientsCount
[remote
] >= d_maxConnectionsPerClient
) {
1354 g_log
<<Logger::Notice
<<"Limit of simultaneous TCP connections per client reached for "<< remote
<<", dropping"<<endl
;
1358 s_clientsCount
[remote
]++;
1362 d_connectionroom_sem
->wait(); // blocks if no connections are available
1365 d_connectionroom_sem
->getValue( &room
);
1367 g_log
<<Logger::Warning
<<"Limit of simultaneous TCP connections reached - raise max-tcp-connections"<<endl
;
1369 if(pthread_create(&tid
, 0, &doConnection
, reinterpret_cast<void*>(fd
))) {
1370 g_log
<<Logger::Error
<<"Error creating thread: "<<stringerror()<<endl
;
1371 d_connectionroom_sem
->post();
1373 decrementClientCount(remote
);
1380 catch(PDNSException
&AE
) {
1381 g_log
<<Logger::Error
<<"TCP Nameserver thread dying because of fatal error: "<<AE
.reason
<<endl
;
1384 g_log
<<Logger::Error
<<"TCPNameserver dying because of an unexpected fatal error"<<endl
;
1386 _exit(1); // take rest of server with us