Bitcoin ABC 0.26.3
P2P Digital Currency
Loading...
Searching...
No Matches
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
40
41typedef enum {
44} dns_class;
45
46typedef enum {
47 TYPE_A = 1,
51 TYPE_MX = 15,
54 QTYPE_ANY = 255
56
58 OK = 0,
59 FORMAT_ERROR = 1,
61 NAME_ERROR = 3,
63 REFUSED = 5,
64};
65
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;
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.
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
132int 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
174 const char *name, int offset, dns_type typ,
175 dns_class cls, int ttl) {
177 int error = 0;
178 // name
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;
200error:
201 *outpos = oldpos;
202 return error;
203}
204
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 }
212 int error = 0;
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;
229error:
230 *outpos = oldpos;
231 return error;
232}
233
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 }
241 int error = 0;
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;
258error:
259 *outpos = oldpos;
260 return error;
261}
262
264 const char *name, int offset, dns_class cls, int ttl,
265 const char *ns) {
268 if (ret) {
269 return ret;
270 }
271
272 // Predeclare to avoid jumping over declaration.
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
293error:
294 *outpos = oldpos;
295 return error;
296}
297
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,
305 if (ret) {
306 return ret;
307 }
308
309 // Predeclare variable to not jump over declarations.
311
312 int error = 0;
313 if (outend - *outpos < 2) {
314 error = -5;
315 goto error;
316 }
317
318 (*outpos) += 2;
319 curpos = *outpos;
321 if (ret) {
322 error = ret;
323 goto error;
324 }
325
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
361error:
362 *outpos = oldpos;
363 return error;
364}
365
367 uint8_t *outbuf) {
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"); */
391 goto error;
392 }
393
394 // check opcode
395 if (((inbuf[2] & 120) >> 3) != 0) {
396 /* tfm::format(std::cout, "Opcode nonzero?\n"); */
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"); */
410 goto error;
411 }
412
413 if (nquestion > 1) {
414 /* tfm::format(std::cout, "Multiple questions %i?\n", nquestion); */
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;
428 goto error;
429 }
430
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))) {
441 goto error;
442 }
443
444 if (inend - inpos < 4) {
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
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
481
482 newpos = outpos;
484 opt->ns, opt->mbox, GetTime(), 604800, 86400,
485 2592000, 604800);
486 if (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)) {
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 =
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) {
532 "", offset, CLASS_IN,
533 opt->datattl, &addr[n]);
534 } else if (addr[n].v == 6) {
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]) {
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.
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
579error:
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
594static int listenSocket = -1;
595
597 struct sockaddr_in6 si_other;
598 int senderSocket = -1;
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 }
612 if (replySocket == -1) {
614 return -1;
615 }
616 int sockopt = 1;
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 inet_pton(AF_INET6, opt->addr, &si_me.sin6_addr);
623 if (bind(listenSocket, (struct sockaddr *)&si_me, sizeof(si_me)) ==
624 -1) {
625 return -2;
626 }
627 }
628
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)) {
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
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) {
676 sizeof(si_other));
677 }
678 }
679 return 0;
680}
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
static ssize_t dnshandle(dns_opt_t *opt, const uint8_t *inbuf, size_t insize, uint8_t *outbuf)
Definition dns.cpp:366
ParseNameStatus parse_name(const uint8_t **inpos, const uint8_t *inend, const uint8_t *inbuf, char *buf, size_t bufsize)
Definition dns.cpp:66
dns_type
Definition dns.cpp:46
@ TYPE_A
Definition dns.cpp:47
@ TYPE_SOA
Definition dns.cpp:50
@ TYPE_MX
Definition dns.cpp:51
@ TYPE_AAAA
Definition dns.cpp:52
@ QTYPE_ANY
Definition dns.cpp:54
@ TYPE_SRV
Definition dns.cpp:53
@ TYPE_NS
Definition dns.cpp:48
@ TYPE_CNAME
Definition dns.cpp:49
int write_name(uint8_t **outpos, const uint8_t *outend, const char *name, int offset)
Definition dns.cpp:132
dns_class
Definition dns.cpp:41
@ CLASS_IN
Definition dns.cpp:42
@ QCLASS_ANY
Definition dns.cpp:43
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
int dnsserver(dns_opt_t *opt)
Definition dns.cpp:596
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
DNSResponseCode
Definition dns.cpp:57
static int listenSocket
Definition dns.cpp:594
#define BUFLEN
Definition dns.cpp:22
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
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
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
bool error(const char *fmt, const Args &...args)
Definition logging.h:226
T GetRand(T nMax=std::numeric_limits< T >::max()) noexcept
Generate a uniform random integer of type T in the range [0..nMax) nMax defaults to std::numeric_limi...
Definition random.h:85
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
int64_t GetTime()
DEPRECATED Use either ClockType::now() or Now<TimePointType>() if a cast is needed.
Definition time.cpp:109
uint8_t data[DSTADDR_DATASIZE]
Definition dns.cpp:38
struct cmsghdr cmsg
Definition dns.cpp:37