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