summaryrefslogtreecommitdiffstats
path: root/contrib/bind/bin/named/ns_req.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/bind/bin/named/ns_req.c')
-rw-r--r--contrib/bind/bin/named/ns_req.c514
1 files changed, 406 insertions, 108 deletions
diff --git a/contrib/bind/bin/named/ns_req.c b/contrib/bind/bin/named/ns_req.c
index 252ddbd..6695881 100644
--- a/contrib/bind/bin/named/ns_req.c
+++ b/contrib/bind/bin/named/ns_req.c
@@ -1,6 +1,6 @@
#if !defined(lint) && !defined(SABER)
static const char sccsid[] = "@(#)ns_req.c 4.47 (Berkeley) 7/1/91";
-static const char rcsid[] = "$Id: ns_req.c,v 8.138.2.4 2001/08/10 03:00:14 marka Exp $";
+static const char rcsid[] = "$Id: ns_req.c,v 8.162 2002/02/01 00:05:36 marka Exp $";
#endif /* not lint */
/*
@@ -153,11 +153,11 @@ static enum req_action req_query(HEADER *hp, u_char **cpp, u_char *eom,
int *buflenp, int *msglenp,
u_char *msg, int dfd, int *ra,
struct sockaddr_in from,
- struct tsig_record *in_tsig);
+ struct tsig_record *in_tsig,
+ u_int16_t udpsize);
static enum req_action req_iquery(HEADER *hp, u_char **cpp, u_char *eom,
- int *buflenp, u_char *msg,
- struct sockaddr_in from);
+ int *buflenp, struct sockaddr_in from);
#ifdef BIND_NOTIFY
static enum req_action req_notify(HEADER *hp, u_char **cpp, u_char *eom,
@@ -165,6 +165,132 @@ static enum req_action req_notify(HEADER *hp, u_char **cpp, u_char *eom,
#endif
/*
+ * See if there is a OPT record at the end of the message.
+ *
+ * Results:
+ * -1 FORMERR
+ * 0 last RR is not a OPT record
+ * n>0 lenght of OPT record
+ */
+int
+ns_get_opt(u_char *msg, u_char *eom,
+ u_int8_t *versionp, u_int16_t *rcodep, u_int16_t *flagp,
+ u_int16_t *bufsizep, u_char **optionsp, size_t *optsizep)
+{
+ HEADER *hp = (HEADER *) msg;
+ u_char *start, *options, *cp;
+ u_int8_t version;
+ u_int16_t rdlen, type, bufsize, flags, optsize, rcode;
+ int i, n, root;
+
+ if (msg == NULL || eom == NULL || (msg + HFIXEDSZ) > eom)
+ return (-1);
+
+ if (ntohs(hp->arcount) == 0)
+ return (0);
+
+ cp = msg + HFIXEDSZ;
+ n = ns_skiprr(cp, eom, ns_s_qd, ntohs(hp->qdcount));
+ if (n < 0)
+ return (-1);
+ cp += n;
+ n = ns_skiprr(cp, eom, ns_s_an, ntohs(hp->ancount));
+ if (n < 0)
+ return (-1);
+ cp += n;
+ n = ns_skiprr(cp, eom, ns_s_ns, ntohs(hp->nscount));
+ if (n < 0)
+ return (-1);
+ cp += n;
+ i = ntohs(hp->arcount);
+ while (i-- > 0) {
+ start = cp;
+ if (cp >= eom)
+ return (-1);
+ root = (*cp == 0);
+ n = dn_skipname(cp, eom);
+ if (n < 0)
+ return (-1);
+ cp += n;
+ if (cp + (2 + 2 + 4 + 2) > eom)
+ return (-1);
+ GETSHORT(type, cp);
+ if (type != ns_t_opt) {
+ cp += INT16SZ + INT32SZ; /* class, ttl */
+ GETSHORT(rdlen, cp);
+ if (cp + rdlen > eom)
+ return (-1);
+ cp += rdlen;
+ continue;
+ }
+ /* We have the OPT record. Check it out in detail. */
+ if (!root)
+ return (-1);
+ GETSHORT(bufsize, cp);
+ rcode = (*cp++ <<4) + hp->rcode ;
+ version = *cp++;
+ GETSHORT(flags, cp);
+ GETSHORT(rdlen, cp);
+ /* ensure options are well formed */
+ options = cp;
+ optsize = rdlen;
+ while (rdlen != 0) {
+ u_int16_t code;
+ u_int16_t len;
+
+ if (rdlen < 4)
+ return (-1);
+ GETSHORT(code, cp);
+ GETSHORT(len, cp);
+ rdlen -= 4;
+ if (len > rdlen)
+ return (-1);
+ cp += len;
+ rdlen -= len;
+ }
+ /* Everything checks out. */
+ if (versionp != NULL)
+ *versionp = version;
+ if (rcodep != NULL)
+ *rcodep = rcode;
+ if (flagp != NULL)
+ *flagp = flags;
+ if (bufsizep != NULL)
+ *bufsizep = bufsize;
+ if (optionsp != NULL)
+ *optionsp = options;
+ if (optsizep != NULL)
+ *optsizep = optsize;
+ return (cp - start);
+ }
+ /* OPT not found */
+ return (0);
+}
+
+int
+ns_add_opt(u_char *msg, u_char *cp, size_t buflen, u_int8_t version,
+ u_int16_t rcode, u_int16_t size, u_int16_t flags,
+ u_char *options, size_t optlen)
+{
+ HEADER *hp = (HEADER *) msg;
+
+ if ((cp + 1 + 2 + 2 + 4 + 2 + optlen) > (msg + buflen))
+ return (-1);
+
+ *cp++ = 0; /* "." */
+ PUTSHORT(ns_t_opt, cp); /* type */
+ PUTSHORT(size, cp); /* class (udp size) */
+ *cp++ = (rcode >> 4) & 0xff; /* ttl (rcode + version + flags) */
+ hp->rcode = rcode & 0xf;
+ *cp++ = version;
+ PUTSHORT(flags, cp);
+ PUTSHORT(optlen, cp); /* rdlen */
+ memcpy(cp, options, optlen); /* options */
+ hp->arcount = htons(ntohs(hp->arcount) + 1);
+ return (1 + 2 + 2 + 4 + 2 + optlen);
+}
+
+/*
* Process request using database; assemble and send response.
*/
void
@@ -173,8 +299,8 @@ ns_req(u_char *msg, int msglen, int buflen, struct qstream *qsp,
{
HEADER *hp = (HEADER *) msg;
u_char *cp, *eom;
- enum req_action action;
- int n, ra, has_tsig, tsig_size, sig2len;
+ enum req_action action = Return;
+ int n, ra, has_tsig, tsig_size = 0, opt_size = 0, sig2len;
u_char *tsigstart;
u_char sig[TSIG_SIG_SIZE], sig2[TSIG_SIG_SIZE];
struct tsig_record *in_tsig = NULL;
@@ -182,8 +308,13 @@ ns_req(u_char *msg, int msglen, int buflen, struct qstream *qsp,
int msglen_orig = msglen;
int buflen_orig = buflen;
int siglen = sizeof sig;
- DST_KEY *key;
+ DST_KEY *key = NULL;
time_t tsig_time;
+ int opt = 0;
+ u_int8_t version = 0;
+ u_int16_t rcode = ns_r_noerror;
+ u_int16_t udpsize = 0;
+ int drop;
#ifdef DEBUG
if (debug > 3) {
@@ -192,6 +323,10 @@ ns_req(u_char *msg, int msglen, int buflen, struct qstream *qsp,
}
#endif
+ drop = drop_port(ntohs(from.sin_port));
+ if (qsp == NULL && drop == 1)
+ return;
+
tsigstart = ns_find_tsig(msg, msg + msglen);
if (tsigstart == NULL)
has_tsig = 0;
@@ -260,6 +395,7 @@ ns_req(u_char *msg, int msglen, int buflen, struct qstream *qsp,
in_tsig->siglen = siglen;
memcpy(in_tsig->sig, sig, siglen);
tsig_size = msglen_orig - msglen;
+ in_tsig->tsig_size = tsig_size;
} else if (has_tsig) {
action = Finish;
in_tsig = memget(sizeof(struct tsig_record));
@@ -268,6 +404,7 @@ ns_req(u_char *msg, int msglen, int buflen, struct qstream *qsp,
in_tsig->key = NULL;
in_tsig->siglen = 0;
tsig_size = msg + msglen - tsigstart;
+ in_tsig->tsig_size = tsig_size;
msglen = tsigstart - msg;
}
@@ -275,6 +412,30 @@ ns_req(u_char *msg, int msglen, int buflen, struct qstream *qsp,
nsid_hash((u_char *)&tt, sizeof(tt));
nsid_hash(msg, (msglen > 512) ? 512 : msglen);
+ if (error == NOERROR) {
+
+ opt = ns_get_opt(msg, msg + msglen, &version,
+ NULL, NULL, &udpsize, NULL, NULL);
+ if (opt < 0) {
+ rcode = ns_r_formerr;
+ action = Finish;
+ } else if (opt == 0) {
+ if (qsp == NULL && buflen > PACKETSZ)
+ buflen_orig = buflen = PACKETSZ;
+ } else if (opt > 0) {
+ if (version != 0) {
+ rcode = ns_r_badvers;
+ action = Finish;
+ }
+ opt_size = 11;
+ if (udpsize < 512)
+ udpsize = 512;
+ if (qsp == NULL && buflen > udpsize)
+ buflen_orig = buflen = udpsize;
+ }
+ } else if (qsp == NULL && buflen > PACKETSZ)
+ buflen_orig = buflen = PACKETSZ;
+
/*
* It's not a response so these bits have no business
* being set. will later simplify work if we can
@@ -290,6 +451,8 @@ ns_req(u_char *msg, int msglen, int buflen, struct qstream *qsp,
if (error == NOERROR)
hp->rcode = ns_r_noerror;
+ if (rcode == ns_r_noerror)
+ rcode = hp->rcode;
cp = msg + HFIXEDSZ;
eom = msg + msglen;
buflen -= HFIXEDSZ;
@@ -297,16 +460,17 @@ ns_req(u_char *msg, int msglen, int buflen, struct qstream *qsp,
free_addinfo(); /* sets addcount to zero */
dnptrs[0] = NULL;
- if (error == NOERROR) {
+ if (error == NOERROR && rcode == ns_r_noerror) {
switch (hp->opcode) {
case ns_o_query:
action = req_query(hp, &cp, eom, qsp,
&buflen, &msglen,
- msg, dfd, &ra, from, in_tsig);
+ msg, dfd, &ra, from,
+ in_tsig, udpsize);
break;
case ns_o_iquery:
- action = req_iquery(hp, &cp, eom, &buflen, msg, from);
+ action = req_iquery(hp, &cp, eom, &buflen, from);
break;
#ifdef BIND_NOTIFY
@@ -317,8 +481,7 @@ ns_req(u_char *msg, int msglen, int buflen, struct qstream *qsp,
#ifdef BIND_UPDATE
case ns_o_update:
- action = req_update(hp, cp, eom, msg, qsp, dfd, from,
- in_tsig);
+ action = req_update(hp, cp, eom, msg, from, in_tsig);
break;
#endif /* BIND_UPDATE */
@@ -334,6 +497,7 @@ ns_req(u_char *msg, int msglen, int buflen, struct qstream *qsp,
hp->rcode = ns_r_notimpl;
action = Finish;
}
+ rcode = hp->rcode;
}
if (in_tsig != NULL) {
@@ -342,13 +506,20 @@ ns_req(u_char *msg, int msglen, int buflen, struct qstream *qsp,
}
/*
+ * Loop advoidance.
+ */
+ if (qsp == NULL && drop == 2 &&
+ (hp->rcode == FORMERR || hp->rcode == NOTIMP))
+ action = Return;
+
+ /*
* Vector via internal opcode.
*/
switch (action) {
case Return:
return;
case Refuse:
- hp->rcode = ns_r_refused;
+ rcode = hp->rcode = ns_r_refused;
cp = eom;
/*FALLTHROUGH*/
case Finish:
@@ -365,13 +536,14 @@ ns_req(u_char *msg, int msglen, int buflen, struct qstream *qsp,
hp->qr = 1; /* set Response flag */
hp->ra = ra; /* init above, may be modified by req_query */
- if (!hp->tc && has_tsig > 0 && buflen < tsig_size)
+ if (!hp->tc && (has_tsig > 0 || opt > 0) &&
+ buflen < (tsig_size + opt_size))
hp->tc = 1;
/*
* If there was a format error, then we don't know what the msg has.
*/
- if (hp->rcode == ns_r_formerr) {
+ if (hp->rcode == ns_r_formerr || rcode == ns_r_badvers) {
hp->qdcount = htons(0);
hp->ancount = htons(0);
hp->nscount = htons(0);
@@ -380,44 +552,67 @@ ns_req(u_char *msg, int msglen, int buflen, struct qstream *qsp,
}
/*
- * If the query had a TSIG and the message is truncated or there was
- * a TSIG error, build a new message with no data and a TSIG.
+ * If the query had a TSIG / OPT and the message is truncated or
+ * there was a TSIG error, build a new message with no data and a
+ * TSIG / OPT.
*/
- if ((hp->tc || error != NOERROR) && has_tsig > 0) {
+ if ((hp->tc || error != NOERROR) && (has_tsig > 0 || opt > 0)) {
sign_again:
hp->ancount = htons(0);
hp->nscount = htons(0);
hp->arcount = htons(0);
cp = msg + HFIXEDSZ;
cp += ns_skiprr(cp, msg + msglen, ns_s_qd, ntohs(hp->qdcount));
- sig2len = sizeof sig2;
- msglen = cp - msg;
- buflen = buflen_orig - msglen;
- n = ns_sign(msg, &msglen, msglen + buflen, error, key,
- sig, siglen, sig2, &sig2len, tsig_time);
- if (n == NS_TSIG_ERROR_NO_SPACE && ntohs(hp->qdcount) != 0) {
- hp->qdcount = htons(0);
- goto sign_again;
+ if (opt > 0) {
+ n = ns_add_opt(msg, cp, buflen_orig, 0,
+ rcode, EDNS_MESSAGE_SZ, 0, NULL, 0);
+ if (n < 0) {
+ hp->qdcount = htons(0);
+ goto sign_again;
+ }
+ cp += n;
+ }
+ if (has_tsig > 0) {
+ sig2len = sizeof sig2;
+ msglen = cp - msg;
+ buflen = buflen_orig - msglen;
+ n = ns_sign(msg, &msglen, msglen + buflen, error, key,
+ sig, siglen, sig2, &sig2len, tsig_time);
+ if (n == NS_TSIG_ERROR_NO_SPACE &&
+ ntohs(hp->qdcount) != 0) {
+ hp->qdcount = htons(0);
+ goto sign_again;
+ }
+ if (n != 0)
+ ns_info(ns_log_default,
+ "ns_req: unable to sign response");
+ cp = msg + msglen;
}
- if (n != 0)
- ns_info(ns_log_default,
- "ns_req: unable to sign response");
- cp = msg + msglen;
}
- /* Either the message is not truncated or there was no TSIG */
+ /* Either the message is not truncated or there was no TSIG & OPT */
else {
/*
* Reserve space for tsig if required.
*/
- if (has_tsig > 0)
- buflen -= tsig_size;
+ if (has_tsig > 0 || opt_size != 0)
+ buflen -= tsig_size + opt_size;
+ INSIST(buflen >= 0);
+ msglen = cp - msg;
n = doaddinfo(hp, cp, buflen);
cp += n;
buflen -= n;
+ msglen += n;
+ if (opt > 0) {
+ buflen += opt_size;
+ n = ns_add_opt(msg, cp, msglen + buflen, 0,
+ rcode, EDNS_MESSAGE_SZ, 0, NULL, 0);
+ INSIST(n > 0);
+ cp += n;
+ buflen -= n;
+ }
if (has_tsig > 0) {
buflen += tsig_size;
sig2len = sizeof sig2;
- msglen = cp - msg;
n = ns_sign(msg, &msglen, msglen + buflen, error, key,
sig, siglen, sig2, &sig2len, tsig_time);
if (n != 0) {
@@ -608,16 +803,42 @@ req_notify(HEADER *hp, u_char **cpp, u_char *eom, u_char *msg,
}
#endif /*BIND_NOTIFY*/
+static int
+add_bind(HEADER *hp, u_char **cpp, u_char *msg, int *msglenp,
+ const char *label, const char *data)
+{
+ u_char *tp;
+
+ hp->ancount = htons(1);
+ hp->nscount = htons(0);
+ hp->arcount = htons(0);
+ hp->rcode = ns_r_noerror;
+ hp->aa = 1;
+ hp->ra = 0;
+ copyCharString(cpp, label); /* Name */
+ copyCharString(cpp, "BIND");
+ *(*cpp)++ = 0x00;
+ PUTSHORT(T_TXT, *cpp); /* Type */
+ PUTSHORT(C_CHAOS, *cpp); /* Class */
+ PUTLONG(0, *cpp); /* TTL */
+ tp = *cpp; /* Temp RdLength */
+ PUTSHORT(0, *cpp);
+ copyCharString(cpp, data);
+ PUTSHORT((*cpp) - (tp + INT16SZ), tp); /* Real RdLength */
+ *msglenp = *cpp - msg; /* Total message length */
+ return (Finish);
+}
static enum req_action
req_query(HEADER *hp, u_char **cpp, u_char *eom, struct qstream *qsp,
int *buflenp, int *msglenp, u_char *msg, int dfd, int *ra,
- struct sockaddr_in from, struct tsig_record *in_tsig)
+ struct sockaddr_in from, struct tsig_record *in_tsig,
+ u_int16_t udpsize)
{
int n, class, type, count, zone, foundname, founddata, omsglen, cname;
int recursion_blocked_by_acl;
u_int16_t id;
- u_int32_t serial_ixfr;
+ u_int32_t serial_ixfr = 0;
int ixfr_found;
int ixfr_error = 0;
char dnbuf2[MAXDNAME];
@@ -631,6 +852,8 @@ req_query(HEADER *hp, u_char **cpp, u_char *eom, struct qstream *qsp,
struct zoneinfo *zp;
struct databuf *dp;
DST_KEY *in_key = (in_tsig != NULL) ? in_tsig->key : NULL;
+ int access_class;
+ int adjustlen = 0;
nameserIncr(from.sin_addr, nssRcvdQ);
@@ -648,14 +871,19 @@ req_query(HEADER *hp, u_char **cpp, u_char *eom, struct qstream *qsp,
/* valid queries have one question and zero answers */
if ((ntohs(hp->qdcount) != 1)
- || ntohs(hp->ancount) != 0
- || ntohs(hp->arcount) != 0) {
+ || ntohs(hp->ancount) != 0) {
ns_debug(ns_log_default, 1,
"FORMERR Query header counts wrong");
hp->rcode = ns_r_formerr;
return (Finish);
}
+ if (ntohs(hp->arcount) != 0) {
+ ns_debug(ns_log_default, 1, "Ignoring addition section");
+ hp->arcount = htons(0);
+ adjustlen = 1;
+ }
+
/*
* Get domain name, class, and type.
*/
@@ -680,8 +908,9 @@ req_query(HEADER *hp, u_char **cpp, u_char *eom, struct qstream *qsp,
GETSHORT(type, *cpp);
GETSHORT(class, *cpp);
if (*cpp < eom && type != ns_t_ixfr) {
- ns_debug(ns_log_default, 6,
- "message length > received message");
+ if (!adjustlen)
+ ns_debug(ns_log_default, 6,
+ "message length > received message");
*msglenp = *cpp - msg;
}
@@ -748,7 +977,7 @@ req_query(HEADER *hp, u_char **cpp, u_char *eom, struct qstream *qsp,
}
GETLONG(serial_ixfr, *cpp);
/* ignore other soa counters */
- if ((*cpp + (4 * INT32SZ)) < eom)
+ if ((*cpp + (4 * INT32SZ)) < eom && !adjustlen)
ns_debug(ns_log_default, 6,
"ixfr: message length > received message");
/* Reset msglenp to cover just the question. */
@@ -838,9 +1067,15 @@ req_query(HEADER *hp, u_char **cpp, u_char *eom, struct qstream *qsp,
/*
* Begin Access Control Point
*/
-
zone = DB_Z_CACHE;
+
+ /*
+ * Map class ANY to to class IN for the purpose of access control.
+ */
+ access_class = (class == C_ANY && !ns_t_xfr_p(type)) ? C_IN : class;
+
if (np) {
+#ifndef FORWARD_ALLOWS
struct namebuf *access_np;
/*
@@ -855,13 +1090,35 @@ req_query(HEADER *hp, u_char **cpp, u_char *eom, struct qstream *qsp,
for (access_np = np; access_np != NULL;
access_np = np_parent(access_np)) {
dp = access_np->n_data;
- while (dp && dp->d_class != class)
+ while (dp && dp->d_class != access_class)
dp = dp->d_next;
if (dp != NULL) {
zone = dp->d_zone;
break;
}
}
+#else
+ /*
+ * Try looking for forward zone. It can be deeper than
+ * any entry in the cache.
+ */
+ if (zone == DB_Z_CACHE) {
+ char *s = dname;
+ int escape = 0;
+ while ((zp = find_zone(s, access_class)) == NULL) {
+ if (*s == '\0')
+ break;
+ while (*s != '\0' && (escape || *s != '.')) {
+ escape = escape ? 0 : (*s == '\\');
+ s++;
+ }
+ if (*s == '.')
+ s++;
+ }
+ if (zp != NULL)
+ zone = zp - zones;
+ }
+#endif
}
zp = &zones[zone];
@@ -941,8 +1198,9 @@ req_query(HEADER *hp, u_char **cpp, u_char *eom, struct qstream *qsp,
for (access_np = np; access_np != NULL;
access_np = np_parent(access_np)) {
dp = access_np->n_data;
- while (dp && (dp->d_class != class ||
- dp->d_zone == DB_Z_CACHE))
+ while (dp &&
+ (dp->d_class != access_class ||
+ dp->d_zone == DB_Z_CACHE))
dp = dp->d_next;
if (dp != NULL) {
zone = dp->d_zone;
@@ -961,9 +1219,9 @@ req_query(HEADER *hp, u_char **cpp, u_char *eom, struct qstream *qsp,
}
}
ns_notice(ns_log_security,
- "denied query from %s for \"%s\" %s",
+ "denied query from %s for \"%s\" %s/%s",
sin_ntoa(from), *dname ? dname : ".",
- p_class(class));
+ p_type(type), p_class(class));
nameserIncr(from.sin_addr, nssRcvdUQ);
return (Refuse);
}
@@ -1054,28 +1312,18 @@ req_query(HEADER *hp, u_char **cpp, u_char *eom, struct qstream *qsp,
* Yow!
*/
if (class == ns_c_chaos && type == ns_t_txt &&
- ns_samename(dnbuf, "VERSION.BIND") == 1) {
- u_char *tp;
+ ns_samename(dnbuf, "VERSION.BIND") == 1 &&
+ server_options->version != NULL &&
+ server_options->version[0] != '\0')
+ return (add_bind(hp, cpp, msg, msglenp,
+ "VERSION", server_options->version));
- hp->ancount = htons(1);
- hp->nscount = htons(0);
- hp->arcount = htons(0);
- hp->rcode = ns_r_noerror;
- hp->aa = 1;
- hp->ra = 0;
- copyCharString(cpp, "VERSION"); /* Name */
- copyCharString(cpp, "BIND");
- *(*cpp)++ = 0x00;
- PUTSHORT(T_TXT, *cpp); /* Type */
- PUTSHORT(C_CHAOS, *cpp); /* Class */
- PUTLONG(0, *cpp); /* TTL */
- tp = *cpp; /* Temp RdLength */
- PUTSHORT(0, *cpp);
- copyCharString(cpp, server_options->version);
- PUTSHORT((*cpp) - (tp + INT16SZ), tp); /* Real RdLength */
- *msglenp = *cpp - msg; /* Total message length */
- return (Finish);
- }
+ if (class == ns_c_chaos && type == ns_t_txt &&
+ ns_samename(dnbuf, "HOSTNAME.BIND") == 1 &&
+ server_options->hostname != NULL &&
+ server_options->hostname[0] != '\0')
+ return (add_bind(hp, cpp, msg, msglenp,
+ "HOSTNAME", server_options->hostname));
/*
* If we don't know anything about the requested name,
@@ -1365,8 +1613,9 @@ req_query(HEADER *hp, u_char **cpp, u_char *eom, struct qstream *qsp,
if (n < 0) {
ns_info(ns_log_default, "res_mkquery(%s) failed",
dname);
- hp->rcode = ns_r_servfail;
+ memcpy(msg, omsg, omsglen);
memput(omsg, omsglen);
+ hp->rcode = ns_r_servfail;
free_nsp(nsp);
return (Finish);
}
@@ -1375,7 +1624,9 @@ req_query(HEADER *hp, u_char **cpp, u_char *eom, struct qstream *qsp,
n = ns_forw(nsp, msg, *msglenp, from, qsp, dfd, &qp,
dname, class, type, np, 0, in_tsig);
if (n != FW_OK && cname) {
+ memcpy(msg, omsg, omsglen);
memput(omsg, omsglen);
+ *msglenp = omsglen;
omsg = NULL;
}
switch (n) {
@@ -1387,6 +1638,11 @@ req_query(HEADER *hp, u_char **cpp, u_char *eom, struct qstream *qsp,
qp->q_cmsgsize = omsglen;
qp->q_id = id;
}
+ if (udpsize != 0) {
+ qp->q_flags |= Q_EDNS;
+ qp->q_udpsize = udpsize;
+ } else
+ qp->q_udpsize = PACKETSZ;
break;
case FW_DUP:
break; /* Duplicate request dropped */
@@ -1441,7 +1697,7 @@ req_query(HEADER *hp, u_char **cpp, u_char *eom, struct qstream *qsp,
static enum req_action
req_iquery(HEADER *hp, u_char **cpp, u_char *eom, int *buflenp,
- u_char *msg, struct sockaddr_in from)
+ struct sockaddr_in from)
{
u_int rdata_offset;
size_t alen;
@@ -1561,7 +1817,7 @@ req_iquery(HEADER *hp, u_char **cpp, u_char *eom, int *buflenp,
*buflenp -= INT16SZ;
hp->qdcount = htons(1);
- if (alen > *buflenp) {
+ if ((int)alen > *buflenp) {
hp->tc = 1;
return (Finish);
}
@@ -1578,6 +1834,10 @@ int
stale(struct databuf *dp) {
struct zoneinfo *zp = &zones[dp->d_zone];
+#ifdef CHECK_MAGIC
+ INSIST(dp->d_magic == DATABUF_MAGIC);
+#endif
+
switch (zp->z_type) {
case z_master:
@@ -1662,6 +1922,7 @@ make_rr(const char *name, struct databuf *dp, u_char *buf,
int32_t n;
int16_t type = dp->d_type;
u_int32_t ttl;
+ u_char naptr_flag;
ns_debug(ns_log_default, 5,
"make_rr(%s, %lx, %lx, %d, %d) %d zone %d ttl %lu",
@@ -1801,6 +2062,7 @@ make_rr(const char *name, struct databuf *dp, u_char *buf,
buflen -= n + 1;
if (buflen < 0)
goto cleanup;
+ naptr_flag = (n == 1) ? *cp1 : 0;
*cp++ = n;
memcpy(cp, cp1, n);
cp += n;
@@ -1839,6 +2101,14 @@ make_rr(const char *name, struct databuf *dp, u_char *buf,
if (n < 0)
goto cleanup;
cp += n;
+ if (doadd && *cp1 != 0) {
+ if (naptr_flag == 's' || naptr_flag == 'S')
+ addname((char*)cp1, name, type, T_SRV,
+ dp->d_class);
+ if (naptr_flag == 'a' || naptr_flag == 'A')
+ addname((char*)cp1, name, type, T_A,
+ dp->d_class);
+ }
/* save data length */
n = (u_int16_t)((cp - sp) - INT16SZ);
@@ -2022,8 +2292,9 @@ doaddinfo(HEADER *hp, u_char *msg, int msglen) {
const char *fname;
register int n, count;
register int ns_logging;
- int finishedA = 0;
- int save_addcount = addcount;
+ int pass = 0;
+ int i, doadd;
+
if (!addcount)
return (0);
@@ -2043,15 +2314,18 @@ doaddinfo(HEADER *hp, u_char *msg, int msglen) {
count = 0;
cp = msg;
loop:
- for (ap = addinfo; --addcount >= 0; ap++) {
+ for (ap = addinfo, i = 0; i < addcount; ap++, i++) {
int foundany = 0,
foundcname = 0,
save_count = count,
save_msglen = msglen;
u_char *save_cp = cp;
- if ((finishedA == 1 && ap->a_type == T_A) ||
- (finishedA == 0 && ap->a_type == T_KEY))
+ if ((pass != 0 &&
+ (pass != 1 || server_options->preferred_glue == 0) &&
+ ap->a_type == T_A) ||
+ (pass != 0 && ap->a_type == T_SRV) ||
+ (pass != 2 && ap->a_type == T_KEY))
continue;
if (ns_logging)
ns_debug(ns_log_default, 3,
@@ -2066,35 +2340,52 @@ loop:
/* look for the data */
(void)delete_stale(np);
for (dp = np->n_data; dp != NULL; dp = dp->d_next) {
- if (dp->d_rcode)
+ if (dp->d_rcode == NXDOMAIN) {
+ if (dp->d_class == ap->a_class)
+ foundany++;
continue;
+ }
if ((match(dp, (int)ap->a_class, T_CNAME) &&
- dp->d_type == T_CNAME) ||
- (match(dp, C_IN, T_CNAME) &&
dp->d_type == T_CNAME)) {
foundcname++;
break;
}
+ if (pass == 0 && ap->a_type == T_A &&
+ server_options->preferred_glue != 0 &&
+ !match(dp, (int)ap->a_class,
+ server_options->preferred_glue)) {
+ continue;
+ }
+ if (pass != 0 && ap->a_type == T_A &&
+ server_options->preferred_glue != 0 &&
+ match(dp, (int)ap->a_class,
+ server_options->preferred_glue)) {
+ continue;
+ }
if (ap->a_type == T_A &&
!match(dp, (int)ap->a_class, T_A) &&
- !match(dp, C_IN, T_A) &&
!match(dp, (int)ap->a_class, T_AAAA) &&
- !match(dp, C_IN, T_AAAA) &&
- !match(dp, (int)ap->a_class, ns_t_a6) &&
- !match(dp, C_IN, ns_t_a6)) {
+ !match(dp, (int)ap->a_class, ns_t_a6)) {
continue;
}
if (ap->a_type == T_KEY &&
- !match(dp, (int)ap->a_class, T_KEY) &&
- !match(dp, C_IN, T_KEY))
+ !match(dp, (int)ap->a_class, T_KEY))
+ continue;
+ if (ap->a_type == T_SRV &&
+ !match(dp, (int)ap->a_class, T_SRV))
continue;
foundany++;
+ if (dp->d_rcode)
+ continue;
/*
* Should be smart and eliminate duplicate
* data here. XXX
*/
- if ((n = make_rr(ap->a_dname, dp, cp, msglen, 0,
+ doadd = 0;
+ if (ap->a_type == T_SRV)
+ doadd = 1;
+ if ((n = make_rr(ap->a_dname, dp, cp, msglen, doadd,
dnptrs, dnptrs_end, 0)) < 0) {
/* truncation in the additional-data section
* is not all that serious. we do not set TC,
@@ -2130,7 +2421,8 @@ loop:
(ap->a_type == T_A || ap->a_type == T_AAAA)) {
/* ask a real server for this info */
(void) sysquery(ap->a_dname, (int)ap->a_class,
- ap->a_type, NULL, 0, ns_port, QUERY);
+ ap->a_type, NULL, NULL, 0, ns_port,
+ QUERY, 0);
}
if (foundcname) {
if (!haveComplained(nhash(ap->a_dname),
@@ -2141,15 +2433,15 @@ loop:
p_type(ap->a_rtype), ap->a_dname);
}
}
- freestr(ap->a_dname);
- freestr(ap->a_rname);
}
- if (finishedA == 0) {
- finishedA = 1;
- addcount = save_addcount;
+ if (pass++ < 2)
goto loop; /* now do the KEYs... */
- }
hp->arcount = htons((u_int16_t)count);
+ for (ap = addinfo, i = 0; i < addcount; ap++, i++) {
+ ap->a_dname = freestr(ap->a_dname);
+ ap->a_rname = freestr(ap->a_rname);
+ }
+ addcount = 0;
return (cp - msg);
}
@@ -2188,27 +2480,16 @@ free_addinfo() {
struct addinfo *ap;
for (ap = addinfo; --addcount >= 0; ap++) {
- freestr(ap->a_dname);
- freestr(ap->a_rname);
+ ap->a_dname = freestr(ap->a_dname);
+ ap->a_rname = freestr(ap->a_rname);
}
addcount = 0;
}
void
free_nsp(struct databuf **nsp) {
- while (*nsp) {
- DRCNTDEC(*nsp);
- if ((*nsp)->d_rcnt)
- ns_debug(ns_log_default, 3, "free_nsp: %s rcnt %d",
- (*nsp)->d_data, (*nsp)->d_rcnt);
- else {
- ns_debug(ns_log_default, 3,
- "free_nsp: %s rcnt %d delayed",
- (*nsp)->d_data, (*nsp)->d_rcnt);
- db_freedata(*nsp); /* delayed free */
- }
- *nsp++ = NULL;
- }
+ while (*nsp)
+ db_detach(nsp++);
}
static void
@@ -2218,3 +2499,20 @@ copyCharString(u_char **dst, const char *src) {
memcpy(*dst, src, len);
*dst += len;
}
+
+/*
+ * Questionable source ports for queries / responses.
+ */
+int
+drop_port(u_int16_t port) {
+ switch (port) {
+ case 7: /* echo */
+ case 13: /* daytime */
+ case 19: /* chargen */
+ case 37: /* time */
+ return (1);
+ case 464: /* kpasswd */
+ return (2);
+ }
+ return (0);
+}
OpenPOWER on IntegriCloud