⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ns_resp.c

📁 早期freebsd实现
💻 C
📖 第 1 页 / 共 4 页
字号:
#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 4.9.1.10 1993/12/06 00:43:02 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. * - * --Copyright-- */#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 void		check_root __P((void)),			check_ns __P((void));static int		norootlogged[MAXCLASS];static char		skipnameFailedAnswer[] = "skipname failed in answer",			skipnameFailedQuery[] =	"skipname failed in query",			outofDataQuery[] =	"ran out of data in query",			outofDataAnswer[] =	"ran out of data in answer",			dlenOverrunAnswer[] =	"dlen overrun in answer",			dlenUnderrunAnswer[] =	"dlen underrun in answer",			outofDataFinal[] =	"out of data in final pass",			outofDataAFinal[] =	"out of data after final pass";voidns_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;#ifdef VALIDATE	register u_char *tempcp;	struct sockaddr_in *server = &from_addr;	int *validatelist;	int lesscount;#endif	struct	databuf *nsp[NSMAX], **nspp;	int i, c, n, ancount, aucount, nscount, arcount;	int old_ancount;	int type, class, dbflags;	int cname = 0; /* flag for processing cname response */	int count, founddata, foundname;	int buflen;	int newmsglen;	char name[MAXDNAME], *dname;	char *fname;	char *formerrmsg = "brain damage";	u_char newmsg[BUFSIZ];	u_char **dpp, *tp;	time_t rtrip;	struct hashbuf *htp;	struct namebuf *np;	struct netinfo *lp;	struct fwdinfo *fwd;	stats[S_RESPONSES].cnt++;#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)));		stats[S_DUPRESP].cnt++;		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 bad responses from servers.	 *  Several possibilities come to mind:	 *	The server is sick and returns SERVFAIL	 *	The server returns some garbage opcode (its sick)	 *	The server can't understand our query and return FORMERR	 *  In all these cases, we simply drop the packet and force	 *  a retry.  This will make him look bad due to unresponsiveness.	 *  Be sure not to include authoritative NXDOMAIN	 */	if ((hp->rcode != NOERROR && hp->rcode != NXDOMAIN)#ifndef NCACHE	    || (hp->rcode == NXDOMAIN && !hp->aa) /* must accept this one if						   * we allow negative caching						   */#endif /*NCACHE*/	    || hp->opcode != QUERY) {		dprintf(2, (ddt, "resp: error (ret %d, op %d), dropped\n",			    hp->rcode, hp->opcode));		stats[S_BADRESPONSES].cnt++;		return;	}#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		 */		doupdate(qp->q_msg, qp->q_msglen, qp->q_msg + sizeof(HEADER),			 0, (struct databuf *)0, 0#ifdef CRED			 , DB_C_AUTH#endif			 );		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	 * 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;		}	}	/*	 * If we were using nameservers, 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; n < qp->q_naddr; n++, qs++)			if (qs->ns_addr.sin_addr.s_addr ==			    from_addr.sin_addr.s_addr)				break;		if (n >= qp->q_naddr) {			dprintf(1, (ddt,				   "Response from unexpected source [%s].%d\n",				    inet_ntoa(from_addr.sin_addr),				    ntohs(from_addr.sin_port)));			stats[S_MARTIANS].cnt++;			/* 			 * 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",				    inet_ntoa(from_addr.sin_addr),				    inet_ntoa(qs->ns_addr.sin_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 %d/%d  now %d/%d rtt %d\n",			    stp->tv_sec, stp->tv_usec,			    tt.tv_sec, tt.tv_usec, 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)){			if (ns->d_nstime == 0)				ns->d_nstime = (u_int32_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;		}		/*		 * 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, inet_ntoa(qs->ns_addr.sin_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; n < qp->q_naddr; n++, qs++) {			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)				ns2->d_nstime = (u_int32_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;			} else			    ns2->d_nstime = (u_int32_t)(ns2->d_nstime * GAMMA);			dprintf(2, (ddt, "NS #%d [%s] rtt now %d\n", n,				    inet_ntoa(qs->ns_addr.sin_addr),				    ns2->d_nstime));		}	}	/*	 * Skip query section	 */	free_addinfo();		/* sets addcount to zero */	cp = msg + sizeof(HEADER);	dpp = dnptrs;	*dpp++ = msg;	if ((*cp & INDIR_MASK) == 0)		*dpp++ = cp;	*dpp = NULL;	if (hp->qdcount) {		n = dn_skipname(cp, msg + msglen);	    	if (n <= 0) {			formerrmsg = skipnameFailedQuery;			goto formerr;		}		cp += n;		GETSHORT(type, cp);		GETSHORT(class, cp);		if (cp - msg > msglen) {			formerrmsg = outofDataQuery;			goto formerr;		}	}	/*	 * Save answers, authority, and additional records for future use.	 */	ancount = ntohs(hp->ancount);	aucount = ntohs(hp->nscount);	arcount = ntohs(hp->arcount);	nscount = 0;	tp = cp;	dprintf(3, (ddt, "resp: ancount %d, aucount %d, arcount %d\n",		    ancount, aucount, arcount));	/*	 *  If there's an answer, check if it's a CNAME response;	 *  if no answer but aucount > 0, see if there is an NS	 *  or just an SOA.  (NOTE: ancount might be 1 with a CNAME,	 *  and NS records may still be in the authority section;	 *  we don't bother counting them, as we only use nscount	 *  if ancount == 0.)	 */	if (ancount == 1 || (ancount == 0 && aucount > 0)) {		c = aucount;		do {			if (tp - msg >= msglen) {				formerrmsg = outofDataAnswer;				goto formerr;			}			n = dn_skipname(tp, msg + msglen);			if (n <= 0) {				formerrmsg = skipnameFailedAnswer;				goto formerr;			}			tp += n;  		/* name */			GETSHORT(i, tp);	/* type */			tp += sizeof(u_int16_t); /* class */			tp += sizeof(u_int32_t); /* ttl */			GETSHORT(count, tp); 	/* dlen */			if (tp - msg > msglen - count) {				formerrmsg = dlenOverrunAnswer;				goto formerr;			}			tp += count;			if (ancount && i == T_CNAME) {				cname++;				dprintf(1,					(ddt,					 "CNAME - needs more processing\n"					 )					);				if (!qp->q_cmsglen) {					qp->q_cmsg = qp->q_msg;					qp->q_cmsglen = qp->q_msglen;					qp->q_msg = NULL;					qp->q_msglen = 0;				}			}			/*			 * See if authority record is a nameserver.			 */			if (ancount == 0 && i == T_NS)				nscount++;		} while (--c > 0);		tp = cp;	}	if (qp->q_flags & Q_ZSERIAL) {		if ((hp->aa)		    && (ancount != 0)		    && (hp->rcode == NOERROR)		    && (type == T_SOA)		    && ((class == C_IN) || (class == C_HS))		    ) {		/* XXX - should check name, too */			int n;			u_int16_t dlen;			u_int32_t serial;			u_char *tp = cp;			if (0 >= (n = dn_skipname(tp, msg + msglen))) {				formerrmsg = skipnameFailedAnswer;				goto formerr;			}			tp += n  		/* name */			   + sizeof(u_int16_t)  /* type */			   + sizeof(u_int16_t)  /* class */			   + sizeof(u_int32_t); /* ttl */			GETSHORT(dlen, tp); 	/* dlen */			if (dlen < (5 * sizeof(u_int32_t))) {				formerrmsg = dlenUnderrunAnswer;				goto formerr;			}			if (0 >= (n = dn_skipname(tp, msg + msglen))) {				formerrmsg = skipnameFailedAnswer;				goto formerr;			}			tp += n;  		/* mname */			if (0 >= (n = dn_skipname(tp, msg + msglen))) {				formerrmsg = skipnameFailedAnswer;				goto formerr;			}			tp += n;  		/* rname */			GETLONG(serial, tp);			qserial_answer(qp, serial);		}		qremove(qp);		return;	}	/*	 * Add the info received in the response to the Data Base	 */	c = ancount + aucount + arcount;#ifdef NCACHE	/* -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;	} /*should ideally validate message before returning it*/#endif /*NCACHE*/#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 (hp->qdcount && 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 */	nspp = nsp;	if (qp->q_flags & Q_SYSTEM)		dbflags = DB_NOTAUTH | DB_NODATA;	else		dbflags = DB_NOTAUTH | DB_NODATA | DB_NOHINTS;	count = c;	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 */	}#ifdef VALIDATE	tempcp = cp;	validatelist = (int *)malloc(count*sizeof(int));	lesscount = 0; /*initialize*/	old_ancount = ancount;	for (i = 0; i < count; i++) {		int VCode;		if (tempcp >= msg + msglen) {			formerrmsg = outofDataFinal;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -