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 unsigned int TCPNameserver::d_maxTCPConnections
= 0;
72 PacketHandler
*TCPNameserver::s_P
;
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
=new 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(shared_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 shared_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
=shared_ptr
<DNSPacket
>(new 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 shared_ptr
<DNSPacket
> reply
;
351 shared_ptr
<DNSPacket
> cached
= shared_ptr
<DNSPacket
>(new 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
.get(), cached
.get())) { // 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
;
380 g_log
<<Logger::Error
<<"TCP server is without backend connections, launching"<<endl
;
381 s_P
=new PacketHandler
;
384 reply
=shared_ptr
<DNSPacket
>(s_P
->doQuestion(packet
.get())); // we really need to ask the backend :-)
387 if(!reply
) // unable to write an answer?
390 sendPacket(reply
, fd
);
393 catch(PDNSException
&ae
) {
396 s_P
= 0; // on next call, backend will be recycled
397 g_log
<<Logger::Error
<<"TCP nameserver had error, cycling backend: "<<ae
.reason
<<endl
;
399 catch(NetworkError
&e
) {
400 g_log
<<Logger::Info
<<"TCP Connection Thread died because of network error: "<<e
.what()<<endl
;
403 catch(std::exception
&e
) {
404 g_log
<<Logger::Error
<<"TCP Connection Thread died because of STL error: "<<e
.what()<<endl
;
408 g_log
<< Logger::Error
<< "TCP Connection Thread caught unknown exception." << endl
;
410 d_connectionroom_sem
->post();
415 catch(const PDNSException
& e
) {
416 g_log
<<Logger::Error
<<"Error closing TCP socket: "<<e
.reason
<<endl
;
418 decrementClientCount(remote
);
424 // call this method with s_plock held!
425 bool TCPNameserver::canDoAXFR(shared_ptr
<DNSPacket
> q
)
427 if(::arg().mustDo("disable-axfr"))
430 if(q
->d_havetsig
) { // if you have one, it must be good
431 TSIGRecordContent trc
;
434 if(!q
->checkForCorrectTSIG(s_P
->getBackend(), &keyname
, &secret
, &trc
)) {
437 getTSIGHashEnum(trc
.d_algoName
, q
->d_tsig_algo
);
438 if (q
->d_tsig_algo
== TSIG_GSS
) {
439 GssContext
gssctx(keyname
);
440 if (!gssctx
.getPeerPrincipal(q
->d_peer_principal
)) {
441 g_log
<<Logger::Warning
<<"Failed to extract peer principal from GSS context with keyname '"<<keyname
<<"'"<<endl
;
446 DNSSECKeeper
dk(s_P
->getBackend());
448 if (q
->d_tsig_algo
== TSIG_GSS
) {
449 vector
<string
> princs
;
450 s_P
->getBackend()->getDomainMetadata(q
->qdomain
, "GSS-ALLOW-AXFR-PRINCIPAL", princs
);
451 for(const std::string
& princ
: princs
) {
452 if (q
->d_peer_principal
== princ
) {
453 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
;
457 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
;
461 if(!dk
.TSIGGrantsAccess(q
->qdomain
, keyname
)) {
462 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
;
466 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
;
471 // cerr<<"checking allow-axfr-ips"<<endl;
472 if(!(::arg()["allow-axfr-ips"].empty()) && d_ng
.match( (ComboAddress
*) &q
->d_remote
)) {
473 g_log
<<Logger::Warning
<<"AXFR of domain '"<<q
->qdomain
<<"' allowed: client IP "<<q
->getRemote()<<" is in allow-axfr-ips"<<endl
;
479 // cerr<<"doing per-zone-axfr-acls"<<endl;
481 if(s_P
->getBackend()->getSOAUncached(q
->qdomain
,sd
)) {
482 // cerr<<"got backend and SOA"<<endl;
485 s_P
->getBackend()->getDomainMetadata(q
->qdomain
, "ALLOW-AXFR-FROM", acl
);
486 for (vector
<string
>::const_iterator i
= acl
.begin(); i
!= acl
.end(); ++i
) {
487 // cerr<<"matching against "<<*i<<endl;
488 if(pdns_iequals(*i
, "AUTO-NS")) {
489 // cerr<<"AUTO-NS magic please!"<<endl;
491 DNSResourceRecord rr
;
494 B
->lookup(QType(QType::NS
),q
->qdomain
);
496 nsset
.insert(DNSName(rr
.content
));
497 for(const auto & j
: nsset
) {
498 vector
<string
> nsips
=fns
.lookup(j
, s_P
->getBackend());
499 for(vector
<string
>::const_iterator k
=nsips
.begin();k
!=nsips
.end();++k
) {
500 // cerr<<"got "<<*k<<" from AUTO-NS"<<endl;
501 if(*k
== q
->getRemote().toString())
503 // cerr<<"got AUTO-NS hit"<<endl;
504 g_log
<<Logger::Warning
<<"AXFR of domain '"<<q
->qdomain
<<"' allowed: client IP "<<q
->getRemote()<<" is in NSset"<<endl
;
512 Netmask nm
= Netmask(*i
);
513 if(nm
.match( (ComboAddress
*) &q
->d_remote
))
515 g_log
<<Logger::Warning
<<"AXFR of domain '"<<q
->qdomain
<<"' allowed: client IP "<<q
->getRemote()<<" is in per-domain ACL"<<endl
;
516 // cerr<<"hit!"<<endl;
523 extern CommunicatorClass Communicator
;
525 if(Communicator
.justNotified(q
->qdomain
, q
->getRemote().toString())) { // we just notified this ip
526 g_log
<<Logger::Warning
<<"Approved AXFR of '"<<q
->qdomain
<<"' from recently notified slave "<<q
->getRemote()<<endl
;
530 g_log
<<Logger::Error
<<"AXFR of domain '"<<q
->qdomain
<<"' denied: client IP "<<q
->getRemote()<<" has no permission"<<endl
;
542 shared_ptr
<DNSPacket
> getFreshAXFRPacket(shared_ptr
<DNSPacket
> q
)
544 shared_ptr
<DNSPacket
> ret
= shared_ptr
<DNSPacket
>(q
->replyPacket());
545 ret
->setCompress(false);
546 ret
->d_dnssecOk
=false; // RFC 5936, 2.2.5
553 /** do the actual zone transfer. Return 0 in case of error, 1 in case of success */
554 int TCPNameserver::doAXFR(const DNSName
&target
, shared_ptr
<DNSPacket
> q
, int outsock
)
556 shared_ptr
<DNSPacket
> outpacket
= getFreshAXFRPacket(q
);
558 outpacket
->d_dnssecOk
=true; // RFC 5936, 2.2.5 'SHOULD'
560 g_log
<<Logger::Error
<<"AXFR of domain '"<<target
<<"' initiated by "<<q
->getRemote()<<endl
;
562 // determine if zone exists and AXFR is allowed using existing backend before spawning a new backend.
566 DLOG(g_log
<<"Looking for SOA"<<endl
); // find domain_id via SOA and list complete domain. No SOA, no AXFR
568 g_log
<<Logger::Error
<<"TCP server is without backend connections in doAXFR, launching"<<endl
;
569 s_P
=new PacketHandler
;
572 // canDoAXFR does all the ACL checks, and has the if(disable-axfr) shortcut, call it first.
574 g_log
<<Logger::Error
<<"AXFR of domain '"<<target
<<"' failed: "<<q
->getRemote()<<" may not request AXFR"<<endl
;
575 outpacket
->setRcode(RCode::NotAuth
);
576 sendPacket(outpacket
,outsock
);
580 if(!s_P
->getBackend()->getSOAUncached(target
, sd
)) {
581 g_log
<<Logger::Error
<<"AXFR of domain '"<<target
<<"' failed: not authoritative"<<endl
;
582 outpacket
->setRcode(RCode::NotAuth
);
583 sendPacket(outpacket
,outsock
);
589 if(!db
.getSOAUncached(target
, sd
)) {
590 g_log
<<Logger::Error
<<"AXFR of domain '"<<target
<<"' failed: not authoritative in second instance"<<endl
;
591 outpacket
->setRcode(RCode::NotAuth
);
592 sendPacket(outpacket
,outsock
);
596 DNSSECKeeper
dk(&db
);
597 dk
.clearCaches(target
);
598 bool securedZone
= dk
.isSecuredZone(target
);
599 bool presignedZone
= dk
.isPresigned(target
);
601 bool noAXFRBecauseOfNSEC3Narrow
=false;
602 NSEC3PARAMRecordContent ns3pr
;
604 bool NSEC3Zone
=false;
605 if(securedZone
&& dk
.getNSEC3PARAM(target
, &ns3pr
, &narrow
)) {
608 g_log
<<Logger::Error
<<"Not doing AXFR of an NSEC3 narrow zone '"<<target
<<"' for "<<q
->getRemote()<<endl
;
609 noAXFRBecauseOfNSEC3Narrow
=true;
613 if(noAXFRBecauseOfNSEC3Narrow
) {
614 g_log
<<Logger::Error
<<"AXFR of domain '"<<target
<<"' denied to "<<q
->getRemote()<<endl
;
615 outpacket
->setRcode(RCode::Refused
);
616 // FIXME: should actually figure out if we are auth over a zone, and send out 9 if we aren't
617 sendPacket(outpacket
,outsock
);
621 TSIGRecordContent trc
;
625 bool haveTSIGDetails
= q
->getTSIGDetails(&trc
, &tsigkeyname
);
627 if(haveTSIGDetails
&& !tsigkeyname
.empty()) {
629 DNSName algorithm
=trc
.d_algoName
; // FIXME400: check
630 if (algorithm
== DNSName("hmac-md5.sig-alg.reg.int"))
631 algorithm
= DNSName("hmac-md5");
632 if (algorithm
!= DNSName("gss-tsig")) {
633 if(!db
.getTSIGKey(tsigkeyname
, &algorithm
, &tsig64
)) {
634 g_log
<<Logger::Error
<<"TSIG key '"<<tsigkeyname
<<"' for domain '"<<target
<<"' not found"<<endl
;
637 if (B64Decode(tsig64
, tsigsecret
) == -1) {
638 g_log
<<Logger::Error
<<"Unable to Base-64 decode TSIG key '"<<tsigkeyname
<<"' for domain '"<<target
<<"'"<<endl
;
645 // SOA *must* go out first, our signing pipe might reorder
646 DLOG(g_log
<<"Sending out SOA"<<endl
);
647 DNSZoneRecord soa
= makeEditedDNSZRFromSOAData(dk
, sd
);
648 outpacket
->addRecord(soa
);
649 if(securedZone
&& !presignedZone
) {
650 set
<DNSName
> authSet
;
651 authSet
.insert(target
);
652 addRRSigs(dk
, db
, authSet
, outpacket
->getRRS());
655 if(haveTSIGDetails
&& !tsigkeyname
.empty())
656 outpacket
->setTSIGDetails(trc
, tsigkeyname
, tsigsecret
, trc
.d_mac
); // first answer is 'normal'
658 sendPacket(outpacket
, outsock
);
660 trc
.d_mac
= outpacket
->d_trc
.d_mac
;
661 outpacket
= getFreshAXFRPacket(q
);
663 ChunkedSigningPipe
csp(target
, (securedZone
&& !presignedZone
), ::arg().asNum("signing-threads", 1));
665 typedef map
<DNSName
, NSECXEntry
, CanonDNSNameCompare
> nsecxrepo_t
;
666 nsecxrepo_t nsecxrepo
;
668 // this is where the DNSKEYs go in
670 DNSSECKeeper::keyset_t keys
= dk
.getKeys(target
);
674 zrr
.dr
.d_name
= target
;
675 zrr
.dr
.d_ttl
= sd
.default_ttl
;
676 zrr
.auth
= 1; // please sign!
678 string publishCDNSKEY
, publishCDS
;
679 dk
.getFromMeta(q
->qdomain
, "PUBLISH-CDNSKEY", publishCDNSKEY
);
680 dk
.getFromMeta(q
->qdomain
, "PUBLISH-CDS", publishCDS
);
681 vector
<DNSZoneRecord
> cds
, cdnskey
;
682 DNSSECKeeper::keyset_t entryPoints
= dk
.getEntryPoints(q
->qdomain
);
683 set
<uint32_t> entryPointIds
;
684 for (auto const& value
: entryPoints
)
685 entryPointIds
.insert(value
.second
.id
);
687 for(const DNSSECKeeper::keyset_t::value_type
& value
: keys
) {
688 zrr
.dr
.d_type
= QType::DNSKEY
;
689 zrr
.dr
.d_content
= std::make_shared
<DNSKEYRecordContent
>(value
.first
.getDNSKEY());
690 DNSName keyname
= NSEC3Zone
? DNSName(toBase32Hex(hashQNameWithSalt(ns3pr
, zrr
.dr
.d_name
))) : zrr
.dr
.d_name
;
691 NSECXEntry
& ne
= nsecxrepo
[keyname
];
693 ne
.d_set
.set(zrr
.dr
.d_type
);
694 ne
.d_ttl
= sd
.default_ttl
;
697 // generate CDS and CDNSKEY records
698 if(entryPointIds
.count(value
.second
.id
) > 0){
699 if(publishCDNSKEY
== "1") {
700 zrr
.dr
.d_type
=QType::CDNSKEY
;
701 zrr
.dr
.d_content
= std::make_shared
<DNSKEYRecordContent
>(value
.first
.getDNSKEY());
702 cdnskey
.push_back(zrr
);
705 if(!publishCDS
.empty()){
706 zrr
.dr
.d_type
=QType::CDS
;
707 vector
<string
> digestAlgos
;
708 stringtok(digestAlgos
, publishCDS
, ", ");
709 for(auto const &digestAlgo
: digestAlgos
) {
710 zrr
.dr
.d_content
=std::make_shared
<DSRecordContent
>(makeDSFromDNSKey(target
, value
.first
.getDNSKEY(), pdns_stou(digestAlgo
)));
717 if(::arg().mustDo("direct-dnskey")) {
718 sd
.db
->lookup(QType(QType::DNSKEY
), target
, NULL
, sd
.domain_id
);
719 while(sd
.db
->get(zrr
)) {
720 zrr
.dr
.d_ttl
= sd
.default_ttl
;
727 if(NSEC3Zone
) { // now stuff in the NSEC3PARAM
728 flags
= ns3pr
.d_flags
;
729 zrr
.dr
.d_type
= QType::NSEC3PARAM
;
731 zrr
.dr
.d_content
= std::make_shared
<NSEC3PARAMRecordContent
>(ns3pr
);
732 ns3pr
.d_flags
= flags
;
733 DNSName keyname
= DNSName(toBase32Hex(hashQNameWithSalt(ns3pr
, zrr
.dr
.d_name
)));
734 NSECXEntry
& ne
= nsecxrepo
[keyname
];
736 ne
.d_set
.set(zrr
.dr
.d_type
);
740 // now start list zone
741 if(!(sd
.db
->list(target
, sd
.domain_id
))) {
742 g_log
<<Logger::Error
<<"Backend signals error condition"<<endl
;
743 outpacket
->setRcode(RCode::ServFail
);
744 sendPacket(outpacket
,outsock
);
749 const bool rectify
= !(presignedZone
|| ::arg().mustDo("disable-axfr-rectify"));
750 set
<DNSName
> qnames
, nsset
, terms
;
751 vector
<DNSZoneRecord
> zrrs
;
753 // Add the CDNSKEY and CDS records we created earlier
754 for (auto const &synth_zrr
: cds
)
755 zrrs
.push_back(synth_zrr
);
757 for (auto const &synth_zrr
: cdnskey
)
758 zrrs
.push_back(synth_zrr
);
760 while(sd
.db
->get(zrr
)) {
761 zrr
.dr
.d_name
.makeUsLowerCase();
762 if(zrr
.dr
.d_name
.isPartOf(target
)) {
763 if (zrr
.dr
.d_type
== QType::ALIAS
&& ::arg().mustDo("outgoing-axfr-expand-alias")) {
764 vector
<DNSZoneRecord
> ips
;
765 int ret1
= stubDoResolve(getRR
<ALIASRecordContent
>(zrr
.dr
)->d_content
, QType::A
, ips
);
766 int ret2
= stubDoResolve(getRR
<ALIASRecordContent
>(zrr
.dr
)->d_content
, QType::AAAA
, ips
);
767 if(ret1
!= RCode::NoError
|| ret2
!= RCode::NoError
) {
768 g_log
<<Logger::Error
<<"Error resolving for ALIAS "<<zrr
.dr
.d_content
->getZoneRepresentation()<<", aborting AXFR"<<endl
;
769 outpacket
->setRcode(RCode::ServFail
);
770 sendPacket(outpacket
,outsock
);
773 for(const auto& ip
: ips
) {
774 zrr
.dr
.d_type
= ip
.dr
.d_type
;
775 zrr
.dr
.d_content
= ip
.dr
.d_content
;
783 qnames
.insert(zrr
.dr
.d_name
);
784 if(zrr
.dr
.d_type
== QType::NS
&& zrr
.dr
.d_name
!=target
)
785 nsset
.insert(zrr
.dr
.d_name
);
787 // remove existing ents
794 g_log
<<Logger::Warning
<<"Zone '"<<target
<<"' contains out-of-zone data '"<<zrr
.dr
.d_name
<<"|"<<DNSRecordContent::NumberToType(zrr
.dr
.d_type
)<<"', ignoring"<<endl
;
798 // Group records by name and type, signpipe stumbles over interrupted rrsets
799 if(securedZone
&& !presignedZone
) {
800 sort(zrrs
.begin(), zrrs
.end(), [](const DNSZoneRecord
& a
, const DNSZoneRecord
& b
) {
801 return tie(a
.dr
.d_name
, a
.dr
.d_type
) < tie(b
.dr
.d_name
, b
.dr
.d_type
);
807 for(DNSZoneRecord
&loopZRR
: zrrs
) {
809 if (loopZRR
.dr
.d_type
!= QType::NS
|| loopZRR
.dr
.d_name
!=target
) {
810 DNSName
shorter(loopZRR
.dr
.d_name
);
812 if (shorter
==target
) // apex is always auth
814 if(nsset
.count(shorter
) && !(loopZRR
.dr
.d_name
==shorter
&& loopZRR
.dr
.d_type
== QType::DS
)) {
818 } while(shorter
.chopOff());
823 // ents are only required for NSEC3 zones
824 uint32_t maxent
= ::arg().asNum("max-ent-entries");
825 set
<DNSName
> nsec3set
, nonterm
;
826 for (auto &loopZRR
: zrrs
) {
828 DNSName shorter
= loopZRR
.dr
.d_name
;
829 if (shorter
!= target
&& shorter
.chopOff() && shorter
!= target
) {
831 if(nsset
.count(shorter
)) {
835 } while(shorter
.chopOff() && shorter
!= target
);
837 shorter
= loopZRR
.dr
.d_name
;
838 if(!skip
&& (loopZRR
.dr
.d_type
!= QType::NS
|| !ns3pr
.d_flags
)) {
840 if(!nsec3set
.count(shorter
)) {
841 nsec3set
.insert(shorter
);
843 } while(shorter
!= target
&& shorter
.chopOff());
847 for(DNSZoneRecord
&loopZRR
: zrrs
) {
848 DNSName
shorter(loopZRR
.dr
.d_name
);
849 while(shorter
!= target
&& shorter
.chopOff()) {
850 if(!qnames
.count(shorter
) && !nonterm
.count(shorter
) && nsec3set
.count(shorter
)) {
852 g_log
<<Logger::Warning
<<"Zone '"<<target
<<"' has too many empty non terminals."<<endl
;
855 nonterm
.insert(shorter
);
861 for(const auto& nt
: nonterm
) {
862 DNSZoneRecord tempRR
;
864 tempRR
.dr
.d_type
=QType::ENT
;
866 zrrs
.push_back(tempRR
);
872 /* now write all other records */
879 for(DNSZoneRecord
&loopZRR
: zrrs
) {
880 if (!presignedZone
&& loopZRR
.dr
.d_type
== QType::RRSIG
)
883 // only skip the DNSKEY, CDNSKEY and CDS if direct-dnskey is enabled, to avoid changing behaviour
884 // when it is not enabled.
885 if(::arg().mustDo("direct-dnskey") && (loopZRR
.dr
.d_type
== QType::DNSKEY
|| loopZRR
.dr
.d_type
== QType::CDNSKEY
|| loopZRR
.dr
.d_type
== QType::CDS
))
889 if(securedZone
&& (loopZRR
.auth
|| loopZRR
.dr
.d_type
== QType::NS
)) {
890 if (NSEC3Zone
|| loopZRR
.dr
.d_type
) {
891 if (presignedZone
&& NSEC3Zone
&& loopZRR
.dr
.d_type
== QType::RRSIG
&& getRR
<RRSIGRecordContent
>(loopZRR
.dr
)->d_type
== QType::NSEC3
) {
892 keyname
= loopZRR
.dr
.d_name
.makeRelative(sd
.qname
);
894 keyname
= NSEC3Zone
? DNSName(toBase32Hex(hashQNameWithSalt(ns3pr
, loopZRR
.dr
.d_name
))) : loopZRR
.dr
.d_name
;
896 NSECXEntry
& ne
= nsecxrepo
[keyname
];
897 ne
.d_ttl
= sd
.default_ttl
;
898 ne
.d_auth
= (ne
.d_auth
|| loopZRR
.auth
|| (NSEC3Zone
&& (!ns3pr
.d_flags
)));
899 if (loopZRR
.dr
.d_type
&& loopZRR
.dr
.d_type
!= QType::RRSIG
) {
900 ne
.d_set
.set(loopZRR
.dr
.d_type
);
905 if (!loopZRR
.dr
.d_type
)
906 continue; // skip empty non-terminals
908 if(loopZRR
.dr
.d_type
== QType::SOA
)
909 continue; // skip SOA - would indicate end of AXFR
911 if(csp
.submit(loopZRR
)) {
913 outpacket
->getRRS() = csp
.getChunk();
914 if(!outpacket
->getRRS().empty()) {
915 if(haveTSIGDetails
&& !tsigkeyname
.empty())
916 outpacket
->setTSIGDetails(trc
, tsigkeyname
, tsigsecret
, trc
.d_mac
, true);
917 sendPacket(outpacket
, outsock
);
918 trc
.d_mac
=outpacket
->d_trc
.d_mac
;
919 outpacket
=getFreshAXFRPacket(q
);
927 udiff=dt.udiffNoReset();
928 cerr<<"Starting NSEC: "<<csp.d_signed/(udiff/1000000.0)<<" sigs/s, "<<csp.d_signed<<" / "<<udiff/1000000.0<<endl;
929 cerr<<"Outstanding: "<<csp.d_outstanding<<", "<<csp.d_queued - csp.d_signed << endl;
930 cerr<<"Ready for consumption: "<<csp.getReady()<<endl;
934 for(nsecxrepo_t::const_iterator iter
= nsecxrepo
.begin(); iter
!= nsecxrepo
.end(); ++iter
) {
935 if(iter
->second
.d_auth
) {
936 NSEC3RecordContent n3rc
;
937 n3rc
.set(iter
->second
.d_set
);
938 const auto numberOfTypesSet
= n3rc
.numberOfTypesSet();
939 if (numberOfTypesSet
!= 0 && (numberOfTypesSet
!= 1 || !n3rc
.isSet(QType::NS
))) {
940 n3rc
.set(QType::RRSIG
);
942 n3rc
.d_salt
= ns3pr
.d_salt
;
943 n3rc
.d_flags
= ns3pr
.d_flags
;
944 n3rc
.d_iterations
= ns3pr
.d_iterations
;
945 n3rc
.d_algorithm
= DNSSECKeeper::SHA1
; // SHA1, fixed in PowerDNS for now
946 nsecxrepo_t::const_iterator inext
= iter
;
948 if(inext
== nsecxrepo
.end())
949 inext
= nsecxrepo
.begin();
950 while(!inext
->second
.d_auth
&& inext
!= iter
)
953 if(inext
== nsecxrepo
.end())
954 inext
= nsecxrepo
.begin();
956 n3rc
.d_nexthash
= fromBase32Hex(inext
->first
.toStringNoDot());
957 zrr
.dr
.d_name
= iter
->first
+sd
.qname
;
959 zrr
.dr
.d_ttl
= sd
.default_ttl
;
960 zrr
.dr
.d_content
= std::make_shared
<NSEC3RecordContent
>(std::move(n3rc
));
961 zrr
.dr
.d_type
= QType::NSEC3
;
962 zrr
.dr
.d_place
= DNSResourceRecord::ANSWER
;
964 if(csp
.submit(zrr
)) {
966 outpacket
->getRRS() = csp
.getChunk();
967 if(!outpacket
->getRRS().empty()) {
968 if(haveTSIGDetails
&& !tsigkeyname
.empty())
969 outpacket
->setTSIGDetails(trc
, tsigkeyname
, tsigsecret
, trc
.d_mac
, true);
970 sendPacket(outpacket
, outsock
);
971 trc
.d_mac
=outpacket
->d_trc
.d_mac
;
972 outpacket
=getFreshAXFRPacket(q
);
981 else for(nsecxrepo_t::const_iterator iter
= nsecxrepo
.begin(); iter
!= nsecxrepo
.end(); ++iter
) {
982 NSECRecordContent nrc
;
983 nrc
.set(iter
->second
.d_set
);
984 nrc
.set(QType::RRSIG
);
985 nrc
.set(QType::NSEC
);
987 if(boost::next(iter
) != nsecxrepo
.end())
988 nrc
.d_next
= boost::next(iter
)->first
;
990 nrc
.d_next
=nsecxrepo
.begin()->first
;
991 zrr
.dr
.d_name
= iter
->first
;
993 zrr
.dr
.d_ttl
= sd
.default_ttl
;
994 zrr
.dr
.d_content
= std::make_shared
<NSECRecordContent
>(std::move(nrc
));
995 zrr
.dr
.d_type
= QType::NSEC
;
996 zrr
.dr
.d_place
= DNSResourceRecord::ANSWER
;
998 if(csp
.submit(zrr
)) {
1000 outpacket
->getRRS() = csp
.getChunk();
1001 if(!outpacket
->getRRS().empty()) {
1002 if(haveTSIGDetails
&& !tsigkeyname
.empty())
1003 outpacket
->setTSIGDetails(trc
, tsigkeyname
, tsigsecret
, trc
.d_mac
, true);
1004 sendPacket(outpacket
, outsock
);
1005 trc
.d_mac
=outpacket
->d_trc
.d_mac
;
1006 outpacket
=getFreshAXFRPacket(q
);
1015 udiff=dt.udiffNoReset();
1016 cerr<<"Flushing pipe: "<<csp.d_signed/(udiff/1000000.0)<<" sigs/s, "<<csp.d_signed<<" / "<<udiff/1000000.0<<endl;
1017 cerr<<"Outstanding: "<<csp.d_outstanding<<", "<<csp.d_queued - csp.d_signed << endl;
1018 cerr<<"Ready for consumption: "<<csp.getReady()<<endl;
1021 outpacket
->getRRS() = csp
.getChunk(true); // flush the pipe
1022 if(!outpacket
->getRRS().empty()) {
1023 if(haveTSIGDetails
&& !tsigkeyname
.empty())
1024 outpacket
->setTSIGDetails(trc
, tsigkeyname
, tsigsecret
, trc
.d_mac
, true); // first answer is 'normal'
1025 sendPacket(outpacket
, outsock
);
1026 trc
.d_mac
=outpacket
->d_trc
.d_mac
;
1027 outpacket
=getFreshAXFRPacket(q
);
1033 udiff
=dt
.udiffNoReset();
1035 g_log
<<Logger::Info
<<"Done signing: "<<csp
.d_signed
/(udiff
/1000000.0)<<" sigs/s, "<<endl
;
1037 DLOG(g_log
<<"Done writing out records"<<endl
);
1038 /* and terminate with yet again the SOA record */
1039 outpacket
=getFreshAXFRPacket(q
);
1040 outpacket
->addRecord(soa
);
1041 if(haveTSIGDetails
&& !tsigkeyname
.empty())
1042 outpacket
->setTSIGDetails(trc
, tsigkeyname
, tsigsecret
, trc
.d_mac
, true);
1044 sendPacket(outpacket
, outsock
);
1046 DLOG(g_log
<<"last packet - close"<<endl
);
1047 g_log
<<Logger::Error
<<"AXFR of domain '"<<target
<<"' to "<<q
->getRemote()<<" finished"<<endl
;
1052 int TCPNameserver::doIXFR(shared_ptr
<DNSPacket
> q
, int outsock
)
1054 shared_ptr
<DNSPacket
> outpacket
=getFreshAXFRPacket(q
);
1056 outpacket
->d_dnssecOk
=true; // RFC 5936, 2.2.5 'SHOULD'
1058 uint32_t serial
= 0;
1059 MOADNSParser
mdp(false, q
->getString());
1060 for(MOADNSParser::answers_t::const_iterator i
=mdp
.d_answers
.begin(); i
!= mdp
.d_answers
.end(); ++i
) {
1061 const DNSRecord
*rr
= &i
->first
;
1062 if (rr
->d_type
== QType::SOA
&& rr
->d_place
== DNSResourceRecord::AUTHORITY
) {
1063 vector
<string
>parts
;
1064 stringtok(parts
, rr
->d_content
->getZoneRepresentation());
1065 if (parts
.size() >= 3) {
1067 serial
=pdns_stou(parts
[2]);
1069 catch(const std::out_of_range
& oor
) {
1070 g_log
<<Logger::Error
<<"Invalid serial in IXFR query"<<endl
;
1071 outpacket
->setRcode(RCode::FormErr
);
1072 sendPacket(outpacket
,outsock
);
1076 g_log
<<Logger::Error
<<"No serial in IXFR query"<<endl
;
1077 outpacket
->setRcode(RCode::FormErr
);
1078 sendPacket(outpacket
,outsock
);
1081 } else if (rr
->d_type
!= QType::TSIG
&& rr
->d_type
!= QType::OPT
) {
1082 g_log
<<Logger::Error
<<"Additional records in IXFR query, type: "<<QType(rr
->d_type
).getName()<<endl
;
1083 outpacket
->setRcode(RCode::FormErr
);
1084 sendPacket(outpacket
,outsock
);
1089 g_log
<<Logger::Error
<<"IXFR of domain '"<<q
->qdomain
<<"' initiated by "<<q
->getRemote()<<" with serial "<<serial
<<endl
;
1091 // determine if zone exists and AXFR is allowed using existing backend before spawning a new backend.
1095 DLOG(g_log
<<"Looking for SOA"<<endl
); // find domain_id via SOA and list complete domain. No SOA, no IXFR
1097 g_log
<<Logger::Error
<<"TCP server is without backend connections in doIXFR, launching"<<endl
;
1098 s_P
=new PacketHandler
;
1101 // canDoAXFR does all the ACL checks, and has the if(disable-axfr) shortcut, call it first.
1102 if(!canDoAXFR(q
) || !s_P
->getBackend()->getSOAUncached(q
->qdomain
, sd
)) {
1103 g_log
<<Logger::Error
<<"IXFR of domain '"<<q
->qdomain
<<"' failed: not authoritative"<<endl
;
1104 outpacket
->setRcode(RCode::NotAuth
);
1105 sendPacket(outpacket
,outsock
);
1111 NSEC3PARAMRecordContent ns3pr
;
1114 dk
.clearCaches(q
->qdomain
);
1115 bool securedZone
= dk
.isSecuredZone(q
->qdomain
);
1116 if(dk
.getNSEC3PARAM(q
->qdomain
, &ns3pr
, &narrow
)) {
1118 g_log
<<Logger::Error
<<"Not doing IXFR of an NSEC3 narrow zone."<<endl
;
1119 g_log
<<Logger::Error
<<"IXFR of domain '"<<q
->qdomain
<<"' denied to "<<q
->getRemote()<<endl
;
1120 outpacket
->setRcode(RCode::Refused
);
1121 sendPacket(outpacket
,outsock
);
1126 DNSName target
= q
->qdomain
;
1129 if(!db
.getSOAUncached(target
, sd
)) {
1130 g_log
<<Logger::Error
<<"IXFR of domain '"<<target
<<"' failed: not authoritative in second instance"<<endl
;
1131 outpacket
->setRcode(RCode::NotAuth
);
1132 sendPacket(outpacket
,outsock
);
1136 if (!rfc1982LessThan(serial
, calculateEditSOA(sd
.serial
, dk
, sd
.qname
))) {
1137 TSIGRecordContent trc
;
1138 DNSName tsigkeyname
;
1141 bool haveTSIGDetails
= q
->getTSIGDetails(&trc
, &tsigkeyname
);
1143 if(haveTSIGDetails
&& !tsigkeyname
.empty()) {
1145 DNSName algorithm
=trc
.d_algoName
; // FIXME400: was toLowerCanonic, compare output
1146 if (algorithm
== DNSName("hmac-md5.sig-alg.reg.int"))
1147 algorithm
= DNSName("hmac-md5");
1149 if(!s_P
->getBackend()->getTSIGKey(tsigkeyname
, &algorithm
, &tsig64
)) {
1150 g_log
<<Logger::Error
<<"TSIG key '"<<tsigkeyname
<<"' for domain '"<<target
<<"' not found"<<endl
;
1153 if (B64Decode(tsig64
, tsigsecret
) == -1) {
1154 g_log
<<Logger::Error
<<"Unable to Base-64 decode TSIG key '"<<tsigkeyname
<<"' for domain '"<<target
<<"'"<<endl
;
1159 UeberBackend signatureDB
;
1161 // SOA *must* go out first, our signing pipe might reorder
1162 DLOG(g_log
<<"Sending out SOA"<<endl
);
1163 DNSZoneRecord soa
= makeEditedDNSZRFromSOAData(dk
, sd
);
1164 outpacket
->addRecord(soa
);
1166 set
<DNSName
> authSet
;
1167 authSet
.insert(target
);
1168 addRRSigs(dk
, signatureDB
, authSet
, outpacket
->getRRS());
1171 if(haveTSIGDetails
&& !tsigkeyname
.empty())
1172 outpacket
->setTSIGDetails(trc
, tsigkeyname
, tsigsecret
, trc
.d_mac
); // first answer is 'normal'
1174 sendPacket(outpacket
, outsock
);
1176 g_log
<<Logger::Error
<<"IXFR of domain '"<<target
<<"' to "<<q
->getRemote()<<" finished"<<endl
;
1181 g_log
<<Logger::Error
<<"IXFR fallback to AXFR for domain '"<<target
<<"' our serial "<<sd
.serial
<<endl
;
1182 return doAXFR(q
->qdomain
, q
, outsock
);
1185 TCPNameserver::~TCPNameserver()
1187 delete d_connectionroom_sem
;
1190 TCPNameserver::TCPNameserver()
1192 d_maxTransactionsPerConn
= ::arg().asNum("max-tcp-transactions-per-conn");
1193 d_idleTimeout
= ::arg().asNum("tcp-idle-timeout");
1194 d_maxConnectionDuration
= ::arg().asNum("max-tcp-connection-duration");
1195 d_maxConnectionsPerClient
= ::arg().asNum("max-tcp-connections-per-client");
1197 // sem_init(&d_connectionroom_sem,0,::arg().asNum("max-tcp-connections"));
1198 d_connectionroom_sem
= new Semaphore( ::arg().asNum( "max-tcp-connections" ));
1199 d_maxTCPConnections
= ::arg().asNum( "max-tcp-connections" );
1201 vector
<string
>locals
;
1202 stringtok(locals
,::arg()["local-address"]," ,");
1204 vector
<string
>locals6
;
1205 stringtok(locals6
,::arg()["local-ipv6"]," ,");
1207 if(locals
.empty() && locals6
.empty())
1208 throw PDNSException("No local address specified");
1210 d_ng
.toMasks(::arg()["allow-axfr-ips"] );
1212 signal(SIGPIPE
,SIG_IGN
);
1214 for(vector
<string
>::const_iterator laddr
=locals
.begin();laddr
!=locals
.end();++laddr
) {
1215 int s
=socket(AF_INET
,SOCK_STREAM
,0);
1218 throw PDNSException("Unable to acquire TCP socket: "+stringerror());
1222 ComboAddress
local(*laddr
, ::arg().asNum("local-port"));
1225 if(setsockopt(s
,SOL_SOCKET
,SO_REUSEADDR
,(char*)&tmp
,sizeof tmp
)<0) {
1226 g_log
<<Logger::Error
<<"Setsockopt failed"<<endl
;
1230 if (::arg().asNum("tcp-fast-open") > 0) {
1232 int fastOpenQueueSize
= ::arg().asNum("tcp-fast-open");
1233 if (setsockopt(s
, IPPROTO_TCP
, TCP_FASTOPEN
, &fastOpenQueueSize
, sizeof fastOpenQueueSize
) < 0) {
1234 g_log
<<Logger::Error
<<"Failed to enable TCP Fast Open for listening socket: "<<strerror(errno
)<<endl
;
1237 g_log
<<Logger::Warning
<<"TCP Fast Open configured but not supported for listening socket"<<endl
;
1241 if( ::arg().mustDo("non-local-bind") )
1242 Utility::setBindAny(AF_INET
, s
);
1244 if(::bind(s
, (sockaddr
*)&local
, local
.getSocklen())<0) {
1246 if( errno
== EADDRNOTAVAIL
&& ! ::arg().mustDo("local-address-nonexist-fail") ) {
1247 g_log
<<Logger::Error
<<"IPv4 Address " << *laddr
<< " does not exist on this server - skipping TCP bind" << endl
;
1250 g_log
<<Logger::Error
<<"Unable to bind to TCP socket " << *laddr
<< ": "<<strerror(errno
)<<endl
;
1251 throw PDNSException("Unable to bind to TCP socket");
1256 g_log
<<Logger::Error
<<"TCP server bound to "<<local
.toStringWithPort()<<endl
;
1257 d_sockets
.push_back(s
);
1259 memset(&pfd
, 0, sizeof(pfd
));
1261 pfd
.events
= POLLIN
;
1263 d_prfds
.push_back(pfd
);
1266 for(vector
<string
>::const_iterator laddr
=locals6
.begin();laddr
!=locals6
.end();++laddr
) {
1267 int s
=socket(AF_INET6
,SOCK_STREAM
,0);
1270 throw PDNSException("Unable to acquire TCPv6 socket: "+stringerror());
1274 ComboAddress
local(*laddr
, ::arg().asNum("local-port"));
1277 if(setsockopt(s
,SOL_SOCKET
,SO_REUSEADDR
,(char*)&tmp
,sizeof tmp
)<0) {
1278 g_log
<<Logger::Error
<<"Setsockopt failed"<<endl
;
1282 if (::arg().asNum("tcp-fast-open") > 0) {
1284 int fastOpenQueueSize
= ::arg().asNum("tcp-fast-open");
1285 if (setsockopt(s
, IPPROTO_TCP
, TCP_FASTOPEN
, &fastOpenQueueSize
, sizeof fastOpenQueueSize
) < 0) {
1286 g_log
<<Logger::Error
<<"Failed to enable TCP Fast Open for listening socket: "<<strerror(errno
)<<endl
;
1289 g_log
<<Logger::Warning
<<"TCP Fast Open configured but not supported for listening socket"<<endl
;
1293 if( ::arg().mustDo("non-local-bind") )
1294 Utility::setBindAny(AF_INET6
, s
);
1295 if(setsockopt(s
, IPPROTO_IPV6
, IPV6_V6ONLY
, &tmp
, sizeof(tmp
)) < 0) {
1296 g_log
<<Logger::Error
<<"Failed to set IPv6 socket to IPv6 only, continuing anyhow: "<<strerror(errno
)<<endl
;
1298 if(bind(s
, (const sockaddr
*)&local
, local
.getSocklen())<0) {
1300 if( errno
== EADDRNOTAVAIL
&& ! ::arg().mustDo("local-ipv6-nonexist-fail") ) {
1301 g_log
<<Logger::Error
<<"IPv6 Address " << *laddr
<< " does not exist on this server - skipping TCP bind" << endl
;
1304 g_log
<<Logger::Error
<<"Unable to bind to TCPv6 socket" << *laddr
<< ": "<<strerror(errno
)<<endl
;
1305 throw PDNSException("Unable to bind to TCPv6 socket");
1310 g_log
<<Logger::Error
<<"TCPv6 server bound to "<<local
.toStringWithPort()<<endl
; // this gets %eth0 right
1311 d_sockets
.push_back(s
);
1314 memset(&pfd
, 0, sizeof(pfd
));
1316 pfd
.events
= POLLIN
;
1318 d_prfds
.push_back(pfd
);
1323 //! Start of TCP operations thread, we launch a new thread for each incoming TCP question
1324 void TCPNameserver::thread()
1326 setThreadName("pdns/tcpnameser");
1330 ComboAddress remote
;
1331 Utility::socklen_t addrlen
=remote
.getSocklen();
1333 int ret
=poll(&d_prfds
[0], d_prfds
.size(), -1); // blocks, forever if need be
1338 for(const pollfd
& pfd
: d_prfds
) {
1339 if(pfd
.revents
& POLLIN
) {
1341 remote
.sin4
.sin_family
= AF_INET6
;
1342 addrlen
=remote
.getSocklen();
1344 if((fd
=accept(sock
, (sockaddr
*)&remote
, &addrlen
))<0) {
1345 g_log
<<Logger::Error
<<"TCP question accept error: "<<strerror(errno
)<<endl
;
1348 g_log
<<Logger::Error
<<"TCP handler out of filedescriptors, exiting, won't recover from this"<<endl
;
1353 if (d_maxConnectionsPerClient
) {
1354 std::lock_guard
<std::mutex
> lock(s_clientsCountMutex
);
1355 if (s_clientsCount
[remote
] >= d_maxConnectionsPerClient
) {
1356 g_log
<<Logger::Notice
<<"Limit of simultaneous TCP connections per client reached for "<< remote
<<", dropping"<<endl
;
1360 s_clientsCount
[remote
]++;
1364 d_connectionroom_sem
->wait(); // blocks if no connections are available
1367 d_connectionroom_sem
->getValue( &room
);
1369 g_log
<<Logger::Warning
<<"Limit of simultaneous TCP connections reached - raise max-tcp-connections"<<endl
;
1371 if(pthread_create(&tid
, 0, &doConnection
, reinterpret_cast<void*>(fd
))) {
1372 g_log
<<Logger::Error
<<"Error creating thread: "<<stringerror()<<endl
;
1373 d_connectionroom_sem
->post();
1375 decrementClientCount(remote
);
1382 catch(PDNSException
&AE
) {
1383 g_log
<<Logger::Error
<<"TCP Nameserver thread dying because of fatal error: "<<AE
.reason
<<endl
;
1386 g_log
<<Logger::Error
<<"TCPNameserver dying because of an unexpected fatal error"<<endl
;
1388 _exit(1); // take rest of server with us
1392 unsigned int TCPNameserver::numTCPConnections()
1395 d_connectionroom_sem
->getValue( &room
);
1396 return d_maxTCPConnections
- room
;