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