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__) ... */ 148