xref: /386bsd/usr/src/lib/libc/net/res_comp.c (revision a2142627)
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