detour.go 1.3 KB

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