implement correct formatted #2143

This commit is contained in:
henrypp committed 2026-09-18 15:41:55 +05:00
1 parent 33bb259574
commit 482893bcd8
12 files changed
+1151 -39

No files matched your search

+2
View File
@@ -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" />
+6
View File
@@ -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
View File
@@ -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 (
+3
View File
@@ -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
View File
@@ -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
View File
@@ -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;
+15
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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);
}
+45
View File
@@ -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
);