private NetService ProcessPTRRecord(PTRRecord record) { if (record.Name != _currentServiceType) { return(null); } NetService service = null; string serviceInstanceName = record.DomainName; // TTL of zero means we need to remove the service from the list if (record.TimeToLive == TimeSpan.Zero) { RemoveService(serviceInstanceName); return(null); } if (_discoveredServices.ContainsKey(serviceInstanceName)) { service = _discoveredServices[serviceInstanceName]; } else { service = new NetService(this); service.FullServiceInstanceName = serviceInstanceName; lock (_discoveredServices) _discoveredServices[serviceInstanceName] = service; } service.TTLExpires = DateTime.Now + record.TimeToLive; return(service); }
/// <summary> /// Advertise a service profile. /// </summary> /// <param name="service"> /// The service profile. /// </param> /// <remarks> /// Any queries for the service or service instance will be answered with /// information from the profile. /// <para> /// Besides adding the profile's resource records to the <see cref="Catalog"/> PTR records are /// created to support DNS-SD and reverse address mapping (DNS address lookup). /// </para> /// </remarks> public void Advertise(ServiceProfile service) { _profiles.Add(service); var catalog = NameServer.Catalog; catalog.Add(new PTRRecord { Name = ServiceName, DomainName = service.QualifiedServiceName }, true); catalog.Add(new PTRRecord { Name = service.QualifiedServiceName, DomainName = service.FullyQualifiedName }, true); foreach (var subtype in service.Subtypes) { var ptr = new PTRRecord { Name = DomainName.Join(new DomainName(subtype), SubName, service.QualifiedServiceName), DomainName = service.FullyQualifiedName }; catalog.Add(ptr, true); } foreach (var r in service.Resources) { catalog.Add(r, true); } catalog.IncludeReverseLookupRecords(); }
private void AnswerReceived(Message message) { List <PTRRecord> answers = message.Answers.Where(a => a.Name == AtemDeviceInfo.ServiceName).OfType <PTRRecord>().ToList(); PTRRecord answer = answers.FirstOrDefault(); if (answer == null) { return; } if (_debug && answers.Count != 1) { Console.WriteLine("Too many answers!"); } List <ResourceRecord> records = message.AdditionalRecords; SRVRecord srvRec = records.OfType <SRVRecord>().FirstOrDefault(r => r.Type == DnsType.SRV && r.Name == answer.DomainName); if (srvRec == null) { if (_debug) { Console.WriteLine("Missing SRV record for " + answer.DomainName); } return; } AddressRecord aRec = records.OfType <AddressRecord>().FirstOrDefault(r => r.Type == DnsType.A && r.Name == srvRec.Target); if (aRec == null) { if (_debug) { Console.WriteLine("Missing A record for " + answer.DomainName); } return; } TXTRecord txtRec = records.OfType <TXTRecord>().FirstOrDefault(r => r.Type == DnsType.TXT && r.Name == answer.DomainName); List <string> strings = txtRec == null ? new List <string>() : txtRec.Strings; string name = string.Join(".", answer.DomainName.Labels); if (name.EndsWith(AtemDeviceInfo.ServiceName)) { name = name.Substring(0, name.Length - AtemDeviceInfo.ServiceName.Length - 1); } var dev = new AtemDeviceInfo(name, srvRec.Target.ToString(), DateTime.Now, aRec.Address.ToString(), srvRec.Port, strings); lock (_knownDevices) { _knownDevices[dev.DeviceId] = dev; } OnDeviceSeen?.Invoke(this, dev); }
private void ReverseDnsRecord(Output <string> resourceGroupName, Zone privateReverseDns, Output <string> ipAddress, int vnetRangePrefix) { var nodeRecord = new PTRRecord($"ptr-{DeploymentName}{vnetRangePrefix / 2 + 1}", new PTRRecordArgs { ResourceGroupName = resourceGroupName, ZoneName = privateReverseDns.Name, Name = ipAddress.Apply(ipAddress => ConstructReveseIpAddress(ipAddress, 3)), Records = { $"{DeploymentName}{vnetRangePrefix / 2 + 1}.{ZoneName}" }, Ttl = 300 }); }
private PTRRecord DeserializePtrRr(string name, int ttl, byte[] bytes, int start, out int bytesRead) { var ptr = new PTRRecord() { Name = name, TimeToLive = ttl, }; ptr.PtrDName = this.dnsSerializer.ParseQuestionName(bytes, start, out bytesRead); return(ptr); }
/// <summary> /// Add PTR records for each authoritative A/AAAA record. /// </summary> /// <remarks> /// This enables reverse DNS lookup of all address records. /// </remarks> public void IncludeReverseLookupRecords() { var addressRecords = this.Values .Where(node => node.Authoritative) .SelectMany(node => node.Resources.OfType <AddressRecord>()); foreach (var a in addressRecords) { var ptr = new PTRRecord { Class = a.Class, Name = new DomainName(a.Address.GetArpaName()), DomainName = a.Name, TTL = a.TTL }; Add(ptr, authoritative: true); } }
public void DuplicateResources() { var node = new Node(); var a = new PTRRecord { Name = "a", DomainName = "alpha" }; var b = new PTRRecord { Name = "a", DomainName = "alpha" }; Assert.AreEqual(a, b); node.Resources.Add(a); node.Resources.Add(b); node.Resources.Add(a); node.Resources.Add(b); Assert.AreEqual(1, node.Resources.Count); }
/// <summary> /// Sends an unsolicited MDNS response describing the /// service profile. /// </summary> /// <param name="profile"> /// The profile to describe. /// </param> /// <remarks> /// Sends a MDNS response <see cref="Message"/> containing the pointer /// and resource records of the <paramref name="profile"/>. /// <para> /// To provide increased robustness against packet loss, /// two unsolicited responses are sent one second apart. /// </para> /// </remarks> public void Announce(ServiceProfile profile) { var message = new Message { QR = true }; // Add the shared records. var ptrRecord = new PTRRecord { Name = profile.QualifiedServiceName, DomainName = profile.FullyQualifiedName }; message.Answers.Add(ptrRecord); // Add the resource records. profile.Resources.ForEach((resource) => { message.Answers.Add(resource); }); message.Questions.Add(new Question() { Name = profile.ServiceName, Class = DnsClass.IN, Type = DnsType.PTR }); foreach (var ip in MulticastService.GetLinkLocalAddresses()) { message.AdditionalRecords.Add(new ARecord() { Class = DnsClass.IN, Type = DnsType.A, Name = profile.ServiceName, Address = ip, TTL = TimeSpan.FromSeconds(120) }); } Mdns.Send(message, false); Task.Delay(1000).Wait(); Mdns.Send(message, false); }
private Message GetStopPublishMessage() { Message message = new Message(); ResourceRecord record; // This message is a response message.QueryResponse = true; // This is an authoritative response message.AuthoritativeAnswer = true; // PTR Record record = new PTRRecord() { TimeToLive = TimeSpan.Zero, Name = Type, DomainName = FullServiceInstanceName, }; message.AnswerRecords.Add(record); return(message); }
/// <summary> /// Sends a goodbye message for the provided /// profile and removes its pointer from the name sever. /// </summary> /// <param name="profile">The profile to send a goodbye message for.</param> public void Unadvertise(ServiceProfile profile) { var message = new Message { QR = true }; var ptrRecord = new PTRRecord { Name = profile.QualifiedServiceName, DomainName = profile.FullyQualifiedName }; ptrRecord.TTL = TimeSpan.Zero; message.Answers.Add(ptrRecord); profile.Resources.ForEach((resource) => { resource.TTL = TimeSpan.Zero; message.AdditionalRecords.Add(resource); }); Mdns.SendAnswer(message); NameServer.Catalog.TryRemove(profile.QualifiedServiceName, out Node _); }
/// <summary> /// Sends an unsolicited MDNS response describing the /// service profile. /// </summary> /// <param name="profile"> /// The profile to describe. /// </param> /// <remarks> /// Sends a MDNS response <see cref="Message"/> containing the pointer /// and resource records of the <paramref name="profile"/>. /// <para> /// To provide increased robustness against packet loss, /// two unsolicited responses are sent one second apart. /// </para> /// </remarks> public void Announce(ServiceProfile profile) { var message = new Message { QR = true }; // Add the shared records. var ptrRecord = new PTRRecord { Name = profile.QualifiedServiceName, DomainName = profile.FullyQualifiedName }; message.Answers.Add(ptrRecord); // Add the resource records. profile.Resources.ForEach((resource) => { message.Answers.Add(resource); }); Mdns.SendAnswer(message, checkDuplicate: false); Task.Delay(1000).Wait(); Mdns.SendAnswer(message, checkDuplicate: false); }
private Message GetPublishMessage(PublishMessageType type) { Message message = new Message(); ResourceRecord record; // This message is a response message.QueryResponse = true; // This is an authoritative response message.AuthoritativeAnswer = true; // SRV Record record = new SRVRecord() { TimeToLive = (type == PublishMessageType.Stop) ? TimeSpan.Zero : BroadcastTTL, CacheFlush = true, Name = FullServiceInstanceName, Target = Hostname, Port = Port, }; message.AnswerRecords.Add(record); // TXT Record if (TXTRecordData != null && TXTRecordData.Count > 0) { record = new TXTRecord() { TimeToLive = (type == PublishMessageType.Stop) ? TimeSpan.Zero : BroadcastTTL, CacheFlush = true, Name = FullServiceInstanceName, Data = TXTRecordData, }; message.AnswerRecords.Add(record); } // PTR Record for DNS-SD Service Type Enumeration if (type == PublishMessageType.Normal) { record = new PTRRecord() { TimeToLive = BroadcastTTL, Name = BonjourUtility.DNSSDServiceTypeEnumerationName, DomainName = Type, }; message.AnswerRecords.Add(record); } // Service PTR Record if (type != PublishMessageType.Initial) { record = new PTRRecord() { TimeToLive = (type == PublishMessageType.Stop) ? TimeSpan.Zero : BroadcastTTL, Name = Type, DomainName = FullServiceInstanceName, }; message.AnswerRecords.Add(record); } // A Records if (type != PublishMessageType.Stop) { foreach (var ip in IPAddresses) { record = new ARecord() { TimeToLive = BroadcastTTL, CacheFlush = true, Name = Hostname, Address = ip, }; message.AdditionalRecords.Add(record); } } return(message); }