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