Coverage Report

Created: 2026-08-13 06:11

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/pdns/pdns/dnsdistdist/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
8.77k
  d_qname(qname), d_content(content)
44
8.77k
{
45
8.77k
  d_content.clear();
46
8.77k
  dnsheader dnsheader;
47
48
8.77k
  memset(&dnsheader, 0, sizeof(dnsheader));
49
8.77k
  dnsheader.id=0;
50
8.77k
  dnsheader.qdcount=htons(1);
51
8.77k
  dnsheader.opcode=opcode;
52
53
8.77k
  const uint8_t* ptr=(const uint8_t*)&dnsheader;
54
8.77k
  d_content.reserve(sizeof(dnsheader) + qname.wirelength() + sizeof(qtype) + sizeof(qclass));
55
8.77k
  d_content.resize(sizeof(dnsheader));
56
8.77k
  uint8_t* dptr=(&*d_content.begin());
57
58
8.77k
  memcpy(dptr, ptr, sizeof(dnsheader));
59
8.77k
  d_namepositions.reserve(16);
60
8.77k
  xfrName(qname, false);
61
8.77k
  xfr16BitInt(qtype);
62
8.77k
  xfr16BitInt(qclass);
63
64
8.77k
  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
8.77k
  d_truncatemarker = d_content.size();
68
8.77k
}
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)
Line
Count
Source
43
8.77k
  d_qname(qname), d_content(content)
