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 + -
显示快捷键?