]>
Commit | Line | Data |
---|---|---|
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 |
34 | namespace 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 */ |