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