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  }