reSIProcate
SIP stack, Dialog Usage Manager and related libraries
Loading...
Searching...
No Matches
ares_expand_name.c
Go to the documentation of this file.
1/* Copyright 1998 by the Massachusetts Institute of Technology.
2 *
3 * Permission to use, copy, modify, and distribute this
4 * software and its documentation for any purpose and without
5 * fee is hereby granted, provided that the above copyright
6 * notice appear in all copies and that both that copyright
7 * notice and this permission notice appear in supporting
8 * documentation, and that the name of M.I.T. not be used in
9 * advertising or publicity pertaining to distribution of the
10 * software without specific, written prior permission.
11 * M.I.T. makes no representations about the suitability of
12 * this software for any purpose. It is provided "as is"
13 * without express or implied warranty.
14 */
15
16
17#include <sys/types.h>
18#include <stdlib.h>
19
20#if !defined(WIN32) && !defined(__CYGWIN__)
21#include <netinet/in.h>
22#include "ares_nameser.h"
23#endif
24
25#include "ares.h"
26
27 /* Maximum number of indirections allowed for a name */
28#define MAX_INDIRS 50
29
30static int name_length(const unsigned char *encoded, const unsigned char *abuf,
31 int alen);
32
33static int is_reservedch(int ch)
34{
35 switch (ch) {
36 case '"':
37 case '.':
38 case ';':
39 case '\\':
40 case '(':
41 case ')':
42 case '@':
43 case '$':
44 return 1;
45 default:
46 break;
47 }
48
49 return 0;
50}
51
52static int ares__isprint(int ch)
53{
54 if (ch >= 0x20 && ch <= 0x7E)
55 return 1;
56 return 0;
57}
58
59/* Expand an RFC1035-encoded domain name given by encoded. The
60 * containing message is given by abuf and alen. The result given by
61 * *s, which is set to a NUL-terminated allocated buffer. *enclen is
62 * set to the length of the encoded name (not the length of the
63 * expanded name; the goal is to tell the caller how many bytes to
64 * move forward to get past the encoded name).
65 *
66 * In the simple case, an encoded name is a series of labels, each
67 * composed of a one-byte length (limited to values between 0 and 63
68 * inclusive) followed by the label contents. The name is terminated
69 * by a zero-length label.
70 *
71 * In the more complicated case, a label may be terminated by an
72 * indirection pointer, specified by two bytes with the high bits of
73 * the first byte (corresponding to INDIR_MASK) set to 11. With the
74 * two high bits of the first byte stripped off, the indirection
75 * pointer gives an offset from the beginning of the containing
76 * message with more labels to decode. Indirection can happen an
77 * arbitrary number of times, so we have to detect loops.
78 *
79 * Since the expanded name uses '.' as a label separator, we use
80 * backslashes to escape periods or backslashes in the expanded name.
81 */
82
83int ares_expand_name(const unsigned char* encoded, const unsigned char* abuf,
84 int alen, char** s, long* enclen)
85{
86 int len, remaining, indir = 0;
87 char* q;
88 const unsigned char* p;
89
90 len = name_length(encoded, abuf, alen);
91 if (len == -1)
92 return ARES_EBADNAME;
93
94 *s = malloc(len + 1);
95 if (!*s)
96 return ARES_ENOMEM;
97 q = *s;
98
99 if (len == 0) {
100 /* RFC2181 says this should be ".": the root of the DNS tree.
101 * Since this function strips trailing dots though, it becomes ""
102 */
103 q[0] = '\0';
104
105 /* indirect root label (like 0xc0 0x0c) is 2 bytes long (stupid, but
106 valid) */
107 if ((*encoded & INDIR_MASK) == INDIR_MASK)
108 *enclen = 2L;
109 else
110 *enclen = 1L; /* the caller should move one byte to get past this */
111
112 return ARES_SUCCESS;
113 }
114
115 /* No error-checking necessary; it was all done by name_length(). */
116 p = encoded;
117 while (*p)
118 {
119 if ((*p & INDIR_MASK) == INDIR_MASK)
120 {
121 if (!indir)
122 {
123 *enclen = (long)(p + 2 - encoded);
124 indir = 1;
125 }
126 p = abuf + ((*p & ~INDIR_MASK) << 8 | *(p + 1));
127 }
128 else
129 {
130 len = *p;
131 remaining = len;
132 p++;
133 while (remaining--)
134 {
135 /* Output as \DDD for consistency with RFC1035 5.1, except
136 * for the special case of a root name response */
137 if (!ares__isprint(*p) && !(len == 1 && *p == 0))
138 {
139 *q++ = '\\';
140 *q++ = '0' + *p / 100;
141 *q++ = '0' + (*p % 100) / 10;
142 *q++ = '0' + (*p % 10);
143 }
144 else if (is_reservedch(*p))
145 {
146 *q++ = '\\';
147 *q++ = *p;
148 }
149 else
150 {
151 *q++ = *p;
152 }
153 p++;
154 }
155 *q++ = '.';
156 }
157 }
158 if (!indir)
159 *enclen = (long)(p + 1 - encoded);
160
161 /* Nuke the trailing period if we wrote one. */
162 if (q > *s)
163 q--;
164 /* Write a trailing NUL in any case. */
165 *q = 0;
166
167 return ARES_SUCCESS;
168}
169
170/* Return the length of the expansion of an encoded domain name, or
171 * -1 if the encoding is invalid.
172 */
173static int name_length(const unsigned char* encoded, const unsigned char* abuf,
174 int alen)
175{
176 int n = 0, offset, indir = 0, top;
177
178 /* Allow the caller to pass us abuf + alen and have us check for it. */
179 if (encoded >= abuf + alen)
180 return -1;
181
182 while (*encoded)
183 {
184 top = (*encoded & INDIR_MASK);
185 if (top == INDIR_MASK)
186 {
187 /* Check the offset and go there. */
188 if (encoded + 1 >= abuf + alen)
189 return -1;
190 offset = (*encoded & ~INDIR_MASK) << 8 | *(encoded + 1);
191 if (offset >= alen)
192 return -1;
193 encoded = abuf + offset;
194
195 /* If we've seen more indirects than the message length,
196 * then there's a loop.
197 */
198 ++indir;
199 if (indir > alen || indir > MAX_INDIRS)
200 return -1;
201 }
202 else if (top == 0x00)
203 {
204 int name_len = *encoded;
205 offset = name_len;
206 if (encoded + offset + 1 >= abuf + alen)
207 return -1;
208 encoded++;
209
210 while (offset--)
211 {
212 if (!ares__isprint(*encoded) && !(name_len == 1 && *encoded == 0))
213 {
214 n += 4;
215 }
216 else if (is_reservedch(*encoded))
217 {
218 n += 2;
219 }
220 else
221 {
222 n += 1;
223 }
224 encoded++;
225 }
226
227 n++;
228 }
229 else
230 {
231 /* RFC 1035 4.1.4 says other options (01, 10) for top 2
232 * bits are reserved.
233 */
234 return -1;
235 }
236 }
237
238 /* If there were any labels at all, then the number of dots is one
239 * less than the number of labels, so subtract one.
240 */
241 return (n) ? n - 1 : n;
242}
#define ARES_SUCCESS
Definition ares.h:79
#define ARES_ENOMEM
Definition ares.h:98
#define ARES_EBADNAME
Definition ares.h:91
static int is_reservedch(int ch)
#define MAX_INDIRS
int ares_expand_name(const unsigned char *encoded, const unsigned char *abuf, int alen, char **s, long *enclen)
static int ares__isprint(int ch)
static int name_length(const unsigned char *encoded, const unsigned char *abuf, int alen)
#define INDIR_MASK
void list()
Definition userAdmin.cxx:66