public void Reachable_Ipv4() { var me = MulticastService.GetIPAddresses() .First(a => a.AddressFamily == AddressFamily.InterNetwork && !IPAddress.IsLoopback(a)); Assert.IsTrue(me.IsReachable(me)); Assert.IsFalse(me.IsReachable(IPAddress.Parse("1.1.1.1"))); //var nat = IPAddress.Parse("165.84.19.151"); // NAT PCP assigned address //Assert.IsTrue(nat.IsReachable(IPAddress.Parse("1.1.1.1"))); }
public void SubnetMask_All() { foreach (var a in MulticastService.GetIPAddresses()) { var network = IPNetwork.Parse(a, a.GetSubnetMask()); Console.WriteLine($"{a} mask {a.GetSubnetMask()} {network}"); Assert.IsTrue(network.Contains(a), $"{a} is not reachable"); } }
public void Disposable() { using (var mdns = new MulticastService()) { Assert.IsNotNull(mdns); } using (var mdns = new MulticastService()) { Assert.IsNotNull(mdns); mdns.Start(); } }
public void Disposable() { using (var sd = new ServiceDiscovery()) { Assert.IsNotNull(sd); } var mdns = new MulticastService(); using (var sd = new ServiceDiscovery(mdns)) { Assert.IsNotNull(sd); } }
public async Task ReceiveLegacyUnicastAnswer() { var service = Guid.NewGuid().ToString() + ".local"; var ready = new ManualResetEvent(false); var query = new Message(); query.Questions.Add(new Question { Name = service, Type = DnsType.A }); var packet = query.ToByteArray(); var client = new UdpClient(); using (var mdns = new MulticastService()) { mdns.NetworkInterfaceDiscovered += (s, e) => ready.Set(); mdns.QueryReceived += (s, e) => { var msg = e.Message; if (msg.Questions.Any(q => q.Name == service)) { var res = msg.CreateResponse(); res.Answers.Add(new ARecord { Name = service, Address = IPAddress.Parse("127.1.1.1") }); mdns.SendAnswer(res, e); } }; mdns.Start(); Assert.IsTrue(ready.WaitOne(TimeSpan.FromSeconds(1)), "ready timeout"); await client.SendAsync(packet, packet.Length, "224.0.0.251", 5353); var r = await client.ReceiveAsync(); var response = new Message(); response.Read(r.Buffer, 0, r.Buffer.Length); Assert.IsTrue(response.IsResponse); Assert.AreEqual(MessageStatus.NoError, response.Status); Assert.IsTrue(response.AA); Assert.AreEqual(1, response.Questions.Count); var a = (ARecord)response.Answers[0]; Assert.AreEqual(IPAddress.Parse("127.1.1.1"), a.Address); Assert.AreEqual(service, a.Name); Assert.AreEqual(TimeSpan.FromSeconds(10), a.TTL); } }
public void NicFromPattern() { var addresses = MulticastService.GetIPAddresses().ToArray(); foreach (var address in addresses) { string pattern = address.ToString(); if (pattern.Contains('.')) { pattern = pattern.Substring(0, pattern.LastIndexOf('.')) + ".0/24"; } var nic = MulticastService.GetNetworkInterfaceFromCIDR(pattern); Assert.IsNotNull(nic); } }
public void MalformedMessage() { byte[] malformedMessage = null; using (var mdns = new MulticastService()) { mdns.MalformedMessage += (s, e) => malformedMessage = e; var msg = new byte[] { 0xff }; var endPoint = new IPEndPoint(IPAddress.Loopback, 5353); var udp = new UdpReceiveResult(msg, endPoint); mdns.OnDnsMessage(this, udp); CollectionAssert.AreEqual(msg, malformedMessage); } }
public void ReceiveAnswer() { var service = Guid.NewGuid().ToString() + ".local"; var done = new ManualResetEvent(false); Message response = null; var mdns = new MulticastService(); mdns.NetworkInterfaceDiscovered += (s, e) => mdns.SendQuery(service); mdns.QueryReceived += (s, e) => { var msg = e.Message; if (msg.Questions.Any(q => q.Name == service)) { var res = msg.CreateResponse(); res.Answers.Add(new ARecord { Name = service, Address = IPAddress.Parse("127.1.1.1") }); mdns.SendAnswer(res); } }; mdns.AnswerReceived += (s, e) => { var msg = e.Message; if (msg.Answers.Any(a => a.Name == service)) { response = msg; done.Set(); } }; try { mdns.Start(); Assert.IsTrue(done.WaitOne(TimeSpan.FromSeconds(1)), "answer timeout"); Assert.IsNotNull(response); Assert.IsTrue(response.IsResponse); Assert.AreEqual(MessageStatus.NoError, response.Status); Assert.IsTrue(response.AA); var a = (ARecord)response.Answers[0]; Assert.AreEqual(IPAddress.Parse("127.1.1.1"), a.Address); } finally { mdns.Stop(); } }
public async Task NoDuplicateResponse() { var service = Guid.NewGuid().ToString() + ".local"; using (var mdns = new MulticastService()) { var answerCount = 0; mdns.NetworkInterfaceDiscovered += (s, e) => { mdns.SendQuery(service); Thread.Sleep(250); mdns.SendQuery(service); }; mdns.QueryReceived += (s, e) => { var msg = e.Message; if (msg.Questions.Any(q => q.Name == service)) { var res = msg.CreateResponse(); res.Answers.Add(new ARecord { Name = service, Address = IPAddress.Parse("127.1.1.1") }); mdns.SendAnswer(res, checkDuplicate: false); } }; mdns.AnswerReceived += (s, e) => { var msg = e.Message; if (msg.Answers.Any(answer => answer.Name == service)) { ++answerCount; } ; }; mdns.Start(); await Task.Delay(2000); Assert.AreEqual(1, answerCount); mdns.SendQuery(service); await Task.Delay(2000); Assert.AreEqual(2, answerCount); } }
public void Discover_ServiceInstance_WithAnswersContainingAdditionRecords() { var service = new ServiceProfile("y", "_sdtest-2._udp", 1024, new[] { IPAddress.Parse("127.1.1.1") }); var done = new ManualResetEvent(false); using (var mdns = new MulticastService()) using (var sd = new ServiceDiscovery(mdns) { AnswersContainsAdditionalRecords = true }) { Message discovered = null; mdns.NetworkInterfaceDiscovered += (s, e) => { sd.QueryServiceInstances(service.ServiceName); }; sd.ServiceInstanceDiscovered += (s, e) => { if (e.ServiceInstanceName == service.FullyQualifiedName) { Assert.IsNotNull(e.Message); discovered = e.Message; done.Set(); } }; sd.Advertise(service); mdns.Start(); Assert.IsTrue(done.WaitOne(TimeSpan.FromSeconds(3)), "instance not found"); var additionalRecordsCount = 1 + // SRVRecord 1 + // TXTRecord 1; // AddressRecord var answersCount = additionalRecordsCount + 1; // PTRRecord Assert.AreEqual(0, discovered.AdditionalRecords.Count); Assert.AreEqual(answersCount, discovered.Answers.Count); } }
public void Multiple_Listeners() { var ready1 = new ManualResetEvent(false); var ready2 = new ManualResetEvent(false); using (var mdns1 = new MulticastService()) using (var mdns2 = new MulticastService()) { mdns1.NetworkInterfaceDiscovered += (s, e) => ready1.Set(); mdns1.Start(); mdns2.NetworkInterfaceDiscovered += (s, e) => ready2.Set(); mdns2.Start(); Assert.IsTrue(ready1.WaitOne(TimeSpan.FromSeconds(1)), "ready1 timeout"); Assert.IsTrue(ready2.WaitOne(TimeSpan.FromSeconds(1)), "ready2 timeout"); } }
public void StartStop_SingleInterface() { var addresses = MulticastService.GetIPAddresses().ToArray(); foreach (var address in addresses) { string pattern = address.ToString(); if (pattern.Contains('.')) { pattern = pattern.Substring(0, pattern.LastIndexOf('.')) + ".0/24"; } var nic = MulticastService.GetNetworkInterfaceFromCIDR(pattern); var mdns = new MulticastService(nic); Assert.IsTrue(mdns.IsUsingSingleInterface); mdns.Start(); mdns.Stop(); } }
public void ReverseAddressMapping() { var service = new ServiceProfile("x9", "_sdtest-1._udp", 1024, new[] { IPAddress.Loopback, IPAddress.IPv6Loopback }); var arpaAddress = IPAddress.Loopback.GetArpaName(); var done = new ManualResetEvent(false); var mdns = new MulticastService(); Message response = null; mdns.NetworkInterfaceDiscovered += (s, e) => mdns.SendQuery(arpaAddress, DnsClass.IN, DnsType.PTR); mdns.AnswerReceived += (s, e) => { var msg = e.Message; if (msg.Answers.OfType <PTRRecord>().Any(p => p.Name == arpaAddress)) { response = msg; done.Set(); } }; try { using (var sd = new ServiceDiscovery(mdns)) { sd.Advertise(service); mdns.Start(); Assert.IsTrue(done.WaitOne(TimeSpan.FromSeconds(1)), "query timeout"); var answers = response.Answers .OfType <PTRRecord>() .Where(ptr => service.HostName == ptr.DomainName); foreach (var answer in answers) { Assert.AreEqual(arpaAddress, answer.Name); Assert.IsTrue(answer.TTL > TimeSpan.Zero); Assert.AreEqual(DnsClass.IN, answer.Class); } } } finally { mdns.Stop(); } }
public void Resolve_NoAnswer() { var service = Guid.NewGuid().ToString() + ".local"; var query = new Message(); query.Questions.Add(new Question { Name = service, Type = DnsType.ANY }); var cancellation = new CancellationTokenSource(500); using (var mdns = new MulticastService()) { mdns.Start(); ExceptionAssert.Throws <TaskCanceledException>(() => { var _ = mdns.ResolveAsync(query, cancellation.Token).Result; }); } }
public void Reachable_Loopback_From_Localhost() { var me = IPAddress.Loopback; foreach (var a in MulticastService.GetIPAddresses()) { Assert.IsTrue(me.IsReachable(a), $"{a}"); } Assert.IsFalse(me.IsReachable(IPAddress.Parse("1.1.1.1"))); Assert.IsFalse(me.IsReachable(IPAddress.Parse("2606:4700:4700::1111"))); me = IPAddress.IPv6Loopback; foreach (var a in MulticastService.GetIPAddresses()) { Assert.IsTrue(me.IsReachable(a), $"{a}"); } Assert.IsFalse(me.IsReachable(IPAddress.Parse("1.1.1.1"))); Assert.IsFalse(me.IsReachable(IPAddress.Parse("2606:4700:4700::1111"))); }
public void ReceiveErrorAnswer() { var service = Guid.NewGuid().ToString() + ".local"; var done = new ManualResetEvent(false); var mdns = new MulticastService(); mdns.NetworkInterfaceDiscovered += (s, e) => mdns.SendQuery(service); mdns.QueryReceived += (s, e) => { var msg = e.Message; if (msg.Questions.Any(q => q.Name == service)) { var res = msg.CreateResponse(); res.Status = MessageStatus.Refused; res.Answers.Add(new ARecord { Name = service, Address = IPAddress.Parse("127.1.1.1") }); mdns.SendAnswer(res); } }; mdns.AnswerReceived += (s, e) => { var msg = e.Message; if (msg.Answers.Any(a => a.Name == service)) { done.Set(); } }; try { mdns.Start(); Assert.IsFalse(done.WaitOne(TimeSpan.FromSeconds(0.5)), "answer was not ignored"); } finally { mdns.Stop(); } }
public void Discover_ServiceInstance_WithAnswersContainingAdditionRecords() { var service = new ServiceProfile("y", "_sdtest-2._udp", 1024); var done = new ManualResetEvent(false); var mdns = new MulticastService(); var sd = new ServiceDiscovery(mdns) { AnswersContainsAdditionalRecords = true }; Message discovered = null; mdns.NetworkInterfaceDiscovered += (s, e) => { sd.QueryServiceInstances(service.ServiceName); }; sd.ServiceInstanceDiscovered += (s, e) => { if (e.ServiceInstanceName == service.FullyQualifiedName) { Assert.IsNotNull(e.Message); discovered = e.Message; done.Set(); } }; try { sd.Advertise(service); mdns.Start(); Assert.IsTrue(done.WaitOne(TimeSpan.FromSeconds(1)), "instance not found"); Assert.AreEqual(0, discovered.AdditionalRecords.Count); Assert.IsTrue(discovered.Answers.Count > 1); } finally { sd.Dispose(); mdns.Stop(); } }
public void Nics() { var done = new ManualResetEvent(false); var mdns = new MulticastService(); IEnumerable <NetworkInterface> nics = null; mdns.NetworkInterfaceDiscovered += (s, e) => { nics = e.NetworkInterfaces; done.Set(); }; mdns.Start(); try { Assert.IsTrue(done.WaitOne(TimeSpan.FromSeconds(1)), "timeout"); Assert.IsTrue(nics.Count() > 0); } finally { mdns.Stop(); } }
/// <summary> /// Determines if the local IP address can be used by the /// remote address. /// </summary> /// <param name="local"></param> /// <param name="remote"></param> /// <returns> /// <b>true</b> if <paramref name="local"/> can be used by <paramref name="remote"/>; /// otherwise, <b>false</b>. /// </returns> public static bool IsReachable(this IPAddress local, IPAddress remote) { // Loopback addresses are only reachable when the remote is // the same host. if (local.Equals(IPAddress.Loopback) || local.Equals(IPAddress.IPv6Loopback)) { return(MulticastService.GetIPAddresses().Contains(remote)); } // IPv4 addresses are reachable when on the same subnet. if (local.AddressFamily == AddressFamily.InterNetwork && remote.AddressFamily == AddressFamily.InterNetwork) { var mask = local.GetSubnetMask(); if (mask != null) { var network = IPNetwork.Parse(local, mask); return(network.Contains(remote)); } // A mask of null should not occur. Is the IP address available on the actual machine or are the local and remote addresses switched in the function call? return(false); } // IPv6 link local addresses are reachable when using the same scope id. if (local.AddressFamily == AddressFamily.InterNetworkV6 && remote.AddressFamily == AddressFamily.InterNetworkV6) { if (local.IsIPv6LinkLocal && remote.IsIPv6LinkLocal) { return(local.ScopeId == remote.ScopeId); } // only interested in link local addresses return(false); } // If nothing of the above matched, they are probably not reachable. -> maybe a IPv4 to IPv6 transmission or vice verse. return(false); }
public void SendNonQuery() { var query = new Message { Opcode = MessageOperation.Status, QR = false }; var done = new ManualResetEvent(false); var mdns = new MulticastService(); mdns.NetworkInterfaceDiscovered += (s, e) => mdns.SendQuery(query); mdns.QueryReceived += (s, e) => done.Set(); try { mdns.Start(); Assert.IsFalse(done.WaitOne(TimeSpan.FromSeconds(0.5)), "query was not ignored"); } finally { mdns.Stop(); } }
public async Task Resolve() { var service = Guid.NewGuid().ToString() + ".local"; var query = new Message(); query.Questions.Add(new Question { Name = service, Type = DnsType.ANY }); var cancellation = new CancellationTokenSource(2000); using (var mdns = new MulticastService()) { mdns.QueryReceived += (s, e) => { var msg = e.Message; if (msg.Questions.Any(q => q.Name == service)) { var res = msg.CreateResponse(); res.Answers.Add(new ARecord { Name = service, Address = IPAddress.Parse("127.1.1.1") }); mdns.SendAnswer(res); } }; mdns.Start(); var response = await mdns.ResolveAsync(query, cancellation.Token); Assert.IsNotNull(response, "no response"); Assert.IsTrue(response.IsResponse); Assert.AreEqual(MessageStatus.NoError, response.Status); Assert.IsTrue(response.AA); var a = (ARecord)response.Answers[0]; Assert.AreEqual(IPAddress.Parse("127.1.1.1"), a.Address); } }
public ServiceProfile(string instanceName, string serviceName, string domainName, ushort port, short ttl, IEnumerable <IPAddress> addresses = null) { InstanceName = instanceName; ServiceName = serviceName; Domain = domainName; var fqn = FullyQualifiedName; var simpleServiceName = ServiceName .Replace("._tcp", "") .Replace("._udp", "") .TrimStart('_'); HostName = $"{InstanceName}.{simpleServiceName}.{Domain}"; Resources.Add(new SRVRecord { Name = fqn, Port = port, Target = HostName }); Resources.Add(new TXTRecord { Name = fqn, Strings = { "txtvers=1" } }); foreach (var address in addresses ?? MulticastService.GetLinkLocalAddresses()) { Resources.Add(AddressRecord.Create(HostName, address)); } servicePtrRecord = new PTRRecord { Name = ServiceName, DomainName = QualifiedServiceName, TTL = TimeSpan.FromSeconds(ttl) }; instancePtrRecord = new PTRRecord { Name = QualifiedServiceName, DomainName = FullyQualifiedName, TTL = TimeSpan.FromSeconds(ttl) }; }
public void Discover_ServiceInstance_with_Subtype() { var service1 = new ServiceProfile("x", "_sdtest-2._udp", 1024); var service2 = new ServiceProfile("y", "_sdtest-2._udp", 1024); service2.Subtypes.Add("apiv2"); var done = new ManualResetEvent(false); var mdns = new MulticastService(); var sd = new ServiceDiscovery(mdns); mdns.NetworkInterfaceDiscovered += (s, e) => { sd.QueryServiceInstances("_sdtest-2._udp", "apiv2"); }; sd.ServiceInstanceDiscovered += (s, e) => { if (e.ServiceInstanceName == service2.FullyQualifiedName) { Assert.IsNotNull(e.Message); done.Set(); } }; try { sd.Advertise(service1); sd.Advertise(service2); mdns.Start(); Assert.IsTrue(done.WaitOne(TimeSpan.FromSeconds(1)), "instance not found"); } finally { sd.Dispose(); mdns.Stop(); } }
/// <summary> /// Creates a new instance of the <see cref="ServiceDiscovery"/> class with /// the specified <see cref="MulticastService"/>. /// </summary> /// <param name="mdns"> /// The underlaying <see cref="MulticastService"/> to use. /// </param> public ServiceDiscovery(MulticastService mdns) { this.Mdns = mdns; mdns.QueryReceived += OnQuery; mdns.AnswerReceived += OnAnswer; }
public void IPAddresses() { var addresses = MulticastService.GetIPAddresses().ToArray(); Assert.AreNotEqual(0, addresses.Length); }
public void Can_Create() { var mdns = new MulticastService(); Assert.IsNotNull(mdns); }
// Enforce multicast defaults, especially TTL. static ServiceProfile() { // Make sure MulticastService is inited. MulticastService.ReferenceEquals(null, null); }