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

PowerDNS / pdns / 14703970107

28 Apr 2025 08:50AM UTC coverage: 63.599% (+0.005%) from 63.594%
14703970107

push

github

web-flow
Merge pull request #15438 from rgacogne/ddist-fix-quic-freebsd-2

dnsdist: Only pass source addresses on sockets bound to ANY

41961 of 100700 branches covered (41.67%)

Branch coverage included in aggregate %.

16 of 19 new or added lines in 4 files covered. (84.21%)

52 existing lines in 12 files now uncovered.

129449 of 168816 relevant lines covered (76.68%)

4631284.5 hits per line

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

70.75
/pdns/dnspacket.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 "utility.hh"
26
#include <algorithm>
27
#include <cstdio>
28
#include <cstdlib>
29
#include <sys/types.h>
30
#include <iostream>
31
#include <string>
32
#include <boost/tokenizer.hpp>
33
#include <boost/functional/hash.hpp>
34
#include <boost/algorithm/string.hpp>
35
#include <openssl/hmac.h>
36
#include <algorithm>
37

38
#include "dnsseckeeper.hh"
39
#include "dns.hh"
40
#include "dnsbackend.hh"
41
#include "ednsoptions.hh"
42
#include "ednscookies.hh"
43
#include "pdnsexception.hh"
44
#include "dnspacket.hh"
45
#include "logger.hh"
46
#include "arguments.hh"
47
#include "dnswriter.hh"
48
#include "dnsparser.hh"
49
#include "dnsrecords.hh"
50
#include "dnssecinfra.hh"
51
#include "base64.hh"
52
#include "ednssubnet.hh"
53
#include "gss_context.hh"
54
#include "dns_random.hh"
55
#include "shuffle.hh"
56

57
bool DNSPacket::s_doEDNSSubnetProcessing;
58
bool DNSPacket::s_doEDNSCookieProcessing;
59
string DNSPacket::s_EDNSCookieKey;
60
uint16_t DNSPacket::s_udpTruncationThreshold;
61

62
DNSPacket::DNSPacket(bool isQuery): d_isQuery(isQuery)
63
{
1,752,333✔
64
  memset(&d, 0, sizeof(d));
1,752,333✔
65
}
1,752,333✔
66

67
const string& DNSPacket::getString(bool throwsOnTruncation)
68
{
2,378,169✔
69
  if(!d_wrapped)
2,378,169✔
70
    wrapup(throwsOnTruncation);
125,956✔
71

72
  return d_rawpacket;
2,378,169✔
73
}
2,378,169✔
74

75
string DNSPacket::getRemoteString() const
76
{
1,829✔
77
  string ret;
1,829✔
78

79
  ret = getRemote().toString();
1,829✔
80

81
  if (d_inner_remote) {
1,829!
82
    ret += "(" + d_inner_remote->toString() + ")";
×
83
  }
×
84

85
  if(hasEDNSSubnet()) {
1,829!
86
    ret += "<-" + getRealRemote().toString();
×
87
  }
×
88

89
  return ret;
1,829✔
90
}
1,829✔
91

92
string DNSPacket::getRemoteStringWithPort() const
93
{
1,703✔
94
  string ret;
1,703✔
95

96
  ret = getRemote().toStringWithPort();
1,703✔
97

98
  if (d_inner_remote) {
1,703!
99
    ret += "(" + d_inner_remote->toStringWithPort() + ")";
×
100
  }
×
101

102
  if(hasEDNSSubnet()) {
1,703!
103
    ret += "<-" + getRealRemote().toString();
×
104
  }
×
105

106
  return ret;
1,703✔
107
}
1,703✔
108

109
ComboAddress DNSPacket::getRemote() const
110
{
101,947✔
111
  return d_remote;
101,947✔
112
}
101,947✔
113

114
ComboAddress DNSPacket::getInnerRemote() const
115
{
103,703✔
116
  return d_inner_remote ? *d_inner_remote : d_remote;
103,703!
117
}
103,703✔
118

119
uint16_t DNSPacket::getRemotePort() const
120
{
×
121
  return d_remote.sin4.sin_port;
×
122
}
×
123

124
void DNSPacket::setRcode(int v)
125
{
15,735✔
126
  d.rcode=v;
15,735✔
127
}
15,735✔
128

