• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

PowerDNS / pdns / 11049952298

26 Sep 2024 09:59AM UTC coverage: 64.7% (+0.005%) from 64.695%
11049952298

Pull #14594

github

web-flow
Merge b1726e0c0 into 42c3a1e1b
Pull Request #14594: auth udp: use stubDoResolve for ALIAS

37040 of 87934 branches covered (42.12%)

Branch coverage included in aggregate %.

25 of 54 new or added lines in 2 files covered. (46.3%)

53 existing lines in 14 files now uncovered.

124664 of 161993 relevant lines covered (76.96%)

4875762.83 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

66.92
/pdns/tcpreceiver.cc
1
/*
2
    PowerDNS Versatile Database Driven Nameserver
3
    Copyright (C) 2002-2012  PowerDNS.COM BV
4

5
    This program is free software; you can redistribute it and/or modify
6
    it under the terms of the GNU General Public License version 2
7
    as published by the Free Software Foundation
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

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
20
    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
21
*/
22
#ifdef HAVE_CONFIG_H
23
#include "config.h"
24
#endif
25
#include <boost/algorithm/string.hpp>
26
#include <boost/scoped_array.hpp>
27
#include "auth-packetcache.hh"
28
#include "utility.hh"
29
#include "threadname.hh"
30
#include "dnssecinfra.hh"
31
#include "dnsseckeeper.hh"
32
#include <cstdio>
33
#include "base32.hh"
34
#include <cstring>
35
#include <cstdlib>
36
#include <sys/types.h>
37
#include <netinet/tcp.h>
38
#include <iostream>
39
#include <string>
40
#include "tcpreceiver.hh"
41
#include "sstuff.hh"
42

43
#include <cerrno>
44
#include <csignal>
45
#include "base64.hh"
46
#include "ueberbackend.hh"
47
#include "dnspacket.hh"
48
#include "nameserver.hh"
49
#include "distributor.hh"
50
#include "lock.hh"
51
#include "logger.hh"
52
#include "arguments.hh"
53

54
#include "auth-main.hh"
55
#include "packethandler.hh"
56
#include "statbag.hh"
57
#include "communicator.hh"
58
#include "namespaces.hh"
59
#include "signingpipe.hh"
60
#include "stubresolver.hh"
61
#include "proxy-protocol.hh"
62
#include "noinitvector.hh"
63
#include "gss_context.hh"
64
#include "pdnsexception.hh"
65
extern AuthPacketCache PC;
66
extern StatBag S;
67

68
/**
69
\file tcpreceiver.cc
70
\brief This file implements the tcpreceiver that receives and answers questions over TCP/IP
71
*/
72

73
std::unique_ptr<Semaphore> TCPNameserver::d_connectionroom_sem{nullptr};
74
LockGuarded<std::unique_ptr<PacketHandler>> TCPNameserver::s_P{nullptr};
75
unsigned int TCPNameserver::d_maxTCPConnections = 0;
76
NetmaskGroup TCPNameserver::d_ng;
77
size_t TCPNameserver::d_maxTransactionsPerConn;
78
size_t TCPNameserver::d_maxConnectionsPerClient;
79
unsigned int TCPNameserver::d_idleTimeout;
80
unsigned int TCPNameserver::d_maxConnectionDuration;
81
LockGuarded<std::map<ComboAddress,size_t,ComboAddress::addressOnlyLessThan>> TCPNameserver::s_clientsCount;
82

83
void TCPNameserver::go()
84
{
159✔
85
  g_log<<Logger::Error<<"Creating backend connection for TCP"<<endl;
159✔
86
  s_P.lock()->reset();
159✔
87
  try {
159✔
88
    *(s_P.lock()) = make_unique<PacketHandler>();
159✔
89
  }
159✔
90
  catch(PDNSException &ae) {
159✔
91
    g_log<<Logger::Error<<"TCP server is unable to launch backends - will try again when questions come in: "<<ae.reason<<endl;
×
92
  }
×
93

94
  std::thread th([this](){thread();});
159✔
95
  th.detach();
159✔
96
}
159✔
97

98
// throws PDNSException if things didn't go according to plan, returns 0 if really 0 bytes were read
99
static int readnWithTimeout(int fd, void* buffer, unsigned int n, unsigned int idleTimeout, bool throwOnEOF=true, unsigned int totalTimeout=0)
100
{
50,649✔
101
  unsigned int bytes=n;
50,649✔
102
  char *ptr = (char*)buffer;
50,649✔
103
  int ret;
50,649✔
104
  time_t start = 0;
50,649✔
105
  unsigned int remainingTotal = totalTimeout;
50,649✔
106
  if (totalTimeout) {
50,649!
107
    start = time(nullptr);
×
108
  }
×
109
  while(bytes) {
100,283✔
110
    ret=read(fd, ptr, bytes);
66,481✔
111
    if(ret < 0) {
66,481✔
112
      if(errno==EAGAIN) {
15,934✔
113
        ret=waitForData(fd, (totalTimeout == 0 || idleTimeout <= remainingTotal) ? idleTimeout : remainingTotal);
15,832!
114
        if(ret < 0)
15,832!
115
          throw NetworkError("Waiting for data read");
×
116
        if(!ret)
15,832!
117
          throw NetworkError("Timeout reading data");
×
118
        continue;
15,832✔
119
      }
15,832✔
120
      else
102✔
121
        throw NetworkError("Reading data: "+stringerror());
102✔
122
    }
15,934✔
123
    if(!ret) {
50,547✔
124
      if(!throwOnEOF && n == bytes)
16,745!
125
        return 0;
16,745✔
126
      else
×
127
        throw NetworkError("Did not fulfill read from TCP due to EOF");
×
128
    }
16,745✔
129

130
    ptr += ret;
33,802✔
131
    bytes -= ret;
33,802✔
132
    if (totalTimeout) {
33,802!
133
      time_t now = time(nullptr);
×
134
      const auto elapsed = now - start;
×
135
      if (elapsed >= static_cast<time_t>(remainingTotal)) {
×
136
        throw NetworkError("Timeout while reading data");
×
137
      }
×
138
      start = now;
×
139
      if (elapsed > 0) {
×
140
        remainingTotal -= elapsed;
×
141
      }
×
142
    }
×
143
  }
33,802✔
144
  return n;
33,802✔
145
}
50,649✔
146

147
// ditto
148
static void writenWithTimeout(int fd, const void *buffer, unsigned int n, unsigned int idleTimeout)
149
{
38,275✔
150
  unsigned int bytes=n;
38,275✔
151
  const char *ptr = (char*)buffer;
38,275✔
152
  int ret;
38,275✔
153
  while(bytes) {
76,496✔
154
    ret=write(fd, ptr, bytes);
38,275✔
155
    if(ret < 0) {
38,275✔
156
      if(errno==EAGAIN) {
54!
157
        ret=waitForRWData(fd, false, idleTimeout, 0);
×
158
        if(ret < 0)
×
159
          throw NetworkError("Waiting for data write");
×
160
        if(!ret)
×
161
          throw NetworkError("Timeout writing data");
×
162
        continue;
×
163
      }
×
164
      else
54✔
165
        throw NetworkError("Writing data: "+stringerror());
54✔
166
    }
54✔
167
    if(!ret) {
38,221!
168
      throw NetworkError("Did not fulfill TCP write due to EOF");
×
169
    }
×
170

171
    ptr += ret;
38,221✔
172
    bytes -= ret;
38,221✔
173
  }
38,221✔
174
}
38,275✔
175

176
void TCPNameserver::sendPacket(std::unique_ptr<DNSPacket>& p, int outsock, bool last)
177
{
38,276✔
178
  uint16_t len=htons(p->getString(true).length());
38,276✔
179

180
  // this also calls p->getString; call it after our explicit call so throwsOnTruncation=true is honoured
181
  g_rs.submitResponse(*p, false, last);
38,276✔
182

183
  string buffer((const char*)&len, 2);
38,276✔
184
  buffer.append(p->getString());
38,276✔
185
  writenWithTimeout(outsock, buffer.c_str(), buffer.length(), d_idleTimeout);
38,276✔
186
}
38,276✔
187

188

189
void TCPNameserver::getQuestion(int fd, char *mesg, int pktlen, const ComboAddress &remote, unsigned int totalTime)
190
try
33,802✔
191
{
33,802✔
192
  readnWithTimeout(fd, mesg, pktlen, d_idleTimeout, true, totalTime);
33,802✔
193
}
33,802✔
194
catch(NetworkError& ae) {
33,802✔
195
  throw NetworkError("Error reading DNS data from TCP client "+remote.toString()+": "+ae.what());
×
196
}
×
197

198
static bool maxConnectionDurationReached(unsigned int maxConnectionDuration, time_t start, unsigned int& remainingTime)
199
{
50,649✔
200
  if (maxConnectionDuration) {
50,649!
201
    time_t elapsed = time(nullptr) - start;
×
202
    if (elapsed >= maxConnectionDuration) {
×
203
      return true;
×
204
    }
×
205
    if (elapsed > 0) {
×
206
      remainingTime = static_cast<unsigned int>(maxConnectionDuration - elapsed);
×
207
    }
×
208
  }
×
209
  return false;
50,649✔
210
}
50,649✔
211

212
void TCPNameserver::decrementClientCount(const ComboAddress& remote)
213
{
16,901✔
214
  if (d_maxConnectionsPerClient) {
16,901!
215
    auto count = s_clientsCount.lock();
×
216
    auto it = count->find(remote);
×
217
    if (it == count->end()) {
×
218
      // this is worrying, but nothing we can do at this point
219
      return;
×
220
    }
×
221
    --it->second;
×
222
    if (it->second == 0) {
×
223
      count->erase(it);
×
224
    }
×
225
  }
×
226
}
16,901✔
227

