PageRenderTime 53ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 1ms

lib/libc/inet/inet_pton.c

http://www.minix3.org/
C | 309 lines | 200 code | 25 blank | 84 comment | 78 complexity | e2fad109d0f1302942628ab27128b88d MD5 | raw file
Possible License(s): MIT, WTFPL, AGPL-1.0, BSD-3-Clause, GPL-3.0, LGPL-2.0, JSON, 0BSD
  1. /* $NetBSD: inet_pton.c,v 1.7 2009/04/12 17:07:17 christos Exp $ */
  2. /*
  3. * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
  4. * Copyright (c) 1996,1999 by Internet Software Consortium.
  5. *
  6. * Permission to use, copy, modify, and distribute this software for any
  7. * purpose with or without fee is hereby granted, provided that the above
  8. * copyright notice and this permission notice appear in all copies.
  9. *
  10. * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
  11. * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  12. * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
  13. * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  14. * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  15. * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
  16. * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  17. */
  18. #include <sys/cdefs.h>
  19. #if defined(LIBC_SCCS) && !defined(lint)
  20. #if 0
  21. static const char rcsid[] = "Id: inet_pton.c,v 1.5 2005/07/28 06:51:47 marka Exp";
  22. #else
  23. __RCSID("$NetBSD: inet_pton.c,v 1.7 2009/04/12 17:07:17 christos Exp $");
  24. #endif
  25. #endif /* LIBC_SCCS and not lint */
  26. #include "port_before.h"
  27. #include "namespace.h"
  28. #include <sys/param.h>
  29. #include <sys/types.h>
  30. #include <sys/socket.h>
  31. #include <netinet/in.h>
  32. #include <arpa/inet.h>
  33. #include <arpa/nameser.h>
  34. #include <string.h>
  35. #include <assert.h>
  36. #include <ctype.h>
  37. #include <errno.h>
  38. #include "port_after.h"
  39. #ifdef __weak_alias
  40. __weak_alias(inet_pton,_inet_pton)
  41. #endif
  42. /*%
  43. * WARNING: Don't even consider trying to compile this on a system where
  44. * sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX.
  45. */
  46. static int inet_pton4(const char *src, u_char *dst, int pton);
  47. static int inet_pton6(const char *src, u_char *dst);
  48. /* int
  49. * inet_pton(af, src, dst)
  50. * convert from presentation format (which usually means ASCII printable)
  51. * to network format (which is usually some kind of binary format).
  52. * return:
  53. * 1 if the address was valid for the specified address family
  54. * 0 if the address wasn't valid (`dst' is untouched in this case)
  55. * -1 if some other error occurred (`dst' is untouched in this case, too)
  56. * author:
  57. * Paul Vixie, 1996.
  58. */
  59. int
  60. inet_pton(int af, const char *src, void *dst)
  61. {
  62. _DIAGASSERT(src != NULL);
  63. _DIAGASSERT(dst != NULL);
  64. switch (af) {
  65. case AF_INET:
  66. return (inet_pton4(src, dst, 1));
  67. case AF_INET6:
  68. return (inet_pton6(src, dst));
  69. default:
  70. errno = EAFNOSUPPORT;
  71. return (-1);
  72. }
  73. /* NOTREACHED */
  74. }
  75. /* int
  76. * inet_pton4(src, dst, pton)
  77. * when last arg is 0: inet_aton(). with hexadecimal, octal and shorthand.
  78. * when last arg is 1: inet_pton(). decimal dotted-quad only.
  79. * return:
  80. * 1 if `src' is a valid input, else 0.
  81. * notice:
  82. * does not touch `dst' unless it's returning 1.
  83. * author:
  84. * Paul Vixie, 1996.
  85. */
  86. static int
  87. inet_pton4(const char *src, u_char *dst, int pton)
  88. {
  89. u_int32_t val;
  90. u_int digit, base;
  91. int n;
  92. unsigned char c;
  93. u_int parts[4];
  94. register u_int *pp = parts;
  95. _DIAGASSERT(src != NULL);
  96. _DIAGASSERT(dst != NULL);
  97. c = *src;
  98. for (;;) {
  99. /*
  100. * Collect number up to ``.''.
  101. * Values are specified as for C:
  102. * 0x=hex, 0=octal, isdigit=decimal.
  103. */
  104. if (!isdigit(c))
  105. return (0);
  106. val = 0; base = 10;
  107. if (c == '0') {
  108. c = *++src;
  109. if (c == 'x' || c == 'X')
  110. base = 16, c = *++src;
  111. else if (isdigit(c) && c != '9')
  112. base = 8;
  113. }
  114. /* inet_pton() takes decimal only */
  115. if (pton && base != 10)
  116. return (0);
  117. for (;;) {
  118. if (isdigit(c)) {
  119. digit = c - '0';
  120. if (digit >= base)
  121. break;
  122. val = (val * base) + digit;
  123. c = *++src;
  124. } else if (base == 16 && isxdigit(c)) {
  125. digit = c + 10 - (islower(c) ? 'a' : 'A');
  126. if (digit >= 16)
  127. break;
  128. val = (val << 4) | digit;
  129. c = *++src;
  130. } else
  131. break;
  132. }
  133. if (c == '.') {
  134. /*
  135. * Internet format:
  136. * a.b.c.d
  137. * a.b.c (with c treated as 16 bits)
  138. * a.b (with b treated as 24 bits)
  139. * a (with a treated as 32 bits)
  140. */
  141. if (pp >= parts + 3)
  142. return (0);
  143. *pp++ = val;
  144. c = *++src;
  145. } else
  146. break;
  147. }
  148. /*
  149. * Check for trailing characters.
  150. */
  151. if (c != '\0' && !isspace(c))
  152. return (0);
  153. /*
  154. * Concoct the address according to
  155. * the number of parts specified.
  156. */
  157. n = pp - parts + 1;
  158. /* inet_pton() takes dotted-quad only. it does not take shorthand. */
  159. if (pton && n != 4)
  160. return (0);
  161. switch (n) {
  162. case 0:
  163. return (0); /* initial nondigit */
  164. case 1: /* a -- 32 bits */
  165. break;
  166. case 2: /* a.b -- 8.24 bits */
  167. if (parts[0] > 0xff || val > 0xffffff)
  168. return (0);
  169. val |= parts[0] << 24;
  170. break;
  171. case 3: /* a.b.c -- 8.8.16 bits */
  172. if ((parts[0] | parts[1]) > 0xff || val > 0xffff)
  173. return (0);
  174. val |= (parts[0] << 24) | (parts[1] << 16);
  175. break;
  176. case 4: /* a.b.c.d -- 8.8.8.8 bits */
  177. if ((parts[0] | parts[1] | parts[2] | val) > 0xff)
  178. return (0);
  179. val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8);
  180. break;
  181. }
  182. if (dst) {
  183. val = htonl(val);
  184. memcpy(dst, &val, NS_INADDRSZ);
  185. }
  186. return (1);
  187. }
  188. /* int
  189. * inet_pton6(src, dst)
  190. * convert presentation level address to network order binary form.
  191. * return:
  192. * 1 if `src' is a valid [RFC1884 2.2] address, else 0.
  193. * notice:
  194. * (1) does not touch `dst' unless it's returning 1.
  195. * (2) :: in a full address is silently ignored.
  196. * credit:
  197. * inspired by Mark Andrews.
  198. * author:
  199. * Paul Vixie, 1996.
  200. */
  201. static int
  202. inet_pton6(const char *src, u_char *dst)
  203. {
  204. static const char xdigits_l[] = "0123456789abcdef",
  205. xdigits_u[] = "0123456789ABCDEF";
  206. u_char tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp;
  207. const char *xdigits, *curtok;
  208. int ch, seen_xdigits;
  209. u_int val;
  210. _DIAGASSERT(src != NULL);
  211. _DIAGASSERT(dst != NULL);
  212. memset((tp = tmp), '\0', NS_IN6ADDRSZ);
  213. endp = tp + NS_IN6ADDRSZ;
  214. colonp = NULL;
  215. /* Leading :: requires some special handling. */
  216. if (*src == ':')
  217. if (*++src != ':')
  218. return (0);
  219. curtok = src;
  220. seen_xdigits = 0;
  221. val = 0;
  222. while ((ch = *src++) != '\0') {
  223. const char *pch;
  224. if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL)
  225. pch = strchr((xdigits = xdigits_u), ch);
  226. if (pch != NULL) {
  227. val <<= 4;
  228. val |= (pch - xdigits);
  229. if (++seen_xdigits > 4)
  230. return (0);
  231. continue;
  232. }
  233. if (ch == ':') {
  234. curtok = src;
  235. if (!seen_xdigits) {
  236. if (colonp)
  237. return (0);
  238. colonp = tp;
  239. continue;
  240. } else if (*src == '\0')
  241. return (0);
  242. if (tp + NS_INT16SZ > endp)
  243. return (0);
  244. *tp++ = (u_char) (val >> 8) & 0xff;
  245. *tp++ = (u_char) val & 0xff;
  246. seen_xdigits = 0;
  247. val = 0;
  248. continue;
  249. }
  250. if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) &&
  251. inet_pton4(curtok, tp, 1) > 0) {
  252. tp += NS_INADDRSZ;
  253. seen_xdigits = 0;
  254. break; /*%< '\\0' was seen by inet_pton4(). */
  255. }
  256. return (0);
  257. }
  258. if (seen_xdigits) {
  259. if (tp + NS_INT16SZ > endp)
  260. return (0);
  261. *tp++ = (u_char) (val >> 8) & 0xff;
  262. *tp++ = (u_char) val & 0xff;
  263. }
  264. if (colonp != NULL) {
  265. /*
  266. * Since some memmove()'s erroneously fail to handle
  267. * overlapping regions, we'll do the shift by hand.
  268. */
  269. const int n = tp - colonp;
  270. int i;
  271. if (tp == endp)
  272. return (0);
  273. for (i = 1; i <= n; i++) {
  274. endp[- i] = colonp[n - i];
  275. colonp[n - i] = 0;
  276. }
  277. tp = endp;
  278. }
  279. if (tp != endp)
  280. return (0);
  281. memcpy(dst, tmp, NS_IN6ADDRSZ);
  282. return (1);
  283. }
  284. /*! \file */