Initial YakPanel commit

This commit is contained in:
Niranjan
2026-04-07 02:04:22 +05:30
commit 2826d3e7f3
5359 changed files with 1390724 additions and 0 deletions

View File

@@ -0,0 +1,78 @@
# coding: utf-8
# -------------------------------------------------------------------
# yakpanel
# -------------------------------------------------------------------
# Copyright (c) 2014-2099 yakpanel(http://www.yakpanel.com) All rights reserved.
# -------------------------------------------------------------------
# Author: wzz <wzz@yakpanel.com>
# -------------------------------------------------------------------
# ------------------------------
# 系统防火墙模型 - 底层基类
# ------------------------------
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":"提示信息"}
'''
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, "设置net.ipv4.ip_forward失败, err: {}".format(stderr))
stdout, stderr = public.ExecShell("sysctl -p")
if stderr:
return self._result(False, "设置net.ipv4.ip_forward失败, err: {}".format(stderr))
return self._result(True, "设置net.ipv4.ip_forward成功")
return self._result(True, "net.ipv4.ip_forward已经设置")
# 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

View File

@@ -0,0 +1,750 @@
#!/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 firewallModel.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 e:
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 = public.ExecShell("firewall-cmd --version")
if "FirewallD is not running" in stdout:
return "Firewalld 没有启动,请先启动再试"
if stderr:
return "获取firewalld版本失败, 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 = public.ExecShell("systemctl start firewalld")
if stderr:
return self._result(False, "启动防火墙失败, err: {}".format(stderr))
return self._result(True, "启动防火墙成功")
# 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 = public.ExecShell("systemctl stop firewalld")
if stderr:
return self._result(False, "停止防火墙失败, err: {}".format(stderr))
return self._result(True, "停止防火墙成功")
# 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 = public.ExecShell("systemctl restart firewalld")
if stderr:
return self._result(False, "重启防火墙失败, err: {}".format(stderr))
return self._result(True, "重启防火墙成功")
# 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 = public.ExecShell("firewall-cmd --reload")
if stderr:
return self._result(False, "重载防火墙失败, err: {}".format(stderr))
return self._result(True, "重载防火墙成功")
# 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.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"]
# 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, "不支持的操作: {}".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, "设置端口失败, 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, "设置端口失败, 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, "设置端口失败, err: {}".format(stderr))
return self._result(True, "设置入站端口成功")
# 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, "不支持的操作: {}".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, "不支持的策略: {}".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, "设置出站端口失败, err: 协议不支持 {}".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, "设置出站端口失败, 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, "设置出站端口失败, err: {}".format(stderr))
return self._result(True, "设置出站端口成功")
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, "设置规则:{} 失败, err: {}".format(operation, rule_str, stderr))
return self._result(True, "设置规则成功".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, "不支持的规则操作: {}".format(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/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, "不支持的操作: {}".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, "不支持的策略: {}".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, "设置出站地址失败, err: {}".format(stderr))
if "NOT_ENABLED" in stderr:
return self._result(False, "规则不存在")
return self._result(True, "设置出站地址成功")
# 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":
rule = {"Family": elem.attrib["family"] if "family" in elem.attrib else "ipv4"}
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 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"
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",
# "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/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, "开启masquerade失败, err: {}".format(stderr))
return self._result(True, "开启masquerade成功")
return self._result(True, "masquerade已经开启")
# 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, "不支持的操作: {}".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, "端口转发规则已经存在")
return self._result(False, "设置端口转发失败, 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, "端口转发规则已经存在")
return self._result(False, "设置端口转发失败, 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, "端口转发规则已经存在")
return self._result(False, "设置端口转发失败, 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, "端口转发规则已经存在")
return self._result(False, "设置端口转发失败, 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, "端口转发规则已经存在")
return self._result(False, "设置端口转发失败, 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, "端口转发规则已经存在")
return self._result(False, "设置端口转发失败, err: {}".format(stderr))
return self._result(True, "设置端口转发成功")
# 2024/3/25 下午 2:37 获取所有端口转发规则
def list_port_forward(self) -> list:
'''
@name 获取所有端口转发规则
@param "data":{"参数名":""} <数据类型> 参数描述
@return list[dict{}...]
'''
return self.parse_public_zone()["forward_ports"]
if __name__ == '__main__':
args = sys.argv
firewall = Firewalld()
Firewalld_status = firewall.status()
if len(args) < 2:
print("Welcome to the Firewalld command-line interface!")
print("Firewall status is :", Firewalld_status)
print("Firewall version: ", firewall.version())
if Firewalld_status == "not running":
print("Firewalld未启动,请启动Firewalld后再执行命令!")
print("启动命令: start")
print()
sys.exit(1)
print("Usage: ")
print("status: Get the status of the firewall.")
print("version: Get the version of the firewall.")
print("start: Start the firewall.")
print("stop: Stop the firewall.")
print("restart: Restart the firewall.")
print("reload: Reload the firewall.")
print("list_input_port: List all input ports.")
print("list_input_address: List all input address rules.")
print("input_port: Add or remove input port.")
print("output_port: Add or remove output port.")
print("list_output_port: List all output ports.")
print("list_output_address: List all output address rules.")
print("rich_rules: Add or remove rich rules.")
sys.exit(1)
if args[1] == "status":
print("Firewall status is :", Firewalld_status)
elif args[1] == "version":
print("Firewall version: ", firewall.version())
elif args[1] == "start":
print(firewall.start())
elif args[1] == "stop":
print(firewall.stop())
elif args[1] == "restart":
print(firewall.restart())
elif args[1] == "reload":
print(firewall.reload())
elif args[1] == "list_input_port":
print(firewall.list_input_port())
elif args[1] == "list_input_address":
print(firewall.list_input_address())
elif args[1] == "input_port":
if len(args) < 4:
print("Usage: input_port Port Protocol")
sys.exit(1)
print(firewall.input_port({"Port": args[2], "Protocol": args[3]}, args[4]))
elif args[1] == "output_port":
if len(args) < 6:
print("Usage: output_port Port Protocol Strategy Priority")
sys.exit(1)
print(firewall.output_port({"Port": args[2], "Protocol": args[3], "Strategy": args[4], "Priority": args[5]}, args[6]))
elif args[1] == "list_output_port":
print(firewall.list_output_port())
elif args[1] == "list_output_address":
print(firewall.list_output_address())
elif args[1] == "rich_rules":
if len(args) < 4:
print("Usage: rich_rules Family Address Port Protocol Strategy")
sys.exit(1)
print(firewall.rich_rules({"Family": args[2], "Address": args[3], "Port": args[4], "Protocol": args[5], "Strategy": args[6]}, args[7]))
elif args[1] == "output_rich_rules":
if len(args) < 6:
print("Usage: output_rich_rules Family Address Port Protocol Strategy Priority")
sys.exit(1)
print(firewall.output_rich_rules({"Family": args[2], "Address": args[3], "Port": args[4], "Protocol": args[5], "Strategy": args[6], "Priority": args[7]}, args[8]))
elif args[1] == "port_forward":
if len(args) < 7:
print("Usage: port_forward Port Protocol ToPort ToAddr")
sys.exit(1)
print(firewall.port_forward({"Port": args[2], "Protocol": args[3], "ToPort": args[4], "ToAddr": args[5]}, args[6]))
else:
print("Command not found!")
sys.exit(1)

View File

@@ -0,0 +1,939 @@
#!/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 os
import sys
if "/www/server/panel/class" not in sys.path:
sys.path.insert(0, "/www/server/panel/class")
import public
from firewallModel.app.appBase import Base
# import re
class Iptables(Base):
def __init__(self):
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 "未知的iptables版本"
return result
except Exception as e:
return "未知版本"
# 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, "当前系统防火墙为iptables不支持设置状态")
# 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, "当前系统防火墙为iptables不支持停止")
# 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, "当前系统防火墙为iptables不支持重启")
# 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, "当前系统防火墙为iptables不支持重载")
# 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: ICMPInternet 控制消息协议)
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 "错误: 不支持的表名."
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 e:
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 e:
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 e:
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 e:
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 e:
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 e:
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, "设置端口规则失败:{}".format(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, "设置端口规则失败:{}".format(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, "设置端口规则失败:{}".format("不支持的链类型"))
if info['Protocol'] not in ["tcp", "udp"]:
return self._result(False, "设置端口规则失败:{}".format("不支持的协议类型"))
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, "设置端口规则失败:{}".format("不支持的策略类型"))
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:
return self._result(False, "设置端口规则失败:{}".format(stderr))
return self._result(True, "设置端口规则成功")
except Exception as e:
return self._result(False, "设置端口规则失败:{}".format(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, "设置端口规则失败:{}".format("不支持的链类型"))
if "Address" in info and info["Address"] == "":
info["Address"] = "all"
if "Address" in info and public.is_ipv6(info['Address']):
return self._result(False, "设置端口规则失败:{}".format("不支持的IPV6地址"))
if info['Protocol'] not in ["tcp", "udp"]:
return self._result(False, "设置端口规则失败:{}".format("不支持的协议类型"))
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, "设置端口规则失败:{}".format("不支持的策略类型"))
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:
return self._result(False, "设置端口规则失败:{}".format(stderr))
return self._result(True, "设置端口规则成功")
except Exception as e:
return self._result(False, "设置端口规则失败:{}".format(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, "设置规则失败:{}".format("不支持的链类型"))
if "Address" in info and info["Address"] == "":
info["Address"] = "all"
if "Address" in info and public.is_ipv6(info['Address']):
return self._result(False, "设置规则失败:{}".format("不支持的IPV6地址"))
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, "设置规则失败:{}".format("不支持的策略类型"))
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:
return self._result(False, "设置规则失败:{}".format(stderr))
return self._result(True, "设置规则成功")
except Exception as e:
return self._result(False, "设置规则失败:{}".format(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, "设置端口规则失败:{}".format(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, "设置端口规则失败:{}".format(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 e:
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 "错误: 不支持的表名."
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 "请输入正确的操作类型. (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, "设置端口转发规则失败:{}".format(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, "不支持的表名{}".format(parm['table']))
rule = "{} -t {} {} {} {}".format(
self.cmd_str, parm['table'], parm['type'], parm['chain_name'], parm['rule']
)
stdout, stderr = public.ExecShell(rule)
if stderr:
return self._result(False, "规则设置失败:{}".format(stderr))
return self._result(True, "规则设置成功")
except Exception as e:
return self._result(False, "规则设置失败: {}".format(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 e:
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("不支持的传参: " + args[1])
sys.exit(1)

View File

@@ -0,0 +1,729 @@
#!/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 os
import sys
if "/www/server/panel/class" not in sys.path:
sys.path.insert(0, "/www/server/panel/class")
import public
# import re
from firewallModel.app.appBase import Base
class Ufw(Base):
def __init__(self):
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 e:
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 e:
return "未知版本"
# 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:
return self._result(False, "启动防火墙失败:{}".format(stderr))
return self._result(True, "启动防火墙成功")
except Exception as e:
return self._result(False, "启动防火墙失败:{}".format(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:
return self._result(False, "停止防火墙失败:{}".format(stderr))
return self._result(True, "停止防火墙成功")
except Exception as e:
return self._result(False, "停止防火墙失败:{}".format(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, "重启防火墙失败:{}".format(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, "重载防火墙失败:{}".format(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 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 e:
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 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 e:
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 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 e:
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 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 e:
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 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 e:
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 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 e:
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 info["Port"].find('-') != -1:
info["Port"] = info["Port"].replace('-', ':')
if operation == "add":
if info['Protocol'].find("/") != -1:
rich_rule = self.cmd_str + " insert 1 {} {}".format(info['Strategy'], info['Port'])
stdout, stderr = public.ExecShell(rich_rule)
elif info['Protocol'] == "tcp/udp":
stdout, stderr = public.ExecShell(self.cmd_str + " allow " + info['Port'])
else:
stdout, stderr = public.ExecShell(self.cmd_str + " allow " + info['Port'] + "/" + info['Protocol'])
else:
if info['Protocol'].find("/") != -1:
rich_rule = "{} delete {} {}".format(self.cmd_str, info['Strategy'], info['Port'])
stdout, stderr = public.ExecShell(rich_rule)
elif info['Protocol'] == "tcp/udp":
stdout, stderr = public.ExecShell(self.cmd_str + " delete allow " + info['Port'])
else:
stdout, stderr = public.ExecShell(self.cmd_str + " delete allow " + info['Port'] + "/" + info['Protocol'])
if stderr:
if "setlocale" in stderr:
return self._result(True, "设置端口规则成功")
return self._result(False, "设置端口规则失败:{}".format(stderr))
return self._result(True, "设置端口规则成功")
except Exception as e:
if "setlocale" in str(e):
return self._result(True, "设置端口规则成功")
return self._result(False, "设置端口规则失败:{}".format(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 operation == "add":
if info['Protocol'].find('/') != -1:
cmd = "{} {} out {}".format(self.cmd_str, info['Strategy'], info['Port'])
else:
cmd = "{} {} out {}/{}".format(self.cmd_str, info['Strategy'], info['Port'], info['Protocol'])
else:
if info['Protocol'].find('/') != -1:
cmd = "{} delete {} out {}".format(self.cmd_str, info['Strategy'], 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, "设置端口规则成功")
return self._result(False, "设置output端口规则失败:{}".format(stderr))
return self._result(True, "设置output端口规则成功")
except Exception as e:
if "setlocale" in str(e):
return self._result(True, "设置output端口规则成功")
return self._result(False, "设置output端口规则失败:{}".format(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, "未知的策略参数:{}".format(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 "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("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, "设置规则成功")
if "setlocale" in stderr:
return self._result(True, "设置规则成功")
return self._result(False, "规则设置失败:{}".format(stderr))
return self._result(True, "设置规则成功")
except Exception as e:
if "setlocale" in str(e):
return self._result(True, "设置规则成功")
return self._result(False, "规则设置失败:{}".format(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, "未知的策略: {}".format(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, "设置output规则成功")
if "setlocale" in stderr:
return self._result(True, "设置规则成功")
return self._result(False, "outpu规则设置失败:{}".format(stderr))
return self._result(True, "设置output规则成功")
except Exception as e:
if "setlocale" in str(e):
return self._result(True, "设置output规则成功")
return self._result(False, "outpu规则设置失败:{}".format(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]
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]
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]
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]
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 firewallModel.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 firewallModel.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未启动,请启动ufw后再执行命令!")
print("启动命令: 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)