github.com/xmplusdev/xray-core@v1.8.10/proxy/vless/outbound/outbound.go (about)

     1  package outbound
     2  
     3  //go:generate go run github.com/xmplusdev/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/xmplusdev/xray-core/common"
    15  	"github.com/xmplusdev/xray-core/common/buf"
    16  	"github.com/xmplusdev/xray-core/common/net"
    17  	"github.com/xmplusdev/xray-core/common/protocol"
    18  	"github.com/xmplusdev/xray-core/common/retry"
    19  	"github.com/xmplusdev/xray-core/common/session"
    20  	"github.com/xmplusdev/xray-core/common/signal"
    21  	"github.com/xmplusdev/xray-core/common/task"
    22  	"github.com/xmplusdev/xray-core/common/xudp"
    23  	"github.com/xmplusdev/xray-core/core"
    24  	"github.com/xmplusdev/xray-core/features/policy"
    25  	"github.com/xmplusdev/xray-core/proxy"
    26  	"github.com/xmplusdev/xray-core/proxy/vless"
    27  	"github.com/xmplusdev/xray-core/proxy/vless/encoding"
    28  	"github.com/xmplusdev/xray-core/transport"
    29  	"github.com/xmplusdev/xray-core/transport/internet"
    30  	"github.com/xmplusdev/xray-core/transport/internet/reality"
    31  	"github.com/xmplusdev/xray-core/transport/internet/stat"
    32  	"github.com/xmplusdev/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  	outbound := session.OutboundFromContext(ctx)
    74  	if outbound == nil || !outbound.Target.IsValid() {
    75  		return newError("target not specified").AtError()
    76  	}
    77  	outbound.Name = "vless"
    78  	inbound := session.InboundFromContext(ctx)
    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 := outbound.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  		if inbound != nil {
   134  			inbound.SetCanSpliceCopy(2)
   135  		}
   136  		switch request.Command {
   137  		case protocol.RequestCommandUDP:
   138  			if !allowUDP443 && request.Port == 443 {
   139  				return newError("XTLS rejected UDP/443 traffic").AtInfo()
   140  			}
   141  		case protocol.RequestCommandMux:
   142  			fallthrough // let server break Mux connections that contain TCP requests
   143  		case protocol.RequestCommandTCP:
   144  			var t reflect.Type
   145  			var p uintptr
   146  			if tlsConn, ok := iConn.(*tls.Conn); ok {
   147  				t = reflect.TypeOf(tlsConn.Conn).Elem()
   148  				p = uintptr(unsafe.Pointer(tlsConn.Conn))
   149  			} else if utlsConn, ok := iConn.(*tls.UConn); ok {
   150  				t = reflect.TypeOf(utlsConn.Conn).Elem()
   151  				p = uintptr(unsafe.Pointer(utlsConn.Conn))
   152  			} else if realityConn, ok := iConn.(*reality.UConn); ok {
   153  				t = reflect.TypeOf(realityConn.Conn).Elem()
   154  				p = uintptr(unsafe.Pointer(realityConn.Conn))
   155  			} else {
   156  				return newError("XTLS only supports TLS and REALITY directly for now.").AtWarning()
   157  			}
   158  			i, _ := t.FieldByName("input")
   159  			r, _ := t.FieldByName("rawInput")
   160  			input = (*bytes.Reader)(unsafe.Pointer(p + i.Offset))
   161  			rawInput = (*bytes.Buffer)(unsafe.Pointer(p + r.Offset))
   162  		}
   163  	default:
   164  		if inbound != nil {
   165  			inbound.SetCanSpliceCopy(3)
   166  		}
   167  	}
   168  
   169  	var newCtx context.Context
   170  	var newCancel context.CancelFunc
   171  	if session.TimeoutOnlyFromContext(ctx) {
   172  		newCtx, newCancel = context.WithCancel(context.Background())
   173  	}
   174  
   175  	sessionPolicy := h.policyManager.ForLevel(request.User.Level)
   176  	ctx, cancel := context.WithCancel(ctx)
   177  	timer := signal.CancelAfterInactivity(ctx, func() {
   178  		cancel()
   179  		if newCancel != nil {
   180  			newCancel()
   181  		}
   182  	}, sessionPolicy.Timeouts.ConnectionIdle)
   183  
   184  	clientReader := link.Reader // .(*pipe.Reader)
   185  	clientWriter := link.Writer // .(*pipe.Writer)
   186  	trafficState := proxy.NewTrafficState(account.ID.Bytes())
   187  	if request.Command == protocol.RequestCommandUDP && (requestAddons.Flow == vless.XRV || (h.cone && request.Port != 53 && request.Port != 443)) {
   188  		request.Command = protocol.RequestCommandMux
   189  		request.Address = net.DomainAddress("v1.mux.cool")
   190  		request.Port = net.Port(666)
   191  	}
   192  
   193  	postRequest := func() error {
   194  		defer timer.SetTimeout(sessionPolicy.Timeouts.DownlinkOnly)
   195  
   196  		bufferWriter := buf.NewBufferedWriter(buf.NewWriter(conn))
   197  		if err := encoding.EncodeRequestHeader(bufferWriter, request, requestAddons); err != nil {
   198  			return newError("failed to encode request header").Base(err).AtWarning()
   199  		}
   200  
   201  		// default: serverWriter := bufferWriter
   202  		serverWriter := encoding.EncodeBodyAddons(bufferWriter, request, requestAddons, trafficState, ctx)
   203  		if request.Command == protocol.RequestCommandMux && request.Port == 666 {
   204  			serverWriter = xudp.NewPacketWriter(serverWriter, target, xudp.GetGlobalID(ctx))
   205  		}
   206  		timeoutReader, ok := clientReader.(buf.TimeoutReader)
   207  		if ok {
   208  			multiBuffer, err1 := timeoutReader.ReadMultiBufferTimeout(time.Millisecond * 500)
   209  			if err1 == nil {
   210  				if err := serverWriter.WriteMultiBuffer(multiBuffer); err != nil {
   211  					return err // ...
   212  				}
   213  			} else if err1 != buf.ErrReadTimeout {
   214  				return err1
   215  			} else if requestAddons.Flow == vless.XRV {
   216  				mb := make(buf.MultiBuffer, 1)
   217  				newError("Insert padding with empty content to camouflage VLESS header ", mb.Len()).WriteToLog(session.ExportIDToError(ctx))
   218  				if err := serverWriter.WriteMultiBuffer(mb); err != nil {
   219  					return err // ...
   220  				}
   221  			}
   222  		} else {
   223  			newError("Reader is not timeout reader, will send out vless header separately from first payload").AtDebug().WriteToLog(session.ExportIDToError(ctx))
   224  		}
   225  		// Flush; bufferWriter.WriteMultiBufer now is bufferWriter.writer.WriteMultiBuffer
   226  		if err := bufferWriter.SetBuffered(false); err != nil {
   227  			return newError("failed to write A request payload").Base(err).AtWarning()
   228  		}
   229  
   230  		var err error
   231  		if requestAddons.Flow == vless.XRV {
   232  			if tlsConn, ok := iConn.(*tls.Conn); ok {
   233  				if tlsConn.ConnectionState().Version != gotls.VersionTLS13 {
   234  					return newError(`failed to use `+requestAddons.Flow+`, found outer tls version `, tlsConn.ConnectionState().Version).AtWarning()
   235  				}
   236  			} else if utlsConn, ok := iConn.(*tls.UConn); ok {
   237  				if utlsConn.ConnectionState().Version != utls.VersionTLS13 {
   238  					return newError(`failed to use `+requestAddons.Flow+`, found outer tls version `, utlsConn.ConnectionState().Version).AtWarning()
   239  				}
   240  			}
   241  			ctx1 := session.ContextWithOutbound(ctx, nil) // TODO enable splice
   242  			err = encoding.XtlsWrite(clientReader, serverWriter, timer, conn, trafficState, ctx1)
   243  		} else {
   244  			// from clientReader.ReadMultiBuffer to serverWriter.WriteMultiBufer
   245  			err = buf.Copy(clientReader, serverWriter, buf.UpdateActivity(timer))
   246  		}
   247  		if err != nil {
   248  			return newError("failed to transfer request payload").Base(err).AtInfo()
   249  		}
   250  
   251  		// Indicates the end of request payload.
   252  		switch requestAddons.Flow {
   253  		default:
   254  		}
   255  		return nil
   256  	}
   257  
   258  	getResponse := func() error {
   259  		defer timer.SetTimeout(sessionPolicy.Timeouts.UplinkOnly)
   260  
   261  		responseAddons, err := encoding.DecodeResponseHeader(conn, request)
   262  		if err != nil {
   263  			return newError("failed to decode response header").Base(err).AtInfo()
   264  		}
   265  
   266  		// default: serverReader := buf.NewReader(conn)
   267  		serverReader := encoding.DecodeBodyAddons(conn, request, responseAddons)
   268  		if requestAddons.Flow == vless.XRV {
   269  			serverReader = proxy.NewVisionReader(serverReader, trafficState, ctx)
   270  		}
   271  		if request.Command == protocol.RequestCommandMux && request.Port == 666 {
   272  			if requestAddons.Flow == vless.XRV {
   273  				serverReader = xudp.NewPacketReader(&buf.BufferedReader{Reader: serverReader})
   274  			} else {
   275  				serverReader = xudp.NewPacketReader(conn)
   276  			}
   277  		}
   278  
   279  		if requestAddons.Flow == vless.XRV {
   280  			err = encoding.XtlsRead(serverReader, clientWriter, timer, conn, input, rawInput, trafficState, ctx)
   281  		} else {
   282  			// from serverReader.ReadMultiBuffer to clientWriter.WriteMultiBufer
   283  			err = buf.Copy(serverReader, clientWriter, buf.UpdateActivity(timer))
   284  		}
   285  
   286  		if err != nil {
   287  			return newError("failed to transfer response payload").Base(err).AtInfo()
   288  		}
   289  
   290  		return nil
   291  	}
   292  
   293  	if newCtx != nil {
   294  		ctx = newCtx
   295  	}
   296  
   297  	if err := task.Run(ctx, postRequest, task.OnSuccess(getResponse, task.Close(clientWriter))); err != nil {
   298  		return newError("connection ends").Base(err).AtInfo()
   299  	}
   300  
   301  	return nil
   302  }