Commit Diff
Diff:
742ca023b125d68f1d622751bd567f0e4eeddaca
8173bff1605fe24b05d34c24a3825d1b5e5dbde9
Commit:
8173bff1605fe24b05d34c24a3825d1b5e5dbde9
Tree:
23c071c40e7c883d1c604abb830aa0fa0dcb9931
Author:
pjp <pjp@delphinusdns.org>
Committer:
pjp <pjp@delphinusdns.org>
Date:
Wed Nov 27 09:29:37 2019 UTC
Message:
Per user request (PiRATA who has been very kind in feedback), allow multiple TXT's to be replied and massaged (dddctl) tested on OpenBSD (kite and trapezoid in production)
blob - b257f72eefe3ab84b2f400cbed9aba0ec397d6de
blob + 8107140e9a061fe2ab13bb34c2a375ee4a3780ee
--- CHANGES
+++ CHANGES
@@ -23,6 +23,8 @@ Changes in RELEASE_1_4 from RELEASE_1_3
which it did not do before.
- fixed referrer NS code with plain subzones incorporating some DNSSEC elements
- remote logging (which was added in BETA_7) has been removed
+- last minute change: teach delphinusdnsd and dddctl to answer multiple TXT's
+ per domain name.
Changes in RELEASE_1_3 from RELEASE_1_2
blob - 1fae1214a9c0b33544d6c63c440f56e79e48d17c
blob + a566b2cb178ceab4a9cc2597edc4478cdcffd623
--- dddctl.c
+++ dddctl.c
@@ -27,7 +27,7 @@
*/
/*
- * $Id: dddctl.c,v 1.89 2019/11/14 18:07:58 pjp Exp $
+ * $Id: dddctl.c,v 1.90 2019/11/27 09:29:37 pjp Exp $
*/
#include <sys/param.h>
@@ -2059,7 +2059,7 @@ int
sign_txt(ddDB *db, char *zonename, struct keysentry *zsk_key, int expiry, struct rbtree *rbt)
{
struct rrset *rrset = NULL;
- struct rr *rrp = NULL;
+ struct rr *rrp = NULL, *rrp2 = NULL;
char tmp[4096];
char signature[4096];
@@ -2067,8 +2067,8 @@ sign_txt(ddDB *db, char *zonename, struct keysentry *z
char *dnsname;
- char *p;
- char *key;
+ char *p, *q;
+ char *key, *tmpkey = NULL;
char *zone;
uint32_t ttl;
@@ -2087,6 +2087,16 @@ sign_txt(ddDB *db, char *zonename, struct keysentry *z
struct tm tm;
u_int32_t expiredon2, signedon2;
+ TAILQ_HEAD(listhead, canonical) head;
+
+ struct canonical {
+ char *data;
+ int len;
+ TAILQ_ENTRY(canonical) entries;
+ } *c1, *c2, *cp;
+
+ TAILQ_INIT(&head);
+
memset(&shabuf, 0, sizeof(shabuf));
key = malloc(10 * 4096);
@@ -2095,6 +2105,13 @@ sign_txt(ddDB *db, char *zonename, struct keysentry *z
return -1;
}
+ tmpkey = malloc(10 * 4096);
+ if (tmpkey == NULL) {
+ dolog(LOG_INFO, "tmpkey out of memory\n");
+ return -1;
+ }
+
+
/* get the ZSK */
if ((zone = get_key(zsk_key, &ttl, &flags, &protocol, &algorithm, (char *)&tmp, sizeof(tmp), &keyid)) == NULL) {
dolog(LOG_INFO, "get_key %s\n", zsk_key->keyname);
@@ -2166,22 +2183,67 @@ sign_txt(ddDB *db, char *zonename, struct keysentry *z
pack(p, dnsname, labellen);
p += labellen;
- /* no signature here */
- /* XXX this should probably be done on a canonical sorted records */
+ TAILQ_FOREACH(rrp2, &rrset->rr_head, entries) {
+ q = tmpkey;
+ pack(q, rbt->zone, rbt->zonelen);
+ q += rbt->zonelen;
+ pack16(q, htons(DNS_TYPE_TXT));
+ q += 2;
+ pack16(q, htons(DNS_CLASS_IN));
+ q += 2;
+ /* the below uses rrp! because we can't have an rrsig differ */
+ pack32(q, htonl(((struct txt *)rrp->rdata)->ttl));
+ q += 4;
+ pack16(q, htons(((struct txt *)rrp2->rdata)->txtlen));
+ q += 2;
+ pack(q, (char *)((struct txt *)rrp2->rdata)->txt, ((struct txt *)rrp2->rdata)->txtlen);
+ q += ((struct txt *)rrp2->rdata)->txtlen;
- pack(p, rbt->zone, rbt->zonelen);
- p += rbt->zonelen;
- pack16(p, htons(DNS_TYPE_TXT));
- p += 2;
- pack16(p, htons(DNS_CLASS_IN));
- p += 2;
- pack32(p, htonl(((struct txt *)rrp->rdata)->ttl));
- p += 4;
- pack16(p, htons(((struct txt *)rrp->rdata)->txtlen));
- p += 2;
- pack(p, ((struct txt *)rrp->rdata)->txt, ((struct txt *)rrp->rdata)->txtlen);
- p += ((struct txt *)rrp->rdata)->txtlen;
+ c1 = malloc(sizeof(struct canonical));
+ if (c1 == NULL) {
+ dolog(LOG_INFO, "c1 out of memory\n");
+ return -1;
+ }
+ c1->len = (q - tmpkey);
+ c1->data = malloc(c1->len);
+ if (c1->data == NULL) {
+ dolog(LOG_INFO, "c1->data out of memory\n");
+ return -1;
+ }
+
+ memcpy(c1->data, tmpkey, c1->len);
+
+ if (TAILQ_EMPTY(&head))
+ TAILQ_INSERT_TAIL(&head, c1, entries);
+ else {
+ TAILQ_FOREACH(c2, &head, entries) {
+ if (c1->len < c2->len)
+ break;
+ else if (c2->len == c1->len &&
+ memcmp(c1->data, c2->data, c1->len) < 0)
+ break;
+ }
+
+ if (c2 != NULL)
+ TAILQ_INSERT_BEFORE(c2, c1, entries);
+ else
+ TAILQ_INSERT_TAIL(&head, c1, entries);
+ }
+ }
+
+#ifdef __linux__
+ TAILQ_FOREACH(c2, &head, entries) {
+#else
+ TAILQ_FOREACH_SAFE(c2, &head, entries, cp) {
+#endif
+ pack(p, c2->data, c2->len);
+ p += c2->len;
+
+ TAILQ_REMOVE(&head, c2, entries);
+ }
+
+
keylen = (p - key);
#if 0
@@ -6082,17 +6144,19 @@ print_rbt(FILE *of, struct rbtree *rbt)
dolog(LOG_INFO, "no txt in zone!\n");
return -1;
}
- fprintf(of, " %s,txt,%d,\"",
- convert_name(rbt->zone, rbt->zonelen),
- ((struct txt *)rrp->rdata)->ttl);
+ TAILQ_FOREACH(rrp2, &rrset->rr_head, entries) {
+ fprintf(of, " %s,txt,%d,\"",
+ convert_name(rbt->zone, rbt->zonelen),
+ ((struct txt *)rrp->rdata)->ttl);
- for (i = 0; i < ((struct txt *)rrp->rdata)->txtlen; i++) {
- if (i % 256 == 0)
- continue;
+ for (i = 0; i < ((struct txt *)rrp2->rdata)->txtlen; i++) {
+ if (i % 256 == 0)
+ continue;
- fprintf(of, "%c", ((struct txt *)rrp->rdata)->txt[i]);
+ fprintf(of, "%c", ((struct txt *)rrp2->rdata)->txt[i]);
+ }
+ fprintf(of, "\"\n");
}
- fprintf(of, "\"\n");
}
if ((rrset = find_rr(rbt, DNS_TYPE_PTR)) != NULL) {
if ((rrp = TAILQ_FIRST(&rrset->rr_head)) == NULL) {
@@ -7396,20 +7460,22 @@ print_rbt_bind(FILE *of, struct rbtree *rbt)
}
if ((rrset = find_rr(rbt, DNS_TYPE_TXT)) != NULL) {
if ((rrp = TAILQ_FIRST(&rrset->rr_head)) == NULL) {
- dolog(LOG_INFO, "no ds in zone!\n");
+ dolog(LOG_INFO, "no txt in zone!\n");
return -1;
}
- fprintf(of, "%s %d IN TXT \"",
- convert_name(rbt->zone, rbt->zonelen),
- ((struct txt *)rrp->rdata)->ttl);
-
- for (i = 0; i < ((struct txt *)rrp->rdata)->txtlen; i++) {
- if (i % 256 == 0)
- continue;
+ TAILQ_FOREACH(rrp2, &rrset->rr_head, entries) {
+ fprintf(of, "%s %d IN TXT \"",
+ convert_name(rbt->zone, rbt->zonelen),
+ ((struct txt *)rrp->rdata)->ttl);
+
+ for (i = 0; i < ((struct txt *)rrp2->rdata)->txtlen; i++) {
+ if (i % 256 == 0)
+ continue;
- fprintf(of, "%c", ((struct txt *)rrp->rdata)->txt[i]);
+ fprintf(of, "%c", ((struct txt *)rrp2->rdata)->txt[i]);
+ }
+ fprintf(of, "\"\n");
}
- fprintf(of, "\"\n");
}
if ((rrset = find_rr(rbt, DNS_TYPE_PTR)) != NULL) {
if ((rrp = TAILQ_FIRST(&rrset->rr_head)) == NULL) {
blob - a0d167cc173343a5e73cddbe3fd0cb2b4515d470
blob + 6d2e15612e00b62e6136ef6db8f492c0bcee417c
--- reply.c
+++ reply.c
@@ -27,7 +27,7 @@
*/
/*
- * $Id: reply.c,v 1.93 2019/11/19 14:15:51 pjp Exp $
+ * $Id: reply.c,v 1.94 2019/11/27 09:29:37 pjp Exp $
*/
#include <sys/types.h>
@@ -3230,6 +3230,7 @@ reply_txt(struct sreply *sreply, ddDB *db)
int replysize = 512;
int retlen = -1;
u_int16_t rollback;
+ int txt_count = 0;
if ((rrset = find_rr(rbt, DNS_TYPE_TXT)) == 0)
return -1;
@@ -3250,10 +3251,6 @@ reply_txt(struct sreply *sreply, ddDB *db)
return (retlen);
}
- rrp = TAILQ_FIRST(&rrset->rr_head);
- if (rrp == 0)
- return -1;
-
/* copy question to reply */
memcpy(reply, buf, sizeof(struct dns_header) + q->hdr->namelen + 4);
/* blank query */
@@ -3279,33 +3276,49 @@ reply_txt(struct sreply *sreply, ddDB *db)
answer = (struct answer *)(&reply[0] + sizeof(struct dns_header) +
q->hdr->namelen + 4);
- answer->name[0] = 0xc0;
- answer->name[1] = 0x0c;
- answer->type = q->hdr->qtype;
- answer->class = q->hdr->qclass;
- answer->ttl = htonl(((struct txt *)rrp->rdata)->ttl);
+ txt_count = 0;
- outlen += 12; /* up to rdata length */
+ TAILQ_FOREACH(rrp, &rrset->rr_head, entries) {
+ /*
+ * answer->name is a pointer to the request (0xc00c)
+ */
- p = (char *)&answer->rdata;
+ answer->name[0] = 0xc0; /* 1 byte */
+ answer->name[1] = 0x0c; /* 2 bytes */
+ answer->type = q->hdr->qtype; /* 4 bytes */
+ answer->class = q->hdr->qclass; /* 6 bytes */
+ answer->ttl = htonl(((struct txt *)rrp->rdata)->ttl); /* 10 b */
- memcpy(p, ((struct txt *)rrp->rdata)->txt, ((struct txt *)rrp->rdata)->txtlen);
- outlen += (((struct txt *)rrp->rdata)->txtlen);
+ /* 12 bytes */
+ answer->rdlength = htons(((struct txt *)rrp->rdata)->txtlen);
+ outlen += 12;
- answer->rdlength = htons(((struct txt *)rrp->rdata)->txtlen);
+ p = (char *)&answer->rdata;
- /* check if we can even fit */
- if (outlen > replysize) {
- NTOHS(odh->query);
- SET_DNS_TRUNCATION(odh);
- HTONS(odh->query);
- odh->answer = 0;
- odh->nsrr = 0;
- odh->additional = 0;
- outlen = rollback;
- goto out;
- }
+ memcpy(p, ((struct txt *)rrp->rdata)->txt, ((struct txt *)rrp->rdata)->txtlen);
+ outlen += (((struct txt *)rrp->rdata)->txtlen);
+ txt_count++;
+
+ /* can we afford to write more, if no truncate */
+ if (outlen > replysize) {
+ NTOHS(odh->query);
+ SET_DNS_TRUNCATION(odh);
+ HTONS(odh->query);
+ odh->answer = 0;
+ odh->nsrr = 0;
+ odh->additional = 0;
+ outlen = rollback;
+ goto out;
+ }
+
+
+ /* set new offset for answer */
+ answer = (struct answer *)&reply[outlen];
+ }
+
+ odh->answer = htons(txt_count);
+
/* Add RRSIG reply_txt */
if (dnssec && q->dnssecok && (rbt->flags & RBT_DNSSEC)) {
int tmplen = 0;
@@ -5549,6 +5562,7 @@ u_int16_t
create_anyreply(struct sreply *sreply, char *reply, int rlen, int offset, int soa)
{
int a_count, aaaa_count, ns_count, mx_count, srv_count, sshfp_count;
+ int txt_count;
int tlsa_count, typelen;
int ds_count, dnskey_count;
int naptr_count, rrsig_count;
@@ -6185,43 +6199,50 @@ create_anyreply(struct sreply *sreply, char *reply, in
}
if ((rrset = find_rr(rbt, DNS_TYPE_TXT)) != 0) {
- rrp = TAILQ_FIRST(&rrset->rr_head);
- if (rrp == 0)
- return -1;
+ txt_count = 0;
+ TAILQ_FOREACH(rrp, &rrset->rr_head, entries) {
- NTOHS(odh->answer);
- odh->answer++;
- HTONS(odh->answer);
+ if ((offset + q->hdr->namelen) > rlen) {
+ goto truncate;
+ }
- if ((offset + q->hdr->namelen) > rlen) {
- goto truncate;
- }
+ memcpy(&reply[offset], q->hdr->name, q->hdr->namelen);
+ offset += q->hdr->namelen;
- memcpy(&reply[offset], q->hdr->name, q->hdr->namelen);
- offset += q->hdr->namelen;
+ if ((tmplen = compress_label((u_char*)reply, offset, q->hdr->namelen)) > 0) {
+ offset = tmplen;
+ }
- if ((tmplen = compress_label((u_char*)reply, offset, q->hdr->namelen)) > 0) {
- offset = tmplen;
- }
+ answer = (struct answer *)&reply[offset];
- answer = (struct answer *)&reply[offset];
- answer->type = htons(DNS_TYPE_TXT);
- answer->class = htons(DNS_CLASS_IN);
- answer->ttl = htonl(((struct txt *)rrp->rdata)->ttl);
+ if (offset + 10 > rlen)
+ goto truncate;
- offset += 10; /* up to rdata length */
+ answer->type = htons(DNS_TYPE_TXT);
+ answer->class = htons(DNS_CLASS_IN);
+ answer->ttl = htonl(((struct txt *)rrp->rdata)->ttl);
- if (offset + ((struct txt *)rrp->rdata)->txtlen > rlen)
- goto truncate;
+ offset += 10; /* up to rdata length */
- p = (char *)&answer->rdata;
- memcpy(p, ((struct txt *)rrp->rdata)->txt, ((struct txt *)rrp->rdata)->txtlen);
- offset += (((struct txt *)rrp->rdata)->txtlen);
+ if (offset + ((struct txt *)rrp->rdata)->txtlen > rlen)
+ goto truncate;
- answer->rdlength = htons(((struct txt *)rrp->rdata)->txtlen);
+ p = (char *)&answer->rdata;
+ memcpy(p, ((struct txt *)rrp->rdata)->txt, ((struct txt *)rrp->rdata)->txtlen);
+ offset += (((struct txt *)rrp->rdata)->txtlen);
+ answer->rdlength = htons(((struct txt *)rrp->rdata)->txtlen);
+
+ txt_count++;
+
+ }
+
+ NTOHS(odh->answer);
+ odh->answer += txt_count;
+ HTONS(odh->answer);
}
+
if ((rrset = find_rr(rbt, DNS_TYPE_TLSA)) != 0) {
tlsa_count = 0;
repomaster@centroid.eu