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