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