1/* $NetBSD: nsec_47.c,v 1.9 2024/02/21 22:52:13 christos Exp $ */ 2 3/* 4 * Copyright (C) Internet Systems Consortium, Inc. ("ISC") 5 * 6 * SPDX-License-Identifier: MPL-2.0 7 * 8 * This Source Code Form is subject to the terms of the Mozilla Public 9 * License, v. 2.0. If a copy of the MPL was not distributed with this 10 * file, you can obtain one at https://mozilla.org/MPL/2.0/. 11 * 12 * See the COPYRIGHT file distributed with this work for additional 13 * information regarding copyright ownership. 14 */ 15 16/* RFC 3845 */ 17 18#ifndef RDATA_GENERIC_NSEC_47_C 19#define RDATA_GENERIC_NSEC_47_C 20 21/* 22 * The attributes do not include DNS_RDATATYPEATTR_SINGLETON 23 * because we must be able to handle a parent/child NSEC pair. 24 */ 25#define RRTYPE_NSEC_ATTRIBUTES \ 26 (DNS_RDATATYPEATTR_DNSSEC | DNS_RDATATYPEATTR_ZONECUTAUTH | \ 27 DNS_RDATATYPEATTR_ATCNAME) 28 29static isc_result_t 30fromtext_nsec(ARGS_FROMTEXT) { 31 isc_token_t token; 32 dns_name_t name; 33 isc_buffer_t buffer; 34 35 REQUIRE(type == dns_rdatatype_nsec); 36 37 UNUSED(type); 38 UNUSED(rdclass); 39 UNUSED(callbacks); 40 41 /* 42 * Next domain. 43 */ 44 RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string, 45 false)); 46 dns_name_init(&name, NULL); 47 buffer_fromregion(&buffer, &token.value.as_region); 48 if (origin == NULL) { 49 origin = dns_rootname; 50 } 51 RETTOK(dns_name_fromtext(&name, &buffer, origin, options, target)); 52 53 return (typemap_fromtext(lexer, target, false)); 54} 55 56static isc_result_t 57totext_nsec(ARGS_TOTEXT) { 58 isc_region_t sr; 59 dns_name_t name; 60 61 REQUIRE(rdata->type == dns_rdatatype_nsec); 62 REQUIRE(rdata->length != 0); 63 64 UNUSED(tctx); 65 66 dns_name_init(&name, NULL); 67 dns_rdata_toregion(rdata, &sr); 68 dns_name_fromregion(&name, &sr); 69 isc_region_consume(&sr, name_length(&name)); 70 RETERR(dns_name_totext(&name, false, target)); 71 /* 72 * Don't leave a trailing space when there's no typemap present. 73 */ 74 if (sr.length > 0) { 75 RETERR(str_totext(" ", target)); 76 } 77 return (typemap_totext(&sr, NULL, target)); 78} 79 80static isc_result_t 81fromwire_nsec(ARGS_FROMWIRE) { 82 isc_region_t sr; 83 dns_name_t name; 84 85 REQUIRE(type == dns_rdatatype_nsec); 86 87 UNUSED(type); 88 UNUSED(rdclass); 89 90 dns_decompress_setmethods(dctx, DNS_COMPRESS_NONE); 91 92 dns_name_init(&name, NULL); 93 RETERR(dns_name_fromwire(&name, source, dctx, options, target)); 94 95 isc_buffer_activeregion(source, &sr); 96 RETERR(typemap_test(&sr, false)); 97 RETERR(mem_tobuffer(target, sr.base, sr.length)); 98 isc_buffer_forward(source, sr.length); 99 return (ISC_R_SUCCESS); 100} 101 102static isc_result_t 103towire_nsec(ARGS_TOWIRE) { 104 isc_region_t sr; 105 dns_name_t name; 106 dns_offsets_t offsets; 107 108 REQUIRE(rdata->type == dns_rdatatype_nsec); 109 REQUIRE(rdata->length != 0); 110 111 dns_compress_setmethods(cctx, DNS_COMPRESS_NONE); 112 dns_name_init(&name, offsets); 113 dns_rdata_toregion(rdata, &sr); 114 dns_name_fromregion(&name, &sr); 115 isc_region_consume(&sr, name_length(&name)); 116 RETERR(dns_name_towire(&name, cctx, target)); 117 118 return (mem_tobuffer(target, sr.base, sr.length)); 119} 120 121static int 122compare_nsec(ARGS_COMPARE) { 123 isc_region_t r1; 124 isc_region_t r2; 125 126 REQUIRE(rdata1->type == rdata2->type); 127 REQUIRE(rdata1->rdclass == rdata2->rdclass); 128 REQUIRE(rdata1->type == dns_rdatatype_nsec); 129 REQUIRE(rdata1->length != 0); 130 REQUIRE(rdata2->length != 0); 131 132 dns_rdata_toregion(rdata1, &r1); 133 dns_rdata_toregion(rdata2, &r2); 134 return (isc_region_compare(&r1, &r2)); 135} 136 137static isc_result_t 138fromstruct_nsec(ARGS_FROMSTRUCT) { 139 dns_rdata_nsec_t *nsec = source; 140 isc_region_t region; 141 142 REQUIRE(type == dns_rdatatype_nsec); 143 REQUIRE(nsec != NULL); 144 REQUIRE(nsec->common.rdtype == type); 145 REQUIRE(nsec->common.rdclass == rdclass); 146 REQUIRE(nsec->typebits != NULL || nsec->len == 0); 147 148 UNUSED(type); 149 UNUSED(rdclass); 150 151 dns_name_toregion(&nsec->next, ®ion); 152 RETERR(isc_buffer_copyregion(target, ®ion)); 153 154 region.base = nsec->typebits; 155 region.length = nsec->len; 156 RETERR(typemap_test(®ion, false)); 157 return (mem_tobuffer(target, nsec->typebits, nsec->len)); 158} 159 160static isc_result_t 161tostruct_nsec(ARGS_TOSTRUCT) { 162 isc_region_t region; 163 dns_rdata_nsec_t *nsec = target; 164 dns_name_t name; 165 166 REQUIRE(rdata->type == dns_rdatatype_nsec); 167 REQUIRE(nsec != NULL); 168 REQUIRE(rdata->length != 0); 169 170 nsec->common.rdclass = rdata->rdclass; 171 nsec->common.rdtype = rdata->type; 172 ISC_LINK_INIT(&nsec->common, link); 173 174 dns_name_init(&name, NULL); 175 dns_rdata_toregion(rdata, ®ion); 176 dns_name_fromregion(&name, ®ion); 177 isc_region_consume(®ion, name_length(&name)); 178 dns_name_init(&nsec->next, NULL); 179 name_duporclone(&name, mctx, &nsec->next); 180 181 nsec->len = region.length; 182 nsec->typebits = mem_maybedup(mctx, region.base, region.length); 183 if (nsec->typebits == NULL) { 184 goto cleanup; 185 } 186 187 nsec->mctx = mctx; 188 return (ISC_R_SUCCESS); 189 190cleanup: 191 if (mctx != NULL) { 192 dns_name_free(&nsec->next, mctx); 193 } 194 return (ISC_R_NOMEMORY); 195} 196 197static void 198freestruct_nsec(ARGS_FREESTRUCT) { 199 dns_rdata_nsec_t *nsec = source; 200 201 REQUIRE(nsec != NULL); 202 REQUIRE(nsec->common.rdtype == dns_rdatatype_nsec); 203 204 if (nsec->mctx == NULL) { 205 return; 206 } 207 208 dns_name_free(&nsec->next, nsec->mctx); 209 if (nsec->typebits != NULL) { 210 isc_mem_free(nsec->mctx, nsec->typebits); 211 } 212 nsec->mctx = NULL; 213} 214 215static isc_result_t 216additionaldata_nsec(ARGS_ADDLDATA) { 217 REQUIRE(rdata->type == dns_rdatatype_nsec); 218 219 UNUSED(rdata); 220 UNUSED(owner); 221 UNUSED(add); 222 UNUSED(arg); 223 224 return (ISC_R_SUCCESS); 225} 226 227static isc_result_t 228digest_nsec(ARGS_DIGEST) { 229 isc_region_t r; 230 231 REQUIRE(rdata->type == dns_rdatatype_nsec); 232 233 dns_rdata_toregion(rdata, &r); 234 return ((digest)(arg, &r)); 235} 236 237static bool 238checkowner_nsec(ARGS_CHECKOWNER) { 239 REQUIRE(type == dns_rdatatype_nsec); 240 241 UNUSED(name); 242 UNUSED(type); 243 UNUSED(rdclass); 244 UNUSED(wildcard); 245 246 return (true); 247} 248 249static bool 250checknames_nsec(ARGS_CHECKNAMES) { 251 REQUIRE(rdata->type == dns_rdatatype_nsec); 252 253 UNUSED(rdata); 254 UNUSED(owner); 255 UNUSED(bad); 256 257 return (true); 258} 259 260static int 261casecompare_nsec(ARGS_COMPARE) { 262 isc_region_t region1; 263 isc_region_t region2; 264 dns_name_t name1; 265 dns_name_t name2; 266 int order; 267 268 REQUIRE(rdata1->type == rdata2->type); 269 REQUIRE(rdata1->rdclass == rdata2->rdclass); 270 REQUIRE(rdata1->type == dns_rdatatype_nsec); 271 REQUIRE(rdata1->length != 0); 272 REQUIRE(rdata2->length != 0); 273 274 dns_name_init(&name1, NULL); 275 dns_name_init(&name2, NULL); 276 277 dns_rdata_toregion(rdata1, ®ion1); 278 dns_rdata_toregion(rdata2, ®ion2); 279 280 dns_name_fromregion(&name1, ®ion1); 281 dns_name_fromregion(&name2, ®ion2); 282 283 order = dns_name_rdatacompare(&name1, &name2); 284 if (order != 0) { 285 return (order); 286 } 287 288 isc_region_consume(®ion1, name_length(&name1)); 289 isc_region_consume(®ion2, name_length(&name2)); 290 291 return (isc_region_compare(®ion1, ®ion2)); 292} 293#endif /* RDATA_GENERIC_NSEC_47_C */ 294