ns_resp.c

来自「<B>Digital的Unix操作系统VAX 4.2源码</B>」· C语言 代码 · 共 2,318 行 · 第 1/4 页

C
2,318
字号
#ifndef lintstatic	char	*sccsid = "@(#)ns_resp.c	4.1	(ULTRIX)	7/2/90";#endif lint/************************************************************************ *									* *			Copyright (c) 1984-1988 by			* *		Digital Equipment Corporation, Maynard, MA		* *			All rights reserved.				* *									* *   This software is furnished under a license and may be used and	* *   copied  only  in accordance with the terms of such license and	* *   with the  inclusion  of  the  above  copyright  notice.   This	* *   software  or  any  other copies thereof may not be provided or	* *   otherwise made available to any other person.  No title to and	* *   ownership of the software is hereby transferred.			* *									* *   This software is  derived  from  software  received  from  the	* *   University    of   California,   Berkeley,   and   from   Bell	* *   Laboratories.  Use, duplication, or disclosure is  subject  to	* *   restrictions  under  license  agreements  with  University  of	* *   California and with AT&T.						* *									* *   The information in this software is subject to change  without	* *   notice  and should not be construed as a commitment by Digital	* *   Equipment Corporation.						* *									* *   Digital assumes no responsibility for the use  or  reliability	* *   of its software on equipment which is not supplied by Digital.	* *									* ************************************************************************//* * Copyright (c) 1986 Regents of the University of California *	All Rights Reserved * static char sccsid[] = "@(#)ns_resp.c	4.50 (Berkeley) 4/7/88"; *//* * Modification History: * * 18-Jan-88	logcher *	Added BIND 4.7.2. *	Added BIND 4.7.2 with ifdef-ed MIT Hesiod support. * * 26-Jan-88	logcher *	Added BIND 4.7.3. * * 08-Mar-88	logcher *	Added bug fix to findns to check if not C_ANY class per bind *	mailing list dated 24-Nov-87 * * 08-Jun-88	logcher *	Added correct MIT Hesiod support. * * 11-Nov-88	logcher *	Updated with V3.0 changes. * * 17-May-89	logcher *	Added BIND 4.8 with MIT Hesiod support. */#include <stdio.h>#include <sys/param.h>#include <sys/time.h>#ifdef ULTRIXFUNC#include <sys/stat.h>#endif ULTRIXFUNC#include <sys/socket.h>#include <sys/file.h>#include <netinet/in.h>#include <syslog.h>#include <arpa/nameser.h>#include "ns.h"#include "db.h"extern	int	debug;extern	FILE	*ddt;extern	int errno;extern	u_char *dnptrs[];extern	time_t retrytime();extern	struct	fwdinfo *fwdtab;extern	struct	sockaddr_in from_addr;	/* Source addr of last packet */extern	int needs_prime_cache;extern	int priming;struct qinfo *sysquery();#ifdef AUTHENextern int netsafe;extern char *res_dotname_head();#endif AUTHEN/* begin KLUDGE */extern int forward_only;#ifndef AUTHENchar *res_dotname_head(str)     char *str;{	char *dest;	char *cpdest;	char *cpsrc;	if((dest = (char *)malloc(MAXDNAME)) == NULL)		return(NULL);	for(cpsrc = str, cpdest = dest; *cpsrc != '.' && *cpsrc != '\0';	    cpsrc++, cpdest++) {                *cpdest = *cpsrc;	}	*cpdest = '\0';	return(dest);}res_dotname_rmhead(str)	char **str;{        char *cp;	for(cp = *str; *cp != '.' && *cp != '\0'; cp++);	if (*cp == '\0')		*str = cp;	else		*str = cp + 1;}#endif AUTHEN/* end KLUDGE */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;	struct	databuf *nsp[NSMAX], **nspp;	int i, c, n, ancount, aucount, nscount, arcount;	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;	u_char newmsg[BUFSIZ];	u_char **dpp, *tp;	time_t rtrip;	struct hashbuf *htp;	struct namebuf *np;	struct netinfo *lp;	extern struct netinfo *local();	extern int nsid;	extern int addcount;#ifdef AUTHEN	int junk;	int tmp_ancount;	int tmp_aucount;	int tmp_arcount;	int ans_authentype = AUTH_NONE;	int ans_authenver = ZERO;	int read_cred = 0;	char ans_name[MAXDNAME];	char resp_name[MAXDNAME];	int new = 0;	int authen = 0;	int authen_count = 0;	u_char *old_tp;	u_char *authen_rr;	int authen_rrlen;	char *dname_authenrr;	int type_authenrr;	int class_authenrr;	char *krbnameptr;	char *dnameptr;	char msgbuf[BUFSIZ];	int msgbuflen;	u_char *tmpmsg;	int tmplen;	int authenlen;#endif AUTHEN#ifdef ULTRIXFUNC	struct fwdinfo *fwd;#endif ULTRIXFUNC#ifdef STATS	stats[S_RESPONSES].cnt++;#endif	hp = (HEADER *) msg;	if ((qp = qfindid(hp->id)) == NULL ) {#ifdef DEBUG		if (debug > 1)			fprintf(ddt,"DUP? dropped (id %d)\n", ntohs(hp->id));#endif#ifdef STATS		stats[S_DUPRESP].cnt++;#endif		return;	}#ifdef DEBUG	if (debug >= 2)		fprintf(ddt,"%s response nsid=%d id=%d\n",			qp->q_system ? "SYSTEM" : "USER",			ntohs(qp->q_nsid), ntohs(qp->q_id));#endif	/*	 *  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)	    || (hp->rcode == NXDOMAIN && !hp->aa)#ifdef AUTHEN	    ) {#else AUTHEN	    || hp->opcode != QUERY) {#endif AUTHEN#ifdef DEBUG		if (debug >= 2)			fprintf(ddt,"resp: error (ret %d, op %d), dropped\n",				hp->rcode, hp->opcode);#endif#ifdef STATS		stats[S_BADRESPONSES].cnt++;#endif		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 DEBUG		if (debug >= 3)			fprintf(ddt,"resp: leaving, UPDATE*\n");#endif		/* return code filled in by doupdate */		goto return_msg;	}#endif ALLOW_UPDATES#ifdef ULTRIXFUNC	/* If there are forwarders qp->q_fwd could be NILL even though		the answer came from a forwarder.  This occurs because		when retry() passes through the q_fwd list it could reach the		last, NILL, entry.  This causes a problem in the code below		because it assumes that if qp->q_fwd == 0 then there could		never be a successfull reply from a forwarder.  If the		response is from a forwarder it is assumed to come from a 		Martian.  The code below sets the value of qp->q_fwd to the		to the value of the forwarder that responded. */	for (fwd = qp->q_fwdorig; fwd; fwd = fwd->next)		if (bcmp((char *)&fwd->fwdaddr.sin_addr,				&from_addr.sin_addr,				sizeof(struct in_addr)) == 0)			qp->q_fwd = fwd;					#endif ULTRIXFUNC	/*	 * If we were using nameservers, find the qinfo pointer and update	 * the rtt and fact that we have called on this server before.	 */	if (qp->q_fwd == (struct fwdinfo *)0) {		struct timeval *stp;		for (n = 0, qs = qp->q_addr; n < qp->q_naddr; n++, qs++)			if (bcmp((char *)&qs->ns_addr.sin_addr,			    &from_addr.sin_addr, sizeof(struct in_addr)) == 0)				break;		if (n >= qp->q_naddr) {#ifdef DEBUG			if (debug)			    fprintf(ddt, "Response from unexpected source %s\n",				inet_ntoa(from_addr.sin_addr));#endif DEBUG#ifdef ULTRIXFUNC			/* this response did not come from a forwarder or from				a nameserver.  A martian really did respond. */			return;#else ULTRIXFUNC#ifdef STATS			stats[S_MARTIANS].cnt++;#endif			/* assume response to have come from last query */			qs = &qp->q_addr[qp->q_curaddr];#endif ULTRIXFUNC		}		stp = &qs->stime;		/* Handle response from a different (untried) ip address */		if (stp->tv_sec == 0) {			ns = qs->ns;			while (qs > qp->q_addr &&			    (qs->stime.tv_sec == 0 || qs->ns != ns))				qs--;			*stp = qs->stime;#ifdef DEBUG			if (debug)			    fprintf(ddt,			    "Response from unused address %s, assuming %s\n",				inet_ntoa(from_addr.sin_addr),				inet_ntoa(qs->ns_addr.sin_addr));#endif DEBUG		}		/* compute query round trip time */		rtrip = ((tt.tv_sec - stp->tv_sec) * 1000 +		    (tt.tv_usec - stp->tv_usec) / 1000);		#ifdef DEBUG		if (debug > 2)			fprintf(ddt,"stime %d/%d  now %d/%d rtt %d\n",			    stp->tv_sec, stp->tv_usec,			    tt.tv_sec, tt.tv_usec, rtrip);#endif		ns = qs->nsdata;		/*		 * Don't update nstime if this doesn't look		 * like an address databuf now.			XXX		 */		if (ns->d_type == T_A && ns->d_class == qs->ns->d_class) {			if (ns->d_nstime == 0)				ns->d_nstime = rtrip;			else				ns->d_nstime = ns->d_nstime * ALPHA +				    (1-ALPHA) * 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(qp->q_nusedns < NSMAX) {			qp->q_usedns[qp->q_nusedns++] = qs->ns;#ifdef DEBUG			if(debug > 1)			    fprintf(ddt, "NS #%d addr %s used, rtt %d\n",				n, inet_ntoa(qs->ns_addr.sin_addr),				ns->d_nstime);#endif DEBUG		}		/*		 * 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 == 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 = rtrip * BETA;			    else				ns2->d_nstime =				    ns2->d_nstime * BETA + (1-ALPHA) * rtrip;			    if (ns2->d_nstime > 1000000)				ns2->d_nstime = 1000000;			} else			    ns2->d_nstime = ns2->d_nstime * GAMMA;#ifdef DEBUG			if(debug > 1)			    fprintf(ddt, "NS #%d %s rtt now %d\n", n,				inet_ntoa(qs->ns_addr.sin_addr),				ns2->d_nstime);#endif DEBUG		}	}	/*	 * Skip query section	 */	addcount = 0;	cp = msg + sizeof(HEADER);	dpp = dnptrs;	*dpp++ = msg;	if ((*cp & INDIR_MASK) == 0)		*dpp++ = cp;	*dpp = NULL;	if (hp->qdcount) {#ifdef AUTHEN		dname_authenrr = resp_name;		n = dn_expand(msg, msg + msglen, cp, dname_authenrr, MAXDNAME);#else AUTHEN		n = dn_skipname(cp, msg + msglen);#endif AUTHEN	    	if (n <= 0)			goto formerr;		cp += n;		GETSHORT(type, cp);		GETSHORT(class, cp);#ifdef AUTHEN		type_authenrr = type;		class_authenrr = class;		if(hp->opcode == AQUERY)			cp += 2 * sizeof(u_short);#endif AUTHEN		if (cp - msg > msglen)			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;#ifdef DEBUG	if (debug >= 3)		fprintf(ddt,"resp: ancount %d, aucount %d, arcount %d\n",			ancount, aucount, arcount);#endif	/*	 *  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.)	 */#ifdef AUTHEN       	if(qp->q_authentype_out != AUTH_NONE)		authen = 0;		else		authen = 1;	authen_count = 0;	tmp_ancount = ancount;	tmp_aucount = aucount;	tmp_arcount = arcount;	if((c = aucount + arcount + ancount) > 0) {		do {			if (tp - msg >= msglen)				goto formerr;			old_tp = tp;			if(c == arcount + aucount + ancount &&					(aucount > 0 || ancount > 0)) {				dname_authenrr = ans_name;				n = dn_expand(msg, msg + msglen, tp,					      dname_authenrr, MAXDNAME);				if (n <= 0)					goto formerr;				tp += n;				GETSHORT(type_authenrr, tp);				GETSHORT(class_authenrr, tp);				tp = old_tp;			}						n = dn_skipname(tp, msg + msglen);			if (n <= 0)				goto formerr;			tp += n;  		/* name */			GETSHORT(i, tp);	/* type */			tp += sizeof(u_short);	/* class */			tp += sizeof(u_long);	/* ttl */			GETSHORT(count, tp); 	/* dlen */			if(i == T_CRED && tmp_ancount == 0 &&				tmp_aucount == 0 && !authen_count) {				authen_count++;				GETSHORT(ans_authentype, tp);				GETSHORT(ans_authenver, tp);				tp -= 2 * sizeof(u_short);				authen_rr = old_tp;				authen_rrlen = (tp - old_tp) + count;			}			if (tp - msg > msglen - count)				goto formerr;			tp += count;			if (ancount == tmp_ancount && tmp_ancount == 1 &&					i == T_CNAME) {				cname++;#ifdef DEBUG				if (debug)					fprintf(ddt,"CNAME - needs more processing\n");#endif				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 && aucount > 0 && i == T_NS)				nscount++;			if(tmp_ancount)				tmp_ancount--;			else if(tmp_aucount)				tmp_aucount--;			else if(tmp_arcount)				tmp_arcount--;		} while (--c > 0);		tp = cp;	}#else AUTHEN	if (ancount == 1 || (ancount == 0 && aucount > 0)) {		c = aucount;		do {			if (tp - msg >= msglen)				goto formerr;			n = dn_skipname(tp, msg + msglen);			if (n <= 0)				goto formerr;			tp += n;  		/* name */			GETSHORT(i, tp);	/* type */			tp += sizeof(u_short);	/* class */			tp += sizeof(u_long);	/* ttl */			GETSHORT(count, tp); 	/* dlen */			if (tp - msg > msglen - count)				goto formerr;			tp += count;			if (ancount && i == T_CNAME) {				cname++;#ifdef DEBUG				if (debug)					fprintf(ddt,"CNAME - needs more processing\n");#endif				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++;

⌨️ 快捷键说明

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