Commit Diff
Diff:
3edf28efe3da8b0628ba68cfaf2f5f437e2f290b
58eafea426891f641a289db08bdc51b7f30c62ae
Commit:
58eafea426891f641a289db08bdc51b7f30c62ae
Tree:
7c09f06280565d1ed95da70c4f28ab94c0658bfe
Author:
pjp <pjp@delphinusdns.org>
Committer:
pjp <pjp@delphinusdns.org>
Date:
Sat May 17 09:18:11 2014 UTC
Message:
RFC 1996 (DNS Notify) support, this couldn't be fully tested on IPv6 since I lack a master on IPv6. Tested on FreeBSD 10, OpenBSD 5.5
blob - 86f1db893aea6b46a4a6d5385db547ad8f19f000
blob + 98705ab5f0e285fc138408c2871002c87f53acde
--- axfr.c
+++ axfr.c
@@ -29,27 +29,37 @@
#include "dns.h"
#include "db.h"
-void axfrloop(int *afd, int sockcount, char **ident, DB *db);
-void axfr_connection(int so, char *address, int is_ipv6, DB *db);
-void reap(int sig);
-int build_header(DB *db, char *reply, char *buf, struct question *q, int answercount);
-int build_soa(DB *db, char *reply, int offset, struct domain *sd, struct question *q);
-int checklabel(DB *db, struct domain *sd, struct domain *soa, struct question *q);
+int notify = 0;
-extern in_addr_t getmask(int prefixlen);
-extern int getmask6(int prefixlen, struct sockaddr_in6 *sin6);
-extern void build_reply(struct sreply *reply, int so, char *buf, int len, struct question *q, struct sockaddr *sa, socklen_t slen, struct domain *sd1, struct domain *sd2, u_int8_t region, int istcp, int wildcard, struct recurses *sr);
-struct question * build_question(char *, int);
+void init_axfr(void);
+int insert_axfr(char *, char *);
+void init_notifyslave(void);
+int insert_notifyslave(char *, char *);
+void axfrloop(int *, int, char **, DB *);
+void axfr_connection(int, char *, int, DB *);
+void reap(int);
+int build_header(DB *, char *, char *, struct question *, int);
+int build_soa(DB *, char *, int, struct domain *, struct question *);
+int checklabel(DB *, struct domain *, struct domain *, struct question *);
+void gather_notifydomains(DB *);
+void notifyslaves(int *);
+void notifypacket(int, void *, void *, int);
+
+extern in_addr_t getmask(int);
+extern int getmask6(int, struct sockaddr_in6 *);
+extern void build_reply(struct sreply *, int, char *, int, struct question *, struct sockaddr *, socklen_t, struct domain *, struct domain *, u_int8_t, int, int, struct recurses *);
extern void reply_fmterror(struct sreply *);
extern void reply_nxdomain(struct sreply *);
extern int get_soa(DB *, struct question *, struct domain *, int);
extern int compress_label(u_char *, int, int);
-extern u_int16_t create_anyreply(struct sreply *sreply, char *reply, int rlen, int offset, int soa);
+extern u_int16_t create_anyreply(struct sreply *, char *, int, int, int);
extern struct question * build_fake_question(char *, int, u_int16_t);
+extern struct question * build_question(char *, int, int);
extern int free_question(struct question *);
extern void dolog(int, char *, ...);
extern int debug, verbose;
+extern time_t time_changed;
SLIST_HEAD(listhead, axfrentry) axfrhead;
@@ -62,9 +72,32 @@ static struct axfrentry {
SLIST_ENTRY(axfrentry) axfr_entry;
} *an2, *anp;
+SLIST_HEAD(notifyslavelisthead, notifyslaveentry) notifyslavehead;
-static const char rcsid[] = "$Id: axfr.c,v 1.7 2014/05/01 15:26:24 pjp Exp $";
+static struct notifyslaveentry {
+ char name[INET6_ADDRSTRLEN];
+ int family;
+ struct sockaddr_storage hostmask;
+ struct sockaddr_storage netmask;
+ u_int8_t prefixlen;
+ SLIST_ENTRY(notifyslaveentry) notifyslave_entry;
+} *nfslnp2, *nfslnp;
+
+
+SLIST_HEAD(notifylisthead, notifyentry) notifyhead;
+
+static struct notifyentry {
+ char domain[DNS_MAXNAME];
+ int domainlen;
+ u_int16_t *ids;
+ u_int16_t *attempts;
+ SLIST_ENTRY(notifyentry) notify_entry;
+} *notn2, *notnp;
+
+
+static const char rcsid[] = "$Id: axfr.c,v 1.8 2014/05/17 09:18:11 pjp Exp $";
+
/*
* INIT_AXFR - initialize the axfr singly linked list
*/
@@ -198,6 +231,66 @@ find_axfr(struct sockaddr_storage *sst, int family)
return (0);
}
+/*
+ * INIT_NOTIFYSLAVE - initialize the axfr singly linked list
+ */
+
+void
+init_notifyslave(void)
+{
+ SLIST_INIT(&notifyslavehead);
+ return;
+}
+
+/*
+ * INSERT_NOTIFYSLAVE - insert an address and prefixlen into the notifyslave slist
+ */
+
+int
+insert_notifyslave(char *address, char *prefixlen)
+{
+ struct sockaddr_in *sin;
+ struct sockaddr_in6 *sin6;
+ int pnum;
+ int ret;
+
+ pnum = atoi(prefixlen);
+ nfslnp2 = calloc(1, sizeof(struct notifyslaveentry)); /* Insert after. */
+ if (nfslnp2 == NULL)
+ return (-1);
+
+
+ if (strchr(address, ':') != NULL) {
+ nfslnp2->family = AF_INET6;
+ sin6 = (struct sockaddr_in6 *)&nfslnp2->hostmask;
+ if ((ret = inet_pton(AF_INET6, address, &sin6->sin6_addr.s6_addr)) != 1)
+ return (-1);
+ sin6->sin6_family = AF_INET6;
+ sin6->sin6_port = htons(53);
+ sin6 = (struct sockaddr_in6 *)&nfslnp2->netmask;
+ sin6->sin6_family = AF_INET6;
+ if (getmask6(pnum, sin6) < 0)
+ return(-1);
+ nfslnp2->prefixlen = pnum;
+ } else {
+
+ nfslnp2->family = AF_INET;
+ sin = (struct sockaddr_in *)&nfslnp2->hostmask;
+ sin->sin_family = AF_INET;
+ sin->sin_addr.s_addr = inet_addr(address);
+ sin->sin_port = htons(53);
+ sin = (struct sockaddr_in *)&nfslnp2->netmask;
+ sin->sin_family = AF_INET;
+ sin->sin_addr.s_addr = getmask(pnum);
+ nfslnp2->prefixlen = pnum;
+
+ }
+
+ SLIST_INSERT_HEAD(&notifyslavehead, nfslnp2, notifyslave_entry);
+
+ return (0);
+}
+
void
axfrloop(int *afd, int sockcount, char **ident, DB *db)
{
@@ -205,13 +298,20 @@ axfrloop(int *afd, int sockcount, char **ident, DB *db
struct timeval tv;
struct sockaddr_storage from;
- struct sockaddr_in6 *sin6;
- struct sockaddr_in *sin;
+ struct sockaddr_in6 *sin6, *sin62;
+ struct sockaddr_in *sin, *sin2;
+ struct dns_header *dh;
+ struct question *question;
- int i, so;
+ int i, so, len;
int sel, maxso = 0;
int is_ipv6, axfr_acl;
+ int notifyfd[2];
+
socklen_t fromlen;
+ char buf[512];
+
+ time_t now;
pid_t pid;
char address[INET6_ADDRSTRLEN];
@@ -220,24 +320,85 @@ axfrloop(int *afd, int sockcount, char **ident, DB *db
for (i = 0; i < sockcount; i++) {
listen(afd[i], 5);
-
- if (afd[i] > maxso)
- maxso = afd[i];
}
+ if (notify) {
+ /*
+ * If a zonefile has changed in the last half hour then
+ * gather all notifydomains and start the notify process
+ */
+
+ notifyfd[0] = -1;
+ notifyfd[1] = -1;
+
+ now = time(NULL);
+ if (difftime(now, time_changed) <= 1800) {
+ gather_notifydomains(db);
+ notifyfd[0] = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+ notifyfd[1] = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
+
+ memset((char *)&from, 0, sizeof(from));
+ sin = (struct sockaddr_in *)&from;
+ sin->sin_family = AF_INET;
+ sin->sin_port = htons(0);
+
+ if (bind(notifyfd[0], (struct sockaddr *)sin, sizeof(*sin)) < 0) {
+ dolog(LOG_INFO, "bind notify: %s\n", strerror(errno));
+ }
+
+ memset((char *)&from, 0, sizeof(from));
+ sin6 = (struct sockaddr_in6 *)&from;
+ sin->sin_family = AF_INET6;
+ sin->sin_port = htons(0);
+
+ if (bind(notifyfd[1], (struct sockaddr *)sin, sizeof(*sin6)) < 0) {
+ dolog(LOG_INFO, "bind notify6: %s\n", strerror(errno));
+ }
+
+ memset((char *)&from, 0, sizeof(from));
+
+ notifyslaves((int *)&notifyfd);
+ }
+ }
+
for (;;) {
FD_ZERO(&rset);
+ maxso = 0;
for (i = 0; i < sockcount; i++) {
FD_SET(afd[i], &rset);
+ if (maxso < afd[i])
+ maxso = afd[i];
}
+
+ if (notify) {
+ if (notifyfd[0] > -1) {
+ FD_SET(notifyfd[0], &rset);
+ if (maxso < notifyfd[0])
+ maxso = notifyfd[0];
+ }
+
+ if (notifyfd[1] > -1) {
+ FD_SET(notifyfd[1], &rset);
+ if (maxso < notifyfd[1])
+ maxso = notifyfd[1];
+ }
+ }
tv.tv_sec = 10;
tv.tv_usec = 0;
- sel = select(maxso + 1, &rset, NULL, NULL, NULL);
+ sel = select(maxso + 1, &rset, NULL, NULL, &tv);
+ if (sel == 0) {
+ if (notify) {
+ if (notifyfd[0] > -1 || notifyfd[1] > -1)
+ notifyslaves((int *)&notifyfd);
+ }
+
+ continue;
+ }
if (sel < 0) {
dolog(LOG_INFO, "select: %s\n", strerror(errno));
continue;
@@ -298,6 +459,155 @@ axfrloop(int *afd, int sockcount, char **ident, DB *db
} /* for (i.. */
+ if (notify) {
+ if (notifyfd[0] > -1 && FD_ISSET(notifyfd[0], &rset)) {
+ fromlen = sizeof(struct sockaddr_storage);
+ len = recvfrom(notifyfd[0], buf, sizeof(buf), 0, (struct sockaddr *)&from, &fromlen);
+ if (len < 0) {
+ dolog(LOG_INFO, "recvfrom: %s\n", strerror(errno));
+ }
+
+ if (len < sizeof(struct dns_header)) {
+ dolog(LOG_INFO, "received bogus reply on notify port, drop\n");
+ continue;
+ }
+
+ dh = (struct dns_header *)&buf[0];
+ if (ntohs(dh->question) != 1) {
+ dolog(LOG_INFO, "question header on notify reply not 1, drop\n");
+ continue;
+ }
+
+ if (! (ntohs(dh->query) & DNS_REPLY)) {
+ dolog(LOG_INFO, "question header is not a reply, drop\n");
+ continue;
+ }
+
+ question = build_question(buf, len, ntohs(dh->additional));
+ if (question == NULL) {
+ dolog(LOG_INFO, "build_question failed on notify reply, drop\n");
+ continue;
+ }
+
+ sin = (struct sockaddr_in *)&from;
+ inet_ntop(AF_INET, (void*)&sin->sin_addr, (char*)&address, sizeof(address));
+
+ SLIST_FOREACH_SAFE(notnp, &notifyhead, notify_entry, notn2) {
+
+ for (i = 0; i < notify; i++) {
+ if (ntohs(dh->id) == notnp->ids[i] &&
+ (ntohs(dh->query) & DNS_NOTIFY) &&
+ (ntohs(dh->query) & DNS_AUTH) &&
+ ntohs(question->hdr->qtype) == DNS_TYPE_SOA &&
+ ntohs(question->hdr->qclass) == DNS_CLASS_IN &&
+ question->hdr->namelen == notnp->domainlen &&
+ memcmp(question->hdr->name, notnp->domain, notnp->domainlen) == 0) {
+ SLIST_FOREACH_SAFE(nfslnp, &notifyslavehead, notifyslave_entry, nfslnp2) {
+ if (nfslnp->family != AF_INET)
+ continue;
+
+ sin2 = (struct sockaddr_in *)&nfslnp->hostmask;
+ if (sin->sin_addr.s_addr == sin2->sin_addr.s_addr) {
+ dolog(LOG_INFO, "notify success! removing address \"%s\" from notify contact list\n", address);
+ SLIST_REMOVE(&notifyslavehead, nfslnp, notifyslaveentry, notifyslave_entry);
+ }
+ }
+ } else {
+ dolog(LOG_INFO, "got a reply from a notify host (%s) DNS->ID %u that says: %04x\n", address, ntohs(dh->id), ntohs(dh->query));
+ }
+ }
+ }
+
+ free_question(question);
+
+ if (SLIST_EMPTY(&notifyslavehead)) {
+ dolog(LOG_INFO, "notifys have been completed, closing notify descriptors!\n");
+ if (notifyfd[0] > -1)
+ close(notifyfd[0]);
+
+ if (notifyfd[1] > -1)
+ close(notifyfd[1]);
+
+ notifyfd[0] = -1;
+ notifyfd[1] = -1;
+ }
+ }
+
+ if (notifyfd[1] > -1 && FD_ISSET(notifyfd[1], &rset)) {
+ fromlen = sizeof(struct sockaddr_storage);
+ len = recvfrom(notifyfd[1], buf, sizeof(buf), 0, (struct sockaddr *)&from, &fromlen);
+ if (len < 0) {
+ dolog(LOG_INFO, "recvfrom: %s\n", strerror(errno));
+ }
+
+ if (len < sizeof(struct dns_header)) {
+ dolog(LOG_INFO, "received bogus reply on notify port, drop\n");
+ continue;
+ }
+
+ dh = (struct dns_header *)&buf[0];
+ if (ntohs(dh->question) != 1) {
+ dolog(LOG_INFO, "question header on notify reply not 1, drop\n");
+ continue;
+ }
+
+ if (! (ntohs(dh->query) & DNS_REPLY)) {
+ dolog(LOG_INFO, "question header is not a reply, drop\n");
+ continue;
+ }
+
+ question = build_question(buf, len, ntohs(dh->additional));
+ if (question == NULL) {
+ dolog(LOG_INFO, "build_question failed on notify reply, drop\n");
+ continue;
+ }
+
+ sin6 = (struct sockaddr_in6 *)&from;
+ inet_ntop(AF_INET6, (void*)&sin6->sin6_addr, (char*)&address, sizeof(address));
+
+ SLIST_FOREACH_SAFE(notnp, &notifyhead, notify_entry, notn2) {
+
+ for (i = 0; i < notify; i++) {
+ if (ntohs(dh->id) == notnp->ids[i] &&
+ (ntohs(dh->query) & DNS_NOTIFY) &&
+ (ntohs(dh->query) & DNS_AUTH) &&
+ ntohs(question->hdr->qtype) == DNS_TYPE_SOA &&
+ ntohs(question->hdr->qclass) == DNS_CLASS_IN &&
+ question->hdr->namelen == notnp->domainlen &&
+ memcmp(question->hdr->name, notnp->domain, notnp->domainlen) == 0) {
+ SLIST_FOREACH_SAFE(nfslnp, &notifyslavehead, notifyslave_entry, nfslnp2) {
+ if (nfslnp->family != AF_INET6)
+ continue;
+
+ sin62 = (struct sockaddr_in6 *)&nfslnp->hostmask;
+ if (memcmp(&sin6->sin6_addr, &sin62->sin6_addr, 16) == 0) {
+ dolog(LOG_INFO, "notify success! removing address \"%s\" from notify contact list\n", address);
+ SLIST_REMOVE(&notifyslavehead, nfslnp, notifyslaveentry, notifyslave_entry);
+ }
+ }
+ } else {
+ dolog(LOG_INFO, "got a reply from a notify host (%s) DNS->ID %u that says: %04x\n", address, ntohs(dh->id), ntohs(dh->query));
+ }
+ }
+ }
+
+ free_question(question);
+
+ if (SLIST_EMPTY(&notifyslavehead)) {
+ dolog(LOG_INFO, "notifys have been completed, closing notify descriptors!\n");
+ if (notifyfd[0] > -1)
+ close(notifyfd[0]);
+
+ if (notifyfd[1] > -1)
+ close(notifyfd[1]);
+
+ notifyfd[0] = -1;
+ notifyfd[1] = -1;
+ }
+ }
+
+ }
+
} /* for (;;) */
}
@@ -375,7 +685,7 @@ axfr_connection(int so, char *address, int is_ipv6, DB
goto drop;
}
- if ((question = build_question((p + 2), dnslen)) == NULL) {
+ if ((question = build_question((p + 2), dnslen, 0)) == NULL) {
dolog(LOG_INFO, "AXFR malformed question, drop\n");
goto drop;
}
@@ -835,4 +1145,198 @@ checklabel(DB *db, struct domain *sd, struct domain *s
return (1);
+}
+
+void
+gather_notifydomains(DB *db)
+{
+ DBT key, data;
+ DBC *cursor;
+
+ time_t now, soatime;
+ struct tm *tm;
+
+ char timestring[128];
+ char buf[128];
+
+ struct domain *sd;
+
+
+ SLIST_INIT(&notifyhead);
+
+ now = time(NULL);
+ tm = localtime(&now);
+ if (tm != NULL)
+ strftime(timestring, sizeof(timestring), "%Y%m%d", tm);
+ else
+ snprintf(timestring, sizeof(timestring), "19700101");
+
+ now = time(NULL);
+
+ if (db->cursor(db, NULL, &cursor, 0) != 0) {
+ dolog(LOG_INFO, "db->cursor: %s\n", strerror(errno));
+ return;
+ }
+
+ memset(&key, 0, sizeof(key));
+ memset(&data, 0, sizeof(data));
+
+
+ if (cursor->c_get(cursor, &key, &data, DB_FIRST) != 0) {
+ dolog(LOG_INFO, "cursor->c_get: %s\n", strerror(errno));
+ cursor->c_close(cursor);
+ return;
+ }
+
+ do {
+ if (data.size != sizeof(struct domain)) {
+ dolog(LOG_INFO, "btree db is damaged\n");
+ cursor->c_close(cursor);
+ return;
+ }
+
+ sd = (struct domain *)data.data;
+
+ if ((sd->flags & DOMAIN_HAVE_SOA) == DOMAIN_HAVE_SOA) {
+ notn2 = malloc(sizeof(struct notifyentry));
+ if (notn2 == NULL) {
+ continue;
+ }
+
+ notn2->ids = calloc(notify, sizeof(u_int16_t));
+ if (notn2->ids == NULL) {
+ free(notn2);
+ continue;
+ }
+
+ notn2->attempts = calloc(notify, sizeof(u_int16_t));
+ if (notn2->attempts == NULL) {
+ free(notn2);
+ continue;
+ }
+
+ memcpy(notn2->domain, sd->zone, sd->zonelen);
+ notn2->domainlen = sd->zonelen;
+
+ soatime = (time_t)sd->soa.serial;
+ snprintf(buf, sizeof(buf), "%u", sd->soa.serial);
+
+ if (strncmp(buf, timestring, strlen(timestring)) == 0) {
+ dolog(LOG_INFO, "inserting zone \"%s\" for notification...\n", sd->zonename);
+ SLIST_INSERT_HEAD(&notifyhead, notn2, notify_entry);
+ } else if (difftime(now, soatime) < 1800 && difftime(now, soatime) > 0) {
+ dolog(LOG_INFO, "2 inserting zone \"%s\" for notification...\n", sd->zonename);
+ SLIST_INSERT_HEAD(&notifyhead, notn2, notify_entry);
+ } else {
+#if 0
+ dolog(LOG_INFO, "SOA serial for zone \"%s\" did not make sense (%s), not notifying\n", sd->zonename, buf);
+#endif
+ free(notn2);
+ }
+ }
+
+ memset(&key, 0, sizeof(key));
+ memset(&data, 0, sizeof(data));
+ } while (cursor->c_get(cursor, &key, &data, DB_NEXT) == 0);
+
+ cursor->c_close(cursor);
+
+ return;
+}
+
+void
+notifyslaves(int *notifyfd)
+{
+ int so;
+ int i;
+
+ i = 0;
+ SLIST_FOREACH(nfslnp, &notifyslavehead, notifyslave_entry) {
+ if (nfslnp->family == AF_INET6) {
+ so = notifyfd[1];
+ } else {
+ so = notifyfd[0];
+ }
+#if 0
+ dolog(LOG_INFO, "notifying %s...\n", nfslnp->name);
+#endif
+
+ SLIST_FOREACH_SAFE(notnp, &notifyhead, notify_entry, notn2) {
+ notnp->ids[i] = arc4random() & 0xffff;
+ notnp->attempts[i]++;
+ if (notnp->attempts[i] > 10) {
+ dolog(LOG_INFO, "notify entry removed due to timeout\n");
+ SLIST_REMOVE(&notifyhead, notnp, notifyentry, notify_entry);
+ }
+
+ notifypacket(so, nfslnp, notnp, i);
+ }
+
+ i++;
+ }
+
+ return;
+}
+
+void
+notifypacket(int so, void *vnse, void *vnotnp, int packetcount)
+{
+ struct notifyslaveentry *nse = (struct notifyslaveentry *)vnse;
+ struct notifyentry *notnp = (struct notifyentry *)vnotnp;
+ struct sockaddr_in bsin, *sin;
+ struct sockaddr_in6 bsin6, *sin6;
+ char packet[512];
+ char *questionname;
+ u_int16_t *classtype;
+ struct dns_header *dnh;
+ int outlen = 0, slen, ret;
+
+ memset(&packet, 0, sizeof(packet));
+ dnh = (struct dns_header *)&packet[0];
+
+ dnh->id = htons(notnp->ids[packetcount]);
+ SET_DNS_NOTIFY(dnh);
+ SET_DNS_AUTHORITATIVE(dnh);
+ SET_DNS_QUERY(dnh);
+ HTONS(dnh->query);
+
+ dnh->question = htons(1);
+
+ outlen += sizeof(struct dns_header);
+ questionname = (char *)&packet[outlen];
+
+ memcpy(questionname, notnp->domain, notnp->domainlen);
+ outlen += notnp->domainlen;
+
+ classtype = (u_int16_t *)&packet[outlen];
+ classtype[0] = htons(DNS_TYPE_SOA);
+ classtype[1] = htons(DNS_CLASS_IN);
+
+ outlen += (2 * sizeof(u_int16_t));
+
+ if (nse->family == AF_INET) {
+ slen = sizeof(struct sockaddr_in);
+ sin = (struct sockaddr_in *)&nse->hostmask;
+ memset(&bsin, 0, sizeof(bsin));
+ bsin.sin_family = AF_INET;
+ bsin.sin_port = htons(53);
+ bsin.sin_addr.s_addr = sin->sin_addr.s_addr;
+
+ ret = sendto(so, packet, outlen, 0, (struct sockaddr *)&bsin, slen);
+ } else {
+ slen = sizeof(struct sockaddr_in6);
+ sin6 = (struct sockaddr_in6 *)&nse->hostmask;
+ memset(&bsin6, 0, sizeof(bsin6));
+ bsin6.sin6_family = AF_INET6;
+ bsin6.sin6_port = htons(53);
+ memcpy(&bsin6.sin6_addr, &sin6->sin6_addr, 16);
+
+ ret = sendto(so, packet, outlen, 0, (struct sockaddr *)sin6, slen);
+ }
+
+ if (ret < 0) {
+ dolog(LOG_INFO, "sendto: %s\n", strerror(errno));
+ }
+
+ return;
}
blob - e1a97f24aa458900ff4a618bc07e7178b9ef387e
blob + f1ac0ac536edb3b36412093575f475c1e61ed840
--- dns.h
+++ dns.h
@@ -94,6 +94,7 @@ struct dns_question_hdr {
*/
#define DNS_REPLY 0x8000 /* if set response if not set query */
+#define DNS_NOTIFY 0x2000 /* a NOTIFY query RFC 1996 */
#define DNS_SREQ 0x1000 /* if set a server status request (STATUS) */
#define DNS_INV 0x800 /* if set an inverse query */
#define DNS_AUTH 0x400 /* Authoritative Answer (AA) in replies */
@@ -113,6 +114,7 @@ struct dns_question_hdr {
#define SET_DNS_REPLY(x) ((x)->query |= (DNS_REPLY))
#define SET_DNS_QUERY(x) ((x)->query &= ~(DNS_REPLY))
+#define SET_DNS_NOTIFY(x) ((x)->query |= (DNS_NOTIFY))
#define SET_DNS_STATUS_REQ(x) ((x)->query |= (DNS_SREQ))
#define SET_DNS_INVERSE_QUERY(x) ((x)->query |= (DNS_INV))
#define SET_DNS_AUTHORITATIVE(x) ((x)->query |= (DNS_AUTH))
@@ -126,6 +128,7 @@ struct dns_question_hdr {
#define SET_DNS_RCODE_FORMATERR(x) ((x)->query |= (DNS_FORMATERR))
#define SET_DNS_RCODE_NOERR(x) ((x)->query |= (DNS_NOERR))
+#define UNSET_DNS_NOTIFY(x) ((x)->query &= ~(DNS_NOTIFY))
#define UNSET_DNS_STATUS_REQ(x) ((x)->query &= ~(DNS_SREQ))
#define UNSET_DNS_INVERSE_QUERY(x) ((x)->query &= ~(DNS_INV))
#define UNSET_DNS_AUTHORITATIVE(x) ((x)->query &= ~(DNS_AUTH))
blob - bdbb62d7255f08daf6992905e639a4325e7517b6
blob + f91f1d6861339dea475f45b89fa3b6c2639de4df
--- example8.conf
+++ example8.conf
@@ -1,7 +1,6 @@
; sample config file that is in production.
;
version "6";
-
options "cool stuff" {
interface "lo0";
interface "em0";
@@ -29,8 +28,15 @@ axfr-for "these hosts" {
192.168.0.0/16;
}
+notify "these hosts" {
+ 192.168.34.1;
+ 192.168.35.1;
+ ::1;
+}
+
+
zone "centroid.eu" {
- centroid.eu,soa,3600,uranus.centroid.eu.,pjp.solarscale.de.,1258740680,3600,1800,7200,3600
+ centroid.eu,soa,3600,uranus.centroid.eu.,pjp.solarscale.de.,2014051701,3600,1800,7200,3600
centroid.eu,ns,3600,proteus.solarscale.de.
centroid.eu,ns,3600,uranus.centroid.eu.
centroid.eu,ns,3600,dione.solarscale.de.
@@ -132,3 +138,4 @@ zone "root hints" {
M.ROOT-SERVERS.NET.,a,3600000,202.12.27.33
M.ROOT-SERVERS.NET.,aaaa,3600000,2001:dc3::35
}
+
blob - 71f25c30eb641ff89d69fca0f81fa24951a80a16
blob + 84db77e188a5fd1c3b2df2d538389059c191f103
--- main.c
+++ main.c
@@ -64,6 +64,7 @@ extern void init_wildcard(void);
extern void init_recurse(void);
extern void init_region(void);
extern void init_filter(void);
+extern void init_notifyslave(void);
extern void collects_init(void);
extern void recurseloop(int sp, int *raw, DB *db);
extern int find_recurse(struct sockaddr_storage *, int);
@@ -168,7 +169,7 @@ static struct tcps {
} *tn1, *tnp, *tntmp;
-static const char rcsid[] = "$Id: main.c,v 1.93 2014/05/11 15:39:50 pjp Exp $";
+static const char rcsid[] = "$Id: main.c,v 1.94 2014/05/17 09:18:11 pjp Exp $";
/*
* MAIN - set up arguments, set up database, set up sockets, call mainloop
@@ -439,6 +440,7 @@ main(int argc, char *argv[])
init_recurse();
init_region();
init_filter();
+ init_notifyslave();
if (parse_file(db, conffile) < 0) {
dolog(LOG_INFO, "parsing config file failed\n");
blob - d03b32fd02b11e17276457af7a6c672a3d25384d
blob + 9db4a8a3de8bc59cbd04bdfc242ae5a8ff68edc4
--- parse.y
+++ parse.y
@@ -58,7 +58,7 @@ typedef struct {
int lineno;
} YYSTYPE;
-static const char rcsid[] = "$Id: parse.y,v 1.19 2014/05/11 15:58:29 pjp Exp $";
+static const char rcsid[] = "$Id: parse.y,v 1.20 2014/05/17 09:18:11 pjp Exp $";
static int version = 0;
static int state = 0;
static uint8_t region = 0;
@@ -67,6 +67,7 @@ static DB *mydb;
YYSTYPE yylval;
+extern int notify;
extern int errno;
extern int debug;
extern int verbose;
@@ -89,11 +90,13 @@ int converted_namelen;
DBT key, data;
struct logging logging;
int axfrport = 0;
+time_t time_changed;
extern char * dns_label(char *, int *);
extern u_int8_t find_region(struct sockaddr_storage *sst, int family);
extern int insert_region(char *address, char *prefixlen, u_int8_t region);
extern int insert_axfr(char *, char *);
+extern int insert_notifyslave(char *, char *);
extern int insert_filter(char *, char *);
extern int insert_recurse(char *, char *);
extern int insert_wildcard(char *, char *);
@@ -177,7 +180,7 @@ parse_file(DB *db, char *filename)
%token VERSION OBRACE EBRACE REGION AXFRFOR RECURSEFOR
%token DOT COLON TEXT WOF INCLUDE ZONE COMMA CRLF
-%token ERROR AXFRPORT LOGGING OPTIONS FILTER
+%token ERROR AXFRPORT LOGGING OPTIONS FILTER NOTIFY
%token <v.string> POUND
%token <v.string> SEMICOLON
@@ -206,6 +209,7 @@ cmd :
| region CRLF
| wof CRLF
| axfr CRLF
+ | notify CRLF
| filter CRLF
| recurse CRLF
| logging
@@ -837,6 +841,55 @@ filterstatement : ipcidr SEMICOLON CRLF
;
+/* notify "these hosts" { .. } */
+
+notify:
+ NOTIFY notifylabel notifycontent
+ {
+ if ((confstatus & CONFIG_VERSION) != CONFIG_VERSION) {
+ dolog(LOG_INFO, "There must be a version at the top of the first configfile\n");
+ return (-1);
+ }
+ }
+ ;
+
+notifylabel:
+ QUOTEDSTRING
+ ;
+
+notifycontent:
+ OBRACE notifystatements EBRACE
+ | OBRACE CRLF notifystatements EBRACE
+ ;
+
+notifystatements :
+ notifystatements notifystatement
+ | notifystatement
+ ;
+
+notifystatement : ipcidr SEMICOLON CRLF
+ {
+ char prefixlength[INET_ADDRSTRLEN];
+ char *dst;
+
+
+ if ((dst = get_prefixlen($1, (char *)&prefixlength, sizeof(prefixlength))) == NULL) {
+ return (-1);
+ }
+
+ if (insert_notifyslave(dst, prefixlength) < 0) {
+ dolog(LOG_ERR, "insert_notifyslave, line %d\n", file->lineno);
+ return (-1);
+ }
+
+ notify++;
+
+ free (dst);
+ free ($1);
+ }
+ | comment CRLF
+ ;
+
/* axfr-for "these hosts" { .. } */
axfr:
@@ -1091,6 +1144,7 @@ struct tab cmdtab[] = {
{ "wildcard-only-for", WOF, STATE_IP },
{ "version", VERSION, 0 },
{ "zone", ZONE, 0 },
+ { "notify", NOTIFY, STATE_IP },
{ NULL, 0, 0}};
int
@@ -2449,23 +2503,35 @@ set_record(struct domain *sdomain, char *converted_nam
struct file *
pushfile(const char *name, int secret)
{
+ struct stat sb;
struct file *nfile;
+ int fd;
if ((nfile = calloc(1, sizeof(struct file))) == NULL) {
- dolog(LOG_INFO, "warn: malloc");
+ dolog(LOG_INFO, "warn: malloc\n");
return (NULL);
}
if ((nfile->name = strdup(name)) == NULL) {
- dolog(LOG_INFO, "warn: malloc");
+ dolog(LOG_INFO, "warn: malloc\n");
free(nfile);
return (NULL);
}
if ((nfile->stream = fopen(nfile->name, "r")) == NULL) {
- dolog(LOG_INFO, "warn: %s", nfile->name);
+ dolog(LOG_INFO, "warn: %s\n", nfile->name);
free(nfile->name);
free(nfile);
return (NULL);
}
+
+ fd = fileno(nfile->stream);
+ if (fstat(fd, &sb) < 0) {
+ dolog(LOG_INFO, "warn: %s\n", strerror(errno));
+ }
+
+ /* get the highest time of all included files */
+ if (time_changed < sb.st_ctime)
+ time_changed = (time_t)sb.st_ctime; /* ufs1 is only 32 bits */
+
nfile->lineno = 1;
TAILQ_INSERT_TAIL(&files, nfile, entry);
return (nfile);
repomaster@centroid.eu