|
|
/*++
Copyright (c) 2001 Microsoft Corporation
Module Name:
ApplicationGatewayServices.cpp : Implementation of CApplicationGatewayServices
Abstract:
This module contains routines for the ALG Manager module's that expose a public api via COM.
Author:
Jon Burstein Jean-Pierre Duplessis
JPDup 10-Nov-2000
Revision History:
--*/
/////////////////////////////////////////////////////////////////////////////
// CApplicationGatewayServices
//
// ApplicationGatewayServices.cpp : Implementation of CApplicationGatewayServices
//
#include "PreComp.h"
#include "AlgController.h"
#include "ApplicationGatewayServices.h"
#include "PendingProxyConnection.h"
#include "DataChannel.h"
#include "PersistentDataChannel.h"
#include "EnumAdapterInfo.h"
STDMETHODIMP CApplicationGatewayServices::CreatePrimaryControlChannel( IN ALG_PROTOCOL eProtocol, IN USHORT usPortToCapture, IN ALG_CAPTURE eCaptureType, IN BOOL fCaptureInbound, IN ULONG ulListenAddress, IN USHORT usListenPort, OUT IPrimaryControlChannel** ppIControlChannel ) /*++
Routine Description:
Arguments:
eProtocol, usPortToCapture, eCaptureType, fCaptureInbound, ulListenAddress, usListenPort, ppIControlChannel
Return Value:
HRESULT - S_OK for success
Environment:
ALG module will call this method to:
--*/ { MYTRACE_ENTER("CApplicationGatewayServices::CreatePrimaryControlChannel") MYTRACE("eProtocol %s", eProtocol==1? "TCP" : "UDP"); MYTRACE("usPortToCapture %d", ntohs(usPortToCapture)); MYTRACE("eCaptureType %s", eCaptureType==eALG_SOURCE_CAPTURE ? "eALG_SOURCE_CAPTURE" : "eALG_DESTINATION_CAPTURE"); MYTRACE("fCaptureInbound %d", fCaptureInbound); MYTRACE("ulListenAddress %s:%d", MYTRACE_IP(ulListenAddress), ntohs(usListenPort));
if ( !ppIControlChannel ) { MYTRACE_ERROR("ppIControlChannel not supplied",0); return E_INVALIDARG; }
if ( eProtocol != eALG_TCP && eProtocol != eALG_UDP ) { MYTRACE_ERROR("Arg - eProtocol",0); return E_INVALIDARG; }
if ( eCaptureType == eALG_SOURCE_CAPTURE && fCaptureInbound ) { MYTRACE_ERROR("Can not have SOURCE CAPTURE and fCaptureInBount at same time",0); return E_INVALIDARG; }
HRESULT hr;
//
// Add new ControlChannel to List of RULES
//
CComObject<CPrimaryControlChannel>* pIChannel; hr = CComObject<CPrimaryControlChannel>::CreateInstance(&pIChannel);
if ( SUCCEEDED(hr) ) { pIChannel->AddRef();
pIChannel->m_Properties.eProtocol = eProtocol; pIChannel->m_Properties.eCaptureType = eCaptureType; pIChannel->m_Properties.fCaptureInbound = fCaptureInbound; pIChannel->m_Properties.ulListeningAddress = ulListenAddress; pIChannel->m_Properties.usCapturePort = usPortToCapture; pIChannel->m_Properties.usListeningPort = usListenPort;
hr = pIChannel->QueryInterface(IID_IPrimaryControlChannel, (void**)ppIControlChannel);
if ( SUCCEEDED(hr) ) { hr = g_pAlgController->m_ControlChannelsPrimary.Add(pIChannel);
if ( FAILED(hr) ) { MYTRACE_ERROR("from m_ControlChannelsPrimary.Add", hr);
(*ppIControlChannel)->Release(); *ppIControlChannel = NULL; } } else { MYTRACE_ERROR("from pIChannel->QueryInterface", hr); }
pIChannel->Release(); } else { MYTRACE_ERROR("CreateInstance(&pIChannel);", hr); }
return hr; }
STDMETHODIMP CApplicationGatewayServices::CreateSecondaryControlChannel( IN ALG_PROTOCOL eProtocol,
IN ULONG ulPrivateAddress, IN USHORT usPrivatePort,
IN ULONG ulPublicAddress, IN USHORT usPublicPort,
IN ULONG ulRemoteAddress, IN USHORT usRemotePort,
IN ULONG ulListenAddress, IN USHORT usListenPort,
IN ALG_DIRECTION eDirection, IN BOOL fPersistent, OUT ISecondaryControlChannel** ppIControlChannel ) /*++
Routine Description:
Arguments:
eProtocol, ulPrivateAddress, usPrivatePort, ulPublicAddress, usPublicPort, ulRemoteAddress, usRemotePort, ulListenAddress, usListenPort, eDirection, fPersistent, ppIControlChannel
Return Value:
HRESULT - S_OK for success
Environment:
ALG module will call this method to:
--*/ { MYTRACE_ENTER("CApplicationGatewayServices::CreateSecondaryControlChannel");
if ( !ppIControlChannel ) { MYTRACE_ERROR("ppIControlChannel not supplied",0); return E_INVALIDARG; }
ULONG ulSourceAddress=0; USHORT usSourcePort=0;
ULONG ulDestinationAddress=0; USHORT usDestinationPort=0;
ULONG ulNewSourceAddress=0; USHORT usNewSourcePort=0;
ULONG ulNewDestinationAddress=0; USHORT usNewDestinationPort=0;
ULONG nFlags=0;
ULONG ulRestrictAdapterIndex=0;
if ( eALG_INBOUND == eDirection ) { if ( ulPublicAddress == 0 || usPublicPort == 0 ) { //
// Madatory arguments for INBOUND
//
MYTRACE_ERROR("ulPublicAddress == 0 || usPublicPort == 0", E_INVALIDARG); return E_INVALIDARG; }
//
// All inbound cases map to a single redirect; unlike a primary control channel, there's no need to create per-adapter redirects.
//
if ( ulRemoteAddress==0 && usRemotePort == 0 ) { //
// Scenario #1a
//
// Inbound connection from unknown machine
//
MYTRACE("SCENARIO:eALG_INBOUND #1a");
nFlags = NatRedirectFlagReceiveOnly;
ulSourceAddress = 0; usSourcePort = 0;
ulDestinationAddress = ulPublicAddress; usDestinationPort = usPublicPort;
ulNewSourceAddress = 0; usNewSourcePort = 0;
ulNewDestinationAddress = ulListenAddress; usNewDestinationPort = usListenPort;
ulRestrictAdapterIndex = 0; } else if ( ulRemoteAddress !=0 && usRemotePort == 0 ) { //
// Scenario #1b
//
// Inbound connection from known machine, but unknown port
//
MYTRACE("SCENARIO:eALG_INBOUND #1b"); nFlags = NatRedirectFlagReceiveOnly|NatRedirectFlagRestrictSource;
ulSourceAddress = ulRemoteAddress; usSourcePort = 0;
ulDestinationAddress = ulPublicAddress; usDestinationPort = usPublicPort;
ulNewSourceAddress = 0; usNewSourcePort = 0;
ulNewDestinationAddress = ulListenAddress; usNewDestinationPort = usListenPort;
ulRestrictAdapterIndex = 0;
} else if ( ulRemoteAddress !=0 && usRemotePort != 0 ) { //
// Scenario #1c
//
// Inbound connection from known machine and port
//
MYTRACE("SCENARIO:eALG_INBOUND #1c");
nFlags = NatRedirectFlagReceiveOnly;
ulSourceAddress = ulRemoteAddress; usSourcePort = usRemotePort;
ulDestinationAddress = ulPublicAddress; usDestinationPort = usPublicPort;
ulNewSourceAddress = ulRemoteAddress; usNewSourcePort = usRemotePort;
ulNewDestinationAddress = ulListenAddress; usNewDestinationPort = usListenPort;
ulRestrictAdapterIndex = 0;
} else return E_INVALIDARG; } else if ( eALG_OUTBOUND == eDirection ) { //
// These cases can also be handled by a single ul
//
if ( ulRemoteAddress !=0 && usRemotePort != 0 && ulPrivateAddress == 0 && usPrivatePort == 0 ) { //
// Scenario #2a
//
// Outbound connection to known machine/port, from any private machine
//
MYTRACE("SCENARIO:eALG_OUTBOUND #2a");
nFlags = 0;
ulSourceAddress = 0; usSourcePort = 0;
ulDestinationAddress = ulRemoteAddress; usDestinationPort = usRemotePort;
ulNewSourceAddress = 0; usNewSourcePort = 0;
ulNewDestinationAddress = ulListenAddress; usNewDestinationPort = usListenPort;
ulRestrictAdapterIndex = 0; } else if ( ulRemoteAddress !=0 && usRemotePort != 0 && ulPrivateAddress != 0 && usPrivatePort == 0 ) { //
// Scenario #2b
//
// Outbound connection to known machine/port, from a specific private machine
//
MYTRACE("SCENARIO:eALG_OUTBOUND #2b"); nFlags = NatRedirectFlagRestrictSource;
ulSourceAddress = ulPrivateAddress; usSourcePort = 0;
ulDestinationAddress = ulRemoteAddress; usDestinationPort = usRemotePort;
ulNewSourceAddress = 0; usNewSourcePort = 0;
ulNewDestinationAddress = ulListenAddress; usNewDestinationPort = usListenPort;
ulRestrictAdapterIndex = 0; } else if ( ulRemoteAddress !=0 && usRemotePort != 0 && ulPrivateAddress != 0 && usPrivatePort != 0 ) { //
// Scenario #2c
//
// Outbound connection to known machine/port, from a specific port on a specific private machine
//
MYTRACE("SCENARIO:eALG_OUTBOUND #2c"); nFlags = 0;
ulSourceAddress = ulPrivateAddress; usSourcePort = usPrivatePort;
ulDestinationAddress = ulRemoteAddress; usDestinationPort = usRemotePort;
ulNewSourceAddress = ulPrivateAddress; usNewSourcePort = usPrivatePort;
ulNewDestinationAddress = ulListenAddress; usNewDestinationPort = usListenPort;
ulRestrictAdapterIndex = 0; } else if ( ulPrivateAddress != 0 && usPrivatePort != 0 && ulRemoteAddress == 0 && usRemotePort == 0 ) { //
// Scenario #2d
//
// Outbound connection from a specific port on a specific private machine, to an unknown machine
//
MYTRACE("SCENARIO:eALG_OUTBOUND #2d"); nFlags = NatRedirectFlagSourceRedirect;
ulSourceAddress = ulPrivateAddress; usSourcePort = usPrivatePort;
ulDestinationAddress = 0; usDestinationPort = 0;
ulNewSourceAddress = ulPrivateAddress; usNewSourcePort = usPrivatePort;
ulNewDestinationAddress = ulListenAddress; usNewDestinationPort = usListenPort;
ulRestrictAdapterIndex = 0; } else if ( ulPrivateAddress != 0 && usPrivatePort != 0 && ulRemoteAddress != 0 && usRemotePort == 0 ) { //
// Scenario #2e
//
// Outbound connection from a specific port on a specific private machine, to a known machine
//
MYTRACE("SCENARIO:eALG_OUTBOUND #2e"); nFlags = 0;
ulSourceAddress = ulPrivateAddress; usSourcePort = usPrivatePort;
ulDestinationAddress = ulRemoteAddress; usDestinationPort = 0;
ulNewSourceAddress = ulPrivateAddress; usNewSourcePort = usPrivatePort;
ulNewDestinationAddress = ulListenAddress; usNewDestinationPort = usListenPort;
ulRestrictAdapterIndex = 0; } else return E_INVALIDARG;
} else { //
//
//
return E_INVALIDARG; }
HRESULT hr; HANDLE_PTR HandleDynamicRedirect=NULL;
if ( fPersistent ) { // Dynamic
hr = g_pAlgController->GetNat()->CreateDynamicRedirect( nFlags, 0, // Adapter Index
(UCHAR)eProtocol, ulDestinationAddress, // ULONG DestinationAddress
usDestinationPort, // USHORT DestinationPort
ulSourceAddress, // ULONG SourceAddress
usSourcePort, // USHORT SourcePort
ulNewDestinationAddress, // ULONG NewDestinationAddress
usNewDestinationPort, // USHORT NewDestinationPort
ulNewSourceAddress, // ULONG NewSourceAddress
usNewSourcePort, // USHORT NewSourcePort
&HandleDynamicRedirect ); } else {
// Normal
hr = g_pAlgController->GetNat()->CreateRedirect( nFlags, (UCHAR)eProtocol,
ulDestinationAddress, // ULONG DestinationAddress
usDestinationPort, // USHORT DestinationPort
ulSourceAddress, // ULONG SourceAddress
usSourcePort, // USHORT SourcePort
ulNewDestinationAddress, // ULONG NewDestinationAddress
usNewDestinationPort, // USHORT NewDestinationPort
ulNewSourceAddress, // ULONG NewSourceAddress
usNewSourcePort, // USHORT NewSourcePort
ulRestrictAdapterIndex, // ULONG RestrictAdapterIndex
0, // DWORD_PTR ThisProcessID
NULL, // HANDLE_PTR CreateEvent
NULL // HANDLE_PTR DeleteEvent
); }
if ( FAILED(hr) ) { MYTRACE_ERROR("From g_pAlgController->GetNat()->CreateRedirect", hr); return hr; }
//
// Add new ControlChannel to List
//
CComObject<CSecondaryControlChannel>* pIChannel; hr = CComObject<CSecondaryControlChannel>::CreateInstance(&pIChannel);
if ( SUCCEEDED(hr) ) { pIChannel->AddRef();
pIChannel->m_Properties.eProtocol = eProtocol; pIChannel->m_Properties.ulPrivateAddress = ulPrivateAddress; pIChannel->m_Properties.usPrivatePort = usPrivatePort; pIChannel->m_Properties.ulPublicAddress = ulPublicAddress; pIChannel->m_Properties.usPublicPort = usPublicPort; pIChannel->m_Properties.ulRemoteAddress = ulRemoteAddress; pIChannel->m_Properties.usRemotePort = usRemotePort; pIChannel->m_Properties.ulListenAddress = ulListenAddress; pIChannel->m_Properties.usListenPort = usListenPort; pIChannel->m_Properties.eDirection = eDirection; pIChannel->m_Properties.fPersistent = fPersistent;
//
// Cache calling parameters used to create the redirect we will need them to cancel the redirect
//
pIChannel->m_ulDestinationAddress = ulDestinationAddress; pIChannel->m_usDestinationPort = usDestinationPort;
pIChannel->m_ulSourceAddress = ulSourceAddress; pIChannel->m_usSourcePort = usSourcePort;
pIChannel->m_ulNewDestinationAddress = ulNewDestinationAddress; pIChannel->m_usNewDestinationPort = usNewDestinationPort;
pIChannel->m_ulNewSourceAddress = ulNewSourceAddress; pIChannel->m_usNewSourcePort = usNewSourcePort;
pIChannel->m_HandleDynamicRedirect = HandleDynamicRedirect;
hr = pIChannel->QueryInterface(IID_ISecondaryControlChannel, (void**)ppIControlChannel);
if ( SUCCEEDED(hr) ) { hr = g_pAlgController->m_ControlChannelsSecondary.Add(pIChannel);
if ( FAILED(hr) ) { MYTRACE_ERROR("Adding to list of SecondaryChannel", hr);
(*ppIControlChannel)->Release(); *ppIControlChannel=NULL;
} } else { MYTRACE_ERROR("QueryInterface(IID_ISecondaryControlChannel", hr); }
pIChannel->Release();
} else { MYTRACE_ERROR("From CreateInstance<CSecondaryControlChannel>", hr); }
return hr; }
STDMETHODIMP CApplicationGatewayServices::GetBestSourceAddressForDestinationAddress( IN ULONG ulDestinationAddress, IN BOOL fDemandDial, OUT ULONG* pulBestSrcAddress ) /*++
Routine Description:
We create a temporary UDP socket, connect the socket to the actual client's IP address, extract the IP address to which the socket is implicitly bound by the TCP/IP driver, and discard the socket. This leaves us with the exact IP address that we need to use to contact the client.
Arguments:
ulDestinationAddress, fDemandDial, pulBestSrcAddress
Return Value:
HRESULT - S_OK for success
Environment:
ALG module will call this method to:
--*/
{ MYTRACE_ENTER("CApplicationGatewayServices::GetBestSourceAddressForDestinationAddress");
HRESULT hr = g_pAlgController->GetNat()->GetBestSourceAddressForDestinationAddress( ulDestinationAddress, fDemandDial, pulBestSrcAddress );
MYTRACE("For Destination address of %s", MYTRACE_IP(ulDestinationAddress) ); MYTRACE("the Best source address is %s", MYTRACE_IP(*pulBestSrcAddress) );
return hr;
}
//
//
//
//
//
//
STDMETHODIMP CApplicationGatewayServices::PrepareProxyConnection( IN ALG_PROTOCOL eProtocol,
IN ULONG ulSourceAddress, IN USHORT usSourcePort,
IN ULONG ulDestinationAddress, IN USHORT usDestinationPort,
IN BOOL fNoTimeout, OUT IPendingProxyConnection** ppPendingConnection ) /*++
Routine Description:
If we have a firwewall interface, possibly install a shadow redirect for this connection. The shadow redirect is necessary to prevent this connection from also being redirected to the proxy (setting in motion an infinite loop...)
Arguments:
eProtocol,
ulSourceAddress, usSourcePort,
ulDestinationAddress, usDestinationPort,
fNoTimeout, ppPendingConnection
Return Value:
HRESULT - S_OK for success
Environment:
ALG module will call this method to:
--*/ { MYTRACE_ENTER("CApplicationGatewayServices::PrepareProxyConnection");
MYTRACE("eProtocol %s", eProtocol==1? "TCP" : "UDP"); MYTRACE("Source %s:%d", MYTRACE_IP(ulSourceAddress), ntohs(usSourcePort)); MYTRACE("Destination %s:%d", MYTRACE_IP(ulDestinationAddress), ntohs(usDestinationPort)); MYTRACE("NoTimeout %d", fNoTimeout);
ULONG ulFlags = NatRedirectFlagLoopback;
if ( !ppPendingConnection ) { MYTRACE_ERROR("ppPendingConnection not supplied",0); return E_INVALIDARG; }
if ( fNoTimeout ) { MYTRACE("NoTimeout specified");
if ( eProtocol == eALG_UDP ) { ulFlags |= NatRedirectFlagNoTimeout; } else { MYTRACE("Wrong use of fNoTimeout && eProtocol != eALG_UDP"); return E_INVALIDARG; } }
HRESULT hr = g_pAlgController->GetNat()->CreateRedirect( ulFlags, (UCHAR)eProtocol,
ulDestinationAddress, // ULONG DestinationAddress,
usDestinationPort, // USHORT DestinationPort,
ulSourceAddress, // ULONG SourceAddress,
usSourcePort, // USHORT SourcePort,
ulDestinationAddress, // ULONG NewDestinationAddress
usDestinationPort, // USHORT NewDestinationPort
ulSourceAddress, // ULONG NewSourceAddress,
usSourcePort, // USHORT NewSourcePort,
0, // ULONG RestrictAdapterIndex
0, // DWORD_PTR ThisProcessID
NULL, // HANDLE_PTR CreateEvent
NULL // HANDLE_PTR DeleteEvent
);
if ( SUCCEEDED(hr) ) { CComObject<CPendingProxyConnection>* pIPendingProxyConnection; CComObject<CPendingProxyConnection>::CreateInstance(&pIPendingProxyConnection);
pIPendingProxyConnection->m_eProtocol = eProtocol; pIPendingProxyConnection->m_ulDestinationAddress = ulDestinationAddress; pIPendingProxyConnection->m_usDestinationPort = usDestinationPort;
pIPendingProxyConnection->m_ulSourceAddress = ulSourceAddress; pIPendingProxyConnection->m_usSourcePort = usSourcePort;
pIPendingProxyConnection->m_ulNewSourceAddress = ulSourceAddress; // Since the PendingProxyConenction is also used
pIPendingProxyConnection->m_usNewSourcePort = usSourcePort; // by PrepareSourceModifiedProxyConnection we use the NewSource
// for the Cancel
pIPendingProxyConnection->QueryInterface(ppPendingConnection);
} else { MYTRACE_ERROR(">GetNat()->CreateRedirect failed", hr); }
return hr;
}
STDMETHODIMP CApplicationGatewayServices::PrepareSourceModifiedProxyConnection( IN ALG_PROTOCOL eProtocol, IN ULONG ulSourceAddress, IN USHORT usSrcPort, IN ULONG ulDestinationAddress, IN USHORT usDestinationPort, IN ULONG ulNewSrcAddress, IN USHORT usNewSourcePort, OUT IPendingProxyConnection** ppPendingConnection ) /*++
Routine Description:
Arguments:
eProtocol, ulSourceAddress, usSrcPort, ulDestinationAddress, usDestinationPort, ulNewSrcAddress, usNewSourcePort, ppPendingConnection
Return Value:
HRESULT - S_OK for success
Environment:
ALG module will call this method to:
--*/ { MYTRACE_ENTER("CApplicationGatewayServices::PrepareSourceModifiedProxyConnection"); MYTRACE("Source %s:%d", MYTRACE_IP(ulSourceAddress), ntohs(usSrcPort)); MYTRACE("Destination %s:%d", MYTRACE_IP(ulDestinationAddress), ntohs(usDestinationPort)); MYTRACE("NewSource %s:%d", MYTRACE_IP(ulNewSrcAddress), ntohs(usNewSourcePort));
if ( !ppPendingConnection ) { MYTRACE_ERROR("IPendingProxyConnection** not supplied",0); return E_INVALIDARG; }
HRESULT hr = g_pAlgController->GetNat()->CreateRedirect( NatRedirectFlagLoopback, (UCHAR)eProtocol,
ulDestinationAddress, // ULONG DestinationAddress,
usDestinationPort, // USHORT DestinationPort,
ulSourceAddress, // ULONG SourceAddress,
usSrcPort, // USHORT SourcePort,
ulDestinationAddress, // ULONG NewDestinationAddress
usDestinationPort, // USHORT NewDestinationPort
ulNewSrcAddress, // ULONG NewSourceAddress,
usNewSourcePort, // USHORT NewSourcePort,
0, // ULONG RestrictAdapterIndex
0, // DWORD_PTR ThisProcessID
NULL, // HANDLE_PTR CreateEvent
NULL // HANDLE_PTR DeleteEvent
);
if ( SUCCEEDED(hr) ) { CComObject<CPendingProxyConnection>* pIPendingProxyConnection; CComObject<CPendingProxyConnection>::CreateInstance(&pIPendingProxyConnection);
pIPendingProxyConnection->m_eProtocol = eProtocol; pIPendingProxyConnection->m_ulDestinationAddress = ulDestinationAddress; pIPendingProxyConnection->m_usDestinationPort = usDestinationPort;
pIPendingProxyConnection->m_ulSourceAddress = ulSourceAddress; pIPendingProxyConnection->m_usSourcePort = usSrcPort;
pIPendingProxyConnection->m_ulNewSourceAddress = ulNewSrcAddress; pIPendingProxyConnection->m_usNewSourcePort = usNewSourcePort;
hr = pIPendingProxyConnection->QueryInterface(ppPendingConnection);
}
return hr; }
HRESULT GetRedirectParameters( IN ALG_DIRECTION eDirection, IN ALG_PROTOCOL eProtocol,
IN ULONG ulPrivateAddress, IN USHORT usPrivatePort, IN ULONG ulPublicAddress, IN USHORT usPublicPort, IN ULONG ulRemoteAddress, IN USHORT usRemotePort,
OUT ULONG& ulFlags, OUT ULONG& ulSourceAddress, OUT USHORT& usSourcePort, OUT ULONG& ulDestinationAddress, OUT USHORT& usDestinationPort, OUT ULONG& ulNewSourceAddress, OUT USHORT& usNewSourcePort, OUT ULONG& ulNewDestinationAddress, OUT USHORT& usNewDestinationPort,
OUT ULONG& ulRestrictAdapterIndex ) /*++
Routine Description:
The logic in these scenario are use by CreateDataChannel and CreatePersitenDataChannel
Arguments:
eProtocol, ulSourceAddress, usSrcPort, ulDestinationAddress, usDestinationPort, ulNewSrcAddress, usNewSourcePort, ppPendingConnection
Return Value:
HRESULT - S_OK for success
Environment:
ALG module will call this method to:
--*/ {
if ( eALG_INBOUND == eDirection ) { if ( ulRemoteAddress == 0 && usRemotePort == 0 ) { // 1a
ulFlags = NatRedirectFlagReceiveOnly;
ulSourceAddress = 0; usSourcePort = 0; ulDestinationAddress = ulPublicAddress; usDestinationPort = usPublicPort; ulNewSourceAddress = 0; usNewSourcePort = 0; ulNewDestinationAddress = ulPrivateAddress; usNewDestinationPort = usPrivatePort; ulRestrictAdapterIndex = 0;
} else if ( ulRemoteAddress != 0 && usRemotePort == 0 ) { // 1b
ulFlags = NatRedirectFlagReceiveOnly|NatRedirectFlagRestrictSource;
ulSourceAddress = ulRemoteAddress; usSourcePort = 0; ulDestinationAddress = ulPublicAddress; usDestinationPort = usPublicPort; ulNewSourceAddress = 0; usNewSourcePort = 0; ulNewDestinationAddress = ulPrivateAddress; usNewDestinationPort = usPrivatePort; ulRestrictAdapterIndex = 0; } else if ( ulRemoteAddress != 0 && usRemotePort != 0 ) { // 1c.
ulFlags = NatRedirectFlagReceiveOnly;
ulSourceAddress = ulRemoteAddress; usSourcePort = usRemotePort; ulDestinationAddress = ulPublicAddress; usDestinationPort = usPublicPort; ulNewSourceAddress = ulRemoteAddress; usNewSourcePort = usRemotePort; ulNewDestinationAddress = ulPrivateAddress; usNewDestinationPort = usPrivatePort;
ulRestrictAdapterIndex = 0; } else return E_INVALIDARG; } else if ( eALG_OUTBOUND == eDirection ) { if ( ulPrivateAddress == 0 && usPrivatePort == 0 ) { // 2a.
ulFlags = 0; ulSourceAddress = 0; usSourcePort = 0; ulDestinationAddress = ulRemoteAddress; usDestinationPort = usRemotePort; ulNewSourceAddress = ulPublicAddress; usNewSourcePort = usPublicPort; ulNewDestinationAddress = ulRemoteAddress; usNewDestinationPort = usRemotePort;
ulRestrictAdapterIndex = 0; } else if ( ulPrivateAddress != 0 && usPrivatePort == 0 ) { // 2b.
ulFlags = NatRedirectFlagRestrictSource; ulSourceAddress = ulPrivateAddress; usSourcePort = 0; ulDestinationAddress = ulRemoteAddress; usDestinationPort = usRemotePort; ulNewSourceAddress = ulPublicAddress; usNewSourcePort = usPublicPort; ulNewDestinationAddress = ulRemoteAddress; usNewDestinationPort = usRemotePort;
ulRestrictAdapterIndex = 0; } else if ( ulPrivateAddress != 0 && usPrivatePort != 0 ) { // 2c.
ulFlags = 0; ulSourceAddress = ulPrivateAddress; usSourcePort = usPrivatePort; ulDestinationAddress = ulRemoteAddress; usDestinationPort = usRemotePort; ulNewSourceAddress = ulPublicAddress; usNewSourcePort = usPublicPort; ulNewDestinationAddress = ulRemoteAddress; usNewDestinationPort = usRemotePort; ulRestrictAdapterIndex = 0; } else return E_INVALIDARG; } else if ( (eALG_INBOUND | eALG_OUTBOUND) == eDirection ) { ulFlags = 0; ulSourceAddress = ulRemoteAddress; usSourcePort = usRemotePort; ulDestinationAddress = ulPublicAddress; usDestinationPort = usPublicPort; ulNewSourceAddress = ulRemoteAddress; usNewSourcePort = usRemotePort; ulNewDestinationAddress = ulPrivateAddress; usNewDestinationPort = usPrivatePort;
ulRestrictAdapterIndex = 0; } else return E_INVALIDARG;
return S_OK; }
STDMETHODIMP CApplicationGatewayServices::CreateDataChannel( IN ALG_PROTOCOL eProtocol, IN ULONG ulPrivateAddress, IN USHORT usPrivatePort, IN ULONG ulPublicAddress, IN USHORT usPublicPort, IN ULONG ulRemoteAddress, IN USHORT usRemotePort, IN ALG_DIRECTION eDirection, IN ALG_NOTIFICATION eDesiredNotification, IN BOOL fNoTimeout, OUT IDataChannel** ppDataChannel ) /*++
Routine Description:
Arguments:
eProtocol, ulPrivateAddress, usPrivatePort, ulPublicAddress, usPublicPort, ulRemoteAddress, usRemotePort, eDirection, eDesiredNotification, fNoTimeout, ppDataChannel
Return Value:
HRESULT - S_OK for success
Environment:
ALG module will call this method to:
--*/ { MYTRACE_ENTER("CApplicationGatewayServices::CreateDataChannel");
if ( !ppDataChannel ) { MYTRACE_ERROR("IDataChannel** not supplied",0); return E_INVALIDARG; }
MYTRACE("eProtocol %d", eProtocol); MYTRACE("ulPrivateAddress %s:%d", MYTRACE_IP(ulPrivateAddress), ntohs(usPrivatePort)); MYTRACE("ulPublicAddress %s:%d", MYTRACE_IP(ulPublicAddress), ntohs(usPublicPort)); MYTRACE("ulRemoteAddress %s:%d", MYTRACE_IP(ulRemoteAddress), ntohs(usRemotePort)); MYTRACE("eDirection %d", eDirection); MYTRACE("eDesiredNotification %d", eDesiredNotification); MYTRACE("fNoTimeout %d", fNoTimeout);
ULONG ulFlags=0;
ULONG ulSourceAddress=0; USHORT usSourcePort=0; ULONG ulDestinationAddress=0; USHORT usDestinationPort=0; ULONG ulNewSourceAddress=0; USHORT usNewSourcePort=0; ULONG ulNewDestinationAddress=0; USHORT usNewDestinationPort=0;
ULONG ulRestrictAdapterIndex=0;
HRESULT hr = GetRedirectParameters( // IN Params
eDirection, eProtocol, ulPrivateAddress, usPrivatePort, ulPublicAddress, usPublicPort, ulRemoteAddress, usRemotePort,
// OUT Params
ulFlags, ulSourceAddress, usSourcePort, ulDestinationAddress, usDestinationPort, ulNewSourceAddress, usNewSourcePort, ulNewDestinationAddress, usNewDestinationPort, ulRestrictAdapterIndex );
if ( FAILED(hr) ) { MYTRACE_ERROR("Invalid parameters pass", hr); return E_INVALIDARG; }
//
// Check for timeout
//
if ( fNoTimeout && eALG_UDP == eProtocol) ulFlags |= NatRedirectFlagNoTimeout;
HANDLE_PTR hCreateEvent = NULL; HANDLE_PTR hDeleteEvent = NULL;
//
// We need to events Create and Delete
//
if ( eALG_SESSION_CREATION & eDesiredNotification ) { hCreateEvent = (HANDLE_PTR)CreateEvent(NULL, FALSE, FALSE, NULL); if ( !hCreateEvent ) { MYTRACE_ERROR("Could not create hCreateEvent", GetLastError()); return HRESULT_FROM_WIN32(GetLastError()); } } else { MYTRACE("NO eALG_SESSION_CREATION notification requested"); }
if ( eALG_SESSION_DELETION & eDesiredNotification ) { hDeleteEvent = (HANDLE_PTR)CreateEvent(NULL, FALSE, FALSE, NULL); if ( !hDeleteEvent ) { MYTRACE_ERROR("Could not create hDeleteEvent", GetLastError()); if ( hCreateEvent ) CloseHandle((HANDLE)hCreateEvent); return HRESULT_FROM_WIN32(GetLastError()); } } else { MYTRACE("NO eALG_SESSION_DELETION notification requested"); }
//
// Create a IDataChannel and cache arg to be able CancelRedirect
//
hr = g_pAlgController->GetNat()->CreateRedirect( ulFlags|NatRedirectFlagLoopback, (UCHAR)eProtocol,
ulDestinationAddress, usDestinationPort,
ulSourceAddress, usSourcePort,
ulNewDestinationAddress, usNewDestinationPort,
ulNewSourceAddress, usNewSourcePort,
ulRestrictAdapterIndex,
GetCurrentProcessId(), hCreateEvent, hDeleteEvent );
if ( FAILED(hr) ) { MYTRACE_ERROR("GetNAT()->CreateRedirect",hr); if ( hCreateEvent ) CloseHandle((HANDLE)hCreateEvent);
if ( hDeleteEvent ) CloseHandle((HANDLE)hDeleteEvent); return hr; }
CComObject<CDataChannel>* pIDataChannel; hr = CComObject<CDataChannel>::CreateInstance(&pIDataChannel);
if ( SUCCEEDED(hr) ) { //
// Save these settings so to be able to return them to the user
// if the IDataChannel->GetProperties is called
//
pIDataChannel->m_Properties.eProtocol = eProtocol; pIDataChannel->m_Properties.ulPrivateAddress = ulPrivateAddress; pIDataChannel->m_Properties.usPrivatePort = usPrivatePort; pIDataChannel->m_Properties.ulPublicAddress = ulPublicAddress; pIDataChannel->m_Properties.usPublicPort = usPublicPort; pIDataChannel->m_Properties.ulRemoteAddress = ulRemoteAddress; pIDataChannel->m_Properties.usRemotePort = usRemotePort; pIDataChannel->m_Properties.eDirection = eDirection; pIDataChannel->m_Properties.eDesiredNotification = eDesiredNotification;
//
// Cache these arguments in order to implement IDataChannel->Cancel
//
pIDataChannel->m_ulSourceAddress = ulSourceAddress; pIDataChannel->m_usSourcePort = usSourcePort; pIDataChannel->m_ulDestinationAddress = ulDestinationAddress; pIDataChannel->m_usDestinationPort = usDestinationPort; pIDataChannel->m_ulNewSourceAddress = ulNewSourceAddress; pIDataChannel->m_usNewSourcePort = usNewSourcePort; pIDataChannel->m_ulNewDestinationAddress = ulNewDestinationAddress; pIDataChannel->m_usNewDestinationPort = usNewDestinationPort; pIDataChannel->m_ulRestrictAdapterIndex = ulRestrictAdapterIndex;
pIDataChannel->m_hCreateEvent = (HANDLE)hCreateEvent; pIDataChannel->m_hDeleteEvent = (HANDLE)hDeleteEvent;
hr = pIDataChannel->QueryInterface(ppDataChannel);
if ( FAILED(hr) ) { MYTRACE_ERROR("QI on IDataChannel", hr); } }
return hr; }
STDMETHODIMP CApplicationGatewayServices::CreatePersistentDataChannel( IN ALG_PROTOCOL eProtocol, IN ULONG ulPrivateAddress, IN USHORT usPrivatePort, IN ULONG ulPublicAddress, IN USHORT usPublicPort, IN ULONG ulRemoteAddress, IN USHORT usRemotePort, IN ALG_DIRECTION eDirection, OUT IPersistentDataChannel** ppIPersistentDataChannel ) /*++
Routine Description:
Arguments:
eProtocol, ulPrivateAddress, usPrivatePort, ulPublicAddress, usPublicPort, ulRemoteAddress, usRemotePort, eDirection, ppIPersistentDataChannel
Return Value:
HRESULT - S_OK for success
Environment:
ALG module will call this method to:
--*/ { MYTRACE_ENTER("CApplicationGatewayServices::CreatePersistentDataChannel");
if ( !ppIPersistentDataChannel ) { MYTRACE_ERROR("IPersistentDataChannel** not supplied",0); return E_INVALIDARG; }
ULONG ulFlags=0;
ULONG ulSourceAddress=0; USHORT usSourcePort=0; ULONG ulDestinationAddress=0; USHORT usDestinationPort=0; ULONG ulNewSourceAddress=0; USHORT usNewSourcePort=0; ULONG ulNewDestinationAddress=0; USHORT usNewDestinationPort=0;
ULONG ulRestrictAdapterIndex=0;
HRESULT hr = GetRedirectParameters( // IN Params
eDirection, eProtocol, ulPrivateAddress, usPrivatePort, ulPublicAddress, usPublicPort, ulRemoteAddress, usRemotePort,
// OUT Params
ulFlags, ulSourceAddress, usSourcePort, ulDestinationAddress, usDestinationPort, ulNewSourceAddress, usNewSourcePort, ulNewDestinationAddress, usNewDestinationPort, ulRestrictAdapterIndex );
if ( FAILED(hr) ) return hr;
//
// Create a IDataChannel and cache arg so to CancelRedirect
//
HANDLE_PTR HandleDynamicRedirect=NULL;
// Dynamic
hr = g_pAlgController->GetNat()->CreateDynamicRedirect( ulFlags, 0, // Adapter Index
(UCHAR)eProtocol,
ulDestinationAddress, // ULONG DestinationAddress
usDestinationPort, // USHORT DestinationPort
ulSourceAddress, // ULONG SourceAddress
usSourcePort, // USHORT SourcePort
ulNewDestinationAddress, // ULONG NewDestinationAddress
usNewDestinationPort, // USHORT NewDestinationPort
ulNewSourceAddress, // ULONG NewSourceAddress
usNewSourcePort, // USHORT NewSourcePort
&HandleDynamicRedirect );
if ( SUCCEEDED(hr) ) { CComObject<CPersistentDataChannel>* pIPersistentDataChannel; CComObject<CPersistentDataChannel>::CreateInstance(&pIPersistentDataChannel);
//
// Save these settings so to be able to return them to the user
// if the IDataChannel->GetProperties is called
//
pIPersistentDataChannel->m_Properties.eProtocol = eProtocol; pIPersistentDataChannel->m_Properties.ulPrivateAddress = ulPrivateAddress; pIPersistentDataChannel->m_Properties.usPrivatePort = usPrivatePort; pIPersistentDataChannel->m_Properties.ulPublicAddress = ulPublicAddress; pIPersistentDataChannel->m_Properties.usPublicPort = usPublicPort; pIPersistentDataChannel->m_Properties.ulRemoteAddress = ulRemoteAddress; pIPersistentDataChannel->m_Properties.usRemotePort = usRemotePort; pIPersistentDataChannel->m_Properties.eDirection = eDirection;
//
// Cache these hanlde in order to implement IPersistentDataChannel->Cancel
//
pIPersistentDataChannel->m_HandleDynamicRedirect = HandleDynamicRedirect;
hr = pIPersistentDataChannel->QueryInterface(ppIPersistentDataChannel);
}
return hr;
}
STDMETHODIMP CApplicationGatewayServices::ReservePort( IN USHORT usPortCount, // must be 1 or more and not more then ALG_MAXIMUM_PORT_RANGE_SIZE
OUT USHORT* pusReservedPort // Received the base reserved port *pusReservedPort+usPortCount-1 are reserved for the caller
) /*++
Routine Description:
Reserve a number of port (usPortCount) port(s)
Arguments:
usPortCount - greated then 1 and not more then ALG_MAXIMUM_PORT_RANGE_SIZE pusReservedPort - Received the base reserved port *pusReservedPort+usPortCount-1 are reserved for the caller
Return Value:
HRESULT - S_OK for success
Environment:
ALG module will call this method to:
--*/ { MYTRACE_ENTER("CApplicationGatewayServices::ReservePort")
if ( usPortCount < 0 || usPortCount > ALG_MAXIMUM_PORT_RANGE_SIZE ) return E_INVALIDARG;
_ASSERT(pusReservedPort);
HRESULT hr = g_pAlgController->GetNat()->ReservePort(usPortCount, pusReservedPort);
if ( FAILED(hr) ) { MYTRACE("Reserving Ports", hr); } else { MYTRACE("%d port stating at %d", usPortCount, ntohs(*pusReservedPort) ); } return hr; }
//
//
//
VOID CALLBACK CApplicationGatewayServices::TimerCallbackReleasePort( PVOID pParameter, // thread data
BOOLEAN TimerOrWaitFired // reason
) { MYTRACE_ENTER("CApplicationGatewayServices::TimerCallbackReleasePort");
CTimerQueueReleasePort* pTimerQueueReleasePort = (CTimerQueueReleasePort*)pParameter;
if ( pTimerQueueReleasePort ) { MYTRACE("Releasing port Base %d count %d", ntohs(pTimerQueueReleasePort->m_usPortBase), pTimerQueueReleasePort->m_usPortCount); g_pAlgController->GetNat()->ReleasePort(pTimerQueueReleasePort->m_usPortBase, pTimerQueueReleasePort->m_usPortCount);
delete pTimerQueueReleasePort; } }
STDMETHODIMP CApplicationGatewayServices::ReleaseReservedPort( IN USHORT usPortBase, // Port to release
IN USHORT usPortCount // Number of port in the range starting at usPortBase
) /*++
Routine Description:
Release the given port(s)
Arguments:
pusReservedPort - The starting base port number usPortCount - greated then 1 and not more then ALG_MAXIMUM_PORT_RANGE_SIZE
Return Value:
HRESULT - S_OK for success - E_FAIL could no release the port Environment:
ALG module will call this method to:
--*/ { MYTRACE_ENTER("CApplicationGatewayServices::ReleaseReservedPort")
MYTRACE("BasePort %d, Count %d", ntohs(usPortBase), usPortCount);
//
// By creating a CTimerQueueReleasePort it will trigger a ReleaseReservePort after 4 minutes
// we need this delay to insure that a ReserverPort does not get the same port that just go Released
// because the connnection would not work (This is a TCP/IP TIME_WAIT restriction)
//
CTimerQueueReleasePort* pTimerReleasePort = new CTimerQueueReleasePort(m_hTimerQueue, usPortBase, usPortCount); if ( pTimerReleasePort ) return S_OK; else return E_FAIL; }
STDMETHODIMP CApplicationGatewayServices::EnumerateAdapters( OUT IEnumAdapterInfo** ppEnumAdapterInfo ) /*++
Routine Description:
Create a list of IEnumAdapterInfo the AddRef will be done soe caller needs to call Release
Arguments:
ppEnumAdapterInfo - receive the enumarator interface of the IAdapterInfo
Return Value:
HRESULT - S_OK for success
Environment:
ALG module will call this method to:
--*/ { MYTRACE_ENTER("CApplicationGatewayServices::EnumerateAdapters")
_ASSERT(ppEnumAdapterInfo==NULL);
HRESULT hr = S_OK;
CreateSTLEnumerator<ComEnumOnSTL_ForAdapters>( (IUnknown**)ppEnumAdapterInfo, NULL, g_pAlgController->m_CollectionOfAdapters.m_ListOfAdapters );
return hr; }
STDMETHODIMP CApplicationGatewayServices::StartAdapterNotifications( IN IAdapterNotificationSink* pSink, OUT DWORD* pdwCookie ) /*++
Routine Description:
The ALG module calls this method to Register a notification sync with the ALG.exe
Arguments:
pSink - Interface to call back with future notification pdwCookie - this cookie will be used to cancel this sink
Return Value:
HRESULT - S_OK for success
Environment:
ALG module will call this method to:
--*/ { MYTRACE_ENTER("CApplicationGatewayServices::StartAdapterNotifications")
if ( pSink==NULL || pdwCookie==NULL ) { MYTRACE("Invalid argument pass"); return E_INVALIDARG; }
return g_pAlgController->m_AdapterNotificationSinks.Add(pSink, pdwCookie); }
STDMETHODIMP CApplicationGatewayServices::StopAdapterNotifications( IN DWORD dwCookieToRemove ) /*++
Routine Description:
Cancel a previously registered sink
Arguments:
pdwCookieToRemove - Pass the cookie that was return from the StartAdapterNotifications
Return Value:
HRESULT - S_OK for success
Environment:
ALG module will call this method to:
--*/ { MYTRACE_ENTER("CApplicationGatewayServices::StopAdapterNotifications")
return g_pAlgController->m_AdapterNotificationSinks.Remove(dwCookieToRemove); }
|