mirror of
https://github.com/henrypp/simplewall.git
synced 2026-10-19 01:30:39 -05:00
implement correct formatted #2143
This commit is contained in:
12 files changed
+1151
-39
No files matched your search
@@ -393,6 +393,7 @@
|
||||
<ClCompile Include="src\search.c" />
|
||||
<ClCompile Include="src\security.c" />
|
||||
<ClCompile Include="src\timer.c" />
|
||||
<ClCompile Include="src\udpstats.c" />
|
||||
<ClCompile Include="src\uwp.cpp" />
|
||||
<ClCompile Include="src\wfp.c" />
|
||||
<ClCompile Include="src\messages.c" />
|
||||
@@ -422,6 +423,7 @@
|
||||
<ClInclude Include="src\search.h" />
|
||||
<ClInclude Include="src\security.h" />
|
||||
<ClInclude Include="src\timer.h" />
|
||||
<ClInclude Include="src\udpstats.h" />
|
||||
<ClInclude Include="src\uwp.h" />
|
||||
<ClInclude Include="src\wfp.h" />
|
||||
<ClInclude Include="src\messages.h" />
|
||||
|
||||
@@ -75,6 +75,9 @@
|
||||
<ClCompile Include="src\uwp.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\udpstats.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="src\main.h">
|
||||
@@ -158,6 +161,9 @@
|
||||
<ClInclude Include="src\uwp.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="src\udpstats.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="src\resource.rc">
|
||||
|
||||
+19
-16
@@ -15,6 +15,7 @@ VOID _app_getapptooltipstring (
|
||||
PR_STRING path = NULL;
|
||||
PITEM_APP ptr_app;
|
||||
PR_STRING string, value;
|
||||
LONG traffic_error;
|
||||
|
||||
ptr_app = _app_getappitem (app_hash);
|
||||
|
||||
@@ -53,6 +54,19 @@ VOID _app_getapptooltipstring (
|
||||
_r_obj_appendstringbuilder (buffer, SZ_CRLF);
|
||||
}
|
||||
|
||||
// UDP accounting status
|
||||
if (ptr_network && ptr_network->protocol == IPPROTO_UDP && (ptr_network->is_stats_initialized || _InterlockedCompareExchange (&ptr_network->traffic_error, 0, 0)))
|
||||
{
|
||||
traffic_error = _InterlockedCompareExchange (&ptr_network->traffic_error, 0, 0);
|
||||
|
||||
_r_obj_appendstringbuilder (buffer, _r_locale_getstring (traffic_error == ERROR_NOT_READY ? IDS_UDP_PENDING : (traffic_error ? IDS_UDP_UNAVAILABLE : IDS_UDP_ACCOUNTING)));
|
||||
|
||||
if (traffic_error && traffic_error != ERROR_NOT_READY)
|
||||
_r_obj_appendstringbuilderformat (buffer, L" (%lu)", (ULONG)traffic_error);
|
||||
|
||||
_r_obj_appendstringbuilder (buffer, SZ_CRLF);
|
||||
}
|
||||
|
||||
// file information
|
||||
_r_obj_initializestringbuilder (&sb, 0);
|
||||
|
||||
@@ -552,7 +566,7 @@ LONG _app_getstateicon (
|
||||
|
||||
default:
|
||||
{
|
||||
return IDI_INACTIVE;
|
||||
return IDI_INACTIVE; // never match!
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -658,25 +672,14 @@ VOID _app_settrayicon (
|
||||
_In_ ENUM_INSTALL_TYPE install_type
|
||||
)
|
||||
{
|
||||
HICON current_handle, new_handle;
|
||||
LONG icon_id, icon_size;
|
||||
HICON hicon;
|
||||
LONG icon_size;
|
||||
|
||||
icon_size = _r_dc_getsystemmetrics (SM_CXSMICON, _r_dc_gettaskbardpi ());
|
||||
icon_id = _app_getstateicon (install_type);
|
||||
|
||||
current_handle = (HICON)_InterlockedCompareExchangePointer ((volatile PVOID_PTR)&config.htray_icon, NULL, config.htray_icon);
|
||||
hicon = _r_sys_loadsharedicon (_r_sys_getimagebase (), MAKEINTRESOURCE (_app_getstateicon (install_type)), icon_size);
|
||||
|
||||
if (current_handle)
|
||||
DestroyIcon (current_handle);
|
||||
|
||||
_r_sys_loadicon (&new_handle, _r_sys_getimagebase (), MAKEINTRESOURCE (icon_id), icon_size);
|
||||
|
||||
_r_tray_setinfo (hwnd, &GUID_TrayIcon, new_handle, _r_app_getname ());
|
||||
|
||||
current_handle = (HICON)_InterlockedCompareExchangePointer ((volatile PVOID_PTR)&config.htray_icon, new_handle, NULL);
|
||||
|
||||
if (current_handle)
|
||||
DestroyIcon (current_handle);
|
||||
_r_tray_setinfo (hwnd, &GUID_TrayIcon, hicon, _r_app_getname ());
|
||||
}
|
||||
|
||||
VOID _app_imagelist_init (
|
||||
|
||||
@@ -22,6 +22,8 @@
|
||||
#include <softpub.h>
|
||||
#include <subauth.h>
|
||||
#include <mscat.h>
|
||||
#include <evntrace.h>
|
||||
#include <evntcons.h>
|
||||
|
||||
#include "app.h"
|
||||
#include "rapp.h"
|
||||
@@ -114,5 +116,6 @@ DECLSPEC_SELECTANY const LONG64 timer_array[] =
|
||||
#include "search.h"
|
||||
#include "security.h"
|
||||
#include "timer.h"
|
||||
#include "udpstats.h"
|
||||
#include "uwp.h"
|
||||
#include "wfp.h"
|
||||
+50
@@ -266,6 +266,24 @@ VOID _app_config_apply (
|
||||
break;
|
||||
}
|
||||
|
||||
case IDM_CONNECTIONS_ENABLE:
|
||||
{
|
||||
new_val = !_r_config_getboolean (L"IsNetworkMonitorEnabled", TRUE, NULL);
|
||||
break;
|
||||
}
|
||||
|
||||
case IDM_CONNECTIONS_SHOWAITCONNECTIONS:
|
||||
{
|
||||
new_val = !_r_config_getboolean (L"IsNetworkShowWaitConnections", TRUE, NULL);
|
||||
break;
|
||||
}
|
||||
|
||||
case IDM_CONNECTIONS_MEASUREUDPTRAFFIC:
|
||||
{
|
||||
new_val = !_r_config_getboolean (L"IsUdpTrafficEnabled", FALSE, NULL);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
return;
|
||||
@@ -411,6 +429,33 @@ VOID _app_config_apply (
|
||||
break;
|
||||
}
|
||||
|
||||
case IDM_CONNECTIONS_ENABLE:
|
||||
{
|
||||
_r_config_setboolean (L"IsNetworkMonitorEnabled", new_val, NULL);
|
||||
|
||||
_r_menu_checkitem (hmenu, IDM_CONNECTIONS_ENABLE, 0, MF_BYCOMMAND, new_val);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case IDM_CONNECTIONS_SHOWAITCONNECTIONS:
|
||||
{
|
||||
_r_config_setboolean (L"IsNetworkShowWaitConnections", new_val, NULL);
|
||||
|
||||
_r_menu_checkitem (hmenu, IDM_CONNECTIONS_SHOWAITCONNECTIONS, 0, MF_BYCOMMAND, new_val);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case IDM_CONNECTIONS_MEASUREUDPTRAFFIC:
|
||||
{
|
||||
_r_config_setboolean (L"IsUdpTrafficEnabled", new_val, NULL);
|
||||
|
||||
_r_menu_checkitem (hmenu, IDM_CONNECTIONS_MEASUREUDPTRAFFIC, 0, MF_BYCOMMAND, new_val);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case IDC_USESTEALTHMODE_CHK:
|
||||
{
|
||||
_r_config_setboolean (L"UseStealthMode", new_val, NULL);
|
||||
@@ -527,6 +572,7 @@ VOID _app_config_apply (
|
||||
case IDM_PROFILETYPE_PLAIN:
|
||||
case IDM_PROFILETYPE_COMPRESSED:
|
||||
case IDM_PROFILETYPE_ENCRYPTED:
|
||||
case IDM_CONNECTIONS_MEASUREUDPTRAFFIC:
|
||||
case IDC_USENETWORKRESOLUTION_CHK:
|
||||
case IDM_USENETWORKRESOLUTION_CHK:
|
||||
case IDC_USECERTIFICATES_CHK:
|
||||
@@ -2109,6 +2155,7 @@ INT_PTR CALLBACK DlgProc (
|
||||
|
||||
case WM_DESTROY:
|
||||
{
|
||||
_app_network_stop ();
|
||||
_app_loginit (FALSE);
|
||||
|
||||
if (_r_queuedlock_islocked (&lock_apply))
|
||||
@@ -3066,6 +3113,9 @@ INT_PTR CALLBACK DlgProc (
|
||||
case IDM_PROFILETYPE_PLAIN:
|
||||
case IDM_PROFILETYPE_COMPRESSED:
|
||||
case IDM_PROFILETYPE_ENCRYPTED:
|
||||
case IDM_CONNECTIONS_ENABLE:
|
||||
case IDM_CONNECTIONS_SHOWAITCONNECTIONS:
|
||||
case IDM_CONNECTIONS_MEASUREUDPTRAFFIC:
|
||||
case IDM_USENETWORKRESOLUTION_CHK:
|
||||
case IDM_USECERTIFICATES_CHK:
|
||||
case IDM_KEEPUNUSED_CHK:
|
||||
|
||||
+72
-5
@@ -209,7 +209,6 @@ typedef struct _STATIC_DATA
|
||||
PSID builtin_admins_sid;
|
||||
|
||||
volatile HWND hnotification;
|
||||
volatile HICON htray_icon;
|
||||
volatile HANDLE hnetevent;
|
||||
volatile HANDLE hlogfile;
|
||||
volatile LONG log_id;
|
||||
@@ -269,7 +268,6 @@ typedef struct _ITEM_LOG
|
||||
volatile PR_STRING local_host_str;
|
||||
|
||||
LONG64 timestamp;
|
||||
|
||||
UINT64 filter_id;
|
||||
|
||||
ULONG app_hash;
|
||||
@@ -429,12 +427,11 @@ typedef struct _ITEM_NETWORK
|
||||
|
||||
UINT16 remote_port;
|
||||
UINT16 local_port;
|
||||
|
||||
UINT8 protocol;
|
||||
|
||||
BOOLEAN is_connection;
|
||||
BOOLEAN is_stats_enabled;
|
||||
BOOLEAN is_stats_initialized;
|
||||
BOOLEAN is_stats_enabled;
|
||||
BOOLEAN is_connection;
|
||||
|
||||
volatile LONG64 download_speed;
|
||||
volatile LONG64 upload_speed;
|
||||
@@ -444,6 +441,9 @@ typedef struct _ITEM_NETWORK
|
||||
ULONG64 last_bytes_in;
|
||||
ULONG64 last_bytes_out;
|
||||
ULONG64 last_stats_tick;
|
||||
ULONG64 udp_created;
|
||||
|
||||
volatile LONG traffic_error;
|
||||
} ITEM_NETWORK, *PITEM_NETWORK;
|
||||
|
||||
typedef struct _ITEM_STATUS
|
||||
@@ -550,3 +550,70 @@ typedef struct _ITEM_TAB_CONTEXT
|
||||
INT listview_id;
|
||||
INT locale_id;
|
||||
} ITEM_TAB_CONTEXT, *PITEM_TAB_CONTEXT;
|
||||
|
||||
typedef struct _UDP_ENDPOINT
|
||||
{
|
||||
BYTE address[0x10];
|
||||
ULONG64 created; // UDP owner table bind timestamp, in FILETIME units
|
||||
ULONG scope_id;
|
||||
ULONG pid;
|
||||
ADDRESS_FAMILY af;
|
||||
USHORT port; // host byte order
|
||||
} UDP_ENDPOINT, *PUDP_ENDPOINT;
|
||||
|
||||
typedef struct UDP_ENTRY
|
||||
{
|
||||
struct UDP_ENTRY *next;
|
||||
UDP_ENDPOINT endpoint;
|
||||
ULONG64 since;
|
||||
ULONG64 received;
|
||||
ULONG64 sent;
|
||||
ULONG error_code;
|
||||
ULONG epoch;
|
||||
BOOLEAN is_observed;
|
||||
} UDP_ENTRY, *PUDP_ENTRY;
|
||||
|
||||
typedef struct UDP_AFD_SOCKET
|
||||
{
|
||||
struct UDP_AFD_SOCKET *next;
|
||||
UDP_ENDPOINT endpoint;
|
||||
ULONG64 handle;
|
||||
BOOLEAN is_bound;
|
||||
BOOLEAN is_unsupported;
|
||||
} UDP_AFD_SOCKET, *PUDP_AFD_SOCKET;
|
||||
|
||||
typedef struct _UDP_TRACE_PROPERTIES
|
||||
{
|
||||
EVENT_TRACE_PROPERTIES properties;
|
||||
WCHAR name[0x40];
|
||||
} UDP_TRACE_PROPERTIES, *PUDP_TRACE_PROPERTIES;
|
||||
|
||||
#define UDP_SESSION_SEMAPHORE L"Global\\simplewall-UDP-owner"
|
||||
#define UDP_SESSION_NAME L"simplewall-UDP"
|
||||
#define UDP_MAX_ENDPOINTS 0x2000
|
||||
#define UDP_BUCKETS 0x100
|
||||
|
||||
typedef struct _SW_UDP_STATS
|
||||
{
|
||||
RTL_SRWLOCK control_lock;
|
||||
RTL_SRWLOCK lock;
|
||||
UDP_ENTRY *buckets[UDP_BUCKETS];
|
||||
UDP_AFD_SOCKET *sockets[UDP_BUCKETS]; // owned by the ETW consumer thread
|
||||
HANDLE hthread;
|
||||
HANDLE hguard;
|
||||
TRACEHANDLE hsession;
|
||||
TRACEHANDLE hconsumer;
|
||||
ULONG socket_count;
|
||||
ULONG count;
|
||||
ULONG epoch;
|
||||
volatile LONG error_code;
|
||||
volatile LONG stopping;
|
||||
BOOLEAN is_owns_guard;
|
||||
} SW_UDP_STATS, *PSW_UDP_STATS;
|
||||
|
||||
typedef struct _UDP_SNAPSHOT
|
||||
{
|
||||
ULONG64 received;
|
||||
ULONG64 sent;
|
||||
ULONG error_code; // nonzero means totals must not be presented as complete
|
||||
} UDP_SNAPSHOT, *PUDP_SNAPSHOT;
|
||||
@@ -78,6 +78,10 @@ VOID _app_message_initialize (
|
||||
|
||||
_r_menu_checkitem (hmenu, IDM_PROFILETYPE_PLAIN, IDM_PROFILETYPE_ENCRYPTED, MF_BYCOMMAND, IDM_PROFILETYPE_PLAIN + _r_calc_clamp (_r_config_getlong (L"ProfileType", 0, NULL), 0, 2));
|
||||
|
||||
_r_menu_checkitem (hmenu, IDM_CONNECTIONS_ENABLE, 0, MF_BYCOMMAND, _r_config_getboolean (L"IsNetworkMonitorEnabled", TRUE, NULL));
|
||||
_r_menu_checkitem (hmenu, IDM_CONNECTIONS_SHOWAITCONNECTIONS, 0, MF_BYCOMMAND, _r_config_getboolean (L"IsNetworkShowWaitConnections", TRUE, NULL));
|
||||
_r_menu_checkitem (hmenu, IDM_CONNECTIONS_MEASUREUDPTRAFFIC, 0, MF_BYCOMMAND, _r_config_getboolean (L"IsUdpTrafficEnabled", FALSE, NULL));
|
||||
|
||||
is_enabled = _r_config_getboolean (L"IsHashesEnabled", FALSE, NULL);
|
||||
|
||||
_r_menu_checkitem (hmenu, IDM_USECERTIFICATES_CHK, 0, MF_BYCOMMAND, _r_config_getboolean (L"IsCertificatesEnabled", TRUE, NULL));
|
||||
@@ -187,6 +191,10 @@ VOID _app_message_localize (
|
||||
_r_menu_setitemtext (hmenu, IDM_PROFILETYPE_COMPRESSED, FALSE, _r_locale_getstring (IDS_PROFILE_TYPE_COMPRESSED));
|
||||
_r_menu_setitemtext (hmenu, IDM_PROFILETYPE_ENCRYPTED, FALSE, _r_locale_getstring (IDS_PROFILE_TYPE_ENCRYPTED));
|
||||
|
||||
_r_menu_setitemtext (hmenu, IDM_CONNECTIONS_ENABLE, FALSE, _r_locale_getstring (IDS_CONNECTIONS_ENABLE));
|
||||
_r_menu_setitemtext (hmenu, IDM_CONNECTIONS_SHOWAITCONNECTIONS, FALSE, _r_locale_getstring (IDS_CONNECTIONS_SHOWAITCONNECTIONS));
|
||||
_r_menu_setitemtext (hmenu, IDM_CONNECTIONS_MEASUREUDPTRAFFIC, FALSE, _r_locale_getstring (IDS_CONNECTIONS_MEASUREUDPTRAFFIC));
|
||||
|
||||
_r_menu_setitemtext (hmenu, IDM_USENETWORKRESOLUTION_CHK, FALSE, _r_locale_getstring (IDS_USENETWORKRESOLUTION_CHK));
|
||||
_r_menu_setitemtext (hmenu, IDM_USECERTIFICATES_CHK, FALSE, _r_locale_getstring (IDS_USECERTIFICATES_CHK));
|
||||
_r_menu_setitemtext (hmenu, IDM_KEEPUNUSED_CHK, FALSE, _r_locale_getstring (IDS_KEEPUNUSED_CHK));
|
||||
@@ -199,6 +207,7 @@ VOID _app_message_localize (
|
||||
{
|
||||
_r_menu_setitemtext (hsubmenu, 5, TRUE, _r_locale_getstring (IDS_TRAY_RULES));
|
||||
_r_menu_setitemtext (hsubmenu, 6, TRUE, _r_locale_getstring (IDS_PROFILE_TYPE));
|
||||
_r_menu_setitemtext (hsubmenu, 7, TRUE, _r_locale_getstring (IDS_TAB_NETWORK));
|
||||
}
|
||||
|
||||
recommended_string = _r_locale_getstring (IDS_RECOMMENDED);
|
||||
@@ -1405,6 +1414,12 @@ VOID _app_displayinfonetwork_callback (
|
||||
case 10:
|
||||
case 11:
|
||||
{
|
||||
if (ptr_network->protocol == IPPROTO_UDP && _InterlockedCompareExchange (&ptr_network->traffic_error, 0, 0))
|
||||
{
|
||||
_r_str_copy (lpnmlv->item.pszText, lpnmlv->item.cchTextMax, L"\x2014");
|
||||
break;
|
||||
}
|
||||
|
||||
if (!ptr_network->is_stats_initialized)
|
||||
break;
|
||||
|
||||
|
||||
+123
-6
@@ -113,7 +113,54 @@ static VOID _app_network_update_tcp6_stats (
|
||||
_app_network_update_stats_values (ptr_network, data_rod.DataBytesIn, data_rod.DataBytesOut);
|
||||
}
|
||||
|
||||
_Ret_maybenull_
|
||||
static VOID _app_network_update_udp_stats (
|
||||
_Inout_ PITEM_NETWORK ptr_network,
|
||||
_In_ PITEM_NETWORK_CONTEXT context,
|
||||
_In_ ULONG pid,
|
||||
_In_ ULONG64 created,
|
||||
_In_ ULONG scope_id
|
||||
)
|
||||
{
|
||||
UDP_ENDPOINT endpoint = {0};
|
||||
UDP_SNAPSHOT snapshot;
|
||||
|
||||
if (!context->udp_stats)
|
||||
return;
|
||||
|
||||
endpoint.pid = pid;
|
||||
endpoint.af = ptr_network->af;
|
||||
endpoint.port = ptr_network->local_port;
|
||||
endpoint.created = created;
|
||||
endpoint.scope_id = scope_id;
|
||||
|
||||
RtlCopyMemory (endpoint.address, &ptr_network->local_addr, endpoint.af == AF_INET ? 4 : 16); // set correct sizes
|
||||
|
||||
udp_stats_read (context->udp_stats, &endpoint, &snapshot);
|
||||
|
||||
_InterlockedExchange (&ptr_network->traffic_error, snapshot.error_code);
|
||||
|
||||
if (snapshot.error_code)
|
||||
{
|
||||
ptr_network->is_stats_initialized = FALSE;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (ptr_network->udp_created != created)
|
||||
{
|
||||
ptr_network->udp_created = created;
|
||||
ptr_network->is_stats_initialized = FALSE;
|
||||
|
||||
_InterlockedExchange64 (&ptr_network->download_speed, 0);
|
||||
_InterlockedExchange64 (&ptr_network->upload_speed, 0);
|
||||
}
|
||||
|
||||
_app_network_update_stats_values (ptr_network, snapshot.received, snapshot.sent);
|
||||
|
||||
_InterlockedExchange64 (&ptr_network->download_total, snapshot.received);
|
||||
_InterlockedExchange64 (&ptr_network->upload_total, snapshot.sent);
|
||||
}
|
||||
|
||||
PITEM_NETWORK_CONTEXT _app_network_getcontext ()
|
||||
{
|
||||
static R_INITONCE init_once = PR_INITONCE_INIT;
|
||||
@@ -132,23 +179,41 @@ PITEM_NETWORK_CONTEXT _app_network_getcontext ()
|
||||
return network_context;
|
||||
}
|
||||
|
||||
VOID _app_network_stop ()
|
||||
{
|
||||
// the original network worker lives until process exit. keep the stopped context valid for that worker; stop/join only our independent ETW consumer.
|
||||
udp_stats_stop (_app_network_getcontext ()->udp_stats);
|
||||
}
|
||||
|
||||
VOID _app_network_initialize (
|
||||
_In_ HWND hwnd
|
||||
)
|
||||
{
|
||||
PITEM_NETWORK_CONTEXT network_context;
|
||||
R_ENVIRONMENT environment;
|
||||
ULONG status;
|
||||
|
||||
if (!_r_config_getboolean (L"IsNetworkMonitorEnabled", TRUE, NULL))
|
||||
return;
|
||||
|
||||
network_context = _app_network_getcontext ();
|
||||
|
||||
if (!network_context)
|
||||
if (!network_context) // USELESS!
|
||||
return;
|
||||
|
||||
network_context->hwnd = hwnd;
|
||||
|
||||
// opt-in: sockets created before capture cannot be mapped by AFD events
|
||||
if (_r_config_getboolean (L"IsUdpTrafficEnabled", FALSE, NULL))
|
||||
{
|
||||
network_context->udp_stats = udp_stats_create ();
|
||||
|
||||
status = udp_stats_start (network_context->udp_stats);
|
||||
|
||||
if (status != STATUS_SUCCESS && status != STATUS_ALREADY_INITIALIZED)
|
||||
_r_log (LOG_LEVEL_WARNING, NULL, L"udp_stats_start", NULL, status);
|
||||
}
|
||||
|
||||
_r_queuedlock_acquireexclusive (&network_context->lock_network);
|
||||
_r_obj_clearhashtable (network_context->network_ptr);
|
||||
_r_queuedlock_releaseexclusive (&network_context->lock_network);
|
||||
@@ -176,6 +241,16 @@ VOID _app_network_uninitialize (
|
||||
_r_queuedlock_releaseexclusive (&context->lock_checker);
|
||||
}
|
||||
|
||||
FORCEINLINE BOOLEAN _app_network_iswaitingconnection (
|
||||
_In_ ULONG pid
|
||||
)
|
||||
{
|
||||
if (pid == PROC_WAITING_PID && !_r_config_getboolean (L"IsNetworkShowWaitConnections", TRUE, NULL))
|
||||
return TRUE;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
VOID _app_network_generatetable (
|
||||
_Inout_ PITEM_NETWORK_CONTEXT network_context
|
||||
)
|
||||
@@ -184,12 +259,16 @@ VOID _app_network_generatetable (
|
||||
PMIB_UDP6TABLE_OWNER_MODULE udp6_table;
|
||||
PMIB_TCPTABLE_OWNER_MODULE tcp4_table;
|
||||
PMIB_UDPTABLE_OWNER_MODULE udp4_table;
|
||||
PITEM_NETWORK ptr_network;
|
||||
IN_ADDR local_addr, remote_addr;
|
||||
PITEM_NETWORK ptr_network;
|
||||
PVOID buffer;
|
||||
ULONG allocated_size, network_hash, required_size = 0;
|
||||
BOOL udp4_complete = FALSE, udp6_complete = FALSE;
|
||||
ULONG status;
|
||||
|
||||
udp_stats_poll (network_context->udp_stats);
|
||||
udp_stats_begin_refresh (network_context->udp_stats);
|
||||
|
||||
_r_queuedlock_acquireexclusive (&network_context->lock_checker);
|
||||
_r_obj_clearhashtable (network_context->checker_ptr);
|
||||
_r_queuedlock_releaseexclusive (&network_context->lock_checker);
|
||||
@@ -209,6 +288,9 @@ VOID _app_network_generatetable (
|
||||
{
|
||||
for (ULONG i = 0; i < tcp4_table->dwNumEntries; i++)
|
||||
{
|
||||
if (_app_network_iswaitingconnection (tcp4_table->table[i].dwOwningPid))
|
||||
continue;
|
||||
|
||||
RtlZeroMemory (&remote_addr, sizeof (IN_ADDR));
|
||||
RtlZeroMemory (&local_addr, sizeof (IN_ADDR));
|
||||
|
||||
@@ -246,6 +328,7 @@ VOID _app_network_generatetable (
|
||||
if (!_app_network_getpath (ptr_network, tcp4_table->table[i].dwOwningPid, tcp4_table->table[i].OwningModuleInfo))
|
||||
{
|
||||
_r_obj_dereference (ptr_network);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -299,6 +382,9 @@ VOID _app_network_generatetable (
|
||||
{
|
||||
for (ULONG i = 0; i < tcp6_table->dwNumEntries; i++)
|
||||
{
|
||||
if (_app_network_iswaitingconnection (tcp6_table->table[i].dwOwningPid))
|
||||
continue;
|
||||
|
||||
network_hash = _app_network_gethash (
|
||||
AF_INET6,
|
||||
tcp6_table->table[i].dwOwningPid,
|
||||
@@ -330,6 +416,7 @@ VOID _app_network_generatetable (
|
||||
if (!_app_network_getpath (ptr_network, tcp6_table->table[i].dwOwningPid, tcp6_table->table[i].OwningModuleInfo))
|
||||
{
|
||||
_r_obj_dereference (ptr_network);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -381,6 +468,8 @@ VOID _app_network_generatetable (
|
||||
|
||||
if (status == NO_ERROR)
|
||||
{
|
||||
udp4_complete = TRUE;
|
||||
|
||||
for (ULONG i = 0; i < udp4_table->dwNumEntries; i++)
|
||||
{
|
||||
RtlZeroMemory (&local_addr, sizeof (IN_ADDR));
|
||||
@@ -389,20 +478,30 @@ VOID _app_network_generatetable (
|
||||
|
||||
network_hash = _app_network_gethash (AF_INET, udp4_table->table[i].dwOwningPid, NULL, 0, &local_addr, udp4_table->table[i].dwLocalPort, IPPROTO_UDP, 0);
|
||||
|
||||
if (_app_network_isitemfound (network_hash))
|
||||
ptr_network = _app_network_getitem (network_hash);
|
||||
|
||||
if (ptr_network)
|
||||
{
|
||||
_app_network_update_udp_stats (ptr_network, network_context, udp4_table->table[i].dwOwningPid, udp4_table->table[i].liCreateTimestamp.QuadPart, 0);
|
||||
|
||||
_r_queuedlock_acquireexclusive (&network_context->lock_checker);
|
||||
_r_obj_addhashtablepointer (network_context->checker_ptr, network_hash, NULL);
|
||||
_r_queuedlock_releaseexclusive (&network_context->lock_checker);
|
||||
|
||||
_r_obj_dereference (ptr_network);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (_app_network_iswaitingconnection (udp4_table->table[i].dwOwningPid))
|
||||
continue;
|
||||
|
||||
ptr_network = (PITEM_NETWORK)_r_obj_allocate (sizeof (ITEM_NETWORK), &_app_dereferencenetwork);
|
||||
|
||||
if (!_app_network_getpath (ptr_network, udp4_table->table[i].dwOwningPid, udp4_table->table[i].OwningModuleInfo))
|
||||
{
|
||||
_r_obj_dereference (ptr_network);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -413,6 +512,8 @@ VOID _app_network_generatetable (
|
||||
ptr_network->local_addr.S_un.S_addr = udp4_table->table[i].dwLocalAddr;
|
||||
ptr_network->local_port = _r_byteswap_ushort ((USHORT)udp4_table->table[i].dwLocalPort);
|
||||
|
||||
_app_network_update_udp_stats (ptr_network, network_context, udp4_table->table[i].dwOwningPid, udp4_table->table[i].liCreateTimestamp.QuadPart, 0);
|
||||
|
||||
if (_app_network_isvalidconnection (ptr_network->af, &ptr_network->local_addr))
|
||||
ptr_network->is_connection = TRUE;
|
||||
|
||||
@@ -444,24 +545,36 @@ VOID _app_network_generatetable (
|
||||
|
||||
if (status == NO_ERROR)
|
||||
{
|
||||
udp6_complete = TRUE;
|
||||
|
||||
for (ULONG i = 0; i < udp6_table->dwNumEntries; i++)
|
||||
{
|
||||
network_hash = _app_network_gethash (AF_INET6, udp6_table->table[i].dwOwningPid, NULL, 0, udp6_table->table[i].ucLocalAddr, udp6_table->table[i].dwLocalPort, IPPROTO_UDP, 0);
|
||||
|
||||
if (_app_network_isitemfound (network_hash))
|
||||
ptr_network = _app_network_getitem (network_hash);
|
||||
|
||||
if (ptr_network)
|
||||
{
|
||||
_app_network_update_udp_stats (ptr_network, network_context, udp6_table->table[i].dwOwningPid, udp6_table->table[i].liCreateTimestamp.QuadPart, udp6_table->table[i].dwLocalScopeId);
|
||||
|
||||
_r_queuedlock_acquireexclusive (&network_context->lock_checker);
|
||||
_r_obj_addhashtablepointer (network_context->checker_ptr, network_hash, NULL);
|
||||
_r_queuedlock_releaseexclusive (&network_context->lock_checker);
|
||||
|
||||
_r_obj_dereference (ptr_network);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (_app_network_iswaitingconnection (udp6_table->table[i].dwOwningPid))
|
||||
continue;
|
||||
|
||||
ptr_network = (PITEM_NETWORK)_r_obj_allocate (sizeof (ITEM_NETWORK), &_app_dereferencenetwork);
|
||||
|
||||
if (!_app_network_getpath (ptr_network, udp6_table->table[i].dwOwningPid, udp6_table->table[i].OwningModuleInfo))
|
||||
{
|
||||
_r_obj_dereference (ptr_network);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -472,6 +585,8 @@ VOID _app_network_generatetable (
|
||||
RtlCopyMemory (ptr_network->local_addr6.u.Byte, udp6_table->table[i].ucLocalAddr, FWP_V6_ADDR_SIZE);
|
||||
ptr_network->local_port = _r_byteswap_ushort ((USHORT)udp6_table->table[i].dwLocalPort);
|
||||
|
||||
_app_network_update_udp_stats (ptr_network, network_context, udp6_table->table[i].dwOwningPid, udp6_table->table[i].liCreateTimestamp.QuadPart, udp6_table->table[i].dwLocalScopeId);
|
||||
|
||||
if (_app_network_isvalidconnection (ptr_network->af, &ptr_network->local_addr6))
|
||||
ptr_network->is_connection = TRUE;
|
||||
|
||||
@@ -486,6 +601,8 @@ VOID _app_network_generatetable (
|
||||
}
|
||||
}
|
||||
|
||||
udp_stats_end_refresh (network_context->udp_stats, udp4_complete, udp6_complete);
|
||||
|
||||
if (buffer)
|
||||
_r_mem_free (buffer);
|
||||
}
|
||||
@@ -772,7 +889,7 @@ VOID _app_network_printlistviewtable (
|
||||
|
||||
_app_listview_addnetworkitem (network_context->hwnd, network_hash);
|
||||
|
||||
if (ptr_network->path && ptr_network->app_hash)
|
||||
if (ptr_network->app_hash && ptr_network->path)
|
||||
_app_getfileinformation (ptr_network->path, ptr_network->app_hash, ptr_network->type, IDC_NETWORK);
|
||||
|
||||
// resolve network address
|
||||
|
||||
+10
-2
@@ -3,17 +3,25 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "udpstats.h"
|
||||
|
||||
typedef struct _ITEM_NETWORK_CONTEXT
|
||||
{
|
||||
HWND hwnd;
|
||||
|
||||
R_QUEUED_LOCK lock_network;
|
||||
R_QUEUED_LOCK lock_checker;
|
||||
|
||||
PR_HASHTABLE network_ptr;
|
||||
PR_HASHTABLE checker_ptr;
|
||||
|
||||
SW_UDP_STATS *udp_stats;
|
||||
|
||||
HWND hwnd;
|
||||
} ITEM_NETWORK_CONTEXT, *PITEM_NETWORK_CONTEXT;
|
||||
|
||||
PITEM_NETWORK_CONTEXT _app_network_getcontext ();
|
||||
|
||||
VOID _app_network_stop ();
|
||||
|
||||
VOID _app_network_initialize (
|
||||
_In_ HWND hwnd
|
||||
);
|
||||
|
||||
+12
-10
@@ -797,20 +797,22 @@ VOID _app_freeapplication (
|
||||
{
|
||||
PITEM_RULE ptr_rule;
|
||||
|
||||
_r_queuedlock_acquireshared (&lock_rules);
|
||||
|
||||
for (ULONG_PTR i = 0; i < _r_obj_getlistsize (rules_list); i++)
|
||||
if (hwnd)
|
||||
{
|
||||
ptr_rule = (PITEM_RULE)_r_obj_getlistitem (rules_list, i);
|
||||
_r_queuedlock_acquireshared (&lock_rules);
|
||||
|
||||
if (!ptr_rule || ptr_rule->type != DATA_RULE_USER)
|
||||
continue;
|
||||
for (ULONG_PTR i = 0; i < _r_obj_getlistsize (rules_list); i++)
|
||||
{
|
||||
ptr_rule = (PITEM_RULE)_r_obj_getlistitem (rules_list, i);
|
||||
|
||||
if (!ptr_rule || ptr_rule->type != DATA_RULE_USER)
|
||||
continue;
|
||||
|
||||
if (hwnd)
|
||||
_app_ruleremoveapp (hwnd, i, ptr_rule, app_hash);
|
||||
}
|
||||
}
|
||||
|
||||
_r_queuedlock_releaseshared (&lock_rules);
|
||||
_r_queuedlock_releaseshared (&lock_rules);
|
||||
}
|
||||
|
||||
_r_obj_removehashtableitem (apps_table, app_hash);
|
||||
}
|
||||
@@ -982,7 +984,7 @@ VOID _app_ruleremoveapp (
|
||||
if (!ptr_rule->apps || !_r_obj_removehashtableitem (ptr_rule->apps, app_hash))
|
||||
return;
|
||||
|
||||
if (ptr_rule->is_enabled && _r_obj_isempty (ptr_rule->apps))
|
||||
if (ptr_rule->is_enabled && _r_obj_isempty2 (ptr_rule->apps))
|
||||
{
|
||||
ptr_rule->is_enabled = FALSE;
|
||||
ptr_rule->is_haveerrors = FALSE;
|
||||
|
||||
+794
@@ -0,0 +1,794 @@
|
||||
// simplewall
|
||||
// Copyright (c) 2026 Henry++
|
||||
// Copyright (c) 2026 Tarkiin
|
||||
// UDP events contain metadata only; no packet payload is captured or stored
|
||||
#include "global.h"
|
||||
|
||||
FORCEINLINE static ULONG udp_bucket (
|
||||
_In_ ULONG pid,
|
||||
_In_ USHORT port
|
||||
)
|
||||
{
|
||||
return (pid ^ port) % UDP_BUCKETS;
|
||||
}
|
||||
|
||||
static VOID udp_initialize_properties (
|
||||
_Out_ PUDP_TRACE_PROPERTIES buffer
|
||||
)
|
||||
{
|
||||
RtlZeroMemory (buffer, sizeof (UDP_TRACE_PROPERTIES));
|
||||
|
||||
buffer->properties.Wnode.BufferSize = sizeof (UDP_TRACE_PROPERTIES);
|
||||
buffer->properties.Wnode.Guid = udp_session;
|
||||
buffer->properties.Wnode.ClientContext = 1; // QPC; ProcessTrace converts to FILETIME
|
||||
buffer->properties.Wnode.Flags = WNODE_FLAG_TRACED_GUID;
|
||||
buffer->properties.BufferSize = 64;
|
||||
//buffer->properties.MinimumBuffers = 0; // already 0
|
||||
buffer->properties.MaximumBuffers = 128;
|
||||
buffer->properties.FlushTimer = 1;
|
||||
buffer->properties.LogFileMode = EVENT_TRACE_REAL_TIME_MODE;
|
||||
buffer->properties.LoggerNameOffset = FIELD_OFFSET (UDP_TRACE_PROPERTIES, name);
|
||||
}
|
||||
|
||||
// select a bound socket, not a remote flow. UDP listeners may use wildcard addresses and IPv6 sockets may receive IPv4. never credit two rows for one event.
|
||||
static INT udp_match (
|
||||
_In_ const PUDP_ENDPOINT endpoint,
|
||||
_In_ ADDRESS_FAMILY af,
|
||||
_In_ const PBYTE address
|
||||
)
|
||||
{
|
||||
ULONG_PTR length;
|
||||
const BYTE mapped[12] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF};
|
||||
const BYTE zero[16] = {0};
|
||||
|
||||
if (endpoint->af == af)
|
||||
{
|
||||
length = (af == AF_INET) ? 4 : 16; // set correct sizes
|
||||
|
||||
if (RtlEqualMemory (endpoint->address, address, length))
|
||||
return 3;
|
||||
|
||||
if (RtlEqualMemory (endpoint->address, zero, length))
|
||||
return 2;
|
||||
}
|
||||
else if (af == AF_INET && endpoint->af == AF_INET6)
|
||||
{
|
||||
if (RtlEqualMemory (endpoint->address, mapped, 12) && !RtlEqualMemory (endpoint->address + 12, address, 4)) // set correct sizes
|
||||
return 2;
|
||||
|
||||
if (RtlEqualMemory (endpoint->address, zero, 16)) // set correct sizes
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static VOID udp_account (
|
||||
_In_ PSW_UDP_STATS stats,
|
||||
_In_ ULONG pid,
|
||||
_In_ ULONG size,
|
||||
_In_ USHORT port,
|
||||
_In_ ADDRESS_FAMILY af,
|
||||
_In_ const PBYTE address,
|
||||
_In_ ULONG scope_id,
|
||||
_In_ BOOLEAN is_receive,
|
||||
_In_ ULONG64 timestamp,
|
||||
_In_ ULONG error_code
|
||||
)
|
||||
{
|
||||
UDP_ENTRY *best = NULL, *entry;
|
||||
INT candidate, score = 0;
|
||||
BOOLEAN is_ambiguous = FALSE;
|
||||
|
||||
AcquireSRWLockExclusive (&stats->lock);
|
||||
|
||||
for (entry = stats->buckets[udp_bucket (pid, port)]; entry; entry = entry->next)
|
||||
{
|
||||
if (entry->endpoint.pid != pid || entry->endpoint.port != port)
|
||||
continue;
|
||||
|
||||
if (af == AF_INET6 && scope_id != MAXDWORD && entry->endpoint.scope_id != scope_id)
|
||||
continue;
|
||||
|
||||
candidate = udp_match (&entry->endpoint, af, address);
|
||||
|
||||
if (candidate > score)
|
||||
{
|
||||
best = entry;
|
||||
score = candidate;
|
||||
is_ambiguous = FALSE;
|
||||
}
|
||||
else if (candidate && candidate == score)
|
||||
{
|
||||
is_ambiguous = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
if (best && !is_ambiguous && timestamp >= best->since)
|
||||
{
|
||||
if (error_code != ERROR_SUCCESS)
|
||||
best->error_code = error_code;
|
||||
|
||||
best->is_observed = TRUE;
|
||||
|
||||
if (is_receive)
|
||||
{
|
||||
best->received += size;
|
||||
}
|
||||
else
|
||||
{
|
||||
best->sent += size;
|
||||
}
|
||||
}
|
||||
else if (is_ambiguous)
|
||||
{
|
||||
// never silently attribute an event to one of several equally good rows
|
||||
for (entry = stats->buckets[udp_bucket (pid, port)]; entry; entry = entry->next)
|
||||
{
|
||||
if (entry->endpoint.pid == pid && entry->endpoint.port == port && udp_match (&entry->endpoint, af, address) == score)
|
||||
entry->error_code = ERROR_INVALID_DATA;
|
||||
}
|
||||
}
|
||||
|
||||
ReleaseSRWLockExclusive (&stats->lock);
|
||||
}
|
||||
|
||||
static ULONG udp_u32 (
|
||||
_In_ const PBYTE data
|
||||
)
|
||||
{
|
||||
ULONG value;
|
||||
|
||||
RtlCopyMemory (&value, data, sizeof (ULONG));
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
static VOID udp_afd_event (
|
||||
_In_ PSW_UDP_STATS stats,
|
||||
_In_ PEVENT_RECORD event
|
||||
)
|
||||
{
|
||||
UDP_AFD_SOCKET **link, *socket;
|
||||
ULONG64 handle = 0;
|
||||
ULONG pointer_size = (event->EventHeader.Flags & EVENT_HEADER_FLAG_32_BIT_HEADER) ? sizeof (ULONG) : sizeof (ULONG64), prefix = 8 + 2 * pointer_size, length, size_offset;
|
||||
USHORT af, port, id = event->EventHeader.EventDescriptor.Id;
|
||||
const PBYTE data = (const PBYTE)(event->UserData);
|
||||
BOOLEAN is_receive = id == 1004 || id == 1006 || id == 1009 || id == 1012 || id == 1015;
|
||||
BOOLEAN is_transfer = is_receive || id == 1003 || id == 1005 || id == 1007 || id == 1011 || id == 1013;
|
||||
|
||||
// RIO uses a different completion path. mark just that socket unavailable.
|
||||
if (id == 4006)
|
||||
{
|
||||
if (event->EventHeader.EventDescriptor.Version != 0 || !data || event->UserDataLength < pointer_size)
|
||||
goto unsupported;
|
||||
|
||||
RtlCopyMemory (&handle, data, pointer_size);
|
||||
|
||||
for (socket = stats->sockets[(handle >> 4) % UDP_BUCKETS]; socket; socket = socket->next)
|
||||
{
|
||||
if (socket->handle == handle)
|
||||
{
|
||||
socket->is_unsupported = TRUE;
|
||||
|
||||
if (socket->is_bound)
|
||||
{
|
||||
udp_account (
|
||||
stats,
|
||||
socket->endpoint.pid,
|
||||
0,
|
||||
socket->endpoint.port,
|
||||
socket->endpoint.af,
|
||||
socket->endpoint.address,
|
||||
socket->endpoint.scope_id,
|
||||
FALSE,
|
||||
event->EventHeader.TimeStamp.QuadPart,
|
||||
ERROR_NOT_SUPPORTED
|
||||
);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (id != 1000 && id != 1001 && id != 1002 && id != 1030 && !is_transfer)
|
||||
return;
|
||||
|
||||
if (event->EventHeader.EventDescriptor.Version != 0 || !data || event->UserDataLength < prefix)
|
||||
goto unsupported;
|
||||
|
||||
RtlCopyMemory (&handle, data + 8 + pointer_size, pointer_size);
|
||||
|
||||
link = &stats->sockets[(handle >> 4) % UDP_BUCKETS];
|
||||
|
||||
while (*link && (*link)->handle != handle)
|
||||
{
|
||||
link = &(*link)->next;
|
||||
}
|
||||
|
||||
socket = *link;
|
||||
|
||||
if ((id == 1001 || id == 1002) && udp_u32 (data) == 0)
|
||||
{
|
||||
if (socket)
|
||||
{
|
||||
*link = socket->next;
|
||||
|
||||
stats->socket_count -= 1;
|
||||
|
||||
_r_mem_free (socket);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (id == 1000 && udp_u32 (data) == 0)
|
||||
{
|
||||
if (event->UserDataLength < prefix + 12 + pointer_size + 4)
|
||||
goto unsupported;
|
||||
|
||||
// kernel endpoint addresses are reused, including by TCP sockets
|
||||
if (socket)
|
||||
{
|
||||
*link = socket->next;
|
||||
|
||||
stats->socket_count -= 1;
|
||||
|
||||
_r_mem_free (socket);
|
||||
|
||||
socket = NULL;
|
||||
}
|
||||
|
||||
if (udp_u32 (data + prefix + 4) != SOCK_DGRAM || udp_u32 (data + prefix + 8) != IPPROTO_UDP)
|
||||
return;
|
||||
|
||||
if (!socket)
|
||||
{
|
||||
if (stats->socket_count >= UDP_MAX_ENDPOINTS)
|
||||
{
|
||||
_InterlockedExchange (&stats->error_code, ERROR_NOT_ENOUGH_MEMORY);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
socket = (UDP_AFD_SOCKET *)_r_mem_allocatesafe (sizeof (UDP_AFD_SOCKET));
|
||||
|
||||
if (!socket)
|
||||
{
|
||||
_InterlockedExchange (&stats->error_code, ERROR_NOT_ENOUGH_MEMORY);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
socket->next = *link;
|
||||
|
||||
*link = socket;
|
||||
|
||||
stats->socket_count += 1;
|
||||
}
|
||||
|
||||
socket->handle = handle;
|
||||
socket->is_bound = FALSE;
|
||||
|
||||
RtlZeroMemory (&socket->endpoint, sizeof (UDP_ENDPOINT));
|
||||
|
||||
socket->endpoint.pid = udp_u32 (data + prefix + 12);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!socket || udp_u32 (data) != 1)
|
||||
return;
|
||||
|
||||
if (id == 1030)
|
||||
{
|
||||
if (event->UserDataLength < prefix + 8)
|
||||
goto unsupported;
|
||||
|
||||
if (udp_u32 (data + prefix) != ERROR_SUCCESS)
|
||||
return;
|
||||
|
||||
length = udp_u32 (data + prefix + 4);
|
||||
|
||||
if (length > event->UserDataLength - prefix - 8 || length < 4)
|
||||
goto unsupported;
|
||||
|
||||
RtlCopyMemory (&af, data + prefix + 8, 2);
|
||||
RtlCopyMemory (&port, data + prefix + 10, 2);
|
||||
|
||||
if ((af != AF_INET && af != AF_INET6) || length < (af == AF_INET ? 16U : 28U))
|
||||
goto unsupported;
|
||||
|
||||
socket->endpoint.af = af;
|
||||
socket->endpoint.port = (USHORT)((port >> 8) | (port << 8));
|
||||
|
||||
RtlCopyMemory (socket->endpoint.address, data + prefix + (af == AF_INET ? 12 : 16), af == AF_INET ? 4 : 16);
|
||||
|
||||
socket->endpoint.scope_id = (af == AF_INET6) ? udp_u32 (data + prefix + 32) : 0;
|
||||
socket->is_bound = socket->endpoint.port != 0;
|
||||
|
||||
if (socket->is_bound && socket->is_unsupported)
|
||||
{
|
||||
udp_account (
|
||||
stats,
|
||||
socket->endpoint.pid,
|
||||
0,
|
||||
socket->endpoint.port,
|
||||
af,
|
||||
socket->endpoint.address,
|
||||
socket->endpoint.scope_id,
|
||||
FALSE,
|
||||
event->EventHeader.TimeStamp.QuadPart,
|
||||
ERROR_NOT_SUPPORTED
|
||||
);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (is_transfer && socket->is_bound)
|
||||
{
|
||||
size_offset = prefix + 4 + pointer_size;
|
||||
|
||||
if (event->UserDataLength < size_offset + 8)
|
||||
goto unsupported;
|
||||
|
||||
if (udp_u32 (data + size_offset + 4) != ERROR_SUCCESS)
|
||||
return;
|
||||
|
||||
udp_account (
|
||||
stats,
|
||||
socket->endpoint.pid,
|
||||
udp_u32 (data + size_offset),
|
||||
socket->endpoint.port,
|
||||
socket->endpoint.af,
|
||||
socket->endpoint.address,
|
||||
socket->endpoint.scope_id,
|
||||
is_receive,
|
||||
event->EventHeader.TimeStamp.QuadPart,
|
||||
socket->is_unsupported ? ERROR_NOT_SUPPORTED : ERROR_SUCCESS
|
||||
);
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
unsupported:
|
||||
|
||||
_InterlockedExchange (&stats->error_code, ERROR_NOT_SUPPORTED);
|
||||
}
|
||||
|
||||
static VOID WINAPI udp_event (
|
||||
_In_ PEVENT_RECORD event
|
||||
)
|
||||
{
|
||||
PSW_UDP_STATS stats = event->UserContext;
|
||||
#if defined(UDP_STATS_DIAGNOSTIC)
|
||||
UDP_STATS_DIAGNOSTIC (event);
|
||||
#endif // UDP_STATS_DIAGNOSTIC
|
||||
|
||||
if (_InterlockedCompareExchange (&stats->stopping, 0, 0))
|
||||
return;
|
||||
|
||||
if (IsEqualGUID (&event->EventHeader.ProviderId, &afd_provider))
|
||||
udp_afd_event (stats, event);
|
||||
}
|
||||
|
||||
static ULONG WINAPI udp_buffer (
|
||||
_In_ PEVENT_TRACE_LOGFILEW buffer
|
||||
)
|
||||
{
|
||||
PSW_UDP_STATS stats = (PSW_UDP_STATS)buffer->Context;
|
||||
|
||||
if (buffer->EventsLost)
|
||||
_InterlockedExchange (&stats->error_code, ERROR_DATA_NOT_ACCEPTED);
|
||||
|
||||
return !_InterlockedCompareExchange (&stats->stopping, 0, 0);
|
||||
}
|
||||
|
||||
static VOID NTAPI udp_thread (
|
||||
_In_ PVOID context
|
||||
)
|
||||
{
|
||||
PSW_UDP_STATS stats = (PSW_UDP_STATS)context;
|
||||
ULONG result;
|
||||
|
||||
result = ProcessTrace (&stats->hconsumer, 1, NULL, NULL);
|
||||
|
||||
if (!_InterlockedCompareExchange (&stats->stopping, 0, 0))
|
||||
_InterlockedExchange (&stats->error_code, result ? result : ERROR_OPERATION_ABORTED);
|
||||
}
|
||||
|
||||
_Ret_maybenull_
|
||||
PSW_UDP_STATS udp_stats_create ()
|
||||
{
|
||||
PSW_UDP_STATS stats;
|
||||
|
||||
stats = (PSW_UDP_STATS)_r_mem_allocatesafe (sizeof (SW_UDP_STATS));
|
||||
|
||||
if (stats)
|
||||
{
|
||||
stats->hconsumer = INVALID_PROCESSTRACE_HANDLE;
|
||||
stats->error_code = ERROR_NOT_READY;
|
||||
}
|
||||
|
||||
return stats;
|
||||
}
|
||||
|
||||
NTSTATUS udp_stats_start (
|
||||
_Inout_opt_ PSW_UDP_STATS stats
|
||||
)
|
||||
{
|
||||
EVENT_TRACE_LOGFILEW logfile = {0};
|
||||
UDP_TRACE_PROPERTIES properties;
|
||||
OBJECT_ATTRIBUTES oa = {0};
|
||||
R_ENVIRONMENT environment;
|
||||
UNICODE_STRING us;
|
||||
WCHAR buffer[0x80];
|
||||
TRACEHANDLE hsession = 0;
|
||||
NTSTATUS status;
|
||||
|
||||
if (!stats)
|
||||
return STATUS_MEMORY_NOT_ALLOCATED;
|
||||
|
||||
if (stats->hguard || _InterlockedCompareExchange (&stats->stopping, 0, 0))
|
||||
return STATUS_ALREADY_INITIALIZED;
|
||||
|
||||
// a global semaphore distinguishes an orphan left by a crash from an active simplewall instance. never stop another tracing application's session.
|
||||
_r_str_printf (buffer, RTL_NUMBER_OF (buffer), L"\\Sessions\\%u\\BaseNamedObjects\\%s", NtCurrentPeb ()->SessionId, UDP_SESSION_SEMAPHORE);
|
||||
|
||||
_r_obj_initializeunicodestring (&us, buffer);
|
||||
|
||||
InitializeObjectAttributes (&oa, &us, OBJ_CASE_INSENSITIVE | OBJ_OPENIF, NULL, NULL);
|
||||
|
||||
status = NtCreateSemaphore (&stats->hguard, SEMAPHORE_ALL_ACCESS, &oa, 1, 1);
|
||||
|
||||
if (NT_SUCCESS (status) || status == STATUS_OBJECT_NAME_COLLISION)
|
||||
{
|
||||
status = _r_sys_waitforsingleobject (stats->hguard, 0);
|
||||
|
||||
stats->is_owns_guard = (status == STATUS_WAIT_0);
|
||||
|
||||
status = stats->is_owns_guard ? STATUS_SUCCESS : STATUS_ALREADY_INITIALIZED;
|
||||
}
|
||||
else
|
||||
{
|
||||
stats->hguard = NULL;
|
||||
|
||||
goto fail;
|
||||
}
|
||||
|
||||
udp_initialize_properties (&properties);
|
||||
|
||||
status = StartTraceW (&hsession, UDP_SESSION_NAME, &properties.properties);
|
||||
|
||||
if (status == ERROR_ALREADY_EXISTS)
|
||||
{
|
||||
udp_initialize_properties (&properties);
|
||||
|
||||
status = ControlTraceW (0, UDP_SESSION_NAME, &properties.properties, EVENT_TRACE_CONTROL_QUERY);
|
||||
|
||||
if (status == ERROR_SUCCESS && IsEqualGUID (&properties.properties.Wnode.Guid, &udp_session))
|
||||
{
|
||||
status = ControlTraceW (0, UDP_SESSION_NAME, &properties.properties, EVENT_TRACE_CONTROL_STOP);
|
||||
|
||||
if (status == ERROR_SUCCESS)
|
||||
{
|
||||
udp_initialize_properties (&properties);
|
||||
|
||||
status = StartTraceW (&hsession, UDP_SESSION_NAME, &properties.properties);
|
||||
}
|
||||
}
|
||||
else if (status == ERROR_SUCCESS)
|
||||
{
|
||||
status = STATUS_ALREADY_INITIALIZED;
|
||||
}
|
||||
}
|
||||
|
||||
if (status != STATUS_SUCCESS)
|
||||
goto fail;
|
||||
|
||||
stats->hsession = hsession;
|
||||
|
||||
// DATAGRAM plus RIO lifecycle metadata; no verbose packet-buffer events
|
||||
status = EnableTraceEx2 (hsession, &afd_provider, EVENT_CONTROL_CODE_ENABLE_PROVIDER, TRACE_LEVEL_INFORMATION, 0x41, 0, 0, NULL);
|
||||
|
||||
if (status != STATUS_SUCCESS)
|
||||
{
|
||||
status = _r_sys_doserrortontstatus (status);
|
||||
|
||||
goto fail;
|
||||
}
|
||||
|
||||
logfile.ProcessTraceMode = PROCESS_TRACE_MODE_REAL_TIME | PROCESS_TRACE_MODE_EVENT_RECORD;
|
||||
logfile.LoggerName = UDP_SESSION_NAME;
|
||||
logfile.EventRecordCallback = &udp_event;
|
||||
logfile.BufferCallback = &udp_buffer;
|
||||
logfile.Context = stats;
|
||||
|
||||
stats->hconsumer = OpenTraceW (&logfile);
|
||||
|
||||
if (stats->hconsumer == INVALID_PROCESSTRACE_HANDLE)
|
||||
{
|
||||
status = _r_sys_doserrortontstatus (NtLastError ());
|
||||
|
||||
goto fail;
|
||||
}
|
||||
|
||||
_InterlockedExchange (&stats->error_code, STATUS_SUCCESS);
|
||||
|
||||
_r_sys_setenvironment (&environment, THREAD_PRIORITY_ABOVE_NORMAL, IoPriorityHigh, MEMORY_PRIORITY_NORMAL);
|
||||
|
||||
status = _r_sys_createthread (&stats->hthread, NtCurrentProcess (), &udp_thread, stats, &environment, L"UdpMonitoring");
|
||||
|
||||
if (!NT_SUCCESS (status))
|
||||
goto fail;
|
||||
|
||||
NtResumeThread (stats->hthread, NULL);
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
|
||||
fail:
|
||||
|
||||
udp_stats_stop (stats);
|
||||
|
||||
_InterlockedExchange (&stats->error_code, status);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
VOID udp_stats_stop (
|
||||
_In_opt_ PSW_UDP_STATS stats
|
||||
)
|
||||
{
|
||||
UDP_TRACE_PROPERTIES properties;
|
||||
|
||||
if (!stats)
|
||||
return;
|
||||
|
||||
AcquireSRWLockExclusive (&stats->control_lock);
|
||||
|
||||
_InterlockedExchange (&stats->error_code, ERROR_OPERATION_ABORTED);
|
||||
_InterlockedExchange (&stats->stopping, TRUE);
|
||||
|
||||
if (stats->hsession)
|
||||
{
|
||||
udp_initialize_properties (&properties);
|
||||
|
||||
ControlTraceW (stats->hsession, NULL, &properties.properties, EVENT_TRACE_CONTROL_STOP);
|
||||
|
||||
stats->hsession = 0;
|
||||
}
|
||||
|
||||
if (stats->hconsumer != INVALID_PROCESSTRACE_HANDLE)
|
||||
CloseTrace (stats->hconsumer);
|
||||
|
||||
if (stats->hthread)
|
||||
{
|
||||
_r_sys_waitforsingleobject (stats->hthread, INFINITE);
|
||||
|
||||
NtClose (stats->hthread);
|
||||
|
||||
stats->hthread = NULL;
|
||||
}
|
||||
|
||||
stats->hconsumer = INVALID_PROCESSTRACE_HANDLE;
|
||||
|
||||
if (stats->hguard)
|
||||
{
|
||||
if (stats->is_owns_guard)
|
||||
NtReleaseSemaphore (stats->hguard, 1, NULL);
|
||||
|
||||
NtClose (stats->hguard);
|
||||
stats->hguard = NULL;
|
||||
|
||||
stats->is_owns_guard = FALSE;
|
||||
}
|
||||
|
||||
ReleaseSRWLockExclusive (&stats->control_lock);
|
||||
}
|
||||
|
||||
VOID udp_stats_destroy (
|
||||
_In_opt_ PSW_UDP_STATS stats
|
||||
)
|
||||
{
|
||||
UDP_AFD_SOCKET *next, *socket;
|
||||
UDP_ENTRY *entry, *next_entry;
|
||||
|
||||
if (!stats)
|
||||
return;
|
||||
|
||||
udp_stats_stop (stats);
|
||||
|
||||
for (ULONG i = 0; i < UDP_BUCKETS; i++)
|
||||
{
|
||||
socket = stats->sockets[i];
|
||||
|
||||
while (socket)
|
||||
{
|
||||
next = socket->next;
|
||||
|
||||
_r_mem_free (socket);
|
||||
|
||||
socket = next;
|
||||
}
|
||||
|
||||
entry = stats->buckets[i];
|
||||
|
||||
while (entry)
|
||||
{
|
||||
next_entry = entry->next;
|
||||
|
||||
_r_mem_free (entry);
|
||||
|
||||
entry = next_entry;
|
||||
}
|
||||
}
|
||||
|
||||
_r_mem_free (stats);
|
||||
}
|
||||
|
||||
ULONG udp_stats_poll (
|
||||
_In_opt_ PSW_UDP_STATS stats
|
||||
)
|
||||
{
|
||||
UDP_TRACE_PROPERTIES properties;
|
||||
ULONG status;
|
||||
|
||||
if (!stats)
|
||||
return ERROR_NOT_READY;
|
||||
|
||||
AcquireSRWLockExclusive (&stats->control_lock);
|
||||
|
||||
status = _InterlockedCompareExchange (&stats->error_code, 0, 0);
|
||||
|
||||
if (status == ERROR_SUCCESS && stats->hsession)
|
||||
{
|
||||
udp_initialize_properties (&properties);
|
||||
|
||||
status = ControlTraceW (stats->hsession, NULL, &properties.properties, EVENT_TRACE_CONTROL_QUERY);
|
||||
|
||||
if (status == ERROR_SUCCESS && (properties.properties.EventsLost || properties.properties.RealTimeBuffersLost || properties.properties.LogBuffersLost))
|
||||
status = ERROR_DATA_NOT_ACCEPTED;
|
||||
|
||||
if (status != ERROR_SUCCESS)
|
||||
_InterlockedExchange (&stats->error_code, status);
|
||||
}
|
||||
|
||||
ReleaseSRWLockExclusive (&stats->control_lock);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
VOID udp_stats_begin_refresh (
|
||||
_Inout_opt_ PSW_UDP_STATS stats
|
||||
)
|
||||
{
|
||||
if (!stats)
|
||||
return;
|
||||
|
||||
AcquireSRWLockExclusive (&stats->lock);
|
||||
stats->epoch += 1;
|
||||
ReleaseSRWLockExclusive (&stats->lock);
|
||||
}
|
||||
|
||||
VOID udp_stats_read (
|
||||
_Inout_ PSW_UDP_STATS stats,
|
||||
_In_ PUDP_ENDPOINT endpoint,
|
||||
_Out_ PUDP_SNAPSHOT snapshot
|
||||
)
|
||||
{
|
||||
LARGE_INTEGER li;
|
||||
UDP_ENTRY *entry;
|
||||
ULONG bucket;
|
||||
|
||||
RtlZeroMemory (snapshot, sizeof (UDP_SNAPSHOT));
|
||||
|
||||
snapshot->error_code = stats ? _InterlockedCompareExchange (&stats->error_code, 0, 0) : ERROR_NOT_READY;
|
||||
|
||||
if (snapshot->error_code != ERROR_SUCCESS)
|
||||
return;
|
||||
|
||||
bucket = udp_bucket (endpoint->pid, endpoint->port);
|
||||
|
||||
AcquireSRWLockExclusive (&stats->lock);
|
||||
|
||||
for (entry = stats->buckets[bucket]; entry; entry = entry->next)
|
||||
{
|
||||
if (entry->endpoint.pid == endpoint->pid && entry->endpoint.port == endpoint->port && entry->endpoint.af == endpoint->af &&
|
||||
entry->endpoint.scope_id == endpoint->scope_id && RtlEqualMemory (entry->endpoint.address, endpoint->address, endpoint->af == AF_INET ? 4 : 16))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!entry)
|
||||
{
|
||||
if (stats->count < UDP_MAX_ENDPOINTS)
|
||||
entry = (PUDP_ENTRY)_r_mem_allocatesafe (sizeof (UDP_ENTRY));
|
||||
|
||||
if (!entry)
|
||||
{
|
||||
snapshot->error_code = ERROR_NOT_ENOUGH_MEMORY;
|
||||
|
||||
ReleaseSRWLockExclusive (&stats->lock);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
entry->next = stats->buckets[bucket];
|
||||
stats->buckets[bucket] = entry;
|
||||
stats->count += 1;
|
||||
}
|
||||
|
||||
if (!entry->since || entry->endpoint.created != endpoint->created)
|
||||
{
|
||||
entry->endpoint = *endpoint;
|
||||
entry->since = _r_sys_gettimestamp (&li)->QuadPart;
|
||||
|
||||
if (endpoint->created > entry->since)
|
||||
entry->since = endpoint->created;
|
||||
|
||||
entry->received = entry->sent = 0;
|
||||
entry->error_code = ERROR_SUCCESS;
|
||||
entry->is_observed = FALSE;
|
||||
}
|
||||
|
||||
snapshot->error_code = entry->error_code ? entry->error_code : (entry->is_observed ? ERROR_SUCCESS : ERROR_NOT_READY);
|
||||
snapshot->received = entry->received;
|
||||
snapshot->sent = entry->sent;
|
||||
entry->epoch = stats->epoch;
|
||||
|
||||
ReleaseSRWLockExclusive (&stats->lock);
|
||||
}
|
||||
|
||||
VOID udp_stats_end_refresh (
|
||||
_In_opt_ SW_UDP_STATS *stats,
|
||||
_In_ BOOLEAN ipv4_complete,
|
||||
_In_ BOOLEAN ipv6_complete
|
||||
)
|
||||
{
|
||||
UDP_ENTRY *entry, *next, *previous;
|
||||
|
||||
if (!stats)
|
||||
return;
|
||||
|
||||
AcquireSRWLockExclusive (&stats->lock);
|
||||
|
||||
for (ULONG i = 0; i < UDP_BUCKETS; i++)
|
||||
{
|
||||
entry = stats->buckets[i];
|
||||
previous = NULL;
|
||||
|
||||
while (entry)
|
||||
{
|
||||
next = entry->next;
|
||||
|
||||
if (entry->epoch != stats->epoch && (entry->endpoint.af == AF_INET ? ipv4_complete : ipv6_complete))
|
||||
{
|
||||
if (previous)
|
||||
{
|
||||
previous->next = next;
|
||||
}
|
||||
else
|
||||
{
|
||||
stats->buckets[i] = next;
|
||||
}
|
||||
|
||||
_r_mem_free (entry);
|
||||
|
||||
stats->count -= 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
previous = entry;
|
||||
}
|
||||
|
||||
entry = next;
|
||||
}
|
||||
}
|
||||
|
||||
ReleaseSRWLockExclusive (&stats->lock);
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
// simplewall
|
||||
// Copyright (c) 2026 Henry++
|
||||
// Copyright (c) 2026 Tarkiin
|
||||
// UDP events contain metadata only; no packet payload is captured or stored
|
||||
#pragma once
|
||||
|
||||
#include "global.h"
|
||||
|
||||
static const GUID afd_provider = {0xE53C6823, 0x7BB8, 0x44BB, {0x90, 0xDC, 0x3F, 0x86, 0x09, 0x0D, 0x48, 0xA6}};
|
||||
static const GUID udp_session = {0x4BFA58D6, 0x5D5D, 0x46F2, {0x93, 0x93, 0xC9, 0xE0, 0x5E, 0x27, 0xB4, 0x71}};
|
||||
|
||||
_Ret_maybenull_
|
||||
PSW_UDP_STATS udp_stats_create ();
|
||||
|
||||
NTSTATUS udp_stats_start (
|
||||
_Inout_opt_ PSW_UDP_STATS stats
|
||||
);
|
||||
|
||||
VOID udp_stats_stop (
|
||||
_In_opt_ PSW_UDP_STATS stats
|
||||
);
|
||||
|
||||
VOID udp_stats_destroy (
|
||||
_In_opt_ PSW_UDP_STATS stats
|
||||
);
|
||||
|
||||
ULONG udp_stats_poll (
|
||||
_In_opt_ PSW_UDP_STATS stats
|
||||
);
|
||||
|
||||
VOID udp_stats_begin_refresh (
|
||||
_Inout_opt_ PSW_UDP_STATS stats
|
||||
);
|
||||
|
||||
VOID udp_stats_read (
|
||||
_Inout_ PSW_UDP_STATS stats,
|
||||
_In_ PUDP_ENDPOINT endpoint,
|
||||
_Out_ PUDP_SNAPSHOT snapshot
|
||||
);
|
||||
|
||||
VOID udp_stats_end_refresh (
|
||||
_In_opt_ SW_UDP_STATS *stats,
|
||||
_In_ BOOLEAN ipv4_complete,
|
||||
_In_ BOOLEAN ipv6_complete
|
||||
);
|
||||
Reference in new issue
Block a user