| 
					
				 | 
			
			
				@@ -1,28 +1,27 @@ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+//go:build !darwin 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 package local 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 import ( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	"context" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	"errors" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	"math/rand" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	"syscall" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	"time" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	"github.com/sagernet/sing-box/adapter" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	C "github.com/sagernet/sing-box/constant" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	"github.com/sagernet/sing-box/dns" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	"github.com/sagernet/sing-box/dns/transport" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	"github.com/sagernet/sing-box/dns/transport/hosts" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	"github.com/sagernet/sing-box/log" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	"github.com/sagernet/sing-box/option" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	"github.com/sagernet/sing/common/buf" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	E "github.com/sagernet/sing/common/exceptions" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	"github.com/sagernet/sing/common/logger" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	M "github.com/sagernet/sing/common/metadata" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	N "github.com/sagernet/sing/common/network" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	mDNS "github.com/miekg/dns" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+func RegisterTransport(registry *dns.TransportRegistry) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	dns.RegisterTransport[option.LocalDNSServerOptions](registry, C.DNSTypeLocal, NewTransport) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 var _ adapter.DNSTransport = (*Transport)(nil) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 type Transport struct { 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -31,6 +30,7 @@ type Transport struct { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	logger   logger.ContextLogger 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	hosts    *hosts.File 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	dialer   N.Dialer 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	preferGo bool 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	resolved ResolvedResolver 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -45,19 +45,22 @@ func NewTransport(ctx context.Context, logger log.ContextLogger, tag string, opt 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		logger:           logger, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		hosts:            hosts.NewFile(hosts.DefaultPath), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		dialer:           transportDialer, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		preferGo:         options.PreferGo, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	}, nil 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 func (t *Transport) Start(stage adapter.StartStage) error { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	switch stage { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	case adapter.StartStateInitialize: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		resolvedResolver, err := NewResolvedResolver(t.ctx, t.logger) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		if err == nil { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-			err = resolvedResolver.Start() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		if !t.preferGo { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			resolvedResolver, err := NewResolvedResolver(t.ctx, t.logger) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 			if err == nil { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-				t.resolved = resolvedResolver 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-			} else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-				t.logger.Warn(E.Cause(err, "initialize resolved resolver")) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				err = resolvedResolver.Start() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				if err == nil { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					t.resolved = resolvedResolver 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				} else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					t.logger.Warn(E.Cause(err, "initialize resolved resolver")) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 			} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	} 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -85,174 +88,5 @@ func (t *Transport) Exchange(ctx context.Context, message *mDNS.Msg) (*mDNS.Msg, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 			return dns.FixedResponse(message.Id, question, addresses, C.DefaultDNSTTL), nil 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	systemConfig := getSystemDNSConfig(t.ctx) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	if systemConfig.singleRequest || !(message.Question[0].Qtype == mDNS.TypeA || message.Question[0].Qtype == mDNS.TypeAAAA) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		return t.exchangeSingleRequest(ctx, systemConfig, message, question.Name) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	} else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		return t.exchangeParallel(ctx, systemConfig, message, question.Name) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-func (t *Transport) exchangeSingleRequest(ctx context.Context, systemConfig *dnsConfig, message *mDNS.Msg, domain string) (*mDNS.Msg, error) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	var lastErr error 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	for _, fqdn := range systemConfig.nameList(domain) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		response, err := t.tryOneName(ctx, systemConfig, fqdn, message) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		if err != nil { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-			lastErr = err 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-			continue 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		return response, nil 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	return nil, lastErr 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-func (t *Transport) exchangeParallel(ctx context.Context, systemConfig *dnsConfig, message *mDNS.Msg, domain string) (*mDNS.Msg, error) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	returned := make(chan struct{}) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	defer close(returned) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	type queryResult struct { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		response *mDNS.Msg 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		err      error 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	results := make(chan queryResult) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	startRacer := func(ctx context.Context, fqdn string) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		response, err := t.tryOneName(ctx, systemConfig, fqdn, message) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		if err == nil { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-			if response.Rcode != mDNS.RcodeSuccess { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-				err = dns.RcodeError(response.Rcode) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-			} else if len(dns.MessageToAddresses(response)) == 0 { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-				err = dns.RcodeSuccess 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-			} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		select { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		case results <- queryResult{response, err}: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		case <-returned: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	queryCtx, queryCancel := context.WithCancel(ctx) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	defer queryCancel() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	var nameCount int 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	for _, fqdn := range systemConfig.nameList(domain) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		nameCount++ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		go startRacer(queryCtx, fqdn) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	var errors []error 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	for { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		select { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		case <-ctx.Done(): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-			return nil, ctx.Err() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		case result := <-results: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-			if result.err == nil { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-				return result.response, nil 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-			} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-			errors = append(errors, result.err) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-			if len(errors) == nameCount { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-				return nil, E.Errors(errors...) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-			} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-func (t *Transport) tryOneName(ctx context.Context, config *dnsConfig, fqdn string, message *mDNS.Msg) (*mDNS.Msg, error) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	serverOffset := config.serverOffset() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	sLen := uint32(len(config.servers)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	var lastErr error 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	for i := 0; i < config.attempts; i++ { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		for j := uint32(0); j < sLen; j++ { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-			server := config.servers[(serverOffset+j)%sLen] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-			question := message.Question[0] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-			question.Name = fqdn 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-			response, err := t.exchangeOne(ctx, M.ParseSocksaddr(server), question, config.timeout, config.useTCP, config.trustAD) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-			if err != nil { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-				lastErr = err 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-				continue 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-			} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-			return response, nil 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	return nil, E.Cause(lastErr, fqdn) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-func (t *Transport) exchangeOne(ctx context.Context, server M.Socksaddr, question mDNS.Question, timeout time.Duration, useTCP, ad bool) (*mDNS.Msg, error) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	if server.Port == 0 { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		server.Port = 53 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	request := &mDNS.Msg{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		MsgHdr: mDNS.MsgHdr{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-			Id:                uint16(rand.Uint32()), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-			RecursionDesired:  true, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-			AuthenticatedData: ad, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		}, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		Question: []mDNS.Question{question}, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		Compress: true, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	request.SetEdns0(buf.UDPBufferSize, false) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	if !useTCP { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		return t.exchangeUDP(ctx, server, request, timeout) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	} else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		return t.exchangeTCP(ctx, server, request, timeout) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-func (t *Transport) exchangeUDP(ctx context.Context, server M.Socksaddr, request *mDNS.Msg, timeout time.Duration) (*mDNS.Msg, error) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	conn, err := t.dialer.DialContext(ctx, N.NetworkUDP, server) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	if err != nil { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		return nil, err 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	defer conn.Close() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	if deadline, loaded := ctx.Deadline(); loaded && !deadline.IsZero() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		newDeadline := time.Now().Add(timeout) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		if deadline.After(newDeadline) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-			deadline = newDeadline 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		conn.SetDeadline(deadline) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	buffer := buf.Get(buf.UDPBufferSize) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	defer buf.Put(buffer) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	rawMessage, err := request.PackBuffer(buffer) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	if err != nil { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		return nil, E.Cause(err, "pack request") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	_, err = conn.Write(rawMessage) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	if err != nil { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		if errors.Is(err, syscall.EMSGSIZE) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-			return t.exchangeTCP(ctx, server, request, timeout) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		return nil, E.Cause(err, "write request") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	n, err := conn.Read(buffer) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	if err != nil { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		if errors.Is(err, syscall.EMSGSIZE) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-			return t.exchangeTCP(ctx, server, request, timeout) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		return nil, E.Cause(err, "read response") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	var response mDNS.Msg 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	err = response.Unpack(buffer[:n]) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	if err != nil { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		return nil, E.Cause(err, "unpack response") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	if response.Truncated { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		return t.exchangeTCP(ctx, server, request, timeout) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	return &response, nil 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-func (t *Transport) exchangeTCP(ctx context.Context, server M.Socksaddr, request *mDNS.Msg, timeout time.Duration) (*mDNS.Msg, error) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	conn, err := t.dialer.DialContext(ctx, N.NetworkTCP, server) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	if err != nil { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		return nil, err 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	defer conn.Close() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	if deadline, loaded := ctx.Deadline(); loaded && !deadline.IsZero() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		newDeadline := time.Now().Add(timeout) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		if deadline.After(newDeadline) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-			deadline = newDeadline 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		conn.SetDeadline(deadline) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	err = transport.WriteMessage(conn, 0, request) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	if err != nil { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		return nil, err 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	return transport.ReadMessage(conn) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	return t.exchange(ctx, message, question.Name) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 |