github.com/TeaOSLab/EdgeNode@v1.3.8/internal/iplibrary/manager_ip_list.go (about) 1 package iplibrary 2 3 import ( 4 "github.com/TeaOSLab/EdgeCommon/pkg/iputils" 5 "github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs" 6 "github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb" 7 teaconst "github.com/TeaOSLab/EdgeNode/internal/const" 8 "github.com/TeaOSLab/EdgeNode/internal/events" 9 "github.com/TeaOSLab/EdgeNode/internal/goman" 10 "github.com/TeaOSLab/EdgeNode/internal/remotelogs" 11 "github.com/TeaOSLab/EdgeNode/internal/rpc" 12 "github.com/TeaOSLab/EdgeNode/internal/trackers" 13 "github.com/TeaOSLab/EdgeNode/internal/utils/idles" 14 "github.com/TeaOSLab/EdgeNode/internal/waf" 15 "github.com/TeaOSLab/EdgeNode/internal/zero" 16 "github.com/iwind/TeaGo/Tea" 17 "github.com/iwind/TeaGo/types" 18 "os" 19 "sync" 20 "time" 21 ) 22 23 var SharedIPListManager = NewIPListManager() 24 var IPListUpdateNotify = make(chan bool, 1) 25 26 func init() { 27 if !teaconst.IsMain { 28 return 29 } 30 31 events.On(events.EventLoaded, func() { 32 goman.New(func() { 33 SharedIPListManager.Start() 34 }) 35 }) 36 events.OnClose(func() { 37 SharedIPListManager.Stop() 38 }) 39 40 var ticker = time.NewTicker(24 * time.Hour) 41 goman.New(func() { 42 idles.RunTicker(ticker, func() { 43 SharedIPListManager.DeleteExpiredItems() 44 }) 45 }) 46 } 47 48 // IPListManager IP名单管理 49 type IPListManager struct { 50 ticker *time.Ticker 51 52 db IPListDB 53 54 lastVersion int64 55 fetchPageSize int64 56 57 listMap map[int64]*IPList 58 mu sync.RWMutex 59 60 isFirstTime bool 61 } 62 63 func NewIPListManager() *IPListManager { 64 return &IPListManager{ 65 fetchPageSize: 5_000, 66 listMap: map[int64]*IPList{}, 67 isFirstTime: true, 68 } 69 } 70 71 func (this *IPListManager) Start() { 72 this.Init() 73 74 // 第一次读取 75 err := this.Loop() 76 if err != nil { 77 remotelogs.ErrorObject("IP_LIST_MANAGER", err) 78 } 79 80 this.ticker = time.NewTicker(60 * time.Second) 81 if Tea.IsTesting() { 82 this.ticker = time.NewTicker(10 * time.Second) 83 } 84 var countErrors = 0 85 for { 86 select { 87 case <-this.ticker.C: 88 case <-IPListUpdateNotify: 89 } 90 err = this.Loop() 91 if err != nil { 92 countErrors++ 93 94 remotelogs.ErrorObject("IP_LIST_MANAGER", err) 95 96 // 连续错误小于3次的我们立即重试 97 if countErrors <= 3 { 98 select { 99 case IPListUpdateNotify <- true: 100 default: 101 } 102 } 103 } else { 104 countErrors = 0 105 } 106 } 107 } 108 109 func (this *IPListManager) Stop() { 110 if this.ticker != nil { 111 this.ticker.Stop() 112 } 113 } 114 115 func (this *IPListManager) Init() { 116 // 从数据库中当中读取数据 117 // 检查sqlite文件是否存在,以便决定使用sqlite还是kv 118 var sqlitePath = Tea.Root + "/data/ip_list.db" 119 _, sqliteErr := os.Stat(sqlitePath) 120 121 var db IPListDB 122 var err error 123 if sqliteErr == nil || !teaconst.EnableKVCacheStore { 124 db, err = NewSQLiteIPList() 125 } else { 126 db, err = NewKVIPList() 127 } 128 129 if err != nil { 130 remotelogs.Error("IP_LIST_MANAGER", "create ip list local database failed: "+err.Error()) 131 } else { 132 this.db = db 133 134 // 删除本地数据库中过期的条目 135 _ = db.DeleteExpiredItems() 136 137 // 本地数据库中最大版本号 138 this.lastVersion, err = db.ReadMaxVersion() 139 if err != nil { 140 remotelogs.Error("IP_LIST_MANAGER", "find max version failed: "+err.Error()) 141 this.lastVersion = 0 142 } 143 remotelogs.Println("IP_LIST_MANAGER", "starting from '"+db.Name()+"' version '"+types.String(this.lastVersion)+"' ...") 144 145 // 从本地数据库中加载 146 var offset int64 = 0 147 var size int64 = 2_000 148 149 var tr = trackers.Begin("IP_LIST_MANAGER:load") 150 defer tr.End() 151 152 for { 153 items, goNext, readErr := db.ReadItems(offset, size) 154 var l = len(items) 155 if readErr != nil { 156 remotelogs.Error("IP_LIST_MANAGER", "read ip list from local database failed: "+readErr.Error()) 157 } else { 158 this.processItems(items, false) 159 if !goNext { 160 break 161 } 162 } 163 offset += int64(l) 164 } 165 } 166 } 167 168 func (this *IPListManager) Loop() error { 169 // 是否同步IP名单 170 nodeConfig, _ := nodeconfigs.SharedNodeConfig() 171 if nodeConfig != nil && !nodeConfig.EnableIPLists { 172 return nil 173 } 174 175 // 第一次同步则打印信息 176 if this.isFirstTime { 177 remotelogs.Println("IP_LIST_MANAGER", "initializing ip items ...") 178 } 179 180 for { 181 hasNext, err := this.fetch() 182 if err != nil { 183 return err 184 } 185 if !hasNext { 186 break 187 } 188 time.Sleep(1 * time.Second) 189 } 190 191 // 第一次同步则打印信息 192 if this.isFirstTime { 193 this.isFirstTime = false 194 remotelogs.Println("IP_LIST_MANAGER", "finished initializing ip items") 195 } 196 197 return nil 198 } 199 200 func (this *IPListManager) fetch() (hasNext bool, err error) { 201 rpcClient, err := rpc.SharedRPC() 202 if err != nil { 203 return false, err 204 } 205 itemsResp, err := rpcClient.IPItemRPC.ListIPItemsAfterVersion(rpcClient.Context(), &pb.ListIPItemsAfterVersionRequest{ 206 Version: this.lastVersion, 207 Size: this.fetchPageSize, 208 }) 209 if err != nil { 210 if rpc.IsConnError(err) { 211 remotelogs.Debug("IP_LIST_MANAGER", "rpc connection error: "+err.Error()) 212 return false, nil 213 } 214 return false, err 215 } 216 var items = itemsResp.IpItems 217 if len(items) == 0 { 218 return false, nil 219 } 220 221 // 保存到本地数据库 222 if this.db != nil { 223 for _, item := range items { 224 err = this.db.AddItem(item) 225 if err != nil { 226 remotelogs.Error("IP_LIST_MANAGER", "insert item to local database failed: "+err.Error()) 227 } 228 } 229 } 230 231 this.processItems(items, true) 232 233 return true, nil 234 } 235 236 func (this *IPListManager) FindList(listId int64) *IPList { 237 this.mu.RLock() 238 var list = this.listMap[listId] 239 this.mu.RUnlock() 240 241 return list 242 } 243 244 func (this *IPListManager) DeleteExpiredItems() { 245 if this.db != nil { 246 _ = this.db.DeleteExpiredItems() 247 } 248 } 249 250 func (this *IPListManager) ListMap() map[int64]*IPList { 251 return this.listMap 252 } 253 254 // 处理IP条目 255 func (this *IPListManager) processItems(items []*pb.IPItem, fromRemote bool) { 256 var changedLists = map[*IPList]zero.Zero{} 257 for _, item := range items { 258 // 调试 259 if Tea.IsTesting() { 260 this.debugItem(item) 261 } 262 263 var list *IPList 264 // TODO 实现节点专有List 265 if item.ServerId > 0 { // 服务专有List 266 switch item.ListType { 267 case "black": 268 list = SharedServerListManager.FindBlackList(item.ServerId, true) 269 case "white": 270 list = SharedServerListManager.FindWhiteList(item.ServerId, true) 271 } 272 } else if item.IsGlobal { // 全局List 273 switch item.ListType { 274 case "black": 275 list = GlobalBlackIPList 276 case "white": 277 list = GlobalWhiteIPList 278 } 279 } else { // 其他List 280 this.mu.Lock() 281 list = this.listMap[item.ListId] 282 this.mu.Unlock() 283 } 284 if list == nil { 285 list = NewIPList() 286 this.mu.Lock() 287 this.listMap[item.ListId] = list 288 this.mu.Unlock() 289 } 290 291 changedLists[list] = zero.New() 292 293 if item.IsDeleted { 294 list.Delete(uint64(item.Id)) 295 296 // 从WAF名单中删除 297 waf.SharedIPBlackList.RemoveIP(item.IpFrom, item.ServerId, fromRemote) 298 299 // 操作事件 300 if fromRemote { 301 SharedActionManager.DeleteItem(item.ListType, item) 302 } 303 304 continue 305 } 306 307 list.AddDelay(&IPItem{ 308 Id: uint64(item.Id), 309 Type: item.Type, 310 IPFrom: iputils.ToBytes(item.IpFrom), 311 IPTo: iputils.ToBytes(item.IpTo), 312 ExpiredAt: item.ExpiredAt, 313 EventLevel: item.EventLevel, 314 }) 315 316 // 事件操作 317 if fromRemote { 318 SharedActionManager.DeleteItem(item.ListType, item) 319 SharedActionManager.AddItem(item.ListType, item) 320 } 321 } 322 323 if len(changedLists) > 0 { 324 for changedList := range changedLists { 325 changedList.Sort() 326 } 327 } 328 329 if fromRemote { 330 var latestVersion = items[len(items)-1].Version 331 if latestVersion > this.lastVersion { 332 this.lastVersion = latestVersion 333 } 334 } 335 } 336 337 // 调试IP信息 338 func (this *IPListManager) debugItem(item *pb.IPItem) { 339 var ipRange = item.IpFrom 340 if len(item.IpTo) > 0 { 341 ipRange += " - " + item.IpTo 342 } 343 344 if item.IsDeleted { 345 remotelogs.Debug("IP_ITEM_DEBUG", "delete '"+ipRange+"'") 346 } else { 347 remotelogs.Debug("IP_ITEM_DEBUG", "add '"+ipRange+"'") 348 } 349 }