github.com/sagernet/sing-box@v1.9.0-rc.20/inbound/tuic.go (about)

     1  //go:build with_quic
     2  
     3  package inbound
     4  
     5  import (
     6  	"context"
     7  	"net"
     8  	"time"
     9  
    10  	"github.com/sagernet/sing-box/adapter"
    11  	"github.com/sagernet/sing-box/common/tls"
    12  	"github.com/sagernet/sing-box/common/uot"
    13  	C "github.com/sagernet/sing-box/constant"
    14  	"github.com/sagernet/sing-box/log"
    15  	"github.com/sagernet/sing-box/option"
    16  	"github.com/sagernet/sing-quic/tuic"
    17  	"github.com/sagernet/sing/common"
    18  	"github.com/sagernet/sing/common/auth"
    19  	E "github.com/sagernet/sing/common/exceptions"
    20  	N "github.com/sagernet/sing/common/network"
    21  
    22  	"github.com/gofrs/uuid/v5"
    23  )
    24  
    25  var _ adapter.Inbound = (*TUIC)(nil)
    26  
    27  type TUIC struct {
    28  	myInboundAdapter
    29  	tlsConfig    tls.ServerConfig
    30  	server       *tuic.Service[int]
    31  	userNameList []string
    32  }
    33  
    34  func NewTUIC(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.TUICInboundOptions) (*TUIC, error) {
    35  	options.UDPFragmentDefault = true
    36  	if options.TLS == nil || !options.TLS.Enabled {
    37  		return nil, C.ErrTLSRequired
    38  	}
    39  	tlsConfig, err := tls.NewServer(ctx, logger, common.PtrValueOrDefault(options.TLS))
    40  	if err != nil {
    41  		return nil, err
    42  	}
    43  	inbound := &TUIC{
    44  		myInboundAdapter: myInboundAdapter{
    45  			protocol:      C.TypeTUIC,
    46  			network:       []string{N.NetworkUDP},
    47  			ctx:           ctx,
    48  			router:        uot.NewRouter(router, logger),
    49  			logger:        logger,
    50  			tag:           tag,
    51  			listenOptions: options.ListenOptions,
    52  		},
    53  		tlsConfig: tlsConfig,
    54  	}
    55  	var udpTimeout time.Duration
    56  	if options.UDPTimeout != 0 {
    57  		udpTimeout = time.Duration(options.UDPTimeout)
    58  	} else {
    59  		udpTimeout = C.UDPTimeout
    60  	}
    61  	service, err := tuic.NewService[int](tuic.ServiceOptions{
    62  		Context:           ctx,
    63  		Logger:            logger,
    64  		TLSConfig:         tlsConfig,
    65  		CongestionControl: options.CongestionControl,
    66  		AuthTimeout:       time.Duration(options.AuthTimeout),
    67  		ZeroRTTHandshake:  options.ZeroRTTHandshake,
    68  		Heartbeat:         time.Duration(options.Heartbeat),
    69  		UDPTimeout:        udpTimeout,
    70  		Handler:           adapter.NewUpstreamHandler(adapter.InboundContext{}, inbound.newConnection, inbound.newPacketConnection, nil),
    71  	})
    72  	if err != nil {
    73  		return nil, err
    74  	}
    75  	var userList []int
    76  	var userNameList []string
    77  	var userUUIDList [][16]byte
    78  	var userPasswordList []string
    79  	for index, user := range options.Users {
    80  		if user.UUID == "" {
    81  			return nil, E.New("missing uuid for user ", index)
    82  		}
    83  		userUUID, err := uuid.FromString(user.UUID)
    84  		if err != nil {
    85  			return nil, E.Cause(err, "invalid uuid for user ", index)
    86  		}
    87  		userList = append(userList, index)
    88  		userNameList = append(userNameList, user.Name)
    89  		userUUIDList = append(userUUIDList, userUUID)
    90  		userPasswordList = append(userPasswordList, user.Password)
    91  	}
    92  	service.UpdateUsers(userList, userUUIDList, userPasswordList)
    93  	inbound.server = service
    94  	inbound.userNameList = userNameList
    95  	return inbound, nil
    96  }
    97  
    98  func (h *TUIC) newConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext) error {
    99  	ctx = log.ContextWithNewID(ctx)
   100  	metadata = h.createMetadata(conn, metadata)
   101  	h.logger.InfoContext(ctx, "inbound connection from ", metadata.Source)
   102  	userID, _ := auth.UserFromContext[int](ctx)
   103  	if userName := h.userNameList[userID]; userName != "" {
   104  		metadata.User = userName
   105  		h.logger.InfoContext(ctx, "[", userName, "] inbound connection to ", metadata.Destination)
   106  	} else {
   107  		h.logger.InfoContext(ctx, "inbound connection to ", metadata.Destination)
   108  	}
   109  	return h.router.RouteConnection(ctx, conn, metadata)
   110  }
   111  
   112  func (h *TUIC) newPacketConnection(ctx context.Context, conn N.PacketConn, metadata adapter.InboundContext) error {
   113  	ctx = log.ContextWithNewID(ctx)
   114  	metadata = h.createPacketMetadata(conn, metadata)
   115  	h.logger.InfoContext(ctx, "inbound packet connection from ", metadata.Source)
   116  	userID, _ := auth.UserFromContext[int](ctx)
   117  	if userName := h.userNameList[userID]; userName != "" {
   118  		metadata.User = userName
   119  		h.logger.InfoContext(ctx, "[", userName, "] inbound packet connection to ", metadata.Destination)
   120  	} else {
   121  		h.logger.InfoContext(ctx, "inbound packet connection to ", metadata.Destination)
   122  	}
   123  	return h.router.RoutePacketConnection(ctx, conn, metadata)
   124  }
   125  
   126  func (h *TUIC) Start() error {
   127  	if h.tlsConfig != nil {
   128  		err := h.tlsConfig.Start()
   129  		if err != nil {
   130  			return err
   131  		}
   132  	}
   133  	packetConn, err := h.myInboundAdapter.ListenUDP()
   134  	if err != nil {
   135  		return err
   136  	}
   137  	return h.server.Start(packetConn)
   138  }
   139  
   140  func (h *TUIC) Close() error {
   141  	return common.Close(
   142  		&h.myInboundAdapter,
   143  		h.tlsConfig,
   144  		common.PtrOrNil(h.server),
   145  	)
   146  }