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 * $Id: res_mkupdate.c,v 1.8 2005/10/14 05:44:26 marka Exp $ 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/types.h> 29 #include <sys/param.h> 30 31 #include <netinet/in.h> 32 #include <arpa/nameser.h> 33 #include <arpa/inet.h> 34 35 #include <errno.h> 36 #include <limits.h> 37 #include <netdb.h> 38 #include <resolv.h> 39 #include <res_update.h> 40 #include <stdio.h> 41 #include <stdlib.h> 42 #include <string.h> 43 #include <unistd.h> 44 #include <ctype.h> 45 46 #ifdef _LIBC 47 #include "isc/list.h" 48 #endif 49 #include "port_after.h" 50 51 /* Options. Leave them on. */ 52 #define DEBUG 53 #define MAXPORT 1024 54 55 static int getnum_str(u_char **, u_char *); 56 static int gethexnum_str(u_char **, u_char *); 57 static int getword_str(char *, int, u_char **, u_char *); 58 static int getstr_str(char *, int, u_char **, u_char *); 59 60 #define ShrinkBuffer(x) if ((buflen -= x) < 0) return (-2); 61 62 /* Forward. */ 63 #ifdef _LIBC 64 static 65 #endif 66 int res_protocolnumber(const char *); 67 #ifdef _LIBC 68 static 69 #endif 70 int res_servicenumber(const char *); 71 72 /*% 73 * Form update packets. 74 * Returns the size of the resulting packet if no error 75 * 76 * On error, 77 * returns 78 *\li -1 if error in reading a word/number in rdata 79 * portion for update packets 80 *\li -2 if length of buffer passed is insufficient 81 *\li -3 if zone section is not the first section in 82 * the linked list, or section order has a problem 83 *\li -4 on a number overflow 84 *\li -5 unknown operation or no records 85 */ 86 int 87 res_nmkupdate(res_state statp, ns_updrec *rrecp_in, u_char *buf, int buflen) { 88 ns_updrec *rrecp_start = rrecp_in; 89 HEADER *hp; 90 u_char *cp, *sp2, *startp, *endp; 91 int n, i, soanum, multiline; 92 ns_updrec *rrecp; 93 struct in_addr ina; 94 struct in6_addr in6a; 95 char buf2[MAXDNAME]; 96 u_char buf3[MAXDNAME]; 97 int section, numrrs = 0, counts[ns_s_max]; 98 u_int16_t rtype, rclass; 99 u_int32_t n1, rttl; 100 u_char *dnptrs[20], **dpp, **lastdnptr; 101 #ifndef _LIBC 102 int siglen; 103 #endif 104 int keylen, certlen; 105 106 /* 107 * Initialize header fields. 108 */ 109 if ((buf == NULL) || (buflen < HFIXEDSZ)) 110 return (-1); 111 memset(buf, 0, HFIXEDSZ); 112 hp = (HEADER *) buf; 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 + NELEM(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 void 1016 res_buildprotolist(void) { 1017 struct protoent *pp; 1018 struct valuelist *slp; 1019 1020 #ifdef MAYBE_HESIOD 1021 setprotoent(0); 1022 #else 1023 setprotoent(1); 1024 #endif 1025 while ((pp = getprotoent()) != NULL) { 1026 slp = (struct valuelist *)malloc(sizeof(struct valuelist)); 1027 if (!slp) 1028 break; 1029 slp->name = strdup(pp->p_name); 1030 if (slp->name == NULL) { 1031 free(slp); 1032 break; 1033 } 1034 slp->port = pp->p_proto; /*%< host byte order */ 1035 slp->next = protolist; 1036 slp->prev = NULL; 1037 if (protolist) 1038 protolist->prev = slp; 1039 protolist = slp; 1040 } 1041 endprotoent(); 1042 } 1043 1044 #ifndef _LIBC 1045 void 1046 res_destroyprotolist(void) { 1047 struct valuelist *plp, *plp_next; 1048 1049 for (plp = protolist; plp != NULL; plp = plp_next) { 1050 plp_next = plp->next; 1051 free(plp->name); 1052 free(plp); 1053 } 1054 protolist = (struct valuelist *)0; 1055 } 1056 #endif 1057 1058 static int 1059 findservice(const char *s, struct valuelist **list) { 1060 struct valuelist *lp = *list; 1061 int n; 1062 1063 for (; lp != NULL; lp = lp->next) 1064 if (strcasecmp(lp->name, s) == 0) { 1065 if (lp != *list) { 1066 lp->prev->next = lp->next; 1067 if (lp->next) 1068 lp->next->prev = lp->prev; 1069 (*list)->prev = lp; 1070 lp->next = *list; 1071 *list = lp; 1072 } 1073 return (lp->port); /*%< host byte order */ 1074 } 1075 if (sscanf(s, "%d", &n) != 1 || n <= 0) 1076 n = -1; 1077 return (n); 1078 } 1079 1080 /*% 1081 * Convert service name or (ascii) number to int. 1082 */ 1083 #ifdef _LIBC 1084 static 1085 #endif 1086 int 1087 res_servicenumber(const char *p) { 1088 if (servicelist == (struct valuelist *)0) 1089 res_buildservicelist(); 1090 return (findservice(p, &servicelist)); 1091 } 1092 1093 /*% 1094 * Convert protocol name or (ascii) number to int. 1095 */ 1096 #ifdef _LIBC 1097 static 1098 #endif 1099 int 1100 res_protocolnumber(const char *p) { 1101 if (protolist == (struct valuelist *)0) 1102 res_buildprotolist(); 1103 return (findservice(p, &protolist)); 1104 } 1105 1106 #ifndef _LIBC 1107 static struct servent * 1108 cgetservbyport(u_int16_t port, const char *proto) { /*%< Host byte order. */ 1109 struct valuelist **list = &servicelist; 1110 struct valuelist *lp = *list; 1111 static struct servent serv; 1112 1113 port = ntohs(port); 1114 for (; lp != NULL; lp = lp->next) { 1115 if (port != (u_int16_t)lp->port) /*%< Host byte order. */ 1116 continue; 1117 if (strcasecmp(lp->proto, proto) == 0) { 1118 if (lp != *list) { 1119 lp->prev->next = lp->next; 1120 if (lp->next) 1121 lp->next->prev = lp->prev; 1122 (*list)->prev = lp; 1123 lp->next = *list; 1124 *list = lp; 1125 } 1126 serv.s_name = lp->name; 1127 serv.s_port = htons((u_int16_t)lp->port); 1128 serv.s_proto = lp->proto; 1129 return (&serv); 1130 } 1131 } 1132 return (0); 1133 } 1134 1135 static struct protoent * 1136 cgetprotobynumber(int proto) { /*%< Host byte order. */ 1137 struct valuelist **list = &protolist; 1138 struct valuelist *lp = *list; 1139 static struct protoent prot; 1140 1141 for (; lp != NULL; lp = lp->next) 1142 if (lp->port == proto) { /*%< Host byte order. */ 1143 if (lp != *list) { 1144 lp->prev->next = lp->next; 1145 if (lp->next) 1146 lp->next->prev = lp->prev; 1147 (*list)->prev = lp; 1148 lp->next = *list; 1149 *list = lp; 1150 } 1151 prot.p_name = lp->name; 1152 prot.p_proto = lp->port; /*%< Host byte order. */ 1153 return (&prot); 1154 } 1155 return (0); 1156 } 1157 1158 const char * 1159 res_protocolname(int num) { 1160 static char number[8]; 1161 struct protoent *pp; 1162 1163 if (protolist == (struct valuelist *)0) 1164 res_buildprotolist(); 1165 pp = cgetprotobynumber(num); 1166 if (pp == NULL) { 1167 (void) sprintf(number, "%d", num); 1168 return (number); 1169 } 1170 return (pp->p_name); 1171 } 1172 1173 const char * 1174 res_servicename(u_int16_t port, const char *proto) { /*%< Host byte order. */ 1175 static char number[8]; 1176 struct servent *ss; 1177 1178 if (servicelist == (struct valuelist *)0) 1179 res_buildservicelist(); 1180 ss = cgetservbyport(htons(port), proto); 1181 if (ss == NULL) { 1182 (void) sprintf(number, "%d", port); 1183 return (number); 1184 } 1185 return (ss->s_name); 1186 } 1187 #endif /* !_LIBC */ 1188