The filter engine calls a callout's classifyFn callout function when there is network data to be processed by the callout. This occurs when all the filtering conditions are true for a filter that specifies the callout for the filter's action. If such a filter has no filtering conditions, the filter engine always calls the callout's classifyFn callout function.
当有一个数据包需要callout处理时,过滤引擎调用callout的classifyFn函数。这发生在过滤器指定的所有条件都为真时。如果过滤器没有过滤条件,过滤引擎会一直调用callout的classifyFn函数。
The filter engine passes several different data items to a callout's classifyFn callout function. These data items include fixed data values, metadata values, raw network data, filter information, and any flow context. The particular data items that the filter engine passes to the callout depend on the specific filtering layer and the conditions under which classifyFn is called. A classifyFn function can use any combination of these data items to make its filtering decisions.
过滤引擎传递几个不同数据项给classifyFn函数,包括固定的的数据、元数据、raw网络数据、过滤器信息和任意的上下文。具体的数据依赖具体的过滤层及classifyFn函数在什么条件下被调用。
The implementation of a callout's classifyFn callout function depends on what the callout is designed to do. The following sections provide examples of some the more typical functions of a callout:
callout的classifyFn函数的实现依赖于callout如何设计。
Using a Callout for Deep Inspection
When a callout is performing deep inspection, its classifyFn callout function can inspect any combination of the fixed data fields, the metadata fields, and any raw packet data that is passed to it, and any relevant data that has been stored in a context associated with the filter or the data flow.
如果callout被用来执行深度检测,它的classifyFn函数可以检查传递给它的任意数据,以及任意保存在与过滤器或者数据流相关的上下文中的信息。
For example:
// classifyFn callout function
VOID NTAPI
ClassifyFn(
IN const FWPS_INCOMING_VALUES0 *inFixedValues,
IN const FWPS_INCOMING_METADATA_VALUES0 *inMetaValues,
IN OUT VOID *layerData,
IN const FWPS_FILTER0 *filter,
IN UINT64 flowContext,
OUT FWPS_CLASSIFY_OUT *classifyOut
)
{
PNET_BUFFER_LIST rawData;
...
// Test for the FWPS_RIGHT_ACTION_WRITE flag to check the rights
// for this callout to return an action. If this flag is not set,
// a callout can still return a BLOCK action in order to VETO a
// PERMIT action that was returned by a previous filter. In this
// example the function just exits if the flag is not set.
if (!(classifyOut->rights & FWPS_RIGHT_ACTION_WRITE))
{
// Return without specifying an action
return;
}
// Get the data fields from inFixedValues
...
// Get any metadata fields from inMetaValues
...
// Get the pointer to the raw data
rawData = (PNET_BUFFER_LIST)layerData;
// Get any filter context data from filter->context
...
// Get any flow context data from flowContext
...
// Inspect the various data sources to determine
// the action to be taken on the data
...
// If the data should be permitted…
if (...) {
// Set the action to permit the data
classifyOut->actionType = FWP_ACTION_PERMIT;
// Check whether the FWPS_RIGHT_ACTION_WRITE flag should be cleared
if (filter->flags & FWPS_FILTER_FLAG_CLEAR_ACTION_RIGHT)
{
// Clear the FWPS_RIGHT_ACTION_WRITE flag
classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
}
return;
}
...
// If the data should be blocked...
if (...) {
// Set the action to block the data
classifyOut->actionType = FWP_ACTION_BLOCK;
// Clear the FWPS_RIGHT_ACTION_WRITE flag
classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
return;
}
...
// If the decision to permit or block should be passed
// to the next filter in the filter engine...
if (...) {
// Set the action to continue with the next filter
classifyOut->actionType = FWP_ACTION_CONTINUE;
return;
}
...
}
The value in filter->action.type determines which actions the callout's classifyFn callout function should return in the actionType member of the structure pointed to by the classifyOut parameter. For more information about these actions, see the FWPS_ACTION0 structure.
filter->action.type的值决定了classifyCout->actionType应该返回什么值。
If a callout must perform additional processing of packet data outside its classifyFn callout function before it can determine whether the data should be permitted or blocked, it must pend the packet data until the processing of the data is completed. For information about how to pend packet data, see Types of Callouts and FwpsPendOperation0.
如果callout必须在classifyFn函数外部执行其它的包数据处理,它必须挂起数据直到数据处理完成。
At some filtering layers, the layerData parameter that is passed by the filter engine to a callout's classifyFn callout function is NULL.
在某些过滤层,layerData参数为NULL。
For information about how to perform deep inspection of stream data, see Using a Callout for Deep Inspection of Stream Data.
Using a Callout for Deep Inspection of Stream Data
When a callout inspects stream data, its classifyFn callout function can inspect any combination of the fixed data fields, the metadata fields, and the raw stream data that is passed to it, and any relevant data that has been stored in a context associated with the filter or the data flow.
For example:
// classifyFn callout function
VOID NTAPI
ClassifyFn(
IN const FWPS_INCOMING_VALUES0 *inFixedValues,
IN const FWPS_INCOMING_METADATA_VALUES0 *inMetaValues,
IN OUT VOID *layerData,
IN const FWPS_FILTER0 *filter,
IN UINT64 flowContext,
OUT FWPS_CLASSIFY_OUT *classifyOut
)
{
FWPS_STREAM_CALLOUT_IO_PACKET0 *ioPacket;
FWPS_STREAM_BUFFER0 *dataStream;
UINT32 bytesRequired;
SIZE_T bytesToPermit;
SIZE_T bytesToBlock;
...
// Get a pointer to the stream callout I/O packet
ioPacket = (FWPS_STREAM_CALLOUT_IO_PACKET0 *)layerData;
// Get the data fields from inFixedValues
...
// Get any metadata fields from inMetaValues
...
// Get the pointer to the data stream
dataStream = ioPacket->dataStream;
// Get any filter context data from filter->context
...
// Get any flow context data from flowContext
...
// Inspect the various data sources to determine
// the action to be taken on the data
...
// If more stream data is required to make a determination...
if (...) {
// Let the filter engine know how many more bytes are needed
ioPacket->streamAction = FWPS_STREAM_ACTION_NEED_MORE_DATA;
ioPacket->countBytesRequired = bytesRequired;
ioPacket->countBytesEnforced = 0;
// Set the action to continue to the next filter
classifyOut->actionType = FWP_ACTION_CONTINUE;
return;
}
...
// If some or all of the data should be permitted...
if (...) {
// No stream-specific action is required
ioPacket->streamAction = FWPS_STREAM_ACTION_NONE;
// Let the filter engine know how many of the leading bytes
// in the stream should be permitted
ioPacket->countBytesRequired = 0;
ioPacket->countBytesEnforced = bytesToPermit;
// Set the action to permit the data
classifyOut->actionType = FWP_ACTION_PERMIT;
return;
}
...
// If some or all of the data should be blocked...
if (...) {
// No stream-specific action is required
ioPacket->streamAction = FWPS_STREAM_ACTION_NONE;
// Let the filter engine know how many of the leading bytes
// in the stream should be blocked
ioPacket->countBytesRequired = 0;
ioPacket->countBytesEnforced = bytesToBlock;
// Set the action to block the data
classifyOut->actionType = FWP_ACTION_BLOCK;
return;
}
...
// If the decision to permit or block should be passed
// to the next filter in the filter engine...
if (...) {
// No stream-specific action is required
ioPacket->streamAction = FWPS_STREAM_ACTION_NONE;
// No bytes are affected by this callout
ioPacket->countBytesRequired = 0;
ioPacket->countBytesEnforced = 0;
return;
}
...
}
The value in filter->action.type determines which actions the callout's classifyFn callout function should return in the actionType member of the structure pointed to by the classifyOut parameter. For more information about these actions, see the FWPS_ACTION0 structure.
For more information about packet and stream data inspection, see Inspecting Packet and Stream Data.