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

PowerDNS / pdns / 12268421405

11 Dec 2024 02:20AM UTC coverage: 64.728% (+3.2%) from 61.567%
12268421405

Pull #14954

github

web-flow
Merge d6414658d into 5089e2c08
Pull Request #14954: clang-tidy: use std::min/max

37522 of 88810 branches covered (42.25%)

Branch coverage included in aggregate %.

3 of 10 new or added lines in 4 files covered. (30.0%)

169 existing lines in 9 files now uncovered.

125906 of 163674 relevant lines covered (76.92%)

4802085.67 hits per line

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

72.4
/pdns/packethandler.cc
1
/*
2
 * This file is part of PowerDNS or dnsdist.
3
 * Copyright -- PowerDNS.COM B.V. and its contributors
4
 *
5
 * This program is free software; you can redistribute it and/or modify
6
 * it under the terms of version 2 of the GNU General Public License as
7
 * published by the Free Software Foundation.
8
 *
9
 * In addition, for the avoidance of any doubt, permission is granted to
10
 * link this program with OpenSSL and to (re)distribute the binaries
11
 * produced as the result of such linking.
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 Street, Fifth Floor, Boston, MA 02110-1301 USA.
21
 */
22
#ifdef HAVE_CONFIG_H
23
#include "config.h"
24
#endif
25
#include "packetcache.hh"
26
#include "utility.hh"
27
#include "base32.hh"
28
#include "base64.hh"
29
#include <string>
30
#include <sys/types.h>
31
#include <boost/algorithm/string.hpp>
32
#include "dnssecinfra.hh"
33
#include "dnsseckeeper.hh"
34
#include "dns.hh"
35
#include "dnsbackend.hh"
36
#include "ueberbackend.hh"
37
#include "dnspacket.hh"
38
#include "nameserver.hh"
39
#include "distributor.hh"
40
#include "logger.hh"
41
#include "arguments.hh"
42
#include "packethandler.hh"
43
#include "statbag.hh"
44
#include "resolver.hh"
45
#include "communicator.hh"
46
#include "dnsproxy.hh"
47
#include "version.hh"
48
#include "auth-main.hh"
49
#include "trusted-notification-proxy.hh"
50
#include "gss_context.hh"
51

52
#if 0
53
#undef DLOG
54
#define DLOG(x) x
55
#endif
56

57
AtomicCounter PacketHandler::s_count;
58
NetmaskGroup PacketHandler::s_allowNotifyFrom;
59
set<string> PacketHandler::s_forwardNotify;
60
bool PacketHandler::s_SVCAutohints{false};
61

62
extern string g_programname;
63

64
// See https://www.rfc-editor.org/rfc/rfc8078.txt and https://www.rfc-editor.org/errata/eid5049 for details
65
const std::shared_ptr<CDNSKEYRecordContent> PacketHandler::s_deleteCDNSKEYContent = std::make_shared<CDNSKEYRecordContent>("0 3 0 AA==");
66
const std::shared_ptr<CDSRecordContent> PacketHandler::s_deleteCDSContent = std::make_shared<CDSRecordContent>("0 0 0 00");
67

68
PacketHandler::PacketHandler():B(g_programname), d_dk(&B)
69
{
714✔
70
  ++s_count;
714✔
71
  d_doDNAME=::arg().mustDo("dname-processing");
714✔
72
  d_doExpandALIAS = ::arg().mustDo("expand-alias");
714✔
73
  d_doResolveAcrossZones = ::arg().mustDo("resolve-across-zones");
714✔
74
  d_logDNSDetails= ::arg().mustDo("log-dns-details");
714✔
75
  string fname= ::arg()["lua-prequery-script"];
714✔
76

77
  if(fname.empty())
714!
78
  {
714✔
79
    d_pdl = nullptr;
714✔
80
  }
714✔
81
  else
×
82
  {
×
83
    d_pdl = std::make_unique<AuthLua4>(::arg()["lua-global-include-dir"]);
×
84
    d_pdl->loadFile(fname);
×
85
  }
×
86
  fname = ::arg()["lua-dnsupdate-policy-script"];
714✔
87
  if (fname.empty())
714!
88
  {
714✔
89
    d_update_policy_lua = nullptr;
714✔
90
  }
714✔
91
  else
×
92
  {
×
93
    try {
×
94
      d_update_policy_lua = std::make_unique<AuthLua4>();
×
95
      d_update_policy_lua->loadFile(fname);
×
96
    }
×
97
    catch (const std::runtime_error& e) {
×
98
      g_log<<Logger::Warning<<"Failed to load update policy - disabling: "<<e.what()<<endl;
×
99
      d_update_policy_lua = nullptr;
×
100
    }
×
101
  }
×
102
}
714✔
103

104
UeberBackend *PacketHandler::getBackend()
105
{
4,060✔
106
  return &B;
4,060✔
107
}
4,060✔
108

109
PacketHandler::~PacketHandler()
110
{
×
111
  --s_count;
×
112
  DLOG(g_log<<Logger::Error<<"PacketHandler destructor called - "<<s_count<<" left"<<endl);
×
113
}
×
114

115
/**
116
 * This adds CDNSKEY records to the answer packet. Returns true if one was added.
117
 *
118
 * @param p          Pointer to the DNSPacket containing the original question
119
 * @param r          Pointer to the DNSPacket where the records should be inserted into
120
 * @return           bool that shows if any records were added
121
**/
122
bool PacketHandler::addCDNSKEY(DNSPacket& p, std::unique_ptr<DNSPacket>& r)
123
{
1,496✔
124
  string publishCDNSKEY;
1,496✔
125
  d_dk.getPublishCDNSKEY(p.qdomain,publishCDNSKEY);
1,496✔
126
  if (publishCDNSKEY.empty())
1,496✔
127
    return false;
320✔
128

129
  DNSZoneRecord rr;
1,176✔
130
  rr.dr.d_type=QType::CDNSKEY;
1,176✔
131
  rr.dr.d_ttl=d_sd.minimum;
1,176✔
132
  rr.dr.d_name=p.qdomain;
1,176✔
133
  rr.auth=true;
1,176✔
134

135
  if (publishCDNSKEY == "0") { // delete DS via CDNSKEY
1,176✔
136
    rr.dr.setContent(s_deleteCDNSKEYContent);
392✔
137
    r->addRecord(std::move(rr));
392✔
138
    return true;
392✔
139
  }
392✔
140

141
  bool haveOne=false;
784✔
142
  DNSSECKeeper::keyset_t entryPoints = d_dk.getEntryPoints(p.qdomain);
784✔
143
  for(const auto& value: entryPoints) {
784✔
144
    if (!value.second.published) {
784!
145
      continue;
×
146
    }
×
147
    rr.dr.setContent(std::make_shared<DNSKEYRecordContent>(value.first.getDNSKEY()));
784✔
148
    r->addRecord(DNSZoneRecord(rr));
784✔
149
    haveOne=true;
784✔
150
  }
784✔
151

152
  if(::arg().mustDo("direct-dnskey")) {
784✔
153
    B.lookup(QType(QType::CDNSKEY), p.qdomain, d_sd.domain_id, &p);
88✔
154

155
    while(B.get(rr)) {
88!
156
      rr.dr.d_ttl=d_sd.minimum;
×
157
      r->addRecord(std::move(rr));
×
158
      haveOne=true;
×
159
    }
×
160
  }
88✔
161
  return haveOne;
784✔
162
}
1,176✔
163

164
/**
165
 * This adds DNSKEY records to the answer packet. Returns true if one was added.
166
 *
167
 * @param p          Pointer to the DNSPacket containing the original question
168
 * @param r          Pointer to the DNSPacket where the records should be inserted into
169
 * @return           bool that shows if any records were added
170
**/
171
bool PacketHandler::addDNSKEY(DNSPacket& p, std::unique_ptr<DNSPacket>& r)
172
{
20,591✔
173
  DNSZoneRecord rr;
20,591✔
174
  bool haveOne=false;
20,591✔
175

176
  DNSSECKeeper::keyset_t keyset = d_dk.getKeys(p.qdomain);
20,591✔
177
  for(const auto& value: keyset) {
21,268✔
178
    if (!value.second.published) {
21,168✔
179
      continue;
384✔
180
    }
384✔
181
    rr.dr.d_type=QType::DNSKEY;
20,784✔
182
    rr.dr.d_ttl=d_sd.minimum;
20,784✔
183
    rr.dr.d_name=p.qdomain;
20,784✔
184
    rr.dr.setContent(std::make_shared<DNSKEYRecordContent>(value.first.getDNSKEY()));
20,784✔
185
    rr.auth=true;
20,784✔
186
    r->addRecord(std::move(rr));
20,784✔
187
    haveOne=true;
20,784✔
188
  }
20,784✔
189

190
  if(::arg().mustDo("direct-dnskey")) {
20,591✔
191
    B.lookup(QType(QType::DNSKEY), p.qdomain, d_sd.domain_id, &p);
1,947✔
192

193
    while(B.get(rr)) {
1,947!
194
      rr.dr.d_ttl=d_sd.minimum;
×
195
      r->addRecord(std::move(rr));
×
196
      haveOne=true;
×
197
    }
×
198
  }
1,947✔
199

200
  return haveOne;
20,591✔
201
}
20,591✔
202

203
/**
204
 * This adds CDS records to the answer packet r.
205
 *
206
 * @param p   Pointer to the DNSPacket containing the original question.
207
 * @param r   Pointer to the DNSPacket where the records should be inserted into.
208
 *            used to determine record TTL.
209
 * @return    bool that shows if any records were added.
210
**/
211
bool PacketHandler::addCDS(DNSPacket& p, std::unique_ptr<DNSPacket>& r)
212
{
1,501✔
213
  string publishCDS;
1,501✔
214
  d_dk.getPublishCDS(p.qdomain, publishCDS);
1,501✔
215
  if (publishCDS.empty())
1,501✔
216
    return false;
321✔
217

218
  vector<string> digestAlgos;
1,180✔
219
  stringtok(digestAlgos, publishCDS, ", ");
1,180✔
220

221
  DNSZoneRecord rr;
1,180✔
222
  rr.dr.d_type=QType::CDS;
1,180✔
223
  rr.dr.d_ttl=d_sd.minimum;
1,180✔
224
  rr.dr.d_name=p.qdomain;
1,180✔
225
  rr.auth=true;
1,180✔
226

227
  if(std::find(digestAlgos.begin(), digestAlgos.end(), "0") != digestAlgos.end()) { // delete DS via CDS
1,180✔
228
    rr.dr.setContent(s_deleteCDSContent);
393✔
229
    r->addRecord(std::move(rr));
393✔
230
    return true;
393✔
231
  }
393✔
232

233
  bool haveOne=false;
787✔
234

235
  DNSSECKeeper::keyset_t keyset = d_dk.getEntryPoints(p.qdomain);
787✔
236

237
  for(auto const &value : keyset) {
790✔
238
    if (!value.second.published) {
790!
239
      continue;
×
240
    }
×
241
    for(auto const &digestAlgo : digestAlgos){
792✔
242
      rr.dr.setContent(std::make_shared<DSRecordContent>(makeDSFromDNSKey(p.qdomain, value.first.getDNSKEY(), pdns::checked_stoi<uint8_t>(digestAlgo))));
792✔
243
      r->addRecord(DNSZoneRecord(rr));
792✔
244
      haveOne=true;
792✔
245
    }
792✔
246
  }
790✔
247

248
  if(::arg().mustDo("direct-dnskey")) {
787✔
249
    B.lookup(QType(QType::CDS), p.qdomain, d_sd.domain_id, &p);
88✔
250

251
    while(B.get(rr)) {
88!
252
      rr.dr.d_ttl=d_sd.minimum;
×
253
      r->addRecord(std::move(rr));
×
254
      haveOne=true;
×
255
    }
×
256
  }
88✔
257

258
  return haveOne;
787✔
259
}
1,180✔
260

261
/** This adds NSEC3PARAM records. Returns true if one was added */
262
bool PacketHandler::addNSEC3PARAM(const DNSPacket& p, std::unique_ptr<DNSPacket>& r)
263
{
2,232✔
264
  DNSZoneRecord rr;
2,232✔
265

266
  NSEC3PARAMRecordContent ns3prc;
2,232✔
267
  if(d_dk.getNSEC3PARAM(p.qdomain, &ns3prc)) {
2,232✔
268
    rr.dr.d_type=QType::NSEC3PARAM;
1,331✔
269
    rr.dr.d_ttl=d_sd.minimum;
1,331✔
270
    rr.dr.d_name=p.qdomain;
1,331✔
271
    ns3prc.d_flags = 0; // the NSEC3PARAM 'flag' is defined to always be zero in RFC5155.
1,331✔
272
    rr.dr.setContent(std::make_shared<NSEC3PARAMRecordContent>(ns3prc));
1,331✔
273
    rr.auth = true;
1,331✔
274
    r->addRecord(std::move(rr));
1,331✔
275
    return true;
1,331✔
276
  }
1,331✔
277
  return false;
901✔
278
}
2,232✔
279

