]> git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/tcpreceiver.cc
706305c87aa718be343b0308dee1ce78b9383ade
[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 Semaphore *TCPNameserver::d_connectionroom_sem;
71 PacketHandler *TCPNameserver::s_P;
72 NetmaskGroup TCPNameserver::d_ng;
73 size_t TCPNameserver::d_maxTransactionsPerConn;
74 size_t TCPNameserver::d_maxConnectionsPerClient;
75 unsigned int TCPNameserver::d_idleTimeout;
76 unsigned int TCPNameserver::d_maxConnectionDuration;
77 std::mutex TCPNameserver::s_clientsCountMutex;
78 std::map<ComboAddress,size_t,ComboAddress::addressOnlyLessThan> TCPNameserver::s_clientsCount;
79
80 void TCPNameserver::go()
81 {
82 g_log<<Logger::Error<<"Creating backend connection for TCP"<<endl;
83 s_P=0;
84 try {
85 s_P=new PacketHandler;
86 }
87 catch(PDNSException &ae) {
88 g_log<<Logger::Error<<"TCP server is unable to launch backends - will try again when questions come in: "<<ae.reason<<endl;
89 }
90 pthread_create(&d_tid, 0, launcher, static_cast<void *>(this));
91 }
92
93 void *TCPNameserver::launcher(void *data)
94 {
95 static_cast<TCPNameserver *>(data)->thread();
96 return 0;
97 }
98
99 // throws PDNSException if things didn't go according to plan, returns 0 if really 0 bytes were read
100 static int readnWithTimeout(int fd, void* buffer, unsigned int n, unsigned int idleTimeout, bool throwOnEOF=true, unsigned int totalTimeout=0)
101 {
102 unsigned int bytes=n;
103 char *ptr = (char*)buffer;
104 int ret;
105 time_t start = 0;
106 unsigned int remainingTotal = totalTimeout;
107 if (totalTimeout) {
108 start = time(NULL);
109 }
110 while(bytes) {
111 ret=read(fd, ptr, bytes);
112 if(ret < 0) {
113 if(errno==EAGAIN) {
114 ret=waitForData(fd, (totalTimeout == 0 || idleTimeout <= remainingTotal) ? idleTimeout : remainingTotal);
115 if(ret < 0)
116 throw NetworkError("Waiting for data read");
117 if(!ret)
118 throw NetworkError("Timeout reading data");
119 continue;
120 }
121 else
122 throw NetworkError("Reading data: "+stringerror());
123 }
124 if(!ret) {
125 if(!throwOnEOF && n == bytes)
126 return 0;
127 else
128 throw NetworkError("Did not fulfill read from TCP due to EOF");
129 }
130
131 ptr += ret;
132 bytes -= ret;
133 if (totalTimeout) {
134 time_t now = time(NULL);
135 unsigned int elapsed = now - start;
136 if (elapsed >= remainingTotal) {
137 throw NetworkError("Timeout while reading data");
138 }
139 start = now;
140 remainingTotal -= elapsed;
141 }
142 }
143 return n;
144 }
145
146 // ditto
147 static void writenWithTimeout(int fd, const void *buffer, unsigned int n, unsigned int idleTimeout)
148 {
149 unsigned int bytes=n;
150 const char *ptr = (char*)buffer;
151 int ret;
152 while(bytes) {
153 ret=write(fd, ptr, bytes);
154 if(ret < 0) {
155 if(errno==EAGAIN) {
156 ret=waitForRWData(fd, false, idleTimeout, 0);
157 if(ret < 0)
158 throw NetworkError("Waiting for data write");
159 if(!ret)
160 throw NetworkError("Timeout writing data");
161 continue;
162 }
163 else
164 throw NetworkError("Writing data: "+stringerror());
165 }
166 if(!ret) {
167 throw NetworkError("Did not fulfill TCP write due to EOF");
168 }
169
170 ptr += ret;
171 bytes -= ret;
172 }
173 }
174
175 void connectWithTimeout(int fd, struct sockaddr* remote, size_t socklen)
176 {
177 int err;
178 Utility::socklen_t len=sizeof(err);
179
180 if((err=connect(fd, remote, socklen))<0 && errno!=EINPROGRESS)
181 throw NetworkError("connect: "+stringerror());
182
183 if(!err)
184 goto done;
185
186 err=waitForRWData(fd, false, 5, 0);
187 if(err == 0)
188 throw NetworkError("Timeout connecting to remote");
189 if(err < 0)
190 throw NetworkError("Error connecting to remote");
191
192 if(getsockopt(fd, SOL_SOCKET,SO_ERROR,(char *)&err,&len)<0)
193 throw NetworkError("Error connecting to remote: "+stringerror()); // Solaris
194
195 if(err)
196 throw NetworkError("Error connecting to remote: "+string(strerror(err)));
197
198 done:
199 ;
200 }
201
202 void TCPNameserver::sendPacket(shared_ptr<DNSPacket> p, int outsock)
203 {
204 g_rs.submitResponse(*p, false);
205
206 uint16_t len=htons(p->getString().length());
207 string buffer((const char*)&len, 2);
208 buffer.append(p->getString());
209 writenWithTimeout(outsock, buffer.c_str(), buffer.length(), d_idleTimeout);
210 }
211
212
213 void TCPNameserver::getQuestion(int fd, char *mesg, int pktlen, const ComboAddress &remote, unsigned int totalTime)
214 try
215 {
216 readnWithTimeout(fd, mesg, pktlen, d_idleTimeout, true, totalTime);
217 }
218 catch(NetworkError& ae) {
219 throw NetworkError("Error reading DNS data from TCP client "+remote.toString()+": "+ae.what());
220 }
221
222 static void incTCPAnswerCount(const ComboAddress& remote)
223 {
224 S.inc("tcp-answers");
225 if(remote.sin4.sin_family == AF_INET6)
226 S.inc("tcp6-answers");
227 else
228 S.inc("tcp4-answers");
229 }
230
231 static bool maxConnectionDurationReached(unsigned int maxConnectionDuration, time_t start, unsigned int& remainingTime)
232 {
233 if (maxConnectionDuration) {
234 time_t elapsed = time(NULL) - start;
235 if (elapsed >= maxConnectionDuration) {
236 return true;
237 }
238 remainingTime = maxConnectionDuration - elapsed;
239 }
240 return false;
241 }
242
243 void TCPNameserver::decrementClientCount(const ComboAddress& remote)
244 {
245 if (d_maxConnectionsPerClient) {
246 std::lock_guard<std::mutex> lock(s_clientsCountMutex);
247 s_clientsCount[remote]--;
248 if (s_clientsCount[remote] == 0) {
249 s_clientsCount.erase(remote);
250 }
251 }
252 }
253
254 void *TCPNameserver::doConnection(void *data)
255 {
256 setThreadName("pdns/tcpConnect");
257 shared_ptr<DNSPacket> packet;
258 // Fix gcc-4.0 error (on AMD64)
259 int fd=(int)(long)data; // gotta love C (generates a harmless warning on opteron)
260 ComboAddress remote;
261 socklen_t remotelen=sizeof(remote);
262 size_t transactions = 0;
263 time_t start = 0;
264 if (d_maxConnectionDuration) {
265 start = time(NULL);
266 }
267
268 pthread_detach(pthread_self());
269 if(getpeername(fd, (struct sockaddr *)&remote, &remotelen) < 0) {
270 g_log<<Logger::Warning<<"Received question from socket which had no remote address, dropping ("<<stringerror()<<")"<<endl;
271 d_connectionroom_sem->post();
272 try {
273 closesocket(fd);
274 }
275 catch(const PDNSException& e) {
276 g_log<<Logger::Error<<"Error closing TCP socket: "<<e.reason<<endl;
277 }
278 return 0;
279 }
280
281 setNonBlocking(fd);
282 try {
283 int mesgsize=65535;
284 scoped_array<char> mesg(new char[mesgsize]);
285
286 DLOG(g_log<<"TCP Connection accepted on fd "<<fd<<endl);
287 bool logDNSQueries= ::arg().mustDo("log-dns-queries");
288 for(;;) {
289 unsigned int remainingTime = 0;
290 transactions++;
291 if (d_maxTransactionsPerConn && transactions > d_maxTransactionsPerConn) {
292 g_log << Logger::Notice<<"TCP Remote "<< remote <<" exceeded the number of transactions per connection, dropping.";
293 break;
294 }
295 if (maxConnectionDurationReached(d_maxConnectionDuration, start, remainingTime)) {
296 g_log << Logger::Notice<<"TCP Remote "<< remote <<" exceeded the maximum TCP connection duration, dropping.";
297 break;
298 }
299
300 uint16_t pktlen;
301 if(!readnWithTimeout(fd, &pktlen, 2, d_idleTimeout, false, remainingTime))
302 break;
303 else
304 pktlen=ntohs(pktlen);
305
306 // this check will always be false *if* no one touches
307 // the mesg array. pktlen can be maximum of 65535 as
308 // it is 2 byte unsigned variable. In getQuestion, we
309 // write to 0 up to pktlen-1 so 65535 is just right.
310
311 // do not remove this check as it will catch if someone
312 // decreases the mesg buffer size for some reason.
313 if(pktlen > mesgsize) {
314 g_log<<Logger::Warning<<"Received an overly large question from "<<remote.toString()<<", dropping"<<endl;
315 break;
316 }
317
318 if (maxConnectionDurationReached(d_maxConnectionDuration, start, remainingTime)) {
319 g_log << Logger::Notice<<"TCP Remote "<< remote <<" exceeded the maximum TCP connection duration, dropping.";
320 break;
321 }
322
323 getQuestion(fd, mesg.get(), pktlen, remote, remainingTime);
324 S.inc("tcp-queries");
325 if(remote.sin4.sin_family == AF_INET6)
326 S.inc("tcp6-queries");
327 else
328 S.inc("tcp4-queries");
329
330 packet=shared_ptr<DNSPacket>(new DNSPacket(true));
331 packet->setRemote(&remote);
332 packet->d_tcp=true;
333 packet->setSocket(fd);
334 if(packet->parse(mesg.get(), pktlen)<0)
335 break;
336
337 if(packet->qtype.getCode()==QType::AXFR) {
338 if(doAXFR(packet->qdomain, packet, fd))
339 incTCPAnswerCount(remote);
340 continue;
341 }
342
343 if(packet->qtype.getCode()==QType::IXFR) {
344 if(doIXFR(packet, fd))
345 incTCPAnswerCount(remote);
346 continue;
347 }
348
349 shared_ptr<DNSPacket> reply;
350 shared_ptr<DNSPacket> cached= shared_ptr<DNSPacket>(new DNSPacket(false));
351 if(logDNSQueries) {
352 string remote_text;
353 if(packet->hasEDNSSubnet())
354 remote_text = packet->getRemote().toString() + "<-" + packet->getRealRemote().toString();
355 else
356 remote_text = packet->getRemote().toString();
357 g_log << Logger::Notice<<"TCP Remote "<< remote_text <<" wants '" << packet->qdomain<<"|"<<packet->qtype.getName() <<
358 "', do = " <<packet->d_dnssecOk <<", bufsize = "<< packet->getMaxReplyLen()<<": ";
359 }
360
361
362 if(packet->couldBeCached() && PC.get(packet.get(), cached.get())) { // short circuit - does the PacketCache recognize this question?
363 if(logDNSQueries)
364 g_log<<"packetcache HIT"<<endl;
365 cached->setRemote(&packet->d_remote);
366 cached->d.id=packet->d.id;
367 cached->d.rd=packet->d.rd; // copy in recursion desired bit
368 cached->commitD(); // commit d to the packet inlined
369
370 sendPacket(cached, fd); // presigned, don't do it again
371 continue;
372 }
373 if(logDNSQueries)
374 g_log<<"packetcache MISS"<<endl;
375 {
376 Lock l(&s_plock);
377 if(!s_P) {
378 g_log<<Logger::Error<<"TCP server is without backend connections, launching"<<endl;
379 s_P=new PacketHandler;
380 }
381
382 reply=shared_ptr<DNSPacket>(s_P->doQuestion(packet.get())); // we really need to ask the backend :-)
383 }
384
385 if(!reply) // unable to write an answer?
386 break;
387
388 sendPacket(reply, fd);
389 }
390 }
391 catch(PDNSException &ae) {
392 Lock l(&s_plock);
393 delete s_P;
394 s_P = 0; // on next call, backend will be recycled
395 g_log<<Logger::Error<<"TCP nameserver had error, cycling backend: "<<ae.reason<<endl;
396 }
397 catch(NetworkError &e) {
398 g_log<<Logger::Info<<"TCP Connection Thread died because of network error: "<<e.what()<<endl;
399 }
400
401 catch(std::exception &e) {
402 g_log<<Logger::Error<<"TCP Connection Thread died because of STL error: "<<e.what()<<endl;
403 }
404 catch( ... )
405 {
406 g_log << Logger::Error << "TCP Connection Thread caught unknown exception." << endl;
407 }
408 d_connectionroom_sem->post();
409
410 try {
411 closesocket(fd);
412 }
413 catch(const PDNSException& e) {
414 g_log<<Logger::Error<<"Error closing TCP socket: "<<e.reason<<endl;
415 }
416 decrementClientCount(remote);
417
418 return 0;
419 }
420
421
422 // call this method with s_plock held!
423 bool TCPNameserver::canDoAXFR(shared_ptr<DNSPacket> q)
424 {
425 if(::arg().mustDo("disable-axfr"))
426 return false;
427
428 if(q->d_havetsig) { // if you have one, it must be good
429 TSIGRecordContent trc;
430 DNSName keyname;
431 string secret;
432 if(!q->checkForCorrectTSIG(s_P->getBackend(), &keyname, &secret, &trc)) {
433 return false;
434 } else {
435 getTSIGHashEnum(trc.d_algoName, q->d_tsig_algo);
436 if (q->d_tsig_algo == TSIG_GSS) {
437 GssContext gssctx(keyname);
438 if (!gssctx.getPeerPrincipal(q->d_peer_principal)) {
439 g_log<<Logger::Warning<<"Failed to extract peer principal from GSS context with keyname '"<<keyname<<"'"<<endl;
440 }
441 }
442 }
443
444 DNSSECKeeper dk(s_P->getBackend());
445
446 if (q->d_tsig_algo == TSIG_GSS) {
447 vector<string> princs;
448 s_P->getBackend()->getDomainMetadata(q->qdomain, "GSS-ALLOW-AXFR-PRINCIPAL", princs);
449 for(const std::string& princ : princs) {
450 if (q->d_peer_principal == princ) {
451 g_log<<Logger::Warning<<"AXFR of domain '"<<q->qdomain<<"' allowed: TSIG signed request with authorized principal '"<<q->d_peer_principal<<"' and algorithm 'gss-tsig'"<<endl;
452 return true;
453 }
454 }
455 g_log<<Logger::Warning<<"AXFR of domain '"<<q->qdomain<<"' denied: TSIG signed request with principal '"<<q->d_peer_principal<<"' and algorithm 'gss-tsig' is not permitted"<<endl;
456 return false;
457 }
458
459 if(!dk.TSIGGrantsAccess(q->qdomain, keyname)) {
460 g_log<<Logger::Error<<"AXFR '"<<q->qdomain<<"' denied: key with name '"<<keyname<<"' and algorithm '"<<getTSIGAlgoName(q->d_tsig_algo)<<"' does not grant access to zone"<<endl;
461 return false;
462 }
463 else {
464 g_log<<Logger::Warning<<"AXFR of domain '"<<q->qdomain<<"' allowed: TSIG signed request with authorized key '"<<keyname<<"' and algorithm '"<<getTSIGAlgoName(q->d_tsig_algo)<<"'"<<endl;
465 return true;
466 }
467 }
468
469 // cerr<<"checking allow-axfr-ips"<<endl;
470 if(!(::arg()["allow-axfr-ips"].empty()) && d_ng.match( (ComboAddress *) &q->d_remote )) {
471 g_log<<Logger::Warning<<"AXFR of domain '"<<q->qdomain<<"' allowed: client IP "<<q->getRemote()<<" is in allow-axfr-ips"<<endl;
472 return true;
473 }
474
475 FindNS fns;
476
477 // cerr<<"doing per-zone-axfr-acls"<<endl;
478 SOAData sd;
479 if(s_P->getBackend()->getSOAUncached(q->qdomain,sd)) {
480 // cerr<<"got backend and SOA"<<endl;
481 DNSBackend *B=sd.db;
482 vector<string> acl;
483 s_P->getBackend()->getDomainMetadata(q->qdomain, "ALLOW-AXFR-FROM", acl);
484 for (vector<string>::const_iterator i = acl.begin(); i != acl.end(); ++i) {
485 // cerr<<"matching against "<<*i<<endl;
486 if(pdns_iequals(*i, "AUTO-NS")) {
487 // cerr<<"AUTO-NS magic please!"<<endl;
488
489 DNSResourceRecord rr;
490 set<DNSName> nsset;
491
492 B->lookup(QType(QType::NS),q->qdomain);
493 while(B->get(rr))
494 nsset.insert(DNSName(rr.content));
495 for(const auto & j: nsset) {
496 vector<string> nsips=fns.lookup(j, s_P->getBackend());
497 for(vector<string>::const_iterator k=nsips.begin();k!=nsips.end();++k) {
498 // cerr<<"got "<<*k<<" from AUTO-NS"<<endl;
499 if(*k == q->getRemote().toString())
500 {
501 // cerr<<"got AUTO-NS hit"<<endl;
502 g_log<<Logger::Warning<<"AXFR of domain '"<<q->qdomain<<"' allowed: client IP "<<q->getRemote()<<" is in NSset"<<endl;
503 return true;
504 }
505 }
506 }
507 }
508 else
509 {
510 Netmask nm = Netmask(*i);
511 if(nm.match( (ComboAddress *) &q->d_remote ))
512 {
513 g_log<<Logger::Warning<<"AXFR of domain '"<<q->qdomain<<"' allowed: client IP "<<q->getRemote()<<" is in per-domain ACL"<<endl;
514 // cerr<<"hit!"<<endl;
515 return true;
516 }
517 }
518 }
519 }
520
521 extern CommunicatorClass Communicator;
522
523 if(Communicator.justNotified(q->qdomain, q->getRemote().toString())) { // we just notified this ip
524 g_log<<Logger::Warning<<"Approved AXFR of '"<<q->qdomain<<"' from recently notified slave "<<q->getRemote()<<endl;
525 return true;
526 }
527
528 g_log<<Logger::Error<<"AXFR of domain '"<<q->qdomain<<"' denied: client IP "<<q->getRemote()<<" has no permission"<<endl;
529 return false;
530 }
531
532 namespace {
533 struct NSECXEntry
534 {
535 NSECBitmap d_set;
536 unsigned int d_ttl;
537 bool d_auth;
538 };
539
540 DNSZoneRecord makeEditedDNSZRFromSOAData(DNSSECKeeper& dk, const SOAData& sd)
541 {
542 SOAData edited = sd;
543 edited.serial = calculateEditSOA(sd.serial, dk, sd.qname);
544
545 DNSRecord soa;
546 soa.d_name = sd.qname;
547 soa.d_type = QType::SOA;
548 soa.d_ttl = sd.ttl;
549 soa.d_place = DNSResourceRecord::ANSWER;
550 soa.d_content = makeSOAContent(edited);
551
552 DNSZoneRecord dzr;
553 dzr.auth = true;
554 dzr.dr = soa;
555
556 return dzr;
557 }
558
559 shared_ptr<DNSPacket> getFreshAXFRPacket(shared_ptr<DNSPacket> q)
560 {
561 shared_ptr<DNSPacket> ret = shared_ptr<DNSPacket>(q->replyPacket());
562 ret->setCompress(false);
563 ret->d_dnssecOk=false; // RFC 5936, 2.2.5
564 ret->d_tcp = true;
565 return ret;
566 }
567 }
568
569
570 /** do the actual zone transfer. Return 0 in case of error, 1 in case of success */
571 int TCPNameserver::doAXFR(const DNSName &target, shared_ptr<DNSPacket> q, int outsock)
572 {
573 shared_ptr<DNSPacket> outpacket= getFreshAXFRPacket(q);
574 if(q->d_dnssecOk)
575 outpacket->d_dnssecOk=true; // RFC 5936, 2.2.5 'SHOULD'
576
577 g_log<<Logger::Error<<"AXFR of domain '"<<target<<"' initiated by "<<q->getRemote()<<endl;
578
579 // determine if zone exists and AXFR is allowed using existing backend before spawning a new backend.
580 SOAData sd;
581 {
582 Lock l(&s_plock);
583 DLOG(g_log<<"Looking for SOA"<<endl); // find domain_id via SOA and list complete domain. No SOA, no AXFR
584 if(!s_P) {
585 g_log<<Logger::Error<<"TCP server is without backend connections in doAXFR, launching"<<endl;
586 s_P=new PacketHandler;
587 }
588
589 // canDoAXFR does all the ACL checks, and has the if(disable-axfr) shortcut, call it first.
590 if (!canDoAXFR(q)) {
591 g_log<<Logger::Error<<"AXFR of domain '"<<target<<"' failed: "<<q->getRemote()<<" may not request AXFR"<<endl;
592 outpacket->setRcode(RCode::NotAuth);
593 sendPacket(outpacket,outsock);
594 return 0;
595 }
596
597 if(!s_P->getBackend()->getSOAUncached(target, sd)) {
598 g_log<<Logger::Error<<"AXFR of domain '"<<target<<"' failed: not authoritative"<<endl;
599 outpacket->setRcode(RCode::NotAuth);
600 sendPacket(outpacket,outsock);
601 return 0;
602 }
603 }
604
605 UeberBackend db;
606 if(!db.getSOAUncached(target, sd)) {
607 g_log<<Logger::Error<<"AXFR of domain '"<<target<<"' failed: not authoritative in second instance"<<endl;
608 outpacket->setRcode(RCode::NotAuth);
609 sendPacket(outpacket,outsock);
610 return 0;
611 }
612
613 DNSSECKeeper dk(&db);
614 dk.clearCaches(target);
615 bool securedZone = dk.isSecuredZone(target);
616 bool presignedZone = dk.isPresigned(target);
617
618 bool noAXFRBecauseOfNSEC3Narrow=false;
619 NSEC3PARAMRecordContent ns3pr;
620 bool narrow;
621 bool NSEC3Zone=false;
622 if(securedZone && dk.getNSEC3PARAM(target, &ns3pr, &narrow)) {
623 NSEC3Zone=true;
624 if(narrow) {
625 g_log<<Logger::Error<<"Not doing AXFR of an NSEC3 narrow zone '"<<target<<"' for "<<q->getRemote()<<endl;
626 noAXFRBecauseOfNSEC3Narrow=true;
627 }
628 }
629
630 if(noAXFRBecauseOfNSEC3Narrow) {
631 g_log<<Logger::Error<<"AXFR of domain '"<<target<<"' denied to "<<q->getRemote()<<endl;
632 outpacket->setRcode(RCode::Refused);
633 // FIXME: should actually figure out if we are auth over a zone, and send out 9 if we aren't
634 sendPacket(outpacket,outsock);
635 return 0;
636 }
637
638 TSIGRecordContent trc;
639 DNSName tsigkeyname;
640 string tsigsecret;
641
642 bool haveTSIGDetails = q->getTSIGDetails(&trc, &tsigkeyname);
643
644 if(haveTSIGDetails && !tsigkeyname.empty()) {
645 string tsig64;
646 DNSName algorithm=trc.d_algoName; // FIXME400: check
647 if (algorithm == DNSName("hmac-md5.sig-alg.reg.int"))
648 algorithm = DNSName("hmac-md5");
649 if (algorithm != DNSName("gss-tsig")) {
650 if(!db.getTSIGKey(tsigkeyname, &algorithm, &tsig64)) {
651 g_log<<Logger::Error<<"TSIG key '"<<tsigkeyname<<"' for domain '"<<target<<"' not found"<<endl;
652 return 0;
653 }
654 if (B64Decode(tsig64, tsigsecret) == -1) {
655 g_log<<Logger::Error<<"Unable to Base-64 decode TSIG key '"<<tsigkeyname<<"' for domain '"<<target<<"'"<<endl;
656 return 0;
657 }
658 }
659 }
660
661
662 // SOA *must* go out first, our signing pipe might reorder
663 DLOG(g_log<<"Sending out SOA"<<endl);
664 DNSZoneRecord soa = makeEditedDNSZRFromSOAData(dk, sd);
665 outpacket->addRecord(soa);
666 if(securedZone && !presignedZone) {
667 set<DNSName> authSet;
668 authSet.insert(target);
669 addRRSigs(dk, db, authSet, outpacket->getRRS());
670 }
671
672 if(haveTSIGDetails && !tsigkeyname.empty())
673 outpacket->setTSIGDetails(trc, tsigkeyname, tsigsecret, trc.d_mac); // first answer is 'normal'
674
675 sendPacket(outpacket, outsock);
676
677 trc.d_mac = outpacket->d_trc.d_mac;
678 outpacket = getFreshAXFRPacket(q);
679
680 ChunkedSigningPipe csp(target, (securedZone && !presignedZone), ::arg().asNum("signing-threads", 1));
681
682 typedef map<DNSName, NSECXEntry, CanonDNSNameCompare> nsecxrepo_t;
683 nsecxrepo_t nsecxrepo;
684
685 // this is where the DNSKEYs go in
686
687 DNSSECKeeper::keyset_t keys = dk.getKeys(target);
688
689 DNSZoneRecord zrr;
690
691 zrr.dr.d_name = target;
692 zrr.dr.d_ttl = sd.default_ttl;
693 zrr.auth = 1; // please sign!
694
695 string publishCDNSKEY, publishCDS;
696 dk.getFromMeta(q->qdomain, "PUBLISH-CDNSKEY", publishCDNSKEY);
697 dk.getFromMeta(q->qdomain, "PUBLISH-CDS", publishCDS);
698 vector<DNSZoneRecord> cds, cdnskey;
699 DNSSECKeeper::keyset_t entryPoints = dk.getEntryPoints(q->qdomain);
700 set<uint32_t> entryPointIds;
701 for (auto const& value : entryPoints)
702 entryPointIds.insert(value.second.id);
703
704 for(const DNSSECKeeper::keyset_t::value_type& value : keys) {
705 zrr.dr.d_type = QType::DNSKEY;
706 zrr.dr.d_content = std::make_shared<DNSKEYRecordContent>(value.first.getDNSKEY());
707 DNSName keyname = NSEC3Zone ? DNSName(toBase32Hex(hashQNameWithSalt(ns3pr, zrr.dr.d_name))) : zrr.dr.d_name;
708 NSECXEntry& ne = nsecxrepo[keyname];
709
710 ne.d_set.set(zrr.dr.d_type);
711 ne.d_ttl = sd.default_ttl;
712 csp.submit(zrr);
713
714 // generate CDS and CDNSKEY records
715 if(entryPointIds.count(value.second.id) > 0){
716 if(publishCDNSKEY == "1") {
717 zrr.dr.d_type=QType::CDNSKEY;
718 zrr.dr.d_content = std::make_shared<DNSKEYRecordContent>(value.first.getDNSKEY());
719 cdnskey.push_back(zrr);
720 }
721
722 if(!publishCDS.empty()){
723 zrr.dr.d_type=QType::CDS;
724 vector<string> digestAlgos;
725 stringtok(digestAlgos, publishCDS, ", ");
726 for(auto const &digestAlgo : digestAlgos) {
727 zrr.dr.d_content=std::make_shared<DSRecordContent>(makeDSFromDNSKey(target, value.first.getDNSKEY(), pdns_stou(digestAlgo)));
728 cds.push_back(zrr);
729 }
730 }
731 }
732 }
733
734 if(::arg().mustDo("direct-dnskey")) {
735 sd.db->lookup(QType(QType::DNSKEY), target, NULL, sd.domain_id);
736 while(sd.db->get(zrr)) {
737 zrr.dr.d_ttl = sd.default_ttl;
738 csp.submit(zrr);
739 }
740 }
741
742 uint8_t flags;
743
744 if(NSEC3Zone) { // now stuff in the NSEC3PARAM
745 flags = ns3pr.d_flags;
746 zrr.dr.d_type = QType::NSEC3PARAM;
747 ns3pr.d_flags = 0;
748 zrr.dr.d_content = std::make_shared<NSEC3PARAMRecordContent>(ns3pr);
749 ns3pr.d_flags = flags;
750 DNSName keyname = DNSName(toBase32Hex(hashQNameWithSalt(ns3pr, zrr.dr.d_name)));
751 NSECXEntry& ne = nsecxrepo[keyname];
752
753 ne.d_set.set(zrr.dr.d_type);
754 csp.submit(zrr);
755 }
756
757 // now start list zone
758 if(!(sd.db->list(target, sd.domain_id))) {
759 g_log<<Logger::Error<<"Backend signals error condition"<<endl;
760 outpacket->setRcode(RCode::ServFail);
761 sendPacket(outpacket,outsock);
762 return 0;
763 }
764
765
766 const bool rectify = !(presignedZone || ::arg().mustDo("disable-axfr-rectify"));
767 set<DNSName> qnames, nsset, terms;
768 vector<DNSZoneRecord> zrrs;
769
770 // Add the CDNSKEY and CDS records we created earlier
771 for (auto const &synth_zrr : cds)
772 zrrs.push_back(synth_zrr);
773
774 for (auto const &synth_zrr : cdnskey)
775 zrrs.push_back(synth_zrr);
776
777 while(sd.db->get(zrr)) {
778 zrr.dr.d_name.makeUsLowerCase();
779 if(zrr.dr.d_name.isPartOf(target)) {
780 if (zrr.dr.d_type == QType::ALIAS && ::arg().mustDo("outgoing-axfr-expand-alias")) {
781 vector<DNSZoneRecord> ips;
782 int ret1 = stubDoResolve(getRR<ALIASRecordContent>(zrr.dr)->d_content, QType::A, ips);
783 int ret2 = stubDoResolve(getRR<ALIASRecordContent>(zrr.dr)->d_content, QType::AAAA, ips);
784 if(ret1 != RCode::NoError || ret2 != RCode::NoError) {
785 g_log<<Logger::Error<<"Error resolving for ALIAS "<<zrr.dr.d_content->getZoneRepresentation()<<", aborting AXFR"<<endl;
786 outpacket->setRcode(RCode::ServFail);
787 sendPacket(outpacket,outsock);
788 return 0;
789 }
790 for(const auto& ip: ips) {
791 zrr.dr.d_type = ip.dr.d_type;
792 zrr.dr.d_content = ip.dr.d_content;
793 zrrs.push_back(zrr);
794 }
795 continue;
796 }
797
798 if (rectify) {
799 if (zrr.dr.d_type) {
800 qnames.insert(zrr.dr.d_name);
801 if(zrr.dr.d_type == QType::NS && zrr.dr.d_name!=target)
802 nsset.insert(zrr.dr.d_name);
803 } else {
804 // remove existing ents
805 continue;
806 }
807 }
808 zrrs.push_back(zrr);
809 } else {
810 if (zrr.dr.d_type)
811 g_log<<Logger::Warning<<"Zone '"<<target<<"' contains out-of-zone data '"<<zrr.dr.d_name<<"|"<<DNSRecordContent::NumberToType(zrr.dr.d_type)<<"', ignoring"<<endl;
812 }
813 }
814
815 // Group records by name and type, signpipe stumbles over interrupted rrsets
816 if(securedZone && !presignedZone) {
817 sort(zrrs.begin(), zrrs.end(), [](const DNSZoneRecord& a, const DNSZoneRecord& b) {
818 return tie(a.dr.d_name, a.dr.d_type) < tie(b.dr.d_name, b.dr.d_type);
819 });
820 }
821
822 if(rectify) {
823 // set auth
824 for(DNSZoneRecord &loopZRR : zrrs) {
825 loopZRR.auth=true;
826 if (loopZRR.dr.d_type != QType::NS || loopZRR.dr.d_name!=target) {
827 DNSName shorter(loopZRR.dr.d_name);
828 do {
829 if (shorter==target) // apex is always auth
830 break;
831 if(nsset.count(shorter) && !(loopZRR.dr.d_name==shorter && loopZRR.dr.d_type == QType::DS)) {
832 loopZRR.auth=false;
833 break;
834 }
835 } while(shorter.chopOff());
836 }
837 }
838
839 if(NSEC3Zone) {
840 // ents are only required for NSEC3 zones
841 uint32_t maxent = ::arg().asNum("max-ent-entries");
842 set<DNSName> nsec3set, nonterm;
843 for (auto &loopZRR: zrrs) {
844 bool skip=false;
845 DNSName shorter = loopZRR.dr.d_name;
846 if (shorter != target && shorter.chopOff() && shorter != target) {
847 do {
848 if(nsset.count(shorter)) {
849 skip=true;
850 break;
851 }
852 } while(shorter.chopOff() && shorter != target);
853 }
854 shorter = loopZRR.dr.d_name;
855 if(!skip && (loopZRR.dr.d_type != QType::NS || !ns3pr.d_flags)) {
856 do {
857 if(!nsec3set.count(shorter)) {
858 nsec3set.insert(shorter);
859 }
860 } while(shorter != target && shorter.chopOff());
861 }
862 }
863
864 for(DNSZoneRecord &loopZRR : zrrs) {
865 DNSName shorter(loopZRR.dr.d_name);
866 while(shorter != target && shorter.chopOff()) {
867 if(!qnames.count(shorter) && !nonterm.count(shorter) && nsec3set.count(shorter)) {
868 if(!(maxent)) {
869 g_log<<Logger::Warning<<"Zone '"<<target<<"' has too many empty non terminals."<<endl;
870 return 0;
871 }
872 nonterm.insert(shorter);
873 --maxent;
874 }
875 }
876 }
877
878 for(const auto& nt : nonterm) {
879 DNSZoneRecord tempRR;
880 tempRR.dr.d_name=nt;
881 tempRR.dr.d_type=QType::ENT;
882 tempRR.auth=true;
883 zrrs.push_back(tempRR);
884 }
885 }
886 }
887
888
889 /* now write all other records */
890
891 DNSName keyname;
892 unsigned int udiff;
893 DTime dt;
894 dt.set();
895 int records=0;
896 for(DNSZoneRecord &loopZRR : zrrs) {
897 if (!presignedZone && loopZRR.dr.d_type == QType::RRSIG)
898 continue;
899
900 // only skip the DNSKEY, CDNSKEY and CDS if direct-dnskey is enabled, to avoid changing behaviour
901 // when it is not enabled.
902 if(::arg().mustDo("direct-dnskey") && (loopZRR.dr.d_type == QType::DNSKEY || loopZRR.dr.d_type == QType::CDNSKEY || loopZRR.dr.d_type == QType::CDS))
903 continue;
904
905 records++;
906 if(securedZone && (loopZRR.auth || loopZRR.dr.d_type == QType::NS)) {
907 if (NSEC3Zone || loopZRR.dr.d_type) {
908 if (presignedZone && NSEC3Zone && loopZRR.dr.d_type == QType::RRSIG && getRR<RRSIGRecordContent>(loopZRR.dr)->d_type == QType::NSEC3) {
909 keyname = loopZRR.dr.d_name.makeRelative(sd.qname);
910 } else {
911 keyname = NSEC3Zone ? DNSName(toBase32Hex(hashQNameWithSalt(ns3pr, loopZRR.dr.d_name))) : loopZRR.dr.d_name;
912 }
913 NSECXEntry& ne = nsecxrepo[keyname];
914 ne.d_ttl = sd.default_ttl;
915 ne.d_auth = (ne.d_auth || loopZRR.auth || (NSEC3Zone && (!ns3pr.d_flags)));
916 if (loopZRR.dr.d_type && loopZRR.dr.d_type != QType::RRSIG) {
917 ne.d_set.set(loopZRR.dr.d_type);
918 }
919 }
920 }
921
922 if (!loopZRR.dr.d_type)
923 continue; // skip empty non-terminals
924
925 if(loopZRR.dr.d_type == QType::SOA)
926 continue; // skip SOA - would indicate end of AXFR
927
928 if(csp.submit(loopZRR)) {
929 for(;;) {
930 outpacket->getRRS() = csp.getChunk();
931 if(!outpacket->getRRS().empty()) {
932 if(haveTSIGDetails && !tsigkeyname.empty())
933 outpacket->setTSIGDetails(trc, tsigkeyname, tsigsecret, trc.d_mac, true);
934 sendPacket(outpacket, outsock);
935 trc.d_mac=outpacket->d_trc.d_mac;
936 outpacket=getFreshAXFRPacket(q);
937 }
938 else
939 break;
940 }
941 }
942 }
943 /*
944 udiff=dt.udiffNoReset();
945 cerr<<"Starting NSEC: "<<csp.d_signed/(udiff/1000000.0)<<" sigs/s, "<<csp.d_signed<<" / "<<udiff/1000000.0<<endl;
946 cerr<<"Outstanding: "<<csp.d_outstanding<<", "<<csp.d_queued - csp.d_signed << endl;
947 cerr<<"Ready for consumption: "<<csp.getReady()<<endl;
948 */
949 if(securedZone) {
950 if(NSEC3Zone) {
951 for(nsecxrepo_t::const_iterator iter = nsecxrepo.begin(); iter != nsecxrepo.end(); ++iter) {
952 if(iter->second.d_auth) {
953 NSEC3RecordContent n3rc;
954 n3rc.set(iter->second.d_set);
955 const auto numberOfTypesSet = n3rc.numberOfTypesSet();
956 if (numberOfTypesSet != 0 && (numberOfTypesSet != 1 || !n3rc.isSet(QType::NS))) {
957 n3rc.set(QType::RRSIG);
958 }
959 n3rc.d_salt = ns3pr.d_salt;
960 n3rc.d_flags = ns3pr.d_flags;
961 n3rc.d_iterations = ns3pr.d_iterations;
962 n3rc.d_algorithm = DNSSECKeeper::SHA1; // SHA1, fixed in PowerDNS for now
963 nsecxrepo_t::const_iterator inext = iter;
964 ++inext;
965 if(inext == nsecxrepo.end())
966 inext = nsecxrepo.begin();
967 while(!inext->second.d_auth && inext != iter)
968 {
969 ++inext;
970 if(inext == nsecxrepo.end())
971 inext = nsecxrepo.begin();
972 }
973 n3rc.d_nexthash = fromBase32Hex(inext->first.toStringNoDot());
974 zrr.dr.d_name = iter->first+sd.qname;
975
976 zrr.dr.d_ttl = sd.default_ttl;
977 zrr.dr.d_content = std::make_shared<NSEC3RecordContent>(std::move(n3rc));
978 zrr.dr.d_type = QType::NSEC3;
979 zrr.dr.d_place = DNSResourceRecord::ANSWER;
980 zrr.auth=true;
981 if(csp.submit(zrr)) {
982 for(;;) {
983 outpacket->getRRS() = csp.getChunk();
984 if(!outpacket->getRRS().empty()) {
985 if(haveTSIGDetails && !tsigkeyname.empty())
986 outpacket->setTSIGDetails(trc, tsigkeyname, tsigsecret, trc.d_mac, true);
987 sendPacket(outpacket, outsock);
988 trc.d_mac=outpacket->d_trc.d_mac;
989 outpacket=getFreshAXFRPacket(q);
990 }
991 else
992 break;
993 }
994 }
995 }
996 }
997 }
998 else for(nsecxrepo_t::const_iterator iter = nsecxrepo.begin(); iter != nsecxrepo.end(); ++iter) {
999 NSECRecordContent nrc;
1000 nrc.set(iter->second.d_set);
1001 nrc.set(QType::RRSIG);
1002 nrc.set(QType::NSEC);
1003
1004 if(boost::next(iter) != nsecxrepo.end())
1005 nrc.d_next = boost::next(iter)->first;
1006 else
1007 nrc.d_next=nsecxrepo.begin()->first;
1008 zrr.dr.d_name = iter->first;
1009
1010 zrr.dr.d_ttl = sd.default_ttl;
1011 zrr.dr.d_content = std::make_shared<NSECRecordContent>(std::move(nrc));
1012 zrr.dr.d_type = QType::NSEC;
1013 zrr.dr.d_place = DNSResourceRecord::ANSWER;
1014 zrr.auth=true;
1015 if(csp.submit(zrr)) {
1016 for(;;) {
1017 outpacket->getRRS() = csp.getChunk();
1018 if(!outpacket->getRRS().empty()) {
1019 if(haveTSIGDetails && !tsigkeyname.empty())
1020 outpacket->setTSIGDetails(trc, tsigkeyname, tsigsecret, trc.d_mac, true);
1021 sendPacket(outpacket, outsock);
1022 trc.d_mac=outpacket->d_trc.d_mac;
1023 outpacket=getFreshAXFRPacket(q);
1024 }
1025 else
1026 break;
1027 }
1028 }
1029 }
1030 }
1031 /*
1032 udiff=dt.udiffNoReset();
1033 cerr<<"Flushing pipe: "<<csp.d_signed/(udiff/1000000.0)<<" sigs/s, "<<csp.d_signed<<" / "<<udiff/1000000.0<<endl;
1034 cerr<<"Outstanding: "<<csp.d_outstanding<<", "<<csp.d_queued - csp.d_signed << endl;
1035 cerr<<"Ready for consumption: "<<csp.getReady()<<endl;
1036 * */
1037 for(;;) {
1038 outpacket->getRRS() = csp.getChunk(true); // flush the pipe
1039 if(!outpacket->getRRS().empty()) {
1040 if(haveTSIGDetails && !tsigkeyname.empty())
1041 outpacket->setTSIGDetails(trc, tsigkeyname, tsigsecret, trc.d_mac, true); // first answer is 'normal'
1042 sendPacket(outpacket, outsock);
1043 trc.d_mac=outpacket->d_trc.d_mac;
1044 outpacket=getFreshAXFRPacket(q);
1045 }
1046 else
1047 break;
1048 }
1049
1050 udiff=dt.udiffNoReset();
1051 if(securedZone)
1052 g_log<<Logger::Info<<"Done signing: "<<csp.d_signed/(udiff/1000000.0)<<" sigs/s, "<<endl;
1053
1054 DLOG(g_log<<"Done writing out records"<<endl);
1055 /* and terminate with yet again the SOA record */
1056 outpacket=getFreshAXFRPacket(q);
1057 outpacket->addRecord(soa);
1058 if(haveTSIGDetails && !tsigkeyname.empty())
1059 outpacket->setTSIGDetails(trc, tsigkeyname, tsigsecret, trc.d_mac, true);
1060
1061 sendPacket(outpacket, outsock);
1062
1063 DLOG(g_log<<"last packet - close"<<endl);
1064 g_log<<Logger::Error<<"AXFR of domain '"<<target<<"' to "<<q->getRemote()<<" finished"<<endl;
1065
1066 return 1;
1067 }
1068
1069 int TCPNameserver::doIXFR(shared_ptr<DNSPacket> q, int outsock)
1070 {
1071 shared_ptr<DNSPacket> outpacket=getFreshAXFRPacket(q);
1072 if(q->d_dnssecOk)
1073 outpacket->d_dnssecOk=true; // RFC 5936, 2.2.5 'SHOULD'
1074
1075 uint32_t serial = 0;
1076 MOADNSParser mdp(false, q->getString());
1077 for(MOADNSParser::answers_t::const_iterator i=mdp.d_answers.begin(); i != mdp.d_answers.end(); ++i) {
1078 const DNSRecord *rr = &i->first;
1079 if (rr->d_type == QType::SOA && rr->d_place == DNSResourceRecord::AUTHORITY) {
1080 vector<string>parts;
1081 stringtok(parts, rr->d_content->getZoneRepresentation());
1082 if (parts.size() >= 3) {
1083 try {
1084 serial=pdns_stou(parts[2]);
1085 }
1086 catch(const std::out_of_range& oor) {
1087 g_log<<Logger::Error<<"Invalid serial in IXFR query"<<endl;
1088 outpacket->setRcode(RCode::FormErr);
1089 sendPacket(outpacket,outsock);
1090 return 0;
1091 }
1092 } else {
1093 g_log<<Logger::Error<<"No serial in IXFR query"<<endl;
1094 outpacket->setRcode(RCode::FormErr);
1095 sendPacket(outpacket,outsock);
1096 return 0;
1097 }
1098 } else if (rr->d_type != QType::TSIG && rr->d_type != QType::OPT) {
1099 g_log<<Logger::Error<<"Additional records in IXFR query, type: "<<QType(rr->d_type).getName()<<endl;
1100 outpacket->setRcode(RCode::FormErr);
1101 sendPacket(outpacket,outsock);
1102 return 0;
1103 }
1104 }
1105
1106 g_log<<Logger::Error<<"IXFR of domain '"<<q->qdomain<<"' initiated by "<<q->getRemote()<<" with serial "<<serial<<endl;
1107
1108 // determine if zone exists and AXFR is allowed using existing backend before spawning a new backend.
1109 SOAData sd;
1110 {
1111 Lock l(&s_plock);
1112 DLOG(g_log<<"Looking for SOA"<<endl); // find domain_id via SOA and list complete domain. No SOA, no IXFR
1113 if(!s_P) {
1114 g_log<<Logger::Error<<"TCP server is without backend connections in doIXFR, launching"<<endl;
1115 s_P=new PacketHandler;
1116 }
1117
1118 // canDoAXFR does all the ACL checks, and has the if(disable-axfr) shortcut, call it first.
1119 if(!canDoAXFR(q) || !s_P->getBackend()->getSOAUncached(q->qdomain, sd)) {
1120 g_log<<Logger::Error<<"IXFR of domain '"<<q->qdomain<<"' failed: not authoritative"<<endl;
1121 outpacket->setRcode(RCode::NotAuth);
1122 sendPacket(outpacket,outsock);
1123 return 0;
1124 }
1125 }
1126
1127 DNSSECKeeper dk;
1128 NSEC3PARAMRecordContent ns3pr;
1129 bool narrow;
1130
1131 dk.clearCaches(q->qdomain);
1132 bool securedZone = dk.isSecuredZone(q->qdomain);
1133 if(dk.getNSEC3PARAM(q->qdomain, &ns3pr, &narrow)) {
1134 if(narrow) {
1135 g_log<<Logger::Error<<"Not doing IXFR of an NSEC3 narrow zone."<<endl;
1136 g_log<<Logger::Error<<"IXFR of domain '"<<q->qdomain<<"' denied to "<<q->getRemote()<<endl;
1137 outpacket->setRcode(RCode::Refused);
1138 sendPacket(outpacket,outsock);
1139 return 0;
1140 }
1141 }
1142
1143 DNSName target = q->qdomain;
1144
1145 UeberBackend db;
1146 if(!db.getSOAUncached(target, sd)) {
1147 g_log<<Logger::Error<<"IXFR of domain '"<<target<<"' failed: not authoritative in second instance"<<endl;
1148 outpacket->setRcode(RCode::NotAuth);
1149 sendPacket(outpacket,outsock);
1150 return 0;
1151 }
1152
1153 if (!rfc1982LessThan(serial, calculateEditSOA(sd.serial, dk, sd.qname))) {
1154 TSIGRecordContent trc;
1155 DNSName tsigkeyname;
1156 string tsigsecret;
1157
1158 bool haveTSIGDetails = q->getTSIGDetails(&trc, &tsigkeyname);
1159
1160 if(haveTSIGDetails && !tsigkeyname.empty()) {
1161 string tsig64;
1162 DNSName algorithm=trc.d_algoName; // FIXME400: was toLowerCanonic, compare output
1163 if (algorithm == DNSName("hmac-md5.sig-alg.reg.int"))
1164 algorithm = DNSName("hmac-md5");
1165 Lock l(&s_plock);
1166 if(!s_P->getBackend()->getTSIGKey(tsigkeyname, &algorithm, &tsig64)) {
1167 g_log<<Logger::Error<<"TSIG key '"<<tsigkeyname<<"' for domain '"<<target<<"' not found"<<endl;
1168 return 0;
1169 }
1170 if (B64Decode(tsig64, tsigsecret) == -1) {
1171 g_log<<Logger::Error<<"Unable to Base-64 decode TSIG key '"<<tsigkeyname<<"' for domain '"<<target<<"'"<<endl;
1172 return 0;
1173 }
1174 }
1175
1176 UeberBackend signatureDB;
1177
1178 // SOA *must* go out first, our signing pipe might reorder
1179 DLOG(g_log<<"Sending out SOA"<<endl);
1180 DNSZoneRecord soa = makeEditedDNSZRFromSOAData(dk, sd);
1181 outpacket->addRecord(soa);
1182 if(securedZone) {
1183 set<DNSName> authSet;
1184 authSet.insert(target);
1185 addRRSigs(dk, signatureDB, authSet, outpacket->getRRS());
1186 }
1187
1188 if(haveTSIGDetails && !tsigkeyname.empty())
1189 outpacket->setTSIGDetails(trc, tsigkeyname, tsigsecret, trc.d_mac); // first answer is 'normal'
1190
1191 sendPacket(outpacket, outsock);
1192
1193 g_log<<Logger::Error<<"IXFR of domain '"<<target<<"' to "<<q->getRemote()<<" finished"<<endl;
1194
1195 return 1;
1196 }
1197
1198 g_log<<Logger::Error<<"IXFR fallback to AXFR for domain '"<<target<<"' our serial "<<sd.serial<<endl;
1199 return doAXFR(q->qdomain, q, outsock);
1200 }
1201
1202 TCPNameserver::~TCPNameserver()
1203 {
1204 delete d_connectionroom_sem;
1205 }
1206
1207 TCPNameserver::TCPNameserver()
1208 {
1209 d_maxTransactionsPerConn = ::arg().asNum("max-tcp-transactions-per-conn");
1210 d_idleTimeout = ::arg().asNum("tcp-idle-timeout");
1211 d_maxConnectionDuration = ::arg().asNum("max-tcp-connection-duration");
1212 d_maxConnectionsPerClient = ::arg().asNum("max-tcp-connections-per-client");
1213
1214 // sem_init(&d_connectionroom_sem,0,::arg().asNum("max-tcp-connections"));
1215 d_connectionroom_sem = new Semaphore( ::arg().asNum( "max-tcp-connections" ));
1216 d_tid=0;
1217 vector<string>locals;
1218 stringtok(locals,::arg()["local-address"]," ,");
1219
1220 vector<string>locals6;
1221 stringtok(locals6,::arg()["local-ipv6"]," ,");
1222
1223 if(locals.empty() && locals6.empty())
1224 throw PDNSException("No local address specified");
1225
1226 d_ng.toMasks(::arg()["allow-axfr-ips"] );
1227
1228 signal(SIGPIPE,SIG_IGN);
1229
1230 for(vector<string>::const_iterator laddr=locals.begin();laddr!=locals.end();++laddr) {
1231 int s=socket(AF_INET,SOCK_STREAM,0);
1232
1233 if(s<0)
1234 throw PDNSException("Unable to acquire TCP socket: "+stringerror());
1235
1236 setCloseOnExec(s);
1237
1238 ComboAddress local(*laddr, ::arg().asNum("local-port"));
1239
1240 int tmp=1;
1241 if(setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(char*)&tmp,sizeof tmp)<0) {
1242 g_log<<Logger::Error<<"Setsockopt failed"<<endl;
1243 _exit(1);
1244 }
1245
1246 if (::arg().asNum("tcp-fast-open") > 0) {
1247 #ifdef TCP_FASTOPEN
1248 int fastOpenQueueSize = ::arg().asNum("tcp-fast-open");
1249 if (setsockopt(s, IPPROTO_TCP, TCP_FASTOPEN, &fastOpenQueueSize, sizeof fastOpenQueueSize) < 0) {
1250 g_log<<Logger::Error<<"Failed to enable TCP Fast Open for listening socket: "<<strerror(errno)<<endl;
1251 }
1252 #else
1253 g_log<<Logger::Warning<<"TCP Fast Open configured but not supported for listening socket"<<endl;
1254 #endif
1255 }
1256
1257 if( ::arg().mustDo("non-local-bind") )
1258 Utility::setBindAny(AF_INET, s);
1259
1260 if(::bind(s, (sockaddr*)&local, local.getSocklen())<0) {
1261 close(s);
1262 if( errno == EADDRNOTAVAIL && ! ::arg().mustDo("local-address-nonexist-fail") ) {
1263 g_log<<Logger::Error<<"IPv4 Address " << *laddr << " does not exist on this server - skipping TCP bind" << endl;
1264 continue;
1265 } else {
1266 g_log<<Logger::Error<<"Unable to bind to TCP socket " << *laddr << ": "<<strerror(errno)<<endl;
1267 throw PDNSException("Unable to bind to TCP socket");
1268 }
1269 }
1270
1271 listen(s,128);
1272 g_log<<Logger::Error<<"TCP server bound to "<<local.toStringWithPort()<<endl;
1273 d_sockets.push_back(s);
1274 struct pollfd pfd;
1275 memset(&pfd, 0, sizeof(pfd));
1276 pfd.fd = s;
1277 pfd.events = POLLIN;
1278
1279 d_prfds.push_back(pfd);
1280 }
1281
1282 for(vector<string>::const_iterator laddr=locals6.begin();laddr!=locals6.end();++laddr) {
1283 int s=socket(AF_INET6,SOCK_STREAM,0);
1284
1285 if(s<0)
1286 throw PDNSException("Unable to acquire TCPv6 socket: "+stringerror());
1287
1288 setCloseOnExec(s);
1289
1290 ComboAddress local(*laddr, ::arg().asNum("local-port"));
1291
1292 int tmp=1;
1293 if(setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(char*)&tmp,sizeof tmp)<0) {
1294 g_log<<Logger::Error<<"Setsockopt failed"<<endl;
1295 _exit(1);
1296 }
1297
1298 if (::arg().asNum("tcp-fast-open") > 0) {
1299 #ifdef TCP_FASTOPEN
1300 int fastOpenQueueSize = ::arg().asNum("tcp-fast-open");
1301 if (setsockopt(s, IPPROTO_TCP, TCP_FASTOPEN, &fastOpenQueueSize, sizeof fastOpenQueueSize) < 0) {
1302 g_log<<Logger::Error<<"Failed to enable TCP Fast Open for listening socket: "<<strerror(errno)<<endl;
1303 }
1304 #else
1305 g_log<<Logger::Warning<<"TCP Fast Open configured but not supported for listening socket"<<endl;
1306 #endif
1307 }
1308
1309 if( ::arg().mustDo("non-local-bind") )
1310 Utility::setBindAny(AF_INET6, s);
1311 if(setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &tmp, sizeof(tmp)) < 0) {
1312 g_log<<Logger::Error<<"Failed to set IPv6 socket to IPv6 only, continuing anyhow: "<<strerror(errno)<<endl;
1313 }
1314 if(bind(s, (const sockaddr*)&local, local.getSocklen())<0) {
1315 close(s);
1316 if( errno == EADDRNOTAVAIL && ! ::arg().mustDo("local-ipv6-nonexist-fail") ) {
1317 g_log<<Logger::Error<<"IPv6 Address " << *laddr << " does not exist on this server - skipping TCP bind" << endl;
1318 continue;
1319 } else {
1320 g_log<<Logger::Error<<"Unable to bind to TCPv6 socket" << *laddr << ": "<<strerror(errno)<<endl;
1321 throw PDNSException("Unable to bind to TCPv6 socket");
1322 }
1323 }
1324
1325 listen(s,128);
1326 g_log<<Logger::Error<<"TCPv6 server bound to "<<local.toStringWithPort()<<endl; // this gets %eth0 right
1327 d_sockets.push_back(s);
1328
1329 struct pollfd pfd;
1330 memset(&pfd, 0, sizeof(pfd));
1331 pfd.fd = s;
1332 pfd.events = POLLIN;
1333
1334 d_prfds.push_back(pfd);
1335 }
1336 }
1337
1338
1339 //! Start of TCP operations thread, we launch a new thread for each incoming TCP question
1340 void TCPNameserver::thread()
1341 {
1342 setThreadName("pdns/tcpnameser");
1343 try {
1344 for(;;) {
1345 int fd;
1346 ComboAddress remote;
1347 Utility::socklen_t addrlen=remote.getSocklen();
1348
1349 int ret=poll(&d_prfds[0], d_prfds.size(), -1); // blocks, forever if need be
1350 if(ret <= 0)
1351 continue;
1352
1353 int sock=-1;
1354 for(const pollfd& pfd : d_prfds) {
1355 if(pfd.revents == POLLIN) {
1356 sock = pfd.fd;
1357 remote.sin4.sin_family = AF_INET6;
1358 addrlen=remote.getSocklen();
1359
1360 if((fd=accept(sock, (sockaddr*)&remote, &addrlen))<0) {
1361 g_log<<Logger::Error<<"TCP question accept error: "<<strerror(errno)<<endl;
1362
1363 if(errno==EMFILE) {
1364 g_log<<Logger::Error<<"TCP handler out of filedescriptors, exiting, won't recover from this"<<endl;
1365 _exit(1);
1366 }
1367 }
1368 else {
1369 if (d_maxConnectionsPerClient) {
1370 std::lock_guard<std::mutex> lock(s_clientsCountMutex);
1371 if (s_clientsCount[remote] >= d_maxConnectionsPerClient) {
1372 g_log<<Logger::Notice<<"Limit of simultaneous TCP connections per client reached for "<< remote<<", dropping"<<endl;
1373 close(fd);
1374 continue;
1375 }
1376 s_clientsCount[remote]++;
1377 }
1378
1379 pthread_t tid;
1380 d_connectionroom_sem->wait(); // blocks if no connections are available
1381
1382 int room;
1383 d_connectionroom_sem->getValue( &room);
1384 if(room<1)
1385 g_log<<Logger::Warning<<"Limit of simultaneous TCP connections reached - raise max-tcp-connections"<<endl;
1386
1387 if(pthread_create(&tid, 0, &doConnection, reinterpret_cast<void*>(fd))) {
1388 g_log<<Logger::Error<<"Error creating thread: "<<stringerror()<<endl;
1389 d_connectionroom_sem->post();
1390 close(fd);
1391 decrementClientCount(remote);
1392 }
1393 }
1394 }
1395 }
1396 }
1397 }
1398 catch(PDNSException &AE) {
1399 g_log<<Logger::Error<<"TCP Nameserver thread dying because of fatal error: "<<AE.reason<<endl;
1400 }
1401 catch(...) {
1402 g_log<<Logger::Error<<"TCPNameserver dying because of an unexpected fatal error"<<endl;
1403 }
1404 _exit(1); // take rest of server with us
1405 }
1406
1407