129
void DNSPacket::setAnswer(bool b)
130
{
127,757✔
131
  if(b) {
127,757!
132
    d_rawpacket.assign(12,(char)0);
127,757✔
133
    memset((void *)&d,0,sizeof(d));
127,757✔
134

135
    d.qr=b;
127,757✔
136
  }
127,757✔
137
}
127,757✔
138

139
void DNSPacket::setA(bool b)
140
{
133,656✔
141
  d.aa=b;
133,656✔
142
}
133,656✔
143

144
void DNSPacket::setID(uint16_t id)
145
{
127,758✔
146
  d.id=id;
127,758✔
147
}
127,758✔
148

149
void DNSPacket::setRA(bool b)
150
{
127,756✔
151
  d.ra=b;
127,756✔
152
}
127,756✔
153

154
void DNSPacket::setRD(bool b)
155
{
127,755✔
156
  d.rd=b;
127,755✔
157
}
127,755✔
158

159
void DNSPacket::setOpcode(uint16_t opcode)
160
{
129,016✔
161
  d.opcode=opcode;
129,016✔
162
}
129,016✔
163

164
void DNSPacket::clearRecords()
UNCOV
165
{
×
UNCOV
166
  d_rrs.clear();
×
UNCOV
167
  d_dedup.clear();
×
UNCOV
168
}
×
169

170
void DNSPacket::addRecord(DNSZoneRecord&& rr)
171
{
271,750✔
172
  // this removes duplicates from the packet.
173
  // in case we are not compressing for AXFR, no such checking is performed!
174

175
  if(d_compress) {
271,750✔
176
    std::string ser = rr.dr.getContent()->serialize(rr.dr.d_name);
268,674✔
177
    auto hash = boost::hash< std::pair<DNSName, std::string> >()({rr.dr.d_name, ser});
268,674✔
178
    if(d_dedup.count(hash)) { // might be a dup
268,674✔
179
      for(auto & i : d_rrs) {
14,827✔
180
        if(rr.dr == i.dr)  // XXX SUPER SLOW
14,827✔
181
          return;
5,593✔
182
      }
14,827✔
183
    }
6,205✔
184
    d_dedup.insert(hash);
263,081✔
185
  }
263,081✔
186
  d_rrs.push_back(std::move(rr));
266,157✔
187
}
266,157✔
188

189
vector<DNSZoneRecord*> DNSPacket::getAPRecords()
190
{
×
191
  vector<DNSZoneRecord*> arrs;
×
192

193
  for(auto & i : d_rrs)
×
194
    {
×
195
      if(i.dr.d_place!=DNSResourceRecord::ADDITIONAL &&
×
196
         (i.dr.d_type==QType::MX ||
×
197
          i.dr.d_type==QType::NS ||
×
198
          i.dr.d_type==QType::SRV))
×
199
        {
×
200
          arrs.push_back(&i);
×
201
        }
×
202
    }
×
203
  return arrs;
×
204
}
×
205

206
vector<DNSZoneRecord*> DNSPacket::getServiceRecords()
207
{
99,221✔
208
  vector<DNSZoneRecord*> arrs;
99,221✔
209

210
  for(auto & i : d_rrs) {
204,560✔
211
    if (i.dr.d_type==QType::SVCB ||
204,560✔
212
        i.dr.d_type==QType::HTTPS) {
204,560✔
213
      arrs.push_back(&i);
1,902✔
214
    }
1,902✔
215
  }
204,560✔
216
  return arrs;
99,221✔
217
}
99,221✔
218

219
vector<DNSZoneRecord*> DNSPacket::getAnswerRecords()
220
{
×
221
  vector<DNSZoneRecord*> arrs;
×
222

223
  for(auto & rr : d_rrs)
×
224
    {
×
225
      if(rr.dr.d_place!=DNSResourceRecord::ADDITIONAL)
×
226
        arrs.push_back(&rr);
×
227
    }
×
228
  return arrs;
×
229
}
×
230

231

232
void DNSPacket::setCompress(bool compress)
233
{
24,383✔
234
  d_compress=compress;
24,383✔
235
  d_rawpacket.reserve(65000);
24,383✔
236
  d_rrs.reserve(200);
24,383✔
237
}
24,383✔
238

