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.

317 lines
8.3 KiB

  1. #include "stdafx.h"
  2. SYNC_COUNTER Q931SyncCounter;
  3. ASYNC_ACCEPT Q931AsyncAccept;
  4. SOCKADDR_IN Q931ListenSocketAddress;
  5. HANDLE Q931LoopbackRedirectHandle;
  6. static
  7. HRESULT
  8. Q931AsyncAcceptFunctionInternal (
  9. IN PVOID Context,
  10. IN SOCKET Socket,
  11. IN SOCKADDR_IN * LocalAddress,
  12. IN SOCKADDR_IN * RemoteAddress
  13. );
  14. void
  15. Q931AsyncAcceptFunction (
  16. IN PVOID Context,
  17. IN SOCKET Socket,
  18. IN SOCKADDR_IN * LocalAddress,
  19. IN SOCKADDR_IN * RemoteAddress
  20. )
  21. {
  22. HRESULT Result;
  23. Result = Q931AsyncAcceptFunctionInternal (
  24. Context,
  25. Socket,
  26. LocalAddress,
  27. RemoteAddress
  28. );
  29. if (S_OK != Result) {
  30. if (INVALID_SOCKET != Socket) {
  31. closesocket (Socket);
  32. Socket = INVALID_SOCKET;
  33. }
  34. }
  35. }
  36. static
  37. HRESULT
  38. Q931AsyncAcceptFunctionInternal (
  39. IN PVOID Context,
  40. IN SOCKET Socket,
  41. IN SOCKADDR_IN * LocalAddress,
  42. IN SOCKADDR_IN * RemoteAddress
  43. )
  44. {
  45. CALL_BRIDGE * CallBridge;
  46. HRESULT Result;
  47. NAT_KEY_SESSION_MAPPING_EX_INFORMATION RedirectInformation;
  48. ULONG RedirectInformationLength;
  49. ULONG Error;
  50. DWORD BestInterfaceAddress;
  51. DebugF (_T("Q931: ----------------------------------------------------------------------\n"));
  52. #if DBG
  53. ExposeTimingWindow ();
  54. #endif
  55. // a new Q.931 connection has been accepted from the network.
  56. // first, we determine the original addresses of the transport connection.
  57. // if the connection was redirected to our socket (due to NAT),
  58. // then the query of the NAT redirect table will yield the original transport addresses.
  59. // if an errant client has connected to our service, well, we really didn't
  60. // intend for that to happen, so we just immediately close the socket.
  61. assert (NatHandle);
  62. RedirectInformationLength = sizeof (RedirectInformation);
  63. Result = NatLookupAndQueryInformationSessionMapping (
  64. NatHandle,
  65. IPPROTO_TCP,
  66. LocalAddress -> sin_addr.s_addr,
  67. LocalAddress -> sin_port,
  68. RemoteAddress -> sin_addr.s_addr,
  69. RemoteAddress -> sin_port,
  70. &RedirectInformation,
  71. &RedirectInformationLength,
  72. NatKeySessionMappingExInformation);
  73. if (STATUS_SUCCESS != STATUS_SUCCESS) {
  74. DebugError (Result, _T("Q931: New connection was accepted, but it is not in the NAT redirect table -- connection will be rejected.\n"));
  75. return Result;
  76. }
  77. Error = GetBestInterfaceAddress (ntohl (RedirectInformation.DestinationAddress), &BestInterfaceAddress);
  78. if (ERROR_SUCCESS != Error) {
  79. if (WSAEHOSTUNREACH == Error) {
  80. Error = RasAutoDialSharedConnection ();
  81. if (ERROR_SUCCESS != Error) {
  82. DebugF (_T("Q931: RasAutoDialSharedConnection failed. Error=%d\n"), Error);
  83. }
  84. } else {
  85. DebugError (Error, _T("LDAP: Failed to get interface address for the destination.\n"));
  86. return HRESULT_FROM_WIN32 (Error);
  87. }
  88. }
  89. // based on the source address of the socket, we decide whether the connection
  90. // came from an internal or external client. this will govern later decisions
  91. // on how the call is routed.
  92. #if DBG
  93. BOOL IsPrivateOrLocalSource;
  94. BOOL IsPublicDestination;
  95. Result = ::IsPrivateAddress (ntohl (RedirectInformation.SourceAddress), &IsPrivateOrLocalSource);
  96. if (S_OK != Result) {
  97. return Result;
  98. }
  99. IsPrivateOrLocalSource = IsPrivateOrLocalSource || ::NhIsLocalAddress (RedirectInformation.SourceAddress);
  100. Result = ::IsPublicAddress (ntohl (RedirectInformation.DestinationAddress), &IsPublicDestination);
  101. if (S_OK != Result) {
  102. return Result;
  103. }
  104. if (::NhIsLocalAddress (RedirectInformation.SourceAddress) &&
  105. ::NhIsLocalAddress (RedirectInformation.DestinationAddress)) {
  106. Debug (_T("Q931: New LOCAL connection.\n"));
  107. } else {
  108. if (IsPrivateOrLocalSource && IsPublicDestination) {
  109. Debug (_T("Q931: New OUTBOUND connection.\n"));
  110. } else {
  111. Debug (_T("Q931: New INBOUND connection.\n"));
  112. }
  113. }
  114. #endif // DBG
  115. DebugF (_T("Q931: Connection redirected: (%08X:%04X -> %08X:%04X) => (%08X:%04X -> %08X:%04X).\n"),
  116. ntohl (RedirectInformation.SourceAddress),
  117. ntohs (RedirectInformation.SourcePort),
  118. ntohl (RedirectInformation.DestinationAddress),
  119. ntohs (RedirectInformation.DestinationPort),
  120. ntohl (RedirectInformation.NewSourceAddress),
  121. ntohs (RedirectInformation.NewSourcePort),
  122. ntohl (RedirectInformation.NewDestinationAddress),
  123. ntohs (RedirectInformation.NewDestinationPort));
  124. CallBridge = new CALL_BRIDGE (&RedirectInformation);
  125. if (!CallBridge) {
  126. DebugF (_T("Q931: Failed to allocate CALL_BRIDGE.\n"));
  127. return E_OUTOFMEMORY;
  128. }
  129. CallBridge -> AddRef ();
  130. // Add the call-bridge to the list. Doing so makes an additional reference
  131. // to the object, which is retained until the object is destroyed by calling
  132. // RemoveCallBridge.
  133. if (CallBridgeList.InsertCallBridge (CallBridge) == S_OK) {
  134. // should we check the local address or the caller's address ?
  135. // The problem is that if someone tries to connect to the
  136. // external IP address from inside, they will still probably succeed
  137. Result = CallBridge -> Initialize (
  138. Socket,
  139. LocalAddress,
  140. RemoteAddress,
  141. &RedirectInformation
  142. );
  143. if (Result != S_OK) {
  144. CallBridge -> TerminateExternal ();
  145. DebugF (_T("Q931: 0x%x accepted new client, but failed to initialize.\n"), CallBridge);
  146. // Probably there was something wrong with just this
  147. // Init failure. Continue to accept more Q.931 connections.
  148. }
  149. }
  150. CallBridge -> Release ();
  151. return Result;
  152. }
  153. HRESULT
  154. Q931CreateBindSocket (
  155. void
  156. )
  157. {
  158. HRESULT Result;
  159. SOCKADDR_IN SocketAddress;
  160. SocketAddress.sin_family = AF_INET;
  161. SocketAddress.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
  162. SocketAddress.sin_port = htons (0); // request dynamic port
  163. Result = Q931AsyncAccept.StartIo (
  164. &SocketAddress,
  165. Q931AsyncAcceptFunction,
  166. NULL
  167. );
  168. if (Result != S_OK) {
  169. DebugError (Result, _T("Q931: Failed to create and bind socket.\n"));
  170. return Result;
  171. }
  172. DebugF (_T("Q931: Asynchronous Accept started.\n"));
  173. Result = Q931AsyncAccept.GetListenSocketAddress (&Q931ListenSocketAddress);
  174. if (Result != S_OK) {
  175. DebugError (Result, _T("Q931: Failed to get listen socket address.\n"));
  176. return Result;
  177. }
  178. return S_OK;
  179. }
  180. void
  181. Q931CloseSocket (
  182. void
  183. )
  184. {
  185. ZeroMemory ((PVOID)&Q931ListenSocketAddress, sizeof (SOCKADDR_IN));
  186. Q931AsyncAccept.StopWait ();
  187. }
  188. HRESULT
  189. Q931StartLoopbackRedirect (
  190. void
  191. )
  192. {
  193. NTSTATUS Status;
  194. Status = NatCreateDynamicAdapterRestrictedPortRedirect (
  195. NatRedirectFlagLoopback | NatRedirectFlagSendOnly,
  196. IPPROTO_TCP,
  197. htons (Q931_TSAP_IP_TCP),
  198. Q931ListenSocketAddress.sin_addr.s_addr,
  199. Q931ListenSocketAddress.sin_port,
  200. ::NhMapAddressToAdapter (htonl (INADDR_LOOPBACK)),
  201. MAX_LISTEN_BACKLOG,
  202. &Q931LoopbackRedirectHandle);
  203. if (Status != STATUS_SUCCESS) {
  204. Q931LoopbackRedirectHandle = NULL;
  205. DebugError (Status, _T("Q931: Failed to create local dynamic redirect.\n"));
  206. return (HRESULT)Status;
  207. }
  208. DebugF (_T("Q931: Connections traversing loopback interface to port %04X will be redirected to %08X:%04X.\n"),
  209. Q931_TSAP_IP_TCP,
  210. SOCKADDR_IN_PRINTF (&Q931ListenSocketAddress));
  211. return (HRESULT) Status;
  212. }
  213. void
  214. Q931StopLoopbackRedirect (
  215. void
  216. )
  217. {
  218. if (Q931LoopbackRedirectHandle) {
  219. NatCancelDynamicRedirect (Q931LoopbackRedirectHandle);
  220. Q931LoopbackRedirectHandle = NULL;
  221. }
  222. }