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

PowerDNS / pdns / 17235120617

26 Aug 2025 10:17AM UTC coverage: 65.959% (-0.02%) from 65.977%
17235120617

Pull #16016

github

web-flow
Merge d1e0ec6fc into 9eeac00a7
Pull Request #16016: auth: random doc nits

42117 of 92446 branches covered (45.56%)

Branch coverage included in aggregate %.

128034 of 165518 relevant lines covered (77.35%)

5925196.8 hits per line

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

67.07
/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
#include "pdns/auth-zonecache.hh"
23
#ifdef HAVE_CONFIG_H
24
#include "config.h"
25
#endif
26
#include <boost/algorithm/string.hpp>
27
#include <boost/scoped_array.hpp>
28
#include "auth-packetcache.hh"
29
#include "utility.hh"
30
#include "threadname.hh"
31
#include "dnssecinfra.hh"
32
#include "dnsseckeeper.hh"
33
#include <cstdio>
34
#include "base32.hh"
35
#include <cstring>
36
#include <cstdlib>
37
#include <sys/types.h>
38
#include <netinet/tcp.h>
39
#include <iostream>
40
#include <string>
41
#include "tcpreceiver.hh"
42
#include "sstuff.hh"
43

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

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

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

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

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

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

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

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

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

172
    ptr += ret;
41,388✔
173
    bytes -= ret;
41,388✔
174
  }
41,388✔
175
}
41,451✔
176

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

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

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

189

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

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

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

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

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

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

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

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

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

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

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

327
      uint16_t pktlen;
39,649✔
328
      if(!readnWithTimeout(fd, &pktlen, 2, d_idleTimeout, false, remainingTime))
39,649✔
329
        break;
19,626✔
330
      else
20,023✔
331
        pktlen=ntohs(pktlen);
20,023✔
332

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

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

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

350
      getQuestion(fd, mesg.get(), pktlen, remote, remainingTime);
20,023✔
351
      S.inc("tcp-queries");
20,023✔
352
      if (accountremote.sin4.sin_family == AF_INET6)
20,023✔
353
        S.inc("tcp6-queries");
2✔
354
      else
20,021✔
355
        S.inc("tcp4-queries");
20,021✔
356

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

368
      if (packet->hasEDNSCookie())
20,023!
369
        S.inc("tcp-cookie-queries");
×
370

371
      if(packet->qtype.getCode()==QType::AXFR) {
20,023✔
372
        packet->d_xfr=true;
1,691✔
373
        g_zoneCache.setZoneVariant(*packet);
1,691✔
374
        doAXFR(packet->qdomainzone, packet, fd);
1,691✔
375
        continue;
1,691✔
376
      }
1,691✔
377

378
      if(packet->qtype.getCode()==QType::IXFR) {
18,332✔
379
        packet->d_xfr=true;
108✔
380
        g_zoneCache.setZoneVariant(*packet);
108✔
381
        doIXFR(packet, fd);
108✔
382
        continue;
108✔
383
      }
108✔
384

385
      std::unique_ptr<DNSPacket> reply;
18,224✔
386
      auto cached = make_unique<DNSPacket>(false);
18,224✔
387
      if(logDNSQueries)  {
18,224!
388
        g_log << Logger::Notice<<"TCP Remote "<< packet->getRemoteString() <<" wants '" << packet->qdomain<<"|"<<packet->qtype.toString() <<
×
389
        "', do = " <<packet->d_dnssecOk <<", bufsize = "<< packet->getMaxReplyLen();
×
390
      }
×
391

392
      if (PC.enabled()) {
18,224✔
393
        if (packet->couldBeCached()) {
3,853!
394
          std::string view{};
3,853✔
395
          if (g_views) {
3,853!
396
            Netmask netmask(packet->d_remote);
×
397
            view = g_zoneCache.getViewFromNetwork(&netmask);
×
398
          }
×
399
          if (PC.get(*packet, *cached, view)) { // short circuit - does the PacketCache recognize this question?
3,853✔
400
            if(logDNSQueries) {
492!
401
              g_log<<": packetcache HIT"<<endl;
×
402
            }
×
403
            cached->setRemote(&packet->d_remote);
492✔
404
            cached->d_inner_remote = packet->d_inner_remote;
492✔
405
            cached->d.id=packet->d.id;
492✔
406
            cached->d.rd=packet->d.rd; // copy in recursion desired bit
492✔
407
            cached->commitD(); // commit d to the packet                        inlined
492✔
408

409
            sendPacket(cached, fd); // presigned, don't do it again
492✔
410
            continue;
492✔
411
          }
492✔
412
        }
3,853✔
413
        if(logDNSQueries)
3,361!
414
            g_log<<": packetcache MISS"<<endl;
×
415
      } else {
14,371✔
416
        if (logDNSQueries) {
14,371!
417
          g_log<<endl;
×
418
        }
×
419
      }
14,371✔
420
      {
17,732✔
421
        auto packetHandler = s_P.lock();
17,732✔
422
        if (!*packetHandler) {
17,732!
423
          g_log<<Logger::Warning<<"TCP server is without backend connections, launching"<<endl;
×
424
          *packetHandler = make_unique<PacketHandler>();
×
425
        }
×
426

427
        reply = (*packetHandler)->doQuestion(*packet); // we really need to ask the backend :-)
17,732✔
428
      }
17,732✔
429

430
      if(!reply)  // unable to write an answer?
17,732✔
431
        break;
126✔
432

433
      sendPacket(reply, fd);
17,606✔
434
#ifdef ENABLE_GSS_TSIG
17,606✔
435
      if (g_doGssTSIG) {
17,606!
436
        packet->cleanupGSS(reply->d.rcode);
×
437
      }
×
438
#endif
17,606✔
439
    }
17,606✔
440
  }
19,919✔
441
  catch(PDNSException &ae) {
19,919✔
442
    s_P.lock()->reset(); // on next call, backend will be recycled
×
443
    g_log << Logger::Error << "TCP Connection Thread for client " << remote << " failed, cycling backend: " << ae.reason << endl;
×
444
  }
×
445
  catch(NetworkError &e) {
19,919✔
446
    g_log << Logger::Info << "TCP Connection Thread for client " << remote << " died because of network error: " << e.what() << endl;
167✔
447
  }
167✔
448

449
  catch(std::exception &e) {
19,919✔
450
    s_P.lock()->reset(); // on next call, backend will be recycled
×
451
    g_log << Logger::Error << "TCP Connection Thread for client " << remote << " died because of STL error, cycling backend: " << e.what() << endl;
×
452
  }
×
453
  catch( ... )
19,919✔
454
  {
19,919✔
455
    s_P.lock()->reset(); // on next call, backend will be recycled
×
456
    g_log << Logger::Error << "TCP Connection Thread for client " << remote << " caught unknown exception, cycling backend." << endl;
×
457
  }
×
458
  d_connectionroom_sem->post();
19,919✔
459

460
  try {
19,919✔
461
    closesocket(fd);
19,919✔
462
  }
19,919✔
463
  catch(const PDNSException& e) {
19,919✔
464
    g_log << Logger::Error << "Error closing TCP socket for client " << remote << ": " << e.reason << endl;
×
465
  }
×
466
  decrementClientCount(remote);
19,919✔
467
}
19,919✔
468

469

