| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135 |
- // Package proxy contains all proxies used by Xray.
- //
- // To implement an inbound or outbound proxy, one needs to do the following:
- // 1. Implement the interface(s) below.
- // 2. Register a config creator through common.RegisterConfig.
- package proxy
- import (
- "context"
- gotls "crypto/tls"
- "io"
- "runtime"
- "github.com/pires/go-proxyproto"
- "github.com/xtls/xray-core/common/buf"
- "github.com/xtls/xray-core/common/errors"
- "github.com/xtls/xray-core/common/net"
- "github.com/xtls/xray-core/common/protocol"
- "github.com/xtls/xray-core/common/session"
- "github.com/xtls/xray-core/common/signal"
- "github.com/xtls/xray-core/features/routing"
- "github.com/xtls/xray-core/features/stats"
- "github.com/xtls/xray-core/transport"
- "github.com/xtls/xray-core/transport/internet"
- "github.com/xtls/xray-core/transport/internet/reality"
- "github.com/xtls/xray-core/transport/internet/stat"
- "github.com/xtls/xray-core/transport/internet/tls"
- )
- // An Inbound processes inbound connections.
- type Inbound interface {
- // Network returns a list of networks that this inbound supports. Connections with not-supported networks will not be passed into Process().
- Network() []net.Network
- // Process processes a connection of given network. If necessary, the Inbound can dispatch the connection to an Outbound.
- Process(context.Context, net.Network, stat.Connection, routing.Dispatcher) error
- }
- // An Outbound process outbound connections.
- type Outbound interface {
- // Process processes the given connection. The given dialer may be used to dial a system outbound connection.
- Process(context.Context, *transport.Link, internet.Dialer) error
- }
- // UserManager is the interface for Inbounds and Outbounds that can manage their users.
- type UserManager interface {
- // AddUser adds a new user.
- AddUser(context.Context, *protocol.MemoryUser) error
- // RemoveUser removes a user by email.
- RemoveUser(context.Context, string) error
- }
- type GetInbound interface {
- GetInbound() Inbound
- }
- type GetOutbound interface {
- GetOutbound() Outbound
- }
- // UnwrapRawConn support unwrap stats, tls, utls, reality and proxyproto conn and get raw tcp conn from it
- func UnwrapRawConn(conn net.Conn) (net.Conn, stats.Counter, stats.Counter) {
- var readCounter, writerCounter stats.Counter
- if conn != nil {
- statConn, ok := conn.(*stat.CounterConnection)
- if ok {
- conn = statConn.Connection
- readCounter = statConn.ReadCounter
- writerCounter = statConn.WriteCounter
- }
- if xc, ok := conn.(*gotls.Conn); ok {
- conn = xc.NetConn()
- } else if utlsConn, ok := conn.(*tls.UConn); ok {
- conn = utlsConn.NetConn()
- } else if realityConn, ok := conn.(*reality.Conn); ok {
- conn = realityConn.NetConn()
- } else if realityUConn, ok := conn.(*reality.UConn); ok {
- conn = realityUConn.NetConn()
- }
- if pc, ok := conn.(*proxyproto.Conn); ok {
- conn = pc.Raw()
- // 8192 > 4096, there is no need to process pc's bufReader
- }
- }
- return conn, readCounter, writerCounter
- }
- // CopyRawConnIfExist use the most efficient copy method.
- // - If caller don't want to turn on splice, do not pass in both reader conn and writer conn
- // - writer are from *transport.Link
- func CopyRawConnIfExist(ctx context.Context, readerConn net.Conn, writerConn net.Conn, writer buf.Writer, timer signal.ActivityUpdater) error {
- readerConn, readCounter, _ := UnwrapRawConn(readerConn)
- writerConn, _, writeCounter := UnwrapRawConn(writerConn)
- reader := buf.NewReader(readerConn)
- if inbound := session.InboundFromContext(ctx); inbound != nil {
- if tc, ok := writerConn.(*net.TCPConn); ok && readerConn != nil && writerConn != nil && (runtime.GOOS == "linux" || runtime.GOOS == "android") {
- for inbound.CanSpliceCopy != 3 {
- if inbound.CanSpliceCopy == 1 {
- newError("CopyRawConn splice").WriteToLog(session.ExportIDToError(ctx))
- runtime.Gosched() // necessary
- w, err := tc.ReadFrom(readerConn)
- if readCounter != nil {
- readCounter.Add(w)
- }
- if writeCounter != nil {
- writeCounter.Add(w)
- }
- if err != nil && errors.Cause(err) != io.EOF {
- return err
- }
- return nil
- }
- buffer, err := reader.ReadMultiBuffer()
- if !buffer.IsEmpty() {
- if readCounter != nil {
- readCounter.Add(int64(buffer.Len()))
- }
- timer.Update()
- if werr := writer.WriteMultiBuffer(buffer); werr != nil {
- return werr
- }
- }
- if err != nil {
- return err
- }
- }
- }
- }
- newError("CopyRawConn readv").WriteToLog(session.ExportIDToError(ctx))
- if err := buf.Copy(reader, writer, buf.UpdateActivity(timer), buf.AddToStatCounter(readCounter)); err != nil {
- return newError("failed to process response").Base(err)
- }
- return nil
- }
|