summaryrefslogtreecommitdiff
path: root/usr.sbin/named/ns_req.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr.sbin/named/ns_req.c')
-rw-r--r--usr.sbin/named/ns_req.c718
1 files changed, 524 insertions, 194 deletions
diff --git a/usr.sbin/named/ns_req.c b/usr.sbin/named/ns_req.c
index afc3fc5af271..1cfbef9f86f9 100644
--- a/usr.sbin/named/ns_req.c
+++ b/usr.sbin/named/ns_req.c
@@ -1,6 +1,6 @@
#if !defined(lint) && !defined(SABER)
static char sccsid[] = "@(#)ns_req.c 4.47 (Berkeley) 7/1/91";
-static char rcsid[] = "$Id: ns_req.c,v 4.9.1.22 1994/07/23 23:23:56 vixie Exp $";
+static char rcsid[] = "$Id: ns_req.c,v 8.8 1995/06/29 09:26:17 vixie Exp $";
#endif /* not lint */
/*
@@ -74,8 +74,10 @@ static char rcsid[] = "$Id: ns_req.c,v 4.9.1.22 1994/07/23 23:23:56 vixie Exp $"
#include "named.h"
struct addinfo {
- char *a_dname; /* domain name */
- u_int a_class; /* class for address */
+ char *a_dname; /* domain name */
+ char *a_rname; /* referred by */
+ u_int16_t a_rtype; /* referred by */
+ u_int16_t a_class; /* class for address */
};
enum req_action { Finish, Refuse, Return };
@@ -86,18 +88,23 @@ static enum req_action req_query __P((HEADER *hp, u_char **cpp, u_char *eom,
u_char *msg, int dfd,
struct sockaddr_in *from));
-#ifdef INVQ
static enum req_action req_iquery __P((HEADER *hp, u_char **cpp, u_char *eom,
int *buflenp, u_char *msg,
struct sockaddr_in *from));
+
+#ifdef BIND_NOTIFY
+static enum req_action req_notify __P((HEADER *hp, u_char **cpp, u_char *eom,
+ u_char *msg,struct sockaddr_in *from));
#endif
static void fwritemsg __P((FILE *, u_char *, int)),
+#ifdef DEBUG
+ printSOAdata __P((struct databuf)),
+#endif
doaxfr __P((struct namebuf *, FILE *,
struct namebuf *, int)),
startxfr __P((struct qstream *, struct namebuf *,
- u_char *, int, int, const char *)),
- printSOAdata __P((struct databuf));
+ u_char *, int, int, const char *));
#ifdef ALLOW_UPDATES
static int InitDynUpdate __P((register HEADER *hp,
@@ -110,7 +117,8 @@ static int InitDynUpdate __P((register HEADER *hp,
#endif
static struct addinfo addinfo[NADDRECS];
-static void addname __P((char *, u_int16_t));
+static void addname __P((const char *, const char *,
+ u_int16_t, u_int16_t));
/*
* Process request using database; assemble and send response.
@@ -126,12 +134,12 @@ ns_req(msg, msglen, buflen, qsp, from, dfd)
register HEADER *hp = (HEADER *) msg;
u_char *cp, *eom;
enum req_action action;
+ int n;
#ifdef DEBUG
if (debug > 3) {
- fprintf(ddt, "ns_req(from=[%s].%d)\n",
- inet_ntoa(from->sin_addr), ntohs(from->sin_port));
- fp_query(msg, ddt);
+ fprintf(ddt, "ns_req(from=%s)\n", sin_ntoa(from));
+ fp_nquery(msg, msglen, ddt);
}
#endif
@@ -148,19 +156,17 @@ ns_req(msg, msglen, buflen, qsp, from, dfd)
return;
}
- /* its a query and these bits have no business
+ /* it's not a response so these bits have no business
* being set. will later simplify work if we can
* safely assume these are always 0 when a query
- * comes in
+ * comes in.
*/
hp->aa = hp->ra = 0;
hp->rcode = NOERROR;
cp = msg + HFIXEDSZ;
eom = msg + msglen;
-
- dnptrs[0] = msg;
- dnptrs[1] = NULL;
+ buflen -= HFIXEDSZ;
free_addinfo(); /* sets addcount to zero */
dnptrs[0] = NULL;
@@ -172,10 +178,14 @@ ns_req(msg, msglen, buflen, qsp, from, dfd)
msg, dfd, from);
break;
-#ifdef INVQ
case IQUERY:
action = req_iquery(hp, &cp, eom, &buflen, msg, from);
break;
+
+#ifdef BIND_NOTIFY
+ case NS_NOTIFY_OP:
+ action = req_notify(hp, &cp, eom, msg, from);
+ break;
#endif
#ifdef ALLOW_UPDATES
@@ -188,14 +198,14 @@ ns_req(msg, msglen, buflen, qsp, from, dfd)
* here is that none of the other return codes equals this one (a good
* assumption, since they only occupy 4 bits over-the-wire)
*/
- /* Call InitDynUpdate for all dynamic update requests */
- case UPDATEM:
- case UPDATEMA:
- case UPDATED:
- case UPDATEDA:
- case UPDATEA:
- n = InitDynUpdate(hp, msg, msglen, cp, from, qsp, dfd);
- if (n == FORWARDED) {
+ /* Call InitDynUpdate for all dynamic update requests */
+ case UPDATEM:
+ case UPDATEMA:
+ case UPDATED:
+ case UPDATEDA:
+ case UPDATEA:
+ n = InitDynUpdate(hp, msg, msglen, cp, from, qsp, dfd);
+ if (n == FORWARDED) {
/* Return directly because InitDynUpdate
* forwarded the query to the primary, so we
* will send response later
@@ -207,11 +217,11 @@ ns_req(msg, msglen, buflen, qsp, from, dfd)
*/
action = Finish;
}
-#endif /* ALLOW_UPDATES */
case ZONEREF:
dprintf(1, (ddt, "Refresh Zone\n"));
/*FALLTHROUGH*/
+#endif /* ALLOW_UPDATES */
default:
dprintf(1, (ddt, "ns_req: Opcode %d not implemented\n",
@@ -238,48 +248,47 @@ ns_req(msg, msglen, buflen, qsp, from, dfd)
/* rest of the function handles this case */
break;
default:
- syslog(LOG_CRIT, "bad action variable in ns_req() -- %d",
- (int) action);
- return; /* XXX - should really exit here */
+ panic(-1, "ns_req: bad action variable");
+ /*NOTREACHED*/
}
/*
* apply final polish
*/
hp->qr = 1; /* set Response flag */
- if (NoRecurse)
- hp->ra = 0; /* No recursion; maybe we're a root server */
- else
- hp->ra = 1; /* Recursion is Available */
+ hp->ra = (NoRecurse == 0);
hp->ancount = htons(hp->ancount);
- if (addcount) {
- int n = doaddinfo(hp, cp, buflen);
- cp += n;
- buflen -= n;
- }
- dprintf(1, (ddt, "ns_req: answer -> [%s].%d fd=%d id=%d %s\n",
- inet_ntoa(from->sin_addr),
- ntohs(from->sin_port),
+ n = doaddinfo(hp, cp, buflen);
+ cp += n;
+ buflen -= n;
+
+ dprintf(1, (ddt, "ns_req: answer -> %s fd=%d id=%d size=%d %s\n",
+ sin_ntoa(from),
(qsp == QSTREAM_NULL) ?dfd :qsp->s_rfd,
- ntohs(hp->id), local(from) == NULL ? "Remote" : "Local"));
+ ntohs(hp->id), cp - msg, local(from) == NULL ? "Remote" : "Local"));
#ifdef DEBUG
if (debug >= 10)
- fp_query(msg, ddt);
+ fp_nquery(msg, cp - msg, ddt);
#endif
if (qsp == QSTREAM_NULL) {
- if (sendto(dfd, msg, cp - msg, 0,
+ if (sendto(dfd, (char*)msg, cp - msg, 0,
(struct sockaddr *)from,
sizeof(*from)) < 0) {
if (!haveComplained((char*)from->sin_addr.s_addr,
sendtoStr))
- syslog(LOG_NOTICE,
- "ns_req: sendto([%s].%d): %m",
- inet_ntoa(from->sin_addr),
- ntohs(from->sin_port));
+ syslog(LOG_INFO,
+ "ns_req: sendto(%s): %m",
+ sin_ntoa(from));
nameserIncr(from->sin_addr, nssSendtoErr);
}
nameserIncr(from->sin_addr, nssSentAns);
+#ifdef XSTATS
+ if (hp->rcode == NXDOMAIN)
+ nameserIncr(from->sin_addr, nssSentNXD);
+ if (!hp->aa)
+ nameserIncr(from->sin_addr, nssSentNaAns);
+#endif
} else {
(void) writemsg(qsp->s_rfd, msg, cp - msg);
sq_done(qsp);
@@ -290,6 +299,124 @@ ns_req(msg, msglen, buflen, qsp, from, dfd)
}
}
+#ifdef BIND_NOTIFY
+int
+findZonePri(zp, from)
+ register const struct zoneinfo *zp;
+ const struct sockaddr_in *from;
+{
+ register u_int32_t from_addr = from->sin_addr.s_addr;
+ register int i;
+
+ for (i = 0; (u_int)i < zp->z_addrcnt; i++)
+ if (zp->z_addr[i].s_addr == from_addr)
+ return (i);
+ return (-1);
+}
+
+static enum req_action
+req_notify(hp, cpp, eom, msg, from)
+ HEADER *hp;
+ u_char **cpp, *eom, *msg;
+ struct sockaddr_in *from;
+{
+ int n, type, class, zn;
+ char dnbuf[MAXDNAME];
+ struct namebuf *np;
+ const char *fname;
+ struct hashbuf *htp = hashtab; /* lookup relative to root */
+
+ /* valid notify's have one question and zero answers */
+ if ((ntohs(hp->qdcount) != 1)
+ || hp->ancount
+ || hp->nscount
+ || hp->arcount) {
+ dprintf(1, (ddt, "FORMERR Notify header counts wrong\n"));
+ hp->qdcount = 0;
+ hp->ancount = 0;
+ hp->nscount = 0;
+ hp->arcount = 0;
+ hp->rcode = FORMERR;
+ return (Finish);
+ }
+
+ n = dn_expand(msg, eom, *cpp, dnbuf, sizeof dnbuf);
+ if (n < 0) {
+ dprintf(1, (ddt, "FORMERR Query expand name failed\n"));
+ hp->rcode = FORMERR;
+ return (Finish);
+ }
+ *cpp += n;
+ GETSHORT(type, *cpp);
+ GETSHORT(class, *cpp);
+ syslog(LOG_INFO, "rcvd NOTIFY(%s %s %s)",
+ dnbuf, p_class(class), p_type(type));
+ /* XXX - when answers are allowed, we'll need to do compression
+ * correctly here, and we will need to check for packet underflow.
+ */
+ np = nlookup(dnbuf, &htp, &fname, 0);
+ if (!np) {
+ syslog(LOG_INFO, "rcvd NOTIFY for \"%s\", name not in cache",
+ dnbuf);
+ hp->rcode = SERVFAIL;
+ return (Finish);
+ }
+ zn = findMyZone(np, class);
+ if (zn == DB_Z_CACHE || zones[zn].z_type != Z_SECONDARY) {
+ /* this can come if a user did an AXFR of some zone somewhere
+ * and that zone's server now wants to tell us that the SOA
+ * has changed. AXFR's always come from nonpriv ports so it
+ * isn't possible to know whether it was the server or just
+ * "dig". this condition can be avoided by using secure zones
+ * since that way only real secondaries can AXFR from you.
+ */
+ syslog(LOG_INFO,
+ "NOTIFY for non-secondary name (%s), from %s",
+ dnbuf, sin_ntoa(from));
+ goto refuse;
+ }
+ if (findZonePri(&zones[zn], from) == -1) {
+ syslog(LOG_INFO,
+ "NOTIFY from non-master server (zone %s), from %s",
+ zones[zn].z_origin, sin_ntoa(from));
+ goto refuse;
+ }
+ switch (type) {
+ case T_SOA:
+ if (strcasecmp(dnbuf, zones[zn].z_origin) != 0) {
+ syslog(LOG_INFO,
+ "NOTIFY(SOA) for non-origin (%s), from %s",
+ dnbuf, sin_ntoa(from));
+ goto refuse;
+ }
+ if (zones[zn].z_flags &
+ (Z_NEED_RELOAD|Z_NEED_XFER|Z_QSERIAL|Z_XFER_RUNNING)) {
+ syslog(LOG_INFO,
+ "NOTIFY(SOA) for zone already xferring (%s)",
+ dnbuf);
+ goto noerror;
+ }
+ zones[zn].z_time = tt.tv_sec;
+ qserial_query(&zones[zn]);
+ /* XXX: qserial_query() can fail due to queue full condition;
+ * we should detect that case here and do something.
+ */
+ break;
+ default:
+ /* unimplemented, but it's not a protocol error, just
+ * something to be ignored.
+ */
+ break;
+ }
+ noerror:
+ hp->rcode = NOERROR;
+ return (Finish);
+ refuse:
+ hp->rcode = REFUSED;
+ return (Finish);
+}
+#endif /*BIND_NOTIFY*/
+
static enum req_action
req_query(hp, cpp, eom, qsp, buflenp, msglenp, msg, dfd, from)
HEADER *hp;
@@ -303,14 +430,26 @@ req_query(hp, cpp, eom, qsp, buflenp, msglenp, msg, dfd, from)
int n, class, type, count, foundname, founddata, omsglen, cname;
u_int16_t id;
u_char **dpp, *omsg, *answers;
- char dnbuf[MAXDNAME], *dname, *fname;
+ char dnbuf[MAXDNAME], *dname;
+ const char *fname;
struct hashbuf *htp;
struct databuf *nsp[NSMAX];
- struct namebuf *np;
+ struct namebuf *np, *anp;
struct qinfo *qp;
struct netinfo *lp;
+#ifdef SECURE_ZONES
+ struct zoneinfo *zp;
+#endif
+ struct databuf *dp;
nameserIncr(from->sin_addr, nssRcvdQ);
+
+#ifdef XSTATS
+ /* Statistics for queries coming from port <> 53, suspect some kind of forwarder */
+ if (from->sin_port != ns_port)
+ nameserIncr(from->sin_addr, nssNotNsQ);
+#endif
+
#ifdef DATUMREFCNT
nsp[0] = NULL;
#endif
@@ -368,10 +507,8 @@ req_query(hp, cpp, eom, qsp, buflenp, msglenp, msg, dfd, from)
/* refuse request if not a TCP connection */
if (qsp == QSTREAM_NULL) {
syslog(LOG_INFO,
- "rejected UDP AXFR from [%s].%u for \"%s\"",
- inet_ntoa(from->sin_addr),
- ntohs(from->sin_port),
- *dnbuf ? dnbuf : ".");
+ "rejected UDP AXFR from %s for \"%s\"",
+ sin_ntoa(from), *dnbuf ? dnbuf : ".");
return (Refuse);
}
/* the position of this is subtle. */
@@ -384,20 +521,16 @@ req_query(hp, cpp, eom, qsp, buflenp, msglenp, msg, dfd, from)
*/
if (!addr_on_netlist(from->sin_addr, xfrnets)) {
syslog(LOG_INFO,
- "unapproved AXFR from [%s].%u for %s",
- inet_ntoa(from->sin_addr),
- ntohs(from->sin_port),
- *dnbuf ? dnbuf : ".");
+ "unapproved AXFR from %s for %s",
+ sin_ntoa(from), *dnbuf ? dnbuf : ".");
return (Refuse);
}
}
#endif /*XFRNETS*/
dnptrs[0] = NULL; /* don't compress names */
hp->rd = 0; /* recursion not possible */
- syslog(LOG_INFO, "approved AXFR from [%s].%d for \"%s\"",
- inet_ntoa(from->sin_addr),
- ntohs(from->sin_port),
- *dnbuf ? dnbuf : ".");
+ syslog(LOG_INFO, "approved AXFR from %s for \"%s\"",
+ sin_ntoa(from), *dnbuf ? dnbuf : ".");
}
*buflenp -= *msglenp;
count = 0;
@@ -416,10 +549,10 @@ req_query(hp, cpp, eom, qsp, buflenp, msglenp, msg, dfd, from)
#endif /*QRYLOG*/
try_again:
- dprintf(1, (ddt, "req: nlookup(%s) id %d type=%d\n",
- dname, hp->id, type));
+ dprintf(1, (ddt, "req: nlookup(%s) id %d type=%d class=%d\n",
+ dname, hp->id, type, class));
htp = hashtab; /* lookup relative to root */
- if ((np = nlookup(dname, &htp, &fname, 0)) == NULL)
+ if ((anp = np = nlookup(dname, &htp, &fname, 0)) == NULL)
fname = "";
dprintf(1, (ddt, "req: %s '%s' as '%s' (cname=%d)\n",
np == NULL ? "missed" : "found",
@@ -438,7 +571,7 @@ try_again:
dprintf(1, (ddt,"req: nlookup(%s) type=%d\n", dname, type));
htp = hashtab;
np = nlookup(dname, &htp, &fname, 0);
- }
+ }
#endif /*LOCALDOM*/
#ifdef YPKLUDGE
@@ -470,17 +603,26 @@ try_again:
goto fetchns;
#ifdef SECURE_ZONES
- if (np->n_data) {
- struct zoneinfo *zp;
-
- zp = &zones[np->n_data->d_zone];
+ /* (gdmr) Make sure the class is correct. If we have the same name
+ * with more than one class then we can't refuse a request for one
+ * class just because another class is blocked. We *really* ought
+ * to look for the correct type too, but since everything in a
+ * particular class of zone has the same secure_zone attribute it
+ * doesn't really matter which type we use! Alternatively, this lot
+ * could all be moved to after the finddata(), by which time only
+ * the correct class/type combinations will be left.
+ */
+ dp = np->n_data;
+ while (dp && (dp->d_class != class))
+ dp = dp->d_next;
+ if (dp) {
+ zp = &zones[dp->d_zone];
if (zp->secure_nets
&& !addr_on_netlist(from->sin_addr, zp->secure_nets)) {
- dprintf(1, (ddt,
- "REFUSED Unauthorized request from %s\n",
- inet_ntoa(from->sin_addr)));
- syslog(LOG_INFO, "Unauthorized request %s from %s",
- dname, inet_ntoa(from->sin_addr));
+ syslog(LOG_NOTICE, "Unauthorized request %s from %s",
+ dname, sin_ntoa(from));
+ dprintf(1, (ddt, "req: refuse %s from %s class %d (%d)\n",
+ dname, sin_ntoa(from), class, zp->z_class));
return (Refuse);
}
}
@@ -490,36 +632,30 @@ try_again:
count = *cpp - msg;
#ifdef NCACHE
- /* if this is a NXDOMAIN, will have only one databuf
- * whose d_rcode field will be NXDOMAIN. So we can go home
- * right here. -ve $ing: anant@isi.edu
+ /* Look for NXDOMAIN record with appropriate class
+ * if found return immediately
*/
- if (np->n_data != NULL && !stale(np->n_data)) {
- if (np->n_data->d_rcode == NXDOMAIN) {
+ for (dp = np->n_data; dp ; dp = dp->d_next) {
+ if (!stale(dp) && (dp->d_rcode == NXDOMAIN) &&
+ (dp->d_class == class)) {
#ifdef RETURNSOA
- n = finddata(np, class, T_SOA, hp, &dname,
- buflenp, &count);
- if (n != 0 ) {
- if (hp->rcode == NOERROR_NODATA) {
+ n = finddata(np, class, T_SOA, hp, &dname,
+ buflenp, &count);
+ if (n != 0 ) {
+ if (hp->rcode == NOERROR_NODATA) {
/* this should not occur */
hp->rcode = NOERROR;
return (Finish);
+ }
+ *cpp += n;
+ *buflenp -= n;
+ *msglenp += n;
+ hp->nscount = htons((u_int16_t)count);
}
- *cpp += n;
- *buflenp -= n;
- *msglenp += n;
- hp->rcode = NXDOMAIN;
- hp->nscount = htons((u_int16_t)count);
- hp->aa = 1;
- return (Finish);
- }
- else
- goto fetchns;
-#else
+#endif
hp->rcode = NXDOMAIN;
hp->aa = 1;
return (Finish);
-#endif
}
}
@@ -569,6 +705,29 @@ try_again:
if ((lp = local(from)) != NULL)
sort_response(answers, count, lp, *cpp);
+#ifdef BIND_NOTIFY
+ if (type == T_SOA &&
+ from->sin_port == ns_port &&
+ np->n_data) {
+ int zn = np->n_data->d_zone;
+
+ if (zn != DB_Z_CACHE) {
+ struct notify *ap;
+
+ /* Old? */
+ ap = findNotifyPeer(&zones[zn], from->sin_addr);
+ /* New? */
+ if (!ap && (ap = (struct notify *)malloc(sizeof *ap))) {
+ ap->addr = from->sin_addr;
+ ap->next = zones[zn].z_notifylist;
+ zones[zn].z_notifylist = ap;
+ }
+ /* Old or New? */
+ if (ap)
+ ap->last = tt.tv_sec;
+ }
+ }
+#endif /*BIND_NOTIFY*/
if (type == T_AXFR) {
hp->ancount = htons(hp->ancount);
startxfr(qsp, np, msg, *cpp - msg, class, dname);
@@ -598,6 +757,7 @@ fetchns:
count = 0;
switch (findns(&np, class, nsp, &count, 0)) {
case NXDOMAIN:
+ /* We are authoritative for this np. */
if (!foundname) {
hp->rcode = NXDOMAIN;
}
@@ -616,7 +776,7 @@ fetchns:
#ifdef ADDAUTH
} else if (hp->ancount) {
/* don't add NS records for NOERROR NODATA
- as some severs can get confused */
+ as some servers can get confused */
#ifdef DATUMREFCNT
free_nsp(nsp);
#endif
@@ -625,7 +785,9 @@ fetchns:
case SERVFAIL:
break;
default:
- if (np) {
+ if (np &&
+ (type != T_NS || np != anp)
+ ) {
n = add_data(np, nsp, *cpp,
*buflenp);
if (n < 0) {
@@ -648,6 +810,7 @@ fetchns:
return (Finish);
case SERVFAIL:
+ /* We're authoritative but the zone isn't loaded. */
if (!founddata && !(forward_only && fwdtab)) {
hp->rcode = SERVFAIL;
#ifdef DATUMREFCNT
@@ -664,17 +827,25 @@ fetchns:
* ("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);
+ /* If the qtype was NS, and the np of the authority is
+ * the same as the np of the data, we don't need to add
+ * another copy of the answer here in the authority
+ * section.
+ */
+ if (!founddata || type != T_NS || anp != 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);
}
- *cpp += n;
- *buflenp -= n;
- hp->nscount = htons((u_int16_t)count);
#ifdef DATUMREFCNT
free_nsp(nsp);
#endif
+ /* Our caller will handle the Additional section. */
return (Finish);
}
@@ -688,8 +859,7 @@ fetchns:
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");
+ syslog(LOG_INFO, "ns_req: Out Of Memory");
hp->rcode = SERVFAIL;
#ifdef DATUMREFCNT
free_nsp(nsp);
@@ -700,9 +870,18 @@ fetchns:
hp->ancount = htons(hp->ancount);
omsglen = *msglenp;
bcopy(msg, omsg, omsglen);
- *msglenp = res_mkquery(QUERY, dname, class, type,
- NULL, 0, NULL, msg,
- *msglenp + *buflenp);
+ n = res_mkquery(QUERY, dname, class, type,
+ NULL, 0, NULL, msg,
+ *msglenp + *buflenp);
+ if (n < 0) {
+ syslog(LOG_INFO, "res_mkquery(%s) failed", dname);
+ hp->rcode = SERVFAIL;
+#ifdef DATUMREFCNT
+ free_nsp(nsp);
+#endif
+ return (Finish);
+ }
+ *msglenp = n;
}
n = ns_forw(nsp, msg, *msglenp, from, qsp, dfd, &qp, dname, np);
if (n != FW_OK && cname)
@@ -727,10 +906,7 @@ fetchns:
*/
if (np) {
if (np->n_dname[0] == '\0') {
- dprintf(1, (ddt,
- "ns_req: no address for root NS\n"
- ));
- syslog(LOG_ERR,
+ syslog(LOG_NOTICE,
"ns_req: no address for root server");
hp->rcode = SERVFAIL;
#ifdef DATUMREFCNT
@@ -762,7 +938,6 @@ fetchns:
return (Return);
}
-#ifdef INVQ
static enum req_action
req_iquery(hp, cpp, eom, buflenp, msg, from)
HEADER *hp;
@@ -771,12 +946,8 @@ req_iquery(hp, cpp, eom, buflenp, msg, from)
u_char *msg;
struct sockaddr_in *from;
{
- register struct invbuf *ip;
- int dlen, alen, i, n, type, class, count;
+ int dlen, alen, n, type, class, count;
char dnbuf[MAXDNAME], anbuf[PACKETSZ], *data, *fname;
- struct namebuf *np;
- struct qinfo *qp;
- struct databuf *dp;
nameserIncr(from->sin_addr, nssRcvdIQ);
@@ -819,8 +990,14 @@ req_iquery(hp, cpp, eom, buflenp, msg, from)
*/
switch (type) {
case T_A:
+#ifndef INVQ
+ if (!fake_iquery)
+ return (Refuse);
+#endif
+#ifdef INVQ
case T_UID:
case T_GID:
+#endif
break;
default:
return (Refuse);
@@ -833,10 +1010,29 @@ req_iquery(hp, cpp, eom, buflenp, msg, from)
*cpp = (u_char *)fname;
*buflenp -= HFIXEDSZ;
count = 0;
+
+#ifdef QRYLOG
+ if (qrylog) {
+ syslog(LOG_INFO, "XX /%s/%s/-%s",
+ inet_ntoa(from->sin_addr),
+ inet_ntoa(data_inaddr((u_char *)data)),
+ p_type(type));
+ }
+#endif /*QRYLOG*/
+
+#ifdef INVQ
+ {
+ register struct invbuf *ip;
+
for (ip = invtab[dhash((u_char *)data, dlen)];
ip != NULL;
ip = ip->i_next) {
+ int i;
+
for (i = 0; i < INVBLKSZ; i++) {
+ struct namebuf *np;
+ struct databuf *dp;
+
if ((np = ip->i_dname[i]) == NULL)
break;
dprintf(5, (ddt, "dname = %d\n", np->n_dname));
@@ -863,6 +1059,30 @@ req_iquery(hp, cpp, eom, buflenp, msg, from)
}
}
}
+ }
+#else /*INVQ*/
+ /*
+ * We can only get here if we are compiled without INVQ (the default)
+ * and the type is T_A and the option "fake-iquery" is on in the boot
+ * file.
+ *
+ * What we do here is send back a bogus response of "[dottedquad]".
+ * A better strategy would be to turn this into a PTR query, but that
+ * would legitimize inverse queries in a way they do not deserve.
+ */
+ sprintf(dnbuf, "[%s]", inet_ntoa(data_inaddr((u_char *)data)));
+ *buflenp -= QFIXEDSZ;
+ n = dn_comp(dnbuf, *cpp, *buflenp, NULL, NULL);
+ if (n < 0) {
+ hp->tc = 1;
+ return (Finish);
+ }
+ *cpp += n;
+ PUTSHORT((u_int16_t)type, *cpp);
+ PUTSHORT((u_int16_t)class, *cpp);
+ *buflenp -= n;
+ count++;
+#endif /*INVQ*/
dprintf(1, (ddt, "req: IQuery %d records\n", count));
hp->qdcount = htons((u_int16_t)count);
if (alen > *buflenp) {
@@ -873,7 +1093,6 @@ req_iquery(hp, cpp, eom, buflenp, msg, from)
*cpp += alen;
return (Finish);
}
-#endif
static void
fwritemsg(rfp, msg, msglen)
@@ -886,7 +1105,8 @@ fwritemsg(rfp, msg, msglen)
__putshort(msglen, len);
if (fwrite((char *)len, INT16SZ, 1, rfp) != 1 ||
fwrite((char *)msg, msglen, 1, rfp) != 1) {
- dprintf(1, (ddt, "fwrite failed %d\n", errno));
+ syslog(LOG_ERR, "fwritemsg: %m");
+ _exit(1);
}
}
@@ -904,10 +1124,14 @@ stale(dp)
case Z_PRIMARY:
return (0);
- case Z_SECONDARY:
#ifdef STUBS
case Z_STUB:
+ /* root stub zones have DB_F_HINT set */
+ if (dp->d_flags & DB_F_HINT)
+ return (0);
+ /* FALLTROUGH */
#endif
+ case Z_SECONDARY:
/*
* Check to see whether a secondary zone
* has expired; if so clear authority flag
@@ -920,27 +1144,37 @@ stale(dp)
"stale: secondary zone %s expired\n",
zp->z_origin));
if (!haveComplained(zp->z_origin, (char*)stale)) {
- syslog(LOG_ERR,
+ syslog(LOG_NOTICE,
"secondary zone \"%s\" expired",
zp->z_origin);
}
zp->z_flags &= ~Z_AUTH;
return (1);
}
+ if (zp->z_lastupdate > tt.tv_sec) {
+ if (!haveComplained(zp->z_origin, (char*)stale)) {
+ syslog(LOG_NOTICE,
+ "secondary zone \"%s\" time warp",
+ zp->z_origin);
+ }
+ zp->z_flags &= ~Z_AUTH;
+ return (1);
+ }
return (0);
case Z_CACHE:
if (dp->d_flags & DB_F_HINT || dp->d_ttl >= tt.tv_sec)
return (0);
- dprintf(3, (ddt, "stale: ttl %d %d (x%x)\n",
- dp->d_ttl, dp->d_ttl - tt.tv_sec, dp->d_flags));
+ dprintf(3, (ddt, "stale: ttl %d %d (x%lx)\n",
+ dp->d_ttl, dp->d_ttl - tt.tv_sec,
+ (u_long)dp->d_flags));
return (1);
default:
/* FALLTHROUGH */ ;
}
- abort();
+ panic(-1, "stale: impossible condition");
/* NOTREACHED */
}
@@ -950,7 +1184,7 @@ stale(dp)
*/
int
make_rr(name, dp, buf, buflen, doadd)
- char *name;
+ const char *name;
register struct databuf *dp;
u_char *buf;
int buflen, doadd;
@@ -962,31 +1196,27 @@ make_rr(name, dp, buf, buflen, doadd)
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,
+ dprintf(5, (ddt, "make_rr(%s, %lx, %lx, %d, %d) %d zone %d ttl %d\n",
+ name, (u_long)dp, (u_long)buf,
buflen, doadd, dp->d_size, dp->d_zone, dp->d_ttl));
#ifdef NCACHE
if (dp->d_rcode
#ifdef RETURNSOA
- && dp->d_rcode != NXDOMAIN
+ && dp->d_rcode != NXDOMAIN
#endif
) {
- syslog(LOG_CRIT, "make_rr d_rcode %d", dp->d_rcode);
-#ifdef DEBUG
- if (debug) abort();
-#endif
- return (-1); /* XXX We should exit here */
+ panic(-1, "make_rr: impossible d_rcode value");
}
#endif
zp = &zones[dp->d_zone];
- /* check for outdated RR before updating dnptrs by dn_comp() (???) */
+ /* 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 */
+ "make_rr: %d=>0, %#lx\n",
+ ttl, (u_long)dp->d_flags));
ttl = 0;
}
} else {
@@ -1047,7 +1277,8 @@ make_rr(name, dp, buf, buflen, doadd)
PUTSHORT((u_int16_t)n, sp);
cp += n;
if (doadd)
- addname((char*)dp->d_data, dp->d_class);
+ addname((char*)dp->d_data, name,
+ dp->d_type, dp->d_class);
break;
case T_SOA:
@@ -1079,22 +1310,51 @@ make_rr(name, dp, buf, buflen, doadd)
/* cp1 == our data/ cp == data of RR */
cp1 = dp->d_data;
+ if ((buflen -= INT16SZ) < 0)
+ return (-1);
+
/* copy preference */
bcopy(cp1, cp, INT16SZ);
cp += INT16SZ;
cp1 += INT16SZ;
- buflen -= INT16SZ;
n = dn_comp((char *)cp1, cp, buflen, dnptrs, edp);
- if (n < 0)
- return (-1);
- cp += n;
+ if (n < 0)
+ return (-1);
+ cp += n;
- /* save data length */
+ /* save data length */
n = (u_int16_t)((cp - sp) - INT16SZ);
- PUTSHORT((u_int16_t)n, sp);
+ PUTSHORT((u_int16_t)n, sp);
if (doadd)
- addname((char*)cp1, dp->d_class);
+ addname((char*)cp1, name, dp->d_type, dp->d_class);
+ break;
+
+ case T_PX:
+ cp1 = dp->d_data;
+
+ if ((buflen -= INT16SZ) < 0)
+ return (-1);
+
+ /* copy preference */
+ bcopy(cp1, cp, INT16SZ);
+ cp += INT16SZ;
+ cp1 += INT16SZ;
+
+ n = dn_comp((char *)cp1, cp, buflen, dnptrs, edp);
+ if (n < 0)
+ return (-1);
+ cp += n;
+ buflen -= n;
+ cp1 += strlen((char *)cp1) + 1;
+ n = dn_comp((char *)cp1, cp, buflen, dnptrs, edp);
+ if (n < 0)
+ return (-1);
+ cp += n;
+
+ /* save data length */
+ n = (u_int16_t)((cp - sp) - INT16SZ);
+ PUTSHORT((u_int16_t)n, sp);
break;
default:
@@ -1109,28 +1369,32 @@ make_rr(name, dp, buf, buflen, doadd)
#if defined(__STDC__) || defined(__GNUC__)
static void
-addname(register char *name,
+addname(register const char *dname,
+ register const char *rname,
+ u_int16_t rtype,
u_int16_t class)
#else
static void
-addname(name, class)
- register char *name;
- u_int16_t class;
+addname(dname, rname, rtype, class)
+ register const char *dname;
+ register const char *rname;
+ u_int16_t rtype;
+ 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)
+ if (strcasecmp(ap->a_dname, dname) == 0)
return;
-
/* add domain name to additional section */
if (addcount < NADDRECS) {
addcount++;
- ap->a_dname = (char *)malloc(strlen(name)+1);
- strcpy(ap->a_dname,name);
+ ap->a_dname = savestr(dname);
+ ap->a_rname = savestr(rname);
+ ap->a_rtype = rtype;
ap->a_class = class;
}
}
@@ -1150,9 +1414,12 @@ doaddinfo(hp, msg, msglen)
register struct addinfo *ap;
register u_char *cp;
struct hashbuf *htp;
- char *fname;
+ const char *fname;
int n, count;
+ if (!addcount)
+ return (0);
+
dprintf(3, (ddt, "doaddinfo() addcount = %d\n", addcount));
if (hp->tc) {
@@ -1165,11 +1432,13 @@ doaddinfo(hp, msg, msglen)
for (ap = addinfo; --addcount >= 0; ap++) {
int foundstale = 0,
foundany = 0,
+ foundcname = 0,
save_count = count,
save_msglen = msglen;
u_char *save_cp = cp;
- dprintf(3, (ddt, "do additional '%s'\n", ap->a_dname));
+ dprintf(3, (ddt, "do additional \"%s\" (from \"%s\")\n",
+ ap->a_dname, ap->a_rname));
htp = hashtab; /* because "nlookup" stomps on arg. */
np = nlookup(ap->a_dname, &htp, &fname, 0);
if (np == NULL || fname != ap->a_dname)
@@ -1177,9 +1446,17 @@ doaddinfo(hp, msg, msglen)
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))
- ) {
+#ifdef NCACHE
+ if (dp->d_rcode)
+ continue;
+#endif
+ if (match(dp, (int)ap->a_class, T_CNAME) ||
+ match(dp, C_IN, T_CNAME)) {
+ foundcname++;
+ break;
+ }
+ if (!match(dp, (int)ap->a_class, T_A) &&
+ !match(dp, C_IN, T_A)) {
continue;
}
foundany++;
@@ -1194,10 +1471,6 @@ doaddinfo(hp, msg, msglen)
));
continue;
}
-#ifdef NCACHE
- if (dp->d_rcode)
- continue;
-#endif
/*
* Should be smart and eliminate duplicate
* data here. XXX
@@ -1213,6 +1486,9 @@ doaddinfo(hp, msg, msglen)
* since we only do A RR's here, the name is
* the key). vixie, 23apr93
*/
+ dprintf(5, (ddt,
+ "addinfo: not enough room, remaining msglen = %d\n",
+ save_msglen));
cp = save_cp;
msglen = save_msglen;
count = save_count;
@@ -1225,16 +1501,31 @@ doaddinfo(hp, msg, msglen)
msglen -= n;
count++;
}
-next_rr: if (foundstale) {
+ next_rr:
+ if (foundstale) {
/* Cache invalidate the address RR's */
delete_all(np, (int)ap->a_class, T_A);
}
- if (foundstale || !foundany) {
+ if (
+#if 0 /*XXX*/
+ !NoRecurse &&
+#endif
+ !foundcname && (foundstale || !foundany)) {
/* ask a real server for this info */
(void) sysquery(ap->a_dname, (int)ap->a_class, T_A,
- NULL, 0);
+ NULL, 0, QUERY);
+ }
+ if (foundcname) {
+ if (!haveComplained((char*)nhash(ap->a_dname),
+ (char*)nhash(ap->a_rname))) {
+ syslog(LOG_INFO,
+ "\"%s %s %s\" points to a CNAME (%s)",
+ ap->a_rname, p_class(ap->a_class),
+ p_type(ap->a_rtype), ap->a_dname);
+ }
}
free(ap->a_dname);
+ free(ap->a_rname);
}
hp->arcount = htons((u_int16_t)count);
return (cp - msg);
@@ -1299,25 +1590,22 @@ doaxfr(np, rfp, top, class)
struct namebuf **npp, **nppend;
u_char msg[PACKETSZ];
u_char *cp;
- char *fname;
+ const char *fname;
char dname[MAXDNAME];
- HEADER *hp = (HEADER *) msg;
+ HEADER *hp;
int fndns;
if (np == top)
dprintf(1, (ddt, "doaxfr()\n"));
fndns = 0;
- hp->id = 0;
+ bzero((char*)msg, sizeof msg);
+ hp = (HEADER *) msg;
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 + HFIXEDSZ);
- getname(np, dname, sizeof(dname));
+ cp = msg + HFIXEDSZ;
+ getname(np, dname, sizeof dname);
/* first do the NS records (del@harris) */
for (dp = np->n_data; dp != NULL; dp = dp->d_next) {
@@ -1357,7 +1645,9 @@ doaxfr(np, rfp, top, class)
break;
if ( (tnp == NULL) && (top->n_dname[0] != '\0') )
continue; /* name server is not below top domain */
- for (tnp = gnp; tnp != top; tnp = tnp->n_parent) {
+ for (tnp = gnp;
+ tnp != NULL && tnp != top;
+ tnp = tnp->n_parent) {
for (tdp = tnp->n_data;
tdp != NULL;
tdp = tdp->d_next) {
@@ -1371,7 +1661,8 @@ doaxfr(np, rfp, top, class)
if (tdp != NULL)
break; /* found a zone cut */
}
- if (tnp == top)
+ if ((tnp == top) ||
+ ((tnp == NULL) && (top->n_dname[0] == '\0')))
continue; /* name server is not in a delegated zone */
/* now we know glue records are needed. send them. */
#endif /*NO_GLUE*/
@@ -1562,8 +1853,6 @@ InitDynUpdate(hp, msg, msglen, startcp, from, qsp, dfd)
*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;
@@ -1618,13 +1907,9 @@ InitDynUpdate(hp, msg, msglen, startcp, from, qsp, dfd)
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);
+ syslog(LOG_NOTICE,
+ "InitDynUpdate: Couldn't find SOA RR for '%s'\n",
+ ZoneName);
hp->rcode = NXDOMAIN;
#ifdef DATUMREFCNT
free_nsp(nsp);
@@ -1690,11 +1975,14 @@ printSOAdata(dp)
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);
+ fprintf(ddt, "printSOAdata(%#lx): origin(%#lx)='%s'\n",
+ (u_long)dp, (u_long)cp, cp);
cp += strlen(cp) + 1; /* skip origin string */
- fprintf(ddt, "printSOAdata: in-charge(%x)='%s'\n", cp, cp);
+ fprintf(ddt, "printSOAdata: in-charge(%#lx)='%s'\n",
+ (u_long)cp, cp);
cp += strlen(cp) + 1; /* skip in-charge string */
- fprintf(ddt, "printSOAdata: serial(%x)=%d\n", cp, _getlong(cp));
+ fprintf(ddt, "printSOAdata: serial(%lx)=%d\n",
+ cp, (u_long)_getlong(cp));
}
#endif
#endif
@@ -1711,6 +1999,15 @@ startxfr(qsp, np, soa, soalen, class, dname)
FILE *rfp;
int fdstat;
pid_t pid;
+#ifdef HAVE_SETVBUF
+ char *buf;
+#endif
+#ifdef SO_SNDBUF
+ static const int sndbuf = XFER_BUFSIZE * 2;
+#endif
+#ifdef SO_LINGER
+ static const struct linger ll = { 1, 120 };
+#endif
dprintf(5, (ddt, "startxfr()\n"));
@@ -1720,16 +2017,16 @@ startxfr(qsp, np, soa, soalen, class, dname)
*/
switch (pid = fork()) {
case -1:
- syslog(LOG_ERR, "startxfr(%s -> [%s]) failing; fork: %m",
- dname, inet_ntoa(qsp->s_from.sin_addr));
+ syslog(LOG_NOTICE, "startxfr(%s -> %s) failing; fork: %m",
+ dname, sin_ntoa(&qsp->s_from));
return;
case 0:
/* child */
break;
default:
/* parent */
- syslog(LOG_DEBUG, "zone transfer of \"%s\" to [%s] (pid %lu)",
- dname, inet_ntoa(qsp->s_from.sin_addr), pid);
+ syslog(LOG_DEBUG, "zone transfer of \"%s\" to %s (pid %lu)",
+ dname, sin_ntoa(&qsp->s_from), pid);
return;
}
@@ -1758,25 +2055,58 @@ startxfr(qsp, np, soa, soalen, class, dname)
_exit(1);
}
(void) fcntl(qsp->s_rfd, F_SETFL, fdstat & ~PORT_NONBLOCK);
+#ifdef HAVE_SETVBUF
+ /* some systems (DEC OSF/1, SunOS) don't initialize the stdio buffer
+ * if all you do between fdopen() and fclose() are fwrite()'s. even
+ * on systems where the buffer is correctly set, it is too small.
+ */
+ if ((buf = malloc(XFER_BUFSIZE)) != NULL)
+ (void) setvbuf(rfp, buf, _IOFBF, XFER_BUFSIZE);
+#endif
+#ifdef SO_SNDBUF
+ /* the default seems to be 4K, and we'd like it to have enough room
+ * to parallelize sending the pushed data with accumulating more
+ * write() data from us.
+ */
+ (void) setsockopt(qsp->s_rfd, SOL_SOCKET, SO_SNDBUF,
+ (char *)&sndbuf, sizeof sndbuf);
+#endif
+ /* XXX: some day we would like to only send the size and header out
+ * when we fill a 64K DNS/AXFR "message" rather than on each RR.
+ * (PVM@ISI gets credit for this idea.)
+ */
fwritemsg(rfp, soa, soalen);
doaxfr(np, rfp, np, class);
fwritemsg(rfp, soa, soalen);
(void) fflush(rfp);
+#ifdef SO_LINGER
+ /* kernels that map pages for IO end up failing if the pipe is full
+ * at exit and we take away the final buffer. this is really a kernel
+ * bug but it's harmless on systems that are not broken, so...
+ */
+ setsockopt(qsp->s_rfd, SOL_SOCKET, SO_LINGER,
+ (char *)&ll, sizeof ll);
+ close(qsp->s_rfd);
+#endif
_exit(0);
+ /* NOTREACHED */
}
+void
free_addinfo() {
struct addinfo *ap;
for (ap = addinfo; --addcount >= 0; ap++) {
free(ap->a_dname);
+ free(ap->a_rname);
}
addcount = 0;
}
#ifdef DATUMREFCNT
+void
free_nsp(nsp)
-struct databuf **nsp;
+ struct databuf **nsp;
{
while (*nsp) {
if (--((*nsp)->d_rcnt)) {