10#include <sys/socket.h>
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))
33#error "can't determine socket option"
38 uint8_t
data[DSTADDR_DATASIZE];
67 const uint8_t *inbuf,
char *buf,
size_t bufsize) {
74 if (*inpos == inend) {
78 int octet = *((*inpos)++);
85 if (bufused == bufsize - 1) {
93 if ((octet & 0xC0) == 0xC0) {
94 if (*inpos == inend) {
97 int ref = ((octet - 0xC0) << 8) + *((*inpos)++);
98 if (ref < 0 || ref >= (*inpos) - inbuf - 2) {
101 const uint8_t *newbuf = inbuf + ref;
102 return parse_name(&newbuf, (*inpos) - 2, inbuf, buf + bufused,
116 if (*inpos == inend) {
119 if (bufused == bufsize - 1) {
122 int c = *((*inpos)++);
135 const char *dot = strchr(
name,
'.');
136 const char *fin = dot;
146 if (outend - *outpos < fin -
name + 2) {
149 *((*outpos)++) = fin -
name;
151 *outpos += fin -
name;
159 if (outend == *outpos) {
164 if (outend - *outpos < 2) {
167 *((*outpos)++) = (offset >> 8) | 0xC0;
168 *((*outpos)++) = offset & 0xFF;
176 uint8_t *oldpos = *outpos;
184 if (outend - *outpos < 8) {
189 *((*outpos)++) = typ >> 8;
190 *((*outpos)++) = typ & 0xFF;
192 *((*outpos)++) = cls >> 8;
193 *((*outpos)++) = cls & 0xFF;
195 *((*outpos)++) = (ttl >> 24) & 0xFF;
196 *((*outpos)++) = (ttl >> 16) & 0xFF;
197 *((*outpos)++) = (ttl >> 8) & 0xFF;
198 *((*outpos)++) = ttl & 0xFF;
211 uint8_t *oldpos = *outpos;
217 if (outend - *outpos < 6) {
225 for (
int i = 0; i < 4; i++) {
226 *((*outpos)++) = ip->
data.
v4[i];
236 int ttl,
const addr_t *ip) {
240 uint8_t *oldpos = *outpos;
246 if (outend - *outpos < 6) {
254 for (
int i = 0; i < 16; i++) {
255 *((*outpos)++) = ip->
data.
v6[i];
266 uint8_t *oldpos = *outpos;
276 if (outend - *outpos < 2) {
289 curpos[-2] = (*outpos - curpos) >> 8;
290 curpos[-1] = (*outpos - curpos) & 0xFF;
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;
313 if (outend - *outpos < 2) {
332 if (outend - *outpos < 20) {
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;
376 int max_auth_size = 0;
380 outbuf[0] = inbuf[0];
381 outbuf[1] = inbuf[1];
383 outbuf[2] = inbuf[2];
384 outbuf[3] = inbuf[3];
388 if (inbuf[2] & 128) {
395 if (((inbuf[2] & 120) >> 3) != 0) {
406 nquestion = (inbuf[4] << 8) + inbuf[5];
407 if (nquestion == 0) {
420 const uint8_t *inpos = inbuf + 12;
421 const uint8_t *inend = inbuf + insize;
423 int offset = inpos - inbuf;
436 int namel = strlen(
name), hostl = strlen(opt->
host);
438 (namel < hostl + 2 ||
name[namel - hostl - 1] !=
'.' ||
439 strcasecmp(
name + namel - hostl, opt->
host))) {
444 if (inend - inpos < 4) {
450 memcpy(outbuf + 12, inbuf + 12, inpos + 4 - (inbuf + 12));
463 int typ = (inpos[0] << 8) + inpos[1];
464 int cls = (inpos[2] << 8) + inpos[3];
467 uint8_t *outpos = outbuf + (inpos - inbuf);
468 uint8_t *outend = outbuf +
BUFLEN;
478 uint8_t *newpos = outpos;
480 max_auth_size = newpos - outpos;
486 if (max_auth_size < newpos - outpos) {
487 max_auth_size = newpos - outpos;
513 GetTime(), 604800, 86400, 2592000, 604800);
524 int naddr = opt->
cb((
void *)opt,
name, addr, 32,
530 if (addr[n].v == 4) {
533 opt->datattl, &addr[n]);
534 }
else if (addr[n].v == 6) {
536 &outpos, outend - max_auth_size,
"", offset,
CLASS_IN,
537 opt->datattl, &addr[n]);
552 if (!have_ns && outbuf[7]) {
559 }
else if (!outbuf[7]) {
566 opt->
mbox,
GetTime(), 604800, 86400, 2592000, 604800);
576 return outpos - outbuf;
581 outbuf[3] |= uint8_t(responseCode) & 0xF;
597 struct sockaddr_in6 si_other;
598 int senderSocket = -1;
599 senderSocket = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
600 if (senderSocket == -1) {
606 struct sockaddr_in6 si_me;
607 if ((
listenSocket = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP)) == -1) {
611 replySocket = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
612 if (replySocket == -1) {
617 setsockopt(
listenSocket, IPPROTO_IPV6, DSTADDR_SOCKOPT, &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)) ==
630 struct iovec iov[1] = {
633 .iov_len =
sizeof(inbuf),
639 msg.msg_name = &si_other;
640 msg.msg_namelen =
sizeof(si_other);
643 msg.msg_control = &
cmsg;
644 msg.msg_controllen =
sizeof(
cmsg);
656 ssize_t ret =
dnshandle(opt, inbuf, insize, outbuf);
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;
669 msg.msg_iov[0].iov_base = inbuf;
670 msg.msg_iov[0].iov_len =
sizeof(inbuf);
675 sendto(
listenSocket, outbuf, ret, 0, (
struct sockaddr *)&si_other,
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)
static ssize_t dnshandle(dns_opt_t *opt, const uint8_t *inbuf, size_t insize, uint8_t *outbuf)
ParseNameStatus parse_name(const uint8_t **inpos, const uint8_t *inend, const uint8_t *inbuf, char *buf, size_t bufsize)
int write_name(uint8_t **outpos, const uint8_t *outend, const char *name, int offset)
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)
int dnsserver(dns_opt_t *opt)
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)
static int write_record(uint8_t **outpos, const uint8_t *outend, const char *name, int offset, dns_type typ, dns_class cls, int ttl)
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)
constexpr int MAX_LABEL_LENGTH
constexpr int MAX_QUERY_NAME_LENGTH
constexpr int MAX_QUERY_NAME_BUFFER_LENGTH
bool error(const char *fmt, const Args &...args)
uint32_t(* cb)(void *opt, char *requested_hostname, addr_t *addr, uint32_t max, uint32_t ipv4, uint32_t ipv6)
int64_t GetTime()
DEPRECATED Use either ClockType::now() or Now<TimePointType>() if a cast is needed.
uint8_t data[DSTADDR_DATASIZE]