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
;
378 g_log
<<Logger::Error
<<"TCP server is without backend connections, launching"<<endl
;
379 s_P
=new PacketHandler
;
382 reply
=shared_ptr
<DNSPacket
>(s_P
->doQuestion(packet
.get())); // we really need to ask the backend :-)
385 if(!reply
) // unable to write an answer?
388 sendPacket(reply
, fd
);
391 catch(PDNSException
&ae
) {
394 s_P
= 0; // on next call, backend will be recycled
395 g_log
<<Logger::Error
<<"TCP nameserver had error, cycling backend: "<<ae
.reason
<<endl
;
397 catch(NetworkError
&e
) {
398 g_log
<<Logger::Info
<<"TCP Connection Thread died because of network error: "<<e
.what()<<endl
;
401 catch(std::exception
&e
) {
402 g_log
<<Logger::Error
<<"TCP Connection Thread died because of STL error: "<<e
.what()<<endl
;
406 g_log
<< Logger::Error
<< "TCP Connection Thread caught unknown exception." << endl
;
408 d_connectionroom_sem
->post();
413 catch(const PDNSException
& e
) {
414 g_log
<<Logger::Error
<<"Error closing TCP socket: "<<e
.reason
<<endl
;
416 decrementClientCount(remote
);
422 // call this method with s_plock held!
423 bool TCPNameserver::canDoAXFR(shared_ptr
<DNSPacket
> q
)
425 if(::arg().mustDo("disable-axfr"))
428 if(q
->d_havetsig
) { // if you have one, it must be good
429 TSIGRecordContent trc
;
432 if(!q
->checkForCorrectTSIG(s_P
->getBackend(), &keyname
, &secret
, &trc
)) {
435 getTSIGHashEnum(trc
.d_algoName
, q
->d_tsig_algo
);
436 if (q
->d_tsig_algo
== TSIG_GSS
) {
437 GssContext
gssctx(keyname
);
438 if (!gssctx
.getPeerPrincipal(q
->d_peer_principal
)) {
439 g_log
<<Logger::Warning
<<"Failed to extract peer principal from GSS context with keyname '"<<keyname
<<"'"<<endl
;
444 DNSSECKeeper
dk(s_P
->getBackend());
446 if (q
->d_tsig_algo
== TSIG_GSS
) {
447 vector
<string
> princs
;
448 s_P
->getBackend()->getDomainMetadata(q
->qdomain
, "GSS-ALLOW-AXFR-PRINCIPAL", princs
);
449 for(const std::string
& princ
: princs
) {
450 if (q
->d_peer_principal
== princ
) {
451 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
;
455 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
;
459 if(!dk
.TSIGGrantsAccess(q
->qdomain
, keyname
)) {
460 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
;
464 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
;
469 // cerr<<"checking allow-axfr-ips"<<endl;
470 if(!(::arg()["allow-axfr-ips"].empty()) && d_ng
.match( (ComboAddress
*) &q
->d_remote
)) {
471 g_log
<<Logger::Warning
<<"AXFR of domain '"<<q
->qdomain
<<"' allowed: client IP "<<q
->getRemote()<<" is in allow-axfr-ips"<<endl
;
477 // cerr<<"doing per-zone-axfr-acls"<<endl;
479 if(s_P
->getBackend()->getSOAUncached(q
->qdomain
,sd
)) {
480 // cerr<<"got backend and SOA"<<endl;
483 s_P
->getBackend()->getDomainMetadata(q
->qdomain
, "ALLOW-AXFR-FROM", acl
);
484 for (vector
<string
>::const_iterator i
= acl
.begin(); i
!= acl
.end(); ++i
) {
485 // cerr<<"matching against "<<*i<<endl;
486 if(pdns_iequals(*i
, "AUTO-NS")) {
487 // cerr<<"AUTO-NS magic please!"<<endl;
489 DNSResourceRecord rr
;
492 B
->lookup(QType(QType::NS
),q
->qdomain
);
494 nsset
.insert(DNSName(rr
.content
));
495 for(const auto & j
: nsset
) {
496 vector
<string
> nsips
=fns
.lookup(j
, s_P
->getBackend());
497 for(vector
<string
>::const_iterator k
=nsips
.begin();k
!=nsips
.end();++k
) {
498 // cerr<<"got "<<*k<<" from AUTO-NS"<<endl;
499 if(*k
== q
->getRemote().toString())
501 // cerr<<"got AUTO-NS hit"<<endl;
502 g_log
<<Logger::Warning
<<"AXFR of domain '"<<q
->qdomain
<<"' allowed: client IP "<<q
->getRemote()<<" is in NSset"<<endl
;
510 Netmask nm
= Netmask(*i
);
511 if(nm
.match( (ComboAddress
*) &q
->d_remote
))
513 g_log
<<Logger::Warning
<<"AXFR of domain '"<<q
->qdomain
<<"' allowed: client IP "<<q
->getRemote()<<" is in per-domain ACL"<<endl
;
514 // cerr<<"hit!"<<endl;
521 extern CommunicatorClass Communicator
;
523 if(Communicator
.justNotified(q
->qdomain
, q
->getRemote().toString())) { // we just notified this ip
524 g_log
<<Logger::Warning
<<"Approved AXFR of '"<<q
->qdomain
<<"' from recently notified slave "<<q
->getRemote()<<endl
;
528 g_log
<<Logger::Error
<<"AXFR of domain '"<<q
->qdomain
<<"' denied: client IP "<<q
->getRemote()<<" has no permission"<<endl
;
540 DNSZoneRecord
makeEditedDNSZRFromSOAData(DNSSECKeeper
& dk
, const SOAData
& sd
)
543 edited
.serial
= calculateEditSOA(sd
.serial
, dk
, sd
.qname
);
546 soa
.d_name
= sd
.qname
;
547 soa
.d_type
= QType::SOA
;
549 soa
.d_place
= DNSResourceRecord::ANSWER
;
550 soa
.d_content
= makeSOAContent(edited
);
559 shared_ptr
<DNSPacket
> getFreshAXFRPacket(shared_ptr
<DNSPacket
> q
)
561 shared_ptr
<DNSPacket
> ret
= shared_ptr
<DNSPacket
>(q
->replyPacket());
562 ret
->setCompress(false);
563 ret
->d_dnssecOk
=false; // RFC 5936, 2.2.5
570 /** do the actual zone transfer. Return 0 in case of error, 1 in case of success */
571 int TCPNameserver::doAXFR(const DNSName
&target
, shared_ptr
<DNSPacket
> q
, int outsock
)
573 shared_ptr
<DNSPacket
> outpacket
= getFreshAXFRPacket(q
);
575 outpacket
->d_dnssecOk
=true; // RFC 5936, 2.2.5 'SHOULD'
577 g_log
<<Logger::Error
<<"AXFR of domain '"<<target
<<"' initiated by "<<q
->getRemote()<<endl
;
579 // determine if zone exists and AXFR is allowed using existing backend before spawning a new backend.
583 DLOG(g_log
<<"Looking for SOA"<<endl
); // find domain_id via SOA and list complete domain. No SOA, no AXFR
585 g_log
<<Logger::Error
<<"TCP server is without backend connections in doAXFR, launching"<<endl
;
586 s_P
=new PacketHandler
;
589 // canDoAXFR does all the ACL checks, and has the if(disable-axfr) shortcut, call it first.
591 g_log
<<Logger::Error
<<"AXFR of domain '"<<target
<<"' failed: "<<q
->getRemote()<<" may not request AXFR"<<endl
;
592 outpacket
->setRcode(RCode::NotAuth
);
593 sendPacket(outpacket
,outsock
);
597 if(!s_P
->getBackend()->getSOAUncached(target
, sd
)) {
598 g_log
<<Logger::Error
<<"AXFR of domain '"<<target
<<"' failed: not authoritative"<<endl
;
599 outpacket
->setRcode(RCode::NotAuth
);
600 sendPacket(outpacket
,outsock
);
606 if(!db
.getSOAUncached(target
, sd
)) {
607 g_log
<<Logger::Error
<<"AXFR of domain '"<<target
<<"' failed: not authoritative in second instance"<<endl
;
608 outpacket
->setRcode(RCode::NotAuth
);
609 sendPacket(outpacket
,outsock
);
613 DNSSECKeeper
dk(&db
);
614 dk
.clearCaches(target
);
615 bool securedZone
= dk
.isSecuredZone(target
);
616 bool presignedZone
= dk
.isPresigned(target
);
618 bool noAXFRBecauseOfNSEC3Narrow
=false;
619 NSEC3PARAMRecordContent ns3pr
;
621 bool NSEC3Zone
=false;
622 if(securedZone
&& dk
.getNSEC3PARAM(target
, &ns3pr
, &narrow
)) {
625 g_log
<<Logger::Error
<<"Not doing AXFR of an NSEC3 narrow zone '"<<target
<<"' for "<<q
->getRemote()<<endl
;
626 noAXFRBecauseOfNSEC3Narrow
=true;
630 if(noAXFRBecauseOfNSEC3Narrow
) {
631 g_log
<<Logger::Error
<<"AXFR of domain '"<<target
<<"' denied to "<<q
->getRemote()<<endl
;
632 outpacket
->setRcode(RCode::Refused
);
633 // FIXME: should actually figure out if we are auth over a zone, and send out 9 if we aren't
634 sendPacket(outpacket
,outsock
);
638 TSIGRecordContent trc
;
642 bool haveTSIGDetails
= q
->getTSIGDetails(&trc
, &tsigkeyname
);
644 if(haveTSIGDetails
&& !tsigkeyname
.empty()) {
646 DNSName algorithm
=trc
.d_algoName
; // FIXME400: check
647 if (algorithm
== DNSName("hmac-md5.sig-alg.reg.int"))
648 algorithm
= DNSName("hmac-md5");
649 if (algorithm
!= DNSName("gss-tsig")) {
650 if(!db
.getTSIGKey(tsigkeyname
, &algorithm
, &tsig64
)) {
651 g_log
<<Logger::Error
<<"TSIG key '"<<tsigkeyname
<<"' for domain '"<<target
<<"' not found"<<endl
;
654 if (B64Decode(tsig64
, tsigsecret
) == -1) {
655 g_log
<<Logger::Error
<<"Unable to Base-64 decode TSIG key '"<<tsigkeyname
<<"' for domain '"<<target
<<"'"<<endl
;
662 // SOA *must* go out first, our signing pipe might reorder
663 DLOG(g_log
<<"Sending out SOA"<<endl
);
664 DNSZoneRecord soa
= makeEditedDNSZRFromSOAData(dk
, sd
);
665 outpacket
->addRecord(soa
);
666 if(securedZone
&& !presignedZone
) {
667 set
<DNSName
> authSet
;
668 authSet
.insert(target
);
669 addRRSigs(dk
, db
, authSet
, outpacket
->getRRS());
672 if(haveTSIGDetails
&& !tsigkeyname
.empty())
673 outpacket
->setTSIGDetails(trc
, tsigkeyname
, tsigsecret
, trc
.d_mac
); // first answer is 'normal'
675 sendPacket(outpacket
, outsock
);
677 trc
.d_mac
= outpacket
->d_trc
.d_mac
;
678 outpacket
= getFreshAXFRPacket(q
);
680 ChunkedSigningPipe
csp(target
, (securedZone
&& !presignedZone
), ::arg().asNum("signing-threads", 1));
682 typedef map
<DNSName
, NSECXEntry
, CanonDNSNameCompare
> nsecxrepo_t
;
683 nsecxrepo_t nsecxrepo
;
685 // this is where the DNSKEYs go in
687 DNSSECKeeper::keyset_t keys
= dk
.getKeys(target
);
691 zrr
.dr
.d_name
= target
;
692 zrr
.dr
.d_ttl
= sd
.default_ttl
;
693 zrr
.auth
= 1; // please sign!
695 string publishCDNSKEY
, publishCDS
;
696 dk
.getFromMeta(q
->qdomain
, "PUBLISH-CDNSKEY", publishCDNSKEY
);
697 dk
.getFromMeta(q
->qdomain
, "PUBLISH-CDS", publishCDS
);
698 vector
<DNSZoneRecord
> cds
, cdnskey
;
699 DNSSECKeeper::keyset_t entryPoints
= dk
.getEntryPoints(q
->qdomain
);
700 set
<uint32_t> entryPointIds
;
701 for (auto const& value
: entryPoints
)
702 entryPointIds
.insert(value
.second
.id
);
704 for(const DNSSECKeeper::keyset_t::value_type
& value
: keys
) {
705 zrr
.dr
.d_type
= QType::DNSKEY
;
706 zrr
.dr
.d_content
= std::make_shared
<DNSKEYRecordContent
>(value
.first
.getDNSKEY());
707 DNSName keyname
= NSEC3Zone
? DNSName(toBase32Hex(hashQNameWithSalt(ns3pr
, zrr
.dr
.d_name
))) : zrr
.dr
.d_name
;
708 NSECXEntry
& ne
= nsecxrepo
[keyname
];
710 ne
.d_set
.set(zrr
.dr
.d_type
);
711 ne
.d_ttl
= sd
.default_ttl
;
714 // generate CDS and CDNSKEY records
715 if(entryPointIds
.count(value
.second
.id
) > 0){
716 if(publishCDNSKEY
== "1") {
717 zrr
.dr
.d_type
=QType::CDNSKEY
;
718 zrr
.dr
.d_content
= std::make_shared
<DNSKEYRecordContent
>(value
.first
.getDNSKEY());
719 cdnskey
.push_back(zrr
);
722 if(!publishCDS
.empty()){
723 zrr
.dr
.d_type
=QType::CDS
;
724 vector
<string
> digestAlgos
;
725 stringtok(digestAlgos
, publishCDS
, ", ");
726 for(auto const &digestAlgo
: digestAlgos
) {
727 zrr
.dr
.d_content
=std::make_shared
<DSRecordContent
>(makeDSFromDNSKey(target
, value
.first
.getDNSKEY(), pdns_stou(digestAlgo
)));
734 if(::arg().mustDo("direct-dnskey")) {
735 sd
.db
->lookup(QType(QType::DNSKEY
), target
, NULL
, sd
.domain_id
);
736 while(sd
.db
->get(zrr
)) {
737 zrr
.dr
.d_ttl
= sd
.default_ttl
;
744 if(NSEC3Zone
) { // now stuff in the NSEC3PARAM
745 flags
= ns3pr
.d_flags
;
746 zrr
.dr
.d_type
= QType::NSEC3PARAM
;
748 zrr
.dr
.d_content
= std::make_shared
<NSEC3PARAMRecordContent
>(ns3pr
);
749 ns3pr
.d_flags
= flags
;
750 DNSName keyname
= DNSName(toBase32Hex(hashQNameWithSalt(ns3pr
, zrr
.dr
.d_name
)));
751 NSECXEntry
& ne
= nsecxrepo
[keyname
];
753 ne
.d_set
.set(zrr
.dr
.d_type
);
757 // now start list zone
758 if(!(sd
.db
->list(target
, sd
.domain_id
))) {
759 g_log
<<Logger::Error
<<"Backend signals error condition"<<endl
;
760 outpacket
->setRcode(RCode::ServFail
);
761 sendPacket(outpacket
,outsock
);
766 const bool rectify
= !(presignedZone
|| ::arg().mustDo("disable-axfr-rectify"));
767 set
<DNSName
> qnames
, nsset
, terms
;
768 vector
<DNSZoneRecord
> zrrs
;
770 // Add the CDNSKEY and CDS records we created earlier
771 for (auto const &synth_zrr
: cds
)
772 zrrs
.push_back(synth_zrr
);
774 for (auto const &synth_zrr
: cdnskey
)
775 zrrs
.push_back(synth_zrr
);
777 while(sd
.db
->get(zrr
)) {
778 zrr
.dr
.d_name
.makeUsLowerCase();
779 if(zrr
.dr
.d_name
.isPartOf(target
)) {
780 if (zrr
.dr
.d_type
== QType::ALIAS
&& ::arg().mustDo("outgoing-axfr-expand-alias")) {
781 vector
<DNSZoneRecord
> ips
;
782 int ret1
= stubDoResolve(getRR
<ALIASRecordContent
>(zrr
.dr
)->d_content
, QType::A
, ips
);
783 int ret2
= stubDoResolve(getRR
<ALIASRecordContent
>(zrr
.dr
)->d_content
, QType::AAAA
, ips
);
784 if(ret1
!= RCode::NoError
|| ret2
!= RCode::NoError
) {
785 g_log
<<Logger::Error
<<"Error resolving for ALIAS "<<zrr
.dr
.d_content
->getZoneRepresentation()<<", aborting AXFR"<<endl
;
786 outpacket
->setRcode(RCode::ServFail
);
787 sendPacket(outpacket
,outsock
);
790 for(const auto& ip
: ips
) {
791 zrr
.dr
.d_type
= ip
.dr
.d_type
;
792 zrr
.dr
.d_content
= ip
.dr
.d_content
;
800 qnames
.insert(zrr
.dr
.d_name
);
801 if(zrr
.dr
.d_type
== QType::NS
&& zrr
.dr
.d_name
!=target
)
802 nsset
.insert(zrr
.dr
.d_name
);
804 // remove existing ents
811 g_log
<<Logger::Warning
<<"Zone '"<<target
<<"' contains out-of-zone data '"<<zrr
.dr
.d_name
<<"|"<<DNSRecordContent::NumberToType(zrr
.dr
.d_type
)<<"', ignoring"<<endl
;
815 // Group records by name and type, signpipe stumbles over interrupted rrsets
816 if(securedZone
&& !presignedZone
) {
817 sort(zrrs
.begin(), zrrs
.end(), [](const DNSZoneRecord
& a
, const DNSZoneRecord
& b
) {
818 return tie(a
.dr
.d_name
, a
.dr
.d_type
) < tie(b
.dr
.d_name
, b
.dr
.d_type
);
824 for(DNSZoneRecord
&loopZRR
: zrrs
) {
826 if (loopZRR
.dr
.d_type
!= QType::NS
|| loopZRR
.dr
.d_name
!=target
) {
827 DNSName
shorter(loopZRR
.dr
.d_name
);
829 if (shorter
==target
) // apex is always auth
831 if(nsset
.count(shorter
) && !(loopZRR
.dr
.d_name
==shorter
&& loopZRR
.dr
.d_type
== QType::DS
)) {
835 } while(shorter
.chopOff());
840 // ents are only required for NSEC3 zones
841 uint32_t maxent
= ::arg().asNum("max-ent-entries");
842 set
<DNSName
> nsec3set
, nonterm
;
843 for (auto &loopZRR
: zrrs
) {
845 DNSName shorter
= loopZRR
.dr
.d_name
;
846 if (shorter
!= target
&& shorter
.chopOff() && shorter
!= target
) {
848 if(nsset
.count(shorter
)) {
852 } while(shorter
.chopOff() && shorter
!= target
);
854 shorter
= loopZRR
.dr
.d_name
;
855 if(!skip
&& (loopZRR
.dr
.d_type
!= QType::NS
|| !ns3pr
.d_flags
)) {
857 if(!nsec3set
.count(shorter
)) {
858 nsec3set
.insert(shorter
);
860 } while(shorter
!= target
&& shorter
.chopOff());
864 for(DNSZoneRecord
&loopZRR
: zrrs
) {
865 DNSName
shorter(loopZRR
.dr
.d_name
);
866 while(shorter
!= target
&& shorter
.chopOff()) {
867 if(!qnames
.count(shorter
) && !nonterm
.count(shorter
) && nsec3set
.count(shorter
)) {
869 g_log
<<Logger::Warning
<<"Zone '"<<target
<<"' has too many empty non terminals."<<endl
;
872 nonterm
.insert(shorter
);
878 for(const auto& nt
: nonterm
) {
879 DNSZoneRecord tempRR
;
881 tempRR
.dr
.d_type
=QType::ENT
;
883 zrrs
.push_back(tempRR
);
889 /* now write all other records */
896 for(DNSZoneRecord
&loopZRR
: zrrs
) {
897 if (!presignedZone
&& loopZRR
.dr
.d_type
== QType::RRSIG
)
900 // only skip the DNSKEY, CDNSKEY and CDS if direct-dnskey is enabled, to avoid changing behaviour
901 // when it is not enabled.
902 if(::arg().mustDo("direct-dnskey") && (loopZRR
.dr
.d_type
== QType::DNSKEY
|| loopZRR
.dr
.d_type
== QType::CDNSKEY
|| loopZRR
.dr
.d_type
== QType::CDS
))
906 if(securedZone
&& (loopZRR
.auth
|| loopZRR
.dr
.d_type
== QType::NS
)) {
907 if (NSEC3Zone
|| loopZRR
.dr
.d_type
) {
908 if (presignedZone
&& NSEC3Zone
&& loopZRR
.dr
.d_type
== QType::RRSIG
&& getRR
<RRSIGRecordContent
>(loopZRR
.dr
)->d_type
== QType::NSEC3
) {
909 keyname
= loopZRR
.dr
.d_name
.makeRelative(sd
.qname
);
911 keyname
= NSEC3Zone
? DNSName(toBase32Hex(hashQNameWithSalt(ns3pr
, loopZRR
.dr
.d_name
))) : loopZRR
.dr
.d_name
;
913 NSECXEntry
& ne
= nsecxrepo
[keyname
];
914 ne
.d_ttl
= sd
.default_ttl
;
915 ne
.d_auth
= (ne
.d_auth
|| loopZRR
.auth
|| (NSEC3Zone
&& (!ns3pr
.d_flags
)));
916 if (loopZRR
.dr
.d_type
&& loopZRR
.dr
.d_type
!= QType::RRSIG
) {
917 ne
.d_set
.set(loopZRR
.dr
.d_type
);
922 if (!loopZRR
.dr
.d_type
)
923 continue; // skip empty non-terminals
925 if(loopZRR
.dr
.d_type
== QType::SOA
)
926 continue; // skip SOA - would indicate end of AXFR
928 if(csp
.submit(loopZRR
)) {
930 outpacket
->getRRS() = csp
.getChunk();
931 if(!outpacket
->getRRS().empty()) {
932 if(haveTSIGDetails
&& !tsigkeyname
.empty())
933 outpacket
->setTSIGDetails(trc
, tsigkeyname
, tsigsecret
, trc
.d_mac
, true);
934 sendPacket(outpacket
, outsock
);
935 trc
.d_mac
=outpacket
->d_trc
.d_mac
;
936 outpacket
=getFreshAXFRPacket(q
);
944 udiff=dt.udiffNoReset();
945 cerr<<"Starting NSEC: "<<csp.d_signed/(udiff/1000000.0)<<" sigs/s, "<<csp.d_signed<<" / "<<udiff/1000000.0<<endl;
946 cerr<<"Outstanding: "<<csp.d_outstanding<<", "<<csp.d_queued - csp.d_signed << endl;
947 cerr<<"Ready for consumption: "<<csp.getReady()<<endl;
951 for(nsecxrepo_t::const_iterator iter
= nsecxrepo
.begin(); iter
!= nsecxrepo
.end(); ++iter
) {
952 if(iter
->second
.d_auth
) {
953 NSEC3RecordContent n3rc
;
954 n3rc
.set(iter
->second
.d_set
);
955 const auto numberOfTypesSet
= n3rc
.numberOfTypesSet();
956 if (numberOfTypesSet
!= 0 && (numberOfTypesSet
!= 1 || !n3rc
.isSet(QType::NS
))) {
957 n3rc
.set(QType::RRSIG
);
959 n3rc
.d_salt
= ns3pr
.d_salt
;
960 n3rc
.d_flags
= ns3pr
.d_flags
;
961 n3rc
.d_iterations
= ns3pr
.d_iterations
;
962 n3rc
.d_algorithm
= DNSSECKeeper::SHA1
; // SHA1, fixed in PowerDNS for now
963 nsecxrepo_t::const_iterator inext
= iter
;
965 if(inext
== nsecxrepo
.end())
966 inext
= nsecxrepo
.begin();
967 while(!inext
->second
.d_auth
&& inext
!= iter
)
970 if(inext
== nsecxrepo
.end())
971 inext
= nsecxrepo
.begin();
973 n3rc
.d_nexthash
= fromBase32Hex(inext
->first
.toStringNoDot());
974 zrr
.dr
.d_name
= iter
->first
+sd
.qname
;
976 zrr
.dr
.d_ttl
= sd
.default_ttl
;
977 zrr
.dr
.d_content
= std::make_shared
<NSEC3RecordContent
>(std::move(n3rc
));
978 zrr
.dr
.d_type
= QType::NSEC3
;
979 zrr
.dr
.d_place
= DNSResourceRecord::ANSWER
;
981 if(csp
.submit(zrr
)) {
983 outpacket
->getRRS() = csp
.getChunk();
984 if(!outpacket
->getRRS().empty()) {
985 if(haveTSIGDetails
&& !tsigkeyname
.empty())
986 outpacket
->setTSIGDetails(trc
, tsigkeyname
, tsigsecret
, trc
.d_mac
, true);
987 sendPacket(outpacket
, outsock
);
988 trc
.d_mac
=outpacket
->d_trc
.d_mac
;
989 outpacket
=getFreshAXFRPacket(q
);
998 else for(nsecxrepo_t::const_iterator iter
= nsecxrepo
.begin(); iter
!= nsecxrepo
.end(); ++iter
) {
999 NSECRecordContent nrc
;
1000 nrc
.set(iter
->second
.d_set
);
1001 nrc
.set(QType::RRSIG
);
1002 nrc
.set(QType::NSEC
);
1004 if(boost::next(iter
) != nsecxrepo
.end())
1005 nrc
.d_next
= boost::next(iter
)->first
;
1007 nrc
.d_next
=nsecxrepo
.begin()->first
;
1008 zrr
.dr
.d_name
= iter
->first
;
1010 zrr
.dr
.d_ttl
= sd
.default_ttl
;
1011 zrr
.dr
.d_content
= std::make_shared
<NSECRecordContent
>(std::move(nrc
));
1012 zrr
.dr
.d_type
= QType::NSEC
;
1013 zrr
.dr
.d_place
= DNSResourceRecord::ANSWER
;
1015 if(csp
.submit(zrr
)) {
1017 outpacket
->getRRS() = csp
.getChunk();
1018 if(!outpacket
->getRRS().empty()) {
1019 if(haveTSIGDetails
&& !tsigkeyname
.empty())
1020 outpacket
->setTSIGDetails(trc
, tsigkeyname
, tsigsecret
, trc
.d_mac
, true);
1021 sendPacket(outpacket
, outsock
);
1022 trc
.d_mac
=outpacket
->d_trc
.d_mac
;
1023 outpacket
=getFreshAXFRPacket(q
);
1032 udiff=dt.udiffNoReset();
1033 cerr<<"Flushing pipe: "<<csp.d_signed/(udiff/1000000.0)<<" sigs/s, "<<csp.d_signed<<" / "<<udiff/1000000.0<<endl;
1034 cerr<<"Outstanding: "<<csp.d_outstanding<<", "<<csp.d_queued - csp.d_signed << endl;
1035 cerr<<"Ready for consumption: "<<csp.getReady()<<endl;
1038 outpacket
->getRRS() = csp
.getChunk(true); // flush the pipe
1039 if(!outpacket
->getRRS().empty()) {
1040 if(haveTSIGDetails
&& !tsigkeyname
.empty())
1041 outpacket
->setTSIGDetails(trc
, tsigkeyname
, tsigsecret
, trc
.d_mac
, true); // first answer is 'normal'
1042 sendPacket(outpacket
, outsock
);
1043 trc
.d_mac
=outpacket
->d_trc
.d_mac
;
1044 outpacket
=getFreshAXFRPacket(q
);
1050 udiff
=dt
.udiffNoReset();
1052 g_log
<<Logger::Info
<<"Done signing: "<<csp
.d_signed
/(udiff
/1000000.0)<<" sigs/s, "<<endl
;
1054 DLOG(g_log
<<"Done writing out records"<<endl
);
1055 /* and terminate with yet again the SOA record */
1056 outpacket
=getFreshAXFRPacket(q
);
1057 outpacket
->addRecord(soa
);
1058 if(haveTSIGDetails
&& !tsigkeyname
.empty())
1059 outpacket
->setTSIGDetails(trc
, tsigkeyname
, tsigsecret
, trc
.d_mac
, true);
1061 sendPacket(outpacket
, outsock
);
1063 DLOG(g_log
<<"last packet - close"<<endl
);
1064 g_log
<<Logger::Error
<<"AXFR of domain '"<<target
<<"' to "<<q
->getRemote()<<" finished"<<endl
;
1069 int TCPNameserver::doIXFR(shared_ptr
<DNSPacket
> q
, int outsock
)
1071 shared_ptr
<DNSPacket
> outpacket
=getFreshAXFRPacket(q
);
1073 outpacket
->d_dnssecOk
=true; // RFC 5936, 2.2.5 'SHOULD'
1075 uint32_t serial
= 0;
1076 MOADNSParser
mdp(false, q
->getString());
1077 for(MOADNSParser::answers_t::const_iterator i
=mdp
.d_answers
.begin(); i
!= mdp
.d_answers
.end(); ++i
) {
1078 const DNSRecord
*rr
= &i
->first
;
1079 if (rr
->d_type
== QType::SOA
&& rr
->d_place
== DNSResourceRecord::AUTHORITY
) {
1080 vector
<string
>parts
;
1081 stringtok(parts
, rr
->d_content
->getZoneRepresentation());
1082 if (parts
.size() >= 3) {
1084 serial
=pdns_stou(parts
[2]);
1086 catch(const std::out_of_range
& oor
) {
1087 g_log
<<Logger::Error
<<"Invalid serial in IXFR query"<<endl
;
1088 outpacket
->setRcode(RCode::FormErr
);
1089 sendPacket(outpacket
,outsock
);
1093 g_log
<<Logger::Error
<<"No serial in IXFR query"<<endl
;
1094 outpacket
->setRcode(RCode::FormErr
);
1095 sendPacket(outpacket
,outsock
);
1098 } else if (rr
->d_type
!= QType::TSIG
&& rr
->d_type
!= QType::OPT
) {
1099 g_log
<<Logger::Error
<<"Additional records in IXFR query, type: "<<QType(rr
->d_type
).getName()<<endl
;
1100 outpacket
->setRcode(RCode::FormErr
);
1101 sendPacket(outpacket
,outsock
);
1106 g_log
<<Logger::Error
<<"IXFR of domain '"<<q
->qdomain
<<"' initiated by "<<q
->getRemote()<<" with serial "<<serial
<<endl
;
1108 // determine if zone exists and AXFR is allowed using existing backend before spawning a new backend.
1112 DLOG(g_log
<<"Looking for SOA"<<endl
); // find domain_id via SOA and list complete domain. No SOA, no IXFR
1114 g_log
<<Logger::Error
<<"TCP server is without backend connections in doIXFR, launching"<<endl
;
1115 s_P
=new PacketHandler
;
1118 // canDoAXFR does all the ACL checks, and has the if(disable-axfr) shortcut, call it first.
1119 if(!canDoAXFR(q
) || !s_P
->getBackend()->getSOAUncached(q
->qdomain
, sd
)) {
1120 g_log
<<Logger::Error
<<"IXFR of domain '"<<q
->qdomain
<<"' failed: not authoritative"<<endl
;
1121 outpacket
->setRcode(RCode::NotAuth
);
1122 sendPacket(outpacket
,outsock
);
1128 NSEC3PARAMRecordContent ns3pr
;
1131 dk
.clearCaches(q
->qdomain
);
1132 bool securedZone
= dk
.isSecuredZone(q
->qdomain
);
1133 if(dk
.getNSEC3PARAM(q
->qdomain
, &ns3pr
, &narrow
)) {
1135 g_log
<<Logger::Error
<<"Not doing IXFR of an NSEC3 narrow zone."<<endl
;
1136 g_log
<<Logger::Error
<<"IXFR of domain '"<<q
->qdomain
<<"' denied to "<<q
->getRemote()<<endl
;
1137 outpacket
->setRcode(RCode::Refused
);
1138 sendPacket(outpacket
,outsock
);
1143 DNSName target
= q
->qdomain
;
1146 if(!db
.getSOAUncached(target
, sd
)) {
1147 g_log
<<Logger::Error
<<"IXFR of domain '"<<target
<<"' failed: not authoritative in second instance"<<endl
;
1148 outpacket
->setRcode(RCode::NotAuth
);
1149 sendPacket(outpacket
,outsock
);
1153 if (!rfc1982LessThan(serial
, calculateEditSOA(sd
.serial
, dk
, sd
.qname
))) {
1154 TSIGRecordContent trc
;
1155 DNSName tsigkeyname
;
1158 bool haveTSIGDetails
= q
->getTSIGDetails(&trc
, &tsigkeyname
);
1160 if(haveTSIGDetails
&& !tsigkeyname
.empty()) {
1162 DNSName algorithm
=trc
.d_algoName
; // FIXME400: was toLowerCanonic, compare output
1163 if (algorithm
== DNSName("hmac-md5.sig-alg.reg.int"))
1164 algorithm
= DNSName("hmac-md5");
1166 if(!s_P
->getBackend()->getTSIGKey(tsigkeyname
, &algorithm
, &tsig64
)) {
1167 g_log
<<Logger::Error
<<"TSIG key '"<<tsigkeyname
<<"' for domain '"<<target
<<"' not found"<<endl
;
1170 if (B64Decode(tsig64
, tsigsecret
) == -1) {
1171 g_log
<<Logger::Error
<<"Unable to Base-64 decode TSIG key '"<<tsigkeyname
<<"' for domain '"<<target
<<"'"<<endl
;
1176 UeberBackend signatureDB
;
1178 // SOA *must* go out first, our signing pipe might reorder
1179 DLOG(g_log
<<"Sending out SOA"<<endl
);
1180 DNSZoneRecord soa
= makeEditedDNSZRFromSOAData(dk
, sd
);
1181 outpacket
->addRecord(soa
);
1183 set
<DNSName
> authSet
;
1184 authSet
.insert(target
);
1185 addRRSigs(dk
, signatureDB
, authSet
, outpacket
->getRRS());
1188 if(haveTSIGDetails
&& !tsigkeyname
.empty())
1189 outpacket
->setTSIGDetails(trc
, tsigkeyname
, tsigsecret
, trc
.d_mac
); // first answer is 'normal'
1191 sendPacket(outpacket
, outsock
);
1193 g_log
<<Logger::Error
<<"IXFR of domain '"<<target
<<"' to "<<q
->getRemote()<<" finished"<<endl
;
1198 g_log
<<Logger::Error
<<"IXFR fallback to AXFR for domain '"<<target
<<"' our serial "<<sd
.serial
<<endl
;
1199 return doAXFR(q
->qdomain
, q
, outsock
);
1202 TCPNameserver::~TCPNameserver()
1204 delete d_connectionroom_sem
;
1207 TCPNameserver::TCPNameserver()
1209 d_maxTransactionsPerConn
= ::arg().asNum("max-tcp-transactions-per-conn");
1210 d_idleTimeout
= ::arg().asNum("tcp-idle-timeout");
1211 d_maxConnectionDuration
= ::arg().asNum("max-tcp-connection-duration");
1212 d_maxConnectionsPerClient
= ::arg().asNum("max-tcp-connections-per-client");
1214 // sem_init(&d_connectionroom_sem,0,::arg().asNum("max-tcp-connections"));
1215 d_connectionroom_sem
= new Semaphore( ::arg().asNum( "max-tcp-connections" ));
1217 vector
<string
>locals
;
1218 stringtok(locals
,::arg()["local-address"]," ,");
1220 vector
<string
>locals6
;
1221 stringtok(locals6
,::arg()["local-ipv6"]," ,");
1223 if(locals
.empty() && locals6
.empty())
1224 throw PDNSException("No local address specified");
1226 d_ng
.toMasks(::arg()["allow-axfr-ips"] );
1228 signal(SIGPIPE
,SIG_IGN
);
1230 for(vector
<string
>::const_iterator laddr
=locals
.begin();laddr
!=locals
.end();++laddr
) {
1231 int s
=socket(AF_INET
,SOCK_STREAM
,0);
1234 throw PDNSException("Unable to acquire TCP socket: "+stringerror());
1238 ComboAddress
local(*laddr
, ::arg().asNum("local-port"));
1241 if(setsockopt(s
,SOL_SOCKET
,SO_REUSEADDR
,(char*)&tmp
,sizeof tmp
)<0) {
1242 g_log
<<Logger::Error
<<"Setsockopt failed"<<endl
;
1246 if (::arg().asNum("tcp-fast-open") > 0) {
1248 int fastOpenQueueSize
= ::arg().asNum("tcp-fast-open");
1249 if (setsockopt(s
, IPPROTO_TCP
, TCP_FASTOPEN
, &fastOpenQueueSize
, sizeof fastOpenQueueSize
) < 0) {
1250 g_log
<<Logger::Error
<<"Failed to enable TCP Fast Open for listening socket: "<<strerror(errno
)<<endl
;
1253 g_log
<<Logger::Warning
<<"TCP Fast Open configured but not supported for listening socket"<<endl
;
1257 if( ::arg().mustDo("non-local-bind") )
1258 Utility::setBindAny(AF_INET
, s
);
1260 if(::bind(s
, (sockaddr
*)&local
, local
.getSocklen())<0) {
1262 if( errno
== EADDRNOTAVAIL
&& ! ::arg().mustDo("local-address-nonexist-fail") ) {
1263 g_log
<<Logger::Error
<<"IPv4 Address " << *laddr
<< " does not exist on this server - skipping TCP bind" << endl
;
1266 g_log
<<Logger::Error
<<"Unable to bind to TCP socket " << *laddr
<< ": "<<strerror(errno
)<<endl
;
1267 throw PDNSException("Unable to bind to TCP socket");
1272 g_log
<<Logger::Error
<<"TCP server bound to "<<local
.toStringWithPort()<<endl
;
1273 d_sockets
.push_back(s
);
1275 memset(&pfd
, 0, sizeof(pfd
));
1277 pfd
.events
= POLLIN
;
1279 d_prfds
.push_back(pfd
);
1282 for(vector
<string
>::const_iterator laddr
=locals6
.begin();laddr
!=locals6
.end();++laddr
) {
1283 int s
=socket(AF_INET6
,SOCK_STREAM
,0);
1286 throw PDNSException("Unable to acquire TCPv6 socket: "+stringerror());
1290 ComboAddress
local(*laddr
, ::arg().asNum("local-port"));
1293 if(setsockopt(s
,SOL_SOCKET
,SO_REUSEADDR
,(char*)&tmp
,sizeof tmp
)<0) {
1294 g_log
<<Logger::Error
<<"Setsockopt failed"<<endl
;
1298 if (::arg().asNum("tcp-fast-open") > 0) {
1300 int fastOpenQueueSize
= ::arg().asNum("tcp-fast-open");
1301 if (setsockopt(s
, IPPROTO_TCP
, TCP_FASTOPEN
, &fastOpenQueueSize
, sizeof fastOpenQueueSize
) < 0) {
1302 g_log
<<Logger::Error
<<"Failed to enable TCP Fast Open for listening socket: "<<strerror(errno
)<<endl
;
1305 g_log
<<Logger::Warning
<<"TCP Fast Open configured but not supported for listening socket"<<endl
;
1309 if( ::arg().mustDo("non-local-bind") )
1310 Utility::setBindAny(AF_INET6
, s
);
1311 if(setsockopt(s
, IPPROTO_IPV6
, IPV6_V6ONLY
, &tmp
, sizeof(tmp
)) < 0) {
1312 g_log
<<Logger::Error
<<"Failed to set IPv6 socket to IPv6 only, continuing anyhow: "<<strerror(errno
)<<endl
;
1314 if(bind(s
, (const sockaddr
*)&local
, local
.getSocklen())<0) {
1316 if( errno
== EADDRNOTAVAIL
&& ! ::arg().mustDo("local-ipv6-nonexist-fail") ) {
1317 g_log
<<Logger::Error
<<"IPv6 Address " << *laddr
<< " does not exist on this server - skipping TCP bind" << endl
;
1320 g_log
<<Logger::Error
<<"Unable to bind to TCPv6 socket" << *laddr
<< ": "<<strerror(errno
)<<endl
;
1321 throw PDNSException("Unable to bind to TCPv6 socket");
1326 g_log
<<Logger::Error
<<"TCPv6 server bound to "<<local
.toStringWithPort()<<endl
; // this gets %eth0 right
1327 d_sockets
.push_back(s
);
1330 memset(&pfd
, 0, sizeof(pfd
));
1332 pfd
.events
= POLLIN
;
1334 d_prfds
.push_back(pfd
);
1339 //! Start of TCP operations thread, we launch a new thread for each incoming TCP question
1340 void TCPNameserver::thread()
1342 setThreadName("pdns/tcpnameser");
1346 ComboAddress remote
;
1347 Utility::socklen_t addrlen
=remote
.getSocklen();
1349 int ret
=poll(&d_prfds
[0], d_prfds
.size(), -1); // blocks, forever if need be
1354 for(const pollfd
& pfd
: d_prfds
) {
1355 if(pfd
.revents
== POLLIN
) {
1357 remote
.sin4
.sin_family
= AF_INET6
;
1358 addrlen
=remote
.getSocklen();
1360 if((fd
=accept(sock
, (sockaddr
*)&remote
, &addrlen
))<0) {
1361 g_log
<<Logger::Error
<<"TCP question accept error: "<<strerror(errno
)<<endl
;
1364 g_log
<<Logger::Error
<<"TCP handler out of filedescriptors, exiting, won't recover from this"<<endl
;
1369 if (d_maxConnectionsPerClient
) {
1370 std::lock_guard
<std::mutex
> lock(s_clientsCountMutex
);
1371 if (s_clientsCount
[remote
] >= d_maxConnectionsPerClient
) {
1372 g_log
<<Logger::Notice
<<"Limit of simultaneous TCP connections per client reached for "<< remote
<<", dropping"<<endl
;
1376 s_clientsCount
[remote
]++;
1380 d_connectionroom_sem
->wait(); // blocks if no connections are available
1383 d_connectionroom_sem
->getValue( &room
);
1385 g_log
<<Logger::Warning
<<"Limit of simultaneous TCP connections reached - raise max-tcp-connections"<<endl
;
1387 if(pthread_create(&tid
, 0, &doConnection
, reinterpret_cast<void*>(fd
))) {
1388 g_log
<<Logger::Error
<<"Error creating thread: "<<stringerror()<<endl
;
1389 d_connectionroom_sem
->post();
1391 decrementClientCount(remote
);
1398 catch(PDNSException
&AE
) {
1399 g_log
<<Logger::Error
<<"TCP Nameserver thread dying because of fatal error: "<<AE
.reason
<<endl
;
1402 g_log
<<Logger::Error
<<"TCPNameserver dying because of an unexpected fatal error"<<endl
;
1404 _exit(1); // take rest of server with us