]> git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/tcpreceiver.cc
Merge pull request #14242 from rgacogne/fix-ixfrdist-uid-gid
[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<time_t>(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 packet->d_xfr=true;
371 doAXFR(packet->qdomain, packet, fd);
372 continue;
373 }
374
375 if(packet->qtype.getCode()==QType::IXFR) {
376 packet->d_xfr=true;
377 doIXFR(packet, fd);
378 continue;
379 }
380
381 std::unique_ptr<DNSPacket> reply;
382 auto cached = make_unique<DNSPacket>(false);
383 if(logDNSQueries) {
384 g_log << Logger::Notice<<"TCP Remote "<< packet->getRemoteString() <<" wants '" << packet->qdomain<<"|"<<packet->qtype.toString() <<
385 "', do = " <<packet->d_dnssecOk <<", bufsize = "<< packet->getMaxReplyLen();
386 }
387
388 if(PC.enabled()) {
389 if(packet->couldBeCached() && PC.get(*packet, *cached)) { // short circuit - does the PacketCache recognize this question?
390 if(logDNSQueries)
391 g_log<<": packetcache HIT"<<endl;
392 cached->setRemote(&packet->d_remote);
393 cached->d_inner_remote = packet->d_inner_remote;
394 cached->d.id=packet->d.id;
395 cached->d.rd=packet->d.rd; // copy in recursion desired bit
396 cached->commitD(); // commit d to the packet inlined
397
398 sendPacket(cached, fd); // presigned, don't do it again
399 continue;
400 }
401 if(logDNSQueries)
402 g_log<<": packetcache MISS"<<endl;
403 } else {
404 if (logDNSQueries) {
405 g_log<<endl;
406 }
407 }
408 {
409 auto packetHandler = s_P.lock();
410 if (!*packetHandler) {
411 g_log<<Logger::Warning<<"TCP server is without backend connections, launching"<<endl;
412 *packetHandler = make_unique<PacketHandler>();
413 }
414
415 reply = (*packetHandler)->doQuestion(*packet); // we really need to ask the backend :-)
416 }
417
418 if(!reply) // unable to write an answer?
419 break;
420
421 sendPacket(reply, fd);
422 #ifdef ENABLE_GSS_TSIG
423 if (g_doGssTSIG) {
424 packet->cleanupGSS(reply->d.rcode);
425 }
426 #endif
427 }
428 }
429 catch(PDNSException &ae) {
430 s_P.lock()->reset(); // on next call, backend will be recycled
431 g_log << Logger::Error << "TCP Connection Thread for client " << remote << " failed, cycling backend: " << ae.reason << endl;
432 }
433 catch(NetworkError &e) {
434 g_log << Logger::Info << "TCP Connection Thread for client " << remote << " died because of network error: " << e.what() << endl;
435 }
436
437 catch(std::exception &e) {
438 s_P.lock()->reset(); // on next call, backend will be recycled
439 g_log << Logger::Error << "TCP Connection Thread for client " << remote << " died because of STL error, cycling backend: " << e.what() << endl;
440 }
441 catch( ... )
442 {
443 s_P.lock()->reset(); // on next call, backend will be recycled
444 g_log << Logger::Error << "TCP Connection Thread for client " << remote << " caught unknown exception, cycling backend." << endl;
445 }
446 d_connectionroom_sem->post();
447
448 try {
449 closesocket(fd);
450 }
451 catch(const PDNSException& e) {
452 g_log << Logger::Error << "Error closing TCP socket for client " << remote << ": " << e.reason << endl;
453 }
454 decrementClientCount(remote);
455 }
456
457
458 bool TCPNameserver::canDoAXFR(std::unique_ptr<DNSPacket>& q, bool isAXFR, std::unique_ptr<PacketHandler>& packetHandler)
459 {
460 if(::arg().mustDo("disable-axfr"))
461 return false;
462
463 string logPrefix=string(isAXFR ? "A" : "I")+"XFR-out zone '"+q->qdomain.toLogString()+"', client '"+q->getInnerRemote().toStringWithPort()+"', ";
464
465 if(q->d_havetsig) { // if you have one, it must be good
466 TSIGRecordContent trc;
467 DNSName keyname;
468 string secret;
469 if(!q->checkForCorrectTSIG(packetHandler->getBackend(), &keyname, &secret, &trc)) {
470 return false;
471 } else {
472 getTSIGHashEnum(trc.d_algoName, q->d_tsig_algo);
473 #ifdef ENABLE_GSS_TSIG
474 if (g_doGssTSIG && q->d_tsig_algo == TSIG_GSS) {
475 GssContext gssctx(keyname);
476 if (!gssctx.getPeerPrincipal(q->d_peer_principal)) {
477 g_log<<Logger::Warning<<"Failed to extract peer principal from GSS context with keyname '"<<keyname<<"'"<<endl;
478 }
479 }
480 #endif
481 }
482
483 DNSSECKeeper dk(packetHandler->getBackend());
484 #ifdef ENABLE_GSS_TSIG
485 if (g_doGssTSIG && q->d_tsig_algo == TSIG_GSS) {
486 vector<string> princs;
487 packetHandler->getBackend()->getDomainMetadata(q->qdomain, "GSS-ALLOW-AXFR-PRINCIPAL", princs);
488 for(const std::string& princ : princs) {
489 if (q->d_peer_principal == princ) {
490 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;
491 return true;
492 }
493 }
494 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;
495 return false;
496 }
497 #endif
498 if(!dk.TSIGGrantsAccess(q->qdomain, keyname)) {
499 g_log<<Logger::Warning<<logPrefix<<"denied: key with name '"<<keyname<<"' and algorithm '"<<getTSIGAlgoName(q->d_tsig_algo)<<"' does not grant access"<<endl;
500 return false;
501 }
502 else {
503 g_log<<Logger::Notice<<logPrefix<<"allowed: TSIG signed request with authorized key '"<<keyname<<"' and algorithm '"<<getTSIGAlgoName(q->d_tsig_algo)<<"'"<<endl;
504 return true;
505 }
506 }
507
508 // cerr<<"checking allow-axfr-ips"<<endl;
509 if(!(::arg()["allow-axfr-ips"].empty()) && d_ng.match( q->getInnerRemote() )) {
510 g_log<<Logger::Notice<<logPrefix<<"allowed: client IP is in allow-axfr-ips"<<endl;
511 return true;
512 }
513
514 FindNS fns;
515
516 // cerr<<"doing per-zone-axfr-acls"<<endl;
517 SOAData sd;
518 if(packetHandler->getBackend()->getSOAUncached(q->qdomain,sd)) {
519 // cerr<<"got backend and SOA"<<endl;
520 vector<string> acl;
521 packetHandler->getBackend()->getDomainMetadata(q->qdomain, "ALLOW-AXFR-FROM", acl);
522 for (const auto & i : acl) {
523 // cerr<<"matching against "<<*i<<endl;
524 if(pdns_iequals(i, "AUTO-NS")) {
525 // cerr<<"AUTO-NS magic please!"<<endl;
526
527 DNSResourceRecord rr;
528 set<DNSName> nsset;
529
530 sd.db->lookup(QType(QType::NS), q->qdomain, sd.domain_id);
531 while (sd.db->get(rr)) {
532 nsset.insert(DNSName(rr.content));
533 }
534 for(const auto & j: nsset) {
535 vector<string> nsips=fns.lookup(j, packetHandler->getBackend());
536 for(const auto & nsip : nsips) {
537 // cerr<<"got "<<*k<<" from AUTO-NS"<<endl;
538 if(nsip == q->getInnerRemote().toString())
539 {
540 // cerr<<"got AUTO-NS hit"<<endl;
541 g_log<<Logger::Notice<<logPrefix<<"allowed: client IP is in NSset"<<endl;
542 return true;
543 }
544 }
545 }
546 }
547 else
548 {
549 Netmask nm = Netmask(i);
550 if(nm.match( q->getInnerRemote() ))
551 {
552 g_log<<Logger::Notice<<logPrefix<<"allowed: client IP is in per-zone ACL"<<endl;
553 // cerr<<"hit!"<<endl;
554 return true;
555 }
556 }
557 }
558 }
559
560 extern CommunicatorClass Communicator;
561
562 if(Communicator.justNotified(q->qdomain, q->getInnerRemote().toString())) { // we just notified this ip
563 g_log<<Logger::Notice<<logPrefix<<"allowed: client IP is from recently notified secondary"<<endl;
564 return true;
565 }
566
567 g_log<<Logger::Warning<<logPrefix<<"denied: client IP has no permission"<<endl;
568 return false;
569 }
570
571 namespace {
572 struct NSECXEntry
573 {
574 NSECBitmap d_set;
575 unsigned int d_ttl;
576 bool d_auth;
577 };
578
579 static std::unique_ptr<DNSPacket> getFreshAXFRPacket(std::unique_ptr<DNSPacket>& q)
580 {
581 std::unique_ptr<DNSPacket> ret = std::unique_ptr<DNSPacket>(q->replyPacket());
582 ret->setCompress(false);
583 ret->d_dnssecOk=false; // RFC 5936, 2.2.5
584 ret->d_tcp = true;
585 return ret;
586 }
587 }
588
589
590 /** do the actual zone transfer. Return 0 in case of error, 1 in case of success */
591 int TCPNameserver::doAXFR(const DNSName &target, std::unique_ptr<DNSPacket>& q, int outsock) // NOLINT(readability-function-cognitive-complexity)
592 {
593 string logPrefix="AXFR-out zone '"+target.toLogString()+"', client '"+q->getRemoteStringWithPort()+"', ";
594
595 std::unique_ptr<DNSPacket> outpacket= getFreshAXFRPacket(q);
596 if(q->d_dnssecOk)
597 outpacket->d_dnssecOk=true; // RFC 5936, 2.2.5 'SHOULD'
598
599 g_log<<Logger::Warning<<logPrefix<<"transfer initiated"<<endl;
600
601 // determine if zone exists and AXFR is allowed using existing backend before spawning a new backend.
602 SOAData sd;
603 {
604 auto packetHandler = s_P.lock();
605 DLOG(g_log<<logPrefix<<"looking for SOA"<<endl); // find domain_id via SOA and list complete domain. No SOA, no AXFR
606 if(!*packetHandler) {
607 g_log<<Logger::Warning<<"TCP server is without backend connections in doAXFR, launching"<<endl;
608 *packetHandler = make_unique<PacketHandler>();
609 }
610
611 // canDoAXFR does all the ACL checks, and has the if(disable-axfr) shortcut, call it first.
612 if (!canDoAXFR(q, true, *packetHandler)) {
613 g_log<<Logger::Warning<<logPrefix<<"failed: client may not request AXFR"<<endl;
614 outpacket->setRcode(RCode::NotAuth);
615 sendPacket(outpacket,outsock);
616 return 0;
617 }
618
619 if (!(*packetHandler)->getBackend()->getSOAUncached(target, sd)) {
620 g_log<<Logger::Warning<<logPrefix<<"failed: not authoritative"<<endl;
621 outpacket->setRcode(RCode::NotAuth);
622 sendPacket(outpacket,outsock);
623 return 0;
624 }
625 }
626
627 UeberBackend db;
628 if(!db.getSOAUncached(target, sd)) {
629 g_log<<Logger::Warning<<logPrefix<<"failed: not authoritative in second instance"<<endl;
630 outpacket->setRcode(RCode::NotAuth);
631 sendPacket(outpacket,outsock);
632 return 0;
633 }
634
635 bool securedZone = false;
636 bool presignedZone = false;
637 bool NSEC3Zone = false;
638 bool narrow = false;
639
640 DomainInfo di;
641 bool isCatalogZone = sd.db->getDomainInfo(target, di, false) && di.isCatalogType();
642
643 NSEC3PARAMRecordContent ns3pr;
644
645 DNSSECKeeper dk(&db);
646 DNSSECKeeper::clearCaches(target);
647 if (!isCatalogZone) {
648 securedZone = dk.isSecuredZone(target);
649 presignedZone = dk.isPresigned(target);
650 }
651
652 if(securedZone && dk.getNSEC3PARAM(target, &ns3pr, &narrow)) {
653 NSEC3Zone=true;
654 if(narrow) {
655 g_log<<Logger::Warning<<logPrefix<<"failed: not doing AXFR of an NSEC3 narrow zone"<<endl;
656 outpacket->setRcode(RCode::Refused);
657 sendPacket(outpacket,outsock);
658 return 0;
659 }
660 }
661
662 TSIGRecordContent trc;
663 DNSName tsigkeyname;
664 string tsigsecret;
665
666 bool haveTSIGDetails = q->getTSIGDetails(&trc, &tsigkeyname);
667
668 if(haveTSIGDetails && !tsigkeyname.empty()) {
669 string tsig64;
670 DNSName algorithm=trc.d_algoName;
671 if (algorithm == DNSName("hmac-md5.sig-alg.reg.int"))
672 algorithm = DNSName("hmac-md5");
673 if (algorithm != DNSName("gss-tsig")) {
674 if(!db.getTSIGKey(tsigkeyname, algorithm, tsig64)) {
675 g_log<<Logger::Warning<<logPrefix<<"TSIG key not found"<<endl;
676 return 0;
677 }
678 if (B64Decode(tsig64, tsigsecret) == -1) {
679 g_log<<Logger::Error<<logPrefix<<"unable to Base-64 decode TSIG key '"<<tsigkeyname<<"'"<<endl;
680 return 0;
681 }
682 }
683 }
684
685
686 // SOA *must* go out first, our signing pipe might reorder
687 DLOG(g_log<<logPrefix<<"sending out SOA"<<endl);
688 DNSZoneRecord soa = makeEditedDNSZRFromSOAData(dk, sd);
689 outpacket->addRecord(DNSZoneRecord(soa));
690 if(securedZone && !presignedZone) {
691 set<DNSName> authSet;
692 authSet.insert(target);
693 addRRSigs(dk, db, authSet, outpacket->getRRS());
694 }
695
696 if(haveTSIGDetails && !tsigkeyname.empty())
697 outpacket->setTSIGDetails(trc, tsigkeyname, tsigsecret, trc.d_mac); // first answer is 'normal'
698
699 sendPacket(outpacket, outsock, false);
700
701 trc.d_mac = outpacket->d_trc.d_mac;
702 outpacket = getFreshAXFRPacket(q);
703
704
705 DNSZoneRecord zrr;
706 vector<DNSZoneRecord> zrrs;
707
708 zrr.dr.d_name = target;
709 zrr.dr.d_ttl = sd.minimum;
710
711 if(securedZone && !presignedZone) { // this is where the DNSKEYs, CDNSKEYs and CDSs go in
712 bool doCDNSKEY = true, doCDS = true;
713 string publishCDNSKEY, publishCDS;
714 dk.getPublishCDNSKEY(q->qdomain, publishCDNSKEY);
715 dk.getPublishCDS(q->qdomain, publishCDS);
716
717 set<uint32_t> entryPointIds;
718 DNSSECKeeper::keyset_t entryPoints = dk.getEntryPoints(target);
719 for (auto const& value : entryPoints) {
720 entryPointIds.insert(value.second.id);
721 }
722
723 DNSSECKeeper::keyset_t keys = dk.getKeys(target);
724 for(const DNSSECKeeper::keyset_t::value_type& value : keys) {
725 if (!value.second.published) {
726 continue;
727 }
728 zrr.dr.d_type = QType::DNSKEY;
729 zrr.dr.setContent(std::make_shared<DNSKEYRecordContent>(value.first.getDNSKEY()));
730 DNSName keyname = NSEC3Zone ? DNSName(toBase32Hex(hashQNameWithSalt(ns3pr, zrr.dr.d_name))) : zrr.dr.d_name;
731 zrrs.push_back(zrr);
732
733 // generate CDS and CDNSKEY records
734 if(doCDNSKEY && entryPointIds.count(value.second.id) > 0){
735 if(!publishCDNSKEY.empty()) {
736 zrr.dr.d_type=QType::CDNSKEY;
737 if (publishCDNSKEY == "0") {
738 doCDNSKEY = false;
739 zrr.dr.setContent(PacketHandler::s_deleteCDNSKEYContent);
740 zrrs.push_back(zrr);
741 } else {
742 zrr.dr.setContent(std::make_shared<DNSKEYRecordContent>(value.first.getDNSKEY()));
743 zrrs.push_back(zrr);
744 }
745 }
746
747 if(doCDS && !publishCDS.empty()){
748 zrr.dr.d_type=QType::CDS;
749 vector<string> digestAlgos;
750 stringtok(digestAlgos, publishCDS, ", ");
751 if(std::find(digestAlgos.begin(), digestAlgos.end(), "0") != digestAlgos.end()) {
752 doCDS = false;
753 zrr.dr.setContent(PacketHandler::s_deleteCDSContent);
754 zrrs.push_back(zrr);
755 } else {
756 for(auto const &digestAlgo : digestAlgos) {
757 zrr.dr.setContent(std::make_shared<DSRecordContent>(makeDSFromDNSKey(target, value.first.getDNSKEY(), pdns::checked_stoi<uint8_t>(digestAlgo))));
758 zrrs.push_back(zrr);
759 }
760 }
761 }
762 }
763 }
764
765 }
766
767 if(NSEC3Zone) { // now stuff in the NSEC3PARAM
768 uint8_t flags = ns3pr.d_flags;
769 zrr.dr.d_type = QType::NSEC3PARAM;
770 ns3pr.d_flags = 0;
771 zrr.dr.setContent(std::make_shared<NSEC3PARAMRecordContent>(ns3pr));
772 ns3pr.d_flags = flags;
773 DNSName keyname = DNSName(toBase32Hex(hashQNameWithSalt(ns3pr, zrr.dr.d_name)));
774 zrrs.push_back(zrr);
775 }
776
777 const bool rectify = !(presignedZone || ::arg().mustDo("disable-axfr-rectify"));
778 set<DNSName> qnames, nsset, terms;
779
780 // Catalog zone start
781 if (di.kind == DomainInfo::Producer) {
782 // Ignore all records except NS at apex
783 sd.db->lookup(QType::NS, target, di.id);
784 while (sd.db->get(zrr)) {
785 zrrs.emplace_back(zrr);
786 }
787 if (zrrs.empty()) {
788 zrr.dr.d_name = target;
789 zrr.dr.d_ttl = 0;
790 zrr.dr.d_type = QType::NS;
791 zrr.dr.setContent(std::make_shared<NSRecordContent>("invalid."));
792 zrrs.emplace_back(zrr);
793 }
794
795 zrrs.emplace_back(CatalogInfo::getCatalogVersionRecord(target));
796
797 vector<CatalogInfo> members;
798 sd.db->getCatalogMembers(target, members, CatalogInfo::CatalogType::Producer);
799 for (const auto& ci : members) {
800 ci.toDNSZoneRecords(target, zrrs);
801 }
802 if (members.empty()) {
803 g_log << Logger::Warning << logPrefix << "catalog zone '" << target << "' has no members" << endl;
804 }
805 goto send;
806 }
807 // Catalog zone end
808
809 // now start list zone
810 if (!sd.db->list(target, sd.domain_id, isCatalogZone)) {
811 g_log<<Logger::Error<<logPrefix<<"backend signals error condition, aborting AXFR"<<endl;
812 outpacket->setRcode(RCode::ServFail);
813 sendPacket(outpacket,outsock);
814 return 0;
815 }
816
817 while(sd.db->get(zrr)) {
818 if (!presignedZone) {
819 if (zrr.dr.d_type == QType::RRSIG) {
820 continue;
821 }
822 if (zrr.dr.d_type == QType::DNSKEY || zrr.dr.d_type == QType::CDNSKEY || zrr.dr.d_type == QType::CDS) {
823 if(!::arg().mustDo("direct-dnskey")) {
824 continue;
825 } else {
826 zrr.dr.d_ttl = sd.minimum;
827 }
828 }
829 }
830 zrr.dr.d_name.makeUsLowerCase();
831 if(zrr.dr.d_name.isPartOf(target)) {
832 if (zrr.dr.d_type == QType::ALIAS && (::arg().mustDo("outgoing-axfr-expand-alias") || ::arg()["outgoing-axfr-expand-alias"] == "ignore-errors")) {
833 vector<DNSZoneRecord> ips;
834 int ret1 = stubDoResolve(getRR<ALIASRecordContent>(zrr.dr)->getContent(), QType::A, ips);
835 int ret2 = stubDoResolve(getRR<ALIASRecordContent>(zrr.dr)->getContent(), QType::AAAA, ips);
836 if (ret1 != RCode::NoError || ret2 != RCode::NoError) {
837 if (::arg()["outgoing-axfr-expand-alias"] == "ignore-errors") {
838 if (ret1 != RCode::NoError) {
839 g_log << Logger::Error << logPrefix << zrr.dr.d_name.toLogString() << ": error resolving A record for ALIAS target " << zrr.dr.getContent()->getZoneRepresentation() << ", continuing AXFR" << endl;
840 }
841 if (ret2 != RCode::NoError) {
842 g_log << Logger::Error << logPrefix << zrr.dr.d_name.toLogString() << ": error resolving AAAA record for ALIAS target " << zrr.dr.getContent()->getZoneRepresentation() << ", continuing AXFR" << endl;
843 }
844 }
845 else {
846 g_log << Logger::Warning << logPrefix << zrr.dr.d_name.toLogString() << ": error resolving for ALIAS " << zrr.dr.getContent()->getZoneRepresentation() << ", aborting AXFR" << endl;
847 outpacket->setRcode(RCode::ServFail);
848 sendPacket(outpacket, outsock);
849 return 0;
850 }
851 }
852 for (auto& ip: ips) {
853 zrr.dr.d_type = ip.dr.d_type;
854 zrr.dr.setContent(ip.dr.getContent());
855 zrrs.push_back(zrr);
856 }
857 continue;
858 }
859
860 if (rectify) {
861 if (zrr.dr.d_type) {
862 qnames.insert(zrr.dr.d_name);
863 if(zrr.dr.d_type == QType::NS && zrr.dr.d_name!=target)
864 nsset.insert(zrr.dr.d_name);
865 } else {
866 // remove existing ents
867 continue;
868 }
869 }
870 zrrs.push_back(zrr);
871 } else {
872 if (zrr.dr.d_type)
873 g_log<<Logger::Warning<<logPrefix<<"zone contains out-of-zone data '"<<zrr.dr.d_name<<"|"<<DNSRecordContent::NumberToType(zrr.dr.d_type)<<"', ignoring"<<endl;
874 }
875 }
876
877 for (auto& loopRR : zrrs) {
878 if ((loopRR.dr.d_type == QType::SVCB || loopRR.dr.d_type == QType::HTTPS)) {
879 // Process auto hints
880 // TODO this is an almost copy of the code in the packethandler
881 auto rrc = getRR<SVCBBaseRecordContent>(loopRR.dr);
882 if (rrc == nullptr) {
883 continue;
884 }
885 auto newRRC = rrc->clone();
886 if (!newRRC) {
887 continue;
888 }
889 DNSName svcTarget = newRRC->getTarget().isRoot() ? loopRR.dr.d_name : newRRC->getTarget();
890 if (newRRC->autoHint(SvcParam::ipv4hint)) {
891 sd.db->lookup(QType::A, svcTarget, sd.domain_id);
892 vector<ComboAddress> hints;
893 DNSZoneRecord rr;
894 while (sd.db->get(rr)) {
895 auto arrc = getRR<ARecordContent>(rr.dr);
896 hints.push_back(arrc->getCA());
897 }
898 if (hints.size() == 0) {
899 newRRC->removeParam(SvcParam::ipv4hint);
900 } else {
901 newRRC->setHints(SvcParam::ipv4hint, hints);
902 }
903 }
904
905 if (newRRC->autoHint(SvcParam::ipv6hint)) {
906 sd.db->lookup(QType::AAAA, svcTarget, sd.domain_id);
907 vector<ComboAddress> hints;
908 DNSZoneRecord rr;
909 while (sd.db->get(rr)) {
910 auto arrc = getRR<AAAARecordContent>(rr.dr);
911 hints.push_back(arrc->getCA());
912 }
913 if (hints.size() == 0) {
914 newRRC->removeParam(SvcParam::ipv6hint);
915 } else {
916 newRRC->setHints(SvcParam::ipv6hint, hints);
917 }
918 }
919
920 loopRR.dr.setContent(std::move(newRRC));
921 }
922 }
923
924 // Group records by name and type, signpipe stumbles over interrupted rrsets
925 if(securedZone && !presignedZone) {
926 sort(zrrs.begin(), zrrs.end(), [](const DNSZoneRecord& a, const DNSZoneRecord& b) {
927 return std::tie(a.dr.d_name, a.dr.d_type) < std::tie(b.dr.d_name, b.dr.d_type);
928 });
929 }
930
931 if(rectify) {
932 // set auth
933 for(DNSZoneRecord &loopZRR : zrrs) {
934 loopZRR.auth=true;
935 if (loopZRR.dr.d_type != QType::NS || loopZRR.dr.d_name!=target) {
936 DNSName shorter(loopZRR.dr.d_name);
937 do {
938 if (shorter==target) // apex is always auth
939 break;
940 if(nsset.count(shorter) && !(loopZRR.dr.d_name==shorter && loopZRR.dr.d_type == QType::DS)) {
941 loopZRR.auth=false;
942 break;
943 }
944 } while(shorter.chopOff());
945 }
946 }
947
948 if(NSEC3Zone) {
949 // ents are only required for NSEC3 zones
950 uint32_t maxent = ::arg().asNum("max-ent-entries");
951 set<DNSName> nsec3set, nonterm;
952 for (auto &loopZRR: zrrs) {
953 bool skip=false;
954 DNSName shorter = loopZRR.dr.d_name;
955 if (shorter != target && shorter.chopOff() && shorter != target) {
956 do {
957 if(nsset.count(shorter)) {
958 skip=true;
959 break;
960 }
961 } while(shorter.chopOff() && shorter != target);
962 }
963 shorter = loopZRR.dr.d_name;
964 if(!skip && (loopZRR.dr.d_type != QType::NS || !ns3pr.d_flags)) {
965 do {
966 if(!nsec3set.count(shorter)) {
967 nsec3set.insert(shorter);
968 }
969 } while(shorter != target && shorter.chopOff());
970 }
971 }
972
973 for(DNSZoneRecord &loopZRR : zrrs) {
974 DNSName shorter(loopZRR.dr.d_name);
975 while(shorter != target && shorter.chopOff()) {
976 if(!qnames.count(shorter) && !nonterm.count(shorter) && nsec3set.count(shorter)) {
977 if(!(maxent)) {
978 g_log<<Logger::Warning<<logPrefix<<"zone has too many empty non terminals, aborting AXFR"<<endl;
979 outpacket->setRcode(RCode::ServFail);
980 sendPacket(outpacket,outsock);
981 return 0;
982 }
983 nonterm.insert(shorter);
984 --maxent;
985 }
986 }
987 }
988
989 for(const auto& nt : nonterm) {
990 DNSZoneRecord tempRR;
991 tempRR.dr.d_name=nt;
992 tempRR.dr.d_type=QType::ENT;
993 tempRR.auth=true;
994 zrrs.push_back(tempRR);
995 }
996 }
997 }
998
999 send:
1000
1001 /* now write all other records */
1002
1003 typedef map<DNSName, NSECXEntry, CanonDNSNameCompare> nsecxrepo_t;
1004 nsecxrepo_t nsecxrepo;
1005
1006 ChunkedSigningPipe csp(target, (securedZone && !presignedZone), ::arg().asNum("signing-threads", 1), ::arg().mustDo("workaround-11804") ? 1 : 100);
1007
1008 DNSName keyname;
1009 unsigned int udiff;
1010 DTime dt;
1011 dt.set();
1012 for(DNSZoneRecord &loopZRR : zrrs) {
1013 if(securedZone && (loopZRR.auth || loopZRR.dr.d_type == QType::NS)) {
1014 if (NSEC3Zone || loopZRR.dr.d_type) {
1015 if (presignedZone && NSEC3Zone && loopZRR.dr.d_type == QType::RRSIG && getRR<RRSIGRecordContent>(loopZRR.dr)->d_type == QType::NSEC3) {
1016 keyname = loopZRR.dr.d_name.makeRelative(sd.qname);
1017 } else {
1018 keyname = NSEC3Zone ? DNSName(toBase32Hex(hashQNameWithSalt(ns3pr, loopZRR.dr.d_name))) : loopZRR.dr.d_name;
1019 }
1020 NSECXEntry& ne = nsecxrepo[keyname];
1021 ne.d_ttl = sd.getNegativeTTL();
1022 ne.d_auth = (ne.d_auth || loopZRR.auth || (NSEC3Zone && (!ns3pr.d_flags)));
1023 if (loopZRR.dr.d_type && loopZRR.dr.d_type != QType::RRSIG) {
1024 ne.d_set.set(loopZRR.dr.d_type);
1025 }
1026 }
1027 }
1028
1029 if (!loopZRR.dr.d_type)
1030 continue; // skip empty non-terminals
1031
1032 if(loopZRR.dr.d_type == QType::SOA)
1033 continue; // skip SOA - would indicate end of AXFR
1034
1035 if(csp.submit(loopZRR)) {
1036 for(;;) {
1037 outpacket->getRRS() = csp.getChunk();
1038 if(!outpacket->getRRS().empty()) {
1039 if(haveTSIGDetails && !tsigkeyname.empty())
1040 outpacket->setTSIGDetails(trc, tsigkeyname, tsigsecret, trc.d_mac, true);
1041 sendPacket(outpacket, outsock, false);
1042 trc.d_mac=outpacket->d_trc.d_mac;
1043 outpacket=getFreshAXFRPacket(q);
1044 }
1045 else
1046 break;
1047 }
1048 }
1049 }
1050 /*
1051 udiff=dt.udiffNoReset();
1052 cerr<<"Starting NSEC: "<<csp.d_signed/(udiff/1000000.0)<<" sigs/s, "<<csp.d_signed<<" / "<<udiff/1000000.0<<endl;
1053 cerr<<"Outstanding: "<<csp.d_outstanding<<", "<<csp.d_queued - csp.d_signed << endl;
1054 cerr<<"Ready for consumption: "<<csp.getReady()<<endl;
1055 */
1056 if(securedZone) {
1057 if(NSEC3Zone) {
1058 for(nsecxrepo_t::const_iterator iter = nsecxrepo.begin(); iter != nsecxrepo.end(); ++iter) {
1059 if(iter->second.d_auth) {
1060 NSEC3RecordContent n3rc;
1061 n3rc.set(iter->second.d_set);
1062 const auto numberOfTypesSet = n3rc.numberOfTypesSet();
1063 if (numberOfTypesSet != 0 && (numberOfTypesSet != 1 || !n3rc.isSet(QType::NS))) {
1064 n3rc.set(QType::RRSIG);
1065 }
1066 n3rc.d_salt = ns3pr.d_salt;
1067 n3rc.d_flags = ns3pr.d_flags;
1068 n3rc.d_iterations = ns3pr.d_iterations;
1069 n3rc.d_algorithm = DNSSECKeeper::DIGEST_SHA1; // SHA1, fixed in PowerDNS for now
1070 nsecxrepo_t::const_iterator inext = iter;
1071 ++inext;
1072 if(inext == nsecxrepo.end())
1073 inext = nsecxrepo.begin();
1074 while(!inext->second.d_auth && inext != iter)
1075 {
1076 ++inext;
1077 if(inext == nsecxrepo.end())
1078 inext = nsecxrepo.begin();
1079 }
1080 n3rc.d_nexthash = fromBase32Hex(inext->first.toStringNoDot());
1081 zrr.dr.d_name = iter->first+sd.qname;
1082
1083 zrr.dr.d_ttl = sd.getNegativeTTL();
1084 zrr.dr.setContent(std::make_shared<NSEC3RecordContent>(std::move(n3rc)));
1085 zrr.dr.d_type = QType::NSEC3;
1086 zrr.dr.d_place = DNSResourceRecord::ANSWER;
1087 zrr.auth=true;
1088 if(csp.submit(zrr)) {
1089 for(;;) {
1090 outpacket->getRRS() = csp.getChunk();
1091 if(!outpacket->getRRS().empty()) {
1092 if(haveTSIGDetails && !tsigkeyname.empty())
1093 outpacket->setTSIGDetails(trc, tsigkeyname, tsigsecret, trc.d_mac, true);
1094 sendPacket(outpacket, outsock, false);
1095 trc.d_mac=outpacket->d_trc.d_mac;
1096 outpacket=getFreshAXFRPacket(q);
1097 }
1098 else
1099 break;
1100 }
1101 }
1102 }
1103 }
1104 }
1105 else for(nsecxrepo_t::const_iterator iter = nsecxrepo.begin(); iter != nsecxrepo.end(); ++iter) {
1106 NSECRecordContent nrc;
1107 nrc.set(iter->second.d_set);
1108 nrc.set(QType::RRSIG);
1109 nrc.set(QType::NSEC);
1110
1111 if(boost::next(iter) != nsecxrepo.end())
1112 nrc.d_next = boost::next(iter)->first;
1113 else
1114 nrc.d_next=nsecxrepo.begin()->first;
1115 zrr.dr.d_name = iter->first;
1116
1117 zrr.dr.d_ttl = sd.getNegativeTTL();
1118 zrr.dr.setContent(std::make_shared<NSECRecordContent>(std::move(nrc)));
1119 zrr.dr.d_type = QType::NSEC;
1120 zrr.dr.d_place = DNSResourceRecord::ANSWER;
1121 zrr.auth=true;
1122 if(csp.submit(zrr)) {
1123 for(;;) {
1124 outpacket->getRRS() = csp.getChunk();
1125 if(!outpacket->getRRS().empty()) {
1126 if(haveTSIGDetails && !tsigkeyname.empty())
1127 outpacket->setTSIGDetails(trc, tsigkeyname, tsigsecret, trc.d_mac, true);
1128 sendPacket(outpacket, outsock, false);
1129 trc.d_mac=outpacket->d_trc.d_mac;
1130 outpacket=getFreshAXFRPacket(q);
1131 }
1132 else
1133 break;
1134 }
1135 }
1136 }
1137 }
1138 /*
1139 udiff=dt.udiffNoReset();
1140 cerr<<"Flushing pipe: "<<csp.d_signed/(udiff/1000000.0)<<" sigs/s, "<<csp.d_signed<<" / "<<udiff/1000000.0<<endl;
1141 cerr<<"Outstanding: "<<csp.d_outstanding<<", "<<csp.d_queued - csp.d_signed << endl;
1142 cerr<<"Ready for consumption: "<<csp.getReady()<<endl;
1143 * */
1144 for(;;) {
1145 outpacket->getRRS() = csp.getChunk(true); // flush the pipe
1146 if(!outpacket->getRRS().empty()) {
1147 if(haveTSIGDetails && !tsigkeyname.empty())
1148 outpacket->setTSIGDetails(trc, tsigkeyname, tsigsecret, trc.d_mac, true); // first answer is 'normal'
1149 try {
1150 sendPacket(outpacket, outsock, false);
1151 }
1152 catch (PDNSException& pe) {
1153 throw PDNSException("during axfr-out of "+target.toString()+", this happened: "+pe.reason);
1154 }
1155 trc.d_mac=outpacket->d_trc.d_mac;
1156 outpacket=getFreshAXFRPacket(q);
1157 }
1158 else
1159 break;
1160 }
1161
1162 udiff=dt.udiffNoReset();
1163 if(securedZone)
1164 g_log<<Logger::Debug<<logPrefix<<"done signing: "<<csp.d_signed/(udiff/1000000.0)<<" sigs/s, "<<endl;
1165
1166 DLOG(g_log<<logPrefix<<"done writing out records"<<endl);
1167 /* and terminate with yet again the SOA record */
1168 outpacket=getFreshAXFRPacket(q);
1169 outpacket->addRecord(std::move(soa));
1170 if(haveTSIGDetails && !tsigkeyname.empty())
1171 outpacket->setTSIGDetails(trc, tsigkeyname, tsigsecret, trc.d_mac, true);
1172
1173 sendPacket(outpacket, outsock);
1174
1175 DLOG(g_log<<logPrefix<<"last packet - close"<<endl);
1176 g_log<<Logger::Notice<<logPrefix<<"AXFR finished"<<endl;
1177
1178 return 1;
1179 }
1180
1181 int TCPNameserver::doIXFR(std::unique_ptr<DNSPacket>& q, int outsock)
1182 {
1183 string logPrefix="IXFR-out zone '"+q->qdomain.toLogString()+"', client '"+q->getRemoteStringWithPort()+"', ";
1184
1185 std::unique_ptr<DNSPacket> outpacket=getFreshAXFRPacket(q);
1186 if(q->d_dnssecOk)
1187 outpacket->d_dnssecOk=true; // RFC 5936, 2.2.5 'SHOULD'
1188
1189 uint32_t serial = 0;
1190 MOADNSParser mdp(false, q->getString());
1191 for(const auto & answer : mdp.d_answers) {
1192 const DNSRecord *rr = &answer.first;
1193 if (rr->d_type == QType::SOA && rr->d_place == DNSResourceRecord::AUTHORITY) {
1194 vector<string>parts;
1195 stringtok(parts, rr->getContent()->getZoneRepresentation());
1196 if (parts.size() >= 3) {
1197 try {
1198 pdns::checked_stoi_into(serial, parts[2]);
1199 }
1200 catch(const std::out_of_range& oor) {
1201 g_log<<Logger::Warning<<logPrefix<<"invalid serial in IXFR query"<<endl;
1202 outpacket->setRcode(RCode::FormErr);
1203 sendPacket(outpacket,outsock);
1204 return 0;
1205 }
1206 } else {
1207 g_log<<Logger::Warning<<logPrefix<<"no serial in IXFR query"<<endl;
1208 outpacket->setRcode(RCode::FormErr);
1209 sendPacket(outpacket,outsock);
1210 return 0;
1211 }
1212 } else if (rr->d_type != QType::TSIG && rr->d_type != QType::OPT) {
1213 g_log<<Logger::Warning<<logPrefix<<"additional records in IXFR query, type: "<<QType(rr->d_type).toString()<<endl;
1214 outpacket->setRcode(RCode::FormErr);
1215 sendPacket(outpacket,outsock);
1216 return 0;
1217 }
1218 }
1219
1220 g_log<<Logger::Warning<<logPrefix<<"transfer initiated with serial "<<serial<<endl;
1221
1222 // determine if zone exists, XFR is allowed, and if IXFR can proceed using existing backend before spawning a new backend.
1223 SOAData sd;
1224 bool securedZone;
1225 bool serialPermitsIXFR;
1226 {
1227 auto packetHandler = s_P.lock();
1228 DLOG(g_log<<logPrefix<<"Looking for SOA"<<endl); // find domain_id via SOA and list complete domain. No SOA, no IXFR
1229 if(!*packetHandler) {
1230 g_log<<Logger::Warning<<"TCP server is without backend connections in doIXFR, launching"<<endl;
1231 *packetHandler = make_unique<PacketHandler>();
1232 }
1233
1234 // canDoAXFR does all the ACL checks, and has the if(disable-axfr) shortcut, call it first.
1235 if(!canDoAXFR(q, false, *packetHandler) || !(*packetHandler)->getBackend()->getSOAUncached(q->qdomain, sd)) {
1236 g_log<<Logger::Warning<<logPrefix<<"failed: not authoritative"<<endl;
1237 outpacket->setRcode(RCode::NotAuth);
1238 sendPacket(outpacket,outsock);
1239 return 0;
1240 }
1241
1242 DNSSECKeeper dk((*packetHandler)->getBackend());
1243 DNSSECKeeper::clearCaches(q->qdomain);
1244 bool narrow = false;
1245 securedZone = dk.isSecuredZone(q->qdomain);
1246 if(dk.getNSEC3PARAM(q->qdomain, nullptr, &narrow)) {
1247 if(narrow) {
1248 g_log<<Logger::Warning<<logPrefix<<"not doing IXFR of an NSEC3 narrow zone"<<endl;
1249 outpacket->setRcode(RCode::Refused);
1250 sendPacket(outpacket,outsock);
1251 return 0;
1252 }
1253 }
1254
1255 serialPermitsIXFR = !rfc1982LessThan(serial, calculateEditSOA(sd.serial, dk, sd.qname));
1256 }
1257
1258 if (serialPermitsIXFR) {
1259 DNSName target = q->qdomain;
1260 TSIGRecordContent trc;
1261 DNSName tsigkeyname;
1262 string tsigsecret;
1263
1264 UeberBackend db;
1265 DNSSECKeeper dk(&db);
1266
1267 bool haveTSIGDetails = q->getTSIGDetails(&trc, &tsigkeyname);
1268
1269 if(haveTSIGDetails && !tsigkeyname.empty()) {
1270 string tsig64;
1271 DNSName algorithm=trc.d_algoName; // FIXME400: was toLowerCanonic, compare output
1272 if (algorithm == DNSName("hmac-md5.sig-alg.reg.int"))
1273 algorithm = DNSName("hmac-md5");
1274 if (!db.getTSIGKey(tsigkeyname, algorithm, tsig64)) {
1275 g_log << Logger::Error << "TSIG key '" << tsigkeyname << "' for domain '" << target << "' not found" << endl;
1276 return 0;
1277 }
1278 if (B64Decode(tsig64, tsigsecret) == -1) {
1279 g_log<<Logger::Error<<logPrefix<<"unable to Base-64 decode TSIG key '"<<tsigkeyname<<"'"<<endl;
1280 return 0;
1281 }
1282 }
1283
1284 // SOA *must* go out first, our signing pipe might reorder
1285 DLOG(g_log<<logPrefix<<"sending out SOA"<<endl);
1286 DNSZoneRecord soa = makeEditedDNSZRFromSOAData(dk, sd);
1287 outpacket->addRecord(std::move(soa));
1288 if(securedZone && outpacket->d_dnssecOk) {
1289 set<DNSName> authSet;
1290 authSet.insert(target);
1291 addRRSigs(dk, db, authSet, outpacket->getRRS());
1292 }
1293
1294 if(haveTSIGDetails && !tsigkeyname.empty())
1295 outpacket->setTSIGDetails(trc, tsigkeyname, tsigsecret, trc.d_mac); // first answer is 'normal'
1296
1297 sendPacket(outpacket, outsock);
1298
1299 g_log<<Logger::Notice<<logPrefix<<"IXFR finished"<<endl;
1300
1301 return 1;
1302 }
1303
1304 g_log<<Logger::Notice<<logPrefix<<"IXFR fallback to AXFR"<<endl;
1305 return doAXFR(q->qdomain, q, outsock);
1306 }
1307
1308 TCPNameserver::~TCPNameserver() = default;
1309 TCPNameserver::TCPNameserver()
1310 {
1311 d_maxTransactionsPerConn = ::arg().asNum("max-tcp-transactions-per-conn");
1312 d_idleTimeout = ::arg().asNum("tcp-idle-timeout");
1313 d_maxConnectionDuration = ::arg().asNum("max-tcp-connection-duration");
1314 d_maxConnectionsPerClient = ::arg().asNum("max-tcp-connections-per-client");
1315
1316 // sem_init(&d_connectionroom_sem,0,::arg().asNum("max-tcp-connections"));
1317 d_connectionroom_sem = make_unique<Semaphore>( ::arg().asNum( "max-tcp-connections" ));
1318 d_maxTCPConnections = ::arg().asNum( "max-tcp-connections" );
1319
1320 vector<string>locals;
1321 stringtok(locals,::arg()["local-address"]," ,");
1322 if(locals.empty())
1323 throw PDNSException("No local addresses specified");
1324
1325 d_ng.toMasks(::arg()["allow-axfr-ips"] );
1326
1327 signal(SIGPIPE,SIG_IGN);
1328
1329 for(auto const &laddr : locals) {
1330 ComboAddress local(laddr, ::arg().asNum("local-port"));
1331
1332 int s=socket(local.sin4.sin_family, SOCK_STREAM, 0);
1333 if(s<0)
1334 throw PDNSException("Unable to acquire TCP socket: "+stringerror());
1335 setCloseOnExec(s);
1336
1337 int tmp=1;
1338 if(setsockopt(s, SOL_SOCKET,SO_REUSEADDR, (char*)&tmp, sizeof tmp) < 0) {
1339 g_log<<Logger::Error<<"Setsockopt failed"<<endl;
1340 _exit(1);
1341 }
1342
1343 if (::arg().asNum("tcp-fast-open") > 0) {
1344 #ifdef TCP_FASTOPEN
1345 int fastOpenQueueSize = ::arg().asNum("tcp-fast-open");
1346 if (setsockopt(s, IPPROTO_TCP, TCP_FASTOPEN, &fastOpenQueueSize, sizeof fastOpenQueueSize) < 0) {
1347 g_log<<Logger::Error<<"Failed to enable TCP Fast Open for listening socket "<<local.toStringWithPort()<<": "<<stringerror()<<endl;
1348 }
1349 #else
1350 g_log<<Logger::Warning<<"TCP Fast Open configured but not supported for listening socket"<<endl;
1351 #endif
1352 }
1353
1354 if(::arg().mustDo("non-local-bind"))
1355 Utility::setBindAny(local.sin4.sin_family, s);
1356
1357 if(local.isIPv6() && setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &tmp, sizeof(tmp)) < 0) {
1358 g_log<<Logger::Error<<"Failed to set IPv6 socket to IPv6 only, continuing anyhow: "<<stringerror()<<endl;
1359 }
1360
1361 if(::bind(s, (sockaddr*)&local, local.getSocklen())<0) {
1362 int err = errno;
1363 close(s);
1364 if( err == EADDRNOTAVAIL && ! ::arg().mustDo("local-address-nonexist-fail") ) {
1365 g_log<<Logger::Error<<"Address " << local.toString() << " does not exist on this server - skipping TCP bind" << endl;
1366 continue;
1367 } else {
1368 g_log<<Logger::Error<<"Unable to bind to TCP socket " << local.toStringWithPort() << ": "<<stringerror(err)<<endl;
1369 throw PDNSException("Unable to bind to TCP socket");
1370 }
1371 }
1372
1373 listen(s, 128);
1374 g_log<<Logger::Error<<"TCP server bound to "<<local.toStringWithPort()<<endl;
1375 d_sockets.push_back(s);
1376 struct pollfd pfd;
1377 memset(&pfd, 0, sizeof(pfd));
1378 pfd.fd = s;
1379 pfd.events = POLLIN;
1380 d_prfds.push_back(pfd);
1381 }
1382 }
1383
1384
1385 //! Start of TCP operations thread, we launch a new thread for each incoming TCP question
1386 void TCPNameserver::thread()
1387 {
1388 setThreadName("pdns/tcpnameser");
1389 try {
1390 for(;;) {
1391 int fd;
1392 ComboAddress remote;
1393 Utility::socklen_t addrlen=remote.getSocklen();
1394
1395 int ret=poll(&d_prfds[0], d_prfds.size(), -1); // blocks, forever if need be
1396 if(ret <= 0)
1397 continue;
1398
1399 int sock=-1;
1400 for(const pollfd& pfd : d_prfds) {
1401 if(pfd.revents & POLLIN) {
1402 sock = pfd.fd;
1403 remote.sin4.sin_family = AF_INET6;
1404 addrlen=remote.getSocklen();
1405
1406 if((fd=accept(sock, (sockaddr*)&remote, &addrlen))<0) {
1407 int err = errno;
1408 g_log<<Logger::Error<<"TCP question accept error: "<<stringerror(err)<<endl;
1409
1410 if(err==EMFILE) {
1411 g_log<<Logger::Error<<"TCP handler out of filedescriptors, exiting, won't recover from this"<<endl;
1412 _exit(1);
1413 }
1414 }
1415 else {
1416 if (d_maxConnectionsPerClient) {
1417 auto clientsCount = s_clientsCount.lock();
1418 if ((*clientsCount)[remote] >= d_maxConnectionsPerClient) {
1419 g_log<<Logger::Notice<<"Limit of simultaneous TCP connections per client reached for "<< remote<<", dropping"<<endl;
1420 close(fd);
1421 continue;
1422 }
1423 (*clientsCount)[remote]++;
1424 }
1425
1426 d_connectionroom_sem->wait(); // blocks if no connections are available
1427
1428 int room;
1429 d_connectionroom_sem->getValue( &room);
1430 if(room<1)
1431 g_log<<Logger::Warning<<"Limit of simultaneous TCP connections reached - raise max-tcp-connections"<<endl;
1432
1433 try {
1434 std::thread connThread(doConnection, fd);
1435 connThread.detach();
1436 }
1437 catch (std::exception& e) {
1438 g_log<<Logger::Error<<"Error creating thread: "<<e.what()<<endl;
1439 d_connectionroom_sem->post();
1440 close(fd);
1441 decrementClientCount(remote);
1442 }
1443 }
1444 }
1445 }
1446 }
1447 }
1448 catch(PDNSException &AE) {
1449 g_log<<Logger::Error<<"TCP Nameserver thread dying because of fatal error: "<<AE.reason<<endl;
1450 }
1451 catch(...) {
1452 g_log<<Logger::Error<<"TCPNameserver dying because of an unexpected fatal error"<<endl;
1453 }
1454 _exit(1); // take rest of server with us
1455 }
1456
1457
1458 unsigned int TCPNameserver::numTCPConnections()
1459 {
1460 int room;
1461 d_connectionroom_sem->getValue( &room);
1462 return d_maxTCPConnections - room;
1463 }