func getRRStr(q dns.Question) (string, bool) { client := connectToRedis() defer client.Close() res := client.HMGet("rr:"+q.Name, "TTL", "CLASS", dns.TypeToString[q.Qtype]).Val() if res == nil { logStuff("No information on name %v", q.Name) return "", true } if res[0] == nil { logStuff("RR for %v is malformed: TTL missing", q.Name) return "", true } if res[1] == nil { logStuff("RR for %v is malformed: CLASS missing", q.Name) return "", true } if res[2] == nil { logStuff("No %v RR for %v. Trying CNAME", dns.TypeToString[q.Qtype], q.Name) res = client.HMGet("rr:"+q.Name, "TTL", "CLASS", "CNAME").Val() if res != nil && res[2] != nil { q.Qtype = dns.StringToType["CNAME"] } else { return "", true } } return fmt.Sprintf("%v %v %v %v %v", q.Name, res[0], res[1], dns.TypeToString[q.Qtype], res[2]), false }
func TestMDNSService_ServiceAddr(t *testing.T) { s := makeService(t) q := dns.Question{ Name: "_http._tcp.local.", Qtype: dns.TypeANY, } recs := s.Records(q) if got, want := len(recs), 5; got != want { t.Fatalf("got %d records, want %d: %v", got, want, recs) } if ptr, ok := recs[0].(*dns.PTR); !ok { t.Errorf("recs[0] should be PTR record, got: %v, all records: %v", recs[0], recs) } else if got, want := ptr.Ptr, "hostname._http._tcp.local."; got != want { t.Fatalf("bad PTR record %v: got %v, want %v", ptr, got, want) } if _, ok := recs[1].(*dns.SRV); !ok { t.Errorf("recs[1] should be SRV record, got: %v, all reccords: %v", recs[1], recs) } if _, ok := recs[2].(*dns.A); !ok { t.Errorf("recs[2] should be A record, got: %v, all records: %v", recs[2], recs) } if _, ok := recs[3].(*dns.AAAA); !ok { t.Errorf("recs[3] should be AAAA record, got: %v, all records: %v", recs[3], recs) } if _, ok := recs[4].(*dns.TXT); !ok { t.Errorf("recs[4] should be TXT record, got: %v, all records: %v", recs[4], recs) } q.Qtype = dns.TypePTR if recs2 := s.Records(q); !reflect.DeepEqual(recs, recs2) { t.Fatalf("PTR question should return same result as ANY question: ANY => %v, PTR => %v", recs, recs2) } }
func TestMDNSService_ServiceAddr(t *testing.T) { s := makeService(t) q := dns.Question{ Name: "_http._tcp.local.", Qtype: dns.TypeANY, } recs := s.Records(q) if len(recs) != 5 { t.Fatalf("bad: %v", recs) } ptr, ok := recs[0].(*dns.PTR) if !ok { t.Fatalf("bad: %v", recs[0]) } if _, ok := recs[1].(*dns.SRV); !ok { t.Fatalf("bad: %v", recs[1]) } if _, ok := recs[2].(*dns.A); !ok { t.Fatalf("bad: %v", recs[2]) } if _, ok := recs[3].(*dns.AAAA); !ok { t.Fatalf("bad: %v", recs[3]) } if _, ok := recs[4].(*dns.TXT); !ok { t.Fatalf("bad: %v", recs[4]) } if ptr.Ptr != s.instanceAddr { t.Fatalf("bad: %v", recs[0]) } q.Qtype = dns.TypePTR recs2 := s.Records(q) if !reflect.DeepEqual(recs, recs2) { t.Fatalf("no match: %v %v", recs, recs2) } }
func (r *Resolver) resolve(question dns.Question, result *dns.Msg, servers, original []string, loopcount int) ([]dns.RR, error) { if len(servers) == 0 { if r.Debug { log.Println("No more servers to query...") } result.Rcode = dns.RcodeServerFailure return nil, nil } //infinite loop prevention if loopcount == 30 { if r.Debug { log.Println("Loop count exhausted") } result.Rcode = dns.RcodeServerFailure return nil, nil } loopcount++ //Pick a server randomly shuffle(servers) server := servers[0] + ":53" nservers := []string{} for i, s := range servers { if i != 0 { nservers = append(nservers, s) } } if r.Debug { log.Println(server) log.Println(nservers) } m := &dns.Msg{} m.SetQuestion(question.Name, question.Qtype) m.RecursionDesired = false res, err := r.exchange(m, server, original) if r.Debug { if err != nil { log.Println(res, err) } } if err != nil { if r.Debug { log.Println(err) } //Restart with remaining servers return r.resolve(question, result, nservers, original, loopcount) } //Check status... if res.Rcode != dns.RcodeSuccess { //Restart with remaining servers return r.resolve(question, result, nservers, original, loopcount) } answerfound := false var cname dns.Question //Check for answers for _, ans := range res.Answer { result.Answer = append(result.Answer, ans) if ans.Header().Rrtype == question.Qtype { answerfound = true } if ans.Header().Rrtype == dns.TypeCNAME { c, _ := ans.(*dns.CNAME) cname.Name = c.Target cname.Qtype = question.Qtype } } if answerfound { return nil, nil } if cname.Name != "" { if r.Debug { log.Println("CNAME", cname, cname.Name) } return r.resolve(cname, result, r.Roothints, r.Roothints, loopcount) } //OK no ans of target type.... or CNAME found... process NS... ns := make(map[string]string) for _, n := range res.Ns { nsrec, _ := n.(*dns.NS) if nsrec != nil { ns[nsrec.Ns] = "" } } //Try to populate ips from additional... for _, a := range res.Extra { extra, ok := a.(*dns.A) if ok { _, ok := ns[extra.Header().Name] if ok { ns[extra.Header().Name] = extra.A.String() } } } newservers := []string{} //Fill in the missing ips for k, ip := range ns { if ip == "" { nsmsg := &dns.Msg{} nsmsg.SetQuestion(k, dns.TypeA) //Lets cheat and ask a recursive... nsmsg.RecursionDesired = true nsres, err := r.exchange(nsmsg, "8.8.8.8:53", []string{"8.8.8.8"}) if err == nil { for _, ans := range nsres.Answer { arec, ok := ans.(*dns.A) if ok { newservers = append(newservers, arec.A.String()) } } } } else { newservers = append(newservers, ip) } } if r.Debug { log.Println(ns) log.Println(newservers) } if len(newservers) == 0 { //Restart return r.resolve(question, result, nservers, original, loopcount) //return nil, errors.New("No NS record") } return r.resolve(question, result, newservers, newservers, 0) return nil, nil }