318 lines
8.3 KiB
C++
318 lines
8.3 KiB
C++
#include "stdafx.h"
|
||
|
||
SYNC_COUNTER Q931SyncCounter;
|
||
ASYNC_ACCEPT Q931AsyncAccept;
|
||
SOCKADDR_IN Q931ListenSocketAddress;
|
||
HANDLE Q931LoopbackRedirectHandle;
|
||
|
||
static
|
||
HRESULT
|
||
Q931AsyncAcceptFunctionInternal (
|
||
IN PVOID Context,
|
||
IN SOCKET Socket,
|
||
IN SOCKADDR_IN * LocalAddress,
|
||
IN SOCKADDR_IN * RemoteAddress
|
||
);
|
||
|
||
|
||
void
|
||
Q931AsyncAcceptFunction (
|
||
IN PVOID Context,
|
||
IN SOCKET Socket,
|
||
IN SOCKADDR_IN * LocalAddress,
|
||
IN SOCKADDR_IN * RemoteAddress
|
||
)
|
||
{
|
||
HRESULT Result;
|
||
|
||
Result = Q931AsyncAcceptFunctionInternal (
|
||
Context,
|
||
Socket,
|
||
LocalAddress,
|
||
RemoteAddress
|
||
);
|
||
|
||
if (S_OK != Result) {
|
||
|
||
if (INVALID_SOCKET != Socket) {
|
||
|
||
closesocket (Socket);
|
||
|
||
Socket = INVALID_SOCKET;
|
||
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
static
|
||
HRESULT
|
||
Q931AsyncAcceptFunctionInternal (
|
||
IN PVOID Context,
|
||
IN SOCKET Socket,
|
||
IN SOCKADDR_IN * LocalAddress,
|
||
IN SOCKADDR_IN * RemoteAddress
|
||
)
|
||
{
|
||
CALL_BRIDGE * CallBridge;
|
||
HRESULT Result;
|
||
NAT_KEY_SESSION_MAPPING_EX_INFORMATION RedirectInformation;
|
||
ULONG RedirectInformationLength;
|
||
ULONG Error;
|
||
DWORD BestInterfaceAddress;
|
||
|
||
DebugF (_T("Q931: ----------------------------------------------------------------------\n"));
|
||
|
||
#if DBG
|
||
ExposeTimingWindow ();
|
||
#endif
|
||
|
||
// a new Q.931 connection has been accepted from the network.
|
||
// first, we determine the original addresses of the transport connection.
|
||
// if the connection was redirected to our socket (due to NAT),
|
||
// then the query of the NAT redirect table will yield the original transport addresses.
|
||
// if an errant client has connected to our service, well, we really didn't
|
||
// intend for that to happen, so we just immediately close the socket.
|
||
|
||
assert (NatHandle);
|
||
|
||
RedirectInformationLength = sizeof (RedirectInformation);
|
||
|
||
Result = NatLookupAndQueryInformationSessionMapping (
|
||
NatHandle,
|
||
IPPROTO_TCP,
|
||
LocalAddress -> sin_addr.s_addr,
|
||
LocalAddress -> sin_port,
|
||
RemoteAddress -> sin_addr.s_addr,
|
||
RemoteAddress -> sin_port,
|
||
&RedirectInformation,
|
||
&RedirectInformationLength,
|
||
NatKeySessionMappingExInformation);
|
||
|
||
if (STATUS_SUCCESS != STATUS_SUCCESS) {
|
||
|
||
DebugError (Result, _T("Q931: New connection was accepted, but it is not in the NAT redirect table -- connection will be rejected.\n"));
|
||
|
||
return Result;
|
||
}
|
||
|
||
Error = GetBestInterfaceAddress (ntohl (RedirectInformation.DestinationAddress), &BestInterfaceAddress);
|
||
|
||
if (ERROR_SUCCESS != Error) {
|
||
|
||
if (WSAEHOSTUNREACH == Error) {
|
||
|
||
Error = RasAutoDialSharedConnection ();
|
||
|
||
if (ERROR_SUCCESS != Error) {
|
||
|
||
DebugF (_T("Q931: RasAutoDialSharedConnection failed. Error=%d\n"), Error);
|
||
|
||
}
|
||
|
||
} else {
|
||
|
||
DebugError (Error, _T("LDAP: Failed to get interface address for the destination.\n"));
|
||
|
||
return HRESULT_FROM_WIN32 (Error);
|
||
}
|
||
|
||
}
|
||
|
||
// based on the source address of the socket, we decide whether the connection
|
||
// came from an internal or external client. this will govern later decisions
|
||
// on how the call is routed.
|
||
|
||
#if DBG
|
||
BOOL IsPrivateOrLocalSource;
|
||
BOOL IsPublicDestination;
|
||
|
||
Result = ::IsPrivateAddress (ntohl (RedirectInformation.SourceAddress), &IsPrivateOrLocalSource);
|
||
|
||
if (S_OK != Result) {
|
||
|
||
return Result;
|
||
}
|
||
|
||
IsPrivateOrLocalSource = IsPrivateOrLocalSource || ::NhIsLocalAddress (RedirectInformation.SourceAddress);
|
||
|
||
Result = ::IsPublicAddress (ntohl (RedirectInformation.DestinationAddress), &IsPublicDestination);
|
||
|
||
if (S_OK != Result) {
|
||
|
||
return Result;
|
||
|
||
}
|
||
|
||
if (::NhIsLocalAddress (RedirectInformation.SourceAddress) &&
|
||
::NhIsLocalAddress (RedirectInformation.DestinationAddress)) {
|
||
|
||
Debug (_T("Q931: New LOCAL connection.\n"));
|
||
|
||
} else {
|
||
|
||
if (IsPrivateOrLocalSource && IsPublicDestination) {
|
||
|
||
Debug (_T("Q931: New OUTBOUND connection.\n"));
|
||
|
||
} else {
|
||
|
||
Debug (_T("Q931: New INBOUND connection.\n"));
|
||
}
|
||
}
|
||
#endif // DBG
|
||
|
||
DebugF (_T("Q931: Connection redirected: (%08X:%04X -> %08X:%04X) => (%08X:%04X -> %08X:%04X).\n"),
|
||
ntohl (RedirectInformation.SourceAddress),
|
||
ntohs (RedirectInformation.SourcePort),
|
||
ntohl (RedirectInformation.DestinationAddress),
|
||
ntohs (RedirectInformation.DestinationPort),
|
||
ntohl (RedirectInformation.NewSourceAddress),
|
||
ntohs (RedirectInformation.NewSourcePort),
|
||
ntohl (RedirectInformation.NewDestinationAddress),
|
||
ntohs (RedirectInformation.NewDestinationPort));
|
||
|
||
CallBridge = new CALL_BRIDGE (&RedirectInformation);
|
||
|
||
if (!CallBridge) {
|
||
|
||
DebugF (_T("Q931: Failed to allocate CALL_BRIDGE.\n"));
|
||
|
||
return E_OUTOFMEMORY;
|
||
}
|
||
|
||
CallBridge -> AddRef ();
|
||
|
||
// Add the call-bridge to the list. Doing so makes an additional reference
|
||
// to the object, which is retained until the object is destroyed by calling
|
||
// RemoveCallBridge.
|
||
|
||
if (CallBridgeList.InsertCallBridge (CallBridge) == S_OK) {
|
||
|
||
// should we check the local address or the caller's address ?
|
||
// The problem is that if someone tries to connect to the
|
||
// external IP address from inside, they will still probably succeed
|
||
|
||
Result = CallBridge -> Initialize (
|
||
Socket,
|
||
LocalAddress,
|
||
RemoteAddress,
|
||
&RedirectInformation
|
||
);
|
||
|
||
if (Result != S_OK) {
|
||
|
||
CallBridge -> TerminateExternal ();
|
||
|
||
DebugF (_T("Q931: 0x%x accepted new client, but failed to initialize.\n"), CallBridge);
|
||
|
||
// Probably there was something wrong with just this
|
||
// Init failure. Continue to accept more Q.931 connections.
|
||
}
|
||
}
|
||
|
||
CallBridge -> Release ();
|
||
|
||
return Result;
|
||
}
|
||
|
||
|
||
HRESULT
|
||
Q931CreateBindSocket (
|
||
void
|
||
)
|
||
{
|
||
HRESULT Result;
|
||
SOCKADDR_IN SocketAddress;
|
||
|
||
SocketAddress.sin_family = AF_INET;
|
||
SocketAddress.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
|
||
SocketAddress.sin_port = htons (0); // request dynamic port
|
||
|
||
Result = Q931AsyncAccept.StartIo (
|
||
&SocketAddress,
|
||
Q931AsyncAcceptFunction,
|
||
NULL
|
||
);
|
||
|
||
if (Result != S_OK) {
|
||
|
||
DebugError (Result, _T("Q931: Failed to create and bind socket.\n"));
|
||
|
||
return Result;
|
||
}
|
||
|
||
DebugF (_T("Q931: Asynchronous Accept started.\n"));
|
||
|
||
Result = Q931AsyncAccept.GetListenSocketAddress (&Q931ListenSocketAddress);
|
||
|
||
if (Result != S_OK) {
|
||
|
||
DebugError (Result, _T("Q931: Failed to get listen socket address.\n"));
|
||
|
||
return Result;
|
||
|
||
}
|
||
|
||
return S_OK;
|
||
}
|
||
|
||
void
|
||
Q931CloseSocket (
|
||
void
|
||
)
|
||
{
|
||
ZeroMemory ((PVOID)&Q931ListenSocketAddress, sizeof (SOCKADDR_IN));
|
||
|
||
Q931AsyncAccept.StopWait ();
|
||
|
||
}
|
||
|
||
|
||
HRESULT
|
||
Q931StartLoopbackRedirect (
|
||
void
|
||
)
|
||
{
|
||
NTSTATUS Status;
|
||
|
||
Status = NatCreateDynamicAdapterRestrictedPortRedirect (
|
||
NatRedirectFlagLoopback | NatRedirectFlagSendOnly,
|
||
IPPROTO_TCP,
|
||
htons (Q931_TSAP_IP_TCP),
|
||
Q931ListenSocketAddress.sin_addr.s_addr,
|
||
Q931ListenSocketAddress.sin_port,
|
||
::NhMapAddressToAdapter (htonl (INADDR_LOOPBACK)),
|
||
MAX_LISTEN_BACKLOG,
|
||
&Q931LoopbackRedirectHandle);
|
||
|
||
if (Status != STATUS_SUCCESS) {
|
||
|
||
Q931LoopbackRedirectHandle = NULL;
|
||
|
||
DebugError (Status, _T("Q931: Failed to create local dynamic redirect.\n"));
|
||
|
||
return (HRESULT)Status;
|
||
}
|
||
|
||
DebugF (_T("Q931: Connections traversing loopback interface to port %04X will be redirected to %08X:%04X.\n"),
|
||
Q931_TSAP_IP_TCP,
|
||
SOCKADDR_IN_PRINTF (&Q931ListenSocketAddress));
|
||
|
||
return (HRESULT) Status;
|
||
}
|
||
|
||
|
||
void
|
||
Q931StopLoopbackRedirect (
|
||
void
|
||
)
|
||
{
|
||
if (Q931LoopbackRedirectHandle) {
|
||
|
||
NatCancelDynamicRedirect (Q931LoopbackRedirectHandle);
|
||
|
||
Q931LoopbackRedirectHandle = NULL;
|
||
}
|
||
}
|