@@ -20,6 +20,7 @@ import (
20
20
"encoding/binary"
21
21
"errors"
22
22
"fmt"
23
+ "math/rand"
23
24
"net"
24
25
"strings"
25
26
"sync"
@@ -81,10 +82,16 @@ var (
81
82
errNoConn = errors .New ("dnscrypt: no connection" )
82
83
)
83
84
84
- func udpExchange (pid string , serverInfo * serverinfo , sharedKey * [32 ]byte , encryptedQuery []byte , clientNonce []byte ) ([]byte , error ) {
85
+ func chooseAny [t net.Addr ](s []t ) t {
86
+ return s [rand .Intn (len (s ))]
87
+ }
88
+
89
+ func udpExchange (pid string , serverInfo * serverinfo , sharedKey * [32 ]byte , encryptedQuery []byte , clientNonce []byte ) (res []byte , relay net.Addr , err error ) {
85
90
upstreamAddr := serverInfo .UDPAddr
86
- if serverInfo .RelayUDPAddr != nil {
87
- upstreamAddr = serverInfo .RelayUDPAddr
91
+ userelay := len (serverInfo .RelayUDPAddrs ) > 0
92
+ if userelay {
93
+ upstreamAddr = chooseAny (serverInfo .RelayUDPAddrs )
94
+ relay = upstreamAddr
88
95
}
89
96
90
97
pc , err := serverInfo .dialudp (pid , upstreamAddr )
@@ -93,14 +100,14 @@ func udpExchange(pid string, serverInfo *serverinfo, sharedKey *[32]byte, encryp
93
100
err = errNoConn
94
101
}
95
102
log .E ("dnscrypt: udp: dialing %s; hasConn? %s(%t); err: %v" , serverInfo , pid , pc != nil , err )
96
- return nil , err
103
+ return
97
104
}
98
105
99
106
defer pc .Close ()
100
107
if err = pc .SetDeadline (time .Now ().Add (timeout8s )); err != nil {
101
- return nil , err
108
+ return
102
109
}
103
- if serverInfo . RelayUDPAddr != nil {
110
+ if userelay {
104
111
prepareForRelay (serverInfo .UDPAddr .IP , serverInfo .UDPAddr .Port , & encryptedQuery )
105
112
}
106
113
// TODO: use a pool
@@ -111,27 +118,31 @@ func udpExchange(pid string, serverInfo *serverinfo, sharedKey *[32]byte, encryp
111
118
core .Recycle (bptr )
112
119
}()
113
120
for tries := 2 ; tries > 0 ; tries -- {
114
- if _ , err : = pc .Write (encryptedQuery ); err != nil {
121
+ if _ , err = pc .Write (encryptedQuery ); err != nil {
115
122
log .E ("dnscrypt: udp: [%s] write err; [%v]" , serverInfo .Name , err )
116
- return nil , err
123
+ return
117
124
}
118
- length , err := pc .Read (encryptedResponse )
125
+ var length int
126
+ length , err = pc .Read (encryptedResponse )
119
127
if err == nil {
120
128
encryptedResponse = encryptedResponse [:length ]
121
129
break
122
130
} else if tries <= 0 {
123
131
log .E ("dnscrypt: udp: [%s] read err; quit [%v]" , serverInfo .Name , err )
124
- return nil , err
132
+ return
125
133
}
126
134
log .D ("dnscrypt: udp: [%s] read err; retry [%v]" , serverInfo .Name , err )
127
135
}
128
- return decrypt (serverInfo , sharedKey , encryptedResponse , clientNonce )
136
+ res , err = decrypt (serverInfo , sharedKey , encryptedResponse , clientNonce )
137
+ return
129
138
}
130
139
131
- func tcpExchange (pid string , serverInfo * serverinfo , sharedKey * [32 ]byte , encryptedQuery []byte , clientNonce []byte ) ([]byte , error ) {
140
+ func tcpExchange (pid string , serverInfo * serverinfo , sharedKey * [32 ]byte , encryptedQuery []byte , clientNonce []byte ) (res []byte , relay net. Addr , err error ) {
132
141
upstreamAddr := serverInfo .TCPAddr
133
- if serverInfo .RelayTCPAddr != nil {
134
- upstreamAddr = serverInfo .RelayTCPAddr
142
+ userelay := len (serverInfo .RelayTCPAddrs ) > 0
143
+ if userelay {
144
+ upstreamAddr = chooseAny (serverInfo .RelayTCPAddrs )
145
+ relay = upstreamAddr
135
146
}
136
147
137
148
pc , err := serverInfo .dialtcp (pid , upstreamAddr )
@@ -140,31 +151,32 @@ func tcpExchange(pid string, serverInfo *serverinfo, sharedKey *[32]byte, encryp
140
151
err = errNoConn
141
152
}
142
153
log .E ("dnscrypt: tcp: dialing %s; hasConn? %s(%t); err: %v" , serverInfo , pid , pc != nil , err )
143
- return nil , err
154
+ return
144
155
}
145
156
defer pc .Close ()
146
- if derr : = pc .SetDeadline (time .Now ().Add (timeout8s )); derr != nil {
147
- log .E ("dnscrypt: tcp: err deadline: %v" , derr )
148
- return nil , derr
157
+ if err = pc .SetDeadline (time .Now ().Add (timeout8s )); err != nil {
158
+ log .E ("dnscrypt: tcp: err deadline: %v" , err )
159
+ return
149
160
}
150
- if serverInfo . RelayTCPAddr != nil {
161
+ if userelay {
151
162
prepareForRelay (serverInfo .TCPAddr .IP , serverInfo .TCPAddr .Port , & encryptedQuery )
152
163
}
153
164
encryptedQuery , err = xdns .PrefixWithSize (encryptedQuery )
154
165
if err != nil {
155
166
log .E ("dnscrypt: tcp: prefix(q) %s err: %v" , serverInfo , err )
156
- return nil , err
167
+ return
157
168
}
158
- if _ , werr : = pc .Write (encryptedQuery ); werr != nil {
159
- log .E ("dnscrypt: tcp: err write: %v" , serverInfo , werr )
160
- return nil , werr
169
+ if _ , err = pc .Write (encryptedQuery ); err != nil {
170
+ log .E ("dnscrypt: tcp: err write: %v" , serverInfo , err )
171
+ return
161
172
}
162
173
encryptedResponse , err := xdns .ReadPrefixed (& pc )
163
174
if err != nil {
164
175
log .E ("dnscrypt: tcp: read(enc) %s err %v" , serverInfo , err )
165
- return nil , err
176
+ return
166
177
}
167
- return decrypt (serverInfo , sharedKey , encryptedResponse , clientNonce )
178
+ res , err = decrypt (serverInfo , sharedKey , encryptedResponse , clientNonce )
179
+ return
168
180
}
169
181
170
182
func prepareForRelay (ip net.IP , port int , eq * []byte ) {
@@ -177,7 +189,7 @@ func prepareForRelay(ip net.IP, port int, eq *[]byte) {
177
189
* eq = relayedQuery
178
190
}
179
191
180
- func query (pid string , packet []byte , serverInfo * serverinfo , useudp bool ) (response []byte , qerr * dnsx.QueryError ) {
192
+ func query (pid string , packet []byte , serverInfo * serverinfo , useudp bool ) (response []byte , relay net. Addr , qerr * dnsx.QueryError ) {
181
193
if len (packet ) < xdns .MinDNSPacketSize {
182
194
qerr = dnsx .NewBadQueryError (errQueryTooShort )
183
195
return
@@ -235,7 +247,7 @@ func query(pid string, packet []byte, serverInfo *serverinfo, useudp bool) (resp
235
247
}
236
248
237
249
if useudp {
238
- response , err = udpExchange (pid , serverInfo , sharedKey , encryptedQuery , clientNonce )
250
+ response , relay , err = udpExchange (pid , serverInfo , sharedKey , encryptedQuery , clientNonce )
239
251
}
240
252
tcpfallback := useudp && err != nil
241
253
if tcpfallback {
@@ -244,7 +256,7 @@ func query(pid string, packet []byte, serverInfo *serverinfo, useudp bool) (resp
244
256
// if udp errored out, try over tcp; or use tcp if udp is disabled
245
257
if tcpfallback || ! useudp {
246
258
useudp = false // switched to tcp
247
- response , err = tcpExchange (pid , serverInfo , sharedKey , encryptedQuery , clientNonce )
259
+ response , relay , err = tcpExchange (pid , serverInfo , sharedKey , encryptedQuery , clientNonce )
248
260
}
249
261
250
262
if err != nil {
@@ -291,14 +303,15 @@ func query(pid string, packet []byte, serverInfo *serverinfo, useudp bool) (resp
291
303
// resolve resolves incoming DNS query, data
292
304
func resolve (network string , data []byte , si * serverinfo , smm * x.DNSSummary ) (response []byte , err error ) {
293
305
var qerr * dnsx.QueryError
306
+ var anonrelayaddr net.Addr
294
307
295
308
before := time .Now ()
296
309
297
310
proto , pid := xdns .Net2ProxyID (network )
298
311
useudp := proto == dnsx .NetTypeUDP
299
312
300
313
// si may be nil
301
- response , qerr = query (pid , data , si , useudp )
314
+ response , anonrelayaddr , qerr = query (pid , data , si , useudp )
302
315
303
316
after := time .Now ()
304
317
@@ -309,8 +322,8 @@ func resolve(network string, data []byte, si *serverinfo, smm *x.DNSSummary) (re
309
322
var anonrelay string
310
323
if si != nil {
311
324
resolver = si .HostName
312
- if si . RelayTCPAddr != nil {
313
- anonrelay = si . RelayTCPAddr . IP .String ()
325
+ if anonrelayaddr != nil { // may be nil
326
+ anonrelay = anonrelayaddr .String ()
314
327
}
315
328
}
316
329
@@ -326,7 +339,7 @@ func resolve(network string, data []byte, si *serverinfo, smm *x.DNSSummary) (re
326
339
smm .RCode = xdns .Rcode (ans )
327
340
smm .RTtl = xdns .RTtl (ans )
328
341
smm .Server = resolver
329
- smm .RelayServer = anonrelay
342
+ smm .RelayServer = anonrelay // may be empty
330
343
smm .Status = status
331
344
332
345
noAnonRelay := len (anonrelay ) <= 0
@@ -394,15 +407,15 @@ func (proxy *DcMulti) start() error {
394
407
curve25519 .ScalarBaseMult (& proxy .proxyPublicKey , & proxy .proxySecretKey )
395
408
396
409
_ , err := proxy .Refresh ()
397
- if len ( proxy .serversInfo .registeredServers ) > 0 {
410
+ if proxy .serversInfo .len ( ) > 0 {
398
411
go func (ctx context.Context ) {
399
412
for {
400
413
select {
401
414
case <- ctx .Done ():
402
415
log .I ("dnscrypt: cert refresh stopped" )
403
416
return
404
417
default :
405
- hasServers := len ( proxy .serversInfo .registeredServers ) > 0
418
+ hasServers := proxy .serversInfo .len ( ) > 0
406
419
allDead := len (proxy .liveServers ) == 0
407
420
delay := certRefreshDelay
408
421
if hasServers && allDead {
0 commit comments