Skip to content

Commit cdc9b34

Browse files
committed
feat: expand compressed IPv6 Host
1 parent 772e099 commit cdc9b34

File tree

1 file changed

+62
-8
lines changed

1 file changed

+62
-8
lines changed

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

Lines changed: 62 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,48 @@ public IEnumerable<string> ExpandWildcard(string wildcard, int startRange = 1, i
150150
}
151151
}
152152

153-
public async Task<IEnumerable<string>> ResolveHostnameAsync(string hostname, CancellationToken cancellationToken = default)
153+
/// <summary>
154+
/// Expands a single IPv6 host into compressed (::) and full (0000:0000:...) forms.
155+
/// Handles optional zone index.
156+
/// </summary>
157+
private IEnumerable<string> ExpandIPv6Host(string host)
158+
{
159+
string hostPart = host;
160+
string? zoneIndex = null;
161+
162+
if (host.Contains('%'))
163+
{
164+
var split = host.Split('%');
165+
hostPart = split[0];
166+
zoneIndex = split[1];
167+
}
168+
169+
if (!IPAddress.TryParse(hostPart, out var ip)) yield break;
170+
if (ip.AddressFamily != AddressFamily.InterNetworkV6) yield break;
171+
172+
// Compressed form
173+
string compressed = ip.ToString();
174+
175+
// Full form
176+
string full = string.Join(":", ip.GetAddressBytes()
177+
.Select((b, i) => i % 2 == 0 ? $"{b:X2}" : $"{b:X2}")
178+
.Select((s, i) => i % 2 == 1 ? s : s) // ensure proper grouping
179+
);
180+
181+
if (zoneIndex != null)
182+
{
183+
yield return $"{compressed}%{zoneIndex}";
184+
yield return $"{full}%{zoneIndex}";
185+
}
186+
else
187+
{
188+
yield return compressed;
189+
yield return full;
190+
}
191+
}
192+
193+
194+
public async Task<IEnumerable<string>> ResolveHostnameAsync(string hostname, CancellationToken cancellationToken = default)
154195
{
155196
try
156197
{
@@ -159,9 +200,10 @@ public async Task<IEnumerable<string>> ResolveHostnameAsync(string hostname, Can
159200
.Where(addr => addr.AddressFamily == AddressFamily.InterNetwork || addr.AddressFamily == AddressFamily.InterNetworkV6)
160201
.Select(addr =>
161202
{
162-
// Include zone index for IPv6 link-local if needed
163-
if (addr.IsIPv6LinkLocal && addr.ScopeId != 0)
203+
// Include zone index for IPv6 link-local
204+
if (addr.AddressFamily == AddressFamily.InterNetworkV6 && addr.IsIPv6LinkLocal && addr.ScopeId != 0)
164205
return addr + "%" + addr.ScopeId;
206+
165207
return addr.ToString();
166208
})
167209
.ToList();
@@ -209,15 +251,28 @@ public async Task<IEnumerable<string>> ResolveHostnameAsync(string hostname, Can
209251
{
210252
string host = (string)target.host;
211253

212-
// Check if it's an IP address or hostname
213-
if (IPAddress.TryParse(host, out _))
254+
if (IPAddress.TryParse(host, out var ip))
214255
{
215-
hosts.Add(host);
256+
if (ip.AddressFamily == AddressFamily.InterNetworkV6)
257+
{
258+
// Expand IPv6 host into compressed and full forms
259+
hosts.AddRange(ExpandIPv6Host(host));
260+
}
261+
else
262+
{
263+
hosts.Add(host); // IPv4
264+
}
216265
}
217266
else
218267
{
219268
IEnumerable<string> resolvedHosts = await ResolveHostnameAsync(host, cancellationToken);
220-
hosts.AddRange(resolvedHosts);
269+
foreach (var resolvedHost in resolvedHosts)
270+
{
271+
if (IPAddress.TryParse(resolvedHost, out var resolvedIp) && resolvedIp.AddressFamily == AddressFamily.InterNetworkV6)
272+
hosts.AddRange(ExpandIPv6Host(resolvedHost));
273+
else
274+
hosts.Add(resolvedHost);
275+
}
221276
}
222277
}
223278
else if (target.cidr != null)
@@ -231,7 +286,6 @@ public async Task<IEnumerable<string>> ResolveHostnameAsync(string hostname, Can
231286
hosts.AddRange(ExpandWildcard(wildcard));
232287
}
233288

234-
// Create endpoint for each expanded host
235289
foreach (string host in hosts)
236290
{
237291
dynamic endpoint = CreateEndpointFromTarget(target, host);

0 commit comments

Comments
 (0)