280

281
// This is our chaos class requests handler. Return 1 if content was added, 0 if it wasn't
282
int PacketHandler::doChaosRequest(const DNSPacket& p, std::unique_ptr<DNSPacket>& r, DNSName &target) const
283
{
×
284
  DNSZoneRecord rr;
×
285

286
  if(p.qtype.getCode()==QType::TXT) {
×
287
    static const DNSName versionbind("version.bind."), versionpdns("version.pdns."), idserver("id.server.");
×
288
    if (target==versionbind || target==versionpdns) {
×
289
      // modes: full, powerdns only, anonymous or custom
290
      const static string mode=::arg()["version-string"];
×
291
      string content;
×
292
      if(mode=="full")
×
293
        content=fullVersionString();
×
294
      else if(mode=="powerdns")
×
295
        content="Served by PowerDNS - https://www.powerdns.com/";
×
296
      else if(mode=="anonymous") {
×
297
        r->setRcode(RCode::ServFail);
×
298
        return 0;
×
299
      }
×
300
      else
×
301
        content=mode;
×
302
      rr.dr.setContent(DNSRecordContent::make(QType::TXT, 1, "\"" + content + "\""));
×
303
    }
×
304
    else if (target==idserver) {
×
305
      // modes: disabled, hostname or custom
306
      const static string id=::arg()["server-id"];
×
307

308
      if (id == "disabled") {
×
309
        r->setRcode(RCode::Refused);
×
310
        return 0;
×
311
      }
×
312
      string tid=id;
×
313
      if(!tid.empty() && tid[0]!='"') { // see #6010 however
×
314
        tid = "\"" + tid + "\"";
×
315
      }
×
316
      rr.dr.setContent(DNSRecordContent::make(QType::TXT, 1, tid));
×
317
    }
×
318
    else {
×
319
      r->setRcode(RCode::Refused);
×
320
      return 0;
×
321
    }
×
322

323
    rr.dr.d_ttl=5;
×
324
    rr.dr.d_name=target;
×
325
    rr.dr.d_type=QType::TXT;
×
326
    rr.dr.d_class=QClass::CHAOS;
×
327
    r->addRecord(std::move(rr));
×
328
    return 1;
×
329
  }
×
330

331
  r->setRcode(RCode::NotImp);
×
332
  return 0;
×
333
}
×
334

335
vector<DNSZoneRecord> PacketHandler::getBestReferralNS(DNSPacket& p, const DNSName &target)
336
{
75,767✔
337
  vector<DNSZoneRecord> ret;
75,767✔
338
  DNSZoneRecord rr;
75,767✔
339
  DNSName subdomain(target);
75,767✔
340
  do {
183,454✔
341
    if(subdomain == d_sd.qname) // stop at SOA
183,454✔
342
      break;
70,305✔
343
    B.lookup(QType(QType::NS), subdomain, d_sd.domain_id, &p);
113,149✔
344
    while(B.get(rr)) {
121,141✔
345
      ret.push_back(rr); // this used to exclude auth NS records for some reason
7,992✔
346
    }
7,992✔
347
    if(!ret.empty())
113,149✔
348
      return ret;
5,462✔
349
  } while( subdomain.chopOff() );   // 'www.powerdns.org' -> 'powerdns.org' -> 'org' -> ''
113,149!
350
  return ret;
70,305✔
351
}
75,767✔
352

353
void PacketHandler::getBestDNAMESynth(DNSPacket& p, DNSName &target, vector<DNSZoneRecord> &ret)
354
{
13,737✔
355
  ret.clear();
13,737✔
356
  DNSZoneRecord rr;
13,737✔
357
  DNSName prefix;
13,737✔
358
  DNSName subdomain(target);
13,737✔
359
  do {
47,332✔
360
    DLOG(g_log<<"Attempting DNAME lookup for "<<subdomain<<", d_sd.qname="<<d_sd.qname<<endl);
47,332✔
361

362
    B.lookup(QType(QType::DNAME), subdomain, d_sd.domain_id, &p);
47,332✔
363
    while(B.get(rr)) {
48,568✔
364
      ret.push_back(rr);  // put in the original
1,236✔
365
      rr.dr.d_type = QType::CNAME;
1,236✔
366
      rr.dr.d_name = prefix + rr.dr.d_name;
1,236✔
367
      rr.dr.setContent(std::make_shared<CNAMERecordContent>(CNAMERecordContent(prefix + getRR<DNAMERecordContent>(rr.dr)->getTarget())));
1,236✔
368
      rr.auth = false; // don't sign CNAME
1,236✔
369
      target = getRR<CNAMERecordContent>(rr.dr)->getTarget();
1,236✔
370
      ret.push_back(rr);
1,236✔
371
    }
1,236✔
372
    if(!ret.empty())
47,332✔
373
      return;
884✔
374
    if(subdomain.countLabels())
46,448✔
375
      prefix.appendRawLabel(subdomain.getRawLabels()[0]); // XXX DNSName pain this feels wrong
45,417✔
376
    if(subdomain == d_sd.qname) // stop at SOA
46,448✔
377
      break;
12,501✔
378

379
  } while( subdomain.chopOff() );   // 'www.powerdns.org' -> 'powerdns.org' -> 'org' -> ''
46,448✔
380
  return;
12,853✔
381
}
13,737✔
382

383

384
// Return best matching wildcard or next closer name
385
bool PacketHandler::getBestWildcard(DNSPacket& p, const DNSName &target, DNSName &wildcard, vector<DNSZoneRecord>* ret)
386
{
21,179✔
387
  ret->clear();
21,179✔
388
  DNSZoneRecord rr;
21,179✔
389
  DNSName subdomain(target);
21,179✔
390
  bool haveSomething=false;
21,179✔
391
  bool haveCNAME = false;
21,179✔
392

393
#ifdef HAVE_LUA_RECORDS
21,179✔
394
  bool doLua=g_doLuaRecord;
21,179✔
395
  if(!doLua) {
21,179!
396
    string val;
21,179✔
397
    d_dk.getFromMeta(d_sd.qname, "ENABLE-LUA-RECORDS", val);
21,179✔
398
    doLua = (val=="1");
21,179✔
399
  }
21,179✔
400
#endif
21,179✔
401

402
  wildcard=subdomain;
21,179✔
403
  while( subdomain.chopOff() && !haveSomething )  {
41,493!
404
    if (subdomain.empty()) {
41,493!
405
      B.lookup(QType(QType::ANY), g_wildcarddnsname, d_sd.domain_id, &p);
×
406
    } else {
41,493✔
407
      B.lookup(QType(QType::ANY), g_wildcarddnsname+subdomain, d_sd.domain_id, &p);
41,493✔
408
    }
41,493✔
409
    while(B.get(rr)) {
51,571✔
410
      if (haveCNAME) {
10,078✔
411
        continue;
789✔
412
      }
789✔
413
#ifdef HAVE_LUA_RECORDS
9,289✔
414
      if (rr.dr.d_type == QType::LUA && !d_dk.isPresigned(d_sd.qname)) {
9,289!
415
        if(!doLua) {
×
416
          DLOG(g_log<<"Have a wildcard LUA match, but not doing LUA record for this zone"<<endl);
×
417
          continue;
×
418
        }
×
419

420
        DLOG(g_log<<"Have a wildcard LUA match"<<endl);
×
421

422
        auto rec=getRR<LUARecordContent>(rr.dr);
×
423
        if (!rec) {
×
424
          continue;
×
425
        }
×
426
        if(rec->d_type == QType::CNAME || rec->d_type == p.qtype.getCode() || (p.qtype.getCode() == QType::ANY && rec->d_type != QType::RRSIG)) {
×
427
          //    noCache=true;
428
          DLOG(g_log<<"Executing Lua: '"<<rec->getCode()<<"'"<<endl);
×
429
          try {
×
430
            auto recvec=luaSynth(rec->getCode(), target, d_sd.qname, d_sd.domain_id, p, rec->d_type, s_LUA);
×
431
            for (const auto& r : recvec) {
×
432
              rr.dr.d_type = rec->d_type; // might be CNAME
×
433
              rr.dr.setContent(r);
×
434
              rr.scopeMask = p.getRealRemote().getBits(); // this makes sure answer is a specific as your question
×
435
              if (rr.dr.d_type == QType::CNAME) {
×
436
                haveCNAME = true;
×
437
                *ret = {rr};
×
438
                break;
×
439
              }
×
440
              ret->push_back(rr);
×
441
            }
×
442
          }
×
443
          catch (std::exception &e) {
×
444
            B.lookupEnd();                 // don't leave DB handle in bad state
×
445

446
            throw;
×
447
          }
×
448
        }
×
449
      }
×
450
      else
9,289✔
451
#endif
9,289✔
452
      if(rr.dr.d_type != QType::ENT && (rr.dr.d_type == p.qtype.getCode() || rr.dr.d_type == QType::CNAME || (p.qtype.getCode() == QType::ANY && rr.dr.d_type != QType::RRSIG))) {
9,289✔
453
        if (rr.dr.d_type == QType::CNAME) {
5,879✔
454
          haveCNAME = true;
2,388✔
455
          ret->clear();
2,388✔
456
        }
2,388✔
457
        ret->push_back(rr);
5,879✔
458
      }
5,879✔
459

460
      wildcard=g_wildcarddnsname+subdomain;
9,289✔
461
      haveSomething=true;
9,289✔
462
    }
9,289✔
463

464
    if ( subdomain == d_sd.qname || haveSomething ) // stop at SOA or result
41,493✔
465
      break;
15,335✔
466

467
    B.lookup(QType(QType::ANY), subdomain, d_sd.domain_id, &p);
26,158✔
468
    if (B.get(rr)) {
26,158✔
469
      DLOG(g_log<<"No wildcard match, ancestor exists"<<endl);
5,844✔
470
      B.lookupEnd();
5,844✔
471
      break;
5,844✔
472
    }
5,844✔
473
    wildcard=subdomain;
20,314✔
474
  }
20,314✔
475

476
  return haveSomething;
21,179✔
477
}
21,179✔
478

479
DNSName PacketHandler::doAdditionalServiceProcessing(const DNSName &firstTarget, const uint16_t &qtype, std::unique_ptr<DNSPacket>& /* r */, vector<DNSZoneRecord>& extraRecords) {
634✔
480
  DNSName ret = firstTarget;
634✔
481
  size_t ctr = 5; // Max 5 SVCB Aliasforms per query
634✔
482
  bool done = false;
634✔
483
  while (!done && ctr > 0) {
1,268!
484
    DNSZoneRecord rr;
634✔
485
    done = true;
634✔
486

487
    if(!ret.isPartOf(d_sd.qname)) {
634✔
488
      continue;
317✔
489
    }
317✔
490

491
    B.lookup(QType(qtype), ret, d_sd.domain_id);
317✔
492
    while (B.get(rr)) {
634✔
493
      rr.dr.d_place = DNSResourceRecord::ADDITIONAL;
317✔
494
      switch (qtype) {
317✔
495
        case QType::SVCB: /* fall-through */
317!
496
        case QType::HTTPS: {
317!
497
          auto rrc = getRR<SVCBBaseRecordContent>(rr.dr);
317✔
498
          extraRecords.push_back(std::move(rr));
317✔
499
          ret = rrc->getTarget().isRoot() ? ret : rrc->getTarget();
317!
500
          if (rrc->getPriority() == 0) {
317!
501
            done = false;
×
502
          }
×
503
          break;
317✔
504
        }
317✔
505
        default:
×
506
          B.lookupEnd();              // don't leave DB handle in bad state
×
507

508
          throw PDNSException("Unknown type (" + QType(qtype).toString() + ") for additional service processing");
×
509
      }
317✔
510
    }
317✔
511
    ctr--;
317✔
512
  }
317✔
513
  return ret;
634✔
514
}
634✔
515

516

