socketpair.c 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  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/socket.h"
  6. #include "lib/net/address.h"
  7. #include <errno.h>
  8. #include <string.h>
  9. #ifdef NEED_ERSATZ_SOCKETPAIR
  10. static inline socklen_t
  11. SIZEOF_SOCKADDR(int domain)
  12. {
  13. switch (domain) {
  14. case AF_INET:
  15. return sizeof(struct sockaddr_in);
  16. case AF_INET6:
  17. return sizeof(struct sockaddr_in6);
  18. default:
  19. return 0;
  20. }
  21. }
  22. /**
  23. * Helper used to implement socketpair on systems that lack it, by
  24. * making a direct connection to localhost.
  25. */
  26. STATIC int
  27. tor_ersatz_socketpair(int family, int type, int protocol, tor_socket_t fd[2])
  28. {
  29. /* This socketpair does not work when localhost is down. So
  30. * it's really not the same thing at all. But it's close enough
  31. * for now, and really, when localhost is down sometimes, we
  32. * have other problems too.
  33. */
  34. tor_socket_t listener = TOR_INVALID_SOCKET;
  35. tor_socket_t connector = TOR_INVALID_SOCKET;
  36. tor_socket_t acceptor = TOR_INVALID_SOCKET;
  37. tor_addr_t listen_tor_addr;
  38. struct sockaddr_storage connect_addr_ss, listen_addr_ss;
  39. struct sockaddr *listen_addr = (struct sockaddr *) &listen_addr_ss;
  40. uint16_t listen_port = 0;
  41. tor_addr_t connect_tor_addr;
  42. uint16_t connect_port = 0;
  43. struct sockaddr *connect_addr = (struct sockaddr *) &connect_addr_ss;
  44. socklen_t size;
  45. int saved_errno = -1;
  46. int ersatz_domain = AF_INET;
  47. memset(&connect_tor_addr, 0, sizeof(connect_tor_addr));
  48. memset(&connect_addr_ss, 0, sizeof(connect_addr_ss));
  49. memset(&listen_tor_addr, 0, sizeof(listen_tor_addr));
  50. memset(&listen_addr_ss, 0, sizeof(listen_addr_ss));
  51. if (protocol
  52. #ifdef AF_UNIX
  53. || family != AF_UNIX
  54. #endif
  55. ) {
  56. #ifdef _WIN32
  57. return -WSAEAFNOSUPPORT;
  58. #else
  59. return -EAFNOSUPPORT;
  60. #endif
  61. }
  62. if (!fd) {
  63. return -EINVAL;
  64. }
  65. listener = tor_open_socket(ersatz_domain, type, 0);
  66. if (!SOCKET_OK(listener)) {
  67. int first_errno = tor_socket_errno(-1);
  68. if (first_errno == SOCK_ERRNO(EPROTONOSUPPORT)
  69. && ersatz_domain == AF_INET) {
  70. /* Assume we're on an IPv6-only system */
  71. ersatz_domain = AF_INET6;
  72. listener = tor_open_socket(ersatz_domain, type, 0);
  73. if (!SOCKET_OK(listener)) {
  74. /* Keep the previous behaviour, which was to return the IPv4 error.
  75. * (This may be less informative on IPv6-only systems.)
  76. * XX/teor - is there a better way to decide which errno to return?
  77. * (I doubt we care much either way, once there is an error.)
  78. */
  79. return -first_errno;
  80. }
  81. }
  82. }
  83. /* If there is no 127.0.0.1 or ::1, this will and must fail. Otherwise, we
  84. * risk exposing a socketpair on a routable IP address. (Some BSD jails
  85. * use a routable address for localhost. Fortunately, they have the real
  86. * AF_UNIX socketpair.) */
  87. if (ersatz_domain == AF_INET) {
  88. tor_addr_from_ipv4h(&listen_tor_addr, INADDR_LOOPBACK);
  89. } else {
  90. tor_addr_parse(&listen_tor_addr, "[::1]");
  91. }
  92. tor_assert(tor_addr_is_loopback(&listen_tor_addr));
  93. size = tor_addr_to_sockaddr(&listen_tor_addr,
  94. 0 /* kernel chooses port. */,
  95. listen_addr,
  96. sizeof(listen_addr_ss));
  97. if (bind(listener, listen_addr, size) == -1)
  98. goto tidy_up_and_fail;
  99. if (listen(listener, 1) == -1)
  100. goto tidy_up_and_fail;
  101. connector = tor_open_socket(ersatz_domain, type, 0);
  102. if (!SOCKET_OK(connector))
  103. goto tidy_up_and_fail;
  104. /* We want to find out the port number to connect to. */
  105. size = sizeof(connect_addr_ss);
  106. if (getsockname(listener, connect_addr, &size) == -1)
  107. goto tidy_up_and_fail;
  108. if (size != SIZEOF_SOCKADDR (connect_addr->sa_family))
  109. goto abort_tidy_up_and_fail;
  110. if (connect(connector, connect_addr, size) == -1)
  111. goto tidy_up_and_fail;
  112. size = sizeof(listen_addr_ss);
  113. acceptor = tor_accept_socket(listener, listen_addr, &size);
  114. if (!SOCKET_OK(acceptor))
  115. goto tidy_up_and_fail;
  116. if (size != SIZEOF_SOCKADDR(listen_addr->sa_family))
  117. goto abort_tidy_up_and_fail;
  118. /* Now check we are talking to ourself by matching port and host on the
  119. two sockets. */
  120. if (getsockname(connector, connect_addr, &size) == -1)
  121. goto tidy_up_and_fail;
  122. /* Set *_tor_addr and *_port to the address and port that was used */
  123. tor_addr_from_sockaddr(&listen_tor_addr, listen_addr, &listen_port);
  124. tor_addr_from_sockaddr(&connect_tor_addr, connect_addr, &connect_port);
  125. if (size != SIZEOF_SOCKADDR (connect_addr->sa_family)
  126. || tor_addr_compare(&listen_tor_addr, &connect_tor_addr, CMP_SEMANTIC)
  127. || listen_port != connect_port) {
  128. goto abort_tidy_up_and_fail;
  129. }
  130. tor_close_socket(listener);
  131. fd[0] = connector;
  132. fd[1] = acceptor;
  133. return 0;
  134. abort_tidy_up_and_fail:
  135. #ifdef _WIN32
  136. saved_errno = WSAECONNABORTED;
  137. #else
  138. saved_errno = ECONNABORTED; /* I hope this is portable and appropriate. */
  139. #endif
  140. tidy_up_and_fail:
  141. if (saved_errno < 0)
  142. saved_errno = errno;
  143. if (SOCKET_OK(listener))
  144. tor_close_socket(listener);
  145. if (SOCKET_OK(connector))
  146. tor_close_socket(connector);
  147. if (SOCKET_OK(acceptor))
  148. tor_close_socket(acceptor);
  149. return -saved_errno;
  150. }
  151. #endif /* defined(NEED_ERSATZ_SOCKETPAIR) */