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
43 static const char digits[] = "0123456789";
44
45 /* Forward. */
46
47 static int special(int);
48 static int printable(int);
49 static 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 */
61 int
MRns_name_len(const u_char * eom,const u_char * src)62 MRns_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 */
97 int
MRns_name_ntop(const u_char * src,char * dst,size_t dstsiz)98 MRns_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
178 int
MRns_name_pton(const char * src,u_char * dst,size_t dstsiz)179 MRns_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
288 int
MRns_name_ntol(const u_char * src,u_char * dst,size_t dstsiz)289 MRns_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 */
333 int
MRns_name_unpack(const u_char * msg,const u_char * eom,const u_char * src,u_char * dst,size_t dstsiz)334 MRns_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 */
422 int
MRns_name_pack(const u_char * src,u_char * dst,unsigned dstsiz,const u_char ** dnptrs,const u_char ** lastdnptr)423 MRns_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) {
497 cleanup:
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 */
514 static int
MRns_name_uncompress(const u_char * msg,const u_char * eom,const u_char * src,char * dst,size_t dstsiz)515 MRns_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 */
542 int
MRns_name_compress(const char * src,u_char * dst,size_t dstsiz,const u_char ** dnptrs,const u_char ** lastdnptr)543 MRns_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 */
560 int
MRns_name_skip(const u_char ** ptrptr,const u_char * eom)561 MRns_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 */
599 static int
special(int ch)600 special(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 */
622 static int
printable(int ch)623 printable(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 */
631 static int
mklower(int ch)632 mklower(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 */
647 static int
dn_find(const u_char * domain,const u_char * msg,const u_char * const * dnptrs,const u_char * const * lastdnptr)648 dn_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 */
MRns_name_uncompress_list(const unsigned char * buf,int buflen,char * dst_buf,size_t dst_size)721 int 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 */
MRns_name_compress_list(const char * buf,int buflen,unsigned char * compbuf,size_t compbuf_size)790 int 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