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__) |
| 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 = 4, |
| 17 kIpv6AddressSize = 16, |
| 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 |