xref: /original-bsd/lib/libc/net/res_comp.c (revision f4b4348c)
1 /*-
2  * Copyright (c) 1985, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * %sccs.include.redist.c%
6  * -
7  * Portions Copyright (c) 1993 by Digital Equipment Corporation.
8  *
9  * Permission to use, copy, modify, and distribute this software for any
10  * purpose with or without fee is hereby granted, provided that the above
11  * copyright notice and this permission notice appear in all copies, and that
12  * the name of Digital Equipment Corporation not be used in advertising or
13  * publicity pertaining to distribution of the document or software without
14  * specific, written prior permission.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
17  * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
18  * OF MERCHANTABILITY AND FITNESS.   IN NO EVENT SHALL DIGITAL EQUIPMENT
19  * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
20  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
21  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
22  * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
23  * SOFTWARE.
24  * -
25  * --Copyright--
26  */
27 
28 #if defined(LIBC_SCCS) && !defined(lint)
29 static char sccsid[] = "@(#)res_comp.c	8.1 (Berkeley) 06/04/93";
30 static char rcsid[] = "$Id: res_comp.c,v 4.9.1.1 1993/05/02 22:43:03 vixie Rel $";
31 #endif /* LIBC_SCCS and not lint */
32 
33 #include <sys/param.h>
34 #include <arpa/nameser.h>
35 #include <netinet/in.h>
36 #include <resolv.h>
37 #include <stdio.h>
38 
39 static int dn_find();
40 
41 /*
42  * Expand compressed domain name 'comp_dn' to full domain name.
43  * 'msg' is a pointer to the begining of the message,
44  * 'eomorig' points to the first location after the message,
45  * 'exp_dn' is a pointer to a buffer of size 'length' for the result.
46  * Return size of compressed name or -1 if there was an error.
47  */
dn_expand(msg,eomorig,comp_dn,exp_dn,length)48 dn_expand(msg, eomorig, comp_dn, exp_dn, length)
49 	const u_char *msg, *eomorig, *comp_dn;
50 	u_char *exp_dn;
51 	int length;
52 {
53 	register u_char *cp, *dn;
54 	register int n, c;
55 	u_char *eom;
56 	int len = -1, checked = 0;
57 
58 	dn = exp_dn;
59 	cp = (u_char *)comp_dn;
60 	eom = exp_dn + length;
61 	/*
62 	 * fetch next label in domain name
63 	 */
64 	while (n = *cp++) {
65 		/*
66 		 * Check for indirection
67 		 */
68 		switch (n & INDIR_MASK) {
69 		case 0:
70 			if (dn != exp_dn) {
71 				if (dn >= eom)
72 					return (-1);
73 				*dn++ = '.';
74 			}
75 			if (dn+n >= eom)
76 				return (-1);
77 			checked += n + 1;
78 			while (--n >= 0) {
79 				if ((c = *cp++) == '.') {
80 					if (dn + n + 2 >= eom)
81 						return (-1);
82 					*dn++ = '\\';
83 				}
84 				*dn++ = c;
85 				if (cp >= eomorig)	/* out of range */
86 					return(-1);
87 			}
88 			break;
89 
90 		case INDIR_MASK:
91 			if (len < 0)
92 				len = cp - comp_dn + 1;
93 			cp = (u_char *)msg + (((n & 0x3f) << 8) | (*cp & 0xff));
94 			if (cp < msg || cp >= eomorig)	/* out of range */
95 				return(-1);
96 			checked += 2;
97 			/*
98 			 * Check for loops in the compressed name;
99 			 * if we've looked at the whole message,
100 			 * there must be a loop.
101 			 */
102 			if (checked >= eomorig - msg)
103 				return (-1);
104 			break;
105 
106 		default:
107 			return (-1);			/* flag error */
108 		}
109 	}
110 	*dn = '\0';
111 	if (len < 0)
112 		len = cp - comp_dn;
113 	return (len);
114 }
115 
116 /*
117  * Compress domain name 'exp_dn' into 'comp_dn'.
118  * Return the size of the compressed name or -1.
119  * 'length' is the size of the array pointed to by 'comp_dn'.
120  * 'dnptrs' is a list of pointers to previous compressed names. dnptrs[0]
121  * is a pointer to the beginning of the message. The list ends with NULL.
122  * 'lastdnptr' is a pointer to the end of the arrary pointed to
123  * by 'dnptrs'. Side effect is to update the list of pointers for
124  * labels inserted into the message as we compress the name.
125  * If 'dnptr' is NULL, we don't try to compress names. If 'lastdnptr'
126  * is NULL, we don't update the list.
127  */
dn_comp(exp_dn,comp_dn,length,dnptrs,lastdnptr)128 dn_comp(exp_dn, comp_dn, length, dnptrs, lastdnptr)
129 	const u_char *exp_dn;
130 	u_char *comp_dn, **dnptrs, **lastdnptr;
131 	int length;
132 {
133 	register u_char *cp, *dn;
134 	register int c, l;
135 	u_char **cpp, **lpp, *sp, *eob;
136 	u_char *msg;
137 
138 	dn = (u_char *)exp_dn;
139 	cp = comp_dn;
140 	eob = cp + length;
141 	if (dnptrs != NULL) {
142 		if ((msg = *dnptrs++) != NULL) {
143 			for (cpp = dnptrs; *cpp != NULL; cpp++)
144 				;
145 			lpp = cpp;	/* end of list to search */
146 		}
147 	} else
148 		msg = NULL;
149 	for (c = *dn++; c != '\0'; ) {
150 		/* look to see if we can use pointers */
151 		if (msg != NULL) {
152 			if ((l = dn_find(dn-1, msg, dnptrs, lpp)) >= 0) {
153 				if (cp+1 >= eob)
154 					return (-1);
155 				*cp++ = (l >> 8) | INDIR_MASK;
156 				*cp++ = l % 256;
157 				return (cp - comp_dn);
158 			}
159 			/* not found, save it */
160 			if (lastdnptr != NULL && cpp < lastdnptr-1) {
161 				*cpp++ = cp;
162 				*cpp = NULL;
163 			}
164 		}
165 		sp = cp++;	/* save ptr to length byte */
166 		do {
167 			if (c == '.') {
168 				c = *dn++;
169 				break;
170 			}
171 			if (c == '\\') {
172 				if ((c = *dn++) == '\0')
173 					break;
174 			}
175 			if (cp >= eob) {
176 				if (msg != NULL)
177 					*lpp = NULL;
178 				return (-1);
179 			}
180 			*cp++ = c;
181 		} while ((c = *dn++) != '\0');
182 		/* catch trailing '.'s but not '..' */
183 		if ((l = cp - sp - 1) == 0 && c == '\0') {
184 			cp--;
185 			break;
186 		}
187 		if (l <= 0 || l > MAXLABEL) {
188 			if (msg != NULL)
189 				*lpp = NULL;
190 			return (-1);
191 		}
192 		*sp = l;
193 	}
194 	if (cp >= eob) {
195 		if (msg != NULL)
196 			*lpp = NULL;
197 		return (-1);
198 	}
199 	*cp++ = '\0';
200 	return (cp - comp_dn);
201 }
202 
203 /*
204  * Skip over a compressed domain name. Return the size or -1.
205  */
__dn_skipname(comp_dn,eom)206 __dn_skipname(comp_dn, eom)
207 	const u_char *comp_dn, *eom;
208 {
209 	register u_char *cp;
210 	register int n;
211 
212 	cp = (u_char *)comp_dn;
213 	while (cp < eom && (n = *cp++)) {
214 		/*
215 		 * check for indirection
216 		 */
217 		switch (n & INDIR_MASK) {
218 		case 0:		/* normal case, n == len */
219 			cp += n;
220 			continue;
221 		default:	/* illegal type */
222 			return (-1);
223 		case INDIR_MASK:	/* indirection */
224 			cp++;
225 		}
226 		break;
227 	}
228 	return (cp - comp_dn);
229 }
230 
231 /*
232  * Search for expanded name from a list of previously compressed names.
233  * Return the offset from msg if found or -1.
234  * dnptrs is the pointer to the first name on the list,
235  * not the pointer to the start of the message.
236  */
237 static int
dn_find(exp_dn,msg,dnptrs,lastdnptr)238 dn_find(exp_dn, msg, dnptrs, lastdnptr)
239 	u_char *exp_dn, *msg;
240 	u_char **dnptrs, **lastdnptr;
241 {
242 	register u_char *dn, *cp, **cpp;
243 	register int n;
244 	u_char *sp;
245 
246 	for (cpp = dnptrs; cpp < lastdnptr; cpp++) {
247 		dn = exp_dn;
248 		sp = cp = *cpp;
249 		while (n = *cp++) {
250 			/*
251 			 * check for indirection
252 			 */
253 			switch (n & INDIR_MASK) {
254 			case 0:		/* normal case, n == len */
255 				while (--n >= 0) {
256 					if (*dn == '.')
257 						goto next;
258 					if (*dn == '\\')
259 						dn++;
260 					if (*dn++ != *cp++)
261 						goto next;
262 				}
263 				if ((n = *dn++) == '\0' && *cp == '\0')
264 					return (sp - msg);
265 				if (n == '.')
266 					continue;
267 				goto next;
268 
269 			default:	/* illegal type */
270 				return (-1);
271 
272 			case INDIR_MASK:	/* indirection */
273 				cp = msg + (((n & 0x3f) << 8) | *cp);
274 			}
275 		}
276 		if (*dn == '\0')
277 			return (sp - msg);
278 	next:	;
279 	}
280 	return (-1);
281 }
282 
283 /*
284  * Routines to insert/extract short/long's. Must account for byte
285  * order and non-alignment problems. This code at least has the
286  * advantage of being portable.
287  *
288  * used by sendmail.
289  */
290 
291 u_short
_getshort(msgp)292 _getshort(msgp)
293 	register u_char *msgp;
294 {
295 	register u_int16_t u;
296 
297 	GETSHORT(u, msgp);
298 	return (u);
299 }
300 
301 u_int32_t
_getlong(msgp)302 _getlong(msgp)
303 	register u_char *msgp;
304 {
305 	register u_int32_t u;
306 
307 	GETLONG(u, msgp);
308 	return (u);
309 }
310 
311 void
312 #if defined(__STDC__) || defined(__cplusplus)
__putshort(register u_short s,register u_char * msgp)313 __putshort(register u_short s, register u_char *msgp)
314 #else
315 __putshort(s, msgp)
316 	register u_int16_t s;
317 	register u_char *msgp;
318 #endif
319 {
320 	PUTSHORT(s, msgp);
321 }
322 
323 void
__putlong(l,msgp)324 __putlong(l, msgp)
325 	register u_int32_t l;
326 	register u_char *msgp;
327 {
328 	PUTLONG(l, msgp);
329 }
330