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

PowerDNS / pdns / 11049952298

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

Pull #14594

github

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

37040 of 87934 branches covered (42.12%)

Branch coverage included in aggregate %.

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

53 existing lines in 14 files now uncovered.

124664 of 161993 relevant lines covered (76.96%)

4875762.83 hits per line

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

72.31
/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 "version.hh"
47
#include "auth-main.hh"
48
#include "trusted-notification-proxy.hh"
49
#include "gss_context.hh"
50
#include "stubresolver.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_logDNSDetails= ::arg().mustDo("log-dns-details");
714✔
74
  string fname= ::arg()["lua-prequery-script"];
714✔
75

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

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

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

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

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

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

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

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

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

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

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

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

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

199
  return haveOne;
20,663✔
200
}
20,663✔
201

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

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

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

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

232
  bool haveOne=false;
787✔
233

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

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

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

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

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

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

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

279

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

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

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

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

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

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

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

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

378
  } while( subdomain.chopOff() );   // 'www.powerdns.org' -> 'powerdns.org' -> 'org' -> ''
46,425✔
379
  return;
12,848✔
380
}
13,732✔
381

382

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

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

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

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

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

445
            throw;
×
446
          }
×
447
        }
×
448
      }
×
449
      else
9,267✔
450
#endif
9,267✔
451
      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,267✔
452
        if (rr.dr.d_type == QType::CNAME) {
5,883✔
453
          haveCNAME = true;
2,388✔
454
          ret->clear();
2,388✔
455
        }
2,388✔
456
        ret->push_back(rr);
5,883✔
457
      }
5,883✔
458

459
      wildcard=g_wildcarddnsname+subdomain;
9,267✔
460
      haveSomething=true;
9,267✔
461
    }
9,267✔
462

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

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

475
  return haveSomething;
21,174✔
476
}
21,174✔
477

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

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

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

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

515

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

725
  DNSZoneRecord rr;
38,642✔
726

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

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

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

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

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

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

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

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

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

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

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

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

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

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

881
    getNSEC3Hashes(narrow, hashed, false, unhashed, before, after, mode);
20,155✔
882

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

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

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

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

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

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

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

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

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

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

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

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

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

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

969
/* Semantics:
970

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

975

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

982

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

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

992
*/
993

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

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

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

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

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

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

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

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

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

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

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

1100
  // Sender verification
1101
  //
1102
  if(!s_allowNotifyFrom.match(p.getInnerRemote()) || p.d_havetsig) {
7!
1103
    if (p.d_havetsig && p.getTSIGKeyname().empty() == false) {
3!
1104
        g_log<<Logger::Notice<<"Received secure NOTIFY for "<<p.qdomain<<" from "<<p.getRemoteString()<<", with TSIG key '"<<p.getTSIGKeyname()<<"'"<<endl;
3✔
1105
    } else {
3✔
1106
      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;
×
1107
      return RCode::Refused;
×
1108
    }
×
1109
  }
3✔
1110

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

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

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

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

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

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

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

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

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

1194
  return doQuestion(p);
86,870✔
1195
}
86,870✔
1196

1197

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

1205
  if(d_dnssec) {
12,271✔
1206
    addNSECX(p, r, target, wildcard, 4);
9,961✔
1207
  }
9,961✔
1208

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

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

1219
  if(d_dnssec) {
22,666✔
1220
    addNSECX(p, r, target, wildcard, mode);
19,061✔
1221
  }
19,061✔
1222

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

1227

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

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

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

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

1260
  return true;
5,462✔
1261
}
75,760✔
1262

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

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

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

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

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

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

1336
  return true;
7,436✔
1337
}
21,174✔
1338

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

1345
  int retargetcount=0;
101,557✔
1346
  set<DNSName> authSet;
101,557✔
1347

1348
  vector<DNSZoneRecord> rrset;
101,557✔
1349
  bool weDone=false, weRedirected=false, weHaveUnauth=false, doSigs=false;
101,557✔
1350

1351
  std::unique_ptr<DNSPacket> r{nullptr};
