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