windows-nt/Source/XPSP1/NT/net/rras/ip/rtrmgr/nat.c
2020-09-26 16:20:57 +08:00

1654 lines
37 KiB
C

/*++
Copyright (c) 1995 Microsoft Corporation
Module Name:
net\ip\rtrmgr\nat.c
Abstract:
Based on filter.c
Abstracts out the NAT functionality
Revision History:
--*/
#include "allinc.h"
DWORD
StartNat(
PIP_NAT_GLOBAL_INFO pNatGlobalInfo
)
{
#if 1
return 0;
#else
PLIST_ENTRY pleNode;
PICB picb;
DWORD dwResult;
NTSTATUS ntStatus;
IO_STATUS_BLOCK IoStatusBlock;
TraceEnter("StartNat");
if(!g_bNatRunning)
{
if(StartDriverAndOpenHandle(IP_NAT_SERVICE_NAME,
DD_IP_NAT_DEVICE_NAME,
&g_hNatDevice) isnot NO_ERROR)
{
Trace0(ERR,
"StartNat: Couldnt open driver");
TraceLeave("StartNat");
return ERROR_OPEN_FAILED;
}
//
// At this point NAT is running
//
ntStatus = NtDeviceIoControlFile(g_hNatDevice,
NULL,
NULL,
NULL,
&IoStatusBlock,
IOCTL_IP_NAT_SET_GLOBAL_INFO,
(PVOID)pNatGlobalInfo,
sizeof(IP_NAT_GLOBAL_INFO),
NULL,
0);
if(ntStatus isnot STATUS_SUCCESS)
{
Trace1(ERR,
"StartNat: Status %X setting global info",
ntStatus);
StopDriverAndCloseHandle(IP_NAT_SERVICE_NAME,
g_hNatDevice);
g_hNatDevice = NULL;
TraceLeave("StartNat");
return ERROR_OPEN_FAILED;
}
g_bNatRunning = TRUE;
//
// Just queue a worker to add the nat info and contexts
//
dwResult = QueueAsyncFunction(RestoreNatInfo,
NULL,
FALSE);
if(dwResult isnot NO_ERROR)
{
Trace1(ERR,
"StartNat: Error %d firing worker function to set nat info",
dwResult);
}
}
TraceLeave("StartNat");
return NO_ERROR;
#endif
}
DWORD
StopNat(
VOID
)
{
#if 1
return 0;
#else
PLIST_ENTRY pleNode;
PICB picb;
DWORD dwResult;
TraceEnter("StopNat");
if(g_bNatRunning)
{
g_bNatRunning = FALSE;
//
// Set the NAT context in the ICBs to INVALID
//
for (pleNode = ICBList.Flink;
pleNode != &ICBList;
pleNode = pleNode->Flink)
{
picb = CONTAINING_RECORD (pleNode, ICB, leIfLink);
if((picb->ritType is ROUTER_IF_TYPE_INTERNAL) or
(picb->ritType is ROUTER_IF_TYPE_LOOPBACK) or
(picb->ritType is ROUTER_IF_TYPE_CLIENT))
{
//
// The above types are not added to the NAT
// or to the IP stack
//
continue;
}
if(picb->dwOperationalState >= MIB_IF_OPER_STATUS_CONNECTED)
{
IpRtAssert(picb->bBound);
UnbindNatInterface(picb);
}
dwResult = DeleteInterfaceFromNat(picb);
if(dwResult isnot NO_ERROR)
{
Trace2(ERR,
"StopNat: NtStatus %x deleting %S from NAT",
dwResult,
picb->pwszName);
}
}
StopDriverAndCloseHandle(IP_NAT_SERVICE_NAME,
g_hNatDevice);
}
TraceLeave("StopNat");
return NO_ERROR;
#endif
}
DWORD
SetGlobalNatInfo(
PRTR_INFO_BLOCK_HEADER pRtrGlobalInfo
)
{
#if 1
return 0;
#else
PRTR_TOC_ENTRY pToc;
PIP_NAT_GLOBAL_INFO pNatGlobalInfo;
NTSTATUS ntStatus;
IO_STATUS_BLOCK IoStatusBlock;
DWORD dwResult;
TraceEnter("SetGlobalNatInfo");
pNatGlobalInfo = NULL;
pToc = GetPointerToTocEntry(IP_NAT_INFO,
pRtrGlobalInfo);
if(pToc)
{
pNatGlobalInfo = GetInfoFromTocEntry(pRtrGlobalInfo,
pToc);
if((pToc->InfoSize is 0) or (pNatGlobalInfo is NULL))
{
//
// Means remove NAT
//
dwResult = StopNat();
if(dwResult isnot NO_ERROR)
{
Trace1(ERR,
"SetGlobalNatInfo: Error %d stopping NAT (no info)",
dwResult);
}
TraceLeave("SetGlobalNatInfo");
return dwResult;
}
}
else
{
Trace0(IF,
"SetGlobalNatInfo: No NAT info, so leaving");
TraceLeave("SetGlobalNatInfo");
return NO_ERROR;
}
EnterCriticalSection(&g_csNatInfo);
if(g_pNatGlobalInfo is NULL)
{
g_pNatGlobalInfo = HeapAlloc(IPRouterHeap,
0,
sizeof(IP_NAT_GLOBAL_INFO));
if(g_pNatGlobalInfo is NULL)
{
Trace1(ERR,
"SetGlobalNatInfo: Error %d allocating memory for NAT info",
GetLastError());
LeaveCriticalSection(&g_csNatInfo);
return ERROR_NOT_ENOUGH_MEMORY;
}
}
//
// Save a copy
//
CopyMemory(g_pNatGlobalInfo,
pNatGlobalInfo,
sizeof(IP_NAT_GLOBAL_INFO));
if(g_bNatRunning)
{
//
// NAT is running, if the user is asking us to stop it,
// do so now an return
//
if(pNatGlobalInfo->NATEnabled is FALSE)
{
dwResult = StopNat();
LeaveCriticalSection(&g_csNatInfo);
if(dwResult isnot NO_ERROR)
{
Trace1(ERR,
"SetGlobalNatInfo: Error %d stopping NAT",
dwResult);
}
TraceLeave("SetGlobalNatInfo");
return dwResult;
}
}
else
{
if(pNatGlobalInfo->NATEnabled is TRUE)
{
dwResult = StartNat(pNatGlobalInfo);
LeaveCriticalSection(&g_csNatInfo);
if(dwResult isnot NO_ERROR)
{
Trace1(ERR,
"SetGlobalNatInfo: Error %d starting NAT",
dwResult);
}
TraceLeave("SetGlobalNatInfo");
//
// Starting NAT causes us to also set the global info
// so we can return from here
//
return dwResult;
}
}
//
// This is the case where NAT is already started and only its info is
// being changed
//
ntStatus = NtDeviceIoControlFile(g_hNatDevice,
NULL,
NULL,
NULL,
&IoStatusBlock,
IOCTL_IP_NAT_SET_GLOBAL_INFO,
(PVOID)pNatGlobalInfo,
sizeof(IP_NAT_GLOBAL_INFO),
NULL,
0);
if (!NT_SUCCESS(ntStatus))
{
Trace1(ERR,
"SetGlobalNatInfo: NtStatus %x setting NAT info",
ntStatus);
TraceLeave("SetGlobalNatInfo");
LeaveCriticalSection(&g_csNatInfo);
return ERROR_CAN_NOT_COMPLETE;
}
LeaveCriticalSection(&g_csNatInfo);
TraceLeave("SetGlobalNatInfo");
return NO_ERROR;
#endif
}
DWORD
AddInterfaceToNat(
PICB picb
)
/*++
Routine Description
Adds an interface to the nat driver and stores the context returned by
the driver
Can only be called if NAT is running
Locks
Arguments
picb
Return Value
--*/
{
#if 1
return 0;
#else
NTSTATUS ntStatus;
IO_STATUS_BLOCK IoStatusBlock;
IP_NAT_CREATE_INTERFACE inBuffer;
DWORD dwInBufLen;
TraceEnter("AddInterfaceToNat");
IpRtAssert((picb->ritType isnot ROUTER_IF_TYPE_INTERNAL) and
(picb->ritType isnot ROUTER_IF_TYPE_LOOPBACK) and
(picb->ritType isnot ROUTER_IF_TYPE_CLIENT));
inBuffer.RtrMgrIndex = picb->dwIfIndex;
inBuffer.RtrMgrContext = picb;
inBuffer.NatInterfaceContext = NULL;
dwInBufLen = sizeof(IP_NAT_CREATE_INTERFACE);
picb->pvNatContext = NULL;
ntStatus = NtDeviceIoControlFile(g_hNatDevice,
NULL,
NULL,
NULL,
&IoStatusBlock,
IOCTL_IP_NAT_CREATE_INTERFACE,
(PVOID)&inBuffer,
dwInBufLen,
(PVOID)&inBuffer,
dwInBufLen);
if(!NT_SUCCESS(ntStatus))
{
Trace2(ERR,
"AddInterfaceToNat: NtStatus %x adding %S to NAT",
ntStatus,
picb->pwszName);
TraceLeave("AddInterfaceToNat");
return ntStatus;
}
picb->pvNatContext = inBuffer.NatInterfaceContext;
TraceLeave("AddInterfaceToNat");
return NO_ERROR;
#endif
}
DWORD
SetNatInterfaceInfo(
PICB picb,
PRTR_INFO_BLOCK_HEADER pInterfaceInfo
)
{
#if 1
return 0;
#else
NTSTATUS ntStatus;
IO_STATUS_BLOCK IoStatusBlock;
DWORD i,dwInBufLen,dwResult;
PRTR_TOC_ENTRY pToc;
PIP_NAT_INTERFACE_INFO pNatInfo;
if((picb->ritType is ROUTER_IF_TYPE_INTERNAL) or
(picb->ritType is ROUTER_IF_TYPE_LOOPBACK) or
(picb->ritType is ROUTER_IF_TYPE_CLIENT))
{
return NO_ERROR;
}
if(!g_bNatRunning)
{
return NO_ERROR;
}
TraceEnter("SetNatInterfaceInfo");
pToc = GetPointerToTocEntry(IP_NAT_INFO,
pInterfaceInfo);
if(pToc is NULL)
{
//
// NULL means we dont need to change anything
//
Trace1(IF,
"SetNatInterfaceInfo: Nat info is NULL for %S, so leaving",
picb->pwszName);
TraceLeave("SetNatInterfaceInfo");
return NO_ERROR;
}
if(pToc->InfoSize is 0)
{
//
// TOC present, but no info
// This means, delete the interface
//
dwResult = UnbindNatInterface(picb);
if(dwResult isnot NO_ERROR)
{
Trace2(ERR,
"SetNatInterfaceInfo: Error %d unbinding %S",
dwResult,
picb->pwszName);
}
dwResult = DeleteInterfaceFromNat(picb);
if(dwResult isnot NO_ERROR)
{
Trace2(ERR,
"SetNatInterfaceInfo: Error %d deleting interface %S",
dwResult,
picb->pwszName);
}
TraceLeave("SetNatInterfaceInfo");
return dwResult;
}
//
// So we have NAT info
//
if(picb->pvNatContext is NULL)
{
//
// Looks like this interface does not have NAT
//
Trace1(IF,
"SetNatInterfaceInfo: No context, assuming interface %S not added to NAT",
picb->pwszName);
//
// Add the interface to NAT
//
dwResult = AddInterfaceToNat(picb);
if(dwResult isnot NO_ERROR)
{
Trace2(ERR,
"SetNatInterfaceInfo: Error %d adding interface %S",
dwResult,
picb->pwszName);
TraceLeave("SetNatInterfaceInfo");
return dwResult;
}
}
if(picb->pvNatInfo)
{
//
// If we are LAN and UP, then this info has been added for
// proxy ARP. Remove it
// An optimization would be to only remove those addresses that will
// be going away by this set, and then only set those addresses
// that will be coming new due to this set.
// But like I said, that is an _optimization_
//
DeleteNatRangeFromProxyArp(picb);
IpRtAssert(picb->ulNatInfoSize isnot 0);
HeapFree(IPRouterHeap,
0,
picb->pvNatInfo);
}
picb->ulNatInfoSize = 0;
dwInBufLen = pToc->InfoSize;
pNatInfo = (PIP_NAT_INTERFACE_INFO)GetInfoFromTocEntry(pInterfaceInfo,
pToc);
//
// Allocate space for nat info
//
picb->pvNatInfo = HeapAlloc(IPRouterHeap,
0,
dwInBufLen);
if(picb->pvNatInfo is NULL)
{
Trace2(ERR,
"SetNatInterfaceInfo: Error %d allocating memory for %S",
GetLastError(),
picb->pwszName);
TraceLeave("SetNatInterfaceInfo");
return ERROR_NOT_ENOUGH_MEMORY;
}
//
// Save a copy of the info
//
CopyMemory(picb->pvNatInfo,
pNatInfo,
dwInBufLen);
picb->ulNatInfoSize = dwInBufLen;
//
// Fill in the context since that will not be in the info that is
// passed to us
//
pNatInfo->NatInterfaceContext = picb->pvNatContext;
ntStatus = NtDeviceIoControlFile(g_hNatDevice,
NULL,
NULL,
NULL,
&IoStatusBlock,
IOCTL_IP_NAT_SET_INTERFACE_INFO,
(PVOID)pNatInfo,
dwInBufLen,
NULL,
0);
if (!NT_SUCCESS(ntStatus))
{
Trace2(ERR,
"SetNatInterfaceInfo: NtStatus %x adding NAT info for %S",
ntStatus,
picb->pwszName);
TraceLeave("SetNatInterfaceInfo");
return ERROR_CAN_NOT_COMPLETE;
}
TraceLeave("SetNatInterfaceInfo");
return NO_ERROR;
#endif
}
DWORD
GetInterfaceNatInfo(
PICB picb,
PRTR_TOC_ENTRY pToc,
PBYTE pbDataPtr,
PRTR_INFO_BLOCK_HEADER pInfoHdrAndBuffer,
PDWORD pdwSize
)
/*++
Routine Description
This function copies out the saved NAT info to the buffer
Can only be called if NAT is running
Locks
ICB_LIST lock held as READER
Arguments
picb
pToc
pbDataPtr
pInfoHdrAndBuffer
pdwSize
Return Value
None
--*/
{
#if 1
return 0;
#else
TraceEnter("GetInterfaceNatInfo");
if(*pdwSize < picb->ulNatInfoSize)
{
*pdwSize = picb->ulNatInfoSize;
TraceLeave("GetInterfaceNatInfo");
return ERROR_INSUFFICIENT_BUFFER;
}
if(picb->pvNatInfo is NULL)
{
IpRtAssert(picb->ulNatInfoSize is 0);
//
// No data
//
*pdwSize = 0;
TraceLeave("GetInterfaceNatInfo");
return ERROR_NO_DATA;
}
IpRtAssert(picb->pvNatContext);
pToc->InfoType = IP_NAT_INFO;
pToc->Count = 1;
pToc->InfoSize = picb->ulNatInfoSize;
pToc->Offset = pbDataPtr - (PBYTE)pInfoHdrAndBuffer;
CopyMemory(pbDataPtr,
picb->pvNatInfo,
picb->ulNatInfoSize);
*pdwSize = picb->ulNatInfoSize;
TraceLeave("GetInterfaceNatInfo");
return NO_ERROR;
#endif
}
DWORD
BindNatInterface(
PICB picb
)
{
#if 1
return 0;
#else
PIP_NAT_BIND_INTERFACE pnbiBindInfo;
NTSTATUS ntStatus;
IO_STATUS_BLOCK IoStatusBlock;
DWORD i, dwInBufLen, dwResult;
PIP_ADAPTER_BINDING_INFO pBinding;
if((picb->ritType is ROUTER_IF_TYPE_INTERNAL) or
(picb->ritType is ROUTER_IF_TYPE_LOOPBACK) or
(picb->ritType is ROUTER_IF_TYPE_CLIENT))
{
return NO_ERROR;
}
if(!g_bNatRunning)
{
return NO_ERROR;
}
TraceEnter("BindNatInterface");
if(picb->pvNatContext is NULL)
{
Trace1(IF,
"BindNatInterface: No context, assuming interface %S not added to NAT",
picb->pwszName);
TraceLeave("SetAddressFromNat");
return NO_ERROR;
}
//
// Try and set the address to NAT
//
if(picb->dwNumAddresses > 0)
{
dwInBufLen = FIELD_OFFSET(IP_NAT_BIND_INTERFACE, BindingInfo[0]) +
SIZEOF_IP_BINDING(picb->dwNumAddresses);
pnbiBindInfo = HeapAlloc(IPRouterHeap,
HEAP_ZERO_MEMORY,
dwInBufLen);
if(pnbiBindInfo is NULL)
{
dwResult = GetLastError();
Trace2(ERR,
"BindNatInterface: Unable to allocate memory for binding for %S",
dwResult,
picb->pwszName);
TraceLeave("BindNatInterface");
return dwResult;
}
pnbiBindInfo->NatInterfaceContext = picb->pvNatContext;
pBinding = (PIP_ADAPTER_BINDING_INFO)pnbiBindInfo->BindingInfo;
pBinding->NumAddresses = picb->dwNumAddresses;
pBinding->RemoteAddress = picb->dwRemoteAddress;
for(i = 0; i < picb->dwNumAddresses; i++)
{
pBinding->Address[i].IPAddress = picb->pibBindings[i].dwAddress;
pBinding->Address[i].Mask = picb->pibBindings[i].dwMask;
}
ntStatus = NtDeviceIoControlFile(g_hNatDevice,
NULL,
NULL,
NULL,
&IoStatusBlock,
IOCTL_IP_NAT_BIND_INTERFACE,
(PVOID)pnbiBindInfo,
dwInBufLen,
NULL,
0);
if(!NT_SUCCESS(ntStatus))
{
Trace2(ERR,
"BindNatInterface: NtStatus %x setting binding for %S",
ntStatus,
picb->pwszName);
}
}
//
// Set the proxy arp range
// This requires that the NAT info already be part of the ICB
//
SetNatRangeForProxyArp(picb);
//
// Set the context to IP stack
//
dwResult = SetNatContextToIpStack(picb);
if(dwResult isnot NO_ERROR)
{
Trace2(ERR,
"BindNatInterface: Error %d setting context for %S",
dwResult,
picb->pwszName);
}
TraceLeave("BindNatInterface");
return ntStatus;
#endif
}
DWORD
UnbindNatInterface(
PICB picb
)
/*++
Routine Description
Locks
Arguments
Return Value
NO_ERROR
--*/
{
#if 1
return 0;
#else
IP_NAT_UNBIND_INTERFACE ubiUnbindInfo;
NTSTATUS ntStatus;
IO_STATUS_BLOCK IoStatusBlock;
DWORD dwResult;
if((picb->ritType is ROUTER_IF_TYPE_INTERNAL) and
(picb->ritType is ROUTER_IF_TYPE_LOOPBACK) and
(picb->ritType is ROUTER_IF_TYPE_CLIENT))
{
return NO_ERROR;
}
if(!g_bNatRunning)
{
return NO_ERROR;
}
TraceEnter("UnbindNatInterface");
if(picb->pvNatContext is NULL)
{
Trace1(IF,
"ClearAddressToNat: No context, assuming interface %S not added to NAT",
picb->pwszName);
TraceLeave("UnbindNatInterface");
return NO_ERROR;
}
ubiUnbindInfo.NatInterfaceContext = picb->pvNatContext;
ntStatus = NtDeviceIoControlFile(g_hNatDevice,
NULL,
NULL,
NULL,
&IoStatusBlock,
IOCTL_IP_NAT_UNBIND_INTERFACE,
(PVOID)&ubiUnbindInfo,
sizeof(IP_NAT_UNBIND_INTERFACE),
NULL,
0);
if(!NT_SUCCESS(ntStatus))
{
Trace2(ERR,
"UnbindNatInterface: NtStatus %x setting binding for %S",
ntStatus,
picb->pwszName);
}
//
// Blow away the proxy arp stuff
//
DeleteNatRangeFromProxyArp(picb);
dwResult = DeleteNatContextFromIpStack(picb);
if(dwResult isnot NO_ERROR)
{
Trace2(ERR,
"UnbindNatInterface: Error %d removing context for %S",
dwResult,
picb->pwszName);
}
TraceLeave("UnbindNatInterface");
return ntStatus;
#endif
}
DWORD
DeleteInterfaceFromNat(
PICB picb
)
{
#if 1
return 0;
#else
IP_NAT_DELETE_INTERFACE DeleteInfo;
NTSTATUS ntStatus;
IO_STATUS_BLOCK IoStatusBlock;
DWORD dwResult;
TraceEnter("DeleteInterfaceFromNat");
IpRtAssert((picb->ritType isnot ROUTER_IF_TYPE_INTERNAL) and
(picb->ritType isnot ROUTER_IF_TYPE_LOOPBACK) and
(picb->ritType isnot ROUTER_IF_TYPE_CLIENT));
if(picb->pvNatContext is NULL)
{
Trace1(IF,
"DeleteInterfaceFromNat: No context, assuming interface %S not added to NAT",
picb->pwszName);
TraceLeave("DeleteInterfaceFromNat");
return NO_ERROR;
}
//
// Non NULL pvContext means NAT must be running
//
IpRtAssert(g_bNatRunning);
IpRtAssert(g_hNatDevice);
//
// Blow away any saved info
//
if(picb->pvNatInfo)
{
IpRtAssert(picb->ulNatInfoSize isnot 0);
HeapFree(IPRouterHeap,
0,
picb->pvNatInfo);
picb->pvNatInfo = NULL;
}
picb->ulNatInfoSize = 0;
DeleteInfo.NatInterfaceContext = picb->pvNatContext;
dwResult = NO_ERROR;
ntStatus = NtDeviceIoControlFile(g_hNatDevice,
NULL,
NULL,
NULL,
&IoStatusBlock,
IOCTL_IP_NAT_DELETE_INTERFACE,
(PVOID)&DeleteInfo,
sizeof(IP_NAT_DELETE_INTERFACE),
NULL,
0);
if(!NT_SUCCESS(ntStatus))
{
Trace2(ERR,
"DeleteInterfaceFromNat: NtStatus %x deleting %S",
ntStatus,
picb->pwszName);
dwResult = ERROR_CAN_NOT_COMPLETE;
}
picb->pvNatContext = NULL;
TraceLeave("DeleteInterfaceFromNat");
return dwResult;
#endif
}
DWORD
SetNatContextToIpStack(
PICB picb
)
/*++
Routine Description
Sets the NAT context as the FIREWALL context in IP
Can only be called if NAT is running
Locks
The ICB list should be held atleast as READER
Arguments
picb ICB for the interface
Return Value
NO_ERROR
--*/
{
#if 1
return 0;
#else
NTSTATUS ntStatus;
IO_STATUS_BLOCK IoStatusBlock;
DWORD dwResult;
IP_SET_IF_CONTEXT_INFO info;
TraceEnter("SetNatContextToIpStack");
IpRtAssert((picb->ritType isnot ROUTER_IF_TYPE_INTERNAL) and
(picb->ritType isnot ROUTER_IF_TYPE_LOOPBACK) and
(picb->ritType isnot ROUTER_IF_TYPE_CLIENT));
if(picb->pvNatContext is NULL)
{
Trace1(IF,
"SetNatContextToIpStack: No context, assuming interface %S not added to NAT",
picb->pwszName);
return NO_ERROR;
}
if(picb->bBound is FALSE)
{
Trace1(IF,
"SetNatContextToIpStack: Not setting context for %S since it is not bound",
picb->pwszName);
TraceLeave("SetNatContextToIpStack");
return NO_ERROR;
}
info.Index = picb->dwAdapterId;
info.Context = picb->pvNatContext;
ntStatus = NtDeviceIoControlFile(g_hIpDevice,
NULL,
NULL,
NULL,
&IoStatusBlock,
IOCTL_IP_SET_FIREWALL_IF,
(PVOID)&info,
sizeof(IP_SET_IF_CONTEXT_INFO),
NULL,
0);
if(!NT_SUCCESS(ntStatus))
{
Trace2(ERR,
"SetNatContextToIpStack: NtStatus %x while setting context for %S",
ntStatus,
picb->pwszName);
TraceLeave("SetNatContextToIpStack");
return ntStatus;
}
TraceLeave("SetNatContextToIpStack");
return NO_ERROR;
#endif
}
DWORD
DeleteNatContextFromIpStack(
PICB picb
)
/*++
Routine Description
Deletes the the NAT context as the FIREWALL context in IP by setting it
to NULL
Can only be called if NAT is running
Locks
The ICB list should be held as WRITER
Arguments
picb ICB for the interface
Return Value
NO_ERROR
--*/
{
#if 1
return 0;
#else
NTSTATUS ntStatus;
IO_STATUS_BLOCK IoStatusBlock;
DWORD dwResult;
IP_SET_IF_CONTEXT_INFO info;
TraceEnter("DeleteNatContextFromIpStack");
IpRtAssert((picb->ritType isnot ROUTER_IF_TYPE_INTERNAL) and
(picb->ritType isnot ROUTER_IF_TYPE_LOOPBACK) and
(picb->ritType isnot ROUTER_IF_TYPE_CLIENT));
if(picb->pvNatContext is NULL)
{
Trace1(IF,
"DeleteNatContextFromIpStack: No context, assuming interface %S not added to NAT",
picb->pwszName);
return NO_ERROR;
}
if(picb->bBound is FALSE)
{
Trace1(IF,
"DeleteNatContextFromIpStack: Not deleting context for %S since it is not bound",
picb->pwszName);
TraceLeave("DeleteNatContextFromIpStack");
return NO_ERROR;
}
info.Index = picb->dwAdapterId;
info.Context = NULL;
ntStatus = NtDeviceIoControlFile(g_hIpDevice,
NULL,
NULL,
NULL,
&IoStatusBlock,
IOCTL_IP_SET_FIREWALL_IF,
(PVOID)&info,
sizeof(IP_SET_IF_CONTEXT_INFO),
NULL,
0);
if(!NT_SUCCESS(ntStatus))
{
Trace2(ERR,
"DeleteNatContextFromIpStack: NtStatus %x while deleting context for %S",
ntStatus,
picb->pwszName);
TraceLeave("DeleteNatContextFromIpStack");
return ntStatus;
}
TraceLeave("DeleteNatContextFromIpStack");
return NO_ERROR;
#endif
}
VOID
SetNatRangeForProxyArp(
PICB picb
)
/*++
Routine Description
This functions adds any address ranges in the NAT info as Proxy Arp
addresses
Locks
ICB_LIST locked as writer
Arguments
picb ICB of the interface whose nat info is being added
Return Value
NONE we log the errors, there isnt much to do with an error code
--*/
{
#if 1
return;
#else
DWORD dwResult, dwAddr, dwStartAddr, dwEndAddr, i;
PIP_NAT_INTERFACE_INFO pNatInfo;
PIP_NAT_ADDRESS_RANGE pRange;
//
// Only do this if we have a valid adapter index and this is a LAN
// interface
//
if((picb->dwOperationalState < MIB_IF_OPER_STATUS_CONNECTED) or
(picb->ritType isnot ROUTER_IF_TYPE_DEDICATED))
{
return;
}
IpRtAssert(picb->bBound);
IpRtAssert(picb->dwAdapterId isnot INVALID_ADAPTER_ID);
pNatInfo = picb->pvNatInfo;
//
// Now, if we have ranges, we need to set the proxy arp addresses on them
//
for(i = 0; i < pNatInfo->Header.TocEntriesCount; i++)
{
if(pNatInfo->Header.TocEntry[i].InfoType isnot IP_NAT_ADDRESS_RANGE_TYPE)
{
continue;
}
if(pNatInfo->Header.TocEntry[i].InfoSize is 0)
{
continue;
}
//
// Here we are adding potentially duplicate PARP entries.
// Hopefully, IP knows how to handle it
//
pRange = GetInfoFromTocEntry(&(pNatInfo->Header),
&(pNatInfo->Header.TocEntry[i]));
//
// Convert to little endian
//
dwStartAddr = ntohl(pRange->StartAddress);
dwEndAddr = ntohl(pRange->EndAddress);
for(dwAddr = dwStartAddr;
dwAddr <= dwEndAddr;
dwAddr++)
{
DWORD dwNetAddr, dwClassMask;
dwNetAddr = htonl(dwAddr);
//
// Throw away useless addresses and then set proxy arp entries
//
dwClassMask = GetClassMask(dwNetAddr);
if(((dwNetAddr & ~pRange->SubnetMask) is 0) or
(dwNetAddr is (dwNetAddr & ~pRange->SubnetMask)) or
((dwNetAddr & ~dwClassMask) is 0) or
(dwNetAddr is (dwNetAddr & ~dwClassMask)))
{
continue;
}
dwResult = SetProxyArpEntryToStack(dwNetAddr,
0xFFFFFFFF,
picb->dwAdapterId,
TRUE,
FALSE);
if(dwResult isnot NO_ERROR)
{
Trace4(ERR,
"SetProxy: Error %x setting %d.%d.%d.%d over adapter %d (%S)",
dwResult,
PRINT_IPADDR(dwNetAddr),
picb->dwAdapterId,
picb->pwszName);
}
}
}
#endif
}
VOID
DeleteNatRangeFromProxyArp(
PICB picb
)
/*++
Routine Description
This removes the previously added proxy arp addresses
Locks
ICB_LIST lock taken as writer
Arguments
picb The icb of the interface whose addr range info needs to be removed
Return Value
NONE
--*/
{
#if 1
return;
#else
DWORD dwResult, dwAddr, dwStartAddr, dwEndAddr, i;
PIP_NAT_INTERFACE_INFO pNatInfo;
PIP_NAT_ADDRESS_RANGE pRange;
//
// Only do this if we have a valid adapter index and this is a LAN
// interface
//
if((picb->dwOperationalState < MIB_IF_OPER_STATUS_CONNECTED) or
(picb->ritType isnot ROUTER_IF_TYPE_DEDICATED))
{
return;
}
IpRtAssert(picb->bBound);
pNatInfo = picb->pvNatInfo;
for(i = 0; i < pNatInfo->Header.TocEntriesCount; i++)
{
if(pNatInfo->Header.TocEntry[i].InfoType isnot IP_NAT_ADDRESS_RANGE_TYPE)
{
continue;
}
if(pNatInfo->Header.TocEntry[i].InfoSize is 0)
{
continue;
}
//
// Here we are adding potentially duplicate PARP entries.
// Hopefully, IP knows how to handle it
//
pRange = GetInfoFromTocEntry(&(pNatInfo->Header),
&(pNatInfo->Header.TocEntry[i]));
dwStartAddr = ntohl(pRange->StartAddress);
dwEndAddr = ntohl(pRange->EndAddress);
for(dwAddr = dwStartAddr;
dwAddr <= dwEndAddr;
dwAddr++)
{
DWORD dwNetAddr, dwClassMask;
dwNetAddr = htonl(dwAddr);
//
// Throw away useless addresses and then set proxy arp entries
//
dwClassMask = GetClassMask(dwNetAddr);
if(((dwNetAddr & ~pRange->SubnetMask) is 0) or
(dwNetAddr is (dwNetAddr & ~pRange->SubnetMask)) or
((dwNetAddr & ~dwClassMask) is 0) or
(dwNetAddr is (dwNetAddr & ~dwClassMask)))
{
continue;
}
dwResult = SetProxyArpEntryToStack(dwNetAddr,
0xFFFFFFFF,
picb->dwAdapterId,
FALSE,
FALSE);
if(dwResult isnot NO_ERROR)
{
Trace4(ERR,
"DeleteProxy: Error %x removing %d.%d.%d.%d over adapter %d (%S)",
dwResult,
PRINT_IPADDR(dwNetAddr),
picb->dwAdapterId,
picb->pwszName);
}
}
}
#endif
}
DWORD
GetNumNatMappings(
PICB picb,
PULONG pulNatMappings
)
/*++
Routine Description
This function queries the NAT with a minimum sized buffer to figure out
the number of mappings
Can only be called if NAT is running
Locks
ICB_LIST lock held as READER
Arguments
picb, ICB of interface whose map count needs to be queried
pulNatMappings Number of mappings
Return Value
NO_ERROR
--*/
{
#if 1
return 0;
#else
DWORD dwResult;
IP_NAT_INTERFACE_STATISTICS stats;
*pulNatMappings = 0;
dwResult = GetNatStatistics(picb,
&stats);
if(dwResult is NO_ERROR)
{
*pulNatMappings = stats.TotalMappings;
}
return dwResult;
#endif
}
DWORD
GetNatMappings(
PICB picb,
PIP_NAT_ENUMERATE_SESSION_MAPPINGS pBuffer,
DWORD dwSize
)
/*++
Routine Description
This function gets the mappings on the interface
Can only be called if NAT is running
Locks
ICB_LIST held as READER
Arguments
picb
pBuffer
pdwSize
Return Value
None
--*/
{
#if 1
return 0;
#else
IO_STATUS_BLOCK IoStatusBlock;
NTSTATUS nStatus;
if(picb->pvNatContext is NULL)
{
return ERROR_SERVICE_NOT_ACTIVE;
}
IpRtAssert(dwSize >= sizeof(IP_NAT_ENUMERATE_SESSION_MAPPINGS));
//
// Zero out the context and stuff
//
ZeroMemory(pBuffer,
sizeof(IP_NAT_ENUMERATE_SESSION_MAPPINGS));
pBuffer->NatInterfaceContext = picb->pvNatContext;
nStatus = NtDeviceIoControlFile(g_hNatDevice,
NULL,
NULL,
NULL,
&IoStatusBlock,
IOCTL_IP_NAT_ENUMERATE_SESSION_MAPPINGS,
(PVOID)pBuffer,
dwSize,
(PVOID)pBuffer,
dwSize);
if(!NT_SUCCESS(nStatus))
{
Trace1(ERR,
"GetNumNatMappings: NtStatus %x",
nStatus);
return ERROR_CAN_NOT_COMPLETE;
}
return NO_ERROR;
#endif
}
DWORD
GetNatStatistics(
PICB picb,
PIP_NAT_INTERFACE_STATISTICS pBuffer
)
/*++
Routine Description
This function retrieves the nat interface statistics into the supplied
buffer
Locks
ICB_LIST lock held as READER
Arguments
picb
pBuffer
Return Value
None
--*/
{
#if 1
return 0;
#else
IO_STATUS_BLOCK IoStatusBlock;
NTSTATUS nStatus;
if(picb->pvNatContext is NULL)
{
return ERROR_SERVICE_NOT_ACTIVE;
}
pBuffer->NatInterfaceContext = picb->pvNatContext;
nStatus = NtDeviceIoControlFile(g_hNatDevice,
NULL,
NULL,
NULL,
&IoStatusBlock,
IOCTL_IP_NAT_GET_INTERFACE_STATISTICS,
(PVOID)pBuffer,
sizeof(IP_NAT_INTERFACE_STATISTICS),
(PVOID)pBuffer,
sizeof(IP_NAT_INTERFACE_STATISTICS));
if(!NT_SUCCESS(nStatus))
{
Trace1(ERR,
"GetNatStatistics: NtStatus %x",
nStatus);
return ERROR_CAN_NOT_COMPLETE;
}
return NO_ERROR;
#endif
}