@@ -37,7 +37,7 @@ func (rs Responses) Fastest() *Response {
37
37
}
38
38
39
39
type Tracer struct {
40
- GotDelegateResponses func (i int , m * dns.Msg , rs Responses )
40
+ GotDelegateResponses func (i int , m * dns.Msg , rs Responses , last bool )
41
41
FollowingCNAME func (domain , target string )
42
42
}
43
43
@@ -51,7 +51,7 @@ func New() Client {
51
51
52
52
// ParallelQuery perform an exchange using m with all servers in parallel and
53
53
// return all responses.
54
- func (c * Client ) ParallelQuery (m * dns.Msg , servers Servers ) Responses {
54
+ func (c * Client ) ParallelQuery (m * dns.Msg , servers [] Server ) Responses {
55
55
rc := make (chan Response )
56
56
cnt := 0
57
57
for _ , s := range servers {
@@ -81,8 +81,9 @@ func (c *Client) RecursiveQuery(m *dns.Msg, tracer Tracer) (r *dns.Msg, rtt time
81
81
m = m .Copy ()
82
82
qname := m .Question [0 ].Name
83
83
qtype := m .Question [0 ].Qtype
84
+ zone := "."
84
85
for i := 1 ; i < 100 ; i ++ {
85
- deleg , servers := c .DCache .Get (qname )
86
+ _ , servers := c .DCache .Get (qname )
86
87
m .Question [0 ].Name = qname
87
88
rs := c .ParallelQuery (m , servers )
88
89
@@ -99,26 +100,47 @@ func (c *Client) RecursiveQuery(m *dns.Msg, tracer Tracer) (r *dns.Msg, rtt time
99
100
}
100
101
rtt += fr .RTT
101
102
102
- done := false
103
+ var done bool
104
+ var deleg bool
105
+ var cname string
103
106
for _ , rr := range r .Answer {
104
- if rr .Header ().Rrtype == qtype && rr .Header ().Name == qname {
107
+ if rr .Header ().Name == qname && rr .Header ().Rrtype == qtype {
105
108
done = true
106
109
break
110
+ } else if rr .Header ().Rrtype == dns .TypeCNAME {
111
+ cname = rr .Header ().Name
112
+ qname = rr .(* dns.CNAME ).Target
113
+ zone = "."
114
+ }
115
+ }
116
+ if ! done && cname == "" {
117
+ for _ , ns := range r .Ns {
118
+ if ns , ok := ns .(* dns.NS ); ok && len (ns .Header ().Name ) > len (zone ) {
119
+ deleg = true
120
+ zone = ns .Header ().Name
121
+ break
122
+ }
107
123
}
108
124
}
109
125
110
- if ! done {
126
+ if deleg {
111
127
lrttc := make (chan time.Duration )
112
128
lc := 0
113
129
for _ , ns := range r .Ns {
114
130
ns , ok := ns .(* dns.NS )
115
131
if ! ok {
116
132
continue // skip DS records
117
133
}
134
+ name := ns .Header ().Name
118
135
var addrs []string
119
136
for _ , rr := range r .Extra {
120
- if a , ok := rr .(* dns.A ); ok && a .Header ().Name == ns .Ns {
121
- addrs = append (addrs , a .A .String ())
137
+ if rr .Header ().Name == ns .Ns {
138
+ switch a := rr .(type ) {
139
+ case * dns.A :
140
+ addrs = append (addrs , a .A .String ())
141
+ case * dns.AAAA :
142
+ addrs = append (addrs , a .AAAA .String ())
143
+ }
122
144
}
123
145
}
124
146
s := Server {
@@ -137,12 +159,13 @@ func (c *Client) RecursiveQuery(m *dns.Msg, tracer Tracer) (r *dns.Msg, rtt time
137
159
if err != nil {
138
160
s .LookupErr = err
139
161
}
140
- c .DCache .Add (ns . Header (). Name , s )
162
+ c .DCache .Add (name , s )
141
163
lrttc <- s .LookupRTT
142
164
}()
143
165
continue
144
166
}
145
- c .DCache .Add (ns .Header ().Name , s )
167
+ c .DCache .Add (name , s )
168
+ c .LCache .Set (s .Name , s .Addrs )
146
169
if tracer .GotDelegateResponses == nil {
147
170
// If not traced, do not resolve all NS
148
171
break
@@ -159,27 +182,17 @@ func (c *Client) RecursiveQuery(m *dns.Msg, tracer Tracer) (r *dns.Msg, rtt time
159
182
}
160
183
161
184
if tracer .GotDelegateResponses != nil {
162
- tracer .GotDelegateResponses (i , m .Copy (), rs )
185
+ last := ! deleg && cname == ""
186
+ tracer .GotDelegateResponses (i , m .Copy (), rs , last )
163
187
}
164
188
165
- if len (r .Answer ) > 0 {
166
- var cname string
167
- for _ , rr := range r .Answer {
168
- if rr .Header ().Rrtype == dns .TypeCNAME {
169
- cname = rr .Header ().Name
170
- qname = rr .(* dns.CNAME ).Target
171
- }
172
- }
173
- if cname != "" {
174
- if tracer .FollowingCNAME != nil {
175
- tracer .FollowingCNAME (cname , qname )
176
- }
177
- continue
189
+ if cname != "" {
190
+ if tracer .FollowingCNAME != nil {
191
+ tracer .FollowingCNAME (cname , qname )
178
192
}
179
- return r , rtt , nil
193
+ continue
180
194
}
181
-
182
- if label , _ := c .DCache .Get (qname ); len (r .Ns ) == 0 || deleg == label {
195
+ if ! deleg {
183
196
return r , rtt , nil
184
197
}
185
198
}
@@ -214,6 +227,9 @@ func (c *Client) lookupHost(m *dns.Msg) (addrs []string, rtt time.Duration, err
214
227
if r .RTT > rtt {
215
228
rtt = r .RTT // get the longest of the two // queries
216
229
}
230
+ if r .Msg == nil {
231
+ continue
232
+ }
217
233
for _ , rr := range r .Msg .Answer {
218
234
switch rr := rr .(type ) {
219
235
case * dns.A :
0 commit comments