diff options
Diffstat (limited to 'usr.sbin/named/ns_resp.c')
-rw-r--r-- | usr.sbin/named/ns_resp.c | 1001 |
1 files changed, 662 insertions, 339 deletions
diff --git a/usr.sbin/named/ns_resp.c b/usr.sbin/named/ns_resp.c index 004721b..fde341c 100644 --- a/usr.sbin/named/ns_resp.c +++ b/usr.sbin/named/ns_resp.c @@ -1,6 +1,6 @@ #if !defined(lint) && !defined(SABER) static char sccsid[] = "@(#)ns_resp.c 4.65 (Berkeley) 3/3/91"; -static char rcsid[] = "$Id: ns_resp.c,v 1.1.1.1 1994/09/22 19:46:13 pst Exp $"; +static char rcsid[] = "$Id: ns_resp.c,v 1.2 1995/05/30 03:48:56 rgrimes Exp $"; #endif /* not lint */ /* @@ -76,19 +76,94 @@ static void check_root __P((void)), static u_int8_t norootlogged[MAXCLASS]; /* XXX- should be a bitmap */ -static char skipnameFailedAnswer[] = "skipname failed in answer", +static const char skipnameFailedAnswer[] = "skipname failed in answer", skipnameFailedQuery[] = "skipname failed in query", outofDataQuery[] = "ran out of data in query", outofDataAnswer[] = "ran out of data in answer", -#ifdef LAME_DELEGATION + notSingleQuery[] = "not exactly one query", expandFailedQuery[] = "dn_expand failed in query", + expandFailedAnswer[] = "dn_expand failed in answer", expandFailedAuth[] = "dn_expand failed in authority", outofDataAuth[] = "ran out of data in authority", -#endif /* LAME_DELEGATION */ dlenOverrunAnswer[] = "dlen overrun in answer", dlenUnderrunAnswer[] = "dlen underrun in answer", outofDataFinal[] = "out of data in final pass", - outofDataAFinal[] = "out of data after final pass"; + outofDataAFinal[] = "out of data after final pass", + editFailed[] = "edit of response failed"; + +static char * +learntFrom(qp, server) + struct qinfo *qp; + struct sockaddr_in *server; +{ + static char *buf = NULL; + char *a, *ns, *na; + struct databuf *db; + char nsbuf[20]; + char abuf[20]; + int i; + + if (buf) { + free(buf); + buf = NULL; + } + + a = ns = na = "<Not Available>"; + + for (i = 0; i < (int)qp->q_naddr; i++) { + if (qp->q_addr[i].ns_addr.sin_addr.s_addr == + server->sin_addr.s_addr) { + db = qp->q_addr[i].ns; + if (db) { +#ifdef STATS + if (db->d_ns) { + strcpy(nsbuf, + inet_ntoa(db->d_ns->addr)); + ns = nsbuf; + } else { + ns = zones[db->d_zone].z_origin; + } +#endif + +#ifdef NCACHE + if (!db->d_rcode) +#endif + na = (char*)qp->q_addr[i].ns->d_data; + } + +#ifdef STATS + db = qp->q_addr[i].nsdata; + if (db) { + if (db->d_ns) { + strcpy(abuf, + inet_ntoa(db->d_ns->addr)); + a = abuf; + } else { + a = zones[db->d_zone].z_origin; + } + } +#endif + break; + } + } + + if ((a == ns) && (ns == na)) /* all "UNKNOWN" */ + return (""); + +#ifdef STATS +# define LEARNTFROM " '%s': learnt (A=%s,NS=%s)" +#else +# define LEARNTFROM " '%s'" +#endif + if (buf = malloc(strlen(a = (*a ? a : "\".\"")) + + strlen(ns = (*ns ? ns : "\".\"")) + + strlen(na = (*na ? na : "\".\"")) + + sizeof(LEARNTFROM))) { + sprintf(buf, LEARNTFROM, na, a, ns); + return (buf); + } + return(""); +} void ns_resp(msg, msglen) @@ -100,24 +175,25 @@ ns_resp(msg, msglen) register struct qserv *qs; register struct databuf *ns, *ns2; register u_char *cp; + u_char *eom = msg + msglen; #ifdef VALIDATE register u_char *tempcp; struct sockaddr_in *server = &from_addr; int *validatelist; - int lesscount; + int lesscount, old_ancount; #endif struct sockaddr_in *nsa; struct databuf *nsp[NSMAX], **nspp; - int i, c, n, ancount, aucount, nscount, arcount; - int old_ancount; - int type, class, dbflags; + int i, c, n, qdcount, ancount, aucount, nscount, arcount; + int qtype, qclass, dbflags; int cname = 0; /* flag for processing cname response */ int count, founddata, foundname; int buflen; int newmsglen; - char name[MAXDNAME], *dname; - char *fname; - char *formerrmsg = "brain damage"; + char name[MAXDNAME], qname[MAXDNAME]; + char *dname; + const char *fname; + const char *formerrmsg = "brain damage"; u_char newmsg[BUFSIZ]; u_char **dpp, *tp; time_t rtrip; @@ -144,6 +220,53 @@ ns_resp(msg, msglen) ntohs(qp->q_nsid), ntohs(qp->q_id))); /* + * Here we handle high level formatting problems by parsing the header. + */ + qdcount = ntohs(hp->qdcount); + ancount = ntohs(hp->ancount); + aucount = ntohs(hp->nscount); /* !!! */ + arcount = ntohs(hp->arcount); + free_addinfo(); /* sets addcount to zero */ + cp = msg + HFIXEDSZ; + dpp = dnptrs; + *dpp++ = msg; + if ((*cp & INDIR_MASK) == 0) + *dpp++ = cp; + *dpp = NULL; + if (qdcount == 1) { + n = dn_expand(msg, eom, cp, qname, sizeof(qname)); + if (n <= 0) { + formerrmsg = expandFailedQuery; + goto formerr; + } + cp += n; + GETSHORT(qtype, cp); + GETSHORT(qclass, cp); + if (cp > eom) { + formerrmsg = outofDataQuery; + goto formerr; + } + if (qp->q_msg && qp->q_msglen && + !res_nameinquery(qname, qtype, qclass, + qp->q_msg, qp->q_msg + qp->q_msglen)) { + char msgbuf[MAXDNAME*2]; + + sprintf(msgbuf, + "query section mismatch (%s %s %s)", + qname, p_class(qclass), p_type(qtype)); + formerrmsg = msgbuf; + goto formerr; + } + } else { + /* Pedantic. */ + qname[0] = '\0'; + qtype = 0; + qclass = 0; + } + + /* cp now points after the query section (if there was one). */ + + /* * Here we handle bad responses from servers. * Several possibilities come to mind: * The server is sick and returns SERVFAIL @@ -157,8 +280,12 @@ ns_resp(msg, msglen) || (hp->rcode == NXDOMAIN && !hp->aa) /* must accept this one if * we allow negative caching */ -#endif /*NCACHE*/ - || hp->opcode != QUERY) { +#endif + || (hp->opcode != QUERY +#ifdef BIND_NOTIFY + && hp->opcode != NS_NOTIFY_OP +#endif + )) { dprintf(2, (ddt, "resp: error (ret %d, op %d), dropped\n", hp->rcode, hp->opcode)); switch (hp->rcode) { @@ -174,63 +301,47 @@ ns_resp(msg, msglen) } return; } + + if (qdcount != 1) { + /* We don't generate or forward these (yet). */ + formerrmsg = notSingleQuery; + goto formerr; + } + #ifdef LAME_DELEGATION /* * Non-authoritative, no answer, no error */ - if (hp->rcode == NOERROR && !hp->aa && ntohs(hp->ancount) == 0 && - ntohs(hp->nscount) > 0) { - -#ifdef LAME_LOGGING - char qname[MAXDNAME]; -#endif /* LAME_LOGGING */ - + if (qdcount == 1 && hp->rcode == NOERROR && !hp->aa && ancount == 0 + && aucount > 0 +#ifdef BIND_NOTIFY + && hp->opcode != NS_NOTIFY_OP +#endif + ) { + u_char *tp; + int type, class; #ifdef DEBUG if (debug > 0) - fp_query(msg, ddt); + fp_nquery(msg, msglen, ddt); #endif - - cp = msg + HFIXEDSZ; - dpp = dnptrs; - *dpp++ = msg; - if ((*cp & INDIR_MASK) == 0) - *dpp++ = cp; - *dpp = NULL; - if (hp->qdcount) { -#ifdef LAME_LOGGING - n = dn_expand(msg, msg + msglen, cp, qname, - sizeof(qname)); - if (n <= 0) { - formerrmsg = expandFailedQuery; - goto formerr; - } -#else /* LAME_LOGGING */ - n = dn_skipname(cp, msg + msglen); - if (n <= 0) { - formerrmsg = skipnameFailedQuery; - goto formerr; - } -#endif /* LAME_LOGGING */ - cp += n; - GETSHORT(type, cp); - GETSHORT(class, cp); - if (cp - msg > msglen) { - formerrmsg = outofDataQuery; - goto formerr; - } -#ifdef LAME_LOGGING - } else { - strcpy(qname, "[No query name!]"); -#endif /* LAME_LOGGING */ - } - n = dn_expand(msg, msg + msglen, cp, name, sizeof name); + /* + * Since there is no answer section (ancount == 0), + * we must be pointing at the authority section (aucount > 0). + */ + tp = cp; + n = dn_expand(msg, eom, tp, name, sizeof name); if (n < 0) { formerrmsg = expandFailedAuth; goto formerr; } - cp += n; - GETSHORT(type, cp); - if (cp - msg > msglen) { + tp += n; + GETSHORT(type, tp); + if (tp >= eom) { + formerrmsg = outofDataAuth; + goto formerr; + } + GETSHORT(class, tp); + if (tp >= eom) { formerrmsg = outofDataAuth; goto formerr; } @@ -238,31 +349,31 @@ ns_resp(msg, msglen) /* * If the answer delegates us either to the same level in * the hierarchy or closer to the root, we consider this - * server lame. + * server lame. Note that for now we only log the message + * if the T_NS was C_IN, which is technically wrong (NS is + * visible in all classes) but necessary anyway (non-IN + * classes tend to not have good strong delegation graphs). */ if (type == T_NS && samedomain(qp->q_domain, name)) { nameserIncr(from_addr.sin_addr, nssRcvdLDel); #ifdef LAME_LOGGING - if (!haveComplained((char*)dhash((u_char*)name, - strlen(name)), - (char*)dhash((u_char*)qp->q_domain, - strlen(qp->q_domain) - ) - ) - ) { + if (class == C_IN && + !haveComplained((char*)nhash(name), + (char*)nhash(qp->q_domain))) syslog(LAME_LOGGING, -"Lame delegation to '%s' from [%s] (server for '%s'?) on query on name '%s'\n", - name, inet_ntoa(from_addr.sin_addr), - qp->q_domain, qname); - } + "Lame server on '%s' (in '%s'?): %s%s\n", + qname, qp->q_domain, + inet_etoa(&from_addr), + learntFrom(qp, &from_addr) + ); + #endif /* LAME_LOGGING */ return; } } #endif /* LAME_DELEGATION */ - #ifdef ALLOW_UPDATES if ( (hp->rcode == NOERROR) && (hp->opcode == UPDATEA || hp->opcode == UPDATED || @@ -297,25 +408,26 @@ ns_resp(msg, msglen) /* XXX: note bad ambiguity here. if one of our forwarders is also * a delegated server for some domain, then we will not update * the RTT information on any replies we get from those servers. + * Workaround: disable recursion on authoritative servers so that + * the ambiguity does not arise. */ /* - * If we were using nameservers, find the qinfo pointer and update + * If we weren't using a forwarder, find the qinfo pointer and update * the rtt and fact that we have called on this server before. */ if (fwd == (struct fwdinfo *)NULL) { struct timeval *stp; - for (n = 0, qs = qp->q_addr; n < qp->q_naddr; n++, qs++) + for (n = 0, qs = qp->q_addr; (u_int)n < qp->q_naddr; n++, qs++) if (qs->ns_addr.sin_addr.s_addr == from_addr.sin_addr.s_addr) break; - if (n >= qp->q_naddr) { + if ((u_int)n >= qp->q_naddr) { if (!haveComplained((char*)from_addr.sin_addr.s_addr, "unexpected source")) { - syslog(LOG_NOTICE, - "Response from unexpected source [%s].%d", - inet_ntoa(from_addr.sin_addr), - ntohs(from_addr.sin_port)); + syslog(LOG_INFO, + "Response from unexpected source (%s)", + inet_etoa(&from_addr)); } /* * We don't know who this response came from so it @@ -338,8 +450,8 @@ ns_resp(msg, msglen) */ dprintf(1, (ddt, "Response from unused address %s, assuming %s\n", - inet_ntoa(from_addr.sin_addr), - inet_ntoa(qs->ns_addr.sin_addr))); + inet_etoa(&from_addr), + inet_etoa(&qs->ns_addr))); /* XXX - catch aliases here */ } @@ -356,9 +468,10 @@ ns_resp(msg, msglen) (tt.tv_usec - stp->tv_usec) / 1000); } - dprintf(3, (ddt, "stime %d/%d now %d/%d rtt %d\n", - stp->tv_sec, stp->tv_usec, - tt.tv_sec, tt.tv_usec, rtrip)); + dprintf(3, (ddt, "stime %lu/%lu now %lu/%lu rtt %ld\n", + (u_long)stp->tv_sec, (u_long)stp->tv_usec, + (u_long)tt.tv_sec, (u_long)tt.tv_usec, + (long)rtrip)); /* prevent floating point overflow, limit to 1000 sec */ if (rtrip > 1000000) { @@ -389,8 +502,8 @@ ns_resp(msg, msglen) */ if (ns && qs->ns && (qp->q_nusedns < NSMAX)) { qp->q_usedns[qp->q_nusedns++] = qs->ns; - dprintf(2, (ddt, "NS #%d addr [%s] used, rtt %d\n", - n, inet_ntoa(qs->ns_addr.sin_addr), + dprintf(2, (ddt, "NS #%d addr %s used, rtt %d\n", + n, inet_etoa(&qs->ns_addr), ns->d_nstime)); } @@ -405,7 +518,7 @@ ns_resp(msg, msglen) * and are no longer the correct type. XXX */ - for (n = 0, qs = qp->q_addr; n < qp->q_naddr; n++, qs++) { + for (n = 0, qs = qp->q_addr; (u_int)n < qp->q_naddr; n++, qs++) { ns2 = qs->nsdata; if ((!ns2) || (ns2 == ns)) continue; @@ -423,46 +536,28 @@ ns_resp(msg, msglen) ns2->d_nstime = 1000000; } else ns2->d_nstime = (u_int32_t)(ns2->d_nstime * GAMMA); - dprintf(2, (ddt, "NS #%d [%s] rtt now %d\n", n, - inet_ntoa(qs->ns_addr.sin_addr), + dprintf(2, (ddt, "NS #%d %s rtt now %d\n", n, + inet_etoa(&qs->ns_addr), ns2->d_nstime)); } } - /*************************************************************/ - - /* - * Skip query section +#ifdef BIND_NOTIFY + /* for now, NOTIFY isn't defined for ANCOUNT!=0, AUCOUNT!=0, + * or ADCOUNT!=0. therefore the only real work to be done for + * a NOTIFY-QR is to remove it from the query queue. */ - free_addinfo(); /* sets addcount to zero */ - cp = msg + HFIXEDSZ; - dpp = dnptrs; - *dpp++ = msg; - if ((*cp & INDIR_MASK) == 0) - *dpp++ = cp; - *dpp = NULL; - type = class = 0; - if (hp->qdcount) { - n = dn_skipname(cp, msg + msglen); - if (n <= 0) { - formerrmsg = skipnameFailedQuery; - goto formerr; - } - cp += n; - GETSHORT(type, cp); - GETSHORT(class, cp); - if (cp - msg > msglen) { - formerrmsg = outofDataQuery; - goto formerr; - } + if (hp->opcode == NS_NOTIFY_OP) { + qremove(qp); + return; } +#endif + + /*************************************************************/ /* * 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; dprintf(3, (ddt, "resp: ancount %d, aucount %d, arcount %d\n", @@ -479,21 +574,21 @@ ns_resp(msg, msglen) if (ancount == 1 || (ancount == 0 && aucount > 0)) { c = aucount; do { - if (tp - msg >= msglen) { + if (tp >= eom) { formerrmsg = outofDataAnswer; goto formerr; } - n = dn_skipname(tp, msg + msglen); + n = dn_skipname(tp, eom); if (n <= 0) { formerrmsg = skipnameFailedAnswer; goto formerr; } tp += n; /* name */ GETSHORT(i, tp); /* type */ - tp += INT16SZ; /* class */ - tp += INT32SZ; /* ttl */ + tp += INT16SZ; /* class */ + tp += INT32SZ; /* ttl */ GETSHORT(count, tp); /* dlen */ - if (tp - msg > msglen - count) { + if (tp + count > eom) { formerrmsg = dlenOverrunAnswer; goto formerr; } @@ -522,38 +617,49 @@ ns_resp(msg, msglen) } if (qp->q_flags & Q_ZSERIAL) { - if ((hp->aa) - && (ancount != 0) - && (hp->rcode == NOERROR) - && (type == T_SOA) - && ((class == C_IN) || (class == C_HS)) - ) { /* XXX - should check name, too */ + if (hp->aa && ancount > 0 && hp->rcode == NOERROR && + qtype == T_SOA && ((qclass == C_IN) || (qclass == C_HS))) { int n; - u_int16_t dlen; + u_int16_t type, class, dlen; u_int32_t serial; u_char *tp = cp; - if (0 >= (n = dn_skipname(tp, msg + msglen))) { - formerrmsg = skipnameFailedAnswer; + n = dn_expand(msg, eom, tp, name, sizeof name); + if (n < 0) { + formerrmsg = expandFailedAnswer; goto formerr; } - tp += n /* name */ - + INT16SZ /* type */ - + INT16SZ /* class */ - + INT32SZ; /* ttl */ + tp += n; /* name */ + GETSHORT(type, tp); /* type */ + GETSHORT(class, tp); /* class */ + tp += INT32SZ; /* ttl */ GETSHORT(dlen, tp); /* dlen */ - - if (dlen < (5 * INT32SZ)) { + if (tp >= eom) { + formerrmsg = outofDataAnswer; + goto formerr; + } + if (strcasecmp(qname, name) || + qtype != type || + qclass != class) { + char msgbuf[MAXDNAME*2]; + + sprintf(msgbuf, + "qserial answer mismatch (%s %s %s)", + name, p_class(class), p_type(type)); + formerrmsg = msgbuf; + goto formerr; + } + if ((u_int)dlen < (5 * INT32SZ)) { formerrmsg = dlenUnderrunAnswer; goto formerr; } - if (0 >= (n = dn_skipname(tp, msg + msglen))) { + if (0 >= (n = dn_skipname(tp, eom))) { formerrmsg = skipnameFailedAnswer; goto formerr; } tp += n; /* mname */ - if (0 >= (n = dn_skipname(tp, msg + msglen))) { + if (0 >= (n = dn_skipname(tp, eom))) { formerrmsg = skipnameFailedAnswer; goto formerr; } @@ -585,7 +691,7 @@ ns_resp(msg, msglen) * DON'T do this now, as it will requery if data are already * in the cache (maybe later with negative caching). */ - if (hp->qdcount && type == T_CNAME && c == 0 && hp->rcode == NOERROR + if (type == T_CNAME && c == 0 && hp->rcode == NOERROR && !(qp->q_flags & Q_SYSTEM)) { dprintf(4, (ddt, "resp: leaving, no CNAME\n")); @@ -603,6 +709,8 @@ ns_resp(msg, msglen) else dbflags = DB_NOTAUTH | DB_NODATA | DB_NOHINTS; count = c; + if (qp->q_flags & Q_PRIMING) + dbflags |= DB_PRIMING; if (hp->tc) { count -= arcount; /* truncation had to affect this */ if (!arcount) { @@ -620,7 +728,7 @@ ns_resp(msg, msglen) old_ancount = ancount; for (i = 0; i < count; i++) { int VCode; - if (tempcp >= msg + msglen) { + if (tempcp >= eom) { free((char *)validatelist); formerrmsg = outofDataFinal; goto formerr; @@ -644,31 +752,34 @@ ns_resp(msg, msglen) */ n = update_msg(msg, &msglen, validatelist, count); free((char *)validatelist); - if (n < 0) + if (n < 0) { + formerrmsg = editFailed; goto formerr; + } count -= lesscount; - if (old_ancount && !hp->ancount) { + ancount = ntohs(hp->ancount); + if (old_ancount && !ancount) { /* We lost all the answers */ dprintf(1, (ddt, "validate count -> 0")); return; } - ancount = ntohs(hp->ancount); #endif for (i = 0; i < count; i++) { struct databuf *ns3; u_char cred; - if (cp >= msg + msglen) { + if (cp >= eom) { formerrmsg = outofDataFinal; goto formerr; } - if (i < ancount) { + if (i < ancount) cred = hp->aa ? DB_C_AUTH : DB_C_ANSWER; - } else { - cred = DB_C_ADDITIONAL; - } + else + cred = (qp->q_flags & Q_PRIMING) + ? DB_C_ANSWER + : DB_C_ADDITIONAL; ns3 = 0; n = doupdate(msg, msglen, cp, 0, &ns3, dbflags, cred); if (n < 0) { @@ -698,14 +809,25 @@ ns_resp(msg, msglen) check_root(); dprintf(3, (ddt, "resp: leaving, SYSQUERY ancount %d\n", ancount)); +#ifdef BIND_NOTIFY + if (qp->q_notifyzone != DB_Z_CACHE) { + struct zoneinfo *zp = &zones[qp->q_notifyzone]; + + /* + * Clear this first since sysnotify() might set it. + */ + qp->q_notifyzone = DB_Z_CACHE; + sysnotify(zp->z_origin, zp->z_class, T_SOA); + } +#endif qremove(qp); -#ifdef DATUMREFCNT +#ifdef DATUMREFCNT free_nsp(nsp); #endif return; } - if (cp > msg + msglen) { + if (cp > eom) { formerrmsg = outofDataAFinal; goto formerr; } @@ -715,13 +837,13 @@ ns_resp(msg, msglen) * sort them appropriately for the local context. */ if (ancount > 1 && (lp = local(&qp->q_from)) != NULL) - sort_response(tp, ancount, lp, msg + msglen); + sort_response(tp, ancount, lp, eom); /* * An answer to a T_ANY query or a successful answer to a * regular query with no indirection, then just return answer. */ - if ((hp->qdcount && type == T_ANY && ancount) || + if ((qtype == T_ANY && ancount) || (!cname && !qp->q_cmsglen && ancount)) { dprintf(3, (ddt, "resp: got as much answer as there is\n")); goto return_msg; @@ -732,7 +854,7 @@ ns_resp(msg, msglen) */ if (!ancount && (!nscount || hp->rcode == NXDOMAIN) && - (hp->aa || fwd || class == C_ANY)) { + (hp->aa || fwd || qclass == C_ANY)) { /* we have an authoritative NO */ dprintf(3, (ddt, "resp: leaving auth NO\n")); if (qp->q_cmsglen) { @@ -784,8 +906,8 @@ ns_resp(msg, msglen) cp += n + QFIXEDSZ; buflen = sizeof(newmsg) - (cp - newmsg); -try_again: - dprintf(1, (ddt, "resp: nlookup(%s) type=%d\n", dname, type)); + try_again: + dprintf(1, (ddt, "resp: nlookup(%s) qtype=%d\n", dname, qtype)); fname = ""; htp = hashtab; /* lookup relative to root */ np = nlookup(dname, &htp, &fname, 0); @@ -796,13 +918,13 @@ try_again: foundname++; count = cp - newmsg; - n = finddata(np, class, type, hp, &dname, &buflen, &count); + n = finddata(np, qclass, qtype, hp, &dname, &buflen, &count); if (n == 0) goto fetch_ns; /* NO data available */ cp += n; buflen -= n; hp->ancount += count; - if (fname != dname && type != T_CNAME && type != T_ANY) { + if (fname != dname && qtype != T_CNAME && qtype != T_ANY) { cname++; goto try_again; } @@ -812,7 +934,7 @@ try_again: "resp: foundname=%d, count=%d, founddata=%d, cname=%d\n", foundname, count, founddata, cname)); -fetch_ns: + fetch_ns: hp->ancount = htons(hp->ancount); /* * Look for name servers to refer to and fill in the authority @@ -822,13 +944,13 @@ fetch_ns: #ifdef DATUMREFCNT free_nsp(nsp); #endif - switch (findns(&np, class, nsp, &count, 0)) { + switch (findns(&np, qclass, nsp, &count, 0)) { case NXDOMAIN: /* shouldn't happen */ dprintf(3, (ddt, "req: leaving (%s, rcode %d)\n", dname, hp->rcode)); if (!foundname) hp->rcode = NXDOMAIN; - if (class != C_ANY) { + if (qclass != C_ANY) { hp->aa = 1; /* XXX: should return SOA if founddata == 0, * but old named's are confused by an SOA @@ -864,40 +986,45 @@ fetch_ns: * to iterate to try and get it. First, infinite loop avoidance. */ if (qp->q_nqueries++ > MAXQUERIES) { - dprintf(1, - (ddt, - "resp: MAXQUERIES exceeded (%s, class %d, type %d)\n", - dname, class, type - ) - ); - syslog(LOG_NOTICE, - "MAXQUERIES exceeded, possible data loop in resolving (%s)", - dname); + dprintf(1, (ddt, "resp: MAXQUERIES exceeded (%s %s %s)\n", + dname, p_class(qclass), p_type(qtype))); + syslog(LOG_INFO, + "MAXQUERIES exceeded, possible data loop in resolving (%s)", + dname); goto servfail; } /* Reset the query control structure */ #ifdef DATUMREFCNT - for (i = 0 ; i < qp->q_naddr ; i++) { - if ((--(qp->q_addr[i].ns->d_rcnt))) { - dprintf(1 ,(ddt, "ns_resp: ns %s rcnt %d\n", - qp->q_addr[i].ns->d_data, - qp->q_addr[i].ns->d_rcnt)); - } else { - dprintf(1 ,(ddt, "ns_resp: ns %s rcnt %d delayed\n", - qp->q_addr[i].ns->d_data, - qp->q_addr[i].ns->d_rcnt)); - free((char*)qp->q_addr[i].ns); - } - if ((--(qp->q_addr[i].nsdata->d_rcnt))) { - dprintf(1 ,(ddt, "ns_resp: nsdata %08.8X rcnt %d\n", - *(int32_t *)(qp->q_addr[i].nsdata->d_data), - qp->q_addr[i].nsdata->d_rcnt)); - } else { - dprintf(1 ,(ddt, "ns_resp: nsdata %08.8X rcnt %d delayed\n", - *(int32_t *)(qp->q_addr[i].nsdata->d_data), - qp->q_addr[i].nsdata->d_rcnt)); - free((char*)qp->q_addr[i].nsdata); + /* XXX - this code should be shared with qfree()'s similar logic. */ + for (i = 0; (u_int)i < qp->q_naddr; i++) { + static const char freed[] = "freed", busy[] = "busy"; + const char *result; + + if (qp->q_addr[i].ns != NULL) { + if ((--(qp->q_addr[i].ns->d_rcnt))) + result = busy; + else { + free((char*)qp->q_addr[i].ns); + result = freed; + } + dprintf(1, (ddt, "ns_resp: ns %s rcnt %d (%s)\n", + qp->q_addr[i].ns->d_data, + qp->q_addr[i].ns->d_rcnt, + result)); + } + if (qp->q_addr[i].nsdata != NULL) { + if ((--(qp->q_addr[i].nsdata->d_rcnt))) + result = busy; + else { + free((char*)qp->q_addr[i].nsdata); + result = freed; + } + dprintf(1, (ddt, + "ns_resp: nsdata %08.8X rcnt %d (%s)\n", + *(int32_t *)(qp->q_addr[i].nsdata->d_data), + qp->q_addr[i].nsdata->d_rcnt, + result)); } } #endif @@ -917,7 +1044,7 @@ fetch_ns: goto return_newmsg; goto servfail; } - for (n = 0; n < qp->q_naddr; n++) + for (n = 0; (u_int)n < qp->q_naddr; n++) qp->q_addr[n].stime.tv_sec = 0; if (!qp->q_fwd) qp->q_addr[0].stime = tt; @@ -933,39 +1060,43 @@ fetch_ns: if (qp->q_msg) (void) free(qp->q_msg); if ((qp->q_msg = (u_char *)malloc(BUFSIZ)) == NULL) { - dprintf(1, (ddt, "resp: malloc error\n")); + syslog(LOG_NOTICE, "resp: malloc error\n"); + goto servfail; + } + n = res_mkquery(QUERY, dname, qclass, qtype, + NULL, 0, NULL, qp->q_msg, BUFSIZ); + if (n < 0) { + syslog(LOG_INFO, "resp: res_mkquery(%s) failed", + dname); goto servfail; } - qp->q_msglen = res_mkquery(QUERY, dname, class, - type, NULL, 0, NULL, - qp->q_msg, BUFSIZ); + qp->q_msglen = n; hp = (HEADER *) qp->q_msg; hp->rd = 0; } else - hp = (HEADER *)qp->q_msg; - hp->id = qp->q_nsid = htons((u_int16_t)++nsid); + hp = (HEADER *) qp->q_msg; + hp->id = qp->q_nsid = htons(nsid_next()); if (qp->q_fwd) hp->rd = 1; unsched(qp); schedretry(qp, retrytime(qp)); nsa = Q_NEXTADDR(qp, 0); - dprintf(1, (ddt, "resp: forw -> [%s].%d ds=%d nsid=%d id=%d %dms\n", - inet_ntoa(nsa->sin_addr), - ntohs(nsa->sin_port), ds, + dprintf(1, (ddt, "resp: forw -> %s ds=%d nsid=%d id=%d %dms\n", + inet_etoa(nsa), ds, ntohs(qp->q_nsid), ntohs(qp->q_id), (qp->q_addr[0].nsdata != NULL) ? qp->q_addr[0].nsdata->d_nstime : (-1))); #ifdef DEBUG if (debug >= 10) - fp_query(msg, ddt); + fp_nquery(qp->q_msg, qp->q_msglen, ddt); #endif - if (sendto(ds, qp->q_msg, qp->q_msglen, 0, + if (sendto(ds, (char*)qp->q_msg, qp->q_msglen, 0, (struct sockaddr *)nsa, sizeof(struct sockaddr_in)) < 0) { if (!haveComplained((char*)nsa->sin_addr.s_addr, sendtoStr)) - syslog(LOG_NOTICE, "ns_resp: sendto([%s].%d): %m", - inet_ntoa(nsa->sin_addr), ntohs(nsa->sin_port)); + syslog(LOG_INFO, "ns_resp: sendto(%s): %m", + inet_etoa(nsa)); nameserIncr(nsa->sin_addr, nssSendtoErr); } hp->rd = 0; /* leave set to 0 for dup detection */ @@ -977,37 +1108,25 @@ fetch_ns: #endif return; -formerr: - dprintf(3, (ddt, - "FORMERR resp() from [%s].%d size err %d, msglen %d\n", - inet_ntoa(from_addr.sin_addr), - ntohs(from_addr.sin_port), - cp - msg, msglen)); + formerr: if (!haveComplained((char*)from_addr.sin_addr.s_addr, - (char*)dhash((u_char *)formerrmsg, - strlen(formerrmsg) - ) - ) - ) { - syslog(LOG_INFO, "Malformed response from [%s].%d (%s)\n", - inet_ntoa(from_addr.sin_addr), - ntohs(from_addr.sin_port), - formerrmsg); - } + (char*)nhash(formerrmsg))) + syslog(LOG_INFO, "Malformed response from %s (%s)\n", + inet_etoa(&from_addr), formerrmsg); nameserIncr(from_addr.sin_addr, nssSentFErr); #ifdef DATUMREFCNT free_nsp(nsp); #endif return; -return_msg: + return_msg: nameserIncr(from_addr.sin_addr, nssRcvdFwdR); nameserIncr(qp->q_from.sin_addr, nssSentFwdR); /* The "standard" return code */ hp->qr = 1; hp->id = qp->q_id; hp->rd = 1; - hp->ra = 1; + hp->ra = (NoRecurse == 0); (void) send_msg(msg, msglen, qp); qremove(qp); #ifdef DATUMREFCNT @@ -1015,17 +1134,22 @@ return_msg: #endif return; -return_newmsg: + return_newmsg: nameserIncr(qp->q_from.sin_addr, nssSentAns); - if (addcount) { - n = doaddinfo(hp, cp, buflen); - cp += n; - buflen -= n; - } + +#ifdef XSTATS + if (!hp->aa) + nameserIncr(qp->q_from.sin_addr, nssSentNaAns); + if (hp->rcode == NXDOMAIN) + nameserIncr(qp->q_from.sin_addr, nssSentNXD); +#endif + n = doaddinfo(hp, cp, buflen); + cp += n; + buflen -= n; hp->qr = 1; hp->id = qp->q_id; hp->rd = 1; - hp->ra = 1; + hp->ra = (NoRecurse == 0); (void) send_msg(newmsg, cp - newmsg, qp); qremove(qp); #ifdef DATUMREFCNT @@ -1033,14 +1157,14 @@ return_newmsg: #endif return; -servfail: + servfail: nameserIncr(qp->q_from.sin_addr, nssSentFail); hp = (HEADER *)(cname ? qp->q_cmsg : qp->q_msg); hp->rcode = SERVFAIL; + hp->qr = 1; hp->id = qp->q_id; hp->rd = 1; - hp->ra = 1; - hp->qr = 1; + hp->ra = (NoRecurse == 0); (void) send_msg((u_char *)hp, (cname ? qp->q_cmsglen : qp->q_msglen), qp); qremove(qp); @@ -1074,8 +1198,8 @@ doupdate(msg, msglen, rrp, zone, savens, flags, cred) int zonenum; #endif - dprintf(3, (ddt, "doupdate(zone %d, savens %x, flags %x)\n", - zone, savens, flags)); + dprintf(3, (ddt, "doupdate(zone %d, savens %#lx, flags %#lx)\n", + zone, (u_long)savens, (u_long)flags)); cp = rrp; if ((n = dn_expand(msg, msg + msglen, cp, dname, sizeof dname)) < 0) { @@ -1109,6 +1233,7 @@ doupdate(msg, msglen, rrp, zone, savens, flags, cred) case T_X25: case T_ISDN: case T_NSAP: + case T_LOC: #ifdef ALLOW_T_UNSPEC case T_UNSPEC: #endif @@ -1188,6 +1313,33 @@ doupdate(msg, msglen, rrp, zone, savens, flags, cred) cp1 = data; break; + case T_PX: + /* grab preference */ + bcopy(cp, data, INT16SZ); + cp1 = data + INT16SZ; + cp += INT16SZ; + + /* get MAP822 name */ + n = dn_expand(msg, msg + msglen, cp, (char *)cp1, + sizeof data - INT16SZ); + if (n < 0) { + hp->rcode = FORMERR; + return (-1); + } + cp += n; + cp1 += (n = strlen((char *)cp1) + 1); + n1 = sizeof(data) - n; + n = dn_expand(msg, msg + msglen, cp, (char *)cp1, n1); + if (n < 0) { + hp->rcode = FORMERR; + return (-1); + } + cp += n; + cp1 += strlen((char *)cp1) + 1; + n = cp1 - data; + cp1 = data; + break; + default: dprintf(3, (ddt, "unknown type %d\n", type)); return ((cp - rrp) + dlen); @@ -1196,7 +1348,7 @@ doupdate(msg, msglen, rrp, zone, savens, flags, cred) dprintf(1, (ddt, "update type %d: %d bytes is too much data\n", type, n)); - hp->rcode = NOCHANGE; /* XXX - FORMERR ??? */ + hp->rcode = FORMERR; return (-1); } @@ -1379,19 +1531,17 @@ doupdate(msg, msglen, rrp, zone, savens, flags, cred) if (!haveComplained((char*)from_addr.sin_addr.s_addr, "bogus root NS")) syslog(LOG_NOTICE, - "bogus root NS %s rcvd from [%s] on query for \"%s\"", - data, inet_ntoa(from_addr.sin_addr), - qname); + "bogus root NS %s rcvd from %s on query for \"%s\"", + data, inet_etoa(&from_addr), qname); return (cp - rrp); } #ifdef BOGUSNS if (bogusns) { if (!haveComplained((char*)from_addr.sin_addr.s_addr, "bogus nonroot NS")) - syslog(LOG_NOTICE, - "bogus nonroot NS %s rcvd from [%s] on query for \"%s\"", - data, inet_ntoa(from_addr.sin_addr), - qname); + syslog(LOG_INFO, + "bogus nonroot NS %s rcvd from %s on query for \"%s\"", + data, inet_etoa(&from_addr), qname); return (cp - rrp); } #endif @@ -1405,9 +1555,9 @@ doupdate(msg, msglen, rrp, zone, savens, flags, cred) if ((n = db_update(dname, dp, dp, flags, hashtab)) != OK) { #ifdef DEBUG if (debug && (n != DATAEXISTS)) - fprintf(ddt,"update failed (%d)\n", n); + fprintf(ddt, "update failed (%d)\n", n); else if (debug >= 3) - fprintf(ddt,"update failed (DATAEXISTS)\n"); + fprintf(ddt, "update failed (DATAEXISTS)\n"); #endif free((char *)dp); } else if (type == T_NS && savens != NULL) @@ -1425,39 +1575,43 @@ send_msg(msg, msglen, qp) return (1); #ifdef DEBUG if (debug) { - fprintf(ddt,"send_msg -> [%s] (%s %d %d) id=%d\n", - inet_ntoa(qp->q_from.sin_addr), + fprintf(ddt,"send_msg -> %s (%s %d) id=%d\n", + inet_etoa(&qp->q_from), qp->q_stream == QSTREAM_NULL ? "UDP" : "TCP", qp->q_stream == QSTREAM_NULL ? qp->q_dfd : qp->q_stream->s_rfd, - ntohs(qp->q_from.sin_port), ntohs(qp->q_id)); } if (debug>4) { struct qinfo *tqp; - for (tqp = qhead; tqp!=QINFO_NULL; tqp = tqp->q_link) { - fprintf(ddt, "qp %x q_id: %d q_nsid: %d q_msglen: %d ", - tqp, tqp->q_id,tqp->q_nsid,tqp->q_msglen); - fprintf(ddt,"q_naddr: %d q_curaddr: %d\n", tqp->q_naddr, - tqp->q_curaddr); - fprintf(ddt,"q_next: %x q_link: %x\n", qp->q_next, - qp->q_link); + for (tqp = nsqhead; tqp!=QINFO_NULL; tqp = tqp->q_link) { + fprintf(ddt, + "qp %#lx q_id: %d q_nsid: %d q_msglen: %d ", + (u_long)tqp, tqp->q_id, + tqp->q_nsid, tqp->q_msglen); + fprintf(ddt, + "q_naddr: %d q_curaddr: %d\n", + tqp->q_naddr, tqp->q_curaddr); + fprintf(ddt, "q_next: %#lx q_link: %#lx\n", + (u_long)qp->q_next, (u_long)qp->q_link); } } if (debug >= 10) - fp_query(msg, ddt); + fp_nquery(msg, msglen, ddt); #endif /* DEBUG */ if (qp->q_stream == QSTREAM_NULL) { - if (sendto(qp->q_dfd, msg, msglen, 0, + if (sendto(qp->q_dfd, (char*)msg, msglen, 0, (struct sockaddr *)&qp->q_from, sizeof(qp->q_from)) < 0) { if (!haveComplained((char*)qp->q_from.sin_addr.s_addr, sendtoStr)) - syslog(LOG_NOTICE, - "send_msg: sendto([%s].%d): %m", - inet_ntoa(qp->q_from.sin_addr), - ntohs(qp->q_from.sin_port)); +#if defined(SPURIOUS_ECONNREFUSED) + if (errno != ECONNREFUSED) +#endif + syslog(LOG_INFO, + "send_msg: sendto(%s): %m", + inet_etoa(&qp->q_from)); nameserIncr(qp->q_from.sin_addr, nssSendtoErr); return (1); } @@ -1484,7 +1638,7 @@ prime(class, type, oqp) sizeof(dname)) < 0) return; dprintf(2, (ddt, "prime: %s\n", dname)); - (void) sysquery(dname, class, type, NULL, 0); + (void) sysquery(dname, class, type, NULL, 0, QUERY); } #endif @@ -1496,7 +1650,7 @@ prime_cache() dprintf(1, (ddt, "prime_cache: priming = %d\n", priming)); if (!priming && fcachetab->h_tab[0] != NULL && !forward_only) { priming++; - if ((qp = sysquery("", C_IN, T_NS, NULL, 0)) == NULL) + if (!(qp = sysquery("", C_IN, T_NS, NULL, 0, QUERY))) priming = 0; else qp->q_flags |= (Q_SYSTEM | Q_PRIMING); @@ -1505,12 +1659,156 @@ prime_cache() return; } +#ifdef BIND_NOTIFY +struct notify * +findNotifyPeer(zp, ina) + const struct zoneinfo *zp; + struct in_addr ina; +{ + register struct notify *ap; + + for (ap = zp->z_notifylist; ap; ap = ap->next) + if (ap->addr.s_addr == ina.s_addr) + break; + return (ap); +} + +/* sysnotify(dname, class, type) + * cause a NOTIFY request to be sysquery()'d to each secondary server + * of the zone that "dname" is within. + */ +void +sysnotify(dname, class, type) + const char *dname; + int class, type; +{ + char *soaname, *zname; + const char *fname; + register struct databuf *dp; + struct in_addr nss[NSMAX]; + int nns, na, zn, nsc; + struct hashbuf *htp; + struct zoneinfo *zp; + struct notify *ap; + struct namebuf *np; + + htp = hashtab; + np = nlookup(dname, &htp, &fname, 0); + if (!np) + panic(-1, "sysnotify: can't find name"); + zn = findMyZone(np, class); + if (zn == DB_Z_CACHE) + panic(-1, "sysnotify: not auth zone"); + zp = &zones[zn]; + if (zp->z_type != Z_PRIMARY && zp->z_type != Z_SECONDARY) + panic(-1, "sysnotify: not pri/sec"); + zname = zp->z_origin; +/* +**DBG** syslog(LOG_INFO, "sysnotify: found \"%s\" in \"%s\" (%s)", +**DBG** dname, zname, zoneTypeString(zp)); +*/ + nns = na = 0; + /* + * Send to recent AXFR peers. + */ + for (ap = zp->z_notifylist; ap; ap = ap->next) { + if (tt.tv_sec - ap->last >= zp->z_refresh) { + /* XXX - probably should do GC here. */ + continue; + } + nss[0] = ap->addr; + nsc = 1; + nns++; + na++; + sysquery(dname, class, T_SOA, nss, nsc, NS_NOTIFY_OP); + } + if (zp->z_type != Z_PRIMARY) + goto done; + /* + * Master. + */ + htp = hashtab; + np = nlookup(zname, &htp, &fname, 0); + if (!np) + panic(-1, "sysnotify: found name but not zone"); + soaname = NULL; + for (dp = np->n_data; dp; dp = dp->d_next) { + if (!dp->d_zone || !match(dp, class, T_SOA)) + continue; + if (soaname) { + syslog(LOG_NOTICE, "multiple SOA's for zone \"%s\"?", + zname); + return; + } + soaname = (char *) dp->d_data; + } + if (!soaname) { + syslog(LOG_NOTICE, "no SOA found for zone \"%s\"", zname); + return; + } + + for (dp = np->n_data; dp; dp = dp->d_next) { + register struct databuf *adp; + struct namebuf *anp; + + if (!dp->d_zone || !match(dp, class, T_NS)) + continue; + /* NS RDATA is server name. */ + if (strcasecmp((char*)dp->d_data, soaname) == 0) + continue; + htp = hashtab; + anp = nlookup((char*)dp->d_data, &htp, &fname, 0); + if (!anp) { + syslog(LOG_INFO, "sysnotify: can't nlookup(%s)?", + (char*)dp->d_data); + continue; + } + nsc = 0; + for (adp = anp->n_data; adp; adp = adp->d_next) { + struct in_addr ina; + if (!match(adp, class, T_A)) + continue; + ina = data_inaddr(adp->d_data); + /* Don't send to things we handled above. */ + ap = findNotifyPeer(zp, ina); + if (ap && tt.tv_sec - ap->last < zp->z_refresh) + goto nextns; + if (nsc < NSMAX) + nss[nsc++] = ina; + } /*next A*/ + if (nsc == 0) { + struct qinfo *qp; + + qp = sysquery((char*)dp->d_data, /*NS name*/ + class, /*XXX: C_IN?*/ + T_A, 0, 0, QUERY); + if (qp) + qp->q_notifyzone = zn; + continue; + } + (void) sysquery(dname, class, T_SOA, nss, nsc, NS_NOTIFY_OP); + nns++; + na += nsc; + nextns:; + } /*next NS*/ + done: + if (nns || na) { + char tmp[MAXDNAME*2]; + + /* Many syslog()'s only take 5 args. */ + sprintf(tmp, "%s %s %s", dname, p_class(class), p_type(type)); + syslog(LOG_INFO, "Sent NOTIFY for \"%s\" (%s); %d NS, %d A", + tmp, zname, nns, na); + } +} +#endif /*BIND_NOTIFY*/ + struct qinfo * -sysquery(dname, class, type, nss, nsc) - char *dname; +sysquery(dname, class, type, nss, nsc, opcode) + const char *dname; int class, type; struct in_addr *nss; - int nsc; + int nsc, opcode; { register struct qinfo *qp, *oqp; register HEADER *hp; @@ -1518,14 +1816,14 @@ sysquery(dname, class, type, nss, nsc) struct databuf *nsp[NSMAX]; struct hashbuf *htp; struct sockaddr_in *nsa; - char *fname; - int count; + const char *fname; + int n, count; #ifdef DATUMREFCNT nsp[0] = NULL; #endif - dprintf(3, (ddt, "sysquery(%s, %d, %d, 0x%x, %d)\n", - dname, class, type, nss, nsc)); + dprintf(3, (ddt, "sysquery(%s, %d, %d, %#lx, %d)\n", + dname, class, type, (u_long)nss, nsc)); qp = qnew(); if (nss && nsc) { @@ -1535,23 +1833,24 @@ sysquery(dname, class, type, nss, nsc) if (priming && dname[0] == '\0') { np = NULL; } else if ((np = nlookup(dname, &htp, &fname, 1)) == NULL) { - dprintf(1, (ddt, - "sysquery: nlookup error on %s?\n", - dname)); + syslog(LOG_INFO, "sysquery: nlookup error on %s?", + dname); + err1: qfree(qp); - return (0); + return (NULL); } - switch (findns(&np, class, nsp, &count, 0)) { + n = findns(&np, class, nsp, &count, 0); + switch (n) { case NXDOMAIN: case SERVFAIL: - dprintf(1, (ddt, - "sysquery: findns error on %s?\n", dname)); - qfree(qp); + syslog(LOG_DEBUG, "sysquery: findns error (%d) on %s?", + n, dname); + err2: #ifdef DATUMREFCNT free_nsp(nsp); #endif - return (0); + goto err1; } } @@ -1569,33 +1868,39 @@ sysquery(dname, class, type, nss, nsc) #endif /* LAME_DELEGATION */ if ((qp->q_msg = (u_char *)malloc(BUFSIZ)) == NULL) { - qfree(qp); -#ifdef DATUMREFCNT - free_nsp(nsp); -#endif - return (0); + syslog(LOG_NOTICE, "sysquery: malloc failed"); + goto err2; + } + n = res_mkquery(opcode, dname, class, + type, NULL, 0, NULL, + qp->q_msg, BUFSIZ); + if (n < 0) { + syslog(LOG_INFO, "sysquery: res_mkquery(%s) failed", dname); + goto err2; } - qp->q_msglen = res_mkquery(QUERY, dname, class, - type, NULL, 0, NULL, - qp->q_msg, BUFSIZ); + qp->q_msglen = n; hp = (HEADER *) qp->q_msg; - hp->id = qp->q_nsid = htons((u_int16_t)++nsid); + hp->id = qp->q_nsid = htons(nsid_next()); hp->rd = (qp->q_fwd ? 1 : 0); /* First check for an already pending query for this data */ - for (oqp = qhead; oqp != QINFO_NULL; oqp = oqp->q_link) { + for (oqp = nsqhead; oqp != QINFO_NULL; oqp = oqp->q_link) { if ((oqp != qp) && (oqp->q_msglen == qp->q_msglen) && bcmp((char *)oqp->q_msg+2, qp->q_msg+2, qp->q_msglen-2) == 0 ) { - dprintf(3, (ddt, "sysquery: duplicate\n")); - qfree(qp); -#ifdef DATUMREFCNT - free_nsp(nsp); -#endif - return (0); +#ifdef BIND_NOTIFY + /* XXX - need fancier test to suppress duplicate + * NOTIFYs to the same server (compare nss?) + */ + if (opcode != NS_NOTIFY_OP) +#endif /*BIND_NOTIFY*/ + { + dprintf(3, (ddt, "sysquery: duplicate\n")); + goto err2; + } } } @@ -1616,20 +1921,19 @@ sysquery(dname, class, type, nss, nsc) } qp->q_naddr = nsc; } else { - if ((count = nslookup(nsp, qp, dname, "sysquery")) <= 0) { - if (count < 0) { - dprintf(1, (ddt, - "sysquery: nslookup reports danger\n")); - } else { - dprintf(1, (ddt, - "sysquery: no addrs found for NS's\n")); + count = nslookup(nsp, qp, dname, "sysquery"); + if (count <= 0) { + if (count < 0) + syslog(LOG_INFO, + "sysquery: nslookup reports danger (%s)", + dname); + else + /* "." domain gets LOG_WARNING here. */ + syslog(dname[0] ? LOG_INFO : LOG_WARNING, + "sysquery: no addrs found for NS (%s)", + dname); + goto err2; } - qfree(qp); -#ifdef DATUMREFCNT - free_nsp(nsp); -#endif - return (0); - } } schedretry(qp, retrytime(qp)); @@ -1638,21 +1942,20 @@ sysquery(dname, class, type, nss, nsc) nsa = Q_NEXTADDR(qp, 0); dprintf(1, (ddt, - "sysquery: send -> [%s].%d dfd=%d nsid=%d id=%d retry=%ld\n", - inet_ntoa(nsa->sin_addr), - ntohs(nsa->sin_port), qp->q_dfd, + "sysquery: send -> %s dfd=%d nsid=%d id=%d retry=%ld\n", + inet_etoa(nsa), qp->q_dfd, ntohs(qp->q_nsid), ntohs(qp->q_id), qp->q_time)); #ifdef DEBUG if (debug >= 10) - fp_query(qp->q_msg, ddt); + fp_nquery(qp->q_msg, qp->q_msglen, ddt); #endif - if (sendto(qp->q_dfd, qp->q_msg, qp->q_msglen, 0, + if (sendto(qp->q_dfd, (char*)qp->q_msg, qp->q_msglen, 0, (struct sockaddr *)nsa, sizeof(struct sockaddr_in)) < 0) { if (!haveComplained((char*)nsa->sin_addr.s_addr, sendtoStr)) - syslog(LOG_NOTICE, "sysquery: sendto([%s].%d): %m", - inet_ntoa(nsa->sin_addr), ntohs(nsa->sin_port)); + syslog(LOG_INFO, "sysquery: sendto(%s): %m", + inet_etoa(nsa)); nameserIncr(nsa->sin_addr, nssSendtoErr); } nameserIncr(nsa->sin_addr, nssSentSysQ); @@ -1678,7 +1981,7 @@ check_root() if (np->n_dname[0] == '\0') break; if (np == NULL) { - syslog(LOG_ERR, "check_root: Can't find root!\n"); + syslog(LOG_NOTICE, "check_root: Can't find root!\n"); return; } for (dp = np->n_data; dp != NULL; dp = dp->d_next) @@ -1686,9 +1989,9 @@ check_root() count++; dprintf(1, (ddt, "%d root servers\n", count)); if (count < MINROOTS) { - syslog(LOG_WARNING, + syslog(LOG_NOTICE, "check_root: %d root servers after query to root server < min", - count); + count); return; } pdp = NULL; @@ -1719,7 +2022,7 @@ check_ns() struct hashbuf *htp; char *dname; int found_arr; - char *fname; + const char *fname; time_t curtime; dprintf(2, (ddt, "check_ns()\n")); @@ -1738,9 +2041,9 @@ check_ns() 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); + "check_ns: %s: not found %s %#lx\n", + dname, fname, (u_long)tnp)); + sysquery(dname, dp->d_class, T_A, NULL, 0, QUERY); continue; } /* look for name server addresses */ @@ -1762,7 +2065,7 @@ check_ns() found_arr++; } if (!found_arr) - (void) sysquery(dname, dp->d_class, T_A, NULL, 0); + sysquery(dname, dp->d_class, T_A, NULL, 0, QUERY); } } } @@ -1770,7 +2073,7 @@ check_ns() /* int findns(npp, class, nsp, countp, flag) * Find NS' or an SOA * npp, class: - * dname whose least-superior NS is wanted + * dname whose most enclosing NS is wanted * nsp, countp: * result array and count; array will also be NULL terminated * flag: @@ -1802,7 +2105,7 @@ findns(npp, class, nsp, countp, flag) else htp = hashtab; -try_again: + try_again: if (htp == fcachetab) needs_prime_cache = 1; while (np == NULL && htp != NULL) { @@ -1814,13 +2117,19 @@ try_again: htp = (htp == hashtab ? fcachetab : NULL); /* Fallback */ } while (np != NULL) { - dprintf(5, (ddt, "findns: np 0x%x '%s'\n", np, np->n_dname)); + dprintf(5, (ddt, "findns: np %#lx '%s'\n", + (u_long)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)) { + if (dp->d_zone != 0 && +#ifdef PURGE_ZONE + ((zones[dp->d_zone].z_type == Z_PRIMARY) || + (zones[dp->d_zone].z_type == Z_SECONDARY)) && +#endif + match(dp, class, T_SOA)) { dprintf(3, (ddt, "findns: SOA found\n")); if (zones[dp->d_zone].z_flags & Z_AUTH) { *npp = np; @@ -1846,6 +2155,10 @@ try_again: for (dp = np->n_data; dp != NULL; dp = dp->d_next) { if (!match(dp, class, T_NS)) continue; +#ifdef NCACHE + if (dp->d_rcode) + continue; +#endif /* * Don't use records that may become invalid to * reference later when we do the rtt computation. @@ -1854,12 +2167,18 @@ try_again: * XXX: this is horribly bogus. */ if ((dp->d_zone == 0) && +#ifdef DATUMREFCNT + (dp->d_ttl < tt.tv_sec) && +#else (dp->d_ttl < (tt.tv_sec+900)) && +#endif !(dp->d_flags & DB_F_HINT)) { dprintf(1, (ddt, "findns: stale entry '%s'\n", np->n_dname)); /* Cache invalidate the NS RR's. */ +#ifndef DATUMREFCNT if (dp->d_ttl < tt.tv_sec) +#endif delete_all(np, class, T_NS); goto try_parent; } @@ -1888,7 +2207,7 @@ try_parent: p_class(class))); if ((unsigned)class < MAXCLASS && norootlogged[class] == 0) { norootlogged[class] = 1; - syslog(LOG_ERR, "No root nameservers for class %s\n", + syslog(LOG_INFO, "No root nameservers for class %s\n", p_class(class)); } return (SERVFAIL); @@ -1936,6 +2255,10 @@ finddata(np, class, type, hp, dnamep, lenp, countp) #endif /*ROUND_ROBIN*/ buflen = *lenp; +#ifdef DEBUG + if (buflen > PACKETSZ) + dprintf(1, (ddt, "finddata(): buflen=%d\n", buflen)); +#endif cp = ((char *)hp) + *countp; for (dp = np->n_data; dp != NULL; dp = dp->d_next) { if (!wanted(dp, class, type)) { @@ -1986,9 +2309,9 @@ finddata(np, class, type, hp, dnamep, lenp, countp) /* * This should not happen, yet it does... */ - syslog(LOG_WARNING, + syslog(LOG_INFO, "NODATA & data for \"%s\" type %d class %d", - *dnamep, type, class); + *dnamep, type, class); continue; } if (type != T_ANY) { @@ -2005,9 +2328,9 @@ finddata(np, class, type, hp, dnamep, lenp, countp) /* * This should not happen, yet it might... */ - syslog(LOG_WARNING, + syslog(LOG_INFO, "NXDOMAIN & data for \"%s\" type %d class %d", - *dnamep, type, class); + *dnamep, type, class); continue; } if (type != T_ANY) { @@ -2040,7 +2363,7 @@ finddata(np, class, type, hp, dnamep, lenp, countp) if (dp->d_type == T_CNAME) { if (type != T_ANY) { /* or T_NS? */ *dnamep = (caddr_t) dp->d_data; - if (dp->d_zone && + if (dp->d_zone != DB_Z_CACHE && (zones[dp->d_zone].z_flags & Z_AUTH) && class != C_ANY) /* XXX */ hp->aa = 1; /* XXX */ @@ -2074,9 +2397,9 @@ wanted(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)); + dprintf(3, (ddt, "wanted(%#lx, %d, %d) [%s %s]\n", + (u_long)dp, class, type, + p_class(dp->d_class), p_type(dp->d_type))); if (dp->d_class != class && class != C_ANY) return (0); @@ -2145,7 +2468,7 @@ add_data(np, dpp, cp, buflen) register int n, count = 0; getname(np, dname, sizeof(dname)); - for(dp = *dpp++; dp != NULL; dp = *dpp++) { + for (dp = *dpp++; dp != NULL; dp = *dpp++) { if (stale(dp)) continue; /* ignore old cache entry */ #ifdef NCACHE @@ -2174,8 +2497,8 @@ delete_all(np, 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)); + dprintf(3, (ddt, "delete_all(%#lx:\"%s\" %s %s)\n", + (u_long)np, np->n_dname, p_class(class), p_type(type))); pdp = NULL; dp = np->n_data; while (dp != NULL) { |