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.
1772 lines
41 KiB
1772 lines
41 KiB
/*++
|
|
|
|
Copyright (c) 1998, Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
rmapi.c
|
|
|
|
Abstract:
|
|
|
|
This module contains code for the part of the router-manager interface
|
|
which is common to all the protocols in this component.
|
|
|
|
Author:
|
|
|
|
Abolade Gbadegesin (aboladeg) 4-Mar-1998
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "precomp.h"
|
|
#pragma hdrstop
|
|
#include <ras.h>
|
|
#include <rasuip.h>
|
|
#include <raserror.h>
|
|
#include <ipinfo.h>
|
|
#include "beacon.h"
|
|
|
|
#include <atlbase.h>
|
|
CComModule _Module;
|
|
#include <atlcom.h>
|
|
#include "nathlp_i.c"
|
|
|
|
BEGIN_OBJECT_MAP(ObjectMap)
|
|
OBJECT_ENTRY(CLSID_SAUpdate, CSharedAccessUpdate)
|
|
END_OBJECT_MAP()
|
|
|
|
|
|
extern "C" {
|
|
#include <iphlpstk.h>
|
|
}
|
|
|
|
HANDLE NhpComponentEvent = NULL;
|
|
NH_COMPONENT_MODE NhComponentMode = NhUninitializedMode;
|
|
const WCHAR NhpDhcpDomainString[] = L"DhcpDomain";
|
|
const WCHAR NhpDomainString[] = L"Domain";
|
|
BOOLEAN NhpDllProcessAttachSucceeded;
|
|
const WCHAR NhpEnableProxy[] = L"EnableProxy";
|
|
const WCHAR NhpICSDomainString[] = L"ICSDomain";
|
|
LONG NhpIsWinsProxyEnabled = -1;
|
|
CRITICAL_SECTION NhLock;
|
|
HMODULE NhpRtrmgrDll = NULL;
|
|
LIST_ENTRY NhApplicationSettingsList;
|
|
LIST_ENTRY NhDhcpReservationList;
|
|
DWORD NhDhcpScopeAddress = 0;
|
|
DWORD NhDhcpScopeMask = 0;
|
|
HANDLE NhFileHandle = INVALID_HANDLE_VALUE;
|
|
const WCHAR NhTcpipParametersString[] =
|
|
L"\\Registry\\Machine\\System\\CurrentControlSet\\Services"
|
|
L"\\Tcpip\\Parameters";
|
|
|
|
//
|
|
// EXTERNAL DECLARATIONS
|
|
//
|
|
|
|
BOOL
|
|
APIENTRY
|
|
DllMain(
|
|
HINSTANCE Instance,
|
|
ULONG Reason,
|
|
PVOID Unused
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Standard DLL entry/exit routine.
|
|
Initializes/shuts-down the modules implemented in the DLL.
|
|
The initialization performed is sufficient that all the modules'
|
|
interface lists can be searched, whether or not the protocols are
|
|
installed or operational.
|
|
|
|
Arguments:
|
|
|
|
Instance - the instance of this DLL in this process
|
|
|
|
Reason - the reason for invocation
|
|
|
|
Unused - unused.
|
|
|
|
Return Value:
|
|
|
|
BOOL - indicates success or failure.
|
|
|
|
--*/
|
|
|
|
{
|
|
switch (Reason) {
|
|
case DLL_PROCESS_ATTACH: {
|
|
WSADATA wd;
|
|
NhpDllProcessAttachSucceeded = FALSE;
|
|
DisableThreadLibraryCalls(Instance);
|
|
__try {
|
|
InitializeCriticalSection(&NhLock);
|
|
} __except(EXCEPTION_EXECUTE_HANDLER) {
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
WSAStartup(MAKEWORD(2,2), &wd);
|
|
NhInitializeTraceManagement();
|
|
if (!NhInitializeEventLogManagement()) {return FALSE; }
|
|
InitializeListHead(&NhApplicationSettingsList);
|
|
InitializeListHead(&NhDhcpReservationList);
|
|
if (NhInitializeBufferManagement()) { return FALSE; }
|
|
if (NhInitializeTimerManagement()) { return FALSE; }
|
|
if (!NatInitializeModule()) { return FALSE; }
|
|
if (!DhcpInitializeModule()) { return FALSE; }
|
|
if (!DnsInitializeModule()) { return FALSE; }
|
|
if (!AlgInitializeModule()) { return FALSE; }
|
|
if (!H323InitializeModule()) { return FALSE; }
|
|
if(FAILED(InitializeBeaconSvr())) { return FALSE; }
|
|
|
|
_Module.Init(ObjectMap, Instance, &LIBID_IPNATHelperLib);
|
|
_Module.RegisterTypeLib();
|
|
NhpDllProcessAttachSucceeded = TRUE;
|
|
break;
|
|
}
|
|
case DLL_PROCESS_DETACH: {
|
|
if (TRUE == NhpDllProcessAttachSucceeded) {
|
|
NhResetComponentMode();
|
|
TerminateBeaconSvr();
|
|
H323CleanupModule();
|
|
AlgCleanupModule();
|
|
DnsCleanupModule();
|
|
DhcpCleanupModule();
|
|
NatCleanupModule();
|
|
NhShutdownTimerManagement();
|
|
NhShutdownBufferManagement();
|
|
NhShutdownEventLogManagement();
|
|
NhShutdownTraceManagement();
|
|
WSACleanup();
|
|
if (NhpRtrmgrDll) {
|
|
FreeLibrary(NhpRtrmgrDll); NhpRtrmgrDll = NULL;
|
|
}
|
|
DeleteCriticalSection(&NhLock);
|
|
|
|
_Module.Term();
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
|
|
} // DllMain
|
|
|
|
|
|
VOID
|
|
NhBuildDhcpReservations(
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Builds the list of DHCP reservations
|
|
|
|
Arguments:
|
|
|
|
none.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
Environment:
|
|
|
|
Invoked with NhLock held on a COM-initialized thread.
|
|
|
|
--*/
|
|
|
|
{
|
|
HRESULT hr;
|
|
IHNetCfgMgr *pCfgMgr = NULL;
|
|
IEnumHNetPortMappingBindings *pEnumBindings;
|
|
IHNetIcsSettings *pIcsSettings;
|
|
PNAT_DHCP_RESERVATION pReservation;
|
|
ULONG ulCount;
|
|
|
|
hr = NhGetHNetCfgMgr(&pCfgMgr);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
//
|
|
// Get the ICS settings interface
|
|
//
|
|
|
|
hr = pCfgMgr->QueryInterface(
|
|
IID_PPV_ARG(IHNetIcsSettings, &pIcsSettings)
|
|
);
|
|
}
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
//
|
|
// Get DHCP scope information
|
|
//
|
|
|
|
hr = pIcsSettings->GetDhcpScopeSettings(
|
|
&NhDhcpScopeAddress,
|
|
&NhDhcpScopeMask
|
|
);
|
|
|
|
//
|
|
// Get enumeration of DHCP reservered addresses
|
|
//
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = pIcsSettings->EnumDhcpReservedAddresses(&pEnumBindings);
|
|
}
|
|
|
|
pIcsSettings->Release();
|
|
}
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
//
|
|
// Process the items in the enum
|
|
//
|
|
|
|
do
|
|
{
|
|
IHNetPortMappingBinding *pBinding;
|
|
|
|
hr = pEnumBindings->Next(1, &pBinding, &ulCount);
|
|
|
|
if (SUCCEEDED(hr) && 1 == ulCount)
|
|
{
|
|
//
|
|
// Allocate a new reservation entry
|
|
//
|
|
|
|
pReservation = reinterpret_cast<PNAT_DHCP_RESERVATION>(
|
|
NH_ALLOCATE(sizeof(*pReservation))
|
|
);
|
|
|
|
if (NULL != pReservation)
|
|
{
|
|
ZeroMemory(pReservation, sizeof(*pReservation));
|
|
|
|
//
|
|
// Get computer name
|
|
//
|
|
|
|
hr = pBinding->GetTargetComputerName(
|
|
&pReservation->Name
|
|
);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
//
|
|
// Get reserved address
|
|
//
|
|
|
|
hr = pBinding->GetTargetComputerAddress(
|
|
&pReservation->Address
|
|
);
|
|
}
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
//
|
|
// Add entry to list
|
|
//
|
|
|
|
InsertTailList(
|
|
&NhDhcpReservationList,
|
|
&pReservation->Link)
|
|
;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Free entry
|
|
//
|
|
|
|
NH_FREE(pReservation);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
|
|
pBinding->Release();
|
|
}
|
|
} while (SUCCEEDED(hr) && 1 == ulCount);
|
|
|
|
pEnumBindings->Release();
|
|
}
|
|
|
|
if (NULL != pCfgMgr)
|
|
{
|
|
pCfgMgr->Release();
|
|
}
|
|
} // NhBuildDhcpReservations
|
|
|
|
|
|
ULONG
|
|
NhDialSharedConnection(
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is invoked to connect a home-router interface.
|
|
The connection is established by invoking the RAS autodial process
|
|
with the appropriate phonebook and entry-name in the security context
|
|
of the logged-on user.
|
|
|
|
Arguments:
|
|
|
|
none.
|
|
|
|
Return Value:
|
|
|
|
ULONG - Win32 status code.
|
|
|
|
--*/
|
|
|
|
{
|
|
return RasAutoDialSharedConnection();
|
|
} // NhDialSharedConnection
|
|
|
|
|
|
VOID
|
|
NhFreeApplicationSettings(
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Frees the list of application settings
|
|
|
|
Arguments:
|
|
|
|
none.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
Environment:
|
|
|
|
Invoked with NhLock held.
|
|
|
|
--*/
|
|
|
|
{
|
|
PLIST_ENTRY Link;
|
|
PNAT_APP_ENTRY pAppEntry;
|
|
|
|
PROFILE("NhFreeApplicationSettings");
|
|
|
|
while (!IsListEmpty(&NhApplicationSettingsList))
|
|
{
|
|
Link = RemoveHeadList(&NhApplicationSettingsList);
|
|
pAppEntry = CONTAINING_RECORD(Link, NAT_APP_ENTRY, Link);
|
|
|
|
CoTaskMemFree(pAppEntry->ResponseArray);
|
|
NH_FREE(pAppEntry);
|
|
}
|
|
} // NhFreeApplicationSettings
|
|
|
|
|
|
VOID
|
|
NhFreeDhcpReservations(
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Frees the list of DHCP reservations
|
|
|
|
Arguments:
|
|
|
|
none.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
Environment:
|
|
|
|
Invoked with NhLock held.
|
|
|
|
--*/
|
|
|
|
{
|
|
PLIST_ENTRY Link;
|
|
PNAT_DHCP_RESERVATION pReservation;
|
|
|
|
PROFILE("NhFreeDhcpReservations");
|
|
|
|
while (!IsListEmpty(&NhDhcpReservationList))
|
|
{
|
|
Link = RemoveHeadList(&NhDhcpReservationList);
|
|
pReservation = CONTAINING_RECORD(Link, NAT_DHCP_RESERVATION, Link);
|
|
|
|
CoTaskMemFree(pReservation->Name);
|
|
NH_FREE(pReservation);
|
|
}
|
|
} // NhFreeDhcpReservations
|
|
|
|
|
|
BOOLEAN
|
|
NhIsDnsProxyEnabled(
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is invoked to discover whether the DNS proxy is enabled.
|
|
|
|
Arguments:
|
|
|
|
none.
|
|
|
|
Return Value:
|
|
|
|
BOOLEAN - TRUE if DNS proxy is enabled, FALSE otherwise
|
|
|
|
Environment:
|
|
|
|
Invoked from an arbitrary context.
|
|
|
|
--*/
|
|
|
|
{
|
|
PROFILE("NhIsDnsProxyEnabled");
|
|
|
|
return DnsIsDnsEnabled();
|
|
|
|
} // NhIsDnsProxyEnabled
|
|
|
|
|
|
BOOLEAN
|
|
NhIsLocalAddress(
|
|
ULONG Address
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is invoked to determine whether the given IP address
|
|
is for a local interface.
|
|
|
|
Arguments:
|
|
|
|
Address - the IP address to find
|
|
|
|
Return Value:
|
|
|
|
BOOLEAN - TRUE if the address is found, FALSE otherwise
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONG Error;
|
|
ULONG i;
|
|
PMIB_IPADDRTABLE Table;
|
|
|
|
Error =
|
|
AllocateAndGetIpAddrTableFromStack(
|
|
&Table, FALSE, GetProcessHeap(), 0
|
|
);
|
|
if (Error) {
|
|
NhTrace(
|
|
TRACE_FLAG_IF,
|
|
"NhIsLocalAddress: GetIpAddrTableFromStack=%d", Error
|
|
);
|
|
return FALSE;
|
|
}
|
|
for (i = 0; i < Table->dwNumEntries; i++) {
|
|
if (Table->table[i].dwAddr == Address) {
|
|
HeapFree(GetProcessHeap(), 0, Table);
|
|
return TRUE;
|
|
}
|
|
}
|
|
HeapFree(GetProcessHeap(), 0, Table);
|
|
return FALSE;
|
|
|
|
} // NhIsLocalAddress
|
|
|
|
|
|
BOOLEAN
|
|
NhIsWinsProxyEnabled(
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is invoked to discover whether the WINS proxy is enabled.
|
|
|
|
Arguments:
|
|
|
|
none.
|
|
|
|
Return Value:
|
|
|
|
BOOLEAN - TRUE if WINS proxy is enabled, FALSE otherwise
|
|
|
|
Environment:
|
|
|
|
Invoked from an arbitrary context.
|
|
|
|
--*/
|
|
|
|
{
|
|
PROFILE("NhIsWinsProxyEnabled");
|
|
|
|
return DnsIsWinsEnabled();
|
|
|
|
} // NhIsWinsProxyEnabled
|
|
|
|
|
|
PIP_ADAPTER_BINDING_INFO
|
|
NhQueryBindingInformation(
|
|
ULONG AdapterIndex
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is called to obtain the binding information
|
|
for the adapter with the given index.
|
|
It does this by obtaining a table of IP addresses from the stack,
|
|
and determining which addresses correspond to the given index.
|
|
|
|
Arguments:
|
|
|
|
AdapterIndex - the adapter for which binding information is required
|
|
|
|
Return Value:
|
|
|
|
PIP_ADAPTER_BINDING_INFO - the allocated binding information
|
|
|
|
--*/
|
|
|
|
{
|
|
PIP_ADAPTER_BINDING_INFO BindingInfo = NULL;
|
|
ULONG Count = 0;
|
|
ULONG i;
|
|
PMIB_IPADDRTABLE Table;
|
|
if (AllocateAndGetIpAddrTableFromStack(
|
|
&Table, FALSE, GetProcessHeap(), 0
|
|
) == NO_ERROR) {
|
|
//
|
|
// Count the adapter's addresses
|
|
//
|
|
for (i = 0; i < Table->dwNumEntries; i++) {
|
|
if (Table->table[i].dwIndex == AdapterIndex) { ++Count; }
|
|
}
|
|
//
|
|
// Allocate space for the binding info
|
|
//
|
|
BindingInfo = reinterpret_cast<PIP_ADAPTER_BINDING_INFO>(
|
|
NH_ALLOCATE(SIZEOF_IP_BINDING(Count))
|
|
);
|
|
if (BindingInfo) {
|
|
//
|
|
// Fill in the binding info
|
|
//
|
|
BindingInfo->AddressCount = Count;
|
|
BindingInfo->RemoteAddress = 0;
|
|
Count = 0;
|
|
for (i = 0; i < Table->dwNumEntries; i++) {
|
|
if (Table->table[i].dwIndex != AdapterIndex) { continue; }
|
|
BindingInfo->Address[Count].Address = Table->table[i].dwAddr;
|
|
BindingInfo->Address[Count].Mask = Table->table[i].dwMask;
|
|
++Count;
|
|
}
|
|
}
|
|
HeapFree(GetProcessHeap(), 0, Table);
|
|
}
|
|
return BindingInfo;
|
|
} // NhQueryBindingInformation
|
|
|
|
|
|
NTSTATUS
|
|
NhQueryDomainName(
|
|
PCHAR* DomainName
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is invoked to obtain the local domain name.
|
|
|
|
Arguments:
|
|
|
|
DomainName - receives the allocated string containing the domain name
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - NT status code.
|
|
|
|
Environment:
|
|
|
|
Invoked from an arbitrary context.
|
|
|
|
--*/
|
|
|
|
{
|
|
PKEY_VALUE_PARTIAL_INFORMATION Information;
|
|
IO_STATUS_BLOCK IoStatus;
|
|
HANDLE Key;
|
|
ULONG Length;
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
NTSTATUS status;
|
|
UNICODE_STRING UnicodeString;
|
|
|
|
PROFILE("NhQueryDomainName");
|
|
|
|
*DomainName = NULL;
|
|
|
|
RtlInitUnicodeString(&UnicodeString, NhTcpipParametersString);
|
|
InitializeObjectAttributes(
|
|
&ObjectAttributes,
|
|
&UnicodeString,
|
|
OBJ_CASE_INSENSITIVE,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
//
|
|
// Open the 'Tcpip' registry key
|
|
//
|
|
|
|
status =
|
|
NtOpenKey(
|
|
&Key,
|
|
KEY_ALL_ACCESS,
|
|
&ObjectAttributes
|
|
);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
NhTrace(
|
|
TRACE_FLAG_REG,
|
|
"NhQueryDomainName: error %x opening registry key",
|
|
status
|
|
);
|
|
return status;
|
|
}
|
|
|
|
//
|
|
// Read the 'Domain' value
|
|
//
|
|
|
|
status =
|
|
NhQueryValueKey(
|
|
Key,
|
|
NhpDomainString,
|
|
&Information
|
|
);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
status =
|
|
NhQueryValueKey(
|
|
Key,
|
|
NhpDhcpDomainString,
|
|
&Information
|
|
);
|
|
}
|
|
|
|
NtClose(Key);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
NhTrace(
|
|
TRACE_FLAG_REG,
|
|
"NhQueryDomainName: error %x querying domain name",
|
|
status
|
|
);
|
|
return status;
|
|
}
|
|
|
|
if (REG_SZ != Information->Type
|
|
|| L'\0' != *(PWCHAR) (Information->Data +
|
|
(Information->DataLength - sizeof(WCHAR)))) {
|
|
|
|
NH_FREE(Information);
|
|
NhTrace(
|
|
TRACE_FLAG_REG,
|
|
"NhQueryDomainName: Registry contains invalid data"
|
|
);
|
|
return STATUS_UNSUCCESSFUL;
|
|
}
|
|
|
|
//
|
|
// Copy the domain name
|
|
//
|
|
|
|
Length = lstrlenW((PWCHAR)Information->Data) + 1;
|
|
|
|
*DomainName = reinterpret_cast<PCHAR>(NH_ALLOCATE(Length));
|
|
|
|
if (!*DomainName) {
|
|
NH_FREE(Information);
|
|
NhTrace(
|
|
TRACE_FLAG_REG,
|
|
"NhQueryDomainName: error allocating domain name"
|
|
);
|
|
return STATUS_NO_MEMORY;
|
|
}
|
|
|
|
status =
|
|
RtlUnicodeToMultiByteN(
|
|
*DomainName,
|
|
Length,
|
|
NULL,
|
|
(PWCHAR)Information->Data,
|
|
Length * sizeof(WCHAR)
|
|
);
|
|
|
|
NH_FREE(Information);
|
|
|
|
return status;
|
|
|
|
} // NhQueryDomainName
|
|
|
|
|
|
ULONG
|
|
NhQueryHostByName(
|
|
PWCHAR pszHostName,
|
|
PWCHAR pszDomainName,
|
|
ULONG ScopeNetwork,
|
|
ULONG ScopeMask
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is a helper routine. It queries the local DNS Client (resident resolver)
|
|
to see if it already knows the IP address of the desired hostname. This
|
|
may have happened by our DHCP module adding it to the hosts.ics file.
|
|
|
|
Arguments:
|
|
|
|
Pointer to the host name and domain suffix name. Scope net and mask.
|
|
|
|
Return Value:
|
|
|
|
IP address of the host; if we dont find it we return 0.
|
|
|
|
Environment:
|
|
|
|
Invoked from an arbitrary context.
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONG retIP = 0;
|
|
PWCHAR pszFQDN = NULL;
|
|
DNS_STATUS dnsStatus;
|
|
PDNS_RECORD pQueryResultsSet = NULL;
|
|
DWORD dwQueryOptions, dwSize;
|
|
|
|
if (!pszHostName ||
|
|
!pszDomainName ||
|
|
!*pszHostName ||
|
|
!*pszDomainName)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
// create a FQDN hostname
|
|
// total length = hostname length + dot length + domainname length + null
|
|
//
|
|
dwSize = wcslen(pszHostName) + 1 + wcslen(pszDomainName) + 1;
|
|
|
|
pszFQDN = reinterpret_cast<PWCHAR>(NH_ALLOCATE(sizeof(WCHAR) * dwSize));
|
|
|
|
if (!pszFQDN)
|
|
{
|
|
NhTrace(
|
|
TRACE_FLAG_DNS,
|
|
"NhQueryHostByName: allocation failed for client name"
|
|
);
|
|
return 0;
|
|
}
|
|
ZeroMemory(pszFQDN, (sizeof(WCHAR) * dwSize));
|
|
|
|
wcscpy(pszFQDN, pszHostName); // copy the hostname
|
|
wcscat(pszFQDN, L"."); // add the dot
|
|
wcscat(pszFQDN, pszDomainName); // add the suffix
|
|
|
|
dwQueryOptions =
|
|
(
|
|
DNS_QUERY_STANDARD |
|
|
DNS_QUERY_CACHE_ONLY |
|
|
DNS_QUERY_TREAT_AS_FQDN
|
|
);
|
|
|
|
dnsStatus = DnsQuery_W(
|
|
(PWSTR) pszFQDN,
|
|
DNS_TYPE_A,
|
|
dwQueryOptions,
|
|
NULL,
|
|
&pQueryResultsSet,
|
|
NULL
|
|
);
|
|
|
|
if ((NO_ERROR == dnsStatus) && (pQueryResultsSet))
|
|
{
|
|
PDNS_RECORD pRR = pQueryResultsSet;
|
|
|
|
while (pRR)
|
|
{
|
|
if (pRR->Flags.S.Section == DNSREC_ANSWER &&
|
|
pRR->wType == DNS_TYPE_A)
|
|
{
|
|
if (((pRR->Data.A.IpAddress & ~ScopeMask) != 0) &&
|
|
((pRR->Data.A.IpAddress & ~ScopeMask) != ~ScopeMask) &&
|
|
((pRR->Data.A.IpAddress & ScopeMask) == ScopeNetwork))
|
|
{
|
|
retIP = pRR->Data.A.IpAddress;
|
|
break;
|
|
}
|
|
}
|
|
|
|
pRR = pRR->pNext;
|
|
}
|
|
}
|
|
|
|
if (pQueryResultsSet)
|
|
{
|
|
DnsRecordListFree(
|
|
pQueryResultsSet,
|
|
DnsFreeRecordListDeep
|
|
);
|
|
}
|
|
|
|
if (pszFQDN)
|
|
{
|
|
NH_FREE(pszFQDN);
|
|
}
|
|
|
|
return retIP;
|
|
} // NhQueryHostByName
|
|
|
|
|
|
NTSTATUS
|
|
NhQueryICSDomainSuffix(
|
|
PWCHAR *ppszDomain
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is a helper routine. It queries the registry to see if there
|
|
is a setting for the ICSDomain string - if not, it returns the default
|
|
suffix used for ICS.
|
|
|
|
Arguments:
|
|
|
|
Pointer to a suffix string. Caller MUST release using NH_FREE.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - NT status code.
|
|
|
|
Environment:
|
|
|
|
Invoked from an arbitrary context.
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS status;
|
|
PKEY_VALUE_PARTIAL_INFORMATION Information;
|
|
IO_STATUS_BLOCK IoStatus;
|
|
HANDLE Key;
|
|
ULONG Length;
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
UNICODE_STRING UnicodeString;
|
|
|
|
if (!ppszDomain)
|
|
{
|
|
NhTrace(
|
|
TRACE_FLAG_REG,
|
|
"NhQueryICSDomainSuffix: invalid (null pointer) parameter"
|
|
);
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
*ppszDomain = NULL;
|
|
|
|
//
|
|
// retrieve current suffix string (if any)
|
|
//
|
|
|
|
RtlInitUnicodeString(&UnicodeString, NhTcpipParametersString);
|
|
InitializeObjectAttributes(
|
|
&ObjectAttributes,
|
|
&UnicodeString,
|
|
OBJ_CASE_INSENSITIVE,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
//
|
|
// Open the 'Tcpip' registry key
|
|
//
|
|
|
|
status =
|
|
NtOpenKey(
|
|
&Key,
|
|
KEY_READ,
|
|
&ObjectAttributes
|
|
);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
NhTrace(
|
|
TRACE_FLAG_REG,
|
|
"NhQueryICSDomainSuffix: error %x opening registry key",
|
|
status
|
|
);
|
|
return status;
|
|
}
|
|
|
|
//
|
|
// Read the 'Domain' value
|
|
//
|
|
|
|
status =
|
|
NhQueryValueKey(
|
|
Key,
|
|
NhpICSDomainString,
|
|
&Information
|
|
);
|
|
|
|
NtClose(Key);
|
|
|
|
if (!NT_SUCCESS(status) || !Information) {
|
|
NhTrace(
|
|
TRACE_FLAG_REG,
|
|
"NhQueryICSDomainSuffix: error %x querying ICSDomain name - "
|
|
"using default instead",
|
|
status
|
|
);
|
|
|
|
//
|
|
// Copy default domain name instead
|
|
//
|
|
|
|
Length = wcslen(DNS_HOMENET_SUFFIX) + 1;
|
|
|
|
*ppszDomain = reinterpret_cast<PWCHAR>(
|
|
NH_ALLOCATE(sizeof(WCHAR) * Length)
|
|
);
|
|
|
|
if (!*ppszDomain) {
|
|
NhTrace(
|
|
TRACE_FLAG_REG,
|
|
"NhQueryICSDomainSuffix: error allocating domain name"
|
|
);
|
|
return STATUS_NO_MEMORY;
|
|
}
|
|
|
|
wcscpy(*ppszDomain, DNS_HOMENET_SUFFIX);
|
|
|
|
}
|
|
else
|
|
{
|
|
|
|
if (REG_SZ != Information->Type
|
|
|| L'\0' != *(PWCHAR) (Information->Data +
|
|
(Information->DataLength - sizeof(WCHAR)))) {
|
|
|
|
NH_FREE(Information);
|
|
NhTrace(
|
|
TRACE_FLAG_REG,
|
|
"NhQueryICSDomainSuffix: Registry contains invalid data"
|
|
);
|
|
return STATUS_UNSUCCESSFUL;
|
|
}
|
|
|
|
//
|
|
// Copy the domain name
|
|
//
|
|
|
|
Length = wcslen((PWCHAR)Information->Data) + 1;
|
|
|
|
*ppszDomain = reinterpret_cast<PWCHAR>(
|
|
NH_ALLOCATE(sizeof(WCHAR) * Length)
|
|
);
|
|
|
|
if (!*ppszDomain) {
|
|
NH_FREE(Information);
|
|
NhTrace(
|
|
TRACE_FLAG_REG,
|
|
"NhQueryICSDomainSuffix: error allocating domain name"
|
|
);
|
|
return STATUS_NO_MEMORY;
|
|
}
|
|
|
|
wcscpy(*ppszDomain, (PWCHAR)Information->Data);
|
|
|
|
NH_FREE(Information);
|
|
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
} // NhQueryICSDomainSuffix
|
|
|
|
|
|
|
|
NTSTATUS
|
|
NhQueryValueKey(
|
|
HANDLE Key,
|
|
const WCHAR ValueName[],
|
|
PKEY_VALUE_PARTIAL_INFORMATION* Information
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is called to obtain the value of a registry key.
|
|
|
|
Arguments:
|
|
|
|
Key - the key to be queried
|
|
|
|
ValueName - the value to be queried
|
|
|
|
Information - receives a pointer to the information read
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - NT status code.
|
|
|
|
--*/
|
|
|
|
{
|
|
UCHAR Buffer[sizeof(KEY_VALUE_PARTIAL_INFORMATION)];
|
|
ULONG InformationLength;
|
|
NTSTATUS status;
|
|
UNICODE_STRING UnicodeString;
|
|
|
|
PROFILE("NhQueryValueKey");
|
|
|
|
RtlInitUnicodeString(&UnicodeString, ValueName);
|
|
|
|
*Information = (PKEY_VALUE_PARTIAL_INFORMATION)Buffer;
|
|
InformationLength = sizeof(KEY_VALUE_PARTIAL_INFORMATION);
|
|
|
|
//
|
|
// Read the value's size
|
|
//
|
|
|
|
status =
|
|
NtQueryValueKey(
|
|
Key,
|
|
&UnicodeString,
|
|
KeyValuePartialInformation,
|
|
*Information,
|
|
InformationLength,
|
|
&InformationLength
|
|
);
|
|
|
|
if (!NT_SUCCESS(status) &&
|
|
status != STATUS_BUFFER_OVERFLOW &&
|
|
status != STATUS_BUFFER_TOO_SMALL
|
|
) {
|
|
NhTrace(
|
|
TRACE_FLAG_REG,
|
|
"NhQueryValueKey: status %08x obtaining value size",
|
|
status
|
|
);
|
|
*Information = NULL;
|
|
return status;
|
|
}
|
|
|
|
//
|
|
// Allocate space for the value's size
|
|
//
|
|
|
|
*Information =
|
|
(PKEY_VALUE_PARTIAL_INFORMATION)NH_ALLOCATE(InformationLength + 2);
|
|
|
|
if (!*Information) {
|
|
NhTrace(
|
|
TRACE_FLAG_REG,
|
|
"NhQueryValueKey: error allocating %d bytes",
|
|
InformationLength + 2
|
|
);
|
|
return STATUS_NO_MEMORY;
|
|
}
|
|
|
|
//
|
|
// Read the value's data
|
|
//
|
|
|
|
status =
|
|
NtQueryValueKey(
|
|
Key,
|
|
&UnicodeString,
|
|
KeyValuePartialInformation,
|
|
*Information,
|
|
InformationLength,
|
|
&InformationLength
|
|
);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
NhTrace(
|
|
TRACE_FLAG_REG,
|
|
"NhQueryValueKey: status %08x obtaining value data",
|
|
status
|
|
);
|
|
NH_FREE(*Information);
|
|
*Information = NULL;
|
|
}
|
|
|
|
return status;
|
|
|
|
} // NhQueryValueKey
|
|
|
|
|
|
ULONG
|
|
NhMapAddressToAdapter(
|
|
ULONG Address
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is invoked to map an IP address to an adapter index.
|
|
It does so by obtaining the stack's address-table, which contains
|
|
valid adapter-indices rather than IP router-manager indices.
|
|
This table is then used to obtain the IP address's adapter-index.
|
|
|
|
Arguments:
|
|
|
|
Address - the local address for which an adapter-index is required
|
|
|
|
Return Value:
|
|
|
|
ULONG - adapter index.
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONG AdapterIndex = (ULONG)-1;
|
|
ULONG i;
|
|
PMIB_IPADDRTABLE Table;
|
|
PROFILE("NhMapAddressToAdapter");
|
|
if (AllocateAndGetIpAddrTableFromStack(
|
|
&Table, FALSE, GetProcessHeap(), 0
|
|
) == NO_ERROR) {
|
|
for (i = 0; i < Table->dwNumEntries; i++) {
|
|
if (Table->table[i].dwAddr != Address) { continue; }
|
|
AdapterIndex = Table->table[i].dwIndex;
|
|
break;
|
|
}
|
|
HeapFree(GetProcessHeap(), 0, Table);
|
|
}
|
|
return AdapterIndex;
|
|
} // NhMapAddressToAdapter
|
|
|
|
|
|
ULONG
|
|
NhMapInterfaceToAdapter(
|
|
ULONG Index
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is invoked to map an interface to an adapter index.
|
|
It does so by invoking the appropriate IP router-manager entry-point.
|
|
|
|
Arguments:
|
|
|
|
Index - the index of the interface to be mapped
|
|
|
|
Return Value:
|
|
|
|
ULONG - adapter index.
|
|
|
|
--*/
|
|
|
|
{
|
|
MAPINTERFACETOADAPTER FarProc;
|
|
PROFILE("NhMapInterfaceToAdapter");
|
|
EnterCriticalSection(&NhLock);
|
|
if (!NhpRtrmgrDll) { NhpRtrmgrDll = LoadLibraryA("IPRTRMGR.DLL"); }
|
|
LeaveCriticalSection(&NhLock);
|
|
if (!NhpRtrmgrDll) { return (ULONG)-1; }
|
|
FarProc = (MAPINTERFACETOADAPTER)GetProcAddress(NhpRtrmgrDll, "MapInterfaceToAdapter");
|
|
return (ULONG)(FarProc ? (*FarProc)(Index) : -1);
|
|
} // NhMapInterfaceToAdapter
|
|
|
|
|
|
VOID
|
|
NhResetComponentMode(
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine relinquishes control of the kernel-mode translation module,
|
|
and returns this module to an uninitialized state.
|
|
|
|
Arguments:
|
|
|
|
none.
|
|
|
|
Return Value:
|
|
|
|
none.
|
|
|
|
--*/
|
|
|
|
{
|
|
EnterCriticalSection(&NhLock);
|
|
if (NhpComponentEvent) {
|
|
CloseHandle(NhpComponentEvent); NhpComponentEvent = NULL;
|
|
}
|
|
if (INVALID_HANDLE_VALUE != NhFileHandle) {
|
|
NatUnloadDriver(NhFileHandle); NhFileHandle = INVALID_HANDLE_VALUE;
|
|
}
|
|
NhComponentMode = NhUninitializedMode;
|
|
LeaveCriticalSection(&NhLock);
|
|
} // NhResetComponentMode
|
|
|
|
|
|
BOOLEAN
|
|
NhSetComponentMode(
|
|
NH_COMPONENT_MODE ComponentMode
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is invoked to atomically set the module into a particular mode
|
|
in order to prevent conflict between shared-access and connection-sharing,
|
|
both of which are implemented in this module, and both of which run
|
|
in the 'netsvcs' instance of SVCHOST.EXE.
|
|
|
|
In setting either mode, the routine first determines whether it is already
|
|
executing in the alternate mode, in which case it fails.
|
|
|
|
Otherwise, it attempts to open a handle to ipnat.sys to claim exclusive
|
|
control of the kernel-mode translation module. The kernel-mode translation
|
|
module enforces exclusive ownership -- it will fail the open w/
|
|
ERROR_ACCESS_DENIED if another process has claimed control of the driver.
|
|
|
|
Otherwise, the kernel-mode translation module is claimed for this module
|
|
and the module is set into the required mode.
|
|
|
|
This routine will also attempt to create a named event. This event
|
|
was previously used to enforce exclusive ownership in the past, when
|
|
the driver was unable to do so. We will not fail if the event already
|
|
exists (or if we are unable to create it). We still create the event,
|
|
though, so that other modules that choose to use this mechanism will
|
|
still be able to correctly report the cause of the error.
|
|
|
|
Arguments:
|
|
|
|
ComponentMode - the mode into which the module is to be set.
|
|
|
|
Return Value:
|
|
|
|
BOOLEAN - TRUE if successful, FALSE if the module could not be set
|
|
or if the kernel-mode translation module has already been claimed.
|
|
|
|
--*/
|
|
|
|
{
|
|
EnterCriticalSection(&NhLock);
|
|
|
|
if (NhUninitializedMode != NhComponentMode
|
|
&& NhComponentMode != ComponentMode) {
|
|
|
|
//
|
|
// The module has been set to a different mode.
|
|
//
|
|
|
|
LeaveCriticalSection(&NhLock);
|
|
NhStartEventLog();
|
|
NhErrorLog(
|
|
(ComponentMode == NhRoutingProtocolMode)
|
|
? IP_NAT_LOG_ROUTING_PROTOCOL_CONFLICT
|
|
: IP_NAT_LOG_SHARED_ACCESS_CONFLICT,
|
|
0,
|
|
""
|
|
);
|
|
NhStopEventLog();
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Attempt to load and open a handle to the NAT driver, if we have not
|
|
// already done so. This is needed to detect if another process has already
|
|
// taken control of the driver.
|
|
//
|
|
|
|
if (INVALID_HANDLE_VALUE == NhFileHandle) {
|
|
ULONG Error;
|
|
IP_NAT_GLOBAL_INFO GlobalInfo;
|
|
|
|
ZeroMemory(&GlobalInfo, sizeof(GlobalInfo));
|
|
GlobalInfo.Header.Version = IP_NAT_VERSION;
|
|
GlobalInfo.Header.Size = FIELD_OFFSET(RTR_INFO_BLOCK_HEADER, TocEntry);
|
|
|
|
Error = NatLoadDriver(&NhFileHandle, &GlobalInfo);
|
|
|
|
if (ERROR_ACCESS_DENIED == Error) {
|
|
|
|
//
|
|
// An access denied error signifies a conflict.
|
|
//
|
|
|
|
NhFileHandle = INVALID_HANDLE_VALUE;
|
|
LeaveCriticalSection(&NhLock);
|
|
NhStartEventLog();
|
|
NhErrorLog(
|
|
(ComponentMode == NhRoutingProtocolMode)
|
|
? IP_NAT_LOG_ROUTING_PROTOCOL_CONFLICT
|
|
: IP_NAT_LOG_SHARED_ACCESS_CONFLICT,
|
|
0,
|
|
""
|
|
);
|
|
NhStopEventLog();
|
|
return FALSE;
|
|
|
|
} else if (NO_ERROR != Error) {
|
|
|
|
//
|
|
// We weren't able to load the driver for some other reason.
|
|
//
|
|
|
|
NhFileHandle = INVALID_HANDLE_VALUE;
|
|
LeaveCriticalSection(&NhLock);
|
|
NhStartEventLog();
|
|
NhErrorLog(
|
|
IP_NAT_LOG_LOAD_DRIVER_FAILED,
|
|
Error,
|
|
""
|
|
);
|
|
NhStopEventLog();
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
if (NULL == NhpComponentEvent) {
|
|
NhpComponentEvent =
|
|
CreateEventA(NULL, FALSE, FALSE, IP_NAT_SERVICE_NAME);
|
|
|
|
//
|
|
// We will continue executing even if we are not able to create
|
|
// the named event, or if the event already exists. This is mainly
|
|
// for other users of the NAT who follow the old access control
|
|
// system, instead of letting the driver enforce single-ownership
|
|
// requirements.
|
|
//
|
|
}
|
|
|
|
NhComponentMode = ComponentMode;
|
|
LeaveCriticalSection(&NhLock);
|
|
return TRUE;
|
|
} // NhSetComponentMode
|
|
|
|
|
|
VOID
|
|
NhSignalNatInterface(
|
|
ULONG Index,
|
|
BOOLEAN Boundary
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is invoked upon reconfiguration of a NAT interface.
|
|
It invokes the reconfiguration for the DHCP allocator and DNS proxy,
|
|
neither of which are expected to operate on a NAT boundary interface.
|
|
This notification gives either (or both) an opportunity to deactivate
|
|
itself on NAT interfaces or reactivate itself on non-NAT interfaces.
|
|
|
|
Arguments:
|
|
|
|
Index - the interface whose configuration has changed
|
|
|
|
Boundary - indicates whether the interface is now a boundary interface
|
|
|
|
Return Value:
|
|
|
|
none.
|
|
|
|
Environment:
|
|
|
|
Invoked from an arbitrary context.
|
|
|
|
--*/
|
|
|
|
{
|
|
PROFILE("NhSignalNatInterface");
|
|
|
|
//
|
|
// Attempt to obtain the corresponding DHCP and DNS interfaces.
|
|
// It is important that this works regardless of whether DHCP allocation,
|
|
// DNS proxying or DirectPlay transparent proxying is enabled;
|
|
// the interface lists are initialized minimally in 'DllMain' above.
|
|
//
|
|
|
|
DhcpSignalNatInterface(Index, Boundary);
|
|
DnsSignalNatInterface(Index, Boundary);
|
|
AlgSignalNatInterface(Index, Boundary);
|
|
H323SignalNatInterface(Index, Boundary);
|
|
|
|
} // NhSignalNatInterface
|
|
|
|
|
|
VOID
|
|
NhUpdateApplicationSettings(
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is invoked to (re)load the advanced application settings.
|
|
|
|
Arguments:
|
|
|
|
none.
|
|
|
|
Return Value:
|
|
|
|
none.
|
|
|
|
--*/
|
|
|
|
{
|
|
HRESULT hr;
|
|
PNAT_APP_ENTRY pAppEntry;
|
|
IHNetCfgMgr *pCfgMgr = NULL;
|
|
IHNetProtocolSettings *pProtocolSettings;
|
|
IEnumHNetApplicationProtocols *pEnumApps;
|
|
BOOLEAN ComInitialized = FALSE;
|
|
ULONG ulCount;
|
|
PROFILE("NhUpdateApplicationSettings");
|
|
|
|
EnterCriticalSection(&NhLock);
|
|
|
|
//
|
|
// Free old settings list
|
|
//
|
|
|
|
NhFreeApplicationSettings();
|
|
|
|
//
|
|
// Free DHCP reservation list
|
|
//
|
|
|
|
NhFreeDhcpReservations();
|
|
|
|
//
|
|
// Make sure COM is initialized on this thread
|
|
//
|
|
|
|
hr = CoInitializeEx(NULL, COINIT_MULTITHREADED | COINIT_DISABLE_OLE1DDE );
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
ComInitialized = TRUE;
|
|
}
|
|
else if (RPC_E_CHANGED_MODE == hr)
|
|
{
|
|
hr = S_OK;
|
|
}
|
|
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
//
|
|
// Get the IHNetCfgMgr pointer out of the GIT
|
|
//
|
|
|
|
hr = NhGetHNetCfgMgr(&pCfgMgr);
|
|
}
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
//
|
|
// Get the IHNetProtocolSettings interface
|
|
//
|
|
|
|
hr = pCfgMgr->QueryInterface(
|
|
IID_PPV_ARG(IHNetProtocolSettings, &pProtocolSettings)
|
|
);
|
|
}
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
//
|
|
// Get the enumeration of enabled application protocols
|
|
//
|
|
|
|
hr = pProtocolSettings->EnumApplicationProtocols(TRUE, &pEnumApps);
|
|
pProtocolSettings->Release();
|
|
}
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
//
|
|
// Process the items in the enum
|
|
//
|
|
|
|
do
|
|
{
|
|
IHNetApplicationProtocol *pAppProtocol;
|
|
|
|
hr = pEnumApps->Next(1, &pAppProtocol, &ulCount);
|
|
|
|
if (SUCCEEDED(hr) && 1 == ulCount)
|
|
{
|
|
//
|
|
// Allocate a new app entry
|
|
//
|
|
|
|
pAppEntry = reinterpret_cast<PNAT_APP_ENTRY>(
|
|
NH_ALLOCATE(sizeof(*pAppEntry))
|
|
);
|
|
|
|
if (NULL != pAppEntry)
|
|
{
|
|
ZeroMemory(pAppEntry, sizeof(*pAppEntry));
|
|
|
|
//
|
|
// Get protocol
|
|
//
|
|
|
|
hr = pAppProtocol->GetOutgoingIPProtocol(
|
|
&pAppEntry->Protocol
|
|
);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
//
|
|
// Get port
|
|
//
|
|
|
|
hr = pAppProtocol->GetOutgoingPort(
|
|
&pAppEntry->Port
|
|
);
|
|
}
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
//
|
|
// Get responses
|
|
//
|
|
|
|
hr = pAppProtocol->GetResponseRanges(
|
|
&pAppEntry->ResponseCount,
|
|
&pAppEntry->ResponseArray
|
|
);
|
|
}
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
//
|
|
// Add entry to list
|
|
//
|
|
|
|
InsertTailList(&NhApplicationSettingsList, &pAppEntry->Link);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Free entry
|
|
//
|
|
|
|
NH_FREE(pAppEntry);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
|
|
pAppProtocol->Release();
|
|
}
|
|
} while (SUCCEEDED(hr) && 1 == ulCount);
|
|
|
|
pEnumApps->Release();
|
|
}
|
|
|
|
//
|
|
// Build the DHCP reservation list
|
|
//
|
|
|
|
NhBuildDhcpReservations();
|
|
|
|
LeaveCriticalSection(&NhLock);
|
|
|
|
//
|
|
// Free config manager
|
|
//
|
|
|
|
if (NULL != pCfgMgr)
|
|
{
|
|
pCfgMgr->Release();
|
|
}
|
|
|
|
//
|
|
// Uninitialize COM
|
|
//
|
|
|
|
if (TRUE == ComInitialized)
|
|
{
|
|
CoUninitialize();
|
|
}
|
|
|
|
} // NhUpdateApplicationSettings
|
|
|
|
|
|
ULONG
|
|
APIENTRY
|
|
RegisterProtocol(
|
|
IN OUT PMPR_ROUTING_CHARACTERISTICS RoutingCharacteristics,
|
|
IN OUT PMPR_SERVICE_CHARACTERISTICS ServiceCharacteristics
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is invoked once for each protocol implemented in this module.
|
|
On each invocation, the supplied 'RoutingCharacteristics' indicates
|
|
the protocol to be registered in its 'dwProtocolId' field.
|
|
|
|
Arguments:
|
|
|
|
RoutingCharacteristics - on input, the protocol to be registered
|
|
and the router-manager's supported functionality.
|
|
|
|
ServiceCharacteristics - unused.
|
|
|
|
Return Value:
|
|
|
|
ULONG - status code.
|
|
|
|
--*/
|
|
|
|
{
|
|
if (RoutingCharacteristics->dwVersion < MS_ROUTER_VERSION) {
|
|
return ERROR_NOT_SUPPORTED;
|
|
}
|
|
|
|
if ((RoutingCharacteristics->fSupportedFunctionality &
|
|
(RF_ROUTING|RF_ADD_ALL_INTERFACES)) !=
|
|
(RF_ROUTING|RF_ADD_ALL_INTERFACES)) {
|
|
return ERROR_NOT_SUPPORTED;
|
|
}
|
|
|
|
switch (RoutingCharacteristics->dwProtocolId) {
|
|
|
|
case MS_IP_NAT: {
|
|
//
|
|
// Attempt to set the component into 'Connection Sharing' mode.
|
|
// This module implements both shared-access and connection-sharing
|
|
// which are mutually exclusive, so we need to ensure that
|
|
// shared-access is not operational before proceeding.
|
|
//
|
|
if (!NhSetComponentMode(NhRoutingProtocolMode)) {
|
|
return ERROR_CAN_NOT_COMPLETE;
|
|
}
|
|
CopyMemory(
|
|
RoutingCharacteristics,
|
|
&NatRoutingCharacteristics,
|
|
sizeof(NatRoutingCharacteristics)
|
|
);
|
|
RoutingCharacteristics->fSupportedFunctionality = RF_ROUTING;
|
|
break;
|
|
}
|
|
|
|
case MS_IP_DNS_PROXY: {
|
|
CopyMemory(
|
|
RoutingCharacteristics,
|
|
&DnsRoutingCharacteristics,
|
|
sizeof(DnsRoutingCharacteristics)
|
|
);
|
|
RoutingCharacteristics->fSupportedFunctionality =
|
|
(RF_ROUTING|RF_ADD_ALL_INTERFACES);
|
|
break;
|
|
}
|
|
|
|
case MS_IP_DHCP_ALLOCATOR: {
|
|
CopyMemory(
|
|
RoutingCharacteristics,
|
|
&DhcpRoutingCharacteristics,
|
|
sizeof(DhcpRoutingCharacteristics)
|
|
);
|
|
RoutingCharacteristics->fSupportedFunctionality =
|
|
(RF_ROUTING|RF_ADD_ALL_INTERFACES);
|
|
break;
|
|
}
|
|
|
|
case MS_IP_ALG: {
|
|
CopyMemory(
|
|
RoutingCharacteristics,
|
|
&AlgRoutingCharacteristics,
|
|
sizeof(AlgRoutingCharacteristics)
|
|
);
|
|
RoutingCharacteristics->fSupportedFunctionality =
|
|
(RF_ROUTING|RF_ADD_ALL_INTERFACES);
|
|
break;
|
|
}
|
|
|
|
case MS_IP_H323: {
|
|
CopyMemory(
|
|
RoutingCharacteristics,
|
|
&H323RoutingCharacteristics,
|
|
sizeof(H323RoutingCharacteristics)
|
|
);
|
|
RoutingCharacteristics->fSupportedFunctionality =
|
|
(RF_ROUTING|RF_ADD_ALL_INTERFACES);
|
|
break;
|
|
}
|
|
|
|
default: {
|
|
return ERROR_NOT_SUPPORTED;
|
|
}
|
|
}
|
|
|
|
ServiceCharacteristics->mscMpr40ServiceChars.fSupportedFunctionality = 0;
|
|
|
|
return NO_ERROR;
|
|
|
|
} // RegisterProtocol
|
|
|