Commit Diff
Diff:
b3b45d41422bccc6c1ff03543b59fb2344c4221f
604e0a34fc223c0f3395d2df777b34cb77193999
Commit:
604e0a34fc223c0f3395d2df777b34cb77193999
Tree:
f6549582451948159c0b19851857eb4ae3bd8a27
Author:
pbug <pbug@delphinusdns.org>
Committer:
pbug <pbug@delphinusdns.org>
Date:
Wed Sep 15 19:34:04 2010 UTC
Message:
* negative caching support, not all finished yet compiles on OpenBSD
blob - a959d73e1a6e97bf259105c52e6ae9aa9151d9d4
blob + d127bf26deeddbe13e9cd6821e3e143c538f83b3
--- db.h
+++ db.h
@@ -35,6 +35,7 @@
#define ERR_NOERROR 0x4
#define RECORD_COUNT 20
+#define NEGATIVE_CACHE_TIME 600 /* DNS & Bind 3rd edition page 35 */
/* db stuff */
@@ -75,6 +76,7 @@ struct domain {
#define DOMAIN_HAVE_NS 0x40
#define DOMAIN_HAVE_TXT 0x80
#define DOMAIN_STATIC_ZONE 0x100
+#define DOMAIN_NEGATIVE_CACHE 0x200
struct soa *soa; /* start of authority */
u_int32_t ttl; /* time to live */
time_t created; /* time created, for dynamic zones */
blob - 212e03d869f3cd3290f754a5677f97963e4bc59c
blob + e72aaa59ba54356225fdcea44b75608c6963de46
--- parse.c
+++ parse.c
@@ -84,7 +84,7 @@ struct cmd_lookup {
static u_int32_t config = 0;
-static const char rcsid[] = "$Id: parse.c,v 1.27 2010/06/06 20:33:57 pbug Exp $";
+static const char rcsid[] = "$Id: parse.c,v 1.28 2010/09/15 19:34:04 pbug Exp $";
/*
* PARSE_FILE - parse the configfile XXX rewrite me in yacc :(
@@ -972,6 +972,10 @@ parse_file0(char *filename, DB *db, FILE *f)
default:
break;
}
+
+ /* Any zone in here gets a static flag */
+
+ sdomain.flags |= DOMAIN_STATIC_ZONE;
/* write new record into btree database */
blob - 5e57b151f9feecfd339e910e5dd4b420e73b052b
blob + 5e97547a50ec294a13382a271bbb28a2c161b72c
--- recurse.c
+++ recurse.c
@@ -37,6 +37,7 @@ extern void update_db(DB *, struct domain *);
extern in_addr_t getmask(int prefixlen);
extern int getmask6(int prefixlen, struct sockaddr_in6 *sin6);
extern struct question * build_question(char *buf, int len);
+extern int free_question(struct question *);
extern int lookup_zone(DB *db, struct question *question, struct domain *sd, int *lzerrno, char *replystring, int wildcard);
@@ -85,12 +86,14 @@ struct recurses {
struct question *question; /* question struct */
SLIST_ENTRY(recurses) entries;
-};
+} *sr, *sr1;
int lookup_ns(DB *, struct recurses *);
int lookup_a(DB *, struct recurses *, struct ns *);
+int recurse_parse(DB *db, struct recurses *sr, char *buf, int len);
+int negative_cache(DB *db, struct recurses *sr);
-static const char rcsid[] = "$Id: recurse.c,v 1.3 2010/09/15 11:35:32 pbug Exp $";
+static const char rcsid[] = "$Id: recurse.c,v 1.4 2010/09/15 19:34:04 pbug Exp $";
/*
* INIT_RECURSE - initialize the recurse singly linked list
@@ -229,10 +232,10 @@ void
recurseloop(int sp, int *raw, DB *db)
{
int sel, ret;
+ int maxso, len, slen = sizeof(struct sockaddr);
fd_set rset;
struct timeval tv;
struct srecurseheader rh;
- struct recurses *sr;
struct domain sd;
struct sockaddr_in sin;
struct dns_header *dh;
@@ -240,6 +243,7 @@ recurseloop(int sp, int *raw, DB *db)
int type, lzerrno, wildcard = 0;
char fakereplystring[DNS_MAXNAME + 1];
+ char buf[2048];
@@ -248,11 +252,20 @@ recurseloop(int sp, int *raw, DB *db)
for (;;) {
FD_ZERO(&rset);
+ maxso = sp;
FD_SET(sp, &rset);
+ /* XXX remember recurseshead is for struct recurses */
+ SLIST_FOREACH(sr1, &recurseshead, entries) {
+ if (maxso < sr1->so)
+ maxso = sr1->so;
+
+ FD_SET(sr1->so, &rset);
+ }
+
tv.tv_sec = 1;
tv.tv_usec = 0;
- sel = select(sp + 1, &rset, NULL, NULL, &tv);
+ sel = select(maxso + 1, &rset, NULL, NULL, &tv);
if (sel < 0) {
syslog(LOG_INFO, "select: %m");
continue;
@@ -280,6 +293,7 @@ recurseloop(int sp, int *raw, DB *db)
sr->len = rh.len;
sr->af = rh.af;
sr->proto = rh.proto;
+ sr->so = -1;
memcpy(&sr->source, &rh.source, sizeof(struct sockaddr_storage));
memcpy(&sr->dest, &rh.dest, sizeof(struct sockaddr_storage));
sr->received = time(NULL);
@@ -298,11 +312,19 @@ recurseloop(int sp, int *raw, DB *db)
sr->so = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (sr->so < 0) {
syslog(LOG_ERR, "socket: %m");
+ free_question(sr->question);
free(sr); /* XXX */
continue;
}
sr->port = arc4random() & 0xffff;
+ /*
+ * we have to avoid picking servers already
+ * running ..
+ */
+ if (sr->port < 1024)
+ sr->port += 1024;
+
sr->id = arc4random() & 0xffff;
memset(&sin, 0, sizeof(sin));
@@ -313,17 +335,28 @@ recurseloop(int sp, int *raw, DB *db)
if (bind(sr->so, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
syslog(LOG_ERR, "bind: %m");
close(sr->so);
+ free_question(sr->question);
free(sr);
continue;
}
- lookup_ns(db, sr);
+ if (lookup_ns(db, sr) <= 0) {
+ syslog(LOG_ERR, "can't establish any servers to reach for zone \"%s\"", sr->question->converted_name);
+ close(sr->so);
+ free_question(sr->question);
+ free(sr);
+ continue;
+ }
memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_port = htons(53);
+#if 1
+ /* use dummy root server for now */
sin.sin_addr.s_addr = inet_addr("192.168.0.2");
-
+#else
+ sin.sin_addr.s_addr = sr->a[0];
+#endif
dh = (struct dns_header *)sr->query;
dh->id = htons(sr->id);
@@ -335,9 +368,12 @@ recurseloop(int sp, int *raw, DB *db)
if (sendto(sr->so, sr->query, sr->len, 0, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
syslog(LOG_ERR, "sendto: %m");
close(sr->so);
+ free_question(sr->question);
free(sr);
continue;
}
+
+ sr->sent_last_query = time(NULL);
/*
* add to our linked list of outstanding
@@ -354,18 +390,66 @@ recurseloop(int sp, int *raw, DB *db)
}
} /* FD_ISSET(sp) */
+
+ SLIST_FOREACH(sr1, &recurseshead, entries) {
+ if (FD_ISSET(sr1->so, &rset)) {
+ /*
+ * we got a reply from the nameserver we
+ * queried, now we must parse the input
+ */
+
+ if ((len = recvfrom(sr1->so, buf, sizeof(buf), 0, (struct sockaddr *)&sin, &slen)) < 0) {
+ syslog(LOG_ERR, "recvfrom: %m");
+ continue;
+ }
-#if 0
- sd = lookup_cache(rh);
- if (sd == NULL) {
-
- fd = lookup_net(rh);
+ /* XXX do some checking of expected IP address */
+ if (sin.sin_addr.s_addr != inet_addr("192.168.0.2")) {
+ syslog(LOG_ERR, "address is not 192.168.0.2");
+ continue;
+ }
- put on linked list, select the descriptor
- } else {
- reply_raw(rh);
- }
+ if (len < sizeof(struct dns_header)) {
+ syslog(LOG_ERR, "size malformed on reply len=%d", len);
+ /* on error, we just go out and wait for the real ID, this sucks! XXX */
+ continue;
+ }
+ dh = (struct dns_header*)&buf[0];
+
+ if (ntohs(dh->id) != sr1->id) {
+ syslog(LOG_ERR, "unexpected dns ID (%u != %u)", ntohs(dh->id), sr->id);
+ /* on error, we just go out and wait for the real ID, this sucks! XXX */
+ continue;
+ }
+
+ if (! (ntohs(dh->query) & DNS_REPLY)) {
+ syslog(LOG_ERR, "reply is not a DNS reply");
+ continue;
+ }
+
+ /* XXX */
+
+ close(sr1->so);
+
+ if (ntohs(dh->query) & DNS_NAMEERR) {
+ negative_cache(db, sr1);
+ syslog(LOG_DEBUG, "added negative cache for domain \"%s\"", sr1->question->converted_name);
+ /* reply negatively */
+ goto remove;
+ }
+
+ recurse_parse(db, sr1, buf, len);
+
+remove:
+ SLIST_REMOVE(&recurseshead, sr1, recurses, entries);
+ free_question(sr->question);
+ free(sr1);
+
+ } /* FD_ISSET(sr1->so */
+ } /* SLIST_FOREACH(sr... */
+
+#if 0
/*
I drew this on a notepad one night, I think that's supposed to how
it shoudl go...
@@ -406,14 +490,14 @@ recurseloop(int sp, int *raw, DB *db)
#endif
- }
+ } /* for(;;) */
-
+ /* NOTREACHED */
}
/*
* LOOKUP_NS - given an address try to look up the nameservers anywhere along
- * its path.
+ * its path. return number of servers reachable or -1 on error.
*/
int
@@ -478,6 +562,32 @@ again:
memcpy((char *)&mydomain, (char *)data.data, sizeof(struct domain));
sd = (struct domain *)&mydomain;
+
+ /*
+ * If we're not a static zone (like hints) and we're
+ * expired then we go on to the next indicator..
+ */
+ if ((! (sd->flags & DOMAIN_STATIC_ZONE)) &&
+ (time(NULL) > (sd->created + sd->ttl))) {
+
+ if (*p != 0) {
+ plen -= (*p + 1);
+ p = (p + (*p + 1));
+ sr->indicator++;
+ continue;
+ } else {
+ return (-1);
+ }
+ }
+ /*
+ * If we have a negative cache, then just return with
+ * error.
+ */
+ if ((sd->flags & DOMAIN_NEGATIVE_CACHE) &&
+ (time(NULL) <= (sd->created + sd->ttl))) {
+ return (-1);
+ }
+
sr->a_count = 0;
sr->a_ptr = 0;
@@ -495,9 +605,12 @@ again:
} while (*p != 0 && ret != 0);
+#if 0
syslog(LOG_DEBUG, "got %d addresses for %s, indicator %d\n", sr->a_count, sr->question->converted_name, sr->indicator);
- return (0);
+#endif
+
+ return (sr->a_count);
}
@@ -554,6 +667,62 @@ lookup_a(DB *db, struct recurses *sr, struct ns *ns)
} else
return (-1);
+
+ return (0);
+}
+
+int
+recurse_parse(DB *db, struct recurses *sr, char *buf, int len)
+{
+ struct dns_header *dh;
+ char *question;
+ int i;
+
+ dh = (struct dns_header *)buf;
+
+
+ return (0);
+}
+
+int
+negative_cache(DB *db, struct recurses *sr)
+{
+ struct domain sd;
+
+ memset(&sd, 0, sizeof(sd));
+
+ sd.zonelen = sr->question->hdr->namelen;
+ if (sd.zone == NULL) {
+ sd.zone = (char *) malloc(sd.zonelen);
+ if (sd.zone == NULL) {
+ syslog(LOG_INFO, "malloc: %m");
+ return (-1);
+ }
+ }
+
+ memcpy((char *)sd.zone, (char *)sr->question->hdr->name, sd.zonelen);
+
+ if (sd.zonename == NULL) {
+ sd.zonename = (char *) malloc(DNS_MAXNAME + 1);
+ if (sd.zonename == NULL) {
+ syslog(LOG_INFO, "malloc(1): %m");
+ return (-1);
+ }
+ }
+
+#if __linux__
+ strncpy((char *)sd.zonename, (char *)sr->question->converted_name, DNS_MAXNAME);
+ sd.zonename[DNS_MAXNAME] = 0;
+#else
+ strlcpy((char *)sd.zonename, (char *)sr->question->converted_name, DNS_MAXNAME + 1);
+#endif
+
+ sd.created = time(NULL);
+ sd.ttl = NEGATIVE_CACHE_TIME; /* 10 minutes */
+
+ sd.flags |= DOMAIN_NEGATIVE_CACHE;
+
+ update_db(db, &sd);
return (0);
}
repomaster@centroid.eu