Skip to content

Commit 72ef095

Browse files
authored
Feature: Ping Monitore - Add multiple hosts (BornToBeRoot#1933)
* Chore: Code cleanup * Chore: Code refactoring / cleanup * Chore: Code Cleanup * Feature: Ping Monitor - Allow multiple hosts * Feature: Ping Monitor - Allow multiple hosts * Feature: Ping Monitor view width * Docs: Add BornToBeRoot#1933 * Feature: Allow multiple hosts in profiles
1 parent e2ac2f5 commit 72ef095

21 files changed

Lines changed: 188 additions & 126 deletions

Source/NETworkManager.Localization/Resources/Strings.Designer.cs

Lines changed: 10 additions & 19 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Source/NETworkManager.Localization/Resources/Strings.resx

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -882,7 +882,7 @@ First make a backup copy of your profile files before enabling encryption!</valu
882882
<value>Hostname or IP address</value>
883883
</data>
884884
<data name="Hosts" xml:space="preserve">
885-
<value>Hosts</value>
885+
<value>Host(s)</value>
886886
</data>
887887
<data name="ID" xml:space="preserve">
888888
<value>ID</value>
@@ -1759,9 +1759,6 @@ Profile files are not affected!</value>
17591759
<data name="Yellow" xml:space="preserve">
17601760
<value>Yellow</value>
17611761
</data>
1762-
<data name="EnterValidValueBetween25and100" xml:space="preserve">
1763-
<value>Enter a valid value between 25 and 100!</value>
1764-
</data>
17651762
<data name="ProfileWithThisNameAlreadyExists" xml:space="preserve">
17661763
<value>A profile with this name already exists!</value>
17671764
</data>
@@ -3314,8 +3311,8 @@ If the option is disabled again, the values are no longer modified. However, the
33143311
<data name="SNTPServerWithThisNameAlreadyExists" xml:space="preserve">
33153312
<value>An SNTP server with this name already exists!</value>
33163313
</data>
3317-
<data name="EnterValidDomainOrIPAddress" xml:space="preserve">
3318-
<value>Enter a valid domain (like "example.com") or a valid IP address (like 192.168.178.1)!</value>
3314+
<data name="EnterValidHostnameOrIPAddress" xml:space="preserve">
3315+
<value>Enter a valid hostname (like "server-01" or "example.com") or a valid IP address (like 192.168.178.1)!</value>
33193316
</data>
33203317
<data name="Servers" xml:space="preserve">
33213318
<value>Server(s)</value>

Source/NETworkManager.Utilities/DNS.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ public async Task<DNSResultIPAddress> ResolveAAsync(string query)
7575
if (result.HasError)
7676
return new DNSResultIPAddress(result.HasError, $"{result.NameServer}: {result.ErrorMessage}");
7777

78-
return new DNSResultIPAddress(result.Answers.ARecords().FirstOrDefault().Address);
78+
return new DNSResultIPAddress(result.Answers.ARecords().FirstOrDefault()?.Address);
7979
}
8080
catch (DnsResponseException ex)
8181
{
@@ -98,7 +98,7 @@ public async Task<DNSResultIPAddress> ResolveAaaaAsync(string query)
9898
if (result.HasError)
9999
return new DNSResultIPAddress(result.HasError, $"{result.NameServer}: {result.ErrorMessage}");
100100

101-
return new DNSResultIPAddress(result.Answers.AaaaRecords().FirstOrDefault().Address);
101+
return new DNSResultIPAddress(result.Answers.AaaaRecords().FirstOrDefault()?.Address);
102102
}
103103
catch (DnsResponseException ex)
104104
{
@@ -120,7 +120,7 @@ public async Task<DNSResultString> ResolveCnameAsync(string query)
120120
if (result.HasError)
121121
return new DNSResultString(result.HasError, $"{result.NameServer}: {result.ErrorMessage}");
122122

123-
return new DNSResultString(result.Answers.CnameRecords().FirstOrDefault().CanonicalName);
123+
return new DNSResultString(result.Answers.CnameRecords().FirstOrDefault()?.CanonicalName);
124124
}
125125
catch (DnsResponseException ex)
126126
{
@@ -142,7 +142,7 @@ public async Task<DNSResultString> ResolvePtrAsync(IPAddress ipAddress)
142142
if (result.HasError)
143143
return new DNSResultString(result.HasError, $"{result.NameServer}: {result.ErrorMessage}");
144144

145-
return new DNSResultString(result.Answers.PtrRecords().FirstOrDefault().PtrDomainName);
145+
return new DNSResultString(result.Answers.PtrRecords().FirstOrDefault()?.PtrDomainName);
146146
}
147147
catch (DnsResponseException ex)
148148
{

Source/NETworkManager.Utilities/DNSResultString.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
///
55
/// </summary>
66
public class DNSResultString : DNSResult
7-
{
7+
{
88
public string Value { get; set; }
99

1010
public DNSResultString(bool hasError, string errorMessage) : base(hasError, errorMessage)

Source/NETworkManager.Utilities/RegexHelper.cs

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -39,12 +39,9 @@ public static class RegexHelper
3939
// Match a subnet from 192.168.178.0/192.0.0.0 to 192.168.178.0/255.255.255.255
4040
public const string IPv4AddressSubnetmaskRegex = @"^" + IPv4AddressValues + @"\/" + SubnetmaskValues + @"$";
4141

42-
// Match IPv6 address
42+
// Match IPv6 address like ::1
4343
public const string IPv6AddressRegex = @"(?:^|(?<=\s))(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))(?=\s|$)";
4444

45-
// Match IPv6 address within a string
46-
public const string IPv6AddressExctractRegex = IPv6AddressRegex;
47-
4845
// Match a subnet like 2001:0db8::/64
4946
public const string IPv6AddressCidrRegex = @"^s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:)))(%.+)?s*(\/([0-9]|[1-9][0-9]|1[0-1][0-9]|12[0-8])){1}?$";
5047

@@ -57,7 +54,7 @@ public static class RegexHelper
5754
// Private hostname values
5855
private const string HostnameValues = @"(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\-]*[A-Za-z0-9])";
5956

60-
// Hostname regex
57+
// Hostname regex like server-01 or server-01.example.com
6158
public const string HostnameRegex = @"^" + HostnameValues + @"$";
6259

6360
// Match a hostname with cidr like server-01.example.com/24

Source/NETworkManager.Validators/DomainOrIPAddressValidator.cs

Lines changed: 0 additions & 19 deletions
This file was deleted.
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
using System.Globalization;
2+
using System.Text.RegularExpressions;
3+
using System.Windows.Controls;
4+
using NETworkManager.Localization.Resources;
5+
using NETworkManager.Utilities;
6+
7+
namespace NETworkManager.Validators
8+
{
9+
public class IPAddressOrHostnameAsRangeValidator : ValidationRule
10+
{
11+
public override ValidationResult Validate(object value, CultureInfo cultureInfo)
12+
{
13+
var input = (value as string)?.Trim();
14+
15+
if (string.IsNullOrEmpty(input))
16+
return new ValidationResult(false, Strings.EnterValidHostnameOrIPAddress);
17+
18+
foreach (var item in input.Split(";"))
19+
{
20+
var localItem = item.Trim();
21+
22+
// 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
23+
var isValid = Regex.IsMatch(localItem, RegexHelper.IPv4AddressRegex) ||
24+
Regex.IsMatch(localItem, RegexHelper.IPv6AddressRegex) ||
25+
Regex.IsMatch(localItem, RegexHelper.HostnameRegex);
26+
27+
if (!isValid)
28+
return new ValidationResult(false, Strings.EnterValidHostnameOrIPAddress);
29+
}
30+
31+
return ValidationResult.ValidResult;
32+
}
33+
}
34+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
using System.Globalization;
2+
using System.Text.RegularExpressions;
3+
using System.Windows.Controls;
4+
using NETworkManager.Localization.Resources;
5+
using NETworkManager.Utilities;
6+
7+
namespace NETworkManager.Validators
8+
{
9+
public class IPAddressOrHostnameValidator : ValidationRule
10+
{
11+
public override ValidationResult Validate(object value, CultureInfo cultureInfo)
12+
{
13+
var input = (value as string)?.Trim();
14+
15+
if(string.IsNullOrEmpty(input))
16+
return new ValidationResult(false, Strings.EnterValidHostnameOrIPAddress);
17+
18+
// Check if it is a valid IPv4 address like 192.168.0.1
19+
if (Regex.IsMatch(input, RegexHelper.IPv4AddressRegex))
20+
return ValidationResult.ValidResult;
21+
22+
// Check if it is a valid IPv6 address like ::1
23+
if (Regex.IsMatch(input, RegexHelper.IPv6AddressRegex))
24+
return ValidationResult.ValidResult;
25+
26+
// Check if it is a valid hostname like server-01 or server-01.example.com
27+
if (Regex.IsMatch(input, RegexHelper.HostnameRegex))
28+
return ValidationResult.ValidResult;
29+
30+
return new ValidationResult(false, Strings.EnterValidHostnameOrIPAddress);
31+
}
32+
}
33+
}

Source/NETworkManager.Validators/OpacityTextboxValidator.cs

Lines changed: 0 additions & 20 deletions
This file was deleted.

Source/NETworkManager/ViewModels/NetworkConnectionViewModel.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -773,7 +773,7 @@ private Task CheckConnectionInternetAsync(CancellationToken ct)
773773

774774
var result = await httpResponse.Content.ReadAsStringAsync();
775775

776-
var match = Regex.Match(result, RegexHelper.IPv6AddressExctractRegex);
776+
var match = Regex.Match(result, RegexHelper.IPv6AddressRegex);
777777

778778
if (match.Success)
779779
{

0 commit comments

Comments
 (0)