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