2020-11-25 19:01:53 +08:00
package conf
import (
"strings"
2024-06-29 14:32:57 -04:00
"github.com/xtls/xray-core/common/errors"
2020-12-04 09:36:16 +08:00
"github.com/xtls/xray-core/common/protocol"
"github.com/xtls/xray-core/common/serial"
2026-05-02 16:32:59 +03:00
"github.com/xtls/xray-core/common/task"
2020-12-04 09:36:16 +08:00
"github.com/xtls/xray-core/proxy/shadowsocks"
2022-05-23 20:45:30 +08:00
"github.com/xtls/xray-core/proxy/shadowsocks_2022"
2023-08-10 04:43:34 +00:00
"google.golang.org/protobuf/proto"
2020-11-25 19:01:53 +08:00
)
func cipherFromString ( c string ) shadowsocks . CipherType {
switch strings . ToLower ( c ) {
case "aes-128-gcm" , "aead_aes_128_gcm" :
return shadowsocks . CipherType_AES_128_GCM
case "aes-256-gcm" , "aead_aes_256_gcm" :
return shadowsocks . CipherType_AES_256_GCM
case "chacha20-poly1305" , "aead_chacha20_poly1305" , "chacha20-ietf-poly1305" :
return shadowsocks . CipherType_CHACHA20_POLY1305
2021-05-25 23:45:48 +08:00
case "xchacha20-poly1305" , "aead_xchacha20_poly1305" , "xchacha20-ietf-poly1305" :
return shadowsocks . CipherType_XCHACHA20_POLY1305
2020-11-25 19:01:53 +08:00
default :
return shadowsocks . CipherType_UNKNOWN
}
}
2021-01-18 22:52:35 +00:00
type ShadowsocksUserConfig struct {
2022-08-07 19:18:23 -04:00
Cipher string `json:"method"`
Password string `json:"password"`
Level byte `json:"level"`
Email string `json:"email"`
Address * Address `json:"address"`
Port uint16 `json:"port"`
2021-01-18 22:52:35 +00:00
}
2020-11-25 19:01:53 +08:00
type ShadowsocksServerConfig struct {
2021-01-18 22:52:35 +00:00
Cipher string `json:"method"`
Password string `json:"password"`
Level byte `json:"level"`
Email string `json:"email"`
2026-05-07 19:10:48 +08:00
Users [] * ShadowsocksUserConfig `json:"users"`
Clients [] * ShadowsocksUserConfig `json:"clients"`
2021-01-18 22:52:35 +00:00
NetworkList * NetworkList `json:"network"`
2020-11-25 19:01:53 +08:00
}
func ( v * ShadowsocksServerConfig ) Build () ( proto . Message , error ) {
2026-01-23 23:45:20 +08:00
errors . PrintNonRemovalDeprecatedFeatureWarning ( "Shadowsocks (with no Forward Secrecy, etc.)" , "VLESS Encryption" )
2026-01-18 04:17:25 +00:00
2026-05-07 19:10:48 +08:00
if v . Clients != nil {
v . Users = v . Clients
}
2026-09-28 02:42:53 +08:00
if _ , err := shadowsocks_2022 . GetCipherMethod ( v . Cipher ); err == nil {
2022-08-07 19:18:23 -04:00
return buildShadowsocks2022 ( v )
2022-05-23 20:45:30 +08:00
}
2020-11-25 19:01:53 +08:00
config := new ( shadowsocks . ServerConfig )
config . Network = v . NetworkList . Build ()
2021-01-18 22:52:35 +00:00
if v . Users != nil {
2026-05-02 16:32:59 +03:00
if len ( v . Users ) > 0 {
config . Users = make ([] * protocol . User , len ( v . Users ))
processUser := func ( idx int ) error {
user := v . Users [ idx ]
account := & shadowsocks . Account {
Password : user . Password ,
CipherType : cipherFromString ( user . Cipher ),
}
if account . Password == "" {
return errors . New ( "Shadowsocks password is not specified." )
}
if account . CipherType < shadowsocks . CipherType_AES_128_GCM ||
account . CipherType > shadowsocks . CipherType_XCHACHA20_POLY1305 {
return errors . New ( "unsupported cipher method: " , user . Cipher )
}
config . Users [ idx ] = & protocol . User {
Email : user . Email ,
Level : uint32 ( user . Level ),
Account : serial . ToTypedMessage ( account ),
}
return nil
2021-01-18 22:52:35 +00:00
}
2026-05-02 16:32:59 +03:00
if err := task . ParallelForN ( len ( v . Users ), processUser ); err != nil {
return nil , err
2021-01-18 22:52:35 +00:00
}
}
} else {
account := & shadowsocks . Account {
Password : v . Password ,
CipherType : cipherFromString ( v . Cipher ),
}
if account . Password == "" {
2024-06-29 14:32:57 -04:00
return nil , errors . New ( "Shadowsocks password is not specified." )
2021-01-18 22:52:35 +00:00
}
if account . CipherType == shadowsocks . CipherType_UNKNOWN {
2024-06-29 14:32:57 -04:00
return nil , errors . New ( "unknown cipher method: " , v . Cipher )
2021-01-18 22:52:35 +00:00
}
config . Users = append ( config . Users , & protocol . User {
Email : v . Email ,
Level : uint32 ( v . Level ),
Account : serial . ToTypedMessage ( account ),
})
2020-11-25 19:01:53 +08:00
}
return config , nil
}
2022-08-07 19:18:23 -04:00
func buildShadowsocks2022 ( v * ShadowsocksServerConfig ) ( proto . Message , error ) {
2026-09-28 02:42:53 +08:00
v . Cipher = strings . ToLower ( v . Cipher )
2022-08-07 19:18:23 -04:00
if len ( v . Users ) == 0 {
config := new ( shadowsocks_2022 . ServerConfig )
config . Method = v . Cipher
config . Key = v . Password
config . Network = v . NetworkList . Build ()
config . Email = v . Email
2026-09-28 02:42:53 +08:00
config . Level = int32 ( v . Level )
2022-08-07 19:18:23 -04:00
return config , nil
}
2022-12-25 19:37:35 -05:00
2022-08-07 19:18:23 -04:00
if v . Cipher == "" {
2024-06-29 14:32:57 -04:00
return nil , errors . New ( "shadowsocks 2022 (multi-user): missing server method" )
2022-08-07 19:18:23 -04:00
}
if ! strings . Contains ( v . Cipher , "aes" ) {
2024-06-29 14:32:57 -04:00
return nil , errors . New ( "shadowsocks 2022 (multi-user): only blake3-aes-*-gcm methods are supported" )
2022-08-07 19:18:23 -04:00
}
if v . Users [ 0 ]. Address == nil {
config := new ( shadowsocks_2022 . MultiUserServerConfig )
config . Method = v . Cipher
config . Key = v . Password
config . Network = v . NetworkList . Build ()
2022-12-25 19:37:35 -05:00
2026-05-02 16:32:59 +03:00
config . Users = make ([] * protocol . User , len ( v . Users ))
processUser := func ( idx int ) error {
user := v . Users [ idx ]
2022-08-07 19:18:23 -04:00
if user . Cipher != "" {
2026-05-02 16:32:59 +03:00
return errors . New ( "shadowsocks 2022 (multi-user): users must have empty method" )
2022-08-07 19:18:23 -04:00
}
2024-11-03 00:25:23 -04:00
account := & shadowsocks_2022 . Account {
Key : user . Password ,
}
2026-05-02 16:32:59 +03:00
config . Users [ idx ] = & protocol . User {
2024-11-03 00:25:23 -04:00
Email : user . Email ,
Level : uint32 ( user . Level ),
Account : serial . ToTypedMessage ( account ),
2026-05-02 16:32:59 +03:00
}
return nil
}
if err := task . ParallelForN ( len ( v . Users ), processUser ); err != nil {
return nil , err
2022-08-07 19:18:23 -04:00
}
return config , nil
}
config := new ( shadowsocks_2022 . RelayServerConfig )
config . Method = v . Cipher
config . Key = v . Password
config . Network = v . NetworkList . Build ()
for _ , user := range v . Users {
if user . Cipher != "" {
2024-06-29 14:32:57 -04:00
return nil , errors . New ( "shadowsocks 2022 (relay): users must have empty method" )
2022-08-07 19:18:23 -04:00
}
if user . Address == nil {
2024-06-29 14:32:57 -04:00
return nil , errors . New ( "shadowsocks 2022 (relay): all users must have relay address" )
2022-08-07 19:18:23 -04:00
}
config . Destinations = append ( config . Destinations , & shadowsocks_2022 . RelayDestination {
2022-12-25 19:37:35 -05:00
Key : user . Password ,
Email : user . Email ,
2022-08-07 19:18:23 -04:00
Address : user . Address . Build (),
2022-12-25 19:37:35 -05:00
Port : uint32 ( user . Port ),
2026-09-28 02:42:53 +08:00
Level : int32 ( user . Level ),
2022-08-07 19:18:23 -04:00
})
}
return config , nil
}
2020-11-25 19:01:53 +08:00
type ShadowsocksServerTarget struct {
2026-06-09 18:55:42 +08:00
Address * Address `json:"address"`
Port uint16 `json:"port"`
Level byte `json:"level"`
Email string `json:"email"`
Cipher string `json:"method"`
Password string `json:"password"`
2020-11-25 19:01:53 +08:00
}
type ShadowsocksClientConfig struct {
2026-06-09 18:55:42 +08:00
Address * Address `json:"address"`
Port uint16 `json:"port"`
Level byte `json:"level"`
Email string `json:"email"`
Cipher string `json:"method"`
Password string `json:"password"`
Servers [] * ShadowsocksServerTarget `json:"servers"`
2020-11-25 19:01:53 +08:00
}
func ( v * ShadowsocksClientConfig ) Build () ( proto . Message , error ) {
2026-01-23 23:45:20 +08:00
errors . PrintNonRemovalDeprecatedFeatureWarning ( "Shadowsocks (with no Forward Secrecy, etc.)" , "VLESS Encryption" )
2026-01-18 04:17:25 +00:00
2025-09-11 21:48:20 +08:00
if v . Address != nil {
v . Servers = [] * ShadowsocksServerTarget {
{
2026-06-09 18:55:42 +08:00
Address : v . Address ,
Port : v . Port ,
Level : v . Level ,
Email : v . Email ,
Cipher : v . Cipher ,
Password : v . Password ,
2025-09-11 21:48:20 +08:00
},
}
}
2025-09-15 21:31:27 +08:00
if len ( v . Servers ) != 1 {
return nil , errors . New ( `Shadowsocks settings: "servers" should have one and only one member. Multiple endpoints in "servers" should use multiple Shadowsocks outbounds and routing balancer instead` )
2020-11-25 19:01:53 +08:00
}
2026-09-28 02:42:53 +08:00
server := v . Servers [ 0 ]
if server . Address == nil {
return nil , errors . New ( "Shadowsocks server address is not set." )
}
if server . Port == 0 {
return nil , errors . New ( "Invalid Shadowsocks port." )
}
if server . Password == "" {
return nil , errors . New ( "Shadowsocks password is not specified." )
2022-05-23 20:45:30 +08:00
}
2026-09-28 02:42:53 +08:00
if _ , err := shadowsocks_2022 . GetCipherMethod ( server . Cipher ); err == nil {
config := new ( shadowsocks_2022 . ClientConfig )
config . Address = server . Address . Build ()
config . Port = uint32 ( server . Port )
config . Method = server . Cipher
config . Key = server . Password
return config , nil
}
2022-05-23 20:45:30 +08:00
config := new ( shadowsocks . ClientConfig )
2026-09-28 02:42:53 +08:00
account := & shadowsocks . Account {
Password : server . Password ,
}
account . CipherType = cipherFromString ( server . Cipher )
if account . CipherType == shadowsocks . CipherType_UNKNOWN {
return nil , errors . New ( "unknown cipher method: " , server . Cipher )
}
ss := & protocol . ServerEndpoint {
Address : server . Address . Build (),
Port : uint32 ( server . Port ),
User : & protocol . User {
Level : uint32 ( server . Level ),
Email : server . Email ,
Account : serial . ToTypedMessage ( account ),
},
2020-11-25 19:01:53 +08:00
}
2026-09-28 02:42:53 +08:00
config . Server = ss
2020-11-25 19:01:53 +08:00
return config , nil
}