1 /* $NetBSD: a6_38.c,v 1.5 2014/12/10 04:37:59 christos Exp $ */ 2 3 /* 4 * Copyright (C) 2004, 2007, 2009, 2014 Internet Systems Consortium, Inc. ("ISC") 5 * Copyright (C) 1999-2003 Internet Software Consortium. 6 * 7 * Permission to use, copy, modify, and/or distribute this software for any 8 * purpose with or without fee is hereby granted, provided that the above 9 * copyright notice and this permission notice appear in all copies. 10 * 11 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 12 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 13 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 14 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 15 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 16 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 17 * PERFORMANCE OF THIS SOFTWARE. 18 */ 19 20 /* Id: a6_38.c,v 1.56 2009/12/04 22:06:37 tbox Exp */ 21 22 /* RFC2874 */ 23 24 #ifndef RDATA_IN_1_A6_28_C 25 #define RDATA_IN_1_A6_28_C 26 27 #include <isc/net.h> 28 29 #define RRTYPE_A6_ATTRIBUTES (0) 30 31 static inline isc_result_t 32 fromtext_in_a6(ARGS_FROMTEXT) { 33 isc_token_t token; 34 unsigned char addr[16]; 35 unsigned char prefixlen; 36 unsigned char octets; 37 unsigned char mask; 38 dns_name_t name; 39 isc_buffer_t buffer; 40 isc_boolean_t ok; 41 42 REQUIRE(type == 38); 43 REQUIRE(rdclass == 1); 44 45 UNUSED(type); 46 UNUSED(rdclass); 47 UNUSED(callbacks); 48 49 /* 50 * Prefix length. 51 */ 52 RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_number, 53 ISC_FALSE)); 54 if (token.value.as_ulong > 128U) 55 RETTOK(ISC_R_RANGE); 56 57 prefixlen = (unsigned char)token.value.as_ulong; 58 RETERR(mem_tobuffer(target, &prefixlen, 1)); 59 60 /* 61 * Suffix. 62 */ 63 if (prefixlen != 128) { 64 /* 65 * Prefix 0..127. 66 */ 67 octets = prefixlen/8; 68 /* 69 * Octets 0..15. 70 */ 71 RETERR(isc_lex_getmastertoken(lexer, &token, 72 isc_tokentype_string, 73 ISC_FALSE)); 74 if (inet_pton(AF_INET6, DNS_AS_STR(token), addr) != 1) 75 RETTOK(DNS_R_BADAAAA); 76 mask = 0xff >> (prefixlen % 8); 77 addr[octets] &= mask; 78 RETERR(mem_tobuffer(target, &addr[octets], 16 - octets)); 79 } 80 81 if (prefixlen == 0) 82 return (ISC_R_SUCCESS); 83 84 RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string, 85 ISC_FALSE)); 86 dns_name_init(&name, NULL); 87 buffer_fromregion(&buffer, &token.value.as_region); 88 origin = (origin != NULL) ? origin : dns_rootname; 89 RETTOK(dns_name_fromtext(&name, &buffer, origin, options, target)); 90 ok = ISC_TRUE; 91 if ((options & DNS_RDATA_CHECKNAMES) != 0) 92 ok = dns_name_ishostname(&name, ISC_FALSE); 93 if (!ok && (options & DNS_RDATA_CHECKNAMESFAIL) != 0) 94 RETTOK(DNS_R_BADNAME); 95 if (!ok && callbacks != NULL) 96 warn_badname(&name, lexer, callbacks); 97 return (ISC_R_SUCCESS); 98 } 99 100 static inline isc_result_t 101 totext_in_a6(ARGS_TOTEXT) { 102 isc_region_t sr, ar; 103 unsigned char addr[16]; 104 unsigned char prefixlen; 105 unsigned char octets; 106 unsigned char mask; 107 char buf[sizeof("128")]; 108 dns_name_t name; 109 dns_name_t prefix; 110 isc_boolean_t sub; 111 112 REQUIRE(rdata->type == 38); 113 REQUIRE(rdata->rdclass == 1); 114 REQUIRE(rdata->length != 0); 115 116 dns_rdata_toregion(rdata, &sr); 117 prefixlen = sr.base[0]; 118 INSIST(prefixlen <= 128); 119 isc_region_consume(&sr, 1); 120 sprintf(buf, "%u", prefixlen); 121 RETERR(str_totext(buf, target)); 122 RETERR(str_totext(" ", target)); 123 124 if (prefixlen != 128) { 125 octets = prefixlen/8; 126 memset(addr, 0, sizeof(addr)); 127 memmove(&addr[octets], sr.base, 16 - octets); 128 mask = 0xff >> (prefixlen % 8); 129 addr[octets] &= mask; 130 ar.base = addr; 131 ar.length = sizeof(addr); 132 RETERR(inet_totext(AF_INET6, &ar, target)); 133 isc_region_consume(&sr, 16 - octets); 134 } 135 136 if (prefixlen == 0) 137 return (ISC_R_SUCCESS); 138 139 RETERR(str_totext(" ", target)); 140 dns_name_init(&name, NULL); 141 dns_name_init(&prefix, NULL); 142 dns_name_fromregion(&name, &sr); 143 sub = name_prefix(&name, tctx->origin, &prefix); 144 return (dns_name_totext(&prefix, sub, target)); 145 } 146 147 static inline isc_result_t 148 fromwire_in_a6(ARGS_FROMWIRE) { 149 isc_region_t sr; 150 unsigned char prefixlen; 151 unsigned char octets; 152 unsigned char mask; 153 dns_name_t name; 154 155 REQUIRE(type == 38); 156 REQUIRE(rdclass == 1); 157 158 UNUSED(type); 159 UNUSED(rdclass); 160 161 dns_decompress_setmethods(dctx, DNS_COMPRESS_NONE); 162 163 isc_buffer_activeregion(source, &sr); 164 /* 165 * Prefix length. 166 */ 167 if (sr.length < 1) 168 return (ISC_R_UNEXPECTEDEND); 169 prefixlen = sr.base[0]; 170 if (prefixlen > 128) 171 return (ISC_R_RANGE); 172 isc_region_consume(&sr, 1); 173 RETERR(mem_tobuffer(target, &prefixlen, 1)); 174 isc_buffer_forward(source, 1); 175 176 /* 177 * Suffix. 178 */ 179 if (prefixlen != 128) { 180 octets = 16 - prefixlen / 8; 181 if (sr.length < octets) 182 return (ISC_R_UNEXPECTEDEND); 183 mask = 0xff >> (prefixlen % 8); 184 sr.base[0] &= mask; /* Ensure pad bits are zero. */ 185 RETERR(mem_tobuffer(target, sr.base, octets)); 186 isc_buffer_forward(source, octets); 187 } 188 189 if (prefixlen == 0) 190 return (ISC_R_SUCCESS); 191 192 dns_name_init(&name, NULL); 193 return (dns_name_fromwire(&name, source, dctx, options, target)); 194 } 195 196 static inline isc_result_t 197 towire_in_a6(ARGS_TOWIRE) { 198 isc_region_t sr; 199 dns_name_t name; 200 dns_offsets_t offsets; 201 unsigned char prefixlen; 202 unsigned char octets; 203 204 REQUIRE(rdata->type == 38); 205 REQUIRE(rdata->rdclass == 1); 206 REQUIRE(rdata->length != 0); 207 208 dns_compress_setmethods(cctx, DNS_COMPRESS_NONE); 209 dns_rdata_toregion(rdata, &sr); 210 prefixlen = sr.base[0]; 211 INSIST(prefixlen <= 128); 212 213 octets = 1 + 16 - prefixlen / 8; 214 RETERR(mem_tobuffer(target, sr.base, octets)); 215 isc_region_consume(&sr, octets); 216 217 if (prefixlen == 0) 218 return (ISC_R_SUCCESS); 219 220 dns_name_init(&name, offsets); 221 dns_name_fromregion(&name, &sr); 222 return (dns_name_towire(&name, cctx, target)); 223 } 224 225 static inline int 226 compare_in_a6(ARGS_COMPARE) { 227 int order; 228 unsigned char prefixlen1, prefixlen2; 229 unsigned char octets; 230 dns_name_t name1; 231 dns_name_t name2; 232 isc_region_t region1; 233 isc_region_t region2; 234 235 REQUIRE(rdata1->type == rdata2->type); 236 REQUIRE(rdata1->rdclass == rdata2->rdclass); 237 REQUIRE(rdata1->type == 38); 238 REQUIRE(rdata1->rdclass == 1); 239 REQUIRE(rdata1->length != 0); 240 REQUIRE(rdata2->length != 0); 241 242 dns_rdata_toregion(rdata1, ®ion1); 243 dns_rdata_toregion(rdata2, ®ion2); 244 prefixlen1 = region1.base[0]; 245 prefixlen2 = region2.base[0]; 246 isc_region_consume(®ion1, 1); 247 isc_region_consume(®ion2, 1); 248 if (prefixlen1 < prefixlen2) 249 return (-1); 250 else if (prefixlen1 > prefixlen2) 251 return (1); 252 /* 253 * Prefix lengths are equal. 254 */ 255 octets = 16 - prefixlen1 / 8; 256 257 if (octets > 0) { 258 order = memcmp(region1.base, region2.base, octets); 259 if (order < 0) 260 return (-1); 261 else if (order > 0) 262 return (1); 263 /* 264 * Address suffixes are equal. 265 */ 266 if (prefixlen1 == 0) 267 return (order); 268 isc_region_consume(®ion1, octets); 269 isc_region_consume(®ion2, octets); 270 } 271 272 dns_name_init(&name1, NULL); 273 dns_name_init(&name2, NULL); 274 dns_name_fromregion(&name1, ®ion1); 275 dns_name_fromregion(&name2, ®ion2); 276 return (dns_name_rdatacompare(&name1, &name2)); 277 } 278 279 static inline isc_result_t 280 fromstruct_in_a6(ARGS_FROMSTRUCT) { 281 dns_rdata_in_a6_t *a6 = source; 282 isc_region_t region; 283 int octets; 284 isc_uint8_t bits; 285 isc_uint8_t first; 286 isc_uint8_t mask; 287 288 REQUIRE(type == 38); 289 REQUIRE(rdclass == 1); 290 REQUIRE(source != NULL); 291 REQUIRE(a6->common.rdtype == type); 292 REQUIRE(a6->common.rdclass == rdclass); 293 294 UNUSED(type); 295 UNUSED(rdclass); 296 297 if (a6->prefixlen > 128) 298 return (ISC_R_RANGE); 299 300 RETERR(uint8_tobuffer(a6->prefixlen, target)); 301 302 /* Suffix */ 303 if (a6->prefixlen != 128) { 304 octets = 16 - a6->prefixlen / 8; 305 bits = a6->prefixlen % 8; 306 if (bits != 0) { 307 mask = 0xffU >> bits; 308 first = a6->in6_addr.s6_addr[16 - octets] & mask; 309 RETERR(uint8_tobuffer(first, target)); 310 octets--; 311 } 312 if (octets > 0) 313 RETERR(mem_tobuffer(target, 314 a6->in6_addr.s6_addr + 16 - octets, 315 octets)); 316 } 317 318 if (a6->prefixlen == 0) 319 return (ISC_R_SUCCESS); 320 dns_name_toregion(&a6->prefix, ®ion); 321 return (isc_buffer_copyregion(target, ®ion)); 322 } 323 324 static inline isc_result_t 325 tostruct_in_a6(ARGS_TOSTRUCT) { 326 dns_rdata_in_a6_t *a6 = target; 327 unsigned char octets; 328 dns_name_t name; 329 isc_region_t r; 330 331 REQUIRE(rdata->type == 38); 332 REQUIRE(rdata->rdclass == 1); 333 REQUIRE(target != NULL); 334 REQUIRE(rdata->length != 0); 335 336 a6->common.rdclass = rdata->rdclass; 337 a6->common.rdtype = rdata->type; 338 ISC_LINK_INIT(&a6->common, link); 339 340 dns_rdata_toregion(rdata, &r); 341 342 a6->prefixlen = uint8_fromregion(&r); 343 isc_region_consume(&r, 1); 344 memset(a6->in6_addr.s6_addr, 0, sizeof(a6->in6_addr.s6_addr)); 345 346 /* 347 * Suffix. 348 */ 349 if (a6->prefixlen != 128) { 350 octets = 16 - a6->prefixlen / 8; 351 INSIST(r.length >= octets); 352 memmove(a6->in6_addr.s6_addr + 16 - octets, r.base, octets); 353 isc_region_consume(&r, octets); 354 } 355 356 /* 357 * Prefix. 358 */ 359 dns_name_init(&a6->prefix, NULL); 360 if (a6->prefixlen != 0) { 361 dns_name_init(&name, NULL); 362 dns_name_fromregion(&name, &r); 363 RETERR(name_duporclone(&name, mctx, &a6->prefix)); 364 } 365 a6->mctx = mctx; 366 return (ISC_R_SUCCESS); 367 } 368 369 static inline void 370 freestruct_in_a6(ARGS_FREESTRUCT) { 371 dns_rdata_in_a6_t *a6 = source; 372 373 REQUIRE(source != NULL); 374 REQUIRE(a6->common.rdclass == 1); 375 REQUIRE(a6->common.rdtype == 38); 376 377 if (a6->mctx == NULL) 378 return; 379 380 if (dns_name_dynamic(&a6->prefix)) 381 dns_name_free(&a6->prefix, a6->mctx); 382 a6->mctx = NULL; 383 } 384 385 static inline isc_result_t 386 additionaldata_in_a6(ARGS_ADDLDATA) { 387 REQUIRE(rdata->type == 38); 388 REQUIRE(rdata->rdclass == 1); 389 390 UNUSED(rdata); 391 UNUSED(add); 392 UNUSED(arg); 393 394 return (ISC_R_SUCCESS); 395 } 396 397 static inline isc_result_t 398 digest_in_a6(ARGS_DIGEST) { 399 isc_region_t r1, r2; 400 unsigned char prefixlen, octets; 401 isc_result_t result; 402 dns_name_t name; 403 404 REQUIRE(rdata->type == 38); 405 REQUIRE(rdata->rdclass == 1); 406 407 dns_rdata_toregion(rdata, &r1); 408 r2 = r1; 409 prefixlen = r1.base[0]; 410 octets = 1 + 16 - prefixlen / 8; 411 412 r1.length = octets; 413 result = (digest)(arg, &r1); 414 if (result != ISC_R_SUCCESS) 415 return (result); 416 if (prefixlen == 0) 417 return (ISC_R_SUCCESS); 418 419 isc_region_consume(&r2, octets); 420 dns_name_init(&name, NULL); 421 dns_name_fromregion(&name, &r2); 422 return (dns_name_digest(&name, digest, arg)); 423 } 424 425 static inline isc_boolean_t 426 checkowner_in_a6(ARGS_CHECKOWNER) { 427 428 REQUIRE(type == 38); 429 REQUIRE(rdclass == 1); 430 431 UNUSED(type); 432 UNUSED(rdclass); 433 434 return (dns_name_ishostname(name, wildcard)); 435 } 436 437 static inline isc_boolean_t 438 checknames_in_a6(ARGS_CHECKNAMES) { 439 isc_region_t region; 440 dns_name_t name; 441 unsigned int prefixlen; 442 443 REQUIRE(rdata->type == 38); 444 REQUIRE(rdata->rdclass == 1); 445 446 UNUSED(owner); 447 448 dns_rdata_toregion(rdata, ®ion); 449 prefixlen = uint8_fromregion(®ion); 450 if (prefixlen == 0) 451 return (ISC_TRUE); 452 isc_region_consume(®ion, 1 + 16 - prefixlen / 8); 453 dns_name_init(&name, NULL); 454 dns_name_fromregion(&name, ®ion); 455 if (!dns_name_ishostname(&name, ISC_FALSE)) { 456 if (bad != NULL) 457 dns_name_clone(&name, bad); 458 return (ISC_FALSE); 459 } 460 return (ISC_TRUE); 461 } 462 463 static inline int 464 casecompare_in_a6(ARGS_COMPARE) { 465 return (compare_in_a6(rdata1, rdata2)); 466 } 467 468 #endif /* RDATA_IN_1_A6_38_C */ 469