This repository has been archived on 2026-03-28. You can view files and clone it, but cannot push or open issues or pull requests.
old-sysmonitord/internal/scanner/scanner.go
wuko233 31ad2fb41a fix: 文件监控支持从远程配置读取;
feat: 添加用户配置的扫描路径支持
2026-03-26 16:35:18 +08:00

135 lines
3.0 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package scanner
import (
"log"
"os"
"path/filepath"
"time"
"github.com/shirou/gopsutil/v4/cpu"
"github.com/wuko233/sysmonitord/internal/network"
"github.com/wuko233/sysmonitord/internal/whitelist"
)
type Scanner struct {
wlManager *whitelist.Manager
client *network.WSClient
cpuLimit float64
scanPaths []string
stopChan chan struct{}
}
func NewScanner(wl *whitelist.Manager, client *network.WSClient, scanPaths []string) *Scanner {
return &Scanner{
wlManager: wl,
client: client,
cpuLimit: 50.0,
scanPaths: scanPaths,
stopChan: make(chan struct{}),
}
}
func (s *Scanner) Start() {
log.Println("[扫描器] 启动文件完整性扫描...")
go s.scanLoop()
}
func (s *Scanner) scanLoop() {
ticker := time.NewTicker(10 * time.Minute)
defer ticker.Stop()
for {
select {
case <-s.stopChan:
return
case <-ticker.C:
s.performScan()
}
}
}
func (s *Scanner) performScan() {
log.Println("[扫描器] 开始新一轮全盘扫描")
fileCount := 0
for _, root := range s.scanPaths {
err := filepath.Walk(root, func(path string, info os.FileInfo, err error) error {
select {
case <-s.stopChan:
return filepath.SkipDir
default:
}
if err != nil {
log.Printf("[扫描器] 访问错误: %v", err)
return nil
}
fileCount++
if fileCount%100 == 0 {
s.checkCPUAndSleep()
}
if info.IsDir() {
if s.wlManager.IsPathIgnored(path) {
return filepath.SkipDir
}
return nil
}
isWhitelisted, isHashMatch, err := s.wlManager.CheckFileStatus(path)
if err != nil {
log.Printf("[扫描器] 检查文件状态失败: %v", err)
return nil
}
if !isWhitelisted {
log.Printf("[扫描器] 发现未在白名单文件: %s", path)
s.reportFile(path, network.TypeScanResult, network.StatusDetected)
} else if !isHashMatch {
log.Printf("[扫描器] 警告文件Hash不匹配(可能被篡改): %s", path)
s.reportFile(path, network.TypeScanResult, network.StatusHashMismatch)
}
return nil
})
if err != nil {
log.Printf("[扫描器] 扫描目录 %s 出错: %v", root, err)
}
}
}
func (s *Scanner) checkCPUAndSleep() {
percent, err := cpu.Percent(200*time.Millisecond, false)
if err != nil || len(percent) == 0 {
log.Printf("[扫描器] 获取CPU使用率失败: %v", err)
return
}
if percent[0] > s.cpuLimit {
log.Printf("[扫描器] CPU使用率过高 (%.2f%%)暂停扫描5秒", percent[0])
time.Sleep(5 * time.Second)
}
time.Sleep(10 * time.Millisecond)
}
func (s *Scanner) reportFile(path string, alertType string, status string) {
payload := network.FileEventPayload{
FilePath: path,
Operation: "", // 周期扫描没有特定操作
Status: status,
Timestamp: time.Now().Unix(),
}
packet := network.NewPacket(network.TypeScanResult, payload)
s.client.SendQueue(packet)
}
func (s *Scanner) Stop() {
log.Println("[扫描器] 停止文件完整性扫描...")
close(s.stopChan)
}