Coverage Report

Created: 2026-04-06 06:13

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
  std::array<unsigned char, 6> bytes;
138
0
  uint16_t theLeft = htons((val >> 32)&0xffffU);
139
0
  uint32_t theRight = htonl(val & 0xffffffffU);
140
0
  memcpy(&bytes[0], (void*)&theLeft, sizeof(theLeft));
141
0
  memcpy(&bytes[2], (void*)&theRight, sizeof(theRight));
142
143
0
  d_content.insert(d_content.end(), bytes.begin(), bytes.end());
144
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)
145
146
template <typename Container> void GenericDNSPacketWriter<Container>::xfrNodeOrLocatorID(const NodeOrLocatorID& val)
147
0
{
148
0
  d_content.insert(d_content.end(), val.content, val.content + sizeof(val.content));
149
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&)
150
151
template <typename Container> void GenericDNSPacketWriter<Container>::xfr32BitInt(uint32_t val)
152
0
{
153
0
  uint32_t rval=htonl(val);
154
0
  uint8_t* ptr=reinterpret_cast<uint8_t*>(&rval);
155
0
  d_content.insert(d_content.end(), ptr, ptr+4);
156
0
}
Unexecuted instantiation: GenericDNSPacketWriter<std::__1::vector<unsigned char, std::__1::allocator<unsigned char> > >::xfr32BitInt(unsigned int)
Unexecuted instantiation: GenericDNSPacketWriter<std::__1::vector<unsigned char, noinit_adaptor<std::__1::allocator<unsigned char> > > >::xfr32BitInt(unsigned int)
157
158
template <typename Container> void GenericDNSPacketWriter<Container>::xfr16BitInt(uint16_t val)
159
0
{
160
0
  uint16_t rval=htons(val);
161
0
  uint8_t* ptr=reinterpret_cast<uint8_t*>(&rval);
162
0
  d_content.insert(d_content.end(), ptr, ptr+2);
163
0
}
Unexecuted instantiation: GenericDNSPacketWriter<std::__1::vector<unsigned char, std::__1::allocator<unsigned char> > >::xfr16BitInt(unsigned short)
Unexecuted instantiation: GenericDNSPacketWriter<std::__1::vector<unsigned char, noinit_adaptor<std::__1::allocator<unsigned char> > > >::xfr16BitInt(unsigned short)
164
165
template <typename Container> void GenericDNSPacketWriter<Container>::xfr8BitInt(uint8_t val)
166
0
{
167
0
  d_content.push_back(val);
168
0
}
Unexecuted instantiation: GenericDNSPacketWriter<std::__1::vector<unsigned char, std::__1::allocator<unsigned char> > >::xfr8BitInt(unsigned char)
Unexecuted instantiation: GenericDNSPacketWriter<std::__1::vector<unsigned char, noinit_adaptor<std::__1::allocator<unsigned char> > > >::xfr8BitInt(unsigned char)
169
170
171
/* input:
172
 if lenField is true
173
  "" -> 0
174
  "blah" -> 4blah
175
  "blah" "blah" -> output 4blah4blah
176
  "verylongstringlongerthan256....characters" \xffverylongstring\x23characters (autosplit)
177
  "blah\"blah" -> 9blah"blah
178
  "blah\97" -> 5blahb
179
180
 if lenField is false
181
  "blah" -> blah
182
  "blah\"blah" -> blah"blah
183
  */
