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 */
8 * \brief Convert in_addr and in6_addr to and from strings.
11 #include "lib/net/inaddr.h"
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"
24 #ifdef HAVE_ARPA_INET_H
25 #include <arpa/inet.h>
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.)
40 tor_inet_aton(const char *str
, struct in_addr
*addr
)
44 bool is_octal
= false;
45 smartlist_t
*sl
= NULL
;
47 if (tor_sscanf(str
, "%3u.%3u.%3u.%3u%c", &a
, &b
, &c
, &d
, &more
) != 4)
50 /* Parse the octets and check them for leading zeros. */
52 smartlist_split_string(sl
, str
, ".", 0, 0);
53 SMARTLIST_FOREACH(sl
, const char *, octet
, {
54 is_octal
= (strlen(octet
) > 1 && octet
[0] == '0');
59 SMARTLIST_FOREACH(sl
, char *, octet
, tor_free(octet
));
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
);
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.
79 tor_inet_ntoa(const struct in_addr
*in
, char *buf
, size_t buf_len
)
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));
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.
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
98 tor_inet_ntop(int af
, const void *src
, char *dst
, size_t len
)
101 if (tor_inet_ntoa(src
, dst
, len
) < 0)
105 } else if (af
== AF_INET6
) {
106 const struct in6_addr
*addr
= src
;
108 int longestGapLen
= 0, longestGapPos
= -1, i
,
109 curGapPos
= -1, curGapLen
= 0;
111 for (i
= 0; i
< 8; ++i
) {
112 words
[i
] = (((uint16_t)addr
->s6_addr
[2*i
])<<8) + addr
->s6_addr
[2*i
+1];
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. */
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]);
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]);
127 if ((strlen(buf
) + 1) > len
) /* +1 for \0 */
129 strlcpy(dst
, buf
, len
);
137 while (i
<8 && words
[i
] == 0) {
140 if (curGapLen
> longestGapLen
) {
141 longestGapPos
= curGapPos
;
142 longestGapLen
= curGapLen
;
148 if (longestGapLen
<=1)
152 for (i
= 0; i
< 8; ++i
) {
153 if (words
[i
] == 0 && longestGapPos
== i
) {
157 while (i
< 8 && words
[i
] == 0)
159 --i
; /* to compensate for loop increment. */
161 tor_snprintf(cp
, sizeof(buf
)-(cp
-buf
), "%x", (unsigned)words
[i
]);
168 if ((strlen(buf
) + 1) > len
) /* +1 for \0 */
170 strlcpy(dst
, buf
, len
);
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>.
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
187 tor_inet_pton(int af
, const char *src
, void *dst
)
190 return tor_inet_aton(src
, dst
);
191 } else if (af
== AF_INET6
) {
192 ssize_t len
= strlen(src
);
194 /* Reject if src has needless trailing ':'. */
195 if (len
> 2 && src
[len
- 1] == ':' && src
[len
- 2] != ':') {
199 struct in6_addr
*out
= dst
;
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
));
208 eow
= src
+strlen(src
);
210 unsigned byte1
,byte2
,byte3
,byte4
;
212 for (eow
= dot
-1; eow
> src
&& TOR_ISDIGIT(*eow
); --eow
)
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)
224 if (byte1
> 255 || byte2
> 255 || byte3
> 255 || byte4
> 255)
227 words
[6] = (byte1
<<8) | byte2
;
228 words
[7] = (byte3
<<8) | byte4
;
236 if (TOR_ISXDIGIT(*src
)) {
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
246 len
= *next
== '\0' ? eow
- src
: next
- src
;
249 if (len
> 1 && !TOR_ISXDIGIT(src
[1]))
250 return 0; /* 0x is not valid */
253 tor_assert(r
< 65536);
254 words
[i
++] = (uint16_t)r
;
257 if (*src
!= ':' && src
!= eow
)
260 } else if (*src
== ':' && i
> 0 && gapPos
== -1) {
263 } else if (*src
== ':' && i
== 0 && src
+1 < eow
&& src
[1] == ':' &&
273 (setWords
== 8 && gapPos
!= -1) ||
274 (setWords
< 8 && gapPos
== -1))
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
);
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;