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