📄 ns_req.c
字号:
dprintf(1, (ddt, "doaddinfo: stale entry '%s'%s\n", np->n_dname, (dp->d_flags&DB_F_HINT) ? " hint" : "" )); continue; }#ifdef NCACHE if (dp->d_rcode) continue;#endif /* * Should be smart and eliminate duplicate * data here. XXX */ if ((n = make_rr(ap->a_dname, dp, cp, msglen, 0)) < 0){ /* truncation in the additional-data section * is not all that serious. we do not set TC, * since the answer and authority sections are * OK; however, since we're not setting TC we * have to make sure that none of the RR's for * this name go out (!TC implies that all * {name,type} appearances are complete -- and * since we only do A RR's here, the name is * the key). vixie, 23apr93 */ cp = save_cp; msglen = save_msglen; count = save_count; break; } dprintf(5, (ddt, "addinfo: adding address data n = %d\n", n)); cp += n; msglen -= n; count++; }next_rr: if (foundstale) { /* Cache invalidate the address RR's */ delete_all(np, (int)ap->a_class, T_A); } if (foundstale || !foundany) { /* ask a real server for this info */ (void) sysquery(ap->a_dname, (int)ap->a_class, T_A, NULL, 0); } free(ap->a_dname); } hp->arcount = htons((u_int16_t)count); return (cp - msg);}intdoaddauth(hp, cp, buflen, np, dp) register HEADER *hp; u_char *cp; int buflen; struct namebuf *np; struct databuf *dp;{ char dnbuf[MAXDNAME]; int n; getname(np, dnbuf, sizeof(dnbuf)); if (stale(dp)) { dprintf(1, (ddt, "doaddauth: can't add stale '%s' (%d) (n=%d)\n", dnbuf, buflen, n)); return 0; } n = make_rr(dnbuf, dp, cp, buflen, 1); if (n <= 0) { dprintf(1, (ddt, "doaddauth: can't add oversize '%s' (%d) (n=%d)\n", dnbuf, buflen, n)); if (n < 0) { hp->tc = 1; } return 0; } hp->nscount = htons((u_int16_t)1); return (n);}/* * Do a zone transfer (or a recursive part of a zone transfer). * SOA record already sent. * * top always refers to the domain at the top of the zone being transferred. * np refers to a domain inside the zone being transferred, * which will be equal to top if this is the first call, * or will be a subdomain below top if this is a recursive call, * rfp is a stdio file to which output is sent. */static voiddoaxfr(np, rfp, top, class) register struct namebuf *np; FILE *rfp; struct namebuf *top; int class; /* Class to transfer */{ register struct databuf *dp; register int n; struct hashbuf *htp; struct databuf *gdp; /* glue databuf */ struct namebuf *gnp; /* glue namebuf */ struct namebuf *tnp; /* top namebuf */ struct databuf *tdp; /* top databuf */ struct namebuf **npp, **nppend; char msg[PACKETSZ]; u_char *cp; char *fname; char dname[MAXDNAME]; HEADER *hp = (HEADER *) msg; int fndns; if (np == top) dprintf(1, (ddt, "doaxfr()\n")); fndns = 0; hp->id = 0; hp->opcode = QUERY; hp->aa = hp->tc = hp->ra = hp->pr = hp->rd = 0; hp->qr = 1; hp->rcode = NOERROR; hp->qdcount = 0; hp->ancount = htons(1); hp->nscount = 0; hp->arcount = 0; cp = (u_char *) (msg + sizeof(HEADER)); getname(np, dname, sizeof(dname)); /* first do the NS records (del@harris) */ for (dp = np->n_data; dp != NULL; dp = dp->d_next) {#ifdef GEN_AXFR if (dp->d_class != class && class != C_ANY) continue;#endif#ifdef NCACHE if (dp->d_rcode) continue;#endif if (dp->d_type == T_NS) { fndns = 1; if ((n = make_rr(dname, dp, cp, sizeof(msg)-sizeof(HEADER), 0)) < 0) continue; fwritemsg(rfp, msg, n + sizeof(HEADER)); if (np != top) { /* Glue the sub domains together by sending * the address records for the sub domain * name servers along if necessary. * Glue is necessary if the server is in any zone * delegated from the current (top) zone. Such * a delegated zone might or might not be that * referred to by the NS record now being handled. */ htp = hashtab; cp = (u_char *) (msg + sizeof(HEADER)); gnp = nlookup((caddr_t)dp->d_data, &htp, &fname, 0); if (gnp == NULL || fname != (caddr_t)dp->d_data) continue; for (tnp = gnp; tnp != NULL; tnp = tnp->n_parent) if ( tnp == top ) break; if ( tnp == NULL ) continue; /* name server is not below top domain */ for (tnp = gnp; tnp != top; tnp = tnp->n_parent) { for (tdp = tnp->n_data; tdp != NULL; tdp = tdp->d_next) {#ifdef GEN_AXFR if (tdp->d_class != class && class != C_ANY) continue;#endif if (tdp->d_type == T_NS) break; } if (tdp != NULL) break; /* found a zone cut */ } if (tnp == top) continue; /* name server is not in a delegated zone */ /* now we know glue records are needed. send them. */ for(gdp=gnp->n_data; gdp != NULL; gdp=gdp->d_next) {#ifdef GEN_AXFR if (gdp->d_class != class && class != C_ANY) continue;#endif if (gdp->d_type != T_A || stale(gdp)) continue;#ifdef NCACHE if (gdp->d_rcode) continue;#endif if ((n = make_rr(fname, gdp, cp, sizeof(msg)-sizeof(HEADER), 0)) < 0) continue; fwritemsg(rfp, msg, n + sizeof(HEADER)); } } } } /* no need to send anything else because of delegation */ if ((np != top) && fndns) return; /* do the rest of the data records */ for (dp = np->n_data; dp != NULL; dp = dp->d_next) {#ifdef GEN_AXFR if (dp->d_class != class && class != C_ANY) continue;#endif /* * Skip the top SOA record (marks end of data); * don't send SOA for subdomains, as we're not sending them; * skip the NS records because we did them first. */ if (dp->d_type == T_SOA || dp->d_type == T_NS) continue; if (dp->d_zone == 0 || stale(dp)) continue;#ifdef NCACHE if (dp->d_rcode) continue;#endif if ((n = make_rr(dname, dp, cp, sizeof(msg)-sizeof(HEADER), 0)) < 0) continue; fwritemsg(rfp, msg, n + sizeof(HEADER)); } /* Finally do non-delegated subdomains. Delegated subdomains * have already been handled. */ /* * We find the subdomains by looking in the hash table for this * domain, but the root domain needs special treatment, because * of the following wart in the database design: * * The top level hash table (pointed to by the global `hashtab' * variable) contains pointers to the namebuf's for the root as * well as for the top-level domains below the root, in contrast * to the usual situation where a hash table contains entries * for domains at the same level. The n_hash member of the * namebuf for the root domain is NULL instead of pointing to a * hashbuf for the top-level domains. The n_parent members of * the namebufs for the top-level domains are NULL instead of * pointing to the namebuf for the root. * * We work around the wart as follows: * * If we are not dealing with the root zone then we just set * htp = np->n_hash, pointing to the hash table for the current * domain, and we walk through the hash table as usual, * processing the namebufs for all the subdomains. * * If we are dealing with the root zone, then we set * htp = hashtab, pointing to the global hash table (because * there is no hash table associated with the root domain's * namebuf. While we walk this hash table, we take care not to * recursively process the entry for the root namebuf. * * (apb@und nov1990) */ htp = ((dname[0] == '\0') ? hashtab : np->n_hash); if (htp == NULL) { return; /* no subdomains */ } npp = htp->h_tab; nppend = npp + htp->h_size; while (npp < nppend) { for (np = *npp++; np != NULL; np = np->n_next) { if (np->n_dname[0] != '\0') { /* don't redo root domain */ doaxfr(np, rfp, top, class); } } } if (np == top) dprintf(1, (ddt, "exit doaxfr()\n"));}#ifdef ALLOW_UPDATES/* * Called by UPDATE{A,D,DA,M,MA} to initiate a dynamic update. If this is the * primary server for the zone being updated, we update the zone's serial * number and then call doupdate directly. If this is a secondary, we just * forward the update; this way, if the primary update fails (e.g., if the * primary is unavailable), we don't update the secondary; if the primary * update suceeds, ns_resp will get called with the response (when it comes * in), and then update the secondary's copy. */static intInitDynUpdate(hp, msg, msglen, startcp, from, qsp, dfd) register HEADER *hp; char *msg; int msglen; u_char *startcp; struct sockaddr_in *from; struct qstream *qsp; int dfd;{ struct databuf *nsp[NSMAX]; struct zoneinfo *zp; char dnbuf[MAXDNAME]; struct hashbuf *htp = hashtab; /* lookup relative to root */ struct namebuf *np; struct databuf *olddp, *newdp, *dp; struct databuf **nspp; char *fname; register u_char *cp = startcp; u_int16_t class, type; int n, size, zonenum; char ZoneName[MAXDNAME], *znp;#ifdef DATUMREFCNT nsp[0] = NULL;#endif if ((n = dn_expand(msg, msg + msglen, cp, dnbuf, sizeof(dnbuf))) < 0) { dprintf(1, (ddt,"FORMERR InitDynUpdate expand name failed\n")); hp->rcode = FORMERR; return(FORMERR); } cp += n; GETSHORT(type, cp); if (type == T_SOA) { /* T_SOA updates not allowed */ hp->rcode = REFUSED; dprintf(1, (ddt, "InitDynUpdate: REFUSED - SOA update\n")); return(REFUSED); } GETSHORT(class, cp); cp += sizeof(u_int32_t); GETSHORT(size, cp);/****XXX - need bounds checking here ****/ cp += size; if ((zonenum = findzone(dnbuf, class)) == 0) { /* zone not found */ hp->rcode = NXDOMAIN; return(NXDOMAIN); } zp = &zones[zonenum]; /* Disallow updates for which we aren't authoratative. Note: the following test doesn't work right: If it's for a non-local zone, we will think it's a primary but be unable to lookup the namebuf, thus returning 'NXDOMAIN' */ if (zp->z_type != Z_PRIMARY && zp->z_type != Z_SECONDARY) { hp->rcode = REFUSED; dprintf(1, (ddt, "InitDynUpdate: REFUSED - non-{primary,secondary} update\n")); return(REFUSED); } if (!(zp->z_state & Z_DYNAMIC)) { hp->rcode = REFUSED; dprintf(1, (ddt, "InitDynUpdate: REFUSED - dynamic flag not set for zone\n")); return(REFUSED); } /* * Lookup the zone namebuf. Lookup "xyz" not "xyz.", since * otherwise the lookup fails, because '.' may have a nil n_hash * associated with it. */ strcpy(ZoneName, zp->z_origin); znp = &ZoneName[strlen(ZoneName) - 1]; if (*znp == '.') *znp = NULL; np = nlookup(ZoneName, &htp, &fname, 0); if ((np == NULL) || (fname != ZoneName)) { dprintf(1, (ddt, "InitDynUpdate: lookup failed on zone (%s)\n", ZoneName)); syslog(LOG_ERR, "InitDynUpdate: lookup failed on zone (%s)\n", ZoneName); hp->rcode = NXDOMAIN; return(NXDOMAIN); } /* * If this is the primary copy increment the serial number. Don't * increment the serial number if this is a secondary; this way, if 2 * different secondaries both update the primary, they will both have * lower serial numbers than the primary has, and hence eventually * refresh and get all updates and become consistent. * * Note that the serial number must be incremented in both the zone * data structure and the zone's namebuf. */ switch (zp->z_type) { case Z_SECONDARY: /* forward update to primary */ nspp = nsp; dp = np->n_data; while (dp != NULL) { if (match(dp, class, T_NS)) { if (nspp < &nsp[NSMAX-1]) { *nspp++ = dp;#ifdef DATUMREFCNT dp->d_rcnt++;#endif } else break; } dp = dp->d_next; } *nspp = NULL; /* Delimiter */ if (ns_forw(nsp, msg, msglen, from, qsp, dfd, NULL, dnbuf) < 0) { hp->rcode = SERVFAIL;#ifdef DATUMREFCNT free_nsp(nsp);#endif return(SERVFAIL); }#ifdef DATUMREFCNT free_nsp(nsp);#endif return(FORWARDED); case Z_PRIMARY: zp->z_serial++; olddp = np->n_data; /* old databuf */ /* Find the SOA record */ for (olddp = np->n_data; olddp != NULL; olddp = olddp->d_next) if (match(olddp, class, T_SOA)) break; if (olddp == NULL) { dprintf(1, (ddt, "InitDynUpdate: Couldn't find SOA record for '%s'\n", ZoneName)); syslog(LOG_ERR, "InitDynUpdate: Couldn't find SOA record for '%s'\n", ZoneName); hp->rcode = NXDOMAIN;#ifdef DATUMREFCNT free_nsp(nsp);#endif return(NXDOMAIN); } newdp = savedata(olddp->d_class, olddp->d_type, olddp->d_ttl, olddp->d_data, olddp->d_size); newdp->d_zone = olddp->d_zone;#ifdef CRED newdp->d_cred = DB_C_AUTH; newdp->d_clev = db_getclev(zp->z_origin);#endif cp = (u_char *)newdp->d_data; cp += strlen(cp) + 1; /* skip origin string */ cp += strlen(cp) + 1; /* skip in-charge string */ putlong((u_int32_t)(zp->z_serial), cp); dprintf(4, (ddt, "after stuffing data into newdp:\n"));#ifdef DEBUG if (debug >= 4) printSOAdata(newdp);#endif if ((n = db_update(ZoneName, olddp, newdp, DB_DELETE, hashtab)) != NOERROR) { dprintf(1, (ddt, "InitDynUpdate: SOA update failed\n")); hp->rcode = NOCHANGE; free((char*) dp); /* vix@dec mar92 */#ifdef DATUMREFCNT free_nsp(nsp);#endif return(NOCHANGE); } /* Now update the RR itself */ if (doupdate(msg, msglen, msg + sizeof(HEADER), zonenum, (struct databuf *)0, DB_NODATA#ifdef CRED , DB_C_AUTH#endif ) < 0) { dprintf(1, (ddt, "InitDynUpdate: doupdate failed\n")); /* doupdate fills in rcode */#ifdef DATUMREFCNT free_nsp(nsp);#endif return(hp->rcode); } zp->z_state |= Z_CHANGED;#ifdef DATUMREFCNT free_nsp(nsp);#endif return(NOERROR); }}#ifdef DEBUG/* * Print the contents of the data in databuf pointed to by dp for an SOA record */static voidprintSOAdata(dp) struct databuf *dp;{ register u_char *cp; if (!debug) return; /* Otherwise fprintf to ddt will bomb */ cp = (u_char *)dp->d_data; fprintf(ddt, "printSOAdata(%x): origin(%x)='%s'\n", dp, cp, cp); cp += strlen(cp) + 1; /* skip origin string */ fprintf(ddt, "printSOAdata: in-charge(%x)='%s'\n", cp, cp); cp += strlen(cp) + 1; /* skip in-charge string */ fprintf(ddt, "printSOAdata: serial(%x)=%d\n", cp, _getlong(cp));}#endif#endifstatic voidstartxfr(qsp, np, msg, msglen, class) struct qstream *qsp; struct namebuf *np; char *msg; int msglen; int class;{ register FILE *rfp; int fdstat; dprintf(5, (ddt, "startxfr()\n")); /* * child does the work while * the parent continues * * XXX this should be a vfork/exec since on non-copy-on-write * systems with huge nameserver images, this is very expensive. */ if (fork() == 0) { dprintf(5, (ddt, "startxfr: child pid %d\n", getpid())); rfp = fdopen(qsp->s_rfd, "w"); setproctitle("zone XFR to", qsp->s_rfd); fdstat = fcntl(qsp->s_rfd, F_GETFL, 0); if (fdstat != -1) (void) fcntl(qsp->s_rfd, F_SETFL, fdstat & ~PORT_NONBLOCK); fwritemsg(rfp, msg, msglen); doaxfr(np, rfp, np, class); fwritemsg(rfp, msg, msglen); (void) fflush(rfp); exit(0); }}free_addinfo(){ register struct addinfo *ap; for (ap = addinfo; --addcount >= 0; ap++) { free(ap->a_dname); } addcount = 0;}#ifdef DATUMREFCNTfree_nsp(nsp)struct databuf **nsp;{ while (*nsp) { if (--((*nsp)->d_rcnt)) { dprintf(3, (ddt, "free_nsp: %s rcnt %d\n", (*nsp)->d_data, (*nsp)->d_rcnt)); } else { dprintf(3, (ddt, "free_nsp: %s rcnt %d delayed\n", (*nsp)->d_data, (*nsp)->d_rcnt)); free(*nsp); /* delayed free */ } nsp++; }}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -