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