129 lines
3.1 KiB
Go
129 lines
3.1 KiB
Go
package scanner
|
|
|
|
import (
|
|
"log"
|
|
"os"
|
|
"strings"
|
|
"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, network.TypeRealtimeFileAlert, op, network.StatusDetected)
|
|
} else if !isHashMatch {
|
|
log.Printf("[监听器] 实时拦截:检测到白名单文件被篡改 (%s): %s", op, path)
|
|
w.reportEvent(path, network.TypeRealtimeFileAlert, op, network.StatusHashMismatch)
|
|
}
|
|
}
|
|
|
|
func (w *Watcher) reportEvent(path, alertType, op string, status string) {
|
|
// 标准化操作类型
|
|
operation := network.OpModify
|
|
if strings.Contains(strings.ToUpper(op), "CREATE") {
|
|
operation = network.OpCreate
|
|
} else if strings.Contains(strings.ToUpper(op), "DELETE") {
|
|
operation = network.OpDelete
|
|
}
|
|
|
|
payload := network.FileEventPayload{
|
|
FilePath: path,
|
|
Operation: operation,
|
|
Status: status,
|
|
Timestamp: time.Now().Unix(),
|
|
}
|
|
|
|
packet := network.NewPacket(alertType, payload)
|
|
w.client.SendQueue(packet)
|
|
}
|
|
|
|
func (w *Watcher) Stop() {
|
|
log.Println("[监听器] 停止实时文件监控...")
|
|
close(w.stopChan)
|
|
w.watcher.Close()
|
|
}
|