OSDN Git Service

versoin1.1.9 (#594)
[bytom/vapor.git] / vendor / github.com / grandcat / zeroconf / server.go
1 package zeroconf
2
3 import (
4         "fmt"
5         "log"
6         "math/rand"
7         "net"
8         "os"
9         "strings"
10         "sync"
11         "time"
12
13         "golang.org/x/net/ipv4"
14         "golang.org/x/net/ipv6"
15
16         "errors"
17
18         "github.com/miekg/dns"
19 )
20
21 const (
22         // Number of Multicast responses sent for a query message (default: 1 < x < 9)
23         multicastRepetitions = 2
24 )
25
26 // Register a service by given arguments. This call will take the system's hostname
27 // and lookup IP by that hostname.
28 func Register(instance, service, domain string, port int, text []string, ifaces []net.Interface) (*Server, error) {
29         entry := NewServiceEntry(instance, service, domain)
30         entry.Port = port
31         entry.Text = text
32
33         if entry.Instance == "" {
34                 return nil, fmt.Errorf("Missing service instance name")
35         }
36         if entry.Service == "" {
37                 return nil, fmt.Errorf("Missing service name")
38         }
39         if entry.Domain == "" {
40                 entry.Domain = "local."
41         }
42         if entry.Port == 0 {
43                 return nil, fmt.Errorf("Missing port")
44         }
45
46         var err error
47         if entry.HostName == "" {
48                 entry.HostName, err = os.Hostname()
49                 if err != nil {
50                         return nil, fmt.Errorf("Could not determine host")
51                 }
52         }
53
54         if !strings.HasSuffix(trimDot(entry.HostName), entry.Domain) {
55                 entry.HostName = fmt.Sprintf("%s.%s.", trimDot(entry.HostName), trimDot(entry.Domain))
56         }
57
58         if len(ifaces) == 0 {
59                 ifaces = listMulticastInterfaces()
60         }
61
62         for _, iface := range ifaces {
63                 v4, v6 := addrsForInterface(&iface)
64                 entry.AddrIPv4 = append(entry.AddrIPv4, v4...)
65                 entry.AddrIPv6 = append(entry.AddrIPv6, v6...)
66         }
67
68         if entry.AddrIPv4 == nil && entry.AddrIPv6 == nil {
69                 return nil, fmt.Errorf("Could not determine host IP addresses")
70         }
71
72         s, err := newServer(ifaces)
73         if err != nil {
74                 return nil, err
75         }
76
77         s.service = entry
78         go s.mainloop()
79         go s.probe()
80
81         return s, nil
82 }
83
84 // RegisterProxy registers a service proxy. This call will skip the hostname/IP lookup and
85 // will use the provided values.
86 func RegisterProxy(instance, service, domain string, port int, host string, ips []string, text []string, ifaces []net.Interface) (*Server, error) {
87         entry := NewServiceEntry(instance, service, domain)
88         entry.Port = port
89         entry.Text = text
90         entry.HostName = host
91
92         if entry.Instance == "" {
93                 return nil, fmt.Errorf("Missing service instance name")
94         }
95         if entry.Service == "" {
96                 return nil, fmt.Errorf("Missing service name")
97         }
98         if entry.HostName == "" {
99                 return nil, fmt.Errorf("Missing host name")
100         }
101         if entry.Domain == "" {
102                 entry.Domain = "local"
103         }
104         if entry.Port == 0 {
105                 return nil, fmt.Errorf("Missing port")
106         }
107
108         if !strings.HasSuffix(trimDot(entry.HostName), entry.Domain) {
109                 entry.HostName = fmt.Sprintf("%s.%s.", trimDot(entry.HostName), trimDot(entry.Domain))
110         }
111
112         for _, ip := range ips {
113                 ipAddr := net.ParseIP(ip)
114                 if ipAddr == nil {
115                         return nil, fmt.Errorf("Failed to parse given IP: %v", ip)
116                 } else if ipv4 := ipAddr.To4(); ipv4 != nil {
117                         entry.AddrIPv4 = append(entry.AddrIPv4, ipAddr)
118                 } else if ipv6 := ipAddr.To16(); ipv6 != nil {
119                         entry.AddrIPv6 = append(entry.AddrIPv6, ipAddr)
120                 } else {
121                         return nil, fmt.Errorf("The IP is neither IPv4 nor IPv6: %#v", ipAddr)
122                 }
123         }
124
125         if len(ifaces) == 0 {
126                 ifaces = listMulticastInterfaces()
127         }
128
129         s, err := newServer(ifaces)
130         if err != nil {
131                 return nil, err
132         }
133
134         s.service = entry
135         go s.mainloop()
136         go s.probe()
137
138         return s, nil
139 }
140
141 const (
142         qClassCacheFlush uint16 = 1 << 15
143 )
144
145 // Server structure encapsulates both IPv4/IPv6 UDP connections
146 type Server struct {
147         service  *ServiceEntry
148         ipv4conn *ipv4.PacketConn
149         ipv6conn *ipv6.PacketConn
150         ifaces   []net.Interface
151
152         shouldShutdown chan struct{}
153         shutdownLock   sync.Mutex
154         shutdownEnd    sync.WaitGroup
155         isShutdown     bool
156         ttl            uint32
157 }
158
159 // Constructs server structure
160 func newServer(ifaces []net.Interface) (*Server, error) {
161         ipv4conn, err4 := joinUdp4Multicast(ifaces)
162         if err4 != nil {
163                 log.Printf("[zeroconf] no suitable IPv4 interface: %s", err4.Error())
164         }
165         ipv6conn, err6 := joinUdp6Multicast(ifaces)
166         if err6 != nil {
167                 log.Printf("[zeroconf] no suitable IPv6 interface: %s", err6.Error())
168         }
169         if err4 != nil && err6 != nil {
170                 // No supported interface left.
171                 return nil, fmt.Errorf("No supported interface")
172         }
173
174         s := &Server{
175                 ipv4conn:       ipv4conn,
176                 ipv6conn:       ipv6conn,
177                 ifaces:         ifaces,
178                 ttl:            3200,
179                 shouldShutdown: make(chan struct{}),
180         }
181
182         return s, nil
183 }
184
185 // Start listeners and waits for the shutdown signal from exit channel
186 func (s *Server) mainloop() {
187         if s.ipv4conn != nil {
188                 go s.recv4(s.ipv4conn)
189         }
190         if s.ipv6conn != nil {
191                 go s.recv6(s.ipv6conn)
192         }
193 }
194
195 // Shutdown closes all udp connections and unregisters the service
196 func (s *Server) Shutdown() {
197         s.shutdown()
198 }
199
200 // SetText updates and announces the TXT records
201 func (s *Server) SetText(text []string) {
202         s.service.Text = text
203         s.announceText()
204 }
205
206 // TTL sets the TTL for DNS replies
207 func (s *Server) TTL(ttl uint32) {
208         s.ttl = ttl
209 }
210
211 // Shutdown server will close currently open connections & channel
212 func (s *Server) shutdown() error {
213         s.shutdownLock.Lock()
214         defer s.shutdownLock.Unlock()
215         if s.isShutdown {
216                 return errors.New("Server is already shutdown")
217         }
218
219         err := s.unregister()
220         if err != nil {
221                 return err
222         }
223
224         close(s.shouldShutdown)
225
226         if s.ipv4conn != nil {
227                 s.ipv4conn.Close()
228         }
229         if s.ipv6conn != nil {
230                 s.ipv6conn.Close()
231         }
232
233         // Wait for connection and routines to be closed
234         s.shutdownEnd.Wait()
235         s.isShutdown = true
236
237         return nil
238 }
239
240 // recv is a long running routine to receive packets from an interface
241 func (s *Server) recv4(c *ipv4.PacketConn) {
242         if c == nil {
243                 return
244         }
245         buf := make([]byte, 65536)
246         s.shutdownEnd.Add(1)
247         defer s.shutdownEnd.Done()
248         for {
249                 select {
250                 case <-s.shouldShutdown:
251                         return
252                 default:
253                         var ifIndex int
254                         n, cm, from, err := c.ReadFrom(buf)
255                         if err != nil {
256                                 continue
257                         }
258                         if cm != nil {
259                                 ifIndex = cm.IfIndex
260                         }
261                         if err := s.parsePacket(buf[:n], ifIndex, from); err != nil {
262                                 // log.Printf("[ERR] zeroconf: failed to handle query v4: %v", err)
263                         }
264                 }
265         }
266 }
267
268 // recv is a long running routine to receive packets from an interface
269 func (s *Server) recv6(c *ipv6.PacketConn) {
270         if c == nil {
271                 return
272         }
273         buf := make([]byte, 65536)
274         s.shutdownEnd.Add(1)
275         defer s.shutdownEnd.Done()
276         for {
277                 select {
278                 case <-s.shouldShutdown:
279                         return
280                 default:
281                         var ifIndex int
282                         n, cm, from, err := c.ReadFrom(buf)
283                         if err != nil {
284                                 continue
285                         }
286                         if cm != nil {
287                                 ifIndex = cm.IfIndex
288                         }
289                         if err := s.parsePacket(buf[:n], ifIndex, from); err != nil {
290                                 // log.Printf("[ERR] zeroconf: failed to handle query v6: %v", err)
291                         }
292                 }
293         }
294 }
295
296 // parsePacket is used to parse an incoming packet
297 func (s *Server) parsePacket(packet []byte, ifIndex int, from net.Addr) error {
298         var msg dns.Msg
299         if err := msg.Unpack(packet); err != nil {
300                 // log.Printf("[ERR] zeroconf: Failed to unpack packet: %v", err)
301                 return err
302         }
303         return s.handleQuery(&msg, ifIndex, from)
304 }
305
306 // handleQuery is used to handle an incoming query
307 func (s *Server) handleQuery(query *dns.Msg, ifIndex int, from net.Addr) error {
308         // Ignore questions with authoritative section for now
309         if len(query.Ns) > 0 {
310                 return nil
311         }
312
313         // Handle each question
314         var err error
315         for _, q := range query.Question {
316                 resp := dns.Msg{}
317                 resp.SetReply(query)
318                 resp.Compress = true
319                 resp.RecursionDesired = false
320                 resp.Authoritative = true
321                 resp.Question = nil // RFC6762 section 6 "responses MUST NOT contain any questions"
322                 resp.Answer = []dns.RR{}
323                 resp.Extra = []dns.RR{}
324                 if err = s.handleQuestion(q, &resp, query, ifIndex); err != nil {
325                         // log.Printf("[ERR] zeroconf: failed to handle question %v: %v", q, err)
326                         continue
327                 }
328                 // Check if there is an answer
329                 if len(resp.Answer) == 0 {
330                         continue
331                 }
332
333                 if isUnicastQuestion(q) {
334                         // Send unicast
335                         if e := s.unicastResponse(&resp, ifIndex, from); e != nil {
336                                 err = e
337                         }
338                 } else {
339                         // Send mulicast
340                         if e := s.multicastResponse(&resp, ifIndex); e != nil {
341                                 err = e
342                         }
343                 }
344         }
345
346         return err
347 }
348
349 // RFC6762 7.1. Known-Answer Suppression
350 func isKnownAnswer(resp *dns.Msg, query *dns.Msg) bool {
351         if len(resp.Answer) == 0 || len(query.Answer) == 0 {
352                 return false
353         }
354
355         if resp.Answer[0].Header().Rrtype != dns.TypePTR {
356                 return false
357         }
358         answer := resp.Answer[0].(*dns.PTR)
359
360         for _, known := range query.Answer {
361                 hdr := known.Header()
362                 if hdr.Rrtype != answer.Hdr.Rrtype {
363                         continue
364                 }
365                 ptr := known.(*dns.PTR)
366                 if ptr.Ptr == answer.Ptr && hdr.Ttl >= answer.Hdr.Ttl/2 {
367                         // log.Printf("skipping known answer: %v", ptr)
368                         return true
369                 }
370         }
371
372         return false
373 }
374
375 // handleQuestion is used to handle an incoming question
376 func (s *Server) handleQuestion(q dns.Question, resp *dns.Msg, query *dns.Msg, ifIndex int) error {
377         if s.service == nil {
378                 return nil
379         }
380
381         switch q.Name {
382         case s.service.ServiceTypeName():
383                 s.serviceTypeName(resp, s.ttl)
384                 if isKnownAnswer(resp, query) {
385                         resp.Answer = nil
386                 }
387
388         case s.service.ServiceName():
389                 s.composeBrowsingAnswers(resp, ifIndex)
390                 if isKnownAnswer(resp, query) {
391                         resp.Answer = nil
392                 }
393
394         case s.service.ServiceInstanceName():
395                 s.composeLookupAnswers(resp, s.ttl, ifIndex, false)
396         }
397
398         return nil
399 }
400
401 func (s *Server) composeBrowsingAnswers(resp *dns.Msg, ifIndex int) {
402         ptr := &dns.PTR{
403                 Hdr: dns.RR_Header{
404                         Name:   s.service.ServiceName(),
405                         Rrtype: dns.TypePTR,
406                         Class:  dns.ClassINET,
407                         Ttl:    s.ttl,
408                 },
409                 Ptr: s.service.ServiceInstanceName(),
410         }
411         resp.Answer = append(resp.Answer, ptr)
412
413         txt := &dns.TXT{
414                 Hdr: dns.RR_Header{
415                         Name:   s.service.ServiceInstanceName(),
416                         Rrtype: dns.TypeTXT,
417                         Class:  dns.ClassINET,
418                         Ttl:    s.ttl,
419                 },
420                 Txt: s.service.Text,
421         }
422         srv := &dns.SRV{
423                 Hdr: dns.RR_Header{
424                         Name:   s.service.ServiceInstanceName(),
425                         Rrtype: dns.TypeSRV,
426                         Class:  dns.ClassINET,
427                         Ttl:    s.ttl,
428                 },
429                 Priority: 0,
430                 Weight:   0,
431                 Port:     uint16(s.service.Port),
432                 Target:   s.service.HostName,
433         }
434         resp.Extra = append(resp.Extra, srv, txt)
435
436         resp.Extra = s.appendAddrs(resp.Extra, s.ttl, ifIndex, false)
437 }
438
439 func (s *Server) composeLookupAnswers(resp *dns.Msg, ttl uint32, ifIndex int, flushCache bool) {
440         // From RFC6762
441         //    The most significant bit of the rrclass for a record in the Answer
442         //    Section of a response message is the Multicast DNS cache-flush bit
443         //    and is discussed in more detail below in Section 10.2, "Announcements
444         //    to Flush Outdated Cache Entries".
445         ptr := &dns.PTR{
446                 Hdr: dns.RR_Header{
447                         Name:   s.service.ServiceName(),
448                         Rrtype: dns.TypePTR,
449                         Class:  dns.ClassINET,
450                         Ttl:    ttl,
451                 },
452                 Ptr: s.service.ServiceInstanceName(),
453         }
454         srv := &dns.SRV{
455                 Hdr: dns.RR_Header{
456                         Name:   s.service.ServiceInstanceName(),
457                         Rrtype: dns.TypeSRV,
458                         Class:  dns.ClassINET | qClassCacheFlush,
459                         Ttl:    ttl,
460                 },
461                 Priority: 0,
462                 Weight:   0,
463                 Port:     uint16(s.service.Port),
464                 Target:   s.service.HostName,
465         }
466         txt := &dns.TXT{
467                 Hdr: dns.RR_Header{
468                         Name:   s.service.ServiceInstanceName(),
469                         Rrtype: dns.TypeTXT,
470                         Class:  dns.ClassINET | qClassCacheFlush,
471                         Ttl:    ttl,
472                 },
473                 Txt: s.service.Text,
474         }
475         dnssd := &dns.PTR{
476                 Hdr: dns.RR_Header{
477                         Name:   s.service.ServiceTypeName(),
478                         Rrtype: dns.TypePTR,
479                         Class:  dns.ClassINET,
480                         Ttl:    ttl,
481                 },
482                 Ptr: s.service.ServiceName(),
483         }
484         resp.Answer = append(resp.Answer, srv, txt, ptr, dnssd)
485
486         resp.Answer = s.appendAddrs(resp.Answer, ttl, ifIndex, flushCache)
487 }
488
489 func (s *Server) serviceTypeName(resp *dns.Msg, ttl uint32) {
490         // From RFC6762
491         // 9.  Service Type Enumeration
492         //
493         //    For this purpose, a special meta-query is defined.  A DNS query for
494         //    PTR records with the name "_services._dns-sd._udp.<Domain>" yields a
495         //    set of PTR records, where the rdata of each PTR record is the two-
496         //    label <Service> name, plus the same domain, e.g.,
497         //    "_http._tcp.<Domain>".
498         dnssd := &dns.PTR{
499                 Hdr: dns.RR_Header{
500                         Name:   s.service.ServiceTypeName(),
501                         Rrtype: dns.TypePTR,
502                         Class:  dns.ClassINET,
503                         Ttl:    ttl,
504                 },
505                 Ptr: s.service.ServiceName(),
506         }
507         resp.Answer = append(resp.Answer, dnssd)
508 }
509
510 // Perform probing & announcement
511 //TODO: implement a proper probing & conflict resolution
512 func (s *Server) probe() {
513         q := new(dns.Msg)
514         q.SetQuestion(s.service.ServiceInstanceName(), dns.TypePTR)
515         q.RecursionDesired = false
516
517         srv := &dns.SRV{
518                 Hdr: dns.RR_Header{
519                         Name:   s.service.ServiceInstanceName(),
520                         Rrtype: dns.TypeSRV,
521                         Class:  dns.ClassINET,
522                         Ttl:    s.ttl,
523                 },
524                 Priority: 0,
525                 Weight:   0,
526                 Port:     uint16(s.service.Port),
527                 Target:   s.service.HostName,
528         }
529         txt := &dns.TXT{
530                 Hdr: dns.RR_Header{
531                         Name:   s.service.ServiceInstanceName(),
532                         Rrtype: dns.TypeTXT,
533                         Class:  dns.ClassINET,
534                         Ttl:    s.ttl,
535                 },
536                 Txt: s.service.Text,
537         }
538         q.Ns = []dns.RR{srv, txt}
539
540         randomizer := rand.New(rand.NewSource(time.Now().UnixNano()))
541
542         for i := 0; i < multicastRepetitions; i++ {
543                 if err := s.multicastResponse(q, 0); err != nil {
544                         log.Println("[ERR] zeroconf: failed to send probe:", err.Error())
545                 }
546                 time.Sleep(time.Duration(randomizer.Intn(250)) * time.Millisecond)
547         }
548
549         // From RFC6762
550         //    The Multicast DNS responder MUST send at least two unsolicited
551         //    responses, one second apart. To provide increased robustness against
552         //    packet loss, a responder MAY send up to eight unsolicited responses,
553         //    provided that the interval between unsolicited responses increases by
554         //    at least a factor of two with every response sent.
555         timeout := 1 * time.Second
556         for i := 0; i < multicastRepetitions; i++ {
557                 for _, intf := range s.ifaces {
558                         resp := new(dns.Msg)
559                         resp.MsgHdr.Response = true
560                         // TODO: make response authoritative if we are the publisher
561                         resp.Compress = true
562                         resp.Answer = []dns.RR{}
563                         resp.Extra = []dns.RR{}
564                         s.composeLookupAnswers(resp, s.ttl, intf.Index, true)
565                         if err := s.multicastResponse(resp, intf.Index); err != nil {
566                                 log.Println("[ERR] zeroconf: failed to send announcement:", err.Error())
567                         }
568                 }
569                 time.Sleep(timeout)
570                 timeout *= 2
571         }
572 }
573
574 // announceText sends a Text announcement with cache flush enabled
575 func (s *Server) announceText() {
576         resp := new(dns.Msg)
577         resp.MsgHdr.Response = true
578
579         txt := &dns.TXT{
580                 Hdr: dns.RR_Header{
581                         Name:   s.service.ServiceInstanceName(),
582                         Rrtype: dns.TypeTXT,
583                         Class:  dns.ClassINET | qClassCacheFlush,
584                         Ttl:    s.ttl,
585                 },
586                 Txt: s.service.Text,
587         }
588
589         resp.Answer = []dns.RR{txt}
590         s.multicastResponse(resp, 0)
591 }
592
593 func (s *Server) unregister() error {
594         resp := new(dns.Msg)
595         resp.MsgHdr.Response = true
596         resp.Answer = []dns.RR{}
597         resp.Extra = []dns.RR{}
598         s.composeLookupAnswers(resp, 0, 0, true)
599         return s.multicastResponse(resp, 0)
600 }
601
602 func (s *Server) appendAddrs(list []dns.RR, ttl uint32, ifIndex int, flushCache bool) []dns.RR {
603         v4 := s.service.AddrIPv4
604         v6 := s.service.AddrIPv6
605         if len(v4) == 0 && len(v6) == 0 {
606                 iface, _ := net.InterfaceByIndex(ifIndex)
607                 if iface != nil {
608                         a4, a6 := addrsForInterface(iface)
609                         v4 = append(v4, a4...)
610                         v6 = append(v6, a6...)
611                 }
612         }
613         if ttl > 0 {
614                 // RFC6762 Section 10 says A/AAAA records SHOULD
615                 // use TTL of 120s, to account for network interface
616                 // and IP address changes.
617                 ttl = 120
618         }
619         var cacheFlushBit uint16
620         if flushCache {
621                 cacheFlushBit = qClassCacheFlush
622         }
623         for _, ipv4 := range v4 {
624                 a := &dns.A{
625                         Hdr: dns.RR_Header{
626                                 Name:   s.service.HostName,
627                                 Rrtype: dns.TypeA,
628                                 Class:  dns.ClassINET | cacheFlushBit,
629                                 Ttl:    ttl,
630                         },
631                         A: ipv4,
632                 }
633                 list = append(list, a)
634         }
635         for _, ipv6 := range v6 {
636                 aaaa := &dns.AAAA{
637                         Hdr: dns.RR_Header{
638                                 Name:   s.service.HostName,
639                                 Rrtype: dns.TypeAAAA,
640                                 Class:  dns.ClassINET | cacheFlushBit,
641                                 Ttl:    ttl,
642                         },
643                         AAAA: ipv6,
644                 }
645                 list = append(list, aaaa)
646         }
647         return list
648 }
649
650 func addrsForInterface(iface *net.Interface) ([]net.IP, []net.IP) {
651         var v4, v6, v6local []net.IP
652         addrs, _ := iface.Addrs()
653         for _, address := range addrs {
654                 if ipnet, ok := address.(*net.IPNet); ok && !ipnet.IP.IsLoopback() {
655                         if ipnet.IP.To4() != nil {
656                                 v4 = append(v4, ipnet.IP)
657                         } else {
658                                 switch ip := ipnet.IP.To16(); ip != nil {
659                                 case ip.IsGlobalUnicast():
660                                         v6 = append(v6, ipnet.IP)
661                                 case ip.IsLinkLocalUnicast():
662                                         v6local = append(v6local, ipnet.IP)
663                                 }
664                         }
665                 }
666         }
667         if len(v6) == 0 {
668                 v6 = v6local
669         }
670         return v4, v6
671 }
672
673 // unicastResponse is used to send a unicast response packet
674 func (s *Server) unicastResponse(resp *dns.Msg, ifIndex int, from net.Addr) error {
675         buf, err := resp.Pack()
676         if err != nil {
677                 return err
678         }
679         addr := from.(*net.UDPAddr)
680         if addr.IP.To4() != nil {
681                 if ifIndex != 0 {
682                         var wcm ipv4.ControlMessage
683                         wcm.IfIndex = ifIndex
684                         _, err = s.ipv4conn.WriteTo(buf, &wcm, addr)
685                 } else {
686                         _, err = s.ipv4conn.WriteTo(buf, nil, addr)
687                 }
688                 return err
689         } else {
690                 if ifIndex != 0 {
691                         var wcm ipv6.ControlMessage
692                         wcm.IfIndex = ifIndex
693                         _, err = s.ipv6conn.WriteTo(buf, &wcm, addr)
694                 } else {
695                         _, err = s.ipv6conn.WriteTo(buf, nil, addr)
696                 }
697                 return err
698         }
699 }
700
701 // multicastResponse us used to send a multicast response packet
702 func (s *Server) multicastResponse(msg *dns.Msg, ifIndex int) error {
703         buf, err := msg.Pack()
704         if err != nil {
705                 return err
706         }
707         if s.ipv4conn != nil {
708                 var wcm ipv4.ControlMessage
709                 if ifIndex != 0 {
710                         wcm.IfIndex = ifIndex
711                         s.ipv4conn.WriteTo(buf, &wcm, ipv4Addr)
712                 } else {
713                         for _, intf := range s.ifaces {
714                                 wcm.IfIndex = intf.Index
715                                 s.ipv4conn.WriteTo(buf, &wcm, ipv4Addr)
716                         }
717                 }
718         }
719
720         if s.ipv6conn != nil {
721                 var wcm ipv6.ControlMessage
722                 if ifIndex != 0 {
723                         wcm.IfIndex = ifIndex
724                         s.ipv6conn.WriteTo(buf, &wcm, ipv6Addr)
725                 } else {
726                         for _, intf := range s.ifaces {
727                                 wcm.IfIndex = intf.Index
728                                 s.ipv6conn.WriteTo(buf, &wcm, ipv6Addr)
729                         }
730                 }
731         }
732         return nil
733 }
734
735 func isUnicastQuestion(q dns.Question) bool {
736         // From RFC6762
737         // 18.12.  Repurposing of Top Bit of qclass in Question Section
738         //
739         //    In the Question Section of a Multicast DNS query, the top bit of the
740         //    qclass field is used to indicate that unicast responses are preferred
741         //    for this particular question.  (See Section 5.4.)
742         return q.Qclass&qClassCacheFlush != 0
743 }