From 0c5a23bbfca1c2abb1d7555eb1c5c0c0e420a156 Mon Sep 17 00:00:00 2001 From: Adien Akhmad Date: Mon, 24 Mar 2025 04:51:43 +0700 Subject: [PATCH] fix mdns crash on scoped IPv6 link-local Before this change the library will always crash with "SocketException: no route to host" when used on IPv6 interface with a scoped address e.g.[FE80::1%1]. The root cause was because the multicast address for IPv6 didn't specify a scope ID for such cases. This commit fixes it by first checking if the local endpoint is an IPv6 link local, if true, it will create and use a scoped multicast address for mdns. The resulting multicast address is then stored for reuse. --- TinyDNS/MDNS.cs | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/TinyDNS/MDNS.cs b/TinyDNS/MDNS.cs index ffad172..998d83e 100644 --- a/TinyDNS/MDNS.cs +++ b/TinyDNS/MDNS.cs @@ -11,6 +11,7 @@ // along with this program. If not, see . using System.Buffers; +using System.Collections.Concurrent; using System.Net; using System.Net.NetworkInformation; using System.Net.Sockets; @@ -32,6 +33,7 @@ public class MDNS : IDisposable private Socket? listenerV4; private Socket? listenerV6; private readonly List senders = []; + private readonly ConcurrentDictionary multicastAddressV6Scoped = []; public delegate Task MessageEventHandler(DNSMessageEvent e); public event MessageEventHandler? AnswerReceived; @@ -441,7 +443,7 @@ private async Task SendMessage(Message msg) if (sender.AddressFamily == AddressFamily.InterNetwork) await sender.SendToAsync(buffer.Slice(0, len), SocketFlags.None, new IPEndPoint(MulticastAddress, PORT), stop.Token); else - await sender.SendToAsync(buffer.Slice(0, len), SocketFlags.None, new IPEndPoint(MulticastAddressV6, PORT), stop.Token); + await sender.SendToAsync(buffer.Slice(0, len), SocketFlags.None, new IPEndPoint(GetMulticastAddressV6(sender.LocalEndPoint), PORT), stop.Token); await Task.Delay(5); } }finally @@ -450,6 +452,15 @@ private async Task SendMessage(Message msg) } } + private IPAddress GetMulticastAddressV6(EndPoint? endPoint) + { + if (endPoint is not IPEndPoint { Address.IsIPv6LinkLocal: true } ip) + return MulticastAddressV6; + + Func factory = scope => new IPAddress(new byte[] { 0xFF, 0x02, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xFB }, scope); + return multicastAddressV6Scoped.GetOrAdd(ip.Address.ScopeId, factory); + } + public void Stop() { stop.Cancel();