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.
532 lines
14 KiB
532 lines
14 KiB
/*++
|
|
|
|
Copyright (c) 1997 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
mapping.h
|
|
|
|
Abstract:
|
|
|
|
This file contains declarations for the management of dynamic mappings.
|
|
This includes the relevant data structures as well as the routines for
|
|
manipulating the structures.
|
|
|
|
Author:
|
|
|
|
Abolade Gbadegesin (t-abolag) 11-July-1997
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#ifndef _NAT_MAPPING_H_
|
|
#define _NAT_MAPPING_H_
|
|
|
|
//
|
|
// Forward declaration of structure defined elsewhere
|
|
//
|
|
|
|
struct _NAT_INTERFACE;
|
|
#define PNAT_INTERFACE struct _NAT_INTERFACE*
|
|
|
|
typedef enum _NAT_SESSION_MAPPING_INFORMATION_CLASS {
|
|
NatKeySessionMappingInformation,
|
|
NatStatisticsSessionMappingInformation,
|
|
#if _WIN32_WINNT > 0x0500
|
|
NatKeySessionMappingExInformation,
|
|
#endif
|
|
NatMaximumSessionMappingInformation
|
|
} NAT_SESSION_MAPPING_INFORMATION_CLASS,
|
|
*PNAT_SESSION_MAPPING_INFORMATION_CLASS;
|
|
|
|
|
|
//
|
|
// Structure: NAT_DYNAMIC_MAPPING
|
|
//
|
|
// This structure holds information about a specific active session.
|
|
// Each instance is held on the global mapping-list as well as
|
|
// on the global mapping-trees for forward and reverse access.
|
|
//
|
|
// Each mapping stores four keys which are address/protocol/port combinations:
|
|
// forward source and destination keys (the original session-endpoints),
|
|
// and reverse source and destination keys (the translated endpoints).
|
|
//
|
|
// Each time a packet is translated using a mapping, the 'LastAccessTime'
|
|
// is set to the number of ticks since system-start (KeQueryTickCount).
|
|
// This value is used by our timer routine to eliminate expired mappings.
|
|
//
|
|
// Synchronization of access to mappings is similar to that of interfaces,
|
|
// editors, and directors:
|
|
//
|
|
// We use a reference count to ensure the existence of a mapping,
|
|
// and a spin-lock to ensure its consistency.
|
|
//
|
|
// The fields of a mapping are only consistent while the spinlock is held
|
|
// (with the exception of fields such as 'PrivateKey' which are read-only)
|
|
//
|
|
// The spinlock can only be acquired if
|
|
// (a) the reference-count has been incremented, or
|
|
// (b) the mapping-list lock is already held.
|
|
//
|
|
// If the mapping is for an edited, directed, or interface's session,
|
|
// it also lives on its editor's, director's or interface's list of mappings.
|
|
// The following holds true of all three lists (i.e. for 'Editor' write
|
|
// 'Director' or 'Interface' as appropriate):
|
|
//
|
|
// As described in 'EDITOR.H', the cached fields 'Editor*' are protected
|
|
// by the global 'EditorMappingLock'. Hence,
|
|
//
|
|
// (a) to read the 'Editor' or 'EditorContext' for a mapping,
|
|
// or to traverse the 'EditorLink' field, 'EditorLock' must be held
|
|
// and the editor referenced. Note that the attempt to reference
|
|
// the editor will fail if the editor has been marked for deletion.
|
|
//
|
|
// (b) to modify the 'Editor' or 'EditorContext' or to add or
|
|
// remove a mapping from its editor's list of mappings by changing
|
|
// the 'EditorLink' field, both 'EditorLock' and 'EditorMappingLock'
|
|
// must be acquired, in that order.
|
|
//
|
|
// Acquisition of 'EditorLock' ensures that the cached editor will not be
|
|
// deleted while being referenced, and acquisition of 'EditorMappingLock'
|
|
// ensures that no changes are being made to the list.
|
|
//
|
|
// N.B. On the rare occasions when 'MappingLock' must be held at the same time
|
|
// as one of 'InterfaceLock', 'EditorLock', and 'DirectorLock', 'MappingLock'
|
|
// must always be acquired first.
|
|
//
|
|
|
|
typedef struct _NAT_DYNAMIC_MAPPING {
|
|
|
|
LIST_ENTRY Link;
|
|
RTL_SPLAY_LINKS SLink[NatMaximumPath];
|
|
ULONG64 DestinationKey[NatMaximumPath]; // read-only
|
|
ULONG64 SourceKey[NatMaximumPath]; // read-only
|
|
LONG64 LastAccessTime;
|
|
|
|
KSPIN_LOCK Lock;
|
|
ULONG ReferenceCount;
|
|
|
|
ULONG AccessCount[NatMaximumPath]; // interlocked-access only
|
|
PNAT_TRANSLATE_ROUTINE TranslateRoutine[NatMaximumPath]; // read-only
|
|
|
|
PNAT_INTERFACE Interfacep;
|
|
PVOID InterfaceContext;
|
|
LIST_ENTRY InterfaceLink;
|
|
|
|
PNAT_EDITOR Editor;
|
|
PVOID EditorContext;
|
|
LIST_ENTRY EditorLink;
|
|
|
|
PNAT_DIRECTOR Director;
|
|
PVOID DirectorContext;
|
|
LIST_ENTRY DirectorLink;
|
|
|
|
ULONG Flags;
|
|
ULONG IpChecksumDelta[NatMaximumPath];
|
|
ULONG ProtocolChecksumDelta[NatMaximumPath];
|
|
|
|
union {
|
|
struct {
|
|
ULONG Expected[NatMaximumPath];
|
|
ULONG Base[NatMaximumPath];
|
|
LONG Delta[NatMaximumPath];
|
|
} TcpSeqNum;
|
|
RTL_SPLAY_LINKS SourceSLink[NatMaximumPath];
|
|
} u;
|
|
|
|
// Maxmimum MSS value. Set to 0 if MSS adjustment is unnecessary.
|
|
USHORT MaxMSS;
|
|
|
|
IP_NAT_SESSION_MAPPING_STATISTICS Statistics;
|
|
ULONG BytesForward; // interlocked-access only
|
|
ULONG BytesReverse; // interlocked-access only
|
|
ULONG PacketsForward; // interlocked-access only
|
|
ULONG PacketsReverse; // interlocked-access only
|
|
ULONG RejectsForward; // interlocked-access only
|
|
ULONG RejectsReverse; // interlocked-access only
|
|
|
|
} NAT_DYNAMIC_MAPPING, *PNAT_DYNAMIC_MAPPING;
|
|
|
|
|
|
//
|
|
// Definition of flags for NAT_DYNAMIC_MAPPING.Flags
|
|
//
|
|
// Set after a mapping has been deleted; when the last reference is released,
|
|
// the mapping will be freed.
|
|
//
|
|
#define NAT_MAPPING_FLAG_DELETED 0x80000000
|
|
#define NAT_MAPPING_DELETED(m) \
|
|
((m)->Flags & NAT_MAPPING_FLAG_DELETED)
|
|
//
|
|
// Set when an editor expires a mapping using 'NatEditorTimeoutSession'.
|
|
//
|
|
#define NAT_MAPPING_FLAG_EXPIRED 0x00000001
|
|
#define NAT_MAPPING_EXPIRED(m) \
|
|
((m)->Flags & NAT_MAPPING_FLAG_EXPIRED)
|
|
//
|
|
// Set when the forward/reverse SYN for a TCP session is seen, respectively
|
|
//
|
|
#define NAT_MAPPING_FLAG_FWD_SYN 0x00000002
|
|
#define NAT_MAPPING_FLAG_REV_SYN 0x00000004
|
|
//
|
|
// Set when the forward/reverse FIN for a TCP session is seen, respectively
|
|
//
|
|
#define NAT_MAPPING_FLAG_FWD_FIN 0x00000008
|
|
#define NAT_MAPPING_FLAG_REV_FIN 0x00000010
|
|
#define NAT_MAPPING_FIN(m) \
|
|
(((m)->Flags & NAT_MAPPING_FLAG_FWD_FIN) && \
|
|
((m)->Flags & NAT_MAPPING_FLAG_REV_FIN))
|
|
//
|
|
// Set when an inbound mapping is created using a static address or port,
|
|
// or because of a director or ticket.
|
|
//
|
|
#define NAT_MAPPING_FLAG_INBOUND 0x00000020
|
|
#define NAT_MAPPING_INBOUND(m) \
|
|
((m)->Flags & NAT_MAPPING_FLAG_INBOUND)
|
|
//
|
|
// Set when a mapping is created by a director and is not subject to expiration.
|
|
//
|
|
#define NAT_MAPPING_FLAG_NO_TIMEOUT 0x00000040
|
|
#define NAT_MAPPING_NO_TIMEOUT(m) \
|
|
((m)->Flags & NAT_MAPPING_FLAG_NO_TIMEOUT)
|
|
//
|
|
// Set when only forward packets are to be translated
|
|
//
|
|
#define NAT_MAPPING_FLAG_UNIDIRECTIONAL 0x00000080
|
|
#define NAT_MAPPING_UNIDIRECTIONAL(m) \
|
|
((m)->Flags & NAT_MAPPING_FLAG_UNIDIRECTIONAL)
|
|
|
|
//
|
|
// Set when director-initiated dissociation should trigger deletion
|
|
//
|
|
#define NAT_MAPPING_FLAG_DELETE_ON_DISSOCIATE_DIRECTOR 0x00000100
|
|
#define NAT_MAPPING_DELETE_ON_DISSOCIATE_DIRECTOR(m) \
|
|
((m)->Flags & NAT_MAPPING_FLAG_DELETE_ON_DISSOCIATE_DIRECTOR)
|
|
|
|
//
|
|
// Set on TCP mappings when the three-way handshake is complete
|
|
//
|
|
#define NAT_MAPPING_FLAG_TCP_OPEN 0x00000200
|
|
#define NAT_MAPPING_TCP_OPEN(m) \
|
|
((m)->Flags & NAT_MAPPING_FLAG_TCP_OPEN)
|
|
//
|
|
// Set if the creation or deletion of this mapping should not
|
|
// be logged
|
|
//
|
|
#define NAT_MAPPING_FLAG_DO_NOT_LOG 0x00000400
|
|
#define NAT_MAPPING_DO_NOT_LOG(m) \
|
|
((m)->Flags & NAT_MAPPING_FLAG_DO_NOT_LOG)
|
|
//
|
|
// Set if the DF bit must be cleared for all packets that belong
|
|
// to this mapping.
|
|
//
|
|
#define NAT_MAPPING_FLAG_CLEAR_DF_BIT 0x00000800
|
|
#define NAT_MAPPING_CLEAR_DF_BIT(m) \
|
|
((m)->Flags & NAT_MAPPING_FLAG_CLEAR_DF_BIT)
|
|
|
|
//
|
|
// Mapping-key manipulation macros
|
|
//
|
|
|
|
#define MAKE_MAPPING_KEY(Key,Protocol,Address,Port) \
|
|
((Key) = \
|
|
(Address) | \
|
|
((ULONG64)((Port) & 0xFFFF) << 32) | \
|
|
((ULONG64)((Protocol) & 0xFF) << 48))
|
|
|
|
#define MAPPING_PROTOCOL(Key) ((UCHAR)(((Key) >> 48) & 0xFF))
|
|
#define MAPPING_PORT(Key) ((USHORT)(((Key) >> 32) & 0xFFFF))
|
|
#define MAPPING_ADDRESS(Key) ((ULONG)(Key))
|
|
|
|
//
|
|
// Resplay threshold; the mapping is resplayed every time its access-count
|
|
// passes this value.
|
|
//
|
|
|
|
#define NAT_MAPPING_RESPLAY_THRESHOLD 5
|
|
|
|
//
|
|
// Defines the depth of the lookaside list for allocating dynamic mappings
|
|
//
|
|
|
|
#define MAPPING_LOOKASIDE_DEPTH 20
|
|
|
|
//
|
|
// Defines the threshold at which ad-hoc cleanup of expired mappings begins.
|
|
//
|
|
|
|
#define MAPPING_CLEANUP_THRESHOLD 1000
|
|
|
|
//
|
|
// Mapping allocation macros
|
|
//
|
|
|
|
#define ALLOCATE_MAPPING_BLOCK() \
|
|
ExAllocateFromNPagedLookasideList(&MappingLookasideList)
|
|
|
|
#define FREE_MAPPING_BLOCK(Block) \
|
|
ExFreeToNPagedLookasideList(&MappingLookasideList,(Block))
|
|
|
|
//
|
|
// GLOBAL VARIABLE DECLARATIONS
|
|
//
|
|
|
|
extern ULONG ExpiredMappingCount;
|
|
extern CACHE_ENTRY MappingCache[NatMaximumPath][CACHE_SIZE];
|
|
extern ULONG MappingCount;
|
|
extern LIST_ENTRY MappingList;
|
|
extern KSPIN_LOCK MappingLock;
|
|
extern NPAGED_LOOKASIDE_LIST MappingLookasideList;
|
|
extern PNAT_DYNAMIC_MAPPING MappingTree[NatMaximumPath];
|
|
|
|
|
|
//
|
|
// MAPPING MANAGEMENT ROUTINES
|
|
//
|
|
|
|
PVOID
|
|
NatAllocateFunction(
|
|
POOL_TYPE PoolType,
|
|
SIZE_T NumberOfBytes,
|
|
ULONG Tag
|
|
);
|
|
|
|
VOID
|
|
NatCleanupMapping(
|
|
PNAT_DYNAMIC_MAPPING Mapping
|
|
);
|
|
|
|
NTSTATUS
|
|
NatCreateMapping(
|
|
ULONG Flags,
|
|
ULONG64 DestinationKey[],
|
|
ULONG64 SourceKey[],
|
|
PNAT_INTERFACE Interfacep,
|
|
PVOID InterfaceContext,
|
|
USHORT MaxMSS,
|
|
PNAT_DIRECTOR Director,
|
|
PVOID DirectorContext,
|
|
PNAT_DYNAMIC_MAPPING* InboundInsertionPoint,
|
|
PNAT_DYNAMIC_MAPPING* OutboundInsertionPoint,
|
|
PNAT_DYNAMIC_MAPPING* MappingCreated
|
|
);
|
|
|
|
NTSTATUS
|
|
NatDeleteMapping(
|
|
PNAT_DYNAMIC_MAPPING Mapping
|
|
);
|
|
|
|
//
|
|
// BOOLEAN
|
|
// NatDereferenceMapping(
|
|
// PNAT_DYNAMIC_MAPPING Mapping
|
|
// );
|
|
//
|
|
|
|
#define \
|
|
NatDereferenceMapping( \
|
|
_Mapping \
|
|
) \
|
|
(InterlockedDecrement(&(_Mapping)->ReferenceCount) \
|
|
? TRUE \
|
|
: (NatCleanupMapping(_Mapping), FALSE))
|
|
|
|
//
|
|
// VOID
|
|
// NatExpireMapping(
|
|
// PNAT_DYNAMIC_MAPPING Mapping
|
|
// );
|
|
//
|
|
|
|
PNAT_DYNAMIC_MAPPING
|
|
NatDestinationLookupForwardMapping(
|
|
ULONG64 DestinationKey
|
|
);
|
|
|
|
PNAT_DYNAMIC_MAPPING
|
|
NatDestinationLookupReverseMapping(
|
|
ULONG64 DestinationKey
|
|
);
|
|
|
|
#define \
|
|
NatExpireMapping( \
|
|
_Mapping \
|
|
) \
|
|
if (!NAT_MAPPING_EXPIRED(_Mapping)) { \
|
|
(_Mapping)->Flags |= NAT_MAPPING_FLAG_EXPIRED; \
|
|
InterlockedIncrement(&ExpiredMappingCount); \
|
|
if (MappingCount > MAPPING_CLEANUP_THRESHOLD && \
|
|
ExpiredMappingCount >= (MappingCount >> 2)) { \
|
|
NatTriggerTimer(); \
|
|
} \
|
|
}
|
|
|
|
|
|
VOID
|
|
NatInitializeMappingManagement(
|
|
VOID
|
|
);
|
|
|
|
PNAT_DYNAMIC_MAPPING
|
|
NatInsertForwardMapping(
|
|
PNAT_DYNAMIC_MAPPING Parent,
|
|
PNAT_DYNAMIC_MAPPING Mapping
|
|
);
|
|
|
|
PNAT_DYNAMIC_MAPPING
|
|
NatInsertReverseMapping(
|
|
PNAT_DYNAMIC_MAPPING Parent,
|
|
PNAT_DYNAMIC_MAPPING Mapping
|
|
);
|
|
|
|
PNAT_DYNAMIC_MAPPING
|
|
NatSourceInsertForwardMapping(
|
|
PNAT_DYNAMIC_MAPPING Parent,
|
|
PNAT_DYNAMIC_MAPPING Mapping
|
|
);
|
|
|
|
PNAT_DYNAMIC_MAPPING
|
|
NatSourceInsertReverseMapping(
|
|
PNAT_DYNAMIC_MAPPING Parent,
|
|
PNAT_DYNAMIC_MAPPING Mapping
|
|
);
|
|
|
|
NTSTATUS
|
|
NatLookupAndQueryInformationMapping(
|
|
UCHAR Protocol,
|
|
ULONG DestinationAddress,
|
|
USHORT DestinationPort,
|
|
ULONG SourceAddress,
|
|
USHORT SourcePort,
|
|
OUT PVOID Information,
|
|
ULONG InformationLength,
|
|
NAT_SESSION_MAPPING_INFORMATION_CLASS InformationClass
|
|
);
|
|
|
|
PNAT_DYNAMIC_MAPPING
|
|
NatLookupForwardMapping(
|
|
ULONG64 DestinationKey,
|
|
ULONG64 SourceKey,
|
|
PNAT_DYNAMIC_MAPPING* InsertionPoint
|
|
);
|
|
|
|
PNAT_DYNAMIC_MAPPING
|
|
NatLookupReverseMapping(
|
|
ULONG64 DestinationKey,
|
|
ULONG64 SourceKey,
|
|
PNAT_DYNAMIC_MAPPING* InsertionPoint
|
|
);
|
|
|
|
VOID
|
|
NatQueryInformationMapping(
|
|
IN PNAT_DYNAMIC_MAPPING Mapping,
|
|
OUT PUCHAR Protocol OPTIONAL,
|
|
OUT PULONG PrivateAddress OPTIONAL,
|
|
OUT PUSHORT PrivatePort OPTIONAL,
|
|
OUT PULONG RemoteAddress OPTIONAL,
|
|
OUT PUSHORT RemotePort OPTIONAL,
|
|
OUT PULONG PublicAddress OPTIONAL,
|
|
OUT PUSHORT PublicPort OPTIONAL,
|
|
OUT PIP_NAT_SESSION_MAPPING_STATISTICS Statistics OPTIONAL
|
|
);
|
|
|
|
NTSTATUS
|
|
NatQueryInterfaceMappingTable(
|
|
IN PIP_NAT_ENUMERATE_SESSION_MAPPINGS InputBuffer,
|
|
IN PIP_NAT_ENUMERATE_SESSION_MAPPINGS OutputBuffer,
|
|
IN PULONG OutputBufferLength
|
|
);
|
|
|
|
NTSTATUS
|
|
NatQueryMappingTable(
|
|
IN PIP_NAT_ENUMERATE_SESSION_MAPPINGS InputBuffer,
|
|
IN PIP_NAT_ENUMERATE_SESSION_MAPPINGS OutputBuffer,
|
|
IN PULONG OutputBufferLength
|
|
);
|
|
|
|
//
|
|
// BOOLEAN
|
|
// NatReferenceMapping(
|
|
// PNAT_DYNAMIC_MAPPING Mapping
|
|
// );
|
|
//
|
|
|
|
#define \
|
|
NatReferenceMapping( \
|
|
_Mapping \
|
|
) \
|
|
(NAT_MAPPING_DELETED(_Mapping) \
|
|
? FALSE \
|
|
: (InterlockedIncrement(&(_Mapping)->ReferenceCount), TRUE))
|
|
|
|
//
|
|
// VOID
|
|
// NatResplayMapping(
|
|
// PNAT_DYNAMIC_MAPPING Mapping,
|
|
// IP_NAT_PATH Path
|
|
// );
|
|
//
|
|
|
|
#define \
|
|
NatResplayMapping( \
|
|
_Mapping, \
|
|
_Path \
|
|
) \
|
|
{ \
|
|
PRTL_SPLAY_LINKS _SLink; \
|
|
KeAcquireSpinLockAtDpcLevel(&MappingLock); \
|
|
if (!NAT_MAPPING_DELETED(_Mapping)) { \
|
|
_SLink = RtlSplay(&(_Mapping)->SLink[_Path]); \
|
|
MappingTree[_Path] = \
|
|
CONTAINING_RECORD(_SLink, NAT_DYNAMIC_MAPPING, SLink[_Path]); \
|
|
} \
|
|
KeReleaseSpinLockFromDpcLevel(&MappingLock); \
|
|
}
|
|
|
|
VOID
|
|
NatShutdownMappingManagement(
|
|
VOID
|
|
);
|
|
|
|
PNAT_DYNAMIC_MAPPING
|
|
NatSourceLookupForwardMapping(
|
|
ULONG64 SourceKey,
|
|
PNAT_DYNAMIC_MAPPING* InsertionPoint
|
|
);
|
|
|
|
PNAT_DYNAMIC_MAPPING
|
|
NatSourceLookupReverseMapping(
|
|
ULONG64 SourceKey,
|
|
PNAT_DYNAMIC_MAPPING* InsertionPoint
|
|
);
|
|
|
|
//
|
|
// VOID
|
|
// NatTryToResplayMapping(
|
|
// PNAT_DYNAMIC_MAPPING Mapping,
|
|
// IP_NAT_PATH Path
|
|
// );
|
|
//
|
|
|
|
#define \
|
|
NatTryToResplayMapping( \
|
|
_Mapping, \
|
|
_Path \
|
|
) \
|
|
if (InterlockedDecrement(&(_Mapping)->AccessCount[(_Path)]) == 0) { \
|
|
NatResplayMapping((_Mapping), (_Path)); \
|
|
InterlockedExchangeAdd( \
|
|
&(_Mapping)->AccessCount[(_Path)], \
|
|
NAT_MAPPING_RESPLAY_THRESHOLD \
|
|
); \
|
|
}
|
|
|
|
VOID
|
|
NatUpdateStatisticsMapping(
|
|
PNAT_DYNAMIC_MAPPING Mapping
|
|
);
|
|
|
|
#undef PNAT_INTERFACE
|
|
|
|
#endif // _NAT_MAPPING_H_
|