529 lines
12 KiB
C
529 lines
12 KiB
C
/*++
|
||
|
||
Copyright (c) 1997 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
raw.c
|
||
|
||
Abstract:
|
||
|
||
This module contains the code for manipulating IP mappings.
|
||
When the NAT decides to translate an IP packet for an unrecognized protocol
|
||
it creates a mapping and places it on the interface's IP-mapping list,
|
||
so that if a reply to the packet arrives, it can be directed to the
|
||
appropriate client.
|
||
|
||
Author:
|
||
|
||
Abolade Gbadegesin (aboladeg) 18-Apr-1998
|
||
|
||
Revision History:
|
||
|
||
Abolade Gbadegesin (aboladeg) 18-Apr-1998
|
||
|
||
Based on icmp.c.
|
||
|
||
--*/
|
||
|
||
#include "precomp.h"
|
||
#pragma hdrstop
|
||
|
||
//
|
||
// GLOBAL DATA DECLARATIONS
|
||
//
|
||
|
||
NPAGED_LOOKASIDE_LIST IpLookasideList;
|
||
LIST_ENTRY IpMappingList[NatMaximumDirection];
|
||
KSPIN_LOCK IpMappingLock;
|
||
|
||
|
||
NTSTATUS
|
||
NatCreateIpMapping(
|
||
PNAT_INTERFACE Interfacep,
|
||
ULONG RemoteAddress,
|
||
ULONG PrivateAddress,
|
||
ULONG PublicAddress,
|
||
UCHAR Protocol,
|
||
PLIST_ENTRY InboundInsertionPoint,
|
||
PLIST_ENTRY OutboundInsertionPoint,
|
||
PNAT_IP_MAPPING* MappingCreated
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Called to create, initialize, and insert an IP mapping in an interface's
|
||
list of IP mappings.
|
||
|
||
Arguments:
|
||
|
||
Interfacep - the interface for the new mapping
|
||
|
||
RemoteAddress - the address of the remote endpoint
|
||
|
||
PrivateAddress - the address of the machine on the private network
|
||
|
||
PublicAddress - the publicly-visible address to replace 'PrivateAddress';
|
||
in case this is 0, an address is chosen in this routine.
|
||
|
||
Protocol - the protocol field of the IP header
|
||
|
||
InboundInsertionPoint - the entry preceding the new mapping in the list
|
||
sorted for inbound searching
|
||
|
||
OutboundInsertionPoint - the entry preceding the new mapping in the list
|
||
sorted for outbound searching
|
||
|
||
MappingCreated - receives the mapping created
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS - indicates success/failure
|
||
|
||
Environment:
|
||
|
||
Invoked with 'IpMappingLock' held by the caller.
|
||
|
||
--*/
|
||
|
||
{
|
||
PLIST_ENTRY Link;
|
||
PNAT_IP_MAPPING Mapping;
|
||
NTSTATUS status;
|
||
PNAT_IP_MAPPING Temp;
|
||
PNAT_USED_ADDRESS UsedAddress;
|
||
|
||
|
||
CALLTRACE(("NatCreateIpMapping\n"));
|
||
|
||
//
|
||
// Allocate a new mapping
|
||
//
|
||
|
||
Mapping = ALLOCATE_IP_BLOCK();
|
||
if (!Mapping) {
|
||
ERROR(("NatCreateIpMapping: allocation failed\n"));
|
||
return STATUS_NO_MEMORY;
|
||
}
|
||
|
||
//
|
||
// Initialize the mapping
|
||
//
|
||
|
||
Mapping->PrivateKey = MAKE_IP_KEY(RemoteAddress, PrivateAddress);
|
||
Mapping->Protocol = Protocol;
|
||
|
||
//
|
||
// See if the public address is specified, and if not, acquire an address
|
||
//
|
||
|
||
if (!PublicAddress) {
|
||
|
||
//
|
||
// Acquire an address mapping for the IP mapping;
|
||
//
|
||
|
||
KeAcquireSpinLockAtDpcLevel(&Interfacep->Lock);
|
||
status =
|
||
NatAcquireFromAddressPool(
|
||
Interfacep,
|
||
PrivateAddress,
|
||
0,
|
||
&UsedAddress
|
||
);
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
KeReleaseSpinLockFromDpcLevel(&Interfacep->Lock);
|
||
TRACE(IP, ("NatCreateIpMapping: no address available\n"));
|
||
FREE_IP_BLOCK(Mapping);
|
||
return STATUS_UNSUCCESSFUL;
|
||
}
|
||
|
||
PublicAddress = UsedAddress->PublicAddress;
|
||
NatDereferenceAddressPoolEntry(Interfacep, UsedAddress);
|
||
KeReleaseSpinLockFromDpcLevel(&Interfacep->Lock);
|
||
}
|
||
|
||
Mapping->PublicKey = MAKE_IP_KEY(RemoteAddress, PublicAddress);
|
||
|
||
TRACE(
|
||
MAPPING,
|
||
("NatCreateIpMapping: Ip=%d:%016I64X:%016I64X\n",
|
||
Mapping->Protocol, Mapping->PrivateKey, Mapping->PublicKey
|
||
));
|
||
|
||
//
|
||
// Insert the mapping in the inbound list
|
||
//
|
||
|
||
if (!InboundInsertionPoint) {
|
||
Temp =
|
||
NatLookupInboundIpMapping(
|
||
Mapping->PrivateKey,
|
||
Protocol,
|
||
&InboundInsertionPoint
|
||
);
|
||
if (Temp) {
|
||
TRACE(IP, ("NatCreateIpMapping: duplicated inbound mapping\n"));
|
||
return STATUS_UNSUCCESSFUL;
|
||
}
|
||
}
|
||
|
||
//
|
||
// Insert the mapping in the outbound list
|
||
//
|
||
|
||
if (!OutboundInsertionPoint) {
|
||
Temp =
|
||
NatLookupOutboundIpMapping(
|
||
Mapping->PublicKey,
|
||
Protocol,
|
||
&OutboundInsertionPoint
|
||
);
|
||
if (Temp) {
|
||
TRACE(IP, ("NatCreateIpMapping: duplicated outbound mapping\n"));
|
||
return STATUS_UNSUCCESSFUL;
|
||
}
|
||
}
|
||
|
||
InsertTailList(InboundInsertionPoint, &Mapping->Link[NatInboundDirection]);
|
||
InsertTailList(OutboundInsertionPoint, &Mapping->Link[NatOutboundDirection]);
|
||
|
||
*MappingCreated = Mapping;
|
||
return STATUS_SUCCESS;
|
||
|
||
} // NatCreateIpMapping
|
||
|
||
|
||
VOID
|
||
NatInitializeRawIpManagement(
|
||
VOID
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is called to initialize the raw IP-layer translation module.
|
||
|
||
Arguments:
|
||
|
||
none.
|
||
|
||
Return Value:
|
||
|
||
none.
|
||
|
||
--*/
|
||
|
||
{
|
||
KeInitializeSpinLock(&IpMappingLock);
|
||
InitializeListHead(&IpMappingList[NatInboundDirection]);
|
||
InitializeListHead(&IpMappingList[NatOutboundDirection]);
|
||
ExInitializeNPagedLookasideList(
|
||
&IpLookasideList,
|
||
NatAllocateFunction,
|
||
NULL,
|
||
0,
|
||
sizeof(NAT_IP_MAPPING),
|
||
NAT_TAG_IP,
|
||
IP_LOOKASIDE_DEPTH
|
||
);
|
||
} // NatInitializeRawIpManagement
|
||
|
||
|
||
PNAT_IP_MAPPING
|
||
NatLookupInboundIpMapping(
|
||
ULONG64 PublicKey,
|
||
UCHAR Protocol,
|
||
PLIST_ENTRY* InsertionPoint
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is called to find an IP mapping using the remote-address
|
||
and the publicly-visible address, which correspond to the 'PublicKey',
|
||
and the 'Protocol' field.
|
||
|
||
Arguments:
|
||
|
||
PublicKey - the remote-address/public-address combination
|
||
|
||
Protocol - the IP protocol of the mapping to be found
|
||
|
||
InsertionPoint - receives the insertion-point if the mapping is not found.
|
||
|
||
Return Value:
|
||
|
||
PNAT_IP_MAPPING - the mapping found, or NULL if not found.
|
||
|
||
--*/
|
||
|
||
{
|
||
PLIST_ENTRY Link;
|
||
PNAT_IP_MAPPING Mapping;
|
||
|
||
CALLTRACE(("NatLookupInboundIpMapping\n"));
|
||
|
||
if (InsertionPoint) { *InsertionPoint = NULL; }
|
||
|
||
for (Link = IpMappingList[NatInboundDirection].Flink;
|
||
Link != &IpMappingList[NatInboundDirection]; Link = Link->Flink) {
|
||
|
||
Mapping =
|
||
CONTAINING_RECORD(
|
||
Link, NAT_IP_MAPPING, Link[NatInboundDirection]
|
||
);
|
||
|
||
if (PublicKey > Mapping->PublicKey) {
|
||
continue;
|
||
} else if (PublicKey < Mapping->PublicKey) {
|
||
break;
|
||
}
|
||
|
||
//
|
||
// Primary keys equal; check secondary keys.
|
||
//
|
||
|
||
if (Protocol > Mapping->Protocol) {
|
||
continue;
|
||
} else if (Protocol < Mapping->Protocol) {
|
||
break;
|
||
}
|
||
|
||
//
|
||
// Secondary keys equal, too. This is the requested item.
|
||
//
|
||
|
||
return Mapping;
|
||
}
|
||
|
||
if (InsertionPoint) { *InsertionPoint = Link; }
|
||
return NULL;
|
||
|
||
} // NatLookupInboundIpMapping
|
||
|
||
|
||
PNAT_IP_MAPPING
|
||
NatLookupOutboundIpMapping(
|
||
ULONG64 PrivateKey,
|
||
UCHAR Protocol,
|
||
PLIST_ENTRY* InsertionPoint
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is called to find an IP mapping using the remote-address
|
||
and the private address, which correspond to the 'PrivateKey'.
|
||
|
||
Arguments:
|
||
|
||
PrivateKey - the remote-address/private-address combination
|
||
|
||
Protocol - the IP protocol of the mapping to be found
|
||
|
||
InsertionPoint - receives insertion-point if mapping not found.
|
||
|
||
Return Value:
|
||
|
||
PNAT_IP_MAPPING - the mapping found, or NULL if not found.
|
||
|
||
--*/
|
||
|
||
{
|
||
PLIST_ENTRY Link;
|
||
PNAT_IP_MAPPING Mapping;
|
||
|
||
CALLTRACE(("NatLookupOutboundIpMapping\n"));
|
||
|
||
if (InsertionPoint) { *InsertionPoint = NULL; }
|
||
|
||
for (Link = IpMappingList[NatOutboundDirection].Flink;
|
||
Link != &IpMappingList[NatOutboundDirection]; Link = Link->Flink) {
|
||
|
||
Mapping =
|
||
CONTAINING_RECORD(
|
||
Link, NAT_IP_MAPPING, Link[NatOutboundDirection]
|
||
);
|
||
|
||
if (PrivateKey > Mapping->PrivateKey) {
|
||
continue;
|
||
} else if (PrivateKey < Mapping->PrivateKey) {
|
||
break;
|
||
}
|
||
|
||
//
|
||
// Primary keys equal; check secondary keys.
|
||
//
|
||
|
||
if (Protocol > Mapping->Protocol) {
|
||
continue;
|
||
} else if (Protocol < Mapping->Protocol) {
|
||
break;
|
||
}
|
||
|
||
//
|
||
// Keys are equal, so we've found it.
|
||
//
|
||
|
||
return Mapping;
|
||
}
|
||
|
||
if (InsertionPoint) { *InsertionPoint = Link; }
|
||
return NULL;
|
||
|
||
} // NatLookupOutboundIpMapping
|
||
|
||
|
||
VOID
|
||
NatShutdownRawIpManagement(
|
||
VOID
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is called to clean up the raw IP-layer translation module.
|
||
|
||
Arguments:
|
||
|
||
none.
|
||
|
||
Return Value:
|
||
|
||
none.
|
||
|
||
--*/
|
||
|
||
{
|
||
ExDeleteNPagedLookasideList(&IpLookasideList);
|
||
} // NatShutdownRawIpManagement
|
||
|
||
|
||
FORWARD_ACTION
|
||
NatTranslateIp(
|
||
PNAT_INTERFACE Interfacep,
|
||
IP_NAT_DIRECTION Direction,
|
||
PNAT_XLATE_CONTEXT Contextp,
|
||
IPRcvBuf** InReceiveBuffer,
|
||
IPRcvBuf** OutReceiveBuffer
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is called to translate a IP data packet.
|
||
|
||
Arguments:
|
||
|
||
Interfacep - the boundary interface over which to translate.
|
||
|
||
Direction - the direction in which the packet is traveling
|
||
|
||
Contextp - initialized with context-information for the packet
|
||
|
||
InReceiveBuffer - input buffer-chain
|
||
|
||
OutReceiveBuffer - receives modified buffer-chain.
|
||
|
||
Return Value:
|
||
|
||
FORWARD_ACTION - indicates action to take on the packet.
|
||
|
||
Environment:
|
||
|
||
Invoked with a reference made to 'Interfacep' by the caller.
|
||
|
||
--*/
|
||
|
||
{
|
||
ULONG Checksum;
|
||
ULONG ChecksumDelta = 0;
|
||
PIP_HEADER IpHeader;
|
||
PNAT_IP_MAPPING Mapping;
|
||
ULONG64 PrivateKey;
|
||
ULONG64 PublicKey;
|
||
BOOLEAN FirewallMode;
|
||
|
||
TRACE(XLATE, ("NatTranslateIp\n"));
|
||
|
||
FirewallMode = Interfacep && NAT_INTERFACE_FW(Interfacep);
|
||
|
||
IpHeader = Contextp->Header;
|
||
|
||
if (Direction == NatInboundDirection) {
|
||
|
||
//
|
||
// Look for the IP mapping for the data packet
|
||
//
|
||
|
||
PublicKey =
|
||
MAKE_IP_KEY(
|
||
Contextp->SourceAddress,
|
||
Contextp->DestinationAddress
|
||
);
|
||
KeAcquireSpinLockAtDpcLevel(&IpMappingLock);
|
||
Mapping =
|
||
NatLookupInboundIpMapping(
|
||
PublicKey,
|
||
IpHeader->Protocol,
|
||
NULL
|
||
);
|
||
if (!Mapping) {
|
||
KeReleaseSpinLockFromDpcLevel(&IpMappingLock);
|
||
return
|
||
((*Contextp->DestinationType < DEST_REMOTE) && !FirewallMode
|
||
? FORWARD : DROP);
|
||
}
|
||
|
||
CHECKSUM_LONG(ChecksumDelta, ~IpHeader->DestinationAddress);
|
||
IpHeader->DestinationAddress = IP_KEY_PRIVATE(Mapping->PrivateKey);
|
||
CHECKSUM_LONG(ChecksumDelta, IpHeader->DestinationAddress);
|
||
|
||
CHECKSUM_UPDATE(IpHeader->Checksum);
|
||
} else {
|
||
|
||
//
|
||
// Look for the IP mapping for the data packet
|
||
//
|
||
|
||
PrivateKey =
|
||
MAKE_IP_KEY(
|
||
Contextp->DestinationAddress,
|
||
Contextp->SourceAddress
|
||
);
|
||
KeAcquireSpinLockAtDpcLevel(&IpMappingLock);
|
||
Mapping =
|
||
NatLookupOutboundIpMapping(
|
||
PrivateKey,
|
||
IpHeader->Protocol,
|
||
NULL
|
||
);
|
||
if (!Mapping) {
|
||
KeReleaseSpinLockFromDpcLevel(&IpMappingLock);
|
||
return DROP;
|
||
}
|
||
|
||
CHECKSUM_LONG(ChecksumDelta, ~IpHeader->SourceAddress);
|
||
IpHeader->SourceAddress = IP_KEY_PUBLIC(Mapping->PublicKey);
|
||
CHECKSUM_LONG(ChecksumDelta, IpHeader->SourceAddress);
|
||
|
||
CHECKSUM_UPDATE(IpHeader->Checksum);
|
||
}
|
||
|
||
KeQueryTickCount((PLARGE_INTEGER)&Mapping->LastAccessTime);
|
||
KeReleaseSpinLockFromDpcLevel(&IpMappingLock);
|
||
*OutReceiveBuffer = *InReceiveBuffer; *InReceiveBuffer = NULL;
|
||
*Contextp->DestinationType = DEST_INVALID;
|
||
return FORWARD;
|
||
|
||
} // NatTranslateIp
|