using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Net; using System.Net.NetworkInformation; using System.Net.Sockets; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Security; using System.Security.Cryptography; using System.Security.Permissions; using System.Threading; using System.Threading.Tasks; using Common.Logging; using Makaretu.Dns.Resolving; using Tmds.Linux; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.0", FrameworkDisplayName = "")] [assembly: AssemblyCompany("Richard Schneider")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyCopyright("© 2018-2019 Richard Schneider")] [assembly: AssemblyDescription("A simple Multicast Domain Name Service based on RFC 6762. Can be used as both a client (sending queries) or a server (responding to queries).")] [assembly: AssemblyFileVersion("0.27.0")] [assembly: AssemblyInformationalVersion("0.27.0")] [assembly: AssemblyProduct("Makaretu.Dns.Multicast")] [assembly: AssemblyTitle("Makaretu.Dns.Multicast")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.27.0.0")] [module: UnverifiableCode] namespace Makaretu.Dns; internal static class LinuxHelper { public unsafe static void ReuseAddresss(Socket socket) { //IL_002a: Unknown result type (might be due to invalid IL or missing references) int num = 1; if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux) && LibC.setsockopt(socket.Handle.ToInt32(), LibC.SOL_SOCKET, LibC.SO_REUSEADDR, (void*)(&num), socklen_t.op_Implicit(4)) != 0) { throw new Exception("Socet reuse addr failed."); } } } public class MessageEventArgs : EventArgs { public Message Message { get; set; } public IPEndPoint RemoteEndPoint { get; set; } public bool IsLegacyUnicast => RemoteEndPoint.Port != MulticastClient.MulticastPort; } internal class MulticastClient : IDisposable { private static readonly ILog log = LogManager.GetLogger(typeof(MulticastClient)); public static readonly int MulticastPort = 5353; private static readonly IPAddress MulticastAddressIp4 = IPAddress.Parse("224.0.0.251"); private static readonly IPAddress MulticastAddressIp6 = IPAddress.Parse("FF02::FB"); private static readonly IPEndPoint MdnsEndpointIp6 = new IPEndPoint(MulticastAddressIp6, MulticastPort); private static readonly IPEndPoint MdnsEndpointIp4 = new IPEndPoint(MulticastAddressIp4, MulticastPort); private readonly List receivers; private readonly ConcurrentDictionary senders = new ConcurrentDictionary(); private bool disposedValue; public event EventHandler MessageReceived; public MulticastClient(bool useIPv4, bool useIpv6, IEnumerable nics) { receivers = new List(); UdpClient udpClient = null; if (useIPv4) { udpClient = new UdpClient(AddressFamily.InterNetwork); udpClient.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, optionValue: true); if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) { LinuxHelper.ReuseAddresss(udpClient.Client); } udpClient.Client.Bind(new IPEndPoint(IPAddress.Any, MulticastPort)); receivers.Add(udpClient); } UdpClient udpClient2 = null; if (useIpv6) { udpClient2 = new UdpClient(AddressFamily.InterNetworkV6); udpClient2.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, optionValue: true); if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) { LinuxHelper.ReuseAddresss(udpClient2.Client); } udpClient2.Client.Bind(new IPEndPoint(IPAddress.IPv6Any, MulticastPort)); receivers.Add(udpClient2); } foreach (IPAddress item in from a in nics.SelectMany(GetNetworkInterfaceLocalAddresses) where (useIPv4 && a.AddressFamily == AddressFamily.InterNetwork) || (useIpv6 && a.AddressFamily == AddressFamily.InterNetworkV6) select a) { if (senders.Keys.Contains(item)) { continue; } IPEndPoint iPEndPoint = new IPEndPoint(item, MulticastPort); UdpClient udpClient3 = new UdpClient(item.AddressFamily); try { switch (item.AddressFamily) { case AddressFamily.InterNetwork: udpClient.Client.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.AddMembership, new MulticastOption(MulticastAddressIp4, item)); udpClient3.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, optionValue: true); if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) { LinuxHelper.ReuseAddresss(udpClient3.Client); } udpClient3.Client.Bind(iPEndPoint); udpClient3.Client.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.AddMembership, new MulticastOption(MulticastAddressIp4)); udpClient3.Client.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.MulticastLoopback, optionValue: true); break; case AddressFamily.InterNetworkV6: udpClient2.Client.SetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.AddMembership, new IPv6MulticastOption(MulticastAddressIp6, item.ScopeId)); udpClient3.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, optionValue: true); udpClient3.Client.Bind(iPEndPoint); udpClient3.Client.SetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.AddMembership, new IPv6MulticastOption(MulticastAddressIp6)); udpClient3.Client.SetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.MulticastLoopback, optionValue: true); break; default: throw new NotSupportedException($"Address family {item.AddressFamily}."); } log.Debug((object)$"Will send via {iPEndPoint}"); if (!senders.TryAdd(item, udpClient3)) { udpClient3.Dispose(); } } catch (SocketException ex) when (ex.SocketErrorCode == SocketError.AddressNotAvailable) { udpClient3.Dispose(); } catch (Exception ex2) { log.Error((object)$"Cannot setup send socket for {item}: {ex2.Message}"); udpClient3.Dispose(); } } foreach (UdpClient receiver in receivers) { Listen(receiver); } } public async Task SendAsync(byte[] message) { foreach (KeyValuePair sender in senders) { try { IPEndPoint endPoint = ((sender.Key.AddressFamily == AddressFamily.InterNetwork) ? MdnsEndpointIp4 : MdnsEndpointIp6); await sender.Value.SendAsync(message, message.Length, endPoint).ConfigureAwait(continueOnCapturedContext: false); } catch (Exception ex) { log.Error((object)$"Sender {sender.Key} failure: {ex.Message}"); } } } private void Listen(UdpClient receiver) { Task.Run(async delegate { try { Task task = receiver.ReceiveAsync(); task.ContinueWith(delegate { Listen(receiver); }, TaskContinuationOptions.OnlyOnRanToCompletion | TaskContinuationOptions.RunContinuationsAsynchronously); task.ContinueWith(delegate(Task x) { this.MessageReceived?.Invoke(this, x.Result); }, TaskContinuationOptions.OnlyOnRanToCompletion | TaskContinuationOptions.RunContinuationsAsynchronously); await task.ConfigureAwait(continueOnCapturedContext: false); } catch { } }); } private IEnumerable GetNetworkInterfaceLocalAddresses(NetworkInterface nic) { return from x in nic.GetIPProperties().UnicastAddresses select x.Address into x where x.AddressFamily != AddressFamily.InterNetworkV6 || x.IsIPv6LinkLocal select x; } protected virtual void Dispose(bool disposing) { if (disposedValue) { return; } if (disposing) { this.MessageReceived = null; foreach (UdpClient receiver in receivers) { try { receiver.Dispose(); } catch { } } receivers.Clear(); foreach (IPAddress key in senders.Keys) { if (senders.TryRemove(key, out var value)) { try { value.Dispose(); } catch { } } } senders.Clear(); } disposedValue = true; } ~MulticastClient() { Dispose(disposing: false); } public void Dispose() { Dispose(disposing: true); GC.SuppressFinalize(this); } } public class MulticastService : IResolver, IDisposable { private const int packetOverhead = 48; private const int maxDatagramSize = 9000; private static readonly TimeSpan maxLegacyUnicastTTL; private static readonly ILog log; private static readonly IPNetwork[] LinkLocalNetworks; private List knownNics = new List(); private int maxPacketSize; private RecentMessages sentMessages = new RecentMessages(); private RecentMessages receivedMessages = new RecentMessages(); private MulticastClient client; private UdpClient unicastClientIp4 = new UdpClient(AddressFamily.InterNetwork); private UdpClient unicastClientIp6 = new UdpClient(AddressFamily.InterNetworkV6); private Func, IEnumerable> networkInterfacesFilter; public bool UseIpv4 { get; set; } public bool UseIpv6 { get; set; } public bool IgnoreDuplicateMessages { get; set; } [Obsolete("This property is deprecated and will be removed in nearest future. Using timer removed with obsording of NetworkChange.NetworkAddressChanged event.", false)] public TimeSpan NetworkInterfaceDiscoveryInterval { get; set; } = TimeSpan.FromMinutes(2.0); public event EventHandler QueryReceived; public event EventHandler AnswerReceived; public event EventHandler MalformedMessage; public event EventHandler NetworkInterfaceDiscovered; static MulticastService() { maxLegacyUnicastTTL = TimeSpan.FromSeconds(10.0); log = LogManager.GetLogger(typeof(MulticastService)); LinkLocalNetworks = new IPNetwork[2] { IPNetwork.Parse("169.254.0.0/16"), IPNetwork.Parse("fe80::/10") }; ResourceRecord.DefaultTTL = TimeSpan.FromMinutes(75.0); ResourceRecord.DefaultHostTTL = TimeSpan.FromSeconds(120.0); } public MulticastService(Func, IEnumerable> filter = null) { networkInterfacesFilter = filter; UseIpv4 = Socket.OSSupportsIPv4; UseIpv6 = Socket.OSSupportsIPv6; IgnoreDuplicateMessages = true; } public static IEnumerable GetNetworkInterfaces() { NetworkInterface[] array = (from nic in NetworkInterface.GetAllNetworkInterfaces() where nic.OperationalStatus == OperationalStatus.Up where nic.NetworkInterfaceType != NetworkInterfaceType.Loopback select nic).ToArray(); if (array.Length != 0) { return array; } return from nic in NetworkInterface.GetAllNetworkInterfaces() where nic.OperationalStatus == OperationalStatus.Up select nic; } public static IEnumerable GetIPAddresses() { return from u in GetNetworkInterfaces().SelectMany((NetworkInterface nic) => nic.GetIPProperties().UnicastAddresses) select u.Address; } public static IEnumerable GetLinkLocalAddresses() { return from a in GetIPAddresses() where a.AddressFamily == AddressFamily.InterNetwork || (a.AddressFamily == AddressFamily.InterNetworkV6 && a.IsIPv6LinkLocal) select a; } public void Start() { maxPacketSize = 8952; knownNics.Clear(); FindNetworkInterfaces(); } public void Stop() { this.QueryReceived = null; this.AnswerReceived = null; this.NetworkInterfaceDiscovered = null; client?.Dispose(); client = null; } private void OnNetworkAddressChanged(object sender, EventArgs e) { FindNetworkInterfaces(); } private void FindNetworkInterfaces() { log.Debug((object)"Finding network interfaces"); try { List currentNics = GetNetworkInterfaces().ToList(); List list = new List(); List list2 = new List(); foreach (NetworkInterface item in knownNics.Where((NetworkInterface k) => !currentNics.Any((NetworkInterface n) => k.Id == n.Id))) { list2.Add(item); if (log.IsDebugEnabled) { log.Debug((object)("Removed nic '" + item.Name + "'.")); } } foreach (NetworkInterface item2 in currentNics.Where((NetworkInterface nic) => !knownNics.Any((NetworkInterface k) => k.Id == nic.Id))) { list.Add(item2); if (log.IsDebugEnabled) { log.Debug((object)("Found nic '" + item2.Name + "'.")); } } knownNics = currentNics; if (list.Any() || list2.Any()) { client?.Dispose(); client = new MulticastClient(UseIpv4, UseIpv6, networkInterfacesFilter?.Invoke(knownNics) ?? knownNics); client.MessageReceived += OnDnsMessage; } if (list.Any()) { this.NetworkInterfaceDiscovered?.Invoke(this, new NetworkInterfaceEventArgs { NetworkInterfaces = list }); } if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { NetworkChange.NetworkAddressChanged -= OnNetworkAddressChanged; NetworkChange.NetworkAddressChanged += OnNetworkAddressChanged; } } catch (Exception ex) { log.Error((object)"FindNics failed", ex); } } public Task ResolveAsync(Message request, CancellationToken cancel = default(CancellationToken)) { TaskCompletionSource tsc = new TaskCompletionSource(); cancel.Register(delegate { AnswerReceived -= checkResponse; tsc.TrySetCanceled(); }); AnswerReceived += checkResponse; SendQuery(request); return tsc.Task; void checkResponse(object s, MessageEventArgs e) { Message response = e.Message; if (request.Questions.All((Question q) => response.Answers.Any((ResourceRecord a) => a.Name == q.Name))) { AnswerReceived -= checkResponse; tsc.SetResult(response); } } } public void SendQuery(DomainName name, DnsClass klass = (DnsClass)1, DnsType type = (DnsType)255) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Expected O, but got Unknown //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Expected O, but got Unknown Message val = new Message { Opcode = (MessageOperation)0, QR = false }; val.Questions.Add(new Question { Name = name, Class = klass, Type = type }); SendQuery(val); } public void SendUnicastQuery(DomainName name, DnsClass klass = (DnsClass)1, DnsType type = (DnsType)255) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Expected O, but got Unknown //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Expected O, but got Unknown Message val = new Message { Opcode = (MessageOperation)0, QR = false }; val.Questions.Add(new Question { Name = name, Class = (DnsClass)(ushort)(klass | 0x8000), Type = type }); SendQuery(val); } public void SendQuery(Message msg) { Send(msg, checkDuplicate: false); } public void SendAnswer(Message answer, bool checkDuplicate = true) { answer.AA = true; answer.Id = 0; answer.Questions.Clear(); answer.Truncate(maxPacketSize); Send(answer, checkDuplicate); } public void SendAnswer(Message answer, MessageEventArgs query, bool checkDuplicate = true) { if (!query.IsLegacyUnicast) { SendAnswer(answer, checkDuplicate); return; } answer.AA = true; answer.Id = query.Message.Id; answer.Questions.Clear(); answer.Questions.AddRange(query.Message.Questions); answer.Truncate(maxPacketSize); foreach (ResourceRecord answer2 in answer.Answers) { answer2.TTL = ((answer2.TTL > maxLegacyUnicastTTL) ? maxLegacyUnicastTTL : answer2.TTL); } foreach (ResourceRecord additionalRecord in answer.AdditionalRecords) { additionalRecord.TTL = ((additionalRecord.TTL > maxLegacyUnicastTTL) ? maxLegacyUnicastTTL : additionalRecord.TTL); } foreach (ResourceRecord additionalRecord2 in answer.AdditionalRecords) { additionalRecord2.TTL = ((additionalRecord2.TTL > maxLegacyUnicastTTL) ? maxLegacyUnicastTTL : additionalRecord2.TTL); } Send(answer, checkDuplicate, query.RemoteEndPoint); } private void Send(Message msg, bool checkDuplicate, IPEndPoint remoteEndPoint = null) { byte[] array = ((DnsObject)msg).ToByteArray(); if (array.Length > maxPacketSize) { throw new ArgumentOutOfRangeException($"Exceeds max packet size of {maxPacketSize}."); } if (!checkDuplicate || sentMessages.TryAdd(array)) { if (remoteEndPoint == null) { client?.SendAsync(array).GetAwaiter().GetResult(); } else { ((remoteEndPoint.Address.AddressFamily == AddressFamily.InterNetwork) ? unicastClientIp4 : unicastClientIp6).SendAsync(array, array.Length, remoteEndPoint).GetAwaiter().GetResult(); } } } public void OnDnsMessage(object sender, UdpReceiveResult result) { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Expected O, but got Unknown //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) if (IgnoreDuplicateMessages && !receivedMessages.TryAdd(result.Buffer)) { return; } Message val = new Message(); try { ((DnsObject)val).Read(result.Buffer, 0, result.Buffer.Length); } catch (Exception ex) { log.Warn((object)"Received malformed message", ex); this.MalformedMessage?.Invoke(this, result.Buffer); return; } if ((int)val.Opcode != 0 || (int)val.Status != 0) { return; } try { if (val.IsQuery && val.Questions.Count > 0) { this.QueryReceived?.Invoke(this, new MessageEventArgs { Message = val, RemoteEndPoint = result.RemoteEndPoint }); } else if (val.IsResponse && val.Answers.Count > 0) { this.AnswerReceived?.Invoke(this, new MessageEventArgs { Message = val, RemoteEndPoint = result.RemoteEndPoint }); } } catch (Exception ex2) { log.Error((object)"Receive handler failed", ex2); } } protected virtual void Dispose(bool disposing) { if (disposing) { Stop(); } } public void Dispose() { Dispose(disposing: true); } } public class NetworkInterfaceEventArgs : EventArgs { public IEnumerable NetworkInterfaces { get; set; } } public class RecentMessages { public ConcurrentDictionary Messages = new ConcurrentDictionary(); public TimeSpan Interval { get; set; } = TimeSpan.FromSeconds(1.0); public bool TryAdd(byte[] message) { Prune(); return Messages.TryAdd(GetId(message), DateTime.Now); } public int Prune() { DateTime dead = DateTime.Now - Interval; int num = 0; foreach (KeyValuePair item in Messages.Where((KeyValuePair x) => x.Value < dead)) { if (Messages.TryRemove(item.Key, out var _)) { num++; } } return num; } public string GetId(byte[] message) { using HashAlgorithm hashAlgorithm = MD5.Create(); return Convert.ToBase64String(hashAlgorithm.ComputeHash(message)); } } public class ServiceDiscovery : IDisposable { private static readonly ILog log = LogManager.GetLogger(typeof(ServiceDiscovery)); private static readonly DomainName LocalDomain = new DomainName("local"); private static readonly DomainName SubName = new DomainName("_sub"); public static readonly DomainName ServiceName = new DomainName("_services._dns-sd._udp.local"); private readonly bool ownsMdns; private List profiles = new List(); public MulticastService Mdns { get; private set; } public bool AnswersContainsAdditionalRecords { get; set; } public NameServer NameServer { get; } = new NameServer { Catalog = new Catalog(), AnswerAllQuestions = true }; public event EventHandler ServiceDiscovered; public event EventHandler ServiceInstanceDiscovered; public event EventHandler ServiceInstanceShutdown; public ServiceDiscovery() : this(new MulticastService()) { ownsMdns = true; Mdns.Start(); } public ServiceDiscovery(MulticastService mdns) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Expected O, but got Unknown //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Expected O, but got Unknown Mdns = mdns; mdns.QueryReceived += OnQuery; mdns.AnswerReceived += OnAnswer; } public void QueryAllServices() { Mdns.SendQuery(ServiceName, (DnsClass)1, (DnsType)12); } public void QueryUnicastAllServices() { Mdns.SendUnicastQuery(ServiceName, (DnsClass)1, (DnsType)12); } public void QueryServiceInstances(DomainName service) { Mdns.SendQuery(DomainName.Join((DomainName[])(object)new DomainName[2] { service, LocalDomain }), (DnsClass)1, (DnsType)12); } public void QueryServiceInstances(DomainName service, string subtype) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Expected O, but got Unknown DomainName name = DomainName.Join((DomainName[])(object)new DomainName[4] { new DomainName(subtype), SubName, service, LocalDomain }); Mdns.SendQuery(name, (DnsClass)1, (DnsType)12); } public void QueryUnicastServiceInstances(DomainName service) { Mdns.SendUnicastQuery(DomainName.Join((DomainName[])(object)new DomainName[2] { service, LocalDomain }), (DnsClass)1, (DnsType)12); } public void Advertise(ServiceProfile service) { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Expected O, but got Unknown //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Expected O, but got Unknown //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Expected O, but got Unknown //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Expected O, but got Unknown profiles.Add(service); Catalog catalog = NameServer.Catalog; catalog.Add((ResourceRecord)new PTRRecord { Name = ServiceName, DomainName = service.QualifiedServiceName }, true); catalog.Add((ResourceRecord)new PTRRecord { Name = service.QualifiedServiceName, DomainName = service.FullyQualifiedName }, true); foreach (string subtype in service.Subtypes) { PTRRecord val = new PTRRecord(); ((ResourceRecord)val).Name = DomainName.Join((DomainName[])(object)new DomainName[3] { new DomainName(subtype), SubName, service.QualifiedServiceName }); val.DomainName = service.FullyQualifiedName; PTRRecord val2 = val; catalog.Add((ResourceRecord)(object)val2, true); } foreach (ResourceRecord resource in service.Resources) { catalog.Add(resource, true); } catalog.IncludeReverseLookupRecords(); } public void Announce(ServiceProfile profile) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Expected O, but got Unknown //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Expected O, but got Unknown Message message = new Message { QR = true }; PTRRecord item = new PTRRecord { Name = profile.QualifiedServiceName, DomainName = profile.FullyQualifiedName }; message.Answers.Add((ResourceRecord)(object)item); profile.Resources.ForEach(delegate(ResourceRecord resource) { message.Answers.Add(resource); }); Mdns.SendAnswer(message, checkDuplicate: false); Task.Delay(1000).Wait(); Mdns.SendAnswer(message, checkDuplicate: false); } public void Unadvertise(ServiceProfile profile) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Expected O, but got Unknown //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Expected O, but got Unknown Message message = new Message { QR = true }; PTRRecord val = new PTRRecord { Name = profile.QualifiedServiceName, DomainName = profile.FullyQualifiedName }; ((ResourceRecord)val).TTL = TimeSpan.Zero; message.Answers.Add((ResourceRecord)(object)val); profile.Resources.ForEach(delegate(ResourceRecord resource) { resource.TTL = TimeSpan.Zero; message.AdditionalRecords.Add(resource); }); Mdns.SendAnswer(message); ((ConcurrentDictionary)(object)NameServer.Catalog).TryRemove(profile.QualifiedServiceName, out Node _); } public void Unadvertise() { profiles.ForEach(delegate(ServiceProfile profile) { Unadvertise(profile); }); } private void OnAnswer(object sender, MessageEventArgs e) { Message message = e.Message; if (log.IsDebugEnabled) { log.Debug((object)$"Answer from {e.RemoteEndPoint}"); } if (log.IsTraceEnabled) { log.Trace((object)message); } foreach (PTRRecord item in from ptr in message.Answers.OfType() where ((ResourceRecord)ptr).Name.IsSubdomainOf(LocalDomain) select ptr) { if (((ResourceRecord)item).Name == ServiceName) { this.ServiceDiscovered?.Invoke(this, item.DomainName); } else if (((ResourceRecord)item).TTL == TimeSpan.Zero) { ServiceInstanceShutdownEventArgs e2 = new ServiceInstanceShutdownEventArgs { ServiceInstanceName = item.DomainName, Message = message }; this.ServiceInstanceShutdown?.Invoke(this, e2); } else { ServiceInstanceDiscoveryEventArgs e3 = new ServiceInstanceDiscoveryEventArgs { ServiceInstanceName = item.DomainName, Message = message }; this.ServiceInstanceDiscovered?.Invoke(this, e3); } } } private void OnQuery(object sender, MessageEventArgs e) { //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Unknown result type (might be due to invalid IL or missing references) Message message = e.Message; if (log.IsDebugEnabled) { log.Debug((object)$"Query from {e.RemoteEndPoint}"); } if (log.IsTraceEnabled) { log.Trace((object)message); } bool flag = false; foreach (Question question in message.Questions) { if ((question.Class & 0x8000) != 0) { flag = true; question.Class = (DnsClass)(ushort)(question.Class & 0x7FFF); } } Message result = NameServer.ResolveAsync(message, default(CancellationToken)).Result; if ((int)result.Status == 0) { if (result.Answers.Any((ResourceRecord a) => a.Name == ServiceName)) { result.AdditionalRecords.Clear(); } if (AnswersContainsAdditionalRecords) { result.Answers.AddRange(result.AdditionalRecords); result.AdditionalRecords.Clear(); } result.Answers.Any((ResourceRecord a) => a.Name == ServiceName); if (flag) { Mdns.SendAnswer(result, e); } else { Mdns.SendAnswer(result, e); } if (log.IsDebugEnabled) { log.Debug((object)"Sending answer"); } if (log.IsTraceEnabled) { log.Trace((object)result); } } } protected virtual void Dispose(bool disposing) { if (disposing && Mdns != null) { Mdns.QueryReceived -= OnQuery; Mdns.AnswerReceived -= OnAnswer; if (ownsMdns) { Mdns.Dispose(); } Mdns = null; } } public void Dispose() { Dispose(disposing: true); } } public class ServiceInstanceDiscoveryEventArgs : MessageEventArgs { public DomainName ServiceInstanceName { get; set; } } public class ServiceInstanceShutdownEventArgs : MessageEventArgs { public DomainName ServiceInstanceName { get; set; } } public class ServiceProfile { public DomainName Domain { get; } = DomainName.op_Implicit("local"); public DomainName ServiceName { get; set; } public DomainName InstanceName { get; set; } public DomainName QualifiedServiceName => DomainName.Join((DomainName[])(object)new DomainName[2] { ServiceName, Domain }); public DomainName HostName { get; set; } public DomainName FullyQualifiedName => DomainName.Join((DomainName[])(object)new DomainName[3] { InstanceName, ServiceName, Domain }); public List Resources { get; set; } = new List(); public List Subtypes { get; set; } = new List(); static ServiceProfile() { } public ServiceProfile() { } public ServiceProfile(DomainName instanceName, DomainName serviceName, ushort port, IEnumerable addresses = null) { //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Expected O, but got Unknown //IL_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_00cf: Unknown result type (might be due to invalid IL or missing references) //IL_00e0: Expected O, but got Unknown //IL_00e6: Unknown result type (might be due to invalid IL or missing references) //IL_00eb: Unknown result type (might be due to invalid IL or missing references) //IL_00f2: Unknown result type (might be due to invalid IL or missing references) //IL_0107: Expected O, but got Unknown InstanceName = instanceName; ServiceName = serviceName; DomainName fullyQualifiedName = FullyQualifiedName; DomainName val = new DomainName(((object)ServiceName).ToString().Replace("._tcp", "").Replace("._udp", "") .Trim(new char[1] { '_' }) .Replace("_", "-")); HostName = DomainName.Join((DomainName[])(object)new DomainName[3] { InstanceName, val, Domain }); Resources.Add((ResourceRecord)new SRVRecord { Name = fullyQualifiedName, Port = port, Target = HostName }); Resources.Add((ResourceRecord)new TXTRecord { Name = fullyQualifiedName, Strings = { "txtvers=1" } }); foreach (IPAddress item in addresses ?? MulticastService.GetLinkLocalAddresses()) { Resources.Add((ResourceRecord)(object)AddressRecord.Create(HostName, item)); } } public void AddProperty(string key, string value) { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Expected O, but got Unknown TXTRecord val = Resources.OfType().FirstOrDefault(); if ((ResourceRecord)(object)val == (ResourceRecord)null) { val = new TXTRecord { Name = FullyQualifiedName }; Resources.Add((ResourceRecord)(object)val); } val.Strings.Add(key + "=" + value); } }