github.com/TeaOSLab/EdgeNode@v1.3.8/internal/nodes/listener_manager.go (about) 1 package nodes 2 3 import ( 4 "fmt" 5 "github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs" 6 "github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs" 7 teaconst "github.com/TeaOSLab/EdgeNode/internal/const" 8 "github.com/TeaOSLab/EdgeNode/internal/firewalls" 9 "github.com/TeaOSLab/EdgeNode/internal/goman" 10 "github.com/TeaOSLab/EdgeNode/internal/remotelogs" 11 "github.com/TeaOSLab/EdgeNode/internal/utils" 12 executils "github.com/TeaOSLab/EdgeNode/internal/utils/exec" 13 "github.com/iwind/TeaGo/Tea" 14 "github.com/iwind/TeaGo/lists" 15 "github.com/iwind/TeaGo/maps" 16 "github.com/iwind/TeaGo/types" 17 "net/url" 18 "regexp" 19 "runtime" 20 "sort" 21 "strings" 22 "sync" 23 "time" 24 ) 25 26 var sharedListenerManager *ListenerManager 27 28 func init() { 29 if !teaconst.IsMain { 30 return 31 } 32 33 sharedListenerManager = NewListenerManager() 34 } 35 36 // ListenerManager 端口监听管理器 37 type ListenerManager struct { 38 listenersMap map[string]*Listener // addr => *Listener 39 http3Listener *HTTPListener 40 41 locker sync.Mutex 42 lastConfig *nodeconfigs.NodeConfig 43 44 retryListenerMap map[string]*Listener // 需要重试的监听器 addr => Listener 45 ticker *time.Ticker 46 47 firewalld *firewalls.Firewalld 48 lastPortStrings string 49 lastTCPPortRanges [][2]int 50 lastUDPPortRanges [][2]int 51 } 52 53 // NewListenerManager 获取新对象 54 func NewListenerManager() *ListenerManager { 55 var manager = &ListenerManager{ 56 listenersMap: map[string]*Listener{}, 57 retryListenerMap: map[string]*Listener{}, 58 ticker: time.NewTicker(1 * time.Minute), 59 firewalld: firewalls.NewFirewalld(), 60 } 61 62 // 提升测试效率 63 if Tea.IsTesting() { 64 manager.ticker = time.NewTicker(5 * time.Second) 65 } 66 67 goman.New(func() { 68 for range manager.ticker.C { 69 manager.retryListeners() 70 } 71 }) 72 73 return manager 74 } 75 76 // Start 启动监听 77 func (this *ListenerManager) Start(nodeConfig *nodeconfigs.NodeConfig) error { 78 this.locker.Lock() 79 defer this.locker.Unlock() 80 81 // 重置数据 82 this.retryListenerMap = map[string]*Listener{} 83 84 // 检查是否有变化 85 /**if this.lastConfig != nil && this.lastConfig.Version == node.Version { 86 return nil 87 }**/ 88 this.lastConfig = nodeConfig 89 90 // 所有的新地址 91 var groupAddrs = []string{} 92 var availableServerGroups = nodeConfig.AvailableGroups() 93 if !nodeConfig.IsOn { 94 availableServerGroups = []*serverconfigs.ServerAddressGroup{} 95 } 96 97 if len(availableServerGroups) == 0 { 98 remotelogs.Println("LISTENER_MANAGER", "no available servers to startup") 99 } 100 101 for _, group := range availableServerGroups { 102 var addr = group.FullAddr() 103 groupAddrs = append(groupAddrs, addr) 104 } 105 106 // 停掉老的 107 for listenerKey, listener := range this.listenersMap { 108 var addr = listener.FullAddr() 109 if !lists.ContainsString(groupAddrs, addr) { 110 remotelogs.Println("LISTENER_MANAGER", "close '"+addr+"'") 111 _ = listener.Close() 112 113 delete(this.listenersMap, listenerKey) 114 } 115 } 116 117 // 启动新的或修改老的 118 for _, group := range availableServerGroups { 119 var addr = group.FullAddr() 120 listener, ok := this.listenersMap[addr] 121 if ok { 122 // 不需要打印reload信息,防止日志数量过多 123 listener.Reload(group) 124 } else { 125 remotelogs.Println("LISTENER_MANAGER", "listen '"+this.prettyAddress(addr)+"'") 126 listener = NewListener() 127 listener.Reload(group) 128 err := listener.Listen() 129 if err != nil { 130 // 放入到重试队列中 131 this.retryListenerMap[addr] = listener 132 133 var firstServer = group.FirstServer() 134 if firstServer == nil { 135 remotelogs.Error("LISTENER_MANAGER", err.Error()) 136 } else { 137 // 当前占用的进程名 138 if strings.Contains(err.Error(), "in use") { 139 portIndex := strings.LastIndex(addr, ":") 140 if portIndex > 0 { 141 var port = addr[portIndex+1:] 142 var processName = this.findProcessNameWithPort(group.IsUDP(), port) 143 if len(processName) > 0 { 144 err = fmt.Errorf("%w (the process using port: '%s')", err, processName) 145 } 146 } 147 } 148 149 remotelogs.ServerError(firstServer.Id, "LISTENER_MANAGER", "listen '"+addr+"' failed: "+err.Error(), nodeconfigs.NodeLogTypeListenAddressFailed, maps.Map{"address": addr}) 150 } 151 152 continue 153 } else { 154 // TODO 是否是从错误中恢复 155 } 156 this.listenersMap[addr] = listener 157 } 158 } 159 160 // 加入到firewalld 161 go this.addToFirewalld(groupAddrs) 162 163 return nil 164 } 165 166 // TotalActiveConnections 获取总的活跃连接数 167 func (this *ListenerManager) TotalActiveConnections() int { 168 this.locker.Lock() 169 defer this.locker.Unlock() 170 171 var total = 0 172 for _, listener := range this.listenersMap { 173 total += listener.listener.CountActiveConnections() 174 } 175 176 if this.http3Listener != nil { 177 total += this.http3Listener.CountActiveConnections() 178 } 179 180 return total 181 } 182 183 // 返回更加友好格式的地址 184 func (this *ListenerManager) prettyAddress(addr string) string { 185 u, err := url.Parse(addr) 186 if err != nil { 187 return addr 188 } 189 if regexp.MustCompile(`^:\d+$`).MatchString(u.Host) { 190 u.Host = "*" + u.Host 191 } 192 return u.String() 193 } 194 195 // 重试失败的Listener 196 func (this *ListenerManager) retryListeners() { 197 this.locker.Lock() 198 defer this.locker.Unlock() 199 200 for addr, listener := range this.retryListenerMap { 201 err := listener.Listen() 202 if err == nil { 203 delete(this.retryListenerMap, addr) 204 this.listenersMap[addr] = listener 205 remotelogs.ServerSuccess(listener.group.FirstServer().Id, "LISTENER_MANAGER", "retry to listen '"+addr+"' successfully", nodeconfigs.NodeLogTypeListenAddressFailed, maps.Map{"address": addr}) 206 } 207 } 208 } 209 210 func (this *ListenerManager) findProcessNameWithPort(isUdp bool, port string) string { 211 if runtime.GOOS != "linux" { 212 return "" 213 } 214 215 path, err := executils.LookPath("ss") 216 if err != nil { 217 return "" 218 } 219 220 var option = "t" 221 if isUdp { 222 option = "u" 223 } 224 225 var cmd = executils.NewTimeoutCmd(10*time.Second, path, "-"+option+"lpn", "sport = :"+port) 226 cmd.WithStdout() 227 err = cmd.Run() 228 if err != nil { 229 return "" 230 } 231 232 var matches = regexp.MustCompile(`(?U)\(\("(.+)",pid=\d+,fd=\d+\)\)`).FindStringSubmatch(cmd.Stdout()) 233 if len(matches) > 1 { 234 return matches[1] 235 } 236 return "" 237 } 238 239 func (this *ListenerManager) addToFirewalld(groupAddrs []string) { 240 if !sharedNodeConfig.AutoOpenPorts { 241 return 242 } 243 244 if this.firewalld == nil || !this.firewalld.IsReady() { 245 return 246 } 247 248 // HTTP/3相关端口 249 var http3Ports = sharedNodeConfig.FindHTTP3Ports() 250 if len(http3Ports) > 0 { 251 for _, port := range http3Ports { 252 var groupAddr = "udp://:" + types.String(port) 253 if !lists.ContainsString(groupAddrs, groupAddr) { 254 groupAddrs = append(groupAddrs, groupAddr) 255 } 256 } 257 } 258 259 // 组合端口号 260 var portStrings = []string{} 261 var udpPorts = []int{} 262 var tcpPorts = []int{} 263 for _, addr := range groupAddrs { 264 var protocol = "tcp" 265 if strings.HasPrefix(addr, "udp") { 266 protocol = "udp" 267 } 268 269 var lastIndex = strings.LastIndex(addr, ":") 270 if lastIndex > 0 { 271 var portString = addr[lastIndex+1:] 272 portStrings = append(portStrings, portString+"/"+protocol) 273 274 switch protocol { 275 case "tcp": 276 tcpPorts = append(tcpPorts, types.Int(portString)) 277 case "udp": 278 udpPorts = append(udpPorts, types.Int(portString)) 279 } 280 } 281 } 282 if len(portStrings) == 0 { 283 return 284 } 285 286 // 检查是否有变化 287 sort.Strings(portStrings) 288 var newPortStrings = strings.Join(portStrings, ",") 289 if newPortStrings == this.lastPortStrings { 290 return 291 } 292 this.locker.Lock() 293 this.lastPortStrings = newPortStrings 294 this.locker.Unlock() 295 296 remotelogs.Println("FIREWALLD", "opening ports automatically ...") 297 defer func() { 298 remotelogs.Println("FIREWALLD", "open ports successfully") 299 }() 300 301 // 合并端口 302 var tcpPortRanges = utils.MergePorts(tcpPorts) 303 var udpPortRanges = utils.MergePorts(udpPorts) 304 305 defer func() { 306 this.locker.Lock() 307 this.lastTCPPortRanges = tcpPortRanges 308 this.lastUDPPortRanges = udpPortRanges 309 this.locker.Unlock() 310 }() 311 312 // 删除老的不存在的端口 313 var tcpPortRangesMap = map[string]bool{} 314 var udpPortRangesMap = map[string]bool{} 315 for _, portRange := range tcpPortRanges { 316 tcpPortRangesMap[this.firewalld.PortRangeString(portRange, "tcp")] = true 317 } 318 for _, portRange := range udpPortRanges { 319 udpPortRangesMap[this.firewalld.PortRangeString(portRange, "udp")] = true 320 } 321 322 for _, portRange := range this.lastTCPPortRanges { 323 var s = this.firewalld.PortRangeString(portRange, "tcp") 324 _, ok := tcpPortRangesMap[s] 325 if ok { 326 continue 327 } 328 remotelogs.Println("FIREWALLD", "remove port '"+s+"'") 329 _ = this.firewalld.RemovePortRangePermanently(portRange, "tcp") 330 } 331 for _, portRange := range this.lastUDPPortRanges { 332 var s = this.firewalld.PortRangeString(portRange, "udp") 333 _, ok := udpPortRangesMap[s] 334 if ok { 335 continue 336 } 337 remotelogs.Println("FIREWALLD", "remove port '"+s+"'") 338 _ = this.firewalld.RemovePortRangePermanently(portRange, "udp") 339 } 340 341 // 添加新的 342 _ = this.firewalld.AllowPortRangesPermanently(tcpPortRanges, "tcp") 343 _ = this.firewalld.AllowPortRangesPermanently(udpPortRanges, "udp") 344 } 345 346 func (this *ListenerManager) reloadFirewalld() { 347 this.locker.Lock() 348 defer this.locker.Unlock() 349 350 var nodeConfig = sharedNodeConfig 351 352 // 所有的新地址 353 var groupAddrs = []string{} 354 var availableServerGroups = nodeConfig.AvailableGroups() 355 if !nodeConfig.IsOn { 356 availableServerGroups = []*serverconfigs.ServerAddressGroup{} 357 } 358 359 if len(availableServerGroups) == 0 { 360 remotelogs.Println("LISTENER_MANAGER", "no available servers to startup") 361 } 362 363 for _, group := range availableServerGroups { 364 var addr = group.FullAddr() 365 groupAddrs = append(groupAddrs, addr) 366 } 367 368 go this.addToFirewalld(groupAddrs) 369 }