github.com/imannamdari/v2ray-core/v5@v5.0.5/proxy/vlite/outbound/outbound.go (about)

     1  package outbound
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"sync"
     7  	"time"
     8  
     9  	"github.com/mustafaturan/bus"
    10  	"github.com/xiaokangwang/VLite/ass/udpconn2tun"
    11  	"github.com/xiaokangwang/VLite/interfaces"
    12  	"github.com/xiaokangwang/VLite/interfaces/ibus"
    13  	vltransport "github.com/xiaokangwang/VLite/transport"
    14  	udpsctpserver "github.com/xiaokangwang/VLite/transport/packetsctp/sctprelay"
    15  	"github.com/xiaokangwang/VLite/transport/packetuni/puniClient"
    16  	"github.com/xiaokangwang/VLite/transport/udp/udpClient"
    17  	"github.com/xiaokangwang/VLite/transport/udp/udpuni/udpunic"
    18  	"github.com/xiaokangwang/VLite/transport/uni/uniclient"
    19  	client2 "github.com/xiaokangwang/VLite/workers/client"
    20  
    21  	"github.com/imannamdari/v2ray-core/v5/common"
    22  	"github.com/imannamdari/v2ray-core/v5/common/environment"
    23  	"github.com/imannamdari/v2ray-core/v5/common/environment/envctx"
    24  	"github.com/imannamdari/v2ray-core/v5/common/net"
    25  	"github.com/imannamdari/v2ray-core/v5/common/net/packetaddr"
    26  	"github.com/imannamdari/v2ray-core/v5/common/session"
    27  	"github.com/imannamdari/v2ray-core/v5/common/signal"
    28  	"github.com/imannamdari/v2ray-core/v5/common/task"
    29  	"github.com/imannamdari/v2ray-core/v5/transport"
    30  	"github.com/imannamdari/v2ray-core/v5/transport/internet"
    31  	"github.com/imannamdari/v2ray-core/v5/transport/internet/udp"
    32  )
    33  
    34  //go:generate go run github.com/imannamdari/v2ray-core/v5/common/errors/errorgen
    35  
    36  func NewUDPOutboundHandler(ctx context.Context, config *UDPProtocolConfig) (*Handler, error) {
    37  	proxyEnvironment := envctx.EnvironmentFromContext(ctx).(environment.ProxyEnvironment)
    38  	statusInstance, err := createStatusFromConfig(config)
    39  	if err != nil {
    40  		return nil, newError("unable to initialize vlite").Base(err)
    41  	}
    42  	proxyEnvironment.TransientStorage().Put(ctx, "status", statusInstance)
    43  	return &Handler{ctx: ctx}, nil
    44  }
    45  
    46  type Handler struct {
    47  	ctx context.Context
    48  }
    49  
    50  // Process implements proxy.Outbound.Process().
    51  func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer internet.Dialer) error {
    52  	proxyEnvironment := envctx.EnvironmentFromContext(h.ctx).(environment.ProxyEnvironment)
    53  	statusInstanceIfce, err := proxyEnvironment.TransientStorage().Get(ctx, "status")
    54  	if err != nil {
    55  		return newError("uninitialized handler").Base(err)
    56  	}
    57  	statusInstance := statusInstanceIfce.(*status)
    58  	err = h.ensureStarted(statusInstance)
    59  	if err != nil {
    60  		return newError("unable to initialize").Base(err)
    61  	}
    62  	connid := session.IDFromContext(ctx)
    63  	outbound := session.OutboundFromContext(ctx)
    64  	if outbound == nil || !outbound.Target.IsValid() {
    65  		return newError("target not specified")
    66  	}
    67  	destination := outbound.Target
    68  	packetConnOut := statusInstance.connAdp.DialUDP(net.UDPAddr{Port: int(connid % 65535)})
    69  	ctx, cancel := context.WithCancel(ctx)
    70  	timer := signal.CancelAfterInactivity(ctx, cancel, time.Second*600)
    71  
    72  	if packetConn, err := packetaddr.ToPacketAddrConn(link, destination); err == nil {
    73  		requestDone := func() error {
    74  			return udp.CopyPacketConn(packetConnOut, packetConn, udp.UpdateActivity(timer))
    75  		}
    76  		responseDone := func() error {
    77  			return udp.CopyPacketConn(packetConn, packetConnOut, udp.UpdateActivity(timer))
    78  		}
    79  		responseDoneAndCloseWriter := task.OnSuccess(responseDone, task.Close(link.Writer))
    80  		if err := task.Run(ctx, requestDone, responseDoneAndCloseWriter); err != nil {
    81  			return newError("connection ends").Base(err)
    82  		}
    83  	}
    84  	return newError("unrecognized connection")
    85  }
    86  
    87  func (h *Handler) ensureStarted(s *status) error {
    88  	s.access.Lock()
    89  	defer s.access.Unlock()
    90  	if s.TunnelRxFromTun == nil {
    91  		err := enableInterface(s)
    92  		if err != nil {
    93  			return err
    94  		}
    95  	}
    96  	return nil
    97  }
    98  
    99  type status struct {
   100  	ctx      context.Context
   101  	password []byte
   102  	msgbus   *bus.Bus
   103  
   104  	udpdialer vltransport.UnderlayTransportDialer
   105  	puni      *puniClient.PacketUniClient
   106  	udprelay  *udpsctpserver.PacketSCTPRelay
   107  	udpserver *client2.UDPClientContext
   108  
   109  	TunnelTxToTun   chan interfaces.UDPPacket
   110  	TunnelRxFromTun chan interfaces.UDPPacket
   111  
   112  	connAdp *udpconn2tun.UDPConn2Tun
   113  
   114  	config UDPProtocolConfig
   115  
   116  	access sync.Mutex
   117  }
   118  
   119  func createStatusFromConfig(config *UDPProtocolConfig) (*status, error) { //nolint:unparam
   120  	s := &status{password: []byte(config.Password)}
   121  	ctx := context.Background()
   122  
   123  	s.msgbus = ibus.NewMessageBus()
   124  	ctx = context.WithValue(ctx, interfaces.ExtraOptionsMessageBus, s.msgbus) //nolint:revive,staticcheck
   125  
   126  	ctx = context.WithValue(ctx, interfaces.ExtraOptionsDisableAutoQuitForClient, true) //nolint:revive,staticcheck
   127  
   128  	if config.EnableFec {
   129  		ctx = context.WithValue(ctx, interfaces.ExtraOptionsUDPFECEnabled, true) //nolint:revive,staticcheck
   130  	}
   131  
   132  	if config.ScramblePacket {
   133  		ctx = context.WithValue(ctx, interfaces.ExtraOptionsUDPShouldMask, true) //nolint:revive,staticcheck
   134  	}
   135  
   136  	ctx = context.WithValue(ctx, interfaces.ExtraOptionsUDPMask, string(s.password)) //nolint:revive,staticcheck
   137  
   138  	if config.HandshakeMaskingPaddingSize != 0 {
   139  		ctxv := &interfaces.ExtraOptionsUsePacketArmorValue{PacketArmorPaddingTo: int(config.HandshakeMaskingPaddingSize), UsePacketArmor: true}
   140  		ctx = context.WithValue(ctx, interfaces.ExtraOptionsUsePacketArmor, ctxv) //nolint:revive,staticcheck
   141  	}
   142  
   143  	destinationString := fmt.Sprintf("%v:%v", config.Address.AsAddress().String(), config.Port)
   144  
   145  	s.udpdialer = udpClient.NewUdpClient(destinationString, ctx)
   146  	if config.EnableStabilization {
   147  		s.udpdialer = udpunic.NewUdpUniClient(string(s.password), ctx, s.udpdialer)
   148  		s.udpdialer = uniclient.NewUnifiedConnectionClient(s.udpdialer, ctx)
   149  	}
   150  	s.ctx = ctx
   151  	return s, nil
   152  }
   153  
   154  func enableInterface(s *status) error {
   155  	conn, err, connctx := s.udpdialer.Connect(s.ctx)
   156  	if err != nil {
   157  		return newError("unable to connect to remote").Base(err)
   158  	}
   159  
   160  	C_C2STraffic := make(chan client2.UDPClientTxToServerTraffic, 8)         //nolint:revive,stylecheck
   161  	C_C2SDataTraffic := make(chan client2.UDPClientTxToServerDataTraffic, 8) //nolint:revive,stylecheck
   162  	C_S2CTraffic := make(chan client2.UDPClientRxFromServerTraffic, 8)       //nolint:revive,stylecheck
   163  
   164  	C_C2STraffic2 := make(chan interfaces.TrafficWithChannelTag, 8)     //nolint:revive,stylecheck
   165  	C_C2SDataTraffic2 := make(chan interfaces.TrafficWithChannelTag, 8) //nolint:revive,stylecheck
   166  	C_S2CTraffic2 := make(chan interfaces.TrafficWithChannelTag, 8)     //nolint:revive,stylecheck
   167  
   168  	go func(ctx context.Context) {
   169  		for {
   170  			select {
   171  			case data := <-C_C2STraffic:
   172  				C_C2STraffic2 <- interfaces.TrafficWithChannelTag(data)
   173  			case <-ctx.Done():
   174  				return
   175  			}
   176  		}
   177  	}(connctx)
   178  
   179  	go func(ctx context.Context) {
   180  		for {
   181  			select {
   182  			case data := <-C_C2SDataTraffic:
   183  				C_C2SDataTraffic2 <- interfaces.TrafficWithChannelTag(data)
   184  			case <-ctx.Done():
   185  				return
   186  			}
   187  		}
   188  	}(connctx)
   189  
   190  	go func(ctx context.Context) {
   191  		for {
   192  			select {
   193  			case data := <-C_S2CTraffic2:
   194  				C_S2CTraffic <- client2.UDPClientRxFromServerTraffic(data)
   195  			case <-ctx.Done():
   196  				return
   197  			}
   198  		}
   199  	}(connctx)
   200  
   201  	TunnelTxToTun := make(chan interfaces.UDPPacket)
   202  	TunnelRxFromTun := make(chan interfaces.UDPPacket)
   203  
   204  	s.TunnelTxToTun = TunnelTxToTun
   205  	s.TunnelRxFromTun = TunnelRxFromTun
   206  
   207  	if s.config.EnableStabilization && s.config.EnableRenegotiation {
   208  		s.puni = puniClient.NewPacketUniClient(C_C2STraffic2, C_C2SDataTraffic2, C_S2CTraffic2, s.password, connctx)
   209  		s.puni.OnAutoCarrier(conn, connctx)
   210  		s.udpserver = client2.UDPClient(connctx, C_C2STraffic, C_C2SDataTraffic, C_S2CTraffic, TunnelTxToTun, TunnelRxFromTun, s.puni)
   211  	} else {
   212  		s.udprelay = udpsctpserver.NewPacketRelayClient(conn, C_C2STraffic2, C_C2SDataTraffic2, C_S2CTraffic2, s.password, connctx)
   213  		s.udpserver = client2.UDPClient(connctx, C_C2STraffic, C_C2SDataTraffic, C_S2CTraffic, TunnelTxToTun, TunnelRxFromTun, s.udprelay)
   214  	}
   215  
   216  	s.ctx = connctx
   217  
   218  	s.connAdp = udpconn2tun.NewUDPConn2Tun(TunnelTxToTun, TunnelRxFromTun)
   219  	return nil
   220  }
   221  
   222  func init() {
   223  	common.Must(common.RegisterConfig((*UDPProtocolConfig)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
   224  		return NewUDPOutboundHandler(ctx, config.(*UDPProtocolConfig))
   225  	}))
   226  }