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