summaryrefslogtreecommitdiffstats
path: root/contrib/bind/named/ns_resp.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/bind/named/ns_resp.c')
-rw-r--r--contrib/bind/named/ns_resp.c1293
1 files changed, 763 insertions, 530 deletions
diff --git a/contrib/bind/named/ns_resp.c b/contrib/bind/named/ns_resp.c
index f64306e..71b60f9 100644
--- a/contrib/bind/named/ns_resp.c
+++ b/contrib/bind/named/ns_resp.c
@@ -1,6 +1,6 @@
#if !defined(lint) && !defined(SABER)
static char sccsid[] = "@(#)ns_resp.c 4.65 (Berkeley) 3/3/91";
-static char rcsid[] = "$Id: ns_resp.c,v 8.27 1996/08/05 08:31:30 vixie Exp $";
+static char rcsid[] = "$Id: ns_resp.c,v 8.37 1996/12/02 09:17:21 vixie Exp $";
#endif /* not lint */
/*
@@ -55,6 +55,28 @@ static char rcsid[] = "$Id: ns_resp.c,v 8.27 1996/08/05 08:31:30 vixie Exp $";
* ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
* SOFTWARE.
* -
+ * Portions Copyright (c) 1995 by International Business Machines, Inc.
+ *
+ * International Business Machines, Inc. (hereinafter called IBM) grants
+ * permission under its copyrights to use, copy, modify, and distribute this
+ * Software with or without fee, provided that the above copyright notice and
+ * all paragraphs of this notice appear in all copies, and that the name of IBM
+ * not be used in connection with the marketing of any product incorporating
+ * the Software or modifications thereof, without specific, written prior
+ * permission.
+ *
+ * To the extent it has a right to do so, IBM grants an immunity from suit
+ * under its patents, if any, for the use, sale or manufacture of products to
+ * the extent that such products are used for performing Domain Name System
+ * dynamic updates in TCP/IP networks by means of the Software. No immunity is
+ * granted for any product per se or for any other function of any product.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", AND IBM DISCLAIMS ALL WARRANTIES,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE. IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL,
+ * DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE, EVEN
+ * IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH DAMAGES.
* --Copyright--
*/
@@ -72,9 +94,6 @@ static char rcsid[] = "$Id: ns_resp.c,v 8.27 1996/08/05 08:31:30 vixie Exp $";
#include "named.h"
-static void check_root __P((void)),
- check_ns __P((void));
-
static u_int8_t norootlogged[MAXCLASS]; /* XXX- should be a bitmap */
static const char skipnameFailedAnswer[] = "skipname failed in answer",
@@ -92,8 +111,34 @@ static const char skipnameFailedAnswer[] = "skipname failed in answer",
dlenUnderrunAnswer[] = "dlen underrun in answer",
outofDataFinal[] = "out of data in final pass",
outofDataAFinal[] = "out of data after final pass",
- badNameFound[] = "found an invalid domain name";
+ badNameFound[] = "found an invalid domain name",
+ wrongQuestion[] = "answer to wrong question",
+ danglingCname[] = "dangling CNAME pointer";
+
+struct db_list {
+ struct db_list *db_next;
+ struct databuf *db_dp;
+};
+
+struct flush_set {
+ char * fs_name;
+ int fs_type;
+ int fs_class;
+ u_int fs_cred;
+ struct db_list *fs_list;
+};
+
+static void rrsetadd __P((struct flush_set *, char *,
+ struct databuf *)),
+ rrsetupdate __P((struct flush_set *, int flags)),
+ flushrrset __P((struct flush_set *));
+static int rrsetcmp __P((char *, struct db_list *)),
+ check_root __P((void)),
+ check_ns __P((void)),
+ rrextract __P((u_char *, int, u_char *,
+ struct databuf **, char *, int));
+#ifdef LAME_LOGGING
static char *
learntFrom(qp, server)
struct qinfo *qp;
@@ -102,8 +147,10 @@ learntFrom(qp, server)
static char *buf = NULL;
char *a, *ns, *na;
struct databuf *db;
+#ifdef STATS
char nsbuf[20];
char abuf[20];
+#endif
int i;
if (buf) {
@@ -167,6 +214,7 @@ learntFrom(qp, server)
sprintf(buf, LEARNTFROM, na, a, ns);
return (buf);
}
+#endif /*LAME_LOGGING*/
void
ns_resp(msg, msglen)
@@ -179,24 +227,20 @@ ns_resp(msg, msglen)
register struct databuf *ns, *ns2;
register u_char *cp;
u_char *eom = msg + msglen;
- register u_char *tempcp;
-#ifdef VALIDATE
- struct sockaddr_in *server = &from_addr;
- struct { char *name; int type, class; u_int cred; } defer_rm[99];
- int defer_rm_count;
-#endif
+ struct flush_set *flushset;
struct sockaddr_in *nsa;
struct databuf *nsp[NSMAX];
int i, c, n, qdcount, ancount, aucount, nscount, arcount;
int qtype, qclass, dbflags;
int restart; /* flag for processing cname response */
int validanswer;
- int cname;
+ int cname, lastwascname;
int count, founddata, foundname;
int buflen;
int newmsglen;
- char name[MAXDNAME], qname[MAXDNAME], msgbuf[MAXDNAME*2];
- char *dname;
+ char name[MAXDNAME], qname[MAXDNAME], aname[MAXDNAME];
+ char msgbuf[MAXDNAME];
+ char *dname, tmpdomain[MAXDNAME];
const char *fname;
const char *formerrmsg = "brain damage";
u_char newmsg[PACKETSZ];
@@ -208,9 +252,7 @@ ns_resp(msg, msglen)
struct fwdinfo *fwd;
nameserIncr(from_addr.sin_addr, nssRcvdR);
-#ifdef DATUMREFCNT
nsp[0] = NULL;
-#endif
hp = (HEADER *) msg;
if ((qp = qfindid(hp->id)) == NULL ) {
dprintf(1, (ddt, "DUP? dropped (id %d)\n", ntohs(hp->id)));
@@ -248,7 +290,8 @@ ns_resp(msg, msglen)
GETSHORT(qtype, cp);
GETSHORT(qclass, cp);
if (!ns_nameok(qname, qclass, response_trans,
- ns_ownercontext(qtype, response_trans))) {
+ ns_ownercontext(qtype, response_trans),
+ qname, from_addr.sin_addr)) {
formerrmsg = badNameFound;
goto formerr;
}
@@ -265,11 +308,16 @@ ns_resp(msg, msglen)
formerrmsg = msgbuf;
goto formerr;
}
+ if (strcasecmp(qp->q_name, qname) != 0 ||
+ qp->q_class != qclass ||
+ qp->q_type != qtype) {
+ formerrmsg = wrongQuestion;
+ goto formerr;
+ }
} else {
- /* Pedantic. */
- qname[0] = '\0';
- qtype = 0;
- qclass = 0;
+ strcpy(qname, qp->q_name);
+ qclass = qp->q_class;
+ qtype = qp->q_type;
}
/* cp now points after the query section. */
@@ -325,25 +373,6 @@ ns_resp(msg, msglen)
goto formerr;
}
-#ifdef ALLOW_UPDATES
- if ( (hp->rcode == NOERROR) &&
- (hp->opcode == UPDATEA || hp->opcode == UPDATED ||
- hp->opcode == UPDATEDA || hp->opcode == UPDATEM ||
- hp->opcode == UPDATEMA) ) {
- /*
- * Update the secondary's copy, now that the primary
- * successfully completed the update. Zone doesn't matter
- * for dyn. update -- doupdate calls findzone to find it
- */
- /* XXX - DB_C_AUTH may be wrong */
- (void) doupdate(qp->q_msg, qp->q_msglen, qp->q_msg + HFIXEDSZ,
- 0, (struct databuf *)0, 0, DB_C_AUTH);
- dprintf(3, (ddt, "resp: leaving, UPDATE*\n"));
- /* return code filled in by doupdate */
- goto return_msg;
- }
-#endif /* ALLOW_UPDATES */
-
/*
* Determine if the response came from a forwarder. Packets from
* anyplace not listed as a forwarder or as a server to whom we
@@ -434,19 +463,20 @@ ns_resp(msg, msglen)
* Don't update nstime if this doesn't look
* like an address databuf now. XXX
*/
- if (ns && (ns->d_type==T_A) && (ns->d_class==qs->ns->d_class)){
+ if (ns &&
+ ns->d_type == T_A &&
+ ns->d_class == qs->ns->d_class) {
+ u_long t;
+
if (ns->d_nstime == 0)
- ns->d_nstime = (u_int32_t)rtrip;
+ t = rtrip;
else
- ns->d_nstime = (u_int32_t)
- (ns->d_nstime * ALPHA
- +
- (1-ALPHA) * (u_int32_t)rtrip);
- /* prevent floating point overflow,
- * limit to 1000 sec
- */
- if (ns->d_nstime > 1000000)
- ns->d_nstime = 1000000;
+ t = ns->d_nstime * ALPHA
+ +
+ (1 - ALPHA) * rtrip;
+ if (t > 65535)
+ t = 65535;
+ ns->d_nstime = (u_int16_t)t;
}
/*
@@ -473,6 +503,8 @@ ns_resp(msg, msglen)
for (n = 0, qs = qp->q_addr;
(u_int)n < qp->q_naddr;
n++, qs++) {
+ u_long t;
+
ns2 = qs->nsdata;
if ((!ns2) || (ns2 == ns))
continue;
@@ -481,15 +513,16 @@ ns_resp(msg, msglen)
continue;
if (qs->stime.tv_sec) {
if (ns2->d_nstime == 0)
- ns2->d_nstime = (u_int32_t)(rtrip * BETA);
+ t = (rtrip * BETA);
else
- ns2->d_nstime = (u_int32_t)(
- ns2->d_nstime * BETA + (1-ALPHA) * rtrip
- );
- if (ns2->d_nstime > 1000000)
- ns2->d_nstime = 1000000;
+ t = ns2->d_nstime * BETA
+ +
+ (1 - ALPHA) * rtrip;
} else
- ns2->d_nstime = (u_int32_t)(ns2->d_nstime * GAMMA);
+ t = ns2->d_nstime * GAMMA;
+ if (t > 65535)
+ t = 65535;
+ ns2->d_nstime = (u_int16_t)t;
dprintf(2, (ddt, "NS #%d %s rtt now %d\n", n,
sin_ntoa(&qs->ns_addr),
ns2->d_nstime));
@@ -509,10 +542,9 @@ ns_resp(msg, msglen)
#ifdef LAME_DELEGATION
/*
- * Non-authoritative, no answer, no error
+ * Non-authoritative, no answer, no error, with referral.
*/
- if (qdcount == 1 && hp->rcode == NOERROR && !hp->aa && ancount == 0
- && aucount > 0
+ if (hp->rcode == NOERROR && !hp->aa && ancount == 0 && aucount > 0
#ifdef BIND_NOTIFY
&& hp->opcode != NS_NOTIFY_OP
#endif
@@ -545,7 +577,8 @@ ns_resp(msg, msglen)
goto formerr;
}
if (!ns_nameok(name, class, response_trans,
- ns_ownercontext(type, response_trans))) {
+ ns_ownercontext(type, response_trans),
+ name, from_addr.sin_addr)) {
formerrmsg = badNameFound;
goto formerr;
}
@@ -613,7 +646,8 @@ ns_resp(msg, msglen)
goto formerr;
}
if (!ns_nameok(name, class, response_trans,
- ns_ownercontext(type, response_trans))){
+ ns_ownercontext(type, response_trans),
+ name, from_addr.sin_addr)) {
formerrmsg = badNameFound;
goto formerr;
}
@@ -717,168 +751,90 @@ ns_resp(msg, msglen)
validanswer = 0;
nscount = 0;
cname = 0;
-#ifdef VALIDATE
- defer_rm_count = 0;
-#endif
+ lastwascname = 0;
+ strcpy(aname, qname);
+
+ if (count) {
+ /* allocate 1 extra record for end of set detection */
+ flushset = (struct flush_set *)
+ calloc(count+1, sizeof(struct flush_set));
+ if (!flushset)
+ panic(-1, "flushset: out of memory");
+ } else
+ flushset = NULL;
for (i = 0; i < count; i++) {
- struct databuf *ns3 = NULL;
- u_char cred;
- int VCode;
- u_int16_t type, class;
+ struct databuf *dp;
+ int type;
if (cp >= eom) {
formerrmsg = outofDataFinal;
goto formerr;
}
-
- /* Get the DNAME. */
- tempcp = cp;
- n = dn_expand(msg, eom, tempcp, name, sizeof name);
- if (n <= 0) {
+ n = rrextract(msg, msglen, cp, &dp, name, sizeof name);
+ if (n < 0) {
formerrmsg = outofDataFinal;
goto formerr;
}
- tempcp += n;
- GETSHORT(type, tempcp);
- GETSHORT(class, tempcp);
- if (!ns_nameok(name, class, response_trans,
- ns_ownercontext(type, response_trans))) {
- formerrmsg = badNameFound;
- goto formerr;
- }
-
- /*
- * See if there are any NS RRs in the authority section
- * for the negative caching logic below. We'll count
- * these before validation.
- */
- if (type == T_NS && i >= ancount && i < ancount + aucount)
- nscount++;
+ cp += n;
+ if (!dp)
+ continue;
+ type = dp->d_type;
+ if (i < ancount) {
+ /* Answer section. */
+ if (strcasecmp(name, aname) != 0) {
+ syslog(LOG_DEBUG, "wrong ans. name (%s != %s)",
+ name, aname);
+ db_free(dp);
+ continue;
+ }
+ if (type == T_CNAME &&
+ qtype != T_CNAME && qtype != T_ANY) {
+ strcpy(aname, (char *)dp->d_data);
+ cname = 1;
+ lastwascname = 1;
+ } else {
+ validanswer = 1;
+ lastwascname = 0;
+ }
- /* Decide what credibility this ought to have in the cache. */
- if (i < ancount)
- cred = (hp->aa && !strcasecmp(name, qname))
+ dp->d_cred = (hp->aa && !strcasecmp(name, qname))
? DB_C_AUTH
: DB_C_ANSWER;
- else
- cred = (qp->q_flags & Q_PRIMING)
- ? DB_C_ANSWER
- : DB_C_ADDITIONAL;
-#ifdef VALIDATE
- if ((n = dovalidate(msg, msglen, cp, 0,
- dbflags, qp->q_domain, server,
- &VCode)) < 0) {
- formerrmsg = outofDataFinal;
- goto formerr;
- }
- if (VCode == INVALID && !(qp->q_flags & Q_SYSTEM)) {
- /*
- * If anything in the answer section fails
- * validation this means that it definitely did
- * not reside below the domain owning the NS RRs
- * that we sent the query to. This means either
- * that it was the target of a CNAME early in the
- * response, in which case we will treat this the
- * same as if the answer was incomplete and restart
- * the query on the CNAME target, or that someone
- * was trying to spoof us.
- */
- if (i < ancount)
- restart = 1;
- /*
- * Restart or no, if we're here it means we are not
- * going to cache this RR. That being the case, we
- * must burn down whatever partial RRset we've got
- * in the cache now, lest we inadvertently answer
- * with a truncated RRset in some future section.
- */
- for (c = 0; c < defer_rm_count; c++)
- if (!strcasecmp(defer_rm[c].name, name) &&
- defer_rm[c].class == class &&
- defer_rm[c].type == type)
- break;
- if (c < defer_rm_count) {
- if (defer_rm[c].cred < cred)
- defer_rm[c].cred = cred;
- } else {
- if (defer_rm_count+1 >=
- (sizeof defer_rm / sizeof defer_rm[0])) {
- formerrmsg = "too many RRs in ns_resp";
- goto formerr;
- }
- defer_rm[defer_rm_count].name = savestr(name);
- defer_rm[defer_rm_count].type = type;
- defer_rm[defer_rm_count].class = class;
- defer_rm[defer_rm_count].cred = cred;
- defer_rm_count++;
- }
} else {
-#endif
- if (i < ancount) {
- /*
- * If there are any non-CNAME RRs (or
- * CNAME RRs if they are an acceptable)
- * then the query is complete unless an
- * intermediate CNAME didn't pass validation,
- * but that's OK.
- */
- if (type != T_CNAME || qtype == T_CNAME ||
- qtype == T_ANY)
- validanswer = 1;
- else
- cname = 1;
- }
- n = doupdate(msg, msglen, cp, 0, &ns3, dbflags, cred);
-#ifdef VALIDATE
- }
-#endif
- if (n < 0) {
- dprintf(1, (ddt, "resp: leaving, doupdate failed\n"));
- formerrmsg = outofDataFinal;
- goto formerr;
- }
- cp += n;
- }
-#ifdef VALIDATE
- if (defer_rm_count > 0) {
- for (i = 0; i < defer_rm_count; i++) {
- register struct databuf *db = NULL;
-
- fname = "";
- htp = hashtab; /* lookup relative to root */
- np = nlookup(defer_rm[i].name, &htp, &fname, 0);
- if (np && fname == defer_rm[i].name &&
- defer_rm[i].class != C_ANY &&
- defer_rm[i].type != T_ANY) {
- /*
- * If doupdate() wouldn't have cached this
- * RR anyway, there's no need to delete it.
- */
- for (db = np->n_data;
- db != NULL;
- db = db->d_next) {
- if (!db->d_zone &&
- match(db, defer_rm[i].class,
- defer_rm[i].type) &&
- db->d_cred >= defer_rm[i].cred) {
- break;
- }
+ /* After answer section. */
+ if (lastwascname) {
+ db_free(dp);
+ break;
+ }
+ if (i < ancount + aucount && type == T_NS) {
+ /* Authority section. */
+ if (!samedomain(aname, name) ||
+ (!cname && !samedomain(name, qp->q_domain))
+ ) {
+ syslog(LOG_DEBUG,
+ "bad referral (%s !< %s)",
+ name, qp->q_domain);
+ db_free(dp);
+ continue;
}
- if (db == NULL)
- delete_all(np, defer_rm[i].class,
- defer_rm[i].type);
- /* XXX: should delete name node if empty? */
+ nscount++;
}
- syslog(LOG_DEBUG, "defer_rm [%s %s %s] (np%#x, db%#x)",
- defer_rm[i].name,
- p_class(defer_rm[i].class),
- p_type(defer_rm[i].type),
- np, db);
- free(defer_rm[i].name);
+ dp->d_cred = (qp->q_flags & Q_PRIMING)
+ ? DB_C_ANSWER
+ : DB_C_ADDITIONAL;
}
+ rrsetadd(flushset, name, dp);
}
-#endif
+ if (flushset) {
+ rrsetupdate(flushset, dbflags);
+ for (i = 0; i < count; i++)
+ if (flushset[i].fs_name)
+ free(flushset[i].fs_name);
+ free((char*)flushset);
+ }
+ if (lastwascname)
+ syslog(LOG_DEBUG, "%s (%s)", danglingCname, aname);
if (cp > eom) {
formerrmsg = outofDataAFinal;
@@ -886,8 +842,22 @@ ns_resp(msg, msglen)
}
if ((qp->q_flags & Q_SYSTEM) && ancount) {
- if (qp->q_flags & Q_PRIMING)
- check_root();
+ if ((qp->q_flags & Q_PRIMING) && !check_root()) {
+ /* mark server as bad */
+ if (!qp->q_fwd)
+ for (i = 0; i < (int)qp->q_naddr; i++)
+ if (qp->q_addr[i].ns_addr.sin_addr.s_addr
+ == from_addr.sin_addr.s_addr)
+ qp->q_addr[i].nretry = MAXRETRY;
+ /* XXX - doesn't handle responses sent from
+ * the wronginterface on a multihomed server
+ */
+ if (qp->q_fwd ||
+ qp->q_addr[qp->q_curaddr].ns_addr.sin_addr.s_addr
+ == from_addr.sin_addr.s_addr)
+ retry(qp);
+ return;
+ }
dprintf(3, (ddt, "resp: leaving, SYSQUERY ancount %d\n",
ancount));
#ifdef BIND_NOTIFY
@@ -949,12 +919,6 @@ ns_resp(msg, msglen)
(hp->aa || fwd || qclass == C_ANY)) {
/* we have an authoritative NO */
dprintf(3, (ddt, "resp: leaving auth NO\n"));
- if (qp->q_cmsglen) {
- /* XXX - what about additional CNAMEs in the chain? */
- msg = qp->q_cmsg;
- msglen = qp->q_cmsglen;
- hp = (HEADER *)msg;
- }
#ifdef NCACHE
/* answer was NO */
if (hp->aa &&
@@ -962,6 +926,12 @@ ns_resp(msg, msglen)
cache_n_resp(msg, msglen);
}
#endif /*NCACHE*/
+ if (qp->q_cmsglen) {
+ /* XXX - what about additional CNAMEs in the chain? */
+ msg = qp->q_cmsg;
+ msglen = qp->q_cmsglen;
+ hp = (HEADER *)msg;
+ }
goto return_msg;
}
@@ -995,6 +965,7 @@ ns_resp(msg, msglen)
hp->ancount = htons(0);
hp->nscount = htons(0);
hp->arcount = htons(0);
+ hp->rcode = NOERROR;
dnptrs[0] = newmsg;
dnptrs[1] = NULL;
cp = newmsg + HFIXEDSZ;
@@ -1037,6 +1008,20 @@ ns_resp(msg, msglen)
n = finddata(np, qclass, qtype, hp, &dname, &buflen, &count);
if (n == 0)
goto fetch_ns; /* NO data available */
+#ifdef NCACHE
+ if (hp->rcode) {
+ if (hp->rcode == NOERROR_NODATA)
+ hp->rcode = NOERROR;
+#ifdef RETURNSOA
+ if (count) {
+ cp += n;
+ buflen -= n;
+ hp->nscount = htons((u_int16_t)count);
+ }
+#endif
+ goto return_newmsg;
+ }
+#endif
cp += n;
buflen -= n;
hp->ancount = htons(ntohs(hp->ancount) + (u_int16_t)count);
@@ -1060,9 +1045,7 @@ ns_resp(msg, msglen)
* section or record the address for forwarding the query
* (recursion desired).
*/
-#ifdef DATUMREFCNT
free_nsp(nsp);
-#endif
switch (findns(&np, qclass, nsp, &count, 0)) {
case NXDOMAIN: /* shouldn't happen */
dprintf(3, (ddt, "req: leaving (%s, rcode %d)\n",
@@ -1071,11 +1054,7 @@ ns_resp(msg, msglen)
hp->rcode = NXDOMAIN;
if (qclass != C_ANY) {
hp->aa = 1;
- /* XXX: should return SOA if founddata == 0,
- * but old named's are confused by an SOA
- * in the auth. section if there's no error.
- */
- if (foundname == 0 && np) {
+ if (np && (!foundname || !founddata)) {
n = doaddauth(hp, cp, buflen, np, nsp[0]);
cp += n;
buflen -= n;
@@ -1114,45 +1093,15 @@ ns_resp(msg, msglen)
}
/* Reset the query control structure */
-#ifdef DATUMREFCNT
- /* XXX - this code should be shared with qfree()'s similar logic. */
- for (i = 0; (u_int)i < qp->q_naddr; i++) {
- static const char freed[] = "freed", busy[] = "busy";
- const char *result;
-
- if (qp->q_addr[i].ns != NULL) {
- if ((--(qp->q_addr[i].ns->d_rcnt)))
- result = busy;
- else
- result = freed;
- dprintf(1, (ddt, "ns_resp: ns %s rcnt %d (%s)\n",
- qp->q_addr[i].ns->d_data,
- qp->q_addr[i].ns->d_rcnt,
- result));
- if (result == freed)
- free((char*)qp->q_addr[i].ns);
- }
- if (qp->q_addr[i].nsdata != NULL) {
- if ((--(qp->q_addr[i].nsdata->d_rcnt)))
- result = busy;
- else
- result = freed;
- dprintf(1, (ddt,
- "ns_resp: nsdata %08.8X rcnt %d (%s)\n",
- *(int32_t *)(qp->q_addr[i].nsdata->d_data),
- qp->q_addr[i].nsdata->d_rcnt,
- result));
- if (result == freed)
- free((char*)qp->q_addr[i].nsdata);
- }
- }
-#endif
+
+ nsfree(qp, "ns_resp");
qp->q_naddr = 0;
qp->q_curaddr = 0;
qp->q_fwd = fwdtab;
-#if defined(LAME_DELEGATION) || defined(VALIDATE)
- getname(np, qp->q_domain, sizeof(qp->q_domain));
-#endif /* LAME_DELEGATION */
+
+ getname(np, tmpdomain, sizeof tmpdomain);
+ qp->q_domain = strdup(tmpdomain);
+
if ((n = nslookup(nsp, qp, dname, "ns_resp")) <= 0) {
if (n < 0) {
dprintf(3, (ddt, "resp: nslookup reports danger\n"));
@@ -1243,9 +1192,7 @@ ns_resp(msg, msglen)
#endif
nameserIncr(qp->q_from.sin_addr, nssRcvdFwdR);
dprintf(3, (ddt, "resp: Query sent.\n"));
-#ifdef DATUMREFCNT
free_nsp(nsp);
-#endif
return;
formerr:
@@ -1256,9 +1203,7 @@ ns_resp(msg, msglen)
#ifdef XSTATS
nameserIncr(from_addr.sin_addr, nssSentFErr);
#endif
-#ifdef DATUMREFCNT
free_nsp(nsp);
-#endif
return;
return_msg:
@@ -1273,9 +1218,7 @@ ns_resp(msg, msglen)
hp->ra = (NoRecurse == 0);
(void) send_msg(msg, msglen, qp);
qremove(qp);
-#ifdef DATUMREFCNT
free_nsp(nsp);
-#endif
return;
return_newmsg:
@@ -1296,9 +1239,7 @@ ns_resp(msg, msglen)
hp->ra = (NoRecurse == 0);
(void) send_msg(newmsg, cp - newmsg, qp);
qremove(qp);
-#ifdef DATUMREFCNT
free_nsp(nsp);
-#endif
return;
servfail:
@@ -1315,42 +1256,31 @@ ns_resp(msg, msglen)
qp);
timeout:
qremove(qp);
-#ifdef DATUMREFCNT
free_nsp(nsp);
-#endif
return;
}
-/*
- * Decode the resource record 'rrp' and update the database.
- * If savens is non-nil, record pointer for forwarding queries a second time.
- */
-int
-doupdate(msg, msglen, rrp, zone, savens, flags, cred)
- u_char *msg, *rrp;
- struct databuf **savens;
- int msglen, zone, flags;
- u_int cred;
+static int
+rrextract(msg, msglen, rrp, dpp, dname, namelen)
+ u_char *msg;
+ int msglen;
+ u_char *rrp;
+ struct databuf **dpp;
+ char *dname;
+ int namelen;
{
register u_char *cp;
register int n;
int class, type, dlen, n1;
u_int32_t ttl;
- struct databuf *dp;
- char dname[MAXDNAME];
u_char *cp1;
u_char data[BUFSIZ];
register HEADER *hp = (HEADER *)msg;
enum context context;
-#ifdef ALLOW_UPDATES
- int zonenum;
-#endif
-
- dprintf(3, (ddt, "doupdate(zone %d, savens %#lx, flags %#lx)\n",
- zone, (u_long)savens, (u_long)flags));
+ *dpp = NULL;
cp = rrp;
- if ((n = dn_expand(msg, msg + msglen, cp, dname, sizeof dname)) < 0) {
+ if ((n = dn_expand(msg, msg + msglen, cp, dname, namelen)) < 0) {
hp->rcode = FORMERR;
return (-1);
}
@@ -1360,15 +1290,29 @@ doupdate(msg, msglen, rrp, zone, savens, flags, cred)
GETLONG(ttl, cp);
GETSHORT(dlen, cp);
if (!ns_nameok(dname, class, response_trans,
- ns_ownercontext(type, response_trans))) {
+ ns_ownercontext(type, response_trans),
+ dname, from_addr.sin_addr)) {
hp->rcode = FORMERR;
return (-1);
}
- dprintf(3, (ddt, "doupdate: dname %s type %d class %d ttl %d\n",
+ dprintf(3, (ddt, "rrextract: dname %s type %d class %d ttl %d\n",
dname, type, class, ttl));
/*
* Convert the resource record data into the internal
* database format.
+ *
+ * On entry to the switch:
+ * CP points to the RDATA section of the wire-format RR.
+ * DLEN is its length.
+ * The memory area at DATA is available for processing.
+ *
+ * On exit from the switch:
+ * CP has been incremented past the RR.
+ * CP1 points to the RDATA section of the database-format RR.
+ * N contains the length of the RDATA section of the dbase-format RR.
+ *
+ * The new data at CP1 for length N will be copied into the database,
+ * so it need not be in any particular storage location.
*/
switch (type) {
case T_A:
@@ -1388,6 +1332,7 @@ doupdate(msg, msglen, rrp, zone, savens, flags, cred)
case T_NSAP:
case T_AAAA:
case T_LOC:
+ case T_KEY:
#ifdef ALLOW_T_UNSPEC
case T_UNSPEC:
#endif
@@ -1409,9 +1354,8 @@ doupdate(msg, msglen, rrp, zone, savens, flags, cred)
return (-1);
}
if (!ns_nameok((char *)data, class, response_trans,
- (type == T_PTR)
- ? ns_ptrcontext(dname)
- : domain_ctx)) {
+ type == T_PTR ?ns_ptrcontext(dname) :domain_ctx,
+ dname, from_addr.sin_addr)) {
hp->rcode = FORMERR;
return (-1);
}
@@ -1434,7 +1378,8 @@ doupdate(msg, msglen, rrp, zone, savens, flags, cred)
hp->rcode = FORMERR;
return (-1);
}
- if (!ns_nameok((char *)data, class, response_trans, context)) {
+ if (!ns_nameok((char *)data, class, response_trans, context,
+ dname, from_addr.sin_addr)) {
hp->rcode = FORMERR;
return (-1);
}
@@ -1452,7 +1397,8 @@ doupdate(msg, msglen, rrp, zone, savens, flags, cred)
context = domain_ctx;
else
context = mailname_ctx;
- if (!ns_nameok((char *)cp1, class, response_trans, context)) {
+ if (!ns_nameok((char *)cp1, class, response_trans, context,
+ dname, from_addr.sin_addr)) {
hp->rcode = FORMERR;
return (-1);
}
@@ -1467,23 +1413,76 @@ doupdate(msg, msglen, rrp, zone, savens, flags, cred)
cp1 = data;
break;
+ case T_NAPTR:
+ /* Grab weight and port. */
+ bcopy(cp, data, INT16SZ*2);
+ cp1 = data + INT16SZ*2;
+ cp += INT16SZ*2;
+
+ /* Flags */
+ n = *cp++;
+ *cp1++ = n;
+ bcopy(cp, cp1, n);
+ cp += n; cp1 += n;
+
+ /* Service */
+ n = *cp++;
+ *cp1++ = n;
+ bcopy(cp, cp1, n);
+ cp += n; cp1 += n;
+
+ /* Regexp */
+ n = *cp++;
+ *cp1++ = n;
+ bcopy(cp, cp1, n);
+ cp += n; cp1 += n;
+
+ /* Replacement */
+ n = dn_expand(msg, msg + msglen, cp, (char *)cp1,
+ sizeof data - (cp1 - data));
+ if (n < 0) {
+ hp->rcode = FORMERR;
+ return (-1);
+ }
+ if (!ns_nameok((char *)cp1, class, response_trans,
+ hostname_ctx, dname, from_addr.sin_addr)) {
+ hp->rcode = FORMERR;
+ return (-1);
+ }
+ cp += n;
+
+ /* compute end of data */
+ cp1 += strlen((char *)cp1) + 1;
+ /* compute size of data */
+ n = cp1 - data;
+ cp1 = data;
+ break;
+
case T_MX:
case T_AFSDB:
case T_RT:
+ case T_SRV:
/* grab preference */
bcopy(cp, data, INT16SZ);
cp1 = data + INT16SZ;
cp += INT16SZ;
+ if (type == T_SRV) {
+ /* Grab weight and port. */
+ bcopy(cp, data, INT16SZ*2);
+ cp1 += INT16SZ*2;
+ cp += INT16SZ*2;
+ }
+
/* get name */
n = dn_expand(msg, msg + msglen, cp, (char *)cp1,
- sizeof data - INT16SZ);
+ sizeof data - (cp1 - data));
if (n < 0) {
hp->rcode = FORMERR;
return (-1);
}
if (!ns_nameok((char *)cp1, class, response_trans,
- hostname_ctx)) {
+ hostname_ctx, dname, from_addr.sin_addr)) {
hp->rcode = FORMERR;
return (-1);
}
@@ -1510,7 +1509,7 @@ doupdate(msg, msglen, rrp, zone, savens, flags, cred)
return (-1);
}
if (!ns_nameok((char *)cp1, class, response_trans,
- domain_ctx)) {
+ domain_ctx, dname, from_addr.sin_addr)) {
hp->rcode = FORMERR;
return (-1);
}
@@ -1523,7 +1522,7 @@ doupdate(msg, msglen, rrp, zone, savens, flags, cred)
return (-1);
}
if (!ns_nameok((char *)cp1, class, response_trans,
- domain_ctx)) {
+ domain_ctx, dname, from_addr.sin_addr)) {
hp->rcode = FORMERR;
return (-1);
}
@@ -1533,6 +1532,84 @@ doupdate(msg, msglen, rrp, zone, savens, flags, cred)
cp1 = data;
break;
+ case T_SIG: {
+ u_long origTTL, exptime, signtime, timetilexp, now;
+
+ /* Check signature time, expiration, and adjust TTL. */
+ /* This code is similar to that in db_load.c. */
+
+ /* Skip coveredType, alg, labels */
+ cp1 = cp + INT16SZ + 1 + 1;
+ GETLONG(origTTL, cp1);
+ GETLONG(exptime, cp1);
+ GETLONG(signtime, cp1);
+ now = time(NULL); /* Get current time in GMT/UTC */
+
+ /* Don't let bogus name servers increase the signed TTL */
+ if (ttl > origTTL) {
+ dprintf(3, (ddt,
+ "shrinking SIG TTL from %d to origTTL %d\n",
+ ttl, origTTL));
+ ttl = origTTL;
+ }
+
+ /* Don't let bogus signers "sign" in the future. */
+ if (signtime > now) {
+ dprintf(3, (ddt,
+ "ignoring SIG: signature date %s is in the future\n",
+ p_secstodate (signtime)));
+ return ((cp - rrp) + dlen);
+ }
+
+ /* Ignore received SIG RR's that are already expired. */
+ if (exptime <= now) {
+ dprintf(3, (ddt,
+ "ignoring SIG: expiration %s is in the past\n",
+ p_secstodate (exptime)));
+ return ((cp - rrp) + dlen);
+ }
+
+ /* Lop off the TTL at the expiration time. */
+ timetilexp = exptime - now;
+ if (timetilexp < ttl) {
+ dprintf(3, (ddt,
+ "shrinking expiring %s SIG TTL from %d to %d\n",
+ p_secstodate (exptime), ttl, timetilexp));
+ ttl = timetilexp;
+ }
+
+ /* The following code is copied from named-xfer.c. */
+ cp1 = (u_char *)data;
+
+ /* first just copy over the type_covered, algorithm, */
+ /* labels, orig ttl, two timestamps, and the footprint */
+ bcopy(cp, cp1, 18);
+ cp += 18;
+ cp1 += 18;
+
+ /* then the signer's name */
+ n = dn_expand(msg, msg + msglen, cp,
+ (char *)cp1, (sizeof data) - 18);
+ if (n < 0)
+ return (-1);
+ cp += n;
+ cp1 += strlen((char*)cp1)+1;
+
+ /* finally, we copy over the variable-length signature.
+ Its size is the total data length, minus what we copied. */
+ n = dlen - (18 + n);
+ if (n > (sizeof data) - (cp1 - (u_char *)data))
+ return (-1); /* out of room! */
+ bcopy(cp, cp1, n);
+ cp += n;
+ cp1 += n;
+
+ /* compute size of data */
+ n = cp1 - (u_char *)data;
+ cp1 = (u_char *)data;
+ break;
+ }
+
default:
dprintf(3, (ddt, "unknown type %d\n", type));
return ((cp - rrp) + dlen);
@@ -1545,157 +1622,45 @@ doupdate(msg, msglen, rrp, zone, savens, flags, cred)
return (-1);
}
-#ifdef ALLOW_UPDATES
- /*
- * If this is a dynamic update request, process it specially; else,
- * execute normal update code.
- */
- switch(hp->opcode) {
+ ttl += tt.tv_sec;
- /* For UPDATEM and UPDATEMA, do UPDATED/UPDATEDA followed by UPDATEA */
- case UPDATEM:
- case UPDATEMA:
+ *dpp = savedata(class, type, ttl, cp1, n);
+ return (cp - rrp);
+}
- /*
- * The named code for UPDATED and UPDATEDA is the same except that for
- * UPDATEDA we we ignore any data that was passed: we just delete all
- * RRs whose name, type, and class matches
- */
- case UPDATED:
- case UPDATEDA:
- if (type == T_SOA) { /* Not allowed */
- dprintf(1, (ddt, "UDPATE: REFUSED - SOA delete\n"));
- hp->rcode = REFUSED;
- return (-1);
- }
- /*
- * Don't check message length if doing UPDATEM/UPDATEMA,
- * since the whole message wont have been demarshalled until
- * we reach the code for UPDATEA
- */
- if ( (hp->opcode == UPDATED) || (hp->opcode == UPDATEDA) ) {
- if (cp != (u_char *)(msg + msglen)) {
- dprintf(1, (ddt,
- "FORMERR UPDATE message length off\n"
- ));
- hp->rcode = FORMERR;
- return (-1);
- }
- }
- if ((zonenum = findzone(dname, class)) == 0) {
- hp->rcode = NXDOMAIN;
- return (-1);
- }
- if (zones[zonenum].z_flags & Z_DYNADDONLY) {
- hp->rcode = NXDOMAIN;
- return (-1);
- }
- if ( (hp->opcode == UPDATED) || (hp->opcode == UPDATEM) ) {
- /* Make a dp for use in db_update, as old dp */
- dp = savedata(class, type, 0, cp1, n);
- dp->d_zone = zonenum;
- dp->d_cred = cred;
- dp->d_clev = db_getclev(zones[zonenum].z_origin);
- n = db_update(dname, dp, NULL, DB_MEXIST | DB_DELETE,
- hashtab);
- if (n != OK) {
- dprintf(1, (ddt,
- "UPDATE: db_update failed\n"));
- free((char*) dp);
- hp->rcode = NOCHANGE;
- return (-1);
- }
- } else { /* UPDATEDA or UPDATEMA */
- int DeletedOne = 0;
- /* Make a dp for use in db_update, as old dp */
- dp = savedata(class, type, 0, NULL, 0);
- dp->d_zone = zonenum;
- dp->d_cred = cred;
- dp->d_clev = db_getclev(zones[zonenum].z_origin);
- do { /* Loop and delete all matching RR(s) */
- n = db_update(dname, dp, NULL, DB_DELETE,
- hashtab);
- if (n != OK)
- break;
- DeletedOne++;
- } while (1);
- free((char*) dp);
- /* Ok for UPDATEMA not to have deleted any RRs */
- if (!DeletedOne && hp->opcode == UPDATEDA) {
- dprintf(1, (ddt,
- "UPDATE: db_update failed\n"));
- hp->rcode = NOCHANGE;
- return (-1);
- }
- }
- if ( (hp->opcode == UPDATED) || (hp->opcode == UPDATEDA) )
- return (cp - rrp);;
- /*
- * Else unmarshal the RR to be added and continue on to
- * UPDATEA code for UPDATEM/UPDATEMA
- */
- if ((n =
- dn_expand(msg, msg+msglen, cp, dname, sizeof(dname))) < 0) {
- dprintf(1, (ddt,
- "FORMERR UPDATE expand name failed\n"));
- hp->rcode = FORMERR;
- return (-1);
- }
- cp += n;
- GETSHORT(type, cp);
- GETSHORT(class, cp);
- GETLONG(ttl, cp);
- GETSHORT(n, cp);
- cp1 = cp;
-/**** XXX - need bounds checking here ****/
- cp += n;
+/*
+ * Decode the resource record 'rrp' and update the database.
+ * If savens is non-nil, record pointer for forwarding queries a second time.
+ */
+int
+doupdate(msg, msglen, rrp, zone, savens, flags, cred)
+ u_char *msg;
+ int msglen;
+ u_char *rrp;
+ int zone;
+ struct databuf **savens;
+ int flags;
+ u_int cred;
+{
+ register u_char *cp;
+ register int n;
+ int class, type;
+ struct databuf *dp;
+ char dname[MAXDNAME];
+ u_char data[BUFSIZ+MAX_MD5RSA_KEY_BYTES];
- case UPDATEA:
- if (n > MAXDATA) {
- dprintf(1, (ddt, "UPDATE: too much data\n"));
- hp->rcode = NOCHANGE;
- return (-1);
- }
- if (cp != (u_char *)(msg + msglen)) {
- dprintf(1, (ddt,
- "FORMERR UPDATE message length off\n"));
- hp->rcode = FORMERR;
- return (-1);
- }
- if ((zonenum = findzone(dname, class)) == 0) {
- hp->rcode = NXDOMAIN;
- return (-1);
- }
- if (zones[zonenum].z_flags & Z_DYNADDONLY) {
- struct hashbuf *htp = hashtab;
- char *fname;
- if (nlookup(dname, &htp, &fname, 0) &&
- !strcasecmp(dname, fname)) {
- dprintf(1, (ddt,
- "refusing add of existing name\n"
- ));
- hp->rcode = REFUSED;
- return (-1);
- }
- }
- dp = savedata(class, type, ttl, cp1, n);
- dp->d_zone = zonenum;
- dp->d_cred = cred;
- dp->d_clev = db_getclev(zones[zonenum].z_origin);
- if ((n = db_update(dname, NULL, dp, DB_NODATA,
- hashtab)) != OK) {
- dprintf(1, (ddt, "UPDATE: db_update failed\n"));
- hp->rcode = NOCHANGE;
- free((char*) dp);
- return (-1);
- }
- else
- return (cp - rrp);
- }
-#endif /* ALLOW_UPDATES */
+ dprintf(3, (ddt, "doupdate(zone %d, savens %#lx, flags %#lx)\n",
+ zone, (u_long)savens, (u_long)flags));
+
+ if ((n = rrextract(msg, msglen, rrp, &dp, dname, sizeof(dname))) == -1)
+ return (-1);
+ if (!dp)
+ return (-1);
+
+ type = dp->d_type;
+ class = dp->d_class;
+ cp = rrp + n;
- if (zone == 0)
- ttl += tt.tv_sec;
#if defined(TRACEROOT) || defined(BOGUSNS)
if ((type == T_NS) && (savens != NULL)) {
char *temp, qname[MAXDNAME];
@@ -1724,6 +1689,7 @@ doupdate(msg, msglen, rrp, zone, savens, flags, cred)
syslog(LOG_NOTICE,
"bogus root NS %s rcvd from %s on query for \"%s\"",
data, sin_ntoa(&from_addr), qname);
+ db_free(dp);
return (cp - rrp);
}
#ifdef BOGUSNS
@@ -1733,13 +1699,13 @@ doupdate(msg, msglen, rrp, zone, savens, flags, cred)
syslog(LOG_INFO,
"bogus nonroot NS %s rcvd from %s on query for \"%s\"",
data, sin_ntoa(&from_addr), qname);
+ db_free(dp);
return (cp - rrp);
}
#endif
}
#endif /*TRACEROOT || BOGUSNS*/
- dp = savedata(class, type, ttl, cp1, n);
dp->d_zone = zone;
dp->d_cred = cred;
dp->d_clev = 0; /* We trust what is on disk more, except root srvrs */
@@ -1750,7 +1716,7 @@ doupdate(msg, msglen, rrp, zone, savens, flags, cred)
else if (debug >= 3)
fprintf(ddt, "update failed (DATAEXISTS)\n");
#endif
- free((char *)dp);
+ db_free(dp);
} else if (type == T_NS && savens != NULL)
*savens = dp;
return (cp - rrp);
@@ -1984,7 +1950,7 @@ sysnotify(dname, class, type)
} /*next NS*/
done:
if (nns || na) {
- char tmp[MAXDNAME*2];
+ char tmp[MAXDNAME];
/* Many syslog()'s only take 5 args. */
sprintf(tmp, "%s %s %s", dname, p_class(class), p_type(type));
@@ -2003,6 +1969,7 @@ sysquery(dname, class, type, nss, nsc, opcode)
{
register struct qinfo *qp, *oqp;
register HEADER *hp;
+ char tmpdomain[MAXDNAME];
struct namebuf *np;
struct databuf *nsp[NSMAX];
struct hashbuf *htp;
@@ -2010,12 +1977,10 @@ sysquery(dname, class, type, nss, nsc, opcode)
const char *fname;
int n, count;
-#ifdef DATUMREFCNT
nsp[0] = NULL;
-#endif
dprintf(3, (ddt, "sysquery(%s, %d, %d, %#lx, %d)\n",
dname, class, type, (u_long)nss, nsc));
- qp = qnew();
+ qp = qnew(dname, class, type);
if (nss && nsc) {
np = NULL;
@@ -2035,12 +2000,10 @@ sysquery(dname, class, type, nss, nsc, opcode)
switch (n) {
case NXDOMAIN:
case SERVFAIL:
- syslog(LOG_DEBUG, "sysquery: findns error (%d) on %s?",
- n, dname);
+ syslog(LOG_DEBUG, "sysquery: findns error (%s) on %s?",
+ n == NXDOMAIN ? "NXDOMAIN" : "SERVFAIL", dname);
err2:
-#ifdef DATUMREFCNT
free_nsp(nsp);
-#endif
goto err1;
}
}
@@ -2054,9 +2017,11 @@ sysquery(dname, class, type, nss, nsc, opcode)
qp->q_fwd = fwdtab;
qp->q_expire = tt.tv_sec + RETRY_TIMEOUT*2;
qp->q_flags |= Q_SYSTEM;
-#if defined(LAME_DELEGATION) || defined(VALIDATE)
- getname(np, qp->q_domain, sizeof(qp->q_domain));
-#endif /* LAME_DELEGATION */
+
+ getname(np, tmpdomain, sizeof tmpdomain);
+ qp->q_domain = strdup(tmpdomain);
+ if (!qp->q_domain)
+ panic(ENOMEM, "ns_resp: strdup failed");
if ((qp->q_msg = (u_char *)malloc(BUFSIZ)) == NULL) {
syslog(LOG_NOTICE, "sysquery: malloc failed");
@@ -2129,10 +2094,8 @@ sysquery(dname, class, type, nss, nsc, opcode)
goto err2;
}
if (np) {
-#ifdef DATUMREFCNT
free_nsp(nsp);
nsp[0] = NULL;
-#endif
np = np_parent(np);
n = findns(&np, class, nsp, &count, 0);
switch (n) {
@@ -2172,9 +2135,7 @@ sysquery(dname, class, type, nss, nsc, opcode)
nameserIncr(nsa->sin_addr, nssSendtoErr);
}
nameserIncr(nsa->sin_addr, nssSentSysQ);
-#ifdef DATUMREFCNT
free_nsp(nsp);
-#endif
return (qp);
}
@@ -2182,7 +2143,7 @@ sysquery(dname, class, type, nss, nsc, opcode)
* Check the list of root servers after receiving a response
* to a query for the root servers.
*/
-static void
+static int
check_root()
{
register struct databuf *dp, *pdp;
@@ -2195,7 +2156,7 @@ check_root()
break;
if (np == NULL) {
syslog(LOG_NOTICE, "check_root: Can't find root!\n");
- return;
+ return (0);
}
for (dp = np->n_data; dp != NULL; dp = dp->d_next)
if (dp->d_type == T_NS)
@@ -2205,7 +2166,7 @@ check_root()
syslog(LOG_NOTICE,
"check_root: %d root servers after query to root server < min",
count);
- return;
+ return (0);
}
pdp = NULL;
dp = np->n_data;
@@ -2221,13 +2182,18 @@ check_root()
pdp = dp;
dp = dp->d_next;
}
- check_ns();
+ if (check_ns())
+ return (1);
+ else {
+ priming = 1;
+ return (0);
+ }
}
/*
* Check the root to make sure that for each NS record we have a A RR
*/
-static void
+static int
check_ns()
{
register struct databuf *dp, *tdp;
@@ -2237,6 +2203,7 @@ check_ns()
int found_arr;
const char *fname;
time_t curtime;
+ int servers = 0, rrsets = 0;
dprintf(2, (ddt, "check_ns()\n"));
@@ -2245,9 +2212,17 @@ check_ns()
if (NAME(*np)[0] != '\0')
continue;
for (dp = np->n_data; dp != NULL; dp = dp->d_next) {
+ int cnames = 0;
+
+#ifdef NCACHE
+ if (dp->d_rcode)
+ continue;
+#endif
if (dp->d_type != T_NS)
continue;
+ servers++;
+
/* look for A records */
dname = (caddr_t) dp->d_data;
htp = hashtab;
@@ -2262,7 +2237,16 @@ check_ns()
}
/* look for name server addresses */
found_arr = 0;
- for (tdp=tnp->n_data; tdp != NULL; tdp=tdp->d_next) {
+ delete_stale(tnp);
+ for (tdp = tnp->n_data;
+ tdp != NULL;
+ tdp = tdp->d_next) {
+#ifdef NCACHE
+ if (tdp->d_rcode)
+ continue;
+#endif
+ if (tdp->d_type == T_CNAME)
+ cnames++;
if (tdp->d_type != T_A ||
tdp->d_class != dp->d_class)
continue;
@@ -2271,22 +2255,28 @@ check_ns()
dprintf(3, (ddt,
"check_ns: stale entry '%s'\n",
NAME(*tnp)));
- /* Cache invalidate the address RR's */
- delete_all(tnp, dp->d_class, T_A);
found_arr = 0;
break;
}
found_arr++;
}
- if (!found_arr)
+ if (found_arr)
+ rrsets++;
+ else if (cnames > 0)
+ syslog(LOG_INFO, "Root NS %s -> CNAME %s",
+ NAME(*np), NAME(*tnp));
+ else
sysquery(dname, dp->d_class, T_A, NULL,
0, QUERY);
}
}
+
+ dprintf(2, (ddt, "check_ns: %d %d\n", servers, rrsets));
+ return ((servers<=2)?(rrsets==servers):((rrsets*2)>=servers));
}
/* int findns(npp, class, nsp, countp, flag)
- * Find NS' or an SOA
+ * Find NS's or an SOA
* npp, class:
* dname whose most enclosing NS is wanted
* nsp, countp:
@@ -2295,8 +2285,11 @@ check_ns()
* boolean: we're being called from ADDAUTH, bypass authority checks
* return value:
* NXDOMAIN: we are authoritative for this {dname,class}
+ * *countp is bogus, but nsp[] has a single SOA returned in it.
* SERVFAIL: we are auth but zone isn't loaded; or, no root servers found
- * OK: success (this is the only case where *countp and nsp[] are valid)
+ * *countp and nsp[] are bogus.
+ * OK: we are not authoritative, and here are the NS records we found.
+ * *countp and nsp[] return NS records of interest.
*/
int
findns(npp, class, nsp, countp, flag)
@@ -2311,9 +2304,7 @@ findns(npp, class, nsp, countp, flag)
register struct databuf **nspp;
struct hashbuf *htp;
-#ifdef DATUMREFCNT
nsp[0] = NULL;
-#endif
if (priming && (np == NULL || NAME(*np)[0] == '\0'))
htp = fcachetab;
@@ -2347,10 +2338,8 @@ findns(npp, class, nsp, countp, flag)
if (zones[dp->d_zone].z_flags & Z_AUTH) {
*npp = np;
nsp[0] = dp;
-#ifdef DATUMREFCNT
nsp[1] = NULL;
dp->d_rcnt++;
-#endif
return (NXDOMAIN);
} else {
/* XXX: zone isn't loaded but we're
@@ -2365,6 +2354,7 @@ findns(npp, class, nsp, countp, flag)
/* If no SOA records, look for NS records. */
nspp = &nsp[0];
*nspp = NULL;
+ delete_stale(np);
for (dp = np->n_data; dp != NULL; dp = dp->d_next) {
if (!match(dp, class, T_NS))
continue;
@@ -2380,15 +2370,10 @@ findns(npp, class, nsp, countp, flag)
* XXX: this is horribly bogus.
*/
if ((dp->d_zone == 0) &&
-#ifdef DATUMREFCNT
(dp->d_ttl < tt.tv_sec) &&
-#else
- (dp->d_ttl < (tt.tv_sec+900)) &&
-#endif
!(dp->d_flags & DB_F_HINT)) {
dprintf(1, (ddt, "findns: stale entry '%s'\n",
NAME(*np)));
-#ifdef DATUMREFCNT
/*
* We may have already added NS databufs
* and are going to throw them away. Fix
@@ -2398,20 +2383,12 @@ findns(npp, class, nsp, countp, flag)
*/
while (nspp > &nsp[0])
(*--nspp)->d_rcnt--;
-#endif
- /* Cache invalidate the NS RR's. */
-#ifndef DATUMREFCNT
- if (dp->d_ttl < tt.tv_sec)
-#endif
- delete_all(np, class, T_NS);
nsp[0] = NULL;
goto try_parent;
}
if (nspp < &nsp[NSMAX-1]) {
*nspp++ = dp;
-#ifdef DATUMREFCNT
dp->d_rcnt++;
-#endif
}
}
@@ -2423,7 +2400,7 @@ findns(npp, class, nsp, countp, flag)
*npp = np;
return (OK); /* Success, got some NS's */
}
-try_parent:
+ try_parent:
np = np_parent(np);
}
if (htp == hashtab) {
@@ -2440,6 +2417,7 @@ try_parent:
return (SERVFAIL);
}
+
/*
* Extract RR's from the given node that match class and type.
* Return number of bytes added to response.
@@ -2455,7 +2433,9 @@ finddata(np, class, type, hp, dnamep, lenp, countp)
{
register struct databuf *dp;
register char *cp;
- int buflen, n, count = 0, foundstale = 0;
+ int buflen, n, count = 0;
+
+ delete_stale(np);
#ifdef ROUND_ROBIN
if (type != T_ANY && type != T_PTR) {
@@ -2498,33 +2478,20 @@ finddata(np, class, type, hp, dnamep, lenp, countp)
#endif /*NCACHE*/
continue;
}
- if (stale(dp)) {
- /*
- * Don't use stale data.
- * Would like to call delete_all here
- * and continue, but the data chain would get
- * munged; can't restart, as make_rr has side
- * effects (leaving pointers in dnptr).
- * Just skip this entry for now
- * and call delete_all at the end.
- */
- dprintf(3, (ddt,
- "finddata: stale entry '%s'\n",
- NAME(*np)));
- if (dp->d_zone == 0)
- foundstale++;
- continue;
- }
if (dp->d_cred == DB_C_ADDITIONAL) {
+#ifdef NOADDITIONAL
+ continue;
+#else
/* we want to expire additional data very
* quickly. current strategy is to cut 5%
* off each time it is accessed. this makes
- * stale(dp) true faster when this datum is
+ * stale(dp) true earlier when this datum is
* used often.
*/
dp->d_ttl = tt.tv_sec
+
0.95 * (int) (dp->d_ttl - tt.tv_sec);
+#endif
}
#ifdef NCACHE
/* -ve $ing stuff, anant@isi.edu
@@ -2541,15 +2508,14 @@ finddata(np, class, type, hp, dnamep, lenp, countp)
*dnamep, type, class);
continue;
}
- if (type != T_ANY) {
- hp->rcode = NOERROR_NODATA;
+ if (type == T_ANY)
+ continue;
+ hp->rcode = NOERROR_NODATA;
+ if (dp->d_size == 0) { /* !RETURNSOA */
*countp = 0;
return 1; /* XXX - we have to report success */
}
- /* don't satisfy T_ANY queries from -$ info */
- continue;
}
-#ifndef RETURNSOA
if (dp->d_rcode == NXDOMAIN) {
if (count != 0) {
/*
@@ -2560,17 +2526,20 @@ finddata(np, class, type, hp, dnamep, lenp, countp)
*dnamep, type, class);
continue;
}
- if (type != T_ANY) {
- hp->rcode = NXDOMAIN;
+ hp->rcode = NXDOMAIN;
+ if (dp->d_size == 0) { /* !RETURNSOA */
*countp = 0;
return 1; /* XXX - we have to report success */
}
- /* don't satisfy T_ANY queries from -$ info */
- continue;
}
-#endif
#endif /*NCACHE*/
+ /* Don't put anything but key or sig RR's in response to
+ requests for key or sig */
+ if (((type == T_SIG) || (type == T_KEY)) &&
+ (!((dp->d_type == T_SIG) || (dp->d_type == T_KEY))) )
+ continue;
+
if ((n = make_rr(*dnamep, dp, (u_char *)cp, buflen, 1)) < 0) {
hp->tc = 1;
*countp = count;
@@ -2588,7 +2557,11 @@ finddata(np, class, type, hp, dnamep, lenp, countp)
hp->aa = 1; /* XXX */
#endif
if (dp->d_type == T_CNAME) {
- if (type != T_ANY) { /* or T_NS? */
+ /* don't alias if querying for key, sig, nxt, or any */
+ if ((type != T_KEY) &&
+ (type != T_SIG) &&
+ (type != T_NXT) &&
+ (type != T_ANY)) { /* or T_NS? */
*dnamep = (caddr_t) dp->d_data;
if (dp->d_zone != DB_Z_CACHE &&
(zones[dp->d_zone].z_flags & Z_AUTH) &&
@@ -2602,14 +2575,6 @@ finddata(np, class, type, hp, dnamep, lenp, countp)
* Cache invalidate the other RR's of same type
* if some have timed out
*/
- if (foundstale) {
- delete_all(np, class, type);
- /* XXX this isn't right if 'type' is something special
- * such as T_AXFR or T_MAILB, since the matching done
- * by match() in delete_all() is different from that
- * done by wanted() above.
- */
- }
dprintf(3, (ddt, "finddata: added %d class %d type %d RRs\n",
count, class, type));
*countp = count;
@@ -2618,19 +2583,25 @@ finddata(np, class, type, hp, dnamep, lenp, countp)
/*
* Do we want this data record based on the class and type?
+ * (We always return found unexpired SIG RR's that cover the wanted rrtype.)
*/
int
wanted(dp, class, type)
struct databuf *dp;
int class, type;
{
+ u_char *cp;
+ u_int16_t coveredType;
+ time_t expiration;
+
dprintf(3, (ddt, "wanted(%#lx, %d, %d) [%s %s]\n",
(u_long)dp, class, type,
p_class(dp->d_class), p_type(dp->d_type)));
if (dp->d_class != class && class != C_ANY)
return (0);
- if (type == dp->d_type)
+ /* Must check SIG for expiration below, other matches return OK here. */
+ if (type == dp->d_type && (type != T_SIG))
return (1);
#ifdef NCACHE
/*-ve $ing stuff, for a T_ANY query, we do not want to return
@@ -2640,7 +2611,26 @@ wanted(dp, class, type)
return (0);
#endif
+ /* First, look at the type of RR. */
switch (dp->d_type) {
+
+ /* Cases to deal with:
+ T_ANY search, return all unexpired SIGs.
+ T_SIG search, return all unexpired SIGs.
+ T_<foo> search, return all unexp SIG <FOO>s.
+ */
+ case T_SIG:
+ cp = dp->d_data;
+ GETSHORT(coveredType,cp);
+ cp += INT16SZ + INT32SZ; /* skip alg, labels, & orig TTL */
+ GETLONG(expiration,cp);
+
+ if (type == T_ANY || type == T_SIG || type == coveredType) {
+ if (expiration > time(0))
+ return (1); /* Unexpired matching SIG */
+ }
+ return (0); /* We don't return this SIG. */
+
case T_ANY:
return (1);
case T_CNAME:
@@ -2653,6 +2643,7 @@ wanted(dp, class, type)
break;
#endif
}
+ /* OK, now look at the type of query. */
switch (type) {
case T_ANY:
return (1);
@@ -2713,6 +2704,225 @@ add_data(np, dpp, cp, buflen, countp)
return (bytes);
}
+static void
+rrsetadd(flushset, name, dp)
+ struct flush_set *flushset;
+ char *name;
+ struct databuf *dp;
+{
+ struct flush_set *fs = flushset;
+ struct db_list *dbl;
+
+ while (fs->fs_name && (
+ strcasecmp(fs->fs_name,name) ||
+ (fs->fs_class != dp->d_class) ||
+ (fs->fs_type != dp->d_type) ||
+ (fs->fs_cred != dp->d_cred))) {
+ fs++;
+ }
+ if (!fs->fs_name) {
+ fs->fs_name = strdup(name);
+ if (!fs->fs_name)
+ panic(-1, "rrsetadd: out of memory");
+ fs->fs_class = dp->d_class;
+ fs->fs_type = dp->d_type;
+ fs->fs_cred = dp->d_cred;
+ fs->fs_list = NULL;
+ }
+ dbl = (struct db_list *)malloc(sizeof(struct db_list));
+ if (!dbl)
+ panic(-1, "rrsetadd: out of memory");
+ dbl->db_next = fs->fs_list;
+ dbl->db_dp = dp;
+ fs->fs_list = dbl;
+}
+
+static int
+ttlcheck(name,dbl)
+ char *name;
+ struct db_list *dbl;
+{
+ int type = dbl->db_dp->d_type;
+ int class = dbl->db_dp->d_class;
+ struct hashbuf *htp = hashtab;
+ const char *fname;
+ register struct namebuf *np;
+ struct db_list *dbp = dbl;
+ struct databuf *dp;
+ u_int32_t ttl;
+ int first;
+
+
+ np = nlookup(name, &htp, &fname, 0);
+ if (np == NULL || fname != name || ns_wildcard(NAME(*np))) {
+ return(1);
+ }
+
+ /* check that all the ttl's we have are the same, if not return 1 */
+ first = 1;
+ for (dp = np->n_data; dp != NULL; dp = dp->d_next) {
+ if (!match(dp, class, type))
+ continue;
+ if (first) {
+ ttl = dp->d_ttl;
+ first = 0;
+ } else if (ttl != dp->d_ttl) {
+ return(1);
+ }
+ }
+
+ /* there are no records of this type in the cache */
+ if (first)
+ return(1);
+
+ /*
+ * the ttls of all records we have in the cache are the same
+ * if the ttls differ in the new set we don't want it.
+ */
+
+ /* check that all the ttl's we have are the same, if not return 0 */
+ first = 1;
+ while (dbp) {
+ if (first) {
+ ttl = dbp->db_dp->d_ttl;
+ first = 0;
+ } else if (ttl != dbp->db_dp->d_ttl) {
+ return(0);
+ }
+ dbp = dbp->db_next;
+ }
+ return(1);
+}
+
+static int
+rrsetcmp(name, dbl)
+ char *name;
+ struct db_list *dbl;
+{
+ int type = dbl->db_dp->d_type;
+ int class = dbl->db_dp->d_class;
+ struct hashbuf *htp = hashtab;
+ const char *fname;
+ register struct namebuf *np;
+ struct db_list *dbp = dbl;
+ struct databuf *dp;
+ int exists = 0;
+
+
+ np = nlookup(name, &htp, &fname, 0);
+ if (np == NULL || fname != name || ns_wildcard(NAME(*np))) {
+ dprintf(1, (ddt, "rrsetcmp: name not in database\n"));
+ return(-1);
+ }
+
+ /* check that all entries in dbl are in the cache */
+ while (dbp) {
+ for (dp = np->n_data; dp != NULL; dp = dp->d_next) {
+ if (match(dp, class, type))
+ exists++;
+ if (!db_cmp(dp, dbp->db_dp)
+#ifdef NOADDITIONAL
+ && ((dp->d_cred == dbp->db_dp->d_cred) ||
+ (dp->d_cred != DB_C_ADDITIONAL))
+#endif
+ )
+ break;
+ }
+ if (!dp) {
+ dprintf(1, (ddt, "rrsetcmp: %srecord%s in database\n",
+ exists ? "" : "no ", exists ? " not" : "s"));
+ return(exists? 1 : -1);
+ }
+ dbp = dbp->db_next;
+ }
+
+ /* Check that all cache entries are in the list. */
+ for (dp = np->n_data; dp != NULL; dp = dp->d_next) {
+ if (!match(dp, class, type))
+ continue;
+#ifdef NCACHE
+ if (dp->d_rcode)
+ return(1);
+#endif
+ dbp = dbl;
+ while (dbp) {
+ if (!db_cmp(dp, dbp->db_dp))
+ break;
+ dbp = dbp->db_next;
+ }
+ if (!dbp) {
+ dprintf(1, (ddt, "rrsetcmp: record not in rrset\n"));
+ return(1);
+ }
+ }
+ dprintf(1, (ddt, "rrsetcmp: rrsets matched\n"));
+ return(0);
+}
+
+static void
+rrsetupdate(flushset, flags)
+ struct flush_set * flushset;
+ int flags;
+{
+ struct flush_set *fs = flushset;
+ struct db_list *dbp, *odbp;
+ int n;
+
+ while (fs->fs_name) {
+ dprintf(1,(ddt, "rrsetupdate: %s\n",
+ fs->fs_name[0] ? fs->fs_name : "."));
+ if ((n = rrsetcmp(fs->fs_name,fs->fs_list)) &&
+ ttlcheck(fs->fs_name,fs->fs_list)) {
+ if (n > 0)
+ flushrrset(fs);
+
+ dbp = fs->fs_list;
+ while (dbp) {
+ n = db_update(fs->fs_name, dbp->db_dp,
+ dbp->db_dp, flags, hashtab);
+ dprintf(1,(ddt, "rrsetupdate: %s %d\n",
+ fs->fs_name[0] ? fs->fs_name : ".", n));
+ if (n != OK)
+ db_free(dbp->db_dp);
+ odbp = dbp;
+ dbp = dbp->db_next;
+ free((char *)odbp);
+ }
+ } else {
+ dbp = fs->fs_list;
+ while (dbp) {
+ db_free(dbp->db_dp);
+ odbp = dbp;
+ dbp = dbp->db_next;
+ free((char *)odbp);
+ }
+ }
+ fs->fs_list = NULL;
+ fs++;
+ }
+}
+
+static void
+flushrrset(fs)
+ struct flush_set * fs;
+{
+ struct databuf *dp;
+ int n;
+
+ dprintf(1, (ddt, "flushrrset(%s, %s, %s, %d)\n",
+ fs->fs_name[0]?fs->fs_name:".", p_type(fs->fs_type),
+ p_class(fs->fs_class), fs->fs_cred));
+ dp = savedata(fs->fs_class, fs->fs_type, 0, NULL, 0);
+ dp->d_zone = 0;
+ dp->d_cred = fs->fs_cred;
+ dp->d_clev = 0;
+ do {
+ n = db_update(fs->fs_name, dp, NULL, DB_DELETE, hashtab);
+ dprintf(1, (ddt, "flushrrset: %d\n", n));
+ } while (n == OK);
+ db_free(dp);
+}
+
/*
* This is best thought of as a "cache invalidate" function.
* It is called whenever a piece of data is determined to have
@@ -2741,3 +2951,26 @@ delete_all(np, class, type)
dp = dp->d_next;
}
}
+
+/* delete_stale(np)
+ * for all RRs associated with this name, check for staleness (& delete)
+ * arguments:
+ * np = pointer to namebuf to be cleaned.
+ * returns:
+ * void.
+ * side effects:
+ * delete_all() can be called, freeing memory and relinking chains.
+ */
+void
+delete_stale(np)
+ struct namebuf *np;
+{
+ struct databuf *dp;
+ again:
+ for (dp = np->n_data; dp != NULL; dp = dp->d_next) {
+ if ((dp->d_zone == 0) && stale(dp)) {
+ delete_all(np, dp->d_class, dp->d_type);
+ goto again;
+ }
+ }
+}
OpenPOWER on IntegriCloud