]> git.ipfire.org Git - thirdparty/pdns.git/blame - pdns/tcpreceiver.cc
add default for empty value to asNum(), and use a value of 1 for all thread settings...
[thirdparty/pdns.git] / pdns / tcpreceiver.cc
CommitLineData
12c86877
BH
1/*
2 PowerDNS Versatile Database Driven Nameserver
2e7834cb 3 Copyright (C) 2002-2012 PowerDNS.COM BV
12c86877
BH
4
5 This program is free software; you can redistribute it and/or modify
22dc646a
BH
6 it under the terms of the GNU General Public License version 2
7 as published by the Free Software Foundation
f782fe38
MH
8
9 Additionally, the license of this program contains a special
10 exception which allows to distribute the program in binary form when
11 it is linked against OpenSSL.
12
12c86877
BH
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
06bd9ccf 20 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
12c86877 21*/
379ab445 22#include "packetcache.hh"
1258abe0 23#include "utility.hh"
add640c0 24#include "dnssecinfra.hh"
4c1474f3 25#include "dnsseckeeper.hh"
12c86877 26#include <cstdio>
4888e4b2 27#include "base32.hh"
12c86877
BH
28#include <cstring>
29#include <cstdlib>
30#include <sys/types.h>
31#include <iostream>
32#include <string>
33#include "tcpreceiver.hh"
67d74e49 34#include "sstuff.hh"
8edfedf1 35#include <boost/foreach.hpp>
12c86877
BH
36#include <errno.h>
37#include <signal.h>
78bcb858 38#include "base64.hh"
12c86877
BH
39#include "ueberbackend.hh"
40#include "dnspacket.hh"
41#include "nameserver.hh"
42#include "distributor.hh"
43#include "lock.hh"
44#include "logger.hh"
45#include "arguments.hh"
379ab445 46
12c86877
BH
47#include "packethandler.hh"
48#include "statbag.hh"
49#include "resolver.hh"
50#include "communicator.hh"
61b26744 51#include "namespaces.hh"
8e9b7d99 52#include "signingpipe.hh"
12c86877
BH
53extern PacketCache PC;
54extern StatBag S;
55
56/**
57\file tcpreceiver.cc
58\brief This file implements the tcpreceiver that receives and answers questions over TCP/IP
59*/
60
ac2bb9e7 61pthread_mutex_t TCPNameserver::s_plock = PTHREAD_MUTEX_INITIALIZER;
12c86877
BH
62Semaphore *TCPNameserver::d_connectionroom_sem;
63PacketHandler *TCPNameserver::s_P;
64int TCPNameserver::s_timeout;
9f1d5826 65NetmaskGroup TCPNameserver::d_ng;
12c86877 66
12c86877
BH
67void TCPNameserver::go()
68{
69 L<<Logger::Error<<"Creating backend connection for TCP"<<endl;
70 s_P=0;
71 try {
72 s_P=new PacketHandler;
73 }
3f81d239 74 catch(PDNSException &ae) {
12c86877 75 L<<Logger::Error<<Logger::NTLog<<"TCP server is unable to launch backends - will try again when questions come in"<<endl;
fd8bc993 76 L<<Logger::Error<<"TCP server is unable to launch backends - will try again when questions come in: "<<ae.reason<<endl;
12c86877
BH
77 }
78 pthread_create(&d_tid, 0, launcher, static_cast<void *>(this));
79}
80
81void *TCPNameserver::launcher(void *data)
82{
83 static_cast<TCPNameserver *>(data)->thread();
84 return 0;
85}
86
3f81d239 87// throws PDNSException if things didn't go according to plan, returns 0 if really 0 bytes were read
6a3e5d1a 88int readnWithTimeout(int fd, void* buffer, unsigned int n, bool throwOnEOF=true)
12c86877 89{
6a3e5d1a
BH
90 unsigned int bytes=n;
91 char *ptr = (char*)buffer;
92 int ret;
93 while(bytes) {
94 ret=read(fd, ptr, bytes);
95 if(ret < 0) {
96 if(errno==EAGAIN) {
4957a608
BH
97 ret=waitForData(fd, 5);
98 if(ret < 0)
99 throw NetworkError("Waiting for data read");
100 if(!ret)
101 throw NetworkError("Timeout reading data");
102 continue;
6a3e5d1a
BH
103 }
104 else
4957a608 105 throw NetworkError("Reading data: "+stringerror());
6a3e5d1a
BH
106 }
107 if(!ret) {
108 if(!throwOnEOF && n == bytes)
4957a608 109 return 0;
6a3e5d1a 110 else
4957a608 111 throw NetworkError("Did not fulfill read from TCP due to EOF");
6a3e5d1a
BH
112 }
113
114 ptr += ret;
115 bytes -= ret;
116 }
117 return n;
118}
12c86877 119
6a3e5d1a
BH
120// ditto
121void writenWithTimeout(int fd, const void *buffer, unsigned int n)
122{
123 unsigned int bytes=n;
124 const char *ptr = (char*)buffer;
125 int ret;
126 while(bytes) {
127 ret=write(fd, ptr, bytes);
128 if(ret < 0) {
129 if(errno==EAGAIN) {
4957a608
BH
130 ret=waitForRWData(fd, false, 5, 0);
131 if(ret < 0)
132 throw NetworkError("Waiting for data write");
133 if(!ret)
134 throw NetworkError("Timeout writing data");
135 continue;
6a3e5d1a
BH
136 }
137 else
4957a608 138 throw NetworkError("Writing data: "+stringerror());
6a3e5d1a 139 }
12c86877 140 if(!ret) {
67d74e49 141 throw NetworkError("Did not fulfill TCP write due to EOF");
12c86877 142 }
6a3e5d1a
BH
143
144 ptr += ret;
145 bytes -= ret;
12c86877 146 }
12c86877
BH
147}
148
6a3e5d1a 149void connectWithTimeout(int fd, struct sockaddr* remote, size_t socklen)
12c86877 150{
6a3e5d1a
BH
151 int err;
152 Utility::socklen_t len=sizeof(err);
153
76473b92 154 if((err=connect(fd, remote, socklen))<0 && errno!=EINPROGRESS)
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 {
3ac5be20 256 char mesg[65535];
12c86877
BH
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 273
366e1e5e
AT
274 // this check will always be false *if* no one touches
275 // the mesg array. pktlen can be maximum of 65535 as
276 // it is 2 byte unsigned variable. In getQuestion, we
277 // write to 0 up to pktlen-1 so 65535 is just right.
278
279 // do not remove this check as it will catch if someone
280 // decreases the mesg buffer size for some reason.
3ac5be20 281 if(pktlen>sizeof(mesg)) {
4957a608
BH
282 L<<Logger::Error<<"Received an overly large question from "<<remote.toString()<<", dropping"<<endl;
283 break;
12c86877
BH
284 }
285
78bcb858 286 getQuestion(fd, mesg, pktlen, remote);
12c86877 287 S.inc("tcp-queries");
3e579e91 288
ff76e8b4 289 packet=shared_ptr<DNSPacket>(new DNSPacket);
809fe23f 290 packet->setRemote(&remote);
e9dd48f9 291 packet->d_tcp=true;
ff76e8b4 292 packet->setSocket(fd);
c1663439 293 if(packet->parse(mesg, pktlen)<0)
4957a608 294 break;
c1663439 295
6e59a580
KM
296 if(packet->qtype.getCode()==QType::AXFR) {
297 if(doAXFR(packet->qdomain, packet, fd))
298 S.inc("tcp-answers");
299 continue;
300 }
301
302 if(packet->qtype.getCode()==QType::IXFR) {
303 if(doIXFR(packet, fd))
304 S.inc("tcp-answers");
4957a608 305 continue;
12c86877
BH
306 }
307
ff76e8b4 308 shared_ptr<DNSPacket> reply;
ff76e8b4 309 shared_ptr<DNSPacket> cached= shared_ptr<DNSPacket>(new DNSPacket);
fe498ace
BH
310 if(logDNSQueries) {
311 string remote;
312 if(packet->hasEDNSSubnet())
313 remote = packet->getRemote() + "<-" + packet->getRealRemote().toString();
314 else
315 remote = packet->getRemote();
316 L << Logger::Notice<<"TCP Remote "<< remote <<" wants '" << packet->qdomain<<"|"<<packet->qtype.getName() <<
bb5903e2 317 "', do = " <<packet->d_dnssecOk <<", bufsize = "<< packet->getMaxReplyLen()<<": ";
fe498ace 318 }
bb5903e2 319
ff76e8b4 320
75fde355 321 if(!packet->d.rd && packet->couldBeCached() && PC.get(packet.get(), cached.get(), false)) { // short circuit - does the PacketCache recognize this question?
21a303f3 322 if(logDNSQueries)
bb5903e2 323 L<<"packetcache HIT"<<endl;
d06799d4 324 cached->setRemote(&packet->d_remote);
4957a608
BH
325 cached->d.id=packet->d.id;
326 cached->d.rd=packet->d.rd; // copy in recursion desired bit
327 cached->commitD(); // commit d to the packet inlined
328
e02d0a59 329 sendPacket(cached, fd); // presigned, don't do it again
4957a608
BH
330 S.inc("tcp-answers");
331 continue;
12c86877 332 }
21a303f3 333 if(logDNSQueries)
bb5903e2 334 L<<"packetcache MISS"<<endl;
12c86877 335 {
4957a608
BH
336 Lock l(&s_plock);
337 if(!s_P) {
338 L<<Logger::Error<<"TCP server is without backend connections, launching"<<endl;
339 s_P=new PacketHandler;
340 }
341 bool shouldRecurse;
342
343 reply=shared_ptr<DNSPacket>(s_P->questionOrRecurse(packet.get(), &shouldRecurse)); // we really need to ask the backend :-)
344
345 if(shouldRecurse) {
346 proxyQuestion(packet);
347 continue;
348 }
12c86877
BH
349 }
350
12c86877 351 if(!reply) // unable to write an answer?
4957a608
BH
352 break;
353
12c86877 354 S.inc("tcp-answers");
ff76e8b4 355 sendPacket(reply, fd);
12c86877 356 }
12c86877 357 }
cc3afe25 358 catch(DBException &e) {
556252ea
BH
359 Lock l(&s_plock);
360 delete s_P;
361 s_P = 0;
362
363 L<<Logger::Error<<"TCP Connection Thread unable to answer a question because of a backend error, cycling"<<endl;
12c86877 364 }
3f81d239 365 catch(PDNSException &ae) {
556252ea
BH
366 Lock l(&s_plock);
367 delete s_P;
368 s_P = 0; // on next call, backend will be recycled
027ffd26 369 L<<Logger::Error<<"TCP nameserver had error, cycling backend: "<<ae.reason<<endl;
ef1d2f44 370 }
0afa9049 371 catch(NetworkError &e) {
2e7834cb 372 L<<Logger::Info<<"TCP Connection Thread died because of network error: "<<e.what()<<endl;
0afa9049
BH
373 }
374
adc10f99 375 catch(std::exception &e) {
12c86877
BH
376 L<<Logger::Error<<"TCP Connection Thread died because of STL error: "<<e.what()<<endl;
377 }
378 catch( ... )
379 {
380 L << Logger::Error << "TCP Connection Thread caught unknown exception." << endl;
381 }
12c86877 382 d_connectionroom_sem->post();
c38f6509 383 Utility::closesocket(fd);
12c86877
BH
384
385 return 0;
386}
387
78bcb858 388
e082fb4c 389// call this method with s_plock held!
ff76e8b4 390bool TCPNameserver::canDoAXFR(shared_ptr<DNSPacket> q)
12c86877 391{
379ab445 392 if(::arg().mustDo("disable-axfr"))
318c3ec6
BH
393 return false;
394
78bcb858
BH
395 if(q->d_havetsig) { // if you have one, it must be good
396 TSIGRecordContent trc;
397 string keyname, secret;
78bcb858
BH
398 if(!checkForCorrectTSIG(q.get(), s_P->getBackend(), &keyname, &secret, &trc))
399 return false;
400
401 DNSSECKeeper dk;
402
403 if(!dk.TSIGGrantsAccess(q->qdomain, keyname, trc.d_algoName)) {
404 L<<Logger::Error<<"AXFR '"<<q->qdomain<<"' denied: key with name '"<<keyname<<"' and algorithm '"<<trc.d_algoName<<"' does not grant access to zone"<<endl;
405 return false;
406 }
407 else {
408 L<<Logger::Warning<<"AXFR of domain '"<<q->qdomain<<"' allowed: TSIG signed request with authorized key '"<<keyname<<"' and algorithm '"<<trc.d_algoName<<"'"<<endl;
409 return true;
410 }
411 }
93afc0a3
PD
412
413 // cerr<<"checking allow-axfr-ips"<<endl;
414 if(!(::arg()["allow-axfr-ips"].empty()) && d_ng.match( (ComboAddress *) &q->d_remote )) {
415 L<<Logger::Warning<<"AXFR of domain '"<<q->qdomain<<"' allowed: client IP "<<q->getRemote()<<" is in allow-axfr-ips"<<endl;
12c86877 416 return true;
ab5edd12 417 }
93afc0a3
PD
418
419 FindNS fns;
420
421 // cerr<<"doing per-zone-axfr-acls"<<endl;
422 SOAData sd;
423 sd.db=(DNSBackend *)-1;
424 if(s_P->getBackend()->getSOA(q->qdomain,sd)) {
425 // cerr<<"got backend and SOA"<<endl;
426 DNSBackend *B=sd.db;
427 vector<string> acl;
428 B->getDomainMetadata(q->qdomain, "ALLOW-AXFR-FROM", acl);
429 for (vector<string>::const_iterator i = acl.begin(); i != acl.end(); ++i) {
430 // cerr<<"matching against "<<*i<<endl;
431 if(pdns_iequals(*i, "AUTO-NS")) {
432 // cerr<<"AUTO-NS magic please!"<<endl;
433
434 DNSResourceRecord rr;
435 set<string> nsset;
436
437 B->lookup(QType(QType::NS),q->qdomain);
438 while(B->get(rr))
439 nsset.insert(rr.content);
440 for(set<string>::const_iterator j=nsset.begin();j!=nsset.end();++j) {
441 vector<string> nsips=fns.lookup(*j, B);
442 for(vector<string>::const_iterator k=nsips.begin();k!=nsips.end();++k) {
443 // cerr<<"got "<<*k<<" from AUTO-NS"<<endl;
444 if(*k == q->getRemote())
445 {
446 // cerr<<"got AUTO-NS hit"<<endl;
447 L<<Logger::Warning<<"AXFR of domain '"<<q->qdomain<<"' allowed: client IP "<<q->getRemote()<<" is in NSset"<<endl;
448 return true;
449 }
450 }
451 }
452 }
453 else
454 {
455 Netmask nm = Netmask(*i);
456 if(nm.match( (ComboAddress *) &q->d_remote ))
457 {
458 L<<Logger::Warning<<"AXFR of domain '"<<q->qdomain<<"' allowed: client IP "<<q->getRemote()<<" is in per-domain ACL"<<endl;
459 // cerr<<"hit!"<<endl;
460 return true;
461 }
462 }
463 }
464 }
465
12c86877
BH
466 extern CommunicatorClass Communicator;
467
468 if(Communicator.justNotified(q->qdomain, q->getRemote())) { // we just notified this ip
469 L<<Logger::Warning<<"Approved AXFR of '"<<q->qdomain<<"' from recently notified slave "<<q->getRemote()<<endl;
470 return true;
471 }
472
93afc0a3 473 L<<Logger::Error<<"AXFR of domain '"<<q->qdomain<<"' denied: client IP "<<q->getRemote()<<" has no permission"<<endl;
12c86877
BH
474 return false;
475}
476
b317b510 477namespace {
54d84273
PD
478 struct NSECXEntry
479 {
480 set<uint16_t> d_set;
481 unsigned int d_ttl;
feef1ece 482 bool d_auth;
54d84273 483 };
8e9b7d99 484
54d84273
PD
485 DNSResourceRecord makeDNSRRFromSOAData(const SOAData& sd)
486 {
487 DNSResourceRecord soa;
488 soa.qname= sd.qname;
489 soa.qtype=QType::SOA;
490 soa.content=serializeSOAData(sd);
491 soa.ttl=sd.ttl;
492 soa.domain_id=sd.domain_id;
493 soa.auth = true;
494 soa.d_place=DNSResourceRecord::ANSWER;
495 return soa;
496 }
8e9b7d99 497
54d84273
PD
498 shared_ptr<DNSPacket> getFreshAXFRPacket(shared_ptr<DNSPacket> q)
499 {
500 shared_ptr<DNSPacket> ret = shared_ptr<DNSPacket>(q->replyPacket());
501 ret->setCompress(false);
502 ret->d_dnssecOk=false; // RFC 5936, 2.2.5
503 ret->d_tcp = true;
504 return ret;
505 }
8e9b7d99
BH
506}
507
54d84273 508
12c86877 509/** do the actual zone transfer. Return 0 in case of error, 1 in case of success */
ff76e8b4 510int TCPNameserver::doAXFR(const string &target, shared_ptr<DNSPacket> q, int outsock)
12c86877 511{
4888e4b2
BH
512 bool noAXFRBecauseOfNSEC3Narrow=false;
513 NSEC3PARAMRecordContent ns3pr;
514 bool narrow;
515 bool NSEC3Zone=false;
8e9b7d99
BH
516
517 DNSSECKeeper dk;
627d2ca2 518 dk.clearCaches(target);
8267bd2c 519 bool securedZone = dk.isSecuredZone(target);
ac4a2f1e
KM
520 bool presignedZone = dk.isPresigned(target);
521
4888e4b2
BH
522 if(dk.getNSEC3PARAM(target, &ns3pr, &narrow)) {
523 NSEC3Zone=true;
524 if(narrow) {
525 L<<Logger::Error<<"Not doing AXFR of an NSEC3 narrow zone.."<<endl;
526 noAXFRBecauseOfNSEC3Narrow=true;
527 }
83fcecff 528 }
78bcb858 529
8e9b7d99 530 shared_ptr<DNSPacket> outpacket= getFreshAXFRPacket(q);
c67e46a1 531 if(q->d_dnssecOk)
05e24311 532 outpacket->d_dnssecOk=true; // RFC 5936, 2.2.5 'SHOULD'
8e9b7d99 533
e082fb4c 534 if(noAXFRBecauseOfNSEC3Narrow) {
20ca8e7d 535 L<<Logger::Error<<"AXFR of domain '"<<target<<"' denied to "<<q->getRemote()<<endl;
12c86877
BH
536 outpacket->setRcode(RCode::Refused);
537 // FIXME: should actually figure out if we are auth over a zone, and send out 9 if we aren't
ff76e8b4 538 sendPacket(outpacket,outsock);
12c86877
BH
539 return 0;
540 }
83fcecff 541
20ca8e7d 542 L<<Logger::Error<<"AXFR of domain '"<<target<<"' initiated by "<<q->getRemote()<<endl;
12c86877
BH
543
544 SOAData sd;
3de83124 545 sd.db=(DNSBackend *)-1; // force uncached answer
12c86877
BH
546 {
547 Lock l(&s_plock);
8e9b7d99 548 DLOG(L<<"Looking for SOA"<<endl); // find domain_id via SOA and list complete domain. No SOA, no AXFR
12a965c5
BH
549 if(!s_P) {
550 L<<Logger::Error<<"TCP server is without backend connections in doAXFR, launching"<<endl;
551 s_P=new PacketHandler;
552 }
12c86877 553
e082fb4c 554 if(!s_P->getBackend()->getSOA(target, sd) || !canDoAXFR(q)) {
d10f9034 555 L<<Logger::Error<<"AXFR of domain '"<<target<<"' failed: not authoritative"<<endl;
12c86877 556 outpacket->setRcode(9); // 'NOTAUTH'
ff76e8b4 557 sendPacket(outpacket,outsock);
12c86877
BH
558 return 0;
559 }
3de83124 560 }
8e9b7d99
BH
561
562 UeberBackend db;
3de83124 563 sd.db=(DNSBackend *)-1; // force uncached answer
8e9b7d99
BH
564 if(!db.getSOA(target, sd)) {
565 L<<Logger::Error<<"AXFR of domain '"<<target<<"' failed: not authoritative in second instance"<<endl;
3de83124 566 outpacket->setRcode(9); // 'NOTAUTH'
ff76e8b4 567 sendPacket(outpacket,outsock);
3de83124
BH
568 return 0;
569 }
7b308b7e 570
3de83124
BH
571 if(!sd.db || sd.db==(DNSBackend *)-1) {
572 L<<Logger::Error<<"Error determining backend for domain '"<<target<<"' trying to serve an AXFR"<<endl;
573 outpacket->setRcode(RCode::ServFail);
ff76e8b4 574 sendPacket(outpacket,outsock);
3de83124 575 return 0;
12c86877 576 }
3de83124 577
78bcb858
BH
578 TSIGRecordContent trc;
579 string tsigkeyname, tsigsecret;
580
581 q->getTSIGDetails(&trc, &tsigkeyname, 0);
582
583 if(!tsigkeyname.empty()) {
584 string tsig64, algorithm;
585 Lock l(&s_plock);
586 s_P->getBackend()->getTSIGKey(tsigkeyname, &algorithm, &tsig64);
587 B64Decode(tsig64, tsigsecret);
588 }
8e9b7d99 589
8e9b7d99
BH
590
591 UeberBackend signatureDB;
8e9b7d99 592
8267bd2c 593 // SOA *must* go out first, our signing pipe might reorder
12c86877 594 DLOG(L<<"Sending out SOA"<<endl);
8267bd2c
BH
595 DNSResourceRecord soa = makeDNSRRFromSOAData(sd);
596 outpacket->addRecord(soa);
92c90b44 597 editSOA(dk, sd.qname, outpacket.get());
8d3cbffa
BH
598 if(securedZone) {
599 set<string, CIStringCompare> authSet;
600 authSet.insert(target);
601 addRRSigs(dk, signatureDB, authSet, outpacket->getRRS());
602 }
8e9b7d99 603
78bcb858
BH
604 if(!tsigkeyname.empty())
605 outpacket->setTSIGDetails(trc, tsigkeyname, tsigsecret, trc.d_mac); // first answer is 'normal'
606
8267bd2c 607 sendPacket(outpacket, outsock);
78bcb858
BH
608
609 trc.d_mac = outpacket->d_trc.d_mac;
8267bd2c
BH
610 outpacket = getFreshAXFRPacket(q);
611
ff99a74b 612 ChunkedSigningPipe csp(target, securedZone, "", ::arg().asNum("signing-threads", 1));
8e9b7d99 613
bec14a20 614 typedef map<string, NSECXEntry> nsecxrepo_t;
9d3151d9 615 nsecxrepo_t nsecxrepo;
4888e4b2
BH
616
617 // this is where the DNSKEYs go in
0c350cb5 618
4c1474f3 619 DNSSECKeeper::keyset_t keys = dk.getKeys(target);
0c350cb5 620
8e9b7d99 621 DNSResourceRecord rr;
0c350cb5 622
794c2f92
PD
623 rr.qname = target;
624 rr.ttl = sd.default_ttl;
625 rr.auth = 1; // please sign!
626
4c1474f3 627 BOOST_FOREACH(const DNSSECKeeper::keyset_t::value_type& value, keys) {
4c1474f3 628 rr.qtype = QType(QType::DNSKEY);
4c1474f3 629 rr.content = value.first.getDNSKEY().getZoneRepresentation();
bec14a20 630 string keyname = NSEC3Zone ? hashQNameWithSalt(ns3pr.d_iterations, ns3pr.d_salt, rr.qname) : labelReverse(rr.qname);
9d3151d9 631 NSECXEntry& ne = nsecxrepo[keyname];
b317b510
BH
632
633 ne.d_set.insert(rr.qtype.getCode());
794c2f92 634 ne.d_ttl = sd.default_ttl;
8e9b7d99 635 csp.submit(rr);
4c1474f3 636 }
0c350cb5 637
cc8df07f 638 if(::arg().mustDo("direct-dnskey")) {
6dae726d
PD
639 sd.db->lookup(QType(QType::DNSKEY), target, NULL, sd.domain_id);
640 while(sd.db->get(rr)) {
641 rr.ttl = sd.default_ttl;
642 csp.submit(rr);
643 }
644 }
645
b8adb30d
KM
646 uint8_t flags;
647
95c5bc40 648 if(NSEC3Zone) { // now stuff in the NSEC3PARAM
b8adb30d 649 flags = ns3pr.d_flags;
ce464268 650 rr.qtype = QType(QType::NSEC3PARAM);
95c5bc40 651 ns3pr.d_flags = 0;
ce464268 652 rr.content = ns3pr.getZoneRepresentation();
b8adb30d 653 ns3pr.d_flags = flags;
ce464268
BH
654 string keyname = hashQNameWithSalt(ns3pr.d_iterations, ns3pr.d_salt, rr.qname);
655 NSECXEntry& ne = nsecxrepo[keyname];
656
657 ne.d_set.insert(rr.qtype.getCode());
658 csp.submit(rr);
659 }
8e9b7d99 660
0c350cb5
BH
661 // now start list zone
662 if(!(sd.db->list(target, sd.domain_id))) {
663 L<<Logger::Error<<"Backend signals error condition"<<endl;
664 outpacket->setRcode(2); // 'SERVFAIL'
665 sendPacket(outpacket,outsock);
666 return 0;
667 }
668
b772ffea 669
5633a4af 670 const bool rectify = !(presignedZone || ::arg().mustDo("disable-axfr-rectify"));
b772ffea
KM
671 set<string> qnames, nsset, terms;
672 vector<DNSResourceRecord> rrs;
673
674 while(sd.db->get(rr)) {
675 if(endsOn(rr.qname, target)) {
676 if (rectify) {
677 if (rr.qtype.getCode()) {
678 qnames.insert(rr.qname);
679 if(rr.qtype.getCode() == QType::NS && !pdns_iequals(rr.qname, target))
680 nsset.insert(rr.qname);
681 } else {
682 // remove existing ents
683 continue;
684 }
685 }
686 rrs.push_back(rr);
687 } else {
688 L<<Logger::Warning<<"Zone '"<<target<<"' contains out-of-zone data '"<<rr.qname<<"'|"<<rr.qtype.getName()<<"', ignoring"<<endl;
689 continue;
690 }
691 }
692
693 if(rectify) {
694 // set auth
695 BOOST_FOREACH(DNSResourceRecord &rr, rrs) {
696 rr.auth=true;
697 if (rr.qtype.getCode() != QType::NS || !pdns_iequals(rr.qname, target)) {
698 string shorter(rr.qname);
699 do {
700 if (pdns_iequals(shorter, target)) // apex is always auth
701 continue;
702 if(nsset.count(shorter) && !(pdns_iequals(rr.qname, shorter) && rr.qtype.getCode() == QType::DS))
703 rr.auth=false;
704 } while(chopOff(shorter));
705 } else
706 continue;
707 }
708
709 if(NSEC3Zone) {
710 // ents are only required for NSEC3 zones
711 uint32_t maxent = ::arg().asNum("max-ent-entries");
712 map<string,bool> nonterm;
713 BOOST_FOREACH(DNSResourceRecord &rr, rrs) {
714 string shorter(rr.qname);
715 while(!pdns_iequals(shorter, target) && chopOff(shorter)) {
716 if(!qnames.count(shorter)) {
717 if(!(maxent)) {
718 L<<Logger::Warning<<"Zone '"<<target<<"' has too many empty non terminals."<<endl;
719 return 0;
720 }
721 if (!nonterm.count(shorter)) {
722 nonterm.insert(pair<string, bool>(shorter, rr.auth));
723 --maxent;
724 } else if (rr.auth)
725 nonterm[shorter]=true;
726 }
727 }
728 }
729
730 pair<string,bool> nt;
731 BOOST_FOREACH(nt, nonterm) {
732 DNSResourceRecord rr;
733 rr.qname=nt.first;
734 rr.qtype="TYPE0";
735 rr.auth=(nt.second || !ns3pr.d_flags);
736 rrs.push_back(rr);
737 }
738 }
739 }
740
741
12c86877 742 /* now write all other records */
8e9b7d99 743
9d3151d9 744 string keyname;
ac4a2f1e 745 set<string> ns3rrs;
3370c993 746 unsigned int udiff;
1c6d9830
BH
747 DTime dt;
748 dt.set();
bec14a20 749 int records=0;
b772ffea 750 BOOST_FOREACH(DNSResourceRecord &rr, rrs) {
ac4a2f1e
KM
751 if (rr.qtype.getCode() == QType::RRSIG) {
752 RRSIGRecordContent rrc(rr.content);
753 if(presignedZone && rrc.d_type == QType::NSEC3)
754 ns3rrs.insert(fromBase32Hex(makeRelative(rr.qname, target)));
794c2f92 755 continue;
ac4a2f1e 756 }
6dae726d
PD
757
758 // only skip the DNSKEY if direct-dnskey is enabled, to avoid changing behaviour
759 // when it is not enabled.
cc8df07f 760 if(::arg().mustDo("direct-dnskey") && rr.qtype.getCode() == QType::DNSKEY)
6dae726d
PD
761 continue;
762
bec14a20 763 records++;
feef1ece 764 if(securedZone && (rr.auth || rr.qtype.getCode() == QType::NS)) {
b5baefaf
PD
765 if (NSEC3Zone || rr.qtype.getCode()) {
766 keyname = NSEC3Zone ? hashQNameWithSalt(ns3pr.d_iterations, ns3pr.d_salt, rr.qname) : labelReverse(rr.qname);
767 NSECXEntry& ne = nsecxrepo[keyname];
768 ne.d_ttl = sd.default_ttl;
ac4a2f1e 769 ne.d_auth = (ne.d_auth || rr.auth || (NSEC3Zone && (!ns3pr.d_flags || (presignedZone && ns3pr.d_flags))));
b5baefaf
PD
770 if (rr.qtype.getCode()) {
771 ne.d_set.insert(rr.qtype.getCode());
772 }
773 }
b317b510 774 }
b5baefaf
PD
775
776 if (!rr.qtype.getCode())
777 continue; // skip empty non-terminals
778
add640c0 779 if(rr.qtype.getCode() == QType::SOA)
12c86877 780 continue; // skip SOA - would indicate end of AXFR
add640c0 781
1c6d9830
BH
782 if(csp.submit(rr)) {
783 for(;;) {
784 outpacket->getRRS() = csp.getChunk();
785 if(!outpacket->getRRS().empty()) {
54d84273
PD
786 if(!tsigkeyname.empty())
787 outpacket->setTSIGDetails(trc, tsigkeyname, tsigsecret, trc.d_mac, true);
1c6d9830 788 sendPacket(outpacket, outsock);
78bcb858 789 trc.d_mac=outpacket->d_trc.d_mac;
1c6d9830
BH
790 outpacket=getFreshAXFRPacket(q);
791 }
792 else
793 break;
794 }
12c86877
BH
795 }
796 }
78bcb858 797 /*
3370c993 798 udiff=dt.udiffNoReset();
1c6d9830
BH
799 cerr<<"Starting NSEC: "<<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 */
feef1ece 803 if(securedZone) {
4888e4b2 804 if(NSEC3Zone) {
9d3151d9 805 for(nsecxrepo_t::const_iterator iter = nsecxrepo.begin(); iter != nsecxrepo.end(); ++iter) {
ac4a2f1e 806 if(iter->second.d_auth && (!presignedZone || !ns3pr.d_flags || ns3rrs.count(iter->first))) {
feef1ece
PD
807 NSEC3RecordContent n3rc;
808 n3rc.d_set = iter->second.d_set;
809 if (n3rc.d_set.size() && (n3rc.d_set.size() != 1 || !n3rc.d_set.count(QType::NS)))
810 n3rc.d_set.insert(QType::RRSIG);
811 n3rc.d_salt=ns3pr.d_salt;
812 n3rc.d_flags = ns3pr.d_flags;
813 n3rc.d_iterations = ns3pr.d_iterations;
814 n3rc.d_algorithm = 1; // SHA1, fixed in PowerDNS for now
815 nsecxrepo_t::const_iterator inext = iter;
816 inext++;
817 if(inext == nsecxrepo.end())
818 inext = nsecxrepo.begin();
ac4a2f1e 819 while((!inext->second.d_auth || (presignedZone && ns3pr.d_flags && !ns3rrs.count(inext->first))) && inext != iter)
feef1ece
PD
820 {
821 inext++;
822 if(inext == nsecxrepo.end())
823 inext = nsecxrepo.begin();
824 }
825 n3rc.d_nexthash = inext->first;
1bad4190 826 rr.qname = dotConcat(toBase32Hex(iter->first), sd.qname);
feef1ece
PD
827
828 rr.ttl = sd.default_ttl;
829 rr.content = n3rc.getZoneRepresentation();
830 rr.qtype = QType::NSEC3;
831 rr.d_place = DNSResourceRecord::ANSWER;
832 rr.auth=true;
833 if(csp.submit(rr)) {
834 for(;;) {
835 outpacket->getRRS() = csp.getChunk();
836 if(!outpacket->getRRS().empty()) {
837 if(!tsigkeyname.empty())
838 outpacket->setTSIGDetails(trc, tsigkeyname, tsigsecret, trc.d_mac, true);
839 sendPacket(outpacket, outsock);
840 trc.d_mac=outpacket->d_trc.d_mac;
841 outpacket=getFreshAXFRPacket(q);
842 }
843 else
844 break;
1c6d9830 845 }
1c6d9830 846 }
8e9b7d99 847 }
4888e4b2
BH
848 }
849 }
9d3151d9 850 else for(nsecxrepo_t::const_iterator iter = nsecxrepo.begin(); iter != nsecxrepo.end(); ++iter) {
ed9c3a50 851 NSECRecordContent nrc;
b317b510 852 nrc.d_set = iter->second.d_set;
ed9c3a50
BH
853 nrc.d_set.insert(QType::RRSIG);
854 nrc.d_set.insert(QType::NSEC);
9d3151d9 855 if(boost::next(iter) != nsecxrepo.end()) {
bec14a20 856 nrc.d_next = labelReverse(boost::next(iter)->first);
ed9c3a50
BH
857 }
858 else
bec14a20 859 nrc.d_next=labelReverse(nsecxrepo.begin()->first);
ed9c3a50 860
bec14a20 861 rr.qname = labelReverse(iter->first);
ed9c3a50 862
b5baefaf 863 rr.ttl = sd.default_ttl;
ed9c3a50
BH
864 rr.content = nrc.getZoneRepresentation();
865 rr.qtype = QType::NSEC;
866 rr.d_place = DNSResourceRecord::ANSWER;
5f5221b4 867 rr.auth=true;
8e9b7d99 868 if(csp.submit(rr)) {
1c6d9830
BH
869 for(;;) {
870 outpacket->getRRS() = csp.getChunk();
871 if(!outpacket->getRRS().empty()) {
78bcb858
BH
872 if(!tsigkeyname.empty())
873 outpacket->setTSIGDetails(trc, tsigkeyname, tsigsecret, trc.d_mac, true);
1c6d9830 874 sendPacket(outpacket, outsock);
78bcb858 875 trc.d_mac=outpacket->d_trc.d_mac;
1c6d9830
BH
876 outpacket=getFreshAXFRPacket(q);
877 }
878 else
879 break;
880 }
8e9b7d99 881 }
add640c0 882 }
add640c0 883 }
78bcb858 884 /*
3370c993 885 udiff=dt.udiffNoReset();
1c6d9830
BH
886 cerr<<"Flushing pipe: "<<csp.d_signed/(udiff/1000000.0)<<" sigs/s, "<<csp.d_signed<<" / "<<udiff/1000000.0<<endl;
887 cerr<<"Outstanding: "<<csp.d_outstanding<<", "<<csp.d_queued - csp.d_signed << endl;
888 cerr<<"Ready for consumption: "<<csp.getReady()<<endl;
78bcb858 889 * */
bec14a20
BH
890 for(;;) {
891 outpacket->getRRS() = csp.getChunk(true); // flush the pipe
892 if(!outpacket->getRRS().empty()) {
78bcb858
BH
893 if(!tsigkeyname.empty())
894 outpacket->setTSIGDetails(trc, tsigkeyname, tsigsecret, trc.d_mac, true); // first answer is 'normal'
bec14a20 895 sendPacket(outpacket, outsock);
78bcb858 896 trc.d_mac=outpacket->d_trc.d_mac;
bec14a20
BH
897 outpacket=getFreshAXFRPacket(q);
898 }
899 else
900 break;
12c86877 901 }
8e9b7d99 902
1c6d9830 903 udiff=dt.udiffNoReset();
f1f85f12
BH
904 if(securedZone)
905 L<<Logger::Info<<"Done signing: "<<csp.d_signed/(udiff/1000000.0)<<" sigs/s, "<<endl;
1c6d9830 906
12c86877
BH
907 DLOG(L<<"Done writing out records"<<endl);
908 /* and terminate with yet again the SOA record */
8e9b7d99 909 outpacket=getFreshAXFRPacket(q);
12c86877 910 outpacket->addRecord(soa);
92c90b44 911 editSOA(dk, sd.qname, outpacket.get());
78bcb858
BH
912 if(!tsigkeyname.empty())
913 outpacket->setTSIGDetails(trc, tsigkeyname, tsigsecret, trc.d_mac, true);
92c90b44 914
ff76e8b4 915 sendPacket(outpacket, outsock);
78bcb858 916
12c86877 917 DLOG(L<<"last packet - close"<<endl);
20ca8e7d 918 L<<Logger::Error<<"AXFR of domain '"<<target<<"' to "<<q->getRemote()<<" finished"<<endl;
12c86877
BH
919
920 return 1;
921}
922
6e59a580
KM
923int TCPNameserver::doIXFR(shared_ptr<DNSPacket> q, int outsock)
924{
925 shared_ptr<DNSPacket> outpacket=getFreshAXFRPacket(q);
926 if(q->d_dnssecOk)
927 outpacket->d_dnssecOk=true; // RFC 5936, 2.2.5 'SHOULD'
928
929 DNSSECKeeper dk;
930 NSEC3PARAMRecordContent ns3pr;
931 bool narrow;
6e59a580
KM
932
933 dk.clearCaches(q->qdomain);
934 bool securedZone = dk.isSecuredZone(q->qdomain);
935 if(dk.getNSEC3PARAM(q->qdomain, &ns3pr, &narrow)) {
6e59a580 936 if(narrow) {
a3bcd88b 937 L<<Logger::Error<<"Not doing IXFR of an NSEC3 narrow zone."<<endl;
6e59a580
KM
938 L<<Logger::Error<<"IXFR of domain '"<<q->qdomain<<"' denied to "<<q->getRemote()<<endl;
939 outpacket->setRcode(RCode::Refused);
940 sendPacket(outpacket,outsock);
941 return 0;
942 }
943 }
944
945 uint32_t serial = 0;
946 MOADNSParser mdp(q->getString());
947 for(MOADNSParser::answers_t::const_iterator i=mdp.d_answers.begin(); i != mdp.d_answers.end(); ++i) {
948 const DNSRecord *rr = &i->first;
949 if (rr->d_type == QType::SOA && rr->d_place == DNSRecord::Nameserver) {
950 vector<string>parts;
951 stringtok(parts, rr->d_content->getZoneRepresentation());
952 if (parts.size() >= 3) {
953 serial=atoi(parts[2].c_str());
954 } else {
955 L<<Logger::Error<<"No serial in IXFR query"<<endl;
956 outpacket->setRcode(RCode::FormErr);
957 sendPacket(outpacket,outsock);
958 return 0;
959 }
960 } else {
961 L<<Logger::Error<<"Additional records in IXFR query"<<endl;
962 outpacket->setRcode(RCode::FormErr);
963 sendPacket(outpacket,outsock);
964 return 0;
965 }
966 }
967
968 L<<Logger::Error<<"IXFR of domain '"<<q->qdomain<<"' initiated by "<<q->getRemote()<<" with serial "<<serial<<endl;
969
970 SOAData sd;
971 sd.db=(DNSBackend *)-1; // force uncached answer
972 {
973 Lock l(&s_plock);
974 DLOG(L<<"Looking for SOA"<<endl); // find domain_id via SOA and list complete domain. No SOA, no IXFR
975 if(!s_P) {
976 L<<Logger::Error<<"TCP server is without backend connections in doIXFR, launching"<<endl;
977 s_P=new PacketHandler;
978 }
979
980 if(!s_P->getBackend()->getSOA(q->qdomain, sd)) {
981 L<<Logger::Error<<"IXFR of domain '"<<q->qdomain<<"' failed: not authoritative"<<endl;
982 outpacket->setRcode(9); // 'NOTAUTH'
983 sendPacket(outpacket,outsock);
984 return 0;
985 }
986 }
987
988 string target = q->qdomain;
989
990 UeberBackend db;
991 sd.db=(DNSBackend *)-1; // force uncached answer
992 if(!db.getSOA(target, sd)) {
993 L<<Logger::Error<<"IXFR of domain '"<<target<<"' failed: not authoritative in second instance"<<endl;
994 outpacket->setRcode(9); // 'NOTAUTH'
995 sendPacket(outpacket,outsock);
996 return 0;
997 }
998
999 if(!sd.db || sd.db==(DNSBackend *)-1) {
1000 L<<Logger::Error<<"Error determining backend for domain '"<<target<<"' trying to serve an IXFR"<<endl;
1001 outpacket->setRcode(RCode::ServFail);
1002 sendPacket(outpacket,outsock);
1003 return 0;
1004 }
1005 if (!rfc1982LessThan(serial, sd.serial)) {
1006 TSIGRecordContent trc;
1007 string tsigkeyname, tsigsecret;
1008
1009 q->getTSIGDetails(&trc, &tsigkeyname, 0);
1010
1011 if(!tsigkeyname.empty()) {
1012 string tsig64, algorithm;
1013 Lock l(&s_plock);
1014 s_P->getBackend()->getTSIGKey(tsigkeyname, &algorithm, &tsig64);
1015 B64Decode(tsig64, tsigsecret);
1016 }
1017
1018 UeberBackend signatureDB;
1019
1020 // SOA *must* go out first, our signing pipe might reorder
1021 DLOG(L<<"Sending out SOA"<<endl);
1022 DNSResourceRecord soa = makeDNSRRFromSOAData(sd);
1023 outpacket->addRecord(soa);
1024 editSOA(dk, sd.qname, outpacket.get());
1025 if(securedZone) {
1026 set<string, CIStringCompare> authSet;
1027 authSet.insert(target);
1028 addRRSigs(dk, signatureDB, authSet, outpacket->getRRS());
1029 }
1030
1031 if(!tsigkeyname.empty())
1032 outpacket->setTSIGDetails(trc, tsigkeyname, tsigsecret, trc.d_mac); // first answer is 'normal'
1033
1034 sendPacket(outpacket, outsock);
1035
1036 L<<Logger::Error<<"IXFR of domain '"<<target<<"' to "<<q->getRemote()<<" finished"<<endl;
1037
1038 return 1;
1039 }
1040
1041 L<<Logger::Error<<"IXFR fallback to AXFR for domain '"<<target<<"' our serial "<<sd.serial<<endl;
1042 return doAXFR(q->qdomain, q, outsock);
1043}
1044
12c86877
BH
1045TCPNameserver::~TCPNameserver()
1046{
1047 delete d_connectionroom_sem;
1048}
1049
1050TCPNameserver::TCPNameserver()
1051{
379ab445
BH
1052// sem_init(&d_connectionroom_sem,0,::arg().asNum("max-tcp-connections"));
1053 d_connectionroom_sem = new Semaphore( ::arg().asNum( "max-tcp-connections" ));
12c86877
BH
1054
1055 s_timeout=10;
1056 vector<string>locals;
379ab445 1057 stringtok(locals,::arg()["local-address"]," ,");
12c86877
BH
1058
1059 vector<string>locals6;
379ab445 1060 stringtok(locals6,::arg()["local-ipv6"]," ,");
12c86877 1061
12c86877 1062 if(locals.empty() && locals6.empty())
3f81d239 1063 throw PDNSException("No local address specified");
12c86877 1064
68b011bd 1065 d_ng.toMasks(::arg()["allow-axfr-ips"] );
9f1d5826 1066
12c86877 1067 signal(SIGPIPE,SIG_IGN);
12c86877
BH
1068
1069 for(vector<string>::const_iterator laddr=locals.begin();laddr!=locals.end();++laddr) {
12c86877 1070 int s=socket(AF_INET,SOCK_STREAM,0);
326484be 1071
12c86877 1072 if(s<0)
3f81d239 1073 throw PDNSException("Unable to acquire TCP socket: "+stringerror());
12c86877 1074
fb316318
PD
1075 Utility::setCloseOnExec(s);
1076
379ab445 1077 ComboAddress local(*laddr, ::arg().asNum("local-port"));
12c86877
BH
1078
1079 int tmp=1;
1080 if(setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(char*)&tmp,sizeof tmp)<0) {
1081 L<<Logger::Error<<"Setsockopt failed"<<endl;
1082 exit(1);
1083 }
326484be 1084
379ab445 1085 if(::bind(s, (sockaddr*)&local, local.getSocklen())<0) {
2c896042 1086 close(s);
5ecb2885
MZ
1087 if( errno == EADDRNOTAVAIL && ! ::arg().mustDo("local-address-nonexist-fail") ) {
1088 L<<Logger::Error<<"IPv4 Address " << *laddr << " does not exist on this server - skipping TCP bind" << endl;
1089 continue;
1090 } else {
1091 L<<Logger::Error<<"binding to TCP socket " << *laddr << ": "<<strerror(errno)<<endl;
2ab7e9ac 1092 throw PDNSException("Unable to bind to TCP socket");
5ecb2885 1093 }
12c86877
BH
1094 }
1095
1096 listen(s,128);
ff76e8b4 1097 L<<Logger::Error<<"TCP server bound to "<<local.toStringWithPort()<<endl;
12c86877 1098 d_sockets.push_back(s);
8edfedf1
BH
1099 struct pollfd pfd;
1100 memset(&pfd, 0, sizeof(pfd));
1101 pfd.fd = s;
1102 pfd.events = POLLIN;
1103
1104 d_prfds.push_back(pfd);
12c86877
BH
1105 }
1106
76473b92 1107#if HAVE_IPV6
12c86877 1108 for(vector<string>::const_iterator laddr=locals6.begin();laddr!=locals6.end();++laddr) {
12c86877
BH
1109 int s=socket(AF_INET6,SOCK_STREAM,0);
1110
1111 if(s<0)
3f81d239 1112 throw PDNSException("Unable to acquire TCPv6 socket: "+stringerror());
178d5134 1113
fb316318
PD
1114 Utility::setCloseOnExec(s);
1115
379ab445 1116 ComboAddress local(*laddr, ::arg().asNum("local-port"));
12c86877
BH
1117
1118 int tmp=1;
1119 if(setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(char*)&tmp,sizeof tmp)<0) {
1120 L<<Logger::Error<<"Setsockopt failed"<<endl;
1121 exit(1);
1122 }
326484be
BH
1123 if(setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &tmp, sizeof(tmp)) < 0) {
1124 L<<Logger::Error<<"Failed to set IPv6 socket to IPv6 only, continuing anyhow: "<<strerror(errno)<<endl;
1125 }
ff76e8b4 1126 if(bind(s, (const sockaddr*)&local, local.getSocklen())<0) {
2c896042 1127 close(s);
5ecb2885
MZ
1128 if( errno == EADDRNOTAVAIL && ! ::arg().mustDo("local-ipv6-nonexist-fail") ) {
1129 L<<Logger::Error<<"IPv6 Address " << *laddr << " does not exist on this server - skipping TCP bind" << endl;
1130 continue;
1131 } else {
1132 L<<Logger::Error<<"binding to TCPv6 socket" << *laddr << ": "<<strerror(errno)<<endl;
2ab7e9ac 1133 throw PDNSException("Unable to bind to TCPv6 socket");
5ecb2885 1134 }
12c86877
BH
1135 }
1136
1137 listen(s,128);
506a9050 1138 L<<Logger::Error<<"TCPv6 server bound to "<<local.toStringWithPort()<<endl; // this gets %eth0 right
12c86877 1139 d_sockets.push_back(s);
8edfedf1
BH
1140
1141 struct pollfd pfd;
1142 memset(&pfd, 0, sizeof(pfd));
1143 pfd.fd = s;
1144 pfd.events = POLLIN;
1145
1146 d_prfds.push_back(pfd);
12c86877 1147 }
76473b92 1148#endif
12c86877
BH
1149}
1150
1151
ff76e8b4 1152//! Start of TCP operations thread, we launch a new thread for each incoming TCP question
12c86877
BH
1153void TCPNameserver::thread()
1154{
12c86877
BH
1155 try {
1156 for(;;) {
1157 int fd;
1158 struct sockaddr_in remote;
1159 Utility::socklen_t addrlen=sizeof(remote);
1160
8edfedf1 1161 int ret=poll(&d_prfds[0], d_prfds.size(), -1); // blocks, forever if need be
8a63d3ce 1162 if(ret <= 0)
4957a608 1163 continue;
8a63d3ce 1164
12c86877 1165 int sock=-1;
8edfedf1 1166 BOOST_FOREACH(const struct pollfd& pfd, d_prfds) {
4957a608
BH
1167 if(pfd.revents == POLLIN) {
1168 sock = pfd.fd;
1169 addrlen=sizeof(remote);
1170
1171 if((fd=accept(sock, (sockaddr*)&remote, &addrlen))<0) {
1172 L<<Logger::Error<<"TCP question accept error: "<<strerror(errno)<<endl;
1173
1174 if(errno==EMFILE) {
1175 L<<Logger::Error<<Logger::NTLog<<"TCP handler out of filedescriptors, exiting, won't recover from this"<<endl;
1176 exit(1);
1177 }
1178 }
1179 else {
1180 pthread_t tid;
1181 d_connectionroom_sem->wait(); // blocks if no connections are available
1182
1183 int room;
1184 d_connectionroom_sem->getValue( &room);
1185 if(room<1)
1186 L<<Logger::Warning<<Logger::NTLog<<"Limit of simultaneous TCP connections reached - raise max-tcp-connections"<<endl;
1187
222efdc0 1188 if(pthread_create(&tid, 0, &doConnection, reinterpret_cast<void*>(fd))) {
4957a608
BH
1189 L<<Logger::Error<<"Error creating thread: "<<stringerror()<<endl;
1190 d_connectionroom_sem->post();
1191 }
1192 }
1193 }
12c86877
BH
1194 }
1195 }
1196 }
3f81d239 1197 catch(PDNSException &AE) {
abc1d928 1198 L<<Logger::Error<<"TCP Nameserver thread dying because of fatal error: "<<AE.reason<<endl;
12c86877
BH
1199 }
1200 catch(...) {
1201 L<<Logger::Error<<"TCPNameserver dying because of an unexpected fatal error"<<endl;
1202 }
1203 exit(1); // take rest of server with us
1204}
1205
1206