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