Skip to content

Commit 517d729

Browse files
authored
Merge pull request #120 from luizluca/nxdomain_for_underscore
Answer NXDOMAIN for _.xxx.yyy.top.domain
2 parents 3fcd128 + 076ec9f commit 517d729

File tree

4 files changed

+100
-0
lines changed

4 files changed

+100
-0
lines changed

src/dns.c

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -390,6 +390,71 @@ int dns_encode_a_response(char *buf, size_t buflen, struct query *q)
390390
return len;
391391
}
392392

393+
int dns_encode_nxdomain(char *buf, size_t buflen, struct query *q, const char *zone)
394+
{
395+
char rnamebuf[256];
396+
char nsbuf[256];
397+
HEADER *header;
398+
char *soa_start;
399+
char *p;
400+
401+
if (buflen < sizeof(HEADER))
402+
return 0;
403+
404+
memset(buf, 0, buflen);
405+
header = (HEADER*)buf;
406+
407+
header->id = htons(q->id);
408+
header->qr = 1; // response
409+
header->opcode = 0;
410+
header->aa = 1; // authoritative
411+
header->tc = 0;
412+
header->rd = 0;
413+
header->ra = 0;
414+
header->rcode = 3; // NXDOMAIN
415+
416+
header->qdcount = htons(1);
417+
header->ancount = htons(0);
418+
header->nscount = htons(1); // We'll include SOA
419+
header->arcount = htons(0);
420+
421+
p = buf + sizeof(HEADER);
422+
423+
// Question section
424+
putname(&p, buflen - (p - buf), q->name);
425+
CHECKLEN(4);
426+
putshort(&p, q->type);
427+
putshort(&p, C_IN);
428+
429+
// Authority section (SOA)
430+
CHECKLEN(10);
431+
putname(&p, buflen - (p - buf), zone); // zone name (owner of SOA)
432+
putshort(&p, T_SOA);
433+
putshort(&p, C_IN);
434+
putlong(&p, 60); // TTL
435+
436+
soa_start = p;
437+
p += 2; // skip rdlength (to be filled later)
438+
439+
// Primary NS and responsible mailbox
440+
snprintf(nsbuf, sizeof(nsbuf), "ns.%s", zone);
441+
putname(&p, buflen - (p - buf), nsbuf);
442+
snprintf(rnamebuf, sizeof(rnamebuf), "hostmaster.%s", zone);
443+
putname(&p, buflen - (p - buf), rnamebuf);
444+
445+
// SOA fields: serial, refresh, retry, expire, minimum
446+
putlong(&p, 1); // serial
447+
putlong(&p, 3600); // refresh
448+
putlong(&p, 1800); // retry
449+
putlong(&p, 604800); // expire
450+
putlong(&p, 60); // minimum
451+
452+
int soalen = p - soa_start - 2;
453+
putshort(&soa_start, soalen); // fill in rdlength
454+
455+
return p - buf;
456+
}
457+
393458
#undef CHECKLEN
394459

395460
unsigned short dns_get_id(char *packet, size_t packetlen)

src/dns.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ int dns_encode(char *, size_t, struct query *, qr_t, const char *, size_t);
3131
int dns_encode_ns_response(char *buf, size_t buflen, struct query *q,
3232
char *topdomain);
3333
int dns_encode_a_response(char *buf, size_t buflen, struct query *q);
34+
int dns_encode_nxdomain(char *buf, size_t buflen, struct query *q, const char *zone);
3435
unsigned short dns_get_id(char *packet, size_t packetlen);
3536
int dns_decode(char *, size_t, struct query *, qr_t, char *, size_t);
3637

src/iodined.c

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1597,6 +1597,27 @@ handle_a_request(int dns_fd, struct query *q, int fakeip)
15971597
}
15981598
}
15991599

1600+
static void
1601+
handle_underscore_request(int dns_fd, struct query *q, const char *topdomain)
1602+
{
1603+
char buf[64*1024];
1604+
int len;
1605+
1606+
len = dns_encode_nxdomain(buf, sizeof(buf), q, topdomain);
1607+
if (len < 1) {
1608+
warnx("dns_encode_nxdomain doesn't fit");
1609+
return;
1610+
}
1611+
1612+
if (debug >= 2) {
1613+
fprintf(stderr, "TX: client %s, type %d, name %s, %d bytes NXDOMAIN reply\n",
1614+
format_addr(&q->from, q->fromlen), q->type, q->name, len);
1615+
}
1616+
if (sendto(dns_fd, buf, len, 0, (struct sockaddr*)&q->from, q->fromlen) <= 0) {
1617+
warn("nxdomain reply send error");
1618+
}
1619+
}
1620+
16001621
static void
16011622
forward_query(int bind_fd, struct query *q)
16021623
{
@@ -1719,6 +1740,18 @@ tunnel_dns(int tun_fd, int dns_fd, struct dnsfd *dns_fds, int bind_fd)
17191740
return 0;
17201741
}
17211742

1743+
/* Handle A-type query for _.***.topdomain. It happens when
1744+
*
1745+
* https://datatracker.ietf.org/doc/html/rfc7816 (qname minimisation)
1746+
* https://github.com/isc-projects/bind9/commit/ae52c2117eba9fa0778125f4e10834d673ab811b
1747+
* */
1748+
if (q.type == T_A &&
1749+
(q.name[0] == '_') &&
1750+
q.name[1] == '.') {
1751+
handle_underscore_request(dns_fd, &q, topdomain);
1752+
return 0;
1753+
}
1754+
17221755
switch (q.type) {
17231756
case T_NULL:
17241757
case T_PRIVATE:

src/windows.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ typedef unsigned int in_addr_t;
4040
#define T_CNAME DNS_TYPE_CNAME
4141
#define T_MX DNS_TYPE_MX
4242
#define T_TXT DNS_TYPE_TXT
43+
#define T_SOA DNS_TYPE_SOA
4344
#define T_SRV DNS_TYPE_SRV
4445

4546
#define C_IN 1

0 commit comments

Comments
 (0)