@@ -2,6 +2,7 @@ package libnetwork
22
33import (
44 "fmt"
5+ "math/rand"
56 "net"
67 "strings"
78 "sync"
@@ -33,13 +34,14 @@ type Resolver interface {
3334}
3435
3536const (
36- resolverIP = "127.0.0.11"
37- dnsPort = "53"
38- ptrIPv4domain = ".in-addr.arpa."
39- ptrIPv6domain = ".ip6.arpa."
40- respTTL = 600
41- maxExtDNS = 3 //max number of external servers to try
42- extIOTimeout = 3 * time .Second
37+ resolverIP = "127.0.0.11"
38+ dnsPort = "53"
39+ ptrIPv4domain = ".in-addr.arpa."
40+ ptrIPv6domain = ".ip6.arpa."
41+ respTTL = 600
42+ maxExtDNS = 3 //max number of external servers to try
43+ extIOTimeout = 3 * time .Second
44+ defaultRespSize = 512
4345)
4446
4547type extDNSEntry struct {
@@ -59,6 +61,10 @@ type resolver struct {
5961 err error
6062}
6163
64+ func init () {
65+ rand .Seed (time .Now ().Unix ())
66+ }
67+
6268// NewResolver creates a new instance of the Resolver
6369func NewResolver (sb * sandbox ) Resolver {
6470 return & resolver {
@@ -166,22 +172,36 @@ func setCommonFlags(msg *dns.Msg) {
166172 msg .RecursionAvailable = true
167173}
168174
175+ func shuffleAddr (addr []net.IP ) []net.IP {
176+ for i := len (addr ) - 1 ; i > 0 ; i -- {
177+ r := rand .Intn (i + 1 )
178+ addr [i ], addr [r ] = addr [r ], addr [i ]
179+ }
180+ return addr
181+ }
182+
169183func (r * resolver ) handleIPv4Query (name string , query * dns.Msg ) (* dns.Msg , error ) {
170184 addr := r .sb .ResolveName (name )
171185 if addr == nil {
172186 return nil , nil
173187 }
174188
175- log .Debugf ("Lookup for %s: IP %s " , name , addr . String () )
189+ log .Debugf ("Lookup for %s: IP %v " , name , addr )
176190
177191 resp := new (dns.Msg )
178192 resp .SetReply (query )
179193 setCommonFlags (resp )
180194
181- rr := new (dns.A )
182- rr .Hdr = dns.RR_Header {Name : name , Rrtype : dns .TypeA , Class : dns .ClassINET , Ttl : respTTL }
183- rr .A = addr
184- resp .Answer = append (resp .Answer , rr )
195+ if len (addr ) > 1 {
196+ addr = shuffleAddr (addr )
197+ }
198+
199+ for _ , ip := range addr {
200+ rr := new (dns.A )
201+ rr .Hdr = dns.RR_Header {Name : name , Rrtype : dns .TypeA , Class : dns .ClassINET , Ttl : respTTL }
202+ rr .A = ip
203+ resp .Answer = append (resp .Answer , rr )
204+ }
185205 return resp , nil
186206}
187207
@@ -215,6 +235,18 @@ func (r *resolver) handlePTRQuery(ptr string, query *dns.Msg) (*dns.Msg, error)
215235 return resp , nil
216236}
217237
238+ func truncateResp (resp * dns.Msg , maxSize int , isTCP bool ) {
239+ if ! isTCP {
240+ resp .Truncated = true
241+ }
242+
243+ // trim the Answer RRs one by one till the whole message fits
244+ // within the reply size
245+ for resp .Len () > maxSize {
246+ resp .Answer = resp .Answer [:len (resp .Answer )- 1 ]
247+ }
248+ }
249+
218250func (r * resolver ) ServeDNS (w dns.ResponseWriter , query * dns.Msg ) {
219251 var (
220252 extConn net.Conn
@@ -238,7 +270,24 @@ func (r *resolver) ServeDNS(w dns.ResponseWriter, query *dns.Msg) {
238270 }
239271
240272 proto := w .LocalAddr ().Network ()
241- if resp == nil {
273+ maxSize := 0
274+ if proto == "tcp" {
275+ maxSize = dns .MaxMsgSize - 1
276+ } else if proto == "udp" {
277+ optRR := query .IsEdns0 ()
278+ if optRR != nil {
279+ maxSize = int (optRR .UDPSize ())
280+ }
281+ if maxSize < defaultRespSize {
282+ maxSize = defaultRespSize
283+ }
284+ }
285+
286+ if resp != nil {
287+ if resp .Len () > maxSize {
288+ truncateResp (resp , maxSize , proto == "tcp" )
289+ }
290+ } else {
242291 for i := 0 ; i < maxExtDNS ; i ++ {
243292 extDNS := & r .extDNSList [i ]
244293 if extDNS .ipStr == "" {
0 commit comments