This commit was generated by cvs2svn to compensate for changes in r35618,

which included commits to RCS files with non-trunk default branches.
This commit is contained in:
Peter Wemm 1998-05-02 11:04:44 +00:00
commit 6b82cbaf57
12 changed files with 1310 additions and 333 deletions

View File

@ -1,4 +1,16 @@
$Id: CHANGES,v 8.53 1997/06/01 20:34:25 vixie Exp vixie $
$Id: CHANGES,v 8.56 1998/04/07 04:59:42 vixie Exp $
--- 4.9.7-T1A released ---
808. [security] A number of routines did insufficient bounds checking which
could cause crashes by reading from an invalid memory
location. (From BIND-8).
807. [bug] The server sometimes leaked the flushset (ns_resp.c).
(From BIND-8).
806. [bug] add_related_additional() leaked memory if the name
was already in the related array. (From BIND-8).
--- 4.9.6 released ---

View File

@ -1,4 +1,4 @@
$Id: INSTALL,v 8.8 1997/06/01 20:34:25 vixie Exp vixie $
$Id: INSTALL,v 8.9 1997/06/24 06:43:50 vixie Exp $
THE FILES:
----------

View File

@ -1,7 +1,7 @@
# Makefile for BIND>=4.9 top level
# vixie@decwrl December, 1992 [original]
#
# $Id: Makefile,v 8.49 1997/06/01 20:34:25 vixie Exp vixie $
# $Id: Makefile,v 8.52 1998/04/07 04:59:42 vixie Exp $
## Copyright (c) 1989
## The Regents of the University of California. All rights reserved.
@ -52,7 +52,7 @@
## ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
## SOFTWARE.
VER = 4.9.6-REL
VER = 4.9.7-T1B
SHELL = /bin/sh
MAKE = make
DESTDIR =

View File