470
bool TCPNameserver::canDoAXFR(std::unique_ptr<DNSPacket>& q, bool isAXFR, std::unique_ptr<PacketHandler>& packetHandler)
471
{
1,799✔
472
  if(::arg().mustDo("disable-axfr"))
1,799!
473
    return false;
×
474

475
  string logPrefix=string(isAXFR ? "A" : "I")+"XFR-out zone '"+q->qdomainzone.toLogString()+"', client '"+q->getInnerRemote().toStringWithPort()+"', ";
1,799✔
476

477
  if(q->d_havetsig) { // if you have one, it must be good
1,799✔
478
    TSIGRecordContent tsigContent;
239✔
479
    DNSName tsigkeyname;
239✔
480
    string secret;
239✔
481
    if (!packetHandler->checkForCorrectTSIG(*q, &tsigkeyname, &secret, &tsigContent)) {
239✔
482
      return false;
144✔
483
    } else {
144✔
484
      getTSIGHashEnum(tsigContent.d_algoName, q->d_tsig_algo);
95✔
485
#ifdef ENABLE_GSS_TSIG
95✔
486
      if (g_doGssTSIG && q->d_tsig_algo == TSIG_GSS) {
95!
487
        GssContext gssctx(tsigkeyname);
×
488
        if (!gssctx.getPeerPrincipal(q->d_peer_principal)) {
×
489
          g_log<<Logger::Warning<<"Failed to extract peer principal from GSS context with keyname '"<<tsigkeyname<<"'"<<endl;
×
490
        }
×
491
      }
×
492
#endif
95✔
493
    }
95✔
494

495
    DNSSECKeeper dk(packetHandler->getBackend());
95✔
496
#ifdef ENABLE_GSS_TSIG
95✔
497
    if (g_doGssTSIG && q->d_tsig_algo == TSIG_GSS) {
95!
498
      vector<string> princs;
×
499
      packetHandler->getBackend()->getDomainMetadata(q->qdomainzone, "GSS-ALLOW-AXFR-PRINCIPAL", princs);
×
500
      for(const std::string& princ :  princs) {
×
501
        if (q->d_peer_principal == princ) {
×
502
          g_log<<Logger::Warning<<"AXFR of domain '"<<q->qdomainzone<<"' allowed: TSIG signed request with authorized principal '"<<q->d_peer_principal<<"' and algorithm 'gss-tsig'"<<endl;
×
503
          return true;
×
504
        }
×
505
      }
×
506
      g_log<<Logger::Warning<<"AXFR of domain '"<<q->qdomainzone<<"' denied: TSIG signed request with principal '"<<q->d_peer_principal<<"' and algorithm 'gss-tsig' is not permitted"<<endl;
×
507
      return false;
×
508
    }
×
509
#endif
95✔
510
    if(!dk.TSIGGrantsAccess(q->qdomainzone, tsigkeyname)) {
95!
511
      g_log<<Logger::Warning<<logPrefix<<"denied: key with name '"<<tsigkeyname<<"' and algorithm '"<<getTSIGAlgoName(q->d_tsig_algo)<<"' does not grant access"<<endl;
×
512
      return false;
×
513
    }
×
514
    else {
95✔
515
      g_log<<Logger::Notice<<logPrefix<<"allowed: TSIG signed request with authorized key '"<<tsigkeyname<<"' and algorithm '"<<getTSIGAlgoName(q->d_tsig_algo)<<"'"<<endl;
95✔
516
      return true;
95✔
517
    }
95✔
518
  }
95✔
519

520
  // cerr<<"checking allow-axfr-ips"<<endl;
521
  if(!(::arg()["allow-axfr-ips"].empty()) && d_ng.match( q->getInnerRemote() )) {
1,560!
522
    g_log<<Logger::Notice<<logPrefix<<"allowed: client IP is in allow-axfr-ips"<<endl;
1,559✔
523
    return true;
1,559✔
524
  }
1,559✔
525

526
  FindNS fns;
1✔
527

528
  // cerr<<"doing per-zone-axfr-acls"<<endl;
529
  SOAData sd;
1✔
530
  if(packetHandler->getBackend()->getSOAUncached(q->qdomainzone,sd)) {
1!
531
    // cerr<<"got backend and SOA"<<endl;
532
    vector<string> acl;
1✔
533
    packetHandler->getBackend()->getDomainMetadata(q->qdomainzone, "ALLOW-AXFR-FROM", acl);
1✔
534
    for (const auto & i : acl) {
1!
535
      // cerr<<"matching against "<<*i<<endl;
536
      if(pdns_iequals(i, "AUTO-NS")) {
1!
537
        // cerr<<"AUTO-NS magic please!"<<endl;
538

539
        DNSResourceRecord rr;
×
540
        set<DNSName> nsset;
×
541

542
        sd.db->lookup(QType(QType::NS), q->qdomain, sd.domain_id);
×
543
        while (sd.db->get(rr)) {
×
544
          nsset.insert(DNSName(rr.content));
×
545
        }
×
546
        for(const auto & j: nsset) {
×
547
          vector<string> nsips=fns.lookup(j, packetHandler->getBackend());
×
548
          for(const auto & nsip : nsips) {
×
549
            // cerr<<"got "<<*k<<" from AUTO-NS"<<endl;
550
            if(nsip == q->getInnerRemote().toString())
×
551
            {
×
552
              // cerr<<"got AUTO-NS hit"<<endl;
553
              g_log<<Logger::Notice<<logPrefix<<"allowed: client IP is in NSset"<<endl;
×
554
              return true;
×
555
            }
×
556
          }
×
557
        }
×
558
      }
×
559
      else
1✔
560
      {
1✔
561
        Netmask nm = Netmask(i);
1✔
562
        if(nm.match( q->getInnerRemote() ))
1!
563
        {
1✔
564
          g_log<<Logger::Notice<<logPrefix<<"allowed: client IP is in per-zone ACL"<<endl;
1✔
565
          // cerr<<"hit!"<<endl;
566
          return true;
1✔
567
        }
1✔
568
      }
1✔
569
    }
1✔
570
  }
1✔
571

572
  extern CommunicatorClass Communicator;
×
573

574
  if(Communicator.justNotified(q->qdomainzone, q->getInnerRemote().toString())) { // we just notified this ip
×
575
    g_log<<Logger::Notice<<logPrefix<<"allowed: client IP is from recently notified secondary"<<endl;
×
576
    return true;
×
577
  }
×
578

579
  g_log<<Logger::Warning<<logPrefix<<"denied: client IP has no permission"<<endl;
×
580
  return false;
×
581
}
×
582

583
namespace {
584
  struct NSECXEntry
585
  {
586
    NSECBitmap d_set;
587
    unsigned int d_ttl;
588
    bool d_auth;
589
  };
590

591
  static std::unique_ptr<DNSPacket> getFreshAXFRPacket(std::unique_ptr<DNSPacket>& q)
592
  {
25,032✔
593
    std::unique_ptr<DNSPacket> ret = std::unique_ptr<DNSPacket>(q->replyPacket());
25,032✔
594
    ret->setCompress(false);
25,032✔
595
    ret->d_dnssecOk=false; // RFC 5936, 2.2.5
25,032✔
596
    ret->d_tcp = true;
25,032✔
597
    return ret;
25,032✔
598
  }
25,032✔
599
}
600

601