517
void PacketHandler::doAdditionalProcessing(DNSPacket& p, std::unique_ptr<DNSPacket>& r)
518
{
97,604✔
519
  DNSName content;
97,604✔
520
  std::unordered_set<DNSName> lookup;
97,604✔
521
  vector<DNSZoneRecord> extraRecords;
97,604✔
522
  const auto& rrs = r->getRRS();
97,604✔
523

524
  lookup.reserve(rrs.size());
97,604✔
525
  for(auto& rr : rrs) {
200,460✔
526
    if(rr.dr.d_place != DNSResourceRecord::ADDITIONAL) {
200,461✔
527
      switch(rr.dr.d_type) {
200,461✔
528
        case QType::NS:
14,032✔
529
          content=getRR<NSRecordContent>(rr.dr)->getNS();
14,032✔
530
          break;
14,032✔
531
        case QType::MX:
5,434✔
532
          content=getRR<MXRecordContent>(rr.dr)->d_mxname;
5,434✔
533
          break;
5,434✔
534
        case QType::SRV:
1,759✔
535
          content=getRR<SRVRecordContent>(rr.dr)->d_target;
1,759✔
536
          break;
1,759✔
537
        case QType::SVCB: /* fall-through */
1,585✔
538
        case QType::HTTPS: {
1,585!
539
          auto rrc = getRR<SVCBBaseRecordContent>(rr.dr);
1,585✔
540
          content = rrc->getTarget();
1,585✔
541
          if (content.isRoot()) {
1,585✔
542
            content = rr.dr.d_name;
951✔
543
          }
951✔
544
          if (rrc->getPriority() == 0) {
1,585✔
545
            content = doAdditionalServiceProcessing(content, rr.dr.d_type, r, extraRecords);
634✔
546
          }
634✔
547
          break;
1,585✔
548
        }
1,585✔
549
        default:
177,651✔
550
          continue;
177,651✔
551
      }
200,461✔
552
      if(content.isPartOf(d_sd.qname)) {
22,810✔
553
        lookup.emplace(content);
17,203✔
554
      }
17,203✔
555
    }
22,810✔
556
  }
200,460✔
557

558
  for(auto& rr : extraRecords) {
97,604✔
559
    r->addRecord(std::move(rr));
317✔
560
  }
317✔
561
  extraRecords.clear();
97,604✔
562
  // TODO should we have a setting to do this?
563
  for (auto &rec : r->getServiceRecords()) {
97,604✔
564
    // Process auto hints
565
    auto rrc = getRR<SVCBBaseRecordContent>(rec->dr);
1,902✔
566
    DNSName target = rrc->getTarget().isRoot() ? rec->dr.d_name : rrc->getTarget();
1,902✔
567

568
    if (rrc->hasParam(SvcParam::ipv4hint) && rrc->autoHint(SvcParam::ipv4hint)) {
1,902!
569
      auto newRRC = rrc->clone();
×
570
      if (!newRRC) {
×
571
        continue;
×
572
      }
×
573
      if (s_SVCAutohints) {
×
574
        auto hints = getIPAddressFor(target, QType::A);
×
575
        if (hints.size() == 0) {
×
576
          newRRC->removeParam(SvcParam::ipv4hint);
×
577
        } else {
×
578
          newRRC->setHints(SvcParam::ipv4hint, hints);
×
579
        }
×
580
      } else {
×
581
        newRRC->removeParam(SvcParam::ipv4hint);
×
582
      }
×
583
      rrc = newRRC;
×
584
      rec->dr.setContent(std::move(newRRC));
×
585
    }
×
586

587
    if (rrc->hasParam(SvcParam::ipv6hint) && rrc->autoHint(SvcParam::ipv6hint)) {
1,902!
588
      auto newRRC = rrc->clone();
×
589
      if (!newRRC) {
×
590
        continue;
×
591
      }
×
592
      if (s_SVCAutohints) {
×
593
        auto hints = getIPAddressFor(target, QType::AAAA);
×
594
        if (hints.size() == 0) {
×
595
          newRRC->removeParam(SvcParam::ipv6hint);
×
596
        } else {
×
597
          newRRC->setHints(SvcParam::ipv6hint, hints);
×
598
        }
×
599
      } else {
×
600
        newRRC->removeParam(SvcParam::ipv6hint);
×
601
      }
×
602
      rec->dr.setContent(std::move(newRRC));
×
603
    }
×
604
  }
1,902✔
605

606
  DNSZoneRecord dzr;
97,604✔
607
  for(const auto& name : lookup) {
97,604✔
608
    B.lookup(QType(QType::ANY), name, d_sd.domain_id, &p);
16,252✔
609
    while(B.get(dzr)) {
78,114✔
610
      if(dzr.dr.d_type == QType::A || dzr.dr.d_type == QType::AAAA) {
61,862✔
611
        dzr.dr.d_place=DNSResourceRecord::ADDITIONAL;
56,302✔
612
        r->addRecord(std::move(dzr));
56,302✔
613
      }
56,302✔
614
    }
61,862✔
615
  }
16,252✔
616
}
97,604✔
617

618
vector<ComboAddress> PacketHandler::getIPAddressFor(const DNSName &target, const uint16_t qtype) {
×
619
  vector<ComboAddress> ret;
×
620
  if (qtype != QType::A && qtype != QType::AAAA) {
×
621
    return ret;
×
622
  }
×
623
  B.lookup(qtype, target, d_sd.domain_id);
×
624
  DNSZoneRecord rr;
×
625
  while (B.get(rr)) {
×
626
    if (qtype == QType::AAAA) {
×
627
      auto aaaarrc = getRR<AAAARecordContent>(rr.dr);
×
628
      ret.push_back(aaaarrc->getCA());
×
629
    } else if (qtype == QType::A) {
×
630
      auto arrc = getRR<ARecordContent>(rr.dr);
×
631
      ret.push_back(arrc->getCA());
×
632
    }
×
633
  }
×
634
  return ret;
×
635
}
×
636

637
void PacketHandler::emitNSEC(std::unique_ptr<DNSPacket>& r, const DNSName& name, const DNSName& next, int mode)
638
{
18,299✔
639
  NSECRecordContent nrc;
18,299✔
640
  nrc.d_next = next;
18,299✔
641

642
  nrc.set(QType::NSEC);
18,299✔
643
  nrc.set(QType::RRSIG);
18,299✔
644
  if(d_sd.qname == name) {
18,299✔
645
    nrc.set(QType::SOA); // 1dfd8ad SOA can live outside the records table
6,701✔
646
    if(!d_dk.isPresigned(d_sd.qname)) {
6,701✔
647
      auto keyset = d_dk.getKeys(name);
5,735✔
648
      for(const auto& value: keyset) {
5,735✔
649
        if (value.second.published) {
5,735✔
650
          nrc.set(QType::DNSKEY);
5,691✔
651
          string publishCDNSKEY;
5,691✔
652
          d_dk.getPublishCDNSKEY(name, publishCDNSKEY);
5,691✔
653
          if (! publishCDNSKEY.empty())
5,691✔
654
            nrc.set(QType::CDNSKEY);
521✔
655
          string publishCDS;
5,691✔
656
          d_dk.getPublishCDS(name, publishCDS);
5,691✔
657
          if (! publishCDS.empty())
5,691✔
658
            nrc.set(QType::CDS);
521✔
659
          break;
5,691✔
660
        }
5,691✔
661
      }
5,735✔
662
    }
5,735✔
663
  }
6,701✔
664

665
  DNSZoneRecord rr;
18,299✔
666
#ifdef HAVE_LUA_RECORDS
18,299✔
667
  bool first{true};
18,299✔
668
  bool doLua{false};
18,299✔
669
#endif
18,299✔
670

671
  B.lookup(QType(QType::ANY), name, d_sd.domain_id);
18,299✔
672
  while(B.get(rr)) {
73,439✔
673
#ifdef HAVE_LUA_RECORDS
55,140✔
674
    if (rr.dr.d_type == QType::LUA && first && !d_dk.isPresigned(d_sd.qname)) {
55,140!
675
      first = false;
×
676
      doLua = g_doLuaRecord;
×
677
      if (!doLua) {
×
678
        string val;
×
679
        d_dk.getFromMeta(d_sd.qname, "ENABLE-LUA-RECORDS", val);
×
680
        doLua = (val == "1");
×
681
      }
×
682
    }
×
683

684
    if (rr.dr.d_type == QType::LUA && doLua) {
55,140!
685
      nrc.set(getRR<LUARecordContent>(rr.dr)->d_type);
×
686
    }
×
687
    else
55,140✔
688
#endif
55,140✔
689
      if (d_doExpandALIAS && rr.dr.d_type == QType::ALIAS) {
55,140✔
690
      // Set the A and AAAA in the NSEC bitmap so aggressive NSEC
691
      // does not falsely deny the type for this name.
692
      // This does NOT add the ALIAS to the bitmap, as that record cannot
693
      // be requested.
694
      if (!d_dk.isPresigned(d_sd.qname)) {
90!
695
        nrc.set(QType::A);
90✔
696
        nrc.set(QType::AAAA);
90✔
697
      }
90✔
698
    }
90✔
699
    else if((rr.dr.d_type == QType::DNSKEY || rr.dr.d_type == QType::CDS || rr.dr.d_type == QType::CDNSKEY) && !d_dk.isPresigned(d_sd.qname) && !::arg().mustDo("direct-dnskey")) {
55,050!
700
      continue;
×
701
    }
×
702
    else if(rr.dr.d_type == QType::NS || rr.auth) {
55,050✔
703
      nrc.set(rr.dr.d_type);
54,550✔
704
    }
54,550✔
705
  }
55,140✔
706

707
  rr.dr.d_name = name;
18,299✔
708
  rr.dr.d_ttl = d_sd.getNegativeTTL();
18,299✔
709
  rr.dr.d_type = QType::NSEC;
18,299✔
710
  rr.dr.setContent(std::make_shared<NSECRecordContent>(std::move(nrc)));
18,299✔
711
  rr.dr.d_place = (mode == 5 ) ? DNSResourceRecord::ANSWER: DNSResourceRecord::AUTHORITY;
18,299✔
712
  rr.auth = true;
18,299✔
713

714
  r->addRecord(std::move(rr));
18,299✔
715
}
18,299✔
716

717
void PacketHandler::emitNSEC3(std::unique_ptr<DNSPacket>& r, const NSEC3PARAMRecordContent& ns3prc, const DNSName& name, const string& namehash, const string& nexthash, int mode)
718
{
38,660✔
719
  NSEC3RecordContent n3rc;
38,660✔
720
  n3rc.d_algorithm = ns3prc.d_algorithm;
38,660✔
721
  n3rc.d_flags = ns3prc.d_flags;
38,660✔
722
  n3rc.d_iterations = ns3prc.d_iterations;
38,660✔
723
  n3rc.d_salt = ns3prc.d_salt;
38,660✔
724
  n3rc.d_nexthash = nexthash;
38,660✔
725

726
  DNSZoneRecord rr;
38,660✔
727

728
  if(!name.empty()) {
38,660✔
729
    if (d_sd.qname == name) {
34,465✔
730
      n3rc.set(QType::SOA); // 1dfd8ad SOA can live outside the records table
10,801✔
731
      n3rc.set(QType::NSEC3PARAM);
10,801✔
732
      if(!d_dk.isPresigned(d_sd.qname)) {
10,801✔
733
        auto keyset = d_dk.getKeys(name);
8,576✔
734
        for(const auto& value: keyset) {
8,576✔
735
          if (value.second.published) {
8,576✔
736
            n3rc.set(QType::DNSKEY);
8,492✔
737
            string publishCDNSKEY;
8,492✔
738
            d_dk.getPublishCDNSKEY(name, publishCDNSKEY);
8,492✔
739
            if (! publishCDNSKEY.empty())
8,492✔
740
              n3rc.set(QType::CDNSKEY);
504✔
741
            string publishCDS;
8,492✔
742
            d_dk.getPublishCDS(name, publishCDS);
8,492✔
743
            if (! publishCDS.empty())
8,492✔
744
              n3rc.set(QType::CDS);
504✔
745
            break;
8,492✔
746
          }
8,492✔
747
        }
8,576✔
748
      }
8,576✔
749
    }
10,801✔
750

751
#ifdef HAVE_LUA_RECORDS
34,465✔
752
    bool first{true};
34,465✔
753
    bool doLua{false};
34,465✔
754
#endif
34,465✔
755

756
    B.lookup(QType(QType::ANY), name, d_sd.domain_id);
34,465✔
757
    while(B.get(rr)) {
128,813✔
758
#ifdef HAVE_LUA_RECORDS
94,348✔
759
      if (rr.dr.d_type == QType::LUA && first && !d_dk.isPresigned(d_sd.qname)) {
94,348!
760
        first = false;
×
761
        doLua = g_doLuaRecord;
×
762
        if (!doLua) {
×
763
          string val;
×
764
          d_dk.getFromMeta(d_sd.qname, "ENABLE-LUA-RECORDS", val);
×
765
          doLua = (val == "1");
×
766
        }
×
767
      }
×
768

769
      if (rr.dr.d_type == QType::LUA && doLua) {
94,348!
770
        n3rc.set(getRR<LUARecordContent>(rr.dr)->d_type);
×
771
      }
×
772
      else
94,348✔
773
#endif
94,348✔
774
        if (d_doExpandALIAS && rr.dr.d_type == QType::ALIAS) {
94,348✔
775
        // Set the A and AAAA in the NSEC3 bitmap so aggressive NSEC
776
        // does not falsely deny the type for this name.
777
        // This does NOT add the ALIAS to the bitmap, as that record cannot
778
        // be requested.
779
        if (!d_dk.isPresigned(d_sd.qname)) {
90!
780
          n3rc.set(QType::A);
90✔
781
          n3rc.set(QType::AAAA);
90✔
782
        }
90✔
783
      }
90✔
784
      else if((rr.dr.d_type == QType::DNSKEY || rr.dr.d_type == QType::CDS || rr.dr.d_type == QType::CDNSKEY) && !d_dk.isPresigned(d_sd.qname) && !::arg().mustDo("direct-dnskey")) {
94,258!
785
        continue;
×
786
      }
×
787
      else if(rr.dr.d_type && (rr.dr.d_type == QType::NS || rr.auth)) {
94,258✔
788
          // skip empty non-terminals
789
          n3rc.set(rr.dr.d_type);
88,289✔
790
      }
88,289✔
791
    }
94,348✔
792
  }
34,465✔
793

794
  const auto numberOfTypesSet = n3rc.numberOfTypesSet();
38,660✔
795
  if (numberOfTypesSet != 0 && !(numberOfTypesSet == 1 && n3rc.isSet(QType::NS))) {
38,660✔
796
    n3rc.set(QType::RRSIG);
27,309✔
797
  }
27,309✔
798

799
  rr.dr.d_name = DNSName(toBase32Hex(namehash))+d_sd.qname;
38,660✔
800
  rr.dr.d_ttl = d_sd.getNegativeTTL();
38,660✔
801
  rr.dr.d_type=QType::NSEC3;
38,660✔
802
  rr.dr.setContent(std::make_shared<NSEC3RecordContent>(std::move(n3rc)));
38,660✔
803
  rr.dr.d_place = (mode == 5 ) ? DNSResourceRecord::ANSWER: DNSResourceRecord::AUTHORITY;
38,660!
804
  rr.auth = true;
38,660✔
805

806
  r->addRecord(std::move(rr));
38,660✔
807
}
38,660✔
808