228
void TCPNameserver::doConnection(int fd)
229
{
16,901✔
230
  setThreadName("pdns/tcpConnect");
16,901✔
231
  std::unique_ptr<DNSPacket> packet;
16,901✔
232
  ComboAddress remote, accountremote;
16,901✔
233
  socklen_t remotelen=sizeof(remote);
16,901✔
234
  size_t transactions = 0;
16,901✔
235
  time_t start = 0;
16,901✔
236
  if (d_maxConnectionDuration) {
16,901!
237
    start = time(nullptr);
×
238
  }
×
239

240
  if(getpeername(fd, (struct sockaddr *)&remote, &remotelen) < 0) {
16,901!
241
    g_log<<Logger::Warning<<"Received question from socket which had no remote address, dropping ("<<stringerror()<<")"<<endl;
×
242
    d_connectionroom_sem->post();
×
243
    try {
×
244
      closesocket(fd);
×
245
    }
×
246
    catch(const PDNSException& e) {
×
247
      g_log<<Logger::Error<<"Error closing TCP socket: "<<e.reason<<endl;
×
248
    }
×
249
    return;
×
250
  }
×
251

252
  setNonBlocking(fd);
16,901✔
253
  try {
16,901✔
254
    int mesgsize=65535;
16,901✔
255
    boost::scoped_array<char> mesg(new char[mesgsize]);
16,901✔
256
    std::optional<ComboAddress> inner_remote;
16,901✔
257
    bool inner_tcp = false;
16,901✔
258

259
    DLOG(g_log<<"TCP Connection accepted on fd "<<fd<<endl);
16,901✔
260
    bool logDNSQueries= ::arg().mustDo("log-dns-queries");
16,901✔
261
    if (g_proxyProtocolACL.match(remote)) {
16,901!
262
      unsigned int remainingTime = 0;
×
263
      PacketBuffer proxyData;
×
264
      proxyData.reserve(g_proxyProtocolMaximumSize);
×
265
      ssize_t used;
×
266

267
      // this for-loop ends by throwing, or by having gathered a complete proxy header
268
      for (;;) {
×
269
        used = isProxyHeaderComplete(proxyData);
×
270
        if (used < 0) {
×
271
          ssize_t origsize = proxyData.size();
×
272
          proxyData.resize(origsize + -used);
×
273
          if (maxConnectionDurationReached(d_maxConnectionDuration, start, remainingTime)) {
×
274
            throw NetworkError("Error reading PROXYv2 header from TCP client "+remote.toString()+": maximum TCP connection duration exceeded");
×
275
          }
×
276

277
          try {
×
278
            readnWithTimeout(fd, &proxyData[origsize], -used, d_idleTimeout, true, remainingTime);
×
279
          }
×
280
          catch(NetworkError& ae) {
×
281
            throw NetworkError("Error reading PROXYv2 header from TCP client "+remote.toString()+": "+ae.what());
×
282
          }
×
283
        }
×
284
        else if (used == 0) {
×
285
          throw NetworkError("Error reading PROXYv2 header from TCP client "+remote.toString()+": PROXYv2 header was invalid");
×
286
        }
×
287
        else if (static_cast<size_t>(used) > g_proxyProtocolMaximumSize) {
×
288
          throw NetworkError("Error reading PROXYv2 header from TCP client "+remote.toString()+": PROXYv2 header too big");
×
289
        }
×
290
        else { // used > 0 && used <= g_proxyProtocolMaximumSize
×
291
          break;
×
292
        }
×
293
      }
×
294
      ComboAddress psource, pdestination;
×
295
      bool proxyProto, tcp;
×
296
      std::vector<ProxyProtocolValue> ppvalues;
×
297

298
      used = parseProxyHeader(proxyData, proxyProto, psource, pdestination, tcp, ppvalues);
×
299
      if (used <= 0) {
×
300
        throw NetworkError("Error reading PROXYv2 header from TCP client "+remote.toString()+": PROXYv2 header was invalid");
×
301
      }
×
302
      if (static_cast<size_t>(used) > g_proxyProtocolMaximumSize) {
×
303
        throw NetworkError("Error reading PROXYv2 header from TCP client "+remote.toString()+": PROXYv2 header was oversized");
×
304
      }
×
305
      inner_remote = psource;
×
306
      inner_tcp = tcp;
×
307
      accountremote = psource;
×
308
    }
×
309
    else {
16,901✔
310
      accountremote = remote;
16,901✔
311
    }
16,901✔
312

313
    for(;;) {
33,748✔
314
      unsigned int remainingTime = 0;
33,748✔
315
      transactions++;
33,748✔
316
      if (d_maxTransactionsPerConn && transactions > d_maxTransactionsPerConn) {
33,748!
317
        g_log << Logger::Notice<<"TCP Remote "<< remote <<" exceeded the number of transactions per connection, dropping.";
×
318
        break;
×
319
      }
×
320
      if (maxConnectionDurationReached(d_maxConnectionDuration, start, remainingTime)) {
33,748!
321
        g_log << Logger::Notice<<"TCP Remote "<< remote <<" exceeded the maximum TCP connection duration, dropping.";
×
322
        break;
×
323
      }
×
324

325
      uint16_t pktlen;
33,748✔
326
      if(!readnWithTimeout(fd, &pktlen, 2, d_idleTimeout, false, remainingTime))
33,748✔
327
        break;
16,745✔
328
      else
17,003✔
329
        pktlen=ntohs(pktlen);
17,003✔
330

331
      // this check will always be false *if* no one touches
332
      // the mesg array. pktlen can be maximum of 65535 as
333
      // it is 2 byte unsigned variable. In getQuestion, we
334
      // write to 0 up to pktlen-1 so 65535 is just right.
335

336
      // do not remove this check as it will catch if someone
337
      // decreases the mesg buffer size for some reason.
338
      if(pktlen > mesgsize) {
17,003!
339
        g_log<<Logger::Warning<<"Received an overly large question from "<<remote.toString()<<", dropping"<<endl;
×
340
        break;
×
341
      }
×
342

343
      if (maxConnectionDurationReached(d_maxConnectionDuration, start, remainingTime)) {
17,003!
344
        g_log << Logger::Notice<<"TCP Remote "<< remote <<" exceeded the maximum TCP connection duration, dropping.";
×
345
        break;
×
346
      }
×
347

348
      getQuestion(fd, mesg.get(), pktlen, remote, remainingTime);
17,003✔
349
      S.inc("tcp-queries");
17,003✔
350
      if (accountremote.sin4.sin_family == AF_INET6)
17,003✔
351
        S.inc("tcp6-queries");
2✔
352
      else
17,001✔
353
        S.inc("tcp4-queries");
17,001✔
354

355
      packet=make_unique<DNSPacket>(true);
17,003✔
356
      packet->setRemote(&remote);
17,003✔
357
      packet->d_tcp=true;
17,003✔
358
      if (inner_remote) {
17,003!
359
        packet->d_inner_remote = inner_remote;
×
360
        packet->d_tcp = inner_tcp;
×
361
      }
×
362
      packet->setSocket(fd);
17,003✔
363
      if(packet->parse(mesg.get(), pktlen)<0)
17,003!
364
        break;
×
365

366
      if (packet->hasEDNSCookie())
17,003!
367
        S.inc("tcp-cookie-queries");
×
368

369
      if(packet->qtype.getCode()==QType::AXFR) {
17,003✔
370
        packet->d_xfr=true;
1,607✔
371
        doAXFR(packet->qdomain, packet, fd);
1,607✔
372
        continue;
1,607✔
373
      }
1,607✔
374

375
      if(packet->qtype.getCode()==QType::IXFR) {
15,396✔
376
        packet->d_xfr=true;
96✔
377
        doIXFR(packet, fd);
96✔
378
        continue;
96✔
379
      }
96✔
380

381
      std::unique_ptr<DNSPacket> reply;
15,300✔
382
      auto cached = make_unique<DNSPacket>(false);
15,300✔
383
      if(logDNSQueries)  {
15,300!
384
        g_log << Logger::Notice<<"TCP Remote "<< packet->getRemoteString() <<" wants '" << packet->qdomain<<"|"<<packet->qtype.toString() <<
×
385
        "', do = " <<packet->d_dnssecOk <<", bufsize = "<< packet->getMaxReplyLen();
×
386
      }
×
387

388
      if(PC.enabled()) {
15,300✔
389
        if(packet->couldBeCached() && PC.get(*packet, *cached)) { // short circuit - does the PacketCache recognize this question?
3,806!
390
          if(logDNSQueries)
510!
391
            g_log<<": packetcache HIT"<<endl;
×
392
          cached->setRemote(&packet->d_remote);
510✔
393
          cached->d_inner_remote = packet->d_inner_remote;
510✔
394
          cached->d.id=packet->d.id;
510✔
395
          cached->d.rd=packet->d.rd; // copy in recursion desired bit
510✔
396
          cached->commitD(); // commit d to the packet                        inlined
510✔
397

398
          sendPacket(cached, fd); // presigned, don't do it again
510✔
399
          continue;
510✔
400
        }
510✔
401
        if(logDNSQueries)
3,296!
402
            g_log<<": packetcache MISS"<<endl;
×
403
      } else {
11,494✔
404
        if (logDNSQueries) {
11,494!
405
          g_log<<endl;
×
406
        }
×
407
      }
11,494✔
408
      {
14,790✔
409
        auto packetHandler = s_P.lock();
14,790✔
410
        if (!*packetHandler) {
14,790!
411
          g_log<<Logger::Warning<<"TCP server is without backend connections, launching"<<endl;
×
412
          *packetHandler = make_unique<PacketHandler>();
×
413
        }
×
414

415
        reply = (*packetHandler)->doQuestion(*packet); // we really need to ask the backend :-)
14,790✔
416
      }
14,790✔
417

418
      if(!reply)  // unable to write an answer?
14,790!
UNCOV
419
        break;
×
420

421
      sendPacket(reply, fd);
14,790✔
422
#ifdef ENABLE_GSS_TSIG
14,790✔
423
      if (g_doGssTSIG) {
14,790!
424
        packet->cleanupGSS(reply->d.rcode);
×
425
      }
×
426
#endif
14,790✔
427
    }
14,790✔
428
  }
16,901✔
429
  catch(PDNSException &ae) {
16,901✔
430
    s_P.lock()->reset(); // on next call, backend will be recycled
×
431
    g_log << Logger::Error << "TCP Connection Thread for client " << remote << " failed, cycling backend: " << ae.reason << endl;
×
432
  }
×
433
  catch(NetworkError &e) {
16,901✔
434
    g_log << Logger::Info << "TCP Connection Thread for client " << remote << " died because of network error: " << e.what() << endl;
156✔
435
  }
156✔
436

437
  catch(std::exception &e) {
16,901✔
438
    s_P.lock()->reset(); // on next call, backend will be recycled
×
439
    g_log << Logger::Error << "TCP Connection Thread for client " << remote << " died because of STL error, cycling backend: " << e.what() << endl;
×
440
  }
×
441
  catch( ... )
16,901✔
442
  {
16,901✔
443
    s_P.lock()->reset(); // on next call, backend will be recycled
×
444
    g_log << Logger::Error << "TCP Connection Thread for client " << remote << " caught unknown exception, cycling backend." << endl;
×
445
  }
×
446
  d_connectionroom_sem->post();
16,901✔
447

448
  try {
16,901✔
449
    closesocket(fd);
16,901✔
450
  }
16,901✔
451
  catch(const PDNSException& e) {
16,901✔
452
    g_log << Logger::Error << "Error closing TCP socket for client " << remote << ": " << e.reason << endl;
×
453
  }
×
454
  decrementClientCount(remote);
16,901✔
455
}
16,901✔
456

