1/* $NetBSD: ns_name.c,v 1.4 2022/04/03 01:10:58 christos Exp $ */ 2 3/* 4 * Copyright (C) 2004-2022 Internet Systems Consortium, Inc. ("ISC") 5 * Copyright (c) 1996-2003 by Internet Software Consortium 6 * 7 * This Source Code Form is subject to the terms of the Mozilla Public 8 * License, v. 2.0. If a copy of the MPL was not distributed with this 9 * file, You can obtain one at http://mozilla.org/MPL/2.0/. 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 * Internet Systems Consortium, Inc. 20 * PO Box 360 21 * Newmarket, NH 03857 USA 22 * <info@isc.org> 23 * http://www.isc.org/ 24 */ 25 26#include <sys/cdefs.h> 27__RCSID("$NetBSD: ns_name.c,v 1.4 2022/04/03 01:10:58 christos Exp $"); 28 29#include <sys/types.h> 30 31#include <netinet/in.h> 32#include <sys/socket.h> 33 34#include <errno.h> 35#include <string.h> 36#include <ctype.h> 37 38#include "ns_name.h" 39#include "arpa/nameser.h" 40 41/* Data. */ 42 43static const char digits[] = "0123456789"; 44 45/* Forward. */ 46 47static int special(int); 48static int printable(int); 49static int dn_find(const u_char *, const u_char *, 50 const u_char * const *, 51 const u_char * const *); 52 53/* Public. */ 54 55/* 56 * MRns_name_len(eom, src) 57 * Compute the length of encoded uncompressed domain name. 58 * return: 59 * -1 if it fails, or to be consumed octets if it succeeds. 60 */ 61int 62MRns_name_len(const u_char *eom, const u_char *src) 63{ 64 const u_char *srcp; 65 unsigned n; 66 int len; 67 68 len = -1; 69 srcp = src; 70 if (srcp >= eom) { 71 errno = EMSGSIZE; 72 return (-1); 73 } 74 /* Fetch next label in domain name. */ 75 while ((n = *srcp++) != 0) { 76 /* Limit checks. */ 77 if (srcp + n >= eom) { 78 errno = EMSGSIZE; 79 return (-1); 80 } 81 srcp += n; 82 } 83 if (len < 0) 84 len = srcp - src; 85 return (len); 86} 87 88/* 89 * MRns_name_ntop(src, dst, dstsiz) 90 * Convert an encoded domain name to printable ascii as per RFC1035. 91 * return: 92 * Number of bytes written to buffer, or -1 (with errno set) 93 * notes: 94 * The root is returned as "." 95 * All other domains are returned in non absolute form 96 */ 97int 98MRns_name_ntop(const u_char *src, char *dst, size_t dstsiz) { 99 const u_char *cp; 100 char *dn, *eom; 101 u_char c; 102 u_int n; 103 104 cp = src; 105 dn = dst; 106 eom = dst + dstsiz; 107 108 while ((n = *cp++) != 0) { 109 if ((n & NS_CMPRSFLGS) != 0) { 110 /* Some kind of compression pointer. */ 111 errno = EMSGSIZE; 112 return (-1); 113 } 114 if (dn != dst) { 115 if (dn >= eom) { 116 errno = EMSGSIZE; 117 return (-1); 118 } 119 *dn++ = '.'; 120 } 121 if (dn + n >= eom) { 122 errno = EMSGSIZE; 123 return (-1); 124 } 125 for ((void)NULL; n > 0; n--) { 126 c = *cp++; 127 if (special(c)) { 128 if (dn + 1 >= eom) { 129 errno = EMSGSIZE; 130 return (-1); 131 } 132 *dn++ = '\\'; 133 *dn++ = (char)c; 134 } else if (!printable(c)) { 135 if (dn + 3 >= eom) { 136 errno = EMSGSIZE; 137 return (-1); 138 } 139 *dn++ = '\\'; 140 *dn++ = digits[c / 100]; 141 *dn++ = digits[(c % 100) / 10]; 142 *dn++ = digits[c % 10]; 143 } else { 144 if (dn >= eom) { 145 errno = EMSGSIZE; 146 return (-1); 147 } 148 *dn++ = (char)c; 149 } 150 } 151 } 152 if (dn == dst) { 153 if (dn >= eom) { 154 errno = EMSGSIZE; 155 return (-1); 156 } 157 *dn++ = '.'; 158 } 159 if (dn >= eom) { 160 errno = EMSGSIZE; 161 return (-1); 162 } 163 *dn++ = '\0'; 164 return (dn - dst); 165} 166 167/* 168 * MRns_name_pton(src, dst, dstsiz) 169 * Convert a ascii string into an encoded domain name as per RFC1035. 170 * return: 171 * -1 if it fails 172 * 1 if string was fully qualified 173 * 0 is string was not fully qualified 174 * notes: 175 * Enforces label and domain length limits. 176 */ 177 178int 179MRns_name_pton(const char *src, u_char *dst, size_t dstsiz) { 180 u_char *label, *bp, *eom; 181 int c, n, escaped; 182 char *cp; 183 184 escaped = 0; 185 bp = dst; 186 eom = dst + dstsiz; 187 label = bp++; 188 189 while ((c = *src++) != 0) { 190 if (escaped) { 191 if ((cp = strchr(digits, c)) != NULL) { 192 n = (cp - digits) * 100; 193 if ((c = *src++) == 0 || 194 (cp = strchr(digits, c)) == NULL) { 195 errno = EMSGSIZE; 196 return (-1); 197 } 198 n += (cp - digits) * 10; 199 if ((c = *src++) == 0 || 200 (cp = strchr(digits, c)) == NULL) { 201 errno = EMSGSIZE; 202 return (-1); 203 } 204 n += (cp - digits); 205 if (n > 255) { 206 errno = EMSGSIZE; 207 return (-1); 208 } 209 c = n; 210 } 211 escaped = 0; 212 } else if (c == '\\') { 213 escaped = 1; 214 continue; 215 } else if (c == '.') { 216 c = (bp - label - 1); 217 if ((c & NS_CMPRSFLGS) != 0) { /* Label too big. */ 218 errno = EMSGSIZE; 219 return (-1); 220 } 221 if (label >= eom) { 222 errno = EMSGSIZE; 223 return (-1); 224 } 225 *label = c; 226 /* Fully qualified ? */ 227 if (*src == '\0') { 228 if (c != 0) { 229 if (bp >= eom) { 230 errno = EMSGSIZE; 231 return (-1); 232 } 233 *bp++ = '\0'; 234 } 235 if ((bp - dst) > MAXCDNAME) { 236 errno = EMSGSIZE; 237 return (-1); 238 } 239 return (1); 240 } 241 if (c == 0 || *src == '.') { 242 errno = EMSGSIZE; 243 return (-1); 244 } 245 label = bp++; 246 continue; 247 } 248 if (bp >= eom) { 249 errno = EMSGSIZE; 250 return (-1); 251 } 252 *bp++ = (u_char)c; 253 } 254 c = (bp - label - 1); 255 if ((c & NS_CMPRSFLGS) != 0) { /* Label too big. */ 256 errno = EMSGSIZE; 257 return (-1); 258 } 259 if (label >= eom) { 260 errno = EMSGSIZE; 261 return (-1); 262 } 263 *label = c; 264 if (c != 0) { 265 if (bp >= eom) { 266 errno = EMSGSIZE; 267 return (-1); 268 } 269 *bp++ = 0; 270 } 271 if ((bp - dst) > MAXCDNAME) { /* src too big */ 272 errno = EMSGSIZE; 273 return (-1); 274 } 275 return (0); 276} 277 278#ifdef notdef 279/* 280 * MRns_name_ntol(src, dst, dstsiz) 281 * Convert a network strings labels into all lowercase. 282 * return: 283 * Number of bytes written to buffer, or -1 (with errno set) 284 * notes: 285 * Enforces label and domain length limits. 286 */ 287 288int 289MRns_name_ntol(const u_char *src, u_char *dst, size_t dstsiz) { 290 const u_char *cp; 291 u_char *dn, *eom; 292 u_char c; 293 u_int n; 294 295 cp = src; 296 dn = dst; 297 eom = dst + dstsiz; 298 299 if (dn >= eom) { 300 errno = EMSGSIZE; 301 return (-1); 302 } 303 while ((n = *cp++) != 0) { 304 if ((n & NS_CMPRSFLGS) != 0) { 305 /* Some kind of compression pointer. */ 306 errno = EMSGSIZE; 307 return (-1); 308 } 309 *dn++ = n; 310 if (dn + n >= eom) { 311 errno = EMSGSIZE; 312 return (-1); 313 } 314 for ((void)NULL; n > 0; n--) { 315 c = *cp++; 316 if (isupper(c)) 317 *dn++ = tolower(c); 318 else 319 *dn++ = c; 320 } 321 } 322 *dn++ = '\0'; 323 return (dn - dst); 324} 325#endif 326 327/* 328 * MRns_name_unpack(msg, eom, src, dst, dstsiz) 329 * Unpack a domain name from a message, source may be compressed. 330 * return: 331 * -1 if it fails, or consumed octets if it succeeds. 332 */ 333int 334MRns_name_unpack(const u_char *msg, const u_char *eom, const u_char *src, 335 u_char *dst, size_t dstsiz) 336{ 337 const u_char *srcp, *dstlim; 338 u_char *dstp; 339 unsigned n; 340 int len; 341 int checked; 342 343 len = -1; 344 checked = 0; 345 dstp = dst; 346 srcp = src; 347 dstlim = dst + dstsiz; 348 if (srcp < msg || srcp >= eom) { 349 errno = EMSGSIZE; 350 return (-1); 351 } 352 /* Fetch next label in domain name. */ 353 while ((n = *srcp++) != 0) { 354 /* Check for indirection. */ 355 switch (n & NS_CMPRSFLGS) { 356 case 0: 357 /* Limit checks. */ 358 if (dstp + n + 1 >= dstlim || srcp + n >= eom) { 359 errno = EMSGSIZE; 360 return (-1); 361 } 362 checked += n + 1; 363 *dstp++ = n; 364 memcpy(dstp, srcp, n); 365 dstp += n; 366 srcp += n; 367 break; 368 369 case NS_CMPRSFLGS: 370 if (srcp >= eom) { 371 errno = EMSGSIZE; 372 return (-1); 373 } 374 if (len < 0) 375 len = srcp - src + 1; 376 n = ((n & 0x3f) << 8) | (*srcp & 0xff); 377 if (n >= eom - msg) { /* Out of range. */ 378 errno = EMSGSIZE; 379 return (-1); 380 } 381 srcp = msg + n; 382 checked += 2; 383 /* 384 * Check for loops in the compressed name; 385 * if we've looked at the whole message, 386 * there must be a loop. 387 */ 388 if (checked >= eom - msg) { 389 errno = EMSGSIZE; 390 return (-1); 391 } 392 break; 393 394 default: 395 errno = EMSGSIZE; 396 return (-1); /* flag error */ 397 } 398 } 399 *dstp = '\0'; 400 if (len < 0) 401 len = srcp - src; 402 return (len); 403} 404 405/* 406 * MRns_name_pack(src, dst, dstsiz, dnptrs, lastdnptr) 407 * Pack domain name 'domain' into 'comp_dn'. 408 * return: 409 * Size of the compressed name, or -1. 410 * notes: 411 * 'dnptrs' is an array of pointers to previous compressed names. 412 * dnptrs[0] is a pointer to the beginning of the message. The array 413 * ends with NULL. 414 * 'lastdnptr' is a pointer to the end of the array pointed to 415 * by 'dnptrs'. 416 * Side effects: 417 * The list of pointers in dnptrs is updated for labels inserted into 418 * the message as we compress the name. If 'dnptr' is NULL, we don't 419 * try to compress names. If 'lastdnptr' is NULL, we don't update the 420 * list. 421 */ 422int 423MRns_name_pack(const u_char *src, u_char *dst, unsigned dstsiz, 424 const u_char **dnptrs, const u_char **lastdnptr) 425{ 426 u_char *dstp; 427 const u_char **cpp, **lpp, *eob, *msg; 428 const u_char *srcp; 429 unsigned n; 430 int l; 431 432 srcp = src; 433 dstp = dst; 434 eob = dstp + dstsiz; 435 lpp = cpp = NULL; 436 if (dnptrs != NULL) { 437 if ((msg = *dnptrs++) != NULL) { 438 for (cpp = dnptrs; *cpp != NULL; cpp++) 439 (void)NULL; 440 lpp = cpp; /* end of list to search */ 441 } 442 } else 443 msg = NULL; 444 445 /* make sure the domain we are about to add is legal */ 446 l = 0; 447 do { 448 n = *srcp; 449 if ((n & NS_CMPRSFLGS) != 0) { 450 errno = EMSGSIZE; 451 return (-1); 452 } 453 l += n + 1; 454 if (l > MAXCDNAME) { 455 errno = EMSGSIZE; 456 return (-1); 457 } 458 srcp += n + 1; 459 } while (n != 0); 460 461 /* from here on we need to reset compression pointer array on error */ 462 srcp = src; 463 do { 464 /* Look to see if we can use pointers. */ 465 n = *srcp; 466 if (n != 0 && msg != NULL) { 467 l = dn_find(srcp, msg, (const u_char * const *)dnptrs, 468 (const u_char * const *)lpp); 469 if (l >= 0) { 470 if (dstp + 1 >= eob) { 471 goto cleanup; 472 } 473 *dstp++ = (l >> 8) | NS_CMPRSFLGS; 474 *dstp++ = l % 256; 475 return (dstp - dst); 476 } 477 /* Not found, save it. */ 478 if (lastdnptr != NULL && cpp < lastdnptr - 1 && 479 (dstp - msg) < 0x4000) { 480 *cpp++ = dstp; 481 *cpp = NULL; 482 } 483 } 484 /* copy label to buffer */ 485 if (n & NS_CMPRSFLGS) { /* Should not happen. */ 486 goto cleanup; 487 } 488 if (dstp + 1 + n >= eob) { 489 goto cleanup; 490 } 491 memcpy(dstp, srcp, n + 1); 492 srcp += n + 1; 493 dstp += n + 1; 494 } while (n != 0); 495 496 if (dstp > eob) { 497cleanup: 498 if (msg != NULL) 499 *lpp = NULL; 500 errno = EMSGSIZE; 501 return (-1); 502 } 503 return (dstp - dst); 504} 505 506/* 507 * MRns_name_uncompress(msg, eom, src, dst, dstsiz) 508 * Expand compressed domain name to presentation format. 509 * return: 510 * Number of bytes read out of `src', or -1 (with errno set). 511 * note: 512 * Root domain returns as "." not "". 513 */ 514static int 515MRns_name_uncompress(const u_char *msg, const u_char *eom, const u_char *src, 516 char *dst, size_t dstsiz) 517{ 518 u_char tmp[NS_MAXCDNAME]; 519 int n; 520 521 if ((n = MRns_name_unpack(msg, eom, src, tmp, sizeof tmp)) == -1) 522 return (-1); 523 if (MRns_name_ntop(tmp, dst, dstsiz) == -1) 524 return (-1); 525 return (n); 526} 527 528/* 529 * MRns_name_compress(src, dst, dstsiz, dnptrs, lastdnptr) 530 * Compress a domain name into wire format, using compression pointers. 531 * return: 532 * Number of bytes consumed in `dst' or -1 (with errno set). 533 * notes: 534 * 'dnptrs' is an array of pointers to previous compressed names. 535 * dnptrs[0] is a pointer to the beginning of the message. 536 * The list ends with NULL. 'lastdnptr' is a pointer to the end of the 537 * array pointed to by 'dnptrs'. Side effect is to update the list of 538 * pointers for labels inserted into the message as we compress the name. 539 * If 'dnptr' is NULL, we don't try to compress names. If 'lastdnptr' 540 * is NULL, we don't update the list. 541 */ 542int 543MRns_name_compress(const char *src, u_char *dst, size_t dstsiz, 544 const u_char **dnptrs, const u_char **lastdnptr) 545{ 546 u_char tmp[NS_MAXCDNAME]; 547 548 if (MRns_name_pton(src, tmp, sizeof tmp) == -1) 549 return (-1); 550 return (MRns_name_pack(tmp, dst, dstsiz, dnptrs, lastdnptr)); 551} 552 553#ifdef notdef 554/* 555 * MRns_name_skip(ptrptr, eom) 556 * Advance *ptrptr to skip over the compressed name it points at. 557 * return: 558 * 0 on success, -1 (with errno set) on failure. 559 */ 560int 561MRns_name_skip(const u_char **ptrptr, const u_char *eom) { 562 const u_char *cp; 563 u_int n; 564 565 cp = *ptrptr; 566 while (cp < eom && (n = *cp++) != 0) { 567 /* Check for indirection. */ 568 switch (n & NS_CMPRSFLGS) { 569 case 0: /* normal case, n == len */ 570 cp += n; 571 continue; 572 case NS_CMPRSFLGS: /* indirection */ 573 cp++; 574 break; 575 default: /* illegal type */ 576 errno = EMSGSIZE; 577 return (-1); 578 } 579 break; 580 } 581 if (cp > eom) { 582 errno = EMSGSIZE; 583 return (-1); 584 } 585 *ptrptr = cp; 586 return (0); 587} 588#endif 589 590/* Private. */ 591 592/* 593 * special(ch) 594 * Thinking in noninternationalized USASCII (per the DNS spec), 595 * is this characted special ("in need of quoting") ? 596 * return: 597 * boolean. 598 */ 599static int 600special(int ch) { 601 switch (ch) { 602 case 0x22: /* '"' */ 603 case 0x2E: /* '.' */ 604 case 0x3B: /* ';' */ 605 case 0x5C: /* '\\' */ 606 /* Special modifiers in zone files. */ 607 case 0x40: /* '@' */ 608 case 0x24: /* '$' */ 609 return (1); 610 default: 611 return (0); 612 } 613} 614 615/* 616 * printable(ch) 617 * Thinking in noninternationalized USASCII (per the DNS spec), 618 * is this character visible and not a space when printed ? 619 * return: 620 * boolean. 621 */ 622static int 623printable(int ch) { 624 return (ch > 0x20 && ch < 0x7f); 625} 626 627/* 628 * Thinking in noninternationalized USASCII (per the DNS spec), 629 * convert this character to lower case if it's upper case. 630 */ 631static int 632mklower(int ch) { 633 if (ch >= 0x41 && ch <= 0x5A) 634 return (ch + 0x20); 635 return (ch); 636} 637 638/* 639 * dn_find(domain, msg, dnptrs, lastdnptr) 640 * Search for the counted-label name in an array of compressed names. 641 * return: 642 * offset from msg if found, or -1. 643 * notes: 644 * dnptrs is the pointer to the first name on the list, 645 * not the pointer to the start of the message. 646 */ 647static int 648dn_find(const u_char *domain, const u_char *msg, 649 const u_char * const *dnptrs, 650 const u_char * const *lastdnptr) 651{ 652 const u_char *dn, *cp, *sp; 653 const u_char * const *cpp; 654 u_int n; 655 656 for (cpp = dnptrs; cpp < lastdnptr; cpp++) { 657 dn = domain; 658 sp = cp = *cpp; 659 while ((n = *cp++) != 0) { 660 /* 661 * check for indirection 662 */ 663 switch (n & NS_CMPRSFLGS) { 664 case 0: /* normal case, n == len */ 665 if (n != *dn++) 666 goto next; 667 for ((void)NULL; n > 0; n--) 668 if (mklower(*dn++) != mklower(*cp++)) 669 goto next; 670 /* Is next root for both ? */ 671 if (*dn == '\0' && *cp == '\0') 672 return (sp - msg); 673 if (*dn) 674 continue; 675 goto next; 676 677 case NS_CMPRSFLGS: /* indirection */ 678 cp = msg + (((n & 0x3f) << 8) | *cp); 679 break; 680 681 default: /* illegal type */ 682 errno = EMSGSIZE; 683 return (-1); 684 } 685 } 686 next: ; 687 } 688 errno = ENOENT; 689 return (-1); 690} 691 692/*! 693 * \brief Creates a string of comma-separated domain-names from a 694 * compressed list 695 * 696 * Produces a null-terminated string of comma-separated domain-names from 697 * a buffer containing a compressed list of domain-names. The names will 698 * be dotted and without enclosing quotes. For example: 699 * If a compressed list contains the follwoing two domain names: 700 * 701 * a. one.two.com 702 * b. three.four.com 703 * 704 * The compressed data will look like this: 705 * 706 * 03 6f 6e 65 03 74 77 6f 03 63 6f 6d 00 05 74 68 707 * 72 65 65 04 66 6f 75 72 c0 08 708 * 709 * and will decompress into: 710 * 711 * one.two.com,three.four.com 712 * 713 * \param buf - buffer containing the compressed list of domain-names 714 * \param buflen - length of compressed list of domain-names 715 * \param dst_buf - buffer to receive the decompressed list 716 * \param dst_size - size of the destination buffer 717 * 718 * \return the length of the decompressed string when successful, -1 on 719 * error. 720 */ 721int MRns_name_uncompress_list(const unsigned char* buf, int buflen, 722 char* dst_buf, size_t dst_size) 723{ 724 const unsigned char* src = buf; 725 char* dst = dst_buf; 726 int consumed = 1; 727 int dst_remaining = dst_size; 728 int added_len = 0; 729 int first_pass = 1; 730 731 if (!buf || buflen == 0 || *buf == 0x00) { 732 /* nothing to do */ 733 *dst = 0; 734 return (0); 735 } 736 737 while ((consumed > 0) && (src < (buf + buflen))) 738 { 739 if (dst_remaining <= 0) { 740 errno = EMSGSIZE; 741 return (-1); 742 } 743 744 if (!first_pass) { 745 *dst++ = ','; 746 *dst = '\0'; 747 dst_remaining--; 748 } 749 750 consumed = MRns_name_uncompress(buf, buf + buflen, src, 751 dst, dst_remaining); 752 if (consumed < 0) { 753 return (-1); 754 } 755 756 src += consumed; 757 added_len = strlen(dst); 758 dst_remaining -= added_len; 759 dst += added_len; 760 first_pass = 0; 761 } 762 *dst='\0'; 763 764 /* return the length of the uncompressed list string */ 765 return (strlen(dst_buf)); 766} 767 768/*! 769 * \brief Creates a compressed list from a string of comma-separated 770 * domain-names 771 * 772 * Produces a buffer containing a compressed data version of a list of 773 * domain-names extracted from a comma-separated string. Given a string 774 * containing: 775 * 776 * one.two.com,three.four.com 777 * 778 * It will compress this into: 779 * 780 * 03 6f 6e 65 03 74 77 6f 03 63 6f 6d 00 05 74 68 781 * 72 65 65 04 66 6f 75 72 c0 08 782 * 783 * \param buf - buffer containing the uncompressed string of domain-names 784 * \param buflen - length of uncompressed string of domain-names 785 * \param compbuf - buffer to receive the compressed list 786 * \param compbuf_size - size of the compression buffer 787 * 788 * \return the length of the compressed data when successful, -1 on error. 789 */ 790int MRns_name_compress_list(const char* buf, int buflen, 791 unsigned char* compbuf, size_t compbuf_size) 792{ 793 char cur_name[NS_MAXCDNAME]; 794 const unsigned char *dnptrs[256], **lastdnptr; 795 const char* src; 796 const char* src_end; 797 unsigned clen = 0; 798 int result = 0; 799 800 memset(compbuf, 0, compbuf_size); 801 memset(dnptrs, 0, sizeof(dnptrs)); 802 dnptrs[0] = compbuf; 803 lastdnptr = &dnptrs[255]; 804 805 src = buf; 806 src_end = buf + buflen; 807 while (src < src_end) { 808 char *comma = strchr(src, ','); 809 int copylen = ((comma != NULL) ? comma - src : strlen(src)); 810 if (copylen > (sizeof(cur_name) - 1)) { 811 errno = EMSGSIZE; 812 return (-1); 813 } 814 815 memcpy(cur_name, src, copylen); 816 cur_name[copylen] = '\0'; 817 src += copylen + 1; 818 819 result = MRns_name_compress(cur_name, compbuf + clen, 820 compbuf_size - clen, 821 dnptrs, lastdnptr); 822 823 if (result < 0) { 824 return (-1); 825 } 826 827 clen += result; 828 } 829 830 /* return size of compressed list */ 831 return(clen); 832} 833