Driver: Prepare traffic statistics.

This commit is contained in:
Nodir Temirkhodjaev 2017-11-22 21:53:22 +05:00
parent 0f6c60a629
commit 809013d91c
4 changed files with 275 additions and 55 deletions

View File

@ -31,8 +31,8 @@ fort_buffer_data_new (PFORT_BUFFER buf)
if (data != NULL) {
buf->data_free = data->next;
} else {
data = ExAllocatePoolWithTag(NonPagedPool, sizeof(FORT_BUFFER_DATA),
FORT_BUFFER_POOL_TAG);
data = ExAllocatePoolWithTag(NonPagedPool,
sizeof(FORT_BUFFER_DATA), FORT_BUFFER_POOL_TAG);
}
return data;
@ -76,7 +76,6 @@ fort_buffer_data_alloc (PFORT_BUFFER buf, UINT32 len)
return data;
}
static void
fort_buffer_data_free (PFORT_BUFFER buf)
{
@ -232,3 +231,24 @@ fort_buffer_cancel_pending (PFORT_BUFFER buf, PIRP irp, ULONG_PTR *info)
return status;
}
static BOOL
fort_buffer_flush_pending (PFORT_BUFFER buf, PIRP *irp, ULONG_PTR *info)
{
UINT32 out_top;
KeAcquireSpinLockAtDpcLevel(&buf->lock);
out_top = buf->out_top;
if (out_top) {
*info = out_top;
buf->out_top = 0;
buf->out_len = 0;
*irp = buf->irp;
buf->irp = NULL;
}
KeReleaseSpinLockFromDpcLevel(&buf->lock);
return out_top != 0;
}

View File

