?? filter.c
字號:
/////////////////////////////////////////////////////
// filter.c文件
// 這個文件包含了驅動程序中過濾相關的代碼 過濾部分
#include "precomp.h"
#pragma hdrstop
#include "iocommon.h"
#include "protoinfo.h"
// 過濾規則列表
typedef struct _PassthruFilterList
{
PassthruFilter filter;
struct _PassthruFilterList *pNext;
} PassthruFilterList, *PPassthruFilterList;
// ADAPT結構中FilterReserved部分
typedef struct _ADAPT_FILTER_RSVD
{
BOOLEAN bFilterInitDone;
// Per-Adapter過濾相關成員
PassthruStatistics Statistics; // 記錄網絡狀態,如傳輸了多少封包,丟棄了多少等等
PPassthruFilterList pFilterList; // 指向過濾列表
}ADAPT_FILTER_RSVD, *PADAPT_FILTER_RSVD;
C_ASSERT(sizeof(ADAPT_FILTER_RSVD) <= sizeof(((PADAPT)0)->FilterReserved));
// OPEN_CONTEXT結構中FilterReserved部分.
typedef struct _OPEN_CONTEXT_FILTER_RSVD
{
BOOLEAN bFilterInitDone;
// 更多的Per-Open-Handle過濾相關成員
}OPEN_FILTER_RSVD, *POPEN_FILTER_RSVD;
C_ASSERT(sizeof(OPEN_FILTER_RSVD) <= sizeof(((POPEN_CONTEXT)0)->FilterReserved));
VOID FltOnInitAdapter(PADAPT pAdapt)
{
PADAPT_FILTER_RSVD pFilterContext;
//
// 初始化ADAPT結構中的FilterReserved域
//
pFilterContext = (PADAPT_FILTER_RSVD )&pAdapt->FilterReserved;
}
VOID FltOnDeinitAdapter(PADAPT pAdapt)
{
PADAPT_FILTER_RSVD pFilterContext;
//
// 反初始化ADAPT結構中的FilterReserved域
//
pFilterContext = (PADAPT_FILTER_RSVD)&pAdapt->FilterReserved;
ClearFilterList(pFilterContext);
}
/////////////////////////////////////////////////////
// 向適配器過濾列表中添加一個過濾規則
NTSTATUS AddFilterToAdapter(PADAPT_FILTER_RSVD pFilterContext, PPassthruFilter pFilter)
{
PPassthruFilterList pNew;
// 為新的過濾規則申請內存空間
if(NdisAllocateMemoryWithTag(&pNew, sizeof(PassthruFilterList), TAG) != NDIS_STATUS_SUCCESS)
return STATUS_INSUFFICIENT_RESOURCES;
// 填充這塊內存
NdisMoveMemory(&pNew->filter, pFilter, sizeof(PassthruFilter));
// 連接到過濾列表中
pNew->pNext = pFilterContext->pFilterList;
pFilterContext->pFilterList = pNew;
return STATUS_SUCCESS;
}
// 刪除適配器過濾列表中的規則
void ClearFilterList(PADAPT_FILTER_RSVD pFilterContext)
{
PPassthruFilterList pList = pFilterContext->pFilterList;
PPassthruFilterList pNext;
// 釋放過濾列表占用的內存
while(pList != NULL)
{
pNext = pList->pNext;
NdisFreeMemory(pList, 0, 0);
pList = pNext;
}
pFilterContext->pFilterList = NULL;
}
// 對那些不能識別的IOCTL,PassThru從主要的DevIoControl例程調用此例程
NTSTATUS FltDevIoControl(PDEVICE_OBJECT pDeviceObject, PIRP pIrp)
{
// 假設失敗
NTSTATUS status = STATUS_INVALID_DEVICE_REQUEST;
// 取得此IRP(pIrp)的I/O堆棧指針
PIO_STACK_LOCATION pIrpStack = IoGetCurrentIrpStackLocation(pIrp);
// 取得I/O控制代碼
ULONG uIoControlCode = pIrpStack->Parameters.DeviceIoControl.IoControlCode;
// 取得I/O緩沖區指針和它的長度
PVOID pIoBuffer = pIrp->AssociatedIrp.SystemBuffer;
ULONG uInSize = pIrpStack->Parameters.DeviceIoControl.InputBufferLength;
ULONG uOutSize = pIrpStack->Parameters.DeviceIoControl.OutputBufferLength;
ULONG uTransLen = 0;
PADAPT pAdapt = NULL;
PADAPT_FILTER_RSVD pFilterContext = NULL;
POPEN_CONTEXT pOpenContext = pIrpStack->FileObject->FsContext;
if(pOpenContext == NULL || (pAdapt = pOpenContext->pAdapt) == NULL)
{
status = STATUS_INVALID_HANDLE;
goto CompleteTheIRP;
}
pFilterContext = (PADAPT_FILTER_RSVD)&pAdapt->FilterReserved;
//
// Fail IOCTL If Unbind Is In Progress Fail IOCTL If Adapter Is Powering Down
//
NdisAcquireSpinLock(&pAdapt->Lock);
if( pAdapt->UnbindingInProcess || pAdapt->StandingBy == TRUE)
{
NdisReleaseSpinLock(&pAdapt->Lock);
status = STATUS_INVALID_DEVICE_STATE;
goto CompleteTheIRP;
}
// 當改變數據時,要擁有SpinLock
// 最后,處理IO控制代碼
switch(uIoControlCode)
{
case IOCTL_PTUSERIO_QUERY_STATISTICS: // 獲取網絡活動狀態
{
uTransLen = sizeof(PassthruStatistics);
if(uOutSize < uTransLen)
{
status = STATUS_BUFFER_TOO_SMALL;
break;
}
NdisMoveMemory(pIoBuffer, &pFilterContext->Statistics, uTransLen);
status = STATUS_SUCCESS;
}
break;
case IOCTL_PTUSERIO_RESET_STATISTICS: // 重設網絡活動狀態
{
NdisZeroMemory(&pFilterContext->Statistics, sizeof(PassthruStatistics));
status = STATUS_SUCCESS;
}
break;
case IOCTL_PTUSERIO_ADD_FILTER: // 添加一個過濾規則
{
if(uInSize >= sizeof(PassthruFilter))
{
DBGPRINT((" 添加一個過濾規則"));
status = AddFilterToAdapter(pFilterContext, (PPassthruFilter)pIoBuffer);
}
else
{
status = STATUS_INVALID_DEVICE_REQUEST;
}
}
break;
case IOCTL_PTUSERIO_CLEAR_FILTER: // 清除過濾規則
{
DBGPRINT((" 清除過濾規則"));
ClearFilterList(pFilterContext);
status = STATUS_SUCCESS;
}
break;
}
NdisReleaseSpinLock(&pAdapt->Lock);
CompleteTheIRP:
if(status == STATUS_SUCCESS)
pIrp->IoStatus.Information = uTransLen;
else
pIrp->IoStatus.Information = 0;
pIrp->IoStatus.Status = status;
IoCompleteRequest(pIrp, IO_NO_INCREMENT);
return status;
}
////////////////////////////////////////////////////
// 讀取封包中的數據
void FltReadPacketData(PNDIS_PACKET pPacket,
PUCHAR lpBufferIn, ULONG nNumberToRead, PUINT lpNumberOfRead)
{
PUCHAR pBuf;
ULONG nBufferSize;
PNDIS_BUFFER pBufferDes = NULL;
// 檢查參數
if(pPacket == NULL || lpBufferIn == NULL || nNumberToRead == 0)
{
if(lpNumberOfRead != NULL)
{
*lpNumberOfRead = 0;
return ;
}
}
// 設置返回數據
*lpNumberOfRead = 0;
// 遍歷封包中的緩沖區描述表,將數據復制到用戶緩沖區
pBufferDes = pPacket->Private.Head;
while(pBufferDes != pPacket->Private.Tail && pBufferDes != NULL)
{
// 獲取此緩沖區描述表的緩沖區信息
NdisQueryBufferSafe(pBufferDes, &pBuf, &nBufferSize, NormalPagePriority);
if(pBuf == NULL)
return;
if(nNumberToRead > nBufferSize) // 復制整個緩沖區
{
NdisMoveMemory(lpBufferIn + *lpNumberOfRead, pBuf, nBufferSize);
nNumberToRead -= nBufferSize;
*lpNumberOfRead += nBufferSize;
}
else // 僅復制剩下的部分
{
NdisMoveMemory(lpBufferIn + *lpNumberOfRead, pBuf, nNumberToRead);
*lpNumberOfRead += nNumberToRead;
return;
}
// 下一個緩沖區描述表
pBufferDes = pBufferDes->Next;
}
}
/////////////////////////////////////////////
// 檢查過濾規則
BOOLEAN FltCheckFilterRules(PPassthruFilterList pFilterList, PUCHAR pPacketData, ULONG nDataLen, BOOLEAN bIncludeETHdr)
{
int nLeavingLen = nDataLen;
PETHeader pEtherHdr;
PIPHeader pIpHdr;
PTCPHeader pTcpHdr;
PUDPHeader pUdpHdr;
// 從緩沖區中萃取出IP頭
// 如果包含以太頭,就要先檢查以太頭
if(bIncludeETHdr)
{
if(nLeavingLen < sizeof(ETHeader))
{
return TRUE;
}
nLeavingLen -= sizeof(ETHeader);
pEtherHdr = (PETHeader)pPacketData;
if(pEtherHdr->type != 0x8) // 如果不是IP協議,則不處理
return TRUE;
pIpHdr = (PIPHeader)(pEtherHdr + 1);
}
else
{
pIpHdr = (PIPHeader)pPacketData;
}
// 驗證剩余數據長度,防止發生內核非法訪問
if(nLeavingLen < sizeof(IPHeader))
return TRUE;
nLeavingLen -= sizeof(IPHeader);
// 檢查版本信息,我們僅處理IPv4
if(((pIpHdr->iphVerLen >> 4) & 0x0f) == 6)
{
return TRUE;
}
if(pIpHdr->ipProtocol == 6 && nLeavingLen >= sizeof(TCPHeader)) // 是TCP協議?
{
// 提取TCP頭
pTcpHdr = (PTCPHeader)(pIpHdr + 1);
// 我們接受所有已經建立連接的TCP封包
if(!(pTcpHdr->flags & 0x02))
{
return TRUE;
}
}
// 與過濾規則比較,決定采取的行動
while(pFilterList != NULL)
{
// 查看封包使用的協議是否和過濾規則相同
if(pFilterList->filter.protocol == 0 || pFilterList->filter.protocol == pIpHdr->ipProtocol)
{
// 如果協議相同,再查看源IP地址
if(pFilterList->filter.sourceIP != 0 &&
pFilterList->filter.sourceIP != (pFilterList->filter.sourceMask & pIpHdr->ipSource))
{
pFilterList = pFilterList->pNext;
continue;
}
// 再查看目的IP地址
if(pFilterList->filter.destinationIP != 0 &&
pFilterList->filter.destinationIP != (pFilterList->filter.destinationMask & pIpHdr->ipDestination))
{
pFilterList = pFilterList->pNext;
continue;
}
// 如果是TCP封包,接著查看TCP端口號
if(pIpHdr->ipProtocol == 6)
{
if(nLeavingLen < 4)
{
return TRUE;
}
pTcpHdr = (PTCPHeader)(pIpHdr + 1);
// 如果源端口號和目的端口號都與規則中的一樣,則按照規則的記錄處理這個封包
if(pFilterList->filter.sourcePort == 0 || pFilterList->filter.sourcePort == pTcpHdr->sourcePort)
{
if(pFilterList->filter.destinationPort == 0 ||
pFilterList->filter.destinationPort == pTcpHdr->destinationPort)
{
DBGPRINT((" 按照規則處理一個TCP封包 \n "));
return !pFilterList->filter.bDrop;
}
}
}
// 如果是UDP封包,接著查看UDP端口號
else if(pIpHdr->ipProtocol == 17)
{
if(nLeavingLen < 4)
{
return !pFilterList->filter.bDrop;
}
pUdpHdr = (PUDPHeader)(pIpHdr + 1);
if(pFilterList->filter.sourcePort == 0 ||
pFilterList->filter.sourcePort == pUdpHdr->sourcePort)
{
if(pFilterList->filter.destinationPort == 0 ||
pFilterList->filter.destinationPort == pUdpHdr->destinationPort)
{
DBGPRINT((" 按照規則處理一個UDP封包 \n "));
return !pFilterList->filter.bDrop;
}
}
}
else
{
// 對于其它封包,我們直接處理
return !pFilterList->filter.bDrop;
}
}
// 比較下一個封包
pFilterList = pFilterList->pNext;
}
// 默認情況下接收所有封包
return TRUE;
}
// 過濾向外發送的數據,從MPSendPackets或者MPSend函數調用
// 如果從MPSendPackets調用就運行在IRQL <= DISPATCH_LEVEL級別
// 如果從MPSend調用,就運行在IRQL == DISPATCH_LEVEL級別
BOOLEAN FltFilterSendPacket(
IN PADAPT pAdapt,
IN PNDIS_PACKET pSendPacket,
IN BOOLEAN bDispatchLevel // TRUE -> IRQL == DISPATCH_LEVEL
)
{
BOOLEAN bPass = TRUE;
PADAPT_FILTER_RSVD pFilterContext = (PADAPT_FILTER_RSVD)&pAdapt->FilterReserved;
UCHAR buffer[MAX_PACKET_HEADER_LEN];
ULONG nReadBytes;
// 當使用過濾數據時,要獲取旋轉鎖
if(bDispatchLevel)
{
NdisDprAcquireSpinLock(&pAdapt->Lock);
}
else
{
NdisAcquireSpinLock(&pAdapt->Lock);
}
// 設置統計數字
pFilterContext->Statistics.nMPSendPktsCt ++;
// 如果沒有設置過濾規則,則放行所有封包
if(pFilterContext->pFilterList == NULL)
goto ExitTheFilter;
////////////////////////////////////////////////////
// 讀取封包中的數據,這里僅讀取封包頭即可
FltReadPacketData(pSendPacket, buffer, MAX_PACKET_HEADER_LEN, &nReadBytes);
// 檢查過濾規則,看看是否允許這個封包通過
bPass = FltCheckFilterRules(pFilterContext->pFilterList, buffer, nReadBytes, TRUE);
if(!bPass)
{
// 拒絕了一個封包
pFilterContext->Statistics.nMPSendPktsDropped ++;
}
ExitTheFilter:
// 過濾之后要釋放旋轉鎖
if(bDispatchLevel)
NdisDprReleaseSpinLock(&pAdapt->Lock);
else
NdisReleaseSpinLock(&pAdapt->Lock);
return bPass;
}
// 過濾接收到的數據,從PtReceivePacket函數調用,運行在DISPATCH_LEVEL IRQL級別
BOOLEAN FltFilterReceivePacket(
IN PADAPT pAdapt,
IN PNDIS_PACKET pReceivedPacket
)
{
BOOLEAN bPass = TRUE;
PADAPT_FILTER_RSVD pFilterContext = (PADAPT_FILTER_RSVD)&pAdapt->FilterReserved;
UCHAR buffer[MAX_PACKET_HEADER_LEN];
ULONG nReadBytes;
// 當使用過濾數據時,要獲取旋轉鎖
NdisDprAcquireSpinLock(&pAdapt->Lock);
// 設置統計數字
pFilterContext->Statistics.nPTRcvPktCt ++;
// 如果沒有設置過濾規則,則放行所有封包
if(pFilterContext->pFilterList == NULL)
goto ExitTheFilter;
////////////////////////////////////////////////////
// 讀取封包中的數據,這里僅讀取封包頭即可
FltReadPacketData(pReceivedPacket, buffer, MAX_PACKET_HEADER_LEN, &nReadBytes);
if(nReadBytes != MAX_PACKET_HEADER_LEN)
{
DBGPRINT((" FltFilterReceivePacket: nReadBytes != MAX_PACKET_HEADER_LEN"));
}
// 檢查過濾規則,看看是否允許這個封包通過
bPass = FltCheckFilterRules(pFilterContext->pFilterList,buffer, nReadBytes, TRUE);
if(!bPass)
{
// 拒絕了一個封包
pFilterContext->Statistics.nPTRcvPktDropped ++;
}
ExitTheFilter:
// 過濾之后要釋放旋轉鎖
NdisDprReleaseSpinLock(&pAdapt->Lock);
return bPass;
}
// 過濾接收到的數據,從PtReceivePacket函數調用,運行在DISPATCH_LEVEL IRQL級別
BOOLEAN FltFilterReceive(
IN PADAPT pAdapt,
IN NDIS_HANDLE MacReceiveContext,
IN PVOID HeaderBuffer,
IN UINT HeaderBufferSize,
IN PVOID LookAheadBuffer,
IN UINT LookAheadBufferSize,
IN UINT PacketSize
)
{
BOOLEAN bPass = TRUE;
PADAPT_FILTER_RSVD pFilterContext = (PADAPT_FILTER_RSVD)&pAdapt->FilterReserved;
PETHeader pEtherHdr = (PETHeader)HeaderBuffer;
// 當使用過濾數據時,要獲取旋轉鎖
NdisDprAcquireSpinLock(&pAdapt->Lock);
// 設置統計數字
pFilterContext->Statistics.nPTRcvCt ++;
// 如果沒有設置過濾規則,則放行所有封包
if(pFilterContext->pFilterList == NULL)
goto ExitTheFilter;
// 如果不是IP協議,則放行
if(pEtherHdr->type != 0x8)
goto ExitTheFilter;
// 檢查過濾規則,看看是否允許這個封包通過
bPass = FltCheckFilterRules(pFilterContext->pFilterList,LookAheadBuffer, LookAheadBufferSize, FALSE);
if(!bPass)
{
// 拒絕了一個封包
pFilterContext->Statistics.nPTRcvDropped ++;
}
ExitTheFilter:
// 過濾之后要釋放旋轉鎖
NdisDprReleaseSpinLock(&pAdapt->Lock);
return bPass;
}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -