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