Tor  0.4.7.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"
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 }
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:52
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:102
Header for util_string.c.