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