Line data Source code
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 291144 : tor_inet_aton(const char *str, struct in_addr *addr)
41 : {
42 291144 : unsigned a, b, c, d;
43 291144 : char more;
44 291144 : bool is_octal = false;
45 291144 : smartlist_t *sl = NULL;
46 :
47 291144 : 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 271336 : sl = smartlist_new();
52 271336 : smartlist_split_string(sl, str, ".", 0, 0);
53 1356651 : SMARTLIST_FOREACH(sl, const char *, octet, {
54 : is_octal = (strlen(octet) > 1 && octet[0] == '0');
55 : if (is_octal) {
56 : break;
57 : }
58 : });
59 1356680 : SMARTLIST_FOREACH(sl, char *, octet, tor_free(octet));
60 271336 : smartlist_free(sl);
61 :
62 271336 : if (is_octal)
63 : return 0;
64 :
65 271315 : if (a > 255) return 0;
66 271313 : if (b > 255) return 0;
67 271311 : if (c > 255) return 0;
68 271310 : if (d > 255) return 0;
69 271307 : addr->s_addr = htonl((a<<24) | (b<<16) | (c<<8) | d);
70 271307 : 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 53611 : tor_inet_ntoa(const struct in_addr *in, char *buf, size_t buf_len)
80 : {
81 53611 : uint32_t a = ntohl(in->s_addr);
82 107222 : return tor_snprintf(buf, buf_len, "%d.%d.%d.%d",
83 53611 : (int)(uint8_t)((a>>24)&0xff),
84 53611 : (int)(uint8_t)((a>>16)&0xff),
85 53611 : (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 54847 : tor_inet_ntop(int af, const void *src, char *dst, size_t len)
99 : {
100 54847 : if (af == AF_INET) {
101 53609 : if (tor_inet_ntoa(src, dst, len) < 0)
102 : return NULL;
103 : else
104 53606 : return dst;
105 1238 : } else if (af == AF_INET6) {
106 : const struct in6_addr *addr = src;
107 : char buf[64], *cp;
108 11142 : int longestGapLen = 0, longestGapPos = -1, i,
109 11142 : curGapPos = -1, curGapLen = 0;
110 : uint16_t words[8];
111 11142 : for (i = 0; i < 8; ++i) {
112 9904 : words[i] = (((uint16_t)addr->s6_addr[2*i])<<8) + addr->s6_addr[2*i+1];
113 : }
114 1238 : if (words[0] == 0 && words[1] == 0 && words[2] == 0 && words[3] == 0 &&
115 743 : words[4] == 0 && ((words[5] == 0 && words[6] && words[7]) ||
116 : (words[5] == 0xffff))) {
117 : /* This is an IPv4 address. */
118 7 : if (words[5] == 0) {
119 1 : tor_snprintf(buf, sizeof(buf), "::%d.%d.%d.%d",
120 1 : addr->s6_addr[12], addr->s6_addr[13],
121 1 : addr->s6_addr[14], addr->s6_addr[15]);
122 : } else {
123 6 : tor_snprintf(buf, sizeof(buf), "::%x:%d.%d.%d.%d", words[5],
124 6 : addr->s6_addr[12], addr->s6_addr[13],
125 6 : addr->s6_addr[14], addr->s6_addr[15]);
126 : }
127 7 : if ((strlen(buf) + 1) > len) /* +1 for \0 */
128 : return NULL;
129 6 : strlcpy(dst, buf, len);
130 6 : return dst;
131 : }
132 : i = 0;
133 4153 : while (i < 8) {
134 2922 : if (words[i] == 0) {
135 1185 : curGapPos = i++;
136 1185 : curGapLen = 1;
137 8111 : while (i<8 && words[i] == 0) {
138 6926 : ++i; ++curGapLen;
139 : }
140 1185 : if (curGapLen > longestGapLen) {
141 1180 : longestGapPos = curGapPos;
142 1180 : longestGapLen = curGapLen;
143 : }
144 : } else {
145 1737 : ++i;
146 : }
147 : }
148 1231 : if (longestGapLen<=1)
149 55 : longestGapPos = -1;
150 :
151 1231 : cp = buf;
152 4154 : for (i = 0; i < 8; ++i) {
153 2923 : if (words[i] == 0 && longestGapPos == i) {
154 1176 : if (i == 0)
155 736 : *cp++ = ':';
156 1176 : *cp++ = ':';
157 9277 : while (i < 8 && words[i] == 0)
158 8101 : ++i;
159 1176 : --i; /* to compensate for loop increment. */
160 : } else {
161 1747 : tor_snprintf(cp, sizeof(buf)-(cp-buf), "%x", (unsigned)words[i]);
162 1747 : cp += strlen(cp);
163 1747 : if (i != 7)
164 1196 : *cp++ = ':';
165 : }
166 : }
167 1231 : *cp = '\0';
168 1231 : if ((strlen(buf) + 1) > len) /* +1 for \0 */
169 : return NULL;
170 1228 : strlcpy(dst, buf, len);
171 1228 : 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 740640 : tor_inet_pton(int af, const char *src, void *dst)
188 : {
189 740640 : if (af == AF_INET) {
190 286261 : return tor_inet_aton(src, dst);
191 454379 : } else if (af == AF_INET6) {
192 454378 : ssize_t len = strlen(src);
193 :
194 : /* Reject if src has needless trailing ':'. */
195 454378 : if (len > 2 && src[len - 1] == ':' && src[len - 2] != ':') {
196 : return 0;
197 : }
198 :
199 454346 : struct in6_addr *out = dst;
200 454346 : uint16_t words[8];
201 454346 : int gapPos = -1, i, setWords=0;
202 454346 : const char *dot = strchr(src, '.');
203 454346 : const char *eow; /* end of words. */
204 454346 : memset(words, 0xf8, sizeof(words));
205 454346 : if (dot == src)
206 : return 0;
207 454344 : else if (!dot)
208 187393 : eow = src+strlen(src);
209 : else {
210 266951 : unsigned byte1,byte2,byte3,byte4;
211 266951 : char more;
212 656370 : for (eow = dot-1; eow > src && TOR_ISDIGIT(*eow); --eow)
213 : ;
214 266951 : if (*eow != ':')
215 266881 : return 0;
216 76 : ++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 76 : if (tor_sscanf(eow, "%3u.%3u.%3u.%3u%c",
221 : &byte1,&byte2,&byte3,&byte4,&more) != 4)
222 : return 0;
223 :
224 71 : if (byte1 > 255 || byte2 > 255 || byte3 > 255 || byte4 > 255)
225 : return 0;
226 :
227 70 : words[6] = (byte1<<8) | byte2;
228 70 : words[7] = (byte3<<8) | byte4;
229 70 : setWords += 2;
230 : }
231 :
232 187463 : i = 0;
233 543305 : while (src < eow) {
234 372363 : if (i > 7)
235 : return 0;
236 372349 : if (TOR_ISXDIGIT(*src)) {
237 187201 : char *next;
238 187201 : long r = strtol(src, &next, 16);
239 187201 : 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 120 : return 0;
244 : }
245 :
246 187201 : len = *next == '\0' ? eow - src : next - src;
247 187201 : if (len > 4)
248 : return 0;
249 187148 : if (len > 1 && !TOR_ISXDIGIT(src[1]))
250 : return 0; /* 0x is not valid */
251 :
252 187141 : tor_assert(r >= 0);
253 187141 : tor_assert(r < 65536);
254 187141 : words[i++] = (uint16_t)r;
255 187141 : setWords++;
256 187141 : src = next;
257 187141 : if (*src != ':' && src != eow)
258 : return 0;
259 187081 : ++src;
260 185148 : } else if (*src == ':' && i > 0 && gapPos == -1) {
261 116924 : gapPos = i;
262 116924 : ++src;
263 68224 : } else if (*src == ':' && i == 0 && src+1 < eow && src[1] == ':' &&
264 : gapPos == -1) {
265 51837 : gapPos = i;
266 51837 : src += 2;
267 : } else {
268 : return 0;
269 : }
270 : }
271 :
272 170942 : if (setWords > 8 ||
273 170932 : (setWords == 8 && gapPos != -1) ||
274 170931 : (setWords < 8 && gapPos == -1))
275 : return 0;
276 :
277 170906 : if (gapPos >= 0) {
278 168681 : int nToMove = setWords - (dot ? 2 : 0) - gapPos;
279 168681 : int gapLen = 8 - setWords;
280 168681 : tor_assert(nToMove >= 0);
281 168681 : memmove(&words[gapPos+gapLen], &words[gapPos],
282 : sizeof(uint16_t)*nToMove);
283 168681 : memset(&words[gapPos], 0, sizeof(uint16_t)*gapLen);
284 : }
285 1538154 : for (i = 0; i < 8; ++i) {
286 1367248 : out->s6_addr[2*i ] = words[i] >> 8;
287 1367248 : out->s6_addr[2*i+1] = words[i] & 0xff;
288 : }
289 :
290 : return 1;
291 : } else {
292 : return -1;
293 : }
294 : }
|