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