]> git.ipfire.org Git - thirdparty/pdns.git/blame - pdns/protozero.hh
Merge pull request #14020 from omoerbeek/rec-compiling-rust-dcos
[thirdparty/pdns.git] / pdns / protozero.hh
CommitLineData
a44a8d66
OM
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
a44a8d66 24#include "config.h"
454e9974 25
a44a8d66 26#include "iputils.hh"
a44a8d66
OM
27#include "gettime.hh"
28#include "uuid-utils.hh"
29
454e9974
RG
30#ifndef DISABLE_PROTOBUF
31
32#include <protozero/pbf_writer.hpp>
33
a44a8d66
OM
34namespace pdns {
35 namespace ProtoZero {
36 class Message {
37 public:
634dd69e
CHB
38
39 enum class MetaValueField : protozero::pbf_tag_type { stringVal = 1, intVal = 2 };
a261cdeb 40 enum class HTTPVersion : protozero::pbf_tag_type { HTTP1 = 1, HTTP2 = 2, HTTP3 = 3 };
634dd69e 41 enum class MetaField : protozero::pbf_tag_type { key = 1, value = 2 };
f5b1d3bb 42 enum class Event : protozero::pbf_tag_type { ts = 1, event = 2, start = 3, boolVal = 4, intVal = 5, stringVal = 6, bytesVal = 7, custom = 8 };
89addb82 43 enum class MessageType : int32_t { DNSQueryType = 1, DNSResponseType = 2, DNSOutgoingQueryType = 3, DNSIncomingResponseType = 4 };
a261cdeb 44 enum class Field : protozero::pbf_tag_type { type = 1, messageId = 2, serverIdentity = 3, socketFamily = 4, socketProtocol = 5, from = 6, to = 7, inBytes = 8, timeSec = 9, timeUsec = 10, id = 11, question = 12, response = 13, originalRequestorSubnet = 14, requestorId = 15, initialRequestId = 16, deviceId = 17, newlyObservedDomain = 18, deviceName = 19, fromPort = 20, toPort = 21, meta = 22, trace = 23, httpVersion = 24 };
543067da 45 enum class QuestionField : protozero::pbf_tag_type { qName = 1, qType = 2, qClass = 3 };
2e627150 46 enum class ResponseField : protozero::pbf_tag_type { rcode = 1, rrs = 2, appliedPolicy = 3, tags = 4, queryTimeSec = 5, queryTimeUsec = 6, appliedPolicyType = 7, appliedPolicyTrigger = 8, appliedPolicyHit = 9, appliedPolicyKind = 10, validationState = 11 };
89addb82 47 enum class RRField : protozero::pbf_tag_type { name = 1, type = 2, class_ = 3, ttl = 4, rdata = 5, udr = 6 };
a261cdeb 48 enum class TransportProtocol : protozero::pbf_tag_type { UDP = 1, TCP = 2, DoT = 3, DoH = 4, DNSCryptUDP = 5, DNSCryptTCP = 6, DoQ = 7 };
89addb82 49
87f46425 50 Message(std::string& buffer): d_buffer(buffer), d_message{d_buffer}
83b261a7
OM
51 {
52 }
ac10822e 53
83b261a7
OM
54 Message(const Message&) = delete;
55 Message(Message&&) = delete;
56 Message& operator=(const Message&) = delete;
57 Message& operator=(Message&&) = delete;
58
cffd3a17 59 void setRequest(const boost::uuids::uuid& uniqueId, const ComboAddress& requestor, const ComboAddress& local, const DNSName& qname, uint16_t qtype, uint16_t qclass, uint16_t id, TransportProtocol proto, size_t len);
d58249ee 60 void setResponse(const DNSName& qname, uint16_t qtype, uint16_t qclass);
a44a8d66 61
89addb82 62 void setType(MessageType mtype)
a44a8d66 63 {
89addb82 64 add_enum(d_message, Field::type, static_cast<int32_t>(mtype));
a44a8d66 65 }
a261cdeb
CHB
66
67 void setHTTPVersion(HTTPVersion version)
68 {
69 add_enum(d_message, Field::httpVersion, static_cast<int32_t>(version));
70 }
87f46425 71
a44a8d66
OM
72 void setMessageIdentity(const boost::uuids::uuid& uniqueId)
73 {
89addb82 74 add_bytes(d_message, Field::messageId, reinterpret_cast<const char*>(uniqueId.begin()), uniqueId.size());
a44a8d66 75 }
87f46425 76
a44a8d66
OM
77 void setServerIdentity(const std::string& serverIdentity)
78 {
89addb82 79 add_bytes(d_message, Field::serverIdentity, serverIdentity.data(), serverIdentity.length());
a44a8d66 80 }
87f46425 81
a44a8d66
OM
82 void setSocketFamily(int family)
83 {
89addb82 84 add_enum(d_message, Field::socketFamily, family == AF_INET ? 1 : 2);
a44a8d66 85 }
87f46425 86
cffd3a17 87 void setSocketProtocol(TransportProtocol proto)
a44a8d66 88 {
cffd3a17 89 add_enum(d_message, Field::socketProtocol, static_cast<int32_t>(proto));
a44a8d66 90 }
87f46425 91
a44a8d66
OM
92 void setFrom(const ComboAddress& ca)
93 {
89addb82 94 encodeComboAddress(static_cast<protozero::pbf_tag_type>(Field::from), ca);
a44a8d66 95 }
87f46425 96
a44a8d66
OM
97 void setTo(const ComboAddress& ca)
98 {
89addb82 99 encodeComboAddress(static_cast<protozero::pbf_tag_type>(Field::to), ca);
a44a8d66 100 }
87f46425 101
a44a8d66
OM
102 void setInBytes(uint64_t len)
103 {
c4de50c9 104 add_uint64(d_message, Field::inBytes, len);
a44a8d66 105 }
87f46425 106
a44a8d66
OM
107 void setTime()
108 {
109 struct timespec ts;
110 gettime(&ts, true);
87f46425
RG
111
112 setTime(ts.tv_sec, ts.tv_nsec / 1000);
113 }
114
115 void setTime(time_t sec, uint32_t usec)
116 {
b59b334d 117 // coverity[store_truncates_time_t]
89addb82
RG
118 add_uint32(d_message, Field::timeSec, sec);
119 add_uint32(d_message, Field::timeUsec, usec);
a44a8d66 120 }
87f46425 121
a44a8d66
OM
122 void setId(uint16_t id)
123 {
89addb82 124 add_uint32(d_message, Field::id, ntohs(id));
a44a8d66 125 }
87f46425 126
a44a8d66
OM
127 void setQuestion(const DNSName& qname, uint16_t qtype, uint16_t qclass)
128 {
89addb82
RG
129 protozero::pbf_writer pbf_question{d_message, static_cast<protozero::pbf_tag_type>(Field::question)};
130 encodeDNSName(pbf_question, d_buffer, static_cast<protozero::pbf_tag_type>(QuestionField::qName), qname);
131 pbf_question.add_uint32(static_cast<protozero::pbf_tag_type>(QuestionField::qType), qtype);
132 pbf_question.add_uint32(static_cast<protozero::pbf_tag_type>(QuestionField::qClass), qclass);
a44a8d66 133 }
87f46425 134
543067da
CHB
135 void setMeta(const std::string& key, const std::unordered_set<std::string>& stringVal, const std::unordered_set<int64_t>& intVal)
136 {
137 protozero::pbf_writer pbf_meta{d_message, static_cast<protozero::pbf_tag_type>(Field::meta)};
138 pbf_meta.add_string(static_cast<protozero::pbf_tag_type>(MetaField::key), key);
139 protozero::pbf_writer pbf_meta_value{pbf_meta, static_cast<protozero::pbf_tag_type>(MetaField::value)};
140 for (const auto& s: stringVal) {
141 pbf_meta_value.add_string(static_cast<protozero::pbf_tag_type>(MetaValueField::stringVal), s);
142 }
143 for (const auto& i: intVal) {
144 pbf_meta_value.add_uint64(static_cast<protozero::pbf_tag_type>(MetaValueField::intVal), i);
634dd69e
CHB
145 }
146 }
147
a44a8d66
OM
148 void setEDNSSubnet(const Netmask& nm, uint8_t mask)
149 {
89addb82 150 encodeNetmask(static_cast<protozero::pbf_tag_type>(Field::originalRequestorSubnet), nm, mask);
a44a8d66 151 }
87f46425 152
a44a8d66
OM
153 void setRequestorId(const std::string& req)
154 {
ac10822e 155 if (!req.empty()) {
89addb82 156 add_string(d_message, Field::requestorId, req);
a44a8d66
OM
157 }
158 }
87f46425 159
00b3e94a 160 void setInitialRequestID(const boost::uuids::uuid& uniqueId)
a44a8d66 161 {
89addb82 162 add_bytes(d_message, Field::initialRequestId, reinterpret_cast<const char*>(uniqueId.begin()), uniqueId.size());
a44a8d66 163 }
87f46425 164
a44a8d66
OM
165 void setDeviceId(const std::string& id)
166 {
ac10822e 167 if (!id.empty()) {
89addb82 168 add_string(d_message, Field::deviceId, id);
a44a8d66
OM
169 }
170 }
87f46425 171
a44a8d66
OM
172 void setNewlyObservedDomain(bool nod)
173 {
89addb82 174 add_bool(d_message, Field::newlyObservedDomain, nod);
a44a8d66 175 }
87f46425 176
a44a8d66
OM
177 void setDeviceName(const std::string& name)
178 {
ac10822e 179 if (!name.empty()) {
89addb82 180 add_string(d_message, Field::deviceName, name);
a44a8d66
OM
181 }
182 }
87f46425 183
a44a8d66
OM
184 void setFromPort(in_port_t port)
185 {
89addb82 186 add_uint32(d_message, Field::fromPort, port);
a44a8d66 187 }
87f46425 188
a44a8d66
OM
189 void setToPort(in_port_t port)
190 {
89addb82 191 add_uint32(d_message, Field::toPort, port);
a44a8d66
OM
192 }
193
87f46425
RG
194 void startResponse()
195 {
89addb82 196 d_response = protozero::pbf_writer{d_message, static_cast<protozero::pbf_tag_type>(Field::response)};
87f46425
RG
197 }
198
199 void commitResponse()
200 {
201 d_response.commit();
202 }
ac10822e 203
a44a8d66
OM
204 void setResponseCode(uint8_t rcode)
205 {
89addb82 206 d_response.add_uint32(static_cast<protozero::pbf_tag_type>(ResponseField::rcode), rcode);
a44a8d66 207 }
d58249ee 208
00b3e94a
RG
209 void setNetworkErrorResponseCode()
210 {
211 /* special code meaning 'network error', like a timeout */
89addb82 212 d_response.add_uint32(static_cast<protozero::pbf_tag_type>(ResponseField::rcode), 65536);
00b3e94a
RG
213 }
214
a44a8d66
OM
215 void setAppliedPolicy(const std::string& policy)
216 {
89addb82 217 d_response.add_string(static_cast<protozero::pbf_tag_type>(ResponseField::appliedPolicy), policy);
a44a8d66 218 }
87f46425 219
47a6825e 220 void addPolicyTags(const std::unordered_set<std::string>& tags)
a44a8d66
OM
221 {
222 for (const auto& tag : tags) {
89addb82 223 addPolicyTag(tag);
a44a8d66
OM
224 }
225 }
87f46425 226
a44a8d66
OM
227 void addPolicyTag(const string& tag)
228 {
89addb82 229 d_response.add_string(static_cast<protozero::pbf_tag_type>(ResponseField::tags), tag);
a44a8d66 230 }
87f46425 231
a44a8d66
OM
232 void setQueryTime(uint32_t sec, uint32_t usec)
233 {
89addb82
RG
234 d_response.add_uint32(static_cast<protozero::pbf_tag_type>(ResponseField::queryTimeSec), sec);
235 d_response.add_uint32(static_cast<protozero::pbf_tag_type>(ResponseField::queryTimeUsec), usec);
a44a8d66 236 }
a44a8d66 237
87f46425
RG
238 void addRRsFromPacket(const char* packet, const size_t len, bool includeCNAME=false);
239 void addRR(const DNSName& name, uint16_t uType, uint16_t uClass, uint32_t uTTL, const std::string& blob);
47a6825e 240
87f46425
RG
241 protected:
242 void encodeComboAddress(protozero::pbf_tag_type type, const ComboAddress& ca);
243 void encodeNetmask(protozero::pbf_tag_type type, const Netmask& subnet, uint8_t mask);
244 void encodeDNSName(protozero::pbf_writer& pbf, std::string& buffer, protozero::pbf_tag_type type, const DNSName& name);
245
89addb82
RG
246 static void add_enum(protozero::pbf_writer& writer, Field type, int32_t value)
247 {
248 writer.add_enum(static_cast<protozero::pbf_tag_type>(type), value);
249 }
250
251 static void add_bool(protozero::pbf_writer& writer, Field type, bool value)
252 {
253 writer.add_bool(static_cast<protozero::pbf_tag_type>(type), value);
254 }
255
256 static void add_uint32(protozero::pbf_writer& writer, Field type, uint32_t value)
257 {
258 writer.add_uint32(static_cast<protozero::pbf_tag_type>(type), value);
259 }
260
261 static void add_uint64(protozero::pbf_writer& writer, Field type, uint64_t value)
262 {
263 writer.add_uint64(static_cast<protozero::pbf_tag_type>(type), value);
264 }
265
0b184c82
ND
266 static void add_bytes(protozero::pbf_writer& writer, Field type, const char* data, size_t len)
267 {
268 writer.add_bytes(static_cast<protozero::pbf_tag_type>(type), data, len);
89addb82
RG
269 }
270
271 static void add_string(protozero::pbf_writer& writer, Field type, const std::string& str)
272 {
273 writer.add_string(static_cast<protozero::pbf_tag_type>(type), str);
274 }
275
276
87f46425 277 std::string& d_buffer;
ac10822e
OM
278 protozero::pbf_writer d_message;
279 protozero::pbf_writer d_response;
a44a8d66
OM
280 };
281 };
282};
454e9974
RG
283
284#endif /* DISABLE_PROTOBUF */