/*++ 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