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