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