"Fossies" - the Fresh Open Source Software Archive 
Member "udns-0.4/udns_dn.c" (5 Jul 2011, 9890 Bytes) of package /linux/misc/dns/udns-0.4.tar.gz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
For more information about "udns_dn.c" see the
Fossies "Dox" file reference documentation.
1 /* udns_dn.c
2 domain names manipulation routines
3
4 Copyright (C) 2005 Michael Tokarev <mjt@corpit.ru>
5 This file is part of UDNS library, an async DNS stub resolver.
6
7 This library is free software; you can redistribute it and/or
8 modify it under the terms of the GNU Lesser General Public
9 License as published by the Free Software Foundation; either
10 version 2.1 of the License, or (at your option) any later version.
11
12 This library is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public
18 License along with this library, in file named COPYING.LGPL; if not,
19 write to the Free Software Foundation, Inc., 59 Temple Place,
20 Suite 330, Boston, MA 02111-1307 USA
21
22 */
23
24 #include <string.h>
25 #include "udns.h"
26
27 unsigned dns_dnlen(dnscc_t *dn) {
28 register dnscc_t *d = dn;
29 while(*d)
30 d += 1 + *d;
31 return (unsigned)(d - dn) + 1;
32 }
33
34 unsigned dns_dnlabels(register dnscc_t *dn) {
35 register unsigned l = 0;
36 while(*dn)
37 ++l, dn += 1 + *dn;
38 return l;
39 }
40
41 unsigned dns_dnequal(register dnscc_t *dn1, register dnscc_t *dn2) {
42 register unsigned c;
43 dnscc_t *dn = dn1;
44 for(;;) {
45 if ((c = *dn1++) != *dn2++)
46 return 0;
47 if (!c)
48 return (unsigned)(dn1 - dn);
49 while(c--) {
50 if (DNS_DNLC(*dn1) != DNS_DNLC(*dn2))
51 return 0;
52 ++dn1; ++dn2;
53 }
54 }
55 }
56
57 unsigned
58 dns_dntodn(dnscc_t *sdn, dnsc_t *ddn, unsigned ddnsiz) {
59 unsigned sdnlen = dns_dnlen(sdn);
60 if (ddnsiz < sdnlen)
61 return 0;
62 memcpy(ddn, sdn, sdnlen);
63 return sdnlen;
64 }
65
66 int
67 dns_ptodn(const char *name, unsigned namelen,
68 dnsc_t *dn, unsigned dnsiz, int *isabs)
69 {
70 dnsc_t *dp; /* current position in dn (len byte first) */
71 dnsc_t *const de /* end of dn: last byte that can be filled up */
72 = dn + (dnsiz >= DNS_MAXDN ? DNS_MAXDN : dnsiz) - 1;
73 dnscc_t *np = (dnscc_t *)name;
74 dnscc_t *ne = np + (namelen ? namelen : strlen((char*)np));
75 dnsc_t *llab; /* start of last label (llab[-1] will be length) */
76 unsigned c; /* next input character, or length of last label */
77
78 if (!dnsiz)
79 return 0;
80 dp = llab = dn + 1;
81
82 while(np < ne) {
83
84 if (*np == '.') { /* label delimiter */
85 c = dp - llab; /* length of the label */
86 if (!c) { /* empty label */
87 if (np == (dnscc_t *)name && np + 1 == ne) {
88 /* special case for root dn, aka `.' */
89 ++np;
90 break;
91 }
92 return -1; /* zero label */
93 }
94 if (c > DNS_MAXLABEL)
95 return -1; /* label too long */
96 llab[-1] = (dnsc_t)c; /* update len of last label */
97 llab = ++dp; /* start new label, llab[-1] will be len of it */
98 ++np;
99 continue;
100 }
101
102 /* check whenever we may put out one more byte */
103 if (dp >= de) /* too long? */
104 return dnsiz >= DNS_MAXDN ? -1 : 0;
105 if (*np != '\\') { /* non-escape, simple case */
106 *dp++ = *np++;
107 continue;
108 }
109 /* handle \-style escape */
110 /* note that traditionally, domain names (gethostbyname etc)
111 * used decimal \dd notation, not octal \ooo (RFC1035), so
112 * we're following this tradition here.
113 */
114 if (++np == ne)
115 return -1; /* bad escape */
116 else if (*np >= '0' && *np <= '9') { /* decimal number */
117 /* we allow not only exactly 3 digits as per RFC1035,
118 * but also 2 or 1, for better usability. */
119 c = *np++ - '0';
120 if (np < ne && *np >= '0' && *np <= '9') { /* 2digits */
121 c = c * 10 + *np++ - '0';
122 if (np < ne && *np >= '0' && *np <= '9') {
123 c = c * 10 + *np++ - '0';
124 if (c > 255)
125 return -1; /* bad escape */
126 }
127 }
128 }
129 else
130 c = *np++;
131 *dp++ = (dnsc_t)c; /* place next out byte */
132 }
133
134 if ((c = dp - llab) > DNS_MAXLABEL)
135 return -1; /* label too long */
136 if ((llab[-1] = (dnsc_t)c) != 0) {
137 *dp++ = 0;
138 if (isabs)
139 *isabs = 0;
140 }
141 else if (isabs)
142 *isabs = 1;
143
144 return dp - dn;
145 }
146
147 dnscc_t dns_inaddr_arpa_dn[14] = "\07in-addr\04arpa";
148
149 dnsc_t *
150 dns_a4todn_(const struct in_addr *addr, dnsc_t *dn, dnsc_t *dne) {
151 const unsigned char *s = ((const unsigned char *)addr) + 4;
152 while(s > (const unsigned char *)addr) {
153 unsigned n = *--s;
154 dnsc_t *p = dn + 1;
155 if (n > 99) {
156 if (p + 2 > dne) return 0;
157 *p++ = n / 100 + '0';
158 *p++ = (n % 100 / 10) + '0';
159 *p = n % 10 + '0';
160 }
161 else if (n > 9) {
162 if (p + 1 > dne) return 0;
163 *p++ = n / 10 + '0';
164 *p = n % 10 + '0';
165 }
166 else {
167 if (p > dne) return 0;
168 *p = n + '0';
169 }
170 *dn = p - dn;
171 dn = p + 1;
172 }
173 return dn;
174 }
175
176 int dns_a4todn(const struct in_addr *addr, dnscc_t *tdn,
177 dnsc_t *dn, unsigned dnsiz) {
178 dnsc_t *dne = dn + (dnsiz > DNS_MAXDN ? DNS_MAXDN : dnsiz);
179 dnsc_t *p;
180 unsigned l;
181 p = dns_a4todn_(addr, dn, dne);
182 if (!p) return 0;
183 if (!tdn)
184 tdn = dns_inaddr_arpa_dn;
185 l = dns_dnlen(tdn);
186 if (p + l > dne) return dnsiz >= DNS_MAXDN ? -1 : 0;
187 memcpy(p, tdn, l);
188 return (p + l) - dn;
189 }
190
191 int dns_a4ptodn(const struct in_addr *addr, const char *tname,
192 dnsc_t *dn, unsigned dnsiz) {
193 dnsc_t *p;
194 int r;
195 if (!tname)
196 return dns_a4todn(addr, NULL, dn, dnsiz);
197 p = dns_a4todn_(addr, dn, dn + dnsiz);
198 if (!p) return 0;
199 r = dns_sptodn(tname, p, dnsiz - (p - dn));
200 return r != 0 ? r : dnsiz >= DNS_MAXDN ? -1 : 0;
201 }
202
203 dnscc_t dns_ip6_arpa_dn[10] = "\03ip6\04arpa";
204
205 dnsc_t *
206 dns_a6todn_(const struct in6_addr *addr, dnsc_t *dn, dnsc_t *dne) {
207 const unsigned char *s = ((const unsigned char *)addr) + 16;
208 if (dn + 64 > dne) return 0;
209 while(s > (const unsigned char *)addr) {
210 unsigned n = *--s & 0x0f;
211 *dn++ = 1;
212 *dn++ = n > 9 ? n + 'a' - 10 : n + '0';
213 *dn++ = 1;
214 n = *s >> 4;
215 *dn++ = n > 9 ? n + 'a' - 10 : n + '0';
216 }
217 return dn;
218 }
219
220 int dns_a6todn(const struct in6_addr *addr, dnscc_t *tdn,
221 dnsc_t *dn, unsigned dnsiz) {
222 dnsc_t *dne = dn + (dnsiz > DNS_MAXDN ? DNS_MAXDN : dnsiz);
223 dnsc_t *p;
224 unsigned l;
225 p = dns_a6todn_(addr, dn, dne);
226 if (!p) return 0;
227 if (!tdn)
228 tdn = dns_ip6_arpa_dn;
229 l = dns_dnlen(tdn);
230 if (p + l > dne) return dnsiz >= DNS_MAXDN ? -1 : 0;
231 memcpy(p, tdn, l);
232 return (p + l) - dn;
233 }
234
235 int dns_a6ptodn(const struct in6_addr *addr, const char *tname,
236 dnsc_t *dn, unsigned dnsiz) {
237 dnsc_t *p;
238 int r;
239 if (!tname)
240 return dns_a6todn(addr, NULL, dn, dnsiz);
241 p = dns_a6todn_(addr, dn, dn + dnsiz);
242 if (!p) return 0;
243 r = dns_sptodn(tname, p, dnsiz - (p - dn));
244 return r != 0 ? r : dnsiz >= DNS_MAXDN ? -1 : 0;
245 }
246
247 /* return size of buffer required to convert the dn into asciiz string.
248 * Keep in sync with dns_dntop() below.
249 */
250 unsigned dns_dntop_size(dnscc_t *dn) {
251 unsigned size = 0; /* the size reqd */
252 dnscc_t *le; /* label end */
253
254 while(*dn) {
255 /* *dn is the length of the next label, non-zero */
256 if (size)
257 ++size; /* for the dot */
258 le = dn + *dn + 1;
259 ++dn;
260 do {
261 switch(*dn) {
262 case '.':
263 case '\\':
264 /* Special modifiers in zone files. */
265 case '"':
266 case ';':
267 case '@':
268 case '$':
269 size += 2;
270 break;
271 default:
272 if (*dn <= 0x20 || *dn >= 0x7f)
273 /* \ddd decimal notation */
274 size += 4;
275 else
276 size += 1;
277 }
278 } while(++dn < le);
279 }
280 size += 1; /* zero byte at the end - string terminator */
281 return size > DNS_MAXNAME ? 0 : size;
282 }
283
284 /* Convert the dn into asciiz string.
285 * Keep in sync with dns_dntop_size() above.
286 */
287 int dns_dntop(dnscc_t *dn, char *name, unsigned namesiz) {
288 char *np = name; /* current name ptr */
289 char *const ne = name + namesiz; /* end of name */
290 dnscc_t *le; /* label end */
291
292 while(*dn) {
293 /* *dn is the length of the next label, non-zero */
294 if (np != name) {
295 if (np >= ne) goto toolong;
296 *np++ = '.';
297 }
298 le = dn + *dn + 1;
299 ++dn;
300 do {
301 switch(*dn) {
302 case '.':
303 case '\\':
304 /* Special modifiers in zone files. */
305 case '"':
306 case ';':
307 case '@':
308 case '$':
309 if (np + 2 > ne) goto toolong;
310 *np++ = '\\';
311 *np++ = *dn;
312 break;
313 default:
314 if (*dn <= 0x20 || *dn >= 0x7f) {
315 /* \ddd decimal notation */
316 if (np + 4 >= ne) goto toolong;
317 *np++ = '\\';
318 *np++ = '0' + (*dn / 100);
319 *np++ = '0' + ((*dn % 100) / 10);
320 *np++ = '0' + (*dn % 10);
321 }
322 else {
323 if (np >= ne) goto toolong;
324 *np++ = *dn;
325 }
326 }
327 } while(++dn < le);
328 }
329 if (np >= ne) goto toolong;
330 *np++ = '\0';
331 return np - name;
332 toolong:
333 return namesiz >= DNS_MAXNAME ? -1 : 0;
334 }
335
336 #ifdef TEST
337 #include <stdio.h>
338 #include <stdlib.h>
339
340 int main(int argc, char **argv) {
341 int i;
342 int sz;
343 dnsc_t dn[DNS_MAXDN+10];
344 dnsc_t *dl, *dp;
345 int isabs;
346
347 sz = (argc > 1) ? atoi(argv[1]) : 0;
348
349 for(i = 2; i < argc; ++i) {
350 int r = dns_ptodn(argv[i], 0, dn, sz, &isabs);
351 printf("%s: ", argv[i]);
352 if (r < 0) printf("error\n");
353 else if (!r) printf("buffer too small\n");
354 else {
355 printf("len=%d dnlen=%d size=%d name:",
356 r, dns_dnlen(dn), dns_dntop_size(dn));
357 dl = dn;
358 while(*dl) {
359 printf(" %d=", *dl);
360 dp = dl + 1;
361 dl = dp + *dl;
362 while(dp < dl) {
363 if (*dp <= ' ' || *dp >= 0x7f)
364 printf("\\%03d", *dp);
365 else if (*dp == '.' || *dp == '\\')
366 printf("\\%c", *dp);
367 else
368 putchar(*dp);
369 ++dp;
370 }
371 }
372 if (isabs) putchar('.');
373 putchar('\n');
374 }
375 }
376 return 0;
377 }
378
379 #endif /* TEST */