github.com/inazumav/sing-box@v0.0.0-20230926072359-ab51429a14f1/inbound/shadowsocks_multi.go (about)

     1  package inbound
     2  
     3  import (
     4  	"context"
     5  	"net"
     6  	"os"
     7  
     8  	"github.com/inazumav/sing-box/adapter"
     9  	C "github.com/inazumav/sing-box/constant"
    10  	"github.com/inazumav/sing-box/log"
    11  	"github.com/inazumav/sing-box/option"
    12  	"github.com/sagernet/sing-shadowsocks"
    13  	"github.com/sagernet/sing-shadowsocks/shadowaead"
    14  	"github.com/sagernet/sing-shadowsocks/shadowaead_2022"
    15  	"github.com/sagernet/sing/common"
    16  	"github.com/sagernet/sing/common/auth"
    17  	"github.com/sagernet/sing/common/buf"
    18  	E "github.com/sagernet/sing/common/exceptions"
    19  	F "github.com/sagernet/sing/common/format"
    20  	N "github.com/sagernet/sing/common/network"
    21  	"github.com/sagernet/sing/common/ntp"
    22  )
    23  
    24  var (
    25  	_ adapter.Inbound           = (*ShadowsocksMulti)(nil)
    26  	_ adapter.InjectableInbound = (*ShadowsocksMulti)(nil)
    27  )
    28  
    29  type ShadowsocksMulti struct {
    30  	myInboundAdapter
    31  	service shadowsocks.MultiService[int]
    32  	users   []option.ShadowsocksUser
    33  }
    34  
    35  func newShadowsocksMulti(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.ShadowsocksInboundOptions) (*ShadowsocksMulti, error) {
    36  	inbound := &ShadowsocksMulti{
    37  		myInboundAdapter: myInboundAdapter{
    38  			protocol:      C.TypeShadowsocks,
    39  			network:       options.Network.Build(),
    40  			ctx:           ctx,
    41  			router:        router,
    42  			logger:        logger,
    43  			tag:           tag,
    44  			listenOptions: options.ListenOptions,
    45  		},
    46  	}
    47  	inbound.connHandler = inbound
    48  	inbound.packetHandler = inbound
    49  	var udpTimeout int64
    50  	if options.UDPTimeout != 0 {
    51  		udpTimeout = options.UDPTimeout
    52  	} else {
    53  		udpTimeout = int64(C.UDPTimeout.Seconds())
    54  	}
    55  	var (
    56  		service shadowsocks.MultiService[int]
    57  		err     error
    58  	)
    59  	if common.Contains(shadowaead_2022.List, options.Method) {
    60  		service, err = shadowaead_2022.NewMultiServiceWithPassword[int](
    61  			options.Method,
    62  			options.Password,
    63  			udpTimeout,
    64  			adapter.NewUpstreamContextHandler(inbound.newConnection, inbound.newPacketConnection, inbound),
    65  			ntp.TimeFuncFromContext(ctx),
    66  		)
    67  	} else if common.Contains(shadowaead.List, options.Method) {
    68  		service, err = shadowaead.NewMultiService[int](
    69  			options.Method,
    70  			udpTimeout,
    71  			adapter.NewUpstreamContextHandler(inbound.newConnection, inbound.newPacketConnection, inbound))
    72  	} else {
    73  		return nil, E.New("unsupported method: " + options.Method)
    74  	}
    75  	if err != nil {
    76  		return nil, err
    77  	}
    78  	err = service.UpdateUsersWithPasswords(common.MapIndexed(options.Users, func(index int, user option.ShadowsocksUser) int {
    79  		return index
    80  	}), common.Map(options.Users, func(user option.ShadowsocksUser) string {
    81  		return user.Password
    82  	}))
    83  	if err != nil {
    84  		return nil, err
    85  	}
    86  	inbound.service = service
    87  	inbound.packetUpstream = service
    88  	inbound.users = options.Users
    89  	return inbound, err
    90  }
    91  
    92  func (h *ShadowsocksMulti) AddUsers(users []option.ShadowsocksUser) error {
    93  	if cap(h.users)-len(h.users) >= len(users) {
    94  		h.users = append(h.users, users...)
    95  	} else {
    96  		tmp := make([]option.ShadowsocksUser, 0, len(h.users)+len(users)+10)
    97  		tmp = append(tmp, h.users...)
    98  		tmp = append(tmp, users...)
    99  		h.users = tmp
   100  	}
   101  	err := h.service.UpdateUsersWithPasswords(common.MapIndexed(h.users, func(index int, user option.ShadowsocksUser) int {
   102  		return index
   103  	}), common.Map(h.users, func(user option.ShadowsocksUser) string {
   104  		return user.Password
   105  	}))
   106  	if err != nil {
   107  		return err
   108  	}
   109  	return nil
   110  }
   111  
   112  func (h *ShadowsocksMulti) DelUsers(name []string) error {
   113  	is := make([]int, 0, len(name))
   114  	ulen := len(name)
   115  	for i := range h.users {
   116  		for _, n := range name {
   117  			if h.users[i].Name == n {
   118  				is = append(is, i)
   119  				ulen--
   120  			}
   121  			if ulen == 0 {
   122  				break
   123  			}
   124  		}
   125  	}
   126  	ulen = len(h.users)
   127  	for _, i := range is {
   128  		h.users[i] = h.users[ulen-1]
   129  		h.users[ulen-1] = option.ShadowsocksUser{}
   130  		h.users = h.users[:ulen-1]
   131  		ulen--
   132  	}
   133  	err := h.service.UpdateUsersWithPasswords(common.MapIndexed(h.users, func(index int, user option.ShadowsocksUser) int {
   134  		return index
   135  	}), common.Map(h.users, func(user option.ShadowsocksUser) string {
   136  		return user.Password
   137  	}))
   138  	return err
   139  }
   140  
   141  func (h *ShadowsocksMulti) NewConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext) error {
   142  	return h.service.NewConnection(adapter.WithContext(log.ContextWithNewID(ctx), &metadata), conn, adapter.UpstreamMetadata(metadata))
   143  }
   144  
   145  func (h *ShadowsocksMulti) NewPacket(ctx context.Context, conn N.PacketConn, buffer *buf.Buffer, metadata adapter.InboundContext) error {
   146  	return h.service.NewPacket(adapter.WithContext(ctx, &metadata), conn, buffer, adapter.UpstreamMetadata(metadata))
   147  }
   148  
   149  func (h *ShadowsocksMulti) NewPacketConnection(ctx context.Context, conn N.PacketConn, metadata adapter.InboundContext) error {
   150  	return os.ErrInvalid
   151  }
   152  
   153  func (h *ShadowsocksMulti) newConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext) error {
   154  	userIndex, loaded := auth.UserFromContext[int](ctx)
   155  	if !loaded {
   156  		return os.ErrInvalid
   157  	}
   158  	user := h.users[userIndex].Name
   159  	if user == "" {
   160  		user = F.ToString(userIndex)
   161  	} else {
   162  		metadata.User = user
   163  	}
   164  	h.logger.InfoContext(ctx, "[", user, "] inbound connection to ", metadata.Destination)
   165  	return h.router.RouteConnection(ctx, conn, metadata)
   166  }
   167  
   168  func (h *ShadowsocksMulti) newPacketConnection(ctx context.Context, conn N.PacketConn, metadata adapter.InboundContext) error {
   169  	userIndex, loaded := auth.UserFromContext[int](ctx)
   170  	if !loaded {
   171  		return os.ErrInvalid
   172  	}
   173  	user := h.users[userIndex].Name
   174  	if user == "" {
   175  		user = F.ToString(userIndex)
   176  	} else {
   177  		metadata.User = user
   178  	}
   179  	ctx = log.ContextWithNewID(ctx)
   180  	h.logger.InfoContext(ctx, "[", user, "] inbound packet connection from ", metadata.Source)
   181  	h.logger.InfoContext(ctx, "[", user, "] inbound packet connection to ", metadata.Destination)
   182  	return h.router.RoutePacketConnection(ctx, conn, metadata)
   183  }