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

📄 ns_req.c

📁 早期freebsd实现
💻 C
📖 第 1 页 / 共 3 页
字号:
#if !defined(lint) && !defined(SABER)static char sccsid[] = "@(#)ns_req.c	4.47 (Berkeley) 7/1/91";static char rcsid[] = "$Id: ns_req.c,v 4.9.1.7 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/uio.h>#include <sys/file.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/nameser.h>#include <arpa/inet.h>#include <fcntl.h>#include <syslog.h>#include <errno.h>#include <stdio.h>#include <resolv.h>#include "named.h"struct addinfo {	char	*a_dname;		/* domain name */	u_int	a_class;		/* class for address */};enum req_action { Finish, Refuse, Return };static enum req_action	req_query __P((HEADER *hp, u_char **cpp, u_char *eom,				       struct qstream *qsp,				       int *buflenp, int *msglenp,				       u_char *msg, int dfd,				       struct sockaddr_in *from)),			req_iquery __P((HEADER *hp, u_char **cpp, u_char *eom,					int *buflenp, u_char *msg));static void		fwritemsg __P((FILE *, char *, int)),			doaxfr __P((struct namebuf *, FILE *,				    struct namebuf *, int)),			startxfr __P((struct qstream *, struct namebuf *,				      char *, int, int)),			printSOAdata __P((struct databuf));#ifdef ALLOW_UPDATESstatic int		InitDynUpdate __P((register HEADER *hp,					   char *msg,					   int msglen,					   u_char *startcp,					   struct sockaddr_in *from,					   struct qstream *qsp,					   int dfd));#endif#ifdef SECURE_ZONESextern struct netinfo *net_on_netlist();#endifstatic struct addinfo	addinfo[NADDRECS];static void		addname __P((char *, u_int16_t));/* * Process request using database; assemble and send response. */voidns_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 = (HEADER *) msg;	u_char *cp, *eom;	enum req_action action;#ifdef DEBUG	if (debug > 3) {		fprintf(ddt, "ns_req(from=[%s].%d)\n",			inet_ntoa(from->sin_addr), ntohs(from->sin_port));		fp_query((char *)msg, ddt);	}#endif	/*	 * XXX - this decision should be made by our caller, not by us.	 */	if (hp->qr) {		ns_resp(msg, msglen);		/* Now is a safe time for housekeeping */		if (needs_prime_cache)			prime_cache();		return;	}	/* its a query and these bits have no business	 * being set. will later simplify work if we can	 * safely assume these are always 0 when a query	 * comes in	 */	hp->aa = hp->ra = 0;	hp->rcode = NOERROR;	cp = msg + sizeof(HEADER);	eom = msg + msglen;	dnptrs[0] = msg;	dnptrs[1] = NULL;	free_addinfo();	/* sets addcount to zero */	dnptrs[0] = NULL;	switch (hp->opcode) {	case QUERY:		action = req_query(hp, &cp, eom, qsp,				   &buflen, &msglen,				   msg, dfd, from);		break;#if INVQ	case IQUERY:		action = req_iquery(hp, &cp, eom, &buflen, msg);		break;#endif#ifdef ALLOW_UPDATES#define FORWARDED 1000/* * In a sense the following constant should be defined in <arpa/nameser.h>, * since it is returned here in place of a response code if the update was * forwarded, and the response codes are defined in nameser.h.  On the other * hand, though, this constant is only seen in this file.  The assumption * here is that none of the other return codes equals this one (a good * assumption, since they only occupy 4 bits over-the-wire) */        /* Call InitDynUpdate for all dynamic update requests */        case UPDATEM:        case UPDATEMA:        case UPDATED:        case UPDATEDA:        case UPDATEA:                n = InitDynUpdate(hp, msg, msglen, cp, from, qsp, dfd);                if (n == FORWARDED) {			/* Return directly because InitDynUpdate			 * forwarded the query to the primary, so we			 * will send response later			 */			action = Return;		} else {			/* Either sucessful primary update or failure;			 * return response code to client			 */			action = Finish;		}#endif /* ALLOW_UPDATES */	case ZONEREF:		dprintf(1, (ddt, "Refresh Zone\n"));		/*FALLTHROUGH*/	default:		dprintf(1, (ddt, "ns_req: Opcode %d not implemented\n",			    hp->opcode));		/* XXX - should syslog, limited by haveComplained */		hp->qdcount = 0;		hp->ancount = 0;		hp->nscount = 0;		hp->arcount = 0;		hp->rcode = NOTIMP;		action = Finish;	}	/*	 * vector via internal opcode.  (yes, it was even uglier before.)	 */	switch (action) {	case Return:		return;	case Refuse:		hp->rcode = REFUSED;		/*FALLTHROUGH*/	case Finish:		/* rest of the function handles this case */		break;	default:		syslog(LOG_CRIT, "bad action variable in ns_req() -- %d",		       (int) action);		return;	/* XXX - should really exit here */	}	/*	 * update statistics	 */	switch (hp->rcode) {	case NOERROR:		stats[S_RESPOK].cnt++;		break;	case FORMERR:		stats[S_RESPFORMERR].cnt++;		break;#ifdef NCACHE	case NXDOMAIN:		stats[S_RESPNXDOMAIN].cnt++;		break;#endif	default:		stats[S_RESPFAIL].cnt++;		break;	}	/*	 * apply final polish	 */	hp->qr = 1;		/* set Response flag */	if (NoRecurse)		hp->ra = 0;	/* No recursion; maybe we're a root server */	else		hp->ra = 1;	/* Recursion is Available */	hp->ancount = htons(hp->ancount);	if (addcount) {		int n = doaddinfo(hp, cp, buflen);		cp += n;		buflen -= n;	}	dprintf(1, (ddt, "ns_req: answer -> [%s].%d fd=%d id=%d %s\n",		    inet_ntoa(from->sin_addr), 		    ntohs(from->sin_port),		    (qsp == QSTREAM_NULL) ?dfd :qsp->s_rfd, 		    ntohs(hp->id), local(from) == NULL ? "Remote" : "Local"));#ifdef DEBUG	if (debug >= 10)		fp_query((char *)msg, ddt);#endif	if (qsp == QSTREAM_NULL) {		if (sendto(dfd, msg, cp - msg, 0,			   (struct sockaddr *)from,			   sizeof(*from)) < 0) {			dprintf(1, (ddt,				    "error returning msg errno=%d\n", errno));		}		stats[S_OUTPKTS].cnt++;	} else {		(void) writemsg(qsp->s_rfd, msg, cp - msg);		sq_done(qsp);	}	if (needs_prime_cache) {		prime_cache();		/* Now is a safe time */	}}static enum req_actionreq_query(hp, cpp, eom, qsp, buflenp, msglenp, msg, dfd, from)	HEADER *hp;	u_char **cpp;	u_char *eom;	struct qstream *qsp;	u_char *msg;	int *buflenp, *msglenp, dfd;	struct sockaddr_in *from;{	int n, class, type, count, foundname, founddata, omsglen, cname;	u_int16_t id;	u_char **dpp, *omsg;	char dnbuf[MAXDNAME], *dname, *fname, *answers;	struct hashbuf *htp;	struct databuf *nsp[NSMAX];	struct namebuf *np;	struct qinfo *qp;	struct netinfo *lp;	stats[S_QUERIES].cnt++;#ifdef DATUMREFCNT	nsp[0] = NULL;#endif	dpp = dnptrs;	*dpp++ = msg;	*dpp = NULL;	/* for early returns (thanks, kre) */	/* valid queries have one question and zero answers */	if ((ntohs(hp->qdcount) != 1)	    || hp->ancount	    || hp->nscount	    || hp->arcount) {		dprintf(1, (ddt, "FORMERR Query header counts wrong\n"));		hp->qdcount = 0;		hp->ancount = 0;		hp->nscount = 0;		hp->arcount = 0;		hp->rcode = FORMERR;		return Finish;	}	/*	 * Get domain name, class, and type.	 */	if ((**cpp & INDIR_MASK) == 0) {		*dpp++ = *cpp;	/* remember name for compression */	}	*dpp = NULL;	n = dn_expand(msg, eom, *cpp, (u_char *)dnbuf, sizeof(dnbuf));	if (n < 0) {		dprintf(1, (ddt, "FORMERR Query expand name failed\n"));		hp->rcode = FORMERR;		return Finish;	}	*cpp += n;	GETSHORT(type, *cpp);	GETSHORT(class, *cpp);	if (*cpp > eom) {		dprintf(1, (ddt, "FORMERR Query message length short\n"));		hp->rcode = FORMERR;		return Finish;	}	if (*cpp < eom) {		dprintf(6, (ddt,"message length > received message\n"));		*msglenp = *cpp - msg;	}	if ((type > T_ANY) || (type < 0)) {		typestats[0]++;	/* Bad type */	} else {		typestats[type]++;	}	/*	 * Process query.	 */	if (type == T_AXFR) {		/* refuse request if not a TCP connection */		if (qsp == QSTREAM_NULL) {			dprintf(1, (ddt, "T_AXFR via UDP refused\n"));			return Refuse;		}#ifdef XFRNETS		if (xfrnets) {			/* if xfrnets was specified, peer address			 * must be on it.  should probably allow			 * for negation some day.			 */			if (!net_on_netlist(from->sin_addr, xfrnets)) {				syslog(LOG_INFO,				       "dangerous AXFR addr: [%s].%u",				       inet_ntoa(from->sin_addr),				       ntohs(from->sin_port));				return Refuse;			}		}#endif /*XFRNETS*/		dnptrs[0] = NULL;	/* don't compress names */		hp->rd = 0;		/* recursion not possible */	}	*buflenp -= *msglenp;	count = 0;	foundname = 0;	founddata = 0;	dname = dnbuf;	cname = 0;#ifdef QRYLOG	if (qrylog) {		syslog(LOG_INFO, "XX /%s/%s/%s",		       inet_ntoa(from->sin_addr), 		       (dname[0] == '\0') ?"." :dname, 		       p_type(type));	}#endif /*QRYLOG*/try_again:	dprintf(1, (ddt, "req: nlookup(%s) id %d type=%d\n",		    dname, hp->id, type));	htp = hashtab;		/* lookup relative to root */	if ((np = nlookup(dname, &htp, &fname, 0)) == NULL)		fname = "";	dprintf(1, (ddt, "req: %s '%s' as '%s' (cname=%d)\n",		    np == NULL ? "missed" : "found",		    dname, fname, cname));#ifdef LOCALDOM	/*	 * if nlookup failed to find the name 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 && localdomain && !strchr(dname, '.')) {		(void) strcat(dname, ".");		(void) strcat(dname, localdomain);		dprintf(1, (ddt,"req: nlookup(%s) type=%d\n", dname, type));		htp = hashtab;		np = nlookup(dname, &htp, &fname, 0);        }#endif /*LOCALDOM*/#ifdef YPKLUDGE	/* Some braindamaged resolver software will not 	   recognize internet addresses in dot notation and 	   send out address  queries for "names" such as 	   128.93.8.1.  This kludge will prevent those 	   from flooding higher level servers.	   We simply claim to be authoritative and that	   the domain doesn't exist.	   Note that we could return the address but we	   don't do that in order to encourage that broken	   software is fixed.	*/	if (!np && type == T_A && class == C_IN && dname) {		struct sockaddr_in ina;		if (inet_aton(dname, &ina)) {			hp->rcode = NXDOMAIN;			hp->aa = 1;			dprintf(3, (ddt, "ypkludge: hit as '%s'\n", dname));			return Finish;		}	}#endif /*YPKLUDGE*/	if ((!np) || (fname != dname))		goto fetchns;#ifdef SECURE_ZONES	if (np->n_data) {		struct zoneinfo *zp;		zp = &zones[np->n_data->d_zone];		if (zp->secure_nets		    && !net_on_netlist(from->sin_addr, zp->secure_nets)) {			dprintf(1, (ddt,				    "REFUSED Unauthorized request from %s\n", 				    inet_ntoa(from->sin_addr)));			syslog(LOG_INFO, "Unauthorized request %s from %s",			       dname, inet_ntoa(from->sin_addr));			return Refuse;		}	}#endif	foundname++;	answers = (char *)*cpp;	count = *cpp - msg;#ifdef NCACHE	/* if this is a NXDOMAIN, will have only one databuf	 * whose d_rcode field will be NXDOMAIN. So we can go home	 * right here. -ve $ing: anant@isi.edu	 */	if (np->n_data != NULL && !stale(np->n_data)) {		if (np->n_data->d_rcode == NXDOMAIN) {			hp->rcode = NXDOMAIN;			founddata = 1;			goto fetchns;		}	}	/* if not NXDOMAIN, the NOERROR_NODATA record might be	 * anywhere in the chain. have to go through the grind.	 * (anant@isi.edu)	 */#endif /*NCACHE*/	n = finddata(np, class, type, hp, &dname, buflenp, &count);	if (n == 0) {		/* NO data available.  Refuse AXFR requests, or		 * look for better servers for other requests.		 */		if (type == T_AXFR) {			dprintf(1, (ddt, "T_AXFR refused: no data\n"));			return Refuse;		} else {			goto fetchns;		}	}#ifdef NCACHE	if (hp->rcode == NOERROR_NODATA) {		hp->rcode = NOERROR;		founddata = 1;		return Finish;	}#endif	*cpp += n;	*buflenp -= n;	*msglenp += n;	hp->ancount += count;	if (fname != dname && type != T_CNAME && type != T_ANY) {		if (cname++ >= MAXCNAMES) {			dprintf(3, (ddt,				    "resp: leaving, MAXCNAMES exceeded\n"));			hp->rcode = SERVFAIL;			return Finish;		}		goto try_again;	}	founddata = 1;	dprintf(3, (ddt,		    "req: foundname=%d, count=%d, founddata=%d, cname=%d\n",		    foundname, count, founddata, cname));	if ((lp = local(from)) != NULL) 		sort_response(answers, count, lp, *cpp);	if (type == T_AXFR) {		hp->ancount = htons(hp->ancount);		startxfr(qsp, np, (char *)msg, *cpp - msg, class);		sqrm(qsp);		return Return;	}#ifdef notdef	/*	 * If we found an authoritative answer,	 * we're done.	 */	if (hp->aa) {		return Finish;	}#endiffetchns:	/*

⌨️ 快捷键说明

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