diff --git a/cmd/start/start.go b/cmd/start/start.go index f8cafa2..b5b2a8f 100644 --- a/cmd/start/start.go +++ b/cmd/start/start.go @@ -4,10 +4,12 @@ import ( "fmt" "os" "sysmonitord/internal/config" + "sysmonitord/internal/scanner/file" "sysmonitord/internal/scanner/hash" "sysmonitord/internal/scanner/process" "sysmonitord/internal/storage" "sysmonitord/pkg/logger" + "time" "github.com/spf13/cobra" "go.uber.org/zap" @@ -42,6 +44,8 @@ var StartCmd = &cobra.Command{ FileSystemFile: cfg.Storage.FileSystemFile, } + // ====== 进程扫描和存储 ====== + procs, err := process.ScanAllProcesses(hashCfg) if err != nil { logger.Log.Error("扫描进程失败", zap.Error(err)) @@ -67,5 +71,36 @@ var StartCmd = &cobra.Command{ zap.Stringer("data", p), ) } + + // ====== 文件扫描和存储 ====== + logger.Log.Info("正在扫描文件系统...") + + startTime := time.Now() + fileCfg := &config.FileScannerConfig{ + IncludePaths: cfg.Scanner.File.IncludePaths, + ExcludePaths: cfg.Scanner.File.ExcludePaths, + FastHash: cfg.Scanner.File.FastHash, + FastHashSize: cfg.Scanner.File.FastHashSize, + FastHashChunk: cfg.Scanner.File.FastHashChunk, + } + + fileScanner := file.NewScanner(fileCfg) + files, err := fileScanner.Scan() + if err != nil { + logger.Log.Error("扫描文件系统失败", zap.Error(err)) + os.Exit(1) + } else { + if err := storage.SaveFileSystem(files, storageCfg.DataDir, storageCfg.FileSystemFile); err != nil { + logger.Log.Error("保存文件系统白名单失败", zap.Error(err)) + os.Exit(1) + } + } + + duration := time.Since(startTime) + logger.Log.Info("文件系统扫描完成", + zap.Int("文件数量", len(files)), + zap.Duration("扫描耗时", duration), + ) + }, } diff --git a/config.yaml b/config.yaml index 03428d0..79bd661 100644 --- a/config.yaml +++ b/config.yaml @@ -10,6 +10,8 @@ audit: scanner: file: + include_paths: + - /home exclude_paths: - /proc - /sys diff --git a/development.md b/development.md index e6f0a02..7d2aa9c 100644 --- a/development.md +++ b/development.md @@ -350,6 +350,8 @@ audit: # 扫描配置 scanner: file: + include_paths: + - / exclude_paths: - /proc/ - /sys/ diff --git a/internal/config/config.go b/internal/config/config.go index 2f24240..039fa72 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -33,6 +33,7 @@ type StorageConfig struct { } type FileScannerConfig struct { + IncludePaths []string `yaml:"include_paths"` ExcludePaths []string `yaml:"exclude_paths"` FastHash bool `yaml:"fast_hash"` FastHashSizeRaw string `yaml:"fast_hash_size"` diff --git a/internal/scanner/file/scanner.go b/internal/scanner/file/scanner.go new file mode 100644 index 0000000..4f0dc4a --- /dev/null +++ b/internal/scanner/file/scanner.go @@ -0,0 +1,107 @@ +package file + +import ( + "fmt" + "io/fs" + "os" + "path/filepath" + "strings" + "sysmonitord/internal/config" + "sysmonitord/internal/scanner/hash" + "sysmonitord/pkg/logger" + + "go.uber.org/zap" +) + +type FileInfo struct { + Path string + Hash string + ModTime int64 + Size int64 +} + +type Scanner struct { + cfg *config.FileScannerConfig +} + +func NewScanner(cfg *config.FileScannerConfig) *Scanner { + return &Scanner{ + cfg: cfg, + } +} + +func (s *Scanner) Scan() ([]FileInfo, error) { + targetPaths := s.cfg.IncludePaths + if len(targetPaths) == 0 { + targetPaths = []string{"/"} + } + + var allFiles []FileInfo + + for _, root := range targetPaths { + if _, err := os.Stat(root); os.IsNotExist(err) { + continue + } + + logger.Log.Info("[scan]正在扫描文件系统", zap.String("root", root)) + + err := filepath.WalkDir(root, s.WalkFunc(&allFiles)) + if err != nil { + logger.Log.Error("[scan]扫描文件系统时发生错误", zap.String("root", root), zap.Error(err)) + } + } + + return allFiles, nil +} + +func (s *Scanner) WalkFunc(result *[]FileInfo) fs.WalkDirFunc { + return func(path string, d fs.DirEntry, err error) error { + if err != nil { + logger.Log.Debug("[scan]跳过路径", zap.String("path", path), zap.Error(err)) + return fs.SkipDir + } + + if d.IsDir() { + return nil + } + + for _, exclude := range s.cfg.ExcludePaths { + if strings.HasPrefix(path, exclude) { + logger.Log.Debug("[scan]跳过路径", zap.String("path", path), zap.String("reason", "匹配排除路径")) + return fs.SkipDir + } + } + + info, err := d.Info() + if err != nil { + logger.Log.Debug("[scan]无法获取文件信息", zap.String("path", path), zap.Error(err)) + return nil + } + + if info.Size() != 0 { + hash, err := hash.SHA256(path, &hash.Config{ + UseFastHash: s.cfg.FastHash, + Threshold: s.cfg.FastHashSize, + ChunkSize: s.cfg.FastHashChunk, + }) + + if err != nil { + logger.Log.Debug("[scan]无法计算文件哈希", zap.String("path", path), zap.Error(err)) + return nil + } + + *result = append(*result, FileInfo{ + Path: path, + Hash: hash, + ModTime: info.ModTime().Unix(), + Size: info.Size(), + }) + } + + return nil + } +} + +func (f FileInfo) String() string { + return fmt.Sprintf("%s:%s", f.Path, f.Hash) +} diff --git a/internal/storage/storage.go b/internal/storage/storage.go index 34748da..d214584 100644 --- a/internal/storage/storage.go +++ b/internal/storage/storage.go @@ -5,6 +5,7 @@ import ( "fmt" "os" "path/filepath" + "sysmonitord/internal/scanner/file" "sysmonitord/internal/scanner/process" "sysmonitord/pkg/logger" "time" @@ -60,3 +61,38 @@ func SaveProcessSystem(proc []process.ProcessInfo, dataDir string, processSystem return nil } + +func SaveFileSystem(files []file.FileInfo, dataDir string, fileSystemFile string) error { + filePath := filepath.Join(dataDir, fileSystemFile) + file, err := os.Create(filePath) // 覆盖 + if err != nil { + return fmt.Errorf("[storage]无法创建储存文件系统文件%s: %w", filePath, err) + } + defer file.Close() + + writer := bufio.NewWriter(file) + + currentTime := time.Now().Format("2006-01-02 15:04:05") + header := fmt.Sprintf("# 文件系统白名单 - 生成时间: %s\n", currentTime) + if _, err := writer.WriteString(header); err != nil { + return err + } + + for _, f := range files { + line := fmt.Sprintf("%v\n", f) + if _, err := writer.WriteString(line); err != nil { + return err + } + } + + if err := writer.Flush(); err != nil { + return err + } + + logger.Log.Info("[storage]文件系统白名单保存成功", + zap.String("file", filePath), + zap.Int("file_count", len(files)), + ) + + return nil +}