From 26cc907024c2e24a40d4028dd741c6099284b70e Mon Sep 17 00:00:00 2001 From: wuko233 Date: Thu, 26 Mar 2026 21:15:05 +0800 Subject: [PATCH] =?UTF-8?q?refactor:=20=E9=87=8D=E6=9E=84=E5=88=9D?= =?UTF-8?q?=E5=A7=8B=E5=8C=96=E9=80=BB=E8=BE=91=EF=BC=8C=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E9=85=8D=E7=BD=AE=E5=8A=A0=E8=BD=BD=E5=92=8C=E8=BF=90=E8=A1=8C?= =?UTF-8?q?=E7=AE=A1=E7=90=86=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- cmd/sysmonitord/main.go | 191 +++----------------------------- internal/initializer/config.go | 84 ++++++++++++++ internal/initializer/logger.go | 22 ++++ internal/initializer/runtime.go | 140 +++++++++++++++++++++++ 4 files changed, 262 insertions(+), 175 deletions(-) create mode 100644 internal/initializer/config.go create mode 100644 internal/initializer/logger.go create mode 100644 internal/initializer/runtime.go diff --git a/cmd/sysmonitord/main.go b/cmd/sysmonitord/main.go index 4a0d1ca..a5e4cd6 100644 --- a/cmd/sysmonitord/main.go +++ b/cmd/sysmonitord/main.go @@ -1,29 +1,16 @@ package main import ( - "io" "log" "os" "os/signal" "syscall" - "time" - "github.com/wuko233/sysmonitord/internal/config" - "github.com/wuko233/sysmonitord/internal/monitor" - "github.com/wuko233/sysmonitord/internal/network" - "github.com/wuko233/sysmonitord/internal/scanner" - "github.com/wuko233/sysmonitord/internal/whitelist" - "gopkg.in/natefinch/lumberjack.v2" -) - -const ( - OfficialConfigURL = "http://localhost:8090/api/v1/configs/official.json" - UserConfigURL = "http://localhost:8090/api/v1/configs/user.json" + "github.com/wuko233/sysmonitord/internal/initializer" ) func main() { - - initLogger() + initializer.InitLogger() log.Println("==========================================") log.Print(` _ _ _ @@ -37,175 +24,29 @@ func main() { `) log.Println("==========================================") - // 加载配置 - log.Println("[启动流程] 1/6: 下载远程安全策略配置...") - cfgLoader := network.NewConfigLoader() + log.Println("[初始化]: 从远程加载配置...") + cfgLoader := initializer.NewConfigLoader() - officialCfg, userCfg, err := cfgLoader.LoadConfigs(network.ConfigUrls{ - OfficialConfigUrl: OfficialConfigURL, - UserConfigUrl: UserConfigURL, - }) + officialCfg, userCfg, err := cfgLoader.Load( + "http://localhost:8090/api/v1/configs/official.json", + "http://localhost:8090/api/v1/configs/user.json", + ) if err != nil { - log.Fatalf("[启动错误]下载配置失败: %v", err) + log.Fatalf("[错误] 加载配置失败: %v", err) + panic(err) } + log.Println("[初始化]: 配置加载成功") - CenterServerURL := determineServerURL(userCfg) - - log.Println("[启动流程] 2/6: 初始化白名单判定引擎...") - wlManager := whitelist.NewManager(officialCfg, userCfg) - wlManager.UpdateConfig(officialCfg, userCfg) - - log.Println("[启动流程] 3/6: 启动中心服务器连接...") - centerClient := network.NewWSClient(network.ClientConfig{ - ServerURL: CenterServerURL, - SendInterval: 1 * time.Second, - BufferSize: 1000, - }) - centerClient.Start() - - auditUrl := wlManager.GetAuditServerUrl() - if auditUrl == "" { - auditUrl = CenterServerURL + runtime := initializer.NewRuntime(*officialCfg, *userCfg) + if err := runtime.Start(); err != nil { + log.Fatalf("[错误] 启动进程失败: %v", err) + panic(err) } - auditClient := network.NewWSClient(network.ClientConfig{ - ServerURL: auditUrl, - SendInterval: 1 * time.Second, - BufferSize: 1000, - }) - auditClient.Start() - - log.Println("[启动流程] 4/6: 启动文件完整性防护...") - - var sysScanner *scanner.Scanner - var sysWatcher *scanner.Watcher - var sshMon *monitor.SSHMonitor - var infoMon *monitor.InfoMonitor - - scanPaths := determineScanPaths(officialCfg, userCfg) - - // 扫盘器 - if userCfg.Modules.FileScanner { - sysScanner = scanner.NewScanner(wlManager, centerClient, scanPaths) - sysScanner.Start() - log.Printf("[监控信息] 文件周期扫描器已启动") - } - - // 监控器 - if userCfg.Modules.FileWatcher { - var err error - sysWatcher, err = scanner.NewWatcher(wlManager, centerClient, scanPaths) - if err != nil { - log.Fatalf("[启动错误] 初始化监控器失败: %v", err) - } else { - sysWatcher.Start() - log.Printf("[监控信息] 文件监控已启动") - } - } - - log.Println("[启动流程] 5/6: 启动系统行为监控...") - - // SSH监控 - if userCfg.Modules.SSHMonitor { - sshAlertChan := make(chan monitor.Alert, 100) - sshMon = monitor.NewSSHMonitor(&userCfg.MonitorConfig.SSHMonitorConfig, sshAlertChan) - go func() { - for alert := range sshAlertChan { - packet := network.NewPacket("SSH_ALERT", alert) - auditClient.SendQueue(packet) - } - }() - - go func() { - if err := sshMon.Start(); err != nil { - log.Printf("[监控错误] SSH监控遇到错误: %v", err) - } - log.Printf("[监控信息] SSH监控已启动") - }() - } - - // 状态监控 - if userCfg.Modules.SystemMonitor { - metricsChan := make(chan monitor.ServerMetrics, 100) - - SystemMonitorCfg := &userCfg.MonitorConfig.SystemMonitorConfig - infoMon = monitor.NewInfoMonitor(SystemMonitorCfg, metricsChan) - - go func() { - for metrics := range metricsChan { - packet := network.NewPacket("STATUS_UPDATE", metrics) - centerClient.SendQueue(packet) - } - }() - - go infoMon.Start() - log.Printf("[监控信息] 系统状态监控已启动") - } - - log.Println("[启动流程] 6/6: 系统监控守护进程启动完成!") stopChan := make(chan os.Signal, 1) signal.Notify(stopChan, os.Interrupt, syscall.SIGTERM) <-stopChan - log.Println("[守护进程] 接收到停止信号,正在关闭...") - if sysWatcher != nil { - sysWatcher.Stop() - } - - if sysScanner != nil { - sysScanner.Stop() - } - if sshMon != nil { - sshMon.Stop() - } - if infoMon != nil { - infoMon.Stop() - } - if centerClient != nil { - centerClient.Stop() - } - - centerClient.Stop() - auditClient.Stop() - - log.Println("[守护进程] 已成功停止,安全退出程序。") -} - -func determineServerURL(userCfg config.UserConfig) string { - // 服务器地址仅从用户配置获取(符合 ARCHITECTURE.md 规范) - if userCfg.Connection.CenterServerURL != "" { - return userCfg.Connection.CenterServerURL - } - - // 默认地址 - return "ws://localhost:8090/api/v1/ws" -} - -func initLogger() { - log.SetOutput(os.Stdout) - fileLogger := &lumberjack.Logger{ - Filename: "/var/log/sysmonitord/sysmonitord.log", - MaxSize: 100, // MB - MaxBackups: 7, - MaxAge: 30, // 天 - Compress: true, - } - - log.SetOutput(io.MultiWriter(os.Stdout, fileLogger)) -} - -func determineScanPaths(officialCfg config.OfficialConfig, userCfg config.UserConfig) []string { - // 从用户配置获取扫描路径 - if len(userCfg.ScanPaths) > 0 { - return userCfg.ScanPaths - } - - // 从官方配置获取扫描路径 - if len(officialCfg.ScanPaths) > 0 { - return officialCfg.ScanPaths - } - - // 默认扫描路径 - return []string{"/bin", "/sbin", "/usr/bin", "/usr/sbin", "/etc", "/tmp", "/home"} + runtime.Stop() } diff --git a/internal/initializer/config.go b/internal/initializer/config.go new file mode 100644 index 0000000..7a7a247 --- /dev/null +++ b/internal/initializer/config.go @@ -0,0 +1,84 @@ +package initializer + +import ( + "encoding/json" + "fmt" + "io" + "net/http" + "time" + + "github.com/wuko233/sysmonitord/internal/config" +) + +type ConfigLoader struct { + client *http.Client +} + +func NewConfigLoader() *ConfigLoader { + return &ConfigLoader{ + client: &http.Client{Timeout: 10 * time.Second}, + } +} + +func (l *ConfigLoader) Load(officialURL, UserURL string) (*config.OfficialConfig, *config.UserConfig, error) { + var officialCfg config.OfficialConfig + var userCfg config.UserConfig + + if err := l.fetchJSON(officialURL, &officialCfg); err != nil { + return nil, nil, fmt.Errorf("加载官方配置失败: %v", err) + } + + if err := l.fetchJSON(UserURL, &userCfg); err != nil { + return nil, nil, fmt.Errorf("加载用户配置失败: %v", err) + } + + return &officialCfg, &userCfg, nil +} + +func (l *ConfigLoader) fetchJSON(url string, target interface{}) error { + resp, err := l.client.Get(url) + if err != nil { + return err + } + defer resp.Body.Close() + + if resp.StatusCode != http.StatusOK { + return fmt.Errorf("HTTP %s", resp.Status) + } + + body, err := io.ReadAll(resp.Body) + if err != nil { + return err + } + + return json.Unmarshal(body, target) +} + +func determineServerURL(userCfg config.UserConfig) string { + if userCfg.Connection.CenterServerURL != "" { + return userCfg.Connection.CenterServerURL + } + + // 默认地址 + return "ws://localhost:8090/api/v1/ws" +} + +func determineScanPaths(officialCfg config.OfficialConfig, userCfg config.UserConfig) []string { + // 从用户配置获取扫描路径 + if len(userCfg.ScanPaths) > 0 { + return userCfg.ScanPaths + } + + // 从官方配置获取扫描路径 + if len(officialCfg.ScanPaths) > 0 { + return officialCfg.ScanPaths + } + + // 默认扫描路径 + return []string{"/bin", "/sbin", "/usr/bin", "/usr/sbin", "/etc", "/tmp", "/home"} +} + +func determineWatchPaths(official config.OfficialConfig, user config.UserConfig) []string { + // 可复用扫描路径,或从 user.WatchPaths 读取 + return determineScanPaths(official, user) +} diff --git a/internal/initializer/logger.go b/internal/initializer/logger.go new file mode 100644 index 0000000..bc169de --- /dev/null +++ b/internal/initializer/logger.go @@ -0,0 +1,22 @@ +package initializer + +import ( + "io" + "log" + "os" + + "gopkg.in/natefinch/lumberjack.v2" +) + +func InitLogger() { + log.SetOutput(os.Stdout) + fileLogger := &lumberjack.Logger{ + Filename: "/var/log/sysmonitord/sysmonitord.log", + MaxSize: 100, // MB + MaxBackups: 7, + MaxAge: 30, // 天 + Compress: true, + } + + log.SetOutput(io.MultiWriter(os.Stdout, fileLogger)) +} diff --git a/internal/initializer/runtime.go b/internal/initializer/runtime.go new file mode 100644 index 0000000..822e71d --- /dev/null +++ b/internal/initializer/runtime.go @@ -0,0 +1,140 @@ +package initializer + +import ( + "log" + "time" + + "github.com/wuko233/sysmonitord/internal/config" + "github.com/wuko233/sysmonitord/internal/monitor" + "github.com/wuko233/sysmonitord/internal/network" + "github.com/wuko233/sysmonitord/internal/scanner" + "github.com/wuko233/sysmonitord/internal/whitelist" +) + +type Runtime struct { + officialCfg config.OfficialConfig + userCfg config.UserConfig + centerCil *network.WSClient + auditCil *network.WSClient + scanner *scanner.Scanner + watcher *scanner.Watcher + sshMon *monitor.SSHMonitor + infoMon *monitor.InfoMonitor +} + +func NewRuntime(official config.OfficialConfig, user config.UserConfig) *Runtime { + return &Runtime{ + officialCfg: official, + userCfg: user, + } +} + +func (r *Runtime) Start() error { + // 初始化白名单引擎 + log.Println("[初始化]: 初始化白名单判定引擎...") + wlManager := whitelist.NewManager(r.officialCfg, r.userCfg) + + // WebSocket客户端 + log.Println("[初始化]: 启动中心服务器连接...") + centerURL := determineServerURL(r.userCfg) + r.centerCil = network.NewWSClient(network.ClientConfig{ + ServerURL: centerURL, + SendInterval: 1 * time.Second, + BufferSize: 1000, + }) + r.centerCil.Start() + + auditURL := wlManager.GetAuditServerUrl() + if auditURL == "" { + auditURL = centerURL + } + r.auditCil = network.NewWSClient(network.ClientConfig{ + ServerURL: auditURL, + SendInterval: 1 * time.Second, + BufferSize: 1000, + }) + r.auditCil.Start() + + // 文件扫描器 + if r.userCfg.Modules.FileScanner { + r.scanner = scanner.NewScanner(wlManager, r.centerCil, determineScanPaths(r.officialCfg, r.userCfg)) + r.scanner.Start() + log.Printf("[初始化]: 文件周期扫描器已启动") + } + + // 文件监控器 + if r.userCfg.Modules.FileWatcher { + var err error + r.watcher, err = scanner.NewWatcher(wlManager, r.centerCil, determineWatchPaths(r.officialCfg, r.userCfg)) + if err != nil { + return err + } + r.watcher.Start() + log.Printf("[初始化]: 文件监控已启动") + } + + // SSH监控器 + if r.userCfg.Modules.SSHMonitor { + sshAlertChan := make(chan monitor.Alert, 100) + r.sshMon = monitor.NewSSHMonitor(&r.userCfg.MonitorConfig.SSHMonitorConfig, sshAlertChan) + go func() { + for alert := range sshAlertChan { + packet := network.NewPacket("SSH_ALERT", alert) + r.auditCil.SendQueue(packet) + } + }() + + go func() { + if err := r.sshMon.Start(); err != nil { + log.Printf("[错误] SSH监控遇到错误: %v", err) + } + log.Printf("[初始化] SSH监控已启动") + }() + } + + // 系统信息监控器 + if r.userCfg.Modules.SystemMonitor { + metricsChan := make(chan monitor.ServerMetrics, 100) + + SystemMonitorCfg := &r.userCfg.MonitorConfig.SystemMonitorConfig + r.infoMon = monitor.NewInfoMonitor(SystemMonitorCfg, metricsChan) + + go func() { + for metrics := range metricsChan { + packet := network.NewPacket("STATUS_UPDATE", metrics) + r.centerCil.SendQueue(packet) + } + }() + + go r.infoMon.Start() + log.Printf("[初始化] 系统状态监控已启动") + } + + return nil +} + +func (r *Runtime) Stop() { + log.Println("[进程]接收到停止信号,正在关闭...") + + if r.watcher != nil { + r.watcher.Stop() + } + if r.scanner != nil { + r.scanner.Stop() + } + if r.sshMon != nil { + r.sshMon.Stop() + } + if r.infoMon != nil { + r.infoMon.Stop() + } + + if r.centerCil != nil { + r.centerCil.Stop() + } + if r.auditCil != nil { + r.auditCil.Stop() + } + + log.Println("[进程] 已成功停止,安全退出程序。") +}