v1.3.9 feat: refactor config flow and firewall system

- remove pre-install UFW blocking logic, fallback to iptables when inactive
- unify firewall behavior across install, update, and uninstall
- normalize user input (spaces, full-width symbols)
- avoid unnecessary sing-box restart for CDN / bandwidth / port hopping changes
- reduce redundant single-use functions

feat: 重构配置流程与防火墙系统

- 移除安装前 UFW 强制校验,inactive 自动回退 iptables
- 统一安装 / 修改 / 卸载的防火墙逻辑
- 自动处理空格与全角符号输入
- 优选地址 / 带宽 / 端口跳跃修改不再重启 sing-box
- 清理单次调用函数,提升结构可读性
This commit is contained in:
fscarmen
2026-04-11 14:22:18 +00:00
parent 1c06a002da
commit d8edd86142
2 changed files with 163 additions and 175 deletions
+9 -8
View File
@@ -24,20 +24,22 @@
* * * * * *
## 1.更新信息 ## 1.更新信息
2026.04.11 v1.3.9 1. remove pre-install UFW blocking logic, fallback to iptables when inactive; 2. avoid unnecessary sing-box restart for CDN / bandwidth / port hopping changes; 3. reduce redundant single-use functions; 1. 移除安装前 UFW 强制校验,inactive 自动回退 iptables; 2. 优选地址 / 带宽 / 端口跳跃修改不再重启 sing-box; 3. 清理单次调用函数,提升结构可读性
2026.04.10 v1.3.8 1. Automatically detect UFW and switch rule management accordingly; 2. Merge the old -p (port change) functionality into -d (config editor), simplifying usage; 3. Remove the standalone -p / -P entry points entirely; 1. 自动检测 UFW 并切换规则管理方式; 2. 将原有 -p(修改端口)功能合并到 -d(配置修改),简化使用方式; 3. 完全移除独立的 -p / -P 入口 2026.04.10 v1.3.8 1. Automatically detect UFW and switch rule management accordingly; 2. Merge the old -p (port change) functionality into -d (config editor), simplifying usage; 3. Remove the standalone -p / -P entry points entirely; 1. 自动检测 UFW 并切换规则管理方式; 2. 将原有 -p(修改端口)功能合并到 -d(配置修改),简化使用方式; 3. 完全移除独立的 -p / -P 入口
2026.04.09 v1.3.7 1. Add support for enabling/disabling Hysteria2 port hopping and modifying port ranges after installation (sb -d); 2. Allow customization of Hysteria2 upload/download bandwidth without reinstalling; 3. Enhance client configuration with proper Hysteria2 bandwidth (up/down) and port hopping parameters; 1. 支持安装后启用/禁用 Hysteria2 端口跳跃,并可修改端口范围 (sb -d); 2. 支持自定义 Hysteria2 上下行带宽,无需重新安装; 3. 完善客户端配置,补充 Hysteria2 上传/下载速率及端口跳跃参数 2026.04.09 v1.3.7 1. Add support for enabling/disabling Hysteria2 port hopping and modifying port ranges after installation (sb -d); 2. Allow customization of Hysteria2 upload/download bandwidth without reinstalling; 3. Enhance client configuration with proper Hysteria2 bandwidth (up/down) and port hopping parameters; 1. 支持安装后启用/禁用 Hysteria2 端口跳跃,并可修改端口范围 (sb -d); 2. 支持自定义 Hysteria2 上下行带宽,无需重新安装; 3. 完善客户端配置,补充 Hysteria2 上传/下载速率及端口跳跃参数
2026.03.22 v1.3.6 1. Refactor: Support modification after installation (CDN, Reality SNI, node name, UUID/password, server IP); 2. Perf: Rewrite text() with bash nameref and pre-scanned TEXT_NEEDS_EVAL map to eliminate per-call grep subprocesses, significantly reducing repeated string-lookup overhead; 1. 重构:支持安装后多项修改(CDN、Reality SNI、节点名、UUID/密码、服务器 IP);2. 性能优化:用 bash nameref 和预扫描 TEXT_NEEDS_EVAL 关联数组重写 text() 函数,消除每次调用产生的 grep 子进程,大幅降低字符串查找开销
2026.03.14 v1.3.5 Performance: Optimize concurrent process execution to significantly accelerate script installation. 性能优化:优化并发进程执行,大幅提升脚本安装速度
2026.02.08 v1.3.4 Chore: upgrade SS encryption method to SS-2022 spec; 新装的 Shadowsocks 协议加密方式从 aes-128-gcm 改为 2022-blake3-aes-128-gcm
<details> <details>
<summary>历史更新 history(点击即可展开或收起)</summary> <summary>历史更新 history(点击即可展开或收起)</summary>
<br> <br>
>2026.03.22 v1.3.6 1. Refactor: Support modification after installation (CDN, Reality SNI, node name, UUID/password, server IP); 2. Perf: Rewrite text() with bash nameref and pre-scanned TEXT_NEEDS_EVAL map to eliminate per-call grep subprocesses, significantly reducing repeated string-lookup overhead; 1. 重构:支持安装后多项修改(CDN、Reality SNI、节点名、UUID/密码、服务器 IP);2. 性能优化:用 bash nameref 和预扫描 TEXT_NEEDS_EVAL 关联数组重写 text() 函数,消除每次调用产生的 grep 子进程,大幅降低字符串查找开销
>
>2026.03.14 v1.3.5 Performance: Optimize concurrent process execution to significantly accelerate script installation. 性能优化:优化并发进程执行,大幅提升脚本安装速度
>
>2026.02.08 v1.3.4 Chore: upgrade SS encryption method to SS-2022 spec; 新装的 Shadowsocks 协议加密方式从 aes-128-gcm 改为 2022-blake3-aes-128-gcm
>
>2026.01.20 v1.3.3 1. Security: In v2rayN, add pinnedPeerCertSha256 for Hysteria2/Trojan to prevent MITM (replaces AllowInsecure); 2. Compatibility: Refactor SFM/SFI/SFA configs for sing-box v1.13.0+; 1. 安全增强:v2rayN 的 Hysteria2/Trojan 支持 pinnedPeerCertSha256 替代 跳过证书验证,防御 MITM 攻击; 2. 适配更新:重构 SFM/SFI/SFA 配置,支持 sing-box v1.13.0+ >2026.01.20 v1.3.3 1. Security: In v2rayN, add pinnedPeerCertSha256 for Hysteria2/Trojan to prevent MITM (replaces AllowInsecure); 2. Compatibility: Refactor SFM/SFI/SFA configs for sing-box v1.13.0+; 1. 安全增强:v2rayN 的 Hysteria2/Trojan 支持 pinnedPeerCertSha256 替代 跳过证书验证,防御 MITM 攻击; 2. 适配更新:重构 SFM/SFI/SFA 配置,支持 sing-box v1.13.0+
> >
>2025.12.11 v1.3.2 Argo tunnel creation via API. Suitable for users with large-scale deployments, one Token for all. Automatically completed: Create tunnel > DNS configuration > Origin settings. Thanks to [zmlu] for providing the method: https://raw.githubusercontent.com/zmlu/sba/main/tunnel.sh; Argo 隧道新增通过 API 创建,适合大量部署的用户,一个 Token 走天下。自动完成:创建隧道 > DNS 配置 > 回源设置。感谢热心网友 [zmlu] 提供的方法: https://raw.githubusercontent.com/zmlu/sba/main/tunnel.sh >2025.12.11 v1.3.2 Argo tunnel creation via API. Suitable for users with large-scale deployments, one Token for all. Automatically completed: Create tunnel > DNS configuration > Origin settings. Thanks to [zmlu] for providing the method: https://raw.githubusercontent.com/zmlu/sba/main/tunnel.sh; Argo 隧道新增通过 API 创建,适合大量部署的用户,一个 Token 走天下。自动完成:创建隧道 > DNS 配置 > 回源设置。感谢热心网友 [zmlu] 提供的方法: https://raw.githubusercontent.com/zmlu/sba/main/tunnel.sh
@@ -164,8 +166,7 @@ sb
| -k | Quick deploy (English version) 使用英文快速安装 | | -k | Quick deploy (English version) 使用英文快速安装 |
| -u | Uninstall 卸载 | | -u | Uninstall 卸载 |
| -n | Export Nodes list 显示节点信息 | | -n | Export Nodes list 显示节点信息 |
| -p <start port> | Change the nodes start port 更改节点的起始端口 | | -d | Change config 修改参数 |
| -d | Change CDN 更换 CDN |
| -s | Stop / Start the Sing-box service 停止/开启 Sing-box 服务 | | -s | Stop / Start the Sing-box service 停止/开启 Sing-box 服务 |
| -a | Stop / Start the Argo Tunnel service 停止/开启 Argo Tunnel 服务 | | -a | Stop / Start the Argo Tunnel service 停止/开启 Argo Tunnel 服务 |
| -v | Sync Argo Xray to the newest 同步 Argo Xray 到最新版本 | | -v | Sync Argo Xray to the newest 同步 Argo Xray 到最新版本 |
+154 -167
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env bash #!/usr/bin/env bash
# 当前脚本版本号 # 当前脚本版本号
VERSION='v1.3.8 (2026.04.10)' VERSION='v1.3.9 (2026.04.11)'
# Github 反代加速代理 # Github 反代加速代理
GITHUB_PROXY=('https://hub.glowp.xyz/' 'https://proxy.vvvv.ee/') GITHUB_PROXY=('https://hub.glowp.xyz/' 'https://proxy.vvvv.ee/')
@@ -32,21 +32,15 @@ cleanup_temp() {
rm -rf "$TEMP_DIR" rm -rf "$TEMP_DIR"
} }
on_interrupt_exit() {
cleanup_temp
echo -e '\n'
exit 1
}
trap cleanup_temp EXIT trap cleanup_temp EXIT
trap on_interrupt_exit INT QUIT TERM trap 'cleanup_temp; printf "\n"; exit 1' INT QUIT TERM
mkdir -p "$TEMP_DIR" mkdir -p "$TEMP_DIR"
E[0]="Language:\n 1. English (default) \n 2. 简体中文" E[0]="Language:\n 1. English (default) \n 2. 简体中文"
C[0]="${E[0]}" C[0]="${E[0]}"
E[1]="1. Automatically detect UFW and switch rule management accordingly; 2. Merge the old -p (port change) functionality into -d (config editor), simplifying usage; 3. Remove the standalone -p / -P entry points entirely" E[1]="1. remove pre-install UFW blocking logic, fallback to iptables when inactive; 2. avoid unnecessary sing-box restart for CDN / bandwidth / port hopping changes; 3. reduce redundant single-use functions"
C[1]="1. 自动检测 UFW 并切换规则管理方式; 2. 将原有 -p(修改端口)功能合并到 -d(配置修改),简化使用方式; 3. 完全移除独立的 -p / -P 入口" C[1]="1. 移除安装前 UFW 强制校验,inactive 自动回退 iptables; 2. 优选地址 / 带宽 / 端口跳跃修改不再重启 sing-box; 3. 清理单次调用函数,提升结构可读性"
E[2]="Downloading Sing-box. Please wait a seconds ..." E[2]="Downloading Sing-box. Please wait a seconds ..."
C[2]="下载 Sing-box 中,请稍等 ..." C[2]="下载 Sing-box 中,请稍等 ..."
E[3]="Input errors up to 5 times.The script is aborted." E[3]="Input errors up to 5 times.The script is aborted."
@@ -337,8 +331,6 @@ E[145]="UFW is not active. PortHopping forwarding rules were written, but you sh
C[145]="UFW 未处于激活状态。PortHopping 转发规则已写入,但建议手动启用 UFW 以确保策略生效" C[145]="UFW 未处于激活状态。PortHopping 转发规则已写入,但建议手动启用 UFW 以确保策略生效"
E[146]="Failed to update UFW PortHopping forwarding rules. Please check UFW configuration files manually." E[146]="Failed to update UFW PortHopping forwarding rules. Please check UFW configuration files manually."
C[146]="更新 UFW 的 PortHopping 转发规则失败,请手动检查 UFW 配置文件" C[146]="更新 UFW 的 PortHopping 转发规则失败,请手动检查 UFW 配置文件"
E[147]="\n[WARN] UFW is detected, but its current status is: \${UFW_STATUS:-unknown}\nBecause UFW rules can affect SSH and port forwarding, please enable and verify UFW manually before running this installer again.\nRecommended first step: ufw allow ssh\nThen enable UFW manually, confirm your SSH session still works, and rerun the script.\nInstaller will now exit.\n"
C[147]="\n[警告] 检测到系统已安装 UFW,但当前状态为: \${UFW_STATUS:-unknown}\n由于 UFW 与 SSH 及端口转发规则关系较复杂,建议先手动启用并确认 UFW 配置正确后,再重新运行本安装脚本。\n建议先执行: ufw allow ssh\n然后手动启用 UFW,确认 SSH 连接正常后,再重新运行脚本。\n安装程序现在退出。\n"
# 自定义字体彩色,read 函数 # 自定义字体彩色,read 函数
warning() { echo -e "\033[31m\033[01m$*\033[0m"; } # 红色 warning() { echo -e "\033[31m\033[01m$*\033[0m"; } # 红色
@@ -1105,18 +1097,6 @@ check_root() {
[ "$(id -u)" != 0 ] && error "\n $(text 43) \n" [ "$(id -u)" != 0 ] && error "\n $(text 43) \n"
} }
check_ufw_active_preinstall() {
command -v ufw >/dev/null 2>&1 && IS_UFW=is_ufw || return 0
local UFW_STATUS
UFW_STATUS=$(ufw status 2>/dev/null | awk '/^Status/{print $NF; exit}')
[ "$UFW_STATUS" = 'active' ] && return 0
eval "echo -e \"\033[31m\033[01m${E[147]}\033[0m\""
eval "echo -e \"\033[31m\033[01m${C[147]}\033[0m\""
exit 1
}
# 判断处理器架构 # 判断处理器架构
check_arch() { check_arch() {
[ "$SYSTEM" = 'Alpine' ] && local IS_MUSL='-musl' [ "$SYSTEM" = 'Alpine' ] && local IS_MUSL='-musl'
@@ -1458,10 +1438,44 @@ add_port_hopping_nat() {
local PORT_HOPPING_TARGET=$3 local PORT_HOPPING_TARGET=$3
local COMMENT="NAT ${PORT_HOPPING_START}:${PORT_HOPPING_END} to ${PORT_HOPPING_TARGET} (Sing-box Family Bucket)" local COMMENT="NAT ${PORT_HOPPING_START}:${PORT_HOPPING_END} to ${PORT_HOPPING_TARGET} (Sing-box Family Bucket)"
local FW_BACKEND local FW_BACKEND
local FW_CHECK=() FW_INSTALL=() FW_TO_INSTALL=()
install_firewall_deps
FW_BACKEND=$(check_port_hopping_firewall) FW_BACKEND=$(check_port_hopping_firewall)
case "$FW_BACKEND" in
ufw )
info "\n $(text 144) \n"
;;
alpine-iptables )
FW_CHECK=("iptables")
FW_INSTALL=("iptables")
;;
firewalld )
FW_CHECK=("firewall-cmd")
FW_INSTALL=("firewalld")
;;
* )
FW_CHECK=("iptables" "netfilter-persistent")
FW_INSTALL=("iptables" "netfilter-persistent")
;;
esac
for i in "${!FW_CHECK[@]}"; do
! command -v "${FW_CHECK[i]}" >/dev/null 2>&1 && FW_TO_INSTALL+=("${FW_INSTALL[i]}")
done
if [ "${#FW_TO_INSTALL[@]}" -gt 0 ]; then
FW_TO_INSTALL=($(printf "%s\n" "${FW_TO_INSTALL[@]}" | sort -u))
[ "$SYSTEM" != 'CentOS' ] && ${PACKAGE_UPDATE[int]} >/dev/null 2>&1
${PACKAGE_INSTALL[int]} "${FW_TO_INSTALL[@]}" >/dev/null 2>&1
fi
if [ "$FW_BACKEND" = 'firewalld' ]; then
[ "$(systemctl is-active firewalld 2>/dev/null)" != 'active' ] && cmd_systemctl enable firewalld >/dev/null 2>&1
[ "$(firewall-cmd --zone=public --get-target 2>/dev/null)" != 'ACCEPT' ] && firewall-cmd --zone=public --set-target=ACCEPT --permanent >/dev/null 2>&1
firewall-cmd --reload >/dev/null 2>&1
fi
if [ "$FW_BACKEND" = 'ufw' ]; then if [ "$FW_BACKEND" = 'ufw' ]; then
add_port_hopping_ufw_rules "$PORT_HOPPING_START" "$PORT_HOPPING_END" "$PORT_HOPPING_TARGET" || warning "\n $(text 146) \n" add_port_hopping_ufw_rules "$PORT_HOPPING_START" "$PORT_HOPPING_END" "$PORT_HOPPING_TARGET" || warning "\n $(text 146) \n"
@@ -1870,21 +1884,12 @@ check_dependencies() {
} }
# 生成 UFW PortHopping 备注 # 生成 UFW PortHopping 备注
port_hopping_ufw_comment() {
local PORT_HOPPING_START=$1
local PORT_HOPPING_END=$2
local PORT_HOPPING_TARGET=$3
echo "Sing-box Family Bucket UFW NAT ${PORT_HOPPING_START}:${PORT_HOPPING_END} -> ${PORT_HOPPING_TARGET}"
}
# 写入 UFW PortHopping NAT 规则
add_port_hopping_ufw_rules() { add_port_hopping_ufw_rules() {
local PORT_HOPPING_START=$1 local PORT_HOPPING_START=$1
local PORT_HOPPING_END=$2 local PORT_HOPPING_END=$2
local PORT_HOPPING_TARGET=$3 local PORT_HOPPING_TARGET=$3
local TARGET_PORT="$3" local TARGET_PORT="$3"
local COMMENT local COMMENT="Sing-box Family Bucket UFW NAT ${PORT_HOPPING_START}:${PORT_HOPPING_END} -> ${TARGET_PORT}"
COMMENT=$(port_hopping_ufw_comment "$PORT_HOPPING_START" "$PORT_HOPPING_END" "$TARGET_PORT")
[ -z "$PORT_HOPPING_START" ] && return 1 [ -z "$PORT_HOPPING_START" ] && return 1
[ -z "$PORT_HOPPING_END" ] && return 1 [ -z "$PORT_HOPPING_END" ] && return 1
@@ -2041,9 +2046,17 @@ check_port_hopping_ufw_rules() {
# 检测防火墙后端 # 检测防火墙后端
check_firewall_backend() { check_firewall_backend() {
if [ "$IS_UFW" = 'is_ufw' ]; then local UFW_STATUS
echo 'ufw'
elif [ "$SYSTEM" = 'Alpine' ]; then if command -v ufw >/dev/null 2>&1; then
UFW_STATUS=$(ufw status 2>/dev/null | awk '/^Status/{print $NF; exit}')
[ "$UFW_STATUS" = 'active' ] && {
echo 'ufw'
return
}
fi
if [ "$SYSTEM" = 'Alpine' ]; then
echo 'alpine-iptables' echo 'alpine-iptables'
elif command -v firewall-cmd >/dev/null 2>&1 || [ "$SYSTEM" = 'CentOS' ]; then elif command -v firewall-cmd >/dev/null 2>&1 || [ "$SYSTEM" = 'CentOS' ]; then
echo 'firewalld' echo 'firewalld'
@@ -2063,35 +2076,6 @@ init_firewall_state_dir() {
} }
# 读取上一次由脚本管理的普通端口规则 # 读取上一次由脚本管理的普通端口规则
read_service_firewall_state() {
MANAGED_TCP_PORTS=()
MANAGED_UDP_PORTS=()
[ ! -s "$SERVICE_FIREWALL_STATE_FILE" ] && return 0
while read -r PROTO PORT; do
case "$PROTO" in
tcp ) MANAGED_TCP_PORTS+=("$PORT") ;;
udp ) MANAGED_UDP_PORTS+=("$PORT") ;;
esac
done < "$SERVICE_FIREWALL_STATE_FILE"
}
# 写入本次由脚本管理的普通端口规则
write_service_firewall_state() {
init_firewall_state_dir
: > "$SERVICE_FIREWALL_STATE_FILE"
for PORT in "${EXPOSED_TCP_PORTS[@]}"; do
[ -n "$PORT" ] && echo "tcp $PORT" >> "$SERVICE_FIREWALL_STATE_FILE"
done
for PORT in "${EXPOSED_UDP_PORTS[@]}"; do
[ -n "$PORT" ] && echo "udp $PORT" >> "$SERVICE_FIREWALL_STATE_FILE"
done
}
# 端口数组去重追加
append_unique_port() { append_unique_port() {
local ARRAY_NAME=$1 local ARRAY_NAME=$1
local PORT=$2 local PORT=$2
@@ -2218,18 +2202,10 @@ del_service_port_rule_firewalld() {
} }
# iptables 普通端口规则备注 # iptables 普通端口规则备注
service_port_iptables_comment() {
local PROTO=$1
local PORT=$2
echo "Sing-box Family Bucket PORT ${PROTO} ${PORT}"
}
# 添加 iptables 普通端口规则
add_service_port_rule_iptables() { add_service_port_rule_iptables() {
local PROTO=$1 local PROTO=$1
local PORT=$2 local PORT=$2
local COMMENT local COMMENT="Sing-box Family Bucket PORT ${PROTO} ${PORT}"
COMMENT=$(service_port_iptables_comment "$PROTO" "$PORT")
[ -z "$PROTO" ] || [ -z "$PORT" ] && return 1 [ -z "$PROTO" ] || [ -z "$PORT" ] && return 1
@@ -2244,8 +2220,7 @@ add_service_port_rule_iptables() {
del_service_port_rule_iptables() { del_service_port_rule_iptables() {
local PROTO=$1 local PROTO=$1
local PORT=$2 local PORT=$2
local COMMENT local COMMENT="Sing-box Family Bucket PORT ${PROTO} ${PORT}"
COMMENT=$(service_port_iptables_comment "$PROTO" "$PORT")
[ -z "$PROTO" ] || [ -z "$PORT" ] && return 0 [ -z "$PROTO" ] || [ -z "$PORT" ] && return 0
@@ -2281,7 +2256,15 @@ purge_service_firewall_rules() {
FW_BACKEND=$(check_firewall_backend) FW_BACKEND=$(check_firewall_backend)
init_firewall_state_dir init_firewall_state_dir
read_service_firewall_state MANAGED_TCP_PORTS=()
MANAGED_UDP_PORTS=()
[ ! -s "$SERVICE_FIREWALL_STATE_FILE" ] || while read -r PROTO PORT; do
case "$PROTO" in
tcp ) MANAGED_TCP_PORTS+=("$PORT") ;;
udp ) MANAGED_UDP_PORTS+=("$PORT") ;;
esac
done < "$SERVICE_FIREWALL_STATE_FILE"
case "$FW_BACKEND" in case "$FW_BACKEND" in
ufw ) ufw )
@@ -2312,14 +2295,87 @@ purge_service_firewall_rules() {
} }
# 同步普通服务端口规则 # 同步普通服务端口规则
sync_service_firewall_rules() { # 同步所有防火墙规则
sync_firewall_rules() {
local FW_BACKEND local FW_BACKEND
local PORT local PORT
local HY2_FILE="${WORK_DIR}/conf/*${NODE_TAG[1]}_inbounds.json"
local HY2_TARGET DESIRED_START DESIRED_END
local EXISTING_START EXISTING_END EXISTING_TARGET
local FILE BASENAME NGINX_PORT HAS_NGINX=false
EXPOSED_TCP_PORTS=()
EXPOSED_UDP_PORTS=()
if [ -s "${WORK_DIR}/nginx.conf" ]; then
HAS_NGINX=true
NGINX_PORT=$(awk '
/listen[[:space:]]+[0-9]+[[:space:]]*;/ && $2 !~ /^\[/ {
gsub(/;/, "", $2)
print $2
exit
}
' "${WORK_DIR}/nginx.conf")
append_unique_port EXPOSED_TCP_PORTS "$NGINX_PORT"
fi
for FILE in ${WORK_DIR}/conf/*_inbounds.json; do
[ ! -s "$FILE" ] && continue
BASENAME=$(basename "$FILE")
PORT=$(awk -F '[:,]' '/"listen_port"/{gsub(/[[:space:]]/, "", $2); print $2; exit}' "$FILE")
[ -z "$PORT" ] && continue
case "$BASENAME" in
*hysteria2_inbounds.json|*tuic_inbounds.json )
append_unique_port EXPOSED_UDP_PORTS "$PORT"
;;
*vmess-ws_inbounds.json|*vless-ws-tls_inbounds.json )
[ "$HAS_NGINX" = false ] && append_unique_port EXPOSED_TCP_PORTS "$PORT"
;;
* )
append_unique_port EXPOSED_TCP_PORTS "$PORT"
;;
esac
done
collect_exposed_ports
FW_BACKEND=$(check_firewall_backend) FW_BACKEND=$(check_firewall_backend)
purge_service_firewall_rules init_firewall_state_dir
MANAGED_TCP_PORTS=()
MANAGED_UDP_PORTS=()
if [ -s "$SERVICE_FIREWALL_STATE_FILE" ]; then
while read -r PROTO PORT; do
case "$PROTO" in
tcp ) MANAGED_TCP_PORTS+=("$PORT") ;;
udp ) MANAGED_UDP_PORTS+=("$PORT") ;;
esac
done < "$SERVICE_FIREWALL_STATE_FILE"
fi
case "$FW_BACKEND" in
ufw )
purge_service_port_rules_ufw
;;
firewalld )
for PORT in "${MANAGED_TCP_PORTS[@]}"; do
del_service_port_rule_firewalld tcp "$PORT"
done
for PORT in "${MANAGED_UDP_PORTS[@]}"; do
del_service_port_rule_firewalld udp "$PORT"
done
;;
alpine-iptables|iptables )
for PORT in "${MANAGED_TCP_PORTS[@]}"; do
del_service_port_rule_iptables tcp "$PORT"
done
for PORT in "${MANAGED_UDP_PORTS[@]}"; do
del_service_port_rule_iptables udp "$PORT"
done
;;
esac
: > "$SERVICE_FIREWALL_STATE_FILE"
reload_or_save_firewall_rules
case "$FW_BACKEND" in case "$FW_BACKEND" in
ufw ) ufw )
@@ -2348,15 +2404,14 @@ sync_service_firewall_rules() {
;; ;;
esac esac
write_service_firewall_state : > "$SERVICE_FIREWALL_STATE_FILE"
for PORT in "${EXPOSED_TCP_PORTS[@]}"; do
[ -n "$PORT" ] && echo "tcp $PORT" >> "$SERVICE_FIREWALL_STATE_FILE"
done
for PORT in "${EXPOSED_UDP_PORTS[@]}"; do
[ -n "$PORT" ] && echo "udp $PORT" >> "$SERVICE_FIREWALL_STATE_FILE"
done
reload_or_save_firewall_rules reload_or_save_firewall_rules
}
# 同步 Hysteria2 端口跳跃规则
sync_port_hopping_firewall_rules() {
local HY2_FILE="${WORK_DIR}/conf/*${NODE_TAG[1]}_inbounds.json"
local HY2_TARGET DESIRED_START DESIRED_END
local EXISTING_START EXISTING_END EXISTING_TARGET
HY2_TARGET=$(awk -F '[:,]' '/"listen_port"/{gsub(/[[:space:]]/, "", $2); print $2; exit}' ${HY2_FILE} 2>/dev/null) HY2_TARGET=$(awk -F '[:,]' '/"listen_port"/{gsub(/[[:space:]]/, "", $2); print $2; exit}' ${HY2_FILE} 2>/dev/null)
@@ -2381,9 +2436,7 @@ sync_port_hopping_firewall_rules() {
return 0 return 0
fi fi
if [ "$EXISTING_START" != "$DESIRED_START" ] || \ if [ "$EXISTING_START" != "$DESIRED_START" ] || [ "$EXISTING_END" != "$DESIRED_END" ] || [ "$EXISTING_TARGET" != "$HY2_TARGET" ]; then
[ "$EXISTING_END" != "$DESIRED_END" ] || \
[ "$EXISTING_TARGET" != "$HY2_TARGET" ]; then
[ -n "$EXISTING_START" ] && [ -n "$EXISTING_END" ] && del_port_hopping_nat [ -n "$EXISTING_START" ] && [ -n "$EXISTING_END" ] && del_port_hopping_nat
PORT_HOPPING_START="$DESIRED_START" PORT_HOPPING_START="$DESIRED_START"
PORT_HOPPING_END="$DESIRED_END" PORT_HOPPING_END="$DESIRED_END"
@@ -2392,77 +2445,6 @@ sync_port_hopping_firewall_rules() {
add_port_hopping_nat "$PORT_HOPPING_START" "$PORT_HOPPING_END" "$PORT_HOPPING_TARGET" add_port_hopping_nat "$PORT_HOPPING_START" "$PORT_HOPPING_END" "$PORT_HOPPING_TARGET"
fi fi
} }
# 同步所有防火墙规则
sync_firewall_rules() {
sync_service_firewall_rules
sync_port_hopping_firewall_rules
}
# 清理所有由脚本管理的防火墙规则
purge_managed_firewall_rules() {
purge_service_firewall_rules
del_port_hopping_nat >/dev/null 2>&1 || true
}
# 按需安装端口跳跃所需的防火墙依赖
# 策略:UFW → 不安装 iptables / netfilter-persistentAlpine → iptablesCentOS 或已装 firewalld → firewalld;其他 → iptables + netfilter-persistent
install_firewall_deps() {
local FW_BACKEND
FW_BACKEND=$(check_port_hopping_firewall)
local FW_CHECK=() FW_INSTALL=() FW_TO_INSTALL=()
case "$FW_BACKEND" in
ufw )
info "\n $(text 144) \n"
return 0
;;
alpine-iptables )
FW_CHECK=("iptables")
FW_INSTALL=("iptables")
;;
firewalld )
FW_CHECK=("firewall-cmd")
FW_INSTALL=("firewalld")
;;
* )
FW_CHECK=("iptables" "netfilter-persistent")
FW_INSTALL=("iptables" "netfilter-persistent")
;;
esac
for i in "${!FW_CHECK[@]}"; do
! command -v "${FW_CHECK[i]}" >/dev/null 2>&1 && FW_TO_INSTALL+=("${FW_INSTALL[i]}")
done
if [ "${#FW_TO_INSTALL[@]}" -gt 0 ]; then
FW_TO_INSTALL=($(printf "%s\n" "${FW_TO_INSTALL[@]}" | sort -u))
[ "$SYSTEM" != 'CentOS' ] && ${PACKAGE_UPDATE[int]} >/dev/null 2>&1
${PACKAGE_INSTALL[int]} "${FW_TO_INSTALL[@]}" >/dev/null 2>&1
fi
# 安装后确保 firewalld 已启动(CentOS 或已装 firewalld 的系统)
if [ "$FW_BACKEND" = 'firewalld' ]; then
[ "$(systemctl is-active firewalld 2>/dev/null)" != 'active' ] && cmd_systemctl enable firewalld >/dev/null 2>&1
[ "$(firewall-cmd --zone=public --get-target 2>/dev/null)" != 'ACCEPT' ] && firewall-cmd --zone=public --set-target=ACCEPT --permanent >/dev/null 2>&1
firewall-cmd --reload >/dev/null 2>&1
fi
}
# 检查并安装 nginx
check_nginx() {
if ! command -v nginx >/dev/null 2>&1; then
info "\n $(text 7) nginx \n"
${PACKAGE_UPDATE[int]} >/dev/null 2>&1
${PACKAGE_INSTALL[int]} nginx >/dev/null 2>&1
# 如果新安装的 Nginx,使用 cmd_systemctl 停止服务
cmd_systemctl disable nginx
fi
}
# Json 生成两个配置文件
export_argo_json_file() { export_argo_json_file() {
local FILE_PATH=$1 local FILE_PATH=$1
[[ -z "$PORT_NGINX" && -s ${WORK_DIR}/nginx.conf ]] && local PORT_NGINX=$(awk '/listen/{print $2; exit}' ${WORK_DIR}/nginx.conf) [[ -z "$PORT_NGINX" && -s ${WORK_DIR}/nginx.conf ]] && local PORT_NGINX=$(awk '/listen/{print $2; exit}' ${WORK_DIR}/nginx.conf)
@@ -3558,7 +3540,12 @@ fetch_quicktunnel_domain() {
# 安装 sing-box 全家桶 # 安装 sing-box 全家桶
install_sing-box() { install_sing-box() {
sing-box_variables sing-box_variables
[ -n "$PORT_NGINX" ] && check_nginx if [ -n "$PORT_NGINX" ] && ! command -v nginx >/dev/null 2>&1; then
info "\n $(text 7) nginx \n"
${PACKAGE_UPDATE[int]} >/dev/null 2>&1
${PACKAGE_INSTALL[int]} nginx >/dev/null 2>&1
cmd_systemctl disable nginx
fi
[ ! -d ${WORK_DIR}/logs ] && mkdir -p ${WORK_DIR}/logs [ ! -d ${WORK_DIR}/logs ] && mkdir -p ${WORK_DIR}/logs
[ ! -d ${TEMP_DIR} ] && mkdir -p $TEMP_DIR [ ! -d ${TEMP_DIR} ] && mkdir -p $TEMP_DIR
ssl_certificate $TLS_SERVER_DEFAULT ssl_certificate $TLS_SERVER_DEFAULT
@@ -4679,7 +4666,8 @@ uninstall() {
sleep 1 sleep 1
[[ -s ${WORK_DIR}/nginx.conf && "$(ps -ef | grep -c '[n]ginx')" = 0 ]] && reading "\n $(text 83) " REMOVE_NGINX [[ -s ${WORK_DIR}/nginx.conf && "$(ps -ef | grep -c '[n]ginx')" = 0 ]] && reading "\n $(text 83) " REMOVE_NGINX
[ "${REMOVE_NGINX,,}" = 'y' ] && ${PACKAGE_UNINSTALL[int]} nginx >/dev/null 2>&1 [ "${REMOVE_NGINX,,}" = 'y' ] && ${PACKAGE_UNINSTALL[int]} nginx >/dev/null 2>&1
purge_managed_firewall_rules purge_service_firewall_rules
del_port_hopping_nat >/dev/null 2>&1 || true
rm -rf ${WORK_DIR} ${TEMP_DIR} ${ARGO_DAEMON_FILE} ${SINGBOX_DAEMON_FILE} /usr/bin/sb rm -rf ${WORK_DIR} ${TEMP_DIR} ${ARGO_DAEMON_FILE} ${SINGBOX_DAEMON_FILE} /usr/bin/sb
info "\n $(text 16) \n" info "\n $(text 16) \n"
else else
@@ -4863,7 +4851,6 @@ if [[ -n "$CONFIG_FILE" && -s "$CONFIG_FILE" ]]; then
fi fi
check_root check_root
check_ufw_active_preinstall
select_language select_language
check_system_info check_system_info
check_brutal check_brutal