602
/** do the actual zone transfer. Return 0 in case of error, 1 in case of success */
603
// NOLINTNEXTLINE(readability-identifier-length)
604
int TCPNameserver::doAXFR(const ZoneName &targetZone, std::unique_ptr<DNSPacket>& q, int outsock)  // NOLINT(readability-function-cognitive-complexity)
605
{
1,691✔
606
  const DNSName& target = targetZone.operator const DNSName&();
1,691✔
607
  string logPrefix="AXFR-out zone '"+targetZone.toLogString()+"', client '"+q->getRemoteStringWithPort()+"', ";
1,691✔
608

609
  std::unique_ptr<DNSPacket> outpacket= getFreshAXFRPacket(q);
1,691✔
610
  if(q->d_dnssecOk) {
1,691✔
611
    outpacket->d_dnssecOk=true; // RFC 5936, 2.2.5 'SHOULD'
167✔
612
  }
167✔
613

614
  g_log<<Logger::Warning<<logPrefix<<"transfer initiated"<<endl;
1,691✔
615

616
  // determine if zone exists and AXFR is allowed using existing backend before spawning a new backend.
617
  SOAData sd;
1,691✔
618
  {
1,691✔
619
    auto packetHandler = s_P.lock();
1,691✔
620
    DLOG(g_log<<logPrefix<<"looking for SOA"<<endl);    // find domain_id via SOA and list complete domain. No SOA, no AXFR
1,691✔
621
    if(!*packetHandler) {
1,691!
622
      g_log<<Logger::Warning<<"TCP server is without backend connections in doAXFR, launching"<<endl;
×
623
      *packetHandler = make_unique<PacketHandler>();
×
624
    }
×
625

626
    // canDoAXFR does all the ACL checks, and has the if(disable-axfr) shortcut, call it first.
627
    if (!canDoAXFR(q, true, *packetHandler)) {
1,691✔
628
      g_log<<Logger::Warning<<logPrefix<<"failed: client may not request AXFR"<<endl;
72✔
629
      outpacket->setRcode(RCode::NotAuth);
72✔
630
      sendPacket(outpacket,outsock);
72✔
631
      return 0;
72✔
632
    }
72✔
633

634
    if (!(*packetHandler)->getBackend()->getSOAUncached(targetZone, sd)) {
1,619!
635
      g_log<<Logger::Warning<<logPrefix<<"failed: not authoritative"<<endl;
×
636
      outpacket->setRcode(RCode::NotAuth);
×
637
      sendPacket(outpacket,outsock);
×
638
      return 0;
×
639
    }
×
640
  }
1,619✔
641

642
  UeberBackend db;
1,619✔
643
  if(!db.getSOAUncached(targetZone, sd)) {
1,619!
644
    g_log<<Logger::Warning<<logPrefix<<"failed: not authoritative in second instance"<<endl;
×
645
    outpacket->setRcode(RCode::NotAuth);
×
646
    sendPacket(outpacket,outsock);
×
647
    return 0;
×
648
  }
×
649

650
  bool securedZone = false;
1,619✔
651
  bool presignedZone = false;
1,619✔
652
  bool NSEC3Zone = false;
1,619✔
653
  bool narrow = false;
1,619✔
654

655
  DomainInfo di;
1,619✔
656
  bool isCatalogZone = sd.db->getDomainInfo(targetZone, di, false) && di.isCatalogType();
1,619!
657

658
  NSEC3PARAMRecordContent ns3pr;
1,619✔
659

660
  DNSSECKeeper dk(&db);
1,619✔
661
  DNSSECKeeper::clearCaches(targetZone);
1,619✔
662
  if (!isCatalogZone) {
1,619✔
663
    securedZone = dk.isSecuredZone(targetZone);
1,583✔
664
    presignedZone = dk.isPresigned(targetZone);
1,583✔
665
  }
1,583✔
666

667
  if(securedZone && dk.getNSEC3PARAM(targetZone, &ns3pr, &narrow)) {
1,619✔
668
    NSEC3Zone=true;
859✔
669
    if(narrow) {
859!
670
      g_log<<Logger::Warning<<logPrefix<<"failed: not doing AXFR of an NSEC3 narrow zone"<<endl;
×
671
      outpacket->setRcode(RCode::Refused);
×
672
      sendPacket(outpacket,outsock);
×
673
      return 0;
×
674
    }
×
675
  }
859✔
676

677
  TSIGRecordContent trc;
1,619✔
678
  DNSName tsigkeyname;
1,619✔
679
  string tsigsecret;
1,619✔
680

681
  bool haveTSIGDetails = q->getTSIGDetails(&trc, &tsigkeyname);
1,619✔
682

683
  if(haveTSIGDetails && !tsigkeyname.empty()) {
1,619!
684
    string tsig64;
59✔
685
    DNSName algorithm=trc.d_algoName;
59✔
686
    if (algorithm == g_hmacmd5dnsname_long) {
59!
687
      algorithm = g_hmacmd5dnsname;
59✔
688
    }
59✔
689
    if (algorithm != g_gsstsigdnsname) {
59!
690
      if(!db.getTSIGKey(tsigkeyname, algorithm, tsig64)) {
59!
691
        g_log<<Logger::Warning<<logPrefix<<"TSIG key not found"<<endl;
×
692
        return 0;
×
693
      }
×
694
      if (B64Decode(tsig64, tsigsecret) == -1) {
59!
695
        g_log<<Logger::Error<<logPrefix<<"unable to Base-64 decode TSIG key '"<<tsigkeyname<<"'"<<endl;
×
696
        return 0;
×
697
      }
×
698
    }
59✔
699
  }
59✔
700

701

702
  // SOA *must* go out first, our signing pipe might reorder
703
  DLOG(g_log<<logPrefix<<"sending out SOA"<<endl);
1,619✔
704
  DNSZoneRecord soa = makeEditedDNSZRFromSOAData(dk, sd);
1,619✔
705
  outpacket->addRecord(DNSZoneRecord(soa));
1,619✔
706
  if(securedZone && !presignedZone) {
1,619✔
707
    set<ZoneName> authSet;
971✔
708
    authSet.insert(targetZone);
971✔
709
    addRRSigs(dk, db, authSet, outpacket->getRRS());
971✔
710
  }
971✔
711

712
  if(haveTSIGDetails && !tsigkeyname.empty())
1,619!
713
    outpacket->setTSIGDetails(trc, tsigkeyname, tsigsecret, trc.d_mac); // first answer is 'normal'
59✔
714

715
  sendPacket(outpacket, outsock, false);
1,619✔
716

717
  trc.d_mac = outpacket->d_trc.d_mac;
1,619✔
718
  outpacket = getFreshAXFRPacket(q);
1,619✔
719

720

721
  DNSZoneRecord zrr;
1,619✔
722
  vector<DNSZoneRecord> zrrs;
1,619✔
723

724
  zrr.dr.d_name = target;
1,619✔
725
  zrr.dr.d_ttl = sd.minimum;
1,619✔
726

727
  if(securedZone && !presignedZone) { // this is where the DNSKEYs, CDNSKEYs and CDSs go in
1,619✔
728
    bool doCDNSKEY = true, doCDS = true;
972✔
729
    string publishCDNSKEY, publishCDS;
972✔
730
    dk.getPublishCDNSKEY(q->qdomainzone, publishCDNSKEY);
972✔
731
    dk.getPublishCDS(q->qdomainzone, publishCDS);
972✔
732

733
    set<uint32_t> entryPointIds;
972✔
734
    DNSSECKeeper::keyset_t entryPoints = dk.getEntryPoints(targetZone);
972✔
735
    for (auto const& value : entryPoints) {
1,027✔
736
      entryPointIds.insert(value.second.id);
1,027✔
737
    }
1,027✔
738

739
    DNSSECKeeper::keyset_t keys = dk.getKeys(targetZone);
972✔
740
    for(const DNSSECKeeper::keyset_t::value_type& value :  keys) {
1,075✔
741
      if (!value.second.published) {
1,075✔
742
        continue;
51✔
743
      }
51✔
744
      zrr.dr.d_type = QType::DNSKEY;
1,024✔
745
      zrr.dr.setContent(std::make_shared<DNSKEYRecordContent>(value.first.getDNSKEY()));
1,024✔
746
      DNSName keyname = NSEC3Zone ? DNSName(toBase32Hex(hashQNameWithSalt(ns3pr, zrr.dr.d_name))) : zrr.dr.d_name;
1,024✔
747
      zrrs.push_back(zrr);
1,024✔
748

749
      // generate CDS and CDNSKEY records
750
      if(doCDNSKEY && entryPointIds.count(value.second.id) > 0){
1,024✔
751
        if(!publishCDNSKEY.empty()) {
976✔
752
          zrr.dr.d_type=QType::CDNSKEY;
219✔
753
          if (publishCDNSKEY == "0") {
219✔
754
            doCDNSKEY = false;
129✔
755
            zrr.dr.setContent(PacketHandler::s_deleteCDNSKEYContent);
129✔
756
            zrrs.push_back(zrr);
129✔
757
          } else {
129✔
758
            zrr.dr.setContent(std::make_shared<DNSKEYRecordContent>(value.first.getDNSKEY()));
90✔
759
            zrrs.push_back(zrr);
90✔
760
          }
90✔
761
        }
219✔
762

763
        if(doCDS && !publishCDS.empty()){
976✔
764
          zrr.dr.d_type=QType::CDS;
224✔
765
          vector<string> digestAlgos;
224✔
766
          stringtok(digestAlgos, publishCDS, ", ");
224✔
767
          if(std::find(digestAlgos.begin(), digestAlgos.end(), "0") != digestAlgos.end()) {
224✔
768
            doCDS = false;
130✔
769
            zrr.dr.setContent(PacketHandler::s_deleteCDSContent);
130✔
770
            zrrs.push_back(zrr);
130✔
771
          } else {
130✔
772
            for(auto const &digestAlgo : digestAlgos) {
94✔
773
              zrr.dr.setContent(std::make_shared<DSRecordContent>(makeDSFromDNSKey(target, value.first.getDNSKEY(), pdns::checked_stoi<uint8_t>(digestAlgo))));
94✔
774
              zrrs.push_back(zrr);
94✔
775
            }
94✔
776
          }
94✔
777
        }
224✔
778
      }
976✔
779
    }
1,024✔
780

781
  }
972✔
782

783
  if(NSEC3Zone) { // now stuff in the NSEC3PARAM
1,619✔
784
    uint8_t flags = ns3pr.d_flags;
859✔
785
    zrr.dr.d_type = QType::NSEC3PARAM;
859✔
786
    ns3pr.d_flags = 0;
859✔
787
    zrr.dr.setContent(std::make_shared<NSEC3PARAMRecordContent>(ns3pr));
859✔
788
    ns3pr.d_flags = flags;
859✔
789
    DNSName keyname = DNSName(toBase32Hex(hashQNameWithSalt(ns3pr, zrr.dr.d_name)));
859✔
790
    zrrs.push_back(zrr);
859✔
791
  }
859✔
792

793
  const bool rectify = !(presignedZone || ::arg().mustDo("disable-axfr-rectify"));
1,619✔
794
  set<DNSName> qnames, nsset, terms;
1,619✔
795

796
  // Catalog zone start
797
  if (di.kind == DomainInfo::Producer) {
1,619✔
798
    // Ignore all records except NS at apex
799
    sd.db->lookup(QType::NS, target, di.id);
36✔
800
    while (sd.db->get(zrr)) {
72✔
801
      zrrs.emplace_back(zrr);
36✔
802
    }
36✔
803
    if (zrrs.empty()) {
36!
804
      zrr.dr.d_name = target;
×
805
      zrr.dr.d_ttl = 0;
×
806
      zrr.dr.d_type = QType::NS;
×
807
      zrr.dr.setContent(std::make_shared<NSRecordContent>("invalid."));
×
808
      zrrs.emplace_back(zrr);
×
809
    }
×
810

811
    zrrs.emplace_back(CatalogInfo::getCatalogVersionRecord(targetZone));
36✔
812

813
    vector<CatalogInfo> members;
36✔
814
    if (!sd.db->getCatalogMembers(targetZone, members, CatalogInfo::CatalogType::Producer)) {
36!
815
      g_log << Logger::Error << logPrefix << "getting catalog members failed, aborting AXFR" << endl;
×
816
      outpacket->setRcode(RCode::ServFail);
×
817
      sendPacket(outpacket, outsock);
×
818
      return 0;
×
819
    }
×
820
    for (const auto& ci : members) {
600✔
821
      ci.toDNSZoneRecords(targetZone, zrrs);
600✔
822
    }
600✔
823
    if (members.empty()) {
36!
824
      g_log << Logger::Warning << logPrefix << "catalog zone '" << targetZone << "' has no members" << endl;
×
825
    }
×
826
    goto send;
36✔
827
  }
36✔
828
  // Catalog zone end
829

830
  // now start list zone
831
  if (!sd.db->list(targetZone, sd.domain_id, isCatalogZone)) {
1,583!
832
    g_log<<Logger::Error<<logPrefix<<"backend signals error condition, aborting AXFR"<<endl;
×
833
    outpacket->setRcode(RCode::ServFail);
×
834
    sendPacket(outpacket,outsock);
×
835
    return 0;
×
836
  }
×
837

838
  while(sd.db->get(zrr)) {
503,494✔
839
    if (!presignedZone) {
501,911✔
840
      if (zrr.dr.d_type == QType::RRSIG) {
484,565!
841
        continue;
×
842
      }
×
843
      if (zrr.dr.d_type == QType::DNSKEY || zrr.dr.d_type == QType::CDNSKEY || zrr.dr.d_type == QType::CDS) {
484,565!
844
        if(!::arg().mustDo("direct-dnskey")) {
×
845
          continue;
×
846
        } else {
×
847
          zrr.dr.d_ttl = sd.minimum;
×
848
        }
×
849
      }
×
850
    }
484,565✔
851
    zrr.dr.d_name.makeUsLowerCase();
501,911✔
852
    if(zrr.dr.d_name.isPartOf(target)) {
501,911✔
853
      if (zrr.dr.d_type == QType::ALIAS && (::arg().mustDo("outgoing-axfr-expand-alias") || ::arg()["outgoing-axfr-expand-alias"] == "ignore-errors")) {
501,821!
854
        vector<DNSZoneRecord> ips;
19✔
855
        int ret1 = stubDoResolve(getRR<ALIASRecordContent>(zrr.dr)->getContent(), QType::A, ips);
19✔
856
        int ret2 = stubDoResolve(getRR<ALIASRecordContent>(zrr.dr)->getContent(), QType::AAAA, ips);
19✔
857
        if (ret1 != RCode::NoError || ret2 != RCode::NoError) {
19!
858
          if (::arg()["outgoing-axfr-expand-alias"] == "ignore-errors") {
×
859
            if (ret1 != RCode::NoError) {
×
860
              g_log << Logger::Error << logPrefix << zrr.dr.d_name.toLogString() << ": error resolving A record for ALIAS target " << zrr.dr.getContent()->getZoneRepresentation() << ", continuing AXFR" << endl;
×
861
            }
×
862
            if (ret2 != RCode::NoError) {
×
863
              g_log << Logger::Error << logPrefix << zrr.dr.d_name.toLogString() << ": error resolving AAAA record for ALIAS target " << zrr.dr.getContent()->getZoneRepresentation() << ", continuing AXFR" << endl;
×
864
            }
×
865
          }
×
866
          else {
×
867
            g_log << Logger::Warning << logPrefix << zrr.dr.d_name.toLogString() << ": error resolving for ALIAS " << zrr.dr.getContent()->getZoneRepresentation() << ", aborting AXFR" << endl;
×
868
            outpacket->setRcode(RCode::ServFail);
×
869
            sendPacket(outpacket, outsock);
×
870
            return 0;
×
871
          }
×
872
        }
×
873
        for (auto& ip: ips) {
38✔
874
          zrr.dr.d_type = ip.dr.d_type;
38✔
875
          zrr.dr.setContent(ip.dr.getContent());
38✔
876
          zrrs.push_back(zrr);
38✔
877
        }
38✔
878
        continue;
19✔
879
      }
19✔
880

881
      if (rectify) {
501,802✔
882
        if (zrr.dr.d_type) {
1,096✔
883
          qnames.insert(zrr.dr.d_name);
952✔
884
          if(zrr.dr.d_type == QType::NS && zrr.dr.d_name!=target)
952✔
885
            nsset.insert(zrr.dr.d_name);
191✔
886
        } else {
952✔
887
          // remove existing ents
888
          continue;
144✔
889
        }
144✔
890
      }
1,096✔
891
      zrrs.push_back(zrr);
501,658✔
892
    } else {
501,658✔
893
      if (zrr.dr.d_type)
90✔
894
        g_log<<Logger::Warning<<logPrefix<<"zone contains out-of-zone data '"<<zrr.dr.d_name<<"|"<<DNSRecordContent::NumberToType(zrr.dr.d_type)<<"', ignoring"<<endl;
30✔
895
    }
90✔
896
  }
501,911✔
897

898
  for (auto& loopRR : zrrs) {
504,022✔
899
    if ((loopRR.dr.d_type == QType::SVCB || loopRR.dr.d_type == QType::HTTPS)) {
504,022!
900
      // Process auto hints
901
      // TODO this is an almost copy of the code in the packethandler
902
      auto rrc = getRR<SVCBBaseRecordContent>(loopRR.dr);
138✔
903
      if (rrc == nullptr) {
138!
904
        continue;
×
905
      }
×
906
      auto newRRC = rrc->clone();
138✔
907
      if (!newRRC) {
138!
908
        continue;
×
909
      }
×
910
      DNSName svcTarget = newRRC->getTarget().isRoot() ? loopRR.dr.d_name : newRRC->getTarget();
138✔
911
      if (newRRC->autoHint(SvcParam::ipv4hint)) {
138!
912
        sd.db->lookup(QType::A, svcTarget, sd.domain_id);
×
913
        vector<ComboAddress> hints;
×
914
        DNSZoneRecord rr;
×
915
        while (sd.db->get(rr)) {
×
916
          auto arrc = getRR<ARecordContent>(rr.dr);
×
917
          hints.push_back(arrc->getCA());
×
918
        }
×
919
        if (hints.size() == 0) {
×
920
          newRRC->removeParam(SvcParam::ipv4hint);
×
921
        } else {
×
922
          newRRC->setHints(SvcParam::ipv4hint, hints);
×
923
        }
×
924
      }
×
925

926
      if (newRRC->autoHint(SvcParam::ipv6hint)) {
138!
927
        sd.db->lookup(QType::AAAA, svcTarget, sd.domain_id);
×
928
        vector<ComboAddress> hints;
×
929
        DNSZoneRecord rr;
×
930
        while (sd.db->get(rr)) {
×
931
          auto arrc = getRR<AAAARecordContent>(rr.dr);
×
932
          hints.push_back(arrc->getCA());
×
933
        }
×
934
        if (hints.size() == 0) {
×
935
          newRRC->removeParam(SvcParam::ipv6hint);
×
936
        } else {
×
937
          newRRC->setHints(SvcParam::ipv6hint, hints);
×
938
        }
×
939
      }
×
940

941
      loopRR.dr.setContent(std::move(newRRC));
138✔
942
    }
138✔
943
  }
504,022✔
944

945
  // Group records by name and type, signpipe stumbles over interrupted rrsets
946
  if(securedZone && !presignedZone) {
1,583✔
947
    sort(zrrs.begin(), zrrs.end(), [](const DNSZoneRecord& a, const DNSZoneRecord& b) {
6,128,577✔
948
      return std::tie(a.dr.d_name, a.dr.d_type) < std::tie(b.dr.d_name, b.dr.d_type);
6,128,577✔
949
    });
6,128,577✔
950
  }
972✔
951

952
  if(rectify) {
1,583✔
953
    // set auth
954
    for(DNSZoneRecord &loopZRR :  zrrs) {
1,001✔
955
      loopZRR.auth=true;
1,001✔
956
      if (loopZRR.dr.d_type != QType::NS || loopZRR.dr.d_name!=target) {
1,001✔
957
        DNSName shorter(loopZRR.dr.d_name);
882✔
958
        do {
1,628✔
959
          if (shorter==target) // apex is always auth
1,628✔
960
            break;
481✔
961
          if(nsset.count(shorter) && !(loopZRR.dr.d_name==shorter && loopZRR.dr.d_type == QType::DS)) {
1,147✔
962
            loopZRR.auth=false;
401✔
963
            break;
401✔
964
          }
401✔
965
        } while(shorter.chopOff());
1,147!
966
      }
882✔
967
    }
1,001✔
968

969
    if(NSEC3Zone) {
69✔
970
      // ents are only required for NSEC3 zones
971
      uint32_t maxent = ::arg().asNum("max-ent-entries");
13✔
972
      set<DNSName> nsec3set, nonterm;
13✔
973
      for (auto &loopZRR: zrrs) {
178✔
974
        bool skip=false;
178✔
975
        DNSName shorter = loopZRR.dr.d_name;
178✔
976
        if (shorter != target && shorter.chopOff() && shorter != target) {
178!
977
          do {
51✔
978
            if(nsset.count(shorter)) {
51✔
979
              skip=true;
11✔
980
              break;
11✔
981
            }
11✔
982
          } while(shorter.chopOff() && shorter != target);
51!
983
        }
31✔
984
        shorter = loopZRR.dr.d_name;
×
985
        if(!skip && (loopZRR.dr.d_type != QType::NS || !ns3pr.d_flags)) {
178!
986
          do {
290✔
987
            if(!nsec3set.count(shorter)) {
290✔
988
              nsec3set.insert(shorter);
104✔
989
            }
104✔
990
          } while(shorter != target && shorter.chopOff());
290!
991
        }
167✔
992
      }
178✔
993

994
      for(DNSZoneRecord &loopZRR :  zrrs) {
178✔
995
        DNSName shorter(loopZRR.dr.d_name);
178✔
996
        while(shorter != target && shorter.chopOff()) {
331!
997
          if(!qnames.count(shorter) && !nonterm.count(shorter) && nsec3set.count(shorter)) {
153✔
998
            if(!(maxent)) {
17!
999
              g_log<<Logger::Warning<<logPrefix<<"zone has too many empty non terminals, aborting AXFR"<<endl;
×
1000
              outpacket->setRcode(RCode::ServFail);
×
1001
              sendPacket(outpacket,outsock);
×
1002
              return 0;
×
1003
            }
×
1004
            nonterm.insert(shorter);
17✔
1005
            --maxent;
17✔
1006
          }
17✔
1007
        }
153✔
1008
      }
178✔
1009

1010
      for(const auto& nt :  nonterm) {
17✔
1011
        DNSZoneRecord tempRR;
17✔
1012
        tempRR.dr.d_name=nt;
17✔
1013
        tempRR.dr.d_type=QType::ENT;
17✔
1014
        tempRR.auth=true;
17✔
1015
        zrrs.push_back(tempRR);
17✔
1016
      }
17✔
1017
    }
13✔
1018
  }
69✔
1019

1020
send:
1,619✔
1021

1022
  /* now write all other records */
1023

1024
  typedef map<DNSName, NSECXEntry, CanonDNSNameCompare> nsecxrepo_t;
1,619✔
1025
  nsecxrepo_t nsecxrepo;
1,619✔
1026

1027
  ChunkedSigningPipe csp(targetZone, (securedZone && !presignedZone), ::arg().asNum("signing-threads", 1), ::arg().mustDo("workaround-11804") ? 1 : 100);
1,619!
1028

1029
  DNSName keyname;
1,619✔
1030
  unsigned int udiff;
1,619✔
1031
  DTime dt;
1,619✔
1032
  dt.set();
1,619✔
1033
  for(DNSZoneRecord &loopZRR :  zrrs) {
504,793✔
1034
    if(securedZone && (loopZRR.auth || loopZRR.dr.d_type == QType::NS)) {
504,793✔
1035
      if (NSEC3Zone || loopZRR.dr.d_type) {
375,930✔
1036
        if (presignedZone && NSEC3Zone && loopZRR.dr.d_type == QType::RRSIG && getRR<RRSIGRecordContent>(loopZRR.dr)->d_type == QType::NSEC3) {
375,089✔
1037
          keyname = loopZRR.dr.d_name.makeRelative(sd.qname());
2,984✔
1038
        } else {
372,105✔
1039
          keyname = NSEC3Zone ? DNSName(toBase32Hex(hashQNameWithSalt(ns3pr, loopZRR.dr.d_name))) : loopZRR.dr.d_name;
372,105✔
1040
        }
372,105✔
1041
        NSECXEntry& ne = nsecxrepo[keyname];
375,089✔
1042
        ne.d_ttl = sd.getNegativeTTL();
375,089✔
1043
        ne.d_auth = (ne.d_auth || loopZRR.auth || (NSEC3Zone && (!ns3pr.d_flags)));
375,089✔
1044
        if (loopZRR.dr.d_type && loopZRR.dr.d_type != QType::RRSIG) {
375,089✔
1045
          ne.d_set.set(loopZRR.dr.d_type);
364,399✔
1046
        }
364,399✔
1047
      }
375,089✔
1048
    }
375,930✔
1049

1050
    if (!loopZRR.dr.d_type)
504,793✔
1051
      continue; // skip empty non-terminals
4,039✔
1052

1053
    if(loopZRR.dr.d_type == QType::SOA)
500,754✔
1054
      continue; // skip SOA - would indicate end of AXFR
1,583✔
1055

1056
    if(csp.submit(loopZRR)) {
499,171✔
1057
      for(;;) {
17,473✔
1058
        outpacket->getRRS() = csp.getChunk();
17,473✔
1059
        if(!outpacket->getRRS().empty()) {
17,473✔
1060
          if(haveTSIGDetails && !tsigkeyname.empty())
9,484!
1061
            outpacket->setTSIGDetails(trc, tsigkeyname, tsigsecret, trc.d_mac, true);
×
1062
          sendPacket(outpacket, outsock, false);
9,484✔
1063
          trc.d_mac=outpacket->d_trc.d_mac;
9,484✔
1064
          outpacket=getFreshAXFRPacket(q);
9,484✔
1065
        }
9,484✔
1066
        else
7,989✔
1067
          break;
7,989✔
1068
      }
17,473✔
1069
    }
7,991✔
1070
  }
499,171✔
1071
  /*
1072
  udiff=dt.udiffNoReset();
1073
  cerr<<"Starting NSEC: "<<csp.d_signed/(udiff/1000000.0)<<" sigs/s, "<<csp.d_signed<<" / "<<udiff/1000000.0<<endl;
1074
  cerr<<"Outstanding: "<<csp.d_outstanding<<", "<<csp.d_queued - csp.d_signed << endl;
1075
  cerr<<"Ready for consumption: "<<csp.getReady()<<endl;
1076
  */
1077
  if(securedZone) {
1,619✔
1078
    if(NSEC3Zone) {
1,344✔
1079
      for(nsecxrepo_t::const_iterator iter = nsecxrepo.begin(); iter != nsecxrepo.end(); ++iter) {
250,822✔
1080
        if(iter->second.d_auth) {
249,965✔
1081
          NSEC3RecordContent n3rc;
249,546✔
1082
          n3rc.set(iter->second.d_set);
249,546✔
1083
          const auto numberOfTypesSet = n3rc.numberOfTypesSet();
249,546✔
1084
          if (numberOfTypesSet != 0 && (numberOfTypesSet != 1 || !n3rc.isSet(QType::NS))) {
249,546✔
1085
            n3rc.set(QType::RRSIG);
247,593✔
1086
          }
247,593✔
1087
          n3rc.d_salt = ns3pr.d_salt;
249,546✔
1088
          n3rc.d_flags = ns3pr.d_flags;
249,546✔
1089
          n3rc.d_iterations = ns3pr.d_iterations;
249,546✔
1090
          n3rc.d_algorithm = DNSSECKeeper::DIGEST_SHA1; // SHA1, fixed in PowerDNS for now
249,546✔
1091
          nsecxrepo_t::const_iterator inext = iter;
249,546✔
1092
          ++inext;
249,546✔
1093
          if(inext == nsecxrepo.end())
249,546✔
1094
            inext = nsecxrepo.begin();
853✔
1095
          while(!inext->second.d_auth && inext != iter)
249,965!
1096
          {
419✔
1097
            ++inext;
419✔
1098
            if(inext == nsecxrepo.end())
419!
1099
              inext = nsecxrepo.begin();
×
1100
          }
419✔
1101
          n3rc.d_nexthash = fromBase32Hex(inext->first.toStringNoDot());
249,546✔
1102
          zrr.dr.d_name = iter->first+sd.qname();
249,546✔
1103

1104
          zrr.dr.d_ttl = sd.getNegativeTTL();
249,546✔
1105
          zrr.dr.setContent(std::make_shared<NSEC3RecordContent>(std::move(n3rc)));
249,546✔
1106
          zrr.dr.d_type = QType::NSEC3;
249,546✔
1107
          zrr.dr.d_place = DNSResourceRecord::ANSWER;
249,546✔
1108
          zrr.auth=true;
249,546✔
1109
          if(csp.submit(zrr)) {
249,546✔
1110
            for(;;) {
10,764✔
1111
              outpacket->getRRS() = csp.getChunk();
10,764✔
1112
              if(!outpacket->getRRS().empty()) {
10,764✔
1113
                if(haveTSIGDetails && !tsigkeyname.empty())
6,052!
1114
                  outpacket->setTSIGDetails(trc, tsigkeyname, tsigsecret, trc.d_mac, true);
×
1115
                sendPacket(outpacket, outsock, false);
6,052✔
1116
                trc.d_mac=outpacket->d_trc.d_mac;
6,052✔
1117
                outpacket=getFreshAXFRPacket(q);
6,052✔
1118
              }
6,052✔
1119
              else
4,712✔
1120
                break;
4,712✔
1121
            }
10,764✔
1122
          }
4,716✔
1123
        }
249,546✔
1124
      }
249,965✔
1125
    }
857✔
1126
    else for(nsecxrepo_t::const_iterator iter = nsecxrepo.begin(); iter != nsecxrepo.end(); ++iter) {
105,251✔
1127
      NSECRecordContent nrc;
104,764✔
1128
      nrc.set(iter->second.d_set);
104,764✔
1129
      nrc.set(QType::RRSIG);
104,764✔
1130
      nrc.set(QType::NSEC);
104,764✔
1131

1132
      if(boost::next(iter) != nsecxrepo.end())
104,764✔
1133
        nrc.d_next = boost::next(iter)->first;
104,277✔
1134
      else
487✔
1135
        nrc.d_next=nsecxrepo.begin()->first;
487✔
1136
      zrr.dr.d_name = iter->first;
104,764✔
1137

1138
      zrr.dr.d_ttl = sd.getNegativeTTL();
104,764✔
1139
      zrr.dr.setContent(std::make_shared<NSECRecordContent>(std::move(nrc)));
104,764✔
1140
      zrr.dr.d_type = QType::NSEC;
104,764✔
1141
      zrr.dr.d_place = DNSResourceRecord::ANSWER;
104,764✔
1142
      zrr.auth=true;
104,764✔
1143
      if(csp.submit(zrr)) {
104,764✔
1144
        for(;;) {
4,579✔
1145
          outpacket->getRRS() = csp.getChunk();
4,579✔
1146
          if(!outpacket->getRRS().empty()) {
4,579✔
1147
            if(haveTSIGDetails && !tsigkeyname.empty())
2,799!
1148
              outpacket->setTSIGDetails(trc, tsigkeyname, tsigsecret, trc.d_mac, true);
×
1149
            sendPacket(outpacket, outsock, false);
2,799✔
1150
            trc.d_mac=outpacket->d_trc.d_mac;
2,799✔
1151
            outpacket=getFreshAXFRPacket(q);
2,799✔
1152
          }
2,799✔
1153
          else
1,780✔
1154
            break;
1,780✔
1155
        }
4,579✔
1156
      }
1,780✔
1157
    }
104,764✔
1158
  }
1,344✔
1159
  /*
1160
  udiff=dt.udiffNoReset();
1161
  cerr<<"Flushing pipe: "<<csp.d_signed/(udiff/1000000.0)<<" sigs/s, "<<csp.d_signed<<" / "<<udiff/1000000.0<<endl;
1162
  cerr<<"Outstanding: "<<csp.d_outstanding<<", "<<csp.d_queued - csp.d_signed << endl;
1163
  cerr<<"Ready for consumption: "<<csp.getReady()<<endl;
1164
  * */
1165
  for(;;) {
3,324✔
1166
    outpacket->getRRS() = csp.getChunk(true); // flush the pipe
3,324✔
1167
    if(!outpacket->getRRS().empty()) {
3,324✔
1168
      if(haveTSIGDetails && !tsigkeyname.empty())
1,749!
1169
        outpacket->setTSIGDetails(trc, tsigkeyname, tsigsecret, trc.d_mac, true); // first answer is 'normal'
59✔
1170
      try {
1,749✔
1171
        sendPacket(outpacket, outsock, false);
1,749✔
1172
      }
1,749✔
1173
      catch (PDNSException& pe) {
1,749✔
1174
        throw PDNSException("during axfr-out of "+target.toString()+", this happened: "+pe.reason);
×
1175
      }
×
1176
      trc.d_mac=outpacket->d_trc.d_mac;
1,711✔
1177
      outpacket=getFreshAXFRPacket(q);
1,711✔
1178
    }
1,711✔
1179
    else
1,575✔
1180
      break;
1,575✔
1181
  }
3,324✔
1182

1183
  udiff=dt.udiffNoReset();
1,581✔
1184
  if(securedZone)
1,581✔
1185
    g_log<<Logger::Debug<<logPrefix<<"done signing: "<<csp.d_signed/(udiff/1000000.0)<<" sigs/s, "<<endl;
1,302✔
1186

1187
  DLOG(g_log<<logPrefix<<"done writing out records"<<endl);
1,581✔
1188
  /* and terminate with yet again the SOA record */
1189
  outpacket=getFreshAXFRPacket(q);
1,581✔
1190
  outpacket->addRecord(std::move(soa));
1,581✔
1191
  if(haveTSIGDetails && !tsigkeyname.empty())
1,581!
1192
    outpacket->setTSIGDetails(trc, tsigkeyname, tsigsecret, trc.d_mac, true);
59✔
1193

1194
  sendPacket(outpacket, outsock);
1,581✔
1195

1196
  DLOG(g_log<<logPrefix<<"last packet - close"<<endl);
1,581✔
1197
  g_log<<Logger::Notice<<logPrefix<<"AXFR finished"<<endl;
1,581✔
1198

1199
  return 1;
1,581✔
1200
}
1,619✔
1201

