1 /*- 2 * SPDX-License-Identifier: ISC 3 * 4 * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") 5 * Copyright (c) 1996-1999 by Internet Software Consortium. 6 * 7 * Permission to use, copy, modify, and 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 12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR 14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT 17 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 */ 19 20 /*! \file 21 * \brief 22 * Based on the Dynamic DNS reference implementation by Viraj Bais 23 * <viraj_bais@ccm.fm.intel.com> 24 */ 25 26 #if !defined(lint) && !defined(SABER) 27 static const char rcsid[] = "$Id: res_mkupdate.c,v 1.10 2008/12/11 09:59:00 marka Exp $"; 28 #endif /* not lint */ 29 #include <sys/cdefs.h> 30 __FBSDID("$FreeBSD$"); 31 32 #include "port_before.h" 33 34 #include <sys/param.h> 35 36 #include <netinet/in.h> 37 #include <arpa/nameser.h> 38 #include <arpa/inet.h> 39 40 #include <errno.h> 41 #include <limits.h> 42 #include <netdb.h> 43 #include <resolv.h> 44 #include <res_update.h> 45 #include <stdio.h> 46 #include <stdlib.h> 47 #include <string.h> 48 #include <unistd.h> 49 #include <ctype.h> 50 51 #ifdef _LIBC 52 #include <isc/list.h> 53 #endif 54 55 #include "port_after.h" 56 57 /* Options. Leave them on. */ 58 #ifndef DEBUG 59 #define DEBUG 60 #endif 61 #define MAXPORT 1024 62 63 static int getnum_str(u_char **, u_char *); 64 static int gethexnum_str(u_char **, u_char *); 65 static int getword_str(char *, int, u_char **, u_char *); 66 static int getstr_str(char *, int, u_char **, u_char *); 67 68 #define ShrinkBuffer(x) if ((buflen -= x) < 0) return (-2); 69 70 /* Forward. */ 71 72 #ifdef _LIBC 73 static 74 #endif 75 int res_protocolnumber(const char *); 76 #ifdef _LIBC 77 static 78 #endif 79 int res_servicenumber(const char *); 80 81 /*% 82 * Form update packets. 83 * Returns the size of the resulting packet if no error 84 * 85 * On error, 86 * returns 87 *\li -1 if error in reading a word/number in rdata 88 * portion for update packets 89 *\li -2 if length of buffer passed is insufficient 90 *\li -3 if zone section is not the first section in 91 * the linked list, or section order has a problem 92 *\li -4 on a number overflow 93 *\li -5 unknown operation or no records 94 */ 95 int 96 res_nmkupdate(res_state statp, ns_updrec *rrecp_in, u_char *buf, int buflen) { 97 ns_updrec *rrecp_start = rrecp_in; 98 HEADER *hp; 99 u_char *cp, *sp2, *startp, *endp; 100 int n, i, soanum, multiline; 101 ns_updrec *rrecp; 102 struct in_addr ina; 103 struct in6_addr in6a; 104 char buf2[MAXDNAME]; 105 u_char buf3[MAXDNAME]; 106 int section, numrrs = 0, counts[ns_s_max]; 107 u_int16_t rtype, rclass; 108 u_int32_t n1, rttl; 109 u_char *dnptrs[20], **dpp, **lastdnptr; 110 #ifndef _LIBC 111 int siglen; 112 #endif 113 int keylen, certlen; 114 115 /* 116 * Initialize header fields. 117 */ 118 if ((buf == NULL) || (buflen < HFIXEDSZ)) 119 return (-1); 120 memset(buf, 0, HFIXEDSZ); 121 hp = (HEADER *) buf; 122 statp->id = res_nrandomid(statp); 123 hp->id = htons(statp->id); 124 hp->opcode = ns_o_update; 125 hp->rcode = NOERROR; 126 cp = buf + HFIXEDSZ; 127 buflen -= HFIXEDSZ; 128 dpp = dnptrs; 129 *dpp++ = buf; 130 *dpp++ = NULL; 131 lastdnptr = dnptrs + nitems(dnptrs); 132 133 if (rrecp_start == NULL) 134 return (-5); 135 else if (rrecp_start->r_section != S_ZONE) 136 return (-3); 137 138 memset(counts, 0, sizeof counts); 139 for (rrecp = rrecp_start; rrecp; rrecp = NEXT(rrecp, r_glink)) { 140 numrrs++; 141 section = rrecp->r_section; 142 if (section < 0 || section >= ns_s_max) 143 return (-1); 144 counts[section]++; 145 for (i = section + 1; i < ns_s_max; i++) 146 if (counts[i]) 147 return (-3); 148 rtype = rrecp->r_type; 149 rclass = rrecp->r_class; 150 rttl = rrecp->r_ttl; 151 /* overload class and type */ 152 if (section == S_PREREQ) { 153 rttl = 0; 154 switch (rrecp->r_opcode) { 155 case YXDOMAIN: 156 rclass = C_ANY; 157 rtype = T_ANY; 158 rrecp->r_size = 0; 159 break; 160 case NXDOMAIN: 161 rclass = C_NONE; 162 rtype = T_ANY; 163 rrecp->r_size = 0; 164 break; 165 case NXRRSET: 166 rclass = C_NONE; 167 rrecp->r_size = 0; 168 break; 169 case YXRRSET: 170 if (rrecp->r_size == 0) 171 rclass = C_ANY; 172 break; 173 default: 174 fprintf(stderr, 175 "res_mkupdate: incorrect opcode: %d\n", 176 rrecp->r_opcode); 177 fflush(stderr); 178 return (-1); 179 } 180 } else if (section == S_UPDATE) { 181 switch (rrecp->r_opcode) { 182 case DELETE: 183 rclass = rrecp->r_size == 0 ? C_ANY : C_NONE; 184 break; 185 case ADD: 186 break; 187 default: 188 fprintf(stderr, 189 "res_mkupdate: incorrect opcode: %d\n", 190 rrecp->r_opcode); 191 fflush(stderr); 192 return (-1); 193 } 194 } 195 196 /* 197 * XXX appending default domain to owner name is omitted, 198 * fqdn must be provided 199 */ 200 if ((n = dn_comp(rrecp->r_dname, cp, buflen, dnptrs, 201 lastdnptr)) < 0) 202 return (-1); 203 cp += n; 204 ShrinkBuffer(n + 2*INT16SZ); 205 PUTSHORT(rtype, cp); 206 PUTSHORT(rclass, cp); 207 if (section == S_ZONE) { 208 if (numrrs != 1 || rrecp->r_type != T_SOA) 209 return (-3); 210 continue; 211 } 212 ShrinkBuffer(INT32SZ + INT16SZ); 213 PUTLONG(rttl, cp); 214 sp2 = cp; /*%< save pointer to length byte */ 215 cp += INT16SZ; 216 if (rrecp->r_size == 0) { 217 if (section == S_UPDATE && rclass != C_ANY) 218 return (-1); 219 else { 220 PUTSHORT(0, sp2); 221 continue; 222 } 223 } 224 startp = rrecp->r_data; 225 endp = startp + rrecp->r_size - 1; 226 /* XXX this should be done centrally. */ 227 switch (rrecp->r_type) { 228 case T_A: 229 if (!getword_str(buf2, sizeof buf2, &startp, endp)) 230 return (-1); 231 if (!inet_aton(buf2, &ina)) 232 return (-1); 233 n1 = ntohl(ina.s_addr); 234 ShrinkBuffer(INT32SZ); 235 PUTLONG(n1, cp); 236 break; 237 case T_CNAME: 238 case T_MB: 239 case T_MG: 240 case T_MR: 241 case T_NS: 242 case T_PTR: 243 case ns_t_dname: 244 if (!getword_str(buf2, sizeof buf2, &startp, endp)) 245 return (-1); 246 n = dn_comp(buf2, cp, buflen, dnptrs, lastdnptr); 247 if (n < 0) 248 return (-1); 249 cp += n; 250 ShrinkBuffer(n); 251 break; 252 case T_MINFO: 253 case T_SOA: 254 case T_RP: 255 for (i = 0; i < 2; i++) { 256 if (!getword_str(buf2, sizeof buf2, &startp, 257 endp)) 258 return (-1); 259 n = dn_comp(buf2, cp, buflen, 260 dnptrs, lastdnptr); 261 if (n < 0) 262 return (-1); 263 cp += n; 264 ShrinkBuffer(n); 265 } 266 if (rrecp->r_type == T_SOA) { 267 ShrinkBuffer(5 * INT32SZ); 268 while (isspace(*startp) || !*startp) 269 startp++; 270 if (*startp == '(') { 271 multiline = 1; 272 startp++; 273 } else 274 multiline = 0; 275 /* serial, refresh, retry, expire, minimum */ 276 for (i = 0; i < 5; i++) { 277 soanum = getnum_str(&startp, endp); 278 if (soanum < 0) 279 return (-1); 280 PUTLONG(soanum, cp); 281 } 282 if (multiline) { 283 while (isspace(*startp) || !*startp) 284 startp++; 285 if (*startp != ')') 286 return (-1); 287 } 288 } 289 break; 290 case T_MX: 291 case T_AFSDB: 292 case T_RT: 293 n = getnum_str(&startp, endp); 294 if (n < 0) 295 return (-1); 296 ShrinkBuffer(INT16SZ); 297 PUTSHORT(n, cp); 298 if (!getword_str(buf2, sizeof buf2, &startp, endp)) 299 return (-1); 300 n = dn_comp(buf2, cp, buflen, dnptrs, lastdnptr); 301 if (n < 0) 302 return (-1); 303 cp += n; 304 ShrinkBuffer(n); 305 break; 306 case T_SRV: 307 n = getnum_str(&startp, endp); 308 if (n < 0) 309 return (-1); 310 ShrinkBuffer(INT16SZ); 311 PUTSHORT(n, cp); 312 313 n = getnum_str(&startp, endp); 314 if (n < 0) 315 return (-1); 316 ShrinkBuffer(INT16SZ); 317 PUTSHORT(n, cp); 318 319 n = getnum_str(&startp, endp); 320 if (n < 0) 321 return (-1); 322 ShrinkBuffer(INT16SZ); 323 PUTSHORT(n, cp); 324 325 if (!getword_str(buf2, sizeof buf2, &startp, endp)) 326 return (-1); 327 n = dn_comp(buf2, cp, buflen, NULL, NULL); 328 if (n < 0) 329 return (-1); 330 cp += n; 331 ShrinkBuffer(n); 332 break; 333 case T_PX: 334 n = getnum_str(&startp, endp); 335 if (n < 0) 336 return (-1); 337 PUTSHORT(n, cp); 338 ShrinkBuffer(INT16SZ); 339 for (i = 0; i < 2; i++) { 340 if (!getword_str(buf2, sizeof buf2, &startp, 341 endp)) 342 return (-1); 343 n = dn_comp(buf2, cp, buflen, dnptrs, 344 lastdnptr); 345 if (n < 0) 346 return (-1); 347 cp += n; 348 ShrinkBuffer(n); 349 } 350 break; 351 case T_WKS: { 352 char bm[MAXPORT/8]; 353 unsigned int maxbm = 0; 354 355 if (!getword_str(buf2, sizeof buf2, &startp, endp)) 356 return (-1); 357 if (!inet_aton(buf2, &ina)) 358 return (-1); 359 n1 = ntohl(ina.s_addr); 360 ShrinkBuffer(INT32SZ); 361 PUTLONG(n1, cp); 362 363 if (!getword_str(buf2, sizeof buf2, &startp, endp)) 364 return (-1); 365 if ((i = res_protocolnumber(buf2)) < 0) 366 return (-1); 367 ShrinkBuffer(1); 368 *cp++ = i & 0xff; 369 370 for (i = 0; i < MAXPORT/8 ; i++) 371 bm[i] = 0; 372 373 while (getword_str(buf2, sizeof buf2, &startp, endp)) { 374 if ((n = res_servicenumber(buf2)) <= 0) 375 return (-1); 376 377 if (n < MAXPORT) { 378 bm[n/8] |= (0x80>>(n%8)); 379 if ((unsigned)n > maxbm) 380 maxbm = n; 381 } else 382 return (-1); 383 } 384 maxbm = maxbm/8 + 1; 385 ShrinkBuffer(maxbm); 386 memcpy(cp, bm, maxbm); 387 cp += maxbm; 388 break; 389 } 390 case T_HINFO: 391 for (i = 0; i < 2; i++) { 392 if ((n = getstr_str(buf2, sizeof buf2, 393 &startp, endp)) < 0) 394 return (-1); 395 if (n > 255) 396 return (-1); 397 ShrinkBuffer(n+1); 398 *cp++ = n; 399 memcpy(cp, buf2, n); 400 cp += n; 401 } 402 break; 403 case T_TXT: 404 for (;;) { 405 if ((n = getstr_str(buf2, sizeof buf2, 406 &startp, endp)) < 0) { 407 if (cp != (sp2 + INT16SZ)) 408 break; 409 return (-1); 410 } 411 if (n > 255) 412 return (-1); 413 ShrinkBuffer(n+1); 414 *cp++ = n; 415 memcpy(cp, buf2, n); 416 cp += n; 417 } 418 break; 419 case T_X25: 420 /* RFC1183 */ 421 if ((n = getstr_str(buf2, sizeof buf2, &startp, 422 endp)) < 0) 423 return (-1); 424 if (n > 255) 425 return (-1); 426 ShrinkBuffer(n+1); 427 *cp++ = n; 428 memcpy(cp, buf2, n); 429 cp += n; 430 break; 431 case T_ISDN: 432 /* RFC1183 */ 433 if ((n = getstr_str(buf2, sizeof buf2, &startp, 434 endp)) < 0) 435 return (-1); 436 if ((n > 255) || (n == 0)) 437 return (-1); 438 ShrinkBuffer(n+1); 439 *cp++ = n; 440 memcpy(cp, buf2, n); 441 cp += n; 442 if ((n = getstr_str(buf2, sizeof buf2, &startp, 443 endp)) < 0) 444 n = 0; 445 if (n > 255) 446 return (-1); 447 ShrinkBuffer(n+1); 448 *cp++ = n; 449 memcpy(cp, buf2, n); 450 cp += n; 451 break; 452 case T_NSAP: 453 if ((n = inet_nsap_addr((char *)startp, (u_char *)buf2, sizeof(buf2))) != 0) { 454 ShrinkBuffer(n); 455 memcpy(cp, buf2, n); 456 cp += n; 457 } else { 458 return (-1); 459 } 460 break; 461 case T_LOC: 462 if ((n = loc_aton((char *)startp, (u_char *)buf2)) != 0) { 463 ShrinkBuffer(n); 464 memcpy(cp, buf2, n); 465 cp += n; 466 } else 467 return (-1); 468 break; 469 case ns_t_sig: 470 #ifdef _LIBC 471 return (-1); 472 #else 473 { 474 int sig_type, success, dateerror; 475 u_int32_t exptime, timesigned; 476 477 /* type */ 478 if ((n = getword_str(buf2, sizeof buf2, 479 &startp, endp)) < 0) 480 return (-1); 481 sig_type = sym_ston(__p_type_syms, buf2, &success); 482 if (!success || sig_type == ns_t_any) 483 return (-1); 484 ShrinkBuffer(INT16SZ); 485 PUTSHORT(sig_type, cp); 486 /* alg */ 487 n = getnum_str(&startp, endp); 488 if (n < 0) 489 return (-1); 490 ShrinkBuffer(1); 491 *cp++ = n; 492 /* labels */ 493 n = getnum_str(&startp, endp); 494 if (n <= 0 || n > 255) 495 return (-1); 496 ShrinkBuffer(1); 497 *cp++ = n; 498 /* ottl & expire */ 499 if (!getword_str(buf2, sizeof buf2, &startp, endp)) 500 return (-1); 501 exptime = ns_datetosecs(buf2, &dateerror); 502 if (!dateerror) { 503 ShrinkBuffer(INT32SZ); 504 PUTLONG(rttl, cp); 505 } 506 else { 507 char *ulendp; 508 u_int32_t ottl; 509 510 errno = 0; 511 ottl = strtoul(buf2, &ulendp, 10); 512 if (errno != 0 || 513 (ulendp != NULL && *ulendp != '\0')) 514 return (-1); 515 ShrinkBuffer(INT32SZ); 516 PUTLONG(ottl, cp); 517 if (!getword_str(buf2, sizeof buf2, &startp, 518 endp)) 519 return (-1); 520 exptime = ns_datetosecs(buf2, &dateerror); 521 if (dateerror) 522 return (-1); 523 } 524 /* expire */ 525 ShrinkBuffer(INT32SZ); 526 PUTLONG(exptime, cp); 527 /* timesigned */ 528 if (!getword_str(buf2, sizeof buf2, &startp, endp)) 529 return (-1); 530 timesigned = ns_datetosecs(buf2, &dateerror); 531 if (!dateerror) { 532 ShrinkBuffer(INT32SZ); 533 PUTLONG(timesigned, cp); 534 } 535 else 536 return (-1); 537 /* footprint */ 538 n = getnum_str(&startp, endp); 539 if (n < 0) 540 return (-1); 541 ShrinkBuffer(INT16SZ); 542 PUTSHORT(n, cp); 543 /* signer name */ 544 if (!getword_str(buf2, sizeof buf2, &startp, endp)) 545 return (-1); 546 n = dn_comp(buf2, cp, buflen, dnptrs, lastdnptr); 547 if (n < 0) 548 return (-1); 549 cp += n; 550 ShrinkBuffer(n); 551 /* sig */ 552 if ((n = getword_str(buf2, sizeof buf2, 553 &startp, endp)) < 0) 554 return (-1); 555 siglen = b64_pton(buf2, buf3, sizeof(buf3)); 556 if (siglen < 0) 557 return (-1); 558 ShrinkBuffer(siglen); 559 memcpy(cp, buf3, siglen); 560 cp += siglen; 561 break; 562 } 563 #endif 564 case ns_t_key: 565 /* flags */ 566 n = gethexnum_str(&startp, endp); 567 if (n < 0) 568 return (-1); 569 ShrinkBuffer(INT16SZ); 570 PUTSHORT(n, cp); 571 /* proto */ 572 n = getnum_str(&startp, endp); 573 if (n < 0) 574 return (-1); 575 ShrinkBuffer(1); 576 *cp++ = n; 577 /* alg */ 578 n = getnum_str(&startp, endp); 579 if (n < 0) 580 return (-1); 581 ShrinkBuffer(1); 582 *cp++ = n; 583 /* key */ 584 if ((n = getword_str(buf2, sizeof buf2, 585 &startp, endp)) < 0) 586 return (-1); 587 keylen = b64_pton(buf2, buf3, sizeof(buf3)); 588 if (keylen < 0) 589 return (-1); 590 ShrinkBuffer(keylen); 591 memcpy(cp, buf3, keylen); 592 cp += keylen; 593 break; 594 case ns_t_nxt: 595 { 596 int success, nxt_type; 597 u_char data[32]; 598 int maxtype; 599 600 /* next name */ 601 if (!getword_str(buf2, sizeof buf2, &startp, endp)) 602 return (-1); 603 n = dn_comp(buf2, cp, buflen, NULL, NULL); 604 if (n < 0) 605 return (-1); 606 cp += n; 607 ShrinkBuffer(n); 608 maxtype = 0; 609 memset(data, 0, sizeof data); 610 for (;;) { 611 if (!getword_str(buf2, sizeof buf2, &startp, 612 endp)) 613 break; 614 nxt_type = sym_ston(__p_type_syms, buf2, 615 &success); 616 if (!success || !ns_t_rr_p(nxt_type)) 617 return (-1); 618 NS_NXT_BIT_SET(nxt_type, data); 619 if (nxt_type > maxtype) 620 maxtype = nxt_type; 621 } 622 n = maxtype/NS_NXT_BITS+1; 623 ShrinkBuffer(n); 624 memcpy(cp, data, n); 625 cp += n; 626 break; 627 } 628 case ns_t_cert: 629 /* type */ 630 n = getnum_str(&startp, endp); 631 if (n < 0) 632 return (-1); 633 ShrinkBuffer(INT16SZ); 634 PUTSHORT(n, cp); 635 /* key tag */ 636 n = getnum_str(&startp, endp); 637 if (n < 0) 638 return (-1); 639 ShrinkBuffer(INT16SZ); 640 PUTSHORT(n, cp); 641 /* alg */ 642 n = getnum_str(&startp, endp); 643 if (n < 0) 644 return (-1); 645 ShrinkBuffer(1); 646 *cp++ = n; 647 /* cert */ 648 if ((n = getword_str(buf2, sizeof buf2, 649 &startp, endp)) < 0) 650 return (-1); 651 certlen = b64_pton(buf2, buf3, sizeof(buf3)); 652 if (certlen < 0) 653 return (-1); 654 ShrinkBuffer(certlen); 655 memcpy(cp, buf3, certlen); 656 cp += certlen; 657 break; 658 case ns_t_aaaa: 659 if (!getword_str(buf2, sizeof buf2, &startp, endp)) 660 return (-1); 661 if (inet_pton(AF_INET6, buf2, &in6a) <= 0) 662 return (-1); 663 ShrinkBuffer(NS_IN6ADDRSZ); 664 memcpy(cp, &in6a, NS_IN6ADDRSZ); 665 cp += NS_IN6ADDRSZ; 666 break; 667 case ns_t_naptr: 668 /* Order Preference Flags Service Replacement Regexp */ 669 /* Order */ 670 n = getnum_str(&startp, endp); 671 if (n < 0 || n > 65535) 672 return (-1); 673 ShrinkBuffer(INT16SZ); 674 PUTSHORT(n, cp); 675 /* Preference */ 676 n = getnum_str(&startp, endp); 677 if (n < 0 || n > 65535) 678 return (-1); 679 ShrinkBuffer(INT16SZ); 680 PUTSHORT(n, cp); 681 /* Flags */ 682 if ((n = getstr_str(buf2, sizeof buf2, 683 &startp, endp)) < 0) { 684 return (-1); 685 } 686 if (n > 255) 687 return (-1); 688 ShrinkBuffer(n+1); 689 *cp++ = n; 690 memcpy(cp, buf2, n); 691 cp += n; 692 /* Service Classes */ 693 if ((n = getstr_str(buf2, sizeof buf2, 694 &startp, endp)) < 0) { 695 return (-1); 696 } 697 if (n > 255) 698 return (-1); 699 ShrinkBuffer(n+1); 700 *cp++ = n; 701 memcpy(cp, buf2, n); 702 cp += n; 703 /* Pattern */ 704 if ((n = getstr_str(buf2, sizeof buf2, 705 &startp, endp)) < 0) { 706 return (-1); 707 } 708 if (n > 255) 709 return (-1); 710 ShrinkBuffer(n+1); 711 *cp++ = n; 712 memcpy(cp, buf2, n); 713 cp += n; 714 /* Replacement */ 715 if (!getword_str(buf2, sizeof buf2, &startp, endp)) 716 return (-1); 717 n = dn_comp(buf2, cp, buflen, NULL, NULL); 718 if (n < 0) 719 return (-1); 720 cp += n; 721 ShrinkBuffer(n); 722 break; 723 default: 724 return (-1); 725 } /*switch*/ 726 n = (u_int16_t)((cp - sp2) - INT16SZ); 727 PUTSHORT(n, sp2); 728 } /*for*/ 729 730 hp->qdcount = htons(counts[0]); 731 hp->ancount = htons(counts[1]); 732 hp->nscount = htons(counts[2]); 733 hp->arcount = htons(counts[3]); 734 return (cp - buf); 735 } 736 737 /*% 738 * Get a whitespace delimited word from a string (not file) 739 * into buf. modify the start pointer to point after the 740 * word in the string. 741 */ 742 static int 743 getword_str(char *buf, int size, u_char **startpp, u_char *endp) { 744 char *cp; 745 int c; 746 747 for (cp = buf; *startpp <= endp; ) { 748 c = **startpp; 749 if (isspace(c) || c == '\0') { 750 if (cp != buf) /*%< trailing whitespace */ 751 break; 752 else { /*%< leading whitespace */ 753 (*startpp)++; 754 continue; 755 } 756 } 757 (*startpp)++; 758 if (cp >= buf+size-1) 759 break; 760 *cp++ = (u_char)c; 761 } 762 *cp = '\0'; 763 return (cp != buf); 764 } 765 766 /*% 767 * get a white spae delimited string from memory. Process quoted strings 768 * and \\DDD escapes. Return length or -1 on error. Returned string may 769 * contain nulls. 770 */ 771 static char digits[] = "0123456789"; 772 static int 773 getstr_str(char *buf, int size, u_char **startpp, u_char *endp) { 774 char *cp; 775 int c, c1 = 0; 776 int inquote = 0; 777 int seen_quote = 0; 778 int escape = 0; 779 int dig = 0; 780 781 for (cp = buf; *startpp <= endp; ) { 782 if ((c = **startpp) == '\0') 783 break; 784 /* leading white space */ 785 if ((cp == buf) && !seen_quote && isspace(c)) { 786 (*startpp)++; 787 continue; 788 } 789 790 switch (c) { 791 case '\\': 792 if (!escape) { 793 escape = 1; 794 dig = 0; 795 c1 = 0; 796 (*startpp)++; 797 continue; 798 } 799 goto do_escape; 800 case '"': 801 if (!escape) { 802 inquote = !inquote; 803 seen_quote = 1; 804 (*startpp)++; 805 continue; 806 } 807 /* fall through */ 808 default: 809 do_escape: 810 if (escape) { 811 switch (c) { 812 case '0': 813 case '1': 814 case '2': 815 case '3': 816 case '4': 817 case '5': 818 case '6': 819 case '7': 820 case '8': 821 case '9': 822 c1 = c1 * 10 + 823 (strchr(digits, c) - digits); 824 825 if (++dig == 3) { 826 c = c1 &0xff; 827 break; 828 } 829 (*startpp)++; 830 continue; 831 } 832 escape = 0; 833 } else if (!inquote && isspace(c)) 834 goto done; 835 if (cp >= buf+size-1) 836 goto done; 837 *cp++ = (u_char)c; 838 (*startpp)++; 839 } 840 } 841 done: 842 *cp = '\0'; 843 return ((cp == buf)? (seen_quote? 0: -1): (cp - buf)); 844 } 845 846 /*% 847 * Get a whitespace delimited base 16 number from a string (not file) into buf 848 * update the start pointer to point after the number in the string. 849 */ 850 static int 851 gethexnum_str(u_char **startpp, u_char *endp) { 852 int c, n; 853 int seendigit = 0; 854 int m = 0; 855 856 if (*startpp + 2 >= endp || strncasecmp((char *)*startpp, "0x", 2) != 0) 857 return getnum_str(startpp, endp); 858 (*startpp)+=2; 859 for (n = 0; *startpp <= endp; ) { 860 c = **startpp; 861 if (isspace(c) || c == '\0') { 862 if (seendigit) /*%< trailing whitespace */ 863 break; 864 else { /*%< leading whitespace */ 865 (*startpp)++; 866 continue; 867 } 868 } 869 if (c == ';') { 870 while ((*startpp <= endp) && 871 ((c = **startpp) != '\n')) 872 (*startpp)++; 873 if (seendigit) 874 break; 875 continue; 876 } 877 if (!isxdigit(c)) { 878 if (c == ')' && seendigit) { 879 (*startpp)--; 880 break; 881 } 882 return (-1); 883 } 884 (*startpp)++; 885 if (isdigit(c)) 886 n = n * 16 + (c - '0'); 887 else 888 n = n * 16 + (tolower(c) - 'a' + 10); 889 seendigit = 1; 890 } 891 return (n + m); 892 } 893 894 /*% 895 * Get a whitespace delimited base 10 number from a string (not file) into buf 896 * update the start pointer to point after the number in the string. 897 */ 898 static int 899 getnum_str(u_char **startpp, u_char *endp) { 900 int c, n; 901 int seendigit = 0; 902 int m = 0; 903 904 for (n = 0; *startpp <= endp; ) { 905 c = **startpp; 906 if (isspace(c) || c == '\0') { 907 if (seendigit) /*%< trailing whitespace */ 908 break; 909 else { /*%< leading whitespace */ 910 (*startpp)++; 911 continue; 912 } 913 } 914 if (c == ';') { 915 while ((*startpp <= endp) && 916 ((c = **startpp) != '\n')) 917 (*startpp)++; 918 if (seendigit) 919 break; 920 continue; 921 } 922 if (!isdigit(c)) { 923 if (c == ')' && seendigit) { 924 (*startpp)--; 925 break; 926 } 927 return (-1); 928 } 929 (*startpp)++; 930 n = n * 10 + (c - '0'); 931 seendigit = 1; 932 } 933 return (n + m); 934 } 935 936 /*% 937 * Allocate a resource record buffer & save rr info. 938 */ 939 ns_updrec * 940 res_mkupdrec(int section, const char *dname, 941 u_int class, u_int type, u_long ttl) { 942 ns_updrec *rrecp = (ns_updrec *)calloc(1, sizeof(ns_updrec)); 943 944 if (!rrecp || !(rrecp->r_dname = strdup(dname))) { 945 if (rrecp) 946 free((char *)rrecp); 947 return (NULL); 948 } 949 INIT_LINK(rrecp, r_link); 950 INIT_LINK(rrecp, r_glink); 951 rrecp->r_class = (ns_class)class; 952 rrecp->r_type = (ns_type)type; 953 rrecp->r_ttl = ttl; 954 rrecp->r_section = (ns_sect)section; 955 return (rrecp); 956 } 957 958 /*% 959 * Free a resource record buffer created by res_mkupdrec. 960 */ 961 void 962 res_freeupdrec(ns_updrec *rrecp) { 963 /* Note: freeing r_dp is the caller's responsibility. */ 964 if (rrecp->r_dname != NULL) 965 free(rrecp->r_dname); 966 free(rrecp); 967 } 968 969 struct valuelist { 970 struct valuelist * next; 971 struct valuelist * prev; 972 char * name; 973 char * proto; 974 int port; 975 }; 976 static struct valuelist *servicelist, *protolist; 977 978 static void 979 res_buildservicelist(void) { 980 struct servent *sp; 981 struct valuelist *slp; 982 983 #ifdef MAYBE_HESIOD 984 setservent(0); 985 #else 986 setservent(1); 987 #endif 988 while ((sp = getservent()) != NULL) { 989 slp = (struct valuelist *)malloc(sizeof(struct valuelist)); 990 if (!slp) 991 break; 992 slp->name = strdup(sp->s_name); 993 slp->proto = strdup(sp->s_proto); 994 if ((slp->name == NULL) || (slp->proto == NULL)) { 995 if (slp->name) free(slp->name); 996 if (slp->proto) free(slp->proto); 997 free(slp); 998 break; 999 } 1000 slp->port = ntohs((u_int16_t)sp->s_port); /*%< host byt order */ 1001 slp->next = servicelist; 1002 slp->prev = NULL; 1003 if (servicelist) 1004 servicelist->prev = slp; 1005 servicelist = slp; 1006 } 1007 endservent(); 1008 } 1009 1010 #ifndef _LIBC 1011 void 1012 res_destroyservicelist() { 1013 struct valuelist *slp, *slp_next; 1014 1015 for (slp = servicelist; slp != NULL; slp = slp_next) { 1016 slp_next = slp->next; 1017 free(slp->name); 1018 free(slp->proto); 1019 free(slp); 1020 } 1021 servicelist = (struct valuelist *)0; 1022 } 1023 #endif 1024 1025 #ifdef _LIBC 1026 static 1027 #endif 1028 void 1029 res_buildprotolist(void) { 1030 struct protoent *pp; 1031 struct valuelist *slp; 1032 1033 #ifdef MAYBE_HESIOD 1034 setprotoent(0); 1035 #else 1036 setprotoent(1); 1037 #endif 1038 while ((pp = getprotoent()) != NULL) { 1039 slp = (struct valuelist *)malloc(sizeof(struct valuelist)); 1040 if (!slp) 1041 break; 1042 slp->name = strdup(pp->p_name); 1043 if (slp->name == NULL) { 1044 free(slp); 1045 break; 1046 } 1047 slp->port = pp->p_proto; /*%< host byte order */ 1048 slp->next = protolist; 1049 slp->prev = NULL; 1050 if (protolist) 1051 protolist->prev = slp; 1052 protolist = slp; 1053 } 1054 endprotoent(); 1055 } 1056 1057 #ifndef _LIBC 1058 void 1059 res_destroyprotolist(void) { 1060 struct valuelist *plp, *plp_next; 1061 1062 for (plp = protolist; plp != NULL; plp = plp_next) { 1063 plp_next = plp->next; 1064 free(plp->name); 1065 free(plp); 1066 } 1067 protolist = (struct valuelist *)0; 1068 } 1069 #endif 1070 1071 static int 1072 findservice(const char *s, struct valuelist **list) { 1073 struct valuelist *lp = *list; 1074 int n; 1075 1076 for (; lp != NULL; lp = lp->next) 1077 if (strcasecmp(lp->name, s) == 0) { 1078 if (lp != *list) { 1079 lp->prev->next = lp->next; 1080 if (lp->next) 1081 lp->next->prev = lp->prev; 1082 (*list)->prev = lp; 1083 lp->next = *list; 1084 *list = lp; 1085 } 1086 return (lp->port); /*%< host byte order */ 1087 } 1088 if (sscanf(s, "%d", &n) != 1 || n <= 0) 1089 n = -1; 1090 return (n); 1091 } 1092 1093 /*% 1094 * Convert service name or (ascii) number to int. 1095 */ 1096 #ifdef _LIBC 1097 static 1098 #endif 1099 int 1100 res_servicenumber(const char *p) { 1101 if (servicelist == (struct valuelist *)0) 1102 res_buildservicelist(); 1103 return (findservice(p, &servicelist)); 1104 } 1105 1106 /*% 1107 * Convert protocol name or (ascii) number to int. 1108 */ 1109 #ifdef _LIBC 1110 static 1111 #endif 1112 int 1113 res_protocolnumber(const char *p) { 1114 if (protolist == (struct valuelist *)0) 1115 res_buildprotolist(); 1116 return (findservice(p, &protolist)); 1117 } 1118 1119 #ifndef _LIBC 1120 static struct servent * 1121 cgetservbyport(u_int16_t port, const char *proto) { /*%< Host byte order. */ 1122 struct valuelist **list = &servicelist; 1123 struct valuelist *lp = *list; 1124 static struct servent serv; 1125 1126 port = ntohs(port); 1127 for (; lp != NULL; lp = lp->next) { 1128 if (port != (u_int16_t)lp->port) /*%< Host byte order. */ 1129 continue; 1130 if (strcasecmp(lp->proto, proto) == 0) { 1131 if (lp != *list) { 1132 lp->prev->next = lp->next; 1133 if (lp->next) 1134 lp->next->prev = lp->prev; 1135 (*list)->prev = lp; 1136 lp->next = *list; 1137 *list = lp; 1138 } 1139 serv.s_name = lp->name; 1140 serv.s_port = htons((u_int16_t)lp->port); 1141 serv.s_proto = lp->proto; 1142 return (&serv); 1143 } 1144 } 1145 return (0); 1146 } 1147 1148 static struct protoent * 1149 cgetprotobynumber(int proto) { /*%< Host byte order. */ 1150 struct valuelist **list = &protolist; 1151 struct valuelist *lp = *list; 1152 static struct protoent prot; 1153 1154 for (; lp != NULL; lp = lp->next) 1155 if (lp->port == proto) { /*%< Host byte order. */ 1156 if (lp != *list) { 1157 lp->prev->next = lp->next; 1158 if (lp->next) 1159 lp->next->prev = lp->prev; 1160 (*list)->prev = lp; 1161 lp->next = *list; 1162 *list = lp; 1163 } 1164 prot.p_name = lp->name; 1165 prot.p_proto = lp->port; /*%< Host byte order. */ 1166 return (&prot); 1167 } 1168 return (0); 1169 } 1170 1171 const char * 1172 res_protocolname(int num) { 1173 static char number[8]; 1174 struct protoent *pp; 1175 1176 if (protolist == (struct valuelist *)0) 1177 res_buildprotolist(); 1178 pp = cgetprotobynumber(num); 1179 if (pp == NULL) { 1180 (void) sprintf(number, "%d", num); 1181 return (number); 1182 } 1183 return (pp->p_name); 1184 } 1185 1186 const char * 1187 res_servicename(u_int16_t port, const char *proto) { /*%< Host byte order. */ 1188 static char number[8]; 1189 struct servent *ss; 1190 1191 if (servicelist == (struct valuelist *)0) 1192 res_buildservicelist(); 1193 ss = cgetservbyport(htons(port), proto); 1194 if (ss == NULL) { 1195 (void) sprintf(number, "%d", port); 1196 return (number); 1197 } 1198 return (ss->s_name); 1199 } 1200 #endif 1201