mirror of https://github.com/tongzx/nt5src
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.
2143 lines
49 KiB
2143 lines
49 KiB
/*++
|
|
|
|
Copyright (c) 1998, Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
natio.h
|
|
|
|
Abstract:
|
|
|
|
This module contains declarations for the NAT's I/O interface
|
|
to the kernel-mode driver.
|
|
|
|
Author:
|
|
|
|
Abolade Gbadegesin (aboladeg) 10-Mar-1998
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "precomp.h"
|
|
#pragma hdrstop
|
|
#include <ras.h>
|
|
#include <rasuip.h>
|
|
#include <raserror.h>
|
|
|
|
//
|
|
// PRIVATE GLOBAL VARIABLES
|
|
//
|
|
|
|
HANDLE NatFileHandle;
|
|
LIST_ENTRY NatInterfaceList;
|
|
//
|
|
// Controls access to 'NatFileHandle' and 'NatInterfaceList'.
|
|
//
|
|
CRITICAL_SECTION NatInterfaceLock;
|
|
|
|
//
|
|
// FORWARD DECLARATIONS
|
|
//
|
|
|
|
VOID
|
|
NatpDisableLoadDriverPrivilege(
|
|
PBOOLEAN WasEnabled
|
|
);
|
|
|
|
BOOLEAN
|
|
NatpEnableLoadDriverPrivilege(
|
|
PBOOLEAN WasEnabled
|
|
);
|
|
|
|
PNAT_INTERFACE
|
|
NatpLookupInterface(
|
|
ULONG Index,
|
|
OUT PLIST_ENTRY* InsertionPoint OPTIONAL
|
|
);
|
|
|
|
|
|
ULONG
|
|
NatBindInterface(
|
|
ULONG Index,
|
|
PNAT_INTERFACE Interfacep OPTIONAL,
|
|
PIP_ADAPTER_BINDING_INFO BindingInfo,
|
|
ULONG AdapterIndex
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is invoked to bind the NAT to an interface.
|
|
|
|
Arguments:
|
|
|
|
Index - the interface to be bound
|
|
|
|
Interfacep - optionally supplies the interface-structure to be bound
|
|
(See 'NATCONN.C' which passes in a static interface-structure).
|
|
|
|
BindingInfo - the interface's address-information
|
|
|
|
AdapterIndex - optionally specifies the interface's TCP/IP adapter index.
|
|
This is set only for home-router interfaces.
|
|
|
|
Return Value:
|
|
|
|
ULONG - Win32 status code.
|
|
|
|
--*/
|
|
|
|
{
|
|
PIP_NAT_CREATE_INTERFACE CreateInterface;
|
|
ULONG Error;
|
|
IO_STATUS_BLOCK IoStatus;
|
|
ULONG Size;
|
|
NTSTATUS status;
|
|
HANDLE WaitEvent;
|
|
|
|
PROFILE("NatBindInterface");
|
|
|
|
Error = NO_ERROR;
|
|
|
|
//
|
|
// Look up the interface to be bound
|
|
//
|
|
|
|
EnterCriticalSection(&NatInterfaceLock);
|
|
if (!Interfacep && !(Interfacep = NatpLookupInterface(Index, NULL))) {
|
|
LeaveCriticalSection(&NatInterfaceLock);
|
|
NhTrace(
|
|
TRACE_FLAG_NAT,
|
|
"NatBindInterface: interface %d not found",
|
|
Index
|
|
);
|
|
return ERROR_NO_SUCH_INTERFACE;
|
|
}
|
|
|
|
//
|
|
// Make sure the interface isn't already bound
|
|
//
|
|
|
|
if (NAT_INTERFACE_BOUND(Interfacep)) {
|
|
LeaveCriticalSection(&NatInterfaceLock);
|
|
NhTrace(
|
|
TRACE_FLAG_NAT,
|
|
"NatBindInterface: interface %d is already bound",
|
|
Index
|
|
);
|
|
return ERROR_ADDRESS_ALREADY_ASSOCIATED;
|
|
}
|
|
|
|
//
|
|
// Allocate the bind-structure
|
|
//
|
|
|
|
Size =
|
|
sizeof(IP_NAT_CREATE_INTERFACE) +
|
|
SIZEOF_IP_BINDING(BindingInfo->AddressCount);
|
|
|
|
CreateInterface = reinterpret_cast<PIP_NAT_CREATE_INTERFACE>(
|
|
NH_ALLOCATE(Size));
|
|
|
|
if (!CreateInterface) {
|
|
LeaveCriticalSection(&NatInterfaceLock);
|
|
NhTrace(
|
|
TRACE_FLAG_NAT,
|
|
"NatBindInterface: allocation failed for interface %d binding",
|
|
Index
|
|
);
|
|
NhErrorLog(
|
|
IP_NAT_LOG_ALLOCATION_FAILED,
|
|
0,
|
|
"%d",
|
|
Size
|
|
);
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
Interfacep->AdapterIndex =
|
|
(AdapterIndex != (ULONG)-1)
|
|
? AdapterIndex
|
|
: NhMapInterfaceToAdapter(Interfacep->Index);
|
|
if (Interfacep->AdapterIndex == (ULONG)-1) {
|
|
LeaveCriticalSection(&NatInterfaceLock);
|
|
NhTrace(
|
|
TRACE_FLAG_NAT,
|
|
"NatBindInterface: NhMapInterfaceToAdapter failed for %d",
|
|
Index
|
|
);
|
|
return ERROR_INVALID_INDEX;
|
|
}
|
|
CreateInterface->Index = Interfacep->AdapterIndex;
|
|
CopyMemory(
|
|
CreateInterface->BindingInfo,
|
|
BindingInfo,
|
|
SIZEOF_IP_BINDING(BindingInfo->AddressCount)
|
|
);
|
|
|
|
WaitEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
|
|
if (WaitEvent == NULL) {
|
|
LeaveCriticalSection(&NatInterfaceLock);
|
|
NhTrace(
|
|
TRACE_FLAG_NAT,
|
|
"NatBindInterface: CreateEvent failed [%d] for interface %d",
|
|
GetLastError(),
|
|
Index
|
|
);
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
//
|
|
// Install the interface
|
|
//
|
|
|
|
status =
|
|
NtDeviceIoControlFile(
|
|
NatFileHandle,
|
|
WaitEvent,
|
|
NULL,
|
|
NULL,
|
|
&IoStatus,
|
|
IOCTL_IP_NAT_CREATE_INTERFACE,
|
|
(PVOID)CreateInterface,
|
|
Size,
|
|
NULL,
|
|
0
|
|
);
|
|
if (status == STATUS_PENDING) {
|
|
WaitForSingleObject(WaitEvent, INFINITE);
|
|
status = IoStatus.Status;
|
|
}
|
|
NH_FREE(CreateInterface);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
CloseHandle(WaitEvent);
|
|
LeaveCriticalSection(&NatInterfaceLock);
|
|
NhTrace(
|
|
TRACE_FLAG_NAT,
|
|
"NatBindInterface: status %08x binding interface %d",
|
|
status,
|
|
Index
|
|
);
|
|
Error = RtlNtStatusToDosError(status);
|
|
NhErrorLog(
|
|
IP_NAT_LOG_IOCTL_FAILED,
|
|
Error,
|
|
""
|
|
);
|
|
return Error;
|
|
}
|
|
|
|
//
|
|
// Now set its configuration
|
|
//
|
|
|
|
Interfacep->Info->Index = Interfacep->AdapterIndex;
|
|
Size =
|
|
FIELD_OFFSET(IP_NAT_INTERFACE_INFO, Header) +
|
|
Interfacep->Info->Header.Size;
|
|
|
|
status =
|
|
NtDeviceIoControlFile(
|
|
NatFileHandle,
|
|
WaitEvent,
|
|
NULL,
|
|
NULL,
|
|
&IoStatus,
|
|
IOCTL_IP_NAT_SET_INTERFACE_INFO,
|
|
(PVOID)Interfacep->Info,
|
|
Size,
|
|
NULL,
|
|
0
|
|
);
|
|
if (status == STATUS_PENDING) {
|
|
WaitForSingleObject(WaitEvent, INFINITE);
|
|
status = IoStatus.Status;
|
|
}
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
ULONG AdapterIndex = Interfacep->AdapterIndex;
|
|
LeaveCriticalSection(&NatInterfaceLock);
|
|
NhTrace(
|
|
TRACE_FLAG_NAT,
|
|
"NatBindInterface: status %08x setting info for interface %d (%d)",
|
|
status,
|
|
Index,
|
|
AdapterIndex
|
|
);
|
|
Error = RtlNtStatusToDosError(status);
|
|
NhErrorLog(
|
|
IP_NAT_LOG_IOCTL_FAILED,
|
|
Error,
|
|
""
|
|
);
|
|
status =
|
|
NtDeviceIoControlFile(
|
|
NatFileHandle,
|
|
WaitEvent,
|
|
NULL,
|
|
NULL,
|
|
&IoStatus,
|
|
IOCTL_IP_NAT_DELETE_INTERFACE,
|
|
(PVOID)&AdapterIndex,
|
|
sizeof(ULONG),
|
|
NULL,
|
|
0
|
|
);
|
|
if (status == STATUS_PENDING) {
|
|
WaitForSingleObject(WaitEvent, INFINITE);
|
|
status = IoStatus.Status;
|
|
}
|
|
CloseHandle(WaitEvent);
|
|
return Error;
|
|
}
|
|
|
|
Interfacep->Flags |= NAT_INTERFACE_FLAG_BOUND;
|
|
|
|
if (Interfacep->Type == ROUTER_IF_TYPE_DEDICATED) {
|
|
NatUpdateProxyArp(Interfacep, TRUE);
|
|
}
|
|
|
|
CloseHandle(WaitEvent);
|
|
|
|
LeaveCriticalSection(&NatInterfaceLock);
|
|
|
|
return Error;
|
|
|
|
} // NatBindInterface
|
|
|
|
|
|
ULONG
|
|
NatConfigureDriver(
|
|
PIP_NAT_GLOBAL_INFO GlobalInfo
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is called to update the configuration for the NAT driver.
|
|
|
|
Arguments:
|
|
|
|
GlobalInfo - the new configuration for the NAT.
|
|
|
|
Return Value:
|
|
|
|
ULONG - Win32 status code.
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONG Error = NO_ERROR;
|
|
IO_STATUS_BLOCK IoStatus;
|
|
NTSTATUS status;
|
|
HANDLE WaitEvent;
|
|
|
|
PROFILE("NatConfigureDriver");
|
|
|
|
WaitEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
|
|
if (WaitEvent == NULL) {
|
|
NhTrace(
|
|
TRACE_FLAG_NAT,
|
|
"NatConfigureDriver: CreateEvent failed [%d]",
|
|
GetLastError()
|
|
);
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
//
|
|
// Attempt to configure the driver
|
|
//
|
|
|
|
EnterCriticalSection(&NatInterfaceLock);
|
|
status =
|
|
NtDeviceIoControlFile(
|
|
NatFileHandle,
|
|
WaitEvent,
|
|
NULL,
|
|
NULL,
|
|
&IoStatus,
|
|
IOCTL_IP_NAT_SET_GLOBAL_INFO,
|
|
(PVOID)GlobalInfo,
|
|
FIELD_OFFSET(IP_NAT_GLOBAL_INFO, Header) + GlobalInfo->Header.Size,
|
|
NULL,
|
|
0
|
|
);
|
|
if (status == STATUS_PENDING) {
|
|
WaitForSingleObject(WaitEvent, INFINITE);
|
|
status = IoStatus.Status;
|
|
}
|
|
LeaveCriticalSection(&NatInterfaceLock);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
NhTrace(
|
|
TRACE_FLAG_NAT,
|
|
"NatConfigureDriver: status %08x setting global info",
|
|
status
|
|
);
|
|
Error = RtlNtStatusToDosError(status);
|
|
NhErrorLog(
|
|
IP_NAT_LOG_IOCTL_FAILED,
|
|
Error,
|
|
""
|
|
);
|
|
}
|
|
|
|
CloseHandle(WaitEvent);
|
|
|
|
return Error;
|
|
|
|
} // NatConfigureDriver
|
|
|
|
|
|
ULONG
|
|
NatConfigureInterface(
|
|
ULONG Index,
|
|
PIP_NAT_INTERFACE_INFO InterfaceInfo
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is invoked to set the configuration for a NAT interface.
|
|
|
|
Arguments:
|
|
|
|
Index - the interface to be configured
|
|
|
|
InterfaceInfo - the configuration for the interface
|
|
|
|
Return Value:
|
|
|
|
ULONG - Win32 status code.
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONG Error;
|
|
PIP_NAT_INTERFACE_INFO Info;
|
|
PNAT_INTERFACE Interfacep;
|
|
IO_STATUS_BLOCK IoStatus;
|
|
ULONG Size;
|
|
NTSTATUS status;
|
|
|
|
PROFILE("NatConfigureInterface");
|
|
|
|
if (!InterfaceInfo) {
|
|
NhTrace(
|
|
TRACE_FLAG_NAT,
|
|
"NatConfigureInterface: no interface info for %d",
|
|
Index
|
|
);
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
//
|
|
// Make a copy of the information
|
|
//
|
|
|
|
Size =
|
|
FIELD_OFFSET(IP_NAT_INTERFACE_INFO, Header) +
|
|
InterfaceInfo->Header.Size;
|
|
|
|
Info = (PIP_NAT_INTERFACE_INFO)NH_ALLOCATE(Size);
|
|
|
|
if (!Info) {
|
|
NhTrace(
|
|
TRACE_FLAG_NAT,
|
|
"NatConfigureInterface: error allocating copy of configuration"
|
|
);
|
|
NhErrorLog(
|
|
IP_NAT_LOG_ALLOCATION_FAILED,
|
|
0,
|
|
"%d",
|
|
Size
|
|
);
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
CopyMemory(
|
|
Info,
|
|
InterfaceInfo,
|
|
Size
|
|
);
|
|
|
|
//
|
|
// Look up the interface to be configured
|
|
//
|
|
|
|
EnterCriticalSection(&NatInterfaceLock);
|
|
if (!(Interfacep = NatpLookupInterface(Index, NULL))) {
|
|
LeaveCriticalSection(&NatInterfaceLock);
|
|
NhTrace(
|
|
TRACE_FLAG_NAT,
|
|
"NatConfigureInterface: interface %d not found",
|
|
Index
|
|
);
|
|
NH_FREE(Info);
|
|
return ERROR_NO_SUCH_INTERFACE;
|
|
}
|
|
|
|
//
|
|
// See if the configuration changed
|
|
//
|
|
|
|
if ((Size ==
|
|
FIELD_OFFSET(IP_NAT_INTERFACE_INFO, Header) +
|
|
Interfacep->Info->Header.Size) &&
|
|
memcmp(InterfaceInfo, Interfacep->Info, Size) == 0
|
|
) {
|
|
LeaveCriticalSection(&NatInterfaceLock);
|
|
NhTrace(
|
|
TRACE_FLAG_NAT,
|
|
"NatConfigureInterface: no change to interface %d configuration",
|
|
Index
|
|
);
|
|
NH_FREE(Info);
|
|
return NO_ERROR;
|
|
}
|
|
|
|
|
|
//
|
|
// See if the interface is bound;
|
|
// if so we need to update the kernel-mode driver's configuration.
|
|
//
|
|
|
|
if (!NAT_INTERFACE_BOUND(Interfacep)) {
|
|
status = STATUS_SUCCESS;
|
|
} else {
|
|
HANDLE WaitEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
|
|
|
|
if (WaitEvent != NULL) {
|
|
Info->Index = Interfacep->AdapterIndex;
|
|
|
|
//
|
|
// Attempt to configure the interface
|
|
//
|
|
|
|
status =
|
|
NtDeviceIoControlFile(
|
|
NatFileHandle,
|
|
WaitEvent,
|
|
NULL,
|
|
NULL,
|
|
&IoStatus,
|
|
IOCTL_IP_NAT_SET_INTERFACE_INFO,
|
|
(PVOID)Info,
|
|
Size,
|
|
NULL,
|
|
0
|
|
);
|
|
if (status == STATUS_PENDING) {
|
|
WaitForSingleObject(WaitEvent, INFINITE);
|
|
status = IoStatus.Status;
|
|
}
|
|
CloseHandle(WaitEvent);
|
|
} else {
|
|
status = STATUS_UNSUCCESSFUL;
|
|
NhTrace(
|
|
TRACE_FLAG_NAT,
|
|
"NatConfigureInterface: CreateEvent failed [%d]",
|
|
GetLastError()
|
|
);
|
|
}
|
|
}
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
NH_FREE(Info);
|
|
NhTrace(
|
|
TRACE_FLAG_NAT,
|
|
"NatConfigureInterface: status %08x setting interface info",
|
|
status
|
|
);
|
|
Error = RtlNtStatusToDosError(status);
|
|
NhErrorLog(
|
|
IP_NAT_LOG_IOCTL_FAILED,
|
|
Error,
|
|
""
|
|
);
|
|
} else {
|
|
Error = NO_ERROR;
|
|
|
|
//
|
|
// Update proxy ARP entries for LAN interfaces
|
|
//
|
|
|
|
if (NAT_INTERFACE_BOUND(Interfacep) &&
|
|
Interfacep->Type == ROUTER_IF_TYPE_DEDICATED
|
|
) {
|
|
NatUpdateProxyArp(Interfacep, FALSE);
|
|
}
|
|
|
|
if (Interfacep->Info) { NH_FREE(Interfacep->Info); }
|
|
Interfacep->Info = Info;
|
|
|
|
if (NAT_INTERFACE_BOUND(Interfacep) &&
|
|
Interfacep->Type == ROUTER_IF_TYPE_DEDICATED
|
|
) {
|
|
NatUpdateProxyArp(Interfacep, TRUE);
|
|
}
|
|
}
|
|
|
|
LeaveCriticalSection(&NatInterfaceLock);
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
if (InterfaceInfo->Flags & IP_NAT_INTERFACE_FLAGS_BOUNDARY) {
|
|
NhSignalNatInterface(
|
|
Index,
|
|
TRUE
|
|
);
|
|
} else {
|
|
NhSignalNatInterface(
|
|
Index,
|
|
FALSE
|
|
);
|
|
}
|
|
}
|
|
|
|
return Error;
|
|
|
|
} // NatConfigureInterface
|
|
|
|
|
|
ULONG
|
|
NatCreateInterface(
|
|
ULONG Index,
|
|
NET_INTERFACE_TYPE Type,
|
|
PIP_NAT_INTERFACE_INFO InterfaceInfo
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is invoked to create an interface with the NAT driver.
|
|
|
|
Arguments:
|
|
|
|
Index - the index of the new interface
|
|
|
|
InterfaceInfo - the configuration for the new interface
|
|
|
|
Return Value:
|
|
|
|
ULONG - Win32 status code.
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONG Error;
|
|
PIP_NAT_INTERFACE_INFO Info;
|
|
PLIST_ENTRY InsertionPoint;
|
|
PNAT_INTERFACE Interfacep;
|
|
IO_STATUS_BLOCK IoStatus;
|
|
ULONG Size;
|
|
NTSTATUS status;
|
|
ROUTER_INTERFACE_TYPE IfType;
|
|
|
|
PROFILE("NatCreateInterface");
|
|
|
|
if (!InterfaceInfo) {
|
|
NhTrace(
|
|
TRACE_FLAG_NAT,
|
|
"NatCreateInterface: no interface info for %d",
|
|
Index
|
|
);
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
//
|
|
// Check for the interface in our table
|
|
//
|
|
|
|
EnterCriticalSection(&NatInterfaceLock);
|
|
if (NatpLookupInterface(Index, &InsertionPoint)) {
|
|
LeaveCriticalSection(&NatInterfaceLock);
|
|
NhTrace(
|
|
TRACE_FLAG_NAT,
|
|
"NatCreateInterface: interface %d already exists",
|
|
Index
|
|
);
|
|
return ERROR_INTERFACE_ALREADY_EXISTS;
|
|
}
|
|
|
|
//
|
|
// Allocate a new interface
|
|
//
|
|
|
|
Interfacep =
|
|
reinterpret_cast<PNAT_INTERFACE>(NH_ALLOCATE(sizeof(NAT_INTERFACE)));
|
|
|
|
if (!Interfacep) {
|
|
LeaveCriticalSection(&NatInterfaceLock);
|
|
NhTrace(
|
|
TRACE_FLAG_NAT,
|
|
"NatCreateInterface: error allocating interface"
|
|
);
|
|
NhErrorLog(
|
|
IP_NAT_LOG_ALLOCATION_FAILED,
|
|
0,
|
|
"%d",
|
|
sizeof(NAT_INTERFACE)
|
|
);
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
//
|
|
// Make a copy of the information
|
|
//
|
|
|
|
Size =
|
|
FIELD_OFFSET(IP_NAT_INTERFACE_INFO, Header) +
|
|
InterfaceInfo->Header.Size;
|
|
|
|
Info = (PIP_NAT_INTERFACE_INFO)NH_ALLOCATE(Size);
|
|
|
|
if (!Info) {
|
|
LeaveCriticalSection(&NatInterfaceLock);
|
|
NH_FREE(Interfacep);
|
|
NhTrace(
|
|
TRACE_FLAG_NAT,
|
|
"NatCreateInterface: error allocating copy of configuration"
|
|
);
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
CopyMemory(
|
|
Info,
|
|
InterfaceInfo,
|
|
Size
|
|
);
|
|
|
|
//
|
|
// Initialize the new interface
|
|
//
|
|
|
|
ZeroMemory(Interfacep, sizeof(*Interfacep));
|
|
|
|
Interfacep->Index = Index;
|
|
Interfacep->AdapterIndex = (ULONG)-1;
|
|
Interfacep->Type = IfType =
|
|
((Type == PERMANENT)
|
|
? ROUTER_IF_TYPE_DEDICATED
|
|
: ROUTER_IF_TYPE_FULL_ROUTER);
|
|
Interfacep->Info = Info;
|
|
InsertTailList(InsertionPoint, &Interfacep->Link);
|
|
|
|
LeaveCriticalSection(&NatInterfaceLock);
|
|
|
|
if (InterfaceInfo->Flags & IP_NAT_INTERFACE_FLAGS_BOUNDARY) {
|
|
NhSignalNatInterface(
|
|
Index,
|
|
TRUE
|
|
);
|
|
} else {
|
|
NhSignalNatInterface(
|
|
Index,
|
|
FALSE
|
|
);
|
|
}
|
|
|
|
return NO_ERROR;
|
|
|
|
} // NatCreateInterface
|
|
|
|
|
|
ULONG
|
|
NatCreateTicket(
|
|
ULONG InterfaceIndex,
|
|
UCHAR Protocol,
|
|
USHORT PublicPort,
|
|
ULONG PublicAddress,
|
|
USHORT PrivatePort,
|
|
ULONG PrivateAddress
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is invoked to add a ticket (static port mapping)
|
|
to an interface.
|
|
|
|
Arguments:
|
|
|
|
InterfaceIndex - the interface to which to add the ticket
|
|
|
|
Protocol, PublicPort, PublicAddress, PrivatePort, PrivateAddress -
|
|
describes the ticket to be created
|
|
|
|
Return Value:
|
|
|
|
ULONG - Win32 status code.
|
|
|
|
--*/
|
|
|
|
{
|
|
IP_NAT_CREATE_TICKET CreateTicket;
|
|
ULONG Error;
|
|
IO_STATUS_BLOCK IoStatus;
|
|
NTSTATUS status;
|
|
HANDLE WaitEvent;
|
|
|
|
PROFILE("NatCreateTicket");
|
|
|
|
WaitEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
|
|
if (WaitEvent == NULL) {
|
|
NhTrace(
|
|
TRACE_FLAG_NAT,
|
|
"NatCreateTicket: CreateEvent failed [%d]",
|
|
GetLastError()
|
|
);
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
CreateTicket.InterfaceIndex = InterfaceIndex;
|
|
CreateTicket.PortMapping.Protocol = Protocol;
|
|
CreateTicket.PortMapping.PublicPort = PublicPort;
|
|
CreateTicket.PortMapping.PublicAddress = PublicAddress;
|
|
CreateTicket.PortMapping.PrivatePort = PrivatePort;
|
|
CreateTicket.PortMapping.PrivateAddress = PrivateAddress;
|
|
|
|
EnterCriticalSection(&NatInterfaceLock);
|
|
|
|
status =
|
|
NtDeviceIoControlFile(
|
|
NatFileHandle,
|
|
WaitEvent,
|
|
NULL,
|
|
NULL,
|
|
&IoStatus,
|
|
IOCTL_IP_NAT_CREATE_TICKET,
|
|
(PVOID)&CreateTicket,
|
|
sizeof(CreateTicket),
|
|
NULL,
|
|
0
|
|
);
|
|
|
|
LeaveCriticalSection(&NatInterfaceLock);
|
|
|
|
if (status == STATUS_PENDING) {
|
|
WaitForSingleObject(WaitEvent, INFINITE);
|
|
status = IoStatus.Status;
|
|
}
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
Error = NO_ERROR;
|
|
} else {
|
|
Error = RtlNtStatusToDosError(status);
|
|
NhTrace(
|
|
TRACE_FLAG_NAT,
|
|
"NatCreateTicket: Ioctl = %d",
|
|
Error
|
|
);
|
|
}
|
|
|
|
CloseHandle(WaitEvent);
|
|
|
|
return Error;
|
|
} // NatCreateTicket
|
|
|
|
|
|
ULONG
|
|
NatDeleteInterface(
|
|
ULONG Index
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is invoked to remove an interface from the NAT.
|
|
|
|
Arguments:
|
|
|
|
Index - the interface to be removed
|
|
|
|
Return Value:
|
|
|
|
ULONG - Win32 status code.
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONG Error;
|
|
PNAT_INTERFACE Interfacep;
|
|
IO_STATUS_BLOCK IoStatus;
|
|
NTSTATUS status;
|
|
HANDLE WaitEvent;
|
|
|
|
PROFILE("NatDeleteInterface");
|
|
|
|
WaitEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
|
|
if (WaitEvent == NULL) {
|
|
NhTrace(
|
|
TRACE_FLAG_NAT,
|
|
"NatDeleteInterface: CreateEvent failed [%d]",
|
|
GetLastError()
|
|
);
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
//
|
|
// Retrieve the interface to be deleted.
|
|
//
|
|
|
|
EnterCriticalSection(&NatInterfaceLock);
|
|
if (!(Interfacep = NatpLookupInterface(Index, NULL))) {
|
|
LeaveCriticalSection(&NatInterfaceLock);
|
|
CloseHandle(WaitEvent);
|
|
NhTrace(
|
|
TRACE_FLAG_NAT,
|
|
"NatDeleteInterface: interface %d not found",
|
|
Index
|
|
);
|
|
return ERROR_NO_SUCH_INTERFACE;
|
|
}
|
|
|
|
Error = NO_ERROR;
|
|
if (NAT_INTERFACE_BOUND(Interfacep)) {
|
|
|
|
//
|
|
// Delete the interface from the kernel-mode driver
|
|
//
|
|
|
|
status =
|
|
NtDeviceIoControlFile(
|
|
NatFileHandle,
|
|
WaitEvent,
|
|
NULL,
|
|
NULL,
|
|
&IoStatus,
|
|
IOCTL_IP_NAT_DELETE_INTERFACE,
|
|
(PVOID)&Interfacep->AdapterIndex,
|
|
sizeof(ULONG),
|
|
NULL,
|
|
0
|
|
);
|
|
if (status == STATUS_PENDING) {
|
|
WaitForSingleObject(WaitEvent, INFINITE);
|
|
status = IoStatus.Status;
|
|
}
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
Error = NO_ERROR;
|
|
} else {
|
|
Error = RtlNtStatusToDosError(status);
|
|
NhErrorLog(
|
|
IP_NAT_LOG_IOCTL_FAILED,
|
|
Error,
|
|
""
|
|
);
|
|
}
|
|
}
|
|
CloseHandle(WaitEvent);
|
|
|
|
//
|
|
// Remove the interface from our list
|
|
//
|
|
|
|
RemoveEntryList(&Interfacep->Link);
|
|
if (Interfacep->Info) {
|
|
NH_FREE(Interfacep->Info);
|
|
}
|
|
NH_FREE(Interfacep);
|
|
|
|
LeaveCriticalSection(&NatInterfaceLock);
|
|
|
|
NhSignalNatInterface(
|
|
Index,
|
|
FALSE
|
|
);
|
|
|
|
return Error;
|
|
|
|
} // NatDeleteInterface
|
|
|
|
|
|
ULONG
|
|
NatDeleteTicket(
|
|
ULONG InterfaceIndex,
|
|
UCHAR Protocol,
|
|
USHORT PublicPort,
|
|
ULONG PublicAddress,
|
|
USHORT PrivatePort,
|
|
ULONG PrivateAddress
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is invoked to remove a ticket (static port mapping)
|
|
from an interface.
|
|
|
|
Arguments:
|
|
|
|
InterfaceIndex - the interface from which to remove the ticket
|
|
|
|
Protocol, PublicPort, PublicAddress, PrivatePort, PrivateAddress -
|
|
describes the ticket to be deleted
|
|
|
|
Return Value:
|
|
|
|
ULONG - Win32 status code.
|
|
|
|
--*/
|
|
|
|
{
|
|
IP_NAT_CREATE_TICKET DeleteTicket;
|
|
ULONG Error;
|
|
IO_STATUS_BLOCK IoStatus;
|
|
NTSTATUS status;
|
|
HANDLE WaitEvent;
|
|
|
|
PROFILE("NatDeleteTicket");
|
|
|
|
WaitEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
|
|
if (WaitEvent == NULL) {
|
|
NhTrace(
|
|
TRACE_FLAG_NAT,
|
|
"NatDeleteTicket: CreateEvent failed [%d]",
|
|
GetLastError()
|
|
);
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
DeleteTicket.InterfaceIndex = InterfaceIndex;
|
|
DeleteTicket.PortMapping.Protocol = Protocol;
|
|
DeleteTicket.PortMapping.PublicPort = PublicPort;
|
|
DeleteTicket.PortMapping.PublicAddress = PublicAddress;
|
|
DeleteTicket.PortMapping.PrivatePort = PrivatePort;
|
|
DeleteTicket.PortMapping.PrivateAddress = PrivateAddress;
|
|
|
|
EnterCriticalSection(&NatInterfaceLock);
|
|
|
|
status =
|
|
NtDeviceIoControlFile(
|
|
NatFileHandle,
|
|
WaitEvent,
|
|
NULL,
|
|
NULL,
|
|
&IoStatus,
|
|
IOCTL_IP_NAT_DELETE_TICKET,
|
|
(PVOID)&DeleteTicket,
|
|
sizeof(DeleteTicket),
|
|
NULL,
|
|
0
|
|
);
|
|
|
|
LeaveCriticalSection(&NatInterfaceLock);
|
|
|
|
if (status == STATUS_PENDING) {
|
|
WaitForSingleObject(WaitEvent, INFINITE);
|
|
status = IoStatus.Status;
|
|
}
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
Error = NO_ERROR;
|
|
} else {
|
|
Error = RtlNtStatusToDosError(status);
|
|
NhTrace(
|
|
TRACE_FLAG_NAT,
|
|
"NatDeleteTicket: Ioctl = %d",
|
|
Error
|
|
);
|
|
}
|
|
|
|
CloseHandle(WaitEvent);
|
|
|
|
return Error;
|
|
} // NatDeleteTicket
|
|
|
|
|
|
|
|
ULONG
|
|
NatGetInterfaceCharacteristics(
|
|
ULONG Index
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is invoked to determine whether the given interface:
|
|
1) Is a NAT boundary interface
|
|
2) Is a NAT private interface
|
|
3) Has the firewall enabled
|
|
|
|
Note that this routine may be invoked even when the NAT
|
|
is neither installed nor running; it operates as expected,
|
|
since the interface list and lock are always initialized in 'DllMain'.
|
|
|
|
Arguments:
|
|
|
|
Index - the interface in question
|
|
|
|
IsNatInterface - optionally set to TRUE if the given index
|
|
is at all a NAT interface.
|
|
|
|
Return Value:
|
|
|
|
BOOLEAN - TRUE if the interface is a NAT boundary interface,
|
|
FALSE otherwise.
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONG Result = 0;
|
|
PNAT_INTERFACE Interfacep;
|
|
PROFILE("NatGetInterfaceCharacteristics");
|
|
|
|
EnterCriticalSection(&NatInterfaceLock);
|
|
|
|
if (!(Interfacep = NatpLookupInterface(Index, NULL))) {
|
|
LeaveCriticalSection(&NatInterfaceLock);
|
|
return Result;
|
|
}
|
|
|
|
if (Interfacep->Info &&
|
|
(Interfacep->Info->Flags & IP_NAT_INTERFACE_FLAGS_FW)) {
|
|
Result = NAT_IF_CHAR_FW;
|
|
}
|
|
|
|
if (Interfacep->Info &&
|
|
(Interfacep->Info->Flags & IP_NAT_INTERFACE_FLAGS_BOUNDARY)) {
|
|
|
|
Result |= NAT_IF_CHAR_BOUNDARY;
|
|
} else if (!NAT_IFC_FW(Result)) {
|
|
|
|
//
|
|
// As the interface isn't public and isn't firewalled, it must
|
|
// be a private interface (or we wouldn't have a record of it).
|
|
//
|
|
|
|
Result |= NAT_IF_CHAR_PRIVATE;
|
|
}
|
|
|
|
LeaveCriticalSection(&NatInterfaceLock);
|
|
|
|
return Result;
|
|
} // NatGetInterfaceCharacteristics
|
|
|
|
|
|
VOID
|
|
NatInstallApplicationSettings(
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is invoked to update the application settings
|
|
(i.e., dynamic tickets) stored with the kernel-mode translation module.
|
|
|
|
Arguments:
|
|
|
|
none
|
|
|
|
Return Value:
|
|
|
|
none.
|
|
|
|
--*/
|
|
|
|
{
|
|
PNAT_APP_ENTRY pAppEntry;
|
|
ULONG Count;
|
|
PIP_NAT_CREATE_DYNAMIC_TICKET CreateTicket;
|
|
IO_STATUS_BLOCK IoStatus;
|
|
ULONG Length;
|
|
PLIST_ENTRY Link;
|
|
NTSTATUS status;
|
|
HANDLE WaitEvent;
|
|
|
|
PROFILE("NatInstallApplicationSettings");
|
|
|
|
//
|
|
// Install a dynamic ticket for each entry in the applications list
|
|
//
|
|
|
|
EnterCriticalSection(&NatInterfaceLock);
|
|
EnterCriticalSection(&NhLock);
|
|
|
|
WaitEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
|
|
if (WaitEvent == NULL) {
|
|
LeaveCriticalSection(&NhLock);
|
|
LeaveCriticalSection(&NatInterfaceLock);
|
|
NhTrace(
|
|
TRACE_FLAG_NAT,
|
|
"NatInstallSharedAccessSettings: CreateEvent failed [%d]",
|
|
GetLastError()
|
|
);
|
|
return;
|
|
}
|
|
|
|
for (Link = NhApplicationSettingsList.Flink;
|
|
Link != &NhApplicationSettingsList;
|
|
Link = Link->Flink)
|
|
{
|
|
|
|
//
|
|
// Each 'application' has a list of 'responses' which specify
|
|
// the ports on which response-sessions are expected.
|
|
// Enumerate the responses and allocate a ticket-structure
|
|
// large enough to hold the list as an array.
|
|
//
|
|
|
|
pAppEntry = CONTAINING_RECORD(Link, NAT_APP_ENTRY, Link);
|
|
|
|
Length =
|
|
pAppEntry->ResponseCount * sizeof(CreateTicket->ResponseArray[0]) +
|
|
FIELD_OFFSET(IP_NAT_CREATE_DYNAMIC_TICKET, ResponseArray);
|
|
|
|
if (!(CreateTicket =
|
|
reinterpret_cast<PIP_NAT_CREATE_DYNAMIC_TICKET>(
|
|
NH_ALLOCATE(Length)
|
|
)))
|
|
{ break; }
|
|
|
|
//
|
|
// Fill in the ticket structure from the application entry
|
|
// and its list of response-entries.
|
|
//
|
|
|
|
CreateTicket->Protocol = pAppEntry->Protocol;
|
|
CreateTicket->Port = pAppEntry->Port;
|
|
CreateTicket->ResponseCount = pAppEntry->ResponseCount;
|
|
|
|
for (Count = 0; Count < pAppEntry->ResponseCount; Count++)
|
|
{
|
|
CreateTicket->ResponseArray[Count].Protocol =
|
|
pAppEntry->ResponseArray[Count].ucIPProtocol;
|
|
CreateTicket->ResponseArray[Count].StartPort =
|
|
pAppEntry->ResponseArray[Count].usStartPort;
|
|
CreateTicket->ResponseArray[Count].EndPort =
|
|
pAppEntry->ResponseArray[Count].usEndPort;
|
|
}
|
|
|
|
//
|
|
// Install the dynamic ticket for this application, and continue.
|
|
//
|
|
|
|
status = NtDeviceIoControlFile(
|
|
NatFileHandle,
|
|
WaitEvent,
|
|
NULL,
|
|
NULL,
|
|
&IoStatus,
|
|
IOCTL_IP_NAT_CREATE_DYNAMIC_TICKET,
|
|
(PVOID)CreateTicket,
|
|
Length,
|
|
NULL,
|
|
0
|
|
);
|
|
if (status == STATUS_PENDING) {
|
|
WaitForSingleObject(WaitEvent, INFINITE);
|
|
status = IoStatus.Status;
|
|
}
|
|
NH_FREE(CreateTicket);
|
|
}
|
|
|
|
LeaveCriticalSection(&NhLock);
|
|
LeaveCriticalSection(&NatInterfaceLock);
|
|
|
|
CloseHandle(WaitEvent);
|
|
} // NatInstallApplicationSettings
|
|
|
|
|
|
BOOLEAN
|
|
NatIsBoundaryInterface(
|
|
ULONG Index,
|
|
PBOOLEAN IsNatInterface OPTIONAL
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is invoked to determine whether the given interface
|
|
has the NAT enabled and is marked as a boundary interface.
|
|
Note that this routine may be invoked even when the NAT
|
|
is neither installed nor running; it operates as expected,
|
|
since the interface list and lock are always initialized in 'DllMain'.
|
|
|
|
Arguments:
|
|
|
|
Index - the interface in question
|
|
|
|
IsNatInterface - optionally set to TRUE if the given index
|
|
is at all a NAT interface.
|
|
|
|
Return Value:
|
|
|
|
BOOLEAN - TRUE if the interface is a NAT boundary interface,
|
|
FALSE otherwise.
|
|
|
|
--*/
|
|
|
|
{
|
|
PNAT_INTERFACE Interfacep;
|
|
PROFILE("NatIsBoundaryInterface");
|
|
|
|
EnterCriticalSection(&NatInterfaceLock);
|
|
if (!(Interfacep = NatpLookupInterface(Index, NULL))) {
|
|
LeaveCriticalSection(&NatInterfaceLock);
|
|
if (IsNatInterface) { *IsNatInterface = FALSE; }
|
|
return FALSE;
|
|
}
|
|
|
|
if (IsNatInterface) { *IsNatInterface = TRUE; }
|
|
|
|
if (Interfacep->Info &&
|
|
(Interfacep->Info->Flags & IP_NAT_INTERFACE_FLAGS_BOUNDARY)) {
|
|
LeaveCriticalSection(&NatInterfaceLock);
|
|
return TRUE;
|
|
}
|
|
LeaveCriticalSection(&NatInterfaceLock);
|
|
return FALSE;
|
|
|
|
} // NatIsBoundaryInterface
|
|
|
|
|
|
PNAT_INTERFACE
|
|
NatpLookupInterface(
|
|
ULONG Index,
|
|
OUT PLIST_ENTRY* InsertionPoint OPTIONAL
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is called to retrieve an interface given its index.
|
|
|
|
Arguments:
|
|
|
|
Index - the index of the interface to be retrieved
|
|
|
|
InsertionPoint - if the interface is not found, optionally receives
|
|
the point where the interface would be inserted in the interface list
|
|
|
|
Return Value:
|
|
|
|
PNAT_INTERFACE - the interface, if found; otherwise, NULL.
|
|
|
|
Environment:
|
|
|
|
Invoked internally from an arbitrary context, with 'NatInterfaceLock'
|
|
held by caller.
|
|
|
|
--*/
|
|
|
|
{
|
|
PNAT_INTERFACE Interfacep;
|
|
PLIST_ENTRY Link;
|
|
|
|
PROFILE("NatpLookupInterface");
|
|
|
|
for (Link = NatInterfaceList.Flink; Link != &NatInterfaceList;
|
|
Link = Link->Flink) {
|
|
Interfacep = CONTAINING_RECORD(Link, NAT_INTERFACE, Link);
|
|
if (Index > Interfacep->Index) {
|
|
continue;
|
|
} else if (Index < Interfacep->Index) {
|
|
break;
|
|
}
|
|
return Interfacep;
|
|
}
|
|
|
|
if (InsertionPoint) { *InsertionPoint = Link; }
|
|
|
|
return NULL;
|
|
|
|
} // NatpLookupInterface
|
|
|
|
|
|
ULONG
|
|
NatQueryInterface(
|
|
ULONG Index,
|
|
PIP_NAT_INTERFACE_INFO InterfaceInfo,
|
|
PULONG InterfaceInfoSize
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is invoked to retrieve the information for a NAT interface.
|
|
|
|
Arguments:
|
|
|
|
Index - the interface whose information is to be queried
|
|
|
|
InterfaceInfo - receives the information
|
|
|
|
InterfaceInfoSize - receives the information size
|
|
|
|
Return Value:
|
|
|
|
ULONG - Win32 status code.
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONG Error;
|
|
PNAT_INTERFACE Interfacep;
|
|
ULONG Size;
|
|
|
|
PROFILE("NatQueryInterface");
|
|
|
|
//
|
|
// Look up the interface to be queried
|
|
//
|
|
|
|
EnterCriticalSection(&NatInterfaceLock);
|
|
if (!(Interfacep = NatpLookupInterface(Index, NULL))) {
|
|
LeaveCriticalSection(&NatInterfaceLock);
|
|
NhTrace(
|
|
TRACE_FLAG_NAT,
|
|
"NatQueryInterface: interface %d not found",
|
|
Index
|
|
);
|
|
return ERROR_NO_SUCH_INTERFACE;
|
|
}
|
|
|
|
//
|
|
// Compute the required size
|
|
//
|
|
|
|
Size =
|
|
FIELD_OFFSET(IP_NAT_INTERFACE_INFO, Header) +
|
|
Interfacep->Info->Header.Size;
|
|
|
|
if (Size >= *InterfaceInfoSize) {
|
|
*InterfaceInfoSize = Size;
|
|
Error = ERROR_INSUFFICIENT_BUFFER;
|
|
} else {
|
|
*InterfaceInfoSize = Size;
|
|
CopyMemory(
|
|
InterfaceInfo,
|
|
Interfacep->Info,
|
|
Size
|
|
);
|
|
Error = NO_ERROR;
|
|
}
|
|
|
|
LeaveCriticalSection(&NatInterfaceLock);
|
|
|
|
return Error;
|
|
|
|
} // NatQueryInterface
|
|
|
|
|
|
ULONG
|
|
NatQueryInterfaceMappingTable(
|
|
ULONG Index,
|
|
PIP_NAT_ENUMERATE_SESSION_MAPPINGS EnumerateTable,
|
|
PULONG EnumerateTableSize
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is invoked to retrieve the session mappings for an interface.
|
|
|
|
Arguments:
|
|
|
|
EnumerateTable - receives the enumerated mappings
|
|
|
|
EnumerateTableSize - indicates the size of 'EnumerateTable'
|
|
|
|
Return Value:
|
|
|
|
ULONG - Win32 error code.
|
|
|
|
--*/
|
|
|
|
{
|
|
IP_NAT_ENUMERATE_SESSION_MAPPINGS Enumerate;
|
|
PNAT_INTERFACE Interfacep;
|
|
IO_STATUS_BLOCK IoStatus;
|
|
ULONG RequiredSize;
|
|
NTSTATUS status;
|
|
HANDLE WaitEvent;
|
|
|
|
PROFILE("NatQueryInterfaceMappingTable");
|
|
|
|
EnterCriticalSection(&NatInterfaceLock);
|
|
if (!(Interfacep = NatpLookupInterface(Index, NULL))) {
|
|
LeaveCriticalSection(&NatInterfaceLock);
|
|
NhTrace(
|
|
TRACE_FLAG_NAT,
|
|
"NatQueryInterfaceMappingTable: interface %d not found",
|
|
Index
|
|
);
|
|
return ERROR_NO_SUCH_INTERFACE;
|
|
}
|
|
|
|
if (!NAT_INTERFACE_BOUND(Interfacep)) {
|
|
|
|
//
|
|
// The interface is not bound, so there aren't any mappings.
|
|
// Indicate zero mappings in the caller's request-buffer.
|
|
//
|
|
|
|
LeaveCriticalSection(&NatInterfaceLock);
|
|
|
|
RequiredSize =
|
|
FIELD_OFFSET(IP_NAT_ENUMERATE_SESSION_MAPPINGS, EnumerateTable[0]);
|
|
|
|
if (*EnumerateTableSize < RequiredSize) {
|
|
*EnumerateTableSize = RequiredSize;
|
|
return ERROR_INSUFFICIENT_BUFFER;
|
|
}
|
|
|
|
EnumerateTable->Index = Index;
|
|
EnumerateTable->EnumerateContext[0] = 0;
|
|
EnumerateTable->EnumerateCount = 0;
|
|
*EnumerateTableSize = RequiredSize;
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
WaitEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
|
|
if (WaitEvent == NULL) {
|
|
LeaveCriticalSection(&NatInterfaceLock);
|
|
NhTrace(
|
|
TRACE_FLAG_NAT,
|
|
"NatQueryInterfaceMappingTable: CreateEvent failed [%d]",
|
|
GetLastError()
|
|
);
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
//
|
|
// Determine the amount of space required
|
|
//
|
|
|
|
Enumerate.Index = Interfacep->AdapterIndex;
|
|
Enumerate.EnumerateCount = 0;
|
|
Enumerate.EnumerateContext[0] = 0;
|
|
status =
|
|
NtDeviceIoControlFile(
|
|
NatFileHandle,
|
|
WaitEvent,
|
|
NULL,
|
|
NULL,
|
|
&IoStatus,
|
|
IOCTL_IP_NAT_GET_INTERFACE_MAPPING_TABLE,
|
|
(PVOID)&Enumerate,
|
|
sizeof(Enumerate),
|
|
(PVOID)&Enumerate,
|
|
sizeof(Enumerate)
|
|
);
|
|
if (status == STATUS_PENDING) {
|
|
WaitForSingleObject(WaitEvent, INFINITE);
|
|
status = IoStatus.Status;
|
|
}
|
|
if (!NT_SUCCESS(status)) {
|
|
CloseHandle(WaitEvent);
|
|
LeaveCriticalSection(&NatInterfaceLock);
|
|
*EnumerateTableSize = 0;
|
|
return RtlNtStatusToDosError(status);
|
|
}
|
|
|
|
RequiredSize =
|
|
FIELD_OFFSET(IP_NAT_ENUMERATE_SESSION_MAPPINGS, EnumerateTable[0]) +
|
|
Enumerate.EnumerateTotalHint * sizeof(IP_NAT_SESSION_MAPPING);
|
|
|
|
//
|
|
// If the caller doesn't have enough space for all these mappings, fail
|
|
//
|
|
|
|
if (*EnumerateTableSize < RequiredSize) {
|
|
CloseHandle(WaitEvent);
|
|
LeaveCriticalSection(&NatInterfaceLock);
|
|
*EnumerateTableSize = RequiredSize + 5 * sizeof(IP_NAT_SESSION_MAPPING);
|
|
return ERROR_INSUFFICIENT_BUFFER;
|
|
}
|
|
|
|
//
|
|
// Attempt to read the mappings
|
|
//
|
|
|
|
Enumerate.Index = Interfacep->AdapterIndex;
|
|
Enumerate.EnumerateCount = 0;
|
|
Enumerate.EnumerateContext[0] = 0;
|
|
status =
|
|
NtDeviceIoControlFile(
|
|
NatFileHandle,
|
|
WaitEvent,
|
|
NULL,
|
|
NULL,
|
|
&IoStatus,
|
|
IOCTL_IP_NAT_GET_INTERFACE_MAPPING_TABLE,
|
|
(PVOID)&Enumerate,
|
|
sizeof(Enumerate),
|
|
(PVOID)EnumerateTable,
|
|
*EnumerateTableSize
|
|
);
|
|
if (status == STATUS_PENDING) {
|
|
WaitForSingleObject(WaitEvent, INFINITE);
|
|
status = IoStatus.Status;
|
|
}
|
|
CloseHandle(WaitEvent);
|
|
LeaveCriticalSection(&NatInterfaceLock);
|
|
|
|
EnumerateTable->Index = Index;
|
|
*EnumerateTableSize =
|
|
FIELD_OFFSET(IP_NAT_ENUMERATE_SESSION_MAPPINGS, EnumerateTable[0]) +
|
|
EnumerateTable->EnumerateCount * sizeof(IP_NAT_SESSION_MAPPING);
|
|
|
|
return NT_SUCCESS(status) ? NO_ERROR : RtlNtStatusToDosError(status);
|
|
|
|
} // NatQueryInterfaceMappingTable
|
|
|
|
|
|
ULONG
|
|
NatQueryMappingTable(
|
|
PIP_NAT_ENUMERATE_SESSION_MAPPINGS EnumerateTable,
|
|
PULONG EnumerateTableSize
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is invoked to retrieve the session mappings for an interface.
|
|
|
|
Arguments:
|
|
|
|
EnumerateTable - receives the enumerated mappings
|
|
|
|
EnumerateTableSize - indicates the size of 'EnumerateTable'
|
|
|
|
Return Value:
|
|
|
|
ULONG - Win32 error code.
|
|
|
|
--*/
|
|
|
|
{
|
|
IP_NAT_ENUMERATE_SESSION_MAPPINGS Enumerate;
|
|
IO_STATUS_BLOCK IoStatus;
|
|
ULONG RequiredSize;
|
|
NTSTATUS status;
|
|
HANDLE WaitEvent;
|
|
|
|
PROFILE("NatQueryMappingTable");
|
|
|
|
WaitEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
|
|
if (WaitEvent == NULL) {
|
|
NhTrace(
|
|
TRACE_FLAG_NAT,
|
|
"NatQueryMappingTable: CreateEvent failed [%d]",
|
|
GetLastError()
|
|
);
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
EnterCriticalSection(&NatInterfaceLock);
|
|
|
|
//
|
|
// Determine the amount of space required
|
|
//
|
|
Enumerate.EnumerateCount = 0;
|
|
Enumerate.EnumerateContext[0] = 0;
|
|
status =
|
|
NtDeviceIoControlFile(
|
|
NatFileHandle,
|
|
WaitEvent,
|
|
NULL,
|
|
NULL,
|
|
&IoStatus,
|
|
IOCTL_IP_NAT_GET_MAPPING_TABLE,
|
|
(PVOID)&Enumerate,
|
|
sizeof(Enumerate),
|
|
(PVOID)&Enumerate,
|
|
sizeof(Enumerate)
|
|
);
|
|
if (status == STATUS_PENDING) {
|
|
WaitForSingleObject(WaitEvent, INFINITE);
|
|
status = IoStatus.Status;
|
|
}
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
LeaveCriticalSection(&NatInterfaceLock);
|
|
CloseHandle(WaitEvent);
|
|
*EnumerateTableSize = 0;
|
|
return RtlNtStatusToDosError(status);
|
|
}
|
|
|
|
RequiredSize =
|
|
FIELD_OFFSET(IP_NAT_ENUMERATE_SESSION_MAPPINGS, EnumerateTable[0]) +
|
|
Enumerate.EnumerateTotalHint * sizeof(IP_NAT_SESSION_MAPPING);
|
|
|
|
//
|
|
// If the caller doesn't have enough space for all these mappings, fail
|
|
//
|
|
|
|
if (*EnumerateTableSize < RequiredSize) {
|
|
LeaveCriticalSection(&NatInterfaceLock);
|
|
CloseHandle(WaitEvent);
|
|
*EnumerateTableSize = RequiredSize + 5 * sizeof(IP_NAT_SESSION_MAPPING);
|
|
return ERROR_INSUFFICIENT_BUFFER;
|
|
}
|
|
|
|
//
|
|
// Attempt to read the mappings
|
|
//
|
|
|
|
Enumerate.EnumerateCount = 0;
|
|
Enumerate.EnumerateContext[0] = 0;
|
|
status =
|
|
NtDeviceIoControlFile(
|
|
NatFileHandle,
|
|
WaitEvent,
|
|
NULL,
|
|
NULL,
|
|
&IoStatus,
|
|
IOCTL_IP_NAT_GET_MAPPING_TABLE,
|
|
(PVOID)&Enumerate,
|
|
sizeof(Enumerate),
|
|
(PVOID)EnumerateTable,
|
|
*EnumerateTableSize
|
|
);
|
|
if (status == STATUS_PENDING) {
|
|
WaitForSingleObject(WaitEvent, INFINITE);
|
|
status = IoStatus.Status;
|
|
}
|
|
|
|
CloseHandle(WaitEvent);
|
|
|
|
LeaveCriticalSection(&NatInterfaceLock);
|
|
|
|
EnumerateTable->Index = (ULONG)-1;
|
|
*EnumerateTableSize =
|
|
FIELD_OFFSET(IP_NAT_ENUMERATE_SESSION_MAPPINGS, EnumerateTable[0]) +
|
|
EnumerateTable->EnumerateCount * sizeof(IP_NAT_SESSION_MAPPING);
|
|
|
|
return NT_SUCCESS(status) ? NO_ERROR : RtlNtStatusToDosError(status);
|
|
|
|
} // NatQueryMappingTable
|
|
|
|
|
|
ULONG
|
|
NatQueryStatisticsInterface(
|
|
ULONG Index,
|
|
PIP_NAT_INTERFACE_STATISTICS InterfaceStatistics,
|
|
PULONG InterfaceStatisticsSize
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is invoked to retrieve the statistics for a NAT interface.
|
|
|
|
Arguments:
|
|
|
|
Index - the index of the interface whose statistics are to be retrieved
|
|
|
|
Return Value:
|
|
|
|
ULONG - Win32 error code.
|
|
|
|
--*/
|
|
|
|
{
|
|
PNAT_INTERFACE Interfacep;
|
|
IO_STATUS_BLOCK IoStatus;
|
|
NTSTATUS status;
|
|
HANDLE WaitEvent;
|
|
|
|
PROFILE("NatQueryStatisticsInterface");
|
|
|
|
//
|
|
// Look up the interface to be queried
|
|
//
|
|
|
|
EnterCriticalSection(&NatInterfaceLock);
|
|
if (!(Interfacep = NatpLookupInterface(Index, NULL))) {
|
|
LeaveCriticalSection(&NatInterfaceLock);
|
|
NhTrace(
|
|
TRACE_FLAG_NAT,
|
|
"NatQueryStatisticsInterface: interface %d not found",
|
|
Index
|
|
);
|
|
return ERROR_NO_SUCH_INTERFACE;
|
|
}
|
|
|
|
//
|
|
// If the interface is not bound, supply zero statistics.
|
|
//
|
|
|
|
if (!NAT_INTERFACE_BOUND(Interfacep)) {
|
|
|
|
LeaveCriticalSection(&NatInterfaceLock);
|
|
|
|
if (*InterfaceStatisticsSize < sizeof(IP_NAT_INTERFACE_STATISTICS)) {
|
|
*InterfaceStatisticsSize = sizeof(IP_NAT_INTERFACE_STATISTICS);
|
|
return ERROR_INSUFFICIENT_BUFFER;
|
|
}
|
|
|
|
*InterfaceStatisticsSize = sizeof(IP_NAT_INTERFACE_STATISTICS);
|
|
ZeroMemory(InterfaceStatistics, sizeof(IP_NAT_INTERFACE_STATISTICS));
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
WaitEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
|
|
if (WaitEvent == NULL) {
|
|
LeaveCriticalSection(&NatInterfaceLock);
|
|
NhTrace(
|
|
TRACE_FLAG_NAT,
|
|
"NatQueryStatisticsInterface: CreateEvent failed [%d]",
|
|
GetLastError()
|
|
);
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
//
|
|
// Attempt to read the statistics for the interface
|
|
//
|
|
|
|
status =
|
|
NtDeviceIoControlFile(
|
|
NatFileHandle,
|
|
WaitEvent,
|
|
NULL,
|
|
NULL,
|
|
&IoStatus,
|
|
IOCTL_IP_NAT_GET_INTERFACE_STATISTICS,
|
|
(PVOID)&Interfacep->AdapterIndex,
|
|
sizeof(ULONG),
|
|
(PVOID)InterfaceStatistics,
|
|
*InterfaceStatisticsSize
|
|
);
|
|
if (status == STATUS_PENDING) {
|
|
WaitForSingleObject(WaitEvent, INFINITE);
|
|
status = IoStatus.Status;
|
|
}
|
|
|
|
CloseHandle(WaitEvent);
|
|
|
|
LeaveCriticalSection(&NatInterfaceLock);
|
|
|
|
if (NT_SUCCESS(status) && IoStatus.Information > *InterfaceStatisticsSize) {
|
|
*InterfaceStatisticsSize = (ULONG)IoStatus.Information;
|
|
return ERROR_INSUFFICIENT_BUFFER;
|
|
}
|
|
|
|
*InterfaceStatisticsSize = (ULONG)IoStatus.Information;
|
|
|
|
return NT_SUCCESS(status) ? NO_ERROR : RtlNtStatusToDosError(status);
|
|
|
|
} // NatQueryStatisticsInterface
|
|
|
|
|
|
VOID
|
|
NatRemoveApplicationSettings(
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is invoked to remove the advanced application settings (i.e.,
|
|
dynamic tickets), and supply the settings to the kernel-mode translation
|
|
module.
|
|
|
|
Arguments:
|
|
|
|
none.
|
|
|
|
Return Value:
|
|
|
|
none.
|
|
|
|
--*/
|
|
|
|
{
|
|
PNAT_APP_ENTRY pAppEntry;
|
|
IP_NAT_DELETE_DYNAMIC_TICKET DeleteTicket;
|
|
IO_STATUS_BLOCK IoStatus;
|
|
PLIST_ENTRY Link;
|
|
NTSTATUS status;
|
|
HANDLE WaitEvent;
|
|
|
|
PROFILE("NatRemoveApplicationSettings");
|
|
|
|
//
|
|
// Each 'application' entry in the shared access settings
|
|
// corresponds to a dynamic ticket for the kernel-mode translator.
|
|
// We begin by removing the dynamic tickets for the old settings, if any,
|
|
// and then we free the old settings in preparation for reloading.
|
|
//
|
|
|
|
WaitEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
|
|
if (WaitEvent == NULL) {
|
|
NhTrace(
|
|
TRACE_FLAG_NAT,
|
|
"NatRemoveSharedAccessSettings: CreateEvent failed [%d]",
|
|
GetLastError()
|
|
);
|
|
return;
|
|
}
|
|
|
|
EnterCriticalSection(&NatInterfaceLock);
|
|
EnterCriticalSection(&NhLock);
|
|
|
|
for (Link = NhApplicationSettingsList.Flink;
|
|
Link != &NhApplicationSettingsList;
|
|
Link = Link->Flink)
|
|
{
|
|
pAppEntry = CONTAINING_RECORD(Link, NAT_APP_ENTRY, Link);
|
|
DeleteTicket.Protocol = pAppEntry->Protocol;
|
|
DeleteTicket.Port = pAppEntry->Port;
|
|
status =
|
|
NtDeviceIoControlFile(
|
|
NatFileHandle,
|
|
WaitEvent,
|
|
NULL,
|
|
NULL,
|
|
&IoStatus,
|
|
IOCTL_IP_NAT_DELETE_DYNAMIC_TICKET,
|
|
(PVOID)&DeleteTicket,
|
|
sizeof(DeleteTicket),
|
|
NULL,
|
|
0
|
|
);
|
|
if (status == STATUS_PENDING) {
|
|
WaitForSingleObject(WaitEvent, INFINITE);
|
|
status = IoStatus.Status;
|
|
}
|
|
}
|
|
|
|
LeaveCriticalSection(&NhLock);
|
|
LeaveCriticalSection(&NatInterfaceLock);
|
|
|
|
CloseHandle(WaitEvent);
|
|
} // NatRemoveSharedAccessSettings
|
|
|
|
|
|
ULONG
|
|
NatUnbindInterface(
|
|
ULONG Index,
|
|
PNAT_INTERFACE Interfacep
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is invoked to remove a binding from the NAT.
|
|
|
|
Arguments:
|
|
|
|
Index - the interface to be unbound
|
|
|
|
Interfacep - optionally supplies the interface-structure to be unbound
|
|
(See 'NATCONN.C' which passes in a static interface-structure).
|
|
|
|
Return Value:
|
|
|
|
ULONG - Win32 status code.
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONG Error;
|
|
IO_STATUS_BLOCK IoStatus;
|
|
NTSTATUS status;
|
|
HANDLE WaitEvent;
|
|
|
|
PROFILE("NatUnbindInterface");
|
|
|
|
WaitEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
|
|
if (WaitEvent == NULL) {
|
|
NhTrace(
|
|
TRACE_FLAG_NAT,
|
|
"NatUnbindInterface: CreateEvent failed [%d]",
|
|
GetLastError()
|
|
);
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
//
|
|
// Retrieve the interface to be unbound.
|
|
//
|
|
|
|
EnterCriticalSection(&NatInterfaceLock);
|
|
if (!Interfacep && !(Interfacep = NatpLookupInterface(Index, NULL))) {
|
|
LeaveCriticalSection(&NatInterfaceLock);
|
|
NhTrace(
|
|
TRACE_FLAG_NAT,
|
|
"NatUnbindInterface: interface %d not found",
|
|
Index
|
|
);
|
|
return ERROR_NO_SUCH_INTERFACE;
|
|
}
|
|
|
|
//
|
|
// Make sure the interface is not already unbound
|
|
//
|
|
|
|
if (!NAT_INTERFACE_BOUND(Interfacep)) {
|
|
LeaveCriticalSection(&NatInterfaceLock);
|
|
NhTrace(
|
|
TRACE_FLAG_NAT,
|
|
"NatUnbindInterface: interface %d already unbound",
|
|
Index
|
|
);
|
|
return ERROR_ADDRESS_NOT_ASSOCIATED;
|
|
}
|
|
|
|
Interfacep->Flags &= ~NAT_INTERFACE_FLAG_BOUND;
|
|
|
|
if (Interfacep->Type == ROUTER_IF_TYPE_DEDICATED) {
|
|
NatUpdateProxyArp(Interfacep, FALSE);
|
|
}
|
|
|
|
//
|
|
// Remove the interface from the kernel-mode driver
|
|
//
|
|
|
|
status =
|
|
NtDeviceIoControlFile(
|
|
NatFileHandle,
|
|
WaitEvent,
|
|
NULL,
|
|
NULL,
|
|
&IoStatus,
|
|
IOCTL_IP_NAT_DELETE_INTERFACE,
|
|
(PVOID)&Interfacep->AdapterIndex,
|
|
sizeof(ULONG),
|
|
NULL,
|
|
0
|
|
);
|
|
if (status == STATUS_PENDING) {
|
|
WaitForSingleObject(WaitEvent, INFINITE);
|
|
status = IoStatus.Status;
|
|
}
|
|
LeaveCriticalSection(&NatInterfaceLock);
|
|
CloseHandle(WaitEvent);
|
|
|
|
Error = NT_SUCCESS(status) ? NO_ERROR : RtlNtStatusToDosError(status);
|
|
|
|
if (Error) {
|
|
NhErrorLog(
|
|
IP_NAT_LOG_IOCTL_FAILED,
|
|
Error,
|
|
""
|
|
);
|
|
}
|
|
|
|
return Error;
|
|
|
|
} // NatUnbindInterface
|
|
|
|
|
|
ULONG
|
|
NatLookupPortMappingAdapter(
|
|
ULONG AdapterIndex,
|
|
UCHAR Protocol,
|
|
ULONG PublicAddress,
|
|
USHORT PublicPort,
|
|
PIP_NAT_PORT_MAPPING PortMappingp
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is invoked to find a mapping that matches the given adapter,
|
|
protocol, public address and public port number. The routine tries to
|
|
match both port and address mapping.
|
|
|
|
Arguments:
|
|
|
|
AdapterIndex - the adapter to be looked up
|
|
Protocol - protocol used to match a mapping
|
|
PublicAddress - public address used to match a mapping
|
|
PublicPort - public port number used to match a mapping
|
|
PortMappingp - pointer to a caller-supplied storage to save the mapping if
|
|
found
|
|
|
|
Return Value:
|
|
|
|
ULONG - Win32 status code.
|
|
|
|
--*/
|
|
|
|
{
|
|
IP_NAT_CREATE_TICKET LookupTicket;
|
|
ULONG Error;
|
|
IO_STATUS_BLOCK IoStatus;
|
|
NTSTATUS status;
|
|
HANDLE WaitEvent;
|
|
|
|
PROFILE("NatLookupPortMappingAdapter");
|
|
|
|
Error = NO_ERROR;
|
|
|
|
WaitEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
|
|
if (WaitEvent == NULL) {
|
|
NhTrace(
|
|
TRACE_FLAG_NAT,
|
|
"NatLookupPortMappingAdapter:"
|
|
" CreateEvent failed [%d] for adapter %d",
|
|
GetLastError(),
|
|
AdapterIndex
|
|
);
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
LookupTicket.InterfaceIndex = AdapterIndex;
|
|
LookupTicket.PortMapping.Protocol = Protocol;
|
|
LookupTicket.PortMapping.PublicPort = PublicPort;
|
|
LookupTicket.PortMapping.PublicAddress = PublicAddress;
|
|
LookupTicket.PortMapping.PrivatePort = 0;
|
|
LookupTicket.PortMapping.PrivateAddress = 0;
|
|
|
|
status =
|
|
NtDeviceIoControlFile(
|
|
NatFileHandle,
|
|
WaitEvent,
|
|
NULL,
|
|
NULL,
|
|
&IoStatus,
|
|
IOCTL_IP_NAT_LOOKUP_TICKET,
|
|
(PVOID)&LookupTicket,
|
|
sizeof(LookupTicket),
|
|
(PVOID)PortMappingp,
|
|
sizeof(*PortMappingp)
|
|
);
|
|
if (status == STATUS_PENDING) {
|
|
WaitForSingleObject(WaitEvent, INFINITE);
|
|
status = IoStatus.Status;
|
|
}
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
NhTrace(
|
|
TRACE_FLAG_NAT,
|
|
"NatLookupPortMappingAdapter:"
|
|
" status %08x getting info for adapter %d",
|
|
status,
|
|
AdapterIndex
|
|
);
|
|
Error = RtlNtStatusToDosError(status);
|
|
}
|
|
|
|
CloseHandle(WaitEvent);
|
|
|
|
return Error;
|
|
}
|