Commit Diff
Diff:
752edb030e8c2e7d3df033ace16d5697c94c40da
199a85cf009d7ca883a49a3890765d5d31de26fa
Commit:
199a85cf009d7ca883a49a3890765d5d31de26fa
Tree:
7b4b585ae9858acbcd35c2a0d0e631465dbf9850
Author:
pjp <pjp@delphinusdns.org>
Committer:
pjp <pjp@delphinusdns.org>
Date:
Sun Feb 24 07:14:02 2019 UTC
Message:
add tsig support, it's not fully done yet but I need to commit now so that a bug from February 15th makes it in. I found it while debugging TSIG answers. The bug was: in reply_mx() there was a htonl() wrongly placed instead of htons() this was fixed and a notice was put up on delphinusdns.org news.
blob - 237501d5a68744948a4d8435e07335702f327029
blob + 6224e9f470aebb15d50c12d78d12dced8b45b62b
--- additional.c
+++ additional.c
@@ -27,13 +27,16 @@
*/
/*
- * $Id: additional.c,v 1.20 2019/02/15 18:47:43 pjp Exp $
+ * $Id: additional.c,v 1.21 2019/02/24 07:14:02 pjp Exp $
*/
#include "ddd-include.h"
#include "ddd-dns.h"
#include "ddd-db.h"
+#include <openssl/evp.h>
+#include <openssl/hmac.h>
+
int additional_a(char *, int, struct rbtree *, char *, int, int, int *);
int additional_aaaa(char *, int, struct rbtree *, char *, int, int, int *);
int additional_mx(char *, int, struct rbtree *, char *, int, int, int *);
@@ -42,12 +45,15 @@ int additional_ptr(char *, int, struct rbtree *, char
int additional_rrsig(char *, int, int, struct rbtree *, char *, int, int, int);
int additional_nsec(char *, int, int, struct rbtree *, char *, int, int);
int additional_nsec3(char *, int, int, struct rbtree *, char *, int, int);
+int additional_tsig(struct question *, char *, int, int, int);
extern int compress_label(u_char *, int, int);
extern struct rbtree * find_rrset(ddDB *db, char *name, int len);
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 int dnssec;
@@ -341,6 +347,161 @@ additional_ptr(char *name, int namelen, struct rbtree
(*retcount)++;
+
+out:
+ return (offset);
+
+}
+/*
+ * ADDITIONAL_TSIG - tag on an additional TSIG record to packet
+ */
+
+int
+additional_tsig(struct question *question, char *reply, int replylen, int offset, int request)
+{
+ struct dns_tsigrr *answer, *ppanswer;
+ u_int16_t *sval;
+ u_int16_t macsize = 32;
+ u_int32_t *lval;
+ int tsignamelen;
+ int ppoffset = 0;
+ char *pseudo_packet = NULL;
+ struct dns_header *odh;
+ char tsigkey[512];
+ time_t now;
+
+ pseudo_packet = malloc(replylen);
+ if (pseudo_packet == NULL) {
+ goto out;
+ }
+
+ if (request == 0) {
+ if (question->tsigerrorcode && question->tsigerrorcode != DNS_BADTIME) {
+ ppoffset = 0;
+ sval = (u_int16_t *)&pseudo_packet[ppoffset];
+ *sval = htons(0);
+ ppoffset += 2;
+ } else {
+ /* RFC 2845 section 3.4.3 */
+ ppoffset = 0;
+ sval = (u_int16_t *)&pseudo_packet[ppoffset];
+ *sval = htons(question->tsigmaclen);
+ ppoffset += 2;
+
+ memcpy(&pseudo_packet[ppoffset], question->tsigmac, question->tsigmaclen);
+ ppoffset += question->tsigmaclen;
+ }
+ }
+
+ odh = (struct dns_header *)reply;
+ memcpy(&pseudo_packet[ppoffset], &reply[0], offset);
+ ppoffset += offset;
+
+ if ((tsignamelen = find_tsig_key(question->tsigkey,
+ question->tsigkeylen, (char *)&tsigkey, sizeof(tsigkey))) < 0) {
+ /* do nothing here? */
+ memset(tsigkey, 0, sizeof(tsigkey));
+ tsignamelen = 0;
+ }
+
+ if ((offset + 2 + 8 + 2 + question->tsigmaclen +
+ question->tsigkeylen +
+ question->tsigalglen + 2 + 2 + 4) > replylen) {
+ goto out;
+ }
+
+ /* keyname */
+ memcpy(&reply[offset], question->tsigkey, question->tsigkeylen);
+ offset += question->tsigkeylen;
+
+ memcpy(&pseudo_packet[ppoffset], question->tsigkey, question->tsigkeylen);
+ ppoffset += question->tsigkeylen;
+
+ /* type TSIG */
+ sval = (u_int16_t *)&reply[offset];
+ *sval = htons(DNS_TYPE_TSIG);
+ offset += 2;
+
+ /* class ANY */
+ sval = (u_int16_t *)&reply[offset];
+ *sval = htons(DNS_CLASS_ANY);
+ offset += 2;
+
+ sval = (u_int16_t *)&pseudo_packet[ppoffset];
+ *sval = htons(DNS_CLASS_ANY);
+ ppoffset += 2;
+
+ /* ttl */
+ lval = (u_int32_t *)&reply[offset];
+ *lval = htonl(0);
+ offset += 4;
+
+ lval = (u_int32_t *)&pseudo_packet[ppoffset];
+ *lval = htonl(0);
+ ppoffset += 4;
+
+ /* rdlen */
+ sval = (u_int16_t *)&reply[offset];
+ *sval = htons(2 + 8 + question->tsigalglen + question->tsigmaclen + 2 + 2 + 2);
+ offset += 2;
+
+ memcpy(&reply[offset], question->tsigalg, question->tsigalglen);
+ offset += question->tsigalglen;
+
+ memcpy(&pseudo_packet[ppoffset], question->tsigalg, question->tsigalglen);
+ ppoffset += question->tsigalglen;
+
+ now = time(NULL);
+
+ answer = (struct dns_tsigrr *)&reply[offset];
+ answer->timefudge = htobe64((u_int64_t)(now << 16) | (300 & 0xffff));
+ answer->macsize = htons(question->tsigmaclen);
+ offset += (8 + 2);
+
+ /* skip mac */
+ offset += question->tsigmaclen;
+
+ sval = (u_int16_t *)&reply[offset];
+ *sval = odh->id;
+ offset += 2;
+
+ sval = (u_int16_t *)&reply[offset];
+ *sval = htons(question->tsigerrorcode);
+ offset += 2;
+
+ sval = (u_int16_t *)&reply[offset];
+ *sval = htons(0);
+ offset += 2;
+
+ ppanswer = (struct dns_tsigrr *)&pseudo_packet[ppoffset];
+ ppanswer->timefudge = htobe64((u_int64_t)(now << 16) | (300 & 0xffff));
+ ppoffset += 8;
+
+
+ /* error */
+ sval = (u_int16_t *)&pseudo_packet[ppoffset];
+ *sval = htons(question->tsigerrorcode);
+ ppoffset += 2;
+
+ /* other len */
+ sval = (u_int16_t *)&pseudo_packet[ppoffset];
+ *sval = htons(0);
+ ppoffset += 2;
+
+
+ if (question->tsigerrorcode == DNS_BADTIME) {
+ HMAC(EVP_sha256(), tsigkey, tsignamelen,
+ (unsigned char *)pseudo_packet, ppoffset,
+ (unsigned char *)&answer->mac[0], (u_int *)&macsize);
+ } else if (question->tsigerrorcode) {
+ memset(&answer->mac[0], 0, question->tsigmaclen);
+ } else {
+ HMAC(EVP_sha256(), tsigkey, tsignamelen,
+ (unsigned char *)pseudo_packet, ppoffset,
+ (unsigned char *)&answer->mac[0], (u_int *)&macsize);
+ }
+
+ free(pseudo_packet);
out:
return (offset);
blob - 4b24c6c3e33216ba4772cdbc4a7341c785c57607
blob + fb43a42b41141cb14bbd5e605d3622e4412b0d54
--- ddd-db.h
+++ ddd-db.h
@@ -27,7 +27,7 @@
*/
/*
- * $Id: ddd-db.h,v 1.15 2019/02/19 11:49:54 pjp Exp $
+ * $Id: ddd-db.h,v 1.16 2019/02/24 07:14:02 pjp Exp $
*/
#ifndef _DB_H
@@ -47,6 +47,7 @@
#define IMSG_PARSEREPLY_MESSAGE 5 /* return message from pledge parser */
#define IMSG_SHUTDOWN_MESSAGE 6 /* shut the server down */
#define IMSG_RELOAD_MESSAGE 7 /* reload/restart the server */
+#define IMSG_PARSEAUTH_MESSAGE 8 /* parse message with auth required */
#define ERR_DROP 0x1
#define ERR_NXDOMAIN 0x2
blob - 5667008966621bda8bee119fe097f0c3407d994d
blob + 0e5f4d5f203a57c066071bb02e6bae81bc7a8993
--- ddd-dns.h
+++ ddd-dns.h
@@ -27,7 +27,7 @@
*/
/*
- * $Id: ddd-dns.h,v 1.6 2017/11/28 15:02:41 pjp Exp $
+ * $Id: ddd-dns.h,v 1.7 2019/02/24 07:14:02 pjp Exp $
*/
#ifndef _DNS_H
@@ -84,6 +84,18 @@ struct dns_optrr {
char rdata[0]; /* attribute, value pairs */
}__attribute__((packed));
+/*
+ * TSIG RR, based on dns_rr
+ * RFC 2845 and RFC 4635 (for SHA-256)
+ */
+
+struct dns_tsigrr {
+ u_int64_t timefudge; /* time (48 bits) and fudge */
+ u_int16_t macsize; /* MAC size == 32 */
+ char mac[32]; /* SHA-256 MAC */
+ /* empty unless error == badtime */
+} __attribute__((packed));
+
/* RFC 1035 - page 28 */
struct dns_question_hdr {
char *name;
@@ -92,8 +104,6 @@ struct dns_question_hdr {
u_int16_t qclass;
};
-
-
/*
* flags RFC 1035, page 26
*/
@@ -106,10 +116,8 @@ struct dns_question_hdr {
#define DNS_TRUNC 0x200 /* Truncated (TC) */
#define DNS_RECURSE 0x100 /* if set Recursion Desired (RD) */
#define DNS_RECAVAIL 0x80 /* if set Recursion Available (RA) */
-#define DNS_BADTIME 0x12 /* RCODE (18) BADTIME RFC 2845 p. 3 */
-#define DNS_BADKEY 0x11 /* RCODE (17) BADKEY RFC 2845 p. 3 */
-#define DNS_BADSIG 0x10 /* RCODE (16) BADSIG RFC 2845 p. 3 */
#define DNS_BADVERS 0x10 /* RCODE (16) BADVERS RFC 2671 p. 6 */
+#define DNS_NOTAUTH 0x9 /* RCODE - Not Authenticated RFC 2845 */
#define DNS_REFUSED 0x5 /* RCODE - Refused */
#define DNS_NOTIMPL 0x4 /* RCODE - Not Implemented */
#define DNS_NAMEERR 0x3 /* RCODE - Name Error, NXDOMAIN */
@@ -117,6 +125,12 @@ struct dns_question_hdr {
#define DNS_FORMATERR 0x1 /* RCODE - Format Error */
#define DNS_NOERR 0x0 /* RCODE - No error */
+/* When DNS_NOTAUTH, add a TSIG header with the following error codes */
+
+#define DNS_BADTIME 0x12 /* RCODE (18) BADTIME RFC 2845 p. 3 */
+#define DNS_BADKEY 0x11 /* RCODE (17) BADKEY RFC 2845 p. 3 */
+#define DNS_BADSIG 0x10 /* RCODE (16) BADSIG RFC 2845 p. 3 */
+
/*
* macros to set flags (must be converted to network byte order after)
*/
@@ -136,6 +150,7 @@ struct dns_question_hdr {
#define SET_DNS_RCODE_SERVFAIL(x) ((x)->query |= (DNS_SERVFAIL))
#define SET_DNS_RCODE_FORMATERR(x) ((x)->query |= (DNS_FORMATERR))
#define SET_DNS_RCODE_NOERR(x) ((x)->query |= (DNS_NOERR))
+#define SET_DNS_RCODE_NOTAUTH(x) ((x)->query |= (DNS_NOTAUTH))
#define UNSET_DNS_NOTIFY(x) ((x)->query &= ~(DNS_NOTIFY))
#define UNSET_DNS_STATUS_REQ(x) ((x)->query &= ~(DNS_SREQ))
@@ -150,6 +165,7 @@ struct dns_question_hdr {
#define UNSET_DNS_RCODE_SERVFAIL(x) ((x)->query &= ~(DNS_SERVFAIL))
#define UNSET_DNS_RCODE_FORMATERR(x) ((x)->query &= ~(DNS_FORMATERR))
#define UNSET_DNS_RCODE_NOERR(x) ((x)->query &= ~(DNS_NOERR))
+#define UNSET_DNS_RCODE_NOTAUTH(x) ((x)->query &= ~(DNS_NOTAUTH))
/* DNSSEC/EDNS0 options RFC 3225 */
@@ -228,6 +244,16 @@ struct question {
int rd;
int dnssecok;
int badvers;
+ int tsigverified;
+ int tsigerrorcode;
+ char tsigalg[DNS_MAXNAME];
+ int tsigalglen;
+ char tsigkey[DNS_MAXNAME];
+ int tsigkeylen;
+ char tsigmac[32];
+ int tsigmaclen;
+ u_int64_t tsig_timefudge;
+ u_int16_t tsigorigid;
};
struct parsequestion {
@@ -241,12 +267,24 @@ struct parsequestion {
int rd;
int dnssecok;
int badvers;
+ int tsigverified;
+ int tsigerrorcode; /* see above ie. DNS_BADTIME */
+ char tsigalg[DNS_MAXNAME];
+ int tsigalglen;
+ char tsigkey[DNS_MAXNAME];
+ int tsigkeylen;
+ char tsigmac[32];
+ int tsigmaclen;
+ u_int64_t tsig_timefudge;
+ u_int16_t tsigorigid;
+
int rc; /* return code */
#define PARSE_RETURN_ACK 0
#define PARSE_RETURN_NAK 1
#define PARSE_RETURN_MALFORMED 2
#define PARSE_RETURN_NOQUESTION 3
#define PARSE_RETURN_NOTAQUESTION 4
+#define PARSE_RETURN_NOTAUTH 5
};
blob - 1947895d395530491001507f0ba25f32ccb01d8c
blob + 8079b6973dfc5848814f8eded406fec23d05ec9d
--- dddctl.c
+++ dddctl.c
@@ -27,7 +27,7 @@
*/
/*
- * $Id: dddctl.c,v 1.55 2019/02/19 14:20:25 pjp Exp $
+ * $Id: dddctl.c,v 1.56 2019/02/24 07:14:02 pjp Exp $
*/
#include "ddd-include.h"
@@ -215,12 +215,17 @@ int insert_region(char *, char *);
int insert_filter(char *, char *);
int insert_whitelist(char *, char *);
int insert_notifyslave(char *, char *);
+int insert_tsig(char *, char *);
+int find_tsig_key(char *, int, char *, int);
+int insert_tsig_key(char *, int, char *);
+
int illdestination;
int *ptr = &illdestination;
int notify = 0;
int whitelist = 0;
+int tsig = 0;
int bcount = 0;
char *bind_list[255];
char *interface_list[255];
@@ -828,6 +833,18 @@ insert_whitelist(char *address, char *prefixlen)
}
int
+insert_tsig(char *address, char *prefixlen)
+{
+ return 0;
+}
+
+int
+insert_tsig_key(char *key, int keylen, char *authkey)
+{
+ return 0;
+}
+
+int
insert_notifyslave(char *address, char *prefixlen)
{
return 0;
@@ -8435,4 +8452,10 @@ count_db(ddDB *db)
printf("Records = %d , ", count);
return count;
+}
+
+int
+find_tsig_key(char *keyname, int keynamelen, char *key, int keylen)
+{
+ return -1;
}
blob - 54bd75d8cf5ad6cdd154922e1dbca216f4f8fada
blob + 3f351963aebd78f9cafc08fbe305117046c7154c
--- 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 ent.c db.c imsg-buffer.c imsg.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 db.c imsg-buffer.c imsg.c tsig.c
CFLAGS= -Wall -g
CFLAGS+= -I${.CURDIR}/..
blob - f58038a88de836bf18f4aeb0d97392cf75ee8d85
blob + 56deaf698d836744615b463e20f9e7de3696acb0
--- 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 ent.c db.c imsg-buffer.c imsg.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 db.c imsg-buffer.c imsg.c tsig.c
CFLAGS= -g
CFLAGS+= -I${.CURDIR}/..
blob - 19028c2d66d489ed7e95d8d98bf538ef57062444
blob + 53c4e02b8775a013a46e4ea43f6a3aea68819c16
--- 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 ent.c db.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 db.c tsig.c
#CFLAGS= -DDEBUG -g -Wall
CFLAGS= -Wall -g
blob - 54d883104ef3f5145c3bcacdbb90bf50112504df
blob + e7fe2f0adfe1981410fa9bfc74c9d82b32381b34
--- delphinusdnsd.c
+++ delphinusdnsd.c
@@ -27,7 +27,7 @@
*/
/*
- * $Id: delphinusdnsd.c,v 1.54 2019/02/18 15:04:21 pjp Exp $
+ * $Id: delphinusdnsd.c,v 1.55 2019/02/24 07:14:02 pjp Exp $
*/
#include "ddd-include.h"
@@ -48,13 +48,15 @@ extern int find_axfr(struct sockaddr_storage *, i
extern int find_filter(struct sockaddr_storage *, int);
extern u_int8_t find_region(struct sockaddr_storage *, int);
extern int find_whitelist(struct sockaddr_storage *, int);
+extern int find_tsig(struct sockaddr_storage *, int);
extern char * get_dns_type(int, int);
extern void init_dnssec(void);
extern void init_region(void);
extern int init_entlist(ddDB *);
extern void init_filter(void);
-extern void init_notifyslave(void);
extern void init_whitelist(void);
+extern void init_tsig(void);
+extern void init_notifyslave(void);
extern struct rbtree * lookup_zone(ddDB *, struct question *, int *, int *, char *);
extern int memcasecmp(u_char *, u_char *, int);
extern void receivelog(char *, int);
@@ -65,6 +67,7 @@ extern int reply_badvers(struct sreply *, ddDB *);
extern int reply_nodata(struct sreply *, ddDB *);
extern int reply_cname(struct sreply *, ddDB *);
extern int reply_fmterror(struct sreply *, ddDB *);
+extern int reply_notauth(struct sreply *, ddDB *);
extern int reply_notimpl(struct sreply *, ddDB *);
extern int reply_nxdomain(struct sreply *, ddDB *);
extern int reply_noerror(struct sreply *, ddDB *);
@@ -90,7 +93,7 @@ extern char *rrlimit_setup(int);
extern char *dns_label(char *, int *);
extern void slave_shutdown(void);
extern int get_record_size(ddDB *, char *, int);
-extern struct question *build_question(char *, int, int);
+extern struct question *build_question(char *, int, int, int);
extern int free_question(struct question *);
extern struct rbtree * create_rr(ddDB *db, char *name, int len, int type, void *rdata);
extern struct rbtree * find_rrset(ddDB *db, char *name, int len);
@@ -171,6 +174,7 @@ extern int axfrport;
extern int ratelimit;
extern int ratelimit_packets_per_second;
extern int whitelist;
+extern int tsig;
extern int dnssec;
static int reload = 0;
@@ -432,6 +436,7 @@ main(int argc, char *argv[], char *environ[])
init_whitelist();
init_notifyslave();
init_dnssec();
+ init_tsig();
if (parse_file(db, conffile) < 0) {
dolog(LOG_INFO, "parsing config file failed\n");
@@ -1344,11 +1349,13 @@ mainloop(struct cfg *cfg, struct imsgbuf **ibuf)
int filter = 0;
int rcheck = 0;
int blacklist = 1;
+ int require_tsig = 0;
int sp;
int lfd;
int idata;
u_int32_t received_ttl;
+ u_int32_t imsg_type;
u_char *ttlptr;
u_int8_t aregion; /* region where the address comes from */
@@ -1606,6 +1613,12 @@ axfrentry:
if (whitelist) {
blacklist = find_whitelist((struct sockaddr_storage *)sin6, AF_INET6);
}
+
+ require_tsig = 0;
+ if (tsig) {
+ require_tsig = find_tsig((struct sockaddr_storage *)sin6, AF_INET6);
+ }
+
} else if (from->sa_family == AF_INET) {
is_ipv6 = 0;
@@ -1624,6 +1637,11 @@ axfrentry:
blacklist = find_whitelist((struct sockaddr_storage *)sin, AF_INET);
}
+ require_tsig = 0;
+ if (tsig) {
+ require_tsig = find_tsig((struct sockaddr_storage *)sin, AF_INET);
+ }
+
} else {
dolog(LOG_INFO, "packet received on descriptor %u interface \"%s\" had weird address family (%u), drop\n", so, cfg->ident[i], from->sa_family);
goto drop;
@@ -1635,7 +1653,7 @@ axfrentry:
goto drop;
}
- if (filter) {
+ if (filter && require_tsig == 0) {
build_reply(&sreply, so, buf, len, NULL, from, fromlen, NULL, NULL, aregion, istcp, 0, NULL, replybuf);
slen = reply_refused(&sreply, NULL);
@@ -1659,8 +1677,12 @@ axfrentry:
}
/* pjp - branch to pledge parser here */
-
- if (imsg_compose(pibuf, IMSG_PARSE_MESSAGE,
+ if (require_tsig)
+ imsg_type = IMSG_PARSEAUTH_MESSAGE;
+ else
+ imsg_type = IMSG_PARSE_MESSAGE;
+
+ if (imsg_compose(pibuf, imsg_type,
0, 0, -1, buf, len) < 0) {
dolog(LOG_INFO, "imsg_compose %s\n", strerror(errno));
}
@@ -1734,8 +1756,17 @@ axfrentry:
dolog(LOG_INFO, "on descriptor %u interface \"%s\" illegal dns packet length from %s, drop\n", so, cfg->ident[i], address);
imsg_free(&imsg);
goto drop;
+ case PARSE_RETURN_NOTAUTH:
+ /* we didn't see a tsig header */
+ if (pq.tsigerrorcode == 1) {
+ build_reply(&sreply, so, buf, len, NULL, from, fromlen, NULL, NULL, aregion, istcp, 0, NULL, replybuf);
+ slen = reply_refused(&sreply, NULL);
+ dolog(LOG_INFO, "UDP connection refused on descriptor %u interface \"%s\" from %s (ttl=%d, region=%d) replying REFUSED, not a tsig\n", so, cfg->ident[i], address, received_ttl, aregion);
+ imsg_free(&imsg);
+ goto drop;
+ }
}
- }
+ }
question = convert_question(&pq);
if (question == NULL) {
@@ -1743,6 +1774,7 @@ axfrentry:
imsg_free(&imsg);
goto drop;
}
+
break;
@@ -1756,12 +1788,19 @@ axfrentry:
/* goto drop beyond this point should goto out instead */
+ if (require_tsig && question->tsigerrorcode != 0) {
+ dolog(LOG_INFO, "on descriptor %u interface \"%s\" not authenticated dns packet (code = %d) from %s, replying notauth\n", so, cfg->ident[i], question->tsigerrorcode, address);
+ snprintf(replystring, DNS_MAXNAME, "NOTAUTH");
+ build_reply(&sreply, so, buf, len, question, from, fromlen, NULL, NULL, aregion, istcp, 0, NULL, replybuf);
+ reply_notauth(&sreply, NULL);
+ goto udpout;
+ }
/* hack around whether we're edns version 0 */
if (question->ednsversion != 0) {
build_reply(&sreply, so, buf, len, question, from, fromlen, NULL, NULL, aregion, istcp, 0, NULL, replybuf);
slen = reply_badvers(&sreply, NULL);
- dolog(LOG_INFO, "on descriptor %u interface \"%s\" edns version is %u from %s, replying badvers\n", so, cfg->ident[i], question->ednsversion, address);
+ dolog(LOG_INFO, "on TCP descriptor %u interface \"%s\" edns version is %u from %s, replying badvers\n", so, cfg->ident[i], question->ednsversion, address);
snprintf(replystring, DNS_MAXNAME, "BADVERS");
goto udpout;
@@ -1960,7 +1999,7 @@ axfrentry:
udpout:
if (lflag) {
- dolog(LOG_INFO, "request on descriptor %u interface \"%s\" from %s (ttl=%u, region=%d) for \"%s\" type=%s class=%u, %s%sanswering \"%s\" (%d/%d)\n", so, cfg->ident[i], address, received_ttl, aregion, question->converted_name, get_dns_type(ntohs(question->hdr->qtype), 1), ntohs(question->hdr->qclass), (question->edns0len ? "edns0, " : ""), (question->dnssecok ? "dnssecok, " : "") , replystring, len, slen);
+ dolog(LOG_INFO, "request on descriptor %u interface \"%s\" from %s (ttl=%u, region=%d) for \"%s\" type=%s class=%u, %s%s%sanswering \"%s\" (%d/%d)\n", so, cfg->ident[i], address, received_ttl, aregion, question->converted_name, get_dns_type(ntohs(question->hdr->qtype), 1), ntohs(question->hdr->qclass), (question->edns0len ? "edns0, " : ""), (question->dnssecok ? "dnssecok, " : ""), (question->tsigverified ? "tsig, " : "") , replystring, len, slen);
}
@@ -2230,6 +2269,7 @@ tcploop(struct cfg *cfg, struct imsgbuf **ibuf)
int lzerrno;
int filter = 0;
int blacklist = 1;
+ int require_tsig = 0;
int axfr_acl = 0;
int sp;
int lfd;
@@ -2270,6 +2310,7 @@ tcploop(struct cfg *cfg, struct imsgbuf **ibuf)
struct parsequestion pq;
ssize_t n, datalen;
+ u_int32_t imsg_type;
if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, &cfg->my_imsg[MY_IMSG_PARSER].imsg_fds[0]) < 0) {
dolog(LOG_INFO, "socketpair() failed\n");
@@ -2384,6 +2425,11 @@ tcploop(struct cfg *cfg, struct imsgbuf **ibuf)
blacklist = find_whitelist((struct sockaddr_storage *)sin6, AF_INET6);
}
axfr_acl = find_axfr((struct sockaddr_storage *)sin6, AF_INET6);
+
+ require_tsig = 0;
+ if (tsig) {
+ require_tsig = find_tsig((struct sockaddr_storage *)sin6, AF_INET6);
+ }
} else if (from->sa_family == AF_INET) {
is_ipv6 = 0;
@@ -2396,6 +2442,11 @@ tcploop(struct cfg *cfg, struct imsgbuf **ibuf)
blacklist = find_whitelist((struct sockaddr_storage *)sin, AF_INET);
}
axfr_acl = find_axfr((struct sockaddr_storage *)sin, AF_INET);
+
+ require_tsig = 0;
+ if (tsig) {
+ require_tsig = find_tsig((struct sockaddr_storage *)sin, AF_INET);
+ }
} else {
dolog(LOG_INFO, "TCP packet received on descriptor %u interface \"%s\" had weird address family (%u), drop\n", so, cfg->ident[i], from->sa_family);
close(so);
@@ -2403,7 +2454,7 @@ tcploop(struct cfg *cfg, struct imsgbuf **ibuf)
}
- if (filter) {
+ if (filter && require_tsig == 0) {
dolog(LOG_INFO, "TCP connection refused on descriptor %u interface \"%s\" from %s, filter policy\n", so, cfg->ident[i], address);
close(so);
continue;
@@ -2474,8 +2525,13 @@ tcploop(struct cfg *cfg, struct imsgbuf **ibuf)
}
/* pjp send to parseloop */
+ if (require_tsig)
+ imsg_type = IMSG_PARSEAUTH_MESSAGE;
+ else
+ imsg_type = IMSG_PARSE_MESSAGE;
+
- if (imsg_compose(pibuf, IMSG_PARSE_MESSAGE,
+ if (imsg_compose(pibuf, imsg_type,
0, 0, -1, pbuf, len) < 0) {
dolog(LOG_INFO, "imsg_compose %s\n", strerror(errno));
}
@@ -2548,6 +2604,14 @@ tcploop(struct cfg *cfg, struct imsgbuf **ibuf)
dolog(LOG_INFO, "TCP packet on descriptor %u interface \"%s\" illegal dns packet length from %s, drop\n", so, cfg->ident[i], address);
imsg_free(&imsg);
goto drop;
+ case PARSE_RETURN_NOTAUTH:
+ if (pq.tsigerrorcode == 1) {
+ build_reply(&sreply, so, buf, len, NULL, from, fromlen, NULL, NULL, aregion, istcp, 0, NULL, replybuf);
+ slen = reply_refused(&sreply, NULL);
+ dolog(LOG_INFO, "TCP connection refused on descriptor %u interface \"%s\" from %s (ttl=TCP, region=%d) replying REFUSED, not a tsig\n", so, cfg->ident[i], address, aregion);
+ imsg_free(&imsg);
+ goto drop;
+ }
}
}
@@ -2569,6 +2633,15 @@ tcploop(struct cfg *cfg, struct imsgbuf **ibuf)
/* goto drop beyond this point should goto out instead */
fakequestion = NULL;
+ if (require_tsig && question->tsigerrorcode != 0) {
+ dolog(LOG_INFO, "on TCP descriptor %u interface \"%s\" not authenticated dns packet (code = %d) from %s, replying notauth\n", so, cfg->ident[i], question->tsigerrorcode, address);
+ snprintf(replystring, DNS_MAXNAME, "NOTAUTH");
+ build_reply(&sreply, so, buf, len, question, from, fromlen, NULL, NULL, aregion, istcp, 0, NULL, replybuf);
+ reply_notauth(&sreply, NULL);
+ goto tcpout;
+ }
+ /* hack around whether we're edns version 0 */
+
/*
* we check now for AXFR's in the query and deny if not found
* in our list of AXFR'ers
@@ -2792,7 +2865,7 @@ tcploop(struct cfg *cfg, struct imsgbuf **ibuf)
tcpout:
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 answering \"%s\" (%d/%d)\n", so, cfg->ident[i], address, aregion, question->converted_name, get_dns_type(ntohs(question->hdr->qtype), 1), ntohs(question->hdr->qclass), (question->edns0len) ? "edns0, " : "", (question->dnssecok) ? "dnssecok, " : "", replystring, len, slen);
+ 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[i], address, aregion, question->converted_name, get_dns_type(ntohs(question->hdr->qtype), 1), ntohs(question->hdr->qclass), (question->edns0len) ? "edns0, " : "", (question->dnssecok) ? "dnssecok, " : "", (question->tsigverified ? "tsig, " : ""), replystring, len, slen);
if (fakequestion != NULL) {
@@ -2844,6 +2917,7 @@ parseloop(struct cfg *cfg, struct imsgbuf **ibuf)
char *packet;
fd_set rset;
int sel;
+ int require_tsig = 0;
int fd = mybuf->fd;
ssize_t n, datalen;
@@ -2889,8 +2963,12 @@ parseloop(struct cfg *cfg, struct imsgbuf **ibuf)
}
datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
+ require_tsig = 0;
switch (imsg.hdr.type) {
+ case IMSG_PARSEAUTH_MESSAGE:
+ require_tsig = 1;
+ /* FALLTHROUGH */
case IMSG_PARSE_MESSAGE:
memset(&pq, 0, sizeof(struct parsequestion));
@@ -2934,7 +3012,7 @@ parseloop(struct cfg *cfg, struct imsgbuf **ibuf)
break;
}
- if ((question = build_question(packet, datalen, ntohs(dh->additional))) == NULL) {
+ if ((question = build_question(packet, datalen, ntohs(dh->additional), require_tsig)) == NULL) {
/* XXX reply nak here */
pq.rc = PARSE_RETURN_MALFORMED;
imsg_compose(mybuf, IMSG_PARSEREPLY_MESSAGE, 0, 0, -1, &pq, sizeof(struct parsequestion));
@@ -2953,6 +3031,18 @@ parseloop(struct cfg *cfg, struct imsgbuf **ibuf)
pq.dnssecok = question->dnssecok;
pq.badvers = question->badvers;
pq.rc = PARSE_RETURN_ACK;
+ pq.tsigverified = question->tsigverified;
+ pq.tsigerrorcode = question->tsigerrorcode;
+ if (pq.tsigerrorcode)
+ pq.rc = PARSE_RETURN_NOTAUTH;
+ memcpy(&pq.tsigmac, question->tsigmac, sizeof(pq.tsigmac));
+ pq.tsigmaclen = question->tsigmaclen;
+ memcpy(&pq.tsigkey, question->tsigkey, sizeof(pq.tsigkey));
+ pq.tsigkeylen = question->tsigkeylen;
+ memcpy(&pq.tsigalg, question->tsigalg, sizeof(pq.tsigalg));
+ pq.tsigalglen = question->tsigalglen;
+ pq.tsig_timefudge = question->tsig_timefudge;
+ pq.tsigorigid = question->tsigorigid;
imsg_compose(mybuf, IMSG_PARSEREPLY_MESSAGE, 0, 0, -1, (char *)&pq, sizeof(struct parsequestion));
msgbuf_write(&mybuf->w);
@@ -3020,6 +3110,19 @@ convert_question(struct parsequestion *pq)
q->rd = pq->rd;
q->dnssecok = pq->dnssecok;
q->badvers = pq->badvers;
+ q->tsigverified = pq->tsigverified;
+ q->tsigerrorcode = pq->tsigerrorcode;
+
+ memcpy(&q->tsigmac, pq->tsigmac, sizeof(q->tsigmac));
+ memcpy(&q->tsigalg, pq->tsigalg, sizeof(q->tsigalg));
+ memcpy(&q->tsigkey, pq->tsigkey, sizeof(q->tsigkey));
+
+ q->tsigmaclen = pq->tsigmaclen;
+ q->tsigalglen = pq->tsigalglen;
+ q->tsigkeylen = pq->tsigkeylen;
+
+ q->tsig_timefudge = pq->tsig_timefudge;
+ q->tsigorigid = pq->tsigorigid;
return (q);
}
blob - 93b1e9a2683c637e10da56ac5db582d37ded544b
blob + 1359d2929aecbfcf2a76561d91171a9dab49de5a
--- parse.y
+++ parse.y
@@ -21,7 +21,7 @@
*/
/*
- * $Id: parse.y,v 1.61 2019/02/18 23:51:34 pjp Exp $
+ * $Id: parse.y,v 1.62 2019/02/24 07:14:02 pjp Exp $
*/
%{
@@ -44,6 +44,8 @@ extern int insert_axfr(char *, char *);
extern int insert_notifyslave(char *, char *);
extern int insert_filter(char *, char *);
extern int insert_whitelist(char *, char *);
+extern int insert_tsig(char *, char *);
+extern int insert_tsig_key(char *, int, char *, int);
extern void slave_shutdown(void);
extern int mybase64_encode(u_char const *, size_t, char *, size_t);
extern int mybase64_decode(char const *, u_char *, size_t);
@@ -55,6 +57,7 @@ extern int display_rr(struct rrset *rrset);
extern int whitelist;
+extern int tsig;
extern int notify;
extern int errno;
extern int debug;
@@ -196,7 +199,8 @@ static int pull_remote_zone(struct rzone *);
%token VERSION OBRACE EBRACE REGION RZONE AXFRFOR
%token DOT COLON TEXT WOF INCLUDE ZONE COMMA CRLF
%token ERROR AXFRPORT LOGGING OPTIONS FILTER NOTIFY
-%token WHITELIST ZINCLUDE MASTER MASTERPORT
+%token WHITELIST ZINCLUDE MASTER MASTERPORT TSIGAUTH
+%token TSIG
%token <v.string> POUND
%token <v.string> SEMICOLON
@@ -220,6 +224,7 @@ cmd_list:
cmd :
version
| rzone
+ | tsigauth
| axfrport
| include
| zinclude
@@ -228,6 +233,7 @@ cmd :
| axfr CRLF
| notify CRLF
| whitelist CRLF
+ | tsig CRLF
| filter CRLF
| logging
| comment CRLF
@@ -347,6 +353,27 @@ quotedfilename:
;
+tsigauth:
+ TSIGAUTH STRING QUOTEDSTRING SEMICOLON CRLF {
+ char key[512];
+ char *keyname;
+ int keylen, keynamelen;
+
+ if ((keylen = mybase64_decode($3, key, sizeof(key))) < 0) {
+ dolog(LOG_ERR, "can't decode tsig base64\n");
+ return -1;
+ }
+
+ keyname = dns_label($2, &keynamelen);
+
+ insert_tsig_key(key, keylen, keyname, keynamelen);
+
+ free($2);
+ free($3);
+ free(keyname);
+ }
+ ;
+
rzone:
RZONE rzonelabel rzonecontent {
struct file *nfile;
@@ -1088,7 +1115,61 @@ loggingstatement:
}
| comment CRLF
;
+/* tsig "these hosts" { .. } */
+tsig:
+ TSIG tsiglabel tsigcontent
+ {
+ if ((confstatus & CONFIG_VERSION) != CONFIG_VERSION) {
+ dolog(LOG_INFO, "There must be a version at the top of the first configfile\n");
+ return (-1);
+ }
+ }
+ ;
+
+tsiglabel:
+ QUOTEDSTRING
+ ;
+
+tsigcontent:
+ OBRACE tsigstatements EBRACE
+ | OBRACE CRLF tsigstatements EBRACE
+ ;
+
+tsigstatements :
+ tsigstatements tsigstatement
+ | tsigstatement
+ ;
+
+tsigstatement : ipcidr SEMICOLON CRLF
+ {
+ char prefixlength[INET_ADDRSTRLEN];
+ char *dst;
+
+
+ if (file->descend == DESCEND_YES) {
+ if ((dst = get_prefixlen($1, (char *)&prefixlength, sizeof(prefixlength))) == NULL) {
+ return (-1);
+ }
+
+ if (insert_tsig(dst, prefixlength) < 0) {
+ dolog(LOG_ERR, "insert_tsig, line %d\n", file->lineno);
+ return (-1);
+ }
+
+ if (debug)
+ printf("tsig inserted %s address\n", $1);
+
+ tsig = 1;
+
+ free (dst);
+ }
+
+ free ($1);
+ }
+ | comment CRLF
+ ;
+
/* whitelist "these hosts" { .. } */
whitelist:
@@ -1386,6 +1467,8 @@ struct tab cmdtab[] = {
{ "options", OPTIONS, 0 },
{ "region", REGION, STATE_IP },
{ "rzone", RZONE, 0 },
+ { "tsig", TSIG, 0 },
+ { "tsig-auth", TSIGAUTH, 0 },
{ "wildcard-only-for", WOF, STATE_IP },
{ "version", VERSION, 0 },
{ "zinclude", ZINCLUDE, 0 },
blob - 5fe18281f4472338c391b77abd9869b0ccb40a70
blob + 7a05d60d70b927c40927f42e226444115ae40d98
--- raxfr.c
+++ raxfr.c
@@ -26,7 +26,7 @@
*
*/
/*
- * $Id: raxfr.c,v 1.10 2019/02/15 15:11:34 pjp Exp $
+ * $Id: raxfr.c,v 1.11 2019/02/24 07:14:02 pjp Exp $
*/
#include "ddd-include.h"
@@ -54,7 +54,6 @@ u_int16_t raxfr_skip(FILE *, u_char *, u_char *);
int raxfr_soa(FILE *, u_char *, u_char *, u_char *, struct soa *, int, u_int32_t, u_int16_t);
int raxfr_peek(FILE *, u_char *, u_char *, u_char *, int *, int, u_int16_t *, u_int32_t);
-static char * expand_compression(u_char *, u_char *, u_char *, u_char *, int *, int);
extern int memcasecmp(u_char *, u_char *, int);
extern char * dns_label(char *, int *);
@@ -65,6 +64,7 @@ extern char *bitmap2human(char *, int);
extern char *convert_name(char *, int);
extern char *base32hex_encode(u_char *, int);
extern u_int64_t timethuman(time_t);
+extern char * expand_compression(u_char *, u_char *, u_char *, u_char *, int *, int);
/* The following alias helps with bounds checking all input, needed! */
@@ -77,58 +77,6 @@ extern u_int64_t timethuman(time_t);
} while (0)
-static char *
-expand_compression(u_char *p, u_char *estart, u_char *end, u_char *expand, int *elen, int max)
-{
- u_short tlen;
- u_char *save = NULL;
- u_int16_t *offset;
-
- /* expand name */
- while ((u_char)*p && p <= end) {
- /* test for compression */
- if ((*p & 0xc0) == 0xc0) {
- /* do not allow recursive compress pointers */
- if (! save) {
- save = p + 2;
- }
- offset = (u_int16_t *)p;
- /* do not allow forwards jumping */
- if ((p - estart) <= (ntohs(*offset) & (~0xc000))) {
- return NULL;
- }
-
- p = (estart + (ntohs(*offset) & (~0xc000)));
- } else {
- if (*elen + 1 >= max) {
- return NULL;
- }
- expand[(*elen)] = *p;
- (*elen)++;
- tlen = *p;
- p++;
- memcpy(&expand[*elen], p, tlen);
- p += tlen;
- if (*elen + tlen >= max) {
- return NULL;
- }
- *elen += tlen;
- }
- }
-
- if (p > end) {
- return NULL;
- }
-
- if (save == NULL) {
- p++;
- (*elen)++;
- return (p);
- } else {
- (*elen)++;
- return (save);
- }
-}
int
raxfr_peek(FILE *f, u_char *p, u_char *estart, u_char *end, int *rrtype, int soacount, u_int16_t *rdlen, u_int32_t format)
blob - 11471fa097c6c99e4f83f8ff15b23f85604edc1b
blob + e6954e8940d6e008dbd2491b76b8cba81217a040
--- reply.c
+++ reply.c
@@ -27,7 +27,7 @@
*/
/*
- * $Id: reply.c,v 1.68 2019/02/18 14:59:55 pjp Exp $
+ * $Id: reply.c,v 1.69 2019/02/24 07:14:02 pjp Exp $
*/
#include "ddd-include.h"
@@ -44,6 +44,7 @@ extern int additional_aaaa(char *, int, struct rbtre
extern int additional_mx(char *, int, struct rbtree *, char *, int, int, int *);
extern int additional_ptr(char *, int, struct rbtree *, char *, int, int, int *);
extern int additional_opt(struct question *, char *, int, int);
+extern int additional_tsig(struct question *, char *, int, int, int);
extern int additional_rrsig(char *, int, int, struct rbtree *, char *, int, int, int);
extern int additional_nsec(char *, int, int, struct rbtree *, char *, int, int);
extern struct question *build_fake_question(char *, int, u_int16_t);
@@ -90,6 +91,7 @@ int reply_cname(struct sreply *, ddDB *);
int reply_any(struct sreply *, ddDB *);
int reply_refused(struct sreply *, ddDB *);
int reply_fmterror(struct sreply *, ddDB *);
+int reply_notauth(struct sreply *, ddDB *);
struct rbtree * find_nsec(char *name, int namelen, struct rbtree *, ddDB *db);
int nsec_comp(const void *a, const void *b);
char * convert_name(char *name, int namelen);
@@ -261,6 +263,14 @@ out:
outlen = additional_opt(q, reply, replysize, outlen);
}
+ if (q->tsigverified == 1) {
+ outlen = additional_tsig(q, reply, replysize, outlen, 0);
+
+ NTOHS(odh->additional);
+ odh->additional++;
+ HTONS(odh->additional);
+ }
+
if (istcp) {
char *tmpbuf;
u_int16_t *plen;
@@ -463,6 +473,15 @@ out:
outlen = additional_opt(q, reply, replysize, outlen);
}
+ if (q->tsigverified == 1) {
+ outlen = additional_tsig(q, reply, replysize, outlen, 0);
+
+ NTOHS(odh->additional);
+ odh->additional++;
+ HTONS(odh->additional);
+ }
+
+
if (istcp) {
char *tmpbuf;
u_int16_t *plen;
@@ -679,6 +698,14 @@ out:
outlen = additional_opt(q, reply, replysize, outlen);
}
+ if (q->tsigverified == 1) {
+ outlen = additional_tsig(q, reply, replysize, outlen, 0);
+
+ NTOHS(odh->additional);
+ odh->additional++;
+ HTONS(odh->additional);
+ }
+
if (istcp) {
char *tmpbuf;
u_int16_t *plen;
@@ -866,6 +893,14 @@ out:
outlen = additional_opt(q, reply, replysize, outlen);
}
+ if (q->tsigverified == 1) {
+ outlen = additional_tsig(q, reply, replysize, outlen, 0);
+
+ NTOHS(odh->additional);
+ odh->additional++;
+ HTONS(odh->additional);
+ }
+
if (istcp) {
char *tmpbuf;
u_int16_t *plen;
@@ -1051,6 +1086,14 @@ out:
outlen = additional_opt(q, reply, replysize, outlen);
}
+ if (q->tsigverified == 1) {
+ outlen = additional_tsig(q, reply, replysize, outlen, 0);
+
+ NTOHS(odh->additional);
+ odh->additional++;
+ HTONS(odh->additional);
+ }
+
if (istcp) {
char *tmpbuf;
u_int16_t *plen;
@@ -1254,6 +1297,14 @@ out:
outlen = additional_opt(q, reply, replysize, outlen);
}
+ if (q->tsigverified == 1) {
+ outlen = additional_tsig(q, reply, replysize, outlen, 0);
+
+ NTOHS(odh->additional);
+ odh->additional++;
+ HTONS(odh->additional);
+ }
+
if (istcp) {
char *tmpbuf;
u_int16_t *plen;
@@ -1398,6 +1449,14 @@ out:
outlen = additional_opt(q, reply, replysize, outlen);
}
+ if (q->tsigverified == 1) {
+ outlen = additional_tsig(q, reply, replysize, outlen, 0);
+
+ NTOHS(odh->additional);
+ odh->additional++;
+ HTONS(odh->additional);
+ }
+
if (istcp) {
char *tmpbuf;
u_int16_t *plen;
@@ -1562,6 +1621,15 @@ out:
outlen = additional_opt(q, reply, replysize, outlen);
}
+ if (q->tsigverified == 1) {
+ outlen = additional_tsig(q, reply, replysize, outlen, 0);
+
+ NTOHS(odh->additional);
+ odh->additional++;
+ HTONS(odh->additional);
+ }
+
+
if (istcp) {
char *tmpbuf;
u_int16_t *plen;
@@ -1712,7 +1780,7 @@ reply_mx(struct sreply *sreply, ddDB *db)
mx_count++;
}
- odh->answer = htonl(mx_count);
+ odh->answer = htons(mx_count);
/* RRSIG reply_mx*/
@@ -1749,6 +1817,14 @@ out:
outlen = additional_opt(q, reply, replysize, outlen);
}
+ if (q->tsigverified == 1) {
+ outlen = additional_tsig(q, reply, replysize, outlen, 0);
+
+ NTOHS(odh->additional);
+ odh->additional++;
+ HTONS(odh->additional);
+ }
+
if (istcp) {
char *tmpbuf;
@@ -1940,6 +2016,14 @@ out:
outlen = additional_opt(q, reply, replysize, outlen);
}
+ if (q->tsigverified == 1) {
+ outlen = additional_tsig(q, reply, replysize, outlen, 0);
+
+ NTOHS(odh->additional);
+ odh->additional++;
+ HTONS(odh->additional);
+ }
+
if (istcp) {
char *tmpbuf;
@@ -2248,6 +2332,14 @@ out:
outlen = additional_opt(q, reply, replysize, outlen);
}
+ if (q->tsigverified == 1) {
+ outlen = additional_tsig(q, reply, replysize, outlen, 0);
+
+ NTOHS(odh->additional);
+ odh->additional++;
+ HTONS(odh->additional);
+ }
+
if (istcp) {
char *tmpbuf;
@@ -2429,6 +2521,14 @@ out:
outlen = additional_opt(q, reply, replysize, outlen);
}
+ if (q->tsigverified == 1) {
+ outlen = additional_tsig(q, reply, replysize, outlen, 0);
+
+ NTOHS(odh->additional);
+ odh->additional++;
+ HTONS(odh->additional);
+ }
+
if (istcp) {
char *tmpbuf;
u_int16_t *plen;
@@ -2680,6 +2780,14 @@ out:
}
+ if (q->tsigverified == 1) {
+ outlen = additional_tsig(q, reply, replysize, outlen, 0);
+
+ NTOHS(odh->additional);
+ odh->additional++;
+ HTONS(odh->additional);
+ }
+
if (istcp) {
char *tmpbuf;
u_int16_t *plen;
@@ -2844,7 +2952,15 @@ out:
outlen = additional_opt(q, reply, replysize, outlen);
}
+ if (q->tsigverified == 1) {
+ outlen = additional_tsig(q, reply, replysize, outlen, 0);
+ NTOHS(odh->additional);
+ odh->additional++;
+ HTONS(odh->additional);
+ }
+
+
if (istcp) {
char *tmpbuf;
u_int16_t *plen;
@@ -3157,6 +3273,14 @@ out:
outlen = additional_opt(q, reply, replysize, outlen);
}
+ if (q->tsigverified == 1) {
+ outlen = additional_tsig(q, reply, replysize, outlen, 0);
+
+ NTOHS(odh->additional);
+ odh->additional++;
+ HTONS(odh->additional);
+ }
+
if (istcp) {
char *tmpbuf;
@@ -3337,6 +3461,14 @@ out:
outlen = additional_opt(q, reply, replysize, outlen);
}
+ if (q->tsigverified == 1) {
+ outlen = additional_tsig(q, reply, replysize, outlen, 0);
+
+ NTOHS(odh->additional);
+ odh->additional++;
+ HTONS(odh->additional);
+ }
+
if (istcp) {
char *tmpbuf;
@@ -3552,6 +3684,14 @@ out:
outlen = additional_opt(q, reply, replysize, outlen);
}
+ if (q->tsigverified == 1) {
+ outlen = additional_tsig(q, reply, replysize, outlen, 0);
+
+ NTOHS(odh->additional);
+ odh->additional++;
+ HTONS(odh->additional);
+ }
+
if (istcp) {
char *tmpbuf;
@@ -3738,6 +3878,14 @@ out:
outlen = additional_opt(q, reply, replysize, outlen);
}
+ if (q->tsigverified == 1) {
+ outlen = additional_tsig(q, reply, replysize, outlen, 0);
+
+ NTOHS(odh->additional);
+ odh->additional++;
+ HTONS(odh->additional);
+ }
+
if (istcp) {
char *tmpbuf;
@@ -4205,6 +4353,14 @@ out:
}
+ if (q->tsigverified == 1) {
+ outlen = additional_tsig(q, reply, replysize, outlen, 0);
+
+ NTOHS(odh->additional);
+ odh->additional++;
+ HTONS(odh->additional);
+ }
+
if (istcp) {
char *tmpbuf;
u_int16_t *plen;
@@ -4301,6 +4457,93 @@ reply_refused(struct sreply *sreply, ddDB *db)
}
/*
+ * REPLY_NOTAUTH() - replies a DNS question (*q) on socket (so)
+ *
+ */
+
+int
+reply_notauth(struct sreply *sreply, ddDB *db)
+{
+ char *reply = sreply->replybuf;
+ struct dns_header *odh;
+ u_int16_t outlen = 0;
+ u_int16_t tmplen;
+
+ int so = sreply->so;
+ int len = sreply->len;
+ char *buf = sreply->buf;
+ struct sockaddr *sa = sreply->sa;
+ int salen = sreply->salen;
+ int istcp = sreply->istcp;
+ int replysize = 512;
+ int retlen = -1;
+
+ struct question *q = sreply->q;
+
+ if (istcp) {
+ replysize = 65535;
+ }
+
+ memset(reply, 0, replysize);
+
+ odh = (struct dns_header *)&reply[0];
+
+
+ if (len > replysize) {
+ return (retlen);
+ }
+
+ memset((char *)&odh->query, 0, sizeof(u_int16_t));
+
+ /* copy question to reply */
+ if (istcp)
+ memcpy(&reply[0], &buf[2], sizeof(struct dns_header) + q->hdr->namelen + 4);
+ else
+ memcpy(&reply[0], buf, sizeof(struct dns_header) + q->hdr->namelen + 4);
+
+
+ outlen += (sizeof(struct dns_header) + q->hdr->namelen + 4);
+
+
+ SET_DNS_REPLY(odh);
+ SET_DNS_RCODE_NOTAUTH(odh);
+
+ HTONS(odh->query);
+
+ odh->additional = htons(1);
+
+ tmplen = additional_tsig(q, reply, replysize, outlen, 0);
+
+ if (tmplen != 0)
+ outlen = tmplen;
+
+ 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_FMTERROR() - replies a DNS question (*q) on socket (so)
*
*/
@@ -4671,6 +4914,14 @@ out:
outlen = additional_opt(q, reply, replysize, outlen);
}
+ if (q->tsigverified == 1) {
+ outlen = additional_tsig(q, reply, replysize, outlen, 0);
+
+ NTOHS(odh->additional);
+ odh->additional++;
+ HTONS(odh->additional);
+ }
+
if (istcp) {
char *tmpbuf;
u_int16_t *plen;
@@ -4804,6 +5055,14 @@ reply_any(struct sreply *sreply, ddDB *db)
outlen = additional_opt(q, reply, replysize, outlen);
}
+ if (q->tsigverified == 1) {
+ outlen = additional_tsig(q, reply, replysize, outlen, 0);
+
+ NTOHS(odh->additional);
+ odh->additional++;
+ HTONS(odh->additional);
+ }
+
if (istcp) {
char *tmpbuf;
u_int16_t *plen;
blob - bf7d88b0a6c8a956a88a82da5c9322c9fbdc5109
blob + c1bf340f7f1b58808ef0975d6b4732475bb09677
--- util.c
+++ util.c
@@ -27,7 +27,7 @@
*/
/*
- * $Id: util.c,v 1.22 2019/02/19 00:15:13 pjp Exp $
+ * $Id: util.c,v 1.23 2019/02/24 07:14:02 pjp Exp $
*/
#include "ddd-include.h"
@@ -35,6 +35,9 @@
#include "ddd-db.h"
#include "ddd-config.h"
+#include <openssl/evp.h>
+#include <openssl/hmac.h>
+
/* prototypes */
@@ -48,14 +51,17 @@ struct question *build_fake_question(char *, int, u_i
char *get_dns_type(int, int);
int memcasecmp(u_char *, u_char *, int);
-struct question *build_question(char *, int, int);
+struct question *build_question(char *, int, int, int);
int free_question(struct question *);
struct rrtab *rrlookup(char *);
+char * expand_compression(u_char *, u_char *, u_char *, u_char *, int *, int);
+void log_diff(char *sha256, char *mac, int len);
/* externs */
extern int debug;
extern int *ptr;
+extern int tsig;
extern void dolog(int, char *, ...);
@@ -65,6 +71,7 @@ extern struct rrset * find_rr(struct rbtree *rbt, u_in
extern int add_rr(struct rbtree *rbt, char *name, int len, u_int16_t rrtype, void *rdata);
extern int display_rr(struct rrset *rrset);
extern int check_ent(char *, int);
+extern int find_tsig_key(char *, int, char *, int);
/* internals */
@@ -608,9 +615,10 @@ memcasecmp(u_char *b1, u_char *b2, int len)
*/
struct question *
-build_question(char *buf, int len, int additional)
+build_question(char *buf, int len, int additional, int require_tsig)
{
- u_int i;
+ char pseudo_packet[4096]; /* for tsig */
+ u_int rollback, i;
u_int namelen = 0;
u_int16_t *qtype, *qclass;
u_int32_t ttl;
@@ -618,6 +626,7 @@ build_question(char *buf, int len, int additional)
char *p, *end_name = NULL;
+ struct dns_tsigrr *tsigrr = NULL;
struct dns_optrr *opt = NULL;
struct question *q = NULL;
struct dns_header *hdr = (struct dns_header *)buf;
@@ -756,26 +765,33 @@ build_question(char *buf, int len, int additional)
*p++ = '.';
*p = '\0';
+ i += (2 * sizeof(u_int16_t)) + 1; /* trailing NUL and type,class*/
/* check for edns0 opt rr */
do {
/* if we don't have an additional section, break */
- if (additional != 1)
+ if (additional < 1)
break;
- i += (2 * sizeof(u_int16_t)) + 1;
+ rollback = i;
/* check that the minimum optrr fits */
/* 10 */
- if (i + sizeof(struct dns_optrr) > len)
+ if (i + sizeof(struct dns_optrr) > len) {
+ i = rollback;
break;
+ }
opt = (struct dns_optrr *)&buf[i];
- if (opt->name[0] != 0)
+ if (opt->name[0] != 0) {
+ i = rollback;
break;
+ }
- if (ntohs(opt->type) != DNS_TYPE_OPT)
+ if (ntohs(opt->type) != DNS_TYPE_OPT) {
+ i = rollback;
break;
+ }
/* RFC 3225 */
ttl = ntohl(opt->ttl);
@@ -788,8 +804,251 @@ build_question(char *buf, int len, int additional)
if (ttl & DNSSEC_OK)
q->dnssecok = 1;
+
+ i += 11 + ntohs(opt->rdlen);
+ // i += sizeof(struct dns_optrr);
+ 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 *pb;
+ char expand[DNS_MAXNAME + 1];
+ char tsigkey[512];
+ u_char sha256[32];
+ u_int shasize = sizeof(sha256);
+ time_t now, tsigtime;
+ int pseudolen1, pseudolen2, ppoffset = 0;
+ int pseudolen3 , pseudolen4;
+ /* if we don't have an additional section, break */
+ if (additional < 1) {
+ break;
+ }
+
+ if (require_tsig == 0) {
+ break;
+ }
+
+ memset(q->tsigkey, 0, sizeof(q->tsigkey));
+ memset(q->tsigalg, 0, sizeof(q->tsigalg));
+ memset(q->tsigmac, 0, sizeof(q->tsigmac));
+ q->tsigkeylen = q->tsigalglen = q->tsigmaclen = 0;
+
+ /* the key name is parsed here */
+ rollback = 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) {
+ free_question(q);
+ return NULL;
+ }
+ i = (pb - buf);
+ pseudolen1 = i;
+
+ memcpy(q->tsigkey, expand, elen);
+ q->tsigkeylen = elen;
+
+
+ if (i + 10 > len) { /* type + class + ttl + rdlen == 10 */
+ i = rollback;
+ break;
+ }
+
+ /* type */
+ val16 = (u_int16_t *)&buf[i];
+ if (ntohs(*val16) != DNS_TYPE_TSIG) {
+ i = rollback;
+ break;
+ }
+ i += 2;
+ pseudolen2 = i;
+
+ /* we don't have any tsig keys configured, no auth done */
+ if (tsig == 0) {
+ i = rollback;
+ break;
+ }
+
+ q->tsigerrorcode = DNS_BADKEY;
+
+ if (require_tsig)
+ require_tsig = 0;
+
+
+ /* class */
+ val16 = (u_int16_t *)&buf[i];
+ if (ntohs(*val16) != DNS_CLASS_ANY) {
+ i = rollback;
+ break;
+ }
+ i += 2;
+
+ /* ttl */
+ val32 = (u_int32_t *)&buf[i];
+ if (ntohl(*val32) != 0) {
+ i = rollback;
+ break;
+ }
+ i += 4;
+
+ /* rdlen */
+ val16 = (u_int16_t *)&buf[i];
+ if (ntohs(*val16) != (len - (i + 2))) {
+ i = rollback;
+ break;
+ }
+ i += 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) {
+ free_question(q);
+ return NULL;
+ }
+ i = (pb - buf);
+ pseudolen4 = i;
+
+ memcpy(q->tsigalg, expand, elen);
+ q->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(q->tsigkey, q->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];
+
+ fudge = ntohs(tsigrr->timefudge & 0xffff);
+ tsigtime = ntohl((tsigrr->timefudge >> 16));
+
+ q->tsig_timefudge = tsigrr->timefudge;
+
+ now = time(NULL);
+ /* outside our fudge window */
+ if (tsigtime < (now - fudge) || tsigtime > (now + fudge)) {
+ q->tsigerrorcode = DNS_BADTIME;
+ break;
+ }
+
+ i += (8 + 2); /* timefudge + macsize */
+
+ if (ntohs(tsigrr->macsize) != 32) {
+ q->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 */
+ val16 = (u_int16_t *)&buf[i];
+ i += 2;
+ if (hdr->id != *val16)
+ hdr->id = *val16;
+ q->tsigorigid = *val16;
+
+ /* error */
+ tsigerror = (u_int16_t *)&buf[i];
+ i += 2;
+
+ /* other len */
+ tsigotherlen = (u_int16_t *)&buf[i];
+ i += 2;
+
+ memcpy(pseudo_packet, 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;
+
+ val16 = (u_int16_t *)&pseudo_packet[ppoffset];
+ *val16 = *tsigerror;
+ ppoffset += 2;
+
+ val16 = (u_int16_t *)&pseudo_packet[ppoffset];
+ *val16 = *tsigotherlen;
+ ppoffset += 2;
+
+ memcpy(&pseudo_packet[ppoffset], &buf[i], len - i);
+ ppoffset += (len - i);
+
+ HMAC(EVP_sha256(), tsigkey, tsignamelen, (unsigned char *)pseudo_packet,
+ ppoffset, (unsigned char *)&sha256, &shasize);
+
+
+
+ if (memcmp(sha256, tsigrr->mac, sizeof(sha256)) != 0) {
+#if DEBUG
+ dolog(LOG_INFO, "HMAC did not verify\n");
+#endif
+ q->tsigerrorcode = DNS_BADSIG;
+ break;
+ }
+
+ /* copy the mac for error coding */
+ memcpy(q->tsigmac, tsigrr->mac, sizeof(q->tsigmac));
+ q->tsigmaclen = 32;
+
+ /* we're now authenticated */
+ q->tsigerrorcode = 0;
+ q->tsigverified = 1;
+
+ } while (0);
+
+ if (require_tsig) {
+ if (q->tsigerrorcode == 0)
+ q->tsigerrorcode = 1; /* 1 for now */
+ }
+
/* fill our name into the dns header struct */
memcpy(q->hdr->name, &buf[sizeof(struct dns_header)], q->hdr->namelen);
@@ -854,3 +1113,90 @@ rrlookup(char *keyword)
return (p);
}
+
+/*
+ * parse a domain name through a compression scheme and stay inside the bounds
+ * returns NULL on error and pointer to the next object;
+ */
+
+char *
+expand_compression(u_char *p, u_char *estart, u_char *end, u_char *expand, int *elen, int max)
+{
+ u_short tlen;
+ u_char *save = NULL;
+ u_int16_t *offset;
+
+ /* expand name */
+ while ((u_char)*p && p <= end) {
+ /* test for compression */
+ if ((*p & 0xc0) == 0xc0) {
+ /* do not allow recursive compress pointers */
+ if (! save) {
+ save = p + 2;
+ }
+ offset = (u_int16_t *)p;
+ /* do not allow forwards jumping */
+ if ((p - estart) <= (ntohs(*offset) & (~0xc000))) {
+ return NULL;
+ }
+
+ p = (estart + (ntohs(*offset) & (~0xc000)));
+ } else {
+ if (*elen + 1 >= max) {
+ return NULL;
+ }
+ expand[(*elen)] = *p;
+ (*elen)++;
+ tlen = *p;
+ p++;
+ memcpy(&expand[*elen], p, tlen);
+ p += tlen;
+ if (*elen + tlen >= max) {
+ return NULL;
+ }
+ *elen += tlen;
+ }
+ }
+
+ if (p > end) {
+ return NULL;
+ }
+
+ if (save == NULL) {
+ p++;
+ (*elen)++;
+ return (p);
+ } else {
+ (*elen)++;
+ return (save);
+ }
+}
+
+void
+log_diff(char *sha256, char *mac, int len)
+{
+ char buf[512];
+ char tbuf[16];
+ int i;
+
+ memset(&buf, 0, sizeof(buf));
+ for (i = 0; i < 32; i++) {
+ snprintf(tbuf, sizeof(tbuf), "%02x", sha256[i] & 0xff);
+ strlcat(buf, tbuf, sizeof(buf));
+ }
+
+ strlcat(buf, "\n", sizeof(buf));
+
+ dolog(LOG_INFO, "our HMAC = %s\n", buf);
+
+ memset(&buf, 0, sizeof(buf));
+ for (i = 0; i < 32; i++) {
+ snprintf(tbuf, sizeof(tbuf), "%02x", mac[i] & 0xff);
+ strlcat(buf, tbuf, sizeof(buf));
+ }
+
+ strlcat(buf, "\n", sizeof(buf));
+
+ dolog(LOG_INFO, "given HMAC = %s\n", buf);
+
+}
blob - /dev/null
blob + caaa7d175fce31d3b1de801ca294a2b0f310d333 (mode 644)
--- /dev/null
+++ tsig.c
@@ -0,0 +1,276 @@
+/*
+ * Copyright (c) 2019 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.
+ *
+ */
+
+/*
+ * $Id: tsig.c,v 1.1 2019/02/24 07:14:02 pjp Exp $
+ */
+
+
+/*
+ * this file is based on filter.c
+ */
+
+#include "ddd-include.h"
+#include "ddd-dns.h"
+#include "ddd-db.h"
+
+int find_tsig(struct sockaddr_storage *, int);
+void init_tsig(void);
+int insert_tsig(char *, char *);
+int find_tsig_key(char *, int, char *, int);
+void init_tsig_key(void);
+int insert_tsig_key(char *, int, char *, int);
+
+extern void dolog(int, char *, ...);
+extern in_addr_t getmask(int);
+extern int getmask6(int, struct sockaddr_in6 *);
+extern int memcasecmp(u_char *, u_char *, int);
+
+extern int debug, verbose;
+
+int tsig = 0; /* tsig is off by default */
+SLIST_HEAD(, tsigkeyentry) tsigkeyhead;
+
+static struct tsigkeyentry {
+ char *keyname;
+ int keynamelen;
+ char *key;
+ int keylen;
+ SLIST_ENTRY(tsigkeyentry) tsig_key_entry;
+} *tk2, *tknp;
+
+
+SLIST_HEAD(, tsigentry) tsighead;
+static struct tsigentry {
+ char name[INET6_ADDRSTRLEN];
+ int family;
+ struct sockaddr_storage hostmask;
+ struct sockaddr_storage netmask;
+ u_int8_t prefixlen;
+ SLIST_ENTRY(tsigentry) tsig_entry;
+} *tsign2, *tsignp;
+
+
+/*
+ * INIT_FILTER - initialize the tsig singly linked list
+ */
+
+void
+init_tsig(void)
+{
+ SLIST_INIT(&tsighead);
+ return;
+}
+
+/*
+ * INSERT_FILTER - insert an address and prefixlen into the tsig slist
+ */
+
+int
+insert_tsig(char *address, char *prefixlen)
+{
+ struct sockaddr_in *sin;
+ struct sockaddr_in6 *sin6;
+ int pnum;
+ int ret;
+
+ pnum = atoi(prefixlen);
+ tsign2 = malloc(sizeof(struct tsigentry)); /* Insert after. */
+
+ if (strchr(address, ':') != NULL) {
+ tsign2->family = AF_INET6;
+ sin6 = (struct sockaddr_in6 *)&tsign2->hostmask;
+ if ((ret = inet_pton(AF_INET6, address, &sin6->sin6_addr.s6_addr)) != 1)
+ return (-1);
+ sin6->sin6_family = AF_INET6;
+ sin6 = (struct sockaddr_in6 *)&tsign2->netmask;
+ sin6->sin6_family = AF_INET6;
+ if (getmask6(pnum, sin6) < 0)
+ return(-1);
+ tsign2->prefixlen = pnum;
+ } else {
+
+ tsign2->family = AF_INET;
+ sin = (struct sockaddr_in *)&tsign2->hostmask;
+ sin->sin_family = AF_INET;
+ sin->sin_addr.s_addr = inet_addr(address);
+ sin = (struct sockaddr_in *)&tsign2->netmask;
+ sin->sin_family = AF_INET;
+ sin->sin_addr.s_addr = getmask(pnum);
+ tsign2->prefixlen = pnum;
+
+ }
+
+ SLIST_INSERT_HEAD(&tsighead, tsign2, tsig_entry);
+
+ return (0);
+}
+
+/*
+ * FIND_FILTER - walk the tsig list and find the correponding network
+ * if a network matches return 1, if no match is found return
+ * 0.
+ */
+
+int
+find_tsig(struct sockaddr_storage *sst, int family)
+{
+ struct sockaddr_in *sin, *sin0;
+ struct sockaddr_in6 *sin6, *sin60, *sin61;
+ u_int32_t hostmask, netmask;
+ u_int32_t a;
+#ifdef __amd64
+ u_int64_t *hm[2], *nm[2], *a6[2];
+#else
+ u_int32_t *hm[4], *nm[4], *a6[4];
+#endif
+
+ SLIST_FOREACH(tsignp, &tsighead, tsig_entry) {
+ if (tsignp->family == AF_INET) {
+ if (family != AF_INET)
+ continue;
+ sin = (struct sockaddr_in *)sst;
+ a = sin->sin_addr.s_addr;
+ sin = (struct sockaddr_in *)&tsignp->hostmask;
+ sin0 = (struct sockaddr_in *)&tsignp->netmask;
+ hostmask = sin->sin_addr.s_addr;
+ netmask = sin0->sin_addr.s_addr;
+ if ((hostmask & netmask) == (a & netmask)) {
+ return (1);
+ } /* if hostmask */
+ } else if (tsignp->family == AF_INET6) {
+ if (family != AF_INET6)
+ continue;
+ sin6 = (struct sockaddr_in6 *)sst;
+ sin60 = (struct sockaddr_in6 *)&tsignp->hostmask;
+ sin61 = (struct sockaddr_in6 *)&tsignp->netmask;
+#ifdef __amd64
+ /*
+ * If this is on a 64 bit machine, we'll benefit
+ * by using 64 bit registers, this should make it
+ * a tad faster...
+ */
+ hm[0] = (u_int64_t *)&sin60->sin6_addr.s6_addr;
+ hm[1] = (hm[0] + 1);
+ nm[0] = (u_int64_t *)&sin61->sin6_addr.s6_addr;
+ nm[1] = (nm[0] + 1);
+ a6[0] = (u_int64_t *)&sin6->sin6_addr.s6_addr;
+ a6[1] = (a6[0] + 1);
+ if ( ((*hm[0] & *nm[0]) == (*a6[0] & *nm[0]))&&
+ ((*hm[1] & *nm[1]) == (*a6[1] & *nm[1]))) {
+#else
+ hm[0] = (u_int32_t *)&sin60->sin6_addr.s6_addr;
+ hm[1] = (hm[0] + 1); hm[2] = (hm[1] + 1);
+ hm[3] = (hm[2] + 1);
+ nm[0] = (u_int32_t *)&sin61->sin6_addr.s6_addr;
+ nm[1] = (nm[0] + 1); nm[2] = (nm[1] + 1);
+ nm[3] = (nm[2] + 1);
+ a6[0] = (u_int32_t *)&sin6->sin6_addr.s6_addr;
+ a6[1] = (a6[0] + 1); a6[2] = (a6[1] + 1);
+ a6[3] = (a6[2] + 1);
+
+ if ( ((*hm[0] & *nm[0]) == (*a6[0] & *nm[0]))&&
+ ((*hm[1] & *nm[1]) == (*a6[1] & *nm[1]))&&
+ ((*hm[2] & *nm[2]) == (*a6[2] & *nm[2]))&&
+ ((*hm[3] & *nm[3]) == (*a6[3] & *nm[3]))) {
+#endif
+
+ return (1);
+ } /* if ip6 address */
+
+ } /* if AF_INET6 */
+ } /* SLIST */
+
+ return (0);
+}
+
+
+
+/*
+ * INIT_TSIG_KEY - initialize the tsig key singly linked list
+ */
+
+void
+init_tsig_key(void)
+{
+ SLIST_INIT(&tsigkeyhead);
+ return;
+}
+
+/*
+ * INSERT_TSIG - insert an address and prefixlen into the tsig slist
+ */
+
+int
+insert_tsig_key(char *key, int keylen, char *keyname, int keynamelen)
+{
+ tk2 = malloc(sizeof(struct tsigkeyentry)); /* Insert after. */
+ if (tk2 == NULL)
+ return -1;
+
+ tk2->key = malloc(keylen);
+ if (tk2->key == NULL)
+ return -1;
+
+ memcpy(tk2->key, key, keylen);
+ tk2->keylen = keylen;
+
+ tk2->keyname = malloc(keynamelen);
+ if (tk2->keyname == NULL) {
+ return -1;
+ }
+ memcpy(tk2->keyname, keyname, keynamelen);
+ tk2->keynamelen = keynamelen;
+
+ SLIST_INSERT_HEAD(&tsigkeyhead, tk2, tsig_key_entry);
+
+ return (0);
+}
+
+/*
+ * FIND_TSIG_KEY - walk the tsig list and find the correponding key
+ */
+
+int
+find_tsig_key(char *keyname, int keynamelen, char *key, int keylen)
+{
+ SLIST_FOREACH(tknp, &tsigkeyhead, tsig_key_entry) {
+ if (keynamelen == tknp->keynamelen &&
+ memcasecmp(tknp->keyname, keyname, keynamelen) == 0) {
+
+ if (keylen < tknp->keylen)
+ return -1;
+
+ memcpy(key, tknp->key, tknp->keylen);
+
+ return (tknp->keylen);
+ }
+ } /* SLIST */
+
+ return -1;
+}
repomaster@centroid.eu