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.
446 lines
10 KiB
446 lines
10 KiB
/*++
|
|
|
|
Copyright (c) 1997-2001 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
NsPacket.h
|
|
|
|
Abstract:
|
|
|
|
IpSec NAT shim packet handling routines
|
|
|
|
Author:
|
|
|
|
Jonathan Burstein (jonburs) 11-July-2001
|
|
|
|
Environment:
|
|
|
|
Kernel mode
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "precomp.h"
|
|
#pragma hdrstop
|
|
|
|
|
|
NTSTATUS
|
|
NsInitializePacketManagement(
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is invoked to initialize the packet management module.
|
|
|
|
Arguments:
|
|
|
|
none.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS.
|
|
|
|
--*/
|
|
|
|
{
|
|
CALLTRACE(("NsInitializePacketManagement\n"));
|
|
|
|
return STATUS_SUCCESS;
|
|
} // NsInitializePacketManagement
|
|
|
|
|
|
NTSTATUS
|
|
NsProcessOutgoingPacket(
|
|
IPHeader UNALIGNED *pIpHeader,
|
|
PVOID pvProtocolHeader,
|
|
ULONG ulProtocolHeaderSize,
|
|
PVOID *ppvIpSecContext
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is invoked by IpSec for each outgoing packet. If this
|
|
packet matches a known connection the remote port will be translated
|
|
(if necessary), and the IpSec context will be returned to the caller.
|
|
|
|
Arguments:
|
|
|
|
pIpHeader - points to the IP header for the packet
|
|
|
|
pvProtocolHeader - points to the upper level protocol header (i.e., TCP,
|
|
UDP, or ICMP) for the packet. Will be NULL if this is not a TCP, UDP,
|
|
or ICMP packet.
|
|
|
|
ulProtocolHeaderSize - the length of the buffer pointed to by
|
|
pvProtocolHeader
|
|
|
|
ppvIpSecContext - receives the IpSec context for this packet; will
|
|
receive NULL if this packet does not belong to a known connection.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS.
|
|
|
|
--*/
|
|
|
|
{
|
|
NS_PACKET_CONTEXT Context;
|
|
KIRQL Irql;
|
|
NTSTATUS Status;
|
|
PNS_CONNECTION_ENTRY pEntry;
|
|
ULONG64 ul64AddressKey;
|
|
ULONG ulPortKey;
|
|
|
|
ASSERT(NULL != pIpHeader);
|
|
ASSERT(NULL != ppvIpSecContext);
|
|
|
|
//
|
|
// Set context to default value
|
|
//
|
|
|
|
*ppvIpSecContext = NULL;
|
|
|
|
Status =
|
|
NsBuildPacketContext(
|
|
pIpHeader,
|
|
pvProtocolHeader,
|
|
ulProtocolHeaderSize,
|
|
&Context
|
|
);
|
|
|
|
//
|
|
// Return immediately if the packet is malformed, or if it
|
|
// is not TCP, UDP, or ICMP
|
|
//
|
|
|
|
if (!NT_SUCCESS(Status)
|
|
|| (NS_PROTOCOL_ICMP != Context.ucProtocol
|
|
&& NS_PROTOCOL_TCP != Context.ucProtocol
|
|
&& NS_PROTOCOL_UDP != Context.ucProtocol))
|
|
{
|
|
TRACE(PACKET,
|
|
("NsProcessOutgoingPacket: Bad or non-TCP/UDP/ICMP packet\n"));
|
|
return Status;
|
|
}
|
|
|
|
TRACE(
|
|
PACKET,
|
|
("NsProcessOutgoingPacket: %d: %d.%d.%d.%d/%d -> %d.%d.%d.%d/%d\n",
|
|
Context.ucProtocol,
|
|
ADDRESS_BYTES(Context.ulSourceAddress),
|
|
NTOHS(Context.usSourcePort),
|
|
ADDRESS_BYTES(Context.ulDestinationAddress),
|
|
NTOHS(Context.usDestinationPort)
|
|
));
|
|
|
|
if (NS_PROTOCOL_ICMP != Context.ucProtocol)
|
|
{
|
|
//
|
|
// Build the connection lookup keys
|
|
//
|
|
|
|
MAKE_ADDRESS_KEY(
|
|
ul64AddressKey,
|
|
Context.ulSourceAddress,
|
|
Context.ulDestinationAddress
|
|
);
|
|
|
|
MAKE_PORT_KEY(
|
|
ulPortKey,
|
|
Context.usSourcePort,
|
|
Context.usDestinationPort
|
|
);
|
|
|
|
//
|
|
// See if this packet matches an existing connection entry
|
|
//
|
|
|
|
KeAcquireSpinLock(&NsConnectionLock, &Irql);
|
|
|
|
pEntry =
|
|
NsLookupOutboundConnectionEntry(
|
|
ul64AddressKey,
|
|
ulPortKey,
|
|
Context.ucProtocol,
|
|
NULL
|
|
);
|
|
|
|
if (NULL != pEntry
|
|
&& NsReferenceConnectionEntry(pEntry))
|
|
{
|
|
KeReleaseSpinLockFromDpcLevel(&NsConnectionLock);
|
|
|
|
*ppvIpSecContext = pEntry->pvIpSecContext;
|
|
Status =
|
|
pEntry->PacketRoutine[NsOutboundDirection](pEntry, &Context);
|
|
|
|
NsDereferenceConnectionEntry(pEntry);
|
|
KeLowerIrql(Irql);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// No match (or entry already deleted) -- nothing more to do.
|
|
//
|
|
|
|
KeReleaseSpinLock(&NsConnectionLock, Irql);
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Branch to ICMP logic
|
|
//
|
|
|
|
Status = NsProcessOutgoingIcmpPacket(&Context, ppvIpSecContext);
|
|
}
|
|
|
|
return Status;
|
|
} // NsProcessOutgoingPacket
|
|
|
|
|
|
NTSTATUS
|
|
NsProcessIncomingPacket(
|
|
IPHeader UNALIGNED *pIpHeader,
|
|
PVOID pvProtocolHeader,
|
|
ULONG ulProtocolHeaderSize,
|
|
PVOID pvIpSecContext
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is invoked by IpSec for each incoming packet. It
|
|
will record the connection information and context for the
|
|
packet (if such information does not yet exist), and, if necessary,
|
|
allocate a new remote port and modify the packet accordingly.
|
|
|
|
Arguments:
|
|
|
|
pIpHeader - points to the IP header for the packet
|
|
|
|
pvProtocolHeader - points to the upper level protocol header (i.e., TCP,
|
|
UDP, or ICMP) for the packet. Will be NULL if this is not a TCP, UDP,
|
|
or ICMP packet.
|
|
|
|
ulProtocolHeaderSize - the length of the buffer pointed to by
|
|
pvProtocolHeader
|
|
|
|
pvIpSecContext - the IpSec context for this packet; this is considered
|
|
an opaque value.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS.
|
|
|
|
--*/
|
|
|
|
{
|
|
NS_PACKET_CONTEXT Context;
|
|
BOOLEAN fPortConflicts;
|
|
KIRQL Irql;
|
|
NTSTATUS Status;
|
|
PNS_CONNECTION_ENTRY pEntry;
|
|
PNS_CONNECTION_ENTRY pInboundInsertionPoint;
|
|
PNS_CONNECTION_ENTRY pOutboundInsertionPoint;
|
|
ULONG64 ul64AddressKey;
|
|
ULONG ulPortKey;
|
|
ULONG ulTranslatedPortKey;
|
|
|
|
ASSERT(NULL != pIpHeader);
|
|
|
|
Status =
|
|
NsBuildPacketContext(
|
|
pIpHeader,
|
|
pvProtocolHeader,
|
|
ulProtocolHeaderSize,
|
|
&Context
|
|
);
|
|
|
|
//
|
|
// Return immediately if the packet is malformed, or if it
|
|
// is not TCP, UDP, or ICMP
|
|
//
|
|
|
|
if (!NT_SUCCESS(Status)
|
|
|| (NS_PROTOCOL_ICMP != Context.ucProtocol
|
|
&& NS_PROTOCOL_TCP != Context.ucProtocol
|
|
&& NS_PROTOCOL_UDP != Context.ucProtocol))
|
|
{
|
|
TRACE(PACKET,
|
|
("NsProcessIncomingPacket: Bad or non-TCP/UDP/ICMP packet\n"));
|
|
return Status;
|
|
}
|
|
|
|
TRACE(
|
|
PACKET,
|
|
("NsProcessIncomingPacket: %d: %d.%d.%d.%d/%d -> %d.%d.%d.%d/%d\n",
|
|
Context.ucProtocol,
|
|
ADDRESS_BYTES(Context.ulSourceAddress),
|
|
NTOHS(Context.usSourcePort),
|
|
ADDRESS_BYTES(Context.ulDestinationAddress),
|
|
NTOHS(Context.usDestinationPort)
|
|
));
|
|
|
|
if (NS_PROTOCOL_ICMP != Context.ucProtocol)
|
|
{
|
|
//
|
|
// Build the connection lookup keys
|
|
//
|
|
|
|
MAKE_ADDRESS_KEY(
|
|
ul64AddressKey,
|
|
Context.ulDestinationAddress,
|
|
Context.ulSourceAddress
|
|
);
|
|
|
|
MAKE_PORT_KEY(
|
|
ulPortKey,
|
|
Context.usDestinationPort,
|
|
Context.usSourcePort
|
|
);
|
|
|
|
KeAcquireSpinLock(&NsConnectionLock, &Irql);
|
|
|
|
//
|
|
// See if this packet matches an existing connection entry
|
|
//
|
|
|
|
pEntry =
|
|
NsLookupInboundConnectionEntry(
|
|
ul64AddressKey,
|
|
ulPortKey,
|
|
Context.ucProtocol,
|
|
pvIpSecContext,
|
|
&fPortConflicts,
|
|
&pInboundInsertionPoint
|
|
);
|
|
|
|
if (NULL != pEntry
|
|
&& NsReferenceConnectionEntry(pEntry))
|
|
{
|
|
KeReleaseSpinLockFromDpcLevel(&NsConnectionLock);
|
|
|
|
Status =
|
|
pEntry->PacketRoutine[NsInboundDirection](pEntry, &Context);
|
|
|
|
NsDereferenceConnectionEntry(pEntry);
|
|
KeLowerIrql(Irql);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// No valid connection entry was found for this packet. Allocate
|
|
// a new source port for the connection (if necessary).
|
|
//
|
|
|
|
Status =
|
|
NsAllocateSourcePort(
|
|
ul64AddressKey,
|
|
ulPortKey,
|
|
Context.ucProtocol,
|
|
fPortConflicts,
|
|
&pOutboundInsertionPoint,
|
|
&ulTranslatedPortKey
|
|
);
|
|
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
//
|
|
// Create the new connection entry
|
|
//
|
|
|
|
Status =
|
|
NsCreateConnectionEntry(
|
|
ul64AddressKey,
|
|
ulPortKey,
|
|
ulTranslatedPortKey,
|
|
Context.ucProtocol,
|
|
pvIpSecContext,
|
|
pInboundInsertionPoint,
|
|
pOutboundInsertionPoint,
|
|
&pEntry
|
|
);
|
|
|
|
KeReleaseSpinLockFromDpcLevel(&NsConnectionLock);
|
|
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
Status =
|
|
pEntry->PacketRoutine[NsInboundDirection](
|
|
pEntry,
|
|
&Context
|
|
);
|
|
|
|
NsDereferenceConnectionEntry(pEntry);
|
|
}
|
|
|
|
KeLowerIrql(Irql);
|
|
}
|
|
else
|
|
{
|
|
KeReleaseSpinLock(&NsConnectionLock, Irql);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Branch to ICMP logic
|
|
//
|
|
|
|
Status = NsProcessIncomingIcmpPacket(&Context, pvIpSecContext);
|
|
}
|
|
|
|
return Status;
|
|
} // NsProcessIncomingPacket
|
|
|
|
|
|
VOID
|
|
NsShutdownPacketManagement(
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is invoked to shutdown the packet management module.
|
|
|
|
Arguments:
|
|
|
|
none.
|
|
|
|
Return Value:
|
|
|
|
none.
|
|
|
|
--*/
|
|
|
|
{
|
|
CALLTRACE(("NsShutdownPacketManagement\n"));
|
|
} // NsShutdownPacketManagement
|
|
|
|
//
|
|
// Now include the code for the per-packet routines --
|
|
// see NsPacketRoutines.h for details
|
|
//
|
|
|
|
#define NS_INBOUND
|
|
#include "NsPacketRoutines.h"
|
|
#undef NS_INBOUND
|
|
|
|
#define NS_OUTBOUND
|
|
#include "NsPacketRoutines.h"
|
|
#undef NS_OUTBOUND
|
|
|
|
|