Bitcoin ABC 0.32.4
P2P Digital Currency
dns.cpp
Go to the documentation of this file.
1// Copyright (c) 2017-2020 The Bitcoin developers
2// Distributed under the MIT software license, see the accompanying
3// file COPYING or http://www.opensource.org/licenses/mit-license.php.
4
5#include <seeder/dns.h>
6
7#include <arpa/inet.h>
8#include <netinet/in.h>
9#include <strings.h>
10#include <sys/socket.h>
11#include <sys/types.h>
12#include <unistd.h>
13#include <util/time.h>
14
15#include <cctype>
16#include <cstdio>
17#include <cstdlib>
18#include <cstring>
19#include <ctime>
20
21#define BUFLEN 512
22
23#if defined IP_RECVDSTADDR
24#define DSTADDR_SOCKOPT IP_RECVDSTADDR
25#define DSTADDR_DATASIZE (CMSG_SPACE(sizeof(struct in6_addr)))
26#define dstaddr(x) (CMSG_DATA(x))
27#elif defined IPV6_PKTINFO
28#define DSTADDR_SOCKOPT IPV6_PKTINFO
29#define DSTADDR_DATASIZE (CMSG_SPACE(sizeof(struct in6_pktinfo)))
30#define dstaddr(x) (&(((struct in6_pktinfo *)(CMSG_DATA(x)))->ipi6_addr))
31#else
32#error "can't determine socket option"
33#endif
34
36 struct cmsghdr cmsg;
37 uint8_t data[DSTADDR_DATASIZE];
38};
39
40typedef enum {
43} dns_class;
44
45typedef enum {
46 TYPE_A = 1,
50 TYPE_MX = 15,
53 QTYPE_ANY = 255
55
56enum class DNSResponseCode : uint8_t {
57 OK = 0,
58 FORMAT_ERROR = 1,
60 NAME_ERROR = 3,
62 REFUSED = 5,
63};
64
65ParseNameStatus parse_name(const uint8_t **inpos, const uint8_t *inend,
66 const uint8_t *inbuf, char *buf, size_t bufsize) {
67 if (bufsize == 0) {
69 }
70 size_t bufused = 0;
71 int init = 1;
72 do {
73 if (*inpos == inend) {
75 }
76 // read length of next component
77 int octet = *((*inpos)++);
78 if (octet == 0) {
79 buf[bufused] = 0;
81 }
82 // add dot in output
83 if (!init) {
84 if (bufused == bufsize - 1) {
86 }
87 buf[bufused++] = '.';
88 } else {
89 init = 0;
90 }
91 // handle references
92 if ((octet & 0xC0) == 0xC0) {
93 if (*inpos == inend) {
95 }
96 int ref = ((octet - 0xC0) << 8) + *((*inpos)++);
97 if (ref < 0 || ref >= (*inpos) - inbuf - 2) {
99 }
100 const uint8_t *newbuf = inbuf + ref;
101 return parse_name(&newbuf, (*inpos) - 2, inbuf, buf + bufused,
102 bufsize - bufused);
103 }
104 if (octet > MAX_LABEL_LENGTH) {
106 }
107 // The maximum size of a query name is 255. The buffer must have
108 // room for the null-character at the end of the buffer after writing
109 // the label.
110 if (octet + bufused > MAX_QUERY_NAME_LENGTH) {
112 }
113 // copy label
114 while (octet) {
115 if (*inpos == inend) {
117 }
118 if (bufused == bufsize - 1) {
120 }
121 int c = *((*inpos)++);
122 if (c == '.') {
124 }
125 octet--;
126 buf[bufused++] = c;
127 }
128 } while (1);
129}
130
131int write_name(uint8_t **outpos, const uint8_t *outend, const char *name,
132 int offset) {
133 while (*name != 0) {
134 const char *dot = strchr(name, '.');
135 const char *fin = dot;
136 if (!dot) {
137 fin = name + strlen(name);
138 }
139 if (fin - name > MAX_LABEL_LENGTH) {
140 return -1;
141 }
142 if (fin == name) {
143 return -3;
144 }
145 if (outend - *outpos < fin - name + 2) {
146 return -2;
147 }
148 *((*outpos)++) = fin - name;
149 memcpy(*outpos, name, fin - name);
150 *outpos += fin - name;
151 if (!dot) {
152 break;
153 }
154 name = dot + 1;
155 }
156 if (offset < 0) {
157 // no reference
158 if (outend == *outpos) {
159 return -2;
160 }
161 *((*outpos)++) = 0;
162 } else {
163 if (outend - *outpos < 2) {
164 return -2;
165 }
166 *((*outpos)++) = (offset >> 8) | 0xC0;
167 *((*outpos)++) = offset & 0xFF;
168 }
169 return 0;
170}
171
172static int write_record(uint8_t **outpos, const uint8_t *outend,
173 const char *name, int offset, dns_type typ,
174 dns_class cls, int ttl) {
175 uint8_t *oldpos = *outpos;
176 int error = 0;
177 // name
178 int ret = write_name(outpos, outend, name, offset);
179 if (ret) {
180 error = ret;
181 goto error;
182 }
183 if (outend - *outpos < 8) {
184 error = -4;
185 goto error;
186 }
187 // type
188 *((*outpos)++) = typ >> 8;
189 *((*outpos)++) = typ & 0xFF;
190 // class
191 *((*outpos)++) = cls >> 8;
192 *((*outpos)++) = cls & 0xFF;
193 // ttl
194 *((*outpos)++) = (ttl >> 24) & 0xFF;
195 *((*outpos)++) = (ttl >> 16) & 0xFF;
196 *((*outpos)++) = (ttl >> 8) & 0xFF;
197 *((*outpos)++) = ttl & 0xFF;
198 return 0;
199error:
200 *outpos = oldpos;
201 return error;
202}
203
204static int write_record_a(uint8_t **outpos, const uint8_t *outend,
205 const char *name, int offset, dns_class cls, int ttl,
206 const addr_t *ip) {
207 if (ip->v != 4) {
208 return -6;
209 }
210 uint8_t *oldpos = *outpos;
211 int error = 0;
212 int ret = write_record(outpos, outend, name, offset, TYPE_A, cls, ttl);
213 if (ret) {
214 return ret;
215 }
216 if (outend - *outpos < 6) {
217 error = -5;
218 goto error;
219 }
220 // rdlength
221 *((*outpos)++) = 0;
222 *((*outpos)++) = 4;
223 // rdata
224 for (int i = 0; i < 4; i++) {
225 *((*outpos)++) = ip->data.v4[i];
226 }
227 return 0;
228error:
229 *outpos = oldpos;
230 return error;
231}
232
233static int write_record_aaaa(uint8_t **outpos, const uint8_t *outend,
234 const char *name, int offset, dns_class cls,
235 int ttl, const addr_t *ip) {
236 if (ip->v != 6) {
237 return -6;
238 }
239 uint8_t *oldpos = *outpos;
240 int error = 0;
241 int ret = write_record(outpos, outend, name, offset, TYPE_AAAA, cls, ttl);
242 if (ret) {
243 return ret;
244 }
245 if (outend - *outpos < 6) {
246 error = -5;
247 goto error;
248 }
249 // rdlength
250 *((*outpos)++) = 0;
251 *((*outpos)++) = 16;
252 // rdata
253 for (int i = 0; i < 16; i++) {
254 *((*outpos)++) = ip->data.v6[i];
255 }
256 return 0;
257error:
258 *outpos = oldpos;
259 return error;
260}
261
262static int write_record_ns(uint8_t **outpos, const uint8_t *outend,
263 const char *name, int offset, dns_class cls, int ttl,
264 const char *ns) {
265 uint8_t *oldpos = *outpos;
266 int ret = write_record(outpos, outend, name, offset, TYPE_NS, cls, ttl);
267 if (ret) {
268 return ret;
269 }
270
271 // Predeclare to avoid jumping over declaration.
272 uint8_t *curpos;
273
274 int error = 0;
275 if (outend - *outpos < 2) {
276 error = -5;
277 goto error;
278 }
279
280 (*outpos) += 2;
281 curpos = *outpos;
282 ret = write_name(outpos, outend, ns, -1);
283 if (ret) {
284 error = ret;
285 goto error;
286 }
287
288 curpos[-2] = (*outpos - curpos) >> 8;
289 curpos[-1] = (*outpos - curpos) & 0xFF;
290 return 0;
291
292error:
293 *outpos = oldpos;
294 return error;
295}
296
297static int write_record_soa(uint8_t **outpos, const uint8_t *outend,
298 const char *name, int offset, dns_class cls,
299 int ttl, const char *mname, const char *rname,
300 uint32_t serial, uint32_t refresh, uint32_t retry,
301 uint32_t expire, uint32_t minimum) {
302 uint8_t *oldpos = *outpos;
303 int ret = write_record(outpos, outend, name, offset, TYPE_SOA, cls, ttl);
304 if (ret) {
305 return ret;
306 }
307
308 // Predeclare variable to not jump over declarations.
309 uint8_t *curpos;
310
311 int error = 0;
312 if (outend - *outpos < 2) {
313 error = -5;
314 goto error;
315 }
316
317 (*outpos) += 2;
318 curpos = *outpos;
319 ret = write_name(outpos, outend, mname, -1);
320 if (ret) {
321 error = ret;
322 goto error;
323 }
324
325 ret = write_name(outpos, outend, rname, -1);
326 if (ret) {
327 error = ret;
328 goto error;
329 }
330
331 if (outend - *outpos < 20) {
332 error = -5;
333 goto error;
334 }
335
336 *((*outpos)++) = (serial >> 24) & 0xFF;
337 *((*outpos)++) = (serial >> 16) & 0xFF;
338 *((*outpos)++) = (serial >> 8) & 0xFF;
339 *((*outpos)++) = serial & 0xFF;
340 *((*outpos)++) = (refresh >> 24) & 0xFF;
341 *((*outpos)++) = (refresh >> 16) & 0xFF;
342 *((*outpos)++) = (refresh >> 8) & 0xFF;
343 *((*outpos)++) = refresh & 0xFF;
344 *((*outpos)++) = (retry >> 24) & 0xFF;
345 *((*outpos)++) = (retry >> 16) & 0xFF;
346 *((*outpos)++) = (retry >> 8) & 0xFF;
347 *((*outpos)++) = retry & 0xFF;
348 *((*outpos)++) = (expire >> 24) & 0xFF;
349 *((*outpos)++) = (expire >> 16) & 0xFF;
350 *((*outpos)++) = (expire >> 8) & 0xFF;
351 *((*outpos)++) = expire & 0xFF;
352 *((*outpos)++) = (minimum >> 24) & 0xFF;
353 *((*outpos)++) = (minimum >> 16) & 0xFF;
354 *((*outpos)++) = (minimum >> 8) & 0xFF;
355 *((*outpos)++) = minimum & 0xFF;
356 curpos[-2] = (*outpos - curpos) >> 8;
357 curpos[-1] = (*outpos - curpos) & 0xFF;
358 return 0;
359
360error:
361 *outpos = oldpos;
362 return error;
363}
364
365static ssize_t dnshandle(dns_opt_t *opt, const uint8_t *inbuf, size_t insize,
366 uint8_t *outbuf) {
368 if (insize < 12) {
369 // DNS header
370 return -1;
371 }
372
373 // Predeclare various variables to avoid jumping over declarations.
374 int have_ns = 0;
375 int max_auth_size = 0;
376 int nquestion = 0;
377
378 // copy id
379 outbuf[0] = inbuf[0];
380 outbuf[1] = inbuf[1];
381 // copy flags;
382 outbuf[2] = inbuf[2];
383 outbuf[3] = inbuf[3];
384 // clear response code
385 outbuf[3] &= ~15;
386 // check qr
387 if (inbuf[2] & 128) {
388 /* tfm::format(std::cout, "Got response?\n"); */
389 responseCode = DNSResponseCode::FORMAT_ERROR;
390 goto error;
391 }
392
393 // check opcode
394 if (((inbuf[2] & 120) >> 3) != 0) {
395 /* tfm::format(std::cout, "Opcode nonzero?\n"); */
397 goto error;
398 }
399
400 // unset TC
401 outbuf[2] &= ~2;
402 // unset RA
403 outbuf[3] &= ~128;
404 // check questions
405 nquestion = (inbuf[4] << 8) + inbuf[5];
406 if (nquestion == 0) {
407 /* tfm::format(std::cout, "No questions?\n"); */
408 responseCode = DNSResponseCode::OK;
409 goto error;
410 }
411
412 if (nquestion > 1) {
413 /* tfm::format(std::cout, "Multiple questions %i?\n", nquestion); */
415 goto error;
416 }
417
418 {
419 const uint8_t *inpos = inbuf + 12;
420 const uint8_t *inend = inbuf + insize;
422 int offset = inpos - inbuf;
423 ParseNameStatus ret = parse_name(&inpos, inend, inbuf, name,
425 if (ret == ParseNameStatus::InputError) {
426 responseCode = DNSResponseCode::FORMAT_ERROR;
427 goto error;
428 }
429
431 responseCode = DNSResponseCode::REFUSED;
432 goto error;
433 }
434
435 int namel = strlen(name), hostl = strlen(opt->host);
436 if (strcasecmp(name, opt->host) &&
437 (namel < hostl + 2 || name[namel - hostl - 1] != '.' ||
438 strcasecmp(name + namel - hostl, opt->host))) {
439 responseCode = DNSResponseCode::REFUSED;
440 goto error;
441 }
442
443 if (inend - inpos < 4) {
444 responseCode = DNSResponseCode::FORMAT_ERROR;
445 goto error;
446 }
447
448 // copy question to output
449 memcpy(outbuf + 12, inbuf + 12, inpos + 4 - (inbuf + 12));
450 // set counts
451 outbuf[4] = 0;
452 outbuf[5] = 1;
453 outbuf[6] = 0;
454 outbuf[7] = 0;
455 outbuf[8] = 0;
456 outbuf[9] = 0;
457 outbuf[10] = 0;
458 outbuf[11] = 0;
459 // set qr
460 outbuf[2] |= 128;
461
462 int typ = (inpos[0] << 8) + inpos[1];
463 int cls = (inpos[2] << 8) + inpos[3];
464 inpos += 4;
465
466 uint8_t *outpos = outbuf + (inpos - inbuf);
467 uint8_t *outend = outbuf + BUFLEN;
468
469 // tfm::format(std::cout, "DNS: Request host='%s' type=%i class=%i\n",
470 // name, typ, cls);
471
472 // calculate max size of authority section
473
474 if (!((typ == TYPE_NS || typ == QTYPE_ANY) &&
475 (cls == CLASS_IN || cls == QCLASS_ANY))) {
476 // authority section will be necessary, either NS or SOA
477 uint8_t *newpos = outpos;
478 write_record_ns(&newpos, outend, "", offset, CLASS_IN, 0, opt->ns);
479 max_auth_size = newpos - outpos;
480
481 newpos = outpos;
482 write_record_soa(&newpos, outend, "", offset, CLASS_IN, opt->nsttl,
483 opt->ns, opt->mbox, GetTime(), 604800, 86400,
484 2592000, 604800);
485 if (max_auth_size < newpos - outpos) {
486 max_auth_size = newpos - outpos;
487 }
488 // tfm::format(std::cout, "Authority section will claim %i bytes
489 // max\n", max_auth_size);
490 }
491
492 // Answer section
493
494 // NS records
495 if ((typ == TYPE_NS || typ == QTYPE_ANY) &&
496 (cls == CLASS_IN || cls == QCLASS_ANY)) {
497 int ret2 = write_record_ns(&outpos, outend - max_auth_size, "",
498 offset, CLASS_IN, opt->nsttl, opt->ns);
499 // tfm::format(std::cout, "wrote NS record: %i\n", ret2);
500 if (!ret2) {
501 outbuf[7]++;
502 have_ns++;
503 }
504 }
505
506 // SOA records
507 if ((typ == TYPE_SOA || typ == QTYPE_ANY) &&
508 (cls == CLASS_IN || cls == QCLASS_ANY) && opt->mbox) {
509 int ret2 =
510 write_record_soa(&outpos, outend - max_auth_size, "", offset,
511 CLASS_IN, opt->nsttl, opt->ns, opt->mbox,
512 GetTime(), 604800, 86400, 2592000, 604800);
513 // tfm::format(std::cout, "wrote SOA record: %i\n", ret2);
514 if (!ret2) {
515 outbuf[7]++;
516 }
517 }
518
519 // A/AAAA records
520 if ((typ == TYPE_A || typ == TYPE_AAAA || typ == QTYPE_ANY) &&
521 (cls == CLASS_IN || cls == QCLASS_ANY)) {
522 addr_t addr[32];
523 int naddr = opt->cb((void *)opt, name, addr, 32,
524 typ == TYPE_A || typ == QTYPE_ANY,
525 typ == TYPE_AAAA || typ == QTYPE_ANY);
526 int n = 0;
527 while (n < naddr) {
528 int mustbreak = 1;
529 if (addr[n].v == 4) {
530 mustbreak = write_record_a(&outpos, outend - max_auth_size,
531 "", offset, CLASS_IN,
532 opt->datattl, &addr[n]);
533 } else if (addr[n].v == 6) {
534 mustbreak = write_record_aaaa(
535 &outpos, outend - max_auth_size, "", offset, CLASS_IN,
536 opt->datattl, &addr[n]);
537 }
538
539 // tfm::format(std::cout, "wrote A record: %i\n",
540 // mustbreak);
541 if (mustbreak) {
542 break;
543 }
544
545 n++;
546 outbuf[7]++;
547 }
548 }
549
550 // Authority section
551 if (!have_ns && outbuf[7]) {
552 int ret2 = write_record_ns(&outpos, outend, "", offset, CLASS_IN,
553 opt->nsttl, opt->ns);
554 // tfm::format(std::cout, "wrote NS record: %i\n", ret2);
555 if (!ret2) {
556 outbuf[9]++;
557 }
558 } else if (!outbuf[7]) {
559 // Didn't include any answers, so reply with SOA as this is a
560 // negative response. If we replied with NS above we'd create a bad
561 // horizontal referral loop, as the NS response indicates where the
562 // resolver should try next.
563 int ret2 = write_record_soa(
564 &outpos, outend, "", offset, CLASS_IN, opt->nsttl, opt->ns,
565 opt->mbox, GetTime(), 604800, 86400, 2592000, 604800);
566 // tfm::format(std::cout, "wrote SOA record: %i\n", ret2);
567 if (!ret2) {
568 outbuf[9]++;
569 }
570 }
571
572 // set AA
573 outbuf[2] |= 4;
574
575 return outpos - outbuf;
576 }
577
578error:
579 // set response code
580 outbuf[3] |= uint8_t(responseCode) & 0xF;
581 // set counts
582 outbuf[4] = 0;
583 outbuf[5] = 0;
584 outbuf[6] = 0;
585 outbuf[7] = 0;
586 outbuf[8] = 0;
587 outbuf[9] = 0;
588 outbuf[10] = 0;
589 outbuf[11] = 0;
590 return 12;
591}
592
593static int listenSocket = -1;
594
596 struct sockaddr_in6 si_other;
597 int senderSocket = -1;
598 senderSocket = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
599 if (senderSocket == -1) {
600 return -3;
601 }
602
603 int replySocket;
604 if (listenSocket == -1) {
605 struct sockaddr_in6 si_me;
606 if ((listenSocket = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP)) == -1) {
607 listenSocket = -1;
608 return -1;
609 }
610 replySocket = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
611 if (replySocket == -1) {
612 close(listenSocket);
613 return -1;
614 }
615 int sockopt = 1;
616 setsockopt(listenSocket, IPPROTO_IPV6, DSTADDR_SOCKOPT, &sockopt,
617 sizeof sockopt);
618 memset((char *)&si_me, 0, sizeof(si_me));
619 si_me.sin6_family = AF_INET6;
620 si_me.sin6_port = htons(opt->port);
621 inet_pton(AF_INET6, opt->addr, &si_me.sin6_addr);
622 if (bind(listenSocket, (struct sockaddr *)&si_me, sizeof(si_me)) ==
623 -1) {
624 return -2;
625 }
626 }
627
628 uint8_t inbuf[BUFLEN], outbuf[BUFLEN];
629 struct iovec iov[1] = {
630 {
631 .iov_base = inbuf,
632 .iov_len = sizeof(inbuf),
633 },
634 };
635
636 union control_data cmsg;
637 msghdr msg;
638 msg.msg_name = &si_other;
639 msg.msg_namelen = sizeof(si_other);
640 msg.msg_iov = iov;
641 msg.msg_iovlen = 1;
642 msg.msg_control = &cmsg;
643 msg.msg_controllen = sizeof(cmsg);
644
645 for (; 1; ++(opt->nRequests)) {
646 ssize_t insize = recvmsg(listenSocket, &msg, 0);
647 // uint8_t *addr = (uint8_t*)&si_other.sin_addr.s_addr;
648 // tfm::format(std::cout, "DNS: Request %llu from %i.%i.%i.%i:%i of
649 // %i bytes\n", (unsigned long long)(opt->nRequests), addr[0],
650 // addr[1], addr[2], addr[3], ntohs(si_other.sin_port), (int)insize);
651 if (insize <= 0) {
652 continue;
653 }
654
655 ssize_t ret = dnshandle(opt, inbuf, insize, outbuf);
656 if (ret <= 0) {
657 continue;
658 }
659
660 bool handled = false;
661 for (struct cmsghdr *hdr = CMSG_FIRSTHDR(&msg); hdr;
662 hdr = CMSG_NXTHDR(&msg, hdr)) {
663 if (hdr->cmsg_level == IPPROTO_IP &&
664 hdr->cmsg_type == DSTADDR_SOCKOPT) {
665 msg.msg_iov[0].iov_base = outbuf;
666 msg.msg_iov[0].iov_len = ret;
667 sendmsg(listenSocket, &msg, 0);
668 msg.msg_iov[0].iov_base = inbuf;
669 msg.msg_iov[0].iov_len = sizeof(inbuf);
670 handled = true;
671 }
672 }
673 if (!handled) {
674 sendto(listenSocket, outbuf, ret, 0, (struct sockaddr *)&si_other,
675 sizeof(si_other));
676 }
677 }
678 return 0;
679}
static int write_record_ns(uint8_t **outpos, const uint8_t *outend, const char *name, int offset, dns_class cls, int ttl, const char *ns)
Definition: dns.cpp:262
static ssize_t dnshandle(dns_opt_t *opt, const uint8_t *inbuf, size_t insize, uint8_t *outbuf)
Definition: dns.cpp:365
ParseNameStatus parse_name(const uint8_t **inpos, const uint8_t *inend, const uint8_t *inbuf, char *buf, size_t bufsize)
Definition: dns.cpp:65
dns_type
Definition: dns.cpp:45
@ TYPE_A
Definition: dns.cpp:46
@ TYPE_SOA
Definition: dns.cpp:49
@ TYPE_MX
Definition: dns.cpp:50
@ TYPE_AAAA
Definition: dns.cpp:51
@ QTYPE_ANY
Definition: dns.cpp:53
@ TYPE_SRV
Definition: dns.cpp:52
@ TYPE_NS
Definition: dns.cpp:47
@ TYPE_CNAME
Definition: dns.cpp:48
int write_name(uint8_t **outpos, const uint8_t *outend, const char *name, int offset)
Definition: dns.cpp:131
dns_class
Definition: dns.cpp:40
@ CLASS_IN
Definition: dns.cpp:41
@ QCLASS_ANY
Definition: dns.cpp:42
static int write_record_aaaa(uint8_t **outpos, const uint8_t *outend, const char *name, int offset, dns_class cls, int ttl, const addr_t *ip)
Definition: dns.cpp:233
int dnsserver(dns_opt_t *opt)
Definition: dns.cpp:595
static int write_record_soa(uint8_t **outpos, const uint8_t *outend, const char *name, int offset, dns_class cls, int ttl, const char *mname, const char *rname, uint32_t serial, uint32_t refresh, uint32_t retry, uint32_t expire, uint32_t minimum)
Definition: dns.cpp:297
DNSResponseCode
Definition: dns.cpp:56
static int listenSocket
Definition: dns.cpp:593
#define BUFLEN
Definition: dns.cpp:21
static int write_record(uint8_t **outpos, const uint8_t *outend, const char *name, int offset, dns_type typ, dns_class cls, int ttl)
Definition: dns.cpp:172
static int write_record_a(uint8_t **outpos, const uint8_t *outend, const char *name, int offset, dns_class cls, int ttl, const addr_t *ip)
Definition: dns.cpp:204
ParseNameStatus
Definition: dns.h:38
constexpr int MAX_LABEL_LENGTH
Definition: dns.h:11
constexpr int MAX_QUERY_NAME_LENGTH
Definition: dns.h:12
constexpr int MAX_QUERY_NAME_BUFFER_LENGTH
Definition: dns.h:14
Definition: common.cpp:21
const char * name
Definition: rest.cpp:47
Definition: dns.h:16
uint8_t v6[16]
Definition: dns.h:20
union addr_t::@17 data
uint8_t v4[4]
Definition: dns.h:19
int v
Definition: dns.h:17
Definition: dns.h:24
int nsttl
Definition: dns.h:27
const char * ns
Definition: dns.h:30
uint32_t(* cb)(void *opt, char *requested_hostname, addr_t *addr, uint32_t max, uint32_t ipv4, uint32_t ipv6)
Definition: dns.h:32
const char * addr
Definition: dns.h:29
uint64_t nRequests
Definition: dns.h:35
const char * host
Definition: dns.h:28
int port
Definition: dns.h:25
const char * mbox
Definition: dns.h:31
int64_t GetTime()
DEPRECATED Use either ClockType::now() or Now<TimePointType>() if a cast is needed.
Definition: time.cpp:105
uint8_t data[DSTADDR_DATASIZE]
Definition: dns.cpp:37
struct cmsghdr cmsg
Definition: dns.cpp:36