ncache.c revision 364a82f7c25b62967678027043425201a5e5171a
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews/*
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews * Copyright (C) 1999, 2000 Internet Software Consortium.
1a03b5e68553c37e9cc0097368909dfc37fb8cefMark Andrews *
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews * Permission to use, copy, modify, and distribute this software for any
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews * purpose with or without fee is hereby granted, provided that the above
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews * copyright notice and this permission notice appear in all copies.
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews *
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews * SOFTWARE.
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews */
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews#include <config.h>
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews#include <isc/assertions.h>
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews#include <isc/region.h>
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews#include <isc/buffer.h>
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews#include <isc/util.h>
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews#include <dns/types.h>
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews#include <dns/ncache.h>
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews#include <dns/name.h>
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews#include <dns/compress.h>
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews#include <dns/message.h>
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews#include <dns/db.h>
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews#include <dns/rdata.h>
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews#include <dns/rdataset.h>
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews#include <dns/rdatalist.h>
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews/*
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews * The format of an ncache rdata is a sequence of one or more records of
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews * the following format:
1a03b5e68553c37e9cc0097368909dfc37fb8cefMark Andrews *
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews * owner name
1a03b5e68553c37e9cc0097368909dfc37fb8cefMark Andrews * type
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews * rdata count
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews * rdata length These two occur 'rdata count'
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews * rdata times.
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews *
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews */
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrewsstatic inline isc_result_t
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrewscopy_rdataset(dns_rdataset_t *rdataset, isc_buffer_t *buffer) {
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews isc_result_t result;
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews unsigned int count;
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews isc_region_t ar, r;
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews dns_rdata_t rdata;
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews /*
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews * Copy the rdataset count to the buffer.
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews */
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews isc_buffer_availableregion(buffer, &ar);
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews if (ar.length < 2)
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews return (ISC_R_NOSPACE);
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews count = dns_rdataset_count(rdataset);
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews INSIST(count <= 65535);
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews isc_buffer_putuint16(buffer, (isc_uint16_t)count);
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews result = dns_rdataset_first(rdataset);
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews while (result == ISC_R_SUCCESS) {
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews dns_rdataset_current(rdataset, &rdata);
1a03b5e68553c37e9cc0097368909dfc37fb8cefMark Andrews dns_rdata_toregion(&rdata, &r);
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews INSIST(r.length <= 65535);
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews isc_buffer_availableregion(buffer, &ar);
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews if (ar.length < 2)
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews return (ISC_R_NOSPACE);
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews /*
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews * Copy the rdata length to the buffer.
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews */
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews isc_buffer_putuint16(buffer, (isc_uint16_t)r.length);
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews /*
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews * Copy the rdata to the buffer.
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews */
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews result = isc_buffer_copyregion(buffer, &r);
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews if (result != ISC_R_SUCCESS)
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews return (result);
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews result = dns_rdataset_next(rdataset);
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews }
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews if (result != ISC_R_NOMORE)
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews return (result);
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews return (ISC_R_SUCCESS);
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews}
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrewsisc_result_t
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrewsdns_ncache_add(dns_message_t *message, dns_db_t *cache, dns_dbnode_t *node,
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews dns_rdatatype_t covers, isc_stdtime_t now,
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews dns_rdataset_t *addedrdataset)
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews{
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews isc_result_t result;
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews isc_buffer_t buffer;
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews isc_region_t r;
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews dns_rdataset_t *rdataset;
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews dns_rdatatype_t type;
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews dns_name_t *name;
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews dns_ttl_t ttl;
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews dns_trust_t trust;
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews dns_rdata_t rdata;
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews dns_rdataset_t ncrdataset;
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews dns_rdatalist_t ncrdatalist;
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews unsigned char data[4096];
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews /*
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews * Convert the authority data from 'message' into a negative cache
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews * rdataset, and store it in 'cache' at 'node'.
1a03b5e68553c37e9cc0097368909dfc37fb8cefMark Andrews */
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews REQUIRE(message != NULL);
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews /*
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews * We assume that all data in the authority section has been
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews * validated by the caller.
1a03b5e68553c37e9cc0097368909dfc37fb8cefMark Andrews */
1a03b5e68553c37e9cc0097368909dfc37fb8cefMark Andrews
1a03b5e68553c37e9cc0097368909dfc37fb8cefMark Andrews /*
1a03b5e68553c37e9cc0097368909dfc37fb8cefMark Andrews * First, build an ncache rdata in buffer.
1a03b5e68553c37e9cc0097368909dfc37fb8cefMark Andrews */
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews ttl = 0xffffffff;
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews trust = 0xffff;
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews isc_buffer_init(&buffer, data, sizeof(data));
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews result = dns_message_firstname(message, DNS_SECTION_AUTHORITY);
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews while (result == ISC_R_SUCCESS) {
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews name = NULL;
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews dns_message_currentname(message, DNS_SECTION_AUTHORITY,
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews &name);
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews if ((name->attributes & DNS_NAMEATTR_NCACHE) != 0) {
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews for (rdataset = ISC_LIST_HEAD(name->list);
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews rdataset != NULL;
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews rdataset = ISC_LIST_NEXT(rdataset, link)) {
1a03b5e68553c37e9cc0097368909dfc37fb8cefMark Andrews if ((rdataset->attributes &
1a03b5e68553c37e9cc0097368909dfc37fb8cefMark Andrews DNS_RDATASETATTR_NCACHE) == 0)
1a03b5e68553c37e9cc0097368909dfc37fb8cefMark Andrews continue;
1a03b5e68553c37e9cc0097368909dfc37fb8cefMark Andrews type = rdataset->type;
1a03b5e68553c37e9cc0097368909dfc37fb8cefMark Andrews if (type == dns_rdatatype_sig)
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews type = rdataset->covers;
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews if (type == dns_rdatatype_soa ||
1a03b5e68553c37e9cc0097368909dfc37fb8cefMark Andrews type == dns_rdatatype_nxt) {
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews if (ttl > rdataset->ttl)
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews ttl = rdataset->ttl;
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews if (trust > rdataset->trust)
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews trust = rdataset->trust;
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews /*
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews * Copy the owner name to the buffer.
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews */
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews dns_name_toregion(name, &r);
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews result = isc_buffer_copyregion(&buffer,
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews &r);
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews if (result != ISC_R_SUCCESS)
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews return (result);
1a03b5e68553c37e9cc0097368909dfc37fb8cefMark Andrews /*
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews * Copy the type to the buffer.
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews */
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews isc_buffer_availableregion(&buffer, &r);
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews if (r.length < 2)
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews return (ISC_R_NOSPACE);
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews isc_buffer_putuint16(&buffer,
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews rdataset->type);
1a03b5e68553c37e9cc0097368909dfc37fb8cefMark Andrews /*
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews * Copy the rdataset into the buffer.
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews */
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews result = copy_rdataset(rdataset,
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews &buffer);
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews if (result != ISC_R_SUCCESS)
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews return (result);
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews }
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews }
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews }
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews result = dns_message_nextname(message, DNS_SECTION_AUTHORITY);
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews }
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews if (result != ISC_R_NOMORE)
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews return (result);
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews if (trust == 0xffff) {
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews /*
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews * We didn't find any authority data from which to create a
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews * negative cache rdataset. In particular, we have no SOA.
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews *
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews * We trust that the caller wants negative caching, so this
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews * means we have a "type 3 nxdomain" or "type 3 nodata"
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews * response (see RFC 2308 for details).
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews *
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews * We will now build a suitable negative cache rdataset that
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews * will cause zero bytes to be emitted when converted to
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews * wire format.
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews */
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews /*
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews * The ownername must exist, but it doesn't matter what value
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews * it has. We use the root name.
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews */
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews dns_name_toregion(dns_rootname, &r);
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews result = isc_buffer_copyregion(&buffer, &r);
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews if (result != ISC_R_SUCCESS)
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews return (result);
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews /*
1a03b5e68553c37e9cc0097368909dfc37fb8cefMark Andrews * Copy the type and a zero rdata count to the buffer.
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews */
1a03b5e68553c37e9cc0097368909dfc37fb8cefMark Andrews isc_buffer_availableregion(&buffer, &r);
1a03b5e68553c37e9cc0097368909dfc37fb8cefMark Andrews if (r.length < 4)
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews return (ISC_R_NOSPACE);
1a03b5e68553c37e9cc0097368909dfc37fb8cefMark Andrews isc_buffer_putuint16(&buffer, 0);
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews isc_buffer_putuint16(&buffer, 0);
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews /*
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews * RFC 2308, section 5, says that negative answers without
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews * SOAs should not be cached.
1a03b5e68553c37e9cc0097368909dfc37fb8cefMark Andrews */
1a03b5e68553c37e9cc0097368909dfc37fb8cefMark Andrews ttl = 0;
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews /*
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews * Set trust.
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews */
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews if ((message->flags & DNS_MESSAGEFLAG_AA) != 0 &&
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews message->counts[DNS_SECTION_ANSWER] == 0) {
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews /*
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews * The response has aa set and we haven't followed
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews * any CNAME or DNAME chains.
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews */
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews trust = dns_trust_authauthority;
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews } else
1a03b5e68553c37e9cc0097368909dfc37fb8cefMark Andrews trust = dns_trust_additional;
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews }
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews /*
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews * Now add it to the cache.
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews */
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews INSIST(trust != 0xffff);
1a03b5e68553c37e9cc0097368909dfc37fb8cefMark Andrews dns_rdata_init(&rdata);
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews isc_buffer_usedregion(&buffer, &r);
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews rdata.data = r.base;
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews rdata.length = r.length;
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews rdata.rdclass = dns_db_class(cache);
1a03b5e68553c37e9cc0097368909dfc37fb8cefMark Andrews rdata.type = 0;
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews
1a03b5e68553c37e9cc0097368909dfc37fb8cefMark Andrews ncrdatalist.rdclass = rdata.rdclass;
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews ncrdatalist.type = 0;
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews ncrdatalist.covers = covers;
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews ncrdatalist.ttl = ttl;
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews ISC_LIST_INIT(ncrdatalist.rdata);
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews ISC_LINK_INIT(&ncrdatalist, link);
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews
1a03b5e68553c37e9cc0097368909dfc37fb8cefMark Andrews ISC_LIST_APPEND(ncrdatalist.rdata, &rdata, link);
1a03b5e68553c37e9cc0097368909dfc37fb8cefMark Andrews
1a03b5e68553c37e9cc0097368909dfc37fb8cefMark Andrews dns_rdataset_init(&ncrdataset);
1a03b5e68553c37e9cc0097368909dfc37fb8cefMark Andrews dns_rdatalist_tordataset(&ncrdatalist, &ncrdataset);
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews ncrdataset.trust = trust;
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews return (dns_db_addrdataset(cache, node, NULL, now, &ncrdataset,
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews 0, addedrdataset));
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews}
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrewsisc_result_t
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrewsdns_ncache_towire(dns_rdataset_t *rdataset, dns_compress_t *cctx,
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews isc_buffer_t *target, unsigned int *countp)
1a03b5e68553c37e9cc0097368909dfc37fb8cefMark Andrews{
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews dns_rdata_t rdata;
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews isc_result_t result;
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews isc_region_t remaining, tremaining;
1a03b5e68553c37e9cc0097368909dfc37fb8cefMark Andrews isc_buffer_t source, savedbuffer, rdlen;
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews dns_name_t name;
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews dns_rdatatype_t type;
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews unsigned int i, rcount, count;
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews /*
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews * Convert the negative caching rdataset 'rdataset' to wire format,
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews * compressing names as specified in 'cctx', and storing the result in
1a03b5e68553c37e9cc0097368909dfc37fb8cefMark Andrews * 'target'.
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews */
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews REQUIRE(rdataset != NULL);
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews REQUIRE(rdataset->type == 0);
1a03b5e68553c37e9cc0097368909dfc37fb8cefMark Andrews
1a03b5e68553c37e9cc0097368909dfc37fb8cefMark Andrews result = dns_rdataset_first(rdataset);
1a03b5e68553c37e9cc0097368909dfc37fb8cefMark Andrews if (result != ISC_R_SUCCESS)
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews return (result);
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews dns_rdataset_current(rdataset, &rdata);
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews INSIST(dns_rdataset_next(rdataset) == ISC_R_NOMORE);
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews isc_buffer_init(&source, rdata.data, rdata.length);
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews isc_buffer_add(&source, rdata.length);
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews if (dns_compress_getedns(cctx) >= 1)
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews dns_compress_setmethods(cctx, DNS_COMPRESS_GLOBAL);
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews else
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews dns_compress_setmethods(cctx, DNS_COMPRESS_GLOBAL14);
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews savedbuffer = *target;
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews count = 0;
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews do {
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews dns_name_init(&name, NULL);
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews isc_buffer_remainingregion(&source, &remaining);
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews dns_name_fromregion(&name, &remaining);
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews INSIST(remaining.length >= name.length);
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews isc_buffer_forward(&source, name.length);
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews remaining.length -= name.length;
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews INSIST(remaining.length >= 4);
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews type = isc_buffer_getuint16(&source);
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews rcount = isc_buffer_getuint16(&source);
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews for (i = 0; i < rcount; i++) {
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews /*
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews * Get the length of this rdata and set up an
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews * rdata structure for it.
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews */
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews isc_buffer_remainingregion(&source, &remaining);
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews INSIST(remaining.length >= 2);
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews dns_rdata_init(&rdata);
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews rdata.length = isc_buffer_getuint16(&source);
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews isc_buffer_remainingregion(&source, &remaining);
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews rdata.data = remaining.base;
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews rdata.type = type;
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews rdata.rdclass = rdataset->rdclass;
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews INSIST(remaining.length >= rdata.length);
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews isc_buffer_forward(&source, rdata.length);
1a03b5e68553c37e9cc0097368909dfc37fb8cefMark Andrews
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews /*
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews * Write the name.
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews */
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews result = dns_name_towire(&name, cctx, target);
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews if (result != ISC_R_SUCCESS)
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews goto rollback;
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews /*
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews * See if we have space for type, class, ttl, and
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews * rdata length. Write the type, class, and ttl.
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews */
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews isc_buffer_remainingregion(target, &tremaining);
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews if (tremaining.length < 10) {
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews result = ISC_R_NOSPACE;
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews goto rollback;
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews }
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews isc_buffer_putuint16(target, type);
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews isc_buffer_putuint16(target, rdataset->rdclass);
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews isc_buffer_putuint32(target, rdataset->ttl);
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews /*
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews * Save space for rdata length.
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews */
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews rdlen = *target;
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews isc_buffer_add(target, 2);
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews /*
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews * Write the rdata.
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews */
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews result = dns_rdata_towire(&rdata, cctx, target);
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews if (result != ISC_R_SUCCESS)
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews goto rollback;
1a03b5e68553c37e9cc0097368909dfc37fb8cefMark Andrews
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews /*
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews * Set the rdata length field to the compressed
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews * length.
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews */
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews INSIST((target->used >= rdlen.used + 2) &&
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews (target->used - rdlen.used - 2 < 65536));
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews isc_buffer_putuint16(&rdlen,
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews (isc_uint16_t)(target->used -
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews rdlen.used - 2));
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews count++;
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews }
1a03b5e68553c37e9cc0097368909dfc37fb8cefMark Andrews isc_buffer_remainingregion(&source, &remaining);
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews } while (remaining.length > 0);
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews *countp = count;
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews return (ISC_R_SUCCESS);
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews rollback:
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews INSIST(savedbuffer.used < 65536);
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews dns_compress_rollback(cctx, (isc_uint16_t)savedbuffer.used);
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews *countp = 0;
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews *target = savedbuffer;
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews return (result);
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews}
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews