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