239
bool DNSPacket::couldBeCached() const
240
{
41,586✔
241
  return !d_wantsnsid && qclass==QClass::IN && !d_havetsig &&
41,586!
242
    !(d_haveednscookie && s_doEDNSCookieProcessing);
41,586!
243
}
41,586✔
244

245
unsigned int DNSPacket::getMinTTL()
246
{
14,937✔
247
  auto iter = std::min_element(d_rrs.begin(), d_rrs.end());
14,937✔
248
  if (iter != d_rrs.end()) {
14,937✔
249
    return iter->dr.d_ttl;
14,713✔
250
  }
14,713✔
251
  return UINT_MAX;
224✔
252
}
14,937✔
253

254
bool DNSPacket::isEmpty()
255
{
236✔
256
  return (d_rrs.empty());
236✔
257
}
236✔
258

259
/** Must be called before attempting to access getData(). This function stuffs all resource
260
 *  records found in rrs into the data buffer. It also frees resource records queued for us.
261
 */
262
void DNSPacket::wrapup(bool throwsOnTruncation)
263
{
125,955✔
264
  if(d_wrapped) {
125,955!
265
    return;
×
266
  }
×
267

268
  DNSZoneRecord rr;
125,955✔
269
  vector<DNSZoneRecord>::iterator pos;
125,955✔
270

271
  // we now need to order rrs so that the different sections come at the right place
272
  // we want a stable sort, based on the d_place field
273

274
  stable_sort(d_rrs.begin(),d_rrs.end(), [](const DNSZoneRecord& a, const DNSZoneRecord& b) {
6,662,890✔
275
      return a.dr.d_place < b.dr.d_place;
6,662,824✔
276
    });
6,662,824✔
277
  static bool mustNotShuffle = ::arg().mustDo("no-shuffle");
125,955✔
278

279
  if(!d_xfr && !mustNotShuffle) {
125,955!
280
    pdns::shuffle(d_rrs);
×
281
  }
×
282
  d_wrapped=true;
125,955✔
283

284
  vector<uint8_t> packet;
125,955✔
285
  DNSPacketWriter pw(packet, qdomain, qtype.getCode(), qclass);
125,955✔
286

287
  pw.getHeader()->rcode=d.rcode;
125,955✔
288
  pw.getHeader()->opcode = d.opcode;
125,955✔
289
  pw.getHeader()->aa=d.aa;
125,955✔
290
  pw.getHeader()->ra=d.ra;
125,955✔
291
  pw.getHeader()->qr=d.qr;
125,955✔
292
  pw.getHeader()->id=d.id;
125,955✔
293
  pw.getHeader()->rd=d.rd;
125,955✔
294
  pw.getHeader()->tc=d.tc;
125,955✔
295

296
  DNSPacketWriter::optvect_t opts;
125,955✔
297

298
  /* optsize is expected to hold an upper bound of data that will be
299
     added after actual record data - i.e. OPT, TSIG.
300
     Because of the way `pw` incrementally writes the packet, we
301
     cannot easily 'go back' and remove a few records. So, to prevent
302
     going over our maximum size, we keep our (potential) extra data
303
     in mind.
304

305
     This means that sometimes we'll send TC even if we'd end up with
306
     a few bytes to spare, but so be it.
307
    */
308
  size_t optsize = 0;
125,955✔
309

310
  if (d_haveednssection || d_dnssecOk) {
125,955✔
311
    /* root label (1), type (2), class (2), ttl (4) + rdlen (2) */
312
    optsize = 11;
95,392✔
313
  }
95,392✔
314

315
  if(d_wantsnsid) {
125,955!
316
    const static string mode_server_id=::arg()["server-id"];
×
317
    if(mode_server_id != "disabled") {
×
318
      opts.emplace_back(EDNSOptionCode::NSID, mode_server_id);
×
319
      optsize += EDNS_OPTION_CODE_SIZE + EDNS_OPTION_LENGTH_SIZE + mode_server_id.size();
×
320
    }
×
321
  }
×
322

323
  if (d_haveednssubnet)
125,955✔
324
  {
36✔
325
    // this is an upper bound
326
    optsize += EDNS_OPTION_CODE_SIZE + EDNS_OPTION_LENGTH_SIZE + 2 + 1 + 1; // code+len+family+src len+scope len
36✔
327
    optsize += d_eso.getSource().isIPv4() ? 4 : 16;
36✔
328
  }
36✔
329

330
  if (d_haveednscookie) {
125,955!
331
    if (d_eco.isWellFormed()) {
×
332
        optsize += EDNS_OPTION_CODE_SIZE + EDNS_OPTION_LENGTH_SIZE + EDNSCookiesOpt::EDNSCookieOptSize;
×
333
    }
×
334
  }
×
335

336
  if (d_trc.d_algoName.countLabels())
125,955✔
337
  {
212✔
338
    // TSIG is not OPT, but we count it in optsize anyway
339
    optsize += d_trc.d_algoName.wirelength() + 3 + 1 + 2; // algo + time + fudge + maclen
212✔
340
    optsize += EVP_MAX_MD_SIZE + 2 + 2 + 2 + 0; // mac + origid + ercode + otherdatalen + no other data
212✔
341

342
    static_assert(EVP_MAX_MD_SIZE <= 64, "EVP_MAX_MD_SIZE is overly huge on this system, please check");
212✔
343
  }
212✔
344

345
  if(!d_rrs.empty() || !opts.empty() || d_haveednssubnet || d_haveednssection || d_haveednscookie) {
125,955!
346
    try {
124,481✔
347
      uint8_t maxScopeMask=0;
124,481✔
348
      for(pos=d_rrs.begin(); pos < d_rrs.end(); ++pos) {
2,087,185✔
349
        maxScopeMask = max(maxScopeMask, pos->scopeMask);
1,963,255✔
350

351
        pw.startRecord(pos->dr.d_name, pos->dr.d_type, pos->dr.d_ttl, pos->dr.d_class, pos->dr.d_place);
1,963,255✔
352
        pos->dr.getContent()->toPacket(pw);
1,963,255✔
353
        if(pw.size() + optsize > (d_tcp ? 65535 : getMaxReplyLen())) {
1,963,255✔
354
          if (throwsOnTruncation) {
551!
355
            throw PDNSException("attempt to write an oversized chunk, see https://docs.powerdns.com/authoritative/settings.html#workaround-11804");
×
356
          }
×
357
          pw.rollback();
551✔
358
          pw.truncate();
551✔
359
          pw.getHeader()->tc=1;
551✔
360
          goto noCommit;
551✔
361
        }
551✔
362
      }
1,963,255✔
363

364
      // if(!pw.getHeader()->tc) // protect against double commit from addSignature
365

366
      if(!d_rrs.empty()) pw.commit();
123,930✔
367

368
      noCommit:;
124,483✔
369

370
      if(d_haveednssubnet) {
124,483✔
371
        EDNSSubnetOpts eso = d_eso;
36✔
372
        // use the scopeMask from the resolver, if it is greater - issue #5469
373
        maxScopeMask = max(maxScopeMask, eso.getScopePrefixLength());
36✔
374
        eso.setScopePrefixLength(maxScopeMask);
36✔
375

376
        string opt = eso.makeOptString();
36✔
377
        opts.emplace_back(8, opt); // 'EDNS SUBNET'
36✔
378
      }
36✔
379

380
      if (d_haveednscookie && d_eco.isWellFormed()) {
124,483!
381
        d_eco.makeServerCookie(s_EDNSCookieKey, getInnerRemote());
×
382
        opts.emplace_back(EDNSOptionCode::COOKIE, d_eco.makeOptString());
×
383
      }
×
384

385
      if(!opts.empty() || d_haveednssection || d_dnssecOk)
124,483!
386
      {
95,393✔
387
        pw.addOpt(s_udpTruncationThreshold, d_ednsrcode, d_dnssecOk ? EDNSOpts::DNSSECOK : 0, opts);
95,393✔
388
        pw.commit();
95,393✔
389
      }
95,393✔
390
    }
124,483✔
391
    catch(std::exception& e) {
124,481✔
392
      g_log<<Logger::Warning<<"Exception: "<<e.what()<<endl;
×
393
      throw;
×
394
    }
×
395
  }
124,481✔
396

397
  if(d_trc.d_algoName.countLabels())
125,956✔
398
    addTSIG(pw, d_trc, d_tsigkeyname, d_tsigsecret, d_tsigprevious, d_tsigtimersonly);
212✔
399

400
  d_rawpacket.assign((char*)&packet[0], packet.size()); // XXX we could do this natively on a vector..
125,956✔
401

402
  // copy RR counts so they can be read later
403
  d.qdcount = pw.getHeader()->qdcount;
125,956✔
404
  d.ancount = pw.getHeader()->ancount;
125,956✔
405
  d.nscount = pw.getHeader()->nscount;
125,956✔
406
  d.arcount = pw.getHeader()->arcount;
125,956✔
407
}
125,956✔
408

