NetBSD/usr.sbin/bind/named/ns_ncache.c

229 lines
5.4 KiB
C

/* $NetBSD: ns_ncache.c,v 1.1.1.1 1998/10/05 18:02:00 tron Exp $ */
#if !defined(lint) && !defined(SABER)
static char rcsid[] = "Id: ns_ncache.c,v 8.17 1998/03/20 01:12:01 halley Exp";
#endif /* not lint */
/*
* Copyright (c) 1996, 1997 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 <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) {
struct databuf *dp;
HEADER *hp;
u_char *cp, *eom, *rdatap;
char dname[MAXDNAME];
int n;
int type, class;
int Vcode;
int flags;
u_int16_t ancount;
u_int dlen;
nameserIncr(from.sin_addr, nssRcvdNXD);
hp = (HEADER *)msg;
cp = msg+HFIXEDSZ;
eom = msg + msglen;
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);
ns_debug(ns_log_ncache, 1, "ncache: dname %s, type %d, class %d",
dname, type, class);
ancount = ntohs(hp->ancount);
while (ancount--) {
u_int32_t ttl;
u_int16_t atype;
u_int16_t 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: form error");
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: form error");
return;
}
cp += n;
if (cp != rdatap + dlen) {
ns_debug(ns_log_ncache, 3, "ncache: form error");
return;
}
}
#ifdef RETURNSOA
if (hp->nscount) {
u_int32_t ttl;
u_int16_t atype;
u_char *tp = cp;
u_char *cp1;
u_char data[MAXDATA];
size_t len = sizeof data;
/* 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(tp, msg + msglen);
if (n < 0) {
ns_debug(ns_log_ncache, 3, "ncache: form error");
return;
}
tp += n;
BOUNDS_CHECK(tp, 3 * INT16SZ + INT32SZ);
GETSHORT(atype, tp); /* type */
if (atype != T_SOA) {
ns_debug(ns_log_ncache, 3,
"ncache: type (%d) != T_SOA", atype);
goto no_soa;
}
tp += INT16SZ; /* class */
GETLONG(ttl, tp); /* ttl */
GETSHORT(dlen, tp); /* dlen */
BOUNDS_CHECK(tp, dlen);
rdatap = tp;
/* origin */
n = dn_expand(msg, msg + msglen, tp, (char*)data, len);
if (n < 0) {
ns_debug(ns_log_ncache, 3,
"ncache: origin form error");
return;
}
tp += n;
n = strlen((char*)data) + 1;
cp1 = data + n;
len -= n;
/* mail */
n = dn_expand(msg, msg + msglen, tp, (char*)cp1, len);
if (n < 0) {
ns_debug(ns_log_ncache, 3, "ncache: mail form error");
return;
}
tp += n;
n = strlen((char*)cp1) + 1;
cp1 += n;
len -= n;
n = 5 * INT32SZ;
BOUNDS_CHECK(tp, n);
memcpy(cp1, tp, n);
/* serial, refresh, retry, expire, min */
cp1 += n;
len -= n;
tp += n;
if (tp != 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, cp, (char*)cp1, len);
if (n < 0) {
ns_debug(ns_log_ncache, 3, "ncache: form error 2");
return;
}
n = strlen((char*)cp1) + 1;
cp1 += n;
dp = savedata(class, type, MIN(ttl, NTTL) + tt.tv_sec, data,
cp1 - data);
} else {
no_soa:
#endif
dp = savedata(class, type, NTTL + tt.tv_sec, NULL, 0);
#ifdef RETURNSOA
}
#endif
dp->d_zone = DB_Z_CACHE;
dp->d_cred = hp->aa ? DB_C_AUTH : DB_C_ANSWER;
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;
}
if ((n = db_update(dname, dp, dp, NULL, flags, hashtab, from)) != OK) {
ns_debug(ns_log_ncache, 1,
"db_update failed (%d), cache_n_resp()", n);
db_freedata(dp);
return;
}
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));
}