feat(脚本): 完善黑名单机制

This commit is contained in:
mack-a
2026-04-13 20:48:55 +08:00
parent d64843bbdd
commit 77a39bd624
2 changed files with 592 additions and 97 deletions
+338 -40
View File
@@ -3309,6 +3309,7 @@ addSingBoxRouteRule() {
domainList="${domainList},$(jq -rc .route.rules[0].rule_set[] "${singBoxConfigPath}${routingName}.json" | awk -F "[_]" '{print $1}' | paste -sd ',')"
domainList="${domainList},$(jq -rc .route.rules[0].domain_regex[] "${singBoxConfigPath}${routingName}.json" | awk -F "[*]" '{print $2}' | paste -sd ',' | sed 's/\\//g')"
fi
fi
local rules=
rules=$(initSingBoxRules "${domainList}" "${routingName}")
@@ -3326,7 +3327,6 @@ addSingBoxRouteRule() {
ruleSetTag=$(echo "${ruleSet}" | jq '.|map(.tag)')
fi
if [[ -n "${singBoxConfigPath}" ]]; then
cat <<EOF >"${singBoxConfigPath}${routingName}.json"
{
"route": {
@@ -6637,8 +6637,10 @@ blacklist() {
echoContent red "\n=============================================================="
echoContent yellow "1.查看已屏蔽域名"
echoContent yellow "2.添加域名"
echoContent yellow "3.屏蔽大陆域名"
echoContent yellow "4.卸载黑名单"
echoContent yellow "3.屏蔽大陆域名+IP"
echoContent yellow "4.卸载黑/白名单"
echoContent yellow "5.添加IP"
echoContent yellow "6.添加域名白名单"
echoContent red "=============================================================="
read -r -p "请选择:" blacklistStatus
@@ -6667,54 +6669,231 @@ blacklist() {
echoContent green " ---> 添加完毕"
elif [[ "${blacklistStatus}" == "3" ]]; then
local allowDomainList="dl.google.com,apple.com,bing.com,microsoft.com,gstatic,xn--ngstr-lra8j.com,googleapis.com,googleapis.cn"
if [[ "${coreInstallType}" == "1" ]]; then
unInstallRouting blackhole_out outboundTag
unInstallRouting blackhole_ip_out outboundTag
addXrayRouting blackhole_out outboundTag "cn"
addXrayIPRouting blackhole_ip_out outboundTag "cn"
addXrayRouting allow_domain_direct_outbound outboundTag "${allowDomainList}" "top"
addXrayOutbound blackhole_out
addXrayOutbound blackhole_ip_out
addXrayOutbound allow_domain_direct_outbound
fi
if [[ -n "${singBoxConfigPath}" ]]; then
addSingBoxRouteRule "cn_block_outbound" "cn" "cn_block_route"
addSingBoxRouteRule "01_direct_outbound" "googleapis.com,googleapis.cn,xn--ngstr-lra8j.com,gstatic.com" "cn_01_google_play_route"
addSingBoxGeoIPRouteRule "block_ip_outbound" "cn" "cn_block_ip_route"
addSingBoxRouteRule "01_direct_outbound" "${allowDomainList}" "00_allow_domain_route"
addSingBoxOutbound "cn_block_outbound"
addSingBoxOutbound "block_ip_outbound"
addSingBoxOutbound "01_direct_outbound"
fi
echoContent green " ---> 屏蔽大陆域名完毕"
echoContent green " ---> 屏蔽大陆域名+IP完毕"
elif [[ "${blacklistStatus}" == "4" ]]; then
if [[ "${coreInstallType}" == "1" ]]; then
unInstallRouting blackhole_out outboundTag
unInstallRouting blackhole_ip_out outboundTag
unInstallRouting allow_domain_direct_outbound outboundTag
removeXrayOutbound blackhole_ip_out
removeXrayOutbound allow_domain_direct_outbound
fi
if [[ -n "${singBoxConfigPath}" ]]; then
removeSingBoxConfig "cn_block_route"
removeSingBoxConfig "cn_block_outbound"
removeSingBoxConfig "cn_block_ip_route"
removeSingBoxConfig "block_ip_route"
removeSingBoxConfig "block_ip_outbound"
removeSingBoxConfig "cn_01_google_play_route"
removeSingBoxConfig "00_allow_domain_route"
removeSingBoxConfig "block_domain_route"
removeSingBoxConfig "block_domain_outbound"
fi
echoContent green " ---> 域名黑名单删除完毕"
echoContent green " ---> 域名黑名单/白名单删除完毕"
elif [[ "${blacklistStatus}" == "5" ]]; then
echoContent red "=============================================================="
echoContent yellow "录入示例:1.1.1.1,8.8.8.8,1.1.1.0/24,2400:3200::/32\n"
read -r -p "请按照上面示例录入IP:" ipList
if [[ -z "${ipList}" ]]; then
echoContent red " ---> IP不可为空"
exit 0
fi
if [[ "${coreInstallType}" == "1" ]]; then
addXrayIPRouting blackhole_ip_out outboundTag "${ipList}"
addXrayOutbound blackhole_ip_out
fi
if [[ -n "${singBoxConfigPath}" ]]; then
addSingBoxIPRouteRule "block_ip_outbound" "${ipList}" "block_ip_route"
addSingBoxOutbound "block_ip_outbound"
fi
echoContent green " ---> 添加IP完毕"
elif [[ "${blacklistStatus}" == "6" ]]; then
echoContent red "=============================================================="
echoContent yellow "录入示例:speedtest,openai,google.com\n"
read -r -p "请按照上面示例录入域名:" allowDomainList
if [[ -z "${allowDomainList}" ]]; then
echoContent red " ---> 域名不可为空"
exit 0
fi
if [[ "${coreInstallType}" == "1" ]]; then
addXrayRouting allow_domain_direct_outbound outboundTag "${allowDomainList}" "top"
addXrayOutbound allow_domain_direct_outbound
fi
if [[ -n "${singBoxConfigPath}" ]]; then
addSingBoxRouteRule "01_direct_outbound" "${allowDomainList}" "00_allow_domain_route"
addSingBoxOutbound "01_direct_outbound"
fi
echoContent green " ---> 添加域名白名单完毕"
else
echoContent red " ---> 选择错误"
exit 0
fi
reloadCore
}
# 下载 dlc.dat_plain.yml 到核心目录
downloadDLCPlainYAML() {
local corePath=$1
local dlcFilePath="${corePath}/dlc.dat_plain.yml"
local tmpFilePath="${dlcFilePath}.tmp"
if [[ -z "${corePath}" ]]; then
return 1
fi
mkdir -p "${corePath}" >/dev/null 2>&1
if [[ -s "${dlcFilePath}" ]]; then
return 0
fi
local dlcDownloadURL="https://github.com/v2fly/domain-list-community/releases/latest/download/dlc.dat_plain.yml"
if [[ "${release}" == "alpine" ]]; then
wget -c -O "${tmpFilePath}" "${dlcDownloadURL}" >/dev/null 2>&1
else
wget -c "${wgetShowProgressStatus}" -O "${tmpFilePath}" "${dlcDownloadURL}" >/dev/null 2>&1
fi
# shellcheck disable=SC2181
if [[ "$?" -ne 0 || ! -s "${tmpFilePath}" ]]; then
rm -f "${tmpFilePath}" >/dev/null 2>&1
return 1
fi
mv "${tmpFilePath}" "${dlcFilePath}" >/dev/null 2>&1
}
# 转义grep/regex匹配字符
escapeDLCRegexPattern() {
# shellcheck disable=SC2016
# shellcheck disable=SC2001
echo "$1" | sed -e 's/[.[\*^$()+?{|]/\\&/g'
}
# 根据规则行号向上回溯对应name
getDLCNameByRuleLine() {
local ruleLine=$1
local dlcFilePath=$2
awk -v targetLine="${ruleLine}" '
/^[[:space:]]*-[[:space:]]*name:[[:space:]]*/ {
line = $0
sub(/^[[:space:]]*-[[:space:]]*name:[[:space:]]*/, "", line)
currentName = line
}
NR == targetLine {
print currentName
exit
}' "${dlcFilePath}"
}
isDomainFormat() {
local target=$1
[[ "${target}" =~ ^([a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z0-9-]{2,63}$ ]]
}
# 根据输入域名匹配 dlc.dat_plain.yml 对应 geosite name
getDLCGeositeName() {
local inputRule=$1
local corePath=$2
local dlcFilePath="${corePath}/dlc.dat_plain.yml"
if [[ -z "${inputRule}" || -z "${corePath}" ]]; then
echo ""
return
fi
local normalizedInput
normalizedInput=$(echo "${inputRule}" | tr '[:upper:]' '[:lower:]' | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
normalizedInput=${normalizedInput#domain:}
normalizedInput=${normalizedInput#full:}
normalizedInput=${normalizedInput#keyword:}
if [[ -z "${normalizedInput}" ]]; then
echo ""
return
fi
if isDomainFormat "${normalizedInput}"; then
return
fi
if ! downloadDLCPlainYAML "${corePath}"; then
echo ""
return
fi
local escapedInput=
escapedInput=$(escapeDLCRegexPattern "${normalizedInput}")
local matchedLine=
matchedLine=$(grep -n -m1 -E "^[[:space:]]*-[[:space:]]*name:[[:space:]]*${escapedInput}[[:space:]]*$" "${dlcFilePath}")
if [[ -n "${matchedLine}" ]]; then
echo "${normalizedInput}"
fi
}
# 获取规则匹配结果,优先geosite,失败回退domain
getDLCMatchedRuleValue() {
local inputRule=$1
local corePath=$2
local normalizedInput=
normalizedInput=$(echo "${inputRule}" | tr '[:upper:]' '[:lower:]' | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
if isDomainFormat "${normalizedInput}"; then
local escapedDomain=
escapedDomain=$(escapeDLCRegexPattern "${normalizedInput}")
echo "regexp:.*${escapedDomain}.*"
return
fi
local matchedRuleName=
matchedRuleName=$(getDLCGeositeName "${normalizedInput}" "${corePath}")
if [[ -n "${matchedRuleName}" ]]; then
echo "geosite:${matchedRuleName}"
else
echo "domain:${normalizedInput}"
fi
}
# 添加routing配置
addXrayRouting() {
local tag=$1 # warp-socks
local type=$2 # outboundTag/inboundTag
local domain=$3 # 域名
local rulePosition=$4
if [[ -z "${tag}" || -z "${type}" || -z "${domain}" ]]; then
echoContent red " ---> 参数错误"
@@ -6750,27 +6929,146 @@ EOF
if echo "${routingRule}" | grep -q "${line}"; then
echoContent yellow " ---> ${line}已存在,跳过"
else
local geositeStatus
geositeStatus=$(curl -s "https://api.github.com/repos/v2fly/domain-list-community/contents/data/${line}" | jq .message)
if [[ "${geositeStatus}" == "null" ]]; then
routingRule=$(echo "${routingRule}" | jq -r '.domain += ["geosite:'"${line}"'"]')
else
routingRule=$(echo "${routingRule}" | jq -r '.domain += ["domain:'"${line}"'"]')
fi
local matchedRuleValue
matchedRuleValue=$(getDLCMatchedRuleValue "${line}" "/etc/v2ray-agent/xray")
routingRule=$(echo "${routingRule}" | jq -r --arg rule "${matchedRuleValue}" '.domain += [$rule]')
fi
done < <(echo "${domain}" | tr ',' '\n')
unInstallRouting "${tag}" "${type}"
if ! grep -q "gstatic.com" ${configPath}09_routing.json && [[ "${tag}" == "blackhole_out" ]]; then
local routing=
routing=$(jq -r ".routing.rules += [{\"type\": \"field\",\"domain\": [\"gstatic.com\"],\"outboundTag\": \"direct\"}]" ${configPath}09_routing.json)
routing=$(jq -r ".routing.rules += [{\"type\": \"field\",\"domain\": [\"domain:gstatic.com\"],\"outboundTag\": \"allow_domain_direct_outbound\"}]" ${configPath}09_routing.json)
echo "${routing}" | jq . >${configPath}09_routing.json
addXrayOutbound allow_domain_direct_outbound
fi
if [[ "${rulePosition}" == "top" ]]; then
routing=$(jq -r ".routing.rules = [${routingRule}] + .routing.rules" ${configPath}09_routing.json)
else
routing=$(jq -r ".routing.rules += [${routingRule}]" ${configPath}09_routing.json)
fi
echo "${routing}" | jq . >${configPath}09_routing.json
}
# 添加 Xray IP 屏蔽路由规则
# 支持 geoip:cn 与自定义 IPv4/IPv6/CIDR
addXrayIPRouting() {
local tag=$1
local type=$2
local ipList=$3
if [[ -z "${tag}" || -z "${type}" || -z "${ipList}" ]]; then
echoContent red " ---> 参数错误"
exit 0
fi
if [[ ! -f "${configPath}09_routing.json" ]]; then
cat <<EOF >${configPath}09_routing.json
{
"routing":{
"type": "field",
"rules": []
}
}
EOF
fi
local routingRule=
routingRule=$(jq -r ".routing.rules[]|select(.outboundTag==\"${tag}\" and (.protocol == null) and (.ip != null))" ${configPath}09_routing.json)
if [[ -z "${routingRule}" ]]; then
routingRule="{\"type\": \"field\",\"ip\": [],\"outboundTag\": \"${tag}\"}"
fi
while read -r line; do
line=$(echo "${line}" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
if [[ -z "${line}" ]]; then
continue
fi
local ipRuleValue=${line}
if [[ "${line}" == "cn" ]]; then
ipRuleValue="geoip:cn"
fi
if echo "${routingRule}" | grep -q "${ipRuleValue}"; then
echoContent yellow " ---> ${ipRuleValue}已存在,跳过"
else
routingRule=$(echo "${routingRule}" | jq -r '.ip += ["'"${ipRuleValue}"'"]')
fi
done < <(echo "${ipList}" | tr ',' '\n')
unInstallRouting "${tag}" "${type}"
local routing=
routing=$(jq -r ".routing.rules += [${routingRule}]" ${configPath}09_routing.json)
echo "${routing}" | jq . >${configPath}09_routing.json
}
# 添加 sing-box IP 屏蔽路由规则
# 支持增量合并历史 ip_cidr
addSingBoxIPRouteRule() {
local outboundTag=$1
local ipList=$2
local routingName=$3
local historyIPs=
if [[ -f "${singBoxConfigPath}${routingName}.json" ]]; then
historyIPs=$(jq -r '.route.rules[0].ip_cidr[]?' "${singBoxConfigPath}${routingName}.json" | paste -sd ',')
fi
if [[ -n "${historyIPs}" ]]; then
ipList="${ipList},${historyIPs}"
fi
local ipCIDR=[]
ipCIDR=$(echo "${ipList}" | tr ',' '\n' | sed 's/^[[:space:]]*//;s/[[:space:]]*$//' | grep -v '^$' | sort -n | uniq | jq -R . | jq -s .)
cat <<EOF >"${singBoxConfigPath}${routingName}.json"
{
"route": {
"rules": [
{
"ip_cidr": ${ipCIDR},
"outbound": "${outboundTag}"
}
]
}
}
EOF
}
# 添加 sing-box GeoIP 远程规则
# 用于大陆 IP 自动屏蔽场景
addSingBoxGeoIPRouteRule() {
local outboundTag=$1
local geoipCode=$2
local routingName=$3
cat <<EOF >"${singBoxConfigPath}${routingName}.json"
{
"route": {
"rules": [
{
"rule_set": [
"geoip_${geoipCode}_${routingName}"
],
"outbound": "${outboundTag}"
}
],
"rule_set": [
{
"tag": "geoip_${geoipCode}_${routingName}",
"type": "remote",
"format": "binary",
"url": "https://raw.githubusercontent.com/SagerNet/sing-geoip/rule-set/geoip-${geoipCode}.srs",
"download_detour": "01_direct_outbound"
}
]
}
}
EOF
}
# 根据tag卸载Routing
unInstallRouting() {
local tag=$1
@@ -7446,13 +7744,21 @@ initSingBoxRules() {
local domainRules=[]
local ruleSet=[]
while read -r line; do
local geositeStatus
geositeStatus=$(curl -s "https://api.github.com/repos/SagerNet/sing-geosite/contents/geosite-${line}.srs?ref=rule-set" | jq .message)
if [[ "${geositeStatus}" == "null" ]]; then
ruleSet=$(echo "${ruleSet}" | jq -r ". += [{\"tag\":\"${line}_$2\",\"type\":\"remote\",\"format\":\"binary\",\"url\":\"https://raw.githubusercontent.com/SagerNet/sing-geosite/rule-set/geosite-${line}.srs\",\"download_detour\":\"01_direct_outbound\"}]")
local normalizedLine=
normalizedLine=$(echo "${line}" | tr '[:upper:]' '[:lower:]' | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
if isDomainFormat "${normalizedLine}"; then
local escapedDomain=
escapedDomain=${normalizedLine//./\\.}
domainRules=$(echo "${domainRules}" | jq -r --arg reg ".*${escapedDomain}.*" '. += [$reg]')
else
domainRules=$(echo "${domainRules}" | jq -r ". += [\"^([a-zA-Z0-9_-]+\\\.)*${line//./\\\\.}\"]")
local matchedRuleName
matchedRuleName=$(getDLCGeositeName "${normalizedLine}" "/etc/v2ray-agent/sing-box")
if [[ -n "${matchedRuleName}" ]]; then
ruleSet=$(echo "${ruleSet}" | jq -r ". += [{\"tag\":\"${matchedRuleName}_$2\",\"type\":\"remote\",\"format\":\"binary\",\"url\":\"https://raw.githubusercontent.com/SagerNet/sing-geosite/rule-set/geosite-${matchedRuleName}.srs\",\"download_detour\":\"01_direct_outbound\"}]")
else
domainRules=$(echo "${domainRules}" | jq -r --arg reg "^([a-zA-Z0-9_-]+\\.)*${normalizedLine//./\\.}" '. += [$reg]')
fi
fi
done < <(echo "$1" | tr ',' '\n' | grep -v '^$' | sort -n | uniq | paste -sd ',' | tr ',' '\n')
echo "{ \"domainRules\":${domainRules},\"ruleSet\":${ruleSet}}"
@@ -7635,14 +7941,9 @@ setSocks5OutboundRouting() {
if echo "${routingRule}" | grep -q "${line}"; then
echoContent yellow " ---> ${line}已存在,跳过"
else
local geositeStatus
geositeStatus=$(curl -s "https://api.github.com/repos/v2fly/domain-list-community/contents/data/${line}" | jq .message)
if [[ "${geositeStatus}" == "null" ]]; then
domainRules=$(echo "${domainRules}" | jq -r ". += [\"geosite:${line}\"]")
else
domainRules=$(echo "${domainRules}" | jq -r ". += [\"domain:${line}\"]")
fi
local matchedRuleValue
matchedRuleValue=$(getDLCMatchedRuleValue "${line}" "/etc/v2ray-agent/xray")
domainRules=$(echo "${domainRules}" | jq -r --arg rule "${matchedRuleValue}" '. += [$rule]')
fi
done < <(echo "${socks5RoutingOutboundDomain}" | tr ',' '\n')
if [[ ! -f "${configPath}09_routing.json" ]]; then
@@ -7793,7 +8094,9 @@ setUnlockSNI() {
read -r -p "请按照上面示例录入域名:" xrayDomainList
local hosts={}
while read -r domain; do
hosts=$(echo "${hosts}" | jq -r ".\"geosite:${domain}\"=\"${setSNIP}\"")
local matchedRuleValue
matchedRuleValue=$(getDLCMatchedRuleValue "${domain}" "/etc/v2ray-agent/xray")
hosts=$(echo "${hosts}" | jq -r --arg key "${matchedRuleValue}" --arg value "${setSNIP}" '. + {($key):$value}')
done < <(echo "${xrayDomainList}" | tr ',' '\n')
cat <<EOF >${configPath}11_dns.json
{
@@ -7826,14 +8129,9 @@ addXrayDNSConfig() {
local domainList=$2
local domains=[]
while read -r line; do
local geositeStatus
geositeStatus=$(curl -s "https://api.github.com/repos/v2fly/domain-list-community/contents/data/${line}" | jq .message)
if [[ "${geositeStatus}" == "null" ]]; then
domains=$(echo "${domains}" | jq -r '. += ["geosite:'"${line}"'"]')
else
domains=$(echo "${domains}" | jq -r '. += ["domain:'"${line}"'"]')
fi
local matchedRuleValue
matchedRuleValue=$(getDLCMatchedRuleValue "${line}" "/etc/v2ray-agent/xray")
domains=$(echo "${domains}" | jq -r --arg rule "${matchedRuleValue}" '. += [$rule]')
done < <(echo "${domainList}" | tr ',' '\n')
if [[ "${coreInstallType}" == "1" ]]; then
@@ -9649,7 +9947,7 @@ menu() {
cd "$HOME" || exit
echoContent red "\n=============================================================="
echoContent green "作者:mack-a"
echoContent green "当前版本:v3.5.12"
echoContent green "当前版本:v3.5.13"
echoContent green "Githubhttps://github.com/mack-a/v2ray-agent"
echoContent green "描述:八合一共存脚本\c"
showInstallStatus