284 lines
8.6 KiB
C++
284 lines
8.6 KiB
C++
|
#include "stdafx.h"
|
||
|
#include "sockinfo.h"
|
||
|
|
||
|
SOCKET_INFO::SOCKET_INFO (void)
|
||
|
: Socket (INVALID_SOCKET)
|
||
|
{
|
||
|
ZeroMemory (&LocalAddress, sizeof (SOCKADDR_IN));
|
||
|
ZeroMemory (&RemoteAddress, sizeof (SOCKADDR_IN));
|
||
|
ZeroMemory (&TrivialRedirectDestAddress, sizeof (SOCKADDR_IN));
|
||
|
ZeroMemory (&TrivialRedirectSourceAddress, sizeof (SOCKADDR_IN));
|
||
|
|
||
|
IsNatRedirectActive = FALSE;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
SOCKET_INFO::Init (
|
||
|
IN SOCKET ArgSocket,
|
||
|
IN SOCKADDR_IN * ArgLocalAddress,
|
||
|
IN SOCKADDR_IN * ArgRemoteAddress)
|
||
|
{
|
||
|
assert (Socket == INVALID_SOCKET);
|
||
|
assert (ArgSocket != INVALID_SOCKET);
|
||
|
assert (ArgLocalAddress);
|
||
|
assert (ArgRemoteAddress);
|
||
|
|
||
|
Socket = ArgSocket;
|
||
|
LocalAddress = *ArgLocalAddress;
|
||
|
RemoteAddress = *ArgRemoteAddress;
|
||
|
}
|
||
|
|
||
|
|
||
|
int SOCKET_INFO::Init (
|
||
|
IN SOCKET ArgSocket,
|
||
|
IN SOCKADDR_IN * ArgRemoteAddress)
|
||
|
{
|
||
|
INT AddressLength;
|
||
|
|
||
|
assert (Socket == INVALID_SOCKET);
|
||
|
assert (ArgSocket != INVALID_SOCKET);
|
||
|
|
||
|
AddressLength = sizeof (SOCKADDR_IN);
|
||
|
|
||
|
if (getsockname (ArgSocket, (SOCKADDR *) &LocalAddress, &AddressLength)) {
|
||
|
return WSAGetLastError();
|
||
|
}
|
||
|
|
||
|
Socket = ArgSocket;
|
||
|
RemoteAddress = *ArgRemoteAddress;
|
||
|
|
||
|
return ERROR_SUCCESS;
|
||
|
}
|
||
|
|
||
|
BOOLEAN
|
||
|
SOCKET_INFO::IsSocketValid (void) {
|
||
|
return Socket != INVALID_SOCKET;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
SOCKET_INFO::SetListenInfo (
|
||
|
IN SOCKET ListenSocket,
|
||
|
IN SOCKADDR_IN * ListenAddress)
|
||
|
{
|
||
|
assert (Socket == INVALID_SOCKET);
|
||
|
assert (ListenSocket != INVALID_SOCKET);
|
||
|
assert (ListenAddress);
|
||
|
|
||
|
Socket = ListenSocket;
|
||
|
LocalAddress = *ListenAddress;
|
||
|
}
|
||
|
|
||
|
int
|
||
|
SOCKET_INFO::Connect(
|
||
|
IN SOCKADDR_IN * ArgRemoteAddress)
|
||
|
{
|
||
|
int Status;
|
||
|
DWORD LocalToRemoteInterfaceAddress;
|
||
|
|
||
|
INT AddressSize = sizeof (SOCKADDR_IN);
|
||
|
BOOL KeepaliveOption;
|
||
|
|
||
|
assert (Socket == INVALID_SOCKET);
|
||
|
assert (ArgRemoteAddress);
|
||
|
|
||
|
Status = GetBestInterfaceAddress (
|
||
|
ntohl (ArgRemoteAddress -> sin_addr.s_addr),
|
||
|
&LocalToRemoteInterfaceAddress);
|
||
|
|
||
|
if (ERROR_SUCCESS != Status) {
|
||
|
DebugF (_T("Q931: Failed to get best interface for the destination %08X:%04X.\n"),
|
||
|
SOCKADDR_IN_PRINTF (ArgRemoteAddress));
|
||
|
|
||
|
return Status;
|
||
|
}
|
||
|
|
||
|
LocalAddress.sin_family = AF_INET;
|
||
|
LocalAddress.sin_addr.s_addr = htonl (LocalToRemoteInterfaceAddress);
|
||
|
LocalAddress.sin_port = htons (0);
|
||
|
|
||
|
Socket = WSASocket (AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED);
|
||
|
|
||
|
if (Socket == INVALID_SOCKET) {
|
||
|
|
||
|
Status = WSAGetLastError ();
|
||
|
|
||
|
DebugF( _T("Q931: Destination %08X:%04X, failed to create socket"),
|
||
|
SOCKADDR_IN_PRINTF (ArgRemoteAddress));
|
||
|
|
||
|
DumpError (Status);
|
||
|
|
||
|
return Status;
|
||
|
|
||
|
}
|
||
|
|
||
|
if (SOCKET_ERROR == bind(Socket, (PSOCKADDR)&LocalAddress, AddressSize)) {
|
||
|
|
||
|
Status = WSAGetLastError ();
|
||
|
|
||
|
DebugLastError (_T("Q931: Failed to bind dest socket.\n"));
|
||
|
|
||
|
goto cleanup;
|
||
|
}
|
||
|
|
||
|
// Set keepalive on the socket
|
||
|
KeepaliveOption = TRUE;
|
||
|
if (SOCKET_ERROR == setsockopt (Socket, SOL_SOCKET, SO_KEEPALIVE,
|
||
|
(PCHAR) &KeepaliveOption, sizeof (KeepaliveOption)))
|
||
|
{
|
||
|
Status = WSAGetLastError ();
|
||
|
|
||
|
DebugLastError (_T("Q931: Failed to set keepalive on the dest socket.\n"));
|
||
|
|
||
|
goto cleanup;
|
||
|
|
||
|
}
|
||
|
|
||
|
if (getsockname (Socket, (struct sockaddr *)&LocalAddress, &AddressSize)) {
|
||
|
|
||
|
Status = WSAGetLastError ();
|
||
|
|
||
|
DebugLastError (_T("Q931: Failed to get name of TCP socket.\n"));
|
||
|
|
||
|
goto cleanup;
|
||
|
}
|
||
|
|
||
|
// Create a trivial redirect. This is used to disallow interception of
|
||
|
// Q.931 connect-attempts by more general Q.931 dynamic port redirect established
|
||
|
// during initialization of the proxy. As a side effect it helps to puncture
|
||
|
// the firewall for both H.245 and Q.931 if the firewall is enabled.
|
||
|
|
||
|
Status = CreateTrivialNatRedirect(
|
||
|
ArgRemoteAddress,
|
||
|
&LocalAddress,
|
||
|
0
|
||
|
);
|
||
|
|
||
|
if(Status != S_OK) {
|
||
|
|
||
|
goto cleanup;
|
||
|
}
|
||
|
|
||
|
RemoteAddress = *ArgRemoteAddress;
|
||
|
|
||
|
// connect to the target server
|
||
|
// -XXX- make this asynchronous some day!!!
|
||
|
Status = connect (Socket, (SOCKADDR *) ArgRemoteAddress, sizeof (SOCKADDR_IN));
|
||
|
|
||
|
if(Status) {
|
||
|
Status = WSAGetLastError ();
|
||
|
|
||
|
goto cleanup;
|
||
|
}
|
||
|
|
||
|
Status = EventMgrBindIoHandle (Socket);
|
||
|
if (Status != S_OK) {
|
||
|
goto cleanup;
|
||
|
}
|
||
|
|
||
|
return ERROR_SUCCESS;
|
||
|
|
||
|
cleanup:
|
||
|
|
||
|
Clear(TRUE);
|
||
|
|
||
|
return Status;
|
||
|
}
|
||
|
|
||
|
HRESULT SOCKET_INFO::CreateTrivialNatRedirect (
|
||
|
IN SOCKADDR_IN * ArgTrivialRedirectDestAddress,
|
||
|
IN SOCKADDR_IN * ArgTrivialRedirectSourceAddress,
|
||
|
IN ULONG RestrictedAdapterIndex)
|
||
|
{
|
||
|
HRESULT Status = S_OK;
|
||
|
ULONG ErrorCode;
|
||
|
ULONG RedirectFlags = NatRedirectFlagLoopback;
|
||
|
|
||
|
_ASSERTE(ArgTrivialRedirectDestAddress);
|
||
|
_ASSERTE(ArgTrivialRedirectSourceAddress);
|
||
|
|
||
|
// Save redirect information. It will be needed when time comes to cancel the redirect.
|
||
|
TrivialRedirectDestAddress.sin_addr.s_addr = ArgTrivialRedirectDestAddress->sin_addr.s_addr;
|
||
|
TrivialRedirectDestAddress.sin_port = ArgTrivialRedirectDestAddress->sin_port;
|
||
|
|
||
|
TrivialRedirectSourceAddress.sin_addr.s_addr = ArgTrivialRedirectSourceAddress->sin_addr.s_addr;
|
||
|
TrivialRedirectSourceAddress.sin_port = ArgTrivialRedirectSourceAddress->sin_port;
|
||
|
|
||
|
if(RestrictedAdapterIndex) {
|
||
|
|
||
|
RedirectFlags |= NatRedirectFlagRestrictAdapter;
|
||
|
}
|
||
|
|
||
|
ErrorCode = NatCreateRedirectEx (
|
||
|
NatHandle,
|
||
|
RedirectFlags,
|
||
|
IPPROTO_TCP,
|
||
|
TrivialRedirectDestAddress.sin_addr.s_addr, // destination address
|
||
|
TrivialRedirectDestAddress.sin_port, // destination port
|
||
|
TrivialRedirectSourceAddress.sin_addr.s_addr, // source addresss
|
||
|
TrivialRedirectSourceAddress.sin_port, // source port
|
||
|
TrivialRedirectDestAddress.sin_addr.s_addr, // new destination address
|
||
|
TrivialRedirectDestAddress.sin_port, // new destination port
|
||
|
TrivialRedirectSourceAddress.sin_addr.s_addr, // new source address
|
||
|
TrivialRedirectSourceAddress.sin_port, // new source port
|
||
|
RestrictedAdapterIndex, // restricted adapter index
|
||
|
NULL, // completion routine
|
||
|
NULL, // completion context
|
||
|
NULL); // notify event
|
||
|
|
||
|
if( NO_ERROR != ErrorCode) {
|
||
|
|
||
|
Status = GetLastErrorAsResult();
|
||
|
|
||
|
DebugF (_T("H323: Failed to set up trivial redirect (%08X:%04X -> %08X:%04X) => (%08X:%04X -> %08X:%04X). Error - %d.\n"),
|
||
|
SOCKADDR_IN_PRINTF(&TrivialRedirectSourceAddress), SOCKADDR_IN_PRINTF(&TrivialRedirectDestAddress),
|
||
|
SOCKADDR_IN_PRINTF(&TrivialRedirectSourceAddress), SOCKADDR_IN_PRINTF(&TrivialRedirectDestAddress),
|
||
|
ErrorCode);
|
||
|
|
||
|
}
|
||
|
else {
|
||
|
|
||
|
DebugF (_T("H323: Set up trivial redirect (%08X:%04X -> %08X:%04X) => (%08X:%04X -> %08X:%04X).\n"),
|
||
|
SOCKADDR_IN_PRINTF(&TrivialRedirectSourceAddress), SOCKADDR_IN_PRINTF(&TrivialRedirectDestAddress),
|
||
|
SOCKADDR_IN_PRINTF(&TrivialRedirectSourceAddress), SOCKADDR_IN_PRINTF(&TrivialRedirectDestAddress));
|
||
|
|
||
|
IsNatRedirectActive = TRUE;
|
||
|
}
|
||
|
|
||
|
return Status;
|
||
|
}
|
||
|
|
||
|
void SOCKET_INFO::Clear (BOOL CancelTrivialRedirect)
|
||
|
{
|
||
|
if (Socket != INVALID_SOCKET) {
|
||
|
closesocket (Socket);
|
||
|
Socket = INVALID_SOCKET;
|
||
|
}
|
||
|
|
||
|
if (CancelTrivialRedirect && IsNatRedirectActive) {
|
||
|
|
||
|
DebugF (_T("H323: Cancelling trivial redirect (%08X:%04X -> %08X:%04X) => (%08X:%04X -> %08X:%04X).\n"),
|
||
|
SOCKADDR_IN_PRINTF(&TrivialRedirectSourceAddress), SOCKADDR_IN_PRINTF(&TrivialRedirectDestAddress),
|
||
|
SOCKADDR_IN_PRINTF(&TrivialRedirectSourceAddress), SOCKADDR_IN_PRINTF(&TrivialRedirectDestAddress));
|
||
|
|
||
|
NatCancelRedirect (
|
||
|
NatHandle,
|
||
|
IPPROTO_TCP,
|
||
|
TrivialRedirectDestAddress.sin_addr.s_addr, // destination address
|
||
|
TrivialRedirectDestAddress.sin_port, // destination port
|
||
|
TrivialRedirectSourceAddress.sin_addr.s_addr, // source addresss
|
||
|
TrivialRedirectSourceAddress.sin_port, // source port
|
||
|
TrivialRedirectDestAddress.sin_addr.s_addr, // new destination address
|
||
|
TrivialRedirectDestAddress.sin_port, // new destination port
|
||
|
TrivialRedirectSourceAddress.sin_addr.s_addr, // new source address
|
||
|
TrivialRedirectSourceAddress.sin_port // new source port
|
||
|
);
|
||
|
|
||
|
IsNatRedirectActive = FALSE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
SOCKET_INFO::~SOCKET_INFO (void)
|
||
|
{
|
||
|
Clear(TRUE);
|
||
|
}
|