From 9b500dbf697645dc640498a65228b4aee85e8e60 Mon Sep 17 00:00:00 2001
From: BornToBeRoot <16019165+BornToBeRoot@users.noreply.github.com>
Date: Thu, 4 Dec 2025 00:32:32 +0100
Subject: [PATCH 1/5] Feature: DNS Lookup - Input server
---
.../DNSServerConnectionInfoProfileToString.cs | 23 -------
.../Network/DNSServer.cs | 36 +++++------
.../Network/DNSServerConnectionInfoProfile.cs | 3 +-
.../Network/ServerConnectionInfoProfile.cs | 7 +-
.../NETworkManager.Settings/SettingsInfo.cs | 2 +-
.../ViewModels/DNSLookupSettingsViewModel.cs | 2 +-
.../ViewModels/DNSLookupViewModel.cs | 64 +++++++++++++++++--
.../NETworkManager/Views/DNSLookupView.xaml | 17 ++---
8 files changed, 92 insertions(+), 62 deletions(-)
delete mode 100644 Source/NETworkManager.Converters/DNSServerConnectionInfoProfileToString.cs
diff --git a/Source/NETworkManager.Converters/DNSServerConnectionInfoProfileToString.cs b/Source/NETworkManager.Converters/DNSServerConnectionInfoProfileToString.cs
deleted file mode 100644
index feb47ef7db..0000000000
--- a/Source/NETworkManager.Converters/DNSServerConnectionInfoProfileToString.cs
+++ /dev/null
@@ -1,23 +0,0 @@
-using System;
-using System.Globalization;
-using System.Windows.Data;
-using NETworkManager.Localization.Resources;
-using NETworkManager.Models.Network;
-
-namespace NETworkManager.Converters;
-
-public sealed class DNSServerConnectionInfoProfileToString : IValueConverter
-{
- public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
- {
- if (value is not DNSServerConnectionInfoProfile dnsServerInfo)
- return "-/-";
-
- return dnsServerInfo.UseWindowsDNSServer ? $"[{Strings.WindowsDNSSettings}]" : dnsServerInfo.Name;
- }
-
- public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
- {
- throw new NotImplementedException();
- }
-}
\ No newline at end of file
diff --git a/Source/NETworkManager.Models/Network/DNSServer.cs b/Source/NETworkManager.Models/Network/DNSServer.cs
index e654d973cb..13cb3d7cd4 100644
--- a/Source/NETworkManager.Models/Network/DNSServer.cs
+++ b/Source/NETworkManager.Models/Network/DNSServer.cs
@@ -13,34 +13,34 @@ public static class DNSServer
/// List of common dns servers.
public static List GetDefaultList()
{
- return new List
- {
+ return
+ [
new(), // Windows DNS server
- new("Cloudflare", new List
- {
+ new("Cloudflare",
+ [
new("1.1.1.1", 53, TransportProtocol.Udp),
new("1.0.0.1", 53, TransportProtocol.Udp)
- }),
- new("DNS.Watch", new List
- {
+ ]),
+ new("DNS.Watch",
+ [
new("84.200.69.80", 53, TransportProtocol.Udp),
new("84.200.70.40", 53, TransportProtocol.Udp)
- }),
- new("Google Public DNS", new List
- {
+ ]),
+ new("Google Public DNS",
+ [
new("8.8.8.8", 53, TransportProtocol.Udp),
new("8.8.4.4", 53, TransportProtocol.Udp)
- }),
- new("Level3", new List
- {
+ ]),
+ new("Level3",
+ [
new("209.244.0.3", 53, TransportProtocol.Udp),
new("209.244.0.4", 53, TransportProtocol.Udp)
- }),
- new("Verisign", new List
- {
+ ]),
+ new("Verisign",
+ [
new("64.6.64.6", 53, TransportProtocol.Udp),
new("64.6.65.6", 53, TransportProtocol.Udp)
- })
- };
+ ])
+ ];
}
}
\ No newline at end of file
diff --git a/Source/NETworkManager.Models/Network/DNSServerConnectionInfoProfile.cs b/Source/NETworkManager.Models/Network/DNSServerConnectionInfoProfile.cs
index 7e06301e30..32737e9f71 100644
--- a/Source/NETworkManager.Models/Network/DNSServerConnectionInfoProfile.cs
+++ b/Source/NETworkManager.Models/Network/DNSServerConnectionInfoProfile.cs
@@ -13,6 +13,7 @@ public class DNSServerConnectionInfoProfile : ServerConnectionInfoProfile
///
public DNSServerConnectionInfoProfile()
{
+ Name = "[Windows DNS]";
UseWindowsDNSServer = true;
}
@@ -28,5 +29,5 @@ public DNSServerConnectionInfoProfile(string name, List se
///
/// Use the DNS server from Windows.
///
- public bool UseWindowsDNSServer { get; set; }
+ public bool UseWindowsDNSServer { get; set; }
}
\ No newline at end of file
diff --git a/Source/NETworkManager.Models/Network/ServerConnectionInfoProfile.cs b/Source/NETworkManager.Models/Network/ServerConnectionInfoProfile.cs
index 8d4848d83c..3c9afed439 100644
--- a/Source/NETworkManager.Models/Network/ServerConnectionInfoProfile.cs
+++ b/Source/NETworkManager.Models/Network/ServerConnectionInfoProfile.cs
@@ -33,5 +33,10 @@ public ServerConnectionInfoProfile(string name, List serve
///
/// List of servers as .
///
- public List Servers { get; set; } = new();
+ public List Servers { get; set; } = [];
+
+ public override string ToString()
+ {
+ return Name;
+ }
}
\ No newline at end of file
diff --git a/Source/NETworkManager.Settings/SettingsInfo.cs b/Source/NETworkManager.Settings/SettingsInfo.cs
index a60d8bcf01..428cd23715 100644
--- a/Source/NETworkManager.Settings/SettingsInfo.cs
+++ b/Source/NETworkManager.Settings/SettingsInfo.cs
@@ -1753,7 +1753,7 @@ public ObservableCollection DNSLookup_DNSServers
}
}
- private DNSServerConnectionInfoProfile _dnsLookup_SelectedDNSServer = new();
+ private DNSServerConnectionInfoProfile _dnsLookup_SelectedDNSServer = null;
public DNSServerConnectionInfoProfile DNSLookup_SelectedDNSServer
{
diff --git a/Source/NETworkManager/ViewModels/DNSLookupSettingsViewModel.cs b/Source/NETworkManager/ViewModels/DNSLookupSettingsViewModel.cs
index 1bcfe63d1d..32e5431643 100644
--- a/Source/NETworkManager/ViewModels/DNSLookupSettingsViewModel.cs
+++ b/Source/NETworkManager/ViewModels/DNSLookupSettingsViewModel.cs
@@ -28,7 +28,7 @@ public class DNSLookupSettingsViewModel : ViewModelBase
public ICollectionView DNSServers { get; }
- private DNSServerConnectionInfoProfile _selectedDNSServer = new();
+ private DNSServerConnectionInfoProfile _selectedDNSServer = null;
public DNSServerConnectionInfoProfile SelectedDNSServer
{
diff --git a/Source/NETworkManager/ViewModels/DNSLookupViewModel.cs b/Source/NETworkManager/ViewModels/DNSLookupViewModel.cs
index 288cef0176..d70fbde655 100644
--- a/Source/NETworkManager/ViewModels/DNSLookupViewModel.cs
+++ b/Source/NETworkManager/ViewModels/DNSLookupViewModel.cs
@@ -16,6 +16,7 @@
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
+using System.Net;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Data;
@@ -57,24 +58,69 @@ public string Host
public ICollectionView DNSServers { get; }
private DNSServerConnectionInfoProfile _dnsServer = new();
-
public DNSServerConnectionInfoProfile DNSServer
{
get => _dnsServer;
- set
+ private set
{
- if (value == _dnsServer)
+ if (_dnsServer == value)
return;
+
+ _dnsServer = value ?? new DNSServerConnectionInfoProfile();
if (!_isLoading)
- SettingsManager.Current.DNSLookup_SelectedDNSServer = value;
+ SettingsManager.Current.DNSLookup_SelectedDNSServer = _dnsServer;
+
+ OnPropertyChanged();
+ }
+ }
+
+ private DNSServerConnectionInfoProfile _selectedListProfile;
+ public DNSServerConnectionInfoProfile SelectedListProfile
+ {
+ get => _selectedListProfile;
+ set
+ {
+ if (_selectedListProfile == value)
+ return;
+
+ if (value != null)
+ {
+ DNSServer = value;
+ DNSServerQuickInput = value.ToString(); // uses your override
+ }
- _dnsServer = value;
+ _selectedListProfile = value;
OnPropertyChanged();
}
}
- private List _queryTypes = new();
+ // Text box content
+ private string _dnsServerQuickInput = string.Empty;
+ public string DNSServerQuickInput
+ {
+ get => _dnsServerQuickInput;
+ set
+ {
+ if (_dnsServerQuickInput == value)
+ return;
+
+ _dnsServerQuickInput = value?.Trim() ?? string.Empty;
+ OnPropertyChanged();
+
+ // As soon as user types → deselect any list item
+ SelectedListProfile = null;
+
+ // Create custom profile from raw IP
+ if (IPAddress.TryParse(_dnsServerQuickInput, out IPAddress x))
+ {
+ // Temporarily switch to this custom profile
+ DNSServer = new DNSServerConnectionInfoProfile("CUSTOM", [new ServerConnectionInfo(x.ToString(), 53)]);
+ }
+ }
+ }
+
+ private List _queryTypes = [];
public List QueryTypes
{
@@ -220,10 +266,14 @@ public DNSLookupViewModel(IDialogCoordinator instance, Guid tabId, string host)
ListSortDirection.Descending));
DNSServers.SortDescriptions.Add(new SortDescription(nameof(DNSServerConnectionInfoProfile.Name),
ListSortDirection.Ascending));
- DNSServer = DNSServers.SourceCollection.Cast()
+ var initialDNSServer = DNSServers.SourceCollection.Cast()
.FirstOrDefault(x => x.Name == SettingsManager.Current.DNSLookup_SelectedDNSServer.Name) ??
DNSServers.SourceCollection.Cast().First();
+ DNSServer = initialDNSServer;
+ SelectedListProfile = initialDNSServer;
+ DNSServerQuickInput = initialDNSServer.ToString();
+
ResultsView = CollectionViewSource.GetDefaultView(Results);
ResultsView.GroupDescriptions.Add(new PropertyGroupDescription(nameof(DNSLookupRecordInfo.NameServerAsString)));
ResultsView.SortDescriptions.Add(new SortDescription(nameof(DNSLookupRecordInfo.NameServerIPAddress),
diff --git a/Source/NETworkManager/Views/DNSLookupView.xaml b/Source/NETworkManager/Views/DNSLookupView.xaml
index 7917c324aa..faab72a4eb 100644
--- a/Source/NETworkManager/Views/DNSLookupView.xaml
+++ b/Source/NETworkManager/Views/DNSLookupView.xaml
@@ -19,7 +19,6 @@
-
@@ -71,15 +70,13 @@
-
-
-
-
-
-
+
From 027b11b6cfdfa8b0b08fd63550155a983e39687d Mon Sep 17 00:00:00 2001
From: BornToBeRoot <16019165+BornToBeRoot@users.noreply.github.com>
Date: Wed, 10 Dec 2025 22:49:26 +0100
Subject: [PATCH 2/5] Feature: Enter dns server in ui
---
Source/GlobalAssemblyInfo.cs | 4 +-
.../Network/DNSLookupErrorArgs.cs | 1 +
.../Network/DNSServerConnectionInfoProfile.cs | 1 +
.../NETworkManager.Settings/SettingsInfo.cs | 28 ++--
.../SettingsManager.cs | 10 ++
.../ViewModels/DNSLookupViewModel.cs | 142 +++++++++++-------
.../NETworkManager/Views/DNSLookupView.xaml | 8 +-
7 files changed, 117 insertions(+), 77 deletions(-)
diff --git a/Source/GlobalAssemblyInfo.cs b/Source/GlobalAssemblyInfo.cs
index 1b58f5b727..f756fd756f 100644
--- a/Source/GlobalAssemblyInfo.cs
+++ b/Source/GlobalAssemblyInfo.cs
@@ -6,5 +6,5 @@
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
-[assembly: AssemblyVersion("2025.11.16.0")]
-[assembly: AssemblyFileVersion("2025.11.16.0")]
+[assembly: AssemblyVersion("2025.12.10.0")]
+[assembly: AssemblyFileVersion("2025.12.10.0")]
diff --git a/Source/NETworkManager.Models/Network/DNSLookupErrorArgs.cs b/Source/NETworkManager.Models/Network/DNSLookupErrorArgs.cs
index ee773b65ca..59d93615d0 100644
--- a/Source/NETworkManager.Models/Network/DNSLookupErrorArgs.cs
+++ b/Source/NETworkManager.Models/Network/DNSLookupErrorArgs.cs
@@ -6,6 +6,7 @@ public class DNSLookupErrorArgs : EventArgs
{
public DNSLookupErrorArgs()
{
+
}
public DNSLookupErrorArgs(string query, string server, string ipEndPoint, string errorMessage)
diff --git a/Source/NETworkManager.Models/Network/DNSServerConnectionInfoProfile.cs b/Source/NETworkManager.Models/Network/DNSServerConnectionInfoProfile.cs
index 32737e9f71..c1ba8003f2 100644
--- a/Source/NETworkManager.Models/Network/DNSServerConnectionInfoProfile.cs
+++ b/Source/NETworkManager.Models/Network/DNSServerConnectionInfoProfile.cs
@@ -24,6 +24,7 @@ public DNSServerConnectionInfoProfile()
/// List of servers as .
public DNSServerConnectionInfoProfile(string name, List servers) : base(name, servers)
{
+
}
///
diff --git a/Source/NETworkManager.Settings/SettingsInfo.cs b/Source/NETworkManager.Settings/SettingsInfo.cs
index 428cd23715..7f195085d2 100644
--- a/Source/NETworkManager.Settings/SettingsInfo.cs
+++ b/Source/NETworkManager.Settings/SettingsInfo.cs
@@ -1723,7 +1723,7 @@ public ExportFileType Traceroute_ExportFileType
#region DNS Lookup
- private ObservableCollection _dnsLookup_HostHistory = new();
+ private ObservableCollection _dnsLookup_HostHistory = [];
public ObservableCollection DNSLookup_HostHistory
{
@@ -1738,7 +1738,7 @@ public ObservableCollection DNSLookup_HostHistory
}
}
- private ObservableCollection _dnsLookup_DNSServers = new();
+ private ObservableCollection _dnsLookup_DNSServers = [];
public ObservableCollection DNSLookup_DNSServers
{
@@ -1753,8 +1753,10 @@ public ObservableCollection DNSLookup_DNSServers
}
}
+ [Obsolete("Use DNSLookup_SelectedDNSServer_v2 instead.")]
private DNSServerConnectionInfoProfile _dnsLookup_SelectedDNSServer = null;
+ [Obsolete("Use DNSLookup_SelectedDNSServer_v2 instead.")]
public DNSServerConnectionInfoProfile DNSLookup_SelectedDNSServer
{
get => _dnsLookup_SelectedDNSServer;
@@ -1768,37 +1770,35 @@ public DNSServerConnectionInfoProfile DNSLookup_SelectedDNSServer
}
}
- private QueryClass _dnsLookup_QueryClass = GlobalStaticConfiguration.DNSLookup_QueryClass;
+ private string _dnsLookup_SelectedDNSServer_v2;
- public QueryClass DNSLookup_QueryClass
+ public string DNSLookup_SelectedDNSServer_v2
{
- get => _dnsLookup_QueryClass;
+ get => _dnsLookup_SelectedDNSServer_v2;
set
{
- if (value == _dnsLookup_QueryClass)
+ if (value == _dnsLookup_SelectedDNSServer_v2)
return;
- _dnsLookup_QueryClass = value;
+ _dnsLookup_SelectedDNSServer_v2 = value;
OnPropertyChanged();
}
}
- /*
- private bool _dnsLookup_ShowOnlyMostCommonQueryTypes = true;
+ private QueryClass _dnsLookup_QueryClass = GlobalStaticConfiguration.DNSLookup_QueryClass;
- public bool DNSLookup_ShowOnlyMostCommonQueryTypes
+ public QueryClass DNSLookup_QueryClass
{
- get => _dnsLookup_ShowOnlyMostCommonQueryTypes;
+ get => _dnsLookup_QueryClass;
set
{
- if (value == _dnsLookup_ShowOnlyMostCommonQueryTypes)
+ if (value == _dnsLookup_QueryClass)
return;
- _dnsLookup_ShowOnlyMostCommonQueryTypes = value;
+ _dnsLookup_QueryClass = value;
OnPropertyChanged();
}
}
- */
private QueryType _dnsLookup_QueryType = GlobalStaticConfiguration.DNSLookup_QueryType;
diff --git a/Source/NETworkManager.Settings/SettingsManager.cs b/Source/NETworkManager.Settings/SettingsManager.cs
index 2d3146aab9..cbd20d5ff4 100644
--- a/Source/NETworkManager.Settings/SettingsManager.cs
+++ b/Source/NETworkManager.Settings/SettingsManager.cs
@@ -337,6 +337,16 @@ private static void UpgradeToLatest(Version version)
{
Log.Info($"Apply upgrade to {version}...");
+ // DNS Lookup
+
+ Log.Info("Migrate DNS Lookup settings to new structure...");
+
+ Current.DNSLookup_SelectedDNSServer_v2 = Current.DNSLookup_SelectedDNSServer?.Name;
+
+ Log.Info($"Selected DNS server set to \"{Current.DNSLookup_SelectedDNSServer_v2}\"");
+
+ // AWS Session Manager
+
Log.Info("Removing deprecated app \"AWS Session Manager\", if it exists...");
var appToRemove = Current.General_ApplicationList
diff --git a/Source/NETworkManager/ViewModels/DNSLookupViewModel.cs b/Source/NETworkManager/ViewModels/DNSLookupViewModel.cs
index fb45193397..ad963abb08 100644
--- a/Source/NETworkManager/ViewModels/DNSLookupViewModel.cs
+++ b/Source/NETworkManager/ViewModels/DNSLookupViewModel.cs
@@ -81,77 +81,50 @@ public string Host
///
/// Backing field for .
///
- private DNSServerConnectionInfoProfile _dnsServer = new();
+ private string _dnsServer;
///
/// Gets or sets the selected DNS server.
+ /// This can either be an ip/host:port or a profile name.
///
- public DNSServerConnectionInfoProfile DNSServer
+ public string DNSServer
{
get => _dnsServer;
- private set
+ set
{
if (_dnsServer == value)
return;
-
- _dnsServer = value ?? new DNSServerConnectionInfoProfile();
- if (!_isLoading)
- SettingsManager.Current.DNSLookup_SelectedDNSServer = _dnsServer;
-
- OnPropertyChanged();
- }
- }
+ // Try finding matching dns server profile by name, otherwise set to null (de-select)
+ SelectedDNSServer = SettingsManager.Current.DNSLookup_DNSServers
+ .FirstOrDefault(x => x.Name == value);
- private DNSServerConnectionInfoProfile _selectedListProfile;
- public DNSServerConnectionInfoProfile SelectedListProfile
- {
- get => _selectedListProfile;
- set
- {
- if (_selectedListProfile == value)
- return;
-
- if (value != null)
- {
- DNSServer = value;
- DNSServerQuickInput = value.ToString(); // uses your override
- }
+ if (!_isLoading)
+ SettingsManager.Current.DNSLookup_SelectedDNSServer_v2 = value;
- _selectedListProfile = value;
+ _dnsServer = value;
OnPropertyChanged();
}
}
- // Text box content
- private string _dnsServerQuickInput = string.Empty;
- public string DNSServerQuickInput
+ private DNSServerConnectionInfoProfile _selectedDNSServer;
+ public DNSServerConnectionInfoProfile SelectedDNSServer
{
- get => _dnsServerQuickInput;
+ get => _selectedDNSServer;
set
{
- if (_dnsServerQuickInput == value)
+ if (_selectedDNSServer == value)
return;
- _dnsServerQuickInput = value?.Trim() ?? string.Empty;
+ _selectedDNSServer = value;
OnPropertyChanged();
-
- // As soon as user types → deselect any list item
- SelectedListProfile = null;
-
- // Create custom profile from raw IP
- if (IPAddress.TryParse(_dnsServerQuickInput, out IPAddress x))
- {
- // Temporarily switch to this custom profile
- DNSServer = new DNSServerConnectionInfoProfile("CUSTOM", [new ServerConnectionInfo(x.ToString(), 53)]);
- }
}
}
///
/// Backing field for .
///
- private List _queryTypes = new();
+ private List _queryTypes = [];
///
/// Gets the list of available query types.
@@ -217,7 +190,7 @@ public bool IsRunning
///
/// Backing field for .
///
- private ObservableCollection _results = new();
+ private ObservableCollection _results = [];
///
/// Gets or sets the collection of lookup results.
@@ -351,13 +324,10 @@ public DNSLookupViewModel(IDialogCoordinator instance, Guid tabId, string host)
ListSortDirection.Descending));
DNSServers.SortDescriptions.Add(new SortDescription(nameof(DNSServerConnectionInfoProfile.Name),
ListSortDirection.Ascending));
- var initialDNSServer = DNSServers.SourceCollection.Cast()
- .FirstOrDefault(x => x.Name == SettingsManager.Current.DNSLookup_SelectedDNSServer.Name) ??
- DNSServers.SourceCollection.Cast().First();
-
- DNSServer = initialDNSServer;
- SelectedListProfile = initialDNSServer;
- DNSServerQuickInput = initialDNSServer.ToString();
+
+ DNSServer = string.IsNullOrEmpty(SettingsManager.Current.DNSLookup_SelectedDNSServer_v2)
+ ? SettingsManager.Current.DNSLookup_DNSServers.FirstOrDefault()?.Name
+ : SettingsManager.Current.DNSLookup_SelectedDNSServer_v2;
ResultsView = CollectionViewSource.GetDefaultView(Results);
ResultsView.GroupDescriptions.Add(new PropertyGroupDescription(nameof(DNSLookupRecordInfo.NameServerAsString)));
@@ -381,7 +351,7 @@ public void OnLoaded()
return;
if (!string.IsNullOrEmpty(Host))
- Query();
+ QueryAsync();
_firstLoad = false;
}
@@ -441,7 +411,7 @@ private bool Query_CanExecute(object parameter)
private void QueryAction()
{
if (!IsRunning)
- Query();
+ QueryAsync();
}
///
@@ -464,7 +434,7 @@ private void ExportAction()
///
/// Performs the DNS query.
///
- private void Query()
+ private async Task QueryAsync()
{
IsStatusMessageDisplayed = false;
StatusMessage = string.Empty;
@@ -496,9 +466,67 @@ private void Query()
dnsSettings.CustomDNSSuffix = SettingsManager.Current.DNSLookup_CustomDNSSuffix?.TrimStart('.');
}
- var dnsLookup = DNSServer.UseWindowsDNSServer
- ? new DNSLookup(dnsSettings)
- : new DNSLookup(dnsSettings, DNSServer.Servers);
+
+ DNSLookup dnsLookup;
+
+ // Try find existing dns server profile
+ var dnsServerProfile = SettingsManager.Current.DNSLookup_DNSServers
+ .FirstOrDefault(x => x.Name == DNSServer);
+
+ // Use profile if found
+ if (dnsServerProfile != null)
+ {
+ dnsLookup = dnsServerProfile.UseWindowsDNSServer
+ ? new DNSLookup(dnsSettings)
+ : new DNSLookup(dnsSettings, dnsServerProfile.Servers);
+ }
+ // Otherwise try to parse custom server string
+ else
+ {
+ List customDNSServers = [];
+
+ foreach (var customDNSServer in DNSServer.Split(';').Select(x => x.Trim()))
+ {
+ var customDNSServerArgs = customDNSServer.Split(':');
+
+ var server = customDNSServerArgs[0];
+ var port = customDNSServerArgs.Length == 2 && int.TryParse(customDNSServerArgs[1], out var p) ? p : 53;
+
+ // Resolve hostname to IP address
+ if (!IPAddress.TryParse(server, out _))
+ {
+ var dnsResult = await DNSClientHelper.ResolveAorAaaaAsync(server,
+ SettingsManager.Current.Network_ResolveHostnamePreferIPv4);
+
+ if (dnsResult.HasError)
+ {
+ var dnsErrorMessage = DNSClientHelper.FormatDNSClientResultError(server, dnsResult);
+
+ if(!string.IsNullOrEmpty(StatusMessage))
+ StatusMessage += Environment.NewLine;
+
+ StatusMessage += $"{Strings.DNSServer}: {dnsErrorMessage}";
+ IsStatusMessageDisplayed = true;
+
+ continue; // Skip this server, try next one
+ }
+
+ server = dnsResult.Value.ToString();
+ }
+
+ customDNSServers.Add(new ServerConnectionInfo(server, port, TransportProtocol.Udp));
+ }
+
+ // Check if we have any valid custom dns servers
+ if (customDNSServers.Count == 0)
+ {
+ IsRunning = false;
+
+ return;
+ }
+
+ dnsLookup = new DNSLookup(dnsSettings, customDNSServers);
+ }
dnsLookup.RecordReceived += DNSLookup_RecordReceived;
dnsLookup.LookupError += DNSLookup_LookupError;
diff --git a/Source/NETworkManager/Views/DNSLookupView.xaml b/Source/NETworkManager/Views/DNSLookupView.xaml
index faab72a4eb..fc2efbd7f6 100644
--- a/Source/NETworkManager/Views/DNSLookupView.xaml
+++ b/Source/NETworkManager/Views/DNSLookupView.xaml
@@ -71,10 +71,10 @@
From 37d77447a450dc35f290f5305d4edf946a29fe0c Mon Sep 17 00:00:00 2001
From: BornToBeRoot <16019165+BornToBeRoot@users.noreply.github.com>
Date: Wed, 10 Dec 2025 23:07:24 +0100
Subject: [PATCH 3/5] Update DNSLookupView.xaml
---
Source/NETworkManager/Views/DNSLookupView.xaml | 15 ++++++++++-----
1 file changed, 10 insertions(+), 5 deletions(-)
diff --git a/Source/NETworkManager/Views/DNSLookupView.xaml b/Source/NETworkManager/Views/DNSLookupView.xaml
index fc2efbd7f6..904c9ef194 100644
--- a/Source/NETworkManager/Views/DNSLookupView.xaml
+++ b/Source/NETworkManager/Views/DNSLookupView.xaml
@@ -73,10 +73,15 @@
+ SelectedItem="{Binding SelectedDNSServer}"
+ IsEditable="True">
+
+
+
+
+
+
+
@@ -93,7 +98,7 @@
Value="True">
-
From 20bd604d06b86b07751befb18d6ab8eaaaf1085f Mon Sep 17 00:00:00 2001
From: BornToBeRoot <16019165+BornToBeRoot@users.noreply.github.com>
Date: Wed, 10 Dec 2025 23:35:05 +0100
Subject: [PATCH 4/5] Chore: Adjust regex for IPv4
---
...lOrEmptyOrIPv4AddressToBooleanConverter.cs | 7 ++--
.../Network/HostRangeHelper.cs | 9 +++--
.../Network/SNTPLookup.cs | 7 ++--
.../NETworkManager.Utilities/RegexHelper.cs | 40 ++++++++++++++-----
.../EmptyOrIPv4AddressValidator.cs | 9 +++--
.../IPAddressOrHostnameAsRangeValidator.cs | 2 +-
.../IPAddressOrHostnameValidator.cs | 2 +-
.../IPv4AddressValidator.cs | 9 ++---
.../MultipleHostsRangeValidator.cs | 12 +++---
.../MultipleIPAddressesValidator.cs | 12 +++---
.../ServerValidator.cs | 4 +-
.../NetworkConnectionWidgetViewModel.cs | 2 +-
.../ServerConnectionInfoProfileDialog.xaml | 2 +-
13 files changed, 68 insertions(+), 49 deletions(-)
diff --git a/Source/NETworkManager.Converters/StringIsNotNullOrEmptyOrIPv4AddressToBooleanConverter.cs b/Source/NETworkManager.Converters/StringIsNotNullOrEmptyOrIPv4AddressToBooleanConverter.cs
index 31e3e5a3d8..a118a33030 100644
--- a/Source/NETworkManager.Converters/StringIsNotNullOrEmptyOrIPv4AddressToBooleanConverter.cs
+++ b/Source/NETworkManager.Converters/StringIsNotNullOrEmptyOrIPv4AddressToBooleanConverter.cs
@@ -1,8 +1,7 @@
-using System;
+using NETworkManager.Utilities;
+using System;
using System.Globalization;
-using System.Text.RegularExpressions;
using System.Windows.Data;
-using NETworkManager.Utilities;
namespace NETworkManager.Converters;
@@ -10,7 +9,7 @@ public sealed class StringIsNotNullOrEmptyOrIPv4AddressToBooleanConverter : IVal
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
- return !string.IsNullOrEmpty(value as string) && !Regex.IsMatch((string)value, RegexHelper.IPv4AddressRegex);
+ return !string.IsNullOrEmpty(value as string) && !RegexHelper.IPv4AddressRegex().IsMatch((string)value);
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
diff --git a/Source/NETworkManager.Models/Network/HostRangeHelper.cs b/Source/NETworkManager.Models/Network/HostRangeHelper.cs
index 9017e5ce80..37928f8368 100644
--- a/Source/NETworkManager.Models/Network/HostRangeHelper.cs
+++ b/Source/NETworkManager.Models/Network/HostRangeHelper.cs
@@ -1,4 +1,6 @@
-using System.Collections.Concurrent;
+using ControlzEx.Standard;
+using NETworkManager.Utilities;
+using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Net;
@@ -6,7 +8,6 @@
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
-using NETworkManager.Utilities;
namespace NETworkManager.Models.Network;
@@ -46,7 +47,7 @@ private static (List<(IPAddress ipAddress, string hostname)> hosts, List
switch (host)
{
// 192.168.0.1
- case var _ when Regex.IsMatch(host, RegexHelper.IPv4AddressRegex):
+ case var _ when RegexHelper.IPv4AddressRegex().IsMatch(host):
// 2001:db8:85a3::8a2e:370:7334
case var _ when Regex.IsMatch(host, RegexHelper.IPv6AddressRegex):
hostsBag.Add((IPAddress.Parse(host), string.Empty));
@@ -71,7 +72,7 @@ private static (List<(IPAddress ipAddress, string hostname)> hosts, List
break;
// 192.168.0.0 - 192.168.0.100
- case var _ when Regex.IsMatch(host, RegexHelper.IPv4AddressRangeRegex):
+ case var _ when RegexHelper.IPv4AddressRangeRegex().IsMatch(host):
var range = host.Split('-');
Parallel.For(IPv4Address.ToInt32(IPAddress.Parse(range[0])),
diff --git a/Source/NETworkManager.Models/Network/SNTPLookup.cs b/Source/NETworkManager.Models/Network/SNTPLookup.cs
index 6f6b8d351c..0a20f369c0 100644
--- a/Source/NETworkManager.Models/Network/SNTPLookup.cs
+++ b/Source/NETworkManager.Models/Network/SNTPLookup.cs
@@ -1,10 +1,11 @@
-using System;
+using ControlzEx.Standard;
+using NETworkManager.Utilities;
+using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
-using NETworkManager.Utilities;
namespace NETworkManager.Models.Network;
@@ -102,7 +103,7 @@ public void QueryAsync(IEnumerable servers, bool dnsResolv
// NTP requires an IP address to connect to
IPAddress serverIP = null;
- if (Regex.IsMatch(server.Server, RegexHelper.IPv4AddressRegex) ||
+ if (RegexHelper.IPv4AddressRegex().IsMatch(server.Server) ||
Regex.IsMatch(server.Server, RegexHelper.IPv6AddressRegex))
{
serverIP = IPAddress.Parse(server.Server);
diff --git a/Source/NETworkManager.Utilities/RegexHelper.cs b/Source/NETworkManager.Utilities/RegexHelper.cs
index c1445c70a7..ba09fd7ce2 100644
--- a/Source/NETworkManager.Utilities/RegexHelper.cs
+++ b/Source/NETworkManager.Utilities/RegexHelper.cs
@@ -1,6 +1,8 @@
-namespace NETworkManager.Utilities;
+using System.Text.RegularExpressions;
-public static class RegexHelper
+namespace NETworkManager.Utilities;
+
+public static partial class RegexHelper
{
///
/// Match an IPv4-Address like 192.168.178.1
@@ -10,20 +12,36 @@ public static class RegexHelper
@"((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)";
///
- /// Match exactly an IPv4-Address like 192.168.178.1
+ /// Provides a compiled regular expression that matches valid IPv4 addresses in dot-decimal notation.
///
- // ReSharper disable once InconsistentNaming
- public const string IPv4AddressRegex = $"^{IPv4AddressValues}$";
+ /// The returned regular expression is compiled for performance. Use this regex to validate or
+ /// extract IPv4 addresses from text. The pattern enforces correct octet ranges and dot separators.
+ /// A instance that matches IPv4 addresses in the format "x.x.x.x", where each x is a number
+ /// from 0 to 255.
+ [GeneratedRegex($"^{IPv4AddressValues}$")]
+ public static partial Regex IPv4AddressRegex();
///
- /// Match IPv4-Address within a string
+ /// Provides a compiled regular expression that matches valid IPv4 addresses within input text.
///
- // ReSharper disable once InconsistentNaming
- public const string IPv4AddressExtractRegex = IPv4AddressValues;
+ /// The returned regular expression matches IPv4 addresses in standard dotted-decimal notation
+ /// (e.g., "192.168.1.1"). The regular expression is compiled for improved performance when used
+ /// repeatedly.
+ /// A instance that can be used to extract IPv4 addresses from strings.
+ [GeneratedRegex(IPv4AddressValues)]
+ public static partial Regex IPv4AddressExtractRegex();
- // Match IPv4-Address Range like 192.168.178.1-192.168.178.127
- // ReSharper disable once InconsistentNaming
- public const string IPv4AddressRangeRegex = $"^{IPv4AddressValues}-{IPv4AddressValues}$";
+ ///
+ /// Gets a regular expression that matches an IPv4 address range in the format "start-end", where both start and end
+ /// are valid IPv4 addresses.
+ ///
+ /// The regular expression expects the input to consist of two IPv4 addresses separated by a
+ /// hyphen, with no additional whitespace or characters. Both addresses must be valid IPv4 addresses. This can be
+ /// used to validate or parse address range strings in network configuration scenarios.
+ /// A instance that matches strings representing IPv4 address ranges, such as
+ /// "192.168.1.1-192.168.1.100".
+ [GeneratedRegex($"^{IPv4AddressValues}-{IPv4AddressValues}$")]
+ public static partial Regex IPv4AddressRangeRegex();
// Match a MAC-Address 000000000000 00:00:00:00:00:00, 00-00-00-00-00-00-00 or 0000.0000.0000
public const string MACAddressRegex =
diff --git a/Source/NETworkManager.Validators/EmptyOrIPv4AddressValidator.cs b/Source/NETworkManager.Validators/EmptyOrIPv4AddressValidator.cs
index 471a02fc5a..53acea2a99 100644
--- a/Source/NETworkManager.Validators/EmptyOrIPv4AddressValidator.cs
+++ b/Source/NETworkManager.Validators/EmptyOrIPv4AddressValidator.cs
@@ -1,8 +1,9 @@
-using System.Globalization;
-using System.Text.RegularExpressions;
-using System.Windows.Controls;
+using ControlzEx.Standard;
using NETworkManager.Localization.Resources;
using NETworkManager.Utilities;
+using System.Globalization;
+using System.Text.RegularExpressions;
+using System.Windows.Controls;
namespace NETworkManager.Validators;
@@ -13,7 +14,7 @@ public override ValidationResult Validate(object value, CultureInfo cultureInfo)
if (string.IsNullOrEmpty(value as string))
return ValidationResult.ValidResult;
- return Regex.IsMatch((string)value, RegexHelper.IPv4AddressRegex)
+ return RegexHelper.IPv4AddressRegex().IsMatch((string)value)
? ValidationResult.ValidResult
: new ValidationResult(false, Strings.EnterValidIPv4Address);
}
diff --git a/Source/NETworkManager.Validators/IPAddressOrHostnameAsRangeValidator.cs b/Source/NETworkManager.Validators/IPAddressOrHostnameAsRangeValidator.cs
index 8392c450dc..ffb76cbb75 100644
--- a/Source/NETworkManager.Validators/IPAddressOrHostnameAsRangeValidator.cs
+++ b/Source/NETworkManager.Validators/IPAddressOrHostnameAsRangeValidator.cs
@@ -20,7 +20,7 @@ public override ValidationResult Validate(object value, CultureInfo cultureInfo)
var localItem = item.Trim();
// Check if it is a valid IPv4 address like 192.168.0.1, a valid IPv6 address like ::1 or a valid hostname like server-01 or server-01.example.com
- var isValid = Regex.IsMatch(localItem, RegexHelper.IPv4AddressRegex) ||
+ var isValid = RegexHelper.IPv4AddressRegex().IsMatch(localItem) ||
Regex.IsMatch(localItem, RegexHelper.IPv6AddressRegex) ||
Regex.IsMatch(localItem, RegexHelper.HostnameOrDomainRegex);
diff --git a/Source/NETworkManager.Validators/IPAddressOrHostnameValidator.cs b/Source/NETworkManager.Validators/IPAddressOrHostnameValidator.cs
index 3aa1980789..3126b87a16 100644
--- a/Source/NETworkManager.Validators/IPAddressOrHostnameValidator.cs
+++ b/Source/NETworkManager.Validators/IPAddressOrHostnameValidator.cs
@@ -16,7 +16,7 @@ public override ValidationResult Validate(object value, CultureInfo cultureInfo)
return new ValidationResult(false, Strings.EnterValidHostnameOrIPAddress);
// Check if it is a valid IPv4 address like 192.168.0.1
- if (Regex.IsMatch(input, RegexHelper.IPv4AddressRegex))
+ if (RegexHelper.IPv4AddressRegex().IsMatch(input))
return ValidationResult.ValidResult;
// Check if it is a valid IPv6 address like ::1
diff --git a/Source/NETworkManager.Validators/IPv4AddressValidator.cs b/Source/NETworkManager.Validators/IPv4AddressValidator.cs
index 9149f54977..2ed8c3060a 100644
--- a/Source/NETworkManager.Validators/IPv4AddressValidator.cs
+++ b/Source/NETworkManager.Validators/IPv4AddressValidator.cs
@@ -1,8 +1,7 @@
-using System.Globalization;
-using System.Text.RegularExpressions;
-using System.Windows.Controls;
-using NETworkManager.Localization.Resources;
+using NETworkManager.Localization.Resources;
using NETworkManager.Utilities;
+using System.Globalization;
+using System.Windows.Controls;
namespace NETworkManager.Validators;
@@ -15,7 +14,7 @@ public override ValidationResult Validate(object value, CultureInfo cultureInfo)
if (string.IsNullOrEmpty(ipAddress))
return new ValidationResult(false, Strings.EnterValidIPv4Address);
- return Regex.IsMatch(ipAddress, RegexHelper.IPv4AddressRegex)
+ return RegexHelper.IPv4AddressRegex().IsMatch(ipAddress)
? ValidationResult.ValidResult
: new ValidationResult(false, Strings.EnterValidIPv4Address);
}
diff --git a/Source/NETworkManager.Validators/MultipleHostsRangeValidator.cs b/Source/NETworkManager.Validators/MultipleHostsRangeValidator.cs
index aa6f4bba96..5b3bdf9bc3 100644
--- a/Source/NETworkManager.Validators/MultipleHostsRangeValidator.cs
+++ b/Source/NETworkManager.Validators/MultipleHostsRangeValidator.cs
@@ -1,10 +1,10 @@
-using System.Globalization;
+using NETworkManager.Localization.Resources;
+using NETworkManager.Models.Network;
+using NETworkManager.Utilities;
+using System.Globalization;
using System.Net;
using System.Text.RegularExpressions;
using System.Windows.Controls;
-using NETworkManager.Localization.Resources;
-using NETworkManager.Models.Network;
-using NETworkManager.Utilities;
namespace NETworkManager.Validators;
@@ -20,7 +20,7 @@ public override ValidationResult Validate(object value, CultureInfo cultureInfo)
foreach (var ipHostOrRange in ((string)value).Replace(" ", "").Split(';'))
{
// 192.168.0.1
- if (Regex.IsMatch(ipHostOrRange, RegexHelper.IPv4AddressRegex))
+ if (RegexHelper.IPv4AddressRegex().IsMatch(ipHostOrRange))
continue;
// 192.168.0.0/24
@@ -32,7 +32,7 @@ public override ValidationResult Validate(object value, CultureInfo cultureInfo)
continue;
// 192.168.0.0 - 192.168.0.100
- if (Regex.IsMatch(ipHostOrRange, RegexHelper.IPv4AddressRangeRegex))
+ if (RegexHelper.IPv4AddressRangeRegex().IsMatch(ipHostOrRange))
{
var range = ipHostOrRange.Split('-');
diff --git a/Source/NETworkManager.Validators/MultipleIPAddressesValidator.cs b/Source/NETworkManager.Validators/MultipleIPAddressesValidator.cs
index 9089606473..ed0d1a3d83 100644
--- a/Source/NETworkManager.Validators/MultipleIPAddressesValidator.cs
+++ b/Source/NETworkManager.Validators/MultipleIPAddressesValidator.cs
@@ -1,8 +1,8 @@
-using System.Globalization;
+using NETworkManager.Localization.Resources;
+using NETworkManager.Utilities;
+using System.Globalization;
using System.Text.RegularExpressions;
using System.Windows.Controls;
-using NETworkManager.Localization.Resources;
-using NETworkManager.Utilities;
namespace NETworkManager.Validators;
@@ -15,13 +15,13 @@ public override ValidationResult Validate(object value, CultureInfo cultureInfo)
for (var index = 0; index < ((string)value).Split(';').Length; index++)
{
- var ipAddress = ((string)value).Split(';')[index];
+ var ipAddress = ((string)value).Split(';')[index].Trim();
- if (!Regex.IsMatch(ipAddress.Trim(), RegexHelper.IPv4AddressRegex) &&
+ if (!RegexHelper.IPv4AddressRegex().IsMatch(ipAddress) &&
!Regex.IsMatch(ipAddress.Trim(), RegexHelper.IPv6AddressRegex))
return new ValidationResult(false, Strings.EnterOneOrMoreValidIPAddresses);
}
return ValidationResult.ValidResult;
}
-}
\ No newline at end of file
+}
diff --git a/Source/NETworkManager.Validators/ServerValidator.cs b/Source/NETworkManager.Validators/ServerValidator.cs
index bd82d4f88c..ca2d381cd3 100644
--- a/Source/NETworkManager.Validators/ServerValidator.cs
+++ b/Source/NETworkManager.Validators/ServerValidator.cs
@@ -6,7 +6,7 @@
namespace NETworkManager.Validators;
-public class ServerValidator : ValidationRule
+public partial class ServerValidator : ValidationRule
{
public ServerDependencyObjectWrapper Wrapper { get; set; }
@@ -22,7 +22,7 @@ public override ValidationResult Validate(object value, CultureInfo cultureInfo)
return new ValidationResult(false, genericErrorResult);
// Check if it is a valid IPv4 address like 192.168.0.1
- if (Regex.IsMatch(input, RegexHelper.IPv4AddressRegex))
+ if (RegexHelper.IPv4AddressRegex().IsMatch(input))
return ValidationResult.ValidResult;
// Check if it is a valid IPv6 address like ::1
diff --git a/Source/NETworkManager/ViewModels/NetworkConnectionWidgetViewModel.cs b/Source/NETworkManager/ViewModels/NetworkConnectionWidgetViewModel.cs
index 50cee9098d..5a0dc1e3bc 100644
--- a/Source/NETworkManager/ViewModels/NetworkConnectionWidgetViewModel.cs
+++ b/Source/NETworkManager/ViewModels/NetworkConnectionWidgetViewModel.cs
@@ -1071,7 +1071,7 @@ private Task CheckConnectionInternetAsync(CancellationToken ct)
var result = await httpResponse.Content.ReadAsStringAsync(ct);
- var match = Regex.Match(result, RegexHelper.IPv4AddressExtractRegex);
+ var match = RegexHelper.IPv4AddressExtractRegex().Match(result);
if (match.Success)
{
diff --git a/Source/NETworkManager/Views/ServerConnectionInfoProfileDialog.xaml b/Source/NETworkManager/Views/ServerConnectionInfoProfileDialog.xaml
index 9333725433..db26ad245e 100644
--- a/Source/NETworkManager/Views/ServerConnectionInfoProfileDialog.xaml
+++ b/Source/NETworkManager/Views/ServerConnectionInfoProfileDialog.xaml
@@ -198,4 +198,4 @@
Style="{StaticResource DefaultButton}" />
-
\ No newline at end of file
+
From eddba620ea6c7a9a11b5ddeba7820da6c7ad1b93 Mon Sep 17 00:00:00 2001
From: BornToBeRoot <16019165+BornToBeRoot@users.noreply.github.com>
Date: Wed, 10 Dec 2025 23:55:37 +0100
Subject: [PATCH 5/5] Chore: Migrate regex to generatedRegex
---
...dateSubnetCalculatorSubnettingConverter.cs | 3 +-
.../Network/HostRangeHelper.cs | 6 +-
.../NETworkManager.Utilities/RegexHelper.cs | 87 +++++++++++++------
.../IPv4IPv6SubnetValidator.cs | 4 +-
.../IPv4IPv6SubnetmaskOrCIDRValidator.cs | 3 +-
.../IPv4SubnetValidator.cs | 5 +-
.../IPv4SubnetmaskOrCIDRValidator.cs | 3 +-
.../MultipleHostsRangeValidator.cs | 6 +-
.../SubnetmaskValidator.cs | 3 +-
.../SubnetCalculatorSubnettingViewModel.cs | 3 +-
Website/docs/changelog/next-release.md | 1 +
11 files changed, 76 insertions(+), 48 deletions(-)
diff --git a/Source/NETworkManager.Converters/ValidateSubnetCalculatorSubnettingConverter.cs b/Source/NETworkManager.Converters/ValidateSubnetCalculatorSubnettingConverter.cs
index 3e97213917..3b5eccf929 100644
--- a/Source/NETworkManager.Converters/ValidateSubnetCalculatorSubnettingConverter.cs
+++ b/Source/NETworkManager.Converters/ValidateSubnetCalculatorSubnettingConverter.cs
@@ -2,7 +2,6 @@
using System.Globalization;
using System.Net;
using System.Net.Sockets;
-using System.Text.RegularExpressions;
using System.Windows.Data;
using NETworkManager.Models.Network;
using NETworkManager.Utilities;
@@ -40,7 +39,7 @@ public object Convert(object[] values, Type targetType, object parameter, Cultur
};
// Support subnetmask like 255.255.255.0
- int newCidr = Regex.IsMatch(newSubnetmaskOrCidr, RegexHelper.SubnetmaskRegex)
+ int newCidr = RegexHelper.SubnetmaskRegex().IsMatch(newSubnetmaskOrCidr)
? System.Convert.ToByte(Subnetmask.ConvertSubnetmaskToCidr(IPAddress.Parse(newSubnetmaskOrCidr)))
: System.Convert.ToByte(newSubnetmaskOrCidr.TrimStart('/'));
diff --git a/Source/NETworkManager.Models/Network/HostRangeHelper.cs b/Source/NETworkManager.Models/Network/HostRangeHelper.cs
index 37928f8368..e7e05922c6 100644
--- a/Source/NETworkManager.Models/Network/HostRangeHelper.cs
+++ b/Source/NETworkManager.Models/Network/HostRangeHelper.cs
@@ -55,9 +55,9 @@ private static (List<(IPAddress ipAddress, string hostname)> hosts, List
break;
// 192.168.0.0/24
- case var _ when Regex.IsMatch(host, RegexHelper.IPv4AddressCidrRegex):
+ case var _ when RegexHelper.IPv4AddressCidrRegex().IsMatch(host):
// 192.168.0.0/255.255.255.0
- case var _ when Regex.IsMatch(host, RegexHelper.IPv4AddressSubnetmaskRegex):
+ case var _ when RegexHelper.IPv4AddressSubnetmaskRegex().IsMatch(host):
var network = IPNetwork2.Parse(host);
Parallel.For(IPv4Address.ToInt32(network.Network), IPv4Address.ToInt32(network.Broadcast) + 1,
@@ -87,7 +87,7 @@ private static (List<(IPAddress ipAddress, string hostname)> hosts, List
break;
// 192.168.[50-100].1
- case var _ when Regex.IsMatch(host, RegexHelper.IPv4AddressSpecialRangeRegex):
+ case var _ when RegexHelper.IPv4AddressSpecialRangeRegex().IsMatch(host):
var octets = host.Split('.');
var list = new List>();
diff --git a/Source/NETworkManager.Utilities/RegexHelper.cs b/Source/NETworkManager.Utilities/RegexHelper.cs
index ba09fd7ce2..d9d48ee014 100644
--- a/Source/NETworkManager.Utilities/RegexHelper.cs
+++ b/Source/NETworkManager.Utilities/RegexHelper.cs
@@ -5,12 +5,22 @@ namespace NETworkManager.Utilities;
public static partial class RegexHelper
{
///
- /// Match an IPv4-Address like 192.168.178.1
- ///
- // ReSharper disable once InconsistentNaming
+ /// Represents a regular expression pattern that matches valid IPv4 address values.
+ ///
private const string IPv4AddressValues =
@"((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)";
+ ///
+ /// Represents a regular expression pattern that matches valid IPv4 subnet mask values.
+ ///
+ private const string SubnetmaskValues =
+ @"(((255\.){3}(255|254|252|248|240|224|192|128|0+))|((255\.){2}(255|254|252|248|240|224|192|128|0+)\.0)|((255\.)(255|254|252|248|240|224|192|128|0+)(\.0+){2})|((255|254|252|248|240|224|192|128|0+)(\.0+){3}))";
+
+ ///
+ /// Represents the regular expression pattern used to validate CIDR notation values for IPv4 subnet masks.
+ ///
+ private const string CidrRegexValues = @"([1-9]|[1-2][0-9]|3[0-2])";
+
///
/// Provides a compiled regular expression that matches valid IPv4 addresses in dot-decimal notation.
///
@@ -43,6 +53,51 @@ public static partial class RegexHelper
[GeneratedRegex($"^{IPv4AddressValues}-{IPv4AddressValues}$")]
public static partial Regex IPv4AddressRangeRegex();
+ ///
+ /// Provides a compiled regular expression that matches valid IPv4 subnet mask values.
+ ///
+ /// The returned regular expression is generated at compile time and is optimized for
+ /// performance. Use this regex to validate or parse subnet mask strings in IPv4 networking scenarios.
+ /// A instance that matches strings representing valid IPv4 subnet masks.
+ [GeneratedRegex($"^{SubnetmaskValues}$")]
+ public static partial Regex SubnetmaskRegex();
+
+ ///
+ /// Provides a compiled regular expression that matches IPv4 addresses with subnet masks in CIDR notation, such as
+ /// "192.168.178.0/255.255.255.0".
+ ///
+ /// The returned regular expression validates both the IPv4 address and the subnet mask
+ /// components. Use this regex to verify input strings representing IPv4 subnets in formats like
+ /// "address/mask".
+ /// A instance that matches strings containing an IPv4 address followed by a subnet mask,
+ /// separated by a forward slash.
+ [GeneratedRegex($@"^{IPv4AddressValues}\/{SubnetmaskValues}$")]
+ public static partial Regex IPv4AddressSubnetmaskRegex();
+
+ ///
+ /// Provides a compiled regular expression that matches an IPv4 address in CIDR notation, such as
+ /// "192.168.178.0/24".
+ ///
+ /// The returned regular expression can be used to validate or extract IPv4 addresses with CIDR
+ /// notation, such as "192.168.1.0/24". The pattern enforces correct formatting for both the address and the prefix
+ /// length.
+ /// A instance that matches strings containing an IPv4 address followed by a slash and a valid
+ /// CIDR prefix length.
+ [GeneratedRegex($@"^{IPv4AddressValues}\/{CidrRegexValues}$")]
+ public static partial Regex IPv4AddressCidrRegex();
+
+ ///
+ /// Creates a regular expression that matches IPv4 addresses, allowing for a special range in one or more octets.
+ ///
+ /// The returned regular expression matches standard IPv4 addresses and addresses where one or
+ /// more octets are defined by a custom range pattern. This is useful for validating or parsing addresses such as
+ /// "192.168.[50-100].1" where a range is specified in place of an octet. The format and behavior of the special
+ /// range are determined by the SpecialRangeRegex value.
+ /// A instance that matches IPv4 addresses with support for custom special ranges as defined by
+ /// SpecialRangeRegex.
+ [GeneratedRegex($@"^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|{SpecialRangeRegex})\.){{3}}((?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)|{SpecialRangeRegex})$")]
+ public static partial Regex IPv4AddressSpecialRangeRegex();
+
// Match a MAC-Address 000000000000 00:00:00:00:00:00, 00-00-00-00-00-00-00 or 0000.0000.0000
public const string MACAddressRegex =
@"^^[A-Fa-f0-9]{12}$|^[A-Fa-f0-9]{2}(:|-){1}[A-Fa-f0-9]{2}(:|-){1}[A-Fa-f0-9]{2}(:|-){1}[A-Fa-f0-9]{2}(:|-){1}[A-Fa-f0-9]{2}(:|-){1}[A-Fa-f0-9]{2}$|^[A-Fa-f0-9]{4}.[A-Fa-f0-9]{4}.[A-Fa-f0-9]{4}$$";
@@ -50,24 +105,7 @@ public static partial class RegexHelper
// Match the first 3 bytes of a MAC-Address 000000, 00:00:00, 00-00-00
public const string MACAddressFirst3BytesRegex =
@"^[A-Fa-f0-9]{6}$|^[A-Fa-f0-9]{2}(:|-){1}[A-Fa-f0-9]{2}(:|-){1}[A-Fa-f0-9]{2}$|^[A-Fa-f0-9]{4}.[A-Fa-f0-9]{2}$";
-
- // Private subnetmask / cidr values
- private const string SubnetmaskValues =
- @"(((255\.){3}(255|254|252|248|240|224|192|128|0+))|((255\.){2}(255|254|252|248|240|224|192|128|0+)\.0)|((255\.)(255|254|252|248|240|224|192|128|0+)(\.0+){2})|((255|254|252|248|240|224|192|128|0+)(\.0+){3}))";
-
- private const string CidrRegex = @"([1-9]|[1-2][0-9]|3[0-2])";
-
- // Match a Subnetmask like 255.255.255.0
- public const string SubnetmaskRegex = @"^" + SubnetmaskValues + @"$";
-
- // Match a subnet from 192.168.178.0/1 to 192.168.178.0/32
- // ReSharper disable once InconsistentNaming
- public const string IPv4AddressCidrRegex = $@"^{IPv4AddressValues}\/{CidrRegex}$";
-
- // Match a subnet from 192.168.178.0/192.0.0.0 to 192.168.178.0/255.255.255.255
- // ReSharper disable once InconsistentNaming
- public const string IPv4AddressSubnetmaskRegex = $@"^{IPv4AddressValues}\/{SubnetmaskValues}$";
-
+
// Match IPv6 address like ::1
// ReSharper disable once InconsistentNaming
public const string IPv6AddressRegex =
@@ -82,11 +120,6 @@ public static partial class RegexHelper
public const string SpecialRangeRegex =
@"\[((?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)|((?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)-(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)))([,]((?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)|((?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)-(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?))))*\]";
- // Match a IPv4-Address like 192.168.[50-100].1
- // ReSharper disable once InconsistentNaming
- public const string IPv4AddressSpecialRangeRegex =
- $@"^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|{SpecialRangeRegex})\.){{3}}((?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)|{SpecialRangeRegex})$";
-
// Private hostname values
private const string HostnameOrDomainValues =
@"(?=.{1,255}$)(?!-)[A-Za-z0-9-]{1,63}(?