package scanner import ( "log" "os" "time" "github.com/fsnotify/fsnotify" "github.com/wuko233/sysmonitord/internal/network" "github.com/wuko233/sysmonitord/internal/whitelist" ) type Watcher struct { wlManager *whitelist.Manager client *network.WSClient watcher *fsnotify.Watcher stopChan chan struct{} watchPaths []string } func NewWatcher(wl *whitelist.Manager, client *network.WSClient) (*Watcher, error) { fsWatch, err := fsnotify.NewWatcher() if err != nil { return nil, err } return &Watcher{ wlManager: wl, client: client, watcher: fsWatch, stopChan: make(chan struct{}), // TODO: 当前仅实现对主目录的监控,后续实现递归监控子目录 watchPaths: []string{ "/bin", "/sbin", "/usr/bin", "/etc/init.d", "/tmp", }, }, nil } func (w *Watcher) Start() { log.Println("[监听器] 启动实时文件监控...") for _, path := range w.watchPaths { if _, err := os.Stat(path); err == nil { if err := w.watcher.Add(path); err != nil { log.Printf("[监听器] 无法监控路径 %s: %v", path, err) } else { log.Printf("[监听器] 开始监控路径: %s", path) } } } go w.eventLoop() } func (w *Watcher) eventLoop() { for { select { case <-w.stopChan: return case event, ok := <-w.watcher.Events: if !ok { return } if event.Has(fsnotify.Create) || event.Has(fsnotify.Write) { if w.wlManager.IsPathIgnored(event.Name) { continue } go w.handleFileChange(event.Name, event.Op.String()) } case err, ok := <-w.watcher.Errors: if !ok { return } log.Printf("[监听器] 错误: %v", err) } } } func (w *Watcher) handleFileChange(path string, op string) { time.Sleep(200 * time.Millisecond) // 等待文件写入完成 if _, err := os.Stat(path); os.IsNotExist(err) { return } isWhitelisted, isHashMatch, err := w.wlManager.CheckFileStatus(path) if err != nil { return } if !isWhitelisted { log.Printf("[监听器] 实时拦截:检测到非白名单文件变动 (%s): %s", op, path) w.reportEvent(path, "REALTIME_FILE_ALERT", op) } else if !isHashMatch { log.Printf("[监听器] 实时拦截:检测到白名单文件被篡改 (%s): %s", op, path) w.reportEvent(path, "REALTIME_HASH_MISMATCH", op) } } func (w *Watcher) reportEvent(path, alertType, op string) { payload := map[string]interface{}{ "filepath": path, "operation": op, "time": time.Now(), } packet := network.NewPacket(alertType, payload) w.client.SendQueue(packet) } func (w *Watcher) Stop() { log.Println("[监听器] 停止实时文件监控...") close(w.stopChan) w.watcher.Close() }