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