409
void DNSPacket::setQuestion(int op, const DNSName &qd, int newqtype)
410
{
×
411
  memset(&d,0,sizeof(d));
×
412
  d.id=dns_random_uint16();
×
413
  d.rd=d.tc=d.aa=false;
×
414
  d.qr=false;
×
415
  d.qdcount=1; // is htons'ed later on
×
416
  d.ancount=d.arcount=d.nscount=0;
×
417
  d.opcode=op;
×
418
  qdomain=qd;
×
419
  qtype=newqtype;
×
420
}
×
421

422
/** convenience function for creating a reply packet from a question packet. */
423
std::unique_ptr<DNSPacket> DNSPacket::replyPacket() const
424
{
127,757✔
425
  auto r=make_unique<DNSPacket>(false);
127,757✔
426
  r->setSocket(d_socket);
127,757✔
427
  r->d_anyLocal=d_anyLocal;
127,757✔
428
  r->setRemote(&d_remote);
127,757✔
429
  r->d_inner_remote=d_inner_remote;
127,757✔
430
  r->setAnswer(true);  // this implies the allocation of the header
127,757✔
431
  r->setA(true); // and we are authoritative
127,757✔
432
  r->setRA(false); // no recursion available
127,757✔
433
  r->setRD(d.rd); // if you wanted to recurse, answer will say you wanted it
127,757✔
434
  r->setID(d.id);
127,757✔
435
  r->setOpcode(d.opcode);
127,757✔
436

437
  r->d_dt=d_dt;
127,757✔
438
  r->d.qdcount=1;
127,757✔
439
  r->d_tcp = d_tcp;
127,757✔
440
  r->qdomain = qdomain;
127,757✔
441
  r->qtype = qtype;
127,757✔
442
  r->qclass = qclass;
127,757✔
443
  r->d_maxreplylen = d_maxreplylen;
127,757✔
444
  r->d_wantsnsid = d_wantsnsid;
127,757✔
445
  r->d_dnssecOk = d_dnssecOk;
127,757✔
446
  r->d_eso = d_eso;
127,757✔
447
  r->d_eco = d_eco;
127,757✔
448
  r->d_haveednssubnet = d_haveednssubnet;
127,757✔
449
  r->d_haveednssection = d_haveednssection;
127,757✔
450
  r->d_haveednscookie = d_haveednscookie;
127,757✔
451
  r->d_ednsversion = 0;
127,757✔
452
  r->d_ednsrcode = 0;
127,757✔
453
  r->d_xfr = d_xfr;
127,757✔
454

455
  if(d_tsigkeyname.countLabels()) {
127,757✔
456
    r->d_tsigkeyname = d_tsigkeyname;
15✔
457
    r->d_tsigprevious = d_tsigprevious;
15✔
458
    r->d_trc = d_trc;
15✔
459
    r->d_tsigsecret = d_tsigsecret;
15✔
460
    r->d_tsigtimersonly = d_tsigtimersonly;
15✔
461
  }
15✔
462
  r->d_havetsig = d_havetsig;
127,757✔
463
  return r;
127,757✔
464
}
127,757✔
465

