outbound.go 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. package anytls
  2. import (
  3. "context"
  4. "net"
  5. "os"
  6. "github.com/sagernet/sing-box/adapter"
  7. "github.com/sagernet/sing-box/adapter/outbound"
  8. "github.com/sagernet/sing-box/common/dialer"
  9. "github.com/sagernet/sing-box/common/tls"
  10. C "github.com/sagernet/sing-box/constant"
  11. "github.com/sagernet/sing-box/log"
  12. "github.com/sagernet/sing-box/option"
  13. "github.com/sagernet/sing/common"
  14. E "github.com/sagernet/sing/common/exceptions"
  15. M "github.com/sagernet/sing/common/metadata"
  16. N "github.com/sagernet/sing/common/network"
  17. "github.com/sagernet/sing/common/uot"
  18. anytls "github.com/anytls/sing-anytls"
  19. )
  20. func RegisterOutbound(registry *outbound.Registry) {
  21. outbound.Register[option.AnyTLSOutboundOptions](registry, C.TypeAnyTLS, NewOutbound)
  22. }
  23. type Outbound struct {
  24. outbound.Adapter
  25. dialer N.Dialer
  26. server M.Socksaddr
  27. tlsConfig tls.Config
  28. client *anytls.Client
  29. uotClient *uot.Client
  30. logger log.ContextLogger
  31. }
  32. func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.AnyTLSOutboundOptions) (adapter.Outbound, error) {
  33. outbound := &Outbound{
  34. Adapter: outbound.NewAdapterWithDialerOptions(C.TypeAnyTLS, tag, []string{N.NetworkTCP, N.NetworkUDP}, options.DialerOptions),
  35. server: options.ServerOptions.Build(),
  36. logger: logger,
  37. }
  38. if options.TLS == nil || !options.TLS.Enabled {
  39. return nil, C.ErrTLSRequired
  40. }
  41. // TCP Fast Open is incompatible with anytls because TFO creates a lazy connection
  42. // that only establishes on first write. The lazy connection returns an empty address
  43. // before establishment, but anytls SOCKS wrapper tries to access the remote address
  44. // during handshake, causing a null pointer dereference crash.
  45. if options.DialerOptions.TCPFastOpen {
  46. return nil, E.New("tcp_fast_open is not supported with anytls outbound")
  47. }
  48. tlsConfig, err := tls.NewClient(ctx, options.Server, common.PtrValueOrDefault(options.TLS))
  49. if err != nil {
  50. return nil, err
  51. }
  52. outbound.tlsConfig = tlsConfig
  53. outboundDialer, err := dialer.NewWithOptions(dialer.Options{
  54. Context: ctx,
  55. Options: options.DialerOptions,
  56. RemoteIsDomain: options.ServerIsDomain(),
  57. })
  58. if err != nil {
  59. return nil, err
  60. }
  61. outbound.dialer = outboundDialer
  62. client, err := anytls.NewClient(ctx, anytls.ClientConfig{
  63. Password: options.Password,
  64. IdleSessionCheckInterval: options.IdleSessionCheckInterval.Build(),
  65. IdleSessionTimeout: options.IdleSessionTimeout.Build(),
  66. MinIdleSession: options.MinIdleSession,
  67. DialOut: outbound.dialOut,
  68. Logger: logger,
  69. })
  70. if err != nil {
  71. return nil, err
  72. }
  73. outbound.client = client
  74. outbound.uotClient = &uot.Client{
  75. Dialer: (anytlsDialer)(client.CreateProxy),
  76. Version: uot.Version,
  77. }
  78. return outbound, nil
  79. }
  80. type anytlsDialer func(ctx context.Context, destination M.Socksaddr) (net.Conn, error)
  81. func (d anytlsDialer) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
  82. return d(ctx, destination)
  83. }
  84. func (d anytlsDialer) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) {
  85. return nil, os.ErrInvalid
  86. }
  87. func (h *Outbound) dialOut(ctx context.Context) (net.Conn, error) {
  88. conn, err := h.dialer.DialContext(ctx, N.NetworkTCP, h.server)
  89. if err != nil {
  90. return nil, err
  91. }
  92. tlsConn, err := tls.ClientHandshake(ctx, conn, h.tlsConfig)
  93. if err != nil {
  94. common.Close(tlsConn, conn)
  95. return nil, err
  96. }
  97. return tlsConn, nil
  98. }
  99. func (h *Outbound) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
  100. ctx, metadata := adapter.ExtendContext(ctx)
  101. metadata.Outbound = h.Tag()
  102. metadata.Destination = destination
  103. switch N.NetworkName(network) {
  104. case N.NetworkTCP:
  105. h.logger.InfoContext(ctx, "outbound connection to ", destination)
  106. return h.client.CreateProxy(ctx, destination)
  107. case N.NetworkUDP:
  108. h.logger.InfoContext(ctx, "outbound UoT packet connection to ", destination)
  109. return h.uotClient.DialContext(ctx, network, destination)
  110. }
  111. return nil, os.ErrInvalid
  112. }
  113. func (h *Outbound) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) {
  114. ctx, metadata := adapter.ExtendContext(ctx)
  115. metadata.Outbound = h.Tag()
  116. metadata.Destination = destination
  117. h.logger.InfoContext(ctx, "outbound UoT packet connection to ", destination)
  118. return h.uotClient.ListenPacket(ctx, destination)
  119. }
  120. func (h *Outbound) Close() error {
  121. return common.Close(h.client)
  122. }