📄 ns_req.c
字号:
* Look for name servers to refer to and fill in the authority * section or record the address for forwarding the query * (recursion desired). */#ifdef DATUMREFCNT free_nsp(nsp);#endif nsp[0] = NULL; count = 0; switch (findns(&np, class, nsp, &count, 0)) { case NXDOMAIN: if (!foundname) { hp->rcode = NXDOMAIN; } dprintf(3, (ddt, "req: leaving (%s, rcode %d)\n", dname, hp->rcode)); if (class != C_ANY) { hp->aa = 1; /* XXX * 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, *cpp, *buflenp, np, nsp[0]); *cpp += n; *buflenp -= n;#ifdef ADDAUTH } else if (hp->ancount) { /* don't add NS records for NOERROR NODATA as some severs can get confused */#ifdef DATUMREFCNT free_nsp(nsp);#endif switch (findns(&np, class, nsp, &count, 1)) { case NXDOMAIN: case SERVFAIL: break; default: if (np) { n = add_data(np, nsp, *cpp, *buflenp); if (n < 0) { hp->tc = 1; n = (-n); } *cpp += n; *buflenp -= n; hp->nscount = htons((u_int16_t) count); } }#endif /*ADDAUTH*/ } }#ifdef DATUMREFCNT free_nsp(nsp);#endif return Finish; case SERVFAIL: if (!founddata && !(forward_only && fwdtab)) { hp->rcode = SERVFAIL;#ifdef DATUMREFCNT free_nsp(nsp);#endif return Finish; } } /* * If we successfully found the answer in the cache, * or this is not a recursive query, or we are purposely * never recursing, then add the nameserver references * ("authority section") here and we're done. */ if (founddata || (!hp->rd) || NoRecurse) { n = add_data(np, nsp, *cpp, *buflenp); if (n < 0) { hp->tc = 1; n = (-n); } *cpp += n; *buflenp -= n; hp->nscount = htons((u_int16_t)count);#ifdef DATUMREFCNT free_nsp(nsp);#endif return 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) *msglenp); if (omsg == (u_char *)NULL) { dprintf(1, (ddt, "ns_req: malloc fail\n")); syslog(LOG_ERR, "ns_req: Out Of Memory"); hp->rcode = SERVFAIL; return Finish; } id = hp->id; hp->ancount = htons(hp->ancount); omsglen = *msglenp; bcopy(msg, omsg, omsglen); *msglenp = res_mkquery(QUERY, dname, class, type, (char *)NULL, 0, NULL, (char *)msg, *msglenp + *buflenp); } n = ns_forw(nsp, msg, *msglenp, from, qsp, dfd, &qp, dname); if (n != FW_OK && cname) free(omsg); switch (n) { case FW_OK: if (cname) { qp->q_cname = cname; qp->q_cmsg = (char *)omsg; qp->q_cmsglen = omsglen; qp->q_id = id; } break; case FW_DUP: break; /* Duplicate request dropped */ case FW_NOSERVER: /* ** Don't go into an infinite loop if ** the admin gave root NS records in the cache ** file without giving address records ** for the root servers. */ if (np) { if (np->n_dname[0] == '\0') { dprintf(1, (ddt, "ns_req: no address for root NS\n" )); syslog(LOG_ERR, "ns_req: no address for root server"); hp->rcode = SERVFAIL; return Finish; }#ifdef VALIDATE /* * we need to kill all the NS records here as * validate will fail as we are talking to the parent * server */ delete_all(np, class, T_NS);#endif np = np->n_parent; } goto fetchns; /* Try again. */ case FW_SERVFAIL: hp->rcode = SERVFAIL;#ifdef DATUMREFCNT free_nsp(nsp);#endif return Finish; }#ifdef DATUMREFCNT free_nsp(nsp);#endif return Return;}#if INVQstatic enum req_actionreq_iquery(hp, cpp, eom, buflenp, msg) HEADER *hp; u_char **cpp, *eom; int *buflenp; u_char *msg;{ register struct invbuf *ip; int dlen, alen, i, n, type, class, count; char dnbuf[MAXDNAME], anbuf[PACKETSZ], *data, *fname; struct namebuf *np; struct qinfo *qp; struct databuf *dp; stats[S_IQUERIES].cnt++; hp->ancount = htons(hp->ancount); if ((hp->ancount != 1) || hp->qdcount || hp->nscount || hp->arcount) { dprintf(1, (ddt, "FORMERR IQuery header counts wrong\n")); hp->qdcount = 0; hp->ancount = 0; hp->nscount = 0; hp->arcount = 0; hp->rcode = FORMERR; return Finish; } /* * Skip domain name, get class, and type. */ if ((n = dn_skipname(*cpp, eom)) < 0) { dprintf(1, (ddt, "FORMERR IQuery packet name problem\n")); hp->rcode = FORMERR; return Finish; } *cpp += n; GETSHORT(type, *cpp); GETSHORT(class, *cpp); *cpp += sizeof(u_int32_t); /* ttl */ GETSHORT(dlen, *cpp); *cpp += dlen; if (*cpp != eom) { dprintf(1, (ddt, "FORMERR IQuery message length off\n")); hp->rcode = FORMERR; return Finish; } /* * not all inverse queries are handled. */ switch (type) { case T_A: case T_UID: case T_GID: break; default: return Refuse; } dprintf(1, (ddt, "req: IQuery class %d type %d\n", class, type)); fname = (char *)msg + sizeof(HEADER); bcopy(fname, anbuf, alen = (char *)*cpp - fname); data = anbuf + alen - dlen; *cpp = (u_char *)fname; *buflenp -= sizeof(HEADER); count = 0; for (ip = invtab[dhash((u_char *)data, dlen)]; ip != NULL; ip = ip->i_next) { for (i = 0; i < INVBLKSZ; i++) { if ((np = ip->i_dname[i]) == NULL) break; dprintf(5, (ddt, "dname = %d\n", np->n_dname)); for (dp = np->n_data; dp != NULL; dp = dp->d_next) { if (!match(dp, class, type)) continue; if (dp->d_size != dlen || bcmp(dp->d_data, data, dlen)) continue; getname(np, dnbuf, sizeof(dnbuf)); dprintf(2, (ddt, "req: IQuery found %s\n", dnbuf)); *buflenp -= QFIXEDSZ; if ((n = dn_comp((u_char *)dnbuf, *cpp, *buflenp, (u_char **)NULL, (u_char **)NULL)) < 0) { hp->tc = 1; return Finish; } *cpp += n; PUTSHORT((u_int16_t)dp->d_type, *cpp); PUTSHORT((u_int16_t)dp->d_class, *cpp); *buflenp -= n; count++; } } } dprintf(1, (ddt, "req: IQuery %d records\n", count)); hp->qdcount = htons((u_int16_t)count); if (alen > *buflenp) { hp->tc = 1; return Finish; } bcopy(anbuf, *cpp, alen); *cpp += alen; return Finish;}#endifstatic voidfwritemsg(rfp, msg, msglen) FILE *rfp; char *msg; int msglen;{ u_int16_t len = htons((u_int16_t)msglen); if (fwrite((char *)&len, sizeof(len), 1, rfp) != 1 || fwrite(msg, msglen, 1, rfp) != 1) { dprintf(1, (ddt, "fwrite failed %d\n", errno)); }}/* * Test a datum for validity and return non-zero if it is out of date. */intstale(dp) register struct databuf *dp;{ register struct zoneinfo *zp = &zones[dp->d_zone]; switch (zp->z_type) { case Z_PRIMARY: return (0); case Z_SECONDARY:#ifdef STUBS case Z_STUB:#endif /* * Check to see whether a secondary zone * has expired; if so clear authority flag * for zone and return true. If lastupdate * is in the future, assume zone is up-to-date. */ if ((int32_t)(tt.tv_sec - zp->z_lastupdate) > (int32_t)zp->z_expire) { dprintf(1, (ddt, "stale: secondary zone %s expired\n", zp->z_origin)); if (!haveComplained(zp->z_origin, (char*)stale)) { syslog(LOG_ERR, "secondary zone \"%s\" expired", zp->z_origin); } zp->z_state &= ~Z_AUTH; return (1); } return (0); case Z_CACHE: dprintf(3, (ddt, "stale: ttl %d %d (x%x)\n", dp->d_ttl, dp->d_ttl - tt.tv_sec, dp->d_flags)); if (dp->d_flags & DB_F_HINT) return(0); return(dp->d_ttl < tt.tv_sec); } abort(); /* NOTREACHED */}/* * Copy databuf into a resource record for replies. * Return size of RR if OK, -1 if buffer is full. */intmake_rr(name, dp, buf, buflen, doadd) char *name; register struct databuf *dp; u_char *buf; int buflen, doadd;{ register u_char *cp; u_char *cp1, *sp; struct zoneinfo *zp; register int32_t n; register int32_t ttl; u_char **edp = dnptrs + sizeof(dnptrs)/sizeof(dnptrs[0]); dprintf(5, (ddt, "make_rr(%s, %x, %x, %d, %d) %d zone %d ttl %d\n", name, dp, buf, buflen, doadd, dp->d_size, dp->d_zone, dp->d_ttl));#ifdef NCACHE if (dp->d_rcode) { syslog(LOG_CRIT, "make_rr d_rcode %d", dp->d_rcode); if (debug) abort(); return -1; /* XXX We should exit here */ }#endif zp = &zones[dp->d_zone]; /* check for outdated RR before updating dnptrs by dn_comp() (???) */ if (zp->z_type == Z_CACHE) { ttl = dp->d_ttl - (u_int32_t) tt.tv_sec; if ((dp->d_flags & DB_F_HINT) || (ttl < 0)) { dprintf(3, (ddt, "make_rr: %d=>0, x%x\n", ttl, dp->d_flags)); /* XXX */ ttl = 0; } } else { if (dp->d_ttl) ttl = dp->d_ttl; else ttl = zp->z_minimum; /* really default */#ifdef notdef /* don't decrease ttl based on time since verification */ if (zp->z_type == Z_SECONDARY) { /* * Set ttl to value received from primary, * less time since we verified it (but never * less than a small positive value). */ ttl -= tt.tv_sec - zp->z_lastupdate; if (ttl <= 0) ttl = 120; }#endif } buflen -= RRFIXEDSZ; if ((n = dn_comp((u_char *)name, (u_char *)buf, buflen, (u_char **)dnptrs, (u_char **)edp)) < 0) return (-1); cp = buf + n; buflen -= n; PUTSHORT((u_int16_t)dp->d_type, cp); PUTSHORT((u_int16_t)dp->d_class, cp); PUTLONG(ttl, cp); sp = cp; cp += sizeof(u_int16_t); switch (dp->d_type) { case T_CNAME: case T_MG: case T_MR: case T_PTR: if ((n = dn_comp((u_char *)dp->d_data, (u_char *)cp, buflen, (u_char **)dnptrs, (u_char **)edp)) < 0) return (-1); PUTSHORT((u_int16_t)n, sp); cp += n; break; case T_MB: case T_NS: /* Store domain name in answer */ if ((n = dn_comp((u_char *)dp->d_data, (u_char *)cp, buflen, (u_char **)dnptrs, (u_char **)edp)) < 0) return (-1); PUTSHORT((u_int16_t)n, sp); cp += n; if (doadd) addname((char*)dp->d_data, dp->d_class); break; case T_SOA: case T_MINFO: case T_RP: cp1 = dp->d_data; if ((n = dn_comp((u_char *)cp1, (u_char *)cp, buflen, (u_char **)dnptrs, (u_char **)edp)) < 0) return (-1); cp += n; buflen -= dp->d_type == T_SOA ? n + 5 * sizeof(u_int32_t) : n; cp1 += strlen((char *)cp1) + 1; if ((n = dn_comp((u_char *)cp1, (u_char *)cp, buflen, (u_char **)dnptrs, (u_char **)edp)) < 0) return (-1); cp += n; if (dp->d_type == T_SOA) { cp1 += strlen((char *)cp1) + 1; bcopy(cp1, cp, (int)(n = dp->d_size - (cp1 - dp->d_data))); cp += n; } n = (u_int16_t)((cp - sp) - sizeof(u_int16_t)); PUTSHORT((u_int16_t)n, sp); break; case T_MX: case T_AFSDB: /* cp1 == our data/ cp == data of RR */ cp1 = dp->d_data; /* copy preference */ bcopy(cp1, cp, sizeof(u_int16_t)); cp += sizeof(u_int16_t); cp1 += sizeof(u_int16_t); buflen -= sizeof(u_int16_t); if ((n = dn_comp((u_char *)cp1, (u_char *)cp, buflen, (u_char **)dnptrs, (u_char **)edp)) < 0) return(-1); cp += n; /* save data length */ n = (u_int16_t)((cp - sp) - sizeof(u_int16_t)); PUTSHORT((u_int16_t)n, sp); if (doadd) addname((char*)cp1, dp->d_class); break; default: if (dp->d_size > buflen) return (-1); bcopy(dp->d_data, cp, dp->d_size); PUTSHORT((u_int16_t)dp->d_size, sp); cp += dp->d_size; } return (cp - buf);}#if defined(__STDC__) || defined(__GNUC__)static voidaddname(register char *name, u_int16_t class)#elsestatic voidaddname(name, class) register char *name; u_int16_t class;#endif{ register struct addinfo *ap; register int n; for (ap = addinfo, n = addcount; --n >= 0; ap++) if (strcasecmp(ap->a_dname, name) == 0) return; /* add domain name to additional section */ if (addcount < NADDRECS) { addcount++; ap->a_dname = malloc(strlen(name)+1); strcpy(ap->a_dname,name); ap->a_class = class; }}/* * Lookup addresses for names in addinfo and put into the message's * additional section. */intdoaddinfo(hp, msg, msglen) HEADER *hp; u_char *msg; int msglen;{ register struct namebuf *np; register struct databuf *dp; register struct addinfo *ap; register u_char *cp; struct hashbuf *htp; char *fname; int n, count; dprintf(3, (ddt, "doaddinfo() addcount = %d\n", addcount)); if (hp->tc) { dprintf(4, (ddt, "doaddinfo(): tc already set, bailing\n")); return 0; } count = 0; cp = msg; for (ap = addinfo; --addcount >= 0; ap++) { int foundstale = 0, foundany = 0, save_count = count, save_msglen = msglen; u_char *save_cp = cp; dprintf(3, (ddt, "do additional '%s'\n", ap->a_dname)); htp = hashtab; /* because "nlookup" stomps on arg. */ np = nlookup(ap->a_dname, &htp, &fname, 0); if (np == NULL || fname != ap->a_dname) goto next_rr; dprintf(3, (ddt, "found it\n")); /* look for the data */ for (dp = np->n_data; dp != NULL; dp = dp->d_next) { if ( (!match(dp, (int)ap->a_class, T_A)) && (!match(dp, C_IN, T_A)) ) { continue; } foundany++; if (stale(dp)) { foundstale++;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -