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.
517 lines
14 KiB
517 lines
14 KiB
/*++
|
|
|
|
Copyright (c) 2001, Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
csaupdate.cpp
|
|
|
|
Abstract:
|
|
|
|
Implementation of CSharedAccessUpdate -- notification sink for
|
|
configuration changes.
|
|
|
|
Author:
|
|
|
|
Jonathan Burstein (jonburs) 20 April 2001
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
|
|
#include "precomp.h"
|
|
#pragma hdrstop
|
|
|
|
#include "beacon.h"
|
|
|
|
//
|
|
// Define a macro version of ntohs which can be applied to constants,
|
|
// and which can thus be computed at compile time.
|
|
//
|
|
|
|
#define NTOHS(p) ((((p) & 0xFF00) >> 8) | (((UCHAR)(p) << 8)))
|
|
|
|
|
|
//
|
|
// H.323/LDAP proxy ports
|
|
//
|
|
|
|
#define H323_Q931_PORT NTOHS(1720)
|
|
#define H323_LDAP_PORT NTOHS(389)
|
|
#define H323_LDAP_ALT_PORT NTOHS(1002)
|
|
|
|
#define INADDR_LOOPBACK_NO 0x0100007f // 127.0.0.1 in network order
|
|
|
|
//
|
|
// Interface methods
|
|
//
|
|
|
|
STDMETHODIMP
|
|
CSharedAccessUpdate::ConnectionPortMappingChanged(
|
|
GUID *pConnectionGuid,
|
|
GUID *pPortMappingGuid,
|
|
BOOLEAN fProtocolChanged
|
|
)
|
|
{
|
|
BOOLEAN fEnabled;
|
|
BOOLEAN fRebuildDhcpList = TRUE;
|
|
HRESULT hr = S_OK;
|
|
IHNetPortMappingBinding *pBinding;
|
|
PNAT_CONNECTION_ENTRY pConnection;
|
|
PNAT_PORT_MAPPING_ENTRY pPortMapping;
|
|
IHNetPortMappingProtocol *pProtocol;
|
|
ULONG ulError;
|
|
USHORT usNewPort = 0;
|
|
UCHAR ucNewProtocol = 0;
|
|
USHORT usOldPort = 0;
|
|
UCHAR ucOldProtocol = 0;
|
|
|
|
PROFILE("ConnectionPortMappingChanged");
|
|
|
|
EnterCriticalSection(&NatInterfaceLock);
|
|
|
|
do
|
|
{
|
|
pConnection = NatFindConnectionEntry(pConnectionGuid);
|
|
if (NULL == pConnection) { break; }
|
|
|
|
//
|
|
// If the connection is not yet bound then there's nothing
|
|
// that we need to do here.
|
|
//
|
|
|
|
if (!NAT_INTERFACE_BOUND(&pConnection->Interface)) { break; }
|
|
|
|
//
|
|
// Locate the old port mapping entry. This entry won't exist if
|
|
// this port mapping wasn't previously enabled.
|
|
//
|
|
|
|
pPortMapping = NatFindPortMappingEntry(pConnection, pPortMappingGuid);
|
|
|
|
if (NULL != pPortMapping)
|
|
{
|
|
//
|
|
// Remove this entry from the connection list and
|
|
// delete the old ticket / UDP broadcast entry.
|
|
//
|
|
|
|
RemoveEntryList(&pPortMapping->Link);
|
|
|
|
if (pPortMapping->fUdpBroadcastMapping)
|
|
{
|
|
if (0 != pPortMapping->pvBroadcastCookie)
|
|
{
|
|
ASSERT(NULL != NhpUdpBroadcastMapper);
|
|
hr = NhpUdpBroadcastMapper->CancelUdpBroadcastMapping(
|
|
pPortMapping->pvBroadcastCookie
|
|
);
|
|
|
|
pPortMapping->pvBroadcastCookie = 0;
|
|
}
|
|
|
|
pConnection->UdpBroadcastPortMappingCount -= 1;
|
|
}
|
|
else
|
|
{
|
|
ulError =
|
|
NatDeleteTicket(
|
|
pConnection->AdapterIndex,
|
|
pPortMapping->ucProtocol,
|
|
pPortMapping->usPublicPort,
|
|
IP_NAT_ADDRESS_UNSPECIFIED,
|
|
pPortMapping->usPrivatePort,
|
|
pPortMapping->ulPrivateAddress
|
|
);
|
|
|
|
pConnection->PortMappingCount -= 1;
|
|
}
|
|
|
|
//
|
|
// Store the old protocol / port information so that
|
|
// we can notify H.323 (if necessary) and the ALG manager.
|
|
//
|
|
|
|
ucOldProtocol = pPortMapping->ucProtocol;
|
|
usOldPort = pPortMapping->usPublicPort;
|
|
|
|
//
|
|
// Check to see if this mapping is still enabled. (We ignore
|
|
// errors from above.)
|
|
//
|
|
|
|
hr = pPortMapping->pBinding->GetEnabled(&fEnabled);
|
|
if (FAILED(hr) || !fEnabled)
|
|
{
|
|
//
|
|
// We'll need to rebuild the DHCP reservation
|
|
// list only if this was a named-based mapping.
|
|
//
|
|
|
|
fRebuildDhcpList = pPortMapping->fNameActive;
|
|
NatFreePortMappingEntry(pPortMapping);
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Allocate a new port mapping entry
|
|
//
|
|
|
|
pPortMapping =
|
|
reinterpret_cast<PNAT_PORT_MAPPING_ENTRY>(
|
|
NH_ALLOCATE(sizeof(*pPortMapping))
|
|
);
|
|
|
|
if (NULL == pPortMapping)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
break;
|
|
}
|
|
|
|
ZeroMemory(pPortMapping, sizeof(*pPortMapping));
|
|
pPortMapping->pProtocolGuid =
|
|
reinterpret_cast<GUID*>(
|
|
CoTaskMemAlloc(sizeof(GUID))
|
|
);
|
|
|
|
if (NULL != pPortMapping->pProtocolGuid)
|
|
{
|
|
CopyMemory(
|
|
pPortMapping->pProtocolGuid,
|
|
pPortMappingGuid,
|
|
sizeof(GUID));
|
|
}
|
|
else
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Load the protocol and binding
|
|
//
|
|
|
|
IHNetCfgMgr *pCfgMgr;
|
|
IHNetProtocolSettings *pProtocolSettings;
|
|
|
|
hr = NhGetHNetCfgMgr(&pCfgMgr);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = pCfgMgr->QueryInterface(
|
|
IID_PPV_ARG(IHNetProtocolSettings, &pProtocolSettings)
|
|
);
|
|
pCfgMgr->Release();
|
|
}
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = pProtocolSettings->FindPortMappingProtocol(
|
|
pPortMappingGuid,
|
|
&pPortMapping->pProtocol
|
|
);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = pConnection->pHNetConnection->GetBindingForPortMappingProtocol(
|
|
pPortMapping->pProtocol,
|
|
&pPortMapping->pBinding
|
|
);
|
|
}
|
|
|
|
pProtocolSettings->Release();
|
|
}
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
//
|
|
// Check if this protocol is enabled
|
|
//
|
|
|
|
hr = pPortMapping->pBinding->GetEnabled(&fEnabled);
|
|
}
|
|
|
|
if (FAILED(hr) || !fEnabled)
|
|
{
|
|
//
|
|
// We don't need to rebuild the DHCP reservations.
|
|
//
|
|
|
|
fRebuildDhcpList = FALSE;
|
|
NatFreePortMappingEntry(pPortMapping);
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Since this is a new entry we always need to load the
|
|
// protocol.
|
|
//
|
|
|
|
fProtocolChanged = TRUE;
|
|
}
|
|
|
|
//
|
|
// Gather the new information
|
|
//
|
|
|
|
if (fProtocolChanged)
|
|
{
|
|
//
|
|
// Need to reload the protocol information
|
|
//
|
|
|
|
hr = pPortMapping->pProtocol->GetIPProtocol(&pPortMapping->ucProtocol);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = pPortMapping->pProtocol->GetPort(&pPortMapping->usPublicPort);
|
|
}
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
NatFreePortMappingEntry(pPortMapping);
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Load the binding information
|
|
//
|
|
|
|
hr = pPortMapping->pBinding->GetTargetPort(&pPortMapping->usPrivatePort);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
BOOLEAN fOldNameActive = pPortMapping->fNameActive;
|
|
hr = pPortMapping->pBinding->GetCurrentMethod(&pPortMapping->fNameActive);
|
|
|
|
if (!fOldNameActive && !pPortMapping->fNameActive)
|
|
{
|
|
fRebuildDhcpList = FALSE;
|
|
}
|
|
}
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = NatpGetTargetAddressForPortMappingEntry(
|
|
pConnection->HNetProperties.fIcsPublic,
|
|
pPortMapping->fNameActive,
|
|
pConnection->pBindingInfo->Address[0].Address,
|
|
pPortMapping->pBinding,
|
|
&pPortMapping->ulPrivateAddress
|
|
);
|
|
}
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
NatFreePortMappingEntry(pPortMapping);
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Create the ticket / UDP broadcast
|
|
//
|
|
|
|
if (NAT_PROTOCOL_UDP == pPortMapping->ucProtocol
|
|
&& 0xffffffff == pPortMapping->ulPrivateAddress)
|
|
{
|
|
DWORD dwAddress;
|
|
DWORD dwMask;
|
|
DWORD dwBroadcastAddress;
|
|
|
|
if (NhQueryScopeInformation(&dwAddress, &dwMask))
|
|
{
|
|
dwBroadcastAddress = (dwAddress & dwMask) | ~dwMask;
|
|
pPortMapping->fUdpBroadcastMapping = TRUE;
|
|
|
|
hr = NhpUdpBroadcastMapper->CreateUdpBroadcastMapping(
|
|
pPortMapping->usPublicPort,
|
|
pConnection->AdapterIndex,
|
|
dwBroadcastAddress,
|
|
&pPortMapping->pvBroadcastCookie
|
|
);
|
|
}
|
|
else
|
|
{
|
|
hr = E_FAIL;
|
|
}
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
InsertTailList(&pConnection->PortMappingList, &pPortMapping->Link);
|
|
pConnection->UdpBroadcastPortMappingCount += 1;
|
|
}
|
|
else
|
|
{
|
|
NatFreePortMappingEntry(pPortMapping);
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ulError =
|
|
NatCreateTicket(
|
|
pConnection->AdapterIndex,
|
|
pPortMapping->ucProtocol,
|
|
pPortMapping->usPublicPort,
|
|
IP_NAT_ADDRESS_UNSPECIFIED,
|
|
pPortMapping->usPrivatePort,
|
|
pPortMapping->ulPrivateAddress
|
|
);
|
|
|
|
if (NO_ERROR == ulError)
|
|
{
|
|
InsertTailList(&pConnection->PortMappingList, &pPortMapping->Link);
|
|
pConnection->PortMappingCount += 1;
|
|
}
|
|
else
|
|
{
|
|
hr = HRESULT_FROM_WIN32(ulError);
|
|
NhTrace(
|
|
TRACE_FLAG_NAT,
|
|
"ConnectionPortMappingModified: NatCreateTicket=%d",
|
|
ulError
|
|
);
|
|
|
|
NatFreePortMappingEntry(pPortMapping);
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Store the old protocol / port information so that
|
|
// we can notify H.323 (if necessary) and the ALG manager.
|
|
//
|
|
|
|
ucNewProtocol = pPortMapping->ucProtocol;
|
|
usNewPort = pPortMapping->usPublicPort;
|
|
}
|
|
while (FALSE);
|
|
|
|
//
|
|
// Determine if we need to notify the H.323 proxy or
|
|
// the ALG manager. We must have found a bound connection
|
|
// above to do this.
|
|
//
|
|
|
|
if (NULL != pConnection && NAT_INTERFACE_BOUND(&pConnection->Interface))
|
|
{
|
|
//
|
|
// If this connection is bound to the H.323 proxy and either
|
|
// the old or new protocol/port combination is applicable
|
|
// remove and add this connection from the that proxy.
|
|
//
|
|
|
|
if (NAT_INTERFACE_ADDED_H323(&pConnection->Interface)
|
|
&& (IsH323Protocol(ucOldProtocol, usOldPort)
|
|
|| IsH323Protocol(ucNewProtocol, usNewPort)))
|
|
{
|
|
H323RmDeleteInterface(pConnection->Interface.Index);
|
|
pConnection->Interface.Flags &= ~NAT_INTERFACE_FLAG_ADDED_H323;
|
|
|
|
ulError =
|
|
H323RmAddInterface(
|
|
NULL,
|
|
pConnection->Interface.Index,
|
|
PERMANENT,
|
|
IF_TYPE_OTHER,
|
|
IF_ACCESS_BROADCAST,
|
|
IF_CONNECTION_DEDICATED,
|
|
NULL,
|
|
IP_NAT_VERSION,
|
|
0,
|
|
0
|
|
);
|
|
|
|
if (NO_ERROR == ulError)
|
|
{
|
|
pConnection->Interface.Flags |= NAT_INTERFACE_FLAG_ADDED_H323;
|
|
|
|
ulError =
|
|
H323RmBindInterface(
|
|
pConnection->Interface.Index,
|
|
pConnection->pBindingInfo
|
|
);
|
|
}
|
|
|
|
if (NO_ERROR == ulError)
|
|
{
|
|
ulError = H323RmEnableInterface(pConnection->Interface.Index);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Inform the ALG manager of the changes
|
|
//
|
|
|
|
if (0 != ucOldProtocol && 0 != usOldPort)
|
|
{
|
|
AlgRmPortMappingChanged(
|
|
pConnection->Interface.Index,
|
|
ucOldProtocol,
|
|
usOldPort
|
|
);
|
|
}
|
|
|
|
if (0 != ucNewProtocol && 0 != usNewPort
|
|
&& (ucOldProtocol != ucNewProtocol
|
|
|| usOldPort != usNewPort))
|
|
{
|
|
AlgRmPortMappingChanged(
|
|
pConnection->Interface.Index,
|
|
ucNewProtocol,
|
|
usNewPort
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
LeaveCriticalSection(&NatInterfaceLock);
|
|
|
|
//
|
|
// We may also need to rebuild the DHCP reservation list
|
|
//
|
|
|
|
if (fRebuildDhcpList)
|
|
{
|
|
EnterCriticalSection(&NhLock);
|
|
|
|
NhFreeDhcpReservations();
|
|
NhBuildDhcpReservations();
|
|
|
|
LeaveCriticalSection(&NhLock);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// Private methods
|
|
//
|
|
|
|
BOOLEAN
|
|
CSharedAccessUpdate::IsH323Protocol(
|
|
UCHAR ucProtocol,
|
|
USHORT usPort
|
|
)
|
|
{
|
|
return (NAT_PROTOCOL_TCP == ucProtocol
|
|
&& (H323_Q931_PORT == usPort
|
|
|| H323_LDAP_PORT == usPort
|
|
|| H323_LDAP_ALT_PORT == usPort));
|
|
}
|
|
|
|
|
|
STDMETHODIMP
|
|
CSharedAccessUpdate::PortMappingListChanged()
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
hr = FireNATEvent_PortMappingsChanged();
|
|
|
|
return hr;
|
|
}
|
|
|