github.com/xraypb/xray-core@v1.6.6/infra/conf/shadowsocks.go (about)

     1  package conf
     2  
     3  import (
     4  	"strings"
     5  
     6  	"github.com/golang/protobuf/proto"
     7  	"github.com/sagernet/sing-shadowsocks/shadowaead_2022"
     8  	C "github.com/sagernet/sing/common"
     9  	"github.com/xraypb/xray-core/common/protocol"
    10  	"github.com/xraypb/xray-core/common/serial"
    11  	"github.com/xraypb/xray-core/proxy/shadowsocks"
    12  	"github.com/xraypb/xray-core/proxy/shadowsocks_2022"
    13  )
    14  
    15  func cipherFromString(c string) shadowsocks.CipherType {
    16  	switch strings.ToLower(c) {
    17  	case "aes-128-gcm", "aead_aes_128_gcm":
    18  		return shadowsocks.CipherType_AES_128_GCM
    19  	case "aes-256-gcm", "aead_aes_256_gcm":
    20  		return shadowsocks.CipherType_AES_256_GCM
    21  	case "chacha20-poly1305", "aead_chacha20_poly1305", "chacha20-ietf-poly1305":
    22  		return shadowsocks.CipherType_CHACHA20_POLY1305
    23  	case "xchacha20-poly1305", "aead_xchacha20_poly1305", "xchacha20-ietf-poly1305":
    24  		return shadowsocks.CipherType_XCHACHA20_POLY1305
    25  	case "none", "plain":
    26  		return shadowsocks.CipherType_NONE
    27  	default:
    28  		return shadowsocks.CipherType_UNKNOWN
    29  	}
    30  }
    31  
    32  type ShadowsocksUserConfig struct {
    33  	Cipher   string   `json:"method"`
    34  	Password string   `json:"password"`
    35  	Level    byte     `json:"level"`
    36  	Email    string   `json:"email"`
    37  	Address  *Address `json:"address"`
    38  	Port     uint16   `json:"port"`
    39  }
    40  
    41  type ShadowsocksServerConfig struct {
    42  	Cipher      string                   `json:"method"`
    43  	Password    string                   `json:"password"`
    44  	Level       byte                     `json:"level"`
    45  	Email       string                   `json:"email"`
    46  	Users       []*ShadowsocksUserConfig `json:"clients"`
    47  	NetworkList *NetworkList             `json:"network"`
    48  	IVCheck     bool                     `json:"ivCheck"`
    49  }
    50  
    51  func (v *ShadowsocksServerConfig) Build() (proto.Message, error) {
    52  	if C.Contains(shadowaead_2022.List, v.Cipher) {
    53  		return buildShadowsocks2022(v)
    54  	}
    55  
    56  	config := new(shadowsocks.ServerConfig)
    57  	config.Network = v.NetworkList.Build()
    58  
    59  	if v.Users != nil {
    60  		for _, user := range v.Users {
    61  			account := &shadowsocks.Account{
    62  				Password:   user.Password,
    63  				CipherType: cipherFromString(user.Cipher),
    64  				IvCheck:    v.IVCheck,
    65  			}
    66  			if account.Password == "" {
    67  				return nil, newError("Shadowsocks password is not specified.")
    68  			}
    69  			if account.CipherType < shadowsocks.CipherType_AES_128_GCM ||
    70  				account.CipherType > shadowsocks.CipherType_XCHACHA20_POLY1305 {
    71  				return nil, newError("unsupported cipher method: ", user.Cipher)
    72  			}
    73  			config.Users = append(config.Users, &protocol.User{
    74  				Email:   user.Email,
    75  				Level:   uint32(user.Level),
    76  				Account: serial.ToTypedMessage(account),
    77  			})
    78  		}
    79  	} else {
    80  		account := &shadowsocks.Account{
    81  			Password:   v.Password,
    82  			CipherType: cipherFromString(v.Cipher),
    83  			IvCheck:    v.IVCheck,
    84  		}
    85  		if account.Password == "" {
    86  			return nil, newError("Shadowsocks password is not specified.")
    87  		}
    88  		if account.CipherType == shadowsocks.CipherType_UNKNOWN {
    89  			return nil, newError("unknown cipher method: ", v.Cipher)
    90  		}
    91  		config.Users = append(config.Users, &protocol.User{
    92  			Email:   v.Email,
    93  			Level:   uint32(v.Level),
    94  			Account: serial.ToTypedMessage(account),
    95  		})
    96  	}
    97  
    98  	return config, nil
    99  }
   100  
   101  func buildShadowsocks2022(v *ShadowsocksServerConfig) (proto.Message, error) {
   102  	if len(v.Users) == 0 {
   103  		config := new(shadowsocks_2022.ServerConfig)
   104  		config.Method = v.Cipher
   105  		config.Key = v.Password
   106  		config.Network = v.NetworkList.Build()
   107  		config.Email = v.Email
   108  		return config, nil
   109  	}
   110  
   111  	if v.Cipher == "" {
   112  		return nil, newError("shadowsocks 2022 (multi-user): missing server method")
   113  	}
   114  	if !strings.Contains(v.Cipher, "aes") {
   115  		return nil, newError("shadowsocks 2022 (multi-user): only blake3-aes-*-gcm methods are supported")
   116  	}
   117  
   118  	if v.Users[0].Address == nil {
   119  		config := new(shadowsocks_2022.MultiUserServerConfig)
   120  		config.Method = v.Cipher
   121  		config.Key = v.Password
   122  		config.Network = v.NetworkList.Build()
   123  
   124  		for _, user := range v.Users {
   125  			if user.Cipher != "" {
   126  				return nil, newError("shadowsocks 2022 (multi-user): users must have empty method")
   127  			}
   128  			config.Users = append(config.Users, &shadowsocks_2022.User{
   129  				Key:   user.Password,
   130  				Email: user.Email,
   131  			})
   132  		}
   133  		return config, nil
   134  	}
   135  
   136  	config := new(shadowsocks_2022.RelayServerConfig)
   137  	config.Method = v.Cipher
   138  	config.Key = v.Password
   139  	config.Network = v.NetworkList.Build()
   140  	for _, user := range v.Users {
   141  		if user.Cipher != "" {
   142  			return nil, newError("shadowsocks 2022 (relay): users must have empty method")
   143  		}
   144  		if user.Address == nil {
   145  			return nil, newError("shadowsocks 2022 (relay): all users must have relay address")
   146  		}
   147  		config.Destinations = append(config.Destinations, &shadowsocks_2022.RelayDestination{
   148  			Key:     user.Password,
   149  			Email:   user.Email,
   150  			Address: user.Address.Build(),
   151  			Port:    uint32(user.Port),
   152  		})
   153  	}
   154  	return config, nil
   155  }
   156  
   157  type ShadowsocksServerTarget struct {
   158  	Address  *Address `json:"address"`
   159  	Port     uint16   `json:"port"`
   160  	Cipher   string   `json:"method"`
   161  	Password string   `json:"password"`
   162  	Email    string   `json:"email"`
   163  	Level    byte     `json:"level"`
   164  	IVCheck  bool     `json:"ivCheck"`
   165  	UoT      bool     `json:"uot"`
   166  }
   167  
   168  type ShadowsocksClientConfig struct {
   169  	Servers []*ShadowsocksServerTarget `json:"servers"`
   170  }
   171  
   172  func (v *ShadowsocksClientConfig) Build() (proto.Message, error) {
   173  	if len(v.Servers) == 0 {
   174  		return nil, newError("0 Shadowsocks server configured.")
   175  	}
   176  
   177  	if len(v.Servers) == 1 {
   178  		server := v.Servers[0]
   179  		if C.Contains(shadowaead_2022.List, server.Cipher) {
   180  			if server.Address == nil {
   181  				return nil, newError("Shadowsocks server address is not set.")
   182  			}
   183  			if server.Port == 0 {
   184  				return nil, newError("Invalid Shadowsocks port.")
   185  			}
   186  			if server.Password == "" {
   187  				return nil, newError("Shadowsocks password is not specified.")
   188  			}
   189  
   190  			config := new(shadowsocks_2022.ClientConfig)
   191  			config.Address = server.Address.Build()
   192  			config.Port = uint32(server.Port)
   193  			config.Method = server.Cipher
   194  			config.Key = server.Password
   195  			config.UdpOverTcp = server.UoT
   196  			return config, nil
   197  		}
   198  	}
   199  
   200  	config := new(shadowsocks.ClientConfig)
   201  	serverSpecs := make([]*protocol.ServerEndpoint, len(v.Servers))
   202  	for idx, server := range v.Servers {
   203  		if C.Contains(shadowaead_2022.List, server.Cipher) {
   204  			return nil, newError("Shadowsocks 2022 accept no multi servers")
   205  		}
   206  		if server.Address == nil {
   207  			return nil, newError("Shadowsocks server address is not set.")
   208  		}
   209  		if server.Port == 0 {
   210  			return nil, newError("Invalid Shadowsocks port.")
   211  		}
   212  		if server.Password == "" {
   213  			return nil, newError("Shadowsocks password is not specified.")
   214  		}
   215  		account := &shadowsocks.Account{
   216  			Password: server.Password,
   217  		}
   218  		account.CipherType = cipherFromString(server.Cipher)
   219  		if account.CipherType == shadowsocks.CipherType_UNKNOWN {
   220  			return nil, newError("unknown cipher method: ", server.Cipher)
   221  		}
   222  
   223  		account.IvCheck = server.IVCheck
   224  
   225  		ss := &protocol.ServerEndpoint{
   226  			Address: server.Address.Build(),
   227  			Port:    uint32(server.Port),
   228  			User: []*protocol.User{
   229  				{
   230  					Level:   uint32(server.Level),
   231  					Email:   server.Email,
   232  					Account: serial.ToTypedMessage(account),
   233  				},
   234  			},
   235  		}
   236  
   237  		serverSpecs[idx] = ss
   238  	}
   239  
   240  	config.Server = serverSpecs
   241  
   242  	return config, nil
   243  }