1135446Strhodes/* 2224092Sdougb * Copyright (C) 2004, 2007-2009, 2011 Internet Systems Consortium, Inc. ("ISC") 3135446Strhodes * Copyright (C) 2003 Internet Software Consortium. 4135446Strhodes * 5186462Sdougb * 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: nsec_47.c,v 1.15 2011/01/13 04:59:26 tbox Exp $ */ 19135446Strhodes 20135446Strhodes/* reviewed: Wed Mar 15 18:21:15 PST 2000 by brister */ 21135446Strhodes 22186462Sdougb/* RFC 3845 */ 23135446Strhodes 24135446Strhodes#ifndef RDATA_GENERIC_NSEC_47_C 25135446Strhodes#define RDATA_GENERIC_NSEC_47_C 26135446Strhodes 27135446Strhodes/* 28135446Strhodes * The attributes do not include DNS_RDATATYPEATTR_SINGLETON 29135446Strhodes * because we must be able to handle a parent/child NSEC pair. 30135446Strhodes */ 31135446Strhodes#define RRTYPE_NSEC_ATTRIBUTES (DNS_RDATATYPEATTR_DNSSEC) 32135446Strhodes 33135446Strhodesstatic inline isc_result_t 34135446Strhodesfromtext_nsec(ARGS_FROMTEXT) { 35135446Strhodes isc_token_t token; 36135446Strhodes dns_name_t name; 37135446Strhodes isc_buffer_t buffer; 38135446Strhodes unsigned char bm[8*1024]; /* 64k bits */ 39135446Strhodes dns_rdatatype_t covered; 40135446Strhodes int octet; 41135446Strhodes int window; 42135446Strhodes 43135446Strhodes REQUIRE(type == 47); 44135446Strhodes 45135446Strhodes UNUSED(type); 46135446Strhodes UNUSED(rdclass); 47135446Strhodes UNUSED(callbacks); 48135446Strhodes 49135446Strhodes /* 50135446Strhodes * Next domain. 51135446Strhodes */ 52135446Strhodes RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string, 53135446Strhodes ISC_FALSE)); 54135446Strhodes dns_name_init(&name, NULL); 55135446Strhodes buffer_fromregion(&buffer, &token.value.as_region); 56135446Strhodes origin = (origin != NULL) ? origin : dns_rootname; 57135446Strhodes RETTOK(dns_name_fromtext(&name, &buffer, origin, options, target)); 58135446Strhodes 59135446Strhodes memset(bm, 0, sizeof(bm)); 60135446Strhodes do { 61135446Strhodes RETERR(isc_lex_getmastertoken(lexer, &token, 62135446Strhodes isc_tokentype_string, ISC_TRUE)); 63135446Strhodes if (token.type != isc_tokentype_string) 64135446Strhodes break; 65135446Strhodes RETTOK(dns_rdatatype_fromtext(&covered, 66135446Strhodes &token.value.as_textregion)); 67135446Strhodes bm[covered/8] |= (0x80>>(covered%8)); 68135446Strhodes } while (1); 69135446Strhodes isc_lex_ungettoken(lexer, &token); 70135446Strhodes for (window = 0; window < 256 ; window++) { 71135446Strhodes /* 72135446Strhodes * Find if we have a type in this window. 73135446Strhodes */ 74135446Strhodes for (octet = 31; octet >= 0; octet--) 75135446Strhodes if (bm[window * 32 + octet] != 0) 76135446Strhodes break; 77135446Strhodes if (octet < 0) 78135446Strhodes continue; 79135446Strhodes RETERR(uint8_tobuffer(window, target)); 80135446Strhodes RETERR(uint8_tobuffer(octet + 1, target)); 81135446Strhodes RETERR(mem_tobuffer(target, &bm[window * 32], octet + 1)); 82135446Strhodes } 83135446Strhodes return (ISC_R_SUCCESS); 84135446Strhodes} 85135446Strhodes 86135446Strhodesstatic inline isc_result_t 87135446Strhodestotext_nsec(ARGS_TOTEXT) { 88135446Strhodes isc_region_t sr; 89135446Strhodes unsigned int i, j, k; 90135446Strhodes dns_name_t name; 91135446Strhodes unsigned int window, len; 92135446Strhodes 93135446Strhodes REQUIRE(rdata->type == 47); 94135446Strhodes REQUIRE(rdata->length != 0); 95135446Strhodes 96218384Sdougb UNUSED(tctx); 97218384Sdougb 98135446Strhodes dns_name_init(&name, NULL); 99135446Strhodes dns_rdata_toregion(rdata, &sr); 100135446Strhodes dns_name_fromregion(&name, &sr); 101135446Strhodes isc_region_consume(&sr, name_length(&name)); 102218384Sdougb RETERR(dns_name_totext(&name, ISC_FALSE, target)); 103135446Strhodes 104135446Strhodes 105135446Strhodes for (i = 0; i < sr.length; i += len) { 106135446Strhodes INSIST(i + 2 <= sr.length); 107135446Strhodes window = sr.base[i]; 108135446Strhodes len = sr.base[i + 1]; 109135446Strhodes INSIST(len > 0 && len <= 32); 110135446Strhodes i += 2; 111135446Strhodes INSIST(i + len <= sr.length); 112135446Strhodes for (j = 0; j < len; j++) { 113135446Strhodes dns_rdatatype_t t; 114135446Strhodes if (sr.base[i + j] == 0) 115135446Strhodes continue; 116135446Strhodes for (k = 0; k < 8; k++) { 117135446Strhodes if ((sr.base[i + j] & (0x80 >> k)) == 0) 118135446Strhodes continue; 119135446Strhodes t = window * 256 + j * 8 + k; 120135446Strhodes RETERR(str_totext(" ", target)); 121135446Strhodes if (dns_rdatatype_isknown(t)) { 122135446Strhodes RETERR(dns_rdatatype_totext(t, target)); 123135446Strhodes } else { 124135446Strhodes char buf[sizeof("TYPE65535")]; 125135446Strhodes sprintf(buf, "TYPE%u", t); 126135446Strhodes RETERR(str_totext(buf, target)); 127135446Strhodes } 128135446Strhodes } 129135446Strhodes } 130135446Strhodes } 131135446Strhodes return (ISC_R_SUCCESS); 132135446Strhodes} 133135446Strhodes 134135446Strhodesstatic /* inline */ isc_result_t 135135446Strhodesfromwire_nsec(ARGS_FROMWIRE) { 136135446Strhodes isc_region_t sr; 137135446Strhodes dns_name_t name; 138135446Strhodes unsigned int window, lastwindow = 0; 139135446Strhodes unsigned int len; 140135446Strhodes isc_boolean_t first = ISC_TRUE; 141135446Strhodes unsigned int i; 142135446Strhodes 143135446Strhodes REQUIRE(type == 47); 144135446Strhodes 145135446Strhodes UNUSED(type); 146135446Strhodes UNUSED(rdclass); 147135446Strhodes 148135446Strhodes dns_decompress_setmethods(dctx, DNS_COMPRESS_NONE); 149135446Strhodes 150135446Strhodes dns_name_init(&name, NULL); 151135446Strhodes RETERR(dns_name_fromwire(&name, source, dctx, options, target)); 152135446Strhodes 153135446Strhodes isc_buffer_activeregion(source, &sr); 154135446Strhodes for (i = 0; i < sr.length; i += len) { 155135446Strhodes /* 156135446Strhodes * Check for overflow. 157135446Strhodes */ 158135446Strhodes if (i + 2 > sr.length) 159135446Strhodes RETERR(DNS_R_FORMERR); 160135446Strhodes window = sr.base[i]; 161135446Strhodes len = sr.base[i + 1]; 162135446Strhodes i += 2; 163135446Strhodes /* 164135446Strhodes * Check that bitmap windows are in the correct order. 165135446Strhodes */ 166135446Strhodes if (!first && window <= lastwindow) 167135446Strhodes RETERR(DNS_R_FORMERR); 168135446Strhodes /* 169135446Strhodes * Check for legal lengths. 170135446Strhodes */ 171135446Strhodes if (len < 1 || len > 32) 172135446Strhodes RETERR(DNS_R_FORMERR); 173135446Strhodes /* 174135446Strhodes * Check for overflow. 175135446Strhodes */ 176135446Strhodes if (i + len > sr.length) 177135446Strhodes RETERR(DNS_R_FORMERR); 178135446Strhodes /* 179135446Strhodes * The last octet of the bitmap must be non zero. 180135446Strhodes */ 181135446Strhodes if (sr.base[i + len - 1] == 0) 182135446Strhodes RETERR(DNS_R_FORMERR); 183135446Strhodes lastwindow = window; 184135446Strhodes first = ISC_FALSE; 185135446Strhodes } 186135446Strhodes if (i != sr.length) 187135446Strhodes return (DNS_R_EXTRADATA); 188135446Strhodes if (first) 189135446Strhodes RETERR(DNS_R_FORMERR); 190135446Strhodes RETERR(mem_tobuffer(target, sr.base, sr.length)); 191135446Strhodes isc_buffer_forward(source, sr.length); 192135446Strhodes return (ISC_R_SUCCESS); 193135446Strhodes} 194135446Strhodes 195135446Strhodesstatic inline isc_result_t 196135446Strhodestowire_nsec(ARGS_TOWIRE) { 197135446Strhodes isc_region_t sr; 198135446Strhodes dns_name_t name; 199135446Strhodes dns_offsets_t offsets; 200135446Strhodes 201135446Strhodes REQUIRE(rdata->type == 47); 202135446Strhodes REQUIRE(rdata->length != 0); 203135446Strhodes 204135446Strhodes dns_compress_setmethods(cctx, DNS_COMPRESS_NONE); 205135446Strhodes dns_name_init(&name, offsets); 206135446Strhodes dns_rdata_toregion(rdata, &sr); 207135446Strhodes dns_name_fromregion(&name, &sr); 208135446Strhodes isc_region_consume(&sr, name_length(&name)); 209135446Strhodes RETERR(dns_name_towire(&name, cctx, target)); 210135446Strhodes 211135446Strhodes return (mem_tobuffer(target, sr.base, sr.length)); 212135446Strhodes} 213135446Strhodes 214135446Strhodesstatic inline int 215135446Strhodescompare_nsec(ARGS_COMPARE) { 216135446Strhodes isc_region_t r1; 217135446Strhodes isc_region_t r2; 218135446Strhodes 219135446Strhodes REQUIRE(rdata1->type == rdata2->type); 220135446Strhodes REQUIRE(rdata1->rdclass == rdata2->rdclass); 221135446Strhodes REQUIRE(rdata1->type == 47); 222135446Strhodes REQUIRE(rdata1->length != 0); 223135446Strhodes REQUIRE(rdata2->length != 0); 224135446Strhodes 225135446Strhodes dns_rdata_toregion(rdata1, &r1); 226135446Strhodes dns_rdata_toregion(rdata2, &r2); 227135446Strhodes return (isc_region_compare(&r1, &r2)); 228135446Strhodes} 229135446Strhodes 230135446Strhodesstatic inline isc_result_t 231135446Strhodesfromstruct_nsec(ARGS_FROMSTRUCT) { 232135446Strhodes dns_rdata_nsec_t *nsec = source; 233135446Strhodes isc_region_t region; 234135446Strhodes unsigned int i, len, window, lastwindow = 0; 235135446Strhodes isc_boolean_t first = ISC_TRUE; 236135446Strhodes 237135446Strhodes REQUIRE(type == 47); 238135446Strhodes REQUIRE(source != NULL); 239135446Strhodes REQUIRE(nsec->common.rdtype == type); 240135446Strhodes REQUIRE(nsec->common.rdclass == rdclass); 241135446Strhodes REQUIRE(nsec->typebits != NULL || nsec->len == 0); 242135446Strhodes 243135446Strhodes UNUSED(type); 244135446Strhodes UNUSED(rdclass); 245135446Strhodes 246135446Strhodes dns_name_toregion(&nsec->next, ®ion); 247135446Strhodes RETERR(isc_buffer_copyregion(target, ®ion)); 248135446Strhodes /* 249135446Strhodes * Perform sanity check. 250135446Strhodes */ 251135446Strhodes for (i = 0; i < nsec->len ; i += len) { 252135446Strhodes INSIST(i + 2 <= nsec->len); 253135446Strhodes window = nsec->typebits[i]; 254135446Strhodes len = nsec->typebits[i+1]; 255135446Strhodes i += 2; 256186462Sdougb INSIST(first || window > lastwindow); 257135446Strhodes INSIST(len > 0 && len <= 32); 258135446Strhodes INSIST(i + len <= nsec->len); 259135446Strhodes INSIST(nsec->typebits[i + len - 1] != 0); 260135446Strhodes lastwindow = window; 261135446Strhodes first = ISC_FALSE; 262135446Strhodes } 263135446Strhodes INSIST(!first); 264135446Strhodes return (mem_tobuffer(target, nsec->typebits, nsec->len)); 265135446Strhodes} 266135446Strhodes 267135446Strhodesstatic inline isc_result_t 268135446Strhodestostruct_nsec(ARGS_TOSTRUCT) { 269135446Strhodes isc_region_t region; 270135446Strhodes dns_rdata_nsec_t *nsec = target; 271135446Strhodes dns_name_t name; 272135446Strhodes 273135446Strhodes REQUIRE(rdata->type == 47); 274135446Strhodes REQUIRE(target != NULL); 275135446Strhodes REQUIRE(rdata->length != 0); 276135446Strhodes 277135446Strhodes nsec->common.rdclass = rdata->rdclass; 278135446Strhodes nsec->common.rdtype = rdata->type; 279135446Strhodes ISC_LINK_INIT(&nsec->common, link); 280135446Strhodes 281135446Strhodes dns_name_init(&name, NULL); 282135446Strhodes dns_rdata_toregion(rdata, ®ion); 283135446Strhodes dns_name_fromregion(&name, ®ion); 284135446Strhodes isc_region_consume(®ion, name_length(&name)); 285135446Strhodes dns_name_init(&nsec->next, NULL); 286135446Strhodes RETERR(name_duporclone(&name, mctx, &nsec->next)); 287135446Strhodes 288135446Strhodes nsec->len = region.length; 289135446Strhodes nsec->typebits = mem_maybedup(mctx, region.base, region.length); 290135446Strhodes if (nsec->typebits == NULL) 291135446Strhodes goto cleanup; 292135446Strhodes 293135446Strhodes nsec->mctx = mctx; 294135446Strhodes return (ISC_R_SUCCESS); 295135446Strhodes 296135446Strhodes cleanup: 297135446Strhodes if (mctx != NULL) 298135446Strhodes dns_name_free(&nsec->next, mctx); 299135446Strhodes return (ISC_R_NOMEMORY); 300135446Strhodes} 301135446Strhodes 302135446Strhodesstatic inline void 303135446Strhodesfreestruct_nsec(ARGS_FREESTRUCT) { 304135446Strhodes dns_rdata_nsec_t *nsec = source; 305135446Strhodes 306135446Strhodes REQUIRE(source != NULL); 307135446Strhodes REQUIRE(nsec->common.rdtype == 47); 308135446Strhodes 309135446Strhodes if (nsec->mctx == NULL) 310135446Strhodes return; 311135446Strhodes 312135446Strhodes dns_name_free(&nsec->next, nsec->mctx); 313135446Strhodes if (nsec->typebits != NULL) 314135446Strhodes isc_mem_free(nsec->mctx, nsec->typebits); 315135446Strhodes nsec->mctx = NULL; 316135446Strhodes} 317135446Strhodes 318135446Strhodesstatic inline isc_result_t 319135446Strhodesadditionaldata_nsec(ARGS_ADDLDATA) { 320135446Strhodes REQUIRE(rdata->type == 47); 321135446Strhodes 322135446Strhodes UNUSED(rdata); 323135446Strhodes UNUSED(add); 324135446Strhodes UNUSED(arg); 325135446Strhodes 326135446Strhodes return (ISC_R_SUCCESS); 327135446Strhodes} 328135446Strhodes 329135446Strhodesstatic inline isc_result_t 330135446Strhodesdigest_nsec(ARGS_DIGEST) { 331135446Strhodes isc_region_t r; 332135446Strhodes 333135446Strhodes REQUIRE(rdata->type == 47); 334135446Strhodes 335135446Strhodes dns_rdata_toregion(rdata, &r); 336135446Strhodes return ((digest)(arg, &r)); 337135446Strhodes} 338135446Strhodes 339135446Strhodesstatic inline isc_boolean_t 340135446Strhodescheckowner_nsec(ARGS_CHECKOWNER) { 341135446Strhodes 342135446Strhodes REQUIRE(type == 47); 343135446Strhodes 344135446Strhodes UNUSED(name); 345135446Strhodes UNUSED(type); 346135446Strhodes UNUSED(rdclass); 347135446Strhodes UNUSED(wildcard); 348135446Strhodes 349135446Strhodes return (ISC_TRUE); 350135446Strhodes} 351135446Strhodes 352135446Strhodesstatic inline isc_boolean_t 353135446Strhodeschecknames_nsec(ARGS_CHECKNAMES) { 354135446Strhodes 355135446Strhodes REQUIRE(rdata->type == 47); 356135446Strhodes 357135446Strhodes UNUSED(rdata); 358135446Strhodes UNUSED(owner); 359135446Strhodes UNUSED(bad); 360135446Strhodes 361135446Strhodes return (ISC_TRUE); 362135446Strhodes} 363135446Strhodes 364224092Sdougbstatic inline int 365224092Sdougbcasecompare_nsec(ARGS_COMPARE) { 366224092Sdougb isc_region_t region1; 367224092Sdougb isc_region_t region2; 368224092Sdougb dns_name_t name1; 369224092Sdougb dns_name_t name2; 370224092Sdougb int order; 371224092Sdougb 372224092Sdougb REQUIRE(rdata1->type == rdata2->type); 373224092Sdougb REQUIRE(rdata1->rdclass == rdata2->rdclass); 374224092Sdougb REQUIRE(rdata1->type == 47); 375224092Sdougb REQUIRE(rdata1->length != 0); 376224092Sdougb REQUIRE(rdata2->length != 0); 377224092Sdougb 378224092Sdougb dns_name_init(&name1, NULL); 379224092Sdougb dns_name_init(&name2, NULL); 380224092Sdougb 381224092Sdougb dns_rdata_toregion(rdata1, ®ion1); 382224092Sdougb dns_rdata_toregion(rdata2, ®ion2); 383224092Sdougb 384224092Sdougb dns_name_fromregion(&name1, ®ion1); 385224092Sdougb dns_name_fromregion(&name2, ®ion2); 386224092Sdougb 387224092Sdougb order = dns_name_rdatacompare(&name1, &name2); 388224092Sdougb if (order != 0) 389224092Sdougb return (order); 390224092Sdougb 391224092Sdougb isc_region_consume(®ion1, name_length(&name1)); 392224092Sdougb isc_region_consume(®ion2, name_length(&name2)); 393224092Sdougb 394224092Sdougb return (isc_region_compare(®ion1, ®ion2)); 395224092Sdougb} 396135446Strhodes#endif /* RDATA_GENERIC_NSEC_47_C */ 397