在 Linux 环境增加自动配置 ICMP 权限的逻辑

This commit is contained in:
dushixiang committed 2025-12-06 15:20:15 +08:00
1 parent 087b4b4071
commit d10fad98ba
3 files changed
+129 -29

No files matched your search

+36 -29
View File
@@ -9,6 +9,7 @@ import (
"syscall"
"github.com/dushixiang/pika/pkg/agent/config"
"github.com/dushixiang/pika/pkg/agent/sysutil"
"github.com/dushixiang/pika/pkg/agent/updater"
"github.com/kardianos/service"
)
@@ -21,33 +22,53 @@ type program struct {
cancel context.CancelFunc
}
// Start 启动服务
func (p *program) Start(s service.Service) error {
log.Println("✅ Pika Agent 服务启动中...")
// 创建 context
p.ctx, p.cancel = context.WithCancel(context.Background())
// configureICMP 配置 ICMP 权限(抽取通用逻辑)
func configureICMP() {
if err := sysutil.ConfigureICMPPermissions(); err != nil {
log.Printf("⚠️ 配置 ICMP 权限失败: %v", err)
log.Println(" 提示: ICMP 监控可能需要 root 权限运行,或手动执行:")
log.Println(" sudo sysctl -w net.ipv4.ping_group_range=\"0 2147483647\"")
}
}
// startAgent 启动 Agent 和自动更新(抽取通用逻辑)
func startAgent(ctx context.Context, cfg *config.Config) *Agent {
// 创建 Agent 实例
p.agent = New(p.cfg)
agent := New(cfg)
// 启动自动更新(如果启用)
if p.cfg.AutoUpdate.Enabled {
upd, err := updater.New(p.cfg, GetVersion())
if cfg.AutoUpdate.Enabled {
upd, err := updater.New(cfg, GetVersion())
if err != nil {
log.Printf("⚠️ 创建更新器失败: %v", err)
} else {
go upd.Start(p.ctx)
go upd.Start(ctx)
}
}
// 在后台启动 Agent
go func() {
if err := p.agent.Start(p.ctx); err != nil {
if err := agent.Start(ctx); err != nil {
log.Printf("⚠️ 探针运行出错: %v", err)
}
}()
return agent
}
// Start 启动服务
func (p *program) Start(s service.Service) error {
log.Println("✅ Pika Agent 服务启动中...")
// 初始化系统配置(Linux ICMP 权限等)
configureICMP()
// 创建 context
p.ctx, p.cancel = context.WithCancel(context.Background())
// 启动 Agent
p.agent = startAgent(p.ctx, p.cfg)
return nil
}
@@ -189,6 +210,9 @@ func (m *ServiceManager) Run() error {
log.Printf(" 采集间隔: %v", m.cfg.GetCollectorInterval())
log.Printf(" 心跳间隔: %v", m.cfg.GetHeartbeatInterval())
// 初始化系统配置(Linux ICMP 权限等)
configureICMP()
// 创建 context
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
@@ -197,25 +221,8 @@ func (m *ServiceManager) Run() error {
interrupt := make(chan os.Signal, 1)
signal.Notify(interrupt, os.Interrupt, syscall.SIGTERM)
// 创建 Agent 实例
agent := New(m.cfg)
// 启动自动更新(如果启用)
if m.cfg.AutoUpdate.Enabled {
upd, err := updater.New(m.cfg, GetVersion())
if err != nil {
log.Printf("⚠️ 创建更新器失败: %v", err)
} else {
go upd.Start(ctx)
}
}
// 启动 Agent
go func() {
if err := agent.Start(ctx); err != nil {
log.Printf("⚠️ 探针运行出错: %v", err)
}
}()
agent := startAgent(ctx, m.cfg)
// 等待中断信号
<-interrupt
+83
View File
@@ -0,0 +1,83 @@
package sysutil
import (
"fmt"
"log"
"os"
"strconv"
"strings"
)
// ConfigureICMPPermissions 配置 ICMP 权限
// 在 Linux 系统上,允许非特权用户发起 ICMP 请求
// 使用 sync.Once 确保只执行一次
func ConfigureICMPPermissions() error {
return doConfigureICMPPermissions()
}
// doConfigureICMPPermissions 实际执行配置
func doConfigureICMPPermissions() error {
const sysctlPath = "/proc/sys/net/ipv4/ping_group_range"
// 1. 先检查当前配置
currentMin, currentMax, err := readPingGroupRange(sysctlPath)
if err != nil {
return fmt.Errorf("读取当前 ICMP 配置失败: %w", err)
}
// 2. 检查是否已经满足要求 (范围包含 0 到 2147483647)
if currentMin <= 0 && currentMax >= 2147483647 {
log.Printf("✅ ICMP 权限已配置: net.ipv4.ping_group_range=%d %d", currentMin, currentMax)
return nil
}
// 3. 需要配置,写入新值
log.Printf("🔧 当前 ICMP 配置: net.ipv4.ping_group_range=%d %d (不满足要求)", currentMin, currentMax)
log.Println(" 正在配置为: 0 2147483647")
if err := writePingGroupRange(sysctlPath, 0, 2147483647); err != nil {
return fmt.Errorf("配置 ICMP 权限失败: %w", err)
}
log.Println("✅ ICMP 权限配置成功: net.ipv4.ping_group_range=0 2147483647")
return nil
}
// readPingGroupRange 读取 ping_group_range 的当前值
func readPingGroupRange(path string) (min, max int, err error) {
data, err := os.ReadFile(path)
if err != nil {
return 0, 0, err
}
// 格式: "min max\n"
fields := strings.Fields(string(data))
if len(fields) != 2 {
return 0, 0, fmt.Errorf("无效的格式: %s", string(data))
}
min, err = strconv.Atoi(fields[0])
if err != nil {
return 0, 0, fmt.Errorf("解析 min 值失败: %w", err)
}
max, err = strconv.Atoi(fields[1])
if err != nil {
return 0, 0, fmt.Errorf("解析 max 值失败: %w", err)
}
return min, max, nil
}
// writePingGroupRange 写入新的 ping_group_range 值
func writePingGroupRange(path string, min, max int) error {
value := fmt.Sprintf("%d\t%d", min, max)
if err := os.WriteFile(path, []byte(value), 0644); err != nil {
// 检查是否是权限问题
if os.IsPermission(err) {
return fmt.Errorf("需要 root 权限才能配置 ICMP 权限: %w", err)
}
return err
}
return nil
}
+10
View File
@@ -0,0 +1,10 @@
//go:build !linux
// +build !linux
package sysutil
// ConfigureICMPPermissions 在非 Linux 平台上不需要配置
func ConfigureICMPPermissions() error {
// Windows 和 macOS 不需要特殊配置
return nil
}