mirror of
https://github.com/tnodir/fort
synced 2024-11-15 03:26:01 +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 log_blocked : 1;
|
||||
UINT32 log_stat : 1;
|
||||
UINT32 filter_transport : 1;
|
||||
|
||||
UINT32 group_bits : 16;
|
||||
} FORT_CONF_FLAGS, *PFORT_CONF_FLAGS;
|
||||
@ -45,6 +46,13 @@ typedef struct fort_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 {
|
||||
FORT_CONF_FLAGS flags;
|
||||
|
||||
@ -67,9 +75,7 @@ typedef struct fort_conf {
|
||||
typedef struct fort_conf_io {
|
||||
UINT16 driver_version;
|
||||
|
||||
UINT32 limit_bits;
|
||||
|
||||
FORT_TRAF limits[FORT_CONF_GROUP_MAX]; /* Bytes per 0.5 sec. */
|
||||
FORT_CONF_GROUP conf_group;
|
||||
|
||||
FORT_CONF conf;
|
||||
} FORT_CONF_IO, *PFORT_CONF_IO;
|
||||
|
@ -7,6 +7,6 @@
|
||||
#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 DRIVER_VERSION 9
|
||||
#define DRIVER_VERSION 10
|
||||
|
||||
#endif // VERSION_H
|
||||
|
@ -4,6 +4,7 @@
|
||||
#define NDIS630 1
|
||||
|
||||
#define WIN9X_COMPAT_SPINLOCK /* XXX: Support Windows 7: KeInitializeSpinLock() */
|
||||
#define POOL_NX_OPTIN 1 /* Enhanced protection of NX pool */
|
||||
|
||||
#include <wdm.h>
|
||||
#include <fwpmk.h>
|
||||
@ -323,8 +324,8 @@ fort_callout_classify_v4 (const FWPS_INCOMING_VALUES0 *inFixedValues,
|
||||
BOOL is_new_proc = FALSE;
|
||||
NTSTATUS status;
|
||||
|
||||
status = fort_stat_flow_associate(&g_device->stat,
|
||||
flowId, process_id, group_index, is_reauth, &is_new_proc);
|
||||
status = fort_flow_associate(&g_device->stat, flowId, process_id,
|
||||
group_index, is_reauth, &is_new_proc);
|
||||
|
||||
if (!NT_SUCCESS(status)) {
|
||||
if (status == FORT_STATUS_FLOW_BLOCK)
|
||||
@ -404,38 +405,85 @@ fort_callout_notify (FWPS_CALLOUT_NOTIFY_TYPE notifyType,
|
||||
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
|
||||
fort_callout_flow_classify_v4 (const FWPS_INCOMING_METADATA_VALUES0 *inMetaValues,
|
||||
const FWPS_FILTER0 *filter,
|
||||
UINT64 flowContext,
|
||||
FWPS_CLASSIFY_OUT0 *classifyOut,
|
||||
UINT32 dataSize, BOOL inbound)
|
||||
{
|
||||
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);
|
||||
|
||||
fort_callout_classify_continue(classifyOut);
|
||||
}
|
||||
|
||||
static void
|
||||
fort_callout_stream_classify_v4 (const FWPS_INCOMING_VALUES0 *inFixedValues,
|
||||
const FWPS_INCOMING_METADATA_VALUES0 *inMetaValues,
|
||||
const FWPS_STREAM_CALLOUT_IO_PACKET0 *packet,
|
||||
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 = (streamData->flags & FWPS_STREAM_FLAG_RECEIVE) != 0;
|
||||
const BOOL inbound = (streamFlags & FWPS_STREAM_FLAG_RECEIVE) != 0;
|
||||
|
||||
UNUSED(inFixedValues);
|
||||
|
||||
fort_callout_flow_classify_v4(inMetaValues, filter, flowContext,
|
||||
fort_callout_flow_classify_v4(inMetaValues, flowContext,
|
||||
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
|
||||
@ -454,9 +502,12 @@ fort_callout_datagram_classify_v4 (const FWPS_INCOMING_VALUES0 *inFixedValues,
|
||||
const BOOL inbound = (direction == FWP_DIRECTION_INBOUND);
|
||||
|
||||
UNUSED(inFixedValues);
|
||||
UNUSED(filter);
|
||||
|
||||
fort_callout_flow_classify_v4(inMetaValues, filter, flowContext,
|
||||
fort_callout_flow_classify_v4(inMetaValues, flowContext,
|
||||
classifyOut, dataSize, inbound);
|
||||
|
||||
fort_callout_classify_continue(classifyOut);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -465,15 +516,7 @@ fort_callout_flow_delete_v4 (UINT16 layerId, UINT32 calloutId, UINT64 flowContex
|
||||
UNUSED(layerId);
|
||||
UNUSED(calloutId);
|
||||
|
||||
fort_stat_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);
|
||||
fort_flow_delete(&g_device->stat, flowContext);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -494,17 +537,23 @@ fort_callout_transport_classify_v4 (const FWPS_INCOMING_VALUES0 *inFixedValues,
|
||||
FWPS_METADATA_FIELD_ALE_CLASSIFY_REQUIRED))
|
||||
&& 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
|
||||
? FORT_STAT_FLOW_DEFER_IN : FORT_STAT_FLOW_DEFER_OUT;
|
||||
? FORT_FLOW_DEFER_IN : FORT_FLOW_DEFER_OUT;
|
||||
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 BOOL defer_flow = (fort_stat_flow_flags(flow) & flow_flags) == flow_flags
|
||||
const UCHAR speed_defer_flags = speed_limit | defer_flag;
|
||||
const BOOL defer_flow = (flow_flags & speed_defer_flags) == speed_defer_flags
|
||||
&& !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:
|
||||
* FWPS_LAYER_INBOUND_TRANSPORT_V4: The beginning of the data.
|
||||
* 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 */
|
||||
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,
|
||||
flow->opt.group_index);
|
||||
|
||||
if (NT_SUCCESS(status))
|
||||
goto block;
|
||||
goto drop;
|
||||
|
||||
if (status == STATUS_CANT_TERMINATE_SELF) {
|
||||
/* 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);
|
||||
return;
|
||||
|
||||
block:
|
||||
drop:
|
||||
fort_callout_classify_drop(classifyOut);
|
||||
return;
|
||||
}
|
||||
@ -721,10 +780,19 @@ fort_callout_remove (void)
|
||||
static void
|
||||
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);
|
||||
}
|
||||
|
||||
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
|
||||
fort_callout_force_reauth (const FORT_CONF_FLAGS old_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 */
|
||||
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) {
|
||||
fort_prov_flow_unregister(engine);
|
||||
}
|
||||
|
||||
stat_prov:
|
||||
if (conf_flags.log_stat) {
|
||||
const BOOL is_speed_limit = (stat->limit_bits != 0);
|
||||
if ((status = fort_prov_flow_register(engine, is_speed_limit)))
|
||||
if ((status = fort_prov_flow_register(engine,
|
||||
conf_flags.filter_transport)))
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
@ -989,13 +1058,15 @@ fort_device_control (PDEVICE_OBJECT device, PIRP irp)
|
||||
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(conf_ref);
|
||||
const FORT_CONF_FLAGS conf_flags = conf_ref->conf.flags;
|
||||
|
||||
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,
|
||||
defer_flush_bits);
|
||||
@ -1064,7 +1135,7 @@ fort_power_callback (PVOID context, PVOID event, PVOID specifics)
|
||||
g_device->power_off = 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;
|
||||
|
||||
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->log_timer);
|
||||
@ -1206,6 +1277,9 @@ DriverEntry (PDRIVER_OBJECT driver, PUNICODE_STRING reg_path)
|
||||
|
||||
UNUSED(reg_path);
|
||||
|
||||
// Use NX Non-Paged Pool
|
||||
ExInitializeDriverRuntime(DrvRtPoolNxOptIn);
|
||||
|
||||
/* Wait for BFE to start */
|
||||
status = fort_bfe_wait();
|
||||
if (!NT_SUCCESS(status)) {
|
||||
|
@ -3,6 +3,8 @@
|
||||
#define FORT_DEFER_FLUSH_ALL 0xFFFFFFFF
|
||||
#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 NTOHL(l) HTONL(l)
|
||||
#define HTONS(s) _byteswap_ushort(s)
|
||||
@ -35,26 +37,38 @@ typedef struct tcp_header {
|
||||
} TCP_HEADER, *PTCP_HEADER;
|
||||
|
||||
typedef struct fort_packet_in {
|
||||
COMPARTMENT_ID compartmentId;
|
||||
|
||||
IF_INDEX interfaceIndex;
|
||||
IF_INDEX subInterfaceIndex;
|
||||
|
||||
UINT16 ipHeaderSize;
|
||||
UINT16 transportHeaderSize;
|
||||
|
||||
UINT16 nblOffset;
|
||||
} FORT_PACKET_IN, *PFORT_PACKET_IN;
|
||||
|
||||
typedef struct fort_packet_out {
|
||||
COMPARTMENT_ID compartmentId;
|
||||
|
||||
UINT32 remoteAddr4;
|
||||
|
||||
SCOPE_ID remoteScopeId;
|
||||
UINT64 endpointHandle;
|
||||
} FORT_PACKET_OUT, *PFORT_PACKET_OUT;
|
||||
|
||||
typedef struct fort_packet {
|
||||
BOOL inbound;
|
||||
typedef struct fort_packet_stream {
|
||||
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;
|
||||
|
||||
@ -63,6 +77,7 @@ typedef struct fort_packet {
|
||||
union {
|
||||
FORT_PACKET_IN in;
|
||||
FORT_PACKET_OUT out;
|
||||
FORT_PACKET_STREAM stream;
|
||||
};
|
||||
} FORT_PACKET, *PFORT_PACKET;
|
||||
|
||||
@ -74,33 +89,187 @@ typedef struct fort_defer_list {
|
||||
typedef struct fort_defer {
|
||||
UINT32 list_bits;
|
||||
|
||||
HANDLE injection4_id;
|
||||
HANDLE transport_injection4_id;
|
||||
HANDLE stream_injection4_id;
|
||||
|
||||
PFORT_PACKET packet_free;
|
||||
|
||||
tommy_arrayof packets;
|
||||
|
||||
FORT_DEFER_LIST stream_list;
|
||||
FORT_DEFER_LIST lists[FORT_DEFER_LIST_MAX]; /* in/out-bounds */
|
||||
|
||||
KSPIN_LOCK lock;
|
||||
} FORT_DEFER, *PFORT_DEFER;
|
||||
|
||||
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
|
||||
fort_defer_open (PFORT_DEFER defer)
|
||||
{
|
||||
NTSTATUS status;
|
||||
|
||||
status = FwpsInjectionHandleCreate0(AF_INET, FWPS_INJECTION_TYPE_TRANSPORT,
|
||||
&defer->injection4_id);
|
||||
&defer->transport_injection4_id);
|
||||
|
||||
if (!NT_SUCCESS(status)) {
|
||||
defer->injection4_id = INVALID_HANDLE_VALUE;
|
||||
defer->transport_injection4_id = INVALID_HANDLE_VALUE;
|
||||
|
||||
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));
|
||||
@ -111,13 +280,14 @@ fort_defer_open (PFORT_DEFER defer)
|
||||
static void
|
||||
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);
|
||||
}
|
||||
|
||||
static NTSTATUS
|
||||
fort_defer_add (PFORT_DEFER defer,
|
||||
fort_defer_packet_add (PFORT_DEFER defer,
|
||||
const FWPS_INCOMING_VALUES0 *inFixedValues,
|
||||
const FWPS_INCOMING_METADATA_VALUES0 *inMetaValues,
|
||||
PNET_BUFFER_LIST netBufList,
|
||||
@ -129,18 +299,12 @@ fort_defer_add (PFORT_DEFER defer,
|
||||
UINT16 list_index;
|
||||
NTSTATUS status;
|
||||
|
||||
if (defer->injection4_id == INVALID_HANDLE_VALUE)
|
||||
if (defer->transport_injection4_id == INVALID_HANDLE_VALUE)
|
||||
return STATUS_FWP_TCPIP_NOT_READY;
|
||||
|
||||
/* Skip self injected packet */
|
||||
{
|
||||
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)
|
||||
if (fort_packet_injected_by_self(defer, netBufList))
|
||||
return STATUS_CANT_TERMINATE_SELF;
|
||||
}
|
||||
|
||||
/* Skip IpSec protected packet */
|
||||
if (inbound) {
|
||||
@ -163,21 +327,12 @@ fort_defer_add (PFORT_DEFER defer,
|
||||
|
||||
defer_list = &defer->lists[list_index];
|
||||
|
||||
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 */
|
||||
if (tommy_arrayof_grow(&defer->packets, size + 1), 0) {
|
||||
pkt = fort_defer_packet_get(defer);
|
||||
if (pkt == NULL) {
|
||||
status = STATUS_INSUFFICIENT_RESOURCES;
|
||||
goto end;
|
||||
}
|
||||
|
||||
pkt = tommy_arrayof_ref(&defer->packets, size);
|
||||
}
|
||||
|
||||
if (defer_list->packet_tail == NULL) {
|
||||
defer_list->packet_head = defer_list->packet_tail = pkt;
|
||||
} else {
|
||||
@ -186,7 +341,9 @@ fort_defer_add (PFORT_DEFER defer,
|
||||
}
|
||||
|
||||
pkt->inbound = inbound;
|
||||
pkt->compartmentId = inMetaValues->compartmentId;
|
||||
pkt->is_stream = FALSE;
|
||||
pkt->dataOffset = 0;
|
||||
pkt->dataSize = 0; /* not used */
|
||||
pkt->netBufList = netBufList;
|
||||
pkt->next = NULL;
|
||||
|
||||
@ -201,13 +358,15 @@ fort_defer_add (PFORT_DEFER defer,
|
||||
? FWPS_FIELD_INBOUND_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->subInterfaceIndex = inFixedValues->incomingValue[subInterfaceField].value.uint32;
|
||||
|
||||
pkt_in->ipHeaderSize = (UINT16) inMetaValues->ipHeaderSize;
|
||||
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));
|
||||
} else {
|
||||
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_OUTBOUND_TRANSPORT_V4_IP_REMOTE_ADDRESS;
|
||||
|
||||
pkt_out->compartmentId = inMetaValues->compartmentId;
|
||||
|
||||
/* host-order -> network-order conversion */
|
||||
pkt_out->remoteAddr4 = HTONL(
|
||||
inFixedValues->incomingValue[remoteAddrField].value.uint32);
|
||||
@ -224,7 +385,7 @@ fort_defer_add (PFORT_DEFER defer,
|
||||
pkt_out->endpointHandle = inMetaValues->transportEndpointHandle;
|
||||
}
|
||||
|
||||
FwpsReferenceNetBufferList0(netBufList, TRUE);
|
||||
FwpsReferenceNetBufferList0(pkt->netBufList, TRUE);
|
||||
|
||||
/* Set to be flushed bit */
|
||||
defer->list_bits |= (1 << list_index);
|
||||
@ -237,8 +398,76 @@ fort_defer_add (PFORT_DEFER defer,
|
||||
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
|
||||
fort_defer_free (PFORT_DEFER defer, PFORT_PACKET pkt,
|
||||
fort_defer_packet_free (PFORT_DEFER defer,
|
||||
PFORT_PACKET pkt,
|
||||
PNET_BUFFER_LIST clonedNetBufList,
|
||||
BOOL dispatchLevel)
|
||||
{
|
||||
@ -264,8 +493,7 @@ fort_defer_free (PFORT_DEFER defer, PFORT_PACKET pkt,
|
||||
KeAcquireInStackQueuedSpinLock(&defer->lock, &lock_queue);
|
||||
}
|
||||
|
||||
pkt->next = defer->packet_free;
|
||||
defer->packet_free = pkt;
|
||||
fort_defer_packet_put(defer, pkt);
|
||||
|
||||
if (dispatchLevel) {
|
||||
KeReleaseInStackQueuedSpinLockFromDpcLevel(&lock_queue);
|
||||
@ -274,91 +502,54 @@ fort_defer_free (PFORT_DEFER defer, PFORT_PACKET pkt,
|
||||
}
|
||||
}
|
||||
|
||||
static NTSTATUS
|
||||
fort_defer_inject_in (PFORT_DEFER defer, PFORT_PACKET pkt,
|
||||
PNET_BUFFER_LIST *clonedNetBufList,
|
||||
FORT_INJECT_COMPLETE_FUNC complete_func)
|
||||
static void
|
||||
fort_defer_packet_inject (PFORT_DEFER defer,
|
||||
PFORT_PACKET pkt,
|
||||
FORT_INJECT_COMPLETE_FUNC complete_func,
|
||||
BOOL dispatchLevel)
|
||||
{
|
||||
PFORT_PACKET_IN pkt_in = &pkt->in;
|
||||
PNET_BUFFER_LIST netBufList = pkt->netBufList;
|
||||
PNET_BUFFER netBuffer = NET_BUFFER_LIST_FIRST_NB(netBufList);
|
||||
while (pkt != NULL) {
|
||||
PFORT_PACKET pkt_next = pkt->next;
|
||||
PNET_BUFFER_LIST clonedNetBufList = NULL;
|
||||
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_in->nblOffset != NET_BUFFER_DATA_OFFSET(netBuffer)) {
|
||||
pkt_in->transportHeaderSize = 0;
|
||||
FORT_INJECT_FUNC inject_func = pkt->is_stream
|
||||
? &fort_packet_inject_stream
|
||||
: (pkt->inbound ? &fort_packet_inject_in : &fort_packet_inject_out);
|
||||
|
||||
status = inject_func(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;
|
||||
}
|
||||
|
||||
/* 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->injection4_id, NULL, NULL, 0,
|
||||
AF_INET, pkt->compartmentId,
|
||||
pkt_in->interfaceIndex, pkt_in->subInterfaceIndex,
|
||||
*clonedNetBufList, complete_func, pkt);
|
||||
fort_defer_packet_free(defer, pkt, clonedNetBufList, dispatchLevel);
|
||||
}
|
||||
|
||||
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
|
||||
fort_defer_flush (PFORT_DEFER defer,
|
||||
fort_defer_packet_flush (PFORT_DEFER defer,
|
||||
FORT_INJECT_COMPLETE_FUNC complete_func,
|
||||
UINT32 list_bits,
|
||||
BOOL dispatchLevel)
|
||||
{
|
||||
KLOCK_QUEUE_HANDLE lock_queue;
|
||||
PFORT_DEFER_LIST defer_list;
|
||||
PFORT_PACKET pkt;
|
||||
PFORT_PACKET pkt_chain;
|
||||
int i;
|
||||
|
||||
list_bits &= defer->list_bits;
|
||||
if (list_bits == 0)
|
||||
return;
|
||||
|
||||
pkt = NULL;
|
||||
pkt_chain = NULL;
|
||||
|
||||
if (dispatchLevel) {
|
||||
KeAcquireInStackQueuedSpinLockAtDpcLevel(&defer->lock, &lock_queue);
|
||||
@ -376,8 +567,8 @@ fort_defer_flush (PFORT_DEFER defer,
|
||||
defer_list = &defer->lists[i];
|
||||
|
||||
if (defer_list->packet_head != NULL) {
|
||||
defer_list->packet_tail->next = pkt;
|
||||
pkt = defer_list->packet_head;
|
||||
defer_list->packet_tail->next = pkt_chain;
|
||||
pkt_chain = defer_list->packet_head;
|
||||
|
||||
defer_list->packet_head = defer_list->packet_tail = NULL;
|
||||
}
|
||||
@ -392,26 +583,61 @@ fort_defer_flush (PFORT_DEFER defer,
|
||||
KeReleaseInStackQueuedSpinLock(&lock_queue);
|
||||
}
|
||||
|
||||
while (pkt != NULL) {
|
||||
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_packet_inject(defer, pkt_chain, complete_func, dispatchLevel);
|
||||
}
|
||||
|
||||
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;
|
||||
} 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;
|
||||
} FORT_STAT_PROC, *PFORT_STAT_PROC;
|
||||
|
||||
#define FORT_STAT_FLOW_SPEED_LIMIT_IN 0x01
|
||||
#define FORT_STAT_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_STAT_FLOW_DEFER_IN 0x04
|
||||
#define FORT_STAT_FLOW_DEFER_OUT 0x08
|
||||
#define FORT_FLOW_SPEED_LIMIT_IN 0x01
|
||||
#define FORT_FLOW_SPEED_LIMIT_OUT 0x02
|
||||
#define FORT_FLOW_SPEED_LIMIT (FORT_FLOW_SPEED_LIMIT_IN | FORT_FLOW_SPEED_LIMIT_OUT)
|
||||
#define FORT_FLOW_DEFER_IN 0x04
|
||||
#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 group_index;
|
||||
UINT16 proc_index;
|
||||
} FORT_STAT_FLOW_OPT, *PFORT_STAT_FLOW_OPT;
|
||||
} FORT_FLOW_OPT, *PFORT_FLOW_OPT;
|
||||
|
||||
/* Synchronize with tommy_hashdyn_node! */
|
||||
typedef struct fort_stat_flow {
|
||||
struct fort_stat_flow *next;
|
||||
struct fort_stat_flow *prev;
|
||||
typedef struct fort_flow {
|
||||
struct fort_flow *next;
|
||||
struct fort_flow *prev;
|
||||
|
||||
union {
|
||||
#if defined(_WIN64)
|
||||
UINT64 flow_id;
|
||||
#else
|
||||
FORT_STAT_FLOW_OPT opt;
|
||||
FORT_FLOW_OPT opt;
|
||||
#endif
|
||||
void *data;
|
||||
};
|
||||
@ -70,11 +74,11 @@ typedef struct fort_stat_flow {
|
||||
tommy_key_t flow_hash;
|
||||
|
||||
#if defined(_WIN64)
|
||||
FORT_STAT_FLOW_OPT opt;
|
||||
FORT_FLOW_OPT opt;
|
||||
#else
|
||||
UINT64 flow_id;
|
||||
#endif
|
||||
} FORT_STAT_FLOW, *PFORT_STAT_FLOW;
|
||||
} FORT_FLOW, *PFORT_FLOW;
|
||||
|
||||
typedef struct fort_stat {
|
||||
UCHAR volatile closed;
|
||||
@ -83,7 +87,6 @@ typedef struct fort_stat {
|
||||
|
||||
UINT16 proc_active_count;
|
||||
|
||||
UINT32 limit_bits;
|
||||
UINT32 group_flush_bits;
|
||||
|
||||
UINT32 stream4_id;
|
||||
@ -94,7 +97,7 @@ typedef struct fort_stat {
|
||||
PFORT_STAT_PROC proc_free;
|
||||
PFORT_STAT_PROC proc_active;
|
||||
|
||||
PFORT_STAT_FLOW flow_free;
|
||||
PFORT_FLOW flow_free;
|
||||
|
||||
tommy_arrayof procs;
|
||||
tommy_hashdyn procs_map;
|
||||
@ -102,17 +105,22 @@ typedef struct fort_stat {
|
||||
tommy_arrayof flows;
|
||||
tommy_hashdyn flows_map;
|
||||
|
||||
FORT_TRAF limits[FORT_CONF_GROUP_MAX];
|
||||
FORT_CONF_GROUP conf_group;
|
||||
|
||||
FORT_STAT_GROUP groups[FORT_CONF_GROUP_MAX];
|
||||
|
||||
KSPIN_LOCK lock;
|
||||
} FORT_STAT, *PFORT_STAT;
|
||||
|
||||
#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) \
|
||||
(((stat)->limit_bits >> ((group_index) * 2)) & 3)
|
||||
(((stat)->conf_group.limit_bits >> ((group_index) * 2)) & 3)
|
||||
|
||||
|
||||
static void
|
||||
@ -215,25 +223,25 @@ fort_stat_proc_add (PFORT_STAT stat, UINT32 process_id)
|
||||
}
|
||||
|
||||
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
|
||||
fort_stat_flow_flags_set (PFORT_STAT_FLOW flow, UCHAR flags)
|
||||
{
|
||||
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)
|
||||
fort_flow_context_set (PFORT_STAT stat, PFORT_FLOW flow)
|
||||
{
|
||||
const UINT64 flow_id = flow->flow_id;
|
||||
const UINT64 flowContext = (UINT64) flow;
|
||||
@ -245,7 +253,7 @@ fort_stat_flow_context_set (PFORT_STAT stat, PFORT_STAT_FLOW flow)
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
@ -256,15 +264,15 @@ fort_stat_flow_context_remove (PFORT_STAT stat, PFORT_STAT_FLOW flow)
|
||||
}
|
||||
|
||||
static void
|
||||
fort_stat_flow_close (PFORT_STAT_FLOW flow)
|
||||
fort_flow_close (PFORT_FLOW flow)
|
||||
{
|
||||
flow->opt.proc_index = FORT_PROC_BAD_INDEX;
|
||||
}
|
||||
|
||||
static PFORT_STAT_FLOW
|
||||
fort_stat_flow_get (PFORT_STAT stat, UINT64 flow_id, tommy_key_t flow_hash)
|
||||
static PFORT_FLOW
|
||||
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);
|
||||
|
||||
while (flow != NULL) {
|
||||
@ -277,7 +285,7 @@ fort_stat_flow_get (PFORT_STAT stat, UINT64 flow_id, tommy_key_t flow_hash)
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
@ -293,12 +301,12 @@ fort_stat_flow_free (PFORT_STAT stat, PFORT_STAT_FLOW flow)
|
||||
}
|
||||
|
||||
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 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);
|
||||
PFORT_STAT_FLOW flow = fort_stat_flow_get(stat, flow_id, flow_hash);
|
||||
const tommy_key_t flow_hash = fort_flow_hash(flow_id);
|
||||
PFORT_FLOW flow = fort_flow_get(stat, flow_id, flow_hash);
|
||||
BOOL is_new_flow = FALSE;
|
||||
|
||||
if (flow == NULL) {
|
||||
@ -323,7 +331,7 @@ fort_stat_flow_add (PFORT_STAT stat, UINT64 flow_id,
|
||||
|
||||
flow->flow_id = flow_id;
|
||||
|
||||
fort_stat_flow_context_set(stat, flow);
|
||||
fort_flow_context_set(stat, flow);
|
||||
|
||||
is_new_flow = TRUE;
|
||||
} else {
|
||||
@ -334,7 +342,8 @@ fort_stat_flow_add (PFORT_STAT stat, UINT64 flow_id,
|
||||
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.proc_index = proc_index;
|
||||
|
||||
@ -347,7 +356,7 @@ fort_stat_open (PFORT_STAT stat)
|
||||
tommy_arrayof_init(&stat->procs, sizeof(FORT_STAT_PROC));
|
||||
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);
|
||||
|
||||
KeInitializeSpinLock(&stat->lock);
|
||||
@ -363,7 +372,7 @@ fort_stat_close (PFORT_STAT stat)
|
||||
stat->closed = TRUE;
|
||||
|
||||
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_hashdyn_done(&stat->procs_map);
|
||||
@ -380,7 +389,7 @@ fort_stat_clear (PFORT_STAT stat)
|
||||
fort_stat_proc_active_clear(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));
|
||||
}
|
||||
@ -402,32 +411,26 @@ fort_stat_update (PFORT_STAT stat, BOOL log_stat)
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
KeAcquireInStackQueuedSpinLock(&stat->lock, &lock_queue);
|
||||
{
|
||||
const UINT32 limit_bits = conf_io->limit_bits;
|
||||
|
||||
stat->limit_bits = limit_bits;
|
||||
|
||||
if (limit_bits != 0) {
|
||||
RtlCopyMemory(stat->limits, conf_io->limits, sizeof(stat->limits));
|
||||
}
|
||||
stat->conf_group = conf_io->conf_group;
|
||||
}
|
||||
KeReleaseInStackQueuedSpinLock(&lock_queue);
|
||||
}
|
||||
|
||||
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,
|
||||
BOOL is_reauth, BOOL *is_new_proc)
|
||||
{
|
||||
const tommy_key_t proc_hash = fort_stat_proc_hash(process_id);
|
||||
KLOCK_QUEUE_HANDLE lock_queue;
|
||||
PFORT_STAT_PROC proc;
|
||||
UCHAR speed_limit;
|
||||
UCHAR fragment, speed_limit;
|
||||
NTSTATUS status;
|
||||
|
||||
KeAcquireInStackQueuedSpinLock(&stat->lock, &lock_queue);
|
||||
@ -455,10 +458,12 @@ fort_stat_flow_associate (PFORT_STAT stat, UINT64 flow_id,
|
||||
*is_new_proc = TRUE;
|
||||
}
|
||||
|
||||
fragment = fort_stat_group_fragment(stat, group_index);
|
||||
speed_limit = fort_stat_group_speed_limit(stat, group_index);
|
||||
|
||||
status = fort_stat_flow_add(stat, flow_id,
|
||||
group_index, proc->proc_index, speed_limit, is_reauth);
|
||||
status = fort_flow_add(stat, flow_id,
|
||||
group_index, proc->proc_index,
|
||||
fragment, speed_limit, is_reauth);
|
||||
|
||||
if (!NT_SUCCESS(status) && *is_new_proc) {
|
||||
fort_stat_proc_free(stat, proc);
|
||||
@ -471,27 +476,27 @@ fort_stat_flow_associate (PFORT_STAT stat, UINT64 flow_id,
|
||||
}
|
||||
|
||||
static void
|
||||
fort_stat_flow_delete (PFORT_STAT stat, UINT64 flowContext)
|
||||
fort_flow_delete (PFORT_STAT stat, UINT64 flowContext)
|
||||
{
|
||||
KLOCK_QUEUE_HANDLE lock_queue;
|
||||
PFORT_STAT_FLOW flow = (PFORT_STAT_FLOW) flowContext;
|
||||
PFORT_FLOW flow = (PFORT_FLOW) flowContext;
|
||||
|
||||
if (stat->closed)
|
||||
return; /* double check to avoid deadlock after remove-flow-context */
|
||||
|
||||
KeAcquireInStackQueuedSpinLock(&stat->lock, &lock_queue);
|
||||
if (!stat->closed) {
|
||||
fort_stat_flow_free(stat, flow);
|
||||
fort_flow_free(stat, flow);
|
||||
}
|
||||
KeReleaseInStackQueuedSpinLock(&lock_queue);
|
||||
}
|
||||
|
||||
static void
|
||||
fort_stat_flow_classify (PFORT_STAT stat, UINT64 flowContext,
|
||||
fort_flow_classify (PFORT_STAT stat, UINT64 flowContext,
|
||||
UINT32 data_len, BOOL inbound)
|
||||
{
|
||||
KLOCK_QUEUE_HANDLE lock_queue;
|
||||
PFORT_STAT_FLOW flow = (PFORT_STAT_FLOW) flowContext;
|
||||
PFORT_FLOW flow = (PFORT_FLOW) flowContext;
|
||||
|
||||
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
|
||||
: &proc->traf.out_bytes;
|
||||
|
||||
const UCHAR stat_flow_flags = fort_flow_flags(flow);
|
||||
|
||||
/* Add traffic to process */
|
||||
*proc_bytes += data_len;
|
||||
|
||||
if (flow->opt.flags & (inbound ? FORT_STAT_FLOW_SPEED_LIMIT_IN
|
||||
: FORT_STAT_FLOW_SPEED_LIMIT_OUT)) {
|
||||
if (stat_flow_flags & (inbound ? FORT_FLOW_SPEED_LIMIT_IN
|
||||
: FORT_FLOW_SPEED_LIMIT_OUT)) {
|
||||
const UCHAR group_index = flow->opt.group_index;
|
||||
|
||||
PFORT_STAT_GROUP group = &stat->groups[group_index];
|
||||
UINT32 *group_bytes = inbound ? &group->traf.in_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
|
||||
: group_limit->out_bytes;
|
||||
|
||||
@ -526,12 +533,12 @@ fort_stat_flow_classify (PFORT_STAT stat, UINT64 flowContext,
|
||||
/* Defer ACK */
|
||||
{
|
||||
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)
|
||||
fort_stat_flow_flags_set(flow, defer_flag);
|
||||
fort_flow_flags_set(flow, defer_flag);
|
||||
else
|
||||
fort_stat_flow_flags_clear(flow, defer_flag);
|
||||
fort_flow_flags_clear(flow, defer_flag);
|
||||
}
|
||||
|
||||
stat->group_flush_bits |= (1 << list_index);
|
||||
@ -614,7 +621,7 @@ fort_stat_dpc_group_flush (PFORT_STAT stat)
|
||||
continue;
|
||||
|
||||
group = &stat->groups[i];
|
||||
group_limit = &stat->limits[i];
|
||||
group_limit = &stat->conf_group.limits[i];
|
||||
|
||||
traf = group->traf;
|
||||
|
||||
|
@ -3,7 +3,7 @@
|
||||
#define FORT_WORKER_REAUTH 0x01
|
||||
|
||||
typedef struct fort_worker {
|
||||
LONG volatile id_bits;
|
||||
UCHAR volatile id_bits;
|
||||
|
||||
PIO_WORKITEM item;
|
||||
} FORT_WORKER, *PFORT_WORKER;
|
||||
@ -27,7 +27,7 @@ static void
|
||||
fort_worker_callback (PVOID device, PVOID context, PIO_WORKITEM item)
|
||||
{
|
||||
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(item);
|
||||
@ -38,9 +38,9 @@ fort_worker_callback (PVOID device, PVOID context, PIO_WORKITEM item)
|
||||
}
|
||||
|
||||
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) {
|
||||
IoQueueWorkItemEx(worker->item, &fort_worker_callback,
|
||||
|
@ -6,6 +6,7 @@
|
||||
AppGroup::AppGroup(QObject *parent) :
|
||||
QObject(parent),
|
||||
m_enabled(true),
|
||||
m_fragmentPacket(false),
|
||||
m_periodEnabled(false),
|
||||
m_periodFrom(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)
|
||||
{
|
||||
if (bool(m_periodEnabled) != periodEnabled) {
|
||||
@ -108,15 +117,20 @@ QString AppGroup::label() const
|
||||
{
|
||||
QString text = name();
|
||||
|
||||
if (limitInEnabled() && speedLimitIn() != 0) {
|
||||
if (fragmentPacket()) {
|
||||
text += QLatin1Char(' ')
|
||||
+ QChar(0x2207) // ∇
|
||||
+ QChar(0x00F7); // ÷
|
||||
}
|
||||
|
||||
if (enabledSpeedLimitIn() != 0) {
|
||||
text += QLatin1Char(' ')
|
||||
+ QChar(0x25BC) // ▼
|
||||
+ NetUtil::formatSpeed(speedLimitIn() * 1024);
|
||||
}
|
||||
|
||||
if (limitOutEnabled() && speedLimitOut() != 0) {
|
||||
if (enabledSpeedLimitOut() != 0) {
|
||||
text += QLatin1Char(' ')
|
||||
+ QChar(0x2206) // ∆
|
||||
+ QChar(0x25B2) // ▲
|
||||
+ NetUtil::formatSpeed(speedLimitOut() * 1024);
|
||||
}
|
||||
|
||||
@ -132,6 +146,8 @@ QVariant AppGroup::toVariant() const
|
||||
{
|
||||
QVariantMap map;
|
||||
|
||||
map["fragmentPacket"] = fragmentPacket();
|
||||
|
||||
map["periodEnabled"] = periodEnabled();
|
||||
map["periodFrom"] = periodFrom();
|
||||
map["periodTo"] = periodTo();
|
||||
@ -152,6 +168,8 @@ void AppGroup::fromVariant(const QVariant &v)
|
||||
{
|
||||
const QVariantMap map = v.toMap();
|
||||
|
||||
m_fragmentPacket = map["fragmentPacket"].toBool();
|
||||
|
||||
m_periodEnabled = map["periodEnabled"].toBool();
|
||||
m_periodFrom = map["periodFrom"].toInt();
|
||||
m_periodTo = map["periodTo"].toInt();
|
||||
|
@ -8,6 +8,7 @@ class AppGroup : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
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(int periodFrom READ periodFrom WRITE setPeriodFrom NOTIFY periodFromChanged)
|
||||
Q_PROPERTY(int periodTo READ periodTo WRITE setPeriodTo NOTIFY periodToChanged)
|
||||
@ -25,6 +26,9 @@ public:
|
||||
bool enabled() const { return m_enabled; }
|
||||
void setEnabled(bool enabled);
|
||||
|
||||
bool fragmentPacket() const { return m_fragmentPacket; }
|
||||
void setFragmentPacket(bool enabled);
|
||||
|
||||
bool periodEnabled() const { return m_periodEnabled; }
|
||||
void setPeriodEnabled(bool periodEnabled);
|
||||
|
||||
@ -46,6 +50,13 @@ public:
|
||||
quint32 speedLimitOut() const { return m_speedLimitOut; }
|
||||
void setSpeedLimitOut(quint32 limit);
|
||||
|
||||
quint32 enabledSpeedLimitIn() const {
|
||||
return limitInEnabled() ? speedLimitIn() : 0;
|
||||
}
|
||||
quint32 enabledSpeedLimitOut() const {
|
||||
return limitOutEnabled() ? speedLimitOut() : 0;
|
||||
}
|
||||
|
||||
QString name() const { return m_name; }
|
||||
void setName(const QString &name);
|
||||
|
||||
@ -62,6 +73,7 @@ public:
|
||||
|
||||
signals:
|
||||
void enabledChanged();
|
||||
void fragmentPacketChanged();
|
||||
void periodEnabledChanged();
|
||||
void periodFromChanged();
|
||||
void periodToChanged();
|
||||
@ -78,6 +90,8 @@ public slots:
|
||||
private:
|
||||
uint m_enabled : 1;
|
||||
|
||||
uint m_fragmentPacket : 1;
|
||||
|
||||
uint m_periodEnabled : 1;
|
||||
uint m_periodFrom : 5;
|
||||
uint m_periodTo : 5;
|
||||
|
@ -7,6 +7,7 @@
|
||||
<file>images/application_double.png</file>
|
||||
<file>images/application_edit.png</file>
|
||||
<file>images/application_error.png</file>
|
||||
<file>images/application_key.png</file>
|
||||
<file>images/arrow_refresh.png</file>
|
||||
<file>images/bin_empty.png</file>
|
||||
<file>images/cancel.png</file>
|
||||
@ -17,8 +18,6 @@
|
||||
<file>images/cross.png</file>
|
||||
<file>images/cut.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/page_copy.png</file>
|
||||
<file>images/page_paste.png</file>
|
||||
|
@ -32,7 +32,7 @@
|
||||
<file>qml/pages/addresses/AddressGroupRow.qml</file>
|
||||
<file>qml/pages/apps/AppsColumn.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/GraphButton.qml</file>
|
||||
<file>qml/pages/log/IpListView.qml</file>
|
||||
|
@ -271,10 +271,10 @@ void GraphWindow::updateWindowTitleSpeed()
|
||||
const auto outBytes = m_graphOut->data()->isEmpty()
|
||||
? 0 : (m_graphOut->data()->constEnd() - 1)->mainValue();
|
||||
|
||||
setWindowTitle(QChar(0x2207) // ∇
|
||||
setWindowTitle(QChar(0x25BC) // ▼
|
||||
+ NetUtil::formatSpeed(quint32(inBytes))
|
||||
+ QLatin1Char(' ')
|
||||
+ QChar(0x2206) // ∆
|
||||
+ QChar(0x25B2) // ▲
|
||||
+ NetUtil::formatSpeed(quint32(outBytes))
|
||||
);
|
||||
}
|
||||
|
Binary file not shown.
@ -315,22 +315,22 @@
|
||||
<translation>Сдвинуть направо</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../qml/pages/apps/AppsColumn.qml" line="47"/>
|
||||
<location filename="../qml/pages/apps/AppsColumn.qml" line="49"/>
|
||||
<source>Enabled</source>
|
||||
<translation>Включено</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../qml/pages/apps/AppsColumn.qml" line="62"/>
|
||||
<location filename="../qml/pages/apps/AppsColumn.qml" line="64"/>
|
||||
<source>period, hours:</source>
|
||||
<translation>период, часы</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../qml/pages/apps/AppsColumn.qml" line="101"/>
|
||||
<location filename="../qml/pages/apps/AppsColumn.qml" line="103"/>
|
||||
<source>Block</source>
|
||||
<translation>Блокировать</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../qml/pages/apps/AppsColumn.qml" line="121"/>
|
||||
<location filename="../qml/pages/apps/AppsColumn.qml" line="123"/>
|
||||
<source>Allow</source>
|
||||
<translation>Разрешить</translation>
|
||||
</message>
|
||||
@ -486,10 +486,16 @@
|
||||
<translation>Ограничение скорости выгрузки, KiB/s:</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../qml/pages/apps/GroupOptionsButton.qml" line="11"/>
|
||||
<location filename="../qml/pages/log/TrafOptionsButton.qml" line="11"/>
|
||||
<source>Options…</source>
|
||||
<translation>Настройки…</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../qml/pages/apps/GroupOptionsButton.qml" line="16"/>
|
||||
<source>Fragment first TCP packet</source>
|
||||
<translation>Фрагментировать первый TCP пакет</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../qml/pages/log/TrafOptionsButton.qml" line="21"/>
|
||||
<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);
|
||||
}
|
||||
|
||||
if (confSaved) {
|
||||
if (confSaved && othersEdited) {
|
||||
mainPage.saved();
|
||||
}
|
||||
|
||||
|
@ -33,7 +33,7 @@ ColumnLayout {
|
||||
Layout.preferredWidth: 10
|
||||
}
|
||||
|
||||
SpeedLimitButton {
|
||||
GroupOptionsButton {
|
||||
enabled: firewallConf.logStat
|
||||
}
|
||||
|
||||
|
@ -6,13 +6,9 @@ import com.fortfirewall 1.0
|
||||
|
||||
ButtonPopup {
|
||||
|
||||
icon.source: !((appGroup.limitInEnabled && appGroup.speedLimitIn)
|
||||
|| (appGroup.limitOutEnabled && appGroup.speedLimitOut))
|
||||
? "qrc:/images/flag_green.png"
|
||||
: "qrc:/images/flag_yellow.png"
|
||||
text: (translationManager.trTrigger
|
||||
&& qsTranslate("qml", "Speed Limit: "))
|
||||
+ speedLimitsText
|
||||
icon.source: "qrc:/images/application_key.png"
|
||||
text: translationManager.trTrigger
|
||||
&& qsTranslate("qml", "Options…")
|
||||
|
||||
readonly property var speedLimitValues: [
|
||||
10, 0, 20, 30, 50, 75, 100, 150, 200, 300, 500, 900,
|
||||
@ -32,28 +28,6 @@ ButtonPopup {
|
||||
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) {
|
||||
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->log_blocked = conf.logBlocked();
|
||||
confFlags->log_stat = conf.logStat();
|
||||
confFlags->filter_transport = appGroupFilterTransport(conf);
|
||||
confFlags->group_bits = conf.appGroupBits();
|
||||
|
||||
return flagsSize;
|
||||
@ -313,8 +314,10 @@ void ConfUtil::writeData(char *output, const FirewallConf &conf,
|
||||
|
||||
drvConfIo->driver_version = DRIVER_VERSION;
|
||||
|
||||
drvConfIo->limit_bits = writeLimits(
|
||||
drvConfIo->limits, conf.appGroupsList());
|
||||
drvConfIo->conf_group.fragment_bits = appGroupFragmentBits(conf);
|
||||
|
||||
drvConfIo->conf_group.limit_bits = writeLimits(
|
||||
drvConfIo->conf_group.limits, conf.appGroupsList());
|
||||
|
||||
drvConf->flags.prov_boot = conf.provBoot();
|
||||
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_stat = conf.logStat();
|
||||
|
||||
drvConf->flags.filter_transport = appGroupFilterTransport(conf);
|
||||
|
||||
drvConf->flags.group_bits = conf.appGroupBits();
|
||||
|
||||
FortCommon::confAppPermsMaskInit(drvConf);
|
||||
@ -343,6 +348,37 @@ void ConfUtil::writeData(char *output, const FirewallConf &conf,
|
||||
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,
|
||||
const QList<AppGroup *> &appGroups)
|
||||
{
|
||||
@ -353,10 +389,11 @@ quint32 ConfUtil::writeLimits(struct fort_traf *limits,
|
||||
for (int i = 0; i < groupsCount; ++i, ++limit) {
|
||||
const AppGroup *appGroup = appGroups.at(i);
|
||||
|
||||
limit->in_bytes = appGroup->enabled() && appGroup->limitInEnabled()
|
||||
? appGroup->speedLimitIn() * 1024 / 2 : 0;
|
||||
limit->out_bytes = appGroup->enabled() && appGroup->limitOutEnabled()
|
||||
? appGroup->speedLimitOut() * 1024 / 2 : 0;
|
||||
if (!appGroup->enabled())
|
||||
continue;
|
||||
|
||||
limit->in_bytes = appGroup->enabledSpeedLimitIn() * 1024 / 2;
|
||||
limit->out_bytes = appGroup->enabledSpeedLimitOut() * 1024 / 2;
|
||||
|
||||
if (limit->in_bytes) {
|
||||
limitBits |= (1 << (i * 2));
|
||||
|
@ -73,6 +73,9 @@ private:
|
||||
quint8 appPeriodsCount,
|
||||
const appgroups_map_t &appGroupIndexes);
|
||||
|
||||
static quint16 appGroupFragmentBits(const FirewallConf &conf);
|
||||
static bool appGroupFilterTransport(const FirewallConf &conf);
|
||||
|
||||
static quint32 writeLimits(struct fort_traf *limits,
|
||||
const QList<AppGroup *> &appGroups);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user