@ -1,18 +1,24 @@
The official version of BIND is now 8.1.1. This is 4.9.6, the last of 4.*
which we are releasing since it has some important security bugs fixed.
Internet Software Consortium
BIND Release 4.9.7 README
$Date: 1998/04/07 04:24:01 $
The official version of ISC BIND is now 8.1.1. This is ISC BIND 4.9.7,
hoped to be the last of 4.*, which we are releasing since it has an important
security bug (plus some memory leaks) fixed.
The official place to get BIND is <URL:ftp://ftp.isc.org/isc/bind/src>.
The official mailing lists are: bind-users@vix.com - users/admins
(use *-request@* for admin mail) bind-workers@vix.com - developers
The official mailing lists are: <bind-users@vix.com> - users/admins
(use *-request@* for admin mail) <bind-workers@vix.com> - developers
The official Usenet newsgroups are: comp.protocols.tcp-ip.domains
comp.protocols.dns.bind
comp.protocols.dns.ops
comp.protocols.dns.std
The official Usenet newsgroups are: <URL:news:comp.protocols.dns.bind>
<URL:news:comp.protocols.dns.ops>
<URL:news:comp.protocols.dns.std>
BIND is currently maintained by: The Internet Software Consortium
(see <URL:http://www.isc.org/isc>.)
BIND is maintained by: The Internet Software Consortium
(see <URL:http://www.isc.org/>)
Bug reports should be sent to: <bind-bugs@vix.com>
Read the top of CHANGES for interesting stuff.

View File

@ -0,0 +1,286 @@
[ Deprecated, unsupported, nonfunctional, but not yet completely excised. ]
Description of Dynamic Update and T_UNSPEC Code
Added by Mike Schwartz
University of Washington Computer Science Department
11/86
schwartz@cs.washington.edu
I have incorporated 2 new features into BIND:
1. Code to allow (unauthenticated) dynamic updates: surrounded by
#ifdef ALLOW_UPDATES
2. Code to allow data of unspecified type: surrounded by
#ifdef ALLOW_T_UNSPEC
Note that you can have one or the other or both (or neither) of these
modifications running, by appropriately modifying the makefiles. Also,
the external interface isn't changed (other than being extended), i.e.,
a BIND server that allows dynamic updates and/or T_UNSPEC data can
still talk to a 'vanilla' server using the 'vanilla' operations.
The description that follows is broken into 3 parts: a functional
description of the dynamic update facility, a functional description of
the T_UNSPEC facility, and a discussion of the implementation of
dynamic updates. The implementation description is mostly intended for
those who want to make future enhancements (especially the addition of
a good authentication mechanism). If you make enhancements, I would be
interested in hearing about them.
1. Dynamic Update Facility
I added this code in conjunction with my research into naming in large
heterogeneous systems. For the purposes of this research, I ignored
security issues. In other words, no authentication/authorization
mechanism exists to control updates. Authentication will hopefully be
addressed at some future point (although probably not by me). In the
mean time, BIND Internet name servers (as opposed to "private" name
server networks operating with their own port numbers, as I use in my
research) should be compiled *without* -DALLOW_UPDATES, so that the
integrity of the Internet name database won't be compromised by this
code.
There are 5 different dynamic update interfaces:
UPDATEA - add a resource record
UPDATED - delete a specific resource record
UPDATEDA - delete all named resource records
UPDATEM - modify a specific resource record
UPDATEMA - modify all named resource records
These all work through the normal resolver interface, i.e., these
interfaces are opcodes, and the data in the buffers passed to
res_mkquery must conform to what is expected for the particular
operation (see the #ifdef ALLOW_UPDATES extensions to nstest.c for
example usage).
UPDATEM is logically equivalent to an UPDATED followed by an UPDATEA,
except that the updates occur atomically at the primary server (as
usual with Domain servers, secondaries may become temporarily
inconsistent). The difference between UPDATED and UPDATEDA is that the
latter allows you to delete all RRs associated with a name; similarly
for UPDATEM and UPDATEMA. The reason for the UPDATE{D,M}A interfaces
is two-fold:
1. Sometimes you want to delete/modify some data, but you know you'll
only have a single RR for that data; in such a case, it's more
convenient to delete/modify the RR by just giving the name;
otherwise, you would have to first look it up, and then
delete/modify it.
2. It is sometimes useful to be able to delete/modify multiple RRs
this way, since one can then perform the operation atomically.
Otherwise, one would have to delete/modify the RRs one-by-one.
One additional point to note about UPDATEMA is that it will return a
success status if there were *zero* or more RRs associated with the given
name (and the RR add succeeds), whereas UPDATEM, UPDATED, and UPDATEDA
will return a success status if there were *one* or more RRs associated
with the given name. The reason for the difference is to handle the
(probably common) case where what you want to do is set a particular
name to contain a single RR, irrespective of whether or not it was
already set.
2. T_UNSPEC Facility
Type T_UNSPEC allows you to store data whose layout BIND doesn't
understand. Data of this type is not marshalled (i.e., converted
between host and network representation, as is done, for example, with
Internet addresses) by BIND, so it is up to the client to make sure
things work out ok w.r.t. heterogeneous data representations. The way
I use this type is to have the client marshal data, store it, retrieve
it, and demarshal it. This way I can store arbitrary data in BIND
without having to add new code for each specific type.
T_UNSPEC data is dumped in an ASCII-encoded, checksummed format so
that, although it's not human-readable, it at least doesn't fill the
dump file with unprintable characters.
Type T_UNSPEC is important for my research environment, where
potentially lots of people want to store data in the name service, and
each person's data looks different. Instead of having BIND understand
the format of each of their data types, the clients define marshaling
routines and pass buffers of marshalled data to BIND; BIND never tries
to demarshal the data...it just holds on to it, and gives it back to
the client when the client requests it, and the client must then
demarshal it.
The Xerox Network System's name service (the Clearinghouse) works this
way. The reason 'vanilla' BIND understands the format of all the data
it holds is probably that BIND is tailored for a very specific
application, and wants to make sure the data it holds makes sense (and,
for some types, BIND needs to take additional action depending on the
data's semantics). For more general purpose name services (like the
Clearinghouse and my usage of BIND), this approach is less tractable.
See the #ifdef ALLOW_T_UNSPEC extensions to nstest.c for example usage of
this type.
3. Dynamic Update Implementation Description
This section is divided into 3 subsections: General Discussion,
Miscellaneous Points, and Known Defects.
3.1 General Discussion
The basic scheme is this: When an update message arrives, a call is
made to InitDynUpdate, which first looks up the SOA record for the zone
the update affects. If this is the primary server for that zone, we do
the update and then update the zone serial number (so that secondaries
will refresh later). If this is a secondary server, we forward the
update to the primary, and if that's successful, we update our copy
afterwards. If it's neither, we refuse the update. (One might think
to try to propagate the update to an authoritative server; I figured
that updates will probably be most likely within an administrative
domain anyway; this could be changed if someone has strong feelings
about it).
Note that this mechanism disallows updates when the primary is
down, preserving the Domain scheme's consistency requirements,
but making the primary a critical point for updates. This seemed
reasonable to me because
1. Alternative schemes must deal with potentially complex
situations involving merging of inconsistent secondary
updates
2. Updates are presumed to be rare relative to read accesses,
so this increased restrictiveness for updates over reads is
probably not critical
I have placed comments through out the code, so it shouldn't be
too hard to see what I did. The majority of the processing is in
doupdate() and InitDynUpdate(). Also, I added a field to the zone
struct, to keep track of when zones get updated, so that only changed
zones get checkpointed.
3.2 Miscellaneous Points
I use ns_maint to call zonedump() if the database changes, to
provide a checkpointing mechanism. I use the zone refresh times to
set up ns_maint interrupts if there are either secondaries or
primaries. Hence, if there is a secondary, this interrupt can cause
zoneref (as before), and if there is a primary, this interrupt can
cause doadump. I also checkpoint if needed before shutting down.
You can force a server to checkpoint any changed zones by sending the
maint signal (SIGALRM) to the process. Otherwise it just checkpoints
during maint. interrupts, or when being shutdown (with SIGTERM).
Sending it the dump signal causes the database to be dumped into the
(single) dump file, but doesn't checkpoint (i.e., update the boot
files). Note that the boot files will be overwritten with checkpoint
files, so if you want to preserve the comments, you should keep copies
of the original boot files separate from the versions that are actually
used.
I disallow T_SOA updates, for several reasons:
- T_SOA deletes at the primary wont be discovered by the secondaries
until they try to request them at maint time, which will cause
a failure
- the corresponding NS record would have to be deleted at the same
time (atomically) to avoid various problems
- T_SOA updates would have to be done in the right order, or else
the primary and secondaries will be out-of-sync for that zone.
My feeling is that changing the zone topology is a weighty enough thing
to do that it should involve changing the load file and reloading all
affected servers.
There are alot of places where bind exits due to catastrophic failures
(mainly malloc failures). I don't try to dump the database in these
places because it's probably inconsistent anyway. It's probably better
to depend on the most recent dump.
3.2 Known Defects
1. I put the following comment in nlookup (db_lookup.c):
Note: at this point, if np->n_data is NULL, we could be in one
of two situations: Either we have come across a name for which
all the RRs have been (dynamically) deleted, or else we have
come across a name which has no RRs associated with it because
it is just a place holder (e.g., EDU). In the former case, we
would like to delete the namebuf, since it is no longer of use,
but in the latter case we need to hold on to it, so future
lookups that depend on it don't fail. The only way I can see
of doing this is to always leave the namebufs around (although
then the memory usage continues to grow whenever names are
added, and can never shrink back down completely when all their
associated RRs are deleted).
Thus, there is a problem that the memory usage will keep growing for
the situation described. You might just choose to ignore this
problem (since I don't see any good way out), since things probably
wont grow fast anyway (how many names are created and then deleted
during a single server incarnation, after all?)
The problem is that one can't delete old namebufs because one would
want to do it from db_update, but db_update calls nlookup to do the
actual work, and can't do it there, since we need to maintain place
holders. One could make db_update not call nlookup, so we know it's
ok to delete the namebuf (since we know the call is part of a delete
call); but then there is code with alot of overlapping functionality
in the 2 routines.
This also causes another problem: If you create a name and then do
UPDATEDA, all it's RRs get deleted, but the name remains; then, if you
do a lookup on that name later, the name is found in the hash table,
but no RRs are found for it. It then forwards the query to itself (for
some reason), and then somehow decides there is no such domain, and then
returns (with the correct answer, but after going through extra work).
But the name remains, and each time it is looked up, we go through
these same steps. This should be fixed, but I don't have time right
now (and the right answer seems to come back anyway, so it's good
enough for now).
2. There are 2 problems that crop up when you store data (other than
T_SOA and T_NS records) in the root:
a. Can't get primary to doaxfr RRs other than SOA and NS to
secondary.
b. Upon checkpoint (zonedump), this data sometimes comes out after other
data in the root, so that (since the SOA and NS records have null
names), they will get interpreted as being records under the
other names upon the next boot up. For example, if you have a
T_A record called ABC, the checkpoint may look like:
$ORIGIN .
ABC IN A 128.95.1.3
99999999 IN NS UW-BORNEO.
IN SOA UW-BORNEO. SCHWARTZ.CS.WASHINGTON.EDU.
( 50 3600 300 3600000 3600 )
Then when booting up the next time, the SOA and NS records get
interpreted as being called "ABC" rather than the null root
name.
3. The secondary server caches the T_A RR for the primary, and hence when
it tries to ns_forw an update, it won't find the address of the primary
using nslookup unless that T_A RR is *also* stored in the main hashtable
(by putting it in a named.db file as well as the named.ca file).

View File

@ -92,7 +92,7 @@ char copyright[] =
#if !defined(lint) && !defined(SABER)
static char sccsid[] = "@(#)named-xfer.c 4.18 (Berkeley) 3/7/91";
static char rcsid[] = "$Id: named-xfer.c,v 8.23 1997/06/01 20:34:34 vixie Exp $";
static char rcsid[] = "$Id: named-xfer.c,v 8.24 1998/04/07 04:59:45 vixie Exp $";
#endif /* not lint */
#include <sys/types.h>
@ -740,6 +740,10 @@ getzone(zp, serial_no, port)
goto badsoa;
}
tmp += n;
if (tmp + 2 * INT16SZ > eom) {
badsoa_msg = "query error";
goto badsoa;
}
GETSHORT(type, tmp);
GETSHORT(class, tmp);
if (class != curclass || type != T_SOA ||
@ -778,6 +782,10 @@ getzone(zp, serial_no, port)
GETSHORT(class, cp4);
GETLONG(ttl, cp4);
GETSHORT(dlen, cp4);
if (cp4 + dlen > eom) {
badsoa_msg = "zinfo dlen too big";
goto badsoa;
}
if (type == T_SOA)
break;
/* Skip to next record, if any. */
@ -1155,6 +1163,8 @@ soa_zinfo(zp, cp, eom)
register int n;
int type, class;
u_long ttl;
u_int dlen;
u_char *rdatap;
/* Are type, class, and ttl OK? */
if (eom - cp < 3 * INT16SZ + INT32SZ)
@ -1162,7 +1172,8 @@ soa_zinfo(zp, cp, eom)
GETSHORT(type, cp);
GETSHORT(class, cp);
GETLONG(ttl, cp);
cp += INT16SZ; /* dlen */
GETSHORT(dlen, cp);
rdatap = cp;
if (type != T_SOA || class != curclass)
return ("zinfo wrong typ/cla/ttl");
/* Skip master name and contact name, we can't validate them. */
@ -1180,9 +1191,19 @@ soa_zinfo(zp, cp, eom)
GETLONG(zp->z_retry, cp);
GETLONG(zp->z_expire, cp);
GETLONG(zp->z_minimum, cp);
if (cp != rdatap + dlen)
return ("bad soa dlen");
return (NULL);
}
#define BOUNDS_CHECK(ptr, count) \
do { \
if ((ptr) + (count) > eom) { \
hp->rcode = FORMERR; \
return (-1); \
} \
} while (0)
/*
* Parse the message, determine if it should be printed, and if so, print it
* in .db file form.
@ -1202,7 +1223,7 @@ print_output(zp, serial_no, msg, msglen, rrp)
int i, j, tab, result, class, type, dlen, n1, n;
char data[BUFSIZ];
u_char *cp1, *cp2, *temp_ptr, *eom, *rr_type_ptr;
u_char *cdata;
u_char *cdata, *rdatap;
char *origin, *proto, dname[MAXDNAME];
char *ignore = "";
const char *badsoa_msg;
@ -1216,10 +1237,13 @@ print_output(zp, serial_no, msg, msglen, rrp)
}
cp += n;
rr_type_ptr = cp;
BOUNDS_CHECK(cp, 3 * INT16SZ + INT32SZ);
GETSHORT(type, cp);
GETSHORT(class, cp);
GETLONG(ttl, cp);
GETSHORT(dlen, cp);
BOUNDS_CHECK(cp, dlen);
rdatap = cp;
origin = strchr(dname, '.');
if (origin == NULL)
@ -1294,10 +1318,7 @@ print_output(zp, serial_no, msg, msglen, rrp)
cp += n;
cp1 += strlen((char *) cp1) + 1;
if (type == T_SOA) {
if ((eom - cp) < (5 * INT32SZ)) {
hp->rcode = FORMERR;
return (-1);
}
BOUNDS_CHECK(cp, 5 * INT32SZ);
temp_ptr = cp + 4 * INT32SZ;
GETLONG(minimum_ttl, temp_ptr);
n = 5 * INT32SZ;
@ -1311,24 +1332,31 @@ print_output(zp, serial_no, msg, msglen, rrp)
case T_NAPTR:
/* Grab weight and port. */
BOUNDS_CHECK(cp, INT16SZ*2);
bcopy(cp, data, INT16SZ*2);
cp1 = (u_char *) (data + INT16SZ*2);
cp += INT16SZ*2;
/* Flags */
BOUNDS_CHECK(cp, 1);
n = *cp++;
BOUNDS_CHECK(cp, n);
*cp1++ = n;
bcopy(cp, cp1, n);
cp += n; cp1 += n;
/* Service */
n = *cp++;
BOUNDS_CHECK(cp, 1);
n = *cp++;
BOUNDS_CHECK(cp, n);
*cp1++ = n;
bcopy(cp, cp1, n);
cp += n; cp1 += n;
/* Regexp */
n = *cp++;
BOUNDS_CHECK(cp, 1);
n = *cp++;
BOUNDS_CHECK(cp, n);
*cp1++ = n;
bcopy(cp, cp1, n);
cp += n; cp1 += n;
@ -1352,11 +1380,13 @@ print_output(zp, serial_no, msg, msglen, rrp)
case T_RT:
case T_SRV:
/* grab preference */
BOUNDS_CHECK(cp, INT16SZ);
bcopy((char *)cp, data, INT16SZ);
cp1 = (u_char *)data + INT16SZ;
cp += INT16SZ;
if (type == T_SRV) {
BOUNDS_CHECK(cp, INT16SZ);
bcopy((char *)cp, cp1, INT16SZ*2);
cp1 += INT16SZ*2;
cp += INT16SZ*2;
@ -1378,6 +1408,7 @@ print_output(zp, serial_no, msg, msglen, rrp)
case T_PX:
/* grab preference */
BOUNDS_CHECK(cp, INT16SZ);
bcopy((char *)cp, data, INT16SZ);
cp1 = (u_char *)data + INT16SZ;
cp += INT16SZ;
@ -1408,6 +1439,7 @@ print_output(zp, serial_no, msg, msglen, rrp)
/* first just copy over the type_covered, algorithm, */
/* labels, orig ttl, two timestamps, and the footprint */
BOUNDS_CHECK(cp, 18);
bcopy( cp, cp1, 18 );
cp += 18;
cp1 += 18;
@ -1423,8 +1455,10 @@ print_output(zp, serial_no, msg, msglen, rrp)
/* finally, we copy over the variable-length signature.
Its size is the total data length, minus what we copied. */
n = dlen - (18 + n);
if (n > (sizeof data) - (cp1 - (u_char *)data))
if (n > (int)((sizeof data) - (int)(cp1 - (u_char *)data))) {
hp->rcode = FORMERR;
return (-1); /* out of room! */
}
bcopy(cp, cp1, n);
cp += n;
cp1 += n;
@ -1448,6 +1482,14 @@ print_output(zp, serial_no, msg, msglen, rrp)
hp->rcode = FORMERR;
return (-1);
}
if (cp != rdatap + dlen) {
dprintf(1, (ddt,
"encoded rdata length is %u, but actual length was %u\n",
dlen, (u_int)(cp - rdatap)));
hp->rcode = FORMERR;
return (-1);
}
cdata = cp1;
result = cp - rrp;

