xref: /csrg-svn/lib/libc/net/res_comp.c (revision 18140)
1 #ifndef lint
2 static char sccsid[] = "@(#)res_comp.c	4.1 (Berkeley) 03/01/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 format to full domain name.
13  * Return size of compressed name or -1 if there was an error.
14  */
15 dn_expand(msg, comp_dn, exp_dn, length)
16 	char *msg, *comp_dn, *exp_dn;
17 	int length;
18 {
19 	register char *cp, *dn;
20 	register int n, c;
21 	char *eom;
22 	int len = 0;
23 
24 	dn = exp_dn;
25 	cp = comp_dn;
26 	eom = exp_dn + length - 1;
27 	/*
28 	 * fetch next label in domain name
29 	 */
30 	while (n = *cp++) {
31 		/*
32 		 * Check for indirection
33 		 */
34 		switch (n & INDIR_MASK) {
35 		case 0:
36 			if (dn != exp_dn)
37 				*dn++ = '.';
38 			if (dn+n >= eom)
39 				return (-1);
40 			while (--n >= 0)
41 				if (islower(c = *cp++))
42 					*dn++ = toupper(c);
43 				else
44 					*dn++ = c;
45 			break;
46 
47 		case INDIR_MASK:
48 			if (len == 0)
49 				len = cp - comp_dn + 1;
50 			cp = msg + (((n & 0x3f) << 8) | (*cp & 0xff));
51 			break;
52 
53 		default:
54 			return (-1);			/* flag error */
55 		}
56 	}
57 	*dn = '\0';
58 	if (len == 0)
59 		len = cp - comp_dn;
60 	return (len);
61 }
62 
63 /*
64  * Compress domain name. Return the size of the compressed name or -1.
65  * Dnptrs is a list of pointers to previous compressed names. dnptrs[0]
66  * is a pointer to the beginning of the message. The list ends with NULL.
67  */
68 dn_comp(exp_dn, comp_dn, length, dnptrs, lastdnptr)
69 	char *exp_dn, *comp_dn;
70 	int length;
71 	char **dnptrs, **lastdnptr;
72 {
73 	register char *cp, *dn;
74 	register int c, l;
75 	char **cpp, **lpp, *sp, *eob;
76 	char *msg;
77 
78 	dn = exp_dn;
79 	cp = comp_dn;
80 	eob = comp_dn + length;
81 	if (dnptrs != NULL) {
82 		if ((msg = *dnptrs++) != NULL) {
83 			for (cpp = dnptrs; *cpp != NULL; cpp++)
84 				;
85 			lpp = cpp;	/* end of list to search */
86 		}
87 	} else
88 		msg = NULL;
89 	for (c = *dn++; c != '\0'; ) {
90 		/* look to see if we can use pointers */
91 		if (msg != NULL) {
92 			if ((l = dn_find(dn-1, msg, dnptrs, lpp)) >= 0) {
93 				if (cp+1 >= eob)
94 					return (-1);
95 				*cp++ = (l >> 8) | INDIR_MASK;
96 				*cp++ = l;
97 				return (cp - comp_dn);
98 			}
99 			/* not found, save it */
100 			if (lastdnptr != NULL && cpp < lastdnptr-1) {
101 				*cpp++ = cp;
102 				*cpp = NULL;
103 			}
104 		}
105 		sp = cp++;	/* save ptr to length byte */
106 		do {
107 			if (c == '.') {
108 				c = *dn++;
109 				break;
110 			}
111 			if (cp >= eob)
112 				return (-1);
113 			*cp++ = c;
114 		} while ((c = *dn++) != '\0');
115 		if ((l = cp - sp - 1) <= 0 || l > MAXLABEL)
116 			return (-1);
117 		*sp = l;
118 	}
119 	if (cp >= eob)
120 		return (-1);
121 	*cp++ = '\0';
122 	return (cp - comp_dn);
123 }
124 
125 /*
126  * Skip over a compressed domain name. Return the size.
127  */
128 dn_skip(buf)
129 	char *buf;
130 {
131 	register char *cp;
132 	register int n;
133 
134 	cp = buf;
135 	while (n = *cp++) {
136 		/*
137 		 * check for indirection
138 		 */
139 		switch (n & INDIR_MASK) {
140 		case 0:		/* normal case, n == len */
141 			cp += n;
142 			continue;
143 		default:	/* illegal type */
144 			return (-1);
145 		case INDIR_MASK:	/* indirection */
146 			cp++;
147 		}
148 		break;
149 	}
150 	return (cp - buf);
151 }
152 
153 /*
154  * Search for expanded name from a list of previously compressed names.
155  * Return the offset from msg if found or -1.
156  */
157 dn_find(exp_dn, msg, dnptrs, lastdnptr)
158 	char *exp_dn, *msg;
159 	char **dnptrs, **lastdnptr;
160 {
161 	register char *dn, *cp, **cpp;
162 	register int n;
163 	char *sp;
164 
165 	for (cpp = dnptrs; cpp < lastdnptr; cpp++) {
166 		dn = exp_dn;
167 		sp = cp = *cpp;
168 		while (n = *cp++) {
169 			/*
170 			 * check for indirection
171 			 */
172 			switch (n & INDIR_MASK) {
173 			case 0:		/* normal case, n == len */
174 				while (--n >= 0)
175 					if (*dn++ != *cp++)
176 						goto next;
177 				if ((n = *dn++) == '\0' && *cp == '\0')
178 					return (sp - msg);
179 				if (n == '.')
180 					continue;
181 				goto next;
182 
183 			default:	/* illegal type */
184 				return (-1);
185 
186 			case INDIR_MASK:	/* indirection */
187 				cp = msg + (((n & 0x3f) << 8) | (*cp & 0xff));
188 			}
189 		}
190 		if (*dn == '\0')
191 			return (sp - msg);
192 	next:	;
193 	}
194 	return (-1);
195 }
196