OLD | NEW |
| (Empty) |
1 /* Copyright 2013 The Chromium Authors. All rights reserved. | |
2 * Use of this source code is governed by a BSD-style license that can be | |
3 * found in the LICENSE file. */ | |
4 | |
5 #include "nacl_io/ossocket.h" | |
6 #if defined(PROVIDES_SOCKET_API) && !defined(__GLIBC__) && !defined(__BIONIC__) | |
7 | |
8 #include <ctype.h> | |
9 #include <errno.h> | |
10 #include <stdlib.h> | |
11 #include <string.h> | |
12 | |
13 #include "sdk_util/macros.h" | |
14 | |
15 enum { | |
16 kIpv4AddressSize = sizeof(in_addr_t), | |
17 kIpv6AddressSize = sizeof(struct in6_addr), | |
18 }; | |
19 | |
20 /* Helper function for inet_pton() for IPv4 addresses. */ | |
21 static int inet_pton_v4(const char* src, void* dst) { | |
22 const char* pos = src; | |
23 uint8_t result[kIpv4AddressSize] = {0}; | |
24 | |
25 int i; | |
26 for (i = 0; i < kIpv4AddressSize; ++i) { | |
27 /* strtol() won't treat whitespace characters in the beginning as an error, | |
28 * so check to ensure this is started with digit before passing to strtol(). | |
29 */ | |
30 if (isspace((int)(*pos))) | |
31 return 0; | |
32 char* end_pos; | |
33 unsigned long value = strtoul(pos, &end_pos, 10); | |
34 if (value > 255 || pos == end_pos) | |
35 return 0; | |
36 result[i] = (unsigned char)value; | |
37 pos = end_pos; | |
38 | |
39 if (i < (kIpv4AddressSize - 1)) { | |
40 if (*pos != '.') | |
41 return 0; | |
42 ++pos; | |
43 } | |
44 } | |
45 if (*pos != '\0') | |
46 return 0; | |
47 memcpy(dst, result, sizeof(result)); | |
48 return 1; | |
49 } | |
50 | |
51 /* Helper function for inet_pton() for IPv6 addresses. */ | |
52 int inet_pton_v6(const char* src, void* dst) { | |
53 /* strtol() skips 0x in from of a number, while it's not allowed in IPv6 | |
54 * addresses. Check that there is no 'x' in the string. */ | |
55 const char* pos = src; | |
56 while (*pos != '\0') { | |
57 if (*pos == 'x') | |
58 return 0; | |
59 pos++; | |
60 } | |
61 pos = src; | |
62 | |
63 uint8_t result[kIpv6AddressSize]; | |
64 memset(&result, 0, sizeof(result)); | |
65 int double_colon_pos = -1; | |
66 int result_pos = 0; | |
67 | |
68 if (*pos == ':') { | |
69 if (*(pos + 1) != ':') | |
70 return 0; | |
71 pos += 2; | |
72 double_colon_pos = 0; | |
73 } | |
74 | |
75 while (*pos != '\0') { | |
76 /* strtol() won't treat whitespace characters in the beginning as an error, | |
77 * so check to ensure this is started with digit before passing to strtol(). | |
78 */ | |
79 if (isspace((int)(*pos))) | |
80 return 0; | |
81 char* end_pos; | |
82 unsigned long word = strtoul(pos, &end_pos, 16); | |
83 if (word > 0xffff || pos == end_pos) | |
84 return 0; | |
85 | |
86 if (*end_pos == '.') { | |
87 if (result_pos + kIpv4AddressSize > kIpv6AddressSize) | |
88 return 0; | |
89 /* Parse rest of address as IPv4 address. */ | |
90 if (!inet_pton_v4(pos, result + result_pos)) | |
91 return 0; | |
92 result_pos += 4; | |
93 break; | |
94 } | |
95 | |
96 if (result_pos > kIpv6AddressSize - 2) | |
97 return 0; | |
98 result[result_pos] = (word & 0xFF00) >> 8; | |
99 result[result_pos + 1] = word & 0xFF; | |
100 result_pos += 2; | |
101 | |
102 if (*end_pos == '\0') | |
103 break; | |
104 | |
105 if (*end_pos != ':') | |
106 return 0; | |
107 | |
108 pos = end_pos + 1; | |
109 if (*pos == ':') { | |
110 if (double_colon_pos != -1) | |
111 return 0; | |
112 double_colon_pos = result_pos; | |
113 ++pos; | |
114 } | |
115 } | |
116 | |
117 /* Finally move the data to the end in case the address contained '::'. */ | |
118 if (result_pos < kIpv6AddressSize) { | |
119 if (double_colon_pos == -1) | |
120 return 0; | |
121 int move_size = result_pos - double_colon_pos; | |
122 int gap_size = kIpv6AddressSize - result_pos; | |
123 memmove(result + kIpv6AddressSize - move_size, | |
124 result + double_colon_pos, move_size); | |
125 memset(result + double_colon_pos, 0, gap_size); | |
126 } | |
127 | |
128 /* Finally copy the result to the output buffer. */ | |
129 memcpy(dst, result, sizeof(result)); | |
130 | |
131 return 1; | |
132 } | |
133 | |
134 int inet_pton(int af, const char *src, void *dst) { | |
135 if (!src || !dst) { | |
136 return 0; | |
137 } | |
138 if (af == AF_INET) { | |
139 return inet_pton_v4(src, dst); | |
140 } else if (af == AF_INET6) { | |
141 return inet_pton_v6(src, dst); | |
142 } | |
143 errno = EAFNOSUPPORT; | |
144 return -1; | |
145 } | |
146 | |
147 #endif /* defined(PROVIDES_SOCKET_API) && !defined(__GLIBC__) ... */ | |
OLD | NEW |