diff --git a/client/cache.go b/client/cache.go index dbe85f3..d8e248c 100644 --- a/client/cache.go +++ b/client/cache.go @@ -53,11 +53,11 @@ func (d *DelegationCache) Get(domain string) (label string, servers []Server) { for offset, end := 0, false; !end; offset, end = dns.NextLabel(domain, offset) { label = domain[offset:] var found bool - if servers, found = d.c[label]; found { - return + if _, found = d.c[label]; found { + return label, append(servers, d.c[label]...) } } - return ".", roots + return ".", append(servers, roots...) } // Add adds a server as a delegation for domain. If addrs is not specified, diff --git a/client/client.go b/client/client.go index b88cd05..e0a3db9 100644 --- a/client/client.go +++ b/client/client.go @@ -52,8 +52,8 @@ func (rs Responses) Fastest() *Response { } type Tracer struct { - GotDelegateResponses func(i int, m *dns.Msg, rs Responses, rtype ResponseType) - FollowingCNAME func(domain, target string) + GotIntermediaryResponse func(i int, m *dns.Msg, rs Responses, rtype ResponseType) + FollowingCNAME func(domain, target string) } // New creates a new Client. @@ -103,6 +103,26 @@ func (c *Client) RecursiveQuery(m *dns.Msg, tracer Tracer) (r *dns.Msg, rtt time zone := "." for i := 1; i < 100; i++ { _, servers := c.DCache.Get(qname) + + // Resolve servers name if needed. + wg := &sync.WaitGroup{} + for i, s := range servers { + if len(s.Addrs) == 0 { + wg.Add(1) + go func(s *Server) { + var err error + lm := m.Copy() + lm.SetQuestion(s.Name, 0) // qtypes are set by lookup host + s.Addrs, s.LookupRTT, err = c.lookupHost(lm) + if err != nil { + s.LookupErr = err + } + wg.Done() + }(&servers[i]) + } + } + wg.Wait() + m.Question[0].Name = qname rs := c.ParallelQuery(m, servers) @@ -147,7 +167,6 @@ func (c *Client) RecursiveQuery(m *dns.Msg, tracer Tracer) (r *dns.Msg, rtt time } if rtype == ResponseTypeDelegation { - wg := &sync.WaitGroup{} for _, ns := range r.Ns { ns, ok := ns.(*dns.NS) if !ok { @@ -171,33 +190,17 @@ func (c *Client) RecursiveQuery(m *dns.Msg, tracer Tracer) (r *dns.Msg, rtt time TTL: ns.Header().Ttl, Addrs: addrs, } - if !s.HasGlue { - wg.Add(1) - go func() { - var err error - lm := m.Copy() - lm.SetQuestion(s.Name, 0) // qtypes are set by lookup host - s.Addrs, s.LookupRTT, err = c.lookupHost(lm) - if err != nil { - s.LookupErr = err - } - c.DCache.Add(name, s) - wg.Done() - }() - continue - } c.DCache.Add(name, s) c.LCache.Set(s.Name, s.Addrs) - if tracer.GotDelegateResponses == nil { - // If not traced, do not resolve all NS + if tracer.GotIntermediaryResponse == nil { + // If not traced, only take first NS. break } } - wg.Wait() } - if tracer.GotDelegateResponses != nil { - tracer.GotDelegateResponses(i, m.Copy(), rs, rtype) + if tracer.GotIntermediaryResponse != nil { + tracer.GotIntermediaryResponse(i, m.Copy(), rs, rtype) } switch rtype { diff --git a/main.go b/main.go index eb10fc7..099a5c8 100644 --- a/main.go +++ b/main.go @@ -81,7 +81,7 @@ func main() { c := client.New() c.Client.Timeout = 500 * time.Millisecond t := client.Tracer{ - GotDelegateResponses: func(i int, m *dns.Msg, rs client.Responses, rtype client.ResponseType) { + GotIntermediaryResponse: func(i int, m *dns.Msg, rs client.Responses, rtype client.ResponseType) { fr := rs.Fastest() var r *dns.Msg if fr != nil { @@ -103,8 +103,13 @@ func main() { ln = pr.Msg.Len() } rtt := float64(pr.RTT) / float64(time.Millisecond) - lrtt := float64(pr.Server.LookupRTT) / float64(time.Millisecond) - fmt.Printf(col(" - %3d bytes in %6.2fms + %6.2fms on %s(%s)", cDarkGray), ln, rtt, lrtt, pr.Addr, pr.Server.Name) + lrtt := "0ms (from cache)" + if pr.Server.HasGlue { + lrtt = "0ms (from glue)" + } else if pr.Server.LookupRTT > 0 { + lrtt = fmt.Sprintf("%.2fms", float64(pr.Server.LookupRTT)/float64(time.Millisecond)) + } + fmt.Printf(col(" - %d bytes in %.2fms + %s lookup on %s(%s)", cDarkGray), ln, rtt, lrtt, pr.Server.Name, pr.Addr) if pr.Err != nil { err := pr.Err if oerr, ok := err.(*net.OpError); ok { @@ -130,13 +135,6 @@ func main() { glue = col("glue: "+strings.Join(s.Addrs, ","), cDarkGray) } else { glue = col("no glue", cYellow) - if s.LookupErr != nil { - glue += fmt.Sprintf(col(": lookup err: %v", cDarkGray), col(s.LookupErr, cRed)) - } else if s.LookupRTT == 0 { - glue += fmt.Sprintf(col(": lookup from cache", cDarkGray)) - } else { - glue += fmt.Sprintf(col(": lookup time: %s", cDarkGray), s.LookupRTT) - } } fmt.Printf("%s %d NS %s (%s)\n", label, s.TTL, s.Name, glue) }