145386Swpaul/* $NetBSD: ncache.c,v 1.9 2024/02/21 22:52:07 christos Exp $ */ 245386Swpaul 345386Swpaul/* 445386Swpaul * Copyright (C) Internet Systems Consortium, Inc. ("ISC") 545386Swpaul * 645386Swpaul * SPDX-License-Identifier: MPL-2.0 745386Swpaul * 845386Swpaul * This Source Code Form is subject to the terms of the Mozilla Public 945386Swpaul * License, v. 2.0. If a copy of the MPL was not distributed with this 1045386Swpaul * file, you can obtain one at https://mozilla.org/MPL/2.0/. 1145386Swpaul * 1245386Swpaul * See the COPYRIGHT file distributed with this work for additional 1345386Swpaul * information regarding copyright ownership. 1445386Swpaul */ 1545386Swpaul 1645386Swpaul/*! \file */ 1745386Swpaul 1845386Swpaul#include <inttypes.h> 1945386Swpaul#include <stdbool.h> 2045386Swpaul 2145386Swpaul#include <isc/buffer.h> 2245386Swpaul#include <isc/util.h> 2345386Swpaul 2445386Swpaul#include <dns/db.h> 2545386Swpaul#include <dns/message.h> 2645386Swpaul#include <dns/ncache.h> 2745386Swpaul#include <dns/rdata.h> 2845386Swpaul#include <dns/rdatalist.h> 2945386Swpaul#include <dns/rdataset.h> 3045386Swpaul#include <dns/rdatastruct.h> 3145386Swpaul 3245386Swpaul#define DNS_NCACHE_RDATA 100U 3345386Swpaul 3445386Swpaul/* 3545386Swpaul * The format of an ncache rdata is a sequence of zero or more records of 3645386Swpaul * the following format: 3745386Swpaul * 3845386Swpaul * owner name 3945386Swpaul * type 4045386Swpaul * trust 4145386Swpaul * rdata count 4245386Swpaul * rdata length These two occur 'rdata count' 4345386Swpaul * rdata times. 4445386Swpaul * 4545386Swpaul */ 4645386Swpaul 4745386Swpaulstatic isc_result_t 4845386Swpauladdoptout(dns_message_t *message, dns_db_t *cache, dns_dbnode_t *node, 4945386Swpaul dns_rdatatype_t covers, isc_stdtime_t now, dns_ttl_t minttl, 5045386Swpaul dns_ttl_t maxttl, bool optout, bool secure, 5145386Swpaul dns_rdataset_t *addedrdataset); 5245386Swpaul 5345386Swpaulstatic isc_result_t 5445386Swpaulcopy_rdataset(dns_rdataset_t *rdataset, isc_buffer_t *buffer) { 5545386Swpaul isc_result_t result; 5645386Swpaul unsigned int count; 5745386Swpaul isc_region_t ar, r; 5845386Swpaul dns_rdata_t rdata = DNS_RDATA_INIT; 5945386Swpaul 6045386Swpaul /* 6145386Swpaul * Copy the rdataset count to the buffer. 6245386Swpaul */ 6345386Swpaul isc_buffer_availableregion(buffer, &ar); 6445386Swpaul if (ar.length < 2) { 6545386Swpaul return (ISC_R_NOSPACE); 6645386Swpaul } 6745386Swpaul count = dns_rdataset_count(rdataset); 6845386Swpaul INSIST(count <= 65535); 6945386Swpaul isc_buffer_putuint16(buffer, (uint16_t)count); 7045386Swpaul 7145386Swpaul result = dns_rdataset_first(rdataset); 7245386Swpaul while (result == ISC_R_SUCCESS) { 7345386Swpaul dns_rdataset_current(rdataset, &rdata); 7445386Swpaul dns_rdata_toregion(&rdata, &r); 7545386Swpaul INSIST(r.length <= 65535); 7645386Swpaul isc_buffer_availableregion(buffer, &ar); 7745386Swpaul if (ar.length < 2) { 7845386Swpaul return (ISC_R_NOSPACE); 7945386Swpaul } 8045386Swpaul /* 8145386Swpaul * Copy the rdata length to the buffer. 8245386Swpaul */ 8345386Swpaul isc_buffer_putuint16(buffer, (uint16_t)r.length); 8445386Swpaul /* 8545386Swpaul * Copy the rdata to the buffer. 8645386Swpaul */ 8745386Swpaul result = isc_buffer_copyregion(buffer, &r); 8845386Swpaul if (result != ISC_R_SUCCESS) { 8945386Swpaul return (result); 9045386Swpaul } 9145386Swpaul dns_rdata_reset(&rdata); 9245386Swpaul result = dns_rdataset_next(rdataset); 9345386Swpaul } 9445386Swpaul if (result != ISC_R_NOMORE) { 9545386Swpaul return (result); 9645386Swpaul } 9745386Swpaul 9845386Swpaul return (ISC_R_SUCCESS); 9945386Swpaul} 10045386Swpaul 10145386Swpaulisc_result_t 10245386Swpauldns_ncache_add(dns_message_t *message, dns_db_t *cache, dns_dbnode_t *node, 10345386Swpaul dns_rdatatype_t covers, isc_stdtime_t now, dns_ttl_t minttl, 10445386Swpaul dns_ttl_t maxttl, dns_rdataset_t *addedrdataset) { 10545386Swpaul return (addoptout(message, cache, node, covers, now, minttl, maxttl, 10645386Swpaul false, false, addedrdataset)); 10745386Swpaul} 10845386Swpaul 10945386Swpaulisc_result_t 11045386Swpauldns_ncache_addoptout(dns_message_t *message, dns_db_t *cache, 11145386Swpaul dns_dbnode_t *node, dns_rdatatype_t covers, 11245386Swpaul isc_stdtime_t now, dns_ttl_t minttl, dns_ttl_t maxttl, 11345386Swpaul bool optout, dns_rdataset_t *addedrdataset) { 11445386Swpaul return (addoptout(message, cache, node, covers, now, minttl, maxttl, 11545386Swpaul optout, true, addedrdataset)); 11645386Swpaul} 11745386Swpaul 11845386Swpaulstatic isc_result_t 11945386Swpauladdoptout(dns_message_t *message, dns_db_t *cache, dns_dbnode_t *node, 12045386Swpaul dns_rdatatype_t covers, isc_stdtime_t now, dns_ttl_t minttl, 12145386Swpaul dns_ttl_t maxttl, bool optout, bool secure, 12245386Swpaul dns_rdataset_t *addedrdataset) { 12345386Swpaul isc_result_t result; 12445386Swpaul isc_buffer_t buffer; 12545386Swpaul isc_region_t r; 12645386Swpaul dns_rdataset_t *rdataset; 12745386Swpaul dns_rdatatype_t type; 12845386Swpaul dns_name_t *name; 12945386Swpaul dns_ttl_t ttl; 13045386Swpaul dns_trust_t trust; 13145386Swpaul dns_rdata_t rdata[DNS_NCACHE_RDATA]; 13245386Swpaul dns_rdataset_t ncrdataset; 13345386Swpaul dns_rdatalist_t ncrdatalist; 13445386Swpaul unsigned char data[65536]; 13545386Swpaul unsigned int next = 0; 13645386Swpaul 13745386Swpaul /* 13845386Swpaul * Convert the authority data from 'message' into a negative cache 13945386Swpaul * rdataset, and store it in 'cache' at 'node'. 14045386Swpaul */ 14145386Swpaul 14245386Swpaul REQUIRE(message != NULL); 14345386Swpaul 14445386Swpaul /* 14545386Swpaul * We assume that all data in the authority section has been 14645386Swpaul * validated by the caller. 14745386Swpaul */ 14845386Swpaul 14945386Swpaul /* 15045386Swpaul * Initialize the list. 15145386Swpaul */ 15245386Swpaul dns_rdatalist_init(&ncrdatalist); 15345386Swpaul ncrdatalist.rdclass = dns_db_class(cache); 15445386Swpaul ncrdatalist.covers = covers; 15545386Swpaul ncrdatalist.ttl = maxttl; 15645386Swpaul 15745386Swpaul /* 15845386Swpaul * Build an ncache rdatas into buffer. 15945386Swpaul */ 16045386Swpaul ttl = maxttl; 16145386Swpaul trust = 0xffff; 16245386Swpaul isc_buffer_init(&buffer, data, sizeof(data)); 16345386Swpaul if (message->counts[DNS_SECTION_AUTHORITY]) { 16445386Swpaul result = dns_message_firstname(message, DNS_SECTION_AUTHORITY); 16545386Swpaul } else { 16645386Swpaul result = ISC_R_NOMORE; 16745386Swpaul } 16845386Swpaul while (result == ISC_R_SUCCESS) { 16945386Swpaul name = NULL; 17045386Swpaul dns_message_currentname(message, DNS_SECTION_AUTHORITY, &name); 17145386Swpaul if ((name->attributes & DNS_NAMEATTR_NCACHE) != 0) { 17245386Swpaul for (rdataset = ISC_LIST_HEAD(name->list); 17345386Swpaul rdataset != NULL; 17445386Swpaul rdataset = ISC_LIST_NEXT(rdataset, link)) 17545386Swpaul { 17645386Swpaul if ((rdataset->attributes & 17745386Swpaul DNS_RDATASETATTR_NCACHE) == 0) 17845386Swpaul { 17945386Swpaul continue; 18045386Swpaul } 18145386Swpaul type = rdataset->type; 18245386Swpaul if (type == dns_rdatatype_rrsig) { 18345386Swpaul type = rdataset->covers; 18445386Swpaul } 18545386Swpaul if (type == dns_rdatatype_soa || 18645386Swpaul type == dns_rdatatype_nsec || 18745386Swpaul type == dns_rdatatype_nsec3) 18845386Swpaul { 18945386Swpaul if (ttl > rdataset->ttl) { 19045386Swpaul ttl = rdataset->ttl; 19145386Swpaul } 19245386Swpaul if (ttl < minttl) { 19345386Swpaul ttl = minttl; 19445386Swpaul } 19545386Swpaul if (trust > rdataset->trust) { 19645386Swpaul trust = rdataset->trust; 19745386Swpaul } 19845386Swpaul /* 19945386Swpaul * Copy the owner name to the buffer. 20045386Swpaul */ 20145386Swpaul dns_name_toregion(name, &r); 20245386Swpaul result = isc_buffer_copyregion(&buffer, 20345386Swpaul &r); 20445386Swpaul if (result != ISC_R_SUCCESS) { 20545386Swpaul return (result); 20645386Swpaul } 20745386Swpaul /* 20845386Swpaul * Copy the type to the buffer. 20945386Swpaul */ 21045386Swpaul isc_buffer_availableregion(&buffer, &r); 21145386Swpaul if (r.length < 3) { 21245386Swpaul return (ISC_R_NOSPACE); 21345386Swpaul } 21445386Swpaul isc_buffer_putuint16(&buffer, 21545386Swpaul rdataset->type); 21645386Swpaul isc_buffer_putuint8( 21745386Swpaul &buffer, 21845386Swpaul (unsigned char)rdataset->trust); 21945386Swpaul /* 22045386Swpaul * Copy the rdataset into the buffer. 22145386Swpaul */ 22245386Swpaul result = copy_rdataset(rdataset, 22345386Swpaul &buffer); 22445386Swpaul if (result != ISC_R_SUCCESS) { 22545386Swpaul return (result); 22645386Swpaul } 22745386Swpaul 22845386Swpaul if (next >= DNS_NCACHE_RDATA) { 22945386Swpaul return (ISC_R_NOSPACE); 23045386Swpaul } 23145386Swpaul dns_rdata_init(&rdata[next]); 23245386Swpaul isc_buffer_remainingregion(&buffer, &r); 23345386Swpaul rdata[next].data = r.base; 23445386Swpaul rdata[next].length = r.length; 23545386Swpaul rdata[next].rdclass = 23645386Swpaul ncrdatalist.rdclass; 23745386Swpaul rdata[next].type = 0; 23845386Swpaul rdata[next].flags = 0; 23945386Swpaul ISC_LIST_APPEND(ncrdatalist.rdata, 24045386Swpaul &rdata[next], link); 24145386Swpaul isc_buffer_forward(&buffer, r.length); 24245386Swpaul next++; 24345386Swpaul } 24445386Swpaul } 24545386Swpaul } 24645386Swpaul result = dns_message_nextname(message, DNS_SECTION_AUTHORITY); 24745386Swpaul } 24845386Swpaul if (result != ISC_R_NOMORE) { 24945386Swpaul return (result); 25045386Swpaul } 25145386Swpaul 25245386Swpaul if (trust == 0xffff) { 25345386Swpaul if ((message->flags & DNS_MESSAGEFLAG_AA) != 0 && 25445386Swpaul message->counts[DNS_SECTION_ANSWER] == 0) 25545386Swpaul { 25645386Swpaul /* 25745386Swpaul * The response has aa set and we haven't followed 25845386Swpaul * any CNAME or DNAME chains. 25945386Swpaul */ 26045386Swpaul trust = dns_trust_authauthority; 26145386Swpaul } else { 26245386Swpaul trust = dns_trust_additional; 26345386Swpaul } 26445386Swpaul ttl = 0; 26545386Swpaul } 26645386Swpaul 26745386Swpaul INSIST(trust != 0xffff); 26845386Swpaul 26945386Swpaul ncrdatalist.ttl = ttl; 27045386Swpaul 27145386Swpaul dns_rdataset_init(&ncrdataset); 27245386Swpaul RUNTIME_CHECK(dns_rdatalist_tordataset(&ncrdatalist, &ncrdataset) == 27345386Swpaul ISC_R_SUCCESS); 27445386Swpaul if (!secure && trust > dns_trust_answer) { 27545386Swpaul trust = dns_trust_answer; 27645386Swpaul } 27745386Swpaul ncrdataset.trust = trust; 27845386Swpaul ncrdataset.attributes |= DNS_RDATASETATTR_NEGATIVE; 27945386Swpaul if (message->rcode == dns_rcode_nxdomain) { 28045386Swpaul ncrdataset.attributes |= DNS_RDATASETATTR_NXDOMAIN; 28145386Swpaul } 28245386Swpaul if (optout) { 28345386Swpaul ncrdataset.attributes |= DNS_RDATASETATTR_OPTOUT; 28445386Swpaul } 28545386Swpaul 28645386Swpaul return (dns_db_addrdataset(cache, node, NULL, now, &ncrdataset, 0, 28745386Swpaul addedrdataset)); 28845386Swpaul} 28945386Swpaul 29045386Swpaulisc_result_t 29145386Swpauldns_ncache_towire(dns_rdataset_t *rdataset, dns_compress_t *cctx, 29245386Swpaul isc_buffer_t *target, unsigned int options, 29345386Swpaul unsigned int *countp) { 29445386Swpaul dns_rdata_t rdata = DNS_RDATA_INIT; 29545386Swpaul isc_result_t result; 29645386Swpaul isc_region_t remaining, tavailable; 29745386Swpaul isc_buffer_t source, savedbuffer, rdlen; 29845386Swpaul dns_name_t name; 29945386Swpaul dns_rdatatype_t type; 30045386Swpaul unsigned int i, rcount, count; 30145386Swpaul 30245386Swpaul /* 30345386Swpaul * Convert the negative caching rdataset 'rdataset' to wire format, 30445386Swpaul * compressing names as specified in 'cctx', and storing the result in 30545386Swpaul * 'target'. 30645386Swpaul */ 30745386Swpaul 30845386Swpaul REQUIRE(rdataset != NULL); 30945386Swpaul REQUIRE(rdataset->type == 0); 31045386Swpaul REQUIRE((rdataset->attributes & DNS_RDATASETATTR_NEGATIVE) != 0); 31145386Swpaul 31245386Swpaul savedbuffer = *target; 31345386Swpaul count = 0; 31445386Swpaul 31545386Swpaul result = dns_rdataset_first(rdataset); 31645386Swpaul while (result == ISC_R_SUCCESS) { 31745386Swpaul dns_rdataset_current(rdataset, &rdata); 31845386Swpaul isc_buffer_init(&source, rdata.data, rdata.length); 31945386Swpaul isc_buffer_add(&source, rdata.length); 32045386Swpaul dns_name_init(&name, NULL); 32145386Swpaul isc_buffer_remainingregion(&source, &remaining); 32245386Swpaul dns_name_fromregion(&name, &remaining); 32345386Swpaul INSIST(remaining.length >= name.length); 32445386Swpaul isc_buffer_forward(&source, name.length); 32545386Swpaul remaining.length -= name.length; 32645386Swpaul 32745386Swpaul INSIST(remaining.length >= 5); 32845386Swpaul type = isc_buffer_getuint16(&source); 32945386Swpaul isc_buffer_forward(&source, 1); 33045386Swpaul rcount = isc_buffer_getuint16(&source); 33145386Swpaul 33245386Swpaul for (i = 0; i < rcount; i++) { 33345386Swpaul /* 33445386Swpaul * Get the length of this rdata and set up an 33545386Swpaul * rdata structure for it. 33645386Swpaul */ 33745386Swpaul isc_buffer_remainingregion(&source, &remaining); 33845386Swpaul INSIST(remaining.length >= 2); 33945386Swpaul dns_rdata_reset(&rdata); 34045386Swpaul rdata.length = isc_buffer_getuint16(&source); 34145386Swpaul isc_buffer_remainingregion(&source, &remaining); 34245386Swpaul rdata.data = remaining.base; 34345386Swpaul rdata.type = type; 34445386Swpaul rdata.rdclass = rdataset->rdclass; 34545386Swpaul INSIST(remaining.length >= rdata.length); 34645386Swpaul isc_buffer_forward(&source, rdata.length); 34745386Swpaul 34845386Swpaul if ((options & DNS_NCACHETOWIRE_OMITDNSSEC) != 0 && 34945386Swpaul dns_rdatatype_isdnssec(type)) 35045386Swpaul { 35145386Swpaul continue; 35245386Swpaul } 35345386Swpaul 35445386Swpaul /* 35545386Swpaul * Write the name. 35645386Swpaul */ 35745386Swpaul dns_compress_setmethods(cctx, DNS_COMPRESS_GLOBAL14); 35845386Swpaul result = dns_name_towire(&name, cctx, target); 35945386Swpaul if (result != ISC_R_SUCCESS) { 36045386Swpaul goto rollback; 36145386Swpaul } 36245386Swpaul 36345386Swpaul /* 36445386Swpaul * See if we have space for type, class, ttl, and 36545386Swpaul * rdata length. Write the type, class, and ttl. 36645386Swpaul */ 36745386Swpaul isc_buffer_availableregion(target, &tavailable); 36845386Swpaul if (tavailable.length < 10) { 36945386Swpaul result = ISC_R_NOSPACE; 37045386Swpaul goto rollback; 37145386Swpaul } 37245386Swpaul isc_buffer_putuint16(target, type); 37345386Swpaul isc_buffer_putuint16(target, rdataset->rdclass); 37445386Swpaul isc_buffer_putuint32(target, rdataset->ttl); 37545386Swpaul 37645386Swpaul /* 37745386Swpaul * Save space for rdata length. 37845386Swpaul */ 37945386Swpaul rdlen = *target; 38045386Swpaul isc_buffer_add(target, 2); 38145386Swpaul 38245386Swpaul /* 38345386Swpaul * Write the rdata. 38445386Swpaul */ 38545386Swpaul result = dns_rdata_towire(&rdata, cctx, target); 38645386Swpaul if (result != ISC_R_SUCCESS) { 38745386Swpaul goto rollback; 38845386Swpaul } 38945386Swpaul 39045386Swpaul /* 39145386Swpaul * Set the rdata length field to the compressed 39245386Swpaul * length. 39345386Swpaul */ 39445386Swpaul INSIST((target->used >= rdlen.used + 2) && 39545386Swpaul (target->used - rdlen.used - 2 < 65536)); 39645386Swpaul isc_buffer_putuint16( 39745386Swpaul &rdlen, 39845386Swpaul (uint16_t)(target->used - rdlen.used - 2)); 39945386Swpaul 40045386Swpaul count++; 40145386Swpaul } 40245386Swpaul INSIST(isc_buffer_remaininglength(&source) == 0); 40345386Swpaul result = dns_rdataset_next(rdataset); 40445386Swpaul dns_rdata_reset(&rdata); 40545386Swpaul } 40645386Swpaul if (result != ISC_R_NOMORE) { 40745386Swpaul goto rollback; 40845386Swpaul } 40945386Swpaul 41045386Swpaul *countp = count; 41145386Swpaul 41245386Swpaul return (ISC_R_SUCCESS); 41345386Swpaul 41445386Swpaulrollback: 41545386Swpaul INSIST(savedbuffer.used < 65536); 41645386Swpaul dns_compress_rollback(cctx, (uint16_t)savedbuffer.used); 41745386Swpaul *countp = 0; 41845386Swpaul *target = savedbuffer; 41945386Swpaul 42045386Swpaul return (result); 42145386Swpaul} 42245386Swpaul 42345386Swpaulstatic void 42445386Swpaulrdataset_disassociate(dns_rdataset_t *rdataset) { 42545386Swpaul UNUSED(rdataset); 42645386Swpaul} 42745386Swpaul 42845386Swpaulstatic isc_result_t 42945386Swpaulrdataset_first(dns_rdataset_t *rdataset) { 43045386Swpaul unsigned char *raw = rdataset->private3; 43145386Swpaul unsigned int count; 43245386Swpaul 43345386Swpaul count = raw[0] * 256 + raw[1]; 43445386Swpaul if (count == 0) { 43545386Swpaul rdataset->private5 = NULL; 43645386Swpaul return (ISC_R_NOMORE); 43745386Swpaul } 43845386Swpaul raw += 2; 43945386Swpaul /* 44045386Swpaul * The privateuint4 field is the number of rdata beyond the cursor 44145386Swpaul * position, so we decrement the total count by one before storing 44245386Swpaul * it. 44345386Swpaul */ 44445386Swpaul count--; 44545386Swpaul rdataset->privateuint4 = count; 44645386Swpaul rdataset->private5 = raw; 44745386Swpaul 44845386Swpaul return (ISC_R_SUCCESS); 44945386Swpaul} 45045386Swpaul 45145386Swpaulstatic isc_result_t 45245386Swpaulrdataset_next(dns_rdataset_t *rdataset) { 45345386Swpaul unsigned int count; 45445386Swpaul unsigned int length; 45545386Swpaul unsigned char *raw; 45645386Swpaul 45745386Swpaul count = rdataset->privateuint4; 45845386Swpaul if (count == 0) { 45945386Swpaul return (ISC_R_NOMORE); 46045386Swpaul } 46145386Swpaul count--; 46245386Swpaul rdataset->privateuint4 = count; 46345386Swpaul raw = rdataset->private5; 46445386Swpaul length = raw[0] * 256 + raw[1]; 46545386Swpaul raw += length + 2; 46645386Swpaul rdataset->private5 = raw; 46745386Swpaul 46845386Swpaul return (ISC_R_SUCCESS); 46945386Swpaul} 47045386Swpaul 47145386Swpaulstatic void 47245386Swpaulrdataset_current(dns_rdataset_t *rdataset, dns_rdata_t *rdata) { 47345386Swpaul unsigned char *raw = rdataset->private5; 47445386Swpaul isc_region_t r; 47545386Swpaul 47645386Swpaul REQUIRE(raw != NULL); 47745386Swpaul 47845386Swpaul r.length = raw[0] * 256 + raw[1]; 47945386Swpaul raw += 2; 48045386Swpaul r.base = raw; 48145386Swpaul dns_rdata_fromregion(rdata, rdataset->rdclass, rdataset->type, &r); 48245386Swpaul} 48345386Swpaul 48445386Swpaulstatic void 48545386Swpaulrdataset_clone(dns_rdataset_t *source, dns_rdataset_t *target) { 48645386Swpaul *target = *source; 48745386Swpaul 48845386Swpaul /* 48945386Swpaul * Reset iterator state. 49045386Swpaul */ 49145386Swpaul target->privateuint4 = 0; 49245386Swpaul target->private5 = NULL; 49345386Swpaul} 49445386Swpaul 49545386Swpaulstatic unsigned int 49645386Swpaulrdataset_count(dns_rdataset_t *rdataset) { 49745386Swpaul unsigned char *raw = rdataset->private3; 49845386Swpaul unsigned int count; 49945386Swpaul 50045386Swpaul count = raw[0] * 256 + raw[1]; 50145386Swpaul 50245386Swpaul return (count); 50345386Swpaul} 50445386Swpaul 50545386Swpaulstatic void 50645386Swpaulrdataset_settrust(dns_rdataset_t *rdataset, dns_trust_t trust) { 50745386Swpaul unsigned char *raw = rdataset->private3; 50845386Swpaul 50945386Swpaul raw[-1] = (unsigned char)trust; 51045386Swpaul rdataset->trust = trust; 51145386Swpaul} 51245386Swpaul 51345386Swpaulstatic dns_rdatasetmethods_t rdataset_methods = { 51445386Swpaul rdataset_disassociate, 51545386Swpaul rdataset_first, 51645386Swpaul rdataset_next, 51745386Swpaul rdataset_current, 51845386Swpaul rdataset_clone, 51945386Swpaul rdataset_count, 52045386Swpaul NULL, /* addnoqname */ 52145386Swpaul NULL, /* getnoqname */ 52245386Swpaul NULL, /* addclosest */ 52345386Swpaul NULL, /* getclosest */ 52445386Swpaul rdataset_settrust, /* settrust */ 52545386Swpaul NULL, /* expire */ 52645386Swpaul NULL, /* clearprefetch */ 52745386Swpaul NULL, /* setownercase */ 52845386Swpaul NULL, /* getownercase */ 52945386Swpaul NULL /* addglue */ 53045386Swpaul}; 53145386Swpaul 53245386Swpaulisc_result_t 53345386Swpauldns_ncache_getrdataset(dns_rdataset_t *ncacherdataset, dns_name_t *name, 53445386Swpaul dns_rdatatype_t type, dns_rdataset_t *rdataset) { 53545386Swpaul isc_result_t result; 53645386Swpaul dns_rdata_t rdata = DNS_RDATA_INIT; 53745386Swpaul isc_region_t remaining; 53845386Swpaul isc_buffer_t source; 53945386Swpaul dns_name_t tname; 54045386Swpaul dns_rdatatype_t ttype; 54145386Swpaul dns_trust_t trust = dns_trust_none; 54245386Swpaul dns_rdataset_t rclone; 54345386Swpaul 54445386Swpaul REQUIRE(ncacherdataset != NULL); 54545386Swpaul REQUIRE(ncacherdataset->type == 0); 54645386Swpaul REQUIRE((ncacherdataset->attributes & DNS_RDATASETATTR_NEGATIVE) != 0); 54745386Swpaul REQUIRE(name != NULL); 54845386Swpaul REQUIRE(!dns_rdataset_isassociated(rdataset)); 54945386Swpaul REQUIRE(type != dns_rdatatype_rrsig); 55045386Swpaul 55145386Swpaul dns_rdataset_init(&rclone); 55245386Swpaul dns_rdataset_clone(ncacherdataset, &rclone); 55345386Swpaul result = dns_rdataset_first(&rclone); 55445386Swpaul while (result == ISC_R_SUCCESS) { 55545386Swpaul dns_rdataset_current(&rclone, &rdata); 55645386Swpaul isc_buffer_init(&source, rdata.data, rdata.length); 55745386Swpaul isc_buffer_add(&source, rdata.length); 55845386Swpaul dns_name_init(&tname, NULL); 55945386Swpaul isc_buffer_remainingregion(&source, &remaining); 56045386Swpaul dns_name_fromregion(&tname, &remaining); 56145386Swpaul INSIST(remaining.length >= tname.length); 56245386Swpaul isc_buffer_forward(&source, tname.length); 56345386Swpaul remaining.length -= tname.length; 56445386Swpaul 56545386Swpaul INSIST(remaining.length >= 3); 56645386Swpaul ttype = isc_buffer_getuint16(&source); 56745386Swpaul 56845386Swpaul if (ttype == type && dns_name_equal(&tname, name)) { 56945386Swpaul trust = isc_buffer_getuint8(&source); 57045386Swpaul INSIST(trust <= dns_trust_ultimate); 57145386Swpaul isc_buffer_remainingregion(&source, &remaining); 57245386Swpaul break; 57345386Swpaul } 57445386Swpaul result = dns_rdataset_next(&rclone); 57545386Swpaul dns_rdata_reset(&rdata); 57645386Swpaul } 57745386Swpaul dns_rdataset_disassociate(&rclone); 57845386Swpaul if (result == ISC_R_NOMORE) { 57945386Swpaul return (ISC_R_NOTFOUND); 58045386Swpaul } 58145386Swpaul if (result != ISC_R_SUCCESS) { 58245386Swpaul return (result); 58345386Swpaul } 58445386Swpaul 58545386Swpaul INSIST(remaining.length != 0); 58645386Swpaul 58745386Swpaul rdataset->methods = &rdataset_methods; 58845386Swpaul rdataset->rdclass = ncacherdataset->rdclass; 58945386Swpaul rdataset->type = type; 59045386Swpaul rdataset->covers = 0; 59145386Swpaul rdataset->ttl = ncacherdataset->ttl; 59245386Swpaul rdataset->trust = trust; 59345386Swpaul rdataset->private1 = NULL; 59445386Swpaul rdataset->private2 = NULL; 59545386Swpaul 59645386Swpaul rdataset->private3 = remaining.base; 59745386Swpaul 59845386Swpaul /* 59945386Swpaul * Reset iterator state. 60045386Swpaul */ 60145386Swpaul rdataset->privateuint4 = 0; 60245386Swpaul rdataset->private5 = NULL; 60345386Swpaul rdataset->private6 = NULL; 60445386Swpaul return (ISC_R_SUCCESS); 60545386Swpaul} 60645386Swpaul 60745386Swpaulisc_result_t 60845386Swpauldns_ncache_getsigrdataset(dns_rdataset_t *ncacherdataset, dns_name_t *name, 60945386Swpaul dns_rdatatype_t covers, dns_rdataset_t *rdataset) { 61045386Swpaul dns_name_t tname; 61145386Swpaul dns_rdata_rrsig_t rrsig; 61245386Swpaul dns_rdata_t rdata = DNS_RDATA_INIT; 61345386Swpaul dns_rdataset_t rclone; 61445386Swpaul dns_rdatatype_t type; 61545386Swpaul dns_trust_t trust = dns_trust_none; 61645386Swpaul isc_buffer_t source; 61745386Swpaul isc_region_t remaining, sigregion; 61845386Swpaul isc_result_t result; 61945386Swpaul unsigned char *raw; 62045386Swpaul unsigned int count; 62145386Swpaul 62245386Swpaul REQUIRE(ncacherdataset != NULL); 62345386Swpaul REQUIRE(ncacherdataset->type == 0); 62445386Swpaul REQUIRE((ncacherdataset->attributes & DNS_RDATASETATTR_NEGATIVE) != 0); 62545386Swpaul REQUIRE(name != NULL); 62645386Swpaul REQUIRE(!dns_rdataset_isassociated(rdataset)); 62745386Swpaul 62845386Swpaul dns_rdataset_init(&rclone); 62945386Swpaul dns_rdataset_clone(ncacherdataset, &rclone); 63045386Swpaul result = dns_rdataset_first(&rclone); 63145386Swpaul while (result == ISC_R_SUCCESS) { 63245386Swpaul dns_rdataset_current(&rclone, &rdata); 63345386Swpaul isc_buffer_init(&source, rdata.data, rdata.length); 63445386Swpaul isc_buffer_add(&source, rdata.length); 63545386Swpaul dns_name_init(&tname, NULL); 63645386Swpaul isc_buffer_remainingregion(&source, &remaining); 63745386Swpaul dns_name_fromregion(&tname, &remaining); 63845386Swpaul INSIST(remaining.length >= tname.length); 63945386Swpaul isc_buffer_forward(&source, tname.length); 64045386Swpaul isc_region_consume(&remaining, tname.length); 64145386Swpaul 64245386Swpaul INSIST(remaining.length >= 2); 64345386Swpaul type = isc_buffer_getuint16(&source); 64445386Swpaul isc_region_consume(&remaining, 2); 64545386Swpaul 64645386Swpaul if (type != dns_rdatatype_rrsig || 64745386Swpaul !dns_name_equal(&tname, name)) 64845386Swpaul { 64945386Swpaul result = dns_rdataset_next(&rclone); 65045386Swpaul dns_rdata_reset(&rdata); 65145386Swpaul continue; 65245386Swpaul } 65345386Swpaul 65445386Swpaul INSIST(remaining.length >= 1); 65545386Swpaul trust = isc_buffer_getuint8(&source); 65645386Swpaul INSIST(trust <= dns_trust_ultimate); 65745386Swpaul isc_region_consume(&remaining, 1); 65845386Swpaul 65945386Swpaul raw = remaining.base; 66045386Swpaul count = raw[0] * 256 + raw[1]; 66145386Swpaul INSIST(count > 0); 66245386Swpaul raw += 2; 66345386Swpaul sigregion.length = raw[0] * 256 + raw[1]; 66445386Swpaul raw += 2; 66545386Swpaul sigregion.base = raw; 66645386Swpaul dns_rdata_reset(&rdata); 66745386Swpaul dns_rdata_fromregion(&rdata, rdataset->rdclass, 66845386Swpaul dns_rdatatype_rrsig, &sigregion); 66945386Swpaul (void)dns_rdata_tostruct(&rdata, &rrsig, NULL); 67045386Swpaul if (rrsig.covered == covers) { 67145386Swpaul isc_buffer_remainingregion(&source, &remaining); 67245386Swpaul break; 67345386Swpaul } 67445386Swpaul 67545386Swpaul result = dns_rdataset_next(&rclone); 67645386Swpaul dns_rdata_reset(&rdata); 67745386Swpaul } 67845386Swpaul dns_rdataset_disassociate(&rclone); 67945386Swpaul if (result == ISC_R_NOMORE) { 68045386Swpaul return (ISC_R_NOTFOUND); 68145386Swpaul } 68245386Swpaul if (result != ISC_R_SUCCESS) { 68345386Swpaul return (result); 68445386Swpaul } 68545386Swpaul 68645386Swpaul INSIST(remaining.length != 0); 68745386Swpaul 68845386Swpaul rdataset->methods = &rdataset_methods; 68945386Swpaul rdataset->rdclass = ncacherdataset->rdclass; 69045386Swpaul rdataset->type = dns_rdatatype_rrsig; 69145386Swpaul rdataset->covers = covers; 69245386Swpaul rdataset->ttl = ncacherdataset->ttl; 69345386Swpaul rdataset->trust = trust; 69445386Swpaul rdataset->private1 = NULL; 69545386Swpaul rdataset->private2 = NULL; 69645386Swpaul 69745386Swpaul rdataset->private3 = remaining.base; 69845386Swpaul 69945386Swpaul /* 70045386Swpaul * Reset iterator state. 70145386Swpaul */ 70245386Swpaul rdataset->privateuint4 = 0; 70345386Swpaul rdataset->private5 = NULL; 70445386Swpaul rdataset->private6 = NULL; 70545386Swpaul return (ISC_R_SUCCESS); 70645386Swpaul} 70745386Swpaul 70845386Swpaulvoid 70945386Swpauldns_ncache_current(dns_rdataset_t *ncacherdataset, dns_name_t *found, 71045386Swpaul dns_rdataset_t *rdataset) { 71145386Swpaul dns_rdata_t rdata = DNS_RDATA_INIT; 71245386Swpaul dns_trust_t trust; 71345386Swpaul isc_region_t remaining, sigregion; 71445386Swpaul isc_buffer_t source; 71545386Swpaul dns_name_t tname; 71645386Swpaul dns_rdatatype_t type; 71745386Swpaul unsigned int count; 71845386Swpaul dns_rdata_rrsig_t rrsig; 71945386Swpaul unsigned char *raw; 72045386Swpaul 72145386Swpaul REQUIRE(ncacherdataset != NULL); 72245386Swpaul REQUIRE(ncacherdataset->type == 0); 72345386Swpaul REQUIRE((ncacherdataset->attributes & DNS_RDATASETATTR_NEGATIVE) != 0); 72445386Swpaul REQUIRE(found != NULL); 72545386Swpaul REQUIRE(!dns_rdataset_isassociated(rdataset)); 72645386Swpaul 72745386Swpaul dns_rdataset_current(ncacherdataset, &rdata); 72845386Swpaul isc_buffer_init(&source, rdata.data, rdata.length); 72945386Swpaul isc_buffer_add(&source, rdata.length); 73045386Swpaul 73145386Swpaul dns_name_init(&tname, NULL); 73245386Swpaul isc_buffer_remainingregion(&source, &remaining); 73345386Swpaul dns_name_fromregion(found, &remaining); 73445386Swpaul INSIST(remaining.length >= found->length); 73545386Swpaul isc_buffer_forward(&source, found->length); 73645386Swpaul remaining.length -= found->length; 73745386Swpaul 73845386Swpaul INSIST(remaining.length >= 5); 73945386Swpaul type = isc_buffer_getuint16(&source); 74045386Swpaul trust = isc_buffer_getuint8(&source); 74145386Swpaul INSIST(trust <= dns_trust_ultimate); 74245386Swpaul isc_buffer_remainingregion(&source, &remaining); 74345386Swpaul 74445386Swpaul rdataset->methods = &rdataset_methods; 74545386Swpaul rdataset->rdclass = ncacherdataset->rdclass; 74645386Swpaul rdataset->type = type; 74745386Swpaul if (type == dns_rdatatype_rrsig) { 74845386Swpaul /* 74945386Swpaul * Extract covers from RRSIG. 75045386Swpaul */ 75145386Swpaul raw = remaining.base; 75245386Swpaul count = raw[0] * 256 + raw[1]; 75345386Swpaul INSIST(count > 0); 75445386Swpaul raw += 2; 75545386Swpaul sigregion.length = raw[0] * 256 + raw[1]; 75645386Swpaul raw += 2; 75745386Swpaul sigregion.base = raw; 75845386Swpaul dns_rdata_reset(&rdata); 75945386Swpaul dns_rdata_fromregion(&rdata, ncacherdataset->rdclass, type, 76045386Swpaul &sigregion); 76145386Swpaul (void)dns_rdata_tostruct(&rdata, &rrsig, NULL); 76245386Swpaul rdataset->covers = rrsig.covered; 76345386Swpaul } else { 76445386Swpaul rdataset->covers = 0; 76545386Swpaul } 76645386Swpaul rdataset->ttl = ncacherdataset->ttl; 76745386Swpaul rdataset->trust = trust; 76845386Swpaul rdataset->private1 = NULL; 76945386Swpaul rdataset->private2 = NULL; 77045386Swpaul 77145386Swpaul rdataset->private3 = remaining.base; 77245386Swpaul 77345386Swpaul /* 77445386Swpaul * Reset iterator state. 77545386Swpaul */ 77645386Swpaul rdataset->privateuint4 = 0; 77745386Swpaul rdataset->private5 = NULL; 77845386Swpaul rdataset->private6 = NULL; 77945386Swpaul} 78045386Swpaul