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