940 lines
28 KiB
Bash
940 lines
28 KiB
Bash
#!/bin/bash
|
|
|
|
# Hysteria2 防火墙管理模块
|
|
# 自动检测并管理 Linux 系统防火墙
|
|
|
|
# 适度的错误处理
|
|
set -uo pipefail
|
|
|
|
# 加载公共库
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
if [[ -f "$SCRIPT_DIR/common.sh" ]]; then
|
|
source "$SCRIPT_DIR/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 "${GREEN}6.${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
|
|
}
|
|
|
|
# 开放 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
|
|
}
|
|
|
|
# 检查端口连通性
|
|
check_port_connectivity() {
|
|
log_info "检查端口连通性"
|
|
|
|
echo -e "${BLUE}=== 端口连通性检查 ===${NC}"
|
|
echo ""
|
|
|
|
# 内部检查:端口监听状态
|
|
echo -e "${GREEN}1. 内部端口监听检查:${NC}"
|
|
if ss -tulpn | grep ":$HYSTERIA_PORT "; then
|
|
log_success "端口 $HYSTERIA_PORT 正在监听"
|
|
else
|
|
log_error "端口 $HYSTERIA_PORT 未在监听"
|
|
echo "可能原因:"
|
|
echo "- Hysteria2 服务未运行"
|
|
echo "- 配置文件中端口设置错误"
|
|
echo "- 服务启动失败"
|
|
echo ""
|
|
fi
|
|
|
|
# 防火墙规则检查
|
|
echo -e "${GREEN}2. 防火墙规则检查:${NC}"
|
|
case $DETECTED_FIREWALL in
|
|
$FW_FIREWALLD)
|
|
if firewall-cmd --query-port="$HYSTERIA_PORT/tcp" >/dev/null 2>&1; then
|
|
echo "✅ TCP 端口规则存在"
|
|
else
|
|
echo "❌ TCP 端口规则不存在"
|
|
fi
|
|
|
|
if firewall-cmd --query-port="$HYSTERIA_PORT/udp" >/dev/null 2>&1; then
|
|
echo "✅ UDP 端口规则存在"
|
|
else
|
|
echo "❌ UDP 端口规则不存在"
|
|
fi
|
|
;;
|
|
$FW_UFW)
|
|
if ufw status | grep "$HYSTERIA_PORT" >/dev/null; then
|
|
echo "✅ 端口规则存在"
|
|
else
|
|
echo "❌ 端口规则不存在"
|
|
fi
|
|
;;
|
|
*)
|
|
echo "⚠️ 请手动检查防火墙规则"
|
|
;;
|
|
esac
|
|
echo ""
|
|
|
|
# 外部连通性测试
|
|
echo -e "${GREEN}3. 外部连通性测试:${NC}"
|
|
echo "将尝试从外部测试端口连通性..."
|
|
|
|
# 获取服务器外部 IP
|
|
local external_ip
|
|
external_ip=$(curl -s --connect-timeout 5 ifconfig.me 2>/dev/null || echo "未知")
|
|
|
|
if [[ "$external_ip" != "未知" ]]; then
|
|
echo "服务器外部 IP: $external_ip"
|
|
echo "您可以使用以下命令从其他机器测试连通性:"
|
|
echo "telnet $external_ip $HYSTERIA_PORT"
|
|
echo "nc -zv $external_ip $HYSTERIA_PORT"
|
|
echo ""
|
|
fi
|
|
|
|
# 云服务商安全组提醒
|
|
echo -e "${YELLOW}注意事项:${NC}"
|
|
echo "- 如果使用云服务器,请检查安全组/防火墙设置"
|
|
echo "- 确保云平台防火墙允许端口 $HYSTERIA_PORT"
|
|
echo "- 某些云服务商默认阻止所有入站连接"
|
|
echo ""
|
|
|
|
wait_for_user
|
|
}
|
|
|
|
# 管理防火墙规则
|
|
manage_firewall_rules() {
|
|
echo -e "${BLUE}=== 防火墙规则管理 ===${NC}"
|
|
echo ""
|
|
echo "1. 查看当前规则"
|
|
echo "2. 删除 Hysteria2 相关规则"
|
|
echo "3. 重新添加 Hysteria2 规则"
|
|
echo "4. 备份当前规则"
|
|
echo ""
|
|
|
|
local choice
|
|
read -p "请选择操作 [1-4]: " choice
|
|
|
|
case $choice in
|
|
1) show_firewall_status ;;
|
|
2) remove_hysteria_rules ;;
|
|
3) open_hysteria_port ;;
|
|
4) backup_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
|
|
}
|
|
|
|
# 备份防火墙规则
|
|
backup_firewall_rules() {
|
|
local backup_dir="/var/backups/s-hy2/firewall"
|
|
local timestamp=$(date +%Y%m%d_%H%M%S)
|
|
|
|
mkdir -p "$backup_dir"
|
|
|
|
case $DETECTED_FIREWALL in
|
|
$FW_FIREWALLD)
|
|
firewall-cmd --list-all > "$backup_dir/firewalld_$timestamp.conf"
|
|
log_success "firewalld 规则已备份到: $backup_dir/firewalld_$timestamp.conf"
|
|
;;
|
|
$FW_UFW)
|
|
ufw status verbose > "$backup_dir/ufw_$timestamp.conf"
|
|
log_success "ufw 规则已备份到: $backup_dir/ufw_$timestamp.conf"
|
|
;;
|
|
$FW_IPTABLES)
|
|
iptables-save > "$backup_dir/iptables_$timestamp.rules"
|
|
log_success "iptables 规则已备份到: $backup_dir/iptables_$timestamp.rules"
|
|
;;
|
|
$FW_NFTABLES)
|
|
nft list ruleset > "$backup_dir/nftables_$timestamp.conf"
|
|
log_success "nftables 规则已备份到: $backup_dir/nftables_$timestamp.conf"
|
|
;;
|
|
*)
|
|
log_error "无法备份未知类型的防火墙"
|
|
;;
|
|
esac
|
|
|
|
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
|
|
}
|
|
|
|
# 端口扫描和诊断
|
|
port_scan_diagnostic() {
|
|
echo -e "${BLUE}=== 端口扫描和诊断 ===${NC}"
|
|
echo ""
|
|
|
|
# 本地端口扫描
|
|
echo -e "${GREEN}1. 本地端口状态:${NC}"
|
|
ss -tulpn | grep -E "(LISTEN|:$HYSTERIA_PORT)" | head -10
|
|
echo ""
|
|
|
|
# 进程检查
|
|
echo -e "${GREEN}2. Hysteria2 进程状态:${NC}"
|
|
if pgrep -f hysteria >/dev/null; then
|
|
ps aux | grep -E "(hysteria|hy2)" | grep -v grep
|
|
log_success "Hysteria2 进程运行中"
|
|
else
|
|
log_warn "未找到 Hysteria2 进程"
|
|
fi
|
|
echo ""
|
|
|
|
# 系统资源检查
|
|
echo -e "${GREEN}3. 系统资源状态:${NC}"
|
|
echo "CPU 使用率:"
|
|
top -bn1 | grep "Cpu(s)" | sed "s/.*, *\([0-9.]*\)%* id.*/\1/" | awk '{print 100 - $1"%"}'
|
|
echo "内存使用率:"
|
|
free -h | awk 'NR==2{printf "%.1f%%\n", $3*100/$2}'
|
|
echo "磁盘使用率:"
|
|
df -h / | awk 'NR==2{print $5}'
|
|
echo ""
|
|
|
|
# 网络连接检查
|
|
echo -e "${GREEN}4. 网络连接状态:${NC}"
|
|
netstat -i | head -5 2>/dev/null || ip link show | head -5
|
|
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-6]: " choice
|
|
|
|
case $choice in
|
|
1) show_firewall_status ;;
|
|
2) open_hysteria_port ;;
|
|
3) check_port_connectivity ;;
|
|
4) manage_firewall_rules ;;
|
|
5) manage_firewall_service ;;
|
|
6) port_scan_diagnostic ;;
|
|
0)
|
|
log_info "返回主菜单"
|
|
break
|
|
;;
|
|
*)
|
|
log_error "无效选择,请重新输入"
|
|
wait_for_user
|
|
;;
|
|
esac
|
|
done
|
|
}
|
|
|
|
# 如果脚本被直接执行
|
|
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
|
|
manage_firewall
|
|
fi |