44
8.77k
{
45
8.77k
  d_content.clear();
46
8.77k
  dnsheader dnsheader;
47
48
8.77k
  memset(&dnsheader, 0, sizeof(dnsheader));
49
8.77k
  dnsheader.id=0;
50
8.77k
  dnsheader.qdcount=htons(1);
51
8.77k
  dnsheader.opcode=opcode;
52
53
8.77k
  const uint8_t* ptr=(const uint8_t*)&dnsheader;
54
8.77k
  d_content.reserve(sizeof(dnsheader) + qname.wirelength() + sizeof(qtype) + sizeof(qclass));
55
8.77k
  d_content.resize(sizeof(dnsheader));
56
8.77k
  uint8_t* dptr=(&*d_content.begin());
57
58
8.77k
  memcpy(dptr, ptr, sizeof(dnsheader));
59
8.77k
  d_namepositions.reserve(16);
60
8.77k
  xfrName(qname, false);
61
8.77k
  xfr16BitInt(qtype);
62
8.77k
  xfr16BitInt(qclass);
63
64
8.77k
  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
8.77k
  d_truncatemarker = d_content.size();
68
8.77k
}
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
17.0k
{
78
17.0k
  d_compress = compress;
79
17.0k
  commit();
80
17.0k
  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
17.0k
  d_rollbackmarker = d_content.size();
84
85
17.0k
  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
17.0k
  else {
90
17.0k
    xfrName(name, compress);
91
17.0k
  }
92
17.0k
  xfr16BitInt(qtype);
93
17.0k
  xfr16BitInt(qclass);
94
17.0k
  xfr32BitInt(ttl);
95
17.0k
  xfr16BitInt(0); // this will be the record size
96
17.0k
  d_recordplace = place;
97
98
17.0k
  d_sor = d_content.size(); // this will remind us where to stuff the record size
99
17.0k
}
GenericDNSPacketWriter<std::__1::vector<unsigned char, std::__1::allocator<unsigned char> > >::startRecord(DNSName const&, unsigned short, unsigned int, unsigned short, DNSResourceRecord::Place, bool)
Line
Count
Source
77
17.0k
{
78
17.0k
  d_compress = compress;
79
17.0k
  commit();
80
17.0k
  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
17.0k
  d_rollbackmarker = d_content.size();
84
85
17.0k
  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
17.0k
  else {
90
17.0k
    xfrName(name, compress);
91
17.0k
  }
92
17.0k
  xfr16BitInt(qtype);
93
17.0k
  xfr16BitInt(qclass);
94
17.0k
  xfr32BitInt(ttl);
95
17.0k
  xfr16BitInt(0); // this will be the record size
96
17.0k
  d_recordplace = place;
97
98
17.0k
  d_sor = d_content.size(); // this will remind us where to stuff the record size
99
17.0k
}
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
1.03k
{
103
1.03k
  uint32_t ttl=0;
104
105
1.03k
  EDNS0Record stuff;
106
107
1.03k
  stuff.version = version;
108
1.03k
  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
1.03k
  stuff.extRCode = extRCode>>4;
118
1.03k
  if (extRCode != 0) { // As this trumps the existing RCODE
119
0
    getHeader()->rcode = extRCode;
120
0
  }
121
122
1.03k
  static_assert(sizeof(EDNS0Record) == sizeof(ttl), "sizeof(EDNS0Record) must match sizeof(ttl)");
123
1.03k
  memcpy(&ttl, &stuff, sizeof(stuff));
124
125
1.03k
  ttl=ntohl(ttl); // will be reversed later on
126
127
1.03k
  startRecord(g_rootdnsname, QType::OPT, ttl, udpsize, DNSResourceRecord::ADDITIONAL, false);
128
40.5k
  for(auto const &option : options) {
129
40.5k
    xfr16BitInt(option.first);
130
40.5k
    xfr16BitInt(option.second.length());
131
40.5k
    xfrBlob(option.second);
132
40.5k
  }
133
1.03k
}
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)
Line
Count
Source
102
1.03k
{
103
1.03k
  uint32_t ttl=0;
104
105
1.03k
  EDNS0Record stuff;
106
107
1.03k
  stuff.version = version;
108
1.03k
  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
1.03k
  stuff.extRCode = extRCode>>4;
118
1.03k
  if (extRCode != 0) { // As this trumps the existing RCODE
119
0
    getHeader()->rcode = extRCode;
120
0
  }
121
122
1.03k
  static_assert(sizeof(EDNS0Record) == sizeof(ttl), "sizeof(EDNS0Record) must match sizeof(ttl)");
123
1.03k
  memcpy(&ttl, &stuff, sizeof(stuff));
124
125
1.03k
  ttl=ntohl(ttl); // will be reversed later on
126
127
1.03k
  startRecord(g_rootdnsname, QType::OPT, ttl, udpsize, DNSResourceRecord::ADDITIONAL, false);
128
40.5k
  for(auto const &option : options) {
129
40.5k
    xfr16BitInt(option.first);
130
40.5k
    xfr16BitInt(option.second.length());
131
40.5k
    xfrBlob(option.second);
132
40.5k
  }
133
1.03k
}
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
12
{
151
12
  d_content.insert(d_content.end(), val.content, val.content + sizeof(val.content));
152
12
}
GenericDNSPacketWriter<std::__1::vector<unsigned char, std::__1::allocator<unsigned char> > >::xfrNodeOrLocatorID(NodeOrLocatorID const&)
Line
Count
Source
150
12
{
151
12
  d_content.insert(d_content.end(), val.content, val.content + sizeof(val.content));
152
12
}
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
331k
{
156
331k
  if (val > std::numeric_limits<uint32_t>::max()) {
157
0
    throw runtime_error("Value too large to fit in 32 bits");
158
0
  }
159
331k
  uint32_t rval=htonl(static_cast<uint32_t>(val));
160
331k
  uint8_t* ptr=reinterpret_cast<uint8_t*>(&rval);
161
331k
  d_content.insert(d_content.end(), ptr, ptr+4);
162
331k
}
GenericDNSPacketWriter<std::__1::vector<unsigned char, std::__1::allocator<unsigned char> > >::xfr32BitInt(unsigned long)
Line
Count
Source
155
331k
{
156
331k
  if (val > std::numeric_limits<uint32_t>::max()) {
157
0
    throw runtime_error("Value too large to fit in 32 bits");
158
0
  }
159
331k
  uint32_t rval=htonl(static_cast<uint32_t>(val));
160
331k
  uint8_t* ptr=reinterpret_cast<uint8_t*>(&rval);
161
331k
  d_content.insert(d_content.end(), ptr, ptr+4);
162
331k
}
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
353k
{
166
353k
  if (val > std::numeric_limits<uint16_t>::max()) {
167
1
    throw runtime_error("Value too large to fit in 16 bits");
168
1
  }
169
353k
  uint16_t rval=htons(static_cast<uint16_t>(val));
170
353k
  uint8_t* ptr=reinterpret_cast<uint8_t*>(&rval);
171
353k
  d_content.insert(d_content.end(), ptr, ptr+2);
172
353k
}
GenericDNSPacketWriter<std::__1::vector<unsigned char, std::__1::allocator<unsigned char> > >::xfr16BitInt(unsigned long)
Line
Count
Source
165
353k
{
166
353k
  if (val > std::numeric_limits<uint16_t>::max()) {
167
1
    throw runtime_error("Value too large to fit in 16 bits");
168
1
  }
169
353k
  uint16_t rval=htons(static_cast<uint16_t>(val));
170
353k
  uint8_t* ptr=reinterpret_cast<uint8_t*>(&rval);
171
353k
  d_content.insert(d_content.end(), ptr, ptr+2);
172
353k
}
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
247k
{
176
247k
  if (val > std::numeric_limits<uint8_t>::max()) {
177
21
    throw runtime_error("Value too large to fit in 8 bits");
178
21
  }
179
247k
  d_content.push_back(static_cast<uint8_t>(val));
180
247k
}
GenericDNSPacketWriter<std::__1::vector<unsigned char, std::__1::allocator<unsigned char> > >::xfr8BitInt(unsigned long)
Line
Count
Source
175
247k
{
176
247k
  if (val > std::numeric_limits<uint8_t>::max()) {
177
21
    throw runtime_error("Value too large to fit in 8 bits");
178
21
  }
179
247k
  d_content.push_back(static_cast<uint8_t>(val));
180
247k
}
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
993
{
198
993
  if(text.empty()) {
199
207
    d_content.push_back(0);
200
207
    return;
201
207
  }
202
786
  vector<string> segments = segmentDNSText(text);
203
170k
  for(const string& str :  segments) {
204
170k
    if(lenField)
205
167k
      d_content.push_back(str.length());
206
170k
    d_content.insert(d_content.end(), str.c_str(), str.c_str() + str.length());
207
170k
  }
208
786
}
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)
Line
Count
Source
197
993
{
198
993
  if(text.empty()) {
199
207
    d_content.push_back(0);
200
207
    return;
201
207
  }
202
786
  vector<string> segments = segmentDNSText(text);
203
170k
  for(const string& str :  segments) {
204
170k
    if(lenField)
205
167k
      d_content.push_back(str.length());
206
170k
    d_content.insert(d_content.end(), str.c_str(), str.c_str() + str.length());
207
170k
  }
208
786
}
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
251k
{
212
251k
  if(text.empty()) {
213
0
    d_content.push_back(0);
214
0
    return;
215
0
  }
216
251k
  if (lenField) {
217
251k
    if (text.length() > 255) {
218
26
      throw runtime_error("invalid unquoted text length");
219
26
    }
220
251k
    d_content.push_back(text.length());
221
251k
  }
222
251k
  d_content.insert(d_content.end(), text.c_str(), text.c_str() + text.length());
223
251k
}
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)
Line
Count
Source
211
251k
{
212
251k
  if(text.empty()) {
213
0
    d_content.push_back(0);
214
0
    return;
215
0
  }
216
251k
  if (lenField) {
217
251k
    if (text.length() > 255) {
218
26
      throw runtime_error("invalid unquoted text length");
219
26
    }
220
251k
    d_content.push_back(text.length());
221
251k
  }
222
251k
  d_content.insert(d_content.end(), text.c_str(), text.c_str() + text.length());
223
251k
}
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) // NOLINT(readability-function-cognitive-complexity)
229
7.04k
{
230
  // iterate over the written labels, see if we find a match
231
7.04k
  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
7.04k
  unsigned int bestpos=0;
238
7.04k
  *matchLen = 0;
239
240
  // positions of each label in the name we are trying to compress
241
7.04k
  boost::container::static_vector<uint16_t, 34> positionsInName;
242
  // positions of labels in the packet we are building
243
7.04k
  boost::container::static_vector<uint16_t, 34> positionsInPacket;
244
245
7.04k
  try {
246
25.7k
    for(auto riter= raw.cbegin(); riter < raw.cend(); ) {
247
25.7k
      if (*riter == 0) {
248
7.04k
        break;
249
7.04k
      }
250
18.7k
      positionsInName.push_back(riter - raw.cbegin());
251
18.7k
      riter += *riter + 1;
252
18.7k
    }
253
7.04k
  }
254
7.04k
  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
7.04k
  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
7.04k
  if (l_verbose) {
271
0
    cout << "Have " << d_namepositions.size() << " to ponder" << endl;
272
0
  }
273
274
7.04k
  int counter=1;
275
7.04k
  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
5.64k
    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
5.64k
    size_t pointerQuota = 50U;
291
    // memcmp here makes things _slower_
292
5.64k
    positionsInPacket.clear();
293
5.64k
    try {
294
23.6k
      for (auto iter = d_content.cbegin() + positionInPacket; iter < d_content.cend() && pointerQuota > 0;) {
295
23.6k
        uint8_t labelLength = *iter;
296
23.6k
        const uint16_t currentPos = (iter - d_content.cbegin());
297
23.6k
        if (l_verbose) {
298
0
          cout << "Found label length: " << std::to_string(labelLength) << " at " << currentPos << endl;
299
0
        }
300
23.6k
        if (labelLength & 0xc0) {
301
2.53k
          uint16_t npos = 0x100*(labelLength & (~0xc0)) + *++iter;
302
          // check against going forward
303
2.53k
          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
2.53k
          iter = d_content.begin() + npos;
310
2.53k
          if (l_verbose) {
311
0
            cout << "Is compressed label to newpos " << npos << ", going there" << endl;
312
0
          }
313
314
2.53k
          if (pointerQuota >= 1) {
315
2.53k
            pointerQuota--;
316
2.53k
            continue;
317
2.53k
          }
318
319
          // out of pointer quota, let's stop there
320
0
          break;
321
2.53k
        }
322
323
21.0k
        if (labelLength == 0) {
324
5.60k
          break;
325
5.60k
        }
326
327
15.4k
        if (currentPos >= maxCompressionOffset) {
328
35
          break; // compression pointers cannot point here
329
35
        }
330
331
15.4k
        positionsInPacket.push_back(currentPos);
332
        // jump to the next label
333
15.4k
        iter += labelLength + 1;
334
15.4k
      }
335
5.64k
    }
336
5.64k
    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
5.64k
    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
5.64k
    auto positionInNameIter = positionsInName.crbegin();
352
5.64k
    auto positionInPacketIter = positionsInPacket.crbegin();
353
5.64k
    unsigned int cmatchlen=1;
354
14.4k
    for(; positionInNameIter != positionsInName.crend() && positionInPacketIter != positionsInPacket.crend(); ++positionInNameIter, ++positionInPacketIter) {
355
      // positionInNameIter is an offset in raw, pvect an offset in packet
356
13.5k
      uint8_t nlen = raw[*positionInNameIter];
357
13.5k
      uint8_t plen = d_content[*positionInPacketIter];
358
359
13.5k
      if (l_verbose) {
360
0
        cout << "nlnen=" << (int)nlen << ", plen=" << (int)plen << endl;
361
0
      }
362
363
13.5k
      if (nlen != plen) {
364
2.92k
        break;
365
2.92k
      }
366
367
10.6k
      auto rawpart = std::string_view(raw.c_str() + *positionInNameIter + 1, nlen); // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
368
10.6k
      auto pktpart = std::string_view((const char*)&d_content[*positionInPacketIter] + 1, nlen); // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
369
10.6k
      if (pdns_ilexicographical_compare_three_way(rawpart, pktpart) != 0) {
370
512
        if (l_verbose) {
371
0
          cout << "Mismatch: " << rawpart << " != " << pktpart << endl;
372
0
        }
373
512
        break;
374
512
      }
375
376
10.1k
      cmatchlen += nlen + 1;
377
10.1k
      if (cmatchlen == raw.length()) { // have matched all of it, can't improve
378
1.29k
        if (l_verbose) {
379
0
          cout << "Stopping search, matched whole name" << endl;
380
0
        }
381
382
1.29k
        *matchLen = cmatchlen;
383
1.29k
        return *positionInPacketIter;
384
1.29k
      }
385
10.1k
    }
386
4.34k
    if (positionInPacketIter != positionsInPacket.crbegin() && *matchLen < cmatchlen) {
387
3.03k
      *matchLen = cmatchlen;
388
3.03k
      bestpos = *--positionInPacketIter;
389
3.03k
    }
390
4.34k
  }
