1 /*
2 * Copyright (c) 1985 Regents of the University of California.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34 #if defined(LIBC_SCCS) && !defined(lint)
35 static char sccsid[] = "@(#)res_comp.c 6.22 (Berkeley) 3/19/91";
36 #endif /* LIBC_SCCS and not lint */
37
38 #include <sys/param.h>
39 #include <arpa/nameser.h>
40 #include <netinet/in.h>
41 #include <resolv.h>
42 #include <stdio.h>
43
44 static dn_find();
45
46 /*
47 * Expand compressed domain name 'comp_dn' to full domain name.
48 * 'msg' is a pointer to the begining of the message,
49 * 'eomorig' points to the first location after the message,
50 * 'exp_dn' is a pointer to a buffer of size 'length' for the result.
51 * Return size of compressed name or -1 if there was an error.
52 */
dn_expand(msg,eomorig,comp_dn,exp_dn,length)53 dn_expand(msg, eomorig, comp_dn, exp_dn, length)
54 const u_char *msg, *eomorig, *comp_dn;
55 u_char *exp_dn;
56 int length;
57 {
58 register u_char *cp, *dn;
59 register int n, c;
60 u_char *eom;
61 int len = -1, checked = 0;
62
63 dn = exp_dn;
64 cp = (u_char *)comp_dn;
65 eom = exp_dn + length;
66 /*
67 * fetch next label in domain name
68 */
69 while (n = *cp++) {
70 /*
71 * Check for indirection
72 */
73 switch (n & INDIR_MASK) {
74 case 0:
75 if (dn != exp_dn) {
76 if (dn >= eom)
77 return (-1);
78 *dn++ = '.';
79 }
80 if (dn+n >= eom)
81 return (-1);
82 checked += n + 1;
83 while (--n >= 0) {
84 if ((c = *cp++) == '.') {
85 if (dn + n + 2 >= eom)
86 return (-1);
87 *dn++ = '\\';
88 }
89 *dn++ = c;
90 if (cp >= eomorig) /* out of range */
91 return(-1);
92 }
93 break;
94
95 case INDIR_MASK:
96 if (len < 0)
97 len = cp - comp_dn + 1;
98 cp = (u_char *)msg + (((n & 0x3f) << 8) | (*cp & 0xff));
99 if (cp < msg || cp >= eomorig) /* out of range */
100 return(-1);
101 checked += 2;
102 /*
103 * Check for loops in the compressed name;
104 * if we've looked at the whole message,
105 * there must be a loop.
106 */
107 if (checked >= eomorig - msg)
108 return (-1);
109 break;
110
111 default:
112 return (-1); /* flag error */
113 }
114 }
115 *dn = '\0';
116 if (len < 0)
117 len = cp - comp_dn;
118 return (len);
119 }
120
121 /*
122 * Compress domain name 'exp_dn' into 'comp_dn'.
123 * Return the size of the compressed name or -1.
124 * 'length' is the size of the array pointed to by 'comp_dn'.
125 * 'dnptrs' is a list of pointers to previous compressed names. dnptrs[0]
126 * is a pointer to the beginning of the message. The list ends with NULL.
127 * 'lastdnptr' is a pointer to the end of the arrary pointed to
128 * by 'dnptrs'. Side effect is to update the list of pointers for
129 * labels inserted into the message as we compress the name.
130 * If 'dnptr' is NULL, we don't try to compress names. If 'lastdnptr'
131 * is NULL, we don't update the list.
132 */
dn_comp(exp_dn,comp_dn,length,dnptrs,lastdnptr)133 dn_comp(exp_dn, comp_dn, length, dnptrs, lastdnptr)
134 const u_char *exp_dn;
135 u_char *comp_dn, **dnptrs, **lastdnptr;
136 int length;
137 {
138 register u_char *cp, *dn;
139 register int c, l;
140 u_char **cpp, **lpp, *sp, *eob;
141 u_char *msg;
142
143 dn = (u_char *)exp_dn;
144 cp = comp_dn;
145 eob = cp + length;
146 if (dnptrs != NULL) {
147 if ((msg = *dnptrs++) != NULL) {
148 for (cpp = dnptrs; *cpp != NULL; cpp++)
149 ;
150 lpp = cpp; /* end of list to search */
151 }
152 } else
153 msg = NULL;
154 for (c = *dn++; c != '\0'; ) {
155 /* look to see if we can use pointers */
156 if (msg != NULL) {
157 if ((l = dn_find(dn-1, msg, dnptrs, lpp)) >= 0) {
158 if (cp+1 >= eob)
159 return (-1);
160 *cp++ = (l >> 8) | INDIR_MASK;
161 *cp++ = l % 256;
162 return (cp - comp_dn);
163 }
164 /* not found, save it */
165 if (lastdnptr != NULL && cpp < lastdnptr-1) {
166 *cpp++ = cp;
167 *cpp = NULL;
168 }
169 }
170 sp = cp++; /* save ptr to length byte */
171 do {
172 if (c == '.') {
173 c = *dn++;
174 break;
175 }
176 if (c == '\\') {
177 if ((c = *dn++) == '\0')
178 break;
179 }
180 if (cp >= eob) {
181 if (msg != NULL)
182 *lpp = NULL;
183 return (-1);
184 }
185 *cp++ = c;
186 } while ((c = *dn++) != '\0');
187 /* catch trailing '.'s but not '..' */
188 if ((l = cp - sp - 1) == 0 && c == '\0') {
189 cp--;
190 break;
191 }
192 if (l <= 0 || l > MAXLABEL) {
193 if (msg != NULL)
194 *lpp = NULL;
195 return (-1);
196 }
197 *sp = l;
198 }
199 if (cp >= eob) {
200 if (msg != NULL)
201 *lpp = NULL;
202 return (-1);
203 }
204 *cp++ = '\0';
205 return (cp - comp_dn);
206 }
207
208 /*
209 * Skip over a compressed domain name. Return the size or -1.
210 */
__dn_skipname(comp_dn,eom)211 __dn_skipname(comp_dn, eom)
212 const u_char *comp_dn, *eom;
213 {
214 register u_char *cp;
215 register int n;
216
217 cp = (u_char *)comp_dn;
218 while (cp < eom && (n = *cp++)) {
219 /*
220 * check for indirection
221 */
222 switch (n & INDIR_MASK) {
223 case 0: /* normal case, n == len */
224 cp += n;
225 continue;
226 default: /* illegal type */
227 return (-1);
228 case INDIR_MASK: /* indirection */
229 cp++;
230 }
231 break;
232 }
233 return (cp - comp_dn);
234 }
235
236 /*
237 * Search for expanded name from a list of previously compressed names.
238 * Return the offset from msg if found or -1.
239 * dnptrs is the pointer to the first name on the list,
240 * not the pointer to the start of the message.
241 */
242 static
dn_find(exp_dn,msg,dnptrs,lastdnptr)243 dn_find(exp_dn, msg, dnptrs, lastdnptr)
244 u_char *exp_dn, *msg;
245 u_char **dnptrs, **lastdnptr;
246 {
247 register u_char *dn, *cp, **cpp;
248 register int n;
249 u_char *sp;
250
251 for (cpp = dnptrs; cpp < lastdnptr; cpp++) {
252 dn = exp_dn;
253 sp = cp = *cpp;
254 while (n = *cp++) {
255 /*
256 * check for indirection
257 */
258 switch (n & INDIR_MASK) {
259 case 0: /* normal case, n == len */
260 while (--n >= 0) {
261 if (*dn == '.')
262 goto next;
263 if (*dn == '\\')
264 dn++;
265 if (*dn++ != *cp++)
266 goto next;
267 }
268 if ((n = *dn++) == '\0' && *cp == '\0')
269 return (sp - msg);
270 if (n == '.')
271 continue;
272 goto next;
273
274 default: /* illegal type */
275 return (-1);
276
277 case INDIR_MASK: /* indirection */
278 cp = msg + (((n & 0x3f) << 8) | *cp);
279 }
280 }
281 if (*dn == '\0')
282 return (sp - msg);
283 next: ;
284 }
285 return (-1);
286 }
287
288 /*
289 * Routines to insert/extract short/long's. Must account for byte
290 * order and non-alignment problems. This code at least has the
291 * advantage of being portable.
292 *
293 * used by sendmail.
294 */
295
296 u_short
_getshort(msgp)297 _getshort(msgp)
298 u_char *msgp;
299 {
300 register u_char *p = (u_char *) msgp;
301 #ifdef vax
302 /*
303 * vax compiler doesn't put shorts in registers
304 */
305 register u_long u;
306 #else
307 register u_short u;
308 #endif
309
310 u = *p++ << 8;
311 return ((u_short)(u | *p));
312 }
313
314 u_long
_getlong(msgp)315 _getlong(msgp)
316 u_char *msgp;
317 {
318 register u_char *p = (u_char *) msgp;
319 register u_long u;
320
321 u = *p++; u <<= 8;
322 u |= *p++; u <<= 8;
323 u |= *p++; u <<= 8;
324 return (u | *p);
325 }
326
327 void
328 #ifdef __STDC__
__putshort(register u_short s,register u_char * msgp)329 __putshort(register u_short s, register u_char *msgp)
330 #else
331 __putshort(s, msgp)
332 register u_short s;
333 register u_char *msgp;
334 #endif
335 {
336 msgp[1] = s;
337 msgp[0] = s >> 8;
338 }
339
340 void
__putlong(l,msgp)341 __putlong(l, msgp)
342 register u_long l;
343 register u_char *msgp;
344 {
345 msgp[3] = l;
346 msgp[2] = (l >>= 8);
347 msgp[1] = (l >>= 8);
348 msgp[0] = l >> 8;
349 }
350