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