Commit Diff
Diff:
cfbdfdca30a7892eab2b34b22211601859332a53
b36746d80f9559a72037b8e5b6999f34507200fa
Commit:
b36746d80f9559a72037b8e5b6999f34507200fa
Tree:
bdf0993b8d9ab9cd9fb483d42e9f63692688af3c
Author:
pbug <pbug@delphinusdns.org>
Committer:
pbug <pbug@delphinusdns.org>
Date:
Sat Sep 25 11:08:06 2010 UTC
Message:
* when querying an A record and the remote end has no A record but there is a zone they reply with a NOERROR and SOA set to authoritative. We now honor that instead of repeating/flooding (sorry bsi.de) and reply to the client as well. tested on zones bsi.de and ipv6.solarscale.de compiles and tested with OpenBSD
blob - c753a37514181072494e7dca0f99034f1be1214c
blob + 363c5b86019196fc4feebc99dbb3802d2c791df2
--- db.h
+++ db.h
@@ -162,6 +162,7 @@ struct recurses {
/* the below is our indicator which part of the lookup we're at */
int indicator; /* indicator of ns lookup */
+ int authoritative; /* last reply was authoritative, type */
int hascallback; /* some request has callback don't remove */
struct question *question; /* question struct */
blob - a328daa51613824f1a4f8826c6662f3da447f947
blob + 016f88173e94ce213858a00f9653aad4ea7bf26c
--- recurse.c
+++ recurse.c
@@ -47,10 +47,12 @@ 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);
void reply_raw(DB *db, struct recurses *sr, struct domain *sd, int *raw);
+void reply_raw_noerror(DB *, struct recurses *, struct domain *, int *);
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);
extern void reply_a(struct sreply *, DB *);
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);
SLIST_HEAD(listhead, recurseentry) recursehead;
@@ -65,7 +67,7 @@ struct recurseentry {
} *rn1, *rn2, *rnp;
-static const char rcsid[] = "$Id: recurse.c,v 1.15 2010/09/24 08:12:14 pbug Exp $";
+static const char rcsid[] = "$Id: recurse.c,v 1.16 2010/09/25 11:08:07 pbug Exp $";
/*
* INIT_RECURSE - initialize the recurse singly linked list
@@ -382,16 +384,29 @@ recurseloop(int sp, int *raw, DB *db)
goto remove;
}
+ sr1->authoritative = 0;
recurse_parse(db, sr1, (u_char*)&buf, len);
type = lookup_zone(db, sr1->question, &sd, &lzerrno, (char *)fakereplystring, wildcard);
if (type < 0) {
syslog(LOG_DEBUG, "lookup_zone failed, doing netlookup");
- if (netlookup(db, sr1) < 0) {
+ if (sr1->authoritative == DNS_TYPE_NS &&
+ netlookup(db, sr1) < 0) {
syslog(LOG_DEBUG, "subsequent netlookup failed");
}
+ if (sr1->authoritative == DNS_TYPE_SOA) {
+ syslog(LOG_DEBUG, "got an authoritative SOA answer, we'd reply an SOA here");
+ memset(&sd, 0, sizeof(struct domain));
+ get_soa(db, sr1->question, &sd, wildcard);
+
+ reply_raw_noerror(db, sr, &sd, raw);
+ if (sr1->callback)
+ sr1->callback->hascallback--;
+ goto remove;
+ }
+
continue;
} else {
/* we've found the record we're looking
@@ -725,12 +740,15 @@ recurse_parse(DB *db, struct recurses *sr, u_char *buf
u_int8_t cn_len[256];
u_char *end = &buf[offset];
int update;
+ int rrcount[3]; /* RR count answer, authoritative, additional */
+ int pointer = 0; /* default answer */
char abuf[INET6_ADDRSTRLEN];
DBT key, data;
struct domain sdomain;
+ struct dns_header *dh;
struct question {
u_int16_t type;
u_int16_t class;
@@ -761,6 +779,18 @@ recurse_parse(DB *db, struct recurses *sr, u_char *buf
u_char *p, *q, *r;
+ dh = (struct dns_header*)&buf[0];
+ rrcount[pointer++] = ntohs(dh->answer);
+ rrcount[pointer++] = ntohs(dh->nsrr);
+ rrcount[pointer++] = ntohs(dh->additional);
+
+ pointer = 0;
+ while (rrcount[pointer] == 0) {
+ pointer++;
+ if (pointer > 2)
+ return (-1);
+ }
+
p = &buf[sizeof(struct dns_header)];
label[0] = p;
@@ -1081,6 +1111,14 @@ again:
}
p += sizeof(in_addr_t);
+ rrcount[pointer]--;
+ if (rrcount[pointer] == 0)
+ pointer++;
+ if (pointer > 2) {
+ syslog(LOG_ERR, "there is more records than indicated in the header!!!");
+ return (-1);
+ }
+
break;
case DNS_TYPE_AAAA:
p += 16; /* sizeof 4 * 32 bit */
@@ -1153,6 +1191,16 @@ again:
}
} /* if update */
+ rrcount[pointer]--;
+ if (pointer == 1) /* authoritative */
+ sr->authoritative = DNS_TYPE_NS;
+ if (rrcount[pointer] == 0)
+ pointer++;
+ if (pointer > 2) {
+ syslog(LOG_ERR, "there is more records than indicated in the header!!!");
+ return (-1);
+ }
+
} /* if type ns */
p++; /* one more */
@@ -1207,21 +1255,32 @@ again:
soa->nsserver_len = cn_len[i - 1];
memcpy(soa->responsible_person, converted_name[i], cn_len[i]);
soa->rp_len = cn_len[i];
- soa->serial = mysoa->serial;
- soa->refresh = mysoa->refresh;
- soa->retry = mysoa->retry;
- soa->expire = mysoa->expire;
- soa->minttl = mysoa->minttl;
+ soa->serial = ntohl(mysoa->serial);
+ soa->refresh = ntohl(mysoa->refresh);
+ soa->retry = ntohl(mysoa->retry);
+ soa->expire = ntohl(mysoa->expire);
+ soa->minttl = ntohl(mysoa->minttl);
sdomain.soa = soa;
sdomain.flags |= DOMAIN_HAVE_SOA;
sdomain.created = time(NULL);
- sdomain.ttl = a->ttl;
+ sdomain.ttl = htonl(a->ttl);
if (! (sdomain.flags & DOMAIN_STATIC_ZONE)) {
update_db(db, &sdomain);
}
+ rrcount[pointer]--;
+ if (pointer == 1) /* authoritative */
+ sr->authoritative = DNS_TYPE_SOA;
+ if (rrcount[pointer] == 0)
+ pointer++;
+
+ if (pointer > 2) {
+ syslog(LOG_ERR, "there is more records than indicated in the header!!!");
+ return (-1);
+ }
+
break;
default:
break;
@@ -1515,4 +1574,39 @@ remove_zone(DB *db, struct domain *sd)
free(zone);
return;
+}
+
+void
+reply_raw_noerror(DB *db, struct recurses *sr, struct domain *sd, int *raw)
+{
+ int so;
+ struct sreply sreply;
+
+ syslog(LOG_DEBUG, "reply_raw_noerror called");
+
+ switch (sr->af) {
+ case AF_INET:
+ so = raw[0];
+ break;
+ case AF_INET6:
+ so = raw[1];
+ break;
+ default:
+ syslog(LOG_ERR, "reply_raw_noerror(): unknown address family in struct recurses");
+ return;
+ }
+
+ switch (sr->proto) {
+ case IPPROTO_UDP:
+ break;
+ default:
+ syslog(LOG_ERR, "reply_raw_noerror(): can't do any protocol other than udp right now");
+ return;
+ }
+
+ build_reply(&sreply, so, sr->query, sr->len, sr->question, NULL, 0, sd, NULL, 0xff, 0, 0, sr);
+
+ reply_noerror(&sreply);
+
+ return;
}
blob - 95fe9622fd57234347979f0ce5f95b9b7282f98a
blob + bee8fa8e97aea852f3674f1d4fb56ef70adb37ec
--- reply.c
+++ reply.c
@@ -70,7 +70,7 @@ struct collects {
} *cn1, *cn2, *cnp;
-static const char rcsid[] = "$Id: reply.c,v 1.27 2010/09/21 19:04:43 pbug Exp $";
+static const char rcsid[] = "$Id: reply.c,v 1.28 2010/09/25 11:08:07 pbug Exp $";
/*
* REPLY_A() - replies a DNS question (*q) on socket (so)
@@ -1864,10 +1864,11 @@ reply_noerror(struct sreply *sreply)
outlen += (q->hdr->namelen + 4);
SET_DNS_REPLY(odh);
- SET_DNS_AUTHORITATIVE(odh);
-#if 0
- SET_DNS_RCODE_NAMEERR(odh);
-#endif
+
+ if (sreply->sr == NULL)
+ SET_DNS_AUTHORITATIVE(odh);
+ else
+ SET_DNS_RECURSION_AVAIL(odh);
NTOHS(odh->query);
@@ -1883,7 +1884,10 @@ reply_noerror(struct sreply *sreply)
answer->name[1] = 0x0c;
answer->type = htons(DNS_TYPE_SOA);
answer->class = q->hdr->qclass;
- answer->ttl = htonl(sd->ttl);
+ if (sreply->sr != NULL)
+ answer->ttl = htonl(sd->ttl - (time(NULL) - sd->created));
+ else
+ answer->ttl = htonl(sd->ttl);
outlen += 12; /* up to rdata length */
@@ -1976,26 +1980,30 @@ reply_noerror(struct sreply *sreply)
answer->rdlength = htons(&reply[outlen] - &answer->rdata);
- if (istcp) {
- char *tmpbuf;
- u_int16_t *plen;
+ if (sreply->sr != NULL) {
+ reply_raw2(so, reply, outlen, sreply->sr);
+ } else {
+ if (istcp) {
+ char *tmpbuf;
+ u_int16_t *plen;
- tmpbuf = malloc(outlen + 2);
- if (tmpbuf == NULL) {
- syslog(LOG_INFO, "malloc: %m");
- }
- plen = (u_int16_t *)tmpbuf;
- *plen = htons(outlen);
+ tmpbuf = malloc(outlen + 2);
+ if (tmpbuf == NULL) {
+ syslog(LOG_INFO, "malloc: %m");
+ }
+ plen = (u_int16_t *)tmpbuf;
+ *plen = htons(outlen);
- memcpy(&tmpbuf[2], reply, outlen);
+ memcpy(&tmpbuf[2], reply, outlen);
- if (send(so, tmpbuf, outlen + 2, 0) < 0) {
- syslog(LOG_INFO, "send: %m");
- }
- free(tmpbuf);
- } else {
- if (sendto(so, reply, outlen, 0, sa, salen) < 0) {
- syslog(LOG_INFO, "sendto: %m");
+ if (send(so, tmpbuf, outlen + 2, 0) < 0) {
+ syslog(LOG_INFO, "send: %m");
+ }
+ free(tmpbuf);
+ } else {
+ if (sendto(so, reply, outlen, 0, sa, salen) < 0) {
+ syslog(LOG_INFO, "sendto: %m");
+ }
}
}
repomaster@centroid.eu