mirror of
https://github.com/XTLS/Xray-core.git
synced 2024-11-04 14:13:03 +00:00
Refactor: Shadowsocks AEAD Single-port Multi-user (Needs Optimizations)
https://t.me/projectXray/170851
This commit is contained in:
parent
99863aa2ac
commit
33755d6e90
@ -33,35 +33,60 @@ func cipherFromString(c string) shadowsocks.CipherType {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ShadowsocksUserConfig struct {
|
||||||
|
Cipher string `json:"method"`
|
||||||
|
Password string `json:"password"`
|
||||||
|
Level byte `json:"level"`
|
||||||
|
Email string `json:"email"`
|
||||||
|
}
|
||||||
|
|
||||||
type ShadowsocksServerConfig struct {
|
type ShadowsocksServerConfig struct {
|
||||||
Cipher string `json:"method"`
|
Cipher string `json:"method"`
|
||||||
Password string `json:"password"`
|
Password string `json:"password"`
|
||||||
UDP bool `json:"udp"`
|
Level byte `json:"level"`
|
||||||
Level byte `json:"level"`
|
Email string `json:"email"`
|
||||||
Email string `json:"email"`
|
Users []*ShadowsocksUserConfig `json:"clients"`
|
||||||
NetworkList *NetworkList `json:"network"`
|
NetworkList *NetworkList `json:"network"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *ShadowsocksServerConfig) Build() (proto.Message, error) {
|
func (v *ShadowsocksServerConfig) Build() (proto.Message, error) {
|
||||||
config := new(shadowsocks.ServerConfig)
|
config := new(shadowsocks.ServerConfig)
|
||||||
config.UdpEnabled = v.UDP
|
|
||||||
config.Network = v.NetworkList.Build()
|
config.Network = v.NetworkList.Build()
|
||||||
|
|
||||||
if v.Password == "" {
|
if v.Users != nil {
|
||||||
return nil, newError("Shadowsocks password is not specified.")
|
for _, user := range v.Users {
|
||||||
}
|
account := &shadowsocks.Account{
|
||||||
account := &shadowsocks.Account{
|
Password: user.Password,
|
||||||
Password: v.Password,
|
CipherType: cipherFromString(user.Cipher),
|
||||||
}
|
}
|
||||||
account.CipherType = cipherFromString(v.Cipher)
|
if account.Password == "" {
|
||||||
if account.CipherType == shadowsocks.CipherType_UNKNOWN {
|
return nil, newError("Shadowsocks password is not specified.")
|
||||||
return nil, newError("unknown cipher method: ", v.Cipher)
|
}
|
||||||
}
|
if account.CipherType < 5 || account.CipherType > 7 {
|
||||||
|
return nil, newError("unsupported cipher method: ", user.Cipher)
|
||||||
config.User = &protocol.User{
|
}
|
||||||
Email: v.Email,
|
config.Users = append(config.Users, &protocol.User{
|
||||||
Level: uint32(v.Level),
|
Email: user.Email,
|
||||||
Account: serial.ToTypedMessage(account),
|
Level: uint32(user.Level),
|
||||||
|
Account: serial.ToTypedMessage(account),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
account := &shadowsocks.Account{
|
||||||
|
Password: v.Password,
|
||||||
|
CipherType: cipherFromString(v.Cipher),
|
||||||
|
}
|
||||||
|
if account.Password == "" {
|
||||||
|
return nil, newError("Shadowsocks password is not specified.")
|
||||||
|
}
|
||||||
|
if account.CipherType == shadowsocks.CipherType_UNKNOWN {
|
||||||
|
return nil, newError("unknown cipher method: ", v.Cipher)
|
||||||
|
}
|
||||||
|
config.Users = append(config.Users, &protocol.User{
|
||||||
|
Email: v.Email,
|
||||||
|
Level: uint32(v.Level),
|
||||||
|
Account: serial.ToTypedMessage(account),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
return config, nil
|
return config, nil
|
||||||
@ -73,7 +98,6 @@ type ShadowsocksServerTarget struct {
|
|||||||
Cipher string `json:"method"`
|
Cipher string `json:"method"`
|
||||||
Password string `json:"password"`
|
Password string `json:"password"`
|
||||||
Email string `json:"email"`
|
Email string `json:"email"`
|
||||||
Ota bool `json:"ota"`
|
|
||||||
Level byte `json:"level"`
|
Level byte `json:"level"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,17 +18,17 @@ func TestShadowsocksServerConfigParsing(t *testing.T) {
|
|||||||
runMultiTestCase(t, []TestCase{
|
runMultiTestCase(t, []TestCase{
|
||||||
{
|
{
|
||||||
Input: `{
|
Input: `{
|
||||||
"method": "aes-128-cfb",
|
"method": "aes-128-gcm",
|
||||||
"password": "xray-password"
|
"password": "xray-password"
|
||||||
}`,
|
}`,
|
||||||
Parser: loadJSON(creator),
|
Parser: loadJSON(creator),
|
||||||
Output: &shadowsocks.ServerConfig{
|
Output: &shadowsocks.ServerConfig{
|
||||||
User: &protocol.User{
|
Users: []*protocol.User{{
|
||||||
Account: serial.ToTypedMessage(&shadowsocks.Account{
|
Account: serial.ToTypedMessage(&shadowsocks.Account{
|
||||||
CipherType: shadowsocks.CipherType_AES_128_CFB,
|
CipherType: shadowsocks.CipherType_AES_128_GCM,
|
||||||
Password: "xray-password",
|
Password: "xray-password",
|
||||||
}),
|
}),
|
||||||
},
|
}},
|
||||||
Network: []net.Network{net.Network_TCP},
|
Network: []net.Network{net.Network_TCP},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -154,13 +154,8 @@ type ServerConfig struct {
|
|||||||
sizeCache protoimpl.SizeCache
|
sizeCache protoimpl.SizeCache
|
||||||
unknownFields protoimpl.UnknownFields
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
// UdpEnabled specified whether or not to enable UDP for Shadowsocks.
|
Users []*protocol.User `protobuf:"bytes,1,rep,name=users,proto3" json:"users,omitempty"`
|
||||||
// Deprecated. Use 'network' field.
|
Network []net.Network `protobuf:"varint,2,rep,packed,name=network,proto3,enum=xray.common.net.Network" json:"network,omitempty"`
|
||||||
//
|
|
||||||
// Deprecated: Do not use.
|
|
||||||
UdpEnabled bool `protobuf:"varint,1,opt,name=udp_enabled,json=udpEnabled,proto3" json:"udp_enabled,omitempty"`
|
|
||||||
User *protocol.User `protobuf:"bytes,2,opt,name=user,proto3" json:"user,omitempty"`
|
|
||||||
Network []net.Network `protobuf:"varint,3,rep,packed,name=network,proto3,enum=xray.common.net.Network" json:"network,omitempty"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *ServerConfig) Reset() {
|
func (x *ServerConfig) Reset() {
|
||||||
@ -195,17 +190,9 @@ func (*ServerConfig) Descriptor() ([]byte, []int) {
|
|||||||
return file_proxy_shadowsocks_config_proto_rawDescGZIP(), []int{1}
|
return file_proxy_shadowsocks_config_proto_rawDescGZIP(), []int{1}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Deprecated: Do not use.
|
func (x *ServerConfig) GetUsers() []*protocol.User {
|
||||||
func (x *ServerConfig) GetUdpEnabled() bool {
|
|
||||||
if x != nil {
|
if x != nil {
|
||||||
return x.UdpEnabled
|
return x.Users
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *ServerConfig) GetUser() *protocol.User {
|
|
||||||
if x != nil {
|
|
||||||
return x.User
|
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -282,39 +269,37 @@ var file_proxy_shadowsocks_config_proto_rawDesc = []byte{
|
|||||||
0x65, 0x72, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x22, 0x2e,
|
0x65, 0x72, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x22, 0x2e,
|
||||||
0x78, 0x72, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x73, 0x68, 0x61, 0x64, 0x6f,
|
0x78, 0x72, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x73, 0x68, 0x61, 0x64, 0x6f,
|
||||||
0x77, 0x73, 0x6f, 0x63, 0x6b, 0x73, 0x2e, 0x43, 0x69, 0x70, 0x68, 0x65, 0x72, 0x54, 0x79, 0x70,
|
0x77, 0x73, 0x6f, 0x63, 0x6b, 0x73, 0x2e, 0x43, 0x69, 0x70, 0x68, 0x65, 0x72, 0x54, 0x79, 0x70,
|
||||||
0x65, 0x52, 0x0a, 0x63, 0x69, 0x70, 0x68, 0x65, 0x72, 0x54, 0x79, 0x70, 0x65, 0x22, 0x97, 0x01,
|
0x65, 0x52, 0x0a, 0x63, 0x69, 0x70, 0x68, 0x65, 0x72, 0x54, 0x79, 0x70, 0x65, 0x22, 0x74, 0x0a,
|
||||||
0x0a, 0x0c, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x23,
|
0x0c, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x30, 0x0a,
|
||||||
0x0a, 0x0b, 0x75, 0x64, 0x70, 0x5f, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x01, 0x20,
|
0x05, 0x75, 0x73, 0x65, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x78,
|
||||||
0x01, 0x28, 0x08, 0x42, 0x02, 0x18, 0x01, 0x52, 0x0a, 0x75, 0x64, 0x70, 0x45, 0x6e, 0x61, 0x62,
|
0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
|
||||||
0x6c, 0x65, 0x64, 0x12, 0x2e, 0x0a, 0x04, 0x75, 0x73, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28,
|
0x63, 0x6f, 0x6c, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x52, 0x05, 0x75, 0x73, 0x65, 0x72, 0x73, 0x12,
|
||||||
0x0b, 0x32, 0x1a, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e,
|
0x32, 0x0a, 0x07, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0e,
|
||||||
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x52, 0x04, 0x75,
|
0x32, 0x18, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e,
|
||||||
0x73, 0x65, 0x72, 0x12, 0x32, 0x0a, 0x07, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x18, 0x03,
|
0x65, 0x74, 0x2e, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x07, 0x6e, 0x65, 0x74, 0x77,
|
||||||
0x20, 0x03, 0x28, 0x0e, 0x32, 0x18, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d,
|
0x6f, 0x72, 0x6b, 0x22, 0x4c, 0x0a, 0x0c, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e,
|
||||||
0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x07,
|
0x66, 0x69, 0x67, 0x12, 0x3c, 0x0a, 0x06, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x18, 0x01, 0x20,
|
||||||
0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x22, 0x4c, 0x0a, 0x0c, 0x43, 0x6c, 0x69, 0x65, 0x6e,
|
0x03, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f,
|
||||||
0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x3c, 0x0a, 0x06, 0x73, 0x65, 0x72, 0x76, 0x65,
|
0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65,
|
||||||
0x72, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63,
|
0x72, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x06, 0x73, 0x65, 0x72, 0x76, 0x65,
|
||||||
0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x53,
|
0x72, 0x2a, 0x9f, 0x01, 0x0a, 0x0a, 0x43, 0x69, 0x70, 0x68, 0x65, 0x72, 0x54, 0x79, 0x70, 0x65,
|
||||||
0x65, 0x72, 0x76, 0x65, 0x72, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x06, 0x73,
|
0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x0f, 0x0a,
|
||||||
0x65, 0x72, 0x76, 0x65, 0x72, 0x2a, 0x9f, 0x01, 0x0a, 0x0a, 0x43, 0x69, 0x70, 0x68, 0x65, 0x72,
|
0x0b, 0x41, 0x45, 0x53, 0x5f, 0x31, 0x32, 0x38, 0x5f, 0x43, 0x46, 0x42, 0x10, 0x01, 0x12, 0x0f,
|
||||||
0x54, 0x79, 0x70, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10,
|
0x0a, 0x0b, 0x41, 0x45, 0x53, 0x5f, 0x32, 0x35, 0x36, 0x5f, 0x43, 0x46, 0x42, 0x10, 0x02, 0x12,
|
||||||
0x00, 0x12, 0x0f, 0x0a, 0x0b, 0x41, 0x45, 0x53, 0x5f, 0x31, 0x32, 0x38, 0x5f, 0x43, 0x46, 0x42,
|
0x0c, 0x0a, 0x08, 0x43, 0x48, 0x41, 0x43, 0x48, 0x41, 0x32, 0x30, 0x10, 0x03, 0x12, 0x11, 0x0a,
|
||||||
0x10, 0x01, 0x12, 0x0f, 0x0a, 0x0b, 0x41, 0x45, 0x53, 0x5f, 0x32, 0x35, 0x36, 0x5f, 0x43, 0x46,
|
0x0d, 0x43, 0x48, 0x41, 0x43, 0x48, 0x41, 0x32, 0x30, 0x5f, 0x49, 0x45, 0x54, 0x46, 0x10, 0x04,
|
||||||
0x42, 0x10, 0x02, 0x12, 0x0c, 0x0a, 0x08, 0x43, 0x48, 0x41, 0x43, 0x48, 0x41, 0x32, 0x30, 0x10,
|
0x12, 0x0f, 0x0a, 0x0b, 0x41, 0x45, 0x53, 0x5f, 0x31, 0x32, 0x38, 0x5f, 0x47, 0x43, 0x4d, 0x10,
|
||||||
0x03, 0x12, 0x11, 0x0a, 0x0d, 0x43, 0x48, 0x41, 0x43, 0x48, 0x41, 0x32, 0x30, 0x5f, 0x49, 0x45,
|
0x05, 0x12, 0x0f, 0x0a, 0x0b, 0x41, 0x45, 0x53, 0x5f, 0x32, 0x35, 0x36, 0x5f, 0x47, 0x43, 0x4d,
|
||||||
0x54, 0x46, 0x10, 0x04, 0x12, 0x0f, 0x0a, 0x0b, 0x41, 0x45, 0x53, 0x5f, 0x31, 0x32, 0x38, 0x5f,
|
0x10, 0x06, 0x12, 0x15, 0x0a, 0x11, 0x43, 0x48, 0x41, 0x43, 0x48, 0x41, 0x32, 0x30, 0x5f, 0x50,
|
||||||
0x47, 0x43, 0x4d, 0x10, 0x05, 0x12, 0x0f, 0x0a, 0x0b, 0x41, 0x45, 0x53, 0x5f, 0x32, 0x35, 0x36,
|
0x4f, 0x4c, 0x59, 0x31, 0x33, 0x30, 0x35, 0x10, 0x07, 0x12, 0x08, 0x0a, 0x04, 0x4e, 0x4f, 0x4e,
|
||||||
0x5f, 0x47, 0x43, 0x4d, 0x10, 0x06, 0x12, 0x15, 0x0a, 0x11, 0x43, 0x48, 0x41, 0x43, 0x48, 0x41,
|
0x45, 0x10, 0x08, 0x42, 0x64, 0x0a, 0x1a, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e,
|
||||||
0x32, 0x30, 0x5f, 0x50, 0x4f, 0x4c, 0x59, 0x31, 0x33, 0x30, 0x35, 0x10, 0x07, 0x12, 0x08, 0x0a,
|
0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x73, 0x68, 0x61, 0x64, 0x6f, 0x77, 0x73, 0x6f, 0x63, 0x6b,
|
||||||
0x04, 0x4e, 0x4f, 0x4e, 0x45, 0x10, 0x08, 0x42, 0x64, 0x0a, 0x1a, 0x63, 0x6f, 0x6d, 0x2e, 0x78,
|
0x73, 0x50, 0x01, 0x5a, 0x2b, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f,
|
||||||
0x72, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x73, 0x68, 0x61, 0x64, 0x6f, 0x77,
|
0x78, 0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61, 0x79, 0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x70,
|
||||||
0x73, 0x6f, 0x63, 0x6b, 0x73, 0x50, 0x01, 0x5a, 0x2b, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e,
|
0x72, 0x6f, 0x78, 0x79, 0x2f, 0x73, 0x68, 0x61, 0x64, 0x6f, 0x77, 0x73, 0x6f, 0x63, 0x6b, 0x73,
|
||||||
0x63, 0x6f, 0x6d, 0x2f, 0x78, 0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61, 0x79, 0x2d, 0x63, 0x6f,
|
0xaa, 0x02, 0x16, 0x58, 0x72, 0x61, 0x79, 0x2e, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x53, 0x68,
|
||||||
0x72, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2f, 0x73, 0x68, 0x61, 0x64, 0x6f, 0x77, 0x73,
|
0x61, 0x64, 0x6f, 0x77, 0x73, 0x6f, 0x63, 0x6b, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f,
|
||||||
0x6f, 0x63, 0x6b, 0x73, 0xaa, 0x02, 0x16, 0x58, 0x72, 0x61, 0x79, 0x2e, 0x50, 0x72, 0x6f, 0x78,
|
0x33,
|
||||||
0x79, 0x2e, 0x53, 0x68, 0x61, 0x64, 0x6f, 0x77, 0x73, 0x6f, 0x63, 0x6b, 0x73, 0x62, 0x06, 0x70,
|
|
||||||
0x72, 0x6f, 0x74, 0x6f, 0x33,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -342,7 +327,7 @@ var file_proxy_shadowsocks_config_proto_goTypes = []interface{}{
|
|||||||
}
|
}
|
||||||
var file_proxy_shadowsocks_config_proto_depIdxs = []int32{
|
var file_proxy_shadowsocks_config_proto_depIdxs = []int32{
|
||||||
0, // 0: xray.proxy.shadowsocks.Account.cipher_type:type_name -> xray.proxy.shadowsocks.CipherType
|
0, // 0: xray.proxy.shadowsocks.Account.cipher_type:type_name -> xray.proxy.shadowsocks.CipherType
|
||||||
4, // 1: xray.proxy.shadowsocks.ServerConfig.user:type_name -> xray.common.protocol.User
|
4, // 1: xray.proxy.shadowsocks.ServerConfig.users:type_name -> xray.common.protocol.User
|
||||||
5, // 2: xray.proxy.shadowsocks.ServerConfig.network:type_name -> xray.common.net.Network
|
5, // 2: xray.proxy.shadowsocks.ServerConfig.network:type_name -> xray.common.net.Network
|
||||||
6, // 3: xray.proxy.shadowsocks.ClientConfig.server:type_name -> xray.common.protocol.ServerEndpoint
|
6, // 3: xray.proxy.shadowsocks.ClientConfig.server:type_name -> xray.common.protocol.ServerEndpoint
|
||||||
4, // [4:4] is the sub-list for method output_type
|
4, // [4:4] is the sub-list for method output_type
|
||||||
|
@ -28,11 +28,8 @@ enum CipherType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
message ServerConfig {
|
message ServerConfig {
|
||||||
// UdpEnabled specified whether or not to enable UDP for Shadowsocks.
|
repeated xray.common.protocol.User users = 1;
|
||||||
// Deprecated. Use 'network' field.
|
repeated xray.common.net.Network network = 2;
|
||||||
bool udp_enabled = 1 [deprecated = true];
|
|
||||||
xray.common.protocol.User user = 2;
|
|
||||||
repeated xray.common.net.Network network = 3;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
message ClientConfig {
|
message ClientConfig {
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package shadowsocks
|
package shadowsocks
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"crypto/cipher"
|
||||||
"crypto/hmac"
|
"crypto/hmac"
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
"crypto/sha256"
|
"crypto/sha256"
|
||||||
@ -10,6 +11,7 @@ import (
|
|||||||
|
|
||||||
"github.com/xtls/xray-core/common"
|
"github.com/xtls/xray-core/common"
|
||||||
"github.com/xtls/xray-core/common/buf"
|
"github.com/xtls/xray-core/common/buf"
|
||||||
|
"github.com/xtls/xray-core/common/crypto"
|
||||||
"github.com/xtls/xray-core/common/dice"
|
"github.com/xtls/xray-core/common/dice"
|
||||||
"github.com/xtls/xray-core/common/net"
|
"github.com/xtls/xray-core/common/net"
|
||||||
"github.com/xtls/xray-core/common/protocol"
|
"github.com/xtls/xray-core/common/protocol"
|
||||||
@ -28,8 +30,32 @@ var addrParser = protocol.NewAddressParser(
|
|||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type FullReader struct {
|
||||||
|
reader io.Reader
|
||||||
|
buffer []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *FullReader) Read(p []byte) (n int, err error) {
|
||||||
|
if r.buffer != nil {
|
||||||
|
n := copy(p, r.buffer)
|
||||||
|
if n == len(r.buffer) {
|
||||||
|
r.buffer = nil
|
||||||
|
} else {
|
||||||
|
r.buffer = r.buffer[n:]
|
||||||
|
}
|
||||||
|
if n == len(p) {
|
||||||
|
return n, nil
|
||||||
|
} else {
|
||||||
|
m, err := r.reader.Read(p[n:])
|
||||||
|
return n + m, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return r.reader.Read(p)
|
||||||
|
}
|
||||||
|
|
||||||
// ReadTCPSession reads a Shadowsocks TCP session from the given reader, returns its header and remaining parts.
|
// ReadTCPSession reads a Shadowsocks TCP session from the given reader, returns its header and remaining parts.
|
||||||
func ReadTCPSession(user *protocol.MemoryUser, reader io.Reader) (*protocol.RequestHeader, buf.Reader, error) {
|
func ReadTCPSession(users []*protocol.MemoryUser, reader io.Reader) (*protocol.RequestHeader, buf.Reader, error) {
|
||||||
|
user := users[0]
|
||||||
account := user.Account.(*MemoryAccount)
|
account := user.Account.(*MemoryAccount)
|
||||||
|
|
||||||
hashkdf := hmac.New(sha256.New, []byte("SSBSKDF"))
|
hashkdf := hmac.New(sha256.New, []byte("SSBSKDF"))
|
||||||
@ -44,28 +70,78 @@ func ReadTCPSession(user *protocol.MemoryUser, reader io.Reader) (*protocol.Requ
|
|||||||
DrainSize := BaseDrainSize + 16 + 38 + RandDrainRolled
|
DrainSize := BaseDrainSize + 16 + 38 + RandDrainRolled
|
||||||
readSizeRemain := DrainSize
|
readSizeRemain := DrainSize
|
||||||
|
|
||||||
|
var r2 buf.Reader
|
||||||
|
|
||||||
|
if len(users) > 1 {
|
||||||
|
buffer := buf.New()
|
||||||
|
defer buffer.Release()
|
||||||
|
|
||||||
|
if _, err := buffer.ReadFullFrom(reader, 50); err != nil {
|
||||||
|
readSizeRemain -= int(buffer.Len())
|
||||||
|
DrainConnN(reader, readSizeRemain)
|
||||||
|
return nil, nil, newError("failed to read 50 bytes").Base(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
bs := buffer.Bytes()
|
||||||
|
|
||||||
|
var aeadCipher *AEADCipher
|
||||||
|
var ivLen int32
|
||||||
|
subkey := make([]byte, 32)
|
||||||
|
length := make([]byte, 16)
|
||||||
|
var aead cipher.AEAD
|
||||||
|
var err error
|
||||||
|
for _, user = range users {
|
||||||
|
account = user.Account.(*MemoryAccount)
|
||||||
|
aeadCipher = account.Cipher.(*AEADCipher)
|
||||||
|
ivLen = aeadCipher.IVSize()
|
||||||
|
subkey = subkey[:aeadCipher.KeyBytes]
|
||||||
|
hkdfSHA1(account.Key, bs[:ivLen], subkey)
|
||||||
|
aead = aeadCipher.AEADAuthCreator(subkey)
|
||||||
|
_, err = aead.Open(length[:0], length[4:16], bs[ivLen:ivLen+18], nil)
|
||||||
|
if err == nil {
|
||||||
|
reader = &FullReader{reader, bs[ivLen:]}
|
||||||
|
auth := &crypto.AEADAuthenticator{
|
||||||
|
AEAD: aead,
|
||||||
|
NonceGenerator: crypto.GenerateInitialAEADNonce(),
|
||||||
|
}
|
||||||
|
r2 = crypto.NewAuthenticationReader(auth, &crypto.AEADChunkSizeParser{
|
||||||
|
Auth: auth,
|
||||||
|
}, reader, protocol.TransferTypeStream, nil)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
readSizeRemain -= int(buffer.Len())
|
||||||
|
DrainConnN(reader, readSizeRemain)
|
||||||
|
return nil, nil, newError("failed to match an user").Base(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
buffer := buf.New()
|
buffer := buf.New()
|
||||||
defer buffer.Release()
|
defer buffer.Release()
|
||||||
|
|
||||||
ivLen := account.Cipher.IVSize()
|
if r2 == nil {
|
||||||
var iv []byte
|
ivLen := account.Cipher.IVSize()
|
||||||
if ivLen > 0 {
|
var iv []byte
|
||||||
if _, err := buffer.ReadFullFrom(reader, ivLen); err != nil {
|
if ivLen > 0 {
|
||||||
readSizeRemain -= int(buffer.Len())
|
if _, err := buffer.ReadFullFrom(reader, ivLen); err != nil {
|
||||||
DrainConnN(reader, readSizeRemain)
|
readSizeRemain -= int(buffer.Len())
|
||||||
return nil, nil, newError("failed to read IV").Base(err)
|
DrainConnN(reader, readSizeRemain)
|
||||||
|
return nil, nil, newError("failed to read IV").Base(err)
|
||||||
|
}
|
||||||
|
iv = append([]byte(nil), buffer.BytesTo(ivLen)...)
|
||||||
}
|
}
|
||||||
|
|
||||||
iv = append([]byte(nil), buffer.BytesTo(ivLen)...)
|
r, err := account.Cipher.NewDecryptionReader(account.Key, iv, reader)
|
||||||
|
if err != nil {
|
||||||
|
readSizeRemain -= int(buffer.Len())
|
||||||
|
DrainConnN(reader, readSizeRemain)
|
||||||
|
return nil, nil, newError("failed to initialize decoding stream").Base(err).AtError()
|
||||||
|
}
|
||||||
|
r2 = r
|
||||||
}
|
}
|
||||||
|
|
||||||
r, err := account.Cipher.NewDecryptionReader(account.Key, iv, reader)
|
br := &buf.BufferedReader{Reader: r2}
|
||||||
if err != nil {
|
|
||||||
readSizeRemain -= int(buffer.Len())
|
|
||||||
DrainConnN(reader, readSizeRemain)
|
|
||||||
return nil, nil, newError("failed to initialize decoding stream").Base(err).AtError()
|
|
||||||
}
|
|
||||||
br := &buf.BufferedReader{Reader: r}
|
|
||||||
|
|
||||||
request := &protocol.RequestHeader{
|
request := &protocol.RequestHeader{
|
||||||
Version: Version,
|
Version: Version,
|
||||||
@ -185,17 +261,49 @@ func EncodeUDPPacket(request *protocol.RequestHeader, payload []byte) (*buf.Buff
|
|||||||
return buffer, nil
|
return buffer, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func DecodeUDPPacket(user *protocol.MemoryUser, payload *buf.Buffer) (*protocol.RequestHeader, *buf.Buffer, error) {
|
func DecodeUDPPacket(users []*protocol.MemoryUser, payload *buf.Buffer) (*protocol.RequestHeader, *buf.Buffer, error) {
|
||||||
account := user.Account.(*MemoryAccount)
|
var user *protocol.MemoryUser
|
||||||
|
var account *MemoryAccount
|
||||||
|
var err error
|
||||||
|
|
||||||
var iv []byte
|
if len(users) > 1 {
|
||||||
if !account.Cipher.IsAEAD() && account.Cipher.IVSize() > 0 {
|
bs := payload.Bytes()
|
||||||
// Keep track of IV as it gets removed from payload in DecodePacket.
|
|
||||||
iv = make([]byte, account.Cipher.IVSize())
|
var aeadCipher *AEADCipher
|
||||||
copy(iv, payload.BytesTo(account.Cipher.IVSize()))
|
var ivLen int32
|
||||||
|
subkey := make([]byte, 32)
|
||||||
|
data := make([]byte, 8192)
|
||||||
|
var aead cipher.AEAD
|
||||||
|
var d []byte
|
||||||
|
for _, user = range users {
|
||||||
|
account = user.Account.(*MemoryAccount)
|
||||||
|
aeadCipher = account.Cipher.(*AEADCipher)
|
||||||
|
ivLen = aeadCipher.IVSize()
|
||||||
|
subkey = subkey[:aeadCipher.KeyBytes]
|
||||||
|
hkdfSHA1(account.Key, bs[:ivLen], subkey)
|
||||||
|
aead = aeadCipher.AEADAuthCreator(subkey)
|
||||||
|
d, err = aead.Open(data[:0], data[8180:8192], bs[ivLen:], nil)
|
||||||
|
if err == nil {
|
||||||
|
payload.Clear()
|
||||||
|
payload.Write(d)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
user = users[0]
|
||||||
|
account = user.Account.(*MemoryAccount)
|
||||||
|
|
||||||
|
var iv []byte
|
||||||
|
if !account.Cipher.IsAEAD() && account.Cipher.IVSize() > 0 {
|
||||||
|
// Keep track of IV as it gets removed from payload in DecodePacket.
|
||||||
|
iv = make([]byte, account.Cipher.IVSize())
|
||||||
|
copy(iv, payload.BytesTo(account.Cipher.IVSize()))
|
||||||
|
}
|
||||||
|
|
||||||
|
err = account.Cipher.DecodePacket(account.Key, payload)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := account.Cipher.DecodePacket(account.Key, payload); err != nil {
|
if err != nil {
|
||||||
return nil, nil, newError("failed to decrypt UDP payload").Base(err)
|
return nil, nil, newError("failed to decrypt UDP payload").Base(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -230,7 +338,7 @@ func (v *UDPReader) ReadMultiBuffer() (buf.MultiBuffer, error) {
|
|||||||
buffer.Release()
|
buffer.Release()
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
u, payload, err := DecodeUDPPacket(v.User, buffer)
|
u, payload, err := DecodeUDPPacket([]*protocol.MemoryUser{v.User}, buffer)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
buffer.Release()
|
buffer.Release()
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -38,7 +38,7 @@ func TestUDPEncoding(t *testing.T) {
|
|||||||
encodedData, err := EncodeUDPPacket(request, data.Bytes())
|
encodedData, err := EncodeUDPPacket(request, data.Bytes())
|
||||||
common.Must(err)
|
common.Must(err)
|
||||||
|
|
||||||
decodedRequest, decodedData, err := DecodeUDPPacket(request.User, encodedData)
|
decodedRequest, decodedData, err := DecodeUDPPacket([]*protocol.MemoryUser{request.User}, encodedData)
|
||||||
common.Must(err)
|
common.Must(err)
|
||||||
|
|
||||||
if r := cmp.Diff(decodedData.Bytes(), data.Bytes()); r != "" {
|
if r := cmp.Diff(decodedData.Bytes(), data.Bytes()); r != "" {
|
||||||
@ -117,7 +117,7 @@ func TestTCPRequest(t *testing.T) {
|
|||||||
|
|
||||||
common.Must(writer.WriteMultiBuffer(buf.MultiBuffer{data}))
|
common.Must(writer.WriteMultiBuffer(buf.MultiBuffer{data}))
|
||||||
|
|
||||||
decodedRequest, reader, err := ReadTCPSession(request.User, cache)
|
decodedRequest, reader, err := ReadTCPSession([]*protocol.MemoryUser{request.User}, cache)
|
||||||
common.Must(err)
|
common.Must(err)
|
||||||
if r := cmp.Diff(decodedRequest, request); r != "" {
|
if r := cmp.Diff(decodedRequest, request); r != "" {
|
||||||
t.Error("request: ", r)
|
t.Error("request: ", r)
|
||||||
|
@ -22,30 +22,32 @@ import (
|
|||||||
|
|
||||||
type Server struct {
|
type Server struct {
|
||||||
config *ServerConfig
|
config *ServerConfig
|
||||||
user *protocol.MemoryUser
|
users []*protocol.MemoryUser
|
||||||
policyManager policy.Manager
|
policyManager policy.Manager
|
||||||
cone bool
|
cone bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewServer create a new Shadowsocks server.
|
// NewServer create a new Shadowsocks server.
|
||||||
func NewServer(ctx context.Context, config *ServerConfig) (*Server, error) {
|
func NewServer(ctx context.Context, config *ServerConfig) (*Server, error) {
|
||||||
if config.GetUser() == nil {
|
if config.Users == nil {
|
||||||
return nil, newError("user is not specified")
|
return nil, newError("empty users")
|
||||||
}
|
|
||||||
|
|
||||||
mUser, err := config.User.ToMemoryUser()
|
|
||||||
if err != nil {
|
|
||||||
return nil, newError("failed to parse user account").Base(err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
v := core.MustFromContext(ctx)
|
v := core.MustFromContext(ctx)
|
||||||
s := &Server{
|
s := &Server{
|
||||||
config: config,
|
config: config,
|
||||||
user: mUser,
|
|
||||||
policyManager: v.GetFeature(policy.ManagerType()).(policy.Manager),
|
policyManager: v.GetFeature(policy.ManagerType()).(policy.Manager),
|
||||||
cone: ctx.Value("cone").(bool),
|
cone: ctx.Value("cone").(bool),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for _, user := range config.Users {
|
||||||
|
u, err := user.ToMemoryUser()
|
||||||
|
if err != nil {
|
||||||
|
return nil, newError("failed to parse user account").Base(err)
|
||||||
|
}
|
||||||
|
s.users = append(s.users, u)
|
||||||
|
}
|
||||||
|
|
||||||
return s, nil
|
return s, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -54,9 +56,6 @@ func (s *Server) Network() []net.Network {
|
|||||||
if len(list) == 0 {
|
if len(list) == 0 {
|
||||||
list = append(list, net.Network_TCP)
|
list = append(list, net.Network_TCP)
|
||||||
}
|
}
|
||||||
if s.config.UdpEnabled {
|
|
||||||
list = append(list, net.Network_UDP)
|
|
||||||
}
|
|
||||||
return list
|
return list
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -103,7 +102,9 @@ func (s *Server) handlerUDPPayload(ctx context.Context, conn internet.Connection
|
|||||||
if inbound == nil {
|
if inbound == nil {
|
||||||
panic("no inbound metadata")
|
panic("no inbound metadata")
|
||||||
}
|
}
|
||||||
inbound.User = s.user
|
if len(s.users) == 1 {
|
||||||
|
inbound.User = s.users[0]
|
||||||
|
}
|
||||||
|
|
||||||
var dest *net.Destination
|
var dest *net.Destination
|
||||||
|
|
||||||
@ -115,9 +116,21 @@ func (s *Server) handlerUDPPayload(ctx context.Context, conn internet.Connection
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, payload := range mpayload {
|
for _, payload := range mpayload {
|
||||||
request, data, err := DecodeUDPPacket(s.user, payload)
|
var request *protocol.RequestHeader
|
||||||
|
var data *buf.Buffer
|
||||||
|
var err error
|
||||||
|
|
||||||
|
if inbound.User != nil {
|
||||||
|
request, data, err = DecodeUDPPacket([]*protocol.MemoryUser{inbound.User}, payload)
|
||||||
|
} else {
|
||||||
|
request, data, err = DecodeUDPPacket(s.users, payload)
|
||||||
|
if err == nil {
|
||||||
|
inbound.User = request.User
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if inbound := session.InboundFromContext(ctx); inbound != nil && inbound.Source.IsValid() {
|
if inbound.Source.IsValid() {
|
||||||
newError("dropping invalid UDP packet from: ", inbound.Source).Base(err).WriteToLog(session.ExportIDToError(ctx))
|
newError("dropping invalid UDP packet from: ", inbound.Source).Base(err).WriteToLog(session.ExportIDToError(ctx))
|
||||||
log.Record(&log.AccessMessage{
|
log.Record(&log.AccessMessage{
|
||||||
From: inbound.Source,
|
From: inbound.Source,
|
||||||
@ -159,11 +172,13 @@ func (s *Server) handlerUDPPayload(ctx context.Context, conn internet.Connection
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) handleConnection(ctx context.Context, conn internet.Connection, dispatcher routing.Dispatcher) error {
|
func (s *Server) handleConnection(ctx context.Context, conn internet.Connection, dispatcher routing.Dispatcher) error {
|
||||||
sessionPolicy := s.policyManager.ForLevel(s.user.Level)
|
sessionPolicy := s.policyManager.ForLevel(0)
|
||||||
conn.SetReadDeadline(time.Now().Add(sessionPolicy.Timeouts.Handshake))
|
if err := conn.SetReadDeadline(time.Now().Add(sessionPolicy.Timeouts.Handshake)); err != nil {
|
||||||
|
return newError("unable to set read deadline").Base(err).AtWarning()
|
||||||
|
}
|
||||||
|
|
||||||
bufferedReader := buf.BufferedReader{Reader: buf.NewReader(conn)}
|
bufferedReader := buf.BufferedReader{Reader: buf.NewReader(conn)}
|
||||||
request, bodyReader, err := ReadTCPSession(s.user, &bufferedReader)
|
request, bodyReader, err := ReadTCPSession(s.users, &bufferedReader)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Record(&log.AccessMessage{
|
log.Record(&log.AccessMessage{
|
||||||
From: conn.RemoteAddr(),
|
From: conn.RemoteAddr(),
|
||||||
@ -179,7 +194,7 @@ func (s *Server) handleConnection(ctx context.Context, conn internet.Connection,
|
|||||||
if inbound == nil {
|
if inbound == nil {
|
||||||
panic("no inbound metadata")
|
panic("no inbound metadata")
|
||||||
}
|
}
|
||||||
inbound.User = s.user
|
inbound.User = request.User
|
||||||
|
|
||||||
dest := request.Destination()
|
dest := request.Destination()
|
||||||
ctx = log.ContextWithAccessMessage(ctx, &log.AccessMessage{
|
ctx = log.ContextWithAccessMessage(ctx, &log.AccessMessage{
|
||||||
@ -191,6 +206,7 @@ func (s *Server) handleConnection(ctx context.Context, conn internet.Connection,
|
|||||||
})
|
})
|
||||||
newError("tunnelling request to ", dest).WriteToLog(session.ExportIDToError(ctx))
|
newError("tunnelling request to ", dest).WriteToLog(session.ExportIDToError(ctx))
|
||||||
|
|
||||||
|
sessionPolicy = s.policyManager.ForLevel(request.User.Level)
|
||||||
ctx, cancel := context.WithCancel(ctx)
|
ctx, cancel := context.WithCancel(ctx)
|
||||||
timer := signal.CancelAfterInactivity(ctx, cancel, sessionPolicy.Timeouts.ConnectionIdle)
|
timer := signal.CancelAfterInactivity(ctx, cancel, sessionPolicy.Timeouts.ConnectionIdle)
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user