Files
s-hy2/scripts/firewall-manager.sh
T
sindricn 5e57b7f357 修复
2025-10-01 17:35:36 +08:00

1215 lines
37 KiB
Bash
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.
#!/bin/bash
# Hysteria2 防火墙管理模块
# 自动检测并管理 Linux 系统防火墙
# 适度的错误处理
set -uo pipefail
# 加载公共库
# SCRIPT_DIR 由主脚本定义,此处已移除以避免覆盖
if [[ -f "$(dirname "${BASH_SOURCE[0]}")/common.sh" ]]; then
source "$(dirname "${BASH_SOURCE[0]}")/common.sh"
else
echo "错误: 无法加载公共库" >&2
exit 1
fi
# 防火墙类型常量 (防止重复定义)
if [[ -z "${FW_UNKNOWN:-}" ]]; then
readonly FW_UNKNOWN=0
readonly FW_IPTABLES=1
readonly FW_FIREWALLD=2
readonly FW_UFW=3
readonly FW_NFTABLES=4
fi
# 全局变量
DETECTED_FIREWALL=$FW_UNKNOWN
FIREWALL_NAME=""
HYSTERIA_PORT=""
# 检测系统防火墙类型(性能优化版本)
detect_firewall() {
log_info "检测系统防火墙类型"
# 使用缓存避免重复检测
local cache_key="firewall_detection"
if [[ -n "${FIREWALL_DETECTION_CACHE:-}" ]]; then
DETECTED_FIREWALL="$FIREWALL_DETECTION_CACHE"
FIREWALL_NAME="$FIREWALL_NAME_CACHE"
log_info "使用缓存的防火墙检测结果: $FIREWALL_NAME"
return 0
fi
# 检测优先级:firewalld > ufw > iptables > nftables
# 批量检查命令存在性
local commands_exist=""
for cmd in systemctl ufw iptables nft; do
if command -v "$cmd" >/dev/null 2>&1; then
commands_exist="$commands_exist $cmd"
fi
done
# 检测 firewalld(优化:一次性检查状态和配置)
if [[ "$commands_exist" == *"systemctl"* ]]; then
local firewalld_status
firewalld_status=$(systemctl is-active firewalld 2>/dev/null || echo "inactive")
if [[ "$firewalld_status" == "active" ]]; then
DETECTED_FIREWALL=$FW_FIREWALLD
FIREWALL_NAME="firewalld"
log_success "检测到防火墙: firewalld (运行中)"
# 缓存结果
FIREWALL_DETECTION_CACHE=$FW_FIREWALLD
FIREWALL_NAME_CACHE="firewalld"
return 0
elif systemctl is-enabled --quiet firewalld 2>/dev/null; then
DETECTED_FIREWALL=$FW_FIREWALLD
FIREWALL_NAME="firewalld"
log_warn "检测到防火墙: firewalld (已安装但未运行)"
# 缓存结果
FIREWALL_DETECTION_CACHE=$FW_FIREWALLD
FIREWALL_NAME_CACHE="firewalld"
return 0
fi
fi
# 检测 ufw(优化:减少命令调用)
if [[ "$commands_exist" == *"ufw"* ]]; then
local ufw_status
ufw_status=$(ufw status 2>/dev/null | head -1 || echo "Status: inactive")
if [[ "$ufw_status" =~ "Status: active" ]]; then
DETECTED_FIREWALL=$FW_UFW
FIREWALL_NAME="ufw"
log_success "检测到防火墙: ufw (激活状态)"
else
DETECTED_FIREWALL=$FW_UFW
FIREWALL_NAME="ufw"
log_warn "检测到防火墙: ufw (已安装但未激活)"
fi
# 缓存结果
FIREWALL_DETECTION_CACHE=$FW_UFW
FIREWALL_NAME_CACHE="ufw"
return 0
fi
# 检测 iptables(优化:快速规则计数)
if [[ "$commands_exist" == *"iptables"* ]]; then
# 优化:使用更快的规则计数方法
local rule_count
rule_count=$(iptables -L -n --line-numbers 2>/dev/null | grep -c "^[0-9]" || echo "0")
if [[ $rule_count -gt 3 ]]; then # 调整阈值,更准确
DETECTED_FIREWALL=$FW_IPTABLES
FIREWALL_NAME="iptables"
log_success "检测到防火墙: iptables (有自定义规则: $rule_count 条)"
else
DETECTED_FIREWALL=$FW_IPTABLES
FIREWALL_NAME="iptables"
log_warn "检测到防火墙: iptables (默认配置)"
return 0
fi
fi
# 检测 nftables
if command -v nft >/dev/null 2>&1; then
local nft_rules
nft_rules=$(nft list tables 2>/dev/null | wc -l)
if [[ $nft_rules -gt 0 ]]; then
DETECTED_FIREWALL=$FW_NFTABLES
FIREWALL_NAME="nftables"
log_success "检测到防火墙: nftables (有配置表)"
return 0
else
DETECTED_FIREWALL=$FW_NFTABLES
FIREWALL_NAME="nftables"
log_warn "检测到防火墙: nftables (无配置表)"
return 0
fi
fi
# 未检测到防火墙
DETECTED_FIREWALL=$FW_UNKNOWN
FIREWALL_NAME="unknown"
log_warn "未检测到已知的防火墙系统"
return 1
}
# 获取 Hysteria2 端口
get_hysteria_port() {
if [[ -f "/etc/hysteria/config.yaml" ]]; then
# 从配置文件提取端口
HYSTERIA_PORT=$(grep -E "^\s*listen:" /etc/hysteria/config.yaml | awk -F':' '{print $NF}' | tr -d ' ' | head -1)
# 如果没有找到端口,使用默认值
if [[ -z "$HYSTERIA_PORT" ]]; then
HYSTERIA_PORT="443"
fi
else
HYSTERIA_PORT="443"
fi
log_info "Hysteria2 端口: $HYSTERIA_PORT"
}
# 显示防火墙管理菜单
show_firewall_menu() {
clear
echo -e "${CYAN}=== Hysteria2 防火墙管理 ===${NC}"
echo ""
echo -e "${BLUE}当前防火墙: ${GREEN}$FIREWALL_NAME${NC}"
echo -e "${BLUE}Hysteria2 端口: ${GREEN}$HYSTERIA_PORT${NC}"
echo ""
echo -e "${GREEN}1.${NC} 查看防火墙状态"
echo -e "${GREEN}2.${NC} 一键管理 Hysteria2 端口"
echo -e "${GREEN}3.${NC} 手动开放端口"
echo -e "${GREEN}4.${NC} 防火墙规则管理"
echo -e "${GREEN}5.${NC} 防火墙服务管理"
echo -e "${RED}0.${NC} 返回主菜单"
echo ""
}
# 查看防火墙状态
show_firewall_status() {
log_info "查看防火墙状态"
case $DETECTED_FIREWALL in
$FW_FIREWALLD)
show_firewalld_status
;;
$FW_UFW)
show_ufw_status
;;
$FW_IPTABLES)
show_iptables_status
;;
$FW_NFTABLES)
show_nftables_status
;;
*)
log_error "未知的防火墙类型"
;;
esac
echo ""
wait_for_user
}
# firewalld 状态
show_firewalld_status() {
echo -e "${BLUE}=== firewalld 状态 ===${NC}"
echo ""
# 服务状态
echo -e "${GREEN}服务状态:${NC}"
systemctl status firewalld --no-pager -l || true
echo ""
# 活动区域
echo -e "${GREEN}活动区域:${NC}"
firewall-cmd --get-active-zones 2>/dev/null || echo "无活动区域"
echo ""
# 默认区域
echo -e "${GREEN}默认区域:${NC}"
firewall-cmd --get-default-zone 2>/dev/null || echo "未设置"
echo ""
# 开放的端口
echo -e "${GREEN}开放的端口:${NC}"
firewall-cmd --list-ports 2>/dev/null || echo "无开放端口"
echo ""
# 检查 Hysteria2 端口
if firewall-cmd --query-port="$HYSTERIA_PORT/tcp" 2>/dev/null; then
echo -e "${GREEN}✅ Hysteria2 端口 $HYSTERIA_PORT/tcp 已开放${NC}"
else
echo -e "${RED}❌ Hysteria2 端口 $HYSTERIA_PORT/tcp 未开放${NC}"
fi
if firewall-cmd --query-port="$HYSTERIA_PORT/udp" 2>/dev/null; then
echo -e "${GREEN}✅ Hysteria2 端口 $HYSTERIA_PORT/udp 已开放${NC}"
else
echo -e "${RED}❌ Hysteria2 端口 $HYSTERIA_PORT/udp 未开放${NC}"
fi
}
# ufw 状态
show_ufw_status() {
echo -e "${BLUE}=== ufw 状态 ===${NC}"
echo ""
# 详细状态
echo -e "${GREEN}详细状态:${NC}"
ufw status verbose 2>/dev/null || echo "ufw 未激活或出错"
echo ""
# 检查 Hysteria2 端口
local ufw_rules
ufw_rules=$(ufw status numbered 2>/dev/null | grep "$HYSTERIA_PORT" || echo "")
if [[ -n "$ufw_rules" ]]; then
echo -e "${GREEN}✅ 找到 Hysteria2 端口相关规则:${NC}"
echo "$ufw_rules"
else
echo -e "${RED}❌ 未找到 Hysteria2 端口 $HYSTERIA_PORT 的规则${NC}"
fi
}
# iptables 状态
show_iptables_status() {
echo -e "${BLUE}=== iptables 状态 ===${NC}"
echo ""
# INPUT 链规则
echo -e "${GREEN}INPUT 链规则:${NC}"
iptables -L INPUT -n --line-numbers 2>/dev/null || echo "无法获取 INPUT 规则"
echo ""
# 检查 Hysteria2 端口
local tcp_rule udp_rule
tcp_rule=$(iptables -L INPUT -n | grep "dpt:$HYSTERIA_PORT" | grep tcp || echo "")
udp_rule=$(iptables -L INPUT -n | grep "dpt:$HYSTERIA_PORT" | grep udp || echo "")
if [[ -n "$tcp_rule" ]]; then
echo -e "${GREEN}✅ 找到 TCP 端口 $HYSTERIA_PORT 规则:${NC}"
echo "$tcp_rule"
else
echo -e "${RED}❌ 未找到 TCP 端口 $HYSTERIA_PORT 规则${NC}"
fi
if [[ -n "$udp_rule" ]]; then
echo -e "${GREEN}✅ 找到 UDP 端口 $HYSTERIA_PORT 规则:${NC}"
echo "$udp_rule"
else
echo -e "${RED}❌ 未找到 UDP 端口 $HYSTERIA_PORT 规则${NC}"
fi
}
# nftables 状态
show_nftables_status() {
echo -e "${BLUE}=== nftables 状态 ===${NC}"
echo ""
# 列出所有表
echo -e "${GREEN}nftables 表:${NC}"
nft list tables 2>/dev/null || echo "无 nftables 表"
echo ""
# 列出规则集
echo -e "${GREEN}规则集:${NC}"
nft list ruleset 2>/dev/null | head -20 || echo "无法获取规则集"
# 简单检查端口
local port_rules
port_rules=$(nft list ruleset 2>/dev/null | grep "$HYSTERIA_PORT" || echo "")
if [[ -n "$port_rules" ]]; then
echo -e "${GREEN}✅ 找到端口 $HYSTERIA_PORT 相关规则${NC}"
else
echo -e "${RED}❌ 未找到端口 $HYSTERIA_PORT 相关规则${NC}"
fi
}
# 手动开放端口(交互式)
open_custom_port() {
log_info "手动开放端口"
echo -e "${BLUE}=== 手动开放端口 ===${NC}"
echo ""
# 获取要开放的端口
local custom_port
while true; do
read -p "请输入要开放的端口号 (1-65535): " custom_port
# 验证端口号
if [[ ! "$custom_port" =~ ^[0-9]+$ ]]; then
echo -e "${RED}错误: 请输入有效的数字${NC}"
continue
fi
if [[ "$custom_port" -lt 1 || "$custom_port" -gt 65535 ]]; then
echo -e "${RED}错误: 端口号必须在 1-65535 范围内${NC}"
continue
fi
break
done
# 选择协议
echo ""
echo "选择协议类型:"
echo "1. TCP"
echo "2. UDP"
echo "3. TCP + UDP"
echo ""
local protocol_choice
local protocols=()
read -p "请选择 [1-3]: " protocol_choice
case $protocol_choice in
1) protocols=("tcp") ;;
2) protocols=("udp") ;;
3) protocols=("tcp" "udp") ;;
*)
log_error "无效选择"
return 1
;;
esac
# 确认开放
echo ""
echo -e "${YELLOW}即将开放端口:${NC}"
echo "端口: $custom_port"
echo "协议: ${protocols[*]}"
echo ""
read -p "确认开放此端口? [y/N]: " confirm
if [[ ! $confirm =~ ^[Yy]$ ]]; then
echo -e "${BLUE}操作已取消${NC}"
return 0
fi
# 执行开放操作
echo -e "${GREEN}正在开放端口 $custom_port...${NC}"
local success=true
for protocol in "${protocols[@]}"; do
case $DETECTED_FIREWALL in
$FW_FIREWALLD)
if ! firewall-cmd --permanent --add-port="$custom_port/$protocol" >/dev/null 2>&1; then
success=false
break
fi
;;
$FW_UFW)
if ! ufw allow "$custom_port/$protocol" >/dev/null 2>&1; then
success=false
break
fi
;;
$FW_IPTABLES)
if ! iptables -I INPUT -p "$protocol" --dport "$custom_port" -j ACCEPT >/dev/null 2>&1; then
success=false
break
fi
;;
$FW_NFTABLES)
if ! nft add rule inet filter input "$protocol" dport "$custom_port" accept >/dev/null 2>&1; then
success=false
break
fi
;;
*)
log_error "不支持的防火墙类型"
return 1
;;
esac
done
if [ "$success" = true ]; then
# 重载配置
case $DETECTED_FIREWALL in
$FW_FIREWALLD)
firewall-cmd --reload >/dev/null 2>&1
;;
$FW_IPTABLES)
save_iptables_rules
;;
esac
log_success "端口 $custom_port (${protocols[*]}) 已成功开放"
else
log_error "端口开放失败"
return 1
fi
echo ""
wait_for_user
}
# 开放 Hysteria2 端口(自动)
open_hysteria_port() {
log_info "开放 Hysteria2 端口: $HYSTERIA_PORT"
case $DETECTED_FIREWALL in
$FW_FIREWALLD)
open_port_firewalld
;;
$FW_UFW)
open_port_ufw
;;
$FW_IPTABLES)
open_port_iptables
;;
$FW_NFTABLES)
open_port_nftables
;;
*)
log_error "不支持的防火墙类型"
return 1
;;
esac
}
# firewalld 开放端口
open_port_firewalld() {
echo -e "${BLUE}=== 使用 firewalld 开放端口 ===${NC}"
echo ""
# 检查服务状态
if ! systemctl is-active --quiet firewalld; then
echo "firewalld 未运行,是否启动? [y/N]"
read -r start_firewalld
if [[ $start_firewalld =~ ^[Yy]$ ]]; then
systemctl start firewalld
log_success "firewalld 已启动"
else
log_error "需要启动 firewalld 才能配置规则"
return 1
fi
fi
# 开放 TCP 端口
if firewall-cmd --add-port="$HYSTERIA_PORT/tcp" --permanent; then
log_success "TCP 端口 $HYSTERIA_PORT 已添加到永久规则"
else
log_error "添加 TCP 端口规则失败"
fi
# 开放 UDP 端口
if firewall-cmd --add-port="$HYSTERIA_PORT/udp" --permanent; then
log_success "UDP 端口 $HYSTERIA_PORT 已添加到永久规则"
else
log_error "添加 UDP 端口规则失败"
fi
# 重新加载规则
if firewall-cmd --reload; then
log_success "防火墙规则已重新加载"
else
log_error "重新加载防火墙规则失败"
fi
# 验证端口
verify_port_opened
}
# ufw 开放端口
open_port_ufw() {
echo -e "${BLUE}=== 使用 ufw 开放端口 ===${NC}"
echo ""
# 检查 ufw 状态
local ufw_status
ufw_status=$(ufw status | head -1)
if [[ "$ufw_status" =~ "inactive" ]]; then
echo "ufw 未激活,是否激活? [y/N]"
read -r enable_ufw
if [[ $enable_ufw =~ ^[Yy]$ ]]; then
ufw --force enable
log_success "ufw 已激活"
else
log_warn "ufw 未激活,将直接添加规则"
fi
fi
# 添加端口规则
if ufw allow "$HYSTERIA_PORT/tcp"; then
log_success "TCP 端口 $HYSTERIA_PORT 规则已添加"
else
log_error "添加 TCP 端口规则失败"
fi
if ufw allow "$HYSTERIA_PORT/udp"; then
log_success "UDP 端口 $HYSTERIA_PORT 规则已添加"
else
log_error "添加 UDP 端口规则失败"
fi
# 验证端口
verify_port_opened
}
# iptables 开放端口
open_port_iptables() {
echo -e "${BLUE}=== 使用 iptables 开放端口 ===${NC}"
echo ""
# 添加 TCP 规则
if iptables -I INPUT -p tcp --dport "$HYSTERIA_PORT" -j ACCEPT; then
log_success "TCP 端口 $HYSTERIA_PORT 规则已添加"
else
log_error "添加 TCP 端口规则失败"
fi
# 添加 UDP 规则
if iptables -I INPUT -p udp --dport "$HYSTERIA_PORT" -j ACCEPT; then
log_success "UDP 端口 $HYSTERIA_PORT 规则已添加"
else
log_error "添加 UDP 端口规则失败"
fi
# 保存规则
echo "是否保存 iptables 规则? [y/N]"
read -r save_rules
if [[ $save_rules =~ ^[Yy]$ ]]; then
save_iptables_rules
else
log_warn "规则未保存,重启后将丢失"
fi
# 验证端口
verify_port_opened
}
# 保存 iptables 规则
save_iptables_rules() {
# 不同发行版的保存方法
if command -v iptables-save >/dev/null && command -v netfilter-persistent >/dev/null; then
# Debian/Ubuntu with netfilter-persistent
netfilter-persistent save
log_success "规则已通过 netfilter-persistent 保存"
elif command -v iptables-save >/dev/null && [[ -f /etc/sysconfig/iptables ]]; then
# CentOS/RHEL
iptables-save > /etc/sysconfig/iptables
log_success "规则已保存到 /etc/sysconfig/iptables"
elif command -v iptables-save >/dev/null; then
# 通用方法
iptables-save > /etc/iptables/rules.v4 2>/dev/null || \
iptables-save > /etc/iptables.rules 2>/dev/null || \
log_warn "无法确定 iptables 规则保存位置"
else
log_error "无法保存 iptables 规则"
fi
}
# nftables 开放端口
open_port_nftables() {
echo -e "${BLUE}=== 使用 nftables 开放端口 ===${NC}"
echo ""
log_warn "nftables 配置较为复杂,建议手动配置"
echo "nftables 基本规则示例:"
echo "nft add rule inet filter input tcp dport $HYSTERIA_PORT accept"
echo "nft add rule inet filter input udp dport $HYSTERIA_PORT accept"
echo ""
echo "是否自动添加基本规则? [y/N]"
read -r auto_add
if [[ $auto_add =~ ^[Yy]$ ]]; then
# 创建基本表和链(如果不存在)
nft add table inet filter 2>/dev/null || true
nft add chain inet filter input { type filter hook input priority 0 \; } 2>/dev/null || true
# 添加规则
if nft add rule inet filter input tcp dport "$HYSTERIA_PORT" accept; then
log_success "TCP 端口 $HYSTERIA_PORT 规则已添加"
fi
if nft add rule inet filter input udp dport "$HYSTERIA_PORT" accept; then
log_success "UDP 端口 $HYSTERIA_PORT 规则已添加"
fi
fi
wait_for_user
}
# 验证端口是否开放
verify_port_opened() {
echo ""
log_info "验证端口开放状态"
# 检查端口监听状态
if ss -tulpn | grep ":$HYSTERIA_PORT " >/dev/null; then
log_success "端口 $HYSTERIA_PORT 正在监听"
else
log_warn "端口 $HYSTERIA_PORT 未在监听(Hysteria2 可能未运行)"
fi
# 防火墙规则验证
case $DETECTED_FIREWALL in
$FW_FIREWALLD)
if firewall-cmd --query-port="$HYSTERIA_PORT/tcp" >/dev/null 2>&1 && \
firewall-cmd --query-port="$HYSTERIA_PORT/udp" >/dev/null 2>&1; then
log_success "防火墙规则验证通过"
else
log_error "防火墙规则验证失败"
fi
;;
$FW_UFW)
if ufw status | grep "$HYSTERIA_PORT" >/dev/null; then
log_success "防火墙规则验证通过"
else
log_error "防火墙规则验证失败"
fi
;;
*)
log_info "请手动验证防火墙规则"
;;
esac
}
# 管理防火墙规则
manage_firewall_rules() {
echo -e "${BLUE}=== 防火墙规则管理 ===${NC}"
echo ""
echo "1. 查看当前规则"
echo "2. 删除 Hysteria2 相关规则"
echo "3. 重新添加 Hysteria2 规则"
echo "4. 启用防火墙规则"
echo "5. 停用防火墙规则"
echo ""
local choice
read -p "请选择操作 [1-5]: " choice
case $choice in
1) show_firewall_status ;;
2) remove_hysteria_rules ;;
3) open_hysteria_port ;;
4) enable_firewall_rules ;;
5) disable_firewall_rules ;;
*)
log_error "无效选择"
wait_for_user
;;
esac
}
# 删除 Hysteria2 相关规则
remove_hysteria_rules() {
echo -e "${YELLOW}警告: 将删除端口 $HYSTERIA_PORT 的防火墙规则${NC}"
echo "确认删除? [y/N]"
read -r confirm_remove
if [[ ! $confirm_remove =~ ^[Yy]$ ]]; then
log_info "取消删除操作"
return 0
fi
case $DETECTED_FIREWALL in
$FW_FIREWALLD)
firewall-cmd --remove-port="$HYSTERIA_PORT/tcp" --permanent 2>/dev/null || true
firewall-cmd --remove-port="$HYSTERIA_PORT/udp" --permanent 2>/dev/null || true
firewall-cmd --reload
log_success "firewalld 规则已删除"
;;
$FW_UFW)
ufw delete allow "$HYSTERIA_PORT/tcp" 2>/dev/null || true
ufw delete allow "$HYSTERIA_PORT/udp" 2>/dev/null || true
log_success "ufw 规则已删除"
;;
$FW_IPTABLES)
iptables -D INPUT -p tcp --dport "$HYSTERIA_PORT" -j ACCEPT 2>/dev/null || true
iptables -D INPUT -p udp --dport "$HYSTERIA_PORT" -j ACCEPT 2>/dev/null || true
log_success "iptables 规则已删除"
;;
*)
log_error "不支持的防火墙类型"
;;
esac
wait_for_user
}
# 启用防火墙规则
enable_firewall_rules() {
log_info "启用防火墙规则"
echo -e "${BLUE}=== 启用防火墙规则 ===${NC}"
echo ""
case $DETECTED_FIREWALL in
$FW_FIREWALLD)
if systemctl is-active firewalld >/dev/null 2>&1; then
echo -e "${GREEN}✅ firewalld 服务已启用并运行${NC}"
echo "当前活动规则:"
firewall-cmd --list-all
else
echo -e "${YELLOW}⚠️ firewalld 服务未运行${NC}"
read -p "是否启动 firewalld 服务? [y/N]: " start_fw
if [[ $start_fw =~ ^[Yy]$ ]]; then
systemctl start firewalld
systemctl enable firewalld
log_success "firewalld 服务已启动并设为开机自启"
else
echo -e "${BLUE}firewalld 服务保持停止状态${NC}"
fi
fi
;;
$FW_UFW)
if ufw status | grep -q "Status: active"; then
echo -e "${GREEN}✅ ufw 防火墙已启用${NC}"
ufw status verbose
else
echo -e "${YELLOW}⚠️ ufw 防火墙未启用${NC}"
read -p "是否启用 ufw 防火墙? [y/N]: " enable_ufw
if [[ $enable_ufw =~ ^[Yy]$ ]]; then
ufw --force enable
log_success "ufw 防火墙已启用"
else
echo -e "${BLUE}ufw 防火墙保持停用状态${NC}"
fi
fi
;;
$FW_IPTABLES)
echo -e "${GREEN}✅ iptables 规则始终有效${NC}"
echo "当前规则:"
iptables -L INPUT -n --line-numbers | head -20
;;
$FW_NFTABLES)
if systemctl is-active nftables >/dev/null 2>&1; then
echo -e "${GREEN}✅ nftables 服务已启用并运行${NC}"
echo "当前规则:"
nft list table inet filter 2>/dev/null | head -20
else
echo -e "${YELLOW}⚠️ nftables 服务未运行${NC}"
read -p "是否启动 nftables 服务? [y/N]: " start_nft
if [[ $start_nft =~ ^[Yy]$ ]]; then
systemctl start nftables
systemctl enable nftables
log_success "nftables 服务已启动并设为开机自启"
else
echo -e "${BLUE}nftables 服务保持停止状态${NC}"
fi
fi
;;
*)
log_error "不支持的防火墙类型"
;;
esac
echo ""
wait_for_user
}
# 停用防火墙规则
disable_firewall_rules() {
log_info "停用防火墙规则"
echo -e "${BLUE}=== 停用防火墙规则 ===${NC}"
echo ""
echo -e "${RED}⚠️ 警告: 停用防火墙规则将降低系统安全性${NC}"
echo ""
read -p "确认要停用防火墙规则吗? [y/N]: " confirm
if [[ ! $confirm =~ ^[Yy]$ ]]; then
echo -e "${BLUE}操作已取消${NC}"
wait_for_user
return 0
fi
case $DETECTED_FIREWALL in
$FW_FIREWALLD)
if systemctl is-active firewalld >/dev/null 2>&1; then
systemctl stop firewalld
systemctl disable firewalld
log_success "firewalld 服务已停止并禁用开机自启"
else
echo -e "${BLUE}firewalld 服务已处于停止状态${NC}"
fi
;;
$FW_UFW)
if ufw status | grep -q "Status: active"; then
ufw --force disable
log_success "ufw 防火墙已停用"
else
echo -e "${BLUE}ufw 防火墙已处于停用状态${NC}"
fi
;;
$FW_IPTABLES)
echo -e "${YELLOW}⚠️ iptables 规则管理${NC}"
echo "选择操作:"
echo "1. 清空所有规则(允许所有流量)"
echo "2. 设置默认拒绝策略但保留现有规则"
echo "3. 取消操作"
echo ""
read -p "请选择 [1-3]: " iptables_choice
case $iptables_choice in
1)
iptables -F INPUT
iptables -P INPUT ACCEPT
save_iptables_rules
log_success "已清空 iptables INPUT 规则并设为允许所有"
;;
2)
iptables -P INPUT DROP
save_iptables_rules
log_success "已设置 iptables 默认拒绝策略"
;;
3)
echo -e "${BLUE}操作已取消${NC}"
;;
esac
;;
$FW_NFTABLES)
if systemctl is-active nftables >/dev/null 2>&1; then
systemctl stop nftables
systemctl disable nftables
log_success "nftables 服务已停止并禁用开机自启"
else
echo -e "${BLUE}nftables 服务已处于停止状态${NC}"
fi
;;
*)
log_error "不支持的防火墙类型"
;;
esac
echo ""
wait_for_user
}
# 防火墙服务管理
manage_firewall_service() {
echo -e "${BLUE}=== 防火墙服务管理 ===${NC}"
echo ""
echo "1. 启动防火墙服务"
echo "2. 停止防火墙服务"
echo "3. 重启防火墙服务"
echo "4. 查看服务状态"
echo "5. 启用开机自启"
echo "6. 禁用开机自启"
echo ""
local choice
read -p "请选择操作 [1-6]: " choice
local service_name
case $DETECTED_FIREWALL in
$FW_FIREWALLD) service_name="firewalld" ;;
$FW_UFW) service_name="ufw" ;;
*)
log_error "当前防火墙不支持 systemctl 管理"
wait_for_user
return 1
;;
esac
case $choice in
1)
systemctl start "$service_name"
log_success "$service_name 服务已启动"
;;
2)
systemctl stop "$service_name"
log_success "$service_name 服务已停止"
;;
3)
systemctl restart "$service_name"
log_success "$service_name 服务已重启"
;;
4)
systemctl status "$service_name" --no-pager -l
;;
5)
systemctl enable "$service_name"
log_success "$service_name 开机自启已启用"
;;
6)
systemctl disable "$service_name"
log_success "$service_name 开机自启已禁用"
;;
*)
log_error "无效选择"
;;
esac
wait_for_user
}
# 智能管理 Hysteria2 端口
smart_manage_hysteria_port() {
log_info "智能管理 Hysteria2 端口"
echo -e "${CYAN}=== 一键管理 Hysteria2 端口 ===${NC}"
echo ""
# 首先检查防火墙服务状态
local firewall_enabled=false
local firewall_running=false
case $DETECTED_FIREWALL in
$FW_FIREWALLD)
if systemctl is-enabled firewalld >/dev/null 2>&1; then
firewall_enabled=true
fi
if systemctl is-active firewalld >/dev/null 2>&1; then
firewall_running=true
fi
;;
$FW_UFW)
if ufw status | grep -q "Status: active"; then
firewall_enabled=true
firewall_running=true
fi
;;
$FW_IPTABLES)
# iptables 总是"运行"的,检查是否有规则
if iptables -L INPUT | grep -q "DROP\|REJECT"; then
firewall_enabled=true
firewall_running=true
fi
;;
$FW_NFTABLES)
if systemctl is-active nftables >/dev/null 2>&1; then
firewall_enabled=true
firewall_running=true
fi
;;
esac
echo -e "${BLUE}防火墙状态检测:${NC}"
echo "防火墙类型: $FIREWALL_NAME"
echo "防火墙服务: $([ "$firewall_running" = true ] && echo "${GREEN}运行中${NC}" || echo "${RED}未运行${NC}")"
echo "Hysteria2 端口: $HYSTERIA_PORT"
echo ""
# 如果防火墙未启用
if [ "$firewall_enabled" = false ] || [ "$firewall_running" = false ]; then
echo -e "${YELLOW}⚠️ 防火墙未启用或未运行${NC}"
echo -e "${BLUE}当前状态:${NC}端口 $HYSTERIA_PORT 可能已可访问(无防火墙限制)"
echo ""
echo -e "${GREEN}安全建议:${NC}"
echo "虽然不影响 Hysteria2 连接,但为了安全考虑,建议启用防火墙并开放特定端口"
echo ""
read -p "是否启用防火墙并配置规则? [y/N]: " enable_fw
if [[ $enable_fw =~ ^[Yy]$ ]]; then
echo -e "${GREEN}正在启用防火墙并配置规则...${NC}"
# 启用防火墙服务
case $DETECTED_FIREWALL in
$FW_FIREWALLD)
systemctl enable --now firewalld
;;
$FW_UFW)
ufw --force enable
;;
$FW_IPTABLES)
echo "iptables 无需启用服务,直接配置规则"
;;
$FW_NFTABLES)
systemctl enable --now nftables
;;
esac
# 开放端口
open_hysteria_port
else
echo -e "${BLUE}保持当前状态,跳过防火墙配置${NC}"
fi
else
# 防火墙已启用,检查端口状态
echo -e "${GREEN}✅ 防火墙已启用${NC}"
echo ""
local port_opened=false
local port_status=""
# 检查端口是否已开放
case $DETECTED_FIREWALL in
$FW_FIREWALLD)
if firewall-cmd --query-port="$HYSTERIA_PORT/tcp" >/dev/null 2>&1 && \
firewall-cmd --query-port="$HYSTERIA_PORT/udp" >/dev/null 2>&1; then
port_opened=true
port_status="TCP/UDP 端口已开放"
else
port_status="端口未开放或部分开放"
fi
;;
$FW_UFW)
if ufw status | grep "$HYSTERIA_PORT" >/dev/null; then
port_opened=true
port_status="端口规则已存在"
else
port_status="端口未开放"
fi
;;
$FW_IPTABLES)
if iptables -L INPUT | grep "$HYSTERIA_PORT" >/dev/null; then
port_opened=true
port_status="端口规则已存在"
else
port_status="端口未开放"
fi
;;
$FW_NFTABLES)
if nft list table inet filter 2>/dev/null | grep "$HYSTERIA_PORT" >/dev/null; then
port_opened=true
port_status="端口规则已存在"
else
port_status="端口未开放"
fi
;;
esac
echo -e "${BLUE}端口状态检测:${NC}$port_status"
echo ""
if [ "$port_opened" = true ]; then
echo -e "${GREEN}✅ 端口 $HYSTERIA_PORT 已正确配置${NC}"
echo -e "${BLUE}Hysteria2 连接应该正常工作${NC}"
else
echo -e "${RED}❌ 端口 $HYSTERIA_PORT 未开放${NC}"
echo -e "${YELLOW}⚠️ 这将影响 Hysteria2 客户端连接${NC}"
echo ""
read -p "是否立即开放端口 $HYSTERIA_PORT [Y/n]: " open_port
if [[ ! $open_port =~ ^[Nn]$ ]]; then
echo -e "${GREEN}正在开放端口 $HYSTERIA_PORT...${NC}"
open_hysteria_port
else
echo -e "${RED}⚠️ 端口未开放,Hysteria2 客户端可能无法连接${NC}"
fi
fi
fi
echo ""
wait_for_user
}
# 部署后验证检查
post_deploy_check() {
log_info "执行部署后验证检查"
echo -e "${CYAN}=== Hysteria2 部署后检查 ===${NC}"
echo ""
local check_passed=0
local total_checks=5
# 检查 1: 服务状态
echo -e "${BLUE}检查 1/5: Hysteria2 服务状态${NC}"
if systemctl is-active --quiet hysteria-server; then
echo "✅ Hysteria2 服务运行正常"
((check_passed++))
else
echo "❌ Hysteria2 服务未运行"
fi
echo ""
# 检查 2: 端口监听
echo -e "${BLUE}检查 2/5: 端口监听状态${NC}"
if ss -tulpn | grep ":$HYSTERIA_PORT " >/dev/null; then
echo "✅ 端口 $HYSTERIA_PORT 正在监听"
((check_passed++))
else
echo "❌ 端口 $HYSTERIA_PORT 未在监听"
fi
echo ""
# 检查 3: 防火墙规则
echo -e "${BLUE}检查 3/5: 防火墙规则${NC}"
case $DETECTED_FIREWALL in
$FW_FIREWALLD)
if firewall-cmd --query-port="$HYSTERIA_PORT/tcp" >/dev/null 2>&1 && \
firewall-cmd --query-port="$HYSTERIA_PORT/udp" >/dev/null 2>&1; then
echo "✅ 防火墙规则配置正确"
((check_passed++))
else
echo "❌ 防火墙规则配置错误"
fi
;;
$FW_UFW)
if ufw status | grep "$HYSTERIA_PORT" >/dev/null; then
echo "✅ 防火墙规则配置正确"
((check_passed++))
else
echo "❌ 防火墙规则配置错误"
fi
;;
*)
echo "⚠️ 无法自动检查防火墙规则"
((check_passed++)) # 给予通过
;;
esac
echo ""
# 检查 4: 配置文件
echo -e "${BLUE}检查 4/5: 配置文件${NC}"
if [[ -f "/etc/hysteria/config.yaml" ]]; then
echo "✅ 配置文件存在"
((check_passed++))
else
echo "❌ 配置文件不存在"
fi
echo ""
# 检查 5: 证书文件
echo -e "${BLUE}检查 5/5: 证书文件${NC}"
if [[ -f "/etc/hysteria/cert.crt" ]] || grep -q "acme:" /etc/hysteria/config.yaml 2>/dev/null; then
echo "✅ 证书配置正常"
((check_passed++))
else
echo "❌ 证书配置可能有问题"
fi
echo ""
# 总结
echo -e "${CYAN}=== 检查结果总结 ===${NC}"
echo "通过检查: $check_passed/$total_checks"
if [[ $check_passed -eq $total_checks ]]; then
echo -e "${GREEN}🎉 所有检查通过!Hysteria2 部署成功${NC}"
elif [[ $check_passed -ge 3 ]]; then
echo -e "${YELLOW}⚠️ 部分检查未通过,但基本功能可用${NC}"
else
echo -e "${RED}❌ 多项检查失败,需要修复问题${NC}"
fi
echo ""
wait_for_user
}
# 主防火墙管理函数
manage_firewall() {
# 初始化
detect_firewall
get_hysteria_port
if [[ $DETECTED_FIREWALL -eq $FW_UNKNOWN ]]; then
log_error "未检测到支持的防火墙系统"
echo "支持的防火墙: firewalld, ufw, iptables, nftables"
wait_for_user
return 1
fi
while true; do
show_firewall_menu
local choice
read -p "请选择操作 [0-5]: " choice
case $choice in
1) show_firewall_status ;;
2) smart_manage_hysteria_port ;;
3) open_custom_port ;;
4) manage_firewall_rules ;;
5) manage_firewall_service ;;
0)
log_info "返回主菜单"
break
;;
*)
log_error "无效选择,请重新输入"
wait_for_user
;;
esac
done
}
# 如果脚本被直接执行
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
manage_firewall
fi