github.com/v2fly/v2ray-core/v4@v4.45.2/proxy/vless/outbound/outbound.go (about)

     1  //go:build !confonly
     2  // +build !confonly
     3  
     4  package outbound
     5  
     6  //go:generate go run github.com/v2fly/v2ray-core/v4/common/errors/errorgen
     7  
     8  import (
     9  	"context"
    10  	"time"
    11  
    12  	core "github.com/v2fly/v2ray-core/v4"
    13  	"github.com/v2fly/v2ray-core/v4/common"
    14  	"github.com/v2fly/v2ray-core/v4/common/buf"
    15  	"github.com/v2fly/v2ray-core/v4/common/net"
    16  	"github.com/v2fly/v2ray-core/v4/common/protocol"
    17  	"github.com/v2fly/v2ray-core/v4/common/retry"
    18  	"github.com/v2fly/v2ray-core/v4/common/session"
    19  	"github.com/v2fly/v2ray-core/v4/common/signal"
    20  	"github.com/v2fly/v2ray-core/v4/common/task"
    21  	"github.com/v2fly/v2ray-core/v4/features/policy"
    22  	"github.com/v2fly/v2ray-core/v4/proxy/vless"
    23  	"github.com/v2fly/v2ray-core/v4/proxy/vless/encoding"
    24  	"github.com/v2fly/v2ray-core/v4/transport"
    25  	"github.com/v2fly/v2ray-core/v4/transport/internet"
    26  )
    27  
    28  func init() {
    29  	common.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
    30  		return New(ctx, config.(*Config))
    31  	}))
    32  }
    33  
    34  // Handler is an outbound connection handler for VLess protocol.
    35  type Handler struct {
    36  	serverList    *protocol.ServerList
    37  	serverPicker  protocol.ServerPicker
    38  	policyManager policy.Manager
    39  }
    40  
    41  // New creates a new VLess outbound handler.
    42  func New(ctx context.Context, config *Config) (*Handler, error) {
    43  	serverList := protocol.NewServerList()
    44  	for _, rec := range config.Vnext {
    45  		s, err := protocol.NewServerSpecFromPB(rec)
    46  		if err != nil {
    47  			return nil, newError("failed to parse server spec").Base(err).AtError()
    48  		}
    49  		serverList.AddServer(s)
    50  	}
    51  
    52  	v := core.MustFromContext(ctx)
    53  	handler := &Handler{
    54  		serverList:    serverList,
    55  		serverPicker:  protocol.NewRoundRobinServerPicker(serverList),
    56  		policyManager: v.GetFeature(policy.ManagerType()).(policy.Manager),
    57  	}
    58  
    59  	return handler, nil
    60  }
    61  
    62  // Process implements proxy.Outbound.Process().
    63  func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer internet.Dialer) error {
    64  	var rec *protocol.ServerSpec
    65  	var conn internet.Connection
    66  
    67  	if err := retry.ExponentialBackoff(5, 200).On(func() error {
    68  		rec = h.serverPicker.PickServer()
    69  		var err error
    70  		conn, err = dialer.Dial(ctx, rec.Destination())
    71  		if err != nil {
    72  			return err
    73  		}
    74  		return nil
    75  	}); err != nil {
    76  		return newError("failed to find an available destination").Base(err).AtWarning()
    77  	}
    78  	defer conn.Close()
    79  
    80  	outbound := session.OutboundFromContext(ctx)
    81  	if outbound == nil || !outbound.Target.IsValid() {
    82  		return newError("target not specified").AtError()
    83  	}
    84  
    85  	target := outbound.Target
    86  	newError("tunneling request to ", target, " via ", rec.Destination()).AtInfo().WriteToLog(session.ExportIDToError(ctx))
    87  
    88  	command := protocol.RequestCommandTCP
    89  	if target.Network == net.Network_UDP {
    90  		command = protocol.RequestCommandUDP
    91  	}
    92  	if target.Address.Family().IsDomain() && target.Address.Domain() == "v1.mux.cool" {
    93  		command = protocol.RequestCommandMux
    94  	}
    95  
    96  	request := &protocol.RequestHeader{
    97  		Version: encoding.Version,
    98  		User:    rec.PickUser(),
    99  		Command: command,
   100  		Address: target.Address,
   101  		Port:    target.Port,
   102  	}
   103  
   104  	account := request.User.Account.(*vless.MemoryAccount)
   105  
   106  	requestAddons := &encoding.Addons{
   107  		Flow: account.Flow,
   108  	}
   109  
   110  	sessionPolicy := h.policyManager.ForLevel(request.User.Level)
   111  	ctx, cancel := context.WithCancel(ctx)
   112  	timer := signal.CancelAfterInactivity(ctx, cancel, sessionPolicy.Timeouts.ConnectionIdle)
   113  
   114  	clientReader := link.Reader // .(*pipe.Reader)
   115  	clientWriter := link.Writer // .(*pipe.Writer)
   116  
   117  	postRequest := func() error {
   118  		defer timer.SetTimeout(sessionPolicy.Timeouts.DownlinkOnly)
   119  
   120  		bufferWriter := buf.NewBufferedWriter(buf.NewWriter(conn))
   121  		if err := encoding.EncodeRequestHeader(bufferWriter, request, requestAddons); err != nil {
   122  			return newError("failed to encode request header").Base(err).AtWarning()
   123  		}
   124  
   125  		// default: serverWriter := bufferWriter
   126  		serverWriter := encoding.EncodeBodyAddons(bufferWriter, request, requestAddons)
   127  		if err := buf.CopyOnceTimeout(clientReader, serverWriter, time.Millisecond*100); err != nil && err != buf.ErrNotTimeoutReader && err != buf.ErrReadTimeout {
   128  			return err // ...
   129  		}
   130  
   131  		// Flush; bufferWriter.WriteMultiBufer now is bufferWriter.writer.WriteMultiBuffer
   132  		if err := bufferWriter.SetBuffered(false); err != nil {
   133  			return newError("failed to write A request payload").Base(err).AtWarning()
   134  		}
   135  
   136  		// from clientReader.ReadMultiBuffer to serverWriter.WriteMultiBufer
   137  		if err := buf.Copy(clientReader, serverWriter, buf.UpdateActivity(timer)); err != nil {
   138  			return newError("failed to transfer request payload").Base(err).AtInfo()
   139  		}
   140  
   141  		return nil
   142  	}
   143  
   144  	getResponse := func() error {
   145  		defer timer.SetTimeout(sessionPolicy.Timeouts.UplinkOnly)
   146  
   147  		responseAddons, err := encoding.DecodeResponseHeader(conn, request)
   148  		if err != nil {
   149  			return newError("failed to decode response header").Base(err).AtInfo()
   150  		}
   151  
   152  		// default: serverReader := buf.NewReader(conn)
   153  		serverReader := encoding.DecodeBodyAddons(conn, request, responseAddons)
   154  
   155  		// from serverReader.ReadMultiBuffer to clientWriter.WriteMultiBufer
   156  		if err := buf.Copy(serverReader, clientWriter, buf.UpdateActivity(timer)); err != nil {
   157  			return newError("failed to transfer response payload").Base(err).AtInfo()
   158  		}
   159  
   160  		return nil
   161  	}
   162  
   163  	if err := task.Run(ctx, postRequest, task.OnSuccess(getResponse, task.Close(clientWriter))); err != nil {
   164  		return newError("connection ends").Base(err).AtInfo()
   165  	}
   166  
   167  	return nil
   168  }