static isc_result_t addoptout(dns_message_t *message, dns_db_t *cache, dns_dbnode_t *node, dns_rdatatype_t covers, isc_stdtime_t now, dns_ttl_t maxttl, isc_boolean_t optout, isc_boolean_t secure, dns_rdataset_t *addedrdataset) { isc_result_t result; isc_buffer_t buffer; isc_region_t r; dns_rdataset_t *rdataset; dns_rdatatype_t type; dns_name_t *name; dns_ttl_t ttl; dns_trust_t trust; dns_rdata_t rdata[DNS_NCACHE_RDATA]; dns_rdataset_t ncrdataset; dns_rdatalist_t ncrdatalist; 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'. */ REQUIRE(message != NULL); /* * We assume that all data in the authority section has been * validated by the caller. */ /* * Initialize the list. */ dns_rdatalist_init(&ncrdatalist); ncrdatalist.rdclass = dns_db_class(cache); ncrdatalist.covers = covers; ncrdatalist.ttl = maxttl; /* * Build an ncache rdatas into buffer. */ ttl = maxttl; trust = 0xffff; isc_buffer_init(&buffer, data, sizeof(data)); if (message->counts[DNS_SECTION_AUTHORITY]) result = dns_message_firstname(message, DNS_SECTION_AUTHORITY); else result = ISC_R_NOMORE; while (result == ISC_R_SUCCESS) { name = NULL; dns_message_currentname(message, DNS_SECTION_AUTHORITY, &name); if ((name->attributes & DNS_NAMEATTR_NCACHE) != 0) { 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_rrsig) type = rdataset->covers; if (type == dns_rdatatype_soa || type == dns_rdatatype_nsec || type == dns_rdatatype_nsec3) { if (ttl > rdataset->ttl) ttl = rdataset->ttl; if (trust > rdataset->trust) trust = rdataset->trust; /* * 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_availableregion(&buffer, &r); if (r.length < 3) return (ISC_R_NOSPACE); isc_buffer_putuint16(&buffer, rdataset->type); isc_buffer_putuint8(&buffer, (unsigned char)rdataset->trust); /* * Copy the rdataset into the buffer. */ result = copy_rdataset(rdataset, &buffer); if (result != ISC_R_SUCCESS) return (result); if (next >= DNS_NCACHE_RDATA) return (ISC_R_NOSPACE); dns_rdata_init(&rdata[next]); isc_buffer_remainingregion(&buffer, &r); rdata[next].data = r.base; rdata[next].length = r.length; rdata[next].rdclass = ncrdatalist.rdclass; rdata[next].type = 0; rdata[next].flags = 0; ISC_LIST_APPEND(ncrdatalist.rdata, &rdata[next], link); isc_buffer_forward(&buffer, r.length); next++; } } } result = dns_message_nextname(message, DNS_SECTION_AUTHORITY); } if (result != ISC_R_NOMORE) return (result); if (trust == 0xffff) { if ((message->flags & DNS_MESSAGEFLAG_AA) != 0 && message->counts[DNS_SECTION_ANSWER] == 0) { /* * The response has aa set and we haven't followed * any CNAME or DNAME chains. */ trust = dns_trust_authauthority; } else trust = dns_trust_additional; ttl = 0; } INSIST(trust != 0xffff); ncrdatalist.ttl = ttl; dns_rdataset_init(&ncrdataset); RUNTIME_CHECK(dns_rdatalist_tordataset(&ncrdatalist, &ncrdataset) == ISC_R_SUCCESS); if (!secure && trust > dns_trust_answer) trust = dns_trust_answer; ncrdataset.trust = trust; ncrdataset.attributes |= DNS_RDATASETATTR_NEGATIVE; if (message->rcode == dns_rcode_nxdomain) ncrdataset.attributes |= DNS_RDATASETATTR_NXDOMAIN; if (optout) ncrdataset.attributes |= DNS_RDATASETATTR_OPTOUT; return (dns_db_addrdataset(cache, node, NULL, now, &ncrdataset, 0, addedrdataset)); }
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_ttl_t maxttl, dns_rdataset_t *addedrdataset) { isc_result_t result; isc_buffer_t buffer; isc_region_t r; dns_rdataset_t *rdataset; dns_rdatatype_t type; dns_name_t *name; dns_ttl_t ttl; dns_trust_t trust; dns_rdata_t rdata = DNS_RDATA_INIT; dns_rdataset_t ncrdataset; dns_rdatalist_t ncrdatalist; unsigned char data[4096]; /* * Convert the authority data from 'message' into a negative cache * rdataset, and store it in 'cache' at 'node'. */ REQUIRE(message != NULL); /* * We assume that all data in the authority section has been * validated by the caller. */ /* * First, build an ncache rdata in buffer. */ ttl = maxttl; trust = 0xffff; isc_buffer_init(&buffer, data, sizeof(data)); if (message->counts[DNS_SECTION_AUTHORITY]) result = dns_message_firstname(message, DNS_SECTION_AUTHORITY); else result = ISC_R_NOMORE; while (result == ISC_R_SUCCESS) { name = NULL; dns_message_currentname(message, DNS_SECTION_AUTHORITY, &name); if ((name->attributes & DNS_NAMEATTR_NCACHE) != 0) { 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_rrsig) type = rdataset->covers; if (type == dns_rdatatype_soa || type == dns_rdatatype_nsec) { if (ttl > rdataset->ttl) ttl = rdataset->ttl; if (trust > rdataset->trust) trust = rdataset->trust; /* * 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_availableregion(&buffer, &r); if (r.length < 2) return (ISC_R_NOSPACE); isc_buffer_putuint16(&buffer, rdataset->type); /* * Copy the rdataset into the buffer. */ result = copy_rdataset(rdataset, &buffer); if (result != ISC_R_SUCCESS) return (result); } } } result = dns_message_nextname(message, DNS_SECTION_AUTHORITY); } 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 RFC 2308 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. */ dns_name_toregion(dns_rootname, &r); result = isc_buffer_copyregion(&buffer, &r); 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); /* * RFC 2308, section 5, says that negative answers without * SOAs should not be cached. */ ttl = 0; /* * Set trust. */ if ((message->flags & DNS_MESSAGEFLAG_AA) != 0 && message->counts[DNS_SECTION_ANSWER] == 0) { /* * The response has aa set and we haven't followed * any CNAME or DNAME chains. */ trust = dns_trust_authauthority; } else trust = dns_trust_additional; } /* * Now add it to the cache. */ INSIST(trust != 0xffff); isc_buffer_usedregion(&buffer, &r); rdata.data = r.base; rdata.length = r.length; rdata.rdclass = dns_db_class(cache); rdata.type = 0; rdata.flags = 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); RUNTIME_CHECK(dns_rdatalist_tordataset(&ncrdatalist, &ncrdataset) == ISC_R_SUCCESS); ncrdataset.trust = trust; if (message->rcode == dns_rcode_nxdomain) ncrdataset.attributes |= DNS_RDATASETATTR_NXDOMAIN; return (dns_db_addrdataset(cache, node, NULL, now, &ncrdataset, 0, addedrdataset)); }