Commit Diff
Diff:
1e005ec5a13d711088de8e390c9ba5e4e3eee316
e0d56ba1e5a551cfd5d9c01fc411460e99233824
Commit:
e0d56ba1e5a551cfd5d9c01fc411460e99233824
Tree:
95d03d01e10fbf55a527d13cc0011589414d8a2a
Author:
pjp <pjp@delphinusdns.org>
Committer:
pjp <pjp@delphinusdns.org>
Date:
Wed Oct 30 12:14:36 2019 UTC
Message:
while working on replication/slave mode and setting up hosts for a test zone I noticed the referrals (delegation) code was broken. This fixes it for hopefully DNSSEC and plain answers.
blob - 42949345c2ec355e65a9e17225f4b067cb56ae93
blob + af62793f96f774a51f33b615b42cfe8023f0d517
--- ddd-db.h
+++ ddd-db.h
@@ -27,7 +27,7 @@
*/
/*
- * $Id: ddd-db.h,v 1.21 2019/09/20 09:51:43 pjp Exp $
+ * $Id: ddd-db.h,v 1.22 2019/10/30 12:14:36 pjp Exp $
*/
#ifndef _DB_H
@@ -54,6 +54,7 @@
#define ERR_NOERROR 0x4
#define ERR_REFUSED 0x8
#define ERR_NODATA 0x10
+#define ERR_DELEGATE 0x20
#define RECORD_COUNT 20
#define NEGATIVE_CACHE_TIME 600 /* DNS & Bind 3rd edition page 35 */
blob - 1e3b6f787d604779be404307932514d6fde1e6e9
blob + 34c431d7e864f8fdc75743a3cf5f2bfff6ef61df
--- dddctl.c
+++ dddctl.c
@@ -27,7 +27,7 @@
*/
/*
- * $Id: dddctl.c,v 1.78 2019/10/15 12:20:49 pjp Exp $
+ * $Id: dddctl.c,v 1.79 2019/10/30 12:14:36 pjp Exp $
*/
#include <sys/param.h>
@@ -211,6 +211,7 @@ int lookup_name(FILE *, int, char *, u_int16_t, struc
int lookup_axfr(FILE *, int, char *, struct soa *, u_int32_t, char *, char *);
int count_db(ddDB *);
void update_soa_serial(ddDB *, char *, time_t);
+int notglue(ddDB *, struct rbtree *, char *);
#if OPENSSL_VERSION_NUMBER < 0x10100000L
@@ -1815,7 +1816,8 @@ calculate_rrsigs(ddDB *db, char *zonename, int expiry)
}
}
if ((rrset = find_rr(rbt, DNS_TYPE_A)) != NULL) {
- if (sign_a(db, zonename, zsk_key, expiry, rbt) < 0) {
+ if (notglue(db, rbt, zonename) &&
+ sign_a(db, zonename, zsk_key, expiry, rbt) < 0) {
fprintf(stderr, "sign_a error\n");
return -1;
}
@@ -1845,7 +1847,9 @@ calculate_rrsigs(ddDB *db, char *zonename, int expiry)
}
}
if ((rrset = find_rr(rbt, DNS_TYPE_AAAA)) != NULL) {
- if (sign_aaaa(db, zonename, zsk_key, expiry, rbt) < 0) {
+ /* find out if we're glue, if not sign */
+ if (notglue(db, rbt, zonename) &&
+ sign_aaaa(db, zonename, zsk_key, expiry, rbt) < 0) {
fprintf(stderr, "sign_aaaa error\n");
return -1;
}
@@ -5861,6 +5865,9 @@ construct_nsec3(ddDB *db, char *zone, int iterations,
return -1;
}
+ /* if we're a glue record, skip */
+ if (! notglue(db, rbt, zone))
+ continue;
bitmap[0] = '\0';
if (find_rr(rbt, DNS_TYPE_A) != NULL)
@@ -8571,4 +8578,67 @@ update_soa_serial(ddDB *db, char *zonename, time_t ser
free(rbt0);
free_question(q);
+}
+
+int
+notglue(ddDB *db, struct rbtree *rbt, char *zonename)
+{
+ struct rbtree *rbt0;
+ struct question *q;
+ char *zoneapex, *p;
+ char replystring[512];
+ int apexlen, len;
+ int retval, lzerrno;
+
+
+ zoneapex = dns_label(zonename, &apexlen);
+ if (zoneapex == NULL) {
+ dolog(LOG_INFO, "can't get dns_label() to work\n");
+ return 0;
+ }
+
+ if (rbt->zonelen == apexlen &&
+ memcasecmp(rbt->zone, zoneapex, rbt->zonelen) == 0) {
+ free(zoneapex);
+ /* we aren't glue */
+ return 1;
+ }
+
+ p = rbt->zone;
+ len = rbt->zonelen;
+
+ do {
+ len -= (*p + 1);
+ p += (*p + 1);
+
+ if (*p == '\0')
+ break;
+
+ q = build_fake_question(p, len, DNS_TYPE_NS, NULL, 0);
+ if (q == NULL) {
+ free(zoneapex);
+ return 1;
+ }
+
+ if ((rbt0 = lookup_zone(db, q, &retval, &lzerrno, (char *)&replystring)) == NULL) {
+ free_question(q);
+ continue;
+ }
+
+ if (len > apexlen && find_rr(rbt0, DNS_TYPE_NS) != NULL) {
+ free(rbt0);
+ free_question(q);
+ free(zoneapex);
+ return 0;
+ }
+
+ free_question(q);
+ free(rbt0);
+
+ } while (*p && len > 0 && ! (len == apexlen && memcasecmp(p, zoneapex, len) == 0));
+
+
+ free(zoneapex);
+ /* let's pretend we're not glue here */
+ return 1;
}
blob - 94c45990f9587b0465335895450e64f1d5956359
blob + 88654c309f23e0d78f884abe9e4c84ea5dcc9df0
--- delphinusdnsd.c
+++ delphinusdnsd.c
@@ -27,7 +27,7 @@
*/
/*
- * $Id: delphinusdnsd.c,v 1.72 2019/10/25 15:13:49 pjp Exp $
+ * $Id: delphinusdnsd.c,v 1.73 2019/10/30 12:14:36 pjp Exp $
*/
@@ -2011,6 +2011,22 @@ axfrentry:
snprintf(replystring, DNS_MAXNAME, "DROP");
slen = 0;
goto udpout;
+
+ case ERR_DELEGATE:
+ if (rbt0 != NULL) {
+ build_reply(&sreply, so, buf, len, question, from, \
+ fromlen, rbt0, NULL, aregion, istcp, \
+ 0, NULL, replybuf);
+
+ slen = reply_ns(&sreply, cfg->db);
+ } else {
+ slen = 0;
+ snprintf(replystring, DNS_MAXNAME, "DROP");
+ }
+
+ goto udpout;
+ break;
+
}
}
@@ -2951,6 +2967,22 @@ tcploop(struct cfg *cfg, struct imsgbuf **ibuf)
snprintf(replystring, DNS_MAXNAME, "DROP");
slen = 0;
goto tcpout;
+
+ case ERR_DELEGATE:
+ if (rbt0 != NULL) {
+
+ build_reply( &sreply, so, pbuf, len, question,
+ from, fromlen, rbt0, NULL,
+ aregion, istcp, 0, NULL,
+ replybuf);
+
+ slen = reply_ns(&sreply, cfg->db);
+ } else {
+ slen = 0;
+ snprintf(replystring, DNS_MAXNAME, "DROP");
+ }
+ goto tcpout;
+
}
}
blob - b07d6a03ac2a44fc26eb1ca4c839cbb310a9bb4c
blob + d9568fe452cdb94b75944105bd691af92063a7ac
--- reply.c
+++ reply.c
@@ -27,7 +27,7 @@
*/
/*
- * $Id: reply.c,v 1.84 2019/10/25 15:13:49 pjp Exp $
+ * $Id: reply.c,v 1.85 2019/10/30 12:14:36 pjp Exp $
*/
#include <sys/types.h>
@@ -93,9 +93,15 @@ extern struct rbtree * find_rrset(ddDB *db, char *name
extern struct rrset * find_rr(struct rbtree *rbt, u_int16_t rrtype);
extern int display_rr(struct rrset *rrset);
extern int rotate_rr(struct rrset *rrset);
+extern struct rbtree * find_nsec3_cover_next_closer(char *name, int namelen, struct rbtree *, ddDB *db);
+extern struct rbtree * find_nsec3_match_closest(char *name, int namelen, struct rbtree *, ddDB *db);
+extern struct rbtree * find_nsec3_wildcard_closest(char *name, int namelen, struct rbtree *, ddDB *db);
+extern struct rbtree * find_nsec3_match_qname(char *name, int namelen, struct rbtree *, ddDB *db);
+extern struct rbtree * get_soa(ddDB *, struct question *);
struct rbtree *Lookup_zone(ddDB *, char *, u_int16_t, u_int16_t, int);
+struct rbtree *get_ns(ddDB *, struct rbtree *, int *);
u_int16_t create_anyreply(struct sreply *, char *, int, int, int);
int reply_a(struct sreply *, ddDB *);
int reply_nsec3(struct sreply *, ddDB *);
@@ -131,10 +137,6 @@ int nsec_comp(const void *a, const void *b);
char * convert_name(char *name, int namelen);
int count_dots(char *name);
char * base32hex_encode(u_char *input, int len);
-struct rbtree * find_nsec3_cover_next_closer(char *name, int namelen, struct rbtree *, ddDB *db);
-struct rbtree * find_nsec3_match_closest(char *name, int namelen, struct rbtree *, ddDB *db);
-struct rbtree * find_nsec3_wildcard_closest(char *name, int namelen, struct rbtree *, ddDB *db);
-struct rbtree * find_nsec3_match_qname(char *name, int namelen, struct rbtree *, ddDB *db);
extern int debug, verbose, dnssec;
extern char *versionstring;
@@ -1901,7 +1903,6 @@ reply_ns(struct sreply *sreply, ddDB *db)
u_int16_t namelen;
struct answer {
- char name[2];
u_int16_t type;
u_int16_t class;
u_int32_t ttl;
@@ -1918,6 +1919,8 @@ reply_ns(struct sreply *sreply, ddDB *db)
struct sockaddr *sa = sreply->sa;
int salen = sreply->salen;
struct rbtree *rbt = sreply->rbt1;
+ struct rbtree *rbt0 = NULL, *rbt1 = NULL;
+ struct rbtree *nrbt = NULL;
struct rrset *rrset = NULL;
struct rr *rrp = NULL;
int istcp = sreply->istcp;
@@ -1925,9 +1928,23 @@ reply_ns(struct sreply *sreply, ddDB *db)
int retlen = -1;
u_int16_t rollback;
int ns_type;
+ int delegation, addiscount;
- if ((rrset = find_rr(rbt, DNS_TYPE_NS)) == 0)
+ SLIST_HEAD(, addis) addishead;
+ struct addis {
+ char name[DNS_MAXNAME];
+ int namelen;
+ SLIST_ENTRY(addis) addis_entries;
+ } *ad0, *ad1;
+
+ SLIST_INIT(&addishead);
+ /* check for apex, delegations */
+ rbt1 = get_ns(db, rbt, &delegation);
+
+ if ((rrset = find_rr(rbt, DNS_TYPE_NS)) == NULL) {
+ free(rbt1);
return -1;
+ }
if (istcp) {
replysize = 65535;
@@ -1941,6 +1958,7 @@ reply_ns(struct sreply *sreply, ddDB *db)
outlen = sizeof(struct dns_header);
if (len > replysize) {
+ free(rbt1);
return (retlen);
}
@@ -1952,7 +1970,9 @@ reply_ns(struct sreply *sreply, ddDB *db)
rollback = outlen;
SET_DNS_REPLY(odh);
- SET_DNS_AUTHORITATIVE(odh);
+
+ if (! delegation)
+ SET_DNS_AUTHORITATIVE(odh);
if (q->rd) {
SET_DNS_RECURSION(odh);
@@ -1965,15 +1985,12 @@ reply_ns(struct sreply *sreply, ddDB *db)
odh->nsrr = 0;
odh->additional = 0;
- /* skip dns header, question name, qtype and qclass */
- answer = (struct answer *)(&reply[0] + sizeof(struct dns_header) +
- q->hdr->namelen + 4);
ns_count = 0;
TAILQ_FOREACH(rrp, &rrset->rr_head, entries) {
- answer->name[0] = 0xc0;
- answer->name[1] = 0x0c;
+ memcpy(&reply[outlen], rbt1->zone, rbt1->zonelen);
+ answer = (struct answer *)(&reply[outlen] + rbt1->zonelen);
answer->type = htons(DNS_TYPE_NS);
answer->class = q->hdr->qclass;
answer->ttl = htonl(((struct ns *)rrp->rdata)->ttl);
@@ -1986,8 +2003,20 @@ reply_ns(struct sreply *sreply, ddDB *db)
memcpy((char *)&answer->ns, (char *)name, namelen);
- outlen += (12 + namelen);
+ outlen += (10 + namelen + rbt1->zonelen);
+ ad0 = malloc(sizeof(struct addis));
+ if (ad0 == NULL) {
+ free(rbt1);
+ dolog(LOG_INFO, "malloc: %s\n", strerror(errno));
+ return -1;
+ }
+
+ memcpy(ad0->name, name, namelen);
+ ad0->namelen = namelen;
+
+ SLIST_INSERT_HEAD(&addishead, ad0, addis_entries);
+
/* compress the label if possible */
if ((tmplen = compress_label((u_char*)reply, outlen, namelen)) > 0) {
/* XXX */
@@ -1995,30 +2024,22 @@ reply_ns(struct sreply *sreply, ddDB *db)
}
answer->rdlength = htons(&reply[outlen] - &answer->ns);
-
-
- /* set new offset for answer */
- answer = (struct answer *)&reply[outlen];
ns_count++;
}
- switch (ns_type) {
- case NS_TYPE_DELEGATE:
+ if (delegation) {
odh->answer = 0;
odh->nsrr = htons(ns_count);
- break;
- default:
+ } else {
odh->answer = htons(ns_count);
odh->nsrr = 0;
- break;
}
-
/* add RRSIG reply_ns */
if (dnssec && q->dnssecok && rbt->dnssec) {
int origlen = outlen;
- tmplen = additional_rrsig(q->hdr->name, q->hdr->namelen, DNS_TYPE_NS, rbt, reply, replysize, outlen, 0);
+ tmplen = additional_rrsig(rbt1->zone, rbt1->zonelen, DNS_TYPE_NS, rbt1, reply, replysize, outlen, 0);
if (tmplen == 0) {
NTOHS(odh->query);
@@ -2038,8 +2059,161 @@ reply_ns(struct sreply *sreply, ddDB *db)
else if (odh->nsrr)
odh->nsrr = htons(ns_count + 1);
}
+
+ if (delegation) {
+ rbt0 = get_soa(db, q);
+ if (rbt0 == NULL) {
+ free(rbt1);
+ return -1;
+ }
+
+ nrbt = find_nsec3_match_qname(rbt1->zone, rbt1->zonelen, rbt0, db);
+ if (nrbt != NULL) {
+ tmplen = additional_nsec3(nrbt->zone, nrbt->zonelen, DNS_TYPE_NSEC3, nrbt, reply, replysize, outlen);
+
+ if (tmplen == 0) {
+ NTOHS(odh->query);
+ SET_DNS_TRUNCATION(odh);
+ HTONS(odh->query);
+ odh->answer = 0;
+ odh->nsrr = 0;
+ odh->additional = 0;
+ outlen = rollback;
+ goto out;
+ }
+
+ outlen = tmplen;
+
+ /* additional_nsec3 adds an RRSIG automatically */
+ if (delegation) {
+ NTOHS(odh->nsrr);
+ odh->nsrr += 2;
+ HTONS(odh->nsrr);
+ } else {
+ NTOHS(odh->answer);
+ odh->answer += 2;
+ HTONS(odh->answer);
+ }
+
+ free(nrbt);
+ }
+
+ free(rbt0);
+ }
}
+ if (delegation)
+ free(rbt1);
+
+ /* tack on additional A or AAAA records */
+
+ SLIST_FOREACH(ad0, &addishead, addis_entries) {
+ addiscount = 0;
+ rbt0 = Lookup_zone(db, ad0->name, ad0->namelen, htons(DNS_TYPE_AAAA), 0);
+ if (rbt0 != NULL && find_rr(rbt0, DNS_TYPE_AAAA) != NULL) {
+ tmplen = additional_aaaa(ad0->name, ad0->namelen, rbt0, reply, replysize, outlen, &addiscount);
+ if (tmplen == 0) {
+ NTOHS(odh->query);
+ SET_DNS_TRUNCATION(odh);
+ HTONS(odh->query);
+ odh->answer = 0;
+ odh->nsrr = 0;
+ odh->additional = 0;
+ outlen = rollback;
+ goto out;
+ }
+
+ outlen = tmplen;
+ NTOHS(odh->additional);
+ odh->additional += addiscount;
+ HTONS(odh->additional);
+
+ /* additional RRSIG for the additional AAAA */
+ if (dnssec && q->dnssecok && rbt0->dnssec) {
+ tmplen = additional_rrsig(ad0->name, ad0->namelen, DNS_TYPE_AAAA, rbt0, reply, replysize, outlen, 0);
+
+ if (tmplen == 0) {
+ NTOHS(odh->query);
+ SET_DNS_TRUNCATION(odh);
+ HTONS(odh->query);
+ odh->answer = 0;
+ odh->nsrr = 0;
+ odh->additional = 0;
+ outlen = rollback;
+ goto out;
+ }
+
+ NTOHS(odh->additional);
+ odh->additional += 1;
+ HTONS(odh->additional);
+
+ outlen = tmplen;
+ }
+
+ free(rbt0);
+ rbt0 = NULL;
+ }
+
+ if (rbt0)
+ free(rbt0);
+
+ addiscount = 0;
+ rbt0 = Lookup_zone(db, ad0->name, ad0->namelen, htons(DNS_TYPE_A), 0);
+ if (rbt0 != NULL && find_rr(rbt0, DNS_TYPE_A) != NULL) {
+ tmplen = additional_a(ad0->name, ad0->namelen, rbt0, reply, replysize, outlen, &addiscount);
+ if (tmplen == 0) {
+ NTOHS(odh->query);
+ SET_DNS_TRUNCATION(odh);
+ HTONS(odh->query);
+ odh->answer = 0;
+ odh->nsrr = 0;
+ odh->additional = 0;
+ outlen = rollback;
+ goto out;
+ }
+
+ outlen = tmplen;
+ NTOHS(odh->additional);
+ odh->additional += addiscount;
+ HTONS(odh->additional);
+
+ /* additional RRSIG for the additional A RR */
+ if (dnssec && q->dnssecok && rbt0->dnssec) {
+ tmplen = additional_rrsig(ad0->name, ad0->namelen, DNS_TYPE_A, rbt0, reply, replysize, outlen, 0);
+
+ if (tmplen == 0) {
+ NTOHS(odh->query);
+ SET_DNS_TRUNCATION(odh);
+ HTONS(odh->query);
+ odh->answer = 0;
+ odh->nsrr = 0;
+ odh->additional = 0;
+ outlen = rollback;
+ goto out;
+ }
+
+ NTOHS(odh->additional);
+ odh->additional += 1;
+ HTONS(odh->additional);
+
+ outlen = tmplen;
+ }
+
+ free(rbt0);
+ rbt0 = NULL;
+ }
+
+ if (rbt0)
+ free(rbt0);
+ }
+
+ while (!SLIST_EMPTY(&addishead)) { /* clean up */
+ ad1 = SLIST_FIRST(&addishead);
+ SLIST_REMOVE_HEAD(&addishead, addis_entries);
+ free(ad1);
+ }
+
+
out:
if (q->edns0len) {
/* tag on edns0 opt record */
@@ -5094,14 +5268,14 @@ Lookup_zone(ddDB *db, char *name, u_int16_t namelen, u
fakequestion = build_fake_question(name, namelen, type, NULL, 0);
if (fakequestion == 0) {
dolog(LOG_INFO, "fakequestion(2) failed\n");
- return (0);
+ return (NULL);
}
rbt = lookup_zone(db, fakequestion, &mytype, &lzerrno, (char *)&fakereplystring);
if (rbt == 0) {
free_question(fakequestion);
- return (0);
+ return (NULL);
}
free_question(fakequestion);
@@ -6395,4 +6569,47 @@ int
reply_nodata(struct sreply *sreply, ddDB *db)
{
return (reply_noerror(sreply, db));
+}
+
+
+/*
+ * GET_NS - walk to delegation name
+ */
+
+struct rbtree *
+get_ns(ddDB *db, struct rbtree *rbt, int *delegation)
+{
+ struct rrset *rrset = NULL;
+ struct rbtree *rbt0;
+ char *p;
+ int len;
+
+ if ((rrset = find_rr(rbt, DNS_TYPE_SOA)) == NULL) {
+ *delegation = 1;
+ } else {
+ *delegation = 0;
+ return (rbt);
+ }
+
+ p = rbt->zone;
+ len = rbt->zonelen;
+
+ while (*p && len > 0) {
+ rbt0 = Lookup_zone(db, p, len, DNS_TYPE_NS, 0);
+ if (rbt0 == NULL) {
+ p += (*p + 1);
+ len -= (*p + 1);
+
+ continue;
+ } else
+ break;
+ }
+
+ if ((rrset = find_rr(rbt0, DNS_TYPE_SOA)) != NULL) {
+ *delegation = 0;
+ free(rbt0);
+ return (rbt);
+ }
+
+ return (rbt0);
}
blob - 5e4e6e13eeb44ad5abd1ae2e42db99ff220c9e19
blob + 3df06b346a8c250b82ca5c2208d41870d7c84dd1
--- util.c
+++ util.c
@@ -27,7 +27,7 @@
*/
/*
- * $Id: util.c,v 1.39 2019/10/25 10:24:49 pjp Exp $
+ * $Id: util.c,v 1.40 2019/10/30 12:14:36 pjp Exp $
*/
#include <sys/types.h>
@@ -283,8 +283,7 @@ lookup_zone(ddDB *db, struct question *question, int *
{
struct rbtree *rbt = NULL;
- struct rrset *rrset = NULL;
- struct rr *rrp = NULL;
+ struct rrset *rrset = NULL, *rrset2 = NULL;
int plen, error;
char *p;
@@ -293,8 +292,9 @@ lookup_zone(ddDB *db, struct question *question, int *
plen = question->hdr->namelen;
*returnval = 0;
+ /* if the find_rrset fails, the find_rr will not get questioned */
if ((rbt = find_rrset(db, p, plen)) == NULL ||
- (rrset = find_rr(rbt, DNS_TYPE_NSEC3)) != NULL) {
+ (rbt->dnssec && (rrset = find_rr(rbt, DNS_TYPE_NSEC3)) != NULL)) {
if (check_ent(p, plen) == 1) {
*lzerrno = ERR_NODATA;
*returnval = -1;
@@ -305,7 +305,7 @@ lookup_zone(ddDB *db, struct question *question, int *
return NULL;
}
-
+
if (rrset != NULL)
free(rbt);
@@ -326,6 +326,12 @@ lookup_zone(ddDB *db, struct question *question, int *
*returnval = -1;
return (rbt);
}
+
+ if ((rrset = find_rr(rbt, DNS_TYPE_NS)) != NULL) {
+ *lzerrno = ERR_DELEGATE;
+ *returnval = -1;
+ return (rbt);
+ }
free(rbt);
}
@@ -337,14 +343,11 @@ lookup_zone(ddDB *db, struct question *question, int *
snprintf(replystring, DNS_MAXNAME, "%s", rbt->humanname);
- if ((rrset = find_rr(rbt, DNS_TYPE_NS)) != NULL) {
- if ((rrp = TAILQ_FIRST(&rrset->rr_head)) != NULL) {
- if (((struct ns *)(rrp->rdata))->ns_type > 0) {
- *returnval = DNS_TYPE_NS;
- *lzerrno = ERR_NOERROR;
- return (rbt);
- }
- }
+ if ((rrset = find_rr(rbt, DNS_TYPE_NS)) != NULL &&
+ (rrset2 = find_rr(rbt, DNS_TYPE_SOA)) == NULL) {
+ *returnval = -1;
+ *lzerrno = ERR_DELEGATE;
+ return (rbt);
}
*returnval = check_qtype(rbt, ntohs(question->hdr->qtype), 0, &error);
@@ -368,7 +371,7 @@ lookup_zone(ddDB *db, struct question *question, int *
u_int16_t
check_qtype(struct rbtree *rbt, u_int16_t type, int nxdomain, int *error)
{
- u_int16_t returnval;
+ u_int16_t returnval = -1;
switch (type) {
repomaster@centroid.eu