669 lines
27 KiB
C#
669 lines
27 KiB
C#
using EonaCat.Json;
|
|
using System.Diagnostics;
|
|
using System.IO;
|
|
using System.Windows;
|
|
using System.Windows.Controls;
|
|
using System.Xml.Serialization;
|
|
using System.Collections.ObjectModel;
|
|
using System.Text.RegularExpressions;
|
|
using System.ComponentModel;
|
|
using System.Windows.Input;
|
|
using EonaCat.Helpers.Commands;
|
|
using System.Text;
|
|
using MessageBox = System.Windows.MessageBox;
|
|
using System.Net.Http;
|
|
using System.Windows.Media;
|
|
using Application = System.Windows.Application;
|
|
using Brushes = System.Drawing.Brushes;
|
|
using Brush = System.Drawing.Brush;
|
|
using System.Windows.Threading;
|
|
|
|
namespace EonaCat.PortMonitor
|
|
{
|
|
public partial class MainWindow : Window
|
|
{
|
|
public ObservableCollection<ConnectionInfo> Connections { get; set; } = new ObservableCollection<ConnectionInfo>();
|
|
private List<ConnectionInfo> _previousConnections = new List<ConnectionInfo>();
|
|
private BackgroundWorker _monitorWorker;
|
|
private int _interval = 1 * 1000;
|
|
WPF.Tray.TrayIcon _trayIcon = new WPF.Tray.TrayIcon();
|
|
|
|
public bool MinimizeToTray { get; private set; }
|
|
public bool MinimizeOnStartup { get; private set; }
|
|
public bool ShowPopups { get; private set; } = true;
|
|
public bool FirstRun { get; private set; } = true;
|
|
|
|
public MainWindow()
|
|
{
|
|
InitializeComponent();
|
|
DataContext = this;
|
|
|
|
NetworkDataGrid.Items.Clear();
|
|
NetworkDataGrid.ItemsSource = Connections;
|
|
|
|
this.StateChanged += MainWindow_StateChanged;
|
|
|
|
SetupTrayIcon();
|
|
|
|
LoadSettings();
|
|
|
|
_monitorWorker = new BackgroundWorker();
|
|
_monitorWorker.DoWork += MonitorWorker_DoWork;
|
|
_monitorWorker.RunWorkerAsync();
|
|
}
|
|
|
|
protected override void OnActivated(EventArgs e)
|
|
{
|
|
base.OnActivated(e);
|
|
if (FirstRun)
|
|
{
|
|
if (MinimizeToTray || MinimizeOnStartup)
|
|
{
|
|
// Minimize to tray on first run
|
|
Hide();
|
|
FirstRun = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
private void LoadSettings()
|
|
{
|
|
if (File.Exists("settings.json"))
|
|
{
|
|
var json = File.ReadAllText("settings.json");
|
|
var settings = JsonHelper.ToObject<dynamic>(json);
|
|
if (settings != null)
|
|
{
|
|
if (settings.MinimizeToTray != null)
|
|
{
|
|
MinimizeToTray = (bool)settings.MinimizeToTray;
|
|
}
|
|
|
|
if (settings.MinimizeOnStartup != null)
|
|
{
|
|
MinimizeOnStartup = (bool)settings.MinimizeOnStartup;
|
|
chkMinimize.IsChecked = MinimizeOnStartup;
|
|
}
|
|
|
|
if (settings.ShowPopups != null)
|
|
{
|
|
ShowPopups = (bool)settings.ShowPopups;
|
|
chkShowPopups.IsChecked = ShowPopups;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private void MainWindow_StateChanged(object? sender, EventArgs e)
|
|
{
|
|
if (WindowState == WindowState.Minimized)
|
|
{
|
|
// Minimize to tray and hide the window
|
|
this.Hide();
|
|
}
|
|
}
|
|
|
|
private void SetupTrayIcon()
|
|
{
|
|
// Load the icon from embedded resource
|
|
var icon = System.Drawing.Icon.ExtractAssociatedIcon(System.Reflection.Assembly.GetExecutingAssembly().Location);
|
|
_trayIcon.Icon = icon;
|
|
_trayIcon.TrayLeftMouseUp += (sender, args) =>
|
|
{
|
|
// Show the main window when the tray icon is clicked
|
|
WindowState = WindowState.Normal;
|
|
Show();
|
|
Activate();
|
|
};
|
|
|
|
_trayIcon.TrayRightMouseUp += (sender, args) =>
|
|
{
|
|
// Generate a context menu for the tray icon
|
|
var contextMenu = new System.Windows.Controls.ContextMenu();
|
|
contextMenu.Items.Add(new MenuItem { Header = "Show", Command = new GiveCommand(() => { Show(); WindowState = WindowState.Normal; }) });
|
|
contextMenu.Items.Add(new MenuItem
|
|
{
|
|
Header = "Exit",
|
|
Command = new GiveCommand(() =>
|
|
{
|
|
Close();
|
|
})
|
|
});
|
|
_trayIcon.ContextMenu = contextMenu;
|
|
};
|
|
}
|
|
|
|
protected override void OnClosing(CancelEventArgs e)
|
|
{
|
|
// Save settings before closing
|
|
var settings = new
|
|
{
|
|
MinimizeToTray = this.WindowState == WindowState.Minimized,
|
|
MinimizeOnStartup = chkMinimize.IsChecked == true,
|
|
ShowPopups = chkShowPopups.IsChecked == true
|
|
};
|
|
File.WriteAllBytes("settings.json", Encoding.UTF8.GetBytes(JsonHelper.ToJson(settings)));
|
|
|
|
base.OnClosing(e);
|
|
}
|
|
|
|
private void MonitorWorker_DoWork(object sender, DoWorkEventArgs e)
|
|
{
|
|
while (true)
|
|
{
|
|
MonitorConnections(null);
|
|
Thread.Sleep(_interval);
|
|
}
|
|
}
|
|
|
|
private async Task NotifyNewConnectionAsync(ConnectionInfo conn)
|
|
{
|
|
if (!ShowPopups)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Create a new notification manager
|
|
var notificationManager = new WPF.Popup.NotificationManager();
|
|
|
|
// Set up the popup's title and content
|
|
string popupTitle = $"New Connection: {conn.Protocol} {conn.LocalAddress}:{conn.LocalPort} -> {conn.RemoteAddress}:{conn.RemotePort}";
|
|
string popupContent = $"Process: {conn.ProcessName}\nState: {conn.State}";
|
|
|
|
// Set up the popup
|
|
var notification = new WPF.Popup.NotificationContent
|
|
{
|
|
Title = popupTitle,
|
|
Message = popupContent,
|
|
Type = WPF.Popup.NotificationType.Information,
|
|
};
|
|
|
|
// Show the popup
|
|
await notificationManager.ShowAsync(notification, expirationTime: TimeSpan.FromSeconds(3), onClick: new Action(() => { ShowConnectionDetails(conn); }));
|
|
}
|
|
|
|
|
|
private void ShowConnectionDetails(ConnectionInfo conn)
|
|
{
|
|
// Play a sound when the notification is clicked
|
|
System.Media.SystemSounds.Asterisk.Play();
|
|
|
|
var detailsWindow = new ConnectionDetailsWindow(conn);
|
|
detailsWindow.Show();
|
|
}
|
|
|
|
private void DataGrid_PreviewMouseDoubleClick(object sender, MouseButtonEventArgs e)
|
|
{
|
|
// Get the DataGrid that triggered the event
|
|
DataGrid dataGrid = sender as DataGrid;
|
|
|
|
if (dataGrid.SelectedItem != null)
|
|
{
|
|
ShowConnectionDetails(dataGrid.SelectedItem as ConnectionInfo);
|
|
}
|
|
}
|
|
|
|
private List<ConnectionInfo> GetActiveConnections()
|
|
{
|
|
var connectionList = new List<ConnectionInfo>();
|
|
foreach (var conn in RunNetstatCommand())
|
|
{
|
|
if (string.IsNullOrEmpty(conn)) continue;
|
|
|
|
var match = ParseNetstatLine(conn);
|
|
if (match.Success)
|
|
{
|
|
var connInfo = new ConnectionInfo
|
|
{
|
|
Protocol = match.Groups["protocol"].Value,
|
|
LocalAddress = match.Groups["localAddress"].Value,
|
|
LocalPort = int.Parse(match.Groups["localPort"].Value),
|
|
RemoteAddress = match.Groups["remoteAddress"].Value,
|
|
RemotePort = int.Parse(match.Groups["remotePort"].Value),
|
|
State = string.IsNullOrEmpty(match.Groups["state"].Value) ? string.Empty : match.Groups["state"].Value, // Handle missing state for UDP
|
|
ProcessId = string.IsNullOrEmpty(match.Groups["pid"].Value) ? 0 : int.Parse(match.Groups["pid"].Value), // Default PID to 0 if missing
|
|
ProcessName = string.IsNullOrEmpty(match.Groups["pid"].Value) ? string.Empty : GetProcessName(int.Parse(match.Groups["pid"].Value)),
|
|
ConnectionTime = DateTime.Now,
|
|
ConnectionStatus = string.Empty
|
|
};
|
|
|
|
connectionList.Add(connInfo);
|
|
}
|
|
}
|
|
return connectionList;
|
|
}
|
|
|
|
private async void MonitorConnections(object state)
|
|
{
|
|
// Store the currently selected connection before the update
|
|
ConnectionInfo selectedConnection = null;
|
|
|
|
// Store the selected item from the DataGrid
|
|
Dispatcher.Invoke(new Action(() =>
|
|
{
|
|
selectedConnection = NetworkDataGrid.SelectedItem as ConnectionInfo;
|
|
}));
|
|
|
|
var currentConnections = await Task.Run(() => GetActiveConnections());
|
|
var inboundConnections = currentConnections.Where(c => IsInboundConnection(c)).ToList();
|
|
var outboundConnections = currentConnections.Where(c => IsOutboundConnection(c)).ToList();
|
|
int totalConnections = currentConnections.Count;
|
|
|
|
// Compare and update connections with the existing ones
|
|
var newConnections = currentConnections.Where(c => !_previousConnections.Any(p => p.LocalAddress == c.LocalAddress && p.LocalPort == c.LocalPort)).ToList();
|
|
var closedConnections = _previousConnections.Where(p => !currentConnections.Any(c => c.LocalAddress == p.LocalAddress && c.LocalPort == p.LocalPort)).ToList();
|
|
var stateChangedConnections = currentConnections.Where(c => _previousConnections.Any(p => p.LocalAddress == c.LocalAddress && p.LocalPort == c.LocalPort && p.State != c.State)).ToList();
|
|
|
|
// Add new connections or update existing ones
|
|
foreach (var newConn in newConnections)
|
|
{
|
|
newConn.ConnectionStatus = "New";
|
|
if (newConn.FirstConnectionTime == DateTime.MinValue)
|
|
{
|
|
newConn.FirstConnectionTime = DateTime.Now;
|
|
}
|
|
|
|
// Add the new connection to the collection
|
|
Dispatcher.Invoke(() => Connections.Add(newConn));
|
|
await NotifyNewConnectionAsync(newConn);
|
|
}
|
|
|
|
// Handle closed connections
|
|
foreach (var closedConn in closedConnections)
|
|
{
|
|
var conn = Connections.FirstOrDefault(c => c.LocalAddress == closedConn.LocalAddress && c.LocalPort == closedConn.LocalPort);
|
|
if (conn != null)
|
|
{
|
|
conn.ConnectionStatus = "Closed";
|
|
|
|
// Remove the connection if the status was set to closed for more than 5 seconds
|
|
if (conn.ConnectionDuration.TotalSeconds > 5)
|
|
{
|
|
await Dispatcher.InvokeAsync(() => Connections.Remove(conn));
|
|
}
|
|
}
|
|
}
|
|
|
|
// Handle state changes
|
|
foreach (var stateChangedConn in stateChangedConnections)
|
|
{
|
|
var conn = Connections.FirstOrDefault(c => c.LocalAddress == stateChangedConn.LocalAddress && c.LocalPort == stateChangedConn.LocalPort);
|
|
if (conn != null)
|
|
{
|
|
conn.ConnectionStatus = "State Changed";
|
|
conn.BackgroundColor = Brushes.Yellow;
|
|
|
|
var timer = new DispatcherTimer
|
|
{
|
|
Interval = TimeSpan.FromSeconds(1)
|
|
};
|
|
timer.Tick += (sender, args) =>
|
|
{
|
|
conn.BackgroundColor = Brushes.Transparent;
|
|
timer.Stop();
|
|
};
|
|
timer.Start();
|
|
}
|
|
}
|
|
|
|
await Dispatcher.InvokeAsync(() =>
|
|
{
|
|
InboundDataGrid.ItemsSource = Connections.Where(x => IsInboundConnection(x));
|
|
OutboundDataGrid.ItemsSource = Connections.Where(x => IsOutboundConnection(x));
|
|
|
|
NetworkDataGrid.Items.Refresh();
|
|
FilterConnections_KeyUp(null, null);
|
|
UpdateConnectionStats(totalConnections, inboundConnections.Count, outboundConnections.Count);
|
|
});
|
|
|
|
// Re-select the previously selected item after the refresh
|
|
if (selectedConnection != null)
|
|
{
|
|
var selectedItem = Connections.FirstOrDefault(c => c.LocalAddress == selectedConnection.LocalAddress && c.LocalPort == selectedConnection.LocalPort);
|
|
if (selectedItem != null)
|
|
{
|
|
Dispatcher.Invoke(() =>
|
|
{
|
|
// Set the previously selected item back to the DataGrid
|
|
NetworkDataGrid.SelectedItem = selectedItem;
|
|
});
|
|
}
|
|
}
|
|
|
|
// Update the previousConnections list for the next iteration
|
|
_previousConnections = currentConnections;
|
|
}
|
|
|
|
private void UpdateConnectionStats(int total, int inbound, int outbound)
|
|
{
|
|
var tcpConnections = Connections.Count(c => c.Protocol == "TCP");
|
|
var udpConnections = Connections.Count(c => c.Protocol == "UDP");
|
|
|
|
var avgConnectionTime = Connections.Average(c => (DateTime.Now - c.ConnectionTime).TotalSeconds);
|
|
TcpUdpStatsText.Text = $"TCP Connections: {tcpConnections}\nUDP Connections: {udpConnections}\nAverage Connection Time: {avgConnectionTime:F2} seconds\nTotal: {total}\nInbound: {inbound}\nOutbound: {outbound}";
|
|
}
|
|
|
|
private bool IsInboundConnection(ConnectionInfo connection)
|
|
{
|
|
// Inbound: LocalAddress is valid, and the machine is accepting the connection (server-side).
|
|
return IsValidIpAddress(connection.LocalAddress) &&
|
|
connection.LocalAddress != "0.0.0.0" &&
|
|
connection.LocalAddress != "::" &&
|
|
!string.IsNullOrEmpty(connection.RemoteAddress) &&
|
|
connection.RemoteAddress != "0.0.0.0" &&
|
|
connection.RemoteAddress != "::" &&
|
|
connection.RemoteAddress != "N/A" &&
|
|
connection.RemotePort != 0;
|
|
}
|
|
|
|
private bool IsOutboundConnection(ConnectionInfo connection)
|
|
{
|
|
// Outbound: LocalAddress is valid, and the machine is initiating the connection (client-side).
|
|
return IsValidIpAddress(connection.LocalAddress) &&
|
|
connection.LocalAddress != "0.0.0.0" &&
|
|
connection.LocalAddress != "::" &&
|
|
IsValidIpAddress(connection.RemoteAddress) &&
|
|
connection.RemoteAddress != "0.0.0.0" &&
|
|
connection.RemoteAddress != "::" &&
|
|
connection.RemoteAddress != "N/A" &&
|
|
connection.LocalPort != 0;
|
|
}
|
|
|
|
private bool IsValidIpAddress(string ipAddress)
|
|
{
|
|
return !string.IsNullOrEmpty(ipAddress) && (IsValidIPv4(ipAddress) || IsValidIPv6(ipAddress));
|
|
}
|
|
|
|
private bool IsValidIPv4(string ipAddress)
|
|
{
|
|
return System.Net.IPAddress.TryParse(ipAddress, out var ip) && ip.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork;
|
|
}
|
|
|
|
private bool IsValidIPv6(string ipAddress)
|
|
{
|
|
return System.Net.IPAddress.TryParse(ipAddress, out var ip) && ip.AddressFamily == System.Net.Sockets.AddressFamily.InterNetworkV6;
|
|
}
|
|
|
|
private List<string> RunNetstatCommand()
|
|
{
|
|
var result = new List<string>();
|
|
try
|
|
{
|
|
ProcessStartInfo startInfo = new ProcessStartInfo("netstat", "-ano")
|
|
{
|
|
RedirectStandardOutput = true,
|
|
UseShellExecute = false,
|
|
CreateNoWindow = true
|
|
};
|
|
|
|
using (Process process = Process.Start(startInfo))
|
|
{
|
|
using (var reader = process.StandardOutput)
|
|
{
|
|
string line;
|
|
while ((line = reader.ReadLine()) != null)
|
|
{
|
|
result.Add(line);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Console.WriteLine($"Error running netstat: {ex.Message}");
|
|
}
|
|
return result;
|
|
}
|
|
|
|
private Match ParseNetstatLine(string line)
|
|
{
|
|
// Regular expression for both TCP and UDP connections, IPv4 and IPv6.
|
|
var regex = new Regex(@"(?<protocol>TCP|UDP)\s+(?<localAddress>[\d\.]+|\[?[A-F0-9:]+\]?):(?<localPort>\d+)\s+(?<remoteAddress>[\d\.]+|\[?[A-F0-9:]+\]?):(?<remotePort>\d+)\s*(?<state>\S*)?\s*(?<pid>\d+)?");
|
|
var match = regex.Match(line);
|
|
return match;
|
|
}
|
|
|
|
private string GetProcessName(int pid)
|
|
{
|
|
try
|
|
{
|
|
var process = Process.GetProcessById(pid);
|
|
return process.ProcessName;
|
|
}
|
|
catch
|
|
{
|
|
return "N/A";
|
|
}
|
|
}
|
|
|
|
private void FilterConnections_KeyUp(object sender, System.Windows.Input.KeyEventArgs e)
|
|
{
|
|
// Get the filter keyword from the input box
|
|
var keywordFilter = KeywordFilter.Text.ToLower();
|
|
|
|
// Filter the connections based on the keyword
|
|
var filteredConnections = Connections?.Where(c =>
|
|
(string.IsNullOrEmpty(keywordFilter) ||
|
|
c.ProcessName.ToLower().Contains(keywordFilter) ||
|
|
c.RemoteAddress.ToLower().Contains(keywordFilter) ||
|
|
c.LocalAddress.ToLower().Contains(keywordFilter) ||
|
|
c.State.ToLower().Contains(keywordFilter) ||
|
|
c.Protocol.ToLower().Contains(keywordFilter) ||
|
|
c.LocalPort.ToString().Contains(keywordFilter) ||
|
|
c.RemotePort.ToString().Contains(keywordFilter)
|
|
)
|
|
).ToList();
|
|
|
|
// Clear the existing items and add filtered ones to the ObservableCollection
|
|
Connections.Clear();
|
|
if (filteredConnections != null)
|
|
{
|
|
foreach (var conn in filteredConnections)
|
|
{
|
|
Connections.Add(conn);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
private void FilterConnections_SelectionChanged(object sender, SelectionChangedEventArgs e)
|
|
{
|
|
FilterConnections_KeyUp(sender, null);
|
|
}
|
|
|
|
private void ExportToJsonButton_Click(object sender, RoutedEventArgs e)
|
|
{
|
|
var json = JsonHelper.ToJson(Connections, Json.Formatting.Indented);
|
|
File.WriteAllText("connections.json", json);
|
|
MessageBox.Show("Connections exported to connections.json", "Export Successful", MessageBoxButton.OK, MessageBoxImage.Information);
|
|
}
|
|
|
|
private void ExportToXmlButton_Click(object sender, RoutedEventArgs e)
|
|
{
|
|
var xmlSerializer = new XmlSerializer(typeof(List<ConnectionInfo>));
|
|
using (var writer = new StreamWriter("connections.xml"))
|
|
{
|
|
xmlSerializer.Serialize(writer, Connections);
|
|
}
|
|
MessageBox.Show("Connections exported to connections.xml", "Export Successful", MessageBoxButton.OK, MessageBoxImage.Information);
|
|
}
|
|
|
|
private void ExportToCsvButton_Click(object sender, RoutedEventArgs e)
|
|
{
|
|
var csvLines = new List<string> { "Protocol,LocalAddress,LocalPort,RemoteAddress,RemotePort,State,ProcessName,ConnectionTime" };
|
|
csvLines.AddRange(Connections.Select(c => $"{c.Protocol},{c.LocalAddress},{c.LocalPort},{c.RemoteAddress},{c.RemotePort},{c.State},{c.ProcessName},{c.ConnectionTime}"));
|
|
|
|
File.WriteAllLines("connections.csv", csvLines);
|
|
MessageBox.Show("Connections exported to connections.csv", "Export Successful", MessageBoxButton.OK, MessageBoxImage.Information);
|
|
}
|
|
|
|
private void SaveFilterPresetButton_Click(object sender, RoutedEventArgs e)
|
|
{
|
|
var filters = new
|
|
{
|
|
Keywords = KeywordFilter.Text,
|
|
};
|
|
|
|
var json = JsonHelper.ToJson(filters);
|
|
File.WriteAllText("filterPreset.json", json);
|
|
}
|
|
|
|
private void LoadFilterPresetButton_Click(object sender, RoutedEventArgs e)
|
|
{
|
|
if (File.Exists("filterPreset.json"))
|
|
{
|
|
var json = File.ReadAllText("filterPreset.json");
|
|
var filters = JsonHelper.ToObject<dynamic>(json);
|
|
|
|
KeywordFilter.Text = filters.Keywords;
|
|
|
|
FilterConnections_KeyUp(null, null);
|
|
}
|
|
}
|
|
|
|
private void ExportToHtmlButton_Click(object sender, RoutedEventArgs e)
|
|
{
|
|
var htmlContent = "<html><body><table border='1'><tr><th>Protocol</th><th>LocalAddress</th><th>LocalPort</th><th>RemoteAddress</th><th>RemotePort</th><th>State</th><th>ProcessName</th><th>ConnectionTime</th></tr>";
|
|
foreach (var conn in Connections)
|
|
{
|
|
htmlContent += $"<tr><td>{conn.Protocol}</td><td>{conn.LocalAddress}</td><td>{conn.LocalPort}</td><td>{conn.RemoteAddress}</td><td>{conn.RemotePort}</td><td>{conn.State}</td><td>{conn.ProcessName}</td><td>{conn.ConnectionTime}</td></tr>";
|
|
}
|
|
htmlContent += "</table></body></html>";
|
|
|
|
File.WriteAllText("connections.html", htmlContent);
|
|
MessageBox.Show("Connections exported to connections.html", "Export Successful", MessageBoxButton.OK, MessageBoxImage.Information);
|
|
}
|
|
|
|
private void chkMinimize_Checked(object sender, RoutedEventArgs e)
|
|
{
|
|
MinimizeOnStartup = chkMinimize.IsChecked == true;
|
|
}
|
|
|
|
private void chkShowPopups_Checked(object sender, RoutedEventArgs e)
|
|
{
|
|
ShowPopups = chkShowPopups.IsChecked == true;
|
|
}
|
|
|
|
private void KillProcessButton_Click(object sender, RoutedEventArgs e)
|
|
{
|
|
if (NetworkDataGrid.SelectedItem is ConnectionInfo selectedConnection)
|
|
{
|
|
try
|
|
{
|
|
var process = Process.GetProcessById(selectedConnection.ProcessId);
|
|
process.Kill();
|
|
MessageBox.Show($"Process {selectedConnection.ProcessName} (PID: {selectedConnection.ProcessId}) terminated.", "Process Killed", MessageBoxButton.OK, MessageBoxImage.Warning);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
MessageBox.Show($"Failed to terminate process: {ex.Message}", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
|
|
}
|
|
}
|
|
}
|
|
|
|
private async void IpLookupButton_Click(object sender, RoutedEventArgs e)
|
|
{
|
|
if (NetworkDataGrid.SelectedItem is ConnectionInfo selectedConnection)
|
|
{
|
|
string apiUrl = $"https://reallyfreegeoip.org/json/{selectedConnection.RemoteAddress}";
|
|
using (HttpClient client = new HttpClient())
|
|
{
|
|
var response = await client.GetStringAsync(apiUrl);
|
|
MessageBox.Show(response, "IP Lookup", MessageBoxButton.OK, MessageBoxImage.Information);
|
|
}
|
|
}
|
|
}
|
|
|
|
private void BlockIpButton_Click(object sender, RoutedEventArgs e)
|
|
{
|
|
// Check if an item is selected in the DataGrid
|
|
if (NetworkDataGrid.SelectedItem is ConnectionInfo selectedConnection)
|
|
{
|
|
// Ask the user for confirmation
|
|
var result = MessageBox.Show(
|
|
$"Are you sure you want to block the IP address: {selectedConnection.RemoteAddress}?",
|
|
"Confirm Block",
|
|
MessageBoxButton.YesNo,
|
|
MessageBoxImage.Question
|
|
);
|
|
|
|
// If the user clicks 'Yes', proceed with blocking the IP
|
|
if (result == MessageBoxResult.Yes)
|
|
{
|
|
string command = $"netsh advfirewall firewall add rule name=\"Blocked {selectedConnection.RemoteAddress}\" dir=in action=block remoteip={selectedConnection.RemoteAddress}";
|
|
Process.Start(new ProcessStartInfo("cmd.exe", "/C " + command) { CreateNoWindow = true });
|
|
MessageBox.Show($"Blocked IP: {selectedConnection.RemoteAddress}", "Firewall Rule Added", MessageBoxButton.OK, MessageBoxImage.Information);
|
|
}
|
|
}
|
|
}
|
|
|
|
private void btnTheme_Click(object sender, RoutedEventArgs e)
|
|
{
|
|
// Ensure the resources exist
|
|
if (!Application.Current.Resources.Contains("DynamicBackgroundColor") ||
|
|
!Application.Current.Resources.Contains("DynamicTextColor"))
|
|
{
|
|
MessageBox.Show("Theme resources are missing!", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
|
|
return;
|
|
}
|
|
|
|
// Retrieve current background color
|
|
SolidColorBrush currentBg = (SolidColorBrush)Application.Current.Resources["DynamicBackgroundColor"];
|
|
|
|
if (currentBg.Color == Colors.Black) // Dark Mode → Light Mode
|
|
{
|
|
Application.Current.Resources["DynamicBackgroundColor"] = new SolidColorBrush(Colors.White);
|
|
Application.Current.Resources["DynamicTextColor"] = new SolidColorBrush(Colors.Black);
|
|
btnTheme.Content = "🌙"; // Set icon to moon for dark mode
|
|
}
|
|
else // Light Mode → Dark Mode
|
|
{
|
|
Application.Current.Resources["DynamicBackgroundColor"] = new SolidColorBrush(Colors.Black);
|
|
Application.Current.Resources["DynamicTextColor"] = new SolidColorBrush(Colors.White);
|
|
btnTheme.Content = "🌞"; // Set icon to sun for light mode
|
|
}
|
|
}
|
|
}
|
|
|
|
public class ConnectionInfo : INotifyPropertyChanged
|
|
{
|
|
private Brush _backgroundColor;
|
|
|
|
public string Protocol { get; set; }
|
|
public string LocalAddress { get; set; }
|
|
public int LocalPort { get; set; }
|
|
public string RemoteAddress { get; set; }
|
|
public int RemotePort { get; set; }
|
|
public string State { get; set; }
|
|
public int ProcessId { get; set; }
|
|
public string ProcessName { get; set; }
|
|
public DateTime ConnectionTime { get; set; }
|
|
public DateTime FirstConnectionTime { get; set; }
|
|
public string ConnectionStatus { get; set; }
|
|
public TimeSpan ConnectionDuration => DateTime.Now - FirstConnectionTime;
|
|
public string FormattedConnectionDuration => ConnectionDuration.ToString(@"hh\:mm\:ss");
|
|
|
|
public Brush BackgroundColor
|
|
{
|
|
get { return _backgroundColor; }
|
|
set
|
|
{
|
|
if (_backgroundColor != value)
|
|
{
|
|
_backgroundColor = value;
|
|
OnPropertyChanged(nameof(BackgroundColor));
|
|
}
|
|
}
|
|
}
|
|
|
|
public event PropertyChangedEventHandler PropertyChanged;
|
|
|
|
protected virtual void OnPropertyChanged(string propertyName)
|
|
{
|
|
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
|
}
|
|
}
|
|
}
|