1999-09-21 20:41:20 +00:00
|
|
|
/*
|
|
|
|
* Copyright (C) 1999 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 <config.h>
|
|
|
|
|
|
|
|
#include <isc/assertions.h>
|
|
|
|
#include <isc/region.h>
|
|
|
|
#include <isc/buffer.h>
|
|
|
|
|
|
|
|
#include <dns/types.h>
|
|
|
|
#include <dns/ncache.h>
|
|
|
|
#include <dns/name.h>
|
|
|
|
#include <dns/compress.h>
|
|
|
|
#include <dns/message.h>
|
|
|
|
#include <dns/db.h>
|
|
|
|
#include <dns/rdata.h>
|
|
|
|
#include <dns/rdataset.h>
|
|
|
|
#include <dns/rdatalist.h>
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The format of an ncache rdata is a sequence of one or more records of
|
|
|
|
* the following format:
|
|
|
|
*
|
|
|
|
* owner name
|
|
|
|
* type
|
|
|
|
* rdata count
|
|
|
|
* rdata length These two occur 'rdata count'
|
|
|
|
* rdata times.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
static inline isc_result_t
|
|
|
|
copy_rdataset(dns_rdataset_t *rdataset, isc_buffer_t *buffer) {
|
|
|
|
isc_result_t result;
|
|
|
|
unsigned int count;
|
|
|
|
isc_region_t ar, r;
|
|
|
|
dns_rdata_t rdata;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Copy the rdataset count to the buffer.
|
|
|
|
*/
|
|
|
|
isc_buffer_available(buffer, &ar);
|
|
|
|
if (ar.length < 2)
|
|
|
|
return (ISC_R_NOSPACE);
|
|
|
|
count = dns_rdataset_count(rdataset);
|
|
|
|
INSIST(count <= 65535);
|
|
|
|
isc_buffer_putuint16(buffer, (isc_uint16_t)count);
|
|
|
|
|
|
|
|
result = dns_rdataset_first(rdataset);
|
|
|
|
while (result == ISC_R_SUCCESS) {
|
|
|
|
dns_rdataset_current(rdataset, &rdata);
|
|
|
|
dns_rdata_toregion(&rdata, &r);
|
|
|
|
INSIST(r.length <= 65535);
|
|
|
|
isc_buffer_available(buffer, &ar);
|
|
|
|
if (ar.length < 2)
|
|
|
|
return (ISC_R_NOSPACE);
|
|
|
|
/*
|
|
|
|
* Copy the rdata length to the buffer.
|
|
|
|
*/
|
|
|
|
isc_buffer_putuint16(buffer, (isc_uint16_t)r.length);
|
|
|
|
/*
|
|
|
|
* Copy the rdata to the buffer.
|
|
|
|
*/
|
|
|
|
result = isc_buffer_copyregion(buffer, &r);
|
|
|
|
if (result != ISC_R_SUCCESS)
|
|
|
|
return (result);
|
|
|
|
result = dns_rdataset_next(rdataset);
|
|
|
|
}
|
|
|
|
if (result != ISC_R_NOMORE)
|
|
|
|
return (result);
|
|
|
|
|
|
|
|
return (ISC_R_SUCCESS);
|
|
|
|
}
|
|
|
|
|
|
|
|
isc_result_t
|
|
|
|
dns_ncache_add(dns_message_t *message, dns_db_t *cache, dns_dbnode_t *node,
|
|
|
|
dns_rdatatype_t covers, isc_stdtime_t now,
|
|
|
|
dns_rdataset_t *addedrdataset)
|
|
|
|
{
|
|
|
|
isc_result_t result;
|
|
|
|
isc_buffer_t buffer;
|
|
|
|
isc_region_t r;
|
|
|
|
dns_rdataset_t *rdataset;
|
|
|
|
dns_rdata_t rdata;
|
|
|
|
dns_rdataset_t ncrdataset;
|
|
|
|
dns_rdatalist_t ncrdatalist;
|
|
|
|
dns_rdatatype_t type;
|
|
|
|
dns_name_t *name;
|
|
|
|
dns_ttl_t ttl;
|
|
|
|
char *data[4096];
|
1999-10-16 00:47:54 +00:00
|
|
|
dns_trust_t trust;
|
1999-09-21 20:41:20 +00:00
|
|
|
|
1999-09-22 00:26:19 +00:00
|
|
|
/*
|
|
|
|
* Convert the authority data from 'message' into a negative cache
|
|
|
|
* rdataset, and store it in 'cache' at 'node'.
|
|
|
|
*/
|
|
|
|
|
|
|
|
REQUIRE(message != NULL);
|
|
|
|
|
1999-09-21 20:41:20 +00:00
|
|
|
/*
|
|
|
|
* We assume that all data in the authority section has been
|
|
|
|
* validated by the caller.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* First, build an ncache rdata in buffer.
|
|
|
|
*/
|
|
|
|
ttl = 0xffffffff;
|
1999-10-16 00:47:54 +00:00
|
|
|
trust = 0xffff;
|
1999-09-21 20:41:20 +00:00
|
|
|
isc_buffer_init(&buffer, data, sizeof data, ISC_BUFFERTYPE_BINARY);
|
|
|
|
result = dns_message_firstname(message, DNS_SECTION_AUTHORITY);
|
|
|
|
while (result == ISC_R_SUCCESS) {
|
|
|
|
name = NULL;
|
|
|
|
dns_message_currentname(message, DNS_SECTION_AUTHORITY,
|
|
|
|
&name);
|
1999-10-16 00:47:54 +00:00
|
|
|
if ((name->attributes & DNS_NAMEATTR_NCACHE) != 0) {
|
1999-10-15 20:50:19 +00:00
|
|
|
for (rdataset = ISC_LIST_HEAD(name->list);
|
|
|
|
rdataset != NULL;
|
|
|
|
rdataset = ISC_LIST_NEXT(rdataset, link)) {
|
|
|
|
if ((rdataset->attributes &
|
|
|
|
DNS_RDATASETATTR_NCACHE) == 0)
|
|
|
|
continue;
|
|
|
|
type = rdataset->type;
|
|
|
|
if (type == dns_rdatatype_sig)
|
|
|
|
type = rdataset->covers;
|
|
|
|
if (type == dns_rdatatype_soa ||
|
|
|
|
type == dns_rdatatype_nxt) {
|
|
|
|
if (ttl > rdataset->ttl)
|
|
|
|
ttl = rdataset->ttl;
|
1999-10-16 00:47:54 +00:00
|
|
|
if (trust > rdataset->trust)
|
|
|
|
trust = rdataset->trust;
|
1999-10-15 20:50:19 +00:00
|
|
|
/*
|
|
|
|
* Copy the owner name to the buffer.
|
|
|
|
*/
|
|
|
|
dns_name_toregion(name, &r);
|
|
|
|
result = isc_buffer_copyregion(&buffer,
|
|
|
|
&r);
|
|
|
|
if (result != ISC_R_SUCCESS)
|
|
|
|
return (result);
|
|
|
|
/*
|
|
|
|
* Copy the type to the buffer.
|
|
|
|
*/
|
|
|
|
isc_buffer_available(&buffer, &r);
|
|
|
|
if (r.length < 2)
|
|
|
|
return (ISC_R_NOSPACE);
|
|
|
|
isc_buffer_putuint16(&buffer, type);
|
|
|
|
/*
|
|
|
|
* Copy the rdataset into the buffer.
|
|
|
|
*/
|
|
|
|
result = copy_rdataset(rdataset,
|
|
|
|
&buffer);
|
|
|
|
if (result != ISC_R_SUCCESS)
|
|
|
|
return (result);
|
|
|
|
}
|
1999-09-21 20:41:20 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
result = dns_message_nextname(message, DNS_SECTION_AUTHORITY);
|
|
|
|
}
|
|
|
|
if (result != ISC_R_NOMORE)
|
|
|
|
return (result);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Now, turn 'buffer' into an ncache rdataset and add it to
|
|
|
|
* the cache.
|
|
|
|
*/
|
|
|
|
|
1999-10-16 00:47:54 +00:00
|
|
|
INSIST(trust != 0xffff);
|
1999-09-21 20:41:20 +00:00
|
|
|
dns_rdata_init(&rdata);
|
1999-10-16 00:47:54 +00:00
|
|
|
isc_buffer_used(&buffer, &r);
|
1999-09-21 20:41:20 +00:00
|
|
|
rdata.data = r.base;
|
|
|
|
rdata.length = r.length;
|
|
|
|
rdata.rdclass = dns_db_class(cache);
|
|
|
|
rdata.type = 0;
|
|
|
|
|
|
|
|
ncrdatalist.rdclass = rdata.rdclass;
|
|
|
|
ncrdatalist.type = 0;
|
|
|
|
ncrdatalist.covers = covers;
|
|
|
|
ncrdatalist.ttl = ttl;
|
|
|
|
ISC_LIST_INIT(ncrdatalist.rdata);
|
|
|
|
ISC_LINK_INIT(&ncrdatalist, link);
|
|
|
|
|
|
|
|
ISC_LIST_APPEND(ncrdatalist.rdata, &rdata, link);
|
|
|
|
|
|
|
|
dns_rdataset_init(&ncrdataset);
|
|
|
|
dns_rdatalist_tordataset(&ncrdatalist, &ncrdataset);
|
1999-10-16 00:47:54 +00:00
|
|
|
ncrdataset.trust = trust;
|
1999-09-21 20:41:20 +00:00
|
|
|
|
|
|
|
result = dns_db_addrdataset(cache, node, NULL, now, &ncrdataset,
|
|
|
|
ISC_FALSE, addedrdataset);
|
|
|
|
|
|
|
|
return (result);
|
|
|
|
}
|
|
|
|
|
|
|
|
isc_result_t
|
|
|
|
dns_ncache_towire(dns_rdataset_t *rdataset, dns_compress_t *cctx,
|
|
|
|
isc_buffer_t *target, unsigned int *countp)
|
|
|
|
{
|
1999-09-22 00:26:19 +00:00
|
|
|
dns_rdata_t rdata;
|
|
|
|
isc_result_t result;
|
|
|
|
isc_region_t remaining, tremaining;
|
|
|
|
isc_buffer_t source, savedbuffer, rdlen;
|
|
|
|
dns_name_t name;
|
|
|
|
dns_rdatatype_t type;
|
|
|
|
unsigned int i, rcount, count;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Convert the negative caching rdataset 'rdataset' to wire format,
|
|
|
|
* compressing names as specified in 'cctx', and storing the result in
|
|
|
|
* 'target'.
|
|
|
|
*/
|
|
|
|
|
1999-09-21 20:41:20 +00:00
|
|
|
REQUIRE(rdataset->type == 0);
|
|
|
|
|
1999-09-22 00:26:19 +00:00
|
|
|
result = dns_rdataset_first(rdataset);
|
|
|
|
if (result != ISC_R_SUCCESS)
|
|
|
|
return (result);
|
|
|
|
dns_rdataset_current(rdataset, &rdata);
|
|
|
|
INSIST(dns_rdataset_next(rdataset) == ISC_R_NOMORE);
|
|
|
|
isc_buffer_init(&source, rdata.data, rdata.length,
|
|
|
|
ISC_BUFFERTYPE_BINARY);
|
|
|
|
isc_buffer_add(&source, rdata.length);
|
1999-09-21 20:41:20 +00:00
|
|
|
|
1999-09-22 00:26:19 +00:00
|
|
|
if (dns_compress_getedns(cctx) >= 1)
|
|
|
|
dns_compress_setmethods(cctx, DNS_COMPRESS_GLOBAL);
|
|
|
|
else
|
|
|
|
dns_compress_setmethods(cctx, DNS_COMPRESS_GLOBAL14);
|
|
|
|
|
|
|
|
savedbuffer = *target;
|
|
|
|
|
|
|
|
count = 0;
|
|
|
|
do {
|
|
|
|
dns_name_init(&name, NULL);
|
|
|
|
isc_buffer_remaining(&source, &remaining);
|
|
|
|
dns_name_fromregion(&name, &remaining);
|
|
|
|
INSIST(remaining.length >= name.length);
|
|
|
|
isc_buffer_forward(&source, name.length);
|
|
|
|
remaining.length -= name.length;
|
|
|
|
|
|
|
|
INSIST(remaining.length >= 4);
|
|
|
|
type = isc_buffer_getuint16(&source);
|
|
|
|
rcount = isc_buffer_getuint16(&source);
|
1999-09-21 20:41:20 +00:00
|
|
|
|
1999-09-22 00:26:19 +00:00
|
|
|
for (i = 0; i < rcount; i++) {
|
|
|
|
/*
|
|
|
|
* Get the length of this rdata and set up an
|
|
|
|
* rdata structure for it.
|
|
|
|
*/
|
|
|
|
isc_buffer_remaining(&source, &remaining);
|
|
|
|
INSIST(remaining.length >= 2);
|
|
|
|
dns_rdata_init(&rdata);
|
|
|
|
rdata.length = isc_buffer_getuint16(&source);
|
|
|
|
isc_buffer_remaining(&source, &remaining);
|
|
|
|
rdata.data = remaining.base;
|
|
|
|
rdata.type = type;
|
|
|
|
rdata.rdclass = rdataset->rdclass;
|
|
|
|
INSIST(remaining.length >= rdata.length);
|
|
|
|
isc_buffer_forward(&source, rdata.length);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Write the name.
|
|
|
|
*/
|
|
|
|
result = dns_name_towire(&name, cctx, target);
|
|
|
|
if (result != DNS_R_SUCCESS)
|
|
|
|
goto rollback;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* See if we have space for type, class, ttl, and
|
|
|
|
* rdata length. Write the type, class, and ttl.
|
|
|
|
*/
|
|
|
|
isc_buffer_remaining(target, &tremaining);
|
|
|
|
if (tremaining.length < 10) {
|
|
|
|
result = ISC_R_NOSPACE;
|
|
|
|
goto rollback;
|
|
|
|
}
|
|
|
|
isc_buffer_putuint16(target, type);
|
|
|
|
isc_buffer_putuint16(target, rdataset->rdclass);
|
|
|
|
isc_buffer_putuint32(target, rdataset->ttl);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Save space for rdata length.
|
|
|
|
*/
|
|
|
|
rdlen = *target;
|
|
|
|
isc_buffer_add(target, 2);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Write the rdata.
|
|
|
|
*/
|
|
|
|
result = dns_compress_localinit(cctx, &name, target);
|
|
|
|
if (result != DNS_R_SUCCESS)
|
|
|
|
goto rollback;
|
|
|
|
|
|
|
|
result = dns_rdata_towire(&rdata, cctx, target);
|
|
|
|
dns_compress_localinvalidate(cctx);
|
|
|
|
if (result != DNS_R_SUCCESS)
|
|
|
|
goto rollback;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Set the rdata length field to the compressed
|
|
|
|
* length.
|
|
|
|
*/
|
|
|
|
isc_buffer_putuint16(&rdlen,
|
|
|
|
target->used - rdlen.used - 2);
|
|
|
|
|
|
|
|
count++;
|
|
|
|
}
|
|
|
|
isc_buffer_remaining(&source, &remaining);
|
|
|
|
} while (remaining.length > 0);
|
|
|
|
|
|
|
|
*countp = count;
|
|
|
|
|
|
|
|
return (ISC_R_SUCCESS);
|
|
|
|
|
|
|
|
rollback:
|
|
|
|
dns_compress_rollback(cctx, savedbuffer.used);
|
|
|
|
*countp = 0;
|
|
|
|
*target = savedbuffer;
|
|
|
|
|
|
|
|
return (result);
|
1999-09-21 20:41:20 +00:00
|
|
|
}
|