From 53230e28b500aeac1a8ea6719a6e943a88c0ed35 Mon Sep 17 00:00:00 2001 From: Teng Zhang Date: Sun, 10 May 2026 19:35:02 +0800 Subject: [PATCH 1/3] feat: add port security awareness panel to firewall page --- agent/app/api/v2/firewall.go | 23 ++ agent/app/dto/firewall.go | 34 ++ agent/app/service/firewall.go | 1 + agent/app/service/firewall_port_security.go | 371 ++++++++++++++++++ agent/router/ro_host.go | 1 + frontend/src/api/interface/host.ts | 31 ++ frontend/src/api/modules/host.ts | 3 + frontend/src/lang/modules/en.ts | 21 + frontend/src/lang/modules/es-es.ts | 19 + frontend/src/lang/modules/ja.ts | 19 + frontend/src/lang/modules/ko.ts | 19 + frontend/src/lang/modules/ms.ts | 19 + frontend/src/lang/modules/pt-br.ts | 19 + frontend/src/lang/modules/ru.ts | 19 + frontend/src/lang/modules/tr.ts | 19 + frontend/src/lang/modules/zh-Hant.ts | 19 + frontend/src/lang/modules/zh.ts | 19 + .../host/firewall/port/awareness/index.vue | 226 +++++++++++ .../src/views/host/firewall/port/index.vue | 11 + 19 files changed, 893 insertions(+) create mode 100644 agent/app/service/firewall_port_security.go create mode 100644 frontend/src/views/host/firewall/port/awareness/index.vue diff --git a/agent/app/api/v2/firewall.go b/agent/app/api/v2/firewall.go index b36ddb871b1d..dde68c46ac20 100644 --- a/agent/app/api/v2/firewall.go +++ b/agent/app/api/v2/firewall.go @@ -337,3 +337,26 @@ func (b *BaseApi) LoadChainStatus(c *gin.Context) { helper.SuccessWithData(c, iptablesService.LoadChainStatus(req)) } + +// @Tags Firewall +// @Summary Get port security overview +// @Accept json +// @Param request body dto.PortSecuritySearch true "request" +// @Success 200 {object} dto.PortSecurityOverview +// @Security ApiKeyAuth +// @Security Timestamp +// @Router /hosts/firewall/port/security [post] +func (b *BaseApi) GetPortSecurity(c *gin.Context) { + var req dto.PortSecuritySearch + if err := helper.CheckBind(&req, c); err != nil { + return + } + + data, err := firewallService.GetPortSecurityOverview(req) + if err != nil { + helper.InternalServer(c, err) + return + } + + helper.SuccessWithData(c, data) +} diff --git a/agent/app/dto/firewall.go b/agent/app/dto/firewall.go index d12a9656b877..363a4abb46e5 100644 --- a/agent/app/dto/firewall.go +++ b/agent/app/dto/firewall.go @@ -111,3 +111,37 @@ type IptablesChainStatus struct { IsBind bool `json:"isBind"` DefaultStrategy string `json:"defaultStrategy"` } + +type PortSecuritySearch struct { + Info string `json:"info"` + Status string `json:"status"` +} + +type PortSecurityOverview struct { + Items []PortSecurityItem `json:"items"` + Summary PortSecuritySummary `json:"summary"` + FireActive bool `json:"fireActive"` + DockerExist bool `json:"dockerExist"` +} + +type PortSecuritySummary struct { + Total int `json:"total"` + Protected int `json:"protected"` + Unprotected int `json:"unprotected"` + DockerBypassed int `json:"dockerBypassed"` + LocalOnly int `json:"localOnly"` +} + +type PortSecurityItem struct { + Port uint32 `json:"port"` + Protocol string `json:"protocol"` + BindAddress string `json:"bindAddress"` + ProcessName string `json:"processName"` + PID int32 `json:"pid"` + SourceType string `json:"sourceType"` + ContainerName string `json:"containerName"` + AppName string `json:"appName"` + Status string `json:"status"` + HasRule bool `json:"hasRule"` + RuleStrategy string `json:"ruleStrategy"` +} diff --git a/agent/app/service/firewall.go b/agent/app/service/firewall.go index b06c2d0e135a..65f395ef57be 100644 --- a/agent/app/service/firewall.go +++ b/agent/app/service/firewall.go @@ -34,6 +34,7 @@ type IFirewallService interface { UpdateAddrRule(req dto.AddrRuleUpdate) error UpdateDescription(req dto.UpdateFirewallDescription) error BatchOperateRule(req dto.BatchRuleOperate) error + GetPortSecurityOverview(req dto.PortSecuritySearch) (*dto.PortSecurityOverview, error) } func NewIFirewallService() IFirewallService { diff --git a/agent/app/service/firewall_port_security.go b/agent/app/service/firewall_port_security.go new file mode 100644 index 000000000000..8680b76e096a --- /dev/null +++ b/agent/app/service/firewall_port_security.go @@ -0,0 +1,371 @@ +package service + +import ( + "context" + "fmt" + "sort" + "strconv" + "strings" + "sync" + "syscall" + "time" + + "github.com/1Panel-dev/1Panel/agent/app/dto" + "github.com/1Panel-dev/1Panel/agent/utils/docker" + "github.com/1Panel-dev/1Panel/agent/utils/firewall" + fireClient "github.com/1Panel-dev/1Panel/agent/utils/firewall/client" + "github.com/docker/docker/api/types/container" + "github.com/shirou/gopsutil/v4/net" + "github.com/shirou/gopsutil/v4/process" +) + +type portKey struct { + port uint32 + protocol string +} + +type dockerPortInfo struct { + containerName string + hostIP string +} + +type firewallRuleEntry struct { + strategy string + portStr string + protocol string +} + +// GetPortSecurityOverview scans all listening ports and cross-references them with +// Docker container bindings and firewall rules to produce a security status overview. +func (u *FirewallService) GetPortSecurityOverview(req dto.PortSecuritySearch) (*dto.PortSecurityOverview, error) { + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + defer cancel() + + var ( + wg sync.WaitGroup + connections []net.ConnectionStat + containers []container.Summary + firewallRules []fireClient.FireInfo + firewallActive bool + dockerExists bool + connectionErr error + dockerErr error + firewallErr error + ) + + wg.Add(3) + go func() { + defer wg.Done() + connections, connectionErr = net.ConnectionsMaxWithContext(ctx, "inet", 32768) + }() + go func() { + defer wg.Done() + cli, err := docker.NewDockerClient() + if err != nil { + dockerErr = err + return + } + defer cli.Close() + dockerExists = true + containers, dockerErr = cli.ContainerList(ctx, container.ListOptions{All: false}) + }() + go func() { + defer wg.Done() + fwClient, err := firewall.NewFirewallClient() + if err != nil { + firewallErr = err + return + } + firewallActive, _ = fwClient.Status() + firewallRules, firewallErr = fwClient.ListPort() + }() + wg.Wait() + + if connectionErr != nil { + return nil, fmt.Errorf("failed to get listening ports: %w", connectionErr) + } + + dockerPortMap := buildDockerPortMap(containers, dockerErr) + ruleIndex := buildFirewallRuleIndex(firewallRules, firewallErr) + appPortMap := buildAppPortMap(ctx) + + seenIndex := make(map[portKey]int) + items := make([]dto.PortSecurityItem, 0) + + for _, conn := range connections { + if conn.Pid == 0 { + continue + } + isListen := conn.Status == "LISTEN" && conn.Type == syscall.SOCK_STREAM + isUDP := conn.Type == syscall.SOCK_DGRAM && conn.Raddr.Port == 0 + if !isListen && !isUDP { + continue + } + + proto := "tcp" + if conn.Type == syscall.SOCK_DGRAM { + proto = "udp" + } + + bindAddr := conn.Laddr.IP + if bindAddr == "" { + bindAddr = "0.0.0.0" + } + + key := portKey{port: conn.Laddr.Port, protocol: proto} + if idx, exists := seenIndex[key]; exists { + if isWildcardAddress(bindAddr) && !isWildcardAddress(items[idx].BindAddress) { + items[idx].BindAddress = bindAddr + } + continue + } + seenIndex[key] = len(items) + + item := dto.PortSecurityItem{ + Port: conn.Laddr.Port, + Protocol: proto, + BindAddress: bindAddr, + ProcessName: getProcessNameByPID(conn.Pid), + PID: conn.Pid, + SourceType: "host", + } + + if dInfo, ok := dockerPortMap[key]; ok { + item.SourceType = "docker" + item.ContainerName = dInfo.containerName + if dInfo.hostIP != "" { + item.BindAddress = dInfo.hostIP + } + } + + if appName, ok := appPortMap[conn.Laddr.Port]; ok { + item.AppName = appName + if item.SourceType == "docker" { + item.SourceType = "appStore" + } + } + + ruleStrategy, hasRule := matchFirewallRule(ruleIndex, conn.Laddr.Port, proto) + item.HasRule = hasRule + item.RuleStrategy = ruleStrategy + + items = append(items, item) + } + + for i := range items { + items[i].Status = determineStatus(items[i].BindAddress, items[i].SourceType, firewallActive, items[i].HasRule) + } + + // Sort by status priority > protocol > port number + sort.Slice(items, func(i, j int) bool { + pi, pj := statusSortPriority(items[i].Status), statusSortPriority(items[j].Status) + if pi != pj { + return pi < pj + } + if items[i].Protocol != items[j].Protocol { + return items[i].Protocol < items[j].Protocol + } + return items[i].Port < items[j].Port + }) + + // Summary is computed before filtering so it reflects overall status + summary := dto.PortSecuritySummary{Total: len(items)} + for _, item := range items { + switch item.Status { + case "protected": + summary.Protected++ + case "noRule": + summary.Unprotected++ + case "dockerBypass": + summary.DockerBypassed++ + case "localOnly": + summary.LocalOnly++ + case "firewallInactive": + summary.Unprotected++ + } + } + + // Apply filters after summary (so summary reflects totals, filters narrow the list) + if req.Info != "" || req.Status != "" { + filtered := make([]dto.PortSecurityItem, 0) + keyword := strings.ToLower(req.Info) + for _, item := range items { + if req.Status != "" && item.Status != req.Status { + continue + } + if keyword != "" { + portStr := strconv.FormatUint(uint64(item.Port), 10) + if !strings.Contains(portStr, keyword) && + !strings.Contains(strings.ToLower(item.ProcessName), keyword) && + !strings.Contains(strings.ToLower(item.ContainerName), keyword) { + continue + } + } + filtered = append(filtered, item) + } + items = filtered + } + + return &dto.PortSecurityOverview{ + Items: items, + Summary: summary, + FireActive: firewallActive, + DockerExist: dockerExists, + }, nil +} + +// buildDockerPortMap creates a lookup map from host port to container info. +func buildDockerPortMap(containers []container.Summary, err error) map[portKey]dockerPortInfo { + result := make(map[portKey]dockerPortInfo) + if err != nil || containers == nil { + return result + } + for _, c := range containers { + name := "" + if len(c.Names) > 0 { + name = strings.TrimPrefix(c.Names[0], "/") + } + for _, p := range c.Ports { + if p.PublicPort == 0 { + continue + } + key := portKey{port: uint32(p.PublicPort), protocol: p.Type} + result[key] = dockerPortInfo{ + containerName: name, + hostIP: p.IP, + } + } + } + return result +} + +// buildFirewallRuleIndex converts firewall rules into a list for port matching. +func buildFirewallRuleIndex(rules []fireClient.FireInfo, err error) []firewallRuleEntry { + if err != nil || rules == nil { + return nil + } + var entries []firewallRuleEntry + for _, r := range rules { + entries = append(entries, firewallRuleEntry{ + strategy: r.Strategy, + portStr: r.Port, + protocol: r.Protocol, + }) + } + return entries +} + +// buildAppPortMap creates a lookup map from port number to app name. +func buildAppPortMap(ctx context.Context) map[uint32]string { + result := make(map[uint32]string) + apps, err := appInstallRepo.ListBy(ctx) + if err != nil { + return result + } + for _, app := range apps { + if app.HttpPort > 0 { + result[uint32(app.HttpPort)] = app.App.Key + } + if app.HttpsPort > 0 { + result[uint32(app.HttpsPort)] = app.App.Key + } + } + systemPort, err := settingRepo.Get(settingRepo.WithByKey("ServerPort")) + if err == nil && systemPort.Value != "" { + if port, e := strconv.ParseUint(systemPort.Value, 10, 32); e == nil { + result[uint32(port)] = "1panel" + } + } + return result +} + +// matchFirewallRule checks if a port has a matching firewall rule, respecting protocol. +func matchFirewallRule(rules []firewallRuleEntry, port uint32, proto string) (string, bool) { + portStr := strconv.FormatUint(uint64(port), 10) + for _, r := range rules { + if r.protocol != "" && r.protocol != "tcp/udp" && r.protocol != proto { + continue + } + if portMatchesRule(portStr, port, r.portStr) { + return r.strategy, true + } + } + return "", false +} + +func portMatchesRule(portStr string, portNum uint32, rulePort string) bool { + if rulePort == portStr { + return true + } + sep := "" + if strings.Contains(rulePort, "-") { + sep = "-" + } else if strings.Contains(rulePort, ":") { + sep = ":" + } + if sep != "" { + parts := strings.Split(rulePort, sep) + if len(parts) == 2 { + start, err1 := strconv.ParseUint(strings.TrimSpace(parts[0]), 10, 32) + end, err2 := strconv.ParseUint(strings.TrimSpace(parts[1]), 10, 32) + if err1 == nil && err2 == nil && uint64(portNum) >= start && uint64(portNum) <= end { + return true + } + } + } + return false +} + +// determineStatus assigns a security status to a port based on its bind address, +// source type, firewall state, and rule coverage. Priority order: +// 1. Non-wildcard bind address → localOnly +// 2. Docker/appStore source → dockerBypass +// 3. Firewall inactive → firewallInactive +// 4. Has matching rule → protected +// 5. Otherwise → noRule +func determineStatus(bindAddr, sourceType string, firewallActive, hasRule bool) string { + if !isWildcardAddress(bindAddr) { + return "localOnly" + } + if sourceType == "docker" || sourceType == "appStore" { + return "dockerBypass" + } + if !firewallActive { + return "firewallInactive" + } + if hasRule { + return "protected" + } + return "noRule" +} + +func statusSortPriority(status string) int { + switch status { + case "firewallInactive": + return 0 + case "dockerBypass": + return 1 + case "noRule": + return 2 + case "protected": + return 3 + case "localOnly": + return 4 + default: + return 5 + } +} + +// isWildcardAddress returns true if the address binds to all interfaces. +func isWildcardAddress(addr string) bool { + return addr == "0.0.0.0" || addr == "::" || addr == "" +} + +func getProcessNameByPID(pid int32) string { + proc, err := process.NewProcess(pid) + if err != nil { + return "" + } + name, _ := proc.Name() + return name +} diff --git a/agent/router/ro_host.go b/agent/router/ro_host.go index bb4446842870..b2fd38e197cf 100644 --- a/agent/router/ro_host.go +++ b/agent/router/ro_host.go @@ -37,6 +37,7 @@ func (s *HostRouter) InitRouter(Router *gin.RouterGroup) { hostRouter.POST("/firewall/filter/rule/batch", baseApi.BatchOperateFilterRule) hostRouter.POST("/firewall/filter/operate", baseApi.OperateFilterChain) hostRouter.POST("/firewall/filter/chain/status", baseApi.LoadChainStatus) + hostRouter.POST("/firewall/port/security", baseApi.GetPortSecurity) hostRouter.POST("/monitor/search", baseApi.LoadMonitor) hostRouter.POST("/monitor/gpu/search", baseApi.LoadGPUMonitor) diff --git a/frontend/src/api/interface/host.ts b/frontend/src/api/interface/host.ts index f6ab0343cd6e..f37118104055 100644 --- a/frontend/src/api/interface/host.ts +++ b/frontend/src/api/interface/host.ts @@ -140,6 +140,37 @@ export namespace Host { rules: Array; } + export interface PortSecuritySearch { + info: string; + status: string; + } + export interface PortSecurityItem { + port: number; + protocol: string; + bindAddress: string; + processName: string; + pid: number; + sourceType: string; + containerName: string; + appName: string; + status: string; + hasRule: boolean; + ruleStrategy: string; + } + export interface PortSecuritySummary { + total: number; + protected: number; + unprotected: number; + dockerBypassed: number; + localOnly: number; + } + export interface PortSecurityOverview { + items: Array; + summary: PortSecuritySummary; + fireActive: boolean; + dockerExist: boolean; + } + export interface MonitorSetting { defaultNetwork: string; defaultIO: string; diff --git a/frontend/src/api/modules/host.ts b/frontend/src/api/modules/host.ts index 3357db136be9..8aca89176696 100644 --- a/frontend/src/api/modules/host.ts +++ b/frontend/src/api/modules/host.ts @@ -43,6 +43,9 @@ export const updateFirewallDescription = (params: Host.UpdateDescription) => { export const batchOperateRule = (params: Host.BatchRule) => { return http.post(`/hosts/firewall/batch`, params, TimeoutEnum.T_60S); }; +export const getPortSecurity = (params: Host.PortSecuritySearch) => { + return http.post(`/hosts/firewall/port/security`, params, TimeoutEnum.T_40S); +}; // Iptables Filter export const searchFilterRules = (params: Host.IptablesFilterRuleSearch) => { diff --git a/frontend/src/lang/modules/en.ts b/frontend/src/lang/modules/en.ts index df08fc3e6a75..419d68ff4026 100644 --- a/frontend/src/lang/modules/en.ts +++ b/frontend/src/lang/modules/en.ts @@ -3361,6 +3361,27 @@ const message = { cookieBlockList: 'Cookie blocklist', dockerHelper: 'The current firewall cannot disable container port mapping. Installed applications can go to the [Installed] page to edit application parameters and configure port release rules.', + portSecurity: 'Port Security Scan', + portSecurityAllSafe: 'All listening ports are protected', + dockerBypass: 'Docker Bypass', + dockerBypassTip: + 'This port is exposed via Docker container mapping, bypassing firewall INPUT chain rules. Adding port rules cannot block external access.', + dockerBypassSuggest: + 'Suggest changing port mapping to 127.0.0.1:{0}:{0} in docker-compose.yml and restart the container.', + dockerBypassHasRule: 'Firewall rule exists ({0} {1}/{2}), but it is not effective.', + noRule: 'No Rule', + localOnly: 'Local Only', + protected: 'Protected', + firewallInactive: 'Firewall Inactive', + goToApp: 'Go to App Settings', + dockerBypassDetail: 'How to fix', + createRuleQuick: 'Create Rule', + portSecurityRiskLabel: 'risk(s)', + portSecurityPendingLabel: 'pending', + portSecuritySafeLabel: 'safe', + portSecuritySource: 'Process / Container', + portSecurityBindAddr: 'Bind Address', + dockerLabel: 'Container', iptablesHelper: 'Detected that the system is using {0} firewall. To switch to iptables, please uninstall it manually first!', quickJump: 'Quick access', diff --git a/frontend/src/lang/modules/es-es.ts b/frontend/src/lang/modules/es-es.ts index b3728ff5c03c..7fc80003fc3c 100644 --- a/frontend/src/lang/modules/es-es.ts +++ b/frontend/src/lang/modules/es-es.ts @@ -3394,6 +3394,25 @@ const message = { cookieBlockList: 'Lista negra de cookies', dockerHelper: 'El firewall actual no puede deshabilitar el mapeo de puertos de contenedores. Las aplicaciones instaladas pueden ir a la página [Instaladas] para editar los parámetros de la aplicación y configurar reglas de liberación de puertos.', + portSecurity: 'Análisis de Seguridad de Puertos', + portSecurityAllSafe: 'Todos los puertos en escucha están protegidos', + dockerBypass: 'Bypass de Docker', + dockerBypassTip: 'Este puerto está expuesto mediante el mapeo de contenedor Docker, eludiendo las reglas de la cadena INPUT del cortafuegos. Añadir reglas de puerto no puede bloquear el acceso externo.', + dockerBypassSuggest: 'Se recomienda cambiar el mapeo de puertos a 127.0.0.1:{0}:{0} en docker-compose.yml y reiniciar el contenedor.', + dockerBypassHasRule: 'Existe una regla de cortafuegos ({0} {1}/{2}), pero no es efectiva.', + noRule: 'Sin Regla', + localOnly: 'Solo Local', + protected: 'Protegido', + firewallInactive: 'Cortafuegos Inactivo', + goToApp: 'Ir a Configuración de la App', + dockerBypassDetail: 'Cómo solucionarlo', + createRuleQuick: 'Crear Regla', + portSecurityRiskLabel: 'riesgo(s)', + portSecurityPendingLabel: 'pendiente(s)', + portSecuritySafeLabel: 'seguro(s)', + portSecuritySource: 'Proceso / Contenedor', + portSecurityBindAddr: 'Dirección de Enlace', + dockerLabel: 'Contenedor', iptablesHelper: 'Se detectó que el sistema está usando el firewall {0}. Para cambiar a iptables, ¡desinstálelo manualmente primero!', quickJump: 'Acceso rápido', diff --git a/frontend/src/lang/modules/ja.ts b/frontend/src/lang/modules/ja.ts index ac49b4333f9e..daf5a5fedde0 100644 --- a/frontend/src/lang/modules/ja.ts +++ b/frontend/src/lang/modules/ja.ts @@ -3384,6 +3384,25 @@ const message = { cookieBlockList: 'クッキーブロックリスト', dockerHelper: '現在のファイアウォールではコンテナのポートマッピングを無効にできません。インストール済みアプリケーションは【インストール済み】ページでアプリケーションパラメータを編集し、ポート開放ルールを設定できます。', + portSecurity: 'ポートセキュリティスキャン', + portSecurityAllSafe: 'すべてのリスニングポートは保護されています', + dockerBypass: 'Docker バイパス', + dockerBypassTip: 'このポートは Docker コンテナマッピングにより公開されており、ファイアウォールの INPUT チェーンルールをバイパスしています。ポートルールを追加しても外部アクセスをブロックできません。', + dockerBypassSuggest: 'docker-compose.yml でポートマッピングを 127.0.0.1:{0}:{0} に変更し、コンテナを再起動することを推奨します。', + dockerBypassHasRule: 'ファイアウォールルールが存在します({0} {1}/{2})が、実際には有効ではありません。', + noRule: 'ルールなし', + localOnly: 'ローカルのみ', + protected: '保護済み', + firewallInactive: 'ファイアウォール無効', + goToApp: 'アプリ設定へ移動', + dockerBypassDetail: '修正方法', + createRuleQuick: 'ルールを作成', + portSecurityRiskLabel: '件のリスク', + portSecurityPendingLabel: '件の未対応', + portSecuritySafeLabel: '件の安全', + portSecuritySource: 'プロセス / コンテナ', + portSecurityBindAddr: 'バインドアドレス', + dockerLabel: 'コンテナ', iptablesHelper: 'システムが {0} ファイアウォールを使用していることを検出しました。iptables に切り替えるには、まず手動でアンインストールしてください!', quickJump: 'クイックアクセス', diff --git a/frontend/src/lang/modules/ko.ts b/frontend/src/lang/modules/ko.ts index b221b0a9c41e..2917b9f3d37f 100644 --- a/frontend/src/lang/modules/ko.ts +++ b/frontend/src/lang/modules/ko.ts @@ -3306,6 +3306,25 @@ const message = { cookieBlockList: '쿠키 차단 목록', dockerHelper: '현재 방화벽은 컨테이너 포트 매핑을 비활성화할 수 없습니다. 설치된 애플리케이션은 [설치됨] 페이지에서 애플리케이션 매개변수를 편집하고 포트 해제 규칙을 구성할 수 있습니다.', + portSecurity: '포트 보안 스캔', + portSecurityAllSafe: '모든 수신 포트가 보호되고 있습니다', + dockerBypass: 'Docker 우회', + dockerBypassTip: '이 포트는 Docker 컨테이너 매핑을 통해 노출되어 방화벽 INPUT 체인 규칙을 우회합니다. 포트 규칙을 추가해도 외부 접근을 차단할 수 없습니다.', + dockerBypassSuggest: 'docker-compose.yml에서 포트 매핑을 127.0.0.1:{0}:{0}으로 변경하고 컨테이너를 재시작하는 것을 권장합니다.', + dockerBypassHasRule: '방화벽 규칙이 존재하지만({0} {1}/{2}), 실제로 적용되지 않습니다.', + noRule: '규칙 없음', + localOnly: '로컬 전용', + protected: '보호됨', + firewallInactive: '방화벽 비활성', + goToApp: '앱 설정으로 이동', + dockerBypassDetail: '해결 방법', + createRuleQuick: '규칙 생성', + portSecurityRiskLabel: '개 위험', + portSecurityPendingLabel: '개 보류', + portSecuritySafeLabel: '개 안전', + portSecuritySource: '프로세스 / 컨테이너', + portSecurityBindAddr: '바인드 주소', + dockerLabel: '컨테이너', iptablesHelper: '시스템이 {0} 방화벽을 사용 중인 것으로 감지되었습니다. iptables로 전환하려면 먼저 수동으로 제거하세요!', used: '사용됨', diff --git a/frontend/src/lang/modules/ms.ts b/frontend/src/lang/modules/ms.ts index 59e8eed9d2e5..113859a2c6cc 100644 --- a/frontend/src/lang/modules/ms.ts +++ b/frontend/src/lang/modules/ms.ts @@ -3432,6 +3432,25 @@ const message = { cookieBlockList: 'Senarai blok Cookie', dockerHelper: 'Firewall semasa tidak boleh melumpuhkan pemetaan port bekas. Aplikasi yang dipasang boleh pergi ke halaman [Dipasang] untuk mengedit parameter aplikasi dan mengkonfigurasi peraturan pelepasan port.', + portSecurity: 'Imbasan Keselamatan Port', + portSecurityAllSafe: 'Semua port yang mendengar telah dilindungi', + dockerBypass: 'Pintasan Docker', + dockerBypassTip: 'Port ini didedahkan melalui pemetaan kontena Docker, memintas peraturan rantai INPUT firewall. Menambah peraturan port tidak dapat menyekat akses luaran.', + dockerBypassSuggest: 'Disarankan untuk menukar pemetaan port kepada 127.0.0.1:{0}:{0} dalam docker-compose.yml dan mulakan semula kontena.', + dockerBypassHasRule: 'Peraturan firewall wujud ({0} {1}/{2}), tetapi ia tidak berkesan.', + noRule: 'Tiada Peraturan', + localOnly: 'Setempat Sahaja', + protected: 'Dilindungi', + firewallInactive: 'Firewall Tidak Aktif', + goToApp: 'Pergi ke Tetapan Aplikasi', + dockerBypassDetail: 'Cara membaiki', + createRuleQuick: 'Cipta Peraturan', + portSecurityRiskLabel: 'risiko', + portSecurityPendingLabel: 'belum selesai', + portSecuritySafeLabel: 'selamat', + portSecuritySource: 'Proses / Kontena', + portSecurityBindAddr: 'Alamat Bind', + dockerLabel: 'Kontena', iptablesHelper: 'Dikesan sistem menggunakan firewall {0}. Untuk beralih ke iptables, sila nyahpasang secara manual dahulu!', quickJump: 'Akses pantas', diff --git a/frontend/src/lang/modules/pt-br.ts b/frontend/src/lang/modules/pt-br.ts index 1c8d80d86dcd..00bd27c88f29 100644 --- a/frontend/src/lang/modules/pt-br.ts +++ b/frontend/src/lang/modules/pt-br.ts @@ -3569,6 +3569,25 @@ const message = { cookieBlockList: 'Lista de cookies bloqueados', dockerHelper: 'O firewall atual não pode desativar o mapeamento de porta de contêiner. Aplicativos instalados podem ir para a página [Instalados] para editar parâmetros do aplicativo e configurar regras de liberação de porta.', + portSecurity: 'Verificação de Segurança de Portas', + portSecurityAllSafe: 'Todas as portas em escuta estão protegidas', + dockerBypass: 'Bypass do Docker', + dockerBypassTip: 'Esta porta está exposta via mapeamento de contêiner Docker, ignorando as regras da cadeia INPUT do firewall. Adicionar regras de porta não pode bloquear o acesso externo.', + dockerBypassSuggest: 'Sugerimos alterar o mapeamento de porta para 127.0.0.1:{0}:{0} no docker-compose.yml e reiniciar o contêiner.', + dockerBypassHasRule: 'Regra de firewall existente ({0} {1}/{2}), mas não está em vigor.', + noRule: 'Sem Regra', + localOnly: 'Apenas Local', + protected: 'Protegido', + firewallInactive: 'Firewall Inativo', + goToApp: 'Ir para Configurações do App', + dockerBypassDetail: 'Como corrigir', + createRuleQuick: 'Criar Regra', + portSecurityRiskLabel: 'risco(s)', + portSecurityPendingLabel: 'pendente(s)', + portSecuritySafeLabel: 'seguro(s)', + portSecuritySource: 'Processo / Contêiner', + portSecurityBindAddr: 'Endereço de Bind', + dockerLabel: 'Contêiner', iptablesHelper: 'Detectado que o sistema está usando o firewall {0}. Para mudar para iptables, desinstale-o manualmente primeiro!', quickJump: 'Acesso rápido', diff --git a/frontend/src/lang/modules/ru.ts b/frontend/src/lang/modules/ru.ts index 07010dd34921..e1f0d6c6d6aa 100644 --- a/frontend/src/lang/modules/ru.ts +++ b/frontend/src/lang/modules/ru.ts @@ -3426,6 +3426,25 @@ const message = { cookieBlockList: 'Черный список Cookie', dockerHelper: 'Текущий брандмауэр не может отключить сопоставление портов контейнера. Установленные приложения могут перейти на страницу [Установленные], чтобы редактировать параметры приложения и настраивать правила открытия портов.', + portSecurity: 'Сканирование безопасности портов', + portSecurityAllSafe: 'Все прослушиваемые порты защищены', + dockerBypass: 'Обход Docker', + dockerBypassTip: 'Этот порт открыт через маппинг контейнера Docker, минуя правила цепочки INPUT брандмауэра. Добавление правил для порта не может заблокировать внешний доступ.', + dockerBypassSuggest: 'Рекомендуется изменить маппинг порта на 127.0.0.1:{0}:{0} в docker-compose.yml и перезапустить контейнер.', + dockerBypassHasRule: 'Правило брандмауэра существует ({0} {1}/{2}), но оно не действует.', + noRule: 'Нет правила', + localOnly: 'Только локально', + protected: 'Защищён', + firewallInactive: 'Брандмауэр неактивен', + goToApp: 'Перейти к настройкам приложения', + dockerBypassDetail: 'Как исправить', + createRuleQuick: 'Создать правило', + portSecurityRiskLabel: 'риск(ов)', + portSecurityPendingLabel: 'в ожидании', + portSecuritySafeLabel: 'безопасно', + portSecuritySource: 'Процесс / Контейнер', + portSecurityBindAddr: 'Адрес привязки', + dockerLabel: 'Контейнер', iptablesHelper: 'Обнаружено, что система использует брандмауэр {0}. Чтобы переключиться на iptables, сначала удалите его вручную!', quickJump: 'Быстрый доступ', diff --git a/frontend/src/lang/modules/tr.ts b/frontend/src/lang/modules/tr.ts index 2d3484cd6814..c1ee99aac507 100644 --- a/frontend/src/lang/modules/tr.ts +++ b/frontend/src/lang/modules/tr.ts @@ -3427,6 +3427,25 @@ const message = { cookieBlockList: 'Çerez engelleme listesi', dockerHelper: 'Mevcut güvenlik duvarı konteyner port eşlemesini devre dışı bırakamaz. Yüklü uygulamalar, uygulama parametrelerini düzenlemek ve port serbest bırakma kurallarını yapılandırmak için [Yüklü] sayfasına gidebilir.', + portSecurity: 'Port Güvenlik Taraması', + portSecurityAllSafe: 'Tüm dinlenen portlar korunuyor', + dockerBypass: 'Docker Atlatma', + dockerBypassTip: 'Bu port, Docker konteyner eşlemesi aracılığıyla açığa çıkmıştır ve güvenlik duvarı INPUT zinciri kurallarını atlatmaktadır. Port kuralı eklemek dış erişimi engelleyemez.', + dockerBypassSuggest: 'docker-compose.yml dosyasında port eşlemesini 127.0.0.1:{0}:{0} olarak değiştirip konteyneri yeniden başlatmanız önerilir.', + dockerBypassHasRule: 'Güvenlik duvarı kuralı mevcut ({0} {1}/{2}), ancak etkili değil.', + noRule: 'Kural Yok', + localOnly: 'Yalnızca Yerel', + protected: 'Korumalı', + firewallInactive: 'Güvenlik Duvarı Devre Dışı', + goToApp: 'Uygulama Ayarlarına Git', + dockerBypassDetail: 'Nasıl düzeltilir', + createRuleQuick: 'Kural Oluştur', + portSecurityRiskLabel: 'risk', + portSecurityPendingLabel: 'beklemede', + portSecuritySafeLabel: 'güvenli', + portSecuritySource: 'İşlem / Konteyner', + portSecurityBindAddr: 'Bağlama Adresi', + dockerLabel: 'Konteyner', iptablesHelper: "Sistemin {0} güvenlik duvarını kullandığı tespit edildi. iptables'a geçmek için lütfen önce manuel olarak kaldırın!", quickJump: 'Hızlı erişim', diff --git a/frontend/src/lang/modules/zh-Hant.ts b/frontend/src/lang/modules/zh-Hant.ts index bf21b1333222..67ca47be6aef 100644 --- a/frontend/src/lang/modules/zh-Hant.ts +++ b/frontend/src/lang/modules/zh-Hant.ts @@ -3112,6 +3112,25 @@ const message = { postCheck: 'POST 參數校驗', cookieBlockList: 'Cookie 黑名單', dockerHelper: '目前防火牆無法停用容器埠映射,已安裝應用可前往【已安裝】頁面編輯應用參數,設定埠放行規則。', + portSecurity: '連接埠安全檢測', + portSecurityAllSafe: '所有監聽連接埠已受保護', + dockerBypass: 'Docker 繞過', + dockerBypassTip: '此連接埠透過 Docker 容器映射,繞過防火牆 INPUT 規則。新增連接埠規則無法阻止外部存取。', + dockerBypassSuggest: '建議在 docker-compose.yml 中將連接埠映射改為 127.0.0.1:{0}:{0},然後重啟容器。', + dockerBypassHasRule: '已有防火牆規則({0} {1}/{2}),但該規則實際不生效。', + noRule: '未配置規則', + localOnly: '僅本機', + protected: '已保護', + firewallInactive: '防火牆未啟用', + goToApp: '前往容器設定', + dockerBypassDetail: '如何修復', + createRuleQuick: '建立規則', + portSecurityRiskLabel: '個風險', + portSecurityPendingLabel: '個待處理', + portSecuritySafeLabel: '個已安全', + portSecuritySource: '處理程序 / 容器', + portSecurityBindAddr: '綁定位址', + dockerLabel: '容器', iptablesHelper: '偵測到系統正在使用 {0} 防火牆,如需切換至 iptables,請先手動解除安裝', quickJump: '快速跳轉', used: '已使用', diff --git a/frontend/src/lang/modules/zh.ts b/frontend/src/lang/modules/zh.ts index 8dfb25a94b9b..fa20e32f22f7 100644 --- a/frontend/src/lang/modules/zh.ts +++ b/frontend/src/lang/modules/zh.ts @@ -3112,6 +3112,25 @@ const message = { cookieBlockList: 'Cookie 黑名单', dockerHelper: '当前防火墙无法禁用容器端口映射,已安装应用可前往【已安装】页面编辑应用参数,配置端口放行规则。', + portSecurity: '端口安全检测', + portSecurityAllSafe: '所有监听端口已保护', + dockerBypass: 'Docker 绕过', + dockerBypassTip: '此端口通过 Docker 容器映射,绕过防火墙 INPUT 规则。添加端口规则无法阻止外部访问。', + dockerBypassSuggest: '建议在 docker-compose.yml 中将端口映射改为 127.0.0.1:{0}:{0},然后重启容器。', + dockerBypassHasRule: '已有防火墙规则({0} {1}/{2}),但该规则实际不生效。', + noRule: '未配规则', + localOnly: '仅本机', + protected: '已保护', + firewallInactive: '防火墙未启用', + goToApp: '前往容器设置', + dockerBypassDetail: '如何修复', + createRuleQuick: '创建规则', + portSecurityRiskLabel: '个风险', + portSecurityPendingLabel: '个待处理', + portSecuritySafeLabel: '个已安全', + portSecuritySource: '进程 / 容器', + portSecurityBindAddr: '绑定地址', + dockerLabel: '容器', iptablesHelper: '检测到系统正在使用 {0} 防火墙,如需切换至 iptables,请先手动卸载!', quickJump: '快速跳转', used: '已使用', diff --git a/frontend/src/views/host/firewall/port/awareness/index.vue b/frontend/src/views/host/firewall/port/awareness/index.vue new file mode 100644 index 000000000000..a6fc34a3f8a3 --- /dev/null +++ b/frontend/src/views/host/firewall/port/awareness/index.vue @@ -0,0 +1,226 @@ + + + + + diff --git a/frontend/src/views/host/firewall/port/index.vue b/frontend/src/views/host/firewall/port/index.vue index 5d5c98f95307..83e2bb07c4de 100644 --- a/frontend/src/views/host/firewall/port/index.vue +++ b/frontend/src/views/host/firewall/port/index.vue @@ -21,6 +21,12 @@ {{ $t('firewall.basicStatus', ['1PANEL_BASIC']) }} + +