Leaked source code of windows server 2003
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.
 
 
 
 
 
 

2621 lines
64 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
NatExpandWildcardMappings(
IN PIP_NAT_INTERFACE_INFO InInfo,
IN PIP_ADAPTER_BINDING_INFO BindingInfo,
OUT PIP_NAT_INTERFACE_INFO *ExpandedInfo
);
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;
PIP_NAT_INTERFACE_INFO ExpandedInfo = NULL;
ULONG ExpandedSize;
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;
}
//
// If a mapping with
// public ip address = 0
// private ip address = 127.0.0.1
// exists, expand that mapping to one mapping for each of the ipaddresses
// bound to the interface.
//
Error = NatExpandWildcardMappings(
Interfacep->Info,
BindingInfo,
&ExpandedInfo);
if ( Error != NO_ERROR ) {
ULONG AdapterIndex = Interfacep->AdapterIndex;
LeaveCriticalSection(&NatInterfaceLock);
NhTrace(
TRACE_FLAG_NAT,
"NatBindInterface: Failed to expand wildcard mappings. Error %d",
Error
);
NhErrorLog(
IP_NAT_LOG_EXPANSION_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;
}
//
// Now set its configuration
//
ExpandedInfo->Index = Interfacep->AdapterIndex;
ExpandedSize =
FIELD_OFFSET(IP_NAT_INTERFACE_INFO, Header) +
ExpandedInfo->Header.Size;
status =
NtDeviceIoControlFile(
NatFileHandle,
WaitEvent,
NULL,
NULL,
&IoStatus,
IOCTL_IP_NAT_SET_INTERFACE_INFO,
(PVOID)ExpandedInfo,
ExpandedSize,
NULL,
0
);
if (status == STATUS_PENDING) {
WaitForSingleObject(WaitEvent, INFINITE);
status = IoStatus.Status;
}
//
// If new Interface Info was allocated, free it
//
if ( ExpandedInfo != Interfacep->Info ) {
NH_FREE(ExpandedInfo);
ExpandedInfo = NULL;
}
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 = NO_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) {
DWORD ExpandedSize = 0;
PIP_ADAPTER_BINDING_INFO BindingInfo;
PIP_NAT_INTERFACE_INFO ExpandedInfo = NULL;
//
// If both, address and port translation are disabled,
// and a mapping with
// public ip address = 0
// private ip address = 127.0.0.1
// exists, expand that mapping to one mapping for each of
// the ipaddresses bound to the interface.
//
BindingInfo = NhQueryBindingInformation(Interfacep->AdapterIndex);
if ( BindingInfo == NULL ) {
LeaveCriticalSection(&NatInterfaceLock);
NhTrace(
TRACE_FLAG_NAT,
"NatConfigureInterface: Failed to Query Binding "
"Information. Error %d",
Error
);
NhErrorLog(
IP_NAT_LOG_EXPANSION_FAILED,
Error,
""
);
NH_FREE(Info);
return Error;
}
Error = NatExpandWildcardMappings(
Info,
BindingInfo,
&ExpandedInfo
);
if ( Error != NO_ERROR ) {
LeaveCriticalSection(&NatInterfaceLock);
NhTrace(
TRACE_FLAG_NAT,
"NatConfigureInterface: Failed to expand wildcard "
"mappings. Error %d",
Error
);
NhErrorLog(
IP_NAT_LOG_EXPANSION_FAILED,
Error,
""
);
NH_FREE(Info);
NH_FREE(BindingInfo);
return Error;
}
NH_FREE(BindingInfo);
BindingInfo = NULL;
ExpandedInfo->Index = Info->Index = Interfacep->AdapterIndex;
ExpandedSize = FIELD_OFFSET(IP_NAT_INTERFACE_INFO, Header) +
ExpandedInfo->Header.Size;
//
// Attempt to configure the interface
//
status =
NtDeviceIoControlFile(
NatFileHandle,
WaitEvent,
NULL,
NULL,
&IoStatus,
IOCTL_IP_NAT_SET_INTERFACE_INFO,
(PVOID)ExpandedInfo,
ExpandedSize,
NULL,
0
);
if (status == STATUS_PENDING) {
WaitForSingleObject(WaitEvent, INFINITE);
status = IoStatus.Status;
}
CloseHandle(WaitEvent);
//
// If new Interface Info was allocated during the call to
// NatExpandWildcardMappings, free it
//
if ( ExpandedInfo != Info ) {
NH_FREE(ExpandedInfo);
ExpandedInfo = NULL;
}
} 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;
}
ULONG
NatExpandWildcardMappings(
IN PIP_NAT_INTERFACE_INFO InInfo,
IN PIP_ADAPTER_BINDING_INFO BindingInfo,
OUT PIP_NAT_INTERFACE_INFO *ExpandedInfo
)
/*++
Routine Description:
This routine is invoked to expand any wildcard(address) mappings, into one
mapping per ipaddress bound to the interface
Assumes that information pointed to by InInfo and BindingInfo does not
change during the duration of this function
Arguments:
InInfo - Pointer to the set of mappings to be expanded
ExpandedInfo - On successful completion, ExpandedInfo contains a pointer
to the expanded set of mappings.
If there were mappings that needed expansion, the function
will allocate the memory for this new set of
mappings.
If no expansion is required, ExpandedInfo will point to the
same location as InInfo.
Return Value:
ULONG - Win32 status code.
If there are no wildcard mappings, it returns ERROR_EXTENDED_ERROR
In case of success: NO_ERROR is returned
--*/
{
ULONG Error;
ULONG Size;
DWORD j, k;
DWORD MappingSize;
DWORD CountOldMappings, CountNewMappings, CountWildcardMappings;
DWORD tempCount;
PIP_NAT_PORT_MAPPING OldMappings = NULL;
PIP_NAT_PORT_MAPPING NewMappings = NULL;
PIP_NAT_INTERFACE_INFO NewInterfaceInfo = NULL;
PRTR_INFO_BLOCK_HEADER NewHeader = NULL;
Error = NO_ERROR;
//
// If a mapping with
// public ip address = 0
// private ip address = 127.0.0.1
// exists, expand that mapping to one mapping for each of the ipaddresses
// bound to the interface.
//
NewInterfaceInfo = InInfo;
do {
//
// We don't do any expansion in case of a private interface
//
if ( InInfo->Flags == 0 ) {
break;
}
//
// If no port mappings exist, break out
//
Error = MprInfoBlockFind(
(LPVOID)&(InInfo->Header),
IP_NAT_PORT_MAPPING_TYPE,
&MappingSize,
&CountOldMappings,
(LPBYTE *)&OldMappings);
if ( Error != NO_ERROR ) {
if ( Error == ERROR_NOT_FOUND ) {
Error = NO_ERROR;
}
break;
}
//
// Count how many mappings need to be expanded
//
CountWildcardMappings = 0;
for ( j = 0; j < CountOldMappings; j++ ) {
if ( IS_WILDCARD_MAPPING(&(OldMappings[j])) ) {
CountWildcardMappings++;
}
}
//
// If there are no wildcard mappings
// return ERROR_EXTENDED_ERROR
//
if ( CountWildcardMappings == 0 ) {
break;
}
//
// allocate memory to hold the new set of mappings
// Number of new mappings will be
//
// ( (OldMappings - WildcardMappings) +
// (WildcardMappings * "no of bound ipaddresses") )
//
CountNewMappings =
(CountOldMappings +
(CountWildcardMappings * (BindingInfo->AddressCount-1)));
Size = CountNewMappings * MappingSize;
NewMappings = (PIP_NAT_PORT_MAPPING)NH_ALLOCATE(Size);
if ( NewMappings == NULL ) {
NhTrace(
TRACE_FLAG_NAT,
"Failed to allocate buffer for expanded mappings. Size: %d",
Size
);
NhErrorLog(
IP_NAT_LOG_ALLOCATION_FAILED,
0,
"%d",
Size
);
//
// If we can't get the buffer, forget about expanding the mappings
// and go on with life.
//
Error = ERROR_NOT_ENOUGH_MEMORY;
break;
}
tempCount = 0;
for ( j = 0; j < CountOldMappings; j++ ) {
if (IS_WILDCARD_MAPPING(&(OldMappings[j]))) {
for ( k = 0; k < BindingInfo->AddressCount; k++ ) {
CopyMemory(&(NewMappings[tempCount]), &(OldMappings[j]),
sizeof(IP_NAT_PORT_MAPPING));
NewMappings[tempCount].PublicAddress =
NewMappings[tempCount].PrivateAddress = BindingInfo->Address[k].Address;
tempCount++;
}
}
else {
CopyMemory(&(NewMappings[tempCount]), &(OldMappings[j]),
sizeof(IP_NAT_PORT_MAPPING));
tempCount++;
}
}
if ( tempCount != CountNewMappings ) {
NhTrace(
TRACE_FLAG_NAT,
"NatExpandWildcardMappings: Unexpected number of expanded "
"mappings: %d. Expected: %d",
tempCount,
CountNewMappings
);
Error = ERROR_INVALID_DATA;
break;
}
#if DBG
{
char publicAddress[128];
char privateAddress[128];
NhTrace(
TRACE_FLAG_NAT,
"NatExpandWildcardMappings: Expanded set of "
"mappings. Total: %d\r\n",
CountNewMappings
);
for ( j = 0; j < CountNewMappings; j++ ) {
_snprintf(
publicAddress,
127,
INET_NTOA(NewMappings[j].PublicAddress)
);
_snprintf(
privateAddress,
127,
INET_NTOA(NewMappings[j].PrivateAddress)
);
NhTrace(
TRACE_FLAG_NAT,
"\tProto: %u, PubPort: %hu, PubAdd: %s, "
"PrivPort: %hu, PrivAdd: %s\r\n",
NewMappings[j].Protocol & 0xFF,
ntohs(NewMappings[j].PublicPort),
publicAddress,
ntohs(NewMappings[j].PrivatePort),
privateAddress
);
}
}
#endif
//
// Now create the new header
//
Error =
MprInfoBlockSet(
&(InInfo->Header),
IP_NAT_PORT_MAPPING_TYPE,
sizeof(IP_NAT_PORT_MAPPING),
CountNewMappings,
(LPBYTE)NewMappings,
(LPVOID *)&NewHeader);
if ( Error != NO_ERROR ) {
NhTrace(
TRACE_FLAG_NAT,
"MprInfoBlockSet failed with error: %d",
Error
);
break;
}
//
// Allocate space for a new IP_NAT_INTERFACE_INFO struct.
//
Size = FIELD_OFFSET(IP_NAT_INTERFACE_INFO, Header) + NewHeader->Size;
NewInterfaceInfo = (PIP_NAT_INTERFACE_INFO)NH_ALLOCATE(Size);
if ( NewInterfaceInfo == NULL ) {
NhTrace(
TRACE_FLAG_NAT,
"Failed to allocate buffer for new NatInterfaceInfo. Size: %d",
Size
);
NhErrorLog(
IP_NAT_LOG_ALLOCATION_FAILED,
0,
"%d",
Size
);
//
// If we can't get the buffer, forget about fixing the mappings
// and go on with life.
//
Error = ERROR_NOT_ENOUGH_MEMORY;
break;
}
//
// Copy the old IP_NAT_INFTERFACE_INFO. Leave out the old header
//
CopyMemory(
NewInterfaceInfo,
InInfo,
FIELD_OFFSET(IP_NAT_INTERFACE_INFO, Header));
//
// Now copy the new header
//
CopyMemory(
((BYTE *)NewInterfaceInfo +
FIELD_OFFSET(IP_NAT_INTERFACE_INFO, Header)),
NewHeader,
NewHeader->Size);
} while (FALSE);
if ( NewMappings ) { NH_FREE(NewMappings); }
if ( NewHeader ) { NH_FREE(NewHeader); }
if ( Error == NO_ERROR ) {
*ExpandedInfo = NewInterfaceInfo;
}
else {
if ( NewInterfaceInfo && NewInterfaceInfo != InInfo ) {
NH_FREE(NewInterfaceInfo);
}
}
return Error;
} // NatExpandWildcardMappings