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

PowerDNS / pdns / 12595591960

03 Jan 2025 09:27AM UTC coverage: 62.774% (+2.5%) from 60.245%
12595591960

Pull #15008

github

web-flow
Merge c2a2749d3 into 788f396a7
Pull Request #15008: Do not follow CNAME records for ANY or CNAME queries

30393 of 78644 branches covered (38.65%)

Branch coverage included in aggregate %.

105822 of 138350 relevant lines covered (76.49%)

4613078.44 hits per line

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

96.32
/pdns/protozero.hh
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
#pragma once
23

24
#include "config.h"
25

26
#include "iputils.hh"
27
#include "gettime.hh"
28
#include "uuid-utils.hh"
29

30
#ifndef DISABLE_PROTOBUF
31

32
#include <protozero/pbf_writer.hpp>
33

34
namespace pdns
35
{
36
namespace ProtoZero
37
{
38
  class Message
39
  {
40
  public:
41
    enum class MetaValueField : protozero::pbf_tag_type
42
    {
43
      stringVal = 1,
44
      intVal = 2
45
    };
46
    enum class HTTPVersion : protozero::pbf_tag_type
47
    {
48
      HTTP1 = 1,
49
      HTTP2 = 2,
50
      HTTP3 = 3
51
    };
52
    enum class MetaField : protozero::pbf_tag_type
53
    {
54
      key = 1,
55
      value = 2
56
    };
57
    enum class Event : protozero::pbf_tag_type
58
    {
59
      ts = 1,
60
      event = 2,
61
      start = 3,
62
      boolVal = 4,
63
      intVal = 5,
64
      stringVal = 6,
65
      bytesVal = 7,
66
      custom = 8
67
    };
68
    enum class MessageType : int32_t
69
    {
70
      DNSQueryType = 1,
71
      DNSResponseType = 2,
72
      DNSOutgoingQueryType = 3,
73
      DNSIncomingResponseType = 4
74
    };
75
    enum class Field : protozero::pbf_tag_type
76
    {
77
      type = 1,
78
      messageId = 2,
79
      serverIdentity = 3,
80
      socketFamily = 4,
81
      socketProtocol = 5,
82
      from = 6,
83
      to = 7,
84
      inBytes = 8,
85
      timeSec = 9,
86
      timeUsec = 10,
87
      id = 11,
88
      question = 12,
89
      response = 13,
90
      originalRequestorSubnet = 14,
91
      requestorId = 15,
92
      initialRequestId = 16,
93
      deviceId = 17,
94
      newlyObservedDomain = 18,
95
      deviceName = 19,
96
      fromPort = 20,
97
      toPort = 21,
98
      meta = 22,
99
      trace = 23,
100
      httpVersion = 24,
101
      workerId = 25,
102
      packetCacheHit = 26,
103
      outgoingQueries = 27,
104
      headerFlags = 28,
105
      ednsVersion = 29,
106
    };
107
    enum class QuestionField : protozero::pbf_tag_type
108
    {
109
      qName = 1,
110
      qType = 2,
111
      qClass = 3
112
    };
113
    enum class ResponseField : protozero::pbf_tag_type
114
    {
115
      rcode = 1,
116
      rrs = 2,
117
      appliedPolicy = 3,
118
      tags = 4,
119
      queryTimeSec = 5,
120
      queryTimeUsec = 6,
121
      appliedPolicyType = 7,
122
      appliedPolicyTrigger = 8,
123
      appliedPolicyHit = 9,
124
      appliedPolicyKind = 10,
125
      validationState = 11
126
    };
127
    enum class RRField : protozero::pbf_tag_type
128
    {
129
      name = 1,
130
      type = 2,
131
      class_ = 3,
132
      ttl = 4,
133
      rdata = 5,
134
      udr = 6
135
    };
136
    enum class TransportProtocol : protozero::pbf_tag_type
137
    {
138
      UDP = 1,
139
      TCP = 2,
140
      DoT = 3,
141
      DoH = 4,
142
      DNSCryptUDP = 5,
143
      DNSCryptTCP = 6,
144
      DoQ = 7
145
    };
146

147
    Message(std::string& buffer) :
148
      d_buffer(buffer), d_message{d_buffer}
149
    {
2,475✔
150
    }
2,475✔
151
    ~Message() = default;
2,475✔
152
    Message(const Message&) = delete;
153
    Message(Message&&) = delete;
154
    Message& operator=(const Message&) = delete;
155
    Message& operator=(Message&&) = delete;
156

157
    void setRequest(const boost::uuids::uuid& uniqueId, const ComboAddress& requestor, const ComboAddress& local, const DNSName& qname, uint16_t qtype, uint16_t qclass, uint16_t qid, TransportProtocol proto, size_t len);
158
    void setResponse(const DNSName& qname, uint16_t qtype, uint16_t qclass);
159

160
    void setType(MessageType mtype)
161
    {
152✔
162
      add_enum(d_message, Field::type, static_cast<int32_t>(mtype));
152✔
163
    }
152✔
164

165
    void setHTTPVersion(HTTPVersion version)
166
    {
5✔
167
      add_enum(d_message, Field::httpVersion, static_cast<int32_t>(version));
5✔
168
    }
5✔
169

170
    void setMessageIdentity(const boost::uuids::uuid& uniqueId)
171
    {
125✔
172
      add_bytes(d_message, Field::messageId, reinterpret_cast<const char*>(uniqueId.begin()), uniqueId.size()); // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast): it's the API
125✔
173
    }
125✔
174

175
    void setServerIdentity(const std::string& serverIdentity)
176
    {
118✔
177
      add_bytes(d_message, Field::serverIdentity, serverIdentity.data(), serverIdentity.length());
118✔
178
    }
118✔
179

180
    void setSocketFamily(int family)
181
    {
125✔
182
      add_enum(d_message, Field::socketFamily, family == AF_INET ? 1 : 2);
125✔
183
    }
125✔
184

185
    void setSocketProtocol(TransportProtocol proto)
186
    {
125✔
187
      add_enum(d_message, Field::socketProtocol, static_cast<int32_t>(proto));
125✔
188
    }
125✔
189

190
    void setFrom(const ComboAddress& address)
191
    {
93✔
192
      encodeComboAddress(static_cast<protozero::pbf_tag_type>(Field::from), address);
93✔
193
    }
93✔
194

195
    void setTo(const ComboAddress& address)
196
    {
125✔
197
      encodeComboAddress(static_cast<protozero::pbf_tag_type>(Field::to), address);
125✔
198
    }
125✔
199

200
    void setInBytes(uint64_t len)
201
    {
117✔
202
      add_uint64(d_message, Field::inBytes, len);
117✔
203
    }
117✔
204

205
    void setTime()
206
    {
125✔
207
      timespec timesp{};
125✔
208
      gettime(&timesp, true);
125✔
209

210
      setTime(timesp.tv_sec, timesp.tv_nsec / 1000);
125✔
211
    }
125✔
212

213
    void setTime(time_t sec, uint32_t usec)
214
    {
227✔
215
      // coverity[store_truncates_time_t]
216
      add_uint32(d_message, Field::timeSec, sec);
227✔
217
      add_uint32(d_message, Field::timeUsec, usec);
227✔
218
    }
227✔
219

220
    void setId(uint16_t qid)
221
    {
125✔
222
      add_uint32(d_message, Field::id, ntohs(qid));
125✔
223
    }
125✔
224

225
    void setQuestion(const DNSName& qname, uint16_t qtype, uint16_t qclass)
226
    {
118✔
227
      protozero::pbf_writer pbf_question{d_message, static_cast<protozero::pbf_tag_type>(Field::question)};
118✔
228
      encodeDNSName(pbf_question, d_buffer, static_cast<protozero::pbf_tag_type>(QuestionField::qName), qname);
118✔
229
      pbf_question.add_uint32(static_cast<protozero::pbf_tag_type>(QuestionField::qType), qtype);
118✔
230
      pbf_question.add_uint32(static_cast<protozero::pbf_tag_type>(QuestionField::qClass), qclass);
118✔
231
    }
118✔
232

233
    void setMeta(const std::string& key, const std::unordered_set<std::string>& stringVal, const std::unordered_set<int64_t>& intVal)
234
    {
92✔
235
      protozero::pbf_writer pbf_meta{d_message, static_cast<protozero::pbf_tag_type>(Field::meta)};
92✔
236
      pbf_meta.add_string(static_cast<protozero::pbf_tag_type>(MetaField::key), key);
92✔
237
      protozero::pbf_writer pbf_meta_value{pbf_meta, static_cast<protozero::pbf_tag_type>(MetaField::value)};
92✔
238
      for (const auto& str : stringVal) {
95✔
239
        pbf_meta_value.add_string(static_cast<protozero::pbf_tag_type>(MetaValueField::stringVal), str);
95✔
240
      }
95✔
241
      for (const auto& val : intVal) {
92✔
242
        pbf_meta_value.add_uint64(static_cast<protozero::pbf_tag_type>(MetaValueField::intVal), val);
5✔
243
      }
5✔
244
    }
92✔
245

246
    void setEDNSSubnet(const Netmask& netmask, uint8_t mask)
247
    {
65✔
248
      encodeNetmask(static_cast<protozero::pbf_tag_type>(Field::originalRequestorSubnet), netmask, mask);
65✔
249
    }
65✔
250

251
    void setRequestorId(const std::string& req)
252
    {
59✔
253
      if (!req.empty()) {
59✔
254
        add_string(d_message, Field::requestorId, req);
8✔
255
      }
8✔
256
    }
59✔
257

258
    void setInitialRequestID(const boost::uuids::uuid& uniqueId)
259
    {
32✔
260
      add_bytes(d_message, Field::initialRequestId, reinterpret_cast<const char*>(uniqueId.begin()), uniqueId.size()); // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast): it's the API
32✔
261
    }
32✔
262

263
    void setDeviceId(const std::string& deviceId)
264
    {
59✔
265
      if (!deviceId.empty()) {
59✔
266
        add_string(d_message, Field::deviceId, deviceId);
8✔
267
      }
8✔
268
    }
59✔
269

270
    void setNewlyObservedDomain(bool nod)
271
    {
×
272
      add_bool(d_message, Field::newlyObservedDomain, nod);
×
273
    }
×
274

275
    void setDeviceName(const std::string& name)
276
    {
59✔
277
      if (!name.empty()) {
59✔
278
        add_string(d_message, Field::deviceName, name);
8✔
279
      }
8✔
280
    }
59✔
281

282
    void setFromPort(in_port_t port)
283
    {
93✔
284
      add_uint32(d_message, Field::fromPort, port);
93✔
285
    }
93✔
286

287
    void setToPort(in_port_t port)
288
    {
125✔
289
      add_uint32(d_message, Field::toPort, port);
125✔
290
    }
125✔
291

292
    void setWorkerId(uint64_t wid)
293
    {
59✔
294
      add_uint64(d_message, Field::workerId, wid);
59✔
295
    }
59✔
296

297
    void setPacketCacheHit(bool hit)
298
    {
35✔
299
      add_bool(d_message, Field::packetCacheHit, hit);
35✔
300
    }
35✔
301

302
    void setOutgoingQueries(uint32_t num)
303
    {
27✔
304
      add_uint32(d_message, Field::outgoingQueries, num);
27✔
305
    }
27✔
306

307
    void setHeaderFlags(uint16_t flags)
308
    {
24✔
309
      add_uint32(d_message, Field::headerFlags, flags);
24✔
310
    }
24✔
311

312
    void setEDNSVersion(uint32_t version)
313
    {
24✔
314
      add_uint32(d_message, Field::ednsVersion, version);
24✔
315
    }
24✔
316

317
    void startResponse()
318
    {
53✔
319
      d_response = protozero::pbf_writer{d_message, static_cast<protozero::pbf_tag_type>(Field::response)};
53✔
320
    }
53✔
321

322
    void commitResponse()
323
    {
53✔
324
      d_response.commit();
53✔
325
    }
53✔
326

327
    void setResponseCode(uint8_t rcode)
328
    {
66✔
329
      d_response.add_uint32(static_cast<protozero::pbf_tag_type>(ResponseField::rcode), rcode);
66✔
330
    }
66✔
331

332
    void setNetworkErrorResponseCode()
333
    {
×
334
      /* special code meaning 'network error', like a timeout */
335
      d_response.add_uint32(static_cast<protozero::pbf_tag_type>(ResponseField::rcode), 65536);
×
336
    }
×
337

338
    void setAppliedPolicy(const std::string& policy)
339
    {
3✔
340
      d_response.add_string(static_cast<protozero::pbf_tag_type>(ResponseField::appliedPolicy), policy);
3✔
341
    }
3✔
342

343
    void addPolicyTags(const std::unordered_set<std::string>& tags)
344
    {
40✔
345
      for (const auto& tag : tags) {
40✔
346
        addPolicyTag(tag);
22✔
347
      }
22✔
348
    }
40✔
349

350
    void addPolicyTag(const string& tag)
351
    {
58✔
352
      d_response.add_string(static_cast<protozero::pbf_tag_type>(ResponseField::tags), tag);
58✔
353
    }
58✔
354

355
    void setQueryTime(uint32_t sec, uint32_t usec)
356
    {
88✔
357
      d_response.add_uint32(static_cast<protozero::pbf_tag_type>(ResponseField::queryTimeSec), sec);
88✔
358
      d_response.add_uint32(static_cast<protozero::pbf_tag_type>(ResponseField::queryTimeUsec), usec);
88✔
359
    }
88✔
360

361
    void addRRsFromPacket(const char* packet, size_t len, bool includeCNAME = false);
362
    void addRR(const DNSName& name, uint16_t uType, uint16_t uClass, uint32_t uTTL, const std::string& blob);
363

364
  protected:
365
    void encodeComboAddress(protozero::pbf_tag_type type, const ComboAddress& address);
366
    void encodeNetmask(protozero::pbf_tag_type type, const Netmask& subnet, uint8_t mask);
367
    static void encodeDNSName(protozero::pbf_writer& pbf, std::string& buffer, protozero::pbf_tag_type type, const DNSName& name);
368

369
    static void add_enum(protozero::pbf_writer& writer, Field type, int32_t value)
370
    {
480✔
371
      writer.add_enum(static_cast<protozero::pbf_tag_type>(type), value);
480✔
372
    }
480✔
373

374
    static void add_bool(protozero::pbf_writer& writer, Field type, bool value)
375
    {
35✔
376
      writer.add_bool(static_cast<protozero::pbf_tag_type>(type), value);
35✔
377
    }
35✔
378

379
    static void add_uint32(protozero::pbf_writer& writer, Field type, uint32_t value)
380
    {
974✔
381
      writer.add_uint32(static_cast<protozero::pbf_tag_type>(type), value);
974✔
382
    }
974✔
383

384
    static void add_uint64(protozero::pbf_writer& writer, Field type, uint64_t value)
385
    {
176✔
386
      writer.add_uint64(static_cast<protozero::pbf_tag_type>(type), value);
176✔
387
    }
176✔
388

389
    static void add_bytes(protozero::pbf_writer& writer, Field type, const char* data, size_t len)
390
    {
343✔
391
      writer.add_bytes(static_cast<protozero::pbf_tag_type>(type), data, len);
343✔
392
    }
343✔
393

394
    static void add_string(protozero::pbf_writer& writer, Field type, const std::string& str)
395
    {
24✔
396
      writer.add_string(static_cast<protozero::pbf_tag_type>(type), str);
24✔
397
    }
24✔
398

399
    // NOLINTBEGIN(cppcoreguidelines-non-private-member-variables-in-classes)
400
    std::string& d_buffer;
401
    protozero::pbf_writer d_message;
402
    protozero::pbf_writer d_response;
403
    // NOLINTEND(cppcoreguidelines-non-private-member-variables-in-classes)
404
  };
405
};
406
};
407

408
#endif /* DISABLE_PROTOBUF */
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc