github.com/xmplusdev/xmcore@v1.8.11-0.20240412132628-5518b55526af/proxy/shadowsocks_2022/inbound_relay.go (about)

     1  package shadowsocks_2022
     2  
     3  import (
     4  	"context"
     5  	"strconv"
     6  	"strings"
     7  
     8  	"github.com/sagernet/sing-shadowsocks/shadowaead_2022"
     9  	C "github.com/sagernet/sing/common"
    10  	A "github.com/sagernet/sing/common/auth"
    11  	B "github.com/sagernet/sing/common/buf"
    12  	"github.com/sagernet/sing/common/bufio"
    13  	E "github.com/sagernet/sing/common/exceptions"
    14  	M "github.com/sagernet/sing/common/metadata"
    15  	N "github.com/sagernet/sing/common/network"
    16  	"github.com/xmplusdev/xmcore/common"
    17  	"github.com/xmplusdev/xmcore/common/buf"
    18  	"github.com/xmplusdev/xmcore/common/log"
    19  	"github.com/xmplusdev/xmcore/common/net"
    20  	"github.com/xmplusdev/xmcore/common/protocol"
    21  	"github.com/xmplusdev/xmcore/common/session"
    22  	"github.com/xmplusdev/xmcore/common/singbridge"
    23  	"github.com/xmplusdev/xmcore/common/uuid"
    24  	"github.com/xmplusdev/xmcore/features/routing"
    25  	"github.com/xmplusdev/xmcore/transport/internet/stat"
    26  )
    27  
    28  func init() {
    29  	common.Must(common.RegisterConfig((*RelayServerConfig)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
    30  		return NewRelayServer(ctx, config.(*RelayServerConfig))
    31  	}))
    32  }
    33  
    34  type RelayInbound struct {
    35  	networks     []net.Network
    36  	destinations []*RelayDestination
    37  	service      *shadowaead_2022.RelayService[int]
    38  }
    39  
    40  func NewRelayServer(ctx context.Context, config *RelayServerConfig) (*RelayInbound, error) {
    41  	networks := config.Network
    42  	if len(networks) == 0 {
    43  		networks = []net.Network{
    44  			net.Network_TCP,
    45  			net.Network_UDP,
    46  		}
    47  	}
    48  	inbound := &RelayInbound{
    49  		networks:     networks,
    50  		destinations: config.Destinations,
    51  	}
    52  	if !C.Contains(shadowaead_2022.List, config.Method) || !strings.Contains(config.Method, "aes") {
    53  		return nil, newError("unsupported method ", config.Method)
    54  	}
    55  	service, err := shadowaead_2022.NewRelayServiceWithPassword[int](config.Method, config.Key, 500, inbound)
    56  	if err != nil {
    57  		return nil, newError("create service").Base(err)
    58  	}
    59  
    60  	for i, destination := range config.Destinations {
    61  		if destination.Email == "" {
    62  			u := uuid.New()
    63  			destination.Email = "unnamed-destination-" + strconv.Itoa(i) + "-" + u.String()
    64  		}
    65  	}
    66  	err = service.UpdateUsersWithPasswords(
    67  		C.MapIndexed(config.Destinations, func(index int, it *RelayDestination) int { return index }),
    68  		C.Map(config.Destinations, func(it *RelayDestination) string { return it.Key }),
    69  		C.Map(config.Destinations, func(it *RelayDestination) M.Socksaddr {
    70  			return singbridge.ToSocksaddr(net.Destination{
    71  				Address: it.Address.AsAddress(),
    72  				Port:    net.Port(it.Port),
    73  			})
    74  		}),
    75  	)
    76  	if err != nil {
    77  		return nil, newError("create service").Base(err)
    78  	}
    79  	inbound.service = service
    80  	return inbound, nil
    81  }
    82  
    83  func (i *RelayInbound) Network() []net.Network {
    84  	return i.networks
    85  }
    86  
    87  func (i *RelayInbound) Process(ctx context.Context, network net.Network, connection stat.Connection, dispatcher routing.Dispatcher) error {
    88  	inbound := session.InboundFromContext(ctx)
    89  	inbound.Name = "shadowsocks-2022-relay"
    90  	inbound.SetCanSpliceCopy(3)
    91  
    92  	var metadata M.Metadata
    93  	if inbound.Source.IsValid() {
    94  		metadata.Source = M.ParseSocksaddr(inbound.Source.NetAddr())
    95  	}
    96  
    97  	ctx = session.ContextWithDispatcher(ctx, dispatcher)
    98  
    99  	if network == net.Network_TCP {
   100  		return singbridge.ReturnError(i.service.NewConnection(ctx, connection, metadata))
   101  	} else {
   102  		reader := buf.NewReader(connection)
   103  		pc := &natPacketConn{connection}
   104  		for {
   105  			mb, err := reader.ReadMultiBuffer()
   106  			if err != nil {
   107  				buf.ReleaseMulti(mb)
   108  				return singbridge.ReturnError(err)
   109  			}
   110  			for _, buffer := range mb {
   111  				packet := B.As(buffer.Bytes()).ToOwned()
   112  				buffer.Release()
   113  				err = i.service.NewPacket(ctx, pc, packet, metadata)
   114  				if err != nil {
   115  					packet.Release()
   116  					buf.ReleaseMulti(mb)
   117  					return err
   118  				}
   119  			}
   120  		}
   121  	}
   122  }
   123  
   124  func (i *RelayInbound) NewConnection(ctx context.Context, conn net.Conn, metadata M.Metadata) error {
   125  	inbound := session.InboundFromContext(ctx)
   126  	userInt, _ := A.UserFromContext[int](ctx)
   127  	user := i.destinations[userInt]
   128  	inbound.User = &protocol.MemoryUser{
   129  		Email: user.Email,
   130  		Level: uint32(user.Level),
   131  	}
   132  	ctx = log.ContextWithAccessMessage(ctx, &log.AccessMessage{
   133  		From:   metadata.Source,
   134  		To:     metadata.Destination,
   135  		Status: log.AccessAccepted,
   136  		Email:  user.Email,
   137  	})
   138  	newError("tunnelling request to tcp:", metadata.Destination).WriteToLog(session.ExportIDToError(ctx))
   139  	dispatcher := session.DispatcherFromContext(ctx)
   140  	link, err := dispatcher.Dispatch(ctx, singbridge.ToDestination(metadata.Destination, net.Network_TCP))
   141  	if err != nil {
   142  		return err
   143  	}
   144  	return singbridge.CopyConn(ctx, nil, link, conn)
   145  }
   146  
   147  func (i *RelayInbound) NewPacketConnection(ctx context.Context, conn N.PacketConn, metadata M.Metadata) error {
   148  	inbound := session.InboundFromContext(ctx)
   149  	userInt, _ := A.UserFromContext[int](ctx)
   150  	user := i.destinations[userInt]
   151  	inbound.User = &protocol.MemoryUser{
   152  		Email: user.Email,
   153  		Level: uint32(user.Level),
   154  	}
   155  	ctx = log.ContextWithAccessMessage(ctx, &log.AccessMessage{
   156  		From:   metadata.Source,
   157  		To:     metadata.Destination,
   158  		Status: log.AccessAccepted,
   159  		Email:  user.Email,
   160  	})
   161  	newError("tunnelling request to udp:", metadata.Destination).WriteToLog(session.ExportIDToError(ctx))
   162  	dispatcher := session.DispatcherFromContext(ctx)
   163  	destination := singbridge.ToDestination(metadata.Destination, net.Network_UDP)
   164  	link, err := dispatcher.Dispatch(ctx, destination)
   165  	if err != nil {
   166  		return err
   167  	}
   168  	outConn := &singbridge.PacketConnWrapper{
   169  		Reader: link.Reader,
   170  		Writer: link.Writer,
   171  		Dest:   destination,
   172  	}
   173  	return bufio.CopyPacketConn(ctx, conn, outConn)
   174  }
   175  
   176  func (i *RelayInbound) NewError(ctx context.Context, err error) {
   177  	if E.IsClosed(err) {
   178  		return
   179  	}
   180  	newError(err).AtWarning().WriteToLog()
   181  }