809
/*
810
   mode 0 = No Data Responses, QTYPE is not DS
811
   mode 1 = No Data Responses, QTYPE is DS
812
   mode 2 = Wildcard No Data Responses
813
   mode 3 = Wildcard Answer Responses
814
   mode 4 = Name Error Responses
815
   mode 5 = Direct NSEC request
816
*/
817
void PacketHandler::addNSECX(DNSPacket& p, std::unique_ptr<DNSPacket>& r, const DNSName& target, const DNSName& wildcard, int mode)
818
{
38,996✔
819
  NSEC3PARAMRecordContent ns3rc;
38,996✔
820
  bool narrow = false;
38,996✔
821
  if(d_dk.getNSEC3PARAM(d_sd.qname, &ns3rc, &narrow))  {
38,996✔
822
    if (mode != 5) // no direct NSEC3 queries, rfc5155 7.2.8
25,041✔
823
      addNSEC3(p, r, target, wildcard, ns3rc, narrow, mode);
23,318✔
824
  }
25,041✔
825
  else {
13,955✔
826
    addNSEC(p, r, target, wildcard, mode);
13,955✔
827
  }
13,955✔
828
}
38,996✔
829

830
bool PacketHandler::getNSEC3Hashes(bool narrow, const std::string& hashed, bool decrement, DNSName& unhashed, std::string& before, std::string& after, int mode)
831
{
39,574✔
832
  bool ret;
39,574✔
833
  if(narrow) { // nsec3-narrow
39,574✔
834
    ret=true;
9,575✔
835
    before=hashed;
9,575✔
836
    if(decrement) {
9,575✔
837
      decrementHash(before);
4,195✔
838
      unhashed.clear();
4,195✔
839
    }
4,195✔
840
    after=hashed;
9,575✔
841
    incrementHash(after);
9,575✔
842
  }
9,575✔
843
  else {
29,999✔
844
    DNSName hashedName = DNSName(toBase32Hex(hashed));
29,999✔
845
    DNSName beforeName, afterName;
29,999✔
846
    if (!decrement && mode >= 2)
29,999✔
847
      beforeName = hashedName;
5,359✔
848
    ret=d_sd.db->getBeforeAndAfterNamesAbsolute(d_sd.domain_id, hashedName, unhashed, beforeName, afterName);
29,999✔
849
    before=fromBase32Hex(beforeName.toString());
29,999✔
850
    after=fromBase32Hex(afterName.toString());
29,999✔
851
  }
29,999✔
852
  return ret;
39,574✔
853
}
39,574✔
854

855
void PacketHandler::addNSEC3(DNSPacket& p, std::unique_ptr<DNSPacket>& r, const DNSName& target, const DNSName& wildcard, const NSEC3PARAMRecordContent& ns3rc, bool narrow, int mode)
856
{
23,318✔
857
  DLOG(g_log<<"addNSEC3() mode="<<mode<<" auth="<<d_sd.qname<<" target="<<target<<" wildcard="<<wildcard<<endl);
23,318✔
858

859
  if (d_sd.db == nullptr) {
23,318✔
860
    if(!B.getSOAUncached(d_sd.qname, d_sd)) {
26!
861
      DLOG(g_log<<"Could not get SOA for domain");
×
862
      return;
×
863
    }
×
864
  }
26✔
865

866
  bool doNextcloser = false;
23,318✔
867
  string before, after, hashed;
23,318✔
868
  DNSName unhashed, closest;
23,318✔
869

870
  if (mode == 2 || mode == 3 || mode == 4) {
23,318✔
871
    closest=wildcard;
10,371✔
872
    closest.chopOff();
10,371✔
873
  } else
10,371✔
874
    closest=target;
12,947✔
875

876
  // add matching NSEC3 RR
877
  if (mode != 3) {
23,318✔
878
    unhashed=(mode == 0 || mode == 1 || mode == 5) ? target : closest;
20,161!
879
    hashed=hashQNameWithSalt(ns3rc, unhashed);
20,161✔
880
    DLOG(g_log<<"1 hash: "<<toBase32Hex(hashed)<<" "<<unhashed<<endl);
20,161✔
881

882
    getNSEC3Hashes(narrow, hashed, false, unhashed, before, after, mode);
20,161✔
883

884
    if (((mode == 0 && ns3rc.d_flags) ||  mode == 1) && (hashed != before)) {
20,161✔
885
      DLOG(g_log<<"No matching NSEC3, do closest (provable) encloser"<<endl);
914✔
886

887
      bool doBreak = false;
914✔
888
      DNSZoneRecord rr;
914✔
889
      while( closest.chopOff() && (closest != d_sd.qname))  { // stop at SOA
987!
890
        B.lookup(QType(QType::ANY), closest, d_sd.domain_id, &p);
242✔
891
        while(B.get(rr))
484✔
892
          if (rr.auth)
242✔
893
            doBreak = true;
169✔
894
        if(doBreak)
242✔
895
          break;
169✔
896
      }
242✔
897
      doNextcloser = true;
914✔
898
      unhashed=closest;
914✔
899
      hashed=hashQNameWithSalt(ns3rc, unhashed);
914✔
900
      DLOG(g_log<<"1 hash: "<<toBase32Hex(hashed)<<" "<<unhashed<<endl);
914✔
901

902
      getNSEC3Hashes(narrow, hashed, false, unhashed, before, after);
914✔
903
    }
914✔
904

905
    if (!after.empty()) {
20,161!
906
      DLOG(g_log<<"Done calling for matching, hashed: '"<<toBase32Hex(hashed)<<"' before='"<<toBase32Hex(before)<<"', after='"<<toBase32Hex(after)<<"'"<<endl);
20,161✔
907
      emitNSEC3(r, ns3rc, unhashed, before, after, mode);
20,161✔
908
    }
20,161✔
909
  }
20,161✔
910

911
  // add covering NSEC3 RR
912
  if ((mode >= 2 && mode <= 4) || doNextcloser) {
23,318!
913
    DNSName next(target);
11,285✔
914
    do {
16,225✔
915
      unhashed=next;
16,225✔
916
    }
16,225✔
917
    while( next.chopOff() && !(next==closest));
16,225!
918

919
    hashed=hashQNameWithSalt(ns3rc, unhashed);
11,285✔
920
    DLOG(g_log<<"2 hash: "<<toBase32Hex(hashed)<<" "<<unhashed<<endl);
11,285✔
921

922
    getNSEC3Hashes(narrow, hashed, true, unhashed, before, after);
11,285✔
923
    DLOG(g_log<<"Done calling for covering, hashed: '"<<toBase32Hex(hashed)<<"' before='"<<toBase32Hex(before)<<"', after='"<<toBase32Hex(after)<<"'"<<endl);
11,285✔
924
    emitNSEC3( r, ns3rc, unhashed, before, after, mode);
11,285✔
925
  }
11,285✔
926

927
  // wildcard denial
928
  if (mode == 2 || mode == 4) {
23,318✔
929
    unhashed=g_wildcarddnsname+closest;
7,214✔
930

931
    hashed=hashQNameWithSalt(ns3rc, unhashed);
7,214✔
932
    DLOG(g_log<<"3 hash: "<<toBase32Hex(hashed)<<" "<<unhashed<<endl);
7,214✔
933

934
    getNSEC3Hashes(narrow, hashed, (mode != 2), unhashed, before, after);
7,214✔
935
    DLOG(g_log<<"Done calling for '*', hashed: '"<<toBase32Hex(hashed)<<"' before='"<<toBase32Hex(before)<<"', after='"<<toBase32Hex(after)<<"'"<<endl);
7,214✔
936
    emitNSEC3( r, ns3rc, unhashed, before, after, mode);
7,214✔
937
  }
7,214✔
938
}
23,318✔
939

940
void PacketHandler::addNSEC(DNSPacket& /* p */, std::unique_ptr<DNSPacket>& r, const DNSName& target, const DNSName& wildcard, int mode)
941
{
14,191✔
942
  DLOG(g_log<<"addNSEC() mode="<<mode<<" auth="<<d_sd.qname<<" target="<<target<<" wildcard="<<wildcard<<endl);
14,191✔
943

944
  if (d_sd.db == nullptr) {
14,191✔
945
    if(!B.getSOAUncached(d_sd.qname, d_sd)) {
20!
946
      DLOG(g_log<<"Could not get SOA for domain"<<endl);
×
947
      return;
×
948
    }
×
949
  }
20✔
950

951
  DNSName before,after;
14,191✔
952
  d_sd.db->getBeforeAndAfterNames(d_sd.domain_id, d_sd.qname, target, before, after);
14,191✔
953
  if (mode != 5 || before == target)
14,191✔
954
    emitNSEC(r, before, after, mode);
14,075✔
955

956
  if (mode == 2 || mode == 4) {
14,191✔
957
    // wildcard NO-DATA or wildcard denial
958
    before.clear();
4,224✔
959
    DNSName closest(wildcard);
4,224✔
960
    if (mode == 4) {
4,224✔
961
      closest.chopOff();
3,736✔
962
      closest.prependRawLabel("*");
3,736✔
963
    }
3,736✔
964
    d_sd.db->getBeforeAndAfterNames(d_sd.domain_id, d_sd.qname, closest, before, after);
4,224✔
965
    emitNSEC(r, before, after, mode);
4,224✔
966
  }
4,224✔
967
  return;
14,191✔
968
}
14,191✔
969

970
/* Semantics:
971

972
- only one backend owns the SOA of a zone
973
- only one AXFR per zone at a time - double startTransaction should fail
974
- backends need to implement transaction semantics
975

976

977
How BindBackend would implement this:
978
   startTransaction makes a file
979
   feedRecord sends everything to that file
980
   commitTransaction moves that file atomically over the regular file, and triggers a reload
981
   rollbackTransaction removes the file
982

983

984
How PostgreSQLBackend would implement this:
985
   startTransaction starts a sql transaction, which also deletes all records
986
   feedRecord is an insert statement
987
   commitTransaction commits the transaction
988
   rollbackTransaction aborts it
989

990
How MySQLBackend would implement this:
991
   (good question!)
992

993
*/
994

