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