shadowsocks.go 2.9 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394
  1. package outbound
  2. import (
  3. "context"
  4. "net"
  5. "github.com/sagernet/sing-box/adapter"
  6. "github.com/sagernet/sing-box/config"
  7. C "github.com/sagernet/sing-box/constant"
  8. "github.com/sagernet/sing-box/log"
  9. "github.com/sagernet/sing-shadowsocks"
  10. "github.com/sagernet/sing-shadowsocks/shadowimpl"
  11. "github.com/sagernet/sing/common/bufio"
  12. E "github.com/sagernet/sing/common/exceptions"
  13. M "github.com/sagernet/sing/common/metadata"
  14. N "github.com/sagernet/sing/common/network"
  15. )
  16. var _ adapter.Outbound = (*Shadowsocks)(nil)
  17. type Shadowsocks struct {
  18. myOutboundAdapter
  19. method shadowsocks.Method
  20. serverAddr M.Socksaddr
  21. }
  22. func NewShadowsocks(router adapter.Router, logger log.Logger, tag string, options *config.ShadowsocksOutboundOptions) (*Shadowsocks, error) {
  23. outbound := &Shadowsocks{
  24. myOutboundAdapter: myOutboundAdapter{
  25. protocol: C.TypeDirect,
  26. logger: logger,
  27. tag: tag,
  28. dialer: NewDialer(router, options.DialerOptions),
  29. },
  30. }
  31. var err error
  32. outbound.method, err = shadowimpl.FetchMethod(options.Method, options.Password)
  33. if err != nil {
  34. return nil, err
  35. }
  36. if options.Server == "" {
  37. return nil, E.New("missing server address")
  38. } else if options.ServerPort == 0 {
  39. return nil, E.New("missing server port")
  40. }
  41. outbound.serverAddr = M.ParseSocksaddrHostPort(options.Server, options.ServerPort)
  42. return outbound, nil
  43. }
  44. func (o *Shadowsocks) NewConnection(ctx context.Context, conn net.Conn, destination M.Socksaddr) error {
  45. serverConn, err := o.DialContext(ctx, "tcp", destination)
  46. if err != nil {
  47. return err
  48. }
  49. return CopyEarlyConn(ctx, conn, serverConn)
  50. }
  51. func (o *Shadowsocks) NewPacketConnection(ctx context.Context, conn N.PacketConn, destination M.Socksaddr) error {
  52. serverConn, err := o.ListenPacket(ctx)
  53. if err != nil {
  54. return err
  55. }
  56. return bufio.CopyPacketConn(ctx, conn, bufio.NewPacketConn(serverConn))
  57. }
  58. func (o *Shadowsocks) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
  59. switch network {
  60. case C.NetworkTCP:
  61. o.logger.WithContext(ctx).Debug("outbound connection to ", destination)
  62. outConn, err := o.dialer.DialContext(ctx, "tcp", o.serverAddr)
  63. if err != nil {
  64. return nil, err
  65. }
  66. return o.method.DialEarlyConn(outConn, destination), nil
  67. case C.NetworkUDP:
  68. o.logger.WithContext(ctx).Debug("outbound packet connection to ", destination)
  69. outConn, err := o.dialer.DialContext(ctx, "udp", o.serverAddr)
  70. if err != nil {
  71. return nil, err
  72. }
  73. return &bufio.BindPacketConn{PacketConn: o.method.DialPacketConn(outConn), Addr: destination}, nil
  74. default:
  75. panic("unknown network " + network)
  76. }
  77. }
  78. func (o *Shadowsocks) ListenPacket(ctx context.Context) (net.PacketConn, error) {
  79. o.logger.WithContext(ctx).Debug("outbound packet connection to ", o.serverAddr)
  80. outConn, err := o.dialer.ListenPacket(ctx)
  81. if err != nil {
  82. return nil, err
  83. }
  84. return o.method.DialPacketConn(&bufio.BindPacketConn{PacketConn: outConn, Addr: o.serverAddr.UDPAddr()}), nil
  85. }