4345 lines
113 KiB
C
4345 lines
113 KiB
C
|
|
/*++
|
|
|
|
Copyright (c) Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
ioctl.c
|
|
|
|
Abstract:
|
|
|
|
|
|
Author:
|
|
|
|
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
/*----------------------------------------------------------------------------
|
|
A note on the interlocking, as of 24-Feb-1997.
|
|
|
|
There are two important locks: the FilterListResourceLock which is
|
|
a resource and the g_filter.ifListLock, which is a spin lock but acts
|
|
like a resource. The former is used to serialize API access to interface state
|
|
and filters. The latter is used to serialize DPC access.
|
|
|
|
----------------------------------------------------------------------------*/
|
|
|
|
#include "globals.h"
|
|
|
|
|
|
ERESOURCE FilterListResourceLock;
|
|
BOOL fCheckDups = FALSE;
|
|
|
|
extern NPAGED_LOOKASIDE_LIST filter_slist;
|
|
extern PAGED_LOOKASIDE_LIST paged_slist;
|
|
|
|
NTSTATUS
|
|
UpdateMatchBindingInformation(
|
|
PFILTER_DRIVER_BINDING_INFO pBindInfo,
|
|
PVOID pvContext
|
|
);
|
|
|
|
NTSTATUS
|
|
CreateCommonInterface(PPAGED_FILTER_INTERFACE pPage,
|
|
DWORD dwBind,
|
|
DWORD dwName,
|
|
DWORD dwFlags);
|
|
|
|
VOID
|
|
FreePagedFilterList(PPFFCB Fcb,
|
|
PPAGED_FILTER pIn,
|
|
PPAGED_FILTER_INTERFACE pPage,
|
|
PDWORD pdwRemoved);
|
|
|
|
VOID
|
|
DeleteFilterList(PLIST_ENTRY pList);
|
|
|
|
BOOL
|
|
IsOnSpecialFilterList(PPAGED_FILTER pPageFilter,
|
|
PLIST_ENTRY List,
|
|
PPAGED_FILTER * pPageHit);
|
|
|
|
PPAGED_FILTER
|
|
IsOnPagedInterface(PPAGED_FILTER pPageFilter,
|
|
PPAGED_FILTER_INTERFACE pPage);
|
|
|
|
PPAGED_FILTER
|
|
MakePagedFilter(
|
|
IN PPFFCB Fcb,
|
|
IN PFILTER_INFOEX pInfo,
|
|
IN DWORD dwEpoch,
|
|
DWORD dwFlags
|
|
);
|
|
|
|
VOID
|
|
NotifyFastPath( PFILTER_INTERFACE pIf, DWORD dwIndex, DWORD dwCode);
|
|
|
|
VOID
|
|
NotifyFastPathIf( PFILTER_INTERFACE pIf);
|
|
|
|
NTSTATUS
|
|
DeleteByHandle(
|
|
IN PPFFCB Fcb,
|
|
IN PPAGED_FILTER_INTERFACE pPage,
|
|
IN PVOID * ppHandles,
|
|
IN DWORD dwLength);
|
|
|
|
NTSTATUS
|
|
CheckFilterAddress(DWORD dwAdd, PFILTER_INTERFACE pIf);
|
|
|
|
VOID
|
|
AddFilterToInterface(
|
|
PFILTER pMatch,
|
|
PFILTER_INTERFACE pIf,
|
|
BOOL fInFilter,
|
|
PFILTER * ppFilter);
|
|
|
|
VOID
|
|
RemoveFilterWorker(
|
|
PPFFCB Fcb,
|
|
PFILTER_INFOEX pFilt,
|
|
DWORD dwCount,
|
|
PPAGED_FILTER_INTERFACE pPage,
|
|
PDWORD pdwRemoved,
|
|
BOOL fInFilter);
|
|
|
|
NTSTATUS
|
|
AllocateAndAddFilterToMatchInterface(
|
|
PPFFCB Fcb,
|
|
PFILTER_INFOEX pInfo,
|
|
BOOL fInFilter,
|
|
PPAGED_FILTER_INTERFACE pPage,
|
|
PBOOL pbAdded,
|
|
PPAGED_FILTER * ppFilter);
|
|
|
|
#pragma alloc_text(PAGED, SetFiltersEx)
|
|
#pragma alloc_text(PAGED, NewInterface)
|
|
#pragma alloc_text(PAGED, MakeNewFilters)
|
|
#pragma alloc_text(PAGED, GetPointerToTocEntry)
|
|
//#pragma alloc_text(PAGED, AddNewInterface)
|
|
#pragma alloc_text(PAGED, MakePagedFilter)
|
|
#pragma alloc_text(PAGED, AllocateAndAddFilterToMatchInterface)
|
|
#pragma alloc_text(PAGED, IsOnSpecialFilterList)
|
|
#pragma alloc_text(PAGED, IsOnPagedInterface)
|
|
#pragma alloc_text(PAGED, UnSetFiltersEx)
|
|
#pragma alloc_text(PAGED, DeleteByHandle)
|
|
#pragma alloc_text(PAGED, DeletePagedInterface)
|
|
|
|
|
|
#define HandleHash(x) HashList[(x) + g_dwHashLists]
|
|
|
|
#define IsValidInterface(pIf) (pIf != 0)
|
|
|
|
#define NOT_RESTRICTION 1
|
|
#define NOT_UNBIND 2
|
|
|
|
#if DOFRAGCHECKING
|
|
DWORD
|
|
GetFragIndex(DWORD dwProt)
|
|
{
|
|
switch(dwProt)
|
|
{
|
|
case FILTER_PROTO_ICMP:
|
|
return FRAG_ICMP;
|
|
case FILTER_PROTO_UDP:
|
|
return FRAG_UDP;
|
|
case FILTER_PROTO_TCP:
|
|
return FRAG_TCP;
|
|
}
|
|
return FRAG_OTHER;
|
|
}
|
|
#endif
|
|
|
|
BOOL CheckDescriptorSize(PFILTER_DESCRIPTOR2 pdsc, PBYTE pbEnd)
|
|
{
|
|
PFILTER_INFOEX pFilt = &pdsc->fiFilter[0];
|
|
|
|
|
|
//
|
|
// Check that there is a full header structure and that
|
|
// the claimed number of filters is present.
|
|
//
|
|
if(((PBYTE)pFilt > pbEnd)
|
|
||
|
|
((PBYTE)(&pFilt[pdsc->dwNumFilters]) > pbEnd) )
|
|
{
|
|
return(FALSE);
|
|
}
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
|
|
BOOL
|
|
WildFilter(PFILTER pf)
|
|
{
|
|
#if WILDHASH
|
|
if(pf->dwFlags & FILTER_FLAGS_INFILTER)
|
|
{
|
|
if(pf->dwFlags & FILTER_FLAGS_DSTWILD)
|
|
{
|
|
return(TRUE);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(pf->dwFlags & FILTER_FLAGS_SRCWILD)
|
|
{
|
|
return(TRUE);
|
|
}
|
|
}
|
|
return(FALSE);
|
|
#else
|
|
return(ANYWILDFILTER(pf))
|
|
#endif
|
|
}
|
|
|
|
//
|
|
// N.B. If WILDHASH is on, then there is code in match.c that
|
|
// does a similar computation. Hence if this changes, then that
|
|
// must also.
|
|
//
|
|
|
|
#if WILDHASH
|
|
DWORD
|
|
ComputeMatchHashIndex(PFILTER pf, PBOOL pfWild)
|
|
{
|
|
DWORD dwX;
|
|
|
|
*pfWild = TRUE;
|
|
|
|
if(!ANYWILDFILTER(pf))
|
|
{
|
|
*pfWild = FALSE;
|
|
|
|
dwX = (pf->SRC_ADDR +
|
|
pf->DEST_ADDR +
|
|
pf->DEST_ADDR +
|
|
PROTOCOLPART(pf->uliProtoSrcDstPort.LowPart) +
|
|
pf->uliProtoSrcDstPort.HighPart);
|
|
|
|
}
|
|
else if(WildFilter(pf))
|
|
{
|
|
if(pf->dwFlags & FILTER_FLAGS_INFILTER)
|
|
{
|
|
dwX = g_dwHashLists;
|
|
}
|
|
else
|
|
{
|
|
dwX = g_dwHashLists + 1;
|
|
}
|
|
*pfWild = FALSE;
|
|
return(dwX);
|
|
}
|
|
else if(pf->dwFlags & FILTER_FLAGS_INFILTER)
|
|
{
|
|
dwX = pf->DEST_ADDR +
|
|
pf->DEST_ADDR +
|
|
PROTOCOLPART(pf->uliProtoSrcDstPort.LowPart) +
|
|
HIWORD(pf->uliProtoSrcDstPort.HighPart);
|
|
}
|
|
else
|
|
{
|
|
dwX = pf->SRC_ADDR +
|
|
PROTOCOLPART(pf->uliProtoSrcDstPort.LowPart) +
|
|
LOWORD(pf->uliProtoSrcDstPort.HighPart);
|
|
}
|
|
return(dwX % g_dwHashLists);
|
|
}
|
|
|
|
#else // WILDHASH
|
|
|
|
__inline
|
|
DWORD
|
|
ComputeMatchHashIndex(PFILTER pf, PBOOL pfWild)
|
|
{
|
|
DWORD dwX;
|
|
|
|
if(WildFilter(pf))
|
|
{
|
|
if(pf->dwFlags & FILTER_FLAGS_SRCWILD)
|
|
{
|
|
dwX = g_dwHashLists;
|
|
}
|
|
else
|
|
{
|
|
dwX = g_dwHashLists + 1;
|
|
}
|
|
return(dwIndex);
|
|
}
|
|
dwX = (pf->SRC_ADDR +
|
|
pf->DEST_ADDR +
|
|
pf->DEST_ADDR +
|
|
PROTOCOLPART(pf->uliProtoSrcDstPort.LowPart) +
|
|
pf->uliProtoSrcDstPort.HighPart) % g_dwHashLists;
|
|
return(dwX);
|
|
}
|
|
#endif // WILDHASH
|
|
|
|
PFILTER_INTERFACE
|
|
FindMatchName(DWORD dwName, DWORD dwBind)
|
|
/*++
|
|
Routine Description:
|
|
Find an interface with the same name or with the
|
|
same binding. The calller must have locked the
|
|
resource
|
|
--*/
|
|
{
|
|
PFILTER_INTERFACE pIf1;
|
|
PLIST_ENTRY pList;
|
|
|
|
for(pList = g_filters.leIfListHead.Flink;
|
|
pList != &g_filters.leIfListHead;
|
|
pList = pList->Flink)
|
|
{
|
|
|
|
pIf1 = CONTAINING_RECORD(pList, FILTER_INTERFACE, leIfLink);
|
|
|
|
if((pIf1->dwName && (dwName == pIf1->dwName))
|
|
||
|
|
((pIf1->dwIpIndex != UNKNOWN_IP_INDEX)
|
|
&&
|
|
(pIf1->dwIpIndex == dwBind)) )
|
|
{
|
|
return(pIf1);
|
|
}
|
|
}
|
|
return(NULL);
|
|
}
|
|
|
|
VOID
|
|
RemoveGlobalFilterFromInterface(PFILTER_INTERFACE pIf,
|
|
DWORD dwType)
|
|
{
|
|
LOCK_STATE LockState;
|
|
|
|
//
|
|
// lock up the filters
|
|
//
|
|
|
|
AcquireWriteLock(&g_filters.ifListLock,&LockState);
|
|
|
|
switch(dwType)
|
|
{
|
|
case PFE_SYNORFRAG:
|
|
pIf->CountSynOrFrag.lInUse--;
|
|
if(pIf->CountSynOrFrag.lInUse == 0)
|
|
{
|
|
pIf->CountSynOrFrag.lCount = 0;
|
|
}
|
|
break;
|
|
|
|
case PFE_SPOOF:
|
|
pIf->CountSpoof.lInUse--;
|
|
if(pIf->CountSpoof.lInUse == 0)
|
|
{
|
|
pIf->CountSpoof.lCount = 0;
|
|
}
|
|
break;
|
|
|
|
case PFE_UNUSEDPORT:
|
|
pIf->CountUnused.lInUse--;
|
|
if(pIf->CountUnused.lInUse == 0)
|
|
{
|
|
pIf->CountUnused.lCount = 0;
|
|
}
|
|
break;
|
|
|
|
case PFE_STRONGHOST:
|
|
pIf->CountStrongHost.lInUse--;
|
|
if(pIf->CountStrongHost.lInUse == 0)
|
|
{
|
|
pIf->CountStrongHost.lCount = 0;
|
|
}
|
|
break;
|
|
|
|
case PFE_ALLOWCTL:
|
|
pIf->CountCtl.lInUse--;
|
|
if(pIf->CountCtl.lInUse == 0)
|
|
{
|
|
pIf->CountCtl.lCount = 0;
|
|
}
|
|
break;
|
|
|
|
case PFE_FULLDENY:
|
|
pIf->CountFullDeny.lInUse--;
|
|
if(pIf->CountFullDeny.lInUse == 0)
|
|
{
|
|
pIf->CountFullDeny.lCount = 0;
|
|
}
|
|
break;
|
|
|
|
case PFE_NOFRAG:
|
|
pIf->CountNoFrag.lInUse--;
|
|
if(pIf->CountNoFrag.lInUse == 0)
|
|
{
|
|
pIf->CountNoFrag.lCount = 0;
|
|
}
|
|
break;
|
|
|
|
case PFE_FRAGCACHE:
|
|
pIf->CountFragCache.lInUse--;
|
|
if(pIf->CountFragCache.lInUse == 0)
|
|
{
|
|
pIf->CountFragCache.lCount = 0;
|
|
}
|
|
break;
|
|
}
|
|
ReleaseWriteLock(&g_filters.ifListLock,&LockState);
|
|
}
|
|
|
|
VOID
|
|
AddGlobalFilterToInterface(PPAGED_FILTER_INTERFACE pPage,
|
|
PFILTER_INFOEX pfilt)
|
|
{
|
|
PFILTER_INTERFACE pIf = pPage->pFilter;
|
|
LOCK_STATE LockState;
|
|
|
|
//
|
|
// lock up the filters
|
|
//
|
|
|
|
AcquireWriteLock(&g_filters.ifListLock,&LockState);
|
|
|
|
switch(pfilt->type)
|
|
{
|
|
case PFE_SYNORFRAG:
|
|
pIf->CountSynOrFrag.lInUse++;
|
|
break;
|
|
|
|
case PFE_SPOOF:
|
|
pIf->CountSpoof.lInUse++;
|
|
break;
|
|
|
|
case PFE_UNUSEDPORT:
|
|
|
|
pIf->CountUnused.lInUse++;
|
|
break;
|
|
|
|
case PFE_STRONGHOST:
|
|
pIf->CountStrongHost.lInUse++;
|
|
break;
|
|
|
|
case PFE_ALLOWCTL:
|
|
pIf->CountCtl.lInUse++;
|
|
break;
|
|
|
|
case PFE_FULLDENY:
|
|
pIf->CountFullDeny.lInUse++;
|
|
break;
|
|
|
|
case PFE_NOFRAG:
|
|
pIf->CountNoFrag.lInUse++;
|
|
break;
|
|
|
|
case PFE_FRAGCACHE:
|
|
pIf->CountFragCache.lInUse++;
|
|
break;
|
|
}
|
|
ReleaseWriteLock(&g_filters.ifListLock,&LockState);
|
|
}
|
|
|
|
/*++
|
|
Start of old STEELHEAD APIS routines.
|
|
--*/
|
|
|
|
#if STEELHEAD
|
|
NTSTATUS
|
|
AddInterface(
|
|
IN PVOID pvRtrMgrCtxt,
|
|
IN DWORD dwRtrMgrIndex,
|
|
IN DWORD dwAdapterId,
|
|
IN PPFFCB Fcb,
|
|
OUT PVOID *ppvFltrDrvrCtxt
|
|
)
|
|
|
|
/*++
|
|
Routine Description
|
|
Adds an interface to the filter driver and makes an association between context
|
|
passed in and interface created
|
|
|
|
Arguments
|
|
pvRtrMgrCtxt - Context passed in
|
|
pvFltrDrvrCtxt - Handle to interface created
|
|
|
|
Return Value
|
|
--*/
|
|
{
|
|
PFILTER_INTERFACE pIf;
|
|
LOCK_STATE LockState;
|
|
NTSTATUS Status;
|
|
|
|
if(Fcb->dwFlags & PF_FCB_NEW)
|
|
{
|
|
return(STATUS_INVALID_DEVICE_REQUEST);
|
|
}
|
|
|
|
Fcb->dwFlags |= PF_FCB_OLD;
|
|
|
|
pIf = NewInterface(pvRtrMgrCtxt,
|
|
dwRtrMgrIndex,
|
|
FORWARD,
|
|
FORWARD,
|
|
(PVOID)Fcb,
|
|
dwAdapterId,
|
|
0);
|
|
|
|
if(pIf is NULL)
|
|
{
|
|
return STATUS_NO_MEMORY;
|
|
}
|
|
|
|
//
|
|
// lock the resource that protects adding new interfaces. This
|
|
// is needed to hold off others until everything is properly
|
|
// verified. The spin lock is insufficient for this.
|
|
//
|
|
|
|
KeEnterCriticalRegion();
|
|
ExAcquireResourceExclusiveLite(&FilterListResourceLock, TRUE);
|
|
|
|
//
|
|
// Check for a name conflict
|
|
//
|
|
|
|
if(FindMatchName(0, dwAdapterId))
|
|
{
|
|
ExFreePool(pIf);
|
|
Status = STATUS_DEVICE_BUSY;
|
|
}
|
|
else
|
|
{
|
|
pIf->dwGlobalEnables |= FI_ENABLE_OLD;
|
|
|
|
*ppvFltrDrvrCtxt = (PVOID)pIf;
|
|
|
|
AcquireWriteLock(&g_filters.ifListLock,&LockState);
|
|
|
|
InsertTailList(&g_filters.leIfListHead,&pIf->leIfLink);
|
|
|
|
ReleaseWriteLock(&g_filters.ifListLock,&LockState);
|
|
Status = STATUS_SUCCESS;
|
|
|
|
}
|
|
ExReleaseResourceLite(&FilterListResourceLock);
|
|
KeLeaveCriticalRegion();
|
|
|
|
return(Status);
|
|
}
|
|
|
|
NTSTATUS
|
|
DeleteInterface(
|
|
IN PVOID pvIfContext
|
|
)
|
|
/*++
|
|
Routine Description
|
|
Deletes an interface and all the filters associated with it
|
|
Clears the cache
|
|
|
|
Arguments
|
|
pvRtrMgrCtxt - Context passed in
|
|
pvFltrDrvrCtxt - Handle to interface created
|
|
|
|
Return Value
|
|
--*/
|
|
{
|
|
PFILTER_INTERFACE pIf;
|
|
LOCK_STATE LockState;
|
|
|
|
pIf = (PFILTER_INTERFACE)pvIfContext;
|
|
|
|
if(!IsValidInterface(pIf) || !(pIf->dwGlobalEnables & FI_ENABLE_OLD))
|
|
{
|
|
return(STATUS_INVALID_DEVICE_REQUEST);
|
|
}
|
|
|
|
KeEnterCriticalRegion();
|
|
ExAcquireResourceExclusiveLite(&FilterListResourceLock, TRUE);
|
|
|
|
AcquireWriteLock(&g_filters.ifListLock,&LockState);
|
|
|
|
DeleteFilters(pIf,
|
|
IN_FILTER_SET);
|
|
|
|
DeleteFilters(pIf,
|
|
OUT_FILTER_SET);
|
|
|
|
RemoveEntryList(&pIf->leIfLink);
|
|
|
|
ClearCache();
|
|
|
|
ReleaseWriteLock(&g_filters.ifListLock,&LockState);
|
|
|
|
ExReleaseResourceLite(&FilterListResourceLock);
|
|
KeLeaveCriticalRegion();
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
SetFilters(
|
|
IN PFILTER_DRIVER_SET_FILTERS pRtrMgrInfo
|
|
)
|
|
/*++
|
|
Routine Description
|
|
Adds the set of in and out filters passed to the interface (identified by the
|
|
context). Also sets the default actions.
|
|
Clears the cache
|
|
|
|
Arguments
|
|
pInfo Pointer to info passed by the router manager
|
|
|
|
Return Value
|
|
|
|
--*/
|
|
{
|
|
PFILTER_INTERFACE pIf;
|
|
LOCK_STATE LockState;
|
|
NTSTATUS ntStatus;
|
|
DWORD dwNumInFilters,dwNumOutFilters;
|
|
FORWARD_ACTION faInAction,faOutAction;
|
|
PFILTER_DESCRIPTOR pFilterDesc;
|
|
PRTR_TOC_ENTRY pInToc,pOutToc;
|
|
LIST_ENTRY InList, OutList;
|
|
|
|
//
|
|
// Sensible defaults
|
|
//
|
|
|
|
dwNumInFilters = dwNumOutFilters = 0;
|
|
faInAction = faOutAction = FORWARD;
|
|
|
|
pIf = (PFILTER_INTERFACE)pRtrMgrInfo->pvDriverContext;
|
|
|
|
if(!IsValidInterface(pIf) || !(pIf->dwGlobalEnables & FI_ENABLE_OLD))
|
|
{
|
|
return(STATUS_INVALID_DEVICE_REQUEST);
|
|
}
|
|
|
|
pInToc = GetPointerToTocEntry(IP_FILTER_DRIVER_IN_FILTER_INFO,
|
|
&pRtrMgrInfo->ribhInfoBlock);
|
|
|
|
pOutToc = GetPointerToTocEntry(IP_FILTER_DRIVER_OUT_FILTER_INFO,
|
|
&pRtrMgrInfo->ribhInfoBlock);
|
|
|
|
if(!pInToc && !pOutToc)
|
|
{
|
|
//
|
|
// Nothing to change
|
|
//
|
|
|
|
TRACE(CONFIG,(
|
|
"IPFLTDRV: Both filter set TOCs were null so nothing to change"
|
|
));
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
if(pInToc)
|
|
{
|
|
//
|
|
// If the infosize is 0, the filters will get deleted and default action
|
|
// set to FORWARD. If infosize isnot 0 but the number of filters in the
|
|
// descriptor is zero, the old filters will get deleted, no new filters
|
|
// will be added, but the default action will be the one specified in the
|
|
// descriptor. If Infosize is not 0 and number od filters is also not zero
|
|
// then old filters will get deleted, new filters created and default
|
|
// action set to what is specified in the
|
|
//
|
|
|
|
if(pInToc->InfoSize)
|
|
{
|
|
pFilterDesc = GetInfoFromTocEntry(&pRtrMgrInfo->ribhInfoBlock,
|
|
pInToc);
|
|
|
|
if(pFilterDesc->dwVersion != 1)
|
|
{
|
|
return(STATUS_INVALID_PARAMETER);
|
|
}
|
|
if(!NT_SUCCESS( ntStatus = MakeNewFilters(pFilterDesc->dwNumFilters,
|
|
pFilterDesc->fiFilter,
|
|
TRUE,
|
|
&InList)))
|
|
|
|
{
|
|
ERROR(("IPFLTDRV: MakeNewFilters failed\n"));
|
|
|
|
return ntStatus;
|
|
}
|
|
|
|
dwNumInFilters = pFilterDesc->dwNumFilters;
|
|
faInAction = pFilterDesc->faDefaultAction;
|
|
}
|
|
}
|
|
|
|
if(pOutToc)
|
|
{
|
|
|
|
if(pOutToc->InfoSize isnot 0)
|
|
{
|
|
pFilterDesc = GetInfoFromTocEntry(&pRtrMgrInfo->ribhInfoBlock,
|
|
pOutToc);
|
|
|
|
if(pFilterDesc->dwVersion != 1)
|
|
{
|
|
ntStatus = STATUS_INVALID_PARAMETER;
|
|
DeleteFilterList(&InList);
|
|
return ntStatus;
|
|
}
|
|
|
|
if(!NT_SUCCESS( ntStatus = MakeNewFilters(pFilterDesc->dwNumFilters,
|
|
pFilterDesc->fiFilter,
|
|
FALSE,
|
|
&OutList)))
|
|
{
|
|
ERROR(("IPFLTDRV: MakeNewFilters failed - %x\n", ntStatus));
|
|
DeleteFilterList(&InList);
|
|
return ntStatus;
|
|
}
|
|
|
|
dwNumOutFilters = pFilterDesc->dwNumFilters;
|
|
faOutAction = pFilterDesc->faDefaultAction;
|
|
}
|
|
}
|
|
|
|
AcquireWriteLock(&g_filters.ifListLock,&LockState);
|
|
|
|
//
|
|
// If new info was given, then blow away the old filters
|
|
// If new filters were also given, then add them
|
|
//
|
|
|
|
if(pInToc)
|
|
{
|
|
|
|
DeleteFilters(pIf, IN_FILTER_SET);
|
|
|
|
if(dwNumInFilters)
|
|
{
|
|
InList.Flink->Blink = &pIf->pleInFilterSet;
|
|
InList.Blink->Flink = &pIf->pleInFilterSet;
|
|
pIf->pleInFilterSet = InList;
|
|
}
|
|
pIf->dwNumInFilters = dwNumInFilters;
|
|
pIf->eaInAction = faInAction;
|
|
|
|
}
|
|
|
|
if(pOutToc)
|
|
{
|
|
DeleteFilters(pIf, OUT_FILTER_SET);
|
|
|
|
if(dwNumOutFilters)
|
|
{
|
|
OutList.Flink->Blink = &pIf->pleOutFilterSet;
|
|
OutList.Blink->Flink = &pIf->pleOutFilterSet;
|
|
pIf->pleOutFilterSet = OutList;
|
|
}
|
|
pIf->dwNumOutFilters = dwNumOutFilters;
|
|
pIf->eaOutAction = faOutAction;
|
|
}
|
|
|
|
ClearCache();
|
|
|
|
ReleaseWriteLock(&g_filters.ifListLock,&LockState);
|
|
|
|
return(STATUS_SUCCESS);
|
|
}
|
|
|
|
NTSTATUS
|
|
UpdateBindingInformation(
|
|
PFILTER_DRIVER_BINDING_INFO pBindInfo,
|
|
PVOID pvContext
|
|
)
|
|
/*++
|
|
Routine Description
|
|
Gets filters and statistics associated with an interface
|
|
It is called with the Spin Lock held as reader
|
|
|
|
Arguments
|
|
pvIf Pointer to FILTER_INTERFACE structure which was passed as a PVOID
|
|
to router manager as a context for the interface
|
|
pInfo FILTER_IF structure filled in by driver
|
|
|
|
Return Value
|
|
|
|
--*/
|
|
{
|
|
PFILTER_INTERFACE pIf;
|
|
LOCK_STATE LockState;
|
|
PFILTER pf;
|
|
DWORD i;
|
|
PLIST_ENTRY List;
|
|
|
|
pIf = (PFILTER_INTERFACE)pvContext;
|
|
|
|
if(!IsValidInterface(pIf) || !(pIf->dwGlobalEnables & FI_ENABLE_OLD))
|
|
{
|
|
return(STATUS_INVALID_DEVICE_REQUEST);
|
|
}
|
|
|
|
AcquireWriteLock(&g_filters.ifListLock,&LockState);
|
|
|
|
|
|
for(List = pIf->pleInFilterSet.Flink;
|
|
List != &pIf->pleInFilterSet;
|
|
List = List->Flink)
|
|
{
|
|
pf = CONTAINING_RECORD(List, FILTER, pleFilters);
|
|
|
|
if(AreAllFieldsUnchanged(pf))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if(DoesSrcAddrUseLocalAddr(pf))
|
|
{
|
|
pf->SRC_ADDR = pBindInfo->dwLocalAddr;
|
|
}
|
|
else if(DoesSrcAddrUseRemoteAddr(pf))
|
|
{
|
|
pf->SRC_ADDR = pBindInfo->dwRemoteAddr;
|
|
}
|
|
|
|
if(DoesDstAddrUseLocalAddr(pf))
|
|
{
|
|
pf->DEST_ADDR = pBindInfo->dwLocalAddr;
|
|
}
|
|
else if(DoesDstAddrUseRemoteAddr(pf))
|
|
{
|
|
pf->DEST_ADDR = pBindInfo->dwRemoteAddr;
|
|
}
|
|
|
|
if(IsSrcMaskLateBound(pf))
|
|
{
|
|
pf->SRC_MASK = pBindInfo->dwMask;
|
|
}
|
|
|
|
if(IsDstMaskLateBound(pf))
|
|
{
|
|
pf->DEST_MASK = pBindInfo->dwMask;
|
|
}
|
|
}
|
|
|
|
|
|
for(List = pIf->pleOutFilterSet.Flink;
|
|
List != &pIf->pleOutFilterSet;
|
|
List = List->Flink)
|
|
{
|
|
pf = CONTAINING_RECORD(List, FILTER, pleFilters);
|
|
|
|
if(AreAllFieldsUnchanged(pf))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if(DoesSrcAddrUseLocalAddr(pf))
|
|
{
|
|
pf->SRC_ADDR = pBindInfo->dwLocalAddr;
|
|
}
|
|
|
|
if(DoesSrcAddrUseRemoteAddr(pf))
|
|
{
|
|
pf->SRC_ADDR = pBindInfo->dwRemoteAddr;
|
|
}
|
|
|
|
if(DoesDstAddrUseLocalAddr(pf))
|
|
{
|
|
pf->SRC_ADDR = pBindInfo->dwLocalAddr;
|
|
}
|
|
|
|
if(DoesDstAddrUseRemoteAddr(pf))
|
|
{
|
|
pf->SRC_ADDR = pBindInfo->dwRemoteAddr;
|
|
}
|
|
|
|
if(IsSrcMaskLateBound(pf))
|
|
{
|
|
pf->SRC_MASK = pBindInfo->dwMask;
|
|
}
|
|
|
|
if(IsDstMaskLateBound(pf))
|
|
{
|
|
pf->DEST_MASK = pBindInfo->dwMask;
|
|
}
|
|
}
|
|
|
|
ClearCache();
|
|
|
|
ReleaseWriteLock(&g_filters.ifListLock,&LockState);
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
GetFilters(
|
|
IN PFILTER_INTERFACE pIf,
|
|
IN BOOL fClear,
|
|
OUT PFILTER_IF pInfo
|
|
)
|
|
/*++
|
|
Routine Description
|
|
Gets filters and statistics associated with an interface
|
|
It is called with the Spin Lock held as reader
|
|
|
|
Arguments
|
|
pvIf Pointer to FILTER_INTERFACE structure which was passed as a PVOID
|
|
to router manager as a context for the interface
|
|
pInfo FILTER_IF structure filled in by driver
|
|
|
|
Return Value
|
|
|
|
--*/
|
|
{
|
|
DWORD i,dwNumInFilters,dwNumOutFilters;
|
|
PFILTER pf;
|
|
PLIST_ENTRY List;
|
|
|
|
if(!IsValidInterface(pIf) || !(pIf->dwGlobalEnables & FI_ENABLE_OLD))
|
|
{
|
|
return(STATUS_INVALID_DEVICE_REQUEST);
|
|
}
|
|
|
|
dwNumInFilters = pIf->dwNumInFilters;
|
|
dwNumOutFilters = pIf->dwNumOutFilters;
|
|
|
|
i = 0;
|
|
|
|
for(List = pIf->pleInFilterSet.Flink;
|
|
List != &pIf->pleInFilterSet;
|
|
i++, List = List->Flink)
|
|
{
|
|
pf = CONTAINING_RECORD(List, FILTER, pleFilters);
|
|
|
|
pInfo->filters[i].dwNumPacketsFiltered = (DWORD)pf->Count.lCount;
|
|
if(fClear)
|
|
{
|
|
pf->Count.lCount = 0;
|
|
}
|
|
|
|
pInfo->filters[i].info.dwSrcAddr = pf->SRC_ADDR;
|
|
pInfo->filters[i].info.dwSrcMask = pf->SRC_MASK;
|
|
pInfo->filters[i].info.dwDstAddr = pf->DEST_ADDR;
|
|
pInfo->filters[i].info.dwDstMask = pf->DEST_MASK;
|
|
pInfo->filters[i].info.dwProtocol = pf->PROTO;
|
|
pInfo->filters[i].info.fLateBound = pf->fLateBound;
|
|
|
|
if(pInfo->filters[i].info.dwProtocol is FILTER_PROTO_ICMP)
|
|
{
|
|
if(LOBYTE(LOWORD(pf->uliProtoSrcDstMask.HighPart)) isnot 0xff)
|
|
{
|
|
pInfo->filters[i].info.wSrcPort = FILTER_ICMP_TYPE_ANY;
|
|
}
|
|
else
|
|
{
|
|
pInfo->filters[i].info.wSrcPort =
|
|
MAKEWORD(LOBYTE(LOWORD(pf->uliProtoSrcDstPort.HighPart)),0x00);
|
|
}
|
|
|
|
if(HIBYTE(LOWORD(pf->uliProtoSrcDstMask.HighPart)) isnot 0xff)
|
|
{
|
|
pInfo->filters[i].info.wDstPort = FILTER_ICMP_CODE_ANY;
|
|
}
|
|
else
|
|
{
|
|
pInfo->filters[i].info.wDstPort =
|
|
MAKEWORD(HIBYTE(LOWORD(pf->uliProtoSrcDstPort.HighPart)),0x00);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pInfo->filters[i].info.wSrcPort =
|
|
LOWORD(pf->uliProtoSrcDstPort.HighPart);
|
|
pInfo->filters[i].info.wDstPort =
|
|
HIWORD(pf->uliProtoSrcDstPort.HighPart);
|
|
|
|
if(pInfo->filters[i].info.dwProtocol is FILTER_PROTO_TCP)
|
|
{
|
|
if(HIBYTE(LOWORD(pf->PROTO)))
|
|
{
|
|
pInfo->filters[i].info.dwProtocol = FILTER_PROTO_TCP_ESTAB;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
i = 0;
|
|
|
|
for(List = pIf->pleOutFilterSet.Flink;
|
|
List != &pIf->pleOutFilterSet;
|
|
i++, List = List->Flink)
|
|
{
|
|
pf = CONTAINING_RECORD(List, FILTER, pleFilters);
|
|
|
|
pInfo->filters[i+dwNumInFilters].dwNumPacketsFiltered =
|
|
(DWORD)pf->Count.lCount;
|
|
|
|
if(fClear)
|
|
{
|
|
pf->Count.lCount = 0;
|
|
}
|
|
|
|
pInfo->filters[i+dwNumInFilters].info.dwSrcAddr = pf->SRC_ADDR;
|
|
pInfo->filters[i+dwNumInFilters].info.dwSrcMask = pf->SRC_MASK;
|
|
pInfo->filters[i+dwNumInFilters].info.dwDstAddr = pf->DEST_ADDR;
|
|
pInfo->filters[i+dwNumInFilters].info.dwDstMask = pf->DEST_MASK;
|
|
pInfo->filters[i+dwNumInFilters].info.dwProtocol = pf->PROTO;
|
|
pInfo->filters[i+dwNumInFilters].info.fLateBound = pf->fLateBound;
|
|
|
|
if(pInfo->filters[i+dwNumInFilters].info.dwProtocol is FILTER_PROTO_ICMP)
|
|
{
|
|
if(LOBYTE(LOWORD(pf->uliProtoSrcDstMask.HighPart)) isnot 0xff)
|
|
{
|
|
pInfo->filters[i+dwNumInFilters].info.wSrcPort = FILTER_ICMP_TYPE_ANY;
|
|
}
|
|
else
|
|
{
|
|
pInfo->filters[i+dwNumInFilters].info.wSrcPort =
|
|
MAKEWORD(LOBYTE(LOWORD(pf->uliProtoSrcDstPort.HighPart)),0x00);
|
|
}
|
|
|
|
if(HIBYTE(LOWORD(pf->uliProtoSrcDstMask.HighPart)) isnot 0xff)
|
|
{
|
|
pInfo->filters[i+dwNumInFilters].info.wDstPort = FILTER_ICMP_CODE_ANY;
|
|
}
|
|
else
|
|
{
|
|
pInfo->filters[i+dwNumInFilters].info.wDstPort =
|
|
MAKEWORD(HIBYTE(LOWORD(pf->uliProtoSrcDstPort.HighPart)),0x00);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pInfo->filters[i+dwNumInFilters].info.wSrcPort =
|
|
LOWORD(pf->uliProtoSrcDstPort.HighPart);
|
|
pInfo->filters[i+dwNumInFilters].info.wDstPort =
|
|
HIWORD(pf->uliProtoSrcDstPort.HighPart);
|
|
|
|
if(pInfo->filters[i].info.dwProtocol is FILTER_PROTO_TCP)
|
|
{
|
|
if(HIBYTE(LOWORD(pf->PROTO)))
|
|
{
|
|
pInfo->filters[i].info.dwProtocol = FILTER_PROTO_TCP_ESTAB;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return(STATUS_SUCCESS);
|
|
}
|
|
|
|
NTSTATUS
|
|
MakeNewFilters(
|
|
IN DWORD dwNumFilters,
|
|
IN PFILTER_INFO pFilterInfo,
|
|
IN BOOL fInFilter,
|
|
OUT PLIST_ENTRY pList
|
|
)
|
|
/*++
|
|
Routine Description
|
|
|
|
|
|
Arguments
|
|
|
|
|
|
Return Value
|
|
--*/
|
|
{
|
|
DWORD i;
|
|
PFILTER pCurrent;
|
|
DWORD dwFlags = (fInFilter ? FILTER_FLAGS_INFILTER : 0) |
|
|
FILTER_FLAGS_OLDFILTER;
|
|
|
|
|
|
PAGED_CODE();
|
|
|
|
InitializeListHead(pList);
|
|
|
|
//
|
|
// Allocate memory for the filters
|
|
//
|
|
|
|
if(!dwNumFilters)
|
|
{
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
for(i = 0; i < dwNumFilters; i++)
|
|
{
|
|
pCurrent = ExAllocatePoolWithTag(
|
|
NonPagedPool,
|
|
dwNumFilters * sizeof(FILTER),
|
|
'2liF');
|
|
if(!pCurrent)
|
|
{
|
|
ERROR((
|
|
"IPFLTDRV: MakeNewFilters: Couldnt allocate memory for in filter set\n"
|
|
));
|
|
DeleteFilterList(pList);
|
|
return STATUS_NO_MEMORY;
|
|
}
|
|
|
|
InsertTailList(pList, &pCurrent->pleFilters);
|
|
|
|
pCurrent->SRC_ADDR = pFilterInfo[i].dwSrcAddr;
|
|
pCurrent->DEST_ADDR = pFilterInfo[i].dwDstAddr;
|
|
pCurrent->SRC_MASK = pFilterInfo[i].dwSrcMask;
|
|
pCurrent->DEST_MASK = pFilterInfo[i].dwDstMask;
|
|
pCurrent->fLateBound = pFilterInfo[i].fLateBound;
|
|
pCurrent->dwFlags = dwFlags;
|
|
|
|
//
|
|
// Now the network ordering stuff - tricky part
|
|
// LP0 LP1 LP2 LP3 HP0 HP1 HP2 HP3
|
|
// Proto 00 00 00 SrcPort DstPort
|
|
//
|
|
// If we have proto == TCP_ESTAB, LP1 is the flags
|
|
//
|
|
// LP0 LP1 LP2 LP3 HP0 HP1 HP2 HP3
|
|
// Proto TCPFlags 00 00 SrcPort DstPort
|
|
//
|
|
|
|
//
|
|
// For addresses, ANY_ADDR is given by 0.0.0.0 and the MASK must be 0.0.0.0
|
|
// For proto and ports 0 means any and the mask is generated as follows
|
|
// If the proto is O then LP0 for Mask is 0xff else its 0x00
|
|
// If a port is 0, the corresponding XP0XP1 is 0x0000 else its 0xffff
|
|
//
|
|
|
|
//
|
|
// ICMP:
|
|
// LP0 LP1 LP2 LP3 HP0 HP1 HP2 HP3
|
|
// 0x1 00 00 00 Typ Cod 00 00
|
|
// ICMP is different since 0 is a valid code and type, so 0xff is used by the
|
|
// user to signify that ANY code or type is to be matched. However to do this
|
|
// we need to have the field set to zero and the the mask set to 00 (for any).
|
|
// But if the filter is specifically for Type/Code = 0 then the field is zero
|
|
// with the mask as 0xff
|
|
//
|
|
|
|
//
|
|
// The protocol is in the low byte of the dwProtocol, so we take that out and
|
|
// make a dword out of it
|
|
//
|
|
|
|
pCurrent->uliProtoSrcDstPort.LowPart =
|
|
MAKELONG(MAKEWORD(LOBYTE(LOWORD(pFilterInfo[i].dwProtocol)),0x00),0x0000);
|
|
|
|
pCurrent->uliProtoSrcDstMask.LowPart = MAKELONG(MAKEWORD(0xff,0x00),0x0000);
|
|
|
|
switch(pFilterInfo[i].dwProtocol)
|
|
{
|
|
case FILTER_PROTO_ANY:
|
|
{
|
|
pCurrent->uliProtoSrcDstPort.HighPart = 0x00000000;
|
|
pCurrent->uliProtoSrcDstMask.LowPart = 0x00000000;
|
|
pCurrent->uliProtoSrcDstMask.HighPart = 0x00000000;
|
|
|
|
break;
|
|
}
|
|
case FILTER_PROTO_ICMP:
|
|
{
|
|
WORD wTypeCode = 0x0000;
|
|
WORD wTypeCodeMask = 0x0000;
|
|
|
|
|
|
if((BYTE)(pFilterInfo[i].wSrcPort) isnot FILTER_ICMP_TYPE_ANY)
|
|
{
|
|
wTypeCode |= MAKEWORD((BYTE)(pFilterInfo[i].wSrcPort),0x00);
|
|
wTypeCodeMask |= MAKEWORD(0xff,0x00);
|
|
}
|
|
|
|
if((BYTE)(pFilterInfo[i].wDstPort) isnot FILTER_ICMP_CODE_ANY)
|
|
{
|
|
wTypeCode |= MAKEWORD(0x00,(BYTE)(pFilterInfo[i].wDstPort));
|
|
wTypeCodeMask |= MAKEWORD(0x00,0xff);
|
|
}
|
|
|
|
pCurrent->uliProtoSrcDstPort.HighPart =
|
|
MAKELONG(wTypeCode,0x0000);
|
|
pCurrent->uliProtoSrcDstMask.HighPart =
|
|
MAKELONG(wTypeCodeMask,0x0000);
|
|
|
|
break;
|
|
}
|
|
case FILTER_PROTO_TCP:
|
|
case FILTER_PROTO_UDP:
|
|
{
|
|
DWORD dwSrcDstPort = 0x00000000;
|
|
DWORD dwSrcDstMask = 0x00000000;
|
|
|
|
if(pFilterInfo[i].wSrcPort isnot FILTER_TCPUDP_PORT_ANY)
|
|
{
|
|
dwSrcDstPort |= MAKELONG(pFilterInfo[i].wSrcPort,0x0000);
|
|
dwSrcDstMask |= MAKELONG(0xffff,0x0000);
|
|
}
|
|
|
|
if(pFilterInfo[i].wDstPort isnot FILTER_TCPUDP_PORT_ANY)
|
|
{
|
|
dwSrcDstPort |= MAKELONG(0x0000,pFilterInfo[i].wDstPort);
|
|
dwSrcDstMask |= MAKELONG(0x0000,0xffff);
|
|
}
|
|
|
|
pCurrent->uliProtoSrcDstPort.HighPart = dwSrcDstPort;
|
|
pCurrent->uliProtoSrcDstMask.HighPart = dwSrcDstMask;
|
|
|
|
break;
|
|
}
|
|
case FILTER_PROTO_TCP_ESTAB:
|
|
{
|
|
DWORD dwSrcDstPort = 0x00000000;
|
|
DWORD dwSrcDstMask = 0x00000000;
|
|
|
|
//
|
|
// The actual protocol is FILTER_PROTO_TCP
|
|
//
|
|
|
|
pCurrent->uliProtoSrcDstPort.LowPart =
|
|
MAKELONG(MAKEWORD(FILTER_PROTO_TCP,ESTAB_FLAGS),0x0000);
|
|
|
|
pCurrent->uliProtoSrcDstMask.LowPart =
|
|
MAKELONG(MAKEWORD(0xff,ESTAB_MASK),0x0000);
|
|
|
|
if(pFilterInfo[i].wSrcPort isnot FILTER_TCPUDP_PORT_ANY)
|
|
{
|
|
dwSrcDstPort |= MAKELONG(pFilterInfo[i].wSrcPort,0x0000);
|
|
dwSrcDstMask |= MAKELONG(0xffff,0x0000);
|
|
}
|
|
|
|
if(pFilterInfo[i].wDstPort isnot FILTER_TCPUDP_PORT_ANY)
|
|
{
|
|
dwSrcDstPort |= MAKELONG(0x0000,pFilterInfo[i].wDstPort);
|
|
dwSrcDstMask |= MAKELONG(0x0000,0xffff);
|
|
}
|
|
|
|
pCurrent->uliProtoSrcDstPort.HighPart = dwSrcDstPort;
|
|
pCurrent->uliProtoSrcDstMask.HighPart = dwSrcDstMask;
|
|
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
//
|
|
// All other protocols have no use for the port field
|
|
//
|
|
pCurrent->uliProtoSrcDstPort.HighPart = 0x00000000;
|
|
pCurrent->uliProtoSrcDstMask.HighPart = 0x00000000;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
#endif // STEELHEAD
|
|
|
|
VOID
|
|
DeleteFilters(
|
|
IN PFILTER_INTERFACE pIf,
|
|
DWORD dwInOrOut
|
|
)
|
|
/*++
|
|
Routine Description
|
|
Deletes all filters associated with an interface
|
|
Assumes that the write lock for this interface is held
|
|
|
|
Arguments
|
|
pIf Pointer to interface
|
|
|
|
Return Value
|
|
--*/
|
|
{
|
|
if(dwInOrOut == IN_FILTER_SET)
|
|
{
|
|
pIf->dwNumInFilters = 0;
|
|
|
|
DeleteFilterList(&pIf->pleInFilterSet);
|
|
}
|
|
else
|
|
{
|
|
pIf->dwNumOutFilters = 0;
|
|
|
|
DeleteFilterList(&pIf->pleOutFilterSet);
|
|
}
|
|
}
|
|
|
|
NTSTATUS
|
|
SetFiltersEx(
|
|
IN PPFFCB Fcb,
|
|
IN PPAGED_FILTER_INTERFACE pPage,
|
|
IN DWORD dwLength,
|
|
IN PFILTER_DRIVER_SET_FILTERS pInfo)
|
|
/*++
|
|
Routine Description:
|
|
Set filters use the new interface definitions.
|
|
|
|
--*/
|
|
{
|
|
PRTR_TOC_ENTRY pInToc,pOutToc;
|
|
PFILTER_INTERFACE pIf = pPage->pFilter;
|
|
PFILTER_DESCRIPTOR2 pFilterDescIn, pFilterDescOut;
|
|
DWORD dwInCount, dwOutCount;
|
|
DWORD i;
|
|
PPAGED_FILTER pPFilter;
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
PBYTE pbEnd = (PBYTE)pInfo + dwLength;
|
|
DWORD dwFiltersAdded = 0;
|
|
|
|
PAGED_CODE();
|
|
|
|
|
|
if(pIf->dwGlobalEnables & FI_ENABLE_OLD)
|
|
{
|
|
return(STATUS_INVALID_DEVICE_REQUEST);
|
|
}
|
|
pInToc = GetPointerToTocEntry(IP_FILTER_DRIVER_IN_FILTER_INFO,
|
|
&pInfo->ribhInfoBlock);
|
|
|
|
pOutToc = GetPointerToTocEntry(IP_FILTER_DRIVER_OUT_FILTER_INFO,
|
|
&pInfo->ribhInfoBlock);
|
|
|
|
if(pInToc && pInToc->InfoSize)
|
|
{
|
|
//
|
|
// filters are defined.
|
|
//
|
|
|
|
pFilterDescIn = GetInfoFromTocEntry(&pInfo->ribhInfoBlock,
|
|
pInToc);
|
|
if(pFilterDescIn->dwVersion != 2)
|
|
{
|
|
ERROR(("IPFLTDRV: SetFiltersEx: Invalid version for FiltersEx\n"));
|
|
return(STATUS_INVALID_PARAMETER);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pFilterDescIn = NULL;
|
|
}
|
|
|
|
if(pOutToc && pOutToc->InfoSize)
|
|
{
|
|
//
|
|
// filters are defined.
|
|
//
|
|
|
|
pFilterDescOut = GetInfoFromTocEntry(&pInfo->ribhInfoBlock,
|
|
pOutToc);
|
|
if(pFilterDescOut->dwVersion != 2)
|
|
{
|
|
ERROR(("IPFLTDRV: SetFiltersEx: Invalid version for FiltersEx\n"));
|
|
return(STATUS_INVALID_PARAMETER);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pFilterDescOut = NULL;
|
|
}
|
|
|
|
//
|
|
// For each set of filters, add the filters to the paged, FCB
|
|
// interface and therefore to the match interface.
|
|
//
|
|
|
|
if((pFilterDescIn && !CheckDescriptorSize(pFilterDescIn, pbEnd))
|
|
||
|
|
(pFilterDescOut && !CheckDescriptorSize(pFilterDescOut, pbEnd)) )
|
|
{
|
|
return(STATUS_BUFFER_TOO_SMALL);
|
|
}
|
|
|
|
if(pFilterDescIn)
|
|
{
|
|
// Adding in filters. For each filter, process as
|
|
// needed. Input filters include the global checks
|
|
/// such as spoofing.
|
|
//
|
|
|
|
for(dwInCount = 0;
|
|
(dwInCount < pFilterDescIn->dwNumFilters);
|
|
dwInCount++)
|
|
{
|
|
PFILTER_INFOEX pFilt = &pFilterDescIn->fiFilter[dwInCount];
|
|
BOOL bAdded;
|
|
|
|
//
|
|
// If a regular filter, add it. If a special, global
|
|
// filter, handle it specially.
|
|
//
|
|
|
|
if(pFilt->type == PFE_FILTER)
|
|
{
|
|
Status = AllocateAndAddFilterToMatchInterface(
|
|
Fcb,
|
|
pFilt,
|
|
TRUE,
|
|
pPage,
|
|
&bAdded,
|
|
&pPFilter);
|
|
if(!NT_SUCCESS(Status))
|
|
{
|
|
if((Status == STATUS_OBJECT_NAME_COLLISION)
|
|
&&
|
|
pPFilter)
|
|
{
|
|
if(!fCheckDups
|
|
||
|
|
(pPFilter->dwFlags & FLAGS_INFOEX_ALLOWDUPS))
|
|
{
|
|
pPFilter->dwInUse++;
|
|
Status = STATUS_SUCCESS;
|
|
}
|
|
else
|
|
{
|
|
ERROR((
|
|
"IPFLTDRV: Adding in filter failed %x\n",
|
|
Status
|
|
));
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
else if(bAdded && (pIf->eaInAction == FORWARD))
|
|
{
|
|
dwFiltersAdded++;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// a special filter of some sort.
|
|
//
|
|
|
|
pPFilter = MakePagedFilter(Fcb, pFilt, pPage->dwUpdateEpoch, 0);
|
|
if(!pPFilter)
|
|
{
|
|
Status = STATUS_NO_MEMORY;
|
|
}
|
|
else
|
|
{
|
|
PPAGED_FILTER pWhoCares;
|
|
|
|
if(IsOnSpecialFilterList(pPFilter,
|
|
&pPage->leSpecialFilterList,
|
|
&pWhoCares))
|
|
{
|
|
|
|
pWhoCares->dwInUse++;
|
|
ExFreePool(pPFilter);
|
|
pPFilter = 0;
|
|
}
|
|
else
|
|
{
|
|
switch(pFilt->type)
|
|
{
|
|
case PFE_SYNORFRAG:
|
|
case PFE_SPOOF:
|
|
case PFE_UNUSEDPORT:
|
|
case PFE_ALLOWCTL:
|
|
case PFE_STRONGHOST:
|
|
case PFE_FULLDENY:
|
|
case PFE_NOFRAG:
|
|
case PFE_FRAGCACHE:
|
|
AddGlobalFilterToInterface(pPage, pFilt);
|
|
break;
|
|
default:
|
|
ERROR(("IPFLTDRV: Unknown filter type\n"));
|
|
ExFreePool(pPFilter);
|
|
pPFilter = 0;
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
break;
|
|
}
|
|
}
|
|
if(pPFilter)
|
|
{
|
|
InsertTailList(&pPage->leSpecialFilterList,
|
|
&pPFilter->leSpecialList);
|
|
}
|
|
else if(!NT_SUCCESS(Status))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
dwInCount = 0;
|
|
}
|
|
|
|
if(!NT_SUCCESS(Status))
|
|
{
|
|
RemoveFilterWorker(
|
|
Fcb,
|
|
&pFilterDescIn->fiFilter[0],
|
|
dwInCount,
|
|
pPage,
|
|
&dwFiltersAdded,
|
|
TRUE);
|
|
return(Status);
|
|
}
|
|
|
|
|
|
//
|
|
// now the output filters. This is a bit simpler since there
|
|
// are no global settings.
|
|
//
|
|
|
|
if(pFilterDescOut)
|
|
{
|
|
//
|
|
// Adding in filters. For each filter, process as
|
|
// needed. Input filters include the global checks
|
|
/// such as spoofing.
|
|
//
|
|
|
|
for(dwOutCount = 0;
|
|
dwOutCount < pFilterDescOut->dwNumFilters;
|
|
dwOutCount++)
|
|
{
|
|
PFILTER_INFOEX pFilt = &pFilterDescOut->fiFilter[dwOutCount];
|
|
BOOL bAdded;
|
|
|
|
//
|
|
// If a regular filter, add it. If a special, global
|
|
// filter, handle it specially.
|
|
//
|
|
|
|
if(pFilt->type == PFE_FILTER)
|
|
{
|
|
Status = AllocateAndAddFilterToMatchInterface(
|
|
Fcb,
|
|
pFilt,
|
|
FALSE,
|
|
pPage,
|
|
&bAdded,
|
|
&pPFilter);
|
|
if(!NT_SUCCESS(Status))
|
|
{
|
|
if((Status == STATUS_OBJECT_NAME_COLLISION)
|
|
&&
|
|
pPFilter)
|
|
{
|
|
if(!fCheckDups
|
|
||
|
|
(pPFilter->dwFlags & FLAGS_INFOEX_ALLOWDUPS))
|
|
{
|
|
pPFilter->dwInUse++;
|
|
Status = STATUS_SUCCESS;
|
|
}
|
|
else
|
|
{
|
|
ERROR((
|
|
"IPFLTDRV: Adding out filter failed %x\n",
|
|
Status
|
|
));
|
|
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
else if(bAdded && (pIf->eaOutAction == FORWARD))
|
|
{
|
|
dwFiltersAdded++;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ERROR(("IPFLTDRV: Ignoring global out filter\n"));
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
if(!NT_SUCCESS(Status))
|
|
{
|
|
RemoveFilterWorker(
|
|
Fcb,
|
|
&pFilterDescIn->fiFilter[0],
|
|
dwInCount,
|
|
pPage,
|
|
&dwFiltersAdded,
|
|
TRUE);
|
|
RemoveFilterWorker(
|
|
Fcb,
|
|
&pFilterDescOut->fiFilter[0],
|
|
dwOutCount,
|
|
pPage,
|
|
&dwFiltersAdded,
|
|
FALSE);
|
|
|
|
}
|
|
else if(dwFiltersAdded)
|
|
{
|
|
NotifyFastPath(pIf, pIf->dwIpIndex, NOT_RESTRICTION);
|
|
}
|
|
return(Status);
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
UpdateBindingInformationEx(
|
|
PFILTER_DRIVER_BINDING_INFO pBindInfo,
|
|
PPAGED_FILTER_INTERFACE pPage)
|
|
/*++
|
|
Routine Description:
|
|
Just like the routine below. But this fixes up the
|
|
paged filters only
|
|
--*/
|
|
|
|
{
|
|
PPAGED_FILTER pf;
|
|
DWORD i;
|
|
|
|
if((pPage->pFilter->dwGlobalEnables & FI_ENABLE_OLD))
|
|
{
|
|
return(STATUS_INVALID_DEVICE_REQUEST);
|
|
}
|
|
|
|
pPage->dwUpdateEpoch++;
|
|
|
|
//
|
|
// update all filters on this paged interface
|
|
//
|
|
|
|
for(i = 0; i < g_dwHashLists; i++)
|
|
{
|
|
PLIST_ENTRY List = &pPage->HashList[i];
|
|
PLIST_ENTRY pList, NextListItem;
|
|
|
|
for(pList = List->Flink;
|
|
pList != List;
|
|
pList = NextListItem)
|
|
{
|
|
NextListItem = pList->Flink;
|
|
|
|
pf = CONTAINING_RECORD(pList, PAGED_FILTER, leHash);
|
|
|
|
if(pf->dwEpoch == pPage->dwUpdateEpoch)
|
|
{
|
|
break;
|
|
}
|
|
|
|
if(AreAllFieldsUnchanged(pf))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// it's to be changed. Take it off of its hash list
|
|
// so it can be rehashed when we are done
|
|
//
|
|
|
|
RemoveEntryList(&pf->leHash);
|
|
|
|
if(DoesSrcAddrUseLocalAddr(pf))
|
|
{
|
|
pf->SRC_ADDR = pBindInfo->dwLocalAddr;
|
|
}
|
|
else if(DoesSrcAddrUseRemoteAddr(pf))
|
|
{
|
|
pf->SRC_ADDR = pBindInfo->dwRemoteAddr;
|
|
}
|
|
|
|
if(DoesDstAddrUseLocalAddr(pf))
|
|
{
|
|
pf->DEST_ADDR = pBindInfo->dwLocalAddr;
|
|
}
|
|
else if(DoesDstAddrUseRemoteAddr(pf))
|
|
{
|
|
pf->DEST_ADDR = pBindInfo->dwRemoteAddr;
|
|
}
|
|
|
|
if(IsSrcMaskLateBound(pf))
|
|
{
|
|
pf->SRC_MASK = pBindInfo->dwMask;
|
|
}
|
|
|
|
if(IsDstMaskLateBound(pf))
|
|
{
|
|
pf->DEST_MASK = pBindInfo->dwMask;
|
|
}
|
|
|
|
pf->dwEpoch = pPage->dwUpdateEpoch;
|
|
|
|
//
|
|
// compute new hash index
|
|
//
|
|
|
|
pf->dwHashIndex = (
|
|
pf->SRC_ADDR +
|
|
pf->DEST_ADDR +
|
|
pf->DEST_ADDR +
|
|
PROTOCOLPART(pf->uliProtoSrcDstPort.LowPart) +
|
|
pf->uliProtoSrcDstPort.HighPart) % g_dwHashLists;
|
|
|
|
|
|
InsertTailList(&pPage->HashList[pf->dwHashIndex],
|
|
&pf->leHash);
|
|
}
|
|
|
|
}
|
|
|
|
return(UpdateMatchBindingInformation(pBindInfo, (PVOID)pPage->pFilter));
|
|
}
|
|
|
|
VOID
|
|
UpdateLateBoundFilter(PFILTER pf,
|
|
DWORD dwLocalAddr,
|
|
DWORD dwRemoteAddr,
|
|
DWORD dwMask)
|
|
{
|
|
|
|
if(DoesSrcAddrUseLocalAddr(pf))
|
|
{
|
|
pf->SRC_ADDR = dwLocalAddr;
|
|
}
|
|
else if(DoesSrcAddrUseRemoteAddr(pf))
|
|
{
|
|
pf->SRC_ADDR = dwRemoteAddr;
|
|
}
|
|
|
|
if(DoesDstAddrUseLocalAddr(pf))
|
|
{
|
|
pf->DEST_ADDR = dwLocalAddr;
|
|
}
|
|
else if(DoesDstAddrUseRemoteAddr(pf))
|
|
{
|
|
pf->DEST_ADDR = dwRemoteAddr;
|
|
}
|
|
|
|
if(IsSrcMaskLateBound(pf))
|
|
{
|
|
pf->SRC_MASK = dwMask;
|
|
}
|
|
|
|
if(IsDstMaskLateBound(pf))
|
|
{
|
|
pf->DEST_MASK = dwMask;
|
|
}
|
|
}
|
|
|
|
NTSTATUS
|
|
UpdateMatchBindingInformation(
|
|
PFILTER_DRIVER_BINDING_INFO pBindInfo,
|
|
PVOID pvContext
|
|
)
|
|
/*++
|
|
Routine Description
|
|
Update the bindings for a new style interface
|
|
|
|
Arguments
|
|
pvIf Pointer to FILTER_INTERFACE structure which was passed as a PVOID
|
|
to router manager as a context for the interface
|
|
pInfo FILTER_IF structure filled in by driver
|
|
|
|
Return Value
|
|
|
|
--*/
|
|
{
|
|
PFILTER_INTERFACE pIf;
|
|
LOCK_STATE LockState;
|
|
PFILTER pf;
|
|
DWORD i;
|
|
DWORD dwX;
|
|
PLIST_ENTRY List, NextList;
|
|
|
|
pIf = (PFILTER_INTERFACE)pvContext;
|
|
|
|
AcquireWriteLock(&g_filters.ifListLock,&LockState);
|
|
|
|
pIf->dwUpdateEpoch++;
|
|
|
|
for(i = 0; i < g_dwHashLists; i++)
|
|
{
|
|
|
|
for(List = pIf->HashList[i].Flink;
|
|
List != &pIf->HashList[i];
|
|
List = NextList)
|
|
{
|
|
pf = CONTAINING_RECORD(List, FILTER, pleHashList);
|
|
|
|
NextList = List->Flink;
|
|
|
|
if(pf->dwEpoch == pIf->dwUpdateEpoch)
|
|
{
|
|
break;
|
|
}
|
|
|
|
pf->dwEpoch = pIf->dwUpdateEpoch;
|
|
|
|
if(!AreAllFieldsUnchanged(pf))
|
|
{
|
|
BOOL fWild;
|
|
|
|
UpdateLateBoundFilter(pf,
|
|
pBindInfo->dwLocalAddr,
|
|
pBindInfo->dwRemoteAddr,
|
|
pBindInfo->dwMask);
|
|
|
|
|
|
dwX = ComputeMatchHashIndex(pf, &fWild);
|
|
RemoveEntryList(&pf->pleHashList);
|
|
InsertTailList(&pIf->HashList[dwX], &pf->pleHashList);
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// finally the wild card filters
|
|
//
|
|
for(i = g_dwHashLists; i <= g_dwHashLists + 1; i++)
|
|
{
|
|
for(List = pIf->HashList[i].Flink;
|
|
List != &pIf->HashList[i];
|
|
List = List->Flink)
|
|
{
|
|
pf = CONTAINING_RECORD(List, FILTER, pleHashList);
|
|
|
|
if(pf->dwEpoch == pIf->dwUpdateEpoch)
|
|
{
|
|
break;
|
|
}
|
|
|
|
pf->dwEpoch = pIf->dwUpdateEpoch;
|
|
if(!AreAllFieldsUnchanged(pf))
|
|
{
|
|
UpdateLateBoundFilter(pf,
|
|
pBindInfo->dwLocalAddr,
|
|
pBindInfo->dwRemoteAddr,
|
|
pBindInfo->dwMask);
|
|
}
|
|
|
|
}
|
|
}
|
|
ClearCache();
|
|
ReleaseWriteLock(&g_filters.ifListLock,&LockState);
|
|
NotifyFastPathIf(pIf);
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
PFILTER_INTERFACE
|
|
NewInterface(
|
|
IN PVOID pvContext,
|
|
IN DWORD dwIndex,
|
|
IN FORWARD_ACTION inAction,
|
|
IN FORWARD_ACTION outAction,
|
|
IN PVOID pvOldInterfaceContext,
|
|
IN DWORD dwIpIndex,
|
|
IN DWORD dwName
|
|
)
|
|
/*++
|
|
Routine Description
|
|
Interface constructor
|
|
|
|
Arguments
|
|
pIf Pointer to interface
|
|
|
|
Return Value
|
|
--*/
|
|
{
|
|
PFILTER_INTERFACE pIf;
|
|
|
|
PAGED_CODE();
|
|
|
|
pIf = (PFILTER_INTERFACE)ExAllocatePoolWithTag(NonPagedPool,
|
|
FILTER_INTERFACE_SIZE,
|
|
'1liF');
|
|
|
|
if(pIf != NULL)
|
|
{
|
|
DWORD i;
|
|
|
|
RtlZeroMemory(pIf, sizeof(*pIf));
|
|
pIf->dwNumOutFilters = pIf->dwNumInFilters = 0;
|
|
pIf->pvRtrMgrContext = pvContext;
|
|
pIf->dwRtrMgrIndex = dwIndex;
|
|
pIf->eaInAction = inAction;
|
|
pIf->eaOutAction = outAction;
|
|
pIf->dwIpIndex = dwIpIndex;
|
|
pIf->dwLinkIpAddress = 0;
|
|
pIf->lInUse = 1;
|
|
pIf->lTotalInDrops = pIf->lTotalOutDrops = 0;
|
|
pIf->dwName = dwName;
|
|
pIf->dwUpdateEpoch = 0;
|
|
pIf->pvHandleContext = pvOldInterfaceContext;
|
|
InitializeListHead(&pIf->pleInFilterSet);
|
|
InitializeListHead(&pIf->pleOutFilterSet);
|
|
for(i = 0; i < FRAG_NUMBEROFENTRIES; i++)
|
|
{
|
|
InitializeListHead(&pIf->FragLists[i]);
|
|
}
|
|
for(i = 0; i <= (g_dwHashLists + 1); i++)
|
|
{
|
|
InitializeListHead(&pIf->HashList[i]);
|
|
}
|
|
}
|
|
|
|
return pIf;
|
|
}
|
|
|
|
|
|
VOID
|
|
DeleteFilterList(PLIST_ENTRY pList)
|
|
/*++
|
|
Routine Description
|
|
Free the list of filters given
|
|
--*/
|
|
{
|
|
while(!IsListEmpty(pList))
|
|
{
|
|
PLIST_ENTRY pEntry = RemoveHeadList(pList);
|
|
|
|
ExFreePool(pEntry);
|
|
}
|
|
}
|
|
|
|
VOID
|
|
ClearFragCache()
|
|
|
|
/*++
|
|
Routine Description
|
|
Clears the fragments cache
|
|
|
|
|
|
Arguments
|
|
None
|
|
|
|
Return Value
|
|
None
|
|
--*/
|
|
{
|
|
DWORD i;
|
|
KIRQL kiCurrIrql;
|
|
PLIST_ENTRY pleNode;
|
|
|
|
if (g_pleFragTable)
|
|
{
|
|
KeAcquireSpinLock(&g_kslFragLock, &kiCurrIrql);
|
|
|
|
for(i = 0; i < g_dwFragTableSize; i++)
|
|
{
|
|
|
|
PLIST_ENTRY pleNode;
|
|
pleNode = g_pleFragTable[i].Flink;
|
|
|
|
while(pleNode != &(g_pleFragTable[i]))
|
|
{
|
|
PFRAG_INFO pfiFragInfo;
|
|
|
|
pfiFragInfo = CONTAINING_RECORD(pleNode, FRAG_INFO, leCacheLink);
|
|
pleNode = pleNode->Flink;
|
|
RemoveEntryList(&(pfiFragInfo->leCacheLink));
|
|
|
|
ExFreeToNPagedLookasideList(
|
|
&g_llFragCacheBlocks,
|
|
pfiFragInfo);
|
|
}
|
|
}
|
|
|
|
KeReleaseSpinLock(&g_kslFragLock,
|
|
kiCurrIrql);
|
|
}
|
|
TRACE(FRAG,("IPFLTDRV: Frag cache cleanup Done\n"));
|
|
|
|
|
|
}
|
|
|
|
VOID
|
|
ClearCache()
|
|
/*++
|
|
Routine Description
|
|
Clears the input and output caches
|
|
Assumes that the write lock has been acquired (for the system)
|
|
|
|
Arguments
|
|
None
|
|
|
|
Return Value
|
|
None
|
|
--*/
|
|
{
|
|
DWORD i;
|
|
PLIST_ENTRY pleNode;
|
|
|
|
//
|
|
// This code assumes that the g_filter.pIn/OutCache is valid and that each of the
|
|
// pointers in the array are valid. If they are not, there is something seriously
|
|
// wrong and you would end up blue screening in someother part of the code anyways
|
|
//
|
|
|
|
TRACE(CACHE,("IPFLTDRV: Clearing in and out cache..."));
|
|
|
|
for(i = 0; i < g_dwCacheSize; i ++)
|
|
{
|
|
ClearInCacheEntry(g_filters.ppInCache[i]);
|
|
ClearOutCacheEntry(g_filters.ppOutCache[i]);
|
|
}
|
|
|
|
TRACE(CACHE,("IPFLTDRV: Done Clearing in and out cache\n"));
|
|
|
|
pleNode = g_freeInFilters.Flink;
|
|
|
|
TRACE(CACHE,("IPFLTDRV: Clearing in free list...\n"));
|
|
|
|
while(pleNode isnot &g_freeInFilters)
|
|
{
|
|
PFILTER_INCACHE pInCache;
|
|
|
|
pInCache = CONTAINING_RECORD(pleNode,FILTER_INCACHE,leFreeLink);
|
|
|
|
ClearInFreeEntry(pInCache);
|
|
|
|
pleNode = pleNode->Flink;
|
|
}
|
|
|
|
TRACE(CACHE,("IPFLTDRV: Done Clearing in free list\n"));
|
|
|
|
pleNode = g_freeOutFilters.Flink;
|
|
|
|
TRACE(CACHE,("IPFLTDRV: Clearing out free list...\n"));
|
|
|
|
while(pleNode isnot &g_freeOutFilters)
|
|
{
|
|
PFILTER_OUTCACHE pOutCache;
|
|
|
|
pOutCache = CONTAINING_RECORD(pleNode,FILTER_OUTCACHE,leFreeLink);
|
|
|
|
ClearOutFreeEntry(pOutCache);
|
|
|
|
pleNode = pleNode->Flink;
|
|
}
|
|
|
|
TRACE(CACHE,("IPFLTDRV: Done Clearing out free list\n"));
|
|
|
|
ClearFragCache();
|
|
|
|
CALLTRACE(("IPFLTDRV: ClearCache Done\n"));
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
PRTR_TOC_ENTRY
|
|
GetPointerToTocEntry(
|
|
DWORD dwType,
|
|
PRTR_INFO_BLOCK_HEADER pInfoHdr
|
|
)
|
|
{
|
|
DWORD i;
|
|
|
|
PAGED_CODE();
|
|
|
|
if(!pInfoHdr)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
for(i = 0; i < pInfoHdr->TocEntriesCount; i++)
|
|
{
|
|
if(pInfoHdr->TocEntry[i].InfoType is dwType)
|
|
{
|
|
return &(pInfoHdr->TocEntry[i]);
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
NTSTATUS
|
|
AddNewInterface(PPFINTERFACEPARAMETERS pInfo,
|
|
PPFFCB Fcb)
|
|
/*++
|
|
Routine Description:
|
|
Create a new interface for this handle. Also create or
|
|
merge with a common underlying interface.
|
|
--*/
|
|
{
|
|
PPAGED_FILTER_INTERFACE pgIf;
|
|
PPAGED_FILTER_INTERFACE pPaged;
|
|
DWORD dwBind = pInfo->dwBindingData;
|
|
NTSTATUS Status;
|
|
KPROCESSOR_MODE Mode;
|
|
DWORD i, dwName = 0;
|
|
|
|
PAGED_CODE();
|
|
|
|
if(Fcb->dwFlags & PF_FCB_OLD)
|
|
{
|
|
return(STATUS_INVALID_DEVICE_REQUEST);
|
|
}
|
|
|
|
Fcb->dwFlags |= PF_FCB_NEW;
|
|
|
|
Mode = ExGetPreviousMode();
|
|
|
|
//
|
|
// verify that this interface is unique on this handle.
|
|
//
|
|
|
|
switch(pInfo->pfbType)
|
|
{
|
|
default:
|
|
Status = STATUS_NO_SUCH_DEVICE;
|
|
break;
|
|
|
|
case PF_BIND_NONE:
|
|
|
|
dwBind = UNKNOWN_IP_INDEX;
|
|
Status = STATUS_SUCCESS;
|
|
break;
|
|
|
|
case PF_BIND_NAME:
|
|
|
|
dwName = dwBind;
|
|
dwBind = UNKNOWN_IP_INDEX;
|
|
Status = STATUS_SUCCESS;
|
|
break;
|
|
}
|
|
|
|
if(NT_SUCCESS(Status))
|
|
{
|
|
//
|
|
// it's not in use on this handle. So create an PAGED
|
|
// FCB to remember this and to link into a non-paged interface.
|
|
//
|
|
|
|
pPaged = ExAllocatePoolWithTag(PagedPool,
|
|
PAGED_INTERFACE_SIZE,
|
|
'pfpI');
|
|
if(!pPaged)
|
|
{
|
|
return(STATUS_NO_MEMORY);
|
|
}
|
|
|
|
//
|
|
// fill in the paged filter definition and allocate
|
|
// a non-paged filter. The non-paged filter could already
|
|
// exist, in which case simply link this to the existing
|
|
// one.
|
|
|
|
if(pInfo->pfLogId)
|
|
{
|
|
//
|
|
// If a Log ID is given, reference the log to
|
|
// prevent it from going away
|
|
//
|
|
|
|
Status = ReferenceLogByHandleId(pInfo->pfLogId,
|
|
Fcb,
|
|
&pPaged->pLog);
|
|
if(!NT_SUCCESS(Status))
|
|
{
|
|
ExFreePool(pPaged);
|
|
return(Status);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pPaged->pLog = NULL;
|
|
}
|
|
|
|
pPaged->dwNumInFilters = pPaged->dwNumOutFilters = 0;
|
|
pPaged->eaInAction = pInfo->eaIn;
|
|
pPaged->eaOutAction = pInfo->eaOut;
|
|
pPaged->dwGlobalEnables = 0;
|
|
pPaged->pvRtrMgrContext = pInfo->fdInterface.pvRtrMgrContext;
|
|
pPaged->dwRtrMgrIndex = pInfo->fdInterface.dwIfIndex;
|
|
pPaged->dwUpdateEpoch = 0;
|
|
|
|
|
|
Status = CreateCommonInterface(pPaged,
|
|
dwBind,
|
|
dwName,
|
|
pInfo->dwInterfaceFlags);
|
|
|
|
if(!NT_SUCCESS(Status))
|
|
{
|
|
if(pPaged->pLog)
|
|
{
|
|
ERROR(("IPFLTDRV: CreateCommonInterface failed: DereferenceLog being called\n"));
|
|
DereferenceLog(pPaged->pLog);
|
|
}
|
|
ExFreePool(pPaged);
|
|
return(Status);
|
|
}
|
|
|
|
pPaged->pvDriverContext =
|
|
pInfo->fdInterface.pvDriverContext = (PVOID)pPaged;
|
|
|
|
InitializeListHead(&pPaged->leSpecialFilterList);
|
|
|
|
for(i = 0; i < 2 * g_dwHashLists; i++)
|
|
{
|
|
PLIST_ENTRY List = &pPaged->HashList[i];
|
|
|
|
InitializeListHead(List);
|
|
}
|
|
|
|
InsertTailList(&Fcb->leInterfaces, &pPaged->leIfLink);
|
|
}
|
|
return(Status);
|
|
}
|
|
|
|
BOOL
|
|
DereferenceFilterInterface(PFILTER_INTERFACE pIf, PPFLOGINTERFACE pLog)
|
|
/*++
|
|
Routine Description:
|
|
Nonpaged routine to dereference a match interface. If the
|
|
reference count goes to zero, free the interface
|
|
--*/
|
|
{
|
|
LOCK_STATE LockState, LockState2;
|
|
BOOL fRel = FALSE;
|
|
|
|
//
|
|
// lock the resource that protects adding new interfaces. This
|
|
// is needed to hold off others until everything is properly
|
|
// verified. The spin lock is insufficient for this.
|
|
//
|
|
|
|
KeEnterCriticalRegion();
|
|
ExAcquireResourceExclusiveLite(&FilterListResourceLock, TRUE);
|
|
AcquireWriteLock(&g_filters.ifListLock,&LockState);
|
|
|
|
if(--pIf->lInUse == 0)
|
|
{
|
|
RemoveEntryList(&pIf->leIfLink);
|
|
if(pIf->dwIpIndex != UNKNOWN_IP_INDEX)
|
|
{
|
|
InterlockedCleanCache(g_filters.pInterfaceCache, pIf->dwIpIndex, pIf->dwLinkIpAddress);
|
|
InterlockedDecrement(&g_ulBoundInterfaceCount);
|
|
|
|
TRACE(CONFIG,(
|
|
"IPFLTDRV: UnBound Interface Index=%d, Link=%d, TotalCnt=%d\n",
|
|
pIf->dwIpIndex,
|
|
pIf->dwLinkIpAddress,
|
|
g_ulBoundInterfaceCount
|
|
));
|
|
}
|
|
fRel = TRUE;
|
|
}
|
|
|
|
ReleaseWriteLock(&g_filters.ifListLock,&LockState);
|
|
|
|
if(fRel)
|
|
{
|
|
//
|
|
// Getting rid of it
|
|
//
|
|
|
|
if(pIf->dwIpIndex != UNKNOWN_IP_INDEX)
|
|
{
|
|
DWORD dwIndex = pIf->dwIpIndex;
|
|
|
|
pIf->dwIpIndex = UNKNOWN_IP_INDEX;
|
|
NotifyFastPath(pIf, dwIndex, NOT_UNBIND);
|
|
}
|
|
|
|
AcquireWriteLock(&g_filters.ifListLock,&LockState2);
|
|
ClearCache();
|
|
ReleaseWriteLock(&g_filters.ifListLock,&LockState2);
|
|
|
|
if(pIf->pLog)
|
|
{
|
|
DereferenceLog(pIf->pLog);
|
|
}
|
|
ExFreePool(pIf);
|
|
}
|
|
else if(pLog)
|
|
{
|
|
//
|
|
// this deref owns the log. So take the log off of the
|
|
// the interface. Note it may be true that the match interface
|
|
// has a different log than the paged interface. This will
|
|
// happen if the log is closed while it exists on the interface.
|
|
// In such a case, the log is removed from the match interface
|
|
// but not the paged interface. And when the paged interface
|
|
// is closed, as is happening now, the log it has is incorrect.
|
|
// So this check is required.
|
|
// The FilterListResourceLock serializes all of this ...
|
|
//
|
|
|
|
if(pLog == pIf->pLog)
|
|
{
|
|
AcquireWriteLock(&g_filters.ifListLock,&LockState2);
|
|
pIf->pLog = 0;
|
|
ReleaseWriteLock(&g_filters.ifListLock,&LockState2);
|
|
DereferenceLog(pLog);
|
|
}
|
|
}
|
|
|
|
ExReleaseResourceLite(&FilterListResourceLock);
|
|
KeLeaveCriticalRegion();
|
|
return(fRel);
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
CreateCommonInterface(PPAGED_FILTER_INTERFACE pPage,
|
|
DWORD dwBind,
|
|
DWORD dwName,
|
|
DWORD dwFlags)
|
|
/*++
|
|
Routine Description:
|
|
Non-paged routine called by AddNewInterface to bind the
|
|
paged interface to an underlying interface, and to bind
|
|
that to a stack interface. The caller should have
|
|
verified that dwBind is a valid stack interface.
|
|
--*/
|
|
{
|
|
PFILTER_INTERFACE pIf, pIf1;
|
|
LOCK_STATE LockState;
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
PPFLOGINTERFACE pLog = pPage->pLog;
|
|
|
|
pIf = NewInterface(pPage->pvRtrMgrContext,
|
|
pPage->dwRtrMgrIndex,
|
|
pPage->eaInAction,
|
|
pPage->eaOutAction,
|
|
0,
|
|
dwBind,
|
|
dwName);
|
|
|
|
if(pIf == NULL)
|
|
{
|
|
return STATUS_NO_MEMORY;
|
|
}
|
|
|
|
if(dwFlags & PFSET_FLAGS_UNIQUE)
|
|
{
|
|
pIf->dwGlobalEnables |= FI_ENABLE_UNIQUE;
|
|
}
|
|
|
|
//
|
|
// lock the resource that protects adding new interfaces. This
|
|
// is needed to hold off others until everything is properly
|
|
// verified. The spin lock is insufficient for this.
|
|
//
|
|
|
|
KeEnterCriticalRegion();
|
|
ExAcquireResourceExclusiveLite(&FilterListResourceLock, TRUE);
|
|
|
|
|
|
//
|
|
// Now reconcile the binding. Note that we had to make the interface
|
|
// first in order to prevent a race with another process trying
|
|
// to bind to the same stack interface.
|
|
//
|
|
|
|
AcquireWriteLock(&g_filters.ifListLock,&LockState);
|
|
|
|
if((dwBind != UNKNOWN_IP_INDEX)
|
|
||
|
|
dwName)
|
|
{
|
|
|
|
pIf1 = FindMatchName(dwName, dwBind);
|
|
|
|
if(pIf1)
|
|
{
|
|
// found it. Make sure it agrees. If so,
|
|
// refcount it and use it
|
|
//
|
|
|
|
if(!(pIf->dwGlobalEnables & FI_ENABLE_OLD)
|
|
&&
|
|
(pIf->eaInAction == pIf1->eaInAction)
|
|
&&
|
|
(pIf->eaOutAction == pIf1->eaOutAction)
|
|
&&
|
|
!(pIf->dwGlobalEnables & FI_ENABLE_UNIQUE)
|
|
&&
|
|
!(pIf1->dwGlobalEnables & FI_ENABLE_UNIQUE)
|
|
)
|
|
{
|
|
|
|
pIf1->lInUse++;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// mismatch. Can't do it
|
|
//
|
|
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pIf1 = 0;
|
|
}
|
|
|
|
if(!pIf1)
|
|
{
|
|
InsertTailList(&g_filters.leIfListHead,&pIf->leIfLink);
|
|
}
|
|
|
|
ReleaseWriteLock(&g_filters.ifListLock,&LockState);
|
|
|
|
if(pIf1)
|
|
{
|
|
//
|
|
// If log is specifed but log alreadye exists, error.
|
|
//
|
|
ExFreePool(pIf);
|
|
if(NT_SUCCESS(Status))
|
|
{
|
|
pPage->pFilter = pIf1;
|
|
if(pIf1->pLog)
|
|
{
|
|
if(pPage->pLog)
|
|
{
|
|
//
|
|
// the interface already has a log. In prinicple
|
|
// this should call DereferenceFilterInterface but
|
|
// this will do and it's faster.
|
|
//
|
|
Status = STATUS_DEVICE_BUSY;
|
|
pIf1->lInUse--;
|
|
}
|
|
}
|
|
else if(pPage->pLog)
|
|
{
|
|
//
|
|
// see comment below about log referencing
|
|
//
|
|
|
|
AddRefToLog(pIf1->pLog = pPage->pLog);
|
|
}
|
|
}
|
|
ExReleaseResourceLite(&FilterListResourceLock);
|
|
KeLeaveCriticalRegion();
|
|
return(Status);
|
|
}
|
|
|
|
NotifyFastPathIf(pIf);
|
|
pPage->pFilter = pIf;
|
|
if(pPage->pLog)
|
|
{
|
|
//
|
|
// Reference the log. Need this since the
|
|
// paged interface can be deleted before the
|
|
// match interface, so each must apply a reference.
|
|
// Actually, only the match needs to do it, but
|
|
// the way the log works, the paged interface already
|
|
// got a reference, so just do it this way.
|
|
// N.B. The single = is intentional
|
|
//
|
|
|
|
AddRefToLog(pIf->pLog = pPage->pLog);
|
|
}
|
|
|
|
ExReleaseResourceLite(&FilterListResourceLock);
|
|
KeLeaveCriticalRegion();
|
|
|
|
return(Status);
|
|
}
|
|
|
|
VOID
|
|
MakeFilterInfo(IN PPAGED_FILTER pPage,
|
|
IN PFILTER_INFOEX pInfo,
|
|
IN DWORD dwFlags)
|
|
{
|
|
PFILTER_INFO2 pFilterInfo = &pInfo->info;
|
|
|
|
if(pInfo->type != PFE_FILTER)
|
|
{
|
|
//
|
|
// a special filter.
|
|
//
|
|
|
|
memset(pPage, 0, sizeof(*pPage));
|
|
pPage->type = pInfo->type;
|
|
pPage->fLateBound = pInfo->dwFlags;
|
|
pPage->dwInUse = 1;
|
|
return;
|
|
}
|
|
|
|
pPage->type = pInfo->type;
|
|
pPage->SRC_ADDR = pFilterInfo->dwaSrcAddr[0];
|
|
pPage->DEST_ADDR = pFilterInfo->dwaDstAddr[0];
|
|
pPage->SRC_MASK = pFilterInfo->dwaSrcMask[0];
|
|
pPage->DEST_MASK = pFilterInfo->dwaDstMask[0];
|
|
pPage->fLateBound = pFilterInfo->fLateBound;
|
|
pPage->wSrcPortHigh = pPage->wDstPortHigh = 0;
|
|
pPage->dwFlags = dwFlags;
|
|
pPage->dwInUse = 1;
|
|
|
|
|
|
if(pPage->SRC_MASK != INADDR_SPECIFIC)
|
|
{
|
|
pPage->dwFlags |= FILTER_FLAGS_SRCWILD;
|
|
}
|
|
if(pPage->DEST_MASK != INADDR_SPECIFIC)
|
|
{
|
|
pPage->dwFlags |= FILTER_FLAGS_DSTWILD;
|
|
}
|
|
|
|
|
|
//
|
|
// Now the network ordering stuff - tricky part
|
|
// LP0 LP1 LP2 LP3 HP0 HP1 HP2 HP3
|
|
// Proto 00 00 00 SrcPort DstPort
|
|
//
|
|
|
|
//
|
|
// For addresses, ANY_ADDR is given by 0.0.0.0 and the MASK must be 0.0.0.0
|
|
// For proto and ports 0 means any and the mask is generated as follows
|
|
// If the proto is O then LP0 for Mask is 0xff else its 0x00
|
|
// If a port is 0, the corresponding XP0XP1 is 0x0000 else its 0xffff
|
|
//
|
|
|
|
//
|
|
// ICMP:
|
|
// LP0 LP1 LP2 LP3 HP0 HP1 HP2 HP3
|
|
// 0x1 00 00 00 Typ Cod 00 00
|
|
// ICMP is different since 0 is a valid code and type, so 0xff is used by the
|
|
// user to signify that ANY code or type is to be matched. However to do this
|
|
// we need to have the field set to zero and the the mask set to 00 (for any).
|
|
// But if the filter is specifically for Type/Code = 0 then the field is zero
|
|
// with the mask as 0xff
|
|
//
|
|
|
|
//
|
|
// The protocol is in the low byte of the dwProtocol, so we take that out and
|
|
// make a dword out of it
|
|
//
|
|
|
|
pPage->uliProtoSrcDstPort.LowPart =
|
|
MAKELONG(MAKEWORD(LOBYTE(LOWORD(pFilterInfo->dwProtocol)),0x00),0x0000);
|
|
|
|
pPage->uliProtoSrcDstMask.LowPart = MAKELONG(MAKEWORD(0xff,0x00),0x0000);
|
|
|
|
switch(pFilterInfo->dwProtocol)
|
|
{
|
|
case FILTER_PROTO_ANY:
|
|
{
|
|
pPage->uliProtoSrcDstPort.HighPart = 0x00000000;
|
|
pPage->uliProtoSrcDstMask.LowPart = 0x00000000;
|
|
pPage->uliProtoSrcDstMask.HighPart = 0x00000000;
|
|
pPage->dwFlags |= FILTER_FLAGS_SRCWILD | FILTER_FLAGS_DSTWILD;
|
|
|
|
break;
|
|
}
|
|
case FILTER_PROTO_ICMP:
|
|
{
|
|
WORD wTypeCode = 0x0000;
|
|
WORD wTypeCodeMask = 0x0000;
|
|
|
|
|
|
//
|
|
// For ICMP, the "ports" occupy the same place as the
|
|
// source port for TCP/UDP. So a wild card in here
|
|
// can never produce a FILTER_FLAGS_DSTWILD but we assume
|
|
// it does. This will put all wild ICMP filters into
|
|
// the default bucket. This seems OK since the performance
|
|
// for matching these is not critical.
|
|
//
|
|
if((BYTE)(pFilterInfo->wSrcPort) != FILTER_ICMP_TYPE_ANY)
|
|
{
|
|
wTypeCode |= MAKEWORD((BYTE)(pFilterInfo->wSrcPort),0x00);
|
|
wTypeCodeMask |= MAKEWORD(0xff,0x00);
|
|
}
|
|
else
|
|
{
|
|
pPage->dwFlags |= FILTER_FLAGS_SRCWILD | FILTER_FLAGS_DSTWILD;
|
|
}
|
|
|
|
if((BYTE)(pFilterInfo->wDstPort) != FILTER_ICMP_CODE_ANY)
|
|
{
|
|
wTypeCode |= MAKEWORD(0x00,(BYTE)(pFilterInfo->wDstPort));
|
|
wTypeCodeMask |= MAKEWORD(0x00,0xff);
|
|
}
|
|
else
|
|
{
|
|
pPage->dwFlags |= FILTER_FLAGS_SRCWILD | FILTER_FLAGS_DSTWILD;
|
|
}
|
|
|
|
pPage->uliProtoSrcDstPort.HighPart =
|
|
MAKELONG(wTypeCode,0x0000);
|
|
pPage->uliProtoSrcDstMask.HighPart =
|
|
MAKELONG(wTypeCodeMask,0x0000);
|
|
|
|
break;
|
|
}
|
|
case FILTER_PROTO_TCP:
|
|
|
|
//
|
|
// if no connections allowed, set the ESTAB_MASK
|
|
// value in the comparison mask
|
|
//
|
|
if(pInfo->dwFlags & FLAGS_INFOEX_NOSYN)
|
|
{
|
|
pPage->uliProtoSrcDstMask.LowPart |=
|
|
MAKELONG(MAKEWORD(0,ESTAB_MASK),0x0000);
|
|
pPage->uliProtoSrcDstPort.LowPart |=
|
|
MAKELONG(MAKEWORD(0,ESTAB_MASK),0x0000);
|
|
}
|
|
|
|
//
|
|
// fall through
|
|
//
|
|
|
|
case FILTER_PROTO_UDP:
|
|
{
|
|
DWORD dwSrcDstPort = 0x00000000;
|
|
DWORD dwSrcDstMask = 0x00000000;
|
|
|
|
if(pFilterInfo->wSrcPort != FILTER_TCPUDP_PORT_ANY)
|
|
{
|
|
dwSrcDstPort |= MAKELONG(pFilterInfo->wSrcPort,0x0000);
|
|
if(pFilterInfo->wSrcPortHigh)
|
|
{
|
|
pPage->wSrcPortHigh = pFilterInfo->wSrcPortHigh;
|
|
pPage->dwFlags |=
|
|
(FILTER_FLAGS_PORTWILD | FILTER_FLAGS_SRCWILD);
|
|
}
|
|
else
|
|
{
|
|
dwSrcDstMask |= MAKELONG(0xffff,0x0000);
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
pPage->dwFlags |= FILTER_FLAGS_SRCWILD;
|
|
}
|
|
|
|
|
|
if(pFilterInfo->wDstPort != FILTER_TCPUDP_PORT_ANY)
|
|
{
|
|
dwSrcDstPort |= MAKELONG(0x0000,pFilterInfo->wDstPort);
|
|
if(pFilterInfo->wDstPortHigh)
|
|
{
|
|
pPage->wDstPortHigh = pFilterInfo->wDstPortHigh;
|
|
pPage->dwFlags |=
|
|
(FILTER_FLAGS_PORTWILD | FILTER_FLAGS_DSTWILD);
|
|
}
|
|
else
|
|
{
|
|
dwSrcDstMask |= MAKELONG(0x0000,0xffff);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pPage->dwFlags |= FILTER_FLAGS_DSTWILD;
|
|
}
|
|
|
|
pPage->uliProtoSrcDstPort.HighPart = dwSrcDstPort;
|
|
pPage->uliProtoSrcDstMask.HighPart = dwSrcDstMask;
|
|
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
//
|
|
// All other protocols have no use for the port field
|
|
//
|
|
pPage->uliProtoSrcDstPort.HighPart = 0x00000000;
|
|
pPage->uliProtoSrcDstMask.HighPart = 0x00000000;
|
|
}
|
|
}
|
|
|
|
//
|
|
// compute the hash index
|
|
//
|
|
|
|
pPage->dwHashIndex = (
|
|
pPage->SRC_ADDR +
|
|
pPage->DEST_ADDR +
|
|
pPage->DEST_ADDR +
|
|
PROTOCOLPART(pPage->uliProtoSrcDstPort.LowPart) +
|
|
pPage->uliProtoSrcDstPort.HighPart) % g_dwHashLists;
|
|
}
|
|
|
|
PPAGED_FILTER
|
|
MakePagedFilter(
|
|
IN PPFFCB Fcb,
|
|
IN PFILTER_INFOEX pInfo,
|
|
IN DWORD dwEpoch,
|
|
IN DWORD dwFlags
|
|
)
|
|
/*++
|
|
Routine Description
|
|
|
|
|
|
Arguments
|
|
|
|
|
|
Return Value
|
|
--*/
|
|
{
|
|
PPAGED_FILTER pPage;
|
|
PFILTER_INFO2 pFilterInfo = &pInfo->info;
|
|
|
|
PAGED_CODE();
|
|
|
|
//
|
|
// Allocate memory for the filters
|
|
//
|
|
|
|
|
|
pPage = (PPAGED_FILTER)ExAllocateFromPagedLookasideList(&paged_slist);
|
|
|
|
if(!pPage)
|
|
{
|
|
ERROR(("IPFLTDRV: Couldnt allocate memory for paged filter set\n"));
|
|
return NULL;
|
|
}
|
|
|
|
pPage->pFilters = NULL;
|
|
|
|
MakeFilterInfo(pPage, pInfo, dwFlags);
|
|
|
|
pPage->dwEpoch = dwEpoch;
|
|
|
|
return pPage;
|
|
}
|
|
|
|
NTSTATUS
|
|
AllocateAndAddFilterToMatchInterface(
|
|
PPFFCB Fcb,
|
|
PFILTER_INFOEX pInfo,
|
|
BOOL fInFilter,
|
|
PPAGED_FILTER_INTERFACE pPage,
|
|
PBOOL pbAdded,
|
|
PPAGED_FILTER * ppFilter)
|
|
/*++
|
|
Routine Description:
|
|
Check if this filter is already on the handle. If not
|
|
allocate a handle fitler and add it to the match
|
|
interface. Note the handle filter is not added to
|
|
the handle. This is so the caller can easily back out
|
|
if something fails.
|
|
Returns: STATUS_SUCCESS if all is well. ppFilter is either NULL
|
|
or contains the new filter.
|
|
--*/
|
|
{
|
|
PPAGED_FILTER pPageFilter, pPage1;
|
|
PFILTER pMatch, pMatch1;
|
|
DWORD dwFlags = (fInFilter ? FILTER_FLAGS_INFILTER : 0);
|
|
DWORD dwAdd;
|
|
|
|
PAGED_CODE();
|
|
|
|
//
|
|
// Make a paged filter so we can figure out whether
|
|
// it exists yet.
|
|
//
|
|
|
|
pPageFilter = MakePagedFilter(
|
|
Fcb,
|
|
pInfo,
|
|
pPage->dwUpdateEpoch,
|
|
dwFlags);
|
|
if(!pPageFilter)
|
|
{
|
|
return STATUS_NO_MEMORY;
|
|
}
|
|
|
|
if(pPage1 = IsOnPagedInterface(pPageFilter, pPage))
|
|
{
|
|
{
|
|
//
|
|
// it already exists. So return the existing one
|
|
// and also the handle
|
|
//
|
|
ExFreeToPagedLookasideList(&paged_slist,
|
|
(PVOID)pPageFilter);
|
|
*ppFilter = pPage1;
|
|
pInfo->pvFilterHandle = (PVOID)pPage1;
|
|
return(STATUS_OBJECT_NAME_COLLISION);
|
|
}
|
|
}
|
|
|
|
//
|
|
// See if we should check out the address.
|
|
//
|
|
|
|
|
|
if(!(pInfo->dwFlags & FLAGS_INFOEX_ALLOWANYREMOTEADDRESS))
|
|
{
|
|
if(pPageFilter->dwFlags & FILTER_FLAGS_INFILTER)
|
|
{
|
|
if(pPageFilter->SRC_MASK != INADDR_SPECIFIC)
|
|
{
|
|
dwAdd = 0;
|
|
}
|
|
else
|
|
{
|
|
dwAdd = pPageFilter->SRC_ADDR;
|
|
}
|
|
}
|
|
else if(pPageFilter->DEST_MASK != INADDR_SPECIFIC)
|
|
{
|
|
dwAdd = 0;
|
|
}
|
|
else
|
|
{
|
|
dwAdd = pPageFilter->DEST_ADDR;
|
|
}
|
|
|
|
//
|
|
// see if address checking should be done. It is done if an
|
|
// address is specified and the filter does not indicate the
|
|
// address is late bound. If it is late bound, just allow it
|
|
// since it may change
|
|
//
|
|
if(dwAdd)
|
|
{
|
|
NTSTATUS Status;
|
|
|
|
if(!BMAddress(dwAdd))
|
|
{
|
|
Status = CheckFilterAddress(dwAdd, pPage->pFilter);
|
|
if(!NT_SUCCESS(Status))
|
|
{
|
|
|
|
ExFreeToPagedLookasideList(&paged_slist,
|
|
(PVOID)pPageFilter);
|
|
return(Status);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
TRACE(CONFIG,("IPFLTDRV: Allow any address is filter\n"));
|
|
}
|
|
|
|
if(!(pInfo->dwFlags & FLAGS_INFOEX_ALLOWANYLOCALADDRESS))
|
|
{
|
|
if(pPageFilter->dwFlags & FILTER_FLAGS_INFILTER)
|
|
{
|
|
if(pPageFilter->DEST_MASK != INADDR_SPECIFIC)
|
|
{
|
|
dwAdd = 0;
|
|
}
|
|
else
|
|
{
|
|
dwAdd = pPageFilter->DEST_ADDR;
|
|
}
|
|
}
|
|
else if(pPageFilter->SRC_MASK != INADDR_SPECIFIC)
|
|
{
|
|
dwAdd = 0;
|
|
}
|
|
else
|
|
{
|
|
dwAdd = pPageFilter->SRC_ADDR;
|
|
}
|
|
|
|
if(dwAdd)
|
|
{
|
|
if(pPage->pFilter->dwIpIndex != UNKNOWN_IP_INDEX)
|
|
{
|
|
if(!BMAddress(dwAdd) &&
|
|
(GetIpStackIndex(dwAdd, FALSE) != pPage->pFilter->dwIpIndex))
|
|
{
|
|
ExFreeToPagedLookasideList(&paged_slist,
|
|
(PVOID)pPageFilter);
|
|
return(STATUS_INVALID_ADDRESS);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// Not on the handle. Assume we need to add a new filter
|
|
// to the match interface. Allocate memory for this filter if
|
|
// necessary
|
|
//
|
|
|
|
pMatch = (PFILTER)ExAllocateFromNPagedLookasideList(
|
|
&filter_slist);
|
|
if(!pMatch)
|
|
{
|
|
ExFreePool(pPageFilter);
|
|
return(STATUS_NO_MEMORY);
|
|
}
|
|
|
|
pInfo->pvFilterHandle = (PVOID)pPageFilter;
|
|
|
|
//
|
|
// We will keep this filter so add it to the hash list
|
|
//
|
|
|
|
InsertTailList(&(pPage->HashList[pPageFilter->dwHashIndex]),
|
|
&pPageFilter->leHash);
|
|
|
|
//
|
|
// Now add it to the handle hash list
|
|
//
|
|
|
|
InsertTailList(&(pPage->HandleHash((UINT_PTR)pPageFilter & HANDLE_HASH_SIZE)),
|
|
&pPageFilter->leHandleHash);
|
|
|
|
|
|
//
|
|
// fix up the match interface
|
|
//
|
|
|
|
pMatch->uliSrcDstAddr = pPageFilter->uliSrcDstAddr;
|
|
pMatch->uliSrcDstMask = pPageFilter->uliSrcDstMask;
|
|
pMatch->uliProtoSrcDstPort = pPageFilter->uliProtoSrcDstPort;
|
|
pMatch->uliProtoSrcDstMask = pPageFilter->uliProtoSrcDstMask;
|
|
pMatch->fLateBound = pPageFilter->fLateBound;
|
|
pMatch->wSrcPortHigh = pPageFilter->wSrcPortHigh;
|
|
pMatch->wDstPortHigh = pPageFilter->wDstPortHigh;
|
|
|
|
pMatch->Count.lCount = 0;
|
|
pMatch->dwFlags = pPageFilter->dwFlags;
|
|
pMatch->dwFlags |= (pInfo->dwFlags & FLAGS_INFOEX_ALLFLAGS);
|
|
pMatch->dwFilterRule = pInfo->dwFilterRule;
|
|
pMatch->Count.lInUse = 0;
|
|
|
|
|
|
AddFilterToInterface(
|
|
pMatch,
|
|
pPage->pFilter,
|
|
fInFilter,
|
|
&pMatch1);
|
|
|
|
if(pMatch1)
|
|
{
|
|
//
|
|
// the filter already exists. Don't need the one we built
|
|
//
|
|
|
|
ExFreePool(pMatch);
|
|
pMatch = pMatch1;
|
|
*pbAdded = FALSE;
|
|
}
|
|
else
|
|
{
|
|
*pbAdded = TRUE;
|
|
}
|
|
pPageFilter->pMatchFilter = pMatch;
|
|
*ppFilter = pPageFilter;
|
|
return(STATUS_SUCCESS);
|
|
}
|
|
|
|
VOID
|
|
AddFilterToInterface(
|
|
PFILTER pFilter,
|
|
PFILTER_INTERFACE pIf,
|
|
BOOL fInFilter,
|
|
PFILTER * ppFilter)
|
|
/*++
|
|
Routine Description:
|
|
Add pFilter to the interface. If it already exists,
|
|
just refcount it and return the address of the
|
|
existing filter.
|
|
--*/
|
|
{
|
|
PFILTER pTemp;
|
|
LOCK_STATE LockState;
|
|
PLIST_ENTRY List, pList;
|
|
PDWORD pdwCount;
|
|
DWORD dwIndex;
|
|
DWORD dwType = pFilter->dwFlags & FILTER_FLAGS_INFILTER;
|
|
BOOL fWild;
|
|
|
|
|
|
*ppFilter = NULL;
|
|
|
|
dwIndex = ComputeMatchHashIndex(pFilter, &fWild);
|
|
|
|
if(fInFilter)
|
|
{
|
|
pList = &pIf->pleInFilterSet;
|
|
pdwCount = &pIf->dwNumInFilters;
|
|
}
|
|
else
|
|
{
|
|
pList = &pIf->pleOutFilterSet;
|
|
pdwCount = &pIf->dwNumOutFilters;
|
|
}
|
|
|
|
//
|
|
// lock up the filters
|
|
//
|
|
AcquireWriteLock(&g_filters.ifListLock,&LockState);
|
|
|
|
for(List = pIf->HashList[dwIndex].Flink;
|
|
List != &pIf->HashList[dwIndex];
|
|
List = List->Flink)
|
|
{
|
|
pTemp = CONTAINING_RECORD(List, FILTER, pleHashList);
|
|
|
|
if((dwType == (pTemp->dwFlags & FILTER_FLAGS_INFILTER))
|
|
&&
|
|
(pTemp->uliSrcDstAddr.QuadPart == pFilter->uliSrcDstAddr.QuadPart)
|
|
&&
|
|
(pTemp->uliSrcDstMask.QuadPart == pFilter->uliSrcDstMask.QuadPart)
|
|
&&
|
|
(pTemp->uliProtoSrcDstPort.QuadPart == pFilter->uliProtoSrcDstPort.QuadPart)
|
|
&&
|
|
(pTemp->uliProtoSrcDstMask.QuadPart == pFilter->uliProtoSrcDstMask.QuadPart)
|
|
&&
|
|
(pTemp->wSrcPortHigh == pFilter->wSrcPortHigh)
|
|
&&
|
|
(pTemp->wDstPortHigh == pFilter->wDstPortHigh)
|
|
)
|
|
{
|
|
pFilter = *ppFilter = pTemp;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(!*ppFilter)
|
|
{
|
|
|
|
//
|
|
// a new filter. Add it to the interface. First flush incorrect cache
|
|
// entries.
|
|
//
|
|
|
|
if(ANYWILDFILTER(pFilter))
|
|
{
|
|
//
|
|
// wild card filters can cause cache entries almost anywhere
|
|
// in the table. Very nasty. So take the draconian step of
|
|
// deleting the entire cache.
|
|
//
|
|
ClearCache();
|
|
}
|
|
else
|
|
{
|
|
ClearCacheEntry(pFilter, pIf);
|
|
}
|
|
pFilter->dwEpoch = pIf->dwUpdateEpoch;
|
|
InsertTailList(pList, &pFilter->pleFilters);
|
|
|
|
//
|
|
// and add it to the proper fragment list
|
|
//
|
|
|
|
#if DOFRAGCHECKING
|
|
InsertTailList(
|
|
&pIf->FragLists[GetFragIndex(PROTOCOLPART(pFilter->PROTO))],
|
|
&pFilter->leFragList);
|
|
#endif
|
|
|
|
*pdwCount+= 1;
|
|
#if WILDHASH
|
|
if(fWild)
|
|
{
|
|
//
|
|
// if a wild filter of some sort, insert at the tail
|
|
// keeping specific filters ahead of wild filters
|
|
//
|
|
InsertTailList((&pIf->HashList[dwIndex]), &pFilter->pleHashList);
|
|
pIf->dwWilds++;
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
//
|
|
// insert at the head on the assumption this filter will
|
|
// be used soon and existing filters already have been
|
|
// used to produce a valid packet cache entry
|
|
//
|
|
InsertHeadList((&pIf->HashList[dwIndex]), &pFilter->pleHashList);
|
|
}
|
|
|
|
}
|
|
|
|
pFilter->Count.lInUse++;
|
|
|
|
ReleaseWriteLock(&g_filters.ifListLock,&LockState);
|
|
}
|
|
|
|
BOOL
|
|
DereferenceFilter(PFILTER pFilt, PFILTER_INTERFACE pIf)
|
|
/*++
|
|
Routine Description:
|
|
|
|
Dereference a filter and if it has no more referents, free it.
|
|
Returns TRUE if the filter was freed, FALSE otherwise.
|
|
--*/
|
|
{
|
|
LOCK_STATE LockState;
|
|
BOOL fFreed = FALSE;
|
|
|
|
//
|
|
// lock up the filters
|
|
//
|
|
AcquireWriteLock(&g_filters.ifListLock,&LockState);
|
|
|
|
//
|
|
// Decrement reference count. If new count is 0, remove
|
|
// the entry but defer freeing the memory until the
|
|
// spin lock is released
|
|
//
|
|
if(--pFilt->Count.lInUse == 0)
|
|
{
|
|
|
|
TRACE(FLDES, ("IPFLTDRV: Deleting a filter: "));
|
|
TRACE_FILTER_DESCRIPTION(pFilt);
|
|
|
|
RemoveEntryList(&pFilt->pleFilters);
|
|
RemoveEntryList(&pFilt->pleHashList);
|
|
#if DOFRAGCHECKING
|
|
RemoveEntryList(&pFilt->leFragList);
|
|
#endif
|
|
|
|
if(pFilt->dwFlags & FILTER_FLAGS_INFILTER)
|
|
{
|
|
pIf->dwNumInFilters--;
|
|
|
|
}
|
|
else
|
|
{
|
|
pIf->dwNumOutFilters--;
|
|
pIf->lEpoch++;
|
|
}
|
|
|
|
if(ANYWILDFILTER(pFilt))
|
|
{
|
|
//
|
|
// wild card filters can cause cache entries almost anywhere
|
|
// in the table. Very nasty.
|
|
//
|
|
#if WILDHASH
|
|
|
|
if(!WildFilter(pFilt))
|
|
{
|
|
pIf->dwWilds--;
|
|
}
|
|
#endif
|
|
ClearAnyCacheEntry(pFilt, pIf);
|
|
}
|
|
else
|
|
{
|
|
ClearCacheEntry(pFilt, pIf);
|
|
}
|
|
fFreed = TRUE;
|
|
}
|
|
ReleaseWriteLock(&g_filters.ifListLock,&LockState);
|
|
if(fFreed)
|
|
{
|
|
ExFreeToNPagedLookasideList(
|
|
&filter_slist,
|
|
(PVOID)pFilt);
|
|
}
|
|
return(fFreed);
|
|
}
|
|
|
|
PPAGED_FILTER
|
|
IsOnPagedInterface(PPAGED_FILTER pPageFilter,
|
|
PPAGED_FILTER_INTERFACE pPage)
|
|
{
|
|
PPAGED_FILTER pPage1;
|
|
PLIST_ENTRY List = &pPage->HashList[pPageFilter->dwHashIndex];
|
|
PLIST_ENTRY pEntry;
|
|
DWORD dwFlags = pPageFilter->dwFlags & FILTER_FLAGS_INFILTER;
|
|
|
|
PAGED_CODE();
|
|
|
|
for(pEntry = List->Flink;
|
|
pEntry != List;
|
|
pEntry = pEntry->Flink)
|
|
{
|
|
pPage1 = CONTAINING_RECORD(pEntry, PAGED_FILTER, leHash);
|
|
|
|
if((dwFlags == (pPage1->dwFlags & FILTER_FLAGS_INFILTER))
|
|
&&
|
|
(pPage1->uliSrcDstAddr.QuadPart == pPageFilter->uliSrcDstAddr.QuadPart)
|
|
&&
|
|
(pPage1->uliSrcDstMask.QuadPart == pPageFilter->uliSrcDstMask.QuadPart)
|
|
&&
|
|
(pPage1->uliProtoSrcDstPort.QuadPart == pPageFilter->uliProtoSrcDstPort.QuadPart)
|
|
&&
|
|
(pPage1->uliProtoSrcDstMask.QuadPart == pPageFilter->uliProtoSrcDstMask.QuadPart)
|
|
&&
|
|
(pPage1->wSrcPortHigh == pPageFilter->wSrcPortHigh)
|
|
&&
|
|
(pPage1->wDstPortHigh == pPageFilter->wDstPortHigh)
|
|
)
|
|
{
|
|
return(pPage1);
|
|
}
|
|
}
|
|
return(NULL);
|
|
}
|
|
|
|
BOOL
|
|
IsOnSpecialFilterList(PPAGED_FILTER pPageFilter,
|
|
PLIST_ENTRY List,
|
|
PPAGED_FILTER * pPageHit)
|
|
{
|
|
PPAGED_FILTER pPage1;
|
|
PLIST_ENTRY pList;
|
|
|
|
PAGED_CODE();
|
|
|
|
|
|
for(pList = List->Flink;
|
|
pList != List;
|
|
pList = pList->Flink)
|
|
{
|
|
pPage1 = CONTAINING_RECORD(pList, PAGED_FILTER, leSpecialList);
|
|
|
|
//
|
|
// See if this filter matches the new one. If so,
|
|
// we've already got it, so just free the new filter
|
|
// and return success
|
|
|
|
if(pPageFilter->type == pPage1->type)
|
|
{
|
|
*pPageHit = pPage1;
|
|
return(TRUE);
|
|
}
|
|
}
|
|
return(FALSE);
|
|
}
|
|
|
|
VOID
|
|
FreePagedFilterList(PPFFCB Fcb,
|
|
PPAGED_FILTER pList,
|
|
PPAGED_FILTER_INTERFACE pPage,
|
|
PDWORD pdwRemoved)
|
|
/*++
|
|
Routine Description:
|
|
Release all of the filters in the list. Each such filter
|
|
has to cause a derefernce of the underlying match
|
|
filter. If the paged filter is a global filter, handle
|
|
it specially
|
|
--*/
|
|
{
|
|
PPAGED_FILTER pFilt;
|
|
|
|
while(pList)
|
|
{
|
|
if(pList->type == PFE_FILTER)
|
|
{
|
|
|
|
if(DereferenceFilter(pList->pMatchFilter, pPage->pFilter))
|
|
{
|
|
//
|
|
// removed a filter. If this added a restriction,
|
|
// note it. A restriction is added only if the
|
|
// default action is DROP
|
|
//
|
|
if(pList->dwFlags & FILTER_FLAGS_INFILTER)
|
|
{
|
|
if(pPage->eaInAction == DROP)
|
|
{
|
|
*pdwRemoved += 1;
|
|
}
|
|
} else if(pPage->eaOutAction == DROP)
|
|
{
|
|
*pdwRemoved += 1;
|
|
}
|
|
}
|
|
RemoveEntryList(&pList->leHash);
|
|
RemoveEntryList(&pList->leHandleHash);
|
|
|
|
}
|
|
else
|
|
{
|
|
RemoveGlobalFilterFromInterface(pPage->pFilter,
|
|
pList->type);
|
|
RemoveEntryList(&pList->leSpecialList);
|
|
}
|
|
pFilt = pList->pFilters;
|
|
ExFreeToPagedLookasideList(&paged_slist,
|
|
(PVOID)pList);
|
|
pList = pFilt;
|
|
}
|
|
}
|
|
|
|
NTSTATUS
|
|
FindAndRemovePagedFilter(
|
|
PPFFCB Fcb,
|
|
PFILTER_INFOEX pInfo,
|
|
BOOL fInFilter,
|
|
PDWORD pdwRemoved,
|
|
PPAGED_FILTER_INTERFACE pPage)
|
|
/*++
|
|
Routine Description:
|
|
Find if the described filter in on the paged interface,
|
|
and if so, remove it, and derefernce the underlying match
|
|
filter.
|
|
--*/
|
|
{
|
|
PAGED_FILTER Page;
|
|
PPAGED_FILTER pPageHit;
|
|
DWORD dwFlags = fInFilter ? FILTER_FLAGS_INFILTER : 0;
|
|
|
|
MakeFilterInfo(&Page, pInfo, dwFlags);
|
|
|
|
//
|
|
// search the interface to see if we have this already.
|
|
//
|
|
|
|
if(Page.type != PFE_FILTER)
|
|
{
|
|
//
|
|
// it's a special filte. Search the list
|
|
//
|
|
if(!IsOnSpecialFilterList(&Page,
|
|
&pPage->leSpecialFilterList,
|
|
&pPageHit)
|
|
)
|
|
{
|
|
return(STATUS_INVALID_PARAMETER);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// a regular filter
|
|
//
|
|
pPageHit = IsOnPagedInterface(&Page, pPage);
|
|
if(!pPageHit)
|
|
{
|
|
return(STATUS_INVALID_PARAMETER);
|
|
}
|
|
}
|
|
|
|
if(!--pPageHit->dwInUse)
|
|
{
|
|
pPageHit->pFilters = NULL;
|
|
FreePagedFilterList(Fcb, pPageHit, pPage, pdwRemoved);
|
|
}
|
|
|
|
return(STATUS_SUCCESS);
|
|
}
|
|
|
|
PPAGED_FILTER
|
|
FindFilterByHandle(
|
|
IN PPFFCB Fcb,
|
|
IN PPAGED_FILTER_INTERFACE pPage,
|
|
IN PVOID pvHandle)
|
|
/*++
|
|
Routine Description:
|
|
Find a filter given its filter handle
|
|
--*/
|
|
{
|
|
PPAGED_FILTER pPaged = 0;
|
|
DWORD dwHash = (DWORD)(((UINT_PTR)pvHandle % HANDLE_HASH_SIZE));
|
|
PLIST_ENTRY pList;
|
|
|
|
for(pList = pPage->HandleHash(dwHash).Flink;
|
|
pList != &pPage->HandleHash(dwHash);
|
|
pList = pList->Flink)
|
|
{
|
|
PPAGED_FILTER ppf = CONTAINING_RECORD(pList,
|
|
PAGED_FILTER,
|
|
leHandleHash);
|
|
|
|
if(ppf == (PPAGED_FILTER)pvHandle)
|
|
{
|
|
pPaged = ppf;
|
|
break;
|
|
}
|
|
}
|
|
return(pPaged);
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
DeleteByHandle(
|
|
IN PPFFCB Fcb,
|
|
IN PPAGED_FILTER_INTERFACE pPage,
|
|
IN PVOID * ppHandles,
|
|
IN DWORD dwLength)
|
|
/*++
|
|
Routine Description:
|
|
Delete filters using the assigned filter handles
|
|
Note the FCB is locked, so it won't change
|
|
--*/
|
|
{
|
|
PFILTER_INTERFACE pIf = pPage->pFilter;
|
|
DWORD dwFilters;
|
|
PPAGED_FILTER pPFilter;
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
DWORD dwFiltersRemoved = 0;
|
|
|
|
PAGED_CODE();
|
|
|
|
if(pPage->pFilter->dwGlobalEnables & FI_ENABLE_OLD)
|
|
{
|
|
return(STATUS_INVALID_DEVICE_REQUEST);
|
|
}
|
|
|
|
//
|
|
// compute number of filters
|
|
//
|
|
|
|
dwFilters = dwLength / sizeof(PVOID);
|
|
|
|
|
|
for(; dwFilters; dwFilters--, ppHandles++)
|
|
{
|
|
//
|
|
// for each handle, locate the filter
|
|
//
|
|
|
|
pPFilter = FindFilterByHandle(Fcb, pPage, *ppHandles);
|
|
if(!pPFilter)
|
|
{
|
|
TRACE(CONFIG,("IPFLTDRV: Could not translate handle to filter\n"));
|
|
}
|
|
else
|
|
{
|
|
if(!--pPFilter->dwInUse)
|
|
{
|
|
pPFilter->pFilters = NULL;
|
|
FreePagedFilterList(Fcb, pPFilter, pPage, &dwFiltersRemoved);
|
|
}
|
|
}
|
|
}
|
|
if(dwFiltersRemoved)
|
|
{
|
|
NotifyFastPath(pIf, pIf->dwIpIndex, NOT_RESTRICTION);
|
|
}
|
|
return(STATUS_SUCCESS);
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
UnSetFiltersEx(
|
|
IN PPFFCB Fcb,
|
|
IN PPAGED_FILTER_INTERFACE pPage,
|
|
IN DWORD dwLength,
|
|
IN PFILTER_DRIVER_SET_FILTERS pInfo)
|
|
/*++
|
|
Routine Description:
|
|
Unset a list of filters from an interface. This is the
|
|
inverse operation of SetFilterEx
|
|
|
|
--*/
|
|
{
|
|
PRTR_TOC_ENTRY pInToc,pOutToc;
|
|
PFILTER_INTERFACE pIf = pPage->pFilter;
|
|
PFILTER_DESCRIPTOR2 pFilterDescIn, pFilterDescOut;
|
|
PPAGED_FILTER pIn = NULL, pOut = NULL;
|
|
DWORD i;
|
|
PPAGED_FILTER pPFilter;
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
PBYTE pbEnd = (PBYTE)pInfo + dwLength;
|
|
DWORD dwFiltersRemoved = 0;
|
|
|
|
PAGED_CODE();
|
|
|
|
if(pPage->pFilter->dwGlobalEnables & FI_ENABLE_OLD)
|
|
{
|
|
return(STATUS_INVALID_DEVICE_REQUEST);
|
|
}
|
|
|
|
pInToc = GetPointerToTocEntry(IP_FILTER_DRIVER_IN_FILTER_INFO,
|
|
&pInfo->ribhInfoBlock);
|
|
|
|
pOutToc = GetPointerToTocEntry(IP_FILTER_DRIVER_OUT_FILTER_INFO,
|
|
&pInfo->ribhInfoBlock);
|
|
|
|
if(pInToc && pInToc->InfoSize)
|
|
{
|
|
//
|
|
// filters are defined.
|
|
//
|
|
|
|
pFilterDescIn = GetInfoFromTocEntry(&pInfo->ribhInfoBlock,
|
|
pInToc);
|
|
if(pFilterDescIn->dwVersion != 2)
|
|
{
|
|
TRACE(CONFIG,("IPFLTDRV: Invalid version for FiltersEx\n"));
|
|
return(STATUS_INVALID_PARAMETER);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pFilterDescIn = NULL;
|
|
}
|
|
|
|
if(pOutToc && pOutToc->InfoSize)
|
|
{
|
|
//
|
|
// filters are defined.
|
|
//
|
|
|
|
pFilterDescOut = GetInfoFromTocEntry(&pInfo->ribhInfoBlock,
|
|
pOutToc);
|
|
if(pFilterDescOut->dwVersion != 2)
|
|
{
|
|
TRACE(CONFIG,("IPFLTDRV: Invalid version for FiltersEx\n"));
|
|
return(STATUS_INVALID_PARAMETER);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pFilterDescOut = NULL;
|
|
}
|
|
|
|
if((pFilterDescIn && !CheckDescriptorSize(pFilterDescIn, pbEnd))
|
|
||
|
|
(pFilterDescOut && !CheckDescriptorSize(pFilterDescOut, pbEnd)) )
|
|
{
|
|
return(STATUS_BUFFER_TOO_SMALL);
|
|
}
|
|
//
|
|
// For each set of filters, remove the filters from the
|
|
// paged interface and thence from the match interface
|
|
|
|
if(pFilterDescIn)
|
|
{
|
|
|
|
//
|
|
// Removing in filters. For each filter, process as
|
|
// needed. Input filters include the global checks
|
|
/// such as spoofing.
|
|
//
|
|
|
|
RemoveFilterWorker(Fcb,
|
|
&pFilterDescIn->fiFilter[0],
|
|
pFilterDescIn->dwNumFilters,
|
|
pPage,
|
|
&dwFiltersRemoved,
|
|
TRUE);
|
|
}
|
|
|
|
//
|
|
// now the output filters. This is a bit simpler since there
|
|
// are no global settings.
|
|
//
|
|
|
|
if(pFilterDescOut)
|
|
{
|
|
|
|
//
|
|
// Adding in filters. For each filter, process as
|
|
// needed. Input filters include the global checks
|
|
/// such as spoofing.
|
|
//
|
|
|
|
RemoveFilterWorker(Fcb,
|
|
&pFilterDescOut->fiFilter[0],
|
|
pFilterDescOut->dwNumFilters,
|
|
pPage,
|
|
&dwFiltersRemoved,
|
|
FALSE);
|
|
}
|
|
if(dwFiltersRemoved)
|
|
{
|
|
NotifyFastPath(pIf, pIf->dwIpIndex, NOT_RESTRICTION);
|
|
}
|
|
return(STATUS_SUCCESS);
|
|
}
|
|
|
|
|
|
VOID
|
|
RemoveFilterWorker(
|
|
PPFFCB Fcb,
|
|
PFILTER_INFOEX pFilt,
|
|
DWORD dwCount,
|
|
PPAGED_FILTER_INTERFACE pPage,
|
|
PDWORD pdwRemoved,
|
|
BOOL fInFilter)
|
|
{
|
|
NTSTATUS Status;
|
|
|
|
//
|
|
// If a regular filter, add it. If a special, global
|
|
// filter, handle it specially.
|
|
//
|
|
|
|
while(dwCount)
|
|
{
|
|
if(fInFilter || (pFilt->type == PFE_FILTER))
|
|
{
|
|
Status = FindAndRemovePagedFilter(
|
|
Fcb,
|
|
pFilt,
|
|
fInFilter,
|
|
pdwRemoved,
|
|
pPage);
|
|
if(!NT_SUCCESS(Status))
|
|
{
|
|
ERROR(("IPFLTDRV: Removing filter failed %x\n", Status));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ERROR(("IPFLTDRV: Ignoring global out filter\n"));
|
|
}
|
|
dwCount--;
|
|
pFilt++;
|
|
}
|
|
}
|
|
|
|
NTSTATUS
|
|
SetInterfaceBinding(PINTERFACEBINDING pBind,
|
|
PPAGED_FILTER_INTERFACE pPage)
|
|
{
|
|
|
|
INTERFACEBINDING2 Bind2;
|
|
NTSTATUS status;
|
|
|
|
//
|
|
// Rather than duplicating the code for the new & the old routine
|
|
// call the new routine by transforming old structure to the new
|
|
// structure.
|
|
//
|
|
|
|
Bind2.pvDriverContext = pBind->pvDriverContext;
|
|
Bind2.pfType = pBind->pfType;
|
|
Bind2.dwAdd = pBind->dwAdd;
|
|
Bind2.dwEpoch = pBind->dwEpoch;
|
|
Bind2.dwLinkAdd = 0;
|
|
|
|
status = SetInterfaceBinding2(&Bind2, pPage);
|
|
pBind->dwEpoch = Bind2.dwEpoch;
|
|
|
|
return(status);
|
|
}
|
|
|
|
NTSTATUS
|
|
SetInterfaceBinding2(PINTERFACEBINDING2 pBind,
|
|
PPAGED_FILTER_INTERFACE pPage)
|
|
{
|
|
PFILTER_INTERFACE pIf1, pIf = pPage->pFilter;
|
|
NTSTATUS Status;
|
|
LOCK_STATE LockState;
|
|
DWORD dwBind, dwOldBind;
|
|
|
|
if(pPage->pFilter->dwGlobalEnables & FI_ENABLE_OLD)
|
|
{
|
|
return(STATUS_INVALID_DEVICE_REQUEST);
|
|
}
|
|
|
|
KeEnterCriticalRegion();
|
|
ExAcquireResourceExclusiveLite(&FilterListResourceLock, TRUE);
|
|
|
|
//
|
|
// verify binding type
|
|
//
|
|
|
|
switch(pBind->pfType)
|
|
{
|
|
default:
|
|
dwBind = UNKNOWN_IP_INDEX;
|
|
break;
|
|
|
|
case PF_BIND_INTERFACEINDEX:
|
|
(VOID)GetIpStackIndex(0, TRUE); // make sure have this list
|
|
dwBind = pBind->dwAdd;
|
|
break;
|
|
|
|
case PF_BIND_IPV4ADDRESS:
|
|
|
|
dwBind = GetIpStackIndex((IPAddr)pBind->dwAdd, TRUE);
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Make sure it is not bound or if it is that it is
|
|
// bound to this interface
|
|
//
|
|
|
|
if(((pIf->dwIpIndex != UNKNOWN_IP_INDEX) &&
|
|
(pIf->dwIpIndex != dwBind) &&
|
|
(pIf->dwLinkIpAddress != pBind->dwLinkAdd) )
|
|
||
|
|
(dwBind == UNKNOWN_IP_INDEX)
|
|
)
|
|
{
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
}
|
|
else
|
|
{
|
|
BOOL fFound = FALSE;
|
|
PLIST_ENTRY pList;
|
|
|
|
//
|
|
// verify that this is not already in use by some other
|
|
// interface
|
|
//
|
|
dwOldBind = pIf->dwIpIndex;
|
|
|
|
AcquireWriteLock(&g_filters.ifListLock,&LockState);
|
|
|
|
for(pList = g_filters.leIfListHead.Flink;
|
|
pList != &g_filters.leIfListHead;
|
|
pList = pList->Flink)
|
|
{
|
|
pIf1 = CONTAINING_RECORD(pList, FILTER_INTERFACE, leIfLink);
|
|
|
|
if((pIf1->dwIpIndex == dwBind) && (pIf1->dwLinkIpAddress == pBind->dwLinkAdd))
|
|
{
|
|
//
|
|
// found it.
|
|
//
|
|
fFound = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(!fFound)
|
|
{
|
|
pIf->dwIpIndex = dwBind;
|
|
pIf->dwLinkIpAddress = pBind->dwLinkAdd;
|
|
InterlockedIncrement(&g_ulBoundInterfaceCount);
|
|
|
|
TRACE(CONFIG,(
|
|
"IPFLTDRV: Bound Interface Index=%d, Link=%d, TotalCnt=%d\n",
|
|
dwBind,
|
|
pBind->dwLinkAdd,
|
|
g_ulBoundInterfaceCount
|
|
));
|
|
}
|
|
|
|
ReleaseWriteLock(&g_filters.ifListLock,&LockState);
|
|
|
|
if(fFound)
|
|
{
|
|
if(pIf1 == pIf)
|
|
{
|
|
Status = STATUS_SUCCESS;
|
|
}
|
|
else
|
|
{
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
|
|
NotifyFastPathIf(pIf);
|
|
if(!++pIf->dwBindEpoch)
|
|
{
|
|
pIf->dwBindEpoch++;
|
|
}
|
|
Status = STATUS_SUCCESS;
|
|
}
|
|
}
|
|
|
|
pBind->dwEpoch = pIf->dwBindEpoch;
|
|
ExReleaseResourceLite(&FilterListResourceLock);
|
|
KeLeaveCriticalRegion();
|
|
return(Status);
|
|
}
|
|
|
|
NTSTATUS
|
|
ClearInterfaceBinding(PPAGED_FILTER_INTERFACE pPage,
|
|
PINTERFACEBINDING pBind)
|
|
{
|
|
PFILTER_INTERFACE pIf = pPage->pFilter;
|
|
NTSTATUS Status;
|
|
|
|
if(pIf->dwGlobalEnables & FI_ENABLE_OLD)
|
|
{
|
|
return(STATUS_INVALID_DEVICE_REQUEST);
|
|
}
|
|
|
|
KeEnterCriticalRegion();
|
|
ExAcquireResourceExclusiveLite(&FilterListResourceLock, TRUE);
|
|
|
|
//
|
|
// Make sure it is bound
|
|
//
|
|
|
|
if((pIf->dwIpIndex == UNKNOWN_IP_INDEX)
|
|
||
|
|
( pBind->dwEpoch
|
|
&&
|
|
(pIf->dwBindEpoch != pBind->dwEpoch)))
|
|
{
|
|
Status = STATUS_SUCCESS;
|
|
}
|
|
else
|
|
{
|
|
|
|
|
|
LOCK_STATE LockState;
|
|
DWORD dwIndex;
|
|
|
|
AcquireWriteLock(&g_filters.ifListLock,&LockState);
|
|
InterlockedCleanCache(g_filters.pInterfaceCache, pIf->dwIpIndex, pIf->dwLinkIpAddress);
|
|
InterlockedDecrement(&g_ulBoundInterfaceCount);
|
|
|
|
TRACE(CONFIG,(
|
|
"IPFLTDRV: UnBound Interface Index=%d, Link=%d, TotalCnt=%d\n",
|
|
pIf->dwIpIndex,
|
|
pIf->dwLinkIpAddress,
|
|
g_ulBoundInterfaceCount
|
|
));
|
|
|
|
ClearCache();
|
|
ReleaseWriteLock(&g_filters.ifListLock, &LockState);
|
|
|
|
dwIndex = pIf->dwIpIndex;
|
|
pIf->dwIpIndex = UNKNOWN_IP_INDEX;
|
|
NotifyFastPath(pIf, dwIndex, NOT_UNBIND);
|
|
Status = STATUS_SUCCESS;
|
|
|
|
}
|
|
ExReleaseResourceLite(&FilterListResourceLock);
|
|
KeLeaveCriticalRegion();
|
|
return(Status);
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
DeletePagedInterface(PPFFCB Fcb, PPAGED_FILTER_INTERFACE pPage)
|
|
/*++
|
|
Routine Description:
|
|
Delete the filters and this interface
|
|
--*/
|
|
{
|
|
PLIST_ENTRY pList;
|
|
PPAGED_FILTER pf;
|
|
PPAGED_FILTER pfp = NULL;
|
|
DWORD i;
|
|
DWORD dwDummy;
|
|
|
|
|
|
PAGED_CODE();
|
|
|
|
if(pPage->pFilter->dwGlobalEnables & FI_ENABLE_OLD)
|
|
{
|
|
return(STATUS_INVALID_DEVICE_REQUEST);
|
|
}
|
|
|
|
for(pList = pPage->leSpecialFilterList.Flink;
|
|
pList != &pPage->leSpecialFilterList;
|
|
pList = pList->Flink)
|
|
{
|
|
pf = CONTAINING_RECORD(pList, PAGED_FILTER, leSpecialList);
|
|
pf->pFilters = pfp;
|
|
pfp = pf;
|
|
}
|
|
for(i = 0; i < g_dwHashLists; i++)
|
|
{
|
|
for(pList = pPage->HashList[i].Flink;
|
|
pList != &pPage->HashList[i];
|
|
pList = pList->Flink)
|
|
{
|
|
pf = CONTAINING_RECORD(pList, PAGED_FILTER, leHash);
|
|
pf->pFilters = pfp;
|
|
pfp = pf;
|
|
}
|
|
}
|
|
FreePagedFilterList(Fcb, pfp, pPage, &dwDummy);
|
|
DereferenceFilterInterface(pPage->pFilter, pPage->pLog);
|
|
if(pPage->pLog)
|
|
{
|
|
DereferenceLog(pPage->pLog);
|
|
}
|
|
|
|
ExFreePool(pPage);
|
|
return(STATUS_SUCCESS);
|
|
}
|
|
NTSTATUS
|
|
GetFiltersEx(
|
|
IN PFILTER_INTERFACE pIf,
|
|
IN BOOL fClear,
|
|
OUT PFILTER_STATS_EX pInfo
|
|
)
|
|
/*++
|
|
Routine Description
|
|
Gets filters and statistics associated with an interface
|
|
It is called with the Spin Lock held as reader
|
|
|
|
Arguments
|
|
pvIf Pointer to FILTER_INTERFACE structure which was passed as a PVOID
|
|
to router manager as a context for the interface
|
|
pInfo FILTER_IF structure filled in by driver
|
|
|
|
Return Value
|
|
|
|
--*/
|
|
{
|
|
DWORD i,dwNumInFilters,dwNumOutFilters;
|
|
PFILTER pf;
|
|
PLIST_ENTRY List;
|
|
|
|
dwNumInFilters = pIf->dwNumInFilters;
|
|
dwNumOutFilters = pIf->dwNumOutFilters;
|
|
|
|
for(i = 0, List = pIf->pleInFilterSet.Flink;
|
|
List != &pIf->pleInFilterSet;
|
|
i++, List = List->Flink)
|
|
{
|
|
PFILTER_INFOEX pEx = &pInfo->info;
|
|
PFILTER_INFO2 pFilt = &pEx->info;
|
|
|
|
pf = CONTAINING_RECORD(List, FILTER, pleFilters);
|
|
pInfo->dwNumPacketsFiltered = (DWORD)pf->Count.lCount;;
|
|
if(fClear)
|
|
{
|
|
pf->Count.lCount = 0;
|
|
}
|
|
|
|
pEx->dwFilterRule = pf->dwFilterRule;
|
|
pEx->type = PFE_FILTER;
|
|
pEx->dwFlags = pf->dwFlags & FLAGS_INFOEX_ALLFLAGS;
|
|
pFilt->addrType = IPV4;
|
|
pFilt->dwaSrcAddr[0] = pf->SRC_ADDR;
|
|
pFilt->dwaSrcMask[0] = pf->SRC_MASK;
|
|
pFilt->dwaDstAddr[0] = pf->DEST_ADDR;
|
|
pFilt->dwaDstMask[0] = pf->DEST_MASK;
|
|
pFilt->dwProtocol = pf->PROTO;
|
|
pFilt->fLateBound = pf->fLateBound;
|
|
pFilt->wSrcPortHigh = pf->wSrcPortHigh;
|
|
pFilt->wDstPortHigh = pf->wDstPortHigh;
|
|
|
|
if(pFilt->dwProtocol == FILTER_PROTO_ICMP)
|
|
{
|
|
if(LOBYTE(LOWORD(pf->uliProtoSrcDstMask.HighPart)) isnot 0xff)
|
|
{
|
|
pFilt->wSrcPort = FILTER_ICMP_TYPE_ANY;
|
|
}
|
|
else
|
|
{
|
|
pFilt->wSrcPort =
|
|
MAKEWORD(LOBYTE(LOWORD(pf->uliProtoSrcDstPort.HighPart)),0x00);
|
|
}
|
|
|
|
if(HIBYTE(LOWORD(pf->uliProtoSrcDstMask.HighPart)) isnot 0xff)
|
|
{
|
|
pFilt->wDstPort = FILTER_ICMP_CODE_ANY;
|
|
}
|
|
else
|
|
{
|
|
pFilt->wDstPort =
|
|
MAKEWORD(HIBYTE(LOWORD(pf->uliProtoSrcDstPort.HighPart)),0x00);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pFilt->wSrcPort =
|
|
LOWORD(pf->uliProtoSrcDstPort.HighPart);
|
|
pFilt->wDstPort =
|
|
HIWORD(pf->uliProtoSrcDstPort.HighPart);
|
|
}
|
|
pInfo++;
|
|
}
|
|
|
|
for(i = 0, List = pIf->pleOutFilterSet.Flink;
|
|
List != &pIf->pleOutFilterSet;
|
|
i++, List = List->Flink)
|
|
{
|
|
PFILTER_INFOEX pEx = &pInfo->info;
|
|
PFILTER_INFO2 pFilt = &pEx->info;
|
|
|
|
pf = CONTAINING_RECORD(List, FILTER, pleFilters);
|
|
|
|
pInfo->dwNumPacketsFiltered =
|
|
(DWORD)pf->Count.lCount;
|
|
|
|
if(fClear)
|
|
{
|
|
pf->Count.lCount = 0;
|
|
}
|
|
|
|
pEx->dwFilterRule = pf->dwFilterRule;
|
|
pEx->type = PFE_FILTER;
|
|
pEx->dwFlags = pf->dwFlags & FLAGS_INFOEX_ALLFLAGS;
|
|
pFilt->addrType = IPV4;
|
|
pFilt->dwaSrcAddr[0] = pf->SRC_ADDR;
|
|
pFilt->dwaSrcMask[0] = pf->SRC_MASK;
|
|
pFilt->dwaDstAddr[0] = pf->DEST_ADDR;
|
|
pFilt->dwaDstMask[0] = pf->DEST_MASK;
|
|
pFilt->dwProtocol = pf->PROTO;
|
|
pFilt->fLateBound = pf->fLateBound;
|
|
|
|
if(pFilt->dwProtocol == FILTER_PROTO_ICMP)
|
|
{
|
|
if(LOBYTE(LOWORD(pf->uliProtoSrcDstMask.HighPart)) isnot 0xff)
|
|
{
|
|
pFilt->wSrcPort = FILTER_ICMP_TYPE_ANY;
|
|
}
|
|
else
|
|
{
|
|
pFilt->wSrcPort =
|
|
MAKEWORD(LOBYTE(LOWORD(pf->uliProtoSrcDstPort.HighPart)),0x00);
|
|
}
|
|
|
|
if(HIBYTE(LOWORD(pf->uliProtoSrcDstMask.HighPart)) isnot 0xff)
|
|
{
|
|
pFilt->wDstPort = FILTER_ICMP_CODE_ANY;
|
|
}
|
|
else
|
|
{
|
|
pFilt->wDstPort =
|
|
MAKEWORD(HIBYTE(LOWORD(pf->uliProtoSrcDstPort.HighPart)),0x00);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pFilt->wSrcPort =
|
|
LOWORD(pf->uliProtoSrcDstPort.HighPart);
|
|
pFilt->wDstPort =
|
|
HIWORD(pf->uliProtoSrcDstPort.HighPart);
|
|
}
|
|
pInfo++;
|
|
}
|
|
|
|
return(STATUS_SUCCESS);
|
|
}
|
|
|
|
NTSTATUS
|
|
GetInterfaceParameters(PPAGED_FILTER_INTERFACE pPage,
|
|
PPFGETINTERFACEPARAMETERS pp,
|
|
PDWORD pdwSize)
|
|
/*++
|
|
Routine Description:
|
|
Read the information about an interface
|
|
|
|
pPage -- the paged filter interface
|
|
pp -- the user's args to this
|
|
pdwSize -- the size of the buffer on IN and the bytes used on OUT
|
|
--*/
|
|
{
|
|
PFILTER_INTERFACE pIf;
|
|
DWORD dwFilterSize;
|
|
BOOL fClear = (pp->dwFlags & GET_FLAGS_RESET) != 0;
|
|
LOCK_STATE LockState;
|
|
|
|
|
|
KeEnterCriticalRegion();
|
|
ExAcquireResourceExclusiveLite(&FilterListResourceLock, TRUE);
|
|
|
|
if(!pPage)
|
|
{
|
|
pIf = FindMatchName(0, (DWORD)((DWORD_PTR)pp->pvDriverContext));
|
|
if(!pIf)
|
|
{
|
|
ExReleaseResourceLite(&FilterListResourceLock);
|
|
KeLeaveCriticalRegion();
|
|
return(STATUS_INVALID_PARAMETER);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pIf = pPage->pFilter;
|
|
}
|
|
|
|
if(pIf->dwGlobalEnables & FI_ENABLE_OLD)
|
|
{
|
|
ExReleaseResourceLite(&FilterListResourceLock);
|
|
KeLeaveCriticalRegion();
|
|
return(STATUS_INVALID_DEVICE_REQUEST);
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// fill in what we can fill in. Need to double lock -- the
|
|
// outer to prevent the interface from going away and filters
|
|
// being changed, the inner to protect the counts.
|
|
//
|
|
|
|
AcquireWriteLock(&g_filters.ifListLock,&LockState);
|
|
|
|
pp->dwInDrops = (DWORD)pIf->lTotalInDrops;
|
|
pp->dwOutDrops = (DWORD)pIf->lTotalOutDrops;
|
|
|
|
pp->dwSynOrFrag = (DWORD)pIf->CountSynOrFrag.lCount +
|
|
(DWORD)pIf->CountNoFrag.lCount;
|
|
pp->dwSpoof = (DWORD)pIf->CountSpoof.lCount +
|
|
(DWORD)pIf->CountStrongHost.lCount;
|
|
pp->dwUnused = (DWORD)pIf->CountUnused.lCount;
|
|
pp->dwTcpCtl = (DWORD)pIf->CountCtl.lCount;
|
|
pp->liSYN.QuadPart = pIf->liSYNCount.QuadPart;
|
|
pp->liTotalLogged.QuadPart = pIf->liLoggedFrames.QuadPart;
|
|
pp->dwLostLogEntries = pIf->dwLostFrames;
|
|
|
|
pp->eaInAction = pIf->eaInAction;
|
|
pp->eaOutAction = pIf->eaOutAction;
|
|
|
|
pp->dwNumInFilters = pIf->dwNumInFilters;
|
|
pp->dwNumOutFilters = pIf->dwNumOutFilters;
|
|
|
|
dwFilterSize = (pIf->dwNumInFilters + pIf->dwNumOutFilters) *
|
|
sizeof(FILTER_STATS_EX);
|
|
|
|
if((pp->dwFlags & GET_FLAGS_FILTERS) != 0)
|
|
{
|
|
//
|
|
// Make sure all of the filters fit
|
|
//
|
|
|
|
if((*pdwSize -
|
|
(sizeof(PFGETINTERFACEPARAMETERS) - sizeof(FILTER_STATS_EX))) <
|
|
dwFilterSize)
|
|
{
|
|
//
|
|
// doesn't fit. Return the required size
|
|
//
|
|
|
|
pp->dwReserved =
|
|
dwFilterSize + (sizeof(PFGETINTERFACEPARAMETERS) -
|
|
sizeof(FILTER_STATS_EX));
|
|
ReleaseWriteLock(&g_filters.ifListLock, &LockState);
|
|
ExReleaseResourceLite(&FilterListResourceLock);
|
|
KeLeaveCriticalRegion();
|
|
return(STATUS_SUCCESS);
|
|
}
|
|
|
|
(VOID)GetFiltersEx(pIf,
|
|
fClear,
|
|
&pp->FilterInfo[0]);
|
|
}
|
|
|
|
//
|
|
// if clear requested, do it now
|
|
//
|
|
if(fClear)
|
|
{
|
|
pIf->lTotalInDrops = 0;
|
|
pIf->lTotalOutDrops = 0;
|
|
pIf->CountSynOrFrag.lCount = 0;
|
|
pIf->CountNoFrag.lCount = 0;
|
|
pIf->CountFragCache.lCount = 0;
|
|
pIf->CountSpoof.lCount = 0;
|
|
pIf->CountUnused.lCount = 0;
|
|
pIf->CountCtl.lCount = 0;
|
|
pIf->CountStrongHost.lCount = 0;
|
|
pIf->liSYNCount.QuadPart = 0;
|
|
pIf->liLoggedFrames.QuadPart = 0;
|
|
pIf->dwLostFrames = 0;
|
|
}
|
|
ReleaseWriteLock(&g_filters.ifListLock, &LockState);
|
|
|
|
ExReleaseResourceLite(&FilterListResourceLock);
|
|
KeLeaveCriticalRegion();
|
|
return(STATUS_SUCCESS);
|
|
}
|
|
|
|
NTSTATUS
|
|
GetSynCountTotal(PFILTER_DRIVER_GET_SYN_COUNT pscCount)
|
|
/*++
|
|
Routine Description:
|
|
Get sum of SYNs on filter interfaces
|
|
--*/
|
|
{
|
|
PFILTER_INTERFACE pIf;
|
|
PLIST_ENTRY pList;
|
|
LOCK_STATE LockState;
|
|
LONGLONG llCount = 0;
|
|
|
|
AcquireWriteLock(&g_filters.ifListLock,&LockState);
|
|
|
|
for(pList = g_filters.leIfListHead.Flink;
|
|
pList != &g_filters.leIfListHead;
|
|
pList = pList->Flink)
|
|
{
|
|
|
|
pIf = CONTAINING_RECORD(pList, FILTER_INTERFACE, leIfLink);
|
|
|
|
if(!(pIf->dwGlobalEnables & FI_ENABLE_OLD))
|
|
{
|
|
//
|
|
// accumulate it here to avoid page faults.
|
|
//
|
|
llCount += pIf->liSYNCount.QuadPart;
|
|
}
|
|
}
|
|
ReleaseWriteLock(&g_filters.ifListLock,&LockState);
|
|
|
|
//
|
|
// Now that no lock is held, store into the pageable
|
|
// value
|
|
//
|
|
pscCount->liCount.QuadPart = llCount;
|
|
return(STATUS_SUCCESS);
|
|
}
|
|
|
|
VOID
|
|
NotifyFastPath(PFILTER_INTERFACE pIf, DWORD dwIndex, DWORD dwCode)
|
|
/*++
|
|
Routine Description:
|
|
Called whenever the filter of an interface change so that
|
|
we can tell the fast path code to clear its cache. This
|
|
must be called at base level as it might sleep or yield.
|
|
--*/
|
|
{
|
|
DWORD dwFilterCount = 1;
|
|
|
|
if(dwIndex != UNKNOWN_IP_INDEX)
|
|
{
|
|
InterlockedIncrement(&pIf->lNotify);
|
|
if(dwCode == NOT_UNBIND)
|
|
{
|
|
LARGE_INTEGER liInterval;
|
|
//
|
|
// it's an unbind. Wait for all existing callouts to
|
|
// complete.
|
|
//
|
|
|
|
liInterval.QuadPart = -1000; // short delay. Start with
|
|
// 100 us;
|
|
while(pIf->lNotify > 1)
|
|
{
|
|
//
|
|
// small delay to allow this to settle
|
|
//
|
|
|
|
KeDelayExecutionThread(KernelMode, FALSE, &liInterval);
|
|
liInterval.QuadPart *= 2;
|
|
}
|
|
dwFilterCount = 0;
|
|
}
|
|
//
|
|
// tell the fast path of this
|
|
//
|
|
InterlockedDecrement(&pIf->lNotify);
|
|
}
|
|
}
|
|
|
|
VOID
|
|
NotifyFastPathIf(PFILTER_INTERFACE pIf)
|
|
/*++
|
|
Routine Description:
|
|
Same as above, but this is called when an interface is first
|
|
bound. Notify only if it has filters or is a DROP interface
|
|
--*/
|
|
{
|
|
if(
|
|
(pIf->eaInAction == DROP)
|
|
||
|
|
(pIf->eaOutAction == DROP)
|
|
||
|
|
pIf->dwNumInFilters
|
|
||
|
|
pIf->dwNumOutFilters)
|
|
{
|
|
NotifyFastPath(pIf, pIf->dwIpIndex, NOT_RESTRICTION);
|
|
}
|
|
}
|
|
|
|
NTSTATUS
|
|
SetExtensionPointer(
|
|
PPF_SET_EXTENSION_HOOK_INFO Info,
|
|
PFILE_OBJECT FileObject
|
|
)
|
|
{
|
|
LOCK_STATE LockState;
|
|
PFILTER_INTERFACE pIf;
|
|
PLIST_ENTRY pList;
|
|
|
|
AcquireWriteLock(&g_Extension.ExtLock, &LockState);
|
|
if (Info->ExtensionPointer == NULL)
|
|
{
|
|
//
|
|
// Extension hook is already set to NULL, be strict about it.
|
|
//
|
|
|
|
if (g_Extension.ExtPointer == NULL)
|
|
{
|
|
ReleaseWriteLock(&g_Extension.ExtLock, &LockState);
|
|
return(STATUS_INVALID_PARAMETER);
|
|
}
|
|
|
|
//
|
|
// File object of the entity hooking and unhooking should match.
|
|
//
|
|
|
|
if (g_Extension.ExtFileObject != FileObject)
|
|
{
|
|
ReleaseWriteLock(&g_Extension.ExtLock, &LockState);
|
|
return(STATUS_INVALID_PARAMETER);
|
|
}
|
|
|
|
|
|
g_Extension.ExtPointer = NULL;
|
|
g_Extension.ExtFileObject = NULL;
|
|
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// We are setting the extension pointer to a non NULL value. The extension pointer must
|
|
// be already set to NULL to begin with, otherwise someone else registered it already.
|
|
//
|
|
|
|
if (g_Extension.ExtPointer != NULL)
|
|
{
|
|
ReleaseWriteLock(&g_Extension.ExtLock,&LockState);
|
|
return(STATUS_INVALID_PARAMETER);
|
|
}
|
|
|
|
//
|
|
// Record the file object here, every other call should be validated against this
|
|
// file object.
|
|
//
|
|
|
|
g_Extension.ExtFileObject = FileObject;
|
|
g_Extension.ExtPointer = Info->ExtensionPointer ;
|
|
|
|
}
|
|
|
|
CALLTRACE(("IPFLTDRV: SetExtensionPointer SUCCESSFUL\n"));
|
|
ReleaseWriteLock(&g_Extension.ExtLock,&LockState);
|
|
|
|
return(STATUS_SUCCESS);
|
|
|
|
}
|
|
|
|
|
|
PFILTER_INTERFACE
|
|
FilterDriverLookupInterface(
|
|
IN ULONG Index,
|
|
IN IPAddr LinkNextHop
|
|
)
|
|
|
|
/*++
|
|
Routine Description:
|
|
|
|
This routine is invoked to search for an interface with the given index
|
|
in our list of interfaces.
|
|
--*/
|
|
|
|
{
|
|
PFILTER_INTERFACE pIf;
|
|
PLIST_ENTRY pList;
|
|
|
|
for (pList = g_filters.leIfListHead.Flink;
|
|
pList != &g_filters.leIfListHead;
|
|
pList = pList->Flink)
|
|
{
|
|
|
|
pIf = CONTAINING_RECORD(pList, FILTER_INTERFACE, leIfLink);
|
|
if ((pIf->dwIpIndex == Index) && (pIf->dwLinkIpAddress == LinkNextHop))
|
|
{
|
|
TRACE(CONFIG,(
|
|
"IPFLTDRV: LookupIF: Found Entry %8x for Index=%d, NextHop=%d\n",
|
|
pIf,
|
|
Index,
|
|
LinkNextHop
|
|
));
|
|
|
|
return pIf;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
|
|
} // FilterDriverLookupInterface
|