View File

@ -21,6 +21,13 @@
#ifdef NCACHE
#define BOUNDS_CHECK(ptr, count) \
do { \
if ((ptr) + (count) > eom) { \
return; \
} \
} while (0)
void
cache_n_resp(msg, msglen)
u_char *msg;
@ -28,7 +35,7 @@ cache_n_resp(msg, msglen)
{
register struct databuf *dp;
HEADER *hp;
u_char *cp;
u_char *cp, *eom, *rdatap;
char dname[MAXDNAME];
int n;
int type, class;
@ -36,19 +43,22 @@ cache_n_resp(msg, msglen)
int Vcode;
#endif
int flags;
u_int dlen;
nameserIncr(from_addr.sin_addr, nssRcvdNXD);
hp = (HEADER *)msg;
cp = msg+HFIXEDSZ;
eom = msg + msglen;
n = dn_expand(msg, msg + msglen, cp, dname, sizeof dname);
n = dn_expand(msg, eom, cp, dname, sizeof dname);
if (n < 0) {
dprintf(1, (ddt, "Query expand name failed:cache_n_resp\n"));
hp->rcode = FORMERR;
return;
}
cp += n;
BOUNDS_CHECK(cp, 2 * INT16SZ);
GETSHORT(type, cp);
GETSHORT(class, cp);
dprintf(1, (ddt,
@ -76,13 +86,14 @@ cache_n_resp(msg, msglen)
if (hp->rcode == NXDOMAIN)
type = T_SOA;
/* store ther SOA record */
n = dn_skipname(tp, msg + msglen);
/* store their SOA record */
n = dn_skipname(tp, eom);
if (n < 0) {
dprintf(3, (ddt, "ncache: form error\n"));
return;
}
tp += n;
BOUNDS_CHECK(tp, 3 * INT16SZ + INT32SZ);
GETSHORT(atype, tp); /* type */
if (atype != T_SOA) {
dprintf(3, (ddt,
@ -91,10 +102,12 @@ cache_n_resp(msg, msglen)
}
tp += INT16SZ; /* class */
GETLONG(ttl, tp); /* ttl */
tp += INT16SZ; /* dlen */
GETSHORT(dlen, tp); /* dlen */
BOUNDS_CHECK(tp, dlen);
rdatap = tp;
/* origin */
n = dn_expand(msg, msg + msglen, tp, (char*)data, len);
n = dn_expand(msg, eom, tp, (char*)data, len);
if (n < 0) {
dprintf(3, (ddt, "ncache: form error 2\n"));
return;
@ -113,10 +126,17 @@ cache_n_resp(msg, msglen)
n = strlen((char*)cp1) + 1;
cp1 += n;
len -= n;
bcopy(tp, cp1, n = 5 * INT32SZ);
n = 5 * INT32SZ;
BOUNDS_CHECK(tp, n);
bcopy(tp, cp1, n);
/* serial, refresh, retry, expire, min */
cp1 += n;
len -= n;
tp += n;
if (tp != rdatap + dlen) {
dprintf(3, (ddt, "ncache: form error 2\n"));
return;
}
/* store the zone of the soa record */
n = dn_expand(msg, msg + msglen, cp, (char*)cp1, len);
if (n < 0) {

View File

@ -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 8.28 1997/06/01 20:34:34 vixie Exp $";
static char rcsid[] = "$Id: ns_req.c,v 8.29 1998/04/07 04:59:45 vixie Exp $";
#endif /* not lint */
/*
@ -328,6 +328,11 @@ req_notify(hp, cpp, eom, msg, from)
hp->rcode = FORMERR;
return (Finish);
}
if (*cpp + 2 * INT16SZ > eom) {
dprintf(1, (ddt, "FORMERR notify too short"));
hp->rcode = FORMERR;
return (Finish);
}
*cpp += n;
GETSHORT(type, *cpp);
GETSHORT(class, *cpp);
@ -461,13 +466,13 @@ req_query(hp, cpp, eom, qsp, buflenp, msglenp, msg, dfd, from)
return (Finish);
}
*cpp += n;
GETSHORT(type, *cpp);
GETSHORT(class, *cpp);
if (*cpp > eom) {
if (*cpp + 2 * INT16SZ > eom) {
dprintf(1, (ddt, "FORMERR Query message length short\n"));
hp->rcode = FORMERR;
return (Finish);
}
GETSHORT(type, *cpp);
GETSHORT(class, *cpp);
if (*cpp < eom) {
dprintf(6, (ddt,"message length > received message\n"));
*msglenp = *cpp - msg;
@ -990,6 +995,11 @@ req_iquery(hp, cpp, eom, buflenp, msg, from)
return (Finish);
}
*cpp += n;
if (*cpp + 3 * INT16SZ + INT32SZ > eom) {
dprintf(1, (ddt, "FORMERR IQuery message too short"));
hp->rcode = FORMERR;
return (Finish);
}
GETSHORT(type, *cpp);
GETSHORT(class, *cpp);
*cpp += INT32SZ; /* ttl */
@ -1007,7 +1017,7 @@ req_iquery(hp, cpp, eom, buflenp, msg, from)
switch (type) {
case T_A:
#ifndef INVQ
if (!fake_iquery)
if (!fake_iquery || dlen != INT32SZ)
return (Refuse);
#endif
#ifdef INVQ
@ -1021,7 +1031,10 @@ req_iquery(hp, cpp, eom, buflenp, msg, from)
dprintf(1, (ddt, "req: IQuery class %d type %d\n", class, type));
fname = (char *)msg + HFIXEDSZ;
bcopy(fname, anbuf, alen = (char *)*cpp - fname);
alen = (char *)*cpp - fname;
if ((size_t)alen > sizeof anbuf)
return (Refuse);
bcopy(fname, anbuf, alen);
data = anbuf + alen - dlen;
*cpp = (u_char *)fname;
*buflenp -= HFIXEDSZ;
@ -1068,6 +1081,10 @@ req_iquery(hp, cpp, eom, buflenp, msg, from)
return (Finish);
}
*cpp += n;
if (*cpp + 2 * INT16SZ > dnbuf + *buflenp) {
hp->tc = 1;
return (Finish);
}
PUTSHORT((u_int16_t)dp->d_type, *cpp);
PUTSHORT((u_int16_t)dp->d_class, *cpp);
*buflenp -= n;
@ -1256,6 +1273,8 @@ make_rr(name, dp, buf, buflen, doadd)
}
buflen -= RRFIXEDSZ;
if (buflen < 0)
return (-1);
#if defined(RETURNSOA) && defined(NCACHE)
if (dp->d_rcode) {
name = (char *)dp->d_data;
@ -1269,6 +1288,8 @@ make_rr(name, dp, buf, buflen, doadd)
return (-1);
cp = buf + n;
buflen -= n;
if (buflen < 0)
return (-1);
PUTSHORT((u_int16_t)type, cp);
PUTSHORT((u_int16_t)dp->d_class, cp);
PUTLONG(ttl, cp);
@ -1308,6 +1329,8 @@ make_rr(name, dp, buf, buflen, doadd)
return (-1);
cp += n;
buflen -= type == T_SOA ? n + 5 * INT32SZ : n;
if (buflen < 0)
return (-1);
cp1 += strlen((char *)cp1) + 1;
n = dn_comp((char *)cp1, cp, buflen, dnptrs, edp);
if (n < 0)
@ -1326,10 +1349,10 @@ 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 order */
buflen -= INT16SZ;
if (buflen < 0)
return (-1);
bcopy(cp1, cp, INT16SZ);
cp += INT16SZ;
cp1 += INT16SZ;
@ -1337,6 +1360,9 @@ make_rr(name, dp, buf, buflen, doadd)
dprintf(1, (ddt, "current size n = %u\n", n));
/* copy preference */
buflen -= INT16SZ;
if (buflen < 0)
return (-1);
bcopy(cp1, cp, INT16SZ);
cp += INT16SZ;
cp1 += INT16SZ;
@ -1345,6 +1371,9 @@ make_rr(name, dp, buf, buflen, doadd)
/* Flags */
n = *cp1++;
buflen -= n + 1;
if (buflen < 0)
return (-1);
dprintf(1, (ddt, "size of n at flags = %d\n", n));
*cp++ = n;
bcopy(cp1,cp,n);
@ -1355,6 +1384,9 @@ make_rr(name, dp, buf, buflen, doadd)
/* Service */
n = *cp1++;
buflen -= n + 1;
if (buflen < 0)
return (-1);
*cp++ = n;
bcopy(cp1,cp,n);
cp += n;
@ -1364,6 +1396,9 @@ make_rr(name, dp, buf, buflen, doadd)
/* Regexp */
n = *cp1++;
buflen -= n + 1;
if (buflen < 0)
return (-1);
*cp++ = n;
bcopy(cp1,cp,n);
cp += n;
@ -1402,6 +1437,9 @@ make_rr(name, dp, buf, buflen, doadd)
cp1 += INT16SZ;
if (type == T_SRV) {
buflen -= INT16SZ*2;
if (buflen < 0)
return (-1);
bcopy(cp1, cp, INT16SZ*2);
cp += INT16SZ*2;
cp1 += INT16SZ*2;

View File

@ -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 8.38 1997/06/01 20:34:34 vixie Exp vixie $";
static char rcsid[] = "$Id: ns_resp.c,v 8.41 1998/04/07 04:59:45 vixie Exp $";
#endif /* not lint */
/*
@ -132,7 +132,8 @@ struct flush_set {
static void rrsetadd __P((struct flush_set *, char *,
struct databuf *)),
rrsetupdate __P((struct flush_set *, int flags)),
flushrrset __P((struct flush_set *));
flushrrset __P((struct flush_set *)),
free_flushset __P((struct flush_set *));
static int rrsetcmp __P((char *, struct db_list *)),
check_root __P((void)),
check_ns __P((void)),
@ -239,7 +240,7 @@ ns_resp(msg, msglen)
register struct databuf *ns, *ns2;
register u_char *cp;
u_char *eom = msg + msglen;
struct flush_set *flushset;
struct flush_set *flushset = NULL;
struct sockaddr_in *nsa;
struct databuf *nsp[NSMAX];
int i, c, n, qdcount, ancount, aucount, nscount, arcount, arfirst;
@ -264,8 +265,6 @@ ns_resp(msg, msglen)
struct fwdinfo *fwd;
char *tname = NULL;
free_related_additional();
nameserIncr(from_addr.sin_addr, nssRcvdR);
nsp[0] = NULL;
hp = (HEADER *) msg;
@ -302,6 +301,10 @@ ns_resp(msg, msglen)
goto formerr;
}
cp += n;
if (cp + 2 * INT16SZ > eom) {
formerrmsg = outofDataQuery;
goto formerr;
}
GETSHORT(qtype, cp);
GETSHORT(qclass, cp);
if (!ns_nameok(qname, qclass, response_trans,
@ -581,16 +584,12 @@ ns_resp(msg, msglen)
goto formerr;
}
tp += n;
if (tp + 2 * INT16SZ > eom) {
formerrmsg = outofDataAuth;
goto formerr;
}
GETSHORT(type, tp);
if (tp >= eom) {
formerrmsg = outofDataAuth;
goto formerr;
}
GETSHORT(class, tp);
if (tp >= eom) {
formerrmsg = outofDataAuth;
goto formerr;
}
if (!ns_nameok(name, class, response_trans,
ns_ownercontext(type, response_trans),
name, from_addr.sin_addr)) {
@ -645,6 +644,7 @@ ns_resp(msg, msglen)
u_int16_t type, class, dlen;
u_int32_t serial;
u_char *tp = cp;
u_char *rdatap;
n = dn_expand(msg, eom, tp, name, sizeof name);
if (n < 0) {
@ -652,14 +652,15 @@ ns_resp(msg, msglen)
goto formerr;
}
tp += n; /* name */
if (tp + 3 * INT16SZ + INT32SZ > eom) {
formerrmsg = outofDataAnswer;
goto formerr;
}
GETSHORT(type, tp); /* type */
GETSHORT(class, tp); /* class */
tp += INT32SZ; /* ttl */
GETSHORT(dlen, tp); /* dlen */
if (tp >= eom) {
formerrmsg = outofDataAnswer;
goto formerr;
}
rdatap = tp; /* start of rdata */
if (!ns_nameok(name, class, response_trans,
ns_ownercontext(type, response_trans),
name, from_addr.sin_addr)) {
@ -675,10 +676,6 @@ ns_resp(msg, msglen)
formerrmsg = msgbuf;
goto formerr;
}
if ((u_int)dlen < (5 * INT32SZ)) {
formerrmsg = dlenUnderrunAnswer;
goto formerr;
}
if (0 >= (n = dn_skipname(tp, eom))) {
formerrmsg = skipnameFailedAnswer;
@ -690,7 +687,16 @@ ns_resp(msg, msglen)
goto formerr;
}
tp += n; /* rname */
if (tp + 5 * INT32SZ > eom) {
formerrmsg = dlenUnderrunAnswer;
goto formerr;
}
GETLONG(serial, tp);
tp += 4 * INT32SZ; /* Skip rest of SOA. */
if ((u_int)(tp - rdatap) != dlen) {
formerrmsg = dlenOverrunAnswer;
goto formerr;
}
qserial_answer(qp, serial);
qremove(qp);
@ -786,12 +792,18 @@ ns_resp(msg, msglen)
maybe_free(&tname);
if (cp >= eom) {
free_related_additional();
if (flushset != NULL)
free_flushset(flushset);
formerrmsg = outofDataFinal;
goto formerr;
}
n = rrextract(msg, msglen, cp, &dp, name, sizeof name, &tname);
if (n < 0) {
free_related_additional();
maybe_free(&tname);
if (flushset != NULL)
free_flushset(flushset);
formerrmsg = outofDataFinal;
goto formerr;
}
@ -921,13 +933,11 @@ ns_resp(msg, msglen)
}
rrsetadd(flushset, name, dp);
}
free_related_additional();
maybe_free(&tname);
if (flushset) {
rrsetupdate(flushset, dbflags);
for (i = 0; i < count; i++)
if (flushset[i].fs_name)
free(flushset[i].fs_name);
free((char*)flushset);
free_flushset(flushset);
}
if (lastwascname && !externalcname)
syslog(LOG_DEBUG, "%s (%s)", danglingCname, aname);
@ -1365,6 +1375,14 @@ ns_resp(msg, msglen)
return;
}
#define BOUNDS_CHECK(ptr, count) \
do { \
if ((ptr) + (count) > eom) { \
hp->rcode = FORMERR; \
return (-1); \
} \
} while (0)
static int
rrextract(msg, msglen, rrp, dpp, dname, namelen, tnamep)
u_char *msg;
@ -1375,7 +1393,7 @@ rrextract(msg, msglen, rrp, dpp, dname, namelen, tnamep)
int namelen;
char **tnamep;
{
register u_char *cp;
register u_char *cp, *eom, *rdatap;
register int n;
int class, type, dlen, n1;
u_int32_t ttl;
@ -1389,15 +1407,19 @@ rrextract(msg, msglen, rrp, dpp, dname, namelen, tnamep)
*dpp = NULL;
cp = rrp;
if ((n = dn_expand(msg, msg + msglen, cp, dname, namelen)) < 0) {
eom = msg + msglen;
if ((n = dn_expand(msg, eom, cp, dname, namelen)) < 0) {
hp->rcode = FORMERR;
return (-1);
}
cp += n;
BOUNDS_CHECK(cp, 2*INT16SZ + INT32SZ + INT16SZ);
GETSHORT(type, cp);
GETSHORT(class, cp);
GETLONG(ttl, cp);
GETSHORT(dlen, cp);
BOUNDS_CHECK(cp, dlen);
rdatap = cp;
if (!ns_nameok(dname, class, response_trans,
ns_ownercontext(type, response_trans),
dname, from_addr.sin_addr)) {
@ -1456,8 +1478,7 @@ rrextract(msg, msglen, rrp, dpp, dname, namelen, tnamep)
case T_MR:
case T_NS:
case T_PTR:
n = dn_expand(msg, msg + msglen, cp,
(char *)data, sizeof data);
n = dn_expand(msg, eom, cp, (char *)data, sizeof data);
if (n < 0) {
hp->rcode = FORMERR;
return (-1);
@ -1483,8 +1504,7 @@ rrextract(msg, msglen, rrp, dpp, dname, namelen, tnamep)
context = mailname_ctx;
/* FALLTHROUGH */
soa_rp_minfo:
n = dn_expand(msg, msg + msglen, cp,
(char *)data, sizeof data);
n = dn_expand(msg, eom, cp, (char *)data, sizeof data);
if (n < 0) {
hp->rcode = FORMERR;
return (-1);
@ -1495,11 +1515,15 @@ rrextract(msg, msglen, rrp, dpp, dname, namelen, tnamep)
return (-1);
}
cp += n;
/*
* The next use of 'cp' is dn_expand(), so we don't have
* to BOUNDS_CHECK() here.
*/
cp1 = data + (n = strlen((char *)data) + 1);
n1 = sizeof(data) - n;
if (type == T_SOA)
n1 -= 5 * INT32SZ;
n = dn_expand(msg, msg + msglen, cp, (char *)cp1, n1);
n = dn_expand(msg, eom, cp, (char *)cp1, n1);
if (n < 0) {
hp->rcode = FORMERR;
return (-1);
@ -1516,7 +1540,9 @@ rrextract(msg, msglen, rrp, dpp, dname, namelen, tnamep)
cp += n;
cp1 += strlen((char *)cp1) + 1;
if (type == T_SOA) {
bcopy(cp, cp1, n = 5 * INT32SZ);
n = 5 * INT32SZ;
BOUNDS_CHECK(cp, n);
bcopy(cp, cp1, n);
cp += n;
cp1 += n;
}
@ -1526,30 +1552,37 @@ rrextract(msg, msglen, rrp, dpp, dname, namelen, tnamep)
case T_NAPTR:
/* Grab weight and port. */
BOUNDS_CHECK(cp, INT16SZ*2);
bcopy(cp, data, INT16SZ*2);
cp1 = data + INT16SZ*2;
cp += INT16SZ*2;
/* Flags */
BOUNDS_CHECK(cp, 1);
n = *cp++;
BOUNDS_CHECK(cp, n);
*cp1++ = n;
bcopy(cp, cp1, n);
cp += n; cp1 += n;
/* Service */
BOUNDS_CHECK(cp, 1);
n = *cp++;
BOUNDS_CHECK(cp, n);
*cp1++ = n;
bcopy(cp, cp1, n);
cp += n; cp1 += n;
/* Regexp */
BOUNDS_CHECK(cp, 1);
n = *cp++;
BOUNDS_CHECK(cp, n);
*cp1++ = n;
bcopy(cp, cp1, n);
cp += n; cp1 += n;
/* Replacement */
n = dn_expand(msg, msg + msglen, cp, (char *)cp1,
n = dn_expand(msg, eom, cp, (char *)cp1,
sizeof data - (cp1 - data));
if (n < 0) {
hp->rcode = FORMERR;
@ -1574,19 +1607,21 @@ rrextract(msg, msglen, rrp, dpp, dname, namelen, tnamep)
case T_RT:
case T_SRV:
/* grab preference */
BOUNDS_CHECK(cp, INT16SZ);
bcopy(cp, data, INT16SZ);
cp1 = data + INT16SZ;
cp += INT16SZ;
if (type == T_SRV) {
/* Grab weight and port. */
BOUNDS_CHECK(cp, INT16SZ*2);
bcopy(cp, cp1, INT16SZ*2);
cp1 += INT16SZ*2;
cp += INT16SZ*2;
}
/* get name */
n = dn_expand(msg, msg + msglen, cp, (char *)cp1,
n = dn_expand(msg, eom, cp, (char *)cp1,
sizeof data - (cp1 - data));
if (n < 0) {
hp->rcode = FORMERR;
@ -1611,13 +1646,14 @@ rrextract(msg, msglen, rrp, dpp, dname, namelen, tnamep)
case T_PX:
/* grab preference */
BOUNDS_CHECK(cp, INT16SZ);
bcopy(cp, data, INT16SZ);
cp1 = data + INT16SZ;
cp += INT16SZ;
/* get MAP822 name */
n = dn_expand(msg, msg + msglen, cp, (char *)cp1,
sizeof data - INT16SZ);
n = dn_expand(msg, eom, cp, (char *)cp1,
sizeof data - INT16SZ);
if (n < 0) {
hp->rcode = FORMERR;
return (-1);
@ -1628,9 +1664,13 @@ rrextract(msg, msglen, rrp, dpp, dname, namelen, tnamep)
return (-1);
}
cp += n;
/*
* The next use of 'cp' is dn_expand(), so we don't have
* to BOUNDS_CHECK() here.
*/
cp1 += (n = strlen((char *)cp1) + 1);
n1 = sizeof(data) - n;
n = dn_expand(msg, msg + msglen, cp, (char *)cp1, n1);
n = dn_expand(msg, eom, cp, (char *)cp1, n1);
if (n < 0) {
hp->rcode = FORMERR;
return (-1);
@ -1653,6 +1693,7 @@ rrextract(msg, msglen, rrp, dpp, dname, namelen, tnamep)
/* This code is similar to that in db_load.c. */
/* Skip coveredType, alg, labels */
BOUNDS_CHECK(cp, INT16SZ + 1 + 1 + 3*INT32SZ);
cp1 = cp + INT16SZ + 1 + 1;
GETLONG(origTTL, cp1);
GETLONG(exptime, cp1);
@ -1697,23 +1738,31 @@ rrextract(msg, msglen, rrp, dpp, dname, namelen, tnamep)
/* first just copy over the type_covered, algorithm, */
/* labels, orig ttl, two timestamps, and the footprint */
BOUNDS_CHECK(cp, 18);
bcopy(cp, cp1, 18);
cp += 18;
cp1 += 18;
/* then the signer's name */
n = dn_expand(msg, msg + msglen, cp,
(char *)cp1, (sizeof data) - 18);
if (n < 0)
n = dn_expand(msg, eom, cp, (char *)cp1, (sizeof data) - 18);
if (n < 0) {
hp->rcode = FORMERR;
return (-1);
}
cp += n;
cp1 += strlen((char*)cp1)+1;
/* finally, we copy over the variable-length signature.
Its size is the total data length, minus what we copied. */
if (18 + (u_int)n > dlen) {
hp->rcode = FORMERR;
return (-1);
}
n = dlen - (18 + n);
if (n > (sizeof data) - (cp1 - (u_char *)data))
if (n > ((int)(sizeof data) - (int)(cp1 - (u_char *)data))) {
hp->rcode = FORMERR;
return (-1); /* out of room! */
}
bcopy(cp, cp1, n);
cp += n;
cp1 += n;
@ -1728,6 +1777,18 @@ rrextract(msg, msglen, rrp, dpp, dname, namelen, tnamep)
dprintf(3, (ddt, "unknown type %d\n", type));
return ((cp - rrp) + dlen);
}
if (cp > eom) {
hp->rcode = FORMERR;
return (-1);
}
if ((u_int)(cp - rdatap) != dlen) {
dprintf(3, (ddt,
"encoded rdata length is %u, but actual length was %u",
dlen, (u_int)(cp - rdatap)));
hp->rcode = FORMERR;
return (-1);
}
if (n > MAXDATA) {
dprintf(1, (ddt,
"update type %d: %d bytes is too much data\n",
@ -3063,6 +3124,17 @@ flushrrset(fs)
db_free(dp);
}
static void
free_flushset(flushset)
struct flush_set *flushset;
{
struct flush_set *fs;
for (fs = flushset; fs->fs_name != NULL; fs++)
free(fs->fs_name);
free((char *)flushset);
}
/*
* This is best thought of as a "cache invalidate" function.
* It is called whenever a piece of data is determined to have
@ -3125,8 +3197,10 @@ add_related_additional(name)
if (num_related >= MAX_RELATED - 1)
return;
for (i = 0; i < num_related; i++)
if (strcasecmp(name, related[i]) == 0)
if (strcasecmp(name, related[i]) == 0) {
free(name);
return;
}
related[num_related++] = name;
}

View File

@ -55,7 +55,7 @@
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)gethostnamadr.c 8.1 (Berkeley) 6/4/93";
static char rcsid[] = "$Id: gethnamaddr.c,v 8.21 1997/06/01 20:34:37 vixie Exp $";
static char rcsid[] = "$Id: gethnamaddr.c,v 8.23 1998/04/07 04:59:46 vixie Exp $";
#endif /* LIBC_SCCS and not lint */
#include <sys/types.h>
@ -152,6 +152,23 @@ dprintf(msg, num)
# define dprintf(msg, num) /*nada*/
#endif
#define BOUNDED_INCR(x) \
do { \
cp += x; \
if (cp > eom) { \
h_errno = NO_RECOVERY; \
return (NULL); \
} \
} while (0)
#define BOUNDS_CHECK(ptr, count) \
do { \
if ((ptr) + (count) > eom) { \
h_errno = NO_RECOVERY; \
return (NULL); \
} \
} while (0)
static struct hostent *
getanswer(answer, anslen, qname, qtype)
const querybuf *answer;
@ -162,7 +179,7 @@ getanswer(answer, anslen, qname, qtype)
register const HEADER *hp;
register const u_char *cp;
register int n;
const u_char *eom;
const u_char *eom, *erdata;
char *bp, **ap, **hap;
int type, class, buflen, ancount, qdcount;
int haveanswer, had_error;
@ -193,7 +210,8 @@ getanswer(answer, anslen, qname, qtype)
qdcount = ntohs(hp->qdcount);
bp = hostbuf;
buflen = sizeof hostbuf;
cp = answer->buf + HFIXEDSZ;
cp = answer->buf;
BOUNDED_INCR(HFIXEDSZ);
if (qdcount != 1) {
h_errno = NO_RECOVERY;
return (NULL);
@ -203,7 +221,7 @@ getanswer(answer, anslen, qname, qtype)
h_errno = NO_RECOVERY;
return (NULL);
}
cp += n + QFIXEDSZ;
BOUNDED_INCR(n + QFIXEDSZ);
if (qtype == T_A || qtype == T_AAAA) {
/* res_send() has already verified that the query name is the
* same as the one we sent; this just gets the expanded name
@ -235,12 +253,15 @@ getanswer(answer, anslen, qname, qtype)
continue;
}
cp += n; /* name */
BOUNDS_CHECK(cp, 3 * INT16SZ + INT32SZ);
type = _getshort(cp);
cp += INT16SZ; /* type */
class = _getshort(cp);
cp += INT16SZ + INT32SZ; /* class, TTL */
n = _getshort(cp);
cp += INT16SZ; /* len */
BOUNDS_CHECK(cp, n);
erdata = cp + n;
if (class != C_IN) {
/* XXX - debug? syslog? */
cp += n;
@ -255,6 +276,10 @@ getanswer(answer, anslen, qname, qtype)
continue;
}
cp += n;
if (cp != erdata) {
h_errno = NO_RECOVERY;
return (NULL);
}
/* Store alias. */
*ap++ = bp;
n = strlen(bp) + 1; /* for the \0 */
@ -283,6 +308,10 @@ getanswer(answer, anslen, qname, qtype)
continue;
}
cp += n;
if (cp != erdata) {
h_errno = NO_RECOVERY;
return (NULL);
}
/* Get canonical name. */
n = strlen(tbuf) + 1; /* for the \0 */
if (n > buflen || n >= MAXHOSTNAMELEN) {
@ -318,6 +347,10 @@ getanswer(answer, anslen, qname, qtype)
}
#if MULTI_PTRS_ARE_ALIASES
cp += n;
if (cp != erdata) {
h_errno = NO_RECOVERY;
return (NULL);
}
if (!haveanswer)
host.h_name = bp;
else if (ap < &host_aliases[MAXALIASES-1])
@ -388,6 +421,10 @@ getanswer(answer, anslen, qname, qtype)
bp += n;
buflen -= n;
cp += n;
if (cp != erdata) {
h_errno = NO_RECOVERY;
return (NULL);
}
break;
default:
abort();

View File

@ -55,7 +55,7 @@
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)res_comp.c 8.1 (Berkeley) 6/4/93";
static char rcsid[] = "$Id: res_comp.c,v 8.12 1997/06/01 20:34:37 vixie Exp $";
static char rcsid[] = "$Id: res_comp.c,v 8.13 1998/04/07 04:24:06 vixie Exp $";
#endif /* LIBC_SCCS and not lint */
#include <sys/types.h>
@ -63,9 +63,10 @@ static char rcsid[] = "$Id: res_comp.c,v 8.12 1997/06/01 20:34:37 vixie Exp $";
#include <netinet/in.h>
#include <arpa/nameser.h>
#include <stdio.h>
#include <resolv.h>
#include <ctype.h>
#include <errno.h>
#include <resolv.h>
#include <stdio.h>
#if defined(BSD) && (BSD >= 199103)
# include <unistd.h>
@ -74,8 +75,17 @@ static char rcsid[] = "$Id: res_comp.c,v 8.12 1997/06/01 20:34:37 vixie Exp $";
# include "../conf/portability.h"
#endif
static int dn_find __P((u_char *exp_dn, u_char *msg,
u_char **dnptrs, u_char **lastdnptr));
static int ns_name_ntop __P((const u_char *, char *, size_t));
static int ns_name_pton __P((const char *, u_char *, size_t));
static int ns_name_unpack __P((const u_char *, const u_char *,
const u_char *, u_char *, size_t));
static int ns_name_pack __P((const u_char *, u_char *, int,
const u_char **, const u_char **));
static int ns_name_uncompress __P((const u_char *, const u_char *,
const u_char *, char *, size_t));
static int ns_name_compress __P((const char *, u_char *, size_t,
const u_char **, const u_char **));
static int ns_name_skip __P((const u_char **, const u_char *));
/*
* Expand compressed domain name 'comp_dn' to full domain name.
@ -85,261 +95,40 @@ static int dn_find __P((u_char *exp_dn, u_char *msg,
* Return size of compressed name or -1 if there was an error.
*/
int
dn_expand(msg, eomorig, comp_dn, exp_dn, length)
const u_char *msg, *eomorig, *comp_dn;
char *exp_dn;
int length;
dn_expand(const u_char *msg, const u_char *eom, const u_char *src,
char *dst, int dstsiz)
{
register const u_char *cp;
register char *dn;
register int n, c;
char *eom;
int len = -1, checked = 0, octets = 0;
int n = ns_name_uncompress(msg, eom, src, dst, (size_t)dstsiz);
dn = exp_dn;
cp = comp_dn;
eom = exp_dn + length;
/*
* fetch next label in domain name
*/
while (n = *cp++) {
/*
* Check for indirection
*/
switch (n & INDIR_MASK) {
case 0:
octets += (n + 1);
if (octets > MAXCDNAME)
return (-1);
if (dn != exp_dn) {
if (dn >= eom)
return (-1);
*dn++ = '.';
}
if (dn+n >= eom)
return (-1);
checked += n + 1;
while (--n >= 0) {
if (((c = *cp++) == '.') || (c == '\\')) {
if (dn + n + 2 >= eom)
return (-1);
*dn++ = '\\';
}
*dn++ = c;
if (cp >= eomorig) /* out of range */
return (-1);
}
break;
case INDIR_MASK:
if (len < 0)
len = cp - comp_dn + 1;
cp = msg + (((n & 0x3f) << 8) | (*cp & 0xff));
if (cp < msg || cp >= eomorig) /* out of range */
return (-1);
checked += 2;
/*
* Check for loops in the compressed name;
* if we've looked at the whole message,
* there must be a loop.
*/
if (checked >= eomorig - msg)
return (-1);
break;
default:
return (-1); /* flag error */
}
}
*dn = '\0';
if (len < 0)
len = cp - comp_dn;
return (len);
if (n > 0 && dst[0] == '.')
dst[0] = '\0';
return (n);
}
/*
* Compress domain name 'exp_dn' into 'comp_dn'.
* Pack domain name 'exp_dn' in presentation form into 'comp_dn'.
* Return the size of the compressed name or -1.
* 'length' is the size of the array pointed to by 'comp_dn'.
* 'dnptrs' is a list of pointers to previous compressed names. dnptrs[0]
* is a pointer to the beginning of the message. The list ends with NULL.
* 'lastdnptr' is a pointer to the end of the arrary pointed to
* by 'dnptrs'. Side effect is to update the list of pointers for
* labels inserted into the message as we compress the name.
* If 'dnptr' is NULL, we don't try to compress names. If 'lastdnptr'
* is NULL, we don't update the list.
*/
int
dn_comp(exp_dn, comp_dn, length, dnptrs, lastdnptr)
const char *exp_dn;
u_char *comp_dn, **dnptrs, **lastdnptr;
int length;
dn_comp(const char *src, u_char *dst, int dstsiz,
u_char **dnptrs, u_char **lastdnptr)
{
register u_char *cp, *dn;
register int c, l;
u_char **cpp, **lpp, *sp, *eob;
u_char *msg;
dn = (u_char *)exp_dn;
cp = comp_dn;
if (length > MAXCDNAME)
length = MAXCDNAME;
eob = cp + length;
lpp = cpp = NULL;
if (dnptrs != NULL) {
if ((msg = *dnptrs++) != NULL) {
for (cpp = dnptrs; *cpp != NULL; cpp++)
;
lpp = cpp; /* end of list to search */
}
} else
msg = NULL;
for (c = *dn++; c != '\0'; ) {
/* look to see if we can use pointers */
if (msg != NULL) {
if ((l = dn_find(dn-1, msg, dnptrs, lpp)) >= 0) {
if (cp+1 >= eob)
return (-1);
*cp++ = (l >> 8) | INDIR_MASK;
*cp++ = l % 256;
return (cp - comp_dn);
}
/* not found, save it */
if (lastdnptr != NULL && cpp < lastdnptr-1) {
*cpp++ = cp;
*cpp = NULL;
}
}
sp = cp++; /* save ptr to length byte */
do {
if (c == '.') {
c = *dn++;
break;
}
if (c == '\\') {
if ((c = *dn++) == '\0')
break;
}
if (cp >= eob) {
if (msg != NULL)
*lpp = NULL;
return (-1);
}
*cp++ = c;
} while ((c = *dn++) != '\0');
/* catch trailing '.'s but not '..' */
if ((l = cp - sp - 1) == 0 && c == '\0') {
cp--;
break;
}
if (l <= 0 || l > MAXLABEL) {
if (msg != NULL)
*lpp = NULL;
return (-1);
}
*sp = l;
}
if (cp >= eob) {
if (msg != NULL)
*lpp = NULL;
return (-1);
}
*cp++ = '\0';
return (cp - comp_dn);
return (ns_name_compress(src, dst, (size_t)dstsiz,
(const u_char **)dnptrs,
(const u_char **)lastdnptr));
}
/*
* Skip over a compressed domain name. Return the size or -1.
*/
int
__dn_skipname(comp_dn, eom)
const u_char *comp_dn, *eom;
{
register const u_char *cp;
register int n;
__dn_skipname(const u_char *ptr, const u_char *eom) {
const u_char *saveptr = ptr;
cp = comp_dn;
while (cp < eom && (n = *cp++)) {
/*
* check for indirection
*/
switch (n & INDIR_MASK) {
case 0: /* normal case, n == len */
cp += n;
continue;
case INDIR_MASK: /* indirection */
cp++;
break;
default: /* illegal type */
return (-1);
}
break;
}
if (cp > eom)
if (ns_name_skip(&ptr, eom) == -1)
return (-1);
return (cp - comp_dn);
}
static int
mklower(ch)
register int ch;
{
if (isascii(ch) && isupper(ch))
return (tolower(ch));
return (ch);
}
/*
* Search for expanded name from a list of previously compressed names.
* Return the offset from msg if found or -1.
* dnptrs is the pointer to the first name on the list,
* not the pointer to the start of the message.
*/
static int
dn_find(exp_dn, msg, dnptrs, lastdnptr)
u_char *exp_dn, *msg;
u_char **dnptrs, **lastdnptr;
{
register u_char *dn, *cp, **cpp;
register int n;
u_char *sp;
for (cpp = dnptrs; cpp < lastdnptr; cpp++) {
dn = exp_dn;
sp = cp = *cpp;
while (n = *cp++) {
/*
* check for indirection
*/
switch (n & INDIR_MASK) {
case 0: /* normal case, n == len */
while (--n >= 0) {
if (*dn == '.')
goto next;
if (*dn == '\\')
dn++;
if (mklower(*dn++) != mklower(*cp++))
goto next;
}
if ((n = *dn++) == '\0' && *cp == '\0')
return (sp - msg);
if (n == '.')
continue;
goto next;
case INDIR_MASK: /* indirection */
cp = msg + (((n & 0x3f) << 8) | *cp);
break;
default: /* illegal type */
return (-1);
}
}
if (*dn == '\0')
return (sp - msg);
next: ;
}
return (-1);
return (ptr - saveptr);
}
/*
@ -509,3 +298,640 @@ __putlong(l, msgp)
{
PUTLONG(l, msgp);
}
/* ++ From BIND 8.1.1. ++ */
/*
* Copyright (c) 1996 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.
*/
/*"Id: ns_name.c,v 1.1 1997/12/13 02:41:13 vixie Exp vixie"*/
/*#include "port_before.h"*/
/*#include <sys/types.h>*/
/*#include <netinet/in.h>*/
/*#include <arpa/nameser.h>*/
/*#include <errno.h>*/
/*#include <resolv.h>*/
/*#include <string.h>*/
/*#include "port_after.h"*/
#define NS_CMPRSFLGS 0xc0 /* Flag bits indicating name compression. */
#define NS_MAXCDNAME 255 /* maximum compressed domain name */
/* Data. */
static char digits[] = "0123456789";
/* Forward. */
static int special(int);
static int printable(int);
static int dn_find(const u_char *, const u_char *,
const u_char * const *,
const u_char * const *);
/* Public. */
/*
* ns_name_ntop(src, dst, dstsiz)
* Convert an encoded domain name to printable ascii as per RFC1035.
* return:
* Number of bytes written to buffer, or -1 (with errno set)
* notes:
* The root is returned as "."
* All other domains are returned in non absolute form
*/
static int
ns_name_ntop(src, dst, dstsiz)
const u_char *src;
char *dst;
size_t dstsiz;
{
const u_char *cp;
char *dn, *eom;
u_char c;
u_int n;
cp = src;
dn = dst;
eom = dst + dstsiz;
while ((n = *cp++) != 0) {
if ((n & NS_CMPRSFLGS) != 0) {
/* Some kind of compression pointer. */
errno = EMSGSIZE;
return (-1);
}
if (dn != dst) {
if (dn >= eom) {
errno = EMSGSIZE;
return (-1);
}
*dn++ = '.';
}
if (dn + n >= eom) {
errno = EMSGSIZE;
return (-1);
}
for ((void)NULL; n > 0; n--) {
c = *cp++;
if (special(c)) {
if (dn + 1 >= eom) {
errno = EMSGSIZE;
return (-1);
}
*dn++ = '\\';
*dn++ = (char)c;
} else if (!printable(c)) {
if (dn + 3 >= eom) {
errno = EMSGSIZE;
return (-1);
}
*dn++ = '\\';
*dn++ = digits[c / 100];
*dn++ = digits[(c % 100) / 10];
*dn++ = digits[c % 10];
} else {
if (dn >= eom) {
errno = EMSGSIZE;
return (-1);
}
*dn++ = (char)c;
}
}
}
if (dn == dst) {
if (dn >= eom) {
errno = EMSGSIZE;
return (-1);
}
*dn++ = '.';
}
if (dn >= eom) {
errno = EMSGSIZE;
return (-1);
}
*dn++ = '\0';
return (dn - dst);
}
/*
* ns_name_pton(src, dst, dstsiz)
* Convert a ascii string into an encoded domain name as per RFC1035.
* return:
* -1 if it fails
* 1 if string was fully qualified
* 0 is string was not fully qualified
* notes:
* Enforces label and domain length limits.
*/
static int
ns_name_pton(src, dst, dstsiz)
const char *src;
u_char *dst;
size_t dstsiz;
{
u_char *label, *bp, *eom;
int c, n, escaped;
char *cp;
escaped = 0;
bp = dst;
eom = dst + dstsiz;
label = bp++;
while ((c = *src++) != 0) {
if (escaped) {
if ((cp = strchr(digits, c)) != NULL) {
n = (cp - digits) * 100;
if ((c = *src++) == 0 ||
(cp = strchr(digits, c)) == NULL) {
errno = EMSGSIZE;
return (-1);
}
n += (cp - digits) * 10;
if ((c = *src++) == 0 ||
(cp = strchr(digits, c)) == NULL) {
errno = EMSGSIZE;
return (-1);
}
n += (cp - digits);
if (n > 255) {
errno = EMSGSIZE;
return (-1);
}
c = n;
}
escaped = 0;
} else if (c == '\\') {
escaped = 1;
continue;
} else if (c == '.') {
c = (bp - label - 1);
if ((c & NS_CMPRSFLGS) != 0) { /* Label too big. */
errno = EMSGSIZE;
return (-1);
}
if (label >= eom) {
errno = EMSGSIZE;
return (-1);
}
*label = c;
/* Fully qualified ? */
if (*src == '\0') {
if (c != 0) {
if (bp >= eom) {
errno = EMSGSIZE;
return (-1);
}
*bp++ = '\0';
}
if ((bp - dst) > MAXCDNAME) {
errno = EMSGSIZE;
return (-1);
}
return (1);
}
if (c == 0) {
errno = EMSGSIZE;
return (-1);
}
label = bp++;
continue;
}
if (bp >= eom) {
errno = EMSGSIZE;
return (-1);
}
*bp++ = (u_char)c;
}
c = (bp - label - 1);
if ((c & NS_CMPRSFLGS) != 0) { /* Label too big. */
errno = EMSGSIZE;
return (-1);
}
if (label >= eom) {
errno = EMSGSIZE;
return (-1);
}
*label = c;
if (c != 0) {
if (bp >= eom) {
errno = EMSGSIZE;
return (-1);
}
*bp++ = 0;
}
if ((bp - dst) > MAXCDNAME) { /* src too big */
errno = EMSGSIZE;
return (-1);
}
return (0);
}
/*
* ns_name_unpack(msg, eom, src, dst, dstsiz)
* Unpack a domain name from a message, source may be compressed.
* return:
* -1 if it fails, or consumed octets if it succeeds.
*/
static int
ns_name_unpack(msg, eom, src, dst, dstsiz)
const u_char *msg;
const u_char *eom;
const u_char *src;
u_char *dst;
size_t dstsiz;
{
const u_char *srcp, *dstlim;
u_char *dstp;
int n, c, len, checked;
len = -1;
checked = 0;
dstp = dst;
srcp = src;
dstlim = dst + dstsiz;
if (srcp < msg || srcp >= eom) {
errno = EMSGSIZE;
return (-1);
}
/* Fetch next label in domain name. */
while ((n = *srcp++) != 0) {
/* Check for indirection. */
switch (n & NS_CMPRSFLGS) {
case 0:
/* Limit checks. */
if (dstp + n + 1 >= dstlim || srcp + n >= eom) {
errno = EMSGSIZE;
return (-1);
}
checked += n + 1;
*dstp++ = n;
memcpy(dstp, srcp, n);
dstp += n;
srcp += n;
break;
case NS_CMPRSFLGS:
if (srcp >= eom) {
errno = EMSGSIZE;
return (-1);
}
if (len < 0)
len = srcp - src + 1;
srcp = msg + (((n & 0x3f) << 8) | (*srcp & 0xff));
if (srcp < msg || srcp >= eom) { /* Out of range. */
errno = EMSGSIZE;
return (-1);
}
checked += 2;
/*
* Check for loops in the compressed name;
* if we've looked at the whole message,
* there must be a loop.
*/
if (checked >= eom - msg) {
errno = EMSGSIZE;
return (-1);
}
break;
default:
errno = EMSGSIZE;
return (-1); /* flag error */
}
}
*dstp = '\0';
if (len < 0)
len = srcp - src;
return (len);
}
/*
* ns_name_pack(src, dst, dstsiz, dnptrs, lastdnptr)
* Pack domain name 'domain' into 'comp_dn'.
* return:
* Size of the compressed name, or -1.
* notes:
* 'dnptrs' is an array of pointers to previous compressed names.
* dnptrs[0] is a pointer to the beginning of the message. The array
* ends with NULL.
* 'lastdnptr' is a pointer to the end of the array pointed to
* by 'dnptrs'.
* Side effects:
* The list of pointers in dnptrs is updated for labels inserted into
* the message as we compress the name. If 'dnptr' is NULL, we don't
* try to compress names. If 'lastdnptr' is NULL, we don't update the
* list.
*/
static int
ns_name_pack(src, dst, dstsiz, dnptrs, lastdnptr)
const u_char *src;
u_char *dst;
int dstsiz;
const u_char **dnptrs;
const u_char **lastdnptr;
{
u_char *dstp;
const u_char **cpp, **lpp, *eob, *msg;
const u_char *srcp;
int n, l;
srcp = src;
dstp = dst;
eob = dstp + dstsiz;
lpp = cpp = NULL;
if (dnptrs != NULL) {
if ((msg = *dnptrs++) != NULL) {
for (cpp = dnptrs; *cpp != NULL; cpp++)
(void)NULL;
lpp = cpp; /* end of list to search */
}
} else
msg = NULL;
/* make sure the domain we are about to add is legal */
l = 0;
do {
n = *srcp;
if ((n & NS_CMPRSFLGS) != 0) {
errno = EMSGSIZE;
return (-1);
}
l += n + 1;
if (l > MAXCDNAME) {
errno = EMSGSIZE;
return (-1);
}
srcp += n + 1;
} while (n != 0);
srcp = src;
do {
/* Look to see if we can use pointers. */
n = *srcp;
if (n != 0 && msg != NULL) {
l = dn_find(srcp, msg, (const u_char * const *)dnptrs,
(const u_char * const *)lpp);
if (l >= 0) {
if (dstp + 1 >= eob) {
errno = EMSGSIZE;
return (-1);
}
*dstp++ = (l >> 8) | NS_CMPRSFLGS;
*dstp++ = l % 256;
return (dstp - dst);
}
/* Not found, save it. */
if (lastdnptr != NULL && cpp < lastdnptr - 1 &&
(dstp - msg) < 0x4000) {
*cpp++ = dstp;
*cpp = NULL;
}
}
/* copy label to buffer */
if (n & NS_CMPRSFLGS) { /* Should not happen. */
errno = EMSGSIZE;
return (-1);
}
if (dstp + 1 + n >= eob) {
errno = EMSGSIZE;
return (-1);
}
memcpy(dstp, srcp, n + 1);
srcp += n + 1;
dstp += n + 1;
} while (n != 0);
if (dstp > eob) {
if (msg != NULL)
*lpp = NULL;
errno = EMSGSIZE;
return (-1);
}
return (dstp - dst);
}
/*
* ns_name_uncompress(msg, eom, src, dst, dstsiz)
* Expand compressed domain name to presentation format.
* return:
* Number of bytes read out of `src', or -1 (with errno set).
* note:
* Root domain returns as "." not "".
*/
static int
ns_name_uncompress(msg, eom, src, dst, dstsiz)
const u_char *msg;
const u_char *eom;
const u_char *src;
char *dst;
size_t dstsiz;
{
u_char tmp[NS_MAXCDNAME];
int n;
if ((n = ns_name_unpack(msg, eom, src, tmp, sizeof tmp)) == -1)
return (-1);
if (ns_name_ntop(tmp, dst, dstsiz) == -1)
return (-1);
return (n);
}
/*
* ns_name_compress(src, dst, dstsiz, dnptrs, lastdnptr)
* Compress a domain name into wire format, using compression pointers.
* return:
* Number of bytes consumed in `dst' or -1 (with errno set).
* notes:
* 'dnptrs' is an array of pointers to previous compressed names.
* dnptrs[0] is a pointer to the beginning of the message.
* The list ends with NULL. 'lastdnptr' is a pointer to the end of the
* array pointed to by 'dnptrs'. Side effect is to update the list of
* pointers for labels inserted into the message as we compress the name.
* If 'dnptr' is NULL, we don't try to compress names. If 'lastdnptr'
* is NULL, we don't update the list.
*/
static int
ns_name_compress(src, dst, dstsiz, dnptrs, lastdnptr)
const char *src;
u_char *dst;
size_t dstsiz;
const u_char **dnptrs;
const u_char **lastdnptr;
{
u_char tmp[NS_MAXCDNAME];
if (ns_name_pton(src, tmp, sizeof tmp) == -1)
return (-1);
return (ns_name_pack(tmp, dst, dstsiz, dnptrs, lastdnptr));
}
/*
* ns_name_skip(ptrptr, eom)
* Advance *ptrptr to skip over the compressed name it points at.
* return:
* 0 on success, -1 (with errno set) on failure.
*/
static int
ns_name_skip(ptrptr, eom)
const u_char **ptrptr;
const u_char *eom;
{
const u_char *cp;
u_int n;
cp = *ptrptr;
while (cp < eom && (n = *cp++) != 0) {
/* Check for indirection. */
switch (n & NS_CMPRSFLGS) {
case 0: /* normal case, n == len */
cp += n;
continue;
case NS_CMPRSFLGS: /* indirection */
cp++;
break;
default: /* illegal type */
errno = EMSGSIZE;
return (-1);
}
break;
}
if (cp > eom) {
errno = EMSGSIZE;
return (-1);
}
*ptrptr = cp;
return (0);
}
/* Private. */
/*
* special(ch)
* Thinking in noninternationalized USASCII (per the DNS spec),
* is this characted special ("in need of quoting") ?
* return:
* boolean.
*/
static int
special(ch)
int ch;
{
switch (ch) {
case 0x22: /* '"' */
case 0x2E: /* '.' */
case 0x3B: /* ';' */
case 0x5C: /* '\\' */
/* Special modifiers in zone files. */
case 0x40: /* '@' */
case 0x24: /* '$' */
return (1);
default:
return (0);
}
}
/*
* printable(ch)
* Thinking in noninternationalized USASCII (per the DNS spec),
* is this character visible and not a space when printed ?
* return:
* boolean.
*/
static int
printable(ch)
int ch;
{
return (ch > 0x20 && ch < 0x7f);
}
/*
* Thinking in noninternationalized USASCII (per the DNS spec),
* convert this character to lower case if it's upper case.
*/
static int
mklower(ch)
int ch;
{
if (ch >= 0x41 && ch <= 0x5A)
return (ch + 0x20);
return (ch);
}
/*
* dn_find(domain, msg, dnptrs, lastdnptr)
* Search for the counted-label name in an array of compressed names.
* return:
* offset from msg if found, or -1.
* notes:
* dnptrs is the pointer to the first name on the list,
* not the pointer to the start of the message.
*/
static int
dn_find(domain, msg, dnptrs, lastdnptr)
const u_char *domain;
const u_char *msg;
const u_char * const *dnptrs;
const u_char * const *lastdnptr;
{
const u_char *dn, *cp, *sp;
const u_char * const *cpp;
u_int n;
for (cpp = dnptrs; cpp < lastdnptr; cpp++) {
dn = domain;
sp = cp = *cpp;
while ((n = *cp++) != 0) {
/*
* check for indirection
*/
switch (n & NS_CMPRSFLGS) {
case 0: /* normal case, n == len */
if (n != *dn++)
goto next;
for ((void)NULL; n > 0; n--)
if (mklower(*dn++) != mklower(*cp++))
goto next;
/* Is next root for both ? */
if (*dn == '\0' && *cp == '\0')
return (sp - msg);
if (*dn)
continue;
goto next;
case NS_CMPRSFLGS: /* indirection */
cp = msg + (((n & 0x3f) << 8) | *cp);
break;
default: /* illegal type */
errno = EMSGSIZE;
return (-1);
}
}
next: ;
}
errno = ENOENT;
return (-1);
}
/* -- From BIND 8.1.1. -- */

View File

@ -55,7 +55,7 @@
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)res_send.c 8.1 (Berkeley) 6/4/93";
static char rcsid[] = "$Id: res_send.c,v 8.13 1997/06/01 20:34:37 vixie Exp $";
static char rcsid[] = "$Id: res_send.c,v 8.14 1998/04/07 04:59:46 vixie Exp $";
#endif /* LIBC_SCCS and not lint */
/* change this to "0"
@ -214,6 +214,8 @@ res_isourserver(inp)
/* int
* res_nameinquery(name, type, class, buf, eom)
* look for (name,type,class) in the query section of packet (buf,eom)
* requires:
* buf + HFIXESDZ <= eom
* returns:
* -1 : format error
* 0 : not found
@ -238,6 +240,8 @@ res_nameinquery(name, type, class, buf, eom)
if (n < 0)
return (-1);
cp += n;
if (cp + 2 * INT16SZ > eom)
return (-1);
ttype = _getshort(cp); cp += INT16SZ;
tclass = _getshort(cp); cp += INT16SZ;
if (ttype == type &&
@ -267,6 +271,9 @@ res_queriesmatch(buf1, eom1, buf2, eom2)
register const u_char *cp = buf1 + HFIXEDSZ;
int qdcount = ntohs(((HEADER*)buf1)->qdcount);
if (buf1 + HFIXEDSZ > eom1 || buf2 + HFIXEDSZ > eom2)
return (-1);
if (qdcount != ntohs(((HEADER*)buf2)->qdcount))
return (0);
while (qdcount-- > 0) {
@ -277,6 +284,8 @@ res_queriesmatch(buf1, eom1, buf2, eom2)
if (n < 0)
return (-1);
cp += n;
if (cp + 2 * INT16SZ > eom1)
return (-1);
ttype = _getshort(cp); cp += INT16SZ;
tclass = _getshort(cp); cp += INT16SZ;
if (!res_nameinquery(tname, ttype, tclass, buf2, eom2))
@ -302,6 +311,10 @@ res_send(buf, buflen, ans, anssiz)
/* errno should have been set by res_init() in this case. */
return (-1);
}
if (anssiz < HFIXEDSZ) {
errno = EINVAL;
return (-1);
}
DprintQ((_res.options & RES_DEBUG) || (_res.pfcode & RES_PRF_QUERY),
(stdout, ";; res_send()\n"), buf, buflen);
v_circuit = (_res.options & RES_USEVC) || buflen > PACKETSZ;
@ -446,6 +459,17 @@ read_len:
len = anssiz;
} else
len = resplen;
if (len < HFIXEDSZ) {
/*
* Undersized message.
*/
Dprint(_res.options & RES_DEBUG,
(stdout, ";; undersized: %d\n", len));
terrno = EMSGSIZE;
badns |= (1 << ns);
res_close();
goto next_ns;
}
cp = ans;
while (len != 0 &&
(n = read(s, (char *)cp, (int)len)) > 0) {
@ -601,12 +625,12 @@ read_len:
if ((long) timeout.tv_sec <= 0)
timeout.tv_sec = 1;
timeout.tv_usec = 0;
if (s+1 > FD_SETSIZE) {
Perror(stderr, "s+1 > FD_SETSIZE", EMFILE);
wait:
if (s < 0 || s >= FD_SETSIZE) {
Perror(stderr, "s out-of-bounds", EMFILE);
res_close();
goto next_ns;
}
wait:
FD_ZERO(&dsmask);
FD_SET(s, &dsmask);
n = select(s+1, &dsmask, (fd_set *)NULL,
@ -638,6 +662,18 @@ read_len:
goto next_ns;
}
gotsomewhere = 1;
if (resplen < HFIXEDSZ) {
/*
* Undersized message.
*/
Dprint(_res.options & RES_DEBUG,
(stdout, ";; undersized: %d\n",
resplen));
terrno = EMSGSIZE;
badns |= (1 << ns);
res_close();
goto next_ns;
}
if (hp->id != anhp->id) {
/*
* response from old query, ignore it.