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

     1  package dialer
     2  
     3  import (
     4  	"context"
     5  	"net"
     6  	"sync"
     7  
     8  	"github.com/sagernet/sing-box/adapter"
     9  	E "github.com/sagernet/sing/common/exceptions"
    10  	M "github.com/sagernet/sing/common/metadata"
    11  	N "github.com/sagernet/sing/common/network"
    12  )
    13  
    14  type DetourDialer struct {
    15  	router   adapter.Router
    16  	detour   string
    17  	dialer   N.Dialer
    18  	initOnce sync.Once
    19  	initErr  error
    20  }
    21  
    22  func NewDetour(router adapter.Router, detour string) N.Dialer {
    23  	return &DetourDialer{router: router, detour: detour}
    24  }
    25  
    26  func (d *DetourDialer) Start() error {
    27  	_, err := d.Dialer()
    28  	return err
    29  }
    30  
    31  func (d *DetourDialer) Dialer() (N.Dialer, error) {
    32  	d.initOnce.Do(func() {
    33  		var loaded bool
    34  		d.dialer, loaded = d.router.Outbound(d.detour)
    35  		if !loaded {
    36  			d.initErr = E.New("outbound detour not found: ", d.detour)
    37  		}
    38  	})
    39  	return d.dialer, d.initErr
    40  }
    41  
    42  func (d *DetourDialer) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
    43  	dialer, err := d.Dialer()
    44  	if err != nil {
    45  		return nil, err
    46  	}
    47  	return dialer.DialContext(ctx, network, destination)
    48  }
    49  
    50  func (d *DetourDialer) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) {
    51  	dialer, err := d.Dialer()
    52  	if err != nil {
    53  		return nil, err
    54  	}
    55  	return dialer.ListenPacket(ctx, destination)
    56  }
    57  
    58  func (d *DetourDialer) Upstream() any {
    59  	detour, _ := d.Dialer()
    60  	return detour
    61  }