From 65866dedf37a7ba4d1c54caef9560c9b58414229 Mon Sep 17 00:00:00 2001 From: Nodir Temirkhodjaev Date: Tue, 16 Mar 2021 21:36:12 +0300 Subject: [PATCH] Driver: Extract Callouts & Device functions from fortdrv.c --- src/driver/Driver.pri | 2 +- src/driver/FortFirewallDriver.pro | 4 + src/driver/common/{fortdev.h => fortdef.h} | 10 +- src/driver/common/fortprov.c | 2 +- src/driver/fortcout.c | 770 +++++++++++++ src/driver/fortcout.h | 27 + src/driver/fortdev.c | 276 +++++ src/driver/fortdev.h | 55 + src/driver/fortdrv.c | 1143 +------------------- src/driver/fortdrv.h | 9 + src/driver/fortdrv_amalg.c | 2 + src/ui/fortcommon.cpp | 2 +- 12 files changed, 1195 insertions(+), 1107 deletions(-) rename src/driver/common/{fortdev.h => fortdef.h} (94%) create mode 100644 src/driver/fortcout.c create mode 100644 src/driver/fortcout.h create mode 100644 src/driver/fortdev.c create mode 100644 src/driver/fortdev.h diff --git a/src/driver/Driver.pri b/src/driver/Driver.pri index 9c81347b..351ac024 100644 --- a/src/driver/Driver.pri +++ b/src/driver/Driver.pri @@ -9,7 +9,7 @@ SOURCES += \ HEADERS += \ $$PWD/common/common.h \ $$PWD/common/fortconf.h \ - $$PWD/common/fortdev.h \ + $$PWD/common/fortdef.h \ $$PWD/common/fortlog.h \ $$PWD/common/fortprov.h \ $$PWD/common/wildmatch.h diff --git a/src/driver/FortFirewallDriver.pro b/src/driver/FortFirewallDriver.pro index 47bbb104..929e1286 100644 --- a/src/driver/FortFirewallDriver.pro +++ b/src/driver/FortFirewallDriver.pro @@ -6,6 +6,8 @@ SOURCES += \ dummy.c \ fortbuf.c \ fortcnf.c \ + fortcout.c \ + fortdev.c \ fortdrv.c \ fortpkt.c \ fortstat.c \ @@ -21,6 +23,8 @@ SOURCES += \ HEADERS += \ fortbuf.h \ fortcnf.h \ + fortcout.h \ + fortdev.h \ fortdrv.h \ fortpkt.h \ fortstat.h \ diff --git a/src/driver/common/fortdev.h b/src/driver/common/fortdef.h similarity index 94% rename from src/driver/common/fortdev.h rename to src/driver/common/fortdef.h index ea0fba2d..761fc04c 100644 --- a/src/driver/common/fortdev.h +++ b/src/driver/common/fortdef.h @@ -1,5 +1,5 @@ -#ifndef FORTDEV_H -#define FORTDEV_H +#ifndef FORTDEF_H +#define FORTDEF_H #include "common.h" @@ -72,7 +72,9 @@ DEFINE_GUID(FORT_GUID_FILTER_REAUTH_IN, 0xc2d858f8, 0x2951, 0x4eed, 0x8d, 0xa1, DEFINE_GUID(FORT_GUID_FILTER_REAUTH_OUT, 0x749709ce, 0x9686, 0x4056, 0xb8, 0x9a, 0x7a, 0x58, 0x52, 0xdf, 0xc8, 0x98); -#define FORT_DEVICE_NAME "\\\\.\\fortfw" +#define FORT_DEVICE_NAME "\\\\.\\fortfw" +#define FORT_NT_DEVICE_NAME L"\\Device\\fortfw" +#define FORT_DOS_DEVICE_NAME L"\\DosDevices\\fortfw" #define FORT_DEVICE_TYPE 0xD000 #define FORT_IOCTL_BASE 0xD00 @@ -88,4 +90,4 @@ DEFINE_GUID(FORT_GUID_FILTER_REAUTH_OUT, 0x749709ce, 0x9686, 0x4056, 0xb8, 0x9a, #define FORT_IOCTL_SETZONES FORT_CTL_CODE(6, FILE_WRITE_DATA) #define FORT_IOCTL_SETZONEFLAG FORT_CTL_CODE(7, FILE_WRITE_DATA) -#endif // FORTDEV_H +#endif // FORTDEF_H diff --git a/src/driver/common/fortprov.c b/src/driver/common/fortprov.c index b2752e22..731b63ef 100644 --- a/src/driver/common/fortprov.c +++ b/src/driver/common/fortprov.c @@ -1,6 +1,6 @@ /* Fort Firewall Driver Provider (Un)Registration */ -#include "fortdev.h" +#include "fortdef.h" #include "fortprov.h" FORT_API void fort_prov_unregister(HANDLE transEngine) diff --git a/src/driver/fortcout.c b/src/driver/fortcout.c new file mode 100644 index 00000000..70d11164 --- /dev/null +++ b/src/driver/fortcout.c @@ -0,0 +1,770 @@ +/* Fort Firewall Callouts */ + +#include "fortcout.h" + +#include "common/fortdef.h" +#include "common/fortprov.h" + +#include "fortdev.h" + +static void fort_callout_classify_block(FWPS_CLASSIFY_OUT0 *classifyOut) +{ + classifyOut->actionType = FWP_ACTION_BLOCK; + classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE; +} + +static void fort_callout_classify_drop(FWPS_CLASSIFY_OUT0 *classifyOut) +{ + classifyOut->flags |= FWPS_CLASSIFY_OUT_FLAG_ABSORB; + + fort_callout_classify_block(classifyOut); +} + +static void fort_callout_classify_permit( + const FWPS_FILTER0 *filter, FWPS_CLASSIFY_OUT0 *classifyOut) +{ + classifyOut->actionType = FWP_ACTION_PERMIT; + if ((filter->flags & FWPS_FILTER_FLAG_CLEAR_ACTION_RIGHT)) { + classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE; + } +} + +static void fort_callout_classify_continue(FWPS_CLASSIFY_OUT0 *classifyOut) +{ + classifyOut->actionType = FWP_ACTION_CONTINUE; +} + +static void fort_callout_classify_v4(const FWPS_INCOMING_VALUES0 *inFixedValues, + const FWPS_INCOMING_METADATA_VALUES0 *inMetaValues, const FWPS_FILTER0 *filter, + FWPS_CLASSIFY_OUT0 *classifyOut, int flagsField, int localIpField, int remoteIpField, + int localPortField, int remotePortField, int ipProtoField, BOOL inbound) +{ + PIRP irp = NULL; + ULONG_PTR info; + + const UINT32 flags = inFixedValues->incomingValue[flagsField].value.uint32; + const UINT32 remote_ip = inFixedValues->incomingValue[remoteIpField].value.uint32; + + if (!fort_device()->conf.conf_flags.filter_locals + && ((flags & FWP_CONDITION_FLAG_IS_LOOPBACK) + || remote_ip == 0xFFFFFFFF)) { /* Local broadcast */ + fort_callout_classify_permit(filter, classifyOut); + return; + } + + PFORT_CONF_REF conf_ref = fort_conf_ref_take(&fort_device()->conf); + + if (conf_ref == NULL) { + if (fort_device_flag(&fort_device()->conf, FORT_DEVICE_PROV_BOOT)) { + fort_callout_classify_block(classifyOut); + } else { + fort_callout_classify_continue(classifyOut); + } + return; + } + + const FORT_CONF_FLAGS conf_flags = conf_ref->conf.flags; + + const UINT32 process_id = (UINT32) inMetaValues->processId; + const UINT32 path_len = + inMetaValues->processPath->size - sizeof(WCHAR); /* chop terminating zero */ + const PVOID path = inMetaValues->processPath->data; + + UCHAR block_reason = FORT_BLOCK_REASON_UNKNOWN; + BOOL blocked = TRUE; + + if (conf_flags.filter_enabled) { + if (conf_flags.stop_traffic) + goto end; + + if (!fort_conf_ip_is_inet(&conf_ref->conf, + (fort_conf_zones_ip_included_func *) fort_conf_zones_ip_included, + &fort_device()->conf, remote_ip)) { + blocked = FALSE; /* permit (LAN) */ + goto end; + } + + if (conf_flags.stop_inet_traffic) + goto end; + + if (!fort_conf_ip_inet_included(&conf_ref->conf, + (fort_conf_zones_ip_included_func *) fort_conf_zones_ip_included, + &fort_device()->conf, remote_ip)) { + block_reason = FORT_BLOCK_REASON_IP_INET; + goto end; + } + } else { + blocked = FALSE; /* permit (Filter Disabled) */ + if (!(conf_flags.log_stat && conf_flags.log_stat_no_filter)) + goto end; + } + + FORT_APP_FLAGS app_flags = + fort_conf_app_find(&conf_ref->conf, path, path_len, fort_conf_exe_find); + + if (!blocked /* collect traffic, when Filter Disabled */ + || (app_flags.v == 0 && conf_flags.allow_all_new) /* collect new Blocked Programs */ + || !fort_conf_app_blocked(&conf_ref->conf, app_flags, &block_reason)) { + if (conf_flags.log_stat) { + const UINT64 flow_id = inMetaValues->flowHandle; + + const IPPROTO ip_proto = + (IPPROTO) inFixedValues->incomingValue[ipProtoField].value.uint8; + const BOOL is_tcp = (ip_proto == IPPROTO_TCP); + + const UCHAR group_index = app_flags.group_index; + const BOOL is_reauth = (flags & FWP_CONDITION_FLAG_IS_REAUTHORIZE); + + BOOL is_new_proc = FALSE; + NTSTATUS status; + + status = fort_flow_associate(&fort_device()->stat, flow_id, process_id, group_index, + is_tcp, is_reauth, &is_new_proc); + + if (!NT_SUCCESS(status)) { + if (status == FORT_STATUS_FLOW_BLOCK) { + block_reason = FORT_BLOCK_REASON_REAUTH; + blocked = TRUE; + goto end; + } + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_ERROR_LEVEL, + "FORT: Classify v4: Flow assoc. error: %x\n", status); + } else if (is_new_proc) { + fort_buffer_proc_new_write( + &fort_device()->buffer, process_id, path_len, path, &irp, &info); + } + } + + blocked = FALSE; /* permit */ + } + + if (app_flags.v == 0 && (conf_flags.allow_all_new || conf_flags.log_blocked) + && conf_flags.filter_enabled) { + app_flags.blocked = (UCHAR) blocked; + app_flags.alerted = 1; + app_flags.is_new = 1; + + if (NT_SUCCESS(fort_conf_ref_exe_add_path(conf_ref, path, path_len, app_flags))) { + fort_buffer_blocked_write( + &fort_device()->buffer, blocked, process_id, path_len, path, &irp, &info); + } + } + +end: + if (blocked) { + /* Log the blocked connection */ + if (block_reason != FORT_BLOCK_REASON_UNKNOWN && conf_flags.log_blocked_ip) { + const UINT32 local_ip = inFixedValues->incomingValue[localIpField].value.uint32; + const UINT16 local_port = inFixedValues->incomingValue[localPortField].value.uint16; + const UINT16 remote_port = inFixedValues->incomingValue[remotePortField].value.uint16; + const IPPROTO ip_proto = + (IPPROTO) inFixedValues->incomingValue[ipProtoField].value.uint8; + + fort_buffer_blocked_ip_write(&fort_device()->buffer, inbound, block_reason, ip_proto, + local_port, remote_port, local_ip, remote_ip, process_id, path_len, path, &irp, + &info); + } + + /* Block the connection */ + fort_callout_classify_block(classifyOut); + } else { + /* Allow the connection */ + fort_callout_classify_permit(filter, classifyOut); + } + + fort_conf_ref_put(&fort_device()->conf, conf_ref); + + if (irp != NULL) { + fort_request_complete_info(irp, STATUS_SUCCESS, info); + } +} + +static void NTAPI fort_callout_connect_v4(const FWPS_INCOMING_VALUES0 *inFixedValues, + const FWPS_INCOMING_METADATA_VALUES0 *inMetaValues, void *layerData, + const FWPS_FILTER0 *filter, const UINT64 flowContext, FWPS_CLASSIFY_OUT0 *classifyOut) +{ + UNUSED(layerData); + UNUSED(flowContext); + + fort_callout_classify_v4(inFixedValues, inMetaValues, filter, classifyOut, + FWPS_FIELD_ALE_AUTH_CONNECT_V4_FLAGS, FWPS_FIELD_ALE_AUTH_CONNECT_V4_IP_LOCAL_ADDRESS, + FWPS_FIELD_ALE_AUTH_CONNECT_V4_IP_REMOTE_ADDRESS, + FWPS_FIELD_ALE_AUTH_CONNECT_V4_IP_LOCAL_PORT, + FWPS_FIELD_ALE_AUTH_CONNECT_V4_IP_REMOTE_PORT, + FWPS_FIELD_ALE_AUTH_CONNECT_V4_IP_PROTOCOL, FALSE); +} + +static void NTAPI fort_callout_accept_v4(const FWPS_INCOMING_VALUES0 *inFixedValues, + const FWPS_INCOMING_METADATA_VALUES0 *inMetaValues, void *layerData, + const FWPS_FILTER0 *filter, const UINT64 flowContext, FWPS_CLASSIFY_OUT0 *classifyOut) +{ + UNUSED(layerData); + UNUSED(flowContext); + + fort_callout_classify_v4(inFixedValues, inMetaValues, filter, classifyOut, + FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V4_FLAGS, + FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V4_IP_LOCAL_ADDRESS, + FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V4_IP_REMOTE_ADDRESS, + FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V4_IP_LOCAL_PORT, + FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V4_IP_REMOTE_PORT, + FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V4_IP_PROTOCOL, TRUE); +} + +static NTSTATUS NTAPI fort_callout_notify( + FWPS_CALLOUT_NOTIFY_TYPE notifyType, const GUID *filterKey, const FWPS_FILTER0 *filter) +{ + UNUSED(notifyType); + UNUSED(filterKey); + UNUSED(filter); + + return STATUS_SUCCESS; +} + +static void NTAPI fort_packet_inject_complete( + PFORT_PACKET pkt, PNET_BUFFER_LIST clonedNetBufList, BOOLEAN dispatchLevel) +{ + fort_defer_packet_free(&fort_device()->defer, pkt, clonedNetBufList, dispatchLevel); +} + +static void fort_callout_defer_packet_flush(UINT32 list_bits, BOOL dispatchLevel) +{ + fort_defer_packet_flush( + &fort_device()->defer, fort_packet_inject_complete, list_bits, dispatchLevel); +} + +static void fort_callout_defer_stream_flush(UINT64 flow_id, BOOL dispatchLevel) +{ + UNUSED(dispatchLevel); + + fort_defer_stream_flush(&fort_device()->defer, fort_packet_inject_complete, flow_id, FALSE); +} + +FORT_API void fort_callout_defer_flush(void) +{ + fort_callout_defer_packet_flush(FORT_DEFER_FLUSH_ALL, FALSE); + fort_callout_defer_stream_flush(FORT_DEFER_STREAM_ALL, FALSE); +} + +static void fort_callout_flow_classify_v4(const FWPS_INCOMING_METADATA_VALUES0 *inMetaValues, + UINT64 flowContext, FWPS_CLASSIFY_OUT0 *classifyOut, UINT32 dataSize, BOOL is_tcp, + BOOL inbound) +{ + const UINT32 headerSize = inbound ? inMetaValues->transportHeaderSize : 0; + + UNUSED(classifyOut); + + fort_flow_classify(&fort_device()->stat, flowContext, headerSize + dataSize, is_tcp, inbound); +} + +static void NTAPI fort_callout_stream_classify_v4(const FWPS_INCOMING_VALUES0 *inFixedValues, + const FWPS_INCOMING_METADATA_VALUES0 *inMetaValues, FWPS_STREAM_CALLOUT_IO_PACKET0 *packet, + const FWPS_FILTER0 *filter, UINT64 flowContext, FWPS_CLASSIFY_OUT0 *classifyOut) +{ + const FWPS_STREAM_DATA0 *streamData = packet->streamData; + const UINT32 streamFlags = streamData->flags; + const UINT32 dataSize = (UINT32) streamData->dataLength; + + const BOOL inbound = (streamFlags & FWPS_STREAM_FLAG_RECEIVE) != 0; + + UNUSED(inFixedValues); + + fort_callout_flow_classify_v4(inMetaValues, flowContext, classifyOut, dataSize, TRUE, inbound); + +/* Flush flow's deferred TCP packets on FIN */ +#if 0 + if (streamFlags & (FWPS_STREAM_FLAG_RECEIVE_DISCONNECT + | FWPS_STREAM_FLAG_SEND_DISCONNECT)) { + PFORT_FLOW flow = (PFORT_FLOW) flowContext; + + const UCHAR flow_flags = fort_flow_flags(flow); + + if (flow_flags & FORT_FLOW_SPEED_LIMIT) { + fort_callout_defer_packet_flush(flow->flow_id, FORT_DEFER_FLUSH_ALL, FALSE); + } + + if (flow_flags & FORT_FLOW_FRAGMENT) { + fort_callout_defer_stream_flush(flow->flow_id, FALSE); + } + + goto permit; + } +#endif + + /* Fragment first TCP packet */ + if ((streamFlags + & (FWPS_STREAM_FLAG_SEND | FWPS_STREAM_FLAG_SEND_EXPEDITED + | FWPS_STREAM_FLAG_SEND_DISCONNECT)) + == FWPS_STREAM_FLAG_SEND) { + PFORT_FLOW flow = (PFORT_FLOW) flowContext; + + const UCHAR flow_flags = fort_flow_flags(flow); + + const UCHAR fragment_flags = (flow_flags + & (FORT_FLOW_FRAGMENT | FORT_FLOW_FRAGMENT_DEFER | FORT_FLOW_FRAGMENTED)); + + if (fragment_flags != 0 && !(fragment_flags & FORT_FLOW_FRAGMENTED)) { + const UCHAR fragment_size = 3; + + if (fragment_flags & FORT_FLOW_FRAGMENT_DEFER) { + const NTSTATUS status = fort_defer_stream_add(&fort_device()->defer, inFixedValues, + inMetaValues, streamData, filter, inbound); + + if (NT_SUCCESS(status)) + goto drop; + + fort_flow_flags_set(flow, FORT_FLOW_FRAGMENTED, TRUE); + } else if (dataSize > fragment_size) { + packet->countBytesEnforced = fragment_size; + + fort_flow_flags_set(flow, FORT_FLOW_FRAGMENT_DEFER, TRUE); + } + } + } + + /* permit: */ + fort_callout_classify_permit(filter, classifyOut); + return; + +drop: + fort_callout_classify_drop(classifyOut); + return; +} + +static void NTAPI fort_callout_datagram_classify_v4(const FWPS_INCOMING_VALUES0 *inFixedValues, + const FWPS_INCOMING_METADATA_VALUES0 *inMetaValues, const PNET_BUFFER_LIST netBufList, + const FWPS_FILTER0 *filter, UINT64 flowContext, FWPS_CLASSIFY_OUT0 *classifyOut) +{ + const PNET_BUFFER netBuf = NET_BUFFER_LIST_FIRST_NB(netBufList); + const UINT32 dataSize = NET_BUFFER_DATA_LENGTH(netBuf); + + const FWP_DIRECTION direction = + (FWP_DIRECTION) inFixedValues->incomingValue[FWPS_FIELD_DATAGRAM_DATA_V4_DIRECTION] + .value.uint8; + const BOOL inbound = (direction == FWP_DIRECTION_INBOUND); + + fort_callout_flow_classify_v4(inMetaValues, flowContext, classifyOut, dataSize, FALSE, inbound); + + fort_callout_classify_permit(filter, classifyOut); +} + +static void NTAPI fort_callout_flow_delete_v4(UINT16 layerId, UINT32 calloutId, UINT64 flowContext) +{ + UNUSED(layerId); + UNUSED(calloutId); + + fort_flow_delete(&fort_device()->stat, flowContext); +} + +static void NTAPI fort_callout_transport_classify_v4(const FWPS_INCOMING_VALUES0 *inFixedValues, + const FWPS_INCOMING_METADATA_VALUES0 *inMetaValues, PNET_BUFFER_LIST netBufList, + const FWPS_FILTER0 *filter, UINT64 flowContext, FWPS_CLASSIFY_OUT0 *classifyOut, + BOOL inbound) +{ + PNET_BUFFER netBuf; + + if (!FWPS_IS_METADATA_FIELD_PRESENT(inMetaValues, FWPS_METADATA_FIELD_ALE_CLASSIFY_REQUIRED) + && netBufList != NULL && (netBuf = NET_BUFFER_LIST_FIRST_NB(netBufList)) != NULL) { + PFORT_FLOW flow = (PFORT_FLOW) flowContext; + + const UCHAR flow_flags = fort_flow_flags(flow); + + const UCHAR defer_flag = inbound ? FORT_FLOW_DEFER_IN : FORT_FLOW_DEFER_OUT; + const UCHAR speed_limit = inbound ? FORT_FLOW_SPEED_LIMIT_OUT : FORT_FLOW_SPEED_LIMIT_IN; + + const UCHAR speed_defer_flags = speed_limit | defer_flag; + const BOOL defer_flow = (flow_flags & speed_defer_flags) == speed_defer_flags + && !fort_device_flag(&fort_device()->conf, FORT_DEVICE_POWER_OFF); + + const BOOL fragment_packet = !inbound + && (flow_flags & (FORT_FLOW_FRAGMENT_DEFER | FORT_FLOW_FRAGMENTED)) + == FORT_FLOW_FRAGMENT_DEFER; + + /* Position in the packet data: + * FWPS_LAYER_INBOUND_TRANSPORT_V4: The beginning of the data. + * FWPS_LAYER_OUTBOUND_TRANSPORT_V4: The beginning of the transport header. + */ + const UINT32 headerOffset = inbound ? 0 : sizeof(TCP_HEADER); + +/* Ignore TCP RST-packets */ +#if 0 + const BOOL ignore_tcp_rst = inbound && fort_device()->conf_flags.ignore_tcp_rst; + + if (ignore_tcp_rst) { + TCP_HEADER buf; + PTCP_HEADER tcpHeader; + UINT32 tcpFlags; + + if (headerOffset != 0) { + NdisRetreatNetBufferDataStart(netBuf, headerOffset, 0, NULL); + } + + tcpHeader = NdisGetDataBuffer(netBuf, sizeof(TCP_HEADER), &buf, 1, 0); + tcpFlags = tcpHeader ? tcpHeader->flags : 0; + + if (headerOffset != 0) { + NdisAdvanceNetBufferDataStart(netBuf, headerOffset, FALSE, NULL); + } + + if (tcpHeader == NULL) + goto permit; + + if (tcpFlags & TCP_FLAG_RST) + goto block; + } +#endif + + /* Defer TCP Pure (zero length) ACK-packets */ + if (defer_flow && NET_BUFFER_DATA_LENGTH(netBuf) == headerOffset) { + const NTSTATUS status = fort_defer_packet_add(&fort_device()->defer, inFixedValues, + inMetaValues, netBufList, inbound, flow->opt.group_index); + + if (NT_SUCCESS(status)) + goto drop; + + if (status == STATUS_CANT_TERMINATE_SELF) { + /* Clear ACK deferring */ + fort_flow_flags_set(flow, defer_flag, FALSE); + } + + goto permit; + } + + /* Fragment first TCP packet */ + if (fragment_packet) { + fort_defer_stream_flush( + &fort_device()->defer, fort_packet_inject_complete, flow->flow_id, FALSE); + + fort_flow_flags_set(flow, FORT_FLOW_FRAGMENTED, TRUE); + } + } + +permit: + fort_callout_classify_permit(filter, classifyOut); + return; + +drop: + fort_callout_classify_drop(classifyOut); + return; +} + +static void NTAPI fort_callout_in_transport_classify_v4(const FWPS_INCOMING_VALUES0 *inFixedValues, + const FWPS_INCOMING_METADATA_VALUES0 *inMetaValues, const PNET_BUFFER_LIST netBufList, + const FWPS_FILTER0 *filter, UINT64 flowContext, FWPS_CLASSIFY_OUT0 *classifyOut) +{ + fort_callout_transport_classify_v4( + inFixedValues, inMetaValues, netBufList, filter, flowContext, classifyOut, TRUE); +} + +static void NTAPI fort_callout_out_transport_classify_v4(const FWPS_INCOMING_VALUES0 *inFixedValues, + const FWPS_INCOMING_METADATA_VALUES0 *inMetaValues, const PNET_BUFFER_LIST netBufList, + const FWPS_FILTER0 *filter, UINT64 flowContext, FWPS_CLASSIFY_OUT0 *classifyOut) +{ + fort_callout_transport_classify_v4( + inFixedValues, inMetaValues, netBufList, filter, flowContext, classifyOut, FALSE); +} + +static void NTAPI fort_callout_delete_v4(UINT16 layerId, UINT32 calloutId, UINT64 flowContext) +{ + UNUSED(layerId); + UNUSED(calloutId); + UNUSED(flowContext); +} + +FORT_API NTSTATUS fort_callout_install(PDEVICE_OBJECT device) +{ + FWPS_CALLOUT0 c; + NTSTATUS status; + + RtlZeroMemory(&c, sizeof(FWPS_CALLOUT0)); + + c.notifyFn = (FWPS_CALLOUT_NOTIFY_FN0) fort_callout_notify; + + /* IPv4 connect callout */ + c.calloutKey = FORT_GUID_CALLOUT_CONNECT_V4; + c.classifyFn = (FWPS_CALLOUT_CLASSIFY_FN0) fort_callout_connect_v4; + + status = FwpsCalloutRegister0(device, &c, &fort_device()->connect4_id); + if (!NT_SUCCESS(status)) { + DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_ERROR_LEVEL, + "FORT: Register Connect V4: Error: %x\n", status); + return status; + } + + /* IPv4 accept callout */ + c.calloutKey = FORT_GUID_CALLOUT_ACCEPT_V4; + c.classifyFn = (FWPS_CALLOUT_CLASSIFY_FN0) fort_callout_accept_v4; + + status = FwpsCalloutRegister0(device, &c, &fort_device()->accept4_id); + if (!NT_SUCCESS(status)) { + DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_ERROR_LEVEL, + "FORT: Register Accept V4: Error: %x\n", status); + return status; + } + + /* IPv4 stream callout */ + c.calloutKey = FORT_GUID_CALLOUT_STREAM_V4; + c.classifyFn = (FWPS_CALLOUT_CLASSIFY_FN0) fort_callout_stream_classify_v4; + + c.flowDeleteFn = fort_callout_flow_delete_v4; + c.flags = FWP_CALLOUT_FLAG_CONDITIONAL_ON_FLOW; + + status = FwpsCalloutRegister0(device, &c, &fort_device()->stat.stream4_id); + if (!NT_SUCCESS(status)) { + DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_ERROR_LEVEL, + "FORT: Register Stream V4: Error: %x\n", status); + return status; + } + + /* IPv4 datagram callout */ + c.calloutKey = FORT_GUID_CALLOUT_DATAGRAM_V4; + c.classifyFn = (FWPS_CALLOUT_CLASSIFY_FN0) fort_callout_datagram_classify_v4; + + /* reuse c.flowDeleteFn & c.flags */ + + status = FwpsCalloutRegister0(device, &c, &fort_device()->stat.datagram4_id); + if (!NT_SUCCESS(status)) { + DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_ERROR_LEVEL, + "FORT: Register Datagram V4: Error: %x\n", status); + return status; + } + + /* IPv4 inbound transport callout */ + c.calloutKey = FORT_GUID_CALLOUT_IN_TRANSPORT_V4; + c.classifyFn = (FWPS_CALLOUT_CLASSIFY_FN0) fort_callout_in_transport_classify_v4; + + c.flowDeleteFn = fort_callout_delete_v4; + /* reuse c.flags */ + + status = FwpsCalloutRegister0(device, &c, &fort_device()->stat.in_transport4_id); + if (!NT_SUCCESS(status)) { + DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_ERROR_LEVEL, + "FORT: Register Inbound Transport V4: Error: %x\n", status); + return status; + } + + /* IPv4 outbound transport callout */ + c.calloutKey = FORT_GUID_CALLOUT_OUT_TRANSPORT_V4; + c.classifyFn = (FWPS_CALLOUT_CLASSIFY_FN0) fort_callout_out_transport_classify_v4; + + /* reuse c.flowDeleteFn & c.flags */ + + status = FwpsCalloutRegister0(device, &c, &fort_device()->stat.out_transport4_id); + if (!NT_SUCCESS(status)) { + DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_ERROR_LEVEL, + "FORT: Register Outbound Transport V4: Error: %x\n", status); + return status; + } + + return STATUS_SUCCESS; +} + +FORT_API void fort_callout_remove(void) +{ + if (fort_device()->connect4_id) { + FwpsCalloutUnregisterById0(fort_device()->connect4_id); + fort_device()->connect4_id = 0; + } + + if (fort_device()->accept4_id) { + FwpsCalloutUnregisterById0(fort_device()->accept4_id); + fort_device()->accept4_id = 0; + } + + if (fort_device()->stat.stream4_id) { + FwpsCalloutUnregisterById0(fort_device()->stat.stream4_id); + fort_device()->stat.stream4_id = 0; + } + + if (fort_device()->stat.datagram4_id) { + FwpsCalloutUnregisterById0(fort_device()->stat.datagram4_id); + fort_device()->stat.datagram4_id = 0; + } + + if (fort_device()->stat.in_transport4_id) { + FwpsCalloutUnregisterById0(fort_device()->stat.in_transport4_id); + fort_device()->stat.in_transport4_id = 0; + } + + if (fort_device()->stat.out_transport4_id) { + FwpsCalloutUnregisterById0(fort_device()->stat.out_transport4_id); + fort_device()->stat.out_transport4_id = 0; + } +} + +FORT_API NTSTATUS fort_callout_force_reauth( + const FORT_CONF_FLAGS old_conf_flags, UINT32 defer_flush_bits) +{ + PFORT_STAT stat = &fort_device()->stat; + NTSTATUS status; + + fort_timer_update(&fort_device()->log_timer, FALSE); + + /* Check app group periods & update group_bits */ + { + int periods_n = 0; + + fort_conf_ref_period_update(&fort_device()->conf, TRUE, &periods_n); + + fort_timer_update(&fort_device()->app_timer, (periods_n != 0)); + } + + const FORT_CONF_FLAGS conf_flags = fort_device()->conf.conf_flags; + + /* Handle log_stat */ + if (old_conf_flags.log_stat != conf_flags.log_stat) { + fort_stat_update(stat, conf_flags.log_stat); + + if (!conf_flags.log_stat) { + defer_flush_bits = FORT_DEFER_FLUSH_ALL; + } + } + + if (defer_flush_bits != 0) { + fort_callout_defer_packet_flush(defer_flush_bits, FALSE); + } + + /* Open provider */ + HANDLE engine; + if ((status = fort_prov_open(&engine))) + goto end; + + fort_prov_trans_begin(engine); + + /* Check provider filters */ + BOOL prov_recreated = FALSE; + if (old_conf_flags.prov_boot != conf_flags.prov_boot) { + fort_prov_unregister(engine); + + if ((status = fort_prov_register(engine, conf_flags.prov_boot))) + goto cleanup; + + prov_recreated = TRUE; + } + + /* Check flow filter */ + { + const PFORT_CONF_GROUP conf_group = &stat->conf_group; + const UINT16 filter_bits = (conf_group->fragment_bits | conf_group->limit_bits); + + const BOOL old_filter_transport = + fort_device_flag(&fort_device()->conf, FORT_DEVICE_FILTER_TRANSPORT) != 0; + const BOOL filter_transport = (conf_flags.group_bits & filter_bits) != 0; + + if (prov_recreated || old_conf_flags.log_stat != conf_flags.log_stat + || old_filter_transport != filter_transport) { + fort_device_flag_set( + &fort_device()->conf, FORT_DEVICE_FILTER_TRANSPORT, filter_transport); + + fort_prov_flow_unregister(engine); + + if (conf_flags.log_stat) { + if ((status = fort_prov_flow_register(engine, filter_transport))) + goto cleanup; + } + } + } + + /* Force reauth filter */ + if ((status = fort_prov_reauth(engine))) + goto cleanup; + + fort_timer_update(&fort_device()->log_timer, + (conf_flags.allow_all_new || conf_flags.log_blocked || conf_flags.log_stat + || conf_flags.log_blocked_ip)); + +cleanup: + if (NT_SUCCESS(status)) { + status = fort_prov_trans_commit(engine); + } else { + fort_prov_trans_abort(engine); + } + + fort_prov_close(engine); + +end: + if (!NT_SUCCESS(status)) { + DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_ERROR_LEVEL, "FORT: Callout Reauth: Error: %x\n", + status); + } + + return status; +} + +FORT_API void fort_callout_timer(void) +{ + PFORT_BUFFER buf = &fort_device()->buffer; + PFORT_STAT stat = &fort_device()->stat; + + KLOCK_QUEUE_HANDLE buf_lock_queue; + KLOCK_QUEUE_HANDLE stat_lock_queue; + + PIRP irp = NULL; + ULONG_PTR info; + + /* Lock buffer */ + fort_buffer_dpc_begin(buf, &buf_lock_queue); + + /* Lock stat */ + fort_stat_dpc_begin(stat, &stat_lock_queue); + + /* Get current Unix time */ + { + LARGE_INTEGER system_time; + PCHAR out; + + KeQuerySystemTime(&system_time); + + if (stat->system_time.QuadPart != system_time.QuadPart + && NT_SUCCESS(fort_buffer_prepare(buf, FORT_LOG_TIME_SIZE, &out, &irp, &info))) { + const INT64 unix_time = fort_system_to_unix_time(system_time.QuadPart); + + stat->system_time = system_time; + + fort_log_time_write(out, unix_time); + } + } + + /* Flush traffic statistics */ + while (stat->proc_active_count != 0) { + const UINT16 proc_count = (stat->proc_active_count < FORT_LOG_STAT_BUFFER_PROC_COUNT) + ? stat->proc_active_count + : FORT_LOG_STAT_BUFFER_PROC_COUNT; + const UINT32 len = FORT_LOG_STAT_SIZE(proc_count); + PCHAR out; + NTSTATUS status; + + status = fort_buffer_prepare(buf, len, &out, &irp, &info); + if (!NT_SUCCESS(status)) { + DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_ERROR_LEVEL, "FORT: Callout Timer: Error: %x\n", + status); + break; + } + + fort_log_stat_traf_header_write(out, proc_count); + out += FORT_LOG_STAT_HEADER_SIZE; + + fort_stat_dpc_traf_flush(stat, proc_count, out); + } + + /* Flush process group statistics */ + const UINT32 defer_flush_bits = fort_stat_dpc_group_flush(stat); + + /* Unlock stat */ + fort_stat_dpc_end(&stat_lock_queue); + + /* Flush pending buffer */ + if (irp == NULL) { + fort_buffer_dpc_flush_pending(buf, &irp, &info); + } + + /* Unlock buffer */ + fort_buffer_dpc_end(&buf_lock_queue); + + if (irp != NULL) { + fort_request_complete_info(irp, STATUS_SUCCESS, info); + } + + /* Flush deferred packets */ + fort_callout_defer_packet_flush(defer_flush_bits, TRUE); +} diff --git a/src/driver/fortcout.h b/src/driver/fortcout.h new file mode 100644 index 00000000..33ce3c04 --- /dev/null +++ b/src/driver/fortcout.h @@ -0,0 +1,27 @@ +#ifndef FORTCOUT_H +#define FORTCOUT_H + +#include "fortdrv.h" + +#include "common/fortconf.h" + +#if defined(__cplusplus) +extern "C" { +#endif + +FORT_API void fort_callout_defer_flush(void); + +FORT_API NTSTATUS fort_callout_install(PDEVICE_OBJECT device); + +FORT_API void fort_callout_remove(void); + +FORT_API NTSTATUS fort_callout_force_reauth( + const FORT_CONF_FLAGS old_conf_flags, UINT32 defer_flush_bits); + +FORT_API void fort_callout_timer(void); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // FORTCOUT_H diff --git a/src/driver/fortdev.c b/src/driver/fortdev.c new file mode 100644 index 00000000..a5069b63 --- /dev/null +++ b/src/driver/fortdev.c @@ -0,0 +1,276 @@ +/* Fort Firewall Driver Device */ + +#include "../version/fort_version.h" + +#include "fortdev.h" + +#include "common/fortdef.h" + +#include "fortcout.h" + +static PFORT_DEVICE g_device = NULL; + +FORT_API PFORT_DEVICE fort_device() +{ + return g_device; +} + +FORT_API void fort_device_set(PFORT_DEVICE device) +{ + g_device = device; +} + +static void fort_worker_reauth(void) +{ + const FORT_CONF_FLAGS conf_flags = g_device->conf.conf_flags; + NTSTATUS status; + + status = fort_callout_force_reauth(conf_flags, 0); + + if (!NT_SUCCESS(status)) { + DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_ERROR_LEVEL, "FORT: Worker Reauth: Error: %x\n", + status); + } +} + +FORT_API void fort_app_period_timer(void) +{ + if (fort_conf_ref_period_update(&g_device->conf, FALSE, NULL)) { + fort_worker_queue(&g_device->worker, FORT_WORKER_REAUTH, &fort_worker_reauth); + } +} + +FORT_API NTSTATUS fort_device_create(PDEVICE_OBJECT device, PIRP irp) +{ + NTSTATUS status = STATUS_SUCCESS; + + UNUSED(device); + + /* Device opened */ + if (fort_device_flag_set(&g_device->conf, FORT_DEVICE_IS_OPENED, TRUE) + & FORT_DEVICE_IS_OPENED) { + status = STATUS_SHARING_VIOLATION; /* Only one client may connect */ + } + + if (NT_SUCCESS(status)) { + /* Clear buffer */ + fort_buffer_clear(&g_device->buffer); + } + + fort_request_complete(irp, status); + + return status; +} + +FORT_API NTSTATUS fort_device_close(PDEVICE_OBJECT device, PIRP irp) +{ + UNUSED(device); + + fort_request_complete(irp, STATUS_SUCCESS); + + return STATUS_SUCCESS; +} + +FORT_API NTSTATUS fort_device_cleanup(PDEVICE_OBJECT device, PIRP irp) +{ + UNUSED(device); + + /* Device closed */ + fort_device_flag_set( + &g_device->conf, (FORT_DEVICE_IS_OPENED | FORT_DEVICE_IS_VALIDATED), FALSE); + + /* Clear conf */ + { + const FORT_CONF_FLAGS old_conf_flags = fort_conf_ref_set(&g_device->conf, NULL); + + fort_conf_zones_set(&g_device->conf, NULL); + + fort_callout_force_reauth(old_conf_flags, FORT_DEFER_FLUSH_ALL); + } + + /* Clear buffer */ + fort_buffer_clear(&g_device->buffer); + + fort_request_complete(irp, STATUS_SUCCESS); + + return STATUS_SUCCESS; +} + +static void fort_device_cancel_pending(PDEVICE_OBJECT device, PIRP irp) +{ + ULONG_PTR info; + NTSTATUS status; + + UNUSED(device); + + status = fort_buffer_cancel_pending(&g_device->buffer, irp, &info); + + IoReleaseCancelSpinLock(irp->CancelIrql); /* before IoCompleteRequest()! */ + + fort_request_complete_info(irp, status, info); +} + +FORT_API NTSTATUS fort_device_control(PDEVICE_OBJECT device, PIRP irp) +{ + ULONG_PTR info = 0; + NTSTATUS status = STATUS_UNSUCCESSFUL; + + UNUSED(device); + + const PIO_STACK_LOCATION irp_stack = IoGetCurrentIrpStackLocation(irp); + const ULONG control_code = irp_stack->Parameters.DeviceIoControl.IoControlCode; + + if (control_code != (ULONG) FORT_IOCTL_VALIDATE + && !fort_device_flag(&g_device->conf, FORT_DEVICE_IS_VALIDATED)) + goto end; + + switch (control_code) { + case FORT_IOCTL_VALIDATE: { + const PFORT_CONF_VERSION conf_ver = irp->AssociatedIrp.SystemBuffer; + const ULONG len = irp_stack->Parameters.DeviceIoControl.InputBufferLength; + + if (len == sizeof(FORT_CONF_VERSION)) { + if (conf_ver->driver_version == DRIVER_VERSION) { + fort_device_flag_set(&g_device->conf, FORT_DEVICE_IS_VALIDATED, TRUE); + status = STATUS_SUCCESS; + } + } + break; + } + case FORT_IOCTL_SETCONF: { + const PFORT_CONF_IO conf_io = irp->AssociatedIrp.SystemBuffer; + const ULONG len = irp_stack->Parameters.DeviceIoControl.InputBufferLength; + + if (len > sizeof(FORT_CONF_IO)) { + const PFORT_CONF conf = &conf_io->conf; + PFORT_CONF_REF conf_ref = fort_conf_ref_new(conf, len - FORT_CONF_IO_CONF_OFF); + + if (conf_ref == NULL) { + status = STATUS_INSUFFICIENT_RESOURCES; + } else { + PFORT_STAT stat = &g_device->stat; + + const FORT_CONF_FLAGS old_conf_flags = fort_conf_ref_set(&g_device->conf, conf_ref); + + const UINT32 defer_flush_bits = + (stat->conf_group.limit_2bits ^ conf_io->conf_group.limit_2bits); + + fort_stat_conf_update(stat, conf_io); + + status = fort_callout_force_reauth(old_conf_flags, defer_flush_bits); + } + } + break; + } + case FORT_IOCTL_SETFLAGS: { + const PFORT_CONF_FLAGS conf_flags = irp->AssociatedIrp.SystemBuffer; + const ULONG len = irp_stack->Parameters.DeviceIoControl.InputBufferLength; + + if (len == sizeof(FORT_CONF_FLAGS)) { + const FORT_CONF_FLAGS old_conf_flags = + fort_conf_ref_flags_set(&g_device->conf, conf_flags); + + const UINT32 defer_flush_bits = + (old_conf_flags.group_bits != conf_flags->group_bits ? FORT_DEFER_FLUSH_ALL + : 0); + + status = fort_callout_force_reauth(old_conf_flags, defer_flush_bits); + } + break; + } + case FORT_IOCTL_GETLOG: { + PVOID out = irp->AssociatedIrp.SystemBuffer; + const ULONG out_len = irp_stack->Parameters.DeviceIoControl.OutputBufferLength; + + if (out_len < FORT_BUFFER_SIZE) { + status = STATUS_BUFFER_TOO_SMALL; + } else { + status = fort_buffer_xmove(&g_device->buffer, irp, out, out_len, &info); + + if (status == STATUS_PENDING) { + KIRQL cirq; + + IoMarkIrpPending(irp); + + IoAcquireCancelSpinLock(&cirq); + IoSetCancelRoutine(irp, fort_device_cancel_pending); + IoReleaseCancelSpinLock(cirq); + + return STATUS_PENDING; + } + } + break; + } + case FORT_IOCTL_ADDAPP: + case FORT_IOCTL_DELAPP: { + const PFORT_APP_ENTRY app_entry = irp->AssociatedIrp.SystemBuffer; + const ULONG len = irp_stack->Parameters.DeviceIoControl.InputBufferLength; + + if (len > sizeof(FORT_APP_ENTRY) && len >= (sizeof(FORT_APP_ENTRY) + app_entry->path_len)) { + PFORT_CONF_REF conf_ref = fort_conf_ref_take(&g_device->conf); + + if (conf_ref == NULL) { + status = STATUS_INSUFFICIENT_RESOURCES; + } else { + if (control_code == (ULONG) FORT_IOCTL_ADDAPP) { + status = fort_conf_ref_exe_add_entry(conf_ref, app_entry, FALSE); + } else { + fort_conf_ref_exe_del_entry(conf_ref, app_entry); + status = STATUS_SUCCESS; + } + + fort_conf_ref_put(&g_device->conf, conf_ref); + + if (NT_SUCCESS(status)) { + fort_worker_reauth(); + } + } + } + break; + } + case FORT_IOCTL_SETZONES: { + const PFORT_CONF_ZONES zones = irp->AssociatedIrp.SystemBuffer; + const ULONG len = irp_stack->Parameters.DeviceIoControl.InputBufferLength; + + if (len >= FORT_CONF_ZONES_DATA_OFF) { + PFORT_CONF_ZONES conf_zones = fort_conf_zones_new(zones, len); + + if (conf_zones == NULL) { + status = STATUS_INSUFFICIENT_RESOURCES; + } else { + fort_conf_zones_set(&g_device->conf, conf_zones); + + fort_worker_reauth(); + + status = STATUS_SUCCESS; + } + } + break; + } + case FORT_IOCTL_SETZONEFLAG: { + const PFORT_CONF_ZONE_FLAG zone_flag = irp->AssociatedIrp.SystemBuffer; + const ULONG len = irp_stack->Parameters.DeviceIoControl.InputBufferLength; + + if (len == sizeof(FORT_CONF_ZONE_FLAG)) { + fort_conf_zone_flag_set(&g_device->conf, zone_flag); + + fort_worker_reauth(); + + status = STATUS_SUCCESS; + } + break; + } + default: + break; + } + +end: + if (!NT_SUCCESS(status) && status != FORT_STATUS_USER_ERROR) { + DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_ERROR_LEVEL, "FORT: Device Control: Error: %x\n", + status); + } + + fort_request_complete_info(irp, status, info); + + return status; +} diff --git a/src/driver/fortdev.h b/src/driver/fortdev.h new file mode 100644 index 00000000..483d5725 --- /dev/null +++ b/src/driver/fortdev.h @@ -0,0 +1,55 @@ +#ifndef FORTDEV_H +#define FORTDEV_H + +#include "fortdrv.h" + +#include "fortbuf.h" +#include "fortcnf.h" +#include "fortpkt.h" +#include "fortstat.h" +#include "forttmr.h" +#include "fortwrk.h" + +typedef struct fort_device +{ + UINT32 connect4_id; + UINT32 accept4_id; + + PCALLBACK_OBJECT power_cb_obj; + PVOID power_cb_reg; + + PCALLBACK_OBJECT systime_cb_obj; + PVOID systime_cb_reg; + + FORT_DEVICE_CONF conf; + FORT_BUFFER buffer; + FORT_STAT stat; + FORT_DEFER defer; + FORT_TIMER log_timer; + FORT_TIMER app_timer; + FORT_WORKER worker; +} FORT_DEVICE, *PFORT_DEVICE; + +#if defined(__cplusplus) +extern "C" { +#endif + +FORT_API PFORT_DEVICE fort_device(); + +FORT_API void fort_device_set(PFORT_DEVICE device); + +FORT_API void fort_app_period_timer(void); + +FORT_API NTSTATUS fort_device_create(PDEVICE_OBJECT device, PIRP irp); + +FORT_API NTSTATUS fort_device_close(PDEVICE_OBJECT device, PIRP irp); + +FORT_API NTSTATUS fort_device_cleanup(PDEVICE_OBJECT device, PIRP irp); + +FORT_API NTSTATUS fort_device_control(PDEVICE_OBJECT device, PIRP irp); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // FORTDEV_H diff --git a/src/driver/fortdrv.c b/src/driver/fortdrv.c index 42a94385..1a1aef39 100644 --- a/src/driver/fortdrv.c +++ b/src/driver/fortdrv.c @@ -1,1071 +1,12 @@ /* Fort Firewall Driver */ -#include "../version/fort_version.h" - #include "fortdrv.h" -#include "common/fortconf.h" -#include "common/fortdev.h" +#include "common/fortdef.h" #include "common/fortprov.h" -#include "fortbuf.h" -#include "fortcnf.h" -#include "fortpkt.h" -#include "fortstat.h" -#include "forttmr.h" -#include "fortwrk.h" - -#define NT_DEVICE_NAME L"\\Device\\fortfw" -#define DOS_DEVICE_NAME L"\\DosDevices\\fortfw" - -#define FORT_DEVICE_POOL_TAG 'DwfF' - -#define fort_request_complete_info(irp, status, info) \ - do { \ - (irp)->IoStatus.Status = (status); \ - (irp)->IoStatus.Information = (info); \ - IoCompleteRequest((irp), IO_NO_INCREMENT); \ - } while (0) - -#define fort_request_complete(irp, status) fort_request_complete_info((irp), (status), 0) - -typedef struct fort_device -{ - UINT32 connect4_id; - UINT32 accept4_id; - - PCALLBACK_OBJECT power_cb_obj; - PVOID power_cb_reg; - - PCALLBACK_OBJECT systime_cb_obj; - PVOID systime_cb_reg; - - FORT_DEVICE_CONF conf; - FORT_BUFFER buffer; - FORT_STAT stat; - FORT_DEFER defer; - FORT_TIMER log_timer; - FORT_TIMER app_timer; - FORT_WORKER worker; -} FORT_DEVICE, *PFORT_DEVICE; - -static PFORT_DEVICE g_device = NULL; - -static void fort_callout_classify_block(FWPS_CLASSIFY_OUT0 *classifyOut) -{ - classifyOut->actionType = FWP_ACTION_BLOCK; - classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE; -} - -static void fort_callout_classify_drop(FWPS_CLASSIFY_OUT0 *classifyOut) -{ - classifyOut->flags |= FWPS_CLASSIFY_OUT_FLAG_ABSORB; - - fort_callout_classify_block(classifyOut); -} - -static void fort_callout_classify_permit( - const FWPS_FILTER0 *filter, FWPS_CLASSIFY_OUT0 *classifyOut) -{ - classifyOut->actionType = FWP_ACTION_PERMIT; - if ((filter->flags & FWPS_FILTER_FLAG_CLEAR_ACTION_RIGHT)) { - classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE; - } -} - -static void fort_callout_classify_continue(FWPS_CLASSIFY_OUT0 *classifyOut) -{ - classifyOut->actionType = FWP_ACTION_CONTINUE; -} - -static void fort_callout_classify_v4(const FWPS_INCOMING_VALUES0 *inFixedValues, - const FWPS_INCOMING_METADATA_VALUES0 *inMetaValues, const FWPS_FILTER0 *filter, - FWPS_CLASSIFY_OUT0 *classifyOut, int flagsField, int localIpField, int remoteIpField, - int localPortField, int remotePortField, int ipProtoField, BOOL inbound) -{ - PIRP irp = NULL; - ULONG_PTR info; - - const UINT32 flags = inFixedValues->incomingValue[flagsField].value.uint32; - const UINT32 remote_ip = inFixedValues->incomingValue[remoteIpField].value.uint32; - - if (!g_device->conf.conf_flags.filter_locals - && ((flags & FWP_CONDITION_FLAG_IS_LOOPBACK) - || remote_ip == 0xFFFFFFFF)) { /* Local broadcast */ - fort_callout_classify_permit(filter, classifyOut); - return; - } - - PFORT_CONF_REF conf_ref = fort_conf_ref_take(&g_device->conf); - - if (conf_ref == NULL) { - if (fort_device_flag(&g_device->conf, FORT_DEVICE_PROV_BOOT)) { - fort_callout_classify_block(classifyOut); - } else { - fort_callout_classify_continue(classifyOut); - } - return; - } - - const FORT_CONF_FLAGS conf_flags = conf_ref->conf.flags; - - const UINT32 process_id = (UINT32) inMetaValues->processId; - const UINT32 path_len = - inMetaValues->processPath->size - sizeof(WCHAR); /* chop terminating zero */ - const PVOID path = inMetaValues->processPath->data; - - UCHAR block_reason = FORT_BLOCK_REASON_UNKNOWN; - BOOL blocked = TRUE; - - if (conf_flags.filter_enabled) { - if (conf_flags.stop_traffic) - goto end; - - if (!fort_conf_ip_is_inet(&conf_ref->conf, - (fort_conf_zones_ip_included_func *) fort_conf_zones_ip_included, - &g_device->conf, remote_ip)) { - blocked = FALSE; /* permit (LAN) */ - goto end; - } - - if (conf_flags.stop_inet_traffic) - goto end; - - if (!fort_conf_ip_inet_included(&conf_ref->conf, - (fort_conf_zones_ip_included_func *) fort_conf_zones_ip_included, - &g_device->conf, remote_ip)) { - block_reason = FORT_BLOCK_REASON_IP_INET; - goto end; - } - } else { - blocked = FALSE; /* permit (Filter Disabled) */ - if (!(conf_flags.log_stat && conf_flags.log_stat_no_filter)) - goto end; - } - - FORT_APP_FLAGS app_flags = - fort_conf_app_find(&conf_ref->conf, path, path_len, fort_conf_exe_find); - - if (!blocked /* collect traffic, when Filter Disabled */ - || (app_flags.v == 0 && conf_flags.allow_all_new) /* collect new Blocked Programs */ - || !fort_conf_app_blocked(&conf_ref->conf, app_flags, &block_reason)) { - if (conf_flags.log_stat) { - const UINT64 flow_id = inMetaValues->flowHandle; - - const IPPROTO ip_proto = - (IPPROTO) inFixedValues->incomingValue[ipProtoField].value.uint8; - const BOOL is_tcp = (ip_proto == IPPROTO_TCP); - - const UCHAR group_index = app_flags.group_index; - const BOOL is_reauth = (flags & FWP_CONDITION_FLAG_IS_REAUTHORIZE); - - BOOL is_new_proc = FALSE; - NTSTATUS status; - - status = fort_flow_associate(&g_device->stat, flow_id, process_id, group_index, is_tcp, - is_reauth, &is_new_proc); - - if (!NT_SUCCESS(status)) { - if (status == FORT_STATUS_FLOW_BLOCK) { - block_reason = FORT_BLOCK_REASON_REAUTH; - blocked = TRUE; - goto end; - } - - DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_ERROR_LEVEL, - "FORT: Classify v4: Flow assoc. error: %x\n", status); - } else if (is_new_proc) { - fort_buffer_proc_new_write( - &g_device->buffer, process_id, path_len, path, &irp, &info); - } - } - - blocked = FALSE; /* permit */ - } - - if (app_flags.v == 0 && (conf_flags.allow_all_new || conf_flags.log_blocked) - && conf_flags.filter_enabled) { - app_flags.blocked = (UCHAR) blocked; - app_flags.alerted = 1; - app_flags.is_new = 1; - - if (NT_SUCCESS(fort_conf_ref_exe_add_path(conf_ref, path, path_len, app_flags))) { - fort_buffer_blocked_write( - &g_device->buffer, blocked, process_id, path_len, path, &irp, &info); - } - } - -end: - if (blocked) { - /* Log the blocked connection */ - if (block_reason != FORT_BLOCK_REASON_UNKNOWN && conf_flags.log_blocked_ip) { - const UINT32 local_ip = inFixedValues->incomingValue[localIpField].value.uint32; - const UINT16 local_port = inFixedValues->incomingValue[localPortField].value.uint16; - const UINT16 remote_port = inFixedValues->incomingValue[remotePortField].value.uint16; - const IPPROTO ip_proto = - (IPPROTO) inFixedValues->incomingValue[ipProtoField].value.uint8; - - fort_buffer_blocked_ip_write(&g_device->buffer, inbound, block_reason, ip_proto, - local_port, remote_port, local_ip, remote_ip, process_id, path_len, path, &irp, - &info); - } - - /* Block the connection */ - fort_callout_classify_block(classifyOut); - } else { - /* Allow the connection */ - fort_callout_classify_permit(filter, classifyOut); - } - - fort_conf_ref_put(&g_device->conf, conf_ref); - - if (irp != NULL) { - fort_request_complete_info(irp, STATUS_SUCCESS, info); - } -} - -static void NTAPI fort_callout_connect_v4(const FWPS_INCOMING_VALUES0 *inFixedValues, - const FWPS_INCOMING_METADATA_VALUES0 *inMetaValues, void *layerData, - const FWPS_FILTER0 *filter, const UINT64 flowContext, FWPS_CLASSIFY_OUT0 *classifyOut) -{ - UNUSED(layerData); - UNUSED(flowContext); - - fort_callout_classify_v4(inFixedValues, inMetaValues, filter, classifyOut, - FWPS_FIELD_ALE_AUTH_CONNECT_V4_FLAGS, FWPS_FIELD_ALE_AUTH_CONNECT_V4_IP_LOCAL_ADDRESS, - FWPS_FIELD_ALE_AUTH_CONNECT_V4_IP_REMOTE_ADDRESS, - FWPS_FIELD_ALE_AUTH_CONNECT_V4_IP_LOCAL_PORT, - FWPS_FIELD_ALE_AUTH_CONNECT_V4_IP_REMOTE_PORT, - FWPS_FIELD_ALE_AUTH_CONNECT_V4_IP_PROTOCOL, FALSE); -} - -static void NTAPI fort_callout_accept_v4(const FWPS_INCOMING_VALUES0 *inFixedValues, - const FWPS_INCOMING_METADATA_VALUES0 *inMetaValues, void *layerData, - const FWPS_FILTER0 *filter, const UINT64 flowContext, FWPS_CLASSIFY_OUT0 *classifyOut) -{ - UNUSED(layerData); - UNUSED(flowContext); - - fort_callout_classify_v4(inFixedValues, inMetaValues, filter, classifyOut, - FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V4_FLAGS, - FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V4_IP_LOCAL_ADDRESS, - FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V4_IP_REMOTE_ADDRESS, - FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V4_IP_LOCAL_PORT, - FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V4_IP_REMOTE_PORT, - FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V4_IP_PROTOCOL, TRUE); -} - -static NTSTATUS NTAPI fort_callout_notify( - FWPS_CALLOUT_NOTIFY_TYPE notifyType, const GUID *filterKey, const FWPS_FILTER0 *filter) -{ - UNUSED(notifyType); - UNUSED(filterKey); - UNUSED(filter); - - return STATUS_SUCCESS; -} - -static void NTAPI fort_packet_inject_complete( - PFORT_PACKET pkt, PNET_BUFFER_LIST clonedNetBufList, BOOLEAN dispatchLevel) -{ - fort_defer_packet_free(&g_device->defer, pkt, clonedNetBufList, dispatchLevel); -} - -static void fort_callout_defer_packet_flush(UINT32 list_bits, BOOL dispatchLevel) -{ - fort_defer_packet_flush( - &g_device->defer, fort_packet_inject_complete, list_bits, dispatchLevel); -} - -static void fort_callout_defer_stream_flush(UINT64 flow_id, BOOL dispatchLevel) -{ - UNUSED(dispatchLevel); - - fort_defer_stream_flush(&g_device->defer, fort_packet_inject_complete, flow_id, FALSE); -} - -static void fort_callout_defer_flush(void) -{ - fort_callout_defer_packet_flush(FORT_DEFER_FLUSH_ALL, FALSE); - fort_callout_defer_stream_flush(FORT_DEFER_STREAM_ALL, FALSE); -} - -static void fort_callout_flow_classify_v4(const FWPS_INCOMING_METADATA_VALUES0 *inMetaValues, - UINT64 flowContext, FWPS_CLASSIFY_OUT0 *classifyOut, UINT32 dataSize, BOOL is_tcp, - BOOL inbound) -{ - const UINT32 headerSize = inbound ? inMetaValues->transportHeaderSize : 0; - - UNUSED(classifyOut); - - fort_flow_classify(&g_device->stat, flowContext, headerSize + dataSize, is_tcp, inbound); -} - -static void NTAPI fort_callout_stream_classify_v4(const FWPS_INCOMING_VALUES0 *inFixedValues, - const FWPS_INCOMING_METADATA_VALUES0 *inMetaValues, FWPS_STREAM_CALLOUT_IO_PACKET0 *packet, - const FWPS_FILTER0 *filter, UINT64 flowContext, FWPS_CLASSIFY_OUT0 *classifyOut) -{ - const FWPS_STREAM_DATA0 *streamData = packet->streamData; - const UINT32 streamFlags = streamData->flags; - const UINT32 dataSize = (UINT32) streamData->dataLength; - - const BOOL inbound = (streamFlags & FWPS_STREAM_FLAG_RECEIVE) != 0; - - UNUSED(inFixedValues); - - fort_callout_flow_classify_v4(inMetaValues, flowContext, classifyOut, dataSize, TRUE, inbound); - -/* Flush flow's deferred TCP packets on FIN */ -#if 0 - if (streamFlags & (FWPS_STREAM_FLAG_RECEIVE_DISCONNECT - | FWPS_STREAM_FLAG_SEND_DISCONNECT)) { - PFORT_FLOW flow = (PFORT_FLOW) flowContext; - - const UCHAR flow_flags = fort_flow_flags(flow); - - if (flow_flags & FORT_FLOW_SPEED_LIMIT) { - fort_callout_defer_packet_flush(flow->flow_id, FORT_DEFER_FLUSH_ALL, FALSE); - } - - if (flow_flags & FORT_FLOW_FRAGMENT) { - fort_callout_defer_stream_flush(flow->flow_id, FALSE); - } - - goto permit; - } -#endif - - /* Fragment first TCP packet */ - if ((streamFlags - & (FWPS_STREAM_FLAG_SEND | FWPS_STREAM_FLAG_SEND_EXPEDITED - | FWPS_STREAM_FLAG_SEND_DISCONNECT)) - == FWPS_STREAM_FLAG_SEND) { - PFORT_FLOW flow = (PFORT_FLOW) flowContext; - - const UCHAR flow_flags = fort_flow_flags(flow); - - const UCHAR fragment_flags = (flow_flags - & (FORT_FLOW_FRAGMENT | FORT_FLOW_FRAGMENT_DEFER | FORT_FLOW_FRAGMENTED)); - - if (fragment_flags != 0 && !(fragment_flags & FORT_FLOW_FRAGMENTED)) { - const UCHAR fragment_size = 3; - - if (fragment_flags & FORT_FLOW_FRAGMENT_DEFER) { - const NTSTATUS status = fort_defer_stream_add( - &g_device->defer, inFixedValues, inMetaValues, streamData, filter, inbound); - - if (NT_SUCCESS(status)) - goto drop; - - fort_flow_flags_set(flow, FORT_FLOW_FRAGMENTED, TRUE); - } else if (dataSize > fragment_size) { - packet->countBytesEnforced = fragment_size; - - fort_flow_flags_set(flow, FORT_FLOW_FRAGMENT_DEFER, TRUE); - } - } - } - - /* permit: */ - fort_callout_classify_permit(filter, classifyOut); - return; - -drop: - fort_callout_classify_drop(classifyOut); - return; -} - -static void NTAPI fort_callout_datagram_classify_v4(const FWPS_INCOMING_VALUES0 *inFixedValues, - const FWPS_INCOMING_METADATA_VALUES0 *inMetaValues, const PNET_BUFFER_LIST netBufList, - const FWPS_FILTER0 *filter, UINT64 flowContext, FWPS_CLASSIFY_OUT0 *classifyOut) -{ - const PNET_BUFFER netBuf = NET_BUFFER_LIST_FIRST_NB(netBufList); - const UINT32 dataSize = NET_BUFFER_DATA_LENGTH(netBuf); - - const FWP_DIRECTION direction = - (FWP_DIRECTION) inFixedValues->incomingValue[FWPS_FIELD_DATAGRAM_DATA_V4_DIRECTION] - .value.uint8; - const BOOL inbound = (direction == FWP_DIRECTION_INBOUND); - - fort_callout_flow_classify_v4(inMetaValues, flowContext, classifyOut, dataSize, FALSE, inbound); - - fort_callout_classify_permit(filter, classifyOut); -} - -static void NTAPI fort_callout_flow_delete_v4(UINT16 layerId, UINT32 calloutId, UINT64 flowContext) -{ - UNUSED(layerId); - UNUSED(calloutId); - - fort_flow_delete(&g_device->stat, flowContext); -} - -static void NTAPI fort_callout_transport_classify_v4(const FWPS_INCOMING_VALUES0 *inFixedValues, - const FWPS_INCOMING_METADATA_VALUES0 *inMetaValues, PNET_BUFFER_LIST netBufList, - const FWPS_FILTER0 *filter, UINT64 flowContext, FWPS_CLASSIFY_OUT0 *classifyOut, - BOOL inbound) -{ - PNET_BUFFER netBuf; - - if (!FWPS_IS_METADATA_FIELD_PRESENT(inMetaValues, FWPS_METADATA_FIELD_ALE_CLASSIFY_REQUIRED) - && netBufList != NULL && (netBuf = NET_BUFFER_LIST_FIRST_NB(netBufList)) != NULL) { - PFORT_FLOW flow = (PFORT_FLOW) flowContext; - - const UCHAR flow_flags = fort_flow_flags(flow); - - const UCHAR defer_flag = inbound ? FORT_FLOW_DEFER_IN : FORT_FLOW_DEFER_OUT; - const UCHAR speed_limit = inbound ? FORT_FLOW_SPEED_LIMIT_OUT : FORT_FLOW_SPEED_LIMIT_IN; - - const UCHAR speed_defer_flags = speed_limit | defer_flag; - const BOOL defer_flow = (flow_flags & speed_defer_flags) == speed_defer_flags - && !fort_device_flag(&g_device->conf, FORT_DEVICE_POWER_OFF); - - const BOOL fragment_packet = !inbound - && (flow_flags & (FORT_FLOW_FRAGMENT_DEFER | FORT_FLOW_FRAGMENTED)) - == FORT_FLOW_FRAGMENT_DEFER; - - /* Position in the packet data: - * FWPS_LAYER_INBOUND_TRANSPORT_V4: The beginning of the data. - * FWPS_LAYER_OUTBOUND_TRANSPORT_V4: The beginning of the transport header. - */ - const UINT32 headerOffset = inbound ? 0 : sizeof(TCP_HEADER); - -/* Ignore TCP RST-packets */ -#if 0 - const BOOL ignore_tcp_rst = inbound && g_device->conf_flags.ignore_tcp_rst; - - if (ignore_tcp_rst) { - TCP_HEADER buf; - PTCP_HEADER tcpHeader; - UINT32 tcpFlags; - - if (headerOffset != 0) { - NdisRetreatNetBufferDataStart(netBuf, headerOffset, 0, NULL); - } - - tcpHeader = NdisGetDataBuffer(netBuf, sizeof(TCP_HEADER), &buf, 1, 0); - tcpFlags = tcpHeader ? tcpHeader->flags : 0; - - if (headerOffset != 0) { - NdisAdvanceNetBufferDataStart(netBuf, headerOffset, FALSE, NULL); - } - - if (tcpHeader == NULL) - goto permit; - - if (tcpFlags & TCP_FLAG_RST) - goto block; - } -#endif - - /* Defer TCP Pure (zero length) ACK-packets */ - if (defer_flow && NET_BUFFER_DATA_LENGTH(netBuf) == headerOffset) { - const NTSTATUS status = fort_defer_packet_add(&g_device->defer, inFixedValues, - inMetaValues, netBufList, inbound, flow->opt.group_index); - - if (NT_SUCCESS(status)) - goto drop; - - if (status == STATUS_CANT_TERMINATE_SELF) { - /* Clear ACK deferring */ - fort_flow_flags_set(flow, defer_flag, FALSE); - } - - goto permit; - } - - /* Fragment first TCP packet */ - if (fragment_packet) { - fort_defer_stream_flush( - &g_device->defer, fort_packet_inject_complete, flow->flow_id, FALSE); - - fort_flow_flags_set(flow, FORT_FLOW_FRAGMENTED, TRUE); - } - } - -permit: - fort_callout_classify_permit(filter, classifyOut); - return; - -drop: - fort_callout_classify_drop(classifyOut); - return; -} - -static void NTAPI fort_callout_in_transport_classify_v4(const FWPS_INCOMING_VALUES0 *inFixedValues, - const FWPS_INCOMING_METADATA_VALUES0 *inMetaValues, const PNET_BUFFER_LIST netBufList, - const FWPS_FILTER0 *filter, UINT64 flowContext, FWPS_CLASSIFY_OUT0 *classifyOut) -{ - fort_callout_transport_classify_v4( - inFixedValues, inMetaValues, netBufList, filter, flowContext, classifyOut, TRUE); -} - -static void NTAPI fort_callout_out_transport_classify_v4(const FWPS_INCOMING_VALUES0 *inFixedValues, - const FWPS_INCOMING_METADATA_VALUES0 *inMetaValues, const PNET_BUFFER_LIST netBufList, - const FWPS_FILTER0 *filter, UINT64 flowContext, FWPS_CLASSIFY_OUT0 *classifyOut) -{ - fort_callout_transport_classify_v4( - inFixedValues, inMetaValues, netBufList, filter, flowContext, classifyOut, FALSE); -} - -static void NTAPI fort_callout_delete_v4(UINT16 layerId, UINT32 calloutId, UINT64 flowContext) -{ - UNUSED(layerId); - UNUSED(calloutId); - UNUSED(flowContext); -} - -static NTSTATUS fort_callout_install(PDEVICE_OBJECT device) -{ - FWPS_CALLOUT0 c; - NTSTATUS status; - - RtlZeroMemory(&c, sizeof(FWPS_CALLOUT0)); - - c.notifyFn = (FWPS_CALLOUT_NOTIFY_FN0) fort_callout_notify; - - /* IPv4 connect callout */ - c.calloutKey = FORT_GUID_CALLOUT_CONNECT_V4; - c.classifyFn = (FWPS_CALLOUT_CLASSIFY_FN0) fort_callout_connect_v4; - - status = FwpsCalloutRegister0(device, &c, &g_device->connect4_id); - if (!NT_SUCCESS(status)) { - DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_ERROR_LEVEL, - "FORT: Register Connect V4: Error: %x\n", status); - return status; - } - - /* IPv4 accept callout */ - c.calloutKey = FORT_GUID_CALLOUT_ACCEPT_V4; - c.classifyFn = (FWPS_CALLOUT_CLASSIFY_FN0) fort_callout_accept_v4; - - status = FwpsCalloutRegister0(device, &c, &g_device->accept4_id); - if (!NT_SUCCESS(status)) { - DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_ERROR_LEVEL, - "FORT: Register Accept V4: Error: %x\n", status); - return status; - } - - /* IPv4 stream callout */ - c.calloutKey = FORT_GUID_CALLOUT_STREAM_V4; - c.classifyFn = (FWPS_CALLOUT_CLASSIFY_FN0) fort_callout_stream_classify_v4; - - c.flowDeleteFn = fort_callout_flow_delete_v4; - c.flags = FWP_CALLOUT_FLAG_CONDITIONAL_ON_FLOW; - - status = FwpsCalloutRegister0(device, &c, &g_device->stat.stream4_id); - if (!NT_SUCCESS(status)) { - DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_ERROR_LEVEL, - "FORT: Register Stream V4: Error: %x\n", status); - return status; - } - - /* IPv4 datagram callout */ - c.calloutKey = FORT_GUID_CALLOUT_DATAGRAM_V4; - c.classifyFn = (FWPS_CALLOUT_CLASSIFY_FN0) fort_callout_datagram_classify_v4; - - /* reuse c.flowDeleteFn & c.flags */ - - status = FwpsCalloutRegister0(device, &c, &g_device->stat.datagram4_id); - if (!NT_SUCCESS(status)) { - DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_ERROR_LEVEL, - "FORT: Register Datagram V4: Error: %x\n", status); - return status; - } - - /* IPv4 inbound transport callout */ - c.calloutKey = FORT_GUID_CALLOUT_IN_TRANSPORT_V4; - c.classifyFn = (FWPS_CALLOUT_CLASSIFY_FN0) fort_callout_in_transport_classify_v4; - - c.flowDeleteFn = fort_callout_delete_v4; - /* reuse c.flags */ - - status = FwpsCalloutRegister0(device, &c, &g_device->stat.in_transport4_id); - if (!NT_SUCCESS(status)) { - DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_ERROR_LEVEL, - "FORT: Register Inbound Transport V4: Error: %x\n", status); - return status; - } - - /* IPv4 outbound transport callout */ - c.calloutKey = FORT_GUID_CALLOUT_OUT_TRANSPORT_V4; - c.classifyFn = (FWPS_CALLOUT_CLASSIFY_FN0) fort_callout_out_transport_classify_v4; - - /* reuse c.flowDeleteFn & c.flags */ - - status = FwpsCalloutRegister0(device, &c, &g_device->stat.out_transport4_id); - if (!NT_SUCCESS(status)) { - DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_ERROR_LEVEL, - "FORT: Register Outbound Transport V4: Error: %x\n", status); - return status; - } - - return STATUS_SUCCESS; -} - -static void fort_callout_remove(void) -{ - if (g_device->connect4_id) { - FwpsCalloutUnregisterById0(g_device->connect4_id); - g_device->connect4_id = 0; - } - - if (g_device->accept4_id) { - FwpsCalloutUnregisterById0(g_device->accept4_id); - g_device->accept4_id = 0; - } - - if (g_device->stat.stream4_id) { - FwpsCalloutUnregisterById0(g_device->stat.stream4_id); - g_device->stat.stream4_id = 0; - } - - if (g_device->stat.datagram4_id) { - FwpsCalloutUnregisterById0(g_device->stat.datagram4_id); - g_device->stat.datagram4_id = 0; - } - - if (g_device->stat.in_transport4_id) { - FwpsCalloutUnregisterById0(g_device->stat.in_transport4_id); - g_device->stat.in_transport4_id = 0; - } - - if (g_device->stat.out_transport4_id) { - FwpsCalloutUnregisterById0(g_device->stat.out_transport4_id); - g_device->stat.out_transport4_id = 0; - } -} - -static NTSTATUS fort_callout_force_reauth( - const FORT_CONF_FLAGS old_conf_flags, UINT32 defer_flush_bits) -{ - PFORT_STAT stat = &g_device->stat; - NTSTATUS status; - - fort_timer_update(&g_device->log_timer, FALSE); - - /* Check app group periods & update group_bits */ - { - int periods_n = 0; - - fort_conf_ref_period_update(&g_device->conf, TRUE, &periods_n); - - fort_timer_update(&g_device->app_timer, (periods_n != 0)); - } - - const FORT_CONF_FLAGS conf_flags = g_device->conf.conf_flags; - - /* Handle log_stat */ - if (old_conf_flags.log_stat != conf_flags.log_stat) { - fort_stat_update(stat, conf_flags.log_stat); - - if (!conf_flags.log_stat) { - defer_flush_bits = FORT_DEFER_FLUSH_ALL; - } - } - - if (defer_flush_bits != 0) { - fort_callout_defer_packet_flush(defer_flush_bits, FALSE); - } - - /* Open provider */ - HANDLE engine; - if ((status = fort_prov_open(&engine))) - goto end; - - fort_prov_trans_begin(engine); - - /* Check provider filters */ - BOOL prov_recreated = FALSE; - if (old_conf_flags.prov_boot != conf_flags.prov_boot) { - fort_prov_unregister(engine); - - if ((status = fort_prov_register(engine, conf_flags.prov_boot))) - goto cleanup; - - prov_recreated = TRUE; - } - - /* Check flow filter */ - { - const PFORT_CONF_GROUP conf_group = &stat->conf_group; - const UINT16 filter_bits = (conf_group->fragment_bits | conf_group->limit_bits); - - const BOOL old_filter_transport = - fort_device_flag(&g_device->conf, FORT_DEVICE_FILTER_TRANSPORT) != 0; - const BOOL filter_transport = (conf_flags.group_bits & filter_bits) != 0; - - if (prov_recreated || old_conf_flags.log_stat != conf_flags.log_stat - || old_filter_transport != filter_transport) { - fort_device_flag_set(&g_device->conf, FORT_DEVICE_FILTER_TRANSPORT, filter_transport); - - fort_prov_flow_unregister(engine); - - if (conf_flags.log_stat) { - if ((status = fort_prov_flow_register(engine, filter_transport))) - goto cleanup; - } - } - } - - /* Force reauth filter */ - if ((status = fort_prov_reauth(engine))) - goto cleanup; - - fort_timer_update(&g_device->log_timer, - (conf_flags.allow_all_new || conf_flags.log_blocked || conf_flags.log_stat - || conf_flags.log_blocked_ip)); - -cleanup: - if (NT_SUCCESS(status)) { - status = fort_prov_trans_commit(engine); - } else { - fort_prov_trans_abort(engine); - } - - fort_prov_close(engine); - -end: - if (!NT_SUCCESS(status)) { - DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_ERROR_LEVEL, "FORT: Callout Reauth: Error: %x\n", - status); - } - - return status; -} - -static void fort_callout_timer(void) -{ - PFORT_BUFFER buf = &g_device->buffer; - PFORT_STAT stat = &g_device->stat; - - KLOCK_QUEUE_HANDLE buf_lock_queue; - KLOCK_QUEUE_HANDLE stat_lock_queue; - - PIRP irp = NULL; - ULONG_PTR info; - - /* Lock buffer */ - fort_buffer_dpc_begin(buf, &buf_lock_queue); - - /* Lock stat */ - fort_stat_dpc_begin(stat, &stat_lock_queue); - - /* Get current Unix time */ - { - LARGE_INTEGER system_time; - PCHAR out; - - KeQuerySystemTime(&system_time); - - if (stat->system_time.QuadPart != system_time.QuadPart - && NT_SUCCESS(fort_buffer_prepare(buf, FORT_LOG_TIME_SIZE, &out, &irp, &info))) { - const INT64 unix_time = fort_system_to_unix_time(system_time.QuadPart); - - stat->system_time = system_time; - - fort_log_time_write(out, unix_time); - } - } - - /* Flush traffic statistics */ - while (stat->proc_active_count != 0) { - const UINT16 proc_count = (stat->proc_active_count < FORT_LOG_STAT_BUFFER_PROC_COUNT) - ? stat->proc_active_count - : FORT_LOG_STAT_BUFFER_PROC_COUNT; - const UINT32 len = FORT_LOG_STAT_SIZE(proc_count); - PCHAR out; - NTSTATUS status; - - status = fort_buffer_prepare(buf, len, &out, &irp, &info); - if (!NT_SUCCESS(status)) { - DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_ERROR_LEVEL, "FORT: Callout Timer: Error: %x\n", - status); - break; - } - - fort_log_stat_traf_header_write(out, proc_count); - out += FORT_LOG_STAT_HEADER_SIZE; - - fort_stat_dpc_traf_flush(stat, proc_count, out); - } - - /* Flush process group statistics */ - const UINT32 defer_flush_bits = fort_stat_dpc_group_flush(stat); - - /* Unlock stat */ - fort_stat_dpc_end(&stat_lock_queue); - - /* Flush pending buffer */ - if (irp == NULL) { - fort_buffer_dpc_flush_pending(buf, &irp, &info); - } - - /* Unlock buffer */ - fort_buffer_dpc_end(&buf_lock_queue); - - if (irp != NULL) { - fort_request_complete_info(irp, STATUS_SUCCESS, info); - } - - /* Flush deferred packets */ - fort_callout_defer_packet_flush(defer_flush_bits, TRUE); -} - -static void fort_worker_reauth(void) -{ - const FORT_CONF_FLAGS conf_flags = g_device->conf.conf_flags; - NTSTATUS status; - - status = fort_callout_force_reauth(conf_flags, 0); - - if (!NT_SUCCESS(status)) { - DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_ERROR_LEVEL, "FORT: Worker Reauth: Error: %x\n", - status); - } -} - -static void fort_app_period_timer(void) -{ - if (fort_conf_ref_period_update(&g_device->conf, FALSE, NULL)) { - fort_worker_queue(&g_device->worker, FORT_WORKER_REAUTH, &fort_worker_reauth); - } -} - -static NTSTATUS fort_device_create(PDEVICE_OBJECT device, PIRP irp) -{ - NTSTATUS status = STATUS_SUCCESS; - - UNUSED(device); - - /* Device opened */ - if (fort_device_flag_set(&g_device->conf, FORT_DEVICE_IS_OPENED, TRUE) - & FORT_DEVICE_IS_OPENED) { - status = STATUS_SHARING_VIOLATION; /* Only one client may connect */ - } - - if (NT_SUCCESS(status)) { - /* Clear buffer */ - fort_buffer_clear(&g_device->buffer); - } - - fort_request_complete(irp, status); - - return status; -} - -static NTSTATUS fort_device_close(PDEVICE_OBJECT device, PIRP irp) -{ - UNUSED(device); - - fort_request_complete(irp, STATUS_SUCCESS); - - return STATUS_SUCCESS; -} - -static NTSTATUS fort_device_cleanup(PDEVICE_OBJECT device, PIRP irp) -{ - UNUSED(device); - - /* Device closed */ - fort_device_flag_set( - &g_device->conf, (FORT_DEVICE_IS_OPENED | FORT_DEVICE_IS_VALIDATED), FALSE); - - /* Clear conf */ - { - const FORT_CONF_FLAGS old_conf_flags = fort_conf_ref_set(&g_device->conf, NULL); - - fort_conf_zones_set(&g_device->conf, NULL); - - fort_callout_force_reauth(old_conf_flags, FORT_DEFER_FLUSH_ALL); - } - - /* Clear buffer */ - fort_buffer_clear(&g_device->buffer); - - fort_request_complete(irp, STATUS_SUCCESS); - - return STATUS_SUCCESS; -} - -static void fort_device_cancel_pending(PDEVICE_OBJECT device, PIRP irp) -{ - ULONG_PTR info; - NTSTATUS status; - - UNUSED(device); - - status = fort_buffer_cancel_pending(&g_device->buffer, irp, &info); - - IoReleaseCancelSpinLock(irp->CancelIrql); /* before IoCompleteRequest()! */ - - fort_request_complete_info(irp, status, info); -} - -static NTSTATUS fort_device_control(PDEVICE_OBJECT device, PIRP irp) -{ - ULONG_PTR info = 0; - NTSTATUS status = STATUS_UNSUCCESSFUL; - - UNUSED(device); - - const PIO_STACK_LOCATION irp_stack = IoGetCurrentIrpStackLocation(irp); - const ULONG control_code = irp_stack->Parameters.DeviceIoControl.IoControlCode; - - if (control_code != (ULONG) FORT_IOCTL_VALIDATE - && !fort_device_flag(&g_device->conf, FORT_DEVICE_IS_VALIDATED)) - goto end; - - switch (control_code) { - case FORT_IOCTL_VALIDATE: { - const PFORT_CONF_VERSION conf_ver = irp->AssociatedIrp.SystemBuffer; - const ULONG len = irp_stack->Parameters.DeviceIoControl.InputBufferLength; - - if (len == sizeof(FORT_CONF_VERSION)) { - if (conf_ver->driver_version == DRIVER_VERSION) { - fort_device_flag_set(&g_device->conf, FORT_DEVICE_IS_VALIDATED, TRUE); - status = STATUS_SUCCESS; - } - } - break; - } - case FORT_IOCTL_SETCONF: { - const PFORT_CONF_IO conf_io = irp->AssociatedIrp.SystemBuffer; - const ULONG len = irp_stack->Parameters.DeviceIoControl.InputBufferLength; - - if (len > sizeof(FORT_CONF_IO)) { - const PFORT_CONF conf = &conf_io->conf; - PFORT_CONF_REF conf_ref = fort_conf_ref_new(conf, len - FORT_CONF_IO_CONF_OFF); - - if (conf_ref == NULL) { - status = STATUS_INSUFFICIENT_RESOURCES; - } else { - PFORT_STAT stat = &g_device->stat; - - const FORT_CONF_FLAGS old_conf_flags = fort_conf_ref_set(&g_device->conf, conf_ref); - - const UINT32 defer_flush_bits = - (stat->conf_group.limit_2bits ^ conf_io->conf_group.limit_2bits); - - fort_stat_conf_update(stat, conf_io); - - status = fort_callout_force_reauth(old_conf_flags, defer_flush_bits); - } - } - break; - } - case FORT_IOCTL_SETFLAGS: { - const PFORT_CONF_FLAGS conf_flags = irp->AssociatedIrp.SystemBuffer; - const ULONG len = irp_stack->Parameters.DeviceIoControl.InputBufferLength; - - if (len == sizeof(FORT_CONF_FLAGS)) { - const FORT_CONF_FLAGS old_conf_flags = - fort_conf_ref_flags_set(&g_device->conf, conf_flags); - - const UINT32 defer_flush_bits = - (old_conf_flags.group_bits != conf_flags->group_bits ? FORT_DEFER_FLUSH_ALL - : 0); - - status = fort_callout_force_reauth(old_conf_flags, defer_flush_bits); - } - break; - } - case FORT_IOCTL_GETLOG: { - PVOID out = irp->AssociatedIrp.SystemBuffer; - const ULONG out_len = irp_stack->Parameters.DeviceIoControl.OutputBufferLength; - - if (out_len < FORT_BUFFER_SIZE) { - status = STATUS_BUFFER_TOO_SMALL; - } else { - status = fort_buffer_xmove(&g_device->buffer, irp, out, out_len, &info); - - if (status == STATUS_PENDING) { - KIRQL cirq; - - IoMarkIrpPending(irp); - - IoAcquireCancelSpinLock(&cirq); - IoSetCancelRoutine(irp, fort_device_cancel_pending); - IoReleaseCancelSpinLock(cirq); - - return STATUS_PENDING; - } - } - break; - } - case FORT_IOCTL_ADDAPP: - case FORT_IOCTL_DELAPP: { - const PFORT_APP_ENTRY app_entry = irp->AssociatedIrp.SystemBuffer; - const ULONG len = irp_stack->Parameters.DeviceIoControl.InputBufferLength; - - if (len > sizeof(FORT_APP_ENTRY) && len >= (sizeof(FORT_APP_ENTRY) + app_entry->path_len)) { - PFORT_CONF_REF conf_ref = fort_conf_ref_take(&g_device->conf); - - if (conf_ref == NULL) { - status = STATUS_INSUFFICIENT_RESOURCES; - } else { - if (control_code == (ULONG) FORT_IOCTL_ADDAPP) { - status = fort_conf_ref_exe_add_entry(conf_ref, app_entry, FALSE); - } else { - fort_conf_ref_exe_del_entry(conf_ref, app_entry); - status = STATUS_SUCCESS; - } - - fort_conf_ref_put(&g_device->conf, conf_ref); - - if (NT_SUCCESS(status)) { - fort_worker_reauth(); - } - } - } - break; - } - case FORT_IOCTL_SETZONES: { - const PFORT_CONF_ZONES zones = irp->AssociatedIrp.SystemBuffer; - const ULONG len = irp_stack->Parameters.DeviceIoControl.InputBufferLength; - - if (len >= FORT_CONF_ZONES_DATA_OFF) { - PFORT_CONF_ZONES conf_zones = fort_conf_zones_new(zones, len); - - if (conf_zones == NULL) { - status = STATUS_INSUFFICIENT_RESOURCES; - } else { - fort_conf_zones_set(&g_device->conf, conf_zones); - - fort_worker_reauth(); - - status = STATUS_SUCCESS; - } - } - break; - } - case FORT_IOCTL_SETZONEFLAG: { - const PFORT_CONF_ZONE_FLAG zone_flag = irp->AssociatedIrp.SystemBuffer; - const ULONG len = irp_stack->Parameters.DeviceIoControl.InputBufferLength; - - if (len == sizeof(FORT_CONF_ZONE_FLAG)) { - fort_conf_zone_flag_set(&g_device->conf, zone_flag); - - fort_worker_reauth(); - - status = STATUS_SUCCESS; - } - break; - } - default: - break; - } - -end: - if (!NT_SUCCESS(status) && status != FORT_STATUS_USER_ERROR) { - DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_ERROR_LEVEL, "FORT: Device Control: Error: %x\n", - status); - } - - fort_request_complete_info(irp, status, info); - - return status; -} +#include "fortdev.h" +#include "fortcout.h" static void fort_power_callback(PVOID context, PVOID event, PVOID specifics) { @@ -1076,7 +17,7 @@ static void fort_power_callback(PVOID context, PVOID event, PVOID specifics) const BOOL power_off = (specifics == NULL); - fort_device_flag_set(&g_device->conf, FORT_DEVICE_POWER_OFF, power_off); + fort_device_flag_set(&fort_device()->conf, FORT_DEVICE_POWER_OFF, power_off); if (power_off) { fort_callout_defer_flush(); @@ -1093,11 +34,11 @@ static NTSTATUS fort_power_callback_register(void) InitializeObjectAttributes(&obj_attr, &obj_name, OBJ_CASE_INSENSITIVE, NULL, NULL); - status = ExCreateCallback(&g_device->power_cb_obj, &obj_attr, FALSE, TRUE); + status = ExCreateCallback(&fort_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); + fort_device()->power_cb_reg = + ExRegisterCallback(fort_device()->power_cb_obj, fort_power_callback, NULL); } return status; @@ -1105,12 +46,12 @@ static NTSTATUS fort_power_callback_register(void) static void fort_power_callback_unregister(void) { - if (g_device->power_cb_reg != NULL) { - ExUnregisterCallback(g_device->power_cb_reg); + if (fort_device()->power_cb_reg != NULL) { + ExUnregisterCallback(fort_device()->power_cb_reg); } - if (g_device->power_cb_obj != NULL) { - ObDereferenceObject(g_device->power_cb_obj); + if (fort_device()->power_cb_obj != NULL) { + ObDereferenceObject(fort_device()->power_cb_obj); } } @@ -1120,7 +61,7 @@ static void fort_systime_callback(PVOID context, PVOID event, PVOID specifics) UNUSED(event); UNUSED(specifics); - if (g_device->app_timer.running) { + if (fort_device()->app_timer.running) { fort_app_period_timer(); } } @@ -1135,11 +76,11 @@ static NTSTATUS fort_systime_callback_register(void) InitializeObjectAttributes(&obj_attr, &obj_name, OBJ_CASE_INSENSITIVE, NULL, NULL); - status = ExCreateCallback(&g_device->systime_cb_obj, &obj_attr, FALSE, TRUE); + status = ExCreateCallback(&fort_device()->systime_cb_obj, &obj_attr, FALSE, TRUE); if (NT_SUCCESS(status)) { - g_device->systime_cb_reg = - ExRegisterCallback(g_device->systime_cb_obj, fort_systime_callback, NULL); + fort_device()->systime_cb_reg = + ExRegisterCallback(fort_device()->systime_cb_obj, fort_systime_callback, NULL); } return status; @@ -1147,32 +88,32 @@ static NTSTATUS fort_systime_callback_register(void) static void fort_systime_callback_unregister(void) { - if (g_device->systime_cb_reg != NULL) { - ExUnregisterCallback(g_device->systime_cb_reg); + if (fort_device()->systime_cb_reg != NULL) { + ExUnregisterCallback(fort_device()->systime_cb_reg); } - if (g_device->systime_cb_obj != NULL) { - ObDereferenceObject(g_device->systime_cb_obj); + if (fort_device()->systime_cb_obj != NULL) { + ObDereferenceObject(fort_device()->systime_cb_obj); } } static void fort_driver_unload(PDRIVER_OBJECT driver) { - if (g_device != NULL) { + if (fort_device() != NULL) { fort_callout_defer_flush(); - fort_timer_close(&g_device->app_timer); - fort_timer_close(&g_device->log_timer); - fort_defer_close(&g_device->defer); - fort_stat_close(&g_device->stat); - fort_buffer_close(&g_device->buffer); + fort_timer_close(&fort_device()->app_timer); + fort_timer_close(&fort_device()->log_timer); + fort_defer_close(&fort_device()->defer); + fort_stat_close(&fort_device()->stat); + fort_buffer_close(&fort_device()->buffer); - fort_worker_unregister(&g_device->worker); + fort_worker_unregister(&fort_device()->worker); fort_power_callback_unregister(); fort_systime_callback_unregister(); - if (!fort_device_flag(&g_device->conf, FORT_DEVICE_PROV_BOOT)) { + if (!fort_device_flag(&fort_device()->conf, FORT_DEVICE_PROV_BOOT)) { fort_prov_unregister(0); } @@ -1183,7 +124,7 @@ static void fort_driver_unload(PDRIVER_OBJECT driver) { UNICODE_STRING device_link; - RtlInitUnicodeString(&device_link, DOS_DEVICE_NAME); + RtlInitUnicodeString(&device_link, FORT_DOS_DEVICE_NAME); IoDeleteSymbolicLink(&device_link); } @@ -1227,14 +168,14 @@ DriverEntry(PDRIVER_OBJECT driver, PUNICODE_STRING reg_path) return status; } - RtlInitUnicodeString(&device_name, NT_DEVICE_NAME); + RtlInitUnicodeString(&device_name, FORT_NT_DEVICE_NAME); status = IoCreateDevice( driver, sizeof(FORT_DEVICE), &device_name, FORT_DEVICE_TYPE, 0, FALSE, &device); if (NT_SUCCESS(status)) { UNICODE_STRING device_link; - RtlInitUnicodeString(&device_link, DOS_DEVICE_NAME); + RtlInitUnicodeString(&device_link, FORT_DOS_DEVICE_NAME); status = IoCreateSymbolicLink(&device_link, &device_name); if (NT_SUCCESS(status)) { @@ -1246,20 +187,21 @@ DriverEntry(PDRIVER_OBJECT driver, PUNICODE_STRING reg_path) device->Flags |= DO_BUFFERED_IO; - g_device = device->DeviceExtension; + fort_device_set(device->DeviceExtension); - RtlZeroMemory(g_device, sizeof(FORT_DEVICE)); + RtlZeroMemory(fort_device(), sizeof(FORT_DEVICE)); - fort_device_conf_open(&g_device->conf); - fort_buffer_open(&g_device->buffer); - fort_stat_open(&g_device->stat); - fort_defer_open(&g_device->defer); - fort_timer_open(&g_device->log_timer, 500, FALSE, &fort_callout_timer); - fort_timer_open(&g_device->app_timer, 60000, TRUE, &fort_app_period_timer); + fort_device_conf_open(&fort_device()->conf); + fort_buffer_open(&fort_device()->buffer); + fort_stat_open(&fort_device()->stat); + fort_defer_open(&fort_device()->defer); + fort_timer_open(&fort_device()->log_timer, 500, FALSE, &fort_callout_timer); + fort_timer_open(&fort_device()->app_timer, 60000, TRUE, &fort_app_period_timer); /* Unregister old filters provider */ { - fort_device_flag_set(&g_device->conf, FORT_DEVICE_PROV_BOOT, fort_prov_is_boot()); + fort_device_flag_set( + &fort_device()->conf, FORT_DEVICE_PROV_BOOT, fort_prov_is_boot()); fort_prov_unregister(0); } @@ -1269,12 +211,13 @@ DriverEntry(PDRIVER_OBJECT driver, PUNICODE_STRING reg_path) /* Register worker */ if (NT_SUCCESS(status)) { - status = fort_worker_register(device, &g_device->worker); + status = fort_worker_register(device, &fort_device()->worker); } /* Register filters provider */ if (NT_SUCCESS(status)) { - const BOOL prov_boot = fort_device_flag(&g_device->conf, FORT_DEVICE_PROV_BOOT); + const BOOL prov_boot = + fort_device_flag(&fort_device()->conf, FORT_DEVICE_PROV_BOOT); status = fort_prov_register(0, prov_boot); } diff --git a/src/driver/fortdrv.h b/src/driver/fortdrv.h index 176802e2..7c05defa 100644 --- a/src/driver/fortdrv.h +++ b/src/driver/fortdrv.h @@ -14,4 +14,13 @@ #define fort_mem_alloc(size, tag) ExAllocatePoolWithTag(NonPagedPool, (size), (tag)) #define fort_mem_free(p, tag) ExFreePoolWithTag((p), (tag)) +#define fort_request_complete_info(irp, status, info) \ + do { \ + (irp)->IoStatus.Status = (status); \ + (irp)->IoStatus.Information = (info); \ + IoCompleteRequest((irp), IO_NO_INCREMENT); \ + } while (0) + +#define fort_request_complete(irp, status) fort_request_complete_info((irp), (status), 0) + #endif // FORTDRV_H diff --git a/src/driver/fortdrv_amalg.c b/src/driver/fortdrv_amalg.c index 799da411..b9b80666 100644 --- a/src/driver/fortdrv_amalg.c +++ b/src/driver/fortdrv_amalg.c @@ -16,4 +16,6 @@ #include "fortstat.c" #include "forttmr.c" #include "fortwrk.c" +#include "fortcout.c" +#include "fortdev.c" #include "fortdrv.c" diff --git a/src/ui/fortcommon.cpp b/src/ui/fortcommon.cpp index 5af4b4f5..ae05ca3c 100644 --- a/src/ui/fortcommon.cpp +++ b/src/ui/fortcommon.cpp @@ -1,7 +1,7 @@ #include "fortcommon.h" #include -#include +#include #include #include