📄 ns_resp.c
字号:
/* * Check the list of root servers after receiving a response * to a query for the root servers. */static voidcheck_root(){ register struct databuf *dp, *pdp; register struct namebuf *np; int count = 0; priming = 0; for (np = hashtab->h_tab[0]; np != NULL; np = np->n_next) if (np->n_dname[0] == '\0') break; if (np == NULL) { syslog(LOG_ERR, "check_root: Can't find root!\n"); return; } for (dp = np->n_data; dp != NULL; dp = dp->d_next) if (dp->d_type == T_NS) count++; dprintf(1, (ddt, "%d root servers\n", count)); if (count < MINROOTS) { syslog(LOG_WARNING, "check_root: %d root servers after query to root server < min", count); return; } pdp = NULL; dp = np->n_data; while (dp != NULL) { if (dp->d_type == T_NS && dp->d_zone == 0 && dp->d_ttl < tt.tv_sec) { dprintf(1, (ddt, "deleting old root server '%s'\n", dp->d_data)); dp = rm_datum(dp, np, pdp); /* SHOULD DELETE FROM HINTS ALSO */ continue; } pdp = dp; dp = dp->d_next; } check_ns();}/* * Check the root to make sure that for each NS record we have a A RR */static voidcheck_ns(){ register struct databuf *dp, *tdp; register struct namebuf *np, *tnp; struct hashbuf *htp; char *dname; int found_arr; char *fname; time_t curtime; dprintf(2, (ddt, "check_ns()\n")); stats[S_CHECKNS].cnt++; curtime = (u_int32_t) tt.tv_sec; for (np = hashtab->h_tab[0]; np != NULL; np = np->n_next) { if (np->n_dname[0] != 0) continue; for (dp = np->n_data; dp != NULL; dp = dp->d_next) { if (dp->d_type != T_NS) continue; /* look for A records */ dname = (caddr_t) dp->d_data; htp = hashtab; tnp = nlookup(dname, &htp, &fname, 0); if (tnp == NULL || fname != dname) { dprintf(3, (ddt, "check_ns: %s: not found %s %x\n", dname, fname, tnp)); sysquery(dname, dp->d_class, T_A, NULL, 0); continue; } /* look for name server addresses */ found_arr = 0; for (tdp=tnp->n_data; tdp!=NULL; tdp=tdp->d_next) { if (tdp->d_type != T_A || tdp->d_class != dp->d_class) continue; if ((tdp->d_zone == 0) && (tdp->d_ttl < curtime)) { dprintf(3, (ddt, "check_ns: stale entry '%s'\n", tnp->n_dname)); /* Cache invalidate the address RR's */ delete_all(tnp, dp->d_class, T_A); found_arr = 0; break; } found_arr++; } if (!found_arr) (void) sysquery(dname, dp->d_class, T_A, NULL, 0); } }}/* * Find NS's or an SOA for the given dname (np) and fill in the * nsp array. Returns OK on success, and SERVFAIL on error. * We return NXDOMAIN to indicate we are authoritative. */intfindns(npp, class, nsp, countp, flag) register struct namebuf **npp; int class; struct databuf **nsp; int *countp; int flag;{ register struct namebuf *np = *npp; register struct databuf *dp; register struct databuf **nspp; struct hashbuf *htp; if (priming && (np == NULL || np->n_dname[0] == '\0')) htp = fcachetab; else htp = hashtab;try_again: if (htp == fcachetab) needs_prime_cache = 1; while (np == NULL && htp != NULL) { dprintf(3, (ddt, "findns: using %s\n", htp == hashtab ? "cache" : "hints")); for (np = htp->h_tab[0]; np != NULL; np = np->n_next) if (np->n_dname[0] == '\0') break; htp = (htp == hashtab ? fcachetab : NULL); /* Fallback */ } while(np != NULL) { dprintf(5, (ddt, "findns: np 0x%x '%s'\n", np, np->n_dname)); /* Look first for SOA records. */#ifdef ADDAUTH if(!flag)#endif for (dp = np->n_data; dp != NULL; dp = dp->d_next) { if (dp->d_zone != 0 && match(dp, class, T_SOA)) { dprintf(3, (ddt, "findns: SOA found\n")); if (zones[dp->d_zone].z_state & Z_AUTH) { *npp = np; nsp[0] = dp;#ifdef DATUMREFCNT nsp[1] = NULL; dp->d_rcnt++;#endif return(NXDOMAIN); } else return (SERVFAIL); } } /* If no SOA records, look for NS records. */ nspp = &nsp[0]; *nspp = NULL; for (dp = np->n_data; dp != NULL; dp = dp->d_next) { if (dp->d_type != T_NS || (dp->d_class != class && class != C_ANY)) continue; /* * Don't use records that may become invalid to * reference later when we do the rtt computation. * Never delete our safety-belt information! */ if ((dp->d_zone == 0) && (dp->d_ttl < (tt.tv_sec+900)) && !(dp->d_flags & DB_F_HINT)) { dprintf(1, (ddt, "findns: stale entry '%s'\n", np->n_dname)); /* Cache invalidate the NS RR's */ if (dp->d_ttl < tt.tv_sec) delete_all(np, class, T_NS); goto try_parent; } if (nspp < &nsp[NSMAX-1]) { *nspp++ = dp;#ifdef DATUMREFCNT dp->d_rcnt++;#endif } } *countp = nspp - nsp; if (*countp > 0) { dprintf(3, (ddt, "findns: %d NS's added for '%s'\n", *countp, np->n_dname)); *nspp = NULL; *npp = np; return OK; /* Success, got some NS's */ }try_parent: np = np->n_parent; } if (htp) goto try_again; dprintf(1, (ddt, "findns: No root nameservers for class %d?\n", class)); if ((unsigned)class < MAXCLASS && norootlogged[class] == 0) { norootlogged[class] = 1; syslog(LOG_ERR, "No root nameservers for class %d\n", class); } return SERVFAIL;}/* * Extract RR's from the given node that match class and type. * Return number of bytes added to response. * If no matching data is found, then 0 is returned. */intfinddata(np, class, type, hp, dnamep, lenp, countp) struct namebuf *np; int class, type; register HEADER *hp; char **dnamep; int *lenp, *countp;{ register struct databuf *dp; register char *cp; int buflen, n, count = 0, foundstale = 0;#ifdef ROUND_ROBIN if (type != T_ANY) { /* cycle order of RRs, for a load balancing effect... */ register struct databuf **dpp; for (dpp = &np->n_data; *dpp; dpp = &dp->d_next) { dp = *dpp; if (dp->d_next && wanted(dp, class, type)) { register struct databuf *lp; *dpp = lp = dp->d_next; dp->d_next = NULL; for (dpp = &lp->d_next; *dpp; dpp = &lp->d_next) { lp = *dpp; } *dpp = dp; break; } } }#endif /*ROUND_ROBIN*/ buflen = *lenp; cp = ((char *)hp) + *countp; for (dp = np->n_data; dp != NULL; dp = dp->d_next) { if (!wanted(dp, class, type)) {#ifndef NCACHE /*if no negative caching then cname => nothing else*/ if (type == T_CNAME && class == dp->d_class) { /* any data means no CNAME exists */ *countp = 0; return 0; }#endif /*NCACHE*/ continue; } if (stale(dp)) { /* * Don't use stale data. * Would like to call delete_all here * and continue, but the data chain would get * munged; can't restart, as make_rr has side * effects (leaving pointers in dnptr). * Just skip this entry for now * and call delete_all at the end. */ dprintf(3, (ddt, "finddata: stale entry '%s'\n", np->n_dname)); if (dp->d_zone == 0) foundstale++; continue; }#ifdef CRED if (dp->d_cred == DB_C_ADDITIONAL) { /* we want to expire additional data very * quickly. current strategy is to cut 5% * off each time it is accessed. this makes * stale(dp) true faster when this datum is * used often. */ dp->d_ttl = tt.tv_sec + 0.95 * (dp->d_ttl - tt.tv_sec); }#endif /*CRED*/#ifdef NCACHE /* -ve $ing stuff, anant@isi.edu * if we have a -ve $ed record, change the rcode on the * header to reflect that */ if (dp->d_rcode == NOERROR_NODATA) { if (count != 0) { /* * This should not happen, yet it does... */ syslog(LOG_WARNING, "NODATA & data for \"%s\" type %d class %d", *dnamep, type, class); continue; } if (type != T_ANY) { hp->rcode = NOERROR_NODATA; *countp = 0; return 1; /* XXX - we have to report success */ } /* don't satisfy T_ANY queries from -$ info */ continue; } if (dp->d_rcode == NXDOMAIN) { if (count != 0) { /* * This should not happen, yet it might... */ syslog(LOG_WARNING, "NXDOMAIN & data for \"%s\" type %d class %d", *dnamep, type, class); continue; } if (type != T_ANY) { hp->rcode = NXDOMAIN; *countp = 0; return 1; /* XXX - we have to report success */ } /* don't satisfy T_ANY queries from -$ info */ continue; }#endif /*NCACHE*/ if ((n = make_rr(*dnamep, dp, (u_char *)cp, buflen, 1)) < 0) { hp->tc = 1; *countp = count; return (*lenp - buflen); } cp += n; buflen -= n; count++;#ifdef notdef /* this isn't right for glue records, aa is set in ns_req */ if (dp->d_zone && (zones[dp->d_zone].z_state & Z_AUTH) && class != C_ANY) hp->aa = 1; /* XXX */#endif if (dp->d_type == T_CNAME) { if (type != T_ANY) { /* or T_NS? */ *dnamep = (caddr_t) dp->d_data; if (dp->d_zone && (zones[dp->d_zone].z_state & Z_AUTH) && class != C_ANY) /* XXX */ hp->aa = 1; /* XXX */ } break; } } /* * Cache invalidate the other RR's of same type * if some have timed out */ if (foundstale) { delete_all(np, class, type); /* XXX this isn't right if 'type' is something special * such as T_AXFR or T_MAILB, since the matching done * by match() in delete_all() is different from that * done by wanted() above. */ } dprintf(3, (ddt, "finddata: added %d class %d type %d RRs\n", count, class, type)); *countp = count; return (*lenp - buflen);}/* * Do we want this data record based on the class and type? */intwanted(dp, class, type) struct databuf *dp; int class, type;{ dprintf(3, (ddt, "wanted(%x, %d, %d) %d, %d\n", dp, class, type, dp->d_class, dp->d_type)); if (dp->d_class != class && class != C_ANY) return (0); if (type == dp->d_type) return (1);#ifdef NCACHE /*-ve $ing stuff, for a T_ANY query, we do not want to return * -ve $ed RRs. */ if (type == T_ANY && dp->d_rcode == NOERROR_NODATA) return (0);#endif switch (dp->d_type) { case T_ANY: return (1); case T_CNAME:#ifdef NCACHE if (dp->d_rcode != NOERROR_NODATA)#endif return (1);#ifdef NCACHE else break;#endif } switch (type) { case T_ANY: return (1); case T_MAILB: switch (dp->d_type) { case T_MR: case T_MB: case T_MG: case T_MINFO: return (1); } break; case T_AXFR: /* T_AXFR needs an authoritative SOA */ if (dp->d_type == T_SOA && dp->d_zone != 0 && (zones[dp->d_zone].z_state & Z_AUTH)) return (1); break; } return (0);}/* * Add RR entries from dpp array to a query/response. * Return the number of bytes added or negative the amount * added if truncation was required. Typically you are * adding NS records to a response. */intadd_data(np, dpp, cp, buflen) struct namebuf *np; struct databuf **dpp; register u_char *cp; int buflen;{ register struct databuf *dp; char dname[MAXDNAME]; register int n, count = 0; getname(np, dname, sizeof(dname)); for(dp = *dpp++; dp != NULL; dp = *dpp++) { if (stale(dp)) continue; /* ignore old cache entry */#ifdef NCACHE if (dp->d_rcode) continue;#endif if ((n = make_rr(dname, dp, cp, buflen, 1)) < 0) return(-count); /* Truncation */ cp += n; buflen -= n; count += n; } return(count);}/* * This is best thought of as a "cache invalidate" function. * It is called whenever a piece of data is determined to have * timed out. It is better to have no information, than to * have partial information you pass off as complete. */voiddelete_all(np, class, type) register struct namebuf *np; int class, type;{ register struct databuf *dp, *pdp; dprintf(3, (ddt, "delete_all: '%s' 0x%x class %d type %d\n", np->n_dname, np, class, type)); pdp = NULL; dp = np->n_data; while (dp != NULL) { if ((dp->d_zone == 0) && !(dp->d_flags & DB_F_HINT) && match(dp, class, type)) { dp = rm_datum(dp, np, pdp); continue; } pdp = dp; dp = dp->d_next; }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -