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