ns_req.c

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

C
1,919
字号
#ifndef lintstatic	char	*sccsid = "@(#)ns_req.c	4.4	(ULTRIX)	4/11/91";#endif lint/************************************************************************ *									* *			Copyright (c) 1984-1990 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_req.c	4.32 (Berkeley) 3/31/88"; *//* * Modification History: * * 18-Jan-88	logcher *	Added BIND 4.7.2. * * 26-Jan-88	logcher *	Added BIND 4.7.3. * * 09-Jun-88	logcher *	Removed incorrect comment regarding Hesiod integration. * * 11-Nov-88	logcher *	Updated with V3.0 changes. * * 18-May-89	logcher *	Added BIND 4.8. * * 09-Apr-90	sue *	Added to the if statement to allow a zone transfer of IN  *	information from a netsafe machine to a non-netsafe machine. * * 06-Aug-90	sue *	If a query was answered between the time of the initial connect *	for a zone transfer and the answer to the zone transfer, the *	zone transfer failed.  This produced spurious error messages in *	syslog.  The change is needed because the address of the *	clients that use TCP sockets was not correctly associated with *	the query from the client.  Changed all references of from_addr *	to from. */#include <stdio.h>#include <sys/param.h>#include <sys/uio.h>#include <sys/time.h>#ifdef ULTRIXFUNC#include <sys/stat.h>#endif ULTRIXFUNC#include <sys/socket.h>#include <netinet/in.h>#include <syslog.h>#include <sys/file.h>#include <arpa/nameser.h>#include "ns.h"#include "db.h"#ifdef AUTHEN#include <netdb.h>#endif AUTHEN#define NADDRECS	20extern	int	debug;extern	FILE	*ddt;struct addinfo {	char	*a_dname;		/* domain name */	u_short	a_class;		/* class for address */};struct	addinfo addinfo[NADDRECS];	/* additional info records */int	addcount;			/* number of names in addinfo */int	xfr_disabled = 0;		/* set to disable zone xfrs */int	needs_prime_cache = 0;		/* set if we need a priming */u_char	*dnptrs[20];		/* ptrs to dnames in message for dn_comp */extern time_t retrytime();extern struct qinfo *sysquery();extern char *localdomain;	/* XXX */extern int errno;#ifdef AUTHENextern struct netinfo netloop;extern int netsafe;extern int defauthentype;extern int defauthenver;extern u_long local_addr;extern char *res_dotname_head();#endif AUTHEN#ifdef ULTRIXFUNCextern struct	fwdinfo *fwdtab;extern int forward_only;extern int needreload;#endif ULTRIXFUNC/* * Process request using database; assemble and send response. * */ns_req(msg, msglen, buflen, qsp, from, dfd)	u_char *msg;	int msglen, buflen;	struct qstream *qsp;	struct sockaddr_in *from;	int dfd;{	register HEADER *hp;	register u_char *cp;	struct namebuf *np;	register struct databuf *dp;	struct hashbuf *htp;	struct netinfo *lp;	char *fname, *answers;	u_char *eom, *omsg;	char dnbuf[MAXDNAME], *dname;	u_char **dpp;	int n, class, type, count, foundname, founddata, omsglen, cname = 0;	u_short id;	struct databuf *nsp[NSMAX];	struct qinfo *qp;	extern struct qinfo *qhead;	extern struct netinfo *local();	extern int nsid;#ifdef ULTRIXFUNC	int findns_count;#endif ULTRIXFUNC#ifdef AUTHEN	char query_name[MAXDNAME];	char ans_name[MAXDNAME];	char temp_string[MAXDNAME];	int read_cred = 0;	u_char *ocp2;	char *dname_authenrr;	int type_authenrr;	int class_authenrr;	AUTH_DAT ns_ad;	int auth_type = AUTH_NONE;	int auth_version = ONE;	int query_to_aquery;	int cred_len;	char *dnptr;	int err;	int junk;	u_char *ocp;	int query_type;	char *auth_ptr;	struct sockaddr_in  addr;#endif AUTHEN#ifdef DEBUG	if (debug > 3) {		fprintf(ddt,"ns_req()\n");		fp_query(msg, ddt);	}#endif#ifdef ULTRIXFUNC	findns_count = 0;	for(n =0; n < NSMAX; n++)		nsp[n] = NULL;#endif ULTRIXFUNC	hp = (HEADER *) msg;	if (hp->qr) {		ns_resp(msg, msglen);		/* Now is a safe time for housekeeping */		if (needs_prime_cache)			prime_cache();		return;	}	hp->rcode = NOERROR;	cp = msg + sizeof(HEADER);	eom = msg + msglen;	dpp = dnptrs;	*dpp++ = msg;	addcount = 0;#ifdef AUTHEN	query_to_aquery = 0;	cred_len = 0;#endif AUTHEN	switch (hp->opcode) {#ifdef AUTHEN	case AQUERY:#endif AUTHEN	case QUERY:#ifdef STATS		stats[S_QUERIES].cnt++;#endif#ifdef AUTHEN		if (ntohs(hp->qdcount) != 1 ||		    hp->ancount || hp->nscount ||  (ntohs(hp->arcount) != 0 &&						   ntohs(hp->arcount) != 1)) {#else AUTHEN		if (ntohs(hp->qdcount) != 1 ||		    hp->ancount || hp->nscount || hp->arcount) {#endif AUTHEN#ifdef DEBUG			if (debug)			    fprintf(ddt,"FORMERR Query header counts wrong\n");#endif			hp->qdcount = 0;			hp->ancount = 0;			hp->nscount = 0;			hp->arcount = 0;			hp->rcode = FORMERR;			goto finish;		}		/*		 * Get domain name, class, and type.		 */		if ((*cp & INDIR_MASK) == 0)			*dpp++ = cp;	/* remember name for compression */		*dpp = NULL;#ifdef AUTHEN		if ((n = dn_expand(msg, eom, cp, query_name,				   sizeof(dnbuf))) < 0) {#else AUTHEN		if ((n = dn_expand(msg, eom, cp, dnbuf,				   sizeof(dnbuf))) < 0) {#endif AUTHEN#ifdef DEBUG			if (debug)			    fprintf(ddt,"FORMERR Query expand name failed\n");#endif			hp->rcode = FORMERR;			goto finish;		}		cp += n;		GETSHORT(type, cp);		GETSHORT(class, cp);#ifdef AUTHEN		dname_authenrr = query_name;		type_authenrr = type;		class_authenrr = class;		if (hp->opcode == AQUERY) {			GETSHORT(auth_type, cp);			GETSHORT(auth_version, cp);					if (auth_type == AUTH_KRB && auth_version == ONE) {				dnptr = query_name;				if(type != T_SOA && type != T_AXFR)					res_dotname_rmhead(&dnptr);				if (from->sin_addr.s_addr == 				    netloop.my_addr.s_addr)					addr.sin_addr.s_addr = local_addr;				else					addr = *from;				if((cred_len = res_rdl_krbcred(auth_version,						&ns_ad,						hp, cp, eom - cp,						dnptr, type, class,						&addr						)) < RET_OK) {					hp->rcode = AUTHENBAD;					goto finish;				}				read_cred = 1;				cp += cred_len;			} else {				hp->rcode = AUTHENBAD;				goto finish;			}		} else if(netsafe && class == C_HS) {			dnptr = query_name;			res_dotname_rmhead(&dnptr);			dnptr = res_dotname_head(dnptr);			if(from->sin_addr.s_addr == netloop.my_addr.s_addr			   && strcmp(dnptr, "auth")) {				eom += 2 * sizeof(u_short);				msglen += 2 * sizeof(u_short);				PUTSHORT(defauthentype, cp);				PUTSHORT(defauthenver, cp);						auth_type = defauthentype;				auth_version = defauthenver;				hp->opcode = AQUERY;				query_to_aquery = 1;				free(dnptr);			} else {				free(dnptr);				hp->rcode = AUTHENBAD;				goto finish;			}		}#endif AUTHEN		if (cp > eom) {#ifdef DEBUG			if (debug)			    fprintf(ddt,"FORMERR Query message length short\n");#endif#ifdef AUTHEN			cp -= cred_len;#endif AUTHEN			hp->rcode = FORMERR;			goto finish;		}#ifdef DEBUG		if (cp < eom)			if (debug > 5)			    fprintf(ddt,"message length > received message\n");#endif#ifdef AUTHEN		cp -= cred_len;		msglen -= cred_len;#endif AUTHEN#ifdef STATS		if ((type > T_ANY) || (type < 0))		    typestats[0]++;	/* Bad type */		else		    typestats[type]++;#endif		/*		 * Process query.		 */		if (type == T_AXFR) {			/* refuse request if not a TCP connection */			if (qsp == QSTREAM_NULL || xfr_disabled) {#ifdef DEBUG				if (debug)					fprintf(ddt,"T_AXFR via UDP refused\n");#endif				hp->rcode = REFUSED;				goto finish;			}			dnptrs[0] = NULL;	/* don't compress names */			hp->rd = 0;		/* recursion not possible */		}		buflen -= (int)(cp - msg);		count = 0;		foundname = 0;		founddata = 0;		dname = dnbuf;#ifdef AUTHEN		hp->arcount = 0;		bcopy(query_name, dnbuf, sizeof(dnbuf));		ocp = cp;#endif AUTHENtry_again:#ifdef DEBUG		if (debug)			fprintf(ddt,"req: nlookup(%s) id %d type=%d\n",			    dname, hp->id, type);#endif		htp = hashtab;		/* lookup relative to root */		if ((np = nlookup(dname, &htp, &fname, 0)) == NULL)			fname = "";#ifdef DEBUG		if (debug)			fprintf(ddt,"req: %s '%s' as '%s' (cname=%d)\n",				np == NULL ? "missed" : "found",				dname, fname, cname);#endif		/* START XXX */		/*		 * if nlookup failed to find address then		 *  see if there are any '.''s in the name		 * if not then add local domain name to the		 * name and try again.		 */		if (np == NULL && localdomain && index(dname, '.') == NULL) {			(void) strcat(dname,".");			(void) strcat(dname, localdomain);#ifdef DEBUG			if (debug)			    fprintf(ddt,"req: nlookup(%s) type=%d\n",				    dname, type);#endif			htp = hashtab;			np = nlookup(dname, &htp, &fname, 0);	        }		/* END XXX */		if (np == NULL || fname != dname)			goto fetchns;		foundname++;		answers = (char *)cp;		count = cp - msg;#ifdef AUTHEN		if(cname) {			n = finddata(np, class, type, hp, &dname,				&buflen, &count, auth_type, auth_version,				&junk, &junk);		} else {			dname_authenrr = ans_name;			strcpy(dname_authenrr, dname);			n = finddata(np, class, type, hp, &dname,				&buflen, &count, auth_type, auth_version,				&type_authenrr, &class_authenrr);		}#else AUTHEN		n = finddata(np, class, type, hp, &dname, &buflen, &count);#endif AUTHEN		if (n == 0)			goto fetchns;		/* NO data available */		cp += n;		buflen -= n;		msglen += n;		hp->ancount += count;		if (strcmp(fname,dname) && type != T_CNAME && type != T_ANY) {			cname++;			goto try_again;		}		founddata = 1;#ifdef DEBUG		if (debug >= 3) {		    fprintf(ddt,"req: foundname = %d count = %d ", foundname, count);		    fprintf(ddt,"founddata = %d cname = %d\n",founddata, cname);		}#endif		if ((lp = local(from)) != NULL) 			sort_response(answers, count, lp, cp);		if (type == T_AXFR) {			hp->ancount = htons(hp->ancount);#ifdef AUTHEN			if(hp->opcode == AQUERY) {				hp->arcount = htons(1 + ntohs(hp->arcount));				if((cred_len = res_mks_krbcred(						auth_version, "", "",						&ns_ad, hp, cp,						buflen, dname_authenrr,						type_authenrr,						class_authenrr))						< RET_OK) {					hp->rcode = AUTHENBAD;					cp = ocp;					dname_authenrr = query_name;					type_authenrr = type;					class_authenrr = class;					hp->ancount = 0;					hp->nscount = 0;					hp->arcount = 0;					goto finish;				} else {					cp += cred_len;				}			} else				/*				 * If not AQUERY and netsafe is on,				 * reject class Hesiod xfers				 */				if(netsafe && class != C_IN) {					hp->rcode = AUTHEN;					dname_authenrr = query_name;					type_authenrr = type;					class_authenrr = class;					hp->ancount = 0;					hp->nscount = 0;					hp->arcount = 0;					goto finish;				}						startxfr(qsp, np,				 hp->opcode == AQUERY ?  1 : 0,				 &ns_ad,				 auth_type,				 auth_version,				 msg,				 cp - msg, cp - cred_len, dname_authenrr,				 type_authenrr, class_authenrr);#else			startxfr(qsp, np, msg, cp - msg);#endif AUTHEN			return;		}#ifdef notdef		/*		 * If we found an authoritative answer,		 * we're done.		 */		if (hp->aa)			goto finish;#endiffetchns:		findns_count++;		/*	 	 * Look for name servers to refer to and fill in the authority	 	 * section or record the address for forwarding the query	 	 * (recursion desired).	 	 */		switch (findns(&np, class, nsp, &count)) {		case NXDOMAIN:			if (!foundname)				hp->rcode = NXDOMAIN;#ifdef DEBUG			if (debug >= 3)				fprintf(ddt,"req: leaving (%s, rcode %d)\n",					dname, hp->rcode);#endif			if (class != C_ANY) {				hp->aa = 1;				/*				 * should return SOA if founddata == 0,				 * but old named's are confused by an SOA				 * in the auth. section if there's no error.				 */				if (foundname == 0 && np) {				    n = doaddauth(hp, cp, buflen, np, nsp[0]);				    cp += n;				    buflen -= n;#ifdef AUTHEN				    dname_authenrr = ans_name;				    getname(np, ans_name, sizeof(ans_name));				    type_authenrr = (int)nsp[0]->d_type;				    class_authenrr = (int)nsp[0]->d_class;#endif AUTHEN				}			}			goto finish;		case SERVFAIL:#ifdef ULTRIXFUNC			if(forward_only && fwdtab)				break;			hp->rcode = SERVFAIL;			goto finish;#else ULTRIXFUNC			hp->rcode = SERVFAIL;			goto finish;#endif ULTRIXFUNC		}		/*		 *  If we successfully found the answer in the cache		 *  or this is not a recursive query, then add the		 *  nameserver references here and return.		 */		if (founddata || (!hp->rd)) {			n = add_data(np, nsp, cp, buflen);			if (n < 0) {				hp->tc = 1;				n = (-n);			}			cp += n;			buflen -= n;			hp->nscount = htons((u_short)count);			goto finish;		}				/*		 *  At this point, we don't have the answer, but we do		 *  have some NS's to try.  If the user would like us		 *  to recurse, create the initial query.  If a cname		 *  is involved, we need to build a new query and save		 *  the old one in cmsg/cmsglen.		 */		if (cname) {			omsg = (u_char *)malloc((unsigned)msglen);			if (omsg == (u_char *)NULL) {#ifdef DEBUG				if (debug)			        	fprintf(ddt,"ns_req: malloc fail\n");#endif				syslog(LOG_ERR, "ns_req: Out Of Memory");				hp->rcode = SERVFAIL;				break;			}			id = hp->id;			hp->ancount = htons(hp->ancount);			bcopy(msg, omsg, omsglen = msglen);#ifdef AUTHEN			msglen = res_mkquery(hp->opcode, dname, class, type,				(char *)NULL, 0, NULL, msg, msglen+buflen);#else AUTHEN			msglen = res_mkquery(QUERY, dname, class, type,				(char *)NULL, 0, NULL, msg, msglen+buflen);#endif AUTHEN		}#ifdef AUTHEN  		n = ns_forw(nsp, msg, msglen, from, qsp, dfd, &qp,			    ((query_to_aquery == 1) ? QUERY: hp->opcode),			    ((query_to_aquery == 1) ? AQUERY: hp->opcode),			    auth_type, auth_version, auth_type, auth_version,			    ns_ad, dname, type, class);#else AUTHEN		n = ns_forw(nsp, msg, msglen, from, qsp, dfd, &qp);#endif AUTHEN		if (n != FW_OK && cname)			free(omsg);		switch (n) {		case FW_OK:			if (cname) {				qp->q_cname++;				qp->q_cmsg = (char *)omsg;				qp->q_cmsglen = omsglen;				qp->q_id = id;			}			break;		case FW_DUP:			break;		/* Duplicate request dropped */

⌨️ 快捷键说明

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