2
0
mirror of https://github.com/acepanel/panel.git synced 2026-02-05 03:22:32 +08:00
Files
panel/app/http/controllers/safe_controller.go
2024-07-28 20:58:33 +08:00

378 lines
10 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package controllers
import (
"regexp"
"strings"
"github.com/goravel/framework/contracts/http"
"github.com/spf13/cast"
"github.com/TheTNB/panel/v2/pkg/h"
"github.com/TheTNB/panel/v2/pkg/io"
"github.com/TheTNB/panel/v2/pkg/os"
"github.com/TheTNB/panel/v2/pkg/shell"
"github.com/TheTNB/panel/v2/pkg/systemctl"
)
type SafeController struct {
ssh string
}
func NewSafeController() *SafeController {
var ssh string
if os.IsRHEL() {
ssh = "sshd"
} else {
ssh = "ssh"
}
return &SafeController{
ssh: ssh,
}
}
// GetFirewallStatus 获取防火墙状态
func (r *SafeController) GetFirewallStatus(ctx http.Context) http.Response {
return h.Success(ctx, r.firewallStatus())
}
// SetFirewallStatus 设置防火墙状态
func (r *SafeController) SetFirewallStatus(ctx http.Context) http.Response {
var err error
if ctx.Request().InputBool("status") {
if os.IsRHEL() {
err = systemctl.Start("firewalld")
if err == nil {
err = systemctl.Enable("firewalld")
}
} else {
_, err = shell.Execf("echo y | ufw enable")
if err == nil {
err = systemctl.Start("ufw")
}
if err == nil {
err = systemctl.Enable("ufw")
}
}
} else {
if os.IsRHEL() {
err = systemctl.Stop("firewalld")
if err == nil {
err = systemctl.Disable("firewalld")
}
} else {
_, err = shell.Execf("ufw disable")
if err == nil {
err = systemctl.Stop("ufw")
}
if err == nil {
err = systemctl.Disable("ufw")
}
}
}
if err != nil {
return h.Error(ctx, http.StatusInternalServerError, err.Error())
}
return h.Success(ctx, nil)
}
// GetFirewallRules 获取防火墙规则
func (r *SafeController) GetFirewallRules(ctx http.Context) http.Response {
if !r.firewallStatus() {
return h.Success(ctx, nil)
}
var rules []map[string]string
if os.IsRHEL() {
out, err := shell.Execf("firewall-cmd --list-all")
if err != nil {
return h.Error(ctx, http.StatusInternalServerError, out)
}
match := regexp.MustCompile(`ports: (.*)`).FindStringSubmatch(out)
if len(match) == 0 {
return h.Success(ctx, http.Json{
"total": 0,
"items": []map[string]string{},
})
}
ports := strings.Split(match[1], " ")
for _, port := range ports {
rule := strings.Split(port, "/")
if len(rule) < 2 {
rules = append(rules, map[string]string{
"port": rule[0],
"protocol": "all",
})
} else {
rules = append(rules, map[string]string{
"port": rule[0],
"protocol": rule[1],
})
}
}
} else {
out, err := shell.Execf("ufw status | grep -v '(v6)' | grep ALLOW | awk '{print $1}'")
if err != nil {
return h.Error(ctx, http.StatusInternalServerError, out)
}
if len(out) == 0 {
return h.Success(ctx, http.Json{
"total": 0,
"items": []map[string]string{},
})
}
for _, port := range strings.Split(out, "\n") {
rule := strings.Split(port, "/")
if len(rule) < 2 {
rules = append(rules, map[string]string{
"port": rule[0],
"protocol": "all",
})
} else {
rules = append(rules, map[string]string{
"port": rule[0],
"protocol": rule[1],
})
}
}
}
paged, total := h.Paginate(ctx, rules)
return h.Success(ctx, http.Json{
"total": total,
"items": paged,
})
}
// AddFirewallRule 添加防火墙规则
func (r *SafeController) AddFirewallRule(ctx http.Context) http.Response {
if !r.firewallStatus() {
return h.Error(ctx, http.StatusInternalServerError, "防火墙未启动")
}
port := ctx.Request().Input("port")
protocol := ctx.Request().Input("protocol")
if port == "" || protocol == "" || (protocol != "tcp" && protocol != "udp") {
return h.Error(ctx, http.StatusUnprocessableEntity, "参数错误")
}
// 端口有 2 种写法,一种是 80-443一种是 80
if strings.Contains(port, "-") {
ports := strings.Split(port, "-")
startPort := cast.ToInt(ports[0])
endPort := cast.ToInt(ports[1])
if startPort < 1 || startPort > 65535 || endPort < 1 || endPort > 65535 || startPort > endPort {
return h.Error(ctx, http.StatusUnprocessableEntity, "参数错误")
}
} else {
port := cast.ToInt(port)
if port < 1 || port > 65535 {
return h.Error(ctx, http.StatusUnprocessableEntity, "参数错误")
}
}
if os.IsRHEL() {
if out, err := shell.Execf("firewall-cmd --remove-port=%s/%s --permanent", port, protocol); err != nil {
return h.Error(ctx, http.StatusInternalServerError, out)
}
if out, err := shell.Execf("firewall-cmd --add-port=%s/%s --permanent", port, protocol); err != nil {
return h.Error(ctx, http.StatusInternalServerError, out)
}
if out, err := shell.Execf("firewall-cmd --reload"); err != nil {
return h.Error(ctx, http.StatusInternalServerError, out)
}
} else {
// ufw 需要替换 - 为 : 添加
if strings.Contains(port, "-") {
port = strings.ReplaceAll(port, "-", ":")
}
if out, err := shell.Execf("ufw delete allow %s/%s", port, protocol); err != nil {
return h.Error(ctx, http.StatusInternalServerError, out)
}
if out, err := shell.Execf("ufw allow %s/%s", port, protocol); err != nil {
return h.Error(ctx, http.StatusInternalServerError, out)
}
if out, err := shell.Execf("ufw reload"); err != nil {
return h.Error(ctx, http.StatusInternalServerError, out)
}
}
return h.Success(ctx, nil)
}
// DeleteFirewallRule 删除防火墙规则
func (r *SafeController) DeleteFirewallRule(ctx http.Context) http.Response {
if !r.firewallStatus() {
return h.Error(ctx, http.StatusUnprocessableEntity, "防火墙未启动")
}
port := ctx.Request().Input("port")
protocol := ctx.Request().Input("protocol")
if port == "" || protocol == "" {
return h.Error(ctx, http.StatusUnprocessableEntity, "参数错误")
}
if protocol == "all" {
protocol = ""
} else {
protocol = "/" + protocol
}
if os.IsRHEL() {
if out, err := shell.Execf("firewall-cmd --remove-port=%s%s --permanent", port, protocol); err != nil {
return h.Error(ctx, http.StatusInternalServerError, out)
}
if out, err := shell.Execf("firewall-cmd --reload"); err != nil {
return h.Error(ctx, http.StatusInternalServerError, out)
}
} else {
if out, err := shell.Execf("ufw delete allow %s%s", port, protocol); err != nil {
return h.Error(ctx, http.StatusInternalServerError, out)
}
if out, err := shell.Execf("ufw reload"); err != nil {
return h.Error(ctx, http.StatusInternalServerError, out)
}
}
return h.Success(ctx, nil)
}
// firewallStatus 获取防火墙状态
func (r *SafeController) firewallStatus() bool {
var running bool
if os.IsRHEL() {
running, _ = systemctl.Status("firewalld")
} else {
running, _ = systemctl.Status("ufw")
}
return running
}
// GetSshStatus 获取 SSH 状态
func (r *SafeController) GetSshStatus(ctx http.Context) http.Response {
running, err := systemctl.Status(r.ssh)
if err != nil {
return h.Error(ctx, http.StatusInternalServerError, err.Error())
}
return h.Success(ctx, running)
}
// SetSshStatus 设置 SSH 状态
func (r *SafeController) SetSshStatus(ctx http.Context) http.Response {
if ctx.Request().InputBool("status") {
if err := systemctl.Enable(r.ssh); err != nil {
return h.Error(ctx, http.StatusInternalServerError, err.Error())
}
if err := systemctl.Start(r.ssh); err != nil {
return h.Error(ctx, http.StatusInternalServerError, err.Error())
}
} else {
if err := systemctl.Stop(r.ssh); err != nil {
return h.Error(ctx, http.StatusInternalServerError, err.Error())
}
if err := systemctl.Disable(r.ssh); err != nil {
return h.Error(ctx, http.StatusInternalServerError, err.Error())
}
}
return h.Success(ctx, nil)
}
// GetSshPort 获取 SSH 端口
func (r *SafeController) GetSshPort(ctx http.Context) http.Response {
out, err := shell.Execf("cat /etc/ssh/sshd_config | grep 'Port ' | awk '{print $2}'")
if err != nil {
return h.Error(ctx, http.StatusInternalServerError, out)
}
return h.Success(ctx, cast.ToInt(out))
}
// SetSshPort 设置 SSH 端口
func (r *SafeController) SetSshPort(ctx http.Context) http.Response {
port := ctx.Request().InputInt("port", 0)
if port == 0 {
return h.Error(ctx, http.StatusUnprocessableEntity, "参数错误")
}
oldPort, err := shell.Execf("cat /etc/ssh/sshd_config | grep 'Port ' | awk '{print $2}'")
if err != nil {
return h.Error(ctx, http.StatusInternalServerError, oldPort)
}
_, _ = shell.Execf("sed -i 's/#Port %s/Port %d/g' /etc/ssh/sshd_config", oldPort, port)
_, _ = shell.Execf("sed -i 's/Port %s/Port %d/g' /etc/ssh/sshd_config", oldPort, port)
status, _ := systemctl.Status(r.ssh)
if status {
_ = systemctl.Restart(r.ssh)
}
return h.Success(ctx, nil)
}
// GetPingStatus 获取 Ping 状态
func (r *SafeController) GetPingStatus(ctx http.Context) http.Response {
if os.IsRHEL() {
out, err := shell.Execf(`firewall-cmd --list-all`)
if err != nil {
return h.Error(ctx, http.StatusInternalServerError, out)
}
if !strings.Contains(out, `rule protocol value="icmp" drop`) {
return h.Success(ctx, true)
} else {
return h.Success(ctx, false)
}
} else {
config, err := io.Read("/etc/ufw/before.rules")
if err != nil {
return h.Error(ctx, http.StatusInternalServerError, err.Error())
}
if strings.Contains(config, "-A ufw-before-input -p icmp --icmp-type echo-request -j ACCEPT") {
return h.Success(ctx, true)
} else {
return h.Success(ctx, false)
}
}
}
// SetPingStatus 设置 Ping 状态
func (r *SafeController) SetPingStatus(ctx http.Context) http.Response {
var out string
var err error
if os.IsRHEL() {
if ctx.Request().InputBool("status") {
out, err = shell.Execf(`firewall-cmd --permanent --remove-rich-rule='rule protocol value=icmp drop'`)
} else {
out, err = shell.Execf(`firewall-cmd --permanent --add-rich-rule='rule protocol value=icmp drop'`)
}
} else {
if ctx.Request().InputBool("status") {
out, err = shell.Execf(`sed -i 's/-A ufw-before-input -p icmp --icmp-type echo-request -j DROP/-A ufw-before-input -p icmp --icmp-type echo-request -j ACCEPT/g' /etc/ufw/before.rules`)
} else {
out, err = shell.Execf(`sed -i 's/-A ufw-before-input -p icmp --icmp-type echo-request -j ACCEPT/-A ufw-before-input -p icmp --icmp-type echo-request -j DROP/g' /etc/ufw/before.rules`)
}
}
if err != nil {
return h.Error(ctx, http.StatusInternalServerError, out)
}
if os.IsRHEL() {
out, err = shell.Execf(`firewall-cmd --reload`)
} else {
out, err = shell.Execf(`ufw reload`)
}
if err != nil {
return h.Error(ctx, http.StatusInternalServerError, out)
}
return h.Success(ctx, nil)
}