tor  0.4.1.0-alpha-dev
socketpair.c
1 /* Copyright (c) 2003-2004, Roger Dingledine
2  * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
3  * Copyright (c) 2007-2019, The Tor Project, Inc. */
4 
5 #include "lib/cc/torint.h"
6 #include "lib/net/socketpair.h"
7 #include "lib/net/inaddr_st.h"
8 #include "lib/arch/bytes.h"
9 
10 #include <errno.h>
11 #include <string.h>
12 
13 #ifdef HAVE_UNISTD_H
14 #include <unistd.h>
15 #endif
16 #ifdef HAVE_NETINET_IN_H
17 #include <netinet/in.h>
18 #endif
19 
20 #ifdef _WIN32
21 #include <winsock2.h>
22 #include <windows.h>
23 #define socket_errno() (WSAGetLastError())
24 #define SOCKET_EPROTONOSUPPORT WSAEPROTONOSUPPORT
25 #else
26 #define closesocket(x) close(x)
27 #define socket_errno() (errno)
28 #define SOCKET_EPROTONOSUPPORT EPROTONOSUPPORT
29 #endif
30 
31 #ifdef NEED_ERSATZ_SOCKETPAIR
32 
33 // Avoid warning about call to memcmp.
34 #define raw_memcmp memcmp
35 
41 static tor_socket_t
42 get_local_listener(int family, int type)
43 {
44  struct sockaddr_in sin;
45  struct sockaddr_in6 sin6;
46  struct sockaddr *sa;
47  int len;
48 
49  memset(&sin, 0, sizeof(sin));
50  memset(&sin6, 0, sizeof(sin6));
51 
53  sock = socket(family, type, 0);
54  if (!SOCKET_OK(sock)) {
55  return TOR_INVALID_SOCKET;
56  }
57 
58  if (family == AF_INET) {
59  sa = (struct sockaddr *) &sin;
60  sin.sin_family = AF_INET;
61  sin.sin_addr.s_addr = tor_htonl(0x7f000001);
62  len = sizeof(sin);
63  } else {
64  sa = (struct sockaddr *) &sin6;
65  sin6.sin6_family = AF_INET6;
66  sin6.sin6_addr.s6_addr[15] = 1;
67  len = sizeof(sin6);
68  }
69 
70  if (bind(sock, sa, len) == -1)
71  goto err;
72  if (listen(sock, 1) == -1)
73  goto err;
74 
75  return sock;
76  err:
77  closesocket(sock);
78  return TOR_INVALID_SOCKET;
79 }
80 
84 static int
85 sockaddr_eq(struct sockaddr *sa1, struct sockaddr *sa2)
86 {
87  if (sa1->sa_family != sa2->sa_family)
88  return 0;
89 
90  if (sa1->sa_family == AF_INET6) {
91  struct sockaddr_in6 *sin6_1 = (struct sockaddr_in6 *) sa1;
92  struct sockaddr_in6 *sin6_2 = (struct sockaddr_in6 *) sa2;
93  return sin6_1->sin6_port == sin6_2->sin6_port &&
94  0==raw_memcmp(sin6_1->sin6_addr.s6_addr, sin6_2->sin6_addr.s6_addr, 16);
95  } else if (sa1->sa_family == AF_INET) {
96  struct sockaddr_in *sin_1 = (struct sockaddr_in *) sa1;
97  struct sockaddr_in *sin_2 = (struct sockaddr_in *) sa2;
98  return sin_1->sin_port == sin_2->sin_port &&
99  sin_1->sin_addr.s_addr == sin_2->sin_addr.s_addr;
100  } else {
101  return 0;
102  }
103 }
104 
114 int
115 tor_ersatz_socketpair(int family, int type, int protocol, tor_socket_t fd[2])
116 {
117  /* This socketpair does not work when localhost is down. So
118  * it's really not the same thing at all. But it's close enough
119  * for now, and really, when localhost is down sometimes, we
120  * have other problems too.
121  */
122  tor_socket_t listener = TOR_INVALID_SOCKET;
123  tor_socket_t connector = TOR_INVALID_SOCKET;
124  tor_socket_t acceptor = TOR_INVALID_SOCKET;
125  struct sockaddr_storage accepted_addr_ss;
126  struct sockaddr_storage connect_addr_ss;
127  struct sockaddr *connect_addr = (struct sockaddr *) &connect_addr_ss;
128  struct sockaddr *accepted_addr = (struct sockaddr *) &accepted_addr_ss;
129  socklen_t size;
130  int saved_errno = -1;
131  int ersatz_domain = AF_INET;
132  socklen_t addrlen = sizeof(struct sockaddr_in);
133 
134  memset(&accepted_addr_ss, 0, sizeof(accepted_addr_ss));
135  memset(&connect_addr_ss, 0, sizeof(connect_addr_ss));
136 
137  if (protocol
138 #ifdef AF_UNIX
139  || family != AF_UNIX
140 #endif
141  ) {
142 #ifdef _WIN32
143  return -WSAEAFNOSUPPORT;
144 #else
145  return -EAFNOSUPPORT;
146 #endif
147  }
148  if (!fd) {
149  return -EINVAL;
150  }
151 
152  listener = get_local_listener(ersatz_domain, type);
153  if (!SOCKET_OK(listener)) {
154  int first_errno = socket_errno();
155  if (first_errno == SOCKET_EPROTONOSUPPORT) {
156  /* Assume we're on an IPv6-only system */
157  ersatz_domain = AF_INET6;
158  addrlen = sizeof(struct sockaddr_in6);
159  listener = get_local_listener(ersatz_domain, type);
160  }
161  if (!SOCKET_OK(listener)) {
162  /* Keep the previous behaviour, which was to return the IPv4 error.
163  * (This may be less informative on IPv6-only systems.)
164  * XX/teor - is there a better way to decide which errno to return?
165  * (I doubt we care much either way, once there is an error.)
166  */
167  return -first_errno;
168  }
169  }
170 
171  connector = socket(ersatz_domain, type, 0);
172  if (!SOCKET_OK(connector))
173  goto tidy_up_and_fail;
174  /* We want to find out the port number to connect to. */
175  size = sizeof(connect_addr_ss);
176  if (getsockname(listener, connect_addr, &size) == -1)
177  goto tidy_up_and_fail;
178  if (size != addrlen)
179  goto abort_tidy_up_and_fail;
180  if (connect(connector, connect_addr, size) == -1)
181  goto tidy_up_and_fail;
182 
183  size = sizeof(accepted_addr_ss);
184  acceptor = accept(listener, accepted_addr, &size);
185  if (!SOCKET_OK(acceptor))
186  goto tidy_up_and_fail;
187  if (size != addrlen)
188  goto abort_tidy_up_and_fail;
189  /* Now check we are talking to ourself by matching port and host on the
190  two sockets. */
191  if (getsockname(connector, connect_addr, &size) == -1)
192  goto tidy_up_and_fail;
193  /* Set *_tor_addr and *_port to the address and port that was used */
194  if (!sockaddr_eq(accepted_addr, connect_addr))
195  goto abort_tidy_up_and_fail;
196  closesocket(listener);
197  fd[0] = connector;
198  fd[1] = acceptor;
199  return 0;
200 
201  abort_tidy_up_and_fail:
202 #ifdef _WIN32
203  saved_errno = WSAECONNABORTED;
204 #else
205  saved_errno = ECONNABORTED; /* I hope this is portable and appropriate. */
206 #endif
207  tidy_up_and_fail:
208  if (saved_errno < 0)
209  saved_errno = errno;
210  if (SOCKET_OK(listener))
211  closesocket(listener);
212  if (SOCKET_OK(connector))
213  closesocket(connector);
214  if (SOCKET_OK(acceptor))
215  closesocket(acceptor);
216  return -saved_errno;
217 }
218 
219 #endif /* defined(NEED_ERSATZ_SOCKETPAIR) */
Integer definitions used throughout Tor.
Define in6_addr, its members, and related types on platforms that lack it.
#define SOCKET_OK(s)
Definition: nettypes.h:39
#define tor_socket_t
Definition: nettypes.h:36
#define TOR_INVALID_SOCKET
Definition: nettypes.h:41
Inline functions for reading and writing multibyte values from the middle of strings, and for manipulating byte order.