]> git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/protobuf.cc
Merge pull request #8223 from PowerDNS/omoerbeek-patch-1
[thirdparty/pdns.git] / pdns / protobuf.cc
1
2 #include "gettime.hh"
3 #include "dnsparser.hh"
4 #include "protobuf.hh"
5 #include "dnsparser.hh"
6 #include "gettime.hh"
7
8 void DNSProtoBufMessage::setType(DNSProtoBufMessageType type)
9 {
10 #ifdef HAVE_PROTOBUF
11 switch(type) {
12 case DNSProtoBufMessage::DNSProtoBufMessageType::Query:
13 d_message.set_type(PBDNSMessage_Type_DNSQueryType);
14 break;
15 case DNSProtoBufMessage::DNSProtoBufMessageType::Response:
16 d_message.set_type(PBDNSMessage_Type_DNSResponseType);
17 break;
18 case DNSProtoBufMessage::DNSProtoBufMessageType::OutgoingQuery:
19 d_message.set_type(PBDNSMessage_Type_DNSOutgoingQueryType);
20 break;
21 case DNSProtoBufMessage::DNSProtoBufMessageType::IncomingResponse:
22 d_message.set_type(PBDNSMessage_Type_DNSIncomingResponseType);
23 break;
24 default:
25 throw std::runtime_error("Unsupported protobuf type: "+std::to_string(type));
26 }
27 #endif /* HAVE_PROTOBUF */
28 }
29
30 DNSProtoBufMessage::DNSProtoBufMessage(DNSProtoBufMessageType type)
31 {
32 setType(type);
33 }
34
35 void DNSProtoBufMessage::setQuestion(const DNSName& qname, uint16_t qtype, uint16_t qclass)
36 {
37 #ifdef HAVE_PROTOBUF
38 PBDNSMessage_DNSQuestion* question = d_message.mutable_question();
39 if (question) {
40 if(!qname.empty())
41 question->set_qname(qname.toString());
42 question->set_qtype(qtype);
43 question->set_qclass(qclass);
44 }
45 #endif /* HAVE_PROTOBUF */
46 }
47
48 void DNSProtoBufMessage::setBytes(size_t bytes)
49 {
50 #ifdef HAVE_PROTOBUF
51 d_message.set_inbytes(bytes);
52 #endif /* HAVE_PROTOBUF */
53 }
54
55 void DNSProtoBufMessage::setResponseCode(uint8_t rcode)
56 {
57 #ifdef HAVE_PROTOBUF
58 PBDNSMessage_DNSResponse* response = d_message.mutable_response();
59 if (response) {
60 response->set_rcode(rcode);
61 }
62 #endif /* HAVE_PROTOBUF */
63 }
64
65 void DNSProtoBufMessage::setNetworkErrorResponseCode()
66 {
67 #ifdef HAVE_PROTOBUF
68 PBDNSMessage_DNSResponse* response = d_message.mutable_response();
69 if (response) {
70 /* special code meaning 'network error', like a timeout */
71 response->set_rcode(65536);
72 }
73 #endif /* HAVE_PROTOBUF */
74 }
75
76 void DNSProtoBufMessage::setTime(time_t sec, uint32_t usec)
77 {
78 #ifdef HAVE_PROTOBUF
79 d_message.set_timesec(sec);
80 d_message.set_timeusec(usec);
81 #endif /* HAVE_PROTOBUF */
82 }
83
84 void DNSProtoBufMessage::setQueryTime(time_t sec, uint32_t usec)
85 {
86 #ifdef HAVE_PROTOBUF
87 PBDNSMessage_DNSResponse* response = d_message.mutable_response();
88 if (response) {
89 response->set_querytimesec(sec);
90 response->set_querytimeusec(usec);
91 }
92 #endif /* HAVE_PROTOBUF */
93 }
94
95 void DNSProtoBufMessage::setEDNSSubnet(const Netmask& subnet, uint8_t mask)
96 {
97 #ifdef HAVE_PROTOBUF
98 if (!subnet.empty()) {
99 ComboAddress ca(subnet.getNetwork());
100 ca.truncate(mask);
101 if (ca.sin4.sin_family == AF_INET) {
102 d_message.set_originalrequestorsubnet(&ca.sin4.sin_addr.s_addr, sizeof(ca.sin4.sin_addr.s_addr));
103 }
104 else if (ca.sin4.sin_family == AF_INET6) {
105 d_message.set_originalrequestorsubnet(&ca.sin6.sin6_addr.s6_addr, sizeof(ca.sin6.sin6_addr.s6_addr));
106 }
107 }
108 #endif /* HAVE_PROTOBUF */
109 }
110
111 void DNSProtoBufMessage::addTag(const std::string& strValue)
112 {
113 #ifdef HAVE_PROTOBUF
114
115 PBDNSMessage_DNSResponse* response = d_message.mutable_response();
116 if (!response)
117 return;
118
119 response->add_tags(strValue);
120
121 #endif /* HAVE_PROTOBUF */
122 }
123
124 void DNSProtoBufMessage::addRR(const DNSName& qname, uint16_t uType, uint16_t uClass, uint32_t uTTL, const std::string& strBlob)
125 {
126 #ifdef HAVE_PROTOBUF
127
128 PBDNSMessage_DNSResponse* response = d_message.mutable_response();
129 if (!response)
130 return;
131 PBDNSMessage_DNSResponse_DNSRR* rr = response->add_rrs();
132 if (rr) {
133 rr->set_name(qname.toString());
134 rr->set_type(uType);
135 rr->set_class_(uClass);
136 rr->set_ttl(uTTL);
137 rr->set_rdata(strBlob.c_str(), strBlob.size());
138 }
139
140 #endif /* HAVE_PROTOBUF */
141 }
142
143 void DNSProtoBufMessage::addRRsFromPacket(const char* packet, const size_t len, bool includeCNAME)
144 {
145 #ifdef HAVE_PROTOBUF
146 if (len < sizeof(struct dnsheader))
147 return;
148
149 const struct dnsheader* dh = (const struct dnsheader*) packet;
150
151 if (ntohs(dh->ancount) == 0)
152 return;
153
154 if (ntohs(dh->qdcount) == 0)
155 return;
156
157 PBDNSMessage_DNSResponse* response = d_message.mutable_response();
158 if (!response)
159 return;
160
161 std::string packetStr(packet, len);
162 PacketReader pr(packetStr);
163
164 size_t idx = 0;
165 DNSName rrname;
166 uint16_t qdcount = ntohs(dh->qdcount);
167 uint16_t ancount = ntohs(dh->ancount);
168 uint16_t rrtype;
169 uint16_t rrclass;
170 string blob;
171 struct dnsrecordheader ah;
172
173 rrname = pr.getName();
174 rrtype = pr.get16BitInt();
175 rrclass = pr.get16BitInt();
176
177 /* consume remaining qd if any */
178 if (qdcount > 1) {
179 for(idx = 1; idx < qdcount; idx++) {
180 rrname = pr.getName();
181 rrtype = pr.get16BitInt();
182 rrclass = pr.get16BitInt();
183 (void) rrtype;
184 (void) rrclass;
185 }
186 }
187
188 /* parse AN */
189 for (idx = 0; idx < ancount; idx++) {
190 rrname = pr.getName();
191 pr.getDnsrecordheader(ah);
192
193 if (ah.d_type == QType::A || ah.d_type == QType::AAAA) {
194 pr.xfrBlob(blob);
195
196 PBDNSMessage_DNSResponse_DNSRR* rr = response->add_rrs();
197 if (rr) {
198 rr->set_name(rrname.toString());
199 rr->set_type(ah.d_type);
200 rr->set_class_(ah.d_class);
201 rr->set_ttl(ah.d_ttl);
202 rr->set_rdata(blob.c_str(), blob.length());
203 }
204 } else if (ah.d_type == QType::CNAME && includeCNAME) {
205 PBDNSMessage_DNSResponse_DNSRR* rr = response->add_rrs();
206 if (rr) {
207 rr->set_name(rrname.toString());
208 rr->set_type(ah.d_type);
209 rr->set_class_(ah.d_class);
210 rr->set_ttl(ah.d_ttl);
211 DNSName target;
212 pr.xfrName(target, true);
213 rr->set_rdata(target.toString());
214 }
215 }
216 else {
217 pr.xfrBlob(blob);
218 }
219 }
220 #endif /* HAVE_PROTOBUF */
221 }
222
223 void DNSProtoBufMessage::setRequestor(const std::string& requestor)
224 {
225 #ifdef HAVE_PROTOBUF
226 d_message.set_from(requestor);
227 #endif /* HAVE_PROTOBUF */
228 }
229
230 void DNSProtoBufMessage::setRequestor(const ComboAddress& requestor)
231 {
232 #ifdef HAVE_PROTOBUF
233 if (requestor.sin4.sin_family == AF_INET) {
234 d_message.set_from(&requestor.sin4.sin_addr.s_addr, sizeof(requestor.sin4.sin_addr.s_addr));
235 }
236 else if (requestor.sin4.sin_family == AF_INET6) {
237 d_message.set_from(&requestor.sin6.sin6_addr.s6_addr, sizeof(requestor.sin6.sin6_addr.s6_addr));
238 }
239 #endif /* HAVE_PROTOBUF */
240 }
241
242 void DNSProtoBufMessage::setRequestorId(const std::string& requestorId)
243 {
244 #ifdef HAVE_PROTOBUF
245 d_message.set_requestorid(requestorId);
246 #endif /* HAVE_PROTOBUF */
247 }
248
249 void DNSProtoBufMessage::setDeviceId(const std::string& deviceId)
250 {
251 #ifdef HAVE_PROTOBUF
252 d_message.set_deviceid(deviceId);
253 #endif /* HAVE_PROTOBUF */
254 }
255
256 void DNSProtoBufMessage::setDeviceName(const std::string& deviceName)
257 {
258 #ifdef HAVE_PROTOBUF
259 d_message.set_devicename(deviceName);
260 #endif /* HAVE_PROTOBUF */
261 }
262
263 void DNSProtoBufMessage::setServerIdentity(const std::string& serverId)
264 {
265 #ifdef HAVE_PROTOBUF
266 d_message.set_serveridentity(serverId);
267 #endif /* HAVE_PROTOBUF */
268 }
269
270 void DNSProtoBufMessage::setResponder(const std::string& responder)
271 {
272 #ifdef HAVE_PROTOBUF
273 d_message.set_to(responder);
274 #endif /* HAVE_PROTOBUF */
275 }
276
277 void DNSProtoBufMessage::setResponder(const ComboAddress& responder)
278 {
279 #ifdef HAVE_PROTOBUF
280 if (responder.sin4.sin_family == AF_INET) {
281 d_message.set_to(&responder.sin4.sin_addr.s_addr, sizeof(responder.sin4.sin_addr.s_addr));
282 }
283 else if (responder.sin4.sin_family == AF_INET6) {
284 d_message.set_to(&responder.sin6.sin6_addr.s6_addr, sizeof(responder.sin6.sin6_addr.s6_addr));
285 }
286 #endif /* HAVE_PROTOBUF */
287 }
288
289 void DNSProtoBufMessage::serialize(std::string& data) const
290 {
291 #ifdef HAVE_PROTOBUF
292 d_message.SerializeToString(&data);
293 #endif /* HAVE_PROTOBUF */
294 }
295
296 std::string DNSProtoBufMessage::toDebugString() const
297 {
298 #ifdef HAVE_PROTOBUF
299 return d_message.DebugString();
300 #else
301 return std::string();
302 #endif /* HAVE_PROTOBUF */
303 }
304
305 #ifdef HAVE_PROTOBUF
306
307 void DNSProtoBufMessage::setUUID(const boost::uuids::uuid& uuid)
308 {
309 std::string* messageId = d_message.mutable_messageid();
310 messageId->resize(uuid.size());
311 std::copy(uuid.begin(), uuid.end(), messageId->begin());
312 }
313
314 void DNSProtoBufMessage::setInitialRequestID(const boost::uuids::uuid& uuid)
315 {
316 std::string* messageId = d_message.mutable_initialrequestid();
317 messageId->resize(uuid.size());
318 std::copy(uuid.begin(), uuid.end(), messageId->begin());
319 }
320
321 void DNSProtoBufMessage::updateTime()
322 {
323 struct timespec ts;
324 gettime(&ts, true);
325 setTime(ts.tv_sec, ts.tv_nsec / 1000);
326 }
327
328 void DNSProtoBufMessage::update(const boost::uuids::uuid& uuid, const ComboAddress* requestor, const ComboAddress* responder, bool isTCP, uint16_t id)
329 {
330 updateTime();
331 setUUID(uuid);
332 d_message.set_id(ntohs(id));
333
334 if (requestor) {
335 d_message.set_socketfamily(requestor->sin4.sin_family == AF_INET ? PBDNSMessage_SocketFamily_INET : PBDNSMessage_SocketFamily_INET6);
336 }
337 else if (responder) {
338 d_message.set_socketfamily(responder->sin4.sin_family == AF_INET ? PBDNSMessage_SocketFamily_INET : PBDNSMessage_SocketFamily_INET6);
339 }
340
341 d_message.set_socketprotocol(isTCP ? PBDNSMessage_SocketProtocol_TCP : PBDNSMessage_SocketProtocol_UDP);
342
343 if (responder) {
344 setResponder(*responder);
345 }
346 if (requestor) {
347 setRequestor(*requestor);
348 }
349 }
350
351
352 DNSProtoBufMessage::DNSProtoBufMessage(DNSProtoBufMessageType type, const boost::uuids::uuid& uuid, const ComboAddress* requestor, const ComboAddress* responder, const DNSName& domain, int qtype, uint16_t qclass, uint16_t qid, bool isTCP, size_t bytes)
353 {
354 update(uuid, requestor, responder, isTCP, qid);
355
356 setType(type);
357
358 setBytes(bytes);
359 setQuestion(domain, qtype, qclass);
360 }
361
362 void DNSProtoBufMessage::copyFrom(const DNSProtoBufMessage& msg)
363 {
364 d_message.CopyFrom(msg.d_message);
365 }
366
367 #endif /* HAVE_PROTOBUF */