github.com/volts-dev/volts@v0.0.0-20240120094013-5e9c65924106/internal/mdns/dns_sd.go (about) 1 package mdns 2 3 import "github.com/miekg/dns" 4 5 // DNSSDService is a service that complies with the DNS-SD (RFC 6762) and MDNS 6 // (RFC 6762) specs for local, multicast-DNS-based discovery. 7 // 8 // DNSSDService implements the Zone interface and wraps an MDNSService instance. 9 // To deploy an mDNS service that is compliant with DNS-SD, it's recommended to 10 // register only the wrapped instance with the server. 11 // 12 // Example usage: 13 // service := &mdns.DNSSDService{ 14 // MDNSService: &mdns.MDNSService{ 15 // Instance: "My Foobar Service", 16 // Service: "_foobar._tcp", 17 // Port: 8000, 18 // } 19 // } 20 // server, err := mdns.NewServer(&mdns.Config{Zone: service}) 21 // if err != nil { 22 // log.Fatalf("Error creating server: %v", err) 23 // } 24 // defer server.Shutdown() 25 type DNSSDService struct { 26 MDNSService *MDNSService 27 } 28 29 // Records returns DNS records in response to a DNS question. 30 // 31 // This function returns the DNS response of the underlying MDNSService 32 // instance. It also returns a PTR record for a request for " 33 // _services._dns-sd._udp.<Domain>", as described in section 9 of RFC 6763 34 // ("Service Type Enumeration"), to allow browsing of the underlying MDNSService 35 // instance. 36 func (s *DNSSDService) Records(q dns.Question) []dns.RR { 37 var recs []dns.RR 38 if q.Name == "_services._dns-sd._udp."+s.MDNSService.Domain+"." { 39 recs = s.dnssdMetaQueryRecords(q) 40 } 41 return append(recs, s.MDNSService.Records(q)...) 42 } 43 44 // dnssdMetaQueryRecords returns the DNS records in response to a "meta-query" 45 // issued to browse for DNS-SD services, as per section 9. of RFC6763. 46 // 47 // A meta-query has a name of the form "_services._dns-sd._udp.<Domain>" where 48 // Domain is a fully-qualified domain, such as "local." 49 func (s *DNSSDService) dnssdMetaQueryRecords(q dns.Question) []dns.RR { 50 // Intended behavior, as described in the RFC: 51 // ...it may be useful for network administrators to find the list of 52 // advertised service types on the network, even if those Service Names 53 // are just opaque identifiers and not particularly informative in 54 // isolation. 55 // 56 // For this purpose, a special meta-query is defined. A DNS query for PTR 57 // records with the name "_services._dns-sd._udp.<Domain>" yields a set of 58 // PTR records, where the rdata of each PTR record is the two-abel 59 // <Service> name, plus the same domain, e.g., "_http._tcp.<Domain>". 60 // Including the domain in the PTR rdata allows for slightly better name 61 // compression in Unicast DNS responses, but only the first two labels are 62 // relevant for the purposes of service type enumeration. These two-label 63 // service types can then be used to construct subsequent Service Instance 64 // Enumeration PTR queries, in this <Domain> or others, to discover 65 // instances of that service type. 66 return []dns.RR{ 67 &dns.PTR{ 68 Hdr: dns.RR_Header{ 69 Name: q.Name, 70 Rrtype: dns.TypePTR, 71 Class: dns.ClassINET, 72 Ttl: defaultTTL, 73 }, 74 Ptr: s.MDNSService.serviceAddr, 75 }, 76 } 77 } 78 79 // Announcement returns DNS records that should be broadcast during the initial 80 // availability of the service, as described in section 8.3 of RFC 6762. 81 // TODO(reddaly): Add this when Announcement is added to the mdns.Zone interface. 82 //func (s *DNSSDService) Announcement() []dns.RR { 83 // return s.MDNSService.Announcement() 84 //}