]> git.ipfire.org Git - thirdparty/pdns.git/blame - pdns/tcpreceiver.cc
update pdns.conf-dist with udp-truncation-threshold setting
[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
8
12c86877
BH
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
06bd9ccf 16 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
12c86877 17*/
379ab445 18#include "packetcache.hh"
1258abe0 19#include "utility.hh"
add640c0 20#include "dnssecinfra.hh"
4c1474f3 21#include "dnsseckeeper.hh"
12c86877 22#include <cstdio>
4888e4b2 23#include "base32.hh"
12c86877
BH
24#include <cstring>
25#include <cstdlib>
26#include <sys/types.h>
27#include <iostream>
28#include <string>
29#include "tcpreceiver.hh"
67d74e49 30#include "sstuff.hh"
8edfedf1 31#include <boost/foreach.hpp>
12c86877
BH
32#include <errno.h>
33#include <signal.h>
78bcb858 34#include "base64.hh"
12c86877
BH
35#include "ueberbackend.hh"
36#include "dnspacket.hh"
37#include "nameserver.hh"
38#include "distributor.hh"
39#include "lock.hh"
40#include "logger.hh"
41#include "arguments.hh"
379ab445 42
12c86877
BH
43#include "packethandler.hh"
44#include "statbag.hh"
45#include "resolver.hh"
46#include "communicator.hh"
61b26744 47#include "namespaces.hh"
8e9b7d99 48#include "signingpipe.hh"
12c86877
BH
49extern PacketCache PC;
50extern StatBag S;
51
52/**
53\file tcpreceiver.cc
54\brief This file implements the tcpreceiver that receives and answers questions over TCP/IP
55*/
56
ac2bb9e7 57pthread_mutex_t TCPNameserver::s_plock = PTHREAD_MUTEX_INITIALIZER;
12c86877
BH
58Semaphore *TCPNameserver::d_connectionroom_sem;
59PacketHandler *TCPNameserver::s_P;
60int TCPNameserver::s_timeout;
9f1d5826 61NetmaskGroup TCPNameserver::d_ng;
12c86877 62
12c86877
BH
63void TCPNameserver::go()
64{
65 L<<Logger::Error<<"Creating backend connection for TCP"<<endl;
66 s_P=0;
67 try {
68 s_P=new PacketHandler;
69 }
70 catch(AhuException &ae) {
71 L<<Logger::Error<<Logger::NTLog<<"TCP server is unable to launch backends - will try again when questions come in"<<endl;
fd8bc993 72 L<<Logger::Error<<"TCP server is unable to launch backends - will try again when questions come in: "<<ae.reason<<endl;
12c86877
BH
73 }
74 pthread_create(&d_tid, 0, launcher, static_cast<void *>(this));
75}
76
77void *TCPNameserver::launcher(void *data)
78{
79 static_cast<TCPNameserver *>(data)->thread();
80 return 0;
81}
82
6a3e5d1a
BH
83// throws AhuException if things didn't go according to plan, returns 0 if really 0 bytes were read
84int readnWithTimeout(int fd, void* buffer, unsigned int n, bool throwOnEOF=true)
12c86877 85{
6a3e5d1a
BH
86 unsigned int bytes=n;
87 char *ptr = (char*)buffer;
88 int ret;
89 while(bytes) {
90 ret=read(fd, ptr, bytes);
91 if(ret < 0) {
92 if(errno==EAGAIN) {
4957a608
BH
93 ret=waitForData(fd, 5);
94 if(ret < 0)
95 throw NetworkError("Waiting for data read");
96 if(!ret)
97 throw NetworkError("Timeout reading data");
98 continue;
6a3e5d1a
BH
99 }
100 else
4957a608 101 throw NetworkError("Reading data: "+stringerror());
6a3e5d1a
BH
102 }
103 if(!ret) {
104 if(!throwOnEOF && n == bytes)
4957a608 105 return 0;
6a3e5d1a 106 else
4957a608 107 throw NetworkError("Did not fulfill read from TCP due to EOF");
6a3e5d1a
BH
108 }
109
110 ptr += ret;
111 bytes -= ret;
112 }
113 return n;
114}
12c86877 115
6a3e5d1a
BH
116// ditto
117void writenWithTimeout(int fd, const void *buffer, unsigned int n)
118{
119 unsigned int bytes=n;
120 const char *ptr = (char*)buffer;
121 int ret;
122 while(bytes) {
123 ret=write(fd, ptr, bytes);
124 if(ret < 0) {
125 if(errno==EAGAIN) {
4957a608
BH
126 ret=waitForRWData(fd, false, 5, 0);
127 if(ret < 0)
128 throw NetworkError("Waiting for data write");
129 if(!ret)
130 throw NetworkError("Timeout writing data");
131 continue;
6a3e5d1a
BH
132 }
133 else
4957a608 134 throw NetworkError("Writing data: "+stringerror());
6a3e5d1a 135 }
12c86877 136 if(!ret) {
67d74e49 137 throw NetworkError("Did not fulfill TCP write due to EOF");
12c86877 138 }
6a3e5d1a
BH
139
140 ptr += ret;
141 bytes -= ret;
12c86877 142 }
12c86877
BH
143}
144
6a3e5d1a 145void connectWithTimeout(int fd, struct sockaddr* remote, size_t socklen)
12c86877 146{
6a3e5d1a
BH
147 int err;
148 Utility::socklen_t len=sizeof(err);
149
150#ifndef WIN32
151 if((err=connect(fd, remote, socklen))<0 && errno!=EINPROGRESS)
152#else
153 if((err=connect(clisock, remote, socklen))<0 && WSAGetLastError() != WSAEWOULDBLOCK )
154#endif // WIN32
67d74e49 155 throw NetworkError("connect: "+stringerror());
6a3e5d1a
BH
156
157 if(!err)
158 goto done;
159
160 err=waitForRWData(fd, false, 5, 0);
161 if(err == 0)
67d74e49 162 throw NetworkError("Timeout connecting to remote");
6a3e5d1a 163 if(err < 0)
67d74e49 164 throw NetworkError("Error connecting to remote");
12c86877 165
6a3e5d1a 166 if(getsockopt(fd, SOL_SOCKET,SO_ERROR,(char *)&err,&len)<0)
67d74e49 167 throw NetworkError("Error connecting to remote: "+stringerror()); // Solaris
6a3e5d1a
BH
168
169 if(err)
67d74e49 170 throw NetworkError("Error connecting to remote: "+string(strerror(err)));
6a3e5d1a
BH
171
172 done:
173 ;
174}
12c86877 175
6a3e5d1a
BH
176void TCPNameserver::sendPacket(shared_ptr<DNSPacket> p, int outsock)
177{
9951e2d0
KM
178
179 /* Query statistics */
180 if(p->qtype.getCode()!=QType::AXFR && p->qtype.getCode()!=QType::IXFR) {
181 if(p->d.aa) {
182 if(p->d.rcode==RCode::NXDomain)
183 S.ringAccount("nxdomain-queries",p->qdomain+"/"+p->qtype.getName());
184 } else if(p->isEmpty()) {
4dbda652 185 S.ringAccount("unauth-queries",p->qdomain+"/"+p->qtype.getName());
9951e2d0
KM
186 S.ringAccount("remotes-unauth",p->getRemote());
187 }
188 }
189
fbaa5e09
BH
190 uint16_t len=htons(p->getString().length());
191 string buffer((const char*)&len, 2);
192 buffer.append(p->getString());
78bcb858 193 writenWithTimeout(outsock, buffer.c_str(), buffer.length());
6a3e5d1a
BH
194}
195
196
197void TCPNameserver::getQuestion(int fd, char *mesg, int pktlen, const ComboAddress &remote)
198try
199{
200 readnWithTimeout(fd, mesg, pktlen);
201}
67d74e49
BH
202catch(NetworkError& ae) {
203 throw NetworkError("Error reading DNS data from TCP client "+remote.toString()+": "+ae.what());
12c86877
BH
204}
205
ff76e8b4
BH
206static void proxyQuestion(shared_ptr<DNSPacket> packet)
207{
208 int sock=socket(AF_INET, SOCK_STREAM, 0);
326484be 209
42c235e5 210 Utility::setCloseOnExec(sock);
ff76e8b4 211 if(sock < 0)
67d74e49 212 throw NetworkError("Error making TCP connection socket to recursor: "+stringerror());
ff76e8b4 213
6a3e5d1a
BH
214 Utility::setNonBlocking(sock);
215 ServiceTuple st;
216 st.port=53;
379ab445 217 parseService(::arg()["recursor"],st);
6a3e5d1a 218
ff76e8b4 219 try {
ff76e8b4 220 ComboAddress recursor(st.host, st.port);
6a3e5d1a 221 connectWithTimeout(sock, (struct sockaddr*)&recursor, recursor.getSocklen());
ff76e8b4
BH
222 const string &buffer=packet->getString();
223
224 uint16_t len=htons(buffer.length()), slen;
225
6a3e5d1a
BH
226 writenWithTimeout(sock, &len, 2);
227 writenWithTimeout(sock, buffer.c_str(), buffer.length());
ff76e8b4 228
c20eca2b 229 readnWithTimeout(sock, &len, 2);
ff76e8b4
BH
230 len=ntohs(len);
231
232 char answer[len];
c20eca2b 233 readnWithTimeout(sock, answer, len);
ff76e8b4
BH
234
235 slen=htons(len);
6a3e5d1a 236 writenWithTimeout(packet->getSocket(), &slen, 2);
ff76e8b4 237
6a3e5d1a 238 writenWithTimeout(packet->getSocket(), answer, len);
ff76e8b4 239 }
67d74e49 240 catch(NetworkError& ae) {
ff76e8b4 241 close(sock);
67d74e49 242 throw NetworkError("While proxying a question to recursor "+st.host+": " +ae.what());
ff76e8b4
BH
243 }
244 close(sock);
245 return;
246}
247
12c86877
BH
248void *TCPNameserver::doConnection(void *data)
249{
ff76e8b4 250 shared_ptr<DNSPacket> packet;
b014ad98
BH
251 // Fix gcc-4.0 error (on AMD64)
252 int fd=(int)(long)data; // gotta love C (generates a harmless warning on opteron)
12c86877 253 pthread_detach(pthread_self());
027ffd26 254 Utility::setNonBlocking(fd);
12c86877 255 try {
12c86877
BH
256 char mesg[512];
257
258 DLOG(L<<"TCP Connection accepted on fd "<<fd<<endl);
21a303f3 259 bool logDNSQueries= ::arg().mustDo("log-dns-queries");
12c86877 260 for(;;) {
809fe23f 261 ComboAddress remote;
38a9b470
BH
262 socklen_t remotelen=sizeof(remote);
263 if(getpeername(fd, (struct sockaddr *)&remote, &remotelen) < 0) {
4957a608
BH
264 L<<Logger::Error<<"Received question from socket which had no remote address, dropping ("<<stringerror()<<")"<<endl;
265 break;
38a9b470 266 }
6a3e5d1a
BH
267
268 uint16_t pktlen;
269 if(!readnWithTimeout(fd, &pktlen, 2, false))
4957a608 270 break;
6a3e5d1a 271 else
4957a608 272 pktlen=ntohs(pktlen);
12c86877
BH
273
274 if(pktlen>511) {
4957a608
BH
275 L<<Logger::Error<<"Received an overly large question from "<<remote.toString()<<", dropping"<<endl;
276 break;
12c86877
BH
277 }
278
78bcb858 279 getQuestion(fd, mesg, pktlen, remote);
12c86877 280 S.inc("tcp-queries");
3e579e91 281
ff76e8b4 282 packet=shared_ptr<DNSPacket>(new DNSPacket);
809fe23f 283 packet->setRemote(&remote);
e9dd48f9 284 packet->d_tcp=true;
ff76e8b4 285 packet->setSocket(fd);
c1663439 286 if(packet->parse(mesg, pktlen)<0)
4957a608 287 break;
c1663439 288
af1311e4 289 if(packet->qtype.getCode()==QType::AXFR || packet->qtype.getCode()==QType::IXFR ) {
4957a608
BH
290 if(doAXFR(packet->qdomain, packet, fd))
291 S.inc("tcp-answers");
292 continue;
12c86877
BH
293 }
294
ff76e8b4 295 shared_ptr<DNSPacket> reply;
ff76e8b4 296 shared_ptr<DNSPacket> cached= shared_ptr<DNSPacket>(new DNSPacket);
fe498ace
BH
297 if(logDNSQueries) {
298 string remote;
299 if(packet->hasEDNSSubnet())
300 remote = packet->getRemote() + "<-" + packet->getRealRemote().toString();
301 else
302 remote = packet->getRemote();
303 L << Logger::Notice<<"TCP Remote "<< remote <<" wants '" << packet->qdomain<<"|"<<packet->qtype.getName() <<
bb5903e2 304 "', do = " <<packet->d_dnssecOk <<", bufsize = "<< packet->getMaxReplyLen()<<": ";
fe498ace 305 }
bb5903e2 306
ff76e8b4 307
bb5903e2 308 if(!packet->d.rd && packet->couldBeCached() && PC.get(packet.get(), cached.get())) { // short circuit - does the PacketCache recognize this question?
21a303f3 309 if(logDNSQueries)
bb5903e2 310 L<<"packetcache HIT"<<endl;
d06799d4 311 cached->setRemote(&packet->d_remote);
4957a608
BH
312 cached->d.id=packet->d.id;
313 cached->d.rd=packet->d.rd; // copy in recursion desired bit
314 cached->commitD(); // commit d to the packet inlined
315
e02d0a59 316 sendPacket(cached, fd); // presigned, don't do it again
4957a608
BH
317 S.inc("tcp-answers");
318 continue;
12c86877 319 }
21a303f3 320 if(logDNSQueries)
bb5903e2 321 L<<"packetcache MISS"<<endl;
12c86877 322 {
4957a608
BH
323 Lock l(&s_plock);
324 if(!s_P) {
325 L<<Logger::Error<<"TCP server is without backend connections, launching"<<endl;
326 s_P=new PacketHandler;
327 }
328 bool shouldRecurse;
329
330 reply=shared_ptr<DNSPacket>(s_P->questionOrRecurse(packet.get(), &shouldRecurse)); // we really need to ask the backend :-)
331
332 if(shouldRecurse) {
333 proxyQuestion(packet);
334 continue;
335 }
12c86877
BH
336 }
337
12c86877 338 if(!reply) // unable to write an answer?
4957a608
BH
339 break;
340
12c86877 341 S.inc("tcp-answers");
ff76e8b4 342 sendPacket(reply, fd);
12c86877 343 }
12c86877 344 }
cc3afe25 345 catch(DBException &e) {
556252ea
BH
346 Lock l(&s_plock);
347 delete s_P;
348 s_P = 0;
349
350 L<<Logger::Error<<"TCP Connection Thread unable to answer a question because of a backend error, cycling"<<endl;
12c86877 351 }
ef1d2f44 352 catch(AhuException &ae) {
556252ea
BH
353 Lock l(&s_plock);
354 delete s_P;
355 s_P = 0; // on next call, backend will be recycled
027ffd26 356 L<<Logger::Error<<"TCP nameserver had error, cycling backend: "<<ae.reason<<endl;
ef1d2f44 357 }
0afa9049 358 catch(NetworkError &e) {
2e7834cb 359 L<<Logger::Info<<"TCP Connection Thread died because of network error: "<<e.what()<<endl;
0afa9049
BH
360 }
361
adc10f99 362 catch(std::exception &e) {
12c86877
BH
363 L<<Logger::Error<<"TCP Connection Thread died because of STL error: "<<e.what()<<endl;
364 }
365 catch( ... )
366 {
367 L << Logger::Error << "TCP Connection Thread caught unknown exception." << endl;
368 }
12c86877 369 d_connectionroom_sem->post();
c38f6509 370 Utility::closesocket(fd);
12c86877
BH
371
372 return 0;
373}
374
78bcb858 375
e082fb4c 376// call this method with s_plock held!
ff76e8b4 377bool TCPNameserver::canDoAXFR(shared_ptr<DNSPacket> q)
12c86877 378{
379ab445 379 if(::arg().mustDo("disable-axfr"))
318c3ec6
BH
380 return false;
381
78bcb858
BH
382 if(q->d_havetsig) { // if you have one, it must be good
383 TSIGRecordContent trc;
384 string keyname, secret;
78bcb858
BH
385 if(!checkForCorrectTSIG(q.get(), s_P->getBackend(), &keyname, &secret, &trc))
386 return false;
387
388 DNSSECKeeper dk;
389
390 if(!dk.TSIGGrantsAccess(q->qdomain, keyname, trc.d_algoName)) {
391 L<<Logger::Error<<"AXFR '"<<q->qdomain<<"' denied: key with name '"<<keyname<<"' and algorithm '"<<trc.d_algoName<<"' does not grant access to zone"<<endl;
392 return false;
393 }
394 else {
395 L<<Logger::Warning<<"AXFR of domain '"<<q->qdomain<<"' allowed: TSIG signed request with authorized key '"<<keyname<<"' and algorithm '"<<trc.d_algoName<<"'"<<endl;
396 return true;
397 }
398 }
93afc0a3
PD
399
400 // cerr<<"checking allow-axfr-ips"<<endl;
401 if(!(::arg()["allow-axfr-ips"].empty()) && d_ng.match( (ComboAddress *) &q->d_remote )) {
402 L<<Logger::Warning<<"AXFR of domain '"<<q->qdomain<<"' allowed: client IP "<<q->getRemote()<<" is in allow-axfr-ips"<<endl;
12c86877 403 return true;
ab5edd12 404 }
93afc0a3
PD
405
406 FindNS fns;
407
408 // cerr<<"doing per-zone-axfr-acls"<<endl;
409 SOAData sd;
410 sd.db=(DNSBackend *)-1;
411 if(s_P->getBackend()->getSOA(q->qdomain,sd)) {
412 // cerr<<"got backend and SOA"<<endl;
413 DNSBackend *B=sd.db;
414 vector<string> acl;
415 B->getDomainMetadata(q->qdomain, "ALLOW-AXFR-FROM", acl);
416 for (vector<string>::const_iterator i = acl.begin(); i != acl.end(); ++i) {
417 // cerr<<"matching against "<<*i<<endl;
418 if(pdns_iequals(*i, "AUTO-NS")) {
419 // cerr<<"AUTO-NS magic please!"<<endl;
420
421 DNSResourceRecord rr;
422 set<string> nsset;
423
424 B->lookup(QType(QType::NS),q->qdomain);
425 while(B->get(rr))
426 nsset.insert(rr.content);
427 for(set<string>::const_iterator j=nsset.begin();j!=nsset.end();++j) {
428 vector<string> nsips=fns.lookup(*j, B);
429 for(vector<string>::const_iterator k=nsips.begin();k!=nsips.end();++k) {
430 // cerr<<"got "<<*k<<" from AUTO-NS"<<endl;
431 if(*k == q->getRemote())
432 {
433 // cerr<<"got AUTO-NS hit"<<endl;
434 L<<Logger::Warning<<"AXFR of domain '"<<q->qdomain<<"' allowed: client IP "<<q->getRemote()<<" is in NSset"<<endl;
435 return true;
436 }
437 }
438 }
439 }
440 else
441 {
442 Netmask nm = Netmask(*i);
443 if(nm.match( (ComboAddress *) &q->d_remote ))
444 {
445 L<<Logger::Warning<<"AXFR of domain '"<<q->qdomain<<"' allowed: client IP "<<q->getRemote()<<" is in per-domain ACL"<<endl;
446 // cerr<<"hit!"<<endl;
447 return true;
448 }
449 }
450 }
451 }
452
12c86877
BH
453 extern CommunicatorClass Communicator;
454
455 if(Communicator.justNotified(q->qdomain, q->getRemote())) { // we just notified this ip
456 L<<Logger::Warning<<"Approved AXFR of '"<<q->qdomain<<"' from recently notified slave "<<q->getRemote()<<endl;
457 return true;
458 }
459
93afc0a3 460 L<<Logger::Error<<"AXFR of domain '"<<q->qdomain<<"' denied: client IP "<<q->getRemote()<<" has no permission"<<endl;
12c86877
BH
461 return false;
462}
463
b317b510 464namespace {
54d84273
PD
465 struct NSECXEntry
466 {
467 set<uint16_t> d_set;
468 unsigned int d_ttl;
feef1ece 469 bool d_auth;
54d84273 470 };
8e9b7d99 471
54d84273
PD
472 DNSResourceRecord makeDNSRRFromSOAData(const SOAData& sd)
473 {
474 DNSResourceRecord soa;
475 soa.qname= sd.qname;
476 soa.qtype=QType::SOA;
477 soa.content=serializeSOAData(sd);
478 soa.ttl=sd.ttl;
479 soa.domain_id=sd.domain_id;
480 soa.auth = true;
481 soa.d_place=DNSResourceRecord::ANSWER;
482 return soa;
483 }
8e9b7d99 484
54d84273
PD
485 shared_ptr<DNSPacket> getFreshAXFRPacket(shared_ptr<DNSPacket> q)
486 {
487 shared_ptr<DNSPacket> ret = shared_ptr<DNSPacket>(q->replyPacket());
488 ret->setCompress(false);
489 ret->d_dnssecOk=false; // RFC 5936, 2.2.5
490 ret->d_tcp = true;
491 return ret;
492 }
8e9b7d99
BH
493}
494
54d84273 495
12c86877 496/** do the actual zone transfer. Return 0 in case of error, 1 in case of success */
ff76e8b4 497int TCPNameserver::doAXFR(const string &target, shared_ptr<DNSPacket> q, int outsock)
12c86877 498{
4888e4b2
BH
499 bool noAXFRBecauseOfNSEC3Narrow=false;
500 NSEC3PARAMRecordContent ns3pr;
501 bool narrow;
502 bool NSEC3Zone=false;
8e9b7d99
BH
503
504 DNSSECKeeper dk;
627d2ca2 505 dk.clearCaches(target);
8267bd2c 506 bool securedZone = dk.isSecuredZone(target);
ac4a2f1e
KM
507 bool presignedZone = dk.isPresigned(target);
508
4888e4b2
BH
509 if(dk.getNSEC3PARAM(target, &ns3pr, &narrow)) {
510 NSEC3Zone=true;
511 if(narrow) {
512 L<<Logger::Error<<"Not doing AXFR of an NSEC3 narrow zone.."<<endl;
513 noAXFRBecauseOfNSEC3Narrow=true;
514 }
83fcecff 515 }
78bcb858 516
8e9b7d99 517 shared_ptr<DNSPacket> outpacket= getFreshAXFRPacket(q);
c67e46a1 518 if(q->d_dnssecOk)
05e24311 519 outpacket->d_dnssecOk=true; // RFC 5936, 2.2.5 'SHOULD'
8e9b7d99 520
e082fb4c 521 if(noAXFRBecauseOfNSEC3Narrow) {
20ca8e7d 522 L<<Logger::Error<<"AXFR of domain '"<<target<<"' denied to "<<q->getRemote()<<endl;
12c86877
BH
523 outpacket->setRcode(RCode::Refused);
524 // FIXME: should actually figure out if we are auth over a zone, and send out 9 if we aren't
ff76e8b4 525 sendPacket(outpacket,outsock);
12c86877
BH
526 return 0;
527 }
83fcecff 528
20ca8e7d 529 L<<Logger::Error<<"AXFR of domain '"<<target<<"' initiated by "<<q->getRemote()<<endl;
12c86877
BH
530
531 SOAData sd;
3de83124 532 sd.db=(DNSBackend *)-1; // force uncached answer
12c86877
BH
533 {
534 Lock l(&s_plock);
8e9b7d99 535 DLOG(L<<"Looking for SOA"<<endl); // find domain_id via SOA and list complete domain. No SOA, no AXFR
12a965c5
BH
536 if(!s_P) {
537 L<<Logger::Error<<"TCP server is without backend connections in doAXFR, launching"<<endl;
538 s_P=new PacketHandler;
539 }
12c86877 540
e082fb4c 541 if(!s_P->getBackend()->getSOA(target, sd) || !canDoAXFR(q)) {
d10f9034 542 L<<Logger::Error<<"AXFR of domain '"<<target<<"' failed: not authoritative"<<endl;
12c86877 543 outpacket->setRcode(9); // 'NOTAUTH'
ff76e8b4 544 sendPacket(outpacket,outsock);
12c86877
BH
545 return 0;
546 }
3de83124 547 }
8e9b7d99
BH
548
549 UeberBackend db;
3de83124 550 sd.db=(DNSBackend *)-1; // force uncached answer
8e9b7d99
BH
551 if(!db.getSOA(target, sd)) {
552 L<<Logger::Error<<"AXFR of domain '"<<target<<"' failed: not authoritative in second instance"<<endl;
3de83124 553 outpacket->setRcode(9); // 'NOTAUTH'
ff76e8b4 554 sendPacket(outpacket,outsock);
3de83124
BH
555 return 0;
556 }
7b308b7e 557
3de83124
BH
558 if(!sd.db || sd.db==(DNSBackend *)-1) {
559 L<<Logger::Error<<"Error determining backend for domain '"<<target<<"' trying to serve an AXFR"<<endl;
560 outpacket->setRcode(RCode::ServFail);
ff76e8b4 561 sendPacket(outpacket,outsock);
3de83124 562 return 0;
12c86877 563 }
3de83124 564
78bcb858
BH
565 TSIGRecordContent trc;
566 string tsigkeyname, tsigsecret;
567
568 q->getTSIGDetails(&trc, &tsigkeyname, 0);
569
570 if(!tsigkeyname.empty()) {
571 string tsig64, algorithm;
572 Lock l(&s_plock);
573 s_P->getBackend()->getTSIGKey(tsigkeyname, &algorithm, &tsig64);
574 B64Decode(tsig64, tsigsecret);
575 }
8e9b7d99 576
8e9b7d99
BH
577
578 UeberBackend signatureDB;
8e9b7d99 579
8267bd2c 580 // SOA *must* go out first, our signing pipe might reorder
12c86877 581 DLOG(L<<"Sending out SOA"<<endl);
8267bd2c
BH
582 DNSResourceRecord soa = makeDNSRRFromSOAData(sd);
583 outpacket->addRecord(soa);
92c90b44 584 editSOA(dk, sd.qname, outpacket.get());
8d3cbffa
BH
585 if(securedZone) {
586 set<string, CIStringCompare> authSet;
587 authSet.insert(target);
588 addRRSigs(dk, signatureDB, authSet, outpacket->getRRS());
589 }
8e9b7d99 590
78bcb858
BH
591 if(!tsigkeyname.empty())
592 outpacket->setTSIGDetails(trc, tsigkeyname, tsigsecret, trc.d_mac); // first answer is 'normal'
593
8267bd2c 594 sendPacket(outpacket, outsock);
78bcb858
BH
595
596 trc.d_mac = outpacket->d_trc.d_mac;
8267bd2c
BH
597 outpacket = getFreshAXFRPacket(q);
598
1c6d9830 599 ChunkedSigningPipe csp(target, securedZone, "", ::arg().asNum("signing-threads"));
8e9b7d99 600
bec14a20 601 typedef map<string, NSECXEntry> nsecxrepo_t;
9d3151d9 602 nsecxrepo_t nsecxrepo;
4888e4b2
BH
603
604 // this is where the DNSKEYs go in
0c350cb5 605
4c1474f3 606 DNSSECKeeper::keyset_t keys = dk.getKeys(target);
0c350cb5 607
8e9b7d99 608 DNSResourceRecord rr;
0c350cb5 609
794c2f92
PD
610 rr.qname = target;
611 rr.ttl = sd.default_ttl;
612 rr.auth = 1; // please sign!
613
4c1474f3 614 BOOST_FOREACH(const DNSSECKeeper::keyset_t::value_type& value, keys) {
4c1474f3 615 rr.qtype = QType(QType::DNSKEY);
4c1474f3 616 rr.content = value.first.getDNSKEY().getZoneRepresentation();
bec14a20 617 string keyname = NSEC3Zone ? hashQNameWithSalt(ns3pr.d_iterations, ns3pr.d_salt, rr.qname) : labelReverse(rr.qname);
9d3151d9 618 NSECXEntry& ne = nsecxrepo[keyname];
b317b510
BH
619
620 ne.d_set.insert(rr.qtype.getCode());
794c2f92 621 ne.d_ttl = sd.default_ttl;
8e9b7d99 622 csp.submit(rr);
4c1474f3 623 }
0c350cb5 624
9097239c 625 if(::arg().mustDo("experimental-direct-dnskey")) {
6dae726d
PD
626 sd.db->lookup(QType(QType::DNSKEY), target, NULL, sd.domain_id);
627 while(sd.db->get(rr)) {
628 rr.ttl = sd.default_ttl;
629 csp.submit(rr);
630 }
631 }
632
b8adb30d
KM
633 uint8_t flags;
634
95c5bc40 635 if(NSEC3Zone) { // now stuff in the NSEC3PARAM
b8adb30d 636 flags = ns3pr.d_flags;
ce464268 637 rr.qtype = QType(QType::NSEC3PARAM);
95c5bc40 638 ns3pr.d_flags = 0;
ce464268 639 rr.content = ns3pr.getZoneRepresentation();
b8adb30d 640 ns3pr.d_flags = flags;
ce464268
BH
641 string keyname = hashQNameWithSalt(ns3pr.d_iterations, ns3pr.d_salt, rr.qname);
642 NSECXEntry& ne = nsecxrepo[keyname];
643
644 ne.d_set.insert(rr.qtype.getCode());
645 csp.submit(rr);
646 }
8e9b7d99 647
0c350cb5
BH
648 // now start list zone
649 if(!(sd.db->list(target, sd.domain_id))) {
650 L<<Logger::Error<<"Backend signals error condition"<<endl;
651 outpacket->setRcode(2); // 'SERVFAIL'
652 sendPacket(outpacket,outsock);
653 return 0;
654 }
655
12c86877 656 /* now write all other records */
8e9b7d99 657
9d3151d9 658 string keyname;
ac4a2f1e 659 set<string> ns3rrs;
1c6d9830
BH
660 DTime dt;
661 dt.set();
bec14a20 662 int records=0;
8e9b7d99 663 while(sd.db->get(rr)) {
ac4a2f1e
KM
664 if (rr.qtype.getCode() == QType::RRSIG) {
665 RRSIGRecordContent rrc(rr.content);
666 if(presignedZone && rrc.d_type == QType::NSEC3)
667 ns3rrs.insert(fromBase32Hex(makeRelative(rr.qname, target)));
794c2f92 668 continue;
ac4a2f1e 669 }
6dae726d
PD
670
671 // only skip the DNSKEY if direct-dnskey is enabled, to avoid changing behaviour
672 // when it is not enabled.
9097239c 673 if(::arg().mustDo("experimental-direct-dnskey") && rr.qtype.getCode() == QType::DNSKEY)
6dae726d
PD
674 continue;
675
bec14a20 676 records++;
feef1ece 677 if(securedZone && (rr.auth || rr.qtype.getCode() == QType::NS)) {
b5baefaf
PD
678 if (NSEC3Zone || rr.qtype.getCode()) {
679 keyname = NSEC3Zone ? hashQNameWithSalt(ns3pr.d_iterations, ns3pr.d_salt, rr.qname) : labelReverse(rr.qname);
680 NSECXEntry& ne = nsecxrepo[keyname];
681 ne.d_ttl = sd.default_ttl;
ac4a2f1e 682 ne.d_auth = (ne.d_auth || rr.auth || (NSEC3Zone && (!ns3pr.d_flags || (presignedZone && ns3pr.d_flags))));
b5baefaf
PD
683 if (rr.qtype.getCode()) {
684 ne.d_set.insert(rr.qtype.getCode());
685 }
686 }
b317b510 687 }
b5baefaf
PD
688
689 if (!rr.qtype.getCode())
690 continue; // skip empty non-terminals
691
add640c0 692 if(rr.qtype.getCode() == QType::SOA)
12c86877 693 continue; // skip SOA - would indicate end of AXFR
add640c0 694
1c6d9830
BH
695 if(csp.submit(rr)) {
696 for(;;) {
697 outpacket->getRRS() = csp.getChunk();
698 if(!outpacket->getRRS().empty()) {
54d84273
PD
699 if(!tsigkeyname.empty())
700 outpacket->setTSIGDetails(trc, tsigkeyname, tsigsecret, trc.d_mac, true);
1c6d9830 701 sendPacket(outpacket, outsock);
78bcb858 702 trc.d_mac=outpacket->d_trc.d_mac;
1c6d9830
BH
703 outpacket=getFreshAXFRPacket(q);
704 }
705 else
706 break;
707 }
12c86877
BH
708 }
709 }
1c6d9830 710 unsigned int udiff=dt.udiffNoReset();
78bcb858 711 /*
1c6d9830
BH
712 cerr<<"Starting NSEC: "<<csp.d_signed/(udiff/1000000.0)<<" sigs/s, "<<csp.d_signed<<" / "<<udiff/1000000.0<<endl;
713 cerr<<"Outstanding: "<<csp.d_outstanding<<", "<<csp.d_queued - csp.d_signed << endl;
714 cerr<<"Ready for consumption: "<<csp.getReady()<<endl;
78bcb858 715 */
feef1ece 716 if(securedZone) {
4888e4b2 717 if(NSEC3Zone) {
9d3151d9 718 for(nsecxrepo_t::const_iterator iter = nsecxrepo.begin(); iter != nsecxrepo.end(); ++iter) {
ac4a2f1e 719 if(iter->second.d_auth && (!presignedZone || !ns3pr.d_flags || ns3rrs.count(iter->first))) {
feef1ece
PD
720 NSEC3RecordContent n3rc;
721 n3rc.d_set = iter->second.d_set;
722 if (n3rc.d_set.size() && (n3rc.d_set.size() != 1 || !n3rc.d_set.count(QType::NS)))
723 n3rc.d_set.insert(QType::RRSIG);
724 n3rc.d_salt=ns3pr.d_salt;
725 n3rc.d_flags = ns3pr.d_flags;
726 n3rc.d_iterations = ns3pr.d_iterations;
727 n3rc.d_algorithm = 1; // SHA1, fixed in PowerDNS for now
728 nsecxrepo_t::const_iterator inext = iter;
729 inext++;
730 if(inext == nsecxrepo.end())
731 inext = nsecxrepo.begin();
ac4a2f1e 732 while((!inext->second.d_auth || (presignedZone && ns3pr.d_flags && !ns3rrs.count(inext->first))) && inext != iter)
feef1ece
PD
733 {
734 inext++;
735 if(inext == nsecxrepo.end())
736 inext = nsecxrepo.begin();
737 }
738 n3rc.d_nexthash = inext->first;
739 rr.qname = dotConcat(toLower(toBase32Hex(iter->first)), sd.qname);
740
741 rr.ttl = sd.default_ttl;
742 rr.content = n3rc.getZoneRepresentation();
743 rr.qtype = QType::NSEC3;
744 rr.d_place = DNSResourceRecord::ANSWER;
745 rr.auth=true;
746 if(csp.submit(rr)) {
747 for(;;) {
748 outpacket->getRRS() = csp.getChunk();
749 if(!outpacket->getRRS().empty()) {
750 if(!tsigkeyname.empty())
751 outpacket->setTSIGDetails(trc, tsigkeyname, tsigsecret, trc.d_mac, true);
752 sendPacket(outpacket, outsock);
753 trc.d_mac=outpacket->d_trc.d_mac;
754 outpacket=getFreshAXFRPacket(q);
755 }
756 else
757 break;
1c6d9830 758 }
1c6d9830 759 }
8e9b7d99 760 }
4888e4b2
BH
761 }
762 }
9d3151d9 763 else for(nsecxrepo_t::const_iterator iter = nsecxrepo.begin(); iter != nsecxrepo.end(); ++iter) {
ed9c3a50 764 NSECRecordContent nrc;
b317b510 765 nrc.d_set = iter->second.d_set;
ed9c3a50
BH
766 nrc.d_set.insert(QType::RRSIG);
767 nrc.d_set.insert(QType::NSEC);
9d3151d9 768 if(boost::next(iter) != nsecxrepo.end()) {
bec14a20 769 nrc.d_next = labelReverse(boost::next(iter)->first);
ed9c3a50
BH
770 }
771 else
bec14a20 772 nrc.d_next=labelReverse(nsecxrepo.begin()->first);
ed9c3a50 773
bec14a20 774 rr.qname = labelReverse(iter->first);
ed9c3a50 775
b5baefaf 776 rr.ttl = sd.default_ttl;
ed9c3a50
BH
777 rr.content = nrc.getZoneRepresentation();
778 rr.qtype = QType::NSEC;
779 rr.d_place = DNSResourceRecord::ANSWER;
5f5221b4 780 rr.auth=true;
8e9b7d99 781 if(csp.submit(rr)) {
1c6d9830
BH
782 for(;;) {
783 outpacket->getRRS() = csp.getChunk();
784 if(!outpacket->getRRS().empty()) {
78bcb858
BH
785 if(!tsigkeyname.empty())
786 outpacket->setTSIGDetails(trc, tsigkeyname, tsigsecret, trc.d_mac, true);
1c6d9830 787 sendPacket(outpacket, outsock);
78bcb858 788 trc.d_mac=outpacket->d_trc.d_mac;
1c6d9830
BH
789 outpacket=getFreshAXFRPacket(q);
790 }
791 else
792 break;
793 }
8e9b7d99 794 }
add640c0 795 }
add640c0 796 }
1c6d9830 797 udiff=dt.udiffNoReset();
78bcb858 798 /*
1c6d9830
BH
799 cerr<<"Flushing pipe: "<<csp.d_signed/(udiff/1000000.0)<<" sigs/s, "<<csp.d_signed<<" / "<<udiff/1000000.0<<endl;
800 cerr<<"Outstanding: "<<csp.d_outstanding<<", "<<csp.d_queued - csp.d_signed << endl;
801 cerr<<"Ready for consumption: "<<csp.getReady()<<endl;
78bcb858 802 * */
bec14a20
BH
803 for(;;) {
804 outpacket->getRRS() = csp.getChunk(true); // flush the pipe
805 if(!outpacket->getRRS().empty()) {
78bcb858
BH
806 if(!tsigkeyname.empty())
807 outpacket->setTSIGDetails(trc, tsigkeyname, tsigsecret, trc.d_mac, true); // first answer is 'normal'
bec14a20 808 sendPacket(outpacket, outsock);
78bcb858 809 trc.d_mac=outpacket->d_trc.d_mac;
bec14a20
BH
810 outpacket=getFreshAXFRPacket(q);
811 }
812 else
813 break;
12c86877 814 }
8e9b7d99 815
1c6d9830 816 udiff=dt.udiffNoReset();
f1f85f12
BH
817 if(securedZone)
818 L<<Logger::Info<<"Done signing: "<<csp.d_signed/(udiff/1000000.0)<<" sigs/s, "<<endl;
1c6d9830 819
12c86877
BH
820 DLOG(L<<"Done writing out records"<<endl);
821 /* and terminate with yet again the SOA record */
8e9b7d99 822 outpacket=getFreshAXFRPacket(q);
12c86877 823 outpacket->addRecord(soa);
92c90b44 824 editSOA(dk, sd.qname, outpacket.get());
78bcb858
BH
825 if(!tsigkeyname.empty())
826 outpacket->setTSIGDetails(trc, tsigkeyname, tsigsecret, trc.d_mac, true);
92c90b44 827
ff76e8b4 828 sendPacket(outpacket, outsock);
78bcb858 829
12c86877 830 DLOG(L<<"last packet - close"<<endl);
20ca8e7d 831 L<<Logger::Error<<"AXFR of domain '"<<target<<"' to "<<q->getRemote()<<" finished"<<endl;
12c86877
BH
832
833 return 1;
834}
835
836TCPNameserver::~TCPNameserver()
837{
838 delete d_connectionroom_sem;
839}
840
841TCPNameserver::TCPNameserver()
842{
379ab445
BH
843// sem_init(&d_connectionroom_sem,0,::arg().asNum("max-tcp-connections"));
844 d_connectionroom_sem = new Semaphore( ::arg().asNum( "max-tcp-connections" ));
12c86877
BH
845
846 s_timeout=10;
847 vector<string>locals;
379ab445 848 stringtok(locals,::arg()["local-address"]," ,");
12c86877
BH
849
850 vector<string>locals6;
379ab445 851 stringtok(locals6,::arg()["local-ipv6"]," ,");
12c86877 852
12c86877
BH
853 if(locals.empty() && locals6.empty())
854 throw AhuException("No local address specified");
855
9f1d5826 856 vector<string> parts;
379ab445 857 stringtok( parts, ::arg()["allow-axfr-ips"], ", \t" ); // is this IP on the guestlist?
9f1d5826
BH
858 for( vector<string>::const_iterator i = parts.begin(); i != parts.end(); ++i ) {
859 d_ng.addMask( *i );
860 }
861
12c86877
BH
862#ifndef WIN32
863 signal(SIGPIPE,SIG_IGN);
864#endif // WIN32
12c86877
BH
865
866 for(vector<string>::const_iterator laddr=locals.begin();laddr!=locals.end();++laddr) {
12c86877 867 int s=socket(AF_INET,SOCK_STREAM,0);
326484be 868
12c86877
BH
869 if(s<0)
870 throw AhuException("Unable to acquire TCP socket: "+stringerror());
12c86877 871
fb316318
PD
872 Utility::setCloseOnExec(s);
873
379ab445 874 ComboAddress local(*laddr, ::arg().asNum("local-port"));
12c86877
BH
875
876 int tmp=1;
877 if(setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(char*)&tmp,sizeof tmp)<0) {
878 L<<Logger::Error<<"Setsockopt failed"<<endl;
879 exit(1);
880 }
326484be 881
379ab445 882 if(::bind(s, (sockaddr*)&local, local.getSocklen())<0) {
12c86877
BH
883 L<<Logger::Error<<"binding to TCP socket: "<<strerror(errno)<<endl;
884 throw AhuException("Unable to bind to TCP socket");
885 }
886
887 listen(s,128);
ff76e8b4 888 L<<Logger::Error<<"TCP server bound to "<<local.toStringWithPort()<<endl;
12c86877 889 d_sockets.push_back(s);
8edfedf1
BH
890 struct pollfd pfd;
891 memset(&pfd, 0, sizeof(pfd));
892 pfd.fd = s;
893 pfd.events = POLLIN;
894
895 d_prfds.push_back(pfd);
12c86877
BH
896 }
897
1258abe0 898#if !WIN32 && HAVE_IPV6
12c86877 899 for(vector<string>::const_iterator laddr=locals6.begin();laddr!=locals6.end();++laddr) {
12c86877
BH
900 int s=socket(AF_INET6,SOCK_STREAM,0);
901
902 if(s<0)
903 throw AhuException("Unable to acquire TCPv6 socket: "+stringerror());
178d5134 904
fb316318
PD
905 Utility::setCloseOnExec(s);
906
379ab445 907 ComboAddress local(*laddr, ::arg().asNum("local-port"));
12c86877
BH
908
909 int tmp=1;
910 if(setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(char*)&tmp,sizeof tmp)<0) {
911 L<<Logger::Error<<"Setsockopt failed"<<endl;
912 exit(1);
913 }
326484be
BH
914 if(setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &tmp, sizeof(tmp)) < 0) {
915 L<<Logger::Error<<"Failed to set IPv6 socket to IPv6 only, continuing anyhow: "<<strerror(errno)<<endl;
916 }
ff76e8b4 917 if(bind(s, (const sockaddr*)&local, local.getSocklen())<0) {
12c86877
BH
918 L<<Logger::Error<<"binding to TCP socket: "<<strerror(errno)<<endl;
919 throw AhuException("Unable to bind to TCPv6 socket");
920 }
921
922 listen(s,128);
506a9050 923 L<<Logger::Error<<"TCPv6 server bound to "<<local.toStringWithPort()<<endl; // this gets %eth0 right
12c86877 924 d_sockets.push_back(s);
8edfedf1
BH
925
926 struct pollfd pfd;
927 memset(&pfd, 0, sizeof(pfd));
928 pfd.fd = s;
929 pfd.events = POLLIN;
930
931 d_prfds.push_back(pfd);
12c86877
BH
932 }
933#endif // WIN32
934}
935
936
ff76e8b4 937//! Start of TCP operations thread, we launch a new thread for each incoming TCP question
12c86877
BH
938void TCPNameserver::thread()
939{
12c86877
BH
940 try {
941 for(;;) {
942 int fd;
943 struct sockaddr_in remote;
944 Utility::socklen_t addrlen=sizeof(remote);
945
8edfedf1 946 int ret=poll(&d_prfds[0], d_prfds.size(), -1); // blocks, forever if need be
8a63d3ce 947 if(ret <= 0)
4957a608 948 continue;
8a63d3ce 949
12c86877 950 int sock=-1;
8edfedf1 951 BOOST_FOREACH(const struct pollfd& pfd, d_prfds) {
4957a608
BH
952 if(pfd.revents == POLLIN) {
953 sock = pfd.fd;
954 addrlen=sizeof(remote);
955
956 if((fd=accept(sock, (sockaddr*)&remote, &addrlen))<0) {
957 L<<Logger::Error<<"TCP question accept error: "<<strerror(errno)<<endl;
958
959 if(errno==EMFILE) {
960 L<<Logger::Error<<Logger::NTLog<<"TCP handler out of filedescriptors, exiting, won't recover from this"<<endl;
961 exit(1);
962 }
963 }
964 else {
965 pthread_t tid;
966 d_connectionroom_sem->wait(); // blocks if no connections are available
967
968 int room;
969 d_connectionroom_sem->getValue( &room);
970 if(room<1)
971 L<<Logger::Warning<<Logger::NTLog<<"Limit of simultaneous TCP connections reached - raise max-tcp-connections"<<endl;
972
222efdc0 973 if(pthread_create(&tid, 0, &doConnection, reinterpret_cast<void*>(fd))) {
4957a608
BH
974 L<<Logger::Error<<"Error creating thread: "<<stringerror()<<endl;
975 d_connectionroom_sem->post();
976 }
977 }
978 }
12c86877
BH
979 }
980 }
981 }
982 catch(AhuException &AE) {
abc1d928 983 L<<Logger::Error<<"TCP Nameserver thread dying because of fatal error: "<<AE.reason<<endl;
12c86877
BH
984 }
985 catch(...) {
986 L<<Logger::Error<<"TCPNameserver dying because of an unexpected fatal error"<<endl;
987 }
988 exit(1); // take rest of server with us
989}
990
991