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