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