ncache.c revision b335299322e50f045f10e4636262cd2f8d407a8b
/*
* Copyright (C) 2004, 2005, 2007, 2008, 2010 Internet Systems Consortium, Inc. ("ISC")
* Copyright (C) 1999-2003 Internet Software Consortium.
*
* 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 ISC DISCLAIMS ALL WARRANTIES WITH
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS. IN NO EVENT SHALL ISC 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: ncache.c,v 1.46 2010/05/14 00:13:43 marka Exp $ */
/*! \file */
#include <config.h>
#include <dns/rdatalist.h>
#include <dns/rdataset.h>
#include <dns/rdatastruct.h>
#define DNS_NCACHE_RDATA 20U
/*
* The format of an ncache rdata is a sequence of one or more records of
* the following format:
*
* owner name
* type
* trust
* rdata count
* rdata length These two occur 'rdata count'
* rdata times.
*
*/
static inline isc_result_t
unsigned int count;
isc_region_t ar, r;
/*
* Copy the rdataset count to the buffer.
*/
return (ISC_R_NOSPACE);
while (result == ISC_R_SUCCESS) {
dns_rdata_toregion(&rdata, &r);
return (ISC_R_NOSPACE);
/*
* Copy the rdata length to the buffer.
*/
/*
* Copy the rdata to the buffer.
*/
if (result != ISC_R_SUCCESS)
return (result);
}
if (result != ISC_R_NOMORE)
return (result);
return (ISC_R_SUCCESS);
}
{
}
{
isc_region_t r;
unsigned char data[4096];
unsigned int next = 0;
/*
* Convert the authority data from 'message' into a negative cache
* rdataset, and store it in 'cache' at 'node'.
*/
/*
* We assume that all data in the authority section has been
* validated by the caller.
*/
/*
* Initialize the list.
*/
ncrdatalist.type = 0;
/*
* Build an ncache rdatas into buffer.
*/
trust = 0xffff;
else
while (result == ISC_R_SUCCESS) {
&name);
if ((rdataset->attributes &
DNS_RDATASETATTR_NCACHE) == 0)
continue;
if (type == dns_rdatatype_rrsig)
if (type == dns_rdatatype_soa ||
type == dns_rdatatype_nsec ||
type == dns_rdatatype_nsec3) {
/*
* Copy the owner name to the buffer.
*/
dns_name_toregion(name, &r);
&r);
if (result != ISC_R_SUCCESS)
return (result);
/*
* Copy the type to the buffer.
*/
&r);
if (r.length < 2)
return (ISC_R_NOSPACE);
/*
* Copy the rdataset into the buffer.
*/
&buffer);
if (result != ISC_R_SUCCESS)
return (result);
if (next >= DNS_NCACHE_RDATA)
return (ISC_R_NOSPACE);
isc_buffer_remainingregion(&buffer, &r);
next++;
}
}
}
}
if (result != ISC_R_NOMORE)
return (result);
if (trust == 0xffff) {
/*
* We didn't find any authority data from which to create a
* negative cache rdataset. In particular, we have no SOA.
*
* We trust that the caller wants negative caching, so this
* means we have a "type 3 nxdomain" or "type 3 nodata"
* response (see RFC2308 for details).
*
* We will now build a suitable negative cache rdataset that
* will cause zero bytes to be emitted when converted to
* wire format.
*/
/*
* The ownername must exist, but it doesn't matter what value
* it has. We use the root name.
*/
if (result != ISC_R_SUCCESS)
return (result);
/*
* Copy the type and a zero rdata count to the buffer.
*/
isc_buffer_availableregion(&buffer, &r);
if (r.length < 4)
return (ISC_R_NOSPACE);
isc_buffer_putuint16(&buffer, 0);
isc_buffer_putuint16(&buffer, 0);
/*
* RFC2308, section 5, says that negative answers without
* SOAs should not be cached.
*/
ttl = 0;
/*
* Set trust.
*/
/*
* The response has aa set and we haven't followed
* any CNAME or DNAME chains.
*/
} else
/*
* Now add it to the cache.
*/
if (next >= DNS_NCACHE_RDATA)
return (ISC_R_NOSPACE);
isc_buffer_remainingregion(&buffer, &r);
}
== ISC_R_SUCCESS);
if (optout)
0, addedrdataset));
}
unsigned int *countp)
{
/*
* Convert the negative caching rdataset 'rdataset' to wire format,
* compressing names as specified in 'cctx', and storing the result in
* 'target'.
*/
savedbuffer = *target;
count = 0;
while (result == ISC_R_SUCCESS) {
for (i = 0; i < rcount; i++) {
/*
* Get the length of this rdata and set up an
* rdata structure for it.
*/
if ((options & DNS_NCACHETOWIRE_OMITDNSSEC) != 0 &&
continue;
/*
* Write the name.
*/
if (result != ISC_R_SUCCESS)
goto rollback;
/*
* See if we have space for type, class, ttl, and
* rdata length. Write the type, class, and ttl.
*/
goto rollback;
}
/*
* Save space for rdata length.
*/
/*
* Write the rdata.
*/
if (result != ISC_R_SUCCESS)
goto rollback;
/*
* Set the rdata length field to the compressed
* length.
*/
count++;
}
}
if (result != ISC_R_NOMORE)
goto rollback;
return (ISC_R_SUCCESS);
*countp = 0;
*target = savedbuffer;
return (result);
}
static void
}
static isc_result_t
unsigned int count;
if (count == 0) {
return (ISC_R_NOMORE);
}
raw += 2;
/*
* The privateuint4 field is the number of rdata beyond the cursor
* position, so we decrement the total count by one before storing
* it.
*/
count--;
return (ISC_R_SUCCESS);
}
static isc_result_t
unsigned int count;
unsigned int length;
unsigned char *raw;
if (count == 0)
return (ISC_R_NOMORE);
count--;
return (ISC_R_SUCCESS);
}
static void
isc_region_t r;
raw += 2;
}
static void
/*
* Reset iterator state.
*/
target->privateuint4 = 0;
}
static unsigned int
unsigned int count;
return (count);
}
static void
}
static dns_rdatasetmethods_t rdataset_methods = {
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
};
{
while (result == ISC_R_SUCCESS) {
break;
}
}
if (result == ISC_R_NOMORE)
return (ISC_R_NOTFOUND);
if (result != ISC_R_SUCCESS)
return (result);
/*
* Reset iterator state.
*/
rdataset->privateuint4 = 0;
return (ISC_R_SUCCESS);
}
{
unsigned char *raw;
unsigned int count;
while (result == ISC_R_SUCCESS) {
if (type != dns_rdatatype_rrsig ||
continue;
}
raw += 2;
raw += 2;
break;
}
}
if (result == ISC_R_NOMORE)
return (ISC_R_NOTFOUND);
if (result != ISC_R_SUCCESS)
return (result);
/*
* Reset iterator state.
*/
rdataset->privateuint4 = 0;
return (ISC_R_SUCCESS);
}
void
{
unsigned int count;
unsigned char *raw;
if (type == dns_rdatatype_rrsig) {
/*
* Extract covers from RRSIG.
*/
raw += 2;
raw += 2;
} else
/*
* Reset iterator state.
*/
rdataset->privateuint4 = 0;
}