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.c3236
1 files changed, 0 insertions, 3236 deletions
diff --git a/contrib/bind/named/ns_resp.c b/contrib/bind/named/ns_resp.c
deleted file mode 100644
index d48da23..0000000
--- a/contrib/bind/named/ns_resp.c
+++ /dev/null
@@ -1,3236 +0,0 @@
-#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.41 1998/04/07 04:59:45 vixie Exp $";
-#endif /* not lint */
-
-/*
- * ++Copyright++ 1986, 1988, 1990
- * -
- * Copyright (c) 1986, 1988, 1990
- * The Regents of the University of California. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the University of
- * California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- * -
- * Portions Copyright (c) 1993 by Digital Equipment Corporation.
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies, and that
- * the name of Digital Equipment Corporation not be used in advertising or
- * publicity pertaining to distribution of the document or software without
- * specific, written prior permission.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
- * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
- * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
- * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
- * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
- * 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--
- */
-
-#include <sys/types.h>
-#include <sys/param.h>
-#include <sys/socket.h>
-#include <sys/file.h>
-#include <netinet/in.h>
-#include <arpa/nameser.h>
-#include <arpa/inet.h>
-#include <syslog.h>
-#include <errno.h>
-#include <stdio.h>
-#include <resolv.h>
-
-#include "named.h"
-
-static u_int8_t norootlogged[MAXCLASS]; /* XXX- should be a bitmap */
-
-static const char skipnameFailedAnswer[] = "skipname failed in answer",
- skipnameFailedAuth[] = "skipname failed in authority",
- skipnameFailedQuery[] = "skipname failed in query",
- outofDataQuery[] = "ran out of data in query",
- outofDataAnswer[] = "ran out of data in answer",
- notSingleQuery[] = "not exactly one query",
- expandFailedQuery[] = "dn_expand failed in query",
- expandFailedAnswer[] = "dn_expand failed in answer",
- expandFailedAuth[] = "dn_expand failed in authority",
- outofDataAuth[] = "ran out of data in authority",
- dlenOverrunAnswer[] = "dlen overrun in answer",
- dlenOverrunAuth[] = "dlen overrun in authority",
- 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",
- 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;
- struct db_list *fs_last;
-};
-
-static void rrsetadd __P((struct flush_set *, char *,
- struct databuf *)),
- rrsetupdate __P((struct flush_set *, int flags)),
- flushrrset __P((struct flush_set *)),
- free_flushset __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,
- char **));
-
-static void add_related_additional __P((char *));
-static void free_related_additional __P((void));
-static int related_additional __P((char *));
-static void maybe_free __P((char **));
-
-#define MAX_RELATED 100
-
-static int num_related = 0;
-static char *related[MAX_RELATED];
-
-#ifdef LAME_LOGGING
-static char *
-learntFrom(qp, server)
- struct qinfo *qp;
- struct sockaddr_in *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) {
- free(buf);
- buf = NULL;
- }
-
- a = ns = na = "<Not Available>";
-
- for (i = 0; i < (int)qp->q_naddr; i++) {
- if (qp->q_addr[i].ns_addr.sin_addr.s_addr ==
- server->sin_addr.s_addr) {
- db = qp->q_addr[i].ns;
- if (db) {
-#ifdef STATS
- if (db->d_ns) {
- strcpy(nsbuf,
- inet_ntoa(db->d_ns->addr));
- ns = nsbuf;
- } else {
- ns = zones[db->d_zone].z_origin;
- }
-#endif
-
-#ifdef NCACHE
- if (!db->d_rcode)
-#endif
- na = (char*)qp->q_addr[i].ns->d_data;
- }
-
-#ifdef STATS
- db = qp->q_addr[i].nsdata;
- if (db) {
- if (db->d_ns) {
- strcpy(abuf,
- inet_ntoa(db->d_ns->addr));
- a = abuf;
- } else {
- a = zones[db->d_zone].z_origin;
- }
- }
-#endif
- break;
- }
- }
-
- if ((a == ns) && (ns == na)) /* all "UNKNOWN" */
- return ("");
-
-#ifdef STATS
-# define LEARNTFROM " '%s': learnt (A=%s,NS=%s)"
-#else
-# define LEARNTFROM " '%s'"
-#endif
- buf = malloc(strlen(a = (*a ? a : "\".\"")) +
- strlen(ns = (*ns ? ns : "\".\"")) +
- strlen(na = (*na ? na : "\".\"")) +
- sizeof(LEARNTFROM));
- if (!buf)
- return ("");
- sprintf(buf, LEARNTFROM, na, a, ns);
- return (buf);
-}
-#endif /*LAME_LOGGING*/
-
-void
-ns_resp(msg, msglen)
- u_char *msg;
- int msglen;
-{
- register struct qinfo *qp;
- register HEADER *hp;
- register struct qserv *qs;
- register struct databuf *ns, *ns2;
- register u_char *cp;
- u_char *eom = msg + msglen;
- struct flush_set *flushset = NULL;
- struct sockaddr_in *nsa;
- struct databuf *nsp[NSMAX];
- int i, c, n, qdcount, ancount, aucount, nscount, arcount, arfirst;
- int qtype, qclass, dbflags;
- int restart; /* flag for processing cname response */
- int validanswer;
- int cname, lastwascname, externalcname;
- int count, founddata, foundname;
- int buflen;
- int newmsglen;
- 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];
- u_char **dpp, *tp;
- time_t rtrip;
- struct hashbuf *htp;
- struct namebuf *np;
- struct netinfo *lp;
- struct fwdinfo *fwd;
- char *tname = NULL;
-
- nameserIncr(from_addr.sin_addr, nssRcvdR);
- nsp[0] = NULL;
- hp = (HEADER *) msg;
- if ((qp = qfindid(hp->id)) == NULL ) {
- dprintf(1, (ddt, "DUP? dropped (id %d)\n", ntohs(hp->id)));
- nameserIncr(from_addr.sin_addr, nssRcvdDupR);
- return;
- }
-
- dprintf(2, (ddt, "Response (%s %s %s) nsid=%d id=%d\n",
- (qp->q_flags & Q_SYSTEM) ?"SYSTEM" :"USER",
- (qp->q_flags & Q_PRIMING) ?"PRIMING" :"NORMAL",
- (qp->q_flags & Q_ZSERIAL) ?"ZSERIAL" :"-",
- ntohs(qp->q_nsid), ntohs(qp->q_id)));
-
- /*
- * Here we handle high level formatting problems by parsing the header.
- */
- qdcount = ntohs(hp->qdcount);
- ancount = ntohs(hp->ancount);
- aucount = ntohs(hp->nscount); /* !!! */
- arcount = ntohs(hp->arcount);
- free_addinfo(); /* sets addcount to zero */
- cp = msg + HFIXEDSZ;
- dpp = dnptrs;
- *dpp++ = msg;
- if ((*cp & INDIR_MASK) == 0)
- *dpp++ = cp;
- *dpp = NULL;
- if (qdcount == 1) {
- n = dn_expand(msg, eom, cp, qname, sizeof(qname));
- if (n <= 0) {
- formerrmsg = expandFailedQuery;
- goto formerr;
- }
- cp += n;
- if (cp + 2 * INT16SZ > eom) {
- formerrmsg = outofDataQuery;
- goto formerr;
- }
- GETSHORT(qtype, cp);
- GETSHORT(qclass, cp);
- if (!ns_nameok(qname, qclass, response_trans,
- ns_ownercontext(qtype, response_trans),
- qname, from_addr.sin_addr)) {
- formerrmsg = badNameFound;
- goto formerr;
- }
- if (cp > eom) {
- formerrmsg = outofDataQuery;
- goto formerr;
- }
- if (qp->q_msg && qp->q_msglen &&
- !res_nameinquery(qname, qtype, qclass,
- qp->q_msg, qp->q_msg + qp->q_msglen)) {
- sprintf(msgbuf,
- "query section mismatch (%s %s %s)",
- qname, p_class(qclass), p_type(qtype));
- formerrmsg = msgbuf;
- goto formerr;
- }
- if (strcasecmp(qp->q_name, qname) != 0 ||
- qp->q_class != qclass ||
- qp->q_type != qtype) {
- formerrmsg = wrongQuestion;
- goto formerr;
- }
- } else {
- strcpy(qname, qp->q_name);
- qclass = qp->q_class;
- qtype = qp->q_type;
- }
-
- /* cp now points after the query section. */
-
- /*
- * Here we handle bad responses from servers.
- * Several possibilities come to mind:
- * The server is sick and returns SERVFAIL
- * The server returns some garbage opcode (it's sick)
- * The server can't understand our query and return FORMERR
- * In all these cases, we drop the packet, disable retries on
- * this server and immediately force a retry.
- */
- if ((hp->rcode != NOERROR && hp->rcode != NXDOMAIN)
- || (hp->opcode != QUERY
-#ifdef BIND_NOTIFY
- && hp->opcode != NS_NOTIFY_OP
-#endif
- )) {
- dprintf(2, (ddt, "resp: error (ret %d, op %d), dropped\n",
- hp->rcode, hp->opcode));
- switch (hp->rcode) {
- case SERVFAIL:
- nameserIncr(from_addr.sin_addr, nssRcvdFail);
- break;
- case FORMERR:
- nameserIncr(from_addr.sin_addr, nssRcvdFErr);
- break;
- default:
- nameserIncr(from_addr.sin_addr, nssRcvdErr);
- break;
- }
- /* 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 wrong
- * interface 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;
- }
-
- if (qdcount != 1) {
- /* We don't generate or forward these (yet). */
- formerrmsg = notSingleQuery;
- goto formerr;
- }
-
- /*
- * Determine if the response came from a forwarder. Packets from
- * anyplace not listed as a forwarder or as a server to whom we
- * might have forwarded the query will be dropped.
- */
- for (fwd = fwdtab; fwd != (struct fwdinfo *)NULL; fwd = fwd->next) {
- if (fwd->fwdaddr.sin_addr.s_addr ==
- from_addr.sin_addr.s_addr) {
- /* XXX - should put this in STATS somewhere. */
- break;
- }
- }
- /*
- * XXX: note bad ambiguity here. if one of our forwarders is also
- * a delegated server for some domain, then we will not update
- * the RTT information on any replies we get from those servers.
- * Workaround: disable recursion on authoritative servers so that
- * the ambiguity does not arise.
- */
- /*
- * If we weren't using a forwarder, find the qinfo pointer and update
- * the rtt and fact that we have called on this server before.
- */
- if (fwd == (struct fwdinfo *)NULL) {
- struct timeval *stp;
-
- for (n = 0, qs = qp->q_addr; (u_int)n < qp->q_naddr; n++, qs++)
- if (qs->ns_addr.sin_addr.s_addr ==
- from_addr.sin_addr.s_addr)
- break;
- if ((u_int)n >= qp->q_naddr) {
- if (!haveComplained((char*)from_addr.sin_addr.s_addr,
- "unexpected source")) {
- syslog(LOG_INFO,
- "Response from unexpected source (%s)",
- sin_ntoa(&from_addr));
- }
- /*
- * We don't know who this response came from so it
- * gets dropped on the floor.
- */
- return;
- }
- stp = &qs->stime;
-
- /* Handle response from different (untried) interface */
- if ((qs->ns != NULL) && (stp->tv_sec == 0)) {
- ns = qs->ns;
- while (qs > qp->q_addr
- && (qs->stime.tv_sec == 0 || qs->ns != ns))
- qs--;
- *stp = qs->stime;
- /* XXX - sometimes stp still ends up pointing to
- * a zero timeval, in spite of the above attempt.
- * Why? What should we do about it?
- */
- dprintf(1, (ddt,
- "Response from unused address %s, assuming %s\n",
- sin_ntoa(&from_addr),
- sin_ntoa(&qs->ns_addr)));
- /* XXX - catch aliases here */
- }
-
- /* compute query round trip time */
- /* XXX - avoid integer overflow, which is quite likely if stp
- * points to a zero timeval (see above).
- * rtrip is of type time_t, which we assume is at least
- * as big as an int.
- */
- if ((tt.tv_sec - stp->tv_sec) > (INT_MAX-999)/1000) {
- rtrip = INT_MAX;
- } else {
- rtrip = ((tt.tv_sec - stp->tv_sec) * 1000 +
- (tt.tv_usec - stp->tv_usec) / 1000);
- }
-
- dprintf(3, (ddt, "stime %lu/%lu now %lu/%lu rtt %ld\n",
- (u_long)stp->tv_sec, (u_long)stp->tv_usec,
- (u_long)tt.tv_sec, (u_long)tt.tv_usec,
- (long)rtrip));
-
- /* prevent floating point overflow, limit to 1000 sec */
- if (rtrip > 1000000) {
- rtrip = 1000000;
- }
- ns = qs->nsdata;
- /*
- * 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) {
- u_long t;
-
- if (ns->d_nstime == 0)
- t = rtrip;
- else
- t = ns->d_nstime * ALPHA
- +
- (1 - ALPHA) * rtrip;
- if (t > 65535)
- t = 65535;
- ns->d_nstime = (u_int16_t)t;
- }
-
- /*
- * Record the source so that we do not use this NS again.
- */
- if (ns && qs->ns && (qp->q_nusedns < NSMAX)) {
- qp->q_usedns[qp->q_nusedns++] = qs->ns;
- dprintf(2, (ddt, "NS #%d addr %s used, rtt %d\n",
- n, sin_ntoa(&qs->ns_addr),
- ns->d_nstime));
- }
-
- /*
- * Penalize those who had earlier chances but failed
- * by multiplying round-trip times by BETA (>1).
- * Improve nstime for unused addresses by applying GAMMA.
- * The GAMMA factor makes unused entries slowly
- * improve, so they eventually get tried again.
- * GAMMA should be slightly less than 1.
- * Watch out for records that may have timed out
- * and are no longer the correct type. XXX
- */
-
- 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;
- if (ns2->d_type != T_A ||
- ns2->d_class != qs->ns->d_class) /* XXX */
- continue;
- if (qs->stime.tv_sec) {
- if (ns2->d_nstime == 0)
- t = (rtrip * BETA);
- else
- t = ns2->d_nstime * BETA
- +
- (1 - ALPHA) * rtrip;
- } else
- 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));
- }
- }
-
-#ifdef BIND_NOTIFY
- /* for now, NOTIFY isn't defined for ANCOUNT!=0, AUCOUNT!=0,
- * or ADCOUNT!=0. therefore the only real work to be done for
- * a NOTIFY-QR is to remove it from the query queue.
- */
- if (hp->opcode == NS_NOTIFY_OP) {
- qremove(qp);
- return;
- }
-#endif
-
-#ifdef LAME_DELEGATION
- /*
- * Non-authoritative, no answer, no error, with referral.
- */
- if (hp->rcode == NOERROR && !hp->aa && ancount == 0 && aucount > 0
-#ifdef BIND_NOTIFY
- && hp->opcode != NS_NOTIFY_OP
-#endif
- ) {
- u_char *tp;
- int type, class;
-#ifdef DEBUG
- if (debug > 0)
- fp_nquery(msg, msglen, ddt);
-#endif
- /*
- * Since there is no answer section (ancount == 0),
- * we must be pointing at the authority section (aucount > 0).
- */
- tp = cp;
- n = dn_expand(msg, eom, tp, name, sizeof name);
- if (n < 0) {
- formerrmsg = expandFailedAuth;
- goto formerr;
- }
- tp += n;
- if (tp + 2 * INT16SZ > eom) {
- formerrmsg = outofDataAuth;
- goto formerr;
- }
- GETSHORT(type, tp);
- GETSHORT(class, tp);
- if (!ns_nameok(name, class, response_trans,
- ns_ownercontext(type, response_trans),
- name, from_addr.sin_addr)) {
- formerrmsg = badNameFound;
- goto formerr;
- }
-
- /*
- * If the answer delegates us either to the same level in
- * the hierarchy or closer to the root, we consider this
- * server lame. Note that for now we only log the message
- * if the T_NS was C_IN, which is technically wrong (NS is
- * visible in all classes) but necessary anyway (non-IN
- * classes tend to not have good strong delegation graphs).
- */
-
- if (type == T_NS && samedomain(qp->q_domain, name)) {
- nameserIncr(from_addr.sin_addr, nssRcvdLDel);
- /* 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;
-#ifdef LAME_LOGGING
- if (class == C_IN &&
- !haveComplained((char*)nhash(sin_ntoa(&from_addr)),
- (char*)nhash(qp->q_domain)))
- syslog(LAME_LOGGING,
- "Lame server on '%s' (in '%s'?): %s%s\n",
- qname, qp->q_domain,
- sin_ntoa(&from_addr),
- learntFrom(qp, &from_addr));
-
-#endif /* LAME_LOGGING */
- /* XXX - doesn't handle responses sent from the wrong
- * interface 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;
- }
- }
-#endif /* LAME_DELEGATION */
-
- if (qp->q_flags & Q_ZSERIAL) {
- if (hp->aa && ancount > 0 && hp->rcode == NOERROR &&
- qtype == T_SOA && ((qclass == C_IN) || (qclass == C_HS))) {
- int n;
- u_int16_t type, class, dlen;
- u_int32_t serial;
- u_char *tp = cp;
- u_char *rdatap;
-
- n = dn_expand(msg, eom, tp, name, sizeof name);
- if (n < 0) {
- formerrmsg = expandFailedAnswer;
- goto formerr;
- }
- tp += n; /* name */
- if (tp + 3 * INT16SZ + INT32SZ > eom) {
- formerrmsg = outofDataAnswer;
- goto formerr;
- }
- GETSHORT(type, tp); /* type */
- GETSHORT(class, tp); /* class */
- tp += INT32SZ; /* ttl */
- GETSHORT(dlen, tp); /* dlen */
- rdatap = tp; /* start of rdata */
- if (!ns_nameok(name, class, response_trans,
- ns_ownercontext(type, response_trans),
- name, from_addr.sin_addr)) {
- formerrmsg = badNameFound;
- goto formerr;
- }
- if (strcasecmp(qname, name) ||
- qtype != type ||
- qclass != class) {
- sprintf(msgbuf,
- "qserial answer mismatch (%s %s %s)",
- name, p_class(class), p_type(type));
- formerrmsg = msgbuf;
- goto formerr;
- }
-
- if (0 >= (n = dn_skipname(tp, eom))) {
- formerrmsg = skipnameFailedAnswer;
- goto formerr;
- }
- tp += n; /* mname */
- if (0 >= (n = dn_skipname(tp, eom))) {
- formerrmsg = skipnameFailedAnswer;
- goto formerr;
- }
- tp += n; /* rname */
- if (tp + 5 * INT32SZ > eom) {
- formerrmsg = dlenUnderrunAnswer;
- goto formerr;
- }
- GETLONG(serial, tp);
- tp += 4 * INT32SZ; /* Skip rest of SOA. */
- if ((u_int)(tp - rdatap) != dlen) {
- formerrmsg = dlenOverrunAnswer;
- goto formerr;
- }
-
- qserial_answer(qp, serial);
- qremove(qp);
- } else {
- retry(qp);
- }
- return;
- }
-
- /*
- * Add the info received in the response to the data base.
- */
- arfirst = ancount + aucount;
- c = arfirst + arcount;
-
- /* -ve $ing non-existence of record, must handle non-authoritative
- * NOERRORs with c == 0.
- */
- if (!hp->aa && hp->rcode == NOERROR && c == 0)
- goto return_msg;
-
-#ifdef notdef
- /*
- * If the request was for a CNAME that doesn't exist,
- * but the name is valid, fetch any other data for the name.
- * DON'T do this now, as it will requery if data are already
- * in the cache (maybe later with negative caching).
- */
- if (type == T_CNAME && c == 0 && hp->rcode == NOERROR
- && !(qp->q_flags & Q_SYSTEM)) {
- dprintf(4, (ddt, "resp: leaving, no CNAME\n"));
-
- /* Cause us to put it in the cache later */
- prime(class, T_ANY, qp);
-
- /* Nothing to store, just give user the answer */
- goto return_msg;
- }
-#endif /* notdef */
-
- if (qp->q_flags & Q_SYSTEM)
- dbflags = DB_NOTAUTH | DB_NODATA;
- else
- dbflags = DB_NOTAUTH | DB_NODATA | DB_NOHINTS;
- count = c;
- if (qp->q_flags & Q_PRIMING)
- dbflags |= DB_PRIMING;
- if (hp->tc) {
- count -= arcount; /* truncation had to affect this */
- if (!arcount) {
- count -= aucount; /* guess it got this too */
- }
- if (!(arcount || aucount)) {
- count -= ancount; /* things are pretty grim */
- }
- /* XXX - should retry this query with TCP */
- /*
- * XXX - if this response is forwarded to the client
- * the truncated section is included. We will not
- * validate it, and if it somehow corrupt, we won't
- * notice.
- *
- * XXX - if the answer section is truncated and we got
- * this response after being redirected by a CNAME, we
- * will not include any part of the final answer in our
- * response to the client. This will make the client
- * think that there are no RRs of the appropriate type.
- */
- }
-
- tp = cp;
-
- restart = 0;
- validanswer = 0;
- nscount = 0;
- cname = 0;
- lastwascname = 0;
- externalcname = 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 *dp;
- int type;
-
- maybe_free(&tname);
- if (cp >= eom) {
- free_related_additional();
- if (flushset != NULL)
- free_flushset(flushset);
- formerrmsg = outofDataFinal;
- goto formerr;
- }
- n = rrextract(msg, msglen, cp, &dp, name, sizeof name, &tname);
- if (n < 0) {
- free_related_additional();
- maybe_free(&tname);
- if (flushset != NULL)
- free_flushset(flushset);
- formerrmsg = outofDataFinal;
- goto formerr;
- }
- cp += n;
- if (!dp)
- continue;
- type = dp->d_type;
- if (i < ancount) {
- /* Answer section. */
- if (externalcname || strcasecmp(name, aname) != 0) {
- if (!externalcname)
- syslog(LOG_DEBUG,
- "wrong ans. name (%s != %s)",
- name, aname);
- else
- dprintf(3, (ddt,
- "ignoring answer '%s' after external cname\n",
- name));
- db_free(dp);
- continue;
- }
- if (type == T_CNAME &&
- qtype != T_CNAME && qtype != T_ANY) {
- strcpy(aname, (char *)dp->d_data);
- if (!samedomain(aname, qp->q_domain))
- externalcname = 1;
- cname = 1;
- lastwascname = 1;
- } else {
- validanswer = 1;
- lastwascname = 0;
- }
-
- if (tname != NULL) {
- add_related_additional(tname);
- tname = NULL;
- }
-
- dp->d_cred = (hp->aa && !strcasecmp(name, qname))
- ? DB_C_AUTH
- : DB_C_ANSWER;
- } else {
- /* After answer section. */
- if (lastwascname) {
- dprintf(3, (ddt,
- "last was cname, ignoring auth. and add.\n"));
- db_free(dp);
- break;
- }
- if (i < arfirst) {
- /* Authority section. */
- switch (type) {
- case T_NS:
- case T_SOA:
- if (!samedomain(aname, name)){
- syslog(LOG_DEBUG,
- "bad referral (%s !< %s)",
- aname[0] ? aname : ".",
- name[0] ? name : ".");
- db_free(dp);
- continue;
- } else if (!samedomain(name,
- qp->q_domain)) {
- if (!externalcname)
- syslog(LOG_DEBUG,
- "bad referral (%s !< %s)",
- name[0] ? name : ".",
- qp->q_domain[0] ?
- qp->q_domain : ".");
- db_free(dp);
- continue;
- }
- if (type == T_NS) {
- nscount++;
- add_related_additional(tname);
- tname = NULL;
- }
- break;
- case T_NXT:
- case T_SIG:
- break;
- default:
- syslog(LOG_DEBUG,
- "invalid RR type '%s' in authority section (name = '%s') from %s",
- p_type(type), name,
- sin_ntoa(&from_addr));
- db_free(dp);
- continue;
- }
- } else {
- /* Additional section. */
- switch (type) {
- case T_A:
- case T_AAAA:
- if (externalcname ||
- !samedomain(name, qp->q_domain)) {
- dprintf(3, (ddt,
- "ignoring additional info '%s' type %s\n",
- name, p_type(type)));
- db_free(dp);
- continue;
- }
- if (!related_additional(name)) {
- syslog(LOG_DEBUG,
- "unrelated additional info '%s' type %s from %s",
- name, p_type(type),
- sin_ntoa(&from_addr));
- db_free(dp);
- continue;
- }
- break;
- case T_KEY:
- case T_SIG:
- break;
- default:
- syslog(LOG_DEBUG,
- "invalid RR type '%s' in additional section (name = '%s') from %s",
- p_type(type), name,
- sin_ntoa(&from_addr));
- db_free(dp);
- continue;
- }
- }
- dp->d_cred = (qp->q_flags & Q_PRIMING)
- ? DB_C_ANSWER
- : DB_C_ADDITIONAL;
- }
- rrsetadd(flushset, name, dp);
- }
- free_related_additional();
- maybe_free(&tname);
- if (flushset) {
- rrsetupdate(flushset, dbflags);
- free_flushset(flushset);
- }
- if (lastwascname && !externalcname)
- syslog(LOG_DEBUG, "%s (%s)", danglingCname, aname);
-
- if (cp > eom) {
- formerrmsg = outofDataAFinal;
- goto formerr;
- }
-
- if ((qp->q_flags & Q_SYSTEM) && ancount) {
- 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
- if (qp->q_notifyzone != DB_Z_CACHE) {
- struct zoneinfo *zp = &zones[qp->q_notifyzone];
-
- /*
- * Clear this first since sysnotify() might set it.
- */
- qp->q_notifyzone = DB_Z_CACHE;
- sysnotify(zp->z_origin, zp->z_class, T_SOA);
- }
-#endif
- qremove(qp);
- return;
- }
-
- if (ancount && count && !validanswer)
- /*
- * Everything passed validation but we didn't get the
- * final answer. The response must have contained
- * a dangling CNAME. Force a restart of the query.
- *
- * Don't set restart if count==0, since this means
- * the response was truncated in the answer section,
- * causing us to set count to 0 which will cause
- * validanswer to be 0 as well even though the answer
- * section probably contained valid RRs (just not
- * a complete set).
- * XXX - this works right if we can just forward this
- * response to the client, but not if we found a CNAME
- * in a prior response and restarted the query.
- */
- restart = 1;
-
- /*
- * If there are addresses and this is a local query,
- * sort them appropriately for the local context.
- */
-#ifdef SORT_RESPONSE
- if (!restart && ancount > 1 && (lp = local(&qp->q_from)) != NULL)
- sort_response(tp, ancount, lp, eom);
-#endif
-
- /*
- * An answer to a T_ANY query or a successful answer to a
- * regular query with no indirection, then just return answer.
- */
- if (!restart && ancount && (qtype == T_ANY || !qp->q_cmsglen)) {
- dprintf(3, (ddt, "resp: got as much answer as there is\n"));
- goto return_msg;
- }
-
- /*
- * We might want to cache this negative answer.
- */
- if (!ancount &&
- (!nscount || hp->rcode == NXDOMAIN) &&
- (hp->aa || fwd || qclass == C_ANY)) {
- /* we have an authoritative NO */
- dprintf(3, (ddt, "resp: leaving auth NO\n"));
-#ifdef NCACHE
- /* answer was NO */
- if (hp->aa &&
- ((hp->rcode == NXDOMAIN) || (hp->rcode == NOERROR))) {
- 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;
- }
-
- /*
- * All messages in here need further processing. i.e. they
- * are either CNAMEs or we got referred again.
- */
- count = 0;
- founddata = 0;
- foundname = 0;
- dname = name;
- /*
- * Even with VALIDATE, if restart==0 and ancount > 0, we should
- * have some valid data because because the data in the answer
- * section is owned by the query name and that passes the
- * validation test by definition
- *
- * XXX - the restart stuff doesn't work if any of the answer RRs
- * is not cacheable (TTL==0 or unknown RR type), since all of the
- * answer must pass through the cache and be re-assembled.
- */
- if ((!restart || !cname) && qp->q_cmsglen && ancount) {
- dprintf(1, (ddt, "Cname second pass\n"));
- newmsglen = MIN(PACKETSZ, qp->q_cmsglen);
- bcopy(qp->q_cmsg, newmsg, newmsglen);
- } else {
- newmsglen = MIN(PACKETSZ, msglen);
- bcopy(msg, newmsg, newmsglen);
- }
- hp = (HEADER *) newmsg;
- hp->ancount = htons(0);
- hp->nscount = htons(0);
- hp->arcount = htons(0);
- hp->rcode = NOERROR;
- dnptrs[0] = newmsg;
- dnptrs[1] = NULL;
- cp = newmsg + HFIXEDSZ;
- /*
- * Keep in mind that none of this code works when QDCOUNT>1.
- * cp ends up pointed just past the query section in both cases.
- */
- /*
- * Arrange for dname to contain the query name. The query
- * name can be either the original query name if restart==0
- * or the target of the last CNAME if we are following a
- * CNAME chain and were referred.
- */
- n = dn_expand(newmsg, newmsg + newmsglen, cp, dname,
- sizeof name);
- if (n < 0) {
- dprintf(1, (ddt, "dn_expand failed\n"));
- goto servfail;
- }
- if (!res_dnok(dname)) {
- dprintf(1, (ddt, "bad name (%s)\n", dname));
- goto servfail;
- }
- cp += n + QFIXEDSZ;
- buflen = sizeof(newmsg) - (cp - newmsg);
-
- cname = 0;
- try_again:
- dprintf(1, (ddt, "resp: nlookup(%s) qtype=%d\n", dname, qtype));
- fname = "";
- htp = hashtab; /* lookup relative to root */
- np = nlookup(dname, &htp, &fname, 0);
- dprintf(1, (ddt, "resp: %s '%s' as '%s' (cname=%d)\n",
- np == NULL ? "missed" : "found", dname, fname, cname));
- if (np == NULL || fname != dname)
- goto fetch_ns;
-
- foundname++;
- count = cp - newmsg;
- 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);
- if (fname != dname && qtype != T_CNAME && qtype != T_ANY) {
- cname++;
- goto try_again;
- }
- founddata = 1;
-
- dprintf(3, (ddt,
- "resp: foundname=%d, count=%d, founddata=%d, cname=%d\n",
- foundname, count, founddata, cname));
-
- fetch_ns:
-
- if (hp->tc)
- goto return_newmsg;
-
- /*
- * Look for name servers to refer to and fill in the authority
- * section or record the address for forwarding the query
- * (recursion desired).
- */
- free_nsp(nsp);
- switch (findns(&np, qclass, nsp, &count, 0)) {
- case NXDOMAIN: /* shouldn't happen */
- dprintf(3, (ddt, "req: leaving (%s, rcode %d)\n",
- dname, hp->rcode));
- if (!foundname)
- hp->rcode = NXDOMAIN;
- if (qclass != C_ANY) {
- hp->aa = 1;
- if (np && (!foundname || !founddata)) {
- n = doaddauth(hp, cp, buflen, np, nsp[0]);
- cp += n;
- buflen -= n;
- }
- }
- goto return_newmsg;
-
- case SERVFAIL:
- goto servfail;
- }
-
- if (founddata) {
- hp = (HEADER *)newmsg;
- n = add_data(np, nsp, cp, buflen, &count);
- if (n < 0) {
- hp->tc = 1;
- n = (-n);
- }
- cp += n;
- buflen -= n;
- hp->nscount = htons((u_int16_t)count);
- goto return_newmsg;
- }
-
- /*
- * If we get here, we don't have the answer yet and are about
- * to iterate to try and get it. First, infinite loop avoidance.
- */
- if (qp->q_nqueries++ > MAXQUERIES) {
- dprintf(1, (ddt, "resp: MAXQUERIES exceeded (%s %s %s)\n",
- dname, p_class(qclass), p_type(qtype)));
- syslog(LOG_INFO,
- "MAXQUERIES exceeded, possible data loop in resolving (%s)",
- dname);
- goto servfail;
- }
-
- /* Reset the query control structure */
-
- nsfree(qp, "ns_resp");
- qp->q_naddr = 0;
- qp->q_curaddr = 0;
- qp->q_fwd = fwdtab;
-
- getname(np, tmpdomain, sizeof tmpdomain);
- if (qp->q_domain != NULL)
- free(qp->q_domain);
- qp->q_domain = strdup(tmpdomain);
- if (qp->q_domain == NULL)
- panic(ENOMEM, "ns_resp: strdup failed");
-
- if ((n = nslookup(nsp, qp, dname, "ns_resp")) <= 0) {
- if (n < 0) {
- dprintf(3, (ddt, "resp: nslookup reports danger\n"));
- if (cname) /* a remote CNAME that does not have data */
- goto return_newmsg;
- goto servfail;
- } else {
- dprintf(3, (ddt, "resp: no addrs found for NS's\n"));
- /*
- * Timeout while sysquery looks up the NS addresses.
- *
- * Hopefully we'll have them when the client asks
- * again.
- *
- * too bad we can't just wait for the sysquery
- * response to restart this query (it's too hard).
- *
- * We could try to crawl back up the tree looking
- * for reachable servers, but we may have just
- * gotten delegated down here by a response with
- * no A RRs for the servers. If we blindly tried
- * this strategy, we bang on the same server forever.
- */
- goto timeout;
- }
- }
- for (n = 0; (u_int)n < qp->q_naddr; n++)
- qp->q_addr[n].stime.tv_sec = 0;
- if (!qp->q_fwd)
- qp->q_addr[0].stime = tt;
- if (cname) {
- if (qp->q_cname++ == MAXCNAMES) {
- dprintf(3, (ddt,
- "resp: leaving, MAXCNAMES exceeded\n"));
- goto servfail;
- }
- dprintf(1, (ddt, "q_cname = %d\n", qp->q_cname));
- dprintf(3, (ddt,
- "resp: building recursive query; nslookup\n"));
- if (!qp->q_cmsg) {
- qp->q_cmsg = qp->q_msg;
- qp->q_cmsglen = qp->q_msglen;
- } else if (qp->q_msg)
- (void) free(qp->q_msg);
- if ((qp->q_msg = (u_char *)malloc(PACKETSZ)) == NULL) {
- syslog(LOG_NOTICE, "resp: malloc error\n");
- goto servfail;
- }
- n = res_mkquery(QUERY, dname, qclass, qtype,
- NULL, 0, NULL, qp->q_msg, PACKETSZ);
- if (n < 0) {
- syslog(LOG_INFO, "resp: res_mkquery(%s) failed",
- dname);
- goto servfail;
- }
- if (qp->q_name != NULL)
- free(qp->q_name);
- qp->q_name = savestr(dname);
- qp->q_msglen = n;
- hp = (HEADER *) qp->q_msg;
- hp->rd = 0;
- } else
- hp = (HEADER *) qp->q_msg;
- hp->id = qp->q_nsid = htons(nsid_next());
- if (qp->q_fwd)
- hp->rd = 1;
- unsched(qp);
- schedretry(qp, retrytime(qp));
- nsa = Q_NEXTADDR(qp, 0);
- dprintf(1, (ddt, "resp: forw -> %s ds=%d nsid=%d id=%d %dms\n",
- sin_ntoa(nsa), ds,
- ntohs(qp->q_nsid), ntohs(qp->q_id),
- (qp->q_addr[0].nsdata != NULL)
- ? qp->q_addr[0].nsdata->d_nstime
- : (-1)));
-#ifdef DEBUG
- if (debug >= 10)
- fp_nquery(qp->q_msg, qp->q_msglen, ddt);
-#endif
- if (sendto(ds, (char*)qp->q_msg, qp->q_msglen, 0,
- (struct sockaddr *)nsa,
- sizeof(struct sockaddr_in)) < 0) {
- if (!haveComplained((char*)nsa->sin_addr.s_addr, sendtoStr))
- syslog(LOG_INFO, "ns_resp: sendto(%s): %m",
- sin_ntoa(nsa));
- nameserIncr(nsa->sin_addr, nssSendtoErr);
- }
- hp->rd = 0; /* leave set to 0 for dup detection */
-#ifdef XSTATS
- nameserIncr(nsa->sin_addr, nssSentFwdR);
-#endif
- nameserIncr(qp->q_from.sin_addr, nssRcvdFwdR);
- dprintf(3, (ddt, "resp: Query sent.\n"));
- free_nsp(nsp);
- return;
-
- formerr:
- if (!haveComplained((char*)from_addr.sin_addr.s_addr,
- (char*)nhash(formerrmsg)))
- syslog(LOG_INFO, "Malformed response from %s (%s)\n",
- sin_ntoa(&from_addr), formerrmsg);
-#ifdef XSTATS
- nameserIncr(from_addr.sin_addr, nssSentFErr);
-#endif
- free_nsp(nsp);
- return;
-
- return_msg:
- nameserIncr(from_addr.sin_addr, nssRcvdFwdR);
-#ifdef XSTATS
- nameserIncr(qp->q_from.sin_addr, nssSentFwdR);
-#endif
- /* The "standard" return code */
- hp->qr = 1;
- hp->id = qp->q_id;
- hp->rd = 1;
- hp->ra = (NoRecurse == 0);
- (void) send_msg(msg, msglen, qp);
- qremove(qp);
- free_nsp(nsp);
- return;
-
- return_newmsg:
- nameserIncr(qp->q_from.sin_addr, nssSentAns);
-
-#ifdef XSTATS
- if (!hp->aa)
- nameserIncr(qp->q_from.sin_addr, nssSentNaAns);
- if (hp->rcode == NXDOMAIN)
- nameserIncr(qp->q_from.sin_addr, nssSentNXD);
-#endif
- n = doaddinfo(hp, cp, buflen);
- cp += n;
- buflen -= n;
- hp->qr = 1;
- hp->id = qp->q_id;
- hp->rd = 1;
- hp->ra = (NoRecurse == 0);
- (void) send_msg(newmsg, cp - newmsg, qp);
- qremove(qp);
- free_nsp(nsp);
- return;
-
- servfail:
-#ifdef XSTATS
- nameserIncr(qp->q_from.sin_addr, nssSentFail);
-#endif
- hp = (HEADER *)(qp->q_cmsglen ? qp->q_cmsg : qp->q_msg);
- hp->rcode = SERVFAIL;
- hp->qr = 1;
- hp->id = qp->q_id;
- hp->rd = 1;
- hp->ra = (NoRecurse == 0);
- (void) send_msg((u_char *)hp, (qp->q_cmsglen ? qp->q_cmsglen : qp->q_msglen),
- qp);
- timeout:
- if (qp->q_stream != QSTREAM_NULL)
- sqrm(qp->q_stream);
- qremove(qp);
- free_nsp(nsp);
- return;
-}
-
-#define BOUNDS_CHECK(ptr, count) \
- do { \
- if ((ptr) + (count) > eom) { \
- hp->rcode = FORMERR; \
- return (-1); \
- } \
- } while (0)
-
-static int
-rrextract(msg, msglen, rrp, dpp, dname, namelen, tnamep)
- u_char *msg;
- int msglen;
- u_char *rrp;
- struct databuf **dpp;
- char *dname;
- int namelen;
- char **tnamep;
-{
- register u_char *cp, *eom, *rdatap;
- register int n;
- int class, type, dlen, n1;
- u_int32_t ttl;
- u_char *cp1;
- u_char data[MAXDNAME*2 + INT32SZ*5];
- register HEADER *hp = (HEADER *)msg;
- enum context context;
-
- if (tnamep != NULL)
- *tnamep = NULL;
-
- *dpp = NULL;
- cp = rrp;
- eom = msg + msglen;
- if ((n = dn_expand(msg, eom, cp, dname, namelen)) < 0) {
- hp->rcode = FORMERR;
- return (-1);
- }
- cp += n;
- BOUNDS_CHECK(cp, 2*INT16SZ + INT32SZ + INT16SZ);
- GETSHORT(type, cp);
- GETSHORT(class, cp);
- GETLONG(ttl, cp);
- GETSHORT(dlen, cp);
- BOUNDS_CHECK(cp, dlen);
- rdatap = cp;
- if (!ns_nameok(dname, class, response_trans,
- ns_ownercontext(type, response_trans),
- dname, from_addr.sin_addr)) {
- hp->rcode = FORMERR;
- return (-1);
- }
- 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:
- if (dlen != INT32SZ) {
- hp->rcode = FORMERR;
- return (-1);
- }
- /*FALLTHROUGH*/
- case T_WKS:
- case T_HINFO:
- case T_UINFO:
- case T_UID:
- case T_GID:
- case T_TXT:
- case T_X25:
- case T_ISDN:
- case T_NSAP:
- case T_AAAA:
- case T_LOC:
- case T_KEY:
-#ifdef ALLOW_T_UNSPEC
- case T_UNSPEC:
-#endif
- cp1 = cp;
- n = dlen;
- cp += n;
- break;
-
- case T_CNAME:
- case T_MB:
- case T_MG:
- case T_MR:
- case T_NS:
- case T_PTR:
- n = dn_expand(msg, eom, cp, (char *)data, sizeof data);
- if (n < 0) {
- hp->rcode = FORMERR;
- return (-1);
- }
- if (!ns_nameok((char *)data, class, response_trans,
- type == T_PTR ?ns_ptrcontext(dname) :domain_ctx,
- dname, from_addr.sin_addr)) {
- hp->rcode = FORMERR;
- return (-1);
- }
- cp += n;
- cp1 = data;
- n = strlen((char *)data) + 1;
- if (tnamep != NULL && (type == T_NS || type == T_MB))
- *tnamep = strdup((char *)cp1);
- break;
-
- case T_SOA:
- context = hostname_ctx;
- goto soa_rp_minfo;
- case T_RP:
- case T_MINFO:
- context = mailname_ctx;
- /* FALLTHROUGH */
- soa_rp_minfo:
- n = dn_expand(msg, eom, cp, (char *)data, sizeof data);
- if (n < 0) {
- hp->rcode = FORMERR;
- return (-1);
- }
- if (!ns_nameok((char *)data, class, response_trans, context,
- dname, from_addr.sin_addr)) {
- hp->rcode = FORMERR;
- return (-1);
- }
- cp += n;
- /*
- * The next use of 'cp' is dn_expand(), so we don't have
- * to BOUNDS_CHECK() here.
- */
- cp1 = data + (n = strlen((char *)data) + 1);
- n1 = sizeof(data) - n;
- if (type == T_SOA)
- n1 -= 5 * INT32SZ;
- n = dn_expand(msg, eom, cp, (char *)cp1, n1);
- if (n < 0) {
- hp->rcode = FORMERR;
- return (-1);
- }
- if (type == T_RP)
- context = domain_ctx;
- else
- context = mailname_ctx;
- if (!ns_nameok((char *)cp1, class, response_trans, context,
- dname, from_addr.sin_addr)) {
- hp->rcode = FORMERR;
- return (-1);
- }
- cp += n;
- cp1 += strlen((char *)cp1) + 1;
- if (type == T_SOA) {
- n = 5 * INT32SZ;
- BOUNDS_CHECK(cp, n);
- bcopy(cp, cp1, n);
- cp += n;
- cp1 += n;
- }
- n = cp1 - data;
- cp1 = data;
- break;
-
- case T_NAPTR:
- /* Grab weight and port. */
- BOUNDS_CHECK(cp, INT16SZ*2);
- bcopy(cp, data, INT16SZ*2);
- cp1 = data + INT16SZ*2;
- cp += INT16SZ*2;
-
- /* Flags */
- BOUNDS_CHECK(cp, 1);
- n = *cp++;
- BOUNDS_CHECK(cp, n);
- *cp1++ = n;
- bcopy(cp, cp1, n);
- cp += n; cp1 += n;
-
- /* Service */
- BOUNDS_CHECK(cp, 1);
- n = *cp++;
- BOUNDS_CHECK(cp, n);
- *cp1++ = n;
- bcopy(cp, cp1, n);
- cp += n; cp1 += n;
-
- /* Regexp */
- BOUNDS_CHECK(cp, 1);
- n = *cp++;
- BOUNDS_CHECK(cp, n);
- *cp1++ = n;
- bcopy(cp, cp1, n);
- cp += n; cp1 += n;
-
- /* Replacement */
- n = dn_expand(msg, eom, 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 */
- BOUNDS_CHECK(cp, INT16SZ);
- bcopy(cp, data, INT16SZ);
- cp1 = data + INT16SZ;
- cp += INT16SZ;
-
- if (type == T_SRV) {
- /* Grab weight and port. */
- BOUNDS_CHECK(cp, INT16SZ*2);
- bcopy(cp, cp1, INT16SZ*2);
- cp1 += INT16SZ*2;
- cp += INT16SZ*2;
- }
-
- /* get name */
- n = dn_expand(msg, eom, 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;
-
- if (tnamep != NULL)
- *tnamep = strdup((char *)cp1);
-
- /* compute end of data */
- cp1 += strlen((char *)cp1) + 1;
- /* compute size of data */
- n = cp1 - data;
- cp1 = data;
- break;
-
- case T_PX:
- /* grab preference */
- BOUNDS_CHECK(cp, INT16SZ);
- bcopy(cp, data, INT16SZ);
- cp1 = data + INT16SZ;
- cp += INT16SZ;
-
- /* get MAP822 name */
- n = dn_expand(msg, eom, cp, (char *)cp1,
- sizeof data - INT16SZ);
- if (n < 0) {
- hp->rcode = FORMERR;
- return (-1);
- }
- if (!ns_nameok((char *)cp1, class, response_trans,
- domain_ctx, dname, from_addr.sin_addr)) {
- hp->rcode = FORMERR;
- return (-1);
- }
- cp += n;
- /*
- * The next use of 'cp' is dn_expand(), so we don't have
- * to BOUNDS_CHECK() here.
- */
- cp1 += (n = strlen((char *)cp1) + 1);
- n1 = sizeof(data) - n;
- n = dn_expand(msg, eom, cp, (char *)cp1, n1);
- if (n < 0) {
- hp->rcode = FORMERR;
- return (-1);
- }
- if (!ns_nameok((char *)cp1, class, response_trans,
- domain_ctx, dname, from_addr.sin_addr)) {
- hp->rcode = FORMERR;
- return (-1);
- }
- cp += n;
- cp1 += strlen((char *)cp1) + 1;
- n = cp1 - data;
- 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 */
- BOUNDS_CHECK(cp, INT16SZ + 1 + 1 + 3*INT32SZ);
- 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 */
- BOUNDS_CHECK(cp, 18);
- bcopy(cp, cp1, 18);
- cp += 18;
- cp1 += 18;
-
- /* then the signer's name */
- n = dn_expand(msg, eom, cp, (char *)cp1, (sizeof data) - 18);
- if (n < 0) {
- hp->rcode = FORMERR;
- 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. */
- if (18 + (u_int)n > dlen) {
- hp->rcode = FORMERR;
- return (-1);
- }
- n = dlen - (18 + n);
- if (n > ((int)(sizeof data) - (int)(cp1 - (u_char *)data))) {
- hp->rcode = FORMERR;
- 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);
- }
-
- if (cp > eom) {
- hp->rcode = FORMERR;
- return (-1);
- }
- if ((u_int)(cp - rdatap) != dlen) {
- dprintf(3, (ddt,
- "encoded rdata length is %u, but actual length was %u",
- dlen, (u_int)(cp - rdatap)));
- hp->rcode = FORMERR;
- return (-1);
- }
- if (n > MAXDATA) {
- dprintf(1, (ddt,
- "update type %d: %d bytes is too much data\n",
- type, n));
- hp->rcode = FORMERR;
- return (-1);
- }
-
- ttl += tt.tv_sec;
-
- *dpp = savedata(class, type, ttl, cp1, n);
- return (cp - rrp);
-}
-
-/*
- * 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];
-
- 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), NULL))
- == -1)
- return (-1);
- if (!dp)
- return (-1);
-
- type = dp->d_type;
- class = dp->d_class;
- cp = rrp + n;
-
-#if defined(TRACEROOT) || defined(BOGUSNS)
- if ((type == T_NS) && (savens != NULL)) {
- char *temp, qname[MAXDNAME];
- register int bogus = 0;
- int bogusns = 0;
-#ifdef BOGUSNS
- if (addr_on_netlist(from_addr.sin_addr, boglist)) {
- bogusns++;
- bogus++;
- }
-#endif
- if (!bogus &&
- ((temp = strrchr((char *)dp->d_data, '.')) != NULL) &&
- !strcasecmp(temp, ".arpa")
- )
- bogus++;
- qname[0] = qname[1] = '\0';
- if (dn_expand(msg, msg + msglen, msg + HFIXEDSZ,
- qname, sizeof(qname)) < 0)
- qname[0] = '?';
- else if (qname[0] == '\0')
- qname[0] = '.';
- if (bogus && ((dname[0] == '\0') && (zone == 0))) {
- if (!haveComplained((char*)from_addr.sin_addr.s_addr,
- "bogus root NS"))
- syslog(LOG_NOTICE,
- "bogus root NS %s rcvd from %s on query for \"%s\"",
- dp->d_data, sin_ntoa(&from_addr), qname);
- db_free(dp);
- return (cp - rrp);
- }
-#ifdef BOGUSNS
- if (bogusns) {
- if (!haveComplained((char*)from_addr.sin_addr.s_addr,
- "bogus nonroot NS"))
- syslog(LOG_INFO,
- "bogus nonroot NS %s rcvd from %s on query for \"%s\"",
- dp->d_data, sin_ntoa(&from_addr), qname);
- db_free(dp);
- return (cp - rrp);
- }
-#endif
- }
-#endif /*TRACEROOT || BOGUSNS*/
-
- dp->d_zone = zone;
- dp->d_cred = cred;
- dp->d_clev = 0; /* We trust what is on disk more, except root srvrs */
- if ((n = db_update(dname, dp, dp, flags, hashtab)) != OK) {
-#ifdef DEBUG
- if (debug && (n != DATAEXISTS))
- fprintf(ddt, "update failed (%d)\n", n);
- else if (debug >= 3)
- fprintf(ddt, "update failed (DATAEXISTS)\n");
-#endif
- db_free(dp);
- } else if (type == T_NS && savens != NULL)
- *savens = dp;
- return (cp - rrp);
-}
-
-int
-send_msg(msg, msglen, qp)
- u_char *msg;
- int msglen;
- struct qinfo *qp;
-{
- if (qp->q_flags & Q_SYSTEM)
- return (1);
-#ifdef DEBUG
- if (debug) {
- fprintf(ddt,"send_msg -> %s (%s %d) id=%d\n",
- sin_ntoa(&qp->q_from),
- qp->q_stream == QSTREAM_NULL ? "UDP" : "TCP",
- qp->q_stream == QSTREAM_NULL ? qp->q_dfd
- : qp->q_stream->s_rfd,
- ntohs(qp->q_id));
- }
- if (debug > 4) {
- struct qinfo *tqp;
-
- for (tqp = nsqhead; tqp!=QINFO_NULL; tqp = tqp->q_link) {
- fprintf(ddt,
- "qp %#lx q_id: %d q_nsid: %d q_msglen: %d ",
- (u_long)tqp, tqp->q_id,
- tqp->q_nsid, tqp->q_msglen);
- fprintf(ddt,
- "q_naddr: %d q_curaddr: %d\n",
- tqp->q_naddr, tqp->q_curaddr);
- fprintf(ddt, "q_next: %#lx q_link: %#lx\n",
- (u_long)qp->q_next, (u_long)qp->q_link);
- }
- }
- if (debug > 5)
- fp_nquery(msg, msglen, ddt);
-#endif /* DEBUG */
- if (qp->q_stream == QSTREAM_NULL) {
- if (sendto(qp->q_dfd, (char*)msg, msglen, 0,
- (struct sockaddr *)&qp->q_from,
- sizeof(qp->q_from)) < 0) {
- if (!haveComplained((char*)qp->q_from.sin_addr.s_addr,
- sendtoStr))
-#if defined(SPURIOUS_ECONNREFUSED)
- if (errno != ECONNREFUSED)
-#endif
- syslog(LOG_INFO,
- "send_msg: sendto(%s): %m",
- sin_ntoa(&qp->q_from));
- nameserIncr(qp->q_from.sin_addr, nssSendtoErr);
- return (1);
- }
- } else {
- (void) writemsg(qp->q_stream->s_rfd, (u_char*)msg, msglen);
- sq_done(qp->q_stream);
- }
- return (0);
-}
-
-#ifdef notdef
-/* i don't quite understand this but the only ref to it is notdef'd --vix */
-prime(class, type, oqp)
- int class, type;
- register struct qinfo *oqp;
-{
- char dname[BUFSIZ];
-
- if (oqp->q_msg == NULL)
- return;
- if (dn_expand((u_char *)oqp->q_msg,
- (u_char *)oqp->q_msg + oqp->q_msglen,
- (u_char *)oqp->q_msg + HFIXEDSZ, (u_char *)dname,
- sizeof(dname)) < 0)
- return;
- dprintf(2, (ddt, "prime: %s\n", dname));
- (void) sysquery(dname, class, type, NULL, 0, QUERY);
-}
-#endif
-
-void
-prime_cache()
-{
- register struct qinfo *qp;
-
- dprintf(1, (ddt, "prime_cache: priming = %d\n", priming));
- if (!priming && fcachetab->h_tab[0] != NULL && !forward_only) {
- priming++;
- if (!(qp = sysquery("", C_IN, T_NS, NULL, 0, QUERY)))
- priming = 0;
- else
- qp->q_flags |= (Q_SYSTEM | Q_PRIMING);
- }
- needs_prime_cache = 0;
- return;
-}
-
-#ifdef BIND_NOTIFY
-struct notify *
-findNotifyPeer(zp, ina)
- const struct zoneinfo *zp;
- struct in_addr ina;
-{
- register struct notify *ap;
-
- for (ap = zp->z_notifylist; ap; ap = ap->next)
- if (ap->addr.s_addr == ina.s_addr)
- break;
- return (ap);
-}
-
-/* sysnotify(dname, class, type)
- * cause a NOTIFY request to be sysquery()'d to each secondary server
- * of the zone that "dname" is within.
- */
-void
-sysnotify(dname, class, type)
- const char *dname;
- int class, type;
-{
- char *soaname, *zname;
- const char *fname;
- register struct databuf *dp;
- struct in_addr nss[NSMAX];
- int nns, na, zn, nsc;
- struct hashbuf *htp;
- struct zoneinfo *zp;
- struct notify *ap;
- struct namebuf *np;
-
- htp = hashtab;
- np = nlookup(dname, &htp, &fname, 0);
- if (!np)
- panic(-1, "sysnotify: can't find name");
- zn = findMyZone(np, class);
- if (zn == DB_Z_CACHE)
- panic(-1, "sysnotify: not auth zone");
- zp = &zones[zn];
- if (zp->z_type != Z_PRIMARY && zp->z_type != Z_SECONDARY)
- panic(-1, "sysnotify: not pri/sec");
- zname = zp->z_origin;
-/*
-**DBG** syslog(LOG_INFO, "sysnotify: found \"%s\" in \"%s\" (%s)",
-**DBG** dname, zname, zoneTypeString(zp));
-*/
- nns = na = 0;
- /*
- * Send to recent AXFR peers.
- */
- for (ap = zp->z_notifylist; ap; ap = ap->next) {
- if (tt.tv_sec - ap->last >= zp->z_refresh) {
- /* XXX - probably should do GC here. */
- continue;
- }
- nss[0] = ap->addr;
- nsc = 1;
- nns++;
- na++;
- sysquery(dname, class, T_SOA, nss, nsc, NS_NOTIFY_OP);
- }
- if (zp->z_type != Z_PRIMARY)
- goto done;
- /*
- * Master.
- */
- htp = hashtab;
- np = nlookup(zname, &htp, &fname, 0);
- if (!np)
- panic(-1, "sysnotify: found name but not zone");
- soaname = NULL;
- for (dp = np->n_data; dp; dp = dp->d_next) {
- if (!dp->d_zone || !match(dp, class, T_SOA))
- continue;
- if (soaname) {
- syslog(LOG_NOTICE, "multiple SOA's for zone \"%s\"?",
- zname);
- return;
- }
- soaname = (char *) dp->d_data;
- }
- if (!soaname) {
- syslog(LOG_NOTICE, "no SOA found for zone \"%s\"", zname);
- return;
- }
-
- for (dp = np->n_data; dp; dp = dp->d_next) {
- register struct databuf *adp;
- struct namebuf *anp;
-
- if (!dp->d_zone || !match(dp, class, T_NS))
- continue;
- /* NS RDATA is server name. */
- if (strcasecmp((char*)dp->d_data, soaname) == 0)
- continue;
- htp = hashtab;
- anp = nlookup((char*)dp->d_data, &htp, &fname, 0);
- if (!anp) {
- syslog(LOG_INFO, "sysnotify: can't nlookup(%s)?",
- (char*)dp->d_data);
- continue;
- }
- nsc = 0;
- for (adp = anp->n_data; adp; adp = adp->d_next) {
- struct in_addr ina;
- if (!match(adp, class, T_A))
- continue;
- ina = data_inaddr(adp->d_data);
- /* Don't send to things we handled above. */
- ap = findNotifyPeer(zp, ina);
- if (ap && tt.tv_sec - ap->last < zp->z_refresh)
- goto nextns;
- if (nsc < NSMAX)
- nss[nsc++] = ina;
- } /*next A*/
- if (nsc == 0) {
- struct qinfo *qp;
-
- qp = sysquery((char*)dp->d_data, /*NS name*/
- class, /*XXX: C_IN?*/
- T_A, 0, 0, QUERY);
- if (qp)
- qp->q_notifyzone = zn;
- continue;
- }
- (void) sysquery(dname, class, T_SOA, nss, nsc, NS_NOTIFY_OP);
- nns++;
- na += nsc;
- nextns:;
- } /*next NS*/
- done:
- if (nns || na) {
- char tmp[MAXDNAME];
-
- /* Many syslog()'s only take 5 args. */
- sprintf(tmp, "%s %s %s", dname, p_class(class), p_type(type));
- syslog(LOG_INFO, "Sent NOTIFY for \"%s\" (%s); %d NS, %d A",
- tmp, zname, nns, na);
- }
-}
-#endif /*BIND_NOTIFY*/
-
-struct qinfo *
-sysquery(dname, class, type, nss, nsc, opcode)
- const char *dname;
- int class, type;
- struct in_addr *nss;
- int nsc, opcode;
-{
- register struct qinfo *qp, *oqp;
- register HEADER *hp;
- char tmpdomain[MAXDNAME];
- struct namebuf *np;
- struct databuf *nsp[NSMAX];
- struct hashbuf *htp;
- struct sockaddr_in *nsa;
- const char *fname;
- int n, count;
-
- nsp[0] = NULL;
- dprintf(3, (ddt, "sysquery(%s, %d, %d, %#lx, %d)\n",
- dname, class, type, (u_long)nss, nsc));
- qp = qnew(dname, class, type);
-
- if (nss && nsc) {
- np = NULL;
- } else {
- htp = hashtab;
- if (priming && dname[0] == '\0') {
- np = NULL;
- } else if ((np = nlookup(dname, &htp, &fname, 1)) == NULL) {
- syslog(LOG_INFO, "sysquery: nlookup error on %s?",
- dname);
- err1:
- qfree(qp);
- return (NULL);
- }
-
- n = findns(&np, class, nsp, &count, 0);
- switch (n) {
- case NXDOMAIN:
- case SERVFAIL:
- syslog(LOG_DEBUG, "sysquery: findns error (%s) on %s?",
- n == NXDOMAIN ? "NXDOMAIN" : "SERVFAIL", dname);
- err2:
- free_nsp(nsp);
- goto err1;
- }
- }
-
- /* build new qinfo struct */
- qp->q_cmsg = qp->q_msg = NULL;
- qp->q_dfd = ds;
- if (nss && nsc)
- qp->q_fwd = NULL;
- else
- qp->q_fwd = fwdtab;
- qp->q_expire = tt.tv_sec + RETRY_TIMEOUT*2;
- qp->q_flags |= Q_SYSTEM;
-
- getname(np, tmpdomain, sizeof tmpdomain);
- if (qp->q_domain != NULL)
- free(qp->q_domain);
- qp->q_domain = strdup(tmpdomain);
- if (qp->q_domain == NULL)
- panic(ENOMEM, "ns_resp: strdup failed");
-
- if ((qp->q_msg = (u_char *)malloc(PACKETSZ)) == NULL) {
- syslog(LOG_NOTICE, "sysquery: malloc failed");
- goto err2;
- }
- n = res_mkquery(opcode, dname, class,
- type, NULL, 0, NULL,
- qp->q_msg, PACKETSZ);
- if (n < 0) {
- syslog(LOG_INFO, "sysquery: res_mkquery(%s) failed", dname);
- goto err2;
- }
- qp->q_msglen = n;
- hp = (HEADER *) qp->q_msg;
- hp->id = qp->q_nsid = htons(nsid_next());
- hp->rd = (qp->q_fwd ? 1 : 0);
-
- /* First check for an already pending query for this data */
- for (oqp = nsqhead; oqp != QINFO_NULL; oqp = oqp->q_link) {
- if ((oqp != qp)
- && (oqp->q_msglen == qp->q_msglen)
- && bcmp((char *)oqp->q_msg+2,
- qp->q_msg+2,
- qp->q_msglen-2) == 0
- ) {
-#ifdef BIND_NOTIFY
- /* XXX - need fancier test to suppress duplicate
- * NOTIFYs to the same server (compare nss?)
- */
- if (opcode != NS_NOTIFY_OP)
-#endif /*BIND_NOTIFY*/
- {
- dprintf(3, (ddt, "sysquery: duplicate\n"));
- goto err2;
- }
- }
- }
-
- if (nss && nsc) {
- int i;
- struct qserv *qs;
-
- for (i = 0, qs = qp->q_addr;
- i < nsc;
- i++, qs++) {
- qs->ns_addr.sin_family = AF_INET;
- qs->ns_addr.sin_addr = nss[i];
- qs->ns_addr.sin_port = ns_port;
- qs->ns = NULL;
- qs->nsdata = NULL;
- qs->stime = tt;
- qs->nretry = 0;
- }
- qp->q_naddr = nsc;
- } else {
- fetch_a:
- count = nslookup(nsp, qp, dname, "sysquery");
- if (count <= 0) {
- if (count < 0) {
- syslog(LOG_INFO,
- "sysquery: nslookup reports danger (%s)",
- dname);
- goto err2;
- } else if (np && NAME(*np)[0] == '\0') {
- syslog(LOG_WARNING,
- "sysquery: no addrs found for root NS (%s)",
- dname);
- if (class == C_IN && !priming)
- needs_prime_cache = 1;
- goto err2;
- }
- if (np) {
- free_nsp(nsp);
- nsp[0] = NULL;
- np = np_parent(np);
- n = findns(&np, class, nsp, &count, 0);
- switch (n) {
- case NXDOMAIN: /*FALLTHROUGH*/
- case SERVFAIL:
- syslog(LOG_DEBUG,
- "sysquery: findns error (%d) on %s?",
- n, dname);
- goto err2;
- }
- goto fetch_a;
- }
- goto err2;
- }
- }
-
- schedretry(qp, retrytime(qp));
- if (qp->q_fwd == NULL)
- qp->q_addr[0].stime = tt; /* XXX - why not every? */
- nsa = Q_NEXTADDR(qp, 0);
-
- dprintf(1, (ddt,
- "sysquery: send -> %s dfd=%d nsid=%d id=%d retry=%ld\n",
- sin_ntoa(nsa), qp->q_dfd,
- ntohs(qp->q_nsid), ntohs(qp->q_id),
- (long)qp->q_time));
-#ifdef DEBUG
- if (debug >= 10)
- fp_nquery(qp->q_msg, qp->q_msglen, ddt);
-#endif
- if (sendto(qp->q_dfd, (char*)qp->q_msg, qp->q_msglen, 0,
- (struct sockaddr *)nsa,
- sizeof(struct sockaddr_in)) < 0) {
- if (!haveComplained((char*)nsa->sin_addr.s_addr, sendtoStr))
- syslog(LOG_INFO, "sysquery: sendto(%s): %m",
- sin_ntoa(nsa));
- nameserIncr(nsa->sin_addr, nssSendtoErr);
- }
- nameserIncr(nsa->sin_addr, nssSentSysQ);
- free_nsp(nsp);
- return (qp);
-}
-
-/*
- * Check the list of root servers after receiving a response
- * to a query for the root servers.
- */
-static int
-check_root()
-{
- register struct databuf *dp, *pdp;
- register struct namebuf *np;
- int count = 0;
-
- priming = 0;
- for (np = hashtab->h_tab[0]; np != NULL; np = np->n_next)
- if (NAME(*np)[0] == '\0')
- break;
- if (np == NULL) {
- syslog(LOG_NOTICE, "check_root: Can't find root!\n");
- return (0);
- }
- for (dp = np->n_data; dp != NULL; dp = dp->d_next)
- if (dp->d_type == T_NS)
- count++;
- dprintf(1, (ddt, "%d root servers\n", count));
- if (count < MINROOTS) {
- syslog(LOG_NOTICE,
- "check_root: %d root servers after query to root server < min",
- count);
- return (0);
- }
- pdp = NULL;
- dp = np->n_data;
- while (dp != NULL) {
- if (dp->d_type == T_NS && dp->d_zone == 0 &&
- dp->d_ttl < tt.tv_sec) {
- dprintf(1, (ddt, "deleting old root server '%s'\n",
- dp->d_data));
- dp = rm_datum(dp, np, pdp);
- /* SHOULD DELETE FROM HINTS ALSO */
- continue;
- }
- pdp = dp;
- dp = dp->d_next;
- }
- 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 int
-check_ns()
-{
- register struct databuf *dp, *tdp;
- register struct namebuf *np, *tnp;
- struct hashbuf *htp;
- char *dname;
- int found_arr;
- const char *fname;
- time_t curtime;
- int servers = 0, rrsets = 0;
-
- dprintf(2, (ddt, "check_ns()\n"));
-
- curtime = (u_int32_t) tt.tv_sec;
- for (np = hashtab->h_tab[0]; np != NULL; np = np->n_next) {
- 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;
- tnp = nlookup(dname, &htp, &fname, 0);
- if (tnp == NULL || fname != dname) {
- dprintf(3, (ddt,
- "check_ns: %s: not found %s %#lx\n",
- dname, fname, (u_long)tnp));
- sysquery(dname, dp->d_class, T_A, NULL,
- 0, QUERY);
- continue;
- }
- /* look for name server addresses */
- found_arr = 0;
- 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;
- if ((tdp->d_zone == 0) &&
- (tdp->d_ttl < curtime)) {
- dprintf(3, (ddt,
- "check_ns: stale entry '%s'\n",
- NAME(*tnp)));
- found_arr = 0;
- break;
- }
- 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's or an SOA
- * npp, class:
- * dname whose most enclosing NS is wanted
- * nsp, countp:
- * result array and count; array will also be NULL terminated
- * flag:
- * 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
- * *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)
- register struct namebuf **npp;
- int class;
- struct databuf **nsp;
- int *countp;
- int flag;
-{
- register struct namebuf *np = *npp;
- register struct databuf *dp;
- register struct databuf **nspp;
- struct hashbuf *htp;
-
- nsp[0] = NULL;
-
- if (priming && (np == NULL || NAME(*np)[0] == '\0'))
- htp = fcachetab;
- else
- htp = hashtab;
-
- try_again:
- if (htp == fcachetab && class == C_IN && !priming)
- needs_prime_cache = 1;
- if (np == NULL) {
- /* find the root */
- for (np = htp->h_tab[0]; np != NULL; np = np->n_next)
- if (NAME(*np)[0] == '\0')
- break;
- }
- while (np != NULL) {
- dprintf(5, (ddt, "findns: np %#lx '%s'\n",
- (u_long)np, NAME(*np)));
- /* Look first for SOA records. */
-#ifdef ADDAUTH
- if (!flag)
-#endif
- for (dp = np->n_data; dp != NULL; dp = dp->d_next) {
- if (dp->d_zone != 0 &&
-#ifdef PURGE_ZONE
- ((zones[dp->d_zone].z_type == Z_PRIMARY) ||
- (zones[dp->d_zone].z_type == Z_SECONDARY)) &&
-#endif
- match(dp, class, T_SOA)) {
- dprintf(3, (ddt, "findns: SOA found\n"));
- if (zones[dp->d_zone].z_flags & Z_AUTH) {
- *npp = np;
- nsp[0] = dp;
- nsp[1] = NULL;
- dp->d_rcnt++;
- return (NXDOMAIN);
- } else {
- /* XXX: zone isn't loaded but we're
- * primary or secondary for it.
- * should we fwd this?
- */
- return (SERVFAIL);
- }
- }
- }
-
- /* 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;
-#ifdef NCACHE
- if (dp->d_rcode)
- continue;
-#endif
- /*
- * Don't use records that may become invalid to
- * reference later when we do the rtt computation.
- * Never delete our safety-belt information!
- *
- * XXX: this is horribly bogus.
- */
- if ((dp->d_zone == 0) &&
- (dp->d_ttl < tt.tv_sec) &&
- !(dp->d_flags & DB_F_HINT)) {
- dprintf(1, (ddt, "findns: stale entry '%s'\n",
- NAME(*np)));
- /*
- * We may have already added NS databufs
- * and are going to throw them away. Fix
- * fix reference counts. We don't need
- * free() them here as we just got them
- * from the cache.
- */
- while (nspp > &nsp[0])
- (*--nspp)->d_rcnt--;
- nsp[0] = NULL;
- goto try_parent;
- }
- if (nspp < &nsp[NSMAX-1]) {
- *nspp++ = dp;
- dp->d_rcnt++;
- }
- }
-
- *countp = nspp - nsp;
- if (*countp > 0) {
- dprintf(3, (ddt, "findns: %d NS's added for '%s'\n",
- *countp, NAME(*np)));
- *nspp = NULL;
- *npp = np;
- return (OK); /* Success, got some NS's */
- }
- try_parent:
- np = np_parent(np);
- }
- if (htp == hashtab) {
- htp = fcachetab;
- goto try_again;
- }
- dprintf(1, (ddt, "findns: No root nameservers for class %s?\n",
- p_class(class)));
- if ((unsigned)class < MAXCLASS && norootlogged[class] == 0) {
- norootlogged[class] = 1;
- syslog(LOG_INFO, "No root nameservers for class %s\n",
- p_class(class));
- }
- return (SERVFAIL);
-}
-
-
-/*
- * Extract RR's from the given node that match class and type.
- * Return number of bytes added to response.
- * If no matching data is found, then 0 is returned.
- */
-int
-finddata(np, class, type, hp, dnamep, lenp, countp)
- struct namebuf *np;
- int class, type;
- register HEADER *hp;
- char **dnamep;
- int *lenp, *countp;
-{
- register struct databuf *dp;
- register char *cp;
- int buflen, n, count = 0;
-
- delete_stale(np);
-
-#ifdef ROUND_ROBIN
- if (type != T_ANY && type != T_PTR) {
- /* cycle order of RRs, for a load balancing effect... */
-
- register struct databuf **dpp;
-
- for (dpp = &np->n_data; dp = *dpp; dpp = &dp->d_next) {
- if (dp->d_next && wanted(dp, class, type)) {
- register struct databuf *lp;
-
- *dpp = lp = dp->d_next;
- dp->d_next = NULL;
-
- for (dpp = &lp->d_next;
- *dpp;
- dpp = &lp->d_next)
- lp = *dpp;
- *dpp = dp;
- break;
- }
- }
- }
-#endif /*ROUND_ROBIN*/
-
- buflen = *lenp;
-#ifdef DEBUG
- if (buflen > PACKETSZ)
- dprintf(1, (ddt, "finddata(): buflen=%d\n", buflen));
-#endif
- cp = ((char *)hp) + *countp;
- for (dp = np->n_data; dp != NULL; dp = dp->d_next) {
- if (!wanted(dp, class, type)) {
-#ifndef NCACHE /*if no negative caching then cname => nothing else*/
- if (type == T_CNAME && class == dp->d_class) {
- /* any data means no CNAME exists */
- *countp = 0;
- return 0;
- }
-#endif /*NCACHE*/
- 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 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
- * if we have a -ve $ed record, change the rcode on the
- * header to reflect that
- */
- if (dp->d_rcode == NOERROR_NODATA) {
- if (count != 0) {
- /*
- * This should not happen, yet it does...
- */
- syslog(LOG_INFO,
- "NODATA & data for \"%s\" type %d class %d",
- *dnamep, type, class);
- continue;
- }
- 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 */
- }
- }
- if (dp->d_rcode == NXDOMAIN) {
- if (count != 0) {
- /*
- * This should not happen, yet it might...
- */
- syslog(LOG_INFO,
- "NXDOMAIN & data for \"%s\" type %d class %d",
- *dnamep, type, class);
- continue;
- }
- hp->rcode = NXDOMAIN;
- if (dp->d_size == 0) { /* !RETURNSOA */
- *countp = 0;
- return 1; /* XXX - we have to report success */
- }
- }
-#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;
- return (*lenp - buflen);
- }
-
- cp += n;
- buflen -= n;
- count++;
-#ifdef notdef
- /* this isn't right for glue records, aa is set in ns_req */
- if (dp->d_zone &&
- (zones[dp->d_zone].z_flags & Z_AUTH) &&
- class != C_ANY)
- hp->aa = 1; /* XXX */
-#endif
- if (dp->d_type == T_CNAME) {
- /* 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) &&
- class != C_ANY) /* XXX */
- hp->aa = 1; /* XXX */
- }
- break;
- }
- }
- /*
- * Cache invalidate the other RR's of same type
- * if some have timed out
- */
- dprintf(3, (ddt, "finddata: added %d class %d type %d RRs\n",
- count, class, type));
- *countp = count;
- return (*lenp - buflen);
-}
-
-/*
- * 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);
- /* 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
- * -ve $ed RRs.
- */
- if (type == T_ANY && dp->d_rcode == NOERROR_NODATA)
- 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:
-#ifdef NCACHE
- if (dp->d_rcode != NOERROR_NODATA)
-#endif
- return (1);
-#ifdef NCACHE
- else
- break;
-#endif
- }
- /* OK, now look at the type of query. */
- switch (type) {
- case T_ANY:
- return (1);
-
- case T_MAILB:
- switch (dp->d_type) {
- case T_MR:
- case T_MB:
- case T_MG:
- case T_MINFO:
- return (1);
- }
- break;
-
- case T_AXFR:
- /* T_AXFR needs an authoritative SOA */
- if (dp->d_type == T_SOA && dp->d_zone != 0
- && (zones[dp->d_zone].z_flags & Z_AUTH))
- return (1);
- break;
- }
- return (0);
-}
-
-/*
- * Add RR entries from dpp array to a query/response.
- * Return the number of bytes added or negative the amount
- * added if truncation occured. Typically you are
- * adding NS records to a response.
- */
-int
-add_data(np, dpp, cp, buflen, countp)
- struct namebuf *np;
- struct databuf **dpp;
- register u_char *cp;
- int buflen, *countp;
-{
- register struct databuf *dp;
- char dname[MAXDNAME];
- register int n, bytes;
-
- bytes = *countp = 0;
- getname(np, dname, sizeof(dname));
- for (dp = *dpp++; dp != NULL; dp = *dpp++) {
- if (stale(dp))
- continue; /* ignore old cache entry */
-#ifdef NCACHE
- if (dp->d_rcode)
- continue;
-#endif
- if ((n = make_rr(dname, dp, cp, buflen, 1)) < 0)
- return (-bytes); /* Truncation */
- cp += n;
- buflen -= n;
- bytes += n;
- (*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;
- fs->fs_last = NULL;
- }
- dbl = (struct db_list *)malloc(sizeof(struct db_list));
- if (!dbl)
- panic(-1, "rrsetadd: out of memory");
- dbl->db_next = NULL;
- dbl->db_dp = dp;
- if (fs->fs_last == NULL)
- fs->fs_list = dbl;
- else
- fs->fs_last->db_next = dbl;
- fs->fs_last = dbl;
-}
-
-static int
-ttlcheck(name,dbl,update)
- char *name;
- struct db_list *dbl;
- int update;
-{
- 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) {
- /* we can't update zone data so return early */
- if (dp->d_zone != 0)
- return(0);
- 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;
- }
-
- /* update ttl if required */
- if (update) {
- for (dp = np->n_data; dp != NULL; dp = dp->d_next) {
- if (!match(dp, class, type))
- continue;
- if (dp->d_ttl > ttl)
- break;
- dp->d_ttl = ttl;
- fixttl(dp);
- }
- }
-
- 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, 0)) {
- 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 {
- if (n == 0)
- (void)ttlcheck(fs->fs_name, fs->fs_list, 1);
- 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);
-}
-
-static void
-free_flushset(flushset)
- struct flush_set *flushset;
-{
- struct flush_set *fs;
-
- for (fs = flushset; fs->fs_name != NULL; fs++)
- free(fs->fs_name);
- free((char *)flushset);
-}
-
-/*
- * This is best thought of as a "cache invalidate" function.
- * It is called whenever a piece of data is determined to have
- * become invalid either through a timeout or a validation
- * failure. It is better to have no information, than to
- * have partial information you pass off as complete.
- */
-void
-delete_all(np, class, type)
- register struct namebuf *np;
- int class, type;
-{
- register struct databuf *dp, *pdp;
-
- dprintf(3, (ddt, "delete_all(%#lx:\"%s\" %s %s)\n",
- (u_long)np, NAME(*np), p_class(class), p_type(type)));
- pdp = NULL;
- dp = np->n_data;
- while (dp != NULL) {
- if ((dp->d_zone == 0) && !(dp->d_flags & DB_F_HINT)
- && match(dp, class, type)) {
- dp = rm_datum(dp, np, pdp);
- continue;
- }
- pdp = dp;
- 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;
- }
- }
-}
-
-
-static void
-add_related_additional(name)
- char *name;
-{
- int i;
-
- if (num_related >= MAX_RELATED - 1)
- return;
- for (i = 0; i < num_related; i++)
- if (strcasecmp(name, related[i]) == 0) {
- free(name);
- return;
- }
- related[num_related++] = name;
-}
-
-static void
-free_related_additional() {
- int i;
-
- for (i = 0; i < num_related; i++)
- free(related[i]);
- num_related = 0;
-}
-
-static int
-related_additional(name)
- char *name;
-{
- int i;
-
- for (i = 0; i < num_related; i++)
- if (strcasecmp(name, related[i]) == 0)
- return (1);
- return (0);
-}
-
-static void
-maybe_free(tname)
- char **tname;
-{
- if (tname == NULL || *tname == NULL)
- return;
- free(*tname);
- *tname = NULL;
-}
OpenPOWER on IntegriCloud