995
int PacketHandler::tryAutoPrimary(const DNSPacket& p, const DNSName& tsigkeyname)
996
{
4✔
997
  if(p.d_tcp)
4!
998
  {
×
999
    // do it right now if the client is TCP
1000
    // rarely happens
1001
    return tryAutoPrimarySynchronous(p, tsigkeyname);
×
1002
  }
×
1003
  else
4✔
1004
  {
4✔
1005
    // queue it if the client is on UDP
1006
    Communicator.addTryAutoPrimaryRequest(p);
4✔
1007
    return 0;
4✔
1008
  }
4✔
1009
}
4✔
1010

1011
int PacketHandler::tryAutoPrimarySynchronous(const DNSPacket& p, const DNSName& tsigkeyname)
1012
{
4✔
1013
  ComboAddress remote = p.getInnerRemote();
4✔
1014
  if(p.hasEDNSSubnet() && pdns::isAddressTrustedNotificationProxy(remote)) {
4!
1015
    remote = p.getRealRemote().getNetwork();
×
1016
  }
×
1017
  else {
4✔
1018
    remote = p.getInnerRemote();
4✔
1019
  }
4✔
1020
  remote.setPort(53);
4✔
1021

1022
  Resolver::res_t nsset;
4✔
1023
  try {
4✔
1024
    Resolver resolver;
4✔
1025
    uint32_t theirserial;
4✔
1026
    resolver.getSoaSerial(remote, p.qdomain, &theirserial);
4✔
1027
    resolver.resolve(remote, p.qdomain, QType::NS, &nsset);
4✔
1028
  }
4✔
1029
  catch(ResolverException &re) {
4✔
1030
    g_log<<Logger::Error<<"Error resolving SOA or NS for "<<p.qdomain<<" at: "<< remote <<": "<<re.reason<<endl;
×
1031
    return RCode::ServFail;
×
1032
  }
×
1033

1034
  // check if the returned records are NS records
1035
  bool haveNS=false;
4✔
1036
  for(const auto& ns: nsset) {
8✔
1037
    if(ns.qtype==QType::NS)
8!
1038
      haveNS=true;
8✔
1039
  }
8✔
1040

1041
  if(!haveNS) {
4!
1042
    g_log << Logger::Error << "While checking for autoprimary, did not find NS for " << p.qdomain << " at: " << remote << endl;
×
1043
    return RCode::ServFail;
×
1044
  }
×
1045

1046
  string nameserver, account;
4✔
1047
  DNSBackend *db;
4✔
1048

1049
  if (!::arg().mustDo("allow-unsigned-autoprimary") && tsigkeyname.empty()) {
4!
1050
    g_log << Logger::Error << "Received unsigned NOTIFY for " << p.qdomain << " from potential autoprimary " << remote << ". Refusing." << endl;
×
1051
    return RCode::Refused;
×
1052
  }
×
1053

1054
  if (!B.autoPrimaryBackend(remote.toString(), p.qdomain, nsset, &nameserver, &account, &db)) {
4✔
1055
    g_log << Logger::Error << "Unable to find backend willing to host " << p.qdomain << " for potential autoprimary " << remote << ". Remote nameservers: " << endl;
2✔
1056
    for(const auto& rr: nsset) {
4✔
1057
      if(rr.qtype==QType::NS)
4!
1058
        g_log<<Logger::Error<<rr.content<<endl;
4✔
1059
    }
4✔
1060
    return RCode::Refused;
2✔
1061
  }
2✔
1062
  try {
2✔
1063
    db->createSecondaryDomain(remote.toString(), p.qdomain, nameserver, account);
2✔
1064
    DomainInfo di;
2✔
1065
    if (!db->getDomainInfo(p.qdomain, di, false)) {
2!
1066
      g_log << Logger::Error << "Failed to create " << p.qdomain << " for potential autoprimary " << remote << endl;
×
1067
      return RCode::ServFail;
×
1068
    }
×
1069
    g_zoneCache.add(p.qdomain, di.id);
2✔
1070
    if (tsigkeyname.empty() == false) {
2✔
1071
      vector<string> meta;
1✔
1072
      meta.push_back(tsigkeyname.toStringNoDot());
1✔
1073
      db->setDomainMetadata(p.qdomain, "AXFR-MASTER-TSIG", meta);
1✔
1074
    }
1✔
1075
  }
2✔
1076
  catch(PDNSException& ae) {
2✔
1077
    g_log << Logger::Error << "Database error trying to create " << p.qdomain << " for potential autoprimary " << remote << ": " << ae.reason << endl;
×
1078
    return RCode::ServFail;
×
1079
  }
×
1080
  g_log << Logger::Warning << "Created new secondary zone '" << p.qdomain << "' from autoprimary " << remote << endl;
2✔
1081
  return RCode::NoError;
2✔
1082
}
2✔
1083

1084
int PacketHandler::processNotify(const DNSPacket& p)
1085
{
7✔
1086
  /* now what?
1087
     was this notification from an approved address?
1088
     was this notification approved by TSIG?
1089
     We determine our internal SOA id (via UeberBackend)
1090
     We determine the SOA at our (known) primary
1091
     if primary is higher -> do stuff
1092
  */
1093

1094
  g_log<<Logger::Debug<<"Received NOTIFY for "<<p.qdomain<<" from "<<p.getRemoteString()<<endl;
7✔
1095

1096
  if(!::arg().mustDo("secondary") && s_forwardNotify.empty()) {
7!
1097
    g_log << Logger::Warning << "Received NOTIFY for " << p.qdomain << " from " << p.getRemoteString() << " but secondary support is disabled in the configuration" << endl;
×
1098
    return RCode::Refused;
×
1099
  }
×
1100

1101
  // Sender verification
1102
  //
1103
  if(!s_allowNotifyFrom.match(p.getInnerRemote()) || p.d_havetsig) {
7!
1104
    if (p.d_havetsig && p.getTSIGKeyname().empty() == false) {
3!
1105
        g_log<<Logger::Notice<<"Received secure NOTIFY for "<<p.qdomain<<" from "<<p.getRemoteString()<<", with TSIG key '"<<p.getTSIGKeyname()<<"'"<<endl;
3✔
1106
    } else {
3✔
UNCOV
1107
      g_log<<Logger::Warning<<"Received NOTIFY for "<<p.qdomain<<" from "<<p.getRemoteString()<<" but the remote is not providing a TSIG key or in allow-notify-from (Refused)"<<endl;
×
UNCOV
1108
      return RCode::Refused;
×
UNCOV
1109
    }
×
1110
  }
3✔
1111

1112
  if ((!::arg().mustDo("allow-unsigned-notify") && !p.d_havetsig) || p.d_havetsig) {
7✔
1113
    if (!p.d_havetsig) {
4✔
1114
      g_log<<Logger::Warning<<"Received unsigned NOTIFY for "<<p.qdomain<<" from "<<p.getRemoteString()<<" while a TSIG key was required (Refused)"<<endl;
1✔
1115
      return RCode::Refused;
1✔
1116
    }
1✔
1117
    vector<string> meta;
3✔
1118
    if (B.getDomainMetadata(p.qdomain,"AXFR-MASTER-TSIG",meta) && meta.size() > 0) {
3!
1119
      DNSName expected{meta[0]};
1✔
1120
      if (p.getTSIGKeyname() != expected) {
1!
1121
        g_log<<Logger::Warning<<"Received secure NOTIFY for "<<p.qdomain<<" from "<<p.getRemoteString()<<": expected TSIG key '"<<expected<<"', got '"<<p.getTSIGKeyname()<<"' (Refused)"<<endl;
×
1122
        return RCode::Refused;
×
1123
      }
×
1124
    }
1✔
1125
  }
3✔
1126

1127
  // Domain verification
1128
  //
1129
  DomainInfo di;
6✔
1130
  if(!B.getDomainInfo(p.qdomain, di, false) || !di.backend) {
6!
1131
    if(::arg().mustDo("autosecondary")) {
4!
1132
      g_log << Logger::Warning << "Received NOTIFY for " << p.qdomain << " from " << p.getRemoteString() << " for which we are not authoritative, trying autoprimary" << endl;
4✔
1133
      return tryAutoPrimary(p, p.getTSIGKeyname());
4✔
1134
    }
4✔
1135
    g_log<<Logger::Notice<<"Received NOTIFY for "<<p.qdomain<<" from "<<p.getRemoteString()<<" for which we are not authoritative (Refused)"<<endl;
×
1136
    return RCode::Refused;
×
1137
  }
4✔
1138

1139
  if(pdns::isAddressTrustedNotificationProxy(p.getInnerRemote())) {
2!
1140
    if (di.primaries.empty()) {
×
1141
      g_log << Logger::Warning << "Received NOTIFY for " << p.qdomain << " from trusted-notification-proxy " << p.getRemoteString() << ", zone does not have any primaries defined (Refused)" << endl;
×
1142
      return RCode::Refused;
×
1143
    }
×
1144
    g_log<<Logger::Notice<<"Received NOTIFY for "<<p.qdomain<<" from trusted-notification-proxy "<<p.getRemoteString()<<endl;
×
1145
  }
×
1146
  else if (::arg().mustDo("primary") && di.isPrimaryType()) {
2!
1147
    g_log << Logger::Warning << "Received NOTIFY for " << p.qdomain << " from " << p.getRemoteString() << " but we are primary (Refused)" << endl;
×
1148
    return RCode::Refused;
×
1149
  }
×
1150
  else if (!di.isPrimary(p.getInnerRemote())) {
2!
1151
    g_log << Logger::Warning << "Received NOTIFY for " << p.qdomain << " from " << p.getRemoteString() << " which is not a primary (Refused)" << endl;
×
1152
    return RCode::Refused;
×
1153
  }
×
1154

1155
  if(!s_forwardNotify.empty()) {
2!
1156
    set<string> forwardNotify(s_forwardNotify);
×
1157
    for(const auto & j : forwardNotify) {
×
1158
      g_log<<Logger::Notice<<"Relaying notification of domain "<<p.qdomain<<" from "<<p.getRemoteString()<<" to "<<j<<endl;
×
1159
      Communicator.notify(p.qdomain,j);
×
1160
    }
×
1161
  }
×
1162

1163
  if(::arg().mustDo("secondary")) {
2!
1164
    g_log<<Logger::Notice<<"Received NOTIFY for "<<p.qdomain<<" from "<<p.getRemoteString()<<" - queueing check"<<endl;
2✔
1165
    di.receivedNotify = true;
2✔
1166
    Communicator.addSecondaryCheckRequest(di, p.getInnerRemote());
2✔
1167
  }
2✔
1168
  return 0;
2✔
1169
}
2✔
1170

1171
static bool validDNSName(const DNSName& name)
1172
{
101,389✔
1173
  if (!g_8bitDNS) {
101,389!
1174
    return name.has8bitBytes() == false;
101,389✔
1175
  }
101,389✔
1176
  return true;
×
1177
}
101,389✔
1178

1179
std::unique_ptr<DNSPacket> PacketHandler::question(DNSPacket& p)
1180
{
86,769✔
1181
  std::unique_ptr<DNSPacket> ret{nullptr};
86,769✔
1182

1183
  if(d_pdl)
86,769!
1184
  {
×
1185
    ret=d_pdl->prequery(p);
×
1186
    if(ret)
×
1187
      return ret;
×
1188
  }
×
1189

1190
  if(p.d.rd) {
86,769!
1191
    static AtomicCounter &rdqueries=*S.getPointer("rd-queries");
×
1192
    rdqueries++;
×
1193
  }
×
1194

1195
  return doQuestion(p);
86,769✔
1196
}
86,769✔
1197

1198

1199
void PacketHandler::makeNXDomain(DNSPacket& p, std::unique_ptr<DNSPacket>& r, const DNSName& target, const DNSName& wildcard)
1200
{
12,276✔
1201
  DNSZoneRecord rr;
12,276✔
1202
  rr=makeEditedDNSZRFromSOAData(d_dk, d_sd, DNSResourceRecord::AUTHORITY);
12,276✔
1203
  rr.dr.d_ttl=d_sd.getNegativeTTL();
12,276✔
1204
  r->addRecord(std::move(rr));
12,276✔
1205

1206
  if(d_dnssec) {
12,276✔
1207
    addNSECX(p, r, target, wildcard, 4);
9,962✔
1208
  }
9,962✔
1209

1210
  r->setRcode(RCode::NXDomain);
12,276✔
1211
}
12,276✔
1212

