]> git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/tcpreceiver.cc
Merge pull request #8659 from rgacogne/auth-dnsseckeeper-clear-static
[thirdparty/pdns.git] / pdns / tcpreceiver.cc
1 /*
2 PowerDNS Versatile Database Driven Nameserver
3 Copyright (C) 2002-2012 PowerDNS.COM BV
4
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
8
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.
12
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.
17
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
21 */
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25 #include <boost/algorithm/string.hpp>
26 #include "auth-packetcache.hh"
27 #include "utility.hh"
28 #include "threadname.hh"
29 #include "dnssecinfra.hh"
30 #include "dnsseckeeper.hh"
31 #include <cstdio>
32 #include "base32.hh"
33 #include <cstring>
34 #include <cstdlib>
35 #include <sys/types.h>
36 #include <netinet/tcp.h>
37 #include <iostream>
38 #include <string>
39 #include "tcpreceiver.hh"
40 #include "sstuff.hh"
41
42 #include <errno.h>
43 #include <signal.h>
44 #include "base64.hh"
45 #include "ueberbackend.hh"
46 #include "dnspacket.hh"
47 #include "nameserver.hh"
48 #include "distributor.hh"
49 #include "lock.hh"
50 #include "logger.hh"
51 #include "arguments.hh"
52
53 #include "common_startup.hh"
54 #include "packethandler.hh"
55 #include "statbag.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;
62 extern StatBag S;
63
64 /**
65 \file tcpreceiver.cc
66 \brief This file implements the tcpreceiver that receives and answers questions over TCP/IP
67 */
68
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;
80
81 void TCPNameserver::go()
82 {
83 g_log<<Logger::Error<<"Creating backend connection for TCP"<<endl;
84 s_P.reset();
85 try {
86 s_P=make_unique<PacketHandler>();
87 }
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;
90 }
91 pthread_create(&d_tid, 0, launcher, static_cast<void *>(this));
92 }
93
94 void *TCPNameserver::launcher(void *data)
95 {
96 static_cast<TCPNameserver *>(data)->thread();
97 return 0;
98 }
99
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)
102 {
103 unsigned int bytes=n;
104 char *ptr = (char*)buffer;
105 int ret;
106 time_t start = 0;
107 unsigned int remainingTotal = totalTimeout;
108 if (totalTimeout) {
109 start = time(NULL);
110 }
111 while(bytes) {
112 ret=read(fd, ptr, bytes);
113 if(ret < 0) {
114 if(errno==EAGAIN) {
115 ret=waitForData(fd, (totalTimeout == 0 || idleTimeout <= remainingTotal) ? idleTimeout : remainingTotal);
116 if(ret < 0)
117 throw NetworkError("Waiting for data read");
118 if(!ret)
119 throw NetworkError("Timeout reading data");
120 continue;
121 }
122 else
123 throw NetworkError("Reading data: "+stringerror());
124 }
125 if(!ret) {
126 if(!throwOnEOF && n == bytes)
127 return 0;
128 else
129 throw NetworkError("Did not fulfill read from TCP due to EOF");
130 }
131
132 ptr += ret;
133 bytes -= ret;
134 if (totalTimeout) {
135 time_t now = time(NULL);
136 unsigned int elapsed = now - start;
137 if (elapsed >= remainingTotal) {
138 throw NetworkError("Timeout while reading data");
139 }
140 start = now;
141 remainingTotal -= elapsed;
142 }
143 }
144 return n;
145 }
146
147 // ditto
148 static void writenWithTimeout(int fd, const void *buffer, unsigned int n, unsigned int idleTimeout)
149 {
150 unsigned int bytes=n;
151 const char *ptr = (char*)buffer;
152 int ret;
153 while(bytes) {
154 ret=write(fd, ptr, bytes);
155 if(ret < 0) {
156 if(errno==EAGAIN) {
157 ret=waitForRWData(fd, false, idleTimeout, 0);
158 if(ret < 0)
159 throw NetworkError("Waiting for data write");
160 if(!ret)
161 throw NetworkError("Timeout writing data");
162 continue;
163 }
164 else
165 throw NetworkError("Writing data: "+stringerror());
166 }
167 if(!ret) {
168 throw NetworkError("Did not fulfill TCP write due to EOF");
169 }
170
171 ptr += ret;
172 bytes -= ret;
173 }
174 }
175
176 void connectWithTimeout(int fd, struct sockaddr* remote, size_t socklen)
177 {
178 int err;
179 Utility::socklen_t len=sizeof(err);
180
181 if((err=connect(fd, remote, socklen))<0 && errno!=EINPROGRESS)
182 throw NetworkError("connect: "+stringerror());
183
184 if(!err)
185 goto done;
186
187 err=waitForRWData(fd, false, 5, 0);
188 if(err == 0)
189 throw NetworkError("Timeout connecting to remote");
190 if(err < 0)
191 throw NetworkError("Error connecting to remote");
192
193 if(getsockopt(fd, SOL_SOCKET,SO_ERROR,(char *)&err,&len)<0)
194 throw NetworkError("Error connecting to remote: "+stringerror()); // Solaris
195
196 if(err)
197 throw NetworkError("Error connecting to remote: "+string(strerror(err)));
198
199 done:
200 ;
201 }
202
203 void TCPNameserver::sendPacket(std::unique_ptr<DNSPacket>& p, int outsock)
204 {
205 g_rs.submitResponse(*p, false);
206
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);
211 }
212
213
214 void TCPNameserver::getQuestion(int fd, char *mesg, int pktlen, const ComboAddress &remote, unsigned int totalTime)
215 try
216 {
217 readnWithTimeout(fd, mesg, pktlen, d_idleTimeout, true, totalTime);
218 }
219 catch(NetworkError& ae) {
220 throw NetworkError("Error reading DNS data from TCP client "+remote.toString()+": "+ae.what());
221 }
222
223 static void incTCPAnswerCount(const ComboAddress& remote)
224 {
225 S.inc("tcp-answers");
226 if(remote.sin4.sin_family == AF_INET6)
227 S.inc("tcp6-answers");
228 else
229 S.inc("tcp4-answers");
230 }
231
232 static bool maxConnectionDurationReached(unsigned int maxConnectionDuration, time_t start, unsigned int& remainingTime)
233 {
234 if (maxConnectionDuration) {
235 time_t elapsed = time(NULL) - start;
236 if (elapsed >= maxConnectionDuration) {
237 return true;
238 }
239 remainingTime = maxConnectionDuration - elapsed;
240 }
241 return false;
242 }
243
244 void TCPNameserver::decrementClientCount(const ComboAddress& remote)
245 {
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);
251 }
252 }
253 }
254
255 void *TCPNameserver::doConnection(void *data)
256 {
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)
261 ComboAddress remote;
262 socklen_t remotelen=sizeof(remote);
263 size_t transactions = 0;
264 time_t start = 0;
265 if (d_maxConnectionDuration) {
266 start = time(NULL);
267 }
268
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();
273 try {
274 closesocket(fd);
275 }
276 catch(const PDNSException& e) {
277 g_log<<Logger::Error<<"Error closing TCP socket: "<<e.reason<<endl;
278 }
279 return 0;
280 }
281
282 setNonBlocking(fd);
283 try {
284 int mesgsize=65535;
285 scoped_array<char> mesg(new char[mesgsize]);
286
287 DLOG(g_log<<"TCP Connection accepted on fd "<<fd<<endl);
288 bool logDNSQueries= ::arg().mustDo("log-dns-queries");
289 for(;;) {
290 unsigned int remainingTime = 0;
291 transactions++;
292 if (d_maxTransactionsPerConn && transactions > d_maxTransactionsPerConn) {
293 g_log << Logger::Notice<<"TCP Remote "<< remote <<" exceeded the number of transactions per connection, dropping.";
294 break;
295 }
296 if (maxConnectionDurationReached(d_maxConnectionDuration, start, remainingTime)) {
297 g_log << Logger::Notice<<"TCP Remote "<< remote <<" exceeded the maximum TCP connection duration, dropping.";
298 break;
299 }
300
301 uint16_t pktlen;
302 if(!readnWithTimeout(fd, &pktlen, 2, d_idleTimeout, false, remainingTime))
303 break;
304 else
305 pktlen=ntohs(pktlen);
306
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.
311
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;
316 break;
317 }
318
319 if (maxConnectionDurationReached(d_maxConnectionDuration, start, remainingTime)) {
320 g_log << Logger::Notice<<"TCP Remote "<< remote <<" exceeded the maximum TCP connection duration, dropping.";
321 break;
322 }
323
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");
328 else
329 S.inc("tcp4-queries");
330
331 packet=make_unique<DNSPacket>(true);
332 packet->setRemote(&remote);
333 packet->d_tcp=true;
334 packet->setSocket(fd);
335 if(packet->parse(mesg.get(), pktlen)<0)
336 break;
337
338 if(packet->qtype.getCode()==QType::AXFR) {
339 if(doAXFR(packet->qdomain, packet, fd))
340 incTCPAnswerCount(remote);
341 continue;
342 }
343
344 if(packet->qtype.getCode()==QType::IXFR) {
345 if(doIXFR(packet, fd))
346 incTCPAnswerCount(remote);
347 continue;
348 }
349
350 std::unique_ptr<DNSPacket> reply;
351 auto cached = make_unique<DNSPacket>(false);
352 if(logDNSQueries) {
353 string remote_text;
354 if(packet->hasEDNSSubnet())
355 remote_text = packet->getRemote().toString() + "<-" + packet->getRealRemote().toString();
356 else
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();
360 }
361
362 if(PC.enabled()) {
363 if(packet->couldBeCached() && PC.get(*packet, *cached)) { // short circuit - does the PacketCache recognize this question?
364 if(logDNSQueries)
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
370
371 sendPacket(cached, fd); // presigned, don't do it again
372 continue;
373 }
374 if(logDNSQueries)
375 g_log<<": packetcache MISS"<<endl;
376 } else {
377 if (logDNSQueries) {
378 g_log<<endl;
379 }
380 }
381 {
382 Lock l(&s_plock);
383 if(!s_P) {
384 g_log<<Logger::Error<<"TCP server is without backend connections, launching"<<endl;
385 s_P=make_unique<PacketHandler>();
386 }
387
388 reply= s_P->doQuestion(*packet); // we really need to ask the backend :-)
389 }
390
391 if(!reply) // unable to write an answer?
392 break;
393
394 sendPacket(reply, fd);
395 }
396 }
397 catch(PDNSException &ae) {
398 Lock l(&s_plock);
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;
401 }
402 catch(NetworkError &e) {
403 g_log<<Logger::Info<<"TCP Connection Thread died because of network error: "<<e.what()<<endl;
404 }
405
406 catch(std::exception &e) {
407 g_log<<Logger::Error<<"TCP Connection Thread died because of STL error: "<<e.what()<<endl;
408 }
409 catch( ... )
410 {
411 g_log << Logger::Error << "TCP Connection Thread caught unknown exception." << endl;
412 }
413 d_connectionroom_sem->post();
414
415 try {
416 closesocket(fd);
417 }
418 catch(const PDNSException& e) {
419 g_log<<Logger::Error<<"Error closing TCP socket: "<<e.reason<<endl;
420 }
421 decrementClientCount(remote);
422
423 return 0;
424 }
425
426
427 // call this method with s_plock held!
428 bool TCPNameserver::canDoAXFR(std::unique_ptr<DNSPacket>& q)
429 {
430 if(::arg().mustDo("disable-axfr"))
431 return false;
432
433 if(q->d_havetsig) { // if you have one, it must be good
434 TSIGRecordContent trc;
435 DNSName keyname;
436 string secret;
437 if(!q->checkForCorrectTSIG(s_P->getBackend(), &keyname, &secret, &trc)) {
438 return false;
439 } else {
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;
445 }
446 }
447 }
448
449 DNSSECKeeper dk(s_P->getBackend());
450
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;
457 return true;
458 }
459 }
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;
461 return false;
462 }
463
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;
466 return false;
467 }
468 else {
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;
470 return true;
471 }
472 }
473
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;
477 return true;
478 }
479
480 FindNS fns;
481
482 // cerr<<"doing per-zone-axfr-acls"<<endl;
483 SOAData sd;
484 if(s_P->getBackend()->getSOAUncached(q->qdomain,sd)) {
485 // cerr<<"got backend and SOA"<<endl;
486 DNSBackend *B=sd.db;
487 vector<string> acl;
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;
493
494 DNSResourceRecord rr;
495 set<DNSName> nsset;
496
497 B->lookup(QType(QType::NS),q->qdomain,sd.domain_id);
498 while(B->get(rr))
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())
505 {
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;
508 return true;
509 }
510 }
511 }
512 }
513 else
514 {
515 Netmask nm = Netmask(*i);
516 if(nm.match( (ComboAddress *) &q->d_remote ))
517 {
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;
520 return true;
521 }
522 }
523 }
524 }
525
526 extern CommunicatorClass Communicator;
527
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;
530 return true;
531 }
532
533 g_log<<Logger::Error<<"AXFR of domain '"<<q->qdomain<<"' denied: client IP "<<q->getRemote()<<" has no permission"<<endl;
534 return false;
535 }
536
537 namespace {
538 struct NSECXEntry
539 {
540 NSECBitmap d_set;
541 unsigned int d_ttl;
542 bool d_auth;
543 };
544
545 static std::unique_ptr<DNSPacket> getFreshAXFRPacket(std::unique_ptr<DNSPacket>& q)
546 {
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
550 ret->d_tcp = true;
551 return ret;
552 }
553 }
554
555
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)
558 {
559 std::unique_ptr<DNSPacket> outpacket= getFreshAXFRPacket(q);
560 if(q->d_dnssecOk)
561 outpacket->d_dnssecOk=true; // RFC 5936, 2.2.5 'SHOULD'
562
563 g_log<<Logger::Error<<"AXFR of domain '"<<target<<"' initiated by "<<q->getRemote()<<endl;
564
565 // determine if zone exists and AXFR is allowed using existing backend before spawning a new backend.
566 SOAData sd;
567 {
568 Lock l(&s_plock);
569 DLOG(g_log<<"Looking for SOA"<<endl); // find domain_id via SOA and list complete domain. No SOA, no AXFR
570 if(!s_P) {
571 g_log<<Logger::Error<<"TCP server is without backend connections in doAXFR, launching"<<endl;
572 s_P=make_unique<PacketHandler>();
573 }
574
575 // canDoAXFR does all the ACL checks, and has the if(disable-axfr) shortcut, call it first.
576 if (!canDoAXFR(q)) {
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);
580 return 0;
581 }
582
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);
587 return 0;
588 }
589 }
590
591 UeberBackend db;
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);
596 return 0;
597 }
598
599 DNSSECKeeper dk(&db);
600 DNSSECKeeper::clearCaches(target);
601 bool securedZone = dk.isSecuredZone(target);
602 bool presignedZone = dk.isPresigned(target);
603
604 bool noAXFRBecauseOfNSEC3Narrow=false;
605 NSEC3PARAMRecordContent ns3pr;
606 bool narrow;
607 bool NSEC3Zone=false;
608 if(securedZone && dk.getNSEC3PARAM(target, &ns3pr, &narrow)) {
609 NSEC3Zone=true;
610 if(narrow) {
611 g_log<<Logger::Error<<"Not doing AXFR of an NSEC3 narrow zone '"<<target<<"' for "<<q->getRemote()<<endl;
612 noAXFRBecauseOfNSEC3Narrow=true;
613 }
614 }
615
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);
621 return 0;
622 }
623
624 TSIGRecordContent trc;
625 DNSName tsigkeyname;
626 string tsigsecret;
627
628 bool haveTSIGDetails = q->getTSIGDetails(&trc, &tsigkeyname);
629
630 if(haveTSIGDetails && !tsigkeyname.empty()) {
631 string tsig64;
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;
638 return 0;
639 }
640 if (B64Decode(tsig64, tsigsecret) == -1) {
641 g_log<<Logger::Error<<"Unable to Base-64 decode TSIG key '"<<tsigkeyname<<"' for domain '"<<target<<"'"<<endl;
642 return 0;
643 }
644 }
645 }
646
647
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());
656 }
657
658 if(haveTSIGDetails && !tsigkeyname.empty())
659 outpacket->setTSIGDetails(trc, tsigkeyname, tsigsecret, trc.d_mac); // first answer is 'normal'
660
661 sendPacket(outpacket, outsock);
662
663 trc.d_mac = outpacket->d_trc.d_mac;
664 outpacket = getFreshAXFRPacket(q);
665
666 ChunkedSigningPipe csp(target, (securedZone && !presignedZone), ::arg().asNum("signing-threads", 1));
667
668 typedef map<DNSName, NSECXEntry, CanonDNSNameCompare> nsecxrepo_t;
669 nsecxrepo_t nsecxrepo;
670
671 // this is where the DNSKEYs go in
672
673 DNSSECKeeper::keyset_t keys = dk.getKeys(target);
674
675 DNSZoneRecord zrr;
676
677 zrr.dr.d_name = target;
678 zrr.dr.d_ttl = sd.default_ttl;
679 zrr.auth = 1; // please sign!
680
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);
689
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];
695
696 ne.d_set.set(zrr.dr.d_type);
697 ne.d_ttl = sd.default_ttl;
698 csp.submit(zrr);
699
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);
706 }
707
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)));
714 cds.push_back(zrr);
715 }
716 }
717 }
718 }
719
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;
724 csp.submit(zrr);
725 }
726 }
727
728 uint8_t flags;
729
730 if(NSEC3Zone) { // now stuff in the NSEC3PARAM
731 flags = ns3pr.d_flags;
732 zrr.dr.d_type = QType::NSEC3PARAM;
733 ns3pr.d_flags = 0;
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];
738
739 ne.d_set.set(zrr.dr.d_type);
740 csp.submit(zrr);
741 }
742
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);
748 return 0;
749 }
750
751
752 const bool rectify = !(presignedZone || ::arg().mustDo("disable-axfr-rectify"));
753 set<DNSName> qnames, nsset, terms;
754 vector<DNSZoneRecord> zrrs;
755
756 // Add the CDNSKEY and CDS records we created earlier
757 for (auto const &synth_zrr : cds)
758 zrrs.push_back(synth_zrr);
759
760 for (auto const &synth_zrr : cdnskey)
761 zrrs.push_back(synth_zrr);
762
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);
774 return 0;
775 }
776 for(const auto& ip: ips) {
777 zrr.dr.d_type = ip.dr.d_type;
778 zrr.dr.d_content = ip.dr.d_content;
779 zrrs.push_back(zrr);
780 }
781 continue;
782 }
783
784 if (rectify) {
785 if (zrr.dr.d_type) {
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);
789 } else {
790 // remove existing ents
791 continue;
792 }
793 }
794 zrrs.push_back(zrr);
795 } else {
796 if (zrr.dr.d_type)
797 g_log<<Logger::Warning<<"Zone '"<<target<<"' contains out-of-zone data '"<<zrr.dr.d_name<<"|"<<DNSRecordContent::NumberToType(zrr.dr.d_type)<<"', ignoring"<<endl;
798 }
799 }
800
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);
805 });
806 }
807
808 if(rectify) {
809 // set auth
810 for(DNSZoneRecord &loopZRR : zrrs) {
811 loopZRR.auth=true;
812 if (loopZRR.dr.d_type != QType::NS || loopZRR.dr.d_name!=target) {
813 DNSName shorter(loopZRR.dr.d_name);
814 do {
815 if (shorter==target) // apex is always auth
816 break;
817 if(nsset.count(shorter) && !(loopZRR.dr.d_name==shorter && loopZRR.dr.d_type == QType::DS)) {
818 loopZRR.auth=false;
819 break;
820 }
821 } while(shorter.chopOff());
822 }
823 }
824
825 if(NSEC3Zone) {
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) {
830 bool skip=false;
831 DNSName shorter = loopZRR.dr.d_name;
832 if (shorter != target && shorter.chopOff() && shorter != target) {
833 do {
834 if(nsset.count(shorter)) {
835 skip=true;
836 break;
837 }
838 } while(shorter.chopOff() && shorter != target);
839 }
840 shorter = loopZRR.dr.d_name;
841 if(!skip && (loopZRR.dr.d_type != QType::NS || !ns3pr.d_flags)) {
842 do {
843 if(!nsec3set.count(shorter)) {
844 nsec3set.insert(shorter);
845 }
846 } while(shorter != target && shorter.chopOff());
847 }
848 }
849
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)) {
854 if(!(maxent)) {
855 g_log<<Logger::Warning<<"Zone '"<<target<<"' has too many empty non terminals."<<endl;
856 return 0;
857 }
858 nonterm.insert(shorter);
859 --maxent;
860 }
861 }
862 }
863
864 for(const auto& nt : nonterm) {
865 DNSZoneRecord tempRR;
866 tempRR.dr.d_name=nt;
867 tempRR.dr.d_type=QType::ENT;
868 tempRR.auth=true;
869 zrrs.push_back(tempRR);
870 }
871 }
872 }
873
874
875 /* now write all other records */
876
877 DNSName keyname;
878 unsigned int udiff;
879 DTime dt;
880 dt.set();
881 int records=0;
882 for(DNSZoneRecord &loopZRR : zrrs) {
883 if (!presignedZone && loopZRR.dr.d_type == QType::RRSIG)
884 continue;
885
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))
889 continue;
890
891 records++;
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);
896 } else {
897 keyname = NSEC3Zone ? DNSName(toBase32Hex(hashQNameWithSalt(ns3pr, loopZRR.dr.d_name))) : loopZRR.dr.d_name;
898 }
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);
904 }
905 }
906 }
907
908 if (!loopZRR.dr.d_type)
909 continue; // skip empty non-terminals
910
911 if(loopZRR.dr.d_type == QType::SOA)
912 continue; // skip SOA - would indicate end of AXFR
913
914 if(csp.submit(loopZRR)) {
915 for(;;) {
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);
923 }
924 else
925 break;
926 }
927 }
928 }
929 /*
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;
934 */
935 if(securedZone) {
936 if(NSEC3Zone) {
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);
944 }
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;
950 ++inext;
951 if(inext == nsecxrepo.end())
952 inext = nsecxrepo.begin();
953 while(!inext->second.d_auth && inext != iter)
954 {
955 ++inext;
956 if(inext == nsecxrepo.end())
957 inext = nsecxrepo.begin();
958 }
959 n3rc.d_nexthash = fromBase32Hex(inext->first.toStringNoDot());
960 zrr.dr.d_name = iter->first+sd.qname;
961
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;
966 zrr.auth=true;
967 if(csp.submit(zrr)) {
968 for(;;) {
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);
976 }
977 else
978 break;
979 }
980 }
981 }
982 }
983 }
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);
989
990 if(boost::next(iter) != nsecxrepo.end())
991 nrc.d_next = boost::next(iter)->first;
992 else
993 nrc.d_next=nsecxrepo.begin()->first;
994 zrr.dr.d_name = iter->first;
995
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;
1000 zrr.auth=true;
1001 if(csp.submit(zrr)) {
1002 for(;;) {
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);
1010 }
1011 else
1012 break;
1013 }
1014 }
1015 }
1016 }
1017 /*
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;
1022 * */
1023 for(;;) {
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);
1031 }
1032 else
1033 break;
1034 }
1035
1036 udiff=dt.udiffNoReset();
1037 if(securedZone)
1038 g_log<<Logger::Info<<"Done signing: "<<csp.d_signed/(udiff/1000000.0)<<" sigs/s, "<<endl;
1039
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);
1046
1047 sendPacket(outpacket, outsock);
1048
1049 DLOG(g_log<<"last packet - close"<<endl);
1050 g_log<<Logger::Error<<"AXFR of domain '"<<target<<"' to "<<q->getRemote()<<" finished"<<endl;
1051
1052 return 1;
1053 }
1054
1055 int TCPNameserver::doIXFR(std::unique_ptr<DNSPacket>& q, int outsock)
1056 {
1057 std::unique_ptr<DNSPacket> outpacket=getFreshAXFRPacket(q);
1058 if(q->d_dnssecOk)
1059 outpacket->d_dnssecOk=true; // RFC 5936, 2.2.5 'SHOULD'
1060
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) {
1069 try {
1070 serial=pdns_stou(parts[2]);
1071 }
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);
1076 return 0;
1077 }
1078 } else {
1079 g_log<<Logger::Error<<"No serial in IXFR query"<<endl;
1080 outpacket->setRcode(RCode::FormErr);
1081 sendPacket(outpacket,outsock);
1082 return 0;
1083 }
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);
1088 return 0;
1089 }
1090 }
1091
1092 g_log<<Logger::Error<<"IXFR of domain '"<<q->qdomain<<"' initiated by "<<q->getRemote()<<" with serial "<<serial<<endl;
1093
1094 // determine if zone exists and AXFR is allowed using existing backend before spawning a new backend.
1095 SOAData sd;
1096 {
1097 Lock l(&s_plock);
1098 DLOG(g_log<<"Looking for SOA"<<endl); // find domain_id via SOA and list complete domain. No SOA, no IXFR
1099 if(!s_P) {
1100 g_log<<Logger::Error<<"TCP server is without backend connections in doIXFR, launching"<<endl;
1101 s_P=make_unique<PacketHandler>();
1102 }
1103
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);
1109 return 0;
1110 }
1111 }
1112
1113 DNSSECKeeper dk;
1114 NSEC3PARAMRecordContent ns3pr;
1115 bool narrow;
1116
1117 DNSSECKeeper::clearCaches(q->qdomain);
1118 bool securedZone = dk.isSecuredZone(q->qdomain);
1119 if(dk.getNSEC3PARAM(q->qdomain, &ns3pr, &narrow)) {
1120 if(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);
1125 return 0;
1126 }
1127 }
1128
1129 DNSName target = q->qdomain;
1130
1131 UeberBackend db;
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);
1136 return 0;
1137 }
1138
1139 if (!rfc1982LessThan(serial, calculateEditSOA(sd.serial, dk, sd.qname))) {
1140 TSIGRecordContent trc;
1141 DNSName tsigkeyname;
1142 string tsigsecret;
1143
1144 bool haveTSIGDetails = q->getTSIGDetails(&trc, &tsigkeyname);
1145
1146 if(haveTSIGDetails && !tsigkeyname.empty()) {
1147 string tsig64;
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");
1151 Lock l(&s_plock);
1152 if(!s_P->getBackend()->getTSIGKey(tsigkeyname, &algorithm, &tsig64)) {
1153 g_log<<Logger::Error<<"TSIG key '"<<tsigkeyname<<"' for domain '"<<target<<"' not found"<<endl;
1154 return 0;
1155 }
1156 if (B64Decode(tsig64, tsigsecret) == -1) {
1157 g_log<<Logger::Error<<"Unable to Base-64 decode TSIG key '"<<tsigkeyname<<"' for domain '"<<target<<"'"<<endl;
1158 return 0;
1159 }
1160 }
1161
1162 UeberBackend signatureDB;
1163
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);
1168 if(securedZone) {
1169 set<DNSName> authSet;
1170 authSet.insert(target);
1171 addRRSigs(dk, signatureDB, authSet, outpacket->getRRS());
1172 }
1173
1174 if(haveTSIGDetails && !tsigkeyname.empty())
1175 outpacket->setTSIGDetails(trc, tsigkeyname, tsigsecret, trc.d_mac); // first answer is 'normal'
1176
1177 sendPacket(outpacket, outsock);
1178
1179 g_log<<Logger::Error<<"IXFR of domain '"<<target<<"' to "<<q->getRemote()<<" finished"<<endl;
1180
1181 return 1;
1182 }
1183
1184 g_log<<Logger::Error<<"IXFR fallback to AXFR for domain '"<<target<<"' our serial "<<sd.serial<<endl;
1185 return doAXFR(q->qdomain, q, outsock);
1186 }
1187
1188 TCPNameserver::~TCPNameserver()
1189 {
1190 }
1191
1192 TCPNameserver::TCPNameserver()
1193 {
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");
1198
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" );
1202 d_tid=0;
1203
1204 vector<string>locals;
1205 stringtok(locals,::arg()["local-address"]," ,");
1206 if(locals.empty())
1207 throw PDNSException("No local addresses specified");
1208
1209 d_ng.toMasks(::arg()["allow-axfr-ips"] );
1210
1211 signal(SIGPIPE,SIG_IGN);
1212
1213 for(auto const &laddr : locals) {
1214 ComboAddress local(laddr, ::arg().asNum("local-port"));
1215
1216 int s=socket(local.sin4.sin_family, SOCK_STREAM, 0);
1217 if(s<0)
1218 throw PDNSException("Unable to acquire TCP socket: "+stringerror());
1219 setCloseOnExec(s);
1220
1221 int tmp=1;
1222 if(setsockopt(s, SOL_SOCKET,SO_REUSEADDR, (char*)&tmp, sizeof tmp) < 0) {
1223 g_log<<Logger::Error<<"Setsockopt failed"<<endl;
1224 _exit(1);
1225 }
1226
1227 if (::arg().asNum("tcp-fast-open") > 0) {
1228 #ifdef TCP_FASTOPEN
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;
1232 }
1233 #else
1234 g_log<<Logger::Warning<<"TCP Fast Open configured but not supported for listening socket"<<endl;
1235 #endif
1236 }
1237
1238 if(::arg().mustDo("non-local-bind"))
1239 Utility::setBindAny(local.sin4.sin_family, s);
1240
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;
1243 }
1244
1245 if(::bind(s, (sockaddr*)&local, local.getSocklen())<0) {
1246 int err = errno;
1247 close(s);
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;
1250 continue;
1251 } else {
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");
1254 }
1255 }
1256
1257 listen(s, 128);
1258 g_log<<Logger::Error<<"TCP server bound to "<<local.toStringWithPort()<<endl;
1259 d_sockets.push_back(s);
1260 struct pollfd pfd;
1261 memset(&pfd, 0, sizeof(pfd));
1262 pfd.fd = s;
1263 pfd.events = POLLIN;
1264 d_prfds.push_back(pfd);
1265 }
1266 }
1267
1268
1269 //! Start of TCP operations thread, we launch a new thread for each incoming TCP question
1270 void TCPNameserver::thread()
1271 {
1272 setThreadName("pdns/tcpnameser");
1273 try {
1274 for(;;) {
1275 int fd;
1276 ComboAddress remote;
1277 Utility::socklen_t addrlen=remote.getSocklen();
1278
1279 int ret=poll(&d_prfds[0], d_prfds.size(), -1); // blocks, forever if need be
1280 if(ret <= 0)
1281 continue;
1282
1283 int sock=-1;
1284 for(const pollfd& pfd : d_prfds) {
1285 if(pfd.revents & POLLIN) {
1286 sock = pfd.fd;
1287 remote.sin4.sin_family = AF_INET6;
1288 addrlen=remote.getSocklen();
1289
1290 if((fd=accept(sock, (sockaddr*)&remote, &addrlen))<0) {
1291 int err = errno;
1292 g_log<<Logger::Error<<"TCP question accept error: "<<stringerror(err)<<endl;
1293
1294 if(err==EMFILE) {
1295 g_log<<Logger::Error<<"TCP handler out of filedescriptors, exiting, won't recover from this"<<endl;
1296 _exit(1);
1297 }
1298 }
1299 else {
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;
1304 close(fd);
1305 continue;
1306 }
1307 s_clientsCount[remote]++;
1308 }
1309
1310 pthread_t tid;
1311 d_connectionroom_sem->wait(); // blocks if no connections are available
1312
1313 int room;
1314 d_connectionroom_sem->getValue( &room);
1315 if(room<1)
1316 g_log<<Logger::Warning<<"Limit of simultaneous TCP connections reached - raise max-tcp-connections"<<endl;
1317
1318 int err;
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();
1322 close(fd);
1323 decrementClientCount(remote);
1324 }
1325 }
1326 }
1327 }
1328 }
1329 }
1330 catch(PDNSException &AE) {
1331 g_log<<Logger::Error<<"TCP Nameserver thread dying because of fatal error: "<<AE.reason<<endl;
1332 }
1333 catch(...) {
1334 g_log<<Logger::Error<<"TCPNameserver dying because of an unexpected fatal error"<<endl;
1335 }
1336 _exit(1); // take rest of server with us
1337 }
1338
1339
1340 unsigned int TCPNameserver::numTCPConnections()
1341 {
1342 int room;
1343 d_connectionroom_sem->getValue( &room);
1344 return d_maxTCPConnections - room;
1345 }