184
template <typename Container> void GenericDNSPacketWriter<Container>::xfrText(const string& text, bool, bool lenField)
185
0
{
186
0
  if(text.empty()) {
187
0
    d_content.push_back(0);
188
0
    return;
189
0
  }
190
0
  vector<string> segments = segmentDNSText(text);
191
0
  for(const string& str :  segments) {
192
0
    if(lenField)
193
0
      d_content.push_back(str.length());
194
0
    d_content.insert(d_content.end(), str.c_str(), str.c_str() + str.length());
195
0
  }
196
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)
197
198
template <typename Container> void GenericDNSPacketWriter<Container>::xfrUnquotedText(const string& text, bool lenField)
199
0
{
200
0
  if(text.empty()) {
201
0
    d_content.push_back(0);
202
0
    return;
203
0
  }
204
0
  if(lenField)
205
0
    d_content.push_back(text.length());
206
0
  d_content.insert(d_content.end(), text.c_str(), text.c_str() + text.length());
207
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)
208
209
210
static constexpr bool l_verbose=false;
211
static constexpr uint16_t maxCompressionOffset=16384;
212
template <typename Container> uint16_t GenericDNSPacketWriter<Container>::lookupName(const DNSName& name, uint16_t* matchLen)
213
0
{
214
  // iterate over the written labels, see if we find a match
215
0
  const auto& raw = name.getStorage();
216
217
  /* name might be a.root-servers.net, we need to be able to benefit from finding:
218
     b.root-servers.net, or even:
219
     b\xc0\x0c
220
  */
221
0
  unsigned int bestpos=0;
222
0
  *matchLen = 0;
223
224
  // positions of each label in the name we are trying to compress
225
0
  boost::container::static_vector<uint16_t, 34> positionsInName;
226
  // positions of labels in the packet we are building
227
0
  boost::container::static_vector<uint16_t, 34> positionsInPacket;
228
229
0
  try {
230
0
    for(auto riter= raw.cbegin(); riter < raw.cend(); ) {
231
0
      if (*riter == 0) {
232
0
        break;
233
0
      }
234
0
      positionsInName.push_back(riter - raw.cbegin());
235
0
      riter += *riter + 1;
236
0
    }
237
0
  }
238
0
  catch (const std::bad_alloc& ba) {
239
0
    if (l_verbose) {
240
0
      cout << "Domain " << name << " too large to compress" << endl;
241
0
    }
242
0
    return 0;
243
0
  }
244
245
0
  if (l_verbose) {
246
0
    cout<<"Input vector for lookup "<<name<<": ";
247
0
    for (const auto n : positionsInName) {
248
0
      cout << n << " ";
249
0
    }
250
0
    cout<<endl;
251
0
    cout<<makeHexDump(string(raw.c_str(), raw.c_str()+raw.size()))<<endl;
252
0
  }
253
254
0
  if (l_verbose) {
255
0
    cout << "Have " << d_namepositions.size() << " to ponder" << endl;
256
0
  }
257
258
0
  int counter=1;
259
0
  for (const auto positionInPacket : d_namepositions) {
260
    // here it's a bit tricky because the names might be compressed,
261
    // so we will gather all labels composing the name, following
262
    // pointers if needed
263
    // for example if there is an uncompressed \1a\1b\1c\0 we will store
264
    // the position of \1a, \1b, \1c
265
    // if there is instead \1a followed by a pointer to \1b\1c\0 earlier
266
    // in the packet we will store the position of \1a, \1b, \1c as well
267
    // they will just be disjoint
268
0
    if (l_verbose) {
269
0
      cout<<"Pos: "<<positionInPacket<<", "<<d_content.size()<<endl;
270
0
      DNSName pname(reinterpret_cast<const char*>(d_content.data()), d_content.size(), positionInPacket, true); // only for debugging
271
0
      cout<<"Looking at '"<<pname<<"' in packet at position "<<positionInPacket<<"/"<<d_content.size()<<", option "<<counter<<"/"<<d_namepositions.size()<<endl;
272
0
      ++counter;
273
0
    }
274
0
    size_t pointerQuota = 50U;
275
    // memcmp here makes things _slower_
276
0
    positionsInPacket.clear();
277
0
    try {
278
0
      for (auto iter = d_content.cbegin() + positionInPacket; iter < d_content.cend() && pointerQuota > 0;) {
279
0
        uint8_t labelLength = *iter;
280
0
        const uint16_t currentPos = (iter - d_content.cbegin());
281
0
        if (l_verbose) {
282
0
          cout << "Found label length: " << std::to_string(labelLength) << " at " << currentPos << endl;
283
0
        }
284
0
        if (labelLength & 0xc0) {
285
0
          uint16_t npos = 0x100*(labelLength & (~0xc0)) + *++iter;
286
          // check against going forward
287
0
          if (npos >= currentPos || npos < sizeof(dnsheader)) {
288
            /* something is not right */
289
0
            break;
290
0
          }
291
292
          // jump to the target of the pointer
293
0
          iter = d_content.begin() + npos;
294
0
          if (l_verbose) {
295
0
            cout << "Is compressed label to newpos " << npos << ", going there" << endl;
296
0
          }
297
298
0
          if (pointerQuota >= 1) {
299
0
            pointerQuota--;
300
0
            continue;
301
0
          }
302
303
          // out of pointer quota, let's stop there
304
0
          break;
305
0
        }
306
307
0
        if (labelLength == 0) {
308
0
          break;
309
0
        }
310
311
0
        if (currentPos >= maxCompressionOffset) {
312
0
          break; // compression pointers cannot point here
313
0
        }
314
315
0
        positionsInPacket.push_back(currentPos);
316
        // jump to the next label
317
0
        iter += labelLength + 1;
318
0
      }
319
0
    }
320
0
    catch (const std::bad_alloc& ba) {
321
0
      if (l_verbose) {
322
0
        cout << "Domain " << name << " too large to compress" << endl;
323
0
      }
324
0
      continue;
325
0
    }
326
327
0
    if (l_verbose) {
328
0
      cout<<"Packet vector: "<<endl;
329
0
      for (const auto n : positionsInPacket) {
330
0
        cout << n << " ";
331
0
      }
332
0
      cout<<endl;
333
0
    }
334
335
0
    auto positionInNameIter = positionsInName.crbegin();
336
0
    auto positionInPacketIter = positionsInPacket.crbegin();
337
0
    unsigned int cmatchlen=1;
338
0
    for(; positionInNameIter != positionsInName.crend() && positionInPacketIter != positionsInPacket.crend(); ++positionInNameIter, ++positionInPacketIter) {
339
      // positionInNameIter is an offset in raw, pvect an offset in packet
340
0
      uint8_t nlen = raw[*positionInNameIter];
341
0
      uint8_t plen = d_content[*positionInPacketIter];
342
343
0
      if (l_verbose) {
344
0
        cout << "nlnen=" << (int)nlen << ", plen=" << (int)plen << endl;
345
0
      }
346
347
0
      if (nlen != plen) {
348
0
        break;
349
0
      }
350
351
0
      if (strncasecmp(raw.c_str() + *positionInNameIter + 1, (const char*)&d_content[*positionInPacketIter] + 1, nlen)) {
352
0
        if (l_verbose) {
353
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;
354
0
        }
355
0
        break;
356
0
      }
357
358
0
      cmatchlen += nlen + 1;
359
0
      if (cmatchlen == raw.length()) { // have matched all of it, can't improve
360
0
        if (l_verbose) {
361
0
          cout << "Stopping search, matched whole name" << endl;
362
0
        }
363
364
0
        *matchLen = cmatchlen;
365
0
        return *positionInPacketIter;
366
0
      }
367
0
    }
368
0
    if (positionInPacketIter != positionsInPacket.crbegin() && *matchLen < cmatchlen) {
369
0
      *matchLen = cmatchlen;
370
0
      bestpos = *--positionInPacketIter;
371
0
    }
372
0
  }
373
0
  return bestpos;
374
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*)
375
// this is the absolute hottest function in the pdns recursor
376
template <typename Container> void GenericDNSPacketWriter<Container>::xfrName(const DNSName& name, bool compress)
377
0
{
378
0
  if(l_verbose)
379
0
    cout<<"Wants to write "<<name<<", compress="<<compress<<", canonic="<<d_canonic<<", LC="<<d_lowerCase<<endl;
380
0
  if(d_canonic || d_lowerCase)   // d_lowerCase implies canonic
381
0
    compress=false;
382
383
0
  if(name.empty() || name.isRoot()) { // for speed
384
0
    d_content.push_back(0);
385
0
    return;
386
0
  }
387
388
0
  uint16_t li=0;
389
0
  uint16_t matchlen=0;
390
0
  if(d_compress && compress && (li=lookupName(name, &matchlen)) && li < maxCompressionOffset) {
391
0
    const auto& dns=name.getStorage();
392
0
    if(l_verbose)
393
0
      cout<<"Found a substring of "<<matchlen<<" bytes from the back, offset: "<<li<<", dnslen: "<<dns.size()<<endl;
394
    // found a substring, if www.powerdns.com matched powerdns.com, we get back matchlen = 13
395
396
0
    unsigned int pos=d_content.size();
397
0
    if(pos < maxCompressionOffset && matchlen != dns.size()) {
398
0
      if(l_verbose)
399
0
        cout<<"Inserting pos "<<pos<<" for "<<name<<" for compressed case"<<endl;
400
0
      d_namepositions.push_back(pos);
401
0
    }
402
403
0
    if(l_verbose)
404
0
      cout<<"Going to write unique part: '"<<makeHexDump(string(dns.c_str(), dns.c_str() + dns.size() - matchlen)) <<"'"<<endl;
405
0
    d_content.insert(d_content.end(), (const unsigned char*)dns.c_str(), (const unsigned char*)dns.c_str() + dns.size() - matchlen);
406
0
    uint16_t offset=li;
407
0
    offset|=0xc000;
408
409
0
    d_content.push_back((char)(offset >> 8));
410
0
    d_content.push_back((char)(offset & 0xff));
411
0
  }
412
0
  else {
413
0
    unsigned int pos=d_content.size();
414
0
    if(l_verbose)
415
0
      cout<<"Found nothing, we are at pos "<<pos<<", inserting whole name"<<endl;
416
0
    if(pos < maxCompressionOffset) {
417
0
      if(l_verbose)
418
0
        cout<<"Inserting pos "<<pos<<" for "<<name<<" for uncompressed case"<<endl;
419
0
      d_namepositions.push_back(pos);
420
0
    }
421
422
0
    std::unique_ptr<DNSName> lc;
423
0
    if(d_lowerCase)
424
0
      lc = make_unique<DNSName>(name.makeLowerCase());
425
426
0
    const DNSName::string_t& raw = (lc ? *lc : name).getStorage();
427
0
    if(l_verbose)
428
0
      cout<<"Writing out the whole thing "<<makeHexDump(string(raw.c_str(),  raw.c_str() + raw.length()))<<endl;
429
0
    d_content.insert(d_content.end(), raw.c_str(), raw.c_str() + raw.size());
430
0
  }
431
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)
432
433
template <typename Container> void GenericDNSPacketWriter<Container>::xfrBlob(const string& blob, int  )
434
0
{
435
0
  const uint8_t* ptr=reinterpret_cast<const uint8_t*>(blob.c_str());
436
0
  d_content.insert(d_content.end(), ptr, ptr+blob.size());
437
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)
438
439
template <typename Container> void GenericDNSPacketWriter<Container>::xfrBlob(const std::vector<uint8_t>& blob)
440
0
{
441
0
  d_content.insert(d_content.end(), blob.begin(), blob.end());
442
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&)
443
444
template <typename Container> void GenericDNSPacketWriter<Container>::xfrBlobNoSpaces(const string& blob, int  )
445
0
{
446
0
  xfrBlob(blob);
447
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)
448
449
template <typename Container> void GenericDNSPacketWriter<Container>::xfrHexBlob(const string& blob, bool /* keepReading */)
450
0
{
451
0
  xfrBlob(blob);
452
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)
453
454
template <typename Container> void GenericDNSPacketWriter<Container>::xfrSvcParamKeyVals(const std::set<SvcParam> &kvs)
455
0
{
456
0
  for (auto const &param : kvs) {
457
    // Key first!
458
0
    xfr16BitInt(param.getKey());
459
460
0
    switch (param.getKey())
461
0
    {
462
0
    case SvcParam::mandatory:
463
0
      xfr16BitInt(2 * param.getMandatory().size());
464
0
      for (auto const &m: param.getMandatory()) {
465
0
        xfr16BitInt(m);
466
0
      }
467
0
      break;
468
0
    case SvcParam::alpn:
469
0
    {
470
0
      uint16_t totalSize = param.getALPN().size(); // All 1 octet size headers for each value
471
0
      for (auto const &a : param.getALPN()) {
472
0
        totalSize += a.length();
473
0
      }
474
0
      xfr16BitInt(totalSize);
475
0
      for (auto const &a : param.getALPN()) {
476
0
        xfrUnquotedText(a, true); // will add the 1-byte length field
477
0
      }
478
0
      break;
479
0
    }
480
0
    case SvcParam::no_default_alpn:
481
0
      xfr16BitInt(0); // no size :)
482
0
      break;
483
0
    case SvcParam::port:
484
0
      xfr16BitInt(2); // size
485
0
      xfr16BitInt(param.getPort());
486
0
      break;
487
0
    case SvcParam::ipv4hint:
488
0
      xfr16BitInt(param.getIPHints().size() * 4); // size
489
0
      for (const auto& a: param.getIPHints()) {
490
0
        xfrCAWithoutPort(param.getKey(), a);
491
0
      }
492
0
      break;
493
0
    case SvcParam::ipv6hint:
494
0
      xfr16BitInt(param.getIPHints().size() * 16); // size
495
0
      for (const auto& a: param.getIPHints()) {
496
0
        xfrCAWithoutPort(param.getKey(), a);
497
0
      }
498
0
      break;
499
0
    case SvcParam::ech:
500
0
      xfr16BitInt(param.getECH().size()); // size
501
0
      xfrBlobNoSpaces(param.getECH());
502
0
      break;
503
0
    case SvcParam::ohttp:
504
0
      xfr16BitInt(0); // no size
505
0
      break;
506
0
    case SvcParam::tls_supported_groups:
507
0
      xfr16BitInt(2 * param.getTLSSupportedGroups().size()); // size
508
0
      for (const auto& group: param.getTLSSupportedGroups()) {
509
0
        xfr16BitInt(group);
510
0
      }
511
0
      break;
512
0
    default:
513
0
      xfr16BitInt(param.getValue().size());
514
0
      xfrBlob(param.getValue());
515
0
      break;
516
0
    }
517
0
  }
518
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&)
519
520
// call __before commit__
521
template <typename Container> void GenericDNSPacketWriter<Container>::getRecordPayload(string& records)
522
0
{
523
0
  records.assign(d_content.begin() + d_sor, d_content.end());
524
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> >&)
525
526
// call __before commit__
527
template <typename Container> void GenericDNSPacketWriter<Container>::getWireFormatContent(string& record)
528
0
{
529
0
  record.assign(d_content.begin() + d_rollbackmarker, d_content.end());
530
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> >&)
531
532
template <typename Container> uint32_t GenericDNSPacketWriter<Container>::size() const
533
0
{
534
0
  return d_content.size();
535
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
536
537
template <typename Container> void GenericDNSPacketWriter<Container>::rollback()
538
0
{
539
0
  d_content.resize(d_rollbackmarker);
540
0
  d_sor = 0;
541
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()
542
543
template <typename Container> void GenericDNSPacketWriter<Container>::truncate()
544
0
{
545
0
  d_content.resize(d_truncatemarker);
546
0
  dnsheader* dh=reinterpret_cast<dnsheader*>( &*d_content.begin());
547
0
  dh->ancount = dh->nscount = dh->arcount = 0;
548
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()
549
550
template <typename Container> void GenericDNSPacketWriter<Container>::commit()
551
0
{
552
0
  if (d_sor == 0) {
553
0
    return;
554
0
  }
555
556
0
  if (d_sor < 2 || d_sor > d_content.size()) {
557
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()));
558
0
  }
559
560
0
  if (d_content.size() > std::numeric_limits<uint16_t>::max()) {
561
0
    throw std::range_error("Trying to build a packet larger than " + std::to_string(std::numeric_limits<uint16_t>::max()) + " bytes");
562
0
  }
563
564
0
  uint16_t rlen = d_content.size() - d_sor;
565
0
  d_content.at(d_sor-2) = rlen >> 8;
566
0
  d_content.at(d_sor-1) = rlen & 0xff;
567
0
  d_sor = 0;
568
0
  auto* dh = reinterpret_cast<dnsheader*>( &*d_content.begin());
569
0
  switch(d_recordplace) {
570
0
  case DNSResourceRecord::QUESTION:
571
0
    dh->qdcount = htons(ntohs(dh->qdcount) + 1);
572
0
    break;
573
0
  case DNSResourceRecord::ANSWER:
574
0
    dh->ancount = htons(ntohs(dh->ancount) + 1);
575
0
    break;
576
0
  case DNSResourceRecord::AUTHORITY:
577
0
    dh->nscount = htons(ntohs(dh->nscount) + 1);
578
0
    break;
579
0
  case DNSResourceRecord::ADDITIONAL:
580
0
    dh->arcount = htons(ntohs(dh->arcount) + 1);
581
0
    break;
582
0
  }
583
584
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()
585
586
template <typename Container> size_t GenericDNSPacketWriter<Container>::getSizeWithOpts(const optvect_t& options) const
587
0
{
588
0
  size_t result = size() + /* root */ 1 + DNS_TYPE_SIZE + DNS_CLASS_SIZE + DNS_TTL_SIZE + DNS_RDLENGTH_SIZE;
589
590
0
  for(auto const &option : options) {
591
0
    result += 4;
592
0
    result += option.second.size();
593
0
  }
594
595
0
  return result;
596
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
597
598
template class GenericDNSPacketWriter<std::vector<uint8_t>>;
599
#include "noinitvector.hh"
600
template class GenericDNSPacketWriter<PacketBuffer>;