inaddr.c (8558B)
1 /* Copyright (c) 2003-2004, Roger Dingledine 2 * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. 3 * Copyright (c) 2007-2021, The Tor Project, Inc. */ 4 /* See LICENSE for licensing information */ 5 6 /** 7 * \file inaddr.c 8 * \brief Convert in_addr and in6_addr to and from strings. 9 **/ 10 11 #include "lib/net/inaddr.h" 12 13 #include "lib/cc/torint.h" 14 #include "lib/container/smartlist.h" 15 #include "lib/log/util_bug.h" 16 #include "lib/malloc/malloc.h" 17 #include "lib/net/inaddr_st.h" 18 #include "lib/string/compat_ctype.h" 19 #include "lib/string/compat_string.h" 20 #include "lib/string/printf.h" 21 #include "lib/string/scanf.h" 22 #include "lib/string/util_string.h" 23 24 #ifdef HAVE_ARPA_INET_H 25 #include <arpa/inet.h> 26 #endif 27 28 #include <stdlib.h> 29 #include <string.h> 30 31 #ifdef _WIN32 32 #include <winsock2.h> 33 #endif 34 35 /** Set *addr to the IP address (in dotted-quad notation) stored in *str. 36 * Return 1 on success, 0 if *str is badly formatted. 37 * (Like inet_aton(str,addr), but works on Windows and Solaris.) 38 */ 39 int 40 tor_inet_aton(const char *str, struct in_addr *addr) 41 { 42 unsigned a, b, c, d; 43 char more; 44 bool is_octal = false; 45 smartlist_t *sl = NULL; 46 47 if (tor_sscanf(str, "%3u.%3u.%3u.%3u%c", &a, &b, &c, &d, &more) != 4) 48 return 0; 49 50 /* Parse the octets and check them for leading zeros. */ 51 sl = smartlist_new(); 52 smartlist_split_string(sl, str, ".", 0, 0); 53 SMARTLIST_FOREACH(sl, const char *, octet, { 54 is_octal = (strlen(octet) > 1 && octet[0] == '0'); 55 if (is_octal) { 56 break; 57 } 58 }); 59 SMARTLIST_FOREACH(sl, char *, octet, tor_free(octet)); 60 smartlist_free(sl); 61 62 if (is_octal) 63 return 0; 64 65 if (a > 255) return 0; 66 if (b > 255) return 0; 67 if (c > 255) return 0; 68 if (d > 255) return 0; 69 addr->s_addr = htonl((a<<24) | (b<<16) | (c<<8) | d); 70 return 1; 71 } 72 73 /** Given an IPv4 in_addr struct *<b>in</b> (in network order, as usual), 74 * write it as a string into the <b>buf_len</b>-byte buffer in 75 * <b>buf</b>. Returns a non-negative integer on success. 76 * Returns -1 on failure. 77 */ 78 int 79 tor_inet_ntoa(const struct in_addr *in, char *buf, size_t buf_len) 80 { 81 uint32_t a = ntohl(in->s_addr); 82 return tor_snprintf(buf, buf_len, "%d.%d.%d.%d", 83 (int)(uint8_t)((a>>24)&0xff), 84 (int)(uint8_t)((a>>16)&0xff), 85 (int)(uint8_t)((a>>8 )&0xff), 86 (int)(uint8_t)((a )&0xff)); 87 } 88 89 /** Given <b>af</b>==AF_INET and <b>src</b> a struct in_addr, or 90 * <b>af</b>==AF_INET6 and <b>src</b> a struct in6_addr, try to format the 91 * address and store it in the <b>len</b>-byte buffer <b>dst</b>. Returns 92 * <b>dst</b> on success, NULL on failure. 93 * 94 * (Like inet_ntop(af,src,dst,len), but works on platforms that don't have it: 95 * Tor sometimes needs to format ipv6 addresses even on platforms without ipv6 96 * support.) */ 97 const char * 98 tor_inet_ntop(int af, const void *src, char *dst, size_t len) 99 { 100 if (af == AF_INET) { 101 if (tor_inet_ntoa(src, dst, len) < 0) 102 return NULL; 103 else 104 return dst; 105 } else if (af == AF_INET6) { 106 const struct in6_addr *addr = src; 107 char buf[64], *cp; 108 int longestGapLen = 0, longestGapPos = -1, i, 109 curGapPos = -1, curGapLen = 0; 110 uint16_t words[8]; 111 for (i = 0; i < 8; ++i) { 112 words[i] = (((uint16_t)addr->s6_addr[2*i])<<8) + addr->s6_addr[2*i+1]; 113 } 114 if (words[0] == 0 && words[1] == 0 && words[2] == 0 && words[3] == 0 && 115 words[4] == 0 && ((words[5] == 0 && words[6] && words[7]) || 116 (words[5] == 0xffff))) { 117 /* This is an IPv4 address. */ 118 if (words[5] == 0) { 119 tor_snprintf(buf, sizeof(buf), "::%d.%d.%d.%d", 120 addr->s6_addr[12], addr->s6_addr[13], 121 addr->s6_addr[14], addr->s6_addr[15]); 122 } else { 123 tor_snprintf(buf, sizeof(buf), "::%x:%d.%d.%d.%d", words[5], 124 addr->s6_addr[12], addr->s6_addr[13], 125 addr->s6_addr[14], addr->s6_addr[15]); 126 } 127 if ((strlen(buf) + 1) > len) /* +1 for \0 */ 128 return NULL; 129 strlcpy(dst, buf, len); 130 return dst; 131 } 132 i = 0; 133 while (i < 8) { 134 if (words[i] == 0) { 135 curGapPos = i++; 136 curGapLen = 1; 137 while (i<8 && words[i] == 0) { 138 ++i; ++curGapLen; 139 } 140 if (curGapLen > longestGapLen) { 141 longestGapPos = curGapPos; 142 longestGapLen = curGapLen; 143 } 144 } else { 145 ++i; 146 } 147 } 148 if (longestGapLen<=1) 149 longestGapPos = -1; 150 151 cp = buf; 152 for (i = 0; i < 8; ++i) { 153 if (words[i] == 0 && longestGapPos == i) { 154 if (i == 0) 155 *cp++ = ':'; 156 *cp++ = ':'; 157 while (i < 8 && words[i] == 0) 158 ++i; 159 --i; /* to compensate for loop increment. */ 160 } else { 161 tor_snprintf(cp, sizeof(buf)-(cp-buf), "%x", (unsigned)words[i]); 162 cp += strlen(cp); 163 if (i != 7) 164 *cp++ = ':'; 165 } 166 } 167 *cp = '\0'; 168 if ((strlen(buf) + 1) > len) /* +1 for \0 */ 169 return NULL; 170 strlcpy(dst, buf, len); 171 return dst; 172 } else { 173 return NULL; 174 } 175 } 176 177 /** Given <b>af</b>==AF_INET or <b>af</b>==AF_INET6, and a string <b>src</b> 178 * encoding an IPv4 address or IPv6 address correspondingly, try to parse the 179 * address and store the result in <b>dst</b> (which must have space for a 180 * struct in_addr or a struct in6_addr, as appropriate). Return 1 on success, 181 * 0 on a bad parse, and -1 on a bad <b>af</b>. 182 * 183 * (Like inet_pton(af,src,dst) but works on platforms that don't have it: Tor 184 * sometimes needs to format ipv6 addresses even on platforms without ipv6 185 * support.) */ 186 int 187 tor_inet_pton(int af, const char *src, void *dst) 188 { 189 if (af == AF_INET) { 190 return tor_inet_aton(src, dst); 191 } else if (af == AF_INET6) { 192 ssize_t len = strlen(src); 193 194 /* Reject if src has needless trailing ':'. */ 195 if (len > 2 && src[len - 1] == ':' && src[len - 2] != ':') { 196 return 0; 197 } 198 199 struct in6_addr *out = dst; 200 uint16_t words[8]; 201 int gapPos = -1, i, setWords=0; 202 const char *dot = strchr(src, '.'); 203 const char *eow; /* end of words. */ 204 memset(words, 0xf8, sizeof(words)); 205 if (dot == src) 206 return 0; 207 else if (!dot) 208 eow = src+strlen(src); 209 else { 210 unsigned byte1,byte2,byte3,byte4; 211 char more; 212 for (eow = dot-1; eow > src && TOR_ISDIGIT(*eow); --eow) 213 ; 214 if (*eow != ':') 215 return 0; 216 ++eow; 217 218 /* We use "scanf" because some platform inet_aton()s are too lax 219 * about IPv4 addresses of the form "1.2.3" */ 220 if (tor_sscanf(eow, "%3u.%3u.%3u.%3u%c", 221 &byte1,&byte2,&byte3,&byte4,&more) != 4) 222 return 0; 223 224 if (byte1 > 255 || byte2 > 255 || byte3 > 255 || byte4 > 255) 225 return 0; 226 227 words[6] = (byte1<<8) | byte2; 228 words[7] = (byte3<<8) | byte4; 229 setWords += 2; 230 } 231 232 i = 0; 233 while (src < eow) { 234 if (i > 7) 235 return 0; 236 if (TOR_ISXDIGIT(*src)) { 237 char *next; 238 long r = strtol(src, &next, 16); 239 if (next == NULL || next == src) { 240 /* The 'next == src' error case can happen on versions of openbsd 241 * which treat "0xfoo" as an error, rather than as "0" followed by 242 * "xfoo". */ 243 return 0; 244 } 245 246 len = *next == '\0' ? eow - src : next - src; 247 if (len > 4) 248 return 0; 249 if (len > 1 && !TOR_ISXDIGIT(src[1])) 250 return 0; /* 0x is not valid */ 251 252 tor_assert(r >= 0); 253 tor_assert(r < 65536); 254 words[i++] = (uint16_t)r; 255 setWords++; 256 src = next; 257 if (*src != ':' && src != eow) 258 return 0; 259 ++src; 260 } else if (*src == ':' && i > 0 && gapPos == -1) { 261 gapPos = i; 262 ++src; 263 } else if (*src == ':' && i == 0 && src+1 < eow && src[1] == ':' && 264 gapPos == -1) { 265 gapPos = i; 266 src += 2; 267 } else { 268 return 0; 269 } 270 } 271 272 if (setWords > 8 || 273 (setWords == 8 && gapPos != -1) || 274 (setWords < 8 && gapPos == -1)) 275 return 0; 276 277 if (gapPos >= 0) { 278 int nToMove = setWords - (dot ? 2 : 0) - gapPos; 279 int gapLen = 8 - setWords; 280 tor_assert(nToMove >= 0); 281 memmove(&words[gapPos+gapLen], &words[gapPos], 282 sizeof(uint16_t)*nToMove); 283 memset(&words[gapPos], 0, sizeof(uint16_t)*gapLen); 284 } 285 for (i = 0; i < 8; ++i) { 286 out->s6_addr[2*i ] = words[i] >> 8; 287 out->s6_addr[2*i+1] = words[i] & 0xff; 288 } 289 290 return 1; 291 } else { 292 return -1; 293 } 294 }