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