inet_ntop.c 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261
  1. /* inet_ntop.c -- convert IPv4 and IPv6 addresses from binary to text form
  2. Copyright (C) 2005-2006, 2008-2023 Free Software Foundation, Inc.
  3. This file is free software: you can redistribute it and/or modify
  4. it under the terms of the GNU Lesser General Public License as
  5. published by the Free Software Foundation; either version 2.1 of the
  6. License, or (at your option) any later version.
  7. This file is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU Lesser General Public License for more details.
  11. You should have received a copy of the GNU Lesser General Public License
  12. along with this program. If not, see <https://www.gnu.org/licenses/>. */
  13. /*
  14. * Copyright (c) 1996-1999 by Internet Software Consortium.
  15. *
  16. * Permission to use, copy, modify, and distribute this software for any
  17. * purpose with or without fee is hereby granted, provided that the above
  18. * copyright notice and this permission notice appear in all copies.
  19. *
  20. * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
  21. * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
  22. * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
  23. * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
  24. * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
  25. * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
  26. * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
  27. * SOFTWARE.
  28. */
  29. #include <config.h>
  30. /* Specification. */
  31. #include <arpa/inet.h>
  32. /* Use this to suppress gcc's "...may be used before initialized" warnings.
  33. Beware: The Code argument must not contain commas. */
  34. #ifndef IF_LINT
  35. # if defined GCC_LINT || defined lint
  36. # define IF_LINT(Code) Code
  37. # else
  38. # define IF_LINT(Code) /* empty */
  39. # endif
  40. #endif
  41. #if HAVE_DECL_INET_NTOP
  42. # undef inet_ntop
  43. const char *
  44. rpl_inet_ntop (int af, const void *restrict src,
  45. char *restrict dst, socklen_t cnt)
  46. {
  47. return inet_ntop (af, src, dst, cnt);
  48. }
  49. #else
  50. # include <stdio.h>
  51. # include <string.h>
  52. # include <errno.h>
  53. # define NS_IN6ADDRSZ 16
  54. # define NS_INT16SZ 2
  55. /*
  56. * WARNING: Don't even consider trying to compile this on a system where
  57. * sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX.
  58. */
  59. typedef int verify_int_size[4 <= sizeof (int) ? 1 : -1];
  60. static const char *inet_ntop4 (const unsigned char *src, char *dst, socklen_t size);
  61. # if HAVE_IPV6
  62. static const char *inet_ntop6 (const unsigned char *src, char *dst, socklen_t size);
  63. # endif
  64. /* char *
  65. * inet_ntop(af, src, dst, size)
  66. * convert a network format address to presentation format.
  67. * return:
  68. * pointer to presentation format address ('dst'), or NULL (see errno).
  69. * author:
  70. * Paul Vixie, 1996.
  71. */
  72. const char *
  73. inet_ntop (int af, const void *restrict src,
  74. char *restrict dst, socklen_t cnt)
  75. {
  76. switch (af)
  77. {
  78. # if HAVE_IPV4
  79. case AF_INET:
  80. return (inet_ntop4 (src, dst, cnt));
  81. # endif
  82. # if HAVE_IPV6
  83. case AF_INET6:
  84. return (inet_ntop6 (src, dst, cnt));
  85. # endif
  86. default:
  87. errno = EAFNOSUPPORT;
  88. return (NULL);
  89. }
  90. /* NOTREACHED */
  91. }
  92. /* const char *
  93. * inet_ntop4(src, dst, size)
  94. * format an IPv4 address
  95. * return:
  96. * 'dst' (as a const)
  97. * notes:
  98. * (1) uses no statics
  99. * (2) takes a u_char* not an in_addr as input
  100. * author:
  101. * Paul Vixie, 1996.
  102. */
  103. static const char *
  104. inet_ntop4 (const unsigned char *src, char *dst, socklen_t size)
  105. {
  106. char tmp[sizeof "255.255.255.255"];
  107. int len;
  108. len = sprintf (tmp, "%u.%u.%u.%u", src[0], src[1], src[2], src[3]);
  109. if (len < 0)
  110. return NULL;
  111. if (len > size)
  112. {
  113. errno = ENOSPC;
  114. return NULL;
  115. }
  116. return strcpy (dst, tmp);
  117. }
  118. # if HAVE_IPV6
  119. /* const char *
  120. * inet_ntop6(src, dst, size)
  121. * convert IPv6 binary address into presentation (printable) format
  122. * author:
  123. * Paul Vixie, 1996.
  124. */
  125. static const char *
  126. inet_ntop6 (const unsigned char *src, char *dst, socklen_t size)
  127. {
  128. /*
  129. * Note that int32_t and int16_t need only be "at least" large enough
  130. * to contain a value of the specified size. On some systems, like
  131. * Crays, there is no such thing as an integer variable with 16 bits.
  132. * Keep this in mind if you think this function should have been coded
  133. * to use pointer overlays. All the world's not a VAX.
  134. */
  135. char tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"], *tp;
  136. struct
  137. {
  138. int base, len;
  139. } best, cur;
  140. unsigned int words[NS_IN6ADDRSZ / NS_INT16SZ];
  141. int i;
  142. /*
  143. * Preprocess:
  144. * Copy the input (bytewise) array into a wordwise array.
  145. * Find the longest run of 0x00's in src[] for :: shorthanding.
  146. */
  147. memset (words, '\0', sizeof words);
  148. for (i = 0; i < NS_IN6ADDRSZ; i += 2)
  149. words[i / 2] = (src[i] << 8) | src[i + 1];
  150. best.base = -1;
  151. cur.base = -1;
  152. IF_LINT(best.len = 0);
  153. IF_LINT(cur.len = 0);
  154. for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++)
  155. {
  156. if (words[i] == 0)
  157. {
  158. if (cur.base == -1)
  159. cur.base = i, cur.len = 1;
  160. else
  161. cur.len++;
  162. }
  163. else
  164. {
  165. if (cur.base != -1)
  166. {
  167. if (best.base == -1 || cur.len > best.len)
  168. best = cur;
  169. cur.base = -1;
  170. }
  171. }
  172. }
  173. if (cur.base != -1)
  174. {
  175. if (best.base == -1 || cur.len > best.len)
  176. best = cur;
  177. }
  178. if (best.base != -1 && best.len < 2)
  179. best.base = -1;
  180. /*
  181. * Format the result.
  182. */
  183. tp = tmp;
  184. for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++)
  185. {
  186. /* Are we inside the best run of 0x00's? */
  187. if (best.base != -1 && i >= best.base && i < (best.base + best.len))
  188. {
  189. if (i == best.base)
  190. *tp++ = ':';
  191. continue;
  192. }
  193. /* Are we following an initial run of 0x00s or any real hex? */
  194. if (i != 0)
  195. *tp++ = ':';
  196. /* Is this address an encapsulated IPv4? */
  197. if (i == 6 && best.base == 0 &&
  198. (best.len == 6 || (best.len == 5 && words[5] == 0xffff)))
  199. {
  200. if (!inet_ntop4 (src + 12, tp, sizeof tmp - (tp - tmp)))
  201. return (NULL);
  202. tp += strlen (tp);
  203. break;
  204. }
  205. {
  206. int len = sprintf (tp, "%x", words[i]);
  207. if (len < 0)
  208. return NULL;
  209. tp += len;
  210. }
  211. }
  212. /* Was it a trailing run of 0x00's? */
  213. if (best.base != -1 && (best.base + best.len) ==
  214. (NS_IN6ADDRSZ / NS_INT16SZ))
  215. *tp++ = ':';
  216. *tp++ = '\0';
  217. /*
  218. * Check for overflow, copy, and we're done.
  219. */
  220. if ((socklen_t) (tp - tmp) > size)
  221. {
  222. errno = ENOSPC;
  223. return NULL;
  224. }
  225. return strcpy (dst, tmp);
  226. }
  227. # endif
  228. #endif