feat: 添加文件完整性扫描和实时监控功能
This commit is contained in:
parent
2adbae8310
commit
c0cf6265e2
|
|
@ -0,0 +1,127 @@
|
|||
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)
|
||||
}
|
||||
|
|
@ -0,0 +1,119 @@
|
|||
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.NewPactet(alertType, payload)
|
||||
w.client.SendQueue(packet)
|
||||
}
|
||||
|
||||
func (w *Watcher) Stop() {
|
||||
log.Println("[监听器] 停止实时文件监控...")
|
||||
close(w.stopChan)
|
||||
w.watcher.Close()
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user