libspf2  1.2.11
__ns_name_uncompress.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 1996,1999 by Internet Software Consortium.
3  *
4  * Permission to use, copy, modify, and distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
9  * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
10  * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
11  * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
12  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
13  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
14  * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
15  * SOFTWARE.
16  */
17 
18 #ifndef lint
19 static const char rcsid[] = "$Id: ns_name.c,v 1.3.2.4 2003/07/02 04:10:27 marka Exp $";
20 #endif
21 
22 /* #include "port_before.h" */
23 #include "config.h"
24 
25 #ifdef STDC_HEADERS
26 # include <stdio.h>
27 #endif
28 
29 #include <sys/types.h>
30 
31 #include <netinet/in.h>
32 #include "arpa_nameser.h"
33 
34 #include <errno.h>
35 /* #include <resolv.h> */
36 #ifdef HAVE_STRING_H
37 # include <string.h> /* strstr / strdup */
38 #else
39 # ifdef HAVE_STRINGS_H
40 # include <strings.h> /* strstr / strdup */
41 # endif
42 #endif
43 
44 #include <ctype.h>
45 #include <stdlib.h>
46 #include <limits.h>
47 
48 /* #include "port_after.h" */
49 
50 #ifdef SPRINTF_CHAR
51 # define SPRINTF(x) strlen(sprintfx)
52 #else
53 # define SPRINTF(x) ((size_t)sprintf x)
54 #endif
55 
56 #define NS_TYPE_ELT 0x40 /* EDNS0 extended label type */
57 #define DNS_LABELTYPE_BITSTRING 0x41
58 
59 /* Data. */
60 
61 static const char digits[] = "0123456789";
62 
63 static const char digitvalue[256] = {
64  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*16*/
65  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*32*/
66  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*48*/
67  0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, /*64*/
68  -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*80*/
69  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*96*/
70  -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*112*/
71  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*128*/
72  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
73  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
74  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
75  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
76  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
77  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
78  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
79  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*256*/
80 };
81 
82 /* Forward. */
83 
84 static int special(int);
85 static int printable(int);
86 static int dn_find(const u_char *, const u_char *,
87  const u_char * const *,
88  const u_char * const *);
89 static int encode_bitsring(const char **, const char *,
90  char **, char **, const char *);
91 static int labellen(const u_char *);
92 static int decode_bitstring(const char **, char *, const char *);
93 
94 /* Public. */
95 
96 /*
97  * ns_name_ntop(src, dst, dstsiz)
98  * Convert an encoded domain name to printable ascii as per RFC1035.
99  * return:
100  * Number of bytes written to buffer, or -1 (with errno set)
101  * notes:
102  * The root is returned as "."
103  * All other domains are returned in non absolute form
104  */
105 int
106 ns_name_ntop(const u_char *src, char *dst, size_t dstsiz)
107 {
108  const u_char *cp;
109  char *dn, *eom;
110  u_char c;
111  u_int n;
112  int l;
113 
114  cp = src;
115  dn = dst;
116  eom = dst + dstsiz;
117 
118  while ((n = *cp++) != 0) {
119  if ((n & NS_CMPRSFLGS) == NS_CMPRSFLGS) {
120  /* Some kind of compression pointer. */
121  errno = EMSGSIZE;
122  return (-1);
123  }
124  if (dn != dst) {
125  if (dn >= eom) {
126  errno = EMSGSIZE;
127  return (-1);
128  }
129  *dn++ = '.';
130  }
131  if ((l = labellen(cp - 1)) < 0) {
132  errno = EMSGSIZE; /* XXX */
133  return(-1);
134  }
135  if (dn + l >= eom) {
136  errno = EMSGSIZE;
137  return (-1);
138  }
139  if ((n & NS_CMPRSFLGS) == NS_TYPE_ELT) {
140  int m;
141 
142  if (n != DNS_LABELTYPE_BITSTRING) {
143  /* XXX: labellen should reject this case */
144  errno = EINVAL;
145  return(-1);
146  }
147  if ((m = decode_bitstring((const char **)&cp, dn, eom)) < 0)
148  {
149  errno = EMSGSIZE;
150  return(-1);
151  }
152  dn += m;
153  continue;
154  }
155  for ((void)NULL; l > 0; l--) {
156  c = *cp++;
157  if (special(c)) {
158  if (dn + 1 >= eom) {
159  errno = EMSGSIZE;
160  return (-1);
161  }
162  *dn++ = '\\';
163  *dn++ = (char)c;
164  } else if (!printable(c)) {
165  if (dn + 3 >= eom) {
166  errno = EMSGSIZE;
167  return (-1);
168  }
169  *dn++ = '\\';
170  *dn++ = digits[c / 100];
171  *dn++ = digits[(c % 100) / 10];
172  *dn++ = digits[c % 10];
173  } else {
174  if (dn >= eom) {
175  errno = EMSGSIZE;
176  return (-1);
177  }
178  *dn++ = (char)c;
179  }
180  }
181  }
182  if (dn == dst) {
183  if (dn >= eom) {
184  errno = EMSGSIZE;
185  return (-1);
186  }
187  *dn++ = '.';
188  }
189  if (dn >= eom) {
190  errno = EMSGSIZE;
191  return (-1);
192  }
193  *dn++ = '\0';
194  return (dn - dst);
195 }
196 
197 /*
198  * ns_name_pton(src, dst, dstsiz)
199  * Convert a ascii string into an encoded domain name as per RFC1035.
200  * return:
201  * -1 if it fails
202  * 1 if string was fully qualified
203  * 0 is string was not fully qualified
204  * notes:
205  * Enforces label and domain length limits.
206  */
207 
208 int
209 ns_name_pton(const char *src, u_char *dst, size_t dstsiz)
210 {
211  u_char *label, *bp, *eom;
212  int c, n, escaped, e = 0;
213  char *cp;
214 
215  escaped = 0;
216  bp = dst;
217  eom = dst + dstsiz;
218  label = bp++;
219 
220  while ((c = *src++) != 0) {
221  if (escaped) {
222  if (c == '[') { /* start a bit string label */
223  if ((cp = strchr(src, ']')) == NULL) {
224  errno = EINVAL; /* ??? */
225  return(-1);
226  }
227  if ((e = encode_bitsring(&src,
228  cp + 2,
229  (char **)&label,
230  (char **)&bp,
231  (const char *)eom))
232  != 0) {
233  errno = e;
234  return(-1);
235  }
236  escaped = 0;
237  label = bp++;
238  if ((c = *src++) == 0)
239  goto done;
240  else if (c != '.') {
241  errno = EINVAL;
242  return(-1);
243  }
244  continue;
245  }
246  else if ((cp = strchr(digits, c)) != NULL) {
247  n = (cp - digits) * 100;
248  if ((c = *src++) == 0 ||
249  (cp = strchr(digits, c)) == NULL) {
250  errno = EMSGSIZE;
251  return (-1);
252  }
253  n += (cp - digits) * 10;
254  if ((c = *src++) == 0 ||
255  (cp = strchr(digits, c)) == NULL) {
256  errno = EMSGSIZE;
257  return (-1);
258  }
259  n += (cp - digits);
260  if (n > 255) {
261  errno = EMSGSIZE;
262  return (-1);
263  }
264  c = n;
265  }
266  escaped = 0;
267  } else if (c == '\\') {
268  escaped = 1;
269  continue;
270  } else if (c == '.') {
271  c = (bp - label - 1);
272  if ((c & NS_CMPRSFLGS) != 0) { /* Label too big. */
273  errno = EMSGSIZE;
274  return (-1);
275  }
276  if (label >= eom) {
277  errno = EMSGSIZE;
278  return (-1);
279  }
280  *label = c;
281  /* Fully qualified ? */
282  if (*src == '\0') {
283  if (c != 0) {
284  if (bp >= eom) {
285  errno = EMSGSIZE;
286  return (-1);
287  }
288  *bp++ = '\0';
289  }
290  if ((bp - dst) > NS_MAXCDNAME) {
291  errno = EMSGSIZE;
292  return (-1);
293  }
294  return (1);
295  }
296  if (c == 0 || *src == '.') {
297  errno = EMSGSIZE;
298  return (-1);
299  }
300  label = bp++;
301  continue;
302  }
303  if (bp >= eom) {
304  errno = EMSGSIZE;
305  return (-1);
306  }
307  *bp++ = (u_char)c;
308  }
309  c = (bp - label - 1);
310  if ((c & NS_CMPRSFLGS) != 0) { /* Label too big. */
311  errno = EMSGSIZE;
312  return (-1);
313  }
314  done:
315  if (label >= eom) {
316  errno = EMSGSIZE;
317  return (-1);
318  }
319  *label = c;
320  if (c != 0) {
321  if (bp >= eom) {
322  errno = EMSGSIZE;
323  return (-1);
324  }
325  *bp++ = 0;
326  }
327  if ((bp - dst) > NS_MAXCDNAME) { /* src too big */
328  errno = EMSGSIZE;
329  return (-1);
330  }
331  return (0);
332 }
333 
334 /*
335  * ns_name_ntol(src, dst, dstsiz)
336  * Convert a network strings labels into all lowercase.
337  * return:
338  * Number of bytes written to buffer, or -1 (with errno set)
339  * notes:
340  * Enforces label and domain length limits.
341  */
342 
343 int
344 ns_name_ntol(const u_char *src, u_char *dst, size_t dstsiz)
345 {
346  const u_char *cp;
347  u_char *dn, *eom;
348  u_char c;
349  u_int n;
350  int l;
351 
352  cp = src;
353  dn = dst;
354  eom = dst + dstsiz;
355 
356  if (dn >= eom) {
357  errno = EMSGSIZE;
358  return (-1);
359  }
360  while ((n = *cp++) != 0) {
361  if ((n & NS_CMPRSFLGS) == NS_CMPRSFLGS) {
362  /* Some kind of compression pointer. */
363  errno = EMSGSIZE;
364  return (-1);
365  }
366  *dn++ = n;
367  if ((l = labellen(cp - 1)) < 0) {
368  errno = EMSGSIZE;
369  return (-1);
370  }
371  if (dn + l >= eom) {
372  errno = EMSGSIZE;
373  return (-1);
374  }
375  for ((void)NULL; l > 0; l--) {
376  c = *cp++;
377  if (isupper(c))
378  *dn++ = tolower(c);
379  else
380  *dn++ = c;
381  }
382  }
383  *dn++ = '\0';
384  return (dn - dst);
385 }
386 
387 /*
388  * ns_name_unpack(msg, eom, src, dst, dstsiz)
389  * Unpack a domain name from a message, source may be compressed.
390  * return:
391  * -1 if it fails, or consumed octets if it succeeds.
392  */
393 int
394 ns_name_unpack(const u_char *msg, const u_char *eom, const u_char *src,
395  u_char *dst, size_t dstsiz)
396 {
397  const u_char *srcp, *dstlim;
398  u_char *dstp;
399  int n, len, checked, l;
400 
401  len = -1;
402  checked = 0;
403  dstp = dst;
404  srcp = src;
405  dstlim = dst + dstsiz;
406  if (srcp < msg || srcp >= eom) {
407  errno = EMSGSIZE;
408  return (-1);
409  }
410  /* Fetch next label in domain name. */
411  while ((n = *srcp++) != 0) {
412  /* Check for indirection. */
413  switch (n & NS_CMPRSFLGS) {
414  case 0:
415  case NS_TYPE_ELT:
416  /* Limit checks. */
417  if ((l = labellen(srcp - 1)) < 0) {
418  errno = EMSGSIZE;
419  return(-1);
420  }
421  if (dstp + l + 1 >= dstlim || srcp + l >= eom) {
422  errno = EMSGSIZE;
423  return (-1);
424  }
425  checked += l + 1;
426  *dstp++ = n;
427  memcpy(dstp, srcp, l);
428  dstp += l;
429  srcp += l;
430  break;
431 
432  case NS_CMPRSFLGS:
433  if (srcp >= eom) {
434  errno = EMSGSIZE;
435  return (-1);
436  }
437  if (len < 0)
438  len = srcp - src + 1;
439  srcp = msg + (((n & 0x3f) << 8) | (*srcp & 0xff));
440  if (srcp < msg || srcp >= eom) { /* Out of range. */
441  errno = EMSGSIZE;
442  return (-1);
443  }
444  checked += 2;
445  /*
446  * Check for loops in the compressed name;
447  * if we've looked at the whole message,
448  * there must be a loop.
449  */
450  if (checked >= eom - msg) {
451  errno = EMSGSIZE;
452  return (-1);
453  }
454  break;
455 
456  default:
457  errno = EMSGSIZE;
458  return (-1); /* flag error */
459  }
460  }
461  *dstp = '\0';
462  if (len < 0)
463  len = srcp - src;
464  return (len);
465 }
466 
467 /*
468  * ns_name_pack(src, dst, dstsiz, dnptrs, lastdnptr)
469  * Pack domain name 'domain' into 'comp_dn'.
470  * return:
471  * Size of the compressed name, or -1.
472  * notes:
473  * 'dnptrs' is an array of pointers to previous compressed names.
474  * dnptrs[0] is a pointer to the beginning of the message. The array
475  * ends with NULL.
476  * 'lastdnptr' is a pointer to the end of the array pointed to
477  * by 'dnptrs'.
478  * Side effects:
479  * The list of pointers in dnptrs is updated for labels inserted into
480  * the message as we compress the name. If 'dnptr' is NULL, we don't
481  * try to compress names. If 'lastdnptr' is NULL, we don't update the
482  * list.
483  */
484 int
485 ns_name_pack(const u_char *src, u_char *dst, int dstsiz,
486  const u_char **dnptrs, const u_char **lastdnptr)
487 {
488  u_char *dstp;
489  const u_char **cpp, **lpp, *eob, *msg;
490  const u_char *srcp;
491  int n, l, first = 1;
492 
493  srcp = src;
494  dstp = dst;
495  eob = dstp + dstsiz;
496  lpp = cpp = NULL;
497  if (dnptrs != NULL) {
498  if ((msg = *dnptrs++) != NULL) {
499  for (cpp = dnptrs; *cpp != NULL; cpp++)
500  (void)NULL;
501  lpp = cpp; /* end of list to search */
502  }
503  } else
504  msg = NULL;
505 
506  /* make sure the domain we are about to add is legal */
507  l = 0;
508  do {
509  int l0;
510 
511  n = *srcp;
512  if ((n & NS_CMPRSFLGS) == NS_CMPRSFLGS) {
513  errno = EMSGSIZE;
514  return (-1);
515  }
516  if ((l0 = labellen(srcp)) < 0) {
517  errno = EINVAL;
518  return(-1);
519  }
520  l += l0 + 1;
521  if (l > NS_MAXCDNAME) {
522  errno = EMSGSIZE;
523  return (-1);
524  }
525  srcp += l0 + 1;
526  } while (n != 0);
527 
528  /* from here on we need to reset compression pointer array on error */
529  srcp = src;
530  do {
531  /* Look to see if we can use pointers. */
532  n = *srcp;
533  if (n != 0 && msg != NULL) {
534  l = dn_find(srcp, msg, (const u_char * const *)dnptrs,
535  (const u_char * const *)lpp);
536  if (l >= 0) {
537  if (dstp + 1 >= eob) {
538  goto cleanup;
539  }
540  *dstp++ = (l >> 8) | NS_CMPRSFLGS;
541  *dstp++ = l % 256;
542  return (dstp - dst);
543  }
544  /* Not found, save it. */
545  if (lastdnptr != NULL && cpp < lastdnptr - 1 &&
546  (dstp - msg) < 0x4000 && first) {
547  *cpp++ = dstp;
548  *cpp = NULL;
549  first = 0;
550  }
551  }
552  /* copy label to buffer */
553  if ((n & NS_CMPRSFLGS) == NS_CMPRSFLGS) {
554  /* Should not happen. */
555  goto cleanup;
556  }
557  n = labellen(srcp);
558  if (dstp + 1 + n >= eob) {
559  goto cleanup;
560  }
561  memcpy(dstp, srcp, n + 1);
562  srcp += n + 1;
563  dstp += n + 1;
564  } while (n != 0);
565 
566  if (dstp > eob) {
567 cleanup:
568  if (msg != NULL)
569  *lpp = NULL;
570  errno = EMSGSIZE;
571  return (-1);
572  }
573  return (dstp - dst);
574 }
575 
576 /*
577  * ns_name_uncompress(msg, eom, src, dst, dstsiz)
578  * Expand compressed domain name to presentation format.
579  * return:
580  * Number of bytes read out of `src', or -1 (with errno set).
581  * note:
582  * Root domain returns as "." not "".
583  */
584 int
585 ns_name_uncompress(const u_char *msg, const u_char *eom, const u_char *src,
586  char *dst, size_t dstsiz)
587 {
588  u_char tmp[NS_MAXCDNAME];
589  int n;
590 
591  if ((n = ns_name_unpack(msg, eom, src, tmp, sizeof tmp)) == -1)
592  return (-1);
593  if (ns_name_ntop(tmp, dst, dstsiz) == -1)
594  return (-1);
595  return (n);
596 }
597 
598 /*
599  * ns_name_compress(src, dst, dstsiz, dnptrs, lastdnptr)
600  * Compress a domain name into wire format, using compression pointers.
601  * return:
602  * Number of bytes consumed in `dst' or -1 (with errno set).
603  * notes:
604  * 'dnptrs' is an array of pointers to previous compressed names.
605  * dnptrs[0] is a pointer to the beginning of the message.
606  * The list ends with NULL. 'lastdnptr' is a pointer to the end of the
607  * array pointed to by 'dnptrs'. Side effect is to update the list of
608  * pointers for labels inserted into the message as we compress the name.
609  * If 'dnptr' is NULL, we don't try to compress names. If 'lastdnptr'
610  * is NULL, we don't update the list.
611  */
612 int
613 ns_name_compress(const char *src, u_char *dst, size_t dstsiz,
614  const u_char **dnptrs, const u_char **lastdnptr)
615 {
616  u_char tmp[NS_MAXCDNAME];
617 
618  if (ns_name_pton(src, tmp, sizeof tmp) == -1)
619  return (-1);
620  return (ns_name_pack(tmp, dst, dstsiz, dnptrs, lastdnptr));
621 }
622 
623 /*
624  * Reset dnptrs so that there are no active references to pointers at or
625  * after src.
626  */
627 void
628 ns_name_rollback(const u_char *src, const u_char **dnptrs,
629  const u_char **lastdnptr)
630 {
631  while (dnptrs < lastdnptr && *dnptrs != NULL) {
632  if (*dnptrs >= src) {
633  *dnptrs = NULL;
634  break;
635  }
636  dnptrs++;
637  }
638 }
639 
640 /*
641  * ns_name_skip(ptrptr, eom)
642  * Advance *ptrptr to skip over the compressed name it points at.
643  * return:
644  * 0 on success, -1 (with errno set) on failure.
645  */
646 int
647 ns_name_skip(const u_char **ptrptr, const u_char *eom)
648 {
649  const u_char *cp;
650  u_int n;
651  int l;
652 
653  cp = *ptrptr;
654  while (cp < eom && (n = *cp++) != 0) {
655  /* Check for indirection. */
656  switch (n & NS_CMPRSFLGS) {
657  case 0: /* normal case, n == len */
658  cp += n;
659  continue;
660  case NS_TYPE_ELT: /* EDNS0 extended label */
661  if ((l = labellen(cp - 1)) < 0) {
662  errno = EMSGSIZE; /* XXX */
663  return(-1);
664  }
665  cp += l;
666  continue;
667  case NS_CMPRSFLGS: /* indirection */
668  cp++;
669  break;
670  default: /* illegal type */
671  errno = EMSGSIZE;
672  return (-1);
673  }
674  break;
675  }
676  if (cp > eom) {
677  errno = EMSGSIZE;
678  return (-1);
679  }
680  *ptrptr = cp;
681  return (0);
682 }
683 
684 /* Private. */
685 
686 /*
687  * special(ch)
688  * Thinking in noninternationalized USASCII (per the DNS spec),
689  * is this characted special ("in need of quoting") ?
690  * return:
691  * boolean.
692  */
693 static int
694 special(int ch) {
695  switch (ch) {
696  case 0x22: /* '"' */
697  case 0x2E: /* '.' */
698  case 0x3B: /* ';' */
699  case 0x5C: /* '\\' */
700  case 0x28: /* '(' */
701  case 0x29: /* ')' */
702  /* Special modifiers in zone files. */
703  case 0x40: /* '@' */
704  case 0x24: /* '$' */
705  return (1);
706  default:
707  return (0);
708  }
709 }
710 
711 /*
712  * printable(ch)
713  * Thinking in noninternationalized USASCII (per the DNS spec),
714  * is this character visible and not a space when printed ?
715  * return:
716  * boolean.
717  */
718 static int
719 printable(int ch) {
720  return (ch > 0x20 && ch < 0x7f);
721 }
722 
723 /*
724  * Thinking in noninternationalized USASCII (per the DNS spec),
725  * convert this character to lower case if it's upper case.
726  */
727 static int
728 mklower(int ch) {
729  if (ch >= 0x41 && ch <= 0x5A)
730  return (ch + 0x20);
731  return (ch);
732 }
733 
734 /*
735  * dn_find(domain, msg, dnptrs, lastdnptr)
736  * Search for the counted-label name in an array of compressed names.
737  * return:
738  * offset from msg if found, or -1.
739  * notes:
740  * dnptrs is the pointer to the first name on the list,
741  * not the pointer to the start of the message.
742  */
743 static int
744 dn_find(const u_char *domain, const u_char *msg,
745  const u_char * const *dnptrs,
746  const u_char * const *lastdnptr)
747 {
748  const u_char *dn, *cp, *sp;
749  const u_char * const *cpp;
750  u_int n;
751 
752  for (cpp = dnptrs; cpp < lastdnptr; cpp++) {
753  sp = *cpp;
754  /*
755  * terminate search on:
756  * root label
757  * compression pointer
758  * unusable offset
759  */
760  while (*sp != 0 && (*sp & NS_CMPRSFLGS) == 0 &&
761  (sp - msg) < 0x4000) {
762  dn = domain;
763  cp = sp;
764  while ((n = *cp++) != 0) {
765  /*
766  * check for indirection
767  */
768  switch (n & NS_CMPRSFLGS) {
769  case 0: /* normal case, n == len */
770  n = labellen(cp - 1); /* XXX */
771 
772  if (n != *dn++)
773  goto next;
774 
775  for ((void)NULL; n > 0; n--)
776  if (mklower(*dn++) !=
777  mklower(*cp++))
778  goto next;
779  /* Is next root for both ? */
780  if (*dn == '\0' && *cp == '\0')
781  return (sp - msg);
782  if (*dn)
783  continue;
784  goto next;
785  case NS_CMPRSFLGS: /* indirection */
786  cp = msg + (((n & 0x3f) << 8) | *cp);
787  break;
788 
789  default: /* illegal type */
790  errno = EMSGSIZE;
791  return (-1);
792  }
793  }
794  next: ;
795  sp += *sp + 1;
796  }
797  }
798  errno = ENOENT;
799  return (-1);
800 }
801 
802 static int
803 decode_bitstring(const char **cpp, char *dn, const char *eom)
804 {
805  const char *cp = *cpp;
806  char *beg = dn, tc;
807  int b, blen, plen, i;
808 
809  if ((blen = (*cp & 0xff)) == 0)
810  blen = 256;
811  plen = (blen + 3) / 4;
812  plen += sizeof("\\[x/]") + (blen > 99 ? 3 : (blen > 9) ? 2 : 1);
813  if (dn + plen >= eom)
814  return(-1);
815 
816  cp++;
817  i = SPRINTF((dn, "\\[x"));
818  if (i < 0)
819  return (-1);
820  dn += i;
821  for (b = blen; b > 7; b -= 8, cp++) {
822  i = SPRINTF((dn, "%02x", *cp & 0xff));
823  if (i < 0)
824  return (-1);
825  dn += i;
826  }
827  if (b > 4) {
828  tc = *cp++;
829  i = SPRINTF((dn, "%02x", tc & (0xff << (8 - b))));
830  if (i < 0)
831  return (-1);
832  dn += i;
833  } else if (b > 0) {
834  tc = *cp++;
835  i = SPRINTF((dn, "%1x",
836  ((tc >> 4) & 0x0f) & (0x0f << (4 - b))));
837  if (i < 0)
838  return (-1);
839  dn += i;
840  }
841  i = SPRINTF((dn, "/%d]", blen));
842  if (i < 0)
843  return (-1);
844  dn += i;
845 
846  *cpp = cp;
847  return(dn - beg);
848 }
849 
850 static int
851 encode_bitsring(const char **bp, const char *end, char **labelp,
852  char ** dst, const char *eom)
853 {
854  int afterslash = 0;
855  const char *cp = *bp;
856  char *tp, c;
857  const char *beg_blen;
858  char *end_blen = NULL;
859  int value = 0, count = 0, tbcount = 0, blen = 0;
860 
861  beg_blen = end_blen = NULL;
862 
863  /* a bitstring must contain at least 2 characters */
864  if (end - cp < 2)
865  return(EINVAL);
866 
867  /* XXX: currently, only hex strings are supported */
868  if (*cp++ != 'x')
869  return(EINVAL);
870  if (!isxdigit((*cp) & 0xff)) /* reject '\[x/BLEN]' */
871  return(EINVAL);
872 
873  for (tp = *dst + 1; cp < end && tp < eom; cp++) {
874  switch((c = *cp)) {
875  case ']': /* end of the bitstring */
876  if (afterslash) {
877  if (beg_blen == NULL)
878  return(EINVAL);
879  blen = (int)strtol(beg_blen, &end_blen, 10);
880  if (*end_blen != ']')
881  return(EINVAL);
882  }
883  if (count)
884  *tp++ = ((value << 4) & 0xff);
885  cp++; /* skip ']' */
886  goto done;
887  case '/':
888  afterslash = 1;
889  break;
890  default:
891  if (afterslash) {
892  if (!isdigit(c&0xff))
893  return(EINVAL);
894  if (beg_blen == NULL) {
895 
896  if (c == '0') {
897  /* blen never begings with 0 */
898  return(EINVAL);
899  }
900  beg_blen = cp;
901  }
902  } else {
903  if (!isxdigit(c&0xff))
904  return(EINVAL);
905  value <<= 4;
906  value += digitvalue[(int)c];
907  count += 4;
908  tbcount += 4;
909  if (tbcount > 256)
910  return(EINVAL);
911  if (count == 8) {
912  *tp++ = value;
913  count = 0;
914  }
915  }
916  break;
917  }
918  }
919  done:
920  if (cp >= end || tp >= eom)
921  return(EMSGSIZE);
922 
923  /*
924  * bit length validation:
925  * If a <length> is present, the number of digits in the <bit-data>
926  * MUST be just sufficient to contain the number of bits specified
927  * by the <length>. If there are insignificant bits in a final
928  * hexadecimal or octal digit, they MUST be zero.
929  * RFC 2673, Section 3.2.
930  */
931  if (blen > 0) {
932  int traillen;
933 
934  if (((blen + 3) & ~3) != tbcount)
935  return(EINVAL);
936  traillen = tbcount - blen; /* between 0 and 3 */
937  if (((value << (8 - traillen)) & 0xff) != 0)
938  return(EINVAL);
939  }
940  else
941  blen = tbcount;
942  if (blen == 256)
943  blen = 0;
944 
945  /* encode the type and the significant bit fields */
946  **labelp = DNS_LABELTYPE_BITSTRING;
947  **dst = blen;
948 
949  *bp = cp;
950  *dst = tp;
951 
952  return(0);
953 }
954 
955 static int
956 labellen(const u_char *lp)
957 {
958  int bitlen;
959  u_char l = *lp;
960 
961  if ((l & NS_CMPRSFLGS) == NS_CMPRSFLGS) {
962  /* should be avoided by the caller */
963  return(-1);
964  }
965 
966  if ((l & NS_CMPRSFLGS) == NS_TYPE_ELT) {
967  if (l == DNS_LABELTYPE_BITSTRING) {
968  if ((bitlen = *(lp + 1)) == 0)
969  bitlen = 256;
970  return((bitlen + 7 ) / 8 + 1);
971  }
972  return(-1); /* unknwon ELT */
973  }
974  return(l);
975 }
#define DNS_LABELTYPE_BITSTRING
int ns_name_unpack(const u_char *msg, const u_char *eom, const u_char *src, u_char *dst, size_t dstsiz)
int ns_name_ntop(const u_char *src, char *dst, size_t dstsiz)
#define NS_CMPRSFLGS
Definition: arpa_nameser.h:139
void ns_name_rollback(const u_char *src, const u_char **dnptrs, const u_char **lastdnptr)
size_t len
Definition: memcmp.c:10
int ns_name_skip(const u_char **ptrptr, const u_char *eom)
int ns_name_ntol(const u_char *src, u_char *dst, size_t dstsiz)
int ns_name_pton(const char *src, u_char *dst, size_t dstsiz)
#define NULL
Definition: spf_internal.h:28
#define NS_MAXCDNAME
Definition: arpa_nameser.h:129
#define SPRINTF(x)
#define NS_TYPE_ELT
int ns_name_pack(const u_char *src, u_char *dst, int dstsiz, const u_char **dnptrs, const u_char **lastdnptr)
int ns_name_compress(const char *src, u_char *dst, size_t dstsiz, const u_char **dnptrs, const u_char **lastdnptr)
u_int const u_char * src
Definition: __ns_get16.c:16
int ns_name_uncompress(const u_char *msg, const u_char *eom, const u_char *src, char *dst, size_t dstsiz)