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 std::unique_ptr
<Semaphore
> TCPNameserver::d_connectionroom_sem
{nullptr};
71 std::unique_ptr
<PacketHandler
> TCPNameserver::s_P
{nullptr};
72 unsigned int TCPNameserver::d_maxTCPConnections
= 0;
73 NetmaskGroup
TCPNameserver::d_ng
;
74 size_t TCPNameserver::d_maxTransactionsPerConn
;
75 size_t TCPNameserver::d_maxConnectionsPerClient
;
76 unsigned int TCPNameserver::d_idleTimeout
;
77 unsigned int TCPNameserver::d_maxConnectionDuration
;
78 std::mutex
TCPNameserver::s_clientsCountMutex
;
79 std::map
<ComboAddress
,size_t,ComboAddress::addressOnlyLessThan
> TCPNameserver::s_clientsCount
;
81 void TCPNameserver::go()
83 g_log
<<Logger::Error
<<"Creating backend connection for TCP"<<endl
;
86 s_P
=make_unique
<PacketHandler
>();
88 catch(PDNSException
&ae
) {
89 g_log
<<Logger::Error
<<"TCP server is unable to launch backends - will try again when questions come in: "<<ae
.reason
<<endl
;
91 pthread_create(&d_tid
, 0, launcher
, static_cast<void *>(this));
94 void *TCPNameserver::launcher(void *data
)
96 static_cast<TCPNameserver
*>(data
)->thread();
100 // throws PDNSException if things didn't go according to plan, returns 0 if really 0 bytes were read
101 static int readnWithTimeout(int fd
, void* buffer
, unsigned int n
, unsigned int idleTimeout
, bool throwOnEOF
=true, unsigned int totalTimeout
=0)
103 unsigned int bytes
=n
;
104 char *ptr
= (char*)buffer
;
107 unsigned int remainingTotal
= totalTimeout
;
112 ret
=read(fd
, ptr
, bytes
);
115 ret
=waitForData(fd
, (totalTimeout
== 0 || idleTimeout
<= remainingTotal
) ? idleTimeout
: remainingTotal
);
117 throw NetworkError("Waiting for data read");
119 throw NetworkError("Timeout reading data");
123 throw NetworkError("Reading data: "+stringerror());
126 if(!throwOnEOF
&& n
== bytes
)
129 throw NetworkError("Did not fulfill read from TCP due to EOF");
135 time_t now
= time(NULL
);
136 unsigned int elapsed
= now
- start
;
137 if (elapsed
>= remainingTotal
) {
138 throw NetworkError("Timeout while reading data");
141 remainingTotal
-= elapsed
;
148 static void writenWithTimeout(int fd
, const void *buffer
, unsigned int n
, unsigned int idleTimeout
)
150 unsigned int bytes
=n
;
151 const char *ptr
= (char*)buffer
;
154 ret
=write(fd
, ptr
, bytes
);
157 ret
=waitForRWData(fd
, false, idleTimeout
, 0);
159 throw NetworkError("Waiting for data write");
161 throw NetworkError("Timeout writing data");
165 throw NetworkError("Writing data: "+stringerror());
168 throw NetworkError("Did not fulfill TCP write due to EOF");
176 void connectWithTimeout(int fd
, struct sockaddr
* remote
, size_t socklen
)
179 Utility::socklen_t len
=sizeof(err
);
181 if((err
=connect(fd
, remote
, socklen
))<0 && errno
!=EINPROGRESS
)
182 throw NetworkError("connect: "+stringerror());
187 err
=waitForRWData(fd
, false, 5, 0);
189 throw NetworkError("Timeout connecting to remote");
191 throw NetworkError("Error connecting to remote");
193 if(getsockopt(fd
, SOL_SOCKET
,SO_ERROR
,(char *)&err
,&len
)<0)
194 throw NetworkError("Error connecting to remote: "+stringerror()); // Solaris
197 throw NetworkError("Error connecting to remote: "+string(strerror(err
)));
203 void TCPNameserver::sendPacket(std::unique_ptr
<DNSPacket
>& p
, int outsock
)
205 g_rs
.submitResponse(*p
, false);
207 uint16_t len
=htons(p
->getString().length());
208 string
buffer((const char*)&len
, 2);
209 buffer
.append(p
->getString());
210 writenWithTimeout(outsock
, buffer
.c_str(), buffer
.length(), d_idleTimeout
);
214 void TCPNameserver::getQuestion(int fd
, char *mesg
, int pktlen
, const ComboAddress
&remote
, unsigned int totalTime
)
217 readnWithTimeout(fd
, mesg
, pktlen
, d_idleTimeout
, true, totalTime
);
219 catch(NetworkError
& ae
) {
220 throw NetworkError("Error reading DNS data from TCP client "+remote
.toString()+": "+ae
.what());
223 static void incTCPAnswerCount(const ComboAddress
& remote
)
225 S
.inc("tcp-answers");
226 if(remote
.sin4
.sin_family
== AF_INET6
)
227 S
.inc("tcp6-answers");
229 S
.inc("tcp4-answers");
232 static bool maxConnectionDurationReached(unsigned int maxConnectionDuration
, time_t start
, unsigned int& remainingTime
)
234 if (maxConnectionDuration
) {
235 time_t elapsed
= time(NULL
) - start
;
236 if (elapsed
>= maxConnectionDuration
) {
239 remainingTime
= maxConnectionDuration
- elapsed
;
244 void TCPNameserver::decrementClientCount(const ComboAddress
& remote
)
246 if (d_maxConnectionsPerClient
) {
247 std::lock_guard
<std::mutex
> lock(s_clientsCountMutex
);
248 s_clientsCount
[remote
]--;
249 if (s_clientsCount
[remote
] == 0) {
250 s_clientsCount
.erase(remote
);
255 void *TCPNameserver::doConnection(void *data
)
257 setThreadName("pdns/tcpConnect");
258 std::unique_ptr
<DNSPacket
> packet
;
259 // Fix gcc-4.0 error (on AMD64)
260 int fd
=(int)(long)data
; // gotta love C (generates a harmless warning on opteron)
262 socklen_t remotelen
=sizeof(remote
);
263 size_t transactions
= 0;
265 if (d_maxConnectionDuration
) {
269 pthread_detach(pthread_self());
270 if(getpeername(fd
, (struct sockaddr
*)&remote
, &remotelen
) < 0) {
271 g_log
<<Logger::Warning
<<"Received question from socket which had no remote address, dropping ("<<stringerror()<<")"<<endl
;
272 d_connectionroom_sem
->post();
276 catch(const PDNSException
& e
) {
277 g_log
<<Logger::Error
<<"Error closing TCP socket: "<<e
.reason
<<endl
;
285 scoped_array
<char> mesg(new char[mesgsize
]);
287 DLOG(g_log
<<"TCP Connection accepted on fd "<<fd
<<endl
);
288 bool logDNSQueries
= ::arg().mustDo("log-dns-queries");
290 unsigned int remainingTime
= 0;
292 if (d_maxTransactionsPerConn
&& transactions
> d_maxTransactionsPerConn
) {
293 g_log
<< Logger::Notice
<<"TCP Remote "<< remote
<<" exceeded the number of transactions per connection, dropping.";
296 if (maxConnectionDurationReached(d_maxConnectionDuration
, start
, remainingTime
)) {
297 g_log
<< Logger::Notice
<<"TCP Remote "<< remote
<<" exceeded the maximum TCP connection duration, dropping.";
302 if(!readnWithTimeout(fd
, &pktlen
, 2, d_idleTimeout
, false, remainingTime
))
305 pktlen
=ntohs(pktlen
);
307 // this check will always be false *if* no one touches
308 // the mesg array. pktlen can be maximum of 65535 as
309 // it is 2 byte unsigned variable. In getQuestion, we
310 // write to 0 up to pktlen-1 so 65535 is just right.
312 // do not remove this check as it will catch if someone
313 // decreases the mesg buffer size for some reason.
314 if(pktlen
> mesgsize
) {
315 g_log
<<Logger::Warning
<<"Received an overly large question from "<<remote
.toString()<<", dropping"<<endl
;
319 if (maxConnectionDurationReached(d_maxConnectionDuration
, start
, remainingTime
)) {
320 g_log
<< Logger::Notice
<<"TCP Remote "<< remote
<<" exceeded the maximum TCP connection duration, dropping.";
324 getQuestion(fd
, mesg
.get(), pktlen
, remote
, remainingTime
);
325 S
.inc("tcp-queries");
326 if(remote
.sin4
.sin_family
== AF_INET6
)
327 S
.inc("tcp6-queries");
329 S
.inc("tcp4-queries");
331 packet
=make_unique
<DNSPacket
>(true);
332 packet
->setRemote(&remote
);
334 packet
->setSocket(fd
);
335 if(packet
->parse(mesg
.get(), pktlen
)<0)
338 if(packet
->qtype
.getCode()==QType::AXFR
) {
339 if(doAXFR(packet
->qdomain
, packet
, fd
))
340 incTCPAnswerCount(remote
);
344 if(packet
->qtype
.getCode()==QType::IXFR
) {
345 if(doIXFR(packet
, fd
))
346 incTCPAnswerCount(remote
);
350 std::unique_ptr
<DNSPacket
> reply
;
351 auto cached
= make_unique
<DNSPacket
>(false);
354 if(packet
->hasEDNSSubnet())
355 remote_text
= packet
->getRemote().toString() + "<-" + packet
->getRealRemote().toString();
357 remote_text
= packet
->getRemote().toString();
358 g_log
<< Logger::Notice
<<"TCP Remote "<< remote_text
<<" wants '" << packet
->qdomain
<<"|"<<packet
->qtype
.getName() <<
359 "', do = " <<packet
->d_dnssecOk
<<", bufsize = "<< packet
->getMaxReplyLen();
363 if(packet
->couldBeCached() && PC
.get(*packet
, *cached
)) { // short circuit - does the PacketCache recognize this question?
365 g_log
<<": packetcache HIT"<<endl
;
366 cached
->setRemote(&packet
->d_remote
);
367 cached
->d
.id
=packet
->d
.id
;
368 cached
->d
.rd
=packet
->d
.rd
; // copy in recursion desired bit
369 cached
->commitD(); // commit d to the packet inlined
371 sendPacket(cached
, fd
); // presigned, don't do it again
375 g_log
<<": packetcache MISS"<<endl
;
384 g_log
<<Logger::Error
<<"TCP server is without backend connections, launching"<<endl
;
385 s_P
=make_unique
<PacketHandler
>();
388 reply
= s_P
->doQuestion(*packet
); // we really need to ask the backend :-)
391 if(!reply
) // unable to write an answer?
394 sendPacket(reply
, fd
);
397 catch(PDNSException
&ae
) {
399 s_P
.reset(); // on next call, backend will be recycled
400 g_log
<<Logger::Error
<<"TCP nameserver had error, cycling backend: "<<ae
.reason
<<endl
;
402 catch(NetworkError
&e
) {
403 g_log
<<Logger::Info
<<"TCP Connection Thread died because of network error: "<<e
.what()<<endl
;
406 catch(std::exception
&e
) {
407 g_log
<<Logger::Error
<<"TCP Connection Thread died because of STL error: "<<e
.what()<<endl
;
411 g_log
<< Logger::Error
<< "TCP Connection Thread caught unknown exception." << endl
;
413 d_connectionroom_sem
->post();
418 catch(const PDNSException
& e
) {
419 g_log
<<Logger::Error
<<"Error closing TCP socket: "<<e
.reason
<<endl
;
421 decrementClientCount(remote
);
427 // call this method with s_plock held!
428 bool TCPNameserver::canDoAXFR(std::unique_ptr
<DNSPacket
>& q
)
430 if(::arg().mustDo("disable-axfr"))
433 if(q
->d_havetsig
) { // if you have one, it must be good
434 TSIGRecordContent trc
;
437 if(!q
->checkForCorrectTSIG(s_P
->getBackend(), &keyname
, &secret
, &trc
)) {
440 getTSIGHashEnum(trc
.d_algoName
, q
->d_tsig_algo
);
441 if (q
->d_tsig_algo
== TSIG_GSS
) {
442 GssContext
gssctx(keyname
);
443 if (!gssctx
.getPeerPrincipal(q
->d_peer_principal
)) {
444 g_log
<<Logger::Warning
<<"Failed to extract peer principal from GSS context with keyname '"<<keyname
<<"'"<<endl
;
449 DNSSECKeeper
dk(s_P
->getBackend());
451 if (q
->d_tsig_algo
== TSIG_GSS
) {
452 vector
<string
> princs
;
453 s_P
->getBackend()->getDomainMetadata(q
->qdomain
, "GSS-ALLOW-AXFR-PRINCIPAL", princs
);
454 for(const std::string
& princ
: princs
) {
455 if (q
->d_peer_principal
== princ
) {
456 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
;
460 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
;
464 if(!dk
.TSIGGrantsAccess(q
->qdomain
, keyname
)) {
465 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
;
469 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
;
474 // cerr<<"checking allow-axfr-ips"<<endl;
475 if(!(::arg()["allow-axfr-ips"].empty()) && d_ng
.match( (ComboAddress
*) &q
->d_remote
)) {
476 g_log
<<Logger::Warning
<<"AXFR of domain '"<<q
->qdomain
<<"' allowed: client IP "<<q
->getRemote()<<" is in allow-axfr-ips"<<endl
;
482 // cerr<<"doing per-zone-axfr-acls"<<endl;
484 if(s_P
->getBackend()->getSOAUncached(q
->qdomain
,sd
)) {
485 // cerr<<"got backend and SOA"<<endl;
488 s_P
->getBackend()->getDomainMetadata(q
->qdomain
, "ALLOW-AXFR-FROM", acl
);
489 for (vector
<string
>::const_iterator i
= acl
.begin(); i
!= acl
.end(); ++i
) {
490 // cerr<<"matching against "<<*i<<endl;
491 if(pdns_iequals(*i
, "AUTO-NS")) {
492 // cerr<<"AUTO-NS magic please!"<<endl;
494 DNSResourceRecord rr
;
497 B
->lookup(QType(QType::NS
),q
->qdomain
,sd
.domain_id
);
499 nsset
.insert(DNSName(rr
.content
));
500 for(const auto & j
: nsset
) {
501 vector
<string
> nsips
=fns
.lookup(j
, s_P
->getBackend());
502 for(vector
<string
>::const_iterator k
=nsips
.begin();k
!=nsips
.end();++k
) {
503 // cerr<<"got "<<*k<<" from AUTO-NS"<<endl;
504 if(*k
== q
->getRemote().toString())
506 // cerr<<"got AUTO-NS hit"<<endl;
507 g_log
<<Logger::Warning
<<"AXFR of domain '"<<q
->qdomain
<<"' allowed: client IP "<<q
->getRemote()<<" is in NSset"<<endl
;
515 Netmask nm
= Netmask(*i
);
516 if(nm
.match( (ComboAddress
*) &q
->d_remote
))
518 g_log
<<Logger::Warning
<<"AXFR of domain '"<<q
->qdomain
<<"' allowed: client IP "<<q
->getRemote()<<" is in per-domain ACL"<<endl
;
519 // cerr<<"hit!"<<endl;
526 extern CommunicatorClass Communicator
;
528 if(Communicator
.justNotified(q
->qdomain
, q
->getRemote().toString())) { // we just notified this ip
529 g_log
<<Logger::Warning
<<"Approved AXFR of '"<<q
->qdomain
<<"' from recently notified slave "<<q
->getRemote()<<endl
;
533 g_log
<<Logger::Error
<<"AXFR of domain '"<<q
->qdomain
<<"' denied: client IP "<<q
->getRemote()<<" has no permission"<<endl
;
545 static std::unique_ptr
<DNSPacket
> getFreshAXFRPacket(std::unique_ptr
<DNSPacket
>& q
)
547 std::unique_ptr
<DNSPacket
> ret
= std::unique_ptr
<DNSPacket
>(q
->replyPacket());
548 ret
->setCompress(false);
549 ret
->d_dnssecOk
=false; // RFC 5936, 2.2.5
556 /** do the actual zone transfer. Return 0 in case of error, 1 in case of success */
557 int TCPNameserver::doAXFR(const DNSName
&target
, std::unique_ptr
<DNSPacket
>& q
, int outsock
)
559 std::unique_ptr
<DNSPacket
> outpacket
= getFreshAXFRPacket(q
);
561 outpacket
->d_dnssecOk
=true; // RFC 5936, 2.2.5 'SHOULD'
563 g_log
<<Logger::Error
<<"AXFR of domain '"<<target
<<"' initiated by "<<q
->getRemote()<<endl
;
565 // determine if zone exists and AXFR is allowed using existing backend before spawning a new backend.
569 DLOG(g_log
<<"Looking for SOA"<<endl
); // find domain_id via SOA and list complete domain. No SOA, no AXFR
571 g_log
<<Logger::Error
<<"TCP server is without backend connections in doAXFR, launching"<<endl
;
572 s_P
=make_unique
<PacketHandler
>();
575 // canDoAXFR does all the ACL checks, and has the if(disable-axfr) shortcut, call it first.
577 g_log
<<Logger::Error
<<"AXFR of domain '"<<target
<<"' failed: "<<q
->getRemote()<<" may not request AXFR"<<endl
;
578 outpacket
->setRcode(RCode::NotAuth
);
579 sendPacket(outpacket
,outsock
);
583 if(!s_P
->getBackend()->getSOAUncached(target
, sd
)) {
584 g_log
<<Logger::Error
<<"AXFR of domain '"<<target
<<"' failed: not authoritative"<<endl
;
585 outpacket
->setRcode(RCode::NotAuth
);
586 sendPacket(outpacket
,outsock
);
592 if(!db
.getSOAUncached(target
, sd
)) {
593 g_log
<<Logger::Error
<<"AXFR of domain '"<<target
<<"' failed: not authoritative in second instance"<<endl
;
594 outpacket
->setRcode(RCode::NotAuth
);
595 sendPacket(outpacket
,outsock
);
599 DNSSECKeeper
dk(&db
);
600 DNSSECKeeper::clearCaches(target
);
601 bool securedZone
= dk
.isSecuredZone(target
);
602 bool presignedZone
= dk
.isPresigned(target
);
604 bool noAXFRBecauseOfNSEC3Narrow
=false;
605 NSEC3PARAMRecordContent ns3pr
;
607 bool NSEC3Zone
=false;
608 if(securedZone
&& dk
.getNSEC3PARAM(target
, &ns3pr
, &narrow
)) {
611 g_log
<<Logger::Error
<<"Not doing AXFR of an NSEC3 narrow zone '"<<target
<<"' for "<<q
->getRemote()<<endl
;
612 noAXFRBecauseOfNSEC3Narrow
=true;
616 if(noAXFRBecauseOfNSEC3Narrow
) {
617 g_log
<<Logger::Error
<<"AXFR of domain '"<<target
<<"' denied to "<<q
->getRemote()<<endl
;
618 outpacket
->setRcode(RCode::Refused
);
619 // FIXME: should actually figure out if we are auth over a zone, and send out 9 if we aren't
620 sendPacket(outpacket
,outsock
);
624 TSIGRecordContent trc
;
628 bool haveTSIGDetails
= q
->getTSIGDetails(&trc
, &tsigkeyname
);
630 if(haveTSIGDetails
&& !tsigkeyname
.empty()) {
632 DNSName algorithm
=trc
.d_algoName
; // FIXME400: check
633 if (algorithm
== DNSName("hmac-md5.sig-alg.reg.int"))
634 algorithm
= DNSName("hmac-md5");
635 if (algorithm
!= DNSName("gss-tsig")) {
636 if(!db
.getTSIGKey(tsigkeyname
, &algorithm
, &tsig64
)) {
637 g_log
<<Logger::Error
<<"TSIG key '"<<tsigkeyname
<<"' for domain '"<<target
<<"' not found"<<endl
;
640 if (B64Decode(tsig64
, tsigsecret
) == -1) {
641 g_log
<<Logger::Error
<<"Unable to Base-64 decode TSIG key '"<<tsigkeyname
<<"' for domain '"<<target
<<"'"<<endl
;
648 // SOA *must* go out first, our signing pipe might reorder
649 DLOG(g_log
<<"Sending out SOA"<<endl
);
650 DNSZoneRecord soa
= makeEditedDNSZRFromSOAData(dk
, sd
);
651 outpacket
->addRecord(soa
);
652 if(securedZone
&& !presignedZone
) {
653 set
<DNSName
> authSet
;
654 authSet
.insert(target
);
655 addRRSigs(dk
, db
, authSet
, outpacket
->getRRS());
658 if(haveTSIGDetails
&& !tsigkeyname
.empty())
659 outpacket
->setTSIGDetails(trc
, tsigkeyname
, tsigsecret
, trc
.d_mac
); // first answer is 'normal'
661 sendPacket(outpacket
, outsock
);
663 trc
.d_mac
= outpacket
->d_trc
.d_mac
;
664 outpacket
= getFreshAXFRPacket(q
);
666 ChunkedSigningPipe
csp(target
, (securedZone
&& !presignedZone
), ::arg().asNum("signing-threads", 1));
668 typedef map
<DNSName
, NSECXEntry
, CanonDNSNameCompare
> nsecxrepo_t
;
669 nsecxrepo_t nsecxrepo
;
671 // this is where the DNSKEYs go in
673 DNSSECKeeper::keyset_t keys
= dk
.getKeys(target
);
677 zrr
.dr
.d_name
= target
;
678 zrr
.dr
.d_ttl
= sd
.default_ttl
;
679 zrr
.auth
= 1; // please sign!
681 string publishCDNSKEY
, publishCDS
;
682 dk
.getFromMeta(q
->qdomain
, "PUBLISH-CDNSKEY", publishCDNSKEY
);
683 dk
.getFromMeta(q
->qdomain
, "PUBLISH-CDS", publishCDS
);
684 vector
<DNSZoneRecord
> cds
, cdnskey
;
685 DNSSECKeeper::keyset_t entryPoints
= dk
.getEntryPoints(q
->qdomain
);
686 set
<uint32_t> entryPointIds
;
687 for (auto const& value
: entryPoints
)
688 entryPointIds
.insert(value
.second
.id
);
690 for(const DNSSECKeeper::keyset_t::value_type
& value
: keys
) {
691 zrr
.dr
.d_type
= QType::DNSKEY
;
692 zrr
.dr
.d_content
= std::make_shared
<DNSKEYRecordContent
>(value
.first
.getDNSKEY());
693 DNSName keyname
= NSEC3Zone
? DNSName(toBase32Hex(hashQNameWithSalt(ns3pr
, zrr
.dr
.d_name
))) : zrr
.dr
.d_name
;
694 NSECXEntry
& ne
= nsecxrepo
[keyname
];
696 ne
.d_set
.set(zrr
.dr
.d_type
);
697 ne
.d_ttl
= sd
.default_ttl
;
700 // generate CDS and CDNSKEY records
701 if(entryPointIds
.count(value
.second
.id
) > 0){
702 if(publishCDNSKEY
== "1") {
703 zrr
.dr
.d_type
=QType::CDNSKEY
;
704 zrr
.dr
.d_content
= std::make_shared
<DNSKEYRecordContent
>(value
.first
.getDNSKEY());
705 cdnskey
.push_back(zrr
);
708 if(!publishCDS
.empty()){
709 zrr
.dr
.d_type
=QType::CDS
;
710 vector
<string
> digestAlgos
;
711 stringtok(digestAlgos
, publishCDS
, ", ");
712 for(auto const &digestAlgo
: digestAlgos
) {
713 zrr
.dr
.d_content
=std::make_shared
<DSRecordContent
>(makeDSFromDNSKey(target
, value
.first
.getDNSKEY(), pdns_stou(digestAlgo
)));
720 if(::arg().mustDo("direct-dnskey")) {
721 sd
.db
->lookup(QType(QType::DNSKEY
), target
, sd
.domain_id
);
722 while(sd
.db
->get(zrr
)) {
723 zrr
.dr
.d_ttl
= sd
.default_ttl
;
730 if(NSEC3Zone
) { // now stuff in the NSEC3PARAM
731 flags
= ns3pr
.d_flags
;
732 zrr
.dr
.d_type
= QType::NSEC3PARAM
;
734 zrr
.dr
.d_content
= std::make_shared
<NSEC3PARAMRecordContent
>(ns3pr
);
735 ns3pr
.d_flags
= flags
;
736 DNSName keyname
= DNSName(toBase32Hex(hashQNameWithSalt(ns3pr
, zrr
.dr
.d_name
)));
737 NSECXEntry
& ne
= nsecxrepo
[keyname
];
739 ne
.d_set
.set(zrr
.dr
.d_type
);
743 // now start list zone
744 if(!(sd
.db
->list(target
, sd
.domain_id
))) {
745 g_log
<<Logger::Error
<<"Backend signals error condition"<<endl
;
746 outpacket
->setRcode(RCode::ServFail
);
747 sendPacket(outpacket
,outsock
);
752 const bool rectify
= !(presignedZone
|| ::arg().mustDo("disable-axfr-rectify"));
753 set
<DNSName
> qnames
, nsset
, terms
;
754 vector
<DNSZoneRecord
> zrrs
;
756 // Add the CDNSKEY and CDS records we created earlier
757 for (auto const &synth_zrr
: cds
)
758 zrrs
.push_back(synth_zrr
);
760 for (auto const &synth_zrr
: cdnskey
)
761 zrrs
.push_back(synth_zrr
);
763 while(sd
.db
->get(zrr
)) {
764 zrr
.dr
.d_name
.makeUsLowerCase();
765 if(zrr
.dr
.d_name
.isPartOf(target
)) {
766 if (zrr
.dr
.d_type
== QType::ALIAS
&& ::arg().mustDo("outgoing-axfr-expand-alias")) {
767 vector
<DNSZoneRecord
> ips
;
768 int ret1
= stubDoResolve(getRR
<ALIASRecordContent
>(zrr
.dr
)->d_content
, QType::A
, ips
);
769 int ret2
= stubDoResolve(getRR
<ALIASRecordContent
>(zrr
.dr
)->d_content
, QType::AAAA
, ips
);
770 if(ret1
!= RCode::NoError
|| ret2
!= RCode::NoError
) {
771 g_log
<<Logger::Error
<<"Error resolving for ALIAS "<<zrr
.dr
.d_content
->getZoneRepresentation()<<", aborting AXFR"<<endl
;
772 outpacket
->setRcode(RCode::ServFail
);
773 sendPacket(outpacket
,outsock
);
776 for(const auto& ip
: ips
) {
777 zrr
.dr
.d_type
= ip
.dr
.d_type
;
778 zrr
.dr
.d_content
= ip
.dr
.d_content
;
786 qnames
.insert(zrr
.dr
.d_name
);
787 if(zrr
.dr
.d_type
== QType::NS
&& zrr
.dr
.d_name
!=target
)
788 nsset
.insert(zrr
.dr
.d_name
);
790 // remove existing ents
797 g_log
<<Logger::Warning
<<"Zone '"<<target
<<"' contains out-of-zone data '"<<zrr
.dr
.d_name
<<"|"<<DNSRecordContent::NumberToType(zrr
.dr
.d_type
)<<"', ignoring"<<endl
;
801 // Group records by name and type, signpipe stumbles over interrupted rrsets
802 if(securedZone
&& !presignedZone
) {
803 sort(zrrs
.begin(), zrrs
.end(), [](const DNSZoneRecord
& a
, const DNSZoneRecord
& b
) {
804 return tie(a
.dr
.d_name
, a
.dr
.d_type
) < tie(b
.dr
.d_name
, b
.dr
.d_type
);
810 for(DNSZoneRecord
&loopZRR
: zrrs
) {
812 if (loopZRR
.dr
.d_type
!= QType::NS
|| loopZRR
.dr
.d_name
!=target
) {
813 DNSName
shorter(loopZRR
.dr
.d_name
);
815 if (shorter
==target
) // apex is always auth
817 if(nsset
.count(shorter
) && !(loopZRR
.dr
.d_name
==shorter
&& loopZRR
.dr
.d_type
== QType::DS
)) {
821 } while(shorter
.chopOff());
826 // ents are only required for NSEC3 zones
827 uint32_t maxent
= ::arg().asNum("max-ent-entries");
828 set
<DNSName
> nsec3set
, nonterm
;
829 for (auto &loopZRR
: zrrs
) {
831 DNSName shorter
= loopZRR
.dr
.d_name
;
832 if (shorter
!= target
&& shorter
.chopOff() && shorter
!= target
) {
834 if(nsset
.count(shorter
)) {
838 } while(shorter
.chopOff() && shorter
!= target
);
840 shorter
= loopZRR
.dr
.d_name
;
841 if(!skip
&& (loopZRR
.dr
.d_type
!= QType::NS
|| !ns3pr
.d_flags
)) {
843 if(!nsec3set
.count(shorter
)) {
844 nsec3set
.insert(shorter
);
846 } while(shorter
!= target
&& shorter
.chopOff());
850 for(DNSZoneRecord
&loopZRR
: zrrs
) {
851 DNSName
shorter(loopZRR
.dr
.d_name
);
852 while(shorter
!= target
&& shorter
.chopOff()) {
853 if(!qnames
.count(shorter
) && !nonterm
.count(shorter
) && nsec3set
.count(shorter
)) {
855 g_log
<<Logger::Warning
<<"Zone '"<<target
<<"' has too many empty non terminals."<<endl
;
858 nonterm
.insert(shorter
);
864 for(const auto& nt
: nonterm
) {
865 DNSZoneRecord tempRR
;
867 tempRR
.dr
.d_type
=QType::ENT
;
869 zrrs
.push_back(tempRR
);
875 /* now write all other records */
882 for(DNSZoneRecord
&loopZRR
: zrrs
) {
883 if (!presignedZone
&& loopZRR
.dr
.d_type
== QType::RRSIG
)
886 // only skip the DNSKEY, CDNSKEY and CDS if direct-dnskey is enabled, to avoid changing behaviour
887 // when it is not enabled.
888 if(::arg().mustDo("direct-dnskey") && (loopZRR
.dr
.d_type
== QType::DNSKEY
|| loopZRR
.dr
.d_type
== QType::CDNSKEY
|| loopZRR
.dr
.d_type
== QType::CDS
))
892 if(securedZone
&& (loopZRR
.auth
|| loopZRR
.dr
.d_type
== QType::NS
)) {
893 if (NSEC3Zone
|| loopZRR
.dr
.d_type
) {
894 if (presignedZone
&& NSEC3Zone
&& loopZRR
.dr
.d_type
== QType::RRSIG
&& getRR
<RRSIGRecordContent
>(loopZRR
.dr
)->d_type
== QType::NSEC3
) {
895 keyname
= loopZRR
.dr
.d_name
.makeRelative(sd
.qname
);
897 keyname
= NSEC3Zone
? DNSName(toBase32Hex(hashQNameWithSalt(ns3pr
, loopZRR
.dr
.d_name
))) : loopZRR
.dr
.d_name
;
899 NSECXEntry
& ne
= nsecxrepo
[keyname
];
900 ne
.d_ttl
= sd
.default_ttl
;
901 ne
.d_auth
= (ne
.d_auth
|| loopZRR
.auth
|| (NSEC3Zone
&& (!ns3pr
.d_flags
)));
902 if (loopZRR
.dr
.d_type
&& loopZRR
.dr
.d_type
!= QType::RRSIG
) {
903 ne
.d_set
.set(loopZRR
.dr
.d_type
);
908 if (!loopZRR
.dr
.d_type
)
909 continue; // skip empty non-terminals
911 if(loopZRR
.dr
.d_type
== QType::SOA
)
912 continue; // skip SOA - would indicate end of AXFR
914 if(csp
.submit(loopZRR
)) {
916 outpacket
->getRRS() = csp
.getChunk();
917 if(!outpacket
->getRRS().empty()) {
918 if(haveTSIGDetails
&& !tsigkeyname
.empty())
919 outpacket
->setTSIGDetails(trc
, tsigkeyname
, tsigsecret
, trc
.d_mac
, true);
920 sendPacket(outpacket
, outsock
);
921 trc
.d_mac
=outpacket
->d_trc
.d_mac
;
922 outpacket
=getFreshAXFRPacket(q
);
930 udiff=dt.udiffNoReset();
931 cerr<<"Starting NSEC: "<<csp.d_signed/(udiff/1000000.0)<<" sigs/s, "<<csp.d_signed<<" / "<<udiff/1000000.0<<endl;
932 cerr<<"Outstanding: "<<csp.d_outstanding<<", "<<csp.d_queued - csp.d_signed << endl;
933 cerr<<"Ready for consumption: "<<csp.getReady()<<endl;
937 for(nsecxrepo_t::const_iterator iter
= nsecxrepo
.begin(); iter
!= nsecxrepo
.end(); ++iter
) {
938 if(iter
->second
.d_auth
) {
939 NSEC3RecordContent n3rc
;
940 n3rc
.set(iter
->second
.d_set
);
941 const auto numberOfTypesSet
= n3rc
.numberOfTypesSet();
942 if (numberOfTypesSet
!= 0 && (numberOfTypesSet
!= 1 || !n3rc
.isSet(QType::NS
))) {
943 n3rc
.set(QType::RRSIG
);
945 n3rc
.d_salt
= ns3pr
.d_salt
;
946 n3rc
.d_flags
= ns3pr
.d_flags
;
947 n3rc
.d_iterations
= ns3pr
.d_iterations
;
948 n3rc
.d_algorithm
= DNSSECKeeper::DIGEST_SHA1
; // SHA1, fixed in PowerDNS for now
949 nsecxrepo_t::const_iterator inext
= iter
;
951 if(inext
== nsecxrepo
.end())
952 inext
= nsecxrepo
.begin();
953 while(!inext
->second
.d_auth
&& inext
!= iter
)
956 if(inext
== nsecxrepo
.end())
957 inext
= nsecxrepo
.begin();
959 n3rc
.d_nexthash
= fromBase32Hex(inext
->first
.toStringNoDot());
960 zrr
.dr
.d_name
= iter
->first
+sd
.qname
;
962 zrr
.dr
.d_ttl
= sd
.default_ttl
;
963 zrr
.dr
.d_content
= std::make_shared
<NSEC3RecordContent
>(std::move(n3rc
));
964 zrr
.dr
.d_type
= QType::NSEC3
;
965 zrr
.dr
.d_place
= DNSResourceRecord::ANSWER
;
967 if(csp
.submit(zrr
)) {
969 outpacket
->getRRS() = csp
.getChunk();
970 if(!outpacket
->getRRS().empty()) {
971 if(haveTSIGDetails
&& !tsigkeyname
.empty())
972 outpacket
->setTSIGDetails(trc
, tsigkeyname
, tsigsecret
, trc
.d_mac
, true);
973 sendPacket(outpacket
, outsock
);
974 trc
.d_mac
=outpacket
->d_trc
.d_mac
;
975 outpacket
=getFreshAXFRPacket(q
);
984 else for(nsecxrepo_t::const_iterator iter
= nsecxrepo
.begin(); iter
!= nsecxrepo
.end(); ++iter
) {
985 NSECRecordContent nrc
;
986 nrc
.set(iter
->second
.d_set
);
987 nrc
.set(QType::RRSIG
);
988 nrc
.set(QType::NSEC
);
990 if(boost::next(iter
) != nsecxrepo
.end())
991 nrc
.d_next
= boost::next(iter
)->first
;
993 nrc
.d_next
=nsecxrepo
.begin()->first
;
994 zrr
.dr
.d_name
= iter
->first
;
996 zrr
.dr
.d_ttl
= sd
.default_ttl
;
997 zrr
.dr
.d_content
= std::make_shared
<NSECRecordContent
>(std::move(nrc
));
998 zrr
.dr
.d_type
= QType::NSEC
;
999 zrr
.dr
.d_place
= DNSResourceRecord::ANSWER
;
1001 if(csp
.submit(zrr
)) {
1003 outpacket
->getRRS() = csp
.getChunk();
1004 if(!outpacket
->getRRS().empty()) {
1005 if(haveTSIGDetails
&& !tsigkeyname
.empty())
1006 outpacket
->setTSIGDetails(trc
, tsigkeyname
, tsigsecret
, trc
.d_mac
, true);
1007 sendPacket(outpacket
, outsock
);
1008 trc
.d_mac
=outpacket
->d_trc
.d_mac
;
1009 outpacket
=getFreshAXFRPacket(q
);
1018 udiff=dt.udiffNoReset();
1019 cerr<<"Flushing pipe: "<<csp.d_signed/(udiff/1000000.0)<<" sigs/s, "<<csp.d_signed<<" / "<<udiff/1000000.0<<endl;
1020 cerr<<"Outstanding: "<<csp.d_outstanding<<", "<<csp.d_queued - csp.d_signed << endl;
1021 cerr<<"Ready for consumption: "<<csp.getReady()<<endl;
1024 outpacket
->getRRS() = csp
.getChunk(true); // flush the pipe
1025 if(!outpacket
->getRRS().empty()) {
1026 if(haveTSIGDetails
&& !tsigkeyname
.empty())
1027 outpacket
->setTSIGDetails(trc
, tsigkeyname
, tsigsecret
, trc
.d_mac
, true); // first answer is 'normal'
1028 sendPacket(outpacket
, outsock
);
1029 trc
.d_mac
=outpacket
->d_trc
.d_mac
;
1030 outpacket
=getFreshAXFRPacket(q
);
1036 udiff
=dt
.udiffNoReset();
1038 g_log
<<Logger::Info
<<"Done signing: "<<csp
.d_signed
/(udiff
/1000000.0)<<" sigs/s, "<<endl
;
1040 DLOG(g_log
<<"Done writing out records"<<endl
);
1041 /* and terminate with yet again the SOA record */
1042 outpacket
=getFreshAXFRPacket(q
);
1043 outpacket
->addRecord(soa
);
1044 if(haveTSIGDetails
&& !tsigkeyname
.empty())
1045 outpacket
->setTSIGDetails(trc
, tsigkeyname
, tsigsecret
, trc
.d_mac
, true);
1047 sendPacket(outpacket
, outsock
);
1049 DLOG(g_log
<<"last packet - close"<<endl
);
1050 g_log
<<Logger::Error
<<"AXFR of domain '"<<target
<<"' to "<<q
->getRemote()<<" finished"<<endl
;
1055 int TCPNameserver::doIXFR(std::unique_ptr
<DNSPacket
>& q
, int outsock
)
1057 std::unique_ptr
<DNSPacket
> outpacket
=getFreshAXFRPacket(q
);
1059 outpacket
->d_dnssecOk
=true; // RFC 5936, 2.2.5 'SHOULD'
1061 uint32_t serial
= 0;
1062 MOADNSParser
mdp(false, q
->getString());
1063 for(MOADNSParser::answers_t::const_iterator i
=mdp
.d_answers
.begin(); i
!= mdp
.d_answers
.end(); ++i
) {
1064 const DNSRecord
*rr
= &i
->first
;
1065 if (rr
->d_type
== QType::SOA
&& rr
->d_place
== DNSResourceRecord::AUTHORITY
) {
1066 vector
<string
>parts
;
1067 stringtok(parts
, rr
->d_content
->getZoneRepresentation());
1068 if (parts
.size() >= 3) {
1070 serial
=pdns_stou(parts
[2]);
1072 catch(const std::out_of_range
& oor
) {
1073 g_log
<<Logger::Error
<<"Invalid serial in IXFR query"<<endl
;
1074 outpacket
->setRcode(RCode::FormErr
);
1075 sendPacket(outpacket
,outsock
);
1079 g_log
<<Logger::Error
<<"No serial in IXFR query"<<endl
;
1080 outpacket
->setRcode(RCode::FormErr
);
1081 sendPacket(outpacket
,outsock
);
1084 } else if (rr
->d_type
!= QType::TSIG
&& rr
->d_type
!= QType::OPT
) {
1085 g_log
<<Logger::Error
<<"Additional records in IXFR query, type: "<<QType(rr
->d_type
).getName()<<endl
;
1086 outpacket
->setRcode(RCode::FormErr
);
1087 sendPacket(outpacket
,outsock
);
1092 g_log
<<Logger::Error
<<"IXFR of domain '"<<q
->qdomain
<<"' initiated by "<<q
->getRemote()<<" with serial "<<serial
<<endl
;
1094 // determine if zone exists and AXFR is allowed using existing backend before spawning a new backend.
1098 DLOG(g_log
<<"Looking for SOA"<<endl
); // find domain_id via SOA and list complete domain. No SOA, no IXFR
1100 g_log
<<Logger::Error
<<"TCP server is without backend connections in doIXFR, launching"<<endl
;
1101 s_P
=make_unique
<PacketHandler
>();
1104 // canDoAXFR does all the ACL checks, and has the if(disable-axfr) shortcut, call it first.
1105 if(!canDoAXFR(q
) || !s_P
->getBackend()->getSOAUncached(q
->qdomain
, sd
)) {
1106 g_log
<<Logger::Error
<<"IXFR of domain '"<<q
->qdomain
<<"' failed: not authoritative"<<endl
;
1107 outpacket
->setRcode(RCode::NotAuth
);
1108 sendPacket(outpacket
,outsock
);
1114 NSEC3PARAMRecordContent ns3pr
;
1117 DNSSECKeeper::clearCaches(q
->qdomain
);
1118 bool securedZone
= dk
.isSecuredZone(q
->qdomain
);
1119 if(dk
.getNSEC3PARAM(q
->qdomain
, &ns3pr
, &narrow
)) {
1121 g_log
<<Logger::Error
<<"Not doing IXFR of an NSEC3 narrow zone."<<endl
;
1122 g_log
<<Logger::Error
<<"IXFR of domain '"<<q
->qdomain
<<"' denied to "<<q
->getRemote()<<endl
;
1123 outpacket
->setRcode(RCode::Refused
);
1124 sendPacket(outpacket
,outsock
);
1129 DNSName target
= q
->qdomain
;
1132 if(!db
.getSOAUncached(target
, sd
)) {
1133 g_log
<<Logger::Error
<<"IXFR of domain '"<<target
<<"' failed: not authoritative in second instance"<<endl
;
1134 outpacket
->setRcode(RCode::NotAuth
);
1135 sendPacket(outpacket
,outsock
);
1139 if (!rfc1982LessThan(serial
, calculateEditSOA(sd
.serial
, dk
, sd
.qname
))) {
1140 TSIGRecordContent trc
;
1141 DNSName tsigkeyname
;
1144 bool haveTSIGDetails
= q
->getTSIGDetails(&trc
, &tsigkeyname
);
1146 if(haveTSIGDetails
&& !tsigkeyname
.empty()) {
1148 DNSName algorithm
=trc
.d_algoName
; // FIXME400: was toLowerCanonic, compare output
1149 if (algorithm
== DNSName("hmac-md5.sig-alg.reg.int"))
1150 algorithm
= DNSName("hmac-md5");
1152 if(!s_P
->getBackend()->getTSIGKey(tsigkeyname
, &algorithm
, &tsig64
)) {
1153 g_log
<<Logger::Error
<<"TSIG key '"<<tsigkeyname
<<"' for domain '"<<target
<<"' not found"<<endl
;
1156 if (B64Decode(tsig64
, tsigsecret
) == -1) {
1157 g_log
<<Logger::Error
<<"Unable to Base-64 decode TSIG key '"<<tsigkeyname
<<"' for domain '"<<target
<<"'"<<endl
;
1162 UeberBackend signatureDB
;
1164 // SOA *must* go out first, our signing pipe might reorder
1165 DLOG(g_log
<<"Sending out SOA"<<endl
);
1166 DNSZoneRecord soa
= makeEditedDNSZRFromSOAData(dk
, sd
);
1167 outpacket
->addRecord(soa
);
1169 set
<DNSName
> authSet
;
1170 authSet
.insert(target
);
1171 addRRSigs(dk
, signatureDB
, authSet
, outpacket
->getRRS());
1174 if(haveTSIGDetails
&& !tsigkeyname
.empty())
1175 outpacket
->setTSIGDetails(trc
, tsigkeyname
, tsigsecret
, trc
.d_mac
); // first answer is 'normal'
1177 sendPacket(outpacket
, outsock
);
1179 g_log
<<Logger::Error
<<"IXFR of domain '"<<target
<<"' to "<<q
->getRemote()<<" finished"<<endl
;
1184 g_log
<<Logger::Error
<<"IXFR fallback to AXFR for domain '"<<target
<<"' our serial "<<sd
.serial
<<endl
;
1185 return doAXFR(q
->qdomain
, q
, outsock
);
1188 TCPNameserver::~TCPNameserver()
1192 TCPNameserver::TCPNameserver()
1194 d_maxTransactionsPerConn
= ::arg().asNum("max-tcp-transactions-per-conn");
1195 d_idleTimeout
= ::arg().asNum("tcp-idle-timeout");
1196 d_maxConnectionDuration
= ::arg().asNum("max-tcp-connection-duration");
1197 d_maxConnectionsPerClient
= ::arg().asNum("max-tcp-connections-per-client");
1199 // sem_init(&d_connectionroom_sem,0,::arg().asNum("max-tcp-connections"));
1200 d_connectionroom_sem
= make_unique
<Semaphore
>( ::arg().asNum( "max-tcp-connections" ));
1201 d_maxTCPConnections
= ::arg().asNum( "max-tcp-connections" );
1204 vector
<string
>locals
;
1205 stringtok(locals
,::arg()["local-address"]," ,");
1207 throw PDNSException("No local addresses specified");
1209 d_ng
.toMasks(::arg()["allow-axfr-ips"] );
1211 signal(SIGPIPE
,SIG_IGN
);
1213 for(auto const &laddr
: locals
) {
1214 ComboAddress
local(laddr
, ::arg().asNum("local-port"));
1216 int s
=socket(local
.sin4
.sin_family
, SOCK_STREAM
, 0);
1218 throw PDNSException("Unable to acquire TCP socket: "+stringerror());
1222 if(setsockopt(s
, SOL_SOCKET
,SO_REUSEADDR
, (char*)&tmp
, sizeof tmp
) < 0) {
1223 g_log
<<Logger::Error
<<"Setsockopt failed"<<endl
;
1227 if (::arg().asNum("tcp-fast-open") > 0) {
1229 int fastOpenQueueSize
= ::arg().asNum("tcp-fast-open");
1230 if (setsockopt(s
, IPPROTO_TCP
, TCP_FASTOPEN
, &fastOpenQueueSize
, sizeof fastOpenQueueSize
) < 0) {
1231 g_log
<<Logger::Error
<<"Failed to enable TCP Fast Open for listening socket "<<local
.toStringWithPort()<<": "<<stringerror()<<endl
;
1234 g_log
<<Logger::Warning
<<"TCP Fast Open configured but not supported for listening socket"<<endl
;
1238 if(::arg().mustDo("non-local-bind"))
1239 Utility::setBindAny(local
.sin4
.sin_family
, s
);
1241 if(local
.isIPv6() && setsockopt(s
, IPPROTO_IPV6
, IPV6_V6ONLY
, &tmp
, sizeof(tmp
)) < 0) {
1242 g_log
<<Logger::Error
<<"Failed to set IPv6 socket to IPv6 only, continuing anyhow: "<<stringerror()<<endl
;
1245 if(::bind(s
, (sockaddr
*)&local
, local
.getSocklen())<0) {
1248 if( err
== EADDRNOTAVAIL
&& ! ::arg().mustDo("local-address-nonexist-fail") ) {
1249 g_log
<<Logger::Error
<<"Address " << local
.toString() << " does not exist on this server - skipping TCP bind" << endl
;
1252 g_log
<<Logger::Error
<<"Unable to bind to TCP socket " << local
.toStringWithPort() << ": "<<stringerror(err
)<<endl
;
1253 throw PDNSException("Unable to bind to TCP socket");
1258 g_log
<<Logger::Error
<<"TCP server bound to "<<local
.toStringWithPort()<<endl
;
1259 d_sockets
.push_back(s
);
1261 memset(&pfd
, 0, sizeof(pfd
));
1263 pfd
.events
= POLLIN
;
1264 d_prfds
.push_back(pfd
);
1269 //! Start of TCP operations thread, we launch a new thread for each incoming TCP question
1270 void TCPNameserver::thread()
1272 setThreadName("pdns/tcpnameser");
1276 ComboAddress remote
;
1277 Utility::socklen_t addrlen
=remote
.getSocklen();
1279 int ret
=poll(&d_prfds
[0], d_prfds
.size(), -1); // blocks, forever if need be
1284 for(const pollfd
& pfd
: d_prfds
) {
1285 if(pfd
.revents
& POLLIN
) {
1287 remote
.sin4
.sin_family
= AF_INET6
;
1288 addrlen
=remote
.getSocklen();
1290 if((fd
=accept(sock
, (sockaddr
*)&remote
, &addrlen
))<0) {
1292 g_log
<<Logger::Error
<<"TCP question accept error: "<<stringerror(err
)<<endl
;
1295 g_log
<<Logger::Error
<<"TCP handler out of filedescriptors, exiting, won't recover from this"<<endl
;
1300 if (d_maxConnectionsPerClient
) {
1301 std::lock_guard
<std::mutex
> lock(s_clientsCountMutex
);
1302 if (s_clientsCount
[remote
] >= d_maxConnectionsPerClient
) {
1303 g_log
<<Logger::Notice
<<"Limit of simultaneous TCP connections per client reached for "<< remote
<<", dropping"<<endl
;
1307 s_clientsCount
[remote
]++;
1311 d_connectionroom_sem
->wait(); // blocks if no connections are available
1314 d_connectionroom_sem
->getValue( &room
);
1316 g_log
<<Logger::Warning
<<"Limit of simultaneous TCP connections reached - raise max-tcp-connections"<<endl
;
1319 if((err
= pthread_create(&tid
, 0, &doConnection
, reinterpret_cast<void*>(fd
)))) {
1320 g_log
<<Logger::Error
<<"Error creating thread: "<<stringerror(err
)<<endl
;
1321 d_connectionroom_sem
->post();
1323 decrementClientCount(remote
);
1330 catch(PDNSException
&AE
) {
1331 g_log
<<Logger::Error
<<"TCP Nameserver thread dying because of fatal error: "<<AE
.reason
<<endl
;
1334 g_log
<<Logger::Error
<<"TCPNameserver dying because of an unexpected fatal error"<<endl
;
1336 _exit(1); // take rest of server with us
1340 unsigned int TCPNameserver::numTCPConnections()
1343 d_connectionroom_sem
->getValue( &room
);
1344 return d_maxTCPConnections
- room
;