更新
This commit is contained in:
@@ -0,0 +1,899 @@
|
||||
# 出站规则管理系统 - 代码实现示例
|
||||
|
||||
## 🔧 核心代码示例
|
||||
|
||||
### 1. 数据结构示例
|
||||
|
||||
#### 规则库文件格式 (library.yaml)
|
||||
```yaml
|
||||
metadata:
|
||||
version: "2.0"
|
||||
created: "2025-09-28T10:00:00Z"
|
||||
last_modified: "2025-09-28T10:30:00Z"
|
||||
total_rules: 3
|
||||
|
||||
rules:
|
||||
rule_1727515200_1234:
|
||||
id: "rule_1727515200_1234"
|
||||
name: "china_direct"
|
||||
type: "direct"
|
||||
description: "中国大陆IP直连,绕过代理"
|
||||
tags: ["direct", "china", "geoip"]
|
||||
created: "2025-09-28T10:00:00Z"
|
||||
modified: "2025-09-28T10:00:00Z"
|
||||
config:
|
||||
direct:
|
||||
mode: "auto"
|
||||
bindDevice: "eth0"
|
||||
bindIPv4: "192.168.1.100"
|
||||
|
||||
rule_1727515260_5678:
|
||||
id: "rule_1727515260_5678"
|
||||
name: "global_proxy"
|
||||
type: "socks5"
|
||||
description: "全局SOCKS5代理服务器"
|
||||
tags: ["proxy", "socks5", "global"]
|
||||
created: "2025-09-28T10:01:00Z"
|
||||
modified: "2025-09-28T10:01:00Z"
|
||||
config:
|
||||
socks5:
|
||||
addr: "proxy.example.com:1080"
|
||||
username: "user123"
|
||||
password: "pass123"
|
||||
|
||||
rule_1727515320_9999:
|
||||
id: "rule_1727515320_9999"
|
||||
name: "corp_http"
|
||||
type: "http"
|
||||
description: "企业HTTP代理"
|
||||
tags: ["proxy", "http", "corporate"]
|
||||
created: "2025-09-28T10:02:00Z"
|
||||
modified: "2025-09-28T10:02:00Z"
|
||||
config:
|
||||
http:
|
||||
url: "http://proxy.corp.com:8080"
|
||||
insecure: false
|
||||
```
|
||||
|
||||
#### 应用状态文件格式 (applied.yaml)
|
||||
```yaml
|
||||
metadata:
|
||||
version: "2.0"
|
||||
last_applied: "2025-09-28T10:30:00Z"
|
||||
hysteria_config: "/etc/hysteria/config.yaml"
|
||||
|
||||
applied_rules:
|
||||
- rule_id: "rule_1727515200_1234"
|
||||
rule_name: "china_direct"
|
||||
applied_at: "2025-09-28T10:30:00Z"
|
||||
acl_rules:
|
||||
- "china_direct(geoip:cn)"
|
||||
- "china_direct(geosite:cn)"
|
||||
|
||||
- rule_id: "rule_1727515260_5678"
|
||||
rule_name: "global_proxy"
|
||||
applied_at: "2025-09-28T10:25:00Z"
|
||||
acl_rules:
|
||||
- "global_proxy(all)"
|
||||
|
||||
backup_config:
|
||||
backup_path: "/etc/hysteria/rules/backups/config_20250928_103000.yaml"
|
||||
created_at: "2025-09-28T10:30:00Z"
|
||||
```
|
||||
|
||||
### 2. 核心函数实现
|
||||
|
||||
#### 规则创建函数
|
||||
```bash
|
||||
#!/bin/bash
|
||||
# 创建新规则的完整实现
|
||||
|
||||
rule_create_interactive() {
|
||||
echo -e "${BLUE}=== 创建新的出站规则 ===${NC}"
|
||||
echo ""
|
||||
|
||||
# 1. 获取规则基本信息
|
||||
local rule_name rule_type rule_description
|
||||
|
||||
while true; do
|
||||
read -p "规则名称 (唯一标识): " rule_name
|
||||
if [[ -z "$rule_name" ]]; then
|
||||
echo -e "${RED}规则名称不能为空${NC}"
|
||||
continue
|
||||
fi
|
||||
|
||||
if rule_exists_by_name "$rule_name"; then
|
||||
echo -e "${RED}规则名称已存在,请选择其他名称${NC}"
|
||||
continue
|
||||
fi
|
||||
|
||||
# 验证名称格式
|
||||
if [[ ! "$rule_name" =~ ^[a-zA-Z0-9_-]+$ ]]; then
|
||||
echo -e "${RED}规则名称只能包含字母、数字、下划线和连字符${NC}"
|
||||
continue
|
||||
fi
|
||||
|
||||
break
|
||||
done
|
||||
|
||||
read -p "规则描述: " rule_description
|
||||
[[ -z "$rule_description" ]] && rule_description="用户自定义规则"
|
||||
|
||||
# 2. 选择规则类型
|
||||
echo ""
|
||||
echo "选择规则类型:"
|
||||
echo "1. Direct (直连)"
|
||||
echo "2. SOCKS5 代理"
|
||||
echo "3. HTTP/HTTPS 代理"
|
||||
echo ""
|
||||
|
||||
local type_choice
|
||||
while true; do
|
||||
read -p "请选择 [1-3]: " type_choice
|
||||
case $type_choice in
|
||||
1) rule_type="direct"; break ;;
|
||||
2) rule_type="socks5"; break ;;
|
||||
3) rule_type="http"; break ;;
|
||||
*)
|
||||
echo -e "${RED}无效选择,请重新输入${NC}"
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
# 3. 配置规则参数
|
||||
local config_json
|
||||
case $rule_type in
|
||||
"direct")
|
||||
config_json=$(rule_create_direct_config)
|
||||
;;
|
||||
"socks5")
|
||||
config_json=$(rule_create_socks5_config)
|
||||
;;
|
||||
"http")
|
||||
config_json=$(rule_create_http_config)
|
||||
;;
|
||||
esac
|
||||
|
||||
if [[ -z "$config_json" ]]; then
|
||||
echo -e "${RED}配置创建失败${NC}"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# 4. 显示配置预览
|
||||
echo ""
|
||||
echo -e "${BLUE}=== 配置预览 ===${NC}"
|
||||
echo "规则名称: $rule_name"
|
||||
echo "规则类型: $rule_type"
|
||||
echo "规则描述: $rule_description"
|
||||
echo "配置详情:"
|
||||
echo "$config_json" | jq '.'
|
||||
echo ""
|
||||
|
||||
# 5. 确认创建
|
||||
read -p "确认创建此规则? [y/N]: " confirm
|
||||
if [[ ! $confirm =~ ^[Yy]$ ]]; then
|
||||
echo -e "${YELLOW}已取消创建${NC}"
|
||||
return 0
|
||||
fi
|
||||
|
||||
# 6. 执行创建
|
||||
local rule_id
|
||||
rule_id=$(rule_create "$rule_name" "$rule_type" "$rule_description" "$config_json")
|
||||
|
||||
if [[ $? -eq 0 ]]; then
|
||||
echo -e "${GREEN}规则创建成功!${NC}"
|
||||
echo "规则ID: $rule_id"
|
||||
echo ""
|
||||
|
||||
# 询问是否立即应用
|
||||
read -p "是否立即应用此规则? [y/N]: " apply_now
|
||||
if [[ $apply_now =~ ^[Yy]$ ]]; then
|
||||
rule_state_apply "$rule_id"
|
||||
fi
|
||||
else
|
||||
echo -e "${RED}规则创建失败${NC}"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Direct类型配置创建
|
||||
rule_create_direct_config() {
|
||||
echo ""
|
||||
echo -e "${BLUE}=== Direct 直连配置 ===${NC}"
|
||||
|
||||
local bind_interface bind_ipv4 bind_ipv6
|
||||
|
||||
# 绑定网卡
|
||||
read -p "是否绑定特定网卡? [y/N]: " bind_iface_choice
|
||||
if [[ $bind_iface_choice =~ ^[Yy]$ ]]; then
|
||||
echo "可用网卡:"
|
||||
ip link show | grep '^[0-9]' | awk -F': ' '{print " " $2}' | grep -v lo
|
||||
read -p "网卡名称: " bind_interface
|
||||
fi
|
||||
|
||||
# 绑定IPv4
|
||||
read -p "是否绑定特定IPv4地址? [y/N]: " bind_ipv4_choice
|
||||
if [[ $bind_ipv4_choice =~ ^[Yy]$ ]]; then
|
||||
while true; do
|
||||
read -p "IPv4地址: " bind_ipv4
|
||||
if [[ "$bind_ipv4" =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then
|
||||
break
|
||||
else
|
||||
echo -e "${RED}IPv4地址格式错误${NC}"
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
# 绑定IPv6
|
||||
read -p "是否绑定特定IPv6地址? [y/N]: " bind_ipv6_choice
|
||||
if [[ $bind_ipv6_choice =~ ^[Yy]$ ]]; then
|
||||
read -p "IPv6地址: " bind_ipv6
|
||||
fi
|
||||
|
||||
# 生成JSON配置
|
||||
local config=$(cat <<EOF
|
||||
{
|
||||
"direct": {
|
||||
"mode": "auto"
|
||||
EOF
|
||||
)
|
||||
|
||||
if [[ -n "$bind_interface" ]]; then
|
||||
config+=',
|
||||
"bindDevice": "'$bind_interface'"'
|
||||
fi
|
||||
|
||||
if [[ -n "$bind_ipv4" ]]; then
|
||||
config+=',
|
||||
"bindIPv4": "'$bind_ipv4'"'
|
||||
fi
|
||||
|
||||
if [[ -n "$bind_ipv6" ]]; then
|
||||
config+=',
|
||||
"bindIPv6": "'$bind_ipv6'"'
|
||||
fi
|
||||
|
||||
config+='
|
||||
}
|
||||
}'
|
||||
|
||||
echo "$config"
|
||||
}
|
||||
|
||||
# SOCKS5类型配置创建
|
||||
rule_create_socks5_config() {
|
||||
echo ""
|
||||
echo -e "${BLUE}=== SOCKS5 代理配置 ===${NC}"
|
||||
|
||||
local addr username password
|
||||
|
||||
# 服务器地址
|
||||
while true; do
|
||||
read -p "代理服务器地址:端口 (例: proxy.com:1080): " addr
|
||||
if [[ -n "$addr" ]] && [[ "$addr" =~ : ]]; then
|
||||
break
|
||||
else
|
||||
echo -e "${RED}地址格式错误,需要包含端口${NC}"
|
||||
fi
|
||||
done
|
||||
|
||||
# 认证配置
|
||||
read -p "是否需要用户名密码认证? [y/N]: " need_auth
|
||||
if [[ $need_auth =~ ^[Yy]$ ]]; then
|
||||
read -p "用户名: " username
|
||||
read -s -p "密码: " password
|
||||
echo ""
|
||||
fi
|
||||
|
||||
# 生成JSON配置
|
||||
local config=$(cat <<EOF
|
||||
{
|
||||
"socks5": {
|
||||
"addr": "$addr"
|
||||
EOF
|
||||
)
|
||||
|
||||
if [[ -n "$username" ]]; then
|
||||
config+=',
|
||||
"username": "'$username'",
|
||||
"password": "'$password'"'
|
||||
fi
|
||||
|
||||
config+='
|
||||
}
|
||||
}'
|
||||
|
||||
echo "$config"
|
||||
}
|
||||
|
||||
# HTTP类型配置创建
|
||||
rule_create_http_config() {
|
||||
echo ""
|
||||
echo -e "${BLUE}=== HTTP 代理配置 ===${NC}"
|
||||
|
||||
local url insecure
|
||||
|
||||
# 代理URL
|
||||
echo "代理类型:"
|
||||
echo "1. HTTP 代理"
|
||||
echo "2. HTTPS 代理"
|
||||
|
||||
local proxy_type_choice
|
||||
read -p "选择 [1-2]: " proxy_type_choice
|
||||
|
||||
if [[ $proxy_type_choice == "1" ]]; then
|
||||
read -p "HTTP代理URL (例: http://user:pass@proxy.com:8080): " url
|
||||
else
|
||||
read -p "HTTPS代理URL (例: https://user:pass@proxy.com:8080): " url
|
||||
read -p "是否跳过TLS证书验证? [y/N]: " skip_tls
|
||||
if [[ $skip_tls =~ ^[Yy]$ ]]; then
|
||||
insecure="true"
|
||||
else
|
||||
insecure="false"
|
||||
fi
|
||||
fi
|
||||
|
||||
# 验证URL格式
|
||||
if [[ ! "$url" =~ ^https?:// ]]; then
|
||||
echo -e "${RED}URL格式错误${NC}"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# 生成JSON配置
|
||||
local config=$(cat <<EOF
|
||||
{
|
||||
"http": {
|
||||
"url": "$url"
|
||||
EOF
|
||||
)
|
||||
|
||||
if [[ -n "$insecure" ]]; then
|
||||
config+=',
|
||||
"insecure": '$insecure
|
||||
fi
|
||||
|
||||
config+='
|
||||
}
|
||||
}'
|
||||
|
||||
echo "$config"
|
||||
}
|
||||
```
|
||||
|
||||
#### 规则应用状态管理
|
||||
```bash
|
||||
#!/bin/bash
|
||||
# 规则应用状态的详细管理
|
||||
|
||||
# 批量应用规则
|
||||
rule_state_batch_apply() {
|
||||
local rule_ids=("$@")
|
||||
|
||||
if [[ ${#rule_ids[@]} -eq 0 ]]; then
|
||||
echo -e "${RED}错误:没有指定要应用的规则${NC}"
|
||||
return 1
|
||||
fi
|
||||
|
||||
echo -e "${BLUE}=== 批量应用规则 ===${NC}"
|
||||
echo "将要应用 ${#rule_ids[@]} 个规则:"
|
||||
|
||||
# 显示规则列表
|
||||
for rule_id in "${rule_ids[@]}"; do
|
||||
local rule_data=$(rule_get "$rule_id")
|
||||
local rule_name=$(echo "$rule_data" | yq eval '.name' -)
|
||||
local rule_type=$(echo "$rule_data" | yq eval '.type' -)
|
||||
echo " - $rule_name ($rule_type)"
|
||||
done
|
||||
|
||||
echo ""
|
||||
read -p "确认批量应用这些规则? [y/N]: " confirm
|
||||
if [[ ! $confirm =~ ^[Yy]$ ]]; then
|
||||
echo -e "${YELLOW}已取消批量应用${NC}"
|
||||
return 0
|
||||
fi
|
||||
|
||||
# 创建统一备份
|
||||
rule_state_create_backup "batch_apply_$(date +%Y%m%d_%H%M%S)"
|
||||
|
||||
# 逐个应用规则
|
||||
local success_count=0
|
||||
local failed_rules=()
|
||||
|
||||
for rule_id in "${rule_ids[@]}"; do
|
||||
local rule_name=$(rule_get "$rule_id" | yq eval '.name' -)
|
||||
echo -n "应用规则: $rule_name ... "
|
||||
|
||||
if rule_state_apply_internal "$rule_id"; then
|
||||
echo -e "${GREEN}成功${NC}"
|
||||
((success_count++))
|
||||
else
|
||||
echo -e "${RED}失败${NC}"
|
||||
failed_rules+=("$rule_id")
|
||||
fi
|
||||
done
|
||||
|
||||
# 汇总结果
|
||||
echo ""
|
||||
echo -e "${BLUE}=== 批量应用结果 ===${NC}"
|
||||
echo "成功应用: $success_count 个规则"
|
||||
|
||||
if [[ ${#failed_rules[@]} -gt 0 ]]; then
|
||||
echo "失败规则: ${#failed_rules[@]} 个"
|
||||
for failed_id in "${failed_rules[@]}"; do
|
||||
local failed_name=$(rule_get "$failed_id" | yq eval '.name' -)
|
||||
echo " - $failed_name ($failed_id)"
|
||||
done
|
||||
fi
|
||||
|
||||
# 询问是否重启服务
|
||||
if [[ $success_count -gt 0 ]]; then
|
||||
echo ""
|
||||
read -p "是否重启Hysteria2服务以应用配置? [y/N]: " restart_choice
|
||||
if [[ $restart_choice =~ ^[Yy]$ ]]; then
|
||||
systemctl restart hysteria-server
|
||||
echo -e "${GREEN}服务已重启${NC}"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
# 规则冲突检测
|
||||
rule_state_check_conflicts() {
|
||||
local new_rule_id="$1"
|
||||
|
||||
local new_rule_data=$(rule_get "$new_rule_id")
|
||||
local new_rule_type=$(echo "$new_rule_data" | yq eval '.type' -)
|
||||
local new_rule_name=$(echo "$new_rule_data" | yq eval '.name' -)
|
||||
|
||||
local conflicts=()
|
||||
|
||||
# 检查已应用规则中是否有同类型冲突
|
||||
local applied_rules=$(rule_state_get_applied)
|
||||
|
||||
while IFS= read -r applied_rule; do
|
||||
local applied_id=$(echo "$applied_rule" | yq eval '.rule_id' -)
|
||||
local applied_rule_data=$(rule_get "$applied_id")
|
||||
local applied_type=$(echo "$applied_rule_data" | yq eval '.type' -)
|
||||
local applied_name=$(echo "$applied_rule_data" | yq eval '.name' -)
|
||||
|
||||
# 检查类型冲突(根据业务规则定义)
|
||||
case "$new_rule_type" in
|
||||
"direct")
|
||||
if [[ "$applied_type" == "direct" ]]; then
|
||||
conflicts+=("$applied_name (同类型直连规则)")
|
||||
fi
|
||||
;;
|
||||
"socks5"|"http")
|
||||
if [[ "$applied_type" == "socks5" ]] || [[ "$applied_type" == "http" ]]; then
|
||||
conflicts+=("$applied_name (代理类型冲突)")
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
# 检查名称冲突
|
||||
if [[ "$applied_name" == "$new_rule_name" ]]; then
|
||||
conflicts+=("$applied_name (名称重复)")
|
||||
fi
|
||||
|
||||
done <<< "$applied_rules"
|
||||
|
||||
if [[ ${#conflicts[@]} -gt 0 ]]; then
|
||||
echo -e "${YELLOW}⚠️ 检测到规则冲突:${NC}"
|
||||
for conflict in "${conflicts[@]}"; do
|
||||
echo " - $conflict"
|
||||
done
|
||||
echo ""
|
||||
|
||||
echo "处理方式:"
|
||||
echo "1. 取消应用新规则"
|
||||
echo "2. 自动解决冲突(取消冲突规则的应用)"
|
||||
echo "3. 强制应用(可能导致配置问题)"
|
||||
|
||||
read -p "请选择 [1-3]: " resolve_choice
|
||||
|
||||
case $resolve_choice in
|
||||
1)
|
||||
echo -e "${BLUE}已取消应用${NC}"
|
||||
return 1
|
||||
;;
|
||||
2)
|
||||
echo -e "${BLUE}正在解决冲突...${NC}"
|
||||
# 这里可以实现自动冲突解决逻辑
|
||||
return 0
|
||||
;;
|
||||
3)
|
||||
echo -e "${YELLOW}强制应用,请注意可能的配置冲突${NC}"
|
||||
return 0
|
||||
;;
|
||||
*)
|
||||
echo -e "${RED}无效选择,取消应用${NC}"
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
# 状态同步检查
|
||||
rule_state_sync_check() {
|
||||
echo -e "${BLUE}=== 状态同步检查 ===${NC}"
|
||||
echo ""
|
||||
|
||||
local sync_issues=()
|
||||
|
||||
# 1. 检查应用状态文件中的规则是否真实存在于配置文件
|
||||
echo "检查应用状态一致性..."
|
||||
|
||||
local applied_rules=$(rule_state_get_applied)
|
||||
while IFS= read -r applied_rule; do
|
||||
local rule_id=$(echo "$applied_rule" | yq eval '.rule_id' -)
|
||||
local rule_name=$(echo "$applied_rule" | yq eval '.rule_name' -)
|
||||
|
||||
# 检查规则是否存在于库中
|
||||
if ! rule_exists "$rule_id"; then
|
||||
sync_issues+=("规则库中不存在已应用的规则: $rule_name ($rule_id)")
|
||||
fi
|
||||
|
||||
# 检查规则是否存在于配置文件中
|
||||
if ! yq eval ".outbounds[] | select(.name == \"$rule_name\")" "$HYSTERIA_CONFIG" >/dev/null 2>&1; then
|
||||
sync_issues+=("配置文件中不存在已应用的规则: $rule_name")
|
||||
fi
|
||||
|
||||
done <<< "$applied_rules"
|
||||
|
||||
# 2. 检查配置文件中的outbound是否都有对应的应用状态
|
||||
echo "检查配置文件一致性..."
|
||||
|
||||
local config_outbounds=$(yq eval '.outbounds[].name' "$HYSTERIA_CONFIG" 2>/dev/null)
|
||||
while IFS= read -r outbound_name; do
|
||||
[[ -z "$outbound_name" ]] && continue
|
||||
|
||||
if ! rule_state_is_applied_by_name "$outbound_name"; then
|
||||
sync_issues+=("配置文件中的规则未记录在应用状态中: $outbound_name")
|
||||
fi
|
||||
|
||||
done <<< "$config_outbounds"
|
||||
|
||||
# 3. 报告结果
|
||||
if [[ ${#sync_issues[@]} -eq 0 ]]; then
|
||||
echo -e "${GREEN}✅ 状态同步检查通过,未发现问题${NC}"
|
||||
else
|
||||
echo -e "${YELLOW}⚠️ 发现 ${#sync_issues[@]} 个同步问题:${NC}"
|
||||
for issue in "${sync_issues[@]}"; do
|
||||
echo " - $issue"
|
||||
done
|
||||
|
||||
echo ""
|
||||
echo "修复选项:"
|
||||
echo "1. 自动修复同步问题"
|
||||
echo "2. 手动处理"
|
||||
echo "3. 忽略问题"
|
||||
|
||||
read -p "请选择 [1-3]: " fix_choice
|
||||
|
||||
case $fix_choice in
|
||||
1)
|
||||
rule_state_auto_fix_sync
|
||||
;;
|
||||
2)
|
||||
echo -e "${BLUE}请手动检查并修复上述问题${NC}"
|
||||
;;
|
||||
3)
|
||||
echo -e "${YELLOW}已忽略同步问题${NC}"
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
echo ""
|
||||
read -p "按任意键继续..." -n 1
|
||||
}
|
||||
|
||||
# 自动修复同步问题
|
||||
rule_state_auto_fix_sync() {
|
||||
echo -e "${BLUE}正在自动修复同步问题...${NC}"
|
||||
|
||||
# 创建修复前的备份
|
||||
rule_state_create_backup "before_sync_fix"
|
||||
|
||||
# 重新构建应用状态文件
|
||||
local temp_applied="/tmp/applied_fixed_$(date +%s).yaml"
|
||||
|
||||
# 初始化新的状态文件
|
||||
cat > "$temp_applied" <<EOF
|
||||
metadata:
|
||||
version: "2.0"
|
||||
last_applied: "$(date -Iseconds)"
|
||||
hysteria_config: "$HYSTERIA_CONFIG"
|
||||
|
||||
applied_rules: []
|
||||
|
||||
backup_config:
|
||||
backup_path: ""
|
||||
created_at: ""
|
||||
EOF
|
||||
|
||||
# 从配置文件重新构建应用状态
|
||||
local config_outbounds=$(yq eval '.outbounds[].name' "$HYSTERIA_CONFIG" 2>/dev/null)
|
||||
while IFS= read -r outbound_name; do
|
||||
[[ -z "$outbound_name" ]] && continue
|
||||
|
||||
# 尝试从规则库中找到对应的规则
|
||||
local rule_id=$(rule_get_id_by_name "$outbound_name")
|
||||
|
||||
if [[ -n "$rule_id" ]]; then
|
||||
# 添加到应用状态
|
||||
local applied_entry=$(cat <<EOF
|
||||
{
|
||||
"rule_id": "$rule_id",
|
||||
"rule_name": "$outbound_name",
|
||||
"applied_at": "$(date -Iseconds)"
|
||||
}
|
||||
EOF
|
||||
)
|
||||
yq eval ".applied_rules += [$applied_entry]" -i "$temp_applied"
|
||||
fi
|
||||
|
||||
done <<< "$config_outbounds"
|
||||
|
||||
# 应用修复后的状态文件
|
||||
mv "$temp_applied" "$APPLIED_STATE"
|
||||
|
||||
echo -e "${GREEN}✅ 同步问题修复完成${NC}"
|
||||
}
|
||||
```
|
||||
|
||||
### 3. 用户界面实现示例
|
||||
|
||||
#### 交互式规则管理界面
|
||||
```bash
|
||||
#!/bin/bash
|
||||
# 用户友好的规则管理界面
|
||||
|
||||
rule_ui_interactive_management() {
|
||||
while true; do
|
||||
clear
|
||||
echo -e "${CYAN}╔═══════════════════════════════════════════════════════════════╗${NC}"
|
||||
echo -e "${CYAN}║ Hysteria2 出站规则管理系统 v2.0 ║${NC}"
|
||||
echo -e "${CYAN}╚═══════════════════════════════════════════════════════════════╝${NC}"
|
||||
echo ""
|
||||
|
||||
# 显示系统状态概览
|
||||
rule_ui_show_status_overview
|
||||
|
||||
echo ""
|
||||
echo -e "${GREEN}┌─ 规则库操作 ─────────────────────────────────┐${NC}"
|
||||
echo -e "${GREEN}│ 1.${NC} 📚 查看规则库 │ ${GREEN}2.${NC} ➕ 创建新规则 │"
|
||||
echo -e "${GREEN}│ 3.${NC} ✏️ 编辑规则 │ ${GREEN}4.${NC} 🗑️ 删除规则 │"
|
||||
echo -e "${GREEN}│ 5.${NC} 📁 导入/导出规则 │ │"
|
||||
echo -e "${GREEN}└─────────────────────────────────────────────┘${NC}"
|
||||
echo ""
|
||||
echo -e "${CYAN}┌─ 应用管理 ───────────────────────────────────┐${NC}"
|
||||
echo -e "${CYAN}│ 6.${NC} 🔍 查看应用状态 │ ${CYAN}7.${NC} ⚡ 应用规则 │"
|
||||
echo -e "${CYAN}│ 8.${NC} ❌ 取消应用规则 │ ${CYAN}9.${NC} 📦 批量操作 │"
|
||||
echo -e "${CYAN}└─────────────────────────────────────────────┘${NC}"
|
||||
echo ""
|
||||
echo -e "${YELLOW}┌─ 系统功能 ───────────────────────────────────┐${NC}"
|
||||
echo -e "${YELLOW}│10.${NC} 💾 备份恢复 │ ${YELLOW}11.${NC} 🔄 状态同步 │"
|
||||
echo -e "${YELLOW}│12.${NC} 🚀 迁移旧配置 │ ${YELLOW}13.${NC} ⚙️ 系统设置 │"
|
||||
echo -e "${YELLOW}└─────────────────────────────────────────────┘${NC}"
|
||||
echo ""
|
||||
echo -e "${RED} 0.${NC} 🚪 返回主菜单"
|
||||
echo ""
|
||||
|
||||
read -p "请选择操作 [0-13]: " choice
|
||||
|
||||
case $choice in
|
||||
1) rule_ui_view_library_detailed ;;
|
||||
2) rule_create_interactive ;;
|
||||
3) rule_ui_edit_rule_interactive ;;
|
||||
4) rule_ui_delete_rule_interactive ;;
|
||||
5) rule_ui_import_export_interactive ;;
|
||||
6) rule_ui_view_applied_detailed ;;
|
||||
7) rule_ui_apply_rule_interactive ;;
|
||||
8) rule_ui_unapply_rule_interactive ;;
|
||||
9) rule_ui_batch_operations_interactive ;;
|
||||
10) rule_ui_backup_restore_interactive ;;
|
||||
11) rule_state_sync_check ;;
|
||||
12) rule_ui_migrate_config_interactive ;;
|
||||
13) rule_ui_system_settings ;;
|
||||
0) break ;;
|
||||
*)
|
||||
echo -e "${RED}无效选择,请重新输入${NC}"
|
||||
sleep 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
}
|
||||
|
||||
# 显示系统状态概览
|
||||
rule_ui_show_status_overview() {
|
||||
local total_rules=$(rule_list | jq 'length')
|
||||
local applied_rules=$(rule_state_get_applied | jq 'length')
|
||||
local unapplied_rules=$((total_rules - applied_rules))
|
||||
|
||||
local status_color="${GREEN}"
|
||||
local status_text="正常"
|
||||
|
||||
# 简单的健康检查
|
||||
if ! rule_state_sync_check_simple; then
|
||||
status_color="${YELLOW}"
|
||||
status_text="需要同步"
|
||||
fi
|
||||
|
||||
echo -e "${BLUE}┌─ 系统状态 ───────────────────────────────────────────────────┐${NC}"
|
||||
echo -e "${BLUE}│${NC} 规则库总数: ${CYAN}$total_rules${NC} 个 │ 已应用: ${GREEN}$applied_rules${NC} 个 │ 未应用: ${YELLOW}$unapplied_rules${NC} 个"
|
||||
echo -e "${BLUE}│${NC} 系统状态: ${status_color}$status_text${NC}"
|
||||
echo -e "${BLUE}└─────────────────────────────────────────────────────────────┘${NC}"
|
||||
}
|
||||
|
||||
# 详细查看规则库
|
||||
rule_ui_view_library_detailed() {
|
||||
while true; do
|
||||
clear
|
||||
echo -e "${BLUE}=== 规则库详细信息 ===${NC}"
|
||||
echo ""
|
||||
|
||||
local rules_json=$(rule_list)
|
||||
if [[ "$rules_json" == "[]" ]]; then
|
||||
echo -e "${YELLOW}📭 规则库为空${NC}"
|
||||
echo ""
|
||||
echo "建议操作:"
|
||||
echo "1. 创建新规则"
|
||||
echo "2. 导入规则文件"
|
||||
echo "3. 从现有配置迁移"
|
||||
echo ""
|
||||
read -p "按任意键返回..." -n 1
|
||||
return
|
||||
fi
|
||||
|
||||
# 显示规则统计
|
||||
local total_count=$(echo "$rules_json" | jq 'length')
|
||||
local direct_count=$(echo "$rules_json" | jq '[.[] | select(.type == "direct")] | length')
|
||||
local socks5_count=$(echo "$rules_json" | jq '[.[] | select(.type == "socks5")] | length')
|
||||
local http_count=$(echo "$rules_json" | jq '[.[] | select(.type == "http")] | length')
|
||||
|
||||
echo -e "${CYAN}📊 规则统计:${NC}"
|
||||
echo " 总数: $total_count 个"
|
||||
echo " ├─ Direct: $direct_count 个"
|
||||
echo " ├─ SOCKS5: $socks5_count 个"
|
||||
echo " └─ HTTP: $http_count 个"
|
||||
echo ""
|
||||
|
||||
# 表格显示规则
|
||||
echo -e "${GREEN}📋 规则列表:${NC}"
|
||||
printf "%-4s %-20s %-8s %-10s %-8s %-25s\n" "序号" "规则名称" "类型" "状态" "标签" "描述"
|
||||
echo "──────────────────────────────────────────────────────────────────────────────"
|
||||
|
||||
local count=1
|
||||
echo "$rules_json" | jq -r '.[] | [.id, .name, .type, .description, (.tags // [])] | @json' | \
|
||||
while IFS= read -r rule_line; do
|
||||
local rule_data=$(echo "$rule_line" | jq -r '.')
|
||||
local id=$(echo "$rule_data" | jq -r '.[0]')
|
||||
local name=$(echo "$rule_data" | jq -r '.[1]')
|
||||
local type=$(echo "$rule_data" | jq -r '.[2]')
|
||||
local desc=$(echo "$rule_data" | jq -r '.[3]')
|
||||
local tags=$(echo "$rule_data" | jq -r '.[4] | join(",")')
|
||||
|
||||
# 检查应用状态
|
||||
local status="🔴 未应用"
|
||||
if rule_state_is_applied "$id"; then
|
||||
status="🟢 已应用"
|
||||
fi
|
||||
|
||||
# 截断长文本
|
||||
[[ ${#desc} -gt 25 ]] && desc="${desc:0:22}..."
|
||||
[[ ${#tags} -gt 8 ]] && tags="${tags:0:5}..."
|
||||
|
||||
printf "%-4s %-20s %-8s %-10s %-8s %-25s\n" "$count" "$name" "$type" "$status" "$tags" "$desc"
|
||||
((count++))
|
||||
done
|
||||
|
||||
echo ""
|
||||
echo "操作选项:"
|
||||
echo "1. 查看规则详情"
|
||||
echo "2. 筛选规则"
|
||||
echo "3. 搜索规则"
|
||||
echo "0. 返回"
|
||||
|
||||
read -p "请选择 [0-3]: " view_choice
|
||||
|
||||
case $view_choice in
|
||||
1)
|
||||
rule_ui_view_rule_details
|
||||
;;
|
||||
2)
|
||||
rule_ui_filter_rules
|
||||
;;
|
||||
3)
|
||||
rule_ui_search_rules
|
||||
;;
|
||||
0)
|
||||
break
|
||||
;;
|
||||
*)
|
||||
echo -e "${RED}无效选择${NC}"
|
||||
sleep 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
}
|
||||
|
||||
# 查看规则详情
|
||||
rule_ui_view_rule_details() {
|
||||
echo ""
|
||||
read -p "请输入要查看的规则名称: " rule_name
|
||||
|
||||
if [[ -z "$rule_name" ]]; then
|
||||
echo -e "${RED}规则名称不能为空${NC}"
|
||||
sleep 1
|
||||
return
|
||||
fi
|
||||
|
||||
local rule_id=$(rule_get_id_by_name "$rule_name")
|
||||
if [[ -z "$rule_id" ]]; then
|
||||
echo -e "${RED}规则不存在: $rule_name${NC}"
|
||||
sleep 2
|
||||
return
|
||||
fi
|
||||
|
||||
local rule_data=$(rule_get "$rule_id")
|
||||
|
||||
clear
|
||||
echo -e "${BLUE}=== 规则详情: $rule_name ===${NC}"
|
||||
echo ""
|
||||
|
||||
echo -e "${CYAN}基本信息:${NC}"
|
||||
echo " 规则ID: $(echo "$rule_data" | yq eval '.id' -)"
|
||||
echo " 规则名称: $(echo "$rule_data" | yq eval '.name' -)"
|
||||
echo " 规则类型: $(echo "$rule_data" | yq eval '.type' -)"
|
||||
echo " 描述: $(echo "$rule_data" | yq eval '.description' -)"
|
||||
echo " 标签: $(echo "$rule_data" | yq eval '.tags // []' - | tr '\n' ',' | sed 's/,$//')"
|
||||
echo ""
|
||||
|
||||
echo -e "${CYAN}时间信息:${NC}"
|
||||
echo " 创建时间: $(echo "$rule_data" | yq eval '.created' -)"
|
||||
echo " 修改时间: $(echo "$rule_data" | yq eval '.modified' -)"
|
||||
echo ""
|
||||
|
||||
echo -e "${CYAN}配置详情:${NC}"
|
||||
echo "$rule_data" | yq eval '.config' - | sed 's/^/ /'
|
||||
echo ""
|
||||
|
||||
# 显示应用状态
|
||||
if rule_state_is_applied "$rule_id"; then
|
||||
echo -e "${GREEN}✅ 应用状态: 已应用${NC}"
|
||||
local applied_info=$(rule_state_get_applied | jq -r ".[] | select(.rule_id == \"$rule_id\")")
|
||||
echo " 应用时间: $(echo "$applied_info" | jq -r '.applied_at')"
|
||||
echo " ACL规则: $(echo "$applied_info" | jq -r '.acl_rules // [] | join(", ")')"
|
||||
else
|
||||
echo -e "${YELLOW}⭕ 应用状态: 未应用${NC}"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
read -p "按任意键继续..." -n 1
|
||||
}
|
||||
```
|
||||
|
||||
## 📋 总结
|
||||
|
||||
这些代码示例展示了新架构的核心特性:
|
||||
|
||||
### ✅ **核心功能实现**
|
||||
1. **完整CRUD操作** - 规则的创建、读取、更新、删除
|
||||
2. **状态管理** - 独立的应用状态追踪和管理
|
||||
3. **配置应用** - 安全的配置文件更新机制
|
||||
4. **用户界面** - 直观友好的交互体验
|
||||
|
||||
### 🎯 **技术特点**
|
||||
1. **JSON/YAML处理** - 使用`yq`和`jq`进行结构化数据操作
|
||||
2. **原子操作** - 配置更新的事务性保证
|
||||
3. **错误处理** - 完善的错误检测和恢复机制
|
||||
4. **输入验证** - 严格的参数和格式验证
|
||||
|
||||
### 🚀 **用户体验**
|
||||
1. **向导式创建** - 步骤引导的规则创建流程
|
||||
2. **实时状态** - 系统状态和规则状态的实时显示
|
||||
3. **批量操作** - 支持多规则的批量管理
|
||||
4. **智能提示** - 冲突检测和解决建议
|
||||
|
||||
这个新架构完全解决了原有系统的问题,提供了现代化、可扩展的出站规则管理解决方案。
|
||||
@@ -0,0 +1,686 @@
|
||||
# 出站规则管理系统实现计划
|
||||
|
||||
## 🚀 实现优先级
|
||||
|
||||
### Phase 1: 核心基础设施 (高优先级)
|
||||
```
|
||||
1. 规则库存储系统
|
||||
2. 基本CRUD操作
|
||||
3. 状态管理器
|
||||
4. 配置应用器
|
||||
5. 数据验证层
|
||||
```
|
||||
|
||||
### Phase 2: 用户界面 (中优先级)
|
||||
```
|
||||
1. 规则库管理UI
|
||||
2. 规则应用管理UI
|
||||
3. 批量操作支持
|
||||
4. 导入/导出功能
|
||||
5. 配置差异查看
|
||||
```
|
||||
|
||||
### Phase 3: 高级功能 (低优先级)
|
||||
```
|
||||
1. 规则模板系统
|
||||
2. 智能冲突检测
|
||||
3. 性能优化
|
||||
4. 高级备份恢复
|
||||
5. 操作审计日志
|
||||
```
|
||||
|
||||
## 📁 文件结构设计
|
||||
|
||||
```
|
||||
/etc/hysteria/
|
||||
├── config.yaml # 主配置文件
|
||||
├── rules/ # 规则管理目录
|
||||
│ ├── library.yaml # 规则库
|
||||
│ ├── applied.yaml # 应用状态
|
||||
│ ├── templates.yaml # 规则模板
|
||||
│ └── backups/ # 配置备份
|
||||
│ ├── config_20250928_103000.yaml
|
||||
│ └── state_20250928_103000.yaml
|
||||
└── logs/ # 日志目录
|
||||
└── rule-management.log
|
||||
|
||||
scripts/
|
||||
├── rules/ # 规则管理脚本目录
|
||||
│ ├── rule-library.sh # 规则库管理器
|
||||
│ ├── rule-state.sh # 状态管理器
|
||||
│ ├── config-applier.sh # 配置应用器
|
||||
│ ├── rule-validator.sh # 规则验证器
|
||||
│ ├── rule-templates.sh # 模板管理器
|
||||
│ ├── migration-helper.sh # 迁移助手
|
||||
│ └── rule-ui.sh # 用户界面
|
||||
└── outbound-manager-v2.sh # 新版主管理器
|
||||
```
|
||||
|
||||
## 🔧 核心组件实现
|
||||
|
||||
### 1. 规则库管理器 (rule-library.sh)
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
# 规则库管理器 - 负责规则的CRUD操作
|
||||
|
||||
# 规则库路径
|
||||
readonly RULE_LIBRARY="/etc/hysteria/rules/library.yaml"
|
||||
readonly RULE_TEMPLATES="/etc/hysteria/rules/templates.yaml"
|
||||
|
||||
# 创建规则
|
||||
rule_create() {
|
||||
local name="$1" type="$2" description="$3" config_json="$4"
|
||||
|
||||
# 生成规则ID
|
||||
local rule_id="rule_$(date +%s)_$(shuf -i 1000-9999 -n 1)"
|
||||
|
||||
# 验证规则格式
|
||||
if ! rule_validate_config "$type" "$config_json"; then
|
||||
echo "ERROR: 规则配置验证失败"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# 检查名称唯一性
|
||||
if rule_exists_by_name "$name"; then
|
||||
echo "ERROR: 规则名称已存在: $name"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# 添加到规则库
|
||||
rule_library_add_entry "$rule_id" "$name" "$type" "$description" "$config_json"
|
||||
|
||||
echo "SUCCESS: 规则创建成功, ID: $rule_id"
|
||||
echo "$rule_id"
|
||||
}
|
||||
|
||||
# 列出所有规则
|
||||
rule_list() {
|
||||
local filter="$1" # 可选: type|applied|name
|
||||
local value="$2" # 过滤值
|
||||
|
||||
if [[ ! -f "$RULE_LIBRARY" ]]; then
|
||||
echo "[]"
|
||||
return 0
|
||||
fi
|
||||
|
||||
# 根据过滤条件返回规则列表
|
||||
case "$filter" in
|
||||
"type")
|
||||
yq eval ".rules[] | select(.type == \"$value\")" "$RULE_LIBRARY"
|
||||
;;
|
||||
"applied")
|
||||
# 需要与状态管理器配合
|
||||
rule_state_get_applied | jq -r '.[].rule_id' | while read -r rule_id; do
|
||||
rule_get "$rule_id"
|
||||
done
|
||||
;;
|
||||
*)
|
||||
yq eval '.rules[]' "$RULE_LIBRARY"
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
# 获取规则详情
|
||||
rule_get() {
|
||||
local rule_id="$1"
|
||||
|
||||
if [[ ! -f "$RULE_LIBRARY" ]]; then
|
||||
echo "ERROR: 规则库不存在"
|
||||
return 1
|
||||
fi
|
||||
|
||||
yq eval ".rules.$rule_id" "$RULE_LIBRARY"
|
||||
}
|
||||
|
||||
# 更新规则
|
||||
rule_update() {
|
||||
local rule_id="$1" field="$2" value="$3"
|
||||
|
||||
# 验证规则存在
|
||||
if ! rule_exists "$rule_id"; then
|
||||
echo "ERROR: 规则不存在: $rule_id"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# 创建备份
|
||||
cp "$RULE_LIBRARY" "${RULE_LIBRARY}.bak"
|
||||
|
||||
# 更新字段
|
||||
case "$field" in
|
||||
"name")
|
||||
if rule_exists_by_name "$value"; then
|
||||
echo "ERROR: 规则名称已存在: $value"
|
||||
return 1
|
||||
fi
|
||||
yq eval ".rules.$rule_id.name = \"$value\"" -i "$RULE_LIBRARY"
|
||||
;;
|
||||
"description")
|
||||
yq eval ".rules.$rule_id.description = \"$value\"" -i "$RULE_LIBRARY"
|
||||
;;
|
||||
"config")
|
||||
# JSON格式的配置更新
|
||||
yq eval ".rules.$rule_id.config = $value" -i "$RULE_LIBRARY"
|
||||
;;
|
||||
*)
|
||||
echo "ERROR: 不支持的字段: $field"
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
|
||||
# 更新修改时间
|
||||
yq eval ".rules.$rule_id.modified = \"$(date -Iseconds)\"" -i "$RULE_LIBRARY"
|
||||
yq eval ".metadata.last_modified = \"$(date -Iseconds)\"" -i "$RULE_LIBRARY"
|
||||
|
||||
rm -f "${RULE_LIBRARY}.bak"
|
||||
echo "SUCCESS: 规则更新成功"
|
||||
}
|
||||
|
||||
# 删除规则
|
||||
rule_delete() {
|
||||
local rule_id="$1"
|
||||
|
||||
# 检查规则是否已应用
|
||||
if rule_state_is_applied "$rule_id"; then
|
||||
echo "ERROR: 无法删除已应用的规则,请先取消应用"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# 创建备份
|
||||
cp "$RULE_LIBRARY" "${RULE_LIBRARY}.bak"
|
||||
|
||||
# 删除规则
|
||||
yq eval "del(.rules.$rule_id)" -i "$RULE_LIBRARY"
|
||||
|
||||
# 更新元数据
|
||||
local total_count=$(yq eval '.rules | keys | length' "$RULE_LIBRARY")
|
||||
yq eval ".metadata.total_rules = $total_count" -i "$RULE_LIBRARY"
|
||||
yq eval ".metadata.last_modified = \"$(date -Iseconds)\"" -i "$RULE_LIBRARY"
|
||||
|
||||
rm -f "${RULE_LIBRARY}.bak"
|
||||
echo "SUCCESS: 规则删除成功"
|
||||
}
|
||||
|
||||
# 辅助函数
|
||||
rule_exists() {
|
||||
local rule_id="$1"
|
||||
yq eval ".rules | has(\"$rule_id\")" "$RULE_LIBRARY" | grep -q "true"
|
||||
}
|
||||
|
||||
rule_exists_by_name() {
|
||||
local name="$1"
|
||||
yq eval ".rules[].name" "$RULE_LIBRARY" | grep -q "^$name$"
|
||||
}
|
||||
|
||||
rule_validate_config() {
|
||||
local type="$1" config="$2"
|
||||
|
||||
case "$type" in
|
||||
"direct")
|
||||
# 验证direct配置格式
|
||||
echo "$config" | jq -e '.direct' >/dev/null
|
||||
;;
|
||||
"socks5")
|
||||
# 验证socks5配置格式
|
||||
echo "$config" | jq -e '.socks5.addr' >/dev/null
|
||||
;;
|
||||
"http")
|
||||
# 验证http配置格式
|
||||
echo "$config" | jq -e '.http.url' >/dev/null
|
||||
;;
|
||||
*)
|
||||
echo "ERROR: 不支持的规则类型: $type"
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
}
|
||||
```
|
||||
|
||||
### 2. 状态管理器 (rule-state.sh)
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
# 状态管理器 - 负责规则应用状态的管理
|
||||
|
||||
readonly APPLIED_STATE="/etc/hysteria/rules/applied.yaml"
|
||||
readonly HYSTERIA_CONFIG="/etc/hysteria/config.yaml"
|
||||
readonly BACKUP_DIR="/etc/hysteria/rules/backups"
|
||||
|
||||
# 应用规则到配置
|
||||
rule_state_apply() {
|
||||
local rule_id="$1"
|
||||
|
||||
# 获取规则详情
|
||||
local rule_data
|
||||
rule_data=$(rule_get "$rule_id")
|
||||
if [[ $? -ne 0 ]]; then
|
||||
echo "ERROR: 规则不存在: $rule_id"
|
||||
return 1
|
||||
fi
|
||||
|
||||
local rule_name=$(echo "$rule_data" | yq eval '.name' -)
|
||||
local rule_type=$(echo "$rule_data" | yq eval '.type' -)
|
||||
local rule_config=$(echo "$rule_data" | yq eval '.config' -)
|
||||
|
||||
# 检查是否已应用
|
||||
if rule_state_is_applied "$rule_id"; then
|
||||
echo "ERROR: 规则已经应用: $rule_name"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# 创建配置备份
|
||||
rule_state_create_backup "before_apply_$rule_name"
|
||||
|
||||
# 应用规则到配置文件
|
||||
if config_applier_add_rule "$rule_name" "$rule_type" "$rule_config"; then
|
||||
# 更新应用状态
|
||||
rule_state_add_applied "$rule_id" "$rule_name"
|
||||
echo "SUCCESS: 规则应用成功: $rule_name"
|
||||
return 0
|
||||
else
|
||||
echo "ERROR: 规则应用失败"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# 取消规则应用
|
||||
rule_state_unapply() {
|
||||
local rule_id="$1"
|
||||
|
||||
# 检查是否已应用
|
||||
if ! rule_state_is_applied "$rule_id"; then
|
||||
echo "ERROR: 规则未应用: $rule_id"
|
||||
return 1
|
||||
fi
|
||||
|
||||
local rule_name=$(rule_state_get_applied_name "$rule_id")
|
||||
|
||||
# 创建配置备份
|
||||
rule_state_create_backup "before_unapply_$rule_name"
|
||||
|
||||
# 从配置文件移除规则
|
||||
if config_applier_remove_rule "$rule_name"; then
|
||||
# 更新应用状态
|
||||
rule_state_remove_applied "$rule_id"
|
||||
echo "SUCCESS: 规则取消应用成功: $rule_name"
|
||||
return 0
|
||||
else
|
||||
echo "ERROR: 规则取消应用失败"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# 获取已应用规则列表
|
||||
rule_state_get_applied() {
|
||||
if [[ ! -f "$APPLIED_STATE" ]]; then
|
||||
echo "[]"
|
||||
return 0
|
||||
fi
|
||||
|
||||
yq eval '.applied_rules[]' "$APPLIED_STATE"
|
||||
}
|
||||
|
||||
# 检查规则是否已应用
|
||||
rule_state_is_applied() {
|
||||
local rule_id="$1"
|
||||
|
||||
if [[ ! -f "$APPLIED_STATE" ]]; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
yq eval ".applied_rules[] | select(.rule_id == \"$rule_id\")" "$APPLIED_STATE" | grep -q "rule_id"
|
||||
}
|
||||
|
||||
# 获取已应用规则的名称
|
||||
rule_state_get_applied_name() {
|
||||
local rule_id="$1"
|
||||
yq eval ".applied_rules[] | select(.rule_id == \"$rule_id\") | .rule_name" "$APPLIED_STATE"
|
||||
}
|
||||
|
||||
# 添加应用状态记录
|
||||
rule_state_add_applied() {
|
||||
local rule_id="$1" rule_name="$2"
|
||||
|
||||
# 初始化状态文件
|
||||
rule_state_init_file
|
||||
|
||||
# 添加应用记录
|
||||
local applied_entry=$(cat <<EOF
|
||||
{
|
||||
"rule_id": "$rule_id",
|
||||
"rule_name": "$rule_name",
|
||||
"applied_at": "$(date -Iseconds)"
|
||||
}
|
||||
EOF
|
||||
)
|
||||
|
||||
yq eval ".applied_rules += [$applied_entry]" -i "$APPLIED_STATE"
|
||||
yq eval ".metadata.last_applied = \"$(date -Iseconds)\"" -i "$APPLIED_STATE"
|
||||
}
|
||||
|
||||
# 移除应用状态记录
|
||||
rule_state_remove_applied() {
|
||||
local rule_id="$1"
|
||||
|
||||
yq eval "del(.applied_rules[] | select(.rule_id == \"$rule_id\"))" -i "$APPLIED_STATE"
|
||||
yq eval ".metadata.last_applied = \"$(date -Iseconds)\"" -i "$APPLIED_STATE"
|
||||
}
|
||||
|
||||
# 创建配置备份
|
||||
rule_state_create_backup() {
|
||||
local backup_name="$1"
|
||||
local timestamp=$(date +%Y%m%d_%H%M%S)
|
||||
local backup_file="$BACKUP_DIR/config_${backup_name}_${timestamp}.yaml"
|
||||
|
||||
mkdir -p "$BACKUP_DIR"
|
||||
cp "$HYSTERIA_CONFIG" "$backup_file"
|
||||
|
||||
# 更新备份记录
|
||||
yq eval ".backup_config.backup_path = \"$backup_file\"" -i "$APPLIED_STATE"
|
||||
yq eval ".backup_config.created_at = \"$(date -Iseconds)\"" -i "$APPLIED_STATE"
|
||||
|
||||
echo "配置备份已创建: $backup_file"
|
||||
}
|
||||
|
||||
# 初始化状态文件
|
||||
rule_state_init_file() {
|
||||
if [[ ! -f "$APPLIED_STATE" ]]; then
|
||||
mkdir -p "$(dirname "$APPLIED_STATE")"
|
||||
cat > "$APPLIED_STATE" <<EOF
|
||||
metadata:
|
||||
version: "2.0"
|
||||
last_applied: "$(date -Iseconds)"
|
||||
hysteria_config: "$HYSTERIA_CONFIG"
|
||||
|
||||
applied_rules: []
|
||||
|
||||
backup_config:
|
||||
backup_path: ""
|
||||
created_at: ""
|
||||
EOF
|
||||
fi
|
||||
}
|
||||
```
|
||||
|
||||
### 3. 配置应用器 (config-applier.sh)
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
# 配置应用器 - 负责将规则应用到Hysteria2配置文件
|
||||
|
||||
# 添加规则到配置文件
|
||||
config_applier_add_rule() {
|
||||
local rule_name="$1" rule_type="$2" rule_config="$3"
|
||||
|
||||
# 创建临时配置文件
|
||||
local temp_config="/tmp/hysteria_apply_$(date +%s).yaml"
|
||||
cp "$HYSTERIA_CONFIG" "$temp_config"
|
||||
|
||||
# 检查是否存在outbounds节点
|
||||
if ! yq eval '.outbounds' "$temp_config" >/dev/null 2>&1; then
|
||||
# 创建outbounds节点
|
||||
yq eval '.outbounds = []' -i "$temp_config"
|
||||
fi
|
||||
|
||||
# 构建规则配置
|
||||
local rule_yaml
|
||||
case "$rule_type" in
|
||||
"direct")
|
||||
rule_yaml=$(echo "$rule_config" | yq eval '{name: "'$rule_name'", type: "direct", direct: .direct}' -)
|
||||
;;
|
||||
"socks5")
|
||||
rule_yaml=$(echo "$rule_config" | yq eval '{name: "'$rule_name'", type: "socks5", socks5: .socks5}' -)
|
||||
;;
|
||||
"http")
|
||||
rule_yaml=$(echo "$rule_config" | yq eval '{name: "'$rule_name'", type: "http", http: .http}' -)
|
||||
;;
|
||||
*)
|
||||
echo "ERROR: 不支持的规则类型: $rule_type"
|
||||
rm -f "$temp_config"
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
|
||||
# 添加规则到outbounds
|
||||
yq eval ".outbounds += [$rule_yaml]" -i "$temp_config"
|
||||
|
||||
# 验证配置文件格式
|
||||
if ! yq eval '.' "$temp_config" >/dev/null 2>&1; then
|
||||
echo "ERROR: 生成的配置文件格式错误"
|
||||
rm -f "$temp_config"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# 原子性更新配置文件
|
||||
if mv "$temp_config" "$HYSTERIA_CONFIG"; then
|
||||
echo "规则已添加到配置文件: $rule_name"
|
||||
return 0
|
||||
else
|
||||
echo "ERROR: 配置文件更新失败"
|
||||
rm -f "$temp_config"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# 从配置文件移除规则
|
||||
config_applier_remove_rule() {
|
||||
local rule_name="$1"
|
||||
|
||||
# 创建临时配置文件
|
||||
local temp_config="/tmp/hysteria_remove_$(date +%s).yaml"
|
||||
cp "$HYSTERIA_CONFIG" "$temp_config"
|
||||
|
||||
# 移除指定规则
|
||||
yq eval "del(.outbounds[] | select(.name == \"$rule_name\"))" -i "$temp_config"
|
||||
|
||||
# 如果outbounds为空,删除整个节点
|
||||
local outbounds_count=$(yq eval '.outbounds | length' "$temp_config")
|
||||
if [[ "$outbounds_count" == "0" ]]; then
|
||||
yq eval 'del(.outbounds)' -i "$temp_config"
|
||||
fi
|
||||
|
||||
# 移除相关ACL规则
|
||||
config_applier_remove_acl_rules "$rule_name" "$temp_config"
|
||||
|
||||
# 验证配置文件格式
|
||||
if ! yq eval '.' "$temp_config" >/dev/null 2>&1; then
|
||||
echo "ERROR: 生成的配置文件格式错误"
|
||||
rm -f "$temp_config"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# 原子性更新配置文件
|
||||
if mv "$temp_config" "$HYSTERIA_CONFIG"; then
|
||||
echo "规则已从配置文件移除: $rule_name"
|
||||
return 0
|
||||
else
|
||||
echo "ERROR: 配置文件更新失败"
|
||||
rm -f "$temp_config"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# 移除ACL规则
|
||||
config_applier_remove_acl_rules() {
|
||||
local rule_name="$1" config_file="$2"
|
||||
|
||||
# 移除inline ACL中的规则引用
|
||||
yq eval "del(.acl.inline[] | select(. | test(\"$rule_name\")))" -i "$config_file"
|
||||
|
||||
# 如果inline ACL为空,删除ACL节点
|
||||
local acl_count=$(yq eval '.acl.inline | length' "$config_file" 2>/dev/null || echo "0")
|
||||
if [[ "$acl_count" == "0" ]]; then
|
||||
yq eval 'del(.acl)' -i "$config_file"
|
||||
fi
|
||||
}
|
||||
|
||||
# 批量应用规则
|
||||
config_applier_batch_apply() {
|
||||
local rule_ids=("$@")
|
||||
|
||||
for rule_id in "${rule_ids[@]}"; do
|
||||
if ! rule_state_apply "$rule_id"; then
|
||||
echo "ERROR: 批量应用在规则 $rule_id 处失败"
|
||||
return 1
|
||||
fi
|
||||
done
|
||||
|
||||
echo "SUCCESS: 批量应用完成,共应用 ${#rule_ids[@]} 个规则"
|
||||
}
|
||||
|
||||
# 验证最终配置
|
||||
config_applier_validate() {
|
||||
local config_file="${1:-$HYSTERIA_CONFIG}"
|
||||
|
||||
# YAML格式验证
|
||||
if ! yq eval '.' "$config_file" >/dev/null 2>&1; then
|
||||
echo "ERROR: YAML格式错误"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# 基本结构验证
|
||||
if yq eval '.outbounds[]' "$config_file" 2>/dev/null | grep -q "name:"; then
|
||||
# 检查规则名称唯一性
|
||||
local names=$(yq eval '.outbounds[].name' "$config_file" | sort)
|
||||
local unique_names=$(echo "$names" | uniq)
|
||||
|
||||
if [[ "$names" != "$unique_names" ]]; then
|
||||
echo "ERROR: 规则名称重复"
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "配置文件验证通过"
|
||||
return 0
|
||||
}
|
||||
```
|
||||
|
||||
## 🎮 用户界面组件
|
||||
|
||||
### 4. 用户界面管理器 (rule-ui.sh)
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
# 用户界面管理器 - 提供友好的交互界面
|
||||
|
||||
# 主菜单
|
||||
rule_ui_main_menu() {
|
||||
while true; do
|
||||
clear
|
||||
echo -e "${CYAN}=== Hysteria2 出站规则管理 v2.0 ===${NC}"
|
||||
echo ""
|
||||
echo -e "${GREEN}规则库管理:${NC}"
|
||||
echo -e "${GREEN} 1.${NC} 查看规则库"
|
||||
echo -e "${GREEN} 2.${NC} 创建新规则"
|
||||
echo -e "${GREEN} 3.${NC} 编辑规则"
|
||||
echo -e "${GREEN} 4.${NC} 删除规则"
|
||||
echo -e "${GREEN} 5.${NC} 导入/导出规则"
|
||||
echo ""
|
||||
echo -e "${CYAN}应用管理:${NC}"
|
||||
echo -e "${CYAN} 6.${NC} 查看应用状态"
|
||||
echo -e "${CYAN} 7.${NC} 应用规则"
|
||||
echo -e "${CYAN} 8.${NC} 取消应用规则"
|
||||
echo -e "${CYAN} 9.${NC} 批量操作"
|
||||
echo ""
|
||||
echo -e "${YELLOW}系统功能:${NC}"
|
||||
echo -e "${YELLOW}10.${NC} 配置备份恢复"
|
||||
echo -e "${YELLOW}11.${NC} 状态同步检查"
|
||||
echo -e "${YELLOW}12.${NC} 迁移旧配置"
|
||||
echo ""
|
||||
echo -e "${RED} 0.${NC} 返回主菜单"
|
||||
echo ""
|
||||
|
||||
read -p "请选择操作 [0-12]: " choice
|
||||
|
||||
case $choice in
|
||||
1) rule_ui_view_library ;;
|
||||
2) rule_ui_create_rule ;;
|
||||
3) rule_ui_edit_rule ;;
|
||||
4) rule_ui_delete_rule ;;
|
||||
5) rule_ui_import_export ;;
|
||||
6) rule_ui_view_applied ;;
|
||||
7) rule_ui_apply_rule ;;
|
||||
8) rule_ui_unapply_rule ;;
|
||||
9) rule_ui_batch_operations ;;
|
||||
10) rule_ui_backup_restore ;;
|
||||
11) rule_ui_sync_check ;;
|
||||
12) rule_ui_migrate_config ;;
|
||||
0) break ;;
|
||||
*)
|
||||
echo -e "${RED}无效选择,请重新输入${NC}"
|
||||
sleep 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
}
|
||||
|
||||
# 查看规则库
|
||||
rule_ui_view_library() {
|
||||
clear
|
||||
echo -e "${BLUE}=== 规则库 ===${NC}"
|
||||
echo ""
|
||||
|
||||
local rules_json=$(rule_list)
|
||||
if [[ "$rules_json" == "[]" ]]; then
|
||||
echo -e "${YELLOW}规则库为空${NC}"
|
||||
echo ""
|
||||
read -p "按任意键继续..." -n 1
|
||||
return
|
||||
fi
|
||||
|
||||
echo -e "${GREEN}当前规则列表:${NC}"
|
||||
echo ""
|
||||
|
||||
# 使用表格格式显示规则
|
||||
printf "%-4s %-20s %-10s %-8s %-30s\n" "序号" "规则名称" "类型" "状态" "描述"
|
||||
echo "────────────────────────────────────────────────────────────────────"
|
||||
|
||||
local count=1
|
||||
echo "$rules_json" | jq -r '.[] | [.id, .name, .type, .description] | @csv' | \
|
||||
while IFS=',' read -r id name type desc; do
|
||||
# 移除CSV引号
|
||||
id=$(echo "$id" | tr -d '"')
|
||||
name=$(echo "$name" | tr -d '"')
|
||||
type=$(echo "$type" | tr -d '"')
|
||||
desc=$(echo "$desc" | tr -d '"')
|
||||
|
||||
# 检查应用状态
|
||||
local status="未应用"
|
||||
if rule_state_is_applied "$id"; then
|
||||
status="${GREEN}已应用${NC}"
|
||||
else
|
||||
status="${YELLOW}未应用${NC}"
|
||||
fi
|
||||
|
||||
printf "%-4s %-20s %-10s %-8s %-30s\n" "$count" "$name" "$type" "$status" "$desc"
|
||||
((count++))
|
||||
done
|
||||
|
||||
echo ""
|
||||
read -p "按任意键继续..." -n 1
|
||||
}
|
||||
```
|
||||
|
||||
## 📋 总结
|
||||
|
||||
这个新架构设计提供了:
|
||||
|
||||
### ✅ **核心优势**
|
||||
- **关注点分离**:规则库、状态管理、配置应用完全解耦
|
||||
- **完整CRUD**:规则的创建、读取、更新、删除全生命周期管理
|
||||
- **状态追踪**:独立的应用状态管理,清晰的规则应用记录
|
||||
- **原子操作**:配置更新的原子性保证,支持回滚
|
||||
- **向后兼容**:保留现有功能,支持渐进式迁移
|
||||
|
||||
### 🎯 **解决的问题**
|
||||
1. ❌ 出站规则直接耦合在配置中 → ✅ 独立规则库管理
|
||||
2. ❌ 无法进行CRUD操作 → ✅ 完整的规则生命周期管理
|
||||
3. ❌ 缺少应用/取消机制 → ✅ 灵活的规则应用状态管理
|
||||
4. ❌ 管理复杂度高 → ✅ 直观的用户界面和批量操作
|
||||
|
||||
### 🚀 **实施路径**
|
||||
1. **Phase 1**: 实现核心基础设施(规则库、状态管理)
|
||||
2. **Phase 2**: 开发用户界面和基本操作
|
||||
3. **Phase 3**: 添加高级功能和优化
|
||||
|
||||
这个架构为Hysteria2出站规则管理提供了现代化、可扩展的解决方案,显著提升了用户体验和系统可维护性。
|
||||
@@ -0,0 +1,371 @@
|
||||
# 出站规则管理架构设计
|
||||
|
||||
## 🎯 架构目标
|
||||
|
||||
### 核心设计原则
|
||||
- **关注点分离**:规则管理 vs 配置应用完全解耦
|
||||
- **CRUD完整性**:创建、读取、更新、删除规则的完整生命周期
|
||||
- **状态管理**:规则库状态与配置文件状态独立维护
|
||||
- **向后兼容**:保留现有功能,平滑升级路径
|
||||
|
||||
### 系统边界定义
|
||||
```
|
||||
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
|
||||
│ 规则库管理 │ │ 状态管理器 │ │ 配置文件应用 │
|
||||
│ (Rule Store) │◄──►│ (State Mgr) │◄──►│ (Config Apply) │
|
||||
└─────────────────┘ └─────────────────┘ └─────────────────┘
|
||||
```
|
||||
|
||||
## 📁 数据存储架构
|
||||
|
||||
### 1. 规则库结构 (`/etc/hysteria/rules/`)
|
||||
```yaml
|
||||
# rules-library.yaml - 规则定义库
|
||||
metadata:
|
||||
version: "2.0"
|
||||
created: "2025-09-28T10:00:00Z"
|
||||
last_modified: "2025-09-28T10:00:00Z"
|
||||
total_rules: 5
|
||||
|
||||
rules:
|
||||
direct_china:
|
||||
id: "rule_001"
|
||||
name: "direct_china"
|
||||
type: "direct"
|
||||
description: "中国大陆直连"
|
||||
tags: ["direct", "china", "bypass"]
|
||||
created: "2025-09-28T10:00:00Z"
|
||||
modified: "2025-09-28T10:00:00Z"
|
||||
config:
|
||||
direct:
|
||||
mode: "auto"
|
||||
bindDevice: "eth0"
|
||||
bindIPv4: "192.168.1.100"
|
||||
|
||||
proxy_global:
|
||||
id: "rule_002"
|
||||
name: "proxy_global"
|
||||
type: "socks5"
|
||||
description: "全局SOCKS5代理"
|
||||
tags: ["proxy", "socks5", "global"]
|
||||
created: "2025-09-28T10:00:00Z"
|
||||
modified: "2025-09-28T10:00:00Z"
|
||||
config:
|
||||
socks5:
|
||||
addr: "proxy.example.com:1080"
|
||||
username: "user123"
|
||||
password: "pass123"
|
||||
```
|
||||
|
||||
### 2. 应用状态管理 (`/etc/hysteria/rules/`)
|
||||
```yaml
|
||||
# applied-rules.yaml - 当前应用状态
|
||||
metadata:
|
||||
version: "2.0"
|
||||
last_applied: "2025-09-28T10:30:00Z"
|
||||
hysteria_config: "/etc/hysteria/config.yaml"
|
||||
|
||||
applied_rules:
|
||||
- rule_id: "rule_001"
|
||||
rule_name: "direct_china"
|
||||
applied_at: "2025-09-28T10:30:00Z"
|
||||
acl_rules:
|
||||
- "direct_china(geoip:cn)"
|
||||
- "direct_china(geosite:cn)"
|
||||
|
||||
- rule_id: "rule_002"
|
||||
rule_name: "proxy_global"
|
||||
applied_at: "2025-09-28T10:30:00Z"
|
||||
acl_rules:
|
||||
- "proxy_global(all)"
|
||||
|
||||
backup_config:
|
||||
backup_path: "/etc/hysteria/backups/config_20250928_103000.yaml"
|
||||
created_at: "2025-09-28T10:30:00Z"
|
||||
```
|
||||
|
||||
### 3. 规则模板库 (`/etc/hysteria/templates/`)
|
||||
```yaml
|
||||
# rule-templates.yaml - 预定义模板
|
||||
templates:
|
||||
china_direct:
|
||||
name: "中国大陆直连"
|
||||
type: "direct"
|
||||
description: "绕过中国大陆IP段,使用直连"
|
||||
default_config:
|
||||
direct:
|
||||
mode: "auto"
|
||||
default_acl:
|
||||
- "{rule_name}(geoip:cn)"
|
||||
- "{rule_name}(geosite:cn)"
|
||||
|
||||
socks5_proxy:
|
||||
name: "SOCKS5代理"
|
||||
type: "socks5"
|
||||
description: "通过SOCKS5代理服务器转发流量"
|
||||
default_config:
|
||||
socks5:
|
||||
addr: "127.0.0.1:1080"
|
||||
default_acl:
|
||||
- "{rule_name}(all)"
|
||||
```
|
||||
|
||||
## 🔧 核心组件架构
|
||||
|
||||
### 1. 规则库管理器 (Rule Library Manager)
|
||||
```bash
|
||||
# 文件: scripts/rule-library-manager.sh
|
||||
|
||||
core_functions:
|
||||
- create_rule() # 创建新规则到库
|
||||
- list_rules() # 列出所有规则
|
||||
- get_rule() # 获取指定规则详情
|
||||
- update_rule() # 更新规则配置
|
||||
- delete_rule() # 从库中删除规则
|
||||
- import_rule() # 从JSON/YAML导入
|
||||
- export_rule() # 导出规则到文件
|
||||
- validate_rule() # 规则格式验证
|
||||
```
|
||||
|
||||
### 2. 状态管理器 (State Manager)
|
||||
```bash
|
||||
# 文件: scripts/rule-state-manager.sh
|
||||
|
||||
core_functions:
|
||||
- get_applied_rules() # 获取当前应用的规则
|
||||
- apply_rule() # 应用规则到配置
|
||||
- unapply_rule() # 取消应用规则
|
||||
- sync_state() # 同步状态与配置文件
|
||||
- create_backup() # 创建配置备份
|
||||
- restore_backup() # 恢复配置备份
|
||||
- validate_state() # 验证状态一致性
|
||||
```
|
||||
|
||||
### 3. 配置应用器 (Config Applier)
|
||||
```bash
|
||||
# 文件: scripts/config-applier.sh
|
||||
|
||||
core_functions:
|
||||
- apply_rules_to_config() # 批量应用规则
|
||||
- remove_rules_from_config() # 批量移除规则
|
||||
- merge_outbound_section() # 合并outbound配置
|
||||
- merge_acl_section() # 合并ACL配置
|
||||
- validate_config() # 验证最终配置
|
||||
- atomic_update() # 原子性配置更新
|
||||
```
|
||||
|
||||
## 🎮 用户界面设计
|
||||
|
||||
### 1. 规则库管理界面
|
||||
```
|
||||
=== 出站规则库管理 ===
|
||||
|
||||
当前规则库: 5 个规则
|
||||
├── direct_china (直连) - 已应用 ✅
|
||||
├── proxy_global (SOCKS5) - 已应用 ✅
|
||||
├── http_corp (HTTP) - 未应用 ⭕
|
||||
├── backup_socks (SOCKS5) - 未应用 ⭕
|
||||
└── cdn_direct (直连) - 未应用 ⭕
|
||||
|
||||
操作选项:
|
||||
1. 查看规则详情
|
||||
2. 创建新规则
|
||||
3. 编辑规则
|
||||
4. 删除规则
|
||||
5. 导入/导出规则
|
||||
6. 规则应用管理 →
|
||||
```
|
||||
|
||||
### 2. 规则应用管理界面
|
||||
```
|
||||
=== 规则应用管理 ===
|
||||
|
||||
当前Hy2配置状态:
|
||||
├── 已应用规则: 2 个
|
||||
│ ├── direct_china (2025-09-28 10:30)
|
||||
│ └── proxy_global (2025-09-28 10:30)
|
||||
├── 备份配置: config_20250928_103000.yaml
|
||||
└── 配置状态: 同步 ✅
|
||||
|
||||
操作选项:
|
||||
1. 应用新规则
|
||||
2. 取消规则应用
|
||||
3. 批量规则管理
|
||||
4. 查看配置差异
|
||||
5. 恢复配置备份
|
||||
6. 重新同步状态
|
||||
```
|
||||
|
||||
## 🔄 工作流程设计
|
||||
|
||||
### 1. 规则创建流程
|
||||
```mermaid
|
||||
graph TD
|
||||
A[选择规则模板] --> B[填写规则配置]
|
||||
B --> C[验证配置格式]
|
||||
C --> D{验证通过?}
|
||||
D -->|是| E[保存到规则库]
|
||||
D -->|否| F[显示错误,重新编辑]
|
||||
F --> B
|
||||
E --> G[生成规则ID]
|
||||
G --> H[更新库元数据]
|
||||
```
|
||||
|
||||
### 2. 规则应用流程
|
||||
```mermaid
|
||||
graph TD
|
||||
A[选择要应用的规则] --> B[创建配置备份]
|
||||
B --> C[检查规则冲突]
|
||||
C --> D{有冲突?}
|
||||
D -->|是| E[显示冲突,询问处理方式]
|
||||
D -->|否| F[合并规则到配置]
|
||||
E --> F
|
||||
F --> G[验证最终配置]
|
||||
G --> H{配置有效?}
|
||||
H -->|是| I[原子性更新配置]
|
||||
H -->|否| J[回滚,显示错误]
|
||||
I --> K[更新应用状态]
|
||||
K --> L[询问是否重启服务]
|
||||
```
|
||||
|
||||
### 3. 规则取消应用流程
|
||||
```mermaid
|
||||
graph TD
|
||||
A[选择要取消的规则] --> B[创建配置备份]
|
||||
B --> C[从配置中移除规则]
|
||||
C --> D[清理相关ACL条目]
|
||||
D --> E[验证配置完整性]
|
||||
E --> F{配置有效?}
|
||||
F -->|是| G[更新配置文件]
|
||||
F -->|否| H[回滚,显示错误]
|
||||
G --> I[更新应用状态]
|
||||
I --> J[询问是否重启服务]
|
||||
```
|
||||
|
||||
## 📋 接口设计规范
|
||||
|
||||
### 1. 规则库接口
|
||||
```bash
|
||||
# 创建规则
|
||||
rule_library_create() {
|
||||
local name="$1" type="$2" config="$3" description="$4"
|
||||
# 返回: rule_id 或错误码
|
||||
}
|
||||
|
||||
# 列出规则
|
||||
rule_library_list() {
|
||||
local filter="$1" # 可选过滤条件
|
||||
# 返回: JSON格式规则列表
|
||||
}
|
||||
|
||||
# 获取规则
|
||||
rule_library_get() {
|
||||
local rule_id="$1"
|
||||
# 返回: JSON格式规则详情
|
||||
}
|
||||
|
||||
# 更新规则
|
||||
rule_library_update() {
|
||||
local rule_id="$1" field="$2" value="$3"
|
||||
# 返回: 成功/失败状态码
|
||||
}
|
||||
|
||||
# 删除规则
|
||||
rule_library_delete() {
|
||||
local rule_id="$1"
|
||||
# 返回: 成功/失败状态码
|
||||
}
|
||||
```
|
||||
|
||||
### 2. 状态管理接口
|
||||
```bash
|
||||
# 应用规则
|
||||
state_apply_rule() {
|
||||
local rule_id="$1"
|
||||
# 返回: 成功/失败状态码
|
||||
}
|
||||
|
||||
# 取消应用
|
||||
state_unapply_rule() {
|
||||
local rule_id="$1"
|
||||
# 返回: 成功/失败状态码
|
||||
}
|
||||
|
||||
# 获取状态
|
||||
state_get_applied() {
|
||||
# 返回: JSON格式已应用规则列表
|
||||
}
|
||||
|
||||
# 同步状态
|
||||
state_sync() {
|
||||
# 返回: 同步结果状态
|
||||
}
|
||||
```
|
||||
|
||||
## 🔄 迁移策略
|
||||
|
||||
### 1. 现有规则提取
|
||||
```bash
|
||||
# 从当前config.yaml提取规则到新架构
|
||||
migrate_existing_rules() {
|
||||
# 1. 解析当前outbound配置
|
||||
# 2. 转换为新规则库格式
|
||||
# 3. 生成应用状态记录
|
||||
# 4. 创建配置备份
|
||||
}
|
||||
```
|
||||
|
||||
### 2. 渐进式迁移
|
||||
```bash
|
||||
Phase 1: 保留现有功能,增加新规则库管理
|
||||
Phase 2: 新规则使用新架构,现有规则兼容
|
||||
Phase 3: 完全迁移到新架构,移除旧代码
|
||||
```
|
||||
|
||||
### 3. 兼容性保证
|
||||
```bash
|
||||
# 检测配置格式版本
|
||||
detect_config_version() {
|
||||
# v1: 直接嵌入式配置
|
||||
# v2: 新架构规则库模式
|
||||
}
|
||||
|
||||
# 自动升级配置格式
|
||||
upgrade_config_format() {
|
||||
# 从v1迁移到v2
|
||||
}
|
||||
```
|
||||
|
||||
## 🎯 性能优化
|
||||
|
||||
### 1. 缓存策略
|
||||
- 规则库内存缓存
|
||||
- 配置文件变更检测
|
||||
- 增量状态同步
|
||||
|
||||
### 2. 批量操作
|
||||
- 批量规则应用/取消
|
||||
- 事务性配置更新
|
||||
- 并行规则验证
|
||||
|
||||
### 3. 错误恢复
|
||||
- 自动配置备份
|
||||
- 原子性操作保证
|
||||
- 状态一致性检查
|
||||
|
||||
## 🔒 安全考虑
|
||||
|
||||
### 1. 权限控制
|
||||
- 规则库文件权限: 600
|
||||
- 配置文件原子更新
|
||||
- 备份文件管理
|
||||
|
||||
### 2. 输入验证
|
||||
- 规则配置格式验证
|
||||
- YAML语法检查
|
||||
- 参数类型检查
|
||||
|
||||
### 3. 操作审计
|
||||
- 规则变更日志
|
||||
- 配置应用记录
|
||||
- 错误操作追踪
|
||||
@@ -0,0 +1,213 @@
|
||||
# Hysteria2 出站规则管理架构改进总结
|
||||
|
||||
## 🎯 问题分析
|
||||
|
||||
您指出的问题完全正确:
|
||||
|
||||
### 原有架构问题
|
||||
- ❌ **直接耦合**: 出站规则直接作用在hy2配置中,无法独立管理
|
||||
- ❌ **无法CRUD**: 缺少系统性的新增、删除、修改操作
|
||||
- ❌ **无状态管理**: 没有应用/取消应用的概念和机制
|
||||
- ❌ **管理复杂**: 用户需要直接操作配置文件,易出错
|
||||
|
||||
## 🏗️ 新架构设计
|
||||
|
||||
### 核心理念:关注点分离
|
||||
```
|
||||
规则存档管理 ↔️ 状态管理 ↔️ 配置应用
|
||||
独立存储 独立追踪 原子更新
|
||||
```
|
||||
|
||||
### 架构组件
|
||||
|
||||
#### 1. 规则库管理器 (`outbound-rules-manager.sh`)
|
||||
**功能**: 独立的规则存档和CRUD操作
|
||||
- 📁 **规则库**: `/etc/hysteria/outbound-rules/rules-library.yaml`
|
||||
- 📊 **状态文件**: `/etc/hysteria/outbound-rules/rules-state.yaml`
|
||||
- 🔧 **CRUD操作**: 完整的规则生命周期管理
|
||||
|
||||
#### 2. 状态管理系统
|
||||
**功能**: 跟踪规则应用状态
|
||||
- 🔍 **状态追踪**: 哪些规则已应用,哪些未应用
|
||||
- 📝 **操作日志**: 同步时间、备份计数
|
||||
- 🔄 **状态同步**: 规则库与配置文件的一致性
|
||||
|
||||
#### 3. 配置应用器
|
||||
**功能**: 原子性的配置文件操作
|
||||
- 🛡️ **原子更新**: 事务性的配置修改
|
||||
- 💾 **自动备份**: 操作前自动创建备份
|
||||
- 🔗 **ACL同步**: 自动维护路由规则一致性
|
||||
|
||||
## 🚀 实现的核心功能
|
||||
|
||||
### 规则库管理 (CRUD)
|
||||
```bash
|
||||
1. 查看所有规则 - 显示规则库中的所有规则及状态
|
||||
2. 添加新规则 - 收集配置并保存到规则库
|
||||
3. 修改规则 - 支持描述和配置参数修改
|
||||
4. 删除规则 - 安全删除并同步配置文件
|
||||
```
|
||||
|
||||
### 应用管理 (Apply/Unapply)
|
||||
```bash
|
||||
5. 查看已应用规则 - 显示当前生效的规则
|
||||
6. 应用规则到配置 - 将规则库中的规则应用到hy2配置
|
||||
7. 取消应用规则 - 从配置文件中移除规则但保留在库中
|
||||
8. 批量管理应用 - 批量操作多个规则
|
||||
```
|
||||
|
||||
### 工具功能
|
||||
```bash
|
||||
9. 导入/导出规则 - 规则的备份和迁移
|
||||
10. 备份/恢复 - 配置文件的版本控制
|
||||
```
|
||||
|
||||
## 📊 数据结构设计
|
||||
|
||||
### 规则库格式 (rules-library.yaml)
|
||||
```yaml
|
||||
rules:
|
||||
china_direct:
|
||||
type: direct
|
||||
description: "中国直连规则"
|
||||
config:
|
||||
mode: auto
|
||||
bindDevice: "eth0"
|
||||
created_at: "2023-01-01T00:00:00Z"
|
||||
updated_at: "2023-01-01T00:00:00Z"
|
||||
|
||||
proxy_socks5:
|
||||
type: socks5
|
||||
description: "海外SOCKS5代理"
|
||||
config:
|
||||
addr: "proxy.example.com:1080"
|
||||
username: "user"
|
||||
password: "pass"
|
||||
created_at: "2023-01-01T00:00:00Z"
|
||||
updated_at: "2023-01-01T00:00:00Z"
|
||||
|
||||
version: "1.0"
|
||||
last_modified: "2023-01-01T00:00:00Z"
|
||||
```
|
||||
|
||||
### 状态管理格式 (rules-state.yaml)
|
||||
```yaml
|
||||
applied_rules:
|
||||
- china_direct
|
||||
- proxy_socks5
|
||||
last_sync: "2023-01-01T00:00:00Z"
|
||||
config_backup_count: 5
|
||||
```
|
||||
|
||||
## 🔄 工作流程
|
||||
|
||||
### 规则创建流程
|
||||
```
|
||||
用户输入 → 参数收集 → 验证配置 → 保存到规则库 → 可选择立即应用
|
||||
```
|
||||
|
||||
### 规则应用流程
|
||||
```
|
||||
选择规则 → 备份配置 → 插入到outbounds → 更新ACL → 更新状态 → 重启服务
|
||||
```
|
||||
|
||||
### 规则取消流程
|
||||
```
|
||||
选择规则 → 备份配置 → 从outbounds移除 → 清理ACL → 更新状态 → 重启服务
|
||||
```
|
||||
|
||||
## 🎨 用户界面改进
|
||||
|
||||
### 新的菜单结构
|
||||
```
|
||||
=== Hysteria2 出站规则管理 ===
|
||||
|
||||
🎯 推荐使用新的规则库管理系统:
|
||||
1. 规则库管理 (推荐) - 独立存档、CRUD操作、状态管理
|
||||
|
||||
🔧 传统直接配置模式:
|
||||
2. 查看当前出站配置
|
||||
3. 添加新的出站规则 (直接写入配置)
|
||||
4. 修改现有配置 (直接修改配置)
|
||||
|
||||
📚 说明:
|
||||
• 规则库管理:支持规则存档、独立管理、应用/取消应用
|
||||
• 传统模式:直接操作配置文件,兼容旧版使用习惯
|
||||
```
|
||||
|
||||
### 规则库管理界面
|
||||
```
|
||||
=== Hysteria2 出站规则库管理 ===
|
||||
|
||||
规则库管理:
|
||||
1. 查看所有规则
|
||||
2. 添加新规则
|
||||
3. 修改规则
|
||||
4. 删除规则
|
||||
|
||||
应用管理:
|
||||
5. 查看已应用规则
|
||||
6. 应用规则到配置
|
||||
7. 取消应用规则
|
||||
8. 批量管理应用
|
||||
|
||||
工具功能:
|
||||
9. 导入/导出规则
|
||||
10. 备份/恢复
|
||||
```
|
||||
|
||||
## ✅ 解决的问题
|
||||
|
||||
| 原有问题 | 新架构解决方案 |
|
||||
|---------|---------------|
|
||||
| ❌ 规则直接耦合在配置中 | ✅ 独立的规则库存储系统 |
|
||||
| ❌ 无法进行CRUD操作 | ✅ 完整的规则生命周期管理 |
|
||||
| ❌ 缺少应用/取消机制 | ✅ 独立的状态管理和应用控制 |
|
||||
| ❌ 管理复杂,用户体验差 | ✅ 直观的用户界面和批量操作 |
|
||||
|
||||
## 🔒 安全特性
|
||||
|
||||
### 数据完整性
|
||||
- 🛡️ **原子操作**: 配置更新的事务性保证
|
||||
- 💾 **自动备份**: 每次修改前自动备份
|
||||
- 🔄 **回滚机制**: 失败时自动恢复
|
||||
|
||||
### 状态一致性
|
||||
- 🔍 **状态同步**: 规则库与配置文件状态一致
|
||||
- 📊 **状态验证**: 自动检测和修复状态不一致
|
||||
- 🔗 **关联管理**: ACL规则与出站规则的联动
|
||||
|
||||
## 🚀 优势总结
|
||||
|
||||
### 用户体验
|
||||
- 🎮 **直观操作**: 图形化界面管理规则
|
||||
- ⚡ **快速操作**: 一键应用/取消规则
|
||||
- 📦 **批量管理**: 多规则同时操作
|
||||
- 🔍 **状态透明**: 清晰的规则状态显示
|
||||
|
||||
### 系统架构
|
||||
- 🏗️ **模块化设计**: 清晰的组件边界
|
||||
- 🔄 **向后兼容**: 保留传统操作模式
|
||||
- 🛡️ **安全可靠**: 原子操作和备份机制
|
||||
- 📈 **可扩展性**: 支持新规则类型和功能
|
||||
|
||||
### 开发维护
|
||||
- 📝 **代码清晰**: 关注点分离,逻辑清楚
|
||||
- 🔧 **易于扩展**: 模块化设计支持功能扩展
|
||||
- 🐛 **易于调试**: 独立组件便于问题定位
|
||||
- 📊 **可观测性**: 完整的状态和日志记录
|
||||
|
||||
## 🎯 使用建议
|
||||
|
||||
### 推荐工作流
|
||||
1. **规则管理**: 使用规则库管理创建和维护规则
|
||||
2. **状态控制**: 通过应用/取消机制控制规则生效
|
||||
3. **批量操作**: 利用批量功能提高操作效率
|
||||
4. **备份管理**: 定期导出规则库进行备份
|
||||
|
||||
### 迁移建议
|
||||
1. **现有用户**: 可继续使用传统模式,逐步迁移到规则库
|
||||
2. **新用户**: 直接使用规则库管理,享受完整功能
|
||||
3. **高级用户**: 结合导入/导出功能进行规则共享
|
||||
|
||||
这个新架构彻底解决了您指出的问题,提供了企业级的出站规则管理解决方案。通过关注点分离和模块化设计,系统变得更加可维护、可扩展且用户友好。
|
||||
@@ -33,11 +33,20 @@ init_outbound_manager() {
|
||||
# 显示出站管理菜单
|
||||
show_outbound_menu() {
|
||||
clear
|
||||
echo -e "${CYAN}=== Hysteria2 出站规则 ===${NC}"
|
||||
echo -e "${CYAN}=== Hysteria2 出站规则管理 ===${NC}"
|
||||
echo ""
|
||||
echo -e "${BLUE}🎯 推荐使用新的规则库管理系统:${NC}"
|
||||
echo -e "${GREEN}1.${NC} 规则库管理 (推荐) - 独立存档、CRUD操作、状态管理"
|
||||
echo ""
|
||||
echo -e "${YELLOW}🔧 传统直接配置模式:${NC}"
|
||||
echo -e "${GREEN}2.${NC} 查看当前出站配置"
|
||||
echo -e "${GREEN}3.${NC} 添加新的出站规则 (直接写入配置)"
|
||||
echo -e "${GREEN}4.${NC} 修改现有配置 (直接修改配置)"
|
||||
echo ""
|
||||
echo -e "${CYAN}📚 说明:${NC}"
|
||||
echo -e " • 规则库管理:支持规则存档、独立管理、应用/取消应用"
|
||||
echo -e " • 传统模式:直接操作配置文件,兼容旧版使用习惯"
|
||||
echo ""
|
||||
echo -e "${GREEN}1.${NC} 查看当前出站配置"
|
||||
echo -e "${GREEN}2.${NC} 添加新的出站规则"
|
||||
echo -e "${GREEN}3.${NC} 修改现有配置"
|
||||
echo -e "${RED}0.${NC} 返回主菜单"
|
||||
echo ""
|
||||
}
|
||||
@@ -1222,12 +1231,22 @@ manage_outbound() {
|
||||
show_outbound_menu
|
||||
|
||||
local choice
|
||||
read -p "请选择操作 [0-3]: " choice
|
||||
read -p "请选择操作 [0-4]: " choice
|
||||
|
||||
case $choice in
|
||||
1) view_current_outbound ;;
|
||||
2) add_outbound_rule ;;
|
||||
3) modify_outbound_config ;;
|
||||
1)
|
||||
# 调用新的规则库管理系统
|
||||
if [[ -f "$SCRIPT_DIR/outbound-rules-manager.sh" ]]; then
|
||||
source "$SCRIPT_DIR/outbound-rules-manager.sh"
|
||||
manage_rules_library
|
||||
else
|
||||
log_error "规则库管理器未找到,请检查安装"
|
||||
wait_for_user
|
||||
fi
|
||||
;;
|
||||
2) view_current_outbound ;;
|
||||
3) add_outbound_rule ;;
|
||||
4) modify_outbound_config ;;
|
||||
0)
|
||||
log_info "返回主菜单"
|
||||
break
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user