mirror of
https://github.com/tnodir/fort
synced 2024-11-15 05:36:09 +00:00
Add ability to fragment first TCP packet.
This commit is contained in:
parent
bb01a52daa
commit
9d707490bd
@ -20,6 +20,7 @@ typedef struct fort_conf_flags {
|
|||||||
UINT32 app_allow_all : 1;
|
UINT32 app_allow_all : 1;
|
||||||
UINT32 log_blocked : 1;
|
UINT32 log_blocked : 1;
|
||||||
UINT32 log_stat : 1;
|
UINT32 log_stat : 1;
|
||||||
|
UINT32 filter_transport : 1;
|
||||||
|
|
||||||
UINT32 group_bits : 16;
|
UINT32 group_bits : 16;
|
||||||
} FORT_CONF_FLAGS, *PFORT_CONF_FLAGS;
|
} FORT_CONF_FLAGS, *PFORT_CONF_FLAGS;
|
||||||
@ -45,6 +46,13 @@ typedef struct fort_traf {
|
|||||||
};
|
};
|
||||||
} FORT_TRAF, *PFORT_TRAF;
|
} FORT_TRAF, *PFORT_TRAF;
|
||||||
|
|
||||||
|
typedef struct fort_conf_group {
|
||||||
|
UINT16 fragment_bits;
|
||||||
|
UINT32 limit_bits;
|
||||||
|
|
||||||
|
FORT_TRAF limits[FORT_CONF_GROUP_MAX]; /* Bytes per 0.5 sec. */
|
||||||
|
} FORT_CONF_GROUP, *PFORT_CONF_GROUP;
|
||||||
|
|
||||||
typedef struct fort_conf {
|
typedef struct fort_conf {
|
||||||
FORT_CONF_FLAGS flags;
|
FORT_CONF_FLAGS flags;
|
||||||
|
|
||||||
@ -67,9 +75,7 @@ typedef struct fort_conf {
|
|||||||
typedef struct fort_conf_io {
|
typedef struct fort_conf_io {
|
||||||
UINT16 driver_version;
|
UINT16 driver_version;
|
||||||
|
|
||||||
UINT32 limit_bits;
|
FORT_CONF_GROUP conf_group;
|
||||||
|
|
||||||
FORT_TRAF limits[FORT_CONF_GROUP_MAX]; /* Bytes per 0.5 sec. */
|
|
||||||
|
|
||||||
FORT_CONF conf;
|
FORT_CONF conf;
|
||||||
} FORT_CONF_IO, *PFORT_CONF_IO;
|
} FORT_CONF_IO, *PFORT_CONF_IO;
|
||||||
|
@ -7,6 +7,6 @@
|
|||||||
#define APP_UPDATES_URL "https://github.com/tnodir/fort/releases"
|
#define APP_UPDATES_URL "https://github.com/tnodir/fort/releases"
|
||||||
#define APP_UPDATES_API_URL "https://api.github.com/repos/tnodir/fort/releases/latest"
|
#define APP_UPDATES_API_URL "https://api.github.com/repos/tnodir/fort/releases/latest"
|
||||||
|
|
||||||
#define DRIVER_VERSION 9
|
#define DRIVER_VERSION 10
|
||||||
|
|
||||||
#endif // VERSION_H
|
#endif // VERSION_H
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
#define NDIS630 1
|
#define NDIS630 1
|
||||||
|
|
||||||
#define WIN9X_COMPAT_SPINLOCK /* XXX: Support Windows 7: KeInitializeSpinLock() */
|
#define WIN9X_COMPAT_SPINLOCK /* XXX: Support Windows 7: KeInitializeSpinLock() */
|
||||||
|
#define POOL_NX_OPTIN 1 /* Enhanced protection of NX pool */
|
||||||
|
|
||||||
#include <wdm.h>
|
#include <wdm.h>
|
||||||
#include <fwpmk.h>
|
#include <fwpmk.h>
|
||||||
@ -323,8 +324,8 @@ fort_callout_classify_v4 (const FWPS_INCOMING_VALUES0 *inFixedValues,
|
|||||||
BOOL is_new_proc = FALSE;
|
BOOL is_new_proc = FALSE;
|
||||||
NTSTATUS status;
|
NTSTATUS status;
|
||||||
|
|
||||||
status = fort_stat_flow_associate(&g_device->stat,
|
status = fort_flow_associate(&g_device->stat, flowId, process_id,
|
||||||
flowId, process_id, group_index, is_reauth, &is_new_proc);
|
group_index, is_reauth, &is_new_proc);
|
||||||
|
|
||||||
if (!NT_SUCCESS(status)) {
|
if (!NT_SUCCESS(status)) {
|
||||||
if (status == FORT_STATUS_FLOW_BLOCK)
|
if (status == FORT_STATUS_FLOW_BLOCK)
|
||||||
@ -404,38 +405,85 @@ fort_callout_notify (FWPS_CALLOUT_NOTIFY_TYPE notifyType,
|
|||||||
return STATUS_SUCCESS;
|
return STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
fort_packet_inject_complete (PFORT_PACKET pkt,
|
||||||
|
PNET_BUFFER_LIST clonedNetBufList,
|
||||||
|
BOOLEAN dispatchLevel)
|
||||||
|
{
|
||||||
|
fort_defer_packet_free(&g_device->defer, pkt, clonedNetBufList, dispatchLevel);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
fort_callout_flow_classify_v4 (const FWPS_INCOMING_METADATA_VALUES0 *inMetaValues,
|
fort_callout_flow_classify_v4 (const FWPS_INCOMING_METADATA_VALUES0 *inMetaValues,
|
||||||
const FWPS_FILTER0 *filter,
|
|
||||||
UINT64 flowContext,
|
UINT64 flowContext,
|
||||||
FWPS_CLASSIFY_OUT0 *classifyOut,
|
FWPS_CLASSIFY_OUT0 *classifyOut,
|
||||||
UINT32 dataSize, BOOL inbound)
|
UINT32 dataSize, BOOL inbound)
|
||||||
{
|
{
|
||||||
const UINT32 headerSize = inbound ? inMetaValues->transportHeaderSize : 0;
|
const UINT32 headerSize = inbound ? inMetaValues->transportHeaderSize : 0;
|
||||||
|
|
||||||
fort_stat_flow_classify(&g_device->stat, flowContext,
|
fort_flow_classify(&g_device->stat, flowContext,
|
||||||
headerSize + dataSize, inbound);
|
headerSize + dataSize, inbound);
|
||||||
|
|
||||||
fort_callout_classify_continue(classifyOut);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
fort_callout_stream_classify_v4 (const FWPS_INCOMING_VALUES0 *inFixedValues,
|
fort_callout_stream_classify_v4 (const FWPS_INCOMING_VALUES0 *inFixedValues,
|
||||||
const FWPS_INCOMING_METADATA_VALUES0 *inMetaValues,
|
const FWPS_INCOMING_METADATA_VALUES0 *inMetaValues,
|
||||||
const FWPS_STREAM_CALLOUT_IO_PACKET0 *packet,
|
FWPS_STREAM_CALLOUT_IO_PACKET0 *packet,
|
||||||
const FWPS_FILTER0 *filter,
|
const FWPS_FILTER0 *filter,
|
||||||
UINT64 flowContext,
|
UINT64 flowContext,
|
||||||
FWPS_CLASSIFY_OUT0 *classifyOut)
|
FWPS_CLASSIFY_OUT0 *classifyOut)
|
||||||
{
|
{
|
||||||
const FWPS_STREAM_DATA0 *streamData = packet->streamData;
|
const FWPS_STREAM_DATA0 *streamData = packet->streamData;
|
||||||
|
const UINT32 streamFlags = streamData->flags;
|
||||||
const UINT32 dataSize = (UINT32) streamData->dataLength;
|
const UINT32 dataSize = (UINT32) streamData->dataLength;
|
||||||
|
|
||||||
const BOOL inbound = (streamData->flags & FWPS_STREAM_FLAG_RECEIVE) != 0;
|
const BOOL inbound = (streamFlags & FWPS_STREAM_FLAG_RECEIVE) != 0;
|
||||||
|
|
||||||
UNUSED(inFixedValues);
|
UNUSED(inFixedValues);
|
||||||
|
|
||||||
fort_callout_flow_classify_v4(inMetaValues, filter, flowContext,
|
fort_callout_flow_classify_v4(inMetaValues, flowContext,
|
||||||
classifyOut, dataSize, inbound);
|
classifyOut, dataSize, inbound);
|
||||||
|
|
||||||
|
/* 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(&g_device->defer,
|
||||||
|
inFixedValues, inMetaValues, streamData, filter, inbound);
|
||||||
|
|
||||||
|
if (NT_SUCCESS(status))
|
||||||
|
goto drop;
|
||||||
|
|
||||||
|
fort_flow_flags_set(flow, FORT_FLOW_FRAGMENTED);
|
||||||
|
}
|
||||||
|
else if (dataSize > fragment_size) {
|
||||||
|
packet->countBytesEnforced = fragment_size;
|
||||||
|
|
||||||
|
fort_flow_flags_set(flow, FORT_FLOW_FRAGMENT_DEFER);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* permit: */
|
||||||
|
fort_callout_classify_permit(filter, classifyOut);
|
||||||
|
return;
|
||||||
|
|
||||||
|
drop:
|
||||||
|
fort_callout_classify_drop(classifyOut);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -454,9 +502,12 @@ fort_callout_datagram_classify_v4 (const FWPS_INCOMING_VALUES0 *inFixedValues,
|
|||||||
const BOOL inbound = (direction == FWP_DIRECTION_INBOUND);
|
const BOOL inbound = (direction == FWP_DIRECTION_INBOUND);
|
||||||
|
|
||||||
UNUSED(inFixedValues);
|
UNUSED(inFixedValues);
|
||||||
|
UNUSED(filter);
|
||||||
|
|
||||||
fort_callout_flow_classify_v4(inMetaValues, filter, flowContext,
|
fort_callout_flow_classify_v4(inMetaValues, flowContext,
|
||||||
classifyOut, dataSize, inbound);
|
classifyOut, dataSize, inbound);
|
||||||
|
|
||||||
|
fort_callout_classify_continue(classifyOut);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -465,15 +516,7 @@ fort_callout_flow_delete_v4 (UINT16 layerId, UINT32 calloutId, UINT64 flowContex
|
|||||||
UNUSED(layerId);
|
UNUSED(layerId);
|
||||||
UNUSED(calloutId);
|
UNUSED(calloutId);
|
||||||
|
|
||||||
fort_stat_flow_delete(&g_device->stat, flowContext);
|
fort_flow_delete(&g_device->stat, flowContext);
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
fort_transport_inject_complete (PFORT_PACKET pkt,
|
|
||||||
PNET_BUFFER_LIST clonedNetBufList,
|
|
||||||
BOOLEAN dispatchLevel)
|
|
||||||
{
|
|
||||||
fort_defer_free(&g_device->defer, pkt, clonedNetBufList, dispatchLevel);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -494,17 +537,23 @@ fort_callout_transport_classify_v4 (const FWPS_INCOMING_VALUES0 *inFixedValues,
|
|||||||
FWPS_METADATA_FIELD_ALE_CLASSIFY_REQUIRED))
|
FWPS_METADATA_FIELD_ALE_CLASSIFY_REQUIRED))
|
||||||
&& netBufList != NULL
|
&& netBufList != NULL
|
||||||
&& (netBuf = NET_BUFFER_LIST_FIRST_NB(netBufList)) != NULL) {
|
&& (netBuf = NET_BUFFER_LIST_FIRST_NB(netBufList)) != NULL) {
|
||||||
PFORT_STAT_FLOW flow = (PFORT_STAT_FLOW) flowContext;
|
PFORT_FLOW flow = (PFORT_FLOW) flowContext;
|
||||||
|
|
||||||
|
const UCHAR flow_flags = fort_flow_flags(flow);
|
||||||
|
|
||||||
const UCHAR defer_flag = inbound
|
const UCHAR defer_flag = inbound
|
||||||
? FORT_STAT_FLOW_DEFER_IN : FORT_STAT_FLOW_DEFER_OUT;
|
? FORT_FLOW_DEFER_IN : FORT_FLOW_DEFER_OUT;
|
||||||
const UCHAR speed_limit = inbound
|
const UCHAR speed_limit = inbound
|
||||||
? FORT_STAT_FLOW_SPEED_LIMIT_OUT : FORT_STAT_FLOW_SPEED_LIMIT_IN;
|
? FORT_FLOW_SPEED_LIMIT_OUT : FORT_FLOW_SPEED_LIMIT_IN;
|
||||||
|
|
||||||
const UCHAR flow_flags = speed_limit | defer_flag;
|
const UCHAR speed_defer_flags = speed_limit | defer_flag;
|
||||||
const BOOL defer_flow = (fort_stat_flow_flags(flow) & flow_flags) == flow_flags
|
const BOOL defer_flow = (flow_flags & speed_defer_flags) == speed_defer_flags
|
||||||
&& !g_device->power_off;
|
&& !g_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:
|
/* Position in the packet data:
|
||||||
* FWPS_LAYER_INBOUND_TRANSPORT_V4: The beginning of the data.
|
* FWPS_LAYER_INBOUND_TRANSPORT_V4: The beginning of the data.
|
||||||
* FWPS_LAYER_OUTBOUND_TRANSPORT_V4: The beginning of the transport header.
|
* FWPS_LAYER_OUTBOUND_TRANSPORT_V4: The beginning of the transport header.
|
||||||
@ -541,25 +590,35 @@ fort_callout_transport_classify_v4 (const FWPS_INCOMING_VALUES0 *inFixedValues,
|
|||||||
|
|
||||||
/* Defer TCP Pure (zero length) ACK-packets */
|
/* Defer TCP Pure (zero length) ACK-packets */
|
||||||
if (defer_flow && NET_BUFFER_DATA_LENGTH(netBuf) == headerOffset) {
|
if (defer_flow && NET_BUFFER_DATA_LENGTH(netBuf) == headerOffset) {
|
||||||
const NTSTATUS status = fort_defer_add(&g_device->defer,
|
const NTSTATUS status = fort_defer_packet_add(&g_device->defer,
|
||||||
inFixedValues, inMetaValues, netBufList, inbound,
|
inFixedValues, inMetaValues, netBufList, inbound,
|
||||||
flow->opt.group_index);
|
flow->opt.group_index);
|
||||||
|
|
||||||
if (NT_SUCCESS(status))
|
if (NT_SUCCESS(status))
|
||||||
goto block;
|
goto drop;
|
||||||
|
|
||||||
if (status == STATUS_CANT_TERMINATE_SELF) {
|
if (status == STATUS_CANT_TERMINATE_SELF) {
|
||||||
/* Clear ACK deferring */
|
/* Clear ACK deferring */
|
||||||
fort_stat_flow_flags_clear(flow, defer_flag);
|
fort_flow_flags_clear(flow, defer_flag);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
goto permit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Fragment first TCP packet */
|
||||||
|
if (fragment_packet) {
|
||||||
|
fort_defer_stream_flush(&g_device->defer, fort_packet_inject_complete,
|
||||||
|
flow->flow_id, FALSE);
|
||||||
|
|
||||||
|
fort_flow_flags_set(flow, FORT_FLOW_FRAGMENTED);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* permit: */
|
permit:
|
||||||
fort_callout_classify_permit(filter, classifyOut);
|
fort_callout_classify_permit(filter, classifyOut);
|
||||||
return;
|
return;
|
||||||
|
|
||||||
block:
|
drop:
|
||||||
fort_callout_classify_drop(classifyOut);
|
fort_callout_classify_drop(classifyOut);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -721,10 +780,19 @@ fort_callout_remove (void)
|
|||||||
static void
|
static void
|
||||||
fort_callout_defer_flush (UINT32 list_bits, BOOL dispatchLevel)
|
fort_callout_defer_flush (UINT32 list_bits, BOOL dispatchLevel)
|
||||||
{
|
{
|
||||||
fort_defer_flush(&g_device->defer, fort_transport_inject_complete,
|
fort_defer_packet_flush(&g_device->defer, fort_packet_inject_complete,
|
||||||
list_bits, dispatchLevel);
|
list_bits, dispatchLevel);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
fort_callout_defer_flush_all (void)
|
||||||
|
{
|
||||||
|
fort_callout_defer_flush(FORT_DEFER_FLUSH_ALL, FALSE);
|
||||||
|
|
||||||
|
fort_defer_stream_flush(&g_device->defer, fort_packet_inject_complete,
|
||||||
|
FORT_DEFER_STREAM_ALL, FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
static NTSTATUS
|
static NTSTATUS
|
||||||
fort_callout_force_reauth (const FORT_CONF_FLAGS old_conf_flags,
|
fort_callout_force_reauth (const FORT_CONF_FLAGS old_conf_flags,
|
||||||
const FORT_CONF_FLAGS conf_flags,
|
const FORT_CONF_FLAGS conf_flags,
|
||||||
@ -766,15 +834,16 @@ fort_callout_force_reauth (const FORT_CONF_FLAGS old_conf_flags,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Check flow filter */
|
/* Check flow filter */
|
||||||
if (old_conf_flags.log_stat != conf_flags.log_stat) {
|
if (old_conf_flags.log_stat != conf_flags.log_stat
|
||||||
|
|| old_conf_flags.filter_transport != conf_flags.filter_transport) {
|
||||||
if (old_conf_flags.log_stat) {
|
if (old_conf_flags.log_stat) {
|
||||||
fort_prov_flow_unregister(engine);
|
fort_prov_flow_unregister(engine);
|
||||||
}
|
}
|
||||||
|
|
||||||
stat_prov:
|
stat_prov:
|
||||||
if (conf_flags.log_stat) {
|
if (conf_flags.log_stat) {
|
||||||
const BOOL is_speed_limit = (stat->limit_bits != 0);
|
if ((status = fort_prov_flow_register(engine,
|
||||||
if ((status = fort_prov_flow_register(engine, is_speed_limit)))
|
conf_flags.filter_transport)))
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -989,13 +1058,15 @@ fort_device_control (PDEVICE_OBJECT device, PIRP irp)
|
|||||||
if (conf_ref == NULL) {
|
if (conf_ref == NULL) {
|
||||||
status = STATUS_INSUFFICIENT_RESOURCES;
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
||||||
} else {
|
} else {
|
||||||
|
PFORT_STAT stat = &g_device->stat;
|
||||||
|
|
||||||
const FORT_CONF_FLAGS old_conf_flags = fort_conf_ref_set(conf_ref);
|
const FORT_CONF_FLAGS old_conf_flags = fort_conf_ref_set(conf_ref);
|
||||||
const FORT_CONF_FLAGS conf_flags = conf_ref->conf.flags;
|
const FORT_CONF_FLAGS conf_flags = conf_ref->conf.flags;
|
||||||
|
|
||||||
const UINT32 defer_flush_bits =
|
const UINT32 defer_flush_bits =
|
||||||
(g_device->stat.limit_bits ^ conf_io->limit_bits);
|
(stat->conf_group.limit_bits ^ conf_io->conf_group.limit_bits);
|
||||||
|
|
||||||
fort_stat_update_limits(&g_device->stat, conf_io);
|
fort_stat_conf_update(stat, conf_io);
|
||||||
|
|
||||||
status = fort_callout_force_reauth(old_conf_flags, conf_flags,
|
status = fort_callout_force_reauth(old_conf_flags, conf_flags,
|
||||||
defer_flush_bits);
|
defer_flush_bits);
|
||||||
@ -1064,7 +1135,7 @@ fort_power_callback (PVOID context, PVOID event, PVOID specifics)
|
|||||||
g_device->power_off = power_off;
|
g_device->power_off = power_off;
|
||||||
|
|
||||||
if (power_off) {
|
if (power_off) {
|
||||||
fort_callout_defer_flush(FORT_DEFER_FLUSH_ALL, FALSE);
|
fort_callout_defer_flush_all();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1154,7 +1225,7 @@ fort_driver_unload (PDRIVER_OBJECT driver)
|
|||||||
UNICODE_STRING device_link;
|
UNICODE_STRING device_link;
|
||||||
|
|
||||||
if (g_device != NULL) {
|
if (g_device != NULL) {
|
||||||
fort_callout_defer_flush(FORT_DEFER_FLUSH_ALL, FALSE);
|
fort_callout_defer_flush_all();
|
||||||
|
|
||||||
fort_timer_close(&g_device->app_timer);
|
fort_timer_close(&g_device->app_timer);
|
||||||
fort_timer_close(&g_device->log_timer);
|
fort_timer_close(&g_device->log_timer);
|
||||||
@ -1206,6 +1277,9 @@ DriverEntry (PDRIVER_OBJECT driver, PUNICODE_STRING reg_path)
|
|||||||
|
|
||||||
UNUSED(reg_path);
|
UNUSED(reg_path);
|
||||||
|
|
||||||
|
// Use NX Non-Paged Pool
|
||||||
|
ExInitializeDriverRuntime(DrvRtPoolNxOptIn);
|
||||||
|
|
||||||
/* Wait for BFE to start */
|
/* Wait for BFE to start */
|
||||||
status = fort_bfe_wait();
|
status = fort_bfe_wait();
|
||||||
if (!NT_SUCCESS(status)) {
|
if (!NT_SUCCESS(status)) {
|
||||||
|
@ -3,6 +3,8 @@
|
|||||||
#define FORT_DEFER_FLUSH_ALL 0xFFFFFFFF
|
#define FORT_DEFER_FLUSH_ALL 0xFFFFFFFF
|
||||||
#define FORT_DEFER_LIST_MAX (FORT_CONF_GROUP_MAX * 2)
|
#define FORT_DEFER_LIST_MAX (FORT_CONF_GROUP_MAX * 2)
|
||||||
|
|
||||||
|
#define FORT_DEFER_STREAM_ALL ((UINT64) ((INT64) -1))
|
||||||
|
|
||||||
#define HTONL(l) _byteswap_ulong(l)
|
#define HTONL(l) _byteswap_ulong(l)
|
||||||
#define NTOHL(l) HTONL(l)
|
#define NTOHL(l) HTONL(l)
|
||||||
#define HTONS(s) _byteswap_ushort(s)
|
#define HTONS(s) _byteswap_ushort(s)
|
||||||
@ -35,26 +37,38 @@ typedef struct tcp_header {
|
|||||||
} TCP_HEADER, *PTCP_HEADER;
|
} TCP_HEADER, *PTCP_HEADER;
|
||||||
|
|
||||||
typedef struct fort_packet_in {
|
typedef struct fort_packet_in {
|
||||||
|
COMPARTMENT_ID compartmentId;
|
||||||
|
|
||||||
IF_INDEX interfaceIndex;
|
IF_INDEX interfaceIndex;
|
||||||
IF_INDEX subInterfaceIndex;
|
IF_INDEX subInterfaceIndex;
|
||||||
|
|
||||||
UINT16 ipHeaderSize;
|
UINT16 ipHeaderSize;
|
||||||
UINT16 transportHeaderSize;
|
UINT16 transportHeaderSize;
|
||||||
|
|
||||||
UINT16 nblOffset;
|
|
||||||
} FORT_PACKET_IN, *PFORT_PACKET_IN;
|
} FORT_PACKET_IN, *PFORT_PACKET_IN;
|
||||||
|
|
||||||
typedef struct fort_packet_out {
|
typedef struct fort_packet_out {
|
||||||
|
COMPARTMENT_ID compartmentId;
|
||||||
|
|
||||||
UINT32 remoteAddr4;
|
UINT32 remoteAddr4;
|
||||||
|
|
||||||
SCOPE_ID remoteScopeId;
|
SCOPE_ID remoteScopeId;
|
||||||
UINT64 endpointHandle;
|
UINT64 endpointHandle;
|
||||||
} FORT_PACKET_OUT, *PFORT_PACKET_OUT;
|
} FORT_PACKET_OUT, *PFORT_PACKET_OUT;
|
||||||
|
|
||||||
typedef struct fort_packet {
|
typedef struct fort_packet_stream {
|
||||||
BOOL inbound;
|
UINT16 layerId;
|
||||||
|
|
||||||
COMPARTMENT_ID compartmentId;
|
UINT32 streamFlags;
|
||||||
|
UINT32 calloutId;
|
||||||
|
|
||||||
|
UINT64 flowId;
|
||||||
|
} FORT_PACKET_STREAM, *PFORT_PACKET_STREAM;
|
||||||
|
|
||||||
|
typedef struct fort_packet {
|
||||||
|
UINT32 inbound : 1;
|
||||||
|
UINT32 is_stream : 1;
|
||||||
|
UINT32 dataOffset : 12;
|
||||||
|
UINT32 dataSize : 18;
|
||||||
|
|
||||||
PNET_BUFFER_LIST netBufList;
|
PNET_BUFFER_LIST netBufList;
|
||||||
|
|
||||||
@ -63,6 +77,7 @@ typedef struct fort_packet {
|
|||||||
union {
|
union {
|
||||||
FORT_PACKET_IN in;
|
FORT_PACKET_IN in;
|
||||||
FORT_PACKET_OUT out;
|
FORT_PACKET_OUT out;
|
||||||
|
FORT_PACKET_STREAM stream;
|
||||||
};
|
};
|
||||||
} FORT_PACKET, *PFORT_PACKET;
|
} FORT_PACKET, *PFORT_PACKET;
|
||||||
|
|
||||||
@ -74,33 +89,187 @@ typedef struct fort_defer_list {
|
|||||||
typedef struct fort_defer {
|
typedef struct fort_defer {
|
||||||
UINT32 list_bits;
|
UINT32 list_bits;
|
||||||
|
|
||||||
HANDLE injection4_id;
|
HANDLE transport_injection4_id;
|
||||||
|
HANDLE stream_injection4_id;
|
||||||
|
|
||||||
PFORT_PACKET packet_free;
|
PFORT_PACKET packet_free;
|
||||||
|
|
||||||
tommy_arrayof packets;
|
tommy_arrayof packets;
|
||||||
|
|
||||||
|
FORT_DEFER_LIST stream_list;
|
||||||
FORT_DEFER_LIST lists[FORT_DEFER_LIST_MAX]; /* in/out-bounds */
|
FORT_DEFER_LIST lists[FORT_DEFER_LIST_MAX]; /* in/out-bounds */
|
||||||
|
|
||||||
KSPIN_LOCK lock;
|
KSPIN_LOCK lock;
|
||||||
} FORT_DEFER, *PFORT_DEFER;
|
} FORT_DEFER, *PFORT_DEFER;
|
||||||
|
|
||||||
typedef void (*FORT_INJECT_COMPLETE_FUNC) (PFORT_PACKET, PNET_BUFFER_LIST, BOOLEAN);
|
typedef void (*FORT_INJECT_COMPLETE_FUNC) (PFORT_PACKET, PNET_BUFFER_LIST, BOOLEAN);
|
||||||
|
typedef NTSTATUS (*FORT_INJECT_FUNC) (PFORT_DEFER, PFORT_PACKET, PNET_BUFFER_LIST *, FORT_INJECT_COMPLETE_FUNC);
|
||||||
|
|
||||||
|
|
||||||
|
static NTSTATUS
|
||||||
|
fort_packet_inject_in (PFORT_DEFER defer,
|
||||||
|
PFORT_PACKET pkt,
|
||||||
|
PNET_BUFFER_LIST *clonedNetBufList,
|
||||||
|
FORT_INJECT_COMPLETE_FUNC complete_func)
|
||||||
|
{
|
||||||
|
PFORT_PACKET_IN pkt_in = &pkt->in;
|
||||||
|
PNET_BUFFER_LIST netBufList = pkt->netBufList;
|
||||||
|
PNET_BUFFER netBuffer = NET_BUFFER_LIST_FIRST_NB(netBufList);
|
||||||
|
NTSTATUS status;
|
||||||
|
|
||||||
|
/* The TCP/IP stack could have retreated the net buffer list by the
|
||||||
|
* transportHeaderSize amount; detect the condition here to avoid
|
||||||
|
* retreating twice.
|
||||||
|
*/
|
||||||
|
if (pkt->dataOffset != NET_BUFFER_DATA_OFFSET(netBuffer)) {
|
||||||
|
pkt_in->transportHeaderSize = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Adjust the net buffer list offset to the start of the IP header. */
|
||||||
|
NdisRetreatNetBufferDataStart(netBuffer,
|
||||||
|
pkt_in->ipHeaderSize + pkt_in->transportHeaderSize, 0, NULL);
|
||||||
|
|
||||||
|
status = FwpsAllocateCloneNetBufferList0(netBufList,
|
||||||
|
NULL, NULL, 0, clonedNetBufList);
|
||||||
|
|
||||||
|
/* Undo the adjustment on the original net buffer list. */
|
||||||
|
NdisAdvanceNetBufferDataStart(netBuffer,
|
||||||
|
pkt_in->ipHeaderSize + pkt_in->transportHeaderSize, FALSE, NULL);
|
||||||
|
|
||||||
|
if (NT_SUCCESS(status)) {
|
||||||
|
status = FwpsInjectTransportReceiveAsync0(
|
||||||
|
defer->transport_injection4_id, NULL, NULL, 0,
|
||||||
|
AF_INET, pkt_in->compartmentId,
|
||||||
|
pkt_in->interfaceIndex, pkt_in->subInterfaceIndex,
|
||||||
|
*clonedNetBufList, complete_func, pkt);
|
||||||
|
}
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
static NTSTATUS
|
||||||
|
fort_packet_inject_out (PFORT_DEFER defer,
|
||||||
|
PFORT_PACKET pkt,
|
||||||
|
PNET_BUFFER_LIST *clonedNetBufList,
|
||||||
|
FORT_INJECT_COMPLETE_FUNC complete_func)
|
||||||
|
{
|
||||||
|
PFORT_PACKET_OUT pkt_out = &pkt->out;
|
||||||
|
PNET_BUFFER_LIST netBufList = pkt->netBufList;
|
||||||
|
NTSTATUS status;
|
||||||
|
|
||||||
|
status = FwpsAllocateCloneNetBufferList0(netBufList,
|
||||||
|
NULL, NULL, 0, clonedNetBufList);
|
||||||
|
|
||||||
|
if (NT_SUCCESS(status)) {
|
||||||
|
FWPS_TRANSPORT_SEND_PARAMS0 send_args;
|
||||||
|
|
||||||
|
RtlZeroMemory(&send_args, sizeof(FWPS_TRANSPORT_SEND_PARAMS0));
|
||||||
|
send_args.remoteAddress = (UCHAR *) &pkt_out->remoteAddr4;
|
||||||
|
send_args.remoteScopeId = pkt_out->remoteScopeId;
|
||||||
|
|
||||||
|
status = FwpsInjectTransportSendAsync0(
|
||||||
|
defer->transport_injection4_id, NULL,
|
||||||
|
pkt_out->endpointHandle, 0,
|
||||||
|
&send_args, AF_INET, pkt_out->compartmentId,
|
||||||
|
*clonedNetBufList, complete_func, pkt);
|
||||||
|
}
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
static NTSTATUS
|
||||||
|
fort_packet_inject_stream (PFORT_DEFER defer,
|
||||||
|
PFORT_PACKET pkt,
|
||||||
|
PNET_BUFFER_LIST *clonedNetBufList,
|
||||||
|
FORT_INJECT_COMPLETE_FUNC complete_func)
|
||||||
|
{
|
||||||
|
PFORT_PACKET_STREAM pkt_stream = &pkt->stream;
|
||||||
|
PNET_BUFFER_LIST netBufList = pkt->netBufList;
|
||||||
|
PNET_BUFFER netBuffer = NET_BUFFER_LIST_FIRST_NB(netBufList);
|
||||||
|
NTSTATUS status;
|
||||||
|
|
||||||
|
/* Adjust the net buffer list offset to the start of the actual data. */
|
||||||
|
NdisAdvanceNetBufferDataStart(netBuffer, pkt->dataOffset, FALSE, NULL);
|
||||||
|
|
||||||
|
status = FwpsAllocateCloneNetBufferList0(netBufList,
|
||||||
|
NULL, NULL, 0, clonedNetBufList);
|
||||||
|
|
||||||
|
/* Undo the adjustment on the original net buffer list. */
|
||||||
|
NdisRetreatNetBufferDataStart(netBuffer, pkt->dataOffset, 0, NULL);
|
||||||
|
|
||||||
|
if (NT_SUCCESS(status)) {
|
||||||
|
status = FwpsStreamInjectAsync0(
|
||||||
|
defer->stream_injection4_id, NULL, 0,
|
||||||
|
pkt_stream->flowId, pkt_stream->calloutId,
|
||||||
|
pkt_stream->layerId, pkt_stream->streamFlags,
|
||||||
|
*clonedNetBufList, pkt->dataSize,
|
||||||
|
complete_func, pkt);
|
||||||
|
}
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
static BOOL
|
||||||
|
fort_packet_injected_by_self (PFORT_DEFER defer,
|
||||||
|
PNET_BUFFER_LIST netBufList)
|
||||||
|
{
|
||||||
|
const FWPS_PACKET_INJECTION_STATE state = FwpsQueryPacketInjectionState0(
|
||||||
|
defer->transport_injection4_id, netBufList, NULL);
|
||||||
|
|
||||||
|
return (state == FWPS_PACKET_INJECTED_BY_SELF
|
||||||
|
|| state == FWPS_PACKET_PREVIOUSLY_INJECTED_BY_SELF);
|
||||||
|
}
|
||||||
|
|
||||||
|
static PFORT_PACKET
|
||||||
|
fort_defer_packet_get (PFORT_DEFER defer)
|
||||||
|
{
|
||||||
|
PFORT_PACKET pkt = NULL;
|
||||||
|
|
||||||
|
if (defer->packet_free != NULL) {
|
||||||
|
pkt = defer->packet_free;
|
||||||
|
defer->packet_free = pkt->next;
|
||||||
|
} else {
|
||||||
|
const tommy_count_t size = tommy_arrayof_size(&defer->packets);
|
||||||
|
|
||||||
|
/* TODO: tommy_arrayof_grow(): check calloc()'s result for NULL */
|
||||||
|
tommy_arrayof_grow(&defer->packets, size + 1);
|
||||||
|
|
||||||
|
pkt = tommy_arrayof_ref(&defer->packets, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
return pkt;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
fort_defer_packet_put (PFORT_DEFER defer, PFORT_PACKET pkt)
|
||||||
|
{
|
||||||
|
pkt->next = defer->packet_free;
|
||||||
|
defer->packet_free = pkt;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
fort_defer_open (PFORT_DEFER defer)
|
fort_defer_open (PFORT_DEFER defer)
|
||||||
{
|
{
|
||||||
NTSTATUS status;
|
NTSTATUS status;
|
||||||
|
|
||||||
status = FwpsInjectionHandleCreate0(AF_INET, FWPS_INJECTION_TYPE_TRANSPORT,
|
status = FwpsInjectionHandleCreate0(AF_INET, FWPS_INJECTION_TYPE_TRANSPORT,
|
||||||
&defer->injection4_id);
|
&defer->transport_injection4_id);
|
||||||
|
|
||||||
if (!NT_SUCCESS(status)) {
|
if (!NT_SUCCESS(status)) {
|
||||||
defer->injection4_id = INVALID_HANDLE_VALUE;
|
defer->transport_injection4_id = INVALID_HANDLE_VALUE;
|
||||||
|
|
||||||
DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_ERROR_LEVEL,
|
DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_ERROR_LEVEL,
|
||||||
"FORT: Defer: Injection init error: %x\n", status);
|
"FORT: Defer: Transport injection init error: %x\n", status);
|
||||||
|
}
|
||||||
|
|
||||||
|
status = FwpsInjectionHandleCreate0(AF_INET, FWPS_INJECTION_TYPE_STREAM,
|
||||||
|
&defer->stream_injection4_id);
|
||||||
|
|
||||||
|
if (!NT_SUCCESS(status)) {
|
||||||
|
defer->stream_injection4_id = INVALID_HANDLE_VALUE;
|
||||||
|
|
||||||
|
DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_ERROR_LEVEL,
|
||||||
|
"FORT: Defer: Stream injection init error: %x\n", status);
|
||||||
}
|
}
|
||||||
|
|
||||||
tommy_arrayof_init(&defer->packets, sizeof(FORT_PACKET));
|
tommy_arrayof_init(&defer->packets, sizeof(FORT_PACKET));
|
||||||
@ -111,13 +280,14 @@ fort_defer_open (PFORT_DEFER defer)
|
|||||||
static void
|
static void
|
||||||
fort_defer_close (PFORT_DEFER defer)
|
fort_defer_close (PFORT_DEFER defer)
|
||||||
{
|
{
|
||||||
FwpsInjectionHandleDestroy0(defer->injection4_id);
|
FwpsInjectionHandleDestroy0(defer->transport_injection4_id);
|
||||||
|
FwpsInjectionHandleDestroy0(defer->stream_injection4_id);
|
||||||
|
|
||||||
tommy_arrayof_done(&defer->packets);
|
tommy_arrayof_done(&defer->packets);
|
||||||
}
|
}
|
||||||
|
|
||||||
static NTSTATUS
|
static NTSTATUS
|
||||||
fort_defer_add (PFORT_DEFER defer,
|
fort_defer_packet_add (PFORT_DEFER defer,
|
||||||
const FWPS_INCOMING_VALUES0 *inFixedValues,
|
const FWPS_INCOMING_VALUES0 *inFixedValues,
|
||||||
const FWPS_INCOMING_METADATA_VALUES0 *inMetaValues,
|
const FWPS_INCOMING_METADATA_VALUES0 *inMetaValues,
|
||||||
PNET_BUFFER_LIST netBufList,
|
PNET_BUFFER_LIST netBufList,
|
||||||
@ -129,18 +299,12 @@ fort_defer_add (PFORT_DEFER defer,
|
|||||||
UINT16 list_index;
|
UINT16 list_index;
|
||||||
NTSTATUS status;
|
NTSTATUS status;
|
||||||
|
|
||||||
if (defer->injection4_id == INVALID_HANDLE_VALUE)
|
if (defer->transport_injection4_id == INVALID_HANDLE_VALUE)
|
||||||
return STATUS_FWP_TCPIP_NOT_READY;
|
return STATUS_FWP_TCPIP_NOT_READY;
|
||||||
|
|
||||||
/* Skip self injected packet */
|
/* Skip self injected packet */
|
||||||
{
|
if (fort_packet_injected_by_self(defer, netBufList))
|
||||||
const FWPS_PACKET_INJECTION_STATE state = FwpsQueryPacketInjectionState0(
|
|
||||||
defer->injection4_id, netBufList, NULL);
|
|
||||||
|
|
||||||
if (state == FWPS_PACKET_INJECTED_BY_SELF
|
|
||||||
|| state == FWPS_PACKET_PREVIOUSLY_INJECTED_BY_SELF)
|
|
||||||
return STATUS_CANT_TERMINATE_SELF;
|
return STATUS_CANT_TERMINATE_SELF;
|
||||||
}
|
|
||||||
|
|
||||||
/* Skip IpSec protected packet */
|
/* Skip IpSec protected packet */
|
||||||
if (inbound) {
|
if (inbound) {
|
||||||
@ -163,21 +327,12 @@ fort_defer_add (PFORT_DEFER defer,
|
|||||||
|
|
||||||
defer_list = &defer->lists[list_index];
|
defer_list = &defer->lists[list_index];
|
||||||
|
|
||||||
if (defer->packet_free != NULL) {
|
pkt = fort_defer_packet_get(defer);
|
||||||
pkt = defer->packet_free;
|
if (pkt == NULL) {
|
||||||
defer->packet_free = pkt->next;
|
|
||||||
} else {
|
|
||||||
const tommy_count_t size = tommy_arrayof_size(&defer->packets);
|
|
||||||
|
|
||||||
/* TODO: tommy_arrayof_grow(): check calloc()'s result for NULL */
|
|
||||||
if (tommy_arrayof_grow(&defer->packets, size + 1), 0) {
|
|
||||||
status = STATUS_INSUFFICIENT_RESOURCES;
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
pkt = tommy_arrayof_ref(&defer->packets, size);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (defer_list->packet_tail == NULL) {
|
if (defer_list->packet_tail == NULL) {
|
||||||
defer_list->packet_head = defer_list->packet_tail = pkt;
|
defer_list->packet_head = defer_list->packet_tail = pkt;
|
||||||
} else {
|
} else {
|
||||||
@ -186,7 +341,9 @@ fort_defer_add (PFORT_DEFER defer,
|
|||||||
}
|
}
|
||||||
|
|
||||||
pkt->inbound = inbound;
|
pkt->inbound = inbound;
|
||||||
pkt->compartmentId = inMetaValues->compartmentId;
|
pkt->is_stream = FALSE;
|
||||||
|
pkt->dataOffset = 0;
|
||||||
|
pkt->dataSize = 0; /* not used */
|
||||||
pkt->netBufList = netBufList;
|
pkt->netBufList = netBufList;
|
||||||
pkt->next = NULL;
|
pkt->next = NULL;
|
||||||
|
|
||||||
@ -201,13 +358,15 @@ fort_defer_add (PFORT_DEFER defer,
|
|||||||
? FWPS_FIELD_INBOUND_TRANSPORT_V4_SUB_INTERFACE_INDEX
|
? FWPS_FIELD_INBOUND_TRANSPORT_V4_SUB_INTERFACE_INDEX
|
||||||
: FWPS_FIELD_OUTBOUND_TRANSPORT_V4_SUB_INTERFACE_INDEX;
|
: FWPS_FIELD_OUTBOUND_TRANSPORT_V4_SUB_INTERFACE_INDEX;
|
||||||
|
|
||||||
|
pkt_in->compartmentId = inMetaValues->compartmentId;
|
||||||
|
|
||||||
pkt_in->interfaceIndex = inFixedValues->incomingValue[interfaceField].value.uint32;
|
pkt_in->interfaceIndex = inFixedValues->incomingValue[interfaceField].value.uint32;
|
||||||
pkt_in->subInterfaceIndex = inFixedValues->incomingValue[subInterfaceField].value.uint32;
|
pkt_in->subInterfaceIndex = inFixedValues->incomingValue[subInterfaceField].value.uint32;
|
||||||
|
|
||||||
pkt_in->ipHeaderSize = (UINT16) inMetaValues->ipHeaderSize;
|
pkt_in->ipHeaderSize = (UINT16) inMetaValues->ipHeaderSize;
|
||||||
pkt_in->transportHeaderSize = (UINT16) inMetaValues->transportHeaderSize;
|
pkt_in->transportHeaderSize = (UINT16) inMetaValues->transportHeaderSize;
|
||||||
|
|
||||||
pkt_in->nblOffset = (UINT16) NET_BUFFER_DATA_OFFSET(
|
pkt->dataOffset = (UINT16) NET_BUFFER_DATA_OFFSET(
|
||||||
NET_BUFFER_LIST_FIRST_NB(netBufList));
|
NET_BUFFER_LIST_FIRST_NB(netBufList));
|
||||||
} else {
|
} else {
|
||||||
PFORT_PACKET_OUT pkt_out = &pkt->out;
|
PFORT_PACKET_OUT pkt_out = &pkt->out;
|
||||||
@ -216,6 +375,8 @@ fort_defer_add (PFORT_DEFER defer,
|
|||||||
? FWPS_FIELD_INBOUND_TRANSPORT_V4_IP_REMOTE_ADDRESS
|
? FWPS_FIELD_INBOUND_TRANSPORT_V4_IP_REMOTE_ADDRESS
|
||||||
: FWPS_FIELD_OUTBOUND_TRANSPORT_V4_IP_REMOTE_ADDRESS;
|
: FWPS_FIELD_OUTBOUND_TRANSPORT_V4_IP_REMOTE_ADDRESS;
|
||||||
|
|
||||||
|
pkt_out->compartmentId = inMetaValues->compartmentId;
|
||||||
|
|
||||||
/* host-order -> network-order conversion */
|
/* host-order -> network-order conversion */
|
||||||
pkt_out->remoteAddr4 = HTONL(
|
pkt_out->remoteAddr4 = HTONL(
|
||||||
inFixedValues->incomingValue[remoteAddrField].value.uint32);
|
inFixedValues->incomingValue[remoteAddrField].value.uint32);
|
||||||
@ -224,7 +385,7 @@ fort_defer_add (PFORT_DEFER defer,
|
|||||||
pkt_out->endpointHandle = inMetaValues->transportEndpointHandle;
|
pkt_out->endpointHandle = inMetaValues->transportEndpointHandle;
|
||||||
}
|
}
|
||||||
|
|
||||||
FwpsReferenceNetBufferList0(netBufList, TRUE);
|
FwpsReferenceNetBufferList0(pkt->netBufList, TRUE);
|
||||||
|
|
||||||
/* Set to be flushed bit */
|
/* Set to be flushed bit */
|
||||||
defer->list_bits |= (1 << list_index);
|
defer->list_bits |= (1 << list_index);
|
||||||
@ -237,8 +398,76 @@ fort_defer_add (PFORT_DEFER defer,
|
|||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static NTSTATUS
|
||||||
|
fort_defer_stream_add (PFORT_DEFER defer,
|
||||||
|
const FWPS_INCOMING_VALUES0 *inFixedValues,
|
||||||
|
const FWPS_INCOMING_METADATA_VALUES0 *inMetaValues,
|
||||||
|
const FWPS_STREAM_DATA0 *streamData,
|
||||||
|
const FWPS_FILTER0 *filter,
|
||||||
|
BOOL inbound)
|
||||||
|
{
|
||||||
|
KLOCK_QUEUE_HANDLE lock_queue;
|
||||||
|
PFORT_PACKET pkt;
|
||||||
|
NTSTATUS status;
|
||||||
|
|
||||||
|
if (defer->stream_injection4_id == INVALID_HANDLE_VALUE)
|
||||||
|
return STATUS_FWP_TCPIP_NOT_READY;
|
||||||
|
|
||||||
|
/* Check data offset compatibility */
|
||||||
|
{
|
||||||
|
const PNET_BUFFER netBuf = NET_BUFFER_LIST_FIRST_NB(streamData->netBufferListChain);
|
||||||
|
const FWPS_STREAM_DATA_OFFSET0 *dataOffset = &streamData->dataOffset;
|
||||||
|
|
||||||
|
if (dataOffset->streamDataOffset != 0
|
||||||
|
&& (dataOffset->netBuffer != netBuf
|
||||||
|
|| dataOffset->mdl != NET_BUFFER_CURRENT_MDL(netBuf)))
|
||||||
|
return STATUS_INVALID_PARAMETER;
|
||||||
|
}
|
||||||
|
|
||||||
|
KeAcquireInStackQueuedSpinLock(&defer->lock, &lock_queue);
|
||||||
|
|
||||||
|
pkt = fort_defer_packet_get(defer);
|
||||||
|
if (pkt == NULL) {
|
||||||
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (defer->stream_list.packet_tail == NULL) {
|
||||||
|
defer->stream_list.packet_head = defer->stream_list.packet_tail = pkt;
|
||||||
|
} else {
|
||||||
|
defer->stream_list.packet_tail->next = pkt;
|
||||||
|
defer->stream_list.packet_tail = pkt;
|
||||||
|
}
|
||||||
|
|
||||||
|
pkt->inbound = inbound;
|
||||||
|
pkt->is_stream = TRUE;
|
||||||
|
pkt->dataOffset = (UINT32) streamData->dataOffset.streamDataOffset;
|
||||||
|
pkt->dataSize = (UINT32) streamData->dataLength;
|
||||||
|
pkt->netBufList = streamData->netBufferListChain;
|
||||||
|
pkt->next = NULL;
|
||||||
|
|
||||||
|
{
|
||||||
|
PFORT_PACKET_STREAM pkt_stream = &pkt->stream;
|
||||||
|
|
||||||
|
pkt_stream->layerId = inFixedValues->layerId;
|
||||||
|
pkt_stream->streamFlags = streamData->flags;
|
||||||
|
pkt_stream->calloutId = filter->action.calloutId;
|
||||||
|
pkt_stream->flowId = inMetaValues->flowHandle;
|
||||||
|
}
|
||||||
|
|
||||||
|
FwpsReferenceNetBufferList0(pkt->netBufList, TRUE);
|
||||||
|
|
||||||
|
status = STATUS_SUCCESS;
|
||||||
|
|
||||||
|
end:
|
||||||
|
KeReleaseInStackQueuedSpinLock(&lock_queue);
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
fort_defer_free (PFORT_DEFER defer, PFORT_PACKET pkt,
|
fort_defer_packet_free (PFORT_DEFER defer,
|
||||||
|
PFORT_PACKET pkt,
|
||||||
PNET_BUFFER_LIST clonedNetBufList,
|
PNET_BUFFER_LIST clonedNetBufList,
|
||||||
BOOL dispatchLevel)
|
BOOL dispatchLevel)
|
||||||
{
|
{
|
||||||
@ -264,8 +493,7 @@ fort_defer_free (PFORT_DEFER defer, PFORT_PACKET pkt,
|
|||||||
KeAcquireInStackQueuedSpinLock(&defer->lock, &lock_queue);
|
KeAcquireInStackQueuedSpinLock(&defer->lock, &lock_queue);
|
||||||
}
|
}
|
||||||
|
|
||||||
pkt->next = defer->packet_free;
|
fort_defer_packet_put(defer, pkt);
|
||||||
defer->packet_free = pkt;
|
|
||||||
|
|
||||||
if (dispatchLevel) {
|
if (dispatchLevel) {
|
||||||
KeReleaseInStackQueuedSpinLockFromDpcLevel(&lock_queue);
|
KeReleaseInStackQueuedSpinLockFromDpcLevel(&lock_queue);
|
||||||
@ -274,91 +502,54 @@ fort_defer_free (PFORT_DEFER defer, PFORT_PACKET pkt,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static NTSTATUS
|
static void
|
||||||
fort_defer_inject_in (PFORT_DEFER defer, PFORT_PACKET pkt,
|
fort_defer_packet_inject (PFORT_DEFER defer,
|
||||||
PNET_BUFFER_LIST *clonedNetBufList,
|
PFORT_PACKET pkt,
|
||||||
FORT_INJECT_COMPLETE_FUNC complete_func)
|
FORT_INJECT_COMPLETE_FUNC complete_func,
|
||||||
|
BOOL dispatchLevel)
|
||||||
{
|
{
|
||||||
PFORT_PACKET_IN pkt_in = &pkt->in;
|
while (pkt != NULL) {
|
||||||
PNET_BUFFER_LIST netBufList = pkt->netBufList;
|
PFORT_PACKET pkt_next = pkt->next;
|
||||||
PNET_BUFFER netBuffer = NET_BUFFER_LIST_FIRST_NB(netBufList);
|
PNET_BUFFER_LIST clonedNetBufList = NULL;
|
||||||
NTSTATUS status;
|
NTSTATUS status;
|
||||||
|
|
||||||
/* The TCP/IP stack could have retreated the net buffer list by the
|
FORT_INJECT_FUNC inject_func = pkt->is_stream
|
||||||
* transportHeaderSize amount; detect the condition here to avoid
|
? &fort_packet_inject_stream
|
||||||
* retreating twice.
|
: (pkt->inbound ? &fort_packet_inject_in : &fort_packet_inject_out);
|
||||||
*/
|
|
||||||
if (pkt_in->nblOffset != NET_BUFFER_DATA_OFFSET(netBuffer)) {
|
status = inject_func(defer, pkt, &clonedNetBufList, complete_func);
|
||||||
pkt_in->transportHeaderSize = 0;
|
|
||||||
|
if (!NT_SUCCESS(status)) {
|
||||||
|
DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_ERROR_LEVEL,
|
||||||
|
"FORT: Defer: Injection prepare error: %x\n", status);
|
||||||
|
|
||||||
|
if (clonedNetBufList != NULL) {
|
||||||
|
clonedNetBufList->Status = STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Adjust the net buffer list offset to the start of the IP header. */
|
fort_defer_packet_free(defer, pkt, clonedNetBufList, dispatchLevel);
|
||||||
NdisRetreatNetBufferDataStart(netBuffer,
|
|
||||||
pkt_in->ipHeaderSize + pkt_in->transportHeaderSize, 0, NULL);
|
|
||||||
|
|
||||||
status = FwpsAllocateCloneNetBufferList0(netBufList,
|
|
||||||
NULL, NULL, 0, clonedNetBufList);
|
|
||||||
|
|
||||||
/* Undo the adjustment on the original net buffer list. */
|
|
||||||
NdisAdvanceNetBufferDataStart(netBuffer,
|
|
||||||
pkt_in->ipHeaderSize + pkt_in->transportHeaderSize, FALSE, NULL);
|
|
||||||
|
|
||||||
if (NT_SUCCESS(status)) {
|
|
||||||
status = FwpsInjectTransportReceiveAsync0(
|
|
||||||
defer->injection4_id, NULL, NULL, 0,
|
|
||||||
AF_INET, pkt->compartmentId,
|
|
||||||
pkt_in->interfaceIndex, pkt_in->subInterfaceIndex,
|
|
||||||
*clonedNetBufList, complete_func, pkt);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return status;
|
pkt = pkt_next;
|
||||||
}
|
}
|
||||||
|
|
||||||
static NTSTATUS
|
|
||||||
fort_defer_inject_out (PFORT_DEFER defer, PFORT_PACKET pkt,
|
|
||||||
PNET_BUFFER_LIST *clonedNetBufList,
|
|
||||||
FORT_INJECT_COMPLETE_FUNC complete_func)
|
|
||||||
{
|
|
||||||
PFORT_PACKET_OUT pkt_out = &pkt->out;
|
|
||||||
PNET_BUFFER_LIST netBufList = pkt->netBufList;
|
|
||||||
NTSTATUS status;
|
|
||||||
|
|
||||||
status = FwpsAllocateCloneNetBufferList0(netBufList,
|
|
||||||
NULL, NULL, 0, clonedNetBufList);
|
|
||||||
|
|
||||||
if (NT_SUCCESS(status)) {
|
|
||||||
FWPS_TRANSPORT_SEND_PARAMS0 send_args;
|
|
||||||
|
|
||||||
RtlZeroMemory(&send_args, sizeof(FWPS_TRANSPORT_SEND_PARAMS0));
|
|
||||||
send_args.remoteAddress = (UCHAR *) &pkt_out->remoteAddr4;
|
|
||||||
send_args.remoteScopeId = pkt_out->remoteScopeId;
|
|
||||||
|
|
||||||
status = FwpsInjectTransportSendAsync0(
|
|
||||||
defer->injection4_id, NULL,
|
|
||||||
pkt_out->endpointHandle, 0,
|
|
||||||
&send_args, AF_INET, pkt->compartmentId,
|
|
||||||
*clonedNetBufList, complete_func, pkt);
|
|
||||||
}
|
|
||||||
|
|
||||||
return status;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
fort_defer_flush (PFORT_DEFER defer,
|
fort_defer_packet_flush (PFORT_DEFER defer,
|
||||||
FORT_INJECT_COMPLETE_FUNC complete_func,
|
FORT_INJECT_COMPLETE_FUNC complete_func,
|
||||||
UINT32 list_bits,
|
UINT32 list_bits,
|
||||||
BOOL dispatchLevel)
|
BOOL dispatchLevel)
|
||||||
{
|
{
|
||||||
KLOCK_QUEUE_HANDLE lock_queue;
|
KLOCK_QUEUE_HANDLE lock_queue;
|
||||||
PFORT_DEFER_LIST defer_list;
|
PFORT_DEFER_LIST defer_list;
|
||||||
PFORT_PACKET pkt;
|
PFORT_PACKET pkt_chain;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
list_bits &= defer->list_bits;
|
list_bits &= defer->list_bits;
|
||||||
if (list_bits == 0)
|
if (list_bits == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
pkt = NULL;
|
pkt_chain = NULL;
|
||||||
|
|
||||||
if (dispatchLevel) {
|
if (dispatchLevel) {
|
||||||
KeAcquireInStackQueuedSpinLockAtDpcLevel(&defer->lock, &lock_queue);
|
KeAcquireInStackQueuedSpinLockAtDpcLevel(&defer->lock, &lock_queue);
|
||||||
@ -376,8 +567,8 @@ fort_defer_flush (PFORT_DEFER defer,
|
|||||||
defer_list = &defer->lists[i];
|
defer_list = &defer->lists[i];
|
||||||
|
|
||||||
if (defer_list->packet_head != NULL) {
|
if (defer_list->packet_head != NULL) {
|
||||||
defer_list->packet_tail->next = pkt;
|
defer_list->packet_tail->next = pkt_chain;
|
||||||
pkt = defer_list->packet_head;
|
pkt_chain = defer_list->packet_head;
|
||||||
|
|
||||||
defer_list->packet_head = defer_list->packet_tail = NULL;
|
defer_list->packet_head = defer_list->packet_tail = NULL;
|
||||||
}
|
}
|
||||||
@ -392,26 +583,61 @@ fort_defer_flush (PFORT_DEFER defer,
|
|||||||
KeReleaseInStackQueuedSpinLock(&lock_queue);
|
KeReleaseInStackQueuedSpinLock(&lock_queue);
|
||||||
}
|
}
|
||||||
|
|
||||||
while (pkt != NULL) {
|
fort_defer_packet_inject(defer, pkt_chain, complete_func, dispatchLevel);
|
||||||
PFORT_PACKET pkt_next = pkt->next;
|
|
||||||
PNET_BUFFER_LIST clonedNetBufList = NULL;
|
|
||||||
NTSTATUS status;
|
|
||||||
|
|
||||||
status = pkt->inbound
|
|
||||||
? fort_defer_inject_in(defer, pkt, &clonedNetBufList, complete_func)
|
|
||||||
: fort_defer_inject_out(defer, pkt, &clonedNetBufList, complete_func);
|
|
||||||
|
|
||||||
if (!NT_SUCCESS(status)) {
|
|
||||||
DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_ERROR_LEVEL,
|
|
||||||
"FORT: Defer: Injection prepare error: %x\n", status);
|
|
||||||
|
|
||||||
if (clonedNetBufList != NULL) {
|
|
||||||
clonedNetBufList->Status = STATUS_SUCCESS;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fort_defer_free(defer, pkt, clonedNetBufList, TRUE);
|
static void
|
||||||
|
fort_defer_stream_flush (PFORT_DEFER defer,
|
||||||
|
FORT_INJECT_COMPLETE_FUNC complete_func,
|
||||||
|
UINT64 flowId,
|
||||||
|
BOOL dispatchLevel)
|
||||||
|
{
|
||||||
|
KLOCK_QUEUE_HANDLE lock_queue;
|
||||||
|
PFORT_PACKET pkt_chain = NULL;
|
||||||
|
|
||||||
|
if (dispatchLevel) {
|
||||||
|
KeAcquireInStackQueuedSpinLockAtDpcLevel(&defer->lock, &lock_queue);
|
||||||
|
} else {
|
||||||
|
KeAcquireInStackQueuedSpinLock(&defer->lock, &lock_queue);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (flowId == FORT_DEFER_STREAM_ALL) {
|
||||||
|
pkt_chain = defer->stream_list.packet_head;
|
||||||
|
|
||||||
|
defer->stream_list.packet_head = defer->stream_list.packet_tail = NULL;
|
||||||
|
}
|
||||||
|
else if (defer->stream_list.packet_head != NULL) {
|
||||||
|
PFORT_PACKET pkt = defer->stream_list.packet_head;
|
||||||
|
|
||||||
|
do {
|
||||||
|
PFORT_PACKET pkt_next = pkt->next;
|
||||||
|
|
||||||
|
if (flowId == pkt->stream.flowId) {
|
||||||
|
if (pkt_chain != NULL) {
|
||||||
|
pkt_chain->next = pkt;
|
||||||
|
}
|
||||||
|
|
||||||
|
pkt->next = NULL;
|
||||||
|
pkt_chain = pkt;
|
||||||
|
|
||||||
|
if (pkt == defer->stream_list.packet_head) {
|
||||||
|
defer->stream_list.packet_head = pkt_next;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pkt == defer->stream_list.packet_tail) {
|
||||||
|
defer->stream_list.packet_tail = NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pkt = pkt_next;
|
pkt = pkt_next;
|
||||||
|
} while (pkt != NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (dispatchLevel) {
|
||||||
|
KeReleaseInStackQueuedSpinLockFromDpcLevel(&lock_queue);
|
||||||
|
} else {
|
||||||
|
KeReleaseInStackQueuedSpinLock(&lock_queue);
|
||||||
|
}
|
||||||
|
|
||||||
|
fort_defer_packet_inject(defer, pkt_chain, complete_func, dispatchLevel);
|
||||||
}
|
}
|
||||||
|
@ -41,28 +41,32 @@ typedef struct fort_stat_proc {
|
|||||||
struct fort_stat_proc *next_active;
|
struct fort_stat_proc *next_active;
|
||||||
} FORT_STAT_PROC, *PFORT_STAT_PROC;
|
} FORT_STAT_PROC, *PFORT_STAT_PROC;
|
||||||
|
|
||||||
#define FORT_STAT_FLOW_SPEED_LIMIT_IN 0x01
|
#define FORT_FLOW_SPEED_LIMIT_IN 0x01
|
||||||
#define FORT_STAT_FLOW_SPEED_LIMIT_OUT 0x02
|
#define FORT_FLOW_SPEED_LIMIT_OUT 0x02
|
||||||
#define FORT_STAT_FLOW_SPEED_LIMIT (FORT_STAT_FLOW_SPEED_LIMIT_IN | FORT_STAT_FLOW_SPEED_LIMIT_OUT)
|
#define FORT_FLOW_SPEED_LIMIT (FORT_FLOW_SPEED_LIMIT_IN | FORT_FLOW_SPEED_LIMIT_OUT)
|
||||||
#define FORT_STAT_FLOW_DEFER_IN 0x04
|
#define FORT_FLOW_DEFER_IN 0x04
|
||||||
#define FORT_STAT_FLOW_DEFER_OUT 0x08
|
#define FORT_FLOW_DEFER_OUT 0x08
|
||||||
|
#define FORT_FLOW_FRAGMENT 0x10
|
||||||
|
#define FORT_FLOW_FRAGMENT_DEFER 0x20
|
||||||
|
#define FORT_FLOW_FRAGMENTED 0x40
|
||||||
|
#define FORT_FLOW_XFLAGS (FORT_FLOW_FRAGMENT_DEFER | FORT_FLOW_FRAGMENTED)
|
||||||
|
|
||||||
typedef struct fort_stat_flow_opt {
|
typedef struct fort_flow_opt {
|
||||||
UCHAR volatile flags;
|
UCHAR volatile flags;
|
||||||
UCHAR group_index;
|
UCHAR group_index;
|
||||||
UINT16 proc_index;
|
UINT16 proc_index;
|
||||||
} FORT_STAT_FLOW_OPT, *PFORT_STAT_FLOW_OPT;
|
} FORT_FLOW_OPT, *PFORT_FLOW_OPT;
|
||||||
|
|
||||||
/* Synchronize with tommy_hashdyn_node! */
|
/* Synchronize with tommy_hashdyn_node! */
|
||||||
typedef struct fort_stat_flow {
|
typedef struct fort_flow {
|
||||||
struct fort_stat_flow *next;
|
struct fort_flow *next;
|
||||||
struct fort_stat_flow *prev;
|
struct fort_flow *prev;
|
||||||
|
|
||||||
union {
|
union {
|
||||||
#if defined(_WIN64)
|
#if defined(_WIN64)
|
||||||
UINT64 flow_id;
|
UINT64 flow_id;
|
||||||
#else
|
#else
|
||||||
FORT_STAT_FLOW_OPT opt;
|
FORT_FLOW_OPT opt;
|
||||||
#endif
|
#endif
|
||||||
void *data;
|
void *data;
|
||||||
};
|
};
|
||||||
@ -70,11 +74,11 @@ typedef struct fort_stat_flow {
|
|||||||
tommy_key_t flow_hash;
|
tommy_key_t flow_hash;
|
||||||
|
|
||||||
#if defined(_WIN64)
|
#if defined(_WIN64)
|
||||||
FORT_STAT_FLOW_OPT opt;
|
FORT_FLOW_OPT opt;
|
||||||
#else
|
#else
|
||||||
UINT64 flow_id;
|
UINT64 flow_id;
|
||||||
#endif
|
#endif
|
||||||
} FORT_STAT_FLOW, *PFORT_STAT_FLOW;
|
} FORT_FLOW, *PFORT_FLOW;
|
||||||
|
|
||||||
typedef struct fort_stat {
|
typedef struct fort_stat {
|
||||||
UCHAR volatile closed;
|
UCHAR volatile closed;
|
||||||
@ -83,7 +87,6 @@ typedef struct fort_stat {
|
|||||||
|
|
||||||
UINT16 proc_active_count;
|
UINT16 proc_active_count;
|
||||||
|
|
||||||
UINT32 limit_bits;
|
|
||||||
UINT32 group_flush_bits;
|
UINT32 group_flush_bits;
|
||||||
|
|
||||||
UINT32 stream4_id;
|
UINT32 stream4_id;
|
||||||
@ -94,7 +97,7 @@ typedef struct fort_stat {
|
|||||||
PFORT_STAT_PROC proc_free;
|
PFORT_STAT_PROC proc_free;
|
||||||
PFORT_STAT_PROC proc_active;
|
PFORT_STAT_PROC proc_active;
|
||||||
|
|
||||||
PFORT_STAT_FLOW flow_free;
|
PFORT_FLOW flow_free;
|
||||||
|
|
||||||
tommy_arrayof procs;
|
tommy_arrayof procs;
|
||||||
tommy_hashdyn procs_map;
|
tommy_hashdyn procs_map;
|
||||||
@ -102,17 +105,22 @@ typedef struct fort_stat {
|
|||||||
tommy_arrayof flows;
|
tommy_arrayof flows;
|
||||||
tommy_hashdyn flows_map;
|
tommy_hashdyn flows_map;
|
||||||
|
|
||||||
FORT_TRAF limits[FORT_CONF_GROUP_MAX];
|
FORT_CONF_GROUP conf_group;
|
||||||
|
|
||||||
FORT_STAT_GROUP groups[FORT_CONF_GROUP_MAX];
|
FORT_STAT_GROUP groups[FORT_CONF_GROUP_MAX];
|
||||||
|
|
||||||
KSPIN_LOCK lock;
|
KSPIN_LOCK lock;
|
||||||
} FORT_STAT, *PFORT_STAT;
|
} FORT_STAT, *PFORT_STAT;
|
||||||
|
|
||||||
#define fort_stat_proc_hash(process_id) tommy_inthash_u32((UINT32) (process_id))
|
#define fort_stat_proc_hash(process_id) tommy_inthash_u32((UINT32) (process_id))
|
||||||
#define fort_stat_flow_hash(flow_id) tommy_inthash_u32((UINT32) (flow_id))
|
#define fort_flow_hash(flow_id) tommy_inthash_u32((UINT32) (flow_id))
|
||||||
|
|
||||||
|
#define fort_stat_group_fragment(stat, group_index) \
|
||||||
|
((((stat)->conf_group.fragment_bits >> (group_index)) & 1) != 0 \
|
||||||
|
? FORT_FLOW_FRAGMENT : 0)
|
||||||
|
|
||||||
#define fort_stat_group_speed_limit(stat, group_index) \
|
#define fort_stat_group_speed_limit(stat, group_index) \
|
||||||
(((stat)->limit_bits >> ((group_index) * 2)) & 3)
|
(((stat)->conf_group.limit_bits >> ((group_index) * 2)) & 3)
|
||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -215,25 +223,25 @@ fort_stat_proc_add (PFORT_STAT stat, UINT32 process_id)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static UCHAR
|
static UCHAR
|
||||||
fort_stat_flow_flags (PFORT_STAT_FLOW flow)
|
fort_flow_flags_set (PFORT_FLOW flow, UCHAR flags)
|
||||||
{
|
{
|
||||||
return flow->opt.flags;
|
return InterlockedOr8(&flow->opt.flags, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
static UCHAR
|
||||||
|
fort_flow_flags_clear (PFORT_FLOW flow, UCHAR flags)
|
||||||
|
{
|
||||||
|
return InterlockedAnd8(&flow->opt.flags, ~flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
static UCHAR
|
||||||
|
fort_flow_flags (PFORT_FLOW flow)
|
||||||
|
{
|
||||||
|
return fort_flow_flags_set(flow, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
fort_stat_flow_flags_set (PFORT_STAT_FLOW flow, UCHAR flags)
|
fort_flow_context_set (PFORT_STAT stat, PFORT_FLOW flow)
|
||||||
{
|
|
||||||
flow->opt.flags |= flags;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
fort_stat_flow_flags_clear (PFORT_STAT_FLOW flow, UCHAR flags)
|
|
||||||
{
|
|
||||||
flow->opt.flags &= ~flags;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
fort_stat_flow_context_set (PFORT_STAT stat, PFORT_STAT_FLOW flow)
|
|
||||||
{
|
{
|
||||||
const UINT64 flow_id = flow->flow_id;
|
const UINT64 flow_id = flow->flow_id;
|
||||||
const UINT64 flowContext = (UINT64) flow;
|
const UINT64 flowContext = (UINT64) flow;
|
||||||
@ -245,7 +253,7 @@ fort_stat_flow_context_set (PFORT_STAT stat, PFORT_STAT_FLOW flow)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
fort_stat_flow_context_remove (PFORT_STAT stat, PFORT_STAT_FLOW flow)
|
fort_flow_context_remove (PFORT_STAT stat, PFORT_FLOW flow)
|
||||||
{
|
{
|
||||||
const UINT64 flow_id = flow->flow_id;
|
const UINT64 flow_id = flow->flow_id;
|
||||||
|
|
||||||
@ -256,15 +264,15 @@ fort_stat_flow_context_remove (PFORT_STAT stat, PFORT_STAT_FLOW flow)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
fort_stat_flow_close (PFORT_STAT_FLOW flow)
|
fort_flow_close (PFORT_FLOW flow)
|
||||||
{
|
{
|
||||||
flow->opt.proc_index = FORT_PROC_BAD_INDEX;
|
flow->opt.proc_index = FORT_PROC_BAD_INDEX;
|
||||||
}
|
}
|
||||||
|
|
||||||
static PFORT_STAT_FLOW
|
static PFORT_FLOW
|
||||||
fort_stat_flow_get (PFORT_STAT stat, UINT64 flow_id, tommy_key_t flow_hash)
|
fort_flow_get (PFORT_STAT stat, UINT64 flow_id, tommy_key_t flow_hash)
|
||||||
{
|
{
|
||||||
PFORT_STAT_FLOW flow = (PFORT_STAT_FLOW) tommy_hashdyn_bucket(
|
PFORT_FLOW flow = (PFORT_FLOW) tommy_hashdyn_bucket(
|
||||||
&stat->flows_map, flow_hash);
|
&stat->flows_map, flow_hash);
|
||||||
|
|
||||||
while (flow != NULL) {
|
while (flow != NULL) {
|
||||||
@ -277,7 +285,7 @@ fort_stat_flow_get (PFORT_STAT stat, UINT64 flow_id, tommy_key_t flow_hash)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
fort_stat_flow_free (PFORT_STAT stat, PFORT_STAT_FLOW flow)
|
fort_flow_free (PFORT_STAT stat, PFORT_FLOW flow)
|
||||||
{
|
{
|
||||||
const UINT16 proc_index = flow->opt.proc_index;
|
const UINT16 proc_index = flow->opt.proc_index;
|
||||||
|
|
||||||
@ -293,12 +301,12 @@ fort_stat_flow_free (PFORT_STAT stat, PFORT_STAT_FLOW flow)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static NTSTATUS
|
static NTSTATUS
|
||||||
fort_stat_flow_add (PFORT_STAT stat, UINT64 flow_id,
|
fort_flow_add (PFORT_STAT stat, UINT64 flow_id,
|
||||||
UCHAR group_index, UINT16 proc_index,
|
UCHAR group_index, UINT16 proc_index,
|
||||||
UCHAR speed_limit, BOOL is_reauth)
|
UCHAR fragment, UCHAR speed_limit, BOOL is_reauth)
|
||||||
{
|
{
|
||||||
const tommy_key_t flow_hash = fort_stat_flow_hash(flow_id);
|
const tommy_key_t flow_hash = fort_flow_hash(flow_id);
|
||||||
PFORT_STAT_FLOW flow = fort_stat_flow_get(stat, flow_id, flow_hash);
|
PFORT_FLOW flow = fort_flow_get(stat, flow_id, flow_hash);
|
||||||
BOOL is_new_flow = FALSE;
|
BOOL is_new_flow = FALSE;
|
||||||
|
|
||||||
if (flow == NULL) {
|
if (flow == NULL) {
|
||||||
@ -323,7 +331,7 @@ fort_stat_flow_add (PFORT_STAT stat, UINT64 flow_id,
|
|||||||
|
|
||||||
flow->flow_id = flow_id;
|
flow->flow_id = flow_id;
|
||||||
|
|
||||||
fort_stat_flow_context_set(stat, flow);
|
fort_flow_context_set(stat, flow);
|
||||||
|
|
||||||
is_new_flow = TRUE;
|
is_new_flow = TRUE;
|
||||||
} else {
|
} else {
|
||||||
@ -334,7 +342,8 @@ fort_stat_flow_add (PFORT_STAT stat, UINT64 flow_id,
|
|||||||
fort_stat_proc_inc(stat, proc_index);
|
fort_stat_proc_inc(stat, proc_index);
|
||||||
}
|
}
|
||||||
|
|
||||||
flow->opt.flags = speed_limit;
|
flow->opt.flags = fragment | speed_limit
|
||||||
|
| (is_new_flow ? 0 : (flow->opt.flags & FORT_FLOW_XFLAGS));
|
||||||
flow->opt.group_index = group_index;
|
flow->opt.group_index = group_index;
|
||||||
flow->opt.proc_index = proc_index;
|
flow->opt.proc_index = proc_index;
|
||||||
|
|
||||||
@ -347,7 +356,7 @@ fort_stat_open (PFORT_STAT stat)
|
|||||||
tommy_arrayof_init(&stat->procs, sizeof(FORT_STAT_PROC));
|
tommy_arrayof_init(&stat->procs, sizeof(FORT_STAT_PROC));
|
||||||
tommy_hashdyn_init(&stat->procs_map);
|
tommy_hashdyn_init(&stat->procs_map);
|
||||||
|
|
||||||
tommy_arrayof_init(&stat->flows, sizeof(FORT_STAT_FLOW));
|
tommy_arrayof_init(&stat->flows, sizeof(FORT_FLOW));
|
||||||
tommy_hashdyn_init(&stat->flows_map);
|
tommy_hashdyn_init(&stat->flows_map);
|
||||||
|
|
||||||
KeInitializeSpinLock(&stat->lock);
|
KeInitializeSpinLock(&stat->lock);
|
||||||
@ -363,7 +372,7 @@ fort_stat_close (PFORT_STAT stat)
|
|||||||
stat->closed = TRUE;
|
stat->closed = TRUE;
|
||||||
|
|
||||||
tommy_hashdyn_foreach_node_arg(&stat->flows_map,
|
tommy_hashdyn_foreach_node_arg(&stat->flows_map,
|
||||||
fort_stat_flow_context_remove, stat);
|
fort_flow_context_remove, stat);
|
||||||
|
|
||||||
tommy_arrayof_done(&stat->procs);
|
tommy_arrayof_done(&stat->procs);
|
||||||
tommy_hashdyn_done(&stat->procs_map);
|
tommy_hashdyn_done(&stat->procs_map);
|
||||||
@ -380,7 +389,7 @@ fort_stat_clear (PFORT_STAT stat)
|
|||||||
fort_stat_proc_active_clear(stat);
|
fort_stat_proc_active_clear(stat);
|
||||||
|
|
||||||
tommy_hashdyn_foreach_node_arg(&stat->procs_map, fort_stat_proc_free, stat);
|
tommy_hashdyn_foreach_node_arg(&stat->procs_map, fort_stat_proc_free, stat);
|
||||||
tommy_hashdyn_foreach_node(&stat->flows_map, fort_stat_flow_close);
|
tommy_hashdyn_foreach_node(&stat->flows_map, fort_flow_close);
|
||||||
|
|
||||||
RtlZeroMemory(stat->groups, sizeof(stat->groups));
|
RtlZeroMemory(stat->groups, sizeof(stat->groups));
|
||||||
}
|
}
|
||||||
@ -402,32 +411,26 @@ fort_stat_update (PFORT_STAT stat, BOOL log_stat)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
fort_stat_update_limits (PFORT_STAT stat, PFORT_CONF_IO conf_io)
|
fort_stat_conf_update (PFORT_STAT stat, PFORT_CONF_IO conf_io)
|
||||||
{
|
{
|
||||||
KLOCK_QUEUE_HANDLE lock_queue;
|
KLOCK_QUEUE_HANDLE lock_queue;
|
||||||
|
|
||||||
KeAcquireInStackQueuedSpinLock(&stat->lock, &lock_queue);
|
KeAcquireInStackQueuedSpinLock(&stat->lock, &lock_queue);
|
||||||
{
|
{
|
||||||
const UINT32 limit_bits = conf_io->limit_bits;
|
stat->conf_group = conf_io->conf_group;
|
||||||
|
|
||||||
stat->limit_bits = limit_bits;
|
|
||||||
|
|
||||||
if (limit_bits != 0) {
|
|
||||||
RtlCopyMemory(stat->limits, conf_io->limits, sizeof(stat->limits));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
KeReleaseInStackQueuedSpinLock(&lock_queue);
|
KeReleaseInStackQueuedSpinLock(&lock_queue);
|
||||||
}
|
}
|
||||||
|
|
||||||
static NTSTATUS
|
static NTSTATUS
|
||||||
fort_stat_flow_associate (PFORT_STAT stat, UINT64 flow_id,
|
fort_flow_associate (PFORT_STAT stat, UINT64 flow_id,
|
||||||
UINT32 process_id, UCHAR group_index,
|
UINT32 process_id, UCHAR group_index,
|
||||||
BOOL is_reauth, BOOL *is_new_proc)
|
BOOL is_reauth, BOOL *is_new_proc)
|
||||||
{
|
{
|
||||||
const tommy_key_t proc_hash = fort_stat_proc_hash(process_id);
|
const tommy_key_t proc_hash = fort_stat_proc_hash(process_id);
|
||||||
KLOCK_QUEUE_HANDLE lock_queue;
|
KLOCK_QUEUE_HANDLE lock_queue;
|
||||||
PFORT_STAT_PROC proc;
|
PFORT_STAT_PROC proc;
|
||||||
UCHAR speed_limit;
|
UCHAR fragment, speed_limit;
|
||||||
NTSTATUS status;
|
NTSTATUS status;
|
||||||
|
|
||||||
KeAcquireInStackQueuedSpinLock(&stat->lock, &lock_queue);
|
KeAcquireInStackQueuedSpinLock(&stat->lock, &lock_queue);
|
||||||
@ -455,10 +458,12 @@ fort_stat_flow_associate (PFORT_STAT stat, UINT64 flow_id,
|
|||||||
*is_new_proc = TRUE;
|
*is_new_proc = TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fragment = fort_stat_group_fragment(stat, group_index);
|
||||||
speed_limit = fort_stat_group_speed_limit(stat, group_index);
|
speed_limit = fort_stat_group_speed_limit(stat, group_index);
|
||||||
|
|
||||||
status = fort_stat_flow_add(stat, flow_id,
|
status = fort_flow_add(stat, flow_id,
|
||||||
group_index, proc->proc_index, speed_limit, is_reauth);
|
group_index, proc->proc_index,
|
||||||
|
fragment, speed_limit, is_reauth);
|
||||||
|
|
||||||
if (!NT_SUCCESS(status) && *is_new_proc) {
|
if (!NT_SUCCESS(status) && *is_new_proc) {
|
||||||
fort_stat_proc_free(stat, proc);
|
fort_stat_proc_free(stat, proc);
|
||||||
@ -471,27 +476,27 @@ fort_stat_flow_associate (PFORT_STAT stat, UINT64 flow_id,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
fort_stat_flow_delete (PFORT_STAT stat, UINT64 flowContext)
|
fort_flow_delete (PFORT_STAT stat, UINT64 flowContext)
|
||||||
{
|
{
|
||||||
KLOCK_QUEUE_HANDLE lock_queue;
|
KLOCK_QUEUE_HANDLE lock_queue;
|
||||||
PFORT_STAT_FLOW flow = (PFORT_STAT_FLOW) flowContext;
|
PFORT_FLOW flow = (PFORT_FLOW) flowContext;
|
||||||
|
|
||||||
if (stat->closed)
|
if (stat->closed)
|
||||||
return; /* double check to avoid deadlock after remove-flow-context */
|
return; /* double check to avoid deadlock after remove-flow-context */
|
||||||
|
|
||||||
KeAcquireInStackQueuedSpinLock(&stat->lock, &lock_queue);
|
KeAcquireInStackQueuedSpinLock(&stat->lock, &lock_queue);
|
||||||
if (!stat->closed) {
|
if (!stat->closed) {
|
||||||
fort_stat_flow_free(stat, flow);
|
fort_flow_free(stat, flow);
|
||||||
}
|
}
|
||||||
KeReleaseInStackQueuedSpinLock(&lock_queue);
|
KeReleaseInStackQueuedSpinLock(&lock_queue);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
fort_stat_flow_classify (PFORT_STAT stat, UINT64 flowContext,
|
fort_flow_classify (PFORT_STAT stat, UINT64 flowContext,
|
||||||
UINT32 data_len, BOOL inbound)
|
UINT32 data_len, BOOL inbound)
|
||||||
{
|
{
|
||||||
KLOCK_QUEUE_HANDLE lock_queue;
|
KLOCK_QUEUE_HANDLE lock_queue;
|
||||||
PFORT_STAT_FLOW flow = (PFORT_STAT_FLOW) flowContext;
|
PFORT_FLOW flow = (PFORT_FLOW) flowContext;
|
||||||
|
|
||||||
KeAcquireInStackQueuedSpinLock(&stat->lock, &lock_queue);
|
KeAcquireInStackQueuedSpinLock(&stat->lock, &lock_queue);
|
||||||
|
|
||||||
@ -500,18 +505,20 @@ fort_stat_flow_classify (PFORT_STAT stat, UINT64 flowContext,
|
|||||||
UINT32 *proc_bytes = inbound ? &proc->traf.in_bytes
|
UINT32 *proc_bytes = inbound ? &proc->traf.in_bytes
|
||||||
: &proc->traf.out_bytes;
|
: &proc->traf.out_bytes;
|
||||||
|
|
||||||
|
const UCHAR stat_flow_flags = fort_flow_flags(flow);
|
||||||
|
|
||||||
/* Add traffic to process */
|
/* Add traffic to process */
|
||||||
*proc_bytes += data_len;
|
*proc_bytes += data_len;
|
||||||
|
|
||||||
if (flow->opt.flags & (inbound ? FORT_STAT_FLOW_SPEED_LIMIT_IN
|
if (stat_flow_flags & (inbound ? FORT_FLOW_SPEED_LIMIT_IN
|
||||||
: FORT_STAT_FLOW_SPEED_LIMIT_OUT)) {
|
: FORT_FLOW_SPEED_LIMIT_OUT)) {
|
||||||
const UCHAR group_index = flow->opt.group_index;
|
const UCHAR group_index = flow->opt.group_index;
|
||||||
|
|
||||||
PFORT_STAT_GROUP group = &stat->groups[group_index];
|
PFORT_STAT_GROUP group = &stat->groups[group_index];
|
||||||
UINT32 *group_bytes = inbound ? &group->traf.in_bytes
|
UINT32 *group_bytes = inbound ? &group->traf.in_bytes
|
||||||
: &group->traf.out_bytes;
|
: &group->traf.out_bytes;
|
||||||
|
|
||||||
const PFORT_TRAF group_limit = &stat->limits[group_index];
|
const PFORT_TRAF group_limit = &stat->conf_group.limits[group_index];
|
||||||
const UINT32 limit_bytes = inbound ? group_limit->in_bytes
|
const UINT32 limit_bytes = inbound ? group_limit->in_bytes
|
||||||
: group_limit->out_bytes;
|
: group_limit->out_bytes;
|
||||||
|
|
||||||
@ -526,12 +533,12 @@ fort_stat_flow_classify (PFORT_STAT stat, UINT64 flowContext,
|
|||||||
/* Defer ACK */
|
/* Defer ACK */
|
||||||
{
|
{
|
||||||
const UCHAR defer_flag = inbound
|
const UCHAR defer_flag = inbound
|
||||||
? FORT_STAT_FLOW_DEFER_OUT : FORT_STAT_FLOW_DEFER_IN;
|
? FORT_FLOW_DEFER_OUT : FORT_FLOW_DEFER_IN;
|
||||||
|
|
||||||
if (defer_flow)
|
if (defer_flow)
|
||||||
fort_stat_flow_flags_set(flow, defer_flag);
|
fort_flow_flags_set(flow, defer_flag);
|
||||||
else
|
else
|
||||||
fort_stat_flow_flags_clear(flow, defer_flag);
|
fort_flow_flags_clear(flow, defer_flag);
|
||||||
}
|
}
|
||||||
|
|
||||||
stat->group_flush_bits |= (1 << list_index);
|
stat->group_flush_bits |= (1 << list_index);
|
||||||
@ -614,7 +621,7 @@ fort_stat_dpc_group_flush (PFORT_STAT stat)
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
group = &stat->groups[i];
|
group = &stat->groups[i];
|
||||||
group_limit = &stat->limits[i];
|
group_limit = &stat->conf_group.limits[i];
|
||||||
|
|
||||||
traf = group->traf;
|
traf = group->traf;
|
||||||
|
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
#define FORT_WORKER_REAUTH 0x01
|
#define FORT_WORKER_REAUTH 0x01
|
||||||
|
|
||||||
typedef struct fort_worker {
|
typedef struct fort_worker {
|
||||||
LONG volatile id_bits;
|
UCHAR volatile id_bits;
|
||||||
|
|
||||||
PIO_WORKITEM item;
|
PIO_WORKITEM item;
|
||||||
} FORT_WORKER, *PFORT_WORKER;
|
} FORT_WORKER, *PFORT_WORKER;
|
||||||
@ -27,7 +27,7 @@ static void
|
|||||||
fort_worker_callback (PVOID device, PVOID context, PIO_WORKITEM item)
|
fort_worker_callback (PVOID device, PVOID context, PIO_WORKITEM item)
|
||||||
{
|
{
|
||||||
PFORT_WORKER worker = (PFORT_WORKER) context;
|
PFORT_WORKER worker = (PFORT_WORKER) context;
|
||||||
const LONG id_bits = InterlockedAnd(&worker->id_bits, 0);
|
const UCHAR id_bits = InterlockedAnd8(&worker->id_bits, 0);
|
||||||
|
|
||||||
UNUSED(device);
|
UNUSED(device);
|
||||||
UNUSED(item);
|
UNUSED(item);
|
||||||
@ -38,9 +38,9 @@ fort_worker_callback (PVOID device, PVOID context, PIO_WORKITEM item)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
fort_worker_queue (PFORT_WORKER worker, int work_id)
|
fort_worker_queue (PFORT_WORKER worker, UCHAR work_id)
|
||||||
{
|
{
|
||||||
const LONG id_bits = InterlockedOr(&worker->id_bits, work_id);
|
const UCHAR id_bits = InterlockedOr8(&worker->id_bits, work_id);
|
||||||
|
|
||||||
if (id_bits == 0) {
|
if (id_bits == 0) {
|
||||||
IoQueueWorkItemEx(worker->item, &fort_worker_callback,
|
IoQueueWorkItemEx(worker->item, &fort_worker_callback,
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
AppGroup::AppGroup(QObject *parent) :
|
AppGroup::AppGroup(QObject *parent) :
|
||||||
QObject(parent),
|
QObject(parent),
|
||||||
m_enabled(true),
|
m_enabled(true),
|
||||||
|
m_fragmentPacket(false),
|
||||||
m_periodEnabled(false),
|
m_periodEnabled(false),
|
||||||
m_periodFrom(0),
|
m_periodFrom(0),
|
||||||
m_periodTo(0),
|
m_periodTo(0),
|
||||||
@ -24,6 +25,14 @@ void AppGroup::setEnabled(bool enabled)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AppGroup::setFragmentPacket(bool enabled)
|
||||||
|
{
|
||||||
|
if (bool(m_fragmentPacket) != enabled) {
|
||||||
|
m_fragmentPacket = enabled;
|
||||||
|
emit fragmentPacketChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void AppGroup::setPeriodEnabled(bool periodEnabled)
|
void AppGroup::setPeriodEnabled(bool periodEnabled)
|
||||||
{
|
{
|
||||||
if (bool(m_periodEnabled) != periodEnabled) {
|
if (bool(m_periodEnabled) != periodEnabled) {
|
||||||
@ -108,15 +117,20 @@ QString AppGroup::label() const
|
|||||||
{
|
{
|
||||||
QString text = name();
|
QString text = name();
|
||||||
|
|
||||||
if (limitInEnabled() && speedLimitIn() != 0) {
|
if (fragmentPacket()) {
|
||||||
text += QLatin1Char(' ')
|
text += QLatin1Char(' ')
|
||||||
+ QChar(0x2207) // ∇
|
+ QChar(0x00F7); // ÷
|
||||||
|
}
|
||||||
|
|
||||||
|
if (enabledSpeedLimitIn() != 0) {
|
||||||
|
text += QLatin1Char(' ')
|
||||||
|
+ QChar(0x25BC) // ▼
|
||||||
+ NetUtil::formatSpeed(speedLimitIn() * 1024);
|
+ NetUtil::formatSpeed(speedLimitIn() * 1024);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (limitOutEnabled() && speedLimitOut() != 0) {
|
if (enabledSpeedLimitOut() != 0) {
|
||||||
text += QLatin1Char(' ')
|
text += QLatin1Char(' ')
|
||||||
+ QChar(0x2206) // ∆
|
+ QChar(0x25B2) // ▲
|
||||||
+ NetUtil::formatSpeed(speedLimitOut() * 1024);
|
+ NetUtil::formatSpeed(speedLimitOut() * 1024);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -132,6 +146,8 @@ QVariant AppGroup::toVariant() const
|
|||||||
{
|
{
|
||||||
QVariantMap map;
|
QVariantMap map;
|
||||||
|
|
||||||
|
map["fragmentPacket"] = fragmentPacket();
|
||||||
|
|
||||||
map["periodEnabled"] = periodEnabled();
|
map["periodEnabled"] = periodEnabled();
|
||||||
map["periodFrom"] = periodFrom();
|
map["periodFrom"] = periodFrom();
|
||||||
map["periodTo"] = periodTo();
|
map["periodTo"] = periodTo();
|
||||||
@ -152,6 +168,8 @@ void AppGroup::fromVariant(const QVariant &v)
|
|||||||
{
|
{
|
||||||
const QVariantMap map = v.toMap();
|
const QVariantMap map = v.toMap();
|
||||||
|
|
||||||
|
m_fragmentPacket = map["fragmentPacket"].toBool();
|
||||||
|
|
||||||
m_periodEnabled = map["periodEnabled"].toBool();
|
m_periodEnabled = map["periodEnabled"].toBool();
|
||||||
m_periodFrom = map["periodFrom"].toInt();
|
m_periodFrom = map["periodFrom"].toInt();
|
||||||
m_periodTo = map["periodTo"].toInt();
|
m_periodTo = map["periodTo"].toInt();
|
||||||
|
@ -8,6 +8,7 @@ class AppGroup : public QObject
|
|||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
Q_PROPERTY(bool enabled READ enabled WRITE setEnabled NOTIFY enabledChanged)
|
Q_PROPERTY(bool enabled READ enabled WRITE setEnabled NOTIFY enabledChanged)
|
||||||
|
Q_PROPERTY(bool fragmentPacket READ fragmentPacket WRITE setFragmentPacket NOTIFY fragmentPacketChanged)
|
||||||
Q_PROPERTY(bool periodEnabled READ periodEnabled WRITE setPeriodEnabled NOTIFY periodEnabledChanged)
|
Q_PROPERTY(bool periodEnabled READ periodEnabled WRITE setPeriodEnabled NOTIFY periodEnabledChanged)
|
||||||
Q_PROPERTY(int periodFrom READ periodFrom WRITE setPeriodFrom NOTIFY periodFromChanged)
|
Q_PROPERTY(int periodFrom READ periodFrom WRITE setPeriodFrom NOTIFY periodFromChanged)
|
||||||
Q_PROPERTY(int periodTo READ periodTo WRITE setPeriodTo NOTIFY periodToChanged)
|
Q_PROPERTY(int periodTo READ periodTo WRITE setPeriodTo NOTIFY periodToChanged)
|
||||||
@ -25,6 +26,9 @@ public:
|
|||||||
bool enabled() const { return m_enabled; }
|
bool enabled() const { return m_enabled; }
|
||||||
void setEnabled(bool enabled);
|
void setEnabled(bool enabled);
|
||||||
|
|
||||||
|
bool fragmentPacket() const { return m_fragmentPacket; }
|
||||||
|
void setFragmentPacket(bool enabled);
|
||||||
|
|
||||||
bool periodEnabled() const { return m_periodEnabled; }
|
bool periodEnabled() const { return m_periodEnabled; }
|
||||||
void setPeriodEnabled(bool periodEnabled);
|
void setPeriodEnabled(bool periodEnabled);
|
||||||
|
|
||||||
@ -46,6 +50,13 @@ public:
|
|||||||
quint32 speedLimitOut() const { return m_speedLimitOut; }
|
quint32 speedLimitOut() const { return m_speedLimitOut; }
|
||||||
void setSpeedLimitOut(quint32 limit);
|
void setSpeedLimitOut(quint32 limit);
|
||||||
|
|
||||||
|
quint32 enabledSpeedLimitIn() const {
|
||||||
|
return limitInEnabled() ? speedLimitIn() : 0;
|
||||||
|
}
|
||||||
|
quint32 enabledSpeedLimitOut() const {
|
||||||
|
return limitOutEnabled() ? speedLimitOut() : 0;
|
||||||
|
}
|
||||||
|
|
||||||
QString name() const { return m_name; }
|
QString name() const { return m_name; }
|
||||||
void setName(const QString &name);
|
void setName(const QString &name);
|
||||||
|
|
||||||
@ -62,6 +73,7 @@ public:
|
|||||||
|
|
||||||
signals:
|
signals:
|
||||||
void enabledChanged();
|
void enabledChanged();
|
||||||
|
void fragmentPacketChanged();
|
||||||
void periodEnabledChanged();
|
void periodEnabledChanged();
|
||||||
void periodFromChanged();
|
void periodFromChanged();
|
||||||
void periodToChanged();
|
void periodToChanged();
|
||||||
@ -78,6 +90,8 @@ public slots:
|
|||||||
private:
|
private:
|
||||||
uint m_enabled : 1;
|
uint m_enabled : 1;
|
||||||
|
|
||||||
|
uint m_fragmentPacket : 1;
|
||||||
|
|
||||||
uint m_periodEnabled : 1;
|
uint m_periodEnabled : 1;
|
||||||
uint m_periodFrom : 5;
|
uint m_periodFrom : 5;
|
||||||
uint m_periodTo : 5;
|
uint m_periodTo : 5;
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
<file>images/application_double.png</file>
|
<file>images/application_double.png</file>
|
||||||
<file>images/application_edit.png</file>
|
<file>images/application_edit.png</file>
|
||||||
<file>images/application_error.png</file>
|
<file>images/application_error.png</file>
|
||||||
|
<file>images/application_key.png</file>
|
||||||
<file>images/arrow_refresh.png</file>
|
<file>images/arrow_refresh.png</file>
|
||||||
<file>images/bin_empty.png</file>
|
<file>images/bin_empty.png</file>
|
||||||
<file>images/cancel.png</file>
|
<file>images/cancel.png</file>
|
||||||
@ -17,8 +18,6 @@
|
|||||||
<file>images/cross.png</file>
|
<file>images/cross.png</file>
|
||||||
<file>images/cut.png</file>
|
<file>images/cut.png</file>
|
||||||
<file>images/database_save.png</file>
|
<file>images/database_save.png</file>
|
||||||
<file>images/flag_green.png</file>
|
|
||||||
<file>images/flag_yellow.png</file>
|
|
||||||
<file>images/link.png</file>
|
<file>images/link.png</file>
|
||||||
<file>images/page_copy.png</file>
|
<file>images/page_copy.png</file>
|
||||||
<file>images/page_paste.png</file>
|
<file>images/page_paste.png</file>
|
||||||
|
@ -32,7 +32,7 @@
|
|||||||
<file>qml/pages/addresses/AddressGroupRow.qml</file>
|
<file>qml/pages/addresses/AddressGroupRow.qml</file>
|
||||||
<file>qml/pages/apps/AppsColumn.qml</file>
|
<file>qml/pages/apps/AppsColumn.qml</file>
|
||||||
<file>qml/pages/apps/AppsTextColumn.qml</file>
|
<file>qml/pages/apps/AppsTextColumn.qml</file>
|
||||||
<file>qml/pages/apps/SpeedLimitButton.qml</file>
|
<file>qml/pages/apps/GroupOptionsButton.qml</file>
|
||||||
<file>qml/pages/log/AppListView.qml</file>
|
<file>qml/pages/log/AppListView.qml</file>
|
||||||
<file>qml/pages/log/GraphButton.qml</file>
|
<file>qml/pages/log/GraphButton.qml</file>
|
||||||
<file>qml/pages/log/IpListView.qml</file>
|
<file>qml/pages/log/IpListView.qml</file>
|
||||||
|
@ -271,10 +271,10 @@ void GraphWindow::updateWindowTitleSpeed()
|
|||||||
const auto outBytes = m_graphOut->data()->isEmpty()
|
const auto outBytes = m_graphOut->data()->isEmpty()
|
||||||
? 0 : (m_graphOut->data()->constEnd() - 1)->mainValue();
|
? 0 : (m_graphOut->data()->constEnd() - 1)->mainValue();
|
||||||
|
|
||||||
setWindowTitle(QChar(0x2207) // ∇
|
setWindowTitle(QChar(0x25BC) // ▼
|
||||||
+ NetUtil::formatSpeed(quint32(inBytes))
|
+ NetUtil::formatSpeed(quint32(inBytes))
|
||||||
+ QLatin1Char(' ')
|
+ QLatin1Char(' ')
|
||||||
+ QChar(0x2206) // ∆
|
+ QChar(0x25B2) // ▲
|
||||||
+ NetUtil::formatSpeed(quint32(outBytes))
|
+ NetUtil::formatSpeed(quint32(outBytes))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
Binary file not shown.
@ -315,22 +315,22 @@
|
|||||||
<translation>Сдвинуть направо</translation>
|
<translation>Сдвинуть направо</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../qml/pages/apps/AppsColumn.qml" line="47"/>
|
<location filename="../qml/pages/apps/AppsColumn.qml" line="49"/>
|
||||||
<source>Enabled</source>
|
<source>Enabled</source>
|
||||||
<translation>Включено</translation>
|
<translation>Включено</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../qml/pages/apps/AppsColumn.qml" line="62"/>
|
<location filename="../qml/pages/apps/AppsColumn.qml" line="64"/>
|
||||||
<source>period, hours:</source>
|
<source>period, hours:</source>
|
||||||
<translation>период, часы</translation>
|
<translation>период, часы</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../qml/pages/apps/AppsColumn.qml" line="101"/>
|
<location filename="../qml/pages/apps/AppsColumn.qml" line="103"/>
|
||||||
<source>Block</source>
|
<source>Block</source>
|
||||||
<translation>Блокировать</translation>
|
<translation>Блокировать</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../qml/pages/apps/AppsColumn.qml" line="121"/>
|
<location filename="../qml/pages/apps/AppsColumn.qml" line="123"/>
|
||||||
<source>Allow</source>
|
<source>Allow</source>
|
||||||
<translation>Разрешить</translation>
|
<translation>Разрешить</translation>
|
||||||
</message>
|
</message>
|
||||||
@ -486,10 +486,16 @@
|
|||||||
<translation>Ограничение скорости выгрузки, KiB/s:</translation>
|
<translation>Ограничение скорости выгрузки, KiB/s:</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/pages/apps/GroupOptionsButton.qml" line="11"/>
|
||||||
<location filename="../qml/pages/log/TrafOptionsButton.qml" line="11"/>
|
<location filename="../qml/pages/log/TrafOptionsButton.qml" line="11"/>
|
||||||
<source>Options…</source>
|
<source>Options…</source>
|
||||||
<translation>Настройки…</translation>
|
<translation>Настройки…</translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../qml/pages/apps/GroupOptionsButton.qml" line="16"/>
|
||||||
|
<source>Fragment first TCP packet</source>
|
||||||
|
<translation>Фрагментировать первый TCP пакет</translation>
|
||||||
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../qml/pages/log/TrafOptionsButton.qml" line="21"/>
|
<location filename="../qml/pages/log/TrafOptionsButton.qml" line="21"/>
|
||||||
<location filename="../qml/pages/log/TrafOptionsButton.qml" line="36"/>
|
<location filename="../qml/pages/log/TrafOptionsButton.qml" line="36"/>
|
||||||
|
BIN
src/ui/images/application_key.png
Normal file
BIN
src/ui/images/application_key.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 670 B |
Binary file not shown.
Before Width: | Height: | Size: 672 B |
Binary file not shown.
Before Width: | Height: | Size: 671 B |
@ -50,7 +50,7 @@ Page {
|
|||||||
: fortManager.applyConf(confFlagsOnly);
|
: fortManager.applyConf(confFlagsOnly);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (confSaved) {
|
if (confSaved && othersEdited) {
|
||||||
mainPage.saved();
|
mainPage.saved();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,7 +33,7 @@ ColumnLayout {
|
|||||||
Layout.preferredWidth: 10
|
Layout.preferredWidth: 10
|
||||||
}
|
}
|
||||||
|
|
||||||
SpeedLimitButton {
|
GroupOptionsButton {
|
||||||
enabled: firewallConf.logStat
|
enabled: firewallConf.logStat
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,13 +6,9 @@ import com.fortfirewall 1.0
|
|||||||
|
|
||||||
ButtonPopup {
|
ButtonPopup {
|
||||||
|
|
||||||
icon.source: !((appGroup.limitInEnabled && appGroup.speedLimitIn)
|
icon.source: "qrc:/images/application_key.png"
|
||||||
|| (appGroup.limitOutEnabled && appGroup.speedLimitOut))
|
text: translationManager.trTrigger
|
||||||
? "qrc:/images/flag_green.png"
|
&& qsTranslate("qml", "Options…")
|
||||||
: "qrc:/images/flag_yellow.png"
|
|
||||||
text: (translationManager.trTrigger
|
|
||||||
&& qsTranslate("qml", "Speed Limit: "))
|
|
||||||
+ speedLimitsText
|
|
||||||
|
|
||||||
readonly property var speedLimitValues: [
|
readonly property var speedLimitValues: [
|
||||||
10, 0, 20, 30, 50, 75, 100, 150, 200, 300, 500, 900,
|
10, 0, 20, 30, 50, 75, 100, 150, 200, 300, 500, 900,
|
||||||
@ -32,28 +28,6 @@ ButtonPopup {
|
|||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
readonly property var speedLimitDisabledText: speedLimitNames[1]
|
|
||||||
|
|
||||||
readonly property string speedLimitsText: {
|
|
||||||
const limitIn = appGroup.limitInEnabled
|
|
||||||
? appGroup.speedLimitIn : 0;
|
|
||||||
const limitOut = appGroup.limitOutEnabled
|
|
||||||
? appGroup.speedLimitOut : 0;
|
|
||||||
|
|
||||||
if (!(limitIn || limitOut))
|
|
||||||
return speedLimitDisabledText;
|
|
||||||
|
|
||||||
var text = "";
|
|
||||||
if (limitIn) {
|
|
||||||
text = "DL " + formatSpeed(limitIn);
|
|
||||||
}
|
|
||||||
if (limitOut) {
|
|
||||||
text += (text ? "; " : "")
|
|
||||||
+ "UL " + formatSpeed(limitOut);
|
|
||||||
}
|
|
||||||
return text;
|
|
||||||
}
|
|
||||||
|
|
||||||
function formatSpeed(kbytes) {
|
function formatSpeed(kbytes) {
|
||||||
return netUtil.formatSpeed(kbytes * 1024);
|
return netUtil.formatSpeed(kbytes * 1024);
|
||||||
}
|
}
|
||||||
@ -108,5 +82,18 @@ ButtonPopup {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
HSeparator {}
|
||||||
|
|
||||||
|
CheckBox {
|
||||||
|
text: translationManager.trTrigger
|
||||||
|
&& qsTranslate("qml", "Fragment first TCP packet")
|
||||||
|
checked: appGroup.fragmentPacket
|
||||||
|
onToggled: {
|
||||||
|
appGroup.fragmentPacket = checked;
|
||||||
|
|
||||||
|
setConfEdited();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -97,6 +97,7 @@ int ConfUtil::writeFlags(const FirewallConf &conf, QByteArray &buf)
|
|||||||
confFlags->app_allow_all = conf.appAllowAll();
|
confFlags->app_allow_all = conf.appAllowAll();
|
||||||
confFlags->log_blocked = conf.logBlocked();
|
confFlags->log_blocked = conf.logBlocked();
|
||||||
confFlags->log_stat = conf.logStat();
|
confFlags->log_stat = conf.logStat();
|
||||||
|
confFlags->filter_transport = appGroupFilterTransport(conf);
|
||||||
confFlags->group_bits = conf.appGroupBits();
|
confFlags->group_bits = conf.appGroupBits();
|
||||||
|
|
||||||
return flagsSize;
|
return flagsSize;
|
||||||
@ -313,8 +314,10 @@ void ConfUtil::writeData(char *output, const FirewallConf &conf,
|
|||||||
|
|
||||||
drvConfIo->driver_version = DRIVER_VERSION;
|
drvConfIo->driver_version = DRIVER_VERSION;
|
||||||
|
|
||||||
drvConfIo->limit_bits = writeLimits(
|
drvConfIo->conf_group.fragment_bits = appGroupFragmentBits(conf);
|
||||||
drvConfIo->limits, conf.appGroupsList());
|
|
||||||
|
drvConfIo->conf_group.limit_bits = writeLimits(
|
||||||
|
drvConfIo->conf_group.limits, conf.appGroupsList());
|
||||||
|
|
||||||
drvConf->flags.prov_boot = conf.provBoot();
|
drvConf->flags.prov_boot = conf.provBoot();
|
||||||
drvConf->flags.filter_enabled = conf.filterEnabled();
|
drvConf->flags.filter_enabled = conf.filterEnabled();
|
||||||
@ -328,6 +331,8 @@ void ConfUtil::writeData(char *output, const FirewallConf &conf,
|
|||||||
drvConf->flags.log_blocked = conf.logBlocked();
|
drvConf->flags.log_blocked = conf.logBlocked();
|
||||||
drvConf->flags.log_stat = conf.logStat();
|
drvConf->flags.log_stat = conf.logStat();
|
||||||
|
|
||||||
|
drvConf->flags.filter_transport = appGroupFilterTransport(conf);
|
||||||
|
|
||||||
drvConf->flags.group_bits = conf.appGroupBits();
|
drvConf->flags.group_bits = conf.appGroupBits();
|
||||||
|
|
||||||
FortCommon::confAppPermsMaskInit(drvConf);
|
FortCommon::confAppPermsMaskInit(drvConf);
|
||||||
@ -343,6 +348,37 @@ void ConfUtil::writeData(char *output, const FirewallConf &conf,
|
|||||||
drvConf->apps_off = appPathsOff;
|
drvConf->apps_off = appPathsOff;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
quint16 ConfUtil::appGroupFragmentBits(const FirewallConf &conf)
|
||||||
|
{
|
||||||
|
quint16 fragmentBits = 0;
|
||||||
|
int i = 0;
|
||||||
|
foreach (const AppGroup *appGroup, conf.appGroupsList()) {
|
||||||
|
if (appGroup->enabled() && appGroup->fragmentPacket()) {
|
||||||
|
fragmentBits |= (1 << i);
|
||||||
|
}
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
return fragmentBits;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ConfUtil::appGroupFilterTransport(const FirewallConf &conf)
|
||||||
|
{
|
||||||
|
foreach (const AppGroup *appGroup, conf.appGroupsList()) {
|
||||||
|
if (!appGroup->enabled())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Fragment
|
||||||
|
if (appGroup->fragmentPacket())
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// Speed limit
|
||||||
|
if (appGroup->enabledSpeedLimitIn() != 0
|
||||||
|
|| appGroup->enabledSpeedLimitOut() != 0)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
quint32 ConfUtil::writeLimits(struct fort_traf *limits,
|
quint32 ConfUtil::writeLimits(struct fort_traf *limits,
|
||||||
const QList<AppGroup *> &appGroups)
|
const QList<AppGroup *> &appGroups)
|
||||||
{
|
{
|
||||||
@ -353,10 +389,11 @@ quint32 ConfUtil::writeLimits(struct fort_traf *limits,
|
|||||||
for (int i = 0; i < groupsCount; ++i, ++limit) {
|
for (int i = 0; i < groupsCount; ++i, ++limit) {
|
||||||
const AppGroup *appGroup = appGroups.at(i);
|
const AppGroup *appGroup = appGroups.at(i);
|
||||||
|
|
||||||
limit->in_bytes = appGroup->enabled() && appGroup->limitInEnabled()
|
if (!appGroup->enabled())
|
||||||
? appGroup->speedLimitIn() * 1024 / 2 : 0;
|
continue;
|
||||||
limit->out_bytes = appGroup->enabled() && appGroup->limitOutEnabled()
|
|
||||||
? appGroup->speedLimitOut() * 1024 / 2 : 0;
|
limit->in_bytes = appGroup->enabledSpeedLimitIn() * 1024 / 2;
|
||||||
|
limit->out_bytes = appGroup->enabledSpeedLimitOut() * 1024 / 2;
|
||||||
|
|
||||||
if (limit->in_bytes) {
|
if (limit->in_bytes) {
|
||||||
limitBits |= (1 << (i * 2));
|
limitBits |= (1 << (i * 2));
|
||||||
|
@ -73,6 +73,9 @@ private:
|
|||||||
quint8 appPeriodsCount,
|
quint8 appPeriodsCount,
|
||||||
const appgroups_map_t &appGroupIndexes);
|
const appgroups_map_t &appGroupIndexes);
|
||||||
|
|
||||||
|
static quint16 appGroupFragmentBits(const FirewallConf &conf);
|
||||||
|
static bool appGroupFilterTransport(const FirewallConf &conf);
|
||||||
|
|
||||||
static quint32 writeLimits(struct fort_traf *limits,
|
static quint32 writeLimits(struct fort_traf *limits,
|
||||||
const QList<AppGroup *> &appGroups);
|
const QList<AppGroup *> &appGroups);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user