17
17
package net
18
18
19
19
import (
20
+ "io"
20
21
"math/rand"
21
22
"sync"
22
23
"time"
@@ -25,6 +26,13 @@ import (
25
26
// Send a request on the connection and hope for a reply.
26
27
// Up to cfg.attempts attempts.
27
28
func exchange (cfg * dnsConfig , c Conn , name string , qtype uint16 ) (* dnsMsg , error ) {
29
+ var useTCP bool
30
+ switch c .(type ) {
31
+ case * UDPConn :
32
+ useTCP = false
33
+ case * TCPConn :
34
+ useTCP = true
35
+ }
28
36
if len (name ) >= 256 {
29
37
return nil , & DNSError {Err : "name too long" , Name : name }
30
38
}
@@ -38,7 +46,10 @@ func exchange(cfg *dnsConfig, c Conn, name string, qtype uint16) (*dnsMsg, error
38
46
if ! ok {
39
47
return nil , & DNSError {Err : "internal error - cannot pack message" , Name : name }
40
48
}
41
-
49
+ if useTCP {
50
+ mlen := uint16 (len (msg ))
51
+ msg = append ([]byte {byte (mlen >> 8 ), byte (mlen )}, msg ... )
52
+ }
42
53
for attempt := 0 ; attempt < cfg .attempts ; attempt ++ {
43
54
n , err := c .Write (msg )
44
55
if err != nil {
@@ -50,9 +61,19 @@ func exchange(cfg *dnsConfig, c Conn, name string, qtype uint16) (*dnsMsg, error
50
61
} else {
51
62
c .SetReadDeadline (time .Now ().Add (time .Duration (cfg .timeout ) * time .Second ))
52
63
}
53
-
54
- buf := make ([]byte , 2000 ) // More than enough.
55
- n , err = c .Read (buf )
64
+ buf := make ([]byte , 2000 )
65
+ if useTCP {
66
+ n , err = io .ReadFull (c , buf [:2 ])
67
+ if err != nil {
68
+ if e , ok := err .(Error ); ok && e .Timeout () {
69
+ continue
70
+ }
71
+ }
72
+ buf = make ([]byte , uint16 (buf [0 ])<< 8 + uint16 (buf [1 ]))
73
+ n , err = io .ReadFull (c , buf )
74
+ } else {
75
+ n , err = c .Read (buf )
76
+ }
56
77
if err != nil {
57
78
if e , ok := err .(Error ); ok && e .Timeout () {
58
79
continue
@@ -98,6 +119,19 @@ func tryOneName(cfg *dnsConfig, name string, qtype uint16) (cname string, addrs
98
119
err = merr
99
120
continue
100
121
}
122
+ if msg .truncated { // see RFC 5966
123
+ c , cerr = Dial ("tcp" , server )
124
+ if cerr != nil {
125
+ err = cerr
126
+ continue
127
+ }
128
+ msg , merr = exchange (cfg , c , name , qtype )
129
+ c .Close ()
130
+ if merr != nil {
131
+ err = merr
132
+ continue
133
+ }
134
+ }
101
135
cname , addrs , err = answer (name , server , msg , qtype )
102
136
if err == nil || err .(* DNSError ).Err == noSuchHost {
103
137
break
0 commit comments