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  //}