1213
void PacketHandler::makeNOError(DNSPacket& p, std::unique_ptr<DNSPacket>& r, const DNSName& target, const DNSName& wildcard, int mode)
1214
{
22,630✔
1215
  DNSZoneRecord rr;
22,630✔
1216
  rr=makeEditedDNSZRFromSOAData(d_dk, d_sd, DNSResourceRecord::AUTHORITY);
22,630✔
1217
  rr.dr.d_ttl=d_sd.getNegativeTTL();
22,630✔
1218
  r->addRecord(std::move(rr));
22,630✔
1219

1220
  if(d_dnssec) {
22,630✔
1221
    addNSECX(p, r, target, wildcard, mode);
19,025✔
1222
  }
19,025✔
1223

1224
  S.inc("noerror-packets");
22,630✔
1225
  S.ringAccount("noerror-queries", p.qdomain, p.qtype);
22,630✔
1226
}
22,630✔
1227

1228

1229
bool PacketHandler::addDSforNS(DNSPacket& p, std::unique_ptr<DNSPacket>& r, const DNSName& dsname)
1230
{
4,541✔
1231
  //cerr<<"Trying to find a DS for '"<<dsname<<"', domain_id = "<<d_sd.domain_id<<endl;
1232
  B.lookup(QType(QType::DS), dsname, d_sd.domain_id, &p);
4,541✔
1233
  DNSZoneRecord rr;
4,541✔
1234
  bool gotOne=false;
4,541✔
1235
  while(B.get(rr)) {
6,039✔
1236
    gotOne=true;
1,498✔
1237
    rr.dr.d_place = DNSResourceRecord::AUTHORITY;
1,498✔
1238
    r->addRecord(std::move(rr));
1,498✔
1239
  }
1,498✔
1240
  return gotOne;
4,541✔
1241
}
4,541✔
1242

1243
bool PacketHandler::tryReferral(DNSPacket& p, std::unique_ptr<DNSPacket>& r, const DNSName &target, bool retargeted)
1244
{
75,767✔
1245
  vector<DNSZoneRecord> rrset = getBestReferralNS(p, target);
75,767✔
1246
  if(rrset.empty())
75,767✔
1247
    return false;
70,305✔
1248

1249
  DNSName name = rrset.begin()->dr.d_name;
5,462✔
1250
  for(auto& rr: rrset) {
7,992✔
1251
    rr.dr.d_place=DNSResourceRecord::AUTHORITY;
7,992✔
1252
    r->addRecord(std::move(rr));
7,992✔
1253
  }
7,992✔
1254
  if(!retargeted)
5,462✔
1255
    r->setA(false);
5,212✔
1256

1257
  if(d_dk.isSecuredZone(d_sd.qname) && !addDSforNS(p, r, name) && d_dnssec) {
5,462✔
1258
    addNSECX(p, r, name, DNSName(), 1);
2,553✔
1259
  }
2,553✔
1260

1261
  return true;
5,462✔
1262
}
75,767✔
1263

1264
void PacketHandler::completeANYRecords(DNSPacket& p, std::unique_ptr<DNSPacket>& r, const DNSName &target)
1265
{
2,743✔
1266
  addNSECX(p, r, target, DNSName(), 5);
2,743✔
1267
  if(d_sd.qname == p.qdomain) {
2,743✔
1268
    if(!d_dk.isPresigned(d_sd.qname)) {
1,341✔
1269
      addDNSKEY(p, r);
1,016✔
1270
      addCDNSKEY(p, r);
1,016✔
1271
      addCDS(p, r);
1,016✔
1272
    }
1,016✔
1273
    addNSEC3PARAM(p, r);
1,341✔
1274
  }
1,341✔
1275
}
2,743✔
1276

1277
bool PacketHandler::tryDNAME(DNSPacket& p, std::unique_ptr<DNSPacket>& r, DNSName &target)
1278
{
13,743✔
1279
  if(!d_doDNAME)
13,743✔
1280
    return false;
6✔
1281
  DLOG(g_log<<Logger::Warning<<"Let's try DNAME.."<<endl);
13,737✔
1282
  vector<DNSZoneRecord> rrset;
13,737✔
1283
  try {
13,737✔
1284
    getBestDNAMESynth(p, target, rrset);
13,737✔
1285
    if(!rrset.empty()) {
13,737✔
1286
      for(size_t i = 0; i < rrset.size(); i++) {
2,652✔
1287
        rrset.at(i).dr.d_place = DNSResourceRecord::ANSWER;
1,768✔
1288
        r->addRecord(std::move(rrset.at(i)));
1,768✔
1289
      }
1,768✔
1290
      return true;
884✔
1291
    }
884✔
1292
  } catch (const std::range_error &e) {
13,737✔
1293
    // Add the DNAME regardless, but throw to let the caller know we could not
1294
    // synthesize a CNAME
1295
    if(!rrset.empty()) {
352!
1296
      for(size_t i = 0; i < rrset.size(); i++) {
704✔
1297
        rrset.at(i).dr.d_place = DNSResourceRecord::ANSWER;
352✔
1298
        r->addRecord(std::move(rrset.at(i)));
352✔
1299
      }
352✔
1300
    }
352✔
1301
    throw e;
352✔
1302
  }
352✔
1303
  return false;
12,501✔
1304
}
13,737✔
1305
bool PacketHandler::tryWildcard(DNSPacket& p, std::unique_ptr<DNSPacket>& r, DNSName &target, DNSName &wildcard, bool& retargeted, bool& nodata)
1306
{
21,179✔
1307
  retargeted = nodata = false;
21,179✔
1308
  DNSName bestmatch;
21,179✔
1309

1310
  vector<DNSZoneRecord> rrset;
21,179✔
1311
  if(!getBestWildcard(p, target, wildcard, &rrset))
21,179✔
1312
    return false;
13,743✔
1313

1314
  if(rrset.empty()) {
7,436✔
1315
    DLOG(g_log<<"Wildcard matched something, but not of the correct type"<<endl);
1,740✔
1316
    nodata=true;
1,740✔
1317
  }
1,740✔
1318
  else {
5,696✔
1319
    bestmatch = target;
5,696✔
1320
    for(auto& rr: rrset) {
5,696✔
1321
      rr.wildcardname = rr.dr.d_name;
5,696✔
1322
      rr.dr.d_name = bestmatch;
5,696✔
1323

1324
      if(rr.dr.d_type == QType::CNAME)  {
5,696✔
1325
        retargeted=true;
2,388✔
1326
        target=getRR<CNAMERecordContent>(rr.dr)->getTarget();
2,388✔
1327
      }
2,388✔
1328

1329
      rr.dr.d_place=DNSResourceRecord::ANSWER;
5,696✔
1330
      r->addRecord(std::move(rr));
5,696✔
1331
    }
5,696✔
1332
  }
5,696✔
1333
  if(d_dnssec && !nodata) {
7,436✔
1334
    addNSECX(p, r, bestmatch, wildcard, 3);
4,713✔
1335
  }
4,713✔
1336

1337
  return true;
7,436✔
1338
}
21,179✔
1339