466
void DNSPacket::spoofQuestion(const DNSPacket& qd)
467
{
399,067✔
468
  d_wrapped=true; // if we do this, don't later on wrapup
399,067✔
469

470
  int labellen;
399,067✔
471
  string::size_type i=sizeof(d);
399,067✔
472

473
  for(;;) {
1,212,825✔
474
    labellen = qd.d_rawpacket[i];
1,212,825✔
475
    if(!labellen) break;
1,212,825✔
476
    i++;
805,496✔
477
    d_rawpacket.replace(i, labellen, qd.d_rawpacket, i, labellen);
805,496✔
478
    i = i + labellen;
805,496✔
479
  }
805,496✔
480
}
399,067✔
481

482
int DNSPacket::noparse(const char *mesg, size_t length)
483
{
405,635✔
484
  d_rawpacket.assign(mesg,length);
405,635✔
485
  if(length < 12) {
405,635!
486
    g_log << Logger::Debug << "Ignoring packet: too short ("<<length<<" < 12) from "
×
487
      << getRemoteStringWithPort();
×
488
    return -1;
×
489
  }
×
490
  d_wantsnsid=false;
405,635✔
491
  d_maxreplylen=512;
405,635✔
492
  memcpy((void *)&d,(const void *)d_rawpacket.c_str(),12);
405,635✔
493
  return 0;
405,635✔
494
}
405,635✔
495

