Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

283 lines
8.6 KiB

  1. #include "stdafx.h"
  2. #include "sockinfo.h"
  3. SOCKET_INFO::SOCKET_INFO (void)
  4. : Socket (INVALID_SOCKET)
  5. {
  6. ZeroMemory (&LocalAddress, sizeof (SOCKADDR_IN));
  7. ZeroMemory (&RemoteAddress, sizeof (SOCKADDR_IN));
  8. ZeroMemory (&TrivialRedirectDestAddress, sizeof (SOCKADDR_IN));
  9. ZeroMemory (&TrivialRedirectSourceAddress, sizeof (SOCKADDR_IN));
  10. IsNatRedirectActive = FALSE;
  11. }
  12. void
  13. SOCKET_INFO::Init (
  14. IN SOCKET ArgSocket,
  15. IN SOCKADDR_IN * ArgLocalAddress,
  16. IN SOCKADDR_IN * ArgRemoteAddress)
  17. {
  18. assert (Socket == INVALID_SOCKET);
  19. assert (ArgSocket != INVALID_SOCKET);
  20. assert (ArgLocalAddress);
  21. assert (ArgRemoteAddress);
  22. Socket = ArgSocket;
  23. LocalAddress = *ArgLocalAddress;
  24. RemoteAddress = *ArgRemoteAddress;
  25. }
  26. int SOCKET_INFO::Init (
  27. IN SOCKET ArgSocket,
  28. IN SOCKADDR_IN * ArgRemoteAddress)
  29. {
  30. INT AddressLength;
  31. assert (Socket == INVALID_SOCKET);
  32. assert (ArgSocket != INVALID_SOCKET);
  33. AddressLength = sizeof (SOCKADDR_IN);
  34. if (getsockname (ArgSocket, (SOCKADDR *) &LocalAddress, &AddressLength)) {
  35. return WSAGetLastError();
  36. }
  37. Socket = ArgSocket;
  38. RemoteAddress = *ArgRemoteAddress;
  39. return ERROR_SUCCESS;
  40. }
  41. BOOLEAN
  42. SOCKET_INFO::IsSocketValid (void) {
  43. return Socket != INVALID_SOCKET;
  44. }
  45. void
  46. SOCKET_INFO::SetListenInfo (
  47. IN SOCKET ListenSocket,
  48. IN SOCKADDR_IN * ListenAddress)
  49. {
  50. assert (Socket == INVALID_SOCKET);
  51. assert (ListenSocket != INVALID_SOCKET);
  52. assert (ListenAddress);
  53. Socket = ListenSocket;
  54. LocalAddress = *ListenAddress;
  55. }
  56. int
  57. SOCKET_INFO::Connect(
  58. IN SOCKADDR_IN * ArgRemoteAddress)
  59. {
  60. int Status;
  61. DWORD LocalToRemoteInterfaceAddress;
  62. INT AddressSize = sizeof (SOCKADDR_IN);
  63. BOOL KeepaliveOption;
  64. assert (Socket == INVALID_SOCKET);
  65. assert (ArgRemoteAddress);
  66. Status = GetBestInterfaceAddress (
  67. ntohl (ArgRemoteAddress -> sin_addr.s_addr),
  68. &LocalToRemoteInterfaceAddress);
  69. if (ERROR_SUCCESS != Status) {
  70. DebugF (_T("Q931: Failed to get best interface for the destination %08X:%04X.\n"),
  71. SOCKADDR_IN_PRINTF (ArgRemoteAddress));
  72. return Status;
  73. }
  74. LocalAddress.sin_family = AF_INET;
  75. LocalAddress.sin_addr.s_addr = htonl (LocalToRemoteInterfaceAddress);
  76. LocalAddress.sin_port = htons (0);
  77. Socket = WSASocket (AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED);
  78. if (Socket == INVALID_SOCKET) {
  79. Status = WSAGetLastError ();
  80. DebugF( _T("Q931: Destination %08X:%04X, failed to create socket"),
  81. SOCKADDR_IN_PRINTF (ArgRemoteAddress));
  82. DumpError (Status);
  83. return Status;
  84. }
  85. if (SOCKET_ERROR == bind(Socket, (PSOCKADDR)&LocalAddress, AddressSize)) {
  86. Status = WSAGetLastError ();
  87. DebugLastError (_T("Q931: Failed to bind dest socket.\n"));
  88. goto cleanup;
  89. }
  90. // Set keepalive on the socket
  91. KeepaliveOption = TRUE;
  92. if (SOCKET_ERROR == setsockopt (Socket, SOL_SOCKET, SO_KEEPALIVE,
  93. (PCHAR) &KeepaliveOption, sizeof (KeepaliveOption)))
  94. {
  95. Status = WSAGetLastError ();
  96. DebugLastError (_T("Q931: Failed to set keepalive on the dest socket.\n"));
  97. goto cleanup;
  98. }
  99. if (getsockname (Socket, (struct sockaddr *)&LocalAddress, &AddressSize)) {
  100. Status = WSAGetLastError ();
  101. DebugLastError (_T("Q931: Failed to get name of TCP socket.\n"));
  102. goto cleanup;
  103. }
  104. // Create a trivial redirect. This is used to disallow interception of
  105. // Q.931 connect-attempts by more general Q.931 dynamic port redirect established
  106. // during initialization of the proxy. As a side effect it helps to puncture
  107. // the firewall for both H.245 and Q.931 if the firewall is enabled.
  108. Status = CreateTrivialNatRedirect(
  109. ArgRemoteAddress,
  110. &LocalAddress,
  111. 0
  112. );
  113. if(Status != S_OK) {
  114. goto cleanup;
  115. }
  116. RemoteAddress = *ArgRemoteAddress;
  117. // connect to the target server
  118. // -XXX- make this asynchronous some day!!!
  119. Status = connect (Socket, (SOCKADDR *) ArgRemoteAddress, sizeof (SOCKADDR_IN));
  120. if(Status) {
  121. Status = WSAGetLastError ();
  122. goto cleanup;
  123. }
  124. Status = EventMgrBindIoHandle (Socket);
  125. if (Status != S_OK) {
  126. goto cleanup;
  127. }
  128. return ERROR_SUCCESS;
  129. cleanup:
  130. Clear(TRUE);
  131. return Status;
  132. }
  133. HRESULT SOCKET_INFO::CreateTrivialNatRedirect (
  134. IN SOCKADDR_IN * ArgTrivialRedirectDestAddress,
  135. IN SOCKADDR_IN * ArgTrivialRedirectSourceAddress,
  136. IN ULONG RestrictedAdapterIndex)
  137. {
  138. HRESULT Status = S_OK;
  139. ULONG ErrorCode;
  140. ULONG RedirectFlags = NatRedirectFlagLoopback;
  141. _ASSERTE(ArgTrivialRedirectDestAddress);
  142. _ASSERTE(ArgTrivialRedirectSourceAddress);
  143. // Save redirect information. It will be needed when time comes to cancel the redirect.
  144. TrivialRedirectDestAddress.sin_addr.s_addr = ArgTrivialRedirectDestAddress->sin_addr.s_addr;
  145. TrivialRedirectDestAddress.sin_port = ArgTrivialRedirectDestAddress->sin_port;
  146. TrivialRedirectSourceAddress.sin_addr.s_addr = ArgTrivialRedirectSourceAddress->sin_addr.s_addr;
  147. TrivialRedirectSourceAddress.sin_port = ArgTrivialRedirectSourceAddress->sin_port;
  148. if(RestrictedAdapterIndex) {
  149. RedirectFlags |= NatRedirectFlagRestrictAdapter;
  150. }
  151. ErrorCode = NatCreateRedirectEx (
  152. NatHandle,
  153. RedirectFlags,
  154. IPPROTO_TCP,
  155. TrivialRedirectDestAddress.sin_addr.s_addr, // destination address
  156. TrivialRedirectDestAddress.sin_port, // destination port
  157. TrivialRedirectSourceAddress.sin_addr.s_addr, // source addresss
  158. TrivialRedirectSourceAddress.sin_port, // source port
  159. TrivialRedirectDestAddress.sin_addr.s_addr, // new destination address
  160. TrivialRedirectDestAddress.sin_port, // new destination port
  161. TrivialRedirectSourceAddress.sin_addr.s_addr, // new source address
  162. TrivialRedirectSourceAddress.sin_port, // new source port
  163. RestrictedAdapterIndex, // restricted adapter index
  164. NULL, // completion routine
  165. NULL, // completion context
  166. NULL); // notify event
  167. if( NO_ERROR != ErrorCode) {
  168. Status = GetLastErrorAsResult();
  169. DebugF (_T("H323: Failed to set up trivial redirect (%08X:%04X -> %08X:%04X) => (%08X:%04X -> %08X:%04X). Error - %d.\n"),
  170. SOCKADDR_IN_PRINTF(&TrivialRedirectSourceAddress), SOCKADDR_IN_PRINTF(&TrivialRedirectDestAddress),
  171. SOCKADDR_IN_PRINTF(&TrivialRedirectSourceAddress), SOCKADDR_IN_PRINTF(&TrivialRedirectDestAddress),
  172. ErrorCode);
  173. }
  174. else {
  175. DebugF (_T("H323: Set up trivial redirect (%08X:%04X -> %08X:%04X) => (%08X:%04X -> %08X:%04X).\n"),
  176. SOCKADDR_IN_PRINTF(&TrivialRedirectSourceAddress), SOCKADDR_IN_PRINTF(&TrivialRedirectDestAddress),
  177. SOCKADDR_IN_PRINTF(&TrivialRedirectSourceAddress), SOCKADDR_IN_PRINTF(&TrivialRedirectDestAddress));
  178. IsNatRedirectActive = TRUE;
  179. }
  180. return Status;
  181. }
  182. void SOCKET_INFO::Clear (BOOL CancelTrivialRedirect)
  183. {
  184. if (Socket != INVALID_SOCKET) {
  185. closesocket (Socket);
  186. Socket = INVALID_SOCKET;
  187. }
  188. if (CancelTrivialRedirect && IsNatRedirectActive) {
  189. DebugF (_T("H323: Cancelling trivial redirect (%08X:%04X -> %08X:%04X) => (%08X:%04X -> %08X:%04X).\n"),
  190. SOCKADDR_IN_PRINTF(&TrivialRedirectSourceAddress), SOCKADDR_IN_PRINTF(&TrivialRedirectDestAddress),
  191. SOCKADDR_IN_PRINTF(&TrivialRedirectSourceAddress), SOCKADDR_IN_PRINTF(&TrivialRedirectDestAddress));
  192. NatCancelRedirect (
  193. NatHandle,
  194. IPPROTO_TCP,
  195. TrivialRedirectDestAddress.sin_addr.s_addr, // destination address
  196. TrivialRedirectDestAddress.sin_port, // destination port
  197. TrivialRedirectSourceAddress.sin_addr.s_addr, // source addresss
  198. TrivialRedirectSourceAddress.sin_port, // source port
  199. TrivialRedirectDestAddress.sin_addr.s_addr, // new destination address
  200. TrivialRedirectDestAddress.sin_port, // new destination port
  201. TrivialRedirectSourceAddress.sin_addr.s_addr, // new source address
  202. TrivialRedirectSourceAddress.sin_port // new source port
  203. );
  204. IsNatRedirectActive = FALSE;
  205. }
  206. }
  207. SOCKET_INFO::~SOCKET_INFO (void)
  208. {
  209. Clear(TRUE);
  210. }