1340
//! Called by the Distributor to ask a question. Returns 0 in case of an error
1341
// NOLINTNEXTLINE(readability-function-cognitive-complexity): TODO Clean this function up.
1342
std::unique_ptr<DNSPacket> PacketHandler::doQuestion(DNSPacket& p)
1343
{
101,456✔
1344
  DNSZoneRecord rr;
101,456✔
1345

1346
  int retargetcount=0;
101,456✔
1347
  set<DNSName> authSet;
101,456✔
1348

1349
  vector<DNSZoneRecord> rrset;
101,456✔
1350
  bool weDone=false, weRedirected=false, weHaveUnauth=false, doSigs=false;
101,456✔
1351
  DNSName haveAlias;
101,456✔
1352
  uint8_t aliasScopeMask;
101,456✔
1353

1354
  std::unique_ptr<DNSPacket> r{nullptr};
101,456✔
1355
  bool noCache=false;
101,456✔
1356

1357
#ifdef HAVE_LUA_RECORDS
101,456✔
1358
  bool doLua=g_doLuaRecord;
101,456✔
1359
#endif
101,456✔
1360

1361
  if(p.d.qr) { // QR bit from dns packet (thanks RA from N)
101,456!
1362
    if(d_logDNSDetails)
×
1363
      g_log<<Logger::Error<<"Received an answer (non-query) packet from "<<p.getRemoteString()<<", dropping"<<endl;
×
1364
    S.inc("corrupt-packets");
×
1365
    S.ringAccount("remotes-corrupt", p.getInnerRemote());
×
1366
    return nullptr;
×
1367
  }
×
1368

1369
  if(p.d.tc) { // truncated query. MOADNSParser would silently parse this packet in an incomplete way.
101,456!
1370
    if(d_logDNSDetails)
×
1371
      g_log<<Logger::Error<<"Received truncated query packet from "<<p.getRemoteString()<<", dropping"<<endl;
×
1372
    S.inc("corrupt-packets");
×
1373
    S.ringAccount("remotes-corrupt", p.getInnerRemote());
×
1374
    return nullptr;
×
1375
  }
×
1376

1377
  if (p.hasEDNS()) {
101,456✔
1378
    if(p.getEDNSVersion() > 0) {
93,236✔
1379
      r = p.replyPacket();
1✔
1380

1381
      // PacketWriter::addOpt will take care of setting this correctly in the packet
1382
      r->setEDNSRcode(ERCode::BADVERS);
1✔
1383
      return r;
1✔
1384
    }
1✔
1385
    if (p.hasEDNSCookie()) {
93,235!
1386
      if (!p.hasWellFormedEDNSCookie()) {
×
1387
        r = p.replyPacket();
×
1388
        r->setRcode(RCode::FormErr);
×
1389
        return r;
×
1390
      }
×
1391
      if (!p.hasValidEDNSCookie() && !p.d_tcp) {
×
1392
        r = p.replyPacket();
×
1393
        r->setEDNSRcode(ERCode::BADCOOKIE);
×
1394
        return r;
×
1395
      }
×
1396
    }
×
1397
  }
93,235✔
1398

1399
  if(p.d_havetsig) {
101,455✔
1400
    DNSName tsigkeyname;
15✔
1401
    string secret;
15✔
1402
    TSIGRecordContent trc;
15✔
1403
    if (!checkForCorrectTSIG(p, &tsigkeyname, &secret, &trc)) {
15!
1404
      r=p.replyPacket();  // generate an empty reply packet
×
1405
      if(d_logDNSDetails)
×
1406
        g_log<<Logger::Error<<"Received a TSIG signed message with a non-validating key"<<endl;
×
1407
      // RFC3007 describes that a non-secure message should be sending Refused for DNS Updates
1408
      if (p.d.opcode == Opcode::Update)
×
1409
        r->setRcode(RCode::Refused);
×
1410
      else
×
1411
        r->setRcode(RCode::NotAuth);
×
1412
      return r;
×
1413
    } else {
15✔
1414
      getTSIGHashEnum(trc.d_algoName, p.d_tsig_algo);
15✔
1415
#ifdef ENABLE_GSS_TSIG
15✔
1416
      if (g_doGssTSIG && p.d_tsig_algo == TSIG_GSS) {
15!
1417
        GssContext gssctx(tsigkeyname);
×
1418
        if (!gssctx.getPeerPrincipal(p.d_peer_principal)) {
×
1419
          g_log<<Logger::Warning<<"Failed to extract peer principal from GSS context with keyname '"<<tsigkeyname<<"'"<<endl;
×
1420
        }
×
1421
      }
×
1422
#endif
15✔
1423
    }
15✔
1424
    p.setTSIGDetails(trc, tsigkeyname, secret, trc.d_mac); // this will get copied by replyPacket()
15✔
1425
    noCache=true;
15✔
1426
  }
15✔
1427

1428
  r=p.replyPacket();  // generate an empty reply packet, possibly with TSIG details inside
101,455✔
1429

1430
  if (p.qtype == QType::TKEY) {
101,455✔
1431
    this->tkeyHandler(p, r);
67✔
1432
    return r;
67✔
1433
  }
67✔
1434

1435
  try {
101,388✔
1436

1437
    // XXX FIXME do this in DNSPacket::parse ?
1438

1439
    if(!validDNSName(p.qdomain)) {
101,388!
1440
      if(d_logDNSDetails)
×
1441
        g_log<<Logger::Error<<"Received a malformed qdomain from "<<p.getRemoteString()<<", '"<<p.qdomain<<"': sending servfail"<<endl;
×
1442
      S.inc("corrupt-packets");
×
1443
      S.ringAccount("remotes-corrupt", p.getInnerRemote());
×
1444
      S.inc("servfail-packets");
×
1445
      r->setRcode(RCode::ServFail);
×
1446
      return r;
×
1447
    }
×
1448
    if(p.d.opcode) { // non-zero opcode (again thanks RA!)
101,388✔
1449
      if(p.d.opcode==Opcode::Update) {
1,259✔
1450
        S.inc("dnsupdate-queries");
1,252✔
1451
        int res=processUpdate(p);
1,252✔
1452
        if (res == RCode::Refused)
1,252✔
1453
          S.inc("dnsupdate-refused");
24✔
1454
        else if (res != RCode::ServFail)
1,228!
1455
          S.inc("dnsupdate-answers");
1,228✔
1456
        r->setRcode(res);
1,252✔
1457
        r->setOpcode(Opcode::Update);
1,252✔
1458
        return r;
1,252✔
1459
      }
1,252✔
1460
      else if(p.d.opcode==Opcode::Notify) {
7!
1461
        S.inc("incoming-notifications");
7✔
1462
        int res=processNotify(p);
7✔
1463
        if(res>=0) {
7!
1464
          r->setRcode(res);
7✔
1465
          r->setOpcode(Opcode::Notify);
7✔
1466
          return r;
7✔
1467
        }
7✔
1468
        return nullptr;
×
1469
      }
7✔
1470

1471
      g_log<<Logger::Error<<"Received an unknown opcode "<<p.d.opcode<<" from "<<p.getRemoteString()<<" for "<<p.qdomain<<endl;
×
1472

1473
      r->setRcode(RCode::NotImp);
×
1474
      return r;
×
1475
    }
1,259✔
1476

1477
    // g_log<<Logger::Warning<<"Query for '"<<p.qdomain<<"' "<<p.qtype.toString()<<" from "<<p.getRemoteString()<< " (tcp="<<p.d_tcp<<")"<<endl;
1478

1479
    if(p.qtype.getCode()==QType::IXFR) {
100,129!
1480
      r->setRcode(RCode::Refused);
×
1481
      return r;
×
1482
    }
×
1483

1484
    DNSName target=p.qdomain;
100,129✔
1485

1486
    // catch chaos qclass requests
1487
    if(p.qclass == QClass::CHAOS) {
100,129!
1488
      if (doChaosRequest(p,r,target))
×
1489
        goto sendit;
×
1490
      else
×
1491
        return r;
×
1492
    }
×
1493

1494
    // we only know about qclass IN (and ANY), send Refused for everything else.
1495
    if(p.qclass != QClass::IN && p.qclass!=QClass::ANY) {
100,129!
1496
      r->setRcode(RCode::Refused);
×
1497
      return r;
×
1498
    }
×
1499

1500
    // send TC for udp ANY query if any-to-tcp is enabled.
1501
    if(p.qtype.getCode() == QType::ANY && !p.d_tcp && g_anyToTcp) {
100,129✔
1502
      r->d.tc = 1;
1,926✔
1503
      r->commitD();
1,926✔
1504
      return r;
1,926✔
1505
    }
1,926✔
1506

1507
    // for qclass ANY the response should never be authoritative unless the response covers all classes.
1508
    if(p.qclass==QClass::ANY)
98,203!
1509
      r->setA(false);
×
1510

1511

1512
  retargeted:;
109,721✔
1513
    if(retargetcount > 10) {    // XXX FIXME, retargetcount++?
109,721✔
1514
      g_log<<Logger::Warning<<"Abort CNAME chain resolution after "<<--retargetcount<<" redirects, sending out servfail. Initial query: '"<<p.qdomain<<"'"<<endl;
299✔
1515
      r=p.replyPacket();
299✔
1516
      r->setRcode(RCode::ServFail);
299✔
1517
      return r;
299✔
1518
    }
299✔
1519

1520
    if (retargetcount > 0 && !d_doResolveAcrossZones && !target.isPartOf(r->qdomainzone)) {
109,422!
1521
      // We are following a retarget outside the initial zone (and do not need to check getAuth to know this). Config asked us not to do that.
1522
      // This is a performance optimization, the generic case is checked after getAuth below.
1523
      goto sendit;  // NOLINT(cppcoreguidelines-avoid-goto)
×
1524
    }
×
1525

1526
    if(!B.getAuth(target, p.qtype, &d_sd)) {
109,422✔
1527
      DLOG(g_log<<Logger::Error<<"We have no authority over zone '"<<target<<"'"<<endl);
2,494✔
1528
      if(!retargetcount) {
2,494✔
1529
        r->setA(false); // drop AA if we never had a SOA in the first place
687✔
1530
        r->setRcode(RCode::Refused); // send REFUSED - but only on empty 'no idea'
687✔
1531
      }
687✔
1532
      goto sendit;
2,494✔
1533
    }
2,494✔
1534
    DLOG(g_log<<Logger::Error<<"We have authority, zone='"<<d_sd.qname<<"', id="<<d_sd.domain_id<<endl);
106,928✔
1535

1536
    if (retargetcount == 0) {
106,928✔
1537
      r->qdomainzone = d_sd.qname;
97,517✔
1538
    } else if (!d_doResolveAcrossZones && r->qdomainzone != d_sd.qname) {
97,517!
1539
      // We are following a retarget outside the initial zone. Config asked us not to do that.
1540
      goto sendit;  // NOLINT(cppcoreguidelines-avoid-goto)
×
1541
    }
×
1542

1543
    authSet.insert(d_sd.qname);
106,928✔
1544
    d_dnssec=(p.d_dnssecOk && d_dk.isSecuredZone(d_sd.qname));
106,928✔
1545
    doSigs |= d_dnssec;
106,928✔
1546

1547
    if(d_sd.qname==p.qdomain) {
106,928✔
1548
      if(!d_dk.isPresigned(d_sd.qname)) {
39,963✔
1549
        if(p.qtype.getCode() == QType::DNSKEY)
35,197✔
1550
        {
19,575✔
1551
          if(addDNSKEY(p, r))
19,575✔
1552
            goto sendit;
19,045✔
1553
        }
19,575✔
1554
        else if(p.qtype.getCode() == QType::CDNSKEY)
15,622✔
1555
        {
480✔
1556
          if(addCDNSKEY(p,r))
480!
1557
            goto sendit;
480✔
1558
        }
480✔
1559
        else if(p.qtype.getCode() == QType::CDS)
15,142✔
1560
        {
485✔
1561
          if(addCDS(p,r))
485✔
1562
            goto sendit;
484✔
1563
        }
485✔
1564
      }
35,197✔
1565
      if(p.qtype.getCode() == QType::NSEC3PARAM)
19,954✔
1566
      {
891✔
1567
        if(addNSEC3PARAM(p,r))
891✔
1568
          goto sendit;
450✔
1569
      }
891✔
1570
    }
19,954✔
1571

1572
    if(p.qtype.getCode() == QType::SOA && d_sd.qname==p.qdomain) {
86,469✔
1573
      rr=makeEditedDNSZRFromSOAData(d_dk, d_sd);
1,043✔
1574
      r->addRecord(std::move(rr));
1,043✔
1575
      goto sendit;
1,043✔
1576
    }
1,043✔
1577

1578
    // this TRUMPS a cname!
1579
    if(d_dnssec && p.qtype.getCode() == QType::NSEC && !d_dk.getNSEC3PARAM(d_sd.qname, nullptr)) {
85,426✔
1580
      addNSEC(p, r, target, DNSName(), 5);
236✔
1581
      if (!r->isEmpty())
236✔
1582
        goto sendit;
160✔
1583
    }
236✔
1584

1585
    // this TRUMPS a cname!
1586
    if(p.qtype.getCode() == QType::RRSIG) {
85,266✔
1587
      g_log<<Logger::Info<<"Direct RRSIG query for "<<target<<" from "<<p.getRemoteString()<<endl;
544✔
1588
      r->setRcode(RCode::Refused);
544✔
1589
      goto sendit;
544✔
1590
    }
544✔
1591

1592
    DLOG(g_log<<"Checking for referrals first, unless this is a DS query"<<endl);
84,722✔
1593
    if(p.qtype.getCode() != QType::DS && tryReferral(p, r, target, retargetcount))
84,722✔
1594
      goto sendit;
4,429✔
1595

1596
    DLOG(g_log<<"Got no referrals, trying ANY"<<endl);
80,293✔
1597

1598
#ifdef HAVE_LUA_RECORDS
80,293✔
1599
    if(!doLua) {
80,293!
1600
      string val;
80,293✔
1601
      d_dk.getFromMeta(d_sd.qname, "ENABLE-LUA-RECORDS", val);
80,293✔
1602
      doLua = (val=="1");
80,293✔
1603
    }
80,293✔
1604
#endif
80,293✔
1605

1606
    // see what we get..
1607
    B.lookup(QType(QType::ANY), target, d_sd.domain_id, &p);
80,293✔
1608
    rrset.clear();
80,293✔
1609
    haveAlias.clear();
80,293✔
1610
    aliasScopeMask = 0;
80,293✔
1611
    weDone = weRedirected = weHaveUnauth =  false;
80,293✔
1612

1613
    while(B.get(rr)) {
285,220✔
1614
#ifdef HAVE_LUA_RECORDS
204,927✔
1615
      if (rr.dr.d_type == QType::LUA && !d_dk.isPresigned(d_sd.qname)) {
204,927!
1616
        if(!doLua)
×
1617
          continue;
×
1618
        auto rec=getRR<LUARecordContent>(rr.dr);
×
1619
        if (!rec) {
×
1620
          continue;
×
1621
        }
×
1622
        if(rec->d_type == QType::CNAME || rec->d_type == p.qtype.getCode() || (p.qtype.getCode() == QType::ANY && rec->d_type != QType::RRSIG)) {
×
1623
          noCache=true;
×
1624
          try {
×
1625
            auto recvec=luaSynth(rec->getCode(), target, d_sd.qname, d_sd.domain_id, p, rec->d_type, s_LUA);
×
1626
            if(!recvec.empty()) {
×
1627
              for (const auto& r_it : recvec) {
×
1628
                rr.dr.d_type = rec->d_type; // might be CNAME
×
1629
                rr.dr.setContent(r_it);
×
1630
                rr.scopeMask = p.getRealRemote().getBits(); // this makes sure answer is a specific as your question
×
1631
                rrset.push_back(rr);
×
1632
              }
×
1633
              if(rec->d_type == QType::CNAME && p.qtype.getCode() != QType::CNAME)
×
1634
                weRedirected = true;
×
1635
              else
×
1636
                weDone = true;
×
1637
            }
×
1638
          }
×
1639
          catch(std::exception &e) {
×
1640
            B.lookupEnd();              // don't leave DB handle in bad state
×
1641

1642
            r=p.replyPacket();
×
1643
            r->setRcode(RCode::ServFail);
×
1644

1645
            return r;
×
1646
          }
×
1647
        }
×
1648
      }
×
1649
#endif
204,927✔
1650
      //cerr<<"got content: ["<<rr.content<<"]"<<endl;
1651
      if (!d_dnssec && p.qtype.getCode() == QType::ANY && (rr.dr.d_type == QType:: DNSKEY || rr.dr.d_type == QType::NSEC3PARAM))
204,927!
1652
        continue; // Don't send dnssec info.
×
1653
      if (rr.dr.d_type == QType::RRSIG) // RRSIGS are added later any way.
204,927✔
1654
        continue; // TODO: this actually means addRRSig should check if the RRSig is already there
37,945✔
1655

1656
      // cerr<<"Auth: "<<rr.auth<<", "<<(rr.dr.d_type == p.qtype)<<", "<<rr.dr.d_type.toString()<<endl;
1657
      if((p.qtype.getCode() == QType::ANY || rr.dr.d_type == p.qtype.getCode()) && rr.auth)
166,982✔
1658
        weDone=true;
65,076✔
1659
      // the line below fakes 'unauth NS' for delegations for non-DNSSEC backends.
1660
      if((rr.dr.d_type == p.qtype.getCode() && !rr.auth) || (rr.dr.d_type == QType::NS && (!rr.auth || !(d_sd.qname==rr.dr.d_name))))
166,982✔
1661
        weHaveUnauth=true;
3,491✔
1662

1663
      if(rr.dr.d_type == QType::CNAME && p.qtype.getCode() != QType::CNAME)
166,982✔
1664
        weRedirected=true;
8,245✔
1665

1666
      if (DP && rr.dr.d_type == QType::ALIAS && (p.qtype.getCode() == QType::A || p.qtype.getCode() == QType::AAAA || p.qtype.getCode() == QType::ANY) && !d_dk.isPresigned(d_sd.qname)) {
166,982!
1667
        if (!d_doExpandALIAS) {
301!
1668
          g_log<<Logger::Info<<"ALIAS record found for "<<target<<", but ALIAS expansion is disabled."<<endl;
×
1669
          continue;
×
1670
        }
×
1671
        haveAlias=getRR<ALIASRecordContent>(rr.dr)->getContent();
301✔
1672
        aliasScopeMask=rr.scopeMask;
301✔
1673
      }
301✔
1674

1675
      // Filter out all SOA's and add them in later
1676
      if(rr.dr.d_type == QType::SOA)
166,982✔
1677
        continue;
18,235✔
1678

1679
      rrset.push_back(rr);
148,747✔
1680
    }
148,747✔
1681

1682
    /* Add in SOA if required */
1683
    if(target==d_sd.qname) {
80,293✔
1684
        rr=makeEditedDNSZRFromSOAData(d_dk, d_sd);
18,229✔
1685
        rrset.push_back(rr);
18,229✔
1686
    }
18,229✔
1687

1688

1689
    DLOG(g_log<<"After first ANY query for '"<<target<<"', id="<<d_sd.domain_id<<": weDone="<<weDone<<", weHaveUnauth="<<weHaveUnauth<<", weRedirected="<<weRedirected<<", haveAlias='"<<haveAlias<<"'"<<endl);
80,293✔
1690
    if(p.qtype.getCode() == QType::DS && weHaveUnauth &&  !weDone && !weRedirected) {
80,293!
1691
      DLOG(g_log<<"Q for DS of a name for which we do have NS, but for which we don't have DS; need to provide an AUTH answer that shows we don't"<<endl);
847✔
1692
      makeNOError(p, r, target, DNSName(), 1);
847✔
1693
      goto sendit;
847✔
1694
    }
847✔
1695

1696
    if(!haveAlias.empty() && (!weDone || p.qtype.getCode() == QType::ANY)) {
79,446!
1697
      DLOG(g_log<<Logger::Warning<<"Found nothing that matched for '"<<target<<"', but did get alias to '"<<haveAlias<<"', referring"<<endl);
301✔
1698
      DP->completePacket(r, haveAlias, target, aliasScopeMask);
301✔
1699
      return nullptr;
301✔
1700
    }
301✔
1701

1702

1703
    // referral for DS query
1704
    if(p.qtype.getCode() == QType::DS) {
79,145✔
1705
      DLOG(g_log<<"Qtype is DS"<<endl);
9,588✔
1706
      bool doReferral = true;
9,588✔
1707
      if(d_dk.doesDNSSEC()) {
9,588✔
1708
        for(auto& loopRR: rrset) {
9,539✔
1709
          // In a dnssec capable backend auth=true means, there is no delegation at
1710
          // or above this qname in this zone (for DS queries). Without a delegation,
1711
          // at or above this level, it is pointless to search for referrals.
1712
          if(loopRR.auth) {
9,264✔
1713
            doReferral = false;
8,016✔
1714
            break;
8,016✔
1715
          }
8,016✔
1716
        }
9,264✔
1717
      } else {
9,357✔
1718
        for(auto& loopRR: rrset) {
408✔
1719
          // In a non dnssec capable backend auth is always true, so our only option
1720
          // is, always look for referrals. Unless there is a direct match for DS.
1721
          if(loopRR.dr.d_type == QType::DS) {
408✔
1722
            doReferral = false;
96✔
1723
            break;
96✔
1724
          }
96✔
1725
        }
408✔
1726
      }
314✔
1727
      if(doReferral) {
9,588✔
1728
        DLOG(g_log<<"DS query found no direct result, trying referral now"<<endl);
1,476✔
1729
        if(tryReferral(p, r, target, retargetcount))
1,476✔
1730
        {
1,033✔
1731
          DLOG(g_log<<"Got referral for DS query"<<endl);
1,033✔
1732
          goto sendit;
1,033✔
1733
        }
1,033✔
1734
      }
1,476✔
1735
    }
9,588✔
1736

1737

1738
    if(rrset.empty()) {
78,112✔
1739
      DLOG(g_log<<Logger::Warning<<"Found nothing in the by-name ANY, but let's try wildcards.."<<endl);
21,179✔
1740
      bool wereRetargeted(false), nodata(false);
21,179✔
1741
      DNSName wildcard;
21,179✔
1742
      if(tryWildcard(p, r, target, wildcard, wereRetargeted, nodata)) {
21,179✔
1743
        if(wereRetargeted) {
7,436✔
1744
          if(!retargetcount) r->qdomainwild=wildcard;
2,388✔
1745
          retargetcount++;
2,388✔
1746
          goto retargeted;
2,388✔
1747
        }
2,388✔
1748
        if(nodata)
5,048✔
1749
          makeNOError(p, r, target, wildcard, 2);
1,740✔
1750

1751
        goto sendit;
5,048✔
1752
      }
7,436✔
1753
      try {
13,743✔
1754
        if (tryDNAME(p, r, target)) {
13,743✔
1755
          retargetcount++;
884✔
1756
          goto retargeted;
884✔
1757
        }
884✔
1758
      } catch (const std::range_error &e) {
13,743✔
1759
        // We couldn't make a CNAME.....
1760
        r->setRcode(RCode::YXDomain);
352✔
1761
        goto sendit;
352✔
1762
      }
352✔
1763

1764
      if (!(((p.qtype.getCode() == QType::CNAME) || (p.qtype.getCode() == QType::ANY)) && retargetcount > 0))
12,507✔
1765
        makeNXDomain(p, r, target, wildcard);
12,276✔
1766

1767
      goto sendit;
12,507✔
1768
    }
13,743✔
1769

1770
    if(weRedirected) {
56,933✔
1771
      for(auto& loopRR: rrset) {
8,245!
1772
        if(loopRR.dr.d_type == QType::CNAME) {
8,245!
1773
          r->addRecord(DNSZoneRecord(loopRR));
8,245✔
1774
          target = getRR<CNAMERecordContent>(loopRR.dr)->getTarget();
8,245✔
1775
          retargetcount++;
8,245✔
1776
          goto retargeted;
8,245✔
1777
        }
8,245✔
1778
      }
8,245✔
1779
    }
8,245✔
1780
    else if(weDone) {
48,688✔
1781
      bool haveRecords = false;
29,230✔
1782
      bool presigned = d_dk.isPresigned(d_sd.qname);
29,230✔
1783
      for(const auto& loopRR: rrset) {
97,941✔
1784
        if (loopRR.dr.d_type == QType::ENT) {
97,941✔
1785
          continue;
589✔
1786
        }
589✔
1787
        if (loopRR.dr.d_type == QType::ALIAS && d_doExpandALIAS && !presigned) {
97,352!
1788
          continue;
×
1789
        }
×
1790
#ifdef HAVE_LUA_RECORDS
97,352✔
1791
        if (loopRR.dr.d_type == QType::LUA && !presigned) {
97,352!
1792
          continue;
×
1793
        }
×
1794
#endif
97,352✔
1795
        if ((p.qtype.getCode() == QType::ANY || loopRR.dr.d_type == p.qtype.getCode()) && loopRR.auth) {
97,352✔
1796
          r->addRecord(DNSZoneRecord(loopRR));
64,025✔
1797
          haveRecords = true;
64,025✔
1798
        }
64,025✔
1799
      }
97,352✔
1800

1801
      if (haveRecords) {
29,230✔
1802
        if(d_dnssec && p.qtype.getCode() == QType::ANY)
28,641✔
1803
          completeANYRecords(p, r, target);
2,743✔
1804
      }
28,641✔
1805
      else
589✔
1806
        makeNOError(p, r, target, DNSName(), 0);
589✔
1807

1808
      goto sendit;
29,230✔
1809
    }
29,230✔
1810
    else if(weHaveUnauth) {
19,458✔
1811
      DLOG(g_log<<"Have unauth data, so need to hunt for best NS records"<<endl);
4✔
1812
      if(tryReferral(p, r, target, retargetcount))
4!
1813
        goto sendit;
×
1814
      // check whether this could be fixed easily
1815
      // if (*(rr.dr.d_name.rbegin()) == '.') {
1816
      //      g_log<<Logger::Error<<"Should not get here ("<<p.qdomain<<"|"<<p.qtype.toString()<<"): you have a trailing dot, this could be the problem (or run pdnsutil rectify-zone " <<d_sd.qname<<")"<<endl;
1817
      // } else {
1818
           g_log<<Logger::Error<<"Should not get here ("<<p.qdomain<<"|"<<p.qtype.toString()<<"): please run pdnsutil rectify-zone "<<d_sd.qname<<endl;
4✔
1819
      // }
1820
    }
4✔
1821
    else {
19,454✔
1822
      DLOG(g_log<<"Have some data, but not the right data"<<endl);
19,454✔
1823
      makeNOError(p, r, target, DNSName(), 0);
19,454✔
1824
    }
19,454✔
1825

1826
  sendit:;
97,604✔
1827
    doAdditionalProcessing(p, r);
97,604✔
1828

1829
    for(const auto& loopRR: r->getRRS()) {
257,018✔
1830
      if(loopRR.scopeMask) {
257,007✔
1831
        noCache=true;
214✔
1832
        break;
214✔
1833
      }
214✔
1834
    }
257,007✔
1835
    if(doSigs)
97,604✔
1836
      addRRSigs(d_dk, B, authSet, r->getRRS(), &p);
79,810✔
1837

1838
    if(PC.enabled() && !noCache && p.couldBeCached())
97,604!
1839
      PC.insert(p, *r, r->getMinTTL()); // in the packet cache
14,568✔
1840
  }
97,604✔
1841
  catch(const DBException &e) {
101,388✔
1842
    g_log<<Logger::Error<<"Backend reported condition which prevented lookup ("+e.reason+") sending out servfail"<<endl;
×
1843
    r=p.replyPacket(); // generate an empty reply packet
×
1844
    r->setRcode(RCode::ServFail);
×
1845
    S.inc("servfail-packets");
×
1846
    S.ringAccount("servfail-queries", p.qdomain, p.qtype);
×
1847
  }
×
1848
  catch(const PDNSException &e) {
101,388✔
1849
    g_log<<Logger::Error<<"Backend reported permanent error which prevented lookup ("+e.reason+"), aborting"<<endl;
×
1850
    throw; // we WANT to die at this point
×
1851
  }
×
1852
  catch(const std::exception &e) {
101,388✔
1853
    g_log<<Logger::Error<<"Exception building answer packet for "<<p.qdomain<<"/"<<p.qtype.toString()<<" ("<<e.what()<<") sending out servfail"<<endl;
×
1854
    r=p.replyPacket(); // generate an empty reply packet
×
1855
    r->setRcode(RCode::ServFail);
×
1856
    S.inc("servfail-packets");
×
1857
    S.ringAccount("servfail-queries", p.qdomain, p.qtype);
×
1858
  }
×
1859
  return r;
97,604✔
1860

1861
}
101,388✔
1862

