128 lines
2.7 KiB
Go
128 lines
2.7 KiB
Go
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) *Scanner {
|
||
return &Scanner{
|
||
wlManager: wl,
|
||
client: client,
|
||
cpuLimit: 50.0,
|
||
scanPaths: []string{"/bin", "/sbin", "/usr/bin", "/usr/sbin", "/etc", "/tmp", "/home"},
|
||
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("[扫描器] 开始新一轮全盘扫描")
|
||
|
||
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 {
|
||
return nil
|
||
}
|
||
|
||
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, "NON_WHITELISTED_FILE")
|
||
} else if !isHashMatch {
|
||
log.Printf("[扫描器] 警告!文件Hash不匹配(可能被篡改): %s", path)
|
||
s.reportFile(path, "FILE_HASH_MISMATCH")
|
||
}
|
||
|
||
return nil
|
||
})
|
||
if err != nil {
|
||
log.Printf("[扫描器] 扫描目录 %s 出错: %v", root, err)
|
||
}
|
||
}
|
||
}
|
||
|
||
func (s *Scanner) checkCPUAndSleep() {
|
||
percent, err := cpu.Percent(time.Second, 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) {
|
||
payload := map[string]interface{}{
|
||
"filepath": path,
|
||
"status": "detected",
|
||
}
|
||
|
||
packet := network.NewPactet(alertType, payload)
|
||
|
||
s.client.SendQueue(packet)
|
||
}
|
||
|
||
func (s *Scanner) Stop() {
|
||
log.Println("[扫描器] 停止文件完整性扫描...")
|
||
close(s.stopChan)
|
||
}
|