github.com/xtls/xray-core@v1.8.12-0.20240518155711-3168d27b0bdb/proxy/vless/outbound/outbound.go (about)

     1  package outbound
     2  
     3  //go:generate go run github.com/xtls/xray-core/common/errors/errorgen
     4  
     5  import (
     6  	"bytes"
     7  	"context"
     8  	gotls "crypto/tls"
     9  	"reflect"
    10  	"time"
    11  	"unsafe"
    12  
    13  	utls "github.com/refraction-networking/utls"
    14  	"github.com/xtls/xray-core/common"
    15  	"github.com/xtls/xray-core/common/buf"
    16  	"github.com/xtls/xray-core/common/net"
    17  	"github.com/xtls/xray-core/common/protocol"
    18  	"github.com/xtls/xray-core/common/retry"
    19  	"github.com/xtls/xray-core/common/session"
    20  	"github.com/xtls/xray-core/common/signal"
    21  	"github.com/xtls/xray-core/common/task"
    22  	"github.com/xtls/xray-core/common/xudp"
    23  	"github.com/xtls/xray-core/core"
    24  	"github.com/xtls/xray-core/features/policy"
    25  	"github.com/xtls/xray-core/proxy"
    26  	"github.com/xtls/xray-core/proxy/vless"
    27  	"github.com/xtls/xray-core/proxy/vless/encoding"
    28  	"github.com/xtls/xray-core/transport"
    29  	"github.com/xtls/xray-core/transport/internet"
    30  	"github.com/xtls/xray-core/transport/internet/reality"
    31  	"github.com/xtls/xray-core/transport/internet/stat"
    32  	"github.com/xtls/xray-core/transport/internet/tls"
    33  )
    34  
    35  func init() {
    36  	common.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
    37  		return New(ctx, config.(*Config))
    38  	}))
    39  }
    40  
    41  // Handler is an outbound connection handler for VLess protocol.
    42  type Handler struct {
    43  	serverList    *protocol.ServerList
    44  	serverPicker  protocol.ServerPicker
    45  	policyManager policy.Manager
    46  	cone          bool
    47  }
    48  
    49  // New creates a new VLess outbound handler.
    50  func New(ctx context.Context, config *Config) (*Handler, error) {
    51  	serverList := protocol.NewServerList()
    52  	for _, rec := range config.Vnext {
    53  		s, err := protocol.NewServerSpecFromPB(rec)
    54  		if err != nil {
    55  			return nil, newError("failed to parse server spec").Base(err).AtError()
    56  		}
    57  		serverList.AddServer(s)
    58  	}
    59  
    60  	v := core.MustFromContext(ctx)
    61  	handler := &Handler{
    62  		serverList:    serverList,
    63  		serverPicker:  protocol.NewRoundRobinServerPicker(serverList),
    64  		policyManager: v.GetFeature(policy.ManagerType()).(policy.Manager),
    65  		cone:          ctx.Value("cone").(bool),
    66  	}
    67  
    68  	return handler, nil
    69  }
    70  
    71  // Process implements proxy.Outbound.Process().
    72  func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer internet.Dialer) error {
    73  	outbounds := session.OutboundsFromContext(ctx)
    74  	ob := outbounds[len(outbounds) - 1]
    75  	if !ob.Target.IsValid() {
    76  		return newError("target not specified").AtError()
    77  	}
    78  	ob.Name = "vless"
    79  
    80  	var rec *protocol.ServerSpec
    81  	var conn stat.Connection
    82  	if err := retry.ExponentialBackoff(5, 200).On(func() error {
    83  		rec = h.serverPicker.PickServer()
    84  		var err error
    85  		conn, err = dialer.Dial(ctx, rec.Destination())
    86  		if err != nil {
    87  			return err
    88  		}
    89  		return nil
    90  	}); err != nil {
    91  		return newError("failed to find an available destination").Base(err).AtWarning()
    92  	}
    93  	defer conn.Close()
    94  
    95  	iConn := conn
    96  	if statConn, ok := iConn.(*stat.CounterConnection); ok {
    97  		iConn = statConn.Connection
    98  	}
    99  	target := ob.Target
   100  	newError("tunneling request to ", target, " via ", rec.Destination().NetAddr()).AtInfo().WriteToLog(session.ExportIDToError(ctx))
   101  
   102  	command := protocol.RequestCommandTCP
   103  	if target.Network == net.Network_UDP {
   104  		command = protocol.RequestCommandUDP
   105  	}
   106  	if target.Address.Family().IsDomain() && target.Address.Domain() == "v1.mux.cool" {
   107  		command = protocol.RequestCommandMux
   108  	}
   109  
   110  	request := &protocol.RequestHeader{
   111  		Version: encoding.Version,
   112  		User:    rec.PickUser(),
   113  		Command: command,
   114  		Address: target.Address,
   115  		Port:    target.Port,
   116  	}
   117  
   118  	account := request.User.Account.(*vless.MemoryAccount)
   119  
   120  	requestAddons := &encoding.Addons{
   121  		Flow: account.Flow,
   122  	}
   123  
   124  	var input *bytes.Reader
   125  	var rawInput *bytes.Buffer
   126  	allowUDP443 := false
   127  	switch requestAddons.Flow {
   128  	case vless.XRV + "-udp443":
   129  		allowUDP443 = true
   130  		requestAddons.Flow = requestAddons.Flow[:16]
   131  		fallthrough
   132  	case vless.XRV:
   133  		ob.CanSpliceCopy = 2
   134  		switch request.Command {
   135  		case protocol.RequestCommandUDP:
   136  			if !allowUDP443 && request.Port == 443 {
   137  				return newError("XTLS rejected UDP/443 traffic").AtInfo()
   138  			}
   139  		case protocol.RequestCommandMux:
   140  			fallthrough // let server break Mux connections that contain TCP requests
   141  		case protocol.RequestCommandTCP:
   142  			var t reflect.Type
   143  			var p uintptr
   144  			if tlsConn, ok := iConn.(*tls.Conn); ok {
   145  				t = reflect.TypeOf(tlsConn.Conn).Elem()
   146  				p = uintptr(unsafe.Pointer(tlsConn.Conn))
   147  			} else if utlsConn, ok := iConn.(*tls.UConn); ok {
   148  				t = reflect.TypeOf(utlsConn.Conn).Elem()
   149  				p = uintptr(unsafe.Pointer(utlsConn.Conn))
   150  			} else if realityConn, ok := iConn.(*reality.UConn); ok {
   151  				t = reflect.TypeOf(realityConn.Conn).Elem()
   152  				p = uintptr(unsafe.Pointer(realityConn.Conn))
   153  			} else {
   154  				return newError("XTLS only supports TLS and REALITY directly for now.").AtWarning()
   155  			}
   156  			i, _ := t.FieldByName("input")
   157  			r, _ := t.FieldByName("rawInput")
   158  			input = (*bytes.Reader)(unsafe.Pointer(p + i.Offset))
   159  			rawInput = (*bytes.Buffer)(unsafe.Pointer(p + r.Offset))
   160  		}
   161  	default:
   162  		ob.CanSpliceCopy = 3
   163  	}
   164  
   165  	var newCtx context.Context
   166  	var newCancel context.CancelFunc
   167  	if session.TimeoutOnlyFromContext(ctx) {
   168  		newCtx, newCancel = context.WithCancel(context.Background())
   169  	}
   170  
   171  	sessionPolicy := h.policyManager.ForLevel(request.User.Level)
   172  	ctx, cancel := context.WithCancel(ctx)
   173  	timer := signal.CancelAfterInactivity(ctx, func() {
   174  		cancel()
   175  		if newCancel != nil {
   176  			newCancel()
   177  		}
   178  	}, sessionPolicy.Timeouts.ConnectionIdle)
   179  
   180  	clientReader := link.Reader // .(*pipe.Reader)
   181  	clientWriter := link.Writer // .(*pipe.Writer)
   182  	trafficState := proxy.NewTrafficState(account.ID.Bytes())
   183  	if request.Command == protocol.RequestCommandUDP && (requestAddons.Flow == vless.XRV || (h.cone && request.Port != 53 && request.Port != 443)) {
   184  		request.Command = protocol.RequestCommandMux
   185  		request.Address = net.DomainAddress("v1.mux.cool")
   186  		request.Port = net.Port(666)
   187  	}
   188  
   189  	postRequest := func() error {
   190  		defer timer.SetTimeout(sessionPolicy.Timeouts.DownlinkOnly)
   191  
   192  		bufferWriter := buf.NewBufferedWriter(buf.NewWriter(conn))
   193  		if err := encoding.EncodeRequestHeader(bufferWriter, request, requestAddons); err != nil {
   194  			return newError("failed to encode request header").Base(err).AtWarning()
   195  		}
   196  
   197  		// default: serverWriter := bufferWriter
   198  		serverWriter := encoding.EncodeBodyAddons(bufferWriter, request, requestAddons, trafficState, ctx)
   199  		if request.Command == protocol.RequestCommandMux && request.Port == 666 {
   200  			serverWriter = xudp.NewPacketWriter(serverWriter, target, xudp.GetGlobalID(ctx))
   201  		}
   202  		timeoutReader, ok := clientReader.(buf.TimeoutReader)
   203  		if ok {
   204  			multiBuffer, err1 := timeoutReader.ReadMultiBufferTimeout(time.Millisecond * 500)
   205  			if err1 == nil {
   206  				if err := serverWriter.WriteMultiBuffer(multiBuffer); err != nil {
   207  					return err // ...
   208  				}
   209  			} else if err1 != buf.ErrReadTimeout {
   210  				return err1
   211  			} else if requestAddons.Flow == vless.XRV {
   212  				mb := make(buf.MultiBuffer, 1)
   213  				newError("Insert padding with empty content to camouflage VLESS header ", mb.Len()).WriteToLog(session.ExportIDToError(ctx))
   214  				if err := serverWriter.WriteMultiBuffer(mb); err != nil {
   215  					return err // ...
   216  				}
   217  			}
   218  		} else {
   219  			newError("Reader is not timeout reader, will send out vless header separately from first payload").AtDebug().WriteToLog(session.ExportIDToError(ctx))
   220  		}
   221  		// Flush; bufferWriter.WriteMultiBufer now is bufferWriter.writer.WriteMultiBuffer
   222  		if err := bufferWriter.SetBuffered(false); err != nil {
   223  			return newError("failed to write A request payload").Base(err).AtWarning()
   224  		}
   225  
   226  		var err error
   227  		if requestAddons.Flow == vless.XRV {
   228  			if tlsConn, ok := iConn.(*tls.Conn); ok {
   229  				if tlsConn.ConnectionState().Version != gotls.VersionTLS13 {
   230  					return newError(`failed to use `+requestAddons.Flow+`, found outer tls version `, tlsConn.ConnectionState().Version).AtWarning()
   231  				}
   232  			} else if utlsConn, ok := iConn.(*tls.UConn); ok {
   233  				if utlsConn.ConnectionState().Version != utls.VersionTLS13 {
   234  					return newError(`failed to use `+requestAddons.Flow+`, found outer tls version `, utlsConn.ConnectionState().Version).AtWarning()
   235  				}
   236  			}
   237  			ctx1 := session.ContextWithInbound(ctx, nil) // TODO enable splice
   238  			err = encoding.XtlsWrite(clientReader, serverWriter, timer, conn, trafficState, ob, ctx1)
   239  		} else {
   240  			// from clientReader.ReadMultiBuffer to serverWriter.WriteMultiBufer
   241  			err = buf.Copy(clientReader, serverWriter, buf.UpdateActivity(timer))
   242  		}
   243  		if err != nil {
   244  			return newError("failed to transfer request payload").Base(err).AtInfo()
   245  		}
   246  
   247  		// Indicates the end of request payload.
   248  		switch requestAddons.Flow {
   249  		default:
   250  		}
   251  		return nil
   252  	}
   253  
   254  	getResponse := func() error {
   255  		defer timer.SetTimeout(sessionPolicy.Timeouts.UplinkOnly)
   256  
   257  		responseAddons, err := encoding.DecodeResponseHeader(conn, request)
   258  		if err != nil {
   259  			return newError("failed to decode response header").Base(err).AtInfo()
   260  		}
   261  
   262  		// default: serverReader := buf.NewReader(conn)
   263  		serverReader := encoding.DecodeBodyAddons(conn, request, responseAddons)
   264  		if requestAddons.Flow == vless.XRV {
   265  			serverReader = proxy.NewVisionReader(serverReader, trafficState, ctx)
   266  		}
   267  		if request.Command == protocol.RequestCommandMux && request.Port == 666 {
   268  			if requestAddons.Flow == vless.XRV {
   269  				serverReader = xudp.NewPacketReader(&buf.BufferedReader{Reader: serverReader})
   270  			} else {
   271  				serverReader = xudp.NewPacketReader(conn)
   272  			}
   273  		}
   274  
   275  		if requestAddons.Flow == vless.XRV {
   276  			err = encoding.XtlsRead(serverReader, clientWriter, timer, conn, input, rawInput, trafficState, ob, ctx)
   277  		} else {
   278  			// from serverReader.ReadMultiBuffer to clientWriter.WriteMultiBufer
   279  			err = buf.Copy(serverReader, clientWriter, buf.UpdateActivity(timer))
   280  		}
   281  
   282  		if err != nil {
   283  			return newError("failed to transfer response payload").Base(err).AtInfo()
   284  		}
   285  
   286  		return nil
   287  	}
   288  
   289  	if newCtx != nil {
   290  		ctx = newCtx
   291  	}
   292  
   293  	if err := task.Run(ctx, postRequest, task.OnSuccess(getResponse, task.Close(clientWriter))); err != nil {
   294  		return newError("connection ends").Base(err).AtInfo()
   295  	}
   296  
   297  	return nil
   298  }