]> git.proxmox.com Git - ceph.git/blob - ceph/src/c-ares/test/dns-proto.cc
update sources to ceph Nautilus 14.2.1
[ceph.git] / ceph / src / c-ares / test / dns-proto.cc
1 #include "dns-proto.h"
2
3 // Include ares internal file for DNS protocol details
4 #include "ares.h"
5 #include "ares_dns.h"
6
7 #include <stdio.h>
8 #include <stdlib.h>
9
10 #include <sstream>
11
12 namespace ares {
13
14 std::string HexDump(std::vector<byte> data) {
15 std::stringstream ss;
16 for (size_t ii = 0; ii < data.size(); ii++) {
17 char buffer[2 + 1];
18 sprintf(buffer, "%02x", data[ii]);
19 ss << buffer;
20 }
21 return ss.str();
22 }
23
24 std::string HexDump(const byte *data, int len) {
25 return HexDump(std::vector<byte>(data, data + len));
26 }
27
28 std::string HexDump(const char *data, int len) {
29 return HexDump(reinterpret_cast<const byte*>(data), len);
30 }
31
32 std::string StatusToString(int status) {
33 switch (status) {
34 case ARES_SUCCESS: return "ARES_SUCCESS";
35 case ARES_ENODATA: return "ARES_ENODATA";
36 case ARES_EFORMERR: return "ARES_EFORMERR";
37 case ARES_ESERVFAIL: return "ARES_ESERVFAIL";
38 case ARES_ENOTFOUND: return "ARES_ENOTFOUND";
39 case ARES_ENOTIMP: return "ARES_ENOTIMP";
40 case ARES_EREFUSED: return "ARES_EREFUSED";
41 case ARES_EBADQUERY: return "ARES_EBADQUERY";
42 case ARES_EBADNAME: return "ARES_EBADNAME";
43 case ARES_EBADFAMILY: return "ARES_EBADFAMILY";
44 case ARES_EBADRESP: return "ARES_EBADRESP";
45 case ARES_ECONNREFUSED: return "ARES_ECONNREFUSED";
46 case ARES_ETIMEOUT: return "ARES_ETIMEOUT";
47 case ARES_EOF: return "ARES_EOF";
48 case ARES_EFILE: return "ARES_EFILE";
49 case ARES_ENOMEM: return "ARES_ENOMEM";
50 case ARES_EDESTRUCTION: return "ARES_EDESTRUCTION";
51 case ARES_EBADSTR: return "ARES_EBADSTR";
52 case ARES_EBADFLAGS: return "ARES_EBADFLAGS";
53 case ARES_ENONAME: return "ARES_ENONAME";
54 case ARES_EBADHINTS: return "ARES_EBADHINTS";
55 case ARES_ENOTINITIALIZED: return "ARES_ENOTINITIALIZED";
56 case ARES_ELOADIPHLPAPI: return "ARES_ELOADIPHLPAPI";
57 case ARES_EADDRGETNETWORKPARAMS: return "ARES_EADDRGETNETWORKPARAMS";
58 case ARES_ECANCELLED: return "ARES_ECANCELLED";
59 default: return "UNKNOWN";
60 }
61 }
62
63 std::string RcodeToString(int rcode) {
64 switch (rcode) {
65 case ns_r_noerror: return "NOERROR";
66 case ns_r_formerr: return "FORMERR";
67 case ns_r_servfail: return "SERVFAIL";
68 case ns_r_nxdomain: return "NXDOMAIN";
69 case ns_r_notimpl: return "NOTIMPL";
70 case ns_r_refused: return "REFUSED";
71 case ns_r_yxdomain: return "YXDOMAIN";
72 case ns_r_yxrrset: return "YXRRSET";
73 case ns_r_nxrrset: return "NXRRSET";
74 case ns_r_notauth: return "NOTAUTH";
75 case ns_r_notzone: return "NOTZONE";
76 case ns_r_badsig: return "BADSIG";
77 case ns_r_badkey: return "BADKEY";
78 case ns_r_badtime: return "BADTIME";
79 default: return "UNKNOWN";
80 }
81 }
82
83 std::string RRTypeToString(int rrtype) {
84 switch (rrtype) {
85 case ns_t_a: return "A";
86 case ns_t_ns: return "NS";
87 case ns_t_md: return "MD";
88 case ns_t_mf: return "MF";
89 case ns_t_cname: return "CNAME";
90 case ns_t_soa: return "SOA";
91 case ns_t_mb: return "MB";
92 case ns_t_mg: return "MG";
93 case ns_t_mr: return "MR";
94 case ns_t_null: return "NULL";
95 case ns_t_wks: return "WKS";
96 case ns_t_ptr: return "PTR";
97 case ns_t_hinfo: return "HINFO";
98 case ns_t_minfo: return "MINFO";
99 case ns_t_mx: return "MX";
100 case ns_t_txt: return "TXT";
101 case ns_t_rp: return "RP";
102 case ns_t_afsdb: return "AFSDB";
103 case ns_t_x25: return "X25";
104 case ns_t_isdn: return "ISDN";
105 case ns_t_rt: return "RT";
106 case ns_t_nsap: return "NSAP";
107 case ns_t_nsap_ptr: return "NSAP_PTR";
108 case ns_t_sig: return "SIG";
109 case ns_t_key: return "KEY";
110 case ns_t_px: return "PX";
111 case ns_t_gpos: return "GPOS";
112 case ns_t_aaaa: return "AAAA";
113 case ns_t_loc: return "LOC";
114 case ns_t_nxt: return "NXT";
115 case ns_t_eid: return "EID";
116 case ns_t_nimloc: return "NIMLOC";
117 case ns_t_srv: return "SRV";
118 case ns_t_atma: return "ATMA";
119 case ns_t_naptr: return "NAPTR";
120 case ns_t_kx: return "KX";
121 case ns_t_cert: return "CERT";
122 case ns_t_a6: return "A6";
123 case ns_t_dname: return "DNAME";
124 case ns_t_sink: return "SINK";
125 case ns_t_opt: return "OPT";
126 case ns_t_apl: return "APL";
127 case ns_t_ds: return "DS";
128 case ns_t_sshfp: return "SSHFP";
129 case ns_t_rrsig: return "RRSIG";
130 case ns_t_nsec: return "NSEC";
131 case ns_t_dnskey: return "DNSKEY";
132 case ns_t_tkey: return "TKEY";
133 case ns_t_tsig: return "TSIG";
134 case ns_t_ixfr: return "IXFR";
135 case ns_t_axfr: return "AXFR";
136 case ns_t_mailb: return "MAILB";
137 case ns_t_maila: return "MAILA";
138 case ns_t_any: return "ANY";
139 case ns_t_zxfr: return "ZXFR";
140 case ns_t_max: return "MAX";
141 default: return "UNKNOWN";
142 }
143 }
144
145 std::string ClassToString(int qclass) {
146 switch (qclass) {
147 case ns_c_in: return "IN";
148 case ns_c_chaos: return "CHAOS";
149 case ns_c_hs: return "HESIOD";
150 case ns_c_none: return "NONE";
151 case ns_c_any: return "ANY";
152 default: return "UNKNOWN";
153 }
154 }
155
156 std::string AddressToString(const void* vaddr, int len) {
157 const byte* addr = reinterpret_cast<const byte*>(vaddr);
158 std::stringstream ss;
159 if (len == 4) {
160 char buffer[4*4 + 3 + 1];
161 sprintf(buffer, "%u.%u.%u.%u",
162 (unsigned char)addr[0],
163 (unsigned char)addr[1],
164 (unsigned char)addr[2],
165 (unsigned char)addr[3]);
166 ss << buffer;
167 } else if (len == 16) {
168 for (int ii = 0; ii < 16; ii+=2) {
169 if (ii > 0) ss << ':';
170 char buffer[4 + 1];
171 sprintf(buffer, "%02x%02x", (unsigned char)addr[ii], (unsigned char)addr[ii+1]);
172 ss << buffer;
173 }
174 } else {
175 ss << "!" << HexDump(addr, len) << "!";
176 }
177 return ss.str();
178 }
179
180 std::string PacketToString(const std::vector<byte>& packet) {
181 const byte* data = packet.data();
182 int len = packet.size();
183 std::stringstream ss;
184 if (len < NS_HFIXEDSZ) {
185 ss << "(too short, len " << len << ")";
186 return ss.str();
187 }
188 ss << ((DNS_HEADER_QR(data) == 0) ? "REQ " : "RSP ");
189 switch (DNS_HEADER_OPCODE(data)) {
190 case ns_o_query: ss << "QRY "; break;
191 case ns_o_iquery: ss << "IQRY "; break;
192 case ns_o_status: ss << "STATUS "; break;
193 case ns_o_notify: ss << "NOTIFY "; break;
194 case ns_o_update: ss << "UPDATE "; break;
195 default: ss << "UNKNOWN(" << DNS_HEADER_OPCODE(data) << ") "; break;
196 }
197 if (DNS_HEADER_AA(data)) ss << "AA ";
198 if (DNS_HEADER_TC(data)) ss << "TC ";
199 if (DNS_HEADER_RD(data)) ss << "RD ";
200 if (DNS_HEADER_RA(data)) ss << "RA ";
201 if (DNS_HEADER_Z(data)) ss << "Z ";
202 if (DNS_HEADER_QR(data) == 1) ss << RcodeToString(DNS_HEADER_RCODE(data));
203
204 int nquestions = DNS_HEADER_QDCOUNT(data);
205 int nanswers = DNS_HEADER_ANCOUNT(data);
206 int nauths = DNS_HEADER_NSCOUNT(data);
207 int nadds = DNS_HEADER_ARCOUNT(data);
208
209 const byte* pq = data + NS_HFIXEDSZ;
210 len -= NS_HFIXEDSZ;
211 for (int ii = 0; ii < nquestions; ii++) {
212 ss << " Q:" << QuestionToString(packet, &pq, &len);
213 }
214 const byte* prr = pq;
215 for (int ii = 0; ii < nanswers; ii++) {
216 ss << " A:" << RRToString(packet, &prr, &len);
217 }
218 for (int ii = 0; ii < nauths; ii++) {
219 ss << " AUTH:" << RRToString(packet, &prr, &len);
220 }
221 for (int ii = 0; ii < nadds; ii++) {
222 ss << " ADD:" << RRToString(packet, &prr, &len);
223 }
224 return ss.str();
225 }
226
227 std::string QuestionToString(const std::vector<byte>& packet,
228 const byte** data, int* len) {
229 std::stringstream ss;
230 ss << "{";
231 if (*len < NS_QFIXEDSZ) {
232 ss << "(too short, len " << *len << ")";
233 return ss.str();
234 }
235
236 char *name = nullptr;
237 long enclen;
238 int rc = ares_expand_name(*data, packet.data(), packet.size(), &name, &enclen);
239 if (rc != ARES_SUCCESS) {
240 ss << "(error from ares_expand_name)";
241 return ss.str();
242 }
243 if (enclen > *len) {
244 ss << "(error, encoded name len " << enclen << "bigger than remaining data " << *len << " bytes)";
245 return ss.str();
246 }
247 *len -= enclen;
248 *data += enclen;
249 ss << "'" << name << "' ";
250 free(name);
251 if (*len < NS_QFIXEDSZ) {
252 ss << "(too short, len left " << *len << ")";
253 return ss.str();
254 }
255 ss << ClassToString(DNS_QUESTION_CLASS(*data)) << " ";
256 ss << RRTypeToString(DNS_QUESTION_TYPE(*data));
257 *data += NS_QFIXEDSZ;
258 *len -= NS_QFIXEDSZ;
259 ss << "}";
260 return ss.str();
261 }
262
263 std::string RRToString(const std::vector<byte>& packet,
264 const byte** data, int* len) {
265 std::stringstream ss;
266 ss << "{";
267 if (*len < NS_RRFIXEDSZ) {
268 ss << "too short, len " << *len << ")";
269 return ss.str();
270 }
271
272 char *name = nullptr;
273 long enclen;
274 int rc = ares_expand_name(*data, packet.data(), packet.size(), &name, &enclen);
275 if (rc != ARES_SUCCESS) {
276 ss << "(error from ares_expand_name)";
277 return ss.str();
278 }
279 if (enclen > *len) {
280 ss << "(error, encoded name len " << enclen << "bigger than remaining data " << *len << " bytes)";
281 return ss.str();
282 }
283 *len -= enclen;
284 *data += enclen;
285 ss << "'" << name << "' ";
286 free(name);
287 name = nullptr;
288
289 if (*len < NS_RRFIXEDSZ) {
290 ss << "(too short, len left " << *len << ")";
291 return ss.str();
292 }
293 int rrtype = DNS_RR_TYPE(*data);
294 if (rrtype == ns_t_opt) {
295 ss << "MAXUDP=" << DNS_RR_CLASS(*data) << " ";
296 ss << RRTypeToString(rrtype) << " ";
297 ss << "RCODE2=" << DNS_RR_TTL(*data);
298 } else {
299 ss << ClassToString(DNS_RR_CLASS(*data)) << " ";
300 ss << RRTypeToString(rrtype) << " ";
301 ss << "TTL=" << DNS_RR_TTL(*data);
302 }
303 int rdatalen = DNS_RR_LEN(*data);
304
305 *data += NS_RRFIXEDSZ;
306 *len -= NS_RRFIXEDSZ;
307 if (*len < rdatalen) {
308 ss << "(RR too long at " << rdatalen << ", len left " << *len << ")";
309 } else {
310 switch (rrtype) {
311 case ns_t_a:
312 case ns_t_aaaa:
313 ss << " " << AddressToString(*data, rdatalen);
314 break;
315 case ns_t_txt: {
316 const byte* p = *data;
317 while (p < (*data + rdatalen)) {
318 int len = *p++;
319 if ((p + len) <= (*data + rdatalen)) {
320 std::string txt(p, p + len);
321 ss << " " << len << ":'" << txt << "'";
322 } else {
323 ss << "(string too long)";
324 }
325 p += len;
326 }
327 break;
328 }
329 case ns_t_cname:
330 case ns_t_ns:
331 case ns_t_ptr: {
332 int rc = ares_expand_name(*data, packet.data(), packet.size(), &name, &enclen);
333 if (rc != ARES_SUCCESS) {
334 ss << "(error from ares_expand_name)";
335 break;
336 }
337 ss << " '" << name << "'";
338 free(name);
339 break;
340 }
341 case ns_t_mx:
342 if (rdatalen > 2) {
343 int rc = ares_expand_name(*data + 2, packet.data(), packet.size(), &name, &enclen);
344 if (rc != ARES_SUCCESS) {
345 ss << "(error from ares_expand_name)";
346 break;
347 }
348 ss << " " << DNS__16BIT(*data) << " '" << name << "'";
349 free(name);
350 } else {
351 ss << "(RR too short)";
352 }
353 break;
354 case ns_t_srv: {
355 if (rdatalen > 6) {
356 const byte* p = *data;
357 unsigned long prio = DNS__16BIT(p);
358 unsigned long weight = DNS__16BIT(p + 2);
359 unsigned long port = DNS__16BIT(p + 4);
360 p += 6;
361 int rc = ares_expand_name(p, packet.data(), packet.size(), &name, &enclen);
362 if (rc != ARES_SUCCESS) {
363 ss << "(error from ares_expand_name)";
364 break;
365 }
366 ss << prio << " " << weight << " " << port << " '" << name << "'";
367 free(name);
368 } else {
369 ss << "(RR too short)";
370 }
371 break;
372 }
373 case ns_t_soa: {
374 const byte* p = *data;
375 int rc = ares_expand_name(p, packet.data(), packet.size(), &name, &enclen);
376 if (rc != ARES_SUCCESS) {
377 ss << "(error from ares_expand_name)";
378 break;
379 }
380 ss << " '" << name << "'";
381 free(name);
382 p += enclen;
383 rc = ares_expand_name(p, packet.data(), packet.size(), &name, &enclen);
384 if (rc != ARES_SUCCESS) {
385 ss << "(error from ares_expand_name)";
386 break;
387 }
388 ss << " '" << name << "'";
389 free(name);
390 p += enclen;
391 if ((p + 20) <= (*data + rdatalen)) {
392 unsigned long serial = DNS__32BIT(p);
393 unsigned long refresh = DNS__32BIT(p + 4);
394 unsigned long retry = DNS__32BIT(p + 8);
395 unsigned long expire = DNS__32BIT(p + 12);
396 unsigned long minimum = DNS__32BIT(p + 16);
397 ss << " " << serial << " " << refresh << " " << retry << " " << expire << " " << minimum;
398 } else {
399 ss << "(RR too short)";
400 }
401 break;
402 }
403 case ns_t_naptr: {
404 if (rdatalen > 7) {
405 const byte* p = *data;
406 unsigned long order = DNS__16BIT(p);
407 unsigned long pref = DNS__16BIT(p + 2);
408 p += 4;
409 ss << order << " " << pref;
410
411 int len = *p++;
412 std::string flags(p, p + len);
413 ss << " " << flags;
414 p += len;
415
416 len = *p++;
417 std::string service(p, p + len);
418 ss << " '" << service << "'";
419 p += len;
420
421 len = *p++;
422 std::string regexp(p, p + len);
423 ss << " '" << regexp << "'";
424 p += len;
425
426 int rc = ares_expand_name(p, packet.data(), packet.size(), &name, &enclen);
427 if (rc != ARES_SUCCESS) {
428 ss << "(error from ares_expand_name)";
429 break;
430 }
431 ss << " '" << name << "'";
432 free(name);
433 } else {
434 ss << "(RR too short)";
435 }
436 break;
437 }
438 default:
439 ss << " " << HexDump(*data, rdatalen);
440 break;
441 }
442 }
443 *data += rdatalen;
444 *len -= rdatalen;
445
446 ss << "}";
447 return ss.str();
448 }
449
450 void PushInt32(std::vector<byte>* data, int value) {
451 data->push_back((value & 0xff000000) >> 24);
452 data->push_back((value & 0x00ff0000) >> 16);
453 data->push_back((value & 0x0000ff00) >> 8);
454 data->push_back(value & 0x000000ff);
455 }
456
457 void PushInt16(std::vector<byte>* data, int value) {
458 data->push_back((value & 0xff00) >> 8);
459 data->push_back(value & 0x00ff);
460 }
461
462 std::vector<byte> EncodeString(const std::string& name) {
463 std::vector<byte> data;
464 std::stringstream ss(name);
465 std::string label;
466 // TODO: cope with escapes
467 while (std::getline(ss, label, '.')) {
468 data.push_back(label.length());
469 data.insert(data.end(), label.begin(), label.end());
470 }
471 data.push_back(0);
472 return data;
473 }
474
475 std::vector<byte> DNSQuestion::data() const {
476 std::vector<byte> data;
477 std::vector<byte> encname = EncodeString(name_);
478 data.insert(data.end(), encname.begin(), encname.end());
479 PushInt16(&data, rrtype_);
480 PushInt16(&data, qclass_);
481 return data;
482 }
483
484 std::vector<byte> DNSRR::data() const {
485 std::vector<byte> data = DNSQuestion::data();
486 PushInt32(&data, ttl_);
487 return data;
488 }
489
490 std::vector<byte> DNSSingleNameRR::data() const {
491 std::vector<byte> data = DNSRR::data();
492 std::vector<byte> encname = EncodeString(other_);
493 int len = encname.size();
494 PushInt16(&data, len);
495 data.insert(data.end(), encname.begin(), encname.end());
496 return data;
497 }
498
499 std::vector<byte> DNSTxtRR::data() const {
500 std::vector<byte> data = DNSRR::data();
501 int len = 0;
502 for (const std::string& txt : txt_) {
503 len += (1 + txt.size());
504 }
505 PushInt16(&data, len);
506 for (const std::string& txt : txt_) {
507 data.push_back(txt.size());
508 data.insert(data.end(), txt.begin(), txt.end());
509 }
510 return data;
511 }
512
513 std::vector<byte> DNSMxRR::data() const {
514 std::vector<byte> data = DNSRR::data();
515 std::vector<byte> encname = EncodeString(other_);
516 int len = 2 + encname.size();
517 PushInt16(&data, len);
518 PushInt16(&data, pref_);
519 data.insert(data.end(), encname.begin(), encname.end());
520 return data;
521 }
522
523 std::vector<byte> DNSSrvRR::data() const {
524 std::vector<byte> data = DNSRR::data();
525 std::vector<byte> encname = EncodeString(target_);
526 int len = 6 + encname.size();
527 PushInt16(&data, len);
528 PushInt16(&data, prio_);
529 PushInt16(&data, weight_);
530 PushInt16(&data, port_);
531 data.insert(data.end(), encname.begin(), encname.end());
532 return data;
533 }
534
535 std::vector<byte> DNSAddressRR::data() const {
536 std::vector<byte> data = DNSRR::data();
537 int len = addr_.size();
538 PushInt16(&data, len);
539 data.insert(data.end(), addr_.begin(), addr_.end());
540 return data;
541 }
542
543 std::vector<byte> DNSSoaRR::data() const {
544 std::vector<byte> data = DNSRR::data();
545 std::vector<byte> encname1 = EncodeString(nsname_);
546 std::vector<byte> encname2 = EncodeString(rname_);
547 int len = encname1.size() + encname2.size() + 5*4;
548 PushInt16(&data, len);
549 data.insert(data.end(), encname1.begin(), encname1.end());
550 data.insert(data.end(), encname2.begin(), encname2.end());
551 PushInt32(&data, serial_);
552 PushInt32(&data, refresh_);
553 PushInt32(&data, retry_);
554 PushInt32(&data, expire_);
555 PushInt32(&data, minimum_);
556 return data;
557 }
558
559 std::vector<byte> DNSOptRR::data() const {
560 std::vector<byte> data = DNSRR::data();
561 int len = 0;
562 for (const DNSOption& opt : opts_) {
563 len += (4 + opt.data_.size());
564 }
565 PushInt16(&data, len);
566 for (const DNSOption& opt : opts_) {
567 PushInt16(&data, opt.code_);
568 PushInt16(&data, opt.data_.size());
569 data.insert(data.end(), opt.data_.begin(), opt.data_.end());
570 }
571 return data;
572 }
573
574 std::vector<byte> DNSNaptrRR::data() const {
575 std::vector<byte> data = DNSRR::data();
576 std::vector<byte> encname = EncodeString(replacement_);
577 int len = (4 + 1 + flags_.size() + 1 + service_.size() + 1 + regexp_.size() + encname.size());
578 PushInt16(&data, len);
579 PushInt16(&data, order_);
580 PushInt16(&data, pref_);
581 data.push_back(flags_.size());
582 data.insert(data.end(), flags_.begin(), flags_.end());
583 data.push_back(service_.size());
584 data.insert(data.end(), service_.begin(), service_.end());
585 data.push_back(regexp_.size());
586 data.insert(data.end(), regexp_.begin(), regexp_.end());
587 data.insert(data.end(), encname.begin(), encname.end());
588 return data;
589 }
590
591 std::vector<byte> DNSPacket::data() const {
592 std::vector<byte> data;
593 PushInt16(&data, qid_);
594 byte b = 0x00;
595 if (response_) b |= 0x80;
596 b |= ((opcode_ & 0x0f) << 3);
597 if (aa_) b |= 0x04;
598 if (tc_) b |= 0x02;
599 if (rd_) b |= 0x01;
600 data.push_back(b);
601 b = 0x00;
602 if (ra_) b |= 0x80;
603 if (z_) b |= 0x40;
604 if (ad_) b |= 0x20;
605 if (cd_) b |= 0x10;
606 b |= (rcode_ & 0x0f);
607 data.push_back(b);
608
609 int count = questions_.size();
610 PushInt16(&data, count);
611 count = answers_.size();
612 PushInt16(&data, count);
613 count = auths_.size();
614 PushInt16(&data, count);
615 count = adds_.size();
616 PushInt16(&data, count);
617
618 for (const std::unique_ptr<DNSQuestion>& question : questions_) {
619 std::vector<byte> qdata = question->data();
620 data.insert(data.end(), qdata.begin(), qdata.end());
621 }
622 for (const std::unique_ptr<DNSRR>& rr : answers_) {
623 std::vector<byte> rrdata = rr->data();
624 data.insert(data.end(), rrdata.begin(), rrdata.end());
625 }
626 for (const std::unique_ptr<DNSRR>& rr : auths_) {
627 std::vector<byte> rrdata = rr->data();
628 data.insert(data.end(), rrdata.begin(), rrdata.end());
629 }
630 for (const std::unique_ptr<DNSRR>& rr : adds_) {
631 std::vector<byte> rrdata = rr->data();
632 data.insert(data.end(), rrdata.begin(), rrdata.end());
633 }
634 return data;
635 }
636
637 } // namespace ares