github.com/xxf098/lite-proxy@v0.15.1-0.20230422081941-12c69f323218/outbound/shadowsocksr.go (about)

     1  package outbound
     2  
     3  import (
     4  	"context"
     5  	"encoding/json"
     6  	"fmt"
     7  	"net"
     8  	"strconv"
     9  
    10  	"github.com/Dreamacro/go-shadowsocks2/core"
    11  	"github.com/Dreamacro/go-shadowsocks2/shadowaead"
    12  	"github.com/Dreamacro/go-shadowsocks2/shadowstream"
    13  	C "github.com/xxf098/lite-proxy/constant"
    14  	"github.com/xxf098/lite-proxy/transport/dialer"
    15  	"github.com/xxf098/lite-proxy/transport/ssr/obfs"
    16  	"github.com/xxf098/lite-proxy/transport/ssr/protocol"
    17  )
    18  
    19  type ShadowSocksR struct {
    20  	*Base
    21  	cipher   core.Cipher
    22  	obfs     obfs.Obfs
    23  	protocol protocol.Protocol
    24  }
    25  
    26  type ShadowSocksROption struct {
    27  	Name          string `proxy:"name,omitempty"`
    28  	Server        string `proxy:"server"`
    29  	Port          int    `proxy:"port"`
    30  	Password      string `proxy:"password"`
    31  	Cipher        string `proxy:"cipher"`
    32  	Obfs          string `proxy:"obfs"`
    33  	ObfsParam     string `proxy:"obfs-param,omitempty"`
    34  	Protocol      string `proxy:"protocol"`
    35  	ProtocolParam string `proxy:"protocol-param,omitempty"`
    36  	UDP           bool   `proxy:"udp,omitempty"`
    37  	Remarks       string `proxy:"remarks,omitempty"`
    38  }
    39  
    40  func (ssr *ShadowSocksR) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) {
    41  	c = ssr.obfs.StreamConn(c)
    42  	c = ssr.cipher.StreamConn(c)
    43  	var (
    44  		iv  []byte
    45  		err error
    46  	)
    47  	switch conn := c.(type) {
    48  	case *shadowstream.Conn:
    49  		iv, err = conn.ObtainWriteIV()
    50  		if err != nil {
    51  			return nil, err
    52  		}
    53  	case *shadowaead.Conn:
    54  		return nil, fmt.Errorf("invalid connection type")
    55  	}
    56  	c = ssr.protocol.StreamConn(c, iv)
    57  	_, err = c.Write(serializesSocksAddr(metadata))
    58  	return c, err
    59  }
    60  
    61  func (ssr *ShadowSocksR) DialContext(ctx context.Context, metadata *C.Metadata) (net.Conn, error) {
    62  	c, err := dialer.DialContext(ctx, "tcp", ssr.addr)
    63  	if err != nil {
    64  		return nil, fmt.Errorf("%s connect error: %w", ssr.addr, err)
    65  	}
    66  	tcpKeepAlive(c)
    67  
    68  	return ssr.StreamConn(c, metadata)
    69  }
    70  
    71  func (ssr *ShadowSocksR) DialUDP(metadata *C.Metadata) (net.PacketConn, error) {
    72  	pc, err := dialer.ListenPacket("udp", "")
    73  	if err != nil {
    74  		return nil, err
    75  	}
    76  
    77  	addr, err := resolveUDPAddr("udp", ssr.addr)
    78  	if err != nil {
    79  		return nil, err
    80  	}
    81  
    82  	pc = ssr.cipher.PacketConn(pc)
    83  	pc = ssr.protocol.PacketConn(pc)
    84  	return &ssPacketConn{PacketConn: pc, rAddr: addr}, nil
    85  }
    86  
    87  func (ssr *ShadowSocksR) MarshalJSON() ([]byte, error) {
    88  	return json.Marshal(map[string]string{
    89  		"type": "shadowsocksr",
    90  	})
    91  }
    92  
    93  func NewShadowSocksR(option *ShadowSocksROption) (*ShadowSocksR, error) {
    94  	addr := net.JoinHostPort(option.Server, strconv.Itoa(option.Port))
    95  	if option.Cipher == "none" {
    96  		option.Cipher = "dummy"
    97  	}
    98  	cipher := option.Cipher
    99  	password := option.Password
   100  	coreCiph, err := core.PickCipher(cipher, nil, password)
   101  	if err != nil {
   102  		return nil, fmt.Errorf("ssr %s initialize error: %w", addr, err)
   103  	}
   104  	var (
   105  		ivSize int
   106  		key    []byte
   107  	)
   108  	if option.Cipher == "dummy" {
   109  		ivSize = 0
   110  		key = core.Kdf(option.Password, 16)
   111  	} else {
   112  		ciph, ok := coreCiph.(*core.StreamCipher)
   113  		if !ok {
   114  			return nil, fmt.Errorf("%s is not dummy or a supported stream cipher in ssr", cipher)
   115  		}
   116  		ivSize = ciph.IVSize()
   117  		key = ciph.Key
   118  	}
   119  
   120  	obfs, obfsOverhead, err := obfs.PickObfs(option.Obfs, &obfs.Base{
   121  		Host:   option.Server,
   122  		Port:   option.Port,
   123  		Key:    key,
   124  		IVSize: ivSize,
   125  		Param:  option.ObfsParam,
   126  	})
   127  	if err != nil {
   128  		return nil, fmt.Errorf("ssr %s initialize obfs error: %w", addr, err)
   129  	}
   130  
   131  	protocol, err := protocol.PickProtocol(option.Protocol, &protocol.Base{
   132  		Key:      key,
   133  		Overhead: obfsOverhead,
   134  		Param:    option.ProtocolParam,
   135  	})
   136  	if err != nil {
   137  		return nil, fmt.Errorf("ssr %s initialize protocol error: %w", addr, err)
   138  	}
   139  
   140  	return &ShadowSocksR{
   141  		Base: &Base{
   142  			name: option.Name,
   143  			addr: addr,
   144  			udp:  option.UDP,
   145  		},
   146  		cipher:   coreCiph,
   147  		obfs:     obfs,
   148  		protocol: protocol,
   149  	}, nil
   150  }