Skip to content

Commit 3032223

Browse files
committed
fix: expand ipv6 to support legacy devices
1 parent 922e994 commit 3032223

File tree

2 files changed

+43
-24
lines changed

2 files changed

+43
-24
lines changed

ThingConnect.Pulse.Server/Services/Monitoring/DiscoveryService.cs

Lines changed: 42 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,11 @@ public IEnumerable<string> ExpandCidr(string cidr)
2626
{
2727
if (cidr.Contains(":")) // IPv6 CIDR
2828
{
29-
return ExpandCidrIPv6(cidr);
29+
foreach (var ip in ExpandCidrIPv6(cidr))
30+
{
31+
yield return ip;
32+
}
33+
yield break;
3034
}
3135

3236
Match match = CidrRegex.Match(cidr);
@@ -71,20 +75,22 @@ public IEnumerable<string> ExpandCidr(string cidr)
7175
}
7276

7377
/// <summary>
74-
/// Expand IPv6 CIDR into addresses (limited to /128 or /127 or /64 to avoid flooding)
78+
/// Expand IPv6 CIDR into addresses (limited to /128, /127, or /64 to avoid flooding)
7579
/// </summary>
7680
private IEnumerable<string> ExpandCidrIPv6(string cidr)
7781
{
82+
var result = new List<string>();
83+
7884
try
7985
{
8086
string[] parts = cidr.Split('/');
8187
if (parts.Length != 2)
8288
{
8389
_logger.LogWarning("Invalid IPv6 CIDR format: {Cidr}", cidr);
84-
yield break;
90+
return result;
8591
}
8692

87-
// Check for zone index (e.g., fe80::1%3)
93+
// Handle zone index
8894
string hostPart = parts[0];
8995
string? zoneIndex = null;
9096
if (hostPart.Contains('%'))
@@ -94,35 +100,43 @@ private IEnumerable<string> ExpandCidrIPv6(string cidr)
94100
zoneIndex = hostSplit[1];
95101
}
96102

97-
if (!IPAddress.TryParse(hostPart, out var ip)) yield break;
98-
if (ip.AddressFamily != AddressFamily.InterNetworkV6) yield break;
103+
if (!IPAddress.TryParse(hostPart, out var ip) || ip.AddressFamily != AddressFamily.InterNetworkV6)
104+
return result;
99105

100-
int prefix = int.Parse(parts[1]);
106+
if (!int.TryParse(parts[1], out int prefix))
107+
return result;
108+
109+
string ApplyZone(string address) => zoneIndex != null ? $"{address}%{zoneIndex}" : address;
101110

102111
if (prefix == 128)
103-
yield return zoneIndex != null ? $"{ip}%{zoneIndex}" : ip.ToString();
112+
{
113+
result.Add(ApplyZone(ip.ToString()));
114+
}
104115
else if (prefix == 127)
105116
{
106117
byte[] bytes = ip.GetAddressBytes();
107-
yield return zoneIndex != null ? $"{ip}%{zoneIndex}" : ip.ToString();
118+
result.Add(ApplyZone(ip.ToString()));
108119

120+
// Flip last bit for second address
109121
bytes[15] |= 1;
110122
var ip2 = new IPAddress(bytes);
111-
yield return zoneIndex != null ? $"{ip2}%{zoneIndex}" : ip2.ToString();
123+
result.Add(ApplyZone(ip2.ToString()));
112124
}
113125
else if (prefix == 64)
114-
yield return zoneIndex != null ? $"{ip}%{zoneIndex}" : ip.ToString();
126+
{
127+
result.Add(ApplyZone(ip.ToString()));
128+
}
115129
else
116130
{
117-
_logger.LogWarning(
118-
"Skipping IPv6 CIDR {Cidr} with prefix /{Prefix} to avoid massive expansion",
119-
cidr, prefix);
131+
_logger.LogWarning("Skipping IPv6 CIDR {Cidr} with prefix /{Prefix}", cidr, prefix);
120132
}
121133
}
122134
catch (Exception ex)
123135
{
124136
_logger.LogWarning(ex, "Failed to expand IPv6 CIDR: {Cidr}", cidr);
125137
}
138+
139+
return result;
126140
}
127141

128142
public IEnumerable<string> ExpandWildcard(string wildcard, int startRange = 1, int endRange = 254)
@@ -154,7 +168,13 @@ public IEnumerable<string> ExpandWildcard(string wildcard, int startRange = 1, i
154168
/// Expands a single IPv6 host into compressed (::) and full (xxxx:xxxx:....) forms.
155169
/// Handles optional zone index.
156170
/// </summary>
157-
private IEnumerable<string> ExpandIPv6Host(string host)
171+
public enum IPv6Format
172+
{
173+
Compressed,
174+
Full
175+
}
176+
177+
private IEnumerable<string> ExpandIPv6Host(string host, IPv6Format format = IPv6Format.Compressed)
158178
{
159179
string hostPart = host;
160180
string? zoneIndex = null;
@@ -169,27 +189,25 @@ private IEnumerable<string> ExpandIPv6Host(string host)
169189
if (!IPAddress.TryParse(hostPart, out var ip)) yield break;
170190
if (ip.AddressFamily != AddressFamily.InterNetworkV6) yield break;
171191

172-
// Compressed form
173192
string compressed = ip.ToString();
174193

175194
// Full form (always 8 groups of 4 hex digits)
176195
string full = string.Join(":", Enumerable.Range(0, 8)
177196
.Select(i => ((ushort)((ip.GetAddressBytes()[i * 2] << 8) |
178-
ip.GetAddressBytes()[i * 2 + 1])).ToString("x4")));
197+
ip.GetAddressBytes()[i * 2 + 1])).ToString("x4")));
198+
199+
string ApplyZone(string addr) => zoneIndex != null ? $"{addr}%{zoneIndex}" : addr;
179200

180-
if (zoneIndex != null)
201+
if (format == IPv6Format.Compressed)
181202
{
182-
yield return $"{compressed}%{zoneIndex}";
183-
yield return $"{full}%{zoneIndex}";
203+
yield return ApplyZone(compressed);
184204
}
185-
else
205+
else if (format == IPv6Format.Full)
186206
{
187-
yield return compressed;
188-
yield return full;
207+
yield return ApplyZone(full);
189208
}
190209
}
191210

192-
193211
public async Task<IEnumerable<string>> ResolveHostnameAsync(string hostname, CancellationToken cancellationToken = default)
194212
{
195213
try

ThingConnect.Pulse.Server/Services/Monitoring/ProbeService.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System.Diagnostics;
2+
using System.Net;
23
using System.Net.NetworkInformation;
34
using System.Net.Sockets;
45
using ThingConnect.Pulse.Server.Data;

0 commit comments

Comments
 (0)