1863
bool PacketHandler::checkForCorrectTSIG(const DNSPacket& packet, DNSName* tsigkeyname, string* secret, TSIGRecordContent* tsigContent)
1864
{
230✔
1865
  uint16_t tsigPos{0};
230✔
1866

1867
  if (!packet.getTSIGDetails(tsigContent, tsigkeyname, &tsigPos)) {
230!
1868
    return false;
×
1869
  }
×
1870

1871
  TSIGTriplet tsigTriplet;
230✔
1872
  tsigTriplet.name = *tsigkeyname;
230✔
1873
  tsigTriplet.algo = tsigContent->d_algoName;
230✔
1874
  if (tsigTriplet.algo == DNSName("hmac-md5.sig-alg.reg.int")) {
230✔
1875
    tsigTriplet.algo = DNSName("hmac-md5");
166✔
1876
  }
166✔
1877

1878
  if (tsigTriplet.algo != DNSName("gss-tsig")) {
230!
1879
    string secret64;
230✔
1880
    if (!B.getTSIGKey(*tsigkeyname, tsigTriplet.algo, secret64)) {
230!
1881
      g_log << Logger::Error << "Packet for domain '" << packet.qdomain << "' denied: can't find TSIG key with name '" << *tsigkeyname << "' and algorithm '" << tsigTriplet.algo << "'" << endl;
×
1882
      return false;
×
1883
    }
×
1884
    B64Decode(secret64, *secret);
230✔
1885
    tsigTriplet.secret = *secret;
230✔
1886
  }
230✔
1887

1888
  try {
230✔
1889
    return packet.validateTSIG(tsigTriplet, *tsigContent, "", tsigContent->d_mac, false);
230✔
1890
  }
230✔
1891
  catch(const std::runtime_error& err) {
230✔
1892
    g_log<<Logger::Error<<"Packet for '"<<packet.qdomain<<"' denied: "<<err.what()<<endl;
128✔
1893
    return false;
128✔
1894
  }
128✔
1895
}
230✔
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