Leaked source code of windows server 2003
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.
 
 
 
 
 
 

308 lines
7.8 KiB

/*++
Copyright (c) 1997-2001 Microsoft Corporation
Module Name:
NsConn.h
Abstract:
Declarations for IpSec NAT shim connection entry management
Author:
Jonathan Burstein (jonburs) 10-July-2001
Environment:
Kernel mode
Revision History:
--*/
#pragma once
//
// Structure: _NS_CONNECTION_ENTRY
//
// This structure holds information about a specific active session.
// Each instance is held on the global connection list as well as
// on the global connection trees for inbound and outbound access.
//
// Each connection entry contains 5 pieces of identifying information:
// 1) the address key (local and remote IP addresses)
// 2) the protocol for the connection (TCP or UDP)
// 3) the IpSec context
// 4) the inbound (original) port key
// 5) the outbound (translated) port key
//
// Each time a packet is processed for a connection, the 'l64AccessOrExpiryTime'
// is set to the number of ticks since system-start (KeQueryTickCount).
// This value is used by our timer routine to eliminate expired connections.
//
// For TCP connections, 'l64AccessOrExpiryTime' will no longer be updated once
// FINs are seen in both direction. This is necessary for the timer routine
// to correctly evaluate whether or not the connection has left the time_wait
// state, and thus to prevent premature port reuse.
//
// Synchronization rules:
//
// We use a reference count to ensure the existence of a connection entry,
// and a spin-lock to ensure its consistency.
//
// The fields of a connection entry are only consistent while the spinlock is
// held (with the exception of fields such as 'ul64AddressKey' which are
// read-only and fields such as 'ulReferenceCount' that are interlocked-access
// only.)
//
// The spinlock can only be acquired if
// (a) the reference-count has been incremented, or
// (b) the connection list lock is already held.
//
typedef struct _NS_CONNECTION_ENTRY
{
LIST_ENTRY Link;
RTL_SPLAY_LINKS SLink[NsMaximumDirection];
KSPIN_LOCK Lock;
ULONG ulReferenceCount; // interlocked-access only
ULONG ulFlags;
ULONG64 ul64AddressKey; // read-only
ULONG ulPortKey[NsMaximumDirection]; // read-only
PVOID pvIpSecContext; // read-only
UCHAR ucProtocol; // read-only
LONG64 l64AccessOrExpiryTime;
ULONG ulAccessCount[NsMaximumDirection]; // interlocked-access only
ULONG ulProtocolChecksumDelta[NsMaximumDirection];
PNS_PACKET_ROUTINE PacketRoutine[NsMaximumDirection]; // read-only
} NS_CONNECTION_ENTRY, *PNS_CONNECTION_ENTRY;
//
// Set after a connection entry has been deleted; when the last
// reference is released the entry will be freed
//
#define NS_CONNECTION_FLAG_DELETED 0x80000000
#define NS_CONNECTION_DELETED(c) \
((c)->ulFlags & NS_CONNECTION_FLAG_DELETED)
//
// Set when a connection entry is expired
//
#define NS_CONNECTION_FLAG_EXPIRED 0x00000001
#define NS_CONNECTION_EXPIRED(c) \
((c)->ulFlags & NS_CONNECTION_FLAG_EXPIRED)
//
// Set when inbound / outbound FIN for a TCP session is seen
//
#define NS_CONNECTION_FLAG_OB_FIN 0x00000002
#define NS_CONNECTION_FLAG_IB_FIN 0x00000004
#define NS_CONNECTION_FIN(c) \
(((c)->ulFlags & NS_CONNECTION_FLAG_OB_FIN) \
&& ((c)->ulFlags & NS_CONNECTION_FLAG_IB_FIN))
//
// Connection entry key manipulation macros
//
#define MAKE_ADDRESS_KEY(Key, ulLocalAddress, ulRemoteAddress) \
((Key) = ((ULONG64)(ulLocalAddress) << 32) | (ulRemoteAddress))
#define CONNECTION_LOCAL_ADDRESS(ul64AddressKey) \
((ULONG)(((ul64AddressKey) >> 32) & 0xFFFFFFFF))
#define CONNECTION_REMOTE_ADDRESS(ul64AddressKey) \
((ULONG)((ul64AddressKey)))
#define MAKE_PORT_KEY(Key, usLocalPort, usRemotePort) \
((Key) = ((ULONG)(usLocalPort & 0xFFFF) << 16) | (usRemotePort & 0xFFFF))
#define CONNECTION_LOCAL_PORT(ulPortKey) \
((USHORT)(((ulPortKey) >> 16) & 0xFFFF))
#define CONNECTION_REMOTE_PORT(ulPortKey) \
((USHORT)(ulPortKey))
//
// Resplay threshold; the entry is resplayed every time its access-count
// passes this value.
//
#define NS_CONNECTION_RESPLAY_THRESHOLD 5
//
// Defines the depth of the lookaside list for allocating connection entries
//
#define NS_CONNECTION_LOOKASIDE_DEPTH 20
//
// Connection entry allocation macros
//
#define ALLOCATE_CONNECTION_BLOCK() \
ExAllocateFromNPagedLookasideList(&NsConnectionLookasideList)
#define FREE_CONNECTION_BLOCK(Block) \
ExFreeToNPagedLookasideList(&NsConnectionLookasideList,(Block))
//
// Port range boundaries
//
#define NS_SOURCE_PORT_BASE 6000
#define NS_SOURCE_PORT_END 65534
//
// GLOBAL VARIABLE DECLARATIONS
//
extern CACHE_ENTRY NsConnectionCache[CACHE_SIZE];
extern ULONG NsConnectionCount;
extern LIST_ENTRY NsConnectionList;
extern KSPIN_LOCK NsConnectionLock;
extern NPAGED_LOOKASIDE_LIST NsConnectionLookasideList;
extern PNS_CONNECTION_ENTRY NsConnectionTree[NsMaximumDirection];
extern USHORT NsNextSourcePort;
//
// Function Prototypes
//
NTSTATUS
NsAllocateSourcePort(
ULONG64 ul64AddressKey,
ULONG ulPortKey,
UCHAR ucProtocol,
BOOLEAN fPortConflicts,
PNS_CONNECTION_ENTRY *ppOutboundInsertionPoint,
PULONG pulTranslatedPortKey
);
VOID
NsCleanupConnectionEntry(
PNS_CONNECTION_ENTRY pEntry
);
NTSTATUS
NsCreateConnectionEntry(
ULONG64 ul64AddressKey,
ULONG ulInboundPortKey,
ULONG ulOutboundPortKey,
UCHAR ucProtocol,
PVOID pvIpSecContext,
PNS_CONNECTION_ENTRY pInboundInsertionPoint,
PNS_CONNECTION_ENTRY pOutboundInsertionPoint,
PNS_CONNECTION_ENTRY *ppNewEntry
);
NTSTATUS
NsDeleteConnectionEntry(
PNS_CONNECTION_ENTRY pEntry
);
__forceinline
VOID
NsDereferenceConnectionEntry(
PNS_CONNECTION_ENTRY pEntry
)
{
if (0 == InterlockedDecrement(&pEntry->ulReferenceCount))
{
NsCleanupConnectionEntry(pEntry);
}
}
NTSTATUS
NsInitializeConnectionManagement(
VOID
);
PNS_CONNECTION_ENTRY
NsLookupInboundConnectionEntry(
ULONG64 ul64AddressKey,
ULONG ulPortKey,
UCHAR ucProtocol,
PVOID pvIpSecContext,
BOOLEAN *pfPortConflicts OPTIONAL,
PNS_CONNECTION_ENTRY *ppInsertionPoint OPTIONAL
);
PNS_CONNECTION_ENTRY
NsLookupOutboundConnectionEntry(
ULONG64 ul64AddressKey,
ULONG ulPortKey,
UCHAR ucProtocol,
PNS_CONNECTION_ENTRY *ppInsertionPoint OPTIONAL
);
__forceinline
BOOLEAN
NsReferenceConnectionEntry(
PNS_CONNECTION_ENTRY pEntry
)
{
if (NS_CONNECTION_DELETED(pEntry))
{
return FALSE;
}
else
{
InterlockedIncrement(&pEntry->ulReferenceCount);
return TRUE;
}
}
__forceinline
VOID
NsResplayConnectionEntry(
PNS_CONNECTION_ENTRY pEntry,
IPSEC_NATSHIM_DIRECTION Direction
)
{
PRTL_SPLAY_LINKS SLink;
KeAcquireSpinLockAtDpcLevel(&NsConnectionLock);
if (!NS_CONNECTION_DELETED(pEntry))
{
SLink = RtlSplay(&pEntry->SLink[Direction]);
NsConnectionTree[Direction] =
CONTAINING_RECORD(SLink, NS_CONNECTION_ENTRY, SLink[Direction]);
}
KeReleaseSpinLockFromDpcLevel(&NsConnectionLock);
}
VOID
NsShutdownConnectionManagement(
VOID
);
__forceinline
VOID
NsTryToResplayConnectionEntry(
PNS_CONNECTION_ENTRY pEntry,
IPSEC_NATSHIM_DIRECTION Direction
)
{
if (0 == InterlockedDecrement(&pEntry->ulAccessCount[Direction]))
{
NsResplayConnectionEntry(pEntry, Direction);
InterlockedExchangeAdd(
&pEntry->ulAccessCount[Direction],
NS_CONNECTION_RESPLAY_THRESHOLD
);
}
}