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.
875 lines
24 KiB
875 lines
24 KiB
/*++
|
|
|
|
Copyright (c) 1999-2001 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
gpc.c
|
|
|
|
Abstract:
|
|
|
|
This module contains the GPC implementation
|
|
|
|
Author:
|
|
|
|
ChunYe
|
|
|
|
Environment:
|
|
|
|
Kernel mode
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
|
|
#include "precomp.h"
|
|
|
|
#ifdef RUN_WPP
|
|
#include "gpc.tmh"
|
|
#endif
|
|
|
|
#if GPC
|
|
|
|
|
|
NTSTATUS
|
|
IPSecGpcInitialize()
|
|
{
|
|
NTSTATUS status;
|
|
INT cf, i;
|
|
|
|
PAGED_CODE();
|
|
|
|
//
|
|
// Initialize FilterList for patterns that are not installed in GPC.
|
|
//
|
|
for (i = MIN_FILTER; i <= MAX_FILTER; i++) {
|
|
InitializeListHead(&g_ipsec.GpcFilterList[i]);
|
|
}
|
|
|
|
//
|
|
// Start with inactive state for the error path.
|
|
//
|
|
IPSEC_DRIVER_INIT_GPC() = FALSE;
|
|
IPSEC_UNSET_GPC_ACTIVE();
|
|
|
|
//
|
|
// GPC registration.
|
|
//
|
|
status = GpcInitialize(&g_ipsec.GpcEntries);
|
|
|
|
if (status == STATUS_SUCCESS) {
|
|
for (cf = GPC_CF_IPSEC_MIN; cf <= GPC_CF_IPSEC_MAX; cf++) {
|
|
status = GPC_REGISTER_CLIENT( cf,
|
|
0,
|
|
GPC_PRIORITY_IPSEC,
|
|
NULL,
|
|
NULL,
|
|
&g_ipsec.GpcClients[cf]);
|
|
|
|
if (status != STATUS_SUCCESS) {
|
|
IPSEC_DEBUG(LL_A, DBF_LOAD, ("GPC failed to register cf %d", cf));
|
|
|
|
g_ipsec.GpcClients[cf] = NULL;
|
|
IPSecGpcDeinitialize();
|
|
|
|
return status;
|
|
}
|
|
}
|
|
} else {
|
|
IPSEC_DEBUG(LL_A, DBF_LOAD, ("Failed to init GPC structures"));
|
|
return status;
|
|
}
|
|
|
|
IPSEC_SET_GPC_ACTIVE();
|
|
IPSEC_DRIVER_INIT_GPC() = TRUE;
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
IPSecGpcDeinitialize()
|
|
{
|
|
INT cf;
|
|
|
|
PAGED_CODE();
|
|
|
|
IPSEC_UNSET_GPC_ACTIVE();
|
|
|
|
//
|
|
// GPC deregistration.
|
|
//
|
|
for (cf = GPC_CF_IPSEC_MIN; cf <= GPC_CF_IPSEC_MAX; cf++) {
|
|
if (g_ipsec.GpcClients[cf]) {
|
|
GPC_DEREGISTER_CLIENT(g_ipsec.GpcClients[cf]);
|
|
}
|
|
}
|
|
|
|
GpcDeinitialize(&g_ipsec.GpcEntries);
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
IPSecEnableGpc()
|
|
{
|
|
KIRQL kIrql;
|
|
|
|
PAGED_CODE();
|
|
|
|
if (IPSEC_DRIVER_INIT_GPC()) {
|
|
AcquireWriteLock(&g_ipsec.SADBLock, &kIrql);
|
|
|
|
IPSEC_SET_GPC_ACTIVE();
|
|
|
|
ReleaseWriteLock(&g_ipsec.SADBLock, kIrql);
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
IPSecDisableGpc()
|
|
{
|
|
KIRQL kIrql;
|
|
|
|
PAGED_CODE();
|
|
|
|
if (IPSEC_DRIVER_INIT_GPC()) {
|
|
AcquireWriteLock(&g_ipsec.SADBLock, &kIrql);
|
|
|
|
IPSEC_UNSET_GPC_ACTIVE();
|
|
|
|
ReleaseWriteLock(&g_ipsec.SADBLock, kIrql);
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
IPSecInitGpcFilter(
|
|
IN PFILTER pFilter,
|
|
IN PGPC_IP_PATTERN pPattern,
|
|
IN PGPC_IP_PATTERN pMask
|
|
)
|
|
{
|
|
PAGED_CODE();
|
|
|
|
RtlZeroMemory(pPattern, sizeof(GPC_IP_PATTERN));
|
|
RtlZeroMemory(pMask, sizeof(GPC_IP_PATTERN));
|
|
|
|
pPattern->SrcAddr = pFilter->SRC_ADDR;
|
|
pPattern->DstAddr = pFilter->DEST_ADDR;
|
|
pPattern->ProtocolId = (UCHAR)pFilter->PROTO;
|
|
pPattern->gpcSrcPort = FI_SRC_PORT(pFilter);
|
|
pPattern->gpcDstPort = FI_DEST_PORT(pFilter);
|
|
|
|
pMask->SrcAddr = pFilter->SRC_MASK;
|
|
pMask->DstAddr = pFilter->DEST_MASK;
|
|
pMask->ProtocolId = (UCHAR)IPSEC_GPC_MASK_ALL;
|
|
pMask->gpcSrcPort = IPSEC_GPC_MASK_NONE;
|
|
pMask->gpcDstPort = IPSEC_GPC_MASK_NONE;
|
|
|
|
switch (pFilter->PROTO) {
|
|
case FILTER_PROTO_ANY:
|
|
if (FI_SRC_PORT(pFilter) != FILTER_TCPUDP_PORT_ANY) {
|
|
RtlFillMemory( &pMask->gpcSrcPort,
|
|
sizeof(pMask->gpcSrcPort),
|
|
IPSEC_GPC_MASK_ALL);
|
|
}
|
|
if (FI_DEST_PORT(pFilter) != FILTER_TCPUDP_PORT_ANY) {
|
|
RtlFillMemory( &pMask->gpcDstPort,
|
|
sizeof(pMask->gpcDstPort),
|
|
IPSEC_GPC_MASK_ALL);
|
|
}
|
|
pMask->ProtocolId = (UCHAR)IPSEC_GPC_MASK_NONE;
|
|
break;
|
|
|
|
case FILTER_PROTO_TCP:
|
|
case FILTER_PROTO_UDP:
|
|
if (FI_SRC_PORT(pFilter) != FILTER_TCPUDP_PORT_ANY) {
|
|
RtlFillMemory( &pMask->gpcSrcPort,
|
|
sizeof(pMask->gpcSrcPort),
|
|
IPSEC_GPC_MASK_ALL);
|
|
}
|
|
if (FI_DEST_PORT(pFilter) != FILTER_TCPUDP_PORT_ANY) {
|
|
RtlFillMemory( &pMask->gpcDstPort,
|
|
sizeof(pMask->gpcDstPort),
|
|
IPSEC_GPC_MASK_ALL);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
IPSecInsertGpcPattern(
|
|
IN PFILTER pFilter
|
|
)
|
|
{
|
|
CLASSIFICATION_HANDLE GpcHandle;
|
|
GPC_IP_PATTERN GpcPattern;
|
|
GPC_IP_PATTERN GpcMask;
|
|
ULONG GpcPriority;
|
|
INT GpcCf;
|
|
NTSTATUS status;
|
|
|
|
PAGED_CODE();
|
|
|
|
GpcCf = IPSecResolveGpcCf(IS_OUTBOUND_FILTER(pFilter));
|
|
|
|
//
|
|
// Add the filter as a CfInfo
|
|
//
|
|
status = GPC_ADD_CFINFO(g_ipsec.GpcClients[GpcCf],
|
|
sizeof(PFILTER),
|
|
(PVOID)&pFilter,
|
|
(GPC_CLIENT_HANDLE)pFilter,
|
|
&pFilter->GpcFilter.GpcCfInfoHandle);
|
|
|
|
if (status == STATUS_SUCCESS) {
|
|
//
|
|
// Now add the filter as a pattern
|
|
//
|
|
IPSecInitGpcFilter(pFilter, &GpcPattern, &GpcMask);
|
|
|
|
if (FI_DEST_PORT(pFilter) == FILTER_TCPUDP_PORT_ANY) {
|
|
GpcPriority = 1;
|
|
} else {
|
|
GpcPriority = 0;
|
|
}
|
|
|
|
ASSERT(GpcPriority < GPC_PRIORITY_IPSEC);
|
|
|
|
status = GPC_ADD_PATTERN( g_ipsec.GpcClients[GpcCf],
|
|
GPC_PROTOCOL_TEMPLATE_IP,
|
|
&GpcPattern,
|
|
&GpcMask,
|
|
GpcPriority,
|
|
pFilter->GpcFilter.GpcCfInfoHandle,
|
|
&pFilter->GpcFilter.GpcPatternHandle,
|
|
&GpcHandle);
|
|
|
|
if (status != STATUS_SUCCESS) {
|
|
IPSEC_DEBUG(LL_A, DBF_GPC, ("GpcAddPattern: failed with status %lx", status));
|
|
|
|
GPC_REMOVE_CFINFO( g_ipsec.GpcClients[GpcCf],
|
|
pFilter->GpcFilter.GpcCfInfoHandle);
|
|
|
|
pFilter->GpcFilter.GpcCfInfoHandle = NULL;
|
|
pFilter->GpcFilter.GpcPatternHandle = NULL;
|
|
} else {
|
|
g_ipsec.GpcNumFilters[GpcPriority]++;
|
|
}
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
IPSecDeleteGpcPattern(
|
|
IN PFILTER pFilter
|
|
)
|
|
{
|
|
ULONG GpcPriority;
|
|
INT GpcCf = IPSecResolveGpcCf(IS_OUTBOUND_FILTER(pFilter));
|
|
|
|
PAGED_CODE();
|
|
|
|
if (pFilter->GpcFilter.GpcPatternHandle) {
|
|
GPC_REMOVE_PATTERN( g_ipsec.GpcClients[GpcCf],
|
|
pFilter->GpcFilter.GpcPatternHandle);
|
|
|
|
pFilter->GpcFilter.GpcPatternHandle = NULL;
|
|
|
|
ASSERT(pFilter->GpcFilter.GpcCfInfoHandle);
|
|
|
|
if (pFilter->GpcFilter.GpcCfInfoHandle) {
|
|
GPC_REMOVE_CFINFO( g_ipsec.GpcClients[GpcCf],
|
|
pFilter->GpcFilter.GpcCfInfoHandle);
|
|
|
|
pFilter->GpcFilter.GpcCfInfoHandle = NULL;
|
|
}
|
|
|
|
if (FI_DEST_PORT(pFilter) == FILTER_TCPUDP_PORT_ANY) {
|
|
GpcPriority = 1;
|
|
} else {
|
|
GpcPriority = 0;
|
|
}
|
|
|
|
ASSERT(GpcPriority < GPC_PRIORITY_IPSEC);
|
|
|
|
g_ipsec.GpcNumFilters[GpcPriority]--;
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
IPSecInsertGpcFilter(
|
|
IN PFILTER pFilter
|
|
)
|
|
{
|
|
NTSTATUS status;
|
|
PFILTER pTempFilter;
|
|
BOOL InsertedFilter = FALSE;
|
|
PLIST_ENTRY pEntry, pPrev;
|
|
PLIST_ENTRY pFilterList;
|
|
KIRQL kIrql;
|
|
|
|
PAGED_CODE();
|
|
|
|
AcquireWriteLock(&g_ipsec.SADBLock, &kIrql);
|
|
|
|
pFilterList = IPSecResolveGpcFilterList(IS_TUNNEL_FILTER(pFilter),
|
|
IS_OUTBOUND_FILTER(pFilter));
|
|
|
|
pEntry = pFilterList->Flink;
|
|
pPrev = pFilterList;
|
|
|
|
while (pEntry != pFilterList) {
|
|
pTempFilter = CONTAINING_RECORD(pEntry,
|
|
FILTER,
|
|
GpcLinkage);
|
|
|
|
if (pFilter->Index > pTempFilter->Index) {
|
|
//
|
|
// found the spot, insert it before pTempFilter
|
|
//
|
|
InsertHeadList(pPrev, &pFilter->GpcLinkage);
|
|
InsertedFilter = TRUE;
|
|
break;
|
|
}
|
|
|
|
pPrev = pEntry;
|
|
pEntry = pEntry->Flink;
|
|
}
|
|
|
|
if (!InsertedFilter) {
|
|
//
|
|
// didn't find spot, stick it in the end
|
|
//
|
|
InsertTailList(pFilterList, &pFilter->GpcLinkage);
|
|
}
|
|
|
|
ReleaseWriteLock(&g_ipsec.SADBLock, kIrql);
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
IPSecDeleteGpcFilter(
|
|
IN PFILTER pFilter
|
|
)
|
|
{
|
|
KIRQL kIrql;
|
|
|
|
PAGED_CODE();
|
|
|
|
if (!pFilter->GpcLinkage.Flink || !pFilter->GpcLinkage.Blink) {
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
AcquireWriteLock(&g_ipsec.SADBLock, &kIrql);
|
|
|
|
IPSecRemoveEntryList(&pFilter->GpcLinkage);
|
|
|
|
ReleaseWriteLock(&g_ipsec.SADBLock, kIrql);
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
IPSecInstallGpcFilter(
|
|
IN PFILTER pFilter
|
|
)
|
|
{
|
|
PAGED_CODE();
|
|
|
|
if (IS_TUNNEL_FILTER(pFilter)) {
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
if (IS_GPC_FILTER(pFilter)) {
|
|
return IPSecInsertGpcPattern(pFilter);
|
|
} else {
|
|
return IPSecInsertGpcFilter(pFilter);
|
|
}
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
IPSecUninstallGpcFilter(
|
|
IN PFILTER pFilter
|
|
)
|
|
{
|
|
PAGED_CODE();
|
|
|
|
if (IS_TUNNEL_FILTER(pFilter)) {
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
if (IS_GPC_FILTER(pFilter)) {
|
|
return IPSecDeleteGpcPattern(pFilter);
|
|
} else {
|
|
return IPSecDeleteGpcFilter(pFilter);
|
|
}
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
IPSecLookupGpcSA(
|
|
IN ULARGE_INTEGER uliSrcDstAddr,
|
|
IN ULARGE_INTEGER uliProtoSrcDstPort,
|
|
IN CLASSIFICATION_HANDLE GpcHandle,
|
|
OUT PFILTER *ppFilter,
|
|
OUT PSA_TABLE_ENTRY *ppSA,
|
|
OUT PSA_TABLE_ENTRY *ppNextSA,
|
|
OUT PSA_TABLE_ENTRY *ppTunnelSA,
|
|
IN BOOLEAN fOutbound,
|
|
IN BOOLEAN fVerify,
|
|
IN PIPSEC_UDP_ENCAP_CONTEXT pNatContext
|
|
)
|
|
{
|
|
PFILTER pFilter;
|
|
PFILTER pTempFilter;
|
|
PLIST_ENTRY pEntry;
|
|
PLIST_ENTRY pFilterList;
|
|
PLIST_ENTRY pSAChain;
|
|
PSA_TABLE_ENTRY pSA;
|
|
REGISTER ULARGE_INTEGER uliPort;
|
|
REGISTER ULARGE_INTEGER uliAddr;
|
|
BOOLEAN fFound = FALSE;
|
|
INT GpcCf;
|
|
CLASSIFICATION_HANDLE TempGpcHandle;
|
|
|
|
*ppSA = NULL;
|
|
*ppFilter = NULL;
|
|
*ppTunnelSA = NULL;
|
|
|
|
//
|
|
// Search in Tunnel filters list first.
|
|
//
|
|
pFilterList = IPSecResolveFilterList(TRUE, fOutbound);
|
|
|
|
for ( pEntry = pFilterList->Flink;
|
|
pEntry != pFilterList;
|
|
pEntry = pEntry->Flink) {
|
|
|
|
pFilter = CONTAINING_RECORD(pEntry,
|
|
FILTER,
|
|
MaskedLinkage);
|
|
|
|
uliAddr.QuadPart = uliSrcDstAddr.QuadPart & pFilter->uliSrcDstMask.QuadPart;
|
|
uliPort.QuadPart = uliProtoSrcDstPort.QuadPart & pFilter->uliProtoSrcDstMask.QuadPart;
|
|
|
|
if ((uliAddr.QuadPart == pFilter->uliSrcDstAddr.QuadPart) &&
|
|
(uliPort.QuadPart == pFilter->uliProtoSrcDstPort.QuadPart)) {
|
|
//
|
|
// Found filter
|
|
//
|
|
fFound = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (fFound) {
|
|
//
|
|
// Search for the particular SA now.
|
|
//
|
|
fFound = FALSE;
|
|
|
|
pSAChain = IPSecResolveSAChain(pFilter, fOutbound? DEST_ADDR: SRC_ADDR);
|
|
|
|
for ( pEntry = pSAChain->Flink;
|
|
pEntry != pSAChain;
|
|
pEntry = pEntry->Flink) {
|
|
|
|
pSA = CONTAINING_RECORD(pEntry,
|
|
SA_TABLE_ENTRY,
|
|
sa_FilterLinkage);
|
|
|
|
ASSERT(pSA->sa_Flags & FLAGS_SA_TUNNEL);
|
|
|
|
if (pFilter->TunnelAddr != 0 && EQUAL_NATENCAP(pNatContext,pSA)) {
|
|
//
|
|
// match the outbound flag also
|
|
//
|
|
ASSERT(fOutbound == (BOOLEAN)((pSA->sa_Flags & FLAGS_SA_OUTBOUND) != 0));
|
|
fFound = TRUE;
|
|
*ppTunnelSA = pSA;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (fFound) {
|
|
fFound = FALSE;
|
|
*ppFilter = pFilter;
|
|
} else {
|
|
//
|
|
// Found a filter entry, but need to negotiate keys.
|
|
//
|
|
*ppFilter = pFilter;
|
|
return STATUS_PENDING;
|
|
}
|
|
}
|
|
|
|
#if DBG
|
|
if (fOutbound) {
|
|
ADD_TO_LARGE_INTEGER(&g_ipsec.GpcTotalPassedIn, 1);
|
|
}
|
|
#endif
|
|
|
|
GpcCf = IPSecResolveGpcCf(fOutbound);
|
|
|
|
TempGpcHandle = 0;
|
|
|
|
if (GpcHandle == 0) {
|
|
#if DBG
|
|
if (fOutbound) {
|
|
ADD_TO_LARGE_INTEGER(&g_ipsec.GpcClassifyNeeded, 1);
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// Classify directly if no GpcHandle passed in.
|
|
//
|
|
IPSEC_CLASSIFY_PACKET( GpcCf,
|
|
uliSrcDstAddr,
|
|
uliProtoSrcDstPort,
|
|
&pFilter,
|
|
&TempGpcHandle);
|
|
} else {
|
|
NTSTATUS status;
|
|
|
|
//
|
|
// Or we use GpcHandle directly to get the filter installed.
|
|
//
|
|
pFilter = NULL;
|
|
|
|
status = GPC_GET_CLIENT_CONTEXT(g_ipsec.GpcClients[GpcCf],
|
|
GpcHandle,
|
|
&pFilter);
|
|
|
|
if (status == STATUS_INVALID_HANDLE) {
|
|
//
|
|
// Re-classify if handle is invalid.
|
|
//
|
|
IPSEC_CLASSIFY_PACKET( GpcCf,
|
|
uliSrcDstAddr,
|
|
uliProtoSrcDstPort,
|
|
&pFilter,
|
|
&TempGpcHandle);
|
|
}
|
|
}
|
|
|
|
#if DBG
|
|
if (IPSecDebug & DBF_EXTRADIAGNOSTIC) {
|
|
PFILTER pDbgFilter = NULL;
|
|
|
|
pFilterList = IPSecResolveFilterList(FALSE, fOutbound);
|
|
|
|
for ( pEntry = pFilterList->Flink;
|
|
pEntry != pFilterList;
|
|
pEntry = pEntry->Flink) {
|
|
|
|
pTempFilter = CONTAINING_RECORD(pEntry,
|
|
FILTER,
|
|
MaskedLinkage);
|
|
|
|
uliAddr.QuadPart = uliSrcDstAddr.QuadPart & pTempFilter->uliSrcDstMask.QuadPart;
|
|
uliPort.QuadPart = uliProtoSrcDstPort.QuadPart & pTempFilter->uliProtoSrcDstMask.QuadPart;
|
|
|
|
if ((uliAddr.QuadPart == pTempFilter->uliSrcDstAddr.QuadPart) &&
|
|
(uliPort.QuadPart == pTempFilter->uliProtoSrcDstPort.QuadPart)) {
|
|
pDbgFilter = pTempFilter;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (pFilter != pDbgFilter &&
|
|
(!pDbgFilter || IS_GPC_FILTER(pDbgFilter))) {
|
|
IPSEC_DEBUG(LL_A, DBF_GPC, ("LookupGpcSA: pFilter %p, pDbgFilter %p, GpcHandle %lx, TempGpcHandle %lx", pFilter, pDbgFilter, GpcHandle, TempGpcHandle));
|
|
IPSEC_DEBUG(LL_A, DBF_GPC, ("LookupGpcSA: Src %lx, Dest %lx, Protocol %d, SPort %lx, DPort %lx", SRC_ADDR, DEST_ADDR, PROTO, SRC_PORT, DEST_PORT));
|
|
|
|
if (DebugGPC) {
|
|
DbgBreakPoint();
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// Continue searching the local GPC filter list if not found.
|
|
//
|
|
if (!pFilter) {
|
|
pFilterList = IPSecResolveGpcFilterList(FALSE, fOutbound);
|
|
|
|
for ( pEntry = pFilterList->Flink;
|
|
pEntry != pFilterList;
|
|
pEntry = pEntry->Flink) {
|
|
|
|
pTempFilter = CONTAINING_RECORD(pEntry,
|
|
FILTER,
|
|
GpcLinkage);
|
|
|
|
uliAddr.QuadPart = uliSrcDstAddr.QuadPart & pTempFilter->uliSrcDstMask.QuadPart;
|
|
uliPort.QuadPart = uliProtoSrcDstPort.QuadPart & pTempFilter->uliProtoSrcDstMask.QuadPart;
|
|
|
|
if ((uliAddr.QuadPart == pTempFilter->uliSrcDstAddr.QuadPart) &&
|
|
(uliPort.QuadPart == pTempFilter->uliProtoSrcDstPort.QuadPart)) {
|
|
pFilter = pTempFilter;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
if (pFilter) {
|
|
//
|
|
// Search for the particular SA now.
|
|
//
|
|
|
|
fFound=FALSE;
|
|
pSAChain = IPSecResolveSAChain(pFilter, fOutbound? DEST_ADDR: SRC_ADDR);
|
|
|
|
for ( pEntry = pSAChain->Flink;
|
|
pEntry != pSAChain;
|
|
pEntry = pEntry->Flink) {
|
|
|
|
pSA = CONTAINING_RECORD(pEntry,
|
|
SA_TABLE_ENTRY,
|
|
sa_FilterLinkage);
|
|
|
|
|
|
if (IS_CLASSD(NET_LONG(pSA->SA_SRC_ADDR))
|
|
|| IS_CLASSD(NET_LONG(pSA->SA_DEST_ADDR))) {
|
|
uliAddr.QuadPart = uliSrcDstAddr.QuadPart & pSA->sa_uliSrcDstMask.QuadPart;
|
|
|
|
IPSEC_DEBUG(LL_A, DBF_HASH, ("MCAST: %d %d %d %d", uliAddr.LowPart, uliAddr.HighPart,
|
|
pSA->sa_uliSrcDstAddr.LowPart,pSA->sa_uliSrcDstAddr.HighPart));
|
|
|
|
if (uliAddr.QuadPart == pSA->sa_uliSrcDstAddr.QuadPart) {
|
|
fFound=TRUE;
|
|
}
|
|
} else if (uliSrcDstAddr.QuadPart == pSA->sa_uliSrcDstAddr.QuadPart && EQUAL_NATENCAP(pNatContext,pSA)) {
|
|
fFound=TRUE;
|
|
}
|
|
if (fFound) {
|
|
IPSEC_DEBUG(LL_A, DBF_HASH, ("Matched entry: %p", pSA));
|
|
ASSERT(fOutbound == (BOOLEAN)((pSA->sa_Flags & FLAGS_SA_OUTBOUND) != 0));
|
|
|
|
//
|
|
// if there is also a tunnel SA, associate it here.
|
|
//
|
|
if (*ppTunnelSA && (fOutbound || fVerify)) {
|
|
*ppNextSA = *ppTunnelSA;
|
|
*ppTunnelSA = NULL;
|
|
}
|
|
|
|
*ppFilter = pFilter;
|
|
*ppSA = pSA;
|
|
return STATUS_SUCCESS;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Found a filter entry, but need to negotiate keys
|
|
// Also, ppTunnelSA is set to the proper tunnel SA we need
|
|
// to hook to this end-2-end SA once it is negotiated.
|
|
//
|
|
*ppFilter = pFilter;
|
|
|
|
return STATUS_PENDING;
|
|
} else {
|
|
//
|
|
// if only tunnel SA found, return that as the SA found.
|
|
//
|
|
if (*ppTunnelSA) {
|
|
*ppSA = *ppTunnelSA;
|
|
*ppTunnelSA = NULL;
|
|
return STATUS_SUCCESS;
|
|
}
|
|
}
|
|
|
|
//
|
|
// no entry found
|
|
//
|
|
return STATUS_NOT_FOUND;
|
|
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
IPSecLookupGpcMaskedSA(
|
|
IN ULARGE_INTEGER uliSrcDstAddr,
|
|
IN ULARGE_INTEGER uliProtoSrcDstPort,
|
|
OUT PFILTER *ppFilter,
|
|
OUT PSA_TABLE_ENTRY *ppSA,
|
|
IN BOOLEAN fOutbound,
|
|
IN PIPSEC_UDP_ENCAP_CONTEXT pNatContext
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Looks up the SA given the relevant addresses.
|
|
|
|
Arguments:
|
|
|
|
uliSrcDstAddr - src/dest IP addr
|
|
uliProtoSrcDstPort - protocol, src/dest port
|
|
ppFilter - filter found
|
|
ppSA - SA found
|
|
fOutbound - direction flag
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS - both filter and SA found
|
|
STATUS_UNSUCCESSFUL - none found
|
|
STATUS_PENDING - filter found, but no SA
|
|
|
|
Notes:
|
|
|
|
Called with SADBLock held.
|
|
|
|
--*/
|
|
{
|
|
REGISTER ULARGE_INTEGER uliPort;
|
|
REGISTER ULARGE_INTEGER uliAddr;
|
|
PFILTER pFilter;
|
|
PFILTER pTempFilter;
|
|
PLIST_ENTRY pFilterList;
|
|
PLIST_ENTRY pSAChain;
|
|
PLIST_ENTRY pEntry;
|
|
PSA_TABLE_ENTRY pSA;
|
|
CLASSIFICATION_HANDLE GpcHandle;
|
|
INT GpcCf;
|
|
|
|
*ppSA = NULL;
|
|
*ppFilter = NULL;
|
|
|
|
GpcCf = IPSecResolveGpcCf(fOutbound);
|
|
|
|
GpcHandle = 0;
|
|
|
|
IPSEC_CLASSIFY_PACKET( GpcCf,
|
|
uliSrcDstAddr,
|
|
uliProtoSrcDstPort,
|
|
&pFilter,
|
|
&GpcHandle);
|
|
|
|
#if DBG
|
|
if (IPSecDebug & DBF_EXTRADIAGNOSTIC) {
|
|
PFILTER pDbgFilter = NULL;
|
|
|
|
pFilterList = IPSecResolveFilterList(FALSE, fOutbound);
|
|
|
|
for ( pEntry = pFilterList->Flink;
|
|
pEntry != pFilterList;
|
|
pEntry = pEntry->Flink) {
|
|
|
|
pTempFilter = CONTAINING_RECORD(pEntry,
|
|
FILTER,
|
|
MaskedLinkage);
|
|
|
|
uliAddr.QuadPart = uliSrcDstAddr.QuadPart & pTempFilter->uliSrcDstMask.QuadPart;
|
|
uliPort.QuadPart = uliProtoSrcDstPort.QuadPart & pTempFilter->uliProtoSrcDstMask.QuadPart;
|
|
|
|
if ((uliAddr.QuadPart == pTempFilter->uliSrcDstAddr.QuadPart) &&
|
|
(uliPort.QuadPart == pTempFilter->uliProtoSrcDstPort.QuadPart)) {
|
|
pDbgFilter = pTempFilter;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (pFilter != pDbgFilter &&
|
|
(!pDbgFilter || IS_GPC_FILTER(pDbgFilter))) {
|
|
IPSEC_DEBUG(LL_A, DBF_GPC, ("LookupMaskedSA: pFilter %p, pDbgFilter %p, GpcHandle %lx", pFilter, pDbgFilter, GpcHandle));
|
|
IPSEC_DEBUG(LL_A, DBF_GPC, ("LookupMaskedSA: Src %lx, Dest %lx, Protocol %d, SPort %lx, DPort %lx", SRC_ADDR, DEST_ADDR, PROTO, SRC_PORT, DEST_PORT));
|
|
|
|
if (DebugGPC) {
|
|
DbgBreakPoint();
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// Continue searching the local GPC filter list if not found.
|
|
//
|
|
if (!pFilter) {
|
|
pFilterList = IPSecResolveGpcFilterList(FALSE, fOutbound);
|
|
|
|
for ( pEntry = pFilterList->Flink;
|
|
pEntry != pFilterList;
|
|
pEntry = pEntry->Flink) {
|
|
|
|
pTempFilter = CONTAINING_RECORD(pEntry,
|
|
FILTER,
|
|
GpcLinkage);
|
|
|
|
uliAddr.QuadPart = uliSrcDstAddr.QuadPart & pTempFilter->uliSrcDstMask.QuadPart;
|
|
uliPort.QuadPart = uliProtoSrcDstPort.QuadPart & pTempFilter->uliProtoSrcDstMask.QuadPart;
|
|
|
|
if ((uliAddr.QuadPart == pTempFilter->uliSrcDstAddr.QuadPart) &&
|
|
(uliPort.QuadPart == pTempFilter->uliProtoSrcDstPort.QuadPart)) {
|
|
pFilter = pTempFilter;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (pFilter) {
|
|
//
|
|
// Search for the particular SA now.
|
|
//
|
|
pSAChain = IPSecResolveSAChain(pFilter, fOutbound? DEST_ADDR: SRC_ADDR);
|
|
|
|
for ( pEntry = pSAChain->Flink;
|
|
pEntry != pSAChain;
|
|
pEntry = pEntry->Flink) {
|
|
|
|
pSA = CONTAINING_RECORD(pEntry,
|
|
SA_TABLE_ENTRY,
|
|
sa_FilterLinkage);
|
|
|
|
if (uliSrcDstAddr.QuadPart == pSA->sa_uliSrcDstAddr.QuadPart && EQUAL_NATENCAP(pNatContext,pSA) ) {
|
|
|
|
IPSEC_DEBUG(LL_A, DBF_HASH, ("Matched entry: %p", pSA));
|
|
ASSERT(fOutbound == (BOOLEAN)((pSA->sa_Flags & FLAGS_SA_OUTBOUND) != 0));
|
|
*ppFilter = pFilter;
|
|
*ppSA = pSA;
|
|
return STATUS_SUCCESS;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Found a filter entry, but need to negotiate keys
|
|
//
|
|
*ppFilter = pFilter;
|
|
return STATUS_PENDING;
|
|
}
|
|
|
|
//
|
|
// no entry found
|
|
//
|
|
return STATUS_NOT_FOUND;
|
|
}
|
|
|
|
|
|
#endif
|
|
|