diff --git a/Common/Common.csproj b/Common/Common.csproj
index 3fe4b02..c68a5be 100644
--- a/Common/Common.csproj
+++ b/Common/Common.csproj
@@ -13,7 +13,14 @@
Wokhan Solutions
..\bin\$(ConfigurationName)
Enable
+ True
+
+
+
+
+
+
@@ -28,6 +35,9 @@
+
+ All
+
diff --git a/Common/IO/Files/NativeMethods.txt b/Common/IO/Files/NativeMethods.txt
new file mode 100644
index 0000000..f5177c0
--- /dev/null
+++ b/Common/IO/Files/NativeMethods.txt
@@ -0,0 +1 @@
+QueryDosDevice
\ No newline at end of file
diff --git a/Common/IO/Files/PathResolver.NativeMethods.cs b/Common/IO/Files/PathResolver.NativeMethods.cs
deleted file mode 100644
index 00b2962..0000000
--- a/Common/IO/Files/PathResolver.NativeMethods.cs
+++ /dev/null
@@ -1,13 +0,0 @@
-using System.Runtime.InteropServices;
-using System.Text;
-
-namespace Wokhan.WindowsFirewallNotifier.Common.IO.Files;
-
-public static partial class PathResolver
-{
- protected static partial class NativeMethods
- {
- [LibraryImport("kernel32.dll", SetLastError = true, StringMarshalling = StringMarshalling.Utf16)]
- internal static unsafe partial uint QueryDosDeviceW(string lpDeviceName, char* lpTargetPath, uint ucchMax);
- }
-}
diff --git a/Common/IO/Files/PathResolver.cs b/Common/IO/Files/PathResolver.cs
index b7f7706..d0b288b 100644
--- a/Common/IO/Files/PathResolver.cs
+++ b/Common/IO/Files/PathResolver.cs
@@ -5,6 +5,9 @@
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
+
+using Windows.Win32;
+
using Wokhan.WindowsFirewallNotifier.Common.Logging;
namespace Wokhan.WindowsFirewallNotifier.Common.IO.Files;
@@ -33,7 +36,7 @@ private static void InitDriveMapping()
foreach (var drive in drives)
{
trimmedDrive = drive.TrimEnd('\\');
- if (NativeMethods.QueryDosDeviceW(trimmedDrive, sb, (uint)len) == 0)
+ if (NativeMethods.QueryDosDevice(trimmedDrive, sb, (uint)len) == 0)
{
throw new Win32Exception(Marshal.GetLastWin32Error(), "Call to QueryDosDevice failed!");
}
diff --git a/Common/NativeMethods.json b/Common/NativeMethods.json
new file mode 100644
index 0000000..f67052a
--- /dev/null
+++ b/Common/NativeMethods.json
@@ -0,0 +1,7 @@
+{
+ "$schema": "https://aka.ms/CsWin32.schema.json",
+ "emitSingleFile": false,
+ "className": "NativeMethods",
+ "multiTargetingFriendlyAPIs": false,
+ "public": false
+}
\ No newline at end of file
diff --git a/Common/Net/IP/AF_INET.cs b/Common/Net/IP/AF_INET.cs
index 19d2099..e9c9769 100644
--- a/Common/Net/IP/AF_INET.cs
+++ b/Common/Net/IP/AF_INET.cs
@@ -2,9 +2,9 @@
public abstract partial class IPHelper
{
- internal enum AF_INET
+ internal class AF_INET
{
- IP4 = 2,
- IP6 = 23
+ internal const uint IP4 = 2;
+ internal const uint IP6 = 23;
}
}
diff --git a/Common/Net/IP/BaseTcpTableOwnerModule.cs b/Common/Net/IP/BaseTcpTableOwnerModule.cs
deleted file mode 100644
index 11a5f2f..0000000
--- a/Common/Net/IP/BaseTcpTableOwnerModule.cs
+++ /dev/null
@@ -1,6 +0,0 @@
-namespace Wokhan.WindowsFirewallNotifier.Common.Net.IP;
-
-internal struct BaseTcpTableOwnerModule
-{
- public uint NumEntries;
-}
diff --git a/Common/Net/IP/Connection.cs b/Common/Net/IP/Connection.cs
new file mode 100644
index 0000000..be64239
--- /dev/null
+++ b/Common/Net/IP/Connection.cs
@@ -0,0 +1,241 @@
+using System;
+using System.ComponentModel;
+using System.Net;
+using System.Runtime.InteropServices;
+
+using Windows.Win32;
+using Windows.Win32.NetworkManagement.IpHelper;
+
+using Wokhan.WindowsFirewallNotifier.Common.Logging;
+
+namespace Wokhan.WindowsFirewallNotifier.Common.Net.IP;
+
+public class Connection
+{
+ private const uint NO_ERROR = 0;
+ private const uint ERROR_INSUFFICIENT_BUFFER = 122;
+ private const uint ERROR_NOT_FOUND = 1168;
+
+ public IPAddress RemoteAddress { get; private set; } = IPAddress.None;
+
+ public int RemotePort { get; private set; } = -1;
+
+ public IPAddress LocalAddress { get; private set; }
+
+ public int LocalPort { get; private set; }
+
+ public Owner? OwnerModule { get; private set; }
+
+ public string Protocol { get; init; } = "TCP";
+
+ public DateTime? CreationTime { get; init; }
+
+ public uint OwningPid { get; init; }
+
+ public ConnectionStatus State { get; private set; } = ConnectionStatus.NOT_APPLICABLE;
+
+ public bool IsLoopback { get; private set; }
+
+ private MIB_TCP6ROW tcp6MIBRow;
+
+ private IConnectionOwnerInfo sourceRow;
+
+ unsafe delegate uint GetOwnerModuleDelegate(object ROW, TCPIP_OWNER_MODULE_INFO_CLASS infoClass, void* buffer, ref int buffSize);
+
+ GetOwnerModuleDelegate getOwnerModule;
+
+ internal Connection(MIB_TCPROW_OWNER_MODULE tcpRow)
+ {
+ sourceRow = tcpRow;
+
+ OwningPid = tcpRow.dwOwningPid;
+ LocalAddress = new IPAddress(tcpRow.dwLocalAddr);
+ LocalPort = IPHelper.GetRealPort(tcpRow.dwLocalPort);
+ if (tcpRow.dwState != (uint)MIB_TCP_STATE.MIB_TCP_STATE_LISTEN)
+ {
+ RemoteAddress = new IPAddress(tcpRow.dwRemoteAddr);
+ RemotePort = IPHelper.GetRealPort(tcpRow.dwRemotePort);
+ }
+ OwnerModule = GetOwningModule();
+ State = (ConnectionStatus)tcpRow.dwState;
+ CreationTime = tcpRow.liCreateTimestamp == 0 ? null : DateTime.FromFileTime(tcpRow.liCreateTimestamp);
+ IsLoopback = IPAddress.IsLoopback(RemoteAddress);
+ }
+
+ internal Connection(MIB_TCP6ROW_OWNER_MODULE tcp6Row)
+ {
+ sourceRow = tcp6Row;
+
+ this.tcp6MIBRow = new MIB_TCP6ROW() { State = (MIB_TCP_STATE)tcp6Row.dwState, LocalAddr = new() { u = new() { Byte = tcp6Row.ucLocalAddr } }, RemoteAddr = new() { u = new() { Byte = tcp6Row.ucRemoteAddr } }, dwLocalPort = tcp6Row.dwLocalPort, dwRemotePort = tcp6Row.dwRemotePort };
+
+ OwningPid = tcp6Row.dwOwningPid;
+ LocalAddress = new IPAddress(tcp6Row.ucLocalAddr.AsSpan().ToArray());
+ LocalPort = IPHelper.GetRealPort(tcp6Row.dwLocalPort);
+ if (tcp6Row.dwState != (uint)MIB_TCP_STATE.MIB_TCP_STATE_LISTEN)
+ {
+ RemoteAddress = new IPAddress(tcp6Row.ucRemoteAddr.AsSpan().ToArray());
+ RemotePort = IPHelper.GetRealPort(tcp6Row.dwRemotePort);
+ }
+ OwnerModule = GetOwningModule();
+ State = (ConnectionStatus)tcp6Row.dwState;
+ CreationTime = tcp6Row.liCreateTimestamp == 0 ? null : DateTime.FromFileTime(tcp6Row.liCreateTimestamp);
+ IsLoopback = IPAddress.IsLoopback(RemoteAddress);
+ }
+
+ internal Connection(MIB_UDPROW_OWNER_MODULE udpRow)
+ {
+ sourceRow = udpRow;
+
+ OwningPid = udpRow.dwOwningPid;
+ LocalAddress = new IPAddress(udpRow.dwLocalAddr);
+ LocalPort = IPHelper.GetRealPort(udpRow.dwLocalPort);
+ OwnerModule = GetOwningModule();
+ Protocol = "UDP";
+ CreationTime = udpRow.liCreateTimestamp == 0 ? null : DateTime.FromFileTime(udpRow.liCreateTimestamp);
+ }
+
+ internal Connection(MIB_UDP6ROW_OWNER_MODULE udp6Row)
+ {
+ sourceRow = udp6Row;
+
+ OwningPid = udp6Row.dwOwningPid;
+ LocalAddress = new IPAddress(udp6Row.ucLocalAddr.AsSpan().ToArray());
+ LocalPort = IPHelper.GetRealPort(udp6Row.dwLocalPort);
+ OwnerModule = GetOwningModule();
+ Protocol = "UDP";
+ CreationTime = udp6Row.liCreateTimestamp == 0 ? null : DateTime.FromFileTime(udp6Row.liCreateTimestamp);
+ }
+
+ private bool EnsureStats(ref bool isAccessDenied)
+ {
+ if (Protocol != "TCP")
+ {
+ throw new InvalidOperationException("Statistics are not available for non-TCP connections. Please check first the connection's protocol.");
+ }
+
+ if (isAccessDenied || State != ConnectionStatus.ESTABLISHED || IPAddress.IsLoopback(RemoteAddress))
+ {
+ return false;
+ }
+
+ var result = new TCP_ESTATS_BANDWIDTH_RW_v0() { EnableCollectionInbound = TCP_BOOLEAN_OPTIONAL.TcpBoolOptEnabled, EnableCollectionOutbound = TCP_BOOLEAN_OPTIONAL.TcpBoolOptEnabled };
+ var r = sourceRow.SetPerTcpConnectionEStats(ref result, tcp6MIBRow);
+ if (r != 0)
+ {
+ throw new Win32Exception((int)r);
+ }
+
+ if (result.EnableCollectionInbound != TCP_BOOLEAN_OPTIONAL.TcpBoolOptEnabled || result.EnableCollectionOutbound != TCP_BOOLEAN_OPTIONAL.TcpBoolOptEnabled)
+ {
+ isAccessDenied = true;
+ return false;
+ }
+
+ return true;
+ }
+
+ ulong _lastInboundReadValue;
+ ulong _lastOutboundReadValue;
+
+ //TODO: not fond of those ref params, but using an interface prevents me to use local private fields - and using a property with a proper setter would result in a backing field creatino, breaking the initial struct layout.
+ public (ulong InboundBandwidth, ulong OutboundBandwidth) GetEstimatedBandwidth(ref bool isAccessDenied)
+ {
+ if (!EnsureStats(ref isAccessDenied))
+ {
+ _lastInboundReadValue = 0;
+ _lastOutboundReadValue = 0;
+
+ return (0, 0);
+ }
+
+ try
+ {
+ var rodObjectNullable = sourceRow.GetPerTcpConnectionEState(tcp6MIBRow);
+
+ if (rodObjectNullable is null)
+ {
+ isAccessDenied = true;
+ return (0, 0);
+ }
+
+ var rodObject = rodObjectNullable.Value;
+
+ // Fix according to https://docs.microsoft.com/en-us/windows/win32/api/iphlpapi/nf-iphlpapi-setpertcpconnectionestats
+ // One must subtract the previously read value to get the right one (as reenabling statistics doesn't work as before starting from Win 10 1709)
+ var inbound = rodObject.InboundBandwidth >= _lastInboundReadValue ? rodObject.InboundBandwidth - _lastInboundReadValue : rodObject.InboundBandwidth;
+ var outbound = rodObject.OutboundBandwidth >= _lastOutboundReadValue ? rodObject.OutboundBandwidth - _lastOutboundReadValue : rodObject.OutboundBandwidth;
+
+ _lastInboundReadValue = rodObject.InboundBandwidth;
+ _lastOutboundReadValue = rodObject.OutboundBandwidth;
+
+ return (inbound, outbound);
+ }
+ catch (Win32Exception we) when (we.NativeErrorCode == IPHelper.ERROR_NOT_FOUND)
+ {
+ _lastInboundReadValue = 0;
+ _lastOutboundReadValue = 0;
+
+ return (0, 0);
+ }
+ }
+
+
+ internal Owner? GetOwningModule()
+ {
+ if (OwningPid is 0 or 4)
+ {
+ return Owner.System;
+ }
+
+ Owner? ret = null;
+
+ var buffer = IntPtr.Zero;
+ try
+ {
+ // No need to set the proper size as it will be recomputed. See https://learn.microsoft.com/en-us/windows/win32/api/iphlpapi/nf-iphlpapi-getownermodulefromtcp6entry#remarks
+ // Meaning that we cannont get the right size from the structure alone, we need to know the exact size including the resulting strings...
+ uint buffSize = 0;
+
+ var retn = sourceRow.GetOwnerModule(IntPtr.Zero, ref buffSize);
+ if (retn != NO_ERROR && retn != ERROR_INSUFFICIENT_BUFFER)
+ {
+ //Cannot get owning module for this connection
+ LogHelper.Info("Unable to get the connection owner: ownerPid=" + OwningPid + " remoteAdr=" + RemoteAddress + ":" + RemotePort);
+ return ret;
+ }
+
+ if (buffSize == 0)
+ {
+ //No buffer? Probably means we can't retrieve any information about this connection; skip it
+ LogHelper.Info("Unable to get the connection owner (no buffer).");
+ return ret;
+ }
+
+ buffer = Marshal.AllocHGlobal((int)buffSize);
+
+ var resp = sourceRow.GetOwnerModule(buffer, ref buffSize);
+ if (resp == NO_ERROR)
+ {
+ var ownerInfo = Marshal.PtrToStructure(buffer);
+ ret = new Owner(ownerInfo.pModuleName.ToString(), ownerInfo.pModulePath.ToString());
+ }
+ else if (resp != ERROR_NOT_FOUND) // Ignore closed connections
+ {
+ LogHelper.Error("Unable to get the connection owner.", new Win32Exception((int)resp));
+ }
+
+ return ret;
+ }
+ catch (Exception e)
+ {
+ return new Owner("ERROR", "");
+ }
+ finally
+ {
+ if (buffer != IntPtr.Zero)
+ {
+ Marshal.FreeHGlobal(buffer);
+ }
+ }
+ }
+}
diff --git a/Common/Net/IP/IConnectionOwnerInfo.cs b/Common/Net/IP/IConnectionOwnerInfo.cs
index 8297543..7378183 100644
--- a/Common/Net/IP/IConnectionOwnerInfo.cs
+++ b/Common/Net/IP/IConnectionOwnerInfo.cs
@@ -1,25 +1,13 @@
using System;
-using Wokhan.WindowsFirewallNotifier.Common.Net.IP.TCP;
+using Windows.Win32.NetworkManagement.IpHelper;
namespace Wokhan.WindowsFirewallNotifier.Common.Net.IP;
public interface IConnectionOwnerInfo
{
- // CHANGE
- byte[] RemoteAddrBytes { get; }
-
- string RemoteAddress { get; }
- int RemotePort { get; }
- string LocalAddress { get; }
- int LocalPort { get; }
- Owner? OwnerModule { get; }
- string Protocol { get; }
- DateTime? CreationTime { get; }
- uint OwningPid { get; }
- ConnectionStatus State { get; }
- bool IsLoopback { get; }
-
- ITcpRow ToTcpRow();
+ internal uint SetPerTcpConnectionEStats(ref TCP_ESTATS_BANDWIDTH_RW_v0 rw, MIB_TCP6ROW? tcp6Row);
+ internal TCP_ESTATS_BANDWIDTH_ROD_v0? GetPerTcpConnectionEState(MIB_TCP6ROW? tcp6Row);
+ internal uint GetOwnerModule(IntPtr buffer, ref uint buffSize);
}
\ No newline at end of file
diff --git a/Common/Net/IP/IPHelper.NativeMethods.cs b/Common/Net/IP/IPHelper.NativeMethods.cs
deleted file mode 100644
index b84157d..0000000
--- a/Common/Net/IP/IPHelper.NativeMethods.cs
+++ /dev/null
@@ -1,11 +0,0 @@
-using System;
-using System.Runtime.InteropServices;
-
-namespace Wokhan.WindowsFirewallNotifier.Common.Net.IP;
-
-internal static partial class NativeMethods
-{
- [LibraryImport("kernel32.dll", SetLastError = false)]
- internal static partial void RtlZeroMemory(IntPtr dest, uint size);
-}
-
diff --git a/Common/Net/IP/IPHelper.cs b/Common/Net/IP/IPHelper.cs
index f59a742..5116a9e 100644
--- a/Common/Net/IP/IPHelper.cs
+++ b/Common/Net/IP/IPHelper.cs
@@ -1,22 +1,22 @@
using Microsoft.Win32;
using System;
+using System.Buffers.Binary;
using System.Collections.Generic;
using System.ComponentModel;
-using System.IO;
using System.Linq;
using System.Net;
+using System.Net.Http;
using System.Net.NetworkInformation;
using System.Net.Sockets;
-using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
-using Wokhan.WindowsFirewallNotifier.Common.IO.Streams;
+using Windows.Win32;
+using Windows.Win32.NetworkManagement.IpHelper;
+
using Wokhan.WindowsFirewallNotifier.Common.Logging;
-using Wokhan.WindowsFirewallNotifier.Common.Net.IP.TCP;
-using Wokhan.WindowsFirewallNotifier.Common.Net.IP.UDP;
namespace Wokhan.WindowsFirewallNotifier.Common.Net.IP;
@@ -28,23 +28,22 @@ public abstract partial class IPHelper
protected const uint NO_ERROR = 0;
protected const uint ERROR_INSUFFICIENT_BUFFER = 122;
- protected const uint ERROR_NOT_FOUND = 1168;
+ internal const uint ERROR_NOT_FOUND = 1168;
- internal static string GetAddressAsString(byte[] _remoteAddr)
- {
- return $"{_remoteAddr[0]}.{_remoteAddr[1]}.{_remoteAddr[2]}.{_remoteAddr[3]}";
- }
+ internal static readonly TCP_ESTATS_BANDWIDTH_ROD_v0 NoBandwidth = new TCP_ESTATS_BANDWIDTH_ROD_v0();
- internal static int GetRealPort(byte[] _remotePort)
- {
- return IPAddress.NetworkToHostOrder(BitConverter.ToInt32(new[] { _remotePort[2], _remotePort[3], _remotePort[0], _remotePort[1] }, 0));
- }
+ public static event EventHandler? StaticPropertyChanged;
- internal static string GetRealAddress(byte[] _remoteAddress)
+ internal static int GetRealPort(uint _remotePort)
{
- return new IPAddress(_remoteAddress).ToString();
+ // This is not working as expected
+ //return IPAddress.NetworkToHostOrder((ushort)_remotePort);
+ // While this is. Which is fun since this is the code of NetworkToHostOrder...
+ return (int)(BitConverter.IsLittleEndian ? BinaryPrimitives.ReverseEndianness((ushort)_remotePort) : (ushort)_remotePort);
}
+ internal static Dictionary TCP4MIBCACHE = new();
+
public static string MergePorts(IEnumerable ports)
{
var result = "";
@@ -104,132 +103,172 @@ public static string MergePorts(IEnumerable ports)
return result;
}
+ private static int maxUserPort = -1;
public static int GetMaxUserPort()
{
- using var maxUserPortKey = Registry.LocalMachine.OpenSubKey(MAX_USER_PORT_REGISTRY_KEY, false);
- var maxUserPortValue = maxUserPortKey?.GetValue(MAX_USER_PORT_REGISTRY_VALUE);
- if (maxUserPortValue is null)
+ if (maxUserPort == -1)
{
- //Default from Windows Vista and up
- return 49152;
- }
+ using var maxUserPortKey = Registry.LocalMachine.OpenSubKey(MAX_USER_PORT_REGISTRY_KEY, false);
+ var maxUserPortValue = maxUserPortKey?.GetValue(MAX_USER_PORT_REGISTRY_VALUE);
+ if (maxUserPortValue is null)
+ {
+ //Default from Windows Vista and up
+ maxUserPort = 49152;
+ }
- return Convert.ToInt32(maxUserPortValue);
+ maxUserPort = Convert.ToInt32(maxUserPortValue);
+ }
+ return maxUserPort;
}
- internal delegate uint GetOwnerModuleDelegate(T pTcpEntry, TCPIP_OWNER_MODULE_INFO_CLASS Class, IntPtr Buffer, ref uint pdwSize);
+ internal delegate uint GetOwnerModuleDelegate(IntPtr buffer, ref uint pdwSize);
+
- internal static Owner? GetOwningModuleInternal(GetOwnerModuleDelegate getOwnerModule, TRow row) where TRow : IConnectionOwnerInfo
+ ///
+ /// Returns details about connection of localPort by process identified by pid.
+ ///
+ ///
+ ///
+ public static Owner? GetOwner(uint pid, int localPort)
{
- Owner? ret = null;
- /*if (ownerCache.TryGetValue(row, out ret))
+ var allConn = GetAllConnections();
+ var ret = allConn.FirstOrDefault(r => r.LocalPort == localPort && r.OwningPid == pid);
+ return ret?.OwnerModule;
+ }
+
+ public static IEnumerable GetAllConnections(bool tcpOnly = false)
+ {
+ var ret = GetAllTCPConnections(AF_INET.IP4).Select(tcpConn => new Connection(tcpConn));
+ if (!tcpOnly)
{
- return ret;
- }*/
+ ret = ret.Concat(GetAllUDPConnections(AF_INET.IP4).Select(tcpConn => new Connection(tcpConn)));
+ }
- if (row.OwningPid == 0)
+ if (Socket.OSSupportsIPv6)
{
- return Owner.System;
+ ret = ret.Concat(GetAllTCPConnections(AF_INET.IP6).Select(tcpConn => new Connection(tcpConn)));
+ if (!tcpOnly)
+ {
+ ret = ret.Concat(GetAllUDPConnections(AF_INET.IP6).Select(tcpConn => new Connection(tcpConn)));
+ }
}
- IntPtr buffer = IntPtr.Zero;
+ return ret;
+ }
+
+ private unsafe static IEnumerable GetAllTCPConnections(uint ipv) where TRow : IConnectionOwnerInfo
+ {
+ IntPtr ptr = IntPtr.Zero;
try
{
uint buffSize = 0;
- var retn = getOwnerModule(row, TCPIP_OWNER_MODULE_INFO_CLASS.TCPIP_OWNER_MODULE_INFO_BASIC, IntPtr.Zero, ref buffSize);
- if (retn != NO_ERROR && retn != ERROR_INSUFFICIENT_BUFFER)
+ _ = NativeMethods.GetExtendedTcpTable(null, ref buffSize, false, ipv, TCP_TABLE_CLASS.TCP_TABLE_OWNER_MODULE_ALL, 0);
+
+ ptr = Marshal.AllocHGlobal((int)buffSize);
+
+ var ret = NativeMethods.GetExtendedTcpTable((void*)ptr, ref buffSize, false, ipv, TCP_TABLE_CLASS.TCP_TABLE_OWNER_MODULE_ALL, 0);
+
+ if (ret == 0)
{
- //Cannot get owning module for this connection
- LogHelper.Info("Unable to get the connection owner: ownerPid=" + row.OwningPid + " remoteAdr=" + row.RemoteAddress + ":" + row.RemotePort);
- return ret;
+ return ReadConnectionTable(ptr);
}
- if (buffSize == 0)
+ else
+ {
+ throw new Win32Exception((int)ret);
+ }
+ }
+ finally
+ {
+ if (ptr != IntPtr.Zero)
{
- //No buffer? Probably means we can't retrieve any information about this connection; skip it
- LogHelper.Info("Unable to get the connection owner (no buffer).");
- return ret;
+ Marshal.FreeHGlobal(ptr);
}
- buffer = Marshal.AllocHGlobal((int)buffSize);
+ }
+ }
- //GetOwnerModuleFromTcpEntry needs the fields of TCPIP_OWNER_MODULE_INFO_BASIC to be NULL
- NativeMethods.RtlZeroMemory(buffer, buffSize);
+ private unsafe static IEnumerable GetAllUDPConnections(uint ipv) where TRow : IConnectionOwnerInfo
+ {
+ IntPtr ptr = IntPtr.Zero;
+ try
+ {
+ uint buffSize = 0;
+ _ = NativeMethods.GetExtendedUdpTable(null, ref buffSize, false, ipv, UDP_TABLE_CLASS.UDP_TABLE_OWNER_MODULE, 0);
+
+ ptr = Marshal.AllocHGlobal((int)buffSize);
+
+ var ret = NativeMethods.GetExtendedUdpTable((void*)ptr, ref buffSize, false, ipv, UDP_TABLE_CLASS.UDP_TABLE_OWNER_MODULE, 0);
- var resp = getOwnerModule(row, TCPIP_OWNER_MODULE_INFO_CLASS.TCPIP_OWNER_MODULE_INFO_BASIC, buffer, ref buffSize);
- if (resp == 0)
+ if (ret == 0)
{
- ret = new Owner(Marshal.PtrToStructure(buffer));
+ return ReadConnectionTable(ptr);
}
- else if (resp != ERROR_NOT_FOUND) // Ignore closed connections
+ else
{
- LogHelper.Error("Unable to get the connection owner.", new Win32Exception((int)resp));
+ throw new Win32Exception((int)ret);
}
-
- //ownerCache.Add(row, ret);
-
- return ret;
}
finally
{
- if (buffer != IntPtr.Zero)
+ if (ptr != IntPtr.Zero)
{
- Marshal.FreeHGlobal(buffer);
+ Marshal.FreeHGlobal(ptr);
}
}
}
- ///
- /// Returns details about connection of localPort by process identified by pid.
- ///
- ///
- ///
- public static Owner? GetOwner(uint pid, int localPort)
+
+ private static unsafe IEnumerable ReadConnectionTable(IntPtr ptr) where TRow : IConnectionOwnerInfo
{
- var allConn = GetAllConnections();
- var ret = allConn.FirstOrDefault(r => r.LocalPort == localPort && r.OwningPid == pid);
- return ret?.OwnerModule;
+ var dwNumEntries = Marshal.ReadInt32(ptr);
+ // Padding may exist after dwNumEntries member; so we have to compute the actual offset.
+ // See https://learn.microsoft.com/en-us/windows/win32/api/tcpmib/ns-tcpmib-mib_tcptable_owner_module#remarks
+ var rowPtr = ptr + Marshal.OffsetOf(nameof(MIB_TCPTABLE_OWNER_MODULE.table));
+
+ return new Span((void*)rowPtr, dwNumEntries).ToArray();
}
- public static IEnumerable GetAllConnections(bool tcpOnly = false)
+ private static IPAddress? _currentIP;
+ public static IPAddress? CurrentIP
{
- var ret = TCPHelper.GetAllTCPConnections();
- if (!tcpOnly)
+ get
{
- ret = ret.Concat(UDPHelper.GetAllUDPConnections());
+ if (_currentIP is null)
+ {
+ SetCurrentIPAsync();
+ }
+ return _currentIP;
}
-
- if (Socket.OSSupportsIPv6)
+ set
{
- ret = ret.Concat(TCPHelper.GetAllTCP6Connections());
- if (!tcpOnly)
+ if (value != _currentIP)
{
- ret = ret.Concat(UDPHelper.GetAllUDP6Connections());
+ _currentIP = value;
+ StaticPropertyChanged?.Invoke(null, new PropertyChangedEventArgs(nameof(CurrentIP)));
}
}
-
- return ret;
}
-
- private static IPAddress? _currentIP;
- public static IPAddress CurrentIP
+ private static async void SetCurrentIPAsync()
{
- get => _currentIP ??= GetPublicIpAddress();
+ CurrentIP = await GetPublicIPAddressAsync();
}
- public static IPAddress GetPublicIpAddress()
+ [GeneratedRegex("^Current IP Address: (?.*)$", RegexOptions.Multiline | RegexOptions.ExplicitCapture)]
+ private static partial Regex CurrentIPAddressRegEx();
+
+ public static async Task GetPublicIPAddressAsync()
{
- var request = (HttpWebRequest)WebRequest.Create(new Uri("http://checkip.eurodyndns.org/"));
- request.Method = "GET";
- request.UserAgent = "curl";
try
{
- using WebResponse response = request.GetResponse();
- using var reader = new StreamReader(response.GetResponseStream());
+ // It's usually not a good idea to instantiate the HttpClient this way (one have to either use a factory or a static client),
+ // but this method will be only called once.
+ using var client = new HttpClient();
- var ans = reader.ReadLines().Skip(2).First();
- var adr = CurrentIPAddressRegEx().Match(ans);
+ var response = await client.GetStringAsync("http://checkip.eurodyndns.org/");
- return IPAddress.Parse(adr.Groups[1].Value.Trim());
+ var adr = CurrentIPAddressRegEx().Match(response);
+
+ return IPAddress.Parse(adr.Groups["ip"].ValueSpan.Trim());
}
catch
{
@@ -240,17 +279,17 @@ public static IPAddress GetPublicIpAddress()
private const int buffer_size = 32;
private const int max_hops = 30;
private const int ping_timeout = 4000;
- public static async Task> GetFullRoute(string adr)
+ public static async Task> GetFullRouteAsync(string adr)
{
var ret = new List();
-
+
using var pong = new Ping();
var po = new PingOptions(1, true);
PingReply? r = null;
var buffer = new byte[buffer_size];
Array.Fill(buffer, (byte)0);
-
+
for (var i = 1; i < max_hops; i++)
{
if (r is not null && r.Status != IPStatus.TimedOut)
@@ -272,7 +311,4 @@ public static async Task> GetFullRoute(string adr)
ret.Add(IPAddress.Parse(adr));
return ret;
}
-
- [GeneratedRegex("Current IP Address: (.*)", RegexOptions.Singleline)]
- private static partial Regex CurrentIPAddressRegEx();
}
diff --git a/Common/Net/IP/NativeMethods.txt b/Common/Net/IP/NativeMethods.txt
new file mode 100644
index 0000000..23e9940
--- /dev/null
+++ b/Common/Net/IP/NativeMethods.txt
@@ -0,0 +1,29 @@
+TCPIP_OWNER_MODULE_BASIC_INFO
+
+// TCP
+SetPerTcpConnectionEStats
+SetPerTcp6ConnectionEStats
+GetPerTcpConnectionEStats
+GetPerTcp6ConnectionEStats
+TCP_ESTATS_BANDWIDTH_RW_v0
+TCP_ESTATS_BANDWIDTH_ROD_v0
+
+GetExtendedTcpTable
+GetOwnerModuleFromTcpEntry
+GetOwnerModuleFromTcp6Entry
+MIB_TCPTABLE_OWNER_MODULE
+MIB_TCPROW_OWNER_MODULE
+MIB_TCP6TABLE_OWNER_MODULE
+
+TCP_TABLE_CLASS
+
+MIB_TCP_STATE
+
+// UDP
+GetExtendedUdpTable
+GetOwnerModuleFromUdpEntry
+GetOwnerModuleFromUdp6Entry
+GetUdpStatisticsEx
+
+MIB_UDPTABLE_OWNER_MODULE
+MIB_UDP6TABLE_OWNER_MODULE
diff --git a/Common/Net/IP/NativeOverrides/MIB_TCP6ROW_OWNER_MODULE.cs b/Common/Net/IP/NativeOverrides/MIB_TCP6ROW_OWNER_MODULE.cs
new file mode 100644
index 0000000..46d3e40
--- /dev/null
+++ b/Common/Net/IP/NativeOverrides/MIB_TCP6ROW_OWNER_MODULE.cs
@@ -0,0 +1,45 @@
+using System;
+using System.Windows;
+
+using Wokhan.WindowsFirewallNotifier.Common.Net.IP;
+using Wokhan.WindowsFirewallNotifier.Common.Net.IP.NativeOverrides;
+
+namespace Windows.Win32.NetworkManagement.IpHelper;
+
+///
+/// IMPORTANT: Never add any field or setter to this struct, as it is PARTIAL and relies on fields generated by CsWin32 P/Invoke source generator.
+/// If you do this, fields order might be broken and P/Invoke will fail (the struct layout in memory being unpredictable for partial structs).
+///
+internal partial struct MIB_TCP6ROW_OWNER_MODULE : IConnectionOwnerInfo
+{
+ unsafe uint IConnectionOwnerInfo.GetOwnerModule(IntPtr buffer, ref uint buffSize)
+ {
+ return NativeMethods.GetOwnerModuleFromTcp6Entry(in this, TCPIP_OWNER_MODULE_INFO_CLASS.TCPIP_OWNER_MODULE_INFO_BASIC, buffer.ToPointer(), ref buffSize);
+ }
+
+ unsafe TCP_ESTATS_BANDWIDTH_ROD_v0? IConnectionOwnerInfo.GetPerTcpConnectionEState(MIB_TCP6ROW? tcp6Row)
+ {
+ var rw = new TCP_ESTATS_BANDWIDTH_RW_v0() { EnableCollectionInbound = TCP_BOOLEAN_OPTIONAL.TcpBoolOptEnabled, EnableCollectionOutbound = TCP_BOOLEAN_OPTIONAL.TcpBoolOptEnabled };
+ var rod = new TCP_ESTATS_BANDWIDTH_ROD_v0();
+
+ var row = tcp6Row.Value;
+
+ var ret = NativeMethods.GetPerTcp6ConnectionEStats(in row, TCP_ESTATS_TYPE.TcpConnectionEstatsBandwidth, (byte*)&rw, 0, MarshalHelper.rwS, null, 0, 0, (byte*)&rod, 0, MarshalHelper.rodS);
+
+ if (ret == 0 && rw.EnableCollectionInbound == TCP_BOOLEAN_OPTIONAL.TcpBoolOptEnabled && rw.EnableCollectionOutbound == TCP_BOOLEAN_OPTIONAL.TcpBoolOptEnabled)
+ {
+ return rod;
+ }
+
+ return null;
+ }
+
+ unsafe uint IConnectionOwnerInfo.SetPerTcpConnectionEStats(ref TCP_ESTATS_BANDWIDTH_RW_v0 rw, MIB_TCP6ROW? tcp6Row)
+ {
+ var row = tcp6Row.Value;
+ fixed (void* rwPtr = &rw)
+ {
+ return NativeMethods.SetPerTcp6ConnectionEStats(&row, TCP_ESTATS_TYPE.TcpConnectionEstatsBandwidth, (byte*)rwPtr, 0, MarshalHelper.rwS, 0);
+ }
+ }
+}
diff --git a/Common/Net/IP/NativeOverrides/MIB_TCPROW_OWNER_MODULE.cs b/Common/Net/IP/NativeOverrides/MIB_TCPROW_OWNER_MODULE.cs
new file mode 100644
index 0000000..1d11203
--- /dev/null
+++ b/Common/Net/IP/NativeOverrides/MIB_TCPROW_OWNER_MODULE.cs
@@ -0,0 +1,51 @@
+using System;
+
+using Wokhan.WindowsFirewallNotifier.Common.Net.IP;
+using Wokhan.WindowsFirewallNotifier.Common.Net.IP.NativeOverrides;
+
+namespace Windows.Win32.NetworkManagement.IpHelper;
+
+///
+/// IMPORTANT: Never add any field or setter to this struct, as it is PARTIAL and relies on fields generated by CsWin32 P/Invoke source generator.
+/// If you do this, fields order might be broken and P/Invoke will fail (the struct layout in memory being unpredictable for partial structs).
+///
+internal partial struct MIB_TCPROW_OWNER_MODULE : IConnectionOwnerInfo
+{
+ unsafe uint IConnectionOwnerInfo.GetOwnerModule(IntPtr buffer, ref uint buffSize)
+ {
+ return NativeMethods.GetOwnerModuleFromTcpEntry(this, TCPIP_OWNER_MODULE_INFO_CLASS.TCPIP_OWNER_MODULE_INFO_BASIC, buffer.ToPointer(), ref buffSize);
+ }
+
+ unsafe TCP_ESTATS_BANDWIDTH_ROD_v0? IConnectionOwnerInfo.GetPerTcpConnectionEState(MIB_TCP6ROW? tcp6Row)
+ {
+ var rw = new TCP_ESTATS_BANDWIDTH_RW_v0() { EnableCollectionInbound = TCP_BOOLEAN_OPTIONAL.TcpBoolOptEnabled, EnableCollectionOutbound = TCP_BOOLEAN_OPTIONAL.TcpBoolOptEnabled };
+ var rod = new TCP_ESTATS_BANDWIDTH_ROD_v0();
+
+ uint ret;
+ // This allows to use the same pointer for the MIB_TCPROW_LH struct as for the current MIB_TCPROW_OWNER_MODULE one, as they share the same structure (the first fields).
+ fixed (void* thisPtr = &this)
+ {
+ ret = NativeMethods.GetPerTcpConnectionEStats((MIB_TCPROW_LH*)thisPtr, TCP_ESTATS_TYPE.TcpConnectionEstatsBandwidth, (byte*)&rw, 0, MarshalHelper.rwS, null, 0, 0, (byte*)&rod, 0, MarshalHelper.rodS);
+ }
+
+ if (ret == 0 && rw.EnableCollectionInbound == TCP_BOOLEAN_OPTIONAL.TcpBoolOptEnabled && rw.EnableCollectionOutbound == TCP_BOOLEAN_OPTIONAL.TcpBoolOptEnabled)
+ {
+ return rod;
+ }
+
+ return null;
+ }
+
+ unsafe uint IConnectionOwnerInfo.SetPerTcpConnectionEStats(ref TCP_ESTATS_BANDWIDTH_RW_v0 rw, MIB_TCP6ROW? tcp6Row)
+ {
+ uint ret;
+
+ fixed (void* thisPtr = &this)
+ fixed (void* rwPtr = &rw)
+ {
+ ret = NativeMethods.SetPerTcpConnectionEStats((MIB_TCPROW_LH*)thisPtr, TCP_ESTATS_TYPE.TcpConnectionEstatsBandwidth, (byte*)rwPtr, 0, MarshalHelper.rwS, 0);
+ }
+
+ return ret;
+ }
+}
diff --git a/Common/Net/IP/NativeOverrides/MIB_UDP6ROW_OWNER_MODULE.cs b/Common/Net/IP/NativeOverrides/MIB_UDP6ROW_OWNER_MODULE.cs
new file mode 100644
index 0000000..0266788
--- /dev/null
+++ b/Common/Net/IP/NativeOverrides/MIB_UDP6ROW_OWNER_MODULE.cs
@@ -0,0 +1,27 @@
+using System;
+
+using Wokhan.WindowsFirewallNotifier.Common.Net.IP;
+
+namespace Windows.Win32.NetworkManagement.IpHelper;
+
+///
+/// IMPORTANT: Never add any field or setter to this struct, as it is PARTIAL and relies on fields generated by CsWin32 P/Invoke source generator.
+/// If you do this, fields order might be broken and P/Invoke will fail (the struct layout in memory being unpredictable for partial structs).
+///
+internal partial struct MIB_UDP6ROW_OWNER_MODULE : IConnectionOwnerInfo
+{
+ unsafe uint IConnectionOwnerInfo.GetOwnerModule(IntPtr buffer, ref uint buffSize)
+ {
+ return NativeMethods.GetOwnerModuleFromUdp6Entry(this, TCPIP_OWNER_MODULE_INFO_CLASS.TCPIP_OWNER_MODULE_INFO_BASIC, buffer.ToPointer(), ref buffSize);
+ }
+
+ TCP_ESTATS_BANDWIDTH_ROD_v0? IConnectionOwnerInfo.GetPerTcpConnectionEState(MIB_TCP6ROW? tcp6Row)
+ {
+ throw new NotImplementedException();
+ }
+
+ uint IConnectionOwnerInfo.SetPerTcpConnectionEStats(ref TCP_ESTATS_BANDWIDTH_RW_v0 rw, MIB_TCP6ROW? tcp6Row)
+ {
+ throw new NotImplementedException();
+ }
+}
diff --git a/Common/Net/IP/NativeOverrides/MIB_UDPROW_OWNER_MODULE.cs b/Common/Net/IP/NativeOverrides/MIB_UDPROW_OWNER_MODULE.cs
new file mode 100644
index 0000000..39843fd
--- /dev/null
+++ b/Common/Net/IP/NativeOverrides/MIB_UDPROW_OWNER_MODULE.cs
@@ -0,0 +1,29 @@
+using System;
+
+using Wokhan.WindowsFirewallNotifier.Common.Net.IP;
+
+namespace Windows.Win32.NetworkManagement.IpHelper;
+
+///
+/// IMPORTANT: Never add any field or setter to this struct, as it is PARTIAL and relies on fields generated by CsWin32 P/Invoke source generator.
+/// If you do this, fields order might be broken and P/Invoke will fail (the struct layout in memory being unpredictable for partial structs).
+///
+internal partial struct MIB_UDPROW_OWNER_MODULE : IConnectionOwnerInfo
+{
+ unsafe uint IConnectionOwnerInfo.GetOwnerModule(IntPtr buffer, ref uint buffSize)
+ {
+ return NativeMethods.GetOwnerModuleFromUdpEntry(this, TCPIP_OWNER_MODULE_INFO_CLASS.TCPIP_OWNER_MODULE_INFO_BASIC, buffer.ToPointer(), ref buffSize);
+ }
+
+ TCP_ESTATS_BANDWIDTH_ROD_v0? IConnectionOwnerInfo.GetPerTcpConnectionEState(MIB_TCP6ROW? tcp6Row)
+ {
+ //TODO: Check GetUdpStatisticsEx?
+ //NativeMethods.GetUdpStatisticsEx(, AF_INET.IP4)
+ throw new NotImplementedException();
+ }
+
+ uint IConnectionOwnerInfo.SetPerTcpConnectionEStats(ref TCP_ESTATS_BANDWIDTH_RW_v0 rw, MIB_TCP6ROW? tcp6Row)
+ {
+ return 0;
+ }
+}
diff --git a/Common/Net/IP/NativeOverrides/MarshalHelper.cs b/Common/Net/IP/NativeOverrides/MarshalHelper.cs
new file mode 100644
index 0000000..44ed75d
--- /dev/null
+++ b/Common/Net/IP/NativeOverrides/MarshalHelper.cs
@@ -0,0 +1,11 @@
+using System.Runtime.InteropServices;
+
+using Windows.Win32.NetworkManagement.IpHelper;
+
+namespace Wokhan.WindowsFirewallNotifier.Common.Net.IP.NativeOverrides;
+
+internal static class MarshalHelper
+{
+ internal static uint rwS = (uint)Marshal.SizeOf();
+ internal static uint rodS = (uint)Marshal.SizeOf();
+}
diff --git a/Common/Net/IP/Owner.cs b/Common/Net/IP/Owner.cs
index a736b34..553f2e0 100644
--- a/Common/Net/IP/Owner.cs
+++ b/Common/Net/IP/Owner.cs
@@ -1,24 +1,6 @@
-using System;
-using System.Runtime.InteropServices;
+namespace Wokhan.WindowsFirewallNotifier.Common.Net.IP;
-namespace Wokhan.WindowsFirewallNotifier.Common.Net.IP;
-
-public class Owner
+public record Owner(string? ModuleName, string? ModulePath)
{
- public static Owner System { get; } = new Owner("System", "System");
-
- public string ModuleName { get; private set; }
- public string ModulePath { get; private set; }
-
- internal Owner(TCPIP_OWNER_MODULE_BASIC_INFO inf)
- {
- ModuleName = Marshal.PtrToStringAuto(inf.p1) ?? String.Empty;
- ModulePath = Marshal.PtrToStringAuto(inf.p2) ?? String.Empty;
- }
-
- public Owner(string moduleName, string modulePath)
- {
- ModuleName = moduleName;
- ModulePath = modulePath;
- }
+ public static readonly Owner System = new Owner("System", "System");
}
diff --git a/Common/Net/IP/TCP/ITcpRow.cs b/Common/Net/IP/TCP/ITcpRow.cs
deleted file mode 100644
index 78a6d9d..0000000
--- a/Common/Net/IP/TCP/ITcpRow.cs
+++ /dev/null
@@ -1,9 +0,0 @@
-using static Wokhan.WindowsFirewallNotifier.Common.Net.IP.TCP.TCPHelper;
-
-namespace Wokhan.WindowsFirewallNotifier.Common.Net.IP.TCP;
-
-public interface ITcpRow
-{
- TCP_ESTATS_BANDWIDTH_ROD_v0 GetTCPBandwidth();
- void EnsureStats();
-}
\ No newline at end of file
diff --git a/Common/Net/IP/TCP/NativeMethods.cs b/Common/Net/IP/TCP/NativeMethods.cs
deleted file mode 100644
index 4eb050f..0000000
--- a/Common/Net/IP/TCP/NativeMethods.cs
+++ /dev/null
@@ -1,13 +0,0 @@
-using System;
-using System.Runtime.InteropServices;
-
-using static Wokhan.WindowsFirewallNotifier.Common.Net.IP.IPHelper;
-
-namespace Wokhan.WindowsFirewallNotifier.Common.Net.IP.TCP;
-
-internal static partial class NativeMethods
-{
- [LibraryImport("iphlpapi.dll", SetLastError = true)]
- internal static partial uint GetExtendedTcpTable(IntPtr pTcpTable, ref uint dwOutBufLen, [MarshalAs(UnmanagedType.Bool)] bool sort, AF_INET ipVersion, TCP_TABLE_CLASS tblClass, uint reserved);
-
-}
diff --git a/Common/Net/IP/TCP/TCP4/MIB_TCPROW.cs b/Common/Net/IP/TCP/TCP4/MIB_TCPROW.cs
deleted file mode 100644
index 1ce8047..0000000
--- a/Common/Net/IP/TCP/TCP4/MIB_TCPROW.cs
+++ /dev/null
@@ -1,23 +0,0 @@
-using System;
-using System.Runtime.InteropServices;
-
-namespace Wokhan.WindowsFirewallNotifier.Common.Net.IP.TCP.TCP4;
-
-[StructLayout(LayoutKind.Sequential)]
-internal struct MIB_TCPROW : ITcpRow
-{
- public ConnectionStatus State;
- [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
- public byte[] dwLocalAddr;
- [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
- public byte[] dwLocalPort;
- [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
- public byte[] dwRemoteAddr;
- [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
- public byte[] dwRemotePort;
-
- public void EnsureStats() => TCPHelper.EnsureStatsAreEnabledInternal(NativeMethods.SetPerTcpConnectionEStats, this);
-
- public TCP_ESTATS_BANDWIDTH_ROD_v0 GetTCPBandwidth() => TCPHelper.GetTCPBandwidthInternal(NativeMethods.GetPerTcpConnectionEStats, this);
-
-}
diff --git a/Common/Net/IP/TCP/TCP4/MIB_TCPROW_OWNER_MODULE.cs b/Common/Net/IP/TCP/TCP4/MIB_TCPROW_OWNER_MODULE.cs
deleted file mode 100644
index f2d5d60..0000000
--- a/Common/Net/IP/TCP/TCP4/MIB_TCPROW_OWNER_MODULE.cs
+++ /dev/null
@@ -1,43 +0,0 @@
-using System;
-using System.Net;
-using System.Runtime.InteropServices;
-
-
-namespace Wokhan.WindowsFirewallNotifier.Common.Net.IP.TCP.TCP4;
-
-//TODO: Switch to internal
-[StructLayout(LayoutKind.Sequential)]
-public struct MIB_TCPROW_OWNER_MODULE : IConnectionOwnerInfo
-{
- internal ConnectionStatus _state;
- [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
- internal byte[] _localAddr;
- [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
- internal byte[] _localPort;
- [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
- internal byte[] _remoteAddr;
- [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
- internal byte[] _remotePort;
-
- internal uint _owningPid;
- internal long _creationTime;
- [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
- internal ulong[] _owningModuleInfo;
-
- public byte[] RemoteAddrBytes => _remoteAddr;
- public ConnectionStatus State => _state;
- public string RemoteAddress => IPHelper.GetAddressAsString(_remoteAddr);
- public string LocalAddress => IPHelper.GetAddressAsString(_localAddr);
- public int RemotePort => IPHelper.GetRealPort(_remotePort);
- public int LocalPort => IPHelper.GetRealPort(_localPort);
- public Owner? OwnerModule => TCPHelper.GetOwningModuleInternal(NativeMethods.GetOwnerModuleFromTcpEntry, this);
- public string Protocol => "TCP";
- public uint OwningPid => _owningPid;
- public DateTime? CreationTime => _creationTime == 0 ? (DateTime?)null : DateTime.FromFileTime(_creationTime);
- public bool IsLoopback => IPAddress.IsLoopback(IPAddress.Parse(RemoteAddress));
-
- public ITcpRow ToTcpRow()
- {
- return new MIB_TCPROW() { dwLocalAddr = _localAddr, dwRemoteAddr = _remoteAddr, dwLocalPort = _localPort, dwRemotePort = _remotePort, State = _state };
- }
-}
diff --git a/Common/Net/IP/TCP/TCP4/MIB_TCPTABLE_OWNER_MODULE.cs b/Common/Net/IP/TCP/TCP4/MIB_TCPTABLE_OWNER_MODULE.cs
deleted file mode 100644
index 078c8e2..0000000
--- a/Common/Net/IP/TCP/TCP4/MIB_TCPTABLE_OWNER_MODULE.cs
+++ /dev/null
@@ -1,11 +0,0 @@
-using System.Runtime.InteropServices;
-
-
-namespace Wokhan.WindowsFirewallNotifier.Common.Net.IP.TCP.TCP4;
-
-[StructLayout(LayoutKind.Sequential)]
-internal struct MIB_TCPTABLE_OWNER_MODULE
-{
- public uint NumEntries;
- public MIB_TCPROW_OWNER_MODULE FirstEntry;
-}
diff --git a/Common/Net/IP/TCP/TCP4/NativeMethods.cs b/Common/Net/IP/TCP/TCP4/NativeMethods.cs
deleted file mode 100644
index c374b49..0000000
--- a/Common/Net/IP/TCP/TCP4/NativeMethods.cs
+++ /dev/null
@@ -1,22 +0,0 @@
-using System;
-using System.Runtime.InteropServices;
-
-using static Wokhan.WindowsFirewallNotifier.Common.Net.IP.IPHelper;
-
-namespace Wokhan.WindowsFirewallNotifier.Common.Net.IP.TCP.TCP4;
-
-internal static partial class NativeMethods
-{
- [DllImport("iphlpapi.dll", SetLastError = true)]
- internal static extern uint GetOwnerModuleFromTcpEntry(MIB_TCPROW_OWNER_MODULE pTcpEntry, TCPIP_OWNER_MODULE_INFO_CLASS Class, IntPtr Buffer, ref uint pdwSize);
-
- [LibraryImport("iphlpapi.dll", SetLastError = true)]
- internal static partial uint GetExtendedTcpTable(IntPtr pTcpTable, ref uint dwOutBufLen, [MarshalAs(UnmanagedType.Bool)] bool sort, AF_INET ipVersion, TCP_TABLE_CLASS tblClass, uint reserved);
-
- [DllImport("iphlpapi.dll", SetLastError = true)]
- internal static extern uint GetPerTcpConnectionEStats(MIB_TCPROW Row, TCP_ESTATS_TYPE EstatsType, IntPtr Rw, uint RwVersion, uint RwSize, IntPtr Ros, uint RosVersion, uint RosSize, IntPtr Rod, uint RodVersion, uint RodSize);
-
- [DllImport("iphlpapi.dll", SetLastError = true)]
- internal static extern uint SetPerTcpConnectionEStats(MIB_TCPROW Row, TCP_ESTATS_TYPE EstatsType, IntPtr Rw, uint RwVersion, uint RwSize, uint Offset);
-
-}
diff --git a/Common/Net/IP/TCP/TCP6/MIB_TCP6ROW.cs b/Common/Net/IP/TCP/TCP6/MIB_TCP6ROW.cs
deleted file mode 100644
index 2867e68..0000000
--- a/Common/Net/IP/TCP/TCP6/MIB_TCP6ROW.cs
+++ /dev/null
@@ -1,24 +0,0 @@
-using System;
-using System.Runtime.InteropServices;
-
-namespace Wokhan.WindowsFirewallNotifier.Common.Net.IP.TCP.TCP6;
-
-[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
-internal struct MIB_TCP6ROW : ITcpRow
-{
- internal ConnectionStatus State;
- [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
- internal byte[] _localAddress;
- internal uint LocalScopeId;
- [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
- internal byte[] _localPort;
- [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
- internal byte[] _remoteAddress;
- internal uint RemoteScopeId;
- [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
- internal byte[] _remotePort;
-
- public void EnsureStats() => TCPHelper.EnsureStatsAreEnabledInternal(NativeMethods.SetPerTcp6ConnectionEStats, this);
-
- public TCP_ESTATS_BANDWIDTH_ROD_v0 GetTCPBandwidth() => TCPHelper.GetTCPBandwidthInternal(NativeMethods.GetPerTcp6ConnectionEStats, this);
-}
diff --git a/Common/Net/IP/TCP/TCP6/MIB_TCP6ROW_OWNER_MODULE.cs b/Common/Net/IP/TCP/TCP6/MIB_TCP6ROW_OWNER_MODULE.cs
deleted file mode 100644
index 663b663..0000000
--- a/Common/Net/IP/TCP/TCP6/MIB_TCP6ROW_OWNER_MODULE.cs
+++ /dev/null
@@ -1,43 +0,0 @@
-using System;
-using System.Net;
-using System.Runtime.InteropServices;
-
-namespace Wokhan.WindowsFirewallNotifier.Common.Net.IP.TCP.TCP6;
-
-[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
-internal struct MIB_TCP6ROW_OWNER_MODULE : IConnectionOwnerInfo
-{
- [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
- internal byte[] _localAddress;
- internal uint LocalScopeId;
- [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
- internal byte[] _localPort;
- [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
- internal byte[] _remoteAddress;
- internal uint RemoteScopeId;
- [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
- internal byte[] _remotePort;
- internal ConnectionStatus _state;
- internal uint _owningPid;
- internal long _creationTime;
- [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
- public ulong[] OwningModuleInfo;
-
-
- public byte[] RemoteAddrBytes => _remoteAddress;
- public uint OwningPid => _owningPid;
- public string LocalAddress => IPHelper.GetRealAddress(_localAddress);
- public int LocalPort => IPHelper.GetRealPort(_localPort);
- public string RemoteAddress => IPHelper.GetRealAddress(_remoteAddress);
- public int RemotePort => IPHelper.GetRealPort(_remotePort);
- public Owner? OwnerModule => TCPHelper.GetOwningModuleInternal(NativeMethods.GetOwnerModuleFromTcp6Entry, this);
- public string Protocol => "TCP";
- public ConnectionStatus State => _state;
- public DateTime? CreationTime => _creationTime == 0 ? null : DateTime.FromFileTime(_creationTime);
- public bool IsLoopback => IPAddress.IsLoopback(IPAddress.Parse(RemoteAddress));
-
- public ITcpRow ToTcpRow()
- {
- return new MIB_TCP6ROW() { _localAddress = _localAddress, _remoteAddress = _remoteAddress, _localPort = _localPort, _remotePort = _remotePort, State = _state };
- }
-}
diff --git a/Common/Net/IP/TCP/TCP6/MIB_TCP6TABLE_OWNER_MODULE.cs b/Common/Net/IP/TCP/TCP6/MIB_TCP6TABLE_OWNER_MODULE.cs
deleted file mode 100644
index b3961a5..0000000
--- a/Common/Net/IP/TCP/TCP6/MIB_TCP6TABLE_OWNER_MODULE.cs
+++ /dev/null
@@ -1,10 +0,0 @@
-using System.Runtime.InteropServices;
-
-namespace Wokhan.WindowsFirewallNotifier.Common.Net.IP.TCP.TCP6;
-
-[StructLayout(LayoutKind.Sequential)]
-internal struct MIB_TCP6TABLE_OWNER_MODULE
-{
- public uint NumEntries;
- public MIB_TCP6ROW_OWNER_MODULE FirstEntry;
-}
\ No newline at end of file
diff --git a/Common/Net/IP/TCP/TCP6/NativeMethods.cs b/Common/Net/IP/TCP/TCP6/NativeMethods.cs
deleted file mode 100644
index c7bdf7b..0000000
--- a/Common/Net/IP/TCP/TCP6/NativeMethods.cs
+++ /dev/null
@@ -1,21 +0,0 @@
-using System;
-using System.Runtime.InteropServices;
-using System.Text;
-
-
-namespace Wokhan.WindowsFirewallNotifier.Common.Net.IP.TCP.TCP6;
-
-internal static partial class NativeMethods
-{
- [DllImport("iphlpapi.dll", SetLastError = true)]
- internal static extern uint GetOwnerModuleFromTcp6Entry(MIB_TCP6ROW_OWNER_MODULE pTcpEntry, TCPIP_OWNER_MODULE_INFO_CLASS Class, IntPtr Buffer, ref uint pdwSize);
-
- [DllImport("iphlpapi.dll", SetLastError = true)]
- internal static extern uint GetPerTcp6ConnectionEStats(MIB_TCP6ROW Row, TCP_ESTATS_TYPE EstatsType, IntPtr Rw, uint RwVersion, uint RwSize, IntPtr Ros, uint RosVersion, uint RosSize, IntPtr Rod, uint RodVersion, uint RodSize);
-
- [DllImport("iphlpapi.dll", SetLastError = true)]
- internal static extern uint SetPerTcp6ConnectionEStats(MIB_TCP6ROW Row, TCP_ESTATS_TYPE EstatsType, IntPtr Rw, uint RwVersion, uint RwSize, uint Offset);
-
- [LibraryImport("ntdll.dll", SetLastError = true/*TODO: test this, CharSet = CharSet.Unicode*/)]
- internal static unsafe partial void RtlIpv6AddressToString(byte[] Addr, char* res);
-}
diff --git a/Common/Net/IP/TCP/TCPHelper.cs b/Common/Net/IP/TCP/TCPHelper.cs
deleted file mode 100644
index 001c18c..0000000
--- a/Common/Net/IP/TCP/TCPHelper.cs
+++ /dev/null
@@ -1,183 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.ComponentModel;
-using System.Runtime.InteropServices;
-
-namespace Wokhan.WindowsFirewallNotifier.Common.Net.IP.TCP;
-
-public partial class TCPHelper : IPHelper
-{
-
- internal delegate uint SetPerTcpConnectionEStatsDelegate(T row, TCP_ESTATS_TYPE eStatsType, IntPtr rw, uint rwVersion, uint rwSize, uint offset);
-
- internal delegate uint GetPerTcpConnectionEStateDelegate(T row, TCP_ESTATS_TYPE eStatsType, nint rw, uint rwVersion, uint rwSize, nint ros, uint rosVersion, uint rosSize, nint rod, uint rodVersion, uint rodSize);
-
-
- private static IEnumerable GetAllTCPConnections(AF_INET aF_INET) where TRow : IConnectionOwnerInfo
- {
- IntPtr buffTable = IntPtr.Zero;
-
- try
- {
- uint buffSize = 0;
- _ = NativeMethods.GetExtendedTcpTable(IntPtr.Zero, ref buffSize, false, aF_INET, TCP_TABLE_CLASS.TCP_TABLE_OWNER_MODULE_ALL, 0);
-
- buffTable = Marshal.AllocHGlobal((int)buffSize);
-
- uint ret = NativeMethods.GetExtendedTcpTable(buffTable, ref buffSize, false, aF_INET, TCP_TABLE_CLASS.TCP_TABLE_OWNER_MODULE_ALL, 0);
- if (ret == 0)
- {
- var tab = Marshal.PtrToStructure(buffTable);
- IntPtr rowPtr = (IntPtr)((long)buffTable + (long)Marshal.OffsetOf(nameof(TCP4.MIB_TCPTABLE_OWNER_MODULE.FirstEntry)));
-
- TRow current;
- for (uint i = 0; i < tab.NumEntries; i++)
- {
- current = Marshal.PtrToStructure(rowPtr);
- rowPtr = (IntPtr)((long)rowPtr + (long)Marshal.SizeOf(current));
-
- yield return current;
- }
- }
- else
- {
- throw new Win32Exception((int)ret);
- }
- }
- finally
- {
- if (buffTable != IntPtr.Zero)
- {
- Marshal.FreeHGlobal(buffTable);
- }
- }
- }
-
-
- internal static void EnsureStatsAreEnabledInternal(SetPerTcpConnectionEStatsDelegate SetPerTcpConnectionEStats, T row)
- {
- var rwS = Marshal.SizeOf();
- IntPtr rw = Marshal.AllocHGlobal(rwS);
- Marshal.StructureToPtr(new TCP_ESTATS_BANDWIDTH_RW_v0() { EnableCollectionInbound = TCP_BOOLEAN_OPTIONAL.TcpBoolOptEnabled, EnableCollectionOutbound = TCP_BOOLEAN_OPTIONAL.TcpBoolOptEnabled }, rw, true);
-
- try
- {
- var r = SetPerTcpConnectionEStats(row, TCP_ESTATS_TYPE.TcpConnectionEstatsBandwidth, rw, 0, (uint)rwS, 0);
- if (r != 0)
- {
- throw new Win32Exception((int)r);
- }
- }
- finally
- {
- Marshal.FreeHGlobal(rw);
- }
- }
-
- internal static TCP_ESTATS_BANDWIDTH_ROD_v0 GetTCPBandwidthInternal(GetPerTcpConnectionEStateDelegate getPerTcpConnectionEState, T row)
- {
- IntPtr rw = IntPtr.Zero;
- IntPtr rod = IntPtr.Zero;
-
- var rwS = Marshal.SizeOf();
- rw = Marshal.AllocHGlobal(rwS);
-
- var rodS = Marshal.SizeOf();
- rod = Marshal.AllocHGlobal(rodS);
-
- try
- {
- var r = getPerTcpConnectionEState(row, TCP_ESTATS_TYPE.TcpConnectionEstatsBandwidth, rw, 0, (uint)rwS, IntPtr.Zero, 0, 0, rod, 0, (uint)rodS);
- if (r != 0)
- {
- throw new Win32Exception((int)r);
- }
-
- var parsedRW = Marshal.PtrToStructure(rw);
- if (parsedRW.EnableCollectionInbound != TCP_BOOLEAN_OPTIONAL.TcpBoolOptEnabled || parsedRW.EnableCollectionOutbound != TCP_BOOLEAN_OPTIONAL.TcpBoolOptEnabled)
- {
- throw new Exception("Monitoring is disabled for this connection.");
- }
-
- return Marshal.PtrToStructure(rod);
- }
- catch (Win32Exception we)
- {
- if (we.NativeErrorCode == ERROR_NOT_FOUND)
- {
- return new TCP_ESTATS_BANDWIDTH_ROD_v0() { InboundBandwidth = 0, OutboundBandwidth = 0 };
- }
- else
- {
- throw;
- }
- }
- catch (Exception)
- {
- throw;
- }
- finally
- {
- if (rw != IntPtr.Zero)
- {
- Marshal.FreeHGlobal(rw);
- }
-
- if (rod != IntPtr.Zero)
- {
- Marshal.FreeHGlobal(rod);
- }
- }
- }
-
-
- /*
- public static TCP_ESTATS_DATA_ROD_v0 GetTCPStatistics(MIB_TCPROW_OWNER_MODULE conn)
- {
- IntPtr rw = IntPtr.Zero;
- IntPtr rod = IntPtr.Zero;
-
- try
- {
- var row = new MIB_TCPROW() { dwLocalAddr = conn._localAddr, dwRemoteAddr = conn._remoteAddr, dwLocalPort = conn._localPort, dwRemotePort = conn._remotePort, dwState = conn._state };
-
- EnsureStatsAreEnabled(row);
-
- var rwS = Marshal.SizeOf(typeof(TCP_ESTATS_DATA_RW_v0));
- rw = Marshal.AllocHGlobal(rwS);
-
- var rodS = Marshal.SizeOf(typeof(TCP_ESTATS_DATA_ROD_v0));
- rod = Marshal.AllocHGlobal(rodS);
-
- var resp = NativeMethods.GetPerTcpConnectionEStats(ref row, TCP_ESTATS_TYPE.TcpConnectionEstatsData, rw, 0, (uint)rwS, IntPtr.Zero, 0, 0, rod, 0, (uint)rodS);
- if (resp != NO_ERROR)
- {
- LogHelper.Error("Unable to get the connection statistics.", new Win32Exception((int)resp));
- }
-
- var parsedRW = Marshal.PtrToStructure(rw);
- var parsedROD = Marshal.PtrToStructure(rod);
-
- return parsedROD;
- }
- finally
- {
- if (rw != IntPtr.Zero)
- {
- Marshal.FreeHGlobal(rw);
- }
-
- if (rod != IntPtr.Zero)
- {
- Marshal.FreeHGlobal(rod);
- }
- }
- }*/
-
- //private static Dictionary ownerCache = new Dictionary();
-
- public static IEnumerable GetAllTCPConnections() => GetAllTCPConnections(AF_INET.IP4);
-
- public static IEnumerable GetAllTCP6Connections() => GetAllTCPConnections(AF_INET.IP6);
-
-}
diff --git a/Common/Net/IP/TCP/TCP_BOOLEAN_OPTIONAL.cs b/Common/Net/IP/TCP/TCP_BOOLEAN_OPTIONAL.cs
deleted file mode 100644
index 25802dd..0000000
--- a/Common/Net/IP/TCP/TCP_BOOLEAN_OPTIONAL.cs
+++ /dev/null
@@ -1,8 +0,0 @@
-namespace Wokhan.WindowsFirewallNotifier.Common.Net.IP.TCP;
-
-internal enum TCP_BOOLEAN_OPTIONAL
-{
- TcpBoolOptDisabled = 0,
- TcpBoolOptEnabled = 1,
- TcpBoolOptUnchanged = -1
-}
diff --git a/Common/Net/IP/TCP/TCP_ESTATS_BANDWIDTH_ROD_v0.cs b/Common/Net/IP/TCP/TCP_ESTATS_BANDWIDTH_ROD_v0.cs
deleted file mode 100644
index bb9a473..0000000
--- a/Common/Net/IP/TCP/TCP_ESTATS_BANDWIDTH_ROD_v0.cs
+++ /dev/null
@@ -1,11 +0,0 @@
-namespace Wokhan.WindowsFirewallNotifier.Common.Net.IP.TCP;
-
-public struct TCP_ESTATS_BANDWIDTH_ROD_v0
-{
- public ulong OutboundBandwidth;
- public ulong InboundBandwidth;
- public ulong OutboundInstability;
- public ulong InboundInstability;
- public bool OutboundBandwidthPeaked;
- public bool InboundBandwidthPeaked;
-}
diff --git a/Common/Net/IP/TCP/TCP_ESTATS_BANDWIDTH_RW_v0.cs b/Common/Net/IP/TCP/TCP_ESTATS_BANDWIDTH_RW_v0.cs
deleted file mode 100644
index 352964c..0000000
--- a/Common/Net/IP/TCP/TCP_ESTATS_BANDWIDTH_RW_v0.cs
+++ /dev/null
@@ -1,10 +0,0 @@
-using System.Runtime.InteropServices;
-
-namespace Wokhan.WindowsFirewallNotifier.Common.Net.IP.TCP;
-
-[StructLayout(LayoutKind.Sequential)]
-internal struct TCP_ESTATS_BANDWIDTH_RW_v0
-{
- internal TCP_BOOLEAN_OPTIONAL EnableCollectionOutbound;
- internal TCP_BOOLEAN_OPTIONAL EnableCollectionInbound;
-}
diff --git a/Common/Net/IP/TCP/TCP_ESTATS_TYPE.cs b/Common/Net/IP/TCP/TCP_ESTATS_TYPE.cs
deleted file mode 100644
index aa0774c..0000000
--- a/Common/Net/IP/TCP/TCP_ESTATS_TYPE.cs
+++ /dev/null
@@ -1,64 +0,0 @@
-namespace Wokhan.WindowsFirewallNotifier.Common.Net.IP.TCP;
-
-/*
-[StructLayout(LayoutKind.Sequential)]
-public struct MIB_TCPSTATS
-{
-public int dwRtoAlgorithm;
-public int dwRtoMin;
-public int dwRtoMax;
-public int dwMaxConn;
-public int dwActiveOpens;
-public int dwPassiveOpens;
-public int dwAttemptFails;
-public int dwEstabResets;
-public int dwCurrEstab;
-public int dwInSegs;
-public int dwOutSegs;
-public int dwRetransSegs;
-public int dwInErrs;
-public int dwOutRsts;
-public int dwNumConns;
-}*/
-
-/*
-[StructLayout(LayoutKind.Sequential)]
-protected struct TCP_ESTATS_DATA_RW_v0
-{
- public bool EnableCollection;
-}*/
-
-/*
-[StructLayout(LayoutKind.Sequential)]
-protected struct TCP_ESTATS_DATA_ROD_v0
-{
- public uint DataBytesOut;
- public uint DataSegsOut;
- public uint DataBytesIn;
- public uint DataSegsIn;
- public uint SegsOut;
- public uint SegsIn;
- public uint SoftErrors;
- public uint SoftErrorReason;
- public uint SndUna;
- public uint SndNxt;
- public uint SndMax;
- public uint ThruBytesAcked;
- public uint RcvNxt;
- public uint ThruBytesReceived;
-}*/
-
-internal enum TCP_ESTATS_TYPE
-{
- TcpConnectionEstatsSynOpts,
- TcpConnectionEstatsData,
- TcpConnectionEstatsSndCong,
- TcpConnectionEstatsPath,
- TcpConnectionEstatsSendBuff,
- TcpConnectionEstatsRec,
- TcpConnectionEstatsObsRec,
- TcpConnectionEstatsBandwidth,
- TcpConnectionEstatsFineRtt,
- TcpConnectionEstatsMaximum
-}
-
diff --git a/Common/Net/IP/TCP/TCP_TABLE_CLASS.cs b/Common/Net/IP/TCP/TCP_TABLE_CLASS.cs
deleted file mode 100644
index f663928..0000000
--- a/Common/Net/IP/TCP/TCP_TABLE_CLASS.cs
+++ /dev/null
@@ -1,14 +0,0 @@
-namespace Wokhan.WindowsFirewallNotifier.Common.Net.IP.TCP;
-
-internal enum TCP_TABLE_CLASS
-{
- TCP_TABLE_BASIC_LISTENER,
- TCP_TABLE_BASIC_CONNECTIONS,
- TCP_TABLE_BASIC_ALL,
- TCP_TABLE_OWNER_PID_LISTENER,
- TCP_TABLE_OWNER_PID_CONNECTIONS,
- TCP_TABLE_OWNER_PID_ALL,
- TCP_TABLE_OWNER_MODULE_LISTENER,
- TCP_TABLE_OWNER_MODULE_CONNECTIONS,
- TCP_TABLE_OWNER_MODULE_ALL
-}
diff --git a/Common/Net/IP/TCPIP_OWNER_MODULE_BASIC_INFO.cs b/Common/Net/IP/TCPIP_OWNER_MODULE_BASIC_INFO.cs
deleted file mode 100644
index d34ad89..0000000
--- a/Common/Net/IP/TCPIP_OWNER_MODULE_BASIC_INFO.cs
+++ /dev/null
@@ -1,11 +0,0 @@
-using System;
-using System.Runtime.InteropServices;
-
-namespace Wokhan.WindowsFirewallNotifier.Common.Net.IP;
-
-[StructLayout(LayoutKind.Sequential)]
-internal struct TCPIP_OWNER_MODULE_BASIC_INFO
-{
- public IntPtr p1;
- public IntPtr p2;
-}
diff --git a/Common/Net/IP/TCPIP_OWNER_MODULE_INFO_CLASS.cs b/Common/Net/IP/TCPIP_OWNER_MODULE_INFO_CLASS.cs
deleted file mode 100644
index 552bbc7..0000000
--- a/Common/Net/IP/TCPIP_OWNER_MODULE_INFO_CLASS.cs
+++ /dev/null
@@ -1,6 +0,0 @@
-namespace Wokhan.WindowsFirewallNotifier.Common.Net.IP;
-
-internal enum TCPIP_OWNER_MODULE_INFO_CLASS
-{
- TCPIP_OWNER_MODULE_INFO_BASIC
-}
diff --git a/Common/Net/IP/UDP/NativeMethods.cs b/Common/Net/IP/UDP/NativeMethods.cs
deleted file mode 100644
index e9e181a..0000000
--- a/Common/Net/IP/UDP/NativeMethods.cs
+++ /dev/null
@@ -1,12 +0,0 @@
-using System;
-using System.Runtime.InteropServices;
-
-using static Wokhan.WindowsFirewallNotifier.Common.Net.IP.IPHelper;
-
-namespace Wokhan.WindowsFirewallNotifier.Common.Net.IP.UDP;
-
-internal static partial class NativeMethods
-{
- [LibraryImport("iphlpapi.dll", SetLastError = true)]
- internal static partial uint GetExtendedUdpTable(IntPtr pUdpTable, ref int dwOutBufLen, [MarshalAs(UnmanagedType.Bool)] bool sort, AF_INET ipVersion, UDP_TABLE_CLASS tblClass, uint reserved);
-}
diff --git a/Common/Net/IP/UDP/UDP4/MIB_UDPROW_OWNER_MODULE.cs b/Common/Net/IP/UDP/UDP4/MIB_UDPROW_OWNER_MODULE.cs
deleted file mode 100644
index 2f5ac1d..0000000
--- a/Common/Net/IP/UDP/UDP4/MIB_UDPROW_OWNER_MODULE.cs
+++ /dev/null
@@ -1,43 +0,0 @@
-using System;
-using System.Net;
-using System.Runtime.InteropServices;
-
-using Wokhan.WindowsFirewallNotifier.Common.Net.IP.TCP;
-
-namespace Wokhan.WindowsFirewallNotifier.Common.Net.IP.UDP.UDP4;
-
-[StructLayout(LayoutKind.Sequential)]
-internal struct MIB_UDPROW_OWNER_MODULE : IConnectionOwnerInfo
-{
- [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]//, FieldOffset(0)]
- internal byte[] _localAddr;
- [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]//, FieldOffset(4)]
- internal byte[] _localPort;
- //[FieldOffset(8)]
- internal uint _owningPid;
- //[FieldOffset(16)]
- internal long _creationTime;
- //[FieldOffset(24)]
- //public int SpecificPortBind;
- //[FieldOffset(24)]
- internal int _flags;
- [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] //FieldOffset(32),
- internal ulong[] _owningModuleInfo;
-
- public byte[] RemoteAddrBytes => Array.Empty();
- public ConnectionStatus State => ConnectionStatus.NOT_APPLICABLE;
- public uint OwningPid => _owningPid;
- public string LocalAddress => IPHelper.GetAddressAsString(_localAddr);
- public int LocalPort => IPHelper.GetRealPort(_localPort);
- public Owner? OwnerModule => IPHelper.GetOwningModuleInternal(NativeMethods.GetOwnerModuleFromUdpEntry, this);
- public string Protocol => "UDP";
- public DateTime? CreationTime => _creationTime == 0 ? null : DateTime.FromFileTime(_creationTime);
- public string RemoteAddress => string.Empty;
- public int RemotePort => -1;
- public bool IsLoopback => IPAddress.IsLoopback(IPAddress.Parse(RemoteAddress));
-
- public ITcpRow ToTcpRow()
- {
- throw new NotImplementedException("UDP connections owner details cannot be mapped to TCP connections rows.");
- }
-}
diff --git a/Common/Net/IP/UDP/UDP4/MIB_UDPTABLE_OWNER_MODULE.cs b/Common/Net/IP/UDP/UDP4/MIB_UDPTABLE_OWNER_MODULE.cs
deleted file mode 100644
index 762cee3..0000000
--- a/Common/Net/IP/UDP/UDP4/MIB_UDPTABLE_OWNER_MODULE.cs
+++ /dev/null
@@ -1,10 +0,0 @@
-using System.Runtime.InteropServices;
-
-namespace Wokhan.WindowsFirewallNotifier.Common.Net.IP.UDP.UDP4;
-
-[StructLayout(LayoutKind.Sequential)]
-internal struct MIB_UDPTABLE_OWNER_MODULE
-{
- public uint NumEntries;
- public MIB_UDPROW_OWNER_MODULE FirstEntry;
-}
diff --git a/Common/Net/IP/UDP/UDP4/NativeMethods.cs b/Common/Net/IP/UDP/UDP4/NativeMethods.cs
deleted file mode 100644
index 728f5b8..0000000
--- a/Common/Net/IP/UDP/UDP4/NativeMethods.cs
+++ /dev/null
@@ -1,13 +0,0 @@
-using System;
-using System.Runtime.InteropServices;
-
-using static Wokhan.WindowsFirewallNotifier.Common.Net.IP.IPHelper;
-
-namespace Wokhan.WindowsFirewallNotifier.Common.Net.IP.UDP.UDP4;
-
-internal static partial class NativeMethods
-{
- [DllImport("iphlpapi.dll", SetLastError = true)]
- internal static extern uint GetOwnerModuleFromUdpEntry(MIB_UDPROW_OWNER_MODULE pUdpEntry, TCPIP_OWNER_MODULE_INFO_CLASS Class, IntPtr Buffer, ref uint pdwSize);
-
-}
diff --git a/Common/Net/IP/UDP/UDP6/MIB_UDP6ROW_OWNER_MODULE.cs b/Common/Net/IP/UDP/UDP6/MIB_UDP6ROW_OWNER_MODULE.cs
deleted file mode 100644
index ec7ac06..0000000
--- a/Common/Net/IP/UDP/UDP6/MIB_UDP6ROW_OWNER_MODULE.cs
+++ /dev/null
@@ -1,43 +0,0 @@
-using System;
-using System.Net;
-using System.Runtime.InteropServices;
-
-using Wokhan.WindowsFirewallNotifier.Common.Net.IP.TCP;
-
-namespace Wokhan.WindowsFirewallNotifier.Common.Net.IP.UDP.UDP6;
-
-[StructLayout(LayoutKind.Sequential)]
-internal struct MIB_UDP6ROW_OWNER_MODULE : IConnectionOwnerInfo
-{
- [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
- internal byte[] _localAddress;
- internal uint LocalScopeId;
- [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
- internal byte[] _localPort;
- internal uint _owningPid;
- //[FieldOffset(16)]
- internal long _creationTime;
- //[FieldOffset(24)]
- //public int SpecificPortBind;
- //[FieldOffset(24)]
- internal int Flags;
- [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] //FieldOffset(32),
- internal ulong[] OwningModuleInfo;
-
- public byte[] RemoteAddrBytes => Array.Empty();
- public ConnectionStatus State => ConnectionStatus.NOT_APPLICABLE;
- public uint OwningPid => _owningPid;
- public string LocalAddress => IPHelper.GetRealAddress(_localAddress);
- public int LocalPort => IPHelper.GetRealPort(_localPort);
- public Owner? OwnerModule => IPHelper.GetOwningModuleInternal(NativeMethods.GetOwnerModuleFromUdp6Entry, this);
- public string Protocol => "UDP";
- public string RemoteAddress => string.Empty;
- public int RemotePort => -1;
- public DateTime? CreationTime => _creationTime == 0 ? (DateTime?)null : DateTime.FromFileTime(_creationTime);
- public bool IsLoopback => IPAddress.IsLoopback(IPAddress.Parse(RemoteAddress));
-
- public ITcpRow ToTcpRow()
- {
- throw new NotImplementedException("UDP connections owner details cannot be mapped to TCP connections rows.");
- }
-}
diff --git a/Common/Net/IP/UDP/UDP6/MIB_UDP6TABLE_OWNER_MODULE.cs b/Common/Net/IP/UDP/UDP6/MIB_UDP6TABLE_OWNER_MODULE.cs
deleted file mode 100644
index d6eb52d..0000000
--- a/Common/Net/IP/UDP/UDP6/MIB_UDP6TABLE_OWNER_MODULE.cs
+++ /dev/null
@@ -1,10 +0,0 @@
-using System.Runtime.InteropServices;
-
-namespace Wokhan.WindowsFirewallNotifier.Common.Net.IP.UDP.UDP6;
-
-[StructLayout(LayoutKind.Sequential)]
-internal struct MIB_UDP6TABLE_OWNER_MODULE
-{
- public uint NumEntries;
- public MIB_UDP6ROW_OWNER_MODULE FirstEntry;
-}
diff --git a/Common/Net/IP/UDP/UDP6/NativeMethods.cs b/Common/Net/IP/UDP/UDP6/NativeMethods.cs
deleted file mode 100644
index 38fc470..0000000
--- a/Common/Net/IP/UDP/UDP6/NativeMethods.cs
+++ /dev/null
@@ -1,10 +0,0 @@
-using System;
-using System.Runtime.InteropServices;
-
-namespace Wokhan.WindowsFirewallNotifier.Common.Net.IP.UDP.UDP6;
-
-internal static class NativeMethods
-{
- [DllImport("iphlpapi.dll", SetLastError = true)]
- internal static extern uint GetOwnerModuleFromUdp6Entry(MIB_UDP6ROW_OWNER_MODULE pUdpEntry, TCPIP_OWNER_MODULE_INFO_CLASS Class, IntPtr Buffer, ref uint pdwSize);
-}
diff --git a/Common/Net/IP/UDP/UDPHelper.cs b/Common/Net/IP/UDP/UDPHelper.cs
deleted file mode 100644
index f377375..0000000
--- a/Common/Net/IP/UDP/UDPHelper.cs
+++ /dev/null
@@ -1,56 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.ComponentModel;
-using System.Runtime.InteropServices;
-
-using static Wokhan.WindowsFirewallNotifier.Common.Net.IP.IPHelper;
-
-namespace Wokhan.WindowsFirewallNotifier.Common.Net.IP.UDP;
-
-public class UDPHelper
-{
- internal static IEnumerable GetAllUDPConnections(AF_INET aF_INET) where TRow : IConnectionOwnerInfo
- {
- IntPtr buffTable = IntPtr.Zero;
-
- try
- {
- var buffSize = 0;
- _ = NativeMethods.GetExtendedUdpTable(IntPtr.Zero, ref buffSize, false, aF_INET, UDP_TABLE_CLASS.UDP_TABLE_OWNER_MODULE, 0);
-
- buffTable = Marshal.AllocHGlobal(buffSize);
-
- var ret = NativeMethods.GetExtendedUdpTable(buffTable, ref buffSize, false, aF_INET, UDP_TABLE_CLASS.UDP_TABLE_OWNER_MODULE, 0);
- if (ret == 0)
- {
- var tab = Marshal.PtrToStructure(buffTable);
- var rowPtr = (IntPtr)((long)buffTable + (long)Marshal.OffsetOf(nameof(UDP4.MIB_UDPTABLE_OWNER_MODULE.FirstEntry)));
-
- TRow current;
- for (var i = 0; i < tab.NumEntries; i++)
- {
- current = Marshal.PtrToStructure(rowPtr);
- rowPtr = (IntPtr)((long)rowPtr + Marshal.SizeOf(current));
-
- yield return current;
-
- }
- }
- else
- {
- throw new Win32Exception((int)ret);
- }
- }
- finally
- {
- if (buffTable != IntPtr.Zero)
- {
- Marshal.FreeHGlobal(buffTable);
- }
- }
- }
-
- public static IEnumerable GetAllUDPConnections() => GetAllUDPConnections(AF_INET.IP4);
- public static IEnumerable GetAllUDP6Connections() => GetAllUDPConnections(AF_INET.IP6);
-
-}
diff --git a/Common/Net/IP/UDP/UDP_TABLE_CLASS.cs b/Common/Net/IP/UDP/UDP_TABLE_CLASS.cs
deleted file mode 100644
index fc8068c..0000000
--- a/Common/Net/IP/UDP/UDP_TABLE_CLASS.cs
+++ /dev/null
@@ -1,8 +0,0 @@
-namespace Wokhan.WindowsFirewallNotifier.Common.Net.IP.UDP;
-
-internal enum UDP_TABLE_CLASS
-{
- UDP_TABLE_BASIC,
- UDP_TABLE_OWNER_PID,
- UDP_TABLE_OWNER_MODULE
-}
diff --git a/Common/Processes/NativeMethods.txt b/Common/Processes/NativeMethods.txt
new file mode 100644
index 0000000..77cf444
--- /dev/null
+++ b/Common/Processes/NativeMethods.txt
@@ -0,0 +1,8 @@
+OpenProcess
+OpenProcessToken
+GetTokenInformation
+TOKEN_USER
+ConvertSidToStringSidW
+CloseHandle
+ShowWindow
+SetForegroundWindow
\ No newline at end of file
diff --git a/Common/Processes/ProcessHelper.NativeMethods.cs b/Common/Processes/ProcessHelper.NativeMethods.cs
deleted file mode 100644
index b2f0683..0000000
--- a/Common/Processes/ProcessHelper.NativeMethods.cs
+++ /dev/null
@@ -1,129 +0,0 @@
-using System;
-using System.Runtime.InteropServices;
-
-namespace Wokhan.WindowsFirewallNotifier.Common.Processes;
-
-public static partial class ProcessHelper
-{
- protected static partial class NativeMethods
- {
- [Flags]
- internal enum ProcessAccessFlags : uint
- {
- All = 0x001F0FFF,
- Terminate = 0x00000001,
- CreateThread = 0x00000002,
- VirtualMemoryOperation = 0x00000008,
- VirtualMemoryRead = 0x00000010,
- VirtualMemoryWrite = 0x00000020,
- DuplicateHandle = 0x00000040,
- CreateProcess = 0x000000080,
- SetQuota = 0x00000100,
- SetInformation = 0x00000200,
- QueryInformation = 0x00000400,
- QueryLimitedInformation = 0x00001000,
- Synchronize = 0x00100000
- }
-
- internal enum TOKEN_INFORMATION_CLASS
- {
- TokenUser = 1,
- TokenGroups,
- TokenPrivileges,
- TokenOwner,
- TokenPrimaryGroup,
- TokenDefaultDacl,
- TokenSource,
- TokenType,
- TokenImpersonationLevel,
- TokenStatistics,
- TokenRestrictedSids,
- TokenSessionId,
- TokenGroupsAndPrivileges,
- TokenSessionReference,
- TokenSandBoxInert,
- TokenAuditPolicy,
- TokenOrigin,
- TokenElevationType,
- TokenLinkedToken,
- TokenElevation,
- TokenHasRestrictions,
- TokenAccessInformation,
- TokenVirtualizationAllowed,
- TokenVirtualizationEnabled,
- TokenIntegrityLevel,
- TokenUIAccess,
- TokenMandatoryPolicy,
- TokenLogonSid,
- TokenIsAppContainer,
- TokenCapabilities,
- TokenAppContainerSid,
- TokenAppContainerNumber,
- TokenUserClaimAttributes,
- TokenDeviceClaimAttributes,
- TokenRestrictedUserClaimAttributes,
- TokenRestrictedDeviceClaimAttributes,
- TokenDeviceGroups,
- TokenRestrictedDeviceGroups,
- TokenSecurityAttributes,
- TokenIsRestricted,
- MaxTokenInfoClass
- }
-
- [StructLayout(LayoutKind.Sequential)]
- internal struct TOKEN_USER
- {
- public SID_AND_ATTRIBUTES User;
- }
-
- [StructLayout(LayoutKind.Sequential)]
- internal struct SID_AND_ATTRIBUTES
- {
- public IntPtr Sid;
- public int Attributes;
- }
-
-
- internal const uint ERROR_SUCCESS = 0;
- internal const uint APPMODEL_ERROR_NO_PACKAGE = 15700;
- internal const uint S_OK = 0x00000000;
-
- [LibraryImport("kernel32.dll", SetLastError = true)]
- internal static partial IntPtr OpenProcess(ProcessAccessFlags dwDesiredAccess, [MarshalAs(UnmanagedType.Bool)] bool bInheritHandle, uint dwProcessId);
-
- internal const int TOKEN_QUERY = 0X00000008;
-
- [LibraryImport("kernel32.dll", SetLastError = true)]
- [return: MarshalAs(UnmanagedType.Bool)]
- internal static partial bool OpenProcessToken(IntPtr ProcessHandle, uint DesiredAccess, out IntPtr TokenHandle);
-
- [LibraryImport("advapi32", SetLastError = true)]
- [return: MarshalAs(UnmanagedType.Bool)]
- internal static partial bool GetTokenInformation(IntPtr hToken, TOKEN_INFORMATION_CLASS TokenInformationClass, IntPtr TokenInformation, uint dwTokenInfoLength, ref uint dwReturnLength);
-
- [LibraryImport("advapi32", SetLastError = true, StringMarshalling = StringMarshalling.Utf16)]
- [return: MarshalAs(UnmanagedType.Bool)]
- internal static partial bool ConvertSidToStringSidW(IntPtr pSID, [MarshalAs(UnmanagedType.LPTStr)] out string pStringSid);
-
- [LibraryImport("kernel32.dll", SetLastError = true)]
- [return: MarshalAs(UnmanagedType.Bool)]
- internal static partial bool CloseHandle(IntPtr hObject);
-
- [LibraryImport("user32.dll")]
- [return: MarshalAs(UnmanagedType.Bool)]
- internal static partial bool ShowWindow(IntPtr hWnd, ShowWindowEnum flags);
-
- [LibraryImport("user32.dll")]
- internal static partial int SetForegroundWindow(IntPtr hwnd);
-
- internal enum ShowWindowEnum
- {
- Hide = 0,
- ShowNormal = 1, ShowMinimized = 2, ShowMaximized = 3,
- Maximize = 3, ShowNormalNoActivate = 4, Show = 5,
- Minimize = 6, ShowMinNoActivate = 7, ShowNoActivate = 8,
- Restore = 9, ShowDefault = 10, ForceMinimized = 11
- };
- }
-
-}
\ No newline at end of file
diff --git a/Common/Processes/ProcessHelper.cs b/Common/Processes/ProcessHelper.cs
index 15b72ca..9731102 100644
--- a/Common/Processes/ProcessHelper.cs
+++ b/Common/Processes/ProcessHelper.cs
@@ -1,12 +1,18 @@
-using System;
+using Microsoft.Win32.SafeHandles;
+
+using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Management;
-using System.Runtime.InteropServices;
using System.Windows;
+using Windows.Win32;
+using Windows.Win32.Foundation;
+using Windows.Win32.Security;
+using Windows.Win32.System.Threading;
+
using Wokhan.WindowsFirewallNotifier.Common.Logging;
namespace Wokhan.WindowsFirewallNotifier.Common.Processes;
@@ -184,62 +190,52 @@ public static Dictionary GetAllServicesByPidWMI()
- public static string GetLocalUserOwner(uint pid)
+ public unsafe static string GetLocalUserOwner(uint pid)
{
//Based on: https://bytes.com/topic/c-sharp/answers/225065-how-call-win32-native-api-gettokeninformation-using-c
- IntPtr hProcess = NativeMethods.OpenProcess(NativeMethods.ProcessAccessFlags.QueryInformation, false, pid);
- if (hProcess == IntPtr.Zero)
+ var hProcess = NativeMethods.OpenProcess_SafeHandle(PROCESS_ACCESS_RIGHTS.PROCESS_QUERY_INFORMATION, false, pid);
+ if (hProcess is null)
{
LogHelper.Warning($"Unable to retrieve process local user owner: process pid={pid} cannot be found!");
return String.Empty;
}
- IntPtr hToken = IntPtr.Zero;
- IntPtr hTokenInformation = IntPtr.Zero;
+ SafeFileHandle hToken = new SafeFileHandle();
+ TOKEN_USER hTokenInformation;
try
{
- if (!NativeMethods.OpenProcessToken(hProcess, NativeMethods.TOKEN_QUERY, out hToken))
+ if (!NativeMethods.OpenProcessToken(hProcess, TOKEN_ACCESS_MASK.TOKEN_QUERY, out hToken))
{
LogHelper.Warning("Unable to retrieve process local user owner: process pid={pid} cannot be opened!");
return String.Empty;
}
- uint dwBufSize = 0;
//TODO: Wait... isn't a negation missing here?!
- if (NativeMethods.GetTokenInformation(hToken, NativeMethods.TOKEN_INFORMATION_CLASS.TokenUser, IntPtr.Zero, 0, ref dwBufSize))
+ if (NativeMethods.GetTokenInformation(hToken, TOKEN_INFORMATION_CLASS.TokenUser, null, 0, out var dwBufSize))
{
LogHelper.Warning("Unexpected result from call to GetTokenInformation.");
return String.Empty;
}
- hTokenInformation = Marshal.AllocHGlobal((int)dwBufSize);
- if (!NativeMethods.GetTokenInformation(hToken, NativeMethods.TOKEN_INFORMATION_CLASS.TokenUser, hTokenInformation, dwBufSize, ref dwBufSize))
+ hTokenInformation = new TOKEN_USER();
+ if (!NativeMethods.GetTokenInformation(hToken, TOKEN_INFORMATION_CLASS.TokenUser, &hTokenInformation, dwBufSize, out dwBufSize))
{
LogHelper.Warning("Unable to retrieve process local user owner: token cannot be opened!");
return String.Empty;
}
- if (!NativeMethods.ConvertSidToStringSidW(Marshal.PtrToStructure(hTokenInformation).User.Sid, out string SID))
+ if (!NativeMethods.ConvertSidToStringSid(hTokenInformation.User.Sid, out PWSTR SID))
{
LogHelper.Warning("Unable to retrieve process local user owner: SID cannot be converted!");
return String.Empty;
}
- return SID;
+ return SID.ToString();
}
finally
{
- if (hTokenInformation != IntPtr.Zero)
- {
- Marshal.FreeHGlobal(hTokenInformation);
- }
-
- if (hToken != IntPtr.Zero)
- {
- NativeMethods.CloseHandle(hToken);
- }
-
- NativeMethods.CloseHandle(hProcess);
+ hToken?.Close();
+ hProcess?.Close();
}
}
@@ -415,11 +411,12 @@ public static void StartOrRestoreToForeground(ProcessNames processName)
if (bProcess.MainWindowHandle == IntPtr.Zero)
{
// the window is hidden so try to restore it before setting focus.
- NativeMethods.ShowWindow(bProcess.Handle, NativeMethods.ShowWindowEnum.Restore);
+ //TODO: this cannot work, obviously. The handle isn't the right one.
+ //NativeMethods.ShowWindow((HWND)bProcess.Handle, Windows.Win32.UI.WindowsAndMessaging.SHOW_WINDOW_CMD.SW_RESTORE);
}
// set user the focus to the window
- _ = NativeMethods.SetForegroundWindow(bProcess.MainWindowHandle);
+ _ = NativeMethods.SetForegroundWindow((HWND)bProcess.MainWindowHandle);
}
else
{
diff --git a/Common/Security/NativeMethods.txt b/Common/Security/NativeMethods.txt
new file mode 100644
index 0000000..c6fe3d8
--- /dev/null
+++ b/Common/Security/NativeMethods.txt
@@ -0,0 +1,4 @@
+GetTokenInformation
+CloseHandle
+
+TOKEN_ELEVATION_TYPE
\ No newline at end of file
diff --git a/Common/Security/UAC.NativeMethods.cs b/Common/Security/UAC.NativeMethods.cs
deleted file mode 100644
index 3d8e159..0000000
--- a/Common/Security/UAC.NativeMethods.cs
+++ /dev/null
@@ -1,74 +0,0 @@
-/* This code has based on http://stackoverflow.com/questions/1220213/detect-if-running-as-administrator-with-or-without-elevated-privileges
- Assumed author: Scott Chamberlain
-
- With additions from https://code.msdn.microsoft.com/windowsdesktop/CSUACSelfElevation-644673d3/
-*/
-using System;
-using System.Runtime.InteropServices;
-
-namespace Wokhan.WindowsFirewallNotifier.Common.Helpers;
-
-public static partial class UAC
-{
- protected static partial class NativeMethods
- {
- internal const string UAC_REGISTRY_KEY = "Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\System";
- internal const string UAC_REGISTRY_VALUE = "EnableLUA";
-
- internal const uint STANDARD_RIGHTS_READ = 0x00020000;
- internal const uint TOKEN_QUERY = 0x0008;
- //internal const uint TOKEN_READ = (STANDARD_RIGHTS_READ | TOKEN_QUERY);
-
- [LibraryImport("advapi32.dll", SetLastError = true)]
- [return: MarshalAs(UnmanagedType.Bool)]
- internal static partial bool OpenProcessToken(IntPtr ProcessHandle, uint DesiredAccess, out IntPtr TokenHandle);
-
- [LibraryImport("kernel32.dll", SetLastError = true)]
- [return: MarshalAs(UnmanagedType.Bool)]
- internal static partial bool CloseHandle(IntPtr hObject);
-
- [LibraryImport("advapi32.dll", SetLastError = true)]
- [return: MarshalAs(UnmanagedType.Bool)]
- internal static partial bool GetTokenInformation(IntPtr TokenHandle, TOKEN_INFORMATION_CLASS TokenInformationClass, IntPtr TokenInformation, uint TokenInformationLength, out uint ReturnLength);
-
- internal enum TOKEN_INFORMATION_CLASS
- {
- TokenUser = 1,
- TokenGroups,
- TokenPrivileges,
- TokenOwner,
- TokenPrimaryGroup,
- TokenDefaultDacl,
- TokenSource,
- TokenType,
- TokenImpersonationLevel,
- TokenStatistics,
- TokenRestrictedSids,
- TokenSessionId,
- TokenGroupsAndPrivileges,
- TokenSessionReference,
- TokenSandBoxInert,
- TokenAuditPolicy,
- TokenOrigin,
- TokenElevationType,
- TokenLinkedToken,
- TokenElevation,
- TokenHasRestrictions,
- TokenAccessInformation,
- TokenVirtualizationAllowed,
- TokenVirtualizationEnabled,
- TokenIntegrityLevel,
- TokenUIAccess,
- TokenMandatoryPolicy,
- TokenLogonSid,
- MaxTokenInfoClass
- }
-
- internal enum TOKEN_ELEVATION_TYPE
- {
- TokenElevationTypeDefault = 1,
- TokenElevationTypeFull,
- TokenElevationTypeLimited
- }
- }
-}
\ No newline at end of file
diff --git a/Common/Security/UAC.cs b/Common/Security/UAC.cs
index f8cfc57..0fe1c40 100644
--- a/Common/Security/UAC.cs
+++ b/Common/Security/UAC.cs
@@ -4,55 +4,63 @@
With additions from https://code.msdn.microsoft.com/windowsdesktop/CSUACSelfElevation-644673d3/
*/
using Microsoft.Win32;
+using Microsoft.Win32.SafeHandles;
+
using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Security.Principal;
+using Windows.Win32;
+using Windows.Win32.Security;
+
namespace Wokhan.WindowsFirewallNotifier.Common.Helpers;
public static partial class UAC
{
+ internal const string UAC_REGISTRY_KEY = "Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\System";
+ internal const string UAC_REGISTRY_VALUE = "EnableLUA";
+
+ internal const uint STANDARD_RIGHTS_READ = 0x00020000;
+ internal const uint TOKEN_QUERY = 0x0008;
+
public static bool CheckUAC()
{
- using RegistryKey uacKey = Registry.LocalMachine.OpenSubKey(NativeMethods.UAC_REGISTRY_KEY, false);
+ using RegistryKey uacKey = Registry.LocalMachine.OpenSubKey(UAC_REGISTRY_KEY, false);
- return uacKey.GetValue(NativeMethods.UAC_REGISTRY_VALUE).Equals(1);
+ return uacKey.GetValue(UAC_REGISTRY_VALUE).Equals(1);
}
- public static bool CheckProcessElevated()
+ public unsafe static bool CheckProcessElevated()
{
if (CheckUAC())
{
- IntPtr tokenHandle = IntPtr.Zero;
- if (!NativeMethods.OpenProcessToken(Process.GetCurrentProcess().Handle, NativeMethods.TOKEN_QUERY, out tokenHandle))
+ if (!NativeMethods.OpenProcessToken(Process.GetCurrentProcess().SafeHandle, TOKEN_ACCESS_MASK.TOKEN_QUERY, out SafeFileHandle tokenHandle))
{
throw new Win32Exception(Marshal.GetLastWin32Error(), "Could not get process token.");
}
try
{
- uint returnedSize = sizeof(NativeMethods.TOKEN_ELEVATION_TYPE);
-
- IntPtr elevationTypePtr = Marshal.AllocHGlobal((int)returnedSize);
+ uint returnedSize = sizeof(TOKEN_ELEVATION_TYPE);
+ var elevationType = new TOKEN_ELEVATION_TYPE();
try
{
- if (NativeMethods.GetTokenInformation(tokenHandle, NativeMethods.TOKEN_INFORMATION_CLASS.TokenElevationType, elevationTypePtr, returnedSize, out returnedSize))
+ if (NativeMethods.GetTokenInformation(tokenHandle, TOKEN_INFORMATION_CLASS.TokenElevationType, &elevationType, returnedSize, out returnedSize))
{
- NativeMethods.TOKEN_ELEVATION_TYPE elevationResult = (NativeMethods.TOKEN_ELEVATION_TYPE)Marshal.ReadInt32(elevationTypePtr);
- switch (elevationResult)
+ switch (elevationType)
{
- case NativeMethods.TOKEN_ELEVATION_TYPE.TokenElevationTypeDefault:
+ case TOKEN_ELEVATION_TYPE.TokenElevationTypeDefault:
//Token is not split; if user is admin, we're admin.
WindowsPrincipal principal = new WindowsPrincipal(WindowsIdentity.GetCurrent());
return principal.IsInRole(WindowsBuiltInRole.Administrator) || principal.IsInRole(0x200); //Domain Administrator
- case NativeMethods.TOKEN_ELEVATION_TYPE.TokenElevationTypeFull:
+ case TOKEN_ELEVATION_TYPE.TokenElevationTypeFull:
//Token is split, but we're admin.
return true;
- case NativeMethods.TOKEN_ELEVATION_TYPE.TokenElevationTypeLimited:
+ case TOKEN_ELEVATION_TYPE.TokenElevationTypeLimited:
//Token is split, and we're limited.
return false;
@@ -67,18 +75,15 @@ public static bool CheckProcessElevated()
}
finally
{
- if (elevationTypePtr != IntPtr.Zero)
- {
- Marshal.FreeHGlobal(elevationTypePtr);
- }
+ //if (elevationTypePtr != IntPtr.Zero)
+ //{
+ // Marshal.FreeHGlobal(elevationTypePtr);
+ //}
}
}
finally
{
- if (tokenHandle != IntPtr.Zero)
- {
- NativeMethods.CloseHandle(tokenHandle);
- }
+ tokenHandle?.Close();
}
}
else
diff --git a/Common/UAP/NativeMethods.txt b/Common/UAP/NativeMethods.txt
new file mode 100644
index 0000000..2da89ce
--- /dev/null
+++ b/Common/UAP/NativeMethods.txt
@@ -0,0 +1,9 @@
+GetPackageFamilyName
+DeriveAppContainerSidFromAppContainerName
+OpenProcess
+ConvertSidToStringSid
+FreeSid
+CloseHandle
+
+ERROR_SUCCESS
+APPMODEL_ERROR_NO_PACKAGE
\ No newline at end of file
diff --git a/Common/UAP/StorePackageHelper.NativeMethods.cs b/Common/UAP/StorePackageHelper.NativeMethods.cs
deleted file mode 100644
index b3b1c4f..0000000
--- a/Common/UAP/StorePackageHelper.NativeMethods.cs
+++ /dev/null
@@ -1,61 +0,0 @@
-using System;
-using System.Runtime.InteropServices;
-
-namespace Wokhan.WindowsFirewallNotifier.Common.UAP;
-
-public static partial class StorePackageHelper
-{
- protected static partial class NativeMethods
- {
- [Flags]
- internal enum ProcessAccessFlags : uint
- {
- All = 0x001F0FFF,
- Terminate = 0x00000001,
- CreateThread = 0x00000002,
- VirtualMemoryOperation = 0x00000008,
- VirtualMemoryRead = 0x00000010,
- VirtualMemoryWrite = 0x00000020,
- DuplicateHandle = 0x00000040,
- CreateProcess = 0x000000080,
- SetQuota = 0x00000100,
- SetInformation = 0x00000200,
- QueryInformation = 0x00000400,
- QueryLimitedInformation = 0x00001000,
- Synchronize = 0x00100000
- }
-
- //Note: Only exists on Windows 8 and higher
- /*[DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
- internal static extern uint GetPackageFullName(IntPtr hProcess, ref uint packageFullNameLength, StringBuilder packageFullName);*/
-
- //Note: Only exists on Windows 8 and higher
- [LibraryImport("kernel32.dll")]
- internal static unsafe partial uint GetPackageFamilyName(IntPtr hProcess, ref uint packageFamilyNameLength, char* packageFamilyName);
-
- //Note: Only exists on Windows 8 and higher
- [LibraryImport("userenv.dll", StringMarshalling = StringMarshalling.Utf16)]
- internal static partial uint DeriveAppContainerSidFromAppContainerName(string pszAppContainerName, out IntPtr ppsidAppContainerSid);
-
- internal const uint ERROR_SUCCESS = 0;
- internal const uint APPMODEL_ERROR_NO_PACKAGE = 15700;
- internal const uint S_OK = 0x00000000;
-
- [LibraryImport("kernel32.dll", SetLastError = true)]
- internal static partial IntPtr OpenProcess(ProcessAccessFlags dwDesiredAccess, [MarshalAs(UnmanagedType.Bool)] bool bInheritHandle, uint dwProcessId);
-
- internal const int TOKEN_QUERY = 0X00000008;
-
- [LibraryImport("advapi32", SetLastError = true, StringMarshalling = StringMarshalling.Utf16)]
- [return: MarshalAs(UnmanagedType.Bool)]
- internal static partial bool ConvertSidToStringSidW(IntPtr pSID, [MarshalAs(UnmanagedType.LPTStr)] out string pStringSid);
-
- [LibraryImport("advapi32")]
- internal static partial IntPtr FreeSid(IntPtr pSid);
-
- [LibraryImport("kernel32.dll", SetLastError = true)]
- [return: MarshalAs(UnmanagedType.Bool)]
- internal static partial bool CloseHandle(IntPtr hObject);
- }
-
-}
\ No newline at end of file
diff --git a/Common/UAP/StorePackageHelper.cs b/Common/UAP/StorePackageHelper.cs
index 9d7d51f..e523856 100644
--- a/Common/UAP/StorePackageHelper.cs
+++ b/Common/UAP/StorePackageHelper.cs
@@ -1,18 +1,17 @@
using Microsoft.Win32;
using System;
-using System.Collections.Generic;
-using System.Drawing;
using System.IO;
using System.Linq;
-using System.Reflection;
-using System.Text;
using System.Threading.Tasks;
-using System.Windows.Media.Imaging;
using System.Xml;
using System.Xml.Linq;
using System.Xml.XPath;
+using Windows.Win32;
+using Windows.Win32.Foundation;
+using Windows.Win32.System.Threading;
+
using Wokhan.WindowsFirewallNotifier.Common.Logging;
namespace Wokhan.WindowsFirewallNotifier.Common.UAP;
@@ -31,11 +30,11 @@ static StorePackageHelper()
{
return Task.Run(() =>
{
- var path = (string?)Registry.ClassesRoot.OpenSubKey($"Local Settings\\Software\\Microsoft\\Windows\\CurrentVersion\\AppModel\\Repository\\Packages\\{packageName}")?.GetValue("PackageRootFolder");
- string? logo = null;
- string? executable = null;
- string? name = null;
- string? description = null;
+ var path = (string?)Registry.ClassesRoot.OpenSubKey($"Local Settings\\Software\\Microsoft\\Windows\\CurrentVersion\\AppModel\\Repository\\Packages\\{packageName}")?.GetValue("PackageRootFolder");
+ string? logo = null;
+ string? executable = null;
+ string? name = null;
+ string? description = null;
if (path is not null)
{
@@ -65,7 +64,10 @@ static StorePackageHelper()
static readonly Version minVersionForApps = new Version(6, 2);
- public static string? GetAppPkgId(uint pid)
+
+
+
+ public unsafe static string? GetAppPkgId(uint pid)
{
if (Environment.OSVersion.Version <= minVersionForApps)
{
@@ -73,8 +75,8 @@ static StorePackageHelper()
return String.Empty;
}
- IntPtr hProcess = NativeMethods.OpenProcess(NativeMethods.ProcessAccessFlags.QueryLimitedInformation, false, pid);
- if (hProcess == IntPtr.Zero)
+ var hProcess = NativeMethods.OpenProcess_SafeHandle(PROCESS_ACCESS_RIGHTS.PROCESS_QUERY_LIMITED_INFORMATION, false, pid);
+ if (hProcess is null)
{
LogHelper.Warning("Unable to retrieve process package id: process cannot be found!");
return String.Empty;
@@ -84,30 +86,27 @@ static StorePackageHelper()
//Based on: https://github.com/jimschubert/clr-profiler/blob/master/src/CLRProfiler45Source/WindowsStoreAppHelper/WindowsStoreAppHelper.cs
uint packageFamilyNameLength = 0;
string packageFamilyName;
- unsafe
- {
- uint retGetPFName = NativeMethods.GetPackageFamilyName(hProcess, ref packageFamilyNameLength, null);
- if ((retGetPFName == NativeMethods.APPMODEL_ERROR_NO_PACKAGE) || (packageFamilyNameLength == 0))
- {
- // Not a WindowsStoreApp process
- return String.Empty;
- }
- // Call again, now that we know the size
- char* packageFamilyNameBld = stackalloc char[(int)packageFamilyNameLength];
- retGetPFName = NativeMethods.GetPackageFamilyName(hProcess, ref packageFamilyNameLength, packageFamilyNameBld);
- if (retGetPFName != NativeMethods.ERROR_SUCCESS)
- {
- LogHelper.Warning("Unable to retrieve process package id: failed to retrieve family package name!");
- return String.Empty;
- }
+ var retGetPFName = NativeMethods.GetPackageFamilyName(hProcess, ref packageFamilyNameLength, null);
+ if ((retGetPFName == WIN32_ERROR.APPMODEL_ERROR_NO_PACKAGE) || (packageFamilyNameLength == 0))
+ {
+ // Not a WindowsStoreApp process
+ return String.Empty;
+ }
- packageFamilyName = new String(packageFamilyNameBld);
+ // Call again, now that we know the size
+ char* packageFamilyNameBld = stackalloc char[(int)packageFamilyNameLength];
+ retGetPFName = NativeMethods.GetPackageFamilyName(hProcess, ref packageFamilyNameLength, packageFamilyNameBld);
+ if (retGetPFName != WIN32_ERROR.ERROR_SUCCESS)
+ {
+ LogHelper.Warning("Unable to retrieve process package id: failed to retrieve family package name!");
+ return String.Empty;
}
- IntPtr pSID;
- uint ret = NativeMethods.DeriveAppContainerSidFromAppContainerName(packageFamilyName, out pSID);
- if (ret != NativeMethods.S_OK)
+ packageFamilyName = new String(packageFamilyNameBld);
+
+ uint ret = NativeMethods.DeriveAppContainerSidFromAppContainerName(packageFamilyName, out var pSID);
+ if (ret != 0)
{
LogHelper.Warning("Unable to retrieve process package id: failed to retrieve package SID!");
return String.Empty;
@@ -115,9 +114,9 @@ static StorePackageHelper()
try
{
- if (NativeMethods.ConvertSidToStringSidW(pSID, out var SID))
+ if (NativeMethods.ConvertSidToStringSid(pSID, out var SID))
{
- return SID;
+ return SID.ToString();
}
LogHelper.Warning("Unable to retrieve process package id: SID cannot be converted!");
@@ -130,7 +129,7 @@ static StorePackageHelper()
}
finally
{
- NativeMethods.CloseHandle(hProcess);
+ hProcess?.Close();
}
}
}
diff --git a/Common/UI/ViewModels/ConnectionBaseInfo.cs b/Common/UI/ViewModels/ConnectionBaseInfo.cs
index 9641326..0549107 100644
--- a/Common/UI/ViewModels/ConnectionBaseInfo.cs
+++ b/Common/UI/ViewModels/ConnectionBaseInfo.cs
@@ -12,7 +12,7 @@
namespace Wokhan.WindowsFirewallNotifier.Common.UI.ViewModels;
-public abstract class ConnectionBaseInfo : ObservableObject
+public abstract partial class ConnectionBaseInfo : ObservableObject
{
public DateTime CreationTime { get; init; }
@@ -43,8 +43,12 @@ public string? TargetHostName
public string? ServiceDisplayName { get; protected set; }
public string? SourceIP { get; protected set; }
public string? SourcePort { get; set; }
- public string? TargetIP { get; protected set; }
- public string? TargetPort { get; protected set; }
+
+ [ObservableProperty]
+ private string? _targetIP;
+
+ [ObservableProperty]
+ private string? _targetPort;
public int RawProtocol { get; protected set; }
diff --git a/Console/Helpers/GeoLocationHelper.cs b/Console/Helpers/GeoLocationHelper.cs
index 290c7e3..c4e6bc7 100644
--- a/Console/Helpers/GeoLocationHelper.cs
+++ b/Console/Helpers/GeoLocationHelper.cs
@@ -119,7 +119,7 @@ await Task.Run(() =>
}
// If not yet set, fallback to the IP-based location
- CurrentCoordinates ??= await IPToLocationAsync(IPHelper.CurrentIP);
+ CurrentCoordinates ??= await IPToLocationAsync(await IPHelper.GetPublicIPAddressAsync());
}
private static void GeoWatcher_PositionChanged(object? sender, GeoPositionChangedEventArgs e)
@@ -138,7 +138,7 @@ public static async Task> ComputeRoute(string target)
}
var loc = new List() { CurrentCoordinates };
- var route = await IPHelper.GetFullRoute(target).ConfigureAwait(false);
+ var route = await IPHelper.GetFullRouteAsync(target).ConfigureAwait(false);
foreach (var ip in route)
{
diff --git a/Console/UI/Controls/BandwidthGraph.xaml b/Console/UI/Controls/BandwidthGraph.xaml
index 805d246..51433a4 100644
--- a/Console/UI/Controls/BandwidthGraph.xaml
+++ b/Console/UI/Controls/BandwidthGraph.xaml
@@ -6,6 +6,7 @@
xmlns:ext="clr-namespace:Wokhan.UI.Xaml.Extensibility;assembly=Wokhan.UI"
xmlns:charts="clr-namespace:LiveChartsCore.SkiaSharpView.WPF;assembly=LiveChartsCore.SkiaSharpView.WPF"
xmlns:system="clr-namespace:System;assembly=System.Runtime"
+ xmlns:controls="clr-namespace:Wokhan.WindowsFirewallNotifier.Console.UI.Controls"
mc:Ignorable="d" x:Name="me"
d:DesignHeight="450" d:DesignWidth="800" ClipToBounds="True">
@@ -36,6 +37,6 @@
-
+
diff --git a/Console/UI/Controls/BandwidthGraph.xaml.cs b/Console/UI/Controls/BandwidthGraph.xaml.cs
index b16ced1..1e98094 100644
--- a/Console/UI/Controls/BandwidthGraph.xaml.cs
+++ b/Console/UI/Controls/BandwidthGraph.xaml.cs
@@ -1,6 +1,8 @@
using LiveChartsCore;
using LiveChartsCore.Kernel;
using LiveChartsCore.SkiaSharpView;
+using LiveChartsCore.SkiaSharpView.Drawing;
+using LiveChartsCore.SkiaSharpView.Drawing.Geometries;
using LiveChartsCore.SkiaSharpView.Painting;
using LiveChartsCore.SkiaSharpView.Painting.Effects;
@@ -11,6 +13,7 @@
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
+using System.Drawing;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Threading;
@@ -65,9 +68,10 @@ private void InitMiniGraph()
};
}
+
private void InitAxes()
{
- var skAxisPaint = new SolidColorPaint(((SolidColorBrush)Application.Current.Resources[SystemColors.WindowTextBrushKey]).Color.ToSKColor());
+ var skAxisPaint = new SolidColorPaint(((SolidColorBrush)Application.Current.Resources[System.Windows.SystemColors.WindowTextBrushKey]).Color.ToSKColor());
crosshairPaint = new SolidColorPaint(SKColors.Red) { StrokeThickness = 1 };
xAxis = (Axis)chart.XAxes.First();
@@ -127,12 +131,21 @@ public double CurrentStart
public ObservableCollection Series { get; } = new();
public double ThumbSize => (xAxis is not null ? (xAxis.MaxLimit - xAxis.MinLimit) * scrollArea.Track.ActualWidth / (xAxis.DataBounds.Max - xAxis.DataBounds.Min) : 0) ?? 0;
+ private string tooltipFormatter(ChartPoint, LabelGeometry> arg)
+ {
+ return $"{((LineSeries)arg.Context.Series).Tag} - In: {UnitFormatter.FormatValue(arg.PrimaryValue, "bps")} / Out: {UnitFormatter.FormatValue(arg.TertiaryValue, "bps")}";
+ }
+
private void logMapper(CustomDateTimePoint dateTimePoint, ChartPoint chartPoint)
{
chartPoint.SecondaryValue = dateTimePoint.DateTime.Ticks;
chartPoint.PrimaryValue = dateTimePoint.Value == 0 ? 0 : Math.Log10(dateTimePoint.Value);
+ chartPoint.TertiaryValue = dateTimePoint.BandwidthIn;
+ chartPoint.QuaternaryValue = dateTimePoint.BandwidthOut;
}
+ DashEffect outDashEffect = new DashEffect(new[] { 2f, 2f });
+
public void UpdateGraph()
{
datetime = DateTime.Now;
@@ -156,8 +169,11 @@ public void UpdateGraph()
seriesOutValues = new();
var color = connectionGroup.First().Color.ToSKColor();
- Series.Add(new LineSeries() { Name = $"{connectionGroup.Key} - In", Fill = null, Stroke = new SolidColorPaint(color) { StrokeThickness = 2 }, Values = seriesInValues, LineSmoothness = 0, Mapping = logMapper });
- Series.Add(new LineSeries() { Name = $"{connectionGroup.Key} - Out", Fill = null, Stroke = new SolidColorPaint(color) { StrokeThickness = 2, PathEffect = new DashEffect(new[] { 2f, 2f }) }, Values = seriesOutValues, LineSmoothness = 0, Mapping = logMapper });
+ var inStroke = new SolidColorPaint(color) { StrokeThickness = 2 };
+ var outStroke = new SolidColorPaint(color) { StrokeThickness = 2, PathEffect = outDashEffect };
+
+ Series.Add(new LineSeries() { Tag = connectionGroup.Key, Name = $"{connectionGroup.Key} - In", TooltipLabelFormatter = tooltipFormatter, Fill = null, Stroke = inStroke, GeometryStroke = inStroke, Values = seriesInValues, LineSmoothness = 0, Mapping = logMapper });
+ Series.Add(new LineSeries() { Tag = connectionGroup.Key, Name = $"{connectionGroup.Key} - Out", IsVisibleAtLegend = false, IsHoverable = false, Fill = null, Stroke = outStroke, GeometryStroke = outStroke, Values = seriesOutValues, LineSmoothness = 0, Mapping = logMapper });
allSeries.Add(connectionGroup.Key, Tuple.Create(seriesInValues, seriesOutValues));
}
@@ -170,14 +186,14 @@ public void UpdateGraph()
lastSumOut += connection.OutboundBandwidth;
}
- AddAndMergePoints(seriesInValues, lastSumIn);
+ AddAndMergePoints(seriesInValues, lastSumIn, lastSumOut);
AddAndMergePoints(seriesOutValues, lastSumOut);
Interlocked.Add(ref totalIn, lastSumIn);
Interlocked.Add(ref totalOut, lastSumOut);
}
- seriesInTotal.Add(new CustomDateTimePoint(datetime, totalIn));
+ seriesInTotal.Add(new CustomDateTimePoint(datetime, totalIn, totalOut));
seriesOutTotal.Add(new CustomDateTimePoint(datetime, totalOut));
NotifyPropertyChanged(nameof(AbsoluteStart));
@@ -197,11 +213,11 @@ public void UpdateGraph()
}
}
- private void AddAndMergePoints(ObservableCollection series, ulong sum)
+ private void AddAndMergePoints(ObservableCollection series, ulong sum, ulong bandwidthOut = 0)
{
if (sum != 0 || series.Count == 0 || series[^1].Value != 0)
{
- series.Add(new CustomDateTimePoint(datetime, sum));
+ series.Add(new CustomDateTimePoint(datetime, sum, sum, bandwidthOut));
//if (series.Count > 3 && series[^2].Value == sum && series[^3].Value == sum)
//{
// series.RemoveAt(series.Count - 2);
diff --git a/Console/UI/Controls/CustomDateTimePoint.cs b/Console/UI/Controls/CustomDateTimePoint.cs
index 4586b76..93f5bb5 100644
--- a/Console/UI/Controls/CustomDateTimePoint.cs
+++ b/Console/UI/Controls/CustomDateTimePoint.cs
@@ -2,4 +2,4 @@
namespace Wokhan.WindowsFirewallNotifier.Console.UI.Controls;
-public record CustomDateTimePoint(DateTime DateTime, ulong Value);
\ No newline at end of file
+public record CustomDateTimePoint(DateTime DateTime, ulong Value, ulong BandwidthIn = 0, ulong BandwidthOut = 0);
\ No newline at end of file
diff --git a/Console/UI/Pages/Connections.xaml b/Console/UI/Pages/Connections.xaml
index dbe0628..c602eb5 100644
--- a/Console/UI/Pages/Connections.xaml
+++ b/Console/UI/Pages/Connections.xaml
@@ -149,7 +149,7 @@
-
+
-
+
+
@@ -230,7 +231,8 @@
-
+
+
diff --git a/Console/UI/Pages/Connections.xaml.cs b/Console/UI/Pages/Connections.xaml.cs
index 0743c24..b63fb44 100644
--- a/Console/UI/Pages/Connections.xaml.cs
+++ b/Console/UI/Pages/Connections.xaml.cs
@@ -127,7 +127,7 @@ protected override void OnTimerTick(object? state, ElapsedEventArgs e)
}
- private void AddOrUpdateConnection(IConnectionOwnerInfo connectionInfo)
+ private void AddOrUpdateConnection(Connection connectionInfo)
{
MonitoredConnection? lvi;
// TEMP: test to avoid enumerating while modifying (might result in a deadlock, to test carefully!)
diff --git a/Console/UI/Pages/EventsLog.xaml.cs b/Console/UI/Pages/EventsLog.xaml.cs
index fdcc572..3c63b00 100644
--- a/Console/UI/Pages/EventsLog.xaml.cs
+++ b/Console/UI/Pages/EventsLog.xaml.cs
@@ -49,7 +49,7 @@ public bool IsTCPOnlyEnabled
[ObservableProperty]
private string _textFilter = String.Empty;
- partial void OnTextFilterChanged(string _) => ResetTextFilter();
+ partial void OnTextFilterChanged(string value) => ResetTextFilter();
[ObservableProperty]
[NotifyCanExecuteChangedFor(nameof(LocateCommand))]
diff --git a/Console/ViewModels/MonitoredConnection.Dummy.cs b/Console/ViewModels/MonitoredConnection.Dummy.cs
index 878c4ef..d6a9a78 100644
--- a/Console/ViewModels/MonitoredConnection.Dummy.cs
+++ b/Console/ViewModels/MonitoredConnection.Dummy.cs
@@ -1,6 +1,7 @@
+using Windows.Win32.NetworkManagement.IpHelper;
+
using Wokhan.WindowsFirewallNotifier.Common.Net.IP;
-using Wokhan.WindowsFirewallNotifier.Common.Net.IP.TCP.TCP4;
namespace Wokhan.WindowsFirewallNotifier.Console.ViewModels;
@@ -8,9 +9,9 @@ public class ConnectionDummy : MonitoredConnection
{
public new string Owner { get => "Demo"; private set { } }
- public ConnectionDummy() : base(new MIB_TCPROW_OWNER_MODULE()) { }
+ //public ConnectionDummy() { }//: base(new MIB_TCPROW_OWNER_MODULE()) { }
- public ConnectionDummy(IConnectionOwnerInfo ownerMod) : base(ownerMod)
+ public ConnectionDummy(Connection ownerMod) : base(ownerMod)
{
}
}
diff --git a/Console/ViewModels/MonitoredConnection.cs b/Console/ViewModels/MonitoredConnection.cs
index 52e027e..77def08 100644
--- a/Console/ViewModels/MonitoredConnection.cs
+++ b/Console/ViewModels/MonitoredConnection.cs
@@ -10,7 +10,6 @@
using Wokhan.ComponentModel.Extensions;
using Wokhan.WindowsFirewallNotifier.Common.Net.GeoLocation;
using Wokhan.WindowsFirewallNotifier.Common.Net.IP;
-using Wokhan.WindowsFirewallNotifier.Common.Net.IP.TCP;
using Wokhan.WindowsFirewallNotifier.Common.UI.ViewModels;
using Wokhan.WindowsFirewallNotifier.Console.Helpers;
@@ -23,10 +22,13 @@ public partial class MonitoredConnection : ConnectionBaseInfo
public DateTime LastSeen { get; private set; }
[ObservableProperty]
- private bool _isAccessDenied;
+ private bool _isSelected;
[ObservableProperty]
- private bool _isSelected;
+ private bool _isNew;
+
+ [ObservableProperty]
+ private bool _isDying;
[ObservableProperty]
private bool _isDead;
@@ -37,12 +39,6 @@ public partial class MonitoredConnection : ConnectionBaseInfo
[ObservableProperty]
private string? _state;
- [ObservableProperty]
- private bool _isDying;
-
- [ObservableProperty]
- private bool _isNew;
-
[ObservableProperty]
private Color _color = Colors.Black;
@@ -52,8 +48,11 @@ public partial class MonitoredConnection : ConnectionBaseInfo
[ObservableProperty]
private ulong _outboundBandwidth;
- private readonly IConnectionOwnerInfo rawConnection;
- private ITcpRow? rawrow;
+ [ObservableProperty]
+ private bool _isAccessDenied;
+
+
+ private readonly Connection rawConnection;
#region Geolocation
@@ -81,7 +80,7 @@ private void OnCoordinatesPropertyChanged(string propertyName)
private IEnumerable ComputeStraightRoute()
{
- if (TargetIP is "127.0.0.1" or "::1" || Protocol == "UDP" && State != "ESTABLISHED" || Owner is null || Coordinates is null || GeoLocationHelper.CurrentCoordinates is null)
+ if (rawConnection.IsLoopback || Protocol == "UDP" && State != "ESTABLISHED" || Owner is null || Coordinates is null || GeoLocationHelper.CurrentCoordinates is null)
{
return NoLocation;
}
@@ -114,20 +113,22 @@ internal void UpdateStartingPoint()
#endregion
- public MonitoredConnection(IConnectionOwnerInfo ownerMod)
+ public MonitoredConnection(Connection ownerMod)
{
rawConnection = ownerMod;
IsNew = true;
Pid = ownerMod.OwningPid;
- SourceIP = ownerMod.LocalAddress;
+ SourceIP = ownerMod.LocalAddress.ToString();
SourcePort = ownerMod.LocalPort.ToString();
CreationTime = ownerMod.CreationTime ?? DateTime.Now;
Protocol = ownerMod.Protocol;
- TargetIP = ownerMod.RemoteAddress;
+ TargetIP = ownerMod.RemoteAddress.ToString();
TargetPort = (ownerMod.RemotePort == -1 ? String.Empty : ownerMod.RemotePort.ToString());
LastSeen = DateTime.Now;
+
+ _isAccessDenied = Protocol != "TCP";
//this._state = Enum.GetName(typeof(ConnectionStatus), ownerMod.State);
if (Pid is 0 or 4)
@@ -140,6 +141,7 @@ public MonitoredConnection(IConnectionOwnerInfo ownerMod)
{
try
{
+ //TODO: check if this is solely to retrieve the owner's executable path as we already have the exe in Connection.cs through GetOwningModule
var module = Process.GetProcessById((int)ownerMod.OwningPid)?.MainModule;
if (module is not null)
{
@@ -168,97 +170,26 @@ public MonitoredConnection(IConnectionOwnerInfo ownerMod)
SetProductInfo();
}
- private bool TryEnableStats()
- {
- try
- {
- // Ignoring bandwidth measurement for loopbacks as it is meaningless anyway
- if (this.TargetIP == "127.0.0.1" || this.TargetIP == "::1")
- {
- return false;
- }
-
- rawrow = this.rawConnection.ToTcpRow();
- rawrow.EnsureStats();
-
- statsEnabled = true;
- }
- catch
- {
- InboundBandwidth = 0;
- OutboundBandwidth = 0;
- IsAccessDenied = true;
- }
-
- return false;
- }
-
-
- internal void UpdateValues(IConnectionOwnerInfo b)
+ internal void UpdateValues(Connection b)
{
//lvi.LocalAddress = b.LocalAddress;
//lvi.Protocol = b.Protocol;
- if (this.TargetIP != b.RemoteAddress)
+ var remoteIP = b.RemoteAddress.ToString();
+ if (this.TargetIP != remoteIP)
{
- TargetIP = b.RemoteAddress;
+ TargetIP = remoteIP;
// Force reset the target host name by setting it to null (it will be recomputed next)
TargetHostName = null;
}
TargetPort = (b.RemotePort == -1 ? String.Empty : b.RemotePort.ToString());
State = Enum.GetName(typeof(ConnectionStatus), b.State);
- if (b.State == ConnectionStatus.ESTABLISHED && !IsAccessDenied)
- {
- if (!statsEnabled)
- {
- TryEnableStats();
- }
- EstimateBandwidth();
- }
- else
+ if (!_isAccessDenied)
{
- InboundBandwidth = 0;
- OutboundBandwidth = 0;
+ // TODO: Should use an object here (embedding all parameters as fields)
+ (InboundBandwidth, OutboundBandwidth) = rawConnection.GetEstimatedBandwidth(ref _isAccessDenied);
}
LastSeen = DateTime.Now;
}
-
-
- private ulong _lastInboundReadValue;
- private ulong _lastOutboundReadValue;
-
- private bool statsEnabled;
- private void EstimateBandwidth()
- {
- if (!statsEnabled)
- {
- return;
- }
-
- Task.Run(() =>
- {
- try
- {
- if (rawrow is not null && !IsAccessDenied)
- {
- var bandwidth = rawrow.GetTCPBandwidth();
- // Fix according to https://docs.microsoft.com/en-us/windows/win32/api/iphlpapi/nf-iphlpapi-setpertcpconnectionestats
- // One must subtract the previously read value to get the right one (as reenabling statistics doesn't work as before starting from Win 10 1709)
- InboundBandwidth = bandwidth.InboundBandwidth >= _lastInboundReadValue ? bandwidth.InboundBandwidth - _lastInboundReadValue : bandwidth.InboundBandwidth;
- OutboundBandwidth = bandwidth.OutboundBandwidth >= _lastOutboundReadValue ? bandwidth.OutboundBandwidth - _lastOutboundReadValue : bandwidth.OutboundBandwidth;
- _lastInboundReadValue = bandwidth.InboundBandwidth;
- _lastOutboundReadValue = bandwidth.OutboundBandwidth;
- }
- }
- catch
- {
- //TODO: Add exception log
- InboundBandwidth = 0;
- OutboundBandwidth = 0;
- }
-
- });
- }
-
}