windows-nt/Source/XPSP1/NT/net/tcpip/apis/iphlpapi/dll/fltclass.cxx
2020-09-26 16:20:57 +08:00

1600 lines
39 KiB
C++

/*++
PDWORD * ppdwAddress*++
Copyright (c) 1997 Microsoft Corporation
Module Name:
Abstract:
Implementation of the packet filter control code
Revision History:
Author:
Arnold Miller (ArnoldM) 24-Sept-1997
--*/
#ifndef CHICAGO // don't need these on Memphis
#include "fltapis.hxx"
//
// these care called from the DLL entry which is C code, so
// declare the names to be something the C compiler can
// generate
//
extern "C"
{
VOID
InitFilterApis();
VOID
UnInitFilterApis();
DWORD
AllocateAndGetIpAddrTableFromStack(
OUT MIB_IPADDRTABLE **ppIpAddrTable,
IN BOOL bOrder,
IN HANDLE hHeap,
IN DWORD dwFlags
);
}
InterfaceContainer icContainer;
//
// All of the class methods. If you're looking for the WIN32
// APIs, try the file fltapis.cxx
//
VOID
InterfaceContainer::InitInterfaceContainer()
{
if(!_Inited)
{
_InitResource();
__try {
InitializeCriticalSection(&_csDriverLock);
_Log = 0;
_hDriver = 0;
_Inited = TRUE;
}
__except (EXCEPTION_EXECUTE_HANDLER) {
_DestroyResource();
_Inited = FALSE;
}
}
}
DWORD
InterfaceContainer::FindInterfaceAndRef(INTERFACE_HANDLE pInterface,
PacketFilterInterface ** ppif)
/*++
Routine Description:
Verify that an INTERFACE_HANDLE refers to an extant filter interface.
If successful the object resource is held shared and must be
derefenced when done
--*/
{
DWORD err;
PacketFilterInterface * ppfInterface;
PacketFilterInterface * plook = (PacketFilterInterface *)pInterface;
//
// No need for a _DriverReady here. The verification of the
// interface is sufficient.
//
_AcquireShared();
ppfInterface = (PacketFilterInterface *)_hcHandles.FetchHandleValue(
(DWORD)((DWORD_PTR)pInterface));
if(ppfInterface)
{
*ppif = ppfInterface;
err = ERROR_SUCCESS;
}
else
{
err = ERROR_INVALID_HANDLE;
}
if(err != ERROR_SUCCESS)
{
_Release();
}
return(err);
}
DWORD
InterfaceContainer::AddInterface(
DWORD dwName,
PFFORWARD_ACTION inAction,
PFFORWARD_ACTION outAction,
BOOL fUseLog,
BOOL fMustBeUnique,
INTERFACE_HANDLE *ppInterface)
/*++
Routine Description:
Add a new interface. All this does is create the interface in
the driver. It does not bind it to the stack.
--*/
{
PacketFilterInterface *pfi;
DWORD err = NO_ERROR;
err = _DriverReady();
if(err != STATUS_SUCCESS)
{
return(err);
}
_AcquireExclusive();
pfi = new PacketFilterInterface(
_hDriver,
dwName,
fUseLog ? _Log : 0,
fMustBeUnique,
(FORWARD_ACTION)inAction,
(FORWARD_ACTION)outAction);
if(!pfi)
{
err = GetLastError();
}
else if((err = pfi->GetStatus()) != STATUS_SUCCESS)
{
delete pfi;
}
else
{
__try
{
err = _hcHandles.NewHandle((PVOID)pfi,
(PDWORD)ppInterface);
}
__except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION)
{
err = ERROR_INVALID_PARAMETER;
}
if(err)
{
//
// Could not add the handle so destroy the interface
//
delete pfi;
}
}
_Release();
return(err);
}
DWORD
InterfaceContainer::DeleteInterface(INTERFACE_HANDLE pInterface)
/*++
Routine Description:
Delete a filter interface.
--*/
{
DWORD err;
PacketFilterInterface *pfi;
_AcquireExclusive();
pfi = (PacketFilterInterface *)_hcHandles.FetchHandleValue(
(DWORD)((DWORD_PTR)pInterface));
if(pfi)
{
//
// a valid handle. Destroy the associated
// interface and free the handle
//
delete pfi;
(VOID)_hcHandles.DeleteHandle((DWORD)((DWORD_PTR)pInterface));
err = ERROR_SUCCESS;
}
else
{
err = ERROR_INVALID_HANDLE;
}
_Release();
return(err);
}
DWORD
InterfaceContainer::SetLogBuffer(
PBYTE pbBuffer,
DWORD dwSize,
DWORD dwThreshold,
DWORD dwEntries,
PDWORD pdwLoggedEntries,
PDWORD pdwLostEntries,
PDWORD pdwSizeUsed)
/*++
Routine Description:
Set a new log buffer for the log
--*/
{
NTSTATUS Status;
PFSETBUFFER pfSet;
IO_STATUS_BLOCK IoStatusBlock;
DWORD err;
//
// Buffer size should be atleast as big as one frame. Actually,
// we can't really say what the size of a frame is going to be
// because the frame has IpHeader and the data which is bigger
// than sizeof(PFLOGFRAME), nevertheless this is a good paramter
// check if caller was passing a zero or something for the size.
//
if (dwSize < sizeof(PFLOGFRAME)) {
return(ERROR_INSUFFICIENT_BUFFER);
}
//
// Make sure that the starting address and the offset both are
// quadword alligned.
//
if (!COUNT_IS_ALIGNED((UINT_PTR)pbBuffer, ALIGN_WORST) ||
!COUNT_IS_ALIGNED(dwSize, ALIGN_WORST)
)
{
return(ERROR_MAPPED_ALIGNMENT);
}
//
// Check the upper bounds for threshold values (dwEntries and dwThreshold)
//
if ( dwThreshold > dwSize ||
(dwEntries * sizeof(PFLOGFRAME)) > dwSize)
return (ERROR_INVALID_PARAMETER);
//
// Check the lower bounds for threshold values (dwEntries and dwThreshold)
//
if ( dwThreshold < sizeof(PFLOGFRAME) )
return (ERROR_INVALID_PARAMETER);
//
// Make sure all the writable memory looks good.
//
if (
IsBadWritePtr(pdwLoggedEntries, sizeof(DWORD)) ||
IsBadWritePtr(pdwLostEntries, sizeof(DWORD)) ||
IsBadWritePtr(pdwSizeUsed, sizeof(DWORD)) ||
IsBadWritePtr(pbBuffer, dwSize)
)
{
return(ERROR_INVALID_PARAMETER);
}
//
// no need to call _DriverReady. If the log exists, the
// driver is ready.
//
_AcquireExclusive();
if(!_Log)
{
err = ERROR_INVALID_HANDLE;
goto Error;
}
pfSet.pfLogId = _Log;
pfSet.dwSize = dwSize;
pfSet.dwSizeThreshold = dwThreshold;
pfSet.dwEntriesThreshold = dwEntries;
pfSet.dwFlags = 0;
pfSet.pbBaseOfLog = pbBuffer;
Status = NtDeviceIoControlFile( _hDriver,
NULL,
NULL,
NULL,
&IoStatusBlock,
IOCTL_SET_LOG_BUFFER,
(PVOID)&pfSet,
sizeof(pfSet),
(PVOID)&pfSet,
sizeof(pfSet));
if(NT_SUCCESS(Status))
{
*pdwLoggedEntries = pfSet.dwLoggedEntries;
*pdwLostEntries = pfSet.dwLostEntries;
*pdwSizeUsed = pfSet.dwSize;
err = ERROR_SUCCESS;
}
else
{
err = CoerceDriverError(Status);
}
Error:
_Release();
return(err);
}
DWORD
InterfaceContainer::MakeLog( HANDLE hEvent )
/*++
Routine Description:
Make a log for this
--*/
{
DWORD err;
PFLOG pfSet;
NTSTATUS Status;
IO_STATUS_BLOCK ioStatus;
err = _DriverReady();
if(err != STATUS_SUCCESS)
{
return(err);
}
_AcquireExclusive();
if(_Log)
{
err = ERROR_ALREADY_ASSIGNED;
}
else
{
memset(&pfSet, 0, sizeof(pfSet));
pfSet.hEvent = hEvent;
pfSet.dwFlags = 0;
Status = NtDeviceIoControlFile(
_hDriver,
NULL,
NULL,
NULL,
&ioStatus,
IOCTL_PF_CREATE_LOG,
(PVOID)&pfSet,
sizeof(pfSet),
(PVOID)&pfSet,
sizeof(pfSet));
if(NT_SUCCESS(Status))
{
_Log = pfSet.pfLogId;
}
else
{
err = CoerceDriverError(Status);
}
}
_Release();
return(err);
}
DWORD
InterfaceContainer::DeleteLog( VOID )
/*++
Routine Description:
Delete the log and by implication remove the log from all
of the interfaces
--*/
{
DWORD err = ERROR_SUCCESS;
PFDELETELOG pfSet;
NTSTATUS Status;
IO_STATUS_BLOCK ioStatus;
_AcquireExclusive();
if(!_Log)
{
err = ERROR_INVALID_HANDLE;
}
else
{
pfSet.pfLogId = _Log;
Status = NtDeviceIoControlFile(
_hDriver,
NULL,
NULL,
NULL,
&ioStatus,
IOCTL_PF_DELETE_LOG,
(PVOID)&pfSet,
sizeof(pfSet),
(PVOID)&pfSet,
sizeof(pfSet));
if(NT_SUCCESS(Status))
{
_Log = 0;
}
else
{
err = CoerceDriverError(Status);
}
}
_Release();
return(err);
}
VOID
InterfaceContainer::AddressUpdateNotification()
{
}
//
// The PacketFilterInterface methods.
//
PacketFilterInterface::PacketFilterInterface(
HANDLE hDriver,
DWORD dwName,
PFLOGGER pfLog,
BOOL fMustBeUnique,
FORWARD_ACTION inAction,
FORWARD_ACTION outAction)
/*++
Routine Description:
Constructor for a new interface. If this interface must
be unique, then dwName should be 0. Otherwise pick
a name that can be associated with other uses, such as the
IP address of the interface or some manifest. This assumes
the creater of this will check the status code and destruct
the object if it is not successful. This is important since
the other methods do not check for successful construction.
--*/
{
PFINTERFACEPARAMETERS Parms;
DWORD dwInBufLen = sizeof(Parms);
IO_STATUS_BLOCK IoStatusBlock;
NTSTATUS Status;
InitializeCriticalSection(&_cs);
_hDriver = hDriver;
_dwFlags = 0;
//
// now create the interface.
//
memset(&Parms, 0, sizeof(Parms));
Parms.pfbType = PF_BIND_NAME;
Parms.eaIn = inAction;
Parms.eaOut = outAction;
Parms.dwBindingData = dwName;
Parms.fdInterface.dwIfIndex = dwName;
Parms.fdInterface.pvRtrMgrContext = UlongToPtr(dwName);
Parms.pfLogId = pfLog;
if(fMustBeUnique)
{
//
// this is a non-sharable interface. Mark it as such
//
Parms.dwInterfaceFlags |= PFSET_FLAGS_UNIQUE;
}
Status = NtDeviceIoControlFile(_hDriver,
NULL,
NULL,
NULL,
&IoStatusBlock,
IOCTL_PF_CREATE_AND_SET_INTERFACE_PARAMETERS,
(PVOID)&Parms,
dwInBufLen,
(PVOID)&Parms,
dwInBufLen);
if(NT_SUCCESS(Status))
{
_err = ERROR_SUCCESS;
_pvDriverContext = Parms.fdInterface.pvDriverContext;
}
else
{
_err = icContainer.CoerceDriverError(Status);
}
}
PacketFilterInterface::~PacketFilterInterface()
/*++
Routine Description:
Destructor. Tells the filter driver to forget this interface. Any
filters will be removed by the driver.
--*/
{
if(!_err)
{
IO_STATUS_BLOCK IoStatusBlock;
FILTER_DRIVER_DELETE_INTERFACE di;
di.pvDriverContext = _pvDriverContext;
NtDeviceIoControlFile(_hDriver,
NULL,
NULL,
NULL,
&IoStatusBlock,
IOCTL_DELETE_INTERFACEEX,
(PVOID)&di,
sizeof(di),
(PVOID)&di,
sizeof(di));
}
DeleteCriticalSection(&_cs);
}
DWORD
PacketFilterInterface::_CommonBind(PFBINDINGTYPE dwBindType, DWORD dwData, DWORD LinkData)
/*++
Routine Description:
Common routine to bind an interface. The driver has
been verified.
--*/
{
INTERFACEBINDING2 Bind2;
IO_STATUS_BLOCK IoStatusBlock;
NTSTATUS Status;
DWORD err;
//
// Must serialize this. Even though the shared resource is held,
// this is a "write" operation and therfore needs strict
// serialization.
//
_Lock();
if(_IsBound())
{
_UnLock();
return(ERROR_INVALID_PARAMETER);
}
//
// We're not bound.
// Note that we are using new type of struture for the compitability.
// The old INTERFACEBINDING structure does not have support for
// link addresses. Note also that we are using a new IOCTL here.
//
Bind2.pvDriverContext = _pvDriverContext;
Bind2.pfType = dwBindType;
Bind2.dwAdd = dwData;
Bind2.dwLinkAdd = LinkData;
Status = NtDeviceIoControlFile(_hDriver,
NULL,
NULL,
NULL,
&IoStatusBlock,
IOCTL_SET_INTERFACE_BINDING2,
(PVOID)&Bind2,
sizeof(Bind2),
(PVOID)&Bind2,
sizeof(Bind2));
if(NT_SUCCESS(Status))
{
_SetBound();
err = ERROR_SUCCESS;
_dwEpoch = Bind2.dwEpoch;
}
else
{
err = icContainer.CoerceDriverError(Status);
}
_UnLock();
return(err);
}
DWORD
PacketFilterInterface::UnBindInterface( VOID )
/*++
Routine Description:
Unbind the interface from whatever it is bound to
--*/
{
INTERFACEBINDING Bind;
IO_STATUS_BLOCK IoStatusBlock;
NTSTATUS Status;
DWORD err;
//
// Must serialize this. Even though the shared resource is held,
// this is a "write" operation and therfore needs strict
// serialization.
//
_Lock();
if(!_IsBound())
{
_UnLock();
return(ERROR_INVALID_PARAMETER);
}
//
// We're address bound. So unbind from the stack
//
Bind.pvDriverContext = _pvDriverContext;
Bind.dwEpoch = _dwEpoch;
Status = NtDeviceIoControlFile(_hDriver,
NULL,
NULL,
NULL,
&IoStatusBlock,
IOCTL_CLEAR_INTERFACE_BINDING,
(PVOID)&Bind,
sizeof(Bind),
(PVOID)&Bind,
sizeof(Bind));
if(NT_SUCCESS(Status))
{
_ClearBound();
err = STATUS_SUCCESS;
}
else
{
err = icContainer.CoerceDriverError(Status);
}
_UnLock();
return(err);
}
DWORD
PacketFilterInterface::AddGlobalFilter(GLOBAL_FILTER gf)
/*++
Routine Description:
Add the specified global filter to the interface
--*/
{
PF_FILTER_DESCRIPTOR fd;
DWORD err;
FILTER_HANDLE fh;
memset(&fd, 0, sizeof(fd));
switch(gf)
{
default:
//
// fall through ...
//
case GF_FRAGCACHE:
case GF_FRAGMENTS:
case GF_STRONGHOST:
err = _AddFilters((PFETYPE)gf, 1, &fd, 0, 0, &fh);
break;
}
return(err);
}
DWORD
PacketFilterInterface::DeleteGlobalFilter(GLOBAL_FILTER gf)
/*++
Routine Descriptor:
Remove a global filter from this interface
--*/
{
PF_FILTER_DESCRIPTOR fd;
DWORD err;
FILTER_HANDLE fh;
memset(&fd, 0, sizeof(fd));
switch(gf)
{
default:
//
// fall through ...
//
case GF_FRAGCACHE:
case GF_FRAGMENTS:
case GF_STRONGHOST:
err = _DeleteFiltersByFilter((PFETYPE)gf, 1, &fd, 0, 0);
break;
}
return(err);
}
DWORD
PacketFilterInterface::DeleteFiltersByHandle(DWORD cHandles,
PFILTER_HANDLE pvHandles)
/*++
Routine Description:
Remove filters by handles returned when the filters were created
--*/
{
IO_STATUS_BLOCK IoStatusBlock;
NTSTATUS Status;
DWORD dwSize = sizeof(PFDELETEBYHANDLE) - sizeof(PVOID) +
(sizeof(PVOID) * cHandles);
PPFDELETEBYHANDLE pDelHandle;
DWORD err = NO_ERROR;
pDelHandle = (PPFDELETEBYHANDLE)new PBYTE[dwSize];
if(!pDelHandle)
{
return(GetLastError());
}
pDelHandle->pvDriverContext = _pvDriverContext;
__try
{
memcpy(&pDelHandle->pvHandles[0],
pvHandles,
cHandles * sizeof(PVOID));
}
__except(GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION)
{
err = ERROR_INVALID_PARAMETER;
delete pDelHandle;
return(err);
}
Status = NtDeviceIoControlFile(_hDriver,
NULL,
NULL,
NULL,
&IoStatusBlock,
IOCTL_PF_DELETE_BY_HANDLE,
(PVOID)pDelHandle,
dwSize,
0,
0);
delete pDelHandle;
if(NT_SUCCESS(Status))
{
err = ERROR_SUCCESS;
}
else
{
err = icContainer.CoerceDriverError(Status);
}
return(err);
}
PFILTER_DRIVER_SET_FILTERS
PacketFilterInterface::_SetFilterBlock(
PFETYPE pfe,
DWORD cInFilters, PPF_FILTER_DESCRIPTOR pfiltIn,
DWORD cOutFilters, PPF_FILTER_DESCRIPTOR pfiltOut,
PDWORD pdwSize,
PFILTER_DESCRIPTOR2 * ppfdIn,
PFILTER_DESCRIPTOR2 * ppfdOut)
/*++
Routine Description:
Private method to allocate and construct an argument block for
setting or deleting filters. This is the heart of this code
as it forms the data structure used for creating filters
and for removing filters by descriptor.
--*/
{
PFILTER_DRIVER_SET_FILTERS pSet;
DWORD dwSetSize, dwInInfoSize, dwOutInfoSize;
DWORD dwOutFilters, dwInFilters;
PRTR_INFO_BLOCK_HEADER pIo;
PFILTER_DESCRIPTOR2 p2;
DWORD err = ERROR_SUCCESS;
//
// compute the memory size needed.
//
dwSetSize = sizeof(FILTER_DRIVER_SET_FILTERS) +
sizeof(RTR_INFO_BLOCK_HEADER) +
(ALIGN_SIZE - 1) + // worst case alignment padding
(2 * sizeof(FILTER_DESCRIPTOR2));
if(cInFilters)
{
dwInFilters = cInFilters;
dwInInfoSize = sizeof(FILTER_INFOEX) * dwInFilters;
dwSetSize += dwInInfoSize;
dwInInfoSize += sizeof(FILTER_DESCRIPTOR2);
}
else
{
dwInInfoSize = sizeof(FILTER_DESCRIPTOR2);
dwInFilters = 0;
}
if(cOutFilters)
{
dwOutFilters = cOutFilters;
dwOutInfoSize = sizeof(FILTER_INFOEX) * dwOutFilters;
dwSetSize += dwOutInfoSize;
dwOutInfoSize += sizeof(FILTER_DESCRIPTOR2);
}
else
{
dwOutFilters = 0;
dwOutInfoSize = sizeof(FILTER_DESCRIPTOR2);
}
if(dwSetSize == (sizeof(FILTER_DRIVER_SET_FILTERS) +
sizeof(RTR_INFO_BLOCK_HEADER) +
(2 * sizeof(FILTER_DESCRIPTOR2))) )
{
SetLastError(PFERROR_NO_FILTERS_GIVEN);
return(NULL);
}
pSet = (PFILTER_DRIVER_SET_FILTERS)new PBYTE[dwSetSize];
if(pSet)
{
*pdwSize = dwSetSize;
//
// create the argument block
//
pSet->pvDriverContext = _pvDriverContext;
pIo = &pSet->ribhInfoBlock;
pIo->Version = RTR_INFO_BLOCK_VERSION;
pIo->Size = dwSetSize;
pIo->TocEntriesCount = 2; // always two of these.
//
// create the ouput filter TOC first. No particular reason,
// but one of them has to be first
//
pIo->TocEntry[0].InfoType = IP_FILTER_DRIVER_OUT_FILTER_INFO;
pIo->TocEntry[0].InfoSize = dwOutInfoSize;
pIo->TocEntry[0].Count = 1;
//
// the filters go after the header and TOCs
//
pIo->TocEntry[0].Offset = sizeof(RTR_INFO_BLOCK_HEADER) +
sizeof(RTR_TOC_ENTRY);
ALIGN_LENGTH(pIo->TocEntry[0].Offset);
//
// make the FILTER_DESCRIPTOR2 values
//
p2 = (PFILTER_DESCRIPTOR2)((PBYTE)pIo + pIo->TocEntry[0].Offset);
*ppfdOut = p2;
p2->dwVersion = 2;
p2->dwNumFilters = dwOutFilters;
while(cOutFilters--)
{
//
// marshall each filter into the block
//
err = _MarshallFilter(pfe, pfiltOut++, &p2->fiFilter[cOutFilters]);
if(err)
{
goto OuttaHere;
}
}
//
// now the input filters
//
pIo->TocEntry[1].InfoType = IP_FILTER_DRIVER_IN_FILTER_INFO;
pIo->TocEntry[1].InfoSize = dwInInfoSize;
pIo->TocEntry[1].Count = 1;
//
// the filters go after the header and TOCs
//
pIo->TocEntry[1].Offset = pIo->TocEntry[0].Offset +
dwOutInfoSize;
p2 = (PFILTER_DESCRIPTOR2)((PBYTE)pIo + pIo->TocEntry[1].Offset);
*ppfdIn = p2;
p2->dwVersion = 2;
p2->dwNumFilters = dwInFilters;
while(cInFilters--)
{
//
// marshall each filter into the block
//
err = _MarshallFilter(pfe, pfiltIn++, &p2->fiFilter[cInFilters]);
if(err)
{
break;
}
}
}
OuttaHere:
if(err && pSet)
{
delete pSet;
pSet = 0;
SetLastError(err);
}
return(pSet);
}
DWORD
PacketFilterInterface::_MarshallFilter(
PFETYPE pfe,
PPF_FILTER_DESCRIPTOR pFilt,
PFILTER_INFOEX pInfo)
/*++
RoutineDescription:
Converts an API version of a filter into a driver version
--*/
{
DWORD err = NO_ERROR;
__try
{
pInfo->type = pfe;
pInfo->dwFlags = (pFilt->dwFilterFlags & FD_FLAGS_ALLFLAGS) |
FLAGS_INFOEX_ALLOWDUPS |
FLAGS_INFOEX_ALLOWANYREMOTEADDRESS |
FLAGS_INFOEX_ALLOWANYLOCALADDRESS;
pInfo->info.addrType = IPV4;
pInfo->dwFilterRule = pFilt->dwRule;
pInfo->info.dwProtocol = pFilt->dwProtocol;
pInfo->info.fLateBound = pFilt->fLateBound;
pInfo->info.wSrcPort = pFilt->wSrcPort;
pInfo->info.wDstPort = pFilt->wDstPort;
pInfo->info.wSrcPortHigh = pFilt->wSrcPortHighRange;
pInfo->info.wDstPortHigh = pFilt->wDstPortHighRange;
if ((pfe == PFE_SYNORFRAG) || (pfe == PFE_STRONGHOST) || (pfe == PFE_FRAGCACHE)) {
pInfo->info.dwaSrcAddr[0] = 0;
pInfo->info.dwaSrcMask[0] = 0;
pInfo->info.dwaDstAddr[0] = 0;
pInfo->info.dwaDstMask[0] = 0;
return(ERROR_SUCCESS);
}
//
// mow the addresses
//
pInfo->info.dwaSrcAddr[0] = *(PDWORD)pFilt->SrcAddr;
pInfo->info.dwaSrcMask[0] = *(PDWORD)pFilt->SrcMask;
pInfo->info.dwaDstAddr[0] = *(PDWORD)pFilt->DstAddr;
pInfo->info.dwaDstMask[0] = *(PDWORD)pFilt->DstMask;
err = ERROR_SUCCESS;
}
__except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION)
{
err = ERROR_INVALID_PARAMETER;
}
return(err);
}
DWORD
PacketFilterInterface::_AddFilters(
PFETYPE pfe,
DWORD cInFilters, PPF_FILTER_DESCRIPTOR pfiltIn,
DWORD cOutFilters, PPF_FILTER_DESCRIPTOR pfiltOut,
PFILTER_HANDLE pfHandle)
/*++
Routine Description:
Private member function to add filters to an interface.
--*/
{
PFILTER_DRIVER_SET_FILTERS pSet;
IO_STATUS_BLOCK IoStatusBlock;
NTSTATUS Status;
DWORD dwSize, err;
PFILTER_DESCRIPTOR2 pfdInput, pfdOutput;
//
// Check the handles before using them, if the memory supplied is
// not accessible, we will save the trouble of calling the IOCTL.
//
if (pfHandle) {
if (IsBadWritePtr(
pfHandle,
sizeof(FILTER_HANDLE)*(cInFilters+cOutFilters)
)
) {
return(ERROR_INVALID_PARAMETER);
}
}
pSet = _SetFilterBlock(pfe,
cInFilters,
pfiltIn,
cOutFilters,
pfiltOut,
&dwSize,
&pfdInput,
&pfdOutput);
if(!pSet)
{
return(GetLastError());
}
//
// ready to apply the filters.
//
Status = NtDeviceIoControlFile(_hDriver,
NULL,
NULL,
NULL,
&IoStatusBlock,
IOCTL_SET_INTERFACE_FILTERS_EX,
(PVOID)pSet,
dwSize,
(PVOID)pSet,
dwSize);
if(NT_SUCCESS(Status))
{
//
// did it. If the caller wants the generated handles
// copy them before freeing the buffer
//
if(pfHandle)
{
_CopyFilterHandles(pfdInput, pfdOutput, pfHandle);
}
err = ERROR_SUCCESS;
}
else
{
err = icContainer.CoerceDriverError(Status);
}
_FreeSetBlock(pSet);
return(err);
}
DWORD
PacketFilterInterface::_DeleteFiltersByFilter(PFETYPE pfe,
DWORD cInFilters, PPF_FILTER_DESCRIPTOR pfiltIn,
DWORD cOutFilters, PPF_FILTER_DESCRIPTOR pfiltOut)
/*++
Routine Description:
Private method to delete filters using filter descriptors
instead of handles. Very slow.
--*/
{
PFILTER_DRIVER_SET_FILTERS pSet;
IO_STATUS_BLOCK IoStatusBlock;
NTSTATUS Status;
DWORD dwSize, err;
PFILTER_DESCRIPTOR2 pfdInput, pfdOutput;
pSet = _SetFilterBlock(pfe,
cInFilters,
pfiltIn,
cOutFilters,
pfiltOut,
&dwSize,
&pfdInput,
&pfdOutput);
if(!pSet)
{
return(GetLastError());
}
//
// ready to apply the filters.
//
Status = NtDeviceIoControlFile(_hDriver,
NULL,
NULL,
NULL,
&IoStatusBlock,
IOCTL_DELETE_INTERFACE_FILTERS_EX,
(PVOID)pSet,
dwSize,
(PVOID)pSet,
dwSize);
if(NT_SUCCESS(Status))
{
err = ERROR_SUCCESS;
}
else
{
err = icContainer.CoerceDriverError(Status);
}
_FreeSetBlock(pSet);
return(err);
}
VOID
PacketFilterInterface::_CopyFilterHandles(PFILTER_DESCRIPTOR2 pfd1,
PFILTER_DESCRIPTOR2 pfd2,
PFILTER_HANDLE pfHandle)
/*++
Routine Description
Copy the generated filter handles from the pSet to the pfHandle.
Called after successfully setting filters.
--*/
{
DWORD dwFilters;
for(dwFilters = pfd1->dwNumFilters; dwFilters;)
{
*pfHandle++ = pfd1->fiFilter[--dwFilters].pvFilterHandle;
}
for(dwFilters = pfd2->dwNumFilters; dwFilters;)
{
*pfHandle++ = pfd2->fiFilter[--dwFilters].pvFilterHandle;
}
}
DWORD
PacketFilterInterface::RebindFilters(PPF_LATEBIND_INFO pLateBindInfo)
/*++
Routine Description:
Public method to adjust filter values for switched interface
--*/
{
FILTER_DRIVER_BINDING_INFO Info;
IO_STATUS_BLOCK IoStatusBlock;
NTSTATUS Status;
_Lock(); // serialize this
Info.pvDriverContext = _pvDriverContext;
Info.dwLocalAddr = *(PDWORD)pLateBindInfo->SrcAddr;
Info.dwRemoteAddr = *(PDWORD)pLateBindInfo->DstAddr;
Info.dwMask = *(PDWORD)pLateBindInfo->Mask;
Status = NtDeviceIoControlFile(_hDriver,
NULL,
NULL,
NULL,
&IoStatusBlock,
IOCTL_SET_LATE_BOUND_FILTERSEX,
(PVOID)&Info,
sizeof(Info),
(PVOID)&Info,
sizeof(Info));
_UnLock();
if(NT_SUCCESS(Status))
{
return(ERROR_SUCCESS);
}
return(icContainer.CoerceDriverError(Status));
}
DWORD
PacketFilterInterface::TestPacket(
PacketFilterInterface * pInInterface,
PacketFilterInterface * pOutInterface,
DWORD cBytes,
PBYTE pbPacket,
PPFFORWARD_ACTION ppAction)
/*++
Routine Description:
Public method to do a test packet operation. Note this is just
passed to any interface.
--*/
{
PFILTER_DRIVER_TEST_PACKET Packet;
IO_STATUS_BLOCK IoStatusBlock;
NTSTATUS Status;
DWORD err, dwSize;
if (cBytes > MAXUSHORT)
{
return(ERROR_INVALID_PARAMETER);
}
//
// Get some data.
//
Packet = (PFILTER_DRIVER_TEST_PACKET) new BYTE[cBytes +
sizeof(FILTER_DRIVER_TEST_PACKET) - 1];
if(!Packet)
{
return(GetLastError());
}
if(pInInterface)
{
Packet->pvInInterfaceContext = pInInterface->GetDriverContext();
}
else
{
Packet->pvInInterfaceContext = 0;
}
if(pOutInterface)
{
Packet->pvOutInterfaceContext = pOutInterface->GetDriverContext();
}
else
{
Packet->pvOutInterfaceContext = 0;
}
__try
{
memcpy(Packet->bIpPacket, pbPacket, cBytes);
}
__except(GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION)
{
delete Packet;
return(ERROR_INVALID_PARAMETER);
}
dwSize = cBytes + FIELD_OFFSET(FILTER_DRIVER_TEST_PACKET, bIpPacket[0]);
Status = NtDeviceIoControlFile(_hDriver,
NULL,
NULL,
NULL,
&IoStatusBlock,
IOCTL_TEST_PACKET,
(PVOID)Packet,
dwSize,
(PVOID)Packet,
dwSize);
if(NT_SUCCESS(Status))
{
*ppAction = (PFFORWARD_ACTION)Packet->eaResult;
err = ERROR_SUCCESS;
}
else
{
err = icContainer.CoerceDriverError(Status);
}
delete Packet;
return(err);
}
DWORD
PacketFilterInterface::GetStatistics(
PPF_INTERFACE_STATS ppfStats,
PDWORD pdwBufferSize,
BOOL fResetCounters)
/*++
Routine Description:
Get the interface statistics, including information on
the filters. Because the WIN32 form of this differs
from the underlying form, this code must allocate
memory to use to store the driver's version of this and
then marshall the results in the user's buffer.
--*/
{
PBYTE pbBuffer = NULL;
PPFGETINTERFACEPARAMETERS pfGetip;
DWORD dwipSize, err = NO_ERROR;
NTSTATUS Status;
IO_STATUS_BLOCK IoStatusBlock;
__try
{
if(*pdwBufferSize < _IfBaseSize())
{
//
// the caller must supply at least this much.
//
*pdwBufferSize = _IfBaseSize();
err = PFERROR_BUFFER_TOO_SMALL;
}
}
__except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION)
{
err = ERROR_INVALID_PARAMETER;
}
if (err != NO_ERROR)
{
goto Cleanup;
}
dwipSize = _IpSizeFromifSize(*pdwBufferSize);
pbBuffer = new BYTE[dwipSize];
if(!pbBuffer)
{
return(GetLastError());
}
//
// make the arguments
//
pfGetip = (PPFGETINTERFACEPARAMETERS)pbBuffer;
pfGetip->dwReserved = dwipSize;
pfGetip->pvDriverContext = _pvDriverContext;
pfGetip->dwFlags = GET_FLAGS_FILTERS;
if(fResetCounters)
{
pfGetip->dwFlags |= GET_FLAGS_RESET;
}
Status = NtDeviceIoControlFile(_hDriver,
NULL,
NULL,
NULL,
&IoStatusBlock,
IOCTL_PF_GET_INTERFACE_PARAMETERS,
(PVOID)pfGetip,
dwipSize,
(PVOID)pfGetip,
dwipSize);
if(!NT_SUCCESS(Status))
{
err = icContainer.CoerceDriverError(Status);
}
else if(pfGetip->dwReserved != dwipSize)
{
//
// Here when the user buffer is insufficient. Compute
// the size needed and return the characteristic error.
// Always return the common statistics
//
__try
{
_MarshallCommonStats(ppfStats, pfGetip);
}
__except(GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION)
{
err = ERROR_INVALID_PARAMETER;
}
*pdwBufferSize = _IfSizeFromipSize((ULONG)pfGetip->dwReserved);
err = ERROR_INSUFFICIENT_BUFFER;
}
else
{
DWORD i, dwFiltersReturned;
PDWORD pdwAddressOffset;
//
// got some data. Need to marshall the result into
// the user's buffer do the easy part
//
__try
{
_MarshallCommonStats(ppfStats, pfGetip);
//
// Get the number of filters returned
//
dwFiltersReturned = pfGetip->dwNumInFilters +
pfGetip->dwNumOutFilters;
pdwAddressOffset = (PDWORD)((PBYTE)ppfStats +
_IfBaseSize() +
(sizeof(PF_FILTER_STATS) *
dwFiltersReturned));
//
// marshall each filter back to the user.
//
for(i = 0; i < dwFiltersReturned; i++)
{
_MarshallStatFilter(&pfGetip->FilterInfo[i],
&ppfStats->FilterInfo[i],
&pdwAddressOffset);
}
}
__except(GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION)
{
err = ERROR_INVALID_PARAMETER;
}
}
Cleanup:
if (pbBuffer) delete pbBuffer;
return(err);
}
VOID
PacketFilterInterface::_MarshallStatFilter(PFILTER_STATS_EX pstat,
PPF_FILTER_STATS pfstats,
PDWORD * ppdwAddress)
/*++
Routine Description:
Private method to marshall a driver supplied filter stats to
an API form of it.
--*/
{
PDWORD pdwSpace = *ppdwAddress;
pfstats->dwNumPacketsFiltered = pstat->dwNumPacketsFiltered;
pfstats->info.dwFilterFlags = 0;
pfstats->info.dwRule = pstat->info.dwFilterRule;
pfstats->info.pfatType = PF_IPV4;
pfstats->info.dwProtocol = pstat->info.info.dwProtocol;
pfstats->info.fLateBound = pstat->info.info.fLateBound;
pfstats->info.wSrcPort = pstat->info.info.wSrcPort;
pfstats->info.wDstPort = pstat->info.info.wDstPort;
pfstats->info.wSrcPortHighRange = pstat->info.info.wSrcPortHigh;
pfstats->info.wDstPortHighRange = pstat->info.info.wDstPortHigh;
pfstats->info.SrcAddr = (PBYTE)pdwSpace;
*pdwSpace++ = pstat->info.info.dwaSrcAddr[0];
pfstats->info.SrcMask = (PBYTE)pdwSpace;
*pdwSpace++ = pstat->info.info.dwaSrcMask[0];
pfstats->info.DstAddr = (PBYTE)pdwSpace;
*pdwSpace++ = pstat->info.info.dwaDstAddr[0];
pfstats->info.DstMask = (PBYTE)pdwSpace;
*pdwSpace++ = pstat->info.info.dwaDstMask[0];
*ppdwAddress = pdwSpace;
}
VOID
InitFilterApis()
{
icContainer.InitInterfaceContainer();
}
VOID
UnInitFilterApis()
{
icContainer.UnInitInterfaceContainer();
}
DWORD StartIpFilterDriver(VOID)
{
SC_HANDLE schSCManager;
SC_HANDLE schService;
DWORD dwErr = NO_ERROR;
BOOL bSuccess;
TCHAR *DriverName = TEXT("IPFILTERDRIVER");
schSCManager =
OpenSCManager(
NULL, // machine (NULL == local)
NULL, // database (NULL == default)
SC_MANAGER_ALL_ACCESS // access required
);
if (!schSCManager) {
return(GetLastError());
}
schService =
OpenService(
schSCManager,
DriverName,
SERVICE_ALL_ACCESS
);
if (!schService) {
CloseServiceHandle(schSCManager);
return(GetLastError());
}
bSuccess =
StartService(
schService,
0,
NULL
);
CloseServiceHandle(schService);
CloseServiceHandle(schSCManager);
if (!bSuccess) {
dwErr = GetLastError();
if (dwErr == ERROR_SERVICE_ALREADY_RUNNING) {
return(NO_ERROR);
}
}
return(dwErr);
}
BOOL
ValidateIndex(DWORD dwIndex)
{
DWORD i, err;
PMIB_IPADDRTABLE pTable;
err = AllocateAndGetIpAddrTableFromStack(&pTable,
FALSE,
GetProcessHeap(),
0);
if (err != NO_ERROR) {
return FALSE;
}
for (i = 0; i < pTable->dwNumEntries; i++) {
if (pTable->table[i].dwIndex == dwIndex) {
HeapFree(GetProcessHeap(),
0,
pTable);
return TRUE;
}
}
HeapFree(GetProcessHeap(),
0,
pTable);
return FALSE;
}
#endif // CHICAGO