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