github.com/xmplusdev/xray-core@v1.8.10/app/proxyman/inbound/dynamic.go (about) 1 package inbound 2 3 import ( 4 "context" 5 "sync" 6 "time" 7 8 "github.com/xmplusdev/xray-core/app/proxyman" 9 "github.com/xmplusdev/xray-core/common/dice" 10 "github.com/xmplusdev/xray-core/common/mux" 11 "github.com/xmplusdev/xray-core/common/net" 12 "github.com/xmplusdev/xray-core/common/task" 13 "github.com/xmplusdev/xray-core/core" 14 "github.com/xmplusdev/xray-core/proxy" 15 "github.com/xmplusdev/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 }