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
|