mirror of
https://github.com/tnodir/fort
synced 2024-11-15 07:45:22 +00:00
Driver: Prepare ACK packets deferring for speed limit.
This commit is contained in:
parent
f6c955e94b
commit
dd358a047a
@ -245,10 +245,7 @@ fort_prov_flow_register (HANDLE transEngine, BOOL filter_transport)
|
||||
|| (status = FwpmFilterAdd0(engine, &dfilter4, NULL, NULL))
|
||||
|| (filter_transport
|
||||
&& ((status = FwpmFilterAdd0(engine, &itfilter4, NULL, NULL))
|
||||
#if 0
|
||||
|| (status = FwpmFilterAdd0(engine, &otfilter4, NULL, NULL))
|
||||
#endif
|
||||
))
|
||||
|| (status = FwpmFilterAdd0(engine, &otfilter4, NULL, NULL))))
|
||||
) {
|
||||
fort_prov_trans_abort(engine);
|
||||
}
|
||||
|
@ -21,40 +21,10 @@
|
||||
#include "../common/fortprov.c"
|
||||
#include "forttds.c"
|
||||
#include "fortbuf.c"
|
||||
#include "fortpkt.c"
|
||||
#include "fortstat.c"
|
||||
#include "forttmr.c"
|
||||
|
||||
#define HTONL(l) _byteswap_ulong(l)
|
||||
#define NTOHL(l) HTONL(l)
|
||||
#define HTONS(s) _byteswap_ushort(s)
|
||||
#define NTOHS(s) HTONS(s)
|
||||
|
||||
#define TCP_HEADER_FLAG_FIN 0x0001
|
||||
#define TCP_HEADER_FLAG_SYN 0x0002
|
||||
#define TCP_HEADER_FLAG_RST 0x0004
|
||||
#define TCP_HEADER_FLAG_PSH 0x0008
|
||||
#define TCP_HEADER_FLAG_ACK 0x0010
|
||||
#define TCP_HEADER_FLAG_URG 0x0020
|
||||
#define TCP_HEADER_FLAG_ECE 0x0040
|
||||
#define TCP_HEADER_FLAG_CWR 0x0080
|
||||
|
||||
typedef struct tcp_header {
|
||||
UINT16 source; // Source Port
|
||||
UINT16 dest; // Destination Port
|
||||
|
||||
UINT32 seq; // Sequence number
|
||||
UINT32 ack_seq; // Acknowledgement number
|
||||
|
||||
UCHAR res1 : 4; // Unused
|
||||
UCHAR doff : 4; // Data offset
|
||||
|
||||
UCHAR flags; // Flags
|
||||
|
||||
UINT16 window; // Window size
|
||||
UINT16 csum; // Checksum
|
||||
UINT16 urg_ptr; // Urgent Pointer
|
||||
} TCP_HEADER, *PTCP_HEADER;
|
||||
|
||||
typedef struct fort_conf_ref {
|
||||
UINT32 volatile refcount;
|
||||
|
||||
@ -65,6 +35,7 @@ typedef struct fort_device {
|
||||
UINT32 prov_boot : 1;
|
||||
UINT32 is_opened : 1;
|
||||
UINT32 was_conf : 1;
|
||||
UINT32 power_off : 1;
|
||||
|
||||
UINT32 connect4_id;
|
||||
UINT32 accept4_id;
|
||||
@ -73,8 +44,12 @@ typedef struct fort_device {
|
||||
PFORT_CONF_REF volatile conf_ref;
|
||||
KSPIN_LOCK conf_lock;
|
||||
|
||||
PCALLBACK_OBJECT power_cb_obj;
|
||||
PVOID power_cb_reg;
|
||||
|
||||
FORT_BUFFER buffer;
|
||||
FORT_STAT stat;
|
||||
FORT_DEFER defer;
|
||||
FORT_TIMER timer;
|
||||
} FORT_DEVICE, *PFORT_DEVICE;
|
||||
|
||||
@ -304,7 +279,7 @@ fort_callout_classify_v4 (const FWPS_INCOMING_VALUES0 *inFixedValues,
|
||||
|
||||
if (!NT_SUCCESS(status)) {
|
||||
DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_ERROR_LEVEL,
|
||||
"FORT: Classify v4: Flow assoc. error: %d\n", status);
|
||||
"FORT: Classify v4: Flow assoc. error: %x\n", status);
|
||||
} else if (is_new_proc) {
|
||||
fort_buffer_proc_new_write(&g_device->buffer,
|
||||
process_id, path_len, path, &irp, &info);
|
||||
@ -388,6 +363,7 @@ fort_callout_flow_classify_v4 (const FWPS_INCOMING_METADATA_VALUES0 *inMetaValue
|
||||
|
||||
if (fort_stat_flow_classify(&g_device->stat, flowContext,
|
||||
headerSize + dataSize, inbound)) {
|
||||
|
||||
fort_callout_classify_drop(classifyOut);
|
||||
} else {
|
||||
fort_callout_classify_permit(filter, classifyOut);
|
||||
@ -443,10 +419,18 @@ fort_callout_flow_delete_v4 (UINT16 layerId, UINT32 calloutId, UINT64 flowContex
|
||||
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);
|
||||
}
|
||||
|
||||
static void
|
||||
fort_callout_transport_classify_v4 (const FWPS_INCOMING_VALUES0 *inFixedValues,
|
||||
const FWPS_INCOMING_METADATA_VALUES0 *inMetaValues,
|
||||
const PNET_BUFFER_LIST netBufList,
|
||||
PNET_BUFFER_LIST netBufList,
|
||||
const FWPS_FILTER0 *filter,
|
||||
UINT64 flowContext,
|
||||
FWPS_CLASSIFY_OUT0 *classifyOut,
|
||||
@ -456,35 +440,72 @@ fort_callout_transport_classify_v4 (const FWPS_INCOMING_VALUES0 *inFixedValues,
|
||||
ipProtoField].value.uint8;
|
||||
const BOOL is_udp = (ip_proto == IPPROTO_UDP);
|
||||
|
||||
if (is_udp) goto permit;
|
||||
if (!(is_udp || FWPS_IS_METADATA_FIELD_PRESENT(inMetaValues,
|
||||
FWPS_METADATA_FIELD_ALE_CLASSIFY_REQUIRED))
|
||||
&& netBufList != NULL) {
|
||||
|
||||
/* 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.
|
||||
*/
|
||||
PFORT_STAT_FLOW flow = (PFORT_STAT_FLOW) flowContext;
|
||||
|
||||
if (inbound && g_device->conf_flags.ignore_tcp_rst) {
|
||||
const PNET_BUFFER netBuf = NET_BUFFER_LIST_FIRST_NB(netBufList);
|
||||
TCP_HEADER buf;
|
||||
PTCP_HEADER tcpHeader;
|
||||
BOOL blocked = FALSE;
|
||||
const BOOL ignore_tcp_rst = inbound && g_device->conf_flags.ignore_tcp_rst;
|
||||
const BOOL defer_flow = flow->opt.speed_limit && !g_device->power_off
|
||||
&& (inbound ? flow->opt.defer_in : flow->opt.defer_out);
|
||||
|
||||
NdisRetreatNetBufferDataStart(netBuf, sizeof(TCP_HEADER), 0, NULL);
|
||||
if (ignore_tcp_rst || defer_flow) {
|
||||
const PNET_BUFFER netBuf = NET_BUFFER_LIST_FIRST_NB(netBufList);
|
||||
TCP_HEADER buf;
|
||||
PTCP_HEADER tcpHeader;
|
||||
UINT32 tcpFlags;
|
||||
|
||||
tcpHeader = NdisGetDataBuffer(netBuf, sizeof(TCP_HEADER), &buf, 1, 0);
|
||||
if (netBuf == NULL)
|
||||
goto permit;
|
||||
|
||||
blocked = (tcpHeader->flags & TCP_HEADER_FLAG_RST);
|
||||
/* Position in the packet data:
|
||||
* FWPS_LAYER_INBOUND_TRANSPORT_V4: The beginning of the data.
|
||||
* FWPS_LAYER_OUTBOUND_TRANSPORT_V4: The beginning of the transport header.
|
||||
*/
|
||||
const UINT32 headerOffset = inbound ? 0 : sizeof(TCP_HEADER);
|
||||
|
||||
NdisAdvanceNetBufferDataStart(netBuf, sizeof(TCP_HEADER), FALSE, NULL);
|
||||
if (headerOffset != 0) {
|
||||
NdisRetreatNetBufferDataStart(netBuf, headerOffset, 0, NULL);
|
||||
}
|
||||
|
||||
if (blocked) {
|
||||
fort_callout_classify_drop(classifyOut);
|
||||
return;
|
||||
tcpHeader = NdisGetDataBuffer(netBuf, sizeof(TCP_HEADER), &buf, 1, 0);
|
||||
tcpFlags = tcpHeader ? tcpHeader->flags : 0;
|
||||
|
||||
if (headerOffset != 0) {
|
||||
NdisAdvanceNetBufferDataStart(netBuf, headerOffset, FALSE, NULL);
|
||||
}
|
||||
|
||||
if (tcpHeader == NULL)
|
||||
goto permit;
|
||||
|
||||
if (ignore_tcp_rst && (tcpFlags & TCP_FLAG_RST))
|
||||
goto block;
|
||||
|
||||
if (defer_flow //&& (tcpFlags & TCP_FLAG_ACK)
|
||||
&& NET_BUFFER_DATA_LENGTH(netBuf) == headerOffset) {
|
||||
NTSTATUS status;
|
||||
|
||||
status = fort_defer_add(&g_device->defer, inFixedValues, inMetaValues,
|
||||
netBufList, inbound);
|
||||
|
||||
if (!NT_SUCCESS(status)) {
|
||||
DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_ERROR_LEVEL,
|
||||
"FORT: Transport Classify: Defer error: %x\n", status);
|
||||
}
|
||||
|
||||
goto block;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
permit:
|
||||
fort_callout_classify_permit(filter, classifyOut);
|
||||
return;
|
||||
|
||||
block:
|
||||
fort_callout_classify_drop(classifyOut);
|
||||
return;
|
||||
}
|
||||
|
||||
static void
|
||||
@ -540,7 +561,7 @@ fort_callout_install (PDEVICE_OBJECT device)
|
||||
status = FwpsCalloutRegister0(device, &c, &g_device->connect4_id);
|
||||
if (!NT_SUCCESS(status)) {
|
||||
DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_ERROR_LEVEL,
|
||||
"FORT: Register Connect V4: Error: %d\n", status);
|
||||
"FORT: Register Connect V4: Error: %x\n", status);
|
||||
return status;
|
||||
}
|
||||
|
||||
@ -551,7 +572,7 @@ fort_callout_install (PDEVICE_OBJECT device)
|
||||
status = FwpsCalloutRegister0(device, &c, &g_device->accept4_id);
|
||||
if (!NT_SUCCESS(status)) {
|
||||
DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_ERROR_LEVEL,
|
||||
"FORT: Register Accept V4: Error: %d\n", status);
|
||||
"FORT: Register Accept V4: Error: %x\n", status);
|
||||
return status;
|
||||
}
|
||||
|
||||
@ -565,7 +586,7 @@ fort_callout_install (PDEVICE_OBJECT device)
|
||||
status = FwpsCalloutRegister0(device, &c, &g_device->stat.stream4_id);
|
||||
if (!NT_SUCCESS(status)) {
|
||||
DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_ERROR_LEVEL,
|
||||
"FORT: Register Stream V4: Error: %d\n", status);
|
||||
"FORT: Register Stream V4: Error: %x\n", status);
|
||||
return status;
|
||||
}
|
||||
|
||||
@ -578,7 +599,7 @@ fort_callout_install (PDEVICE_OBJECT device)
|
||||
status = FwpsCalloutRegister0(device, &c, &g_device->stat.datagram4_id);
|
||||
if (!NT_SUCCESS(status)) {
|
||||
DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_ERROR_LEVEL,
|
||||
"FORT: Register Datagram V4: Error: %d\n", status);
|
||||
"FORT: Register Datagram V4: Error: %x\n", status);
|
||||
return status;
|
||||
}
|
||||
|
||||
@ -589,7 +610,7 @@ fort_callout_install (PDEVICE_OBJECT device)
|
||||
status = FwpsCalloutRegister0(device, &c, &g_device->stat.in_transport4_id);
|
||||
if (!NT_SUCCESS(status)) {
|
||||
DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_ERROR_LEVEL,
|
||||
"FORT: Register Inbound Transport V4: Error: %d\n", status);
|
||||
"FORT: Register Inbound Transport V4: Error: %x\n", status);
|
||||
return status;
|
||||
}
|
||||
|
||||
@ -600,7 +621,7 @@ fort_callout_install (PDEVICE_OBJECT device)
|
||||
status = FwpsCalloutRegister0(device, &c, &g_device->stat.out_transport4_id);
|
||||
if (!NT_SUCCESS(status)) {
|
||||
DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_ERROR_LEVEL,
|
||||
"FORT: Register Outbound Transport V4: Error: %d\n", status);
|
||||
"FORT: Register Outbound Transport V4: Error: %x\n", status);
|
||||
return status;
|
||||
}
|
||||
|
||||
@ -667,7 +688,7 @@ fort_callout_force_reauth (PDEVICE_OBJECT device,
|
||||
if ((status = fort_prov_register(engine, conf_flags.prov_boot)))
|
||||
goto cleanup;
|
||||
|
||||
goto stat;
|
||||
goto stat_prov;
|
||||
}
|
||||
|
||||
/* Check flow filter */
|
||||
@ -676,10 +697,10 @@ fort_callout_force_reauth (PDEVICE_OBJECT device,
|
||||
fort_prov_flow_unregister(engine);
|
||||
}
|
||||
|
||||
stat:
|
||||
stat_prov:
|
||||
if (conf_flags.log_stat) {
|
||||
if ((status = fort_prov_flow_register(engine,
|
||||
(conf_flags.ignore_tcp_rst != 0))))
|
||||
(conf_flags.ignore_tcp_rst || stat->limit_bits))))
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
@ -703,7 +724,7 @@ fort_callout_force_reauth (PDEVICE_OBJECT device,
|
||||
end:
|
||||
if (!NT_SUCCESS(status)) {
|
||||
DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_ERROR_LEVEL,
|
||||
"FORT: Callout Reauth: Error: %d\n", status);
|
||||
"FORT: Callout Reauth: Error: %x\n", status);
|
||||
}
|
||||
|
||||
return status;
|
||||
@ -715,8 +736,8 @@ fort_callout_timer (void)
|
||||
PFORT_BUFFER buf = &g_device->buffer;
|
||||
PFORT_STAT stat = &g_device->stat;
|
||||
|
||||
KLOCK_QUEUE_HANDLE stat_lock_queue;
|
||||
KLOCK_QUEUE_HANDLE buf_lock_queue;
|
||||
KLOCK_QUEUE_HANDLE stat_lock_queue;
|
||||
|
||||
PIRP irp = NULL;
|
||||
ULONG_PTR info;
|
||||
@ -755,6 +776,19 @@ fort_callout_timer (void)
|
||||
if (irp != NULL) {
|
||||
fort_request_complete_info(irp, STATUS_SUCCESS, info);
|
||||
}
|
||||
|
||||
/* Flush deferred packets */
|
||||
fort_defer_dpc_flush(&g_device->defer, fort_transport_inject_complete);
|
||||
}
|
||||
|
||||
static void
|
||||
fort_callout_timer_force (void)
|
||||
{
|
||||
KLOCK_QUEUE_HANDLE lock_queue;
|
||||
|
||||
KeAcquireInStackQueuedSpinLock(&g_device->conf_lock, &lock_queue);
|
||||
fort_callout_timer(); // Should be called from DISPATCH_LEVEL!
|
||||
KeReleaseInStackQueuedSpinLock(&lock_queue);
|
||||
}
|
||||
|
||||
static NTSTATUS
|
||||
@ -903,7 +937,7 @@ fort_device_control (PDEVICE_OBJECT device, PIRP irp)
|
||||
|
||||
if (!NT_SUCCESS(status)) {
|
||||
DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_ERROR_LEVEL,
|
||||
"FORT: Device Control: Error: %d\n", status);
|
||||
"FORT: Device Control: Error: %x\n", status);
|
||||
}
|
||||
|
||||
fort_request_complete_info(irp, status, info);
|
||||
@ -911,16 +945,73 @@ fort_device_control (PDEVICE_OBJECT device, PIRP irp)
|
||||
return status;
|
||||
}
|
||||
|
||||
static void
|
||||
fort_power_callback (PVOID context, PVOID event, PVOID specifics)
|
||||
{
|
||||
BOOL power_off;
|
||||
|
||||
UNUSED(context);
|
||||
|
||||
if (event != (PVOID) PO_CB_SYSTEM_STATE_LOCK)
|
||||
return;
|
||||
|
||||
power_off = (specifics == NULL);
|
||||
g_device->power_off = power_off;
|
||||
|
||||
if (power_off) {
|
||||
fort_callout_timer_force();
|
||||
}
|
||||
}
|
||||
|
||||
static NTSTATUS
|
||||
fort_power_callback_register (void)
|
||||
{
|
||||
OBJECT_ATTRIBUTES obj_attr;
|
||||
UNICODE_STRING obj_name;
|
||||
NTSTATUS status;
|
||||
|
||||
RtlInitUnicodeString(&obj_name, L"\\Callback\\PowerState");
|
||||
|
||||
InitializeObjectAttributes(&obj_attr, &obj_name,
|
||||
OBJ_CASE_INSENSITIVE, NULL, NULL);
|
||||
|
||||
status = ExCreateCallback(&g_device->power_cb_obj, &obj_attr, FALSE, TRUE);
|
||||
|
||||
if (NT_SUCCESS(status)) {
|
||||
g_device->power_cb_reg = ExRegisterCallback(g_device->power_cb_obj,
|
||||
fort_power_callback, NULL);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static void
|
||||
fort_power_callback_unregister (void)
|
||||
{
|
||||
if (g_device->power_cb_reg != NULL) {
|
||||
ExUnregisterCallback(g_device->power_cb_reg);
|
||||
}
|
||||
|
||||
if (g_device->power_cb_obj != NULL) {
|
||||
ObDereferenceObject(g_device->power_cb_obj);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
fort_driver_unload (PDRIVER_OBJECT driver)
|
||||
{
|
||||
UNICODE_STRING device_link;
|
||||
|
||||
if (g_device != NULL) {
|
||||
fort_callout_timer_force();
|
||||
|
||||
fort_timer_close(&g_device->timer);
|
||||
fort_defer_close(&g_device->defer);
|
||||
fort_stat_close(&g_device->stat);
|
||||
fort_buffer_close(&g_device->buffer);
|
||||
|
||||
fort_power_callback_unregister();
|
||||
|
||||
if (!g_device->prov_boot) {
|
||||
fort_prov_unregister(0);
|
||||
}
|
||||
@ -993,6 +1084,7 @@ DriverEntry (PDRIVER_OBJECT driver, PUNICODE_STRING reg_path)
|
||||
|
||||
fort_buffer_open(&g_device->buffer);
|
||||
fort_stat_open(&g_device->stat);
|
||||
fort_defer_open(&g_device->defer);
|
||||
fort_timer_open(&g_device->timer, &fort_callout_timer);
|
||||
|
||||
KeInitializeSpinLock(&g_device->conf_lock);
|
||||
@ -1011,12 +1103,17 @@ DriverEntry (PDRIVER_OBJECT driver, PUNICODE_STRING reg_path)
|
||||
if (NT_SUCCESS(status)) {
|
||||
status = fort_prov_register(0, g_device->prov_boot);
|
||||
}
|
||||
|
||||
/* Register power state change callback */
|
||||
if (NT_SUCCESS(status)) {
|
||||
status = fort_power_callback_register();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!NT_SUCCESS(status)) {
|
||||
DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_ERROR_LEVEL,
|
||||
"FORT: Entry: Error: %d\n", status);
|
||||
"FORT: Entry: Error: %x\n", status);
|
||||
fort_driver_unload(driver);
|
||||
}
|
||||
|
||||
|
353
src/driver/fortpkt.c
Normal file
353
src/driver/fortpkt.c
Normal file
@ -0,0 +1,353 @@
|
||||
/* Fort Firewall ACK Packets Deferring & Re-injection */
|
||||
|
||||
#define HTONL(l) _byteswap_ulong(l)
|
||||
#define NTOHL(l) HTONL(l)
|
||||
#define HTONS(s) _byteswap_ushort(s)
|
||||
#define NTOHS(s) HTONS(s)
|
||||
|
||||
#define TCP_FLAG_FIN 0x0001
|
||||
#define TCP_FLAG_SYN 0x0002
|
||||
#define TCP_FLAG_RST 0x0004
|
||||
#define TCP_FLAG_PSH 0x0008
|
||||
#define TCP_FLAG_ACK 0x0010
|
||||
#define TCP_FLAG_URG 0x0020
|
||||
#define TCP_FLAG_ECE 0x0040
|
||||
#define TCP_FLAG_CWR 0x0080
|
||||
|
||||
typedef struct tcp_header {
|
||||
UINT16 source; // Source Port
|
||||
UINT16 dest; // Destination Port
|
||||
|
||||
UINT32 seq; // Sequence number
|
||||
UINT32 ack_seq; // Acknowledgement number
|
||||
|
||||
UCHAR res1 : 4; // Unused
|
||||
UCHAR doff : 4; // Data offset
|
||||
|
||||
UCHAR flags; // Flags
|
||||
|
||||
UINT16 window; // Window size
|
||||
UINT16 csum; // Checksum
|
||||
UINT16 urg_ptr; // Urgent Pointer
|
||||
} TCP_HEADER, *PTCP_HEADER;
|
||||
|
||||
typedef struct fort_packet_in {
|
||||
IF_INDEX interfaceIndex;
|
||||
IF_INDEX subInterfaceIndex;
|
||||
|
||||
UINT16 ipHeaderSize;
|
||||
UINT16 transportHeaderSize;
|
||||
|
||||
UINT16 nblOffset;
|
||||
} FORT_PACKET_IN, *PFORT_PACKET_IN;
|
||||
|
||||
typedef struct fort_packet_out {
|
||||
UINT32 remoteAddr4;
|
||||
|
||||
SCOPE_ID remoteScopeId;
|
||||
UINT64 endpointHandle;
|
||||
} FORT_PACKET_OUT, *PFORT_PACKET_OUT;
|
||||
|
||||
typedef struct fort_packet {
|
||||
BOOL inbound;
|
||||
|
||||
COMPARTMENT_ID compartmentId;
|
||||
|
||||
PNET_BUFFER_LIST netBufList;
|
||||
|
||||
struct fort_packet *next;
|
||||
|
||||
union {
|
||||
FORT_PACKET_IN in;
|
||||
FORT_PACKET_OUT out;
|
||||
};
|
||||
} FORT_PACKET, *PFORT_PACKET;
|
||||
|
||||
typedef struct fort_defer {
|
||||
HANDLE injection4_id;
|
||||
|
||||
PFORT_PACKET packet_head;
|
||||
PFORT_PACKET packet_tail;
|
||||
PFORT_PACKET packet_free;
|
||||
|
||||
tommy_arrayof packets;
|
||||
|
||||
KSPIN_LOCK lock;
|
||||
} FORT_DEFER, *PFORT_DEFER;
|
||||
|
||||
typedef void (*FORT_INJECT_COMPLETE_FUNC) (PFORT_PACKET, PNET_BUFFER_LIST, BOOLEAN);
|
||||
|
||||
|
||||
static void
|
||||
fort_defer_open (PFORT_DEFER defer)
|
||||
{
|
||||
NTSTATUS status;
|
||||
|
||||
status = FwpsInjectionHandleCreate0(AF_INET, FWPS_INJECTION_TYPE_TRANSPORT,
|
||||
&defer->injection4_id);
|
||||
|
||||
if (!NT_SUCCESS(status)) {
|
||||
defer->injection4_id = INVALID_HANDLE_VALUE;
|
||||
|
||||
DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_ERROR_LEVEL,
|
||||
"FORT: Defer: Injection init error: %x\n", status);
|
||||
}
|
||||
|
||||
tommy_arrayof_init(&defer->packets, sizeof(FORT_PACKET));
|
||||
|
||||
KeInitializeSpinLock(&defer->lock);
|
||||
}
|
||||
|
||||
static void
|
||||
fort_defer_close (PFORT_DEFER defer)
|
||||
{
|
||||
FwpsInjectionHandleDestroy0(defer->injection4_id);
|
||||
|
||||
tommy_arrayof_done(&defer->packets);
|
||||
}
|
||||
|
||||
static NTSTATUS
|
||||
fort_defer_add (PFORT_DEFER defer,
|
||||
const FWPS_INCOMING_VALUES0 *inFixedValues,
|
||||
const FWPS_INCOMING_METADATA_VALUES0 *inMetaValues,
|
||||
PNET_BUFFER_LIST netBufList,
|
||||
BOOL inbound)
|
||||
{
|
||||
KLOCK_QUEUE_HANDLE lock_queue;
|
||||
PFORT_PACKET pkt;
|
||||
NTSTATUS status;
|
||||
|
||||
if (defer->injection4_id == INVALID_HANDLE_VALUE)
|
||||
return STATUS_FWP_TCPIP_NOT_READY;
|
||||
|
||||
/* Skip IpSec protected packet */
|
||||
if (inbound) {
|
||||
FWPS_PACKET_LIST_INFORMATION info;
|
||||
|
||||
status = FwpsGetPacketListSecurityInformation0(netBufList,
|
||||
FWPS_PACKET_LIST_INFORMATION_QUERY_IPSEC
|
||||
| FWPS_PACKET_LIST_INFORMATION_QUERY_INBOUND, &info);
|
||||
|
||||
if (!NT_SUCCESS(status))
|
||||
return status;
|
||||
|
||||
if (info.ipsecInformation.inbound.isSecure)
|
||||
return STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
|
||||
KeAcquireInStackQueuedSpinLock(&defer->lock, &lock_queue);
|
||||
|
||||
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) {
|
||||
status = STATUS_INSUFFICIENT_RESOURCES;
|
||||
goto end;
|
||||
}
|
||||
|
||||
pkt = tommy_arrayof_ref(&defer->packets, size);
|
||||
}
|
||||
|
||||
if (defer->packet_tail == NULL) {
|
||||
defer->packet_head = defer->packet_tail = pkt;
|
||||
} else {
|
||||
defer->packet_tail->next = pkt;
|
||||
}
|
||||
|
||||
pkt->inbound = inbound;
|
||||
pkt->compartmentId = inMetaValues->compartmentId;
|
||||
pkt->netBufList = netBufList;
|
||||
pkt->next = NULL;
|
||||
|
||||
if (inbound) {
|
||||
PFORT_PACKET_IN pkt_in = &pkt->in;
|
||||
|
||||
const int interfaceField = inbound
|
||||
? FWPS_FIELD_INBOUND_TRANSPORT_V4_INTERFACE_INDEX
|
||||
: FWPS_FIELD_OUTBOUND_TRANSPORT_V4_INTERFACE_INDEX;
|
||||
|
||||
const int subInterfaceField = inbound
|
||||
? FWPS_FIELD_INBOUND_TRANSPORT_V4_SUB_INTERFACE_INDEX
|
||||
: FWPS_FIELD_OUTBOUND_TRANSPORT_V4_SUB_INTERFACE_INDEX;
|
||||
|
||||
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(
|
||||
NET_BUFFER_LIST_FIRST_NB(netBufList));
|
||||
} else {
|
||||
PFORT_PACKET_OUT pkt_out = &pkt->out;
|
||||
|
||||
const int remoteAddrField = inbound
|
||||
? FWPS_FIELD_INBOUND_TRANSPORT_V4_IP_REMOTE_ADDRESS
|
||||
: FWPS_FIELD_OUTBOUND_TRANSPORT_V4_IP_REMOTE_ADDRESS;
|
||||
|
||||
/* host-order -> network-order conversion */
|
||||
pkt_out->remoteAddr4 = HTONL(
|
||||
inFixedValues->incomingValue[remoteAddrField].value.uint32);
|
||||
|
||||
pkt_out->remoteScopeId = inMetaValues->remoteScopeId;
|
||||
pkt_out->endpointHandle = inMetaValues->transportEndpointHandle;
|
||||
}
|
||||
|
||||
FwpsReferenceNetBufferList0(netBufList, TRUE);
|
||||
|
||||
status = STATUS_SUCCESS;
|
||||
|
||||
end:
|
||||
KeReleaseInStackQueuedSpinLock(&lock_queue);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static void
|
||||
fort_defer_free (PFORT_DEFER defer, PFORT_PACKET pkt,
|
||||
PNET_BUFFER_LIST clonedNetBufList,
|
||||
BOOL dispatchLevel)
|
||||
{
|
||||
KLOCK_QUEUE_HANDLE lock_queue;
|
||||
|
||||
if (clonedNetBufList != NULL) {
|
||||
const NTSTATUS status = clonedNetBufList->Status;
|
||||
|
||||
if (!NT_SUCCESS(status)) {
|
||||
DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_ERROR_LEVEL,
|
||||
"FORT: Defer: Injection error: %x\n", status);
|
||||
}
|
||||
|
||||
FwpsFreeCloneNetBufferList0(clonedNetBufList, 0);
|
||||
}
|
||||
|
||||
FwpsDereferenceNetBufferList0(pkt->netBufList, FALSE);
|
||||
|
||||
/* Add to free chain */
|
||||
if (dispatchLevel) {
|
||||
KeAcquireInStackQueuedSpinLockAtDpcLevel(&defer->lock, &lock_queue);
|
||||
} else {
|
||||
KeAcquireInStackQueuedSpinLock(&defer->lock, &lock_queue);
|
||||
}
|
||||
|
||||
pkt->next = defer->packet_free;
|
||||
defer->packet_free = pkt;
|
||||
|
||||
if (dispatchLevel) {
|
||||
KeReleaseInStackQueuedSpinLockFromDpcLevel(&lock_queue);
|
||||
} else {
|
||||
KeReleaseInStackQueuedSpinLock(&lock_queue);
|
||||
}
|
||||
}
|
||||
|
||||
static NTSTATUS
|
||||
fort_defer_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_in->nblOffset != 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->injection4_id, NULL, NULL, 0,
|
||||
AF_INET, pkt->compartmentId,
|
||||
pkt_in->interfaceIndex, pkt_in->subInterfaceIndex,
|
||||
*clonedNetBufList, complete_func, pkt);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
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_dpc_flush (PFORT_DEFER defer, FORT_INJECT_COMPLETE_FUNC complete_func)
|
||||
{
|
||||
KLOCK_QUEUE_HANDLE lock_queue;
|
||||
PFORT_PACKET pkt;
|
||||
|
||||
KeAcquireInStackQueuedSpinLockAtDpcLevel(&defer->lock, &lock_queue);
|
||||
|
||||
pkt = defer->packet_head;
|
||||
if (pkt != NULL) {
|
||||
defer->packet_head = defer->packet_tail = NULL;
|
||||
}
|
||||
|
||||
KeReleaseInStackQueuedSpinLockFromDpcLevel(&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)) {
|
||||
if (clonedNetBufList != NULL) {
|
||||
clonedNetBufList->Status = status;
|
||||
} else {
|
||||
DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_ERROR_LEVEL,
|
||||
"FORT: Defer: Injection prepare error: %x\n", status);
|
||||
}
|
||||
|
||||
fort_defer_free(defer, pkt, clonedNetBufList, TRUE);
|
||||
}
|
||||
|
||||
pkt = pkt_next;
|
||||
}
|
||||
}
|
@ -30,6 +30,8 @@ typedef struct fort_stat_proc {
|
||||
|
||||
typedef struct fort_stat_flow_opt {
|
||||
UCHAR speed_limit : 1;
|
||||
UCHAR defer_in : 1;
|
||||
UCHAR defer_out : 1;
|
||||
UCHAR group_index;
|
||||
UINT16 proc_index;
|
||||
} FORT_STAT_FLOW_OPT, *PFORT_STAT_FLOW_OPT;
|
||||
@ -43,7 +45,7 @@ typedef struct fort_stat_flow {
|
||||
#if defined(_WIN64)
|
||||
UINT64 flow_id;
|
||||
#else
|
||||
FORT_STAT_FLOW_OPT opt;
|
||||
FORT_STAT_FLOW_OPT volatile opt;
|
||||
#endif
|
||||
void *data;
|
||||
};
|
||||
@ -51,7 +53,7 @@ typedef struct fort_stat_flow {
|
||||
tommy_key_t flow_hash;
|
||||
|
||||
#if defined(_WIN64)
|
||||
FORT_STAT_FLOW_OPT opt;
|
||||
FORT_STAT_FLOW_OPT volatile opt;
|
||||
#else
|
||||
UINT64 flow_id;
|
||||
#endif
|
||||
@ -345,6 +347,7 @@ fort_stat_flow_add (PFORT_STAT stat, UINT64 flow_id,
|
||||
}
|
||||
|
||||
flow->opt.speed_limit = (UCHAR) speed_limit;
|
||||
flow->opt.defer_in = flow->opt.defer_out = FALSE;
|
||||
flow->opt.group_index = group_index;
|
||||
flow->opt.proc_index = proc_index;
|
||||
|
||||
@ -525,13 +528,23 @@ fort_stat_flow_classify (PFORT_STAT stat, UINT64 flowContext,
|
||||
PFORT_STAT_GROUP group = &stat->groups[group_index];
|
||||
UINT32 *group_bytes = inbound ? &group->traf.in_bytes
|
||||
: &group->traf.out_bytes;
|
||||
UCHAR defer_flow = TRUE;
|
||||
|
||||
if (*group_bytes < limit_bytes) {
|
||||
// Add traffic to app. group
|
||||
*group_bytes += data_len;
|
||||
|
||||
defer_flow = (*group_bytes >= limit_bytes);
|
||||
} else {
|
||||
limited = TRUE;
|
||||
}
|
||||
|
||||
// Defer ACK
|
||||
if (inbound) {
|
||||
flow->opt.defer_out = defer_flow;
|
||||
} else {
|
||||
flow->opt.defer_in = defer_flow;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user