391
5.74k
  return bestpos;
392
7.04k
}
GenericDNSPacketWriter<std::__1::vector<unsigned char, std::__1::allocator<unsigned char> > >::lookupName(DNSName const&, unsigned short*)
Line
Count
Source
229
7.04k
{
230
  // iterate over the written labels, see if we find a match
231
7.04k
  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
7.04k
  unsigned int bestpos=0;
238
7.04k
  *matchLen = 0;
239
240
  // positions of each label in the name we are trying to compress
241
7.04k
  boost::container::static_vector<uint16_t, 34> positionsInName;
242
  // positions of labels in the packet we are building
243
7.04k
  boost::container::static_vector<uint16_t, 34> positionsInPacket;
244
245
7.04k
  try {
246
25.7k
    for(auto riter= raw.cbegin(); riter < raw.cend(); ) {
247
25.7k
      if (*riter == 0) {
248
7.04k
        break;
249
7.04k
      }
250
18.7k
      positionsInName.push_back(riter - raw.cbegin());
251
18.7k
      riter += *riter + 1;
252
18.7k
    }
253
7.04k
  }
254
7.04k
  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
7.04k
  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
7.04k
  if (l_verbose) {
271
0
    cout << "Have " << d_namepositions.size() << " to ponder" << endl;
272
0
  }
273
274
7.04k
  int counter=1;
275
7.04k
  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
5.64k
    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
5.64k
    size_t pointerQuota = 50U;
291
    // memcmp here makes things _slower_
292
5.64k
    positionsInPacket.clear();
293
5.64k
    try {
294
23.6k
      for (auto iter = d_content.cbegin() + positionInPacket; iter < d_content.cend() && pointerQuota > 0;) {
295
23.6k
        uint8_t labelLength = *iter;
296
23.6k
        const uint16_t currentPos = (iter - d_content.cbegin());
297
23.6k
        if (l_verbose) {
298
0
          cout << "Found label length: " << std::to_string(labelLength) << " at " << currentPos << endl;
299
0
        }
300
23.6k
        if (labelLength & 0xc0) {
301
2.53k
          uint16_t npos = 0x100*(labelLength & (~0xc0)) + *++iter;
302
          // check against going forward
303
2.53k
          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
2.53k
          iter = d_content.begin() + npos;
310
2.53k
          if (l_verbose) {
311
0
            cout << "Is compressed label to newpos " << npos << ", going there" << endl;
312
0
          }
313
314
2.53k
          if (pointerQuota >= 1) {
315
2.53k
            pointerQuota--;
316
2.53k
            continue;
317
2.53k
          }
318
319
          // out of pointer quota, let's stop there
320
0
          break;
321
2.53k
        }
322
323
21.0k
        if (labelLength == 0) {
324
5.60k
          break;
325
5.60k
        }
326
327
15.4k
        if (currentPos >= maxCompressionOffset) {
328
35
          break; // compression pointers cannot point here
329
35
        }
330
331
15.4k
        positionsInPacket.push_back(currentPos);
332
        // jump to the next label
333
15.4k
        iter += labelLength + 1;
334
15.4k
      }
335
5.64k
    }
336
5.64k
    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
5.64k
    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
5.64k
    auto positionInNameIter = positionsInName.crbegin();
352
5.64k
    auto positionInPacketIter = positionsInPacket.crbegin();
353
5.64k
    unsigned int cmatchlen=1;
354
14.4k
    for(; positionInNameIter != positionsInName.crend() && positionInPacketIter != positionsInPacket.crend(); ++positionInNameIter, ++positionInPacketIter) {
355
      // positionInNameIter is an offset in raw, pvect an offset in packet
356
13.5k
      uint8_t nlen = raw[*positionInNameIter];
357
13.5k
      uint8_t plen = d_content[*positionInPacketIter];
358
359
13.5k
      if (l_verbose) {
360
0
        cout << "nlnen=" << (int)nlen << ", plen=" << (int)plen << endl;
361
0
      }
362
363
13.5k
      if (nlen != plen) {
364
2.92k
        break;
365
2.92k
      }
366
367
10.6k
      auto rawpart = std::string_view(raw.c_str() + *positionInNameIter + 1, nlen); // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
368
10.6k
      auto pktpart = std::string_view((const char*)&d_content[*positionInPacketIter] + 1, nlen); // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
369
10.6k
      if (pdns_ilexicographical_compare_three_way(rawpart, pktpart) != 0) {
370
512
        if (l_verbose) {
371
0
          cout << "Mismatch: " << rawpart << " != " << pktpart << endl;
372
0
        }
373
512
        break;
374
512
      }
375
376
10.1k
      cmatchlen += nlen + 1;
377
10.1k
      if (cmatchlen == raw.length()) { // have matched all of it, can't improve
378
1.29k
        if (l_verbose) {
379
0
          cout << "Stopping search, matched whole name" << endl;
380
0
        }
381
382
1.29k
        *matchLen = cmatchlen;
383
1.29k
        return *positionInPacketIter;
384
1.29k
      }
385
10.1k
    }
386
4.34k
    if (positionInPacketIter != positionsInPacket.crbegin() && *matchLen < cmatchlen) {
387
3.03k
      *matchLen = cmatchlen;
388
3.03k
      bestpos = *--positionInPacketIter;
389
3.03k
    }
390
4.34k
  }
