Files

83 lines
2.2 KiB
Go

package sysutil
import (
"fmt"
"log/slog"
"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 {
slog.Info("ICMP 权限已配置", "min", currentMin, "max", currentMax)
return nil
}
// 3. 需要配置,写入新值
slog.Info("当前 ICMP 配置不满足要求,正在配置", "current_min", currentMin, "current_max", currentMax, "target", "0 2147483647")
if err := writePingGroupRange(sysctlPath, 0, 2147483647); err != nil {
return fmt.Errorf("配置 ICMP 权限失败: %w", err)
}
slog.Info("ICMP 权限配置成功", "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
}