github.com/sagernet/sing-box@v1.9.0-rc.20/common/dialer/resolve.go (about)

     1  package dialer
     2  
     3  import (
     4  	"context"
     5  	"net"
     6  	"net/netip"
     7  	"time"
     8  
     9  	"github.com/sagernet/sing-box/adapter"
    10  	"github.com/sagernet/sing-box/log"
    11  	"github.com/sagernet/sing-dns"
    12  	"github.com/sagernet/sing/common/bufio"
    13  	M "github.com/sagernet/sing/common/metadata"
    14  	N "github.com/sagernet/sing/common/network"
    15  )
    16  
    17  type ResolveDialer struct {
    18  	dialer        N.Dialer
    19  	parallel      bool
    20  	router        adapter.Router
    21  	strategy      dns.DomainStrategy
    22  	fallbackDelay time.Duration
    23  }
    24  
    25  func NewResolveDialer(router adapter.Router, dialer N.Dialer, parallel bool, strategy dns.DomainStrategy, fallbackDelay time.Duration) *ResolveDialer {
    26  	return &ResolveDialer{
    27  		dialer,
    28  		parallel,
    29  		router,
    30  		strategy,
    31  		fallbackDelay,
    32  	}
    33  }
    34  
    35  func (d *ResolveDialer) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
    36  	if !destination.IsFqdn() {
    37  		return d.dialer.DialContext(ctx, network, destination)
    38  	}
    39  	ctx, metadata := adapter.ExtendContext(ctx)
    40  	ctx = log.ContextWithOverrideLevel(ctx, log.LevelDebug)
    41  	metadata.Destination = destination
    42  	metadata.Domain = ""
    43  	var addresses []netip.Addr
    44  	var err error
    45  	if d.strategy == dns.DomainStrategyAsIS {
    46  		addresses, err = d.router.LookupDefault(ctx, destination.Fqdn)
    47  	} else {
    48  		addresses, err = d.router.Lookup(ctx, destination.Fqdn, d.strategy)
    49  	}
    50  	if err != nil {
    51  		return nil, err
    52  	}
    53  	if d.parallel {
    54  		return N.DialParallel(ctx, d.dialer, network, destination, addresses, d.strategy == dns.DomainStrategyPreferIPv6, d.fallbackDelay)
    55  	} else {
    56  		return N.DialSerial(ctx, d.dialer, network, destination, addresses)
    57  	}
    58  }
    59  
    60  func (d *ResolveDialer) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) {
    61  	if !destination.IsFqdn() {
    62  		return d.dialer.ListenPacket(ctx, destination)
    63  	}
    64  	ctx, metadata := adapter.ExtendContext(ctx)
    65  	ctx = log.ContextWithOverrideLevel(ctx, log.LevelDebug)
    66  	metadata.Destination = destination
    67  	metadata.Domain = ""
    68  	var addresses []netip.Addr
    69  	var err error
    70  	if d.strategy == dns.DomainStrategyAsIS {
    71  		addresses, err = d.router.LookupDefault(ctx, destination.Fqdn)
    72  	} else {
    73  		addresses, err = d.router.Lookup(ctx, destination.Fqdn, d.strategy)
    74  	}
    75  	if err != nil {
    76  		return nil, err
    77  	}
    78  	conn, destinationAddress, err := N.ListenSerial(ctx, d.dialer, destination, addresses)
    79  	if err != nil {
    80  		return nil, err
    81  	}
    82  	return bufio.NewNATPacketConn(bufio.NewPacketConn(conn), M.SocksaddrFrom(destinationAddress, destination.Port), destination), nil
    83  }
    84  
    85  func (d *ResolveDialer) Upstream() any {
    86  	return d.dialer
    87  }