github.com/inazumav/sing-box@v0.0.0-20230926072359-ab51429a14f1/outbound/shadowsocksr.go (about)

     1  //go:build with_shadowsocksr
     2  
     3  package outbound
     4  
     5  import (
     6  	"context"
     7  	"errors"
     8  	"fmt"
     9  	"net"
    10  
    11  	"github.com/inazumav/sing-box/adapter"
    12  	"github.com/inazumav/sing-box/common/dialer"
    13  	C "github.com/inazumav/sing-box/constant"
    14  	"github.com/inazumav/sing-box/log"
    15  	"github.com/inazumav/sing-box/option"
    16  	"github.com/inazumav/sing-box/transport/clashssr/obfs"
    17  	"github.com/inazumav/sing-box/transport/clashssr/protocol"
    18  	"github.com/sagernet/sing/common/bufio"
    19  	E "github.com/sagernet/sing/common/exceptions"
    20  	M "github.com/sagernet/sing/common/metadata"
    21  	N "github.com/sagernet/sing/common/network"
    22  
    23  	"github.com/Dreamacro/clash/transport/shadowsocks/core"
    24  	"github.com/Dreamacro/clash/transport/shadowsocks/shadowstream"
    25  	"github.com/Dreamacro/clash/transport/socks5"
    26  )
    27  
    28  var _ adapter.Outbound = (*ShadowsocksR)(nil)
    29  
    30  type ShadowsocksR struct {
    31  	myOutboundAdapter
    32  	dialer     N.Dialer
    33  	serverAddr M.Socksaddr
    34  	cipher     core.Cipher
    35  	obfs       obfs.Obfs
    36  	protocol   protocol.Protocol
    37  }
    38  
    39  func NewShadowsocksR(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.ShadowsocksROutboundOptions) (*ShadowsocksR, error) {
    40  	outboundDialer, err := dialer.New(router, options.DialerOptions)
    41  	if err != nil {
    42  		return nil, err
    43  	}
    44  	outbound := &ShadowsocksR{
    45  		myOutboundAdapter: myOutboundAdapter{
    46  			protocol:     C.TypeShadowsocksR,
    47  			network:      options.Network.Build(),
    48  			router:       router,
    49  			logger:       logger,
    50  			tag:          tag,
    51  			dependencies: withDialerDependency(options.DialerOptions),
    52  		},
    53  		dialer:     outboundDialer,
    54  		serverAddr: options.ServerOptions.Build(),
    55  	}
    56  	var cipher string
    57  	switch options.Method {
    58  	case "none":
    59  		cipher = "dummy"
    60  	default:
    61  		cipher = options.Method
    62  	}
    63  	outbound.cipher, err = core.PickCipher(cipher, nil, options.Password)
    64  	if err != nil {
    65  		return nil, err
    66  	}
    67  	var (
    68  		ivSize int
    69  		key    []byte
    70  	)
    71  	if cipher == "dummy" {
    72  		ivSize = 0
    73  		key = core.Kdf(options.Password, 16)
    74  	} else {
    75  		streamCipher, ok := outbound.cipher.(*core.StreamCipher)
    76  		if !ok {
    77  			return nil, fmt.Errorf("%s is not none or a supported stream cipher in ssr", cipher)
    78  		}
    79  		ivSize = streamCipher.IVSize()
    80  		key = streamCipher.Key
    81  	}
    82  	obfs, obfsOverhead, err := obfs.PickObfs(options.Obfs, &obfs.Base{
    83  		Host:   options.Server,
    84  		Port:   int(options.ServerPort),
    85  		Key:    key,
    86  		IVSize: ivSize,
    87  		Param:  options.ObfsParam,
    88  	})
    89  	if err != nil {
    90  		return nil, E.Cause(err, "initialize obfs")
    91  	}
    92  	protocol, err := protocol.PickProtocol(options.Protocol, &protocol.Base{
    93  		Key:      key,
    94  		Overhead: obfsOverhead,
    95  		Param:    options.ProtocolParam,
    96  	})
    97  	if err != nil {
    98  		return nil, E.Cause(err, "initialize protocol")
    99  	}
   100  	outbound.obfs = obfs
   101  	outbound.protocol = protocol
   102  	return outbound, nil
   103  }
   104  
   105  func (h *ShadowsocksR) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
   106  	ctx, metadata := adapter.AppendContext(ctx)
   107  	metadata.Outbound = h.tag
   108  	metadata.Destination = destination
   109  	switch network {
   110  	case N.NetworkTCP:
   111  		h.logger.InfoContext(ctx, "outbound connection to ", destination)
   112  		conn, err := h.dialer.DialContext(ctx, network, h.serverAddr)
   113  		if err != nil {
   114  			return nil, err
   115  		}
   116  		conn = h.cipher.StreamConn(h.obfs.StreamConn(conn))
   117  		writeIv, err := conn.(*shadowstream.Conn).ObtainWriteIV()
   118  		if err != nil {
   119  			conn.Close()
   120  			return nil, err
   121  		}
   122  		conn = h.protocol.StreamConn(conn, writeIv)
   123  		err = M.SocksaddrSerializer.WriteAddrPort(conn, destination)
   124  		if err != nil {
   125  			conn.Close()
   126  			return nil, E.Cause(err, "write request")
   127  		}
   128  		return conn, nil
   129  	case N.NetworkUDP:
   130  		conn, err := h.ListenPacket(ctx, destination)
   131  		if err != nil {
   132  			return nil, err
   133  		}
   134  		return bufio.NewBindPacketConn(conn, destination), nil
   135  	default:
   136  		return nil, E.Extend(N.ErrUnknownNetwork, network)
   137  	}
   138  }
   139  
   140  func (h *ShadowsocksR) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) {
   141  	ctx, metadata := adapter.AppendContext(ctx)
   142  	metadata.Outbound = h.tag
   143  	metadata.Destination = destination
   144  	h.logger.InfoContext(ctx, "outbound packet connection to ", destination)
   145  	outConn, err := h.dialer.DialContext(ctx, N.NetworkUDP, h.serverAddr)
   146  	if err != nil {
   147  		return nil, err
   148  	}
   149  	packetConn := h.cipher.PacketConn(bufio.NewUnbindPacketConn(outConn))
   150  	packetConn = h.protocol.PacketConn(packetConn)
   151  	packetConn = &ssPacketConn{packetConn, outConn.RemoteAddr()}
   152  	return packetConn, nil
   153  }
   154  
   155  func (h *ShadowsocksR) NewConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext) error {
   156  	return NewConnection(ctx, h, conn, metadata)
   157  }
   158  
   159  func (h *ShadowsocksR) NewPacketConnection(ctx context.Context, conn N.PacketConn, metadata adapter.InboundContext) error {
   160  	return NewPacketConnection(ctx, h, conn, metadata)
   161  }
   162  
   163  type ssPacketConn struct {
   164  	net.PacketConn
   165  	rAddr net.Addr
   166  }
   167  
   168  func (spc *ssPacketConn) WriteTo(b []byte, addr net.Addr) (n int, err error) {
   169  	packet, err := socks5.EncodeUDPPacket(socks5.ParseAddrToSocksAddr(addr), b)
   170  	if err != nil {
   171  		return
   172  	}
   173  	return spc.PacketConn.WriteTo(packet[3:], spc.rAddr)
   174  }
   175  
   176  func (spc *ssPacketConn) ReadFrom(b []byte) (int, net.Addr, error) {
   177  	n, _, e := spc.PacketConn.ReadFrom(b)
   178  	if e != nil {
   179  		return 0, nil, e
   180  	}
   181  
   182  	addr := socks5.SplitAddr(b[:n])
   183  	if addr == nil {
   184  		return 0, nil, errors.New("parse addr error")
   185  	}
   186  
   187  	udpAddr := addr.UDPAddr()
   188  	if udpAddr == nil {
   189  		return 0, nil, errors.New("parse addr error")
   190  	}
   191  
   192  	copy(b, b[len(addr):])
   193  	return n - len(addr), udpAddr, e
   194  }