Commit Diff
Diff:
b55adb0c8e519c884d80e7ea12a174d5e2dfd5ed
f1e825ef04c852d71ae660b0ab8736ac66ece115
Commit:
f1e825ef04c852d71ae660b0ab8736ac66ece115
Tree:
fccaa25b5a5abf4c3b4b737ddedf7d594af22f50
Author:
pbug <pbug@delphinusdns.org>
Committer:
pbug <pbug@delphinusdns.org>
Date:
Tue Sep 28 08:12:59 2010 UTC
Message:
* use a "lookrecord" field to see from what we're looking up stuff in parse_recurse, basically this protects us from inheriting bad glue tested on OpenBSD
blob - e7d4697ebcd3a3509658c87f3098c52cd7eede77
blob + 88a645b1eaf8797e30825b60c9c5f563d27c8df7
--- db.h
+++ db.h
@@ -162,6 +162,7 @@ struct recurses {
/* the below is our indicator which part of the lookup we're at */
+ u_char *lookrecord; /* what zone lookup is it from */
int indicator; /* indicator of ns lookup */
int authoritative; /* last reply was authoritative, type */
int hascallback; /* some request has callback don't remove */
blob - 8c7b93bbe1a951a36ef10625c50bc0ff0136f888
blob + c3768ed1bacc398ac226ac26c6d25bceeb446380
--- recurse.c
+++ recurse.c
@@ -45,7 +45,7 @@ int lookup_a(DB *, struct recurses *, struct ns *);
int recurse_parse(DB *db, struct recurses *sr, u_char *buf, u_int16_t offset);
int negative_cache(DB *db, struct recurses *sr);
int netlookup(DB *db, struct recurses *sr);
-int fakerecurse(DB *db, struct recurses *sr, struct ns *ns);
+int fakerecurse(DB *db, struct recurses *sr, struct ns *ns, int);
void reply_raw(DB *db, struct recurses *sr, struct domain *sd, int *raw);
void reply_raw_cname(DB *db, struct recurses *sr, struct domain *sd, int *raw);
void reply_raw_noerror(DB *, struct recurses *, struct domain *, int *);
@@ -64,7 +64,13 @@ extern int memcasecmp(u_char *, u_char *, int);
extern int get_soa(DB *, struct question *, struct domain *, int);
extern void reply_noerror(struct sreply *);
void remove_zone(DB *db, struct domain *sd);
+int contains(u_char *a, u_char *b);
+int level(u_char *p);
+#ifndef MIN
+#define MIN(a,b) ((a < b) ? a : b)
+#endif
+
SLIST_HEAD(listhead, recurseentry) recursehead;
struct recurseentry {
@@ -77,7 +83,7 @@ struct recurseentry {
} *rn1, *rn2, *rnp;
-static const char rcsid[] = "$Id: recurse.c,v 1.24 2010/09/26 16:20:08 pbug Exp $";
+static const char rcsid[] = "$Id: recurse.c,v 1.25 2010/09/28 08:13:00 pbug Exp $";
/*
* INIT_RECURSE - initialize the recurse singly linked list
@@ -246,6 +252,7 @@ recurseloop(int sp, int *raw, DB *db)
if (type < 0) {
netlookup(db, sr1);
} else {
+ SLIST_REMOVE(&recurseshead, sr1, recurses, entries);
sr1->callback->hascallback--;
free_question(sr1->question);
free(sr1);
@@ -257,12 +264,13 @@ recurseloop(int sp, int *raw, DB *db)
* fakesr launches we may as well expire recurses
* that have timed out (> 10 seconds)
*/
- if (difftime(time(NULL), sr1->received) >= 10) {
+ if (difftime(time(NULL), sr1->received) >= 30) {
syslog(LOG_DEBUG, "removing recurses struct");
SLIST_REMOVE(&recurseshead, sr1, recurses, entries);
if (sr1->so != -1) {
if (close(sr1->so) < 0)
syslog(LOG_ERR, "close: %m");
+ sr1->so = -1;
}
free_question(sr1->question);
@@ -319,6 +327,7 @@ recurseloop(int sp, int *raw, DB *db)
sr->hascallback = 0;
sr->isfake = 0;
sr->packetcount = 0;
+ sr->lookrecord = NULL;
memcpy(&sr->source, &rh.source, sizeof(struct sockaddr_storage));
memcpy(&sr->dest, &rh.dest, sizeof(struct sockaddr_storage));
sr->received = time(NULL);
@@ -608,7 +617,12 @@ again:
syslog(LOG_DEBUG, "we gots a lookup, yay!\n");
#endif
+ /*
+ * record which record we used
+ */
+ sr->lookrecord = p;
+
memcpy((char *)&mydomain, (char *)data.data, sizeof(struct domain));
sd = (struct domain *)&mydomain;
@@ -724,8 +738,8 @@ lookup_a(DB *db, struct recurses *sr, struct ns *ns)
}
if (! found) {
- syslog(LOG_DEBUG, "calling fakerecurse, sleeping 1 second for debug");
- fakerecurse(db, sr, ns);
+ syslog(LOG_DEBUG, "calling fakerecurse");
+ fakerecurse(db, sr, ns, DNS_TYPE_A);
return (-1);
}
@@ -824,6 +838,7 @@ recurse_parse(DB *db, struct recurses *sr, u_char *buf
struct answer *a;
struct mysoa *mysoa;
struct soa *soa;
+ struct ns ns;
u_int i, j, k;
u_int16_t *compressor;
@@ -1147,8 +1162,26 @@ again:
syslog(LOG_INFO, "db can't hold any more records\n");
update = 0;
}
+
+ /*
+ * check if we're a 2nd level domain or higher and
+ * if we were directly querying the zone...
+ */
if (update) {
+ if (level(sr->lookrecord) > 1) {
+ if (!contains(sr->lookrecord, converted_name[i])) {
+ memcpy(ns.nsserver, converted_name[i], cn_len[i]);
+ ns.nslen = cn_len[i];
+
+ fakerecurse(db, sr, &ns, DNS_TYPE_A);
+ update = 0;
+ }
+ }
+ }
+
+
+ if (update) {
memcpy(&sdomain.a[j], p, sizeof(in_addr_t));
sdomain.a_count++;
sdomain.region[j] = 0xff;
@@ -1161,9 +1194,10 @@ again:
if (! (sdomain.flags & DOMAIN_STATIC_ZONE)) {
update_db(db, &sdomain);
inet_ntop(AF_INET, p, abuf, sizeof(abuf));
- syslog(LOG_DEBUG, "updateing zone %s with address %s ttl= %u\n", converted_name[i], abuf, sdomain.ttl);
+ syslog(LOG_DEBUG, "updateing zone %s with address %s ttl= %u, lookrecord = %s", converted_name[i], abuf, sdomain.ttl, sr->lookrecord);
}
- }
+ } else
+ free(sdomain.zone);
p += sizeof(in_addr_t);
if (pointer > 2) {
@@ -1196,7 +1230,24 @@ again:
update = 0;
}
+ /*
+ * check if we're a 2nd level domain or higher and
+ * if we were directly querying the zone...
+ */
+
if (update) {
+ if (level(sr->lookrecord) > 1) {
+ if (!contains(sr->lookrecord, converted_name[i])) {
+ memcpy(ns.nsserver, converted_name[i], cn_len[i]);
+ ns.nslen = cn_len[i];
+
+ fakerecurse(db, sr, &ns, DNS_TYPE_AAAA);
+ update = 0;
+ }
+ }
+ }
+
+ if (update) {
sdomain.aaaa[j] = malloc(sizeof(struct in6_addr));
if (sdomain.aaaa[j] == NULL) {
syslog(LOG_ERR, "malloc: %m");
@@ -1215,7 +1266,8 @@ again:
inet_ntop(AF_INET6, p, abuf, sizeof(abuf));
syslog(LOG_DEBUG, "updateing zone %s with address %s ttl= %u\n", converted_name[i], abuf, sdomain.ttl);
}
- }
+ } else
+ free(sdomain.zone);
if (pointer > 2) {
syslog(LOG_ERR, "there is more records than indicated in the header!!!");
@@ -1281,6 +1333,27 @@ again:
}
if (ntohs(a->type) == DNS_TYPE_CNAME) {
+ /*
+ * we check this as well as the A and AAAA
+ * types since it may be possible to glue
+ * a CNAME instead of an A and thus poison
+ * our cache...
+ */
+ if (level(sr->lookrecord) > 1) {
+ if (!contains(sr->lookrecord, converted_name[i - 1])) {
+
+ memcpy(ns.nsserver, converted_name[i - 1], cn_len[i - 1]);
+ ns.nslen = cn_len[i];
+
+ fakerecurse(db, sr, &ns, DNS_TYPE_A);
+ free(sdomain.zone);
+ rrcount[pointer]--;
+ if (rrcount[pointer] == 0)
+ pointer++;
+ p++;
+ break;
+ }
+ }
sdomain.cname = malloc(cn_len[i]);
if (sdomain.cname == NULL) {
@@ -1345,11 +1418,8 @@ again:
} else if (ntohs(a->type) == DNS_TYPE_NS) {
update = 1;
for (j = 0; j < sdomain.ns_count; j++) {
+ if (memcasecmp(sdomain.ns[j]->nsserver, converted_name[i], MIN(cn_len[i], sdomain.ns[j]->nslen)) == 0) {
#if 0
- syslog(LOG_DEBUG, "nameserver record %s", sdomain.ns[j]->nsserver);
-#endif
- if (memcmp(sdomain.ns[j]->nsserver, converted_name[i], cn_len[i]) == 0) {
-#if 0
syslog(LOG_INFO, "record exists already");
#endif
update = 0;
@@ -1399,7 +1469,7 @@ again:
} else if (ntohs(a->type) == DNS_TYPE_MX) {
update = 1;
for (j = 0; j < sdomain.mx_count; j++) {
- if (memcmp(sdomain.mx[j]->exchange, converted_name[i], cn_len[i]) == 0) {
+ if (memcasecmp(sdomain.mx[j]->exchange, converted_name[i], MIN(cn_len[i], sdomain.mx[j]->exchangelen)) == 0) {
update = 0;
}
}
@@ -1666,7 +1736,7 @@ netlookup(DB *db, struct recurses *sr)
*/
int
-fakerecurse(DB *db, struct recurses *sr, struct ns *ns)
+fakerecurse(DB *db, struct recurses *sr, struct ns *ns, int type)
{
struct recurses *fakesr;
struct dns_header *dh;
@@ -1679,7 +1749,7 @@ fakerecurse(DB *db, struct recurses *sr, struct ns *ns
/* check if we have already started a fakerecurse on the same name */
SLIST_FOREACH(sr2, &recurseshead, entries) {
- if (memcasecmp((u_char *)ns->nsserver, (u_char *)sr2->question->hdr->name, ns->nslen) == 0) {
+ if (memcasecmp((u_char *)ns->nsserver, (u_char *)sr2->question->hdr->name, MIN(ns->nslen, sr2->question->hdr->namelen)) == 0) {
syslog(LOG_INFO, "already have a fakerecurse structure with name %s, drop\n", ns->nsserver);
return (-1);
}
@@ -1705,8 +1775,9 @@ fakerecurse(DB *db, struct recurses *sr, struct ns *ns
fakesr->launched = 0;
fakesr->received = time(NULL);
fakesr->packetcount = 0;
+ fakesr->lookrecord = NULL;
- fakesr->question = build_fake_question(ns->nsserver, ns->nslen, htons(DNS_TYPE_A));
+ fakesr->question = build_fake_question(ns->nsserver, ns->nslen, htons(type));
if (fakesr->question == NULL) {
syslog(LOG_ERR, "malformed question in recurse.c");
free(fakesr);
@@ -1977,4 +2048,59 @@ reply_raw_nxdomain(DB *db, struct recurses *sr, struct
reply_nxdomain(&sreply);
return;
+}
+
+
+/*
+ * LEVEL - traverse a domain name and count how many levels it has
+ * first level is a TLD, then a 2nd level domain and so on.
+ */
+
+int
+level(u_char *p)
+{
+ int level = 0;
+
+ while (*p) {
+ level++;
+ p += ((*p) + 1);
+ }
+
+ return (level);
+}
+
+/*
+ * CONTAINS - check if domain name A is contained in domain name B
+ *
+ */
+
+int
+contains(u_char *a, u_char *b)
+{
+ u_char *p = a;
+ u_char *q = b;
+ u_int plen = 0, qlen = 0;
+
+ while (*p) {
+ plen += (*p) + 1;
+ p += ((*p) + 1);
+ }
+
+ while (*q) {
+ qlen += ((*q) + 1);
+ q += ((*q) + 1);
+ }
+
+ p = a;
+ q = b;
+
+ while (*q) {
+ if ((plen == qlen) && memcasecmp(p, q, qlen) == 0)
+ return (1);
+
+ qlen -= ((*q) + 1);
+ q += ((*q) + 1);
+ }
+
+ return (0);
}
repomaster@centroid.eu