457

458
bool TCPNameserver::canDoAXFR(std::unique_ptr<DNSPacket>& q, bool isAXFR, std::unique_ptr<PacketHandler>& packetHandler)
459
{
1,703✔
460
  if(::arg().mustDo("disable-axfr"))
1,703!
461
    return false;
×
462

463
  string logPrefix=string(isAXFR ? "A" : "I")+"XFR-out zone '"+q->qdomain.toLogString()+"', client '"+q->getInnerRemote().toStringWithPort()+"', ";
1,703✔
464

465
  if(q->d_havetsig) { // if you have one, it must be good
1,703✔
466
    TSIGRecordContent tsigContent;
215✔
467
    DNSName tsigkeyname;
215✔
468
    string secret;
215✔
469
    if (!packetHandler->checkForCorrectTSIG(*q, &tsigkeyname, &secret, &tsigContent)) {
215✔
470
      return false;
128✔
471
    } else {
128✔
472
      getTSIGHashEnum(tsigContent.d_algoName, q->d_tsig_algo);
87✔
473
#ifdef ENABLE_GSS_TSIG
87✔
474
      if (g_doGssTSIG && q->d_tsig_algo == TSIG_GSS) {
87!
475
        GssContext gssctx(tsigkeyname);
×
476
        if (!gssctx.getPeerPrincipal(q->d_peer_principal)) {
×
477
          g_log<<Logger::Warning<<"Failed to extract peer principal from GSS context with keyname '"<<tsigkeyname<<"'"<<endl;
×
478
        }
×
479
      }
×
480
#endif
87✔
481
    }
87✔
482

483
    DNSSECKeeper dk(packetHandler->getBackend());
87✔
484
#ifdef ENABLE_GSS_TSIG
87✔
485
    if (g_doGssTSIG && q->d_tsig_algo == TSIG_GSS) {
87!
486
      vector<string> princs;
×
487
      packetHandler->getBackend()->getDomainMetadata(q->qdomain, "GSS-ALLOW-AXFR-PRINCIPAL", princs);
×
488
      for(const std::string& princ :  princs) {
×
489
        if (q->d_peer_principal == princ) {
×
490
          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;
×
491
          return true;
×
492
        }
×
493
      }
×
494
      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;
×
495
      return false;
×
496
    }
×
497
#endif
87✔
498
    if(!dk.TSIGGrantsAccess(q->qdomain, tsigkeyname)) {
87!
499
      g_log<<Logger::Warning<<logPrefix<<"denied: key with name '"<<tsigkeyname<<"' and algorithm '"<<getTSIGAlgoName(q->d_tsig_algo)<<"' does not grant access"<<endl;
×
500
      return false;
×
501
    }
×
502
    else {
87✔
503
      g_log<<Logger::Notice<<logPrefix<<"allowed: TSIG signed request with authorized key '"<<tsigkeyname<<"' and algorithm '"<<getTSIGAlgoName(q->d_tsig_algo)<<"'"<<endl;
87✔
504
      return true;
87✔
505
    }
87✔
506
  }
87✔
507

508
  // cerr<<"checking allow-axfr-ips"<<endl;
509
  if(!(::arg()["allow-axfr-ips"].empty()) && d_ng.match( q->getInnerRemote() )) {
1,488!
510
    g_log<<Logger::Notice<<logPrefix<<"allowed: client IP is in allow-axfr-ips"<<endl;
1,487✔
511
    return true;
1,487✔
512
  }
1,487✔
513

514
  FindNS fns;
1✔
515

516
  // cerr<<"doing per-zone-axfr-acls"<<endl;
517
  SOAData sd;
1✔
518
  if(packetHandler->getBackend()->getSOAUncached(q->qdomain,sd)) {
1!
519
    // cerr<<"got backend and SOA"<<endl;
520
    vector<string> acl;
1✔
521
    packetHandler->getBackend()->getDomainMetadata(q->qdomain, "ALLOW-AXFR-FROM", acl);
1✔
522
    for (const auto & i : acl) {
1!
523
      // cerr<<"matching against "<<*i<<endl;
524
      if(pdns_iequals(i, "AUTO-NS")) {
1!
525
        // cerr<<"AUTO-NS magic please!"<<endl;
526

527
        DNSResourceRecord rr;
×
528
        set<DNSName> nsset;
×
529

530
        sd.db->lookup(QType(QType::NS), q->qdomain, sd.domain_id);
×
531
        while (sd.db->get(rr)) {
×
532
          nsset.insert(DNSName(rr.content));
×
533
        }
×
534
        for(const auto & j: nsset) {
×
535
          vector<string> nsips=fns.lookup(j, packetHandler->getBackend());
×
536
          for(const auto & nsip : nsips) {
×
537
            // cerr<<"got "<<*k<<" from AUTO-NS"<<endl;
538
            if(nsip == q->getInnerRemote().toString())
×
539
            {
×
540
              // cerr<<"got AUTO-NS hit"<<endl;
541
              g_log<<Logger::Notice<<logPrefix<<"allowed: client IP is in NSset"<<endl;
×
542
              return true;
×
543
            }
×
544
          }
×
545
        }
×
546
      }
×
547
      else
1✔
548
      {
1✔
549
        Netmask nm = Netmask(i);
1✔
550
        if(nm.match( q->getInnerRemote() ))
1!
551
        {
1✔
552
          g_log<<Logger::Notice<<logPrefix<<"allowed: client IP is in per-zone ACL"<<endl;
1✔
553
          // cerr<<"hit!"<<endl;
554
          return true;
1✔
555
        }
1✔
556
      }
1✔
557
    }
1✔
558
  }
1✔
559

560
  extern CommunicatorClass Communicator;
×
561

562
  if(Communicator.justNotified(q->qdomain, q->getInnerRemote().toString())) { // we just notified this ip
×
563
    g_log<<Logger::Notice<<logPrefix<<"allowed: client IP is from recently notified secondary"<<endl;
×
564
    return true;
×
565
  }
×
566

567
  g_log<<Logger::Warning<<logPrefix<<"denied: client IP has no permission"<<endl;
×
568
  return false;
×
569
}
×
570

571
namespace {
572
  struct NSECXEntry
573
  {
574
    NSECBitmap d_set;
575
    unsigned int d_ttl;
576
    bool d_auth;
577
  };
578

579
  static std::unique_ptr<DNSPacket> getFreshAXFRPacket(std::unique_ptr<DNSPacket>& q)
580
  {
24,583✔
581
    std::unique_ptr<DNSPacket> ret = std::unique_ptr<DNSPacket>(q->replyPacket());
24,583✔
582
    ret->setCompress(false);
24,583✔
583
    ret->d_dnssecOk=false; // RFC 5936, 2.2.5
24,583✔
584
    ret->d_tcp = true;
24,583✔
585
    return ret;
24,583✔
586
  }
24,583✔
587
}
588

589

