/*++ 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( NH_ALLOCATE(sizeof(*pPortMapping)) ); if (NULL == pPortMapping) { hr = E_OUTOFMEMORY; break; } ZeroMemory(pPortMapping, sizeof(*pPortMapping)); pPortMapping->pProtocolGuid = reinterpret_cast( 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; }