github.com/database64128/shadowsocks-go@v1.7.0/service/client.go (about)

     1  package service
     2  
     3  import (
     4  	"fmt"
     5  	"net/netip"
     6  
     7  	"github.com/database64128/shadowsocks-go/conn"
     8  	"github.com/database64128/shadowsocks-go/direct"
     9  	"github.com/database64128/shadowsocks-go/http"
    10  	"github.com/database64128/shadowsocks-go/ss2022"
    11  	"github.com/database64128/shadowsocks-go/zerocopy"
    12  	"go.uber.org/zap"
    13  )
    14  
    15  // ClientConfig stores a client configuration.
    16  // It may be marshaled as or unmarshaled from JSON.
    17  type ClientConfig struct {
    18  	Name               string    `json:"name"`
    19  	Endpoint           conn.Addr `json:"endpoint"`
    20  	Protocol           string    `json:"protocol"`
    21  	DialerFwmark       int       `json:"dialerFwmark"`
    22  	DialerTrafficClass int       `json:"dialerTrafficClass"`
    23  
    24  	// TCP
    25  	EnableTCP bool `json:"enableTCP"`
    26  	DialerTFO bool `json:"dialerTFO"`
    27  
    28  	// UDP
    29  	EnableUDP bool `json:"enableUDP"`
    30  	MTU       int  `json:"mtu"`
    31  
    32  	// Shadowsocks
    33  	PSK           []byte   `json:"psk"`
    34  	IPSKs         [][]byte `json:"iPSKs"`
    35  	PaddingPolicy string   `json:"paddingPolicy"`
    36  	cipherConfig  *ss2022.ClientCipherConfig
    37  
    38  	// Taint
    39  	UnsafeRequestStreamPrefix  []byte `json:"unsafeRequestStreamPrefix"`
    40  	UnsafeResponseStreamPrefix []byte `json:"unsafeResponseStreamPrefix"`
    41  
    42  	listenConfigCache conn.ListenConfigCache
    43  	dialerCache       conn.DialerCache
    44  	logger            *zap.Logger
    45  }
    46  
    47  // Initialize initializes the client configuration.
    48  func (cc *ClientConfig) Initialize(listenConfigCache conn.ListenConfigCache, dialerCache conn.DialerCache, logger *zap.Logger) error {
    49  	switch cc.Protocol {
    50  	case "2022-blake3-aes-128-gcm", "2022-blake3-aes-256-gcm":
    51  		err := ss2022.CheckPSKLength(cc.Protocol, cc.PSK, cc.IPSKs)
    52  		if err != nil {
    53  			return err
    54  		}
    55  		cc.cipherConfig, err = ss2022.NewClientCipherConfig(cc.PSK, cc.IPSKs, cc.EnableUDP)
    56  		if err != nil {
    57  			return err
    58  		}
    59  	}
    60  	cc.listenConfigCache = listenConfigCache
    61  	cc.dialerCache = dialerCache
    62  	cc.logger = logger
    63  	return nil
    64  }
    65  
    66  // TCPClient creates a zerocopy.TCPClient from the ClientConfig.
    67  func (cc *ClientConfig) TCPClient() (zerocopy.TCPClient, error) {
    68  	if !cc.EnableTCP {
    69  		return nil, errNetworkDisabled
    70  	}
    71  
    72  	dialer := cc.dialerCache.Get(conn.DialerSocketOptions{
    73  		Fwmark:       cc.DialerFwmark,
    74  		TrafficClass: cc.DialerTrafficClass,
    75  		TCPFastOpen:  cc.DialerTFO,
    76  	})
    77  
    78  	switch cc.Protocol {
    79  	case "direct":
    80  		return direct.NewTCPClient(cc.Name, dialer), nil
    81  	case "none", "plain":
    82  		return direct.NewShadowsocksNoneTCPClient(cc.Name, cc.Endpoint.String(), dialer), nil
    83  	case "socks5":
    84  		return direct.NewSocks5TCPClient(cc.Name, cc.Endpoint.String(), dialer), nil
    85  	case "http":
    86  		return http.NewProxyClient(cc.Name, cc.Endpoint.String(), dialer), nil
    87  	case "2022-blake3-aes-128-gcm", "2022-blake3-aes-256-gcm":
    88  		if len(cc.UnsafeRequestStreamPrefix) != 0 || len(cc.UnsafeResponseStreamPrefix) != 0 {
    89  			cc.logger.Warn("Unsafe stream prefix taints the client", zap.String("client", cc.Name))
    90  		}
    91  		return ss2022.NewTCPClient(cc.Name, cc.Endpoint.String(), dialer, cc.cipherConfig, cc.UnsafeRequestStreamPrefix, cc.UnsafeResponseStreamPrefix), nil
    92  	default:
    93  		return nil, fmt.Errorf("unknown protocol: %s", cc.Protocol)
    94  	}
    95  }
    96  
    97  func (cc *ClientConfig) UDPClient() (zerocopy.UDPClient, error) {
    98  	if !cc.EnableUDP {
    99  		return nil, errNetworkDisabled
   100  	}
   101  
   102  	if cc.MTU < minimumMTU {
   103  		return nil, ErrMTUTooSmall
   104  	}
   105  
   106  	var (
   107  		endpointAddrPort netip.AddrPort
   108  		err              error
   109  	)
   110  
   111  	// Resolve endpoint address for some protocols.
   112  	switch cc.Protocol {
   113  	case "none", "plain", "socks5", "2022-blake3-aes-128-gcm", "2022-blake3-aes-256-gcm":
   114  		endpointAddrPort, err = cc.Endpoint.ResolveIPPort()
   115  		if err != nil {
   116  			return nil, err
   117  		}
   118  	}
   119  
   120  	listenConfig := cc.listenConfigCache.Get(conn.ListenerSocketOptions{
   121  		Fwmark:           cc.DialerFwmark,
   122  		TrafficClass:     cc.DialerTrafficClass,
   123  		PathMTUDiscovery: true,
   124  	})
   125  
   126  	switch cc.Protocol {
   127  	case "direct":
   128  		return direct.NewUDPClient(cc.Name, cc.MTU, listenConfig), nil
   129  	case "none", "plain":
   130  		return direct.NewShadowsocksNoneUDPClient(endpointAddrPort, cc.Name, cc.MTU, listenConfig), nil
   131  	case "socks5":
   132  		return direct.NewSocks5UDPClient(endpointAddrPort, cc.Name, cc.MTU, listenConfig), nil
   133  	case "2022-blake3-aes-128-gcm", "2022-blake3-aes-256-gcm":
   134  		shouldPad, err := ss2022.ParsePaddingPolicy(cc.PaddingPolicy)
   135  		if err != nil {
   136  			return nil, err
   137  		}
   138  		return ss2022.NewUDPClient(endpointAddrPort, cc.Name, cc.MTU, listenConfig, cc.cipherConfig, shouldPad), nil
   139  	default:
   140  		return nil, fmt.Errorf("unknown protocol: %s", cc.Protocol)
   141  	}
   142  }