xref: /illumos-gate/usr/src/lib/libresolv/res_comp.c (revision 7c478bd9)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 1996 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
28 /*	  All Rights Reserved  	*/
29 
30 /*
31  * University Copyright- Copyright (c) 1982, 1986, 1988
32  * The Regents of the University of California
33  * All Rights Reserved
34  *
35  * University Acknowledgment- Portions of this document are derived from
36  * software developed by the University of California, Berkeley, and its
37  * contributors.
38  */
39 
40 #pragma ident	"%Z%%M%	%I%	%E% SMI"
41 
42 #include "synonyms.h"
43 
44 #include <sys/types.h>
45 #include <stdio.h>
46 #include <arpa/nameser.h>
47 
48 static dn_find();
49 
50 
51 /*
52  * Expand compressed domain name 'comp_dn' to full domain name.
53  * 'msg' is a pointer to the begining of the message,
54  * 'eomorig' points to the first location after the message,
55  * 'exp_dn' is a pointer to a buffer of size 'length' for the result.
56  * Return size of compressed name or -1 if there was an error.
57  */
58 dn_expand(msg, eomorig, comp_dn, exp_dn, length)
59 	u_char *msg, *eomorig, *comp_dn, *exp_dn;
60 	int length;
61 {
62 	register u_char *cp, *dn;
63 	register int n, c;
64 	u_char *eom;
65 	int len = -1, checked = 0;
66 
67 	dn = exp_dn;
68 	cp = comp_dn;
69 	eom = exp_dn + length;
70 	/*
71 	 * fetch next label in domain name
72 	 */
73 	while (n = *cp++) {
74 		/*
75 		 * Check for indirection
76 		 */
77 		switch (n & INDIR_MASK) {
78 		case 0:
79 			if (dn != exp_dn) {
80 				if (dn >= eom)
81 					return (-1);
82 				*dn++ = '.';
83 			}
84 			if (dn+n >= eom)
85 				return (-1);
86 			checked += n + 1;
87 			while (--n >= 0) {
88 				if ((c = *cp++) == '.') {
89 					if (dn + n + 2 >= eom)
90 						return (-1);
91 					*dn++ = '\\';
92 				}
93 				*dn++ = c;
94 				if (cp >= eomorig)	/* out of range */
95 					return (-1);
96 			}
97 			break;
98 
99 		case INDIR_MASK:
100 			if (len < 0)
101 				len = cp - comp_dn + 1;
102 			cp = msg + (((n & 0x3f) << 8) | (*cp & 0xff));
103 			if (cp < msg || cp >= eomorig)	/* out of range */
104 				return (-1);
105 			checked += 2;
106 			/*
107 			 * Check for loops in the compressed name;
108 			 * if we've looked at the whole message,
109 			 * there must be a loop.
110 			 */
111 			if (checked >= eomorig - msg)
112 				return (-1);
113 			break;
114 
115 		default:
116 			return (-1);			/* flag error */
117 		}
118 	}
119 	*dn = '\0';
120 	if (len < 0)
121 		len = cp - comp_dn;
122 	return (len);
123 }
124 
125 /*
126  * Compress domain name 'exp_dn' into 'comp_dn'.
127  * Return the size of the compressed name or -1.
128  * 'length' is the size of the array pointed to by 'comp_dn'.
129  * 'dnptrs' is a list of pointers to previous compressed names. dnptrs[0]
130  * is a pointer to the beginning of the message. The list ends with NULL.
131  * 'lastdnptr' is a pointer to the end of the arrary pointed to
132  * by 'dnptrs'. Side effect is to update the list of pointers for
133  * labels inserted into the message as we compress the name.
134  * If 'dnptr' is NULL, we don't try to compress names. If 'lastdnptr'
135  * is NULL, we don't update the list.
136  */
137 dn_comp(exp_dn, comp_dn, length, dnptrs, lastdnptr)
138 	u_char *exp_dn, *comp_dn;
139 	int length;
140 	u_char **dnptrs, **lastdnptr;
141 {
142 	register u_char *cp, *dn;
143 	register int c, l;
144 	u_char **cpp, **lpp, *sp, *eob;
145 	u_char *msg;
146 
147 	dn = exp_dn;
148 	cp = comp_dn;
149 	eob = cp + length;
150 	if (dnptrs != NULL) {
151 		if ((msg = *dnptrs++) != NULL) {
152 			for (cpp = dnptrs; *cpp != NULL; cpp++)
153 				;
154 			lpp = cpp;	/* end of list to search */
155 		}
156 	} else
157 		msg = NULL;
158 	for (c = *dn++; c != '\0'; /*EMPTY*/) {
159 		/* look to see if we can use pointers */
160 		if (msg != NULL) {
161 			if ((l = dn_find(dn-1, msg, dnptrs, lpp)) >= 0) {
162 				if (cp+1 >= eob)
163 					return (-1);
164 				*cp++ = (l >> 8) | INDIR_MASK;
165 				*cp++ = l % 256;
166 				return (cp - comp_dn);
167 			}
168 			/* not found, save it */
169 			if (lastdnptr != NULL && cpp < lastdnptr-1) {
170 				*cpp++ = cp;
171 				*cpp = NULL;
172 			}
173 		}
174 		sp = cp++;	/* save ptr to length byte */
175 		do {
176 			if (c == '.') {
177 				c = *dn++;
178 				break;
179 			}
180 			if (c == '\\') {
181 				if ((c = *dn++) == '\0')
182 					break;
183 			}
184 			if (cp >= eob) {
185 				if (msg != NULL)
186 					*lpp = NULL;
187 				return (-1);
188 			}
189 			*cp++ = c;
190 		} while ((c = *dn++) != '\0');
191 		/* catch trailing '.'s but not '..' */
192 		if ((l = cp - sp - 1) == 0 && c == '\0') {
193 			cp--;
194 			break;
195 		}
196 		if (l <= 0 || l > MAXLABEL) {
197 			if (msg != NULL)
198 				*lpp = NULL;
199 			return (-1);
200 		}
201 		*sp = l;
202 	}
203 	if (cp >= eob) {
204 		if (msg != NULL)
205 			*lpp = NULL;
206 		return (-1);
207 	}
208 	*cp++ = '\0';
209 	return (cp - comp_dn);
210 }
211 
212 /*
213  * Skip over a compressed domain name. Return the size or -1.
214  */
215 dn_skipname(comp_dn, eom)
216 	u_char *comp_dn, *eom;
217 {
218 	register u_char *cp;
219 	register int n;
220 
221 	cp = comp_dn;
222 	while (cp < eom && (n = *cp++)) {
223 		/*
224 		 * check for indirection
225 		 */
226 		switch (n & INDIR_MASK) {
227 		case 0:		/* normal case, n == len */
228 			cp += n;
229 			continue;
230 		default:	/* illegal type */
231 			return (-1);
232 		case INDIR_MASK:	/* indirection */
233 			cp++;
234 		}
235 		break;
236 	}
237 	return (cp - comp_dn);
238 }
239 
240 /*
241  * Search for expanded name from a list of previously compressed names.
242  * Return the offset from msg if found or -1.
243  * dnptrs is the pointer to the first name on the list,
244  * not the pointer to the start of the message.
245  */
246 static
247 dn_find(exp_dn, msg, dnptrs, lastdnptr)
248 	u_char *exp_dn, *msg;
249 	u_char **dnptrs, **lastdnptr;
250 {
251 	register u_char *dn, *cp, **cpp;
252 	register int n;
253 	u_char *sp;
254 
255 	for (cpp = dnptrs; cpp < lastdnptr; cpp++) {
256 		dn = exp_dn;
257 		sp = cp = *cpp;
258 		while (n = *cp++) {
259 			/*
260 			 * check for indirection
261 			 */
262 			switch (n & INDIR_MASK) {
263 			case 0:		/* normal case, n == len */
264 				while (--n >= 0) {
265 					if (*dn == '.')
266 						goto next;
267 					if (*dn == '\\')
268 						dn++;
269 					if (*dn++ != *cp++)
270 						goto next;
271 				}
272 				if ((n = *dn++) == '\0' && *cp == '\0')
273 					return (sp - msg);
274 				if (n == '.')
275 					continue;
276 				goto next;
277 
278 			default:	/* illegal type */
279 				return (-1);
280 
281 			case INDIR_MASK:	/* indirection */
282 				cp = msg + (((n & 0x3f) << 8) | *cp);
283 			}
284 		}
285 		if (*dn == '\0')
286 			return (sp - msg);
287 	next:	/*EMPTY*/;
288 	}
289 	return (-1);
290 }
291 
292 /*
293  * Routines to insert/extract short/long's. Must account for byte
294  * order and non-alignment problems. This code at least has the
295  * advantage of being portable.
296  *
297  * used by sendmail.
298  */
299 
300 u_short
301 _getshort(msgp)
302 	u_char *msgp;
303 {
304 	register u_char *p = (u_char *) msgp;
305 #ifdef vax
306 	/*
307 	 * vax compiler doesn't put shorts in registers
308 	 */
309 	register u_long u;
310 #else
311 	register u_short u;
312 #endif
313 
314 	u = *p++ << 8;
315 	return ((u_short)(u | *p));
316 }
317 
318 u_long
319 _getlong(msgp)
320 	u_char *msgp;
321 {
322 	register u_char *p = (u_char *) msgp;
323 	register u_long u;
324 
325 	u = *p++; u <<= 8;
326 	u |= *p++; u <<= 8;
327 	u |= *p++; u <<= 8;
328 	return (u | *p);
329 }
330 
331 
332 putshort(s, msgp)
333 	register u_short s;
334 	register u_char *msgp;
335 {
336 
337 	msgp[1] = s;
338 	msgp[0] = s >> 8;
339 }
340 
341 putlong(l, msgp)
342 	register u_long l;
343 	register u_char *msgp;
344 {
345 
346 	msgp[3] = l;
347 	msgp[2] = (l >>= 8);
348 	msgp[1] = (l >>= 8);
349 	msgp[0] = l >> 8;
350 }
351