#!/bin/sh # =================配置区域================= # 你的配置文件名 (例如 openclash, passwall 等) CONFIG_PACKAGE="hijpass" # ========================================= LUA_SCRIPT="/usr/lib/hijpass/luci-utils.lua" GEOVIEW_SCRIPT="/usr/lib/hijpass/geoview.sh" . /lib/functions.sh INPUT=$1 GEOSITE_TAGS= GEOIP_TAGS= if [ -z "$INPUT" ]; then echo "用法: $0 <域名 或 IP>" exit 1 fi if ! echo "$INPUT" | grep -Eq "^[A-Za-z0-9._:/-]{1,255}$" >/dev/null 2>&1; then echo "非法输入: $INPUT" >&2 exit 1 fi # ========================================= # 函数 1: IP/CIDR 匹配检查 # 参数 1: 目标 IP (例如 192.168.1.5) # 参数 2: 规则 IP 或 CIDR (例如 192.168.1.0/24) # 返回: 0(命中), 1(未命中) # ========================================= check_ip_cidr_match() { local target_ip="$1" local rule_cidr="$2" lua $LUA_SCRIPT ipmatch "$target_ip" "$rule_cidr" >/dev/null 2>&1 return $? } # ========================================= # 函数 2: 复杂域名匹配检查 (核心更新) # 支持: 纯字符串, regexp:, domain:, full: # ========================================= check_domain_complex_match() { local target="$1" local rule="$2" # 1. 处理 "full:" (完整匹配) # 语法: full:www.google.com if echo "$rule" | grep -q "^full:"; then local content="${rule#full:}" if [ "$target" = "$content" ]; then return 0 fi return 1 fi # 2. 处理 "domain:" (域名及子域名匹配) # 语法: domain:google.com (匹配 google.com 和 mail.google.com) if echo "$rule" | grep -q "^domain:"; then local content="${rule#domain:}" # 情况A: 完全相等 if [ "$target" = "$content" ]; then return 0 fi # 情况B: 是子域名 (即 target 以 .content 结尾) # 使用 case 语句进行后缀匹配,效率高且兼容性好 case "$target" in *."$content") return 0 ;; esac return 1 fi # 3. 处理 "regexp:" (正则表达式) # 语法: regexp:^www\. if echo "$rule" | grep -q "^regexp:"; then local content="${rule#regexp:}" # 使用 grep -E 进行扩展正则匹配,-i 忽略大小写 if echo "$target" | grep -E -i -q -e "$content"; then return 0 fi return 1 fi # 4. 处理 "纯字符串" (关键字匹配) # 语法: baidu (匹配 www.baidu.com, baidu.net) # 只要 target 包含 rule 字符串即算命中 if echo "$target" | grep -F -i -q -e "$rule"; then return 0 fi return 1 } # ========================================= # 函数 3: GeoSite/GeoIP 标签检查 (抽象层) # 参数 1: 规则行内容 (例如 geosite:google) # 返回: 1 (始终不命中,仅做日志提示) # 说明: Shell 无法解析 dat 文件,此函数仅用于识别标签类型 # ========================================= check_geo_label_match() { local tags="$1" [ -z "$tags" ] && return 1 [ "$tags" = "notfound" ] && return 1 local rule_line="$2" local type="$3" for tag in $tags; do if [ "$type:$tag" = "$rule_line" ]; then return 0 fi done return 1 } # ========================================= # 主逻辑 # ========================================= # 1. 识别输入类型 if lua $LUA_SCRIPT iptype "$INPUT" >/dev/null 2>&1; then IS_IP=1 TYPE="IP" # echo "正在检测 IP: $INPUT ..." else IS_IP=0 TYPE="域名" # echo "正在检测域名: $INPUT ..." fi MATCHED_RULE="" # UCI 遍历回调函数 handle_rule() { local config="$1" local name local enabled local domain_list local ip_list local proxy_node config_get name "$config" name "Unnamed" config_get enabled "$config" enabled "0" config_get proxy_node "$config" proxy_node "default" [ "$enabled" != "1" ] && return 0 # === 检查 IP 列表 === if [ "$IS_IP" -eq 1 ]; then config_get ip_list "$config" ip_list if [ -n "$ip_list" ]; then [ -z "$GEOIP_TAGS" ] && { if echo "$ip_list" | grep -v '^[[:space:]]*#' | grep -E -q 'geoip:'; then GEOIP_TAGS="$($GEOVIEW_SCRIPT -l "geoip" "$INPUT")" [ -z "$GEOIP_TAGS" ] && GEOIP_TAGS="notfound" fi } while IFS= read -r line; do # 清理注释和空格 clean_line=$(echo "$line" | sed 's/#.*//' | sed 's/^[ \t]*//;s/[ \t]*$//') [ -z "$clean_line" ] && continue if echo "$clean_line" | grep -vq "geoip:"; then # 调用 IP 检查函数 if check_ip_cidr_match "$INPUT" "$clean_line"; then print_result "$name" "$clean_line" "$proxy_node" "$config" exit 0 fi elif echo "$clean_line" | grep -E -q '^rule-set:'; then continue else if check_geo_label_match "$GEOIP_TAGS" "$clean_line" "geoip"; then print_result "$name" "$clean_line" "$proxy_node" "$config" exit 0 fi fi done </dev/null; then if check_domain_complex_match "$INPUT" "$clean_line"; then print_result "$name" "$clean_line" "$proxy_node" "$config" exit 0 fi elif echo "$clean_line" | grep -E -q '^rule-set:'; then continue else if check_geo_label_match "$GEOSITE_TAGS" "$clean_line" "geosite"; then print_result "$name" "$clean_line" "$proxy_node" "$config" exit 0 fi fi done <