socketpair.c 5.8 KB

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