496
void DNSPacket::setTSIGDetails(const TSIGRecordContent& tr, const DNSName& keyname, const string& secret, const string& previous, bool timersonly)
497
{
212✔
498
  d_trc=tr;
212✔
499
  d_trc.d_origID = (((d.id & 0xFF)<<8) | ((d.id & 0xFF00)>>8));
212✔
500
  d_tsigkeyname = keyname;
212✔
501
  d_tsigsecret = secret;
212✔
502
  d_tsigprevious = previous;
212✔
503
  d_tsigtimersonly=timersonly;
212✔
504
}
212✔
505

506
bool DNSPacket::getTSIGDetails(TSIGRecordContent* trc, DNSName* keyname, uint16_t* tsigPosOut) const
507
{
1,809✔
508
  MOADNSParser mdp(d_isQuery, d_rawpacket);
1,809✔
509
  uint16_t tsigPos = mdp.getTSIGPos();
1,809✔
510
  if(!tsigPos)
1,809✔
511
    return false;
1,490✔
512

513
  bool gotit=false;
319✔
514
  for(const auto & answer : mdp.d_answers) {
713✔
515
    if(answer.d_type == QType::TSIG && answer.d_class == QType::ANY) {
713!
516
      // cast can fail, f.e. if d_content is an UnknownRecordContent.
517
      auto content = getRR<TSIGRecordContent>(answer);
319✔
518
      if (!content) {
319!
519
        g_log<<Logger::Error<<"TSIG record has no or invalid content (invalid packet)"<<endl;
×
520
        return false;
×
521
      }
×
522
      *trc = *content;
319✔
523
      *keyname = answer.d_name;
319✔
524
      gotit=true;
319✔
525
    }
319✔
526
  }
713✔
527
  if(!gotit)
319!
528
    return false;
×
529

530
  if (tsigPosOut) {
319✔
531
    *tsigPosOut = tsigPos;
230✔
532
  }
230✔
533

534
  return true;
319✔
535
}
319✔
536

537
bool DNSPacket::validateTSIG(const TSIGTriplet& tsigTriplet, const TSIGRecordContent& tsigContent, const std::string& previousMAC, const std::string& theirMAC, bool timersOnly) const
538
{
230✔
539
  MOADNSParser mdp(d_isQuery, d_rawpacket);
230✔
540
  uint16_t tsigPos = mdp.getTSIGPos();
230✔
541
  if (tsigPos == 0) {
230!
542
    return false;
×
543
  }
×
544

545
  return ::validateTSIG(d_rawpacket, tsigPos, tsigTriplet, tsigContent, previousMAC, theirMAC, timersOnly);
230✔
546
}
230✔
547

548
bool DNSPacket::getTKEYRecord(TKEYRecordContent *tr, DNSName *keyname) const
549
{
67✔
550
  MOADNSParser mdp(d_isQuery, d_rawpacket);
67✔
551
  bool gotit=false;
67✔
552

553
  for(const auto & answer : mdp.d_answers) {
67✔
554
    if (gotit) {
67!
555
      g_log<<Logger::Error<<"More than one TKEY record found in query"<<endl;
×
556
      return false;
×
557
    }
×
558

559
    if(answer.d_type == QType::TKEY) {
67!
560
      // cast can fail, f.e. if d_content is an UnknownRecordContent.
561
      auto content = getRR<TKEYRecordContent>(answer);
67✔
562
      if (!content) {
67!
563
        g_log<<Logger::Error<<"TKEY record has no or invalid content (invalid packet)"<<endl;
×
564
        return false;
×
565
      }
×
566
      *tr = *content;
67✔
567
      *keyname = answer.d_name;
67✔
568
      gotit=true;
67✔
569
    }
67✔
570
  }
67✔
571

572
  return gotit;
67✔
573
}
67✔
574

