Initial YakPanel commit
This commit is contained in:
113
class_v2/firewallModelV2/app/appBase.py
Normal file
113
class_v2/firewallModelV2/app/appBase.py
Normal file
@@ -0,0 +1,113 @@
|
||||
# coding: utf-8
|
||||
# -------------------------------------------------------------------
|
||||
# yakpanel
|
||||
# -------------------------------------------------------------------
|
||||
# Copyright (c) 2014-2099 yakpanel(http://www.yakpanel.com) All rights reserved.
|
||||
# -------------------------------------------------------------------
|
||||
# Author: wzz <wzz@yakpanel.com>
|
||||
# -------------------------------------------------------------------
|
||||
|
||||
# ------------------------------
|
||||
# 系统防火墙模型 - 底层基类
|
||||
# ------------------------------
|
||||
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
if "/www/server/panel/class" not in sys.path:
|
||||
sys.path.insert(0, "/www/server/panel/class")
|
||||
import public
|
||||
|
||||
|
||||
class Base(object):
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
# 2024/3/22 下午 3:18 通用返回
|
||||
def _result(self, status: bool, msg: str) -> dict:
|
||||
"""
|
||||
@name 通用返回
|
||||
@author wzz <2024/3/22 下午 3:19>
|
||||
@param status: True/False
|
||||
msg: 提示信息
|
||||
@return dict{"status":True/False,"msg":"提示信息"}
|
||||
"""
|
||||
return {"status": status, "msg": msg}
|
||||
|
||||
# 2024/3/22 下午 4:55 检查是否设置了net.ipv4.ip_forward = 1,没有则设置
|
||||
def check_ip_forward(self) -> dict:
|
||||
"""
|
||||
@name 检查是否设置了net.ipv4.ip_forward = 1,没有则设置
|
||||
@param "data":{"参数名":""} <数据类型> 参数描述
|
||||
@return dict{"status":True/False,"msg":"提示信息"}
|
||||
"""
|
||||
import os
|
||||
if os.path.exists("/etc/default/ufw"):
|
||||
# ufw需要开启转发
|
||||
public.ExecShell(
|
||||
""" grep -q 'DEFAULT_FORWARD_POLICY="DROP"' /etc/default/ufw && sed -i 's/DEFAULT_FORWARD_POLICY="DROP"/DEFAULT_FORWARD_POLICY="ACCEPT"/' /etc/default/ufw && ufw reload """
|
||||
)
|
||||
public.ExecShell(
|
||||
"iptables -t nat -C POSTROUTING -j MASQUERADE 2>/dev/null || sudo iptables -t nat -A POSTROUTING -j MASQUERADE"
|
||||
)
|
||||
stdout, stderr = public.ExecShell("sysctl net.ipv4.ip_forward")
|
||||
if "net.ipv4.ip_forward = 1" not in stdout:
|
||||
# 2024/3/22 下午 4:56 永久设置
|
||||
stdout, stderr = public.ExecShell("echo net.ipv4.ip_forward=1 >> /etc/sysctl.conf")
|
||||
if stderr:
|
||||
return self._result(False, "Setting net.ipv4.ip_forward failed, err: {}".format(stderr))
|
||||
|
||||
stdout, stderr = public.ExecShell("sysctl -p")
|
||||
if stderr:
|
||||
return self._result(False, "Setting net.ipv4.ip_forward failed, err: {}".format(stderr))
|
||||
return self._result(True, "Set net.ipv4.ip_forward successfully")
|
||||
return self._result(True, "net.ipv4.ip_forward has been set")
|
||||
|
||||
# 2024/3/18 上午 11:35 处理192.168.1.100-192.168.1.200这种ip范围
|
||||
# 返回192.168.1.100,192.168.1.101,192.168.1...,192.168.1.200列表
|
||||
def handle_ip_range(self, ip):
|
||||
"""
|
||||
@name 处理192.168.1.100-192.168.1.200这种ip范围的ip列表
|
||||
@author wzz <2024/3/19 下午 4:58>
|
||||
@param "data":{"参数名":""} <数据类型> 参数描述
|
||||
@return dict{"status":True/False,"msg":"提示信息"}
|
||||
"""
|
||||
ip_range = ip.split("-")
|
||||
ip_start = ip_range[0]
|
||||
ip_end = ip_range[1]
|
||||
ip_start = ip_start.split(".")
|
||||
ip_end = ip_end.split(".")
|
||||
ip_start = [int(i) for i in ip_start]
|
||||
ip_end = [int(i) for i in ip_end]
|
||||
ip_list = []
|
||||
for i in range(ip_start[0], ip_end[0] + 1):
|
||||
for j in range(ip_start[1], ip_end[1] + 1):
|
||||
for k in range(ip_start[2], ip_end[2] + 1):
|
||||
for l in range(ip_start[3], ip_end[3] + 1):
|
||||
ip_list.append("{}.{}.{}.{}".format(i, j, k, l))
|
||||
return ip_list
|
||||
|
||||
# 处理70-79这种端口范围
|
||||
# 返回70,71,72,...79列表
|
||||
def handle_port_range(self, port):
|
||||
"""
|
||||
@name 处理70-79这种端口范围的端口列表
|
||||
@param "data":{"参数名":""} <数据类型> 参数描述
|
||||
@return dict{"status":True/False,"msg":"提示信息"}
|
||||
"""
|
||||
port_range = port.split("-")
|
||||
port_start = int(port_range[0])
|
||||
port_end = int(port_range[1])
|
||||
port_list = []
|
||||
for i in range(port_start, port_end + 1):
|
||||
port_list.append(i)
|
||||
return port_list
|
||||
|
||||
def run_command(self, command):
|
||||
try:
|
||||
result = subprocess.run(
|
||||
command, shell=True, check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True
|
||||
)
|
||||
return result.stdout, result.stderr
|
||||
except subprocess.CalledProcessError as e:
|
||||
return e.stdout, e.stderr
|
||||
761
class_v2/firewallModelV2/app/firewalld.py
Normal file
761
class_v2/firewallModelV2/app/firewalld.py
Normal file
@@ -0,0 +1,761 @@
|
||||
#!/www/server/panel/pyenv/bin/python3.7
|
||||
# coding: utf-8
|
||||
# -------------------------------------------------------------------
|
||||
# yakpanel
|
||||
# -------------------------------------------------------------------
|
||||
# Copyright (c) 2014-2099 yakpanel(http://www.yakpanel.com) All rights reserved.
|
||||
# -------------------------------------------------------------------
|
||||
# Author: wzz <wzz@yakpanel.com>
|
||||
# -------------------------------------------------------------------
|
||||
|
||||
# ------------------------------
|
||||
# 系统防火墙模型 - firewalld封装库
|
||||
# ------------------------------
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
if "/www/server/panel/class" not in sys.path:
|
||||
sys.path.insert(0, "/www/server/panel/class")
|
||||
import public
|
||||
from firewallModelV2.app.appBase import Base
|
||||
|
||||
|
||||
class Firewalld(Base):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.cmd_str = self._set_cmd_str()
|
||||
|
||||
def _set_cmd_str(self) -> str:
|
||||
return "firewall-cmd"
|
||||
|
||||
# 2024/3/20 下午 12:00 获取防火墙状态
|
||||
def status(self) -> bool:
|
||||
"""
|
||||
@name 获取防火墙状态
|
||||
@author wzz <2024/3/20 下午 12:01>
|
||||
@param "data":{"参数名":""} <数据类型> 参数描述
|
||||
@return dict{"status":True/False,"msg":"提示信息"}
|
||||
"""
|
||||
try:
|
||||
stdout, stderr = public.ExecShell("systemctl is-active firewalld")
|
||||
if "not running" in stdout:
|
||||
return False
|
||||
return True
|
||||
except Exception as _:
|
||||
return False
|
||||
|
||||
# 2024/3/20 下午 12:00 获取防火墙版本号
|
||||
def version(self) -> str:
|
||||
"""
|
||||
@name 获取防火墙版本号
|
||||
@author wzz <2024/3/20 下午 12:00>
|
||||
@param "data":{"参数名":""} <数据类型> 参数描述
|
||||
@return dict{"status":True/False,"msg":"提示信息"}
|
||||
"""
|
||||
stdout, stderr = self.run_command("firewall-cmd --version")
|
||||
if "FirewallD is not running" in stdout:
|
||||
return "Firewalld has not started, please start it and try again."
|
||||
if stderr:
|
||||
return "Failed to obtain firewalld version, err: {}".format(stderr)
|
||||
return stdout.strip()
|
||||
|
||||
# 2024/3/20 下午 12:08 启动防火墙
|
||||
def start(self) -> dict:
|
||||
"""
|
||||
@name 启动防火墙
|
||||
@author wzz <2024/3/20 下午 12:08>
|
||||
@param "data":{"参数名":""} <数据类型> 参数描述
|
||||
@return dict{"status":True/False,"msg":"提示信息"}
|
||||
"""
|
||||
stdout, stderr = self.run_command("systemctl start firewalld")
|
||||
if stderr:
|
||||
return self._result(False, "Startup failed, err: {}".format(stderr))
|
||||
return self._result(True, "Started successfully")
|
||||
|
||||
# 2024/3/20 下午 12:10 停止防火墙
|
||||
def stop(self) -> dict:
|
||||
"""
|
||||
@name 停止防火墙
|
||||
@author wzz <2024/3/20 下午 12:10>
|
||||
@param "data":{"参数名":""} <数据类型> 参数描述
|
||||
@return dict{"status":True/False,"msg":"提示信息"}
|
||||
"""
|
||||
stdout, stderr = self.run_command("systemctl stop firewalld")
|
||||
if stderr:
|
||||
return self._result(False, "Stop failed, err: {}".format(stderr))
|
||||
return self._result(True, "Stop successfully")
|
||||
|
||||
# 2024/3/20 下午 12:11 重启防火墙
|
||||
def restart(self) -> dict:
|
||||
"""
|
||||
@name 重启防火墙
|
||||
@author wzz <2024/3/20 下午 12:11>
|
||||
@param "data":{"参数名":""} <数据类型> 参数描述
|
||||
@return dict{"status":True/False,"msg":"提示信息"}
|
||||
"""
|
||||
stdout, stderr = self.run_command("systemctl restart firewalld")
|
||||
if stderr:
|
||||
return self._result(False, "The reboot failed, err: {}".format(stderr))
|
||||
return self._result(True, "The reboot was successful")
|
||||
|
||||
# 2024/3/20 下午 12:11 重载防火墙
|
||||
def reload(self) -> dict:
|
||||
"""
|
||||
@name 重载防火墙
|
||||
@author wzz <2024/3/20 下午 12:11>
|
||||
@param "data":{"参数名":""} <数据类型> 参数描述
|
||||
@return dict{"status":True/False,"msg":"提示信息"}
|
||||
"""
|
||||
stdout, stderr = self.run_command("firewall-cmd --reload")
|
||||
if stderr:
|
||||
return self._result(False, "Overload failed, err: {}".format(stderr))
|
||||
return self._result(True, "The overload was successful")
|
||||
|
||||
# 2024/3/20 下午 12:12 获取所有防火墙端口列表
|
||||
def list_port(self) -> list:
|
||||
"""
|
||||
@name 获取所有防火墙端口列表
|
||||
@author wzz <2024/3/20 下午 12:12>
|
||||
@param "data":{"参数名":""} <数据类型> 参数描述
|
||||
@return dict{"status":True/False,"msg":"提示信息"}
|
||||
"""
|
||||
return self.parse_public_zone()["ports"] + self.list_output_port()
|
||||
|
||||
# 2024/3/20 下午 12:12 获取防火墙端口INPUT列表
|
||||
def list_input_port(self) -> list:
|
||||
"""
|
||||
@name 获取防火墙端口列表
|
||||
@author wzz <2024/3/20 下午 12:12>
|
||||
@param "data":{"参数名":""} <数据类型> 参数描述
|
||||
@return dict{"status":True/False,"msg":"提示信息"}
|
||||
"""
|
||||
return self.parse_public_zone()["ports"]
|
||||
|
||||
# 2024/3/22 上午 11:28 获取所有OUTPUT的direct 端口规则
|
||||
def list_output_port(self) -> list:
|
||||
"""
|
||||
@name 获取所有OUTPUT的direct 端口规则
|
||||
@param "data":{"参数名":""} <数据类型> 参数描述
|
||||
@return dict{"status":True/False,"msg":"提示信息"}
|
||||
"""
|
||||
list_direct_rules = self.parse_direct_xml()["ports"]
|
||||
datas = []
|
||||
for rule in list_direct_rules:
|
||||
if rule.get("Chain") == "OUTPUT":
|
||||
datas.append(rule)
|
||||
return datas
|
||||
|
||||
# 2024/3/20 下午 12:21 获取防火墙的rule的ip规则列表
|
||||
def list_address(self) -> list:
|
||||
"""
|
||||
@name 获取防火墙的rule的ip规则列表
|
||||
@author wzz <2024/3/20 下午 2:45>
|
||||
@param "data":{"参数名":""} <数据类型> 参数描述
|
||||
@return dict{"status":True/False,"msg":"提示信息"}
|
||||
"""
|
||||
return self.parse_public_zone()["rules"] + self.parse_trusted_zone()["rules"] + self.list_output_address()
|
||||
|
||||
# 2024/3/20 下午 12:21 获取防火墙的rule input的ip规则列表
|
||||
def list_input_address(self) -> list:
|
||||
"""
|
||||
@name 获取防火墙的rule input的ip规则列表
|
||||
@author wzz <2024/3/20 下午 2:45>
|
||||
@param "data":{"参数名":""} <数据类型> 参数描述
|
||||
@return dict{"status":True/False,"msg":"提示信息"}
|
||||
"""
|
||||
return self.parse_public_zone()["rules"] + self.parse_trusted_zone()["rules"]
|
||||
|
||||
# 2024/3/22 下午 4:07 获取所有OUTPUT的direct ip规则
|
||||
def list_output_address(self) -> list:
|
||||
"""
|
||||
@name 获取所有OUTPUT的direct ip规则
|
||||
@param "data":{"参数名":""} <数据类型> 参数描述
|
||||
@return dict{"status":True/False,"msg":"提示信息"}
|
||||
"""
|
||||
list_direct_rules = self.parse_direct_xml()["rules"]
|
||||
datas = []
|
||||
for rule in list_direct_rules:
|
||||
if rule.get("Chain") == "OUTPUT":
|
||||
datas.append(rule)
|
||||
return datas
|
||||
|
||||
# 2024/3/20 下午 5:34 添加或删除防火墙端口
|
||||
def input_port(self, info: dict, operation: str) -> dict:
|
||||
"""
|
||||
@name 添加或删除防火墙端口
|
||||
@author wzz <2024/3/20 下午 5:34>
|
||||
@param info:{"Port": args[2], "Protocol": args[3]}
|
||||
operation: add/remove
|
||||
@return dict{"status":True/False,"msg":"提示信息"}
|
||||
"""
|
||||
if operation not in ["add", "remove"]:
|
||||
return self._result(False, "Unsupported actions: {}".format(operation))
|
||||
|
||||
# 2024/3/25 下午 6:00 处理tcp/udp双协议的端口
|
||||
if info['Protocol'].find("/") != -1:
|
||||
stdout, stderr = public.ExecShell(
|
||||
"{cmd_str} --zone=public --{operation}-port={port}/{prot} --permanent"
|
||||
.format(
|
||||
cmd_str=self.cmd_str,
|
||||
operation=operation,
|
||||
port=info['Port'],
|
||||
prot="tcp"
|
||||
)
|
||||
)
|
||||
if stderr:
|
||||
return self._result(False, "Failed to set the port, err: {}".format(stderr))
|
||||
stdout, stderr = public.ExecShell(
|
||||
"{cmd_str} --zone=public --{operation}-port={port}/{prot} --permanent"
|
||||
.format(
|
||||
cmd_str=self.cmd_str,
|
||||
operation=operation,
|
||||
port=info['Port'],
|
||||
prot="udp"
|
||||
)
|
||||
)
|
||||
if stderr:
|
||||
return self._result(False, "Failed to set the port, err: {}".format(stderr))
|
||||
else:
|
||||
# 2024/3/25 下午 6:00 处理单协议的端口
|
||||
stdout, stderr = public.ExecShell(
|
||||
"{cmd_str} --zone=public --{operation}-port={port}/{prot} --permanent"
|
||||
.format(
|
||||
cmd_str=self.cmd_str,
|
||||
operation=operation,
|
||||
port=info['Port'],
|
||||
prot=info['Protocol']
|
||||
)
|
||||
)
|
||||
if stderr:
|
||||
return self._result(False, "Failed to set the port, err: {}".format(stderr))
|
||||
return self._result(True, "The inbound port was set successfully")
|
||||
|
||||
# 2024/3/20 下午 6:02 设置output的防火墙端口规则
|
||||
def output_port(self, info: dict, operation: str) -> dict:
|
||||
"""
|
||||
@name 设置output的防火墙端口规则
|
||||
@param "data":{"参数名":""} <数据类型> 参数描述
|
||||
@return dict{"status":True/False,"msg":"提示信息"}
|
||||
"""
|
||||
if operation not in ["add", "remove"]:
|
||||
return self._result(False, "Unsupported actions: {}".format(operation))
|
||||
|
||||
if info['Strategy'] == "accept":
|
||||
info['Strategy'] = "ACCEPT"
|
||||
elif info['Strategy'] == "drop":
|
||||
info['Strategy'] = "DROP"
|
||||
elif info['Strategy'] == "reject":
|
||||
info['Strategy'] = "REJECT"
|
||||
else:
|
||||
return self._result(False, "Unsupported policies: {}".format(info['Strategy']))
|
||||
|
||||
info['Port'] = info['Port'].replace("-", ":")
|
||||
|
||||
if "/" in info['Protocol']:
|
||||
info['Protocol'] = info['Protocol'].split("/")
|
||||
for pp in info['Protocol']:
|
||||
if not pp in ["tcp", "udp"]:
|
||||
return self._result(False,
|
||||
"Failed to set outbound port, err: The protocol is not supported {}".format(pp))
|
||||
|
||||
stdout, stderr = public.ExecShell(
|
||||
"{cmd_str} --permanent --direct --{operation}-rule ipv4 filter OUTPUT {priority} -p {prot} --dport {port} -j {strategy}"
|
||||
.format(
|
||||
cmd_str=self.cmd_str,
|
||||
operation=operation,
|
||||
priority=info['Priority'],
|
||||
prot=pp,
|
||||
port=info['Port'],
|
||||
strategy=info['Strategy']
|
||||
)
|
||||
)
|
||||
if stderr:
|
||||
return self._result(False, "Failed to set outbound port, err: {}".format(stderr))
|
||||
else:
|
||||
stdout, stderr = public.ExecShell(
|
||||
"{cmd_str} --permanent --direct --{operation}-rule ipv4 filter OUTPUT {priority} -p {prot} --dport {port} -j {strategy}"
|
||||
.format(
|
||||
cmd_str=self.cmd_str,
|
||||
operation=operation,
|
||||
priority=info['Priority'],
|
||||
prot=info['Protocol'],
|
||||
port=info['Port'],
|
||||
strategy=info['Strategy']
|
||||
)
|
||||
)
|
||||
|
||||
if stderr:
|
||||
return self._result(False, "Failed to set outbound port, err: {}".format(stderr))
|
||||
|
||||
return self._result(True, "The outbound port was set successfully")
|
||||
|
||||
def set_rich_rule(self, info: dict, operation: str) -> dict:
|
||||
"""
|
||||
@name 添加或删除复杂规则
|
||||
@param "data":{"参数名":""} <数据类型> 参数描述
|
||||
@return dict{"status":True/False,"msg":"提示信息"}
|
||||
"""
|
||||
rule_str = "rule family={}".format(info['Family'].lower())
|
||||
if "Address" in info and info["Address"] != "all":
|
||||
rule_str += " source address={}".format(info['Address'])
|
||||
if info.get("Port"):
|
||||
rule_str += " port port={}".format(info['Port'])
|
||||
if info.get("Protocol"):
|
||||
rule_str += " protocol={}".format(info['Protocol'])
|
||||
rule_str += " {}".format(info['Strategy'])
|
||||
|
||||
stdout, stderr = public.ExecShell(
|
||||
"{} --zone=public --{}-rich-rule='{}' --permanent"
|
||||
.format(self.cmd_str, operation, rule_str))
|
||||
|
||||
if stderr:
|
||||
return self._result(False, "Failed to set the rule:{} , err: {}".format(operation, rule_str, stderr))
|
||||
return self._result(True, "The rule is set successfully".format(operation))
|
||||
|
||||
# 2024/3/22 上午 11:35 添加或删除复杂规则
|
||||
def rich_rules(self, info: dict, operation: str) -> dict:
|
||||
"""
|
||||
@name 添加或删除复杂规则
|
||||
@author wzz <2024/3/22 上午 11:35>
|
||||
@param "data":{"参数名":""} <数据类型> 参数描述
|
||||
@return dict{"status":True/False,"msg":"提示信息"}
|
||||
"""
|
||||
|
||||
if operation not in ["add", "remove"]:
|
||||
return self._result(False, "Unsupported rule actions: {}".format(operation))
|
||||
|
||||
if "Zone" in info and info["Zone"] == "trusted":
|
||||
return self.rich_trusted_rule(info, operation)
|
||||
|
||||
if "Protocol" in info and info["Protocol"] == "all":
|
||||
info["Protocol"] = "tcp/udp"
|
||||
|
||||
if "Protocol" in info and info['Protocol'].find("/") != -1:
|
||||
result_list = []
|
||||
for protocol in info['Protocol'].split("/"):
|
||||
info['Protocol'] = protocol
|
||||
result_list.append(self.set_rich_rule(info, operation))
|
||||
|
||||
return {"status": True, "msg": result_list}
|
||||
else:
|
||||
return self.set_rich_rule(info, operation)
|
||||
|
||||
# 2024/7/23 下午4:36 设置trusted区域的ip规则
|
||||
def rich_trusted_rule(self, info: dict, operation: str) -> dict:
|
||||
"""
|
||||
@name 设置trusted区域的ip规则
|
||||
@param "data":{"参数名":""} <数据类型> 参数描述
|
||||
@return dict{"status":True/False,"msg":"提示信息"}
|
||||
"""
|
||||
try:
|
||||
if operation not in ["add", "remove"]:
|
||||
return self._result(False, "Unsupported actions: {}".format(operation))
|
||||
|
||||
if not info['Strategy'].lower() in ("accept", "drop", "reject"):
|
||||
return self._result(False, "Unsupported policies: {}".format(info['Strategy'].lower()))
|
||||
|
||||
rich_rules = self.cmd_str + " --zone=trusted"
|
||||
if info['Strategy'].lower() == "accept":
|
||||
rich_rules += " --{0}-source='{1}' --permanent".format(operation, info["Address"])
|
||||
else:
|
||||
rich_rules += " --{0}-rich-rule='rule family=\"{1}\" source address=\"{2}\" {3}' --permanent".format(
|
||||
operation,
|
||||
info['Family'],
|
||||
info['Address'],
|
||||
info['Strategy'].lower()
|
||||
)
|
||||
stdout, stderr = public.ExecShell(rich_rules)
|
||||
if "success" not in stdout and stderr:
|
||||
return self._result(False, "The setup failed, err: {}".format(stderr))
|
||||
return self._result(True, "The setup was successful")
|
||||
except:
|
||||
return self._result(False, "The setup failed")
|
||||
|
||||
# 2024/3/24 下午 10:43 设置output的防火墙ip规则
|
||||
def output_rich_rules(self, info: dict, operation: str) -> dict:
|
||||
"""
|
||||
@name 设置output的防火墙ip规则
|
||||
@param "data":{"参数名":""} <数据类型> 参数描述
|
||||
@return dict{"status":True/False,"msg":"提示信息"}
|
||||
"""
|
||||
if operation not in ["add", "remove"]:
|
||||
return self._result(False, "Unsupported actions: {}".format(operation))
|
||||
|
||||
if info['Strategy'] == "accept":
|
||||
info['Strategy'] = "ACCEPT"
|
||||
elif info['Strategy'] == "drop":
|
||||
info['Strategy'] = "DROP"
|
||||
elif info['Strategy'] == "reject":
|
||||
info['Strategy'] = "REJECT"
|
||||
else:
|
||||
return self._result(False, "Unsupported policies: {}".format(info['Strategy']))
|
||||
|
||||
rich_rules = self.cmd_str + " --permanent --direct --{0}-rule ipv4 filter OUTPUT".format(operation)
|
||||
if "Priority" in info:
|
||||
rich_rules += " {}".format(info["Priority"])
|
||||
if "Address" in info:
|
||||
rich_rules += " -d {}".format(info["Address"])
|
||||
if "Protocol" in info:
|
||||
rich_rules += " -p {}".format(info["Protocol"])
|
||||
if "Port" in info:
|
||||
info["Port"] = info["Port"].replace("-", ":")
|
||||
rich_rules += " --dport {}".format(info["Port"])
|
||||
if "Strategy" in info:
|
||||
rich_rules += " -j {}".format(info["Strategy"])
|
||||
|
||||
stdout, stderr = public.ExecShell(rich_rules)
|
||||
if "success" not in stdout and stderr:
|
||||
return self._result(False, "Failed to set an outbound address, err: {}".format(stderr))
|
||||
if "NOT_ENABLED" in stderr:
|
||||
return self._result(False, "The rules don't exist")
|
||||
return self._result(True, "The outbound address was set successfully")
|
||||
|
||||
# 2024/3/22 下午 12:22 解析public区域的防火墙规则
|
||||
def parse_public_zone(self) -> dict:
|
||||
"""
|
||||
@name 解析public区域的防火墙规则
|
||||
@author wzz <2024/3/22 下午 12:22>
|
||||
@param "data":{"参数名":""} <数据类型> 参数描述
|
||||
@return dict{"services": services, "ports": ports, "rules": rules} rules是ip规则
|
||||
"""
|
||||
try:
|
||||
import xml.etree.ElementTree as ET
|
||||
file_path = "/etc/firewalld/zones/public.xml"
|
||||
if not os.path.exists(file_path):
|
||||
return {"services": [], "ports": [], "rules": [], "forward_ports": []}
|
||||
|
||||
services = []
|
||||
ports = []
|
||||
rules = []
|
||||
forward_ports = []
|
||||
|
||||
tree = ET.parse(file_path)
|
||||
root = tree.getroot()
|
||||
|
||||
for elem in root:
|
||||
# 2024/3/22 下午 3:01 服务规则
|
||||
if elem.tag == "service":
|
||||
services.append(elem.attrib['name'])
|
||||
# 2024/3/22 下午 3:01 端口规则
|
||||
elif elem.tag == "port":
|
||||
port = {
|
||||
"Protocol": elem.attrib["protocol"],
|
||||
"Port": elem.attrib["port"],
|
||||
"Strategy": "accept",
|
||||
"Family": "ipv4",
|
||||
"Address": "all",
|
||||
"Chain": "INPUT",
|
||||
}
|
||||
ports.append(port)
|
||||
# 2024/3/22 下午 3:01 复杂的规则配置
|
||||
elif elem.tag == "rule":
|
||||
if not "family" in elem.attrib:
|
||||
continue
|
||||
rule = {"Family": elem.attrib["family"]}
|
||||
for subelem in elem:
|
||||
rule["Strategy"] = "accept"
|
||||
if subelem.tag == "source":
|
||||
if "address" in subelem.attrib:
|
||||
rule["Address"] = subelem.attrib["address"]
|
||||
else:
|
||||
continue
|
||||
rule["Address"] = "all" if rule["Address"] == "Anywhere" else rule["Address"]
|
||||
elif subelem.tag == "port":
|
||||
rule["port"] = {"protocol": subelem.attrib["protocol"], "port": subelem.attrib["port"]}
|
||||
elif subelem.tag == "drop":
|
||||
rule["Strategy"] = "drop"
|
||||
elif subelem.tag == "accept":
|
||||
rule["Strategy"] = "accept"
|
||||
elif subelem.tag == "forward-port":
|
||||
rule["forward-port"] = {
|
||||
"protocol": subelem.attrib["protocol"],
|
||||
"S_Port": subelem.attrib["port"],
|
||||
"T_Address": subelem.attrib["to-addr"],
|
||||
"T_Port": subelem.attrib["to-port"],
|
||||
}
|
||||
|
||||
# 2024/3/22 下午 3:02 如果端口在里面,就放到端口规则列表中,否则就是ip规则
|
||||
if "port" in rule:
|
||||
ports.append({
|
||||
"Protocol": rule["port"]["protocol"] if "protocol" in rule["port"] else "tcp",
|
||||
"Port": rule["port"]["port"],
|
||||
"Strategy": rule["Strategy"] if "Strategy" in rule else "accept",
|
||||
"Family": rule["Family"] if "Family" in rule else "ipv4",
|
||||
"Address": rule["Address"] if "Address" in rule else "all",
|
||||
"Chain": "INPUT",
|
||||
})
|
||||
# 2024/3/25 下午 5:01 处理带源ip的端口转发规则
|
||||
elif "forward-port" in rule:
|
||||
forward_ports.append({
|
||||
"type": "port_forward",
|
||||
"number": len(forward_ports) + 1,
|
||||
"Protocol": rule["forward-port"]["protocol"],
|
||||
"S_Address": rule["Address"],
|
||||
"S_Port": rule["forward-port"]["S_Port"],
|
||||
"T_Address": rule["forward-port"]["T_Address"],
|
||||
"T_Port": rule["forward-port"]["T_Port"],
|
||||
})
|
||||
else:
|
||||
if "Address" not in rule:
|
||||
continue
|
||||
|
||||
rule["Chain"] = "INPUT"
|
||||
rule["Zone"] = "public"
|
||||
rules.append(rule)
|
||||
# 2024/3/25 下午 2:57 端口转发规则
|
||||
elif elem.tag == "forward-port":
|
||||
port = {
|
||||
"type": "port_forward",
|
||||
"number": len(forward_ports) + 1,
|
||||
"Protocol": elem.attrib["protocol"] if "protocol" in elem.attrib else "tcp",
|
||||
"S_Address": "",
|
||||
"S_Port": elem.attrib["port"] if "port" in elem.attrib else "",
|
||||
"T_Address": elem.attrib["to-addr"] if "to-addr" in elem.attrib else "",
|
||||
"T_Port": elem.attrib["to-port"] if "to-port" in elem.attrib else "",
|
||||
}
|
||||
forward_ports.append(port)
|
||||
|
||||
return {"services": services, "ports": ports, "rules": rules, "forward_ports": forward_ports}
|
||||
except Exception as e:
|
||||
return {"services": [], "ports": [], "rules": [], "forward_ports": []}
|
||||
|
||||
# 2024/3/22 下午 2:32 解析direct.xml的防火墙规则
|
||||
def parse_direct_xml(self) -> dict:
|
||||
"""
|
||||
@name 解析direct.xml的防火墙规则
|
||||
@author wzz <2024/3/22 下午 2:32>
|
||||
@param "data":{"参数名":""} <数据类型> 参数描述
|
||||
@return list[dict{}...]
|
||||
"""
|
||||
try:
|
||||
import xml.etree.ElementTree as ET
|
||||
file_path = "/etc/firewalld/direct.xml"
|
||||
if not os.path.exists(file_path):
|
||||
return {"ports": [], "rules": []}
|
||||
|
||||
ports = []
|
||||
rules = []
|
||||
|
||||
tree = ET.parse(file_path)
|
||||
root = tree.getroot()
|
||||
|
||||
for elem in root:
|
||||
if elem.tag == "rule":
|
||||
protocol = "tcp"
|
||||
port = ""
|
||||
strategy = ""
|
||||
address = ""
|
||||
|
||||
elem_t = elem.text.split(" ")
|
||||
# 2024/3/22 下午 4:14 解析 Options 得到端口,策略,地址,协议
|
||||
for i in elem_t:
|
||||
if i == "-p":
|
||||
protocol = elem_t[elem_t.index(i) + 1] # 如果找到匹配项,结果为索引+1的值,-p tcp,值为tcp
|
||||
elif i == "--dport":
|
||||
port = elem_t[elem_t.index(i) + 1]
|
||||
elif i == "-j":
|
||||
strategy = elem_t[elem_t.index(i) + 1]
|
||||
elif i == "-d":
|
||||
address = elem_t[elem_t.index(i) + 1]
|
||||
|
||||
rule = {
|
||||
"Family": elem.attrib["ipv"],
|
||||
"Chain": elem.attrib["chain"],
|
||||
"Strategy": strategy.lower(),
|
||||
"Address": address if address != "" else "all",
|
||||
"Zone": "direct",
|
||||
# "Options": elem.text
|
||||
}
|
||||
|
||||
# 2024/3/22 下午 4:13 如果端口不为空,就是端口规则
|
||||
if port != "":
|
||||
rule["Port"] = port
|
||||
rule["Protocol"] = protocol
|
||||
|
||||
ports.append(rule)
|
||||
# 2024/3/22 下午 4:14 如果端口为空,就是ip规则
|
||||
else:
|
||||
rules.append(rule)
|
||||
|
||||
return {"ports": ports, "rules": rules}
|
||||
except Exception as e:
|
||||
return {"ports": [], "rules": []}
|
||||
|
||||
# 2024/7/17 下午3:29 解析trusted区域的防火墙规则
|
||||
def parse_trusted_zone(self) -> dict:
|
||||
"""
|
||||
@name 解析trusted区域的防火墙规则
|
||||
@param "data":{"参数名":""} <数据类型> 参数描述
|
||||
@return dict{"services": services, "ports": ports, "rules": rules, "forward_ports": forward_ports} rules是ip规则
|
||||
"""
|
||||
try:
|
||||
import xml.etree.ElementTree as ET
|
||||
file_path = "/etc/firewalld/zones/trusted.xml"
|
||||
if not os.path.exists(file_path):
|
||||
return {"services": [], "ports": [], "rules": [], "forward_ports": []}
|
||||
|
||||
services = []
|
||||
ports = []
|
||||
rules = []
|
||||
forward_ports = []
|
||||
|
||||
tree = ET.parse(file_path)
|
||||
root = tree.getroot()
|
||||
|
||||
for elem in root:
|
||||
if elem.tag == "source":
|
||||
rule = {
|
||||
"Family": "ipv4",
|
||||
"Strategy": "accept",
|
||||
"Address": elem.attrib["address"],
|
||||
"Chain": "INPUT",
|
||||
"Zone": "trusted",
|
||||
}
|
||||
rules.append(rule)
|
||||
elif elem.tag == "rule":
|
||||
rule = {
|
||||
"Family": "ipv4",
|
||||
"Chain": "INPUT",
|
||||
"Zone": "trusted",
|
||||
"Strategy": "accept",
|
||||
"Address": "",
|
||||
}
|
||||
for sb in elem:
|
||||
if sb.tag == "source":
|
||||
rule["Address"] = sb.attrib["address"]
|
||||
elif sb.tag == "drop":
|
||||
rule["Strategy"] = "drop"
|
||||
if rule["Address"] != "":
|
||||
rules.append(rule)
|
||||
|
||||
return {"services": services, "ports": ports, "rules": rules, "forward_ports": forward_ports}
|
||||
except Exception as _:
|
||||
return {"services": [], "ports": [], "rules": [], "forward_ports": []}
|
||||
|
||||
# 2024/3/22 下午 4:54 检查是否开启了masquerade,没有则开启
|
||||
def check_masquerade(self) -> dict:
|
||||
"""
|
||||
@name 检查是否开启了masquerade,没有则开启
|
||||
@param "data":{"参数名":""} <数据类型> 参数描述
|
||||
@return dict{"status":True/False,"msg":"提示信息"}
|
||||
"""
|
||||
stdout, stderr = public.ExecShell("firewall-cmd --query-masquerade")
|
||||
if "no" in stdout:
|
||||
stdout, stderr = public.ExecShell("firewall-cmd --add-masquerade")
|
||||
if stderr:
|
||||
return self._result(False, "Failed to open masquerade, err: {}".format(stderr))
|
||||
return self._result(True, "Open masquerade successfully")
|
||||
return self._result(True, "masquerade is already on")
|
||||
|
||||
# 2024/3/22 下午 4:57 设置端口转发
|
||||
def port_forward(self, info: dict, operation: str) -> dict:
|
||||
"""
|
||||
@name 设置端口转发
|
||||
@param "data":{"参数名":""} <数据类型> 参数描述
|
||||
@return dict{"status":True/False,"msg":"提示信息"}
|
||||
"""
|
||||
if operation not in ["add", "remove"]:
|
||||
return self._result(False, "Unsupported actions: {}".format(operation))
|
||||
|
||||
if operation == "add":
|
||||
check_masquerade = self.check_masquerade()
|
||||
if not check_masquerade["status"]:
|
||||
return check_masquerade
|
||||
|
||||
# 2024/3/25 下午 6:07 处理有源地址的情况
|
||||
if "S_Address" in info and info["S_Address"] != "":
|
||||
# 2024/3/25 下午 6:05 处理tcp/udp双协议的情况
|
||||
if info['Protocol'].find("/") != -1:
|
||||
rich_rules = self.cmd_str + " --zone=public"
|
||||
rich_rules += " --{0}-rich-rule='rule family=\"{1}\" source address=\"{2}\" forward-port port=\"{3}\" protocol=\"tcp\" to-port=\"{4}\" to-addr=\"{5}\"' --permanent".format(
|
||||
operation,
|
||||
info['Family'],
|
||||
info['S_Address'],
|
||||
info['S_Port'],
|
||||
info['T_Port'],
|
||||
info['T_Address'],
|
||||
)
|
||||
stdout, stderr = public.ExecShell(rich_rules)
|
||||
if "success" not in stdout and stderr:
|
||||
if "ALREADY_ENABLED" in stderr:
|
||||
return self._result(True, "Port forwarding rules already exist")
|
||||
return self._result(False, "Failed to set port forwarding, err: {}".format(stderr))
|
||||
|
||||
rich_rules = self.cmd_str + " --zone=public"
|
||||
rich_rules += " --{0}-rich-rule='rule family=\"{1}\" source address=\"{2}\" forward-port port=\"{3}\" protocol=\"udp\" to-port=\"{4}\" to-addr=\"{5}\"' --permanent".format(
|
||||
operation,
|
||||
info['Family'],
|
||||
info['S_Address'],
|
||||
info['S_Port'],
|
||||
info['T_Port'],
|
||||
info['T_Address'],
|
||||
)
|
||||
stdout, stderr = public.ExecShell(rich_rules)
|
||||
if "success" not in stdout and stderr:
|
||||
if "ALREADY_ENABLED" in stderr:
|
||||
return self._result(True, "Port forwarding rules already exist")
|
||||
return self._result(False, "Failed to set port forwarding, err: {}".format(stderr))
|
||||
|
||||
# 2024/3/25 下午 6:05 处理单协议的情况
|
||||
else:
|
||||
rich_rules = self.cmd_str + " --zone=public"
|
||||
rich_rules += " --{0}-rich-rule='rule family=\"{1}\" source address=\"{2}\" forward-port port=\"{3}\" protocol=\"{4}\" to-port=\"{5}\" to-addr=\"{6}\"'".format(
|
||||
operation,
|
||||
info['Family'],
|
||||
info['S_Address'],
|
||||
info['S_Port'],
|
||||
info['Protocol'],
|
||||
info['T_Port'],
|
||||
info['T_Address'],
|
||||
)
|
||||
rich_rules += " --permanent"
|
||||
stdout, stderr = public.ExecShell(rich_rules)
|
||||
if "success" not in stdout and stderr:
|
||||
if "ALREADY_ENABLED" in stderr:
|
||||
return self._result(True, "Port forwarding rules already exist")
|
||||
return self._result(False, "Failed to set port forwarding, err: {}".format(stderr))
|
||||
|
||||
# 2024/3/25 下午 6:08 处理没有源地址的情况
|
||||
else:
|
||||
# 2024/3/25 下午 6:05 处理tcp/udp双协议的情况
|
||||
if info['Protocol'].find("/") != -1:
|
||||
stdout, stderr = public.ExecShell(
|
||||
"{} --zone=public --{}-forward-port='port={}:proto={}:toport={}:toaddr={}' --permanent"
|
||||
.format(self.cmd_str, operation, info['S_Port'], "udp", info['T_Port'], info['T_Address'])
|
||||
)
|
||||
if "success" not in stdout and stderr:
|
||||
if "ALREADY_ENABLED" in stderr:
|
||||
return self._result(True, "Port forwarding rules already exist")
|
||||
return self._result(False, "Failed to set port forwarding, err: {}".format(stderr))
|
||||
|
||||
stdout, stderr = public.ExecShell(
|
||||
"{} --zone=public --{}-forward-port='port={}:proto={}:toport={}:toaddr={}' --permanent"
|
||||
.format(self.cmd_str, operation, info['S_Port'], "tcp", info['T_Port'], info['T_Address'])
|
||||
)
|
||||
if "success" not in stdout and stderr:
|
||||
if "ALREADY_ENABLED" in stderr:
|
||||
return self._result(True, "Port forwarding rules already exist")
|
||||
return self._result(False, "Failed to set port forwarding, err: {}".format(stderr))
|
||||
# 2024/3/25 下午 6:09 处理单协议的情况
|
||||
else:
|
||||
stdout, stderr = public.ExecShell(
|
||||
"{} --zone=public --{}-forward-port='port={}:proto={}:toport={}:toaddr={}' --permanent"
|
||||
.format(self.cmd_str, operation, info['S_Port'], info['Protocol'], info['T_Port'],
|
||||
info['T_Address'])
|
||||
)
|
||||
if "success" not in stdout and stderr:
|
||||
if "ALREADY_ENABLED" in stderr:
|
||||
return self._result(True, "Port forwarding rules already exist")
|
||||
return self._result(False, "Failed to set port forwarding, err: {}".format(stderr))
|
||||
|
||||
return self._result(True, "Port forwarding is set successfully")
|
||||
|
||||
# 2024/3/25 下午 2:37 获取所有端口转发规则
|
||||
def list_port_forward(self) -> list:
|
||||
"""
|
||||
@name 获取所有端口转发规则
|
||||
@param "data":{"参数名":""} <数据类型> 参数描述
|
||||
@return list[dict{}...]
|
||||
"""
|
||||
return self.parse_public_zone()["forward_ports"]
|
||||
940
class_v2/firewallModelV2/app/iptables.py
Normal file
940
class_v2/firewallModelV2/app/iptables.py
Normal file
@@ -0,0 +1,940 @@
|
||||
#!/www/server/panel/pyenv/bin/python3.7
|
||||
# coding: utf-8
|
||||
# -------------------------------------------------------------------
|
||||
# yakpanel
|
||||
# -------------------------------------------------------------------
|
||||
# Copyright (c) 2014-2099 yakpanel(http://www.yakpanel.com) All rights reserved.
|
||||
# -------------------------------------------------------------------
|
||||
# Author: wzz <wzz@yakpanel.com>
|
||||
# -------------------------------------------------------------------
|
||||
|
||||
# ------------------------------
|
||||
# 系统防火墙模型 - iptables封装库
|
||||
# ------------------------------
|
||||
|
||||
import re
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
if "/www/server/panel/class" not in sys.path:
|
||||
sys.path.insert(0, "/www/server/panel/class")
|
||||
import public
|
||||
from firewallModelV2.app.appBase import Base
|
||||
|
||||
|
||||
class Iptables(Base):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.cmd_str = self._set_cmd_str()
|
||||
self.protocol = {
|
||||
"6": "tcp",
|
||||
"17": "udp",
|
||||
"0": "all"
|
||||
}
|
||||
|
||||
def _set_cmd_str(self):
|
||||
return "iptables"
|
||||
|
||||
# 2024/3/19 下午 5:00 获取系统防火墙的运行状态
|
||||
def status(self):
|
||||
"""
|
||||
@name 获取系统防火墙的运行状态
|
||||
@author wzz <2024/3/19 下午 5:00>
|
||||
@param "data":{"参数名":""} <数据类型> 参数描述
|
||||
@return dict{"status":True/False,"msg":"提示信息"}
|
||||
"""
|
||||
return "running"
|
||||
|
||||
# 2024/3/19 下午 5:00 获取系统防火墙的版本号
|
||||
def version(self):
|
||||
"""
|
||||
@name 获取系统防火墙的版本号
|
||||
@author wzz <2024/3/19 下午 5:00>
|
||||
@param "data":{"参数名":""} <数据类型> 参数描述
|
||||
@return dict{"status":True/False,"msg":"提示信息"}
|
||||
"""
|
||||
try:
|
||||
result = public.ExecShell("iptables -v 2>&1|awk '{print $2}'|head -1")[0].replace("\n", "")
|
||||
if result == "":
|
||||
return "Unknown version of iptables"
|
||||
return result
|
||||
except Exception as _:
|
||||
return "Unknown version"
|
||||
|
||||
# 2024/3/19 下午 5:00 启动防火墙
|
||||
def start(self):
|
||||
"""
|
||||
@name 启动防火墙
|
||||
@author wzz <2024/3/19 下午 5:00>
|
||||
@param "data":{"参数名":""} <数据类型> 参数描述
|
||||
@return dict{"status":True/False,"msg":"提示信息"}
|
||||
"""
|
||||
return self._result(True, public.lang("The current system firewall is iptables and does not support setting status."))
|
||||
|
||||
# 2024/3/19 下午 5:00 停止防火墙
|
||||
def stop(self):
|
||||
"""
|
||||
@name 停止防火墙
|
||||
@author wzz <2024/3/19 下午 5:00>
|
||||
@param "data":{"参数名":""} <数据类型> 参数描述
|
||||
@return dict{"status":True/False,"msg":"提示信息"}
|
||||
"""
|
||||
return self._result(True, public.lang("The current system firewall is iptables and does not support stopping."))
|
||||
|
||||
# 2024/3/19 下午 4:59 重启防火墙
|
||||
def restart(self):
|
||||
"""
|
||||
@name 重启防火墙
|
||||
@author wzz <2024/3/19 下午 4:59>
|
||||
@param "data":{"参数名":""} <数据类型> 参数描述
|
||||
@return dict{"status":True/False,"msg":"提示信息"}
|
||||
"""
|
||||
return self._result(True, public.lang("The current system firewall is iptables and does not support restarting."))
|
||||
|
||||
# 2024/3/19 下午 4:59 重载防火墙
|
||||
def reload(self):
|
||||
"""
|
||||
@name 重载防火墙
|
||||
@author wzz <2024/3/19 下午 4:59>
|
||||
@param "data":{"参数名":""} <数据类型> 参数描述
|
||||
@return dict{"status":True/False,"msg":"提示信息"}
|
||||
"""
|
||||
return self._result(True, public.lang("The current system firewall is iptables,which does not support reloading. "))
|
||||
|
||||
# 2024/3/19 下午 3:36 检查表名是否合法
|
||||
def check_table_name(self, table_name):
|
||||
"""
|
||||
@name 检查表名是否合法
|
||||
@param "table_name": "filter/nat/mangle/raw/security"
|
||||
@return dict{"status":True/False,"msg":"提示信息"}
|
||||
"""
|
||||
table_names = ['filter', 'nat', 'mangle', 'raw', 'security']
|
||||
if table_name not in table_names:
|
||||
return False
|
||||
return True
|
||||
|
||||
# 2024/3/19 下午 3:55 解析规则列表输出,返回规则列表字典
|
||||
def parse_rules(self, stdout):
|
||||
"""
|
||||
@name 解析规则列表输出,返回规则列表字典
|
||||
@author wzz <2024/3/19 下午 3:53>
|
||||
字段含义:
|
||||
"number": 规则编号,对应规则在链中的顺序。
|
||||
"chain": 规则所属的链的名称。
|
||||
"pkts": 规则匹配的数据包数量。
|
||||
"bytes": 规则匹配的数据包字节数。
|
||||
"target": 规则的目标动作,表示数据包匹配到该规则后应该执行的操作。
|
||||
"prot": 规则适用的协议类型。
|
||||
"opt": 规则的选项,包括规则中使用的匹配条件或特定选项。
|
||||
"in": 规则匹配的数据包的输入接口。
|
||||
"out": 规则匹配的数据包的输出接口。
|
||||
"source": 规则匹配的数据包的源地址。
|
||||
"destination": 规则匹配的数据包的目标地址。
|
||||
"options": 规则的其他选项或说明,通常是规则中的注释或附加信息。
|
||||
|
||||
protocol(port协议头中数字对应的协议类型):
|
||||
0: 表示所有协议
|
||||
1: ICMP(Internet 控制消息协议)
|
||||
6: TCP(传输控制协议)
|
||||
17: UDP(用户数据报协议)
|
||||
@param "data":{"参数名":""} <数据类型> 参数描述
|
||||
@return dict{"status":True/False,"msg":"提示信息"}
|
||||
"""
|
||||
lines = stdout.strip().split('\n')
|
||||
rules = []
|
||||
current_chain = None
|
||||
for line in lines:
|
||||
if line.startswith("Chain"):
|
||||
current_chain = line.split()[1]
|
||||
elif (line.startswith("target") or line.strip() == "" or "source" in line or
|
||||
"Warning: iptables-legacy tables present" in line):
|
||||
# 过滤表头,空行,警告
|
||||
continue
|
||||
else:
|
||||
rule_info = line.split()
|
||||
rule = {
|
||||
"number": rule_info[0],
|
||||
"chain": current_chain,
|
||||
"pkts": rule_info[1],
|
||||
"bytes": rule_info[2],
|
||||
"target": rule_info[3],
|
||||
"prot": rule_info[4],
|
||||
"opt": rule_info[5],
|
||||
"in": rule_info[6],
|
||||
"out": rule_info[7],
|
||||
"source": rule_info[8],
|
||||
"destination": rule_info[9],
|
||||
"options": " ".join(rule_info[10:]).strip()
|
||||
}
|
||||
rules.append(rule)
|
||||
return rules
|
||||
|
||||
# 2024/3/19 下午 3:02 列出指定表的指定链的规则
|
||||
def list_rules(self, parm):
|
||||
"""
|
||||
@name 列出指定表的指定链的规则
|
||||
@author wzz <2024/3/19 下午 3:02>
|
||||
@param
|
||||
@return
|
||||
"""
|
||||
try:
|
||||
if not self.check_table_name(parm['table']):
|
||||
return "Error: Unsupported table name."
|
||||
stdout = subprocess.check_output(
|
||||
[self.cmd_str, '-t', parm['table'], '-L', parm['chain_name'], '-nv', '--line-numbers'],
|
||||
stderr=subprocess.STDOUT, universal_newlines=True
|
||||
)
|
||||
return self.parse_rules(stdout)
|
||||
except Exception as _:
|
||||
return []
|
||||
|
||||
# 2024/4/29 下午12:16 列出iptables中所有INPUT和OUTPUT的端口规则
|
||||
def list_port(self):
|
||||
"""
|
||||
@name 列出iptables中所有INPUT和OUTPUT的端口规则
|
||||
@return [{
|
||||
"Protocol": "tcp",
|
||||
"Port": "8888",
|
||||
"Strategy": "accept",
|
||||
"Family": "ipv4",
|
||||
"Address": "all",
|
||||
"Chain": "INPUT"
|
||||
}]
|
||||
"""
|
||||
try:
|
||||
list_port = self.list_input_port() + self.list_output_port()
|
||||
for i in list_port:
|
||||
i["Strategy"] = i["Strategy"].lower()
|
||||
return list_port
|
||||
except Exception as e:
|
||||
return []
|
||||
|
||||
# 2024/4/29 下午2:39 列出防火墙中所有的INPUT端口规则
|
||||
def list_input_port(self):
|
||||
"""
|
||||
@name 列出防火墙中所有的INPUT端口规则
|
||||
@return [{
|
||||
"Protocol": "tcp",
|
||||
"Port": "8888",
|
||||
"Strategy": "accept",
|
||||
"Family": "ipv4",
|
||||
"Address": "all",
|
||||
"Chain": "INPUT"
|
||||
}]
|
||||
"""
|
||||
try:
|
||||
list_port = self.get_chain_port("INPUT")
|
||||
for i in list_port:
|
||||
i["Strategy"] = i["Strategy"].lower()
|
||||
return list_port
|
||||
except Exception as e:
|
||||
return []
|
||||
|
||||
# 2024/4/29 下午2:39 列出防火墙中所有的OUTPUT端口规则
|
||||
def list_output_port(self):
|
||||
"""
|
||||
@name 列出防火墙中所有的OUTPUT端口规则
|
||||
@return [{
|
||||
"Protocol": "tcp",
|
||||
"Port": "8888",
|
||||
"Strategy": "accept",
|
||||
"Family": "ipv4",
|
||||
"Address": "all",
|
||||
"Chain": "OUTPUT"
|
||||
}]
|
||||
"""
|
||||
try:
|
||||
list_port = self.get_chain_port("OUTPUT")
|
||||
for i in list_port:
|
||||
i["Strategy"] = i["Strategy"].lower()
|
||||
return list_port
|
||||
except Exception as e:
|
||||
return []
|
||||
|
||||
# 2024/4/29 下午3:28 根据链来获取端口规则,暂时只支持INPUT/OUTPUT链
|
||||
def get_chain_port(self, chain):
|
||||
"""
|
||||
@name 根据链来获取端口规则
|
||||
@author wzz <2024/4/29 下午3:29>
|
||||
@param chain = INPUT/OUTPUT
|
||||
@return [{
|
||||
"Protocol": "tcp",
|
||||
"Port": "8888",
|
||||
"Strategy": "accept",
|
||||
"Family": "ipv4",
|
||||
"Address": "all",
|
||||
"Chain": "OUTPUT"
|
||||
}]
|
||||
"""
|
||||
if chain not in ["INPUT", "OUTPUT"]:
|
||||
return []
|
||||
|
||||
try:
|
||||
stdout = self.get_chain_data(chain)
|
||||
if stdout == "":
|
||||
return []
|
||||
|
||||
lines = stdout.strip().split('\n')
|
||||
rules = []
|
||||
for line in lines:
|
||||
if line.startswith("Chain"):
|
||||
continue
|
||||
if not "dpt:" in line and not "multiport sports" in line:
|
||||
continue
|
||||
rule_info = line.split()
|
||||
if rule_info[0] == "num":
|
||||
continue
|
||||
if not rule_info[3] in ["ACCEPT", "DROP", "REJECT"]:
|
||||
continue
|
||||
if not rule_info[4] in self.protocol:
|
||||
continue
|
||||
if not "dpt" in rule_info[-1] and not "-" in rule_info[-1] and not ":" in rule_info[-1]:
|
||||
continue
|
||||
|
||||
if ":" in rule_info[-1] and not "dpt" in rule_info[-1]:
|
||||
Port = rule_info[-1]
|
||||
elif "-" in rule_info[-1]:
|
||||
Port = rule_info[-5].split(":")[1]
|
||||
else:
|
||||
Port = rule_info[-1].split(":")[1]
|
||||
|
||||
if "source IP range" in line and "multiport sports" in line:
|
||||
Address = rule_info[-4]
|
||||
elif not "0.0.0.0/0" in rule_info[8]:
|
||||
Address = rule_info[8]
|
||||
elif "-" in rule_info[-1]:
|
||||
Address = rule_info[-1]
|
||||
else:
|
||||
Address = "all"
|
||||
|
||||
rule = {
|
||||
"Protocol": self.protocol[rule_info[4]],
|
||||
"Port": Port,
|
||||
"Strategy": rule_info[3],
|
||||
"Family": "ipv4",
|
||||
"Address": Address,
|
||||
"Chain": chain,
|
||||
}
|
||||
rules.append(rule)
|
||||
|
||||
return rules
|
||||
except Exception as e:
|
||||
return []
|
||||
|
||||
# 2024/4/29 下午3:28 根据链来获取IP规则,暂时只支持INPUT/OUTPUT链
|
||||
def get_chain_ip(self, chain):
|
||||
"""
|
||||
@name 根据链来获取端口规则
|
||||
@author wzz <2024/4/29 下午3:29>
|
||||
@param chain = INPUT/OUTPUT
|
||||
@return [
|
||||
{
|
||||
"Family": "ipv4",
|
||||
"Address": "192.168.1.190",
|
||||
"Strategy": "accept",
|
||||
"Chain": "INPUT"
|
||||
}
|
||||
]
|
||||
"""
|
||||
if chain not in ["INPUT", "OUTPUT"]:
|
||||
return []
|
||||
|
||||
try:
|
||||
stdout = self.get_chain_data(chain)
|
||||
if stdout == "":
|
||||
return []
|
||||
|
||||
lines = stdout.strip().split('\n')
|
||||
rules = []
|
||||
for line in lines:
|
||||
if line.startswith("Chain"):
|
||||
continue
|
||||
if "dpt:" in line or "multiport sports" in line:
|
||||
continue
|
||||
rule_info = line.split()
|
||||
if rule_info[0] == "num":
|
||||
continue
|
||||
if not rule_info[3] in ["ACCEPT", "DROP", "REJECT"]:
|
||||
continue
|
||||
if not rule_info[4] in self.protocol:
|
||||
continue
|
||||
|
||||
Address = ""
|
||||
if not "0.0.0.0/0" in rule_info[8]:
|
||||
Address = rule_info[8]
|
||||
elif "0.0.0.0/0" in rule_info[8] and "-" in rule_info[-1]:
|
||||
Address = rule_info[-1]
|
||||
|
||||
if Address == "":
|
||||
continue
|
||||
|
||||
rule = {
|
||||
"Family": "ipv4",
|
||||
"Address": Address,
|
||||
"Strategy": rule_info[3],
|
||||
"Chain": chain,
|
||||
}
|
||||
rules.append(rule)
|
||||
|
||||
return rules
|
||||
except Exception as _:
|
||||
return []
|
||||
|
||||
# 2024/4/29 下午4:01 获取指定链的数据
|
||||
def get_chain_data(self, chain):
|
||||
"""
|
||||
@name 获取指定链的数据
|
||||
@author wzz <2024/4/29 下午4:01>
|
||||
@param "data":{"参数名":""} <数据类型> 参数描述
|
||||
@return dict{"status":True/False,"msg":"提示信息"}
|
||||
"""
|
||||
try:
|
||||
cmd = "{} -t filter -L {} -nv --line-numbers".format(self.cmd_str, chain)
|
||||
stdout, stderr = public.ExecShell(cmd)
|
||||
return stdout
|
||||
except Exception as _:
|
||||
return ""
|
||||
|
||||
# 2024/4/29 下午2:46 列出防火墙中所有的INPUT和OUTPUT的ip规则
|
||||
def list_address(self):
|
||||
"""
|
||||
@name 列出防火墙中所有的ip规则
|
||||
@author wzz <2024/4/29 下午2:47>
|
||||
@param "data":{"参数名":""} <数据类型> 参数描述
|
||||
@return
|
||||
"""
|
||||
try:
|
||||
list_address = self.get_chain_ip("INPUT") + self.get_chain_ip("OUTPUT")
|
||||
for i in list_address:
|
||||
i["Strategy"] = i["Strategy"].lower()
|
||||
return list_address
|
||||
except Exception as _:
|
||||
return []
|
||||
|
||||
# 2024/4/29 下午2:48 列出防火墙中所有input的ip规则
|
||||
def list_input_address(self):
|
||||
"""
|
||||
@name 列出防火墙中所有input的ip规则
|
||||
@author wzz <2024/4/29 下午2:48>
|
||||
@param "data":{"参数名":""} <数据类型> 参数描述
|
||||
@return dict{"status":True/False,"msg":"提示信息"}
|
||||
"""
|
||||
try:
|
||||
list_address = self.get_chain_ip("INPUT")
|
||||
for i in list_address:
|
||||
i["Strategy"] = i["Strategy"].lower()
|
||||
return list_address
|
||||
except Exception as _:
|
||||
return []
|
||||
|
||||
# 2024/4/29 下午2:49 列出防火墙中所有output的ip规则
|
||||
def list_output_address(self):
|
||||
"""
|
||||
@name 列出防火墙中所有output的ip规则
|
||||
@author wzz <2024/4/29 下午2:49>
|
||||
@param "data":{"参数名":""} <数据类型> 参数描述
|
||||
@return dict{"status":True/False,"msg":"提示信息"}
|
||||
"""
|
||||
try:
|
||||
list_address = self.get_chain_ip("OUTPUT")
|
||||
for i in list_address:
|
||||
i["Strategy"] = i["Strategy"].lower()
|
||||
return list_address
|
||||
except Exception as _:
|
||||
return []
|
||||
|
||||
# 2024/4/29 下午2:49 添加INPUT端口规则
|
||||
def input_port(self, info, operation):
|
||||
"""
|
||||
@name 添加INPUT端口规则
|
||||
@author wzz <2024/4/29 下午2:50>
|
||||
@param "data":{"参数名":""} <数据类型> 参数描述
|
||||
@return dict{"status":True/False,"msg":"提示信息"}
|
||||
"""
|
||||
try:
|
||||
return self.set_chain_port(info, operation, "INPUT")
|
||||
except Exception as e:
|
||||
return self._result(False, public.lang("Failed to set a port rule:{}", str(e)))
|
||||
|
||||
# 2024/4/29 下午2:50 设置output端口策略
|
||||
def output_port(self, info, operation):
|
||||
"""
|
||||
@name 设置output端口策略
|
||||
@author wzz <2024/4/29 下午2:50>
|
||||
@param "data":{"参数名":""} <数据类型> 参数描述
|
||||
@return dict{"status":True/False,"msg":"提示信息"}
|
||||
"""
|
||||
try:
|
||||
return self.set_chain_port(info, operation, "OUTPUT")
|
||||
except Exception as e:
|
||||
return self._result(False, public.lang("Failed to set a port rule:{}", str(e)))
|
||||
|
||||
# 2024/4/29 下午4:49 添加/删除指定链的端口规则
|
||||
def set_chain_port(self, info, operation, chain):
|
||||
"""
|
||||
@name 添加/删除指定链的端口规则
|
||||
@author wzz <2024/4/29 下午4:49>
|
||||
@param "data":{"参数名":""} <数据类型> 参数描述
|
||||
@return dict{"status":True/False,"msg":"提示信息"}
|
||||
"""
|
||||
try:
|
||||
if not chain in ["INPUT", "OUTPUT"]:
|
||||
return self._result(False, public.lang("Failed to set a port rule:{}", "Unsupported chain types"))
|
||||
|
||||
if info['Protocol'] not in ["tcp", "udp"]:
|
||||
return self._result(False, public.lang("Failed to set a port rule:{}", "Unsupported protocol types"))
|
||||
if info["Strategy"] == "accept":
|
||||
info["Strategy"] = "ACCEPT"
|
||||
elif info["Strategy"] == "drop":
|
||||
info["Strategy"] = "DROP"
|
||||
elif info["Strategy"] == "reject":
|
||||
info["Strategy"] = "REJECT"
|
||||
else:
|
||||
return self._result(False, public.lang("Failed to set a port rule:{}",
|
||||
"The type of policy that is not supported"))
|
||||
|
||||
if operation == "add":
|
||||
operation = "-I"
|
||||
elif operation == "remove":
|
||||
operation = "-D"
|
||||
|
||||
rule = "{} -t filter {} {} -p {} --dport {} -j {}".format(
|
||||
self.cmd_str,
|
||||
operation,
|
||||
chain,
|
||||
info['Protocol'],
|
||||
info['Port'],
|
||||
info['Strategy']
|
||||
)
|
||||
stdout, stderr = public.ExecShell(rule)
|
||||
if stderr and "setlocale: LC_ALL: cannot change locale (en_US.UTF-8)" not in stderr:
|
||||
return self._result(False, public.lang("Failed to set a port rule:{}", stderr))
|
||||
return self._result(True, public.lang("The port rule was successfully configured"))
|
||||
except Exception as e:
|
||||
return self._result(False, public.lang("Failed to set a port rule:{}", str(e)))
|
||||
|
||||
# 2024/4/29 下午5:01 添加/删除指定链的复杂端口规则
|
||||
def set_chain_rich_port(self, info, operation, chain):
|
||||
"""
|
||||
@name 添加/删除指定链的复杂端口规则
|
||||
@param "data":{"参数名":""} <数据类型> 参数描述
|
||||
@return dict{"status":True/False,"msg":"提示信息"}
|
||||
"""
|
||||
try:
|
||||
if not chain in ["INPUT", "OUTPUT"]:
|
||||
return self._result(False, public.lang("Failed to set a port rule:{}", "Unsupported chain types"))
|
||||
|
||||
if "Address" in info and info["Address"] == "":
|
||||
info["Address"] = "all"
|
||||
if "Address" in info and public.is_ipv6(info['Address']):
|
||||
return self._result(False, public.lang("Failed to set a port rule:{}",
|
||||
"IPV 6 addresses that are not supported"))
|
||||
|
||||
if info['Protocol'] not in ["tcp", "udp"]:
|
||||
return self._result(False, public.lang("Failed to set a port rule:{}", "Unsupported protocol types"))
|
||||
if info["Strategy"] == "accept":
|
||||
info["Strategy"] = "ACCEPT"
|
||||
elif info["Strategy"] == "drop":
|
||||
info["Strategy"] = "DROP"
|
||||
elif info["Strategy"] == "reject":
|
||||
info["Strategy"] = "REJECT"
|
||||
else:
|
||||
return self._result(False, public.lang("Failed to set a port rule:{}",
|
||||
"The type of policy that is not supported"))
|
||||
|
||||
if operation == "add":
|
||||
operation = "-I"
|
||||
elif operation == "remove":
|
||||
operation = "-D"
|
||||
|
||||
info['Port'] = info['Port'].replace("-", ":")
|
||||
info["Address"] = info["Address"].replace(":", "-")
|
||||
if ":" in info['Port'] or "-" in info['Port']:
|
||||
if ":" in info["Address"] or "-" in info["Address"]:
|
||||
# iptables -t filter -I INPUT -m iprange --src-range 192.168.1.100-192.168.1.200 -p tcp -m multiport --sports 8000:9000 -j ACCEPT
|
||||
rule = "{} -t filter {} {} -m iprange --src-range {} -p {} -m multiport --sports {} -j {}".format(
|
||||
self.cmd_str,
|
||||
operation,
|
||||
chain,
|
||||
info['Address'],
|
||||
info['Protocol'],
|
||||
info['Port'],
|
||||
info['Strategy']
|
||||
)
|
||||
else:
|
||||
# iptables -t filter -I INPUT -p tcp -m multiport --sports 8000:9000 -s 192.168.1.100 -j ACCEPT
|
||||
rule = "{} -t filter {} {} -p {} -m multiport --sports {} -s {} -j {}".format(
|
||||
self.cmd_str,
|
||||
operation,
|
||||
chain,
|
||||
info['Protocol'],
|
||||
info['Port'],
|
||||
info['Address'],
|
||||
info['Strategy']
|
||||
)
|
||||
else:
|
||||
if ":" in info["Address"] or "-" in info["Address"]:
|
||||
# iptables -t filter -I OUTPUT -p tcp --dport 22333 -m iprange --src-range 192.168.1.100-192.168.1.200 -j ACCEPT
|
||||
rule = "{} -t filter {} {} -p {} --dport {} -m iprange --src-range {} -j {}".format(
|
||||
self.cmd_str,
|
||||
operation,
|
||||
chain,
|
||||
info['Protocol'],
|
||||
info['Port'],
|
||||
info['Address'],
|
||||
info['Strategy']
|
||||
)
|
||||
else:
|
||||
# iptables -t filter -I OUTPUT -p tcp --dport 22333 -s 192.168.1.0/24 -j ACCEPT
|
||||
rule = "{} -t filter {} {} -p {} --dport {} -s {} -j {}".format(
|
||||
self.cmd_str,
|
||||
operation,
|
||||
chain,
|
||||
info['Protocol'],
|
||||
info['Port'],
|
||||
info['Address'],
|
||||
info['Strategy']
|
||||
)
|
||||
|
||||
stdout, stderr = public.ExecShell(rule)
|
||||
if stderr and "setlocale: LC_ALL: cannot change locale (en_US.UTF-8)" not in stderr:
|
||||
return self._result(False, public.lang("Failed to set a port rule:{}", stderr))
|
||||
return self._result(True, public.lang("The port rule was successfully configured"))
|
||||
except Exception as e:
|
||||
return self._result(False, public.lang("Failed to set a port rule:{}", str(e)))
|
||||
|
||||
# 2024/4/29 下午5:01 添加/删除指定链的复杂ip规则
|
||||
def set_chain_rich_ip(self, info, operation, chain):
|
||||
"""
|
||||
@name 添加/删除指定链的复杂ip规则
|
||||
@param "data":{"参数名":""} <数据类型> 参数描述
|
||||
@return dict{"status":True/False,"msg":"提示信息"}
|
||||
"""
|
||||
try:
|
||||
if not chain in ["INPUT", "OUTPUT"]:
|
||||
return self._result(False, public.lang("Failed to set the rule:{}", "Unsupported chain types"))
|
||||
|
||||
if "Address" in info and info["Address"] == "":
|
||||
info["Address"] = "all"
|
||||
if "Address" in info and public.is_ipv6(info['Address']):
|
||||
return self._result(False, public.lang("Failed to set the rule:{}", "IPV 6 addresses that are not supported"))
|
||||
|
||||
if info["Strategy"] == "accept":
|
||||
info["Strategy"] = "ACCEPT"
|
||||
elif info["Strategy"] == "drop":
|
||||
info["Strategy"] = "DROP"
|
||||
elif info["Strategy"] == "reject":
|
||||
info["Strategy"] = "REJECT"
|
||||
else:
|
||||
return self._result(False, public.lang("Failed to set the rule:{}",
|
||||
"The type of policy that is not supported"))
|
||||
|
||||
if operation == "add":
|
||||
operation = "-I"
|
||||
elif operation == "remove":
|
||||
operation = "-D"
|
||||
|
||||
if ":" in info["Address"] or "-" in info["Address"]:
|
||||
# iptables -t filter -I INPUT -m iprange --src-range 192.168.1.100-192.168.1.200 -j ACCEPT
|
||||
rule = "{} -t filter {} {} -m iprange --src-range {} -j {}".format(
|
||||
self.cmd_str,
|
||||
operation,
|
||||
chain,
|
||||
info['Address'],
|
||||
info['Strategy']
|
||||
)
|
||||
else:
|
||||
# iptables -t filter -I INPUT -s 192.168.1.100 -j ACCEPT
|
||||
rule = "{} -t filter {} {} -s {} -j {}".format(
|
||||
self.cmd_str,
|
||||
operation,
|
||||
chain,
|
||||
info['Address'],
|
||||
info['Strategy']
|
||||
)
|
||||
|
||||
stdout, stderr = public.ExecShell(rule)
|
||||
if stderr and "setlocale: LC_ALL: cannot change locale (en_US.UTF-8)" not in stderr:
|
||||
return self._result(False, public.lang("Failed to set the rule:{}", stderr))
|
||||
return self._result(True, public.lang("The rule is set successfully"))
|
||||
except Exception as e:
|
||||
return self._result(False, public.lang("Failed to set the rule:{}", str(e)))
|
||||
|
||||
# 2024/4/29 下午2:51 INPUT复杂一些的规则管理
|
||||
def rich_rules(self, info, operation):
|
||||
"""
|
||||
@name
|
||||
@author wzz <2024/4/29 下午2:51>
|
||||
@param "data":{"参数名":""} <数据类型> 参数描述
|
||||
@return dict{"status":True/False,"msg":"提示信息"}
|
||||
"""
|
||||
try:
|
||||
if "Priority" in info and not "Port" in info:
|
||||
return self.set_chain_rich_ip(info, operation, "INPUT")
|
||||
else:
|
||||
return self.set_chain_rich_port(info, operation, "INPUT")
|
||||
except Exception as e:
|
||||
return self._result(False, public.lang("Failed to set a port rule:{}", str(e)))
|
||||
|
||||
# 2024/4/29 下午2:52 OUTPUT复杂一些的规则管理
|
||||
def output_rich_rules(self, info, operation):
|
||||
"""
|
||||
@name OUTPUT复杂一些的规则管理
|
||||
@param "data":{"参数名":""} <数据类型> 参数描述
|
||||
@return dict{"status":True/False,"msg":"提示信息"}
|
||||
"""
|
||||
try:
|
||||
if "Priority" in info and not "Port" in info:
|
||||
return self.set_chain_rich_ip(info, operation, "OUTPUT")
|
||||
else:
|
||||
return self.set_chain_rich_port(info, operation, "OUTPUT")
|
||||
except Exception as e:
|
||||
return self._result(False, public.lang("Failed to set a port rule:{}", str(e)))
|
||||
|
||||
# 2024/3/19 下午 3:03 清空指定链中的所有规则
|
||||
def flush_chain(self, chain_name):
|
||||
"""
|
||||
@name 清空指定链中的所有规则
|
||||
@author wzz <2024/3/19 下午 3:03>
|
||||
@param "data":{"参数名":""} <数据类型> 参数描述
|
||||
@return dict{"status":True/False,"msg":"提示信息"}
|
||||
"""
|
||||
try:
|
||||
subprocess.check_output(
|
||||
[self.cmd_str, '-F', chain_name], stderr=subprocess.STDOUT, universal_newlines=True
|
||||
)
|
||||
return chain_name + " chain flushed successfully."
|
||||
except Exception as _:
|
||||
return "Failed to flush " + chain_name + " chain."
|
||||
|
||||
# 2024/3/19 下午 3:03 获取当前系统中可用的链的名称列表
|
||||
def get_chain_names(self, parm):
|
||||
"""
|
||||
@name 获取当前系统中可用的链的名称列表
|
||||
@author wzz <2024/3/19 下午 3:03>
|
||||
@param "data":{"参数名":""} <数据类型> 参数描述
|
||||
@return dict{"status":True/False,"msg":"提示信息"}
|
||||
"""
|
||||
try:
|
||||
if not self.check_table_name(parm['table']):
|
||||
return "Error: Unsupported table name."
|
||||
stdout = subprocess.check_output(
|
||||
[self.cmd_str, '-t', parm['table'], '-L'], stderr=subprocess.STDOUT, universal_newlines=True
|
||||
)
|
||||
chain_names = re.findall(r"Chain\s([A-Z]+)", stdout)
|
||||
return chain_names
|
||||
except Exception as e:
|
||||
return []
|
||||
|
||||
# 2024/3/19 下午 3:17 构造端口转发规则,然后调用insert_rule方法插入规则
|
||||
def port_forward(self, info, operation):
|
||||
"""
|
||||
@name 构造端口转发规则,然后调用insert_rule方法插入规则
|
||||
@param "info": {
|
||||
"Protocol": "tcp/udp",
|
||||
"S_Port": "80",
|
||||
"T_Address": "0.0.0.0/0",
|
||||
"T_Port": "8080"
|
||||
}
|
||||
@param "operation": "add" or "remove"
|
||||
@return dict{"status":True/False,"msg":"提示信息"}
|
||||
"""
|
||||
try:
|
||||
rule = " -p {}".format(info['Protocol'])
|
||||
|
||||
if "S_Address" in info and info['S_Address'] != "":
|
||||
rule += " -s {}".format(info['S_Address'])
|
||||
|
||||
rule += " --dport {0} -j DNAT --to-destination {1}:{2}".format(
|
||||
info['S_Port'],
|
||||
info['T_Address'],
|
||||
info['T_Port'],
|
||||
)
|
||||
|
||||
parm = {
|
||||
"table": "nat",
|
||||
"chain_name": "PREROUTING",
|
||||
"rule": rule
|
||||
}
|
||||
if operation not in ["add", "remove"]:
|
||||
return "Please enter the correct type of operation. (add/remove)"
|
||||
|
||||
if operation == "add":
|
||||
parm['type'] = "-I"
|
||||
elif operation == "remove":
|
||||
parm['type'] = "-D"
|
||||
return self.rule_manage(parm)
|
||||
except Exception as e:
|
||||
return self._result(False, public.lang("Failed to set a port forwarding rule:{}", str(e)))
|
||||
|
||||
# 2024/3/19 下午 3:03 在指定链中管理规则
|
||||
def rule_manage(self, parm):
|
||||
"""
|
||||
@name 在指定链中管理规则
|
||||
@author wzz <2024/3/19 下午 3:03>
|
||||
@param "data":{"参数名":""} <数据类型> 参数描述
|
||||
@return dict{"status":True/False,"msg":"提示信息"}
|
||||
"""
|
||||
try:
|
||||
if not self.check_table_name(parm['table']):
|
||||
return self._result(False, public.lang("Unsupported table names: {}", parm['table']))
|
||||
|
||||
rule = "{} -t {} {} {} {}".format(
|
||||
self.cmd_str, parm['table'], parm['type'], parm['chain_name'], parm['rule']
|
||||
)
|
||||
stdout, stderr = public.ExecShell(rule)
|
||||
if stderr and "setlocale: LC_ALL: cannot change locale (en_US.UTF-8)" not in stderr:
|
||||
return self._result(False, public.lang("The rule setup failed:{}", stderr))
|
||||
|
||||
return self._result(True, public.lang("The rule is set successfully"))
|
||||
except Exception as e:
|
||||
return self._result(False, public.lang("The rule setup failed: {}", str(e)))
|
||||
|
||||
# 2024/4/29 下午5:55 获取所有端口转发列表
|
||||
def list_port_forward(self):
|
||||
"""
|
||||
@name 获取所有端口转发列表
|
||||
@author wzz <2024/4/29 下午5:55>
|
||||
@param "data":{"参数名":""} <数据类型> 参数描述
|
||||
@return dict{"status":True/False,"msg":"提示信息"}
|
||||
"""
|
||||
return self.get_nat_prerouting_rules()
|
||||
|
||||
# 2024/3/19 下午 4:00 调用list_rules获取所有nat表中的PREROUTING链的规则(端口转发规则),并分析成字典返回
|
||||
def get_nat_prerouting_rules(self):
|
||||
"""
|
||||
@name 调用list_rules获取所有nat表中的PREROUTING链的规则(端口转发规则),并分析成字典返回
|
||||
@return dict{"status":True/False,"msg":"提示信息"}
|
||||
"""
|
||||
try:
|
||||
port_forward_rules = self.list_rules({"table": "nat", "chain_name": "PREROUTING"})
|
||||
rules = []
|
||||
for rule in port_forward_rules:
|
||||
if rule["target"] != "DNAT": continue
|
||||
options = rule["options"].split(' ')
|
||||
|
||||
protocol = "TCP"
|
||||
if rule["prot"] == "6" or rule["prot"] == "tcp":
|
||||
protocol = "TCP"
|
||||
elif rule["prot"] == "17" or rule["prot"] == "udp":
|
||||
protocol = "UDP"
|
||||
elif rule["prot"] == "0" or rule["prot"] == "all":
|
||||
protocol = "TCP/UDP"
|
||||
rules.append({
|
||||
"type": "port_forward",
|
||||
"number": rule["number"],
|
||||
"S_Address": rule["source"],
|
||||
"S_Port": options[1].split("dpt:")[1],
|
||||
"T_Address": options[2].split("to:")[1].split(":")[0],
|
||||
"T_Port": options[2].split("to:")[1].split(":")[1],
|
||||
"Protocol": protocol.lower()
|
||||
})
|
||||
return rules
|
||||
except Exception as _:
|
||||
return []
|
||||
|
||||
# 2024/4/29 下午2:43 格式化输出json
|
||||
def format_json(self, data):
|
||||
"""
|
||||
@name 格式化输出json
|
||||
@param "data": json数据
|
||||
@return json字符串
|
||||
"""
|
||||
import json
|
||||
from pygments import highlight, lexers, formatters
|
||||
|
||||
formatted_json = json.dumps(data, indent=3)
|
||||
colorful_json = highlight(formatted_json.encode('utf-8'), lexers.JsonLexer(),
|
||||
formatters.TerminalFormatter())
|
||||
return colorful_json
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
args = sys.argv
|
||||
firewall = Iptables()
|
||||
if len(args) < 2:
|
||||
print("Welcome to the iptables command-line interface!")
|
||||
print()
|
||||
print("Available options:")
|
||||
print("list_rules: list_rules <table> <chain_name>")
|
||||
print("flush_chain: flush_chain <table>")
|
||||
print("get_chain_names: get_chain_names <table>")
|
||||
print("port_forward: port_forward <S_Address> <S_Port> <T_Address> <T_Port> <Protocol> <Operation>")
|
||||
print("get_nat_prerouting_rules: get_nat_prerouting_rules")
|
||||
print()
|
||||
sys.exit(1)
|
||||
if args[1] == "list_rules":
|
||||
# firewall.list_rules({"table": args[2], "chain_name": args[3]})
|
||||
print(firewall.list_rules({"table": args[2], "chain_name": args[3]}))
|
||||
elif args[1] == "flush_chain":
|
||||
print(firewall.flush_chain(args[2]))
|
||||
elif args[1] == "get_chain_names":
|
||||
table = args[2] if len(args) > 2 else "filter"
|
||||
print(firewall.get_chain_names({"table": table}))
|
||||
elif args[1] == "port_forward":
|
||||
if len(args) < 8:
|
||||
print("传参使用方法: port_forward <S_Address> <S_Port> <T_Address> <T_Port> <Protocol> <Operation>")
|
||||
sys.exit(1)
|
||||
|
||||
info = {
|
||||
"S_Address": args[2],
|
||||
"S_Port": args[3],
|
||||
"T_Address": args[4],
|
||||
"T_Port": args[5],
|
||||
"Protocol": args[6]
|
||||
}
|
||||
print(firewall.port_forward(info, args[7]))
|
||||
elif args[1] == "get_nat_prerouting_rules":
|
||||
import json
|
||||
from pygments import highlight, lexers, formatters
|
||||
|
||||
formatted_json = json.dumps(firewall.get_nat_prerouting_rules(), indent=3)
|
||||
colorful_json = highlight(formatted_json.encode('utf-8'), lexers.JsonLexer(),
|
||||
formatters.TerminalFormatter())
|
||||
print(colorful_json)
|
||||
# print(firewall.get_nat_prerouting_rules())
|
||||
elif args[1] == "list_port":
|
||||
print(firewall.format_json(firewall.list_port()))
|
||||
elif args[1] == "list_input_port":
|
||||
print(firewall.format_json(firewall.list_input_port()))
|
||||
elif args[1] == "list_output_port":
|
||||
print(firewall.format_json(firewall.list_output_port()))
|
||||
elif args[1] == "list_address":
|
||||
print(firewall.format_json(firewall.list_address()))
|
||||
elif args[1] == "list_input_address":
|
||||
print(firewall.format_json(firewall.list_input_address()))
|
||||
elif args[1] == "list_output_address":
|
||||
print(firewall.format_json(firewall.list_output_address()))
|
||||
elif args[1] == "input_port":
|
||||
info = {
|
||||
"Protocol": args[2],
|
||||
"Port": args[3],
|
||||
"Strategy": args[4]
|
||||
}
|
||||
print(firewall.input_port(info, args[5]))
|
||||
elif args[1] == "output_port":
|
||||
info = {
|
||||
"Protocol": args[2],
|
||||
"Port": args[3],
|
||||
"Strategy": args[4]
|
||||
}
|
||||
print(firewall.output_port(info, args[5]))
|
||||
elif args[1] == "rich_rules":
|
||||
info = {
|
||||
"Protocol": args[2],
|
||||
"Port": args[3],
|
||||
"Address": args[4],
|
||||
"Strategy": args[5]
|
||||
}
|
||||
print(firewall.rich_rules(info, args[6]))
|
||||
elif args[1] == "output_rich_rules":
|
||||
info = {
|
||||
"Protocol": args[2],
|
||||
"Port": args[3],
|
||||
"Address": args[4],
|
||||
"Strategy": args[5]
|
||||
}
|
||||
print(firewall.output_rich_rules(info, args[6]))
|
||||
else:
|
||||
print("Unsupported parameters: " + args[1])
|
||||
sys.exit(1)
|
||||
760
class_v2/firewallModelV2/app/ufw.py
Normal file
760
class_v2/firewallModelV2/app/ufw.py
Normal file
@@ -0,0 +1,760 @@
|
||||
#!/www/server/panel/pyenv/bin/python3.7
|
||||
# coding: utf-8
|
||||
# -------------------------------------------------------------------
|
||||
# yakpanel
|
||||
# -------------------------------------------------------------------
|
||||
# Copyright (c) 2014-2099 yakpanel(http://www.yakpanel.com) All rights reserved.
|
||||
# -------------------------------------------------------------------
|
||||
# Author: wzz <wzz@yakpanel.com>
|
||||
# -------------------------------------------------------------------
|
||||
|
||||
# ------------------------------
|
||||
# 系统防火墙模型 - ufw封装库
|
||||
# ------------------------------
|
||||
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
if "/www/server/panel/class" not in sys.path:
|
||||
sys.path.insert(0, "/www/server/panel/class")
|
||||
import public
|
||||
from firewallModelV2.app.appBase import Base
|
||||
|
||||
|
||||
class Ufw(Base):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.cmd_str = self._set_cmd_str()
|
||||
|
||||
def _set_cmd_str(self):
|
||||
return "ufw"
|
||||
|
||||
# 2024/3/19 下午 5:00 获取系统防火墙的运行状态
|
||||
def status(self):
|
||||
"""
|
||||
@name 获取系统防火墙的运行状态
|
||||
@author wzz <2024/3/19 下午 5:00>
|
||||
@param "data":{"参数名":""} <数据类型> 参数描述
|
||||
@return dict{"status":True/False,"msg":"提示信息"}
|
||||
"""
|
||||
try:
|
||||
result = subprocess.run([self.cmd_str, "status"], capture_output=True, text=True, check=True)
|
||||
if "Status: active" in result.stdout:
|
||||
return "running"
|
||||
elif "状态: 激活" in result.stdout:
|
||||
return "running"
|
||||
else:
|
||||
return "not running"
|
||||
except subprocess.CalledProcessError:
|
||||
return "not running"
|
||||
except Exception as _:
|
||||
return "not running"
|
||||
|
||||
# 2024/3/19 下午 5:00 获取系统防火墙的版本号
|
||||
def version(self):
|
||||
"""
|
||||
@name 获取系统防火墙的版本号
|
||||
@author wzz <2024/3/19 下午 5:00>
|
||||
@param "data":{"参数名":""} <数据类型> 参数描述
|
||||
@return dict{"status":True/False,"msg":"提示信息"}
|
||||
"""
|
||||
try:
|
||||
result = subprocess.run([self.cmd_str, "version"], capture_output=True, text=True, check=True)
|
||||
info = result.stdout.replace("\n", "")
|
||||
return info.replace("ufw ", "")
|
||||
except Exception as _:
|
||||
return "Unknown version"
|
||||
|
||||
# 2024/3/19 下午 5:00 启动防火墙
|
||||
def start(self):
|
||||
"""
|
||||
@name 启动防火墙
|
||||
@author wzz <2024/3/19 下午 5:00>
|
||||
@param "data":{"参数名":""} <数据类型> 参数描述
|
||||
@return dict{"status":True/False,"msg":"提示信息"}
|
||||
"""
|
||||
try:
|
||||
stdout, stderr = public.ExecShell("echo y | {} enable".format(self.cmd_str))
|
||||
if stderr and "setlocale: LC_ALL: cannot change locale (en_US.UTF-8)" not in stderr:
|
||||
return self._result(False, public.lang("Failed to start firewall:{}", stderr))
|
||||
return self._result(True, public.lang("The firewall was started successfully"))
|
||||
except Exception as e:
|
||||
return self._result(False, public.lang("Failed to start firewall:{}", str(e)))
|
||||
|
||||
# 2024/3/19 下午 5:00 停止防火墙
|
||||
def stop(self):
|
||||
"""
|
||||
@name 停止防火墙
|
||||
@author wzz <2024/3/19 下午 5:00>
|
||||
@param "data":{"参数名":""} <数据类型> 参数描述
|
||||
@return dict{"status":True/False,"msg":"提示信息"}
|
||||
"""
|
||||
try:
|
||||
stdout, stderr = public.ExecShell("{} disable".format(self.cmd_str))
|
||||
if stderr and "setlocale: LC_ALL: cannot change locale (en_US.UTF-8)" not in stderr:
|
||||
return self._result(False, public.lang("Failed to stop the firewall:{}", stderr))
|
||||
return self._result(True, public.lang("The firewall was stopped"))
|
||||
except Exception as e:
|
||||
return self._result(False, public.lang("Failed to stop the firewall:{}", str(e)))
|
||||
|
||||
# 2024/3/19 下午 4:59 重启防火墙
|
||||
def restart(self):
|
||||
"""
|
||||
@name 重启防火墙
|
||||
@author wzz <2024/3/19 下午 4:59>
|
||||
@param "data":{"参数名":""} <数据类型> 参数描述
|
||||
@return dict{"status":True/False,"msg":"提示信息"}
|
||||
"""
|
||||
try:
|
||||
self.stop()
|
||||
self.start()
|
||||
except Exception as e:
|
||||
return self._result(False, public.lang("Failed to restart the firewall:{}", str(e)))
|
||||
|
||||
# 2024/3/19 下午 4:59 重载防火墙
|
||||
def reload(self):
|
||||
"""
|
||||
@name 重载防火墙
|
||||
@author wzz <2024/3/19 下午 4:59>
|
||||
@param "data":{"参数名":""} <数据类型> 参数描述
|
||||
@return dict{"status":True/False,"msg":"提示信息"}
|
||||
"""
|
||||
try:
|
||||
subprocess.run([self.cmd_str, "reload"], check=True, stdout=subprocess.PIPE)
|
||||
except Exception as e:
|
||||
return self._result(False, public.lang("Overloaded firewall failed:{}", str(e)))
|
||||
|
||||
# 2024/3/19 上午 10:39 列出防火墙中所有端口规则
|
||||
def list_port(self):
|
||||
"""
|
||||
@name 列出防火墙中所有端口规则
|
||||
@author wzz <2024/3/19 上午 10:39>
|
||||
@param "data":{"参数名":""} <数据类型> 参数描述
|
||||
@return dict{"status":True/False,"msg":"提示信息"}
|
||||
"""
|
||||
try:
|
||||
result = subprocess.run(
|
||||
[self.cmd_str, "status", "verbose"], capture_output=True, text=True, check=True
|
||||
)
|
||||
port_infos = result.stdout.split("\n")
|
||||
datas = []
|
||||
is_start = False
|
||||
for line in port_infos:
|
||||
if "fail2ban" in line.lower():
|
||||
continue
|
||||
if line.startswith("-"):
|
||||
is_start = True
|
||||
continue
|
||||
if not is_start:
|
||||
continue
|
||||
item_fire = self._load_info(line, "port")
|
||||
if item_fire.get("Port") and item_fire["Port"] != "Anywhere" and "." not in item_fire["Port"]:
|
||||
item_fire["Port"] = item_fire["Port"].replace(":", "-")
|
||||
item_fire["Address"] = "all" if item_fire["Address"] == "Anywhere" else item_fire["Address"]
|
||||
|
||||
datas.append(item_fire)
|
||||
return datas
|
||||
except Exception as _:
|
||||
return []
|
||||
|
||||
# 2024/3/19 上午 10:39 列出防火墙中所有input端口规则
|
||||
def list_input_port(self):
|
||||
"""
|
||||
@name 列出防火墙中所有input端口规则
|
||||
@author wzz <2024/3/19 上午 10:39>
|
||||
@param "data":{"参数名":""} <数据类型> 参数描述
|
||||
@return dict{"status":True/False,"msg":"提示信息"}
|
||||
"""
|
||||
try:
|
||||
result = subprocess.run(
|
||||
[self.cmd_str, "status", "verbose"], capture_output=True, text=True, check=True
|
||||
)
|
||||
port_infos = result.stdout.split("\n")
|
||||
datas = []
|
||||
is_start = False
|
||||
for line in port_infos:
|
||||
if "fail2ban" in line.lower():
|
||||
continue
|
||||
if line.startswith("-"):
|
||||
is_start = True
|
||||
continue
|
||||
if not is_start:
|
||||
continue
|
||||
item_fire = self._load_info(line, "port")
|
||||
if item_fire.get("Port") and item_fire["Port"] != "Anywhere" and "." not in item_fire["Port"]:
|
||||
item_fire["Port"] = item_fire["Port"].replace(":", "-")
|
||||
|
||||
if item_fire["Chain"] == "INPUT":
|
||||
datas.append(item_fire)
|
||||
return datas
|
||||
except Exception as _:
|
||||
return []
|
||||
|
||||
# 2024/3/19 上午 10:39 列出防火墙中所有output端口规则
|
||||
def list_output_port(self):
|
||||
"""
|
||||
@name 列出防火墙中所有output端口规则
|
||||
@author wzz <2024/3/19 上午 10:39>
|
||||
@param "data":{"参数名":""} <数据类型> 参数描述
|
||||
@return dict{"status":True/False,"msg":"提示信息"}
|
||||
"""
|
||||
try:
|
||||
result = subprocess.run(
|
||||
[self.cmd_str, "status", "verbose"], capture_output=True, text=True, check=True
|
||||
)
|
||||
port_infos = result.stdout.split("\n")
|
||||
datas = []
|
||||
is_start = False
|
||||
for line in port_infos:
|
||||
if "fail2ban" in line.lower():
|
||||
continue
|
||||
if line.startswith("-"):
|
||||
is_start = True
|
||||
continue
|
||||
if not is_start:
|
||||
continue
|
||||
item_fire = self._load_info(line, "port")
|
||||
if item_fire.get("Port") and item_fire["Port"] != "Anywhere" and "." not in item_fire["Port"]:
|
||||
item_fire["Port"] = item_fire["Port"].replace(":", "-")
|
||||
|
||||
if item_fire["Chain"] == "OUTPUT":
|
||||
datas.append(item_fire)
|
||||
return datas
|
||||
except Exception as _:
|
||||
return []
|
||||
|
||||
# 2024/3/19 上午 10:39 列出防火墙中所有的ip规则
|
||||
def list_address(self):
|
||||
"""
|
||||
@name 列出防火墙中所有的ip规则
|
||||
@author wzz <2024/3/19 上午 10:39>
|
||||
@param "data":{"参数名":""} <数据类型> 参数描述
|
||||
@return dict{"status":True/False,"msg":"提示信息"}
|
||||
"""
|
||||
try:
|
||||
result = subprocess.run(
|
||||
[self.cmd_str, "status", "verbose"], capture_output=True, text=True, check=True
|
||||
)
|
||||
port_infos = result.stdout.split("\n")
|
||||
datas = []
|
||||
is_start = False
|
||||
for line in port_infos:
|
||||
if "fail2ban" in line.lower():
|
||||
continue
|
||||
if line.startswith("-"):
|
||||
is_start = True
|
||||
continue
|
||||
if not is_start:
|
||||
continue
|
||||
item_fire = self._load_info(line, "address")
|
||||
if "Port" in item_fire: continue
|
||||
if item_fire.get("Address"):
|
||||
datas.append(item_fire)
|
||||
return datas
|
||||
except Exception as _:
|
||||
return []
|
||||
|
||||
# 2024/3/19 上午 10:39 列出防火墙中所有input的ip规则
|
||||
def list_input_address(self):
|
||||
"""
|
||||
@name 列出防火墙中所有input的ip规则
|
||||
@author wzz <2024/3/19 上午 10:39>
|
||||
@param "data":{"参数名":""} <数据类型> 参数描述
|
||||
@return dict{"status":True/False,"msg":"提示信息"}
|
||||
"""
|
||||
try:
|
||||
result = subprocess.run(
|
||||
[self.cmd_str, "status", "verbose"], capture_output=True, text=True, check=True
|
||||
)
|
||||
port_infos = result.stdout.split("\n")
|
||||
datas = []
|
||||
is_start = False
|
||||
for line in port_infos:
|
||||
if "fail2ban" in line.lower():
|
||||
continue
|
||||
if line.startswith("-"):
|
||||
is_start = True
|
||||
continue
|
||||
if not is_start:
|
||||
continue
|
||||
if " IN" not in line:
|
||||
continue
|
||||
item_fire = self._load_info(line, "address")
|
||||
if "Port" in item_fire: continue
|
||||
if item_fire.get("Address"):
|
||||
datas.append(item_fire)
|
||||
return datas
|
||||
except Exception as _:
|
||||
return []
|
||||
|
||||
# 2024/3/19 上午 10:39 列出防火墙中所有output的ip规则
|
||||
def list_output_address(self):
|
||||
"""
|
||||
@name 列出防火墙中所有output的ip规则
|
||||
@author wzz <2024/3/19 上午 10:39>
|
||||
@param "data":{"参数名":""} <数据类型> 参数描述
|
||||
@return dict{"status":True/False,"msg":"提示信息"}
|
||||
"""
|
||||
try:
|
||||
result = subprocess.run(
|
||||
[self.cmd_str, "status", "verbose"], capture_output=True, text=True, check=True
|
||||
)
|
||||
port_infos = result.stdout.split("\n")
|
||||
datas = []
|
||||
is_start = False
|
||||
for line in port_infos:
|
||||
if "fail2ban" in line.lower():
|
||||
continue
|
||||
if line.startswith("-"):
|
||||
is_start = True
|
||||
continue
|
||||
if not is_start:
|
||||
continue
|
||||
if " OUT" not in line:
|
||||
continue
|
||||
item_fire = self._load_info(line, "address")
|
||||
if "Port" in item_fire: continue
|
||||
if item_fire.get("Address"):
|
||||
datas.append(item_fire)
|
||||
return datas
|
||||
except Exception as _:
|
||||
return []
|
||||
|
||||
# 2024/3/19 下午 4:59 添加端口规则
|
||||
def input_port(self, info, operation):
|
||||
"""
|
||||
@name 添加端口规则
|
||||
@author wzz <2024/3/19 下午 4:59>
|
||||
@param "data":{"参数名":""} <数据类型> 参数描述
|
||||
@return dict{"status":True/False,"msg":"提示信息"}
|
||||
"""
|
||||
try:
|
||||
if info["Strategy"] == "accept":
|
||||
info["Strategy"] = "allow"
|
||||
elif info["Strategy"] == "drop":
|
||||
info["Strategy"] = "deny"
|
||||
|
||||
if "Port" in info and info["Port"].find('-') != -1:
|
||||
info["Port"] = info["Port"].replace('-', ':')
|
||||
|
||||
if operation == "add":
|
||||
if info['Protocol'] == "tcp/udp":
|
||||
cmd = "{cmd_str} allow {port}/tcp;{cmd_str} allow {port}/udp".format(cmd_str=self.cmd_str, port=info['Port'])
|
||||
stdout, stderr = public.ExecShell(cmd)
|
||||
else:
|
||||
stdout, stderr = public.ExecShell(self.cmd_str + " allow " + info['Port'] + "/" + info['Protocol'])
|
||||
else:
|
||||
if info['Protocol'] == "tcp/udp":
|
||||
cmd = "{cmd_str} delete allow {port}/tcp;{cmd_str} delete allow {port}/udp".format(cmd_str=self.cmd_str, port=info['Port'])
|
||||
stdout, stderr = public.ExecShell(cmd)
|
||||
else:
|
||||
stdout, stderr = public.ExecShell(self.cmd_str + " delete allow " + info['Port'] + "/" + info['Protocol'])
|
||||
|
||||
if stderr:
|
||||
if "setlocale" in stderr:
|
||||
return self._result(True, public.lang("The port rule was successfully configured"))
|
||||
return self._result(False, public.lang("Failed to set a port rule:{}", stderr))
|
||||
|
||||
return self._result(True, public.lang("The port rule was successfully configured"))
|
||||
|
||||
except Exception as e:
|
||||
if "setlocale" in str(e):
|
||||
return self._result(True, public.lang("The port rule was successfully configured"))
|
||||
return self._result(False, public.lang("Failed to set a port rule:{}", str(e)))
|
||||
|
||||
# 2024/3/24 下午 11:28 设置output端口策略
|
||||
def output_port(self, info, operation):
|
||||
"""
|
||||
@name 设置output端口策略
|
||||
@param info: 端口号
|
||||
@param operation: 操作
|
||||
@return None
|
||||
"""
|
||||
try:
|
||||
if info["Strategy"] == "accept":
|
||||
info["Strategy"] = "allow"
|
||||
elif info["Strategy"] == "drop":
|
||||
info["Strategy"] = "deny"
|
||||
|
||||
if "Port" in info and info["Port"].find('-') != -1:
|
||||
info["Port"] = info["Port"].replace('-', ':')
|
||||
|
||||
if operation == "add":
|
||||
if info['Protocol'].find('/') != -1:
|
||||
cmd = "{cmd_str} {strategy} out {port}/tcp;{cmd_str} {strategy} out {port}/udp".format(cmd_str=self.cmd_str,strategy = info['Strategy'],port=info['Port'])
|
||||
else:
|
||||
cmd = "{} {} out {}/{}".format(self.cmd_str, info['Strategy'], info['Port'], info['Protocol'])
|
||||
else:
|
||||
if info['Protocol'].find('/') != -1:
|
||||
cmd = "{cmd_str} delete {strategy} out {port}/tcp;{cmd_str} delete {strategy} out {port}/udp".format(cmd_str=self.cmd_str, strategy=info['Strategy'], port=info['Port'])
|
||||
else:
|
||||
cmd = "{} delete {} out {}/{}".format(self.cmd_str, info['Strategy'], info['Port'], info['Protocol'])
|
||||
stdout, stderr = public.ExecShell(cmd)
|
||||
if stderr:
|
||||
if "setlocale" in stderr:
|
||||
return self._result(True, public.lang("The port rule was successfully configured"))
|
||||
return self._result(False, public.lang("Failed to set the output port rule:{}", stderr))
|
||||
return self._result(True, public.lang("The output port rule is set successfully"))
|
||||
except Exception as e:
|
||||
if "setlocale" in str(e):
|
||||
return self._result(True, public.lang("The output port rule is set successfully"))
|
||||
return self._result(False, public.lang("Failed to set the output port rule:{}", str(e)))
|
||||
|
||||
# 2024/3/19 下午 4:58 复杂一些的规则管理
|
||||
def rich_rules(self, info, operation):
|
||||
"""
|
||||
@name 复杂一些的规则管理
|
||||
@author wzz <2024/3/19 下午 4:58>
|
||||
@param "data":{"参数名":""} <数据类型> 参数描述
|
||||
@return dict{"status":True/False,"msg":"提示信息"}
|
||||
"""
|
||||
try:
|
||||
if info["Strategy"] == "accept":
|
||||
info["Strategy"] = "allow"
|
||||
elif info["Strategy"] == "drop":
|
||||
info["Strategy"] = "deny"
|
||||
else:
|
||||
return self._result(False, public.lang("Unknown policy parameters:{}", info["Strategy"]))
|
||||
|
||||
if "Port" in info and info["Port"].find('-') != -1:
|
||||
info["Port"] = info["Port"].replace('-', ':')
|
||||
|
||||
rule_str = "{} insert 1 {} ".format(self.cmd_str, info["Strategy"])
|
||||
if "Address" in info and public.is_ipv6(info['Address']):
|
||||
rule_str = "{} {} ".format(self.cmd_str, info["Strategy"])
|
||||
if operation == "remove":
|
||||
rule_str = "{} delete {} ".format(self.cmd_str, info["Strategy"])
|
||||
|
||||
if "Address" in info and info['Address'] != "all":
|
||||
rule_str += "from {} ".format(info['Address'])
|
||||
if len(info.get("Protocol", "")) != 0 and "/" not in info['Protocol']:
|
||||
rule_str += "proto {} ".format(info['Protocol'])
|
||||
if len(info.get("Protocol", "")) != 0 and "/" in info['Protocol']:
|
||||
if "Address" in info and info['Address'] != "all":
|
||||
if not "from {} ".format(info['Address']) in rule_str:
|
||||
rule_str += "from any "
|
||||
if len(info.get("Port", "")) != 0:
|
||||
rule_str += "to any port {} ".format(info['Port'])
|
||||
|
||||
if len(info.get("Protocol", "")) != 0 and "/" in info['Protocol']:
|
||||
for i in ["tcp", "udp"]:
|
||||
cmd_str = rule_str + "proto {}".format(i)
|
||||
stdout, stderr = public.ExecShell(cmd_str)
|
||||
if stderr:
|
||||
if "Rule added" in stdout or "Rule deleted" in stdout or "Rule updated" in stdout or "Rule inserted" in stdout or "Skipping adding existing rule" in stdout:
|
||||
return self._result(True, public.lang("The rule is set successfully"))
|
||||
if "setlocale" in stderr:
|
||||
return self._result(True, public.lang("The rule is set successfully"))
|
||||
return self._result(False, public.lang(f"The rule setup failed:{stderr}"))
|
||||
|
||||
return self._result(True, public.lang("The rule is set successfully"))
|
||||
stdout, stderr = public.ExecShell(rule_str)
|
||||
if stderr:
|
||||
if "Rule added" in stdout or "Rule deleted" in stdout or "Rule updated" in stdout or "Rule inserted" in stdout or "Skipping adding existing rule" in stdout:
|
||||
return self._result(True, public.lang("The rule is set successfully"))
|
||||
if "setlocale" in stderr:
|
||||
return self._result(True, public.lang("The rule is set successfully"))
|
||||
return self._result(False, public.lang("The rule setup failed:{}", stderr))
|
||||
return self._result(True, public.lang("The rule is set successfully"))
|
||||
except Exception as e:
|
||||
if "setlocale" in str(e):
|
||||
return self._result(True, public.lang("The rule is set successfully"))
|
||||
return self._result(False, public.lang("The rule setup failed:{}", e))
|
||||
|
||||
# 2024/3/24 下午 11:29 设置output rich_rules
|
||||
def output_rich_rules(self, info, operation):
|
||||
"""
|
||||
@name 设置output rich_rules
|
||||
@param info: 规则
|
||||
@param operation: 操作
|
||||
@return None
|
||||
"""
|
||||
try:
|
||||
if info["Strategy"] == "accept":
|
||||
info["Strategy"] = "allow"
|
||||
elif info["Strategy"] == "drop":
|
||||
info["Strategy"] = "deny"
|
||||
else:
|
||||
return self._result(False, public.lang("Unknown strategy: {}", info["Strategy"]))
|
||||
|
||||
rule_str = "{} insert 1 {} ".format(self.cmd_str, info["Strategy"])
|
||||
if "Address" in info and public.is_ipv6(info['Address']):
|
||||
rule_str = "{} {} ".format(self.cmd_str, info["Strategy"])
|
||||
if operation == "remove":
|
||||
rule_str = "{} delete {} ".format(self.cmd_str, info["Strategy"])
|
||||
|
||||
if len(info.get("Address", "")) != 0:
|
||||
rule_str += "out from {} ".format(info['Address'])
|
||||
if len(info.get("Protocol", "")) != 0:
|
||||
rule_str += "proto {} ".format(info['Protocol'])
|
||||
if len(info.get("Port", "")) != 0:
|
||||
rule_str += "to any port {} ".format(info['Port'])
|
||||
stdout, stderr = public.ExecShell(rule_str)
|
||||
if stderr:
|
||||
if "Rule added" in stdout or "Rule deleted" in stdout or "Rule updated" in stdout or "Rule inserted" in stdout or "Skipping adding existing rule" in stdout:
|
||||
return self._result(True, public.lang("The output rule is set successfully"))
|
||||
if "setlocale" in stderr:
|
||||
return self._result(True, public.lang("The rule is set successfully"))
|
||||
return self._result(False, public.lang("outpuThe rule setup failed:{}", stderr))
|
||||
return self._result(True, public.lang("The output rule is set successfully"))
|
||||
except Exception as e:
|
||||
if "setlocale" in str(e):
|
||||
return self._result(True, public.lang("The output rule is set successfully"))
|
||||
return self._result(False, public.lang("outpuThe rule setup failed:{}", e))
|
||||
|
||||
# 2024/3/19 下午 5:01 解析防火墙规则信息,返回字典格式数据,用于添加或删除防火墙规则
|
||||
def _load_info(self, line, fire_type):
|
||||
"""
|
||||
@name 解析防火墙规则信息,返回字典格式数据,用于添加或删除防火墙规则
|
||||
@author wzz <2024/3/19 上午 10:38>
|
||||
@param "data":{"参数名":""} <数据类型> 参数描述
|
||||
@return dict{"status":True/False,"msg":"提示信息"}
|
||||
"""
|
||||
fields = line.split()
|
||||
item_info = {}
|
||||
if "LIMIT" in line or "ALLOW FWD" in line:
|
||||
return item_info
|
||||
if len(fields) < 4:
|
||||
return item_info
|
||||
if fields[0] == "Anywhere" and fire_type != "port":
|
||||
item_info["Strategy"] = "drop"
|
||||
|
||||
if fields[1] != "(v6)":
|
||||
if fields[1] == "ALLOW":
|
||||
item_info["Strategy"] = "accept"
|
||||
if fields[2] == "IN":
|
||||
item_info["Chain"] = "INPUT"
|
||||
elif fields[2] == "OUT":
|
||||
item_info["Chain"] = "OUTPUT"
|
||||
item_info["Address"] = fields[3] if fields[3] != "Anywhere" else "all"
|
||||
item_info["Family"] = "ipv4"
|
||||
else:
|
||||
if fields[2] == "ALLOW":
|
||||
item_info["Strategy"] = "accept"
|
||||
if fields[3] == "IN":
|
||||
item_info["Chain"] = "INPUT"
|
||||
elif fields[3] == "OUT":
|
||||
item_info["Chain"] = "OUTPUT"
|
||||
item_info["Address"] = fields[4] if fields[4] != "Anywhere" else "all"
|
||||
item_info["Family"] = "ipv6"
|
||||
|
||||
return item_info
|
||||
|
||||
if "/" in fields[0]:
|
||||
item_info["Port"] = fields[0].split("/")[0]
|
||||
item_info["Protocol"] = fields[0].split("/")[1]
|
||||
else:
|
||||
item_info["Port"] = fields[0]
|
||||
item_info["Protocol"] = "tcp/udp"
|
||||
|
||||
if "v6" in fields[1]:
|
||||
item_info["Family"] = "ipv6"
|
||||
if fields[2] == "ALLOW":
|
||||
item_info["Strategy"] = "accept"
|
||||
else:
|
||||
item_info["Strategy"] = "drop"
|
||||
|
||||
if fields[3] == "IN":
|
||||
item_info["Chain"] = "INPUT"
|
||||
elif fields[3] == "OUT":
|
||||
item_info["Chain"] = "OUTPUT"
|
||||
item_info["Address"] = fields[4] if fields[4] != "Anywhere" else "all"
|
||||
|
||||
else:
|
||||
item_info["Family"] = "ipv4" if ":" not in fields[3] else "ipv6"
|
||||
|
||||
if fields[1] == "ALLOW":
|
||||
item_info["Strategy"] = "accept"
|
||||
else:
|
||||
item_info["Strategy"] = "drop"
|
||||
|
||||
if fields[2] == "IN":
|
||||
item_info["Chain"] = "INPUT"
|
||||
elif fields[2] == "OUT":
|
||||
item_info["Chain"] = "OUTPUT"
|
||||
item_info["Address"] = fields[3] if fields[3] != "Anywhere" else "all"
|
||||
|
||||
return item_info
|
||||
|
||||
# 2024/3/25 下午 2:29 设置端口转发
|
||||
def port_forward(self, info, operation):
|
||||
"""
|
||||
@name 设置端口转发
|
||||
@param port: 端口号
|
||||
@param ip: ip地址
|
||||
@param operation: 操作
|
||||
@return None
|
||||
"""
|
||||
from firewallModelV2.app.iptables import Iptables
|
||||
self.firewall = Iptables()
|
||||
return self.firewall.port_forward(info, operation)
|
||||
|
||||
# 2024/3/25 下午 2:34 获取所有端口转发列表
|
||||
def list_port_forward(self):
|
||||
"""
|
||||
@name 获取所有端口转发列表
|
||||
@return None
|
||||
"""
|
||||
from firewallModelV2.app.iptables import Iptables
|
||||
self.firewall = Iptables()
|
||||
return self.firewall.get_nat_prerouting_rules()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
args = sys.argv
|
||||
firewall = Ufw()
|
||||
ufw_status = firewall.status()
|
||||
if len(args) < 2:
|
||||
print("Welcome to the UFW (Uncomplicated Firewall) command-line interface!")
|
||||
print("Firewall status is :", ufw_status)
|
||||
print("Firewall version: ", firewall.version())
|
||||
if ufw_status == "not running":
|
||||
print("ufw is not started, please start ufw and then execute the command!")
|
||||
print("Start the command: start")
|
||||
print()
|
||||
sys.exit(1)
|
||||
print()
|
||||
print("Available options:")
|
||||
print("1. Check Firewall Status: status")
|
||||
print("2. Check Firewall Version: version")
|
||||
print("3. Start Firewall: start")
|
||||
print("4. Stop Firewall: stop")
|
||||
print("5. Restart Firewall: restart")
|
||||
print("6. Reload Firewall: reload")
|
||||
print("7. List All Ports: list_port")
|
||||
print("8. List All IP Addresses: list_address")
|
||||
print("9. Add Port: add_port <port> <protocol>")
|
||||
print("10. Remove Port: remove_port <port> <protocol>")
|
||||
print("11. Add Port Rule: add_port_rule <address> <port> <protocol> <strategy> <operation>")
|
||||
print("12. Remove Port Rule: remove_port_rule <address> <port> <protocol> <strategy> <operation>")
|
||||
print("13. Add IP Rule: add_ip_rule <address> <strategy> <operation>")
|
||||
print("14. Remove IP Rule: remove_ip_rule <address> <strategy> <operation>")
|
||||
print()
|
||||
sys.exit(1)
|
||||
if args[1] == "status":
|
||||
print(firewall.status())
|
||||
elif args[1] == "version":
|
||||
print(firewall.version())
|
||||
elif args[1] == "start":
|
||||
error = firewall.start()
|
||||
if error:
|
||||
print(f"Error: {error}")
|
||||
else:
|
||||
print("Firewall started successfully.")
|
||||
elif args[1] == "stop":
|
||||
error = firewall.stop()
|
||||
if error:
|
||||
print(f"Error: {error}")
|
||||
else:
|
||||
print("Firewall stopped successfully.")
|
||||
elif args[1] == "restart":
|
||||
error = firewall.restart()
|
||||
if error:
|
||||
print(f"Error: {error}")
|
||||
else:
|
||||
print("Firewall restarted successfully.")
|
||||
elif args[1] == "reload":
|
||||
error = firewall.reload()
|
||||
if error:
|
||||
print(f"Error: {error}")
|
||||
else:
|
||||
print("Firewall reloaded successfully.")
|
||||
elif args[1] == "list_input_port":
|
||||
ports = firewall.list_input_port()
|
||||
for p in ports:
|
||||
print(p)
|
||||
elif args[1] == "list_output_port":
|
||||
ports = firewall.list_output_port()
|
||||
for p in ports:
|
||||
print(p)
|
||||
elif args[1] == "list_input_address":
|
||||
addresses = firewall.list_input_address()
|
||||
for a in addresses:
|
||||
print(a)
|
||||
elif args[1] == "list_output_address":
|
||||
addresses = firewall.list_output_address()
|
||||
for a in addresses:
|
||||
print(a)
|
||||
elif args[1] == "add_port":
|
||||
port = args[2]
|
||||
protocol = args[3]
|
||||
error = firewall.input_port(f"{port}/{protocol}", "allow")
|
||||
if error:
|
||||
print(f"Error: {error}")
|
||||
else:
|
||||
print(f"Port {port}/{protocol} added successfully.")
|
||||
elif args[1] == "remove_port":
|
||||
port = args[2]
|
||||
protocol = args[3]
|
||||
error = firewall.input_port(f"{port}/{protocol}", "remove")
|
||||
if error:
|
||||
print(f"Error: {error}")
|
||||
else:
|
||||
print(f"Port {port}/{protocol} removed successfully.")
|
||||
elif args[1] == "add_port_rule":
|
||||
address = args[2]
|
||||
port = args[3]
|
||||
protocol = args[4]
|
||||
strategy = args[5]
|
||||
operation = args[6]
|
||||
error = firewall.rich_rules(
|
||||
{"Address": address, "Port": port, "Protocol": protocol, "Strategy": strategy}, operation)
|
||||
if error:
|
||||
print(f"Error: {error}")
|
||||
else:
|
||||
print("Rich rule added successfully.")
|
||||
elif args[1] == "remove_port_rule":
|
||||
address = args[2]
|
||||
port = args[3]
|
||||
protocol = args[4]
|
||||
strategy = args[5]
|
||||
operation = args[6]
|
||||
error = firewall.rich_rules(
|
||||
{"Address": address, "Port": port, "Protocol": protocol, "Strategy": strategy}, operation)
|
||||
if error:
|
||||
print(f"Error: {error}")
|
||||
else:
|
||||
print("Rich rule removed successfully.")
|
||||
elif args[1] == "add_ip_rule":
|
||||
address = args[2]
|
||||
strategy = args[3]
|
||||
operation = args[4]
|
||||
error = firewall.rich_rules(
|
||||
{"Address": address, "Strategy": strategy}, operation)
|
||||
if error:
|
||||
print(f"Error: {error}")
|
||||
else:
|
||||
print("Rich rule added successfully.")
|
||||
elif args[1] == "remove_ip_rule":
|
||||
address = args[2]
|
||||
strategy = args[3]
|
||||
operation = args[4]
|
||||
error = firewall.rich_rules(
|
||||
{"Address": address, "Strategy": strategy}, operation)
|
||||
if error:
|
||||
print(f"Error: {error}")
|
||||
else:
|
||||
print("Rich rule removed successfully.")
|
||||
elif args[1] == "output_port":
|
||||
port = args[2]
|
||||
operation = args[3]
|
||||
error = firewall.output_port(port, operation)
|
||||
if error:
|
||||
print(f"Error: {error}")
|
||||
else:
|
||||
print(f"Output port {port} {operation} successfully.")
|
||||
elif args[1] == "output_rich_rules":
|
||||
address = args[2]
|
||||
port = args[3]
|
||||
protocol = args[4]
|
||||
strategy = args[5]
|
||||
operation = args[6]
|
||||
error = firewall.output_rich_rules(
|
||||
{"Address": address, "Port": port, "Protocol": protocol, "Strategy": strategy}, operation)
|
||||
if error:
|
||||
print(f"Error: {error}")
|
||||
else:
|
||||
print("Output rich rule added successfully.")
|
||||
else:
|
||||
print("Invalid args")
|
||||
sys.exit(1)
|
||||
Reference in New Issue
Block a user