石海三侠
首页
关于
暗色
(C:)
小说
农女成凰
血色万里
全部满分
白羽帝国
无敌俏丫鬟
九十九阶魔方
重生追美
神助攻
疯狂星期天
天命战警
技术
随笔
在小说站内容页中显示图片
iOS与nginx的孽缘,设置出错导致ssl不停报错
mccms漫城数据库配置文件保存位置
google play 测试链接位置!
jieqi cms 1.7加密免费版的章节模板位置
Mysql 3.7安全快速更新数据结构
在设置网站反向代理需要注意的问题
让宝塔面板识别cloudflare访问者的真实ip
设置为图床的服务器注意要点
webdrive 2019 映射驱动器到ubuntu
3072 object(s)
解决动态ip访问宝塔面板的白名单设置问题
服务器使用宝塔面板,安全策略只开放了80 443 以及宝塔面板端口,客户端要持续向服务器提交数据,也就必须访问3306 mysql端口,宝塔面板提供白名单,可以将客户端ip写入白名单,这样就可以访问所有端口,非常方便! 但是,因为客户端网络经常不定时切换ip,新切换的ip并不在白名单内,无法访问3306端口,导致数据更新失败。 解决思路:让服务器定时检测客户端ip,发现变更自动写入白名单。 具体方法:首先在dynu.com注册个账号,下载安装客户端,这样就可以随时用固定的域名检测客户端ip是多少,然后在服务器端设置定时任务,每隔3分钟ping一下域名,将返回的ip写入白名单,因为宝塔白名单有唯一性,所以不用担心写入无数个同样的ip。 宝塔面板>9.6.0 ubuntu python检测代码: ```python #coding: utf-8 #free_firewall import time, hashlib, sys, os, json, socket import glob, logging LOG_DIR = "/var/log/btwhitelist" MAX_LOG_DAYS = 2 logging.basicConfig( filename='/var/log/btwhitelist/debug.log', level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s' ) class bt_api: __BT_KEY = 'xxxxxxxxxxxxxxxxxxxxxx' __BT_PANEL = 'https://x.x.x.x:44415' def __init__(self, bt_panel=None, bt_key=None): if bt_panel: if not bt_panel.startswith(('http://', 'https://')): bt_panel = 'https://' + bt_panel self.__BT_PANEL = bt_panel if bt_key: self.__BT_KEY = bt_key def get_domain_ip(self, domain): try: return socket.gethostbyname(domain) except socket.gaierror: return None def get_firewall_rules(self): # 修改为使用新的IP规则列表接口 url = self.__BT_PANEL + '/firewall/com/ip_rules_list' p_data = self.__get_key_data() p_data['chain'] = "ALL" p_data['p'] = 1 # 添加分页参数 p_data['row'] = 30 # 获取足够多的规则 result = self.__http_post_cookie(url, p_data) return json.loads(result) if result else {"data": []} def add_firewall_rule(self, ip): # 修改为使用新的设置IP规则接口 url = self.__BT_PANEL + '/firewall/com/set_ip_rule' p_data = self.__get_key_data() # 构建符合新接口要求的参数 p_data['types'] = 'accept' p_data['brief'] = 'API_ADD_HOME' p_data['address'] = ip p_data['chain'] = 'INPUT' p_data['family'] = 'ipv4' p_data['zone'] = 'public' p_data['operation'] = 'add' p_data['strategy'] = 'accept' result = self.__http_post_cookie(url, p_data) try: return json.loads(result) except: return {"status": False, "msg": result} def ensure_ip_access(self, domain): ip = self.get_domain_ip(domain) if not ip: return {"status": False, "msg": f"域名解析失败: {domain}"} rules = self.get_firewall_rules() # 检查IP是否已在白名单中 existing_rules = [rule for rule in rules.get("data", []) if rule.get('address') == ip and rule.get('type') == 'accept' and rule.get('port') == '0:65535' and rule.get('protocol') == 'all'] if existing_rules: return {"status": True, "msg": f"IP {ip} 已在白名单中(全端口开放)"} else: result = self.add_firewall_rule(ip) print("添加规则响应:", result) # 调试输出 if result.get("status") or "设置成功" in str(result): return {"status": True, "msg": f"已添加IP {ip} 到防火墙白名单"} else: return {"status": False, "msg": f"添加失败: {result.get('msg', '未知错误')}"} def __get_md5(self, s): return hashlib.md5(s.encode('utf-8')).hexdigest() def __get_key_data(self): now_time = int(time.time()) token = self.__get_md5(str(now_time) + self.__get_md5(self.__BT_KEY)) return {"request_token": token, "request_time": now_time} def __http_post_cookie(self, url, p_data, timeout=10): cookie_file = f'./{self.__get_md5(self.__BT_PANEL)}.cookie' if sys.version_info[0] == 2: return "{}" # Python2支持省略 else: import urllib.request, ssl, http.cookiejar # 创建忽略SSL验证的上下文 context = ssl._create_unverified_context() cookie_obj = http.cookiejar.MozillaCookieJar(cookie_file) if os.path.exists(cookie_file): cookie_obj.load(cookie_file, ignore_discard=True, ignore_expires=True) # 创建使用自定义上下文的HTTPS处理器 https_handler = urllib.request.HTTPSHandler(context=context) # 创建包含cookie处理器和HTTPS处理器的opener handler = urllib.request.HTTPCookieProcessor(cookie_obj) opener = urllib.request.build_opener(handler, https_handler) # 准备请求数据 data = urllib.parse.urlencode(p_data).encode('utf-8') req = urllib.request.Request(url, data) try: response = opener.open(req, timeout=timeout) result = response.read() if type(result) == bytes: result = result.decode('utf-8') # 保存更新后的cookie cookie_obj.save(ignore_discard=True, ignore_expires=True) return result except Exception as e: error_msg = f"API请求失败: {str(e)}" print(error_msg) # 输出详细错误信息 return json.dumps({"status": False, "msg": error_msg}) # 清理旧日志 def clean_old_logs(): now = time.time() for log_file in glob.glob(f"{LOG_DIR}/*.log"): if os.stat(log_file).st_mtime < now - MAX_LOG_DAYS * 86400: try: os.remove(log_file) print(f"Deleted old log: {log_file}") except Exception as e: print(f"Error deleting {log_file}: {str(e)}") # 执行主逻辑 if __name__ == '__main__': clean_old_logs() logging.info("脚本启动") domain = "*.*.com" api = bt_api() # 调试步骤1: 先获取当前防火墙规则 print("获取防火墙规则...") rules = api.get_firewall_rules() print(f"当前规则数: {len(rules.get('data', []))}") print("=== 获取白名单 ===") addresses = [item["Address"] for item in rules["data"]] # 打印结果 for addr in addresses: print(addr) # 调试步骤2: 获取域名IP ip = api.get_domain_ip(domain) logging.info(f"域名 {domain} 解析到IP: {ip}") print(f"域名 {domain} 解析到IP: {ip}") # 调试步骤3: 执行主要功能 # result = api.ensure_ip_access(domain) result = api.add_firewall_rule(ip) print("最终结果:", json.dumps(result, ensure_ascii=False, indent=2)) logging.info(json.dumps(result, ensure_ascii=False, indent=2)) ``` 然后在宝塔面板计划任务中,增加 /usr/bin/python3 /root/btwhitelist.py # 搞定!
← 上一篇:Ubuntu 24 ext4转Btrfs教程
下一篇:用Xmind思维导图来写故事大纲 →