270 lines
6.5 KiB
C
270 lines
6.5 KiB
C
#if !defined(lint) && !defined(SABER)
|
|
static const char rcsid[] = "$Id: ns_ncache.c,v 8.29.4.1 2002/11/14 13:41:31 marka Exp $";
|
|
#endif /* not lint */
|
|
|
|
/*
|
|
* Copyright (c) 1996-2000 by Internet Software Consortium.
|
|
*
|
|
* Permission to use, copy, modify, and distribute this software for any
|
|
* purpose with or without fee is hereby granted, provided that the above
|
|
* copyright notice and this permission notice appear in all copies.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
|
|
* ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
|
|
* OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
|
|
* CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
|
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
|
|
* PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
|
|
* ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
|
|
* SOFTWARE.
|
|
*/
|
|
|
|
#include "port_before.h"
|
|
|
|
#include <sys/types.h>
|
|
#include <sys/param.h>
|
|
#include <sys/socket.h>
|
|
#include <sys/file.h>
|
|
#include <sys/un.h>
|
|
|
|
#include <netinet/in.h>
|
|
#include <arpa/nameser.h>
|
|
|
|
#include <errno.h>
|
|
#include <resolv.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <syslog.h>
|
|
#include <time.h>
|
|
|
|
#include <isc/eventlib.h>
|
|
#include <isc/logging.h>
|
|
|
|
#include "port_after.h"
|
|
|
|
#include "named.h"
|
|
|
|
#define BOUNDS_CHECK(ptr, count) \
|
|
do { \
|
|
if ((ptr) + (count) > eom) { \
|
|
return; \
|
|
} \
|
|
} while (0)
|
|
|
|
void
|
|
cache_n_resp(u_char *msg, int msglen, struct sockaddr_in from,
|
|
const char *qname, int qclass, int qtype)
|
|
{
|
|
struct databuf *dp;
|
|
HEADER *hp;
|
|
u_char *cp, *eom, *rdatap;
|
|
char dname[MAXDNAME];
|
|
int n, type, class, flags;
|
|
u_int ancount, nscount, dlen;
|
|
#ifdef RETURNSOA
|
|
u_int32_t ttl;
|
|
u_int16_t atype;
|
|
u_char *sp, *cp1;
|
|
u_char data[MAXDATA];
|
|
u_char *eod = data + sizeof(data);
|
|
#endif
|
|
|
|
nameserIncr(from.sin_addr, nssRcvdNXD);
|
|
|
|
hp = (HEADER *)msg;
|
|
cp = msg + HFIXEDSZ;
|
|
eom = msg + msglen;
|
|
|
|
switch (ntohs(hp->qdcount)) {
|
|
case 0:
|
|
dname[sizeof dname - 1] = '\0';
|
|
strncpy(dname, qname, sizeof dname);
|
|
if (dname[sizeof dname - 1] != '\0') {
|
|
ns_debug(ns_log_ncache, 1,
|
|
"qp->qname too long (%d)", strlen(qname));
|
|
hp->rcode = FORMERR;
|
|
return;
|
|
}
|
|
class = qclass;
|
|
type = qtype;
|
|
break;
|
|
case 1:
|
|
n = dn_expand(msg, eom, cp, dname, sizeof dname);
|
|
if (n < 0) {
|
|
ns_debug(ns_log_ncache, 1,
|
|
"Query expand name failed: cache_n_resp");
|
|
hp->rcode = FORMERR;
|
|
return;
|
|
}
|
|
cp += n;
|
|
BOUNDS_CHECK(cp, 2 * INT16SZ);
|
|
GETSHORT(type, cp);
|
|
GETSHORT(class, cp);
|
|
if (class > CLASS_MAX) {
|
|
ns_debug(ns_log_ncache, 1,
|
|
"bad class in cache_n_resp");
|
|
hp->rcode = FORMERR;
|
|
return;
|
|
}
|
|
break;
|
|
default:
|
|
ns_debug(ns_log_ncache, 1,
|
|
"QDCOUNT>1 (%d) in cache_n_resp", ntohs(hp->qdcount));
|
|
hp->rcode = FORMERR;
|
|
return;
|
|
}
|
|
ns_debug(ns_log_ncache, 1, "ncache: dname %s, type %d, class %d",
|
|
dname, type, class);
|
|
|
|
ancount = ntohs(hp->ancount);
|
|
nscount = ntohs(hp->nscount);
|
|
|
|
while (ancount--) {
|
|
u_int32_t ttl;
|
|
int atype, aclass;
|
|
|
|
n = dn_skipname(cp, eom);
|
|
if (n < 0) {
|
|
ns_debug(ns_log_ncache, 3, "ncache: form error");
|
|
return;
|
|
}
|
|
cp += n;
|
|
BOUNDS_CHECK(cp, 3 * INT16SZ + INT32SZ);
|
|
GETSHORT(atype, cp);
|
|
GETSHORT(aclass, cp);
|
|
if (atype != T_CNAME || aclass != class) {
|
|
ns_debug(ns_log_ncache, 3,
|
|
"ncache: not CNAME (%s) or wrong class (%s)",
|
|
p_type(atype), p_class(aclass));
|
|
return;
|
|
}
|
|
GETLONG(ttl, cp);
|
|
GETSHORT(dlen, cp);
|
|
BOUNDS_CHECK(cp, dlen);
|
|
rdatap = cp;
|
|
n = dn_expand(msg, msg + msglen, cp, dname, sizeof dname);
|
|
if (n < 0) {
|
|
ns_debug(ns_log_ncache, 3, "ncache: bad cname target");
|
|
return;
|
|
}
|
|
cp += n;
|
|
if (cp != rdatap + dlen) {
|
|
ns_debug(ns_log_ncache, 3, "ncache: bad cname rdata");
|
|
return;
|
|
}
|
|
}
|
|
|
|
dp = NULL;
|
|
#ifdef RETURNSOA
|
|
while (nscount--) {
|
|
sp = cp;
|
|
|
|
/* we store NXDOMAIN as T_SOA regardless of the query type */
|
|
if (hp->rcode == NXDOMAIN)
|
|
type = T_SOA;
|
|
|
|
/* store ther SOA record */
|
|
n = dn_skipname(cp, msg + msglen);
|
|
if (n < 0) {
|
|
ns_debug(ns_log_ncache, 3, "ncache: form error");
|
|
return;
|
|
}
|
|
cp += n;
|
|
|
|
BOUNDS_CHECK(cp, 3 * INT16SZ + INT32SZ);
|
|
GETSHORT(atype, cp); /* type */
|
|
cp += INT16SZ; /* class */
|
|
GETLONG(ttl, cp); /* ttl */
|
|
GETSHORT(dlen, cp); /* dlen */
|
|
BOUNDS_CHECK(cp, dlen);
|
|
if (atype != T_SOA) {
|
|
ns_debug(ns_log_ncache, 3,
|
|
"ncache: type (%d) != T_SOA", atype);
|
|
cp += dlen;
|
|
continue;
|
|
}
|
|
rdatap = cp;
|
|
|
|
/* origin */
|
|
n = dn_expand(msg, msg + msglen, cp, (char*)data, eod - data);
|
|
if (n < 0) {
|
|
ns_debug(ns_log_ncache, 3,
|
|
"ncache: origin form error");
|
|
return;
|
|
}
|
|
cp += n;
|
|
n = strlen((char*)data) + 1;
|
|
cp1 = data + n;
|
|
/* mail */
|
|
n = dn_expand(msg, msg + msglen, cp, (char*)cp1, eod - cp1);
|
|
if (n < 0) {
|
|
ns_debug(ns_log_ncache, 3, "ncache: mail form error");
|
|
return;
|
|
}
|
|
cp += n;
|
|
n = strlen((char*)cp1) + 1;
|
|
cp1 += n;
|
|
n = 5 * INT32SZ;
|
|
if (n > (eod - cp1)) /* Can't happen. See MAXDATA. */
|
|
return;
|
|
BOUNDS_CHECK(cp, n);
|
|
memcpy(cp1, cp, n);
|
|
/* serial, refresh, retry, expire, min */
|
|
cp1 += n;
|
|
cp += n;
|
|
if (cp != rdatap + dlen) {
|
|
ns_debug(ns_log_ncache, 3, "ncache: form error");
|
|
return;
|
|
}
|
|
/* store the zone of the soa record */
|
|
n = dn_expand(msg, msg + msglen, sp, (char*)cp1, eod - cp1);
|
|
if (n < 0) {
|
|
ns_debug(ns_log_ncache, 3, "ncache: form error 2");
|
|
return;
|
|
}
|
|
n = strlen((char*)cp1) + 1;
|
|
cp1 += n;
|
|
|
|
/*
|
|
* we only want to store these long enough so that
|
|
* ns_resp can find it.
|
|
*/
|
|
if (qtype == T_SOA && hp->rcode == NXDOMAIN)
|
|
ttl = 0;
|
|
dp = savedata(class, type,
|
|
MIN(ttl, server_options->max_ncache_ttl) +
|
|
tt.tv_sec, data,
|
|
cp1 - data);
|
|
break;
|
|
}
|
|
#endif
|
|
if (dp == NULL)
|
|
#ifdef STRICT_RFC2308
|
|
dp = savedata(class, type, tt.tv_sec, NULL, 0);
|
|
#else
|
|
dp = savedata(class, type, NTTL + tt.tv_sec, NULL, 0);
|
|
#endif
|
|
dp->d_zone = DB_Z_CACHE;
|
|
dp->d_cred = hp->aa ? DB_C_AUTH : DB_C_ANSWER;
|
|
dp->d_secure = DB_S_INSECURE; /* BEW - should be UNCHECKED */
|
|
dp->d_clev = 0;
|
|
if(hp->rcode == NXDOMAIN) {
|
|
dp->d_rcode = NXDOMAIN;
|
|
flags = DB_NODATA|DB_NOTAUTH|DB_NOHINTS;
|
|
} else {
|
|
dp->d_rcode = NOERROR_NODATA;
|
|
flags = DB_NOTAUTH|DB_NOHINTS;
|
|
}
|
|
|
|
n = db_update(dname, dp, dp, NULL, flags, hashtab, from);
|
|
if (n != OK)
|
|
ns_debug(ns_log_ncache, 1,
|
|
"db_update failed (%d), cache_n_resp()", n);
|
|
else
|
|
ns_debug(ns_log_ncache, 4,
|
|
"ncache succeeded: [%s %s %s] rcode:%d ttl:%ld",
|
|
dname, p_type(type), p_class(class),
|
|
dp->d_rcode, (long)(dp->d_ttl - tt.tv_sec));
|
|
db_detach(&dp);
|
|
}
|