1213 lines
25 KiB
C
1213 lines
25 KiB
C
/*++
|
||
|
||
Copyright (c) 1997 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
entry.c
|
||
|
||
Abstract:
|
||
|
||
This module contains the entry-code for the IP Network Address Translator.
|
||
|
||
Author:
|
||
|
||
Abolade Gbadegesin (t-abolag) 11-July-1997
|
||
|
||
Revision History:
|
||
|
||
William Ingle (billi) 12-May-2001 NULL security descriptor check
|
||
|
||
--*/
|
||
|
||
#include "precomp.h"
|
||
#pragma hdrstop
|
||
|
||
|
||
//
|
||
// GLOBAL DATA DEFINITIONS
|
||
//
|
||
|
||
COMPONENT_REFERENCE ComponentReference;
|
||
|
||
//
|
||
// Win32 device-name
|
||
//
|
||
|
||
WCHAR ExternalName[] = L"\\DosDevices\\IPNAT";
|
||
|
||
//
|
||
// Device- and file-object for the IP driver
|
||
//
|
||
|
||
extern PDEVICE_OBJECT IpDeviceObject = NULL;
|
||
extern PFILE_OBJECT IpFileObject = NULL;
|
||
extern HANDLE TcpDeviceHandle = NULL;
|
||
|
||
//
|
||
// Device-object for the NAT driver
|
||
//
|
||
|
||
extern PDEVICE_OBJECT NatDeviceObject = NULL;
|
||
|
||
//
|
||
// Registry parameters key name
|
||
//
|
||
|
||
WCHAR ParametersName[] = L"Parameters";
|
||
|
||
//
|
||
// Name of value holding reserved ports
|
||
//
|
||
|
||
WCHAR ReservedPortsName[] = L"ReservedPorts";
|
||
|
||
//
|
||
// Start and end of reserved-port range
|
||
//
|
||
|
||
USHORT ReservedPortsLowerRange = DEFAULT_START_PORT;
|
||
USHORT ReservedPortsUpperRange = DEFAULT_END_PORT;
|
||
|
||
//
|
||
// Device- and file-object for the TCP driver
|
||
//
|
||
|
||
extern PDEVICE_OBJECT TcpDeviceObject = NULL;
|
||
extern PFILE_OBJECT TcpFileObject = NULL;
|
||
|
||
//
|
||
// Registry path for the driver's parameters
|
||
//
|
||
|
||
const WCHAR IpNatParametersPath[] =
|
||
L"\\Registry\\Machine\\System\\CurrentControlSet\\Services"
|
||
L"\\IpNat\\Parameters";
|
||
|
||
//
|
||
// Timeout interval for TCP session mappings
|
||
//
|
||
|
||
ULONG TcpTimeoutSeconds = DEFAULT_TCP_TIMEOUT;
|
||
|
||
//
|
||
// Bitmap of enabled tracing message classes
|
||
//
|
||
|
||
ULONG TraceClassesEnabled = 0;
|
||
|
||
//
|
||
// Registry trace-class value name
|
||
//
|
||
|
||
WCHAR TraceClassesEnabledName[] = L"TraceClassesEnabled";
|
||
|
||
//
|
||
// Timeout interval for UDP and other message-oriented session mappings
|
||
//
|
||
|
||
ULONG UdpTimeoutSeconds = DEFAULT_UDP_TIMEOUT;
|
||
|
||
#if NAT_WMI
|
||
//
|
||
// Copy of our registry path for WMI use.
|
||
//
|
||
|
||
UNICODE_STRING NatRegistryPath;
|
||
#endif
|
||
|
||
//
|
||
// Name of value for allowing inbound non-unicast
|
||
//
|
||
|
||
WCHAR AllowInboundNonUnicastTrafficName[] = L"AllowInboundNonUnicastTraffic";
|
||
|
||
|
||
//
|
||
// If true, non-unicast traffic will not be dropped
|
||
// when recevied on a firewalled interface.
|
||
//
|
||
|
||
BOOLEAN AllowInboundNonUnicastTraffic = FALSE;
|
||
|
||
|
||
//
|
||
// FUNCTION PROTOTYPES (alphabetically)
|
||
//
|
||
|
||
NTSTATUS
|
||
DriverEntry(
|
||
IN PDRIVER_OBJECT DriverObject,
|
||
IN PUNICODE_STRING RegistryPath
|
||
);
|
||
|
||
NTSTATUS
|
||
NatAdjustSecurityDescriptor(
|
||
VOID
|
||
);
|
||
|
||
VOID
|
||
NatCleanupDriver(
|
||
VOID
|
||
);
|
||
|
||
VOID
|
||
NatCreateExternalNaming(
|
||
IN PUNICODE_STRING DeviceString
|
||
);
|
||
|
||
VOID
|
||
NatDeleteExternalNaming(
|
||
VOID
|
||
);
|
||
|
||
NTSTATUS
|
||
NatInitializeDriver(
|
||
VOID
|
||
);
|
||
|
||
NTSTATUS
|
||
NatSetFirewallHook(
|
||
BOOLEAN Install
|
||
);
|
||
|
||
VOID
|
||
NatUnloadDriver(
|
||
IN PDRIVER_OBJECT DriverObject
|
||
);
|
||
|
||
#ifdef ALLOC_PRAGMA
|
||
#pragma alloc_text(INIT, DriverEntry)
|
||
#pragma alloc_text(INIT, NatAdjustSecurityDescriptor)
|
||
#pragma alloc_text(PAGE, NatCreateExternalNaming)
|
||
#pragma alloc_text(PAGE, NatDeleteExternalNaming)
|
||
#endif
|
||
|
||
|
||
NTSTATUS
|
||
DriverEntry(
|
||
IN PDRIVER_OBJECT DriverObject,
|
||
IN PUNICODE_STRING RegistryPath
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Performs driver-initialization for NAT.
|
||
|
||
Arguments:
|
||
|
||
Return Value:
|
||
|
||
STATUS_SUCCESS if initialization succeeded, error code otherwise.
|
||
|
||
--*/
|
||
|
||
{
|
||
WCHAR DeviceName[] = DD_IP_NAT_DEVICE_NAME;
|
||
UNICODE_STRING DeviceString;
|
||
LONG i;
|
||
OBJECT_ATTRIBUTES ObjectAttributes;
|
||
HANDLE ParametersKey;
|
||
HANDLE ServiceKey;
|
||
NTSTATUS status;
|
||
UNICODE_STRING String;
|
||
|
||
PAGED_CODE();
|
||
|
||
CALLTRACE(("DriverEntry\n"));
|
||
|
||
#if DBG
|
||
//
|
||
// Open the registry key
|
||
//
|
||
InitializeObjectAttributes(
|
||
&ObjectAttributes,
|
||
RegistryPath,
|
||
OBJ_CASE_INSENSITIVE,
|
||
NULL,
|
||
NULL
|
||
);
|
||
status = ZwOpenKey(&ServiceKey, KEY_READ, &ObjectAttributes);
|
||
if (NT_SUCCESS(status)) {
|
||
RtlInitUnicodeString(&String, ParametersName);
|
||
InitializeObjectAttributes(
|
||
&ObjectAttributes,
|
||
&String,
|
||
OBJ_CASE_INSENSITIVE,
|
||
ServiceKey,
|
||
NULL
|
||
);
|
||
status = ZwOpenKey(&ParametersKey, KEY_READ, &ObjectAttributes);
|
||
ZwClose(ServiceKey);
|
||
if (NT_SUCCESS(status)) {
|
||
UCHAR Buffer[32];
|
||
ULONG BytesRead;
|
||
PKEY_VALUE_PARTIAL_INFORMATION Value;
|
||
RtlInitUnicodeString(&String, TraceClassesEnabledName);
|
||
status =
|
||
ZwQueryValueKey(
|
||
ParametersKey,
|
||
&String,
|
||
KeyValuePartialInformation,
|
||
(PKEY_VALUE_PARTIAL_INFORMATION)Buffer,
|
||
sizeof(Buffer),
|
||
&BytesRead
|
||
);
|
||
ZwClose(ParametersKey);
|
||
if (NT_SUCCESS(status) &&
|
||
((PKEY_VALUE_PARTIAL_INFORMATION)Buffer)->Type == REG_DWORD) {
|
||
TraceClassesEnabled =
|
||
*(PULONG)((PKEY_VALUE_PARTIAL_INFORMATION)Buffer)->Data;
|
||
}
|
||
}
|
||
}
|
||
#endif
|
||
|
||
#if NAT_WMI
|
||
|
||
//
|
||
// Record our registry path for WMI use
|
||
//
|
||
|
||
NatRegistryPath.Length = 0;
|
||
NatRegistryPath.MaximumLength
|
||
= RegistryPath->MaximumLength + sizeof( UNICODE_NULL );
|
||
NatRegistryPath.Buffer = ExAllocatePoolWithTag(
|
||
PagedPool,
|
||
NatRegistryPath.MaximumLength,
|
||
NAT_TAG_WMI
|
||
);
|
||
|
||
if( NatRegistryPath.Buffer )
|
||
{
|
||
RtlCopyUnicodeString( &NatRegistryPath, RegistryPath );
|
||
}
|
||
else
|
||
{
|
||
ERROR(("NAT: Unable to allocate string for RegistryPath\n"));
|
||
return STATUS_NO_MEMORY;
|
||
}
|
||
#endif
|
||
|
||
//
|
||
// Create the device's object.
|
||
//
|
||
|
||
RtlInitUnicodeString(&DeviceString, DeviceName);
|
||
|
||
status =
|
||
IoCreateDevice(
|
||
DriverObject,
|
||
0,
|
||
&DeviceString,
|
||
FILE_DEVICE_NETWORK,
|
||
FILE_DEVICE_SECURE_OPEN,
|
||
FALSE,
|
||
&NatDeviceObject
|
||
);
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
ERROR(("IoCreateDevice failed (0x%08X)\n", status));
|
||
return status;
|
||
}
|
||
|
||
//
|
||
// Adjust the security descriptor on the device object.
|
||
//
|
||
|
||
status = NatAdjustSecurityDescriptor();
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
ERROR(("NatAdjustSecurityDescriptor failed (0x%08x)\n", status));
|
||
return status;
|
||
}
|
||
|
||
//
|
||
// Initialize file-object tracking items
|
||
//
|
||
|
||
KeInitializeSpinLock(&NatFileObjectLock);
|
||
NatOwnerProcessId = NULL;
|
||
NatFileObjectCount = 0;
|
||
|
||
//
|
||
// Setup the driver object
|
||
//
|
||
|
||
DriverObject->DriverUnload = NatUnloadDriver;
|
||
DriverObject->FastIoDispatch = &NatFastIoDispatch;
|
||
DriverObject->DriverStartIo = NULL;
|
||
|
||
for (i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++) {
|
||
DriverObject->MajorFunction[i] = NatDispatch;
|
||
}
|
||
|
||
//
|
||
// Create a Win32-accessible device object
|
||
//
|
||
|
||
NatCreateExternalNaming(&DeviceString);
|
||
|
||
//
|
||
// Initialize the driver's structures
|
||
//
|
||
|
||
status = NatInitializeDriver();
|
||
|
||
return status;
|
||
|
||
} // DriverEntry
|
||
|
||
|
||
NTSTATUS
|
||
NatAdjustSecurityDescriptor(
|
||
VOID
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Modifies the security descriptor on the NAT's device object so
|
||
that only SYSTEM has any permissions.
|
||
|
||
Arguments:
|
||
|
||
none.
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS - success/error code.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
PACE_HEADER AceHeader;
|
||
PSID AceSid;
|
||
PACL Dacl;
|
||
BOOLEAN DaclDefaulted;
|
||
BOOLEAN DaclPresent;
|
||
DWORD i;
|
||
BOOLEAN MemoryAllocated;
|
||
PSECURITY_DESCRIPTOR NatSD = NULL;
|
||
PACL NewDacl = NULL;
|
||
SECURITY_DESCRIPTOR NewSD;
|
||
SECURITY_INFORMATION SecurityInformation;
|
||
ULONG Size;
|
||
NTSTATUS status;
|
||
|
||
do
|
||
{
|
||
//
|
||
// Get our original security descriptor
|
||
//
|
||
|
||
status =
|
||
ObGetObjectSecurity(
|
||
NatDeviceObject,
|
||
&NatSD,
|
||
&MemoryAllocated
|
||
);
|
||
|
||
// ObGetObjectSecurity can return a NULL security descriptor
|
||
// even with NT_SUCCESS status code
|
||
if (!NT_SUCCESS(status) || (NULL==NatSD)) {
|
||
break;
|
||
}
|
||
|
||
//
|
||
// Obtain the Dacl from the security descriptor
|
||
//
|
||
|
||
status =
|
||
RtlGetDaclSecurityDescriptor(
|
||
NatSD,
|
||
&DaclPresent,
|
||
&Dacl,
|
||
&DaclDefaulted
|
||
);
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
break;
|
||
}
|
||
|
||
ASSERT(FALSE != DaclPresent);
|
||
|
||
//
|
||
// Make a copy of the Dacl so that we can modify it.
|
||
//
|
||
|
||
NewDacl =
|
||
ExAllocatePoolWithTag(
|
||
PagedPool,
|
||
Dacl->AclSize,
|
||
NAT_TAG_SD
|
||
);
|
||
|
||
if (NULL == NewDacl) {
|
||
status = STATUS_NO_MEMORY;
|
||
break;
|
||
}
|
||
|
||
RtlCopyMemory(NewDacl, Dacl, Dacl->AclSize);
|
||
|
||
//
|
||
// Loop through the DACL, removing any access allowed
|
||
// entries that aren't for SYSTEM
|
||
//
|
||
|
||
for (i = 0; i < NewDacl->AceCount; i++) {
|
||
|
||
status = RtlGetAce(NewDacl, i, &AceHeader);
|
||
|
||
if (NT_SUCCESS(status)) {
|
||
|
||
if (ACCESS_ALLOWED_ACE_TYPE == AceHeader->AceType) {
|
||
|
||
AceSid = (PSID) &((ACCESS_ALLOWED_ACE*)AceHeader)->SidStart;
|
||
|
||
if (!RtlEqualSid(AceSid, SeExports->SeLocalSystemSid)) {
|
||
|
||
status = RtlDeleteAce(NewDacl, i);
|
||
if (NT_SUCCESS(status)) {
|
||
i -= 1;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
ASSERT(NewDacl->AceCount > 0);
|
||
|
||
//
|
||
// Create a new security descriptor to hold the new Dacl.
|
||
//
|
||
|
||
status =
|
||
RtlCreateSecurityDescriptor(
|
||
&NewSD,
|
||
SECURITY_DESCRIPTOR_REVISION
|
||
);
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
break;
|
||
}
|
||
|
||
//
|
||
// Place the new Dacl into the new SD
|
||
//
|
||
|
||
status =
|
||
RtlSetDaclSecurityDescriptor(
|
||
&NewSD,
|
||
TRUE,
|
||
NewDacl,
|
||
FALSE
|
||
);
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
break;
|
||
}
|
||
|
||
//
|
||
// Set the new SD into our device object. Only the Dacl from the
|
||
// SD will be set.
|
||
//
|
||
|
||
SecurityInformation = DACL_SECURITY_INFORMATION;
|
||
status =
|
||
ObSetSecurityObjectByPointer(
|
||
NatDeviceObject,
|
||
SecurityInformation,
|
||
&NewSD
|
||
);
|
||
|
||
} while (FALSE);
|
||
|
||
if (NULL != NatSD) {
|
||
ObReleaseObjectSecurity(NatSD, MemoryAllocated);
|
||
}
|
||
|
||
if (NULL != NewDacl) {
|
||
ExFreePool(NewDacl);
|
||
}
|
||
|
||
return status;
|
||
|
||
} // NatAdjustSecurityDescriptor
|
||
|
||
|
||
VOID
|
||
NatCleanupDriver(
|
||
VOID
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is invoked when the last reference to the NAT driver
|
||
is released.
|
||
|
||
Arguments:
|
||
|
||
none.
|
||
|
||
Return Value:
|
||
|
||
none.
|
||
|
||
--*/
|
||
|
||
{
|
||
CALLTRACE(("NatCleanupDriver\n"));
|
||
|
||
} // NatCleanupDriver
|
||
|
||
|
||
VOID
|
||
NatCreateExternalNaming(
|
||
IN PUNICODE_STRING DeviceString
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Creates a symbolic-link to the NAT's device-object so
|
||
the NAT can be opened by a user-mode process.
|
||
|
||
Arguments:
|
||
|
||
DeviceString - Unicode name of the NAT's device-object.
|
||
|
||
Return Value:
|
||
|
||
none.
|
||
|
||
--*/
|
||
|
||
{
|
||
UNICODE_STRING symLinkString;
|
||
PAGED_CODE();
|
||
RtlInitUnicodeString(&symLinkString, ExternalName);
|
||
IoCreateSymbolicLink(&symLinkString, DeviceString);
|
||
|
||
} // NatCreateExternalNaming
|
||
|
||
|
||
VOID
|
||
NatDeleteExternalNaming(
|
||
VOID
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Deletes the Win32 symbolic-link to the NAT's device-object
|
||
|
||
Arguments:
|
||
|
||
Return Value:
|
||
|
||
none.
|
||
|
||
--*/
|
||
|
||
{
|
||
UNICODE_STRING symLinkString;
|
||
PAGED_CODE();
|
||
RtlInitUnicodeString(&symLinkString, ExternalName);
|
||
IoDeleteSymbolicLink(&symLinkString);
|
||
|
||
} // NatDeleteExternalNaming
|
||
|
||
|
||
|
||
NTSTATUS
|
||
NatInitializeDriver(
|
||
VOID
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Performs initialization of the driver's structures.
|
||
|
||
Arguments:
|
||
|
||
none.
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS - success/error code.
|
||
|
||
--*/
|
||
|
||
{
|
||
OBJECT_ATTRIBUTES ObjectAttributes;
|
||
HANDLE ParametersKey;
|
||
NTSTATUS status;
|
||
NTSTATUS status2;
|
||
UNICODE_STRING UnicodeString;
|
||
IO_STATUS_BLOCK IoStatus;
|
||
|
||
CALLTRACE(("NatInitializeDriver\n"));
|
||
|
||
//
|
||
// Set up global synchronization objects
|
||
//
|
||
|
||
InitializeComponentReference(&ComponentReference, NatCleanupDriver);
|
||
|
||
//
|
||
// Obtain the IP and TCP driver device-objects
|
||
//
|
||
|
||
RtlInitUnicodeString(&UnicodeString, DD_IP_DEVICE_NAME);
|
||
status =
|
||
IoGetDeviceObjectPointer(
|
||
&UnicodeString,
|
||
SYNCHRONIZE|GENERIC_READ|GENERIC_WRITE,
|
||
&IpFileObject,
|
||
&IpDeviceObject
|
||
);
|
||
if (!NT_SUCCESS(status)) {
|
||
ERROR(("NatInitializeDriver: error %X getting IP object\n", status));
|
||
return status;
|
||
}
|
||
|
||
RtlInitUnicodeString(&UnicodeString, DD_TCP_DEVICE_NAME);
|
||
status =
|
||
IoGetDeviceObjectPointer(
|
||
&UnicodeString,
|
||
SYNCHRONIZE|GENERIC_READ|GENERIC_WRITE,
|
||
&TcpFileObject,
|
||
&TcpDeviceObject
|
||
);
|
||
if (!NT_SUCCESS(status)) {
|
||
ERROR(("NatInitializeDriver: error %X getting TCP object\n", status));
|
||
return status;
|
||
}
|
||
|
||
//
|
||
// Open Tcp Kernel Device
|
||
//
|
||
InitializeObjectAttributes(
|
||
&ObjectAttributes,
|
||
&UnicodeString,
|
||
OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
|
||
NULL,
|
||
NULL);
|
||
|
||
status =
|
||
ZwCreateFile(
|
||
&TcpDeviceHandle,
|
||
GENERIC_READ,
|
||
&ObjectAttributes,
|
||
&IoStatus,
|
||
NULL,
|
||
FILE_ATTRIBUTE_NORMAL,
|
||
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||
FILE_OPEN_IF,
|
||
0,
|
||
NULL,
|
||
0);
|
||
|
||
if ( !NT_SUCCESS(status) )
|
||
{
|
||
ERROR(("ZwCreateFile failed (0x%08X)\n", status));
|
||
}
|
||
|
||
ObReferenceObject(IpDeviceObject);
|
||
ObReferenceObject(TcpDeviceObject);
|
||
|
||
//
|
||
// Initialize all object-modules
|
||
//
|
||
|
||
NatInitializeTimerManagement();
|
||
NatInitializeMappingManagement();
|
||
NatInitializeDirectorManagement();
|
||
NatInitializeEditorManagement();
|
||
NatInitializeRedirectManagement();
|
||
NatInitializeDynamicTicketManagement();
|
||
NatInitializeIcmpManagement();
|
||
NatInitializeRawIpManagement();
|
||
NatInitializeInterfaceManagement();
|
||
#if 0
|
||
status = NatInitializeAddressManagement();
|
||
if (!NT_SUCCESS(status)) { return status; }
|
||
#endif
|
||
NatInitializePacketManagement();
|
||
NatInitializeNotificationManagement();
|
||
|
||
#if NAT_WMI
|
||
NatInitializeWMI();
|
||
#endif
|
||
|
||
//
|
||
// Initialize NAT-provided editors.
|
||
//
|
||
|
||
status = NatInitializePptpManagement();
|
||
if (!NT_SUCCESS(status)) { return status; }
|
||
|
||
//
|
||
// Commence translation of packets, and start the periodic timer.
|
||
//
|
||
|
||
status = NatInitiateTranslation();
|
||
|
||
//
|
||
// Read optional registry settings.
|
||
// The user may customize the range of ports used by modifying
|
||
// the reserved-ports setting in the registry.
|
||
// We now check to see if there is such a value,
|
||
// and if so, we use it as our reserved-port range.
|
||
//
|
||
// The user may also specify that inbound non-unicast traffic
|
||
// is allowed on a firewalled interface.
|
||
//
|
||
//
|
||
// N.B. Failures here are not returned to the caller.
|
||
//
|
||
|
||
RtlInitUnicodeString(&UnicodeString, IpNatParametersPath);
|
||
InitializeObjectAttributes(
|
||
&ObjectAttributes,
|
||
&UnicodeString,
|
||
OBJ_CASE_INSENSITIVE,
|
||
NULL,
|
||
NULL
|
||
);
|
||
|
||
status2 = ZwOpenKey(&ParametersKey, KEY_READ, &ObjectAttributes);
|
||
|
||
if (NT_SUCCESS(status2)) {
|
||
|
||
UCHAR Buffer[sizeof(KEY_VALUE_PARTIAL_INFORMATION)];
|
||
ULONG EndPort;
|
||
PWCHAR p;
|
||
ULONG StartPort;
|
||
PKEY_VALUE_PARTIAL_INFORMATION Value = NULL;
|
||
ULONG ValueLength;
|
||
|
||
//
|
||
// First check for allowed non-unicast traffic.
|
||
//
|
||
|
||
RtlInitUnicodeString(
|
||
&UnicodeString,
|
||
AllowInboundNonUnicastTrafficName
|
||
);
|
||
|
||
status2 =
|
||
ZwQueryValueKey(
|
||
ParametersKey,
|
||
&UnicodeString,
|
||
KeyValuePartialInformation,
|
||
(PKEY_VALUE_PARTIAL_INFORMATION)Buffer,
|
||
sizeof(Buffer),
|
||
&ValueLength
|
||
);
|
||
|
||
if (NT_SUCCESS(status2)
|
||
&& REG_DWORD == ((PKEY_VALUE_PARTIAL_INFORMATION)Buffer)->Type) {
|
||
|
||
AllowInboundNonUnicastTraffic =
|
||
1 == *((PULONG)((PKEY_VALUE_PARTIAL_INFORMATION)Buffer)->Data);
|
||
}
|
||
|
||
//
|
||
// Check for reserved ports
|
||
//
|
||
|
||
|
||
do {
|
||
|
||
RtlInitUnicodeString(&UnicodeString, ReservedPortsName);
|
||
|
||
status2 =
|
||
ZwQueryValueKey(
|
||
ParametersKey,
|
||
&UnicodeString,
|
||
KeyValuePartialInformation,
|
||
(PKEY_VALUE_PARTIAL_INFORMATION)Buffer,
|
||
sizeof(Buffer),
|
||
&ValueLength
|
||
);
|
||
if (status2 != STATUS_BUFFER_OVERFLOW) { break; }
|
||
|
||
Value =
|
||
(PKEY_VALUE_PARTIAL_INFORMATION)
|
||
ExAllocatePoolWithTag(
|
||
PagedPool, ValueLength, NAT_TAG_RANGE_ARRAY
|
||
);
|
||
if (!Value) { break; }
|
||
|
||
status2 =
|
||
ZwQueryValueKey(
|
||
ParametersKey,
|
||
&UnicodeString,
|
||
KeyValuePartialInformation,
|
||
(PKEY_VALUE_PARTIAL_INFORMATION)Value,
|
||
ValueLength,
|
||
&ValueLength
|
||
);
|
||
if (!NT_SUCCESS(status2)) { break; }
|
||
|
||
//
|
||
// The value should be in the format "xxx-yyy\0\0";
|
||
// read the first number
|
||
//
|
||
|
||
p = (PWCHAR)Value->Data;
|
||
RtlInitUnicodeString(&UnicodeString, p);
|
||
status2 = RtlUnicodeStringToInteger(&UnicodeString, 10, &StartPort);
|
||
if (!NT_SUCCESS(status2)) { break; }
|
||
|
||
//
|
||
// Advance past '-'
|
||
//
|
||
|
||
while (*p && *p != L'-') { ++p; }
|
||
if (*p != L'-') { break; } else { ++p; }
|
||
|
||
//
|
||
// Read second number
|
||
//
|
||
|
||
RtlInitUnicodeString(&UnicodeString, p);
|
||
status2 = RtlUnicodeStringToInteger(&UnicodeString, 10, &EndPort);
|
||
if (!NT_SUCCESS(status2)) { break; }
|
||
|
||
//
|
||
// Validate the resulting range
|
||
//
|
||
|
||
if (StartPort > 0 &&
|
||
StartPort < 65535 &&
|
||
EndPort > 0 &&
|
||
EndPort < 65535 &&
|
||
StartPort <= EndPort
|
||
) {
|
||
ReservedPortsLowerRange = NTOHS((USHORT)StartPort);
|
||
ReservedPortsUpperRange = NTOHS((USHORT)EndPort);
|
||
}
|
||
|
||
} while(FALSE);
|
||
|
||
if (Value) { ExFreePool(Value); }
|
||
ZwClose(ParametersKey);
|
||
}
|
||
|
||
return status;
|
||
|
||
} // NatInitializeDriver
|
||
|
||
|
||
|
||
NTSTATUS
|
||
NatInitiateTranslation(
|
||
VOID
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is invoked on creation of the first interface,
|
||
to launch the periodic timer and install the firewall hook.
|
||
|
||
Arguments:
|
||
|
||
none.
|
||
|
||
Return Value:
|
||
|
||
STATUS_SUCCESS if successful, error code otherwise.
|
||
|
||
--*/
|
||
|
||
{
|
||
CALLTRACE(("NatInitiateTranslation\n"));
|
||
|
||
//
|
||
// Launch the timer
|
||
//
|
||
|
||
NatStartTimer();
|
||
|
||
//
|
||
// Install 'NatTranslate' as the firewall hook
|
||
//
|
||
|
||
return NatSetFirewallHook(TRUE);
|
||
|
||
} // NatInitiateTranslation
|
||
|
||
|
||
NTSTATUS
|
||
NatSetFirewallHook(
|
||
BOOLEAN Install
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is called to set (Install==TRUE) or clear (Install==FALSE) the
|
||
value of the firewall-callout function pointer in the IP driver.
|
||
|
||
Arguments:
|
||
|
||
Install - indicates whether to install or remove the hook.
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS - indicates success/failure
|
||
|
||
Environment:
|
||
|
||
The routine assumes the caller is executing at PASSIVE_LEVEL.
|
||
|
||
--*/
|
||
|
||
{
|
||
IP_SET_FIREWALL_HOOK_INFO HookInfo;
|
||
IO_STATUS_BLOCK IoStatus;
|
||
PIRP Irp;
|
||
TCP_RESERVE_PORT_RANGE PortRange;
|
||
KEVENT LocalEvent;
|
||
NTSTATUS status;
|
||
|
||
CALLTRACE(("NatSetFirewallHook\n"));
|
||
|
||
//
|
||
// Register (or deregister) as a firewall
|
||
//
|
||
|
||
HookInfo.FirewallPtr = (IPPacketFirewallPtr)NatTranslatePacket;
|
||
HookInfo.Priority = 1;
|
||
HookInfo.Add = Install;
|
||
|
||
KeInitializeEvent(&LocalEvent, SynchronizationEvent, FALSE);
|
||
Irp =
|
||
IoBuildDeviceIoControlRequest(
|
||
IOCTL_IP_SET_FIREWALL_HOOK,
|
||
IpDeviceObject,
|
||
(PVOID)&HookInfo,
|
||
sizeof(HookInfo),
|
||
NULL,
|
||
0,
|
||
FALSE,
|
||
&LocalEvent,
|
||
&IoStatus
|
||
);
|
||
|
||
if (!Irp) {
|
||
ERROR(("NatSetFirewallHook: IoBuildDeviceIoControlRequest=0\n"));
|
||
return STATUS_UNSUCCESSFUL;
|
||
}
|
||
|
||
status = IoCallDriver(IpDeviceObject, Irp);
|
||
if (status == STATUS_PENDING) {
|
||
KeWaitForSingleObject(&LocalEvent, Executive, KernelMode, FALSE, NULL);
|
||
status = IoStatus.Status;
|
||
}
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
ERROR(("NatSetFirewallHook: IpSetFirewallHook=0x%08X\n", status));
|
||
return status;
|
||
}
|
||
|
||
if (ReservedPortsLowerRange != DEFAULT_START_PORT ||
|
||
ReservedPortsUpperRange != DEFAULT_END_PORT
|
||
) {
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
//
|
||
// Reserve (or unreserve) our port-range
|
||
//
|
||
// N.B. The IOCTL expects host-order numbers and we store the range
|
||
// in network order, so do a swap before reserving the ports.
|
||
//
|
||
|
||
PortRange.LowerRange = NTOHS(DEFAULT_START_PORT);
|
||
PortRange.UpperRange = NTOHS(DEFAULT_END_PORT);
|
||
Irp =
|
||
IoBuildDeviceIoControlRequest(
|
||
Install
|
||
? IOCTL_TCP_RESERVE_PORT_RANGE
|
||
: IOCTL_TCP_UNRESERVE_PORT_RANGE,
|
||
TcpDeviceObject,
|
||
(PVOID)&PortRange,
|
||
sizeof(PortRange),
|
||
NULL,
|
||
0,
|
||
FALSE,
|
||
&LocalEvent,
|
||
&IoStatus
|
||
);
|
||
if (!Irp) {
|
||
ERROR(("NatSetFirewallHook: IoBuildDeviceIoControlRequest(2)=0\n"));
|
||
return STATUS_UNSUCCESSFUL;
|
||
}
|
||
|
||
status = IoCallDriver(TcpDeviceObject, Irp);
|
||
if (status == STATUS_PENDING) {
|
||
KeWaitForSingleObject(&LocalEvent, Executive, KernelMode, FALSE, NULL);
|
||
status = IoStatus.Status;
|
||
}
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
ERROR(("NatSetFirewallHook: Tcp(Un)ReservePortRange=0x%08X\n", status));
|
||
}
|
||
|
||
return status;
|
||
|
||
} // NatSetFirewallHook
|
||
|
||
|
||
VOID
|
||
NatTerminateTranslation(
|
||
VOID
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
On cleanup of the last interface, this routine is invoked
|
||
to stop the periodic timer and de-install the firewall hook.
|
||
|
||
|
||
Arguments:
|
||
|
||
none.
|
||
|
||
Return Value:
|
||
|
||
none.
|
||
|
||
--*/
|
||
|
||
{
|
||
CALLTRACE(("NatTerminateTranslation\n"));
|
||
NatSetFirewallHook(FALSE);
|
||
|
||
} // NatTerminateTranslation
|
||
|
||
|
||
VOID
|
||
NatUnloadDriver(
|
||
IN PDRIVER_OBJECT DriverObject
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Performs cleanup for the NAT.
|
||
|
||
Arguments:
|
||
|
||
DriverObject - reference to the NAT's driver-object
|
||
|
||
Return Value:
|
||
|
||
--*/
|
||
|
||
{
|
||
PNAT_EDITOR Editor;
|
||
PLIST_ENTRY List;
|
||
|
||
CALLTRACE(("NatUnloadDriver\n"));
|
||
|
||
//
|
||
// Stop translation and clear the periodic timer
|
||
//
|
||
|
||
NatTerminateTranslation();
|
||
|
||
//
|
||
// Stop the route-change-notification in our packet-management and
|
||
// address-management modules.
|
||
// This forces completion of the route-change and address-change IRPs,
|
||
// which in turn releases component-references which would otherwise not
|
||
// drop until a route-change and address-change occurred.
|
||
//
|
||
|
||
NatShutdownNotificationManagement();
|
||
NatShutdownPacketManagement();
|
||
#if 0
|
||
NatShutdownAddressManagement();
|
||
#endif
|
||
|
||
//
|
||
// Drop our self-reference and wait for all activity to cease.
|
||
//
|
||
|
||
ReleaseInitialComponentReference(&ComponentReference, TRUE);
|
||
|
||
//
|
||
// Tear down our Win32-namespace symbolic link
|
||
//
|
||
|
||
NatDeleteExternalNaming();
|
||
|
||
//
|
||
// Delete the NAT's device object
|
||
//
|
||
|
||
IoDeleteDevice(DriverObject->DeviceObject);
|
||
|
||
//
|
||
// Shutdown object modules
|
||
//
|
||
|
||
#if NAT_WMI
|
||
NatShutdownWMI();
|
||
|
||
if( NatRegistryPath.Buffer )
|
||
{
|
||
ExFreePool( NatRegistryPath.Buffer );
|
||
RtlInitUnicodeString( &NatRegistryPath, NULL );
|
||
}
|
||
#endif
|
||
|
||
NatShutdownPptpManagement();
|
||
NatShutdownTimerManagement();
|
||
NatShutdownMappingManagement();
|
||
NatShutdownEditorManagement();
|
||
NatShutdownDirectorManagement();
|
||
NatShutdownDynamicTicketManagement();
|
||
NatShutdownRawIpManagement();
|
||
NatShutdownIcmpManagement();
|
||
NatShutdownInterfaceManagement();
|
||
|
||
//
|
||
// Release references to the IP and TCP driver objects
|
||
//
|
||
|
||
ObDereferenceObject((PVOID)IpFileObject);
|
||
ObDereferenceObject(IpDeviceObject);
|
||
ObDereferenceObject((PVOID)TcpFileObject);
|
||
ObDereferenceObject(TcpDeviceObject);
|
||
|
||
if (TcpDeviceHandle) {
|
||
|
||
ZwClose(TcpDeviceHandle);
|
||
TcpDeviceHandle = NULL;
|
||
}
|
||
|
||
DeleteComponentReference(&ComponentReference);
|
||
|
||
} // NatUnloadDriver
|