From cf7e675c454d8aaed1dbf03194c09ca1b221a9ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Tue, 24 May 2022 07:25:12 +0800 Subject: [PATCH] Add shadowsocks 2022 multi-user inbound --- go.sum | 2 - infra/conf/shadowsocks.go | 29 ++- proxy/shadowsocks_2022/config.pb.go | 266 ++++++++++++++++++++---- proxy/shadowsocks_2022/config.proto | 15 +- proxy/shadowsocks_2022/inbound.go | 4 + proxy/shadowsocks_2022/inbound_multi.go | 161 ++++++++++++++ 6 files changed, 427 insertions(+), 50 deletions(-) create mode 100644 proxy/shadowsocks_2022/inbound_multi.go diff --git a/go.sum b/go.sum index 0d0adca3..6c815371 100644 --- a/go.sum +++ b/go.sum @@ -174,8 +174,6 @@ github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3 h1:f/FNXud6gA3MNr github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3/go.mod h1:HgjTstvQsPGkxUsCd2KWxErBblirPizecHcpD3ffK+s= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= -github.com/sagernet/sing v0.0.0-20220522025344-b21aa294fca3 h1:z6cVzCta0vPVKo4lsiHMEDmw3cSFC5TGojXobbTS1DA= -github.com/sagernet/sing v0.0.0-20220522025344-b21aa294fca3/go.mod h1:7aFl1bLxdWLIhptc1DwhMWpRfT62rJYzKPYuYlzYs5w= github.com/sagernet/sing v0.0.0-20220523024450-2216901ec429 h1:31vx64WHtycaqw0bGLl6ImJvmHsXqHoPzkuwKmTqbx8= github.com/sagernet/sing v0.0.0-20220523024450-2216901ec429/go.mod h1:7aFl1bLxdWLIhptc1DwhMWpRfT62rJYzKPYuYlzYs5w= github.com/seiflotfy/cuckoofilter v0.0.0-20220411075957-e3b120b3f5fb h1:XfLJSPIOUX+osiMraVgIrMR27uMXnRJWGm1+GL8/63U= diff --git a/infra/conf/shadowsocks.go b/infra/conf/shadowsocks.go index 2cc5a210..5390f728 100644 --- a/infra/conf/shadowsocks.go +++ b/infra/conf/shadowsocks.go @@ -48,13 +48,36 @@ type ShadowsocksServerConfig struct { func (v *ShadowsocksServerConfig) Build() (proto.Message, error) { if C.Contains(shadowaead_2022.List, v.Cipher) { + if len(v.Users) > 0 { + if v.Cipher == "" { + return nil, newError("shadowsocks 2022 (multi-user): missing server method") + } + if !strings.Contains(v.Cipher, "aes") { + return nil, newError("shadowsocks 2022 (multi-user): only blake3-aes-*-gcm methods are supported") + } + + config := new(shadowsocks_2022.MultiUserServerConfig) + config.Method = v.Cipher + + config.Key = v.Password + config.Network = v.NetworkList.Build() + + for _, user := range v.Users { + if user.Cipher != "" { + return nil, newError("shadowsocks 2022 (multi-user): users must have empty method") + } + config.Users = append(config.Users, &shadowsocks_2022.User{ + Key: user.Password, + Email: user.Email, + }) + } + return config, nil + } + config := new(shadowsocks_2022.ServerConfig) config.Method = v.Cipher config.Key = v.Password config.Network = v.NetworkList.Build() - if len(v.Users) != 0 { - return nil, newError("shadowsocks 2022 ciphers accept no users.") - } return config, nil } diff --git a/proxy/shadowsocks_2022/config.pb.go b/proxy/shadowsocks_2022/config.pb.go index a31c28e1..57bea592 100644 --- a/proxy/shadowsocks_2022/config.pb.go +++ b/proxy/shadowsocks_2022/config.pb.go @@ -28,7 +28,8 @@ type ServerConfig struct { Method string `protobuf:"bytes,1,opt,name=method,proto3" json:"method,omitempty"` Key string `protobuf:"bytes,2,opt,name=key,proto3" json:"key,omitempty"` - Network []net.Network `protobuf:"varint,3,rep,packed,name=network,proto3,enum=xray.common.net.Network" json:"network,omitempty"` + Email string `protobuf:"bytes,3,opt,name=email,proto3" json:"email,omitempty"` + Network []net.Network `protobuf:"varint,4,rep,packed,name=network,proto3,enum=xray.common.net.Network" json:"network,omitempty"` } func (x *ServerConfig) Reset() { @@ -77,6 +78,13 @@ func (x *ServerConfig) GetKey() string { return "" } +func (x *ServerConfig) GetEmail() string { + if x != nil { + return x.Email + } + return "" +} + func (x *ServerConfig) GetNetwork() []net.Network { if x != nil { return x.Network @@ -84,6 +92,132 @@ func (x *ServerConfig) GetNetwork() []net.Network { return nil } +type MultiUserServerConfig struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Method string `protobuf:"bytes,1,opt,name=method,proto3" json:"method,omitempty"` + Key string `protobuf:"bytes,2,opt,name=key,proto3" json:"key,omitempty"` + Users []*User `protobuf:"bytes,3,rep,name=users,proto3" json:"users,omitempty"` + Network []net.Network `protobuf:"varint,4,rep,packed,name=network,proto3,enum=xray.common.net.Network" json:"network,omitempty"` +} + +func (x *MultiUserServerConfig) Reset() { + *x = MultiUserServerConfig{} + if protoimpl.UnsafeEnabled { + mi := &file_proxy_shadowsocks_2022_config_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *MultiUserServerConfig) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*MultiUserServerConfig) ProtoMessage() {} + +func (x *MultiUserServerConfig) ProtoReflect() protoreflect.Message { + mi := &file_proxy_shadowsocks_2022_config_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use MultiUserServerConfig.ProtoReflect.Descriptor instead. +func (*MultiUserServerConfig) Descriptor() ([]byte, []int) { + return file_proxy_shadowsocks_2022_config_proto_rawDescGZIP(), []int{1} +} + +func (x *MultiUserServerConfig) GetMethod() string { + if x != nil { + return x.Method + } + return "" +} + +func (x *MultiUserServerConfig) GetKey() string { + if x != nil { + return x.Key + } + return "" +} + +func (x *MultiUserServerConfig) GetUsers() []*User { + if x != nil { + return x.Users + } + return nil +} + +func (x *MultiUserServerConfig) GetNetwork() []net.Network { + if x != nil { + return x.Network + } + return nil +} + +type User struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Key string `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"` + Email string `protobuf:"bytes,2,opt,name=email,proto3" json:"email,omitempty"` +} + +func (x *User) Reset() { + *x = User{} + if protoimpl.UnsafeEnabled { + mi := &file_proxy_shadowsocks_2022_config_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *User) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*User) ProtoMessage() {} + +func (x *User) ProtoReflect() protoreflect.Message { + mi := &file_proxy_shadowsocks_2022_config_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use User.ProtoReflect.Descriptor instead. +func (*User) Descriptor() ([]byte, []int) { + return file_proxy_shadowsocks_2022_config_proto_rawDescGZIP(), []int{2} +} + +func (x *User) GetKey() string { + if x != nil { + return x.Key + } + return "" +} + +func (x *User) GetEmail() string { + if x != nil { + return x.Email + } + return "" +} + type ClientConfig struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -99,7 +233,7 @@ type ClientConfig struct { func (x *ClientConfig) Reset() { *x = ClientConfig{} if protoimpl.UnsafeEnabled { - mi := &file_proxy_shadowsocks_2022_config_proto_msgTypes[1] + mi := &file_proxy_shadowsocks_2022_config_proto_msgTypes[3] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -112,7 +246,7 @@ func (x *ClientConfig) String() string { func (*ClientConfig) ProtoMessage() {} func (x *ClientConfig) ProtoReflect() protoreflect.Message { - mi := &file_proxy_shadowsocks_2022_config_proto_msgTypes[1] + mi := &file_proxy_shadowsocks_2022_config_proto_msgTypes[3] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -125,7 +259,7 @@ func (x *ClientConfig) ProtoReflect() protoreflect.Message { // Deprecated: Use ClientConfig.ProtoReflect.Descriptor instead. func (*ClientConfig) Descriptor() ([]byte, []int) { - return file_proxy_shadowsocks_2022_config_proto_rawDescGZIP(), []int{1} + return file_proxy_shadowsocks_2022_config_proto_rawDescGZIP(), []int{3} } func (x *ClientConfig) GetAddress() *net.IPOrDomain { @@ -173,33 +307,49 @@ var file_proxy_shadowsocks_2022_config_proto_rawDesc = []byte{ 0x32, 0x32, 0x1a, 0x18, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x6e, 0x65, 0x74, 0x2f, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x18, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x6e, 0x65, 0x74, 0x2f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x6c, 0x0a, 0x0c, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, - 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x16, 0x0a, 0x06, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x12, 0x10, - 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, - 0x12, 0x32, 0x0a, 0x07, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x18, 0x03, 0x20, 0x03, 0x28, - 0x0e, 0x32, 0x18, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, - 0x6e, 0x65, 0x74, 0x2e, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x07, 0x6e, 0x65, 0x74, - 0x77, 0x6f, 0x72, 0x6b, 0x22, 0xba, 0x01, 0x0a, 0x0c, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, - 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x35, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, - 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x49, 0x50, 0x4f, 0x72, 0x44, 0x6f, 0x6d, - 0x61, 0x69, 0x6e, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x12, 0x0a, 0x04, - 0x70, 0x6f, 0x72, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x70, 0x6f, 0x72, 0x74, - 0x12, 0x16, 0x0a, 0x06, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x06, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, - 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x35, 0x0a, 0x17, 0x72, 0x65, - 0x64, 0x75, 0x63, 0x65, 0x64, 0x5f, 0x69, 0x76, 0x5f, 0x68, 0x65, 0x61, 0x64, 0x5f, 0x65, 0x6e, - 0x74, 0x72, 0x6f, 0x70, 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x14, 0x72, 0x65, 0x64, - 0x75, 0x63, 0x65, 0x64, 0x49, 0x76, 0x48, 0x65, 0x61, 0x64, 0x45, 0x6e, 0x74, 0x72, 0x6f, 0x70, - 0x79, 0x42, 0x72, 0x0a, 0x1f, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x70, 0x72, - 0x6f, 0x78, 0x79, 0x2e, 0x73, 0x68, 0x61, 0x64, 0x6f, 0x77, 0x73, 0x6f, 0x63, 0x6b, 0x73, 0x5f, - 0x32, 0x30, 0x32, 0x32, 0x50, 0x01, 0x5a, 0x30, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, - 0x6f, 0x6d, 0x2f, 0x78, 0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61, 0x79, 0x2d, 0x63, 0x6f, 0x72, - 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2f, 0x73, 0x68, 0x61, 0x64, 0x6f, 0x77, 0x73, 0x6f, - 0x63, 0x6b, 0x73, 0x5f, 0x32, 0x30, 0x32, 0x32, 0xaa, 0x02, 0x1a, 0x58, 0x72, 0x61, 0x79, 0x2e, - 0x50, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x53, 0x68, 0x61, 0x64, 0x6f, 0x77, 0x73, 0x6f, 0x63, 0x6b, - 0x73, 0x32, 0x30, 0x32, 0x32, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x82, 0x01, 0x0a, 0x0c, 0x53, 0x65, 0x72, 0x76, 0x65, + 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x16, 0x0a, 0x06, 0x6d, 0x65, 0x74, 0x68, 0x6f, + 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x12, + 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, + 0x79, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x12, 0x32, 0x0a, 0x07, 0x6e, 0x65, 0x74, 0x77, 0x6f, + 0x72, 0x6b, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0e, 0x32, 0x18, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, + 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x4e, 0x65, 0x74, 0x77, 0x6f, + 0x72, 0x6b, 0x52, 0x07, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x22, 0xae, 0x01, 0x0a, 0x15, + 0x4d, 0x75, 0x6c, 0x74, 0x69, 0x55, 0x73, 0x65, 0x72, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x43, + 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x16, 0x0a, 0x06, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x12, 0x10, 0x0a, + 0x03, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, + 0x37, 0x0a, 0x05, 0x75, 0x73, 0x65, 0x72, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x21, + 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x73, 0x68, 0x61, 0x64, + 0x6f, 0x77, 0x73, 0x6f, 0x63, 0x6b, 0x73, 0x5f, 0x32, 0x30, 0x32, 0x32, 0x2e, 0x55, 0x73, 0x65, + 0x72, 0x52, 0x05, 0x75, 0x73, 0x65, 0x72, 0x73, 0x12, 0x32, 0x0a, 0x07, 0x6e, 0x65, 0x74, 0x77, + 0x6f, 0x72, 0x6b, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0e, 0x32, 0x18, 0x2e, 0x78, 0x72, 0x61, 0x79, + 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x4e, 0x65, 0x74, 0x77, + 0x6f, 0x72, 0x6b, 0x52, 0x07, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x22, 0x2e, 0x0a, 0x04, + 0x55, 0x73, 0x65, 0x72, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x22, 0xba, 0x01, 0x0a, + 0x0c, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x35, 0x0a, + 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, + 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, + 0x2e, 0x49, 0x50, 0x4f, 0x72, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x52, 0x07, 0x61, 0x64, 0x64, + 0x72, 0x65, 0x73, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x0d, 0x52, 0x04, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x6d, 0x65, 0x74, 0x68, + 0x6f, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, + 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, + 0x65, 0x79, 0x12, 0x35, 0x0a, 0x17, 0x72, 0x65, 0x64, 0x75, 0x63, 0x65, 0x64, 0x5f, 0x69, 0x76, + 0x5f, 0x68, 0x65, 0x61, 0x64, 0x5f, 0x65, 0x6e, 0x74, 0x72, 0x6f, 0x70, 0x79, 0x18, 0x05, 0x20, + 0x01, 0x28, 0x08, 0x52, 0x14, 0x72, 0x65, 0x64, 0x75, 0x63, 0x65, 0x64, 0x49, 0x76, 0x48, 0x65, + 0x61, 0x64, 0x45, 0x6e, 0x74, 0x72, 0x6f, 0x70, 0x79, 0x42, 0x72, 0x0a, 0x1f, 0x63, 0x6f, 0x6d, + 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x73, 0x68, 0x61, 0x64, + 0x6f, 0x77, 0x73, 0x6f, 0x63, 0x6b, 0x73, 0x5f, 0x32, 0x30, 0x32, 0x32, 0x50, 0x01, 0x5a, 0x30, + 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x78, 0x74, 0x6c, 0x73, 0x2f, + 0x78, 0x72, 0x61, 0x79, 0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2f, + 0x73, 0x68, 0x61, 0x64, 0x6f, 0x77, 0x73, 0x6f, 0x63, 0x6b, 0x73, 0x5f, 0x32, 0x30, 0x32, 0x32, + 0xaa, 0x02, 0x1a, 0x58, 0x72, 0x61, 0x79, 0x2e, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x53, 0x68, + 0x61, 0x64, 0x6f, 0x77, 0x73, 0x6f, 0x63, 0x6b, 0x73, 0x32, 0x30, 0x32, 0x32, 0x62, 0x06, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -214,21 +364,25 @@ func file_proxy_shadowsocks_2022_config_proto_rawDescGZIP() []byte { return file_proxy_shadowsocks_2022_config_proto_rawDescData } -var file_proxy_shadowsocks_2022_config_proto_msgTypes = make([]protoimpl.MessageInfo, 2) +var file_proxy_shadowsocks_2022_config_proto_msgTypes = make([]protoimpl.MessageInfo, 4) var file_proxy_shadowsocks_2022_config_proto_goTypes = []interface{}{ - (*ServerConfig)(nil), // 0: xray.proxy.shadowsocks_2022.ServerConfig - (*ClientConfig)(nil), // 1: xray.proxy.shadowsocks_2022.ClientConfig - (net.Network)(0), // 2: xray.common.net.Network - (*net.IPOrDomain)(nil), // 3: xray.common.net.IPOrDomain + (*ServerConfig)(nil), // 0: xray.proxy.shadowsocks_2022.ServerConfig + (*MultiUserServerConfig)(nil), // 1: xray.proxy.shadowsocks_2022.MultiUserServerConfig + (*User)(nil), // 2: xray.proxy.shadowsocks_2022.User + (*ClientConfig)(nil), // 3: xray.proxy.shadowsocks_2022.ClientConfig + (net.Network)(0), // 4: xray.common.net.Network + (*net.IPOrDomain)(nil), // 5: xray.common.net.IPOrDomain } var file_proxy_shadowsocks_2022_config_proto_depIdxs = []int32{ - 2, // 0: xray.proxy.shadowsocks_2022.ServerConfig.network:type_name -> xray.common.net.Network - 3, // 1: xray.proxy.shadowsocks_2022.ClientConfig.address:type_name -> xray.common.net.IPOrDomain - 2, // [2:2] is the sub-list for method output_type - 2, // [2:2] is the sub-list for method input_type - 2, // [2:2] is the sub-list for extension type_name - 2, // [2:2] is the sub-list for extension extendee - 0, // [0:2] is the sub-list for field type_name + 4, // 0: xray.proxy.shadowsocks_2022.ServerConfig.network:type_name -> xray.common.net.Network + 2, // 1: xray.proxy.shadowsocks_2022.MultiUserServerConfig.users:type_name -> xray.proxy.shadowsocks_2022.User + 4, // 2: xray.proxy.shadowsocks_2022.MultiUserServerConfig.network:type_name -> xray.common.net.Network + 5, // 3: xray.proxy.shadowsocks_2022.ClientConfig.address:type_name -> xray.common.net.IPOrDomain + 4, // [4:4] is the sub-list for method output_type + 4, // [4:4] is the sub-list for method input_type + 4, // [4:4] is the sub-list for extension type_name + 4, // [4:4] is the sub-list for extension extendee + 0, // [0:4] is the sub-list for field type_name } func init() { file_proxy_shadowsocks_2022_config_proto_init() } @@ -250,6 +404,30 @@ func file_proxy_shadowsocks_2022_config_proto_init() { } } file_proxy_shadowsocks_2022_config_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*MultiUserServerConfig); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_proxy_shadowsocks_2022_config_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*User); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_proxy_shadowsocks_2022_config_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*ClientConfig); i { case 0: return &v.state @@ -268,7 +446,7 @@ func file_proxy_shadowsocks_2022_config_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_proxy_shadowsocks_2022_config_proto_rawDesc, NumEnums: 0, - NumMessages: 2, + NumMessages: 4, NumExtensions: 0, NumServices: 0, }, diff --git a/proxy/shadowsocks_2022/config.proto b/proxy/shadowsocks_2022/config.proto index 4f3c620c..f2363689 100644 --- a/proxy/shadowsocks_2022/config.proto +++ b/proxy/shadowsocks_2022/config.proto @@ -12,7 +12,20 @@ import "common/net/address.proto"; message ServerConfig { string method = 1; string key = 2; - repeated xray.common.net.Network network = 3; + string email = 3; + repeated xray.common.net.Network network = 4; +} + +message MultiUserServerConfig { + string method = 1; + string key = 2; + repeated User users = 3; + repeated xray.common.net.Network network = 4; +} + +message User { + string key = 1; + string email = 2; } message ClientConfig { diff --git a/proxy/shadowsocks_2022/inbound.go b/proxy/shadowsocks_2022/inbound.go index 1c25c3b7..75ecf845 100644 --- a/proxy/shadowsocks_2022/inbound.go +++ b/proxy/shadowsocks_2022/inbound.go @@ -30,6 +30,7 @@ func init() { type Inbound struct { networks []net.Network service shadowsocks.Service + email string } func NewServer(ctx context.Context, config *ServerConfig) (*Inbound, error) { @@ -42,6 +43,7 @@ func NewServer(ctx context.Context, config *ServerConfig) (*Inbound, error) { } inbound := &Inbound{ networks: networks, + email: config.Email, } if !C.Contains(shadowaead_2022.List, config.Method) { return nil, newError("unsupported method ", config.Method) @@ -103,6 +105,7 @@ func (i *Inbound) NewConnection(ctx context.Context, conn net.Conn, metadata M.M From: metadata.Source, To: metadata.Destination, Status: log.AccessAccepted, + Email: i.email, }) newError("tunnelling request to tcp:", metadata.Destination).WriteToLog(session.ExportIDToError(ctx)) dispatcher := session.DispatcherFromContext(ctx) @@ -123,6 +126,7 @@ func (i *Inbound) NewPacketConnection(ctx context.Context, conn N.PacketConn, me From: metadata.Source, To: metadata.Destination, Status: log.AccessAccepted, + Email: i.email, }) newError("tunnelling request to udp:", metadata.Destination).WriteToLog(session.ExportIDToError(ctx)) dispatcher := session.DispatcherFromContext(ctx) diff --git a/proxy/shadowsocks_2022/inbound_multi.go b/proxy/shadowsocks_2022/inbound_multi.go new file mode 100644 index 00000000..bdf35df4 --- /dev/null +++ b/proxy/shadowsocks_2022/inbound_multi.go @@ -0,0 +1,161 @@ +package shadowsocks_2022 + +import ( + "context" + "encoding/base64" + + B "github.com/sagernet/sing/common/buf" + "github.com/sagernet/sing/common/bufio" + M "github.com/sagernet/sing/common/metadata" + N "github.com/sagernet/sing/common/network" + "github.com/sagernet/sing/common/random" + "github.com/sagernet/sing/protocol/shadowsocks" + "github.com/sagernet/sing/protocol/shadowsocks/shadowaead_2022" + "github.com/xtls/xray-core/common" + "github.com/xtls/xray-core/common/buf" + "github.com/xtls/xray-core/common/log" + "github.com/xtls/xray-core/common/net" + "github.com/xtls/xray-core/common/session" + "github.com/xtls/xray-core/common/uuid" + "github.com/xtls/xray-core/features/routing" + "github.com/xtls/xray-core/transport/internet/stat" +) + +func init() { + common.Must(common.RegisterConfig((*MultiUserServerConfig)(nil), func(ctx context.Context, config interface{}) (interface{}, error) { + return NewMultiServer(ctx, config.(*MultiUserServerConfig)) + })) +} + +type MultiUserInbound struct { + networks []net.Network + service *shadowaead_2022.MultiService[string] +} + +func NewMultiServer(ctx context.Context, config *MultiUserServerConfig) (*MultiUserInbound, error) { + networks := config.Network + if len(networks) == 0 { + networks = []net.Network{ + net.Network_TCP, + net.Network_UDP, + } + } + inbound := &MultiUserInbound{ + networks: networks, + } + if config.Key == "" { + return nil, newError("missing key") + } + psk, err := base64.StdEncoding.DecodeString(config.Key) + if err != nil { + return nil, newError("parse config").Base(err) + } + service, err := shadowaead_2022.NewMultiService[string](config.Method, psk, random.Default, 500, inbound) + if err != nil { + return nil, newError("create service").Base(err) + } + + for _, user := range config.Users { + if user.Email == "" { + u := uuid.New() + user.Email = "(user with empty email - " + u.String() + ")" + } + uPsk, err := base64.StdEncoding.DecodeString(user.Key) + if err != nil { + return nil, newError("parse user key for ", user.Email).Base(err) + } + err = service.AddUser(user.Email, uPsk) + if err != nil { + return nil, newError("add user").Base(err) + } + } + + inbound.service = service + return inbound, nil +} + +func (i *MultiUserInbound) Network() []net.Network { + return i.networks +} + +func (i *MultiUserInbound) Process(ctx context.Context, network net.Network, connection stat.Connection, dispatcher routing.Dispatcher) error { + inbound := session.InboundFromContext(ctx) + if inbound == nil { + panic("no inbound metadata") + } + + var metadata M.Metadata + if inbound.Source.IsValid() { + metadata.Source = M.ParseSocksaddr(inbound.Source.NetAddr()) + } + + ctx = session.ContextWithDispatcher(ctx, dispatcher) + + if network == net.Network_TCP { + return i.service.NewConnection(ctx, connection, metadata) + } else { + reader := buf.NewReader(connection) + pc := &natPacketConn{connection} + for { + mb, err := reader.ReadMultiBuffer() + if err != nil { + return err + } + for _, buffer := range mb { + err = i.service.NewPacket(ctx, pc, B.As(buffer.Bytes()), metadata) + if err != nil { + return err + } + } + } + } +} + +func (i *MultiUserInbound) NewConnection(ctx context.Context, conn net.Conn, metadata M.Metadata) error { + userCtx := ctx.(*shadowsocks.UserContext[string]) + ctx = log.ContextWithAccessMessage(userCtx.Context, &log.AccessMessage{ + From: metadata.Source, + To: metadata.Destination, + Status: log.AccessAccepted, + Email: userCtx.User, + }) + newError("tunnelling request to tcp:", metadata.Destination).WriteToLog(session.ExportIDToError(ctx)) + dispatcher := session.DispatcherFromContext(ctx) + link, err := dispatcher.Dispatch(ctx, toDestination(metadata.Destination, net.Network_TCP)) + if err != nil { + return err + } + outConn := &pipeConnWrapper{ + &buf.BufferedReader{Reader: link.Reader}, + link.Writer, + conn, + } + return bufio.CopyConn(ctx, conn, outConn) +} + +func (i *MultiUserInbound) NewPacketConnection(ctx context.Context, conn N.PacketConn, metadata M.Metadata) error { + userCtx := ctx.(*shadowsocks.UserContext[string]) + ctx = log.ContextWithAccessMessage(userCtx.Context, &log.AccessMessage{ + From: metadata.Source, + To: metadata.Destination, + Status: log.AccessAccepted, + Email: userCtx.User, + }) + newError("tunnelling request to udp:", metadata.Destination).WriteToLog(session.ExportIDToError(ctx)) + dispatcher := session.DispatcherFromContext(ctx) + destination := toDestination(metadata.Destination, net.Network_UDP) + link, err := dispatcher.Dispatch(ctx, destination) + if err != nil { + return err + } + outConn := &packetConnWrapper{ + Reader: link.Reader, + Writer: link.Writer, + Dest: destination, + } + return bufio.CopyPacketConn(ctx, conn, outConn) +} + +func (i *MultiUserInbound) HandleError(err error) { + newError(err).AtWarning().WriteToLog() +}