Source code of Windows XP (NT5)
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.
 
 
 
 
 
 

528 lines
12 KiB

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