1135446Strhodes/* 2234010Sdougb * Copyright (C) 2004-2012 Internet Systems Consortium, Inc. ("ISC") 3135446Strhodes * Copyright (C) 1999-2003 Internet Software Consortium. 4135446Strhodes * 5193149Sdougb * Permission to use, copy, modify, and/or distribute this software for any 6135446Strhodes * purpose with or without fee is hereby granted, provided that the above 7135446Strhodes * copyright notice and this permission notice appear in all copies. 8135446Strhodes * 9135446Strhodes * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 10135446Strhodes * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 11135446Strhodes * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 12135446Strhodes * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 13135446Strhodes * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 14135446Strhodes * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 15135446Strhodes * PERFORMANCE OF THIS SOFTWARE. 16135446Strhodes */ 17135446Strhodes 18234010Sdougb/* $Id$ */ 19135446Strhodes 20170222Sdougb/*! \file */ 21170222Sdougb 22135446Strhodes#include <config.h> 23135446Strhodes 24135446Strhodes#include <stdlib.h> 25135446Strhodes 26135446Strhodes#include <isc/buffer.h> 27135446Strhodes#include <isc/mem.h> 28135446Strhodes#include <isc/random.h> 29245163Serwin#include <isc/serial.h> 30135446Strhodes#include <isc/util.h> 31135446Strhodes 32135446Strhodes#include <dns/name.h> 33135446Strhodes#include <dns/ncache.h> 34135446Strhodes#include <dns/rdata.h> 35135446Strhodes#include <dns/rdataset.h> 36135446Strhodes#include <dns/compress.h> 37135446Strhodes 38222395Sdougbstatic const char *trustnames[] = { 39222395Sdougb "none", 40222395Sdougb "pending-additional", 41222395Sdougb "pending-answer", 42222395Sdougb "additional", 43222395Sdougb "glue", 44222395Sdougb "answer", 45222395Sdougb "authauthority", 46222395Sdougb "authanswer", 47222395Sdougb "secure", 48222395Sdougb "local" /* aka ultimate */ 49222395Sdougb}; 50222395Sdougb 51222395Sdougbconst char * 52222395Sdougbdns_trust_totext(dns_trust_t trust) { 53222395Sdougb if (trust >= sizeof(trustnames)/sizeof(*trustnames)) 54222395Sdougb return ("bad"); 55222395Sdougb return (trustnames[trust]); 56222395Sdougb} 57222395Sdougb 58135446Strhodesvoid 59135446Strhodesdns_rdataset_init(dns_rdataset_t *rdataset) { 60135446Strhodes 61135446Strhodes /* 62135446Strhodes * Make 'rdataset' a valid, disassociated rdataset. 63135446Strhodes */ 64135446Strhodes 65135446Strhodes REQUIRE(rdataset != NULL); 66135446Strhodes 67135446Strhodes rdataset->magic = DNS_RDATASET_MAGIC; 68135446Strhodes rdataset->methods = NULL; 69135446Strhodes ISC_LINK_INIT(rdataset, link); 70135446Strhodes rdataset->rdclass = 0; 71135446Strhodes rdataset->type = 0; 72135446Strhodes rdataset->ttl = 0; 73135446Strhodes rdataset->trust = 0; 74135446Strhodes rdataset->covers = 0; 75135446Strhodes rdataset->attributes = 0; 76135446Strhodes rdataset->count = ISC_UINT32_MAX; 77135446Strhodes rdataset->private1 = NULL; 78135446Strhodes rdataset->private2 = NULL; 79135446Strhodes rdataset->private3 = NULL; 80135446Strhodes rdataset->privateuint4 = 0; 81135446Strhodes rdataset->private5 = NULL; 82135446Strhodes rdataset->private6 = NULL; 83193149Sdougb rdataset->resign = 0; 84135446Strhodes} 85135446Strhodes 86135446Strhodesvoid 87135446Strhodesdns_rdataset_invalidate(dns_rdataset_t *rdataset) { 88135446Strhodes 89135446Strhodes /* 90135446Strhodes * Invalidate 'rdataset'. 91135446Strhodes */ 92135446Strhodes 93135446Strhodes REQUIRE(DNS_RDATASET_VALID(rdataset)); 94135446Strhodes REQUIRE(rdataset->methods == NULL); 95135446Strhodes 96135446Strhodes rdataset->magic = 0; 97135446Strhodes ISC_LINK_INIT(rdataset, link); 98135446Strhodes rdataset->rdclass = 0; 99135446Strhodes rdataset->type = 0; 100135446Strhodes rdataset->ttl = 0; 101135446Strhodes rdataset->trust = 0; 102135446Strhodes rdataset->covers = 0; 103135446Strhodes rdataset->attributes = 0; 104135446Strhodes rdataset->count = ISC_UINT32_MAX; 105135446Strhodes rdataset->private1 = NULL; 106135446Strhodes rdataset->private2 = NULL; 107135446Strhodes rdataset->private3 = NULL; 108135446Strhodes rdataset->privateuint4 = 0; 109135446Strhodes rdataset->private5 = NULL; 110135446Strhodes} 111135446Strhodes 112135446Strhodesvoid 113135446Strhodesdns_rdataset_disassociate(dns_rdataset_t *rdataset) { 114135446Strhodes 115135446Strhodes /* 116135446Strhodes * Disassociate 'rdataset' from its rdata, allowing it to be reused. 117135446Strhodes */ 118135446Strhodes 119135446Strhodes REQUIRE(DNS_RDATASET_VALID(rdataset)); 120135446Strhodes REQUIRE(rdataset->methods != NULL); 121135446Strhodes 122135446Strhodes (rdataset->methods->disassociate)(rdataset); 123135446Strhodes rdataset->methods = NULL; 124135446Strhodes ISC_LINK_INIT(rdataset, link); 125135446Strhodes rdataset->rdclass = 0; 126135446Strhodes rdataset->type = 0; 127135446Strhodes rdataset->ttl = 0; 128135446Strhodes rdataset->trust = 0; 129135446Strhodes rdataset->covers = 0; 130135446Strhodes rdataset->attributes = 0; 131135446Strhodes rdataset->count = ISC_UINT32_MAX; 132135446Strhodes rdataset->private1 = NULL; 133135446Strhodes rdataset->private2 = NULL; 134135446Strhodes rdataset->private3 = NULL; 135135446Strhodes rdataset->privateuint4 = 0; 136135446Strhodes rdataset->private5 = NULL; 137135446Strhodes rdataset->private6 = NULL; 138135446Strhodes} 139135446Strhodes 140135446Strhodesisc_boolean_t 141135446Strhodesdns_rdataset_isassociated(dns_rdataset_t *rdataset) { 142135446Strhodes /* 143135446Strhodes * Is 'rdataset' associated? 144135446Strhodes */ 145135446Strhodes 146135446Strhodes REQUIRE(DNS_RDATASET_VALID(rdataset)); 147135446Strhodes 148135446Strhodes if (rdataset->methods != NULL) 149135446Strhodes return (ISC_TRUE); 150135446Strhodes 151135446Strhodes return (ISC_FALSE); 152135446Strhodes} 153135446Strhodes 154135446Strhodesstatic void 155135446Strhodesquestion_disassociate(dns_rdataset_t *rdataset) { 156135446Strhodes UNUSED(rdataset); 157135446Strhodes} 158135446Strhodes 159135446Strhodesstatic isc_result_t 160135446Strhodesquestion_cursor(dns_rdataset_t *rdataset) { 161135446Strhodes UNUSED(rdataset); 162193149Sdougb 163135446Strhodes return (ISC_R_NOMORE); 164135446Strhodes} 165135446Strhodes 166135446Strhodesstatic void 167135446Strhodesquestion_current(dns_rdataset_t *rdataset, dns_rdata_t *rdata) { 168135446Strhodes /* 169135446Strhodes * This routine should never be called. 170135446Strhodes */ 171135446Strhodes UNUSED(rdataset); 172135446Strhodes UNUSED(rdata); 173193149Sdougb 174135446Strhodes REQUIRE(0); 175135446Strhodes} 176135446Strhodes 177135446Strhodesstatic void 178135446Strhodesquestion_clone(dns_rdataset_t *source, dns_rdataset_t *target) { 179135446Strhodes *target = *source; 180135446Strhodes} 181135446Strhodes 182135446Strhodesstatic unsigned int 183135446Strhodesquestion_count(dns_rdataset_t *rdataset) { 184135446Strhodes /* 185135446Strhodes * This routine should never be called. 186135446Strhodes */ 187135446Strhodes UNUSED(rdataset); 188135446Strhodes REQUIRE(0); 189135446Strhodes 190135446Strhodes return (0); 191135446Strhodes} 192135446Strhodes 193135446Strhodesstatic dns_rdatasetmethods_t question_methods = { 194135446Strhodes question_disassociate, 195135446Strhodes question_cursor, 196135446Strhodes question_cursor, 197135446Strhodes question_current, 198135446Strhodes question_clone, 199135446Strhodes question_count, 200135446Strhodes NULL, 201170222Sdougb NULL, 202170222Sdougb NULL, 203170222Sdougb NULL, 204193149Sdougb NULL, 205193149Sdougb NULL, 206205292Sdougb NULL, 207205292Sdougb NULL, 208135446Strhodes NULL 209135446Strhodes}; 210135446Strhodes 211135446Strhodesvoid 212135446Strhodesdns_rdataset_makequestion(dns_rdataset_t *rdataset, dns_rdataclass_t rdclass, 213135446Strhodes dns_rdatatype_t type) 214135446Strhodes{ 215135446Strhodes 216135446Strhodes /* 217135446Strhodes * Make 'rdataset' a valid, associated, question rdataset, with a 218135446Strhodes * question class of 'rdclass' and type 'type'. 219135446Strhodes */ 220135446Strhodes 221135446Strhodes REQUIRE(DNS_RDATASET_VALID(rdataset)); 222135446Strhodes REQUIRE(rdataset->methods == NULL); 223135446Strhodes 224135446Strhodes rdataset->methods = &question_methods; 225135446Strhodes rdataset->rdclass = rdclass; 226135446Strhodes rdataset->type = type; 227135446Strhodes rdataset->attributes |= DNS_RDATASETATTR_QUESTION; 228135446Strhodes} 229135446Strhodes 230135446Strhodesunsigned int 231135446Strhodesdns_rdataset_count(dns_rdataset_t *rdataset) { 232135446Strhodes 233135446Strhodes /* 234135446Strhodes * Return the number of records in 'rdataset'. 235135446Strhodes */ 236135446Strhodes 237135446Strhodes REQUIRE(DNS_RDATASET_VALID(rdataset)); 238135446Strhodes REQUIRE(rdataset->methods != NULL); 239135446Strhodes 240135446Strhodes return ((rdataset->methods->count)(rdataset)); 241135446Strhodes} 242135446Strhodes 243135446Strhodesvoid 244135446Strhodesdns_rdataset_clone(dns_rdataset_t *source, dns_rdataset_t *target) { 245135446Strhodes 246135446Strhodes /* 247135446Strhodes * Make 'target' refer to the same rdataset as 'source'. 248135446Strhodes */ 249135446Strhodes 250135446Strhodes REQUIRE(DNS_RDATASET_VALID(source)); 251135446Strhodes REQUIRE(source->methods != NULL); 252135446Strhodes REQUIRE(DNS_RDATASET_VALID(target)); 253135446Strhodes REQUIRE(target->methods == NULL); 254135446Strhodes 255135446Strhodes (source->methods->clone)(source, target); 256135446Strhodes} 257135446Strhodes 258135446Strhodesisc_result_t 259135446Strhodesdns_rdataset_first(dns_rdataset_t *rdataset) { 260135446Strhodes 261135446Strhodes /* 262135446Strhodes * Move the rdata cursor to the first rdata in the rdataset (if any). 263135446Strhodes */ 264135446Strhodes 265135446Strhodes REQUIRE(DNS_RDATASET_VALID(rdataset)); 266135446Strhodes REQUIRE(rdataset->methods != NULL); 267135446Strhodes 268135446Strhodes return ((rdataset->methods->first)(rdataset)); 269135446Strhodes} 270135446Strhodes 271135446Strhodesisc_result_t 272135446Strhodesdns_rdataset_next(dns_rdataset_t *rdataset) { 273135446Strhodes 274135446Strhodes /* 275135446Strhodes * Move the rdata cursor to the next rdata in the rdataset (if any). 276135446Strhodes */ 277135446Strhodes 278135446Strhodes REQUIRE(DNS_RDATASET_VALID(rdataset)); 279135446Strhodes REQUIRE(rdataset->methods != NULL); 280135446Strhodes 281135446Strhodes return ((rdataset->methods->next)(rdataset)); 282135446Strhodes} 283135446Strhodes 284135446Strhodesvoid 285135446Strhodesdns_rdataset_current(dns_rdataset_t *rdataset, dns_rdata_t *rdata) { 286135446Strhodes 287135446Strhodes /* 288135446Strhodes * Make 'rdata' refer to the current rdata. 289135446Strhodes */ 290135446Strhodes 291135446Strhodes REQUIRE(DNS_RDATASET_VALID(rdataset)); 292135446Strhodes REQUIRE(rdataset->methods != NULL); 293135446Strhodes 294135446Strhodes (rdataset->methods->current)(rdataset, rdata); 295135446Strhodes} 296135446Strhodes 297135446Strhodes#define MAX_SHUFFLE 32 298135446Strhodes#define WANT_FIXED(r) (((r)->attributes & DNS_RDATASETATTR_FIXEDORDER) != 0) 299135446Strhodes#define WANT_RANDOM(r) (((r)->attributes & DNS_RDATASETATTR_RANDOMIZE) != 0) 300135446Strhodes 301135446Strhodesstruct towire_sort { 302135446Strhodes int key; 303135446Strhodes dns_rdata_t *rdata; 304135446Strhodes}; 305135446Strhodes 306135446Strhodesstatic int 307135446Strhodestowire_compare(const void *av, const void *bv) { 308135446Strhodes const struct towire_sort *a = (const struct towire_sort *) av; 309135446Strhodes const struct towire_sort *b = (const struct towire_sort *) bv; 310135446Strhodes return (a->key - b->key); 311135446Strhodes} 312135446Strhodes 313135446Strhodesstatic isc_result_t 314165071Sdougbtowiresorted(dns_rdataset_t *rdataset, const dns_name_t *owner_name, 315135446Strhodes dns_compress_t *cctx, isc_buffer_t *target, 316165071Sdougb dns_rdatasetorderfunc_t order, const void *order_arg, 317135446Strhodes isc_boolean_t partial, unsigned int options, 318135446Strhodes unsigned int *countp, void **state) 319135446Strhodes{ 320135446Strhodes dns_rdata_t rdata = DNS_RDATA_INIT; 321135446Strhodes isc_region_t r; 322135446Strhodes isc_result_t result; 323225361Sdougb unsigned int i, count = 0, added, choice; 324135446Strhodes isc_buffer_t savedbuffer, rdlen, rrbuffer; 325135446Strhodes unsigned int headlen; 326135446Strhodes isc_boolean_t question = ISC_FALSE; 327135446Strhodes isc_boolean_t shuffle = ISC_FALSE; 328135446Strhodes dns_rdata_t *shuffled = NULL, shuffled_fixed[MAX_SHUFFLE]; 329135446Strhodes struct towire_sort *sorted = NULL, sorted_fixed[MAX_SHUFFLE]; 330135446Strhodes 331135446Strhodes UNUSED(state); 332135446Strhodes 333135446Strhodes /* 334135446Strhodes * Convert 'rdataset' to wire format, compressing names as specified 335135446Strhodes * in cctx, and storing the result in 'target'. 336135446Strhodes */ 337135446Strhodes 338135446Strhodes REQUIRE(DNS_RDATASET_VALID(rdataset)); 339135446Strhodes REQUIRE(countp != NULL); 340135446Strhodes REQUIRE((order == NULL) == (order_arg == NULL)); 341135446Strhodes REQUIRE(cctx != NULL && cctx->mctx != NULL); 342135446Strhodes 343135446Strhodes if ((rdataset->attributes & DNS_RDATASETATTR_QUESTION) != 0) { 344135446Strhodes question = ISC_TRUE; 345135446Strhodes count = 1; 346135446Strhodes result = dns_rdataset_first(rdataset); 347135446Strhodes INSIST(result == ISC_R_NOMORE); 348223812Sdougb } else if ((rdataset->attributes & DNS_RDATASETATTR_NEGATIVE) != 0) { 349135446Strhodes /* 350135446Strhodes * This is a negative caching rdataset. 351135446Strhodes */ 352135446Strhodes unsigned int ncache_opts = 0; 353135446Strhodes if ((options & DNS_RDATASETTOWIRE_OMITDNSSEC) != 0) 354135446Strhodes ncache_opts |= DNS_NCACHETOWIRE_OMITDNSSEC; 355135446Strhodes return (dns_ncache_towire(rdataset, cctx, target, ncache_opts, 356135446Strhodes countp)); 357135446Strhodes } else { 358135446Strhodes count = (rdataset->methods->count)(rdataset); 359135446Strhodes result = dns_rdataset_first(rdataset); 360135446Strhodes if (result == ISC_R_NOMORE) 361135446Strhodes return (ISC_R_SUCCESS); 362135446Strhodes if (result != ISC_R_SUCCESS) 363135446Strhodes return (result); 364135446Strhodes } 365135446Strhodes 366135446Strhodes /* 367193149Sdougb * Do we want to shuffle this answer? 368135446Strhodes */ 369135446Strhodes if (!question && count > 1 && 370135446Strhodes (!WANT_FIXED(rdataset) || order != NULL) && 371135446Strhodes rdataset->type != dns_rdatatype_rrsig) 372135446Strhodes shuffle = ISC_TRUE; 373135446Strhodes 374135446Strhodes if (shuffle && count > MAX_SHUFFLE) { 375135446Strhodes shuffled = isc_mem_get(cctx->mctx, count * sizeof(*shuffled)); 376135446Strhodes sorted = isc_mem_get(cctx->mctx, count * sizeof(*sorted)); 377135446Strhodes if (shuffled == NULL || sorted == NULL) 378135446Strhodes shuffle = ISC_FALSE; 379135446Strhodes } else { 380135446Strhodes shuffled = shuffled_fixed; 381135446Strhodes sorted = sorted_fixed; 382135446Strhodes } 383135446Strhodes 384135446Strhodes if (shuffle) { 385135446Strhodes /* 386135446Strhodes * First we get handles to all of the rdata. 387135446Strhodes */ 388135446Strhodes i = 0; 389135446Strhodes do { 390135446Strhodes INSIST(i < count); 391135446Strhodes dns_rdata_init(&shuffled[i]); 392135446Strhodes dns_rdataset_current(rdataset, &shuffled[i]); 393135446Strhodes i++; 394135446Strhodes result = dns_rdataset_next(rdataset); 395135446Strhodes } while (result == ISC_R_SUCCESS); 396135446Strhodes if (result != ISC_R_NOMORE) 397135446Strhodes goto cleanup; 398135446Strhodes INSIST(i == count); 399135446Strhodes 400135446Strhodes /* 401135446Strhodes * Now we shuffle. 402135446Strhodes */ 403135446Strhodes if (WANT_FIXED(rdataset)) { 404135446Strhodes /* 405135446Strhodes * 'Fixed' order. 406135446Strhodes */ 407135446Strhodes INSIST(order != NULL); 408135446Strhodes for (i = 0; i < count; i++) { 409135446Strhodes sorted[i].key = (*order)(&shuffled[i], 410135446Strhodes order_arg); 411135446Strhodes sorted[i].rdata = &shuffled[i]; 412135446Strhodes } 413135446Strhodes } else if (WANT_RANDOM(rdataset)) { 414135446Strhodes /* 415135446Strhodes * 'Random' order. 416135446Strhodes */ 417135446Strhodes for (i = 0; i < count; i++) { 418135446Strhodes dns_rdata_t rdata; 419135446Strhodes isc_uint32_t val; 420135446Strhodes 421135446Strhodes isc_random_get(&val); 422135446Strhodes choice = i + (val % (count - i)); 423135446Strhodes rdata = shuffled[i]; 424135446Strhodes shuffled[i] = shuffled[choice]; 425135446Strhodes shuffled[choice] = rdata; 426135446Strhodes if (order != NULL) 427135446Strhodes sorted[i].key = (*order)(&shuffled[i], 428135446Strhodes order_arg); 429135446Strhodes else 430135446Strhodes sorted[i].key = 0; /* Unused */ 431135446Strhodes sorted[i].rdata = &shuffled[i]; 432135446Strhodes } 433135446Strhodes } else { 434135446Strhodes /* 435135446Strhodes * "Cyclic" order. 436135446Strhodes */ 437135446Strhodes isc_uint32_t val; 438135446Strhodes unsigned int j; 439135446Strhodes 440135446Strhodes val = rdataset->count; 441135446Strhodes if (val == ISC_UINT32_MAX) 442135446Strhodes isc_random_get(&val); 443135446Strhodes j = val % count; 444135446Strhodes for (i = 0; i < count; i++) { 445135446Strhodes if (order != NULL) 446234010Sdougb sorted[i].key = (*order)(&shuffled[j], 447135446Strhodes order_arg); 448135446Strhodes else 449234010Sdougb sorted[i].key = 0; /* Unused */ 450234010Sdougb sorted[i].rdata = &shuffled[j]; 451135446Strhodes j++; 452135446Strhodes if (j == count) 453135446Strhodes j = 0; /* Wrap around. */ 454135446Strhodes } 455135446Strhodes } 456135446Strhodes 457135446Strhodes /* 458135446Strhodes * Sorted order. 459135446Strhodes */ 460135446Strhodes if (order != NULL) 461135446Strhodes qsort(sorted, count, sizeof(sorted[0]), 462135446Strhodes towire_compare); 463135446Strhodes } 464135446Strhodes 465135446Strhodes savedbuffer = *target; 466135446Strhodes i = 0; 467135446Strhodes added = 0; 468135446Strhodes 469135446Strhodes do { 470135446Strhodes /* 471135446Strhodes * Copy out the name, type, class, ttl. 472135446Strhodes */ 473193149Sdougb 474135446Strhodes rrbuffer = *target; 475135446Strhodes dns_compress_setmethods(cctx, DNS_COMPRESS_GLOBAL14); 476135446Strhodes result = dns_name_towire(owner_name, cctx, target); 477135446Strhodes if (result != ISC_R_SUCCESS) 478135446Strhodes goto rollback; 479135446Strhodes headlen = sizeof(dns_rdataclass_t) + sizeof(dns_rdatatype_t); 480135446Strhodes if (!question) 481135446Strhodes headlen += sizeof(dns_ttl_t) 482135446Strhodes + 2; /* XXX 2 for rdata len */ 483135446Strhodes isc_buffer_availableregion(target, &r); 484135446Strhodes if (r.length < headlen) { 485135446Strhodes result = ISC_R_NOSPACE; 486135446Strhodes goto rollback; 487135446Strhodes } 488135446Strhodes isc_buffer_putuint16(target, rdataset->type); 489135446Strhodes isc_buffer_putuint16(target, rdataset->rdclass); 490135446Strhodes if (!question) { 491135446Strhodes isc_buffer_putuint32(target, rdataset->ttl); 492135446Strhodes 493135446Strhodes /* 494135446Strhodes * Save space for rdlen. 495135446Strhodes */ 496135446Strhodes rdlen = *target; 497135446Strhodes isc_buffer_add(target, 2); 498135446Strhodes 499135446Strhodes /* 500135446Strhodes * Copy out the rdata 501135446Strhodes */ 502135446Strhodes if (shuffle) 503135446Strhodes rdata = *(sorted[i].rdata); 504135446Strhodes else { 505135446Strhodes dns_rdata_reset(&rdata); 506135446Strhodes dns_rdataset_current(rdataset, &rdata); 507135446Strhodes } 508135446Strhodes result = dns_rdata_towire(&rdata, cctx, target); 509135446Strhodes if (result != ISC_R_SUCCESS) 510135446Strhodes goto rollback; 511135446Strhodes INSIST((target->used >= rdlen.used + 2) && 512135446Strhodes (target->used - rdlen.used - 2 < 65536)); 513135446Strhodes isc_buffer_putuint16(&rdlen, 514135446Strhodes (isc_uint16_t)(target->used - 515135446Strhodes rdlen.used - 2)); 516135446Strhodes added++; 517135446Strhodes } 518135446Strhodes 519135446Strhodes if (shuffle) { 520135446Strhodes i++; 521135446Strhodes if (i == count) 522135446Strhodes result = ISC_R_NOMORE; 523135446Strhodes else 524135446Strhodes result = ISC_R_SUCCESS; 525135446Strhodes } else { 526135446Strhodes result = dns_rdataset_next(rdataset); 527135446Strhodes } 528135446Strhodes } while (result == ISC_R_SUCCESS); 529135446Strhodes 530135446Strhodes if (result != ISC_R_NOMORE) 531135446Strhodes goto rollback; 532135446Strhodes 533135446Strhodes *countp += count; 534135446Strhodes 535135446Strhodes result = ISC_R_SUCCESS; 536135446Strhodes goto cleanup; 537135446Strhodes 538135446Strhodes rollback: 539135446Strhodes if (partial && result == ISC_R_NOSPACE) { 540135446Strhodes INSIST(rrbuffer.used < 65536); 541135446Strhodes dns_compress_rollback(cctx, (isc_uint16_t)rrbuffer.used); 542135446Strhodes *countp += added; 543135446Strhodes *target = rrbuffer; 544135446Strhodes goto cleanup; 545135446Strhodes } 546135446Strhodes INSIST(savedbuffer.used < 65536); 547135446Strhodes dns_compress_rollback(cctx, (isc_uint16_t)savedbuffer.used); 548135446Strhodes *countp = 0; 549135446Strhodes *target = savedbuffer; 550135446Strhodes 551135446Strhodes cleanup: 552135446Strhodes if (sorted != NULL && sorted != sorted_fixed) 553135446Strhodes isc_mem_put(cctx->mctx, sorted, count * sizeof(*sorted)); 554135446Strhodes if (shuffled != NULL && shuffled != shuffled_fixed) 555135446Strhodes isc_mem_put(cctx->mctx, shuffled, count * sizeof(*shuffled)); 556135446Strhodes return (result); 557135446Strhodes} 558135446Strhodes 559135446Strhodesisc_result_t 560135446Strhodesdns_rdataset_towiresorted(dns_rdataset_t *rdataset, 561165071Sdougb const dns_name_t *owner_name, 562135446Strhodes dns_compress_t *cctx, 563135446Strhodes isc_buffer_t *target, 564135446Strhodes dns_rdatasetorderfunc_t order, 565165071Sdougb const void *order_arg, 566135446Strhodes unsigned int options, 567135446Strhodes unsigned int *countp) 568135446Strhodes{ 569135446Strhodes return (towiresorted(rdataset, owner_name, cctx, target, 570135446Strhodes order, order_arg, ISC_FALSE, options, 571135446Strhodes countp, NULL)); 572135446Strhodes} 573135446Strhodes 574135446Strhodesisc_result_t 575135446Strhodesdns_rdataset_towirepartial(dns_rdataset_t *rdataset, 576165071Sdougb const dns_name_t *owner_name, 577135446Strhodes dns_compress_t *cctx, 578135446Strhodes isc_buffer_t *target, 579135446Strhodes dns_rdatasetorderfunc_t order, 580165071Sdougb const void *order_arg, 581135446Strhodes unsigned int options, 582135446Strhodes unsigned int *countp, 583135446Strhodes void **state) 584135446Strhodes{ 585135446Strhodes REQUIRE(state == NULL); /* XXX remove when implemented */ 586135446Strhodes return (towiresorted(rdataset, owner_name, cctx, target, 587135446Strhodes order, order_arg, ISC_TRUE, options, 588135446Strhodes countp, state)); 589135446Strhodes} 590135446Strhodes 591135446Strhodesisc_result_t 592135446Strhodesdns_rdataset_towire(dns_rdataset_t *rdataset, 593135446Strhodes dns_name_t *owner_name, 594135446Strhodes dns_compress_t *cctx, 595135446Strhodes isc_buffer_t *target, 596135446Strhodes unsigned int options, 597135446Strhodes unsigned int *countp) 598135446Strhodes{ 599135446Strhodes return (towiresorted(rdataset, owner_name, cctx, target, 600135446Strhodes NULL, NULL, ISC_FALSE, options, countp, NULL)); 601135446Strhodes} 602135446Strhodes 603135446Strhodesisc_result_t 604135446Strhodesdns_rdataset_additionaldata(dns_rdataset_t *rdataset, 605135446Strhodes dns_additionaldatafunc_t add, void *arg) 606135446Strhodes{ 607135446Strhodes dns_rdata_t rdata = DNS_RDATA_INIT; 608135446Strhodes isc_result_t result; 609135446Strhodes 610135446Strhodes /* 611135446Strhodes * For each rdata in rdataset, call 'add' for each name and type in the 612135446Strhodes * rdata which is subject to additional section processing. 613135446Strhodes */ 614135446Strhodes 615135446Strhodes REQUIRE(DNS_RDATASET_VALID(rdataset)); 616135446Strhodes REQUIRE((rdataset->attributes & DNS_RDATASETATTR_QUESTION) == 0); 617135446Strhodes 618135446Strhodes result = dns_rdataset_first(rdataset); 619135446Strhodes if (result != ISC_R_SUCCESS) 620135446Strhodes return (result); 621135446Strhodes 622135446Strhodes do { 623135446Strhodes dns_rdataset_current(rdataset, &rdata); 624135446Strhodes result = dns_rdata_additionaldata(&rdata, add, arg); 625135446Strhodes if (result == ISC_R_SUCCESS) 626135446Strhodes result = dns_rdataset_next(rdataset); 627135446Strhodes dns_rdata_reset(&rdata); 628135446Strhodes } while (result == ISC_R_SUCCESS); 629135446Strhodes 630135446Strhodes if (result != ISC_R_NOMORE) 631135446Strhodes return (result); 632135446Strhodes 633135446Strhodes return (ISC_R_SUCCESS); 634135446Strhodes} 635135446Strhodes 636135446Strhodesisc_result_t 637135446Strhodesdns_rdataset_addnoqname(dns_rdataset_t *rdataset, dns_name_t *name) { 638135446Strhodes 639135446Strhodes REQUIRE(DNS_RDATASET_VALID(rdataset)); 640135446Strhodes REQUIRE(rdataset->methods != NULL); 641135446Strhodes if (rdataset->methods->addnoqname == NULL) 642135446Strhodes return (ISC_R_NOTIMPLEMENTED); 643135446Strhodes return((rdataset->methods->addnoqname)(rdataset, name)); 644135446Strhodes} 645135446Strhodes 646135446Strhodesisc_result_t 647135446Strhodesdns_rdataset_getnoqname(dns_rdataset_t *rdataset, dns_name_t *name, 648193149Sdougb dns_rdataset_t *neg, dns_rdataset_t *negsig) 649135446Strhodes{ 650135446Strhodes REQUIRE(DNS_RDATASET_VALID(rdataset)); 651135446Strhodes REQUIRE(rdataset->methods != NULL); 652135446Strhodes 653135446Strhodes if (rdataset->methods->getnoqname == NULL) 654135446Strhodes return (ISC_R_NOTIMPLEMENTED); 655193149Sdougb return((rdataset->methods->getnoqname)(rdataset, name, neg, negsig)); 656135446Strhodes} 657170222Sdougb 658193149Sdougbisc_result_t 659193149Sdougbdns_rdataset_addclosest(dns_rdataset_t *rdataset, dns_name_t *name) { 660193149Sdougb 661193149Sdougb REQUIRE(DNS_RDATASET_VALID(rdataset)); 662193149Sdougb REQUIRE(rdataset->methods != NULL); 663193149Sdougb if (rdataset->methods->addclosest == NULL) 664193149Sdougb return (ISC_R_NOTIMPLEMENTED); 665193149Sdougb return((rdataset->methods->addclosest)(rdataset, name)); 666193149Sdougb} 667193149Sdougb 668193149Sdougbisc_result_t 669193149Sdougbdns_rdataset_getclosest(dns_rdataset_t *rdataset, dns_name_t *name, 670193149Sdougb dns_rdataset_t *neg, dns_rdataset_t *negsig) 671193149Sdougb{ 672193149Sdougb REQUIRE(DNS_RDATASET_VALID(rdataset)); 673193149Sdougb REQUIRE(rdataset->methods != NULL); 674193149Sdougb 675193149Sdougb if (rdataset->methods->getclosest == NULL) 676193149Sdougb return (ISC_R_NOTIMPLEMENTED); 677193149Sdougb return((rdataset->methods->getclosest)(rdataset, name, neg, negsig)); 678193149Sdougb} 679193149Sdougb 680170222Sdougb/* 681170222Sdougb * Additional cache stuff 682170222Sdougb */ 683170222Sdougbisc_result_t 684170222Sdougbdns_rdataset_getadditional(dns_rdataset_t *rdataset, 685170222Sdougb dns_rdatasetadditional_t type, 686170222Sdougb dns_rdatatype_t qtype, 687170222Sdougb dns_acache_t *acache, 688170222Sdougb dns_zone_t **zonep, 689170222Sdougb dns_db_t **dbp, 690170222Sdougb dns_dbversion_t **versionp, 691170222Sdougb dns_dbnode_t **nodep, 692170222Sdougb dns_name_t *fname, 693170222Sdougb dns_message_t *msg, 694170222Sdougb isc_stdtime_t now) 695170222Sdougb{ 696170222Sdougb REQUIRE(DNS_RDATASET_VALID(rdataset)); 697170222Sdougb REQUIRE(rdataset->methods != NULL); 698170222Sdougb REQUIRE(zonep == NULL || *zonep == NULL); 699170222Sdougb REQUIRE(dbp != NULL && *dbp == NULL); 700170222Sdougb REQUIRE(versionp != NULL && *versionp == NULL); 701170222Sdougb REQUIRE(nodep != NULL && *nodep == NULL); 702170222Sdougb REQUIRE(fname != NULL); 703170222Sdougb REQUIRE(msg != NULL); 704170222Sdougb 705170222Sdougb if (acache != NULL && rdataset->methods->getadditional != NULL) { 706170222Sdougb return ((rdataset->methods->getadditional)(rdataset, type, 707170222Sdougb qtype, acache, 708170222Sdougb zonep, dbp, 709170222Sdougb versionp, nodep, 710170222Sdougb fname, msg, now)); 711170222Sdougb } 712170222Sdougb 713170222Sdougb return (ISC_R_FAILURE); 714170222Sdougb} 715170222Sdougb 716170222Sdougbisc_result_t 717170222Sdougbdns_rdataset_setadditional(dns_rdataset_t *rdataset, 718170222Sdougb dns_rdatasetadditional_t type, 719170222Sdougb dns_rdatatype_t qtype, 720170222Sdougb dns_acache_t *acache, 721170222Sdougb dns_zone_t *zone, 722170222Sdougb dns_db_t *db, 723170222Sdougb dns_dbversion_t *version, 724170222Sdougb dns_dbnode_t *node, 725170222Sdougb dns_name_t *fname) 726170222Sdougb{ 727170222Sdougb REQUIRE(DNS_RDATASET_VALID(rdataset)); 728170222Sdougb REQUIRE(rdataset->methods != NULL); 729170222Sdougb 730170222Sdougb if (acache != NULL && rdataset->methods->setadditional != NULL) { 731170222Sdougb return ((rdataset->methods->setadditional)(rdataset, type, 732170222Sdougb qtype, acache, zone, 733170222Sdougb db, version, 734170222Sdougb node, fname)); 735170222Sdougb } 736170222Sdougb 737170222Sdougb return (ISC_R_FAILURE); 738170222Sdougb} 739170222Sdougb 740170222Sdougbisc_result_t 741170222Sdougbdns_rdataset_putadditional(dns_acache_t *acache, 742170222Sdougb dns_rdataset_t *rdataset, 743170222Sdougb dns_rdatasetadditional_t type, 744170222Sdougb dns_rdatatype_t qtype) 745170222Sdougb{ 746170222Sdougb REQUIRE(DNS_RDATASET_VALID(rdataset)); 747170222Sdougb REQUIRE(rdataset->methods != NULL); 748170222Sdougb 749170222Sdougb if (acache != NULL && rdataset->methods->putadditional != NULL) { 750170222Sdougb return ((rdataset->methods->putadditional)(acache, rdataset, 751170222Sdougb type, qtype)); 752170222Sdougb } 753170222Sdougb 754170222Sdougb return (ISC_R_FAILURE); 755170222Sdougb} 756170222Sdougb 757205292Sdougbvoid 758205292Sdougbdns_rdataset_settrust(dns_rdataset_t *rdataset, dns_trust_t trust) { 759205292Sdougb REQUIRE(DNS_RDATASET_VALID(rdataset)); 760205292Sdougb REQUIRE(rdataset->methods != NULL); 761205292Sdougb 762205292Sdougb if (rdataset->methods->settrust != NULL) 763205292Sdougb (rdataset->methods->settrust)(rdataset, trust); 764205292Sdougb else 765205292Sdougb rdataset->trust = trust; 766205292Sdougb} 767205292Sdougb 768205292Sdougbvoid 769205292Sdougbdns_rdataset_expire(dns_rdataset_t *rdataset) { 770205292Sdougb REQUIRE(DNS_RDATASET_VALID(rdataset)); 771205292Sdougb REQUIRE(rdataset->methods != NULL); 772205292Sdougb 773205292Sdougb if (rdataset->methods->expire != NULL) 774205292Sdougb (rdataset->methods->expire)(rdataset); 775205292Sdougb} 776245163Serwin 777245163Serwinvoid 778245163Serwindns_rdataset_trimttl(dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset, 779245163Serwin dns_rdata_rrsig_t *rrsig, isc_stdtime_t now, 780245163Serwin isc_boolean_t acceptexpired) 781245163Serwin{ 782245163Serwin isc_uint32_t ttl = 0; 783245163Serwin 784245163Serwin REQUIRE(DNS_RDATASET_VALID(rdataset)); 785245163Serwin REQUIRE(DNS_RDATASET_VALID(sigrdataset)); 786245163Serwin REQUIRE(rrsig != NULL); 787245163Serwin 788245163Serwin /* 789245163Serwin * If we accept expired RRsets keep them for no more than 120 seconds. 790245163Serwin */ 791245163Serwin if (acceptexpired && 792245163Serwin (isc_serial_le(rrsig->timeexpire, ((now + 120) & 0xffffffff)) || 793245163Serwin isc_serial_le(rrsig->timeexpire, now))) 794245163Serwin ttl = 120; 795245163Serwin else if (isc_serial_ge(rrsig->timeexpire, now)) 796245163Serwin ttl = rrsig->timeexpire - now; 797245163Serwin 798245163Serwin ttl = ISC_MIN(ISC_MIN(rdataset->ttl, sigrdataset->ttl), 799245163Serwin ISC_MIN(rrsig->originalttl, ttl)); 800245163Serwin rdataset->ttl = ttl; 801245163Serwin sigrdataset->ttl = ttl; 802245163Serwin} 803