github.com/v2fly/v2ray-core/v5@v5.16.2-0.20240507031116-8191faa6e095/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/v2fly/v2ray-core/v5/common" 22 "github.com/v2fly/v2ray-core/v5/common/environment" 23 "github.com/v2fly/v2ray-core/v5/common/environment/envctx" 24 "github.com/v2fly/v2ray-core/v5/common/net" 25 "github.com/v2fly/v2ray-core/v5/common/net/packetaddr" 26 "github.com/v2fly/v2ray-core/v5/common/session" 27 "github.com/v2fly/v2ray-core/v5/common/signal" 28 "github.com/v2fly/v2ray-core/v5/common/task" 29 "github.com/v2fly/v2ray-core/v5/transport" 30 "github.com/v2fly/v2ray-core/v5/transport/internet" 31 "github.com/v2fly/v2ray-core/v5/transport/internet/udp" 32 ) 33 34 //go:generate go run github.com/v2fly/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 }