101,557✔
1352
  bool noCache=false;
101,557✔
1353

1354
#ifdef HAVE_LUA_RECORDS
101,557✔
1355
  bool doLua=g_doLuaRecord;
101,557✔
1356
#endif
101,557✔
1357

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

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

1374
  if (p.hasEDNS()) {
101,557✔
1375
    if(p.getEDNSVersion() > 0) {
93,337✔
1376
      r = p.replyPacket();
1✔
1377

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

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

1425
  r=p.replyPacket();  // generate an empty reply packet, possibly with TSIG details inside
101,556✔
1426

1427
  if (p.qtype == QType::TKEY) {
101,556✔
1428
    this->tkeyHandler(p, r);
67✔
1429
    return r;
67✔
1430
  }
67✔
1431

1432
  try {
101,489✔
1433

1434
    // XXX FIXME do this in DNSPacket::parse ?
1435

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

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

1470
      r->setRcode(RCode::NotImp);
×
1471
      return r;
×
1472
    }
1,259✔
1473

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

1476
    if(p.qtype.getCode()==QType::IXFR) {
100,230!
1477
      r->setRcode(RCode::Refused);
×
1478
      return r;
×
1479
    }
×
1480

1481
    DNSName target=p.qdomain;
100,230✔
1482

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

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

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

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

1508

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

1517
    if(!B.getAuth(target, p.qtype, &d_sd)) {
109,523✔
1518
      DLOG(g_log<<Logger::Error<<"We have no authority over zone '"<<target<<"'"<<endl);
2,494✔
1519
      if(!retargetcount) {
2,494✔
1520
        r->setA(false); // drop AA if we never had a SOA in the first place
687✔
1521
        r->setRcode(RCode::Refused); // send REFUSED - but only on empty 'no idea'
687✔
1522
      }
687✔
1523
      goto sendit;
2,494✔
1524
    }
2,494✔
1525
    DLOG(g_log<<Logger::Error<<"We have authority, zone='"<<d_sd.qname<<"', id="<<d_sd.domain_id<<endl);
107,029✔
1526

1527
    authSet.insert(d_sd.qname);
107,029✔
1528
    d_dnssec=(p.d_dnssecOk && d_dk.isSecuredZone(d_sd.qname));
107,029✔
1529
    doSigs |= d_dnssec;
107,029✔
1530

1531
    if(!retargetcount) r->qdomainzone=d_sd.qname;
107,029✔
1532

1533
    if(d_sd.qname==p.qdomain) {
107,029✔
1534
      if(!d_dk.isPresigned(d_sd.qname)) {
40,071✔
1535
        if(p.qtype.getCode() == QType::DNSKEY)
35,305✔
1536
        {
19,647✔
1537
          if(addDNSKEY(p, r))
19,647✔
1538
            goto sendit;
19,117✔
1539
        }
19,647✔
1540
        else if(p.qtype.getCode() == QType::CDNSKEY)
15,658✔
1541
        {
480✔
1542
          if(addCDNSKEY(p,r))
480!
1543
            goto sendit;
480✔
1544
        }
480✔
1545
        else if(p.qtype.getCode() == QType::CDS)
15,178✔
1546
        {
485✔
1547
          if(addCDS(p,r))
485✔
1548
            goto sendit;
484✔
1549
        }
485✔
1550
      }
35,305✔
1551
      if(p.qtype.getCode() == QType::NSEC3PARAM)
19,990✔
1552
      {
891✔
1553
        if(addNSEC3PARAM(p,r))
891✔
1554
          goto sendit;
450✔
1555
      }
891✔
1556
    }
19,990✔
1557

1558
    if(p.qtype.getCode() == QType::SOA && d_sd.qname==p.qdomain) {
86,498✔
1559
      rr=makeEditedDNSZRFromSOAData(d_dk, d_sd);
1,043✔
1560
      r->addRecord(std::move(rr));
1,043✔
1561
      goto sendit;
1,043✔
1562
    }
1,043✔
1563

1564
    // this TRUMPS a cname!
1565
    if(d_dnssec && p.qtype.getCode() == QType::NSEC && !d_dk.getNSEC3PARAM(d_sd.qname, nullptr)) {
85,455✔
1566
      addNSEC(p, r, target, DNSName(), 5);
236✔
1567
      if (!r->isEmpty())
236✔
1568
        goto sendit;
160✔
1569
    }
236✔
1570

1571
    // this TRUMPS a cname!
1572
    if(p.qtype.getCode() == QType::RRSIG) {
85,295✔
1573
      g_log<<Logger::Info<<"Direct RRSIG query for "<<target<<" from "<<p.getRemoteString()<<endl;
544✔
1574
      r->setRcode(RCode::Refused);
544✔
1575
      goto sendit;
544✔
1576
    }
544✔
1577

1578
    DLOG(g_log<<"Checking for referrals first, unless this is a DS query"<<endl);
84,751✔
1579
    if(p.qtype.getCode() != QType::DS && tryReferral(p, r, target, retargetcount))
84,751✔
1580
      goto sendit;
4,429✔
1581

1582
    DLOG(g_log<<"Got no referrals, trying ANY"<<endl);
80,322✔
1583

1584
#ifdef HAVE_LUA_RECORDS
80,322✔
1585
    if(!doLua) {
80,322!
1586
      string val;
80,322✔
1587
      d_dk.getFromMeta(d_sd.qname, "ENABLE-LUA-RECORDS", val);
80,322✔
1588
      doLua = (val=="1");
80,322✔
1589
    }
80,322✔
1590
#endif
80,322✔
1591

1592
    // see what we get..
1593
    B.lookup(QType(QType::ANY), target, d_sd.domain_id, &p);
80,322✔
1594
    rrset.clear();
80,322✔
1595
    weDone = weRedirected = weHaveUnauth =  false;
80,322✔
1596

1597
    while(B.get(rr)) {
285,046✔
1598
#ifdef HAVE_LUA_RECORDS
204,724✔
1599
      if (rr.dr.d_type == QType::LUA && !d_dk.isPresigned(d_sd.qname)) {
204,724!
1600
        if(!doLua)
×
1601
          continue;
×
1602
        auto rec=getRR<LUARecordContent>(rr.dr);
×
1603
        if (!rec) {
×
1604
          continue;
×
1605
        }
×
1606
        if(rec->d_type == QType::CNAME || rec->d_type == p.qtype.getCode() || (p.qtype.getCode() == QType::ANY && rec->d_type != QType::RRSIG)) {
×
1607
          noCache=true;
×
1608
          try {
×
1609
            auto recvec=luaSynth(rec->getCode(), target, d_sd.qname, d_sd.domain_id, p, rec->d_type, s_LUA);
×
1610
            if(!recvec.empty()) {
×
1611
              for (const auto& r_it : recvec) {
×
1612
                rr.dr.d_type = rec->d_type; // might be CNAME
×
1613
                rr.dr.setContent(r_it);
×
NEW
1614
                rr.scopeMask = p.getRealRemote().getBits(); // this makes sure answer is as specific as your question
×
1615
                rrset.push_back(rr);
×
1616
              }
×
1617
              if(rec->d_type == QType::CNAME && p.qtype.getCode() != QType::CNAME)
×
1618
                weRedirected = true;
×
1619
              else
×
1620
                weDone = true;
×
1621
            }
×
1622
          }
×
1623
          catch(std::exception &e) {
×
1624
            B.lookupEnd();              // don't leave DB handle in bad state
×
1625

1626
            r=p.replyPacket();
×
1627
            r->setRcode(RCode::ServFail);
×
1628

1629
            return r;
×
1630
          }
×
1631
        }
×
1632
      }
×
1633
#endif
204,724✔
1634
      if (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)) {
204,724!
1635
        if (!d_doExpandALIAS) {
301!
NEW
1636
          g_log<<Logger::Info<<"ALIAS record found for "<<target<<", but ALIAS expansion is disabled."<<endl;
×
NEW
1637
          continue;
×
NEW
1638
        }
×
1639
        DNSName aliasTarget = getRR<ALIASRecordContent>(rr.dr)->getContent();
301✔
1640
        if (aliasTarget.empty()) {
301!
NEW
1641
          continue;
×
NEW
1642
        }
×
1643

1644
        vector<DNSZoneRecord> ips;
301✔
1645
        EDNSSubnetOpts eso;
301✔
1646
        if (r->hasEDNSSubnet()) {
301!
NEW
1647
          eso.scope = r->d_eso.scope;
×
NEW
1648
          eso.source = r->d_eso.source;
×
NEW
1649
        }
×
1650
        int ret1 = RCode::NoError;
301✔
1651
        int ret2 = RCode::NoError;
301✔
1652
        if (r->qtype == QType::A || r->qtype == QType::ANY) {
301!
1653
          ret1 = stubDoResolve(aliasTarget, QType::A, ips, r->hasEDNSSubnet() ? &eso : nullptr);
169!
1654
        }
169✔
1655
        if (r->qtype == QType::AAAA || r->qtype == QType::ANY) {
301!
1656
          ret2 = stubDoResolve(aliasTarget, QType::AAAA, ips, r->hasEDNSSubnet() ? &eso : nullptr);
132!
1657
        }
132✔
1658

1659
        if (ret1 != RCode::NoError || ret2 != RCode::NoError) {
301!
NEW
1660
          g_log << Logger::Error << "Error resolving for " << target << " ALIAS " << aliasTarget << " over UDP";
×
NEW
1661
          if (ret1 != RCode::NoError) {
×
NEW
1662
            g_log << Logger::Error << ", A-record query returned " << RCode::to_s(ret1);
×
NEW
1663
          }
×
NEW
1664
          if (ret2 != RCode::NoError) {
×
NEW
1665
            g_log << Logger::Error << ", AAAA-record query returned " << RCode::to_s(ret2);
×
NEW
1666
          }
×
NEW
1667
          g_log << Logger::Error << ", returning SERVFAIL" << endl;
×
1668

NEW
1669
          while (B.get(rr)) {
×
1670
            // don't leave DB handle in bad state
NEW
1671
          }
×
1672

NEW
1673
          r = p.replyPacket();
×
NEW
1674
          r->setRcode(RCode::ServFail);
×
NEW
1675
          return r;
×
NEW
1676
        }
×
1677

1678
        for (auto& ip : ips) { // NOLINT(readability-identifier-length)
301✔
1679
          ip.dr.d_name = target;
301✔
1680
          if (r->hasEDNSSubnet()) {
301!
1681
            // update the EDNS options with info from the resolver - issue #5469
1682
            // note that this relies on the ECS string encoder to use the source network, and only take the prefix length from scope
NEW
1683
            ip.scopeMask = eso.scope.getBits();
×
NEW
1684
          }
×
1685
          rrset.push_back(ip);
301✔
1686
        }
301✔
1687

1688
        weDone = true;
301✔
1689
      }
301✔
1690

1691
      //cerr<<"got content: ["<<rr.content<<"]"<<endl;
1692
      if (!d_dnssec && p.qtype.getCode() == QType::ANY && (rr.dr.d_type == QType:: DNSKEY || rr.dr.d_type == QType::NSEC3PARAM))
204,724!
1693
        continue; // Don't send dnssec info.
×
1694
      if (rr.dr.d_type == QType::RRSIG) // RRSIGS are added later any way.
204,724✔
1695
        continue; // TODO: this actually means addRRSig should check if the RRSig is already there
37,945✔
1696

1697
      // cerr<<"Auth: "<<rr.auth<<", "<<(rr.dr.d_type == p.qtype)<<", "<<rr.dr.d_type.toString()<<endl;
1698
      if((p.qtype.getCode() == QType::ANY || rr.dr.d_type == p.qtype.getCode()) && rr.auth)
166,779✔
1699
        weDone=true;
64,757✔
1700
      // the line below fakes 'unauth NS' for delegations for non-DNSSEC backends.
1701
      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,779✔
1702
        weHaveUnauth=true;
3,491✔
1703

1704
      if(rr.dr.d_type == QType::CNAME && p.qtype.getCode() != QType::CNAME)
166,779✔
1705
        weRedirected=true;
8,245✔
1706

1707
      // Filter out all SOA's and add them in later
1708
      if(rr.dr.d_type == QType::SOA)
166,779✔
1709
        continue;
18,271✔
1710

1711
      rrset.push_back(rr);
148,508✔
1712
    }
148,508✔
1713

1714
    /* Add in SOA if required */
1715
    if(target==d_sd.qname) {
80,322✔
1716
        rr=makeEditedDNSZRFromSOAData(d_dk, d_sd);
18,265✔
1717
        rrset.push_back(rr);
18,265✔
1718
    }
18,265✔
1719

1720

1721
    DLOG(g_log<<"After first ANY query for '"<<target<<"', id="<<d_sd.domain_id<<": weDone="<<weDone<<", weHaveUnauth="<<weHaveUnauth<<", weRedirected="<<weRedirected<<endl);
80,322✔
1722
    if(p.qtype.getCode() == QType::DS && weHaveUnauth &&  !weDone && !weRedirected) {
80,322!
1723
      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✔
1724
      makeNOError(p, r, target, DNSName(), 1);
847✔
1725
      goto sendit;
847✔
1726
    }
847✔
1727

1728
    // referral for DS query
1729
    if(p.qtype.getCode() == QType::DS) {
79,475✔
1730
      DLOG(g_log<<"Qtype is DS"<<endl);
9,624✔
1731
      bool doReferral = true;
9,624✔
1732
      if(d_dk.doesDNSSEC()) {
9,624✔
1733
        for(auto& loopRR: rrset) {
9,544✔
1734
          // In a dnssec capable backend auth=true means, there is no delegation at
1735
          // or above this qname in this zone (for DS queries). Without a delegation,
1736
          // at or above this level, it is pointless to search for referrals.
1737
          if(loopRR.auth) {
9,269✔
1738
            doReferral = false;
8,052✔
1739
            break;
8,052✔
1740
          }
8,052✔
1741
        }
9,269✔
1742
      } else {
9,393✔
1743
        for(auto& loopRR: rrset) {
408✔
1744
          // In a non dnssec capable backend auth is always true, so our only option
1745
          // is, always look for referrals. Unless there is a direct match for DS.
1746
          if(loopRR.dr.d_type == QType::DS) {
408✔
1747
            doReferral = false;
96✔
1748
            break;
96✔
1749
          }
96✔
1750
        }
408✔
1751
      }
314✔
1752
      if(doReferral) {
9,624✔
1753
        DLOG(g_log<<"DS query found no direct result, trying referral now"<<endl);
1,476✔
1754
        if(tryReferral(p, r, target, retargetcount))
1,476✔
1755
        {
1,033✔
1756
          DLOG(g_log<<"Got referral for DS query"<<endl);
1,033✔
1757
          goto sendit;
1,033✔
1758
        }
1,033✔
1759
      }
1,476✔
1760
    }
9,624✔
1761

1762

1763
    if(rrset.empty()) {
78,442✔
1764
      DLOG(g_log<<Logger::Warning<<"Found nothing in the by-name ANY, but let's try wildcards.."<<endl);
21,174✔
1765
      bool wereRetargeted(false), nodata(false);
21,174✔
1766
      DNSName wildcard;
21,174✔
1767
      if(tryWildcard(p, r, target, wildcard, wereRetargeted, nodata)) {
21,174✔
1768
        if(wereRetargeted) {
7,436✔
1769
          if(!retargetcount) r->qdomainwild=wildcard;
2,388✔
1770
          retargetcount++;
2,388✔
1771
          goto retargeted;
2,388✔
1772
        }
2,388✔
1773
        if(nodata)
5,048✔
1774
          makeNOError(p, r, target, wildcard, 2);
1,740✔
1775

1776
        goto sendit;
5,048✔
1777
      }
7,436✔
1778
      try {
13,738✔
1779
        if (tryDNAME(p, r, target)) {
13,738✔
1780
          retargetcount++;
884✔
1781
          goto retargeted;
884✔
1782
        }
884✔
1783
      } catch (const std::range_error &e) {
13,738✔
1784
        // We couldn't make a CNAME.....
1785
        r->setRcode(RCode::YXDomain);
352✔
1786
        goto sendit;
352✔
1787
      }
352✔
1788

1789
      if (!(((p.qtype.getCode() == QType::CNAME) || (p.qtype.getCode() == QType::ANY)) && retargetcount > 0))
12,502✔
1790
        makeNXDomain(p, r, target, wildcard);
12,271✔
1791

1792
      goto sendit;
12,502✔
1793
    }
13,738✔
1794

1795
    if(weRedirected) {
57,268✔
1796
      for(auto& loopRR: rrset) {
8,245!
1797
        if(loopRR.dr.d_type == QType::CNAME) {
8,245!
1798
          r->addRecord(DNSZoneRecord(loopRR));
8,245✔
1799
          target = getRR<CNAMERecordContent>(loopRR.dr)->getTarget();
8,245✔
1800
          retargetcount++;
8,245✔
1801
          goto retargeted;
8,245✔
1802
        }
8,245✔
1803
      }
8,245✔
1804
    }
8,245✔
1805
    else if(weDone) {
49,023✔
1806
      bool haveRecords = false;
29,529✔
1807
      bool presigned = d_dk.isPresigned(d_sd.qname);
29,529✔
1808
      for(const auto& loopRR: rrset) {
98,160✔
1809
        if (loopRR.dr.d_type == QType::ENT) {
98,160✔
1810
          continue;
589✔
1811
        }
589✔
1812
        if (loopRR.dr.d_type == QType::ALIAS && d_doExpandALIAS && !presigned) {
97,571!
1813
          continue;
301✔
1814
        }
301✔
1815
#ifdef HAVE_LUA_RECORDS
97,270✔
1816
        if (loopRR.dr.d_type == QType::LUA && !presigned) {
97,270!
1817
          continue;
×
1818
        }
×
1819
#endif
97,270✔
1820
        if ((p.qtype.getCode() == QType::ANY || loopRR.dr.d_type == p.qtype.getCode()) && loopRR.auth) {
97,270✔
1821
          r->addRecord(DNSZoneRecord(loopRR));
64,007✔
1822
          haveRecords = true;
64,007✔
1823
        }
64,007✔
1824
      }
97,270✔
1825

1826
      if (haveRecords) {
29,529✔
1827
        if(d_dnssec && p.qtype.getCode() == QType::ANY)
28,940✔
1828
          completeANYRecords(p, r, target);
2,743✔
1829
      }
28,940✔
1830
      else
589✔
1831
        makeNOError(p, r, target, DNSName(), 0);
589✔
1832

1833
      goto sendit;
29,529✔
1834
    }
29,529✔
1835
    else if(weHaveUnauth) {
19,494✔
1836
      DLOG(g_log<<"Have unauth data, so need to hunt for best NS records"<<endl);
4✔
1837
      if(tryReferral(p, r, target, retargetcount))
4!
1838
        goto sendit;
×
1839
      // check whether this could be fixed easily
1840
      // if (*(rr.dr.d_name.rbegin()) == '.') {
1841
      //      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;
1842
      // } else {
1843
           g_log<<Logger::Error<<"Should not get here ("<<p.qdomain<<"|"<<p.qtype.toString()<<"): please run pdnsutil rectify-zone "<<d_sd.qname<<endl;
4✔
1844
      // }
1845
    }
4✔
1846
    else {
19,490✔
1847
      DLOG(g_log<<"Have some data, but not the right data"<<endl);
19,490✔
1848
      makeNOError(p, r, target, DNSName(), 0);
19,490✔
1849
    }
19,490✔
1850

1851
  sendit:;
98,006✔
1852
    doAdditionalProcessing(p, r);
98,006✔
1853

1854
    for(const auto& loopRR: r->getRRS()) {
257,109✔
1855
      if(loopRR.scopeMask) {
257,098✔
1856
        noCache=true;
214✔
1857
        break;
214✔
1858
      }
214✔
1859
    }
257,098✔
1860
    if(doSigs)
98,006✔
1861
      addRRSigs(d_dk, B, authSet, r->getRRS(), &p);
80,052✔
1862

1863
    if(PC.enabled() && !noCache && p.couldBeCached())
98,006!
1864
      PC.insert(p, *r, r->getMinTTL()); // in the packet cache
14,569✔
1865
  }
