Coverage Report

Created: 2026-05-24 06:25

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/pdns/pdns/dnswriter.cc
Line
Count
Source
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 <boost/version.hpp>
26
#include <boost/container/static_vector.hpp>
27
#include "dnswriter.hh"
28
#include "misc.hh"
29
#include "dnsparser.hh"
30
31
#include <limits.h>
32
33
/* d_content:                                      <---- d_stuff ---->
34
                                      v d_truncatemarker
35
   dnsheader | qname | qtype | qclass | {recordname| dnsrecordheader | record }
36
                                        ^ d_rollbackmarker           ^ d_sor
37
38
39
*/
40
41
template <typename Container>
42
GenericDNSPacketWriter<Container>::GenericDNSPacketWriter(Container& content, const DNSName& qname, uint16_t qtype, uint16_t qclass, uint8_t opcode) :
43
0
  d_qname(qname), d_content(content)
44
0
{
45
0
  d_content.clear();
46
0
  dnsheader dnsheader;
47
48
0
  memset(&dnsheader, 0, sizeof(dnsheader));
49
0
  dnsheader.id=0;
50
0
  dnsheader.qdcount=htons(1);
51
0
  dnsheader.opcode=opcode;
52
53
0
  const uint8_t* ptr=(const uint8_t*)&dnsheader;
54
0
  d_content.reserve(sizeof(dnsheader) + qname.wirelength() + sizeof(qtype) + sizeof(qclass));
55
0
  d_content.resize(sizeof(dnsheader));
56
0
  uint8_t* dptr=(&*d_content.begin());
57
58
0
  memcpy(dptr, ptr, sizeof(dnsheader));
59
0
  d_namepositions.reserve(16);
60
0
  xfrName(qname, false);
61
0
  xfr16BitInt(qtype);
62
0
  xfr16BitInt(qclass);
63
64
0
  if (d_content.size() > std::numeric_limits<decltype(d_truncatemarker)>::max()) {
65
0
    throw std::range_error("Trying to build a packet larger than " + std::to_string(std::numeric_limits<decltype(d_truncatemarker)>::max()) + " bytes");
66
0
  }
67
0
  d_truncatemarker = d_content.size();
68
0
}
Unexecuted instantiation: GenericDNSPacketWriter<std::__1::vector<unsigned char, std::__1::allocator<unsigned char> > >::GenericDNSPacketWriter(std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >&, DNSName const&, unsigned short, unsigned short, unsigned char)
Unexecuted instantiation: GenericDNSPacketWriter<std::__1::vector<unsigned char, noinit_adaptor<std::__1::allocator<unsigned char> > > >::GenericDNSPacketWriter(std::__1::vector<unsigned char, noinit_adaptor<std::__1::allocator<unsigned char> > >&, DNSName const&, unsigned short, unsigned short, unsigned char)
69
70
template <typename Container> dnsheader* GenericDNSPacketWriter<Container>::getHeader()
71
0
{
72
0
  return reinterpret_cast<dnsheader*>(&*d_content.begin());
73
0
}
Unexecuted instantiation: GenericDNSPacketWriter<std::__1::vector<unsigned char, std::__1::allocator<unsigned char> > >::getHeader()
Unexecuted instantiation: GenericDNSPacketWriter<std::__1::vector<unsigned char, noinit_adaptor<std::__1::allocator<unsigned char> > > >::getHeader()
74
75
76
template <typename Container> void GenericDNSPacketWriter<Container>::startRecord(const DNSName& name, uint16_t qtype, uint32_t ttl, uint16_t qclass, DNSResourceRecord::Place place, bool compress)
77
0
{
78
0
  d_compress = compress;
79
0
  commit();
80
0
  if (d_content.size() > std::numeric_limits<decltype(d_rollbackmarker)>::max()) {
81
0
    throw std::range_error("Trying to build a packet larger than " + std::to_string(std::numeric_limits<decltype(d_rollbackmarker)>::max()) + " bytes");
82
0
  }
83
0
  d_rollbackmarker = d_content.size();
84
85
0
  if (compress && !name.isRoot() && d_qname==name) {  // don't do the whole label compression thing if we *know* we can get away with "see question" - except when compressing the root
86
0
    static const std::array<unsigned char, 2> marker{0xc0, 0x0c};
87
0
    d_content.insert(d_content.end(), reinterpret_cast<const char *>(marker.begin()), reinterpret_cast<const char *>(marker.end()));
88
0
  }
89
0
  else {
90
0
    xfrName(name, compress);
91
0
  }
92
0
  xfr16BitInt(qtype);
93
0
  xfr16BitInt(qclass);
94
0
  xfr32BitInt(ttl);
95
0
  xfr16BitInt(0); // this will be the record size
96
0
  d_recordplace = place;
97
98
0
  d_sor = d_content.size(); // this will remind us where to stuff the record size
99
0
}
Unexecuted instantiation: GenericDNSPacketWriter<std::__1::vector<unsigned char, std::__1::allocator<unsigned char> > >::startRecord(DNSName const&, unsigned short, unsigned int, unsigned short, DNSResourceRecord::Place, bool)
Unexecuted instantiation: GenericDNSPacketWriter<std::__1::vector<unsigned char, noinit_adaptor<std::__1::allocator<unsigned char> > > >::startRecord(DNSName const&, unsigned short, unsigned int, unsigned short, DNSResourceRecord::Place, bool)
100
101
template <typename Container> void GenericDNSPacketWriter<Container>::addOpt(const uint16_t udpsize, const uint16_t extRCode, const uint16_t ednsFlags, const optvect_t& options, const uint8_t version)
102
0
{
103
0
  uint32_t ttl=0;
104
105
0
  EDNS0Record stuff;
106
107
0
  stuff.version = version;
108
0
  stuff.extFlags = htons(ednsFlags);
109
110
  /* RFC 6891 section 4 on the Extended RCode wire format
111
   *    EXTENDED-RCODE
112
   *        Forms the upper 8 bits of extended 12-bit RCODE (together with the
113
   *        4 bits defined in [RFC1035].  Note that EXTENDED-RCODE value 0
114
   *        indicates that an unextended RCODE is in use (values 0 through 15).
115
   */
116
  // XXX Should be check for extRCode > 1<<12 ?
117
0
  stuff.extRCode = extRCode>>4;
118
0
  if (extRCode != 0) { // As this trumps the existing RCODE
119
0
    getHeader()->rcode = extRCode;
120
0
  }
121
122
0
  static_assert(sizeof(EDNS0Record) == sizeof(ttl), "sizeof(EDNS0Record) must match sizeof(ttl)");
123
0
  memcpy(&ttl, &stuff, sizeof(stuff));
124
125
0
  ttl=ntohl(ttl); // will be reversed later on
126
127
0
  startRecord(g_rootdnsname, QType::OPT, ttl, udpsize, DNSResourceRecord::ADDITIONAL, false);
128
0
  for(auto const &option : options) {
129
0
    xfr16BitInt(option.first);
130
0
    xfr16BitInt(option.second.length());
131
0
    xfrBlob(option.second);
132
0
  }
133
0
}
Unexecuted instantiation: GenericDNSPacketWriter<std::__1::vector<unsigned char, std::__1::allocator<unsigned char> > >::addOpt(unsigned short, unsigned short, unsigned short, std::__1::vector<std::__1::pair<unsigned short, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, std::__1::allocator<std::__1::pair<unsigned short, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > > const&, unsigned char)
Unexecuted instantiation: GenericDNSPacketWriter<std::__1::vector<unsigned char, noinit_adaptor<std::__1::allocator<unsigned char> > > >::addOpt(unsigned short, unsigned short, unsigned short, std::__1::vector<std::__1::pair<unsigned short, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, std::__1::allocator<std::__1::pair<unsigned short, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > > const&, unsigned char)
134
135
template <typename Container> void GenericDNSPacketWriter<Container>::xfr48BitInt(uint64_t val)
136
0
{
137
0
  if ((val >> 48) != 0) {
138
0
    throw runtime_error("Value too large to fit in 48 bits");
139
0
  }
140
0
  std::array<unsigned char, 6> bytes;
141
0
  uint16_t theLeft = htons((val >> 32)&0xffffU);
142
0
  uint32_t theRight = htonl(val & 0xffffffffU);
143
0
  memcpy(&bytes[0], (void*)&theLeft, sizeof(theLeft));
144
0
  memcpy(&bytes[2], (void*)&theRight, sizeof(theRight));
145
146
0
  d_content.insert(d_content.end(), bytes.begin(), bytes.end());
147
0
}
Unexecuted instantiation: GenericDNSPacketWriter<std::__1::vector<unsigned char, std::__1::allocator<unsigned char> > >::xfr48BitInt(unsigned long)
Unexecuted instantiation: GenericDNSPacketWriter<std::__1::vector<unsigned char, noinit_adaptor<std::__1::allocator<unsigned char> > > >::xfr48BitInt(unsigned long)
148
149
template <typename Container> void GenericDNSPacketWriter<Container>::xfrNodeOrLocatorID(const NodeOrLocatorID& val)
150
0
{
151
0
  d_content.insert(d_content.end(), val.content, val.content + sizeof(val.content));
152
0
}
Unexecuted instantiation: GenericDNSPacketWriter<std::__1::vector<unsigned char, std::__1::allocator<unsigned char> > >::xfrNodeOrLocatorID(NodeOrLocatorID const&)
Unexecuted instantiation: GenericDNSPacketWriter<std::__1::vector<unsigned char, noinit_adaptor<std::__1::allocator<unsigned char> > > >::xfrNodeOrLocatorID(NodeOrLocatorID const&)
153
154
template <typename Container> void GenericDNSPacketWriter<Container>::xfr32BitInt(uint64_t val)
155
0
{
156
0
  if (val > std::numeric_limits<uint32_t>::max()) {
157
0
    throw runtime_error("Value too large to fit in 32 bits");
158
0
  }
159
0
  uint32_t rval=htonl(static_cast<uint32_t>(val));
160
0
  uint8_t* ptr=reinterpret_cast<uint8_t*>(&rval);
161
0
  d_content.insert(d_content.end(), ptr, ptr+4);
162
0
}
Unexecuted instantiation: GenericDNSPacketWriter<std::__1::vector<unsigned char, std::__1::allocator<unsigned char> > >::xfr32BitInt(unsigned long)
Unexecuted instantiation: GenericDNSPacketWriter<std::__1::vector<unsigned char, noinit_adaptor<std::__1::allocator<unsigned char> > > >::xfr32BitInt(unsigned long)
163
164
template <typename Container> void GenericDNSPacketWriter<Container>::xfr16BitInt(uint64_t val)
165
0
{
166
0
  if (val > std::numeric_limits<uint16_t>::max()) {
167
0
    throw runtime_error("Value too large to fit in 16 bits");
168
0
  }
169
0
  uint16_t rval=htons(static_cast<uint16_t>(val));
170
0
  uint8_t* ptr=reinterpret_cast<uint8_t*>(&rval);
171
0
  d_content.insert(d_content.end(), ptr, ptr+2);
172
0
}
Unexecuted instantiation: GenericDNSPacketWriter<std::__1::vector<unsigned char, std::__1::allocator<unsigned char> > >::xfr16BitInt(unsigned long)
Unexecuted instantiation: GenericDNSPacketWriter<std::__1::vector<unsigned char, noinit_adaptor<std::__1::allocator<unsigned char> > > >::xfr16BitInt(unsigned long)
173
174
template <typename Container> void GenericDNSPacketWriter<Container>::xfr8BitInt(uint64_t val)
175
0
{
176
0
  if (val > std::numeric_limits<uint8_t>::max()) {
177
0
    throw runtime_error("Value too large to fit in 8 bits");
178
0
  }
179
0
  d_content.push_back(static_cast<uint8_t>(val));
180
0
}
Unexecuted instantiation: GenericDNSPacketWriter<std::__1::vector<unsigned char, std::__1::allocator<unsigned char> > >::xfr8BitInt(unsigned long)
Unexecuted instantiation: GenericDNSPacketWriter<std::__1::vector<unsigned char, noinit_adaptor<std::__1::allocator<unsigned char> > > >::xfr8BitInt(unsigned long)
181
182
183
/* input:
184
 if lenField is true
185
  "" -> 0
186
  "blah" -> 4blah
187
  "blah" "blah" -> output 4blah4blah
188
  "verylongstringlongerthan256....characters" \xffverylongstring\x23characters (autosplit)
189
  "blah\"blah" -> 9blah"blah
190
  "blah\97" -> 5blahb
191
192
 if lenField is false
193
  "blah" -> blah
194
  "blah\"blah" -> blah"blah
195
  */