391
5.74k
  return bestpos;
392
7.04k
}
Unexecuted instantiation: GenericDNSPacketWriter<std::__1::vector<unsigned char, noinit_adaptor<std::__1::allocator<unsigned char> > > >::lookupName(DNSName const&, unsigned short*)
393
// this is the absolute hottest function in the pdns recursor
394
template <typename Container> void GenericDNSPacketWriter<Container>::xfrName(const DNSName& name, bool compress)
395
28.0k
{
396
28.0k
  if(l_verbose)
397
0
    cout<<"Wants to write "<<name<<", compress="<<compress<<", canonic="<<d_canonic<<", LC="<<d_lowerCase<<endl;
398
28.0k
  if(d_canonic || d_lowerCase)   // d_lowerCase implies canonic
399
6.30k
    compress=false;
400
401
28.0k
  if(name.empty() || name.isRoot()) { // for speed
402
18.7k
    d_content.push_back(0);
403
18.7k
    return;
404
18.7k
  }
405
406
9.33k
  uint16_t li=0;
407
9.33k
  uint16_t matchlen=0;
408
9.33k
  if(d_compress && compress && (li=lookupName(name, &matchlen)) && li < maxCompressionOffset) {
409
3.49k
    const auto& dns=name.getStorage();
410
3.49k
    if(l_verbose)
411
0
      cout<<"Found a substring of "<<matchlen<<" bytes from the back, offset: "<<li<<", dnslen: "<<dns.size()<<endl;
412
    // found a substring, if www.powerdns.com matched powerdns.com, we get back matchlen = 13
413
414
3.49k
    unsigned int pos=d_content.size();
415
3.49k
    if(pos < maxCompressionOffset && matchlen != dns.size()) {
416
2.13k
      if(l_verbose)
417
0
        cout<<"Inserting pos "<<pos<<" for "<<name<<" for compressed case"<<endl;
418
2.13k
      d_namepositions.push_back(pos);
419
2.13k
    }
420
421
3.49k
    if(l_verbose)
422
0
      cout<<"Going to write unique part: '"<<makeHexDump(string(dns.c_str(), dns.c_str() + dns.size() - matchlen)) <<"'"<<endl;
423
3.49k
    d_content.insert(d_content.end(), (const unsigned char*)dns.c_str(), (const unsigned char*)dns.c_str() + dns.size() - matchlen);
424
3.49k
    uint16_t offset=li;
425
3.49k
    offset|=0xc000;
426
427
3.49k
    d_content.push_back((char)(offset >> 8));
428
3.49k
    d_content.push_back((char)(offset & 0xff));
429
3.49k
  }
430
5.84k
  else {
431
5.84k
    unsigned int pos=d_content.size();
432
5.84k
    if(l_verbose)
433
0
      cout<<"Found nothing, we are at pos "<<pos<<", inserting whole name"<<endl;
434
5.84k
    if(pos < maxCompressionOffset) {
435
5.64k
      if(l_verbose)
436
0
        cout<<"Inserting pos "<<pos<<" for "<<name<<" for uncompressed case"<<endl;
437
5.64k
      d_namepositions.push_back(pos);
438
5.64k
    }
439
440
5.84k
    std::unique_ptr<DNSName> lc;
441
5.84k
    if(d_lowerCase)
442
0
      lc = make_unique<DNSName>(name.makeLowerCase());
443
444
5.84k
    const DNSName::string_t& raw = (lc ? *lc : name).getStorage();
445
5.84k
    if(l_verbose)
446
0
      cout<<"Writing out the whole thing "<<makeHexDump(string(raw.c_str(),  raw.c_str() + raw.length()))<<endl;
447
5.84k
    d_content.insert(d_content.end(), raw.c_str(), raw.c_str() + raw.size());
448
5.84k
  }
449
9.33k
}
GenericDNSPacketWriter<std::__1::vector<unsigned char, std::__1::allocator<unsigned char> > >::xfrName(DNSName const&, bool)
Line
Count
Source
395
28.0k
{
396
28.0k
  if(l_verbose)
397
0
    cout<<"Wants to write "<<name<<", compress="<<compress<<", canonic="<<d_canonic<<", LC="<<d_lowerCase<<endl;
398
28.0k
  if(d_canonic || d_lowerCase)   // d_lowerCase implies canonic
399
6.30k
    compress=false;
400
401
28.0k
  if(name.empty() || name.isRoot()) { // for speed
402
18.7k
    d_content.push_back(0);
403
18.7k
    return;
404
18.7k
  }
405
406
9.33k
  uint16_t li=0;
407
9.33k
  uint16_t matchlen=0;
408
9.33k
  if(d_compress && compress && (li=lookupName(name, &matchlen)) && li < maxCompressionOffset) {
409
3.49k
    const auto& dns=name.getStorage();
410
3.49k
    if(l_verbose)
411
0
      cout<<"Found a substring of "<<matchlen<<" bytes from the back, offset: "<<li<<", dnslen: "<<dns.size()<<endl;
412
    // found a substring, if www.powerdns.com matched powerdns.com, we get back matchlen = 13
413
414
3.49k
    unsigned int pos=d_content.size();
415
3.49k
    if(pos < maxCompressionOffset && matchlen != dns.size()) {
416
2.13k
      if(l_verbose)
417
0
        cout<<"Inserting pos "<<pos<<" for "<<name<<" for compressed case"<<endl;
418
2.13k
      d_namepositions.push_back(pos);
419
2.13k
    }
420
421
3.49k
    if(l_verbose)
422
0
      cout<<"Going to write unique part: '"<<makeHexDump(string(dns.c_str(), dns.c_str() + dns.size() - matchlen)) <<"'"<<endl;
423
3.49k
    d_content.insert(d_content.end(), (const unsigned char*)dns.c_str(), (const unsigned char*)dns.c_str() + dns.size() - matchlen);
424
3.49k
    uint16_t offset=li;
425
3.49k
    offset|=0xc000;
426
427
3.49k
    d_content.push_back((char)(offset >> 8));
428
3.49k
    d_content.push_back((char)(offset & 0xff));
429
3.49k
  }
430
5.84k
  else {
431
5.84k
    unsigned int pos=d_content.size();
432
5.84k
    if(l_verbose)
433
0
      cout<<"Found nothing, we are at pos "<<pos<<", inserting whole name"<<endl;
434
5.84k
    if(pos < maxCompressionOffset) {
435
5.64k
      if(l_verbose)
436
0
        cout<<"Inserting pos "<<pos<<" for "<<name<<" for uncompressed case"<<endl;
437
5.64k
      d_namepositions.push_back(pos);
438
5.64k
    }
439
440
5.84k
    std::unique_ptr<DNSName> lc;
441
5.84k
    if(d_lowerCase)
442
0
      lc = make_unique<DNSName>(name.makeLowerCase());
443
444
5.84k
    const DNSName::string_t& raw = (lc ? *lc : name).getStorage();
445
5.84k
    if(l_verbose)
446
0
      cout<<"Writing out the whole thing "<<makeHexDump(string(raw.c_str(),  raw.c_str() + raw.length()))<<endl;
447
5.84k
    d_content.insert(d_content.end(), raw.c_str(), raw.c_str() + raw.size());
448
5.84k
  }
449
9.33k
}
Unexecuted instantiation: GenericDNSPacketWriter<std::__1::vector<unsigned char, noinit_adaptor<std::__1::allocator<unsigned char> > > >::xfrName(DNSName const&, bool)
450
451
template <typename Container> void GenericDNSPacketWriter<Container>::xfrBlob(const string& blob, int  )
452
68.9k
{
453
68.9k
  const uint8_t* ptr=reinterpret_cast<const uint8_t*>(blob.c_str());
454
68.9k
  d_content.insert(d_content.end(), ptr, ptr+blob.size());
455
68.9k
}
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)
Line
Count
Source
452
68.9k
{
453
68.9k
  const uint8_t* ptr=reinterpret_cast<const uint8_t*>(blob.c_str());
454
68.9k
  d_content.insert(d_content.end(), ptr, ptr+blob.size());
455
68.9k
}
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)
456
457
template <typename Container> void GenericDNSPacketWriter<Container>::xfrBlob(const std::vector<uint8_t>& blob)
458
0
{
459
0
  d_content.insert(d_content.end(), blob.begin(), blob.end());
460
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&)
461
462
template <typename Container> void GenericDNSPacketWriter<Container>::xfrBlobNoSpaces(const string& blob, int  )
463
233
{
464
233
  xfrBlob(blob);
465
233
}
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)
Line
Count
Source
463
233
{
464
233
  xfrBlob(blob);
465
233
}
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)
466
467
template <typename Container> void GenericDNSPacketWriter<Container>::xfrHexBlob(const string& blob, bool /* keepReading */)
468
88
{
469
88
  xfrBlob(blob);
470
88
}
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)
Line
Count
Source
468
88
{
469
88
  xfrBlob(blob);
470
88
}
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)
471
472
template <typename Container> void GenericDNSPacketWriter<Container>::xfrSvcParamKeyVals(const std::set<SvcParam> &kvs)
473
1.35k
{
474
3.19k
  for (auto const &param : kvs) {
475
    // Key first!
476
3.19k
    xfr16BitInt(param.getKey());
477
478
3.19k
    switch (param.getKey())
479
3.19k
    {
480
254
    case SvcParam::mandatory:
481
254
      xfr16BitInt(2 * param.getMandatory().size());
482
6.26k
      for (auto const &m: param.getMandatory()) {
483
6.26k
        xfr16BitInt(m);
484
6.26k
      }
485
254
      break;
486
360
    case SvcParam::alpn:
487
360
    {
488
360
      size_t totalSize = param.getALPN().size(); // All 1 octet size headers for each value
489
251k
      for (auto const &a : param.getALPN()) {
490
251k
        totalSize += a.length();
491
251k
      }
492
360
      if (totalSize > std::numeric_limits<uint16_t>::max()) {
493
0
        throw runtime_error("invalid total length of alpn parameters");
494
0
      }
495
360
      xfr16BitInt(static_cast<uint16_t>(totalSize));
496
251k
      for (auto const &a : param.getALPN()) {
497
251k
        xfrUnquotedText(a, true); // will add the 1-byte length field
498
251k
      }
499
360
      break;
500
360
    }
501
80
    case SvcParam::no_default_alpn:
502
80
      xfr16BitInt(0); // no size :)
503
80
      break;
504
73
    case SvcParam::port:
505
73
      xfr16BitInt(2); // size
506
73
      xfr16BitInt(param.getPort());
507
73
      break;
508
200
    case SvcParam::ipv4hint:
509
200
      xfr16BitInt(param.getIPHints().size() * 4); // size
510
313k
      for (const auto& a: param.getIPHints()) {
511
313k
        xfrCAWithoutPort(param.getKey(), a);
512
313k
      }
513
200
      break;
514
137
    case SvcParam::ipv6hint:
515
137
      xfr16BitInt(param.getIPHints().size() * 16); // size
516
13.0k
      for (const auto& a: param.getIPHints()) {
517
13.0k
        xfrCAWithoutPort(param.getKey(), a);
518
13.0k
      }
519
137
      break;
520
233
    case SvcParam::ech:
521
233
      xfr16BitInt(param.getECH().size()); // size
522
233
      xfrBlobNoSpaces(param.getECH());
523
233
      break;
524
54
    case SvcParam::ohttp:
525
54
      xfr16BitInt(0); // no size
526
54
      break;
527
57
    case SvcParam::tls_supported_groups:
528
57
      xfr16BitInt(2 * param.getTLSSupportedGroups().size()); // size
529
170k
      for (const auto& group: param.getTLSSupportedGroups()) {
530
170k
        xfr16BitInt(group);
531
170k
      }
532
57
      break;
533
1.74k
    default:
534
1.74k
      xfr16BitInt(param.getValue().size());
535
1.74k
      xfrBlob(param.getValue());
536
1.74k
      break;
537
3.19k
    }
538
3.19k
  }
539
1.35k
}
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&)
Line
Count
Source
473
1.35k
{
474
3.19k
  for (auto const &param : kvs) {
475
    // Key first!
476
3.19k
    xfr16BitInt(param.getKey());
477
478
3.19k
    switch (param.getKey())
479
3.19k
    {
480
254
    case SvcParam::mandatory:
481
254
      xfr16BitInt(2 * param.getMandatory().size());
482
6.26k
      for (auto const &m: param.getMandatory()) {
483
6.26k
        xfr16BitInt(m);
484
6.26k
      }
485
254
      break;
486
360
    case SvcParam::alpn:
487
360
    {
488
360
      size_t totalSize = param.getALPN().size(); // All 1 octet size headers for each value
489
251k
      for (auto const &a : param.getALPN()) {
490
251k
        totalSize += a.length();
491
251k
      }
492
360
      if (totalSize > std::numeric_limits<uint16_t>::max()) {
493
0
        throw runtime_error("invalid total length of alpn parameters");
494
0
      }
495
360
      xfr16BitInt(static_cast<uint16_t>(totalSize));
496
251k
      for (auto const &a : param.getALPN()) {
497
251k
        xfrUnquotedText(a, true); // will add the 1-byte length field
498
251k
      }
499
360
      break;
500
360
    }
501
80
    case SvcParam::no_default_alpn:
502
80
      xfr16BitInt(0); // no size :)
503
80
      break;
504
73
    case SvcParam::port:
505
73
      xfr16BitInt(2); // size
506
73
      xfr16BitInt(param.getPort());
507
73
      break;
508
200
    case SvcParam::ipv4hint:
509
200
      xfr16BitInt(param.getIPHints().size() * 4); // size
510
313k
      for (const auto& a: param.getIPHints()) {
511
313k
        xfrCAWithoutPort(param.getKey(), a);
512
313k
      }
513
200
      break;
514
137
    case SvcParam::ipv6hint:
515
137
      xfr16BitInt(param.getIPHints().size() * 16); // size
516
13.0k
      for (const auto& a: param.getIPHints()) {
517
13.0k
        xfrCAWithoutPort(param.getKey(), a);
518
13.0k
      }
519
137
      break;
520
233
    case SvcParam::ech:
521
233
      xfr16BitInt(param.getECH().size()); // size
522
233
      xfrBlobNoSpaces(param.getECH());
523
233
      break;
524
54
    case SvcParam::ohttp:
525
54
      xfr16BitInt(0); // no size
526
54
      break;
527
57
    case SvcParam::tls_supported_groups:
528
57
      xfr16BitInt(2 * param.getTLSSupportedGroups().size()); // size
529
170k
      for (const auto& group: param.getTLSSupportedGroups()) {
530
170k
        xfr16BitInt(group);
531
170k
      }
532
57
      break;
533
1.74k
    default:
534
1.74k
      xfr16BitInt(param.getValue().size());
535
1.74k
      xfrBlob(param.getValue());
536
1.74k
      break;
537
3.19k
    }
538
3.19k
  }
539
1.35k
}
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&)
540
541
// call __before commit__
542
template <typename Container> void GenericDNSPacketWriter<Container>::getRecordPayload(string& records)
543
3.88k
{
544
3.88k
  records.assign(d_content.begin() + d_sor, d_content.end());
545
3.88k
}
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> >&)
Line
Count
Source
543
3.88k
{
544
3.88k
  records.assign(d_content.begin() + d_sor, d_content.end());
545
3.88k
}
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> >&)
546
547
// call __before commit__
548
template <typename Container> void GenericDNSPacketWriter<Container>::getWireFormatContent(string& record)
549
0
{
550
0
  record.assign(d_content.begin() + d_rollbackmarker, d_content.end());
551
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> >&)
552
553
template <typename Container> uint32_t GenericDNSPacketWriter<Container>::size() const
554
0
{
555
0
  return d_content.size();
556
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
557
558
template <typename Container> void GenericDNSPacketWriter<Container>::rollback()
559
0
{
560
0
  d_content.resize(d_rollbackmarker);
561
0
  d_sor = 0;
562
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()
563
564
template <typename Container> void GenericDNSPacketWriter<Container>::truncate()
565
0
{
566
0
  d_content.resize(d_truncatemarker);
567
0
  dnsheader* dh=reinterpret_cast<dnsheader*>( &*d_content.begin());
568
0
  dh->ancount = dh->nscount = dh->arcount = 0;
569
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()
570
571
template <typename Container> void GenericDNSPacketWriter<Container>::commit()
572
21.7k
{
573
21.7k
  if (d_sor == 0) {
574
8.77k
    return;
575
8.77k
  }
576
577
13.0k
  if (d_sor < 2 || d_sor > d_content.size()) {
578
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()));
579
0
  }
580
581
13.0k
  if (d_content.size() > std::numeric_limits<uint16_t>::max()) {
582
53
    throw std::range_error("Trying to build a packet larger than " + std::to_string(std::numeric_limits<uint16_t>::max()) + " bytes");
583
53
  }
584
585
12.9k
  uint16_t rlen = d_content.size() - d_sor;
586
12.9k
  d_content.at(d_sor-2) = rlen >> 8;
587
12.9k
  d_content.at(d_sor-1) = rlen & 0xff;
588
12.9k
  d_sor = 0;
589
12.9k
  auto* dh = reinterpret_cast<dnsheader*>( &*d_content.begin());
590
12.9k
  switch(d_recordplace) {
591
0
  case DNSResourceRecord::QUESTION:
592
0
    dh->qdcount = htons(ntohs(dh->qdcount) + 1);
593
0
    break;
594
11.9k
  case DNSResourceRecord::ANSWER:
595
11.9k
    dh->ancount = htons(ntohs(dh->ancount) + 1);
596
11.9k
    break;
597
0
  case DNSResourceRecord::AUTHORITY:
598
0
    dh->nscount = htons(ntohs(dh->nscount) + 1);
599
0
    break;
600
988
  case DNSResourceRecord::ADDITIONAL:
601
988
    dh->arcount = htons(ntohs(dh->arcount) + 1);
602
988
    break;
603
12.9k
  }
604
605
12.9k
}
GenericDNSPacketWriter<std::__1::vector<unsigned char, std::__1::allocator<unsigned char> > >::commit()
Line
Count
Source
572
21.7k
{
573
21.7k
  if (d_sor == 0) {
574
8.77k
    return;
575
8.77k
  }
576
577
13.0k
  if (d_sor < 2 || d_sor > d_content.size()) {
578
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()));
579
0
  }
