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  }