github.com/sagernet/sing-box@v1.2.7/inbound/http.go (about)

     1  package inbound
     2  
     3  import (
     4  	std_bufio "bufio"
     5  	"context"
     6  	"net"
     7  	"os"
     8  
     9  	"github.com/sagernet/sing-box/adapter"
    10  	"github.com/sagernet/sing-box/common/tls"
    11  	C "github.com/sagernet/sing-box/constant"
    12  	"github.com/sagernet/sing-box/log"
    13  	"github.com/sagernet/sing-box/option"
    14  	"github.com/sagernet/sing/common"
    15  	"github.com/sagernet/sing/common/auth"
    16  	E "github.com/sagernet/sing/common/exceptions"
    17  	N "github.com/sagernet/sing/common/network"
    18  	"github.com/sagernet/sing/protocol/http"
    19  )
    20  
    21  var (
    22  	_ adapter.Inbound           = (*HTTP)(nil)
    23  	_ adapter.InjectableInbound = (*HTTP)(nil)
    24  )
    25  
    26  type HTTP struct {
    27  	myInboundAdapter
    28  	authenticator auth.Authenticator
    29  	tlsConfig     tls.ServerConfig
    30  }
    31  
    32  func NewHTTP(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.HTTPMixedInboundOptions) (*HTTP, error) {
    33  	inbound := &HTTP{
    34  		myInboundAdapter: myInboundAdapter{
    35  			protocol:       C.TypeHTTP,
    36  			network:        []string{N.NetworkTCP},
    37  			ctx:            ctx,
    38  			router:         router,
    39  			logger:         logger,
    40  			tag:            tag,
    41  			listenOptions:  options.ListenOptions,
    42  			setSystemProxy: options.SetSystemProxy,
    43  		},
    44  		authenticator: auth.NewAuthenticator(options.Users),
    45  	}
    46  	if options.TLS != nil {
    47  		tlsConfig, err := tls.NewServer(ctx, router, logger, common.PtrValueOrDefault(options.TLS))
    48  		if err != nil {
    49  			return nil, err
    50  		}
    51  		inbound.tlsConfig = tlsConfig
    52  	}
    53  	inbound.connHandler = inbound
    54  	return inbound, nil
    55  }
    56  
    57  func (h *HTTP) Start() error {
    58  	if h.tlsConfig != nil {
    59  		err := h.tlsConfig.Start()
    60  		if err != nil {
    61  			return E.Cause(err, "create TLS config")
    62  		}
    63  	}
    64  	return h.myInboundAdapter.Start()
    65  }
    66  
    67  func (h *HTTP) Close() error {
    68  	return common.Close(
    69  		&h.myInboundAdapter,
    70  		h.tlsConfig,
    71  	)
    72  }
    73  
    74  func (h *HTTP) NewConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext) error {
    75  	var err error
    76  	if h.tlsConfig != nil {
    77  		conn, err = tls.ServerHandshake(ctx, conn, h.tlsConfig)
    78  		if err != nil {
    79  			return err
    80  		}
    81  	}
    82  	return http.HandleConnection(ctx, conn, std_bufio.NewReader(conn), h.authenticator, h.upstreamUserHandler(metadata), adapter.UpstreamMetadata(metadata))
    83  }
    84  
    85  func (h *HTTP) NewPacketConnection(ctx context.Context, conn N.PacketConn, metadata adapter.InboundContext) error {
    86  	return os.ErrInvalid
    87  }
    88  
    89  func (a *myInboundAdapter) upstreamUserHandler(metadata adapter.InboundContext) adapter.UpstreamHandlerAdapter {
    90  	return adapter.NewUpstreamHandler(metadata, a.newUserConnection, a.streamUserPacketConnection, a)
    91  }
    92  
    93  func (a *myInboundAdapter) newUserConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext) error {
    94  	user, loaded := auth.UserFromContext[string](ctx)
    95  	if !loaded {
    96  		a.logger.InfoContext(ctx, "inbound connection to ", metadata.Destination)
    97  		return a.router.RouteConnection(ctx, conn, metadata)
    98  	}
    99  	metadata.User = user
   100  	a.logger.InfoContext(ctx, "[", user, "] inbound connection to ", metadata.Destination)
   101  	return a.router.RouteConnection(ctx, conn, metadata)
   102  }
   103  
   104  func (a *myInboundAdapter) streamUserPacketConnection(ctx context.Context, conn N.PacketConn, metadata adapter.InboundContext) error {
   105  	user, loaded := auth.UserFromContext[string](ctx)
   106  	if !loaded {
   107  		a.logger.InfoContext(ctx, "inbound packet connection to ", metadata.Destination)
   108  		return a.router.RoutePacketConnection(ctx, conn, metadata)
   109  	}
   110  	metadata.User = user
   111  	a.logger.InfoContext(ctx, "[", user, "] inbound packet connection to ", metadata.Destination)
   112  	return a.router.RoutePacketConnection(ctx, conn, metadata)
   113  }