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