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