github.com/xraypb/Xray-core@v1.8.1/proxy/shadowsocks_2022/inbound_multi.go (about) 1 package shadowsocks_2022 2 3 import ( 4 "context" 5 "encoding/base64" 6 "strconv" 7 "strings" 8 "sync" 9 10 "github.com/sagernet/sing-shadowsocks/shadowaead_2022" 11 C "github.com/sagernet/sing/common" 12 A "github.com/sagernet/sing/common/auth" 13 B "github.com/sagernet/sing/common/buf" 14 "github.com/sagernet/sing/common/bufio" 15 E "github.com/sagernet/sing/common/exceptions" 16 M "github.com/sagernet/sing/common/metadata" 17 N "github.com/sagernet/sing/common/network" 18 "github.com/xraypb/Xray-core/common" 19 "github.com/xraypb/Xray-core/common/buf" 20 "github.com/xraypb/Xray-core/common/log" 21 "github.com/xraypb/Xray-core/common/net" 22 "github.com/xraypb/Xray-core/common/protocol" 23 "github.com/xraypb/Xray-core/common/session" 24 "github.com/xraypb/Xray-core/common/uuid" 25 "github.com/xraypb/Xray-core/features/routing" 26 "github.com/xraypb/Xray-core/transport/internet/stat" 27 ) 28 29 func init() { 30 common.Must(common.RegisterConfig((*MultiUserServerConfig)(nil), func(ctx context.Context, config interface{}) (interface{}, error) { 31 return NewMultiServer(ctx, config.(*MultiUserServerConfig)) 32 })) 33 } 34 35 type MultiUserInbound struct { 36 sync.Mutex 37 networks []net.Network 38 users []*User 39 service *shadowaead_2022.MultiService[int] 40 } 41 42 func NewMultiServer(ctx context.Context, config *MultiUserServerConfig) (*MultiUserInbound, error) { 43 networks := config.Network 44 if len(networks) == 0 { 45 networks = []net.Network{ 46 net.Network_TCP, 47 net.Network_UDP, 48 } 49 } 50 inbound := &MultiUserInbound{ 51 networks: networks, 52 users: config.Users, 53 } 54 if config.Key == "" { 55 return nil, newError("missing key") 56 } 57 psk, err := base64.StdEncoding.DecodeString(config.Key) 58 if err != nil { 59 return nil, newError("parse config").Base(err) 60 } 61 service, err := shadowaead_2022.NewMultiService[int](config.Method, psk, 500, inbound, nil) 62 if err != nil { 63 return nil, newError("create service").Base(err) 64 } 65 66 for i, user := range config.Users { 67 if user.Email == "" { 68 u := uuid.New() 69 user.Email = "unnamed-user-" + strconv.Itoa(i) + "-" + u.String() 70 } 71 } 72 err = service.UpdateUsersWithPasswords( 73 C.MapIndexed(config.Users, func(index int, it *User) int { return index }), 74 C.Map(config.Users, func(it *User) string { return it.Key }), 75 ) 76 if err != nil { 77 return nil, newError("create service").Base(err) 78 } 79 80 inbound.service = service 81 return inbound, nil 82 } 83 84 // AddUser implements proxy.UserManager.AddUser(). 85 func (i *MultiUserInbound) AddUser(ctx context.Context, u *protocol.MemoryUser) error { 86 i.Lock() 87 defer i.Unlock() 88 89 account := u.Account.(*MemoryAccount) 90 if account.Email != "" { 91 for idx := range i.users { 92 if i.users[idx].Email == account.Email { 93 return newError("User ", account.Email, " already exists.") 94 } 95 } 96 } 97 i.users = append(i.users, &User{ 98 Key: account.Key, 99 Email: account.Email, 100 Level: account.Level, 101 }) 102 103 // sync to multi service 104 // Considering implements shadowsocks2022 in xray-core may have better performance. 105 i.service.UpdateUsersWithPasswords( 106 C.MapIndexed(i.users, func(index int, it *User) int { return index }), 107 C.Map(i.users, func(it *User) string { return it.Key }), 108 ) 109 110 return nil 111 } 112 113 // RemoveUser implements proxy.UserManager.RemoveUser(). 114 func (i *MultiUserInbound) RemoveUser(ctx context.Context, email string) error { 115 if email == "" { 116 return newError("Email must not be empty.") 117 } 118 119 i.Lock() 120 defer i.Unlock() 121 122 idx := -1 123 for ii, u := range i.users { 124 if strings.EqualFold(u.Email, email) { 125 idx = ii 126 break 127 } 128 } 129 130 if idx == -1 { 131 return newError("User ", email, " not found.") 132 } 133 134 ulen := len(i.users) 135 136 i.users[idx] = i.users[ulen-1] 137 i.users[ulen-1] = nil 138 i.users = i.users[:ulen-1] 139 140 // sync to multi service 141 // Considering implements shadowsocks2022 in xray-core may have better performance. 142 i.service.UpdateUsersWithPasswords( 143 C.MapIndexed(i.users, func(index int, it *User) int { return index }), 144 C.Map(i.users, func(it *User) string { return it.Key }), 145 ) 146 147 return nil 148 } 149 150 func (i *MultiUserInbound) Network() []net.Network { 151 return i.networks 152 } 153 154 func (i *MultiUserInbound) Process(ctx context.Context, network net.Network, connection stat.Connection, dispatcher routing.Dispatcher) error { 155 inbound := session.InboundFromContext(ctx) 156 inbound.Name = "shadowsocks-2022-multi" 157 158 var metadata M.Metadata 159 if inbound.Source.IsValid() { 160 metadata.Source = M.ParseSocksaddr(inbound.Source.NetAddr()) 161 } 162 163 ctx = session.ContextWithDispatcher(ctx, dispatcher) 164 165 if network == net.Network_TCP { 166 return returnError(i.service.NewConnection(ctx, connection, metadata)) 167 } else { 168 reader := buf.NewReader(connection) 169 pc := &natPacketConn{connection} 170 for { 171 mb, err := reader.ReadMultiBuffer() 172 if err != nil { 173 buf.ReleaseMulti(mb) 174 return returnError(err) 175 } 176 for _, buffer := range mb { 177 packet := B.As(buffer.Bytes()).ToOwned() 178 err = i.service.NewPacket(ctx, pc, packet, metadata) 179 if err != nil { 180 packet.Release() 181 buf.ReleaseMulti(mb) 182 return err 183 } 184 buffer.Release() 185 } 186 } 187 } 188 } 189 190 func (i *MultiUserInbound) NewConnection(ctx context.Context, conn net.Conn, metadata M.Metadata) error { 191 inbound := session.InboundFromContext(ctx) 192 userInt, _ := A.UserFromContext[int](ctx) 193 user := i.users[userInt] 194 inbound.User = &protocol.MemoryUser{ 195 Email: user.Email, 196 Level: uint32(user.Level), 197 } 198 ctx = log.ContextWithAccessMessage(ctx, &log.AccessMessage{ 199 From: metadata.Source, 200 To: metadata.Destination, 201 Status: log.AccessAccepted, 202 Email: user.Email, 203 }) 204 newError("tunnelling request to tcp:", metadata.Destination).WriteToLog(session.ExportIDToError(ctx)) 205 dispatcher := session.DispatcherFromContext(ctx) 206 link, err := dispatcher.Dispatch(ctx, toDestination(metadata.Destination, net.Network_TCP)) 207 if err != nil { 208 return err 209 } 210 outConn := &pipeConnWrapper{ 211 &buf.BufferedReader{Reader: link.Reader}, 212 link.Writer, 213 conn, 214 } 215 return bufio.CopyConn(ctx, conn, outConn) 216 } 217 218 func (i *MultiUserInbound) NewPacketConnection(ctx context.Context, conn N.PacketConn, metadata M.Metadata) error { 219 inbound := session.InboundFromContext(ctx) 220 userInt, _ := A.UserFromContext[int](ctx) 221 user := i.users[userInt] 222 inbound.User = &protocol.MemoryUser{ 223 Email: user.Email, 224 Level: uint32(user.Level), 225 } 226 ctx = log.ContextWithAccessMessage(ctx, &log.AccessMessage{ 227 From: metadata.Source, 228 To: metadata.Destination, 229 Status: log.AccessAccepted, 230 Email: user.Email, 231 }) 232 newError("tunnelling request to udp:", metadata.Destination).WriteToLog(session.ExportIDToError(ctx)) 233 dispatcher := session.DispatcherFromContext(ctx) 234 destination := toDestination(metadata.Destination, net.Network_UDP) 235 link, err := dispatcher.Dispatch(ctx, destination) 236 if err != nil { 237 return err 238 } 239 outConn := &packetConnWrapper{ 240 Reader: link.Reader, 241 Writer: link.Writer, 242 Dest: destination, 243 } 244 return bufio.CopyPacketConn(ctx, conn, outConn) 245 } 246 247 func (i *MultiUserInbound) NewError(ctx context.Context, err error) { 248 if E.IsClosed(err) { 249 return 250 } 251 newError(err).AtWarning().WriteToLog() 252 }