mirror of
https://github.com/tnodir/fort
synced 2024-11-15 13:06:36 +00:00
Driver: Extract Callouts & Device functions from fortdrv.c
This commit is contained in:
parent
034875ac62
commit
65866dedf3
@ -9,7 +9,7 @@ SOURCES += \
|
|||||||
HEADERS += \
|
HEADERS += \
|
||||||
$$PWD/common/common.h \
|
$$PWD/common/common.h \
|
||||||
$$PWD/common/fortconf.h \
|
$$PWD/common/fortconf.h \
|
||||||
$$PWD/common/fortdev.h \
|
$$PWD/common/fortdef.h \
|
||||||
$$PWD/common/fortlog.h \
|
$$PWD/common/fortlog.h \
|
||||||
$$PWD/common/fortprov.h \
|
$$PWD/common/fortprov.h \
|
||||||
$$PWD/common/wildmatch.h
|
$$PWD/common/wildmatch.h
|
||||||
|
@ -6,6 +6,8 @@ SOURCES += \
|
|||||||
dummy.c \
|
dummy.c \
|
||||||
fortbuf.c \
|
fortbuf.c \
|
||||||
fortcnf.c \
|
fortcnf.c \
|
||||||
|
fortcout.c \
|
||||||
|
fortdev.c \
|
||||||
fortdrv.c \
|
fortdrv.c \
|
||||||
fortpkt.c \
|
fortpkt.c \
|
||||||
fortstat.c \
|
fortstat.c \
|
||||||
@ -21,6 +23,8 @@ SOURCES += \
|
|||||||
HEADERS += \
|
HEADERS += \
|
||||||
fortbuf.h \
|
fortbuf.h \
|
||||||
fortcnf.h \
|
fortcnf.h \
|
||||||
|
fortcout.h \
|
||||||
|
fortdev.h \
|
||||||
fortdrv.h \
|
fortdrv.h \
|
||||||
fortpkt.h \
|
fortpkt.h \
|
||||||
fortstat.h \
|
fortstat.h \
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
#ifndef FORTDEV_H
|
#ifndef FORTDEF_H
|
||||||
#define FORTDEV_H
|
#define FORTDEF_H
|
||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
|
||||||
@ -73,6 +73,8 @@ DEFINE_GUID(FORT_GUID_FILTER_REAUTH_OUT, 0x749709ce, 0x9686, 0x4056, 0xb8, 0x9a,
|
|||||||
0xdf, 0xc8, 0x98);
|
0xdf, 0xc8, 0x98);
|
||||||
|
|
||||||
#define FORT_DEVICE_NAME "\\\\.\\fortfw"
|
#define FORT_DEVICE_NAME "\\\\.\\fortfw"
|
||||||
|
#define FORT_NT_DEVICE_NAME L"\\Device\\fortfw"
|
||||||
|
#define FORT_DOS_DEVICE_NAME L"\\DosDevices\\fortfw"
|
||||||
|
|
||||||
#define FORT_DEVICE_TYPE 0xD000
|
#define FORT_DEVICE_TYPE 0xD000
|
||||||
#define FORT_IOCTL_BASE 0xD00
|
#define FORT_IOCTL_BASE 0xD00
|
||||||
@ -88,4 +90,4 @@ DEFINE_GUID(FORT_GUID_FILTER_REAUTH_OUT, 0x749709ce, 0x9686, 0x4056, 0xb8, 0x9a,
|
|||||||
#define FORT_IOCTL_SETZONES FORT_CTL_CODE(6, FILE_WRITE_DATA)
|
#define FORT_IOCTL_SETZONES FORT_CTL_CODE(6, FILE_WRITE_DATA)
|
||||||
#define FORT_IOCTL_SETZONEFLAG FORT_CTL_CODE(7, FILE_WRITE_DATA)
|
#define FORT_IOCTL_SETZONEFLAG FORT_CTL_CODE(7, FILE_WRITE_DATA)
|
||||||
|
|
||||||
#endif // FORTDEV_H
|
#endif // FORTDEF_H
|
@ -1,6 +1,6 @@
|
|||||||
/* Fort Firewall Driver Provider (Un)Registration */
|
/* Fort Firewall Driver Provider (Un)Registration */
|
||||||
|
|
||||||
#include "fortdev.h"
|
#include "fortdef.h"
|
||||||
#include "fortprov.h"
|
#include "fortprov.h"
|
||||||
|
|
||||||
FORT_API void fort_prov_unregister(HANDLE transEngine)
|
FORT_API void fort_prov_unregister(HANDLE transEngine)
|
||||||
|
770
src/driver/fortcout.c
Normal file
770
src/driver/fortcout.c
Normal file
@ -0,0 +1,770 @@
|
|||||||
|
/* Fort Firewall Callouts */
|
||||||
|
|
||||||
|
#include "fortcout.h"
|
||||||
|
|
||||||
|
#include "common/fortdef.h"
|
||||||
|
#include "common/fortprov.h"
|
||||||
|
|
||||||
|
#include "fortdev.h"
|
||||||
|
|
||||||
|
static void fort_callout_classify_block(FWPS_CLASSIFY_OUT0 *classifyOut)
|
||||||
|
{
|
||||||
|
classifyOut->actionType = FWP_ACTION_BLOCK;
|
||||||
|
classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void fort_callout_classify_drop(FWPS_CLASSIFY_OUT0 *classifyOut)
|
||||||
|
{
|
||||||
|
classifyOut->flags |= FWPS_CLASSIFY_OUT_FLAG_ABSORB;
|
||||||
|
|
||||||
|
fort_callout_classify_block(classifyOut);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void fort_callout_classify_permit(
|
||||||
|
const FWPS_FILTER0 *filter, FWPS_CLASSIFY_OUT0 *classifyOut)
|
||||||
|
{
|
||||||
|
classifyOut->actionType = FWP_ACTION_PERMIT;
|
||||||
|
if ((filter->flags & FWPS_FILTER_FLAG_CLEAR_ACTION_RIGHT)) {
|
||||||
|
classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void fort_callout_classify_continue(FWPS_CLASSIFY_OUT0 *classifyOut)
|
||||||
|
{
|
||||||
|
classifyOut->actionType = FWP_ACTION_CONTINUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void fort_callout_classify_v4(const FWPS_INCOMING_VALUES0 *inFixedValues,
|
||||||
|
const FWPS_INCOMING_METADATA_VALUES0 *inMetaValues, const FWPS_FILTER0 *filter,
|
||||||
|
FWPS_CLASSIFY_OUT0 *classifyOut, int flagsField, int localIpField, int remoteIpField,
|
||||||
|
int localPortField, int remotePortField, int ipProtoField, BOOL inbound)
|
||||||
|
{
|
||||||
|
PIRP irp = NULL;
|
||||||
|
ULONG_PTR info;
|
||||||
|
|
||||||
|
const UINT32 flags = inFixedValues->incomingValue[flagsField].value.uint32;
|
||||||
|
const UINT32 remote_ip = inFixedValues->incomingValue[remoteIpField].value.uint32;
|
||||||
|
|
||||||
|
if (!fort_device()->conf.conf_flags.filter_locals
|
||||||
|
&& ((flags & FWP_CONDITION_FLAG_IS_LOOPBACK)
|
||||||
|
|| remote_ip == 0xFFFFFFFF)) { /* Local broadcast */
|
||||||
|
fort_callout_classify_permit(filter, classifyOut);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
PFORT_CONF_REF conf_ref = fort_conf_ref_take(&fort_device()->conf);
|
||||||
|
|
||||||
|
if (conf_ref == NULL) {
|
||||||
|
if (fort_device_flag(&fort_device()->conf, FORT_DEVICE_PROV_BOOT)) {
|
||||||
|
fort_callout_classify_block(classifyOut);
|
||||||
|
} else {
|
||||||
|
fort_callout_classify_continue(classifyOut);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const FORT_CONF_FLAGS conf_flags = conf_ref->conf.flags;
|
||||||
|
|
||||||
|
const UINT32 process_id = (UINT32) inMetaValues->processId;
|
||||||
|
const UINT32 path_len =
|
||||||
|
inMetaValues->processPath->size - sizeof(WCHAR); /* chop terminating zero */
|
||||||
|
const PVOID path = inMetaValues->processPath->data;
|
||||||
|
|
||||||
|
UCHAR block_reason = FORT_BLOCK_REASON_UNKNOWN;
|
||||||
|
BOOL blocked = TRUE;
|
||||||
|
|
||||||
|
if (conf_flags.filter_enabled) {
|
||||||
|
if (conf_flags.stop_traffic)
|
||||||
|
goto end;
|
||||||
|
|
||||||
|
if (!fort_conf_ip_is_inet(&conf_ref->conf,
|
||||||
|
(fort_conf_zones_ip_included_func *) fort_conf_zones_ip_included,
|
||||||
|
&fort_device()->conf, remote_ip)) {
|
||||||
|
blocked = FALSE; /* permit (LAN) */
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (conf_flags.stop_inet_traffic)
|
||||||
|
goto end;
|
||||||
|
|
||||||
|
if (!fort_conf_ip_inet_included(&conf_ref->conf,
|
||||||
|
(fort_conf_zones_ip_included_func *) fort_conf_zones_ip_included,
|
||||||
|
&fort_device()->conf, remote_ip)) {
|
||||||
|
block_reason = FORT_BLOCK_REASON_IP_INET;
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
blocked = FALSE; /* permit (Filter Disabled) */
|
||||||
|
if (!(conf_flags.log_stat && conf_flags.log_stat_no_filter))
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
FORT_APP_FLAGS app_flags =
|
||||||
|
fort_conf_app_find(&conf_ref->conf, path, path_len, fort_conf_exe_find);
|
||||||
|
|
||||||
|
if (!blocked /* collect traffic, when Filter Disabled */
|
||||||
|
|| (app_flags.v == 0 && conf_flags.allow_all_new) /* collect new Blocked Programs */
|
||||||
|
|| !fort_conf_app_blocked(&conf_ref->conf, app_flags, &block_reason)) {
|
||||||
|
if (conf_flags.log_stat) {
|
||||||
|
const UINT64 flow_id = inMetaValues->flowHandle;
|
||||||
|
|
||||||
|
const IPPROTO ip_proto =
|
||||||
|
(IPPROTO) inFixedValues->incomingValue[ipProtoField].value.uint8;
|
||||||
|
const BOOL is_tcp = (ip_proto == IPPROTO_TCP);
|
||||||
|
|
||||||
|
const UCHAR group_index = app_flags.group_index;
|
||||||
|
const BOOL is_reauth = (flags & FWP_CONDITION_FLAG_IS_REAUTHORIZE);
|
||||||
|
|
||||||
|
BOOL is_new_proc = FALSE;
|
||||||
|
NTSTATUS status;
|
||||||
|
|
||||||
|
status = fort_flow_associate(&fort_device()->stat, flow_id, process_id, group_index,
|
||||||
|
is_tcp, is_reauth, &is_new_proc);
|
||||||
|
|
||||||
|
if (!NT_SUCCESS(status)) {
|
||||||
|
if (status == FORT_STATUS_FLOW_BLOCK) {
|
||||||
|
block_reason = FORT_BLOCK_REASON_REAUTH;
|
||||||
|
blocked = TRUE;
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_ERROR_LEVEL,
|
||||||
|
"FORT: Classify v4: Flow assoc. error: %x\n", status);
|
||||||
|
} else if (is_new_proc) {
|
||||||
|
fort_buffer_proc_new_write(
|
||||||
|
&fort_device()->buffer, process_id, path_len, path, &irp, &info);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
blocked = FALSE; /* permit */
|
||||||
|
}
|
||||||
|
|
||||||
|
if (app_flags.v == 0 && (conf_flags.allow_all_new || conf_flags.log_blocked)
|
||||||
|
&& conf_flags.filter_enabled) {
|
||||||
|
app_flags.blocked = (UCHAR) blocked;
|
||||||
|
app_flags.alerted = 1;
|
||||||
|
app_flags.is_new = 1;
|
||||||
|
|
||||||
|
if (NT_SUCCESS(fort_conf_ref_exe_add_path(conf_ref, path, path_len, app_flags))) {
|
||||||
|
fort_buffer_blocked_write(
|
||||||
|
&fort_device()->buffer, blocked, process_id, path_len, path, &irp, &info);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
end:
|
||||||
|
if (blocked) {
|
||||||
|
/* Log the blocked connection */
|
||||||
|
if (block_reason != FORT_BLOCK_REASON_UNKNOWN && conf_flags.log_blocked_ip) {
|
||||||
|
const UINT32 local_ip = inFixedValues->incomingValue[localIpField].value.uint32;
|
||||||
|
const UINT16 local_port = inFixedValues->incomingValue[localPortField].value.uint16;
|
||||||
|
const UINT16 remote_port = inFixedValues->incomingValue[remotePortField].value.uint16;
|
||||||
|
const IPPROTO ip_proto =
|
||||||
|
(IPPROTO) inFixedValues->incomingValue[ipProtoField].value.uint8;
|
||||||
|
|
||||||
|
fort_buffer_blocked_ip_write(&fort_device()->buffer, inbound, block_reason, ip_proto,
|
||||||
|
local_port, remote_port, local_ip, remote_ip, process_id, path_len, path, &irp,
|
||||||
|
&info);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Block the connection */
|
||||||
|
fort_callout_classify_block(classifyOut);
|
||||||
|
} else {
|
||||||
|
/* Allow the connection */
|
||||||
|
fort_callout_classify_permit(filter, classifyOut);
|
||||||
|
}
|
||||||
|
|
||||||
|
fort_conf_ref_put(&fort_device()->conf, conf_ref);
|
||||||
|
|
||||||
|
if (irp != NULL) {
|
||||||
|
fort_request_complete_info(irp, STATUS_SUCCESS, info);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void NTAPI fort_callout_connect_v4(const FWPS_INCOMING_VALUES0 *inFixedValues,
|
||||||
|
const FWPS_INCOMING_METADATA_VALUES0 *inMetaValues, void *layerData,
|
||||||
|
const FWPS_FILTER0 *filter, const UINT64 flowContext, FWPS_CLASSIFY_OUT0 *classifyOut)
|
||||||
|
{
|
||||||
|
UNUSED(layerData);
|
||||||
|
UNUSED(flowContext);
|
||||||
|
|
||||||
|
fort_callout_classify_v4(inFixedValues, inMetaValues, filter, classifyOut,
|
||||||
|
FWPS_FIELD_ALE_AUTH_CONNECT_V4_FLAGS, FWPS_FIELD_ALE_AUTH_CONNECT_V4_IP_LOCAL_ADDRESS,
|
||||||
|
FWPS_FIELD_ALE_AUTH_CONNECT_V4_IP_REMOTE_ADDRESS,
|
||||||
|
FWPS_FIELD_ALE_AUTH_CONNECT_V4_IP_LOCAL_PORT,
|
||||||
|
FWPS_FIELD_ALE_AUTH_CONNECT_V4_IP_REMOTE_PORT,
|
||||||
|
FWPS_FIELD_ALE_AUTH_CONNECT_V4_IP_PROTOCOL, FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void NTAPI fort_callout_accept_v4(const FWPS_INCOMING_VALUES0 *inFixedValues,
|
||||||
|
const FWPS_INCOMING_METADATA_VALUES0 *inMetaValues, void *layerData,
|
||||||
|
const FWPS_FILTER0 *filter, const UINT64 flowContext, FWPS_CLASSIFY_OUT0 *classifyOut)
|
||||||
|
{
|
||||||
|
UNUSED(layerData);
|
||||||
|
UNUSED(flowContext);
|
||||||
|
|
||||||
|
fort_callout_classify_v4(inFixedValues, inMetaValues, filter, classifyOut,
|
||||||
|
FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V4_FLAGS,
|
||||||
|
FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V4_IP_LOCAL_ADDRESS,
|
||||||
|
FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V4_IP_REMOTE_ADDRESS,
|
||||||
|
FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V4_IP_LOCAL_PORT,
|
||||||
|
FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V4_IP_REMOTE_PORT,
|
||||||
|
FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V4_IP_PROTOCOL, TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static NTSTATUS NTAPI fort_callout_notify(
|
||||||
|
FWPS_CALLOUT_NOTIFY_TYPE notifyType, const GUID *filterKey, const FWPS_FILTER0 *filter)
|
||||||
|
{
|
||||||
|
UNUSED(notifyType);
|
||||||
|
UNUSED(filterKey);
|
||||||
|
UNUSED(filter);
|
||||||
|
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void NTAPI fort_packet_inject_complete(
|
||||||
|
PFORT_PACKET pkt, PNET_BUFFER_LIST clonedNetBufList, BOOLEAN dispatchLevel)
|
||||||
|
{
|
||||||
|
fort_defer_packet_free(&fort_device()->defer, pkt, clonedNetBufList, dispatchLevel);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void fort_callout_defer_packet_flush(UINT32 list_bits, BOOL dispatchLevel)
|
||||||
|
{
|
||||||
|
fort_defer_packet_flush(
|
||||||
|
&fort_device()->defer, fort_packet_inject_complete, list_bits, dispatchLevel);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void fort_callout_defer_stream_flush(UINT64 flow_id, BOOL dispatchLevel)
|
||||||
|
{
|
||||||
|
UNUSED(dispatchLevel);
|
||||||
|
|
||||||
|
fort_defer_stream_flush(&fort_device()->defer, fort_packet_inject_complete, flow_id, FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
FORT_API void fort_callout_defer_flush(void)
|
||||||
|
{
|
||||||
|
fort_callout_defer_packet_flush(FORT_DEFER_FLUSH_ALL, FALSE);
|
||||||
|
fort_callout_defer_stream_flush(FORT_DEFER_STREAM_ALL, FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void fort_callout_flow_classify_v4(const FWPS_INCOMING_METADATA_VALUES0 *inMetaValues,
|
||||||
|
UINT64 flowContext, FWPS_CLASSIFY_OUT0 *classifyOut, UINT32 dataSize, BOOL is_tcp,
|
||||||
|
BOOL inbound)
|
||||||
|
{
|
||||||
|
const UINT32 headerSize = inbound ? inMetaValues->transportHeaderSize : 0;
|
||||||
|
|
||||||
|
UNUSED(classifyOut);
|
||||||
|
|
||||||
|
fort_flow_classify(&fort_device()->stat, flowContext, headerSize + dataSize, is_tcp, inbound);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void NTAPI fort_callout_stream_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)
|
||||||
|
{
|
||||||
|
const FWPS_STREAM_DATA0 *streamData = packet->streamData;
|
||||||
|
const UINT32 streamFlags = streamData->flags;
|
||||||
|
const UINT32 dataSize = (UINT32) streamData->dataLength;
|
||||||
|
|
||||||
|
const BOOL inbound = (streamFlags & FWPS_STREAM_FLAG_RECEIVE) != 0;
|
||||||
|
|
||||||
|
UNUSED(inFixedValues);
|
||||||
|
|
||||||
|
fort_callout_flow_classify_v4(inMetaValues, flowContext, classifyOut, dataSize, TRUE, inbound);
|
||||||
|
|
||||||
|
/* Flush flow's deferred TCP packets on FIN */
|
||||||
|
#if 0
|
||||||
|
if (streamFlags & (FWPS_STREAM_FLAG_RECEIVE_DISCONNECT
|
||||||
|
| FWPS_STREAM_FLAG_SEND_DISCONNECT)) {
|
||||||
|
PFORT_FLOW flow = (PFORT_FLOW) flowContext;
|
||||||
|
|
||||||
|
const UCHAR flow_flags = fort_flow_flags(flow);
|
||||||
|
|
||||||
|
if (flow_flags & FORT_FLOW_SPEED_LIMIT) {
|
||||||
|
fort_callout_defer_packet_flush(flow->flow_id, FORT_DEFER_FLUSH_ALL, FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (flow_flags & FORT_FLOW_FRAGMENT) {
|
||||||
|
fort_callout_defer_stream_flush(flow->flow_id, FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
goto permit;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Fragment first TCP packet */
|
||||||
|
if ((streamFlags
|
||||||
|
& (FWPS_STREAM_FLAG_SEND | FWPS_STREAM_FLAG_SEND_EXPEDITED
|
||||||
|
| FWPS_STREAM_FLAG_SEND_DISCONNECT))
|
||||||
|
== FWPS_STREAM_FLAG_SEND) {
|
||||||
|
PFORT_FLOW flow = (PFORT_FLOW) flowContext;
|
||||||
|
|
||||||
|
const UCHAR flow_flags = fort_flow_flags(flow);
|
||||||
|
|
||||||
|
const UCHAR fragment_flags = (flow_flags
|
||||||
|
& (FORT_FLOW_FRAGMENT | FORT_FLOW_FRAGMENT_DEFER | FORT_FLOW_FRAGMENTED));
|
||||||
|
|
||||||
|
if (fragment_flags != 0 && !(fragment_flags & FORT_FLOW_FRAGMENTED)) {
|
||||||
|
const UCHAR fragment_size = 3;
|
||||||
|
|
||||||
|
if (fragment_flags & FORT_FLOW_FRAGMENT_DEFER) {
|
||||||
|
const NTSTATUS status = fort_defer_stream_add(&fort_device()->defer, inFixedValues,
|
||||||
|
inMetaValues, streamData, filter, inbound);
|
||||||
|
|
||||||
|
if (NT_SUCCESS(status))
|
||||||
|
goto drop;
|
||||||
|
|
||||||
|
fort_flow_flags_set(flow, FORT_FLOW_FRAGMENTED, TRUE);
|
||||||
|
} else if (dataSize > fragment_size) {
|
||||||
|
packet->countBytesEnforced = fragment_size;
|
||||||
|
|
||||||
|
fort_flow_flags_set(flow, FORT_FLOW_FRAGMENT_DEFER, TRUE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* permit: */
|
||||||
|
fort_callout_classify_permit(filter, classifyOut);
|
||||||
|
return;
|
||||||
|
|
||||||
|
drop:
|
||||||
|
fort_callout_classify_drop(classifyOut);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void NTAPI fort_callout_datagram_classify_v4(const FWPS_INCOMING_VALUES0 *inFixedValues,
|
||||||
|
const FWPS_INCOMING_METADATA_VALUES0 *inMetaValues, const PNET_BUFFER_LIST netBufList,
|
||||||
|
const FWPS_FILTER0 *filter, UINT64 flowContext, FWPS_CLASSIFY_OUT0 *classifyOut)
|
||||||
|
{
|
||||||
|
const PNET_BUFFER netBuf = NET_BUFFER_LIST_FIRST_NB(netBufList);
|
||||||
|
const UINT32 dataSize = NET_BUFFER_DATA_LENGTH(netBuf);
|
||||||
|
|
||||||
|
const FWP_DIRECTION direction =
|
||||||
|
(FWP_DIRECTION) inFixedValues->incomingValue[FWPS_FIELD_DATAGRAM_DATA_V4_DIRECTION]
|
||||||
|
.value.uint8;
|
||||||
|
const BOOL inbound = (direction == FWP_DIRECTION_INBOUND);
|
||||||
|
|
||||||
|
fort_callout_flow_classify_v4(inMetaValues, flowContext, classifyOut, dataSize, FALSE, inbound);
|
||||||
|
|
||||||
|
fort_callout_classify_permit(filter, classifyOut);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void NTAPI fort_callout_flow_delete_v4(UINT16 layerId, UINT32 calloutId, UINT64 flowContext)
|
||||||
|
{
|
||||||
|
UNUSED(layerId);
|
||||||
|
UNUSED(calloutId);
|
||||||
|
|
||||||
|
fort_flow_delete(&fort_device()->stat, flowContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void NTAPI fort_callout_transport_classify_v4(const FWPS_INCOMING_VALUES0 *inFixedValues,
|
||||||
|
const FWPS_INCOMING_METADATA_VALUES0 *inMetaValues, PNET_BUFFER_LIST netBufList,
|
||||||
|
const FWPS_FILTER0 *filter, UINT64 flowContext, FWPS_CLASSIFY_OUT0 *classifyOut,
|
||||||
|
BOOL inbound)
|
||||||
|
{
|
||||||
|
PNET_BUFFER netBuf;
|
||||||
|
|
||||||
|
if (!FWPS_IS_METADATA_FIELD_PRESENT(inMetaValues, FWPS_METADATA_FIELD_ALE_CLASSIFY_REQUIRED)
|
||||||
|
&& netBufList != NULL && (netBuf = NET_BUFFER_LIST_FIRST_NB(netBufList)) != NULL) {
|
||||||
|
PFORT_FLOW flow = (PFORT_FLOW) flowContext;
|
||||||
|
|
||||||
|
const UCHAR flow_flags = fort_flow_flags(flow);
|
||||||
|
|
||||||
|
const UCHAR defer_flag = inbound ? FORT_FLOW_DEFER_IN : FORT_FLOW_DEFER_OUT;
|
||||||
|
const UCHAR speed_limit = inbound ? FORT_FLOW_SPEED_LIMIT_OUT : FORT_FLOW_SPEED_LIMIT_IN;
|
||||||
|
|
||||||
|
const UCHAR speed_defer_flags = speed_limit | defer_flag;
|
||||||
|
const BOOL defer_flow = (flow_flags & speed_defer_flags) == speed_defer_flags
|
||||||
|
&& !fort_device_flag(&fort_device()->conf, FORT_DEVICE_POWER_OFF);
|
||||||
|
|
||||||
|
const BOOL fragment_packet = !inbound
|
||||||
|
&& (flow_flags & (FORT_FLOW_FRAGMENT_DEFER | FORT_FLOW_FRAGMENTED))
|
||||||
|
== FORT_FLOW_FRAGMENT_DEFER;
|
||||||
|
|
||||||
|
/* Position in the packet data:
|
||||||
|
* FWPS_LAYER_INBOUND_TRANSPORT_V4: The beginning of the data.
|
||||||
|
* FWPS_LAYER_OUTBOUND_TRANSPORT_V4: The beginning of the transport header.
|
||||||
|
*/
|
||||||
|
const UINT32 headerOffset = inbound ? 0 : sizeof(TCP_HEADER);
|
||||||
|
|
||||||
|
/* Ignore TCP RST-packets */
|
||||||
|
#if 0
|
||||||
|
const BOOL ignore_tcp_rst = inbound && fort_device()->conf_flags.ignore_tcp_rst;
|
||||||
|
|
||||||
|
if (ignore_tcp_rst) {
|
||||||
|
TCP_HEADER buf;
|
||||||
|
PTCP_HEADER tcpHeader;
|
||||||
|
UINT32 tcpFlags;
|
||||||
|
|
||||||
|
if (headerOffset != 0) {
|
||||||
|
NdisRetreatNetBufferDataStart(netBuf, headerOffset, 0, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
tcpHeader = NdisGetDataBuffer(netBuf, sizeof(TCP_HEADER), &buf, 1, 0);
|
||||||
|
tcpFlags = tcpHeader ? tcpHeader->flags : 0;
|
||||||
|
|
||||||
|
if (headerOffset != 0) {
|
||||||
|
NdisAdvanceNetBufferDataStart(netBuf, headerOffset, FALSE, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tcpHeader == NULL)
|
||||||
|
goto permit;
|
||||||
|
|
||||||
|
if (tcpFlags & TCP_FLAG_RST)
|
||||||
|
goto block;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Defer TCP Pure (zero length) ACK-packets */
|
||||||
|
if (defer_flow && NET_BUFFER_DATA_LENGTH(netBuf) == headerOffset) {
|
||||||
|
const NTSTATUS status = fort_defer_packet_add(&fort_device()->defer, inFixedValues,
|
||||||
|
inMetaValues, netBufList, inbound, flow->opt.group_index);
|
||||||
|
|
||||||
|
if (NT_SUCCESS(status))
|
||||||
|
goto drop;
|
||||||
|
|
||||||
|
if (status == STATUS_CANT_TERMINATE_SELF) {
|
||||||
|
/* Clear ACK deferring */
|
||||||
|
fort_flow_flags_set(flow, defer_flag, FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
goto permit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Fragment first TCP packet */
|
||||||
|
if (fragment_packet) {
|
||||||
|
fort_defer_stream_flush(
|
||||||
|
&fort_device()->defer, fort_packet_inject_complete, flow->flow_id, FALSE);
|
||||||
|
|
||||||
|
fort_flow_flags_set(flow, FORT_FLOW_FRAGMENTED, TRUE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
permit:
|
||||||
|
fort_callout_classify_permit(filter, classifyOut);
|
||||||
|
return;
|
||||||
|
|
||||||
|
drop:
|
||||||
|
fort_callout_classify_drop(classifyOut);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void NTAPI fort_callout_in_transport_classify_v4(const FWPS_INCOMING_VALUES0 *inFixedValues,
|
||||||
|
const FWPS_INCOMING_METADATA_VALUES0 *inMetaValues, const PNET_BUFFER_LIST netBufList,
|
||||||
|
const FWPS_FILTER0 *filter, UINT64 flowContext, FWPS_CLASSIFY_OUT0 *classifyOut)
|
||||||
|
{
|
||||||
|
fort_callout_transport_classify_v4(
|
||||||
|
inFixedValues, inMetaValues, netBufList, filter, flowContext, classifyOut, TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void NTAPI fort_callout_out_transport_classify_v4(const FWPS_INCOMING_VALUES0 *inFixedValues,
|
||||||
|
const FWPS_INCOMING_METADATA_VALUES0 *inMetaValues, const PNET_BUFFER_LIST netBufList,
|
||||||
|
const FWPS_FILTER0 *filter, UINT64 flowContext, FWPS_CLASSIFY_OUT0 *classifyOut)
|
||||||
|
{
|
||||||
|
fort_callout_transport_classify_v4(
|
||||||
|
inFixedValues, inMetaValues, netBufList, filter, flowContext, classifyOut, FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void NTAPI fort_callout_delete_v4(UINT16 layerId, UINT32 calloutId, UINT64 flowContext)
|
||||||
|
{
|
||||||
|
UNUSED(layerId);
|
||||||
|
UNUSED(calloutId);
|
||||||
|
UNUSED(flowContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
FORT_API NTSTATUS fort_callout_install(PDEVICE_OBJECT device)
|
||||||
|
{
|
||||||
|
FWPS_CALLOUT0 c;
|
||||||
|
NTSTATUS status;
|
||||||
|
|
||||||
|
RtlZeroMemory(&c, sizeof(FWPS_CALLOUT0));
|
||||||
|
|
||||||
|
c.notifyFn = (FWPS_CALLOUT_NOTIFY_FN0) fort_callout_notify;
|
||||||
|
|
||||||
|
/* IPv4 connect callout */
|
||||||
|
c.calloutKey = FORT_GUID_CALLOUT_CONNECT_V4;
|
||||||
|
c.classifyFn = (FWPS_CALLOUT_CLASSIFY_FN0) fort_callout_connect_v4;
|
||||||
|
|
||||||
|
status = FwpsCalloutRegister0(device, &c, &fort_device()->connect4_id);
|
||||||
|
if (!NT_SUCCESS(status)) {
|
||||||
|
DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_ERROR_LEVEL,
|
||||||
|
"FORT: Register Connect V4: Error: %x\n", status);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* IPv4 accept callout */
|
||||||
|
c.calloutKey = FORT_GUID_CALLOUT_ACCEPT_V4;
|
||||||
|
c.classifyFn = (FWPS_CALLOUT_CLASSIFY_FN0) fort_callout_accept_v4;
|
||||||
|
|
||||||
|
status = FwpsCalloutRegister0(device, &c, &fort_device()->accept4_id);
|
||||||
|
if (!NT_SUCCESS(status)) {
|
||||||
|
DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_ERROR_LEVEL,
|
||||||
|
"FORT: Register Accept V4: Error: %x\n", status);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* IPv4 stream callout */
|
||||||
|
c.calloutKey = FORT_GUID_CALLOUT_STREAM_V4;
|
||||||
|
c.classifyFn = (FWPS_CALLOUT_CLASSIFY_FN0) fort_callout_stream_classify_v4;
|
||||||
|
|
||||||
|
c.flowDeleteFn = fort_callout_flow_delete_v4;
|
||||||
|
c.flags = FWP_CALLOUT_FLAG_CONDITIONAL_ON_FLOW;
|
||||||
|
|
||||||
|
status = FwpsCalloutRegister0(device, &c, &fort_device()->stat.stream4_id);
|
||||||
|
if (!NT_SUCCESS(status)) {
|
||||||
|
DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_ERROR_LEVEL,
|
||||||
|
"FORT: Register Stream V4: Error: %x\n", status);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* IPv4 datagram callout */
|
||||||
|
c.calloutKey = FORT_GUID_CALLOUT_DATAGRAM_V4;
|
||||||
|
c.classifyFn = (FWPS_CALLOUT_CLASSIFY_FN0) fort_callout_datagram_classify_v4;
|
||||||
|
|
||||||
|
/* reuse c.flowDeleteFn & c.flags */
|
||||||
|
|
||||||
|
status = FwpsCalloutRegister0(device, &c, &fort_device()->stat.datagram4_id);
|
||||||
|
if (!NT_SUCCESS(status)) {
|
||||||
|
DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_ERROR_LEVEL,
|
||||||
|
"FORT: Register Datagram V4: Error: %x\n", status);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* IPv4 inbound transport callout */
|
||||||
|
c.calloutKey = FORT_GUID_CALLOUT_IN_TRANSPORT_V4;
|
||||||
|
c.classifyFn = (FWPS_CALLOUT_CLASSIFY_FN0) fort_callout_in_transport_classify_v4;
|
||||||
|
|
||||||
|
c.flowDeleteFn = fort_callout_delete_v4;
|
||||||
|
/* reuse c.flags */
|
||||||
|
|
||||||
|
status = FwpsCalloutRegister0(device, &c, &fort_device()->stat.in_transport4_id);
|
||||||
|
if (!NT_SUCCESS(status)) {
|
||||||
|
DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_ERROR_LEVEL,
|
||||||
|
"FORT: Register Inbound Transport V4: Error: %x\n", status);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* IPv4 outbound transport callout */
|
||||||
|
c.calloutKey = FORT_GUID_CALLOUT_OUT_TRANSPORT_V4;
|
||||||
|
c.classifyFn = (FWPS_CALLOUT_CLASSIFY_FN0) fort_callout_out_transport_classify_v4;
|
||||||
|
|
||||||
|
/* reuse c.flowDeleteFn & c.flags */
|
||||||
|
|
||||||
|
status = FwpsCalloutRegister0(device, &c, &fort_device()->stat.out_transport4_id);
|
||||||
|
if (!NT_SUCCESS(status)) {
|
||||||
|
DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_ERROR_LEVEL,
|
||||||
|
"FORT: Register Outbound Transport V4: Error: %x\n", status);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
FORT_API void fort_callout_remove(void)
|
||||||
|
{
|
||||||
|
if (fort_device()->connect4_id) {
|
||||||
|
FwpsCalloutUnregisterById0(fort_device()->connect4_id);
|
||||||
|
fort_device()->connect4_id = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fort_device()->accept4_id) {
|
||||||
|
FwpsCalloutUnregisterById0(fort_device()->accept4_id);
|
||||||
|
fort_device()->accept4_id = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fort_device()->stat.stream4_id) {
|
||||||
|
FwpsCalloutUnregisterById0(fort_device()->stat.stream4_id);
|
||||||
|
fort_device()->stat.stream4_id = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fort_device()->stat.datagram4_id) {
|
||||||
|
FwpsCalloutUnregisterById0(fort_device()->stat.datagram4_id);
|
||||||
|
fort_device()->stat.datagram4_id = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fort_device()->stat.in_transport4_id) {
|
||||||
|
FwpsCalloutUnregisterById0(fort_device()->stat.in_transport4_id);
|
||||||
|
fort_device()->stat.in_transport4_id = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fort_device()->stat.out_transport4_id) {
|
||||||
|
FwpsCalloutUnregisterById0(fort_device()->stat.out_transport4_id);
|
||||||
|
fort_device()->stat.out_transport4_id = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FORT_API NTSTATUS fort_callout_force_reauth(
|
||||||
|
const FORT_CONF_FLAGS old_conf_flags, UINT32 defer_flush_bits)
|
||||||
|
{
|
||||||
|
PFORT_STAT stat = &fort_device()->stat;
|
||||||
|
NTSTATUS status;
|
||||||
|
|
||||||
|
fort_timer_update(&fort_device()->log_timer, FALSE);
|
||||||
|
|
||||||
|
/* Check app group periods & update group_bits */
|
||||||
|
{
|
||||||
|
int periods_n = 0;
|
||||||
|
|
||||||
|
fort_conf_ref_period_update(&fort_device()->conf, TRUE, &periods_n);
|
||||||
|
|
||||||
|
fort_timer_update(&fort_device()->app_timer, (periods_n != 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
const FORT_CONF_FLAGS conf_flags = fort_device()->conf.conf_flags;
|
||||||
|
|
||||||
|
/* Handle log_stat */
|
||||||
|
if (old_conf_flags.log_stat != conf_flags.log_stat) {
|
||||||
|
fort_stat_update(stat, conf_flags.log_stat);
|
||||||
|
|
||||||
|
if (!conf_flags.log_stat) {
|
||||||
|
defer_flush_bits = FORT_DEFER_FLUSH_ALL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (defer_flush_bits != 0) {
|
||||||
|
fort_callout_defer_packet_flush(defer_flush_bits, FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Open provider */
|
||||||
|
HANDLE engine;
|
||||||
|
if ((status = fort_prov_open(&engine)))
|
||||||
|
goto end;
|
||||||
|
|
||||||
|
fort_prov_trans_begin(engine);
|
||||||
|
|
||||||
|
/* Check provider filters */
|
||||||
|
BOOL prov_recreated = FALSE;
|
||||||
|
if (old_conf_flags.prov_boot != conf_flags.prov_boot) {
|
||||||
|
fort_prov_unregister(engine);
|
||||||
|
|
||||||
|
if ((status = fort_prov_register(engine, conf_flags.prov_boot)))
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
prov_recreated = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check flow filter */
|
||||||
|
{
|
||||||
|
const PFORT_CONF_GROUP conf_group = &stat->conf_group;
|
||||||
|
const UINT16 filter_bits = (conf_group->fragment_bits | conf_group->limit_bits);
|
||||||
|
|
||||||
|
const BOOL old_filter_transport =
|
||||||
|
fort_device_flag(&fort_device()->conf, FORT_DEVICE_FILTER_TRANSPORT) != 0;
|
||||||
|
const BOOL filter_transport = (conf_flags.group_bits & filter_bits) != 0;
|
||||||
|
|
||||||
|
if (prov_recreated || old_conf_flags.log_stat != conf_flags.log_stat
|
||||||
|
|| old_filter_transport != filter_transport) {
|
||||||
|
fort_device_flag_set(
|
||||||
|
&fort_device()->conf, FORT_DEVICE_FILTER_TRANSPORT, filter_transport);
|
||||||
|
|
||||||
|
fort_prov_flow_unregister(engine);
|
||||||
|
|
||||||
|
if (conf_flags.log_stat) {
|
||||||
|
if ((status = fort_prov_flow_register(engine, filter_transport)))
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Force reauth filter */
|
||||||
|
if ((status = fort_prov_reauth(engine)))
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
fort_timer_update(&fort_device()->log_timer,
|
||||||
|
(conf_flags.allow_all_new || conf_flags.log_blocked || conf_flags.log_stat
|
||||||
|
|| conf_flags.log_blocked_ip));
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
if (NT_SUCCESS(status)) {
|
||||||
|
status = fort_prov_trans_commit(engine);
|
||||||
|
} else {
|
||||||
|
fort_prov_trans_abort(engine);
|
||||||
|
}
|
||||||
|
|
||||||
|
fort_prov_close(engine);
|
||||||
|
|
||||||
|
end:
|
||||||
|
if (!NT_SUCCESS(status)) {
|
||||||
|
DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_ERROR_LEVEL, "FORT: Callout Reauth: Error: %x\n",
|
||||||
|
status);
|
||||||
|
}
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
FORT_API void fort_callout_timer(void)
|
||||||
|
{
|
||||||
|
PFORT_BUFFER buf = &fort_device()->buffer;
|
||||||
|
PFORT_STAT stat = &fort_device()->stat;
|
||||||
|
|
||||||
|
KLOCK_QUEUE_HANDLE buf_lock_queue;
|
||||||
|
KLOCK_QUEUE_HANDLE stat_lock_queue;
|
||||||
|
|
||||||
|
PIRP irp = NULL;
|
||||||
|
ULONG_PTR info;
|
||||||
|
|
||||||
|
/* Lock buffer */
|
||||||
|
fort_buffer_dpc_begin(buf, &buf_lock_queue);
|
||||||
|
|
||||||
|
/* Lock stat */
|
||||||
|
fort_stat_dpc_begin(stat, &stat_lock_queue);
|
||||||
|
|
||||||
|
/* Get current Unix time */
|
||||||
|
{
|
||||||
|
LARGE_INTEGER system_time;
|
||||||
|
PCHAR out;
|
||||||
|
|
||||||
|
KeQuerySystemTime(&system_time);
|
||||||
|
|
||||||
|
if (stat->system_time.QuadPart != system_time.QuadPart
|
||||||
|
&& NT_SUCCESS(fort_buffer_prepare(buf, FORT_LOG_TIME_SIZE, &out, &irp, &info))) {
|
||||||
|
const INT64 unix_time = fort_system_to_unix_time(system_time.QuadPart);
|
||||||
|
|
||||||
|
stat->system_time = system_time;
|
||||||
|
|
||||||
|
fort_log_time_write(out, unix_time);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Flush traffic statistics */
|
||||||
|
while (stat->proc_active_count != 0) {
|
||||||
|
const UINT16 proc_count = (stat->proc_active_count < FORT_LOG_STAT_BUFFER_PROC_COUNT)
|
||||||
|
? stat->proc_active_count
|
||||||
|
: FORT_LOG_STAT_BUFFER_PROC_COUNT;
|
||||||
|
const UINT32 len = FORT_LOG_STAT_SIZE(proc_count);
|
||||||
|
PCHAR out;
|
||||||
|
NTSTATUS status;
|
||||||
|
|
||||||
|
status = fort_buffer_prepare(buf, len, &out, &irp, &info);
|
||||||
|
if (!NT_SUCCESS(status)) {
|
||||||
|
DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_ERROR_LEVEL, "FORT: Callout Timer: Error: %x\n",
|
||||||
|
status);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
fort_log_stat_traf_header_write(out, proc_count);
|
||||||
|
out += FORT_LOG_STAT_HEADER_SIZE;
|
||||||
|
|
||||||
|
fort_stat_dpc_traf_flush(stat, proc_count, out);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Flush process group statistics */
|
||||||
|
const UINT32 defer_flush_bits = fort_stat_dpc_group_flush(stat);
|
||||||
|
|
||||||
|
/* Unlock stat */
|
||||||
|
fort_stat_dpc_end(&stat_lock_queue);
|
||||||
|
|
||||||
|
/* Flush pending buffer */
|
||||||
|
if (irp == NULL) {
|
||||||
|
fort_buffer_dpc_flush_pending(buf, &irp, &info);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Unlock buffer */
|
||||||
|
fort_buffer_dpc_end(&buf_lock_queue);
|
||||||
|
|
||||||
|
if (irp != NULL) {
|
||||||
|
fort_request_complete_info(irp, STATUS_SUCCESS, info);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Flush deferred packets */
|
||||||
|
fort_callout_defer_packet_flush(defer_flush_bits, TRUE);
|
||||||
|
}
|
27
src/driver/fortcout.h
Normal file
27
src/driver/fortcout.h
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
#ifndef FORTCOUT_H
|
||||||
|
#define FORTCOUT_H
|
||||||
|
|
||||||
|
#include "fortdrv.h"
|
||||||
|
|
||||||
|
#include "common/fortconf.h"
|
||||||
|
|
||||||
|
#if defined(__cplusplus)
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
FORT_API void fort_callout_defer_flush(void);
|
||||||
|
|
||||||
|
FORT_API NTSTATUS fort_callout_install(PDEVICE_OBJECT device);
|
||||||
|
|
||||||
|
FORT_API void fort_callout_remove(void);
|
||||||
|
|
||||||
|
FORT_API NTSTATUS fort_callout_force_reauth(
|
||||||
|
const FORT_CONF_FLAGS old_conf_flags, UINT32 defer_flush_bits);
|
||||||
|
|
||||||
|
FORT_API void fort_callout_timer(void);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
} // extern "C"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // FORTCOUT_H
|
276
src/driver/fortdev.c
Normal file
276
src/driver/fortdev.c
Normal file
@ -0,0 +1,276 @@
|
|||||||
|
/* Fort Firewall Driver Device */
|
||||||
|
|
||||||
|
#include "../version/fort_version.h"
|
||||||
|
|
||||||
|
#include "fortdev.h"
|
||||||
|
|
||||||
|
#include "common/fortdef.h"
|
||||||
|
|
||||||
|
#include "fortcout.h"
|
||||||
|
|
||||||
|
static PFORT_DEVICE g_device = NULL;
|
||||||
|
|
||||||
|
FORT_API PFORT_DEVICE fort_device()
|
||||||
|
{
|
||||||
|
return g_device;
|
||||||
|
}
|
||||||
|
|
||||||
|
FORT_API void fort_device_set(PFORT_DEVICE device)
|
||||||
|
{
|
||||||
|
g_device = device;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void fort_worker_reauth(void)
|
||||||
|
{
|
||||||
|
const FORT_CONF_FLAGS conf_flags = g_device->conf.conf_flags;
|
||||||
|
NTSTATUS status;
|
||||||
|
|
||||||
|
status = fort_callout_force_reauth(conf_flags, 0);
|
||||||
|
|
||||||
|
if (!NT_SUCCESS(status)) {
|
||||||
|
DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_ERROR_LEVEL, "FORT: Worker Reauth: Error: %x\n",
|
||||||
|
status);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FORT_API void fort_app_period_timer(void)
|
||||||
|
{
|
||||||
|
if (fort_conf_ref_period_update(&g_device->conf, FALSE, NULL)) {
|
||||||
|
fort_worker_queue(&g_device->worker, FORT_WORKER_REAUTH, &fort_worker_reauth);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FORT_API NTSTATUS fort_device_create(PDEVICE_OBJECT device, PIRP irp)
|
||||||
|
{
|
||||||
|
NTSTATUS status = STATUS_SUCCESS;
|
||||||
|
|
||||||
|
UNUSED(device);
|
||||||
|
|
||||||
|
/* Device opened */
|
||||||
|
if (fort_device_flag_set(&g_device->conf, FORT_DEVICE_IS_OPENED, TRUE)
|
||||||
|
& FORT_DEVICE_IS_OPENED) {
|
||||||
|
status = STATUS_SHARING_VIOLATION; /* Only one client may connect */
|
||||||
|
}
|
||||||
|
|
||||||
|
if (NT_SUCCESS(status)) {
|
||||||
|
/* Clear buffer */
|
||||||
|
fort_buffer_clear(&g_device->buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
fort_request_complete(irp, status);
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
FORT_API NTSTATUS fort_device_close(PDEVICE_OBJECT device, PIRP irp)
|
||||||
|
{
|
||||||
|
UNUSED(device);
|
||||||
|
|
||||||
|
fort_request_complete(irp, STATUS_SUCCESS);
|
||||||
|
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
FORT_API NTSTATUS fort_device_cleanup(PDEVICE_OBJECT device, PIRP irp)
|
||||||
|
{
|
||||||
|
UNUSED(device);
|
||||||
|
|
||||||
|
/* Device closed */
|
||||||
|
fort_device_flag_set(
|
||||||
|
&g_device->conf, (FORT_DEVICE_IS_OPENED | FORT_DEVICE_IS_VALIDATED), FALSE);
|
||||||
|
|
||||||
|
/* Clear conf */
|
||||||
|
{
|
||||||
|
const FORT_CONF_FLAGS old_conf_flags = fort_conf_ref_set(&g_device->conf, NULL);
|
||||||
|
|
||||||
|
fort_conf_zones_set(&g_device->conf, NULL);
|
||||||
|
|
||||||
|
fort_callout_force_reauth(old_conf_flags, FORT_DEFER_FLUSH_ALL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Clear buffer */
|
||||||
|
fort_buffer_clear(&g_device->buffer);
|
||||||
|
|
||||||
|
fort_request_complete(irp, STATUS_SUCCESS);
|
||||||
|
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void fort_device_cancel_pending(PDEVICE_OBJECT device, PIRP irp)
|
||||||
|
{
|
||||||
|
ULONG_PTR info;
|
||||||
|
NTSTATUS status;
|
||||||
|
|
||||||
|
UNUSED(device);
|
||||||
|
|
||||||
|
status = fort_buffer_cancel_pending(&g_device->buffer, irp, &info);
|
||||||
|
|
||||||
|
IoReleaseCancelSpinLock(irp->CancelIrql); /* before IoCompleteRequest()! */
|
||||||
|
|
||||||
|
fort_request_complete_info(irp, status, info);
|
||||||
|
}
|
||||||
|
|
||||||
|
FORT_API NTSTATUS fort_device_control(PDEVICE_OBJECT device, PIRP irp)
|
||||||
|
{
|
||||||
|
ULONG_PTR info = 0;
|
||||||
|
NTSTATUS status = STATUS_UNSUCCESSFUL;
|
||||||
|
|
||||||
|
UNUSED(device);
|
||||||
|
|
||||||
|
const PIO_STACK_LOCATION irp_stack = IoGetCurrentIrpStackLocation(irp);
|
||||||
|
const ULONG control_code = irp_stack->Parameters.DeviceIoControl.IoControlCode;
|
||||||
|
|
||||||
|
if (control_code != (ULONG) FORT_IOCTL_VALIDATE
|
||||||
|
&& !fort_device_flag(&g_device->conf, FORT_DEVICE_IS_VALIDATED))
|
||||||
|
goto end;
|
||||||
|
|
||||||
|
switch (control_code) {
|
||||||
|
case FORT_IOCTL_VALIDATE: {
|
||||||
|
const PFORT_CONF_VERSION conf_ver = irp->AssociatedIrp.SystemBuffer;
|
||||||
|
const ULONG len = irp_stack->Parameters.DeviceIoControl.InputBufferLength;
|
||||||
|
|
||||||
|
if (len == sizeof(FORT_CONF_VERSION)) {
|
||||||
|
if (conf_ver->driver_version == DRIVER_VERSION) {
|
||||||
|
fort_device_flag_set(&g_device->conf, FORT_DEVICE_IS_VALIDATED, TRUE);
|
||||||
|
status = STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case FORT_IOCTL_SETCONF: {
|
||||||
|
const PFORT_CONF_IO conf_io = irp->AssociatedIrp.SystemBuffer;
|
||||||
|
const ULONG len = irp_stack->Parameters.DeviceIoControl.InputBufferLength;
|
||||||
|
|
||||||
|
if (len > sizeof(FORT_CONF_IO)) {
|
||||||
|
const PFORT_CONF conf = &conf_io->conf;
|
||||||
|
PFORT_CONF_REF conf_ref = fort_conf_ref_new(conf, len - FORT_CONF_IO_CONF_OFF);
|
||||||
|
|
||||||
|
if (conf_ref == NULL) {
|
||||||
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
||||||
|
} else {
|
||||||
|
PFORT_STAT stat = &g_device->stat;
|
||||||
|
|
||||||
|
const FORT_CONF_FLAGS old_conf_flags = fort_conf_ref_set(&g_device->conf, conf_ref);
|
||||||
|
|
||||||
|
const UINT32 defer_flush_bits =
|
||||||
|
(stat->conf_group.limit_2bits ^ conf_io->conf_group.limit_2bits);
|
||||||
|
|
||||||
|
fort_stat_conf_update(stat, conf_io);
|
||||||
|
|
||||||
|
status = fort_callout_force_reauth(old_conf_flags, defer_flush_bits);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case FORT_IOCTL_SETFLAGS: {
|
||||||
|
const PFORT_CONF_FLAGS conf_flags = irp->AssociatedIrp.SystemBuffer;
|
||||||
|
const ULONG len = irp_stack->Parameters.DeviceIoControl.InputBufferLength;
|
||||||
|
|
||||||
|
if (len == sizeof(FORT_CONF_FLAGS)) {
|
||||||
|
const FORT_CONF_FLAGS old_conf_flags =
|
||||||
|
fort_conf_ref_flags_set(&g_device->conf, conf_flags);
|
||||||
|
|
||||||
|
const UINT32 defer_flush_bits =
|
||||||
|
(old_conf_flags.group_bits != conf_flags->group_bits ? FORT_DEFER_FLUSH_ALL
|
||||||
|
: 0);
|
||||||
|
|
||||||
|
status = fort_callout_force_reauth(old_conf_flags, defer_flush_bits);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case FORT_IOCTL_GETLOG: {
|
||||||
|
PVOID out = irp->AssociatedIrp.SystemBuffer;
|
||||||
|
const ULONG out_len = irp_stack->Parameters.DeviceIoControl.OutputBufferLength;
|
||||||
|
|
||||||
|
if (out_len < FORT_BUFFER_SIZE) {
|
||||||
|
status = STATUS_BUFFER_TOO_SMALL;
|
||||||
|
} else {
|
||||||
|
status = fort_buffer_xmove(&g_device->buffer, irp, out, out_len, &info);
|
||||||
|
|
||||||
|
if (status == STATUS_PENDING) {
|
||||||
|
KIRQL cirq;
|
||||||
|
|
||||||
|
IoMarkIrpPending(irp);
|
||||||
|
|
||||||
|
IoAcquireCancelSpinLock(&cirq);
|
||||||
|
IoSetCancelRoutine(irp, fort_device_cancel_pending);
|
||||||
|
IoReleaseCancelSpinLock(cirq);
|
||||||
|
|
||||||
|
return STATUS_PENDING;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case FORT_IOCTL_ADDAPP:
|
||||||
|
case FORT_IOCTL_DELAPP: {
|
||||||
|
const PFORT_APP_ENTRY app_entry = irp->AssociatedIrp.SystemBuffer;
|
||||||
|
const ULONG len = irp_stack->Parameters.DeviceIoControl.InputBufferLength;
|
||||||
|
|
||||||
|
if (len > sizeof(FORT_APP_ENTRY) && len >= (sizeof(FORT_APP_ENTRY) + app_entry->path_len)) {
|
||||||
|
PFORT_CONF_REF conf_ref = fort_conf_ref_take(&g_device->conf);
|
||||||
|
|
||||||
|
if (conf_ref == NULL) {
|
||||||
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
||||||
|
} else {
|
||||||
|
if (control_code == (ULONG) FORT_IOCTL_ADDAPP) {
|
||||||
|
status = fort_conf_ref_exe_add_entry(conf_ref, app_entry, FALSE);
|
||||||
|
} else {
|
||||||
|
fort_conf_ref_exe_del_entry(conf_ref, app_entry);
|
||||||
|
status = STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
fort_conf_ref_put(&g_device->conf, conf_ref);
|
||||||
|
|
||||||
|
if (NT_SUCCESS(status)) {
|
||||||
|
fort_worker_reauth();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case FORT_IOCTL_SETZONES: {
|
||||||
|
const PFORT_CONF_ZONES zones = irp->AssociatedIrp.SystemBuffer;
|
||||||
|
const ULONG len = irp_stack->Parameters.DeviceIoControl.InputBufferLength;
|
||||||
|
|
||||||
|
if (len >= FORT_CONF_ZONES_DATA_OFF) {
|
||||||
|
PFORT_CONF_ZONES conf_zones = fort_conf_zones_new(zones, len);
|
||||||
|
|
||||||
|
if (conf_zones == NULL) {
|
||||||
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
||||||
|
} else {
|
||||||
|
fort_conf_zones_set(&g_device->conf, conf_zones);
|
||||||
|
|
||||||
|
fort_worker_reauth();
|
||||||
|
|
||||||
|
status = STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case FORT_IOCTL_SETZONEFLAG: {
|
||||||
|
const PFORT_CONF_ZONE_FLAG zone_flag = irp->AssociatedIrp.SystemBuffer;
|
||||||
|
const ULONG len = irp_stack->Parameters.DeviceIoControl.InputBufferLength;
|
||||||
|
|
||||||
|
if (len == sizeof(FORT_CONF_ZONE_FLAG)) {
|
||||||
|
fort_conf_zone_flag_set(&g_device->conf, zone_flag);
|
||||||
|
|
||||||
|
fort_worker_reauth();
|
||||||
|
|
||||||
|
status = STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
end:
|
||||||
|
if (!NT_SUCCESS(status) && status != FORT_STATUS_USER_ERROR) {
|
||||||
|
DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_ERROR_LEVEL, "FORT: Device Control: Error: %x\n",
|
||||||
|
status);
|
||||||
|
}
|
||||||
|
|
||||||
|
fort_request_complete_info(irp, status, info);
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
55
src/driver/fortdev.h
Normal file
55
src/driver/fortdev.h
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
#ifndef FORTDEV_H
|
||||||
|
#define FORTDEV_H
|
||||||
|
|
||||||
|
#include "fortdrv.h"
|
||||||
|
|
||||||
|
#include "fortbuf.h"
|
||||||
|
#include "fortcnf.h"
|
||||||
|
#include "fortpkt.h"
|
||||||
|
#include "fortstat.h"
|
||||||
|
#include "forttmr.h"
|
||||||
|
#include "fortwrk.h"
|
||||||
|
|
||||||
|
typedef struct fort_device
|
||||||
|
{
|
||||||
|
UINT32 connect4_id;
|
||||||
|
UINT32 accept4_id;
|
||||||
|
|
||||||
|
PCALLBACK_OBJECT power_cb_obj;
|
||||||
|
PVOID power_cb_reg;
|
||||||
|
|
||||||
|
PCALLBACK_OBJECT systime_cb_obj;
|
||||||
|
PVOID systime_cb_reg;
|
||||||
|
|
||||||
|
FORT_DEVICE_CONF conf;
|
||||||
|
FORT_BUFFER buffer;
|
||||||
|
FORT_STAT stat;
|
||||||
|
FORT_DEFER defer;
|
||||||
|
FORT_TIMER log_timer;
|
||||||
|
FORT_TIMER app_timer;
|
||||||
|
FORT_WORKER worker;
|
||||||
|
} FORT_DEVICE, *PFORT_DEVICE;
|
||||||
|
|
||||||
|
#if defined(__cplusplus)
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
FORT_API PFORT_DEVICE fort_device();
|
||||||
|
|
||||||
|
FORT_API void fort_device_set(PFORT_DEVICE device);
|
||||||
|
|
||||||
|
FORT_API void fort_app_period_timer(void);
|
||||||
|
|
||||||
|
FORT_API NTSTATUS fort_device_create(PDEVICE_OBJECT device, PIRP irp);
|
||||||
|
|
||||||
|
FORT_API NTSTATUS fort_device_close(PDEVICE_OBJECT device, PIRP irp);
|
||||||
|
|
||||||
|
FORT_API NTSTATUS fort_device_cleanup(PDEVICE_OBJECT device, PIRP irp);
|
||||||
|
|
||||||
|
FORT_API NTSTATUS fort_device_control(PDEVICE_OBJECT device, PIRP irp);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
} // extern "C"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // FORTDEV_H
|
1143
src/driver/fortdrv.c
1143
src/driver/fortdrv.c
File diff suppressed because it is too large
Load Diff
@ -14,4 +14,13 @@
|
|||||||
#define fort_mem_alloc(size, tag) ExAllocatePoolWithTag(NonPagedPool, (size), (tag))
|
#define fort_mem_alloc(size, tag) ExAllocatePoolWithTag(NonPagedPool, (size), (tag))
|
||||||
#define fort_mem_free(p, tag) ExFreePoolWithTag((p), (tag))
|
#define fort_mem_free(p, tag) ExFreePoolWithTag((p), (tag))
|
||||||
|
|
||||||
|
#define fort_request_complete_info(irp, status, info) \
|
||||||
|
do { \
|
||||||
|
(irp)->IoStatus.Status = (status); \
|
||||||
|
(irp)->IoStatus.Information = (info); \
|
||||||
|
IoCompleteRequest((irp), IO_NO_INCREMENT); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define fort_request_complete(irp, status) fort_request_complete_info((irp), (status), 0)
|
||||||
|
|
||||||
#endif // FORTDRV_H
|
#endif // FORTDRV_H
|
||||||
|
@ -16,4 +16,6 @@
|
|||||||
#include "fortstat.c"
|
#include "fortstat.c"
|
||||||
#include "forttmr.c"
|
#include "forttmr.c"
|
||||||
#include "fortwrk.c"
|
#include "fortwrk.c"
|
||||||
|
#include "fortcout.c"
|
||||||
|
#include "fortdev.c"
|
||||||
#include "fortdrv.c"
|
#include "fortdrv.c"
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
#include "fortcommon.h"
|
#include "fortcommon.h"
|
||||||
|
|
||||||
#include <common/fortconf.h>
|
#include <common/fortconf.h>
|
||||||
#include <common/fortdev.h>
|
#include <common/fortdef.h>
|
||||||
#include <common/fortlog.h>
|
#include <common/fortlog.h>
|
||||||
#include <common/fortprov.h>
|
#include <common/fortprov.h>
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user