1/* $NetBSD: naptr_35.c,v 1.1.1.1 2011/09/11 17:18:57 christos Exp $ */ 2 3/* 4 * Copyright (C) 2004, 2005, 2007-2009, 2011, 2012 Internet Systems Consortium, Inc. ("ISC") 5 * Copyright (C) 1999-2001, 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 */ 21 22/* Reviewed: Thu Mar 16 16:52:50 PST 2000 by bwelling */ 23 24/* RFC2915 */ 25 26#ifndef RDATA_GENERIC_NAPTR_35_C 27#define RDATA_GENERIC_NAPTR_35_C 28 29#define RRTYPE_NAPTR_ATTRIBUTES (0) 30#ifdef HAVE_REGEX_H 31#include <regex.h> 32#endif 33 34/* 35 * Check the wire format of the Regexp field. 36 * Don't allow embeded NUL's. 37 */ 38static inline isc_result_t 39txt_valid_regex(const unsigned char *txt) { 40#ifdef HAVE_REGEX_H 41 regex_t preg; 42 unsigned int regflags = REG_EXTENDED; 43 unsigned int nsub = 0; 44 char regex[256]; 45 char *cp; 46#endif 47 isc_boolean_t flags = ISC_FALSE; 48 isc_boolean_t replace = ISC_FALSE; 49 unsigned char c; 50 unsigned char delim; 51 unsigned int len; 52 53 len = *txt++; 54 if (len == 0U) 55 return (ISC_R_SUCCESS); 56 57 delim = *txt++; 58 len--; 59 60 /* 61 * Digits, backslash and flags can't be delimiters. 62 */ 63 switch (delim) { 64 case '0': case '1': case '2': case '3': case '4': 65 case '5': case '6': case '7': case '8': case '9': 66 case '\\': case 'i': case 0: 67 return (DNS_R_SYNTAX); 68 } 69 70#ifdef HAVE_REGEX_H 71 memset(&preg, 0, sizeof(preg)); 72 cp = regex; 73#endif 74 75 while (len-- > 0) { 76 c = *txt++; 77 if (c == 0) 78 return (DNS_R_SYNTAX); 79 if (c == delim && !replace) { 80 replace = ISC_TRUE; 81 continue; 82 } else if (c == delim && !flags) { 83 flags = ISC_TRUE; 84 continue; 85 } else if (c == delim) 86 return (DNS_R_SYNTAX); 87 /* 88 * Flags are not escaped. 89 */ 90 if (flags) { 91 switch (c) { 92 case 'i': 93#ifdef HAVE_REGEX_H 94 regflags |= REG_ICASE; 95#endif 96 continue; 97 default: 98 return (DNS_R_SYNTAX); 99 } 100 } 101#ifdef HAVE_REGEX_H 102 if (!replace) 103 *cp++ = c; 104#endif 105 if (c == '\\') { 106 if (len == 0) 107 return (DNS_R_SYNTAX); 108 c = *txt++; 109 if (c == 0) 110 return (DNS_R_SYNTAX); 111 len--; 112 if (replace) 113 switch (c) { 114 case '0': return (DNS_R_SYNTAX); 115#ifdef HAVE_REGEX_H 116 case '1': if (nsub < 1) nsub = 1; break; 117 case '2': if (nsub < 2) nsub = 2; break; 118 case '3': if (nsub < 3) nsub = 3; break; 119 case '4': if (nsub < 4) nsub = 4; break; 120 case '5': if (nsub < 5) nsub = 5; break; 121 case '6': if (nsub < 6) nsub = 6; break; 122 case '7': if (nsub < 7) nsub = 7; break; 123 case '8': if (nsub < 8) nsub = 8; break; 124 case '9': if (nsub < 9) nsub = 9; break; 125#endif 126 } 127#ifdef HAVE_REGEX_H 128 if (!replace) 129 *cp++ = c; 130#endif 131 } 132 } 133 if (!flags) 134 return (DNS_R_SYNTAX); 135#ifdef HAVE_REGEX_H 136 *cp = '\0'; 137 if (regcomp(&preg, regex, regflags)) 138 return (DNS_R_SYNTAX); 139 /* 140 * Check that substitutions in the replacement string are consistant 141 * with the regular expression. 142 */ 143 if (preg.re_nsub < nsub) { 144 regfree(&preg); 145 return (DNS_R_SYNTAX); 146 } 147 regfree(&preg); 148#endif 149 return (ISC_R_SUCCESS); 150} 151 152static inline isc_result_t 153fromtext_naptr(ARGS_FROMTEXT) { 154 isc_token_t token; 155 dns_name_t name; 156 isc_buffer_t buffer; 157 unsigned char *regex; 158 159 REQUIRE(type == 35); 160 161 UNUSED(type); 162 UNUSED(rdclass); 163 UNUSED(callbacks); 164 165 /* 166 * Order. 167 */ 168 RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_number, 169 ISC_FALSE)); 170 if (token.value.as_ulong > 0xffffU) 171 RETTOK(ISC_R_RANGE); 172 RETERR(uint16_tobuffer(token.value.as_ulong, target)); 173 174 /* 175 * Preference. 176 */ 177 RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_number, 178 ISC_FALSE)); 179 if (token.value.as_ulong > 0xffffU) 180 RETTOK(ISC_R_RANGE); 181 RETERR(uint16_tobuffer(token.value.as_ulong, target)); 182 183 /* 184 * Flags. 185 */ 186 RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_qstring, 187 ISC_FALSE)); 188 RETTOK(txt_fromtext(&token.value.as_textregion, target)); 189 190 /* 191 * Service. 192 */ 193 RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_qstring, 194 ISC_FALSE)); 195 RETTOK(txt_fromtext(&token.value.as_textregion, target)); 196 197 /* 198 * Regexp. 199 */ 200 regex = isc_buffer_used(target); 201 RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_qstring, 202 ISC_FALSE)); 203 RETTOK(txt_fromtext(&token.value.as_textregion, target)); 204 RETTOK(txt_valid_regex(regex)); 205 206 /* 207 * Replacement. 208 */ 209 RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string, 210 ISC_FALSE)); 211 dns_name_init(&name, NULL); 212 buffer_fromregion(&buffer, &token.value.as_region); 213 origin = (origin != NULL) ? origin : dns_rootname; 214 RETTOK(dns_name_fromtext(&name, &buffer, origin, options, target)); 215 return (ISC_R_SUCCESS); 216} 217 218static inline isc_result_t 219totext_naptr(ARGS_TOTEXT) { 220 isc_region_t region; 221 dns_name_t name; 222 dns_name_t prefix; 223 isc_boolean_t sub; 224 char buf[sizeof("64000")]; 225 unsigned short num; 226 227 REQUIRE(rdata->type == 35); 228 REQUIRE(rdata->length != 0); 229 230 dns_name_init(&name, NULL); 231 dns_name_init(&prefix, NULL); 232 233 dns_rdata_toregion(rdata, ®ion); 234 235 /* 236 * Order. 237 */ 238 num = uint16_fromregion(®ion); 239 isc_region_consume(®ion, 2); 240 sprintf(buf, "%u", num); 241 RETERR(str_totext(buf, target)); 242 RETERR(str_totext(" ", target)); 243 244 /* 245 * Preference. 246 */ 247 num = uint16_fromregion(®ion); 248 isc_region_consume(®ion, 2); 249 sprintf(buf, "%u", num); 250 RETERR(str_totext(buf, target)); 251 RETERR(str_totext(" ", target)); 252 253 /* 254 * Flags. 255 */ 256 RETERR(txt_totext(®ion, target)); 257 RETERR(str_totext(" ", target)); 258 259 /* 260 * Service. 261 */ 262 RETERR(txt_totext(®ion, target)); 263 RETERR(str_totext(" ", target)); 264 265 /* 266 * Regexp. 267 */ 268 RETERR(txt_totext(®ion, target)); 269 RETERR(str_totext(" ", target)); 270 271 /* 272 * Replacement. 273 */ 274 dns_name_fromregion(&name, ®ion); 275 sub = name_prefix(&name, tctx->origin, &prefix); 276 return (dns_name_totext(&prefix, sub, target)); 277} 278 279static inline isc_result_t 280fromwire_naptr(ARGS_FROMWIRE) { 281 dns_name_t name; 282 isc_region_t sr; 283 unsigned char *regex; 284 285 REQUIRE(type == 35); 286 287 UNUSED(type); 288 UNUSED(rdclass); 289 290 dns_decompress_setmethods(dctx, DNS_COMPRESS_NONE); 291 292 dns_name_init(&name, NULL); 293 294 /* 295 * Order, preference. 296 */ 297 isc_buffer_activeregion(source, &sr); 298 if (sr.length < 4) 299 return (ISC_R_UNEXPECTEDEND); 300 RETERR(mem_tobuffer(target, sr.base, 4)); 301 isc_buffer_forward(source, 4); 302 303 /* 304 * Flags. 305 */ 306 RETERR(txt_fromwire(source, target)); 307 308 /* 309 * Service. 310 */ 311 RETERR(txt_fromwire(source, target)); 312 313 /* 314 * Regexp. 315 */ 316 regex = isc_buffer_used(target); 317 RETERR(txt_fromwire(source, target)); 318 RETERR(txt_valid_regex(regex)); 319 320 /* 321 * Replacement. 322 */ 323 return (dns_name_fromwire(&name, source, dctx, options, target)); 324} 325 326static inline isc_result_t 327towire_naptr(ARGS_TOWIRE) { 328 dns_name_t name; 329 dns_offsets_t offsets; 330 isc_region_t sr; 331 332 REQUIRE(rdata->type == 35); 333 REQUIRE(rdata->length != 0); 334 335 dns_compress_setmethods(cctx, DNS_COMPRESS_NONE); 336 /* 337 * Order, preference. 338 */ 339 dns_rdata_toregion(rdata, &sr); 340 RETERR(mem_tobuffer(target, sr.base, 4)); 341 isc_region_consume(&sr, 4); 342 343 /* 344 * Flags. 345 */ 346 RETERR(mem_tobuffer(target, sr.base, sr.base[0] + 1)); 347 isc_region_consume(&sr, sr.base[0] + 1); 348 349 /* 350 * Service. 351 */ 352 RETERR(mem_tobuffer(target, sr.base, sr.base[0] + 1)); 353 isc_region_consume(&sr, sr.base[0] + 1); 354 355 /* 356 * Regexp. 357 */ 358 RETERR(mem_tobuffer(target, sr.base, sr.base[0] + 1)); 359 isc_region_consume(&sr, sr.base[0] + 1); 360 361 /* 362 * Replacement. 363 */ 364 dns_name_init(&name, offsets); 365 dns_name_fromregion(&name, &sr); 366 return (dns_name_towire(&name, cctx, target)); 367} 368 369static inline int 370compare_naptr(ARGS_COMPARE) { 371 dns_name_t name1; 372 dns_name_t name2; 373 isc_region_t region1; 374 isc_region_t region2; 375 int order, len; 376 377 REQUIRE(rdata1->type == rdata2->type); 378 REQUIRE(rdata1->rdclass == rdata2->rdclass); 379 REQUIRE(rdata1->type == 35); 380 REQUIRE(rdata1->length != 0); 381 REQUIRE(rdata2->length != 0); 382 383 dns_rdata_toregion(rdata1, ®ion1); 384 dns_rdata_toregion(rdata2, ®ion2); 385 386 /* 387 * Order, preference. 388 */ 389 order = memcmp(region1.base, region2.base, 4); 390 if (order != 0) 391 return (order < 0 ? -1 : 1); 392 isc_region_consume(®ion1, 4); 393 isc_region_consume(®ion2, 4); 394 395 /* 396 * Flags. 397 */ 398 len = ISC_MIN(region1.base[0], region2.base[0]); 399 order = memcmp(region1.base, region2.base, len + 1); 400 if (order != 0) 401 return (order < 0 ? -1 : 1); 402 isc_region_consume(®ion1, region1.base[0] + 1); 403 isc_region_consume(®ion2, region2.base[0] + 1); 404 405 /* 406 * Service. 407 */ 408 len = ISC_MIN(region1.base[0], region2.base[0]); 409 order = memcmp(region1.base, region2.base, len + 1); 410 if (order != 0) 411 return (order < 0 ? -1 : 1); 412 isc_region_consume(®ion1, region1.base[0] + 1); 413 isc_region_consume(®ion2, region2.base[0] + 1); 414 415 /* 416 * Regexp. 417 */ 418 len = ISC_MIN(region1.base[0], region2.base[0]); 419 order = memcmp(region1.base, region2.base, len + 1); 420 if (order != 0) 421 return (order < 0 ? -1 : 1); 422 isc_region_consume(®ion1, region1.base[0] + 1); 423 isc_region_consume(®ion2, region2.base[0] + 1); 424 425 /* 426 * Replacement. 427 */ 428 dns_name_init(&name1, NULL); 429 dns_name_init(&name2, NULL); 430 431 dns_name_fromregion(&name1, ®ion1); 432 dns_name_fromregion(&name2, ®ion2); 433 434 return (dns_name_rdatacompare(&name1, &name2)); 435} 436 437static inline isc_result_t 438fromstruct_naptr(ARGS_FROMSTRUCT) { 439 dns_rdata_naptr_t *naptr = source; 440 isc_region_t region; 441 442 REQUIRE(type == 35); 443 REQUIRE(source != NULL); 444 REQUIRE(naptr->common.rdtype == type); 445 REQUIRE(naptr->common.rdclass == rdclass); 446 REQUIRE(naptr->flags != NULL || naptr->flags_len == 0); 447 REQUIRE(naptr->service != NULL || naptr->service_len == 0); 448 REQUIRE(naptr->regexp != NULL || naptr->regexp_len == 0); 449 450 UNUSED(type); 451 UNUSED(rdclass); 452 453 RETERR(uint16_tobuffer(naptr->order, target)); 454 RETERR(uint16_tobuffer(naptr->preference, target)); 455 RETERR(uint8_tobuffer(naptr->flags_len, target)); 456 RETERR(mem_tobuffer(target, naptr->flags, naptr->flags_len)); 457 RETERR(uint8_tobuffer(naptr->service_len, target)); 458 RETERR(mem_tobuffer(target, naptr->service, naptr->service_len)); 459 RETERR(uint8_tobuffer(naptr->regexp_len, target)); 460 RETERR(mem_tobuffer(target, naptr->regexp, naptr->regexp_len)); 461 dns_name_toregion(&naptr->replacement, ®ion); 462 return (isc_buffer_copyregion(target, ®ion)); 463} 464 465static inline isc_result_t 466tostruct_naptr(ARGS_TOSTRUCT) { 467 dns_rdata_naptr_t *naptr = target; 468 isc_region_t r; 469 isc_result_t result; 470 dns_name_t name; 471 472 REQUIRE(rdata->type == 35); 473 REQUIRE(target != NULL); 474 REQUIRE(rdata->length != 0); 475 476 naptr->common.rdclass = rdata->rdclass; 477 naptr->common.rdtype = rdata->type; 478 ISC_LINK_INIT(&naptr->common, link); 479 480 naptr->flags = NULL; 481 naptr->service = NULL; 482 naptr->regexp = NULL; 483 484 dns_rdata_toregion(rdata, &r); 485 486 naptr->order = uint16_fromregion(&r); 487 isc_region_consume(&r, 2); 488 489 naptr->preference = uint16_fromregion(&r); 490 isc_region_consume(&r, 2); 491 492 naptr->flags_len = uint8_fromregion(&r); 493 isc_region_consume(&r, 1); 494 INSIST(naptr->flags_len <= r.length); 495 naptr->flags = mem_maybedup(mctx, r.base, naptr->flags_len); 496 if (naptr->flags == NULL) 497 goto cleanup; 498 isc_region_consume(&r, naptr->flags_len); 499 500 naptr->service_len = uint8_fromregion(&r); 501 isc_region_consume(&r, 1); 502 INSIST(naptr->service_len <= r.length); 503 naptr->service = mem_maybedup(mctx, r.base, naptr->service_len); 504 if (naptr->service == NULL) 505 goto cleanup; 506 isc_region_consume(&r, naptr->service_len); 507 508 naptr->regexp_len = uint8_fromregion(&r); 509 isc_region_consume(&r, 1); 510 INSIST(naptr->regexp_len <= r.length); 511 naptr->regexp = mem_maybedup(mctx, r.base, naptr->regexp_len); 512 if (naptr->regexp == NULL) 513 goto cleanup; 514 isc_region_consume(&r, naptr->regexp_len); 515 516 dns_name_init(&name, NULL); 517 dns_name_fromregion(&name, &r); 518 dns_name_init(&naptr->replacement, NULL); 519 result = name_duporclone(&name, mctx, &naptr->replacement); 520 if (result != ISC_R_SUCCESS) 521 goto cleanup; 522 naptr->mctx = mctx; 523 return (ISC_R_SUCCESS); 524 525 cleanup: 526 if (mctx != NULL && naptr->flags != NULL) 527 isc_mem_free(mctx, naptr->flags); 528 if (mctx != NULL && naptr->service != NULL) 529 isc_mem_free(mctx, naptr->service); 530 if (mctx != NULL && naptr->regexp != NULL) 531 isc_mem_free(mctx, naptr->regexp); 532 return (ISC_R_NOMEMORY); 533} 534 535static inline void 536freestruct_naptr(ARGS_FREESTRUCT) { 537 dns_rdata_naptr_t *naptr = source; 538 539 REQUIRE(source != NULL); 540 REQUIRE(naptr->common.rdtype == 35); 541 542 if (naptr->mctx == NULL) 543 return; 544 545 if (naptr->flags != NULL) 546 isc_mem_free(naptr->mctx, naptr->flags); 547 if (naptr->service != NULL) 548 isc_mem_free(naptr->mctx, naptr->service); 549 if (naptr->regexp != NULL) 550 isc_mem_free(naptr->mctx, naptr->regexp); 551 dns_name_free(&naptr->replacement, naptr->mctx); 552 naptr->mctx = NULL; 553} 554 555static inline isc_result_t 556additionaldata_naptr(ARGS_ADDLDATA) { 557 dns_name_t name; 558 dns_offsets_t offsets; 559 isc_region_t sr; 560 dns_rdatatype_t atype; 561 unsigned int i, flagslen; 562 char *cp; 563 564 REQUIRE(rdata->type == 35); 565 566 /* 567 * Order, preference. 568 */ 569 dns_rdata_toregion(rdata, &sr); 570 isc_region_consume(&sr, 4); 571 572 /* 573 * Flags. 574 */ 575 atype = 0; 576 flagslen = sr.base[0]; 577 cp = (char *)&sr.base[1]; 578 for (i = 0; i < flagslen; i++, cp++) { 579 if (*cp == 'S' || *cp == 's') { 580 atype = dns_rdatatype_srv; 581 break; 582 } 583 if (*cp == 'A' || *cp == 'a') { 584 atype = dns_rdatatype_a; 585 break; 586 } 587 } 588 isc_region_consume(&sr, flagslen + 1); 589 590 /* 591 * Service. 592 */ 593 isc_region_consume(&sr, sr.base[0] + 1); 594 595 /* 596 * Regexp. 597 */ 598 isc_region_consume(&sr, sr.base[0] + 1); 599 600 /* 601 * Replacement. 602 */ 603 dns_name_init(&name, offsets); 604 dns_name_fromregion(&name, &sr); 605 606 if (atype != 0) 607 return ((add)(arg, &name, atype)); 608 609 return (ISC_R_SUCCESS); 610} 611 612static inline isc_result_t 613digest_naptr(ARGS_DIGEST) { 614 isc_region_t r1, r2; 615 unsigned int length, n; 616 isc_result_t result; 617 dns_name_t name; 618 619 REQUIRE(rdata->type == 35); 620 621 dns_rdata_toregion(rdata, &r1); 622 r2 = r1; 623 length = 0; 624 625 /* 626 * Order, preference. 627 */ 628 length += 4; 629 isc_region_consume(&r2, 4); 630 631 /* 632 * Flags. 633 */ 634 n = r2.base[0] + 1; 635 length += n; 636 isc_region_consume(&r2, n); 637 638 /* 639 * Service. 640 */ 641 n = r2.base[0] + 1; 642 length += n; 643 isc_region_consume(&r2, n); 644 645 /* 646 * Regexp. 647 */ 648 n = r2.base[0] + 1; 649 length += n; 650 isc_region_consume(&r2, n); 651 652 /* 653 * Digest the RR up to the replacement name. 654 */ 655 r1.length = length; 656 result = (digest)(arg, &r1); 657 if (result != ISC_R_SUCCESS) 658 return (result); 659 660 /* 661 * Replacement. 662 */ 663 664 dns_name_init(&name, NULL); 665 dns_name_fromregion(&name, &r2); 666 667 return (dns_name_digest(&name, digest, arg)); 668} 669 670static inline isc_boolean_t 671checkowner_naptr(ARGS_CHECKOWNER) { 672 673 REQUIRE(type == 35); 674 675 UNUSED(name); 676 UNUSED(type); 677 UNUSED(rdclass); 678 UNUSED(wildcard); 679 680 return (ISC_TRUE); 681} 682 683static inline isc_boolean_t 684checknames_naptr(ARGS_CHECKNAMES) { 685 686 REQUIRE(rdata->type == 35); 687 688 UNUSED(rdata); 689 UNUSED(owner); 690 UNUSED(bad); 691 692 return (ISC_TRUE); 693} 694 695static inline int 696casecompare_naptr(ARGS_COMPARE) { 697 return (compare_naptr(rdata1, rdata2)); 698} 699 700#endif /* RDATA_GENERIC_NAPTR_35_C */ 701