98,006✔
1866
  catch(const DBException &e) {
101,489✔
1867
    g_log<<Logger::Error<<"Backend reported condition which prevented lookup ("+e.reason+") sending out servfail"<<endl;
×
1868
    r=p.replyPacket(); // generate an empty reply packet
×
1869
    r->setRcode(RCode::ServFail);
×
1870
    S.inc("servfail-packets");
×
1871
    S.ringAccount("servfail-queries", p.qdomain, p.qtype);
×
1872
  }
×
1873
  catch(const PDNSException &e) {
101,489✔
1874
    g_log<<Logger::Error<<"Backend reported permanent error which prevented lookup ("+e.reason+"), aborting"<<endl;
×
1875
    throw; // we WANT to die at this point
×
1876
  }
×
1877
  catch(const std::exception &e) {
101,489✔
1878
    g_log<<Logger::Error<<"Exception building answer packet for "<<p.qdomain<<"/"<<p.qtype.toString()<<" ("<<e.what()<<") sending out servfail"<<endl;
×
1879
    r=p.replyPacket(); // generate an empty reply packet
×
1880
    r->setRcode(RCode::ServFail);
×
1881
    S.inc("servfail-packets");
×
1882
    S.ringAccount("servfail-queries", p.qdomain, p.qtype);
×
1883
  }
