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