// Retrieve the MX records for miek.nl. func ExampleMX() { config, _ := dns.ClientConfigFromFile("/etc/resolv.conf") c := new(dns.Client) m := new(dns.Msg) m.SetQuestion("miek.nl.", dns.TypeMX) m.RecursionDesired = true r, _, err := c.Exchange(m, config.Servers[0]+":"+config.Port) if err != nil { return } if r.Rcode != dns.RcodeSuccess { return } for _, a := range r.Answer { if mx, ok := a.(*dns.MX); ok { fmt.Printf("%s\n", mx.String()) } } }
// query is used to perform a lookup and stream results func (c *client) query(params *QueryParam) error { // Create the service name serviceAddr := fmt.Sprintf("%s.%s.", trimDot(params.Service), trimDot(params.Domain)) // Start listening for response packets msgCh := make(chan *dns.Msg, 32) go c.recv(c.ipv4UnicastConn, msgCh) go c.recv(c.ipv6UnicastConn, msgCh) go c.recv(c.ipv4MulticastConn, msgCh) go c.recv(c.ipv6MulticastConn, msgCh) // Send the query m := new(dns.Msg) m.SetQuestion(serviceAddr, dns.TypePTR) // RFC 6762, section 18.12. Repurposing of Top Bit of qclass in Question // Section // // In the Question Section of a Multicast DNS query, the top bit of the qclass // field is used to indicate that unicast responses are preferred for this // particular question. (See Section 5.4.) if params.WantUnicastResponse { m.Question[0].Qclass |= 1 << 15 } m.RecursionDesired = false if err := c.sendQuery(m); err != nil { return err } // Map the in-progress responses inprogress := make(map[string]*ServiceEntry) // Listen until we reach the timeout finish := time.After(params.Timeout) for { select { case resp := <-msgCh: var inp *ServiceEntry for _, answer := range append(resp.Answer, resp.Extra...) { // TODO(reddaly): Check that response corresponds to serviceAddr? switch rr := answer.(type) { case *dns.PTR: // Create new entry for this inp = ensureName(inprogress, rr.Ptr) case *dns.SRV: // Check for a target mismatch if rr.Target != rr.Hdr.Name { alias(inprogress, rr.Hdr.Name, rr.Target) } // Get the port inp = ensureName(inprogress, rr.Hdr.Name) inp.Host = rr.Target inp.Port = int(rr.Port) case *dns.TXT: // Pull out the txt inp = ensureName(inprogress, rr.Hdr.Name) inp.Info = strings.Join(rr.Txt, "|") inp.hasTXT = true case *dns.A: // Pull out the IP inp = ensureName(inprogress, rr.Hdr.Name) inp.Addr = rr.A // @Deprecated inp.AddrV4 = rr.A case *dns.AAAA: // Pull out the IP inp = ensureName(inprogress, rr.Hdr.Name) inp.Addr = rr.AAAA // @Deprecated inp.AddrV6 = rr.AAAA } } if inp == nil { continue } // Check if this entry is complete if inp.complete() { if inp.sent { continue } inp.sent = true select { case params.Entries <- inp: default: } } else { // Fire off a node specific query m := new(dns.Msg) m.SetQuestion(inp.Name, dns.TypePTR) m.RecursionDesired = false if err := c.sendQuery(m); err != nil { log.Printf("[ERR] mdns: Failed to query instance %s: %v", inp.Name, err) } } case <-finish: return nil } } }