]> git.ipfire.org Git - thirdparty/pdns.git/blob - 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
1 /*
2 PowerDNS Versatile Database Driven Nameserver
3 Copyright (C) 2002-2012 PowerDNS.COM BV
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License version 2
7 as published by the Free Software Foundation
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
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
20 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
21 */
22 #include "packetcache.hh"
23 #include "utility.hh"
24 #include "dnssecinfra.hh"
25 #include "dnsseckeeper.hh"
26 #include <cstdio>
27 #include "base32.hh"
28 #include <cstring>
29 #include <cstdlib>
30 #include <sys/types.h>
31 #include <iostream>
32 #include <string>
33 #include "tcpreceiver.hh"
34 #include "sstuff.hh"
35 #include <boost/foreach.hpp>
36 #include <errno.h>
37 #include <signal.h>
38 #include "base64.hh"
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"
46
47 #include "packethandler.hh"
48 #include "statbag.hh"
49 #include "resolver.hh"
50 #include "communicator.hh"
51 #include "namespaces.hh"
52 #include "signingpipe.hh"
53 extern PacketCache PC;
54 extern 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
61 pthread_mutex_t TCPNameserver::s_plock = PTHREAD_MUTEX_INITIALIZER;
62 Semaphore *TCPNameserver::d_connectionroom_sem;
63 PacketHandler *TCPNameserver::s_P;
64 int TCPNameserver::s_timeout;
65 NetmaskGroup TCPNameserver::d_ng;
66
67 void 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 }
74 catch(PDNSException &ae) {
75 L<<Logger::Error<<Logger::NTLog<<"TCP server is unable to launch backends - will try again when questions come in"<<endl;
76 L<<Logger::Error<<"TCP server is unable to launch backends - will try again when questions come in: "<<ae.reason<<endl;
77 }
78 pthread_create(&d_tid, 0, launcher, static_cast<void *>(this));
79 }
80
81 void *TCPNameserver::launcher(void *data)
82 {
83 static_cast<TCPNameserver *>(data)->thread();
84 return 0;
85 }
86
87 // throws PDNSException if things didn't go according to plan, returns 0 if really 0 bytes were read
88 int readnWithTimeout(int fd, void* buffer, unsigned int n, bool throwOnEOF=true)
89 {
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) {
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;
103 }
104 else
105 throw NetworkError("Reading data: "+stringerror());
106 }
107 if(!ret) {
108 if(!throwOnEOF && n == bytes)
109 return 0;
110 else
111 throw NetworkError("Did not fulfill read from TCP due to EOF");
112 }
113
114 ptr += ret;
115 bytes -= ret;
116 }
117 return n;
118 }
119
120 // ditto
121 void 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) {
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;
136 }
137 else
138 throw NetworkError("Writing data: "+stringerror());
139 }
140 if(!ret) {
141 throw NetworkError("Did not fulfill TCP write due to EOF");
142 }
143
144 ptr += ret;
145 bytes -= ret;
146 }
147 }
148
149 void connectWithTimeout(int fd, struct sockaddr* remote, size_t socklen)
150 {
151 int err;
152 Utility::socklen_t len=sizeof(err);
153
154 if((err=connect(fd, remote, socklen))<0 && errno!=EINPROGRESS)
155 throw NetworkError("connect: "+stringerror());
156
157 if(!err)
158 goto done;
159
160 err=waitForRWData(fd, false, 5, 0);
161 if(err == 0)
162 throw NetworkError("Timeout connecting to remote");
163 if(err < 0)
164 throw NetworkError("Error connecting to remote");
165
166 if(getsockopt(fd, SOL_SOCKET,SO_ERROR,(char *)&err,&len)<0)
167 throw NetworkError("Error connecting to remote: "+stringerror()); // Solaris
168
169 if(err)
170 throw NetworkError("Error connecting to remote: "+string(strerror(err)));
171
172 done:
173 ;
174 }
175
176 void TCPNameserver::sendPacket(shared_ptr<DNSPacket> p, int outsock)
177 {
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()) {
185 S.ringAccount("unauth-queries",p->qdomain+"/"+p->qtype.getName());
186 S.ringAccount("remotes-unauth",p->getRemote());
187 }
188 }
189
190 uint16_t len=htons(p->getString().length());
191 string buffer((const char*)&len, 2);
192 buffer.append(p->getString());
193 writenWithTimeout(outsock, buffer.c_str(), buffer.length());
194 }
195
196
197 void TCPNameserver::getQuestion(int fd, char *mesg, int pktlen, const ComboAddress &remote)
198 try
199 {
200 readnWithTimeout(fd, mesg, pktlen);
201 }
202 catch(NetworkError& ae) {
203 throw NetworkError("Error reading DNS data from TCP client "+remote.toString()+": "+ae.what());
204 }
205
206 static void proxyQuestion(shared_ptr<DNSPacket> packet)
207 {
208 int sock=socket(AF_INET, SOCK_STREAM, 0);
209
210 Utility::setCloseOnExec(sock);
211 if(sock < 0)
212 throw NetworkError("Error making TCP connection socket to recursor: "+stringerror());
213
214 Utility::setNonBlocking(sock);
215 ServiceTuple st;
216 st.port=53;
217 parseService(::arg()["recursor"],st);
218
219 try {
220 ComboAddress recursor(st.host, st.port);
221 connectWithTimeout(sock, (struct sockaddr*)&recursor, recursor.getSocklen());
222 const string &buffer=packet->getString();
223
224 uint16_t len=htons(buffer.length()), slen;
225
226 writenWithTimeout(sock, &len, 2);
227 writenWithTimeout(sock, buffer.c_str(), buffer.length());
228
229 readnWithTimeout(sock, &len, 2);
230 len=ntohs(len);
231
232 char answer[len];
233 readnWithTimeout(sock, answer, len);
234
235 slen=htons(len);
236 writenWithTimeout(packet->getSocket(), &slen, 2);
237
238 writenWithTimeout(packet->getSocket(), answer, len);
239 }
240 catch(NetworkError& ae) {
241 close(sock);
242 throw NetworkError("While proxying a question to recursor "+st.host+": " +ae.what());
243 }
244 close(sock);
245 return;
246 }
247
248 void *TCPNameserver::doConnection(void *data)
249 {
250 shared_ptr<DNSPacket> packet;
251 // Fix gcc-4.0 error (on AMD64)
252 int fd=(int)(long)data; // gotta love C (generates a harmless warning on opteron)
253 pthread_detach(pthread_self());
254 Utility::setNonBlocking(fd);
255 try {
256 char mesg[65535];
257
258 DLOG(L<<"TCP Connection accepted on fd "<<fd<<endl);
259 bool logDNSQueries= ::arg().mustDo("log-dns-queries");
260 for(;;) {
261 ComboAddress remote;
262 socklen_t remotelen=sizeof(remote);
263 if(getpeername(fd, (struct sockaddr *)&remote, &remotelen) < 0) {
264 L<<Logger::Error<<"Received question from socket which had no remote address, dropping ("<<stringerror()<<")"<<endl;
265 break;
266 }
267
268 uint16_t pktlen;
269 if(!readnWithTimeout(fd, &pktlen, 2, false))
270 break;
271 else
272 pktlen=ntohs(pktlen);
273
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.
281 if(pktlen>sizeof(mesg)) {
282 L<<Logger::Error<<"Received an overly large question from "<<remote.toString()<<", dropping"<<endl;
283 break;
284 }
285
286 getQuestion(fd, mesg, pktlen, remote);
287 S.inc("tcp-queries");
288
289 packet=shared_ptr<DNSPacket>(new DNSPacket);
290 packet->setRemote(&remote);
291 packet->d_tcp=true;
292 packet->setSocket(fd);
293 if(packet->parse(mesg, pktlen)<0)
294 break;
295
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");
305 continue;
306 }
307
308 shared_ptr<DNSPacket> reply;
309 shared_ptr<DNSPacket> cached= shared_ptr<DNSPacket>(new DNSPacket);
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() <<
317 "', do = " <<packet->d_dnssecOk <<", bufsize = "<< packet->getMaxReplyLen()<<": ";
318 }
319
320
321 if(!packet->d.rd && packet->couldBeCached() && PC.get(packet.get(), cached.get(), false)) { // short circuit - does the PacketCache recognize this question?
322 if(logDNSQueries)
323 L<<"packetcache HIT"<<endl;
324 cached->setRemote(&packet->d_remote);
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
329 sendPacket(cached, fd); // presigned, don't do it again
330 S.inc("tcp-answers");
331 continue;
332 }
333 if(logDNSQueries)
334 L<<"packetcache MISS"<<endl;
335 {
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 }
349 }
350
351 if(!reply) // unable to write an answer?
352 break;
353
354 S.inc("tcp-answers");
355 sendPacket(reply, fd);
356 }
357 }
358 catch(DBException &e) {
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;
364 }
365 catch(PDNSException &ae) {
366 Lock l(&s_plock);
367 delete s_P;
368 s_P = 0; // on next call, backend will be recycled
369 L<<Logger::Error<<"TCP nameserver had error, cycling backend: "<<ae.reason<<endl;
370 }
371 catch(NetworkError &e) {
372 L<<Logger::Info<<"TCP Connection Thread died because of network error: "<<e.what()<<endl;
373 }
374
375 catch(std::exception &e) {
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 }
382 d_connectionroom_sem->post();
383 Utility::closesocket(fd);
384
385 return 0;
386 }
387
388
389 // call this method with s_plock held!
390 bool TCPNameserver::canDoAXFR(shared_ptr<DNSPacket> q)
391 {
392 if(::arg().mustDo("disable-axfr"))
393 return false;
394
395 if(q->d_havetsig) { // if you have one, it must be good
396 TSIGRecordContent trc;
397 string keyname, secret;
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 }
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;
416 return true;
417 }
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
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
473 L<<Logger::Error<<"AXFR of domain '"<<q->qdomain<<"' denied: client IP "<<q->getRemote()<<" has no permission"<<endl;
474 return false;
475 }
476
477 namespace {
478 struct NSECXEntry
479 {
480 set<uint16_t> d_set;
481 unsigned int d_ttl;
482 bool d_auth;
483 };
484
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 }
497
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 }
506 }
507
508
509 /** do the actual zone transfer. Return 0 in case of error, 1 in case of success */
510 int TCPNameserver::doAXFR(const string &target, shared_ptr<DNSPacket> q, int outsock)
511 {
512 bool noAXFRBecauseOfNSEC3Narrow=false;
513 NSEC3PARAMRecordContent ns3pr;
514 bool narrow;
515 bool NSEC3Zone=false;
516
517 DNSSECKeeper dk;
518 dk.clearCaches(target);
519 bool securedZone = dk.isSecuredZone(target);
520 bool presignedZone = dk.isPresigned(target);
521
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 }
528 }
529
530 shared_ptr<DNSPacket> outpacket= getFreshAXFRPacket(q);
531 if(q->d_dnssecOk)
532 outpacket->d_dnssecOk=true; // RFC 5936, 2.2.5 'SHOULD'
533
534 if(noAXFRBecauseOfNSEC3Narrow) {
535 L<<Logger::Error<<"AXFR of domain '"<<target<<"' denied to "<<q->getRemote()<<endl;
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
538 sendPacket(outpacket,outsock);
539 return 0;
540 }
541
542 L<<Logger::Error<<"AXFR of domain '"<<target<<"' initiated by "<<q->getRemote()<<endl;
543
544 SOAData sd;
545 sd.db=(DNSBackend *)-1; // force uncached answer
546 {
547 Lock l(&s_plock);
548 DLOG(L<<"Looking for SOA"<<endl); // find domain_id via SOA and list complete domain. No SOA, no AXFR
549 if(!s_P) {
550 L<<Logger::Error<<"TCP server is without backend connections in doAXFR, launching"<<endl;
551 s_P=new PacketHandler;
552 }
553
554 if(!s_P->getBackend()->getSOA(target, sd) || !canDoAXFR(q)) {
555 L<<Logger::Error<<"AXFR of domain '"<<target<<"' failed: not authoritative"<<endl;
556 outpacket->setRcode(9); // 'NOTAUTH'
557 sendPacket(outpacket,outsock);
558 return 0;
559 }
560 }
561
562 UeberBackend db;
563 sd.db=(DNSBackend *)-1; // force uncached answer
564 if(!db.getSOA(target, sd)) {
565 L<<Logger::Error<<"AXFR of domain '"<<target<<"' failed: not authoritative in second instance"<<endl;
566 outpacket->setRcode(9); // 'NOTAUTH'
567 sendPacket(outpacket,outsock);
568 return 0;
569 }
570
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);
574 sendPacket(outpacket,outsock);
575 return 0;
576 }
577
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 }
589
590
591 UeberBackend signatureDB;
592
593 // SOA *must* go out first, our signing pipe might reorder
594 DLOG(L<<"Sending out SOA"<<endl);
595 DNSResourceRecord soa = makeDNSRRFromSOAData(sd);
596 outpacket->addRecord(soa);
597 editSOA(dk, sd.qname, outpacket.get());
598 if(securedZone) {
599 set<string, CIStringCompare> authSet;
600 authSet.insert(target);
601 addRRSigs(dk, signatureDB, authSet, outpacket->getRRS());
602 }
603
604 if(!tsigkeyname.empty())
605 outpacket->setTSIGDetails(trc, tsigkeyname, tsigsecret, trc.d_mac); // first answer is 'normal'
606
607 sendPacket(outpacket, outsock);
608
609 trc.d_mac = outpacket->d_trc.d_mac;
610 outpacket = getFreshAXFRPacket(q);
611
612 ChunkedSigningPipe csp(target, securedZone, "", ::arg().asNum("signing-threads", 1));
613
614 typedef map<string, NSECXEntry> nsecxrepo_t;
615 nsecxrepo_t nsecxrepo;
616
617 // this is where the DNSKEYs go in
618
619 DNSSECKeeper::keyset_t keys = dk.getKeys(target);
620
621 DNSResourceRecord rr;
622
623 rr.qname = target;
624 rr.ttl = sd.default_ttl;
625 rr.auth = 1; // please sign!
626
627 BOOST_FOREACH(const DNSSECKeeper::keyset_t::value_type& value, keys) {
628 rr.qtype = QType(QType::DNSKEY);
629 rr.content = value.first.getDNSKEY().getZoneRepresentation();
630 string keyname = NSEC3Zone ? hashQNameWithSalt(ns3pr.d_iterations, ns3pr.d_salt, rr.qname) : labelReverse(rr.qname);
631 NSECXEntry& ne = nsecxrepo[keyname];
632
633 ne.d_set.insert(rr.qtype.getCode());
634 ne.d_ttl = sd.default_ttl;
635 csp.submit(rr);
636 }
637
638 if(::arg().mustDo("direct-dnskey")) {
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
646 uint8_t flags;
647
648 if(NSEC3Zone) { // now stuff in the NSEC3PARAM
649 flags = ns3pr.d_flags;
650 rr.qtype = QType(QType::NSEC3PARAM);
651 ns3pr.d_flags = 0;
652 rr.content = ns3pr.getZoneRepresentation();
653 ns3pr.d_flags = flags;
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 }
660
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
669
670 const bool rectify = !(presignedZone || ::arg().mustDo("disable-axfr-rectify"));
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
742 /* now write all other records */
743
744 string keyname;
745 set<string> ns3rrs;
746 unsigned int udiff;
747 DTime dt;
748 dt.set();
749 int records=0;
750 BOOST_FOREACH(DNSResourceRecord &rr, rrs) {
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)));
755 continue;
756 }
757
758 // only skip the DNSKEY if direct-dnskey is enabled, to avoid changing behaviour
759 // when it is not enabled.
760 if(::arg().mustDo("direct-dnskey") && rr.qtype.getCode() == QType::DNSKEY)
761 continue;
762
763 records++;
764 if(securedZone && (rr.auth || rr.qtype.getCode() == QType::NS)) {
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;
769 ne.d_auth = (ne.d_auth || rr.auth || (NSEC3Zone && (!ns3pr.d_flags || (presignedZone && ns3pr.d_flags))));
770 if (rr.qtype.getCode()) {
771 ne.d_set.insert(rr.qtype.getCode());
772 }
773 }
774 }
775
776 if (!rr.qtype.getCode())
777 continue; // skip empty non-terminals
778
779 if(rr.qtype.getCode() == QType::SOA)
780 continue; // skip SOA - would indicate end of AXFR
781
782 if(csp.submit(rr)) {
783 for(;;) {
784 outpacket->getRRS() = csp.getChunk();
785 if(!outpacket->getRRS().empty()) {
786 if(!tsigkeyname.empty())
787 outpacket->setTSIGDetails(trc, tsigkeyname, tsigsecret, trc.d_mac, true);
788 sendPacket(outpacket, outsock);
789 trc.d_mac=outpacket->d_trc.d_mac;
790 outpacket=getFreshAXFRPacket(q);
791 }
792 else
793 break;
794 }
795 }
796 }
797 /*
798 udiff=dt.udiffNoReset();
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;
802 */
803 if(securedZone) {
804 if(NSEC3Zone) {
805 for(nsecxrepo_t::const_iterator iter = nsecxrepo.begin(); iter != nsecxrepo.end(); ++iter) {
806 if(iter->second.d_auth && (!presignedZone || !ns3pr.d_flags || ns3rrs.count(iter->first))) {
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();
819 while((!inext->second.d_auth || (presignedZone && ns3pr.d_flags && !ns3rrs.count(inext->first))) && inext != iter)
820 {
821 inext++;
822 if(inext == nsecxrepo.end())
823 inext = nsecxrepo.begin();
824 }
825 n3rc.d_nexthash = inext->first;
826 rr.qname = dotConcat(toBase32Hex(iter->first), sd.qname);
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;
845 }
846 }
847 }
848 }
849 }
850 else for(nsecxrepo_t::const_iterator iter = nsecxrepo.begin(); iter != nsecxrepo.end(); ++iter) {
851 NSECRecordContent nrc;
852 nrc.d_set = iter->second.d_set;
853 nrc.d_set.insert(QType::RRSIG);
854 nrc.d_set.insert(QType::NSEC);
855 if(boost::next(iter) != nsecxrepo.end()) {
856 nrc.d_next = labelReverse(boost::next(iter)->first);
857 }
858 else
859 nrc.d_next=labelReverse(nsecxrepo.begin()->first);
860
861 rr.qname = labelReverse(iter->first);
862
863 rr.ttl = sd.default_ttl;
864 rr.content = nrc.getZoneRepresentation();
865 rr.qtype = QType::NSEC;
866 rr.d_place = DNSResourceRecord::ANSWER;
867 rr.auth=true;
868 if(csp.submit(rr)) {
869 for(;;) {
870 outpacket->getRRS() = csp.getChunk();
871 if(!outpacket->getRRS().empty()) {
872 if(!tsigkeyname.empty())
873 outpacket->setTSIGDetails(trc, tsigkeyname, tsigsecret, trc.d_mac, true);
874 sendPacket(outpacket, outsock);
875 trc.d_mac=outpacket->d_trc.d_mac;
876 outpacket=getFreshAXFRPacket(q);
877 }
878 else
879 break;
880 }
881 }
882 }
883 }
884 /*
885 udiff=dt.udiffNoReset();
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;
889 * */
890 for(;;) {
891 outpacket->getRRS() = csp.getChunk(true); // flush the pipe
892 if(!outpacket->getRRS().empty()) {
893 if(!tsigkeyname.empty())
894 outpacket->setTSIGDetails(trc, tsigkeyname, tsigsecret, trc.d_mac, true); // first answer is 'normal'
895 sendPacket(outpacket, outsock);
896 trc.d_mac=outpacket->d_trc.d_mac;
897 outpacket=getFreshAXFRPacket(q);
898 }
899 else
900 break;
901 }
902
903 udiff=dt.udiffNoReset();
904 if(securedZone)
905 L<<Logger::Info<<"Done signing: "<<csp.d_signed/(udiff/1000000.0)<<" sigs/s, "<<endl;
906
907 DLOG(L<<"Done writing out records"<<endl);
908 /* and terminate with yet again the SOA record */
909 outpacket=getFreshAXFRPacket(q);
910 outpacket->addRecord(soa);
911 editSOA(dk, sd.qname, outpacket.get());
912 if(!tsigkeyname.empty())
913 outpacket->setTSIGDetails(trc, tsigkeyname, tsigsecret, trc.d_mac, true);
914
915 sendPacket(outpacket, outsock);
916
917 DLOG(L<<"last packet - close"<<endl);
918 L<<Logger::Error<<"AXFR of domain '"<<target<<"' to "<<q->getRemote()<<" finished"<<endl;
919
920 return 1;
921 }
922
923 int 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;
932
933 dk.clearCaches(q->qdomain);
934 bool securedZone = dk.isSecuredZone(q->qdomain);
935 if(dk.getNSEC3PARAM(q->qdomain, &ns3pr, &narrow)) {
936 if(narrow) {
937 L<<Logger::Error<<"Not doing IXFR of an NSEC3 narrow zone."<<endl;
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
1045 TCPNameserver::~TCPNameserver()
1046 {
1047 delete d_connectionroom_sem;
1048 }
1049
1050 TCPNameserver::TCPNameserver()
1051 {
1052 // sem_init(&d_connectionroom_sem,0,::arg().asNum("max-tcp-connections"));
1053 d_connectionroom_sem = new Semaphore( ::arg().asNum( "max-tcp-connections" ));
1054
1055 s_timeout=10;
1056 vector<string>locals;
1057 stringtok(locals,::arg()["local-address"]," ,");
1058
1059 vector<string>locals6;
1060 stringtok(locals6,::arg()["local-ipv6"]," ,");
1061
1062 if(locals.empty() && locals6.empty())
1063 throw PDNSException("No local address specified");
1064
1065 d_ng.toMasks(::arg()["allow-axfr-ips"] );
1066
1067 signal(SIGPIPE,SIG_IGN);
1068
1069 for(vector<string>::const_iterator laddr=locals.begin();laddr!=locals.end();++laddr) {
1070 int s=socket(AF_INET,SOCK_STREAM,0);
1071
1072 if(s<0)
1073 throw PDNSException("Unable to acquire TCP socket: "+stringerror());
1074
1075 Utility::setCloseOnExec(s);
1076
1077 ComboAddress local(*laddr, ::arg().asNum("local-port"));
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 }
1084
1085 if(::bind(s, (sockaddr*)&local, local.getSocklen())<0) {
1086 close(s);
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;
1092 throw PDNSException("Unable to bind to TCP socket");
1093 }
1094 }
1095
1096 listen(s,128);
1097 L<<Logger::Error<<"TCP server bound to "<<local.toStringWithPort()<<endl;
1098 d_sockets.push_back(s);
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);
1105 }
1106
1107 #if HAVE_IPV6
1108 for(vector<string>::const_iterator laddr=locals6.begin();laddr!=locals6.end();++laddr) {
1109 int s=socket(AF_INET6,SOCK_STREAM,0);
1110
1111 if(s<0)
1112 throw PDNSException("Unable to acquire TCPv6 socket: "+stringerror());
1113
1114 Utility::setCloseOnExec(s);
1115
1116 ComboAddress local(*laddr, ::arg().asNum("local-port"));
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 }
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 }
1126 if(bind(s, (const sockaddr*)&local, local.getSocklen())<0) {
1127 close(s);
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;
1133 throw PDNSException("Unable to bind to TCPv6 socket");
1134 }
1135 }
1136
1137 listen(s,128);
1138 L<<Logger::Error<<"TCPv6 server bound to "<<local.toStringWithPort()<<endl; // this gets %eth0 right
1139 d_sockets.push_back(s);
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);
1147 }
1148 #endif
1149 }
1150
1151
1152 //! Start of TCP operations thread, we launch a new thread for each incoming TCP question
1153 void TCPNameserver::thread()
1154 {
1155 try {
1156 for(;;) {
1157 int fd;
1158 struct sockaddr_in remote;
1159 Utility::socklen_t addrlen=sizeof(remote);
1160
1161 int ret=poll(&d_prfds[0], d_prfds.size(), -1); // blocks, forever if need be
1162 if(ret <= 0)
1163 continue;
1164
1165 int sock=-1;
1166 BOOST_FOREACH(const struct pollfd& pfd, d_prfds) {
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
1188 if(pthread_create(&tid, 0, &doConnection, reinterpret_cast<void*>(fd))) {
1189 L<<Logger::Error<<"Error creating thread: "<<stringerror()<<endl;
1190 d_connectionroom_sem->post();
1191 }
1192 }
1193 }
1194 }
1195 }
1196 }
1197 catch(PDNSException &AE) {
1198 L<<Logger::Error<<"TCP Nameserver thread dying because of fatal error: "<<AE.reason<<endl;
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