Tor 0.4.9.0-alpha-dev
inaddr.c
Go to the documentation of this file.
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"
15#include "lib/log/util_bug.h"
16#include "lib/malloc/malloc.h"
17#include "lib/net/inaddr_st.h"
20#include "lib/string/printf.h"
21#include "lib/string/scanf.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 */
39int
40tor_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 */
78int
79tor_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.) */
97const char *
98tor_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.) */
186int
187tor_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}
Locale-independent character-type inspection (header)
Header for compat_string.c.
int tor_inet_ntoa(const struct in_addr *in, char *buf, size_t buf_len)
Definition: inaddr.c:79
int tor_inet_aton(const char *str, struct in_addr *addr)
Definition: inaddr.c:40
int tor_inet_pton(int af, const char *src, void *dst)
Definition: inaddr.c:187
const char * tor_inet_ntop(int af, const void *src, char *dst, size_t len)
Definition: inaddr.c:98
Header for inaddr.c.
Define in6_addr, its members, and related types on platforms that lack it.
Headers for util_malloc.c.
#define tor_free(p)
Definition: malloc.h:56
int tor_snprintf(char *str, size_t size, const char *format,...)
Definition: printf.c:27
Header for printf.c.
int tor_sscanf(const char *buf, const char *pattern,...)
Definition: scanf.c:309
Header for scanf.c.
Header for smartlist.c.
smartlist_t * smartlist_new(void)
#define SMARTLIST_FOREACH(sl, type, var, cmd)
int smartlist_split_string(smartlist_t *sl, const char *str, const char *sep, int flags, int max)
Integer definitions used throughout Tor.
Macros to manage assertions, fatal and non-fatal.
#define tor_assert(expr)
Definition: util_bug.h:103
Header for util_string.c.