575
/** This function takes data from the network, possibly received with recvfrom, and parses
576
    it into our class. Results of calling this function multiple times on one packet are
577
    unknown. Returns -1 if the packet cannot be parsed.
578
*/
579
int DNSPacket::parse(const char *mesg, size_t length)
580
try
1,309,831✔
581
{
1,309,831✔
582
  d_rawpacket.assign(mesg,length);
1,309,831✔
583
  d_wrapped=true;
1,309,831✔
584
  if(length < 12) {
1,309,831!
585
    g_log << Logger::Debug << "Ignoring packet: too short from "
×
586
      << getRemoteString() << endl;
×
587
    return -1;
×
588
  }
×
589

590
  MOADNSParser mdp(d_isQuery, d_rawpacket);
1,309,831✔
591
  EDNSOpts edo;
1,309,831✔
592

593
  // ANY OPTION WHICH *MIGHT* BE SET DOWN BELOW SHOULD BE CLEARED FIRST!
594

595
  d_wantsnsid=false;
1,309,831✔
596
  d_dnssecOk=false;
1,309,831✔
597
  d_havetsig = mdp.getTSIGPos();
1,309,831✔
598
  d_haveednssubnet = false;
1,309,831✔
599
  d_haveednssection = false;
1,309,831✔
600
  d_haveednscookie = false;
1,309,831✔
601
  d_ednscookievalid = false;
1,309,831✔
602

603
  if(getEDNSOpts(mdp, &edo)) {
1,309,831✔
604
    d_haveednssection=true;
105,900✔
605
    /* rfc6891 6.2.3:
606
       "Values lower than 512 MUST be treated as equal to 512."
607
    */
608
    d_ednsRawPacketSizeLimit=edo.d_packetsize;
105,900✔
609
    d_maxreplylen=std::min(std::max(static_cast<uint16_t>(512), edo.d_packetsize), s_udpTruncationThreshold);
105,900✔
610
    if((edo.d_extFlags & EDNSOpts::DNSSECOK) != 0) {
105,900✔
611
      d_dnssecOk=true;
105,609✔
612
    }
105,609✔
613

614
    for(const auto & option : edo.d_options) {
105,900✔
615
      if(option.first == EDNSOptionCode::NSID) {
241!
616
        d_wantsnsid=true;
×
617
      }
×
618
      else if(s_doEDNSSubnetProcessing && (option.first == EDNSOptionCode::ECS)) { // 'EDNS SUBNET'
241!
619
        if (EDNSSubnetOpts::getFromString(option.second, &d_eso)) {
36!
620
          //cerr<<"Parsed, source: "<<d_eso.source.toString()<<", scope: "<<d_eso.scope.toString()<<", family = "<<d_eso.scope.getNetwork().sin4.sin_family<<endl;
621
          d_haveednssubnet=true;
36✔
622
        }
36✔
623
      }
36✔
624
      else if (s_doEDNSCookieProcessing && option.first == EDNSOptionCode::COOKIE) {
205!
625
        d_haveednscookie = true;
×
626
        d_eco.makeFromString(option.second);
×
627
        d_ednscookievalid = d_eco.isValid(s_EDNSCookieKey, d_remote);
×
628
      }
×
629
      else {
205✔
630
        // cerr<<"Have an option #"<<iter->first<<": "<<makeHexDump(iter->second)<<endl;
631
      }
205✔
632
    }
241✔
633
    d_ednsversion = edo.d_version;
105,900✔
634
    d_ednsrcode = edo.d_extRCode;
105,900✔
635
 }
105,900✔
636
  else  {
1,203,931✔
637
    d_maxreplylen=512;
1,203,931✔
638
    d_ednsRawPacketSizeLimit=-1;
1,203,931✔
639
  }
1,203,931✔
640

641
  memcpy((void *)&d,(const void *)d_rawpacket.c_str(),12);
1,309,831✔
642
  qdomain=mdp.d_qname;
1,309,831✔
643
  // if(!qdomain.empty()) // strip dot
644
  //   boost::erase_tail(qdomain, 1);
645

646
  if(!ntohs(d.qdcount)) {
1,309,831!
647
    if(!d_tcp) {
×
648
      g_log << Logger::Debug << "No question section in packet from " << getRemoteString() <<", RCode="<<RCode::to_s(d.rcode)<<endl;
×
649
      return -1;
×
650
    }
×
651
  }
×
652

653
  qtype=mdp.d_qtype;
1,309,831✔
654
  qclass=mdp.d_qclass;
1,309,831✔
655

656
  d_trc = TSIGRecordContent();
1,309,831✔
657

658
  return 0;
1,309,831✔
659
}
1,309,831✔
660
catch(std::exception& e) {
1,309,831✔
661
  g_log << Logger::Debug << "Parse error in packet from " << getRemoteString() << ": " << e.what() << endl;
×
662
  return -1;
×
663
}
×
664