590
/** do the actual zone transfer. Return 0 in case of error, 1 in case of success */
591
int TCPNameserver::doAXFR(const DNSName &target, std::unique_ptr<DNSPacket>& q, int outsock)  // NOLINT(readability-function-cognitive-complexity)
592
{
1,607✔
593
  string logPrefix="AXFR-out zone '"+target.toLogString()+"', client '"+q->getRemoteStringWithPort()+"', ";
1,607✔
594

595
  std::unique_ptr<DNSPacket> outpacket= getFreshAXFRPacket(q);
1,607✔
596
  if(q->d_dnssecOk)
1,607✔
597
    outpacket->d_dnssecOk=true; // RFC 5936, 2.2.5 'SHOULD'
156✔
598

599
  g_log<<Logger::Warning<<logPrefix<<"transfer initiated"<<endl;
1,607✔
600

601
  // determine if zone exists and AXFR is allowed using existing backend before spawning a new backend.
602
  SOAData sd;
1,607✔
603
  {
1,607✔
604
    auto packetHandler = s_P.lock();
1,607✔
605
    DLOG(g_log<<logPrefix<<"looking for SOA"<<endl);    // find domain_id via SOA and list complete domain. No SOA, no AXFR
1,607✔
606
    if(!*packetHandler) {
1,607!
607
      g_log<<Logger::Warning<<"TCP server is without backend connections in doAXFR, launching"<<endl;
×
608
      *packetHandler = make_unique<PacketHandler>();
×
609
    }
×
610

611
    // canDoAXFR does all the ACL checks, and has the if(disable-axfr) shortcut, call it first.
612
    if (!canDoAXFR(q, true, *packetHandler)) {
1,607✔
613
      g_log<<Logger::Warning<<logPrefix<<"failed: client may not request AXFR"<<endl;
64✔
614
      outpacket->setRcode(RCode::NotAuth);
64✔
615
      sendPacket(outpacket,outsock);
64✔
616
      return 0;
64✔
617
    }
64✔
618

619
    if (!(*packetHandler)->getBackend()->getSOAUncached(target, sd)) {
1,543!
620
      g_log<<Logger::Warning<<logPrefix<<"failed: not authoritative"<<endl;
×
621
      outpacket->setRcode(RCode::NotAuth);
×
622
      sendPacket(outpacket,outsock);
×
623
      return 0;
×
624
    }
×
625
  }
1,543✔
626

627
  UeberBackend db;
1,543✔
628
  if(!db.getSOAUncached(target, sd)) {
1,543!
629
    g_log<<Logger::Warning<<logPrefix<<"failed: not authoritative in second instance"<<endl;
×
630
    outpacket->setRcode(RCode::NotAuth);
×
631
    sendPacket(outpacket,outsock);
×
632
    return 0;
×
633
  }
×
634

635
  bool securedZone = false;
1,543✔
636
  bool presignedZone = false;
1,543✔
637
  bool NSEC3Zone = false;
1,543✔
638
  bool narrow = false;
1,543✔
639

640
  DomainInfo di;
1,543✔
641
  bool isCatalogZone = sd.db->getDomainInfo(target, di, false) && di.isCatalogType();
1,543!
642

643
  NSEC3PARAMRecordContent ns3pr;
1,543✔
644

645
  DNSSECKeeper dk(&db);
1,543✔
646
  DNSSECKeeper::clearCaches(target);
1,543✔
647
  if (!isCatalogZone) {
1,543✔
648
    securedZone = dk.isSecuredZone(target);
1,507✔
649
    presignedZone = dk.isPresigned(target);
1,507✔
650
  }
1,507✔
651

652
  if(securedZone && dk.getNSEC3PARAM(target, &ns3pr, &narrow)) {
1,543✔
653
    NSEC3Zone=true;
813✔
654
    if(narrow) {
813!
655
      g_log<<Logger::Warning<<logPrefix<<"failed: not doing AXFR of an NSEC3 narrow zone"<<endl;
×
656
      outpacket->setRcode(RCode::Refused);
×
657
      sendPacket(outpacket,outsock);
×
658
      return 0;
×
659
    }
×
660
  }
813✔
661

662
  TSIGRecordContent trc;
1,543✔
663
  DNSName tsigkeyname;
1,543✔
664
  string tsigsecret;
1,543✔
665

666
  bool haveTSIGDetails = q->getTSIGDetails(&trc, &tsigkeyname);
1,543✔
667

668
  if(haveTSIGDetails && !tsigkeyname.empty()) {
1,543!
669
    string tsig64;
55✔
670
    DNSName algorithm=trc.d_algoName;
55✔
671
    if (algorithm == DNSName("hmac-md5.sig-alg.reg.int"))
55!
672
      algorithm = DNSName("hmac-md5");
55✔
673
    if (algorithm != DNSName("gss-tsig")) {
55!
674
      if(!db.getTSIGKey(tsigkeyname, algorithm, tsig64)) {
55!
675
        g_log<<Logger::Warning<<logPrefix<<"TSIG key not found"<<endl;
×
676
        return 0;
×
677
      }
×
678
      if (B64Decode(tsig64, tsigsecret) == -1) {
55!
679
        g_log<<Logger::Error<<logPrefix<<"unable to Base-64 decode TSIG key '"<<tsigkeyname<<"'"<<endl;
×
680
        return 0;
×
681
      }
×
682
    }
55✔
683
  }
55✔
684

685

686
  // SOA *must* go out first, our signing pipe might reorder
687
  DLOG(g_log<<logPrefix<<"sending out SOA"<<endl);
1,543✔
688
  DNSZoneRecord soa = makeEditedDNSZRFromSOAData(dk, sd);
1,543✔
689
  outpacket->addRecord(DNSZoneRecord(soa));
1,543✔
690
  if(securedZone && !presignedZone) {
1,543✔
691
    set<DNSName> authSet;
903✔
692
    authSet.insert(target);
903✔
693
    addRRSigs(dk, db, authSet, outpacket->getRRS());
903✔
694
  }
903✔
695

696
  if(haveTSIGDetails && !tsigkeyname.empty())
1,543!
697
    outpacket->setTSIGDetails(trc, tsigkeyname, tsigsecret, trc.d_mac); // first answer is 'normal'
55✔
698

699
  sendPacket(outpacket, outsock, false);
1,543✔
700

701
  trc.d_mac = outpacket->d_trc.d_mac;
1,543✔
702
  outpacket = getFreshAXFRPacket(q);
1,543✔
703

704

705
  DNSZoneRecord zrr;
1,543✔
706
  vector<DNSZoneRecord> zrrs;
1,543✔
707

708
  zrr.dr.d_name = target;
1,543✔
709
  zrr.dr.d_ttl = sd.minimum;
1,543✔
710

711
  if(securedZone && !presignedZone) { // this is where the DNSKEYs, CDNSKEYs and CDSs go in
1,543✔
712
    bool doCDNSKEY = true, doCDS = true;
903✔
713
    string publishCDNSKEY, publishCDS;
903✔
714
    dk.getPublishCDNSKEY(q->qdomain, publishCDNSKEY);
903✔
715
    dk.getPublishCDS(q->qdomain, publishCDS);
903✔
716

717
    set<uint32_t> entryPointIds;
903✔
718
    DNSSECKeeper::keyset_t entryPoints = dk.getEntryPoints(target);
903✔
719
    for (auto const& value : entryPoints) {
958✔
720
      entryPointIds.insert(value.second.id);
958✔
721
    }
958✔
722

723
    DNSSECKeeper::keyset_t keys = dk.getKeys(target);
903✔
724
    for(const DNSSECKeeper::keyset_t::value_type& value :  keys) {
1,003✔
725
      if (!value.second.published) {
1,003✔
726
        continue;
51✔
727
      }
51✔
728
      zrr.dr.d_type = QType::DNSKEY;
952✔
729
      zrr.dr.setContent(std::make_shared<DNSKEYRecordContent>(value.first.getDNSKEY()));
952✔
730
      DNSName keyname = NSEC3Zone ? DNSName(toBase32Hex(hashQNameWithSalt(ns3pr, zrr.dr.d_name))) : zrr.dr.d_name;
952✔
731
      zrrs.push_back(zrr);
952✔
732

733
      // generate CDS and CDNSKEY records
734
      if(doCDNSKEY && entryPointIds.count(value.second.id) > 0){
952!
735
        if(!publishCDNSKEY.empty()) {
907✔
736
          zrr.dr.d_type=QType::CDNSKEY;
201✔
737
          if (publishCDNSKEY == "0") {
201✔
738
            doCDNSKEY = false;
117✔
739
            zrr.dr.setContent(PacketHandler::s_deleteCDNSKEYContent);
117✔
740
            zrrs.push_back(zrr);
117✔
741
          } else {
117✔
742
            zrr.dr.setContent(std::make_shared<DNSKEYRecordContent>(value.first.getDNSKEY()));
84✔
743
            zrrs.push_back(zrr);
84✔
744
          }
84✔
745
        }
201✔
746

747
        if(doCDS && !publishCDS.empty()){
907✔
748
          zrr.dr.d_type=QType::CDS;
206✔
749
          vector<string> digestAlgos;
206✔
750
          stringtok(digestAlgos, publishCDS, ", ");
206✔
751
          if(std::find(digestAlgos.begin(), digestAlgos.end(), "0") != digestAlgos.end()) {
206✔
752
            doCDS = false;
118✔
753
            zrr.dr.setContent(PacketHandler::s_deleteCDSContent);
118✔
754
            zrrs.push_back(zrr);
118✔
755
          } else {
118✔
756
            for(auto const &digestAlgo : digestAlgos) {
88✔
757
              zrr.dr.setContent(std::make_shared<DSRecordContent>(makeDSFromDNSKey(target, value.first.getDNSKEY(), pdns::checked_stoi<uint8_t>(digestAlgo))));
88✔
758
              zrrs.push_back(zrr);
88✔
759
            }
88✔
760
          }
88✔
761
        }
206✔
762
      }
907✔
763
    }
952✔
764

765
  }
903✔
766

767
  if(NSEC3Zone) { // now stuff in the NSEC3PARAM
1,543✔
768
    uint8_t flags = ns3pr.d_flags;
813✔
769
    zrr.dr.d_type = QType::NSEC3PARAM;
813✔
770
    ns3pr.d_flags = 0;
813✔
771
    zrr.dr.setContent(std::make_shared<NSEC3PARAMRecordContent>(ns3pr));
813✔
772
    ns3pr.d_flags = flags;
813✔
773
    DNSName keyname = DNSName(toBase32Hex(hashQNameWithSalt(ns3pr, zrr.dr.d_name)));
813✔
774
    zrrs.push_back(zrr);
813✔
775
  }
813✔
776

777
  const bool rectify = !(presignedZone || ::arg().mustDo("disable-axfr-rectify"));
1,543✔
778
  set<DNSName> qnames, nsset, terms;
1,543✔
779

780
  // Catalog zone start
781
  if (di.kind == DomainInfo::Producer) {
1,543✔
782
    // Ignore all records except NS at apex
783
    sd.db->lookup(QType::NS, target, di.id);
36✔
784
    while (sd.db->get(zrr)) {
72✔
785
      zrrs.emplace_back(zrr);
36✔
786
    }
36✔
787
    if (zrrs.empty()) {
36!
788
      zrr.dr.d_name = target;
×
789
      zrr.dr.d_ttl = 0;
×
790
      zrr.dr.d_type = QType::NS;
×
791
      zrr.dr.setContent(std::make_shared<NSRecordContent>("invalid."));
×
792
      zrrs.emplace_back(zrr);
×
793
    }
×
794

795
    zrrs.emplace_back(CatalogInfo::getCatalogVersionRecord(target));
36✔
796

797
    vector<CatalogInfo> members;
36✔
798
    sd.db->getCatalogMembers(target, members, CatalogInfo::CatalogType::Producer);
36✔
799
    for (const auto& ci : members) {
600✔
800
      ci.toDNSZoneRecords(target, zrrs);
600✔
801
    }
600✔
802
    if (members.empty()) {
36!
803
      g_log << Logger::Warning << logPrefix << "catalog zone '" << target << "' has no members" << endl;
×
804
    }
×
805
    goto send;
36✔
806
  }
36✔
807
  // Catalog zone end
808

809
  // now start list zone
810
  if (!sd.db->list(target, sd.domain_id, isCatalogZone)) {
1,507!
811
    g_log<<Logger::Error<<logPrefix<<"backend signals error condition, aborting AXFR"<<endl;
×
812
    outpacket->setRcode(RCode::ServFail);
×
813
    sendPacket(outpacket,outsock);
×
814
    return 0;
×
815
  }
×
816

817
  while(sd.db->get(zrr)) {
500,507✔
818
    if (!presignedZone) {
499,000✔
819
      if (zrr.dr.d_type == QType::RRSIG) {
482,393!
820
        continue;
×
821
      }
×
822
      if (zrr.dr.d_type == QType::DNSKEY || zrr.dr.d_type == QType::CDNSKEY || zrr.dr.d_type == QType::CDS) {
482,393!
823
        if(!::arg().mustDo("direct-dnskey")) {
×
824
          continue;
×
825
        } else {
×
826
          zrr.dr.d_ttl = sd.minimum;
×
827
        }
×
828
      }
×
829
    }
482,393✔
830
    zrr.dr.d_name.makeUsLowerCase();
499,000✔
831
    if(zrr.dr.d_name.isPartOf(target)) {
499,000✔
832
      if (zrr.dr.d_type == QType::ALIAS && (::arg().mustDo("outgoing-axfr-expand-alias") || ::arg()["outgoing-axfr-expand-alias"] == "ignore-errors")) {
498,910!
833
        vector<DNSZoneRecord> ips;
19✔
834
        int ret1 = stubDoResolve(getRR<ALIASRecordContent>(zrr.dr)->getContent(), QType::A, ips);
19✔
835
        int ret2 = stubDoResolve(getRR<ALIASRecordContent>(zrr.dr)->getContent(), QType::AAAA, ips);
19✔
836
        if (ret1 != RCode::NoError || ret2 != RCode::NoError) {
19!
837
          if (::arg()["outgoing-axfr-expand-alias"] == "ignore-errors") {
×
838
            if (ret1 != RCode::NoError) {
×
839
              g_log << Logger::Error << logPrefix << zrr.dr.d_name.toLogString() << ": error resolving A record for ALIAS target " << zrr.dr.getContent()->getZoneRepresentation() << ", continuing AXFR" << endl;
×
840
            }
×
841
            if (ret2 != RCode::NoError) {
×
842
              g_log << Logger::Error << logPrefix << zrr.dr.d_name.toLogString() << ": error resolving AAAA record for ALIAS target " << zrr.dr.getContent()->getZoneRepresentation() << ", continuing AXFR" << endl;
×
843
            }
×
844
          }
×
845
          else {
×
846
            g_log << Logger::Warning << logPrefix << zrr.dr.d_name.toLogString() << ": error resolving for ALIAS " << zrr.dr.getContent()->getZoneRepresentation() << ", aborting AXFR" << endl;
×
847
            outpacket->setRcode(RCode::ServFail);
×
848
            sendPacket(outpacket, outsock);
×
849
            return 0;
×
850
          }
×
851
        }
×
852
        for (auto& ip: ips) {
38✔
853
          zrr.dr.d_type = ip.dr.d_type;
38✔
854
          zrr.dr.setContent(ip.dr.getContent());
38✔
855
          zrrs.push_back(zrr);
38✔
856
        }
38✔
857
        continue;
19✔
858
      }
19✔
859

860
      if (rectify) {
498,891✔
861
        if (zrr.dr.d_type) {
1,091✔
862
          qnames.insert(zrr.dr.d_name);
947✔
863
          if(zrr.dr.d_type == QType::NS && zrr.dr.d_name!=target)
947✔
864
            nsset.insert(zrr.dr.d_name);
191✔
865
        } else {
947✔
866
          // remove existing ents
867
          continue;
144✔
868
        }
144✔
869
      }
1,091✔
870
      zrrs.push_back(zrr);
498,747✔
871
    } else {
498,747✔
872
      if (zrr.dr.d_type)
90✔
873
        g_log<<Logger::Warning<<logPrefix<<"zone contains out-of-zone data '"<<zrr.dr.d_name<<"|"<<DNSRecordContent::NumberToType(zrr.dr.d_type)<<"', ignoring"<<endl;
30✔
874
    }
90✔
875
  }
499,000✔
876

877
  for (auto& loopRR : zrrs) {
500,957✔
878
    if ((loopRR.dr.d_type == QType::SVCB || loopRR.dr.d_type == QType::HTTPS)) {
500,957!
879
      // Process auto hints
880
      // TODO this is an almost copy of the code in the packethandler
881
      auto rrc = getRR<SVCBBaseRecordContent>(loopRR.dr);
115✔
882
      if (rrc == nullptr) {
115!
883
        continue;
×
884
      }
×
885
      auto newRRC = rrc->clone();
115✔
886
      if (!newRRC) {
115!
887
        continue;
×
888
      }
×
889
      DNSName svcTarget = newRRC->getTarget().isRoot() ? loopRR.dr.d_name : newRRC->getTarget();
115✔
890
      if (newRRC->autoHint(SvcParam::ipv4hint)) {
115!
891
        sd.db->lookup(QType::A, svcTarget, sd.domain_id);
×
892
        vector<ComboAddress> hints;
×
893
        DNSZoneRecord rr;
×
894
        while (sd.db->get(rr)) {
×
895
          auto arrc = getRR<ARecordContent>(rr.dr);
×
896
          hints.push_back(arrc->getCA());
×
897
        }
×
898
        if (hints.size() == 0) {
×
899
          newRRC->removeParam(SvcParam::ipv4hint);
×
900
        } else {
×
901
          newRRC->setHints(SvcParam::ipv4hint, hints);
×
902
        }
×
903
      }
×
904

905
      if (newRRC->autoHint(SvcParam::ipv6hint)) {
115!
906
        sd.db->lookup(QType::AAAA, svcTarget, sd.domain_id);
×
907
        vector<ComboAddress> hints;
×
908
        DNSZoneRecord rr;
×
909
        while (sd.db->get(rr)) {
×
910
          auto arrc = getRR<AAAARecordContent>(rr.dr);
×
911
          hints.push_back(arrc->getCA());
×
912
        }
×
913
        if (hints.size() == 0) {
×
914
          newRRC->removeParam(SvcParam::ipv6hint);
×
915
        } else {
×
916
          newRRC->setHints(SvcParam::ipv6hint, hints);
×
917
        }
×
918
      }
×
919

920
      loopRR.dr.setContent(std::move(newRRC));
115✔
921
    }
115✔
922
  }
500,957✔
923

924
  // Group records by name and type, signpipe stumbles over interrupted rrsets
925
  if(securedZone && !presignedZone) {
1,507✔
926
    sort(zrrs.begin(), zrrs.end(), [](const DNSZoneRecord& a, const DNSZoneRecord& b) {
6,096,907✔
927
      return std::tie(a.dr.d_name, a.dr.d_type) < std::tie(b.dr.d_name, b.dr.d_type);
6,096,907✔
928
    });
6,096,907✔
929
  }
903✔
930

931
  if(rectify) {
1,507✔
932
    // set auth
933
    for(DNSZoneRecord &loopZRR :  zrrs) {
996✔
934
      loopZRR.auth=true;
996✔
935
      if (loopZRR.dr.d_type != QType::NS || loopZRR.dr.d_name!=target) {
996✔
936
        DNSName shorter(loopZRR.dr.d_name);
877✔
937
        do {
1,618✔
938
          if (shorter==target) // apex is always auth
1,618✔
939
            break;
476✔
940
          if(nsset.count(shorter) && !(loopZRR.dr.d_name==shorter && loopZRR.dr.d_type == QType::DS)) {
1,142✔
941
            loopZRR.auth=false;
401✔
942
            break;
401✔
943
          }
401✔
944
        } while(shorter.chopOff());
1,142!
945
      }
877✔
946
    }
996✔
947

948
    if(NSEC3Zone) {
69✔
949
      // ents are only required for NSEC3 zones
950
      uint32_t maxent = ::arg().asNum("max-ent-entries");
13✔
951
      set<DNSName> nsec3set, nonterm;
13✔
952
      for (auto &loopZRR: zrrs) {
173✔
953
        bool skip=false;
173✔
954
        DNSName shorter = loopZRR.dr.d_name;
173✔
955
        if (shorter != target && shorter.chopOff() && shorter != target) {
173!
956
          do {
51✔
957
            if(nsset.count(shorter)) {
51✔
958
              skip=true;
11✔
959
              break;
11✔
960
            }
11✔
961
          } while(shorter.chopOff() && shorter != target);
51!
962
        }
31✔
963
        shorter = loopZRR.dr.d_name;
×
964
        if(!skip && (loopZRR.dr.d_type != QType::NS || !ns3pr.d_flags)) {
173!
965
          do {
280✔
966
            if(!nsec3set.count(shorter)) {
280✔
967
              nsec3set.insert(shorter);
101✔
968
            }
101✔
969
          } while(shorter != target && shorter.chopOff());
280!
970
        }
162✔
971
      }
173✔
972

973
      for(DNSZoneRecord &loopZRR :  zrrs) {
173✔
974
        DNSName shorter(loopZRR.dr.d_name);
173✔
975
        while(shorter != target && shorter.chopOff()) {
321!
976
          if(!qnames.count(shorter) && !nonterm.count(shorter) && nsec3set.count(shorter)) {
148✔
977
            if(!(maxent)) {
17!
978
              g_log<<Logger::Warning<<logPrefix<<"zone has too many empty non terminals, aborting AXFR"<<endl;
×
979
              outpacket->setRcode(RCode::ServFail);
×
980
              sendPacket(outpacket,outsock);
×
981
              return 0;
×
982
            }
×
983
            nonterm.insert(shorter);
17✔
984
            --maxent;
17✔
985
          }
17✔
986
        }
148✔
987
      }
173✔
988

989
      for(const auto& nt :  nonterm) {
17✔
990
        DNSZoneRecord tempRR;
17✔
991
        tempRR.dr.d_name=nt;
17✔
992
        tempRR.dr.d_type=QType::ENT;
17✔
993
        tempRR.auth=true;
17✔
994
        zrrs.push_back(tempRR);
17✔
995
      }
17✔
996
    }
13✔
997
  }
69✔
998

999
send:
1,543✔
1000

1001
  /* now write all other records */
1002

1003
  typedef map<DNSName, NSECXEntry, CanonDNSNameCompare> nsecxrepo_t;
1,543✔
1004
  nsecxrepo_t nsecxrepo;
1,543✔
1005

1006
  ChunkedSigningPipe csp(target, (securedZone && !presignedZone), ::arg().asNum("signing-threads", 1), ::arg().mustDo("workaround-11804") ? 1 : 100);
1,543!
1007

1008
  DNSName keyname;
1,543✔
1009
  unsigned int udiff;
1,543✔
1010
  DTime dt;
1,543✔
1011
  dt.set();
1,543✔
1012
  for(DNSZoneRecord &loopZRR :  zrrs) {
501,754✔
1013
    if(securedZone && (loopZRR.auth || loopZRR.dr.d_type == QType::NS)) {
501,754✔
1014
      if (NSEC3Zone || loopZRR.dr.d_type) {
373,290✔
1015
        if (presignedZone && NSEC3Zone && loopZRR.dr.d_type == QType::RRSIG && getRR<RRSIGRecordContent>(loopZRR.dr)->d_type == QType::NSEC3) {
372,485✔
1016
          keyname = loopZRR.dr.d_name.makeRelative(sd.qname);
2,846✔
1017
        } else {
369,639✔
1018
          keyname = NSEC3Zone ? DNSName(toBase32Hex(hashQNameWithSalt(ns3pr, loopZRR.dr.d_name))) : loopZRR.dr.d_name;
369,639✔
1019
        }
369,639✔
1020
        NSECXEntry& ne = nsecxrepo[keyname];
372,485✔
1021
        ne.d_ttl = sd.getNegativeTTL();
372,485✔
1022
        ne.d_auth = (ne.d_auth || loopZRR.auth || (NSEC3Zone && (!ns3pr.d_flags)));
372,485✔
1023
        if (loopZRR.dr.d_type && loopZRR.dr.d_type != QType::RRSIG) {
372,485✔
1024
          ne.d_set.set(loopZRR.dr.d_type);
362,261✔
1025
        }
362,261✔
1026
      }
372,485✔
1027
    }
373,290✔
1028

1029
    if (!loopZRR.dr.d_type)
501,754✔
1030
      continue; // skip empty non-terminals
3,823✔
1031

1032
    if(loopZRR.dr.d_type == QType::SOA)
497,931✔
1033
      continue; // skip SOA - would indicate end of AXFR
1,507✔
1034

1035
    if(csp.submit(loopZRR)) {
496,424✔
1036
      for(;;) {
17,486✔
1037
        outpacket->getRRS() = csp.getChunk();
17,486✔
1038
        if(!outpacket->getRRS().empty()) {
17,486✔
1039
          if(haveTSIGDetails && !tsigkeyname.empty())
9,517!
1040
            outpacket->setTSIGDetails(trc, tsigkeyname, tsigsecret, trc.d_mac, true);
×
1041
          sendPacket(outpacket, outsock, false);
9,517✔
1042
          trc.d_mac=outpacket->d_trc.d_mac;
9,517✔
1043
          outpacket=getFreshAXFRPacket(q);
9,517✔
1044
        }
9,517✔
1045
        else
7,969✔
1046
          break;
7,969✔
1047
      }
17,486✔
1048
    }
7,969✔
1049
  }
496,424✔
1050
  /*
1051
  udiff=dt.udiffNoReset();
1052
  cerr<<"Starting NSEC: "<<csp.d_signed/(udiff/1000000.0)<<" sigs/s, "<<csp.d_signed<<" / "<<udiff/1000000.0<<endl;
1053
  cerr<<"Outstanding: "<<csp.d_outstanding<<", "<<csp.d_queued - csp.d_signed << endl;
1054
  cerr<<"Ready for consumption: "<<csp.getReady()<<endl;
1055
  */
1056
  if(securedZone) {
1,543✔
1057
    if(NSEC3Zone) {
1,277✔
1058
      for(nsecxrepo_t::const_iterator iter = nsecxrepo.begin(); iter != nsecxrepo.end(); ++iter) {
249,990✔
1059
        if(iter->second.d_auth) {
249,177✔
1060
          NSEC3RecordContent n3rc;
248,780✔
1061
          n3rc.set(iter->second.d_set);
248,780✔
1062
          const auto numberOfTypesSet = n3rc.numberOfTypesSet();
248,780✔
1063
          if (numberOfTypesSet != 0 && (numberOfTypesSet != 1 || !n3rc.isSet(QType::NS))) {
248,780✔
1064
            n3rc.set(QType::RRSIG);
246,911✔
1065
          }
246,911✔
1066
          n3rc.d_salt = ns3pr.d_salt;
248,780✔
1067
          n3rc.d_flags = ns3pr.d_flags;
248,780✔
1068
          n3rc.d_iterations = ns3pr.d_iterations;
248,780✔
1069
          n3rc.d_algorithm = DNSSECKeeper::DIGEST_SHA1; // SHA1, fixed in PowerDNS for now
248,780✔
1070
          nsecxrepo_t::const_iterator inext = iter;
248,780✔
1071
          ++inext;
248,780✔
1072
          if(inext == nsecxrepo.end())
248,780✔
1073
            inext = nsecxrepo.begin();
813✔
1074
          while(!inext->second.d_auth && inext != iter)
249,177!
1075
          {
397✔
1076
            ++inext;
397✔
1077
            if(inext == nsecxrepo.end())
397!
1078
              inext = nsecxrepo.begin();
×
1079
          }
397✔
1080
          n3rc.d_nexthash = fromBase32Hex(inext->first.toStringNoDot());
248,780✔
1081
          zrr.dr.d_name = iter->first+sd.qname;
248,780✔
1082

1083
          zrr.dr.d_ttl = sd.getNegativeTTL();
248,780✔
1084
          zrr.dr.setContent(std::make_shared<NSEC3RecordContent>(std::move(n3rc)));
248,780✔
1085
          zrr.dr.d_type = QType::NSEC3;
248,780✔
1086
          zrr.dr.d_place = DNSResourceRecord::ANSWER;
248,780✔
1087
          zrr.auth=true;
248,780✔
1088
          if(csp.submit(zrr)) {
248,780✔
1089
            for(;;) {
10,527✔
1090
              outpacket->getRRS() = csp.getChunk();
10,527✔
1091
              if(!outpacket->getRRS().empty()) {
10,527✔
1092
                if(haveTSIGDetails && !tsigkeyname.empty())
5,886!
1093
                  outpacket->setTSIGDetails(trc, tsigkeyname, tsigsecret, trc.d_mac, true);
×
1094
                sendPacket(outpacket, outsock, false);
5,886✔
1095
                trc.d_mac=outpacket->d_trc.d_mac;
5,886✔
1096
                outpacket=getFreshAXFRPacket(q);
5,886✔
1097
              }
5,886✔
1098
              else
4,641✔
1099
                break;
4,641✔
1100
            }
10,527✔
1101
          }
4,641✔
1102
        }
248,780✔
1103
      }
249,177✔
1104
    }
813✔
1105
    else for(nsecxrepo_t::const_iterator iter = nsecxrepo.begin(); iter != nsecxrepo.end(); ++iter) {
104,793✔
1106
      NSECRecordContent nrc;
104,329✔
1107
      nrc.set(iter->second.d_set);
104,329✔
1108
      nrc.set(QType::RRSIG);
104,329✔
1109
      nrc.set(QType::NSEC);
104,329✔
1110

1111
      if(boost::next(iter) != nsecxrepo.end())
104,329✔
1112
        nrc.d_next = boost::next(iter)->first;
103,865✔
1113
      else
464✔
1114
        nrc.d_next=nsecxrepo.begin()->first;
464✔
1115
      zrr.dr.d_name = iter->first;
104,329✔
1116

1117
      zrr.dr.d_ttl = sd.getNegativeTTL();
104,329✔
1118
      zrr.dr.setContent(std::make_shared<NSECRecordContent>(std::move(nrc)));
104,329✔
1119
      zrr.dr.d_type = QType::NSEC;
104,329✔
1120
      zrr.dr.d_place = DNSResourceRecord::ANSWER;
104,329✔
1121
      zrr.auth=true;
104,329✔
1122
      if(csp.submit(zrr)) {
104,329✔
1123
        for(;;) {
4,532✔
1124
          outpacket->getRRS() = csp.getChunk();
4,532✔
1125
          if(!outpacket->getRRS().empty()) {
4,532✔
1126
            if(haveTSIGDetails && !tsigkeyname.empty())
2,779!
1127
              outpacket->setTSIGDetails(trc, tsigkeyname, tsigsecret, trc.d_mac, true);
×
1128
            sendPacket(outpacket, outsock, false);
2,779✔
1129
            trc.d_mac=outpacket->d_trc.d_mac;
2,779✔
1130
            outpacket=getFreshAXFRPacket(q);
2,779✔
1131
          }
2,779✔
1132
          else
1,753✔
1133
            break;
1,753✔
1134
        }
4,532✔
1135
      }
1,753✔
1136
    }
104,329✔
1137
  }
1,277✔
1138
  /*
1139
  udiff=dt.udiffNoReset();
1140
  cerr<<"Flushing pipe: "<<csp.d_signed/(udiff/1000000.0)<<" sigs/s, "<<csp.d_signed<<" / "<<udiff/1000000.0<<endl;
1141
  cerr<<"Outstanding: "<<csp.d_outstanding<<", "<<csp.d_queued - csp.d_signed << endl;
1142
  cerr<<"Ready for consumption: "<<csp.getReady()<<endl;
1143
  * */
1144
  for(;;) {
3,193✔
1145
    outpacket->getRRS() = csp.getChunk(true); // flush the pipe
3,193✔
1146
    if(!outpacket->getRRS().empty()) {
3,193✔
1147
      if(haveTSIGDetails && !tsigkeyname.empty())
1,688!
1148
        outpacket->setTSIGDetails(trc, tsigkeyname, tsigsecret, trc.d_mac, true); // first answer is 'normal'
55✔
1149
      try {
1,688✔
1150
        sendPacket(outpacket, outsock, false);
1,688✔
1151
      }
1,688✔
1152
      catch (PDNSException& pe) {
1,688✔
1153
        throw PDNSException("during axfr-out of "+target.toString()+", this happened: "+pe.reason);
×
1154
      }
×
1155
      trc.d_mac=outpacket->d_trc.d_mac;
1,650✔
1156
      outpacket=getFreshAXFRPacket(q);
1,650✔
1157
    }
1,650✔
1158
    else
1,505✔
1159
      break;
1,505✔
1160
  }
3,193✔
1161

1162
  udiff=dt.udiffNoReset();
1,505✔
1163
  if(securedZone)
1,505✔
1164
    g_log<<Logger::Debug<<logPrefix<<"done signing: "<<csp.d_signed/(udiff/1000000.0)<<" sigs/s, "<<endl;
1,239✔
1165

1166
  DLOG(g_log<<logPrefix<<"done writing out records"<<endl);
1,505✔
1167
  /* and terminate with yet again the SOA record */
1168
  outpacket=getFreshAXFRPacket(q);
1,505✔
1169
  outpacket->addRecord(std::move(soa));
1,505✔
1170
  if(haveTSIGDetails && !tsigkeyname.empty())
1,505!
1171
    outpacket->setTSIGDetails(trc, tsigkeyname, tsigsecret, trc.d_mac, true);
55✔
1172

1173
  sendPacket(outpacket, outsock);
1,505✔
1174

1175
  DLOG(g_log<<logPrefix<<"last packet - close"<<endl);
1,505✔
1176
  g_log<<Logger::Notice<<logPrefix<<"AXFR finished"<<endl;
1,505✔
1177

1178
  return 1;
1,505✔
1179
}
1,543✔
1180