×
1884
  return r;
98,006✔
1885

1886
}
101,489✔
1887

1888
bool PacketHandler::checkForCorrectTSIG(const DNSPacket& packet, DNSName* tsigkeyname, string* secret, TSIGRecordContent* tsigContent)
1889
{
230✔
1890
  uint16_t tsigPos{0};
230✔
1891

1892
  if (!packet.getTSIGDetails(tsigContent, tsigkeyname, &tsigPos)) {
230!
1893
    return false;
×
1894
  }
×
1895

1896
  TSIGTriplet tsigTriplet;
230✔
1897
  tsigTriplet.name = *tsigkeyname;
230✔
1898
  tsigTriplet.algo = tsigContent->d_algoName;
230✔
1899
  if (tsigTriplet.algo == DNSName("hmac-md5.sig-alg.reg.int")) {
230✔
1900
    tsigTriplet.algo = DNSName("hmac-md5");
166✔
1901
  }
166✔
1902

1903
  if (tsigTriplet.algo != DNSName("gss-tsig")) {
230!
1904
    string secret64;
230✔
1905
    if (!B.getTSIGKey(*tsigkeyname, tsigTriplet.algo, secret64)) {
230!
1906
      g_log << Logger::Error << "Packet for domain '" << packet.qdomain << "' denied: can't find TSIG key with name '" << *tsigkeyname << "' and algorithm '" << tsigTriplet.algo << "'" << endl;
×
1907
      return false;
×
1908
    }
×
1909
    B64Decode(secret64, *secret);
230✔
1910
    tsigTriplet.secret = *secret;
230✔
1911
  }
230✔
1912

1913
  try {
230✔
1914
    return packet.validateTSIG(tsigTriplet, *tsigContent, "", tsigContent->d_mac, false);
230✔
1915
  }
230✔
1916
  catch(const std::runtime_error& err) {
230✔
1917
    g_log<<Logger::Error<<"Packet for '"<<packet.qdomain<<"' denied: "<<err.what()<<endl;
128✔
1918
    return false;
128✔
1919
  }
128✔
1920
}
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