665
unsigned int DNSPacket::getMaxReplyLen()
666
{
413,743✔
667
  return d_maxreplylen;
413,743✔
668
}
413,743✔
669

670
void DNSPacket::setMaxReplyLen(int bytes)
671
{
10,425✔
672
  d_maxreplylen=bytes;
10,425✔
673
}
10,425✔
674

675
//! Use this to set where this packet was received from or should be sent to
676
void DNSPacket::setRemote(const ComboAddress *outer)
677
{
254,454✔
678
  d_remote=*outer;
254,454✔
679
  d_inner_remote.reset();
254,454✔
680
}
254,454✔
681

682
bool DNSPacket::hasEDNSSubnet() const
683
{
3,951✔
684
  return d_haveednssubnet;
3,951✔
685
}
3,951✔
686

687
bool DNSPacket::hasEDNS() const
688
{
103,074✔
689
  return d_haveednssection;
103,074✔
690
}
103,074✔
691

692
bool DNSPacket::hasEDNSCookie() const
693
{
210,367✔
694
  return d_haveednscookie;
210,367✔
695
}
210,367✔
696

697
bool DNSPacket::hasWellFormedEDNSCookie() const
698
{
×
699
  if (!d_haveednscookie) {
×
700
    return false;
×
701
  }
×
702
  return d_eco.isWellFormed();
×
703
}
×
704

705
bool DNSPacket::hasValidEDNSCookie() const
706
{
×
707
  if (!hasWellFormedEDNSCookie()) {
×
708
    return false;
×
709
  }
×
710
  return d_ednscookievalid;
×
711
}
×
712

713
void DNSPacket::setRealRemote(const Netmask& netmask) {
×
714
  d_eso.setSource(netmask);
×
715
  d_haveednssubnet = true;
×
716
}
×
717

718
Netmask DNSPacket::getRealRemote() const
719
{
625✔
720
  return d_haveednssubnet ? d_eso.getSource() : Netmask{getInnerRemote()};
625✔
721
}
625✔
722

723
void DNSPacket::setSocket(Utility::sock_t sock)
724
{
253,904✔
725
  d_socket = sock;
253,904✔
726
}
253,904✔
727

728
void DNSPacket::commitD()
729
{
12,928✔
730
  d_rawpacket.replace(0,12,(char *)&d,12); // copy in d
12,928✔
731
}
12,928✔
732

733
const DNSName& DNSPacket::getTSIGKeyname() const {
14✔
734
  return d_tsigkeyname;
14✔
735
}
14✔
736

737
#ifdef ENABLE_GSS_TSIG
738
void DNSPacket::cleanupGSS(int rcode)
739
{
×
740
  // We cannot check g_doGssTSIG here, as this code is also included in other executables
741
  // than pdns_server.
742
  if (rcode != RCode::NoError && d_tsig_algo == TSIG_GSS && !getTSIGKeyname().empty()) {
×
743
    GssContext ctx(getTSIGKeyname());
×
744
    ctx.destroy();
×
745
  }
×
746
}
×
747
#endif
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

© 2026 Coveralls, Inc