1181
int TCPNameserver::doIXFR(std::unique_ptr<DNSPacket>& q, int outsock)
1182
{
96✔
1183
  string logPrefix="IXFR-out zone '"+q->qdomain.toLogString()+"', client '"+q->getRemoteStringWithPort()+"', ";
96✔
1184

1185
  std::unique_ptr<DNSPacket> outpacket=getFreshAXFRPacket(q);
96✔
1186
  if(q->d_dnssecOk)
96!
1187
    outpacket->d_dnssecOk=true; // RFC 5936, 2.2.5 'SHOULD'
×
1188

1189
  uint32_t serial = 0;
96✔
1190
  MOADNSParser mdp(false, q->getString());
96✔
1191
  for(const auto & answer : mdp.d_answers) {
288✔
1192
    const DNSRecord *dnsRecord = &answer;
288✔
1193
    if (dnsRecord->d_type == QType::SOA && dnsRecord->d_place == DNSResourceRecord::AUTHORITY) {
288!
1194
      vector<string>parts;
96✔
1195
      stringtok(parts, dnsRecord->getContent()->getZoneRepresentation());
96✔
1196
      if (parts.size() >= 3) {
96!
1197
        try {
96✔
1198
          pdns::checked_stoi_into(serial, parts[2]);
96✔
1199
        }
96✔
1200
        catch(const std::out_of_range& oor) {
96✔
1201
          g_log<<Logger::Warning<<logPrefix<<"invalid serial in IXFR query"<<endl;
×
1202
          outpacket->setRcode(RCode::FormErr);
×
1203
          sendPacket(outpacket,outsock);
×
1204
          return 0;
×
1205
        }
×
1206
      } else {
96✔
1207
        g_log<<Logger::Warning<<logPrefix<<"no serial in IXFR query"<<endl;
×
1208
        outpacket->setRcode(RCode::FormErr);
×
1209
        sendPacket(outpacket,outsock);
×
1210
        return 0;
×
1211
      }
×
1212
    } else if (dnsRecord->d_type != QType::TSIG && dnsRecord->d_type != QType::OPT) {
192!
1213
      g_log<<Logger::Warning<<logPrefix<<"additional records in IXFR query, type: "<<QType(dnsRecord->d_type).toString()<<endl;
×
1214
      outpacket->setRcode(RCode::FormErr);
×
1215
      sendPacket(outpacket,outsock);
×
1216
      return 0;
×
1217
    }
×
1218
  }
288✔
1219

1220
  g_log<<Logger::Warning<<logPrefix<<"transfer initiated with serial "<<serial<<endl;
96✔
1221

1222
  // determine if zone exists, XFR is allowed, and if IXFR can proceed using existing backend before spawning a new backend.
1223
  SOAData sd;
96✔
1224
  bool securedZone;
96✔
1225
  bool serialPermitsIXFR;
96✔
1226
  {
96✔
1227
    auto packetHandler = s_P.lock();
96✔
1228
    DLOG(g_log<<logPrefix<<"Looking for SOA"<<endl); // find domain_id via SOA and list complete domain. No SOA, no IXFR
96✔
1229
    if(!*packetHandler) {
96!
1230
      g_log<<Logger::Warning<<"TCP server is without backend connections in doIXFR, launching"<<endl;
×
1231
      *packetHandler = make_unique<PacketHandler>();
×
1232
    }
×
1233

1234
    // canDoAXFR does all the ACL checks, and has the if(disable-axfr) shortcut, call it first.
1235
    if(!canDoAXFR(q, false, *packetHandler) || !(*packetHandler)->getBackend()->getSOAUncached(q->qdomain, sd)) {
96!
1236
      g_log<<Logger::Warning<<logPrefix<<"failed: not authoritative"<<endl;
64✔
1237
      outpacket->setRcode(RCode::NotAuth);
64✔
1238
      sendPacket(outpacket,outsock);
64✔
1239
      return 0;
64✔
1240
    }
64✔
1241

1242
    DNSSECKeeper dk((*packetHandler)->getBackend());
32✔
1243
    DNSSECKeeper::clearCaches(q->qdomain);
32✔
1244
    bool narrow = false;
32✔
1245
    securedZone = dk.isSecuredZone(q->qdomain);
32✔
1246
    if(dk.getNSEC3PARAM(q->qdomain, nullptr, &narrow)) {
32✔
1247
      if(narrow) {
14!
1248
        g_log<<Logger::Warning<<logPrefix<<"not doing IXFR of an NSEC3 narrow zone"<<endl;
×
1249
        outpacket->setRcode(RCode::Refused);
×
1250
        sendPacket(outpacket,outsock);
×
1251
        return 0;
×
1252
      }
×
1253
    }
14✔
1254

1255
    serialPermitsIXFR = !rfc1982LessThan(serial, calculateEditSOA(sd.serial, dk, sd.qname));
32✔
1256
  }
32✔
1257

1258
  if (serialPermitsIXFR) {
32!
1259
    DNSName target = q->qdomain;
32✔
1260
    TSIGRecordContent trc;
32✔
1261
    DNSName tsigkeyname;
32✔
1262
    string tsigsecret;
32✔
1263

1264
    UeberBackend db;
32✔
1265
    DNSSECKeeper dk(&db);
32✔
1266

1267
    bool haveTSIGDetails = q->getTSIGDetails(&trc, &tsigkeyname);
32✔
1268

1269
    if(haveTSIGDetails && !tsigkeyname.empty()) {
32!
1270
      string tsig64;
32✔
1271
      DNSName algorithm=trc.d_algoName; // FIXME400: was toLowerCanonic, compare output
32✔
1272
      if (algorithm == DNSName("hmac-md5.sig-alg.reg.int"))
32!
1273
        algorithm = DNSName("hmac-md5");
32✔
1274
      if (!db.getTSIGKey(tsigkeyname, algorithm, tsig64)) {
32!
1275
        g_log << Logger::Error << "TSIG key '" << tsigkeyname << "' for domain '" << target << "' not found" << endl;
×
1276
        return 0;
×
1277
      }
×
1278
      if (B64Decode(tsig64, tsigsecret) == -1) {
32!
1279
        g_log<<Logger::Error<<logPrefix<<"unable to Base-64 decode TSIG key '"<<tsigkeyname<<"'"<<endl;
×
1280
        return 0;
×
1281
      }
×
1282
    }
32✔
1283

1284
    // SOA *must* go out first, our signing pipe might reorder
1285
    DLOG(g_log<<logPrefix<<"sending out SOA"<<endl);
32✔
1286
    DNSZoneRecord soa = makeEditedDNSZRFromSOAData(dk, sd);
32✔
1287
    outpacket->addRecord(std::move(soa));
32✔
1288
    if(securedZone && outpacket->d_dnssecOk) {
32!
1289
      set<DNSName> authSet;
×
1290
      authSet.insert(target);
×
1291
      addRRSigs(dk, db, authSet, outpacket->getRRS());
×
1292
    }
×
1293

1294
    if(haveTSIGDetails && !tsigkeyname.empty())
32!
1295
      outpacket->setTSIGDetails(trc, tsigkeyname, tsigsecret, trc.d_mac); // first answer is 'normal'
32✔
1296

1297
    sendPacket(outpacket, outsock);
32✔
1298

1299
    g_log<<Logger::Notice<<logPrefix<<"IXFR finished"<<endl;
32✔
1300

1301
    return 1;
32✔
1302
  }
32✔
1303

1304
  g_log<<Logger::Notice<<logPrefix<<"IXFR fallback to AXFR"<<endl;
×
1305
  return doAXFR(q->qdomain, q, outsock);
×
1306
}
32✔
1307

