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 }