1 /* De-compressing DNS domain names into binary-encoded uncompressed name.
2  * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
3  * Copyright (c) 1996,1999 by Internet Software Consortium.
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
15  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17 
18 #include <arpa/nameser.h>
19 #include <errno.h>
20 #include <shlib-compat.h>
21 #include <stddef.h>
22 #include <string.h>
23 
24 /* Unpack a domain name from a message, source may be compressed.
25    Returns -1 if it fails, or consumed octets if it succeeds.  */
26 int
___ns_name_unpack(const unsigned char * msg,const unsigned char * eom,const unsigned char * src,unsigned char * dst,size_t dstsiz)27 ___ns_name_unpack (const unsigned char *msg, const unsigned char *eom,
28                    const unsigned char *src, unsigned char *dst, size_t dstsiz)
29 {
30   const unsigned char *srcp, *dstlim;
31   unsigned char *dstp;
32   int n, len, checked;
33 
34   len = -1;
35   checked = 0;
36   dstp = dst;
37   srcp = src;
38   dstlim = dst + dstsiz;
39   if (srcp < msg || srcp >= eom)
40     {
41       __set_errno (EMSGSIZE);
42       return -1;
43     }
44   /* Fetch next label in domain name.  */
45   while ((n = *srcp++) != 0)
46     {
47       /* Check for indirection.  */
48       switch (n & NS_CMPRSFLGS)
49         {
50         case 0:
51           /* Limit checks.  */
52           if (n >= 64)
53             {
54               __set_errno (EMSGSIZE);
55               return -1;
56             }
57           /* NB: n + 1 and >= to cover the *dstp = '\0' assignment
58              below.  */
59           if (n + 1 >= dstlim - dstp || n >= eom - srcp)
60             {
61               __set_errno (EMSGSIZE);
62               return -1;
63             }
64           checked += n + 1;
65           *dstp++ = n;
66           memcpy (dstp, srcp, n);
67           dstp += n;
68           srcp += n;
69           break;
70 
71         case NS_CMPRSFLGS:
72           if (srcp >= eom)
73             {
74               __set_errno (EMSGSIZE);
75               return -1;
76             }
77           if (len < 0)
78             len = srcp - src + 1;
79           {
80             int target = ((n & 0x3f) << 8) | *srcp;
81             if (target >= eom - msg)
82               {
83               /* Out of range.  */
84                 __set_errno (EMSGSIZE);
85                 return -1;
86             }
87             srcp = msg + target;
88           }
89           checked += 2;
90           /* Check for loops in the compressed name; if we've looked
91              at the whole message, there must be a loop.  */
92           if (checked >= eom - msg)
93             {
94               __set_errno (EMSGSIZE);
95               return -1;
96             }
97           break;
98 
99         default:
100           __set_errno (EMSGSIZE);
101           return -1;
102         }
103     }
104   *dstp = '\0';
105   if (len < 0)
106     len = srcp - src;
107   return len;
108 }
109 versioned_symbol (libc, ___ns_name_unpack, ns_name_unpack, GLIBC_2_34);
110 versioned_symbol (libc, ___ns_name_unpack, __ns_name_unpack, GLIBC_PRIVATE);
111 libc_hidden_ver (___ns_name_unpack, __ns_name_unpack)
112 
113 #if OTHER_SHLIB_COMPAT (libresolv, GLIBC_2_9, GLIBC_2_34)
114 compat_symbol (libresolv, ___ns_name_unpack, ns_name_unpack, GLIBC_2_9);
115 #endif
116