]> git.ipfire.org Git - thirdparty/pdns.git/blame - pdns/tcpreceiver.cc
Merge branch 'master' into docs-fix-numerous-things-big-chain
[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) {
66157226 496 vector<string> nsips=fns.lookup(j, s_P->getBackend());
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
13f9e280 540 DNSZoneRecord makeEditedDNSZRFromSOAData(DNSSECKeeper& dk, const SOAData& sd)
54d84273 541 {
13f9e280
CH
542 SOAData edited = sd;
543 edited.serial = calculateEditSOA(sd.serial, dk, sd.qname);
544
545 DNSRecord soa;
546 soa.d_name = sd.qname;
547 soa.d_type = QType::SOA;
548 soa.d_ttl = sd.ttl;
549 soa.d_place = DNSResourceRecord::ANSWER;
550 soa.d_content = makeSOAContent(edited);
551
552 DNSZoneRecord dzr;
553 dzr.auth = true;
554 dzr.dr = soa;
555
556 return dzr;
54d84273 557 }
8e9b7d99 558
54d84273
PD
559 shared_ptr<DNSPacket> getFreshAXFRPacket(shared_ptr<DNSPacket> q)
560 {
561 shared_ptr<DNSPacket> ret = shared_ptr<DNSPacket>(q->replyPacket());
562 ret->setCompress(false);
563 ret->d_dnssecOk=false; // RFC 5936, 2.2.5
564 ret->d_tcp = true;
565 return ret;
566 }
8e9b7d99
BH
567}
568
54d84273 569
12c86877 570/** do the actual zone transfer. Return 0 in case of error, 1 in case of success */
7abbc40f 571int TCPNameserver::doAXFR(const DNSName &target, shared_ptr<DNSPacket> q, int outsock)
12c86877 572{
8e9b7d99 573 shared_ptr<DNSPacket> outpacket= getFreshAXFRPacket(q);
c67e46a1 574 if(q->d_dnssecOk)
05e24311 575 outpacket->d_dnssecOk=true; // RFC 5936, 2.2.5 'SHOULD'
22893145 576
e6a9dde5 577 g_log<<Logger::Error<<"AXFR of domain '"<<target<<"' initiated by "<<q->getRemote()<<endl;
12c86877 578
22893145 579 // determine if zone exists and AXFR is allowed using existing backend before spawning a new backend.
12c86877
BH
580 SOAData sd;
581 {
582 Lock l(&s_plock);
e6a9dde5 583 DLOG(g_log<<"Looking for SOA"<<endl); // find domain_id via SOA and list complete domain. No SOA, no AXFR
12a965c5 584 if(!s_P) {
e6a9dde5 585 g_log<<Logger::Error<<"TCP server is without backend connections in doAXFR, launching"<<endl;
12a965c5
BH
586 s_P=new PacketHandler;
587 }
12c86877 588
ea99d474 589 // canDoAXFR does all the ACL checks, and has the if(disable-axfr) shortcut, call it first.
8090f5a2 590 if (!canDoAXFR(q)) {
e6a9dde5 591 g_log<<Logger::Error<<"AXFR of domain '"<<target<<"' failed: "<<q->getRemote()<<" may not request AXFR"<<endl;
9c556f63 592 outpacket->setRcode(RCode::NotAuth);
8090f5a2
AT
593 sendPacket(outpacket,outsock);
594 return 0;
595 }
596
8090f5a2 597 if(!s_P->getBackend()->getSOAUncached(target, sd)) {
e6a9dde5 598 g_log<<Logger::Error<<"AXFR of domain '"<<target<<"' failed: not authoritative"<<endl;
9c556f63 599 outpacket->setRcode(RCode::NotAuth);
ff76e8b4 600 sendPacket(outpacket,outsock);
12c86877
BH
601 return 0;
602 }
3de83124 603 }
22893145 604
8e9b7d99 605 UeberBackend db;
79ba7763 606 if(!db.getSOAUncached(target, sd)) {
e6a9dde5 607 g_log<<Logger::Error<<"AXFR of domain '"<<target<<"' failed: not authoritative in second instance"<<endl;
79ba7763 608 outpacket->setRcode(RCode::NotAuth);
ff76e8b4 609 sendPacket(outpacket,outsock);
3de83124 610 return 0;
12c86877 611 }
3de83124 612
ea99d474 613 DNSSECKeeper dk(&db);
22893145
CH
614 dk.clearCaches(target);
615 bool securedZone = dk.isSecuredZone(target);
616 bool presignedZone = dk.isPresigned(target);
617
618 bool noAXFRBecauseOfNSEC3Narrow=false;
619 NSEC3PARAMRecordContent ns3pr;
620 bool narrow;
621 bool NSEC3Zone=false;
dacacb23 622 if(securedZone && dk.getNSEC3PARAM(target, &ns3pr, &narrow)) {
22893145
CH
623 NSEC3Zone=true;
624 if(narrow) {
e6a9dde5 625 g_log<<Logger::Error<<"Not doing AXFR of an NSEC3 narrow zone '"<<target<<"' for "<<q->getRemote()<<endl;
22893145
CH
626 noAXFRBecauseOfNSEC3Narrow=true;
627 }
628 }
629
630 if(noAXFRBecauseOfNSEC3Narrow) {
e6a9dde5 631 g_log<<Logger::Error<<"AXFR of domain '"<<target<<"' denied to "<<q->getRemote()<<endl;
22893145
CH
632 outpacket->setRcode(RCode::Refused);
633 // FIXME: should actually figure out if we are auth over a zone, and send out 9 if we aren't
634 sendPacket(outpacket,outsock);
635 return 0;
636 }
637
78bcb858 638 TSIGRecordContent trc;
7abbc40f
PD
639 DNSName tsigkeyname;
640 string tsigsecret;
78bcb858 641
ea3816cf 642 bool haveTSIGDetails = q->getTSIGDetails(&trc, &tsigkeyname);
78bcb858 643
60a1c204 644 if(haveTSIGDetails && !tsigkeyname.empty()) {
2c26f25a 645 string tsig64;
3343ad1f 646 DNSName algorithm=trc.d_algoName; // FIXME400: check
290a083d 647 if (algorithm == DNSName("hmac-md5.sig-alg.reg.int"))
648 algorithm = DNSName("hmac-md5");
649 if (algorithm != DNSName("gss-tsig")) {
ea99d474 650 if(!db.getTSIGKey(tsigkeyname, &algorithm, &tsig64)) {
e6a9dde5 651 g_log<<Logger::Error<<"TSIG key '"<<tsigkeyname<<"' for domain '"<<target<<"' not found"<<endl;
53ace5d5
PL
652 return 0;
653 }
654 if (B64Decode(tsig64, tsigsecret) == -1) {
e6a9dde5 655 g_log<<Logger::Error<<"Unable to Base-64 decode TSIG key '"<<tsigkeyname<<"' for domain '"<<target<<"'"<<endl;
53ace5d5
PL
656 return 0;
657 }
84fc3f8b 658 }
78bcb858 659 }
8e9b7d99 660
8e9b7d99 661
8267bd2c 662 // SOA *must* go out first, our signing pipe might reorder
e6a9dde5 663 DLOG(g_log<<"Sending out SOA"<<endl);
13f9e280
CH
664 DNSZoneRecord soa = makeEditedDNSZRFromSOAData(dk, sd);
665 outpacket->addRecord(soa);
3c68fb14 666 if(securedZone && !presignedZone) {
7abbc40f 667 set<DNSName> authSet;
8d3cbffa 668 authSet.insert(target);
ea99d474 669 addRRSigs(dk, db, authSet, outpacket->getRRS());
8d3cbffa 670 }
8e9b7d99 671
60a1c204 672 if(haveTSIGDetails && !tsigkeyname.empty())
78bcb858
BH
673 outpacket->setTSIGDetails(trc, tsigkeyname, tsigsecret, trc.d_mac); // first answer is 'normal'
674
8267bd2c 675 sendPacket(outpacket, outsock);
78bcb858
BH
676
677 trc.d_mac = outpacket->d_trc.d_mac;
8267bd2c
BH
678 outpacket = getFreshAXFRPacket(q);
679
3c68fb14 680 ChunkedSigningPipe csp(target, (securedZone && !presignedZone), ::arg().asNum("signing-threads", 1));
8e9b7d99 681
6e8694df 682 typedef map<DNSName, NSECXEntry, CanonDNSNameCompare> nsecxrepo_t;
9d3151d9 683 nsecxrepo_t nsecxrepo;
4888e4b2
BH
684
685 // this is where the DNSKEYs go in
0c350cb5 686
4c1474f3 687 DNSSECKeeper::keyset_t keys = dk.getKeys(target);
0c350cb5 688
90ba52e0 689 DNSZoneRecord zrr;
0c350cb5 690
90ba52e0 691 zrr.dr.d_name = target;
692 zrr.dr.d_ttl = sd.default_ttl;
693 zrr.auth = 1; // please sign!
794c2f92 694
991a0977 695 string publishCDNSKEY, publishCDS;
0900d2d3
CH
696 dk.getFromMeta(q->qdomain, "PUBLISH-CDNSKEY", publishCDNSKEY);
697 dk.getFromMeta(q->qdomain, "PUBLISH-CDS", publishCDS);
90ba52e0 698 vector<DNSZoneRecord> cds, cdnskey;
f889ab99
PL
699 DNSSECKeeper::keyset_t entryPoints = dk.getEntryPoints(q->qdomain);
700 set<uint32_t> entryPointIds;
701 for (auto const& value : entryPoints)
702 entryPointIds.insert(value.second.id);
991a0977 703
ff05fd12 704 for(const DNSSECKeeper::keyset_t::value_type& value : keys) {
90ba52e0 705 zrr.dr.d_type = QType::DNSKEY;
706 zrr.dr.d_content = std::make_shared<DNSKEYRecordContent>(value.first.getDNSKEY());
6e8694df 707 DNSName keyname = NSEC3Zone ? DNSName(toBase32Hex(hashQNameWithSalt(ns3pr, zrr.dr.d_name))) : zrr.dr.d_name;
9d3151d9 708 NSECXEntry& ne = nsecxrepo[keyname];
b317b510 709
22a0ef16 710 ne.d_set.set(zrr.dr.d_type);
794c2f92 711 ne.d_ttl = sd.default_ttl;
90ba52e0 712 csp.submit(zrr);
991a0977
PL
713
714 // generate CDS and CDNSKEY records
f889ab99 715 if(entryPointIds.count(value.second.id) > 0){
991a0977 716 if(publishCDNSKEY == "1") {
90ba52e0 717 zrr.dr.d_type=QType::CDNSKEY;
718 zrr.dr.d_content = std::make_shared<DNSKEYRecordContent>(value.first.getDNSKEY());
719 cdnskey.push_back(zrr);
991a0977
PL
720 }
721
722 if(!publishCDS.empty()){
90ba52e0 723 zrr.dr.d_type=QType::CDS;
991a0977
PL
724 vector<string> digestAlgos;
725 stringtok(digestAlgos, publishCDS, ", ");
56225bd3 726 for(auto const &digestAlgo : digestAlgos) {
90ba52e0 727 zrr.dr.d_content=std::make_shared<DSRecordContent>(makeDSFromDNSKey(target, value.first.getDNSKEY(), pdns_stou(digestAlgo)));
728 cds.push_back(zrr);
991a0977
PL
729 }
730 }
731 }
4c1474f3 732 }
0c350cb5 733
cc8df07f 734 if(::arg().mustDo("direct-dnskey")) {
6dae726d 735 sd.db->lookup(QType(QType::DNSKEY), target, NULL, sd.domain_id);
90ba52e0 736 while(sd.db->get(zrr)) {
737 zrr.dr.d_ttl = sd.default_ttl;
738 csp.submit(zrr);
6dae726d
PD
739 }
740 }
741
b8adb30d
KM
742 uint8_t flags;
743
95c5bc40 744 if(NSEC3Zone) { // now stuff in the NSEC3PARAM
b8adb30d 745 flags = ns3pr.d_flags;
90ba52e0 746 zrr.dr.d_type = QType::NSEC3PARAM;
95c5bc40 747 ns3pr.d_flags = 0;
90ba52e0 748 zrr.dr.d_content = std::make_shared<NSEC3PARAMRecordContent>(ns3pr);
b8adb30d 749 ns3pr.d_flags = flags;
6e8694df 750 DNSName keyname = DNSName(toBase32Hex(hashQNameWithSalt(ns3pr, zrr.dr.d_name)));
ce464268
BH
751 NSECXEntry& ne = nsecxrepo[keyname];
752
22a0ef16 753 ne.d_set.set(zrr.dr.d_type);
90ba52e0 754 csp.submit(zrr);
ce464268 755 }
8e9b7d99 756
0c350cb5
BH
757 // now start list zone
758 if(!(sd.db->list(target, sd.domain_id))) {
e6a9dde5 759 g_log<<Logger::Error<<"Backend signals error condition"<<endl;
9c556f63 760 outpacket->setRcode(RCode::ServFail);
0c350cb5
BH
761 sendPacket(outpacket,outsock);
762 return 0;
763 }
764
b772ffea 765
5633a4af 766 const bool rectify = !(presignedZone || ::arg().mustDo("disable-axfr-rectify"));
7abbc40f 767 set<DNSName> qnames, nsset, terms;
90ba52e0 768 vector<DNSZoneRecord> zrrs;
b772ffea 769
991a0977 770 // Add the CDNSKEY and CDS records we created earlier
cece60fc
CH
771 for (auto const &synth_zrr : cds)
772 zrrs.push_back(synth_zrr);
90ba52e0 773
cece60fc
CH
774 for (auto const &synth_zrr : cdnskey)
775 zrrs.push_back(synth_zrr);
90ba52e0 776
777 while(sd.db->get(zrr)) {
8bf260dd 778 zrr.dr.d_name.makeUsLowerCase();
90ba52e0 779 if(zrr.dr.d_name.isPartOf(target)) {
780 if (zrr.dr.d_type == QType::ALIAS && ::arg().mustDo("outgoing-axfr-expand-alias")) {
781 vector<DNSZoneRecord> ips;
782 int ret1 = stubDoResolve(getRR<ALIASRecordContent>(zrr.dr)->d_content, QType::A, ips);
783 int ret2 = stubDoResolve(getRR<ALIASRecordContent>(zrr.dr)->d_content, QType::AAAA, ips);
273d88b2 784 if(ret1 != RCode::NoError || ret2 != RCode::NoError) {
e6a9dde5 785 g_log<<Logger::Error<<"Error resolving for ALIAS "<<zrr.dr.d_content->getZoneRepresentation()<<", aborting AXFR"<<endl;
9c556f63 786 outpacket->setRcode(RCode::ServFail);
273d88b2
PD
787 sendPacket(outpacket,outsock);
788 return 0;
789 }
d86e1bf7 790 for(const auto& ip: ips) {
90ba52e0 791 zrr.dr.d_type = ip.dr.d_type;
0438fd89 792 zrr.dr.d_content = ip.dr.d_content;
90ba52e0 793 zrrs.push_back(zrr);
d86e1bf7 794 }
a68df29d 795 continue;
d86e1bf7
PD
796 }
797
b772ffea 798 if (rectify) {
90ba52e0 799 if (zrr.dr.d_type) {
800 qnames.insert(zrr.dr.d_name);
801 if(zrr.dr.d_type == QType::NS && zrr.dr.d_name!=target)
802 nsset.insert(zrr.dr.d_name);
b772ffea
KM
803 } else {
804 // remove existing ents
805 continue;
806 }
807 }
a68df29d 808 zrrs.push_back(zrr);
b772ffea 809 } else {
90ba52e0 810 if (zrr.dr.d_type)
e6a9dde5 811 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
812 }
813 }
814
75f2589f 815 // Group records by name and type, signpipe stumbles over interrupted rrsets
22a676e0 816 if(securedZone && !presignedZone) {
8daafcc1
KM
817 sort(zrrs.begin(), zrrs.end(), [](const DNSZoneRecord& a, const DNSZoneRecord& b) {
818 return tie(a.dr.d_name, a.dr.d_type) < tie(b.dr.d_name, b.dr.d_type);
819 });
820 }
75f2589f 821
b772ffea
KM
822 if(rectify) {
823 // set auth
2010ac95
RG
824 for(DNSZoneRecord &loopZRR : zrrs) {
825 loopZRR.auth=true;
826 if (loopZRR.dr.d_type != QType::NS || loopZRR.dr.d_name!=target) {
827 DNSName shorter(loopZRR.dr.d_name);
b772ffea 828 do {
e325f20c 829 if (shorter==target) // apex is always auth
cb045f61 830 break;
2010ac95
RG
831 if(nsset.count(shorter) && !(loopZRR.dr.d_name==shorter && loopZRR.dr.d_type == QType::DS)) {
832 loopZRR.auth=false;
cb045f61 833 break;
9f70b77a 834 }
7abbc40f 835 } while(shorter.chopOff());
9f70b77a 836 }
b772ffea
KM
837 }
838
839 if(NSEC3Zone) {
840 // ents are only required for NSEC3 zones
841 uint32_t maxent = ::arg().asNum("max-ent-entries");
6ded341a 842 set<DNSName> nsec3set, nonterm;
2010ac95 843 for (auto &loopZRR: zrrs) {
6ded341a 844 bool skip=false;
2010ac95 845 DNSName shorter = loopZRR.dr.d_name;
6ded341a
KM
846 if (shorter != target && shorter.chopOff() && shorter != target) {
847 do {
848 if(nsset.count(shorter)) {
849 skip=true;
850 break;
851 }
852 } while(shorter.chopOff() && shorter != target);
853 }
2010ac95
RG
854 shorter = loopZRR.dr.d_name;
855 if(!skip && (loopZRR.dr.d_type != QType::NS || !ns3pr.d_flags)) {
6ded341a
KM
856 do {
857 if(!nsec3set.count(shorter)) {
858 nsec3set.insert(shorter);
859 }
860 } while(shorter != target && shorter.chopOff());
861 }
862 }
863
2010ac95
RG
864 for(DNSZoneRecord &loopZRR : zrrs) {
865 DNSName shorter(loopZRR.dr.d_name);
e325f20c 866 while(shorter != target && shorter.chopOff()) {
6ded341a 867 if(!qnames.count(shorter) && !nonterm.count(shorter) && nsec3set.count(shorter)) {
b772ffea 868 if(!(maxent)) {
e6a9dde5 869 g_log<<Logger::Warning<<"Zone '"<<target<<"' has too many empty non terminals."<<endl;
b772ffea
KM
870 return 0;
871 }
6ded341a
KM
872 nonterm.insert(shorter);
873 --maxent;
b772ffea
KM
874 }
875 }
876 }
877
9e23e712 878 for(const auto& nt : nonterm) {
2010ac95
RG
879 DNSZoneRecord tempRR;
880 tempRR.dr.d_name=nt;
881 tempRR.dr.d_type=QType::ENT;
882 tempRR.auth=true;
883 zrrs.push_back(tempRR);
b772ffea
KM
884 }
885 }
886 }
887
888
12c86877 889 /* now write all other records */
8e9b7d99 890
6e8694df 891 DNSName keyname;
3370c993 892 unsigned int udiff;
1c6d9830
BH
893 DTime dt;
894 dt.set();
bec14a20 895 int records=0;
2010ac95 896 for(DNSZoneRecord &loopZRR : zrrs) {
3c68fb14 897 if (!presignedZone && loopZRR.dr.d_type == QType::RRSIG)
794c2f92 898 continue;
6dae726d 899
991a0977 900 // only skip the DNSKEY, CDNSKEY and CDS if direct-dnskey is enabled, to avoid changing behaviour
6dae726d 901 // when it is not enabled.
2010ac95 902 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
903 continue;
904
bec14a20 905 records++;
2010ac95
RG
906 if(securedZone && (loopZRR.auth || loopZRR.dr.d_type == QType::NS)) {
907 if (NSEC3Zone || loopZRR.dr.d_type) {
3c68fb14
KM
908 if (presignedZone && NSEC3Zone && loopZRR.dr.d_type == QType::RRSIG && getRR<RRSIGRecordContent>(loopZRR.dr)->d_type == QType::NSEC3) {
909 keyname = loopZRR.dr.d_name.makeRelative(sd.qname);
910 } else {
911 keyname = NSEC3Zone ? DNSName(toBase32Hex(hashQNameWithSalt(ns3pr, loopZRR.dr.d_name))) : loopZRR.dr.d_name;
912 }
b5baefaf
PD
913 NSECXEntry& ne = nsecxrepo[keyname];
914 ne.d_ttl = sd.default_ttl;
3c68fb14
KM
915 ne.d_auth = (ne.d_auth || loopZRR.auth || (NSEC3Zone && (!ns3pr.d_flags)));
916 if (loopZRR.dr.d_type && loopZRR.dr.d_type != QType::RRSIG) {
22a0ef16 917 ne.d_set.set(loopZRR.dr.d_type);
b5baefaf
PD
918 }
919 }
b317b510 920 }
b5baefaf 921
2010ac95 922 if (!loopZRR.dr.d_type)
b5baefaf
PD
923 continue; // skip empty non-terminals
924
2010ac95 925 if(loopZRR.dr.d_type == QType::SOA)
12c86877 926 continue; // skip SOA - would indicate end of AXFR
add640c0 927
2010ac95 928 if(csp.submit(loopZRR)) {
1c6d9830
BH
929 for(;;) {
930 outpacket->getRRS() = csp.getChunk();
931 if(!outpacket->getRRS().empty()) {
60a1c204 932 if(haveTSIGDetails && !tsigkeyname.empty())
54d84273 933 outpacket->setTSIGDetails(trc, tsigkeyname, tsigsecret, trc.d_mac, true);
1c6d9830 934 sendPacket(outpacket, outsock);
78bcb858 935 trc.d_mac=outpacket->d_trc.d_mac;
1c6d9830
BH
936 outpacket=getFreshAXFRPacket(q);
937 }
938 else
939 break;
940 }
12c86877
BH
941 }
942 }
78bcb858 943 /*
3370c993 944 udiff=dt.udiffNoReset();
1c6d9830
BH
945 cerr<<"Starting NSEC: "<<csp.d_signed/(udiff/1000000.0)<<" sigs/s, "<<csp.d_signed<<" / "<<udiff/1000000.0<<endl;
946 cerr<<"Outstanding: "<<csp.d_outstanding<<", "<<csp.d_queued - csp.d_signed << endl;
947 cerr<<"Ready for consumption: "<<csp.getReady()<<endl;
78bcb858 948 */
feef1ece 949 if(securedZone) {
4888e4b2 950 if(NSEC3Zone) {
9d3151d9 951 for(nsecxrepo_t::const_iterator iter = nsecxrepo.begin(); iter != nsecxrepo.end(); ++iter) {
3c68fb14 952 if(iter->second.d_auth) {
feef1ece 953 NSEC3RecordContent n3rc;
22a0ef16 954 n3rc.set(iter->second.d_set);
27d4a65b
RG
955 const auto numberOfTypesSet = n3rc.numberOfTypesSet();
956 if (numberOfTypesSet != 0 && (numberOfTypesSet != 1 || !n3rc.isSet(QType::NS))) {
957 n3rc.set(QType::RRSIG);
958 }
959 n3rc.d_salt = ns3pr.d_salt;
feef1ece
PD
960 n3rc.d_flags = ns3pr.d_flags;
961 n3rc.d_iterations = ns3pr.d_iterations;
27d4a65b 962 n3rc.d_algorithm = DNSSECKeeper::SHA1; // SHA1, fixed in PowerDNS for now
feef1ece 963 nsecxrepo_t::const_iterator inext = iter;
cb167afd 964 ++inext;
feef1ece
PD
965 if(inext == nsecxrepo.end())
966 inext = nsecxrepo.begin();
3c68fb14 967 while(!inext->second.d_auth && inext != iter)
feef1ece 968 {
cb167afd 969 ++inext;
feef1ece
PD
970 if(inext == nsecxrepo.end())
971 inext = nsecxrepo.begin();
972 }
6e8694df
KM
973 n3rc.d_nexthash = fromBase32Hex(inext->first.toStringNoDot());
974 zrr.dr.d_name = iter->first+sd.qname;
90ba52e0 975
976 zrr.dr.d_ttl = sd.default_ttl;
27d4a65b 977 zrr.dr.d_content = std::make_shared<NSEC3RecordContent>(std::move(n3rc));
90ba52e0 978 zrr.dr.d_type = QType::NSEC3;
979 zrr.dr.d_place = DNSResourceRecord::ANSWER;
980 zrr.auth=true;
981 if(csp.submit(zrr)) {
feef1ece
PD
982 for(;;) {
983 outpacket->getRRS() = csp.getChunk();
984 if(!outpacket->getRRS().empty()) {
60a1c204 985 if(haveTSIGDetails && !tsigkeyname.empty())
feef1ece
PD
986 outpacket->setTSIGDetails(trc, tsigkeyname, tsigsecret, trc.d_mac, true);
987 sendPacket(outpacket, outsock);
988 trc.d_mac=outpacket->d_trc.d_mac;
989 outpacket=getFreshAXFRPacket(q);
990 }
991 else
992 break;
1c6d9830 993 }
1c6d9830 994 }
8e9b7d99 995 }
4888e4b2
BH
996 }
997 }
9d3151d9 998 else for(nsecxrepo_t::const_iterator iter = nsecxrepo.begin(); iter != nsecxrepo.end(); ++iter) {
ed9c3a50 999 NSECRecordContent nrc;
22a0ef16 1000 nrc.set(iter->second.d_set);
27d4a65b
RG
1001 nrc.set(QType::RRSIG);
1002 nrc.set(QType::NSEC);
6e8694df
KM
1003
1004 if(boost::next(iter) != nsecxrepo.end())
1005 nrc.d_next = boost::next(iter)->first;
ed9c3a50 1006 else
6e8694df
KM
1007 nrc.d_next=nsecxrepo.begin()->first;
1008 zrr.dr.d_name = iter->first;
1009
90ba52e0 1010 zrr.dr.d_ttl = sd.default_ttl;
27d4a65b 1011 zrr.dr.d_content = std::make_shared<NSECRecordContent>(std::move(nrc));
90ba52e0 1012 zrr.dr.d_type = QType::NSEC;
1013 zrr.dr.d_place = DNSResourceRecord::ANSWER;
1014 zrr.auth=true;
1015 if(csp.submit(zrr)) {
1c6d9830
BH
1016 for(;;) {
1017 outpacket->getRRS() = csp.getChunk();
1018 if(!outpacket->getRRS().empty()) {
60a1c204 1019 if(haveTSIGDetails && !tsigkeyname.empty())
78bcb858 1020 outpacket->setTSIGDetails(trc, tsigkeyname, tsigsecret, trc.d_mac, true);
1c6d9830 1021 sendPacket(outpacket, outsock);
78bcb858 1022 trc.d_mac=outpacket->d_trc.d_mac;
1c6d9830
BH
1023 outpacket=getFreshAXFRPacket(q);
1024 }
1025 else
1026 break;
1027 }
8e9b7d99 1028 }
add640c0 1029 }
add640c0 1030 }
78bcb858 1031 /*
3370c993 1032 udiff=dt.udiffNoReset();
1c6d9830
BH
1033 cerr<<"Flushing pipe: "<<csp.d_signed/(udiff/1000000.0)<<" sigs/s, "<<csp.d_signed<<" / "<<udiff/1000000.0<<endl;
1034 cerr<<"Outstanding: "<<csp.d_outstanding<<", "<<csp.d_queued - csp.d_signed << endl;
1035 cerr<<"Ready for consumption: "<<csp.getReady()<<endl;
78bcb858 1036 * */
bec14a20
BH
1037 for(;;) {
1038 outpacket->getRRS() = csp.getChunk(true); // flush the pipe
1039 if(!outpacket->getRRS().empty()) {
60a1c204 1040 if(haveTSIGDetails && !tsigkeyname.empty())
78bcb858 1041 outpacket->setTSIGDetails(trc, tsigkeyname, tsigsecret, trc.d_mac, true); // first answer is 'normal'
bec14a20 1042 sendPacket(outpacket, outsock);
78bcb858 1043 trc.d_mac=outpacket->d_trc.d_mac;
bec14a20
BH
1044 outpacket=getFreshAXFRPacket(q);
1045 }
1046 else
1047 break;
12c86877 1048 }
8e9b7d99 1049
1c6d9830 1050 udiff=dt.udiffNoReset();
f1f85f12 1051 if(securedZone)
e6a9dde5 1052 g_log<<Logger::Info<<"Done signing: "<<csp.d_signed/(udiff/1000000.0)<<" sigs/s, "<<endl;
1c6d9830 1053
e6a9dde5 1054 DLOG(g_log<<"Done writing out records"<<endl);
12c86877 1055 /* and terminate with yet again the SOA record */
8e9b7d99 1056 outpacket=getFreshAXFRPacket(q);
13f9e280 1057 outpacket->addRecord(soa);
60a1c204 1058 if(haveTSIGDetails && !tsigkeyname.empty())
78bcb858 1059 outpacket->setTSIGDetails(trc, tsigkeyname, tsigsecret, trc.d_mac, true);
92c90b44 1060
ff76e8b4 1061 sendPacket(outpacket, outsock);
78bcb858 1062
e6a9dde5
PL
1063 DLOG(g_log<<"last packet - close"<<endl);
1064 g_log<<Logger::Error<<"AXFR of domain '"<<target<<"' to "<<q->getRemote()<<" finished"<<endl;
12c86877
BH
1065
1066 return 1;
1067}
1068
6e59a580
KM
1069int TCPNameserver::doIXFR(shared_ptr<DNSPacket> q, int outsock)
1070{
1071 shared_ptr<DNSPacket> outpacket=getFreshAXFRPacket(q);
1072 if(q->d_dnssecOk)
1073 outpacket->d_dnssecOk=true; // RFC 5936, 2.2.5 'SHOULD'
1074
6e59a580 1075 uint32_t serial = 0;
27c0050c 1076 MOADNSParser mdp(false, q->getString());
6e59a580
KM
1077 for(MOADNSParser::answers_t::const_iterator i=mdp.d_answers.begin(); i != mdp.d_answers.end(); ++i) {
1078 const DNSRecord *rr = &i->first;
e693ff5a 1079 if (rr->d_type == QType::SOA && rr->d_place == DNSResourceRecord::AUTHORITY) {
6e59a580
KM
1080 vector<string>parts;
1081 stringtok(parts, rr->d_content->getZoneRepresentation());
1082 if (parts.size() >= 3) {
95dd3b90
RG
1083 try {
1084 serial=pdns_stou(parts[2]);
1085 }
1086 catch(const std::out_of_range& oor) {
e6a9dde5 1087 g_log<<Logger::Error<<"Invalid serial in IXFR query"<<endl;
95dd3b90
RG
1088 outpacket->setRcode(RCode::FormErr);
1089 sendPacket(outpacket,outsock);
1090 return 0;
1091 }
6e59a580 1092 } else {
e6a9dde5 1093 g_log<<Logger::Error<<"No serial in IXFR query"<<endl;
6e59a580
KM
1094 outpacket->setRcode(RCode::FormErr);
1095 sendPacket(outpacket,outsock);
1096 return 0;
1097 }
3e67ea8b 1098 } else if (rr->d_type != QType::TSIG && rr->d_type != QType::OPT) {
e6a9dde5 1099 g_log<<Logger::Error<<"Additional records in IXFR query, type: "<<QType(rr->d_type).getName()<<endl;
6e59a580
KM
1100 outpacket->setRcode(RCode::FormErr);
1101 sendPacket(outpacket,outsock);
1102 return 0;
1103 }
1104 }
1105
e6a9dde5 1106 g_log<<Logger::Error<<"IXFR of domain '"<<q->qdomain<<"' initiated by "<<q->getRemote()<<" with serial "<<serial<<endl;
6e59a580 1107
22893145 1108 // determine if zone exists and AXFR is allowed using existing backend before spawning a new backend.
6e59a580 1109 SOAData sd;
6e59a580
KM
1110 {
1111 Lock l(&s_plock);
e6a9dde5 1112 DLOG(g_log<<"Looking for SOA"<<endl); // find domain_id via SOA and list complete domain. No SOA, no IXFR
6e59a580 1113 if(!s_P) {
e6a9dde5 1114 g_log<<Logger::Error<<"TCP server is without backend connections in doIXFR, launching"<<endl;
6e59a580
KM
1115 s_P=new PacketHandler;
1116 }
1117
22893145
CH
1118 // canDoAXFR does all the ACL checks, and has the if(disable-axfr) shortcut, call it first.
1119 if(!canDoAXFR(q) || !s_P->getBackend()->getSOAUncached(q->qdomain, sd)) {
e6a9dde5 1120 g_log<<Logger::Error<<"IXFR of domain '"<<q->qdomain<<"' failed: not authoritative"<<endl;
9c556f63 1121 outpacket->setRcode(RCode::NotAuth);
6e59a580
KM
1122 sendPacket(outpacket,outsock);
1123 return 0;
1124 }
1125 }
1126
22893145
CH
1127 DNSSECKeeper dk;
1128 NSEC3PARAMRecordContent ns3pr;
1129 bool narrow;
1130
1131 dk.clearCaches(q->qdomain);
1132 bool securedZone = dk.isSecuredZone(q->qdomain);
1133 if(dk.getNSEC3PARAM(q->qdomain, &ns3pr, &narrow)) {
1134 if(narrow) {
e6a9dde5
PL
1135 g_log<<Logger::Error<<"Not doing IXFR of an NSEC3 narrow zone."<<endl;
1136 g_log<<Logger::Error<<"IXFR of domain '"<<q->qdomain<<"' denied to "<<q->getRemote()<<endl;
22893145
CH
1137 outpacket->setRcode(RCode::Refused);
1138 sendPacket(outpacket,outsock);
1139 return 0;
1140 }
1141 }
1142
7abbc40f 1143 DNSName target = q->qdomain;
6e59a580
KM
1144
1145 UeberBackend db;
79ba7763 1146 if(!db.getSOAUncached(target, sd)) {
e6a9dde5 1147 g_log<<Logger::Error<<"IXFR of domain '"<<target<<"' failed: not authoritative in second instance"<<endl;
79ba7763 1148 outpacket->setRcode(RCode::NotAuth);
6e59a580
KM
1149 sendPacket(outpacket,outsock);
1150 return 0;
1151 }
24d9e514 1152
13f9e280 1153 if (!rfc1982LessThan(serial, calculateEditSOA(sd.serial, dk, sd.qname))) {
6e59a580 1154 TSIGRecordContent trc;
7abbc40f
PD
1155 DNSName tsigkeyname;
1156 string tsigsecret;
6e59a580 1157
ea3816cf 1158 bool haveTSIGDetails = q->getTSIGDetails(&trc, &tsigkeyname);
6e59a580 1159
60a1c204 1160 if(haveTSIGDetails && !tsigkeyname.empty()) {
bb7fb11c 1161 string tsig64;
3343ad1f 1162 DNSName algorithm=trc.d_algoName; // FIXME400: was toLowerCanonic, compare output
290a083d 1163 if (algorithm == DNSName("hmac-md5.sig-alg.reg.int"))
1164 algorithm = DNSName("hmac-md5");
6e59a580 1165 Lock l(&s_plock);
53ace5d5 1166 if(!s_P->getBackend()->getTSIGKey(tsigkeyname, &algorithm, &tsig64)) {
e6a9dde5 1167 g_log<<Logger::Error<<"TSIG key '"<<tsigkeyname<<"' for domain '"<<target<<"' not found"<<endl;
53ace5d5
PL
1168 return 0;
1169 }
1170 if (B64Decode(tsig64, tsigsecret) == -1) {
e6a9dde5 1171 g_log<<Logger::Error<<"Unable to Base-64 decode TSIG key '"<<tsigkeyname<<"' for domain '"<<target<<"'"<<endl;
53ace5d5
PL
1172 return 0;
1173 }
6e59a580
KM
1174 }
1175
1176 UeberBackend signatureDB;
1177
1178 // SOA *must* go out first, our signing pipe might reorder
e6a9dde5 1179 DLOG(g_log<<"Sending out SOA"<<endl);
13f9e280
CH
1180 DNSZoneRecord soa = makeEditedDNSZRFromSOAData(dk, sd);
1181 outpacket->addRecord(soa);
6e59a580 1182 if(securedZone) {
7abbc40f 1183 set<DNSName> authSet;
6e59a580
KM
1184 authSet.insert(target);
1185 addRRSigs(dk, signatureDB, authSet, outpacket->getRRS());
1186 }
1187
60a1c204 1188 if(haveTSIGDetails && !tsigkeyname.empty())
6e59a580
KM
1189 outpacket->setTSIGDetails(trc, tsigkeyname, tsigsecret, trc.d_mac); // first answer is 'normal'
1190
1191 sendPacket(outpacket, outsock);
1192
e6a9dde5 1193 g_log<<Logger::Error<<"IXFR of domain '"<<target<<"' to "<<q->getRemote()<<" finished"<<endl;
6e59a580
KM
1194
1195 return 1;
1196 }
1197
e6a9dde5 1198 g_log<<Logger::Error<<"IXFR fallback to AXFR for domain '"<<target<<"' our serial "<<sd.serial<<endl;
6e59a580
KM
1199 return doAXFR(q->qdomain, q, outsock);
1200}
1201
12c86877
BH
1202TCPNameserver::~TCPNameserver()
1203{
1204 delete d_connectionroom_sem;
1205}
1206
1207TCPNameserver::TCPNameserver()
1208{
cb0af1a1
RG
1209 d_maxTransactionsPerConn = ::arg().asNum("max-tcp-transactions-per-conn");
1210 d_idleTimeout = ::arg().asNum("tcp-idle-timeout");
1211 d_maxConnectionDuration = ::arg().asNum("max-tcp-connection-duration");
1212 d_maxConnectionsPerClient = ::arg().asNum("max-tcp-connections-per-client");
1213
379ab445
BH
1214// sem_init(&d_connectionroom_sem,0,::arg().asNum("max-tcp-connections"));
1215 d_connectionroom_sem = new Semaphore( ::arg().asNum( "max-tcp-connections" ));
117e1bf2 1216 d_tid=0;
12c86877 1217 vector<string>locals;
379ab445 1218 stringtok(locals,::arg()["local-address"]," ,");
12c86877
BH
1219
1220 vector<string>locals6;
379ab445 1221 stringtok(locals6,::arg()["local-ipv6"]," ,");
12c86877 1222
12c86877 1223 if(locals.empty() && locals6.empty())
3f81d239 1224 throw PDNSException("No local address specified");
12c86877 1225
68b011bd 1226 d_ng.toMasks(::arg()["allow-axfr-ips"] );
9f1d5826 1227
12c86877 1228 signal(SIGPIPE,SIG_IGN);
12c86877
BH
1229
1230 for(vector<string>::const_iterator laddr=locals.begin();laddr!=locals.end();++laddr) {
12c86877 1231 int s=socket(AF_INET,SOCK_STREAM,0);
326484be 1232
12c86877 1233 if(s<0)
3f81d239 1234 throw PDNSException("Unable to acquire TCP socket: "+stringerror());
12c86877 1235
3897b9e1 1236 setCloseOnExec(s);
fb316318 1237
379ab445 1238 ComboAddress local(*laddr, ::arg().asNum("local-port"));
12c86877
BH
1239
1240 int tmp=1;
1241 if(setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(char*)&tmp,sizeof tmp)<0) {
e6a9dde5 1242 g_log<<Logger::Error<<"Setsockopt failed"<<endl;
5bd2ea7b 1243 _exit(1);
12c86877 1244 }
940d7811
RG
1245
1246 if (::arg().asNum("tcp-fast-open") > 0) {
1247#ifdef TCP_FASTOPEN
1248 int fastOpenQueueSize = ::arg().asNum("tcp-fast-open");
1249 if (setsockopt(s, IPPROTO_TCP, TCP_FASTOPEN, &fastOpenQueueSize, sizeof fastOpenQueueSize) < 0) {
e6a9dde5 1250 g_log<<Logger::Error<<"Failed to enable TCP Fast Open for listening socket: "<<strerror(errno)<<endl;
940d7811
RG
1251 }
1252#else
e6a9dde5 1253 g_log<<Logger::Warning<<"TCP Fast Open configured but not supported for listening socket"<<endl;
940d7811
RG
1254#endif
1255 }
1256
fec7dd5a
SS
1257 if( ::arg().mustDo("non-local-bind") )
1258 Utility::setBindAny(AF_INET, s);
1259
379ab445 1260 if(::bind(s, (sockaddr*)&local, local.getSocklen())<0) {
2c896042 1261 close(s);
5ecb2885 1262 if( errno == EADDRNOTAVAIL && ! ::arg().mustDo("local-address-nonexist-fail") ) {
e6a9dde5 1263 g_log<<Logger::Error<<"IPv4 Address " << *laddr << " does not exist on this server - skipping TCP bind" << endl;
5ecb2885
MZ
1264 continue;
1265 } else {
e6a9dde5 1266 g_log<<Logger::Error<<"Unable to bind to TCP socket " << *laddr << ": "<<strerror(errno)<<endl;
2ab7e9ac 1267 throw PDNSException("Unable to bind to TCP socket");
5ecb2885 1268 }
12c86877
BH
1269 }
1270
1271 listen(s,128);
e6a9dde5 1272 g_log<<Logger::Error<<"TCP server bound to "<<local.toStringWithPort()<<endl;
12c86877 1273 d_sockets.push_back(s);
8edfedf1
BH
1274 struct pollfd pfd;
1275 memset(&pfd, 0, sizeof(pfd));
1276 pfd.fd = s;
1277 pfd.events = POLLIN;
1278
1279 d_prfds.push_back(pfd);
12c86877
BH
1280 }
1281
12c86877 1282 for(vector<string>::const_iterator laddr=locals6.begin();laddr!=locals6.end();++laddr) {
12c86877
BH
1283 int s=socket(AF_INET6,SOCK_STREAM,0);
1284
1285 if(s<0)
3f81d239 1286 throw PDNSException("Unable to acquire TCPv6 socket: "+stringerror());
178d5134 1287
3897b9e1 1288 setCloseOnExec(s);
fb316318 1289
379ab445 1290 ComboAddress local(*laddr, ::arg().asNum("local-port"));
12c86877
BH
1291
1292 int tmp=1;
1293 if(setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(char*)&tmp,sizeof tmp)<0) {
e6a9dde5 1294 g_log<<Logger::Error<<"Setsockopt failed"<<endl;
5bd2ea7b 1295 _exit(1);
12c86877 1296 }
940d7811
RG
1297
1298 if (::arg().asNum("tcp-fast-open") > 0) {
1299#ifdef TCP_FASTOPEN
1300 int fastOpenQueueSize = ::arg().asNum("tcp-fast-open");
1301 if (setsockopt(s, IPPROTO_TCP, TCP_FASTOPEN, &fastOpenQueueSize, sizeof fastOpenQueueSize) < 0) {
e6a9dde5 1302 g_log<<Logger::Error<<"Failed to enable TCP Fast Open for listening socket: "<<strerror(errno)<<endl;
940d7811
RG
1303 }
1304#else
e6a9dde5 1305 g_log<<Logger::Warning<<"TCP Fast Open configured but not supported for listening socket"<<endl;
940d7811
RG
1306#endif
1307 }
1308
fec7dd5a
SS
1309 if( ::arg().mustDo("non-local-bind") )
1310 Utility::setBindAny(AF_INET6, s);
326484be 1311 if(setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &tmp, sizeof(tmp)) < 0) {
e6a9dde5 1312 g_log<<Logger::Error<<"Failed to set IPv6 socket to IPv6 only, continuing anyhow: "<<strerror(errno)<<endl;
326484be 1313 }
ff76e8b4 1314 if(bind(s, (const sockaddr*)&local, local.getSocklen())<0) {
2c896042 1315 close(s);
5ecb2885 1316 if( errno == EADDRNOTAVAIL && ! ::arg().mustDo("local-ipv6-nonexist-fail") ) {
e6a9dde5 1317 g_log<<Logger::Error<<"IPv6 Address " << *laddr << " does not exist on this server - skipping TCP bind" << endl;
5ecb2885
MZ
1318 continue;
1319 } else {
e6a9dde5 1320 g_log<<Logger::Error<<"Unable to bind to TCPv6 socket" << *laddr << ": "<<strerror(errno)<<endl;
2ab7e9ac 1321 throw PDNSException("Unable to bind to TCPv6 socket");
5ecb2885 1322 }
12c86877
BH
1323 }
1324
1325 listen(s,128);
e6a9dde5 1326 g_log<<Logger::Error<<"TCPv6 server bound to "<<local.toStringWithPort()<<endl; // this gets %eth0 right
12c86877 1327 d_sockets.push_back(s);
8edfedf1
BH
1328
1329 struct pollfd pfd;
1330 memset(&pfd, 0, sizeof(pfd));
1331 pfd.fd = s;
1332 pfd.events = POLLIN;
1333
1334 d_prfds.push_back(pfd);
12c86877 1335 }
12c86877
BH
1336}
1337
1338
ff76e8b4 1339//! Start of TCP operations thread, we launch a new thread for each incoming TCP question
12c86877
BH
1340void TCPNameserver::thread()
1341{
519f5484 1342 setThreadName("pdns/tcpnameser");
12c86877
BH
1343 try {
1344 for(;;) {
1345 int fd;
cb0af1a1
RG
1346 ComboAddress remote;
1347 Utility::socklen_t addrlen=remote.getSocklen();
12c86877 1348
8edfedf1 1349 int ret=poll(&d_prfds[0], d_prfds.size(), -1); // blocks, forever if need be
8a63d3ce 1350 if(ret <= 0)
4957a608 1351 continue;
8a63d3ce 1352
12c86877 1353 int sock=-1;
8ce9e4e6 1354 for(const pollfd& pfd : d_prfds) {
c1ee10a6 1355 if(pfd.revents & POLLIN) {
4957a608 1356 sock = pfd.fd;
cb0af1a1
RG
1357 remote.sin4.sin_family = AF_INET6;
1358 addrlen=remote.getSocklen();
4957a608
BH
1359
1360 if((fd=accept(sock, (sockaddr*)&remote, &addrlen))<0) {
e6a9dde5 1361 g_log<<Logger::Error<<"TCP question accept error: "<<strerror(errno)<<endl;
4957a608
BH
1362
1363 if(errno==EMFILE) {
e6a9dde5 1364 g_log<<Logger::Error<<"TCP handler out of filedescriptors, exiting, won't recover from this"<<endl;
5bd2ea7b 1365 _exit(1);
4957a608
BH
1366 }
1367 }
1368 else {
cb0af1a1
RG
1369 if (d_maxConnectionsPerClient) {
1370 std::lock_guard<std::mutex> lock(s_clientsCountMutex);
1371 if (s_clientsCount[remote] >= d_maxConnectionsPerClient) {
e6a9dde5 1372 g_log<<Logger::Notice<<"Limit of simultaneous TCP connections per client reached for "<< remote<<", dropping"<<endl;
cb0af1a1
RG
1373 close(fd);
1374 continue;
1375 }
1376 s_clientsCount[remote]++;
1377 }
1378
4957a608
BH
1379 pthread_t tid;
1380 d_connectionroom_sem->wait(); // blocks if no connections are available
1381
1382 int room;
1383 d_connectionroom_sem->getValue( &room);
1384 if(room<1)
e6a9dde5 1385 g_log<<Logger::Warning<<"Limit of simultaneous TCP connections reached - raise max-tcp-connections"<<endl;
4957a608 1386
222efdc0 1387 if(pthread_create(&tid, 0, &doConnection, reinterpret_cast<void*>(fd))) {
e6a9dde5 1388 g_log<<Logger::Error<<"Error creating thread: "<<stringerror()<<endl;
4957a608 1389 d_connectionroom_sem->post();
48e8d70b 1390 close(fd);
cb0af1a1 1391 decrementClientCount(remote);
4957a608
BH
1392 }
1393 }
1394 }
12c86877
BH
1395 }
1396 }
1397 }
3f81d239 1398 catch(PDNSException &AE) {
e6a9dde5 1399 g_log<<Logger::Error<<"TCP Nameserver thread dying because of fatal error: "<<AE.reason<<endl;
12c86877
BH
1400 }
1401 catch(...) {
e6a9dde5 1402 g_log<<Logger::Error<<"TCPNameserver dying because of an unexpected fatal error"<<endl;
12c86877 1403 }
5bd2ea7b 1404 _exit(1); // take rest of server with us
12c86877
BH
1405}
1406
1407