2012-06-03 19:10:46 +02:00
|
|
|
#include <stdbool.h>
|
2011-12-13 16:02:51 +01:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
2013-07-15 12:20:36 +02:00
|
|
|
#include <strings.h>
|
2011-12-13 16:02:51 +01:00
|
|
|
#include <stdlib.h>
|
|
|
|
#include <sys/socket.h>
|
|
|
|
#include <netinet/in.h>
|
|
|
|
#include <stdint.h>
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <arpa/inet.h>
|
2011-12-16 16:56:36 +01:00
|
|
|
#include <time.h>
|
|
|
|
#include <ctype.h>
|
2012-06-03 19:10:46 +02:00
|
|
|
#include <unistd.h>
|
2011-12-13 16:02:51 +01:00
|
|
|
|
2011-12-20 14:29:21 +01:00
|
|
|
#include "dns.h"
|
2011-12-16 16:56:36 +01:00
|
|
|
|
2011-12-20 14:29:21 +01:00
|
|
|
#define BUFLEN 512
|
2011-12-20 05:20:50 +01:00
|
|
|
|
2012-06-03 19:10:46 +02:00
|
|
|
#if defined IP_RECVDSTADDR
|
|
|
|
# define DSTADDR_SOCKOPT IP_RECVDSTADDR
|
2014-07-21 13:26:21 +02:00
|
|
|
# define DSTADDR_DATASIZE (CMSG_SPACE(sizeof(struct in6_addr)))
|
2012-06-03 19:10:46 +02:00
|
|
|
# define dstaddr(x) (CMSG_DATA(x))
|
2014-07-21 13:26:21 +02:00
|
|
|
#elif defined IPV6_PKTINFO
|
|
|
|
struct in6_pktinfo
|
|
|
|
{
|
|
|
|
struct in6_addr ipi6_addr; /* src/dst IPv6 address */
|
|
|
|
unsigned int ipi6_ifindex; /* send/recv interface index */
|
|
|
|
};
|
2012-06-03 19:10:46 +02:00
|
|
|
|
2014-07-21 13:26:21 +02:00
|
|
|
# define DSTADDR_SOCKOPT IPV6_PKTINFO
|
|
|
|
# define DSTADDR_DATASIZE (CMSG_SPACE(sizeof(struct in6_pktinfo)))
|
|
|
|
# define dstaddr(x) (&(((struct in6_pktinfo *)(CMSG_DATA(x)))->ipi6_addr))
|
2012-06-03 19:10:46 +02:00
|
|
|
#else
|
|
|
|
# error "can't determine socket option"
|
|
|
|
#endif
|
|
|
|
|
|
|
|
union control_data {
|
|
|
|
struct cmsghdr cmsg;
|
|
|
|
unsigned char data[DSTADDR_DATASIZE];
|
|
|
|
};
|
|
|
|
|
2011-12-13 16:02:51 +01:00
|
|
|
typedef enum {
|
|
|
|
CLASS_IN = 1,
|
|
|
|
QCLASS_ANY = 255
|
|
|
|
} dns_class;
|
|
|
|
|
|
|
|
typedef enum {
|
|
|
|
TYPE_A = 1,
|
|
|
|
TYPE_NS = 2,
|
|
|
|
TYPE_CNAME = 5,
|
|
|
|
TYPE_SOA = 6,
|
|
|
|
TYPE_MX = 15,
|
|
|
|
TYPE_AAAA = 28,
|
|
|
|
TYPE_SRV = 33,
|
|
|
|
QTYPE_ANY = 255
|
|
|
|
} dns_type;
|
|
|
|
|
|
|
|
|
|
|
|
// 0: ok
|
2011-12-16 16:56:36 +01:00
|
|
|
// -1: premature end of input, forward reference, component > 63 char, invalid character
|
2011-12-13 19:35:10 +01:00
|
|
|
// -2: insufficient space in output
|
2011-12-16 16:56:36 +01:00
|
|
|
int static parse_name(const unsigned char **inpos, const unsigned char *inend, const unsigned char *inbuf, char *buf, size_t bufsize) {
|
2011-12-13 16:02:51 +01:00
|
|
|
size_t bufused = 0;
|
2011-12-13 19:35:10 +01:00
|
|
|
int init = 1;
|
2011-12-13 16:02:51 +01:00
|
|
|
do {
|
|
|
|
if (*inpos == inend)
|
|
|
|
return -1;
|
2011-12-13 19:35:10 +01:00
|
|
|
// read length of next component
|
|
|
|
int octet = *((*inpos)++);
|
2011-12-13 16:02:51 +01:00
|
|
|
if (octet == 0) {
|
|
|
|
buf[bufused] = 0;
|
|
|
|
return 0;
|
|
|
|
}
|
2011-12-13 19:35:10 +01:00
|
|
|
// add dot in output
|
|
|
|
if (!init) {
|
|
|
|
if (bufused == bufsize-1)
|
|
|
|
return -2;
|
|
|
|
buf[bufused++] = '.';
|
|
|
|
} else
|
|
|
|
init = 0;
|
|
|
|
// handle references
|
|
|
|
if ((octet & 0xC0) == 0xC0) {
|
|
|
|
if (*inpos == inend)
|
|
|
|
return -1;
|
|
|
|
int ref = ((octet - 0xC0) << 8) + *((*inpos)++);
|
2015-03-07 13:03:08 +01:00
|
|
|
if (ref < 0 || ref >= (*inpos)-inbuf-2) return -1;
|
2011-12-13 19:35:10 +01:00
|
|
|
const unsigned char *newbuf = inbuf + ref;
|
2015-03-07 13:03:08 +01:00
|
|
|
return parse_name(&newbuf, (*inpos) - 2, inbuf, buf+bufused, bufsize-bufused);
|
2011-12-13 19:35:10 +01:00
|
|
|
}
|
|
|
|
if (octet > 63) return -1;
|
2011-12-16 16:56:36 +01:00
|
|
|
// copy label
|
2011-12-13 16:02:51 +01:00
|
|
|
while (octet) {
|
|
|
|
if (*inpos == inend)
|
|
|
|
return -1;
|
|
|
|
if (bufused == bufsize-1)
|
|
|
|
return -2;
|
2011-12-16 16:56:36 +01:00
|
|
|
int c = *((*inpos)++);
|
|
|
|
if (c == '.')
|
|
|
|
return -1;
|
2011-12-13 16:02:51 +01:00
|
|
|
octet--;
|
2011-12-16 16:56:36 +01:00
|
|
|
buf[bufused++] = c;
|
2011-12-13 16:02:51 +01:00
|
|
|
}
|
|
|
|
} while(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
// 0: k
|
|
|
|
// -1: component > 63 characters
|
|
|
|
// -2: insufficent space in output
|
|
|
|
// -3: two subsequent dots
|
2011-12-20 14:29:21 +01:00
|
|
|
int static write_name(unsigned char** outpos, const unsigned char *outend, const char *name, int offset) {
|
2011-12-13 16:02:51 +01:00
|
|
|
while (*name != 0) {
|
|
|
|
char *dot = strchr(name, '.');
|
2011-12-20 14:29:21 +01:00
|
|
|
const char *fin = dot;
|
2011-12-13 16:02:51 +01:00
|
|
|
if (!dot) fin = name + strlen(name);
|
|
|
|
if (fin - name > 63) return -1;
|
|
|
|
if (fin == name) return -3;
|
|
|
|
if (outend - *outpos < fin - name + 2) return -2;
|
2011-12-13 19:35:10 +01:00
|
|
|
*((*outpos)++) = fin - name;
|
2011-12-13 16:02:51 +01:00
|
|
|
memcpy(*outpos, name, fin - name);
|
2011-12-13 19:35:10 +01:00
|
|
|
*outpos += fin - name;
|
2011-12-13 16:02:51 +01:00
|
|
|
if (!dot) break;
|
|
|
|
name = dot + 1;
|
|
|
|
}
|
2011-12-13 19:35:10 +01:00
|
|
|
if (offset < 0) {
|
|
|
|
// no reference
|
|
|
|
if (outend == *outpos) return -2;
|
|
|
|
*((*outpos)++) = 0;
|
|
|
|
} else {
|
|
|
|
if (outend - *outpos < 2) return -2;
|
|
|
|
*((*outpos)++) = (offset >> 8) | 0xC0;
|
|
|
|
*((*outpos)++) = offset & 0xFF;
|
|
|
|
}
|
2011-12-13 16:02:51 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2011-12-20 14:29:21 +01:00
|
|
|
int static write_record(unsigned char** outpos, const unsigned char *outend, const char *name, int offset, dns_type typ, dns_class cls, int ttl) {
|
2011-12-13 16:02:51 +01:00
|
|
|
unsigned char *oldpos = *outpos;
|
2011-12-13 19:35:10 +01:00
|
|
|
int error = 0;
|
2011-12-13 16:02:51 +01:00
|
|
|
// name
|
2011-12-13 19:35:10 +01:00
|
|
|
int ret = write_name(outpos, outend, name, offset);
|
|
|
|
if (ret) { error = ret; goto error; }
|
|
|
|
if (outend - *outpos < 8) { error = -4; goto error; }
|
2011-12-13 16:02:51 +01:00
|
|
|
// type
|
2011-12-13 19:35:10 +01:00
|
|
|
*((*outpos)++) = typ >> 8; *((*outpos)++) = typ & 0xFF;
|
2011-12-13 16:02:51 +01:00
|
|
|
// class
|
2011-12-13 19:35:10 +01:00
|
|
|
*((*outpos)++) = cls >> 8; *((*outpos)++) = cls & 0xFF;
|
2011-12-13 16:02:51 +01:00
|
|
|
// ttl
|
2011-12-13 19:35:10 +01:00
|
|
|
*((*outpos)++) = (ttl >> 24) & 0xFF; *((*outpos)++) = (ttl >> 16) & 0xFF; *((*outpos)++) = (ttl >> 8) & 0xFF; *((*outpos)++) = ttl & 0xFF;
|
|
|
|
return 0;
|
|
|
|
error:
|
|
|
|
*outpos = oldpos;
|
|
|
|
return error;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-05-25 15:41:27 +02:00
|
|
|
int static write_record_a(unsigned char** outpos, const unsigned char *outend, const char *name, int offset, dns_class cls, int ttl, const addr_t *ip) {
|
|
|
|
if (ip->v != 4)
|
|
|
|
return -6;
|
2011-12-13 19:35:10 +01:00
|
|
|
unsigned char *oldpos = *outpos;
|
|
|
|
int error = 0;
|
|
|
|
int ret = write_record(outpos, outend, name, offset, TYPE_A, cls, ttl);
|
|
|
|
if (ret) return ret;
|
|
|
|
if (outend - *outpos < 6) { error = -5; goto error; }
|
2011-12-13 16:02:51 +01:00
|
|
|
// rdlength
|
2011-12-13 19:35:10 +01:00
|
|
|
*((*outpos)++) = 0; *((*outpos)++) = 4;
|
2011-12-13 16:02:51 +01:00
|
|
|
// rdata
|
2011-12-16 16:56:36 +01:00
|
|
|
for (int i=0; i<4; i++)
|
2012-05-25 15:41:27 +02:00
|
|
|
*((*outpos)++) = ip->data.v4[i];
|
2011-12-13 19:35:10 +01:00
|
|
|
return 0;
|
|
|
|
error:
|
|
|
|
*outpos = oldpos;
|
|
|
|
return error;
|
|
|
|
}
|
|
|
|
|
2012-05-25 15:41:27 +02:00
|
|
|
int static write_record_aaaa(unsigned char** outpos, const unsigned char *outend, const char *name, int offset, dns_class cls, int ttl, const addr_t *ip) {
|
|
|
|
if (ip->v != 6)
|
|
|
|
return -6;
|
2011-12-16 16:56:36 +01:00
|
|
|
unsigned char *oldpos = *outpos;
|
|
|
|
int error = 0;
|
|
|
|
int ret = write_record(outpos, outend, name, offset, TYPE_AAAA, cls, ttl);
|
|
|
|
if (ret) return ret;
|
|
|
|
if (outend - *outpos < 6) { error = -5; goto error; }
|
|
|
|
// rdlength
|
|
|
|
*((*outpos)++) = 0; *((*outpos)++) = 16;
|
|
|
|
// rdata
|
|
|
|
for (int i=0; i<16; i++)
|
2012-05-25 15:41:27 +02:00
|
|
|
*((*outpos)++) = ip->data.v6[i];
|
2011-12-16 16:56:36 +01:00
|
|
|
return 0;
|
|
|
|
error:
|
|
|
|
*outpos = oldpos;
|
|
|
|
return error;
|
|
|
|
}
|
|
|
|
|
2011-12-20 14:29:21 +01:00
|
|
|
int static write_record_ns(unsigned char** outpos, const unsigned char *outend, char *name, int offset, dns_class cls, int ttl, const char *ns) {
|
2011-12-13 19:35:10 +01:00
|
|
|
unsigned char *oldpos = *outpos;
|
|
|
|
int ret = write_record(outpos, outend, name, offset, TYPE_NS, cls, ttl);
|
|
|
|
if (ret) return ret;
|
|
|
|
int error = 0;
|
|
|
|
if (outend - *outpos < 2) { error = -5; goto error; }
|
|
|
|
(*outpos) += 2;
|
|
|
|
unsigned char *curpos = *outpos;
|
|
|
|
ret = write_name(outpos, outend, ns, -1);
|
|
|
|
if (ret) { error = ret; goto error; }
|
|
|
|
curpos[-2] = (*outpos - curpos) >> 8;
|
|
|
|
curpos[-1] = (*outpos - curpos) & 0xFF;
|
2011-12-13 16:02:51 +01:00
|
|
|
return 0;
|
|
|
|
error:
|
|
|
|
*outpos = oldpos;
|
2011-12-13 19:35:10 +01:00
|
|
|
return error;
|
2011-12-13 16:02:51 +01:00
|
|
|
}
|
|
|
|
|
2011-12-20 14:29:21 +01:00
|
|
|
int static write_record_soa(unsigned char** outpos, const unsigned char *outend, char *name, int offset, dns_class cls, int ttl, const char* mname, const char *rname,
|
2011-12-16 16:56:36 +01:00
|
|
|
uint32_t serial, uint32_t refresh, uint32_t retry, uint32_t expire, uint32_t minimum) {
|
|
|
|
unsigned char *oldpos = *outpos;
|
|
|
|
int ret = write_record(outpos, outend, name, offset, TYPE_SOA, cls, ttl);
|
|
|
|
if (ret) return ret;
|
|
|
|
int error = 0;
|
|
|
|
if (outend - *outpos < 2) { error = -5; goto error; }
|
|
|
|
(*outpos) += 2;
|
|
|
|
unsigned char *curpos = *outpos;
|
|
|
|
ret = write_name(outpos, outend, mname, -1);
|
|
|
|
if (ret) { error = ret; goto error; }
|
|
|
|
ret = write_name(outpos, outend, rname, -1);
|
|
|
|
if (ret) { error = ret; goto error; }
|
|
|
|
if (outend - *outpos < 20) { error = -5; goto error; }
|
|
|
|
*((*outpos)++) = (serial >> 24) & 0xFF; *((*outpos)++) = (serial >> 16) & 0xFF; *((*outpos)++) = (serial >> 8) & 0xFF; *((*outpos)++) = serial & 0xFF;
|
|
|
|
*((*outpos)++) = (refresh >> 24) & 0xFF; *((*outpos)++) = (refresh >> 16) & 0xFF; *((*outpos)++) = (refresh >> 8) & 0xFF; *((*outpos)++) = refresh & 0xFF;
|
|
|
|
*((*outpos)++) = (retry >> 24) & 0xFF; *((*outpos)++) = (retry >> 16) & 0xFF; *((*outpos)++) = (retry >> 8) & 0xFF; *((*outpos)++) = retry & 0xFF;
|
|
|
|
*((*outpos)++) = (expire >> 24) & 0xFF; *((*outpos)++) = (expire >> 16) & 0xFF; *((*outpos)++) = (expire >> 8) & 0xFF; *((*outpos)++) = expire & 0xFF;
|
|
|
|
*((*outpos)++) = (minimum >> 24) & 0xFF; *((*outpos)++) = (minimum >> 16) & 0xFF; *((*outpos)++) = (minimum >> 8) & 0xFF; *((*outpos)++) = minimum & 0xFF;
|
|
|
|
curpos[-2] = (*outpos - curpos) >> 8;
|
|
|
|
curpos[-1] = (*outpos - curpos) & 0xFF;
|
|
|
|
return 0;
|
|
|
|
error:
|
|
|
|
*outpos = oldpos;
|
|
|
|
return error;
|
|
|
|
}
|
|
|
|
|
2011-12-20 14:29:21 +01:00
|
|
|
ssize_t static dnshandle(dns_opt_t *opt, const unsigned char *inbuf, size_t insize, unsigned char* outbuf) {
|
2011-12-13 16:02:51 +01:00
|
|
|
int error = 0;
|
|
|
|
if (insize < 12) // DNS header
|
|
|
|
return -1;
|
|
|
|
// copy id
|
|
|
|
outbuf[0] = inbuf[0];
|
|
|
|
outbuf[1] = inbuf[1];
|
|
|
|
// copy flags;
|
|
|
|
outbuf[2] = inbuf[2];
|
|
|
|
outbuf[3] = inbuf[3];
|
|
|
|
// clear error
|
2011-12-13 19:35:10 +01:00
|
|
|
outbuf[3] &= ~15;
|
2011-12-13 16:02:51 +01:00
|
|
|
// check qr
|
2011-12-16 16:56:36 +01:00
|
|
|
if (inbuf[2] & 128) { /* printf("Got response?\n"); */ error = 1; goto error; }
|
2011-12-13 16:02:51 +01:00
|
|
|
// check opcode
|
2011-12-16 16:56:36 +01:00
|
|
|
if (((inbuf[2] & 120) >> 3) != 0) { /* printf("Opcode nonzero?\n"); */ error = 4; goto error; }
|
2011-12-13 16:02:51 +01:00
|
|
|
// unset TC
|
2011-12-13 19:35:10 +01:00
|
|
|
outbuf[2] &= ~2;
|
2011-12-13 16:02:51 +01:00
|
|
|
// unset RA
|
2011-12-13 19:35:10 +01:00
|
|
|
outbuf[3] &= ~128;
|
2011-12-13 16:02:51 +01:00
|
|
|
// check questions
|
2011-12-13 19:35:10 +01:00
|
|
|
int nquestion = (inbuf[4] << 8) + inbuf[5];
|
2011-12-16 16:56:36 +01:00
|
|
|
if (nquestion == 0) { /* printf("No questions?\n"); */ error = 0; goto error; }
|
|
|
|
if (nquestion > 1) { /* printf("Multiple questions %i?\n", nquestion); */ error = 4; goto error; }
|
2011-12-13 16:02:51 +01:00
|
|
|
const unsigned char *inpos = inbuf + 12;
|
|
|
|
const unsigned char *inend = inbuf + insize;
|
|
|
|
char name[256];
|
2011-12-13 19:35:10 +01:00
|
|
|
int offset = inpos - inbuf;
|
|
|
|
int ret = parse_name(&inpos, inend, inbuf, name, 256);
|
2011-12-13 16:02:51 +01:00
|
|
|
if (ret == -1) { error = 1; goto error; }
|
|
|
|
if (ret == -2) { error = 5; goto error; }
|
2011-12-20 14:29:21 +01:00
|
|
|
int namel = strlen(name), hostl = strlen(opt->host);
|
2013-07-15 12:20:36 +02:00
|
|
|
if (strcasecmp(name, opt->host) && (namel<hostl+2 || name[namel-hostl-1]!='.' || strcasecmp(name+namel-hostl,opt->host))) { error = 5; goto error; }
|
2011-12-13 16:02:51 +01:00
|
|
|
if (inend - inpos < 4) { error = 1; goto error; }
|
|
|
|
// copy question to output
|
|
|
|
memcpy(outbuf+12, inbuf+12, inpos+4 - (inbuf+12));
|
|
|
|
// set counts
|
|
|
|
outbuf[4] = 0; outbuf[5] = 1;
|
|
|
|
outbuf[6] = 0; outbuf[7] = 0;
|
|
|
|
outbuf[8] = 0; outbuf[9] = 0;
|
|
|
|
outbuf[10] = 0; outbuf[11] = 0;
|
2011-12-13 19:35:10 +01:00
|
|
|
// set qr
|
|
|
|
outbuf[2] |= 128;
|
2011-12-13 16:02:51 +01:00
|
|
|
|
2011-12-13 19:35:10 +01:00
|
|
|
int typ = (inpos[0] << 8) + inpos[1];
|
|
|
|
int cls = (inpos[2] << 8) + inpos[3];
|
2011-12-13 16:02:51 +01:00
|
|
|
inpos += 4;
|
|
|
|
|
|
|
|
unsigned char *outpos = outbuf+(inpos-inbuf);
|
|
|
|
unsigned char *outend = outbuf + BUFLEN;
|
|
|
|
|
2015-07-02 15:58:14 +02:00
|
|
|
// printf("DNS: Request host='%s' type=%i class=%i\n", name, typ, cls);
|
2011-12-13 19:35:10 +01:00
|
|
|
|
2015-07-02 15:58:14 +02:00
|
|
|
// calculate max size of authority section
|
2011-12-13 19:35:10 +01:00
|
|
|
|
2015-07-02 15:58:14 +02:00
|
|
|
int max_auth_size = 0;
|
2011-12-13 19:35:10 +01:00
|
|
|
|
|
|
|
if (!((typ == TYPE_NS || typ == QTYPE_ANY) && (cls == CLASS_IN || cls == QCLASS_ANY))) {
|
2015-07-02 15:58:14 +02:00
|
|
|
// authority section will be necessary, either NS or SOA
|
|
|
|
unsigned char *newpos = outpos;
|
|
|
|
write_record_ns(&newpos, outend, "", offset, CLASS_IN, 0, opt->ns);
|
|
|
|
max_auth_size = newpos - outpos;
|
|
|
|
|
|
|
|
newpos = outpos;
|
|
|
|
write_record_soa(&newpos, outend, "", offset, CLASS_IN, opt->nsttl, opt->ns, opt->mbox, time(NULL), 604800, 86400, 2592000, 604800);
|
|
|
|
if (max_auth_size < newpos - outpos)
|
|
|
|
max_auth_size = newpos - outpos;
|
|
|
|
// printf("Authority section will claim %i bytes max\n", max_auth_size);
|
2011-12-13 19:35:10 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// Answer section
|
|
|
|
|
|
|
|
int have_ns = 0;
|
|
|
|
|
2011-12-16 16:56:36 +01:00
|
|
|
// NS records
|
2011-12-13 19:35:10 +01:00
|
|
|
if ((typ == TYPE_NS || typ == QTYPE_ANY) && (cls == CLASS_IN || cls == QCLASS_ANY)) {
|
2015-07-02 15:58:14 +02:00
|
|
|
int ret2 = write_record_ns(&outpos, outend - max_auth_size, "", offset, CLASS_IN, opt->nsttl, opt->ns);
|
2011-12-16 16:56:36 +01:00
|
|
|
// printf("wrote NS record: %i\n", ret2);
|
2011-12-13 19:35:10 +01:00
|
|
|
if (!ret2) { outbuf[7]++; have_ns++; }
|
|
|
|
}
|
2011-12-16 16:56:36 +01:00
|
|
|
|
|
|
|
// SOA records
|
2012-01-01 19:18:56 +01:00
|
|
|
if ((typ == TYPE_SOA || typ == QTYPE_ANY) && (cls == CLASS_IN || cls == QCLASS_ANY) && opt->mbox) {
|
2015-07-02 15:58:14 +02:00
|
|
|
int ret2 = write_record_soa(&outpos, outend - max_auth_size, "", offset, CLASS_IN, opt->nsttl, opt->ns, opt->mbox, time(NULL), 604800, 86400, 2592000, 604800);
|
2011-12-16 16:56:36 +01:00
|
|
|
// printf("wrote SOA record: %i\n", ret2);
|
|
|
|
if (!ret2) { outbuf[7]++; }
|
|
|
|
}
|
2011-12-13 19:35:10 +01:00
|
|
|
|
2012-05-25 15:41:27 +02:00
|
|
|
// A/AAAA records
|
|
|
|
if ((typ == TYPE_A || typ == TYPE_AAAA || typ == QTYPE_ANY) && (cls == CLASS_IN || cls == QCLASS_ANY)) {
|
|
|
|
addr_t addr[32];
|
2016-05-21 12:19:25 +02:00
|
|
|
int naddr = opt->cb((void*)opt, name, addr, 32, typ == TYPE_A || typ == QTYPE_ANY, typ == TYPE_AAAA || typ == QTYPE_ANY);
|
2011-12-20 05:20:50 +01:00
|
|
|
int n = 0;
|
|
|
|
while (n < naddr) {
|
2012-05-25 15:41:27 +02:00
|
|
|
int ret = 1;
|
2012-05-25 15:59:10 +02:00
|
|
|
if (addr[n].v == 4)
|
2015-07-02 15:58:14 +02:00
|
|
|
ret = write_record_a(&outpos, outend - max_auth_size, "", offset, CLASS_IN, opt->datattl, &addr[n]);
|
2012-05-25 15:59:10 +02:00
|
|
|
else if (addr[n].v == 6)
|
2015-07-02 15:58:14 +02:00
|
|
|
ret = write_record_aaaa(&outpos, outend - max_auth_size, "", offset, CLASS_IN, opt->datattl, &addr[n]);
|
2011-12-16 16:56:36 +01:00
|
|
|
// printf("wrote A record: %i\n", ret);
|
2011-12-13 19:35:10 +01:00
|
|
|
if (!ret) {
|
2011-12-20 05:20:50 +01:00
|
|
|
n++;
|
2011-12-13 19:35:10 +01:00
|
|
|
outbuf[7]++;
|
|
|
|
} else
|
|
|
|
break;
|
2011-12-20 05:20:50 +01:00
|
|
|
}
|
2011-12-13 19:35:10 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// Authority section
|
2015-07-02 15:58:14 +02:00
|
|
|
if (!have_ns && outbuf[7]) {
|
2011-12-20 14:29:21 +01:00
|
|
|
int ret2 = write_record_ns(&outpos, outend, "", offset, CLASS_IN, opt->nsttl, opt->ns);
|
2011-12-16 16:56:36 +01:00
|
|
|
// printf("wrote NS record: %i\n", ret2);
|
2011-12-13 19:35:10 +01:00
|
|
|
if (!ret2) {
|
|
|
|
outbuf[9]++;
|
|
|
|
}
|
2011-12-13 16:02:51 +01:00
|
|
|
}
|
2015-07-02 15:58:14 +02:00
|
|
|
else if (!outbuf[7]) {
|
|
|
|
// Didn't include any answers, so reply with SOA as this is a negative
|
|
|
|
// response. If we replied with NS above we'd create a bad horizontal
|
|
|
|
// referral loop, as the NS response indicates where the resolver should
|
|
|
|
// try next.
|
|
|
|
int ret2 = write_record_soa(&outpos, outend, "", offset, CLASS_IN, opt->nsttl, opt->ns, opt->mbox, time(NULL), 604800, 86400, 2592000, 604800);
|
|
|
|
// printf("wrote SOA record: %i\n", ret2);
|
|
|
|
if (!ret2) { outbuf[9]++; }
|
|
|
|
}
|
2011-12-13 16:02:51 +01:00
|
|
|
|
|
|
|
// set AA
|
2011-12-13 19:35:10 +01:00
|
|
|
outbuf[2] |= 4;
|
|
|
|
|
2011-12-13 16:02:51 +01:00
|
|
|
return outpos - outbuf;
|
|
|
|
error:
|
|
|
|
// set error
|
2011-12-13 19:35:10 +01:00
|
|
|
outbuf[3] |= error & 0xF;
|
2011-12-13 16:02:51 +01:00
|
|
|
// set counts
|
|
|
|
outbuf[4] = 0; outbuf[5] = 0;
|
|
|
|
outbuf[6] = 0; outbuf[7] = 0;
|
|
|
|
outbuf[8] = 0; outbuf[9] = 0;
|
|
|
|
outbuf[10] = 0; outbuf[11] = 0;
|
|
|
|
return 12;
|
|
|
|
}
|
|
|
|
|
2012-05-04 01:15:49 +02:00
|
|
|
static int listenSocket = -1;
|
|
|
|
|
2011-12-20 14:29:21 +01:00
|
|
|
int dnsserver(dns_opt_t *opt) {
|
2014-07-21 13:26:21 +02:00
|
|
|
struct sockaddr_in6 si_other;
|
2012-05-04 01:15:49 +02:00
|
|
|
int senderSocket = -1;
|
2014-07-21 13:26:21 +02:00
|
|
|
senderSocket = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
|
2012-05-04 01:15:49 +02:00
|
|
|
if (senderSocket == -1)
|
|
|
|
return -3;
|
|
|
|
|
2012-06-03 19:10:46 +02:00
|
|
|
int replySocket;
|
2012-05-04 01:15:49 +02:00
|
|
|
if (listenSocket == -1) {
|
2014-07-21 13:26:21 +02:00
|
|
|
struct sockaddr_in6 si_me;
|
|
|
|
if ((listenSocket=socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP))==-1) {
|
2012-05-04 01:15:49 +02:00
|
|
|
listenSocket = -1;
|
|
|
|
return -1;
|
|
|
|
}
|
2014-07-21 13:26:21 +02:00
|
|
|
replySocket = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
|
2012-06-03 19:10:46 +02:00
|
|
|
if (replySocket == -1)
|
|
|
|
{
|
|
|
|
close(listenSocket);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
int sockopt = 1;
|
2014-07-21 13:26:21 +02:00
|
|
|
setsockopt(listenSocket, IPPROTO_IPV6, DSTADDR_SOCKOPT, &sockopt, sizeof sockopt);
|
2012-05-04 01:15:49 +02:00
|
|
|
memset((char *) &si_me, 0, sizeof(si_me));
|
2014-07-21 13:26:21 +02:00
|
|
|
si_me.sin6_family = AF_INET6;
|
|
|
|
si_me.sin6_port = htons(opt->port);
|
|
|
|
si_me.sin6_addr = in6addr_any;
|
2012-05-04 01:15:49 +02:00
|
|
|
if (bind(listenSocket, (struct sockaddr*)&si_me, sizeof(si_me))==-1)
|
|
|
|
return -2;
|
|
|
|
}
|
2012-06-03 19:10:46 +02:00
|
|
|
|
2011-12-13 16:02:51 +01:00
|
|
|
unsigned char inbuf[BUFLEN], outbuf[BUFLEN];
|
2012-06-03 19:10:46 +02:00
|
|
|
struct iovec iov[1] = {
|
|
|
|
{
|
|
|
|
.iov_base = inbuf,
|
|
|
|
.iov_len = sizeof(inbuf),
|
|
|
|
},
|
|
|
|
};
|
|
|
|
union control_data cmsg;
|
|
|
|
struct msghdr msg = {
|
|
|
|
.msg_name = &si_other,
|
|
|
|
.msg_namelen = sizeof(si_other),
|
|
|
|
.msg_iov = iov,
|
|
|
|
.msg_iovlen = 1,
|
|
|
|
.msg_control = &cmsg,
|
|
|
|
.msg_controllen = sizeof(cmsg),
|
|
|
|
};
|
|
|
|
for (; 1; ++(opt->nRequests))
|
|
|
|
{
|
|
|
|
ssize_t insize = recvmsg(listenSocket, &msg, 0);
|
2014-07-21 13:26:21 +02:00
|
|
|
// unsigned char *addr = (unsigned char*)&si_other.sin_addr.s_addr;
|
2011-12-26 15:53:22 +01:00
|
|
|
// printf("DNS: Request %llu from %i.%i.%i.%i:%i of %i bytes\n", (unsigned long long)(opt->nRequests), addr[0], addr[1], addr[2], addr[3], ntohs(si_other.sin_port), (int)insize);
|
2012-06-03 19:10:46 +02:00
|
|
|
if (insize <= 0)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
ssize_t ret = dnshandle(opt, inbuf, insize, outbuf);
|
|
|
|
if (ret <= 0)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
bool handled = false;
|
|
|
|
for (struct cmsghdr*hdr = CMSG_FIRSTHDR(&msg); hdr; hdr = CMSG_NXTHDR(&msg, hdr))
|
|
|
|
{
|
|
|
|
if (hdr->cmsg_level == IPPROTO_IP && hdr->cmsg_type == DSTADDR_SOCKOPT)
|
|
|
|
{
|
|
|
|
msg.msg_iov[0].iov_base = outbuf;
|
2013-04-18 09:36:41 +02:00
|
|
|
msg.msg_iov[0].iov_len = ret;
|
2012-06-03 19:10:46 +02:00
|
|
|
sendmsg(listenSocket, &msg, 0);
|
|
|
|
msg.msg_iov[0].iov_base = inbuf;
|
2013-04-18 09:36:41 +02:00
|
|
|
msg.msg_iov[0].iov_len = sizeof(inbuf);
|
2012-06-03 19:10:46 +02:00
|
|
|
handled = true;
|
|
|
|
}
|
2011-12-13 16:02:51 +01:00
|
|
|
}
|
2012-06-03 19:10:46 +02:00
|
|
|
if (!handled)
|
|
|
|
sendto(listenSocket, outbuf, ret, 0, (struct sockaddr*)&si_other, sizeof(si_other));
|
|
|
|
}
|
2011-12-13 16:02:51 +01:00
|
|
|
return 0;
|
|
|
|
}
|