196
template <typename Container> void GenericDNSPacketWriter<Container>::xfrText(const string& text, bool, bool lenField)
197
0
{
198
0
  if(text.empty()) {
199
0
    d_content.push_back(0);
200
0
    return;
201
0
  }
202
0
  vector<string> segments = segmentDNSText(text);
203
0
  for(const string& str :  segments) {
204
0
    if(lenField)
205
0
      d_content.push_back(str.length());
206
0
    d_content.insert(d_content.end(), str.c_str(), str.c_str() + str.length());
207
0
  }
208
0
}
Unexecuted instantiation: GenericDNSPacketWriter<std::__1::vector<unsigned char, std::__1::allocator<unsigned char> > >::xfrText(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, bool, bool)
Unexecuted instantiation: GenericDNSPacketWriter<std::__1::vector<unsigned char, noinit_adaptor<std::__1::allocator<unsigned char> > > >::xfrText(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, bool, bool)
209
210
template <typename Container> void GenericDNSPacketWriter<Container>::xfrUnquotedText(const string& text, bool lenField)
211
0
{
212
0
  if(text.empty()) {
213
0
    d_content.push_back(0);
214
0
    return;
215
0
  }
216
0
  if (lenField) {
217
0
    if (text.length() > 255) {
218
0
      throw runtime_error("invalid unquoted text length");
219
0
    }
220
0
    d_content.push_back(text.length());
221
0
  }
222
0
  d_content.insert(d_content.end(), text.c_str(), text.c_str() + text.length());
223
0
}
Unexecuted instantiation: GenericDNSPacketWriter<std::__1::vector<unsigned char, std::__1::allocator<unsigned char> > >::xfrUnquotedText(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, bool)
Unexecuted instantiation: GenericDNSPacketWriter<std::__1::vector<unsigned char, noinit_adaptor<std::__1::allocator<unsigned char> > > >::xfrUnquotedText(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, bool)
224
225
226
static constexpr bool l_verbose=false;
227
static constexpr uint16_t maxCompressionOffset=16384;
228
template <typename Container> uint16_t GenericDNSPacketWriter<Container>::lookupName(const DNSName& name, uint16_t* matchLen)
229
0
{
230
  // iterate over the written labels, see if we find a match
231
0
  const auto& raw = name.getStorage();
232
233
  /* name might be a.root-servers.net, we need to be able to benefit from finding:
234
     b.root-servers.net, or even:
235
     b\xc0\x0c
236
  */
237
0
  unsigned int bestpos=0;
238
0
  *matchLen = 0;
239
240
  // positions of each label in the name we are trying to compress
241
0
  boost::container::static_vector<uint16_t, 34> positionsInName;
242
  // positions of labels in the packet we are building
243
0
  boost::container::static_vector<uint16_t, 34> positionsInPacket;
244
245
0
  try {
246
0
    for(auto riter= raw.cbegin(); riter < raw.cend(); ) {
247
0
      if (*riter == 0) {
248
0
        break;
249
0
      }
250
0
      positionsInName.push_back(riter - raw.cbegin());
251
0
      riter += *riter + 1;
252
0
    }
253
0
  }
254
0
  catch (const std::bad_alloc& ba) {
255
0
    if (l_verbose) {
256
0
      cout << "Domain " << name << " too large to compress" << endl;
257
0
    }
258
0
    return 0;
259
0
  }
260
261
0
  if (l_verbose) {
262
0
    cout<<"Input vector for lookup "<<name<<": ";
263
0
    for (const auto n : positionsInName) {
264
0
      cout << n << " ";
265
0
    }
266
0
    cout<<endl;
267
0
    cout<<makeHexDump(string(raw.c_str(), raw.c_str()+raw.size()))<<endl;
268
0
  }
269
270
0
  if (l_verbose) {
271
0
    cout << "Have " << d_namepositions.size() << " to ponder" << endl;
272
0
  }
273
274
0
  int counter=1;
275
0
  for (const auto positionInPacket : d_namepositions) {
276
    // here it's a bit tricky because the names might be compressed,
277
    // so we will gather all labels composing the name, following
278
    // pointers if needed
279
    // for example if there is an uncompressed \1a\1b\1c\0 we will store
280
    // the position of \1a, \1b, \1c
281
    // if there is instead \1a followed by a pointer to \1b\1c\0 earlier
282
    // in the packet we will store the position of \1a, \1b, \1c as well
283
    // they will just be disjoint
284
0
    if (l_verbose) {
285
0
      cout<<"Pos: "<<positionInPacket<<", "<<d_content.size()<<endl;
286
0
      DNSName pname(reinterpret_cast<const char*>(d_content.data()), d_content.size(), positionInPacket, true); // only for debugging
287
0
      cout<<"Looking at '"<<pname<<"' in packet at position "<<positionInPacket<<"/"<<d_content.size()<<", option "<<counter<<"/"<<d_namepositions.size()<<endl;
288
0
      ++counter;
289
0
    }
290
0
    size_t pointerQuota = 50U;
291
    // memcmp here makes things _slower_
292
0
    positionsInPacket.clear();
293
0
    try {
294
0
      for (auto iter = d_content.cbegin() + positionInPacket; iter < d_content.cend() && pointerQuota > 0;) {
295
0
        uint8_t labelLength = *iter;
296
0
        const uint16_t currentPos = (iter - d_content.cbegin());
297
0
        if (l_verbose) {
298
0
          cout << "Found label length: " << std::to_string(labelLength) << " at " << currentPos << endl;
299
0
        }
300
0
        if (labelLength & 0xc0) {
301
0
          uint16_t npos = 0x100*(labelLength & (~0xc0)) + *++iter;
302
          // check against going forward
303
0
          if (npos >= currentPos || npos < sizeof(dnsheader)) {
304
            /* something is not right */
305
0
            break;
306
0
          }
307
308
          // jump to the target of the pointer
309
0
          iter = d_content.begin() + npos;
310
0
          if (l_verbose) {
311
0
            cout << "Is compressed label to newpos " << npos << ", going there" << endl;
312
0
          }
313
314
0
          if (pointerQuota >= 1) {
315
0
            pointerQuota--;
316
0
            continue;
317
0
          }
318
319
          // out of pointer quota, let's stop there
320
0
          break;
321
0
        }
322
323
0
        if (labelLength == 0) {
324
0
          break;
325
0
        }
326
327
0
        if (currentPos >= maxCompressionOffset) {
328
0
          break; // compression pointers cannot point here
329
0
        }
330
331
0
        positionsInPacket.push_back(currentPos);
332
        // jump to the next label
333
0
        iter += labelLength + 1;
334
0
      }
335
0
    }
336
0
    catch (const std::bad_alloc& ba) {
337
0
      if (l_verbose) {
338
0
        cout << "Domain " << name << " too large to compress" << endl;
339
0
      }
340
0
      continue;
341
0
    }
342
343
0
    if (l_verbose) {
344
0
      cout<<"Packet vector: "<<endl;
345
0
      for (const auto n : positionsInPacket) {
346
0
        cout << n << " ";
347
0
      }
348
0
      cout<<endl;
349
0
    }
350
351
0
    auto positionInNameIter = positionsInName.crbegin();
352
0
    auto positionInPacketIter = positionsInPacket.crbegin();
353
0
    unsigned int cmatchlen=1;
354
0
    for(; positionInNameIter != positionsInName.crend() && positionInPacketIter != positionsInPacket.crend(); ++positionInNameIter, ++positionInPacketIter) {
355
      // positionInNameIter is an offset in raw, pvect an offset in packet
356
0
      uint8_t nlen = raw[*positionInNameIter];
357
0
      uint8_t plen = d_content[*positionInPacketIter];
358
359
0
      if (l_verbose) {
360
0
        cout << "nlnen=" << (int)nlen << ", plen=" << (int)plen << endl;
361
0
      }
362
363
0
      if (nlen != plen) {
364
0
        break;
365
0
      }
366
367
0
      if (strncasecmp(raw.c_str() + *positionInNameIter + 1, (const char*)&d_content[*positionInPacketIter] + 1, nlen)) {
368
0
        if (l_verbose) {
369
0
          cout << "Mismatch: " << string(raw.c_str() + *positionInNameIter + 1, raw.c_str() + *positionInNameIter + nlen + 1) << " != " << string((const char*)&d_content[*positionInPacketIter] + 1, (const char*)&d_content[*positionInPacketIter] + nlen + 1) << endl;
370
0
        }
371
0
        break;
372
0
      }
373
374
0
      cmatchlen += nlen + 1;
375
0
      if (cmatchlen == raw.length()) { // have matched all of it, can't improve
376
0
        if (l_verbose) {
377
0
          cout << "Stopping search, matched whole name" << endl;
378
0
        }
379
380
0
        *matchLen = cmatchlen;
381
0
        return *positionInPacketIter;
382
0
      }
383
0
    }
384
0
    if (positionInPacketIter != positionsInPacket.crbegin() && *matchLen < cmatchlen) {
385
0
      *matchLen = cmatchlen;
386
0
      bestpos = *--positionInPacketIter;
387
0
    }
388
0
  }
389
0
  return bestpos;
390
0
}
Unexecuted instantiation: GenericDNSPacketWriter<std::__1::vector<unsigned char, std::__1::allocator<unsigned char> > >::lookupName(DNSName const&, unsigned short*)
Unexecuted instantiation: GenericDNSPacketWriter<std::__1::vector<unsigned char, noinit_adaptor<std::__1::allocator<unsigned char> > > >::lookupName(DNSName const&, unsigned short*)
391
// this is the absolute hottest function in the pdns recursor
392
template <typename Container> void GenericDNSPacketWriter<Container>::xfrName(const DNSName& name, bool compress)
393
0
{
394
0
  if(l_verbose)
395
0
    cout<<"Wants to write "<<name<<", compress="<<compress<<", canonic="<<d_canonic<<", LC="<<d_lowerCase<<endl;
396
0
  if(d_canonic || d_lowerCase)   // d_lowerCase implies canonic
397
0
    compress=false;
398
399
0
  if(name.empty() || name.isRoot()) { // for speed
400
0
    d_content.push_back(0);
401
0
    return;
402
0
  }
403
404
0
  uint16_t li=0;
405
0
  uint16_t matchlen=0;
406
0
  if(d_compress && compress && (li=lookupName(name, &matchlen)) && li < maxCompressionOffset) {
407
0
    const auto& dns=name.getStorage();
408
0
    if(l_verbose)
409
0
      cout<<"Found a substring of "<<matchlen<<" bytes from the back, offset: "<<li<<", dnslen: "<<dns.size()<<endl;
410
    // found a substring, if www.powerdns.com matched powerdns.com, we get back matchlen = 13
411
412
0
    unsigned int pos=d_content.size();
413
0
    if(pos < maxCompressionOffset && matchlen != dns.size()) {
414
0
      if(l_verbose)
415
0
        cout<<"Inserting pos "<<pos<<" for "<<name<<" for compressed case"<<endl;
416
0
      d_namepositions.push_back(pos);
417
0
    }
418
419
0
    if(l_verbose)
420
0
      cout<<"Going to write unique part: '"<<makeHexDump(string(dns.c_str(), dns.c_str() + dns.size() - matchlen)) <<"'"<<endl;
421
0
    d_content.insert(d_content.end(), (const unsigned char*)dns.c_str(), (const unsigned char*)dns.c_str() + dns.size() - matchlen);
422
0
    uint16_t offset=li;
423
0
    offset|=0xc000;
424
425
0
    d_content.push_back((char)(offset >> 8));
426
0
    d_content.push_back((char)(offset & 0xff));
427
0
  }
428
0
  else {
429
0
    unsigned int pos=d_content.size();
430
0
    if(l_verbose)
431
0
      cout<<"Found nothing, we are at pos "<<pos<<", inserting whole name"<<endl;
432
0
    if(pos < maxCompressionOffset) {
433
0
      if(l_verbose)
434
0
        cout<<"Inserting pos "<<pos<<" for "<<name<<" for uncompressed case"<<endl;
435
0
      d_namepositions.push_back(pos);
436
0
    }
437
438
0
    std::unique_ptr<DNSName> lc;
439
0
    if(d_lowerCase)
440
0
      lc = make_unique<DNSName>(name.makeLowerCase());
441
442
0
    const DNSName::string_t& raw = (lc ? *lc : name).getStorage();
443
0
    if(l_verbose)
444
0
      cout<<"Writing out the whole thing "<<makeHexDump(string(raw.c_str(),  raw.c_str() + raw.length()))<<endl;
445
0
    d_content.insert(d_content.end(), raw.c_str(), raw.c_str() + raw.size());
446
0
  }
447
0
}
Unexecuted instantiation: GenericDNSPacketWriter<std::__1::vector<unsigned char, std::__1::allocator<unsigned char> > >::xfrName(DNSName const&, bool)
Unexecuted instantiation: GenericDNSPacketWriter<std::__1::vector<unsigned char, noinit_adaptor<std::__1::allocator<unsigned char> > > >::xfrName(DNSName const&, bool)
448
449
template <typename Container> void GenericDNSPacketWriter<Container>::xfrBlob(const string& blob, int  )
450
0
{
451
0
  const uint8_t* ptr=reinterpret_cast<const uint8_t*>(blob.c_str());
452
0
  d_content.insert(d_content.end(), ptr, ptr+blob.size());
453
0
}
Unexecuted instantiation: GenericDNSPacketWriter<std::__1::vector<unsigned char, std::__1::allocator<unsigned char> > >::xfrBlob(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, int)
Unexecuted instantiation: GenericDNSPacketWriter<std::__1::vector<unsigned char, noinit_adaptor<std::__1::allocator<unsigned char> > > >::xfrBlob(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, int)
454
455
template <typename Container> void GenericDNSPacketWriter<Container>::xfrBlob(const std::vector<uint8_t>& blob)
456
0
{
457
0
  d_content.insert(d_content.end(), blob.begin(), blob.end());
458
0
}
Unexecuted instantiation: GenericDNSPacketWriter<std::__1::vector<unsigned char, std::__1::allocator<unsigned char> > >::xfrBlob(std::__1::vector<unsigned char, std::__1::allocator<unsigned char> > const&)
Unexecuted instantiation: GenericDNSPacketWriter<std::__1::vector<unsigned char, noinit_adaptor<std::__1::allocator<unsigned char> > > >::xfrBlob(std::__1::vector<unsigned char, std::__1::allocator<unsigned char> > const&)
459
460
template <typename Container> void GenericDNSPacketWriter<Container>::xfrBlobNoSpaces(const string& blob, int  )
461
0
{
462
0
  xfrBlob(blob);
463
0
}
Unexecuted instantiation: GenericDNSPacketWriter<std::__1::vector<unsigned char, std::__1::allocator<unsigned char> > >::xfrBlobNoSpaces(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, int)
Unexecuted instantiation: GenericDNSPacketWriter<std::__1::vector<unsigned char, noinit_adaptor<std::__1::allocator<unsigned char> > > >::xfrBlobNoSpaces(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, int)
464
465
template <typename Container> void GenericDNSPacketWriter<Container>::xfrHexBlob(const string& blob, bool /* keepReading */)
466
0
{
467
0
  xfrBlob(blob);
468
0
}
Unexecuted instantiation: GenericDNSPacketWriter<std::__1::vector<unsigned char, std::__1::allocator<unsigned char> > >::xfrHexBlob(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, bool)
Unexecuted instantiation: GenericDNSPacketWriter<std::__1::vector<unsigned char, noinit_adaptor<std::__1::allocator<unsigned char> > > >::xfrHexBlob(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, bool)
469
470
template <typename Container> void GenericDNSPacketWriter<Container>::xfrSvcParamKeyVals(const std::set<SvcParam> &kvs)
471
0
{
472
0
  for (auto const &param : kvs) {
473
    // Key first!
474
0
    xfr16BitInt(param.getKey());
475
476
0
    switch (param.getKey())
477
0
    {
478
0
    case SvcParam::mandatory:
479
0
      xfr16BitInt(2 * param.getMandatory().size());
480
0
      for (auto const &m: param.getMandatory()) {
481
0
        xfr16BitInt(m);
482
0
      }
483
0
      break;
484
0
    case SvcParam::alpn:
485
0
    {
486
0
      size_t totalSize = param.getALPN().size(); // All 1 octet size headers for each value
487
0
      for (auto const &a : param.getALPN()) {
488
0
        totalSize += a.length();
489
0
      }
490
0
      if (totalSize > std::numeric_limits<uint16_t>::max()) {
491
0
        throw runtime_error("invalid total length of alpn parameters");
492
0
      }
493
0
      xfr16BitInt(static_cast<uint16_t>(totalSize));
494
0
      for (auto const &a : param.getALPN()) {
495
0
        xfrUnquotedText(a, true); // will add the 1-byte length field
496
0
      }
497
0
      break;
498
0
    }
499
0
    case SvcParam::no_default_alpn:
500
0
      xfr16BitInt(0); // no size :)
501
0
      break;
502
0
    case SvcParam::port:
503
0
      xfr16BitInt(2); // size
504
0
      xfr16BitInt(param.getPort());
505
0
      break;
506
0
    case SvcParam::ipv4hint:
507
0
      xfr16BitInt(param.getIPHints().size() * 4); // size
508
0
      for (const auto& a: param.getIPHints()) {
509
0
        xfrCAWithoutPort(param.getKey(), a);
510
0
      }
511
0
      break;
512
0
    case SvcParam::ipv6hint:
513
0
      xfr16BitInt(param.getIPHints().size() * 16); // size
514
0
      for (const auto& a: param.getIPHints()) {
515
0
        xfrCAWithoutPort(param.getKey(), a);
516
0
      }
517
0
      break;
518
0
    case SvcParam::ech:
519
0
      xfr16BitInt(param.getECH().size()); // size
520
0
      xfrBlobNoSpaces(param.getECH());
521
0
      break;
522
0
    case SvcParam::ohttp:
523
0
      xfr16BitInt(0); // no size
524
0
      break;
525
0
    case SvcParam::tls_supported_groups:
526
0
      xfr16BitInt(2 * param.getTLSSupportedGroups().size()); // size
527
0
      for (const auto& group: param.getTLSSupportedGroups()) {
528
0
        xfr16BitInt(group);
529
0
      }
530
0
      break;
531
0
    default:
532
0
      xfr16BitInt(param.getValue().size());
533
0
      xfrBlob(param.getValue());
534
0
      break;
535
0
    }
536
0
  }
537
0
}
Unexecuted instantiation: GenericDNSPacketWriter<std::__1::vector<unsigned char, std::__1::allocator<unsigned char> > >::xfrSvcParamKeyVals(std::__1::set<SvcParam, std::__1::less<SvcParam>, std::__1::allocator<SvcParam> > const&)
Unexecuted instantiation: GenericDNSPacketWriter<std::__1::vector<unsigned char, noinit_adaptor<std::__1::allocator<unsigned char> > > >::xfrSvcParamKeyVals(std::__1::set<SvcParam, std::__1::less<SvcParam>, std::__1::allocator<SvcParam> > const&)
538
539
// call __before commit__
540
template <typename Container> void GenericDNSPacketWriter<Container>::getRecordPayload(string& records)
541
0
{
542
0
  records.assign(d_content.begin() + d_sor, d_content.end());
543
0
}
Unexecuted instantiation: GenericDNSPacketWriter<std::__1::vector<unsigned char, std::__1::allocator<unsigned char> > >::getRecordPayload(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >&)
Unexecuted instantiation: GenericDNSPacketWriter<std::__1::vector<unsigned char, noinit_adaptor<std::__1::allocator<unsigned char> > > >::getRecordPayload(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >&)
544
545
// call __before commit__
546
template <typename Container> void GenericDNSPacketWriter<Container>::getWireFormatContent(string& record)
547
0
{
548
0
  record.assign(d_content.begin() + d_rollbackmarker, d_content.end());
549
0
}
Unexecuted instantiation: GenericDNSPacketWriter<std::__1::vector<unsigned char, std::__1::allocator<unsigned char> > >::getWireFormatContent(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >&)
Unexecuted instantiation: GenericDNSPacketWriter<std::__1::vector<unsigned char, noinit_adaptor<std::__1::allocator<unsigned char> > > >::getWireFormatContent(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >&)
550
551
template <typename Container> uint32_t GenericDNSPacketWriter<Container>::size() const
552
0
{
553
0
  return d_content.size();
554
0
}
Unexecuted instantiation: GenericDNSPacketWriter<std::__1::vector<unsigned char, std::__1::allocator<unsigned char> > >::size() const
Unexecuted instantiation: GenericDNSPacketWriter<std::__1::vector<unsigned char, noinit_adaptor<std::__1::allocator<unsigned char> > > >::size() const
555
556
template <typename Container> void GenericDNSPacketWriter<Container>::rollback()
557
0
{
558
0
  d_content.resize(d_rollbackmarker);
559
0
  d_sor = 0;
560
0
}
Unexecuted instantiation: GenericDNSPacketWriter<std::__1::vector<unsigned char, std::__1::allocator<unsigned char> > >::rollback()
Unexecuted instantiation: GenericDNSPacketWriter<std::__1::vector<unsigned char, noinit_adaptor<std::__1::allocator<unsigned char> > > >::rollback()
561
562
template <typename Container> void GenericDNSPacketWriter<Container>::truncate()
563
0
{
564
0
  d_content.resize(d_truncatemarker);
565
0
  dnsheader* dh=reinterpret_cast<dnsheader*>( &*d_content.begin());
566
0
  dh->ancount = dh->nscount = dh->arcount = 0;
567
0
}
Unexecuted instantiation: GenericDNSPacketWriter<std::__1::vector<unsigned char, std::__1::allocator<unsigned char> > >::truncate()
Unexecuted instantiation: GenericDNSPacketWriter<std::__1::vector<unsigned char, noinit_adaptor<std::__1::allocator<unsigned char> > > >::truncate()
568
569
template <typename Container> void GenericDNSPacketWriter<Container>::commit()
570
0
{
571
0
  if (d_sor == 0) {
572
0
    return;
573
0
  }
574
575
0
  if (d_sor < 2 || d_sor > d_content.size()) {
576
0
    throw std::range_error("Invalid start of record when trying to build a packet: " + std::to_string(d_sor) + " / " + std::to_string(d_content.size()));
577
0
  }
578
579
0
  if (d_content.size() > std::numeric_limits<uint16_t>::max()) {
580
0
    throw std::range_error("Trying to build a packet larger than " + std::to_string(std::numeric_limits<uint16_t>::max()) + " bytes");
581
0
  }
582
583
0
  uint16_t rlen = d_content.size() - d_sor;
584
0
  d_content.at(d_sor-2) = rlen >> 8;
585
0
  d_content.at(d_sor-1) = rlen & 0xff;
586
0
  d_sor = 0;
587
0
  auto* dh = reinterpret_cast<dnsheader*>( &*d_content.begin());
588
0
  switch(d_recordplace) {
589
0
  case DNSResourceRecord::QUESTION:
590
0
    dh->qdcount = htons(ntohs(dh->qdcount) + 1);
591
0
    break;
592
0
  case DNSResourceRecord::ANSWER:
593
0
    dh->ancount = htons(ntohs(dh->ancount) + 1);
594
0
    break;
595
0
  case DNSResourceRecord::AUTHORITY:
596
0
    dh->nscount = htons(ntohs(dh->nscount) + 1);
597
0
    break;
598
0
  case DNSResourceRecord::ADDITIONAL:
599
0
    dh->arcount = htons(ntohs(dh->arcount) + 1);
600
0
    break;
601
0
  }
602
603
0
}
Unexecuted instantiation: GenericDNSPacketWriter<std::__1::vector<unsigned char, std::__1::allocator<unsigned char> > >::commit()
Unexecuted instantiation: GenericDNSPacketWriter<std::__1::vector<unsigned char, noinit_adaptor<std::__1::allocator<unsigned char> > > >::commit()
604
605
template <typename Container> size_t GenericDNSPacketWriter<Container>::getSizeWithOpts(const optvect_t& options) const
606
0
{
607
0
  size_t result = size() + /* root */ 1 + DNS_TYPE_SIZE + DNS_CLASS_SIZE + DNS_TTL_SIZE + DNS_RDLENGTH_SIZE;
608
609
0
  for(auto const &option : options) {
610
0
    result += 4;
611
0
    result += option.second.size();
612
0
  }
613
614
0
  return result;
615
0
}
Unexecuted instantiation: GenericDNSPacketWriter<std::__1::vector<unsigned char, std::__1::allocator<unsigned char> > >::getSizeWithOpts(std::__1::vector<std::__1::pair<unsigned short, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, std::__1::allocator<std::__1::pair<unsigned short, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > > const&) const
Unexecuted instantiation: GenericDNSPacketWriter<std::__1::vector<unsigned char, noinit_adaptor<std::__1::allocator<unsigned char> > > >::getSizeWithOpts(std::__1::vector<std::__1::pair<unsigned short, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, std::__1::allocator<std::__1::pair<unsigned short, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > > const&) const
616
617
template class GenericDNSPacketWriter<std::vector<uint8_t>>;
618
#include "noinitvector.hh"
619
template class GenericDNSPacketWriter<PacketBuffer>;