]> git.ipfire.org Git - thirdparty/pdns.git/blame - pdns/tcpreceiver.cc
apply Jimmy Bergmans INCEPTION-EPOCH serial-tweak, and document it.
[thirdparty/pdns.git] / pdns / tcpreceiver.cc
CommitLineData
12c86877
BH
1/*
2 PowerDNS Versatile Database Driven Nameserver
b317b510 3 Copyright (C) 2002-2011 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{
78bcb858
BH
178 const string buffer = p->getString();
179 uint16_t len=htons(buffer.length());
6a3e5d1a 180 writenWithTimeout(outsock, &len, 2);
78bcb858 181 writenWithTimeout(outsock, buffer.c_str(), buffer.length());
6a3e5d1a
BH
182}
183
184
185void TCPNameserver::getQuestion(int fd, char *mesg, int pktlen, const ComboAddress &remote)
186try
187{
188 readnWithTimeout(fd, mesg, pktlen);
189}
67d74e49
BH
190catch(NetworkError& ae) {
191 throw NetworkError("Error reading DNS data from TCP client "+remote.toString()+": "+ae.what());
12c86877
BH
192}
193
ff76e8b4
BH
194static void proxyQuestion(shared_ptr<DNSPacket> packet)
195{
196 int sock=socket(AF_INET, SOCK_STREAM, 0);
42c235e5 197 Utility::setCloseOnExec(sock);
ff76e8b4 198 if(sock < 0)
67d74e49 199 throw NetworkError("Error making TCP connection socket to recursor: "+stringerror());
ff76e8b4 200
6a3e5d1a
BH
201 Utility::setNonBlocking(sock);
202 ServiceTuple st;
203 st.port=53;
379ab445 204 parseService(::arg()["recursor"],st);
6a3e5d1a 205
ff76e8b4 206 try {
ff76e8b4 207 ComboAddress recursor(st.host, st.port);
6a3e5d1a 208 connectWithTimeout(sock, (struct sockaddr*)&recursor, recursor.getSocklen());
ff76e8b4
BH
209 const string &buffer=packet->getString();
210
211 uint16_t len=htons(buffer.length()), slen;
212
6a3e5d1a
BH
213 writenWithTimeout(sock, &len, 2);
214 writenWithTimeout(sock, buffer.c_str(), buffer.length());
ff76e8b4
BH
215
216 int ret;
217
6a3e5d1a 218 ret=readnWithTimeout(sock, &len, 2);
ff76e8b4
BH
219 len=ntohs(len);
220
221 char answer[len];
6a3e5d1a 222 ret=readnWithTimeout(sock, answer, len);
ff76e8b4
BH
223
224 slen=htons(len);
6a3e5d1a 225 writenWithTimeout(packet->getSocket(), &slen, 2);
ff76e8b4 226
6a3e5d1a 227 writenWithTimeout(packet->getSocket(), answer, len);
ff76e8b4 228 }
67d74e49 229 catch(NetworkError& ae) {
ff76e8b4 230 close(sock);
67d74e49 231 throw NetworkError("While proxying a question to recursor "+st.host+": " +ae.what());
ff76e8b4
BH
232 }
233 close(sock);
234 return;
235}
236
12c86877
BH
237void *TCPNameserver::doConnection(void *data)
238{
ff76e8b4 239 shared_ptr<DNSPacket> packet;
b014ad98
BH
240 // Fix gcc-4.0 error (on AMD64)
241 int fd=(int)(long)data; // gotta love C (generates a harmless warning on opteron)
12c86877 242 pthread_detach(pthread_self());
027ffd26 243 Utility::setNonBlocking(fd);
12c86877 244 try {
12c86877
BH
245 char mesg[512];
246
247 DLOG(L<<"TCP Connection accepted on fd "<<fd<<endl);
21a303f3 248 bool logDNSQueries= ::arg().mustDo("log-dns-queries");
12c86877 249 for(;;) {
809fe23f 250 ComboAddress remote;
38a9b470
BH
251 socklen_t remotelen=sizeof(remote);
252 if(getpeername(fd, (struct sockaddr *)&remote, &remotelen) < 0) {
4957a608
BH
253 L<<Logger::Error<<"Received question from socket which had no remote address, dropping ("<<stringerror()<<")"<<endl;
254 break;
38a9b470 255 }
6a3e5d1a
BH
256
257 uint16_t pktlen;
258 if(!readnWithTimeout(fd, &pktlen, 2, false))
4957a608 259 break;
6a3e5d1a 260 else
4957a608 261 pktlen=ntohs(pktlen);
12c86877
BH
262
263 if(pktlen>511) {
4957a608
BH
264 L<<Logger::Error<<"Received an overly large question from "<<remote.toString()<<", dropping"<<endl;
265 break;
12c86877
BH
266 }
267
78bcb858 268 getQuestion(fd, mesg, pktlen, remote);
12c86877 269 S.inc("tcp-queries");
3e579e91 270
ff76e8b4 271 packet=shared_ptr<DNSPacket>(new DNSPacket);
809fe23f 272 packet->setRemote(&remote);
e9dd48f9 273 packet->d_tcp=true;
ff76e8b4 274 packet->setSocket(fd);
c1663439 275 if(packet->parse(mesg, pktlen)<0)
4957a608 276 break;
c1663439 277
af1311e4 278 if(packet->qtype.getCode()==QType::AXFR || packet->qtype.getCode()==QType::IXFR ) {
4957a608
BH
279 if(doAXFR(packet->qdomain, packet, fd))
280 S.inc("tcp-answers");
281 continue;
12c86877
BH
282 }
283
ff76e8b4 284 shared_ptr<DNSPacket> reply;
ff76e8b4 285 shared_ptr<DNSPacket> cached= shared_ptr<DNSPacket>(new DNSPacket);
21a303f3 286 if(logDNSQueries)
d06799d4 287 L << Logger::Notice<<"TCP Remote "<< packet->d_remote.toString() <<" wants '" << packet->qdomain<<"|"<<packet->qtype.getName() <<
bb5903e2
BH
288 "', do = " <<packet->d_dnssecOk <<", bufsize = "<< packet->getMaxReplyLen()<<": ";
289
ff76e8b4 290
bb5903e2 291 if(!packet->d.rd && packet->couldBeCached() && PC.get(packet.get(), cached.get())) { // short circuit - does the PacketCache recognize this question?
21a303f3 292 if(logDNSQueries)
bb5903e2 293 L<<"packetcache HIT"<<endl;
d06799d4 294 cached->setRemote(&packet->d_remote);
4957a608
BH
295 cached->d.id=packet->d.id;
296 cached->d.rd=packet->d.rd; // copy in recursion desired bit
297 cached->commitD(); // commit d to the packet inlined
298
e02d0a59 299 sendPacket(cached, fd); // presigned, don't do it again
4957a608
BH
300 S.inc("tcp-answers");
301 continue;
12c86877 302 }
21a303f3 303 if(logDNSQueries)
bb5903e2 304 L<<"packetcache MISS"<<endl;
12c86877 305 {
4957a608
BH
306 Lock l(&s_plock);
307 if(!s_P) {
308 L<<Logger::Error<<"TCP server is without backend connections, launching"<<endl;
309 s_P=new PacketHandler;
310 }
311 bool shouldRecurse;
312
313 reply=shared_ptr<DNSPacket>(s_P->questionOrRecurse(packet.get(), &shouldRecurse)); // we really need to ask the backend :-)
314
315 if(shouldRecurse) {
316 proxyQuestion(packet);
317 continue;
318 }
12c86877
BH
319 }
320
12c86877 321 if(!reply) // unable to write an answer?
4957a608
BH
322 break;
323
12c86877 324 S.inc("tcp-answers");
ff76e8b4 325 sendPacket(reply, fd);
12c86877 326 }
12c86877 327 }
cc3afe25 328 catch(DBException &e) {
556252ea
BH
329 Lock l(&s_plock);
330 delete s_P;
331 s_P = 0;
332
333 L<<Logger::Error<<"TCP Connection Thread unable to answer a question because of a backend error, cycling"<<endl;
12c86877 334 }
ef1d2f44 335 catch(AhuException &ae) {
556252ea
BH
336 Lock l(&s_plock);
337 delete s_P;
338 s_P = 0; // on next call, backend will be recycled
027ffd26 339 L<<Logger::Error<<"TCP nameserver had error, cycling backend: "<<ae.reason<<endl;
ef1d2f44 340 }
0afa9049
BH
341 catch(NetworkError &e) {
342 L<<Logger::Info<<"TCP Connection Thread died because of STL error: "<<e.what()<<endl;
343 }
344
adc10f99 345 catch(std::exception &e) {
12c86877
BH
346 L<<Logger::Error<<"TCP Connection Thread died because of STL error: "<<e.what()<<endl;
347 }
348 catch( ... )
349 {
350 L << Logger::Error << "TCP Connection Thread caught unknown exception." << endl;
351 }
12c86877 352 d_connectionroom_sem->post();
c38f6509 353 Utility::closesocket(fd);
12c86877
BH
354
355 return 0;
356}
357
78bcb858
BH
358
359
ff76e8b4 360bool TCPNameserver::canDoAXFR(shared_ptr<DNSPacket> q)
12c86877 361{
379ab445 362 if(::arg().mustDo("disable-axfr"))
318c3ec6
BH
363 return false;
364
78bcb858
BH
365 if(q->d_havetsig) { // if you have one, it must be good
366 TSIGRecordContent trc;
367 string keyname, secret;
368 Lock l(&s_plock);
369 if(!checkForCorrectTSIG(q.get(), s_P->getBackend(), &keyname, &secret, &trc))
370 return false;
371
372 DNSSECKeeper dk;
373
374 if(!dk.TSIGGrantsAccess(q->qdomain, keyname, trc.d_algoName)) {
375 L<<Logger::Error<<"AXFR '"<<q->qdomain<<"' denied: key with name '"<<keyname<<"' and algorithm '"<<trc.d_algoName<<"' does not grant access to zone"<<endl;
376 return false;
377 }
378 else {
379 L<<Logger::Warning<<"AXFR of domain '"<<q->qdomain<<"' allowed: TSIG signed request with authorized key '"<<keyname<<"' and algorithm '"<<trc.d_algoName<<"'"<<endl;
380 return true;
381 }
382 }
93afc0a3
PD
383
384 // cerr<<"checking allow-axfr-ips"<<endl;
385 if(!(::arg()["allow-axfr-ips"].empty()) && d_ng.match( (ComboAddress *) &q->d_remote )) {
386 L<<Logger::Warning<<"AXFR of domain '"<<q->qdomain<<"' allowed: client IP "<<q->getRemote()<<" is in allow-axfr-ips"<<endl;
12c86877 387 return true;
ab5edd12 388 }
93afc0a3
PD
389
390 FindNS fns;
391
392 // cerr<<"doing per-zone-axfr-acls"<<endl;
393 SOAData sd;
394 sd.db=(DNSBackend *)-1;
395 if(s_P->getBackend()->getSOA(q->qdomain,sd)) {
396 // cerr<<"got backend and SOA"<<endl;
397 DNSBackend *B=sd.db;
398 vector<string> acl;
399 B->getDomainMetadata(q->qdomain, "ALLOW-AXFR-FROM", acl);
400 for (vector<string>::const_iterator i = acl.begin(); i != acl.end(); ++i) {
401 // cerr<<"matching against "<<*i<<endl;
402 if(pdns_iequals(*i, "AUTO-NS")) {
403 // cerr<<"AUTO-NS magic please!"<<endl;
404
405 DNSResourceRecord rr;
406 set<string> nsset;
407
408 B->lookup(QType(QType::NS),q->qdomain);
409 while(B->get(rr))
410 nsset.insert(rr.content);
411 for(set<string>::const_iterator j=nsset.begin();j!=nsset.end();++j) {
412 vector<string> nsips=fns.lookup(*j, B);
413 for(vector<string>::const_iterator k=nsips.begin();k!=nsips.end();++k) {
414 // cerr<<"got "<<*k<<" from AUTO-NS"<<endl;
415 if(*k == q->getRemote())
416 {
417 // cerr<<"got AUTO-NS hit"<<endl;
418 L<<Logger::Warning<<"AXFR of domain '"<<q->qdomain<<"' allowed: client IP "<<q->getRemote()<<" is in NSset"<<endl;
419 return true;
420 }
421 }
422 }
423 }
424 else
425 {
426 Netmask nm = Netmask(*i);
427 if(nm.match( (ComboAddress *) &q->d_remote ))
428 {
429 L<<Logger::Warning<<"AXFR of domain '"<<q->qdomain<<"' allowed: client IP "<<q->getRemote()<<" is in per-domain ACL"<<endl;
430 // cerr<<"hit!"<<endl;
431 return true;
432 }
433 }
434 }
435 }
436
12c86877
BH
437 extern CommunicatorClass Communicator;
438
439 if(Communicator.justNotified(q->qdomain, q->getRemote())) { // we just notified this ip
440 L<<Logger::Warning<<"Approved AXFR of '"<<q->qdomain<<"' from recently notified slave "<<q->getRemote()<<endl;
441 return true;
442 }
443
93afc0a3 444 L<<Logger::Error<<"AXFR of domain '"<<q->qdomain<<"' denied: client IP "<<q->getRemote()<<" has no permission"<<endl;
12c86877
BH
445 return false;
446}
447
b317b510 448namespace {
9d3151d9 449struct NSECXEntry
b317b510
BH
450{
451 set<uint16_t> d_set;
452 unsigned int d_ttl;
453};
8e9b7d99
BH
454
455DNSResourceRecord makeDNSRRFromSOAData(const SOAData& sd)
456{
457 DNSResourceRecord soa;
458 soa.qname= sd.qname;
459 soa.qtype=QType::SOA;
460 soa.content=serializeSOAData(sd);
461 soa.ttl=sd.ttl;
462 soa.domain_id=sd.domain_id;
463 soa.auth = true;
464 soa.d_place=DNSResourceRecord::ANSWER;
465 return soa;
466}
467
468shared_ptr<DNSPacket> getFreshAXFRPacket(shared_ptr<DNSPacket> q)
469{
470 shared_ptr<DNSPacket> ret = shared_ptr<DNSPacket>(q->replyPacket());
471 ret->setCompress(false);
c67e46a1 472 ret->d_dnssecOk=false; // RFC 5936, 2.2.5
8e9b7d99
BH
473 ret->d_tcp = true;
474 return ret;
475}
476
b317b510 477}
12c86877 478/** do the actual zone transfer. Return 0 in case of error, 1 in case of success */
ff76e8b4 479int TCPNameserver::doAXFR(const string &target, shared_ptr<DNSPacket> q, int outsock)
12c86877 480{
4888e4b2
BH
481 bool noAXFRBecauseOfNSEC3Narrow=false;
482 NSEC3PARAMRecordContent ns3pr;
483 bool narrow;
484 bool NSEC3Zone=false;
8e9b7d99
BH
485
486 DNSSECKeeper dk;
8267bd2c 487 bool securedZone = dk.isSecuredZone(target);
4888e4b2
BH
488 if(dk.getNSEC3PARAM(target, &ns3pr, &narrow)) {
489 NSEC3Zone=true;
490 if(narrow) {
491 L<<Logger::Error<<"Not doing AXFR of an NSEC3 narrow zone.."<<endl;
492 noAXFRBecauseOfNSEC3Narrow=true;
493 }
83fcecff 494 }
78bcb858 495
8e9b7d99 496 shared_ptr<DNSPacket> outpacket= getFreshAXFRPacket(q);
c67e46a1 497 if(q->d_dnssecOk)
05e24311 498 outpacket->d_dnssecOk=true; // RFC 5936, 2.2.5 'SHOULD'
8e9b7d99 499
4888e4b2 500 if(!canDoAXFR(q) || noAXFRBecauseOfNSEC3Narrow) {
20ca8e7d 501 L<<Logger::Error<<"AXFR of domain '"<<target<<"' denied to "<<q->getRemote()<<endl;
12c86877
BH
502 outpacket->setRcode(RCode::Refused);
503 // FIXME: should actually figure out if we are auth over a zone, and send out 9 if we aren't
ff76e8b4 504 sendPacket(outpacket,outsock);
12c86877
BH
505 return 0;
506 }
83fcecff 507
20ca8e7d 508 L<<Logger::Error<<"AXFR of domain '"<<target<<"' initiated by "<<q->getRemote()<<endl;
12c86877
BH
509
510 SOAData sd;
3de83124 511 sd.db=(DNSBackend *)-1; // force uncached answer
12c86877
BH
512 {
513 Lock l(&s_plock);
8e9b7d99 514 DLOG(L<<"Looking for SOA"<<endl); // find domain_id via SOA and list complete domain. No SOA, no AXFR
12a965c5
BH
515 if(!s_P) {
516 L<<Logger::Error<<"TCP server is without backend connections in doAXFR, launching"<<endl;
517 s_P=new PacketHandler;
518 }
12c86877 519
5f5221b4 520 if(!s_P->getBackend()->getSOA(target, sd)) {
d10f9034 521 L<<Logger::Error<<"AXFR of domain '"<<target<<"' failed: not authoritative"<<endl;
12c86877 522 outpacket->setRcode(9); // 'NOTAUTH'
ff76e8b4 523 sendPacket(outpacket,outsock);
12c86877
BH
524 return 0;
525 }
3de83124 526 }
8e9b7d99
BH
527
528 UeberBackend db;
3de83124 529 sd.db=(DNSBackend *)-1; // force uncached answer
8e9b7d99
BH
530 if(!db.getSOA(target, sd)) {
531 L<<Logger::Error<<"AXFR of domain '"<<target<<"' failed: not authoritative in second instance"<<endl;
3de83124 532 outpacket->setRcode(9); // 'NOTAUTH'
ff76e8b4 533 sendPacket(outpacket,outsock);
3de83124
BH
534 return 0;
535 }
7b308b7e 536
3de83124
BH
537 if(!sd.db || sd.db==(DNSBackend *)-1) {
538 L<<Logger::Error<<"Error determining backend for domain '"<<target<<"' trying to serve an AXFR"<<endl;
539 outpacket->setRcode(RCode::ServFail);
ff76e8b4 540 sendPacket(outpacket,outsock);
3de83124 541 return 0;
12c86877 542 }
3de83124 543
78bcb858
BH
544 TSIGRecordContent trc;
545 string tsigkeyname, tsigsecret;
546
547 q->getTSIGDetails(&trc, &tsigkeyname, 0);
548
549 if(!tsigkeyname.empty()) {
550 string tsig64, algorithm;
551 Lock l(&s_plock);
552 s_P->getBackend()->getTSIGKey(tsigkeyname, &algorithm, &tsig64);
553 B64Decode(tsig64, tsigsecret);
554 }
8e9b7d99 555
8e9b7d99
BH
556
557 UeberBackend signatureDB;
8e9b7d99 558
8267bd2c 559 // SOA *must* go out first, our signing pipe might reorder
12c86877 560 DLOG(L<<"Sending out SOA"<<endl);
8267bd2c
BH
561 DNSResourceRecord soa = makeDNSRRFromSOAData(sd);
562 outpacket->addRecord(soa);
92c90b44 563 editSOA(dk, sd.qname, outpacket.get());
8d3cbffa
BH
564 if(securedZone) {
565 set<string, CIStringCompare> authSet;
566 authSet.insert(target);
567 addRRSigs(dk, signatureDB, authSet, outpacket->getRRS());
568 }
8e9b7d99 569
78bcb858
BH
570 if(!tsigkeyname.empty())
571 outpacket->setTSIGDetails(trc, tsigkeyname, tsigsecret, trc.d_mac); // first answer is 'normal'
572
8267bd2c 573 sendPacket(outpacket, outsock);
78bcb858
BH
574
575 trc.d_mac = outpacket->d_trc.d_mac;
8267bd2c
BH
576 outpacket = getFreshAXFRPacket(q);
577
1c6d9830 578 ChunkedSigningPipe csp(target, securedZone, "", ::arg().asNum("signing-threads"));
8e9b7d99 579
bec14a20 580 typedef map<string, NSECXEntry> nsecxrepo_t;
9d3151d9 581 nsecxrepo_t nsecxrepo;
4888e4b2
BH
582
583 // this is where the DNSKEYs go in
0c350cb5 584
4c1474f3 585 DNSSECKeeper::keyset_t keys = dk.getKeys(target);
0c350cb5 586
8e9b7d99 587 DNSResourceRecord rr;
0c350cb5 588
4c1474f3
BH
589 BOOST_FOREACH(const DNSSECKeeper::keyset_t::value_type& value, keys) {
590 rr.qname = target;
591 rr.qtype = QType(QType::DNSKEY);
b317b510 592 rr.ttl = sd.default_ttl;
68875163 593 rr.auth = 1; // please sign!
4c1474f3 594 rr.content = value.first.getDNSKEY().getZoneRepresentation();
bec14a20 595 string keyname = NSEC3Zone ? hashQNameWithSalt(ns3pr.d_iterations, ns3pr.d_salt, rr.qname) : labelReverse(rr.qname);
9d3151d9 596 NSECXEntry& ne = nsecxrepo[keyname];
b317b510
BH
597
598 ne.d_set.insert(rr.qtype.getCode());
599 ne.d_ttl = rr.ttl;
8e9b7d99 600 csp.submit(rr);
4c1474f3 601 }
0c350cb5 602
95c5bc40 603 if(NSEC3Zone) { // now stuff in the NSEC3PARAM
ce464268 604 rr.qtype = QType(QType::NSEC3PARAM);
95c5bc40 605 ns3pr.d_flags = 0;
ce464268 606 rr.content = ns3pr.getZoneRepresentation();
95c5bc40 607 ns3pr.d_flags = 1;
ce464268
BH
608 string keyname = hashQNameWithSalt(ns3pr.d_iterations, ns3pr.d_salt, rr.qname);
609 NSECXEntry& ne = nsecxrepo[keyname];
610
611 ne.d_set.insert(rr.qtype.getCode());
612 csp.submit(rr);
613 }
8e9b7d99 614
0c350cb5
BH
615 // now start list zone
616 if(!(sd.db->list(target, sd.domain_id))) {
617 L<<Logger::Error<<"Backend signals error condition"<<endl;
618 outpacket->setRcode(2); // 'SERVFAIL'
619 sendPacket(outpacket,outsock);
620 return 0;
621 }
622
12c86877 623 /* now write all other records */
8e9b7d99 624
9d3151d9 625 string keyname;
1c6d9830
BH
626 DTime dt;
627 dt.set();
bec14a20 628 int records=0;
8e9b7d99 629 while(sd.db->get(rr)) {
bec14a20
BH
630 records++;
631 if(securedZone && (rr.auth || rr.qtype.getCode() == QType::NS || rr.qtype.getCode() == QType::DS)) { // this is probably NSEC specific, NSEC3 is different
632 keyname = NSEC3Zone ? hashQNameWithSalt(ns3pr.d_iterations, ns3pr.d_salt, rr.qname) : labelReverse(rr.qname);
9d3151d9 633 NSECXEntry& ne = nsecxrepo[keyname];
b317b510
BH
634 ne.d_set.insert(rr.qtype.getCode());
635 ne.d_ttl = rr.ttl;
636 }
add640c0 637 if(rr.qtype.getCode() == QType::SOA)
12c86877 638 continue; // skip SOA - would indicate end of AXFR
add640c0 639
1c6d9830
BH
640 if(csp.submit(rr)) {
641 for(;;) {
642 outpacket->getRRS() = csp.getChunk();
643 if(!outpacket->getRRS().empty()) {
78bcb858
BH
644 if(!tsigkeyname.empty())
645 outpacket->setTSIGDetails(trc, tsigkeyname, tsigsecret, trc.d_mac, true);
1c6d9830 646 sendPacket(outpacket, outsock);
78bcb858 647 trc.d_mac=outpacket->d_trc.d_mac;
1c6d9830
BH
648 outpacket=getFreshAXFRPacket(q);
649 }
650 else
651 break;
652 }
12c86877
BH
653 }
654 }
1c6d9830 655 unsigned int udiff=dt.udiffNoReset();
78bcb858 656 /*
1c6d9830
BH
657 cerr<<"Starting NSEC: "<<csp.d_signed/(udiff/1000000.0)<<" sigs/s, "<<csp.d_signed<<" / "<<udiff/1000000.0<<endl;
658 cerr<<"Outstanding: "<<csp.d_outstanding<<", "<<csp.d_queued - csp.d_signed << endl;
659 cerr<<"Ready for consumption: "<<csp.getReady()<<endl;
78bcb858 660 */
420faf6b 661 if(securedZone) {
4888e4b2 662 if(NSEC3Zone) {
9d3151d9
BH
663 for(nsecxrepo_t::const_iterator iter = nsecxrepo.begin(); iter != nsecxrepo.end(); ++iter) {
664 NSEC3RecordContent n3rc;
665 n3rc.d_set = iter->second.d_set;
666 n3rc.d_set.insert(QType::RRSIG);
667 n3rc.d_salt=ns3pr.d_salt;
668 n3rc.d_flags = 0;
669 n3rc.d_iterations = ns3pr.d_iterations;
670 n3rc.d_algorithm = 1; // SHA1, fixed in PowerDNS for now
671 if(boost::next(iter) != nsecxrepo.end()) {
672 n3rc.d_nexthash = boost::next(iter)->first;
673 }
674 else
675 n3rc.d_nexthash=nsecxrepo.begin()->first;
676
677 rr.qname = dotConcat(toLower(toBase32Hex(iter->first)), sd.qname);
678
679 rr.ttl = iter->second.d_ttl;
680 rr.content = n3rc.getZoneRepresentation();
681 rr.qtype = QType::NSEC3;
682 rr.d_place = DNSResourceRecord::ANSWER;
683 rr.auth=true;
8e9b7d99 684 if(csp.submit(rr)) {
1c6d9830
BH
685 for(;;) {
686 outpacket->getRRS() = csp.getChunk();
687 if(!outpacket->getRRS().empty()) {
78bcb858
BH
688 if(!tsigkeyname.empty())
689 outpacket->setTSIGDetails(trc, tsigkeyname, tsigsecret, trc.d_mac, true);
1c6d9830 690 sendPacket(outpacket, outsock);
78bcb858 691 trc.d_mac=outpacket->d_trc.d_mac;
1c6d9830
BH
692 outpacket=getFreshAXFRPacket(q);
693 }
694 else
695 break;
696 }
8e9b7d99 697 }
4888e4b2
BH
698 }
699 }
9d3151d9 700 else for(nsecxrepo_t::const_iterator iter = nsecxrepo.begin(); iter != nsecxrepo.end(); ++iter) {
ed9c3a50 701 NSECRecordContent nrc;
b317b510 702 nrc.d_set = iter->second.d_set;
ed9c3a50
BH
703 nrc.d_set.insert(QType::RRSIG);
704 nrc.d_set.insert(QType::NSEC);
9d3151d9 705 if(boost::next(iter) != nsecxrepo.end()) {
bec14a20 706 nrc.d_next = labelReverse(boost::next(iter)->first);
ed9c3a50
BH
707 }
708 else
bec14a20 709 nrc.d_next=labelReverse(nsecxrepo.begin()->first);
ed9c3a50 710
bec14a20 711 rr.qname = labelReverse(iter->first);
ed9c3a50 712
b317b510 713 rr.ttl = iter->second.d_ttl;
ed9c3a50
BH
714 rr.content = nrc.getZoneRepresentation();
715 rr.qtype = QType::NSEC;
716 rr.d_place = DNSResourceRecord::ANSWER;
5f5221b4 717 rr.auth=true;
1c6d9830 718
8e9b7d99 719 if(csp.submit(rr)) {
1c6d9830
BH
720 for(;;) {
721 outpacket->getRRS() = csp.getChunk();
722 if(!outpacket->getRRS().empty()) {
78bcb858
BH
723 if(!tsigkeyname.empty())
724 outpacket->setTSIGDetails(trc, tsigkeyname, tsigsecret, trc.d_mac, true);
1c6d9830 725 sendPacket(outpacket, outsock);
78bcb858 726 trc.d_mac=outpacket->d_trc.d_mac;
1c6d9830
BH
727 outpacket=getFreshAXFRPacket(q);
728 }
729 else
730 break;
731 }
8e9b7d99 732 }
add640c0 733 }
add640c0 734 }
1c6d9830 735 udiff=dt.udiffNoReset();
78bcb858 736 /*
1c6d9830
BH
737 cerr<<"Flushing pipe: "<<csp.d_signed/(udiff/1000000.0)<<" sigs/s, "<<csp.d_signed<<" / "<<udiff/1000000.0<<endl;
738 cerr<<"Outstanding: "<<csp.d_outstanding<<", "<<csp.d_queued - csp.d_signed << endl;
739 cerr<<"Ready for consumption: "<<csp.getReady()<<endl;
78bcb858 740 * */
bec14a20
BH
741 for(;;) {
742 outpacket->getRRS() = csp.getChunk(true); // flush the pipe
743 if(!outpacket->getRRS().empty()) {
78bcb858
BH
744 if(!tsigkeyname.empty())
745 outpacket->setTSIGDetails(trc, tsigkeyname, tsigsecret, trc.d_mac, true); // first answer is 'normal'
bec14a20 746 sendPacket(outpacket, outsock);
78bcb858 747 trc.d_mac=outpacket->d_trc.d_mac;
bec14a20
BH
748 outpacket=getFreshAXFRPacket(q);
749 }
750 else
751 break;
12c86877 752 }
8e9b7d99 753
1c6d9830 754 udiff=dt.udiffNoReset();
f1f85f12
BH
755 if(securedZone)
756 L<<Logger::Info<<"Done signing: "<<csp.d_signed/(udiff/1000000.0)<<" sigs/s, "<<endl;
1c6d9830 757
12c86877
BH
758 DLOG(L<<"Done writing out records"<<endl);
759 /* and terminate with yet again the SOA record */
8e9b7d99 760 outpacket=getFreshAXFRPacket(q);
12c86877 761 outpacket->addRecord(soa);
92c90b44 762 editSOA(dk, sd.qname, outpacket.get());
78bcb858
BH
763 if(!tsigkeyname.empty())
764 outpacket->setTSIGDetails(trc, tsigkeyname, tsigsecret, trc.d_mac, true);
92c90b44 765
ff76e8b4 766 sendPacket(outpacket, outsock);
78bcb858 767
12c86877 768 DLOG(L<<"last packet - close"<<endl);
20ca8e7d 769 L<<Logger::Error<<"AXFR of domain '"<<target<<"' to "<<q->getRemote()<<" finished"<<endl;
12c86877
BH
770
771 return 1;
772}
773
774TCPNameserver::~TCPNameserver()
775{
776 delete d_connectionroom_sem;
777}
778
779TCPNameserver::TCPNameserver()
780{
379ab445
BH
781// sem_init(&d_connectionroom_sem,0,::arg().asNum("max-tcp-connections"));
782 d_connectionroom_sem = new Semaphore( ::arg().asNum( "max-tcp-connections" ));
12c86877
BH
783
784 s_timeout=10;
785 vector<string>locals;
379ab445 786 stringtok(locals,::arg()["local-address"]," ,");
12c86877
BH
787
788 vector<string>locals6;
379ab445 789 stringtok(locals6,::arg()["local-ipv6"]," ,");
12c86877 790
12c86877
BH
791 if(locals.empty() && locals6.empty())
792 throw AhuException("No local address specified");
793
794 d_highfd=0;
795
9f1d5826 796 vector<string> parts;
379ab445 797 stringtok( parts, ::arg()["allow-axfr-ips"], ", \t" ); // is this IP on the guestlist?
9f1d5826
BH
798 for( vector<string>::const_iterator i = parts.begin(); i != parts.end(); ++i ) {
799 d_ng.addMask( *i );
800 }
801
12c86877
BH
802#ifndef WIN32
803 signal(SIGPIPE,SIG_IGN);
804#endif // WIN32
12c86877
BH
805
806 for(vector<string>::const_iterator laddr=locals.begin();laddr!=locals.end();++laddr) {
12c86877 807 int s=socket(AF_INET,SOCK_STREAM,0);
42c235e5 808 Utility::setCloseOnExec(s);
12c86877
BH
809
810 if(s<0)
811 throw AhuException("Unable to acquire TCP socket: "+stringerror());
12c86877 812
379ab445 813 ComboAddress local(*laddr, ::arg().asNum("local-port"));
12c86877
BH
814
815 int tmp=1;
816 if(setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(char*)&tmp,sizeof tmp)<0) {
817 L<<Logger::Error<<"Setsockopt failed"<<endl;
818 exit(1);
819 }
820
379ab445 821 if(::bind(s, (sockaddr*)&local, local.getSocklen())<0) {
12c86877
BH
822 L<<Logger::Error<<"binding to TCP socket: "<<strerror(errno)<<endl;
823 throw AhuException("Unable to bind to TCP socket");
824 }
825
826 listen(s,128);
ff76e8b4 827 L<<Logger::Error<<"TCP server bound to "<<local.toStringWithPort()<<endl;
12c86877 828 d_sockets.push_back(s);
8edfedf1
BH
829 struct pollfd pfd;
830 memset(&pfd, 0, sizeof(pfd));
831 pfd.fd = s;
832 pfd.events = POLLIN;
833
834 d_prfds.push_back(pfd);
835
12c86877
BH
836 d_highfd=max(s,d_highfd);
837 }
838
1258abe0 839#if !WIN32 && HAVE_IPV6
12c86877 840 for(vector<string>::const_iterator laddr=locals6.begin();laddr!=locals6.end();++laddr) {
12c86877 841 int s=socket(AF_INET6,SOCK_STREAM,0);
42c235e5 842 Utility::setCloseOnExec(s);
12c86877
BH
843
844 if(s<0)
845 throw AhuException("Unable to acquire TCPv6 socket: "+stringerror());
178d5134 846
379ab445 847 ComboAddress local(*laddr, ::arg().asNum("local-port"));
12c86877
BH
848
849 int tmp=1;
850 if(setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(char*)&tmp,sizeof tmp)<0) {
851 L<<Logger::Error<<"Setsockopt failed"<<endl;
852 exit(1);
853 }
854
ff76e8b4 855 if(bind(s, (const sockaddr*)&local, local.getSocklen())<0) {
12c86877
BH
856 L<<Logger::Error<<"binding to TCP socket: "<<strerror(errno)<<endl;
857 throw AhuException("Unable to bind to TCPv6 socket");
858 }
859
860 listen(s,128);
506a9050 861 L<<Logger::Error<<"TCPv6 server bound to "<<local.toStringWithPort()<<endl; // this gets %eth0 right
12c86877 862 d_sockets.push_back(s);
8edfedf1
BH
863
864 struct pollfd pfd;
865 memset(&pfd, 0, sizeof(pfd));
866 pfd.fd = s;
867 pfd.events = POLLIN;
868
869 d_prfds.push_back(pfd);
870 d_highfd=max(s, d_highfd);
12c86877
BH
871 }
872#endif // WIN32
873}
874
875
ff76e8b4 876//! Start of TCP operations thread, we launch a new thread for each incoming TCP question
12c86877
BH
877void TCPNameserver::thread()
878{
879 struct timeval tv;
880 tv.tv_sec=1;
881 tv.tv_usec=0;
882 try {
883 for(;;) {
884 int fd;
885 struct sockaddr_in remote;
886 Utility::socklen_t addrlen=sizeof(remote);
887
8edfedf1 888 int ret=poll(&d_prfds[0], d_prfds.size(), -1); // blocks, forever if need be
8a63d3ce 889 if(ret <= 0)
4957a608 890 continue;
8a63d3ce 891
12c86877 892 int sock=-1;
8edfedf1 893 BOOST_FOREACH(const struct pollfd& pfd, d_prfds) {
4957a608
BH
894 if(pfd.revents == POLLIN) {
895 sock = pfd.fd;
896 addrlen=sizeof(remote);
897
898 if((fd=accept(sock, (sockaddr*)&remote, &addrlen))<0) {
899 L<<Logger::Error<<"TCP question accept error: "<<strerror(errno)<<endl;
900
901 if(errno==EMFILE) {
902 L<<Logger::Error<<Logger::NTLog<<"TCP handler out of filedescriptors, exiting, won't recover from this"<<endl;
903 exit(1);
904 }
905 }
906 else {
907 pthread_t tid;
908 d_connectionroom_sem->wait(); // blocks if no connections are available
909
910 int room;
911 d_connectionroom_sem->getValue( &room);
912 if(room<1)
913 L<<Logger::Warning<<Logger::NTLog<<"Limit of simultaneous TCP connections reached - raise max-tcp-connections"<<endl;
914
915 if(pthread_create(&tid, 0, &doConnection, (void *)fd)) {
916 L<<Logger::Error<<"Error creating thread: "<<stringerror()<<endl;
917 d_connectionroom_sem->post();
918 }
919 }
920 }
12c86877
BH
921 }
922 }
923 }
924 catch(AhuException &AE) {
925 L<<Logger::Error<<"TCP Namerserver thread dying because of fatal error: "<<AE.reason<<endl;
926 }
927 catch(...) {
928 L<<Logger::Error<<"TCPNameserver dying because of an unexpected fatal error"<<endl;
929 }
930 exit(1); // take rest of server with us
931}
932
933