580
581
13.0k
  if (d_content.size() > std::numeric_limits<uint16_t>::max()) {
582
53
    throw std::range_error("Trying to build a packet larger than " + std::to_string(std::numeric_limits<uint16_t>::max()) + " bytes");
583
53
  }
584
585
12.9k
  uint16_t rlen = d_content.size() - d_sor;
586
12.9k
  d_content.at(d_sor-2) = rlen >> 8;
587
12.9k
  d_content.at(d_sor-1) = rlen & 0xff;
588
12.9k
  d_sor = 0;
589
12.9k
  auto* dh = reinterpret_cast<dnsheader*>( &*d_content.begin());
590
12.9k
  switch(d_recordplace) {
591
0
  case DNSResourceRecord::QUESTION:
592
0
    dh->qdcount = htons(ntohs(dh->qdcount) + 1);
593
0
    break;
594
11.9k
  case DNSResourceRecord::ANSWER:
595
11.9k
    dh->ancount = htons(ntohs(dh->ancount) + 1);
596
11.9k
    break;
597
0
  case DNSResourceRecord::AUTHORITY:
598
0
    dh->nscount = htons(ntohs(dh->nscount) + 1);
599
0
    break;
600
988
  case DNSResourceRecord::ADDITIONAL:
601
988
    dh->arcount = htons(ntohs(dh->arcount) + 1);
602
988
    break;
603
12.9k
  }
604
605
12.9k
}
Unexecuted instantiation: GenericDNSPacketWriter<std::__1::vector<unsigned char, noinit_adaptor<std::__1::allocator<unsigned char> > > >::commit()
606
607
template <typename Container> size_t GenericDNSPacketWriter<Container>::getSizeWithOpts(const optvect_t& options) const
608
0
{
609
0
  size_t result = size() + /* root */ 1 + DNS_TYPE_SIZE + DNS_CLASS_SIZE + DNS_TTL_SIZE + DNS_RDLENGTH_SIZE;
610
611
0
  for(auto const &option : options) {
612
0
    result += 4;
613
0
    result += option.second.size();
614
0
  }
615
616
0
  return result;
617
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
618
619
template class GenericDNSPacketWriter<std::vector<uint8_t>>;
620
#include "noinitvector.hh"
621
template class GenericDNSPacketWriter<PacketBuffer>;