1308
TCPNameserver::~TCPNameserver() = default;
×
1309
TCPNameserver::TCPNameserver()
1310
{
159✔
1311
  d_maxTransactionsPerConn = ::arg().asNum("max-tcp-transactions-per-conn");
159✔
1312
  d_idleTimeout = ::arg().asNum("tcp-idle-timeout");
159✔
1313
  d_maxConnectionDuration = ::arg().asNum("max-tcp-connection-duration");
159✔
1314
  d_maxConnectionsPerClient = ::arg().asNum("max-tcp-connections-per-client");
159✔
1315

1316
//  sem_init(&d_connectionroom_sem,0,::arg().asNum("max-tcp-connections"));
1317
  d_connectionroom_sem = make_unique<Semaphore>( ::arg().asNum( "max-tcp-connections" ));
159✔
1318
  d_maxTCPConnections = ::arg().asNum( "max-tcp-connections" );
159✔
1319

1320
  vector<string>locals;
159✔
1321
  stringtok(locals,::arg()["local-address"]," ,");
159✔
1322
  if(locals.empty())
159!
1323
    throw PDNSException("No local addresses specified");
×
1324

1325
  d_ng.toMasks(::arg()["allow-axfr-ips"] );
159✔
1326

1327
  signal(SIGPIPE,SIG_IGN);
159✔
1328

1329
  for(auto const &laddr : locals) {
213✔
1330
    ComboAddress local(laddr, ::arg().asNum("local-port"));
213✔
1331

1332
    int s=socket(local.sin4.sin_family, SOCK_STREAM, 0);
213✔
1333
    if(s<0)
213!
1334
      throw PDNSException("Unable to acquire TCP socket: "+stringerror());
×
1335
    setCloseOnExec(s);
213✔
1336

1337
    int tmp=1;
213✔
1338
    if(setsockopt(s, SOL_SOCKET,SO_REUSEADDR, (char*)&tmp, sizeof tmp) < 0) {
213!
1339
      g_log<<Logger::Error<<"Setsockopt failed"<<endl;
×
1340
      _exit(1);
×
1341
    }
×
1342

1343
    if (::arg().asNum("tcp-fast-open") > 0) {
213!
1344
#ifdef TCP_FASTOPEN
×
1345
      int fastOpenQueueSize = ::arg().asNum("tcp-fast-open");
×
1346
      if (setsockopt(s, IPPROTO_TCP, TCP_FASTOPEN, &fastOpenQueueSize, sizeof fastOpenQueueSize) < 0) {
×
1347
        g_log<<Logger::Error<<"Failed to enable TCP Fast Open for listening socket "<<local.toStringWithPort()<<": "<<stringerror()<<endl;
×
1348
      }
×
1349
#else
1350
      g_log<<Logger::Warning<<"TCP Fast Open configured but not supported for listening socket"<<endl;
1351
#endif
1352
    }
×
1353

1354
    if(::arg().mustDo("non-local-bind"))
213!
1355
      Utility::setBindAny(local.sin4.sin_family, s);
×
1356

1357
    if(local.isIPv6() && setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &tmp, sizeof(tmp)) < 0) {
213!
1358
      g_log<<Logger::Error<<"Failed to set IPv6 socket to IPv6 only, continuing anyhow: "<<stringerror()<<endl;
×
1359
    }
×
1360

1361
    if(::bind(s, (sockaddr*)&local, local.getSocklen())<0) {
213!
1362
      int err = errno;
×
1363
      close(s);
×
1364
      if( err == EADDRNOTAVAIL && ! ::arg().mustDo("local-address-nonexist-fail") ) {
×
1365
        g_log<<Logger::Error<<"Address " << local.toString() << " does not exist on this server - skipping TCP bind" << endl;
×
1366
        continue;
×
1367
      } else {
×
1368
        g_log<<Logger::Error<<"Unable to bind to TCP socket " << local.toStringWithPort() << ": "<<stringerror(err)<<endl;
×
1369
        throw PDNSException("Unable to bind to TCP socket");
×
1370
      }
×
1371
    }
×
1372

1373
    listen(s, 128);
213✔
1374
    g_log<<Logger::Error<<"TCP server bound to "<<local.toStringWithPort()<<endl;
213✔
1375
    d_sockets.push_back(s);
213✔
1376
    struct pollfd pfd;
213✔
1377
    memset(&pfd, 0, sizeof(pfd));
213✔
1378
    pfd.fd = s;
213✔
1379
    pfd.events = POLLIN;
213✔
1380
    d_prfds.push_back(pfd);
213✔
1381
  }
