Commit Diff
Diff:
6880491c558b73e81a54df9b55b15de209a3ffe9
f60513d62db728d489741251fcfb902e3c4624b4
Commit:
f60513d62db728d489741251fcfb902e3c4624b4
Tree:
db7e21141d0af023dd9c9373f67f1628d07fa8e3
Author:
pjp <pjp@delphinusdns.org>
Committer:
pjp <pjp@delphinusdns.org>
Date:
Fri Jul 3 06:49:57 2020 UTC
Message:
BIG COMMIT TIME - this work pertains to the FORWARD process - add one log to additional_tsig() - add dup sockets, these are UDP duplicates and are created in the same order as the udp sockets, but they do a shutdown(.., SHUT_RD) so they can't read, this is to prevent them from getting network traffic, they are only for replying for the FORWARD process. - remove struct forward from ddd-db.h and move it to struct sforward in ddd-dns.h - add a tsigoffset in struct tsig, this will help in stripping TSIG RR's from an authenticated reply. - add a zonecount variable which counts how many zones we have, if it's 0 a series of checks get skipped at startup. (such as determine_glue() and init_entlist() - make sure that forward is an integer and struct forward is called sforward - in the lookup logic when we reply NO_DATA skip to FORWARD when we were going to reply REFUSED, becuase we can only be UNDER some internal zones. We did goto's in this case forwardudp/forwardtcp. - make sure we write the forward imsg to the cortex not the cortex control. - many many changes to forward.c, most significant would likely be check_tsig() which is based on build_question(), which skips all RR's in a reply and then authenticates the TSIG filling a returning tsig struct. - in util.c lookup_zone logic have some short circuits if we have forwarding turned on. ie. if zonecount == 0 only forward.
blob - 7ebc8a7fa37972731a10180cad6d2a35350fa803
blob + 003e0cea233a772dbb720680fc6821ceea251651
--- additional.c
+++ additional.c
@@ -27,7 +27,7 @@
*/
/*
- * $Id: additional.c,v 1.35 2020/05/07 12:17:35 pjp Exp $
+ * $Id: additional.c,v 1.36 2020/07/03 06:49:57 pjp Exp $
*/
#include <sys/types.h>
@@ -41,6 +41,8 @@
#include <stdlib.h>
#include <string.h>
+#include <syslog.h>
+
#ifdef __linux__
#include <grp.h>
#define __USE_BSD 1
@@ -90,8 +92,10 @@ 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 find_tsig_key(char *, int, char *, int);
+extern void dolog(int, char *, ...);
+
extern int dnssec;
@@ -477,6 +481,8 @@ additional_tsig(struct question *question, char *reply
if ((offset + 2 + 8 + 2 + question->tsig.tsigmaclen +
question->tsig.tsigkeylen +
question->tsig.tsigalglen + 2 + 2 + 4) > replylen) {
+ dolog(LOG_ERR, "additional_tsig: is bigger than replylen\n");
+ offset = rollback;
goto out;
}
blob - 8b5218a5f1d570ccc0e8dc520f118e48d2468296
blob + 05e3e5ccc9f772d4b755f670653e6ae736d57ddd
--- ddd-db.h
+++ ddd-db.h
@@ -27,7 +27,7 @@
*/
/*
- * $Id: ddd-db.h,v 1.37 2020/07/01 05:07:47 pjp Exp $
+ * $Id: ddd-db.h,v 1.38 2020/07/03 06:49:57 pjp Exp $
*/
#ifndef _DB_H
@@ -336,6 +336,7 @@ struct cfg {
int udp[DEFAULT_SOCKET]; /* udp sockets */
int tcp[DEFAULT_SOCKET]; /* tcp socket */
int axfr[DEFAULT_SOCKET]; /* axfr udp socket */
+ int dup[DEFAULT_SOCKET]; /* dup sockets */
char *ident[DEFAULT_SOCKET]; /* identification of interface */
struct my_imsg {
int imsg_fds[2];
@@ -419,13 +420,6 @@ struct raxfr_logic {
int rrtype;
int dnssec;
int (*raxfr)(FILE *, u_char *, u_char *, u_char *, struct soa *, u_int16_t, HMAC_CTX *);
-};
-
-struct forward {
- struct sockaddr_storage from;
- uint16_t rport;
- char buf[4000]; /* the maximum payload of an imsg is 0xffff */
- int buflen;
};
#endif /* _DB_H */
blob - 9b9d3680b94ee5b5ca9238f841e5ce472ba525c3
blob + 99767a3a2328070799bc8b21149dd4691c7c3e8e
--- ddd-dns.h
+++ ddd-dns.h
@@ -27,7 +27,7 @@
*/
/*
- * $Id: ddd-dns.h,v 1.16 2020/06/28 08:59:30 pjp Exp $
+ * $Id: ddd-dns.h,v 1.17 2020/07/03 06:49:57 pjp Exp $
*/
#ifndef _DNS_H
@@ -254,6 +254,7 @@ struct tsig {
int tsigmaclen;
u_int64_t tsig_timefudge;
u_int16_t tsigorigid;
+ int tsigoffset;
};
#define DEFAULT_TSIG_FUDGE 300
@@ -293,6 +294,29 @@ struct parsequestion {
pid_t pid; /* originating pid */
};
+struct sforward {
+ int family;
+
+ struct sockaddr_in from4;
+ struct sockaddr_in6 from6;
+
+ int oldsel;
+ uint16_t rport;
+ char buf[512];
+ int buflen;
+ struct dns_header header;
+ uint16_t type;
+ uint16_t class;
+ uint16_t edns0len;
+
+ int havemac;
+ char tsigname[256];
+ int tsignamelen;
+ uint64_t tsigtimefudge;
+
+ char mac[32];
+};
+
blob - 9456046f18c0fb520fb88c817a0fb3f2795111d4
blob + 1c2080bccd6b372a6d2438edb322d18b715c62ed
--- dddctl.c
+++ dddctl.c
@@ -27,7 +27,7 @@
*/
/*
- * $Id: dddctl.c,v 1.108 2020/07/01 05:07:47 pjp Exp $
+ * $Id: dddctl.c,v 1.109 2020/07/03 06:49:57 pjp Exp $
*/
#include <sys/types.h>
@@ -83,6 +83,7 @@ int debug = 0;
int verbose = 0;
int forward = 0;
int forwardtsig = 0;
+int zonecount = 0;
extern int dnssec;
extern int bytes_received;
blob - e970fa2ecfb54b6e49bd82a34e149221b59b7436
blob + 2d672a2641a4f9f70f3f6a55bda9c8a3f63105ee
--- delphinusdnsd.c
+++ delphinusdnsd.c
@@ -27,7 +27,7 @@
*/
/*
- * $Id: delphinusdnsd.c,v 1.109 2020/07/01 05:07:47 pjp Exp $
+ * $Id: delphinusdnsd.c,v 1.110 2020/07/03 06:49:57 pjp Exp $
*/
@@ -278,6 +278,7 @@ int bcount = 0;
int icount = 0;
int forward = 0;
int forwardtsig = 0;
+int zonecount = 0;
u_int16_t port = 53;
u_int32_t cachesize = 0;
char *bind_list[255];
@@ -301,6 +302,7 @@ int
main(int argc, char *argv[], char *environ[])
{
static int udp[DEFAULT_SOCKET];
+ static int dup[DEFAULT_SOCKET];
static int tcp[DEFAULT_SOCKET];
static int afd[DEFAULT_SOCKET];
static int uafd[DEFAULT_SOCKET];
@@ -553,13 +555,13 @@ main(int argc, char *argv[], char *environ[])
exit(1);
}
- if (determine_glue(db) < 0) {
+ if (zonecount && determine_glue(db) < 0) {
dolog(LOG_INFO, "determine_glue() failed\n");
ddd_shutdown();
exit(1);
}
- if (init_entlist(db) < 0) {
+ if (zonecount && init_entlist(db) < 0) {
dolog(LOG_INFO, "creating entlist failed\n");
ddd_shutdown();
exit(1);
@@ -614,11 +616,42 @@ main(int argc, char *argv[], char *environ[])
res = res0;
+ if ((dup[i] = socket(res->ai_family, res->ai_socktype, res->ai_protocol)) < 0) {
+ dolog(LOG_INFO, "dup socket: %s\n", strerror(errno));
+ ddd_shutdown();
+ exit(1);
+ }
+
+ on = 1;
+ if (setsockopt(dup[i], SOL_SOCKET, SO_REUSEPORT,
+ &on, sizeof(on)) < 0) {
+ dolog(LOG_INFO, "setsockopt: %s\n", strerror(errno));
+ }
+
+ if (shutdown(dup[i], SHUT_RD) < 0) {
+ dolog(LOG_INFO, "shutdown: %s\n", strerror(errno));
+ ddd_shutdown();
+ exit(1);
+ }
+
+ if (bind(dup[i], res->ai_addr, res->ai_addrlen) < 0) {
+ dolog(LOG_INFO, "bind: %s\n", strerror(errno));
+ ddd_shutdown();
+ exit(1);
+ }
+
+
if ((udp[i] = socket(res->ai_family, res->ai_socktype, res->ai_protocol)) < 0) {
dolog(LOG_INFO, "socket: %s\n", strerror(errno));
ddd_shutdown();
exit(1);
}
+
+ on = 1;
+ if (setsockopt(udp[i], SOL_SOCKET, SO_REUSEPORT,
+ &on, sizeof(on)) < 0) {
+ dolog(LOG_INFO, "setsockopt: %s\n", strerror(errno));
+ }
if (bind(udp[i], res->ai_addr, res->ai_addrlen) < 0) {
dolog(LOG_INFO, "bind: %s\n", strerror(errno));
@@ -632,11 +665,6 @@ main(int argc, char *argv[], char *environ[])
&on, sizeof(on)) < 0) {
dolog(LOG_INFO, "setsockopt: %s\n", strerror(errno));
}
- on = 1;
- if (setsockopt(udp[i], SOL_SOCKET, SO_REUSEPORT,
- &on, sizeof(on)) < 0) {
- dolog(LOG_INFO, "setsockopt: %s\n", strerror(errno));
- }
} else if (res->ai_family == AF_INET6) {
/* RFC 3542 page 30 */
on = 1;
@@ -644,11 +672,6 @@ main(int argc, char *argv[], char *environ[])
IPV6_RECVHOPLIMIT, &on, sizeof(on)) < 0) {
dolog(LOG_INFO, "setsockopt: %s\n", strerror(errno));
}
- on = 1;
- if (setsockopt(udp[i], SOL_SOCKET, SO_REUSEPORT,
- &on, sizeof(on)) < 0) {
- dolog(LOG_INFO, "setsockopt: %s\n", strerror(errno));
- }
}
ident[i] = bind_list[i];
@@ -784,11 +807,43 @@ main(int argc, char *argv[], char *environ[])
continue;
}
+ if ((dup[i] = socket(pifap->ifa_addr->sa_family, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
+ dolog(LOG_INFO, "dup socket: %s\n", strerror(errno));
+ ddd_shutdown();
+ exit(1);
+ }
+
+ on = 1;
+ if (setsockopt(dup[i], SOL_SOCKET, SO_REUSEPORT,
+ &on, sizeof(on)) < 0) {
+ dolog(LOG_INFO, "setsockopt: %s\n", strerror(errno));
+ }
+
+ if (shutdown(dup[i], SHUT_RD) < 0) {
+ dolog(LOG_INFO, "shutdown: %s\n", strerror(errno));
+ ddd_shutdown();
+ exit(1);
+ }
+
+ if (bind(dup[i], (struct sockaddr *)pifap->ifa_addr, salen) < 0) {
+ dolog(LOG_INFO, "bind: %s\n", strerror(errno));
+ ddd_shutdown();
+ exit(1);
+ }
+
+
if ((udp[i] = socket(pifap->ifa_addr->sa_family, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
dolog(LOG_INFO, "socket: %s\n", strerror(errno));
ddd_shutdown();
exit(1);
}
+
+ on = 1;
+ if (setsockopt(udp[i], SOL_SOCKET, SO_REUSEPORT,
+ &on, sizeof(on)) < 0) {
+ dolog(LOG_INFO, "setsockopt: %s\n", strerror(errno));
+ }
+
if (bind(udp[i], (struct sockaddr *)pifap->ifa_addr, salen) < 0) {
dolog(LOG_INFO, "bind: %s\n", strerror(errno));
@@ -802,11 +857,6 @@ main(int argc, char *argv[], char *environ[])
&on, sizeof(on)) < 0) {
dolog(LOG_INFO, "setsockopt: %s\n", strerror(errno));
}
- on = 1;
- if (setsockopt(udp[i], SOL_SOCKET, SO_REUSEPORT,
- &on, sizeof(on)) < 0) {
- dolog(LOG_INFO, "setsockopt: %s\n", strerror(errno));
- }
} else if (pifap->ifa_addr->sa_family == AF_INET6) {
/* RFC 3542 page 30 */
on = 1;
@@ -814,11 +864,6 @@ main(int argc, char *argv[], char *environ[])
IPV6_RECVHOPLIMIT, &on, sizeof(on)) < 0) {
dolog(LOG_INFO, "setsockopt: %s\n", strerror(errno));
}
- on = 1;
- if (setsockopt(udp[i], SOL_SOCKET, SO_REUSEPORT,
- &on, sizeof(on)) < 0) {
- dolog(LOG_INFO, "setsockopt: %s\n", strerror(errno));
- }
}
@@ -959,6 +1004,8 @@ main(int argc, char *argv[], char *environ[])
close(uafd[j]);
close(afd[j]);
}
+
+ cfg->dup[j] = dup[j];
}
setproctitle("FORWARD engine");
@@ -1136,6 +1183,8 @@ main(int argc, char *argv[], char *environ[])
cfg->axfr[i] = uafd[i];
cfg->ident[i] = strdup(ident[i]);
+
+ close(dup[i]);
}
setproctitle("child %d pid %d", n, cfg->pid);
@@ -1158,6 +1207,7 @@ main(int argc, char *argv[], char *environ[])
cfg->ident[i] = strdup(ident[i]);
+ close(dup[i]);
}
(void)mainloop(cfg, &cortex_ibuf);
@@ -1446,7 +1496,7 @@ mainloop(struct cfg *cfg, struct imsgbuf *ibuf)
fd_set rset;
pid_t pid;
- int sel;
+ int sel, oldsel;
int len, slen = 0;
int is_ipv6;
int i, nomore = 0;
@@ -1504,13 +1554,13 @@ mainloop(struct cfg *cfg, struct imsgbuf *ibuf)
struct imsgbuf *pibuf;
struct imsg imsg;
- struct forward *forward;
+ struct sforward *sforward;
ssize_t n, datalen;
- forward = calloc(1, sizeof(struct forward));
- if (forward == NULL) {
+ sforward = (struct sforward *)calloc(1, sizeof(struct sforward));
+ if (sforward == NULL) {
dolog(LOG_ERR, "calloc: %s\n", strerror(errno));
ddd_shutdown();
exit(1);
@@ -1650,6 +1700,7 @@ mainloop(struct cfg *cfg, struct imsgbuf *ibuf)
if (FD_ISSET(cfg->udp[i], &rset)) {
istcp = 0;
so = cfg->udp[i];
+ oldsel = i;
axfrentry:
fromlen = sizeof(sockaddr_large);
@@ -2015,6 +2066,8 @@ axfrentry:
build_reply(&sreply, so, buf, len, question, from, fromlen, rbt1, rbt0, aregion, istcp, 0, replybuf);
slen = reply_nodata(&sreply, cfg->db);
} else {
+ if (forward)
+ goto forwardudp;
build_reply(&sreply, so, buf, len, question, from, fromlen, rbt1, rbt0, aregion, istcp, 0, replybuf);
slen = reply_refused(&sreply, cfg->db);
snprintf(replystring, DNS_MAXNAME, "REFUSED");
@@ -2023,6 +2076,7 @@ axfrentry:
break;
case ERR_FORWARD:
+forwardudp:
if (forwardtsig) {
if (question->tsig.have_tsig &&
question->tsig.tsigverified) {
@@ -2043,23 +2097,45 @@ axfrentry:
goto udpout;
}
- memcpy(&forward->from, from, fromlen);
+ memset(sforward, 0, sizeof(struct sforward));
+ sforward->oldsel = oldsel;
+
switch (from->sa_family) {
case AF_INET:
- forward->rport = sin->sin_port;
+ sforward->rport = sin->sin_port;
+ memcpy((char *)&sforward->from4, sin, fromlen);
+ sforward->family = AF_INET;
+
break;
case AF_INET6:
- forward->rport = sin6->sin6_port;
+ sforward->rport = sin6->sin6_port;
+ memcpy((char *)&sforward->from6, sin6, fromlen);
+ sforward->family = AF_INET6;
+
break;
}
- memcpy(&forward->buf, buf, len);
- forward->buflen = len;
+ memcpy(&sforward->buf, question->hdr->name, question->hdr->namelen);
+ sforward->buflen = question->hdr->namelen;
+
+ memcpy((char *)&sforward->header, buf, sizeof(struct dns_header));
+ sforward->type = question->hdr->qtype;
+ sforward->class = question->hdr->qclass;
+ sforward->edns0len = question->edns0len;
- imsg_compose(ibuf, IMSG_FORWARD_UDP,
- 0, 0, -1, forward, sizeof(struct forward));
+ if (question->tsig.have_tsig && question->tsig.tsigverified) {
+ sforward->havemac = 1;
+ memcpy((char *)&sforward->tsigname, question->tsig.tsigkey, question->tsig.tsigkeylen);
+ sforward->tsignamelen = question->tsig.tsigkeylen;
+ memcpy(&sforward->mac, question->tsig.tsigmac, sizeof(sforward->mac));
+ sforward->tsigtimefudge = question->tsig.tsig_timefudge;
+ } else
+ sforward->havemac = 0;
- msgbuf_write(&ibuf->w);
+ imsg_compose(udp_ibuf, IMSG_FORWARD_UDP,
+ 0, 0, -1, sforward, sizeof(struct sforward));
+
+ msgbuf_write(&udp_ibuf->w);
goto udpout;
break;
@@ -2523,6 +2599,16 @@ tcploop(struct cfg *cfg, struct imsgbuf *ibuf)
ssize_t n, datalen;
u_int32_t imsg_type;
+ struct sforward *sforward;
+
+
+ sforward = (struct sforward *)calloc(1, sizeof(struct sforward));
+ if (sforward == NULL) {
+ dolog(LOG_ERR, "calloc: %s\n", strerror(errno));
+ ddd_shutdown();
+ exit(1);
+ }
+
if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, PF_UNSPEC, &cfg->my_imsg[MY_IMSG_PARSER].imsg_fds[0]) < 0) {
dolog(LOG_INFO, "socketpair() failed\n");
ddd_shutdown();
@@ -2994,25 +3080,28 @@ tcploop(struct cfg *cfg, struct imsgbuf *ibuf)
goto tcpout;
break;
case ERR_NODATA:
- if (rbt0) {
- free(rbt0);
- rbt0 = NULL;
- }
+ if (rbt0) {
+ free(rbt0);
+ rbt0 = NULL;
+ }
- rbt0 = get_soa(cfg->db, question);
- if (rbt0 != NULL) {
- snprintf(replystring, DNS_MAXNAME, "NODATA");
- build_reply(&sreply, so, pbuf, len, question, from, fromlen, rbt0, NULL, aregion, istcp, 0, replybuf);
- slen = reply_nodata(&sreply, cfg->db);
- } else {
- snprintf(replystring, DNS_MAXNAME, "REFUSED");
- build_reply(&sreply, so, pbuf, len, question, from, fromlen, rbt0, NULL, aregion, istcp, 0, replybuf);
- slen = reply_refused(&sreply, cfg->db);
- }
+ rbt0 = get_soa(cfg->db, question);
+ if (rbt0 != NULL) {
+ snprintf(replystring, DNS_MAXNAME, "NODATA");
+ build_reply(&sreply, so, pbuf, len, question, from, fromlen, rbt0, NULL, aregion, istcp, 0, replybuf);
+ slen = reply_nodata(&sreply, cfg->db);
+ } else {
+ if (forward)
+ goto forwardtcp;
- goto tcpout;
- break;
+ snprintf(replystring, DNS_MAXNAME, "REFUSED");
+ build_reply(&sreply, so, pbuf, len, question, from, fromlen, rbt0, NULL, aregion, istcp, 0, replybuf);
+ slen = reply_refused(&sreply, cfg->db);
+ }
+ goto tcpout;
+ break;
+
case ERR_NXDOMAIN:
snprintf(replystring, DNS_MAXNAME, "NXDOMAIN");
@@ -3030,6 +3119,7 @@ tcploop(struct cfg *cfg, struct imsgbuf *ibuf)
goto tcpout;
case ERR_FORWARD:
+forwardtcp:
if (forwardtsig) {
if (question->tsig.have_tsig &&
question->tsig.tsigverified) {
@@ -3044,11 +3134,71 @@ tcploop(struct cfg *cfg, struct imsgbuf *ibuf)
snprintf(replystring, DNS_MAXNAME, "FORWARD");
/* send query to forward process/cortex */
- imsg_compose(ibuf, IMSG_FORWARD_TCP,
- 0, 0, tcpnp->so, &tcpnp->buf, tcpnp->bytes_read);
+ if (len > 4000) {
+ dolog(LOG_INFO, "question is larger than 4000 bytes, not forwarding\n");
+ goto tcpout;
+ }
+ switch (from->sa_family) {
+ case AF_INET:
+ memcpy(&sforward->from4, from, fromlen);
+ sforward->rport = sin->sin_port;
+ sforward->family = AF_INET;
+ break;
+ case AF_INET6:
+ memcpy(&sforward->from6, from, fromlen);
+ sforward->rport = sin6->sin6_port;
+ sforward->family = AF_INET6;
+ break;
+ }
+
+ memcpy(&sforward->buf, question->hdr->name, question->hdr->namelen);
+ sforward->buflen = question->hdr->namelen;
+
+ memcpy((char *)&sforward->header, pbuf, sizeof(struct dns_header));
+ sforward->type = question->hdr->qtype;
+ sforward->class = question->hdr->qclass;
+
+ sforward->edns0len = question->edns0len;
+
+ if (question->tsig.have_tsig && question->tsig.tsigverified) {
+ sforward->havemac = 1;
+ memcpy((char *)&sforward->tsigname, question->tsig.tsigkey, question->tsig.tsigkeylen);
+ sforward->tsignamelen = question->tsig.tsigkeylen;
+ memcpy(&sforward->mac, question->tsig.tsigmac, sizeof(sforward->mac));
+ sforward->tsigtimefudge = question->tsig.tsig_timefudge;
+ } else
+ sforward->havemac = 0;
+
+ imsg_compose(ibuf, IMSG_FORWARD_TCP,
+ 0, 0, so, sforward, sizeof(struct sforward));
msgbuf_write(&ibuf->w);
- goto tcpout;
+ slen = 0;
+
+ if (lflag)
+ dolog(LOG_INFO, "request on descriptor %u interface \"%s\" from %s (ttl=TCP, region=%d) for \"%s\" type=%s class=%u, %s%s%s answering \"%s\" (%d/%d)\n", so, cfg->ident[tcpnp->intidx], tcpnp->address, aregion, question->converted_name, get_dns_type(ntohs(question->hdr->qtype), 1), ntohs(question->hdr->qclass), (question->edns0len) ? "edns0, " : "", (question->dnssecok) ? "dnssecok, " : "", (question->tsig.tsigverified ? "tsig, " : ""), replystring, len, slen);
+
+ if (fakequestion != NULL) {
+ free_question(fakequestion);
+ }
+
+ free_question(question);
+
+ if (rbt0) {
+ free(rbt0);
+ rbt0 = NULL;
+ }
+ if (rbt1) {
+ free (rbt1);
+ rbt1 = NULL;
+ }
+ TAILQ_REMOVE(&tcphead, tcpnp, tcpentries);
+ close(tcpnp->so);
+ free(tcpnp->address);
+ free(tcpnp);
+ if (conncnt > 0)
+ conncnt--;
+ continue;
break;
case ERR_NOERROR:
@@ -3095,6 +3245,7 @@ tcploop(struct cfg *cfg, struct imsgbuf *ibuf)
} else {
slen = 0;
snprintf(replystring, DNS_MAXNAME, "DROP");
+
}
goto tcpout;
@@ -3272,7 +3423,8 @@ tcploop(struct cfg *cfg, struct imsgbuf *ibuf)
conncnt--;
continue;
- } /* TAILQ_FOREACH */
+
+ } /* TAILQ_FOREACH_SAFE */
/*
* kick off the idlers
@@ -3353,9 +3505,10 @@ parseloop(struct cfg *cfg, struct imsgbuf *ibuf)
datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
require_tsig = 0;
+ memset(&pq, 0, sizeof(struct parsequestion));
+
switch (imsg.hdr.type) {
case IMSG_PARSE_MESSAGE:
- memset(&pq, 0, sizeof(struct parsequestion));
/* XXX magic numbers */
if (datalen > 16384) {
@@ -3874,6 +4027,11 @@ setup_cortex(struct imsgbuf *ibuf)
exit(1);
}
+#if 0
+ /* reopenlog */
+ openlog(__progname, LOG_PID | LOG_NDELAY, LOG_DAEMON);
+#endif
+
#if __OpenBSD__
if (unveil("/", "") == -1) {
dolog(LOG_INFO, "unveil cortex: %s\n", strerror(errno));
@@ -3961,6 +4119,7 @@ setup_cortex(struct imsgbuf *ibuf)
imsg_compose(&neup2->ibuf, IMSG_FORWARD_UDP, 0, 0, -1, imsg.data, datalen);
msgbuf_write(&neup2->ibuf.w);
+
break;
blob - 20258f6572cfab2725d52153c74f9bf4bcde738e
blob + 2baaf14567800ff6aa96ab9e6c9fc40a65892d32
--- forward.c
+++ forward.c
@@ -27,7 +27,7 @@
*/
/*
- * $Id: forward.c,v 1.3 2020/07/01 05:07:47 pjp Exp $
+ * $Id: forward.c,v 1.4 2020/07/03 06:49:57 pjp Exp $
*/
#include <sys/types.h>
@@ -77,18 +77,11 @@
#include "endian.h"
#endif
+#include <openssl/hmac.h>
+
#include "ddd-dns.h"
#include "ddd-db.h"
-void init_forward(void);
-int insert_forward(struct sockaddr_storage *, uint16_t, char *);
-void forwardloop(ddDB *, struct cfg *, struct imsgbuf *);
-void forwardthis(int, struct forward *);
-
-extern void dolog(int, char *, ...);
-
-extern int debug, verbose;
-
SLIST_HEAD(, forwardentry) forwardhead;
static struct forwardentry {
@@ -97,23 +90,67 @@ static struct forwardentry {
struct sockaddr_storage host;
uint16_t destport;
char *tsigkey;
+ int active;
SLIST_ENTRY(forwardentry) forward_entry;
} *fw2, *fwp;
SLIST_HEAD(, forwardqueue) fwqhead;
static struct forwardqueue {
- time_t time;
- struct sockaddr_storage host;
- uint16_t id;
- uint16_t port;
- struct sockaddr_storage oldhost;
- uint16_t oldid;
- uint16_t oldport;
- int so;
- SLIST_ENTRY(forwardqueue) entries;
+ uint32_t longid; /* a long identifier */
+ time_t time; /* time created */
+ struct sockaddr_storage host; /* remote host to query */
+ uint16_t id; /* new id to query */
+ uint16_t port; /* remote port to query */
+ struct sockaddr_in oldhost4; /* old v4 host source */
+ struct sockaddr_in6 oldhost6; /* old v6 host source */
+ uint16_t oldid; /* old id source */
+ uint16_t oldport; /* the old port */
+ int oldfamily; /* old family */
+ int oldsel; /* this indicates which sock */
+ int so; /* open connected socket */
+ int returnso; /* return socket (TCP) */
+ int istcp; /* whether we're tcp */
+ int family; /* our family */
+ char *tsigkey; /* which key we use for query */
+ uint64_t tsigtimefudge; /* passed tsigtimefudge */
+ char mac[32]; /* passed mac from query */
+ int haveoldmac; /* do we have an old mac? */
+ char oldkeyname[256]; /* old key name */
+ int oldkeynamelen; /* old key name len */
+ char oldmac[32]; /* old mac */
+ SLIST_ENTRY(forwardqueue) entries; /* next entry */
} *fwq1, *fwq2, *fwqp;
+void init_forward(void);
+int insert_forward(int, struct sockaddr_storage *, uint16_t, char *);
+void forwardloop(ddDB *, struct cfg *, struct imsgbuf *);
+void forwardthis(int, struct sforward *);
+void sendit(struct forwardqueue *, struct sforward *);
+void returnit(struct cfg *cfg, struct forwardqueue *, char *, int);
+struct tsig * check_tsig(char *, int, char *);
+
+extern void dolog(int, char *, ...);
+extern void pack16(char *, u_int16_t);
+extern uint16_t unpack16(char *);
+extern uint32_t unpack32(char *);
+extern void ddd_shutdown(void);
+extern int additional_opt(struct question *, char *, int, int);
+extern int additional_tsig(struct question *, char *, int, int, int, int, HMAC_CTX *);
+extern struct question *build_question(char *, int, int, char *);
+extern struct question *build_fake_question(char *, int, u_int16_t, char *, int);
+extern int free_question(struct question *);
+extern char * dns_label(char *, int *);
+extern int find_tsig_key(char *, int, char *, int);
+extern int memcasecmp(u_char *, u_char *, int);
+extern char * expand_compression(u_char *, u_char *, u_char *, u_char *, int *, int);
+
+
+extern int debug, verbose;
+extern int tsig;
+extern int dnssec;
+
+
/*
* INIT_FORWARD - initialize the forward singly linked list
*/
@@ -131,7 +168,7 @@ init_forward(void)
*/
int
-insert_forward(struct sockaddr_storage *ip, uint16_t port, char *tsigkey)
+insert_forward(int family, struct sockaddr_storage *ip, uint16_t port, char *tsigkey)
{
fw2 = calloc(1, sizeof(struct forwardentry));
if (fw2 == NULL) {
@@ -139,7 +176,9 @@ insert_forward(struct sockaddr_storage *ip, uint16_t p
return 1;
}
- switch (fw2->family = ip->ss_family) {
+ fw2->family = family;
+
+ switch (fw2->family) {
case AF_INET:
inet_ntop(AF_INET, (struct sockaddr_in *)ip, fw2->name, sizeof(fw2->name));
break;
@@ -160,6 +199,8 @@ insert_forward(struct sockaddr_storage *ip, uint16_t p
return 1;
}
}
+
+ fw2->active = 1;
SLIST_INSERT_HEAD(&forwardhead, fw2, forward_entry);
@@ -169,21 +210,70 @@ insert_forward(struct sockaddr_storage *ip, uint16_t p
void
forwardloop(ddDB *db, struct cfg *cfg, struct imsgbuf *ibuf)
{
+ char *buf;
struct imsg imsg;
int max, sel;
+ int len, need;
ssize_t n, datalen;
fd_set rset;
+ buf = calloc(1, (0xffff + 2));
+ if (buf == NULL) {
+ dolog(LOG_INFO, "calloc: %s\n", strerror(errno));
+ ddd_shutdown();
+ exit(1);
+ }
+
for (;;) {
FD_ZERO(&rset);
FD_SET(ibuf->fd, &rset);
if (ibuf->fd > max)
max = ibuf->fd;
+ SLIST_FOREACH(fwq1, &fwqhead, entries) {
+ if (fwq1->so > max)
+ max = fwq1->so;
+
+ FD_SET(fwq1->so, &rset);
+ }
+
sel = select(max + 1, &rset, NULL, NULL, NULL);
if (sel == -1) {
continue;
}
+
+ SLIST_FOREACH_SAFE(fwq1, &fwqhead, entries, fwqp) {
+ if (FD_ISSET(fwq1->so, &rset)) {
+ if (fwq1->istcp) {
+ len = recv(fwq1->so, buf, 2, MSG_WAITALL);
+ if (len < 0) {
+ goto drop;
+ }
+ need = ntohs(unpack16(buf));
+ len = recv(fwq1->so, buf, need, MSG_WAITALL);
+ returnit(cfg, fwq1, buf, len);
+ } else {
+ len = recv(fwq1->so, buf, 0xffff, 0);
+ if (len < 0) {
+ goto drop;
+ }
+ returnit(cfg, fwq1, buf, len);
+ }
+
+drop:
+
+ SLIST_REMOVE(&fwqhead, fwq1, forwardqueue, entries);
+ close(fwq1->so);
+ if (fwq1->returnso != -1)
+ close(fwq2->returnso);
+
+ if (fwq1->tsigkey)
+ free(fwq1->tsigkey);
+
+ free(fwq1);
+
+ }
+ }
if (FD_ISSET(ibuf->fd, &rset)) {
if ((n = imsg_read(ibuf)) < 0 && errno != EAGAIN) {
@@ -205,20 +295,24 @@ forwardloop(ddDB *db, struct cfg *cfg, struct imsgbuf
break;
datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
- if (datalen != sizeof(struct forward)) {
+ if (datalen != sizeof(struct sforward)) {
imsg_free(&imsg);
continue;
}
switch(imsg.hdr.type) {
case IMSG_FORWARD_UDP:
+#if DEBUG
dolog(LOG_INFO, "received UDP message from mainloop\n");
- forwardthis(-1, imsg.data);
+#endif
+ forwardthis(-1, (struct sforward *)imsg.data);
break;
case IMSG_FORWARD_TCP:
+#if DEBUG
dolog(LOG_INFO, "received TCP message and descriptor\n");
- forwardthis(imsg.fd, imsg.data);
+#endif
+ forwardthis(imsg.fd, (struct sforward *)imsg.data);
break;
}
@@ -228,46 +322,841 @@ forwardloop(ddDB *db, struct cfg *cfg, struct imsgbuf
} /* FD_ISSET... */
}
- while (1)
- sleep(10);
-
/* NOTREACHED */
-
}
void
-forwardthis(int so, struct forward *forward)
+forwardthis(int so, struct sforward *sforward)
{
- struct dns_header *dh = (struct dns_header *)forward->buf;
+ int found = 0;
time_t now;
char *p;
+ socklen_t namelen;
now = time(NULL);
- p = forward->buf;
+ p = sforward->buf;
SLIST_FOREACH_SAFE(fwq1, &fwqhead, entries, fwq2) {
if (difftime(now, fwq1->time) > 15) {
SLIST_REMOVE(&fwqhead, fwq1, forwardqueue, entries);
+ if (fwq1->returnso != -1)
+ close(fwq1->returnso);
+ close(fwq1->so);
+ if (fwq1->tsigkey)
+ free(fwq1->tsigkey);
+ free(fwq1);
continue;
}
- if (memcmp(&fwq1->oldhost, &forward->from,
- sizeof(struct sockaddr_storage)) == 0 &&
- fwq1->oldport == forward->rport &&
- fwq1->oldid == dh->id) {
- /* found, break... */
+ found = 0;
+ switch (fwq1->oldfamily) {
+ case AF_INET:
+ if (memcmp(&fwq1->oldhost4.sin_addr.s_addr,
+ &sforward->from4.sin_addr.s_addr,
+ sizeof(struct in_addr)) == 0 &&
+ fwq1->oldport == sforward->rport &&
+ fwq1->oldid == sforward->header.id) {
+ /* found, break... */
+ found = 1;
+ }
break;
+ case AF_INET6:
+ if (memcmp(&fwq1->oldhost6.sin6_addr,
+ &sforward->from6.sin6_addr, 16) == 0 &&
+ fwq1->oldport == sforward->rport &&
+ fwq1->oldid == sforward->header.id) {
+ /* found, break... */
+ found = 1;
+ }
+ break;
}
+
+ if (found)
+ break;
}
if (fwq1 == NULL) {
/* create a new queue and send it */
+
+ SLIST_FOREACH(fw2, &forwardhead, forward_entry) {
+ if (fw2->active == 1)
+ break;
+ }
+
+ if (fw2 == NULL) {
+ SLIST_FOREACH(fwp, &forwardhead, forward_entry) {
+ if (fwp != fw2) {
+ fw2 = fwp;
+ fw2->active = 1;
+ break;
+ }
+ }
+
+ if (fw2 == NULL) {
+ dolog(LOG_INFO, "FORWARD: no suitable destinations found\n");
+ return;
+ }
+
+ }
+ fwq1 = calloc(1, sizeof(struct forwardqueue));
+ if (fwq1 == NULL) {
+ dolog(LOG_INFO, "calloc: %s\n", strerror(errno));
+ return;
+ }
+ fwq1->oldfamily = sforward->family;
+ fwq1->oldsel = sforward->oldsel;
+
+ switch (sforward->family) {
+ case AF_INET:
+ memcpy(&fwq1->oldhost4, &sforward->from4, sizeof(struct sockaddr_in));
+ break;
+ case AF_INET6:
+ memcpy(&fwq1->oldhost6, &sforward->from6, sizeof(struct sockaddr_in));
+ break;
+ }
+
+ fwq1->oldport = sforward->rport;
+ fwq1->oldid = sforward->header.id;
+
+ fwq1->port = fw2->destport;
+ fwq1->longid = arc4random();
+ fwq1->id = fwq1->longid % 0xffff;
+ fwq1->time = now;
+ if (so == -1)
+ fwq1->istcp = 0;
+ else
+ fwq1->istcp = 1;
+
+
+ memcpy((char *)&fwq1->host, (char *)&fw2->host, sizeof(struct sockaddr_storage));
+
+ fwq1->family = fw2->family;
+ if (fw2->tsigkey) {
+ fwq1->tsigkey = strdup(fw2->tsigkey);
+ if (fwq1->tsigkey == NULL) {
+ dolog(LOG_ERR, "FORWARD strdup: %s\n", strerror(errno));
+ free(fwq1);
+ return;
+ }
+ } else
+ fwq1->tsigkey = NULL;
+
+ /* connect the UDP sockets */
+
+ fwq1->so = socket(fw2->family, (fwq1->istcp != 1) ? SOCK_DGRAM : SOCK_STREAM, 0);
+ if (fwq1->so < 0) {
+ dolog(LOG_ERR, "FORWARD socket: %s\n", strerror(errno));
+ if (fwq1->tsigkey)
+ free(fwq1->tsigkey);
+ free(fwq1);
+ return;
+ }
+
+ namelen = (fw2->family == AF_INET) ? sizeof(struct sockaddr_in) \
+ : sizeof(struct sockaddr_in6);
+
+ if (connect(fwq1->so, (struct sockaddr *)&fwq1->host, namelen) < 0) {
+ dolog(LOG_ERR, "FORWARD can't connect: %s\n", strerror(errno));
+ if (fwq1->tsigkey)
+ free(fwq1->tsigkey);
+
+ free(fwq1);
+ return;
+ }
+
+ fwq1->returnso = so;
+
+ /* are we TSIG'ed? save key and mac */
+ if (sforward->havemac) {
+ fwq1->haveoldmac = 1;
+ memcpy(&fwq1->oldkeyname, &sforward->tsigname, sizeof(fwq1->oldkeyname));
+ fwq1->oldkeynamelen = sforward->tsignamelen;
+ memcpy(&fwq1->oldmac, &sforward->mac, sizeof(fwq1->oldmac));
+ fwq1->tsigtimefudge = sforward->tsigtimefudge;
+ } else
+ fwq1->haveoldmac = 0;
+
+ SLIST_INSERT_HEAD(&fwqhead, fwq1, entries);
+
+ sendit(fwq1, sforward);
} else {
/* resend this one */
fwq1->time = now;
+ sendit(fwq1, sforward);
}
+ return;
+}
+
+void
+sendit(struct forwardqueue *fwq, struct sforward *sforward)
+{
+ struct dns_header *dh;
+ struct question *q;
+ char *buf, *p, *packet;
+ char *tsigname;
+ int len = 0, outlen;
+ int tsignamelen = 0;
+
+ buf = calloc(1, (0xffff + 2));
+ if (buf == NULL) {
+ dolog(LOG_INFO, "calloc: %s\n", strerror(errno));
+ return;
+ }
+
+ if (fwq->tsigkey) {
+ tsigname = dns_label(fwq->tsigkey, &tsignamelen);
+ if (tsigname == NULL) {
+ dolog(LOG_INFO, "dns_label failed\n");
+ free(buf);
+ return;
+ }
+ } else {
+ tsigname = NULL;
+ tsignamelen = 0;
+ }
+
+ q = build_fake_question(sforward->buf, sforward->buflen, sforward->type, tsigname, tsignamelen);
+
+ if (q == NULL) {
+ dolog(LOG_INFO, "build_fake_question failed\n");
+ free(buf);
+ return;
+ }
+
+ q->edns0len = sforward->edns0len;
+ if (fwq->istcp == 1) {
+ p = &buf[2];
+ } else
+ p = &buf[0];
+
+ packet = p;
+ dh = (struct dns_header *)p;
+
+ memcpy((char *)dh, (char *)&sforward->header, sizeof(struct dns_header));
+ dh->id = htons(fwq->id);
+ dh->question = htons(1);
+ dh->answer = 0; dh->nsrr = 0; dh->additional = htons(1);
+
+ memset((char *)&dh->query, 0, sizeof(dh->query));
+
+ SET_DNS_QUERY(dh);
+ SET_DNS_RECURSION(dh);
+ HTONS(dh->query);
+
+ p += sizeof(struct dns_header);
+ len += sizeof(struct dns_header);
+
+ memcpy(p, sforward->buf, sforward->buflen);
+ p += sforward->buflen;
+ len += sforward->buflen;
+
+ pack16(p, sforward->type);
+ p += 2;
+ pack16(p, sforward->class);
+
+ p += 2;
+ len += 4; /* type and class */
+
+ /* additionals */
+
+ if (dnssec)
+ q->dnssecok = 1;
+
+ outlen = additional_opt(q, packet, 0xffff, len);
+ len = outlen;
+
+ if (tsigname) {
+ outlen = additional_tsig(q, packet, 0xffff, len, 1, 0, NULL);
+ dh->additional = htons(2);
+ }
+
+ memcpy(&fwq->mac, &q->tsig.tsigmac, 32);
+
+ len = outlen;
+ p = packet + outlen;
+
+ if (fwq->istcp == 1) {
+ pack16(buf, htons(len));
+ send(fwq->so, buf, len + 2, 0);
+ } else
+ send(fwq->so, buf, len, 0);
+
+
+ free(buf);
+ free_question(q);
+
+ return;
+}
+
+void
+returnit(struct cfg *cfg, struct forwardqueue *fwq, char *rbuf, int rlen)
+{
+
+ struct dns_header *dh;
+ struct tsig *stsig = NULL;
+ struct question *q;
+
+ char *buf, *buf0, *p;
+
+ int so;
+ int len = 0;
+ int outlen;
+
+ socklen_t tolen;
+
+ buf = calloc(1, 0xffff + 2);
+ if (buf == NULL) {
+ dolog(LOG_INFO, "calloc: %s\n", strerror(errno));
+ return;
+ }
+
+ if (fwq->istcp == 1) {
+ p = &buf[2];
+ so = fwq->returnso;
+ len = 2;
+ } else {
+ p = buf;
+ so = cfg->dup[fwq->oldsel];
+ }
+
+ if (rlen <= sizeof(struct dns_header)) {
+ dolog(LOG_INFO, "FORWARD returnit, returned packet is too small");
+ free(buf);
+ return;
+ }
+
+ memcpy(p, rbuf, rlen);
+ dh = (struct dns_header *)p;
+
+ if (! (ntohs(dh->query) & DNS_REPLY)) {
+ dolog(LOG_INFO, "FORWARD returnit, returned packet is not a reply\n");
+ free(buf);
+ return;
+ }
+
+ if (dh->id != htons(fwq->id)) {
+ /* returned packet ID does not match */
+ dolog(LOG_INFO, "FORWARD returnit, returned packet ID does not match %d vs %d\n", ntohs(dh->id), fwq->id);
+ free(buf);
+ return;
+ }
+
+ if (fwq->tsigkey) {
+ buf0 = calloc(1, rlen);
+ if (buf0 == NULL) {
+ dolog(LOG_INFO, "calloc: %s\n", strerror(errno));
+ free(buf);
+ return;
+ }
+
+ memcpy(buf0, p, rlen);
+
+ stsig = check_tsig(buf0, rlen, fwq->mac);
+ if (stsig == NULL) {
+ dolog(LOG_INFO, "FORWARD returninit, malformed reply packet\n");
+ free(buf);
+ free(buf0);
+ return;
+ }
+
+ free(buf0);
+
+
+ if (stsig->have_tsig && stsig->tsigverified == 0) {
+ dolog(LOG_INFO, "FORWARD returnit, TSIG didn't check out error code = %d\n", stsig->tsigerrorcode);
+ free(buf);
+ return;
+ }
+
+ NTOHS(dh->additional);
+ dh->additional--;
+ HTONS(dh->additional);
+
+ rlen = stsig->tsigoffset;
+ }
+
+ /* add new tsig if needed */
+ pack16((char *)&dh->id, fwq->oldid);
+
+ NTOHS(dh->query);
+ dh->query &= ~(DNS_AUTH | DNS_NOTIFY); /* take AA answers out */
+ SET_DNS_RECURSION(dh);
+ SET_DNS_RECURSION_AVAIL(dh);
+ HTONS(dh->query);
+
+ if (fwq->haveoldmac) {
+ q = build_fake_question(p, rlen, DNS_TYPE_A, fwq->oldkeyname, fwq->oldkeynamelen);
+
+ if (q == NULL) {
+ dolog(LOG_INFO, "build_fake_question failed\n");
+ free(buf);
+ return;
+ }
+
+ memcpy(&q->tsig.tsigmac, &fwq->oldmac, 32);
+ q->tsig.tsigmaclen = 32;
+ q->tsig.tsigalglen = 13;
+ q->tsig.tsigerrorcode = 0;
+ q->tsig.tsigorigid = fwq->oldid;
+ q->tsig.have_tsig = 1;
+ q->tsig.tsig_timefudge = fwq->tsigtimefudge;
+
+ outlen = additional_tsig(q, p, 0xffff, rlen, 0, 0, NULL);
+ if (outlen == rlen) {
+ dolog(LOG_INFO, "additional tsig failed\n");
+ } else {
+ rlen = outlen;
+
+ NTOHS(dh->additional);
+ dh->additional++;
+ HTONS(dh->additional);
+
+ free_question(q);
+ }
+ }
+
+ len += rlen;
+
+ if (fwq->istcp == 1) {
+ pack16(buf, htons(rlen));
+ if (send(so, buf, len, 0) != len)
+ dolog(LOG_INFO, "send(): %s\n", strerror(errno));
+ close(so); /* only close the tcp stream */
+ fwq->returnso = -1;
+
+ } else {
+
+ switch (fwq->oldfamily) {
+ case AF_INET:
+ tolen = sizeof(struct sockaddr_in);
+ if (sendto(so, buf, len, 0, (struct sockaddr *)&fwq->oldhost4, tolen) < 0)
+ dolog(LOG_INFO, "sendto: %s\n", strerror(errno));
+ break;
+ default:
+ tolen = sizeof(struct sockaddr_in6);
+ if (sendto(so, buf, len, 0, (struct sockaddr *)&fwq->oldhost6, tolen) < 0)
+ dolog(LOG_INFO, "sendto: %s\n", strerror(errno));
+ break;
+ }
+ }
+
+ free(buf);
+ return;
+}
+
+struct tsig *
+check_tsig(char *buf, int len, char *mac)
+{
+ char pseudo_packet[4096]; /* for tsig */
+ char expand[DNS_MAXNAME + 1];
+ u_int rollback, i, j;
+ u_int16_t type, rdlen;
+ u_int32_t ttl;
+ u_int64_t timefudge;
+ int elen = 0;
+ int additional;
+
+ char *o, *pb;
+
+ struct dns_tsigrr *tsigrr = NULL;
+ struct dns_optrr *opt = NULL;
+ struct dns_header *hdr = (struct dns_header *)buf;
+ struct tsig *rtsig;
+
+
+ rtsig = (void *)calloc(1, sizeof(struct tsig));
+ if (rtsig == NULL) {
+ dolog(LOG_INFO, "calloc: %s\n", strerror(errno));
+ return NULL;
+ }
+
+ rollback = i = sizeof(struct dns_header);
+ /* the name is parsed here */
+ elen = 0;
+ memset(&expand, 0, sizeof(expand));
+ pb = expand_compression((u_char *)&buf[i], (u_char *)buf, (u_char *)&buf[len], (u_char *)&expand, &elen, sizeof(expand));
+ if (pb == NULL) {
+ dolog(LOG_INFO, "expand_compression() failed -2\n");
+ free(rtsig);
+ return NULL;
+ }
+ i = (pb - buf);
+ if (i > len) {
+ free(rtsig);
+ return NULL;
+ }
+
+ i += (2 * sizeof(u_int16_t)); /* type,class */
+
+ /* skip any payloads other than additional */
+
+ additional = ntohs(hdr->additional);
+ j = ntohs(hdr->answer) + ntohs(hdr->nsrr) + ntohs(hdr->additional);
+
+ for (;j > 0; j--) {
+ rollback = i;
+ /* the name is parsed here */
+ elen = 0;
+ memset(&expand, 0, sizeof(expand));
+ pb = expand_compression((u_char *)&buf[i], (u_char *)buf, (u_char *)&buf[len], (u_char *)&expand, &elen, sizeof(expand));
+ if (pb == NULL) {
+ dolog(LOG_INFO, "expand_compression() failed -1\n");
+ free(rtsig);
+ return NULL;
+ }
+ i = (pb - buf);
+ if (i > len) {
+ free(rtsig);
+ return NULL;
+ }
+
+ type = ntohs(unpack16(&buf[i]));
+ if (type == DNS_TYPE_OPT || type == DNS_TYPE_TSIG) {
+ i = rollback;
+ break;
+ }
+
+ i += 8; /* skip type, class, ttl */
+ if (i > len) {
+ free(rtsig);
+ return NULL;
+ }
+
+ rdlen = unpack16(&buf[i]);
+ i += 2; /* skip rdlen */
+ i += ntohs(rdlen); /* skip rdata, next */
+
+ if (i > len) {
+ free(rtsig);
+ return NULL;
+ }
+ }
+
+
+ /* check for edns0 opt rr */
+ do {
+ /* if we don't have an additional section, break */
+ if (additional < 1)
+ break;
+
+ rollback = i;
+
+ /* check that the minimum optrr fits */
+ /* 10 */
+ if (i + sizeof(struct dns_optrr) > len) {
+ i = rollback;
+ break;
+ }
+
+ opt = (struct dns_optrr *)&buf[i];
+ if (opt->name[0] != 0) {
+ i = rollback;
+ break;
+ }
+
+ if (ntohs(opt->type) != DNS_TYPE_OPT) {
+ i = rollback;
+ break;
+ }
+
+ /* RFC 3225 */
+ ttl = ntohl(opt->ttl);
+
+ i += 11 + ntohs(opt->rdlen);
+ if (i > len) {
+ free(rtsig);
+ return NULL;
+ }
+ additional--;
+ } while (0);
+ /* check for TSIG rr */
+ do {
+ u_int16_t val16, tsigerror, tsigotherlen;
+ u_int16_t fudge;
+ u_int32_t val32;
+ int elen, tsignamelen;
+ char tsigkey[512];
+ u_char sha256[32];
+ u_int shasize = sizeof(sha256);
+ time_t now, tsigtime;
+ int pseudolen1, pseudolen2, ppoffset = 0;
+ int pseudolen3 , pseudolen4;
+
+ rtsig->have_tsig = 0;
+ rtsig->tsigerrorcode = 1;
+
+ /* if we don't have an additional section, break */
+ if (additional < 1) {
+ break;
+ }
+
+ memset(rtsig->tsigkey, 0, sizeof(rtsig->tsigkey));
+ memset(rtsig->tsigalg, 0, sizeof(rtsig->tsigalg));
+ memset(rtsig->tsigmac, 0, sizeof(rtsig->tsigmac));
+ rtsig->tsigkeylen = rtsig->tsigalglen = rtsig->tsigmaclen = 0;
+
+ /* the key name is parsed here */
+ rollback = i;
+ rtsig->tsigoffset = i;
+
+ elen = 0;
+ memset(&expand, 0, sizeof(expand));
+ pb = expand_compression((u_char *)&buf[i], (u_char *)buf, (u_char *)&buf[len], (u_char *)&expand, &elen, sizeof(expand));
+ if (pb == NULL) {
+ dolog(LOG_INFO, "expand_compression() failed\n");
+ free(rtsig);
+ return NULL;
+ }
+ i = (pb - buf);
+ pseudolen1 = i;
+
+ memcpy(rtsig->tsigkey, expand, elen);
+ rtsig->tsigkeylen = elen;
+
+
+ if (i + 10 > len) { /* type + class + ttl + rdlen == 10 */
+ i = rollback;
+ break;
+ }
+
+ /* type */
+ o = &buf[i];
+ val16 = unpack16(o);
+ if (ntohs(val16) != DNS_TYPE_TSIG) {
+ i = rollback;
+ break;
+ }
+ i += 2;
+ o += 2;
+ pseudolen2 = i;
+
+ rtsig->have_tsig = 1;
+
+ /* we don't have any tsig keys configured, no auth done */
+ if (tsig == 0) {
+ i = rollback;
+ break;
+ }
+
+ rtsig->tsigerrorcode = DNS_BADKEY;
+
+ /* class */
+ val16 = unpack16(o);
+ if (ntohs(val16) != DNS_CLASS_ANY) {
+#if DEBUG
+ dolog(LOG_INFO, "TSIG not class ANY\n");
+#endif
+ i = rollback;
+ break;
+ }
+ i += 2;
+ o += 2;
+
+ /* ttl */
+ val32 = unpack32(o);
+ if (ntohl(val32) != 0) {
+#if DEBUG
+ dolog(LOG_INFO, "TSIG not TTL 0\n");
+#endif
+ i = rollback;
+ break;
+ }
+ i += 4;
+ o += 4;
+
+ /* rdlen */
+ val16 = unpack16(o);
+ if (ntohs(val16) != (len - (i + 2))) {
+#if DEBUG
+ dolog(LOG_INFO, "TSIG not matching RDLEN\n");
+#endif
+ i = rollback;
+ break;
+ }
+ i += 2;
+ o += 2;
+ pseudolen3 = i;
+
+ /* the algorithm name is parsed here */
+ elen = 0;
+ memset(&expand, 0, sizeof(expand));
+ pb = expand_compression((u_char *)&buf[i], (u_char *)buf, (u_char *)&buf[len], (u_char *)&expand, &elen, sizeof(expand));
+ if (pb == NULL) {
+ dolog(LOG_INFO, "expand_compression() failed 2\n");
+ free(rtsig);
+ return NULL;
+ }
+ i = (pb - buf);
+ pseudolen4 = i;
+
+ memcpy(rtsig->tsigalg, expand, elen);
+ rtsig->tsigalglen = elen;
+
+ /* now check for MAC type, since it's given once again */
+ if (elen == 11) {
+ if (expand[0] != 9 ||
+ memcasecmp(&expand[1], "hmac-sha1", 9) != 0) {
+ break;
+ }
+ } else if (elen == 13) {
+ if (expand[0] != 11 ||
+ memcasecmp(&expand[1], "hmac-sha256", 11) != 0) {
+ break;
+ }
+ } else if (elen == 26) {
+ if (expand[0] != 8 ||
+ memcasecmp(&expand[1], "hmac-md5", 8) != 0) {
+ break;
+ }
+ } else {
+ break;
+ }
+
+ /*
+ * this is a delayed (moved down) check of the key, we don't
+ * know if this is a TSIG packet until we've chekced the TSIG
+ * type, that's why it's delayed...
+ */
+
+ if ((tsignamelen = find_tsig_key(rtsig->tsigkey, rtsig->tsigkeylen, (char *)&tsigkey, sizeof(tsigkey))) < 0) {
+ /* we don't have the name configured, let it pass */
+ i = rollback;
+ break;
+ }
+
+ if (i + sizeof(struct dns_tsigrr) > len) {
+ i = rollback;
+ break;
+ }
+
+ tsigrr = (struct dns_tsigrr *)&buf[i];
+ /* XXX */
+#ifndef __OpenBSD__
+ timefudge = be64toh(tsigrr->timefudge);
+#else
+ timefudge = betoh64(tsigrr->timefudge);
+#endif
+ fudge = (u_int16_t)(timefudge & 0xffff);
+ tsigtime = (u_int64_t)(timefudge >> 16);
+
+ rtsig->tsig_timefudge = tsigrr->timefudge;
+
+ i += (8 + 2); /* timefudge + macsize */
+
+ if (ntohs(tsigrr->macsize) != 32) {
+#if DEBUG
+ dolog(LOG_INFO, "bad macsize\n");
+#endif
+ rtsig->tsigerrorcode = DNS_BADSIG;
+ break;
+ }
+
+ i += ntohs(tsigrr->macsize);
+
+
+ /* now get the MAC from packet with length rollback */
+ NTOHS(hdr->additional);
+ hdr->additional--;
+ HTONS(hdr->additional);
+
+ /* origid */
+ o = &buf[i];
+ val16 = unpack16(o);
+ i += 2;
+ o += 2;
+ if (hdr->id != val16)
+ hdr->id = val16;
+ rtsig->tsigorigid = val16;
+
+ /* error */
+ tsigerror = unpack16(o);
+ i += 2;
+ o += 2;
+
+ /* other len */
+ tsigotherlen = unpack16(o);
+ i += 2;
+ o += 2;
+
+ ppoffset = 0;
+
+ /* check if we have a request mac, this means it's an answer */
+ if (mac) {
+ o = &pseudo_packet[ppoffset];
+ pack16(o, htons(32));
+ ppoffset += 2;
+
+ memcpy(&pseudo_packet[ppoffset], mac, 32);
+ ppoffset += 32;
+ }
+
+ memcpy(&pseudo_packet[ppoffset], buf, pseudolen1);
+ ppoffset += pseudolen1;
+ memcpy((char *)&pseudo_packet[ppoffset], &buf[pseudolen2], 6);
+ ppoffset += 6;
+
+ memcpy((char *)&pseudo_packet[ppoffset], &buf[pseudolen3], pseudolen4 - pseudolen3);
+ ppoffset += (pseudolen4 - pseudolen3);
+
+ memcpy((char *)&pseudo_packet[ppoffset], (char *)&tsigrr->timefudge, 8);
+ ppoffset += 8;
+
+ o = &pseudo_packet[ppoffset];
+ pack16(o, tsigerror);
+ ppoffset += 2;
+ o += 2;
+
+ o = &pseudo_packet[ppoffset];
+ pack16(o, tsigotherlen);
+ ppoffset += 2;
+ o += 2;
+
+ memcpy(&pseudo_packet[ppoffset], &buf[i], len - i);
+ ppoffset += (len - i);
+
+ /* check for BADTIME before the HMAC memcmp as per RFC 2845 */
+ now = time(NULL);
+ /* outside our fudge window */
+ if (tsigtime < (now - fudge) || tsigtime > (now + fudge)) {
+#if DEBUG
+ dolog(LOG_INFO, "outside of our fudge window\n");
+#endif
+ rtsig->tsigerrorcode = DNS_BADTIME;
+ break;
+ }
+
+ HMAC(EVP_sha256(), tsigkey, tsignamelen, (unsigned char *)pseudo_packet,
+ ppoffset, (unsigned char *)&sha256, &shasize);
+
+
+
+#if __OpenBSD__
+ if (timingsafe_memcmp(sha256, tsigrr->mac, sizeof(sha256)) != 0) {
+#else
+ if (memcmp(sha256, tsigrr->mac, sizeof(sha256)) != 0) {
+#endif
+#if DEBUG
+ dolog(LOG_INFO, "HMAC did not verify\n");
+#endif
+ rtsig->tsigerrorcode = DNS_BADSIG;
+ break;
+ }
+
+ /* copy the mac for error coding */
+ memcpy(rtsig->tsigmac, tsigrr->mac, sizeof(rtsig->tsigmac));
+ rtsig->tsigmaclen = 32;
+
+ /* we're now authenticated */
+ rtsig->tsigerrorcode = 0;
+ rtsig->tsigverified = 1;
+
+ } while (0);
+
+ /* parse type and class from the question */
+
+ return (rtsig);
}
blob - 0798042f6da6f2510745eaf4632f28e56ecb9caa
blob + 1ef9e924409429e276a23b85837484e85b49da78
--- parse.y
+++ parse.y
@@ -21,7 +21,7 @@
*/
/*
- * $Id: parse.y,v 1.100 2020/07/01 05:07:47 pjp Exp $
+ * $Id: parse.y,v 1.101 2020/07/03 06:49:57 pjp Exp $
*/
%{
@@ -92,7 +92,7 @@ extern int insert_region(char *, char *, u_int8_t);
extern int insert_axfr(char *, char *);
extern int insert_notifyddd(char *, char *);
extern int insert_filter(char *, char *);
-extern int insert_forward(struct sockaddr_storage *, uint16_t, char *);
+extern int insert_forward(int, struct sockaddr_storage *, uint16_t, char *);
extern int insert_whitelist(char *, char *);
extern int insert_tsig(char *, char *);
extern int insert_tsig_key(char *, int, char *, int);
@@ -114,6 +114,7 @@ extern int errno;
extern int debug;
extern int forward;
extern int forwardtsig;
+extern int zonecount;
extern int verbose;
extern int bflag;
extern int iflag;
@@ -803,12 +804,7 @@ rzonestatement:
zone:
ZONE zonelabel zonecontent
{
-#if 0
- if ((confstatus & CONFIG_VERSION) != CONFIG_VERSION) {
- dolog(LOG_INFO, "There must be a version at the top of the first configfile\n");
- return (-1);
- }
-#endif
+ zonecount++;
}
;
@@ -1453,12 +1449,19 @@ forwardstatement : INCOMINGTSIG STRING SEMICOLON CRLF
memset(&sso, 0, sizeof(struct sockaddr_storage));
- if (strchr($2, ':') != NULL)
- inet_pton(AF_INET6, $2, sin6);
- else
- inet_pton(AF_INET, $2, sin);
+ if (strchr($2, ':') != NULL) {
+ inet_pton(AF_INET6, $2, &sin6->sin6_addr);
+ sin6->sin6_family = AF_INET6;
+ sin6->sin6_port = htons($4);
+ sin6->sin6_len = sizeof(struct sockaddr_in6);
+ insert_forward(AF_INET6, &sso, $4, $6);
+ } else {
+ inet_pton(AF_INET, $2, &sin->sin_addr);
+ sin->sin_family = AF_INET;
+ sin->sin_port = htons($4);
+ insert_forward(AF_INET, &sso, $4, $6);
+ }
- insert_forward(&sso, $4, $6);
free($5);
free($6);
blob - 67318e281179501b9bcd6317b5dbb48ede3820fc
blob + d02e1d6375933da40f7bd6bb9a6701bca1be6836
--- util.c
+++ util.c
@@ -27,7 +27,7 @@
*/
/*
- * $Id: util.c,v 1.63 2020/06/30 07:09:46 pjp Exp $
+ * $Id: util.c,v 1.64 2020/07/03 06:49:57 pjp Exp $
*/
#include <sys/types.h>
@@ -124,6 +124,7 @@ extern int debug;
extern int *ptr;
extern int tsig;
extern int forward;
+extern int zonecount;
extern void dolog(int, char *, ...);
@@ -360,12 +361,8 @@ lookup_zone(ddDB *db, struct question *question, int *
*returnval = 0;
if (forward) {
- /*
- * We short circuit forwarded lookups to the root, which
- * would usually come out as ERR_NODATA for some reason
- * I don't know why exactly, XXX.
- */
- if (plen == 1 && *p == '\0') {
+ /* short circuit when we have no zones loaded */
+ if (zonecount == 0) {
*lzerrno = ERR_FORWARD;
*returnval = -1;
repomaster@centroid.eu