@ -38,6 +38,7 @@ typedef struct fort_device {
UINT32 flow4_id;
FORT_BUFFER buffer;
FORT_STAT stat;
FORT_TIMER timer;
PFORT_CONF_REF volatile conf_ref;
@ -51,8 +52,8 @@ static PFORT_CONF_REF
fort_conf_ref_new (const PFORT_CONF conf, ULONG len)
{
const ULONG ref_len = len + offsetof(FORT_CONF_REF, conf);
PFORT_CONF_REF conf_ref = ExAllocatePoolWithTag(NonPagedPool, ref_len,
FORT_DEVICE_POOL_TAG);
PFORT_CONF_REF conf_ref = ExAllocatePoolWithTag(
NonPagedPool, ref_len, FORT_DEVICE_POOL_TAG);
if (conf_ref != NULL) {
conf_ref->refcount = 0;
@ -208,7 +209,7 @@ fort_callout_classify_v4 (const FWPS_INCOMING_VALUES0 *inFixedValues,
if (!blocked) {
if (ip_included && conf_flags.log_stat) {
fort_stat_flow_associate(inMetaValues->flowHandle,
fort_stat_flow_associate(&g_device->stat, inMetaValues->flowHandle,
g_device->flow4_id, (UINT32) inMetaValues->processId);
}
goto permit;
@ -289,6 +290,34 @@ fort_callout_notify (FWPS_CALLOUT_NOTIFY_TYPE notifyType,
return STATUS_SUCCESS;
}
static void
fort_callout_flow_delete_v4 (UINT16 layerId,
UINT32 calloutId,
UINT64 flowContext)
{
UNUSED(layerId);
UNUSED(calloutId);
fort_stat_flow_delete(&g_device->stat, flowContext);
}
static void
fort_callout_flow_classify_v4 (const FWPS_INCOMING_VALUES0 *inFixedValues,
const FWPS_INCOMING_METADATA_VALUES0 *inMetaValues,
FWPS_STREAM_CALLOUT_IO_PACKET0 *packet,
const FWPS_FILTER0 *filter,
UINT64 flowContext,
FWPS_CLASSIFY_OUT0 *classifyOut)
{
FWPS_STREAM_DATA0 *streamData = packet->streamData;
fort_stat_flow_classify(&g_device->stat, flowContext,
(UINT32) streamData->dataLength,
(streamData->flags & FWPS_STREAM_FLAG_RECEIVE) != 0);
classifyOut->actionType = FWP_ACTION_CONTINUE;
}
static NTSTATUS
fort_callout_install (PDEVICE_OBJECT device)
{
@ -407,6 +436,24 @@ fort_callout_force_reauth (PDEVICE_OBJECT device,
return status;
}
static void
fort_callout_timer (void)
{
// Flush traffic statistics
{
}
// Flush pending buffer
{
PIRP irp;
ULONG_PTR info;
if (fort_buffer_flush_pending(&g_device->buffer, &irp, &info)) {
fort_request_complete_info(irp, STATUS_SUCCESS, info);
}
}
}
static NTSTATUS
fort_device_create (PDEVICE_OBJECT device, PIRP irp)
{
@ -565,6 +612,7 @@ fort_driver_unload (PDRIVER_OBJECT driver)
if (g_device != NULL) {
fort_timer_close(&g_device->timer);
fort_stat_close(&g_device->stat);
fort_buffer_close(&g_device->buffer);
if (!g_device->prov_boot) {
@ -638,7 +686,8 @@ DriverEntry (PDRIVER_OBJECT driver, PUNICODE_STRING reg_path)
RtlZeroMemory(g_device, sizeof(FORT_DEVICE));
fort_buffer_init(&g_device->buffer);
fort_timer_init(&g_device->timer, &g_device->buffer);
fort_stat_init(&g_device->stat);
fort_timer_init(&g_device->timer, &fort_callout_timer);
KeInitializeSpinLock(&g_device->conf_lock);

View File

@ -1,45 +1,204 @@
/* Fort Firewall Usage Statistics */
/* Fort Firewall Traffic Statistics */
static void
fort_stat_flow_associate (UINT64 flowId,
UINT32 calloutId,
UINT32 processId)
#define FORT_STAT_POOL_TAG 'SwfF'
typedef struct fort_stat_proc {
UINT32 process_id;
UINT32 in_bytes;
UINT32 out_bytes;
int refcount;
} FORT_STAT_PROC, *PFORT_STAT_PROC;
typedef struct fort_stat {
UINT32 proc_top;
UINT32 proc_count;
int proc_free_index;
PFORT_STAT_PROC procs;
KSPIN_LOCK lock;
} FORT_STAT, *PFORT_STAT;
static int
fort_stat_proc_index (PFORT_STAT stat, UINT32 process_id)
{
NTSTATUS status;
PFORT_STAT_PROC proc = stat->procs;
const int n = stat->proc_count;
int i;
status = FwpsFlowAssociateContext0(
flowId, FWPS_LAYER_STREAM_V4, calloutId, processId);
for (i = 0; i < n; ++i, ++proc) {
if (process_id == proc->process_id)
return i;
}
DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_ERROR_LEVEL,
"FORT: flow +: %d %d\n", flowId, processId);
//STATUS_OBJECT_NAME_EXISTS
return -1;
}
static void
fort_callout_flow_delete_v4 (UINT16 layerId,
UINT32 calloutId,
UINT64 flowContext)
fort_stat_proc_inc (PFORT_STAT stat, int proc_index)
{
UNUSED(layerId);
UNUSED(calloutId);
PFORT_STAT_PROC proc = &stat->procs[proc_index];
DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_ERROR_LEVEL,
"FORT: flow -: %d\n", (UINT32) flowContext);
proc->refcount++;
}
static void
fort_callout_flow_classify_v4 (const FWPS_INCOMING_VALUES0 *inFixedValues,
const FWPS_INCOMING_METADATA_VALUES0 *inMetaValues,
FWPS_STREAM_CALLOUT_IO_PACKET0 *packet,
const FWPS_FILTER0 *filter,
UINT64 flowContext,
FWPS_CLASSIFY_OUT0 *classifyOut)
fort_stat_proc_dec (PFORT_STAT stat, int proc_index)
{
FWPS_STREAM_DATA0 *streamData = packet->streamData;
PFORT_STAT_PROC proc = &stat->procs[proc_index];
if (--proc->refcount > 0)
return;
proc->process_id = 0;
proc->refcount = stat->proc_free_index;
stat->proc_free_index = proc_index;
}
static void
fort_stat_proc_del (PFORT_STAT stat)
{
ExFreePoolWithTag(stat->procs, FORT_STAT_POOL_TAG);
}
static BOOL
fort_stat_proc_realloc (PFORT_STAT stat)
{
const UINT32 count = stat->proc_count;
const UINT32 new_count = (count ? count : 16) * 3 / 2;
PFORT_STAT_PROC new_procs = ExAllocatePoolWithTag(NonPagedPool,
new_count * sizeof(FORT_STAT_PROC), FORT_STAT_POOL_TAG);
if (new_procs == NULL)
return FALSE;
RtlCopyMemory(new_procs, stat->procs, count * sizeof(FORT_STAT_PROC));
fort_stat_proc_del(stat);
stat->proc_count = new_count;
stat->procs = new_procs;
return TRUE;
}
static int
fort_stat_proc_add (PFORT_STAT stat, UINT32 process_id)
{
PFORT_STAT_PROC proc;
int proc_index = stat->proc_free_index;
if (proc_index != -1) {
proc = &stat->procs[proc_index];
stat->proc_free_index = proc->refcount;
}
else {
if (stat->proc_top >= stat->proc_count
&& !fort_stat_proc_realloc(stat)) {
return -1;
}
proc_index = stat->proc_top++;
proc = &stat->procs[proc_index];
}
proc->process_id = process_id;
proc->in_bytes = proc->out_bytes = 0;
proc->refcount = 1;
return proc_index;
}
static void
fort_stat_init (PFORT_STAT stat)
{
stat->proc_free_index = -1;
KeInitializeSpinLock(&stat->lock);
}
static void
fort_stat_close (PFORT_STAT stat)
{
fort_stat_proc_del(stat);
}
static void
fort_stat_flow_associate (PFORT_STAT stat, UINT64 flow_id,
UINT32 callout_id, UINT32 process_id)
{
KIRQL irq;
UINT64 flow_context;
int proc_index;
KeAcquireSpinLock(&stat->lock, &irq);
proc_index = fort_stat_proc_index(stat, process_id);
if (proc_index == -1) {
proc_index = fort_stat_proc_add(stat, process_id);
if (proc_index == -1)
goto end;
}
flow_context = (UINT64) process_id | ((UINT64) proc_index << 32);
fort_stat_proc_inc(stat, proc_index);
if (!NT_SUCCESS(FwpsFlowAssociateContext0(flow_id,
FWPS_LAYER_STREAM_V4, callout_id, flow_context))) {
fort_stat_proc_dec(stat, proc_index);
}
end:
KeReleaseSpinLock(&stat->lock, irq);
DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_ERROR_LEVEL,
"FORT: flow >: %d %d %d\n", inMetaValues->flowHandle, flowContext, streamData->dataLength);
classifyOut->actionType = FWP_ACTION_CONTINUE;
"FORT: flow +: %d\n", process_id);
}
static void
fort_stat_flow_delete (PFORT_STAT stat, UINT64 flow_context)
{
KIRQL irq;
const int proc_index = (int) (flow_context >> 32);
KeAcquireSpinLock(&stat->lock, &irq);
fort_stat_proc_dec(stat, proc_index);
KeReleaseSpinLock(&stat->lock, irq);
DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_ERROR_LEVEL,
"FORT: flow -: %d\n", (UINT32) flow_context);
}
static void
fort_stat_flow_classify (PFORT_STAT stat, UINT64 flow_context,
UINT32 data_len, BOOL inbound)
{
PFORT_STAT_PROC proc;
KIRQL irq;
const UINT32 process_id = (UINT32) flow_context;
const int proc_index = (int) (flow_context >> 32);
KeAcquireSpinLock(&stat->lock, &irq);
proc = &stat->procs[proc_index];
if (inbound) {
proc->in_bytes += data_len;
} else {
proc->out_bytes += data_len;
}
KeReleaseSpinLock(&stat->lock, irq);
DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_ERROR_LEVEL,
"FORT: flow >: %d %d\n", (UINT32) flow_context, data_len);
}

View File

@ -1,43 +1,35 @@
/* Fort Firewall Timer */
typedef void (*FORT_TIMER_FUNC) (void);
typedef struct fort_timer {
UINT32 running : 1;
FORT_TIMER_FUNC callback;
KDPC dpc;
KTIMER id;
} FORT_TIMER, *PFORT_TIMER;
static void
fort_timer_callback (PKDPC dpc, PFORT_BUFFER buf, PVOID arg1, PVOID arg2)
fort_timer_callback (PKDPC dpc, PFORT_TIMER timer, PVOID arg1, PVOID arg2)
{
PIRP irp = NULL;
ULONG info;
UNUSED(dpc);
UNUSED(arg1);
UNUSED(arg2);
KeAcquireSpinLockAtDpcLevel(&buf->lock);
info = buf->out_top;
if (info) {
buf->out_top = 0;
buf->out_len = 0;
irp = buf->irp;
buf->irp = NULL;
}
KeReleaseSpinLockFromDpcLevel(&buf->lock);
if (info) {
fort_request_complete_info(irp, STATUS_SUCCESS, info);
if (timer->callback != NULL) {
timer->callback();
}
}
static void
fort_timer_init (PFORT_TIMER timer, PFORT_BUFFER buf)
fort_timer_init (PFORT_TIMER timer, FORT_TIMER_FUNC callback)
{
KeInitializeDpc(&timer->dpc, &fort_timer_callback, buf);
timer->callback = callback;
KeInitializeDpc(&timer->dpc, &fort_timer_callback, timer);
KeInitializeTimer(&timer->id);
}