windows-nt/Source/XPSP1/NT/net/rras/ip/nathlp/natsvc/natio.cpp
2020-09-26 16:20:57 +08:00

2144 lines
49 KiB
C++
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
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;
}