]> git.proxmox.com Git - mirror_edk2.git/blob - StdLib/BsdSocketLib/ns_name.c
Add Socket Libraries.
[mirror_edk2.git] / StdLib / BsdSocketLib / ns_name.c
1 /*
2 * Copyright (c) 1996 by Internet Software Consortium.
3 *
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
9 * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
10 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
11 * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
12 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
13 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
14 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
15 * SOFTWARE.
16 */
17
18 /*
19 * Portions copyright (c) 1999, 2000
20 * Intel Corporation.
21 * All rights reserved.
22 *
23 * Redistribution and use in source and binary forms, with or without
24 * modification, are permitted provided that the following conditions
25 * are met:
26 *
27 * 1. Redistributions of source code must retain the above copyright
28 * notice, this list of conditions and the following disclaimer.
29 *
30 * 2. Redistributions in binary form must reproduce the above copyright
31 * notice, this list of conditions and the following disclaimer in the
32 * documentation and/or other materials provided with the distribution.
33 *
34 * 3. All advertising materials mentioning features or use of this software
35 * must display the following acknowledgement:
36 *
37 * This product includes software developed by Intel Corporation and
38 * its contributors.
39 *
40 * 4. Neither the name of Intel Corporation or its contributors may be
41 * used to endorse or promote products derived from this software
42 * without specific prior written permission.
43 *
44 * THIS SOFTWARE IS PROVIDED BY INTEL CORPORATION AND CONTRIBUTORS ``AS IS''
45 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
46 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
47 * ARE DISCLAIMED. IN NO EVENT SHALL INTEL CORPORATION OR CONTRIBUTORS BE
48 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
49 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
50 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
51 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
52 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
53 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
54 * THE POSSIBILITY OF SUCH DAMAGE.
55 *
56 */
57
58 #ifndef lint
59 static char rcsid[] = "$Id: ns_name.c,v 1.1.1.1 2003/11/19 01:51:32 kyu3 Exp $";
60 #endif
61
62 #include <sys/types.h>
63
64 #include <netinet/in.h>
65 #include <arpa/nameser.h>
66
67 #include <errno.h>
68 #include <resolv.h>
69 #include <string.h>
70
71 /* Data. */
72
73 static char digits[] = "0123456789";
74
75 /* Forward. */
76
77 static int special(int);
78 static int printable(int);
79 static int dn_find(const u_char *, const u_char *,
80 const u_char * const *,
81 const u_char * const *);
82
83 /* Public. */
84
85 /*
86 * ns_name_ntop(src, dst, dstsiz)
87 * Convert an encoded domain name to printable ascii as per RFC1035.
88 * return:
89 * Number of bytes written to buffer, or -1 (with errno set)
90 * notes:
91 * The root is returned as "."
92 * All other domains are returned in non absolute form
93 */
94 int
95 ns_name_ntop(const u_char *src, char *dst, size_t dstsiz) {
96 const u_char *cp;
97 char *dn, *eom;
98 u_char c;
99 u_int n;
100
101 cp = src;
102 dn = dst;
103 eom = dst + dstsiz;
104
105 while ((n = *cp++) != 0) {
106 if ((n & NS_CMPRSFLGS) != 0) {
107 /* Some kind of compression pointer. */
108 errno = EMSGSIZE;
109 return (-1);
110 }
111 if (dn != dst) {
112 if (dn >= eom) {
113 errno = EMSGSIZE;
114 return (-1);
115 }
116 *dn++ = '.';
117 }
118 if (dn + n >= eom) {
119 errno = EMSGSIZE;
120 return (-1);
121 }
122 for ((void)NULL; n > 0; n--) {
123 c = *cp++;
124 if (special(c)) {
125 if (dn + 1 >= eom) {
126 errno = EMSGSIZE;
127 return (-1);
128 }
129 *dn++ = '\\';
130 *dn++ = (char)c;
131 } else if (!printable(c)) {
132 if (dn + 3 >= eom) {
133 errno = EMSGSIZE;
134 return (-1);
135 }
136 *dn++ = '\\';
137 *dn++ = digits[c / 100];
138 *dn++ = digits[(c % 100) / 10];
139 *dn++ = digits[c % 10];
140 } else {
141 if (dn >= eom) {
142 errno = EMSGSIZE;
143 return (-1);
144 }
145 *dn++ = (char)c;
146 }
147 }
148 }
149 if (dn == dst) {
150 if (dn >= eom) {
151 errno = EMSGSIZE;
152 return (-1);
153 }
154 *dn++ = '.';
155 }
156 if (dn >= eom) {
157 errno = EMSGSIZE;
158 return (-1);
159 }
160 *dn++ = '\0';
161 return ((int)(dn - dst));
162 }
163
164 /*
165 * ns_name_pton(src, dst, dstsiz)
166 * Convert a ascii string into an encoded domain name as per RFC1035.
167 * return:
168 * -1 if it fails
169 * 1 if string was fully qualified
170 * 0 is string was not fully qualified
171 * notes:
172 * Enforces label and domain length limits.
173 */
174
175 int
176 ns_name_pton(const char *src, u_char *dst, size_t dstsiz) {
177 u_char *label, *bp, *eom;
178 int c, n, escaped;
179 char *cp;
180
181 escaped = 0;
182 bp = dst;
183 eom = dst + dstsiz;
184 label = bp++;
185
186 while ((c = *src++) != 0) {
187 if (escaped) {
188 if ((cp = strchr(digits, c)) != NULL) {
189 n = (int)(cp - digits) * 100;
190 if ((c = *src++) == 0 ||
191 (cp = strchr(digits, c)) == NULL) {
192 errno = EMSGSIZE;
193 return (-1);
194 }
195 n += (int)(cp - digits) * 10;
196 if ((c = *src++) == 0 ||
197 (cp = strchr(digits, c)) == NULL) {
198 errno = EMSGSIZE;
199 return (-1);
200 }
201 n += (int)(cp - digits);
202 if (n > 255) {
203 errno = EMSGSIZE;
204 return (-1);
205 }
206 c = n;
207 }
208 escaped = 0;
209 } else if (c == '\\') {
210 escaped = 1;
211 continue;
212 } else if (c == '.') {
213 c = ((int)(bp - label) - 1);
214 if ((c & NS_CMPRSFLGS) != 0) { /* Label too big. */
215 errno = EMSGSIZE;
216 return (-1);
217 }
218 if (label >= eom) {
219 errno = EMSGSIZE;
220 return (-1);
221 }
222 *label = (u_char)c;
223 /* Fully qualified ? */
224 if (*src == '\0') {
225 if (c != 0) {
226 if (bp >= eom) {
227 errno = EMSGSIZE;
228 return (-1);
229 }
230 *bp++ = '\0';
231 }
232 if ((bp - dst) > MAXCDNAME) {
233 errno = EMSGSIZE;
234 return (-1);
235 }
236 return (1);
237 }
238 if (c == 0) {
239 errno = EMSGSIZE;
240 return (-1);
241 }
242 label = bp++;
243 continue;
244 }
245 if (bp >= eom) {
246 errno = EMSGSIZE;
247 return (-1);
248 }
249 *bp++ = (u_char)c;
250 }
251 c = ((int)(bp - label) - 1);
252 if ((c & NS_CMPRSFLGS) != 0) { /* Label too big. */
253 errno = EMSGSIZE;
254 return (-1);
255 }
256 if (label >= eom) {
257 errno = EMSGSIZE;
258 return (-1);
259 }
260 *label = (u_char)c;
261 if (c != 0) {
262 if (bp >= eom) {
263 errno = EMSGSIZE;
264 return (-1);
265 }
266 *bp++ = 0;
267 }
268 if ((bp - dst) > MAXCDNAME) { /* src too big */
269 errno = EMSGSIZE;
270 return (-1);
271 }
272 return (0);
273 }
274
275 /*
276 * ns_name_unpack(msg, eom, src, dst, dstsiz)
277 * Unpack a domain name from a message, source may be compressed.
278 * return:
279 * -1 if it fails, or consumed octets if it succeeds.
280 */
281 int
282 ns_name_unpack(const u_char *msg, const u_char *eom, const u_char *src,
283 u_char *dst, size_t dstsiz)
284 {
285 const u_char *srcp, *dstlim;
286 u_char *dstp;
287 int n, len, checked;
288
289 len = -1;
290 checked = 0;
291 dstp = dst;
292 srcp = src;
293 dstlim = dst + dstsiz;
294 if (srcp < msg || srcp >= eom) {
295 errno = EMSGSIZE;
296 return (-1);
297 }
298 /* Fetch next label in domain name. */
299 while ((n = *srcp++) != 0) {
300 /* Check for indirection. */
301 switch (n & NS_CMPRSFLGS) {
302 case 0:
303 /* Limit checks. */
304 if (dstp + n + 1 >= dstlim || srcp + n >= eom) {
305 errno = EMSGSIZE;
306 return (-1);
307 }
308 checked += n + 1;
309 *dstp++ = (u_char)n;
310 memcpy(dstp, srcp, n);
311 dstp += n;
312 srcp += n;
313 break;
314
315 case NS_CMPRSFLGS:
316 if (srcp >= eom) {
317 errno = EMSGSIZE;
318 return (-1);
319 }
320 if (len < 0)
321 len = (int)(srcp - src) + 1;
322 srcp = msg + (((n & 0x3f) << 8) | (*srcp & 0xff));
323 if (srcp < msg || srcp >= eom) { /* Out of range. */
324 errno = EMSGSIZE;
325 return (-1);
326 }
327 checked += 2;
328 /*
329 * Check for loops in the compressed name;
330 * if we've looked at the whole message,
331 * there must be a loop.
332 */
333 if (checked >= eom - msg) {
334 errno = EMSGSIZE;
335 return (-1);
336 }
337 break;
338
339 default:
340 errno = EMSGSIZE;
341 return (-1); /* flag error */
342 }
343 }
344 *dstp = '\0';
345 if (len < 0)
346 len = (int)(srcp - src);
347 return (len);
348 }
349
350 /*
351 * ns_name_pack(src, dst, dstsiz, dnptrs, lastdnptr)
352 * Pack domain name 'domain' into 'comp_dn'.
353 * return:
354 * Size of the compressed name, or -1.
355 * notes:
356 * 'dnptrs' is an array of pointers to previous compressed names.
357 * dnptrs[0] is a pointer to the beginning of the message. The array
358 * ends with NULL.
359 * 'lastdnptr' is a pointer to the end of the array pointed to
360 * by 'dnptrs'.
361 * Side effects:
362 * The list of pointers in dnptrs is updated for labels inserted into
363 * the message as we compress the name. If 'dnptr' is NULL, we don't
364 * try to compress names. If 'lastdnptr' is NULL, we don't update the
365 * list.
366 */
367 int
368 ns_name_pack(const u_char *src, u_char *dst, int dstsiz,
369 const u_char **dnptrs, const u_char **lastdnptr)
370 {
371 u_char *dstp;
372 const u_char **cpp, **lpp, *eob, *msg;
373 const u_char *srcp;
374 int n, l;
375
376 srcp = src;
377 dstp = dst;
378 eob = dstp + dstsiz;
379 lpp = cpp = NULL;
380 if (dnptrs != NULL) {
381 if ((msg = *dnptrs++) != NULL) {
382 for (cpp = dnptrs; *cpp != NULL; cpp++)
383 (void)NULL;
384 lpp = cpp; /* end of list to search */
385 }
386 } else
387 msg = NULL;
388
389 /* make sure the domain we are about to add is legal */
390 l = 0;
391 do {
392 n = *srcp;
393 if ((n & NS_CMPRSFLGS) != 0) {
394 errno = EMSGSIZE;
395 return (-1);
396 }
397 l += n + 1;
398 if (l > MAXCDNAME) {
399 errno = EMSGSIZE;
400 return (-1);
401 }
402 srcp += n + 1;
403 } while (n != 0);
404
405 srcp = src;
406 do {
407 /* Look to see if we can use pointers. */
408 n = *srcp;
409 if (n != 0 && msg != NULL) {
410 l = dn_find(srcp, msg, (const u_char * const *)dnptrs,
411 (const u_char * const *)lpp);
412 if (l >= 0) {
413 if (dstp + 1 >= eob) {
414 errno = EMSGSIZE;
415 return (-1);
416 }
417 *dstp++ = (u_char)((l >> 8) | NS_CMPRSFLGS );
418 *dstp++ = (u_char)( l % 256 );
419 return ((int)(dstp - dst));
420 }
421 /* Not found, save it. */
422 if (lastdnptr != NULL && cpp < lastdnptr - 1 &&
423 (dstp - msg) < 0x4000) {
424 *cpp++ = dstp;
425 *cpp = NULL;
426 }
427 }
428 /* copy label to buffer */
429 if (n & NS_CMPRSFLGS) { /* Should not happen. */
430 errno = EMSGSIZE;
431 return (-1);
432 }
433 if (dstp + 1 + n >= eob) {
434 errno = EMSGSIZE;
435 return (-1);
436 }
437 memcpy(dstp, srcp, n + 1);
438 srcp += n + 1;
439 dstp += n + 1;
440 } while (n != 0);
441
442 if (dstp > eob) {
443 if (msg != NULL)
444 *lpp = NULL;
445 errno = EMSGSIZE;
446 return (-1);
447 }
448 return ((int)(dstp - dst));
449 }
450
451 /*
452 * ns_name_uncompress(msg, eom, src, dst, dstsiz)
453 * Expand compressed domain name to presentation format.
454 * return:
455 * Number of bytes read out of `src', or -1 (with errno set).
456 * note:
457 * Root domain returns as "." not "".
458 */
459 int
460 ns_name_uncompress(const u_char *msg, const u_char *eom, const u_char *src,
461 char *dst, size_t dstsiz)
462 {
463 u_char tmp[NS_MAXCDNAME];
464 int n;
465
466 if ((n = ns_name_unpack(msg, eom, src, tmp, sizeof tmp)) == -1)
467 return (-1);
468 if (ns_name_ntop(tmp, dst, dstsiz) == -1)
469 return (-1);
470 return (n);
471 }
472
473 /*
474 * ns_name_compress(src, dst, dstsiz, dnptrs, lastdnptr)
475 * Compress a domain name into wire format, using compression pointers.
476 * return:
477 * Number of bytes consumed in `dst' or -1 (with errno set).
478 * notes:
479 * 'dnptrs' is an array of pointers to previous compressed names.
480 * dnptrs[0] is a pointer to the beginning of the message.
481 * The list ends with NULL. 'lastdnptr' is a pointer to the end of the
482 * array pointed to by 'dnptrs'. Side effect is to update the list of
483 * pointers for labels inserted into the message as we compress the name.
484 * If 'dnptr' is NULL, we don't try to compress names. If 'lastdnptr'
485 * is NULL, we don't update the list.
486 */
487 int
488 ns_name_compress(const char *src, u_char *dst, size_t dstsiz,
489 const u_char **dnptrs, const u_char **lastdnptr)
490 {
491 u_char tmp[NS_MAXCDNAME];
492
493 if (ns_name_pton(src, tmp, sizeof tmp) == -1)
494 return (-1);
495 return (ns_name_pack(tmp, dst, (int)dstsiz, dnptrs, lastdnptr));
496 }
497
498 /*
499 * ns_name_skip(ptrptr, eom)
500 * Advance *ptrptr to skip over the compressed name it points at.
501 * return:
502 * 0 on success, -1 (with errno set) on failure.
503 */
504 int
505 ns_name_skip(const u_char **ptrptr, const u_char *eom) {
506 const u_char *cp;
507 u_int n;
508
509 cp = *ptrptr;
510 while (cp < eom && (n = *cp++) != 0) {
511 /* Check for indirection. */
512 switch (n & NS_CMPRSFLGS) {
513 case 0: /* normal case, n == len */
514 cp += n;
515 continue;
516 case NS_CMPRSFLGS: /* indirection */
517 cp++;
518 break;
519 default: /* illegal type */
520 errno = EMSGSIZE;
521 return (-1);
522 }
523 break;
524 }
525 if (cp > eom) {
526 errno = EMSGSIZE;
527 return (-1);
528 }
529 *ptrptr = cp;
530 return (0);
531 }
532
533 /* Private. */
534
535 /*
536 * special(ch)
537 * Thinking in noninternationalized USASCII (per the DNS spec),
538 * is this characted special ("in need of quoting") ?
539 * return:
540 * boolean.
541 */
542 static int
543 special(int ch) {
544 switch (ch) {
545 case 0x22: /* '"' */
546 case 0x2E: /* '.' */
547 case 0x3B: /* ';' */
548 case 0x5C: /* '\\' */
549 /* Special modifiers in zone files. */
550 case 0x40: /* '@' */
551 case 0x24: /* '$' */
552 return (1);
553 default:
554 return (0);
555 }
556 }
557
558 /*
559 * printable(ch)
560 * Thinking in noninternationalized USASCII (per the DNS spec),
561 * is this character visible and not a space when printed ?
562 * return:
563 * boolean.
564 */
565 static int
566 printable(int ch) {
567 return (ch > 0x20 && ch < 0x7f);
568 }
569
570 /*
571 * Thinking in noninternationalized USASCII (per the DNS spec),
572 * convert this character to lower case if it's upper case.
573 */
574 static int
575 mklower(int ch) {
576 if (ch >= 0x41 && ch <= 0x5A)
577 return (ch + 0x20);
578 return (ch);
579 }
580
581 /*
582 * dn_find(domain, msg, dnptrs, lastdnptr)
583 * Search for the counted-label name in an array of compressed names.
584 * return:
585 * offset from msg if found, or -1.
586 * notes:
587 * dnptrs is the pointer to the first name on the list,
588 * not the pointer to the start of the message.
589 */
590 static int
591 dn_find(const u_char *domain, const u_char *msg,
592 const u_char * const *dnptrs,
593 const u_char * const *lastdnptr)
594 {
595 const u_char *dn, *cp, *sp;
596 const u_char * const *cpp;
597 u_int n;
598
599 for (cpp = dnptrs; cpp < lastdnptr; cpp++) {
600 dn = domain;
601 sp = cp = *cpp;
602 while ((n = *cp++) != 0) {
603 /*
604 * check for indirection
605 */
606 switch (n & NS_CMPRSFLGS) {
607 case 0: /* normal case, n == len */
608 if (n != *dn++)
609 goto next;
610 for ((void)NULL; n > 0; n--)
611 if (mklower(*dn++) != mklower(*cp++))
612 goto next;
613 /* Is next root for both ? */
614 if (*dn == '\0' && *cp == '\0')
615 return ((int)(sp - msg));
616 if (*dn)
617 continue;
618 goto next;
619
620 case NS_CMPRSFLGS: /* indirection */
621 cp = msg + (((n & 0x3f) << 8) | *cp);
622 break;
623
624 default: /* illegal type */
625 errno = EMSGSIZE;
626 return (-1);
627 }
628 }
629 next: ;
630 }
631 errno = ENOENT;
632 return (-1);
633 }