1202
int TCPNameserver::doIXFR(std::unique_ptr<DNSPacket>& q, int outsock)
1203
{
108✔
1204
  string logPrefix="IXFR-out zone '"+q->qdomainzone.toLogString()+"', client '"+q->getRemoteStringWithPort()+"', ";
108✔
1205

1206
  std::unique_ptr<DNSPacket> outpacket=getFreshAXFRPacket(q);
108✔
1207
  if(q->d_dnssecOk)
108!
1208
    outpacket->d_dnssecOk=true; // RFC 5936, 2.2.5 'SHOULD'
×
1209

1210
  uint32_t serial = 0;
108✔
1211
  MOADNSParser mdp(false, q->getString());
108✔
1212
  for(const auto & answer : mdp.d_answers) {
324✔
1213
    const DNSRecord *dnsRecord = &answer;
324✔
1214
    if (dnsRecord->d_type == QType::SOA && dnsRecord->d_place == DNSResourceRecord::AUTHORITY) {
324!
1215
      vector<string>parts;
108✔
1216
      stringtok(parts, dnsRecord->getContent()->getZoneRepresentation());
108✔
1217
      if (parts.size() >= 3) {
108!
1218
        try {
108✔
1219
          pdns::checked_stoi_into(serial, parts[2]);
108✔
1220
        }
108✔
1221
        catch(const std::out_of_range& oor) {
108✔
1222
          g_log<<Logger::Warning<<logPrefix<<"invalid serial in IXFR query"<<endl;
×
1223
          outpacket->setRcode(RCode::FormErr);
×
1224
          sendPacket(outpacket,outsock);
×
1225
          return 0;
×
1226
        }
×
1227
      } else {
108✔
1228
        g_log<<Logger::Warning<<logPrefix<<"no serial in IXFR query"<<endl;
×
1229
        outpacket->setRcode(RCode::FormErr);
×
1230
        sendPacket(outpacket,outsock);
×
1231
        return 0;
×
1232
      }
×
1233
    } else if (dnsRecord->d_type != QType::TSIG && dnsRecord->d_type != QType::OPT) {
216!
1234
      g_log<<Logger::Warning<<logPrefix<<"additional records in IXFR query, type: "<<QType(dnsRecord->d_type).toString()<<endl;
×
1235
      outpacket->setRcode(RCode::FormErr);
×
1236
      sendPacket(outpacket,outsock);
×
1237
      return 0;
×
1238
    }
×
1239
  }
324✔
1240

1241
  g_log<<Logger::Warning<<logPrefix<<"transfer initiated with serial "<<serial<<endl;
108✔
1242

1243
  // determine if zone exists, XFR is allowed, and if IXFR can proceed using existing backend before spawning a new backend.
1244
  SOAData sd;
108✔
1245
  bool securedZone;
108✔
1246
  bool serialPermitsIXFR;
108✔
1247
  {
108✔
1248
    auto packetHandler = s_P.lock();
108✔
1249
    DLOG(g_log<<logPrefix<<"Looking for SOA"<<endl); // find domain_id via SOA and list complete domain. No SOA, no IXFR
108✔
1250
    if(!*packetHandler) {
108!
1251
      g_log<<Logger::Warning<<"TCP server is without backend connections in doIXFR, launching"<<endl;
×
1252
      *packetHandler = make_unique<PacketHandler>();
×
1253
    }
×
1254

1255
    // canDoAXFR does all the ACL checks, and has the if(disable-axfr) shortcut, call it first.
1256
    if(!canDoAXFR(q, false, *packetHandler) || !(*packetHandler)->getBackend()->getSOAUncached(q->qdomainzone, sd)) {
108!
1257
      g_log<<Logger::Warning<<logPrefix<<"failed: not authoritative"<<endl;
72✔
1258
      outpacket->setRcode(RCode::NotAuth);
72✔
1259
      sendPacket(outpacket,outsock);
72✔
1260
      return 0;
72✔
1261
    }
72✔
1262

1263
    DNSSECKeeper dk((*packetHandler)->getBackend());
36✔
1264
    DNSSECKeeper::clearCaches(q->qdomainzone);
36✔
1265
    bool narrow = false;
36✔
1266
    securedZone = dk.isSecuredZone(q->qdomainzone);
36✔
1267
    if(dk.getNSEC3PARAM(q->qdomainzone, nullptr, &narrow)) {
36✔
1268
      if(narrow) {
16!
1269
        g_log<<Logger::Warning<<logPrefix<<"not doing IXFR of an NSEC3 narrow zone"<<endl;
×
1270
        outpacket->setRcode(RCode::Refused);
×
1271
        sendPacket(outpacket,outsock);
×
1272
        return 0;
×
1273
      }
×
1274
    }
16✔
1275

1276
    serialPermitsIXFR = !rfc1982LessThan(serial, calculateEditSOA(sd.serial, dk, sd.zonename));
36✔
1277
  }
36✔
1278

1279
  if (serialPermitsIXFR) {
36!
1280
    const ZoneName& target = q->qdomainzone;
36✔
1281
    TSIGRecordContent trc;
36✔
1282
    DNSName tsigkeyname;
36✔
1283
    string tsigsecret;
36✔
1284

1285
    UeberBackend db;
36✔
1286
    DNSSECKeeper dk(&db);
36✔
1287

1288
    bool haveTSIGDetails = q->getTSIGDetails(&trc, &tsigkeyname);
36✔
1289

1290
    if(haveTSIGDetails && !tsigkeyname.empty()) {
36!
1291
      string tsig64;
36✔
1292
      DNSName algorithm=trc.d_algoName; // FIXME400: was toLowerCanonic, compare output
36✔
1293
      if (algorithm == g_hmacmd5dnsname_long) {
36!
1294
        algorithm = g_hmacmd5dnsname;
36✔
1295
      }
36✔
1296
      if (!db.getTSIGKey(tsigkeyname, algorithm, tsig64)) {
36!
1297
        g_log << Logger::Error << "TSIG key '" << tsigkeyname << "' for domain '" << target << "' not found" << endl;
×
1298
        return 0;
×
1299
      }
×
1300
      if (B64Decode(tsig64, tsigsecret) == -1) {
36!
1301
        g_log<<Logger::Error<<logPrefix<<"unable to Base-64 decode TSIG key '"<<tsigkeyname<<"'"<<endl;
×
1302
        return 0;
×
1303
      }
×
1304
    }
36✔
1305

1306
    // SOA *must* go out first, our signing pipe might reorder
1307
    DLOG(g_log<<logPrefix<<"sending out SOA"<<endl);
36✔
1308
    DNSZoneRecord soa = makeEditedDNSZRFromSOAData(dk, sd);
36✔
1309
    outpacket->addRecord(std::move(soa));
36✔
1310
    if(securedZone && outpacket->d_dnssecOk) {
36!
1311
      set<ZoneName> authSet;
×
1312
      authSet.insert(target);
×
1313
      addRRSigs(dk, db, authSet, outpacket->getRRS());
×
1314
    }
×
1315

1316
    if(haveTSIGDetails && !tsigkeyname.empty())
36!
1317
      outpacket->setTSIGDetails(trc, tsigkeyname, tsigsecret, trc.d_mac); // first answer is 'normal'
36✔
1318

1319
    sendPacket(outpacket, outsock);
36✔
1320

1321
    g_log<<Logger::Notice<<logPrefix<<"IXFR finished"<<endl;
36✔
1322

1323
    return 1;
36✔
1324
  }
36✔
1325

1326
  g_log<<Logger::Notice<<logPrefix<<"IXFR fallback to AXFR"<<endl;
×
1327
  return doAXFR(q->qdomainzone, q, outsock);
×
1328
}
36✔
1329

