🛸 Sync 2026-10-29 02:04:12

This commit is contained in:
github-actions[bot] committed 2026-10-29 02:04:12 +08:00
1 parent b21929fceb
commit bfd56813e0
37 files changed
+3918 -4346

No files matched your search

+2 -2
View File
@@ -1,8 +1,8 @@
include $(TOPDIR)/rules.mk include $(TOPDIR)/rules.mk
PKG_NAME:=isp-split PKG_NAME:=isp-split
PKG_VERSION:=0.2.1 PKG_VERSION:=0.2.2
PKG_RELEASE:=2 PKG_RELEASE:=3
PKG_LICENSE:=MIT PKG_LICENSE:=MIT
PKG_LICENSE_FILES:=LICENSE PKG_LICENSE_FILES:=LICENSE
PKG_MAINTAINER:=jihebube <jihebube@users.noreply.github.com> PKG_MAINTAINER:=jihebube <jihebube@users.noreply.github.com>
+186 -23
View File
@@ -15,7 +15,14 @@
# install 注册开机自启与每日更新 # install 注册开机自启与每日更新
# uninstall 卸载所有改动 # uninstall 卸载所有改动
set -u set -u
ISP_VERSION="0.2.1-logo" ISP_VERSION="0.2.2"
# 配置表里的注释行(# 开头,允许前导空白)必须在按空白展开之前整行删掉
# (B-1)。否则 `for row in $ISP_TABLE` 会把 "#" 与后面的文字拆成两个
# token,注释片段被当成数据行。只改内存,不写回配置文件。
_strip_comments() {
printf '%s\n' "$1" | sed 's/^[[:space:]]*#.*$//' | sed '/^[[:space:]]*$/d'
}
CONF=${ISP_SPLIT_CONF:-/etc/isp-split.conf} CONF=${ISP_SPLIT_CONF:-/etc/isp-split.conf}
BASE=${ISP_SPLIT_BASE:-/etc/isp-split} BASE=${ISP_SPLIT_BASE:-/etc/isp-split}
@@ -47,9 +54,10 @@ DNSMASQ_SERVICE=${DNSMASQ_SERVICE:-/etc/init.d/dnsmasq}
# 但 ISP_TABLE 的最后一列会变成 "1\r",`[ "$4" = "1" ]` 永远不成立: # 但 ISP_TABLE 的最后一列会变成 "1\r",`[ "$4" = "1" ]` 永远不成立:
# plan 只剩一张空表、status 只剩兜底行、apply 报"没有启用的运营商", # plan 只剩一张空表、status 只剩兜底行、apply 报"没有启用的运营商",
# 而真正的原因(行尾多了一个 \r)完全看不出来。这里在入口统一去掉。 # 而真正的原因(行尾多了一个 \r)完全看不出来。这里在入口统一去掉。
ISP_TABLE=$(printf '%s' "${ISP_TABLE:-}" | tr -d '\r') # 注释行也在同一处删掉(B-1):删除必须发生在任何按空白展开之前。
DNS_TABLE=$(printf '%s' "${DNS_TABLE:-}" | tr -d '\r') ISP_TABLE=$(_strip_comments "$(printf '%s' "${ISP_TABLE:-}" | tr -d '\r')")
DOMAIN_SPLIT=$(printf '%s' "${DOMAIN_SPLIT:-}" | tr -d '\r') DNS_TABLE=$(_strip_comments "$(printf '%s' "${DNS_TABLE:-}" | tr -d '\r')")
DOMAIN_SPLIT=$(_strip_comments "$(printf '%s' "${DOMAIN_SPLIT:-}" | tr -d '\r')")
# ---- 多数据源(0.2.1 默认双源)---- # ---- 多数据源(0.2.1 默认双源)----
# ISP_SOURCES 为空 = 单源兼容模式:仍按 ISP_MIRROR/<源名>.txt 拉取, # ISP_SOURCES 为空 = 单源兼容模式:仍按 ISP_MIRROR/<源名>.txt 拉取,
@@ -1453,7 +1461,7 @@ cmd_apply() {
# 取第一个 enabled=1 的行,而不是无条件取第一行:用户禁用第一个 # 取第一个 enabled=1 的行,而不是无条件取第一行:用户禁用第一个
# 运营商后,wire 不会为它建集合,旧写法会让每日 refresh 永久失败。 # 运营商后,wire 不会为它建集合,旧写法会让每日 refresh 永久失败。
_fs="" _fs=""
for _row in $(_conf_val ISP_TABLE 2>/dev/null); do for _row in $(_conf_table ISP_TABLE 2>/dev/null); do
_old_ifs=$IFS _old_ifs=$IFS
IFS=':' IFS=':'
set -- $_row set -- $_row
@@ -1596,6 +1604,112 @@ _write_rule() {
} >> "$WORK/rules.txt" } >> "$WORK/rules.txt"
} }
# ---- 孤儿 ipset 段收敛(B-4)----
# 段名可以改名/删除/禁用,但 mwan3 的 config ipset 段不会自己消失:
# 旧段仍然 enabled=1、loadfile 指向旧数据文件,mwan3 下次 reload 照样
# 建集合、灌元素,永久驻留。旧版 uninstall 也只看"当前表里的名字",
# 连卸载都清不掉。
#
# 识别方式只有一个:isp_split=1 标记(_wire_ipset 写入)。绝不按 isp_
# 前缀猜 —— 用户自己的 mwan3 ipset 段可能也叫 isp_xxx。没有标记的段
# (0.2.1-happy 之前的旧版本写的)一律不动,只在日志里列出来。
#
# 当前仍有效的集合名:ISP_TABLE 里第 4 列=1 的行。DNS_TABLE 不引用
# ipset,但把它的字段也纳入保护集合,避免同名段被误删(保守兜底)。
_keep_set_names() {
_ks=" "
for _row in $ISP_TABLE; do
[ -n "$_row" ] || continue
_old_ifs=$IFS
IFS=':'
set -- $_row
IFS=$_old_ifs
[ $# -ge 4 ] || continue
[ "$4" = "1" ] || continue
_ks="$_ks$2 "
done
for _row in ${DNS_TABLE:-}; do
[ -n "$_row" ] || continue
_old_ifs=$IFS
IFS=':'
set -- $_row
IFS=$_old_ifs
for _f in "$@"; do
case "$_f" in "" | *[!A-Za-z0-9_]*) continue ;; esac
_ks="$_ks$_f "
done
done
printf '%s\n' "$_ks"
}
# 所有 config rule 引用的 ipset 名(空格分隔,带前后空格便于整词匹配)
_rule_ipset_refs() {
_ri=" "
for _ri_sec in $(uci -q show mwan3 2>/dev/null |
sed -n 's/^mwan3\.\([^=]*\)=rule$/\1/p'); do
_ri_v=$(uci -q get "mwan3.$_ri_sec.ipset" 2>/dev/null) || continue
for _ri_x in $_ri_v; do
case "$_ri_x" in "" | *[!A-Za-z0-9_]*) continue ;; esac
_ri="$_ri$_ri_x "
done
done
printf '%s\n' "$_ri"
}
_prune_orphan_ipsets() {
[ -f "$CFG_MWAN3" ] || return 0
_po_keep=$(_keep_set_names)
_po_refs=$(_rule_ipset_refs)
_po_changed=0
for _po_sec in $(uci -q show mwan3 2>/dev/null |
sed -n 's/^mwan3\.\([^=]*\)=ipset$/\1/p'); do
_po_name=$(uci -q get "mwan3.$_po_sec.name" 2>/dev/null) || continue
[ -n "$_po_name" ] || continue
# 仍被当前启用的行引用:保留
case "$_po_keep" in *" $_po_name "*) continue ;; esac
# 没有标记的段不是本工具写的(或旧版本写的):绝不删
if [ "$(uci -q get "mwan3.$_po_sec.isp_split" 2>/dev/null)" != "1" ]; then
case "$_po_name" in
isp_*)
log "提示:ipset 段 $_po_sec($_po_name)没有 isp_split 标记,保留不动(旧版本或用户自建)"
;;
esac
continue
fi
# 仍被任何 mwan3 规则引用:删了会让 mwan3 渲染失败,只告警
case "$_po_refs" in
*" $_po_name "*)
log "警告:孤儿 ipset 段 $_po_sec($_po_name)仍被 mwan3 规则引用,保留"
continue
;;
esac
if uci -q delete "mwan3.$_po_sec" 2>/dev/null; then
log "已清理孤儿 ipset 段 $_po_sec($_po_name)"
_po_changed=1
else
log "警告:清理 ipset 段 $_po_sec 失败,保留"
fi
done
[ "$_po_changed" = "1" ] && uci -q commit mwan3 2>/dev/null
return 0
}
# 卸载:按 isp_split=1 标记删除所有本工具的 ipset 段。
# 不能按"当前 ISP_TABLE 的名字"删:改名/删除的旧段会漏掉,永远清不掉。
# 无标记的段一律不碰。
_uninstall_ipsets() {
_ui_n=0
for _ui_sec in $(uci -q show mwan3 2>/dev/null |
sed -n 's/^mwan3\.\([^=]*\)=ipset$/\1/p'); do
[ "$(uci -q get "mwan3.$_ui_sec.isp_split" 2>/dev/null)" = "1" ] || continue
uci -q delete "mwan3.$_ui_sec" 2>/dev/null && _ui_n=$((_ui_n + 1))
done
uci -q commit mwan3 2>/dev/null
[ "$_ui_n" -gt 0 ] &&
log "已删除 $_ui_n 个带 isp_split 标记的 ipset 段(含改名/删除的孤儿段)"
return 0
}
cmd_wire() { cmd_wire() {
_openclash_fakeip_warn _openclash_fakeip_warn
need_nft need_nft
@@ -1651,6 +1765,9 @@ cmd_wire() {
cat "$WORK/mwan3.new" > "$CFG_MWAN3" cat "$WORK/mwan3.new" > "$CFG_MWAN3"
log "规则已注入(备份: $WORK/mwan3.bak)" log "规则已注入(备份: $WORK/mwan3.bak)"
# 5. 收敛孤儿 ipset 段:必须放在规则块重写之后 —— 改名时旧规则
# 这一刻才消失;若在注入前做,旧规则仍引用旧段,会被误判成"保留"。
_prune_orphan_ipsets
/etc/init.d/mwan3 reload /etc/init.d/mwan3 reload
_fallback_counter || _fallback_counter ||
log "警告:兜底计数规则未安装成功(status 的兜底行会缺失或为旧值),可稍后重跑 isp-split apply" log "警告:兜底计数规则未安装成功(status 的兜底行会缺失或为旧值),可稍后重跑 isp-split apply"
@@ -1748,8 +1865,9 @@ cmd_verify() {
echo "⚠ DNS 旁路规则缺失(mwan3 重启会清掉运行时插入的规则)" echo "⚠ DNS 旁路规则缺失(mwan3 重启会清掉运行时插入的规则)"
echo " 恢复:isp-split dns (或 isp-split wire)" echo " 恢复:isp-split dns (或 isp-split wire)"
fi fi
if [ "$(nft list chain inet mwan3 mwan3_rules 2>/dev/null | grep -c "counter name")" -eq 0 ] && # 兜底计数器由 COUNT_FALLBACK 控制,与 DNS_TABLE 无关(B-2)。
[ -n "${DNS_TABLE:-}" ]; then if [ "${COUNT_FALLBACK:-1}" = "1" ] &&
[ "$(nft list chain inet mwan3 mwan3_rules 2>/dev/null | grep -c "counter name")" -eq 0 ]; then
echo "⚠ 兜底计数规则缺失(同上)" echo "⚠ 兜底计数规则缺失(同上)"
echo " 恢复:isp-split apply" echo " 恢复:isp-split apply"
fi fi
@@ -1761,6 +1879,23 @@ cmd_verify() {
# ---------------------------------------------------------------- plan (dry-run) # ---------------------------------------------------------------- plan (dry-run)
# dnsmasq 是否编译了 nftset(域名→nftset 钉线的前置条件,F-5)。
# 返回:0=支持,1=不支持,2=没有 dnsmasq。
# OpenWrt 基础版 dnsmasq 的编译选项是 no-ipset no-nftset,必须装
# dnsmasq-full 才有。这里只检测并提示,不阻断、不改变任何行为。
_dnsmasq_nftset() {
command -v dnsmasq >/dev/null 2>&1 || return 2
_dn_opts=$(dnsmasq --version 2>/dev/null |
sed -n 's/^Compile time options:[[:space:]]*//p' | head -1)
# 没有 Compile time options 行的老版本无法证明支持,按不支持处理
[ -n "$_dn_opts" ] || return 1
case " $_dn_opts " in
*" no-nftset "*) return 1 ;;
*" nftset "* | *" +nftset "*) return 0 ;;
esac
return 1
}
# 只读预演:不写任何文件、不发任何 uci/nft 改动。 # 只读预演:不写任何文件、不发任何 uci/nft 改动。
cmd_plan() { cmd_plan() {
_openclash_fakeip_warn _openclash_fakeip_warn
@@ -1813,7 +1948,7 @@ cmd_plan() {
done done
[ "$_dp_any" = "1" ] || echo " (无)" [ "$_dp_any" = "1" ] || echo " (无)"
echo " 说明: 未启用项不会被 apply 写入;残留的 nft 规则会在下次 wire 重写规则块时移除," echo " 说明: 未启用项不会被 apply 写入;残留的 nft 规则会在下次 wire 重写规则块时移除,"
echo " mwan3 ipset 配置段与对应 nft 集合会在 uninstall 时清理。" echo " mwan3 ipset 配置段(带 isp_split=1 标记)会在下次 wire 与 uninstall 时清理。"
echo echo
echo "dnsmasq confdir(多线路 DNS 片段写入位置):" echo "dnsmasq confdir(多线路 DNS 片段写入位置):"
@@ -1853,6 +1988,24 @@ cmd_plan() {
;; ;;
esac esac
echo
echo "dnsmasq nftset 能力(域名钉线的前置条件;本版本只检测,不启用钉线):"
_dnsmasq_nftset
_nf=$?
case "$_nf" in
0)
echo " ✓ 支持 nftset(dnsmasq 编译选项含 nftset)"
;;
1)
echo " ⚠ 不支持 nftset(dnsmasq 编译选项为 no-nftset 或缺少该选项)"
echo " 域名钉线不可用;多线路 DNS 的 server=/域名/IP@接口 不受影响。"
echo " 需要域名→nftset 时请安装 dnsmasq-full。"
;;
*)
echo " ⚠ 未找到 dnsmasq,无法检测 nftset 能力"
;;
esac
echo echo
echo "将会写入的 nft 集合声明(每个启用的运营商一个):" echo "将会写入的 nft 集合声明(每个启用的运营商一个):"
_p3() { _p3() {
@@ -2173,8 +2326,10 @@ cmd_status() {
grep -oE "packets [0-9]+ bytes [0-9]+" | head -1) grep -oE "packets [0-9]+ bytes [0-9]+" | head -1)
_fp=$(echo "$_fb" | awk '{print $2}') _fp=$(echo "$_fb" | awk '{print $2}')
_fb_b=$(echo "$_fb" | awk '{print $4}') _fb_b=$(echo "$_fb" | awk '{print $4}')
# 与其余行走同一个 _human 换算,否则这一列是裸字节数、
# 既不对齐也没有单位(B-3)。--json 里的 bytes 保持纯数字。
printf '%-14s %-10s %10s %12s %10s %s\n' \ printf '%-14s %-10s %10s %12s %10s %s\n' \
"兜底" "-" "-" "${_fp:-0}" "${_fb_b:-0}" "未命中集合" "兜底" "-" "-" "${_fp:-0}" "$(_human "${_fb_b:-0}")" "未命中集合"
fi fi
echo echo
echo "注: 命中包/流量为连接首包统计(ct state new;后续包由 conntrack 恢复标记,不再经过规则链)。" echo "注: 命中包/流量为连接首包统计(ct state new;后续包由 conntrack 恢复标记,不再经过规则链)。"
@@ -3035,6 +3190,12 @@ _conf_val() {
' "${2:-$CONF}" ' "${2:-$CONF}"
} }
# 取配置表的值并删掉注释行。conf_get / apply 直接读文件,不能只依赖入口
# 那次清理(B-1)。必须先整行删注释、再按空白展开,顺序不能反。
_conf_table() {
_strip_comments "$(_conf_val "$1")"
}
conf_get() { conf_get() {
[ -f "$CONF" ] || die "找不到 $CONF" [ -f "$CONF" ] || die "找不到 $CONF"
printf 'dns_mode\t%s\n' "$(_conf_val DNS_MODE)" printf 'dns_mode\t%s\n' "$(_conf_val DNS_MODE)"
@@ -3042,11 +3203,11 @@ conf_get() {
"$(uci -q show mwan3 2>/dev/null | sed -n 's/^mwan3\.\([^=]*\)=policy$/\1/p' | tr '\n' ' ')" "$(uci -q show mwan3 2>/dev/null | sed -n 's/^mwan3\.\([^=]*\)=policy$/\1/p' | tr '\n' ' ')"
# 值支持两种书写格式:多行(每行一条)或单行空格分隔。 # 值支持两种书写格式:多行(每行一条)或单行空格分隔。
# 先把所有空白折叠成换行,再按冒号拆字段——两种格式统一处理。 # 先把所有空白折叠成换行,再按冒号拆字段——两种格式统一处理。
_conf_val ISP_TABLE | tr -s ' \t' '\n' | _conf_table ISP_TABLE | tr -s ' \t' '\n' |
awk -F: 'NF >= 4 { printf "isp\t%s\t%s\t%s\t%s\n", $1, $2, $3, $4 }' awk -F: 'NF >= 4 { printf "isp\t%s\t%s\t%s\t%s\n", $1, $2, $3, $4 }'
_conf_val DNS_TABLE | tr -s ' \t' '\n' | _conf_table DNS_TABLE | tr -s ' \t' '\n' |
awk -F: 'NF >= 2 { printf "dns\t%s\t%s\n", $1, $2 }' awk -F: 'NF >= 2 { printf "dns\t%s\t%s\n", $1, $2 }'
_conf_val DOMAIN_SPLIT | tr -s ' \t' '\n' | _conf_table DOMAIN_SPLIT | tr -s ' \t' '\n' |
awk -F: 'NF >= 2 { printf "domain\t%s\t%s\n", $1, $2 }' awk -F: 'NF >= 2 { printf "domain\t%s\t%s\n", $1, $2 }'
} }
@@ -3103,6 +3264,11 @@ _row_check() {
# 直接对一整行做校验(不拆字段的调用点用) # 直接对一整行做校验(不拆字段的调用点用)
_row_check_row() { _row_check_row() {
# 双保险(B-1):入口已删注释行,这里再挡一次带前导空白的 # 行,
# 避免将来新增调用点绕过入口清理时又把注释当数据。
case "$1" in
'#'* | [[:space:]]*'#'*) return 0 ;;
esac
_rr_ifs=$IFS _rr_ifs=$IFS
IFS=':' IFS=':'
set -- $1 set -- $1
@@ -3134,6 +3300,12 @@ _valid_ipv4() {
_conf_validate() { _conf_validate() {
_key=$1 _key=$1
_val=$2 _val=$2
# 注释行不参与校验(B-1):整行删掉后再按空白拆字段。清理必须发生在
# 空白展开之前,否则 "# 说明:xxx" 会被拆成 "#" 和 "说明:xxx" 两段。
# 这里只改局部副本,写回文件的内容仍保留用户注释。
case "$_key" in
ISP_TABLE | DNS_TABLE | DOMAIN_SPLIT) _val=$(_strip_comments "$_val") ;;
esac
case "$_val" in case "$_val" in
*'$'* | *'`'* | *'"'* | *"'"* | *'\'* | *';'* | *'|'*) *'$'* | *'`'* | *'"'* | *"'"* | *'\'* | *';'* | *'|'*)
die "配置值含不允许的字符(\$ \` \" ' \\ ; |)" die "配置值含不允许的字符(\$ \` \" ' \\ ; |)"
@@ -3684,17 +3856,8 @@ cmd_uninstall() {
cat "$WORK/mwan3.new" > "$CFG_MWAN3" cat "$WORK/mwan3.new" > "$CFG_MWAN3"
fi fi
for row in $ISP_TABLE; do # 按标记删,而不是按当前表名:改名/删除的孤儿段也要清掉(B-4)。
_old_ifs=$IFS _uninstall_ipsets
IFS=':'
set -- $row
IFS=$_old_ifs
case "$row" in \#*) continue ;; esac
[ $# -ge 2 ] || continue
_valid_name "$2" || continue
uci -q delete "mwan3.ipset_$2" 2>/dev/null
done
uci -q commit mwan3
/etc/init.d/mwan3 reload >/dev/null 2>&1 /etc/init.d/mwan3 reload >/dev/null 2>&1
# 恢复 dnsmasq confdir 原值(状态文件在 $BASE 里,必须先恢复再删目录) # 恢复 dnsmasq confdir 原值(状态文件在 $BASE 里,必须先恢复再删目录)
@@ -203,6 +203,13 @@ function renderListeners(s, uciconfig, isClient) {
o.depends('type', 'mieru'); o.depends('type', 'mieru');
o.modalonly = true; o.modalonly = true;
o = s.taboption('field_general', form.Value, 'mieru_tcp_idle_timeout', _('TCP idle timeout'),
_('In seconds.'), _('Minimum value is $s.').format('60'));
o.placeholder = '1800';
o.validate = hm.validateTimeDuration;
o.depends('type', 'mieru');
o.modalonly = true;
o = s.taboption('field_general', form.Value, 'mieru_traffic_pattern', _('Traffic pattern'), o = s.taboption('field_general', form.Value, 'mieru_traffic_pattern', _('Traffic pattern'),
_('A base64 string is used to fine-tune network behavior.<br/>Please refer to the <a target="_blank" href="%s" rel="noreferrer noopener">document</a>.') _('A base64 string is used to fine-tune network behavior.<br/>Please refer to the <a target="_blank" href="%s" rel="noreferrer noopener">document</a>.')
.format('https://github.com/enfein/mieru/blob/main/docs/traffic-pattern.md')); .format('https://github.com/enfein/mieru/blob/main/docs/traffic-pattern.md'));
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
@@ -265,6 +265,7 @@ export function parseListener(cfg) {
transport: cfg.mieru_transport, transport: cfg.mieru_transport,
"traffic-pattern": cfg.mieru_traffic_pattern, "traffic-pattern": cfg.mieru_traffic_pattern,
"user-hint-is-mandatory": strToBool(cfg.mieru_user_hint_is_mandatory), "user-hint-is-mandatory": strToBool(cfg.mieru_user_hint_is_mandatory),
"tcp-idle-timeout": durationToSecond(cfg.mieru_tcp_idle_timeout),
/* Sudoku */ /* Sudoku */
key: cfg.sudoku_key, key: cfg.sudoku_key,
+2 -2
View File
@@ -1,8 +1,8 @@
include $(TOPDIR)/rules.mk include $(TOPDIR)/rules.mk
PKG_NAME:=luci-app-isp-split PKG_NAME:=luci-app-isp-split
PKG_VERSION:=0.2.1 PKG_VERSION:=0.2.2
PKG_RELEASE:=2 PKG_RELEASE:=3
PKG_LICENSE:=MIT PKG_LICENSE:=MIT
PKG_LICENSE_FILES:=LICENSE PKG_LICENSE_FILES:=LICENSE
PKG_MAINTAINER:=jihebube <jihebube@users.noreply.github.com> PKG_MAINTAINER:=jihebube <jihebube@users.noreply.github.com>
@@ -131,6 +131,10 @@ return view.extend({
out.split('\n').forEach(function(line) { out.split('\n').forEach(function(line) {
if (!line) if (!line)
return; return;
/* 注释行不是数据行(B-1)。conf get 已在 shell 侧过滤,
这里再挡一次,避免旧版脚本或手工拼接的输出被渲染成红行。 */
if (/^\s*#/.test(line))
return;
var f = line.split('\t'); var f = line.split('\t');
if (f[0] === 'dns_mode') if (f[0] === 'dns_mode')
model.mode = (f[1] || 'bind').trim(); model.mode = (f[1] || 'bind').trim();
@@ -354,7 +354,13 @@ return view.extend({
box.removeChild(box.firstChild); box.removeChild(box.firstChild);
var rows = (this.status || []).filter(function(r) { var rows = (this.status || []).filter(function(r) {
return r && r.set !== '兜底'; /* B-1:注释行不是运营商行。shell 侧已过滤,这里兜底,
防止旧脚本/手工数据在总览页多出一张卡片。 */
if (!r || r.set === '兜底')
return false;
if (/^\s*#/.test(String(r.set || '')) || /^\s*#/.test(String(r.src || '')))
return false;
return true;
}); });
if (!rows.length) { if (!rows.length) {
+2 -2
View File
@@ -1,8 +1,8 @@
include $(TOPDIR)/rules.mk include $(TOPDIR)/rules.mk
PKG_NAME:=luci-app-open-box PKG_NAME:=luci-app-open-box
PKG_VERSION:=0.1.370 PKG_VERSION:=0.1.371
PKG_RELEASE:=50 PKG_RELEASE:=51
PKG_MAINTAINER:=liandu2024 PKG_MAINTAINER:=liandu2024
PKG_LICENSE:=GPL-3.0-or-later PKG_LICENSE:=GPL-3.0-or-later
+2 -2
View File
@@ -7,8 +7,8 @@
include $(TOPDIR)/rules.mk include $(TOPDIR)/rules.mk
PKG_NAME:=luci-app-passwall PKG_NAME:=luci-app-passwall
PKG_VERSION:=26.10.22 PKG_VERSION:=26.10.29
PKG_RELEASE:=353 PKG_RELEASE:=354
PKG_PO_VERSION:=$(PKG_VERSION) PKG_PO_VERSION:=$(PKG_VERSION)
PKG_CONFIG_DEPENDS:= \ PKG_CONFIG_DEPENDS:= \
+7 -5
View File
@@ -246,9 +246,9 @@ end
function UrlEncode(szText) function UrlEncode(szText)
if type(szText) ~= "string" then return "" end if type(szText) ~= "string" then return "" end
return szText:gsub("([^%w%-_%.%~])", function(c) return (szText:gsub("([^%w%-_%.%~])", function(c)
return string.format("%%%02X", string.byte(c)) return string.format("%%%02X", string.byte(c))
end) end))
end end
function UrlDecode(szText) function UrlDecode(szText)
@@ -1401,9 +1401,11 @@ function to_download_progress(app_name, task_id, total_size)
total_size = tonumber(total_size) or 0 total_size = tonumber(total_size) or 0
local tmp_file = "/tmp/" .. app_name .. "_download." .. task_id local tmp_file = "/tmp/" .. app_name .. "_download." .. task_id
local downloaded = tonumber(fs.stat(tmp_file, "size")) or 0 local downloaded
if app_name == appname then if app_name == appname then
downloaded = (tonumber(fs.stat(tmp_file .. "1", "size")) or 0) + (tonumber(fs.stat(tmp_file .. "2", "size")) or 0) downloaded = (tonumber((fs.stat(tmp_file .. "1", "size"))) or 0) + (tonumber((fs.stat(tmp_file .. "2", "size"))) or 0)
else
downloaded = tonumber((fs.stat(tmp_file, "size"))) or 0
end end
local percent local percent
if total_size > 0 then if total_size > 0 then
@@ -1558,7 +1560,7 @@ function get_version()
end end
version = (version or ""):match("^%s*(.-)%s*$") version = (version or ""):match("^%s*(.-)%s*$")
-- Normalize APK's -rN release notation while retaining the release number. -- Normalize APK's -rN release notation while retaining the release number.
return version:gsub("%-r(%d+)$", "-%1") return (version:gsub("%-r(%d+)$", "-%1"))
end end
function to_check_self() function to_check_self()
@@ -259,6 +259,17 @@ local com = self.com
detail.textContent = installingNotice; detail.textContent = installingNotice;
// Read the tiny result file even if rpcd restart invalidates the session. // Read the tiny result file even if rpcd restart invalidates the session.
var pending = false, finished = false; var pending = false, finished = false;
function finishInstall(code) {
if (finished) return;
finished = true;
clearInterval(timer);
removePageNotice(appname);
if (code) onRequestError(btn, updateFailedText);
else {
window.onbeforeunload = undefined;
window.location.reload();
}
}
var timer = setInterval(function() { var timer = setInterval(function() {
if (pending) return; if (pending) return;
pending = true; pending = true;
@@ -271,27 +282,28 @@ local com = self.com
if (finished) return; if (finished) return;
var json; var json;
try { json = JSON.parse(xhr.responseText); } catch (e) { return; } try { json = JSON.parse(xhr.responseText); } catch (e) { return; }
if (typeof json.code !== 'number') return; if (!json || typeof json.code !== 'number') return;
finished = true; finishInstall(json.code);
clearInterval(timer);
removePageNotice(appname);
if (json.code) onRequestError(btn, updateFailedText);
else {
window.onbeforeunload = undefined;
window.location.reload();
}
}; };
xhr.send(); xhr.send();
}, 1000); }, 1000);
XHR.post(url, {token: tokenStr, task: 'install', id: id, // Legacy LuCI has no static XHR.post(), and its instance callback has no JSON argument.
force: appInfoList[appname].has_update ? '0' : '1'}, function(x, json) { var request = new XMLHttpRequest();
if (!finished && json && json.code) { request.open('POST', url, true);
finished = true; request.timeout = 300000;
clearInterval(timer); request.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
removePageNotice(appname); request.onerror = request.ontimeout = function() { finishInstall(1); };
onRequestError(btn, updateFailedText); request.onload = function() {
if (finished) return;
var json;
try { json = JSON.parse(request.responseText); } catch (e) {}
if (request.status < 200 || request.status >= 300 || !json ||
typeof json.code !== 'number' || json.code) {
finishInstall(1);
} }
}, 300); };
request.send('token=' + encodeURIComponent(tokenStr) + '&task=install&id=' + encodeURIComponent(id) +
'&force=' + (appInfoList[appname].has_update ? '0' : '1'));
} }
//]]> //]]>
@@ -300,89 +300,36 @@ table td, .table .td {
text-align: right; text-align: right;
} }
.custom-dropdown { .pw-group-select {
position: relative;
border: 1px solid #d9d9d9;
border-radius: 2px;
width: 180px; width: 180px;
height: 28px; height: 28px;
font-size: 13px; flex: 0 0 180px;
background: #fff;
cursor: pointer;
box-sizing: border-box;
display: block;
}
.selected-display {
display: flex;
justify-content: space-between;
align-items: center;
padding: 0 8px;
width: 100%;
height: 100%;
box-sizing: border-box;
font-size: 12px;
color: #666;
}
.selected-display:hover {
background-color: #f7f7f7;
}
.dropdown-list {
position: absolute;
top: calc(100% + 2px);
left: -1px;
width: calc(100% + 2px);
border: 1px solid #d9d9d9;
border-radius: 2px;
border-top: none;
box-shadow: 0 1px 3px rgba(0,0,0,0.15);
background: #fff;
list-style: none;
margin: 0;
padding: 0;
max-height: 200px;
overflow-y: auto;
overflow-x: hidden;
z-index: 100;
box-sizing: border-box;
color: #666;
}
.dropdown-item {
padding: 4px 8px;
line-height: 20px;
cursor: pointer;
}
.dropdown-item.selected {
background-color: #1e90ff;
color: #fff;
}
.create-item-input::placeholder {
text-align: center;
}
.dropdown-item.custom-input input {
width: 100%;
box-sizing: border-box;
padding: 3px;
font-size: 13px;
line-height: 20px;
border: 1px solid #ccc;
text-align: left; text-align: left;
} }
.arrow-down-small { .pw-group-select > .cbi-dropdown,
width: 0; .pw-group-select > .cbi-input-text,
height: 0; .pw-group-select > .cbi-input-select {
border-left: 4px solid transparent; width: 100% !important;
border-right: 4px solid transparent; min-width: 0 !important;
border-top: 5px solid #555; max-width: 100% !important;
display: inline-block; height: 28px !important;
vertical-align: middle; min-height: 28px !important;
box-sizing: border-box;
margin: 0;
padding-top: 0;
padding-bottom: 0;
font-size: 13px;
}
.pw-group-select > .cbi-dropdown > ul:not(.dropdown) > li,
.pw-group-select > .cbi-dropdown > .open {
height: 26px;
min-height: 0;
line-height: 26px;
padding-top: 0;
padding-bottom: 0;
box-sizing: border-box;
} }
</style> </style>
@@ -1077,97 +1024,103 @@ table td, .table .td {
//<![CDATA[ //<![CDATA[
//Pop-up logic //Pop-up logic
// Custom group dropdown list events function normalize_group_name(value, groups) {
function dropdown_list_fun(div_id) { const name = value.trim();
const dropdown = document.getElementById(div_id); return groups.find(group => group.toLowerCase() === name.toLowerCase()) || name;
if (!dropdown) return; }
const display = dropdown.querySelector(".selected-display"); function init_group_dropdown(div_id) {
const displayText = display.querySelector(".text"); const container = document.getElementById(div_id);
const list = dropdown.querySelector(".dropdown-list"); if (!container || container._group_ready || container._group_loading) return;
const hidden = dropdown.querySelector('input[type="hidden"]'); const tabs = document.querySelector("#node_list .cbi-tabmenu");
const input = dropdown.querySelector(".create-item-input"); if (!tabs) {
setTimeout(() => init_group_dropdown(div_id), 50);
display.addEventListener("click", function() { return;
list.style.display = list.style.display === "none" ? "block" : "none";
input.value = "";
//input.focus();
});
function selectItem(li) {
list.querySelectorAll(".dropdown-item").forEach(function(el){
el.classList.remove("selected");
});
li.classList.add("selected");
hidden.value = li.dataset.value;
displayText.textContent = li.dataset.value || "<%:default%>";
list.style.display = "none";
} }
list.addEventListener("click", function(e){ const choices = { "default": "<%:default%>" };
const li = e.target.closest(".dropdown-item"); const groups = ["default"];
if (!li || li.classList.contains("custom-input")) return; tabs.querySelectorAll("li[group_name]").forEach(function(tab) {
selectItem(li); const group = tab.getAttribute("group_name");
}); if (group !== "default" && !groups.includes(group)) {
choices[group] = group;
input.addEventListener("keydown", function(e){ groups.push(group);
const isEnter = e.key === "Enter" || e.keyCode === 13;
if (!isEnter) return;
e.stopPropagation();
e.preventDefault();
const val = input.value.trim();
if (!val) return;
if (val.toLowerCase() === "default") {
const emptyLi = Array.from(list.querySelectorAll(".dropdown-item"))
.find(function(el){ return !el.dataset.value; });
if (emptyLi) selectItem(emptyLi);
input.value = "";
return;
} }
});
let li = Array.from(list.querySelectorAll(".dropdown-item")).find(function(el){ const input = container.querySelector("input");
return el.dataset.value && el.dataset.value.toLowerCase() === val.toLowerCase(); <% if is_js_luci then -%>
container._group_loading = true;
L.require("ui").then(function(ui) {
const widget = new ui.Dropdown("default", choices, {
id: input.id,
name: input.name,
multiple: false,
optional: false,
create: true,
sort: groups,
custom_placeholder: "-- <%:custom%> --"
}); });
if (!li) { const dropdown = widget.render();
li = document.createElement("li"); // Normalize before LuCI handles Enter and replaces its single custom item.
li.className = "dropdown-item"; dropdown.addEventListener("keydown", function(e) {
li.dataset.value = val; if (!e.target.classList.contains("create-item-input") ||
li.textContent = val; (e.key !== "Enter" && e.keyCode !== 13)) return;
list.insertBefore(li, input.parentNode); if (e.isComposing) {
} e.stopPropagation();
return;
input.value = ""; }
selectItem(li); const values = Array.from(dropdown.querySelectorAll("ul.dropdown > li[data-value]:not([unselectable])"), li => li.dataset.value);
}); e.target.value = normalize_group_name(e.target.value, values);
// Read group names from tab if (!e.target.value) {
function InsertGroup(list, input) { e.preventDefault();
const tabs = document.querySelectorAll(".cbi-tabmenu li"); e.stopPropagation();
if (!tabs.length) { }
setTimeout(() => InsertGroup(list, input), 50); }, true);
return; const customInput = dropdown.querySelector(".create-item-input");
} // The custom input row must not shadow a group named "-".
customInput.parentNode.removeAttribute("data-value");
tabs.forEach(function(li){ customInput.setAttribute("inputmode", "text");
const group = li.id.split('.').pop(); customInput.setAttribute("enterkeyhint", "done");
if(group === "default") return; dropdown.addEventListener("cbi-dropdown-change", function() {
if(Array.from(list.querySelectorAll(".dropdown-item")).some(el => el.dataset.value === group)) return; customInput.value = "";
const newLi = document.createElement("li");
newLi.className = "dropdown-item";
newLi.dataset.value = group;
newLi.textContent = group;
list.insertBefore(newLi, input.parentNode);
}); });
} container.replaceChild(dropdown, input);
InsertGroup(list, input); container._group_widget = widget;
container._group_ready = true;
// Automatically collapses when clicking on the outside. container._group_loading = false;
document.addEventListener("click", function(e) { }).catch(function(error) {
if (!dropdown.contains(e.target)) { container._group_loading = false;
list.style.display = "none"; console.error("Group dropdown init failed:", error);
alert("<%:Error%>");
});
<% else -%>
input.disabled = false;
input.addEventListener("blur", function() {
input.value = normalize_group_name(input.value, groups) || "default";
});
input.addEventListener("keydown", function(e) {
if ((e.key === "Enter" || e.keyCode === 13) && !e.isComposing) {
e.preventDefault();
e.stopPropagation();
input.blur();
} }
}); });
cbi_combobox_init(input.id, choices, "<%:default%>", "-- <%:custom%> --");
container._group_ready = true;
<% end -%>
}
function get_group_value(div_id) {
const container = document.getElementById(div_id);
return (container._group_widget ? container._group_widget.getValue() : container.querySelector("input").value) || "default";
}
function close_group_dropdown(div_id) {
const container = document.getElementById(div_id);
const dropdown = container.querySelector(".cbi-dropdown[open]");
if (dropdown) dropdown.dispatchEvent(new CustomEvent("cbi-dropdown-close"));
const input = container.querySelector(".create-item-input");
if (input) input.value = "";
} }
function getBg(el) { function getBg(el) {
@@ -1187,20 +1140,18 @@ table td, .table .td {
const addLinkDiv = document.getElementById("add_link_div"); const addLinkDiv = document.getElementById("add_link_div");
addLinkDiv.style.background = getBg(document.querySelector('.cbi-section')) || getBg(document.body) || ''; addLinkDiv.style.background = getBg(document.querySelector('.cbi-section')) || getBg(document.body) || '';
addLinkDiv.style.display = "block"; addLinkDiv.style.display = "block";
if (!addLinkDiv._dropdown_inited) { init_group_dropdown("addlink_group_custom");
addLinkDiv._dropdown_inited = true;
dropdown_list_fun("addlink_group_custom");
}
document.getElementById("nodes_link").focus(); document.getElementById("nodes_link").focus();
}, },
close() { close() {
close_group_dropdown("addlink_group_custom");
document.getElementById('modal-mask').style.display = 'none'; document.getElementById('modal-mask').style.display = 'none';
document.getElementById("add_link_div").style.display = "none"; document.getElementById("add_link_div").style.display = "none";
document.body.classList.remove('modal-open'); document.body.classList.remove('modal-open');
}, },
add_node() { add_node() {
let nodes_link = document.getElementById("nodes_link").value; let nodes_link = document.getElementById("nodes_link").value;
const group = (document.querySelector('#addlink_group_custom input[type="hidden"]')?.value || "default"); const group = get_group_value("addlink_group_custom");
nodes_link = nodes_link.replace(/\t/g, "").replace(/\r\n|\r/g, "\n").replace(/<[^>]*>/g, '').trim(); nodes_link = nodes_link.replace(/\t/g, "").replace(/\r\n|\r/g, "\n").replace(/<[^>]*>/g, '').trim();
if (nodes_link != "") { if (nodes_link != "") {
nodes_link = decodeIfBase64(nodes_link); nodes_link = decodeIfBase64(nodes_link);
@@ -1279,23 +1230,21 @@ table td, .table .td {
const reassignGroupDiv = document.getElementById("reassign_group_div"); const reassignGroupDiv = document.getElementById("reassign_group_div");
reassignGroupDiv.style.background = getBg(document.querySelector('.cbi-section')) || getBg(document.body) || ''; reassignGroupDiv.style.background = getBg(document.querySelector('.cbi-section')) || getBg(document.body) || '';
reassignGroupDiv.style.display = "block"; reassignGroupDiv.style.display = "block";
if (!reassignGroupDiv._dropdown_inited) { init_group_dropdown("reassign_group_custom");
reassignGroupDiv._dropdown_inited = true;
dropdown_list_fun("reassign_group_custom");
}
} else { } else {
alert("<%:You no select nodes !%>"); alert("<%:You no select nodes !%>");
} }
} }
}, },
close() { close() {
close_group_dropdown("reassign_group_custom");
document.getElementById('modal-mask').style.display = 'none'; document.getElementById('modal-mask').style.display = 'none';
document.getElementById("reassign_group_div").style.display = "none"; document.getElementById("reassign_group_div").style.display = "none";
document.body.classList.remove('modal-open'); document.body.classList.remove('modal-open');
}, },
action() { action() {
const ids = []; const ids = [];
const group = (document.querySelector('#reassign_group_custom input[type="hidden"]')?.value || "default"); const group = get_group_value("reassign_group_custom");
const visibleContainer = document.querySelector('#cbi-passwall-nodes > .cbi-tabcontainer[style*="display:block"], #cbi-passwall-nodes > .cbi-tabcontainer[style*="display: block"]'); const visibleContainer = document.querySelector('#cbi-passwall-nodes > .cbi-tabcontainer[style*="display:block"], #cbi-passwall-nodes > .cbi-tabcontainer[style*="display: block"]');
if (!visibleContainer) return; if (!visibleContainer) return;
const doms = visibleContainer.getElementsByClassName("nodes_select"); const doms = visibleContainer.getElementsByClassName("nodes_select");
@@ -1742,19 +1691,9 @@ table td, .table .td {
</div> </div>
<div class="value-custom"> <div class="value-custom">
<div class="value-field-custom"> <div class="value-field-custom">
<label class="value-title-custom" for="addlink_group_custom"><%:Group Name%></label> <label class="value-title-custom" for="addlink_group"><%:Group Name%></label>
<div id="addlink_group_custom" class="custom-dropdown"> <div id="addlink_group_custom" class="pw-group-select">
<div class="selected-display"> <input id="addlink_group" name="addlink_group" class="cbi-input-text" type="text" value="default" disabled>
<span class="text"><%:default%></span>
<span class="arrow-down-small"></span>
</div>
<ul class="dropdown-list" style="display:none;">
<li class="dropdown-item selected" data-value=""><%:default%></li>
<li class="dropdown-item custom-input">
<input type="text" placeholder="-- <%:custom%> --" class="create-item-input" inputmode="text" enterkeyhint="done">
</li>
</ul>
<input type="hidden" name="addlink_group" value="">
</div> </div>
</div> </div>
</div> </div>
@@ -1770,19 +1709,9 @@ table td, .table .td {
<h3><%:Reassign Node Group%></h3> <h3><%:Reassign Node Group%></h3>
<div class="value-custom"> <div class="value-custom">
<div class="value-field-custom"> <div class="value-field-custom">
<label class="value-title-custom" for="reassign_group_custom"><%:Group Name%></label> <label class="value-title-custom" for="to_group"><%:Group Name%></label>
<div id="reassign_group_custom" class="custom-dropdown"> <div id="reassign_group_custom" class="pw-group-select">
<div class="selected-display"> <input id="to_group" name="to_group" class="cbi-input-text" type="text" value="default" disabled>
<span class="text"><%:default%></span>
<span class="arrow-down-small"></span>
</div>
<ul class="dropdown-list" style="display:none;">
<li class="dropdown-item selected" data-value=""><%:default%></li>
<li class="dropdown-item custom-input">
<input type="text" placeholder="-- <%:custom%> --" class="create-item-input" inputmode="text" enterkeyhint="done">
</li>
</ul>
<input type="hidden" name="to_group" value="">
</div> </div>
</div> </div>
</div> </div>
File diff suppressed because it is too large. Load diff
@@ -36,12 +36,7 @@
101.125.6.0/24 101.125.6.0/24
101.126.0.0/18 101.126.0.0/18
101.126.128.0/19 101.126.128.0/19
101.126.172.0/22 101.126.168.0/21
101.126.176.0/20
101.126.192.0/19
101.126.228.0/22
101.126.232.0/21
101.126.240.0/20
101.126.64.0/19 101.126.64.0/19
101.126.96.0/20 101.126.96.0/20
101.128.0.0/22 101.128.0.0/22
@@ -132,6 +127,8 @@
101.96.142.0/23 101.96.142.0/23
101.96.144.0/20 101.96.144.0/20
101.96.192.0/18 101.96.192.0/18
102.216.81.0/24
102.216.82.0/24
103.1.168.0/22 103.1.168.0/22
103.1.20.0/22 103.1.20.0/22
103.1.8.0/22 103.1.8.0/22
@@ -222,6 +219,7 @@
103.140.14.0/23 103.140.14.0/23
103.141.10.0/23 103.141.10.0/23
103.142.234.0/23 103.142.234.0/23
103.142.82.0/24
103.142.96.0/23 103.142.96.0/23
103.143.16.0/22 103.143.16.0/22
103.143.228.0/23 103.143.228.0/23
@@ -301,9 +299,6 @@
103.197.0.0/22 103.197.0.0/22
103.197.228.0/22 103.197.228.0/22
103.198.124.0/22 103.198.124.0/22
103.198.216.0/21
103.198.224.0/20
103.198.244.0/22
103.198.60.0/22 103.198.60.0/22
103.2.108.0/22 103.2.108.0/22
103.2.208.0/22 103.2.208.0/22
@@ -374,6 +369,7 @@
103.217.184.0/21 103.217.184.0/21
103.217.192.0/20 103.217.192.0/20
103.218.216.0/22 103.218.216.0/22
103.218.92.0/22
103.219.100.0/23 103.219.100.0/23
103.219.176.0/22 103.219.176.0/22
103.219.184.0/22 103.219.184.0/22
@@ -394,7 +390,7 @@
103.222.176.0/21 103.222.176.0/21
103.222.184.0/22 103.222.184.0/22
103.222.216.0/22 103.222.216.0/22
103.222.33.0/24 103.222.32.0/23
103.222.40.0/22 103.222.40.0/22
103.223.132.0/22 103.223.132.0/22
103.223.144.0/20 103.223.144.0/20
@@ -426,12 +422,12 @@
103.230.236.0/22 103.230.236.0/22
103.231.16.0/24 103.231.16.0/24
103.231.64.0/21 103.231.64.0/21
103.232.144.0/22
103.232.166.0/23 103.232.166.0/23
103.233.128.0/22 103.233.128.0/22
103.233.136.0/24 103.233.136.0/24
103.233.138.0/24 103.233.138.0/24
103.233.162.0/23 103.233.162.0/23
103.233.228.0/22
103.233.4.0/22 103.233.4.0/22
103.233.52.0/22 103.233.52.0/22
103.234.128.0/23 103.234.128.0/23
@@ -488,7 +484,7 @@
103.240.84.0/22 103.240.84.0/22
103.241.220.0/22 103.241.220.0/22
103.241.95.0/24 103.241.95.0/24
103.242.128.0/24 103.242.128.0/23
103.242.130.0/24 103.242.130.0/24
103.242.168.0/23 103.242.168.0/23
103.242.172.0/22 103.242.172.0/22
@@ -500,6 +496,7 @@
103.244.64.0/22 103.244.64.0/22
103.244.80.0/22 103.244.80.0/22
103.245.128.0/22 103.245.128.0/22
103.245.25.0/24
103.246.152.0/22 103.246.152.0/22
103.247.168.0/22 103.247.168.0/22
103.247.176.0/22 103.247.176.0/22
@@ -642,8 +639,7 @@
103.49.108.0/22 103.49.108.0/22
103.49.12.0/22 103.49.12.0/22
103.49.176.0/24 103.49.176.0/24
103.5.192.0/23 103.5.192.0/22
103.5.194.0/24
103.5.52.0/24 103.5.52.0/24
103.52.100.0/22 103.52.100.0/22
103.52.172.0/22 103.52.172.0/22
@@ -658,7 +654,6 @@
103.56.100.0/22 103.56.100.0/22
103.56.104.0/22 103.56.104.0/22
103.56.152.0/22 103.56.152.0/22
103.56.184.0/22
103.56.60.0/22 103.56.60.0/22
103.56.76.0/22 103.56.76.0/22
103.57.12.0/22 103.57.12.0/22
@@ -706,6 +701,7 @@
103.73.158.0/24 103.73.158.0/24
103.73.204.0/22 103.73.204.0/22
103.73.48.0/24 103.73.48.0/24
103.74.126.0/23
103.74.24.0/21 103.74.24.0/21
103.74.48.0/22 103.74.48.0/22
103.74.80.0/22 103.74.80.0/22
@@ -776,6 +772,7 @@
103.98.125.0/24 103.98.125.0/24
103.98.127.0/24 103.98.127.0/24
103.98.220.0/22 103.98.220.0/22
103.98.224.0/22
103.98.248.0/23 103.98.248.0/23
103.98.251.0/24 103.98.251.0/24
103.98.252.0/22 103.98.252.0/22
@@ -849,7 +846,7 @@
106.92.0.0/16 106.92.0.0/16
107.158.37.0/24 107.158.37.0/24
109.244.0.0/16 109.244.0.0/16
109.66.22.0/24 109.66.22.0/23
110.100.0.0/16 110.100.0.0/16
110.112.0.0/15 110.112.0.0/15
110.114.0.0/16 110.114.0.0/16
@@ -924,12 +921,14 @@
111.223.12.0/22 111.223.12.0/22
111.224.0.0/14 111.224.0.0/14
111.228.0.0/18 111.228.0.0/18
111.228.80.0/22
111.229.0.0/16 111.229.0.0/16
111.230.0.0/15 111.230.0.0/15
111.235.156.0/22 111.235.156.0/22
111.235.160.0/22 111.235.160.0/22
111.235.164.0/23 111.235.164.0/23
111.235.168.0/22 111.235.169.0/24
111.235.170.0/23
111.235.172.0/23 111.235.172.0/23
111.235.174.0/24 111.235.174.0/24
111.235.178.0/23 111.235.178.0/23
@@ -995,6 +994,7 @@
113.46.0.0/16 113.46.0.0/16
113.47.0.0/18 113.47.0.0/18
113.47.104.0/22 113.47.104.0/22
113.47.108.0/23
113.47.110.0/24 113.47.110.0/24
113.47.112.0/20 113.47.112.0/20
113.47.128.0/18 113.47.128.0/18
@@ -1022,6 +1022,7 @@
113.8.0.0/15 113.8.0.0/15
114.104.0.0/14 114.104.0.0/14
114.110.0.0/20 114.110.0.0/20
114.110.112.0/22
114.110.96.0/22 114.110.96.0/22
114.111.0.0/23 114.111.0.0/23
114.111.16.0/20 114.111.16.0/20
@@ -1044,10 +1045,7 @@
114.113.221.0/24 114.113.221.0/24
114.113.223.0/24 114.113.223.0/24
114.113.224.0/20 114.113.224.0/20
114.113.63.0/24
114.113.64.0/22 114.113.64.0/22
114.113.80.0/22
114.113.84.0/24
114.113.88.0/21 114.113.88.0/21
114.113.96.0/19 114.113.96.0/19
114.114.112.0/21 114.114.112.0/21
@@ -1124,6 +1122,7 @@
115.31.64.0/22 115.31.64.0/22
115.32.0.0/19 115.32.0.0/19
115.32.104.0/21 115.32.104.0/21
115.32.112.0/22
115.32.120.0/21 115.32.120.0/21
115.32.128.0/19 115.32.128.0/19
115.32.32.0/20 115.32.32.0/20
@@ -1259,6 +1258,8 @@
117.40.0.0/14 117.40.0.0/14
117.44.0.0/15 117.44.0.0/15
117.48.0.0/18 117.48.0.0/18
117.48.100.0/22
117.48.104.0/21
117.48.112.0/20 117.48.112.0/20
117.48.128.0/19 117.48.128.0/19
117.48.160.0/20 117.48.160.0/20
@@ -1482,6 +1483,7 @@
119.37.2.0/24 119.37.2.0/24
119.38.0.0/21 119.38.0.0/21
119.38.192.0/19 119.38.192.0/19
119.38.224.0/24
119.39.0.0/16 119.39.0.0/16
119.4.0.0/14 119.4.0.0/14
119.40.128.0/17 119.40.128.0/17
@@ -1507,6 +1509,7 @@
119.44.24.0/23 119.44.24.0/23
119.44.253.0/24 119.44.253.0/24
119.44.254.0/23 119.44.254.0/23
119.44.26.0/24
119.44.4.0/23 119.44.4.0/23
119.44.45.0/24 119.44.45.0/24
119.44.46.0/24 119.44.46.0/24
@@ -1550,6 +1553,7 @@
119.80.200.0/22 119.80.200.0/22
119.80.240.0/22 119.80.240.0/22
119.80.248.0/21 119.80.248.0/21
119.80.56.0/24
119.80.8.0/22 119.80.8.0/22
119.84.0.0/14 119.84.0.0/14
119.88.128.0/17 119.88.128.0/17
@@ -1662,7 +1666,6 @@
121.8.0.0/13 121.8.0.0/13
121.89.0.0/16 121.89.0.0/16
121.91.104.0/21 121.91.104.0/21
122.0.64.0/18
122.10.133.0/24 122.10.133.0/24
122.10.136.0/23 122.10.136.0/23
122.102.64.0/20 122.102.64.0/20
@@ -1800,8 +1803,11 @@
123.4.0.0/14 123.4.0.0/14
123.49.192.0/23 123.49.192.0/23
123.49.194.0/24 123.49.194.0/24
123.49.196.0/24
123.49.231.0/24 123.49.231.0/24
123.49.232.0/24 123.49.232.0/24
123.49.237.0/24
123.49.238.0/23
123.49.240.0/24 123.49.240.0/24
123.49.242.0/23 123.49.242.0/23
123.49.245.0/24 123.49.245.0/24
@@ -1848,6 +1854,8 @@
124.14.22.0/24 124.14.22.0/24
124.14.224.0/19 124.14.224.0/19
124.14.5.0/24 124.14.5.0/24
124.14.52.0/22
124.14.6.0/24
124.14.64.0/18 124.14.64.0/18
124.14.8.0/24 124.14.8.0/24
124.151.0.0/16 124.151.0.0/16
@@ -1901,6 +1909,7 @@
124.71.128.0/18 124.71.128.0/18
124.71.192.0/19 124.71.192.0/19
124.71.224.0/20 124.71.224.0/20
124.71.244.0/23
124.71.250.0/24 124.71.250.0/24
124.72.0.0/13 124.72.0.0/13
124.88.0.0/13 124.88.0.0/13
@@ -1992,6 +2001,7 @@
140.210.224.0/20 140.210.224.0/20
140.210.32.0/22 140.210.32.0/22
140.210.4.0/22 140.210.4.0/22
140.210.40.0/23
140.210.64.0/18 140.210.64.0/18
140.210.8.0/21 140.210.8.0/21
140.224.0.0/16 140.224.0.0/16
@@ -2003,7 +2013,10 @@
140.250.0.0/16 140.250.0.0/16
140.255.0.0/16 140.255.0.0/16
140.75.0.0/16 140.75.0.0/16
141.11.210.0/24
141.11.219.0/24 141.11.219.0/24
142.86.252.0/23
142.86.254.0/24
143.20.246.0/24 143.20.246.0/24
143.64.0.0/16 143.64.0.0/16
144.0.0.0/16 144.0.0.0/16
@@ -2016,6 +2029,7 @@
144.48.64.0/22 144.48.64.0/22
144.52.0.0/16 144.52.0.0/16
144.7.0.0/17 144.7.0.0/17
144.79.42.0/23
144.79.54.0/23 144.79.54.0/23
144.79.70.0/23 144.79.70.0/23
145.14.71.0/24 145.14.71.0/24
@@ -2028,6 +2042,7 @@
145.14.90.0/24 145.14.90.0/24
146.19.167.0/24 146.19.167.0/24
146.19.236.0/24 146.19.236.0/24
146.19.53.0/24
146.196.112.0/21 146.196.112.0/21
146.196.56.0/22 146.196.56.0/22
146.196.68.0/22 146.196.68.0/22
@@ -2043,6 +2058,7 @@
150.138.0.0/15 150.138.0.0/15
150.158.0.0/16 150.158.0.0/16
150.223.0.0/16 150.223.0.0/16
150.242.152.0/22
150.242.156.0/23 150.242.156.0/23
150.242.168.0/22 150.242.168.0/22
150.242.184.0/22 150.242.184.0/22
@@ -2111,26 +2127,28 @@
155.102.24.0/24 155.102.24.0/24
155.102.26.0/23 155.102.26.0/23
155.102.28.0/22 155.102.28.0/22
155.102.32.0/21 155.102.32.0/23
155.102.34.0/24
155.102.36.0/22
155.102.4.0/23 155.102.4.0/23
155.102.40.0/23 155.102.40.0/23
155.102.43.0/24 155.102.43.0/24
155.102.44.0/22 155.102.44.0/22
155.102.48.0/20 155.102.49.0/24
155.102.64.0/23 155.102.50.0/23
155.102.67.0/24 155.102.52.0/22
155.102.68.0/23 155.102.56.0/21
155.102.64.0/24
155.102.69.0/24
155.102.70.0/24 155.102.70.0/24
155.102.72.0/23 155.102.72.0/21
155.102.74.0/24
155.102.76.0/22
155.102.8.0/22 155.102.8.0/22
155.102.80.0/22 155.102.80.0/24
155.102.84.0/24 155.102.82.0/23
155.102.86.0/23 155.102.84.0/22
155.102.88.0/22 155.102.91.0/24
155.102.94.0/23 155.102.94.0/24
155.102.96.0/22 155.102.98.0/23
155.126.176.0/23 155.126.176.0/23
156.107.160.0/23 156.107.160.0/23
156.107.170.0/24 156.107.170.0/24
@@ -2185,7 +2203,6 @@
162.105.0.0/16 162.105.0.0/16
162.128.248.0/24 162.128.248.0/24
162.14.0.0/16 162.14.0.0/16
162.141.140.0/24
162.4.136.0/23 162.4.136.0/23
163.0.0.0/16 163.0.0.0/16
163.125.0.0/16 163.125.0.0/16
@@ -2210,11 +2227,14 @@
163.181.136.0/22 163.181.136.0/22
163.181.140.0/24 163.181.140.0/24
163.181.142.0/23 163.181.142.0/23
163.181.144.0/20 163.181.144.0/22
163.181.148.0/23
163.181.15.0/24 163.181.15.0/24
163.181.150.0/24
163.181.152.0/21
163.181.16.0/22 163.181.16.0/22
163.181.160.0/24 163.181.160.0/24
163.181.162.0/23 163.181.163.0/24
163.181.164.0/22 163.181.164.0/22
163.181.168.0/21 163.181.168.0/21
163.181.176.0/21 163.181.176.0/21
@@ -2263,7 +2283,6 @@
163.181.99.0/24 163.181.99.0/24
163.204.0.0/16 163.204.0.0/16
163.223.178.0/23 163.223.178.0/23
163.223.72.0/23
163.227.40.0/23 163.227.40.0/23
163.228.0.0/16 163.228.0.0/16
163.244.246.0/24 163.244.246.0/24
@@ -2271,6 +2290,7 @@
163.5.166.0/24 163.5.166.0/24
163.5.53.0/24 163.5.53.0/24
163.5.79.0/24 163.5.79.0/24
163.52.28.0/23
163.53.128.0/22 163.53.128.0/22
163.53.168.0/22 163.53.168.0/22
163.53.44.0/22 163.53.44.0/22
@@ -2279,11 +2299,11 @@
163.61.178.0/23 163.61.178.0/23
163.61.202.0/23 163.61.202.0/23
163.61.214.0/23 163.61.214.0/23
164.163.236.0/22
165.101.208.0/23 165.101.208.0/23
165.101.70.0/24 165.101.70.0/24
166.111.0.0/16 166.111.0.0/16
167.139.0.0/16 167.139.0.0/16
167.160.27.0/24
167.189.0.0/16 167.189.0.0/16
167.220.244.0/22 167.220.244.0/22
168.160.0.0/17 168.160.0.0/17
@@ -2291,7 +2311,7 @@
168.160.158.0/23 168.160.158.0/23
168.160.160.0/21 168.160.160.0/21
168.160.168.0/24 168.160.168.0/24
170.33.98.0/24 169.40.59.0/24
171.104.0.0/13 171.104.0.0/13
171.112.0.0/12 171.112.0.0/12
171.208.0.0/12 171.208.0.0/12
@@ -2348,18 +2368,19 @@
180.178.224.0/21 180.178.224.0/21
180.178.232.0/22 180.178.232.0/22
180.178.248.0/21 180.178.248.0/21
180.184.0.0/21 180.184.0.0/23
180.184.128.0/20 180.184.128.0/20
180.184.14.0/24 180.184.14.0/24
180.184.144.0/21 180.184.144.0/21
180.184.152.0/22 180.184.152.0/22
180.184.16.0/24
180.184.160.0/20 180.184.160.0/20
180.184.176.0/21 180.184.176.0/21
180.184.184.0/22 180.184.184.0/22
180.184.192.0/18 180.184.192.0/18
180.184.2.0/24
180.184.24.0/21 180.184.24.0/21
180.184.32.0/19 180.184.32.0/19
180.184.6.0/23
180.184.64.0/19 180.184.64.0/19
180.184.8.0/23 180.184.8.0/23
180.184.96.0/21 180.184.96.0/21
@@ -2445,14 +2466,12 @@
183.91.48.0/21 183.91.48.0/21
183.91.56.0/24 183.91.56.0/24
183.91.61.0/24 183.91.61.0/24
183.91.63.0/24
183.92.0.0/14 183.92.0.0/14
185.39.51.0/24 185.39.51.0/24
185.75.173.0/24 185.75.173.0/24
185.75.174.0/24 185.75.174.0/24
187.7.197.0/24
188.131.128.0/17 188.131.128.0/17
188.220.42.0/24
188.220.68.0/24
192.140.160.0/19 192.140.160.0/19
192.140.208.0/21 192.140.208.0/21
192.144.128.0/17 192.144.128.0/17
@@ -2461,7 +2480,6 @@
192.51.173.0/24 192.51.173.0/24
192.6.87.0/24 192.6.87.0/24
193.112.0.0/16 193.112.0.0/16
193.233.49.0/24
194.127.229.0/24 194.127.229.0/24
194.138.202.0/23 194.138.202.0/23
194.138.245.0/24 194.138.245.0/24
@@ -2476,6 +2494,9 @@
198.23.184.0/24 198.23.184.0/24
198.23.195.0/24 198.23.195.0/24
199.182.239.0/24 199.182.239.0/24
199.19.20.0/23
199.19.22.0/24
199.190.46.0/24
199.244.144.0/24 199.244.144.0/24
2.58.86.0/24 2.58.86.0/24
2.59.182.0/24 2.59.182.0/24
@@ -2598,7 +2619,7 @@
202.84.17.0/24 202.84.17.0/24
202.85.208.0/20 202.85.208.0/20
202.89.232.0/21 202.89.232.0/21
202.89.96.0/22 202.89.96.0/24
202.90.20.0/22 202.90.20.0/22
202.90.96.0/20 202.90.96.0/20
202.91.176.0/21 202.91.176.0/21
@@ -2620,6 +2641,7 @@
203.107.120.0/22 203.107.120.0/22
203.107.124.0/23 203.107.124.0/23
203.107.13.0/24 203.107.13.0/24
203.107.14.0/24
203.107.2.0/24 203.107.2.0/24
203.107.20.0/22 203.107.20.0/22
203.107.24.0/24 203.107.24.0/24
@@ -2627,6 +2649,7 @@
203.107.28.0/22 203.107.28.0/22
203.107.32.0/19 203.107.32.0/19
203.107.6.0/24 203.107.6.0/24
203.107.70.0/24
203.107.72.0/21 203.107.72.0/21
203.107.80.0/21 203.107.80.0/21
203.107.96.0/23 203.107.96.0/23
@@ -2713,6 +2736,7 @@
203.205.80.0/21 203.205.80.0/21
203.205.88.0/22 203.205.88.0/22
203.205.92.0/23 203.205.92.0/23
203.205.94.0/24
203.207.104.0/22 203.207.104.0/22
203.207.112.0/20 203.207.112.0/20
203.207.128.0/18 203.207.128.0/18
@@ -2905,8 +2929,8 @@
203.99.18.0/24 203.99.18.0/24
203.99.20.0/22 203.99.20.0/22
203.99.24.0/21 203.99.24.0/21
204.14.76.0/24
204.235.241.0/24 204.235.241.0/24
206.109.70.0/23
206.109.75.0/24 206.109.75.0/24
210.12.0.0/16 210.12.0.0/16
210.13.0.0/17 210.13.0.0/17
@@ -3108,8 +3132,8 @@
211.160.8.0/22 211.160.8.0/22
211.160.80.0/20 211.160.80.0/20
211.161.0.0/20 211.161.0.0/20
211.161.101.0/24 211.161.100.0/22
211.161.102.0/23 211.161.104.0/22
211.161.120.0/21 211.161.120.0/21
211.161.192.0/22 211.161.192.0/22
211.161.203.0/24 211.161.203.0/24
@@ -3120,6 +3144,7 @@
211.161.32.0/20 211.161.32.0/20
211.161.60.0/23 211.161.60.0/23
211.161.62.0/24 211.161.62.0/24
211.161.98.0/23
211.162.0.0/21 211.162.0.0/21
211.162.119.0/24 211.162.119.0/24
211.162.120.0/21 211.162.120.0/21
@@ -3183,9 +3208,9 @@
211.99.64.0/18 211.99.64.0/18
211.99.8.0/21 211.99.8.0/21
212.129.128.0/17 212.129.128.0/17
212.212.26.0/24
212.64.0.0/17 212.64.0.0/17
216.105.166.0/24 216.105.166.0/24
217.217.211.0/24
218.0.0.0/11 218.0.0.0/11
218.100.88.0/21 218.100.88.0/21
218.104.0.0/15 218.104.0.0/15
@@ -3253,10 +3278,9 @@
218.98.111.0/24 218.98.111.0/24
218.98.112.0/20 218.98.112.0/20
218.98.160.0/24 218.98.160.0/24
218.98.176.0/22 218.98.176.0/21
218.98.180.0/23
218.98.182.0/24
218.98.192.0/24 218.98.192.0/24
218.98.208.0/21
218.98.96.0/21 218.98.96.0/21
219.128.0.0/12 219.128.0.0/12
219.144.0.0/14 219.144.0.0/14
@@ -3322,9 +3346,10 @@
220.113.96.0/21 220.113.96.0/21
220.114.250.0/23 220.114.250.0/23
220.154.0.0/20 220.154.0.0/20
220.154.116.0/23
220.154.128.0/20 220.154.128.0/20
220.154.147.0/24 220.154.147.0/24
220.154.16.0/22 220.154.16.0/21
220.154.64.0/20 220.154.64.0/20
220.154.80.0/22 220.154.80.0/22
220.160.0.0/12 220.160.0.0/12
@@ -3417,7 +3442,6 @@
222.128.0.0/12 222.128.0.0/12
222.16.0.0/12 222.16.0.0/12
222.160.0.0/14 222.160.0.0/14
222.167.254.0/24
222.168.0.0/13 222.168.0.0/13
222.176.0.0/12 222.176.0.0/12
222.192.0.0/11 222.192.0.0/11
@@ -3531,7 +3555,6 @@
31.77.184.0/22 31.77.184.0/22
36.1.0.0/16 36.1.0.0/16
36.112.0.0/15 36.112.0.0/15
36.114.0.0/16
36.128.0.0/10 36.128.0.0/10
36.16.0.0/12 36.16.0.0/12
36.192.0.0/16 36.192.0.0/16
@@ -3558,16 +3581,16 @@
36.96.0.0/12 36.96.0.0/12
38.102.232.0/22 38.102.232.0/22
38.105.24.0/21 38.105.24.0/21
38.134.56.0/24
38.134.58.0/23 38.134.58.0/23
38.247.24.0/23 38.247.24.0/22
38.247.27.0/24 38.247.32.0/22
38.247.32.0/24
38.247.34.0/23
38.247.36.0/24 38.247.36.0/24
38.247.38.0/23 38.247.38.0/23
38.84.220.0/24 38.84.220.0/24
38.95.112.0/20 38.95.112.0/22
38.95.117.0/24
38.95.118.0/23
38.95.120.0/21
38.95.232.0/23 38.95.232.0/23
39.104.0.0/14 39.104.0.0/14
39.108.0.0/16 39.108.0.0/16
@@ -3579,7 +3602,6 @@
40.125.128.0/17 40.125.128.0/17
40.126.64.0/18 40.126.64.0/18
40.162.0.0/16 40.162.0.0/16
40.183.101.0/24
40.72.0.0/15 40.72.0.0/15
42.100.0.0/14 42.100.0.0/14
42.120.0.0/15 42.120.0.0/15
@@ -3608,8 +3630,10 @@
42.240.0.0/21 42.240.0.0/21
42.240.12.0/23 42.240.12.0/23
42.240.128.0/17 42.240.128.0/17
42.240.14.0/24
42.240.16.0/23 42.240.16.0/23
42.240.20.0/22 42.240.20.0/22
42.240.24.0/24
42.240.48.0/24 42.240.48.0/24
42.240.8.0/22 42.240.8.0/22
42.242.0.0/15 42.242.0.0/15
@@ -3649,43 +3673,45 @@
43.109.116.0/23 43.109.116.0/23
43.109.118.0/24 43.109.118.0/24
43.109.12.0/22 43.109.12.0/22
43.109.120.0/23 43.109.120.0/22
43.109.126.0/24 43.109.124.0/24
43.109.133.0/24 43.109.126.0/23
43.109.134.0/23 43.109.128.0/20
43.109.136.0/22
43.109.140.0/23
43.109.143.0/24
43.109.144.0/23 43.109.144.0/23
43.109.146.0/24 43.109.146.0/24
43.109.148.0/23 43.109.148.0/23
43.109.150.0/24 43.109.150.0/24
43.109.156.0/24 43.109.156.0/24
43.109.158.0/23
43.109.16.0/23 43.109.16.0/23
43.109.160.0/22 43.109.160.0/22
43.109.164.0/23 43.109.164.0/23
43.109.167.0/24 43.109.167.0/24
43.109.168.0/21 43.109.168.0/21
43.109.176.0/24 43.109.176.0/24
43.109.178.0/23
43.109.184.0/23 43.109.184.0/23
43.109.186.0/24 43.109.186.0/24
43.109.19.0/24 43.109.19.0/24
43.109.190.0/23 43.109.190.0/23
43.109.192.0/21 43.109.192.0/22
43.109.197.0/24
43.109.199.0/24
43.109.2.0/24 43.109.2.0/24
43.109.200.0/23 43.109.200.0/23
43.109.202.0/24 43.109.202.0/24
43.109.206.0/23 43.109.206.0/23
43.109.208.0/23 43.109.208.0/22
43.109.21.0/24 43.109.21.0/24
43.109.214.0/23 43.109.214.0/23
43.109.216.0/21 43.109.216.0/21
43.109.22.0/24 43.109.22.0/24
43.109.224.0/23 43.109.224.0/23
43.109.226.0/24 43.109.226.0/24
43.109.239.0/24 43.109.235.0/24
43.109.24.0/23 43.109.237.0/24
43.109.26.0/24 43.109.238.0/23
43.109.24.0/22
43.109.28.0/24 43.109.28.0/24
43.109.30.0/23 43.109.30.0/23
43.109.32.0/23 43.109.32.0/23
@@ -3705,13 +3731,14 @@
43.109.70.0/24 43.109.70.0/24
43.109.72.0/23 43.109.72.0/23
43.109.76.0/22 43.109.76.0/22
43.109.8.0/23
43.109.83.0/24 43.109.83.0/24
43.109.84.0/22 43.109.84.0/22
43.109.88.0/22 43.109.88.0/22
43.109.9.0/24
43.109.92.0/23 43.109.92.0/23
43.109.94.0/24 43.109.94.0/24
43.109.96.0/23 43.109.96.0/23
43.116.128.0/20
43.136.0.0/13 43.136.0.0/13
43.144.0.0/15 43.144.0.0/15
43.176.0.0/14 43.176.0.0/14
@@ -3893,7 +3920,8 @@
44.30.152.0/24 44.30.152.0/24
44.30.164.0/24 44.30.164.0/24
44.30.171.0/24 44.30.171.0/24
44.30.190.0/24 44.30.180.0/24
44.30.226.0/24
44.31.216.0/24 44.31.216.0/24
44.31.28.0/24 44.31.28.0/24
44.31.43.0/24 44.31.43.0/24
@@ -3943,6 +3971,7 @@
45.127.129.0/24 45.127.129.0/24
45.127.144.0/21 45.127.144.0/21
45.137.97.0/24 45.137.97.0/24
45.140.144.0/24
45.146.82.0/24 45.146.82.0/24
45.248.108.0/23 45.248.108.0/23
45.248.110.0/24 45.248.110.0/24
@@ -3963,7 +3992,6 @@
45.251.96.0/21 45.251.96.0/21
45.252.0.0/22 45.252.0.0/22
45.252.104.0/22 45.252.104.0/22
45.252.48.0/22
45.253.112.0/21 45.253.112.0/21
45.253.132.0/22 45.253.132.0/22
45.253.136.0/21 45.253.136.0/21
@@ -3981,7 +4009,6 @@
45.254.50.0/24 45.254.50.0/24
45.254.64.0/20 45.254.64.0/20
45.254.8.0/22 45.254.8.0/22
45.255.152.0/22
45.40.192.0/18 45.40.192.0/18
45.65.20.0/22 45.65.20.0/22
45.82.238.0/23 45.82.238.0/23
@@ -3990,13 +4017,12 @@
46.37.112.0/24 46.37.112.0/24
47.112.0.0/13 47.112.0.0/13
47.120.0.0/14 47.120.0.0/14
47.246.0.0/22 47.246.1.0/24
47.246.12.0/23 47.246.12.0/23
47.246.15.0/24 47.246.2.0/23
47.246.20.0/24 47.246.20.0/24
47.246.22.0/23 47.246.22.0/23
47.246.24.0/24 47.246.24.0/24
47.246.26.0/24
47.246.28.0/22 47.246.28.0/22
47.246.36.0/22 47.246.36.0/22
47.246.4.0/24 47.246.4.0/24
@@ -4006,7 +4032,6 @@
47.246.46.0/24 47.246.46.0/24
47.246.48.0/23 47.246.48.0/23
47.246.50.0/24 47.246.50.0/24
47.246.57.0/24
47.246.58.0/24 47.246.58.0/24
47.246.6.0/24 47.246.6.0/24
47.246.60.0/22 47.246.60.0/22
@@ -4048,7 +4073,7 @@
52.82.134.0/23 52.82.134.0/23
52.82.136.0/24 52.82.136.0/24
52.82.144.0/23 52.82.144.0/23
52.82.148.0/23 52.82.148.0/22
52.82.160.0/21 52.82.160.0/21
52.82.170.0/23 52.82.170.0/23
52.82.172.0/22 52.82.172.0/22
@@ -4095,7 +4120,7 @@
58.82.0.0/22 58.82.0.0/22
58.83.0.0/16 58.83.0.0/16
58.87.64.0/18 58.87.64.0/18
58.99.128.0/17 58.99.254.0/23
59.107.0.0/17 59.107.0.0/17
59.108.0.0/16 59.108.0.0/16
59.110.0.0/16 59.110.0.0/16
@@ -4147,6 +4172,7 @@
59.152.38.0/23 59.152.38.0/23
59.153.164.0/22 59.153.164.0/22
59.153.168.0/24 59.153.168.0/24
59.153.172.0/24
59.153.32.0/22 59.153.32.0/22
59.153.4.0/23 59.153.4.0/23
59.153.92.0/22 59.153.92.0/22
@@ -4177,6 +4203,7 @@
60.160.0.0/11 60.160.0.0/11
60.194.0.0/15 60.194.0.0/15
60.200.0.0/24 60.200.0.0/24
60.200.35.0/24
60.204.0.0/14 60.204.0.0/14
60.208.0.0/12 60.208.0.0/12
60.232.0.0/16 60.232.0.0/16
@@ -4212,7 +4239,6 @@
62.84.174.0/24 62.84.174.0/24
63.140.0.0/24 63.140.0.0/24
63.140.3.0/24 63.140.3.0/24
64.204.200.0/24
64.50.181.0/24 64.50.181.0/24
66.102.240.0/21 66.102.240.0/21
66.102.248.0/22 66.102.248.0/22
@@ -4239,10 +4265,12 @@
71.137.0.0/18 71.137.0.0/18
72.244.228.0/24 72.244.228.0/24
74.1.16.0/24 74.1.16.0/24
74.2.225.0/24
78.105.182.0/23 78.105.182.0/23
79.133.176.0/24 79.133.176.0/24
79.175.118.0/24 79.175.118.0/24
79.175.67.0/24
79.180.180.0/24
79.182.118.0/24
8.128.32.0/19 8.128.32.0/19
8.128.4.0/22 8.128.4.0/22
8.128.64.0/19 8.128.64.0/19
@@ -4295,5 +4323,4 @@
87.76.222.0/24 87.76.222.0/24
87.84.190.0/23 87.84.190.0/23
89.106.68.0/24 89.106.68.0/24
89.116.144.0/24
94.191.0.0/17 94.191.0.0/17
@@ -3,6 +3,7 @@
2001:4510:1480::/41 2001:4510:1480::/41
2001:4510:400::/40 2001:4510:400::/40
2001:4511:1480::/41 2001:4511:1480::/41
2001:550:1601::/48
2001:678:53c::/48 2001:678:53c::/48
2001:678:970::/48 2001:678:970::/48
2001:7fa:5::/48 2001:7fa:5::/48
@@ -12,11 +13,13 @@
2001:daa:1::/48 2001:daa:1::/48
2001:daa:2::/47 2001:daa:2::/47
2001:daa:4::/47 2001:daa:4::/47
2001:daa:6::/48
2001:daa:9::/48 2001:daa:9::/48
2001:dc7::/32 2001:dc7::/32
2001:dd8:1::/48 2001:dd8:1::/48
2001:dd9::/48 2001:dd9::/48
2001:df1:61c0::/48 2001:df1:61c0::/48
2001:df5:7800::/48
2001:df6:40::/48 2001:df6:40::/48
2400:1160::/32 2400:1160::/32
2400:3200::/32 2400:3200::/32
@@ -87,8 +90,8 @@
2400:9620::/32 2400:9620::/32
2400:a860:1::/48 2400:a860:1::/48
2400:a860:2::/47 2400:a860:2::/47
2400:a860:4::/47 2400:a860:4::/46
2400:a860:6::/48 2400:a860:8::/47
2400:a980::/29 2400:a980::/29
2400:ae00:1981::/48 2400:ae00:1981::/48
2400:b200::/32 2400:b200::/32
@@ -108,6 +111,7 @@
2401:1160::/32 2401:1160::/32
2401:1200::/48 2401:1200::/48
2401:1320::/32 2401:1320::/32
2401:18ef:1000::/44
2401:1d40::/32 2401:1d40::/32
2401:2780::/32 2401:2780::/32
2401:2a00:f000::/43 2401:2a00:f000::/43
@@ -155,6 +159,7 @@
2401:9a00:10::/46 2401:9a00:10::/46
2401:9a00::/44 2401:9a00::/44
2401:a140:1::/48 2401:a140:1::/48
2401:a540::/32
2401:b180::/32 2401:b180::/32
2401:b400:11::/48 2401:b400:11::/48
2401:b400:14::/48 2401:b400:14::/48
@@ -164,9 +169,6 @@
2401:b400::/45 2401:b400::/45
2401:b680::/32 2401:b680::/32
2401:be00::/32 2401:be00::/32
2401:c020:14::/48
2401:c020:6::/48
2401:c020:8::/47
2401:ca00::/32 2401:ca00::/32
2401:cb80::/32 2401:cb80::/32
2401:cc00::/32 2401:cc00::/32
@@ -183,12 +185,10 @@
2401:f860:100::/40 2401:f860:100::/40
2401:f860:88::/48 2401:f860:88::/48
2401:f860:90::/48 2401:f860:90::/48
2401:f860:92::/47 2401:f860:92::/48
2401:f860:94::/48 2401:f860:94::/48
2401:f860:97::/48 2401:f860:97::/48
2401:fa00:40::/48
2402:1440::/32 2402:1440::/32
2402:18a0::/32
2402:2000::/32 2402:2000::/32
2402:34e0::/32 2402:34e0::/32
2402:36e0::/44 2402:36e0::/44
@@ -219,6 +219,7 @@
2402:6f40::/48 2402:6f40::/48
2402:6fc0::/48 2402:6fc0::/48
2402:7040::/32 2402:7040::/32
2402:7060::/32
2402:7d80:240::/48 2402:7d80:240::/48
2402:7d80:8888::/48 2402:7d80:8888::/48
2402:7d80::/48 2402:7d80::/48
@@ -252,6 +253,7 @@
2402:f140:ff04::/48 2402:f140:ff04::/48
2402:f140:ff10::/46 2402:f140:ff10::/46
2402:f140:ff14::/48 2402:f140:ff14::/48
2402:f140:ff20::/46
2402:f140:ff24::/48 2402:f140:ff24::/48
2402:f8c0::/42 2402:f8c0::/42
2403:1b80::/48 2403:1b80::/48
@@ -308,12 +310,11 @@
2404:2280:123::/48 2404:2280:123::/48
2404:2280:125::/48 2404:2280:125::/48
2404:2280:126::/47 2404:2280:126::/47
2404:2280:128::/46 2404:2280:128::/47
2404:2280:12e::/48 2404:2280:12e::/48
2404:2280:130::/48 2404:2280:130::/48
2404:2280:134::/48 2404:2280:134::/48
2404:2280:136::/47 2404:2280:136::/47
2404:2280:138::/48
2404:2280:13b::/48 2404:2280:13b::/48
2404:2280:13c::/47 2404:2280:13c::/47
2404:2280:142::/48 2404:2280:142::/48
@@ -342,7 +343,6 @@
2404:2280:19e::/48 2404:2280:19e::/48
2404:2280:1a4::/46 2404:2280:1a4::/46
2404:2280:1a8::/47 2404:2280:1a8::/47
2404:2280:1b0::/48
2404:2280:1b2::/48 2404:2280:1b2::/48
2404:2280:1b4::/46 2404:2280:1b4::/46
2404:2280:1b8::/47 2404:2280:1b8::/47
@@ -366,7 +366,6 @@
2404:2280:1ee::/48 2404:2280:1ee::/48
2404:2280:1f0::/45 2404:2280:1f0::/45
2404:2280:1f8::/46 2404:2280:1f8::/46
2404:2280:1fe::/48
2404:2280:201::/48 2404:2280:201::/48
2404:2280:202::/47 2404:2280:202::/47
2404:2280:205::/48 2404:2280:205::/48
@@ -381,6 +380,7 @@
2404:2280:21d::/48 2404:2280:21d::/48
2404:2280:21e::/48 2404:2280:21e::/48
2404:2280:221::/48 2404:2280:221::/48
2404:2280:225::/48
2404:2280:226::/47 2404:2280:226::/47
2404:2280:259::/48 2404:2280:259::/48
2404:2280:25a::/47 2404:2280:25a::/47
@@ -388,10 +388,7 @@
2404:2280:265::/48 2404:2280:265::/48
2404:2280:266::/47 2404:2280:266::/47
2404:2280:268::/45 2404:2280:268::/45
2404:2280:270::/45 2404:2280:270::/44
2404:2280:278::/47
2404:2280:27b::/48
2404:2280:27c::/46
2404:2280:282::/47 2404:2280:282::/47
2404:2280:284::/47 2404:2280:284::/47
2404:2280:288::/46 2404:2280:288::/46
@@ -425,19 +422,18 @@
2404:2280:2dc::/47 2404:2280:2dc::/47
2404:2280:2df::/48 2404:2280:2df::/48
2404:2280:2f1::/48 2404:2280:2f1::/48
2404:2280:2f2::/48 2404:2280:2f2::/47
2404:2280:2f6::/47 2404:2280:2f4::/46
2404:2280:2f8::/47 2404:2280:2f8::/46
2404:2280:2fb::/48
2404:2280:2fc::/48 2404:2280:2fc::/48
2404:2280:303::/48 2404:2280:303::/48
2404:2280:304::/46 2404:2280:304::/46
2404:2280:308::/46 2404:2280:308::/45
2404:2280:30c::/47 2404:2280:310::/47
2404:2280:30e::/48
2404:2280:313::/48 2404:2280:313::/48
2404:2280:314::/48 2404:2280:314::/48
2404:2280:316::/47 2404:2280:316::/47
2404:2280:31a::/48
2404:3700::/48 2404:3700::/48
2404:4dc0::/32 2404:4dc0::/32
2404:6380:1000::/48 2404:6380:1000::/48
@@ -525,7 +521,6 @@
2406:280::/32 2406:280::/32
2406:3340::/32 2406:3340::/32
2406:3640:1::/48 2406:3640:1::/48
2406:4440:f000::/44
2406:4d00::/48 2406:4d00::/48
2406:52c0::/32 2406:52c0::/32
2406:5340:6666::/48 2406:5340:6666::/48
@@ -539,6 +534,7 @@
2406:840:1800::/48 2406:840:1800::/48
2406:840:180::/48 2406:840:180::/48
2406:840:1::/48 2406:840:1::/48
2406:840:200::/48
2406:840:20::/48 2406:840:20::/48
2406:840:2380::/48 2406:840:2380::/48
2406:840:2800::/48 2406:840:2800::/48
@@ -546,7 +542,7 @@
2406:840:2::/48 2406:840:2::/48
2406:840:2e0::/48 2406:840:2e0::/48
2406:840:3800::/48 2406:840:3800::/48
2406:840:380::/48 2406:840:380::/47
2406:840:3c2::/48 2406:840:3c2::/48
2406:840:3e0::/48 2406:840:3e0::/48
2406:840:4100::/47 2406:840:4100::/47
@@ -577,19 +573,24 @@
2406:840:860::/48 2406:840:860::/48
2406:840:880::/46 2406:840:880::/46
2406:840:90::/48 2406:840:90::/48
2406:840:9110::/47
2406:840:9112::/48
2406:840:9178::/48 2406:840:9178::/48
2406:840:9200::/40 2406:840:9200::/40
2406:840:9680::/44
2406:840:9700::/40 2406:840:9700::/40
2406:840:9804::/46 2406:840:9804::/46
2406:840:981a::/48 2406:840:981a::/48
2406:840:981c::/46 2406:840:981c::/46
2406:840:9962::/47 2406:840:9962::/48
2406:840:9964::/48 2406:840:9964::/48
2406:840:9966::/47 2406:840:9966::/47
2406:840:996c::/48 2406:840:996c::/48
2406:840:9970::/44 2406:840:9977::/48
2406:840:a00::/48
2406:840:a10::/47 2406:840:a10::/47
2406:840:a31::/48 2406:840:a31::/48
2406:840:a32::/48
2406:840:c02::/48 2406:840:c02::/48
2406:840:c60::/48 2406:840:c60::/48
2406:840:cb8::/48 2406:840:cb8::/48
@@ -606,12 +607,12 @@
2406:840:e330::/44 2406:840:e330::/44
2406:840:e57e::/48 2406:840:e57e::/48
2406:840:e600::/44 2406:840:e600::/44
2406:840:e620::/47
2406:840:e80f::/48 2406:840:e80f::/48
2406:840:eb00::/46 2406:840:eb00::/46
2406:840:eb04::/47 2406:840:eb04::/47
2406:840:eb07::/48 2406:840:eb07::/48
2406:840:eb08::/48 2406:840:eb08::/48
2406:840:eb0b::/48
2406:840:eb0f::/48 2406:840:eb0f::/48
2406:840:eb80::/42 2406:840:eb80::/42
2406:840:ee40::/47 2406:840:ee40::/47
@@ -624,7 +625,7 @@
2406:840:f401::/48 2406:840:f401::/48
2406:840:f402::/48 2406:840:f402::/48
2406:840:f44f::/48 2406:840:f44f::/48
2406:840:f680::/44 2406:840:f683::/48
2406:840:f889::/48 2406:840:f889::/48
2406:840:fa01::/48 2406:840:fa01::/48
2406:840:fa40::/48 2406:840:fa40::/48
@@ -667,7 +668,6 @@
2406:840:fdb0::/48 2406:840:fdb0::/48
2406:840:fdc0::/48 2406:840:fdc0::/48
2406:840:fe50::/47 2406:840:fe50::/47
2406:840:fe73::/48
2406:840:fe90::/46 2406:840:fe90::/46
2406:840:fe94::/48 2406:840:fe94::/48
2406:840:fe96::/47 2406:840:fe96::/47
@@ -730,7 +730,6 @@
2407:c080:6000::/36 2407:c080:6000::/36
2407:c080:8000::/36 2407:c080:8000::/36
2407:c080::/35 2407:c080::/35
2407:d9c0::/32
2408:4000::/22 2408:4000::/22
2408:8000:1000::/36 2408:8000:1000::/36
2408:8000:2000::/35 2408:8000:2000::/35
@@ -1274,6 +1273,7 @@
2408:8a27:4000::/35 2408:8a27:4000::/35
2409:2000::/31 2409:2000::/31
2409:2002::/32 2409:2002::/32
2409:2003:10::/44
2409:2003::/47 2409:2003::/47
2409:27fa::/48 2409:27fa::/48
2409:27fa:f000::/48 2409:27fa:f000::/48
@@ -1281,9 +1281,7 @@
2409:27fc::/48 2409:27fc::/48
2409:27fe::/33 2409:27fe::/33
2409:8000::/20 2409:8000::/20
240a:2000::/40 240a:2000::/24
240a:2001:1000::/36
240a:2001:100::/40
240a:4002:1b00::/40 240a:4002:1b00::/40
240a:4010:8000::/33 240a:4010:8000::/33
240a:4020:83a::/48 240a:4020:83a::/48
@@ -1379,7 +1377,20 @@
240a:42f0::/29 240a:42f0::/29
240a:42f8::/30 240a:42f8::/30
240a:6001::/48 240a:6001::/48
240a:a000::/20 240a:a000::/29
240a:a008::/30
240a:a00c::/31
240a:a00e:100::/40
240a:a00e::/48
240a:a00f::/32
240a:a010::/28
240a:a020::/27
240a:a040::/26
240a:a080::/25
240a:a100::/24
240a:a200::/23
240a:a400::/22
240a:a800::/21
240a:c000::/20 240a:c000::/20
240b:e001::/32 240b:e001::/32
240b:e002::/31 240b:e002::/31
@@ -1390,11 +1401,25 @@
240c:c000::/20 240c:c000::/20
240d:4000::/21 240d:4000::/21
240d:c000:f1e0::/47 240d:c000:f1e0::/47
240d:c000:f1e3::/48
240d:c000:f1e4::/47
240d:c000:f1ef::/48 240d:c000:f1ef::/48
240e::/20 240e::/20
2602:f2dc:9d::/48
2602:f32a:30::/44
2602:f46d:1::/48 2602:f46d:1::/48
2602:f486:f0::/48
2602:f919:fef::/48
2602:f92a:1300::/47
2602:f92a:1303::/48
2602:f92a:1305::/48
2602:f92a:1306::/48
2602:f92a:1310::/48
2602:f92a:1312::/48
2602:f92a:1320::/48
2602:f92a:1322::/48
2602:f92a:a460::/48 2602:f92a:a460::/48
2602:f92a:a462::/48 2602:f92a:a462::/47
2602:f92a:a468::/48 2602:f92a:a468::/48
2602:f92a:a46d::/48 2602:f92a:a46d::/48
2602:f92a:a474::/48 2602:f92a:a474::/48
@@ -1404,8 +1429,8 @@
2602:f9f6:402::/48 2602:f9f6:402::/48
2602:f9f6:450::/48 2602:f9f6:450::/48
2602:fa02:36::/48 2602:fa02:36::/48
2602:fa02:58::/48
2602:fa02:d00::/40 2602:fa02:d00::/40
2602:faa8:702::/48
2602:faa8:708::/47 2602:faa8:708::/47
2602:faa8:70f::/48 2602:faa8:70f::/48
2602:fbda:600::/48 2602:fbda:600::/48
@@ -1425,8 +1450,7 @@
2605:9d80:9042::/48 2605:9d80:9042::/48
2605:9d80:9071::/48 2605:9d80:9071::/48
2605:9d80:9092::/48 2605:9d80:9092::/48
2804:1e48:9002::/48 2a04:3e00::/29
2a04:3e00:1002::/48
2a04:f580:8010::/47 2a04:f580:8010::/47
2a04:f580:8090::/48 2a04:f580:8090::/48
2a04:f580:8210::/47 2a04:f580:8210::/47
@@ -1434,12 +1458,10 @@
2a04:f580:9010::/48 2a04:f580:9010::/48
2a04:f580:9012::/47 2a04:f580:9012::/47
2a04:f580:9020::/48 2a04:f580:9020::/48
2a04:f580:9030::/48
2a04:f580:9040::/48 2a04:f580:9040::/48
2a04:f580:9050::/48 2a04:f580:9050::/48
2a04:f580:9060::/48 2a04:f580:9060::/48
2a04:f580:9070::/48 2a04:f580:9070::/48
2a04:f580:9080::/48
2a04:f580:9210::/48 2a04:f580:9210::/48
2a04:f580:9212::/47 2a04:f580:9212::/47
2a04:f580:9220::/48 2a04:f580:9220::/48
@@ -1457,9 +1479,8 @@
2a06:9801:2ba::/48 2a06:9801:2ba::/48
2a06:9801:f95::/48 2a06:9801:f95::/48
2a06:9f81:4600::/44 2a06:9f81:4600::/44
2a06:9f81:4620::/44 2a06:9f81:4630::/44
2a06:9f81:4640::/43 2a06:9f81:4640::/44
2a06:9f81:4660::/44
2a06:a005:260::/43 2a06:a005:260::/43
2a06:a005:280::/43 2a06:a005:280::/43
2a06:a005:2a0::/44 2a06:a005:2a0::/44
@@ -1470,11 +1491,9 @@
2a0a:d681:e000::/40 2a0a:d681:e000::/40
2a0a:d682:d000::/36 2a0a:d682:d000::/36
2a0a:d682:e000::/35 2a0a:d682:e000::/35
2a0a:d685:1e0::/47 2a0a:d685:1e0::/48
2a0a:d685:1fb::/48
2a0a:d685:1fd::/48 2a0a:d685:1fd::/48
2a0a:d685:1fe::/47 2a0a:d685:1ff::/48
2a0a:d685:200::/47
2a0a:d685:300::/40 2a0a:d685:300::/40
2a0a:d687:f001::/48 2a0a:d687:f001::/48
2a0a:d687:f004::/47 2a0a:d687:f004::/47
@@ -1483,68 +1502,95 @@
2a0b:2542:300::/40 2a0b:2542:300::/40
2a0b:4340:97::/48 2a0b:4340:97::/48
2a0b:4e07:230::/44 2a0b:4e07:230::/44
2a0b:a304::/30
2a0c:b641:571::/48 2a0c:b641:571::/48
2a0c:b641:573::/48 2a0c:b641:573::/48
2a0c:e641::/32 2a0c:e641::/32
2a0d:2681::/32 2a0d:2681::/32
2a0d:2901::/32
2a0d:88c4::/30
2a0d:c7c7:400::/38 2a0d:c7c7:400::/38
2a0d:d941::/36 2a0d:d941::/36
2a0e:4001:3000::/40
2a0e:4001:9000::/36 2a0e:4001:9000::/36
2a0e:4005:ff20::/48 2a0e:4005:ff20::/48
2a0e:4005:ffd0::/48
2a0e:4005:ffdd::/48 2a0e:4005:ffdd::/48
2a0e:4007:1::/48
2a0e:4007:2::/47
2a0e:4007:4::/48
2a0e:4007:6::/47
2a0e:aa06:400::/44 2a0e:aa06:400::/44
2a0e:aa06:440::/48 2a0e:aa06:440::/48
2a0e:aa06:450::/44 2a0e:aa06:450::/44
2a0e:aa06:490::/44 2a0e:aa06:490::/44
2a0e:aa07:f0dc::/48
2a0e:aa07:f0df::/48
2a0e:b107:14a0::/44 2a0e:b107:14a0::/44
2a0e:b107:1522::/48 2a0e:b107:1522::/48
2a0e:b107:1f0::/47 2a0e:b107:1f0::/47
2a0e:b107:2440::/44
2a0e:b107:740::/44 2a0e:b107:740::/44
2a0e:b107:da0::/44 2a0e:b107:da0::/44
2a0f:1cc5:110::/44 2a0f:1cc5:10::/46
2a0f:1cc5:130::/44 2a0f:1cc5:130::/44
2a0f:1cc5:140::/42 2a0f:1cc5:140::/44
2a0f:1cc5:14::/46
2a0f:1cc5:1600::/44 2a0f:1cc5:1600::/44
2a0f:1cc5:170::/44
2a0f:1cc5:1c01::/48 2a0f:1cc5:1c01::/48
2a0f:1cc5:1c02::/48 2a0f:1cc5:1c02::/48
2a0f:1cc5:1c30::/48 2a0f:1cc5:1c20::/48
2a0f:1cc5:2000::/40 2a0f:1cc5:2000::/40
2a0f:1cc5:2510::/44 2a0f:1cc5:2550::/48
2a0f:1cc5:2520::/44
2a0f:1cc5:2600::/41 2a0f:1cc5:2600::/41
2a0f:1cc5:2680::/42 2a0f:1cc5:2680::/42
2a0f:1cc5:2d01::/48 2a0f:1cc5:2d01::/48
2a0f:1cc5:3203::/48 2a0f:1cc5:3203::/48
2a0f:1cc5:3210::/44
2a0f:1cc5:3222::/48 2a0f:1cc5:3222::/48
2a0f:1cc5:3700::/43 2a0f:1cc5:3700::/43
2a0f:1cc5:3720::/48
2a0f:1cc5:4300::/40 2a0f:1cc5:4300::/40
2a0f:1cc5:4508::/45 2a0f:1cc5:4508::/45
2a0f:1cc5:4510::/45 2a0f:1cc5:4510::/44
2a0f:1cc5:451c::/46 2a0f:1cc5:4520::/46
2a0f:1cc5:4560::/44
2a0f:1cc5:45ff::/48 2a0f:1cc5:45ff::/48
2a0f:1cc5:4600::/39 2a0f:1cc5:4600::/39
2a0f:1cc5:49f0::/48 2a0f:1cc5:49f0::/48
2a0f:1cc5:57fb::/48
2a0f:1cc5:57fc::/47
2a0f:1cc5:57ff::/48
2a0f:1cc5:600::/47 2a0f:1cc5:600::/47
2a0f:1cc5:603::/48 2a0f:1cc5:603::/48
2a0f:1cc5:620::/48
2a0f:1cc5:642::/48 2a0f:1cc5:642::/48
2a0f:1cc5:644::/48 2a0f:1cc5:644::/48
2a0f:1cc5:662::/48 2a0f:1cc5:661::/48
2a0f:1cc5:6a0::/47 2a0f:1cc5:6a0::/47
2a0f:1cc5:d00::/48
2a0f:1cc5:f00::/46 2a0f:1cc5:f00::/46
2a0f:1cc5:f05::/48 2a0f:1cc5:f05::/48
2a0f:1cc5:f06::/47 2a0f:1cc5:f06::/47
2a0f:1cc5:f08::/47 2a0f:1cc5:f08::/47
2a0f:1cc5:f10::/48
2a0f:1cc5:f12::/47
2a0f:1cc5:fff::/48 2a0f:1cc5:fff::/48
2a0f:1cc6:b110::/47 2a0f:1cc6:b110::/48
2a0f:1cc6:b210::/48 2a0f:1cc6:b210::/47
2a0f:1cc6:b212::/48 2a0f:1cc6:b212::/48
2a0f:1cc6:b240::/43 2a0f:1cc6:b240::/43
2a0f:1cc6:b271::/48
2a0f:2384::/30
2a0f:2706::/32 2a0f:2706::/32
2a0f:6280:1400::/43 2a0f:4684::/30
2a0f:6280:1440::/42 2a0f:6280:1400::/41
2a0f:6280:1480::/44 2a0f:6280:1480::/44
2a0f:6281::/32 2a0f:6280:14a0::/44
2a0f:6280:7000::/38
2a0f:6280:7400::/39
2a0f:6280:7800::/39
2a0f:6284:4c00::/44
2a0f:6284:4c20::/44 2a0f:6284:4c20::/44
2a0f:6284:4c30::/48 2a0f:6284:4c30::/48
2a0f:6284:4c40::/43 2a0f:6284:4c40::/43
@@ -1552,64 +1598,61 @@
2a0f:6284:4c80::/43 2a0f:6284:4c80::/43
2a0f:6284:4ca0::/44 2a0f:6284:4ca0::/44
2a0f:6284:4cc0::/43 2a0f:6284:4cc0::/43
2a0f:7304::/30
2a0f:85c1:bfe::/48 2a0f:85c1:bfe::/48
2a0f:9400:6110::/48 2a0f:9400:6110::/48
2a0f:9fc0::/29 2a0f:a704::/30
2a0f:a140::/29
2a10:ccc0:cc1::/48 2a10:ccc0:cc1::/48
2a10:ccc0:cc2::/48 2a10:ccc0:cc2::/48
2a10:ccc0:ccc::/48 2a10:ccc0:ccc::/48
2a10:fa81:d00::/40 2a10:fa81:d00::/40
2a10:fa86:4000::/36
2a10:fa86::/34 2a10:fa86::/34
2a10:fa86:c000::/34 2a10:fa86:c000::/34
2a12:3fc6:2::/48 2a12:3fc6:4::/48
2a12:3fc6::/47 2a12:3fc6::/46
2a12:cb40:1::/48 2a12:cb40:1::/48
2a12:cb40:2::/48 2a12:cb40:2::/48
2a12:cb41:1200::/44 2a12:cb41:1200::/44
2a12:cb41:1300::/44 2a12:cb41:1300::/44
2a12:cb41:13f0::/44 2a12:cb41:13f0::/44
2a12:cb41:600::/44 2a12:cb41:600::/44
2a12:cb46:6000::/38
2a12:cb46::/36 2a12:cb46::/36
2a12:cb47:ffff::/48 2a12:cb47:ffff::/48
2a13:1801:180::/43 2a13:1801:180::/43
2a13:1801:200::/44 2a13:1801:200::/44
2a13:1802::/43 2a13:1802::/43
2a13:8c87::/32 2a13:9500:194::/48
2a13:9500:194::/47
2a13:a5c3:f000::/40 2a13:a5c3:f000::/40
2a13:a5c3:ff50::/44 2a13:a5c3:ff50::/44
2a13:a5c5::/48 2a13:a5c5::/48
2a13:aac4:f000::/44 2a13:aac4:f000::/44
2a13:b487:1200::/42 2a13:b487:1200::/44
2a13:c8c3:e803::/48 2a13:b487:1220::/43
2a13:e5c0:ee02::/48 2a13:e5c0:ee02::/48
2a14:4380::/29
2a14:5f00::/29 2a14:5f00::/29
2a14:67c1:b500::/40 2a14:67c1:b500::/40
2a14:67c2:519::/48
2a14:67c2:520::/48 2a14:67c2:520::/48
2a14:67c3:1100::/47 2a14:67c3:1100::/47
2a14:67c3:190::/47 2a14:67c3:190::/47
2a14:67c3:192::/48 2a14:67c3:192::/48
2a14:67c3:30::/44 2a14:67c3:30::/44
2a14:67c3:8800::/44
2a14:7580:740::/44 2a14:7580:740::/44
2a14:7580:d10::/44 2a14:7580:d00::/43
2a14:7580:d20::/46 2a14:7580:d20::/46
2a14:7580:d41::/48
2a14:7580:d42::/47
2a14:7580:ff64::/48
2a14:7580:ffee::/48 2a14:7580:ffee::/48
2a14:7580:fff3::/48 2a14:7580:fff3::/48
2a14:7580:fffa::/48
2a14:7581:3810::/48 2a14:7581:3810::/48
2a14:7581:3814::/48 2a14:7581:fe1::/48
2a14:7581:3818::/48 2a14:7583:e900::/48
2a14:7582:7000::/36
2a14:7583:efe7::/48 2a14:7583:efe7::/48
2a14:7583:efef::/48
2a14:7583:f411::/48 2a14:7583:f411::/48
2a14:7583:f4f0::/48 2a14:7583:f4f0::/48
2a14:7583:f4f4::/48 2a14:7583:f4f4::/48
2a14:7583:f4fe::/48
2a14:7583:f701::/48 2a14:7583:f701::/48
2a14:7583:f703::/48 2a14:7583:f703::/48
2a14:7583:f704::/47 2a14:7583:f704::/47
@@ -1620,18 +1663,17 @@
2a14:7583:f744::/48 2a14:7583:f744::/48
2a14:7583:f764::/48 2a14:7583:f764::/48
2a14:7586:6103::/48 2a14:7586:6103::/48
2a14:7586:6104::/47 2a14:7586:6104::/48
2a14:7586:6106::/48 2a14:7586:6106::/47
2a14:7586:6108::/48 2a14:7586:6108::/48
2a14:7586:6110::/48 2a14:7586:6110::/48
2a14:7586:6113::/48
2a14:7586:6115::/48
2a14:7586:6300::/44 2a14:7586:6300::/44
2a14:ae00:50::/44
2c0f:f7a8:8011::/48 2c0f:f7a8:8011::/48
2c0f:f7a8:8050::/48 2c0f:f7a8:8050::/48
2c0f:f7a8:805f::/48 2c0f:f7a8:805f::/48
2c0f:f7a8:8150::/48 2c0f:f7a8:8150::/48
2c0f:f7a8:815f::/48 2c0f:f7a8:815f::/48
2c0f:f7a8:8211::/48 2c0f:f7a8:8211::/48
2c0f:f7a8:9020::/48
2c0f:f7a8:9041::/48 2c0f:f7a8:9041::/48
2c0f:f7a8:9220::/48
@@ -4,6 +4,9 @@
1000giri.net 1000giri.net
10beasts.net 10beasts.net
10musume.com 10musume.com
123av.com
123av.me
123av.org
12bet.com 12bet.com
12vpn.com 12vpn.com
12vpn.net 12vpn.net
@@ -56,6 +59,7 @@
6parker.com 6parker.com
6parknews.com 6parknews.com
7capture.com 7capture.com
7x24hrs.com
8-d.com 8-d.com
85cc.us 85cc.us
881903.com 881903.com
@@ -128,6 +132,7 @@ agoogleaday.com
agro.hk agro.hk
ai.dev ai.dev
ai.studio ai.studio
aidc.com.tw
aihub.top aihub.top
aiosearch.com aiosearch.com
aiph.net aiph.net
@@ -213,19 +218,15 @@ aoxvpn.com
apartmentratings.com apartmentratings.com
apartments.com apartments.com
apat1989.org apat1989.org
api-gl.lbkrs.com
api-secure.recaptcha.net api-secure.recaptcha.net
api-verify.recaptcha.net api-verify.recaptcha.net
api.ai api.ai
api.futunn.com
api.lbkrs.com
api.moomoobull.com api.moomoobull.com
api.palworldgame.com api.palworldgame.com
api.pureapk.com api.pureapk.com
api.recaptcha.net api.recaptcha.net
api.shuaiapi.com api.shuaiapi.com
api.steampowered.com api.steampowered.com
api5.futunn.com
apiary.io apiary.io
apigee.com apigee.com
apk.support apk.support
@@ -530,6 +531,7 @@ bloomberg.de
bloombergview.com bloombergview.com
bloomfortune.com bloomfortune.com
blubrry.com blubrry.com
blue-plus.net
bmdru.com bmdru.com
bnbstatic.com bnbstatic.com
bnext.com.tw bnext.com.tw
@@ -552,6 +554,7 @@ bowenpress.com
boxpn.com boxpn.com
boxun.com boxun.com
boxun.tv boxun.tv
boylove.cc
boysmaster.com boysmaster.com
br.st br.st
braumeister.org braumeister.org
@@ -612,6 +615,7 @@ byrut.org
c-est-simple.com c-est-simple.com
c-span.org c-span.org
c-spanvideo.org c-spanvideo.org
c.go-mpulse.net
c.mi.com c.mi.com
c2cx.com c2cx.com
c3pool.com c3pool.com
@@ -627,6 +631,7 @@ camfrog.com
campaign-archive.com campaign-archive.com
campaignforuyghurs.org campaignforuyghurs.org
cams.com cams.com
cangku.moe
canva.com canva.com
canyu.org canyu.org
caobian.info caobian.info
@@ -669,7 +674,6 @@ cdjp.org
cdn-images.mailchimp.com cdn-images.mailchimp.com
cdn-telegram.org cdn-telegram.org
cdn.arstechnica.net cdn.arstechnica.net
cdn.futustatic.com
cdn.jwplayer.com cdn.jwplayer.com
cdn.printfriendly.com cdn.printfriendly.com
cdn.seatguru.com cdn.seatguru.com
@@ -757,6 +761,7 @@ chinesedemocracy.com
chinesegay.org chinesegay.org
chinesen.de chinesen.de
chinesenews.net.au chinesenews.net.au
chineseposters.net
chineseradioseattle.com chineseradioseattle.com
chineseupress.com chineseupress.com
chingcheong.com chingcheong.com
@@ -819,7 +824,6 @@ cn.fmnnow.com
cn.sandscotaicentral.com cn.sandscotaicentral.com
cn.shafaqna.com cn.shafaqna.com
cn.theaustralian.com.au cn.theaustralian.com.au
cn.uptodown.com
cna.com.tw cna.com.tw
cnbbnews.wordpress.com cnbbnews.wordpress.com
cnbeta.com.tw cnbeta.com.tw
@@ -856,6 +860,7 @@ comparitech.com
compileheart.com compileheart.com
connect.facebook.net connect.facebook.net
conoha.jp conoha.jp
console.typesafe.ai
contests.twilio.com contests.twilio.com
cool18.com cool18.com
coolaler.com coolaler.com
@@ -871,6 +876,7 @@ counter.social
coursehero.com coursehero.com
covenantswatch.org.tw covenantswatch.org.tw
coze.com coze.com
cpc.com.tw
cpj.org cpj.org
cpu-monkey.com cpu-monkey.com
cq99.us cq99.us
@@ -893,6 +899,7 @@ crrev.com
crucial.com crucial.com
crunchyroll.com crunchyroll.com
cruxpool.com cruxpool.com
csc.com.tw
csdparty.com csdparty.com
csis.org csis.org
csmonitor.com csmonitor.com
@@ -900,6 +907,7 @@ css.pixnet.in
csuchen.de csuchen.de
csw.org.uk csw.org.uk
ct.org.tw ct.org.tw
ctee.com.tw
ctinets.com ctinets.com
ctinews.com ctinews.com
ctinsider.com ctinsider.com
@@ -981,6 +989,7 @@ deviantart.net
devio.us devio.us
devpn.com devpn.com
devv.ai devv.ai
dh.net
diaoyuislands.org diaoyuislands.org
digiland.tw digiland.tw
digisfera.com digisfera.com
@@ -1047,7 +1056,6 @@ dougscripts.com
doujincafe.com doujincafe.com
dowjones.io dowjones.io
download.dappcdn.com download.dappcdn.com
download.futunn.com
dpool.top dpool.top
dpp.org.tw dpp.org.tw
dpr.info dpr.info
@@ -1168,6 +1176,7 @@ everipedia.org
evschool.net evschool.net
exchristian.hk exchristian.hk
exhentai.org exhentai.org
eximbank.com.tw
exmo.com exmo.com
exmormon.org exmormon.org
expatshield.com expatshield.com
@@ -1397,6 +1406,7 @@ futuremessage.org
futustatic.com futustatic.com
fututrade.com fututrade.com
fututrustee.com fututrustee.com
fuyin116.com
fw.cm fw.cm
fxcm-chinese.com fxcm-chinese.com
fxnetworks.com fxnetworks.com
@@ -1406,6 +1416,7 @@ g.ai
g.co g.co
g0v.social g0v.social
g6hentai.com g6hentai.com
ga.jspm.io
gab.com gab.com
gabocorp.com gabocorp.com
gagaoolala.com gagaoolala.com
@@ -1819,7 +1830,9 @@ haiwaikan.com
hakkatv.org.tw hakkatv.org.tw
halktv.com.tr halktv.com.tr
hanime.tv hanime.tv
hanime1.com
hanime1.me hanime1.me
hanimeone.me
hardsextube.com hardsextube.com
hautelook.com hautelook.com
hautelookcdn.com hautelookcdn.com
@@ -1841,6 +1854,8 @@ help.byspotify.com
helpeachpeople.com helpeachpeople.com
helpster.de helpster.de
hembed.com hembed.com
hentai.tv
hentaiclub.net
heqinglian.net heqinglian.net
heritage.org heritage.org
herokuapp.com herokuapp.com
@@ -1883,6 +1898,7 @@ hkcnews.com
hkcoc.com hkcoc.com
hkcoc.weather.com.hk hkcoc.weather.com.hk
hkdc.us hkdc.us
hkej.com
hket.com hket.com
hkfaa.com hkfaa.com
hkgalden.com hkgalden.com
@@ -1985,6 +2001,7 @@ iam.soy
iask.ca iask.ca
iavian.net iavian.net
ibvpn.com ibvpn.com
icdf.org.tw
icedrive.net icedrive.net
icij.org icij.org
icl-fi.org icl-fi.org
@@ -2042,6 +2059,7 @@ indianarrative.com
indiandefensenews.in indiandefensenews.in
indiatoday.in indiatoday.in
indiemerch.com indiemerch.com
indsr.org.tw
inews-api.tvb.com inews-api.tvb.com
info-graf.fr info-graf.fr
infosec.exchange infosec.exchange
@@ -2068,6 +2086,7 @@ investigating.wordpress.com
investing.com investing.com
invidio.us invidio.us
inxian.com inxian.com
ipac.global
ipdefenseforum.com ipdefenseforum.com
ipfire.org ipfire.org
ipfs.4everland.io ipfs.4everland.io
@@ -2126,9 +2145,11 @@ japantimes.co.jp
jav321.com jav321.com
javakiba.org javakiba.org
javbus.com javbus.com
javchu.com
javdb.com javdb.com
javfinder.ai javfinder.ai
javfor.me javfor.me
javfree.me
javhub.net javhub.net
javhuge.com javhuge.com
javlibrary.com javlibrary.com
@@ -2150,6 +2171,7 @@ jintian.net
jinx.com jinx.com
jitouch.com jitouch.com
jkb.cc jkb.cc
jkforum.net
jma.go.jp jma.go.jp
jmsc.hku.hk jmsc.hku.hk
jmscult.com jmscult.com
@@ -2197,9 +2219,11 @@ kex.com
keycdn.com keycdn.com
kfor.com kfor.com
khatrimaza.org khatrimaza.org
khc.edu.tw
kichiku-doujinko.com kichiku-doujinko.com
kik.com kik.com
killwall.com killwall.com
kimootoko.net
kindle4rss.com kindle4rss.com
kindleren.com kindleren.com
kingdomsalvation.org kingdomsalvation.org
@@ -2242,6 +2266,7 @@ lala.im
lama.com.tw lama.com.tw
lamayeshe.com lamayeshe.com
lamnia.co.uk lamnia.co.uk
landbank.com.tw
landofhope.tv landofhope.tv
lantern.io lantern.io
laogai.org laogai.org
@@ -2305,6 +2330,7 @@ linkedin.com
linktr.ee linktr.ee
linux.do linux.do
linux.org.hk linux.org.hk
linux.sb
liquiditytp.com liquiditytp.com
liquidvpn.com liquidvpn.com
listennotes.com listennotes.com
@@ -2359,7 +2385,6 @@ lvv2.com
lyfhk.net lyfhk.net
lzjscript.com lzjscript.com
lzmtnews.org lzmtnews.org
m.hkgalden.com
m.me m.me
m.moegirl.org m.moegirl.org
macgamestore.com macgamestore.com
@@ -2395,6 +2420,7 @@ mastodon.social
mastodon.xyz mastodon.xyz
matainja.com matainja.com
material.io material.io
matichon.co.th
matome-plus.com matome-plus.com
matome-plus.net matome-plus.net
matrix.org matrix.org
@@ -2438,7 +2464,9 @@ meridian-trust.org
meripet.com meripet.com
merit-times.com.tw merit-times.com.tw
messenger.com messenger.com
meta.ai
meta.com meta.com
metaaivm.com
metafilter.com metafilter.com
metamask.io metamask.io
metart.com metart.com
@@ -2478,13 +2506,17 @@ mingshengbao.com
minhhue.net minhhue.net
miningpoolhub.com miningpoolhub.com
ministrybooks.org ministrybooks.org
minkch.com
minzhuzhongguo.org minzhuzhongguo.org
miraheze.org miraheze.org
mirdc.org.tw
miroguide.com miroguide.com
mirror.xyz mirror.xyz
mirrorbooks.com mirrorbooks.com
mirrormedia.mg mirrormedia.mg
missav.ai
missav.com missav.com
missav.live
missav.ws missav.ws
mistral.ai mistral.ai
mitbbs.com mitbbs.com
@@ -2508,6 +2540,7 @@ moby.to
mod.io mod.io
modernchinastudies.org modernchinastudies.org
moeerolibrary.com moeerolibrary.com
moeli-desu.com
moeshare.cc moeshare.cc
mog.com mog.com
mohu.club mohu.club
@@ -2535,6 +2568,7 @@ mos.ru
mosavi.io mosavi.io
motherless.com motherless.com
movements.org movements.org
movie.eroterest.net
moviefap.com moviefap.com
mpettis.com mpettis.com
mpfinance.com mpfinance.com
@@ -2548,6 +2582,7 @@ mthruf.com
mubi.com mubi.com
mullvad.net mullvad.net
multiply.com multiply.com
muse.ai
music.amazon.com music.amazon.com
musixmatch.com musixmatch.com
muzi.com muzi.com
@@ -2586,6 +2621,7 @@ national-lottery.co.uk
nationalawakening.org nationalawakening.org
nationalinterest.org nationalinterest.org
nationalreview.com nationalreview.com
nationthailand.com
nationwide.com nationwide.com
naughtyamerica.com naughtyamerica.com
naver.com naver.com
@@ -2597,6 +2633,7 @@ nbyy.tv
nchrd.org nchrd.org
ncn.org ncn.org
ndi.org ndi.org
ned.org
nekoslovakia.net nekoslovakia.net
neo-miracle.com neo-miracle.com
neodb.social neodb.social
@@ -2665,6 +2702,9 @@ nitter.net
niu.moe niu.moe
niusnews.com niusnews.com
njactb.org njactb.org
njav.com
njav.tv
njavtv.com
nlfreevpn.com nlfreevpn.com
nmsl.website nmsl.website
nnews.eu nnews.eu
@@ -2677,6 +2717,7 @@ nordstromimage.com
nordstromrack.com nordstromrack.com
nordvpn.com nordvpn.com
nos.nl nos.nl
note.com
notepad-plus-plus.org notepad-plus-plus.org
nottinghampost.com nottinghampost.com
now.com now.com
@@ -2687,6 +2728,7 @@ npnt.me
npsboost.com npsboost.com
nradio.me nradio.me
nrk.no nrk.no
nstc.org.tw
ntd.tv ntd.tv
ntdtv.com ntdtv.com
ntdtv.com.tw ntdtv.com.tw
@@ -2768,12 +2810,8 @@ ooni.org
open.firstory.me open.firstory.me
openai.com openai.com
openapi-quote.longbridge.cn openapi-quote.longbridge.cn
openapi-quote.longbridge.com
openapi-trade.longbridge.cn openapi-trade.longbridge.cn
openapi-trade.longbridge.com
openapi.futunn.com
openapi.longbridge.cn openapi.longbridge.cn
openapi.longbridge.com
openart.ai openart.ai
opencritic.com opencritic.com
opendemocracy.net opendemocracy.net
@@ -2920,6 +2958,7 @@ plexvpn.pro
plurk.com plurk.com
plus.codes plus.codes
pmatehunter.com pmatehunter.com
po-kaki-to.com
po2b.com po2b.com
podbean.com podbean.com
podcast.co podcast.co
@@ -2929,6 +2968,7 @@ poe.com
points-media.com points-media.com
pokerstars.com pokerstars.com
pokerstars.net pokerstars.net
poland.tw
politicalchina.org politicalchina.org
poloniex.com poloniex.com
polymarket.com polymarket.com
@@ -3024,14 +3064,15 @@ qianglie.com
qiangwaikan.com qiangwaikan.com
qiangyou.org qiangyou.org
qianmo.tw qianmo.tw
qingse.one
qiwen.lu qiwen.lu
qmp4.com qmp4.com
qobuz.com
qoos.com qoos.com
qq.co.za qq.co.za
qstatus.com qstatus.com
qtcard.futunn.com
qtcardfthk.futufin.com
qtrac.eu qtrac.eu
quakemachinex.com
questvisual.com questvisual.com
quitccp.org quitccp.org
quiz.directory quiz.directory
@@ -3122,15 +3163,18 @@ rlwlw.com
rmbl.ws rmbl.ws
roblox.com roblox.com
robustnessiskey.com robustnessiskey.com
roc-taiwan.org
rocket-inc.net rocket-inc.net
rocket.chat rocket.chat
rocksdb.org rocksdb.org
rocmgov.org
rojo.com rojo.com
rolfoundation.org rolfoundation.org
rolia.net rolia.net
rolsociety.org rolsociety.org
ronjoneswriter.com ronjoneswriter.com
rou.video rou.video
roushuwo.com
rsdlmonitor.com rsdlmonitor.com
rsf-chinese.org rsf-chinese.org
rsf.org rsf.org
@@ -3264,6 +3308,7 @@ simpleswap.io
simplex.chat simplex.chat
sina.com.hk sina.com.hk
sinchew.com.my sinchew.com.my
sing-box.sagernet.org
singaporepools.com.sg singaporepools.com.sg
singlelogin.se singlelogin.se
singtao.com singtao.com
@@ -3433,7 +3478,7 @@ supchina.com
superpages.com superpages.com
supervpn.net supervpn.net
superzooi.com superzooi.com
support.futunn.com supjav.com
supremecourt.gov supremecourt.gov
suprememastertv.com suprememastertv.com
surfeasy.com surfeasy.com
@@ -3462,10 +3507,12 @@ taa-usa.org
taaze.tw taaze.tw
taedp.org.tw taedp.org.tw
tagwalk.com tagwalk.com
taiav.com
tails.net tails.net
taipeisociety.org taipeisociety.org
taipeitimes.com taipeitimes.com
taisounds.com taisounds.com
taiwanembassy.org
taiwanhot.net taiwanhot.net
taiwanjustice.net taiwanjustice.net
taiwanncf.org.tw taiwanncf.org.tw
@@ -3518,6 +3565,7 @@ tew.org
textnow.com textnow.com
textnow.me textnow.me
tfc-taiwan.org.tw tfc-taiwan.org.tw
tfd.org.tw
tfhub.dev tfhub.dev
tfiflve.com tfiflve.com
tg-me.com tg-me.com
@@ -3694,8 +3742,6 @@ totalvpn.com
tou.tv tou.tv
tpi.org.tw tpi.org.tw
tracfone.com tracfone.com
trade.futunn.com
trade.longportapp.com
tradeup.com tradeup.com
tradingview.com tradingview.com
translate.goog translate.goog
@@ -3713,6 +3759,7 @@ tryai.dev
tryheart.jp tryheart.jp
tsdr.uspto.gov tsdr.uspto.gov
tt1069.com tt1069.com
ttl.com.tw
tttan.com tttan.com
ttv.com.tw ttv.com.tw
ttvnw.net ttvnw.net
@@ -3765,6 +3812,7 @@ tweetwally.com
tweez.net tweez.net
twelve.today twelve.today
twerkingbutt.com twerkingbutt.com
twfhcsec.com.tw
twftp.org twftp.org
twgov.tw twgov.tw
twgreatdaily.com twgreatdaily.com
@@ -3807,6 +3855,7 @@ twt.tl
twtkr.com twtkr.com
twttr.com twttr.com
tx.me tx.me
tybio.com.tw
tycool.com tycool.com
typepad.com typepad.com
typeset.io typeset.io
@@ -3902,6 +3951,7 @@ valeursactuelles.com
vansky.com vansky.com
vaticannews.va vaticannews.va
vatn.org vatn.org
vava8.com
vcf-online.org vcf-online.org
vcfbuilder.org vcfbuilder.org
veed.io veed.io
@@ -3995,6 +4045,7 @@ vpsxb.net
vrchat.com vrchat.com
vrporn.com vrporn.com
vrsmash.com vrsmash.com
vscc.org.tw
vtunnel.com vtunnel.com
vultryhw.com vultryhw.com
w-pool.com w-pool.com
@@ -4003,6 +4054,7 @@ waffle1999.com
wainao.me wainao.me
walletconnect.com walletconnect.com
walletconnect.org walletconnect.org
wallhaven.cc
wallmama.com wallmama.com
wallpapercasa.com wallpapercasa.com
wallsttv.com wallsttv.com
@@ -4149,6 +4201,7 @@ write.as
writesonic.com writesonic.com
wsj.com wsj.com
wsj.net wsj.net
wtfpass.com
wufafangwen.com wufafangwen.com
wufi.org.tw wufi.org.tw
wujieliulan.com wujieliulan.com
@@ -4251,6 +4304,7 @@ xvideos-cdn.com
xvideos.com xvideos.com
xvideos.es xvideos.es
xvinlink.com xvinlink.com
xx.net
xxx.com xxx.com
xxx.xxx xxx.xxx
xxxx.com.au xxxx.com.au
@@ -4374,6 +4428,7 @@ zootool.com
zophar.net zophar.net
zorrovpn.com zorrovpn.com
zozotown.com zozotown.com
zozovideo.com
zpn.im zpn.im
zspeeder.me zspeeder.me
zuo.la zuo.la
+2 -2
View File
@@ -6,8 +6,8 @@
include $(TOPDIR)/rules.mk include $(TOPDIR)/rules.mk
PKG_NAME:=luci-app-passwall2 PKG_NAME:=luci-app-passwall2
PKG_VERSION:=26.10.20 PKG_VERSION:=26.10.29
PKG_RELEASE:=154 PKG_RELEASE:=155
PKG_PO_VERSION:=$(PKG_VERSION) PKG_PO_VERSION:=$(PKG_VERSION)
PKG_CONFIG_DEPENDS:= \ PKG_CONFIG_DEPENDS:= \
+6 -4
View File
@@ -276,9 +276,9 @@ end
function UrlEncode(szText) function UrlEncode(szText)
if type(szText) ~= "string" then return "" end if type(szText) ~= "string" then return "" end
return szText:gsub("([^%w%-_%.%~])", function(c) return (szText:gsub("([^%w%-_%.%~])", function(c)
return string.format("%%%02X", string.byte(c)) return string.format("%%%02X", string.byte(c))
end) end))
end end
function UrlDecode(szText) function UrlDecode(szText)
@@ -1413,12 +1413,14 @@ function to_download_progress(app_name, task_id, total_size)
total_size = tonumber(total_size) or 0 total_size = tonumber(total_size) or 0
local tmp_file = "/tmp/" .. app_name .. "_download." .. task_id local tmp_file = "/tmp/" .. app_name .. "_download." .. task_id
local downloaded = tonumber(fs.stat(tmp_file, "size")) or 0 local downloaded
if app_name == appname then if app_name == appname then
downloaded = 0 downloaded = 0
for part = 1, 5 do for part = 1, 5 do
downloaded = downloaded + (tonumber(fs.stat(tmp_file .. part, "size")) or 0) downloaded = downloaded + (tonumber((fs.stat(tmp_file .. part, "size"))) or 0)
end end
else
downloaded = tonumber((fs.stat(tmp_file, "size"))) or 0
end end
local percent local percent
if total_size > 0 then if total_size > 0 then
@@ -261,6 +261,17 @@ local com = self.com
detail.textContent = installingNotice; detail.textContent = installingNotice;
// Read the tiny result file even if rpcd restart invalidates the session. // Read the tiny result file even if rpcd restart invalidates the session.
var pending = false, finished = false; var pending = false, finished = false;
function finishInstall(code) {
if (finished) return;
finished = true;
clearInterval(timer);
removePageNotice(appname);
if (code) onRequestError(btn, updateFailedText);
else {
window.onbeforeunload = undefined;
window.location.reload();
}
}
var timer = setInterval(function() { var timer = setInterval(function() {
if (pending) return; if (pending) return;
pending = true; pending = true;
@@ -273,28 +284,29 @@ local com = self.com
if (finished) return; if (finished) return;
var json; var json;
try { json = JSON.parse(xhr.responseText); } catch (e) { return; } try { json = JSON.parse(xhr.responseText); } catch (e) { return; }
if (typeof json.code !== 'number') return; if (!json || typeof json.code !== 'number') return;
finished = true; finishInstall(json.code);
clearInterval(timer);
removePageNotice(appname);
if (json.code) onRequestError(btn, updateFailedText);
else {
window.onbeforeunload = undefined;
window.location.reload();
}
}; };
xhr.send(); xhr.send();
}, 1000); }, 1000);
XHR.post(url, {token: tokenStr, task: 'install', id: id, // Legacy LuCI has no static XHR.post(), and its instance callback has no JSON argument.
force: appInfoList[appname].has_update ? '0' : '1', var request = new XMLHttpRequest();
languages: appInfoList[appname].languages || ''}, function(x, json) { request.open('POST', url, true);
if (!finished && json && json.code) { request.timeout = 300000;
finished = true; request.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
clearInterval(timer); request.onerror = request.ontimeout = function() { finishInstall(1); };
removePageNotice(appname); request.onload = function() {
onRequestError(btn, updateFailedText); if (finished) return;
var json;
try { json = JSON.parse(request.responseText); } catch (e) {}
if (request.status < 200 || request.status >= 300 || !json ||
typeof json.code !== 'number' || json.code) {
finishInstall(1);
} }
}, 300); };
request.send('token=' + encodeURIComponent(tokenStr) + '&task=install&id=' + encodeURIComponent(id) +
'&force=' + (appInfoList[appname].has_update ? '0' : '1') +
'&languages=' + encodeURIComponent(appInfoList[appname].languages || ''));
} }
//]]> //]]>
@@ -298,89 +298,36 @@ table td, .table .td {
text-align: right; text-align: right;
} }
.custom-dropdown { .pw-group-select {
position: relative;
border: 1px solid #d9d9d9;
border-radius: 2px;
width: 180px; width: 180px;
height: 28px; height: 28px;
font-size: 13px; flex: 0 0 180px;
background: #fff;
cursor: pointer;
box-sizing: border-box;
display: block;
}
.selected-display {
display: flex;
justify-content: space-between;
align-items: center;
padding: 0 8px;
width: 100%;
height: 100%;
box-sizing: border-box;
font-size: 12px;
color: #666;
}
.selected-display:hover {
background-color: #f7f7f7;
}
.dropdown-list {
position: absolute;
top: calc(100% + 2px);
left: -1px;
width: calc(100% + 2px);
border: 1px solid #d9d9d9;
border-radius: 2px;
border-top: none;
box-shadow: 0 1px 3px rgba(0,0,0,0.15);
background: #fff;
list-style: none;
margin: 0;
padding: 0;
max-height: 200px;
overflow-y: auto;
overflow-x: hidden;
z-index: 100;
box-sizing: border-box;
color: #666;
}
.dropdown-item {
padding: 4px 8px;
line-height: 20px;
cursor: pointer;
}
.dropdown-item.selected {
background-color: #1e90ff;
color: #fff;
}
.create-item-input::placeholder {
text-align: center;
}
.dropdown-item.custom-input input {
width: 100%;
box-sizing: border-box;
padding: 3px;
font-size: 13px;
line-height: 20px;
border: 1px solid #ccc;
text-align: left; text-align: left;
} }
.arrow-down-small { .pw-group-select > .cbi-dropdown,
width: 0; .pw-group-select > .cbi-input-text,
height: 0; .pw-group-select > .cbi-input-select {
border-left: 4px solid transparent; width: 100% !important;
border-right: 4px solid transparent; min-width: 0 !important;
border-top: 5px solid #555; max-width: 100% !important;
display: inline-block; height: 28px !important;
vertical-align: middle; min-height: 28px !important;
box-sizing: border-box;
margin: 0;
padding-top: 0;
padding-bottom: 0;
font-size: 13px;
}
.pw-group-select > .cbi-dropdown > ul:not(.dropdown) > li,
.pw-group-select > .cbi-dropdown > .open {
height: 26px;
min-height: 0;
line-height: 26px;
padding-top: 0;
padding-bottom: 0;
box-sizing: border-box;
} }
</style> </style>
@@ -1072,97 +1019,103 @@ table td, .table .td {
//<![CDATA[ //<![CDATA[
//Pop-up logic //Pop-up logic
// Custom group dropdown list events function normalize_group_name(value, groups) {
function dropdown_list_fun(div_id) { const name = value.trim();
const dropdown = document.getElementById(div_id); return groups.find(group => group.toLowerCase() === name.toLowerCase()) || name;
if (!dropdown) return; }
const display = dropdown.querySelector(".selected-display"); function init_group_dropdown(div_id) {
const displayText = display.querySelector(".text"); const container = document.getElementById(div_id);
const list = dropdown.querySelector(".dropdown-list"); if (!container || container._group_ready || container._group_loading) return;
const hidden = dropdown.querySelector('input[type="hidden"]'); const tabs = document.querySelector("#node_list .cbi-tabmenu");
const input = dropdown.querySelector(".create-item-input"); if (!tabs) {
setTimeout(() => init_group_dropdown(div_id), 50);
display.addEventListener("click", function() { return;
list.style.display = list.style.display === "none" ? "block" : "none";
input.value = "";
//input.focus();
});
function selectItem(li) {
list.querySelectorAll(".dropdown-item").forEach(function(el){
el.classList.remove("selected");
});
li.classList.add("selected");
hidden.value = li.dataset.value;
displayText.textContent = li.dataset.value || "<%:default%>";
list.style.display = "none";
} }
list.addEventListener("click", function(e){ const choices = { "default": "<%:default%>" };
const li = e.target.closest(".dropdown-item"); const groups = ["default"];
if (!li || li.classList.contains("custom-input")) return; tabs.querySelectorAll("li[group_name]").forEach(function(tab) {
selectItem(li); const group = tab.getAttribute("group_name");
}); if (group !== "default" && !groups.includes(group)) {
choices[group] = group;
input.addEventListener("keydown", function(e){ groups.push(group);
const isEnter = e.key === "Enter" || e.keyCode === 13;
if (!isEnter) return;
e.stopPropagation();
e.preventDefault();
const val = input.value.trim();
if (!val) return;
if (val.toLowerCase() === "default") {
const emptyLi = Array.from(list.querySelectorAll(".dropdown-item"))
.find(function(el){ return !el.dataset.value; });
if (emptyLi) selectItem(emptyLi);
input.value = "";
return;
} }
});
let li = Array.from(list.querySelectorAll(".dropdown-item")).find(function(el){ const input = container.querySelector("input");
return el.dataset.value && el.dataset.value.toLowerCase() === val.toLowerCase(); <% if api.is_js_luci() then -%>
container._group_loading = true;
L.require("ui").then(function(ui) {
const widget = new ui.Dropdown("default", choices, {
id: input.id,
name: input.name,
multiple: false,
optional: false,
create: true,
sort: groups,
custom_placeholder: "-- <%:custom%> --"
}); });
if (!li) { const dropdown = widget.render();
li = document.createElement("li"); // Normalize before LuCI handles Enter and replaces its single custom item.
li.className = "dropdown-item"; dropdown.addEventListener("keydown", function(e) {
li.dataset.value = val; if (!e.target.classList.contains("create-item-input") ||
li.textContent = val; (e.key !== "Enter" && e.keyCode !== 13)) return;
list.insertBefore(li, input.parentNode); if (e.isComposing) {
} e.stopPropagation();
return;
input.value = ""; }
selectItem(li); const values = Array.from(dropdown.querySelectorAll("ul.dropdown > li[data-value]:not([unselectable])"), li => li.dataset.value);
}); e.target.value = normalize_group_name(e.target.value, values);
// Read group names from tab if (!e.target.value) {
function InsertGroup(list, input) { e.preventDefault();
const tabs = document.querySelectorAll(".cbi-tabmenu li"); e.stopPropagation();
if (!tabs.length) { }
setTimeout(() => InsertGroup(list, input), 50); }, true);
return; const customInput = dropdown.querySelector(".create-item-input");
} // The custom input row must not shadow a group named "-".
customInput.parentNode.removeAttribute("data-value");
tabs.forEach(function(li){ customInput.setAttribute("inputmode", "text");
const group = li.id.split('.').pop(); customInput.setAttribute("enterkeyhint", "done");
if(group === "default") return; dropdown.addEventListener("cbi-dropdown-change", function() {
if(Array.from(list.querySelectorAll(".dropdown-item")).some(el => el.dataset.value === group)) return; customInput.value = "";
const newLi = document.createElement("li");
newLi.className = "dropdown-item";
newLi.dataset.value = group;
newLi.textContent = group;
list.insertBefore(newLi, input.parentNode);
}); });
} container.replaceChild(dropdown, input);
InsertGroup(list, input); container._group_widget = widget;
container._group_ready = true;
// Automatically collapses when clicking on the outside. container._group_loading = false;
document.addEventListener("click", function(e) { }).catch(function(error) {
if (!dropdown.contains(e.target)) { container._group_loading = false;
list.style.display = "none"; console.error("Group dropdown init failed:", error);
alert("<%:Error%>");
});
<% else -%>
input.disabled = false;
input.addEventListener("blur", function() {
input.value = normalize_group_name(input.value, groups) || "default";
});
input.addEventListener("keydown", function(e) {
if ((e.key === "Enter" || e.keyCode === 13) && !e.isComposing) {
e.preventDefault();
e.stopPropagation();
input.blur();
} }
}); });
cbi_combobox_init(input.id, choices, "<%:default%>", "-- <%:custom%> --");
container._group_ready = true;
<% end -%>
}
function get_group_value(div_id) {
const container = document.getElementById(div_id);
return (container._group_widget ? container._group_widget.getValue() : container.querySelector("input").value) || "default";
}
function close_group_dropdown(div_id) {
const container = document.getElementById(div_id);
const dropdown = container.querySelector(".cbi-dropdown[open]");
if (dropdown) dropdown.dispatchEvent(new CustomEvent("cbi-dropdown-close"));
const input = container.querySelector(".create-item-input");
if (input) input.value = "";
} }
function getBg(el) { function getBg(el) {
@@ -1182,20 +1135,18 @@ table td, .table .td {
const addLinkDiv = document.getElementById("add_link_div"); const addLinkDiv = document.getElementById("add_link_div");
addLinkDiv.style.background = getBg(document.querySelector('.cbi-section')) || getBg(document.body) || ''; addLinkDiv.style.background = getBg(document.querySelector('.cbi-section')) || getBg(document.body) || '';
addLinkDiv.style.display = "block"; addLinkDiv.style.display = "block";
if (!addLinkDiv._dropdown_inited) { init_group_dropdown("addlink_group_custom");
addLinkDiv._dropdown_inited = true;
dropdown_list_fun("addlink_group_custom");
}
document.getElementById("nodes_link").focus(); document.getElementById("nodes_link").focus();
}, },
close() { close() {
close_group_dropdown("addlink_group_custom");
document.getElementById('modal-mask').style.display = 'none'; document.getElementById('modal-mask').style.display = 'none';
document.getElementById("add_link_div").style.display = "none"; document.getElementById("add_link_div").style.display = "none";
document.body.classList.remove('modal-open'); document.body.classList.remove('modal-open');
}, },
add_node() { add_node() {
let nodes_link = document.getElementById("nodes_link").value; let nodes_link = document.getElementById("nodes_link").value;
const group = (document.querySelector('#addlink_group_custom input[type="hidden"]')?.value || "default"); const group = get_group_value("addlink_group_custom");
nodes_link = nodes_link.replace(/\t/g, "").replace(/\r\n|\r/g, "\n").replace(/<[^>]*>/g, '').trim(); nodes_link = nodes_link.replace(/\t/g, "").replace(/\r\n|\r/g, "\n").replace(/<[^>]*>/g, '').trim();
if (nodes_link != "") { if (nodes_link != "") {
nodes_link = decodeIfBase64(nodes_link); nodes_link = decodeIfBase64(nodes_link);
@@ -1274,23 +1225,21 @@ table td, .table .td {
const reassignGroupDiv = document.getElementById("reassign_group_div"); const reassignGroupDiv = document.getElementById("reassign_group_div");
reassignGroupDiv.style.background = getBg(document.querySelector('.cbi-section')) || getBg(document.body) || ''; reassignGroupDiv.style.background = getBg(document.querySelector('.cbi-section')) || getBg(document.body) || '';
reassignGroupDiv.style.display = "block"; reassignGroupDiv.style.display = "block";
if (!reassignGroupDiv._dropdown_inited) { init_group_dropdown("reassign_group_custom");
reassignGroupDiv._dropdown_inited = true;
dropdown_list_fun("reassign_group_custom");
}
} else { } else {
alert("<%:You no select nodes !%>"); alert("<%:You no select nodes !%>");
} }
} }
}, },
close() { close() {
close_group_dropdown("reassign_group_custom");
document.getElementById('modal-mask').style.display = 'none'; document.getElementById('modal-mask').style.display = 'none';
document.getElementById("reassign_group_div").style.display = "none"; document.getElementById("reassign_group_div").style.display = "none";
document.body.classList.remove('modal-open'); document.body.classList.remove('modal-open');
}, },
action() { action() {
const ids = []; const ids = [];
const group = (document.querySelector('#reassign_group_custom input[type="hidden"]')?.value || "default"); const group = get_group_value("reassign_group_custom");
const visibleContainer = document.querySelector('#cbi-passwall2-nodes > .cbi-tabcontainer[style*="display:block"], #cbi-passwall2-nodes > .cbi-tabcontainer[style*="display: block"]'); const visibleContainer = document.querySelector('#cbi-passwall2-nodes > .cbi-tabcontainer[style*="display:block"], #cbi-passwall2-nodes > .cbi-tabcontainer[style*="display: block"]');
if (!visibleContainer) return; if (!visibleContainer) return;
const doms = visibleContainer.getElementsByClassName("nodes_select"); const doms = visibleContainer.getElementsByClassName("nodes_select");
@@ -1740,19 +1689,9 @@ table td, .table .td {
</div> </div>
<div class="value-custom"> <div class="value-custom">
<div class="value-field-custom"> <div class="value-field-custom">
<label class="value-title-custom" for="addlink_group_custom"><%:Group Name%></label> <label class="value-title-custom" for="addlink_group"><%:Group Name%></label>
<div id="addlink_group_custom" class="custom-dropdown"> <div id="addlink_group_custom" class="pw-group-select">
<div class="selected-display"> <input id="addlink_group" name="addlink_group" class="cbi-input-text" type="text" value="default" disabled>
<span class="text"><%:default%></span>
<span class="arrow-down-small"></span>
</div>
<ul class="dropdown-list" style="display:none;">
<li class="dropdown-item selected" data-value=""><%:default%></li>
<li class="dropdown-item custom-input">
<input type="text" placeholder="-- <%:custom%> --" class="create-item-input" inputmode="text" enterkeyhint="done">
</li>
</ul>
<input type="hidden" name="addlink_group" value="">
</div> </div>
</div> </div>
</div> </div>
@@ -1768,19 +1707,9 @@ table td, .table .td {
<h3><%:Reassign Node Group%></h3> <h3><%:Reassign Node Group%></h3>
<div class="value-custom"> <div class="value-custom">
<div class="value-field-custom"> <div class="value-field-custom">
<label class="value-title-custom" for="reassign_group_custom"><%:Group Name%></label> <label class="value-title-custom" for="to_group"><%:Group Name%></label>
<div id="reassign_group_custom" class="custom-dropdown"> <div id="reassign_group_custom" class="pw-group-select">
<div class="selected-display"> <input id="to_group" name="to_group" class="cbi-input-text" type="text" value="default" disabled>
<span class="text"><%:default%></span>
<span class="arrow-down-small"></span>
</div>
<ul class="dropdown-list" style="display:none;">
<li class="dropdown-item selected" data-value=""><%:default%></li>
<li class="dropdown-item custom-input">
<input type="text" placeholder="-- <%:custom%> --" class="create-item-input" inputmode="text" enterkeyhint="done">
</li>
</ul>
<input type="hidden" name="to_group" value="">
</div> </div>
</div> </div>
</div> </div>
+2 -2
View File
@@ -5,8 +5,8 @@
include $(TOPDIR)/rules.mk include $(TOPDIR)/rules.mk
PKG_NAME:=mihomo PKG_NAME:=mihomo
PKG_VERSION:=1.19.32 PKG_VERSION:=1.19.33
PKG_RELEASE:=35 PKG_RELEASE:=36
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
PKG_SOURCE_URL:=https://codeload.github.com/metacubex/mihomo/tar.gz/v$(PKG_VERSION)? PKG_SOURCE_URL:=https://codeload.github.com/metacubex/mihomo/tar.gz/v$(PKG_VERSION)?
+2 -2
View File
@@ -1,8 +1,8 @@
include $(TOPDIR)/rules.mk include $(TOPDIR)/rules.mk
PKG_NAME:=minigate PKG_NAME:=minigate
PKG_VERSION:=2026.10.28 PKG_VERSION:=2026.10.28-2
PKG_RELEASE:=8 PKG_RELEASE:=9
PKG_LICENSE:=MIT PKG_LICENSE:=MIT
PKG_MAINTAINER:=MiniGate PKG_MAINTAINER:=MiniGate
+22 -15
View File
@@ -2,9 +2,9 @@
一个类似 Lucky 的轻量级 OpenWrt 应用,提供四大核心功能:DDNS、SSL 证书、反向代理、登录防护。 一个类似 Lucky 的轻量级 OpenWrt 应用,提供四大核心功能:DDNS、SSL 证书、反向代理、登录防护。
当前版本:**v2026.10.28**。界面名称为 **MiniGate**,仓库名及 OpenWrt 内部包名均为 **`minigate`**。 当前版本:**v2026.10.28-2**。界面名称为 **MiniGate**,仓库名及 OpenWrt 内部包名均为 **`minigate`**。
> OpenWrt 用户请从 [Releases](https://github.com/tpxcer/minigate/releases/latest) 下载 `minigate_2026.10.28_all.ipk`。不要把 GitHub 自动生成的 `Source code (zip)` / `Source code (tar.gz)` 当安装包上传到 LuCI。 > OpenWrt 用户请从 [Releases](https://github.com/tpxcer/minigate/releases/latest) 下载 `minigate_2026.10.28-2_all.ipk`。不要把 GitHub 自动生成的 `Source code (zip)` / `Source code (tar.gz)` 当安装包上传到 LuCI。
## 项目定位 ## 项目定位
@@ -102,20 +102,20 @@ MiniGate 面向需要自托管轻量网关能力的 OpenWrt / ImmortalWrt 用户
从 [Releases](https://github.com/tpxcer/minigate/releases/latest) 下载: 从 [Releases](https://github.com/tpxcer/minigate/releases/latest) 下载:
`minigate_2026.10.28_all.ipk` `minigate_2026.10.28-2_all.ipk`
**通过 LuCI 界面安装:** **通过 LuCI 界面安装:**
1. 打开 LuCI → **系统** → **软件包** 1. 打开 LuCI → **系统** → **软件包**
2. 点击 **上传软件包** 2. 点击 **上传软件包**
3. 选择 `minigate_2026.10.28_all.ipk`,点击安装 3. 选择 `minigate_2026.10.28-2_all.ipk`,点击安装
**通过命令行安装:** **通过命令行安装:**
```bash ```bash
cd /tmp cd /tmp
wget -O minigate_2026.10.28_all.ipk https://github.com/tpxcer/minigate/releases/download/v2026.10.28/minigate_2026.10.28_all.ipk wget -O minigate_2026.10.28-2_all.ipk https://github.com/tpxcer/minigate/releases/download/v2026.10.28-2/minigate_2026.10.28-2_all.ipk
opkg update opkg update
opkg install /tmp/minigate_2026.10.28_all.ipk opkg install /tmp/minigate_2026.10.28-2_all.ipk
rm -f /tmp/luci-indexcache /tmp/luci-modulecache 2>/dev/null rm -f /tmp/luci-indexcache /tmp/luci-modulecache 2>/dev/null
/etc/init.d/uhttpd restart /etc/init.d/uhttpd restart
/etc/init.d/minigate restart /etc/init.d/minigate restart
@@ -134,7 +134,7 @@ Release 用的 `.ipk` 请用仓库脚本生成,避免生成 Debian 风格 ar
脚本会输出: 脚本会输出:
```text ```text
dist/minigate_2026.10.28_all.ipk dist/minigate_2026.10.28-2_all.ipk
``` ```
该文件外层是 OpenWrt/ImmortalWrt 24.10 兼容的 `tar.gz`,内部成员顺序为 `debian-binary`、`control.tar.gz`、`data.tar.gz`。 该文件外层是 OpenWrt/ImmortalWrt 24.10 兼容的 `tar.gz`,内部成员顺序为 `debian-binary`、`control.tar.gz`、`data.tar.gz`。
@@ -162,7 +162,7 @@ wget -qO- https://raw.githubusercontent.com/tpxcer/minigate/main/scripts/install
需要指定并核对具体版本时,执行: 需要指定并核对具体版本时,执行:
```bash ```bash
d="$(mktemp -d /tmp/minigate.XXXXXX)" && cd "$d" && wget -q https://github.com/tpxcer/minigate/releases/download/v2026.10.28/minigate-v2026.10.28-src.tar.gz && wget -q https://github.com/tpxcer/minigate/releases/download/v2026.10.28/SHA256SUMS && grep 'minigate-v2026.10.28-src.tar.gz$' SHA256SUMS | sha256sum -c - && tar xzf minigate-v2026.10.28-src.tar.gz && sh install.sh && /etc/init.d/uhttpd restart && /etc/init.d/minigate restart d="$(mktemp -d /tmp/minigate.XXXXXX)" && cd "$d" && wget -q https://github.com/tpxcer/minigate/releases/download/v2026.10.28-2/minigate-v2026.10.28-2-src.tar.gz && wget -q https://github.com/tpxcer/minigate/releases/download/v2026.10.28-2/SHA256SUMS && grep 'minigate-v2026.10.28-2-src.tar.gz$' SHA256SUMS | sha256sum -c - && tar xzf minigate-v2026.10.28-2-src.tar.gz && sh install.sh && /etc/init.d/uhttpd restart && /etc/init.d/minigate restart
``` ```
其中 `minigate.XXXXXX` 是临时目录模板,系统会自动把六个 `X` 替换为随机字符,避免与已有目录重名。该命令会校验源码包的 SHA-256、保留现有 minigate 配置并重启 LuCI 与 minigate 服务。 其中 `minigate.XXXXXX` 是临时目录模板,系统会自动把六个 `X` 替换为随机字符,避免与已有目录重名。该命令会校验源码包的 SHA-256、保留现有 minigate 配置并重启 LuCI 与 minigate 服务。
@@ -177,14 +177,14 @@ ssh root@192.168.1.1
# 2. 在路由器上直接下载 Release 源码包 # 2. 在路由器上直接下载 Release 源码包
cd /tmp cd /tmp
wget -O minigate-src.tar.gz https://github.com/tpxcer/minigate/releases/download/v2026.10.28/minigate-v2026.10.28-src.tar.gz wget -O minigate-src.tar.gz https://github.com/tpxcer/minigate/releases/download/v2026.10.28-2/minigate-v2026.10.28-2-src.tar.gz
wget -O minigate-SHA256SUMS https://github.com/tpxcer/minigate/releases/download/v2026.10.28/SHA256SUMS wget -O minigate-SHA256SUMS https://github.com/tpxcer/minigate/releases/download/v2026.10.28-2/SHA256SUMS
awk '$2 == "minigate-v2026.10.28-src.tar.gz" {print $1 " minigate-src.tar.gz"}' minigate-SHA256SUMS | sha256sum -c - || exit 1 awk '$2 == "minigate-v2026.10.28-2-src.tar.gz" {print $1 " minigate-src.tar.gz"}' minigate-SHA256SUMS | sha256sum -c - || exit 1
# 3. 解压到独立目录并安装 # 3. 解压到独立目录并安装
mkdir -p /tmp/minigate-v2026.10.28 mkdir -p /tmp/minigate-v2026.10.28-2
tar xzf minigate-src.tar.gz -C /tmp/minigate-v2026.10.28 tar xzf minigate-src.tar.gz -C /tmp/minigate-v2026.10.28-2
cd /tmp/minigate-v2026.10.28 cd /tmp/minigate-v2026.10.28-2
sh install.sh sh install.sh
# 4. 启动服务 # 4. 启动服务
@@ -234,7 +234,7 @@ SSH 登录后执行上方「方法 2」的一条命令,保留原有配置并
### IPK 升级 ### IPK 升级
```bash ```bash
opkg install --force-reinstall /tmp/minigate_2026.10.28_all.ipk opkg install --force-reinstall /tmp/minigate_2026.10.28-2_all.ipk
rm -f /tmp/luci-indexcache /tmp/luci-modulecache 2>/dev/null rm -f /tmp/luci-indexcache /tmp/luci-modulecache 2>/dev/null
/etc/init.d/minigate restart /etc/init.d/minigate restart
``` ```
@@ -425,6 +425,13 @@ minigate/
## 更新日志 ## 更新日志
### v2026.10.28-2
- 修复 v2026.10.28 引入的登录防护回归:达到失败阈值时,封禁地址被修复防火墙的读取过程清空,日志显示「封禁 失败」,新的攻击来源不会被封禁(已有封禁不受影响)。升级后会立即恢复正常封禁
### v2026.10.28-1
- 「公网访问范围」的地区选择改为收起式:收起时只显示已选地区标签和数量,展开后按华北、东北、华东、华中、华南、西南、西北、港澳台分组对齐排列,支持按地区名或大区名搜索、一键清空、点标签上的 × 移除
- 修复 v2026.10.28 中关闭「限制公网访问地区」后保存反向代理页会提示未选择地区、导致整页无法保存的问题
### v2026.10.28 ### v2026.10.28
- 修复:通配符主域名停用或删除后,其子域名会退回成 443 端口的明文 HTTP 站点,并可能让 Nginx 因两个默认站点无法加载;现在子域名随主域名一起停用,并可单独停用 - 修复:通配符主域名停用或删除后,其子域名会退回成 443 端口的明文 HTTP 站点,并可能让 Nginx 因两个默认站点无法加载;现在子域名随主域名一起停用,并可单独停用
- 修复:同一端口同时有 HTTP 和 HTTPS 规则时生成无法加载的配置;冲突规则会被跳过并在总览提示 - 修复:同一端口同时有 HTTP 和 HTTPS 规则时生成无法加载的配置;冲突规则会被跳过并在总览提示
+22 -2
View File
@@ -219,12 +219,24 @@ if regions_file then
regions_file:close() regions_file:close()
end end
-- 34 个地区按大区分组,收起时只显示已选地区,展开后可搜索(模板 minigate/region_select)
local REGION_GROUPS = {"华北", "东北", "华东", "华中", "华南", "西南", "西北", "港澳台"}
local function region_group(code)
local prefix = tonumber(code:sub(1, 2)) or 99
if prefix < 20 then return 1 elseif prefix < 30 then return 2 elseif prefix < 40 then return 3
elseif prefix < 44 then return 4 elseif prefix < 50 then return 5 elseif prefix < 60 then return 6
elseif prefix < 70 then return 7 end
return 8
end
o = s:option(MultiValue, "access_regions", "允许的省级地区", "勾选允许访问的地区,可多选。关闭地区限制即恢复所有地区访问。") o = s:option(MultiValue, "access_regions", "允许的省级地区", "勾选允许访问的地区,可多选。关闭地区限制即恢复所有地区访问。")
o.widget = "checkbox" o.widget = "checkbox"
o.size = 6 o.template = "minigate/region_select"
o.default = "510000" o.default = "510000"
o.rmempty = false o.rmempty = false
o:depends("access_enabled", "1") o:depends("access_enabled", "1")
o.groups = {}
for i, name in ipairs(REGION_GROUPS) do o.groups[i] = {name, {}} end
-- 旧版本以 list 保存;统一转成以空格分隔的字符串供复选框回显 -- 旧版本以 list 保存;统一转成以空格分隔的字符串供复选框回显
o.cfgvalue = function(self, section) o.cfgvalue = function(self, section)
local value = m.uci:get("minigate", section, "access_regions") local value = m.uci:get("minigate", section, "access_regions")
@@ -235,6 +247,8 @@ local valid_regions = {}
for _, region in ipairs(access_regions) do for _, region in ipairs(access_regions) do
o:value(region[1], region[2]) o:value(region[1], region[2])
valid_regions[region[1]] = true valid_regions[region[1]] = true
local group = o.groups[region_group(region[1])][2]
group[#group + 1] = region[1]
end end
o.validate = function(self, value, section) o.validate = function(self, value, section)
local values = {} local values = {}
@@ -247,7 +261,13 @@ o.validate = function(self, value, section)
for _, code in ipairs(values) do for _, code in ipairs(values) do
if not valid_regions[code] then return nil, "请从列表中选择有效的省级地区" end if not valid_regions[code] then return nil, "请从列表中选择有效的省级地区" end
end end
return value return table.concat(values, " ")
end
-- 关闭地区限制时这个字段被隐藏、不会提交;LuCI 不在服务端判断依赖,
-- 不跳过会把「未提交」当成未选择而报错,导致整页无法保存。
o.parse = function(self, section, novld)
if self.map:formvalue("cbid.minigate." .. section .. ".access_enabled") ~= "1" then return end
return MultiValue.parse(self, section, novld)
end end
return m return m
@@ -0,0 +1,94 @@
<%+cbi/valueheader%>
<%
local selected = {}
for code in tostring(self:cfgvalue(section) or self.default or ""):gmatch("%S+") do selected[code] = true end
local names = {}
for i, key in ipairs(self.keylist) do names[key] = self.vallist[i] end
%>
<div class="mgx-region" id="<%=cbid%>.region">
<div class="mgx-region-field" role="button" tabindex="0" aria-expanded="false" aria-controls="<%=cbid%>.panel">
<span class="mgx-region-chips"></span>
<span class="mgx-region-count mgx-muted"></span>
<span class="mgx-region-arrow mgx-muted" aria-hidden="true">&#9662;</span>
</div>
<div class="mgx-region-panel" id="<%=cbid%>.panel" hidden="hidden">
<div class="mgx-region-tools">
<input type="text" class="cbi-input-text mgx-region-search" placeholder="搜索地区,如 川、重庆、西南" aria-label="搜索地区" />
<button type="button" class="cbi-button mgx-region-clear">清空</button>
</div>
<% for _, group in ipairs(self.groups) do if #group[2] > 0 then %>
<div class="mgx-region-group" data-group="<%=pcdata(group[1])%>">
<div class="mgx-region-gname"><%=pcdata(group[1])%></div>
<div class="mgx-region-items">
<% for _, code in ipairs(group[2]) do %>
<label data-name="<%=pcdata(names[code])%>"><input type="checkbox" class="cbi-input-checkbox" name="<%=cbid%>" value="<%=code%>"<% if selected[code] then %> checked="checked"<% end %> /> <%=pcdata(names[code])%></label>
<% end %>
</div>
</div>
<% end end %>
<div class="mgx-region-empty mgx-muted" hidden="hidden">没有匹配的地区</div>
</div>
</div>
<script type="text/javascript">
(function(){
var root=document.getElementById('<%=cbid%>.region');
if(!root)return;
var field=root.querySelector('.mgx-region-field'),panel=root.querySelector('.mgx-region-panel');
var chips=root.querySelector('.mgx-region-chips'),count=root.querySelector('.mgx-region-count');
var boxes=root.querySelectorAll('input[type=checkbox]');
function render(){
chips.textContent='';
var n=0;
for(var i=0;i<boxes.length;i++){
if(!boxes[i].checked)continue;
n++;
var chip=document.createElement('span'),remove=document.createElement('button');
chip.className='mgx-region-chip';
chip.appendChild(document.createTextNode(boxes[i].parentNode.getAttribute('data-name')));
remove.type='button';
remove.className='mgx-region-remove';
remove.setAttribute('aria-label','移除'+boxes[i].parentNode.getAttribute('data-name'));
remove.textContent='×';
remove.onclick=(function(box){return function(e){e.stopPropagation();box.checked=false;render();};})(boxes[i]);
chip.appendChild(remove);
chips.appendChild(chip);
}
if(!n){
var hint=document.createElement('span');
hint.className='mgx-err';
hint.textContent='请至少选择一个地区';
chips.appendChild(hint);
}
count.textContent='已选 '+n+' 个';
}
function toggle(open){
if(open===undefined)open=panel.hidden;
panel.hidden=!open;
field.setAttribute('aria-expanded',open?'true':'false');
if(open)root.querySelector('.mgx-region-search').focus();
}
field.onclick=function(){toggle();};
field.onkeydown=function(e){if(e.key==='Enter'||e.key===' '){e.preventDefault();toggle();}};
for(var i=0;i<boxes.length;i++)boxes[i].onchange=render;
root.querySelector('.mgx-region-clear').onclick=function(){for(var i=0;i<boxes.length;i++)boxes[i].checked=false;render();};
// 按地区名或大区名筛选;回车不提交整页表单
var search=root.querySelector('.mgx-region-search');
search.onkeydown=function(e){if(e.key==='Enter')e.preventDefault();};
search.oninput=function(){
var q=search.value.replace(/\s+/g,''),groups=root.querySelectorAll('.mgx-region-group'),shown=0;
for(var g=0;g<groups.length;g++){
var labels=groups[g].querySelectorAll('label'),any=false,inGroup=!q||groups[g].getAttribute('data-group').indexOf(q)>=0;
for(var l=0;l<labels.length;l++){
var hit=inGroup||labels[l].getAttribute('data-name').indexOf(q)>=0;
labels[l].hidden=!hit;
if(hit)any=true;
}
groups[g].hidden=!any;
if(any)shown++;
}
root.querySelector('.mgx-region-empty').hidden=shown>0;
};
render();
})();
</script>
<%+cbi/valuefooter%>
+19
View File
@@ -21,6 +21,25 @@
.mgx-actions{display:flex;flex-wrap:wrap;gap:10px;align-items:center;margin-bottom:10px} .mgx-actions{display:flex;flex-wrap:wrap;gap:10px;align-items:center;margin-bottom:10px}
.mgx-sync{margin-top:4px;font-size:12px!important;padding:2px 10px!important} .mgx-sync{margin-top:4px;font-size:12px!important;padding:2px 10px!important}
.mgx-sync-result{margin-left:8px;font-size:12px} .mgx-sync-result{margin-left:8px;font-size:12px}
.mgx-region{max-width:720px}
.mgx-region [hidden]{display:none!important}
.mgx-region-field{display:flex;flex-wrap:wrap;align-items:center;gap:6px;min-height:34px;padding:5px 8px;border:1px solid var(--mgx-border);border-radius:6px;background:var(--mgx-control);color:var(--mgx-text);cursor:pointer;box-sizing:border-box}
.mgx-region-field:focus{outline:2px solid var(--mgx-info);outline-offset:1px}
.mgx-region-chips{display:contents}
.mgx-region-chip{display:inline-flex;align-items:center;gap:2px;padding:1px 4px 1px 8px;border-radius:4px;background:rgba(25,113,194,.14);color:var(--mgx-info);font-size:12px;line-height:20px}
.mgx-region-remove{min-width:0!important;height:20px!important;margin:0!important;padding:0 4px!important;border:0!important;background:transparent!important;color:inherit!important;font-size:14px!important;line-height:20px!important;cursor:pointer;box-shadow:none!important}
.mgx-region-count{margin-left:auto;font-size:12px;white-space:nowrap}
.mgx-region-arrow{font-size:12px}
.mgx-region-panel{margin-top:6px;padding:8px 12px;border:1px solid var(--mgx-border);border-radius:6px;background:var(--mgx-surface)}
.mgx-region-tools{display:flex;gap:8px;align-items:center;margin-bottom:4px}
.mgx-region-search{flex:1;min-width:0}
.mgx-region-group{display:grid;grid-template-columns:4em minmax(0,1fr);gap:4px 10px;padding:6px 0;border-top:1px solid var(--mgx-border)}
.mgx-region-gname{padding-top:2px;color:var(--mgx-muted);font-size:12px}
.mgx-region-items{display:grid;grid-template-columns:repeat(auto-fill,minmax(9.5em,1fr));gap:4px 12px}
.mgx-region-items label{display:flex;align-items:center;gap:6px;margin:0;color:var(--mgx-text);font-size:13px;white-space:nowrap;cursor:pointer}
.mgx-region-items input{margin:0}
.mgx-region-empty{padding:8px 0;font-size:12px}
@media(max-width:640px){.mgx-region-group{grid-template-columns:minmax(0,1fr)}.mgx-region-items{grid-template-columns:repeat(2,minmax(0,1fr))}}
@keyframes mgx-spin{from{transform:rotate(0deg)}to{transform:rotate(360deg)}} @keyframes mgx-spin{from{transform:rotate(0deg)}to{transform:rotate(360deg)}}
.mgx-spin{display:inline-block;margin-right:8px;animation:mgx-spin 1s linear infinite} .mgx-spin{display:inline-block;margin-right:8px;animation:mgx-spin 1s linear infinite}
</style> </style>
+29
View File
@@ -0,0 +1,29 @@
## 地区选择整理
「反向代理 → 高级设置:公网访问范围」中的地区选择改为收起式控件。原来 34 个复选框依次排开,看起来比较凌乱。
- 收起时只显示已选地区的标签和已选数量,例如「四川省 ×」「已选 1 个」。点标签上的 × 就能移除对应地区。
- 展开后,地区按华北、东北、华东、华中、华南、西南、西北、港澳台分组,各组对齐排列;手机上自动改为两列。
- 支持按地区名或大区名搜索,例如输入「川」「重庆」「西南」;也可以一键清空。全部清空时会提示至少选择一个地区。
- 复选框仍是 LuCI 原生表单字段,提交和保存方式不变;同时兼容旧版保存为列表的配置。
## 修复
修复 v2026.10.28 的一个问题:关闭「限制公网访问地区」后,保存反向代理页会提示未选择地区,导致整页无法保存。原因是地区字段隐藏后不会提交,LuCI 把“未提交”当成“没有选择”。现在只在开启地区限制时检查地区选择,关闭限制时保留原有选择。
## 验证
- 本地完整测试全部通过,无跳过。新增测试覆盖三类内容:
- 用真实页面数据渲染地区模板:34 个原生复选框、8 个分组、已选状态;
- 兼容旧版的列表格式;
- 关闭地区限制时不再阻止保存。
- 在浏览器中检查了深色、浅色和 375px 手机宽度下的显示,以及展开、搜索、勾选、移除标签、清空和表单提交,均正常,页面没有横向溢出。
- 浏览器检查用的是模拟的 LuCI 页面外框,FanchmWrt 主题下的实际效果需安装后确认。
- 本次不自动更新路由器。
## 安装包
- opkg 安装包:`minigate_2026.10.28-1_all.ipk`。
- 源码安装包:`minigate-v2026.10.28-1-src.tar.gz`。
- 兼容旧更新器:`luci-app-minigate-v2026.10.28-1-src.tar.gz`。
- 使用随附的 `SHA256SUMS` 校验文件完整性。
+24
View File
@@ -0,0 +1,24 @@
## 修复登录防护无法封禁新 IP
修复 v2026.10.28 引入的回归:从 v2026.10.28 起,登录失败次数达到阈值后,登录防护封禁的是一个空地址。日志里显示 `封禁 失败:防火墙未接受该地址`,攻击来源的失败次数一直累加,却不会被封禁。
- 原因:修复防火墙时会读取持久化的封禁文件,读取循环里的 `ip` 变量没有声明为局部变量。shell 的 `local` 是动态作用域,读到文件末尾时把调用方准备封禁的地址清空了。
- 修复:把读取循环中的变量改为局部变量。新增的回归测试分别覆盖防火墙集合完好和重载后为空两种情况,确认达到阈值后封禁的是正确地址、写入封禁文件并清除失败计数。
- 升级前已生效的封禁不受影响,升级后新的攻击来源恢复正常封禁。
## 说明
「公网访问范围」只限制 MiniGate 反代的网站,不会把 IP 加入封禁列表。登录防护页面的封禁列表来自 SSH 和 LuCI 登录失败,不区分地区。SSH 端口对公网开放时,各地的爆破来源都会出现在这个列表里。
## 验证
- 本地完整测试全部通过,无跳过;CI 在 Ubuntu(dash)下运行同一套测试。
- 新的回归测试在修复前失败,修复后通过;同一场景也已在 dash 下单独复验。
- 本次不自动更新路由器。
## 安装包
- opkg 安装包:`minigate_2026.10.28-2_all.ipk`。
- 源码安装包:`minigate-v2026.10.28-2-src.tar.gz`。
- 兼容旧更新器:`luci-app-minigate-v2026.10.28-2-src.tar.gz`。
- 使用随附的 `SHA256SUMS` 校验文件完整性。
@@ -208,7 +208,8 @@ ensure_nft() {
# 防火墙重载后,随包的集合会重新出现但内容为空;持久化文件里仍有未过期封禁时恢复 # 防火墙重载后,随包的集合会重新出现但内容为空;持久化文件里仍有未过期封禁时恢复
sets_lost_bans() { sets_lost_bans() {
local now set # ip/exp 必须是局部变量:shell 的 local 是动态作用域,读到文件末尾会清空调用方的 ip
local now set ip exp
now=$(date +%s) now=$(date +%s)
for set in "$SET4" "$SET6"; do for set in "$SET4" "$SET6"; do
nft list set $TABLE $set 2>/dev/null | grep -q 'elements' && continue nft list set $TABLE $set 2>/dev/null | grep -q 'elements' && continue
@@ -255,7 +256,7 @@ restore_bans() {
local now=$(date +%s) local now=$(date +%s)
local tmp="${BANS_FILE}.tmp" local tmp="${BANS_FILE}.tmp"
> "$tmp" > "$tmp"
local count=0 local count=0 ip exp
while read -r ip exp; do while read -r ip exp; do
[ -z "$ip" ] && continue [ -z "$ip" ] && continue
case "$exp" in ''|*[!0-9]*) continue ;; esac case "$exp" in ''|*[!0-9]*) continue ;; esac
+1 -1
View File
@@ -3,7 +3,7 @@
PATH=/usr/sbin:/usr/bin:/sbin:/bin PATH=/usr/sbin:/usr/bin:/sbin:/bin
export PATH export PATH
CURRENT_VERSION="2026.10.28" CURRENT_VERSION="2026.10.28-2"
REPOSITORY="tpxcer/minigate" REPOSITORY="tpxcer/minigate"
API_URL="https://api.github.com/repos/${REPOSITORY}/releases/latest" API_URL="https://api.github.com/repos/${REPOSITORY}/releases/latest"
DOWNLOAD_ROOT="https://github.com/${REPOSITORY}/releases/download" DOWNLOAD_ROOT="https://github.com/${REPOSITORY}/releases/download"
+1 -1
View File
@@ -5,7 +5,7 @@ ROOT_DIR="$(CDPATH= cd -- "$(dirname -- "$0")/.." && pwd)"
OUT_DIR="${1:-$ROOT_DIR/dist}" OUT_DIR="${1:-$ROOT_DIR/dist}"
PKG_NAME="minigate" PKG_NAME="minigate"
PKG_VERSION="2026.10.28" PKG_VERSION="2026.10.28-2"
PKG_ARCH="all" PKG_ARCH="all"
PKG_FILE="${PKG_NAME}_${PKG_VERSION}_${PKG_ARCH}.ipk" PKG_FILE="${PKG_NAME}_${PKG_VERSION}_${PKG_ARCH}.ipk"
DEPS="libc, luci-base, luci-compat, nginx-ssl, nginx-mod-stream, openssl-util, wget, curl, jsonfilter, coreutils-stat, nftables" DEPS="libc, luci-base, luci-compat, nginx-ssl, nginx-mod-stream, openssl-util, wget, curl, jsonfilter, coreutils-stat, nftables"
+35
View File
@@ -178,3 +178,38 @@ test('upgrades stop the old login guard tree before running the previous init sc
assert.ok(treeStop > 0 && treeStop < initStop, 'installer must stop the login guard tree before the old init script'); assert.ok(treeStop > 0 && treeStop < initStop, 'installer must stop the login guard tree before the old init script');
assert.match(installer, /stop_process_tree\(\) \{[\s\S]*pgrep -P "\$1"/); assert.match(installer, /stop_process_tree\(\) \{[\s\S]*pgrep -P "\$1"/);
}); });
// 回归:v2026.10.28 中修复防火墙时读取 bans.txt 的循环变量覆盖了调用方的 ip,
// 达到阈值后用空地址封禁,日志出现「封禁 失败」,攻击者再也不会被封。
test('reaching the threshold bans the attacking address even when other bans are persisted', () => {
for (const setsEmpty of [false, true]) {
const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'minigate-lg-threshold-'));
const dataDir = path.join(dir, 'data');
const calls = path.join(dir, 'nft.log');
fs.mkdirSync(dataDir);
fs.writeFileSync(path.join(dataDir, 'bans.txt'), '111.170.34.182 9999999999\n185.246.128.170 9999999999\n');
const result = spawnSync('/bin/sh', ['-c', `
logger() { :; }
uci() { case "$3" in minigate.login_guard.threshold) echo 3 ;; *) return 1 ;; esac; }
nft() {
printf '%s\\n' "$*" >> ${JSON.stringify(calls)}
case "$*" in
'list set inet fw4 login_banned_v4'|'list set inet fw4 login_banned_v6') [ ${setsEmpty ? 1 : 0} = 1 ] || echo 'elements = { 111.170.34.182 }' ;;
'list chain inet fw4 input') echo '@login_banned_v4 @login_banned_v6' ;;
esac
return 0
}
export MINIGATE_LG_LIBRARY_ONLY=1 MINIGATE_LG_DATA_DIR=${JSON.stringify(dataDir)}
export MINIGATE_LG_RUN_DIR=${JSON.stringify(path.join(dir, 'run'))} MINIGATE_LG_LOG=${JSON.stringify(path.join(dir, 'lg.log'))}
. ${JSON.stringify(script)}
for i in 1 2 3; do handle_failure 139.162.161.162; done
`], { encoding: 'utf8' });
assert.equal(result.status, 0, result.stderr);
const log = fs.readFileSync(path.join(dir, 'lg.log'), 'utf8');
assert.match(fs.readFileSync(calls, 'utf8'), /add element inet fw4 login_banned_v4 \{ 139\.162\.161\.162 timeout 43200s \}/, `setsEmpty=${setsEmpty}`);
assert.match(log, /BAN 139\.162\.161\.162 12小时(达到 3 次失败)/);
assert.doesNotMatch(log, /封禁 +失败/);
assert.match(fs.readFileSync(path.join(dataDir, 'bans.txt'), 'utf8'), /^139\.162\.161\.162 \d+$/m);
assert.equal(fs.existsSync(path.join(dir, 'run/counters/139.162.161.162')), false, 'counter is cleared after a ban');
}
});
+142
View File
@@ -0,0 +1,142 @@
const { test } = require('node:test');
const assert = require('node:assert/strict');
const fs = require('node:fs');
const path = require('node:path');
const { spawnSync } = require('node:child_process');
const lua = process.env.MINIGATE_TEST_LUA;
const root = path.resolve(__dirname, '..');
const template = path.join(root, 'luasrc/view/minigate/region_select.htm');
const proxyPage = path.join(root, 'luasrc/model/cbi/minigate/proxy.lua');
const regions = path.join(root, 'root/usr/lib/minigate/geo/regions.txt');
// 最小的 LuCI 模板解释器:只支持本模板用到的 <% %>、<%= %> 和 <%+ %>(include 输出占位)
const renderer = `
local function compile(src)
local code, pos = {"local _o = {}\\nlocal function _w(v) _o[#_o + 1] = tostring(v) end\\n"}, 1
while true do
local s, e = src:find("<%", pos, true)
local text = src:sub(pos, (s or 0) - 1)
if s == nil then text = src:sub(pos) end
code[#code + 1] = "_w(" .. string.format("%q", text) .. ")\\n"
if not s then break end
local close = assert(src:find("%>", e + 1, true), "unclosed tag")
local body = src:sub(e + 1, close - 1)
local mode = body:sub(1, 1)
if mode == "=" then
code[#code + 1] = "_w(" .. body:sub(2) .. ")\\n"
elseif mode == "+" then
code[#code + 1] = "_w('<!--include " .. body:sub(2):gsub("%s", "") .. "-->')\\n"
else
code[#code + 1] = body .. "\\n"
end
pos = close + 2
end
code[#code + 1] = "return table.concat(_o)"
return table.concat(code)
end
function render_template(file, scope)
local f = assert(io.open(file)); local src = f:read("*a"); f:close()
local fn = assert(loadstring(compile(src), file))
setfenv(fn, setmetatable(scope, {__index = _G}))
return fn()
end
function pcdata(v)
return (tostring(v or ""):gsub("[&<>\\"']", {["&"]="&amp;", ["<"]="&lt;", [">"]="&gt;", ['"']="&quot;", ["'"]="&#39;"}))
end
`;
// 用 proxy.lua 生成真实的 option(分组、选项、cfgvalue),再渲染模板
const pageLoader = `
local options, stored = {}, nil
local function node()
local n = {}
function n:option(kind, name)
local o = {kind=kind, name=name, keylist={}, vallist={}}
function o:value(k, v) self.keylist[#self.keylist + 1] = k; self.vallist[#self.vallist + 1] = v or k end
function o:depends() end
options[name] = o
return o
end
return n
end
function Map()
local m = node()
m.uci = {get=function() return stored end}
function m:section() return node() end
return m
end
for _, name in ipairs({'Flag','Value','DynamicList','ListValue','DummyValue','MultiValue','NamedSection','TypedSection','SimpleSection'}) do _G[name] = name end
package.preload['luci.model.uci'] = function() return {cursor=function() return {foreach=function() end, get=function() return nil end} end} end
package.preload['luci.controller.minigate'] = function() return {ddns_state=function() return {} end} end
local real_open = io.open
io.open = function(file, mode)
if file == '/usr/lib/minigate/geo/regions.txt' then file = ${JSON.stringify(regions)} end
return real_open(file, mode)
end
assert(dofile(${JSON.stringify(proxyPage)}))
local o = options.access_regions
function render_regions(value)
stored = value
return render_template(${JSON.stringify(template)}, {self=o, section='global', cbid='cbid.minigate.global.access_regions'})
end
`;
function run(body) {
const result = spawnSync(lua, ['-'], { encoding: 'utf8', input: renderer + pageLoader + body });
assert.equal(result.status, 0, result.stderr || result.stdout);
return result.stdout;
}
test('region selector renders 34 native checkboxes grouped by region with saved choices checked', { skip: !lua }, () => {
const html = run(`io.write(render_regions({'510000', '500000'}))`);
const boxes = html.match(/<input type="checkbox" class="cbi-input-checkbox" name="cbid\.minigate\.global\.access_regions" value="\d{6}"[^>]*>/g) || [];
assert.equal(boxes.length, 34);
const checked = boxes.filter(box => box.includes('checked="checked"')).map(box => box.match(/value="(\d+)"/)[1]);
assert.deepEqual(checked.sort(), ['500000', '510000']);
const groups = [...html.matchAll(/data-group="([^"]+)"/g)].map(match => match[1]);
assert.deepEqual(groups, ['华北', '东北', '华东', '华中', '华南', '西南', '西北', '港澳台']);
const southwest = html.slice(html.indexOf('data-group="西南"'), html.indexOf('data-group="西北"'));
for (const name of ['重庆市', '四川省', '贵州省', '云南省', '西藏']) assert.ok(southwest.includes(`data-name="${name}"`), name);
assert.match(html, /^<!--include cbi\/valueheader-->/);
assert.match(html, /<!--include cbi\/valuefooter-->\s*$/);
assert.match(html, /id="cbid\.minigate\.global\.access_regions\.panel" hidden="hidden"/);
});
test('region selector accepts the old list format and falls back to the default region', { skip: !lua }, () => {
const out = run(`
local function checked(html) local n = 0; for _ in html:gmatch('checked="checked"') do n = n + 1 end; return n end
print(checked(render_regions('510000 500000 440000')), checked(render_regions(nil)), render_regions(nil):match('value="510000" checked') ~= nil)
`);
assert.equal(out.trim(), '3\t1\ttrue');
});
test('region choices are saved as one string and a hidden field never blocks saving the page', { skip: !lua }, () => {
const out = run(`
local o = options.access_regions
print(o.validate(o, {'510000', '500000'}, 'global'), o.validate(o, '510000', 'global'))
print(o.validate(o, {'510000', '990000'}, 'global'), (select(2, o.validate(o, nil, 'global'))))
local parsed = 0
MultiValue = {parse=function() parsed = parsed + 1 end}
local form = {}
o.map = {formvalue=function(_, key) return form[key] end}
o.parse(o, 'global')
form['cbid.minigate.global.access_enabled'] = '1'
o.parse(o, 'global')
print(parsed)
`);
assert.equal(out.trim(), '510000 500000\t510000\nnil\t请选择至少一个允许的地区\n1');
});
test('region selector script keeps the page form intact and styles follow the theme', () => {
const html = fs.readFileSync(template, 'utf8');
const style = fs.readFileSync(path.join(root, 'luasrc/view/minigate/style.htm'), 'utf8');
// 芯片的移除按钮、清空按钮都不能提交表单;搜索框回车不提交
assert.match(html, /remove\.type='button'/);
assert.match(html, /<button type="button" class="cbi-button mgx-region-clear">/);
assert.match(html, /search\.onkeydown=function\(e\)\{if\(e\.key==='Enter'\)e\.preventDefault\(\);\}/);
assert.match(style, /\.mgx-region-items\{display:grid;grid-template-columns:repeat\(auto-fill,minmax\(9\.5em,1fr\)\)/);
assert.match(style, /\.mgx-region \[hidden\]\{display:none!important\}/);
});
+2 -2
View File
@@ -7,8 +7,8 @@
include $(TOPDIR)/rules.mk include $(TOPDIR)/rules.mk
PKG_NAME:=upx PKG_NAME:=upx
PKG_VERSION:=5.2.1 PKG_VERSION:=5.3.0
PKG_RELEASE:=4 PKG_RELEASE:=5
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)-src.tar.xz PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)-src.tar.xz
PKG_SOURCE_URL:=https://github.com/upx/upx/releases/download/v$(PKG_VERSION) PKG_SOURCE_URL:=https://github.com/upx/upx/releases/download/v$(PKG_VERSION)