github.com/imannamdari/v2ray-core/v5@v5.0.5/app/proxyman/outbound/handler.go (about) 1 package outbound 2 3 import ( 4 "context" 5 6 core "github.com/imannamdari/v2ray-core/v5" 7 "github.com/imannamdari/v2ray-core/v5/app/proxyman" 8 "github.com/imannamdari/v2ray-core/v5/common" 9 "github.com/imannamdari/v2ray-core/v5/common/dice" 10 "github.com/imannamdari/v2ray-core/v5/common/mux" 11 "github.com/imannamdari/v2ray-core/v5/common/net" 12 "github.com/imannamdari/v2ray-core/v5/common/net/packetaddr" 13 "github.com/imannamdari/v2ray-core/v5/common/serial" 14 "github.com/imannamdari/v2ray-core/v5/common/session" 15 "github.com/imannamdari/v2ray-core/v5/features/dns" 16 "github.com/imannamdari/v2ray-core/v5/features/outbound" 17 "github.com/imannamdari/v2ray-core/v5/features/policy" 18 "github.com/imannamdari/v2ray-core/v5/features/stats" 19 "github.com/imannamdari/v2ray-core/v5/proxy" 20 "github.com/imannamdari/v2ray-core/v5/transport" 21 "github.com/imannamdari/v2ray-core/v5/transport/internet" 22 "github.com/imannamdari/v2ray-core/v5/transport/internet/security" 23 "github.com/imannamdari/v2ray-core/v5/transport/pipe" 24 ) 25 26 func getStatCounter(v *core.Instance, tag string) (stats.Counter, stats.Counter) { 27 var uplinkCounter stats.Counter 28 var downlinkCounter stats.Counter 29 30 policy := v.GetFeature(policy.ManagerType()).(policy.Manager) 31 if len(tag) > 0 && policy.ForSystem().Stats.OutboundUplink { 32 statsManager := v.GetFeature(stats.ManagerType()).(stats.Manager) 33 name := "outbound>>>" + tag + ">>>traffic>>>uplink" 34 c, _ := stats.GetOrRegisterCounter(statsManager, name) 35 if c != nil { 36 uplinkCounter = c 37 } 38 } 39 if len(tag) > 0 && policy.ForSystem().Stats.OutboundDownlink { 40 statsManager := v.GetFeature(stats.ManagerType()).(stats.Manager) 41 name := "outbound>>>" + tag + ">>>traffic>>>downlink" 42 c, _ := stats.GetOrRegisterCounter(statsManager, name) 43 if c != nil { 44 downlinkCounter = c 45 } 46 } 47 48 return uplinkCounter, downlinkCounter 49 } 50 51 // Handler is an implements of outbound.Handler. 52 type Handler struct { 53 tag string 54 senderSettings *proxyman.SenderConfig 55 streamSettings *internet.MemoryStreamConfig 56 proxy proxy.Outbound 57 outboundManager outbound.Manager 58 mux *mux.ClientManager 59 uplinkCounter stats.Counter 60 downlinkCounter stats.Counter 61 dns dns.Client 62 } 63 64 // NewHandler create a new Handler based on the given configuration. 65 func NewHandler(ctx context.Context, config *core.OutboundHandlerConfig) (outbound.Handler, error) { 66 v := core.MustFromContext(ctx) 67 uplinkCounter, downlinkCounter := getStatCounter(v, config.Tag) 68 h := &Handler{ 69 tag: config.Tag, 70 outboundManager: v.GetFeature(outbound.ManagerType()).(outbound.Manager), 71 uplinkCounter: uplinkCounter, 72 downlinkCounter: downlinkCounter, 73 } 74 75 if config.SenderSettings != nil { 76 senderSettings, err := serial.GetInstanceOf(config.SenderSettings) 77 if err != nil { 78 return nil, err 79 } 80 switch s := senderSettings.(type) { 81 case *proxyman.SenderConfig: 82 h.senderSettings = s 83 mss, err := internet.ToMemoryStreamConfig(s.StreamSettings) 84 if err != nil { 85 return nil, newError("failed to parse stream settings").Base(err).AtWarning() 86 } 87 h.streamSettings = mss 88 default: 89 return nil, newError("settings is not SenderConfig") 90 } 91 } 92 93 proxyConfig, err := serial.GetInstanceOf(config.ProxySettings) 94 if err != nil { 95 return nil, err 96 } 97 98 rawProxyHandler, err := common.CreateObject(ctx, proxyConfig) 99 if err != nil { 100 return nil, err 101 } 102 103 proxyHandler, ok := rawProxyHandler.(proxy.Outbound) 104 if !ok { 105 return nil, newError("not an outbound handler") 106 } 107 108 if h.senderSettings != nil && h.senderSettings.MultiplexSettings != nil { 109 config := h.senderSettings.MultiplexSettings 110 if config.Concurrency < 1 || config.Concurrency > 1024 { 111 return nil, newError("invalid mux concurrency: ", config.Concurrency).AtWarning() 112 } 113 h.mux = &mux.ClientManager{ 114 Enabled: h.senderSettings.MultiplexSettings.Enabled, 115 Picker: &mux.IncrementalWorkerPicker{ 116 Factory: mux.NewDialingWorkerFactory( 117 ctx, 118 proxyHandler, 119 h, 120 mux.ClientStrategy{ 121 MaxConcurrency: config.Concurrency, 122 MaxConnection: 128, 123 }, 124 ), 125 }, 126 } 127 } 128 129 if h.senderSettings != nil && h.senderSettings.DomainStrategy != proxyman.SenderConfig_AS_IS { 130 err := core.RequireFeatures(ctx, func(d dns.Client) error { 131 h.dns = d 132 return nil 133 }) 134 if err != nil { 135 return nil, err 136 } 137 } 138 139 h.proxy = proxyHandler 140 return h, nil 141 } 142 143 // Tag implements outbound.Handler. 144 func (h *Handler) Tag() string { 145 return h.tag 146 } 147 148 // Dispatch implements proxy.Outbound.Dispatch. 149 func (h *Handler) Dispatch(ctx context.Context, link *transport.Link) { 150 if h.mux != nil && (h.mux.Enabled || session.MuxPreferedFromContext(ctx)) { 151 if err := h.mux.Dispatch(ctx, link); err != nil { 152 err := newError("failed to process mux outbound traffic").Base(err) 153 session.SubmitOutboundErrorToOriginator(ctx, err) 154 err.WriteToLog(session.ExportIDToError(ctx)) 155 common.Interrupt(link.Writer) 156 } 157 } else { 158 if err := h.proxy.Process(ctx, link, h); err != nil { 159 // Ensure outbound ray is properly closed. 160 err := newError("failed to process outbound traffic").Base(err) 161 session.SubmitOutboundErrorToOriginator(ctx, err) 162 err.WriteToLog(session.ExportIDToError(ctx)) 163 common.Interrupt(link.Writer) 164 } else { 165 common.Must(common.Close(link.Writer)) 166 } 167 common.Interrupt(link.Reader) 168 } 169 } 170 171 // Address implements internet.Dialer. 172 func (h *Handler) Address() net.Address { 173 if h.senderSettings == nil || h.senderSettings.Via == nil { 174 return nil 175 } 176 return h.senderSettings.Via.AsAddress() 177 } 178 179 // Dial implements internet.Dialer. 180 func (h *Handler) Dial(ctx context.Context, dest net.Destination) (internet.Connection, error) { 181 if h.senderSettings != nil { 182 if h.senderSettings.ProxySettings.HasTag() && !h.senderSettings.ProxySettings.TransportLayerProxy { 183 tag := h.senderSettings.ProxySettings.Tag 184 handler := h.outboundManager.GetHandler(tag) 185 if handler != nil { 186 newError("proxying to ", tag, " for dest ", dest).AtDebug().WriteToLog(session.ExportIDToError(ctx)) 187 ctx = session.ContextWithOutbound(ctx, &session.Outbound{ 188 Target: dest, 189 }) 190 191 opts := pipe.OptionsFromContext(ctx) 192 uplinkReader, uplinkWriter := pipe.New(opts...) 193 downlinkReader, downlinkWriter := pipe.New(opts...) 194 195 go handler.Dispatch(ctx, &transport.Link{Reader: uplinkReader, Writer: downlinkWriter}) 196 conn := net.NewConnection(net.ConnectionInputMulti(uplinkWriter), net.ConnectionOutputMulti(downlinkReader)) 197 198 securityEngine, err := security.CreateSecurityEngineFromSettings(ctx, h.streamSettings) 199 if err != nil { 200 return nil, newError("unable to create security engine").Base(err) 201 } 202 203 if securityEngine != nil { 204 conn, err = securityEngine.Client(conn, security.OptionWithDestination{Dest: dest}) 205 if err != nil { 206 return nil, newError("unable to create security protocol client from security engine").Base(err) 207 } 208 } 209 210 return h.getStatCouterConnection(conn), nil 211 } 212 213 newError("failed to get outbound handler with tag: ", tag).AtWarning().WriteToLog(session.ExportIDToError(ctx)) 214 } 215 216 if h.senderSettings.Via != nil { 217 outbound := session.OutboundFromContext(ctx) 218 if outbound == nil { 219 outbound = new(session.Outbound) 220 ctx = session.ContextWithOutbound(ctx, outbound) 221 } 222 outbound.Gateway = h.senderSettings.Via.AsAddress() 223 } 224 225 if h.senderSettings.DomainStrategy != proxyman.SenderConfig_AS_IS { 226 outbound := session.OutboundFromContext(ctx) 227 if outbound == nil { 228 outbound = new(session.Outbound) 229 ctx = session.ContextWithOutbound(ctx, outbound) 230 } 231 outbound.Resolver = func(ctx context.Context, domain string) net.Address { 232 return h.resolveIP(ctx, domain, h.Address()) 233 } 234 } 235 } 236 237 enablePacketAddrCapture := true 238 if h.senderSettings != nil && h.senderSettings.ProxySettings != nil && h.senderSettings.ProxySettings.HasTag() && h.senderSettings.ProxySettings.TransportLayerProxy { 239 tag := h.senderSettings.ProxySettings.Tag 240 newError("transport layer proxying to ", tag, " for dest ", dest).AtDebug().WriteToLog(session.ExportIDToError(ctx)) 241 ctx = session.SetTransportLayerProxyTagToContext(ctx, tag) 242 enablePacketAddrCapture = false 243 } 244 245 if isStream, err := packetaddr.GetDestinationSubsetOf(dest); err == nil && enablePacketAddrCapture { 246 packetConn, err := internet.ListenSystemPacket(ctx, &net.UDPAddr{IP: net.AnyIP.IP(), Port: 0}, h.streamSettings.SocketSettings) 247 if err != nil { 248 return nil, newError("unable to listen socket").Base(err) 249 } 250 conn := packetaddr.ToPacketAddrConnWrapper(packetConn, isStream) 251 return h.getStatCouterConnection(conn), nil 252 } 253 254 conn, err := internet.Dial(ctx, dest, h.streamSettings) 255 return h.getStatCouterConnection(conn), err 256 } 257 258 func (h *Handler) resolveIP(ctx context.Context, domain string, localAddr net.Address) net.Address { 259 strategy := h.senderSettings.DomainStrategy 260 ips, err := dns.LookupIPWithOption(h.dns, domain, dns.IPOption{ 261 IPv4Enable: strategy == proxyman.SenderConfig_USE_IP || strategy == proxyman.SenderConfig_USE_IP4 || (localAddr != nil && localAddr.Family().IsIPv4()), 262 IPv6Enable: strategy == proxyman.SenderConfig_USE_IP || strategy == proxyman.SenderConfig_USE_IP6 || (localAddr != nil && localAddr.Family().IsIPv6()), 263 FakeEnable: false, 264 }) 265 if err != nil { 266 newError("failed to get IP address for domain ", domain).Base(err).WriteToLog(session.ExportIDToError(ctx)) 267 } 268 if len(ips) == 0 { 269 return nil 270 } 271 return net.IPAddress(ips[dice.Roll(len(ips))]) 272 } 273 274 func (h *Handler) getStatCouterConnection(conn internet.Connection) internet.Connection { 275 if h.uplinkCounter != nil || h.downlinkCounter != nil { 276 return &internet.StatCouterConnection{ 277 Connection: conn, 278 ReadCounter: h.downlinkCounter, 279 WriteCounter: h.uplinkCounter, 280 } 281 } 282 return conn 283 } 284 285 // GetOutbound implements proxy.GetOutbound. 286 func (h *Handler) GetOutbound() proxy.Outbound { 287 return h.proxy 288 } 289 290 // Start implements common.Runnable. 291 func (h *Handler) Start() error { 292 return nil 293 } 294 295 // Close implements common.Closable. 296 func (h *Handler) Close() error { 297 common.Close(h.mux) 298 return nil 299 }