213✔
1382
}
159✔
1383

1384

1385
//! Start of TCP operations thread, we launch a new thread for each incoming TCP question
1386
void TCPNameserver::thread()
1387
{
159✔
1388
  setThreadName("pdns/tcpnameser");
159✔
1389
  try {
159✔
1390
    for(;;) {
17,060✔
1391
      int fd;
17,060✔
1392
      ComboAddress remote;
17,060✔
1393
      Utility::socklen_t addrlen=remote.getSocklen();
17,060✔
1394

1395
      int ret=poll(&d_prfds[0], d_prfds.size(), -1); // blocks, forever if need be
17,060✔
1396
      if(ret <= 0)
17,060!
1397
        continue;
×
1398

1399
      int sock=-1;
17,060✔
1400
      for(const pollfd& pfd :  d_prfds) {
21,965✔
1401
        if(pfd.revents & POLLIN) {
21,932✔
1402
          sock = pfd.fd;
16,901✔
1403
          remote.sin4.sin_family = AF_INET6;
16,901✔
1404
          addrlen=remote.getSocklen();
16,901✔
1405

1406
          if((fd=accept(sock, (sockaddr*)&remote, &addrlen))<0) {
16,901!
1407
            int err = errno;
×
1408
            g_log<<Logger::Error<<"TCP question accept error: "<<stringerror(err)<<endl;
×
1409

1410
            if(err==EMFILE) {
×
1411
              g_log<<Logger::Error<<"TCP handler out of filedescriptors, exiting, won't recover from this"<<endl;
×
1412
              _exit(1);
×
1413
            }
×
1414
          }
×
1415
          else {
16,901✔
1416
            if (d_maxConnectionsPerClient) {
16,901!
1417
              auto clientsCount = s_clientsCount.lock();
×
1418
              if ((*clientsCount)[remote] >= d_maxConnectionsPerClient) {
×
1419
                g_log<<Logger::Notice<<"Limit of simultaneous TCP connections per client reached for "<< remote<<", dropping"<<endl;
×
1420
                close(fd);
×
1421
                continue;
×
1422
              }
×
1423
              (*clientsCount)[remote]++;
×
1424
            }
×
1425

1426
            d_connectionroom_sem->wait(); // blocks if no connections are available
16,901✔
1427

1428
            int room;
16,901✔
1429
            d_connectionroom_sem->getValue( &room);
16,901✔
1430
            if(room<1)
16,901!
1431
              g_log<<Logger::Warning<<"Limit of simultaneous TCP connections reached - raise max-tcp-connections"<<endl;
×
1432

1433
            try {
16,901✔
1434
              std::thread connThread(doConnection, fd);
16,901✔
1435
              connThread.detach();
16,901✔
1436
            }
16,901✔
1437
            catch (std::exception& e) {
16,901✔
1438
              g_log<<Logger::Error<<"Error creating thread: "<<e.what()<<endl;
×
1439
              d_connectionroom_sem->post();
×
1440
              close(fd);
×
1441
              decrementClientCount(remote);
×
1442
            }
×
1443
          }
16,901✔
1444
        }
16,901✔
1445
      }
21,932✔
1446
    }
17,060✔
1447
  }
159✔
1448
  catch(PDNSException &AE) {
159✔
1449
    g_log<<Logger::Error<<"TCP Nameserver thread dying because of fatal error: "<<AE.reason<<endl;
×
1450
  }
×
1451
  catch(...) {
159✔
1452
    g_log<<Logger::Error<<"TCPNameserver dying because of an unexpected fatal error"<<endl;
×
1453
  }
×
1454
  _exit(1); // take rest of server with us
×
1455
}
159✔
1456

1457

1458
unsigned int TCPNameserver::numTCPConnections()
1459
{
9✔
1460
  int room;
9✔
1461
  d_connectionroom_sem->getValue( &room);
9✔
1462
  return d_maxTCPConnections - room;
9✔
1463
}
9✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc