diff --git a/backend/app/dto/firewall.go b/backend/app/dto/firewall.go index fb209f2af..9f534a09a 100644 --- a/backend/app/dto/firewall.go +++ b/backend/app/dto/firewall.go @@ -1,9 +1,10 @@ package dto type FirewallBaseInfo struct { - Name string `json:"name"` - Status string `json:"status"` - Version string `json:"version"` + Name string `json:"name"` + Status string `json:"status"` + Version string `json:"version"` + PingStatus string `json:"pingStatus"` } type RuleSearch struct { @@ -13,7 +14,7 @@ type RuleSearch struct { } type FirewallOperation struct { - Operation string `json:"operation" validate:"required,oneof=start stop reload"` + Operation string `json:"operation" validate:"required,oneof=start stop disablePing enablePing"` } type PortRuleOperate struct { diff --git a/backend/app/service/firewall.go b/backend/app/service/firewall.go index e60f48dfa..a1c56970a 100644 --- a/backend/app/service/firewall.go +++ b/backend/app/service/firewall.go @@ -38,6 +38,10 @@ func (u *FirewallService) LoadBaseInfo() (dto.FirewallBaseInfo, error) { if err != nil { return baseInfo, err } + baseInfo.PingStatus, err = client.PingStatus() + if err != nil { + return baseInfo, err + } if baseInfo.Status == "not running" { baseInfo.Version = "-" return baseInfo, err @@ -110,8 +114,10 @@ func (u *FirewallService) OperateFirewall(operation string) error { return client.Start() case "stop": return client.Stop() - case "reload": - return client.Reload() + case "disablePing": + return client.UpdatePingStatus("0") + case "enablePing": + return client.UpdatePingStatus("1") } return fmt.Errorf("not support such operation: %s", operation) } diff --git a/backend/utils/firewall/client.go b/backend/utils/firewall/client.go index d455daad6..e6840c309 100644 --- a/backend/utils/firewall/client.go +++ b/backend/utils/firewall/client.go @@ -1,16 +1,23 @@ package firewall import ( + "errors" + "os" + "github.com/1Panel-dev/1Panel/backend/utils/firewall/client" ) type FirewallClient interface { - Name() string + Name() string // ufw firewalld Start() error Stop() error Reload() error - Status() (string, error) + Status() (string, error) // running not running Version() (string, error) + + PingStatus() (string, error) // Enable Disable + UpdatePingStatus(enabel string) error + ListPort() ([]client.FireInfo, error) ListAddress() ([]client.FireInfo, error) @@ -20,11 +27,11 @@ type FirewallClient interface { } func NewFirewallClient() (FirewallClient, error) { - // if _, err := os.Stat("/usr/sbin/firewalld"); err == nil { - return client.NewFirewalld() - // } - // if _, err := os.Stat("/usr/sbin/ufw"); err == nil { - // return client.NewUfw() - // } - // return nil, errors.New("no such type") + if _, err := os.Stat("/usr/sbin/firewalld"); err == nil { + return client.NewFirewalld() + } + if _, err := os.Stat("/usr/sbin/ufw"); err == nil { + return client.NewUfw() + } + return nil, errors.New("no such type") } diff --git a/backend/utils/firewall/client/firewalld.go b/backend/utils/firewall/client/firewalld.go index d79b911da..c0fe6c724 100644 --- a/backend/utils/firewall/client/firewalld.go +++ b/backend/utils/firewall/client/firewalld.go @@ -4,21 +4,14 @@ import ( "fmt" "strings" - "github.com/1Panel-dev/1Panel/backend/utils/ssh" + "github.com/1Panel-dev/1Panel/backend/constant" + "github.com/1Panel-dev/1Panel/backend/utils/cmd" ) -type Firewall struct { - Client ssh.ConnInfo -} +type Firewall struct{} func NewFirewalld() (*Firewall, error) { - ConnInfo := ssh.ConnInfo{ - Addr: "172.16.10.143", - User: "root", - AuthMode: "password", - Port: 22, - } - return &Firewall{Client: ConnInfo}, nil + return &Firewall{}, nil } func (f *Firewall) Name() string { @@ -26,12 +19,12 @@ func (f *Firewall) Name() string { } func (f *Firewall) Status() (string, error) { - stdout, _ := f.Client.Run("firewall-cmd --state") + stdout, _ := cmd.Exec("firewall-cmd --state") return strings.ReplaceAll(stdout, "\n", ""), nil } func (f *Firewall) Version() (string, error) { - stdout, err := f.Client.Run("firewall-cmd --version") + stdout, err := cmd.Exec("firewall-cmd --version") if err != nil { return "", fmt.Errorf("load the firewall version failed, err: %s", stdout) } @@ -39,15 +32,35 @@ func (f *Firewall) Version() (string, error) { } func (f *Firewall) Start() error { - stdout, err := f.Client.Run("systemctl start firewalld") + stdout, err := cmd.Exec("systemctl start firewalld") if err != nil { return fmt.Errorf("enable the firewall failed, err: %s", stdout) } return nil } +func (f *Firewall) PingStatus() (string, error) { + stdout, _ := cmd.Exec("firewall-cmd --query-rich-rule='rule protocol value=icmp drop'") + if stdout == "yes\n" { + return constant.StatusEnable, nil + } + return constant.StatusDisable, nil +} + +func (f *Firewall) UpdatePingStatus(enabel string) error { + operation := "add" + if enabel == "0" { + operation = "remove" + } + stdout, err := cmd.Execf("firewall-cmd --permanent --%s-rich-rule='rule protocol value=icmp drop'", operation) + if err != nil { + return fmt.Errorf("update firewall ping status failed, err: %s", stdout) + } + return f.Reload() +} + func (f *Firewall) Stop() error { - stdout, err := f.Client.Run("systemctl stop firewalld") + stdout, err := cmd.Exec("systemctl stop firewalld") if err != nil { return fmt.Errorf("stop the firewall failed, err: %s", stdout) } @@ -55,7 +68,7 @@ func (f *Firewall) Stop() error { } func (f *Firewall) Reload() error { - stdout, err := f.Client.Run("firewall-cmd --reload") + stdout, err := cmd.Exec("firewall-cmd --reload") if err != nil { return fmt.Errorf("reload firewall failed, err: %s", stdout) } @@ -63,7 +76,7 @@ func (f *Firewall) Reload() error { } func (f *Firewall) ListPort() ([]FireInfo, error) { - stdout, err := f.Client.Run("firewall-cmd --zone=public --list-ports") + stdout, err := cmd.Exec("firewall-cmd --zone=public --list-ports") if err != nil { return nil, err } @@ -79,7 +92,7 @@ func (f *Firewall) ListPort() ([]FireInfo, error) { datas = append(datas, itemPort) } - stdout1, err := f.Client.Run("firewall-cmd --zone=public --list-rich-rules") + stdout1, err := cmd.Exec("firewall-cmd --zone=public --list-rich-rules") if err != nil { return nil, err } @@ -97,7 +110,7 @@ func (f *Firewall) ListPort() ([]FireInfo, error) { } func (f *Firewall) ListAddress() ([]FireInfo, error) { - stdout, err := f.Client.Run("firewall-cmd --zone=public --list-rich-rules") + stdout, err := cmd.Exec("firewall-cmd --zone=public --list-rich-rules") if err != nil { return nil, err } @@ -116,7 +129,7 @@ func (f *Firewall) ListAddress() ([]FireInfo, error) { } func (f *Firewall) Port(port FireInfo, operation string) error { - stdout, err := f.Client.Run(fmt.Sprintf("firewall-cmd --zone=public --%s-port=%s/%s --permanent", operation, port.Port, port.Protocol)) + stdout, err := cmd.Execf("firewall-cmd --zone=public --%s-port=%s/%s --permanent", operation, port.Port, port.Protocol) if err != nil { return fmt.Errorf("%s port failed, err: %s", operation, stdout) } @@ -136,7 +149,7 @@ func (f *Firewall) RichRules(rule FireInfo, operation string) error { } ruleStr += rule.Strategy - stdout, err := f.Client.Run(fmt.Sprintf("firewall-cmd --zone=public --%s-rich-rule '%s' --permanent", operation, ruleStr)) + stdout, err := cmd.Execf("firewall-cmd --zone=public --%s-rich-rule '%s' --permanent", operation, ruleStr) if err != nil { return fmt.Errorf("%s rich rules failed, err: %s", operation, stdout) } @@ -149,7 +162,7 @@ func (f *Firewall) PortForward(info Forward, operation string) error { ruleStr = fmt.Sprintf("firewall-cmd --%s-forward-port=port=%s:proto=%s:toaddr=%s:toport=%s --permanent", operation, info.Port, info.Protocol, info.Address, info.Target) } - stdout, err := f.Client.Run(ruleStr) + stdout, err := cmd.Exec(ruleStr) if err != nil { return fmt.Errorf("%s port forward failed, err: %s", operation, stdout) } diff --git a/backend/utils/firewall/client/ufw.go b/backend/utils/firewall/client/ufw.go index 456c1cf24..5c48263db 100644 --- a/backend/utils/firewall/client/ufw.go +++ b/backend/utils/firewall/client/ufw.go @@ -2,24 +2,20 @@ package client import ( "fmt" + "io/ioutil" + "os" "strings" "github.com/1Panel-dev/1Panel/backend/constant" - "github.com/1Panel-dev/1Panel/backend/utils/ssh" + "github.com/1Panel-dev/1Panel/backend/utils/cmd" ) -type Ufw struct { - Client ssh.ConnInfo -} +const confPath = "/etc/ufw/sysctl.conf" + +type Ufw struct{} func NewUfw() (*Ufw, error) { - ConnInfo := ssh.ConnInfo{ - Addr: "172.16.10.234", - User: "ubuntu", - AuthMode: "password", - Port: 22, - } - return &Ufw{Client: ConnInfo}, nil + return &Ufw{}, nil } func (f *Ufw) Name() string { @@ -27,7 +23,7 @@ func (f *Ufw) Name() string { } func (f *Ufw) Status() (string, error) { - stdout, err := f.Client.Run("sudo ufw status | grep Status") + stdout, err := cmd.Exec("sudo ufw status | grep Status") if err != nil { return "", fmt.Errorf("load the firewall status failed, err: %s", stdout) } @@ -38,7 +34,7 @@ func (f *Ufw) Status() (string, error) { } func (f *Ufw) Version() (string, error) { - stdout, err := f.Client.Run("sudo ufw version | grep ufw") + stdout, err := cmd.Exec("sudo ufw version | grep ufw") if err != nil { return "", fmt.Errorf("load the firewall status failed, err: %s", stdout) } @@ -47,7 +43,7 @@ func (f *Ufw) Version() (string, error) { } func (f *Ufw) Start() error { - stdout, err := f.Client.Run("echo y | sudo ufw enable") + stdout, err := cmd.Exec("echo y | sudo ufw enable") if err != nil { return fmt.Errorf("enable the firewall failed, err: %s", stdout) } @@ -55,9 +51,9 @@ func (f *Ufw) Start() error { } func (f *Ufw) PingStatus() (string, error) { - stdout, err := f.Client.Run("cat /etc/ufw/sysctl.conf | grep net/ipv4/icmp_echo_ignore_all= ") + stdout, err := cmd.Exec("cat /etc/ufw/sysctl.conf | grep net/ipv4/icmp_echo_ignore_all= ") if err != nil { - return constant.StatusDisable, fmt.Errorf("enable the firewall failed, err: %s", stdout) + return constant.StatusDisable, fmt.Errorf("load firewall ping status failed, err: %s", stdout) } if stdout == "net/ipv4/icmp_echo_ignore_all=1\n" { return constant.StatusEnable, nil @@ -65,8 +61,35 @@ func (f *Ufw) PingStatus() (string, error) { return constant.StatusDisable, nil } +func (f *Ufw) UpdatePingStatus(enabel string) error { + lineBytes, err := ioutil.ReadFile(confPath) + if err != nil { + return err + } + files := strings.Split(string(lineBytes), "\n") + var newFiles []string + for _, line := range files { + if strings.Contains(line, "net/ipv4/icmp_echo_ignore_all") || strings.HasPrefix(line, "net/ipv4/icmp_echo_ignore_all") { + newFiles = append(newFiles, "net/ipv4/icmp_echo_ignore_all="+enabel) + } else { + newFiles = append(newFiles, line) + } + } + file, err := os.OpenFile(confPath, os.O_WRONLY|os.O_TRUNC, 0666) + if err != nil { + return err + } + defer file.Close() + _, err = file.WriteString(strings.Join(newFiles, "\n")) + if err != nil { + return err + } + + return nil +} + func (f *Ufw) Stop() error { - stdout, err := f.Client.Run("sudo ufw disable") + stdout, err := cmd.Exec("sudo ufw disable") if err != nil { return fmt.Errorf("stop the firewall failed, err: %s", stdout) } @@ -78,7 +101,7 @@ func (f *Ufw) Reload() error { } func (f *Ufw) ListPort() ([]FireInfo, error) { - stdout, err := f.Client.Run("sudo ufw status verbose") + stdout, err := cmd.Exec("sudo ufw status verbose") if err != nil { return nil, err } @@ -103,7 +126,7 @@ func (f *Ufw) ListPort() ([]FireInfo, error) { } func (f *Ufw) ListAddress() ([]FireInfo, error) { - stdout, err := f.Client.Run("sudo ufw status verbose") + stdout, err := cmd.Exec("sudo ufw status verbose") if err != nil { return nil, err } @@ -150,7 +173,7 @@ func (f *Ufw) Port(port FireInfo, operation string) error { if len(port.Protocol) != 0 { command += fmt.Sprintf("/%s", port.Protocol) } - stdout, err := f.Client.Run(command) + stdout, err := cmd.Exec(command) if err != nil { return fmt.Errorf("%s port failed, err: %s", operation, stdout) } @@ -183,7 +206,7 @@ func (f *Ufw) RichRules(rule FireInfo, operation string) error { ruleStr += fmt.Sprintf("to any port %s ", rule.Port) } - stdout, err := f.Client.Run(ruleStr) + stdout, err := cmd.Exec(ruleStr) if err != nil { return fmt.Errorf("%s rich rules failed, err: %s", operation, stdout) } @@ -196,7 +219,7 @@ func (f *Ufw) PortForward(info Forward, operation string) error { ruleStr = fmt.Sprintf("firewall-cmd --%s-forward-port=port=%s:proto=%s:toaddr=%s:toport=%s --permanent", operation, info.Port, info.Protocol, info.Address, info.Target) } - stdout, err := f.Client.Run(ruleStr) + stdout, err := cmd.Exec(ruleStr) if err != nil { return fmt.Errorf("%s port forward failed, err: %s", operation, stdout) } diff --git a/frontend/src/api/interface/host.ts b/frontend/src/api/interface/host.ts index b49c18c9a..efe9502b9 100644 --- a/frontend/src/api/interface/host.ts +++ b/frontend/src/api/interface/host.ts @@ -57,6 +57,7 @@ export namespace Host { name: string; status: string; version: string; + pingStatus: string; } export interface RuleSearch extends ReqPage { info: string; diff --git a/frontend/src/lang/modules/en.ts b/frontend/src/lang/modules/en.ts index aca99acca..8fb628c0e 100644 --- a/frontend/src/lang/modules/en.ts +++ b/frontend/src/lang/modules/en.ts @@ -21,6 +21,8 @@ const message = { clean: 'Clean', login: 'Login', close: 'Close', + stop: 'Stop', + start: 'Start', view: 'View', watch: 'Watch', handle: 'Handle', @@ -1181,6 +1183,38 @@ const message = { argsCheck: 'GET parameter check', postCheck: 'POST parameter verification', cookieBlockList: 'Cookie Blacklist', + + firewall: 'Firewall', + firewallHelper: '{0} System firewall', + firewallNotStart: 'The firewall service is not enabled at present, please enable it first!', + stopFirewallHelper: + 'If the firewall is disabled, the server loses security protection. Do you want to continue?', + startFirewallHelper: + 'After the firewall is enabled, the current server security can be better protected. Do you want to continue?', + noPing: 'Disable ping', + noPingHelper: + 'If the ping function is disabled, the server cannot be pinged. Do you want to continue the operation?', + onPingHelper: 'If you disable ping, hackers may discover your server. Do you want to continue?', + protocol: 'Protocol', + port: 'Port', + changeStrategy: 'Change the {0} strategy', + changeStrategyHelper: + 'Change [{1}] {0} strategy to [{2}]. After setting, {0} will access {2} externally. Do you want to continue?', + portHelper: 'Multiple ports can be entered, such as 80,81, or range ports, such as 80-88', + strategy: 'Strategy', + accept: 'Accept', + drop: 'Drop', + source: 'Source', + anyWhere: 'AnyWhere', + address: 'Specified IP', + allow: 'Allow', + deny: 'Deny', + addressHelper1: 'Support for multiple IP, such as 172.16.10.11 172.16.10.99', + addressHelper2: 'You can enter an IP address segment, for example, 172.16.10.0/24', + addressHelper3: 'You can enter an IP address range, such as 172.16.10.11-172.16.10.99', + allIP: 'All IP', + portRule: 'Port rule', + ipRule: 'IP rule', }, }; diff --git a/frontend/src/lang/modules/zh.ts b/frontend/src/lang/modules/zh.ts index 38748c9a9..f4ba58b60 100644 --- a/frontend/src/lang/modules/zh.ts +++ b/frontend/src/lang/modules/zh.ts @@ -1188,6 +1188,9 @@ const message = { firewallNotStart: '当前未开启防火墙服务,请先开启!', stopFirewallHelper: '停用系统防火墙,服务器将失去安全防护,是否继续操作?', startFirewallHelper: '启用系统防火墙后,可以更好的防护当前的服务器安全,是否继续操作?', + noPing: '禁 ping', + noPingHelper: '禁 ping 后不影响服务器正常使用,但无法 ping 通服务器,是否继续操作?', + onPingHelper: '解除禁 ping 状态可能会被黑客发现您的服务器,是否继续操作?', protocol: '协议', port: '端口', changeStrategy: '修改{0}策略', diff --git a/frontend/src/views/cronjob/index.vue b/frontend/src/views/cronjob/index.vue index 17a80a5cc..1467b8782 100644 --- a/frontend/src/views/cronjob/index.vue +++ b/frontend/src/views/cronjob/index.vue @@ -15,7 +15,7 @@ {{ $t('commons.button.create') }}{{ $t('cronjob.cronTask') }} - + {{ $t('commons.button.delete') }} diff --git a/frontend/src/views/host/firewall/ip/index.vue b/frontend/src/views/host/firewall/ip/index.vue index cbee42814..c59e451dc 100644 --- a/frontend/src/views/host/firewall/ip/index.vue +++ b/frontend/src/views/host/firewall/ip/index.vue @@ -14,7 +14,7 @@ {{ $t('commons.button.create') }} {{ $t('firewall.ipRule') }} - + {{ $t('commons.button.delete') }} diff --git a/frontend/src/views/host/firewall/port/index.vue b/frontend/src/views/host/firewall/port/index.vue index 5b7155f12..1bea264a2 100644 --- a/frontend/src/views/host/firewall/port/index.vue +++ b/frontend/src/views/host/firewall/port/index.vue @@ -15,7 +15,7 @@ {{ $t('commons.button.create') }}{{ $t('firewall.portRule') }} - + {{ $t('commons.button.delete') }} diff --git a/frontend/src/views/host/firewall/status/index.vue b/frontend/src/views/host/firewall/status/index.vue index a5b265038..a51e81752 100644 --- a/frontend/src/views/host/firewall/status/index.vue +++ b/frontend/src/views/host/firewall/status/index.vue @@ -16,6 +16,15 @@ {{ $t('commons.button.stop') }} + + {{ $t('firewall.noPing') }} + @@ -36,19 +45,21 @@ import i18n from '@/lang'; import { ElMessageBox } from 'element-plus'; import { ref } from 'vue'; -const baseInfo = ref({ status: '', name: '', version: '' }); +const baseInfo = ref({ status: '', name: '', version: '', pingStatus: '' }); +const onPing = ref(); const acceptParams = (): void => { - loadBaseInfo(); + loadBaseInfo(true); }; const emit = defineEmits(['search', 'update:status', 'update:loading']); -const loadBaseInfo = async () => { +const loadBaseInfo = async (search: boolean) => { await loadFireBaseInfo() .then((res) => { baseInfo.value = res.data; + onPing.value = baseInfo.value.pingStatus; emit('update:status', baseInfo.value.status); - if (baseInfo.value.status === 'running') { + if (baseInfo.value.status === 'running' && search) { emit('search'); } else { emit('update:loading', false); @@ -70,7 +81,7 @@ const onOperate = async (operation: string) => { emit('update:status', 'running'); await operateFire(operation) .then(() => { - loadBaseInfo(); + loadBaseInfo(true); }) .catch(() => { emit('update:loading', false); @@ -78,6 +89,31 @@ const onOperate = async (operation: string) => { }); }; +const onPingOperate = async (operation: string) => { + let operationHelper = + operation === 'Enabel' ? i18n.global.t('firewall.noPingHelper') : i18n.global.t('firewall.onPingHelper'); + ElMessageBox.confirm(operationHelper, i18n.global.t('firewall.noPing'), { + confirmButtonText: i18n.global.t('commons.button.confirm'), + cancelButtonText: i18n.global.t('commons.button.cancel'), + }) + .then(async () => { + emit('update:loading', true); + emit('update:status', 'running'); + operation = operation === 'Disable' ? 'enablePing' : 'disablePing'; + await operateFire(operation) + .then(() => { + loadBaseInfo(false); + }) + .catch(() => { + loadBaseInfo(false); + }); + }) + .catch(() => { + emit('update:loading', true); + loadBaseInfo(false); + }); +}; + defineExpose({ acceptParams, });