1330
TCPNameserver::~TCPNameserver() = default;
×
1331
TCPNameserver::TCPNameserver()
1332
{
169✔
1333
  d_maxTransactionsPerConn = ::arg().asNum("max-tcp-transactions-per-conn");
169✔
1334
  d_idleTimeout = ::arg().asNum("tcp-idle-timeout");
169✔
1335
  d_maxConnectionDuration = ::arg().asNum("max-tcp-connection-duration");
169✔
1336
  d_maxConnectionsPerClient = ::arg().asNum("max-tcp-connections-per-client");
169✔
1337

1338
//  sem_init(&d_connectionroom_sem,0,::arg().asNum("max-tcp-connections"));
1339
  d_connectionroom_sem = make_unique<Semaphore>( ::arg().asNum( "max-tcp-connections" ));
169✔
1340
  d_maxTCPConnections = ::arg().asNum( "max-tcp-connections" );
169✔
1341

1342
  vector<string>locals;
169✔
1343
  stringtok(locals,::arg()["local-address"]," ,");
169✔
1344
  if(locals.empty())
169!
1345
    throw PDNSException("No local addresses specified");
×
1346

1347
  d_ng.toMasks(::arg()["allow-axfr-ips"] );
169✔
1348

1349
  signal(SIGPIPE,SIG_IGN);
169✔
1350

1351
  for(auto const &laddr : locals) {
223✔
1352
    ComboAddress local(laddr, ::arg().asNum("local-port"));
223✔
1353

1354
    int s=socket(local.sin4.sin_family, SOCK_STREAM, 0);
223✔
1355
    if(s<0)
223!
1356
      throw PDNSException("Unable to acquire TCP socket: "+stringerror());
×
1357
    setCloseOnExec(s);
223✔
1358

1359
    int tmp=1;
223✔
1360
    if(setsockopt(s, SOL_SOCKET,SO_REUSEADDR, (char*)&tmp, sizeof tmp) < 0) {
223!
1361
      g_log<<Logger::Error<<"Setsockopt failed"<<endl;
×
1362
      _exit(1);
×
1363
    }
×
1364

1365
    if (::arg().asNum("tcp-fast-open") > 0) {
223!
1366
#ifdef TCP_FASTOPEN
×
1367
      int fastOpenQueueSize = ::arg().asNum("tcp-fast-open");
×
1368
      if (setsockopt(s, IPPROTO_TCP, TCP_FASTOPEN, &fastOpenQueueSize, sizeof fastOpenQueueSize) < 0) {
×
1369
        g_log<<Logger::Error<<"Failed to enable TCP Fast Open for listening socket "<<local.toStringWithPort()<<": "<<stringerror()<<endl;
×
1370
      }
×
1371
#else
1372
      g_log<<Logger::Warning<<"TCP Fast Open configured but not supported for listening socket"<<endl;
1373
#endif
1374
    }
×
1375

1376
    if(::arg().mustDo("non-local-bind"))
223!
1377
      Utility::setBindAny(local.sin4.sin_family, s);
×
1378

1379
    if(local.isIPv6() && setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &tmp, sizeof(tmp)) < 0) {
223!
1380
      g_log<<Logger::Error<<"Failed to set IPv6 socket to IPv6 only, continuing anyhow: "<<stringerror()<<endl;
×
1381
    }
×
1382

1383
    if(::bind(s, (sockaddr*)&local, local.getSocklen())<0) {
223!
1384
      int err = errno;
×
1385
      close(s);
×
1386
      if( err == EADDRNOTAVAIL && ! ::arg().mustDo("local-address-nonexist-fail") ) {
×
1387
        g_log<<Logger::Error<<"Address " << local.toString() << " does not exist on this server - skipping TCP bind" << endl;
×
1388
        continue;
×
1389
      } else {
×
1390
        g_log<<Logger::Error<<"Unable to bind to TCP socket " << local.toStringWithPort() << ": "<<stringerror(err)<<endl;
×
1391
        throw PDNSException("Unable to bind to TCP socket");
×
1392
      }
×
1393
    }
×
1394

1395
    listen(s, 128);
223✔
1396
    g_log<<Logger::Error<<"TCP server bound to "<<local.toStringWithPort()<<endl;
223✔
1397
    d_sockets.push_back(s);
223✔
1398
    struct pollfd pfd;
223✔
1399
    memset(&pfd, 0, sizeof(pfd));
223✔
1400
    pfd.fd = s;
223✔
1401
    pfd.events = POLLIN;
223✔
1402
    d_prfds.push_back(pfd);
223✔
1403
  }
