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