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