diff --git a/backend/app/service/fail2ban.go b/backend/app/service/fail2ban.go index 8c934dba5..a05d47478 100644 --- a/backend/app/service/fail2ban.go +++ b/backend/app/service/fail2ban.go @@ -8,6 +8,8 @@ import ( "strings" "github.com/1Panel-dev/1Panel/backend/app/dto" + "github.com/1Panel-dev/1Panel/backend/buserr" + "github.com/1Panel-dev/1Panel/backend/utils/systemctl" "github.com/1Panel-dev/1Panel/backend/utils/toolbox" ) @@ -97,6 +99,25 @@ func (u *Fail2BanService) Operate(operation string) error { } func (u *Fail2BanService) UpdateConf(req dto.Fail2BanUpdate) error { + if req.Key == "banaction" { + switch req.Value { + case "firewallcmd-ipset": + isActive, _ := systemctl.IsActive("firewalld") + if !isActive { + return buserr.WithName("ErrBanAction", "firewalld") + } + case "ufw": + isActive, _ := systemctl.IsActive("ufw") + if !isActive { + return buserr.WithName("ErrBanAction", "ufw") + } + } + } + if req.Key == "logpath" { + if _, err := os.Stat(req.Value); err != nil { + return err + } + } conf, err := os.ReadFile(defaultFail2BanPath) if err != nil { return fmt.Errorf("read fail2ban conf of %s failed, err: %v", defaultFail2BanPath, err) diff --git a/backend/i18n/lang/en.yaml b/backend/i18n/lang/en.yaml index b33dbcd92..8b4fe7fca 100644 --- a/backend/i18n/lang/en.yaml +++ b/backend/i18n/lang/en.yaml @@ -160,3 +160,4 @@ ErrBashExecute: "Script execution error, please check the specific information i #toolbox ErrNotExistUser: "The current user does not exist. Please modify and retry!" +ErrBanAction: "Setting failed, the current {{ .name }} service is unavailable, please check and try again!" diff --git a/backend/i18n/lang/zh-Hant.yaml b/backend/i18n/lang/zh-Hant.yaml index 412305d07..5ca6937e6 100644 --- a/backend/i18n/lang/zh-Hant.yaml +++ b/backend/i18n/lang/zh-Hant.yaml @@ -161,3 +161,4 @@ ErrBashExecute: "腳本執行錯誤,請在任務輸出文本域中查看具體 #toolbox ErrNotExistUser: "當前使用者不存在,請修改後重試!" +ErrBanAction: "設置失敗,當前 {{ .name }} 服務不可用,請檢查後重試!" diff --git a/backend/i18n/lang/zh.yaml b/backend/i18n/lang/zh.yaml index 47b6e6ab9..3eaae534f 100644 --- a/backend/i18n/lang/zh.yaml +++ b/backend/i18n/lang/zh.yaml @@ -159,4 +159,5 @@ ErrFirewall: "当前未检测到系统 firewalld 或 ufw 服务,请检查后 ErrBashExecute: "脚本执行错误,请在任务输出文本域中查看具体信息。" #toolbox -ErrNotExistUser: "当前用户不存在,请修改后重试!" \ No newline at end of file +ErrNotExistUser: "当前用户不存在,请修改后重试!" +ErrBanAction: "设置失败,当前 {{ .name }} 服务不可用,请检查后重试!" \ No newline at end of file diff --git a/backend/utils/toolbox/fail2ban.go b/backend/utils/toolbox/fail2ban.go index 00e68a906..c77b9dd88 100644 --- a/backend/utils/toolbox/fail2ban.go +++ b/backend/utils/toolbox/fail2ban.go @@ -1,7 +1,6 @@ package toolbox import ( - "encoding/json" "fmt" "os" "strings" @@ -98,10 +97,11 @@ func (f *Fail2ban) ListBanned() ([]string, error) { if err != nil { return lists, err } - stdout = strings.ReplaceAll(stdout, "\n", "") - stdout = strings.ReplaceAll(stdout, "'", "\"") - if err := json.Unmarshal([]byte(stdout), &lists); err != nil { - return lists, fmt.Errorf("handle json unmarshal (%s) failed, err: %v", stdout, err) + itemList := strings.Split(stdout, "\n") + for _, item := range itemList { + if len(item) != 0 { + lists = append(lists, item) + } } return lists, nil } @@ -146,6 +146,7 @@ port = 22 maxretry = 5 findtime = 300 bantime = 600 +banaction = $banaction action = %(action_mwl)s logpath = $logpath` diff --git a/frontend/src/lang/modules/en.ts b/frontend/src/lang/modules/en.ts index d7ef36e6f..fc8e559df 100644 --- a/frontend/src/lang/modules/en.ts +++ b/frontend/src/lang/modules/en.ts @@ -950,6 +950,8 @@ const message = { dnsTestFailed: 'DNS configuration information is not available. Please modify and try again!', }, fail2ban: { + sshPort: 'Listen to SSH Port', + sshPortHelper: 'Current Fail2ban listens to the SSH connection port of the host', noFail2ban: 'Fail2ban service not detected, please refer to the official documentation for installation', unActive: 'The Fail2ban service is not enabled at present, please enable it first!', operation: 'Perform [{0}] operation on Fail2ban service, continue?', @@ -959,6 +961,8 @@ const message = { maxRetry: 'Maximum Retry Attempts', banTime: 'Ban Time', banTimeHelper: 'Default ban time is 10 minutes, -1 indicates permanent ban', + banTimeRule: 'Please enter a valid ban time or -1', + banAllTime: 'Permanent Ban', findTime: 'Discovery Period', banAction: 'Ban Action', banActionOption: 'Ban specified IP addresses using {0}', diff --git a/frontend/src/lang/modules/tw.ts b/frontend/src/lang/modules/tw.ts index aefa8e3ec..98ada819d 100644 --- a/frontend/src/lang/modules/tw.ts +++ b/frontend/src/lang/modules/tw.ts @@ -901,12 +901,16 @@ const message = { dnsTestFailed: 'DNS 配置信息不可用,請修改後重試!', }, fail2ban: { + sshPort: '監聽 SSH 端口', + sshPortHelper: '當前 Fail2ban 監聽主機 SSH 連接端口', noFail2ban: '未檢測到 Fail2ban 服務,請參考官方文檔進行安裝', unActive: '當前未開啟 Fail2ban 服務,請先開啟!', operation: '對 Fail2ban 服務進行 [{0}] 操作,是否繼續?', fail2banChange: 'Fail2ban 配置修改', ignoreHelper: '白名單中的 IP 列表將被忽略屏蔽,是否繼續?', bannedHelper: '黑名單中的 IP 列表將被伺服器屏蔽,是否繼續?', + banTimeRule: '請輸入正確的禁用時間或 -1', + banAllTime: '永久禁用', maxRetry: '最大重試次數', banTime: '禁用時間', banTimeHelper: '默認禁用時間為 10 分鐘,禁用時間為 -1 則表示永久禁用', diff --git a/frontend/src/lang/modules/zh.ts b/frontend/src/lang/modules/zh.ts index 79d388161..cd6562917 100644 --- a/frontend/src/lang/modules/zh.ts +++ b/frontend/src/lang/modules/zh.ts @@ -902,6 +902,8 @@ const message = { dnsTestFailed: 'DNS 配置信息不可用,请修改后重试!', }, fail2ban: { + sshPort: '监听 SSH 端口', + sshPortHelper: '当前 Fail2ban 监听主机 SSH 连接端口', noFail2ban: '未检测到 Fail2ban 服务,请参考官方文档进行安装', unActive: '当前未开启 Fail2ban 服务,请先开启!', operation: '对 Fail2ban 服务进行 [{0}] 操作,是否继续?', @@ -911,6 +913,8 @@ const message = { maxRetry: '最大重试次数', banTime: '禁用时间', banTimeHelper: '默认禁用时间为 10 分钟,禁用时间为 -1 则表示永久禁用', + banTimeRule: '请输入正确的禁用时间或者 -1', + banAllTime: '永久禁用', findTime: '发现周期', banAction: '禁用方式', banActionOption: '通过 {0} 来禁用指定的 IP 地址', diff --git a/frontend/src/views/host/ssh/ssh/index.vue b/frontend/src/views/host/ssh/ssh/index.vue index ca124214a..00e25b911 100644 --- a/frontend/src/views/host/ssh/ssh/index.vue +++ b/frontend/src/views/host/ssh/ssh/index.vue @@ -246,7 +246,7 @@ const onOperate = async (operation: string) => { }); }) .catch(() => { - autoStart.value = operation === 'enable' ? 'disable' : 'enable'; + search(); }); }; diff --git a/frontend/src/views/toolbox/fail2ban/ban-time/index.vue b/frontend/src/views/toolbox/fail2ban/ban-time/index.vue index c25062b76..324d67989 100644 --- a/frontend/src/views/toolbox/fail2ban/ban-time/index.vue +++ b/frontend/src/views/toolbox/fail2ban/ban-time/index.vue @@ -4,14 +4,17 @@ - + - + @@ -43,7 +46,6 @@ import { reactive, ref } from 'vue'; import i18n from '@/lang'; import { MsgSuccess } from '@/utils/message'; import { FormInstance } from 'element-plus'; -import { Rules } from '@/global/form-rules'; import DrawerHeader from '@/components/drawer-header/index.vue'; import { updateFail2ban } from '@/api/modules/toolbox'; import { splitTime, transTimeUnit } from '@/utils/util'; @@ -61,6 +63,20 @@ const form = reactive({ banTimeUnit: 's', }); +const rules = reactive({ + banTime: [{ validator: checkBanTime, trigger: 'blur' }], +}); +function checkBanTime(rule: any, value: any, callback: any) { + if (value === -1) { + callback(); + } + const reg = /^[1-9]\d*$/; + if (!reg.test(value)) { + return callback(new Error(i18n.global.t('toolbox.fail2ban.banTimeRule'))); + } + callback(); +} + const formRef = ref(); const acceptParams = (params: DialogProps): void => { @@ -74,11 +90,12 @@ const onSave = async (formEl: FormInstance | undefined) => { if (!formEl) return; formEl.validate(async (valid) => { if (!valid) return; + let itemMsg = + form.banTime === -1 + ? i18n.global.t('toolbox.fail2ban.banAllTime') + : form.banTime + transTimeUnit(form.banTimeUnit); ElMessageBox.confirm( - i18n.global.t('ssh.sshChangeHelper', [ - i18n.global.t('toolbox.fail2ban.banTime'), - form.banTime + transTimeUnit(form.banTimeUnit), - ]), + i18n.global.t('ssh.sshChangeHelper', [i18n.global.t('toolbox.fail2ban.banTime'), itemMsg]), i18n.global.t('toolbox.fail2ban.fail2banChange'), { confirmButtonText: i18n.global.t('commons.button.confirm'), @@ -86,7 +103,8 @@ const onSave = async (formEl: FormInstance | undefined) => { type: 'info', }, ).then(async () => { - await updateFail2ban({ key: 'bantime', value: form.banTime + form.banTimeUnit }) + let itemValue = form.banTime === -1 ? '-1' : form.banTime + form.banTimeUnit; + await updateFail2ban({ key: 'bantime', value: itemValue }) .then(async () => { MsgSuccess(i18n.global.t('commons.msg.operationSuccess')); loading.value = false; diff --git a/frontend/src/views/toolbox/fail2ban/index.vue b/frontend/src/views/toolbox/fail2ban/index.vue index fa45d2a87..dd6a8308e 100644 --- a/frontend/src/views/toolbox/fail2ban/index.vue +++ b/frontend/src/views/toolbox/fail2ban/index.vue @@ -65,6 +65,16 @@ + + + + + {{ $t('commons.button.set') }} + + + + {{ $t('toolbox.fail2ban.sshPortHelper') }} + @@ -164,6 +174,7 @@ + @@ -179,6 +190,7 @@ import BanTime from '@/views/toolbox/fail2ban/ban-time/index.vue'; import FindTime from '@/views/toolbox/fail2ban/find-time/index.vue'; import BanAction from '@/views/toolbox/fail2ban/ban-action/index.vue'; import LogPath from '@/views/toolbox/fail2ban/log-path/index.vue'; +import Port from '@/views/toolbox/fail2ban/port/index.vue'; import IPs from '@/views/toolbox/fail2ban/ips/index.vue'; import i18n from '@/lang'; import { MsgSuccess } from '@/utils/message'; @@ -191,6 +203,7 @@ const formRef = ref(); const extensions = [javascript(), oneDark]; const confShowType = ref('base'); +const portRef = ref(); const maxRetryRef = ref(); const banTimeRef = ref(); const findTimeRef = ref(); @@ -242,6 +255,9 @@ const onSaveFile = async () => { }); }); }; +const onChangePort = () => { + portRef.value.acceptParams({ port: form.port }); +}; const onChangeMaxRetry = () => { maxRetryRef.value.acceptParams({ maxRetry: form.maxRetry }); }; @@ -279,7 +295,7 @@ const onOperate = async (operation: string) => { }); }) .catch(() => { - autoStart.value = operation === 'enable' ? 'disable' : 'enable'; + search(); }); }; @@ -307,7 +323,8 @@ const search = async () => { form.port = res.data.port; form.maxRetry = res.data.maxRetry; form.banTime = res.data.banTime; - form.banTimeItem = transTimeUnit(form.banTime); + form.banTimeItem = + form.banTime === '-1' ? i18n.global.t('toolbox.fail2ban.banAllTime') : transTimeUnit(form.banTime); form.findTime = res.data.findTime; form.findTimeItem = transTimeUnit(form.findTime); form.banAction = res.data.banAction; diff --git a/frontend/src/views/toolbox/fail2ban/port/index.vue b/frontend/src/views/toolbox/fail2ban/port/index.vue new file mode 100644 index 000000000..10127e226 --- /dev/null +++ b/frontend/src/views/toolbox/fail2ban/port/index.vue @@ -0,0 +1,100 @@ + + + + + + + + + + + + + + + + + + {{ $t('commons.button.cancel') }} + + {{ $t('commons.button.confirm') }} + + + + + + +