github.com/xraypb/xray-core@v1.6.6/app/proxyman/inbound/dynamic.go (about)

     1  package inbound
     2  
     3  import (
     4  	"context"
     5  	"sync"
     6  	"time"
     7  
     8  	"github.com/xraypb/xray-core/app/proxyman"
     9  	"github.com/xraypb/xray-core/common/dice"
    10  	"github.com/xraypb/xray-core/common/mux"
    11  	"github.com/xraypb/xray-core/common/net"
    12  	"github.com/xraypb/xray-core/common/task"
    13  	"github.com/xraypb/xray-core/core"
    14  	"github.com/xraypb/xray-core/proxy"
    15  	"github.com/xraypb/xray-core/transport/internet"
    16  )
    17  
    18  type DynamicInboundHandler struct {
    19  	tag            string
    20  	v              *core.Instance
    21  	proxyConfig    interface{}
    22  	receiverConfig *proxyman.ReceiverConfig
    23  	streamSettings *internet.MemoryStreamConfig
    24  	portMutex      sync.Mutex
    25  	portsInUse     map[net.Port]bool
    26  	workerMutex    sync.RWMutex
    27  	worker         []worker
    28  	lastRefresh    time.Time
    29  	mux            *mux.Server
    30  	task           *task.Periodic
    31  
    32  	ctx context.Context
    33  }
    34  
    35  func NewDynamicInboundHandler(ctx context.Context, tag string, receiverConfig *proxyman.ReceiverConfig, proxyConfig interface{}) (*DynamicInboundHandler, error) {
    36  	v := core.MustFromContext(ctx)
    37  	h := &DynamicInboundHandler{
    38  		tag:            tag,
    39  		proxyConfig:    proxyConfig,
    40  		receiverConfig: receiverConfig,
    41  		portsInUse:     make(map[net.Port]bool),
    42  		mux:            mux.NewServer(ctx),
    43  		v:              v,
    44  		ctx:            ctx,
    45  	}
    46  
    47  	mss, err := internet.ToMemoryStreamConfig(receiverConfig.StreamSettings)
    48  	if err != nil {
    49  		return nil, newError("failed to parse stream settings").Base(err).AtWarning()
    50  	}
    51  	if receiverConfig.ReceiveOriginalDestination {
    52  		if mss.SocketSettings == nil {
    53  			mss.SocketSettings = &internet.SocketConfig{}
    54  		}
    55  		if mss.SocketSettings.Tproxy == internet.SocketConfig_Off {
    56  			mss.SocketSettings.Tproxy = internet.SocketConfig_Redirect
    57  		}
    58  		mss.SocketSettings.ReceiveOriginalDestAddress = true
    59  	}
    60  
    61  	h.streamSettings = mss
    62  
    63  	h.task = &task.Periodic{
    64  		Interval: time.Minute * time.Duration(h.receiverConfig.AllocationStrategy.GetRefreshValue()),
    65  		Execute:  h.refresh,
    66  	}
    67  
    68  	return h, nil
    69  }
    70  
    71  func (h *DynamicInboundHandler) allocatePort() net.Port {
    72  	allPorts := []int32{}
    73  	for _, pr := range h.receiverConfig.PortList.Range {
    74  		for i := pr.From; i <= pr.To; i++ {
    75  			allPorts = append(allPorts, int32(i))
    76  		}
    77  	}
    78  	h.portMutex.Lock()
    79  	defer h.portMutex.Unlock()
    80  
    81  	for {
    82  		r := dice.Roll(len(allPorts))
    83  		port := net.Port(allPorts[r])
    84  		_, used := h.portsInUse[port]
    85  		if !used {
    86  			h.portsInUse[port] = true
    87  			return port
    88  		}
    89  	}
    90  }
    91  
    92  func (h *DynamicInboundHandler) closeWorkers(workers []worker) {
    93  	ports2Del := make([]net.Port, len(workers))
    94  	for idx, worker := range workers {
    95  		ports2Del[idx] = worker.Port()
    96  		if err := worker.Close(); err != nil {
    97  			newError("failed to close worker").Base(err).WriteToLog()
    98  		}
    99  	}
   100  
   101  	h.portMutex.Lock()
   102  	for _, port := range ports2Del {
   103  		delete(h.portsInUse, port)
   104  	}
   105  	h.portMutex.Unlock()
   106  }
   107  
   108  func (h *DynamicInboundHandler) refresh() error {
   109  	h.lastRefresh = time.Now()
   110  
   111  	timeout := time.Minute * time.Duration(h.receiverConfig.AllocationStrategy.GetRefreshValue()) * 2
   112  	concurrency := h.receiverConfig.AllocationStrategy.GetConcurrencyValue()
   113  	workers := make([]worker, 0, concurrency)
   114  
   115  	address := h.receiverConfig.Listen.AsAddress()
   116  	if address == nil {
   117  		address = net.AnyIP
   118  	}
   119  
   120  	uplinkCounter, downlinkCounter := getStatCounter(h.v, h.tag)
   121  
   122  	for i := uint32(0); i < concurrency; i++ {
   123  		port := h.allocatePort()
   124  		rawProxy, err := core.CreateObject(h.v, h.proxyConfig)
   125  		if err != nil {
   126  			newError("failed to create proxy instance").Base(err).AtWarning().WriteToLog()
   127  			continue
   128  		}
   129  		p := rawProxy.(proxy.Inbound)
   130  		nl := p.Network()
   131  		if net.HasNetwork(nl, net.Network_TCP) {
   132  			worker := &tcpWorker{
   133  				tag:             h.tag,
   134  				address:         address,
   135  				port:            port,
   136  				proxy:           p,
   137  				stream:          h.streamSettings,
   138  				recvOrigDest:    h.receiverConfig.ReceiveOriginalDestination,
   139  				dispatcher:      h.mux,
   140  				sniffingConfig:  h.receiverConfig.GetEffectiveSniffingSettings(),
   141  				uplinkCounter:   uplinkCounter,
   142  				downlinkCounter: downlinkCounter,
   143  				ctx:             h.ctx,
   144  			}
   145  			if err := worker.Start(); err != nil {
   146  				newError("failed to create TCP worker").Base(err).AtWarning().WriteToLog()
   147  				continue
   148  			}
   149  			workers = append(workers, worker)
   150  		}
   151  
   152  		if net.HasNetwork(nl, net.Network_UDP) {
   153  			worker := &udpWorker{
   154  				tag:             h.tag,
   155  				proxy:           p,
   156  				address:         address,
   157  				port:            port,
   158  				dispatcher:      h.mux,
   159  				sniffingConfig:  h.receiverConfig.GetEffectiveSniffingSettings(),
   160  				uplinkCounter:   uplinkCounter,
   161  				downlinkCounter: downlinkCounter,
   162  				stream:          h.streamSettings,
   163  				ctx:             h.ctx,
   164  			}
   165  			if err := worker.Start(); err != nil {
   166  				newError("failed to create UDP worker").Base(err).AtWarning().WriteToLog()
   167  				continue
   168  			}
   169  			workers = append(workers, worker)
   170  		}
   171  	}
   172  
   173  	h.workerMutex.Lock()
   174  	h.worker = workers
   175  	h.workerMutex.Unlock()
   176  
   177  	time.AfterFunc(timeout, func() {
   178  		h.closeWorkers(workers)
   179  	})
   180  
   181  	return nil
   182  }
   183  
   184  func (h *DynamicInboundHandler) Start() error {
   185  	return h.task.Start()
   186  }
   187  
   188  func (h *DynamicInboundHandler) Close() error {
   189  	return h.task.Close()
   190  }
   191  
   192  func (h *DynamicInboundHandler) GetRandomInboundProxy() (interface{}, net.Port, int) {
   193  	h.workerMutex.RLock()
   194  	defer h.workerMutex.RUnlock()
   195  
   196  	if len(h.worker) == 0 {
   197  		return nil, 0, 0
   198  	}
   199  	w := h.worker[dice.Roll(len(h.worker))]
   200  	expire := h.receiverConfig.AllocationStrategy.GetRefreshValue() - uint32(time.Since(h.lastRefresh)/time.Minute)
   201  	return w.Proxy(), w.Port(), int(expire)
   202  }
   203  
   204  func (h *DynamicInboundHandler) Tag() string {
   205  	return h.tag
   206  }