|
|
/*++
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
//
if (pConnection->HNetProperties.fIcsPublic) { hr = pPortMapping->pBinding->GetTargetComputerAddress(&pPortMapping->ulPrivateAddress);
if (SUCCEEDED(hr) && INADDR_LOOPBACK_NO == pPortMapping->ulPrivateAddress) { //
// If the port mapping targets the loopback address
// we want to use the address from the binding
// info instead.
//
pPortMapping->ulPrivateAddress = pConnection->pBindingInfo->Address[0].Address; } } else { pPortMapping->ulPrivateAddress = pConnection->pBindingInfo->Address[0].Address; }
if (SUCCEEDED(hr)) { 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 (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; }
|