Commit Diff
Diff:
b9da453498998a0f3ff39644929748233ad921a3
d26ffa55c5cc0928aebfafd125904dfd234c7884
Commit:
d26ffa55c5cc0928aebfafd125904dfd234c7884
Tree:
aeedc5d3a6d4357afefdb75368b5a7d74c00836d
Author:
pjp <pjp@delphinusdns.org>
Committer:
pjp <pjp@delphinusdns.org>
Date:
Mon Jan 9 14:26:50 2017 UTC
Message:
To ENT or not to ENT, that is the question! I'd rather be with ENT! Add RFC 8020 Empty Non-Terminal Name support. This adds a singly linked list with domain names in the system. Since there can be multiple domain names it is a forest. And we search for ENTS in this forest given a question that would normally be getting an NXDOMAIN. Since an NXDOMAIN is not normal according to RFC 8020 we rewrite output to be NODATA when not dnssec'ed. When DNSSEC'ed we return with a NOERROR (this still needs testing).
blob - ff99a774ffd8b806c64ef9d23c65f2078343948d
blob + a03dd8d6705f1c5661da6b09060da85951a42a58
--- Makefile.linux
+++ Makefile.linux
@@ -8,8 +8,8 @@ AR=ar
all: delphinusdnsd dd-convert
-delphinusdnsd: additional.o parse.o delphinusdnsd.o reply.o region.o log.o axfr.o filter.o ratelimit.o whitelist.o base64.o dnssec.o util.o
- $(CC) $(CFLAGS) -o delphinusdnsd/delphinusdnsd additional.o delphinusdnsd.o parse.o reply.o region.o log.o axfr.o filter.o ratelimit.o whitelist.o base64.o dnssec.o util.o $(LDADD)
+delphinusdnsd: additional.o parse.o delphinusdnsd.o reply.o region.o log.o axfr.o filter.o ratelimit.o whitelist.o base64.o dnssec.o util.o ent.o
+ $(CC) $(CFLAGS) -o delphinusdnsd/delphinusdnsd additional.o delphinusdnsd.o parse.o reply.o region.o log.o axfr.o filter.o ratelimit.o whitelist.o base64.o dnssec.o util.o ent.o $(LDADD)
dd-convert: dd-convert.o util.o dnssec.o parse.o base64.o
$(CC) $(CFLAGS) -o dd-convert/dd-convert dd-convert.o util.o dnssec.o base64.o parse.o $(LDADD)
@@ -59,6 +59,8 @@ dnssec.o: dnssec.c
util.o: util.c
$(CC) $(CFLAGS) -c util.c
+ent.o: ent.c
+ $(CC) $(CFLAGS) -c ent.c
install: install-delphinusdnsd install-dd-convert
blob - b7e9e28132d6472af905f688eaccf2b82158daf8
blob + d31a0d01a675ada17ce5d3e415ca607ba0429c5d
--- ddd-db.h
+++ ddd-db.h
@@ -35,6 +35,7 @@
#define ERR_NXDOMAIN 0x2
#define ERR_NOERROR 0x4
#define ERR_REFUSED 0x8
+#define ERR_NODATA 0x10
#define RECORD_COUNT 20
#define NEGATIVE_CACHE_TIME 600 /* DNS & Bind 3rd edition page 35 */
blob - 208e10a75e05070e5c81b5bd6dbb857d46ad53a4
blob + 02a8a2ef05a7cacbfd9c69470d30195cceddbb77
--- delphinusdnsd/Makefile.freebsd
+++ delphinusdnsd/Makefile.freebsd
@@ -2,7 +2,7 @@
PROG=delphinusdnsd
-SRCS=delphinusdnsd.c parse.y reply.c additional.c region.c log.c axfr.c filter.c ratelimit.c whitelist.c base64.c dnssec.c util.c
+SRCS=delphinusdnsd.c parse.y reply.c additional.c region.c log.c axfr.c filter.c ratelimit.c whitelist.c base64.c dnssec.c util.c ent.c
#CFLAGS= -DDEBUG -g -Wall
CFLAGS= -Wall -g -I/usr/local/include/db5
blob - 97192608b55dbf2242a6385cbd3656b197d2d08a
blob + c732666951c6106e293f3c087d07c0629e79d386
--- delphinusdnsd/Makefile.netbsd
+++ delphinusdnsd/Makefile.netbsd
@@ -2,7 +2,7 @@
PROG=delphinusdnsd
-SRCS=delphinusdnsd.c parse.y reply.c additional.c region.c log.c axfr.c filter.c ratelimit.c whitelist.c base64.c dnssec.c util.c
+SRCS=delphinusdnsd.c parse.y reply.c additional.c region.c log.c axfr.c filter.c ratelimit.c whitelist.c base64.c dnssec.c util.c ent.c
CFLAGS= -g -I/usr/pkg/include/db5/
CFLAGS+= -I${.CURDIR}/..
blob - 40ae5cd90584ce8f6ffdec055f8010ae624b0a10
blob + 126bd636ecd133c0b5fabad7a3f50911deb17af5
--- delphinusdnsd/Makefile.openbsd
+++ delphinusdnsd/Makefile.openbsd
@@ -2,7 +2,7 @@
PROG=delphinusdnsd
-SRCS=delphinusdnsd.c parse.y reply.c additional.c region.c log.c axfr.c filter.c ratelimit.c whitelist.c base64.c dnssec.c util.c
+SRCS=delphinusdnsd.c parse.y reply.c additional.c region.c log.c axfr.c filter.c ratelimit.c whitelist.c base64.c dnssec.c util.c ent.c
#CFLAGS= -DDEBUG -g -Wall
CFLAGS= -Wall -g -I/usr/local/include/db4
blob - 0bf965fdce478fa41125731fe383c3b8e2bccb05
blob + 0ad0c3a7bf27799f33c2eb491a5b43bffa1d70b7
--- delphinusdnsd.c
+++ delphinusdnsd.c
@@ -35,6 +35,7 @@
extern void add_rrlimit(int, u_int16_t *, int, char *);
extern void axfrloop(int *, int, char **, DB *);
extern struct question *build_fake_question(char *, int, u_int16_t);
+extern int check_ent(char *, int);
extern int check_rrlimit(int, u_int16_t *, int, char *);
extern u_int16_t check_qtype(struct domain *, u_int16_t, int, int *);
extern void collects_init(void);
@@ -47,6 +48,7 @@ extern char * get_dns_type(int, int);
extern void init_dnssec(void);
extern void init_recurse(void);
extern void init_region(void);
+extern int init_entlist(DB *);
extern void init_filter(void);
extern void init_notifyslave(void);
extern void init_whitelist(void);
@@ -57,6 +59,7 @@ extern int reply_a(struct sreply *, DB *);
extern int reply_aaaa(struct sreply *, DB *);
extern int reply_any(struct sreply *);
extern int reply_badvers(struct sreply *);
+extern int reply_nodata(struct sreply *);
extern int reply_cname(struct sreply *);
extern int reply_fmterror(struct sreply *);
extern int reply_notimpl(struct sreply *);
@@ -118,6 +121,7 @@ extern int axfrport;
extern int ratelimit;
extern int ratelimit_packets_per_second;
extern int whitelist;
+extern int dnssec;
static int reload = 0;
static int mshutdown = 0;
@@ -166,7 +170,7 @@ static struct tcps {
} *tn1, *tnp, *tntmp;
-static const char rcsid[] = "$Id: delphinusdnsd.c,v 1.7 2017/01/03 08:36:38 pjp Exp $";
+static const char rcsid[] = "$Id: delphinusdnsd.c,v 1.8 2017/01/09 14:26:50 pjp Exp $";
/*
* MAIN - set up arguments, set up database, set up sockets, call mainloop
@@ -415,6 +419,12 @@ main(int argc, char *argv[])
exit(1);
}
+ if (init_entlist(db) < 0) {
+ dolog(LOG_INFO, "creating entlist failed\n");
+ slave_shutdown();
+ exit(1);
+ }
+
/* ratelimiting setup */
if (ratelimit) {
ratelimit_backlog = ratelimit_packets_per_second * 2;
@@ -1934,12 +1944,26 @@ mainloop(struct cfg *cfg)
goto tcpout;
break;
case ERR_NXDOMAIN:
- goto tcpnxdomain;
+ /* check if our question is for an ENT */
+ if (check_ent(question->hdr->name, question->hdr->namelen) == 1) {
+ if (dnssec) {
+ goto tcpnoerror;
+ } else {
+ snprintf(replystring, DNS_MAXNAME, "NODATA");
+ build_reply(&sreply, tnp->so, pbuf, len, question, from, fromlen, sd0, NULL, aregion, istcp, 0, NULL, replybuf);
+ slen = reply_nodata(&sreply);
+ goto tcpout;
+ break;
+ }
+ } else {
+ goto tcpnxdomain;
+ }
case ERR_NOERROR:
/*
* this is hackish not sure if this should be here
*/
+tcpnoerror:
snprintf(replystring, DNS_MAXNAME, "NOERROR");
/*
@@ -1968,6 +1992,19 @@ mainloop(struct cfg *cfg)
switch (type0) {
case 0:
+ /* check for ents */
+ if (check_ent(question->hdr->name, question->hdr->namelen) == 1) {
+ if (dnssec) {
+ goto tcpnoerror;
+ } else {
+ snprintf(replystring, DNS_MAXNAME, "NODATA");
+ build_reply(&sreply, tnp->so, pbuf, len, question, from, fromlen, sd0, NULL, aregion, istcp, 0, NULL, replybuf);
+ slen = reply_nodata(&sreply);
+ goto tcpout;
+ }
+ }
+
+
/*
* lookup_zone could not find an RR for the
* question at all -> nxdomain
@@ -2572,12 +2609,27 @@ axfrentry:
goto udpout;
break;
case ERR_NXDOMAIN:
- goto udpnxdomain;
+ /* check if our question is for an ENT */
+ if (check_ent(question->hdr->name, question->hdr->namelen) == 1) {
+ if (dnssec) {
+ goto udpnoerror;
+ } else {
+ snprintf(replystring, DNS_MAXNAME, "NODATA");
+ build_reply(&sreply, so, buf, len, question, from, fromlen, sd0, NULL, aregion, istcp, 0, NULL, replybuf);
+ slen = reply_nodata(&sreply);
+ goto udpout;
+ break;
+ }
+ } else {
+ goto udpnxdomain;
+ }
case ERR_NOERROR:
/*
* this is hackish not sure if this should be here
*/
+udpnoerror:
+
snprintf(replystring, DNS_MAXNAME, "NOERROR");
/*
@@ -2605,6 +2657,17 @@ axfrentry:
switch (type0) {
case 0:
udpnxdomain:
+ if (check_ent(question->hdr->name, question->hdr->namelen) == 1) {
+ if (dnssec) {
+ goto udpnoerror;
+ } else {
+ snprintf(replystring, DNS_MAXNAME, "NODATA");
+ build_reply(&sreply, so, buf, len, question, from, fromlen, sd0, NULL, aregion, istcp, 0, NULL, replybuf);
+ slen = reply_nodata(&sreply);
+ goto udpout;
+ }
+ }
+
/*
* lookup_zone could not find an RR for the
* question at all -> nxdomain
blob - /dev/null
blob + fb919c0498d075b2efe1776fce15b31b6a13532a (mode 644)
--- /dev/null
+++ ent.c
@@ -0,0 +1,160 @@
+/*
+ * Copyright (c) 2017 Peter J. Philipp
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+/*
+ * this file is based on whitelist.c
+ */
+
+#include "ddd-include.h"
+#include "ddd-dns.h"
+#include "ddd-db.h"
+
+int init_entlist(DB *);
+int check_ent(char *, int);
+static int ent_contains(char *, int, char *, int);
+
+extern void dolog(int, char *, ...);
+extern int memcasecmp(u_char *, u_char *, int);
+
+extern int debug, verbose;
+
+SLIST_HEAD(listhead, ententry) enthead;
+
+static struct ententry {
+ char *name;
+ int len;
+ u_int64_t flags;
+ SLIST_ENTRY(ententry) ent_entry;
+} *ent2, *entp;
+
+
+static const char rcsid[] = "$Id: ent.c,v 1.1 2017/01/09 14:26:50 pjp Exp $";
+
+/*
+ * INIT_ENTLIST - initialize the ent singly linked list
+ */
+
+int
+init_entlist(DB *db)
+{
+ DBT key, data;
+ DBC *cursor;
+ struct domain *sd = NULL;
+ int curs;
+
+ SLIST_INIT(&enthead);
+
+ if (db->cursor(db, NULL, &cursor, 0) != 0) {
+ dolog(LOG_INFO, "db->cursor: %s\n", strerror(errno));
+ return -1;
+ }
+
+ memset(&key, 0, sizeof(key));
+ memset(&data, 0, sizeof(data));
+
+ /* herd all ENT candidates into our ent-list */
+ curs = cursor->c_get(cursor, &key, &data, DB_FIRST);
+ do {
+
+ if (curs != 0) {
+ dolog(LOG_INFO, "cursor->c_get: %s\n", strerror(errno));
+ return -1;
+ }
+
+ sd = (struct domain *)data.data;
+ ent2 = malloc(sizeof(struct ententry));
+ if (ent2 == NULL) {
+ dolog(LOG_INFO, "malloc: %s\n", strerror(errno));
+ return -1;
+ }
+
+ ent2->name = malloc(sd->zonelen);
+ if (ent2->name == NULL) {
+ dolog(LOG_INFO, "malloc: %s\n", strerror(errno));
+ return -1;
+ }
+
+
+ memcpy(ent2->name, sd->zone, sd->zonelen);
+ ent2->len = sd->zonelen;
+ ent2->flags = sd->flags;
+
+ SLIST_INSERT_HEAD(&enthead, ent2, ent_entry);
+
+ memset(&key, 0, sizeof(key));
+ memset(&data, 0, sizeof(data));
+
+ } while ((curs = cursor->c_get(cursor, &key, &data, DB_NEXT)) == 0);
+
+
+ return 0;
+}
+
+/*
+ * Check if the provided name is an empty non-terminating (ENT) name, if so
+ * return 1, else return 0
+ */
+
+int
+check_ent(char *name, int len)
+{
+ /* walk the dns forest searching for a matching ENT */
+ SLIST_FOREACH(entp, &enthead, ent_entry) {
+ /* skip ent candidates that are too short */
+ if (entp->len <= len)
+ continue;
+ if (ent_contains(name, len, entp->name, entp->len)) {
+ return (1);
+ }
+ }
+
+ return (0);
+}
+
+
+static int
+ent_contains(char *name, int len, char *entname, int entlen)
+{
+ char *p;
+ int l;
+
+ p = entname;
+ l = entlen;
+ while (*p) {
+ l -= (*p + 1);
+ p += (*p + 1);
+
+ if (l != len)
+ continue;
+
+ if (memcasecmp(name, p, l) == 0)
+ return 1;
+ }
+
+ return 0;
+}
blob - 1a70d7aef43274a31239e201a80e156e3ebb296c
blob + d3757e91b5b30e488914809febdb23e6109a53f7
--- reply.c
+++ reply.c
@@ -68,6 +68,7 @@ int reply_notimpl(struct sreply *);
int reply_nxdomain(struct sreply *, DB *);
int reply_noerror(struct sreply *, DB *);
int reply_badvers(struct sreply *);
+int reply_nodata(struct sreply *);
int reply_soa(struct sreply *);
int reply_ptr(struct sreply *);
int reply_txt(struct sreply *);
@@ -109,7 +110,7 @@ extern uint8_t vslen;
outlen = tmplen; \
} while (0);
-static const char rcsid[] = "$Id: reply.c,v 1.51 2016/07/06 05:12:51 pjp Exp $";
+static const char rcsid[] = "$Id: reply.c,v 1.52 2017/01/09 14:26:50 pjp Exp $";
/*
* REPLY_A() - replies a DNS question (*q) on socket (so)
@@ -6037,6 +6038,87 @@ reply_badvers(struct sreply *sreply)
q->badvers = 1;
outlen = additional_opt(q, reply, replysize, outlen);
}
+
+ if (istcp) {
+ char *tmpbuf;
+ u_int16_t *plen;
+
+ tmpbuf = malloc(outlen + 2);
+ if (tmpbuf == NULL) {
+ dolog(LOG_INFO, "malloc: %s\n", strerror(errno));
+ }
+ plen = (u_int16_t *)tmpbuf;
+ *plen = htons(outlen);
+
+ memcpy(&tmpbuf[2], reply, outlen);
+
+ if ((retlen = send(so, tmpbuf, outlen + 2, 0)) < 0) {
+ dolog(LOG_INFO, "send: %s\n", strerror(errno));
+ }
+ free(tmpbuf);
+ } else {
+ if ((retlen = sendto(so, reply, outlen, 0, sa, salen)) < 0) {
+ dolog(LOG_INFO, "sendto: %s\n", strerror(errno));
+ }
+ }
+
+ return (retlen);
+}
+
+
+/*
+ * REPLY_NODATA() - replies a DNS question (*q) on socket (so) based on
+ * reply_badvers().
+ *
+ */
+
+int
+reply_nodata(struct sreply *sreply)
+{
+ char *reply = sreply->replybuf;
+ struct dns_header *odh;
+ u_int16_t outlen;
+
+ int so = sreply->so;
+ char *buf = sreply->buf;
+ int len = sreply->len;
+ struct question *q = sreply->q;
+ struct sockaddr *sa = sreply->sa;
+ int salen = sreply->salen;
+ int istcp = sreply->istcp;
+ int replysize = 512;
+ int retlen = -1;
+
+ if (istcp) {
+ replysize = 65535;
+ }
+
+ if (!istcp && q->edns0len > 512)
+ replysize = q->edns0len;
+
+ odh = (struct dns_header *)&reply[0];
+ outlen = sizeof(struct dns_header);
+
+ if (len > replysize) {
+ return (retlen);
+
+ }
+
+ memcpy(reply, buf, sizeof(struct dns_header) + q->hdr->namelen + 4);
+ memset((char *)&odh->query, 0, sizeof(u_int16_t));
+
+ outlen += (q->hdr->namelen + 4);
+
+ SET_DNS_REPLY(odh);
+ SET_DNS_AUTHORITATIVE(odh);
+ SET_DNS_RCODE_NOERR(odh);
+
+ HTONS(odh->query);
+
+ odh->question = htons(1);
+ odh->answer = 0;
+ odh->nsrr = 0;
+ odh->additional = 0;
if (istcp) {
char *tmpbuf;
repomaster@centroid.eu