diff --git a/backend/app/repo/app_install.go b/backend/app/repo/app_install.go index cc0d61141..496371920 100644 --- a/backend/app/repo/app_install.go +++ b/backend/app/repo/app_install.go @@ -112,6 +112,7 @@ type RootInfo struct { ID uint `json:"id"` Name string `json:"name"` Port int64 `json:"port"` + HttpsPort int64 `json:"httpsPort"` Password string `json:"password"` UserPassword string `json:"userPassword"` ContainerName string `json:"containerName"` @@ -152,6 +153,7 @@ func (a *AppInstallRepo) LoadBaseInfo(key string, name string) (*RootInfo, error info.UserPassword = userPassword } info.Port = int64(appInstall.HttpPort) + info.HttpsPort = int64(appInstall.HttpsPort) info.ID = appInstall.ID info.ContainerName = appInstall.ContainerName info.Name = appInstall.Name diff --git a/backend/app/service/app_install.go b/backend/app/service/app_install.go index d7d78b021..9545c9089 100644 --- a/backend/app/service/app_install.go +++ b/backend/app/service/app_install.go @@ -387,6 +387,10 @@ func (a *AppInstallService) ChangeAppPort(req request.PortUpdate) error { } } + if err := OperateFirewallPort([]int{int(appInstall.Port)}, []int{int(req.Port)}); err != nil { + global.LOG.Errorf("allow firewall failed, err: %v", err) + } + return nil } diff --git a/backend/app/service/firewall.go b/backend/app/service/firewall.go index a1c56970a..09a099426 100644 --- a/backend/app/service/firewall.go +++ b/backend/app/service/firewall.go @@ -2,9 +2,12 @@ package service import ( "fmt" + "strconv" "strings" "github.com/1Panel-dev/1Panel/backend/app/dto" + "github.com/1Panel-dev/1Panel/backend/utils/cmd" + "github.com/1Panel-dev/1Panel/backend/utils/common" "github.com/1Panel-dev/1Panel/backend/utils/firewall" fireClient "github.com/1Panel-dev/1Panel/backend/utils/firewall/client" "github.com/jinzhu/copier" @@ -101,6 +104,22 @@ func (u *FirewallService) SearchWithPage(req dto.RuleSearch) (int64, interface{} backDatas = datas[start:end] } + if req.Type == "port" { + apps := u.loadPortByApp() + for i := 0; i < len(backDatas); i++ { + backDatas[i].IsUsed = common.ScanPortWithProtocol(backDatas[i].Port, backDatas[i].Protocol) + if backDatas[i].Protocol == "udp" { + continue + } + for _, app := range apps { + if app.HttpPort == backDatas[i].Port || app.HttpsPort == backDatas[i].Port { + backDatas[i].APPName = app.AppName + break + } + } + } + } + return int64(total), backDatas, nil } @@ -111,9 +130,24 @@ func (u *FirewallService) OperateFirewall(operation string) error { } switch operation { case "start": - return client.Start() + if err := client.Start(); err != nil { + return err + } + serverPort, err := settingRepo.Get(settingRepo.WithByKey("ServerPort")) + if err != nil { + return err + } + if err := client.Port(fireClient.FireInfo{Port: serverPort.Value, Protocol: "tcp", Strategy: "accept"}, "add"); err != nil { + return err + } + _, _ = cmd.Exec("systemctl restart docker") + return nil case "stop": - return client.Stop() + if err := client.Stop(); err != nil { + return err + } + _, _ = cmd.Exec("systemctl restart docker") + return nil case "disablePing": return client.UpdatePingStatus("0") case "enablePing": @@ -134,16 +168,47 @@ func (u *FirewallService) OperatePortRule(req dto.PortRuleOperate, reload bool) return u.operatePort(client, req) } } - if req.Protocol == "tcp/udp" { - req.Protocol = "tcp" - if err := u.operatePort(client, req); err != nil { - return err + if client.Name() == "firewalld" && strings.Contains(req.Port, ",") { + ports := strings.Split(req.Port, ",") + for _, port := range ports { + if len(port) == 0 { + continue + } + req.Port = port + req.Protocol = "tcp" + if err := u.operatePort(client, req); err != nil { + return err + } + req.Protocol = "udp" + if err := u.operatePort(client, req); err != nil { + return err + } + } + } else { + req.Protocol = "tcp" + if err := u.operatePort(client, req); err != nil { + return err + } + req.Protocol = "udp" + if err := u.operatePort(client, req); err != nil { + return err + } + } + } else { + if strings.Contains(req.Port, ",") { + ports := strings.Split(req.Port, ",") + for _, port := range ports { + req.Port = port + if err := u.operatePort(client, req); err != nil { + return err + } + } + } else { + if err := u.operatePort(client, req); err != nil { + return err + } } - req.Protocol = "udp" - } - if err := u.operatePort(client, req); err != nil { - return err } if reload { return client.Reload() @@ -228,6 +293,26 @@ func (u *FirewallService) BacthOperateRule(req dto.BatchRuleOperate) error { return client.Reload() } +func OperateFirewallPort(oldPorts, newPorts []int) error { + fmt.Printf("old: %v, new: %v \n", oldPorts, newPorts) + client, err := firewall.NewFirewallClient() + if err != nil { + return err + } + for _, port := range newPorts { + + if err := client.Port(fireClient.FireInfo{Port: strconv.Itoa(port), Protocol: "tcp", Strategy: "accept"}, "add"); err != nil { + return err + } + } + for _, port := range oldPorts { + if err := client.Port(fireClient.FireInfo{Port: strconv.Itoa(port), Protocol: "tcp", Strategy: "accept"}, "remove"); err != nil { + return err + } + } + return client.Reload() +} + func (u *FirewallService) operatePort(client firewall.FirewallClient, req dto.PortRuleOperate) error { var fireInfo fireClient.FireInfo if err := copier.Copy(&fireInfo, &req); err != nil { @@ -246,3 +331,31 @@ func (u *FirewallService) operatePort(client firewall.FirewallClient, req dto.Po } return client.Port(fireInfo, req.Operation) } + +type portOfApp struct { + AppName string + HttpPort string + HttpsPort string +} + +func (u *FirewallService) loadPortByApp() []portOfApp { + var datas []portOfApp + apps, err := appInstallRepo.ListBy() + if err != nil { + return datas + } + for i := 0; i < len(apps); i++ { + datas = append(datas, portOfApp{ + AppName: apps[i].App.Key, + HttpPort: strconv.Itoa(apps[i].HttpPort), + HttpsPort: strconv.Itoa(apps[i].HttpsPort), + }) + } + systemPort, err := settingRepo.Get(settingRepo.WithByKey("ServerPort")) + if err != nil { + return datas + } + datas = append(datas, portOfApp{AppName: "1panel", HttpPort: systemPort.Value}) + + return datas +} diff --git a/backend/app/service/setting.go b/backend/app/service/setting.go index 93ef774d5..454023805 100644 --- a/backend/app/service/setting.go +++ b/backend/app/service/setting.go @@ -70,7 +70,14 @@ func (u *SettingService) UpdatePort(port uint) error { if common.ScanPort(int(port)) { return buserr.WithDetail(constant.ErrPortInUsed, port, nil) } - + serverPort, err := settingRepo.Get(settingRepo.WithByKey("ServerPort")) + if err != nil { + return err + } + portValue, _ := strconv.Atoi(serverPort.Value) + if err := OperateFirewallPort([]int{portValue}, []int{int(port)}); err != nil { + global.LOG.Errorf("set system firewall ports failed, err: %v", err) + } if err := settingRepo.Update("ServerPort", strconv.Itoa(int(port))); err != nil { return err } diff --git a/backend/utils/common/common.go b/backend/utils/common/common.go index b29dc42cc..2126d8310 100644 --- a/backend/utils/common/common.go +++ b/backend/utils/common/common.go @@ -11,6 +11,8 @@ import ( "sort" "strconv" "strings" + + "github.com/1Panel-dev/1Panel/backend/utils/cmd" ) func CompareVersion(version1 string, version2 string) bool { @@ -92,6 +94,27 @@ func ScanPort(port int) bool { return false } +func ScanPortWithProtocol(port, Protocol string) bool { + command := "netstat -ntpl" + if Protocol == "udp" { + command = "netstat -nupl" + } + stdout, err := cmd.Execf("%s | awk '{print $4}' ", command) + if err != nil { + return false + } + lines := strings.Split(stdout, "\n") + if len(lines) == 0 { + return false + } + for _, line := range lines { + if strings.HasSuffix(line, ":"+port) { + return true + } + } + return false +} + func ExistWithStrArray(str string, arr []string) bool { for _, a := range arr { if strings.Contains(a, str) { diff --git a/backend/utils/firewall/client/firewalld.go b/backend/utils/firewall/client/firewalld.go index c0fe6c724..680624c24 100644 --- a/backend/utils/firewall/client/firewalld.go +++ b/backend/utils/firewall/client/firewalld.go @@ -20,7 +20,10 @@ func (f *Firewall) Name() string { func (f *Firewall) Status() (string, error) { stdout, _ := cmd.Exec("firewall-cmd --state") - return strings.ReplaceAll(stdout, "\n", ""), nil + if stdout == "running\n" { + return "running", nil + } + return "not running", nil } func (f *Firewall) Version() (string, error) { @@ -83,6 +86,9 @@ func (f *Firewall) ListPort() ([]FireInfo, error) { ports := strings.Split(strings.ReplaceAll(stdout, "\n", ""), " ") var datas []FireInfo for _, port := range ports { + if len(port) == 0 { + continue + } var itemPort FireInfo if strings.Contains(port, "/") { itemPort.Port = strings.Split(port, "/")[0] @@ -121,7 +127,7 @@ func (f *Firewall) ListAddress() ([]FireInfo, error) { continue } itemRule := f.loadInfo(rule) - if len(itemRule.Port) == 0 { + if len(itemRule.Port) == 0 && len(itemRule.Address) != 0 { datas = append(datas, itemRule) } } @@ -137,18 +143,22 @@ func (f *Firewall) Port(port FireInfo, operation string) error { } func (f *Firewall) RichRules(rule FireInfo, operation string) error { - ruleStr := "rule family=ipv4 " - if len(rule.Address) != 0 { - ruleStr += fmt.Sprintf("source address=%s ", rule.Address) + ruleStr := "" + if strings.Contains(rule.Address, "-") { + ruleStr = fmt.Sprintf("rule source ipset=%s %s", rule.Address, rule.Strategy) + } else { + ruleStr = "rule family=ipv4 " + if len(rule.Address) != 0 { + ruleStr += fmt.Sprintf("source address=%s ", rule.Address) + } + if len(rule.Port) != 0 { + ruleStr += fmt.Sprintf("port port=%s ", rule.Port) + } + if len(rule.Protocol) != 0 { + ruleStr += fmt.Sprintf("protocol=%s ", rule.Protocol) + } + ruleStr += rule.Strategy } - if len(rule.Port) != 0 { - ruleStr += fmt.Sprintf("port port=%s ", rule.Port) - } - if len(rule.Protocol) != 0 { - ruleStr += fmt.Sprintf("protocol=%s ", rule.Protocol) - } - ruleStr += rule.Strategy - 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) @@ -176,13 +186,15 @@ func (f *Firewall) loadInfo(line string) FireInfo { switch { case strings.Contains(item, "family="): itemRule.Family = strings.ReplaceAll(item, "family=", "") + case strings.Contains(item, "ipset="): + itemRule.Address = strings.ReplaceAll(item, "ipset=", "") case strings.Contains(item, "address="): itemRule.Address = strings.ReplaceAll(item, "address=", "") case strings.Contains(item, "port="): itemRule.Port = strings.ReplaceAll(item, "port=", "") case strings.Contains(item, "protocol="): itemRule.Protocol = strings.ReplaceAll(item, "protocol=", "") - case item == "accept" || item == "drop": + case item == "accept" || item == "drop" || item == "reject": itemRule.Strategy = item } } diff --git a/backend/utils/firewall/client/firewalld_test.go b/backend/utils/firewall/client/firewalld_test.go deleted file mode 100644 index 854ddbca4..000000000 --- a/backend/utils/firewall/client/firewalld_test.go +++ /dev/null @@ -1,37 +0,0 @@ -package client - -import ( - "fmt" - "strings" - "testing" - - "github.com/1Panel-dev/1Panel/backend/utils/ssh" -) - -func TestFire(t *testing.T) { - ConnInfo := ssh.ConnInfo{ - Addr: "172.16.10.234", - User: "ubuntu", - AuthMode: "password", - Port: 22, - } - output, err := ConnInfo.Run("sudo ufw status verbose") - if err != nil { - fmt.Println(err) - } - - lines := strings.Split(string(output), "\n") - var datas []FireInfo - isStart := false - for _, line := range lines { - if strings.HasPrefix(line, "--") { - isStart = true - continue - } - if !isStart { - continue - } - - } - fmt.Println(datas) -} diff --git a/backend/utils/firewall/client/info.go b/backend/utils/firewall/client/info.go index d931084fb..d9b507b0d 100644 --- a/backend/utils/firewall/client/info.go +++ b/backend/utils/firewall/client/info.go @@ -6,6 +6,9 @@ type FireInfo struct { Port string `json:"port"` Protocol string `json:"protocol"` // tcp udp tcp/udp Strategy string `json:"strategy"` // accept drop + + APPName string `json:"appName"` + IsUsed bool `json:"isUsed"` } type Forward struct { diff --git a/backend/utils/firewall/client/ufw.go b/backend/utils/firewall/client/ufw.go index 5c48263db..113c48c0d 100644 --- a/backend/utils/firewall/client/ufw.go +++ b/backend/utils/firewall/client/ufw.go @@ -85,6 +85,11 @@ func (f *Ufw) UpdatePingStatus(enabel string) error { return err } + stdout, err := cmd.Exec("sudo ufw reload") + if err != nil { + return fmt.Errorf("reload ufw setting failed, err: %v", stdout) + } + return nil } diff --git a/frontend/src/api/interface/host.ts b/frontend/src/api/interface/host.ts index efe9502b9..70f3a2929 100644 --- a/frontend/src/api/interface/host.ts +++ b/frontend/src/api/interface/host.ts @@ -69,6 +69,8 @@ export namespace Host { port: string; protocol: string; strategy: string; + appName: string; + isUsed: boolean; } export interface RulePort { operation: string; diff --git a/frontend/src/lang/modules/en.ts b/frontend/src/lang/modules/en.ts index 8fb628c0e..f6ffe35e6 100644 --- a/frontend/src/lang/modules/en.ts +++ b/frontend/src/lang/modules/en.ts @@ -1185,19 +1185,33 @@ const message = { cookieBlockList: 'Cookie Blacklist', firewall: 'Firewall', + used: 'Used', + unUsed: 'Unused', 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?', + 'After the system 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?', + 'After the firewall is enabled, the 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?', + noPingTitle: 'Disable ping', + noPingHelper: 'If the ping function is disabled, the server cannot be pinged. Do you want to continue?', onPingHelper: 'If you disable ping, hackers may discover your server. Do you want to continue?', protocol: 'Protocol', port: 'Port', changeStrategy: 'Change the {0} strategy', + changeStrategyIPHelper1: + 'Change the IP address strategy to [deny]. After the IP address is set, access to the server is prohibited. Do you want to continue?', + changeStrategyIPHelper2: + 'Change the IP address strategy to [allow]. After the IP address is set, normal access is restored. Do you want to continue?', + changeStrategyPortHelper1: + 'Change the port policy to [drop]. After the port policy is set, external access is denied. Do you want to continue?', + changeStrategyPortHelper2: + 'Change the port policy to [accept]. After the policy is set, normal port access will be restored. Do you want to continue?', + stop: 'Stop', + portFormatError: 'Please enter the correct port information!', + portHelper1: 'Multiple ports, such as 8080 and 8081', + portHelper2: 'Range port, such as 8080-8089', 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', @@ -1209,9 +1223,10 @@ const message = { 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', + addressFormatError: 'Please enter a valid ip address!', + addressHelper1: 'Multiple IP please separated with ",", such as 172.16.10.11, 172.16.10.99', + addressHelper2: 'IP segment, such as 172.16.10.0/24', + addressHelper3: '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 f4ba58b60..3d43e1c25 100644 --- a/frontend/src/lang/modules/zh.ts +++ b/frontend/src/lang/modules/zh.ts @@ -807,6 +807,8 @@ const message = { LOCAL: '服务器磁盘', currentPath: '当前路径', OSS: '阿里云 OSS', + COS: '腾讯云 cos browser', + KODO: '七牛云 Kodo', S3: '亚马逊 S3 云存储', MINIO: 'MINIO', SFTP: 'SFTP', @@ -1184,18 +1186,27 @@ const message = { cookieBlockList: 'Cookie 黑名单', firewall: '防火墙', + used: '已使用', + unUsed: '未使用', firewallHelper: '{0}系统防火墙', firewallNotStart: '当前未开启防火墙服务,请先开启!', - stopFirewallHelper: '停用系统防火墙,服务器将失去安全防护,是否继续操作?', - startFirewallHelper: '启用系统防火墙后,可以更好的防护当前的服务器安全,是否继续操作?', + stopFirewallHelper: '系统防火墙关闭后,服务器将失去安全防护,是否继续?', + startFirewallHelper: '系统防火墙开启后,可以更好的防护服务器安全,是否继续?', noPing: '禁 ping', - noPingHelper: '禁 ping 后不影响服务器正常使用,但无法 ping 通服务器,是否继续操作?', - onPingHelper: '解除禁 ping 状态可能会被黑客发现您的服务器,是否继续操作?', + noPingTitle: '是否禁 ping', + noPingHelper: '禁 ping 后将无法 ping 通服务器,是否继续?', + onPingHelper: '解除禁 ping 后您的服务器可能会被黑客发现,是否继续?', protocol: '协议', port: '端口', changeStrategy: '修改{0}策略', - changeStrategyHelper: '修改 [{1}] {0}策略为 [{2}],设置后该{0}将{2}外部访问,是否继续操作?', - portHelper: '支持输入多个端口,如 80,81 或者范围端口,如 80-88', + changeStrategyIPHelper1: 'IP 策略修改为【屏蔽】,设置后该 IP 将禁止访问服务器,是否继续?', + changeStrategyIPHelper2: 'IP 策略修改为【放行】,设置后该 IP 将恢复正常访问,是否继续?', + changeStrategyPortHelper1: '端口策略修改为【拒绝】,设置后端口将拒绝外部访问,是否继续?', + changeStrategyPortHelper2: '端口策略为【允许】,设置后端口将恢复正常访问,是否继续?', + stop: '禁止', + portFormatError: '请输入正确的端口信息!', + portHelper1: '多个端口,如:8080,8081', + portHelper2: '范围端口,如:8080-8089', strategy: '策略', accept: '允许', drop: '拒绝', @@ -1204,9 +1215,10 @@ const message = { address: '指定 IP', allow: '放行', deny: '屏蔽', - addressHelper1: '支持输入多个 IP ,如 172.16.10.11,172.16.10.99', - addressHelper2: '支持输入 IP 段,如 172.16.10.0/24', - addressHelper3: '支持输入 IP 范围,如 172.16.10.11-172.16.10.99', + addressFormatError: '请输入合法的 ip 地址!', + addressHelper1: '多个 IP 请用 "," 隔开:172.16.10.11,172.16.10.99', + addressHelper2: 'IP 段:172.16.0.0/24', + addressHelper3: 'IP 范围:172.16.10.10-172.16.10.19(暂不支持跨网段范围)', allIP: '所有 IP', portRule: '端口规则', ipRule: 'IP 规则', diff --git a/frontend/src/utils/util.ts b/frontend/src/utils/util.ts index e88c6a0f2..d66935d08 100644 --- a/frontend/src/utils/util.ts +++ b/frontend/src/utils/util.ts @@ -167,6 +167,15 @@ export function checkIp(value: string): boolean { } } +export function checkPort(value: string): boolean { + const reg = /^([0-9]|[1-9]\d{1,3}|[1-5]\d{4}|6[0-5]{2}[0-3][0-5])$/; + if (!reg.test(value) && value !== '') { + return true; + } else { + return false; + } +} + export function getProvider(provider: string): string { switch (provider) { case 'dnsAccount': diff --git a/frontend/src/views/host/firewall/ip/index.vue b/frontend/src/views/host/firewall/ip/index.vue index c59e451dc..7b5d72640 100644 --- a/frontend/src/views/host/firewall/ip/index.vue +++ b/frontend/src/views/host/firewall/ip/index.vue @@ -1,5 +1,5 @@