Files
yakpanel-core/class/safeModel/firewallModel.py
2026-04-07 02:04:22 +05:30

4002 lines
171 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# coding: utf-8
# -------------------------------------------------------------------
# YakPanel
# -------------------------------------------------------------------
# Copyright (c) 2015-2099 YakPanel(www.yakpanel.com) All rights reserved.
# -------------------------------------------------------------------
# Author: hwliang <hwl@yakpanel.com>
# -------------------------------------------------------------------
# 系统防火墙
# ------------------------------
import sys, os, json, re, time, sqlite3
import contextlib
import traceback
from types import coroutine
from xml.etree.ElementTree import ElementTree, Element
from safeModel.base import safeBase
from flask import send_file, abort
os.chdir("/www/server/panel")
sys.path.append("class/")
import public
class main(safeBase):
__isFirewalld = False
__isUfw = False
__firewall_obj = None
_add_sid = 0
_ip_list = []
_port_list = []
_ufw_default = '/etc/default/ufw'
_ufw_sysctl = '/etc/ufw/sysctl.conf'
_ufw_before = '/etc/ufw/before.rules'
_trans_status = "/www/server/panel/plugin/firewall/status.json"
_rule_path = "/www/server/panel/plugin/firewall/"
_ips_path = "/www/server/panel/plugin/firewall/ips.txt"
_country_path = "/www/server/panel/plugin/firewall/country.txt"
_white_list_file = "/www/server/panel/plugin/firewall/whitelist.txt" # 证书验证IP
_white_list = []
_firewall_create_tip = '{}/data/firewall_sqlite.pl'.format(
public.get_panel_path())
def __init__(self):
self.__firewall_obj = firewalld()
if os.path.exists('/usr/sbin/firewalld') and os.path.exists('/usr/bin/yum'):
self.__isFirewalld = True
if os.path.exists('/usr/sbin/ufw') and os.path.exists('/usr/bin/apt-get'):
self.__isUfw = True
# self.__ufw = '/usr/sbin/ufw'
self.get_old_rule()
if not os.path.exists(self._trans_status):
ret = {"status": "close"}
public.writeFile(self._trans_status, json.dumps(ret))
if not os.path.exists(self._firewall_create_tip):
Sqlite()
public.writeFile(self._firewall_create_tip, '')
def get_old_rule(self):
"""
@兼容防火墙插件规则
"""
self._rule_path = self._rule_path.replace('plugin', 'data')
if not os.path.exists(self._rule_path): os.makedirs(self._rule_path)
if os.path.exists(self._trans_status):
n_path = self._trans_status.replace('plugin', 'data')
if not os.path.exists(n_path):
public.writeFile(n_path, public.readFile(self._trans_status))
if os.path.exists(self._ips_path):
n_path = self._ips_path.replace('plugin', 'data')
if not os.path.exists(n_path):
public.writeFile(n_path, public.readFile(self._ips_path))
if os.path.exists(self._white_list_file):
n_path = self._white_list_file.replace('plugin', 'data')
if not os.path.exists(n_path):
public.writeFile(n_path,
public.readFile(self._white_list_file))
if os.path.exists(self._country_path):
n_path = self._country_path.replace('plugin', 'data')
if not os.path.exists(n_path):
public.writeFile(n_path, public.readFile(self._country_path))
self._white_list_file = self._white_list_file.replace('plugin', 'data')
self._country_path = self._country_path.replace('plugin', 'data')
self._ips_path = self._ips_path.replace('plugin', 'data')
self._trans_status = self._trans_status.replace('plugin', 'data')
def install_sys_firewall(self, get):
"""
@安装系统防火墙
"""
res = public.install_sys_firewall()
if res:
return public.returnMsg(True, public.lang("Successful installation"))
return public.returnMsg(False, public.lang("installation failed"))
def get_firewall_info(self, get):
"""
@name 获取防火墙统计
"""
data = {}
data['port'] = public.M('firewall_new').count()
data['ip'] = public.M('firewall_ip').count()
data['trans'] = public.M('firewall_trans').count()
data['country'] = public.M('firewall_country').count()
isPing = True
try:
file = '/etc/sysctl.conf'
conf = public.readFile(file)
rep = r"#*net\.ipv4\.icmp_echo_ignore_all\s*=\s*([0-9]+)\n"
tmp = re.search(rep, conf).groups(0)[0]
if tmp == '1': isPing = False
except:
isPing = True
data['ping'] = isPing
data['status'] = self.get_firewall_status()
return data
# 服务状态获取
def get_firewall_status(self):
if self.__isUfw:
res = public.ExecShell("systemctl is-active ufw")[0]
if res == "active":
return True
res = public.ExecShell("systemctl list-units | grep ufw")[0]
if res.find('active running') != -1:
return True
res = public.ExecShell('/lib/ufw/ufw-init status')[0]
if res.find("Firewall is not running") != -1:
return False
res = public.ExecShell('ufw status verbose')[0]
if res.find('inactive') != -1:
return False
return True
if self.__isFirewalld:
res = public.ExecShell("ps -ef|grep firewalld|grep -v grep")[0]
if res:
return True
res = public.ExecShell("systemctl is-active firewalld")[0]
if res == "active":
return True
res = public.ExecShell("systemctl list-units | grep firewalld")[0]
if res.find('active running') != -1:
return True
return False
else:
res = public.ExecShell("/etc/init.d/iptables status")[0]
if res.find('not running') != -1:
return False
res = public.ExecShell("systemctl is-active iptables")[0]
if res == "active": return True
return True
def SetPing(self, get):
if get.status == '1':
get.status = '0'
else:
get.status = '1'
filename = '/etc/sysctl.conf'
conf = public.readFile(filename)
if conf.find('net.ipv4.icmp_echo') != -1:
rep = r"net\.ipv4\.icmp_echo.*"
conf = re.sub(rep, 'net.ipv4.icmp_echo_ignore_all=' + get.status + "\n", conf)
else:
conf += "\nnet.ipv4.icmp_echo_ignore_all=" + get.status + "\n"
if public.writeFile(filename, conf):
public.ExecShell('sysctl -p')
return public.returnMsg(True, public.lang("SUCCESS"))
else:
return public.returnMsg(
False,
# '<a style="color:red;">错误设置失败sysctl.conf不可写!</a><br>'
# '1、如果安装了[YakPanel 系统加固],请先关闭<br>'
# '2、如果安装了云锁请关闭[系统加固]功能<br>'
# '3、如果安装了安全狗请关闭[系统防护]功能<br>'
# '4、如果使用了其它安全软件请先卸载<br>'
'<a style="color:red;">Error: Setting failed, sysctl.conf is not writable!</a><br>'
'1. If [System Hardening] is installed, please close it first<br>'
'2. If Cloud Lock is installed, please turn off the [System Hardening] function<br>'
'3. If a security dog is installed, please turn off the [System Protection] function<br>'
'4. If you use other security software, please uninstall it first<br>'
)
# 服务状态控制
def firewall_admin(self, get):
order = ['reload', 'restart', 'stop', 'start']
if not get.status in order:
return public.returnMsg(False, public.lang("unknown control command!"))
names = ["reload", "restart", "stop", "start"]
result = dict(zip(order, names))
if self.__isUfw:
if get.status == "stop":
public.ExecShell('/usr/sbin/ufw disable')
elif get.status == "start":
public.ExecShell('echo y|/usr/sbin/ufw enable')
elif get.status == "reload":
public.ExecShell('/usr/sbin/ufw reload')
elif get.status == "restart":
public.ExecShell('/usr/sbin/ufw disable && /usr/sbin/ufw enable')
# ufw防火墙启动时重载一次sysctl
# 解决deian系统启动ufw后禁ping失1效 by wzz/2023-06-14
filename = '/etc/sysctl.conf'
conf = public.readFile(filename)
if conf.find('net.ipv4.icmp_echo') != -1:
public.ExecShell("sysctl -p")
public.WriteLog("system firewall", "firewall {}".format(result[get.status]))
return public.returnMsg(True, public.lang("firewall has {}", result[get.status]))
if self.__isFirewalld:
public.ExecShell('systemctl {} firewalld'.format(get.status))
public.WriteLog("system firewall", "firewall {}".format(result[get.status]))
return public.returnMsg(True, public.lang("firewall has {}", result[get.status]))
else:
public.ExecShell('service iptables {}'.format(get.status))
public.WriteLog("system firewall", "firewall {}".format(result[get.status]))
return public.returnMsg(True, public.lang("firewall has {}", result[get.status]))
# 重载防火墙配置
def FirewallReload(self):
if self.__isUfw:
public.ExecShell('/usr/sbin/ufw reload') # 兼容安装了多个防火墙的情况 hezhihong # return
# 解决deian系统启动ufw后禁ping失1效 by wzz/2023-06-14
filename = '/etc/sysctl.conf'
conf = public.readFile(filename)
if conf.find('net.ipv4.icmp_echo') != -1:
public.ExecShell("sysctl -p")
if self.__isFirewalld:
public.ExecShell('firewall-cmd --reload')
else:
public.ExecShell('/etc/init.d/iptables save')
public.ExecShell('/etc/init.d/iptables restart')
# 端口扫描
def CheckPort(self, port, protocol):
import socket
localIP = '127.0.0.1'
temp = {}
temp['port'] = port
temp['local'] = True
try:
if 'tcp' in protocol.lower():
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.settimeout(0.01)
s.connect((localIP, port))
s.close()
if 'udp' in protocol.lower():
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.settimeout(0.01)
s.sendto(b'', (localIP, port))
s.close()
except:
temp['local'] = False
result = 0
if temp['local']: result += 2
return result
# 查询入栈规则
def get_rules_list(self, args):
if self.__isFirewalld:
self.__firewall_obj = firewalld()
self.GetList()
else:
self.get_ufw_list()
try:
p = 1
limit = 15
if 'p' in args: p = args.p
if 'limit' in args: limit = args.limit
where = '1=1'
sql = public.M('firewall_new')
if hasattr(args, 'query'):
where = " ports like '%{search}%' or brief like '%{search}%' or address like '%{search}%'".format(
search=args.query)
count = sql.where(where, ()).count()
data = public.get_page(count, int(p), int(limit))
data['data'] = sql.where(where, ()).limit('{},{}'.format(data['shift'], data['row'])).order('addtime desc').select()
res_data = data['data']
for i in range(len(res_data)):
if not 'ports' in res_data[i]:
res_data[i]['status'] = -1
continue
d = res_data[i]
_port = d['ports']
_protocol = d['protocol']
if _port.find(':') != -1 or _port.find('.') != -1 or _port.find(
'-') != -1:
d['status'] = -1
else:
d['status'] = self.CheckPort(int(_port), _protocol)
for i in res_data:
if 'brief' in i:
i['brief'] = public.xsssec(i['brief'])
return res_data
except:
return []
def check_firewall_rule(self, args):
"""
@检测防火墙规则
"""
port = args['port']
find = public.M('firewall_new').where('ports=?', (str(port),)).find()
if find:
return True
return False
# 端口检查
def check_port(self, port_list):
rep1 = r"^\d{1,5}(:\d{1,5})?$"
# rep1 = r'^[0-9]|[1-9]\d{1,3}|[1-5]\d{4}|6[0-4]\d{3}|65[0-4]\d{2}|655[0-2]\d|6553[0-5]$'
for port in port_list:
if port.find('-') != -1:
ports = port.split('-')
if not re.search(rep1, ports[0]):
return public.returnMsg(False, public.lang("Port range is incorrect!"))
if not re.search(rep1, ports[1]):
return public.returnMsg(False, public.lang("Port range is incorrect!"))
elif port.find(':') != -1:
ports = port.split(':')
if not re.search(rep1, ports[0]):
return public.returnMsg(False, public.lang("Port range is incorrect!"))
if not re.search(rep1, ports[1]):
return public.returnMsg(False, public.lang("Port range is incorrect!"))
else:
if not re.search(rep1, port):
return public.returnMsg(False, public.lang("Port range is incorrect!"))
def parse_ip_interval(self, ip_str):
"""解析区间IP
author: lx
date: 2022/10/25
Returns:
list : IP列表
"""
ips = []
try:
rep2 = r"^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}(\/\d{1,2})?$"
searchor = re.compile(rep2)
if ip_str.find("-") != -1:
pre_ip, end_ip = ip_str.split("-")
if searchor.search(pre_ip) and searchor.search(end_ip):
ips.append(pre_ip)
pinx = pre_ip.rfind(".") + 1
einx = end_ip.rfind(".") + 1
pre = pre_ip[0:pinx]
end = end_ip[0:einx]
if pre == end:
start_num = int(pre_ip[pinx:])
end_num = min(int(end_ip[einx:]), 255)
for i in range(start_num + 1, end_num):
new_ip = pre + str(i)
if searchor.search(new_ip):
ips.append(new_ip)
end_ip = end + str(end_num)
ips.append(end_ip)
except:
pass
return ips
# 判断是否为ipv6网段
@staticmethod
def is_ipv6_network_segment_or_ipv6_address(ip_datas: str) -> bool:
from ipaddress import IPv6Network, IPv6Address
try:
tmp_data = IPv6Network(ip_datas)
except:
try:
tmp_data = IPv6Address(ip_datas)
except:
return False
return True
# 添加入栈规则
def create_rules2(self, get):
'''
get 里面 有 protocol port type address brief 五个参数
protocol == ['tcp','udp']
port = 端口
types == [accept、drop] # 放行和禁止
address 地址允许放行的ip如果全部就是0.0.0.0/0;另外可以包含“,"或者"-"
表示区间IP
brief 备注说明
'''
protocol = get.protocol
ports = get.ports.strip()
types = get.types
address = get.source.strip()
port_list = ports.split(',')
result = self.check_port(port_list) # 检测端口
if result: return result
allow_ips = []
if address:
sources = [
sip.strip() for sip in address.split(",") if sip.strip()
]
rep2 = r"^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}(\/\d{1,2})?$"
_ips = []
for source_ip in sources:
if source_ip.find("-") != -1:
_ips += self.parse_ip_interval(source_ip)
else:
_ips.append(source_ip)
for source_ip in _ips:
if not re.search(rep2, source_ip) and not self.is_ipv6_network_segment_or_ipv6_address(source_ip):
return public.returnMsg(False, public.lang("IP address you've input is illegal!"))
allow_ips.append(source_ip)
if not allow_ips:
allow_ips.append("")
for source_ip in allow_ips:
if self.__isUfw:
for port in port_list:
if port.find('-') != -1:
port = port.replace('-', ':')
self.add_ufw_rule(source_ip, protocol, port, types)
else:
if self.__isFirewalld:
for port in port_list:
if port.find(':') != -1:
port = port.replace(':', '-')
self.add_firewall_rule(source_ip, protocol, port,
types)
else:
for port in port_list:
self.add_iptables_rule(source_ip, protocol, port, types)
# 添加入栈规则
def create_rules(self, get):
'''
get 里面 有 protocol port type address brief 五个参数
protocol == ['tcp','udp']
port = 端口
types == [accept、drop] # 放行和禁止
address 地址允许放行的ip如果全部就是0.0.0.0/0;另外可以包含“,"或者"-"
表示区间IP
brief 备注说明
'''
protocol = get.protocol
ports = get.ports.strip()
types = get.types
address = get.source.strip()
brief = get.brief.strip()
port_list = ports.split(',')
is_add = 2 if 'add' not in get else get.add
domain_total = '' if ("domain" not in get or not get.domain) else get.domain.strip()
domain = '' if ("domain" not in get or not get.domain) else get.domain.strip() + '|' + address
result = self.check_port(port_list) # 检测端口
if result: return result
allow_ips = []
if address:
sources = [sip.strip() for sip in address.split(",") if sip.strip()]
rep2 = r"^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}(\/\d{1,2})?$"
_ips = []
for source_ip in sources:
if source_ip.find("-") != -1:
_ips += self.parse_ip_interval(source_ip)
else:
_ips.append(source_ip)
for source_ip in _ips:
if not re.search(rep2, source_ip) and not self.is_ipv6_network_segment_or_ipv6_address(source_ip):
return public.returnMsg(False, public.lang("IP address you've input is illegal!"))
query_result = public.M('firewall_new').where(
'ports=? and address=? and protocol=? and types=?',
(ports, source_ip, protocol, types,)
).count()
if query_result > 0:
continue
allow_ips.append(source_ip)
if not allow_ips:
allow_ips.append("")
# 忽略的列表
ignore_list = []
addtime = time.strftime('%Y-%m-%d %X', time.localtime())
for source_ip in allow_ips:
for port in port_list:
if is_add == 1: continue
# 检测端口是否已经添加过
query_result = public.M('firewall_new').where(
'ports=? and address=? and protocol=? and types=?',
(port, source_ip, protocol, types,)
).find()
firewall_rules = self.get_sys_firewall_rules()
if query_result:
new_query_result = {"ports": query_result["ports"], "address": query_result["address"],
"protocol": query_result["protocol"], "types": query_result["types"]}
for firewall_rule in firewall_rules:
if new_query_result == firewall_rule:
ignore_list.append(port)
break
self._add_firewall_rules(source_ip, protocol, port, types)
if not query_result:
self._add_sid = public.M('firewall_new').add(
'ports,brief,protocol,address,types,addtime,domain,sid',
(port, public.xsssec(brief), protocol, source_ip, types, addtime, domain, 0)
)
if domain:
domain_sid = public.M('firewall_domain').add(
'types,domain,port,address,brief,addtime,sid,protocol,domain_total',
(types, domain, ports, address, public.xsssec(brief), addtime, self._add_sid, protocol,
domain_total)
)
public.M('firewall_new').where("id=?", (self._add_sid,)).save('sid', domain_sid)
if len(allow_ips) > 0:
self.FirewallReload()
if not get.source.strip():
log_ip = "All IPs"
else:
log_ip = get.source.strip()
strategy = ''
if types == 'accept':
strategy = "accept"
elif types == 'drop':
strategy = "drop"
public.WriteLog("system firewall",
"Add port rules: Protocol:{}, Port:{}, Policy:{}, IP:{}".format(protocol, ports, strategy, log_ip))
# 如果有忽略的端口,返回忽略的端口
if ignore_list:
return public.returnMsg(True,
'Added successfully, {} The same rule exists for the port and has been skipped'.format(
', '.join(ignore_list)))
return public.returnMsg(True, public.lang("Added successfully!"))
# 删除入栈规则
def remove_rules(self, get):
'''
get 里面有 id protocol port type address 五个参数
protocol == ['tcp','udp']
port = 端口
types == [accept、drop] # 放行和禁止
address 地址允许放行的ip
'''
# 检测是否开启防火墙 hezhihong
if not self.get_firewall_status():
return public.returnMsg(False, public.lang("Please enable the firewall before proceeding."))
id = get.id
address = get.address
protocol = get.protocol
ports = get.ports
types = get.types
self._del_firewall_rules(address, protocol, ports, types)
public.M('firewall_new').where("id=?", (id,)).delete()
self.FirewallReload()
if not get.address:
log_ip = "All IPs"
else:
log_ip = get.address
if types == 'accept':
strategy = "accept"
elif types == 'drop':
strategy = "drop"
public.WriteLog("system firewall",
"Delete port rules: Protocol:{}, Port:{}, Policy:{}, IP:{}".format(get.protocol, get.ports, types,
log_ip))
return public.returnMsg(True, public.lang("Delete successfully!"))
# 修改入栈规则
def modify_rules(self, get, addtime=None):
'''
get 里面有 id protocol port type address 五个参数
protocol == ['tcp','udp']
port = 端口
types==['reject','accept'] # 放行和禁止
address 地址允许放行的ip如果全部就是0.0.0.0/0
'''
# 检测是否开启防火墙 hezhihong
if not self.get_firewall_status():
return public.returnMsg(False, public.lang("Please enable the firewall before proceeding."))
id = get.id
protocol = get.protocol
ports = get.ports.strip()
types = get.types
address = get.source.strip()
brief = get.brief.strip()
domain = '' if 'domain' not in get else get.domain
domain_total = domain.split('|')[0]
sid = 0 if 'sid' not in get else get.sid
if address:
rep = r"^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}(\/\d{1,2})?$"
if not re.search(rep, get.source) and self.is_ipv6_network_segment_or_ipv6_address(get.source):
return public.returnMsg(False, public.lang("IP address you've input is illegal!"))
data = public.M('firewall_new').where('id=?', (id,)).field(
'id,address,protocol,ports,types,brief,addtime,domain'
).find()
if data:
_address = data.get("address", "")
_protocol = data.get("protocol", "")
_port = data.get("ports", "")
_type = data.get("types", "")
else:
_address = _protocol = _port = _type = ""
self._modify_firewall_rules(_address, _protocol, _port, _type, address, protocol, ports, types)
addtime = time.strftime('%Y-%m-%d %X', time.localtime())
public.M('firewall_new').where('id=?', id).update({
'address': address,
'protocol': protocol,
'ports': ports,
'types': types,
'brief': brief,
'addtime': addtime,
'sid': sid,
'domain': domain
}
)
if domain:
public.M('firewall_domain').where("id=?", (sid,)).save(
'sid,types,brief,protocol,domain_total',
(id, types, brief, protocol, domain_total)
)
with contextlib.suppress(Exception):
if int(ports) == 22: self.delete_service()
self.FirewallReload()
if not address:
log_ip = "All IPs"
else:
log_ip = address
if get.types == 'accept':
strategy = "accept"
elif get.types == 'drop':
strategy = "drop"
public.WriteLog("system firewall",
"Modify port rules Protocol:{}, Port:{}, Policy:{}, IP:{}".format(get.protocol, get.ports.strip(), get.types,
log_ip))
return public.returnMsg(True, public.lang("Added successfully!"))
# firewall端口规则添加
def add_firewall_rule(self, address, protocol, ports, types):
if not address:
if protocol.find('/') != -1:
if types == "accept":
public.ExecShell(
'firewall-cmd --permanent --zone=public --add-port=' +
ports + '/tcp')
public.ExecShell(
'firewall-cmd --permanent --zone=public --add-port=' +
ports + '/udp')
else:
public.ExecShell(
'firewall-cmd --permanent --add-rich-rule="rule family=ipv4 port protocol="tcp" port="%s" drop"'
% ports
)
public.ExecShell(
'firewall-cmd --permanent --add-rich-rule="rule family=ipv4 port protocol="udp" port="%s" drop"'
% ports
)
else:
if types == "accept":
public.ExecShell(
'firewall-cmd --permanent --zone=public --add-port=' +
ports + '/' + protocol + '')
else:
public.ExecShell(
'firewall-cmd --permanent --add-rich-rule="rule family=ipv4 port protocol="%s" port="%s" drop"'
% (protocol, ports))
return True
if self.is_ipv6_network_segment_or_ipv6_address(address):
if protocol.find('/') != -1:
public.ExecShell(
'firewall-cmd --permanent '
'--add-rich-rule="rule family=ipv6 source address="%s" port protocol="tcp" port="%s" %s"'
% (address, ports, types))
public.ExecShell(
'firewall-cmd --permanent '
'--add-rich-rule="rule family=ipv6 source address="%s" port protocol="udp" port="%s" %s"'
% (address, ports, types))
else:
public.ExecShell(
'firewall-cmd --permanent '
'--add-rich-rule="rule family=ipv6 source address="%s" port protocol="%s" port="%s" %s"'
% (address, protocol, ports, types))
else:
if protocol.find('/') != -1:
public.ExecShell(
'firewall-cmd --permanent '
'--add-rich-rule="rule family=ipv4 source address="%s" port protocol="tcp" port="%s" %s"'
% (address, ports, types))
public.ExecShell(
'firewall-cmd --permanent '
'--add-rich-rule="rule family=ipv4 source address="%s" port protocol="udp" port="%s" %s"'
% (address, ports, types))
else:
public.ExecShell(
'firewall-cmd --permanent '
'--add-rich-rule="rule family=ipv4 source address="%s" port protocol="%s" port="%s" %s"'
% (address, protocol, ports, types))
return True
# firewall端口规则删除
def del_firewall_rule(self, address, protocol, ports, types):
if not address:
if protocol.find('/') != -1:
if types == "accept":
public.ExecShell(
'firewall-cmd --permanent --zone=public --remove-port='
+ ports + '/tcp')
public.ExecShell(
'firewall-cmd --permanent --zone=public --remove-port='
+ ports + '/udp')
else:
public.ExecShell(
'firewall-cmd --permanent '
'--remove-rich-rule="rule family=ipv4 port protocol="tcp" port="%s" drop"'
% ports
)
public.ExecShell(
'firewall-cmd --permanent '
'--remove-rich-rule="rule family=ipv4 port protocol="udp" port="%s" drop"'
% ports
)
else:
if types == "accept":
public.ExecShell(
'firewall-cmd --permanent --zone=public --remove-port='
+ ports + '/' + protocol + '')
else:
public.ExecShell(
'firewall-cmd --permanent '
'--remove-rich-rule="rule family=ipv4 port protocol="%s" port="%s" drop"'
% (protocol, ports))
self.update_panel_data(ports)
return True
if self.is_ipv6_network_segment_or_ipv6_address(address):
if protocol.find('/') != -1:
public.ExecShell(
'firewall-cmd --permanent '
'--remove-rich-rule="rule family="ipv6" source address="%s" port protocol="tcp" port="%s" %s"'
% (address, ports, types))
public.ExecShell(
'firewall-cmd --permanent '
'--remove-rich-rule="rule family="ipv6" source address="%s" port protocol="udp" port="%s" %s"'
% (address, ports, types))
else:
public.ExecShell(
'firewall-cmd --permanent '
'--remove-rich-rule="rule family="ipv6" source address="%s" port protocol="%s" port="%s" %s"'
% (address, protocol, ports, types))
else:
if protocol.find('/') != -1:
public.ExecShell(
'firewall-cmd --permanent '
'--remove-rich-rule="rule family="ipv4" source address="%s" port protocol="tcp" port="%s" %s"'
% (address, ports, types))
public.ExecShell(
'firewall-cmd --permanent '
'--remove-rich-rule="rule family="ipv4" source address="%s" port protocol="udp" port="%s" %s"'
% (address, ports, types))
else:
public.ExecShell(
'firewall-cmd --permanent '
'--remove-rich-rule="rule family="ipv4" source address="%s" port protocol="%s" port="%s" %s"'
% (address, protocol, ports, types))
return True
# firewall端口规则编辑
def edit_firewall_rule(self, _address, _protocol, _port, _type, address,
protocol, ports, types):
if not _address:
if _protocol.find('/') != -1:
if _type == "accept":
public.ExecShell(
'firewall-cmd --permanent --zone=public --remove-port='
+ _port + '/tcp')
public.ExecShell(
'firewall-cmd --permanent --zone=public --remove-port='
+ _port + '/udp')
else:
public.ExecShell(
'firewall-cmd --permanent '
'--remove-rich-rule="rule family=ipv4 port protocol="tcp" port="%s" drop"'
% ports
)
public.ExecShell(
'firewall-cmd --permanent '
'--remove-rich-rule="rule family=ipv4 port protocol="udp" port="%s" drop"'
% ports
)
else:
if _type == "accept":
public.ExecShell(
'firewall-cmd --permanent --zone=public --remove-port='
+ _port + '/' + _protocol + '')
else:
public.ExecShell(
'firewall-cmd --permanent '
'--remove-rich-rule="rule family=ipv4 port protocol="%s" port="%s" drop"'
% (protocol, ports))
else:
if self.is_ipv6_network_segment_or_ipv6_address(address):
if _protocol.find('/') != -1:
public.ExecShell(
'firewall-cmd --permanent '
'--remove-rich-rule="rule family="ipv6" source address="%s" port protocol="tcp" port="%s" %s"'
% (_address, _port, _type))
public.ExecShell(
'firewall-cmd --permanent '
'--remove-rich-rule="rule family="ipv6" source address="%s" port protocol="udp" port="%s" %s"'
% (_address, _port, _type))
else:
public.ExecShell(
'firewall-cmd --permanent '
'--remove-rich-rule="rule family="ipv6" source address="%s" port protocol="%s" port="%s" %s"'
% (_address, _protocol, _port, _type))
else:
if _protocol.find('/') != -1:
public.ExecShell(
'firewall-cmd --permanent '
'--remove-rich-rule="rule family="ipv4" source address="%s" port protocol="tcp" port="%s" %s"'
% (_address, _port, _type))
public.ExecShell(
'firewall-cmd --permanent '
'--remove-rich-rule="rule family="ipv4" source address="%s" port protocol="udp" port="%s" %s"'
% (_address, _port, _type))
else:
public.ExecShell(
'firewall-cmd --permanent '
'--remove-rich-rule="rule family="ipv4" source address="%s" port protocol="%s" port="%s" %s"'
% (_address, _protocol, _port, _type))
if not address:
if protocol.find('/') != -1:
if types == "accept":
public.ExecShell(
'firewall-cmd --permanent --zone=public --add-port=' +
ports + '/tcp')
public.ExecShell(
'firewall-cmd --permanent --zone=public --add-port=' +
ports + '/udp')
else:
public.ExecShell(
'firewall-cmd --permanent '
'--add-rich-rule="rule family=ipv4 port protocol="tcp" port="%s" drop"'
% ports
)
public.ExecShell(
'firewall-cmd --permanent '
'--add-rich-rule="rule family=ipv4 port protocol="udp" port="%s" drop"'
% ports
)
else:
if types == "accept":
public.ExecShell(
'firewall-cmd --permanent --zone=public --add-port=' +
ports + '/' + protocol + '')
else:
public.ExecShell(
'firewall-cmd --permanent '
'--add-rich-rule="rule family=ipv4 port protocol="%s" port="%s" drop"'
% (protocol, ports))
else:
if self.is_ipv6_network_segment_or_ipv6_address(address):
if protocol.find('/') != -1:
public.ExecShell(
'firewall-cmd --permanent '
'--add-rich-rule="rule family=ipv6 source address="%s" port protocol="tcp" port="%s" %s"'
% (address, ports, types))
public.ExecShell(
'firewall-cmd --permanent '
'--add-rich-rule="rule family=ipv6 source address="%s" port protocol="udp" port="%s" %s"'
% (address, ports, types))
else:
public.ExecShell(
'firewall-cmd --permanent '
'--add-rich-rule="rule family=ipv6 source address="%s" port protocol="%s" port="%s" %s"'
% (address, protocol, ports, types))
else:
if protocol.find('/') != -1:
public.ExecShell(
'firewall-cmd --permanent '
'--add-rich-rule="rule family=ipv4 source address="%s" port protocol="tcp" port="%s" %s"'
% (address, ports, types))
public.ExecShell(
'firewall-cmd --permanent '
'--add-rich-rule="rule family=ipv4 source address="%s" port protocol="udp" port="%s" %s"'
% (address, ports, types))
else:
public.ExecShell(
'firewall-cmd --permanent '
'--add-rich-rule="rule family=ipv4 source address="%s" port protocol="%s" port="%s" %s"'
% (address, protocol, ports, types))
return True
# ufw 端口规则添加
def add_ufw_rule(self, address, protocol, ports, types):
rule = "allow" if types == "accept" else "deny"
if address == "":
if protocol.find('/') != -1:
# public.ExecShell('ufw ' + rule + ' ' + ports + '/tcp')
# public.ExecShell('ufw ' + rule + ' ' + ports + '/udp')
public.ExecShell('ufw ' + rule + ' ' + ports)
else:
public.ExecShell('ufw ' + rule + ' ' + ports + '/' + protocol + '')
else:
if protocol.find('/') != -1:
# public.ExecShell('ufw ' + rule + ' proto tcp from ' + address + ' to any port ' + ports + '')
# public.ExecShell('ufw ' + rule + ' proto udp from ' + address + ' to any port ' + ports + '')
public.ExecShell('ufw ' + rule + ' from ' + address + ' to any port ' + ports + '')
else:
public.ExecShell(
'ufw ' + rule + ' proto ' + protocol + ' from ' + address + ' to any port ' + ports + '')
# ufw 端口规则删除
def del_ufw_rule(self, address, protocol, ports, types):
rule = "allow" if types == "accept" else "deny"
if address == "":
if protocol.find('/') != -1:
public.ExecShell('ufw delete ' + rule + ' ' + ports + '/tcp')
public.ExecShell('ufw delete ' + rule + ' ' + ports + '/udp')
public.ExecShell('ufw delete ' + rule + ' ' + ports)
else:
public.ExecShell('ufw delete ' + rule + ' ' + ports + '/' + protocol + '')
else:
if protocol.find('/') != -1:
public.ExecShell('ufw delete ' + rule + ' proto tcp from ' + address + ' to any port ' + ports + '')
public.ExecShell('ufw delete ' + rule + ' proto udp from ' + address + ' to any port ' + ports + '')
public.ExecShell('ufw delete ' + rule + ' from ' + address + ' to any port ' + ports)
else:
public.ExecShell(
'ufw delete ' + rule + ' proto ' + protocol + ' from ' + address + ' to any port ' + ports + ''
)
self.update_panel_data(ports)
# ufw 端口规则修改
def edit_ufw_rule(self, _address, _protocol, _port, _type, address,
protocol, ports, types):
_rule = "allow" if _type == "accept" else "deny"
rules = "allow" if types == "accept" else "deny"
if _address == "":
if _protocol.find('/') != -1:
public.ExecShell('ufw delete ' + _rule + ' ' + _port + '/tcp')
public.ExecShell('ufw delete ' + _rule + ' ' + _port + '/udp')
public.ExecShell('ufw delete ' + _rule + ' ' + _port)
else:
public.ExecShell('ufw delete ' + _rule + ' ' + _port + '/' + _protocol + '')
else:
if _protocol.find('/') != -1:
public.ExecShell('ufw delete ' + _rule + ' proto tcp from ' + _address + ' to any port ' + _port + '')
public.ExecShell('ufw delete ' + _rule + ' proto udp from ' + _address + ' to any port ' + _port + '')
public.ExecShell('ufw delete ' + _rule + ' from ' + _address + ' to any port ' + _port)
else:
public.ExecShell(
'ufw delete ' + _rule + ' proto ' + _protocol + ' from ' + _address + ' to any port ' + _port + ''
)
if address == "":
if protocol.find('/') != -1:
# public.ExecShell('ufw ' + rules + ' ' + ports + '/tcp')
# public.ExecShell('ufw ' + rules + ' ' + ports + '/udp')
public.ExecShell('ufw ' + rules + ' ' + ports)
else:
public.ExecShell('ufw ' + rules + ' ' + ports + '/' + protocol + '')
else:
if protocol.find('/') != -1:
# public.ExecShell('ufw ' + rules + ' proto tcp from ' + address + ' to any port ' + ports + '')
# public.ExecShell('ufw ' + rules + ' proto udp from ' + address + ' to any port ' + ports + '')
public.ExecShell('ufw ' + rules + ' from ' + address + ' to any port ' + ports)
else:
public.ExecShell(
'ufw ' + rules + ' proto ' + protocol + ' from ' + address + ' to any port ' + ports + ''
)
# iptables端口规则添加
def add_iptables_rule(self, address, protocol, ports, types):
rule = "ACCEPT" if types == "accept" else "DROP"
if not address:
if protocol.find('/') != -1:
public.ExecShell(
'iptables -I INPUT -p tcp -m state --state NEW -m tcp --dport '
+ ports + ' -j ' + rule + '')
public.ExecShell(
'iptables -I INPUT -p tcp -m state --state NEW -m udp --dport '
+ ports + ' -j ' + rule + '')
else:
public.ExecShell(
'iptables -I INPUT -p tcp -m state --state NEW -m ' +
protocol + ' --dport ' + ports + ' -j ' + rule + '')
else:
if protocol.find('/') != -1:
public.ExecShell('iptables -I INPUT -s ' + address +
' -p tcp --dport ' + ports + ' -j ' + rule +
'')
public.ExecShell('iptables -I INPUT -s ' + address +
' -p udp --dport ' + ports + ' -j ' + rule +
'')
else:
public.ExecShell('iptables -I INPUT -s ' + address + ' -p ' +
protocol + ' --dport ' + ports + ' -j ' +
rule + '')
return True
# iptables端口规则删除
def del_iptables_rule(self, address, protocol, ports, types):
rule = "ACCEPT" if types == "accept" else "DROP"
if not address:
if protocol.find('/') != -1:
public.ExecShell(
'iptables -D INPUT -p tcp -m state --state NEW -m tcp --dport '
+ ports + ' -j ' + rule + '')
public.ExecShell(
'iptables -D INPUT -p tcp -m state --state NEW -m udp --dport '
+ ports + ' -j ' + rule + '')
else:
public.ExecShell(
'iptables -D INPUT -p tcp -m state --state NEW -m ' +
protocol + ' --dport ' + ports + ' -j ' + rule + '')
else:
if protocol.find('/') != -1:
public.ExecShell('iptables -D INPUT -s ' + address +
' -p tcp --dport ' + ports + ' -j ' + rule +
'')
public.ExecShell('iptables -D INPUT -s ' + address +
' -p udp --dport ' + ports + ' -j ' + rule +
'')
else:
public.ExecShell('iptables -D INPUT -s ' + address + ' -p ' +
protocol + ' --dport ' + ports + ' -j ' +
rule + '')
return True
# iptables端口规则编辑
def edit_iptables_rule(self, _address, _protocol, _port, _type, address,
protocol, ports, types):
rule1 = "ACCEPT" if _type == "accept" else "DROP"
rule2 = "ACCEPT" if types == "accept" else "DROP"
if not _address:
if _protocol.find('/') != -1:
public.ExecShell(
'iptables -D INPUT -p tcp -m state --state NEW -m tcp --dport '
+ _port + ' -j ' + rule1 + '')
public.ExecShell(
'iptables -D INPUT -p tcp -m state --state NEW -m udp --dport '
+ _port + ' -j ' + rule1 + '')
else:
public.ExecShell(
'iptables -D INPUT -p tcp -m state --state NEW -m ' +
_protocol + ' --dport ' + _port + ' -j ' + rule1 + '')
else:
if _protocol.find('/') != -1:
public.ExecShell('iptables -D INPUT -s ' + _address +
' -p tcp --dport ' + _port + ' -j ' + rule1 +
'')
public.ExecShell('iptables -D INPUT -s ' + _address +
' -p udp --dport ' + _port + ' -j ' + rule1 +
'')
else:
public.ExecShell('iptables -D INPUT -s ' + _address + ' -p ' +
_protocol + ' --dport ' + _port + ' -j ' +
rule1 + '')
if not address:
if protocol.find('/') != -1:
public.ExecShell(
'iptables -I INPUT -p tcp -m state --state NEW -m tcp --dport '
+ ports + ' -j ' + rule2 + '')
public.ExecShell(
'iptables -I INPUT -p tcp -m state --state NEW -m udp --dport '
+ ports + ' -j ' + rule2 + '')
else:
public.ExecShell(
'iptables -I INPUT -p tcp -m state --state NEW -m ' +
protocol + ' --dport ' + ports + ' -j ' + rule2 + '')
else:
if protocol.find('/') != -1:
public.ExecShell('iptables -I INPUT -s ' + address +
' -p tcp --dport ' + ports + ' -j ' + rule2 +
'')
public.ExecShell('iptables -I INPUT -s ' + address +
' -p udp --dport ' + ports + ' -j ' + rule2 +
'')
else:
public.ExecShell('iptables -I INPUT -s ' + address + ' -p ' +
protocol + ' --dport ' + ports + ' -j ' +
rule2 + '')
return True
# 修改面板数据
def update_panel_data(self, ports):
res = public.M('firewall').where("port=?", (ports,)).delete()
# 查询IP规则
def get_ip_rules_list(self, args):
p = 1
limit = 15
if 'p' in args: p = args.p
if 'limit' in args: limit = args.limit
where = '1=1'
sql = public.M('firewall_ip')
if hasattr(args, 'query'):
where = " address like '%{search}%' or brief like '%{search}%' ".format(
search=args.query)
count = sql.where(where, ()).count()
data = public.get_page(count, int(p), int(limit))
data['data'] = sql.where(where, ()).limit('{},{}'.format(
data['shift'], data['row'])).order('addtime desc').select()
data['data'] = public.return_area(data['data'], 'address')
return data
def check_a_ip(self, address):
"""
@name 检测A记录是否为域名
@author hezhihong
"""
if address:
if public.is_ipv4(address) or public.is_ipv6(address):
return address
if address[-1] == '.':
address = address[:-1]
if public.is_domain(address): return self.get_a_ip(address)
return address
def get_a_ip(self, hostname):
'''
@name 检测主机名是否有A记录
@author hezhihong
:param hostname:
:return:
'''
if not self.install_dnspython():
return public.returnMsg(False, public.lang("Please install dnspython module first: btpip install dnspython"))
import dns.resolver
# 尝试3次
a_ip = []
for i in range(3):
try:
resolver = dns.resolver.Resolver()
resolver.timeout = 1
try:
result = resolver.query(hostname, 'A')
except:
result = resolver.resolve(hostname, 'A')
for i in result.response.answer:
for j in i.items:
try:
A_ip = str(j).strip()
if A_ip[-1] == '.':
A_ip = A_ip[:-1]
except:
pass
if A_ip not in a_ip:
a_ip.append(A_ip)
except:
pass
# 去除域名
if len(a_ip) > 1:
for i2 in a_ip:
if public.is_ipv4(i2) or public.is_ipv6(i2):
continue
if public.is_domain(i2):
a_ip.remove(i2)
return a_ip
def install_dnspython(self):
"""
@name 安装dnspython模块
@author hezhihong
"""
# 检测dns解析
try:
import dns.resolver
return True
except:
if os.path.exists('/www/server/panel/pyenv'):
public.ExecShell('/www/server/panel/pyenv/bin/pip install dnspython')
else:
public.ExecShell('pip3 install dnspython')
try:
import dns.resolver
return True
except:
return False
def del_domain_ip(self, args):
"""
@name 删除域名设置
@author hezhihong
"""
if 'id' not in args or not args.id or 'sid' not in args:
return public.returnMsg(False, public.lang("Parameter error"))
domain_id = int(args.sid)
# 删除IP规则
if domain_id > 0:
# 删除域名解析
public.M('firewall_domain').where('id=?', (str(domain_id),)).delete()
# 删除端口规则
if 'ports' in args:
self.remove_rules(args)
# 删除IP规则
else:
self.remove_ip_rules(args)
# 当没有域名解析时,删除计划任务
if not public.M('firewall_domain').count():
pdata = public.M('crontab').where('name=?',
'[Do not delete] System firewall domain name resolution detection task').select()
if pdata:
for i in pdata:
args = {"id": i['id']}
import crontab
crontab.crontab().DelCrontab(args)
return public.returnMsg(True, public.lang("successfully deleted"))
def add_crontab(self):
"""
@name 构造日志切割任务
@author hezhihong
"""
python_path = ''
try:
python_path = public.ExecShell('which btpython')[0].strip("\n")
except:
try:
python_path = public.ExecShell('which python')[0].strip("\n")
except:
pass
if not python_path: return False
if not public.M('crontab').where('name=?', (
'[Do not delete] System firewall domain name resolution detection task',)).count():
cmd = '{} {}'.format(python_path, '/www/server/panel/script/firewall_domain.py')
args = {"name": "[Do not delete] System firewall domain name resolution detection task", "type": 'minute-n',
"where1": '5', "hour": '',
"minute": '', "sName": "",
"sType": 'toShell', "notice": '', "notice_channel": '', "save": '', "save_local": '1',
"backupTo": '', "sBody": cmd,
"urladdress": ''}
import crontab
res = crontab.crontab().AddCrontab(args)
if res and "id" in res.keys():
return True
return False
return True
def __check_auth(self):
try:
from pluginAuth import Plugin
plugin_obj = Plugin(False)
plugin_list = plugin_obj.get_plugin_list()
if int(plugin_list['ltd']) > time.time():
return True
return False
except:
return False
def set_domain_ip2(self, args):
"""
@name 设置域名规则
@author hezhihong
"""
pay = self.__check_auth()
if not pay: return public.returnMsg(False, public.lang("Current features are exclusive to the professional version"))
if not args.domain: return public.returnMsg(False, public.lang("Please enter domain name"))
ports = ''
if 'ports' in args and args.ports: ports = args.ports
ip = args.source
# 添加计划任务
self.add_crontab()
# 添加端口规则
# {"protocol":"tcp","ports":"819","choose":"point","address":"125.93.252.236","types":"accept","brief":"","source":"125.93.252.236"}
args.address = ip
args.source = ip
if ports:
if public.is_ipv6(ip):
return public.returnMsg(False, public.lang("The domain name is resolved to an IPv6 address and port rules are not supported."))
self.create_rules2(args)
# 添加IP规则
else:
# return 333
self.create_ip_rules(args)
return public.returnMsg(True, public.lang("Domain name {} resolution added successfully", args.domain))
def set_domain_ip(self, args):
"""
@name 设置域名规则
@author hezhihong
"""
pay = self.__check_auth()
if not pay: return public.returnMsg(False, public.lang("Current features are exclusive to the professional version"))
if not args.domain: return public.returnMsg(False, public.lang("Please enter domain name"))
ports = ''
if 'ports' in args and args.ports: ports = args.ports
protocol = '' if 'protocol' not in args else args.protocol
a_ip = self.get_a_ip(args.domain)
# return a_ip
if a_ip and len(a_ip) < 2 and public.is_domain(a_ip[0]):
# return 111
a_ip = [self.check_a_ip(a_ip[0])]
# return a_ip
if not a_ip:
return public.returnMsg(False, public.lang("The domain name resolution has not been resolved or the resolution has not taken effect. If it has been resolved, please try again after 10 minutes."))
if public.M('firewall_domain').where("domain=? and types=? and port=? and protocol=?",
(args.domain, args.types, ports, protocol,)).count():
return public.returnMsg(False, public.lang("Domain name {} already exists", args.domain))
# 添加计划任务
self.add_crontab()
# 添加端口规则
# {"protocol":"tcp","ports":"819","choose":"point","address":"125.93.252.236","types":"accept","brief":"","source":"125.93.252.236"}
for ip in a_ip:
args.address = ip
args.source = ip
if ports:
if public.is_ipv6(ip):
return public.returnMsg(False, public.lang("The domain name is resolved to an IPv6 address and port rules are not supported."))
self.create_rules(args)
# 添加IP规则
else:
# return 333
self.create_ip_rules(args)
return public.returnMsg(True, public.lang("Domain name {} resolution added successfully", args.domain))
def modify_domain_ip(self, args):
"""
@name 修改域名规则(当修改为指定域名或从指定域名修改为其他时,需要调用此方法)
@name hezhihong
"""
pay = self.__check_auth()
if not pay: return public.returnMsg(False, public.lang("Current features are exclusive to the professional version"))
# 检测是否开启防火墙 hezhihong
if not self.get_firewall_status():
return public.returnMsg(False, public.lang("Please enable the firewall before proceeding."))
modify_args = public.dict_obj()
modify_args.id = args.id
modify_args.types = args.types
modify_args.brief = args.brief
modify_args.address = args.address
modify_args.sid = 0 if 'sid' not in args else args.sid
ports = '' if 'ports' not in args else args.ports
domain = '' if 'domain' not in args else args.domain
if ports: modify_args.ports = ports
choose = '' if 'choose' not in args else args.choose
pdata = {}
if int(args.sid) > 0:
pdata = public.M('firewall_domain').where('id=?', (args.sid,)).find()
# 修改端口规则
if ports:
modify_args.protocol = args.protocol
# 已经指定域名
if int(args.sid) > 0:
# 当修改为指定域名时
if choose == 'domain':
# 当修改为不同域名时
if domain != pdata['domain']:
self.del_domain_ip(args)
self.set_domain_ip(args)
# 当修改为相同域名时
else:
pdata['protocol'] = args.protocol
pdata['types'] = args.types
pdata['brief'] = public.xsssec(args.brief)
addtime = time.strftime('%Y-%m-%d %X', time.localtime())
pdata['addtime'] = addtime
public.M('firewall_domain').where('id=?', pdata['id']).update(pdata)
self.modify_rules(args)
return public.returnMsg(True, public.lang("Successfully modified"))
else:
args.domain = ''
self.del_domain_ip(args)
self.create_rules(args)
return public.returnMsg(True, public.lang("Successfully modified"))
# 当未指定域名时
else:
# 修改为指定域名
if domain:
self.remove_rules(args)
self.set_domain_ip(args)
return public.returnMsg(True, public.lang("Successfully modified"))
# 修改IP规则
else:
if int(args.sid) > 0:
modify_args.address = pdata['address']
modify_args.domain = pdata['domain']
return self.modify_ip_rules(modify_args)
# IP地址检测
def check_ip(self, address_list):
rep = r"^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}(\/\d{1,2})?$"
for address in address_list:
address = address.split('/')[0]
if address.find('-') != -1:
addresses = address.split('-')
if addresses[0] >= addresses[1]:
return public.returnMsg(False, public.lang("IP address you've input is illegal!"))
s_ips = addresses[0].split(".")
e_ips = addresses[1].split(".")
head_s_ip = s_ips[0] + "." + s_ips[1] + "." + s_ips[2] + "."
head_e_ip = e_ips[0] + "." + e_ips[1] + "." + e_ips[2] + "."
if head_s_ip != head_e_ip:
return public.returnMsg(False, public.lang("IP address you've input is illegal!"))
if not re.search(rep, addresses[0]):
return public.returnMsg(False, public.lang("IP address you've input is illegal!"))
if not re.search(rep, addresses[1]):
return public.returnMsg(False, public.lang("IP address you've input is illegal!"))
else:
if not re.search(rep, address) and not public.is_ipv6(address):
return public.returnMsg(False, public.lang("IP address you've input is illegal!"))
# 获取IP范围
def get_ip(self, address):
result = []
arrys = address.split("-")
s_ips = arrys[0].split(".")
e_ips = arrys[1].split(".")
head_s_ip = s_ips[0] + "." + s_ips[1] + "." + s_ips[2] + "."
region = int(e_ips[-1]) - int(s_ips[-1])
for num in range(0, region + 1):
result.append(head_s_ip + str(num + int(s_ips[-1])))
return result
def handle_firewall_ip(self, address, types):
ip_list = self.get_ip(address)
if isinstance(ip_list, dict):
return
public.ExecShell(
'firewall-cmd --permanent --zone=public --new-ipset=' + address +
' --type=hash:net')
xml_path = "/etc/firewalld/ipsets/%s.xml" % address
tree = ElementTree()
tree.parse(xml_path)
root = tree.getroot()
for ip in ip_list:
entry = Element("entry")
entry.text = ip
root.append(entry)
self.format(root)
tree.write(xml_path, 'utf-8', xml_declaration=True)
# public.ExecShell('firewall-cmd --permanent --zone=public --add-rich-rule=\'rule source ipset="'+ address +'" accept\'')
public.ExecShell(
'firewall-cmd --permanent --zone=public --add-rich-rule=\'rule source ipset="'
+ address + '" ' + types + '\'')
def handle_ufw_ip(self, address, types):
ip_list = self.get_ip(address)
if isinstance(ip_list, dict):
return
public.ExecShell('ipset create ' + address + ' hash:net')
for ip in ip_list:
public.ExecShell('ipset add ' + address + ' ' + ip)
public.ExecShell('iptables -I INPUT -m set --match-set ' + address +
' src -j ' + types.upper())
# 检查IP地址是否在范围内
def ip_in_range(self, ip, ip_range):
import ipaddress
# 2024/1/3 下午 7:59 兼容192.168.0.0/24这种形式
if ip_range.find('/') != -1:
return ipaddress.ip_address(ip) in ipaddress.ip_network(ip_range)
ip_range = ip_range.split('-')
if len(ip_range) == 1: # 如果只有一个IP地址
return ipaddress.ip_address(ip) == ipaddress.ip_address(ip_range[0])
else: # 如果是一个IP范围
start_ip, end_ip = ip_range
ip_networks = ipaddress.summarize_address_range(ipaddress.ip_address(start_ip), ipaddress.ip_address(end_ip))
return any(ipaddress.ip_address(ip) in net for net in ip_networks)
# 添加IP规则
def create_ip_rules(self, get):
from flask import request
user_ip = request.remote_addr
_address = get.address.strip()
original_types = get.types
brief = get.brief
domain_total = '' if ('domain' not in get or not get.domain) else get.domain.strip()
domain = '' if ('domain' not in get or not get.domain) else get.domain.strip() + '|' + _address
address_list = _address.split(',')
# public.print_log('############ ip接口 {}'.format(address_list))
result = self.check_ip(address_list)
if result:
return result
# 先处理用户的IP地址
old_login_ip = public.M('firewall_ip').where("brief=?", ("IP that allows users to log in",)).field(
'id, address').select()
# public.print_log('############ ip接口user_ip {}'.format(user_ip))
for ip_range in address_list:
if self.ip_in_range(user_ip, ip_range):
if old_login_ip and old_login_ip[0][' address'] != user_ip:
address = old_login_ip[0][' address']
public.M('firewall_ip').where("address=?", (address,)).delete()
self.update_panel_data(address) # 删除面板自带防火墙的表数据
self.add_rule(user_ip, "accept", "IP that allows users to log in", domain, domain_total)
break
# 然后处理其他的IP地址
for address in address_list:
self.add_rule(address, original_types, brief, domain, domain_total)
self.FirewallReload()
public.WriteLog("system firewall", "Add IP rules: IP: {}, policy: {}".format(_address, original_types))
return public.returnMsg(True, public.lang("Added successfully!"))
# 添加单个IP规则
def add_rule(self, address, types, brief, domain, domain_total):
if public.M('firewall_ip').where("address=? and types=? and domain=?", (address, types, domain)).count() > 0:
return
if self.__isUfw:
# public.print_log('############ ip接口 1')
_rule = "allow" if types == "accept" else "deny"
if address.find('-') != -1:
# public.print_log('############!!! ip接口 2')
self.handle_ufw_ip(address, types)
else:
# public.print_log('############!!! ip接口 3')
is_debian = True if public.get_os_version().lower().find("debian") != -1 else False
if not is_debian:
if _rule == "allow":
if public.is_ipv6(address):
public.ExecShell('ufw ' + _rule + ' from ' + address + ' to any')
else:
public.ExecShell('ufw insert 1 ' + _rule + ' from ' + address + ' to any')
else:
public.ExecShell('ufw ' + _rule + ' from ' + address + ' to any')
else:
public.ExecShell('iptables -I INPUT -s ' + address + ' -j ' + types.upper())
else:
# public.print_log('############!!! ip接口 4')
if self.__isFirewalld:
# public.print_log('############ ip接口 6')
if address.find('-') != -1:
self.handle_firewall_ip(address, types)
else:
if types == "accept":
public.ExecShell('firewall-cmd --permanent --add-source=' + address + ' --zone=trusted')
else:
if public.is_ipv6(address):
public.ExecShell(
'firewall-cmd --permanent --add-rich-rule=\'rule family=ipv6 source address="' + address + '" ' + types + '\'')
else:
public.ExecShell(
'firewall-cmd --permanent --add-rich-rule=\'rule family=ipv4 source address="' + address + '" ' + types + '\'')
else:
# public.print_log('############ ip接口 7')
if address.find('-') != -1:
self.handle_ufw_ip(address, types)
else:
public.ExecShell('iptables -I INPUT -s ' + address + ' -j ' + types.upper())
addtime = time.strftime('%Y-%m-%d %X', time.localtime())
self._add_sid = public.M('firewall_ip').add('address,types,brief,addtime,domain,sid',
(address, types, public.xsssec(brief), addtime, domain, 0,))
# public.print_log('############ ip接口 8{}'.format(self._add_sid))
if domain:
# public.print_log('############ ip接口9{}'.format(domain))
domain_sid = public.M('firewall_domain').add(
'types,domain,port,address,brief,addtime,sid,protocol,domain_total', (
types, domain, '', address, public.xsssec(brief), addtime, self._add_sid, '', domain_total))
public.M('firewall_ip').where("id=?", (self._add_sid,)).save('sid', domain_sid)
# 删除All IPs规则
def remove_all_ip_rules(self, get):
ip_list = public.M('firewall_ip').select()
for ip in ip_list:
id = ip["id"]
address = ip["address"]
types = ip["types"]
if self.__isUfw:
_rule = "allow" if types == "accept" else "deny"
if address.find('-') != -1:
public.ExecShell('iptables -D INPUT -m set --match-set ' +
address + ' src -j ' + types.upper())
public.ExecShell('ipset destroy ' + address)
else:
is_debian = True if public.get_os_version().lower().find(
"debian") != -1 else False
if not is_debian:
public.ExecShell('ufw delete ' + _rule + ' from ' + address + ' to any')
else:
public.ExecShell("iptables -D INPUT -s " + address +
" -j " + types.upper())
else:
if self.__isFirewalld:
if address.find('-') != -1:
public.ExecShell(
'firewall-cmd --permanent --zone=public --remove-rich-rule=\'rule source ipset="'
+ address + '" ' + types + '\'')
public.ExecShell(
'firewall-cmd --permanent --zone=public --delete-ipset='
+ address)
else:
public.ExecShell(
'firewall-cmd --permanent --remove-source=' +
address + ' --zone=trusted')
if public.is_ipv6(address):
public.ExecShell(
'firewall-cmd --permanent --remove-rich-rule=\'rule family=ipv6 source address="'
+ address + '" ' + types + '\'')
else:
public.ExecShell(
'firewall-cmd --permanent --remove-rich-rule=\'rule family=ipv4 source address="'
+ address + '" ' + types + '\'')
else:
if address.find('-') != -1:
public.ExecShell(
'iptables -D INPUT -m set --match-set ' + address +
' src -j ' + types.upper())
public.ExecShell('ipset destroy ' + address)
else:
public.ExecShell('iptables -D INPUT -s ' + address +
' -j ' + types.upper())
public.M('firewall_ip').where("id=?", (id,)).delete()
self.update_panel_data(address) # 删除面板自带防火墙的表数据
self.FirewallReload()
return public.returnMsg(True, public.lang("All IP rules have been removed."))
# 删除IP规则
def remove_ip_rules(self, get):
id = get.id
address = get.address
types = get.types
if self.__isUfw:
_rule = "allow" if types == "accept" else "deny"
if address.find('-') != -1:
public.ExecShell('iptables -D INPUT -m set --match-set ' +
address + ' src -j ' + types.upper())
public.ExecShell('ipset destroy ' + address)
else:
is_debian = True if public.get_os_version().lower().find(
"debian") != -1 else False
if not is_debian:
public.ExecShell('ufw delete ' + _rule + ' from ' + address + ' to any')
else:
public.ExecShell('ufw delete ' + _rule + ' from ' + address + ' to any')
public.ExecShell("iptables -D INPUT -s " + address +
" -j " + types.upper())
else:
if self.__isFirewalld:
if address.find('-') != -1:
public.ExecShell(
'firewall-cmd --permanent --zone=public --remove-rich-rule=\'rule source ipset="'
+ address + '" ' + types + '\'')
public.ExecShell(
'firewall-cmd --permanent --zone=public --delete-ipset='
+ address)
else:
public.ExecShell(
'firewall-cmd --permanent --remove-source=' + address +
' --zone=trusted')
if public.is_ipv6(address):
public.ExecShell(
'firewall-cmd --permanent --remove-rich-rule=\'rule family=ipv6 source address="'
+ address + '" ' + types + '\'')
else:
public.ExecShell(
'firewall-cmd --permanent --remove-rich-rule=\'rule family=ipv4 source address="'
+ address + '" ' + types + '\'')
else:
if address.find('-') != -1:
public.ExecShell('iptables -D INPUT -m set --match-set ' +
address + ' src -j ' + types.upper())
public.ExecShell('ipset destroy ' + address)
else:
public.ExecShell('iptables -D INPUT -s ' + address +
' -j ' + types.upper())
public.M('firewall_ip').where("id=?", (id,)).delete()
self.update_panel_data(address) # 删除面板自带防火墙的表数据
self.FirewallReload()
strategy = ''
if get.types == 'accept':
strategy = "accept"
elif get.types == 'drop':
strategy = "drop"
public.WriteLog("system firewall", "Delete IP rules: IP:{}, policy:{}".format(get.address, strategy))
return public.returnMsg(True, public.lang("Delete successfully!"))
# 修改IP规则
def modify_ip_rules(self, get):
id = get.id
address = get.address.strip()
types = get.types
brief = get.brief
result = self.check_ip([address])
sid = 0 if 'sid' not in get else get.sid
domain = '' if 'domain' not in get else get.domain
domain_total = domain.split('|')[0]
# return 22
if result:
return result
data = public.M('firewall_ip').where(
'id=?', (id,)).field('id,address,types,brief,addtime').find()
_address = data.get("address", "")
_type = data.get("types", "")
if self.__isUfw:
rule1 = "allow" if _type == "accept" else "deny"
if _address.find('-') != -1:
public.ExecShell('iptables -D INPUT -m set --match-set ' +
_address + ' src -j ' + _type.upper())
public.ExecShell('ipset destroy ' + _address)
else:
is_debian = True if public.get_os_version().lower().find(
"debian") != -1 else False
if not is_debian:
public.ExecShell('ufw delete ' + rule1 + ' from ' + address + ' to any')
else:
cmd = "iptables -D INPUT -s " + address + " -j " + _type.upper(
)
public.ExecShell(cmd)
# public.ExecShell('ufw delete ' + rule1 + ' from ' + _address + ' to any')
rule2 = "allow" if types == "accept" else "deny"
if address.find('-') != -1:
self.handle_ufw_ip(address, types)
else:
is_debian = True if public.get_os_version().lower().find(
"debian") != -1 else False
if not is_debian:
if rule2 == "allow":
if public.is_ipv6(address):
public.ExecShell('ufw ' + rule2 + ' from ' + address + ' to any')
else:
public.ExecShell('ufw insert 1 ' + rule2 + ' from ' + address + ' to any')
else:
public.ExecShell('ufw ' + rule2 + ' from ' + address + ' to any')
else:
public.ExecShell('iptables -I INPUT -s ' + address +
' -j ' + types.upper())
else:
if self.__isFirewalld:
if _address.find('-') != -1:
public.ExecShell(
'firewall-cmd --permanent --zone=public --remove-rich-rule=\'rule source ipset="'
+ _address + '" ' + _type + '\'')
public.ExecShell(
'firewall-cmd --permanent --zone=public --delete-ipset='
+ _address)
else:
public.ExecShell(
'firewall-cmd --permanent --remove-source=' +
_address + ' --zone=trusted')
if public.is_ipv6(address):
public.ExecShell(
'firewall-cmd --permanent --remove-rich-rule=\'rule family=ipv6 source address="'
+ _address + '" ' + _type + '\'')
else:
public.ExecShell(
'firewall-cmd --permanent --remove-rich-rule=\'rule family=ipv4 source address="'
+ _address + '" ' + _type + '\'')
if address.find('-') != -1:
brief = address
self.handle_firewall_ip(address, types)
else:
if types == "accept":
public.ExecShell(
'firewall-cmd --permanent --add-source=' +
address + ' --zone=trusted')
else:
if public.is_ipv6(address):
public.ExecShell(
'firewall-cmd --permanent --add-rich-rule=\'rule family=ipv6 source address="'
+ address + '" ' + types + '\'')
else:
public.ExecShell(
'firewall-cmd --permanent --add-rich-rule=\'rule family=ipv4 source address="'
+ address + '" ' + types + '\'')
else:
if _address.find('-') != -1:
public.ExecShell('iptables -D INPUT -m set --match-set ' +
_address + ' src -j ' + types.upper())
public.ExecShell('ipset destroy ' + _address)
else:
public.ExecShell('iptables -D INPUT -s ' + _address +
' -j ' + _type.upper())
if address.find('-') != -1:
self.handle_ufw_ip(address, types)
else:
public.ExecShell('iptables -I INPUT -s ' + address +
' -j ' + types.upper())
addtime = time.strftime('%Y-%m-%d %X', time.localtime())
public.M('firewall_ip').where('id=?', id).update(
{'address': address, 'types': types, 'brief': brief, 'addtime': addtime, 'sid': sid, 'domain': domain})
if domain:
public.M('firewall_domain').where('id=?', (sid,)).save('sid,types,brief,domain_total',
(id, types, brief, domain_total))
self.FirewallReload()
old_strategy = ''
if types == 'accept':
old_strategy = "accept"
elif types == 'drop':
old_strategy = "drop"
if get.types == 'accept':
strategy = "accept"
elif get.types == 'drop':
strategy = "drop"
public.WriteLog("system firewall",
"修改规则, IP:{}, 策略:{} -> IP:{}, 策略:{}".format(_address, old_strategy, get.address.strip(),
get.types))
return public.returnMsg(True, public.lang("Successful operation"))
# 查看端口转发状态
def trans_status(self):
content = dict()
with open(self._trans_status, 'r') as fr:
content = json.loads(fr.read())
if content["status"] == "open":
return True
self.open_forward()
content["status"] = "open"
with open(self._trans_status, 'w') as fw:
fw.write(json.dumps(content))
return True
# 查询端口转发
def get_forward_list(self, args):
result = self.trans_status()
p = 1
limit = 15
if 'p' in args: p = args.p
if 'limit' in args: limit = args.limit
where = '1=1'
sql = public.M('firewall_trans')
if hasattr(args, 'query'):
where = " start_port like '%{search}%'".format(search=args.query)
count = sql.where(where, ()).count()
data = public.get_page(count, int(p), int(limit))
data['data'] = sql.where(where, ()).limit('{},{}'.format(
data['shift'], data['row'])).order('addtime desc').select()
return data
# 添加端口转发
def create_forward(self, get):
s_port = get.s_ports.strip() # 起始端口
d_port = get.d_ports.strip() # 目的端口
d_ip = get.d_address.strip() # 目的ip
protocol = get.protocol
rep1 = r"^\d{1,5}(:\d{1,5})?$"
if not re.search(rep1, s_port):
return public.returnMsg(False, public.lang("Port range is incorrect!"))
if not re.search(rep1, d_port):
return public.returnMsg(False, public.lang("Port range is incorrect!"))
rep = r"^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}(\/\d{1,2})?$"
if d_ip:
if not re.search(rep, get.d_address) and not public.is_ipv6(
get.d_address):
return public.returnMsg(False, public.lang("IP address you've input is illegal!"))
if d_ip in ["127.0.0.1", "localhost"]:
d_ip = ""
if public.M('firewall_trans').where("start_port=?",
(s_port,)).count() > 0:
return public.returnMsg(False, public.lang("This port already exists, please do not add it again!"))
if self.__isUfw:
content = self.ufw_handle_add(s_port, d_port, d_ip, protocol)
self.save_profile(self._ufw_before, content)
else:
if self.__isFirewalld:
self.firewall_handle_add(s_port, d_port, d_ip, protocol)
else:
self.iptables_handle_add(s_port, d_port, d_ip, protocol)
addtime = time.strftime('%Y-%m-%d %X', time.localtime())
public.M('firewall_trans').add(
'start_port, ended_ip, ended_port, protocol, addtime',
(s_port, d_ip, d_port, protocol, addtime))
self.FirewallReload()
public.WriteLog("system firewall",
"Add port forwarding rules: Start port: {}, Destination port: {}, Destination IP: {}".format(s_port,
d_port,
d_ip))
return public.returnMsg(True, public.lang("Added successfully!"))
# 删除端口转发
def remove_forward(self, get):
id = get.id
s_port = get.s_port
d_port = get.d_port
d_ip = get.d_ip
protocol = get.protocol
if self.__isUfw:
content = self.ufw_handle_del(s_port, d_port, d_ip, protocol)
self.save_profile(self._ufw_before, content)
else:
if self.__isFirewalld:
self.firewall_handle_del(s_port, d_port, d_ip, protocol)
else:
self.iptables_handle_del(s_port, d_port, d_ip, protocol)
public.M('firewall_trans').where("id=?", (id,)).delete()
self.FirewallReload()
public.WriteLog("system firewall",
"Delete port forwarding rules: Start port: {}, Destination port: {}, Destination IP: {}".format(
s_port, d_port, d_ip))
return public.returnMsg(True, public.lang("Delete successfully!"))
# 修改端口转发
def modify_forward(self, get):
id = get.id
s_port = get.s_ports.strip()
d_port = get.d_ports.strip()
d_ip = get.d_address.strip()
pool = get.protocol
rep1 = r"^\d{1,5}(:\d{1,5})?$"
if not re.search(rep1, s_port):
return public.returnMsg(False, public.lang("Port range is incorrect!"))
if not re.search(rep1, d_port):
return public.returnMsg(False, public.lang("Port range is incorrect!"))
data = public.M('firewall_trans').where('id=?', (id,)).field(
'id,start_port,ended_ip,ended_port,protocol,addtime').find()
start_port = data.get("start_port", "")
ended_ip = data.get("ended_ip", "")
ended_port = data.get("ended_port", "")
protocol = data.get("protocol", "")
if d_ip:
rep = r"^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}(\/\d{1,2})?$"
if not re.search(rep, get.d_address) and not public.is_ipv6(
get.d_address):
return public.returnMsg(False, public.lang("IP address you've input is illegal!"))
if d_ip in ["127.0.0.1", "localhost"]:
d_ip = ""
if self.__isUfw:
content = self.ufw_handle_update(start_port, ended_ip, ended_port,
protocol, s_port, d_ip, d_port,
pool)
self.save_profile(self._ufw_before, content)
else:
if self.__isFirewalld:
self.firewall_handle_update(start_port, ended_ip, ended_port,
protocol, s_port, d_ip, d_port,
pool)
else:
self.iptables_handle_update(start_port, ended_ip, ended_port,
protocol, s_port, d_ip, d_port,
pool)
addtime = time.strftime('%Y-%m-%d %X', time.localtime())
public.M('firewall_trans').where('id=?', id).update(
{'start_port': s_port, "ended_ip": d_ip, "ended_port": d_port, "protocol": pool})
self.FirewallReload()
public.WriteLog("system firewall",
"Modify port forwarding rules: Start port: {}, Destination port: {}, Destination IP: {} -> Start port: {}, Destination port: {}, Destination IP: {}".format(
start_port, ended_port, ended_ip, s_port, d_port, d_ip))
return public.returnMsg(True, public.lang("Successful operation."))
# 处理ufw的端口转发添加
def ufw_handle_add(self, s_port, d_port, d_ip, protocol):
content = self.get_profile(self._ufw_before)
if content.find('*nat') == -1:
content = "*nat\n" + ":PREROUTING ACCEPT [0:0]\n" + ":POSTROUTING ACCEPT [0:0]\n" + "COMMIT\n" + content
array = content.split('\n')
result = array.index(":POSTROUTING ACCEPT [0:0]")
if d_ip == "":
if protocol.find('/') != -1:
_string = "-A PREROUTING -p tcp --dport {1} -j REDIRECT --to-port {2}\n".format(
s_port, d_port)
_string = _string + "-A PREROUTING -p udp --dport {1} -j REDIRECT --to-port {2}".format(
s_port, d_port)
else:
_string = "-A PREROUTING -p {0} --dport {1} -j REDIRECT --to-port {2}".format(
protocol, s_port, d_port)
else:
_string = "-A PREROUTING -p {0} --dport {1} -j DNAT --to-destination {2}:{3}\n".format(
protocol, s_port, d_ip,
d_port) + "-A POSTROUTING -d {0} -j MASQUERADE".format(d_ip)
array.insert(result + 1, _string)
return '\n'.join(array)
# 处理ufw的端口转发删除
def ufw_handle_del(self, s_port, d_port, d_ip, protocol):
content = self.get_profile(self._ufw_before)
if d_ip == "":
_string = "-A PREROUTING -p {0} --dport {1} -j REDIRECT --to-port {2}\n".format(
protocol, s_port, d_port)
else:
_string = "-A PREROUTING -p {0} --dport {1} -j DNAT --to-destination {2}:{3}\n".format(
protocol, s_port, d_ip,
d_port) + "-A POSTROUTING -d {0} -j MASQUERADE\n".format(d_ip)
content = content.replace(_string, "")
return content
# 处理ufw的端口转发修改
def ufw_handle_update(self, start_port, ended_ip, ended_port, protocol,
s_port, d_ip, d_port, pool):
content = self.get_profile(self._ufw_before)
if ended_ip == "":
s_string = "-A PREROUTING -p {0} --dport {1} -j REDIRECT --to-port {2}\n".format(
protocol, start_port, ended_port)
else:
s_string = "-A PREROUTING -p {0} --dport {1} -j DNAT --to-destination {2}:{3}\n".format(
protocol, start_port, ended_ip, ended_port
) + "-A POSTROUTING -d {0} -j MASQUERADE\n".format(ended_ip)
if d_ip == "":
d_string = "-A PREROUTING -p {0} --dport {1} -j REDIRECT --to-port {2}\n".format(
pool, s_port, d_port)
else:
d_string = "-A PREROUTING -p {0} --dport {1} -j DNAT --to-destination {2}:{3}\n".format(
pool, s_port, d_ip,
d_port) + "-A POSTROUTING -d {0} -j MASQUERADE\n".format(d_ip)
content = content.replace(s_string, d_string)
return content
# 处理firewall的端口转发添加
def firewall_handle_add(self, s_port, d_port, d_ip, protocol):
if protocol.find('/') != -1:
public.ExecShell(
"firewall-cmd --permanent --zone=public --add-forward-port=port="
+ s_port + ":proto=tcp:toaddr=" + d_ip + ":toport=" + d_port +
"")
public.ExecShell(
"firewall-cmd --permanent --zone=public --add-forward-port=port="
+ s_port + ":proto=udp:toaddr=" + d_ip + ":toport=" + d_port +
"")
else:
cmd = "firewall-cmd --permanent --zone=public --add-forward-port=port=" + s_port + ":proto=" + protocol + ":toaddr=" + d_ip + ":toport=" + d_port + ""
public.ExecShell(cmd)
# 处理firewall的端口转发删除
def firewall_handle_del(self, s_port, d_port, d_ip, protocol):
if protocol.find('/') != -1:
public.ExecShell(
"firewall-cmd --permanent --zone=public --remove-forward-port=port="
+ s_port + ":proto=tcp:toaddr=" + d_ip + ":toport=" + d_port +
"")
public.ExecShell(
"firewall-cmd --permanent --zone=public --remove-forward-port=port="
+ s_port + ":proto=udp:toaddr=" + d_ip + ":toport=" + d_port +
"")
else:
public.ExecShell(
"firewall-cmd --permanent --zone=public --remove-forward-port=port="
+ s_port + ":proto=" + protocol + ":toaddr=" + d_ip +
":toport=" + d_port + "")
# 处理firewall的端口转发修改
def firewall_handle_update(self, start_port, ended_ip, ended_port,
protocol, s_port, d_ip, d_port, pool):
if protocol.find('/') != -1:
public.ExecShell(
"firewall-cmd --permanent --zone=public --remove-forward-port=port="
+ start_port + ":proto=tcp:toaddr=" + ended_ip + ":toport=" +
ended_port + "")
public.ExecShell(
"firewall-cmd --permanent --zone=public --remove-forward-port=port="
+ start_port + ":proto=udp:toaddr=" + ended_ip + ":toport=" +
ended_port + "")
else:
public.ExecShell(
"firewall-cmd --permanent --zone=public --remove-forward-port=port="
+ start_port + ":proto=" + protocol + ":toaddr=" + ended_ip +
":toport=" + ended_port + "")
if pool.find('/') != -1:
public.ExecShell(
"firewall-cmd --permanent --zone=public --add-forward-port=port="
+ s_port + ":proto=tcp:toaddr=" + d_ip + ":toport=" + d_port +
"")
public.ExecShell(
"firewall-cmd --permanent --zone=public --add-forward-port=port="
+ s_port + ":proto=udp:toaddr=" + d_ip + ":toport=" + d_port +
"")
else:
public.ExecShell(
"firewall-cmd --permanent --zone=public --add-forward-port=port="
+ s_port + ":proto=" + pool + ":toaddr=" + d_ip + ":toport=" +
d_port + "")
# 处理iptables的端口转发添加
def iptables_handle_add(self, s_port, d_port, d_ip, protocol):
if d_ip == "":
if protocol.find('/') != -1:
public.ExecShell(
"iptables -t nat -A PREROUTING -p tcp --dport " + s_port +
" -j REDIRECT --to-port " + d_port + '')
public.ExecShell(
"iptables -t nat -A PREROUTING -p udp --dport " + s_port +
" -j REDIRECT --to-port " + d_port + '')
else:
public.ExecShell("iptables -t nat -A PREROUTING -p " +
protocol + " --dport " + s_port +
" -j REDIRECT --to-port " + d_port + '')
else:
if protocol.find('/') != -1:
public.ExecShell(
"iptables -t nat -A PREROUTING -p tcp --dport " + s_port +
" -j DNAT --to-destination " + d_ip + ":" + d_port + '')
public.ExecShell(
"iptables -t nat -A PREROUTING -p udp --dport " + s_port +
" -j DNAT --to-destination " + d_ip + ":" + d_port + '')
public.ExecShell(
"iptables -t nat -A POSTROUTING -j MASQUERADE")
else:
public.ExecShell(
"iptables -t nat -A PREROUTING -p " + protocol + " --dport " + s_port + " -j DNAT --to-destination " + d_ip + ":" + d_port + '')
public.ExecShell("iptables -t nat -A POSTROUTING -j MASQUERADE")
return True
# 处理iptables的端口转发删除
def iptables_handle_del(self, s_port, d_port, d_ip, protocol):
if d_ip == "":
if protocol.find('/') != -1:
public.ExecShell(
"iptables -t nat -D PREROUTING -p tcp --dport " + s_port +
" -j REDIRECT --to-port " + d_port + '')
public.ExecShell(
"iptables -t nat -D PREROUTING -p udp --dport " + s_port +
" -j REDIRECT --to-port " + d_port + '')
else:
public.ExecShell("iptables -t nat -D PREROUTING -p " +
protocol + " --dport " + s_port +
" -j REDIRECT --to-port " + d_port + '')
else:
if protocol.find('/') != -1:
public.ExecShell(
"iptables -t nat -D PREROUTING -p tcp --dport " + s_port + " -j DNAT --to-destination " + d_ip + ":" + d_port + '')
public.ExecShell(
"iptables -t nat -D PREROUTING -p udp --dport " + s_port + " -j DNAT --to-destination " + d_ip + ":" + d_port + '')
public.ExecShell("iptables -t nat -D POSTROUTING -j MASQUERADE")
else:
public.ExecShell(
"iptables -t nat -D PREROUTING -p " + protocol + " --dport " + s_port + " -j DNAT --to-destination " + d_ip + ":" + d_port + '')
public.ExecShell("iptables -t nat -D POSTROUTING -j MASQUERADE")
return True
# 处理iptables的端口转发删除
def iptables_handle_update(self, start_port, ended_ip, ended_port,
protocol, s_port, d_ip, d_port, pool):
if ended_ip == "":
if protocol.find('/') != -1:
public.ExecShell(
"iptables -t nat -D PREROUTING -p tcp --dport " + s_port +
" -j REDIRECT --to-port " + d_port + '')
public.ExecShell(
"iptables -t nat -D PREROUTING -p udp --dport " + s_port +
" -j REDIRECT --to-port " + d_port + '')
else:
public.ExecShell("iptables -t nat -D PREROUTING -p " +
protocol + " --dport " + s_port +
" -j REDIRECT --to-port " + d_port + '')
else:
if protocol.find('/') != -1:
public.ExecShell(
"iptables -t nat -D PREROUTING -p tcp --dport " + s_port + " -j DNAT --to-destination " + d_ip + ":" + d_port + '')
public.ExecShell(
"iptables -t nat -D PREROUTING -p udp --dport " + s_port + " -j DNAT --to-destination " + d_ip + ":" + d_port + '')
public.ExecShell("iptables -t nat -D POSTROUTING -j MASQUERADE")
else:
public.ExecShell(
"iptables -t nat -D PREROUTING -p " + protocol + " --dport " + s_port + " -j DNAT --to-destination " + d_ip + ":" + d_port + '')
public.ExecShell("iptables -t nat -D POSTROUTING -j MASQUERADE")
if d_ip == "":
if pool.find('/') != -1:
public.ExecShell(
"iptables -t nat -A PREROUTING -p tcp --dport " + s_port +
" -j REDIRECT --to-port " + d_port + '')
public.ExecShell(
"iptables -t nat -A PREROUTING -p udp --dport " + s_port +
" -j REDIRECT --to-port " + d_port + '')
else:
public.ExecShell("iptables -t nat -A PREROUTING -p " +
protocol + " --dport " + s_port +
" -j REDIRECT --to-port " + d_port + '')
else:
if pool.find('/') != -1:
public.ExecShell(
"iptables -t nat -A PREROUTING -p tcp --dport " + s_port + " -j DNAT --to-destination " + d_ip + ":" + d_port + '')
public.ExecShell(
"iptables -t nat -A PREROUTING -p udp --dport " + s_port + " -j DNAT --to-destination " + d_ip + ":" + d_port + '')
public.ExecShell("iptables -t nat -A POSTROUTING -j MASQUERADE")
else:
public.ExecShell(
"iptables -t nat -A PREROUTING -p " + protocol + " --dport " + s_port + " -j DNAT --to-destination " + d_ip + ":" + d_port + '')
public.ExecShell("iptables -t nat -A POSTROUTING -j MASQUERADE")
return True
# 开启端口转发
def open_forward(self):
if self.__isUfw:
content1 = self.get_profile(self._ufw_default)
content2 = self.get_profile(self._ufw_sysctl)
content1 = content1.replace('DEFAULT_FORWARD_POLICY="DROP"',
'DEFAULT_FORWARD_POLICY="ACCEPT"')
content2 = content2.replace('#net/ipv4/ip_forward=1',
'net/ipv4/ip_forward=1')
self.save_profile(self._ufw_default, content1)
self.save_profile(self._ufw_sysctl, content2)
self.FirewallReload()
return True
if self.__isFirewalld:
public.ExecShell(
'echo "\nnet.ipv4.ip_forward=1" >> /etc/sysctl.conf')
public.ExecShell('firewall-cmd --add-masquerade --permanent')
self.FirewallReload()
else:
public.ExecShell(
'echo "\nnet.ipv4.ip_forward=1" >> /etc/sysctl.conf')
public.ExecShell('sysctl -p /etc/sysctl.conf')
self.FirewallReload()
return True
# 开启或关闭端口转发
def open_close_forward(self, get):
if not get.status in ["open", "close"]:
return public.returnMsg(False, public.lang("Unknown control command!"))
if self.__isUfw:
content1 = self.get_profile(self._ufw_default)
content2 = self.get_profile(self._ufw_sysctl)
if get.status == 'open':
content1 = content1.replace('DEFAULT_FORWARD_POLICY="DROP"',
'DEFAULT_FORWARD_POLICY="ACCEPT"')
content2 = content2.replace('#net/ipv4/ip_forward=1',
'net/ipv4/ip_forward=1')
else:
content1 = content1.replace('DEFAULT_FORWARD_POLICY="ACCEPT"',
'DEFAULT_FORWARD_POLICY="DROP"')
content2 = content2.replace('net/ipv4/ip_forward=1',
'#net/ipv4/ip_forward=1')
self.save_profile(self._ufw_default, content1)
self.save_profile(self._ufw_sysctl, content2)
self.FirewallReload()
return public.returnMsg(True,
public.lang('Enable' if get.status == "open" else "Disable"))
if self.__isFirewalld:
if get.status == 'open':
public.ExecShell('firewall-cmd --add-masquerade --permanent')
else:
public.ExecShell(
'firewall-cmd --remove-masquerade --permanent')
self.FirewallReload()
else:
public.ExecShell(
'echo "net.ipv4.ip_forward=1" >> /etc/sysctl.conf')
public.ExecShell('sysctl -p /etc/sysctl.conf')
return public.returnMsg(True, public.lang("Turn off port forwarding"))
def get_host_ip(self):
"""
查询本机ip地址
:return:
"""
try:
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.connect(('8.8.8.8', 80))
ip = s.getsockname()[0]
finally:
s.close()
return ip
def load_white_list(self):
try:
if not self._white_list:
ip_data = self.get_profile(self._white_list_file)
white_list_ips = json.loads(ip_data)
white_list = []
for ip_obj in white_list_ips:
white_list += ip_obj["ips"]
self._white_list = white_list
# public.WriteLog("firewall_debug", str(white_list))
return self._white_list
except Exception as e:
public.WriteLog("firewall", "Failed to load whitelist")
return []
def verify_ip(self, ip_entry):
"""检查规则IP是否和内网IP重叠"""
try:
try:
import IPy
except:
ipy_tips = '/tmp/bt_ipy.pl'
if not os.path.exists(ipy_tips):
os.system("nohup btpip install IPy &>/dev/null &")
public.WriteFile(ipy_tips, 'True')
release_ips = [
IPy.IP("127.0.0.1"),
IPy.IP("172.16.1.1"),
IPy.IP("10.0.0.1"),
IPy.IP("192.168.0.0"),
IPy.IP(self.get_host_ip())
]
white_list = self.load_white_list()
release_ips += white_list
ip = IPy.IP(ip_entry, make_net=True)
for rip_obj in release_ips:
overlap = ip.overlaps(rip_obj)
if overlap > 0:
return False
return True
except:
return False
def handle_firewall_country(self, brief, ip_list, types, port_list):
try:
public.ExecShell(
'firewall-cmd --permanent --zone=public --new-ipset=' + brief +
' --type=hash:net')
xml_path = "/etc/firewalld/ipsets/%s.xml" % brief
tree = ElementTree()
tree.parse(xml_path)
root = tree.getroot()
for ip in ip_list:
if self.verify_ip(ip):
entry = Element("entry")
entry.text = ip
root.append(entry)
self.format(root)
tree.write(xml_path, 'utf-8', xml_declaration=True)
if port_list:
for port in port_list:
public.ExecShell(
'firewall-cmd --permanent --zone=public --add-rich-rule=\'rule source ipset="'
+ brief + '" port port="' + port + '" protocol=tcp ' +
types + '\'')
else:
public.ExecShell(
'firewall-cmd --permanent --zone=public --add-rich-rule=\'rule source ipset="'
+ brief + '" ' + types + '\'')
except Exception as e:
return {"status": "error", "msg": e}
def handle_ufw_country(self, brief, ip_list, types, port_list):
tmp_path = '/tmp/firewall_tmp.sh'
tmp_file = open(tmp_path, 'w')
_string = "#!/bin/bash\n"
for ip in ip_list:
if self.verify_ip(ip):
_string = _string + 'ipset add ' + brief + ' ' + ip + '\n'
tmp_file.write(_string)
tmp_file.close()
public.ExecShell('ipset create ' + brief +
' hash:net; /bin/bash /tmp/firewall_tmp.sh')
if port_list:
for port in port_list:
public.ExecShell('iptables -I INPUT -m set --match-set ' +
brief + ' src -p tcp --destination-port ' +
port + ' -j ' + types.upper())
else:
public.ExecShell('iptables -I INPUT -m set --match-set ' + brief +
' src -j ' + types.upper())
# 查询区域规则
def get_country_list(self, args):
p = 1
limit = 15
if 'p' in args: p = args.p
if 'limit' in args: limit = args.limit
where = '1=1'
sql = public.M('firewall_country')
if hasattr(args, 'query'):
where = " country like '%{search}%' or brief like '%{search}%'".format(
search=args.query)
count = sql.where(where, ()).count()
data = public.get_page(count, int(p), int(limit))
data['data'] = sql.where(where, ()).limit('{},{}'.format(
data['shift'], data['row'])).order('addtime desc').select()
return data
def create_countrys(self, get):
try:
if not hasattr(get, 'country'):
return public.returnMsg(False, public.lang("Please enter the country name!"))
input_country = get.country
countrys = self.get_countrys(None)
countrys = countrys[1:]
# 2024/1/6 下午 5:00 获取防火墙状态,如果没有启动则启动防火墙
if not self.get_firewall_status():
get.status = "start"
self.firewall_admin(get)
if "Except China" in input_country:
input_country = [i['CH'] for i in countrys if not "China" in i['CH']]
countrys_dict = {i['CH']: i['brief'] for i in countrys}
content = self.get_profile(self._ips_path)
for i in input_country:
get.brief = countrys_dict.get(i, None)
get.country = i
self.create_country(get, True, content)
else:
countrys_dict = {i['CH']: i['brief'] for i in countrys}
if isinstance(input_country, str):
input_country = [input_country]
for i in input_country:
get.brief = countrys_dict.get(i, None)
get.country = i
self.create_country(get, True)
get.status = "restart"
self.firewall_admin(get)
return public.returnMsg(True, public.lang("Added successfully"))
except:
print(traceback.format_exc())
return public.returnMsg(False, public.lang("Add failed"))
# 添加区域规则
def create_country(self, get, is_mutil=False, _ips_paths=None):
brief = get.brief
types = get.types # types in [accept, drop]
ports = get.ports
country = get.country
rep = r"^\d{1,5}(:\d{1,5})?$"
port_list = []
# 检测该区域是否已添加过全部端口规则 hezhihong
add_list = public.M('firewall_country').where("country=?", (country,)).field('ports').select()
for add in add_list:
if not add['ports']:
return public.returnMsg(False, public.lang("This area has already been added, please do not add it again!"))
if ports:
port_list = ports.split(',')
for port in port_list:
if not re.search(rep, port):
return public.returnMsg(False, public.lang("Port range is incorrect!"))
if public.M('firewall_country').where(
"country=? and ports=?", (country, port)).count() > 0:
public.print_log('############ 地区接口8{}'.format(port))
return public.returnMsg(False, public.lang("This area has already been added, please do not add it again!"))
self.get_os_info()
if _ips_paths is None:
content = self.get_profile(self._ips_path)
else:
content = _ips_paths
result = json.loads(content)
ip_list = []
for r in result:
if brief == r["brief"]:
ip_list = r["ips"]
break
if not ip_list:
public.print_log('############ 地区接口7'.format())
return public.returnMsg(True, public.lang("Please enter the correct area name!"))
if self.__isUfw:
self.handle_ufw_country(brief, ip_list, types, port_list)
else:
if self.__isFirewalld:
result = self.handle_firewall_country(brief, ip_list, types,
port_list)
if result:
public.print_log('############ 地区接口6{}'.format(result))
return result
else:
self.handle_ufw_country(brief, ip_list, types, port_list)
addtime = time.strftime('%Y-%m-%d %X', time.localtime())
if port_list:
for port in port_list:
public.M('firewall_country').add(
'country,types,brief,ports,addtime',
(country, types, brief, port, addtime))
else:
public.M('firewall_country').add(
'country,types,brief,ports,addtime',
(country, types, brief, '', addtime))
if is_mutil is False:
# self.FirewallReload()
get.status = "restart"
self.firewall_admin(get)
if not get.ports:
log_port = "All ports"
else:
log_port = get.ports
# strategy = ''
# if get.types == 'accept':
# strategy = "accept"
# elif get.types == 'drop':
# strategy = "drop"
public.print_log('############ 地区接口5'.format())
public.WriteLog("system firewall",
"Add regional rules: Region:{}, Policy:{}, Port:{}".format(get.country, get.types, log_port))
return public.returnMsg(True, public.lang("Added successfully!"))
# 删除区域规则
def remove_country(self, get):
id = get.id
types = get.types
brief = get.brief
ports = get.ports
country = get.country
reload = True
if "not_reload" in get:
reload = get.not_reload.lower() == "true"
public.M('firewall_country').where("id=?", (id,)).delete()
if self.__isUfw:
if not ports:
public.ExecShell('iptables -D INPUT -m set --match-set ' +
brief + ' src -j ' + types.upper())
else:
public.ExecShell('iptables -D INPUT -m set --match-set ' +
brief + ' src -p tcp --destination-port ' +
ports + ' -j ' + types.upper())
if not public.M('firewall_country').where("country=?",
(country,)).count() > 0:
public.ExecShell('ipset destroy ' + brief)
else:
if self.__isFirewalld:
if not ports:
public.ExecShell(
'firewall-cmd --permanent --zone=public --remove-rich-rule=\'rule source ipset="'
+ brief + '" ' + types + '\'')
else:
public.ExecShell(
'firewall-cmd --permanent --zone=public --remove-rich-rule=\'rule source ipset="'
+ brief + '" port port="' + ports + '" protocol=tcp ' +
types + '\'')
if not public.M('firewall_country').where(
"country=?", (country,)).count() > 0:
public.ExecShell(
'firewall-cmd --permanent --zone=public --delete-ipset='
+ brief)
else:
if not ports:
public.ExecShell('iptables -D INPUT -m set --match-set ' +
brief + ' src -j ' + types.upper())
else:
public.ExecShell('iptables -D INPUT -m set --match-set ' +
brief +
' src -p tcp --destination-port ' +
ports + ' -j ' + types.upper())
if not public.M('firewall_country').where(
"country=?", (country,)).count() > 0:
public.ExecShell('ipset destroy ' + brief)
if reload:
get.status = "restart"
self.firewall_admin(get)
if not get.ports:
log_port = "All ports"
else:
log_port = get.ports
strategy = ''
if get.types == 'accept':
strategy = "accept"
elif get.types == 'drop':
strategy = 'drop'
public.WriteLog("system firewall",
"Delete zone rules: Region:{}, Policy:{}, Port:{}".format(get.country, strategy, log_port))
return public.returnMsg(True, public.lang("Delete successfully!"))
# 编辑区域规则
def modify_country(self, get):
# 2022/11/24 修复编辑地区端口规则问题 lx
id = get.id
# types = get.types
# brief = get.brief
# country = get.country
data = public.M('firewall_country').where(
'id=?',
(id,)).field('id,country,types,brief,ports,addtime').find()
ori_get = public.dict_obj()
ori_get.id = id
ori_get.types = data.get("types", "")
ori_get.brief = data.get("brief", "")
ori_get.country = data.get("country", "")
ori_get.ports = data.get("ports", "")
ori_get.not_reload = "true"
rm_res = self.remove_country(ori_get)
if rm_res["status"]:
create_res = self.create_country(get)
if create_res["status"]:
return public.returnMsg(True, public.lang("Successful operation"))
return public.returnMsg(False, public.lang("operation failed"))
# 获取服务端列表centos
def GetList(self):
try:
result, arry = self.__Obj.GetAcceptPortList()
addtime = time.strftime('%Y-%m-%d %X', time.localtime())
for i in range(len(result)):
if "address" not in result[i].keys(): continue
tmp = self.check_db_exists(result[i]['ports'],
result[i]['address'],
result[i]['types'])
protocol = result[i]['protocol']
ports = result[i]['ports']
types = result[i]['types']
address = result[i]['address']
if not tmp:
if ports:
public.M('firewall_new').add(
'ports,protocol,address,types,brief,addtime',
(ports, protocol, address, types, '', addtime))
else:
public.M('firewall_ip').add(
'address,types,brief,addtime',
(address, types, '', addtime))
for i in range(len(arry)):
if arry[i]['port']:
tmp = self.check_trans_data(arry[i]['port'])
protocol = arry[i]['protocol']
s_port = arry[i]['port']
d_port = arry[i]['to-port']
address = arry[i]['address']
if not tmp:
public.M('firewall_trans').add(
'start_port,ended_ip,ended_port,protocol,addtime',
(s_port, address, d_port, protocol, addtime))
except Exception as e:
file = open('error.txt', 'w')
return public.returnMsg(False, e)
# 获取服务端列表ufw
def get_ufw_list(self):
data = public.M('firewall').field('id,port,ps,addtime').select()
if type(data) != list: return
try:
for dt in data:
port = dt['port']
brief = dt['ps']
addtime = dt['addtime']
if port.find('.') != -1:
tmp = self.check_db_exists('', port, 'drop')
if not tmp:
public.M('firewall_ip').add('address,types,brief,addtime',
(port, 'drop', '', addtime))
else:
tmp = self.check_db_exists(port, '', 'accept')
if not tmp:
public.M('firewall_new').add(
'ports,brief,protocol,address,types,addtime',
(port, brief, 'tcp/udp', '', 'accept', addtime))
except:
pass
# 检查数据库是否存在
def check_db_exists(self, ports, address, types):
if ports:
data = public.M('firewall_new').field(
'id,ports,protocol,address,types,brief,addtime').select()
for dt in data:
if dt['ports'] == ports: return dt
return False
else:
data = public.M('firewall_ip').field(
'id,address,types,brief,addtime').select()
for dt in data:
if dt["address"] == address and dt["types"] == types: return dt
return False
def check_trans_data(self, ports):
data = public.M('firewall_trans').field(
'id,start_port,ended_ip,ended_port,protocol,addtime').select()
for dt in data:
if dt['start_port'] == ports: return dt
return False
# 规则导出:服务器
def export_rules(self, get):
rule_name = get.rule_name
arry = []
data_list = None
filename = ''
if rule_name == "port_rule":
filename = self._rule_path + "port.json"
data_list = public.M('firewall_new').order("id desc").select()
elif rule_name == "ip_rule":
filename = self._rule_path + "ip.json"
data_list = public.M('firewall_ip').order("id desc").select()
elif rule_name == "trans_rule":
filename = self._rule_path + "forward.json"
data_list = public.M('firewall_trans').order("id desc").select()
elif rule_name == "country_rule":
filename = self._rule_path + "country.json"
data_list = public.M('firewall_country').order("id desc").select()
if not data_list:
data_list = []
# 将数据格式换成以|分割的字符串 hezhihong
write_string = ""
if data_list:
for i in data_list:
for v in i.keys():
if v == 'domain': i[v] = i[v].replace('|', '#')
write_string += str(i[v]) + "|"
write_string += '\n'
public.writeFile(filename, write_string)
public.WriteLog("system firewall", "Export port rules")
return public.returnMsg(True, filename)
# 规则导出:本地
def get_file(self, args):
filename = args.filename
mimetype = "application/octet-stream"
if not os.path.exists(filename): return abort(404)
return send_file(filename,
mimetype=mimetype,
as_attachment=True,
attachment_filename=os.path.basename(filename),
cache_timeout=0)
# 规则导入json
def import_rules(self, get):
try:
rule_name = get.rule_name # 规则名:[port_rule, ip_rule, trans_rule, country_rule]
file_name = get.file_name # 文件命:[port.json, ip.json, trans.json, country.json]
file_path = "{0}{1}".format(self._rule_path, file_name)
data_list = self.get_profile(file_path)
pay = self.__check_auth()
not_pay_list = []
tmp_data = []
# |分隔符格式文件导入 hezhihong
if data_list and isinstance(data_list, str):
if data_list.find('|') != -1:
data_list = data_list.split('\n')
for data in data_list:
if not data: continue
split_data = data.split('|')
data_dict = {}
data_dict['id'] = split_data[0]
if rule_name == 'port_rule':
if not pay and split_data[7].find('#') != -1:
not_pay_list.append(data)
continue
data_dict['protocol'] = split_data[1]
data_dict['ports'] = split_data[2]
data_dict['types'] = split_data[3]
data_dict['address'] = split_data[4]
data_dict['brief'] = split_data[5]
data_dict['addtime'] = split_data[6]
data_dict['domain'] = split_data[7]
elif rule_name == 'ip_rule':
if not pay and split_data[6].find('#') != -1:
not_pay_list.append(data)
continue
data_dict['types'] = split_data[1]
data_dict['address'] = split_data[2]
data_dict['brief'] = split_data[3]
data_dict['addtime'] = split_data[4]
data_dict['domain'] = split_data[6]
elif rule_name == 'trans_rule':
data_dict['start_port'] = split_data[1]
data_dict['ended_ip'] = split_data[2]
data_dict['ended_port'] = split_data[3]
data_dict['protocol'] = split_data[4]
data_dict['addtime'] = split_data[5]
elif rule_name == 'country_rule':
data_dict['types'] = split_data[1]
data_dict['country'] = split_data[2]
data_dict['brief'] = split_data[3]
data_dict['addtime'] = split_data[4]
data_dict['ports'] = split_data[5]
tmp_data.append(data_dict)
data_list = tmp_data
# 一行一条规则格式文件导入 hezhihong
if data_list and isinstance(data_list, str):
data_list = data_list.strip()
if isinstance(data_list, str) and data_list.find('\n') != -1:
data_list = data_list.split('\n')
try:
data_list.remove('')
except:
pass
if isinstance(data_list, str):
try:
data_list = json.loads(data_list)
except:
if os.path.exists(file_path):
os.remove(file_path)
return public.ReturnMsg(False, "The file content is incorrect!")
if data_list:
if isinstance(data_list, dict):
data_list = [data_list]
if not isinstance(data_list, list):
if os.path.exists(file_path):
os.remove(file_path)
return public.ReturnMsg(False, "The file content is incorrect!")
if len(data_list) == 0:
return public.ReturnMsg(False, "The file is empty!")
result = self.hand_import_rules(rule_name, data_list)
os.remove(file_path)
if not_pay_list:
not_pay_list = ("<br/>" + "-" * 20 + "<br/>").join(not_pay_list)
return public.ReturnMsg(
result["status"],
"{}<br/>The designated domain name function is exclusive to the Enterprise Edition, and the following rules are not imported:<br/>{}".format(
result["msg"], not_pay_list)
)
public.WriteLog("system firewall", "Import port rules")
return public.ReturnMsg(result["status"], result["msg"])
except Exception:
return public.ReturnMsg(False,
"The import failed. The format of the rules is wrong. Please try again according to the format of the export rules!")
# 处理规则导入读取json文件内容
def hand_import_rules(self, rule_name, data_list):
table_head = []
try:
if rule_name == "port_rule":
table_head = ["id", "protocol", "ports", "types", "address", "brief", "addtime", "domain", ]
for data in data_list:
# 兼容一行一条规则格式文件导入 hezhihong
try:
data = json.loads(data)
except:
pass
res = all([field in data.keys() for field in table_head])
if not res or len(table_head) != len(data.keys()):
return {"status": False, "msg": "The data format is incorrect!"}
get = public.dict_obj()
get.protocol = data["protocol"]
get.ports = data["ports"]
get.types = data["types"]
get.source = data["address"]
get.brief = data["brief"]
# 兼容域名导入 hezhihong
if 'domain' in data.keys() and data['domain']:
get.domain = data['domain'].split('#')[0]
get.source = data['domain'].split('#')[1]
result = self.create_rules(get)
if not result["status"]:
continue
elif rule_name == "ip_rule":
table_head = ["id", "types", "address", "brief", "addtime"]
for data in data_list:
# 兼容一行一条规则格式文件导入 hezhihong
try:
data = json.loads(data)
except:
pass
res = all([field in data.keys() for field in table_head])
if not res:
return {"status": False, "msg": "The data format is incorrect!"}
get = public.dict_obj()
get.types = data["types"]
get.address = data["address"]
get.brief = data["brief"]
# 兼容域名导入 hezhihong
if 'domain' in data.keys() and data['domain']:
get.domain = data['domain'].split('#')[0]
get.source = data['domain'].split('#')[1]
result = self.create_ip_rules(get)
if not result["status"]:
continue
elif rule_name == "trans_rule":
table_head = [
"id", "start_port", "ended_ip", "ended_port", "protocol",
"addtime"
]
for data in data_list:
# 兼容一行一条规则格式文件导入 hezhihong
try:
data = json.loads(data)
except:
pass
res = all([field in data.keys() for field in table_head])
if not res:
return {"status": False, "msg": "The data format is incorrect!"}
get = public.dict_obj()
get.s_ports = data["start_port"]
get.d_address = data["ended_ip"]
get.d_ports = data["ended_port"]
get.protocol = data["protocol"]
result = self.create_forward(get)
if not result["status"]:
continue
elif rule_name == "country_rule":
table_head = ["id", "types", "country", "brief", "addtime", "ports"]
for data in data_list:
# 兼容一行一条规则格式文件导入 hezhihong
try:
data = json.loads(data)
except:
pass
res = all([field in data.keys() for field in table_head])
if not res:
return {"status": False, "msg": "The data format is incorrect!"}
get = public.dict_obj()
get.types = data["types"]
get.ports = data["ports"]
get.brief = data["brief"]
get.country = data["country"]
result = self.create_country(get)
if not result["status"]:
continue
except:
return {"status": False, "msg": "Import failed!"}
return {"status": True, "msg": "Imported successfully!"}
def get_countrys(self, get):
result = []
content = self.get_profile(self._country_path)
result = json.loads(content)
result = sorted(result, key=lambda x: x['CH'], reverse=True);
if isinstance(result, list):
result.insert(0, {"CH": "Except China", "brief": "OTHER"})
return result
# 读取配置文件
def get_profile(self, path):
if not os.path.exists(path):
b_path = os.path.dirname(path)
if not os.path.exists(b_path): os.makedirs(b_path)
if path in [
self._ips_path, self._country_path, self._white_list_file
]:
public.downloadFile(
'https://www.yakpanel.com/install/lib/{}'.format(
os.path.basename(path)), path)
content = ""
with open(path, "r") as fr:
content = fr.read()
return content
# 保存配置文件
def save_profile(self, path, data):
with open(path, "w") as fw:
fw.write(data)
# 读取配置文件
def update_profile(self, path):
import files
f = files.files()
return f.GetFileBody(path)
# 获取端口规则列表
def get_port_rules(self, get):
rule_list = public.M('firewall_new').order("id desc").select()
return public.returnMsg(True, rule_list)
# 整理配置文件格式
def format(self, em, level=0):
i = "\n" + level * " "
if len(em):
if not em.text or not em.text.strip():
em.text = i + " "
for e in em:
self.format(e, level + 1)
if not e.tail or not e.tail.strip():
e.tail = i
if level and (not em.tail or not em.tail.strip()):
em.tail = i
def check_table(self):
if public.M('sqlite_master').where('type=? AND name=?',
('table', 'firewall_new')).count():
if public.M('sqlite_master').where(
'type=? AND name=?', ('table', 'firewall_ip')).count():
if public.M('sqlite_master').where(
'type=? AND name=?',
('table', 'firewall_trans')).count():
if public.M('sqlite_master').where(
'type=? AND name=?',
('table', 'firewall_country')).count():
return True
return Sqlite()
def delete_service(self):
if self.__isUfw:
public.ExecShell('ufw delete allow ssh')
else:
if self.__isFirewalld:
public.ExecShell(
'firewall-cmd --zone=public --remove-service=ssh --permanent'
)
else:
pass
return True
# 获取系统类型(具体到哪个版本)
def get_os_info(self):
tmp = {"osname": "", "version": ""}
if os.path.exists('/etc/redhat-release'):
sys_info = public.ReadFile('/etc/redhat-release')
elif os.path.exists('/usr/bin/yum'):
sys_info = public.ReadFile('/etc/issue')
elif os.path.exists('/etc/issue'):
sys_info = public.ReadFile('/etc/issue')
try:
tmp['osname'] = sys_info.split()[0]
tmp['version'] = re.search(r'\d+(\.\d*)*', sys_info).group()
except:
os_result = public.ExecShell(". /etc/os-release && echo $ID")[0]
if "amzn" == os_result:
tmp['osname'] = 'CentOS'
tmp['version'] = '8'
if tmp["osname"] == "CentOS":
if tmp["version"].startswith("8"):
content = self.get_profile("/etc/firewalld/firewalld.conf")
content = content.replace("FirewallBackend=nftables", "FirewallBackend=iptables")
self.save_profile("/etc/firewalld/firewalld.conf", content)
public.ExecShell("systemctl restart firewalld")
return True
# 新加代码----- start
def sync_must_ports(self, get):
'''
同步必须放行的端口
@param get:
@return:
'''
protocol = "tcp"
ports = get.ports.strip()
print(ports)
if not ports: return public.returnMsg(False, public.lang("Port cannot be empty!"))
port_list = ports.split(",") if ports.find(",") != -1 else [ports]
types = "accept"
check_result = self.check_port(port_list)
if check_result: return check_result
firewall_type = 'iptables'
if self.__isFirewalld: firewall_type = 'firewalld'
if self.__isUfw: firewall_type = 'ufw'
try:
# 2024/1/6 下午 5:00 获取防火墙状态,如果没有启动则启动防火墙
if not self.get_firewall_status():
get = public.dict_obj()
get.status = 1
self.firewall_admin(get)
for port in port_list:
if firewall_type == 'firewalld':
if port.find(':') != -1: port = port.replace(':', '-')
self.add_firewall_rule("", protocol, port, types)
elif firewall_type == 'ufw':
if port.find('-') != -1: port = port.replace('-', ':')
self.add_ufw_rule("", protocol, port, types)
else:
self.add_iptables_rule("", protocol, port, types)
query_result = public.M('firewall_new').where(
'ports=? and address=? and protocol=? and types=?',
(port, "", protocol, types)
).find()
print(query_result)
if query_result: continue
addtime = time.strftime('%Y-%m-%d %X', time.localtime())
self._add_sid = public.M('firewall_new').add(
'ports,brief,protocol,address,types,addtime,domain,sid',
(port, "", protocol, "", types, addtime, "", 0)
)
return public.returnMsg(True, public.lang("Added successfully!"))
except Exception:
print(traceback.format_exc())
return public.returnMsg(False, public.lang("Failed to add"))
def _get_webserver(self):
'''
获取web服务器类型
@return:
'''
webserver = ''
if os.path.exists('/www/server/nginx/sbin/nginx'):
webserver = 'nginx'
elif os.path.exists('/www/server/apache/bin/httpd'):
webserver = 'apache'
elif os.path.exists('/usr/local/lsws/bin/lswsctrl'):
webserver = 'lswsctrl'
return webserver
def get_port_info(self, get):
'''
获取面板防火墙关键服务端口放行状态信息
判断服务是否存在,能读取文件就读取文件,配置文件不大不会影响性能,这种方式能最大缩短接口响应时间,公网测试80ms
@param get:
@return:
'''
ports_list = []
result_list = [{"name": "FTP passive port", "status": 0, "port": "39000-40000"}]
webserver = self._get_webserver()
if webserver in ['nginx', 'apache', 'lswsctrl']:
result_list.append({"name": "website port", "status": 0, "port": "80"})
ports_list.append("80")
port_443, _ = public.ExecShell("fuser -n tcp 443")
if port_443:
result_list.append({"name": "HTTPS port", "status": 0, "port": "443"})
ports_list.append("443")
_panel_port_file = '/www/server/panel/data/port.pl'
panel_port = public.readFile(_panel_port_file).strip(" ").strip("\n")
cmd = "cat /www/server/pure-ftpd/etc/pure-ftpd.conf |grep Bind|awk -F ',' '{print $2}'"
ftp_port = public.ExecShell(cmd)[0].strip(" ").strip("\n").strip("\r")
cmd = "cat /etc/ssh/sshd_config |grep -E '^Port'|awk '{print $2}'|awk 'NR == 1'"
ssh_port = public.ExecShell(cmd)[0].strip(" ").strip("\n")
if ssh_port == "": ssh_port = "22"
ports_list.append(panel_port)
result_list.append({"name": "panel", "status": 0, "port": panel_port})
ports_list.append(ftp_port)
result_list.append({"name": "FTP active port", "status": 0, "port": ftp_port})
ports_list.append(ssh_port)
result_list.append({"name": "SSH", "status": 0, "port": ssh_port})
ports_list.append("39000-40000")
if self.__isUfw:
return self._get_ufw_port_status(ports_list, result_list)
if self.__isFirewalld:
return self._get_firewall_port_status(ports_list, result_list)
return {}
def _get_firewall_port_status(self, ports_list, result_list):
'''
获取firewalld防火墙端口状态
@param ports_list:
@param result_list:
@return:
'''
with contextlib.suppress(Exception):
_firewalld_ports, _ = self.__firewall_obj.GetAcceptPortList()
# print("_firewalld_ports: ", _firewalld_ports)
for firewalld_port in _firewalld_ports:
if firewalld_port['ports'] in ports_list:
for result in result_list:
if result['port'] == firewalld_port['ports']:
result['status'] = 1
break
return result_list
def _get_ufw_port_status(self, ports_list, result_list):
'''
获取ufw防火墙端口状态
@param ports_list:
@param result_list:
@return:
'''
with contextlib.suppress(Exception):
rules_result = self._get_ufw_port_info()
# print("rules_result: ", rules_result)
ports_set = set(ports_list) # 将要查找的端口列表转换成集合,以便进行高效查找
for rule in rules_result:
if 'tcp' in rule['protocol'] and rule['ports'] in ports_set:
for result in result_list:
if result['port'] == rule['ports']:
result['status'] = 1
ports_set.remove(rule['ports'])
break
if not ports_set: break
return result_list
def _get_ufw_port_info(self):
'''
获取ufw防火墙端口信息
@return:
'''
with open('/etc/ufw/user.rules', 'r') as f:
content = f.read()
start_index = content.find('### RULES ###')
end_index = content.find('### END RULES ###')
result = content[start_index + 15:end_index]
sys_rules = [rule for rule in result.split('\n') if rule != '' and '###' in rule]
# 将sys_rules列表中的每个元素拆分出来,并且去掉空格,元素为字符串,例如:'### tuple ### allow tcp 20 0.0.0.0/0 any 0.0.0.0/0 in'
# 拆分后的列表元素为:{'protocol': 'tcp', 'ports': '20', 'types': 'allow', 'address': '0.0.0.0'}
rules = []
for rule in sys_rules:
rule = rule.split(' ')
rule = [i for i in rule if i != '']
rules.append({
'protocol': rule[4] if rule[4] != 'any' else 'tcp/udp',
'ports': rule[5] if rule[5].find(':') == -1 else rule[5].replace(':', '-'),
'types': 'accept' if rule[3] == 'allow' else 'drop',
'address': rule[8] if rule[8] != '0.0.0.0/0' else ''
})
unique_set = set(tuple(sorted(item.items())) for item in rules)
rules = [dict(item) for item in unique_set]
return rules
@staticmethod
def get_listening_processes(get: public.dict_obj):
'''
获取指定端口的进程信息
@param get:
@return:
'''
if 'port' not in get.get_items().keys(): return public.returnMsg(False, public.lang("Parameter passing error, please pass the port field"))
if len(get.port) == 0: return public.returnMsg(False, public.lang("Port cannot be empty"))
if get.port.find('-') != -1 or get.port.find(':') != -1: return public.returnMsg(False, public.lang("Range ports not supported"))
if not get.port.isdigit(): return public.returnMsg(False, public.lang("Port must be numeric"))
if int(get.port) < 1 or int(get.port) > 65535: return public.returnMsg(False, public.lang("The port range is 1-65535"))
process_name = ''
process_pid = ''
process_cmd = ''
cmd = "lsof -i:{}|grep LISTEN|grep -v COMMAND".format(get.port) + "|awk '{print $1,$2}'"
info_list = public.ExecShell(cmd)[0].split("\n")[0].split(" ")
if len(info_list) == 2:
process_name = info_list[0]
process_pid = info_list[1]
cmd_ps = "ps aux|grep {}|grep -v grep".format(process_pid)
cmd_awk = "|awk '{print $11,$12,$13,$14}'"
process_cmd = public.ExecShell(cmd_ps + cmd_awk)[0].split("\n")[0].strip(" ")
return {
"process_name": process_name,
"process_pid": process_pid,
"process_cmd": process_cmd
}
def get_diff_panel_firewall_rules(self, get):
'''
对比面板防火墙规则数据库和防火墙配置文件,取出差异的规则
@return:
'''
# 获取面板防火墙规则数据库
panel_firewall_rules = self.get_panel_firewall_rules()
# 获取防火墙配置文件
firewall_rules = self.get_sys_firewall_rules()
# 取出差异的规则
diff_rules = self._get_diff_rules(panel_firewall_rules, firewall_rules)
return diff_rules
def get_panel_firewall_rules(self):
'''
获取面板防火墙规则数据库
@return:
'''
all_ports = public.M('firewall_new').field('protocol,ports,types,address').order('addtime desc').select()
unique_set = set(tuple(sorted(item.items())) for item in all_ports)
new_ports = [dict(item) for item in unique_set]
return new_ports
def get_sys_firewall_rules(self):
'''
获取防火墙配置文件
@return:
'''
if self.__isUfw: return self._get_ufw_port_info()
if self.__isFirewalld: return self.__firewall_obj.recombine_rules()
return []
def _diff_dict_list(self, list1, list2):
'''
比较两个dict类型的list,返回list1中有,而list2中没有的元素
@param list1:
@param list2:
@return:
'''
list1_not_in_list2 = []
for item1 in list1:
found = False
try:
for item2 in list2:
# 对比'protocol,ports,types,address'是否相同
if all(item1[key] == item2[key] for key in ('protocol', 'ports', 'types', 'address')):
found = True
break
except KeyError:
continue
if not found: list1_not_in_list2.append(item1)
return list1_not_in_list2
def _get_diff_rules(self, panel_firewall_rules, firewall_rules):
'''
取出差异的规则
@param panel_firewall_rules:
@param firewall_rules:
@return:
'''
firewall_diff_rules_name = 'firewall_diff_rules'
firewall_diff_rules = {}
if os.path.isfile("config/{}.json".format(firewall_diff_rules_name)):
firewall_diff_rules = public.read_config(firewall_diff_rules_name)
if not firewall_diff_rules:
data = {
"panel_not_in_sys_fw_diff_list": self._diff_dict_list(panel_firewall_rules, firewall_rules),
"sys_not_in_panel_fw_diff_list": self._diff_dict_list(firewall_rules, panel_firewall_rules),
"panel_exclude": [],
"sys_exclude": []
}
public.save_config(firewall_diff_rules_name, data)
return data
panel_not_in_sys_fw_diff_list = self._diff_dict_list(panel_firewall_rules, firewall_rules)
sys_not_in_panel_fw_diff_list = self._diff_dict_list(firewall_rules, panel_firewall_rules)
# 如果firewall_diff_rules的panel_exclude和sys_exclude中有值,则将其从panel_not_in_sys_fw_diff_list和sys_not_in_panel_fw_diff_list中去掉
if firewall_diff_rules['panel_exclude']:
for key in firewall_diff_rules['panel_exclude']:
if key in panel_not_in_sys_fw_diff_list:
panel_not_in_sys_fw_diff_list.remove(key)
if firewall_diff_rules['sys_exclude']:
for key in firewall_diff_rules['sys_exclude']:
# panel_not_in_sys_fw_diff_list是list如果key在panel_not_in_sys_fw_diff_list中,则将其从panel_not_in_sys_fw_diff_list中去掉
if key in sys_not_in_panel_fw_diff_list:
sys_not_in_panel_fw_diff_list.remove(key)
# 将差异规则写入文件并返回
firewall_diff_rules['panel_not_in_sys_fw_diff_list'] = panel_not_in_sys_fw_diff_list
firewall_diff_rules['sys_not_in_panel_fw_diff_list'] = sys_not_in_panel_fw_diff_list
public.save_config(firewall_diff_rules_name, firewall_diff_rules)
return firewall_diff_rules
def exclude_diff_rules(self, get):
'''
排除firewall_diff_rules的规则并写入配置文件
@param get:
@return:
'''
try:
panel_excludes = get.panel_exclude if "panel_exclude" in get.get_items().keys() else {}
sys_excludes = get.sys_exclude if "sys_exclude" in get.get_items().keys() else {}
status = get.status if "status" in get.get_items().keys() else {}
# print("panel_excludes: ", panel_excludes)
if status == 'add':
return self._add_exclude(panel_excludes, sys_excludes)
elif status == 'del':
return self._del_exclude(panel_excludes, sys_excludes)
except Exception as e:
# print(e)
return public.returnMsg(False, public.lang("Ignore rule failed,{}!", e))
def _add_exclude(self, panel_excludes, sys_excludes):
'''
添加排除规则
@param panel_exclude:
@param sys_exclude:
@return:
'''
firewall_diff_rules_name = 'firewall_diff_rules'
firewall_diff_rules = {}
if os.path.isfile("config/{}.json".format(firewall_diff_rules_name)):
firewall_diff_rules = public.read_config(firewall_diff_rules_name)
if not firewall_diff_rules['panel_exclude']:
firewall_diff_rules['panel_exclude'] = panel_excludes
else:
for exclude in panel_excludes:
if exclude not in firewall_diff_rules['panel_exclude']:
firewall_diff_rules['panel_exclude'].append(exclude)
if not firewall_diff_rules['sys_exclude']:
firewall_diff_rules['sys_exclude'] = sys_excludes
else:
for exclude in sys_excludes:
if exclude not in firewall_diff_rules['sys_exclude']:
firewall_diff_rules['sys_exclude'].append(exclude)
public.save_config(firewall_diff_rules_name, firewall_diff_rules)
return public.returnMsg(True, public.lang("Ignore rules successfully!"))
def _del_exclude(self, panel_excludes, sys_excludes):
'''
删除排除规则
@param panel_excludes:
@param sys_excludes:
@return:
'''
firewall_diff_rules_name = 'firewall_diff_rules'
firewall_diff_rules = {}
if os.path.isfile("config/{}.json".format(firewall_diff_rules_name)):
firewall_diff_rules = public.read_config(firewall_diff_rules_name)
new_panel_exclude = []
new_sys_exclude = []
for exclude in firewall_diff_rules['panel_exclude']:
if exclude not in panel_excludes:
new_panel_exclude.append(exclude)
for exclude in firewall_diff_rules['sys_exclude']:
if exclude not in sys_excludes:
new_sys_exclude.append(exclude)
firewall_diff_rules['panel_exclude'] = new_panel_exclude
firewall_diff_rules['sys_exclude'] = new_sys_exclude
public.save_config(firewall_diff_rules_name, firewall_diff_rules)
return public.returnMsg(True, public.lang("Cancel ignore rule successfully!"))
def _add_firewall_rules(self, source_ip, protocol, port, types):
'''
添加防火墙规则
@param source_ip:
@param protocol:
@param port:
@param types:
@return:
'''
if self.__isUfw:
if port.find('-') != -1:
port = port.replace('-', ':')
self.add_ufw_rule(source_ip, protocol, port, types)
elif self.__isFirewalld:
if port.find(':') != -1:
port = port.replace(':', '-')
self.add_firewall_rule(source_ip, protocol, port, types)
else:
self.add_iptables_rule(source_ip, protocol, port, types)
def _del_firewall_rules(self, source_ip, protocol, port, types):
'''
删除防火墙规则
@param source_ip:
@param protocol:
@param port:
@param types:
@return:
'''
if self.__isUfw:
self.del_ufw_rule(source_ip, protocol, port, types)
elif self.__isFirewalld:
self.del_firewall_rule(source_ip, protocol, port, types)
else:
self.del_iptables_rule(source_ip, protocol, port, types)
def _modify_firewall_rules(self, address, protocol, port, type, source_ip, source_protocol, ports, types):
'''
修改防火墙规则1
@param address:
@param protocol:
@param port:
@param type:
@param source_ip:
@param source_protocol:
@param ports:
@param types:
@return:
'''
if self.__isUfw:
self.edit_ufw_rule(address, protocol, port, type, source_ip, source_protocol, ports, types)
elif self.__isFirewalld:
self.edit_firewall_rule(address, protocol, port, type, source_ip, source_protocol, ports, types)
else:
self.edit_iptables_rule(address, protocol, port, type, source_ip, source_protocol, ports, types)
# 新加代码----- end
# 端口防扫描 --- start
def _get_server_lists_scan(self):
"""
@name 获取服务器常用端口
@return:
"""
return {
"sshd": "{}".format(public.get_sshd_port()),
"mysql": "{}".format(public.get_mysql_info()["port"]),
"ftpd": "21",
"dovecot": "110,143",
"postfix": "25,465,587",
}
def get_anti_scan_logs(self, get):
"""
@name 获取防扫描日志
@param get:
@return:
"""
get = public.dict_obj()
server_lists = self._get_server_lists_scan()
result_dict = {
"currently_failed": 0,
"total_failed": 0,
"currently_banned": 0,
"total_banned": 0,
"banned_ip_list": []
}
import PluginLoader
for key in server_lists:
get.mode = key
logs_result = PluginLoader.plugin_run('fail2ban', 'get_status', get)
if type(logs_result['msg']) is dict:
result_dict["currently_failed"] += int(logs_result["msg"]["currently_failed"])
result_dict["total_failed"] += int(logs_result["msg"]["total_failed"])
result_dict["currently_banned"] += int(logs_result["msg"]["currently_banned"])
result_dict["total_banned"] += int(logs_result["msg"]["total_banned"])
result_dict["banned_ip_list"] += logs_result["msg"]["banned_ip_list"]
return result_dict
def get_anti_scan_status(self, get):
"""
@name 获取端口防扫描
@return:
"""
plugin_path = "/www/server/panel/plugin/fail2ban"
result_data = {"status": 0, "installed": 1}
if not os.path.exists("{}".format(plugin_path)):
result_data['installed'] = 0
return result_data
sock = "{}/fail2ban.sock".format(plugin_path)
if not os.path.exists(sock):
return result_data
server_lists = self._get_server_lists_scan()
s_file = '{}/plugin/fail2ban/config.json'.format(public.get_panel_path())
if os.path.exists(s_file):
try:
data = json.loads(public.readFile(s_file))
if len(data) == 0:
return result_data
for key in server_lists:
if key in data:
if data[key]['act'] != 'true':
result_data['status'] = 0
return result_data
result_data['status'] = 1
return result_data
except:
pass
return result_data
def set_anti_scan_status(self, get):
"""
@name 设置常用端口防扫描
@param get:
@return:
"""
scan_status = get.status if "status" in get else 0
param_dict = {
'type': 'edit',
'act': 'true' if scan_status == 1 else 'false',
'maxretry': '30',
'findtime': '300',
'bantime': '600',
'port': '',
'mode': ''
}
server_lists = self._get_server_lists_scan()
_set_up_path = "/www/server/panel/plugin/fail2ban"
_config = _set_up_path + "/config.json"
if not os.path.exists(_set_up_path + "/fail2ban_main.py"):
return public.returnMsg(False, public.lang("fail2ban plugin is not installed"))
if os.path.exists(_config):
try:
_conf_data = json.loads(public.ReadFile(_config))
except:
_conf_data = {}
else:
_conf_data = {}
import PluginLoader
# if scan_status == "1" and PluginLoader.plugin_run('fail2ban', 'get_fail2ban_status', get) is False:
# get.type = "start"
# PluginLoader.plugin_run('fail2ban', 'set_fail2ban_status', get)
for key in server_lists:
tmp = param_dict.copy()
tmp["port"] = server_lists[key]
tmp["mode"] = key
if key not in _conf_data:
tmp["type"] = "add"
else:
tmp["maxretry"] = _conf_data[key]["maxretry"]
tmp["findtime"] = _conf_data[key]["findtime"]
tmp["bantime"] = _conf_data[key]["bantime"]
tmp = public.to_dict_obj(tmp)
PluginLoader.plugin_run('fail2ban', 'set_anti', tmp)
del tmp
# if scan_status == "0":
# get.type = "stop"
# PluginLoader.plugin_run('fail2ban', 'set_fail2ban_status', get)
public.WriteLog("Port Scanning Prevention", "[Security]-[System Firewall]-[Set Port Scanning Prevention]")
return public.returnMsg(True, public.lang("Setup successful!"))
def del_ban_ip(self, get):
"""
删除封锁IP
@param get:
@return:
"""
get.ip = get.ip
import PluginLoader
server_lists = self._get_server_lists_scan()
for key in server_lists:
get.mode = key
PluginLoader.plugin_run('fail2ban', 'ban_ip_release', get)
return public.returnMsg(True, public.lang("Unlocked successfully"))
# 端口防扫描 --- end111
class firewalld:
__TREE = None
__ROOT = None
__CONF_FILE = '/etc/firewalld/zones/public.xml'
# 初始化配置文件XML对象
def __init__(self):
if self.__TREE: return
if not os.path.exists(self.__CONF_FILE): return
self.__TREE = ElementTree()
self.__TREE.parse(self.__CONF_FILE)
self.__ROOT = self.__TREE.getroot()
# 获取规则列表
def GetAcceptPortList(self):
try:
mlist = self.__ROOT.getchildren()
except:
mlist = []
data, arry = [], []
if len(mlist) < 1:
return data, arry
data, arry = [], []
for p in mlist:
tmp = {}
if p.tag == 'port':
tmp["protocol"] = p.attrib['protocol']
tmp['ports'] = p.attrib['port']
tmp['types'] = 'accept'
tmp['address'] = ''
elif p.tag == 'forward-port':
tmp["protocol"] = p.attrib['protocol']
tmp["port"] = p.attrib['port']
tmp["address"] = p.attrib.get('to-addr', '')
tmp["to-port"] = p.attrib['to-port']
arry.append(tmp)
continue
elif p.tag == 'rule':
tmp["types"] = 'accept'
tmp['ports'] = ''
tmp['protocol'] = ''
ch = p.getchildren()
for c in ch:
if c.tag == 'port':
tmp['protocol'] = c.attrib['protocol']
tmp['ports'] = c.attrib['port']
elif c.tag == 'drop':
tmp['types'] = 'drop'
elif c.tag == 'reject':
tmp['types'] = 'reject'
elif c.tag == 'source':
if "address" in c.attrib.keys():
tmp['address'] = c.attrib['address']
if "address" not in tmp:
tmp['address'] = ''
else:
continue
if tmp:
data.append(tmp)
return data, arry
def recombine_rules(self):
'''
重组防火墙规则,将tcp和udp端口相同的规则合并111111
@return:
'''
firewalld_rules = self.GetAcceptPortList()[0]
tcp_rules = []
udp_rules = []
for rule in firewalld_rules:
if rule['protocol'] == 'tcp':
tcp_rules.append(rule)
elif rule['protocol'] == 'udp':
udp_rules.append(rule)
result_rules = []
for tcp_rule in tcp_rules:
for udp_rule in udp_rules:
if tcp_rule['ports'] == udp_rule['ports']:
if tcp_rule['types'] == udp_rule['types']:
if tcp_rule['address'] == udp_rule['address']:
if tcp_rule['protocol'] != udp_rule['protocol']:
tcp_rule['protocol'] = 'tcp/udp'
udp_rules.remove(udp_rule)
break
result_rules.append(tcp_rule)
result_rules.extend(udp_rules)
return result_rules
class Sqlite():
db_file = None # 数据库文件
connection = None # 数据库连接对象
def __init__(self):
self.db_file = "/www/server/panel/data/default.db"
self.create_table()
# 获取数据库对象
def GetConn(self):
try:
if self.connection == None:
self.connection = sqlite3.connect(self.db_file)
self.connection.text_factory = str
except Exception as ex:
import traceback
traceback.print_exc()
return "error: " + str(ex)
def create_table(self):
# 创建firewall_new表记录端口规则
if not public.M('sqlite_master').where(
'type=? AND name=?', ('table', 'firewall_new')).count():
public.M('').execute('''CREATE TABLE "firewall_new" (
"id" INTEGER PRIMARY KEY AUTOINCREMENT,
"protocol" TEXT DEFAULT '',
"ports" TEXT,
"types" TEXT,
"address" TEXT DEFAULT '',
"brief" TEXT DEFAULT '',
"addtime" TEXT DEFAULT '');''')
public.M('').execute(
'CREATE INDEX firewall_new_port ON firewall_new (ports);')
if public.M('firewall_new').count() < 1:
# 写入默认数据
if not public.M('firewall_new').where('ports=?', ('80',)).count():
public.M('firewall_new').add(
'ports,brief,addtime,protocol,types',
('80', 'Website default port', '0000-00-00 00:00:00', 'tcp', 'accept')
)
if not public.M('firewall_new').where('ports=?', ('21',)).count():
public.M('firewall_new').add(
'ports,brief,addtime,protocol,types',
('21', 'FTP service', '0000-00-00 00:00:00', 'tcp', 'accept')
)
if not public.M('firewall_new').where('ports=?', ('22',)).count():
public.M('firewall_new').add(
'ports,brief,addtime,protocol,types',
('22', 'SSH remote service', '0000-00-00 00:00:00', 'tcp', 'accept')
)
try:
_panel_port_file = '/www/server/panel/data/port.pl'
panel_port = public.readFile(_panel_port_file).strip(" ").strip("\n")
except Exception:
panel_port = '8888'
if not public.M('firewall_new').where('ports=?', (panel_port,)).count():
public.M('firewall_new').add(
'ports,brief,addtime,protocol,types',
(panel_port, 'panel', '0000-00-00 00:00:00', 'tcp', 'accept')
)
# 创建firewall_ip表记录IP规则屏蔽或放行
if not public.M('sqlite_master').where(
'type=? AND name=?', ('table', 'firewall_ip')).count():
public.M('').execute('''CREATE TABLE "firewall_ip" (
"id" INTEGER PRIMARY KEY AUTOINCREMENT,
"types" TEXT,
"address" TEXT DEFAULT '',
"brief" TEXT DEFAULT '',
"addtime" TEXT DEFAULT '');''')
public.M('').execute(
'CREATE INDEX firewall_ip_addr ON firewall_ip (address);')
# 创建firewall_trans表记录端口转发记录
if not public.M('sqlite_master').where(
'type=? AND name=?', ('table', 'firewall_trans')).count():
public.M('').execute('''CREATE TABLE firewall_trans (
"id" INTEGER PRIMARY KEY AUTOINCREMENT,
"start_port" TEXT,
"ended_ip" TEXT,
"ended_port" TEXT,
"protocol" TEXT DEFAULT '',
"addtime" TEXT DEFAULT '');''')
public.M('').execute(
'CREATE INDEX firewall_trans_port ON firewall_trans (start_port);'
)
# 创建firewall_country表记录IP规则屏蔽或放行
if not public.M('sqlite_master').where(
'type=? AND name=?', ('table', 'firewall_country')).count():
public.M('').execute('''CREATE TABLE "firewall_country" (
"id" INTEGER PRIMARY KEY AUTOINCREMENT,
"types" TEXT,
"country" TEXT DEFAULT '',
"brief" TEXT DEFAULT '',
"addtime" TEXT DEFAULT '');''')
public.M('').execute('CREATE INDEX firewall_country_name ON firewall_country (country);')
# 创建firewall_domain表记录域名规则屏蔽或放行
if not public.M('sqlite_master').where('type=? AND name=?', ('table', 'firewall_domain')).count():
public.M('').execute('''CREATE TABLE "firewall_domain" (
"id" INTEGER PRIMARY KEY AUTOINCREMENT,
"types" TEXT,
"domain" TEXT,
"domain_total" TEXT,
"port" TEXT,
"sid" int DEFAULT 0,
"address" TEXT DEFAULT '',
"brief" TEXT DEFAULT '',
"protocol" TEXT DEFAULT '',
"addtime" TEXT DEFAULT '');''')
public.M('').execute('CREATE INDEX firewall_domain_addr ON firewall_domain (domain);')
# 修复之前已经创建的 firewall_domain 表无 domain_total 字段的问题
create_table_str = public.M('firewall_new').table('sqlite_master').where(
'type=? AND name=?', ('table', 'firewall_new')).getField('sql')
if 'domain_total' not in create_table_str:
public.M('firewall_new').execute('ALTER TABLE "firewall_domain" ADD "domain_total" TEXT DEFAULT ""')
# 修复之前已经创建的 firewall_new 表无 domain 字段的问题
create_table_str = public.M('firewall_new').table('sqlite_master').where(
'type=? AND name=?', ('table', 'firewall_new')).getField('sql')
if 'domain' not in create_table_str:
public.M('firewall_new').execute('ALTER TABLE "firewall_new" ADD "domain" TEXT DEFAULT ""')
if 'sid' not in create_table_str:
public.M('firewall_new').execute('ALTER TABLE "firewall_new" ADD "sid" int DEFAULT 0')
# 修复之前已经创建的 firewall_ip 表无 domain 字段的问题
create_table_str = public.M('firewall_ip').table('sqlite_master').where(
'type=? AND name=?', ('table', 'firewall_ip')).getField('sql')
if 'sid' not in create_table_str:
public.M('firewall_ip').execute('ALTER TABLE "firewall_ip" ADD "sid" int DEFAULT 0')
if 'domain' not in create_table_str:
public.M('firewall_ip').execute('ALTER TABLE "firewall_ip" ADD "domain" TEXT DEFAULT ""')
# 修复之前已经创建的 firewall_country 表无 ports 字段的问题
create_table_str = public.M('firewall_country').table('sqlite_master').where(
'type=? AND name=?', ('table', 'firewall_country')).getField('sql')
if 'ports' not in create_table_str:
public.M('firewall_country').execute('ALTER TABLE "firewall_country" ADD "ports" TEXT DEFAULT ""')
def create_trigger(self, sql):
self.GetConn()
self.connection.text_factory = str
try:
result = self.connection.execute(sql)
id = result.lastrowid
self.connection.commit()
self.rm_lock()
return id
except Exception as ex:
return "error: " + str(ex)
sql = """
CREATE TRIGGER update_port AFTER DELETE ON firewall
when old.port!=''
BEGIN
delete from firewall_new where ports = old.port;
delete from firewall_ip where address = old.port;
END;
"""
s = Sqlite()
s.create_trigger(sql)