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
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
|