github.com/sagernet/sing-box@v1.2.7/inbound/trojan.go (about) 1 package inbound 2 3 import ( 4 "context" 5 "net" 6 "os" 7 8 "github.com/sagernet/sing-box/adapter" 9 "github.com/sagernet/sing-box/common/tls" 10 C "github.com/sagernet/sing-box/constant" 11 "github.com/sagernet/sing-box/log" 12 "github.com/sagernet/sing-box/option" 13 "github.com/sagernet/sing-box/transport/trojan" 14 "github.com/sagernet/sing-box/transport/v2ray" 15 "github.com/sagernet/sing/common" 16 "github.com/sagernet/sing/common/auth" 17 E "github.com/sagernet/sing/common/exceptions" 18 F "github.com/sagernet/sing/common/format" 19 M "github.com/sagernet/sing/common/metadata" 20 N "github.com/sagernet/sing/common/network" 21 ) 22 23 var ( 24 _ adapter.Inbound = (*Trojan)(nil) 25 _ adapter.InjectableInbound = (*Trojan)(nil) 26 ) 27 28 type Trojan struct { 29 myInboundAdapter 30 service *trojan.Service[int] 31 users []option.TrojanUser 32 tlsConfig tls.ServerConfig 33 fallbackAddr M.Socksaddr 34 fallbackAddrTLSNextProto map[string]M.Socksaddr 35 transport adapter.V2RayServerTransport 36 } 37 38 func NewTrojan(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.TrojanInboundOptions) (*Trojan, error) { 39 inbound := &Trojan{ 40 myInboundAdapter: myInboundAdapter{ 41 protocol: C.TypeTrojan, 42 network: []string{N.NetworkTCP}, 43 ctx: ctx, 44 router: router, 45 logger: logger, 46 tag: tag, 47 listenOptions: options.ListenOptions, 48 }, 49 users: options.Users, 50 } 51 if options.TLS != nil { 52 tlsConfig, err := tls.NewServer(ctx, router, logger, common.PtrValueOrDefault(options.TLS)) 53 if err != nil { 54 return nil, err 55 } 56 inbound.tlsConfig = tlsConfig 57 } 58 var fallbackHandler N.TCPConnectionHandler 59 if options.Fallback != nil && options.Fallback.Server != "" || len(options.FallbackForALPN) > 0 { 60 if options.Fallback != nil && options.Fallback.Server != "" { 61 inbound.fallbackAddr = options.Fallback.Build() 62 if !inbound.fallbackAddr.IsValid() { 63 return nil, E.New("invalid fallback address: ", inbound.fallbackAddr) 64 } 65 } 66 if len(options.FallbackForALPN) > 0 { 67 if inbound.tlsConfig == nil { 68 return nil, E.New("fallback for ALPN is not supported without TLS") 69 } 70 fallbackAddrNextProto := make(map[string]M.Socksaddr) 71 for nextProto, destination := range options.FallbackForALPN { 72 fallbackAddr := destination.Build() 73 if !fallbackAddr.IsValid() { 74 return nil, E.New("invalid fallback address for ALPN ", nextProto, ": ", fallbackAddr) 75 } 76 fallbackAddrNextProto[nextProto] = fallbackAddr 77 } 78 inbound.fallbackAddrTLSNextProto = fallbackAddrNextProto 79 } 80 fallbackHandler = adapter.NewUpstreamContextHandler(inbound.fallbackConnection, nil, nil) 81 } 82 service := trojan.NewService[int](adapter.NewUpstreamContextHandler(inbound.newConnection, inbound.newPacketConnection, inbound), fallbackHandler) 83 err := service.UpdateUsers(common.MapIndexed(options.Users, func(index int, it option.TrojanUser) int { 84 return index 85 }), common.Map(options.Users, func(it option.TrojanUser) string { 86 return it.Password 87 })) 88 if err != nil { 89 return nil, err 90 } 91 if options.Transport != nil { 92 inbound.transport, err = v2ray.NewServerTransport(ctx, common.PtrValueOrDefault(options.Transport), inbound.tlsConfig, (*trojanTransportHandler)(inbound)) 93 if err != nil { 94 return nil, E.Cause(err, "create server transport: ", options.Transport.Type) 95 } 96 } 97 inbound.service = service 98 inbound.connHandler = inbound 99 return inbound, nil 100 } 101 102 func (h *Trojan) Start() error { 103 if h.tlsConfig != nil { 104 err := h.tlsConfig.Start() 105 if err != nil { 106 return E.Cause(err, "create TLS config") 107 } 108 } 109 if h.transport == nil { 110 return h.myInboundAdapter.Start() 111 } 112 if common.Contains(h.transport.Network(), N.NetworkTCP) { 113 tcpListener, err := h.myInboundAdapter.ListenTCP() 114 if err != nil { 115 return err 116 } 117 go func() { 118 sErr := h.transport.Serve(tcpListener) 119 if sErr != nil && !E.IsClosed(sErr) { 120 h.logger.Error("transport serve error: ", sErr) 121 } 122 }() 123 } 124 if common.Contains(h.transport.Network(), N.NetworkUDP) { 125 udpConn, err := h.myInboundAdapter.ListenUDP() 126 if err != nil { 127 return err 128 } 129 go func() { 130 sErr := h.transport.ServePacket(udpConn) 131 if sErr != nil && !E.IsClosed(sErr) { 132 h.logger.Error("transport serve error: ", sErr) 133 } 134 }() 135 } 136 return nil 137 } 138 139 func (h *Trojan) Close() error { 140 return common.Close( 141 &h.myInboundAdapter, 142 h.tlsConfig, 143 h.transport, 144 ) 145 } 146 147 func (h *Trojan) newTransportConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext) error { 148 h.injectTCP(conn, metadata) 149 return nil 150 } 151 152 func (h *Trojan) NewConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext) error { 153 var err error 154 if h.tlsConfig != nil && h.transport == nil { 155 conn, err = tls.ServerHandshake(ctx, conn, h.tlsConfig) 156 if err != nil { 157 return err 158 } 159 } 160 return h.service.NewConnection(adapter.WithContext(ctx, &metadata), conn, adapter.UpstreamMetadata(metadata)) 161 } 162 163 func (h *Trojan) NewPacketConnection(ctx context.Context, conn N.PacketConn, metadata adapter.InboundContext) error { 164 return os.ErrInvalid 165 } 166 167 func (h *Trojan) newConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext) error { 168 userIndex, loaded := auth.UserFromContext[int](ctx) 169 if !loaded { 170 return os.ErrInvalid 171 } 172 user := h.users[userIndex].Name 173 if user == "" { 174 user = F.ToString(userIndex) 175 } else { 176 metadata.User = user 177 } 178 h.logger.InfoContext(ctx, "[", user, "] inbound connection to ", metadata.Destination) 179 return h.router.RouteConnection(ctx, conn, metadata) 180 } 181 182 func (h *Trojan) fallbackConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext) error { 183 var fallbackAddr M.Socksaddr 184 if len(h.fallbackAddrTLSNextProto) > 0 { 185 if tlsConn, loaded := common.Cast[tls.Conn](conn); loaded { 186 connectionState := tlsConn.ConnectionState() 187 if connectionState.NegotiatedProtocol != "" { 188 if fallbackAddr, loaded = h.fallbackAddrTLSNextProto[connectionState.NegotiatedProtocol]; !loaded { 189 return E.New("fallback disabled for ALPN: ", connectionState.NegotiatedProtocol) 190 } 191 } 192 } 193 } 194 if !fallbackAddr.IsValid() { 195 if !h.fallbackAddr.IsValid() { 196 return E.New("fallback disabled by default") 197 } 198 fallbackAddr = h.fallbackAddr 199 } 200 h.logger.InfoContext(ctx, "fallback connection to ", fallbackAddr) 201 metadata.Destination = fallbackAddr 202 return h.router.RouteConnection(ctx, conn, metadata) 203 } 204 205 func (h *Trojan) newPacketConnection(ctx context.Context, conn N.PacketConn, metadata adapter.InboundContext) error { 206 userIndex, loaded := auth.UserFromContext[int](ctx) 207 if !loaded { 208 return os.ErrInvalid 209 } 210 user := h.users[userIndex].Name 211 if user == "" { 212 user = F.ToString(userIndex) 213 } else { 214 metadata.User = user 215 } 216 h.logger.InfoContext(ctx, "[", user, "] inbound packet connection to ", metadata.Destination) 217 return h.router.RoutePacketConnection(ctx, conn, metadata) 218 } 219 220 var _ adapter.V2RayServerTransportHandler = (*trojanTransportHandler)(nil) 221 222 type trojanTransportHandler Trojan 223 224 func (t *trojanTransportHandler) NewConnection(ctx context.Context, conn net.Conn, metadata M.Metadata) error { 225 return (*Trojan)(t).newTransportConnection(ctx, conn, adapter.InboundContext{ 226 Source: metadata.Source, 227 Destination: metadata.Destination, 228 }) 229 } 230 231 func (t *trojanTransportHandler) FallbackConnection(ctx context.Context, conn net.Conn, metadata M.Metadata) error { 232 return (*Trojan)(t).fallbackConnection(ctx, conn, adapter.InboundContext{ 233 Source: metadata.Source, 234 Destination: metadata.Destination, 235 }) 236 }