mirror of
https://github.com/1Panel-dev/1Panel.git
synced 2025-10-12 08:26:50 +08:00
* feat(systemctl): 实现服务管理器初始化和命令执行 - 新增 systemctl 包,实现对 systemd、openrc 和 sysvinit 三种服务管理器的支持 - 添加服务状态检查、启动、停止、重启和启用/禁用功能 - 实现服务发现和智能服务名处理 - 添加配置文件查看功能 - 优化错误处理和日志记录 * refactor(system): 重构系统服务管理逻辑 - 引入 systemctl 工具包以统一处理系统服务 - 优化服务状态获取、配置文件路径解析等逻辑 - 重构 HostToolService 中的 GetToolStatus 方法 - 更新 DockerService、SettingService 等相关服务的处理方式 - 调整快照创建和恢复过程中的服务处理逻辑 * feat(utils): 添加目录复制功能并优化文件复制逻辑 - 新增 CopyDirs 函数,用于复制整个目录及其内容 - 添加对符号链接的复制支持 - 实现通用的 Copy 函数,根据文件类型自动选择 CopyFile 或 CopyDirs - 在 CopyFile 函数中增加对源文件是目录的检查和错误提示 * refactortoolbox: 重构 Fail2ban 和 Pure-FTPd 的管理逻辑 - 优化了 Fail2ban 和 Pure-FTPd 的启动、停止、重启等操作的实现 - 改进了 Fail2ban 版本信息的获取方法 - 统一了错误处理和日志记录的格式 - 调整了部分导入的包,提高了代码的可维护性 * build: 禁用 CGO 以提高构建性能和兼容性 - 在 Linux 后端构建命令中添加 CGO_ENABLED=0 环境变量 - 此修改可以提高构建速度,并确保生成的二进制文件在没有 C 库依赖的环境中也能运行 * refactor(docker): 重构 Docker 服务的重启和操作逻辑 - 添加 isDockerSnapInstalled 函数来判断 Docker 是否通过 Snap 安装 - 在 OperateDocker 和 restartDocker 函数中增加对 Snap 安装的处理 - 移除未使用的 getDockerRestartCommand 函数 * fix(service): 优化快照恢复后的服务重启逻辑 - 在使用 systemd 管理服务时,增加 daemon-reload 操作以确保服务配置更新 - 重启 1panel 服务,以应用快照恢复的更改 * refactor(server): 支持非 systemd 系统的恢复操作 - 增加 isSystemd 函数判断系统是否为 systemd 类型 - 根据系统类型选择性地恢复服务文件 - 兼容 systemd 和非 systemd 系统的恢复流程 * fix(upgrade): 优化升级过程中的服务重启逻辑 - 移动服务重启逻辑到版本号更新之后,修复因提前重启导致的版本号未更新BUG。 - 在 systemctl 重启之前添加 daemon-reload 命令 --------- Co-authored-by: gcsong023 <gcsong023@users.noreply.github.com>
187 lines
4.7 KiB
Go
187 lines
4.7 KiB
Go
package toolbox
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"regexp"
|
|
"strings"
|
|
|
|
"github.com/1Panel-dev/1Panel/backend/global"
|
|
"github.com/1Panel-dev/1Panel/backend/utils/cmd"
|
|
"github.com/1Panel-dev/1Panel/backend/utils/systemctl"
|
|
)
|
|
|
|
type Fail2ban struct{}
|
|
|
|
const defaultPath = "/etc/fail2ban/jail.local"
|
|
|
|
type FirewallClient interface {
|
|
Status() (bool, bool, bool)
|
|
Version() (string, error)
|
|
Operate(operate string) error
|
|
OperateSSHD(operate, ip string) error
|
|
}
|
|
|
|
func NewFail2Ban() (*Fail2ban, error) {
|
|
isExist, _ := systemctl.IsExist("fail2ban")
|
|
if isExist {
|
|
if _, err := os.Stat(defaultPath); err != nil {
|
|
if err := initLocalFile(); err != nil {
|
|
return nil, err
|
|
}
|
|
err := systemctl.Restart("fail2ban")
|
|
if err != nil {
|
|
global.LOG.Errorf("restart fail2ban failed, err: %s", err)
|
|
return nil, err
|
|
}
|
|
}
|
|
}
|
|
return &Fail2ban{}, nil
|
|
}
|
|
|
|
func (f *Fail2ban) Status() (bool, bool, bool) {
|
|
isEnable, _ := systemctl.IsEnable("fail2ban.service")
|
|
isActive, _ := systemctl.IsActive("fail2ban.service")
|
|
isExist, _ := systemctl.IsExist("fail2ban.service")
|
|
|
|
return isEnable, isActive, isExist
|
|
}
|
|
|
|
func (f *Fail2ban) Version() string {
|
|
stdout, err := cmd.Exec("fail2ban-client --version")
|
|
if err != nil {
|
|
global.LOG.Errorf("load the fail2ban version failed, err: %s", stdout)
|
|
return "-"
|
|
}
|
|
versionRe := regexp.MustCompile(`(?i)fail2ban[:\s-]*v?(\d+\.\d+\.\d+)`)
|
|
matches := versionRe.FindStringSubmatch(stdout)
|
|
if len(matches) > 1 {
|
|
return matches[1]
|
|
}
|
|
global.LOG.Errorf("Version regex failed to match output: %s", stdout)
|
|
return "-"
|
|
}
|
|
func (f *Fail2ban) Operate(operate string) error {
|
|
switch operate {
|
|
case "start", "restart", "stop", "enable", "disable":
|
|
stdout, err := systemctl.CustomAction(operate, "fail2ban")
|
|
if err != nil {
|
|
return fmt.Errorf("%s the fail2ban failed, err: %s", operate, stdout.Output)
|
|
}
|
|
return nil
|
|
case "reload":
|
|
stdout, err := cmd.Exec("fail2ban-client reload")
|
|
if err != nil {
|
|
return fmt.Errorf("fail2ban-client reload, err: %s", stdout)
|
|
}
|
|
return nil
|
|
default:
|
|
return fmt.Errorf("not support such operation: %v", operate)
|
|
}
|
|
}
|
|
|
|
func (f *Fail2ban) ReBanIPs(ips []string) error {
|
|
ipItems, _ := f.ListBanned()
|
|
stdout, err := cmd.Execf("fail2ban-client unban --all")
|
|
if err != nil {
|
|
stdout1, err := cmd.Execf("fail2ban-client set sshd banip %s", strings.Join(ipItems, " "))
|
|
if err != nil {
|
|
global.LOG.Errorf("rebanip after fail2ban-client unban --all failed, err: %s", stdout1)
|
|
}
|
|
return fmt.Errorf("fail2ban-client unban --all failed, err: %s", stdout)
|
|
}
|
|
stdout1, err := cmd.Execf("fail2ban-client set sshd banip %s", strings.Join(ips, " "))
|
|
if err != nil {
|
|
return fmt.Errorf("handle `fail2ban-client set sshd banip %s` failed, err: %s", strings.Join(ips, " "), stdout1)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (f *Fail2ban) ListBanned() ([]string, error) {
|
|
var lists []string
|
|
stdout, err := cmd.Exec("fail2ban-client status sshd | grep 'Banned IP list:'")
|
|
if err != nil {
|
|
return lists, err
|
|
}
|
|
itemList := strings.Split(strings.Trim(stdout, "\n"), "Banned IP list:")
|
|
if len(itemList) != 2 {
|
|
return lists, nil
|
|
}
|
|
|
|
ips := strings.Fields(itemList[1])
|
|
for _, item := range ips {
|
|
if len(item) != 0 {
|
|
lists = append(lists, item)
|
|
}
|
|
}
|
|
return lists, nil
|
|
}
|
|
|
|
func (f *Fail2ban) ListIgnore() ([]string, error) {
|
|
var lists []string
|
|
stdout, err := cmd.Exec("fail2ban-client get sshd ignoreip")
|
|
if err != nil {
|
|
return lists, err
|
|
}
|
|
stdout = strings.ReplaceAll(stdout, "|", "")
|
|
stdout = strings.ReplaceAll(stdout, "`", "")
|
|
stdout = strings.ReplaceAll(stdout, "\n", "")
|
|
addrs := strings.Split(stdout, "-")
|
|
for _, addr := range addrs {
|
|
if !strings.HasPrefix(addr, " ") {
|
|
continue
|
|
}
|
|
lists = append(lists, strings.ReplaceAll(addr, " ", ""))
|
|
}
|
|
return lists, nil
|
|
}
|
|
|
|
func initLocalFile() error {
|
|
f, err := os.Create(defaultPath)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer f.Close()
|
|
initFile := `#DEFAULT-START
|
|
[DEFAULT]
|
|
bantime = 600
|
|
findtime = 300
|
|
maxretry = 5
|
|
banaction = $banaction
|
|
action = %(action_mwl)s
|
|
#DEFAULT-END
|
|
|
|
[sshd]
|
|
ignoreip = 127.0.0.1/8
|
|
enabled = true
|
|
filter = sshd
|
|
port = 22
|
|
maxretry = 5
|
|
findtime = 300
|
|
bantime = 600
|
|
banaction = $banaction
|
|
action = %(action_mwl)s
|
|
logpath = $logpath`
|
|
|
|
banaction := ""
|
|
if active, _ := systemctl.IsActive("firewalld"); active {
|
|
banaction = "firewallcmd-ipset"
|
|
} else if active, _ := systemctl.IsActive("ufw"); active {
|
|
banaction = "ufw"
|
|
} else {
|
|
banaction = "iptables-allports"
|
|
}
|
|
initFile = strings.ReplaceAll(initFile, "$banaction", banaction)
|
|
|
|
logPath := ""
|
|
if _, err := os.Stat("/var/log/secure"); err == nil {
|
|
logPath = "/var/log/secure"
|
|
} else {
|
|
logPath = "/var/log/auth.log"
|
|
}
|
|
initFile = strings.ReplaceAll(initFile, "$logpath", logPath)
|
|
if err := os.WriteFile(defaultPath, []byte(initFile), 0640); err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|