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