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