223✔
1404
}
169✔
1405

1406

1407
//! Start of TCP operations thread, we launch a new thread for each incoming TCP question
1408
void TCPNameserver::thread()
1409
{
169✔
1410
  setThreadName("pdns/tcpnameser");
169✔
1411
  try {
169✔
1412
    for(;;) {
20,088✔
1413
      int fd;
20,088✔
1414
      ComboAddress remote;
20,088✔
1415
      Utility::socklen_t addrlen=remote.getSocklen();
20,088✔
1416

1417
      int ret=poll(&d_prfds[0], d_prfds.size(), -1); // blocks, forever if need be
20,088✔
1418
      if(ret <= 0)
20,088!
1419
        continue;
×
1420

1421
      int sock=-1;
20,088✔
1422
      for(const pollfd& pfd :  d_prfds) {
25,042✔
1423
        if(pfd.revents & POLLIN) {
25,009✔
1424
          sock = pfd.fd;
19,919✔
1425
          remote.sin4.sin_family = AF_INET6;
19,919✔
1426
          addrlen=remote.getSocklen();
19,919✔
1427

1428
          if((fd=accept(sock, (sockaddr*)&remote, &addrlen))<0) {
19,919!
1429
            int err = errno;
×
1430
            g_log<<Logger::Error<<"TCP question accept error: "<<stringerror(err)<<endl;
×
1431

1432
            if(err==EMFILE) {
×
1433
              g_log<<Logger::Error<<"TCP handler out of filedescriptors, exiting, won't recover from this"<<endl;
×
1434
              _exit(1);
×
1435
            }
×
1436
          }
×
1437
          else {
19,919✔
1438
            if (d_maxConnectionsPerClient) {
19,919!
1439
              auto clientsCount = s_clientsCount.lock();
×
1440
              if ((*clientsCount)[remote] >= d_maxConnectionsPerClient) {
×
1441
                g_log<<Logger::Notice<<"Limit of simultaneous TCP connections per client reached for "<< remote<<", dropping"<<endl;
×
1442
                close(fd);
×
1443
                continue;
×
1444
              }
×
1445
              (*clientsCount)[remote]++;
×
1446
            }
×
1447

1448
            d_connectionroom_sem->wait(); // blocks if no connections are available
19,919✔
1449

1450
            int room;
19,919✔
1451
            d_connectionroom_sem->getValue( &room);
19,919✔
1452
            if(room<1)
19,919!
1453
              g_log<<Logger::Warning<<"Limit of simultaneous TCP connections reached - raise max-tcp-connections"<<endl;
×
1454

1455
            try {
19,919✔
1456
              std::thread connThread(doConnection, fd);
19,919✔
1457
              connThread.detach();
19,919✔
1458
            }
19,919✔
1459
            catch (std::exception& e) {
19,919✔
1460
              g_log<<Logger::Error<<"Error creating thread: "<<e.what()<<endl;
×
1461
              d_connectionroom_sem->post();
×
1462
              close(fd);
×
1463
              decrementClientCount(remote);
×
1464
            }
×
1465
          }
19,919✔
1466
        }
19,919✔
1467
      }
25,009✔
1468
    }
20,088✔
1469
  }
169✔
1470
  catch(PDNSException &AE) {
169✔
1471
    g_log<<Logger::Error<<"TCP Nameserver thread dying because of fatal error: "<<AE.reason<<endl;
×
1472
  }
×
1473
  catch(...) {
169✔
1474
    g_log<<Logger::Error<<"TCPNameserver dying because of an unexpected fatal error"<<endl;
×
1475
  }
×
1476
  _exit(1); // take rest of server with us
×
1477
}
169✔
1478

1479

1480
unsigned int TCPNameserver::numTCPConnections()
1481
{
9✔
1482
  int room;
9✔
1483
  d_connectionroom_sem->getValue( &room);
9✔
1484
  return d_maxTCPConnections - room;
9✔
1485
}
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