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