diff --git a/clashoo/Makefile b/clashoo/Makefile deleted file mode 100644 index a74e6673..00000000 --- a/clashoo/Makefile +++ /dev/null @@ -1,156 +0,0 @@ -include $(TOPDIR)/rules.mk - -PKG_NAME:=clashoo -PKG_UPSTREAM_VERSION:=1.19.33 -PKG_UPSTREAM_TAG:=v$(PKG_UPSTREAM_VERSION) -PKG_SHORT_SHA:=3f27ef3 - -PKG_VERSION:=2026.10.25.$(PKG_UPSTREAM_VERSION) -PKG_RELEASE:=5 - -PKG_SOURCE:=$(PKG_NAME)-stable-$(PKG_UPSTREAM_TAG)-$(PKG_SHORT_SHA).tar.gz -PKG_SOURCE_SUBDIR:=$(PKG_NAME)-stable-$(PKG_UPSTREAM_TAG)-$(PKG_SHORT_SHA) -PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_SOURCE_SUBDIR) -PKG_SOURCE_URL:=https://github.com/kenzok8/openwrt-clashoo/releases/download/mihomo-src -PKG_SOURCE_VERSION:=3f27ef39f8c96bbfbc8b0b9bb10f5c9ef60149d8 -PKG_HASH:=1ef7a4087f3805bd2624a940e2e43a0bc23719a25465c9f503aa6c11572f1321 -PKG_BUILD_VERSION:=$(PKG_UPSTREAM_TAG) - -PKG_LICENSE:=GPL3.0+ -PKG_MAINTAINER:=kenzok8 - -PKG_BUILD_DEPENDS:=golang/host -PKG_BUILD_PARALLEL:=1 -PKG_BUILD_FLAGS:=no-mips16 - -PKG_BUILD_TIME:=$(shell date -u -Iseconds) - -GO_PKG:=github.com/metacubex/mihomo -GO_PKG_LDFLAGS_X:=$(GO_PKG)/constant.Version=$(PKG_BUILD_VERSION) $(GO_PKG)/constant.BuildTime=$(PKG_BUILD_TIME) -GO_PKG_TAGS:=with_gvisor - -include $(INCLUDE_DIR)/package.mk -include $(TOPDIR)/feeds/packages/lang/golang/golang-package.mk - -define Package/clashoo - SECTION:=net - CATEGORY:=Network - TITLE:=Clashoo (Mihomo) - DEPENDS:=$(GO_ARCH_DEPENDS) +ca-bundle +yq +firewall4 +ip-full +coreutils-nohup +coreutils-timeout +kmod-inet-diag +kmod-nft-socket +kmod-nft-tproxy +kmod-tun +kmod-dummy +unzip - PROVIDES:=mihomo clash-meta -endef - -define Package/clashoo/description - Mihomo proxy core with runtime environment for Clashoo. -endef - -define Package/clashoo/conffiles -/etc/config/clashoo -endef - -define Package/clashoo/install - $(call GoPackage/Package/Install/Bin,$(1)) - - $(INSTALL_DIR) $(1)/usr/libexec/clashoo - $(INSTALL_DIR) $(1)/usr/bin - mv -f $(1)/usr/bin/mihomo $(1)/usr/libexec/clashoo/mihomo-stable - ln -sf /usr/libexec/clashoo/mihomo-stable $(1)/usr/bin/mihomo - ln -sf /usr/libexec/clashoo/mihomo-stable $(1)/usr/bin/clash-meta - - $(INSTALL_DIR) $(1)/etc/init.d - $(INSTALL_DIR) $(1)/etc/config - $(INSTALL_DIR) $(1)/etc/clashoo - $(INSTALL_DIR) $(1)/etc/clashoo/provider - $(INSTALL_DIR) $(1)/etc/clashoo/proxyprovider - $(INSTALL_DIR) $(1)/etc/clashoo/ruleprovider - $(INSTALL_DIR) $(1)/usr/share/clashoo - $(INSTALL_DIR) $(1)/usr/share/clashbackup - $(INSTALL_DIR) $(1)/usr/share/clashoo/config - $(INSTALL_DIR) $(1)/usr/share/clashoo/config/sub - $(INSTALL_DIR) $(1)/usr/share/clashoo/config/upload - $(INSTALL_DIR) $(1)/usr/share/clashoo/config/custom - - $(INSTALL_BIN) $(CURDIR)/files/etc/init.d/clashoo $(1)/etc/init.d/clashoo - $(INSTALL_CONF) $(CURDIR)/files/etc/config/clashoo $(1)/etc/config/clashoo - $(INSTALL_DATA) $(CURDIR)/files/etc/config/clashoo $(1)/usr/share/clashoo/clashoo.default - $(CP) $(CURDIR)/files/usr/share/clashoo/* $(1)/usr/share/clashoo/ - $(INSTALL_BIN) $(CURDIR)/files/usr/share/clashoo/migrate_lan_acl.sh $(1)/usr/share/clashoo/migrate_lan_acl.sh - $(INSTALL_BIN) $(CURDIR)/files/usr/share/clashoo/migrate_fake_ip_filter.sh $(1)/usr/share/clashoo/migrate_fake_ip_filter.sh - $(INSTALL_BIN) $(CURDIR)/files/usr/share/clashoo/detect_core_arch.sh $(1)/usr/share/clashoo/detect_core_arch.sh - $(INSTALL_BIN) $(CURDIR)/files/usr/share/clashoo/diagnose_bypass.sh $(1)/usr/share/clashoo/diagnose_bypass.sh - - $(RM) $(1)/usr/share/clashoo/dashboard - $(RM) $(1)/usr/share/clashoo/yacd - $(RM) $(1)/usr/share/clashoo/update.log - $(RM) $(1)/usr/share/clashoo/geoip.log - $(RM) $(1)/usr/share/clashoo/core_down_complete -endef - -define Package/clashoo/preinst -#!/bin/sh -if [ -z "$${IPKG_INSTROOT}" ]; then - save_core() { - src="$$1" - dst="$$2" - [ -f "$$src" ] && [ ! -L "$$src" ] || return 0 - if [ -e "$$dst" ] || [ -L "$$dst" ]; then return 0; fi - mkdir -p "$$(dirname "$$dst")" || return 1 - tmp="$$dst.tmp.$$$$" - cp "$$src" "$$tmp" && chmod 0755 "$$tmp" && cmp -s "$$src" "$$tmp" || { - rm -f "$$tmp" - return 1 - } - if command -v sha256sum >/dev/null 2>&1; then - old_hash="$$(sha256sum "$$src" | awk '{print $$1}')" - new_hash="$$(sha256sum "$$tmp" | awk '{print $$1}')" - [ "$$old_hash" = "$$new_hash" ] || { - rm -f "$$tmp" - return 1 - } - fi - mv -f "$$tmp" "$$dst" - } - save_core /usr/bin/mihomo /usr/share/clashoo/bin/mihomo-alpha || exit 1 - save_core /usr/bin/mihomo-stable /usr/share/clashoo/bin/mihomo-stable || exit 1 - if [ -x /usr/bin/clash-meta ] && [ ! -L /usr/bin/clash-meta ] && [ ! -e /usr/share/clashoo/bin/mihomo-stable ]; then - if ! /usr/bin/clash-meta -v 2>/dev/null | grep -Eiq '(alpha|beta|rc|pre|smart)'; then - save_core /usr/bin/clash-meta /usr/share/clashoo/bin/mihomo-stable || exit 1 - fi - fi -fi -exit 0 -endef - -define Package/clashoo/postinst -#!/bin/sh -if [ -z "$${IPKG_INSTROOT}" ]; then - rm -f /usr/share/clashoo/check_luci_version.sh /usr/share/clashoo/check_clash_meta_version.sh /usr/share/clashoo/check_mihomo_core_version.sh - rm -f /usr/share/clashoo/cuslist.sh /usr/share/clashoo/groups.sh /usr/share/clashoo/load_groups.sh /usr/share/clashoo/panel_diag.sh - rm -f /usr/share/clashoo/rmlist.sh /usr/share/clashoo/uplist.sh /usr/share/clashoo/rpc_restart_async.sh /usr/share/clashoo/rpc_update_china_ip_async.sh - rm -rf /usr/share/clashoo/create - # 旧方案把 stable 内核放在 /usr/bin/mihomo-stable,现方案改用 - # /usr/libexec/clashoo/mihomo-stable(随包)+ /usr/share/clashoo/bin/(自定义下载)。 - # preinst 已把它抄到 /usr/share/clashoo/bin/mihomo-stable,确认内容相同后才删 - # 旧位置;目标已有其他自定义内核时保留旧文件,避免误删。 - if [ -f /usr/share/clashoo/bin/mihomo-stable ] && [ -f /usr/bin/mihomo-stable ] && [ ! -L /usr/bin/mihomo-stable ] && cmp -s /usr/bin/mihomo-stable /usr/share/clashoo/bin/mihomo-stable; then - rm -f /usr/bin/mihomo-stable - fi - /usr/share/clashoo/migrate_lan_acl.sh >/dev/null 2>&1 || true - /usr/share/clashoo/migrate_fake_ip_filter.sh >/dev/null 2>&1 || true - /usr/share/clashoo/detect_core_arch.sh >/dev/null 2>&1 || true - if [ "$$(uci -q get clashoo.config.enable 2>/dev/null)" = "1" ]; then - /etc/init.d/clashoo enable 2>/dev/null || true - else - /etc/init.d/clashoo disable 2>/dev/null || true - fi -fi -exit 0 -endef - -define Build/Prepare - $(Build/Prepare/Default) - $(RM) -r $(PKG_BUILD_DIR)/rules/logic_test -endef - -$(eval $(call GoBinPackage,clashoo)) -$(eval $(call BuildPackage,clashoo)) diff --git a/clashoo/files/etc/config/clashoo b/clashoo/files/etc/config/clashoo deleted file mode 100644 index d744fb10..00000000 --- a/clashoo/files/etc/config/clashoo +++ /dev/null @@ -1,156 +0,0 @@ - -config clashoo 'config' - option redir_port '7891' - option http_port '8080' - option socks_port '1080' - option mixed_port '7890' - option enable_ipv6 'true' - option enable '0' - option dash_port '9090' - option dashboard_panel 'zashboard' - option level 'info' - option core '2' - option allow_lan '1' - option dnsforwader '1' - option subcri 'meta' - option cusrule '0' - option dnscache '1' - option p_mode 'rule' - option append_rules '0' - option enhanced_mode 'fake-ip' - option fake_ip_range '198.18.0.1/16' - option fake_ip_range6 'fc00::/18' - list fake_ip_filter '+.lan' - list fake_ip_filter '+.local' - list fake_ip_filter 'localhost.ptlogin2.qq.com' - list fake_ip_filter 'rule-set:cn_domain' - option fake_ip_filter_migrated '1' - option listen_port '1053' - option interf '0' - option download_core 'amd64-compatible' - option dcore '2' - option same_tag '1' - option geoip_source '3' - option geoip_format 'mmdb' - option geodata_loader 'standard' - option tproxy_port '7982' - option access_control '0' - option acl_migrated '1' - option tcp_mode 'redirect' - option tun_mode '0' - option core_mirror_prefix 'https://gh-proxy.com/' - option core_download_advanced '0' - list default_nameserver '223.5.5.5' - list default_nameserver '119.29.29.29' - option dns_ecs '' - option dns_ecs_override '0' - option fallback_filter_geoip '0' - list fallback_filter_ipcidr '240.0.0.0/4' - option dns_respect_rules '1' - option dns_loopback_compat '0' - option dns_migrated '1' - option block_quic '0' - option singbox_independent_cache '0' - option udp_mode 'tproxy' - option ipv4_dns_hijack '1' - option ipv6_dns_hijack '1' - option ipv4_proxy '1' - option ipv6_proxy '1' - option fake_ip_ping_hijack '1' - option dns_leak_protect '0' - option geoip_mmdb_url 'https://raw.githubusercontent.com/Loyalsoldier/geoip/release/Country.mmdb' - option geosite_url 'https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/geosite.dat' - option geoip_dat_url 'https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/geoip.dat' - option enable_udp '1' - option stack 'gvisor' - option bypass_china '1' - option bypass_china_ipv6 '1' - option bypass_port_mode 'common' - option sniffer_streaming '1' - option selection_cache '1' - option fake_ip_cache '1' - option enable_dns '1' - option disable_quic_gso '1' - option smart_policy_priority 'Premium:0.9;SG:1.3' - option smart_prefer_asn '1' - option smart_uselightgbm '1' - option smart_collectdata '1' - option smart_collect_size '100' - option smart_collect_rate '1' - option smart_lgbm_auto_update '1' - option smart_lgbm_update_interval '72' - option smart_lgbm_url 'https://github.com/vernesong/mihomo/releases/download/LightGBM-Model/Model.bin' - list defaul_nameserver '114.114.114.114' - list defaul_nameserver '223.5.5.5' - option auto_update '1' - option auto_update_time '72' - option auto_subscription_update '0' - option subscription_update_interval '72' - option auto_clear_log '1' - option clear_time '72' - option core_type 'mihomo' - option smart_auto_switch '0' - option core_only '0' - -config hosts - option enabled '0' - option adress '*.clash.dev' - option ip '127.0.0.1' - -config hosts - option enabled '0' - option adress 'alpha.clash.dev' - option ip '::1' - -config dnsservers - option enabled '1' - option ser_type 'nameserver' - option ser_address 'https://dns.alidns.com/dns-query' - option protocol 'none' - -config dnsservers - option enabled '1' - option ser_type 'nameserver' - option ser_address 'https://doh.pub/dns-query' - option protocol 'none' - -config dnsservers - option enabled '1' - option ser_type 'proxy-server-nameserver' - option ser_address '1.1.1.1' - option protocol 'tls://' - option ser_port '853' - -config dnsservers - option enabled '1' - option ser_type 'fallback' - option ser_address 'https://cloudflare-dns.com/dns-query' - option protocol 'none' - -config dnsservers - option enabled '1' - option ser_type 'fallback' - option ser_address 'https://dns.google/dns-query' - option protocol 'none' - -config dnsservers - option enabled '1' - option ser_type 'direct-nameserver' - option ser_address '223.5.5.5' - option protocol 'udp://' - -config dns_policy - option enabled '1' - option policy_type 'nameserver-policy' - option matcher 'geosite:cn' - list nameserver 'https://dns.alidns.com/dns-query' - list nameserver 'https://doh.pub/dns-query' - -config authentication - -# default empty custom-rule row so the section shows the input form, not just an add -# button; injectors skip rules with an empty ipaaddr, so it generates nothing until filled -config addtype - option type 'DOMAIN-SUFFIX' - option pgroup 'DIRECT' - option ipaaddr '' diff --git a/clashoo/files/etc/init.d/clashoo b/clashoo/files/etc/init.d/clashoo deleted file mode 100755 index a58f650e..00000000 --- a/clashoo/files/etc/init.d/clashoo +++ /dev/null @@ -1,2769 +0,0 @@ -#!/bin/sh /etc/rc.common -USE_PROCD=1 -EXTRA_COMMANDS="refresh_cron" - -START=99 -STOP=15 - -CORE_LOG_PATH="/var/log/clashoo/core.log" -SINGBOX_BIN_DIR="/usr/share/clashoo/bin" -SINGBOX_RUNTIME_DIR="/var/run/clashoo/sing-box" -SINGBOX_RUNTIME_CONFIG="$SINGBOX_RUNTIME_DIR/config.json" -SINGBOX_WORKDIR="$SINGBOX_RUNTIME_DIR/work" - -. /usr/share/clashoo/runtime/dns_helpers.sh 2>/dev/null || true - -command_exists() { - command -v "$1" >/dev/null 2>&1 -} - -shell_quote() { - printf "'" - printf '%s' "$1" | sed "s/'/'\\\\''/g" - printf "'" -} - -use_fw4_backend() { - command_exists fw4 && command_exists nft -} - -backend_name() { - if use_fw4_backend; then - echo "fw4" - else - echo "unsupported" - fi -} - -backend_apply_rules() { - if use_fw4_backend; then - /usr/share/clashoo/net/fw4.sh apply - else - _log_runtime_error "Current environment requires fw4+nft support" - return 1 - fi -} - -backend_remove_rules() { - if use_fw4_backend; then - /usr/share/clashoo/net/fw4.sh remove - else - return 0 - fi -} - -_clashoo_enabled() { - [ "$(uci -q get clashoo.config.enable 2>/dev/null)" = "1" ] -} - -# Compute start-wait window: TUN needs longer for utun setup + fake-ip pool init. -# Override via `uci set clashoo.config.start_wait_secs=N` for slow devices. -_compute_start_wait() { - local override - override="$(uci -q get clashoo.config.start_wait_secs)" - if [ -n "$override" ] && [ "$override" -gt 0 ] 2>/dev/null; then - echo "$override"; return - fi - if [ "$(uci -q get clashoo.config.tun_mode)" = "1" ]; then - echo 15 - else - echo 6 - fi -} - -selected_singbox_binary() { - local dcore - dcore="$(uci -q get clashoo.config.dcore 2>/dev/null)" - case "$dcore" in - 4) echo "$SINGBOX_BIN_DIR/sing-box-stable" ;; - 5) echo "$SINGBOX_BIN_DIR/sing-box-alpha" ;; - *) return 1 ;; - esac -} - -_migrate_legacy_singbox_binary() { - local dcore target legacy staged - dcore="$(uci -q get clashoo.config.dcore 2>/dev/null)" - target="$(selected_singbox_binary)" || return 1 - [ -e "$target" ] && return 0 - case "$dcore" in - 4) legacy="/usr/bin/sing-box-stable" ;; - 5) legacy="/usr/bin/sing-box-alpha" ;; - *) return 1 ;; - esac - [ -x "$legacy" ] || return 1 - mkdir -p "$SINGBOX_BIN_DIR" >/dev/null 2>&1 || return 1 - staged="${target}.$$" - rm -f "$staged" >/dev/null 2>&1 - cp -f "$legacy" "$staged" >/dev/null 2>&1 || { - rm -f "$staged" >/dev/null 2>&1 - return 1 - } - chmod 0755 "$staged" >/dev/null 2>&1 || { - rm -f "$staged" >/dev/null 2>&1 - return 1 - } - mv -f "$staged" "$target" >/dev/null 2>&1 || { - rm -f "$staged" >/dev/null 2>&1 - return 1 - } - return 0 -} - -_ensure_singbox_binary() { - local target - target="$(selected_singbox_binary)" || return 1 - [ -e "$target" ] || _migrate_legacy_singbox_binary || return 1 - [ -x "$target" ] -} - -_singbox_pid_owns_private_binary() { - local pid stable alpha exe cmdline - pid="$1" - stable="$SINGBOX_BIN_DIR/sing-box-stable" - alpha="$SINGBOX_BIN_DIR/sing-box-alpha" - [ -d "/proc/$pid" ] || return 1 - if command_exists readlink; then - exe="$(readlink -f "/proc/$pid/exe" 2>/dev/null)" - if [ "$exe" = "$stable" ] || [ "$exe" = "$alpha" ]; then - return 0 - fi - fi - cmdline="$(tr '\000' ' ' < "/proc/$pid/cmdline" 2>/dev/null)" - case "$cmdline" in - "$stable"|"$stable "*|"$alpha"|"$alpha "*) return 0 ;; - esac - return 1 -} - -_singbox_instance_pid() { - local _pid - _pid="$(ubus call service list '{"name":"clashoo","verbose":true}' 2>/dev/null \ - | jsonfilter -e '@.clashoo.instances.singbox.pid' 2>/dev/null | head -n1)" - [ -n "$_pid" ] && _singbox_pid_owns_private_binary "$_pid" && echo "$_pid" -} - -_singbox_running() { - local _pid - _pid="$(_singbox_instance_pid)" - [ -n "$_pid" ] && [ -d "/proc/$_pid" ] -} - -# Roll back partial state when start failed after backend rules / DNS were applied. -# Reuses the same cleanup primitives as stop_service so behavior stays consistent. -_rollback_failed_start() { - log_msg "Rolling back failed start" "启动失败,正在回退防火墙与 DNS 配置" - backend_remove_rules >/dev/null 2>&1 - cleanup_stale_core_nft >/dev/null 2>&1 - revert_dns >/dev/null 2>&1 - stop_singbox_service >/dev/null 2>&1 - _kill_core >/dev/null 2>&1 - rm -rf /www/luci-static/yacd 2>/dev/null - del_cron >/dev/null 2>&1 -} - -cleanup_stale_core_nft() { - for _nft_table in "inet mihomo" "inet sing-box"; do - nft delete table $_nft_table 2>/dev/null || true - done -} - -_core_candidates() { - echo "/usr/share/clashoo/bin/mihomo-stable /usr/libexec/clashoo/mihomo-stable /usr/share/clashoo/bin/mihomo-alpha /usr/bin/mihomo /usr/bin/clash-meta /etc/clashoo/clash" -} - -_migrate_legacy_mihomo_stable() { - local legacy=/usr/bin/clash-meta target=/usr/share/clashoo/bin/mihomo-stable version staged - [ -x "$target" ] && return 0 - [ -x "$legacy" ] && [ ! -L "$legacy" ] || return 0 - version=$("$legacy" -v 2>/dev/null | head -n 1) - [ -n "$version" ] || return 0 - echo "$version" | grep -Eiq '(alpha|beta|rc|pre|smart)' && return 0 - mkdir -p "$(dirname "$target")" || return 1 - staged="${target}.$$" - cp -f "$legacy" "$staged" 2>/dev/null && chmod 0755 "$staged" && mv -f "$staged" "$target" -} - -_mihomo_stable_binary() { - local bundled=/usr/libexec/clashoo/mihomo-stable manual=/usr/share/clashoo/bin/mihomo-stable bundled_ver manual_ver - # A successful custom download is an explicit override, even if its version is older. - if [ -x "$manual" ] && - [ "$(sed -n '1{s/^[[:space:]]*//;s/[[:space:]]*$//;p;}' /usr/share/clashoo/clash_meta_version 2>/dev/null)" = "custom-url" ]; then - echo "$manual" - return 0 - fi - [ -x "$bundled" ] || { [ -x "$manual" ] && { echo "$manual"; return 0; }; return 1; } - [ -x "$manual" ] || { echo "$bundled"; return; } - bundled_ver="$("$bundled" -v 2>/dev/null | awk '{for (i = 1; i < NF; i++) if ($i == "Meta") {print $(i + 1); exit}}')" - manual_ver="$("$manual" -v 2>/dev/null | awk '{for (i = 1; i < NF; i++) if ($i == "Meta") {print $(i + 1); exit}}')" - bundled_ver="${bundled_ver#v}" - manual_ver="${manual_ver#v}" - printf '%s\n' "$bundled_ver" | grep -Eq '^[0-9]+\.[0-9]+\.[0-9]+$' || bundled_ver="" - printf '%s\n' "$manual_ver" | grep -Eq '^[0-9]+\.[0-9]+\.[0-9]+$' || manual_ver="" - if [ -n "$bundled_ver" ] && [ -n "$manual_ver" ]; then - if awk -v manual="$manual_ver" -v bundled="$bundled_ver" 'BEGIN { - split(manual, m, "."); split(bundled, b, "."); - for (i = 1; i <= 3; i++) { - if (m[i] + 0 > b[i] + 0) exit 0; - if (m[i] + 0 < b[i] + 0) exit 1; - } - exit 0; - }'; then - echo "$manual" - else - echo "$bundled" - fi - elif [ -n "$manual_ver" ]; then - echo "$manual" - else - echo "$bundled" - fi -} - -_detect_selected_core() { - local selected - selected=$(uci get clashoo.config.core 2>/dev/null) - case "$selected" in - 1) - for _bin in /usr/bin/smart /etc/clashoo/clash /usr/bin/clash; do - [ -x "$_bin" ] && echo "$_bin" && return - done - return 1 - ;; - 2|mihomo) - _mihomo_stable_binary - return $? - ;; - 3|mihomo-alpha) - [ -x /usr/share/clashoo/bin/mihomo-alpha ] && echo /usr/share/clashoo/bin/mihomo-alpha && return - return 1 - ;; - esac - _detect_core -} - -core_supports_advanced_features() { - case "$CLASH" in - */mihomo|*/mihomo-stable|*/mihomo-alpha|*/clash-meta|*/smart) - return 0 - ;; - *) - return 1 - ;; - esac -} - -# only trust procd instance PIDs (not binary name); openclash/nikki/passwall share -# the same binary names. Use ubus service list as source of truth. -_clashoo_instance_pid() { - ubus call service list "{\"name\":\"clashoo\",\"verbose\":true}" 2>/dev/null \ - | jsonfilter -e '@.clashoo.instances.*.pid' 2>/dev/null | head -n1 -} - -_core_running() { - local _pid - _pid="$(_clashoo_instance_pid)" - [ -n "$_pid" ] && [ -d "/proc/$_pid" ] -} - -# kill only clashoo procd instances, never by binary name — would hit co-installed plugins. -_kill_core() { - local _pid _wait - _pid="$(_clashoo_instance_pid)" - [ -n "$_pid" ] || return 0 - kill "$_pid" >/dev/null 2>&1 - _wait=0 - while [ "$_wait" -lt 3 ] && [ -d "/proc/$_pid" ]; do - sleep 1 - _wait=$((_wait + 1)) - done - [ -d "/proc/$_pid" ] && kill -9 "$_pid" >/dev/null 2>&1 -} - -_selected_core_running() { - if is_singbox_selected; then - _singbox_running - else - _core_running - fi -} - -selected_core_family() { - local core_type - core_type="$(uci -q get clashoo.config.core_type 2>/dev/null)" - [ "$core_type" = "singbox" ] && echo "singbox" || echo "mihomo" -} - -is_singbox_selected() { - [ "$(selected_core_family)" = "singbox" ] -} - -sync_legacy_core_field() { - local dcore legacy - dcore="$(uci -q get clashoo.config.dcore 2>/dev/null)" - if is_singbox_selected; then - [ "$dcore" = "5" ] && legacy="5" || legacy="4" - else - case "$dcore" in - 1) legacy="1" ;; - 3) legacy="3" ;; - *) legacy="2" ;; - esac - fi - uci -q set clashoo.config.core="$legacy" - uci -q commit clashoo >/dev/null 2>&1 -} - -prepare_singbox_runtime() { - local active src redir_port tproxy_port mixed_port dns_port tmp_config - active="$(uci -q get clashoo.config.singbox_active 2>/dev/null)" - src="/usr/share/clashoo/config/singbox/${active}" - tmp_config="${SINGBOX_RUNTIME_CONFIG}.tmp.$$" - - mkdir -p "$SINGBOX_RUNTIME_DIR" "$SINGBOX_WORKDIR" "$(dirname "$CORE_LOG_PATH")" >/dev/null 2>&1 || return 1 - rm -f "$tmp_config" >/dev/null 2>&1 - if [ -n "$active" ] && [ -r "$src" ]; then - cp -f "$src" "$tmp_config" >/dev/null 2>&1 || { - rm -f "$tmp_config" >/dev/null 2>&1 - return 1 - } - elif [ -r "$SINGBOX_RUNTIME_CONFIG" ]; then - cp -f "$SINGBOX_RUNTIME_CONFIG" "$tmp_config" >/dev/null 2>&1 || { - rm -f "$tmp_config" >/dev/null 2>&1 - return 1 - } - else - _log_runtime_error "sing-box config.json is missing; please generate or select a sing-box profile first" - rm -f "$tmp_config" >/dev/null 2>&1 - return 1 - fi - - command -v ucode >/dev/null 2>&1 || { - _log_runtime_error "ucode is required to prepare sing-box runtime config" - rm -f "$tmp_config" >/dev/null 2>&1 - return 1 - } - # Migrate every imported config, including core-only mode, before any - # Clashoo-specific normalization. The temp file is in the runtime dir so - # a failed migration/normalization never replaces the last good config. - ucode /usr/share/clashoo/lib/migrate_singbox.uc "$tmp_config" >/dev/null 2>&1 || { - _log_runtime_error "sing-box runtime config migration failed" - rm -f "$tmp_config" >/dev/null 2>&1 - return 1 - } - - if [ "$(uci -q get clashoo.config.core_only 2>/dev/null)" != "1" ]; then - local has_tun_device dash_port dash_pass - - has_tun_device=1 - runtime_has_tun_device || has_tun_device=0 - redir_port="$(uci -q get clashoo.config.redir_port 2>/dev/null)" - tproxy_port="$(uci -q get clashoo.config.tproxy_port 2>/dev/null)" - mixed_port="$(uci -q get clashoo.config.mixed_port 2>/dev/null)" - dns_port="$(uci -q get clashoo.config.listen_port 2>/dev/null)" - dash_port="$(uci -q get clashoo.config.dash_port 2>/dev/null)" - dash_pass="$(uci -q get clashoo.config.dash_pass 2>/dev/null)" - [ -z "$redir_port" ] && redir_port=7891 - [ -z "$tproxy_port" ] && tproxy_port=7982 - [ -z "$mixed_port" ] && mixed_port=7890 - [ -z "$dns_port" ] && dns_port=1053 - [ -z "$dash_port" ] && dash_port=9090 - # routing_mark 6666 must match fw4.sh CORE_ROUTING_MARK (0x1a0a). - # Never reuse PROXY_FWMARK (0x162) — it would pull egress to lo -> unreachable. - ucode /usr/share/clashoo/lib/normalize_singbox_config.uc \ - "$tmp_config" "$redir_port" "$tproxy_port" "$mixed_port" "$has_tun_device" "6666" "$dns_port" "$dash_port" "$dash_pass" >/dev/null 2>&1 || { - _log_runtime_error "sing-box runtime config normalization failed" - rm -f "$tmp_config" >/dev/null 2>&1 - return 1 - } - fi - - mv -f "$tmp_config" "$SINGBOX_RUNTIME_CONFIG" >/dev/null 2>&1 || { - rm -f "$tmp_config" >/dev/null 2>&1 - return 1 - } - return 0 -} - -start_singbox_service() { - local bin - bin="$(selected_singbox_binary)" || return 1 - if ! _ensure_singbox_binary; then - _log_runtime_error "sing-box core not found, please install the local sing-box binary first" - return 1 - fi - prepare_singbox_runtime || return 1 - # preflight dry-run with watchdog: bail on bad config without touching - # firewall/dnsmasq, and never let a hung check freeze startup/UI. - _run_with_timeout 15 "$bin" -c "$SINGBOX_RUNTIME_CONFIG" check >> "$CORE_LOG_PATH" 2>&1 - _pf_rc=$? - if [ "$_pf_rc" -ne 0 ]; then - _pf_reason="$(_preflight_reason)" - if [ "$_pf_rc" -eq 124 ]; then - log_msg "sing-box config preflight timed out, retry shortly. ${_pf_reason}" "sing-box 配置预检超时,稍后自动重试。${_pf_reason}" - runtime_state_record_health "fail" "preflight:singbox_timeout" - else - log_msg "sing-box config dry-run failed; firewall/DNS untouched. ${_pf_reason}" "sing-box 配置预检失败,未应用防火墙与 DNS 改动。${_pf_reason}" - runtime_state_record_health "fail" "preflight:singbox_dry_run_failed" - fi - return 1 - fi - procd_open_instance "singbox" - procd_set_param command "$bin" run -c "$SINGBOX_RUNTIME_CONFIG" -D "$SINGBOX_WORKDIR" - procd_set_param user root - procd_set_param file "$SINGBOX_RUNTIME_CONFIG" - procd_set_param stdout 1 - procd_set_param stderr 1 - procd_set_param limits core="unlimited" - procd_set_param limits nofile="1000000 1000000" - procd_set_param respawn 3600 5 5 - procd_close_instance -} - -stop_singbox_service() { - local _wait=0 _pid - # procd_kill removes the named instance and disables its respawn; signaling - # the child through ubus would let procd recreate it behind our back. - procd_kill clashoo singbox >/dev/null 2>&1 || true - _pid="$(_singbox_instance_pid)" - [ -n "$_pid" ] || return 0 - while [ "$_wait" -lt 3 ]; do - _pid="$(_singbox_instance_pid)" - [ -z "$_pid" ] && return 0 - _singbox_running || return 0 - sleep 1 - _wait=$((_wait + 1)) - done -} - -_log_runtime_error() { - local message="$1" - echo "$message" > "$REAL_LOG" - echo " $(date "+%Y-%m-%d %H:%M:%S") - $message" >> /usr/share/clashoo/clashoo.txt -} - -# Run a command with a self-watchdog timeout. busybox has no `timeout` binary, -# so poll the backgrounded pid and kill it on overrun. Returns the command's -# exit status, or 124 when the watchdog fired (timed out). -_run_with_timeout() { - local _to="$1"; shift - local _pid _i=0 - "$@" & - _pid=$! - while [ "$_i" -lt "$_to" ]; do - kill -0 "$_pid" 2>/dev/null || { wait "$_pid"; return $?; } - sleep 1 - _i=$((_i + 1)) - done - kill -TERM "$_pid" 2>/dev/null - sleep 1 - kill -KILL "$_pid" 2>/dev/null - wait "$_pid" 2>/dev/null - return 124 -} - -# Pull a concise failure reason out of the core log so users see the real error -# (e.g. "can't download MMDB") instead of only "preflight failed". -_preflight_reason() { - local line - line="$(grep -E 'level=(error|fatal)' "$CORE_LOG_PATH" 2>/dev/null | tail -1)" - [ -n "$line" ] || line="$(tail -1 "$CORE_LOG_PATH" 2>/dev/null)" - case "$line" in - *'msg="'*) line="$(printf '%s' "$line" | sed -n 's/.*msg="\([^"]*\)".*/\1/p')" ;; - esac - printf '%s' "$line" -} - -log_msg() { - local en_msg="$1" zh_msg="$2" - local out_msg now - now="$(date "+%Y-%m-%d %H:%M:%S")" - if [ "${lang}" = "en" ]; then - out_msg="$en_msg" - else - out_msg="$zh_msg" - fi - echo "$out_msg" > "$REAL_LOG" - [ -n "$out_msg" ] && echo " ${now} - ${out_msg}" >> /usr/share/clashoo/clashoo.txt -} - -runtime_state_reset() { - rm -f "$RUNTIME_STATE_FILE" >/dev/null 2>&1 || true -} - -runtime_state_set() { - local key="$1" value="${2:-}" safe_value - [ -n "$key" ] || return 0 - mkdir -p "$(dirname "$RUNTIME_STATE_FILE")" >/dev/null 2>&1 - touch "$RUNTIME_STATE_FILE" - value="$(printf '%s' "$value" | tr '\r\n' ' ')" - safe_value="$(printf '%s' "$value" | sed 's/[\/&|\\]/\\&/g')" - if grep -q "^${key}=" "$RUNTIME_STATE_FILE" 2>/dev/null; then - sed -i "s|^${key}=.*|${key}=${safe_value}|g" "$RUNTIME_STATE_FILE" - else - echo "${key}=${value}" >> "$RUNTIME_STATE_FILE" - fi -} - -runtime_has_tun_device() { - ip tuntap add mode tun name cotuntest >/dev/null 2>&1 || return 1 - ip link del cotuntest >/dev/null 2>&1 || true - return 0 -} - -resolve_effective_tp_modes() { - local configured_tcp configured_udp - configured_tcp="$(uci -q get clashoo.config.tcp_mode 2>/dev/null)" - configured_udp="$(uci -q get clashoo.config.udp_mode 2>/dev/null)" - [ -z "$configured_tcp" ] && configured_tcp="redirect" - [ -z "$configured_udp" ] && configured_udp="$configured_tcp" - - EFFECTIVE_TCP_MODE="$configured_tcp" - EFFECTIVE_UDP_MODE="$configured_udp" - RUNTIME_DEGRADED="0" - RUNTIME_DEGRADE_REASON="" - HAS_TUN_DEVICE="1" - - if ! runtime_has_tun_device; then - HAS_TUN_DEVICE="0" - if [ "$EFFECTIVE_TCP_MODE" = "tun" ]; then - EFFECTIVE_TCP_MODE="redirect" - RUNTIME_DEGRADED="1" - fi - if [ "$EFFECTIVE_UDP_MODE" = "tun" ]; then - EFFECTIVE_UDP_MODE="tproxy" - RUNTIME_DEGRADED="1" - fi - fi - - [ "$RUNTIME_DEGRADED" = "1" ] && RUNTIME_DEGRADE_REASON="tun_unavailable_auto_fallback" -} - -runtime_state_record_preflight() { - local configured_tcp configured_udp core_family enhanced_mode - core_family="$1" - configured_tcp="$(uci -q get clashoo.config.tcp_mode 2>/dev/null)" - configured_udp="$(uci -q get clashoo.config.udp_mode 2>/dev/null)" - enhanced_mode="$(uci -q get clashoo.config.enhanced_mode 2>/dev/null)" - [ -z "$configured_tcp" ] && configured_tcp="redirect" - [ -z "$configured_udp" ] && configured_udp="$configured_tcp" - [ -z "$enhanced_mode" ] && enhanced_mode="fake-ip" - - runtime_state_set "configured_core" "$core_family" - runtime_state_set "configured_tcp_mode" "$configured_tcp" - runtime_state_set "configured_udp_mode" "$configured_udp" - runtime_state_set "effective_tcp_mode" "$EFFECTIVE_TCP_MODE" - runtime_state_set "effective_udp_mode" "$EFFECTIVE_UDP_MODE" - runtime_state_set "has_tun_device" "$HAS_TUN_DEVICE" - runtime_state_set "degraded" "$RUNTIME_DEGRADED" - runtime_state_set "degrade_reason" "$RUNTIME_DEGRADE_REASON" - runtime_state_set "enhanced_mode" "$enhanced_mode" - runtime_state_set "health_status" "pending" - runtime_state_set "health_detail" "init" - runtime_state_set "updated_at" "$(date +%s)" -} - -runtime_state_record_health() { - local status detail - status="$1" - detail="${2:-}" - [ -z "$status" ] && status="unknown" - runtime_state_set "health_status" "$status" - runtime_state_set "health_detail" "$detail" - runtime_state_set "updated_at" "$(date +%s)" -} - -runtime_state_accepts_health_update() { - _selected_core_running || return 1 - case "$(grep '^health_detail=' "$RUNTIME_STATE_FILE" 2>/dev/null | cut -d= -f2-)" in - service_stopped|service_disabled|boot_disabled) - return 1 - ;; - esac - return 0 -} - -curl_has_final_http_response() { - awk ' - /^HTTP\// && $0 !~ /Connection established/ { ok=1 } - END { exit ok ? 0 : 1 } - ' -} - -runtime_run_health_check() { - local dns_state explicit_state transparent_state detail require_fakeip mixed_port _try - local dns_out dns_addr _url - - runtime_state_accepts_health_update || return 1 - - dns_state="na" - explicit_state="na" - transparent_state="na" - require_fakeip="0" - [ "$(uci -q get clashoo.config.enable_dns 2>/dev/null)" != "0" ] && [ "$(uci -q get clashoo.config.enhanced_mode 2>/dev/null)" = "fake-ip" ] && require_fakeip="1" - - if command_exists nslookup; then - dns_state="fail" - for _try in 1 2 3; do - if command_exists timeout; then - dns_out="$(timeout 3 nslookup www.google.com 127.0.0.1 2>/dev/null)" - else - dns_out="$(nslookup www.google.com 127.0.0.1 2>/dev/null)" - fi - dns_addr="$(echo "$dns_out" | awk '/^Address: /{print $2} /^Address [0-9]+: /{print $3}' | grep -E '^[0-9a-fA-F:.]+$' | tail -n1)" - if [ -n "$dns_addr" ]; then - if echo "$dns_addr" | grep -Eq '^198\.18\.|^fc00:'; then - dns_state="ok" - else - dns_state="compat" - fi - break - fi - sleep 1 - done - fi - - mixed_port="$(uci -q get clashoo.config.mixed_port 2>/dev/null)" - [ -z "$mixed_port" ] && mixed_port="7890" - if command_exists curl; then - explicit_state="fail" - for _url in https://www.google.com/generate_204 https://www.gstatic.com/generate_204; do - for _try in 1 2; do - if curl -4 --proxy "http://127.0.0.1:${mixed_port}" -I --max-time 6 -sS "$_url" 2>/dev/null | curl_has_final_http_response; then - explicit_state="ok" - break 2 - fi - sleep 1 - done - done - transparent_state="fail" - for _url in https://www.google.com https://www.gstatic.com/generate_204; do - for _try in 1 2; do - if curl -4 -I --max-time 6 -sS "$_url" 2>/dev/null | curl_has_final_http_response; then - transparent_state="ok" - break 2 - fi - sleep 1 - done - done - fi - - detail="dns:${dns_state};explicit:${explicit_state};transparent:${transparent_state}" - # Pass on explicit (local mixed-port) reachability alone. The transparent - # probe tests the router's OWN output-redirect path, which is unreliable on - # some stacks (PPPoE/GL.iNet, issue #25) yet does not reflect LAN-client - # proxying — keep it informational in `detail`, not a pass gate. - if [ "$explicit_state" = "ok" ]; then - if [ "$require_fakeip" = "0" ] || [ "$dns_state" = "ok" ] || [ "$dns_state" = "compat" ] || [ "$dns_state" = "na" ]; then - runtime_state_accepts_health_update || return 1 - runtime_state_record_health "pass" "$detail" - return 0 - fi - fi - - runtime_state_accepts_health_update || return 1 - runtime_state_record_health "fail" "$detail" - echo " $(date "+%Y-%m-%d %H:%M:%S") - runtime health check failed: ${detail}" >> /usr/share/clashoo/clashoo.txt - return 1 -} - -# check now; on fail detach a bounded re-check so cold-start false-fails self-correct -runtime_run_health_check_settle() { - runtime_run_health_check && return 0 - local lock="/tmp/clashoo_health_recheck.lock" - ( set -C; echo "$$" >"$lock" ) 2>/dev/null || return 1 - ( - exec 1000>&- 2>/dev/null - trap 'rm -f "$lock"' EXIT - _i=0 - while [ "$_i" -lt 8 ]; do - sleep 15 - _selected_core_running || break - runtime_run_health_check && break - _i=$((_i + 1)) - done - ) /dev/null 2>&1 & - return 1 -} - -_require_runtime_network_stack() { - local missing="" - - for _cmd in fw4 nft ip; do - command_exists "$_cmd" || missing="$missing $_cmd" - done - - if [ -n "$missing" ]; then - _log_runtime_error "Missing required fw4 runtime tools:$missing" - return 1 - fi - - return 0 -} - -_service_enabled() { - local svc="$1" - [ -x "/etc/init.d/${svc}" ] || return 1 - "/etc/init.d/${svc}" enabled >/dev/null 2>&1 -} - -# auto-detect core binary by priority: mihomo > clash-meta > built-in clash -_detect_core() { - for _bin in $(_core_candidates); do - [ -x "$_bin" ] && echo "$_bin" && return - done - echo "/etc/clashoo/clash" -} -CLASH="$(_detect_selected_core)" -CLASH_CONFIG="/etc/clashoo" -CRON_FILE="/etc/crontabs/root" -CONFIG_YAML="/etc/clashoo/config.yaml" - -CUSLIST="/tmp/dnsmasq.d/custom_list.conf" -CUSLITT="/tmp/dnsmasq.clashoo" -CUSLISTV="/var/dnsmasq.d/custom_list.conf" -CUSLITTV="/var/dnsmasq.clashoo" -REAL_LOG="/usr/share/clashoo/clashoo_real.txt" -RUNTIME_STATE_FILE="/tmp/clashoo/runtime_state" -DNS_STATE_DIR="/tmp/clashoo" -DNS_STATE_SERVER_FILE="${DNS_STATE_DIR}/dnsmasq_server.before" -DNS_STATE_NORESOLV_FILE="${DNS_STATE_DIR}/dnsmasq_noresolv.before" -DNS_STATE_CACHE_FILE="${DNS_STATE_DIR}/dnsmasq_cachesize.before" -DNS_STATE_RESOLV_FILE="${DNS_STATE_DIR}/dnsmasq_resolvfile.before" - -cleanup_legacy_startup_backups() { -#=========================================================================================================================== - # Historical backup artifacts can clutter LuCI "System -> Startup". - # Keep runtime clean by removing known obsolete backup filenames. - # The old `*bak*` glob also wiped other packages' backups (e.g. wireless.bak), - # so scope it to Clashoo's own script names (legacy `clash`, current `clashoo`). - # `._*` is macOS AppleDouble metadata, never a valid init script, so it stays. - rm -f /etc/init.d/._clash \ - /etc/init.d/._* \ - /etc/init.d/clash*bak* >/dev/null 2>&1 || true -#=========================================================================================================================== -} - -migrate_legacy_clash_dir() { - local legacy_dir target_dir legacy_path target_path legacy_name - legacy_dir="/etc/clash" - target_dir="/etc/clashoo" - - [ -d "$legacy_dir" ] || return 0 - mkdir -p "$target_dir" >/dev/null 2>&1 - - for legacy_name in config.yaml Country.mmdb geoip.metadb geosite.dat geoip.dat GeoLite2-ASN.mmdb; do - legacy_path="${legacy_dir}/${legacy_name}" - target_path="${target_dir}/${legacy_name}" - [ -e "$legacy_path" ] || continue - [ -e "$target_path" ] || mv -f "$legacy_path" "$target_path" >/dev/null 2>&1 - done - - for legacy_name in rules ruleset rule-set profiles; do - legacy_path="${legacy_dir}/${legacy_name}" - target_path="${target_dir}/${legacy_name}" - [ -e "$legacy_path" ] || continue - [ -e "$target_path" ] || mv -f "$legacy_path" "$target_path" >/dev/null 2>&1 - done - - rmdir "$legacy_dir" >/dev/null 2>&1 || true -} - -backup_dnsmasq_state() { -#=========================================================================================================================== - [ -f "$DNS_STATE_SERVER_FILE" ] && return 0 - mkdir -p "$DNS_STATE_DIR" >/dev/null 2>&1 - uci -q get dhcp.@dnsmasq[0].server >"$DNS_STATE_SERVER_FILE" 2>/dev/null || : >"$DNS_STATE_SERVER_FILE" - uci -q get dhcp.@dnsmasq[0].noresolv >"$DNS_STATE_NORESOLV_FILE" 2>/dev/null || : >"$DNS_STATE_NORESOLV_FILE" - uci -q get dhcp.@dnsmasq[0].cachesize >"$DNS_STATE_CACHE_FILE" 2>/dev/null || : >"$DNS_STATE_CACHE_FILE" - uci -q get dhcp.@dnsmasq[0].resolvfile >"$DNS_STATE_RESOLV_FILE" 2>/dev/null || : >"$DNS_STATE_RESOLV_FILE" -#=========================================================================================================================== -} - -add_clash_dns_server() { -#=========================================================================================================================== - local dns_port="$1" - printf '%s' "$dns_port" | grep -Eq '^[0-9]+$' || return 1 - uci del_list dhcp.@dnsmasq[0].server="127.0.0.1#${dns_port}" >/dev/null 2>&1 || true - uci add_list dhcp.@dnsmasq[0].server="127.0.0.1#${dns_port}" >/dev/null 2>&1 -#=========================================================================================================================== -} - -restore_dnsmasq_state() { -#=========================================================================================================================== - local token saved - [ -d "$DNS_STATE_DIR" ] || return 0 - - if [ -f "$DNS_STATE_SERVER_FILE" ]; then - saved="$(cat "$DNS_STATE_SERVER_FILE" 2>/dev/null)" - uci -q delete dhcp.@dnsmasq[0].server >/dev/null 2>&1 - for token in $saved; do - uci add_list dhcp.@dnsmasq[0].server="$token" >/dev/null 2>&1 - done - fi - - if [ -s "$DNS_STATE_NORESOLV_FILE" ]; then - uci set dhcp.@dnsmasq[0].noresolv="$(cat "$DNS_STATE_NORESOLV_FILE" 2>/dev/null)" >/dev/null 2>&1 - else - uci -q delete dhcp.@dnsmasq[0].noresolv >/dev/null 2>&1 - fi - - if [ -s "$DNS_STATE_CACHE_FILE" ]; then - uci set dhcp.@dnsmasq[0].cachesize="$(cat "$DNS_STATE_CACHE_FILE" 2>/dev/null)" >/dev/null 2>&1 - else - uci -q delete dhcp.@dnsmasq[0].cachesize >/dev/null 2>&1 - fi - - if [ -s "$DNS_STATE_RESOLV_FILE" ]; then - uci set dhcp.@dnsmasq[0].resolvfile="$(cat "$DNS_STATE_RESOLV_FILE" 2>/dev/null)" >/dev/null 2>&1 - else - uci -q delete dhcp.@dnsmasq[0].resolvfile >/dev/null 2>&1 - fi - - rm -f "$DNS_STATE_SERVER_FILE" "$DNS_STATE_NORESOLV_FILE" "$DNS_STATE_CACHE_FILE" "$DNS_STATE_RESOLV_FILE" >/dev/null 2>&1 - rmdir "$DNS_STATE_DIR" >/dev/null 2>&1 || true -#=========================================================================================================================== -} - -ensure_dns_when_core_stopped() { -#=========================================================================================================================== - local force="${1:-0}" servers token remote_servers - [ "$force" = "1" ] || ! _selected_core_running || return 0 - servers="$(uci -q get dhcp.@dnsmasq[0].server 2>/dev/null)" - remote_servers="" - for token in $servers; do - case "$token" in - 127.0.0.1#1053|127.0.0.1#5300|127.0.0.1#7874) ;; - *) remote_servers="${remote_servers} ${token}" ;; - esac - done - - if [ "$force" = "1" ] || [ -z "$remote_servers" ]; then - uci -q delete dhcp.@dnsmasq[0].server >/dev/null 2>&1 - for token in $remote_servers; do - uci add_list dhcp.@dnsmasq[0].server="$token" >/dev/null 2>&1 - done - fi - if [ -z "$remote_servers" ]; then - uci add_list dhcp.@dnsmasq[0].server='119.29.29.29' >/dev/null 2>&1 - uci add_list dhcp.@dnsmasq[0].server='223.5.5.5' >/dev/null 2>&1 - fi - if [ "$force" = "1" ] || [ -z "$remote_servers" ]; then - uci set dhcp.@dnsmasq[0].noresolv='0' >/dev/null 2>&1 - fi -#=========================================================================================================================== -} - -_dnsmasq_state_digest() { - local _nr _cs - _nr="$(uci -q get dhcp.@dnsmasq[0].noresolv 2>/dev/null)" - _cs="$(uci -q get dhcp.@dnsmasq[0].cachesize 2>/dev/null)" - case "$_nr" in ''|0|false) _nr=0 ;; *) _nr=1 ;; esac - [ -n "$_cs" ] || _cs=default - printf '%s|%s|%s|%s' \ - "$(uci -q get dhcp.@dnsmasq[0].server 2>/dev/null)" \ - "$_nr" "$_cs" \ - "$(uci -q get dhcp.@dnsmasq[0].resolvfile 2>/dev/null)" -} - -_reload_dnsmasq() { - /etc/init.d/dnsmasq reload >/dev/null 2>&1 && return 0 - /etc/init.d/dnsmasq restart >/dev/null 2>&1 -} - -revert_dns() { -#=========================================================================================================================== - local _before _after - _before="$(_dnsmasq_state_digest)" - restore_dnsmasq_state - ensure_dns_when_core_stopped "${1:-0}" - rm -rf "$CUSLIST" "$CUSLITT" "$CUSLISTV" "$CUSLITTV" 2>/dev/null - _after="$(_dnsmasq_state_digest)" - if [ "$_before" = "$_after" ]; then - uci -q revert dhcp - return 0 - fi - uci commit dhcp - _reload_dnsmasq >/dev/null 2>&1 -#=========================================================================================================================== -} - -add_cron(){ -#=========================================================================================================================== - # core.log 落在 tmpfs 上,按分钟卡一次大小;内核对日志没有上限, - # 一旦刷屏写满 /tmp,dnsmasq 与配置生成都会跟着挂。 - [ -z "$(grep -w "lib/core_log_guard.sh" "$CRON_FILE")" ] && echo "* * * * * sh /usr/share/clashoo/lib/core_log_guard.sh >/dev/null 2>&1" >> "$CRON_FILE" - - auto=$(uci get clashoo.config.auto_update 2>/dev/null) - clear=$(uci get clashoo.config.auto_clear_log 2>/dev/null) - if [ "${auto:-0}" -eq 1 ] || [ "${clear:-0}" -eq 1 ]; then - [ -z "$(grep -w "/usr/share/clashoo/update/maintenance_cron.sh" "$CRON_FILE")" ] && echo "23 * * * * sh /usr/share/clashoo/update/maintenance_cron.sh >/dev/null 2>&1" >> "$CRON_FILE" - fi - - sub_auto=$(uci get clashoo.config.auto_subscription_update 2>/dev/null) - if [ "${sub_auto:-0}" -eq 1 ]; then - [ -z "$(grep -w "/usr/share/clashoo/update/subscription_update_cron.sh" "$CRON_FILE")" ] && echo "7 * * * * sh /usr/share/clashoo/update/subscription_update_cron.sh >/dev/null 2>&1" >> "$CRON_FILE" - fi - - lgbm_auto=$(uci get clashoo.config.smart_lgbm_auto_update 2>/dev/null) - if [ "${lgbm_auto:-0}" -eq 1 ]; then - lgbm_interval=$(uci get clashoo.config.smart_lgbm_update_interval 2>/dev/null) - echo "$lgbm_interval" | grep -Eq '^[0-9]+$' || lgbm_interval=72 - [ "$lgbm_interval" -lt 1 ] && lgbm_interval=72 - lgbm_days=$(( lgbm_interval / 24 )) - [ "$lgbm_days" -lt 1 ] && lgbm_days=1 - [ -z "$(grep -w "update/lgbm_update.sh" "$CRON_FILE")" ] && echo "0 3 */$lgbm_days * * sh /usr/share/clashoo/update/lgbm_update.sh >/dev/null 2>&1" >> "$CRON_FILE" - fi - crontab "$CRON_FILE" -#=========================================================================================================================== -} - -del_cron(){ -#=========================================================================================================================== - sed -i '/update\/geoip.sh/d' "$CRON_FILE" - sed -i '/rpc_async.sh update_geoip/d' "$CRON_FILE" - sed -i '/\/usr\/share\/clash\/geoip.sh/d' "$CRON_FILE" - sed -i '/update\/update_all.sh/d' "$CRON_FILE" - sed -i '/\/usr\/share\/clash\/update_all.sh/d' "$CRON_FILE" - sed -i '/update\/maintenance_cron.sh/d' "$CRON_FILE" - sed -i '/lib\/core_log_guard.sh/d' "$CRON_FILE" - sed -i '/clashoo.txt/d' "$CRON_FILE" - sed -i '/update\/lgbm_update.sh/d' "$CRON_FILE" - sed -i '/\/usr\/share\/clash\/lgbm_update.sh/d' "$CRON_FILE" - sed -i '/update\/subscription_update_cron.sh/d' "$CRON_FILE" - /etc/init.d/cron restart -#=========================================================================================================================== -} - -refresh_cron() { - del_cron >/dev/null 2>&1 - [ "$(uci -q get clashoo.config.core_only 2>/dev/null)" != "1" ] && _selected_core_running && add_cron >/dev/null 2>&1 - return 0 -} - - -select_config(){ -#=========================================================================================================================== -CONFIG_YAML_PATH=$(uci get clashoo.config.use_config 2>/dev/null) -log_msg "Checking Config file" "正在检查配置文件" - -# Runtime dir may be missing (e.g. after a broken uninstall left the package -# installed but its /etc/clashoo dir removed). Recreate it so the cp below -# can't silently fail and leave the core without a config. -mkdir -p "$(dirname "$CONFIG_YAML")" 2>/dev/null - -if [ -f "$CONFIG_YAML_PATH" ] && [ -s "$CONFIG_YAML_PATH" ];then - - if ! cp "$CONFIG_YAML_PATH" "$CONFIG_YAML" 2>/dev/null || [ ! -s "$CONFIG_YAML" ];then - log_msg "Failed to stage config file" "配置写入失败:运行目录缺失或不可写" - sleep 5 - echo "Clashoo" >$REAL_LOG - return 1 - fi - -elif [ ! -f "$CONFIG_YAML_PATH" ] && [ ! -f "$CONFIG_YAML" ];then - - log_msg "No config found" "找不到配置文章" - sleep 5 - echo "Clashoo" >$REAL_LOG - return 1 - -elif [ ! -s "$CONFIG_YAML_PATH" ] && [ ! -s "$CONFIG_YAML" ];then - - log_msg "Your Config File is Empty" "你的config.yaml有问题还是为了空" - sleep 5 - echo "Clashoo" >$REAL_LOG - return 1 - -fi - -#=========================================================================================================================== -} - - - -_dns_roles_look_broken() { - local i=0 t a en broken=1 fb_total=0 fb_domestic=0 - while :; do - t="$(uci -q get clashoo.@dnsservers[$i].ser_type 2>/dev/null)" - [ -n "$t" ] || break - en="$(uci -q get clashoo.@dnsservers[$i].enabled 2>/dev/null)" - a="$(uci -q get clashoo.@dnsservers[$i].ser_address 2>/dev/null)" - i=$((i + 1)) - [ "$en" = "0" ] && continue - case "$t" in - nameserver) - printf '%s' "$a" | grep -qE '1\.1\.1\.1|1\.0\.0\.1|one\.one\.one\.one|cloudflare|8\.8\.8\.8|8\.8\.4\.4|dns\.google|9\.9\.9\.9' && broken=0 - ;; - fallback) - fb_total=$((fb_total + 1)) - printf '%s' "$a" | grep -qE '223\.5\.5\.5|223\.6\.6\.6|119\.29\.29\.29|119\.28\.28\.28|114\.114|180\.184|alidns|doh\.pub|dnspod' && fb_domestic=$((fb_domestic + 1)) - ;; - esac - done - [ "$fb_total" -gt 0 ] && [ "$fb_total" = "$fb_domestic" ] && broken=0 - return $broken -} - -_dns_drop_legacy_geolocation_policy() { - local i=0 matcher nameserver - while uci -q get "clashoo.@dns_policy[$i]" >/dev/null 2>&1; do - matcher="$(uci -q get "clashoo.@dns_policy[$i].matcher" 2>/dev/null)" - nameserver="$(uci -q get "clashoo.@dns_policy[$i].nameserver" 2>/dev/null)" - if [ "$matcher" = "geosite:geolocation-!cn" ] && [ "$nameserver" = "https://cloudflare-dns.com/dns-query" ]; then - uci -q delete "clashoo.@dns_policy[$i]" - continue - fi - i=$((i + 1)) - done -} - -_migrate_dns_roles() { - local ver - ver="$(uci -q get clashoo.config.dns_migrated 2>/dev/null)" - [ "$ver" = "3" ] && return 0 - if [ "$ver" = "2" ]; then - _dns_drop_legacy_geolocation_policy - uci -q set clashoo.config.dns_migrated='3' - uci -q commit clashoo - return 0 - fi - if [ "$ver" = "1" ] && ! _dns_roles_look_broken; then - _dns_drop_legacy_geolocation_policy - uci -q set clashoo.config.dns_migrated='3' - uci -q commit clashoo - return 0 - fi - while uci -q delete clashoo.@dnsservers[0] >/dev/null 2>&1; do :; done - while uci -q delete clashoo.@dns_policy[0] >/dev/null 2>&1; do :; done - _add_dnsserver() { - local sec - sec="$(uci -q add clashoo dnsservers)" || return 1 - uci -q set clashoo."$sec".enabled='1' - uci -q set clashoo."$sec".ser_type="$1" - uci -q set clashoo."$sec".ser_address="$2" - uci -q set clashoo."$sec".protocol="${3:-none}" - [ -n "$4" ] && uci -q set clashoo."$sec".ser_port="$4" - } - _add_dnsserver 'nameserver' 'https://dns.alidns.com/dns-query' - _add_dnsserver 'nameserver' 'https://doh.pub/dns-query' - _add_dnsserver 'proxy-server-nameserver' '1.1.1.1' 'tls://' '853' - _add_dnsserver 'fallback' 'https://cloudflare-dns.com/dns-query' - _add_dnsserver 'fallback' 'https://dns.google/dns-query' - _add_dnsserver 'direct-nameserver' '223.5.5.5' 'udp://' - local sec - sec="$(uci -q add clashoo dns_policy)" - uci -q set clashoo."$sec".enabled='1' - uci -q set clashoo."$sec".policy_type='nameserver-policy' - uci -q set clashoo."$sec".matcher='geosite:cn' - uci -q add_list clashoo."$sec".nameserver='https://dns.alidns.com/dns-query' - uci -q add_list clashoo."$sec".nameserver='https://doh.pub/dns-query' - uci -q set clashoo.config.dns_migrated='3' - uci -q commit clashoo - log_msg "Upstream DNS roles migrated" "上游 DNS 角色已恢复为经典防污染模型(国内主解析 + 境外 fallback)" -} - -_user_dns_fields() { - local field out="" force="${1:-}" - command -v yq >/dev/null 2>&1 || return 0 - [ -s "$CONFIG_YAML" ] || return 0 - for field in nameserver proxy-server-nameserver fallback direct-nameserver \ - default-nameserver nameserver-policy proxy-server-nameserver-policy respect-rules; do - case ",$force," in *,"$field",*) continue ;; esac - [ "$(yq -M e "(.dns // {}) | has(\"${field}\")" "$CONFIG_YAML" 2>/dev/null)" = "true" ] && - out="${out}${out:+,}${field}" - done - [ "$(yq -M e '.dns."prefer-h3" // false' "$CONFIG_YAML" 2>/dev/null)" = "true" ] && - out="${out}${out:+,}prefer-h3" - printf '%s' "$out" -} - -_dns_list_values() { - local field="$1" - command -v yq >/dev/null 2>&1 || return 0 - yq -M e -r "(.dns.\"${field}\" // [])[]" "$CONFIG_YAML" 2>/dev/null | sed '/^null$/d' -} - -_dns_value_is_domestic() { - case "$1" in - *223.5.5.5*|*119.29.29.29*|*114.114.114.114*|*180.184.*|*1.2.4.8*|*doh.pub*|*alidns*|*dns.pub*|*dnspod*) - return 0 ;; - esac - return 1 -} - -_dns_list_all_domestic() { - local field="$1" value seen=0 - for value in $(_dns_list_values "$field"); do - seen=1 - _dns_value_is_domestic "$value" || return 1 - done - [ "$seen" = "1" ] -} - -_dns_has_cn_rule_set() { - _dns_list_values "fake-ip-filter" | grep -qx 'rule-set:cn_domain' || return 1 - yq -M e -r '(.dns."nameserver-policy"."rule-set:cn_domain" // [])[]' "$CONFIG_YAML" 2>/dev/null | grep -q . -} - -_clashoo_dns_force_fields() { - command -v yq >/dev/null 2>&1 || return 0 - [ -s "$CONFIG_YAML" ] || return 0 - local managed legacy fields - fields="nameserver,proxy-server-nameserver,direct-nameserver,default-nameserver,nameserver-policy,proxy-server-nameserver-policy,respect-rules" - managed="$(yq -M e '(.dns."x-clashoo-managed-dns" // false) == true' "$CONFIG_YAML" 2>/dev/null)" - if [ "$managed" = "true" ]; then - printf '%s' "$fields" - return 0 - fi - legacy=0 - if _dns_has_cn_rule_set && - _dns_list_all_domestic "nameserver" && - _dns_list_all_domestic "proxy-server-nameserver"; then - legacy=1 - fi - [ "$legacy" = "1" ] && printf '%s' "$fields" - return 0 -} - -_dns_nameserver_inherit_mode() { - local has_nameserver marker prefer_h3 respect_false has_proxy force_respect - command -v yq >/dev/null 2>&1 || return 0 - [ -s "$CONFIG_YAML" ] || return 0 - - has_nameserver="$(yq -M e '(.dns.nameserver // null) | (tag != "!!null" and length > 0)' "$CONFIG_YAML" 2>/dev/null)" - [ "$has_nameserver" = "true" ] || return 0 - - marker=0 - if yq -M e -r '(.dns.nameserver // null) | .. | select(tag == "!!str")' "$CONFIG_YAML" 2>/dev/null | - awk ' - { - hash = index($0, "#") - if (!hash) next - fragment = substr($0, hash + 1) - split(fragment, parts, "&") - if (parts[1] !~ /=/) { found = 1; exit } - } - END { exit(found ? 0 : 1) }'; then - marker=1 - fi - prefer_h3="$(yq -M e '(.dns."prefer-h3" // false) == true' "$CONFIG_YAML" 2>/dev/null)" - respect_false="$(yq -M e '((.dns // {}) | has("respect-rules")) and ((.dns."respect-rules") == false or (.dns."respect-rules") == "false")' "$CONFIG_YAML" 2>/dev/null)" - has_proxy="$(yq -M e '(.dns // {}) | has("proxy-server-nameserver")' "$CONFIG_YAML" 2>/dev/null)" - force_respect=0 - case ",${CLASHOO_DNS_FORCE:-}," in - *,respect-rules,*) force_respect=1 ;; - esac - - # skip suppresses both the generated proxy role and automatic respect-rules. - if [ "$marker" = "1" ] || - { [ "$prefer_h3" = "true" ] && [ "$force_respect" != "1" ]; } || - { [ "$respect_false" = "true" ] && [ "$force_respect" != "1" ]; } || - [ "$(uci -q get clashoo.config.dns_respect_rules 2>/dev/null)" = "0" ]; then - printf '%s' skip - return 0 - fi - case ",${CLASHOO_DNS_FORCE:-}," in - *,proxy-server-nameserver,*) return 0 ;; - esac - [ "$has_proxy" = "true" ] && return 0 - printf '%s' inherit -} - -# issue #73: mihomo resolves proxy server domains through -# proxy-server-nameserver(-policy) and ignores nameserver-policy there. Airports -# ship their own resolver for node domains (e.g. "+.chylink.xyz" -> DoT) which -# answers with reachable relay IPs, so mirror the entries that match a node -# server domain before mixin drops them. -# -# Everything travels through a private 0700 work dir: large airports can produce -# hundreds of KB of policy entries, which neither argv nor env vars can carry -# (E2BIG), and predictable /tmp names are symlink bait. -_dns_node_policy_workdir="" - -_dns_node_policy_cleanup() { - [ -n "${_dns_node_policy_workdir:-}" ] || return 0 - rm -rf "$_dns_node_policy_workdir" 2>/dev/null - _dns_node_policy_workdir="" - return 0 -} - -# Same inputs yml_change feeds mixin: settle FORCE/PRESENT here so the skip -# decision cannot disagree with the config that mixin actually generates. -_dns_node_policy_mode() { - CLASHOO_DNS_FORCE="$(_clashoo_dns_force_fields)" - CLASHOO_DNS_PRESENT="$(_user_dns_fields "$CLASHOO_DNS_FORCE")" - export CLASHOO_DNS_FORCE CLASHOO_DNS_PRESENT - _dns_nameserver_inherit_mode -} - -_dns_node_policy_capture() { - _dns_node_policy_cleanup - command -v yq >/dev/null 2>&1 || return 0 - command -v ucode >/dev/null 2>&1 || return 0 - - local helper workdir - helper="${CLASHOO_NODE_DNS_UC:-/usr/share/clashoo/runtime/dns_node_policy.uc}" - [ -r "$helper" ] || return 0 - [ -s "$CONFIG_YAML" ] || return 0 - - # skip mode keeps the source DNS verbatim: mihomo already falls back to the - # normal DNS policy for node domains when no dedicated resolver is generated. - [ "$(_dns_node_policy_mode)" = "skip" ] && return 0 - - # sweep leftovers from an interrupted start; they are private to root anyway - find "${TMPDIR:-/tmp}" -maxdepth 1 -name 'clashoo-node-dns.*' -mmin +60 \ - -exec rm -rf {} + >/dev/null 2>&1 - - workdir="$(mktemp -d "${TMPDIR:-/tmp}/clashoo-node-dns.XXXXXX" 2>/dev/null)" || return 0 - chmod 700 "$workdir" 2>/dev/null - - if ! yq -M e -o=json -I0 '({"policies": (.dns."nameserver-policy" // {}), "servers": [(.proxies // [])[] | select(type == "!!map") | .server // ""]})' "$CONFIG_YAML" > "$workdir/source.json" 2>/dev/null || - [ ! -s "$workdir/source.json" ]; then - rm -rf "$workdir" - return 0 - fi - chmod 600 "$workdir/source.json" 2>/dev/null - - if ! CLASHOO_NODE_DNS_SOURCE_FILE="$workdir/source.json" ucode "$helper" > "$workdir/policy.json" 2>/dev/null || - [ ! -s "$workdir/policy.json" ]; then - rm -rf "$workdir" - return 0 - fi - chmod 600 "$workdir/policy.json" 2>/dev/null - rm -f "$workdir/source.json" - - if [ "$(yq -M e -r 'length' "$workdir/policy.json" 2>/dev/null)" = "0" ]; then - rm -rf "$workdir" - return 0 - fi - - _dns_node_policy_workdir="$workdir" - return 0 -} - -_dns_node_policy_apply() { - local policy_file rc - policy_file="${_dns_node_policy_workdir:+"$_dns_node_policy_workdir/policy.json"}" - if [ -z "$policy_file" ] || [ ! -s "$policy_file" ] || ! command -v yq >/dev/null 2>&1; then - _dns_node_policy_cleanup - return 0 - fi - - # existing keys keep their value; overlapping patterns are left to mihomo - CLASHOO_NODE_DNS_POLICY_FILE="$policy_file" yq -M e -i '(.dns // {}) as $dns | - (load(strenv(CLASHOO_NODE_DNS_POLICY_FILE)) // {}) as $derived | - .dns."proxy-server-nameserver-policy" = ($derived * ($dns."proxy-server-nameserver-policy" // {})) - ' "$CONFIG_YAML" 2>/dev/null - rc=$? - - # mihomo rejects a node policy without a proxy node resolver - if [ "$(yq -M e -r '((.dns."proxy-server-nameserver" // []) | length)' "$CONFIG_YAML" 2>/dev/null)" = "0" ]; then - yq -M e -i '.dns."proxy-server-nameserver" = (.dns."default-nameserver" // ["223.5.5.5"])' "$CONFIG_YAML" 2>/dev/null || true - fi - - _dns_node_policy_cleanup - [ "$rc" = "0" ] && log_msg "Inherited node domain DNS policy from subscription" "已从订阅继承节点域名 DNS 策略" - return 0 -} - -_dns_proxy_nameservers() { - local i=0 t en a p port s out="" prefix - while :; do - t="$(uci -q get clashoo.@dnsservers[$i].ser_type 2>/dev/null)" - [ -n "$t" ] || break - en="$(uci -q get clashoo.@dnsservers[$i].enabled 2>/dev/null)" - a="$(uci -q get clashoo.@dnsservers[$i].ser_address 2>/dev/null)" - p="$(uci -q get clashoo.@dnsservers[$i].protocol 2>/dev/null)" - port="$(uci -q get clashoo.@dnsservers[$i].ser_port 2>/dev/null)" - i=$((i + 1)) - [ "$t" = "proxy-server-nameserver" ] || continue - [ "$en" = "0" ] && continue - if printf '%s' "$a" | grep -Eq '^[A-Za-z][A-Za-z0-9+.-]*://'; then - s="$a" - else - case "$p" in - ''|none) prefix='' ;; - udp|udp://) prefix='udp://' ;; - tcp|tcp://) prefix='tcp://' ;; - dot|tls|tls://) prefix='tls://' ;; - doh|https|https://) prefix='https://' ;; - doq|quic|quic://) prefix='quic://' ;; - *) prefix="$p" ;; - esac - s="${prefix}${a}" - [ -n "$port" ] && s="${s}:${port}" - fi - [ -n "$s" ] && out="${out}${out:+ }${s}" - done - printf '%s' "$out" -} - -_adapt_dns_loopback_resolver() { - local filter listen host host_pattern old_port servers replacement tmp - [ "$(uci -q get clashoo.config.dns_loopback_compat 2>/dev/null)" = "1" ] || return 0 - command -v yq >/dev/null 2>&1 || return 0 - [ -s "$CONFIG_YAML" ] || return 0 - - filter="${CLASHOO_DNS_LOOPBACK_FILTER:-/usr/share/clashoo/runtime/dns_loopback_adapter.yq}" - [ -r "$filter" ] || return 0 - [ "$(yq -M e '(.dns."proxy-server-nameserver" | type)' "$CONFIG_YAML" 2>/dev/null)" = "!!seq" ] || return 0 - - listen="$(yq -M e -r '.dns.listen // ""' "$CONFIG_YAML" 2>/dev/null)" - old_port="${listen##*:}" - host="${listen%:*}" - printf '%s' "$old_port" | grep -Eq '^[0-9]+$' || return 0 - host="$(printf '%s' "$host" | tr 'A-Z' 'a-z')" - case "$host" in - ""|0.0.0.0|'[::]'|::) - host_pattern='(localhost|127(\.[0-9]{1,3}){3}|\[?::1\]?)' ;; - localhost) - host_pattern='localhost' ;; - 127.*) - printf '%s' "$host" | grep -Eq '^127(\.[0-9]{1,3}){3}$' || return 0 - host_pattern="$(printf '%s' "$host" | sed 's/\./\\./g')" ;; - '[::1]'|::1) - host_pattern='\[?::1\]?' ;; - *) - return 0 ;; - esac - - servers="$(yq -M e -r '.dns."proxy-server-nameserver"[]' "$CONFIG_YAML" 2>/dev/null)" - printf '%s\n' "$servers" | grep -Eiq "^([A-Za-z][A-Za-z0-9+.-]*://)?(${host_pattern}):${old_port}($|[/#?])" || return 0 - - replacement="$(_dns_proxy_nameservers)" - [ -n "$replacement" ] || replacement='tls://1.1.1.1:853' - tmp="$(mktemp "${CONFIG_YAML}.dns-loopback.XXXXXX" 2>/dev/null)" || return 0 - export CLASHOO_DNS_OLD_PORT="$old_port" - export CLASHOO_DNS_HOST_PATTERN="$host_pattern" - export CLASHOO_DNS_REPLACEMENT="$replacement" - if yq -M e --from-file "$filter" "$CONFIG_YAML" > "$tmp" 2>/dev/null && - mv -f "$tmp" "$CONFIG_YAML"; then - log_msg "Adapted stale loopback proxy DNS" "已适配失效的回环节点 DNS" - else - rm -f "$tmp" - log_msg "Loopback proxy DNS adaptation failed; preserved source settings" "回环节点 DNS 适配失败,已保留原配置" - fi - unset CLASHOO_DNS_OLD_PORT CLASHOO_DNS_HOST_PATTERN CLASHOO_DNS_REPLACEMENT - return 0 -} - -backfill_custom_sniffer_overrides() { - [ "$CLASHOO_KEEP_SNIFFER" = "1" ] || return 0 - [ "$(uci -q get clashoo.config.sniffer_streaming 2>/dev/null)" = "1" ] || return 0 - command -v yq >/dev/null 2>&1 || return 0 - [ -s "$CONFIG_YAML" ] || return 0 - [ -r /usr/share/clashoo/runtime/sniffer_overrides.yq ] || return 0 - yq -M e -i --from-file /usr/share/clashoo/runtime/sniffer_overrides.yq "$CONFIG_YAML" 2>/dev/null || true -} - -ensure_quic_fallback_guard() { - [ "$(uci -q get clashoo.config.sniffer_streaming 2>/dev/null)" = "1" ] || return 0 - [ "${EFFECTIVE_UDP_MODE:-off}" != "off" ] || return 0 - [ "$(uci -q get clashoo.config.block_quic 2>/dev/null)" != "1" ] || return 0 - command -v yq >/dev/null 2>&1 || return 0 - [ -s "$CONFIG_YAML" ] || return 0 - [ -r /usr/share/clashoo/runtime/quic_fallback_guard.yq ] || return 0 - yq -M e -i --from-file /usr/share/clashoo/runtime/quic_fallback_guard.yq "$CONFIG_YAML" 2>/dev/null || true -} - -yml_change() { - CLASHOO_DNS_FORCE="$(_clashoo_dns_force_fields)" - CLASHOO_DNS_PRESENT="$(_user_dns_fields "$CLASHOO_DNS_FORCE")" - CLASHOO_DNS_INHERIT_MODE="$(_dns_nameserver_inherit_mode)" - CLASHOO_DNS_INHERIT_NAMESERVER="" - if [ "$CLASHOO_DNS_INHERIT_MODE" = "inherit" ]; then - CLASHOO_DNS_INHERIT_NAMESERVER="$(yq -M e -o=json '(.dns.nameserver // [])' "$CONFIG_YAML" 2>/dev/null)" - fi - export CLASHOO_DNS_FORCE - export CLASHOO_DNS_PRESENT - export CLASHOO_DNS_INHERIT_MODE - export CLASHOO_DNS_INHERIT_NAMESERVER - CLASHOO_KEEP_FAKEIP_FILTER="" - CLASHOO_KEEP_SNIFFER="" - if command -v yq >/dev/null 2>&1 && [ -s "$CONFIG_YAML" ]; then - [ "$(yq -M e '(.dns // {}) | has("fake-ip-filter")' "$CONFIG_YAML" 2>/dev/null)" = "true" ] && - CLASHOO_KEEP_FAKEIP_FILTER=1 - [ "$(yq -M e 'has("sniffer")' "$CONFIG_YAML" 2>/dev/null)" = "true" ] && - CLASHOO_KEEP_SNIFFER=1 - fi - export CLASHOO_KEEP_FAKEIP_FILTER - export CLASHOO_KEEP_SNIFFER - ucode /usr/share/clashoo/runtime/mixin.uc 2>/dev/null | yq -M -p json -o yaml > /tmp/_clashoo_mixin.yaml 2>/dev/null && - yq -M eval-all '. as $item ireduce ({}; . * $item)' "$CONFIG_YAML" /tmp/_clashoo_mixin.yaml > "${CONFIG_YAML}.mixin" 2>/dev/null && - mv -f "${CONFIG_YAML}.mixin" "$CONFIG_YAML" 2>/dev/null && - rm -f /tmp/_clashoo_mixin.yaml 2>/dev/null - backfill_custom_sniffer_overrides - ensure_quic_fallback_guard -} - -_uci_fake_ip_filter_extras() { - local item list - list="$(uci -q get clashoo.config.fake_ip_filter 2>/dev/null)" - set -f - for item in $list; do - case "$item" in - '*.lan'|'localhost.ptlogin2.qq.com') - continue ;; - geosite:cn) - printf '%s\n' 'rule-set:cn_domain' ;; - *) - printf '%s\n' "$item" ;; - esac - done - set +f -} - -drop_legacy_cn_ip_injection() { - command -v yq >/dev/null 2>&1 || return 0 - [ -s "$CONFIG_YAML" ] || return 0 - - if ! yq -M e -i ' - . as $doc | - (select( - (.["rule-providers"].clashoo_cn_ip | length) == 4 and - .["rule-providers"].clashoo_cn_ip.type == "file" and - .["rule-providers"].clashoo_cn_ip.path == "./ruleset/cn-ip.txt" and - .["rule-providers"].clashoo_cn_ip.format == "text" and - .["rule-providers"].clashoo_cn_ip.behavior == "ipcidr" and - ([$doc | .. | select(tag == "!!str" and contains("clashoo_cn_ip")) | - select(. != "RULE-SET,clashoo_cn_ip,DIRECT")] | length) == 0 - )) |= ( - del(.["rule-providers"].clashoo_cn_ip) | - (select(has("rules")) | .rules) |= [.[] | select(. != "RULE-SET,clashoo_cn_ip,DIRECT")] - ) - ' "$CONFIG_YAML" 2>/dev/null; then - log_msg "Failed to remove legacy CN fallback injection" "清理旧版国内直连注入失败,请检查配置" - fi -} - -_effective_fake_ip_filter_mode() { - local mode - mode="$(uci -q get clashoo.config.fake_ip_filter_mode 2>/dev/null)" - if [ -z "$mode" ] && command -v yq >/dev/null 2>&1 && [ -s "$CONFIG_YAML" ]; then - mode="$(yq -M e '(.dns."fake-ip-filter-mode" // "") | tostring' "$CONFIG_YAML" 2>/dev/null)" - [ "$mode" = "null" ] && mode="" - fi - [ -n "$mode" ] || mode="blacklist" - printf '%s\n' "$mode" -} - -_shipped_fake_ip_filter_defaults() { - local f="/usr/share/clashoo/clashoo.default" - [ -s "$f" ] || return 0 - sed -n "s/^[[:space:]]*list[[:space:]]\{1,\}fake_ip_filter[[:space:]]\{1,\}'\{0,1\}\([^']*\)'\{0,1\}[[:space:]]*$/\1/p" "$f" -} - -_fake_ip_filter_as_rule() { - local f="$1" - case "$f" in - *,fake-ip|*,real-ip) printf '%s\n' "$f"; return ;; - esac - case "$f" in - *,*) printf '%s,real-ip\n' "$f" ;; - geosite:*) printf 'GEOSITE,%s,real-ip\n' "${f#geosite:}" ;; - rule-set:*) printf 'RULE-SET,%s,real-ip\n' "${f#rule-set:}" ;; - '+.'*) printf 'DOMAIN-SUFFIX,%s,real-ip\n' "${f#+.}" ;; - *'*'*) printf 'DOMAIN-WILDCARD,%s,real-ip\n' "$f" ;; - *) printf 'DOMAIN,%s,real-ip\n' "$f" ;; - esac -} - -_yq_apply_atomic() { - local expr="$1" cand - cand="${CONFIG_YAML}.cand.$$" - cp "$CONFIG_YAML" "$cand" 2>/dev/null || return 1 - if ! yq -M e -i "$expr" "$cand" 2>/dev/null; then - rm -f "$cand" 2>/dev/null - return 1 - fi - if ! yq -M e '.' "$cand" >/dev/null 2>&1; then - rm -f "$cand" 2>/dev/null - return 1 - fi - mv -f "$cand" "$CONFIG_YAML" 2>/dev/null || { rm -f "$cand" 2>/dev/null; return 1; } - return 0 -} - -normalize_fake_ip_filter() { - command -v yq >/dev/null 2>&1 || return 0 - [ -s "$CONFIG_YAML" ] || return 0 - - local mode dir work out item skip d - mode="$(_effective_fake_ip_filter_mode)" - - if [ "$mode" = "blacklist" ] || - [ "$(yq -M e '(.dns // {}) | has("fake-ip-filter")' "$CONFIG_YAML" 2>/dev/null)" != "true" ]; then - CLASHOO_FIF_MODE="$mode" _yq_apply_atomic '.dns."fake-ip-filter-mode" = strenv(CLASHOO_FIF_MODE)' || - log_msg "Failed to write fake-ip-filter-mode, subscription value kept" \ - "写入 fake-ip 过滤模式失败,已保留订阅自带的设置" - return 0 - fi - - dir="$(mktemp -d /tmp/.clashoo_fif.XXXXXX 2>/dev/null)" || return 0 - work="$dir/in" - out="$dir/out" - yq -M e '.dns."fake-ip-filter"[]' "$CONFIG_YAML" 2>/dev/null > "$work" || { rm -rf "$dir"; return 0; } - [ -s "$work" ] || { rm -rf "$dir"; return 0; } - - while IFS= read -r item; do - [ -n "$item" ] || continue - if [ "$mode" = "whitelist" ]; then - skip=0 - set -f - for d in $(_shipped_fake_ip_filter_defaults); do - [ "$item" = "$d" ] && skip=1 && break - done - set +f - [ "$skip" = "1" ] && continue - printf '%s\n' "$item" >> "$out" - else - _fake_ip_filter_as_rule "$item" >> "$out" - fi - done < "$work" - - if [ -s "$out" ]; then - CLASHOO_FIF_MODE="$mode" CLASHOO_FIF="$(cat "$out")" _yq_apply_atomic \ - '.dns."fake-ip-filter-mode" = strenv(CLASHOO_FIF_MODE) | .dns."fake-ip-filter" = (strenv(CLASHOO_FIF) | split("\n"))' || - log_msg "Failed to normalize fake-ip filter, subscription settings kept" \ - "规范化 fake-ip 过滤失败,已保留订阅自带的模式与列表" - else - CLASHOO_FIF_MODE="$mode" _yq_apply_atomic \ - '.dns."fake-ip-filter-mode" = strenv(CLASHOO_FIF_MODE) | del(.dns."fake-ip-filter")' || - log_msg "Failed to normalize fake-ip filter, subscription settings kept" \ - "规范化 fake-ip 过滤失败,已保留订阅自带的模式与列表" - log_msg "Fake-IP allowlist is empty after dropping shipped defaults, add your own entries" \ - "白名单模式下过滤列表已空(随包默认项在此模式下语义相反已跳过),请自行填写需要 Fake-IP 的域名" - fi - rm -rf "$dir" 2>/dev/null -} - -_ensure_cn_domain_rule_provider() { - command -v yq >/dev/null 2>&1 || return 0 - [ -s "$CONFIG_YAML" ] || return 0 - yq -M e -i ' - .["rule-providers"].cn_domain = { - "type": "file", - "path": "./ruleset/cn.mrs", - "format": "mrs", - "behavior": "domain" - } - ' "$CONFIG_YAML" 2>/dev/null || true -} - -append_luci_fake_ip_filter_extras() { - [ -n "${CLASHOO_KEEP_FAKEIP_FILTER:-}" ] || return 0 - command -v yq >/dev/null 2>&1 || return 0 - [ -s "$CONFIG_YAML" ] || return 0 - - local item needs_cn_file - needs_cn_file="/tmp/.clashoo_need_cn_rs.$$" - rm -f "$needs_cn_file" 2>/dev/null - _uci_fake_ip_filter_extras | while IFS= read -r item; do - [ -n "$item" ] || continue - [ "$item" = "rule-set:cn_domain" ] && : > "$needs_cn_file" - CLASHOO_FAKEIP_FILTER_ITEM="$item" yq -M e -i ' - .dns."fake-ip-filter" = (((.dns."fake-ip-filter" // []) + [strenv(CLASHOO_FAKEIP_FILTER_ITEM)]) | unique) - ' "$CONFIG_YAML" 2>/dev/null || true - done - [ -f "$needs_cn_file" ] && _ensure_cn_domain_rule_provider - rm -f "$needs_cn_file" 2>/dev/null -} - -ensure_dns_cn_policy_fallback() { - command -v yq >/dev/null 2>&1 || return 0 - [ -s "$CONFIG_YAML" ] || return 0 - [ "$(yq -M e '(.dns // {}) | has("nameserver-policy")' "$CONFIG_YAML" 2>/dev/null)" = "true" ] || return 0 - [ "$(yq -M e '((.dns."nameserver-policy" // {}) | type) == "!!map"' "$CONFIG_YAML" 2>/dev/null)" = "true" ] || return 0 - - if [ "$(yq -M e '(.dns."nameserver-policy" // {}) | has("rule-set:cn_domain")' "$CONFIG_YAML" 2>/dev/null)" = "true" ]; then - _ensure_cn_domain_rule_provider - return 0 - fi - - if [ "$(yq -M e '(.dns."nameserver-policy" // {}) | has("geosite:cn")' "$CONFIG_YAML" 2>/dev/null)" = "true" ]; then - yq -M e -i '.dns."nameserver-policy"."rule-set:cn_domain" = .dns."nameserver-policy"."geosite:cn"' "$CONFIG_YAML" 2>/dev/null || true - else - yq -M e -i '.dns."nameserver-policy"."rule-set:cn_domain" = ["https://223.5.5.5/dns-query", "https://doh.pub/dns-query"]' "$CONFIG_YAML" 2>/dev/null || true - fi - _ensure_cn_domain_rule_provider -} - -_remap_dns_system_nameserver() { - command -v yq >/dev/null 2>&1 || return 0 - [ -s "$CONFIG_YAML" ] || return 0 - yq -M e -i '(.dns | .. | select(. == "system")) |= "223.5.5.5"' "$CONFIG_YAML" 2>/dev/null || true -} - -ip_rules() { -#=========================================================================================================================== - CLASHOO_CONFIG_YAML="$CONFIG_YAML" sh /usr/share/clashoo/runtime/iprules.sh 2>/dev/null -#=========================================================================================================================== -} - - -smart_inject() { -#=========================================================================================================================== - local smart_auto smart_priority smart_asn smart_lgbm smart_collect smart_collect_size - local smart_collect_rate smart_lgbm_auto smart_lgbm_interval smart_lgbm_url - local prefer_asn_val lgbm_val collect_val collect_rate PRIORITY_TMP - - smart_auto=$(uci get clashoo.config.smart_auto_switch 2>/dev/null) - - # Remove any fields injected by a previous smart_inject run (idempotency) - sed -i '/^ uselightgbm:/d; /^ collectdata:/d; /^ prefer-asn:/d; /^ sample-rate:/d' "$CONFIG_YAML" 2>/dev/null - sed -i '/^ policy-priority:/d' "$CONFIG_YAML" 2>/dev/null - sed -i '/^lgbm-auto-update:/d; /^lgbm-url:/d; /^lgbm-update-interval:/d' "$CONFIG_YAML" 2>/dev/null - # revert previous smart injection: type:smart -> url-test - if command -v yq >/dev/null 2>&1; then - yq e -i '(.["proxy-groups"] // []) |= map(if .type == "smart" then .type = "url-test" else . end)' "$CONFIG_YAML" 2>/dev/null - fi - - [ "${smart_auto:-0}" != "1" ] && return 0 - # only inject smart fields when core=1; type:smart rejected by standard mihomo. - [ "$(uci -q get clashoo.config.core 2>/dev/null)" = "1" ] || return 0 - - smart_priority=$(uci get clashoo.config.smart_policy_priority 2>/dev/null) - smart_asn=$(uci get clashoo.config.smart_prefer_asn 2>/dev/null) - smart_lgbm=$(uci get clashoo.config.smart_uselightgbm 2>/dev/null) - smart_collect=$(uci get clashoo.config.smart_collectdata 2>/dev/null) - smart_collect_size=$(uci get clashoo.config.smart_collect_size 2>/dev/null) - smart_collect_rate=$(uci get clashoo.config.smart_collect_rate 2>/dev/null) - smart_lgbm_auto=$(uci get clashoo.config.smart_lgbm_auto_update 2>/dev/null) - smart_lgbm_interval=$(uci get clashoo.config.smart_lgbm_update_interval 2>/dev/null) - smart_lgbm_url=$(uci get clashoo.config.smart_lgbm_url 2>/dev/null) - - [ -z "$smart_collect_size" ] && smart_collect_size=100 - [ -z "$smart_collect_rate" ] && smart_collect_rate=1 - [ -z "$smart_lgbm_interval" ] && smart_lgbm_interval=72 - [ -z "$smart_lgbm_url" ] && smart_lgbm_url="https://github.com/vernesong/mihomo/releases/download/LightGBM-Model/Model.bin" - - [ "${smart_asn:-0}" = "1" ] && prefer_asn_val="true" || prefer_asn_val="false" - [ "${smart_lgbm:-0}" = "1" ] && lgbm_val="true" || lgbm_val="false" - [ "${smart_collect:-0}" = "1" ] && collect_val="true" || collect_val="false" - collect_rate="${smart_collect_rate:-1}" - - # Prefer structured YAML mutation (OpenClash-like behavior) when yq exists. - if command -v yq >/dev/null 2>&1; then - export SMART_PRIORITY="${smart_priority:-}" - export SMART_PREFER_ASN="$prefer_asn_val" - export SMART_USELGBM="$lgbm_val" - export SMART_COLLECT="$collect_val" - export SMART_COLLECT_RATE="${collect_rate:-1}" - export SMART_COLLECT_SIZE="${smart_collect_size:-100}" - export SMART_LGBM_AUTO="$([ "${smart_lgbm_auto:-0}" = "1" ] && echo "true" || echo "false")" - export SMART_LGBM_URL="${smart_lgbm_url:-}" - export SMART_LGBM_INTERVAL="${smart_lgbm_interval:-72}" - - if yq e ' - .["proxy-groups"] = ((.["proxy-groups"] // []) | map( - if (.type == "url-test" or .type == "load-balance" or .type == "smart") then - .type = "smart" | - .["prefer-asn"] = (env(SMART_PREFER_ASN) == "true") | - .uselightgbm = (env(SMART_USELGBM) == "true") | - .collectdata = (env(SMART_COLLECT) == "true") | - .["sample-rate"] = (env(SMART_COLLECT_RATE) | tonumber) | - (if env(SMART_PRIORITY) != "" then .["policy-priority"] = env(SMART_PRIORITY) else del(.["policy-priority"]) end) - else . - end - )) | - (if env(SMART_COLLECT) == "true" then - .profile = (.profile // {}) | - .profile["smart-collector-size"] = (env(SMART_COLLECT_SIZE) | tonumber) - else - . - end) | - (if env(SMART_USELGBM) == "true" then - .["lgbm-auto-update"] = (env(SMART_LGBM_AUTO) == "true") | - .["lgbm-url"] = env(SMART_LGBM_URL) | - .["lgbm-update-interval"] = (env(SMART_LGBM_INTERVAL) | tonumber) - else - del(.["lgbm-auto-update"], .["lgbm-url"], .["lgbm-update-interval"]) - end) - ' "$CONFIG_YAML" > /tmp/_smart_inject.yaml 2>/dev/null; then - mv /tmp/_smart_inject.yaml "$CONFIG_YAML" - unset SMART_PRIORITY SMART_PREFER_ASN SMART_USELGBM SMART_COLLECT SMART_COLLECT_RATE - unset SMART_COLLECT_SIZE SMART_LGBM_AUTO SMART_LGBM_URL SMART_LGBM_INTERVAL - return 0 - fi - - unset SMART_PRIORITY SMART_PREFER_ASN SMART_USELGBM SMART_COLLECT SMART_COLLECT_RATE - unset SMART_COLLECT_SIZE SMART_LGBM_AUTO SMART_LGBM_URL SMART_LGBM_INTERVAL - fi - - # Fallback path (no yq): line-based mutation with indentation-aware awk. - # Step 1: Replace any-indentation type: url-test/load-balance to type: smart - awk ' - /^[ \t]*type:[ \t]*(url-test|load-balance)[ \t]*$/ { - sub(/type:[ \t]*(url-test|load-balance)[ \t]*$/, "type: smart") - } - { print } - ' "$CONFIG_YAML" > /tmp/_smart_type.yaml && mv /tmp/_smart_type.yaml "$CONFIG_YAML" - - # Step 2: Build policy-priority value temp file (avoid quoting issues) - PRIORITY_TMP="/tmp/_smart_priority.txt" - printf '' > "$PRIORITY_TMP" - if [ -n "$smart_priority" ]; then - printf '%s\n' "$smart_priority" > "$PRIORITY_TMP" - fi - - # Step 3: Inject smart fields after each "type: smart" with preserved indentation - awk -v pfile="$PRIORITY_TMP" \ - -v prefer_asn="$prefer_asn_val" \ - -v lgbm="$lgbm_val" \ - -v collect="$collect_val" \ - -v rate="$collect_rate" ' - /^[ \t]*type:[ \t]*smart[ \t]*$/ { - match($0, /^[ \t]*/) - indent = substr($0, RSTART, RLENGTH) - print - while ((getline line < pfile) > 0) { - if (line != "") - print indent "policy-priority: \047" line "\047" - } - close(pfile) - print indent "prefer-asn: " prefer_asn - print indent "uselightgbm: " lgbm - print indent "collectdata: " collect - print indent "sample-rate: " rate - next - } - { print } - ' "$CONFIG_YAML" > /tmp/_smart_inject.yaml && mv /tmp/_smart_inject.yaml "$CONFIG_YAML" - rm -f "$PRIORITY_TMP" 2>/dev/null - - # Step 4: profile.smart-collector-size (preserve profile child indentation from source YAML) - if grep -q '^profile:[ ]*$' "$CONFIG_YAML"; then - profile_indent="$( - awk ' - /^profile:[ \t]*$/ { - while (getline > 0) { - if ($0 ~ /^[ \t]*$/) { - continue - } - if ($0 ~ /^[^ \t]/) { - break - } - match($0, /^[ \t]+/) - print substr($0, RSTART, RLENGTH) - exit - } - } - ' "$CONFIG_YAML" - )" - [ -n "$profile_indent" ] || profile_indent=" " - - if grep -q '^[ ]*smart-collector-size:[ ]*' "$CONFIG_YAML"; then - awk -v indent="$profile_indent" -v size="$smart_collect_size" ' - /^[ \t]*smart-collector-size:[ \t]*/ { - print indent "smart-collector-size: " size - next - } - { print } - ' "$CONFIG_YAML" > /tmp/_smart_profile.yaml && mv /tmp/_smart_profile.yaml "$CONFIG_YAML" - else - awk -v indent="$profile_indent" -v size="$smart_collect_size" ' - /^profile:[ \t]*$/ { - print - print indent "smart-collector-size: " size - next - } - { print } - ' "$CONFIG_YAML" > /tmp/_smart_profile.yaml && mv /tmp/_smart_profile.yaml "$CONFIG_YAML" - fi - else - printf '\nprofile:\n store-selected: true\n smart-collector-size: %s\n' "$smart_collect_size" >> "$CONFIG_YAML" - fi - - # Step 5: Top-level lgbm fields (only when lgbm enabled) - if [ "$lgbm_val" = "true" ]; then - lgbm_auto_val="false" - [ "${smart_lgbm_auto:-0}" = "1" ] && lgbm_auto_val="true" - printf 'lgbm-auto-update: %s\nlgbm-url: "%s"\nlgbm-update-interval: %s\n' \ - "$lgbm_auto_val" "$smart_lgbm_url" "$smart_lgbm_interval" >> "$CONFIG_YAML" - fi -#=========================================================================================================================== -} - - -_lan_acl_enabled() { - local section - for section in $(uci -q show clashoo 2>/dev/null | sed -n 's/^clashoo\.\([^.=]*\)=lan_acl$/\1/p'); do - [ "$(uci -q get "clashoo.${section}.enabled" 2>/dev/null)" != "0" ] && return 0 - done - [ "$(uci -q get clashoo.config.acl_migrated 2>/dev/null)" = "1" ] && return 1 - case "$(uci -q get clashoo.config.access_control 2>/dev/null)" in - 1|2) return 0 ;; - esac - return 1 -} - -_lan_dns_split_enabled() { - _lan_acl_enabled || return 1 - [ "$(uci -q get clashoo.config.enable_dns 2>/dev/null)" != "0" ] || return 1 - [ "$(uci -q get clashoo.config.ipv4_dns_hijack 2>/dev/null)" = "1" ] || - [ "$(uci -q get clashoo.config.ipv6_dns_hijack 2>/dev/null)" = "1" ] -} - -yml_dns_change(){ -#=========================================================================================================================== - dns_port=$(sed -n 's/^[[:space:]]*listen:.*:[[:space:]]*['"'"'"]*\([0-9]\{1,\}\)['"'"'"]*[[:space:]]*$/\1/p' "$CONFIG_YAML" 2>/dev/null | head -n1) - listen_port=$(uci get clashoo.config.listen_port 2>/dev/null) - [ -z "$listen_port" ] && listen_port=5300 - if [ -z "$dns_port" ]; then - dns_port="$listen_port" - if grep -q '^dns:' "$CONFIG_YAML" && ! grep -q "^ \{0,\}listen:" "$CONFIG_YAML"; then - sed -i "/^dns:/a\ listen: 0.0.0.0:${dns_port}" "$CONFIG_YAML" 2>/dev/null - fi - fi - if [ "${CLASHOO_RELOAD_CANDIDATE:-0}" = "1" ]; then - if [ "${dns_port:-0}" -eq 53 ]; then - sed -i "s@^\([[:space:]]*listen:[[:space:]]*\)0\.0\.0\.0:53@\10.0.0.0:${listen_port}@g" "$CONFIG_YAML" || return 1 - fi - return 0 - fi - dnsforwader=$(uci get clashoo.config.dnsforwader 2>/dev/null) - dnscache=$(uci get clashoo.config.dnscache 2>/dev/null) - if [ "$(uci -q get clashoo.config.enable_dns 2>/dev/null)" = "0" ]; then - revert_dns >/dev/null 2>&1 - return 0 - fi - if _lan_dns_split_enabled; then - revert_dns 1 >/dev/null 2>&1 - return 0 - fi - backup_dnsmasq_state - if [ "${dns_port:-0}" -eq 53 ]; then - sed -i "s@^\([[:space:]]*listen:[[:space:]]*\)0\.0\.0\.0:53@\10.0.0.0:${listen_port}@g" "$CONFIG_YAML" - dns_port="$listen_port" - fi - - if [ "${dnsforwader:-0}" -ne 0 ]; then - uci -q delete dhcp.@dnsmasq[0].server - if [ "${dns_port:-0}" -eq 53 ]; then - - log_msg "Setting dns forwarder" "设置dns转发器" - - add_clash_dns_server 5300 - uci delete dhcp.@dnsmasq[0].resolvfile - uci set dhcp.@dnsmasq[0].noresolv=1 - uci commit dhcp - if [ "${dnscache:-0}" -eq 0 ];then - log_msg "Disabling dns cache" "禁用dns缓存" - uci set dhcp.@dnsmasq[0].cachesize=0 - uci commit dhcp - fi - else - echo "Setting dns forwarder" >$REAL_LOG - add_clash_dns_server "$dns_port" - uci delete dhcp.@dnsmasq[0].resolvfile - uci set dhcp.@dnsmasq[0].noresolv=1 - uci commit dhcp - if [ "${dnscache:-0}" -eq 0 ];then - log_msg "Disabling dns cache" "禁用dns缓存" - - uci set dhcp.@dnsmasq[0].cachesize=0 - uci commit dhcp - fi - fi - elif [ "${dnsforwader:-0}" -ne 1 ]; then - if [ "${dnscache:-0}" -eq 0 ];then - log_msg "Disabling dns cache" "禁用dns缓存" - - uci set dhcp.@dnsmasq[0].cachesize=0 - uci commit dhcp - fi - fi -#=========================================================================================================================== -} - -singbox_dns_change() { -#=========================================================================================================================== - local dnsforwader dnscache dns_port - if _lan_dns_split_enabled; then - revert_dns 1 >/dev/null 2>&1 - return 0 - fi - dnsforwader="$(uci get clashoo.config.dnsforwader 2>/dev/null)" - if [ "${dnsforwader:-0}" -eq 0 ]; then - return 0 - fi - - dnscache="$(uci get clashoo.config.dnscache 2>/dev/null)" - dns_port="$(uci get clashoo.config.listen_port 2>/dev/null)" - [ -z "$dns_port" ] && dns_port=1053 - - backup_dnsmasq_state - _sb_dns_before="$(_dnsmasq_state_digest)" - uci -q delete dhcp.@dnsmasq[0].server - add_clash_dns_server "$dns_port" - uci -q delete dhcp.@dnsmasq[0].resolvfile - uci set dhcp.@dnsmasq[0].noresolv='1' - if [ "${dnscache:-0}" -eq 0 ]; then - uci set dhcp.@dnsmasq[0].cachesize='0' - fi - if [ "$(_dnsmasq_state_digest)" != "$_sb_dns_before" ]; then - uci commit dhcp >/dev/null 2>&1 - _reload_dnsmasq >/dev/null 2>&1 - else - uci -q revert dhcp >/dev/null 2>&1 - fi - unset _sb_dns_before -#=========================================================================================================================== -} - - -check(){ - - sed -i 's/^Proxy Group:/proxy-groups:/g' "$CONFIG_YAML" - sed -i 's/^proxy-provider:/proxy-providers:/g' "$CONFIG_YAML" - sed -i 's/^Proxy:/proxies:/g' "$CONFIG_YAML" - sed -i 's/^Rule:/rules:/g' "$CONFIG_YAML" - sed -i 's/^rule-provider:/rule-providers:/g' "$CONFIG_YAML" - -} - -rules(){ -#=========================================================================================================================== - /usr/share/clashoo/net/fw4.sh apply >/dev/null 2>&1 - return $? -#=========================================================================================================================== -} - - -restore() { - sh /usr/share/clashoo/runtime/restore.sh >/dev/null 2>&1 -} - -_config_needs_mmdb() { - grep -Eq '^[[:space:]]*-[[:space:]]*["'\'']?GEOIP,|^[[:space:]]*geoip:[[:space:]]|^[[:space:]]*geoip-code:[[:space:]]' "$CONFIG_YAML" -} - -_has_valid_local_mmdb() { - local db_file db_size - - for db_file in /etc/clashoo/geoip.metadb /etc/clashoo/Country.mmdb; do - [ -f "$db_file" ] || continue - db_size=$(wc -c <"$db_file" 2>/dev/null) - [ -n "$db_size" ] || continue - if [ "$db_file" = "/etc/clashoo/geoip.metadb" ] && [ "$db_size" -ge 1000000 ]; then - return 0 - fi - if [ "$db_file" = "/etc/clashoo/Country.mmdb" ] && [ "$db_size" -ge 2000000 ]; then - return 0 - fi - done - - return 1 -} - -_config_needs_geosite() { - # Matches: routing rules (- GEOSITE,...), geosite: child blocks, and - # list-item refs like `- geosite:cn` / `- 'geosite:cn'` used in - # fake-ip-filter (the default config ships one, easy to miss). - grep -Eq "^[[:space:]]*-[[:space:]]*[\"']?GEOSITE,|^[[:space:]]*geosite:[[:space:]]*|^[[:space:]]*[\"']geosite:|^[[:space:]]*-[[:space:]]*[\"']?geosite:" "$CONFIG_YAML" -} - -_has_valid_local_geosite() { - local site_file site_size - - for site_file in /etc/clashoo/GeoSite.dat /etc/clashoo/geosite.dat; do - [ -f "$site_file" ] || continue - site_size=$(wc -c <"$site_file" 2>/dev/null) - [ -n "$site_size" ] || continue - if [ "$site_size" -ge 2000000 ]; then - if [ "$site_file" = "/etc/clashoo/geosite.dat" ]; then - cp -f "$site_file" /etc/clashoo/GeoSite.dat >/dev/null 2>&1 || true - chmod 644 /etc/clashoo/GeoSite.dat >/dev/null 2>&1 || true - fi - return 0 - fi - done - - return 1 -} - -_strip_geox_url_block() { - awk ' - BEGIN { skip=0 } - /^geox-url:[[:space:]]*$/ { skip=1; next } - skip && /^[^[:space:]]/ { skip=0 } - !skip { print } - ' "$CONFIG_YAML" > /tmp/_clashoo_geox.yaml && mv /tmp/_clashoo_geox.yaml "$CONFIG_YAML" -} - -_strip_yaml_child_block() { - local regex="$1" - awk -v target="$regex" ' - function indent_of(line) { - match(line, /^[[:space:]]*/) - return RLENGTH - } - { - if (skip) { - if (length($0) == 0) { - next - } - if (indent_of($0) > base_indent) { - next - } - skip=0 - } - if ($0 ~ target) { - skip=1 - base_indent=indent_of($0) - next - } - print - } - ' "$CONFIG_YAML" > /tmp/_clashoo_geo_block.yaml && mv /tmp/_clashoo_geo_block.yaml "$CONFIG_YAML" -} - -_strip_yaml_rule_lines() { - local regex="$1" - awk -v target="$regex" ' - $0 ~ target { next } - { print } - ' "$CONFIG_YAML" > /tmp/_clashoo_geo_rules.yaml && mv /tmp/_clashoo_geo_rules.yaml "$CONFIG_YAML" -} - - -_start_geoip_update_async() { - if [ -f /var/run/geoip_update ]; then - return 0 - fi - touch /var/run/geoip_update >/dev/null 2>&1 - (exec 1000>&-; nohup /usr/share/clashoo/update/geoip.sh >/dev/null 2>&1 /dev/null 2>&1 - rm -f /etc/clashoo/geoip.metadb >/dev/null 2>&1 - log_msg "GeoIP database is invalid or incomplete, fallback to bootstrap mode" "GeoIP 数据库无效或下载不完整,已回退到引导模式" - fi - [ "$needs_geosite" -eq 1 ] && _has_valid_local_geosite && needs_geosite=0 - - if [ "$needs_mmdb" -eq 0 ] && [ "$needs_geosite" -eq 0 ]; then - return 0 - fi - - sed -i '/^geodata-mode:/d; /^geodata-loader:/d' "$CONFIG_YAML" 2>/dev/null - _strip_geox_url_block - - if [ "$needs_mmdb" -eq 1 ]; then - _strip_yaml_rule_lines "^[[:space:]]*-[[:space:]]*[\"']?GEOIP," - sed -i '/^[[:space:]]*geoip:[[:space:]]*/d' "$CONFIG_YAML" 2>/dev/null - sed -i '/^[[:space:]]*geoip-code:[[:space:]]*/d' "$CONFIG_YAML" 2>/dev/null - fi - - if [ "$needs_geosite" -eq 1 ]; then - rm -f /etc/clashoo/GeoSite.dat /etc/clashoo/geosite.dat >/dev/null 2>&1 - _strip_yaml_rule_lines "^[[:space:]]*-[[:space:]]*[\"']?GEOSITE," - _strip_yaml_child_block '^[[:space:]]*geosite:[[:space:]]*$' - _strip_yaml_child_block "^[[:space:]]*'geosite:[^']*'[[:space:]]*:[[:space:]]*$" - _strip_yaml_child_block '^[[:space:]]*"geosite:[^"]*"[[:space:]]*:[[:space:]]*$' - _strip_yaml_child_block '^[[:space:]]*geosite:[^[:space:]]+:[[:space:]]*$' - _strip_yaml_rule_lines '^[[:space:]]*geosite:[[:space:]]+[^[:space:]].*' - # list-item refs (e.g. fake-ip-filter: - geosite:cn / - 'geosite:cn') - sed -i "/^[[:space:]]*-[[:space:]]*[\"']\{0,1\}geosite:/d" "$CONFIG_YAML" 2>/dev/null - fi - - # Defer the geo download until the core is up: a fresh box has no working - # proxy yet, so fetching now would hit the (likely blocked) mirrors and fail. - # Record what was missing so the post-start watcher can fetch geo through the - # live proxy and only reload once geo is complete. See _finish_geo_bootstrap. - printf '%s %s\n' "$needs_mmdb" "$needs_geosite" > /var/run/clashoo_bootstrap_pending 2>/dev/null - log_msg "Geo data missing, started in bootstrap mode; will fetch geo via proxy then reload" "Geo 数据缺失,已切换为引导模式;待代理可用后自动补全并重载" -} - -# After the core is up in bootstrap mode, fetch the missing geo data through the -# now-working proxy and, once it is complete, reload the full (un-stripped) -# config so geo rules take effect. Loop-safe: only reloads when the geo that was -# actually missing is now valid, so the next start won't re-enter bootstrap. -_finish_geo_bootstrap() { - local need_mmdb need_geosite still - [ -f /var/run/clashoo_bootstrap_pending ] || return 0 - # core-only never strips, so a flag there would be stale — clear and skip. - if [ "$(uci -q get clashoo.config.core_only 2>/dev/null)" = "1" ]; then - rm -f /var/run/clashoo_bootstrap_pending >/dev/null 2>&1 - return 0 - fi - read need_mmdb need_geosite < /var/run/clashoo_bootstrap_pending 2>/dev/null - - log_msg "Bootstrap: fetching geo data via proxy" "引导模式:正在通过代理补全 Geo 数据" - if [ "$need_geosite" = "1" ]; then - /usr/share/clashoo/update/geoip.sh --require-geosite >/dev/null 2>&1 - else - /usr/share/clashoo/update/geoip.sh >/dev/null 2>&1 - fi - - still=0 - [ "$need_mmdb" = "1" ] && ! _has_valid_local_mmdb && still=1 - [ "$need_geosite" = "1" ] && ! _has_valid_local_geosite && still=1 - if [ "$still" = "1" ]; then - log_msg "Bootstrap: geo fetch incomplete, will retry on next update" "引导模式:Geo 补全未完成,将在下次更新时重试" - return 0 - fi - - rm -f /var/run/clashoo_bootstrap_pending >/dev/null 2>&1 - _clashoo_enabled || return 0 - log_msg "Bootstrap: geo ready, reloading full config" "引导模式:Geo 数据已就绪,正在重载完整配置" - /etc/init.d/clashoo restart >/dev/null 2>&1 -} - - - - - -_start_validate_core() { - local core bin - core="$(uci -q get clashoo.config.core 2>/dev/null)" - if is_singbox_selected; then - bin="$(selected_singbox_binary)" - if [ -z "$bin" ] || ! _ensure_singbox_binary; then - log_msg "sing-box core not found, please install the local sing-box binary first" "找不到本地 sing-box 内核,请先安装 sing-box 二进制" - echo "Clashoo" > "$REAL_LOG" - return 1 - fi - return 0 - fi - - if [ "${core:-0}" -eq 1 ] && [ ! -x "$CLASH" ]; then - log_msg "Smart core not found, please install the local Smart binary first" "找不到本地 Smart 内核,请先安装 Smart 二进制" - echo "Clashoo" > "$REAL_LOG" - return 1 - elif [ "${core:-0}" -eq 2 ] && [ ! -x "$CLASH" ]; then - log_msg "mihomo stable core not found, detected binary is unavailable: $CLASH" "找不到可用的 mihomo 稳定版内核: $CLASH" - sleep 1 - echo "Clashoo" > "$REAL_LOG" - return 1 - elif [ "${core:-0}" -eq 3 ] && [ ! -x "$CLASH" ]; then - log_msg "mihomo Alpha core not found, detected binary is unavailable: $CLASH" "找不到可用的 mihomo Alpha 内核,请在组件更新中安装: $CLASH" - sleep 1 - echo "Clashoo" > "$REAL_LOG" - return 1 - elif [ "${core:-0}" -ne 1 ] && [ "${core:-0}" -ne 2 ] && [ "${core:-0}" -ne 3 ] && [ ! -x "$CLASH" ]; then - log_msg "invalid core setting (${core}), detected binary is unavailable: $CLASH" "内核配置异常 (${core}),且找不到可用内核: $CLASH" - echo "Clashoo" > "$REAL_LOG" - return 1 - fi - return 0 -} - -_start_prepare_config() { - local _reload_candidate="${CLASHOO_RELOAD_CANDIDATE:-0}" - # Core-only: run the imported config verbatim. select_config already copied - # it to /etc/clashoo/config.yaml, so skip every mixin/DNS/rule rewrite below. - [ "$(uci -q get clashoo.config.core_only 2>/dev/null)" = "1" ] && return 0 - - check >/dev/null 2>&1 || return 1 - - [ "$_reload_candidate" = "1" ] || _migrate_dns_roles >/dev/null 2>&1 - - enable_dns=$(uci get clashoo.config.enable_dns 2>/dev/null) - - if [ -z "$(grep -E "^ {0,}listen:" "$CONFIG_YAML")" ] || [ -z "$(grep -E "^ {0,}enhanced-mode:" "$CONFIG_YAML")" ] || [ -z "$(grep -E "^ {0,}dns:" "$CONFIG_YAML")" ];then - - if [ "${enable_dns:-0}" -eq 0 ];then - [ "$_reload_candidate" = "1" ] && return 1 - uci set clashoo.config.enable_dns="1" && uci commit clashoo - log_msg "Enabling Custom Dns" "启用自定义DNS" - fi - - fi - - if { egrep -q '^ {0,}rule-providers:' "$CONFIG_YAML" || egrep -q '^ {0,}script:' "$CONFIG_YAML"; } && ! core_supports_advanced_features; then - [ "$_reload_candidate" = "1" ] && return 1 - if [ -n "$(_mihomo_stable_binary)" ]; then - uci set clashoo.config.core="2" && uci commit clashoo - elif [ -x /usr/share/clashoo/bin/mihomo-alpha ]; then - uci set clashoo.config.core="3" && uci commit clashoo - else - log_msg "Current config requires mihomo/clash-meta core" "当前配置需要 mihomo 或 clash-meta 内核" - backend_remove_rules >/dev/null 2>&1 - sleep 1 - echo "Clashoo" > "$REAL_LOG" - exit 0 - fi - core=$(uci get clashoo.config.core 2>/dev/null) - CLASH="$(_detect_selected_core)" - sleep 1 - fi - - if [ "$(uci get clashoo.config.p_mode 2>/dev/null)" = "script" ]; then - [ "$_reload_candidate" = "1" ] && return 1 - uci set clashoo.config.p_mode="rule" && uci commit clashoo - fi - - # flatten YAML merge anchors first (yq 4.53+ breaks "<<" keys on rewrite) - if command -v yq >/dev/null 2>&1 && grep -q '<<[[:space:]]*:' "$CONFIG_YAML" 2>/dev/null; then - yq e -i 'explode(.)' "$CONFIG_YAML" 2>/dev/null || true - fi - _adapt_dns_loopback_resolver >/dev/null 2>&1 - # stage bundled cn.mrs into the core dir; mihomo rejects rule-set paths outside /etc/clashoo - if [ "$_reload_candidate" != "1" ] && [ -f /usr/share/clashoo/ruleset/cn.mrs ]; then - if [ ! -f /etc/clashoo/ruleset/cn.mrs ] || [ /usr/share/clashoo/ruleset/cn.mrs -nt /etc/clashoo/ruleset/cn.mrs ]; then - mkdir -p /etc/clashoo/ruleset - cp -f /usr/share/clashoo/ruleset/cn.mrs /etc/clashoo/ruleset/cn.mrs 2>/dev/null - fi - fi - _dns_node_policy_capture - yml_change >/dev/null 2>&1 - _dns_node_policy_apply - append_luci_fake_ip_filter_extras >/dev/null 2>&1 - normalize_fake_ip_filter >/dev/null 2>&1 - drop_legacy_cn_ip_injection >/dev/null 2>&1 - dns_leak_protect=$(uci -q get clashoo.config.dns_leak_protect 2>/dev/null) - if command -v dns_mihomo_apply_leak_protect >/dev/null 2>&1; then - case "$(uci -q get clashoo.config.ipv6_proxy 2>/dev/null)" in - 1|true) _ipv6_proxied=1 ;; - *) _ipv6_proxied=0 ;; - esac - if [ "${dns_leak_protect:-0}" = "1" ] && [ "$_ipv6_proxied" = "0" ]; then - _ipv6_value="false" - else - case "$(uci -q get clashoo.config.enable_ipv6 2>/dev/null)" in - true|1) _ipv6_value="true" ;; - false|0) _ipv6_value="false" ;; - *) _ipv6_value="" ;; - esac - fi - unset _ipv6_proxied - dns_mihomo_apply_leak_protect "$CONFIG_YAML" "${dns_leak_protect:-0}" "$_ipv6_value" >/dev/null 2>&1 - unset _ipv6_value - fi - smart_inject >/dev/null 2>&1 - - if ! _has_valid_local_mmdb; then - log_msg "GeoIP database not found, continue without local GeoIP DB" "未找到本地 GeoIP 数据库,继续启动(可在系统页更新 GeoIP)" - fi - - [ "$_reload_candidate" = "1" ] || _prepare_geo_bootstrap_mode - _remap_dns_system_nameserver >/dev/null 2>&1 - ensure_dns_cn_policy_fallback >/dev/null 2>&1 - - - if [ ! -f "$CONFIG_YAML" ];then - [ "$_reload_candidate" = "1" ] && return 1 - log_msg "Cannot find config.yaml" "找不到config.yaml" - backend_remove_rules >/dev/null 2>&1 - sleep 1 - echo "Clashoo" > "$REAL_LOG" - exit 0 - fi - - yml_dns_change >/dev/null 2>&1 || return 1 - - # Sync processed config (with DNS listen injected) to mihomo working directory - [ "$_reload_candidate" = "1" ] || cp -f "$CONFIG_YAML" "${CLASH_CONFIG}/config.yaml" 2>/dev/null - - ip_rules >/dev/null 2>&1 -} - -_core_only_ui_args() { - [ "$(uci -q get clashoo.config.core_only 2>/dev/null)" = "1" ] || return 0 - [ -f /etc/clashoo/dashboard/index.html ] || return 0 - grep -Eq '^[[:space:]]*external-ui:' "$CONFIG_YAML" 2>/dev/null && return 0 - printf ' -ext-ui %s' "$(shell_quote /etc/clashoo/dashboard)" -} - -_mihomo_proxy_dns_valid() { - local config="$1" proxy_count policy_count respect_rules - command -v yq >/dev/null 2>&1 || return 0 - [ -s "$config" ] || return 0 - proxy_count="$(yq -M e -r '(.dns."proxy-server-nameserver" // []) | length' "$config" 2>/dev/null)" - [ "$proxy_count" = "0" ] || return 0 - policy_count="$(yq -M e -r '(.dns."proxy-server-nameserver-policy" // {}) | length' "$config" 2>/dev/null)" - respect_rules="$(yq -M e -r '.dns."respect-rules" // false' "$config" 2>/dev/null)" - [ "$policy_count" = "0" ] && [ "$respect_rules" != "true" ] -} - -_start_launch_core() { - local _cmd _core_only - disable_quic_gso=$(uci get clashoo.config.disable_quic_gso 2>/dev/null) - _core_only=$(uci -q get clashoo.config.core_only 2>/dev/null) - mkdir -p "$(dirname "$CORE_LOG_PATH")" >/dev/null 2>&1 - touch "$CORE_LOG_PATH" >/dev/null 2>&1 - # core.log 在 tmpfs 上,先按大小裁剪,避免上次跑飞的大日志直接卡死启动 - sh /usr/share/clashoo/lib/core_log_guard.sh "$CORE_LOG_PATH" >/dev/null 2>&1 - - # Core-only runs the imported config verbatim, which may reference absolute - # paths (e.g. OpenClash's external-ui /usr/share/openclash/ui). mihomo's - # SAFE_PATHS guard rejects paths outside the working dir, so relax it here — - # in core-only the user is explicitly trusting their own config. - [ "$_core_only" = "1" ] && export SAFE_PATHS="/" - - if ! _mihomo_proxy_dns_valid "${CLASH_CONFIG}/config.yaml"; then - log_msg "Proxy node DNS is required by node DNS policy or respect-rules; set a Proxy Node Domain Resolver in LuCI" "节点域名 DNS 策略或 DNS 遵循规则需要代理节点域名解析,请在 LuCI 中配置" - runtime_state_record_health "fail" "preflight:proxy_dns_missing" - echo "Clashoo" > "$REAL_LOG" - return 1 - fi - - # preflight dry-run with watchdog: bail on bad config without touching - # firewall/dnsmasq, and never let a geo auto-download (mihomo blocks ~90s on - # a missing GeoIP/GeoSite when GitHub is unreachable) freeze startup/UI. - _run_with_timeout 15 "$CLASH" -d "$CLASH_CONFIG" -t >> "$CORE_LOG_PATH" 2>&1 - _pf_rc=$? - if [ "$_pf_rc" -ne 0 ]; then - _pf_reason="$(_preflight_reason)" - if [ "$_pf_rc" -eq 124 ]; then - log_msg "Config preflight timed out (likely downloading geo data), retry shortly. ${_pf_reason}" "配置预检超时(可能正在下载 Geo 数据),稍后自动重试。${_pf_reason}" - runtime_state_record_health "fail" "preflight:timeout" - _start_geoip_update_async - else - log_msg "Config dry-run failed; firewall/DNS untouched. ${_pf_reason}" "配置预检失败,未应用防火墙与 DNS 改动。${_pf_reason}" - runtime_state_record_health "fail" "preflight:config_dry_run_failed" - fi - echo "Clashoo" > "$REAL_LOG" - return 1 - fi - - procd_open_instance - _cmd="$(shell_quote "$CLASH") -d $(shell_quote "$CLASH_CONFIG")$(_core_only_ui_args) >> $(shell_quote "$CORE_LOG_PATH") 2>&1" - procd_set_param command /bin/sh -c "$_cmd" - [ "$disable_quic_gso" = "1" ] && procd_set_param env QUIC_GO_DISABLE_GSO=1 - [ "$_core_only" = "1" ] && procd_set_param env SAFE_PATHS=/ - # 默认 4095 个 fd 顶不住 BT/PCDN 类连接洪水,打爆后核心会陷入 - # accept 失败刷屏,与 sing-box 实例保持一致提到 1000000。 - procd_set_param limits core="unlimited" - procd_set_param limits nofile="1000000 1000000" - procd_set_param respawn 3600 5 5 - procd_close_instance - [ "$disable_quic_gso" = "1" ] && log_msg "Disable quic-go GSO support" "已启用:禁用 quic-go GSO 支持" - ln -s /usr/share/clashoo/yacd /www/luci-static/yacd 2>/dev/null - - # Core-only: just keep the core process; do not take over firewall/DNS/cron. - if [ "$(uci -q get clashoo.config.core_only 2>/dev/null)" != "1" ]; then - log_msg "Configuring firewall rules" "配置防火墙规则" - backend_apply_rules >/dev/null 2>&1 - - if [ "$(_dnsmasq_state_digest)" != "$_dnsmasq_digest_before" ]; then - log_msg "Reloading DNS resolver" "重启 DNS 解析" - _reload_dnsmasq >/dev/null 2>&1 - fi - - restore >/dev/null 2>&1 - add_cron - else - log_msg "Core-only mode: skipping firewall/DNS takeover" "仅内核模式:跳过防火墙与 DNS 接管" - fi - echo "Clashoo" > "$REAL_LOG" - # procd starts the core process only after start_service() returns, so we - # cannot block here waiting for it. Launch a background watcher instead. - # If the core never appears within the window, roll back the firewall - # rules and dnsmasq override we already applied — otherwise the box is - # left with a hijacked DNS pointing at a port nobody is listening on. - ( - exec 1000>&- - _bg_max="$(_compute_start_wait)" - bg_wait=0 - while [ "$bg_wait" -lt "$_bg_max" ]; do - sleep 1 - if _core_running; then - runtime_run_health_check_settle >/dev/null 2>&1 - # kick access check immediately so panel shows current state (daemon polls every 5-20s) - /usr/share/clashoo/net/access_check_cache.sh >/dev/null 2>&1 & - # bootstrap mode: now that the proxy is up, fetch geo + reload full config - _finish_geo_bootstrap - exit 0 - fi - bg_wait=$((bg_wait + 1)) - done - _rollback_failed_start - runtime_state_record_health "fail" "start:core_not_running" - echo " $(date "+%Y-%m-%d %H:%M:%S") - clashoo core not detected within ${_bg_max}s, rolled back" >> /usr/share/clashoo/clashoo.txt - echo "Clashoo" > "$REAL_LOG" - ) & -} - -boot(){ - if [ "$(uci -q get clashoo.config.enable 2>/dev/null)" = "1" ]; then - runtime_state_reset - runtime_state_set "health_status" "starting" - runtime_state_set "health_detail" "boot_starting" - runtime_state_set "updated_at" "$(date +%s)" - # start_service does mihomo -t dry-run + firewall restart + dnsmasq reload/fallback - # (~20-30s on LXC). Doing this synchronously in boot() blocks rcS S99 stage - # and during that window sshd/uhttpd refuse connections (kex reset). Detach - # to background with a small settle delay so the rcS pipeline finishes and - # management plane stays responsive while clashoo brings the proxy up. - ( - exec 1000>&- /dev/null 2>&1 - sleep 5 - _clashoo_enabled || exit 0 - /etc/init.d/clashoo start - ) & - else - runtime_state_reset - runtime_state_set "health_status" "stopped" - runtime_state_set "health_detail" "boot_disabled" - runtime_state_set "updated_at" "$(date +%s)" - echo "Clashoo" > "$REAL_LOG" - fi - return 0 -} - -start_service(){ -#=========================================================================================================================== - lang=$(uci get luci.main.lang 2>/dev/null) - enable=$(uci get clashoo.config.enable 2>/dev/null) - mode=$(uci get clashoo.config.mode 2>/dev/null) - tun_mode=$(uci get clashoo.config.tun_mode 2>/dev/null) - core_only=$(uci -q get clashoo.config.core_only 2>/dev/null) - - sync_legacy_core_field - _migrate_legacy_mihomo_stable - CLASH="$(_detect_selected_core)" - - cleanup_legacy_startup_backups - migrate_legacy_clash_dir - /usr/share/clashoo/migrate_lan_acl.sh >/dev/null 2>&1 || true - /usr/share/clashoo/migrate_fake_ip_filter.sh >/dev/null 2>&1 || true - runtime_state_reset - - if [ "${enable:-0}" -eq 1 ]; then - resolve_effective_tp_modes - runtime_state_record_preflight "$(selected_core_family)" - log_msg "Starting Clashoo" "启动 Clashoo" - if is_singbox_selected; then - if _core_running; then stop_service >/dev/null 2>&1; fi - resolve_effective_tp_modes - runtime_state_record_preflight "singbox" - if ! _require_runtime_network_stack; then - runtime_state_record_health "fail" "preflight:missing_fw4_stack" - echo "Clashoo" > "$REAL_LOG" - return 1 - fi - if ! _start_validate_core; then - runtime_state_record_health "fail" "preflight:core_validation_failed" - return 1 - fi - if ! start_singbox_service; then - # preflight failure already recorded; avoid blanket overwrite - case "$(grep '^health_detail=' "$RUNTIME_STATE_FILE" 2>/dev/null | cut -d= -f2-)" in - preflight:*) ;; - *) runtime_state_record_health "fail" "start:singbox_service_failed" ;; - esac - echo "Clashoo" > "$REAL_LOG" - return 1 - fi - if [ "$core_only" != "1" ]; then - log_msg "Configuring firewall rules" "配置防火墙规则" - backend_apply_rules >/dev/null 2>&1 - singbox_dns_change >/dev/null 2>&1 - add_cron >/dev/null 2>&1 - else - log_msg "Core-only mode: skipping firewall/DNS takeover" "仅内核模式:跳过防火墙与 DNS 接管" - fi - # procd does not launch the named instance until start_service returns - # and rc.common submits the completed service definition. Watch it in - # the background, just like the mihomo path, then roll back only if the - # registered private instance never becomes healthy. - ( - exec 1000>&- - _bg_max="$(_compute_start_wait)" - _bg_wait=0 - while [ "$_bg_wait" -lt "$_bg_max" ]; do - sleep 1 - if _singbox_running; then - runtime_run_health_check_settle >/dev/null 2>&1 - exit 0 - fi - _bg_wait=$((_bg_wait + 1)) - done - _rollback_failed_start - runtime_state_record_health "fail" "start:singbox_not_running" - echo " $(date "+%Y-%m-%d %H:%M:%S") - clashoo sing-box not detected within ${_bg_max}s, rolled back" >> /usr/share/clashoo/clashoo.txt - echo "Clashoo" > "$REAL_LOG" - ) & - echo "Clashoo" > "$REAL_LOG" - return 0 - fi - if _core_running; then stop_service >/dev/null 2>&1; fi - if ! select_config >/dev/null 2>&1; then - runtime_state_record_health "fail" "preflight:config_missing" - _log_runtime_error "Config file is missing or empty; please import a subscription/config first" - return 1 - fi - - if ! _require_runtime_network_stack; then - runtime_state_record_health "fail" "preflight:missing_fw4_stack" - echo "Clashoo" > "$REAL_LOG" - exit 0 - fi - - -if ! _start_validate_core; then - runtime_state_record_health "fail" "preflight:core_validation_failed" - return 1 -fi - -if [ -f "$CONFIG_YAML" ] && [ -s "$CONFIG_YAML" ] ; then - - _dnsmasq_digest_before="$(_dnsmasq_state_digest)" - _start_prepare_config - - _start_launch_core - -else - if [ "${lang}" = "en" ]; then - echo " $(date "+%Y-%m-%d %H:%M:%S") - problem with config.yaml, config.yaml is either empty or not found " >> /usr/share/clashoo/clashoo.txt - elif [ "${lang}" = "zh_cn" ]; then - echo " $(date "+%Y-%m-%d %H:%M:%S") - 你的config.yaml有问题还是为了空 0kb " >> /usr/share/clashoo/clashoo.txt - fi - runtime_state_record_health "fail" "start:config_yaml_invalid" - log_msg "Config file invalid or empty" "配置文件无效或为空" - echo "Clashoo" > "$REAL_LOG" -fi - -else - runtime_state_set "health_status" "stopped" - runtime_state_set "health_detail" "service_disabled" - runtime_state_set "updated_at" "$(date +%s)" - if [ "${lang}" = "en" ]; then - echo " $(date "+%Y-%m-%d %H:%M:%S") - Enable Client and Start Client Again" >> /usr/share/clashoo/clashoo.txt - elif [ "${lang}" = "zh_cn" ]; then - echo " $(date "+%Y-%m-%d %H:%M:%S") - 启用客户端并重新启动客户端" >> /usr/share/clashoo/clashoo.txt - fi - echo "Clashoo" > "$REAL_LOG" -fi -#=========================================================================================================================== -} - - -remove_mark(){ - /usr/share/clashoo/net/fw4.sh remove >/dev/null 2>&1 - return 0 -} - -stop_service(){ -#=========================================================================================================================== - # The updater restarts once after an in-place APK upgrade. Skip the - # package-manager pre-deinstall stop to avoid its ~120s script wait. - if [ -r /var/run/clashoo_package_upgrade ]; then - _upgrade_pid="$(cat /var/run/clashoo_package_upgrade 2>/dev/null)" - case "$_upgrade_pid" in - ''|*[!0-9]*) rm -f /var/run/clashoo_package_upgrade ;; - *) - [ -d "/proc/$_upgrade_pid" ] && return 0 - rm -f /var/run/clashoo_package_upgrade - ;; - esac - fi - - lang=$(uci get luci.main.lang 2>/dev/null) - tun_mode=$(uci get clashoo.config.tun_mode 2>/dev/null) - - # server.list is read-only; just clean up merged temp files in /tmp - rm -f /tmp/clashoo/fake_filter.list /tmp/clashoo/fake_filter.yaml 2>/dev/null - - log_msg "Stopping Clashoo" "正在停止 Clashoo" - for _ac_sig in TERM KILL; do - for _ac_pid in $(pgrep -f access_check_daemon 2>/dev/null); do - tr '\0' ' ' < "/proc/$_ac_pid/cmdline" 2>/dev/null | grep -q access_check_daemon.sh && kill -"$_ac_sig" "$_ac_pid" 2>/dev/null - done - done - rm -rf /tmp/clashoo/access_check_daemon.pid /tmp/clashoo/access_check_daemon.lock 2>/dev/null - rm -f /var/run/clashoo_bootstrap_pending 2>/dev/null - log_msg "Removing firewall rules" "清理防火墙规则" - backend_remove_rules >/dev/null 2>&1 - cleanup_stale_core_nft >/dev/null 2>&1 - revert_dns >/dev/null 2>&1 - - sh /usr/share/clashoo/runtime/backup.sh >/dev/null 2>&1 - - stop_singbox_service - _kill_core - - rm -rf /www/luci-static/yacd 2>/dev/null - - del_cron >/dev/null 2>&1 - - - echo "" >/usr/share/clashoo/clashoo.txt >/dev/null 2>&1 - - echo "0" > /usr/share/clashoo/logstatus_check >/dev/null 2>&1 - - if [ "${lang}" = "en" ]; then - echo " $(date "+%Y-%m-%d %H:%M:%S") - CLIENT IS DISABLED " >> /usr/share/clashoo/clashoo.txt - elif [ "${lang}" = "zh_cn" ]; then - echo " $(date "+%Y-%m-%d %H:%M:%S") - 客户端被禁用 " >> /usr/share/clashoo/clashoo.txt - fi - echo "Clashoo" > "$REAL_LOG" - - if _core_running; then - _kill_core - fi - for _cpid in $(pgrep -f /etc/clashoo 2>/dev/null); do - _ccl="$(tr '\0' ' ' < "/proc/$_cpid/cmdline" 2>/dev/null)" - printf '%s' "$_ccl" | grep -q -e '-d /etc/clashoo' -e '-f /etc/clashoo/config.yaml' && kill "$_cpid" 2>/dev/null - done - runtime_state_reset - runtime_state_set "health_status" "stopped" - runtime_state_set "health_detail" "service_stopped" - runtime_state_set "updated_at" "$(date +%s)" - - # kick access check on stop (proxy_listening fast-paths to down; UI reflects stop within 5s) - (exec 1000>&-; /usr/share/clashoo/net/access_check_cache.sh >/dev/null 2>&1) & - -#=========================================================================================================================== -} - -_mihomo_reload_api() { - local _path="$1" _response="$2" _dp _ds _lip - _dp="$(uci -q get clashoo.config.dash_port)"; [ -n "$_dp" ] || _dp=9090 - _ds="$(uci -q get clashoo.config.dash_pass)" - _lip="$(uci -q get network.lan.ipaddr 2>/dev/null | awk -F'/' '{print $1}')" - [ -n "$_lip" ] || _lip=127.0.0.1 - MIHOMO_RELOAD_CURL_RC=0 - MIHOMO_RELOAD_HTTP_CODE="$(curl -sS -m 5 -o "$_response" -w '%{http_code}' \ - -H "Authorization: Bearer ${_ds}" -H "Content-Type: application/json" \ - -X PUT -d '{"path":"'"$_path"'"}' \ - "http://${_lip}:${_dp}/configs?force=true" 2>/dev/null)" || MIHOMO_RELOAD_CURL_RC=$? - [ "$MIHOMO_RELOAD_CURL_RC" -eq 0 ] || return 1 - case "$MIHOMO_RELOAD_HTTP_CODE" in - 2??) return 0 ;; - *) return 1 ;; - esac -} - -_mihomo_reload_save_dns() { - MIHOMO_DHCP_MODE="$(stat -c %a /etc/config/dhcp)" || return 1 - cp /etc/config/dhcp "$1" -} - -_mihomo_reload_restore_dns() { - cp "$1" /etc/config/dhcp && chmod "$MIHOMO_DHCP_MODE" /etc/config/dhcp && - uci -q revert dhcp && _reload_dnsmasq >/dev/null 2>&1 -} - -_mihomo_reload_restore() { - local _previous="$1" _response="$2" _dns_backup="$3" _peripheral_changed="$4" _restore _failed=0 - if ! _mihomo_reload_api "$_previous" "$_response"; then - return 1 - fi - if [ "$_peripheral_changed" = "1" ]; then - if _restore="$(mktemp "${CLASH_CONFIG}/.reload-restore.XXXXXX")"; then - cp "$_previous" "$_restore" && mv -f "$_restore" "$CONFIG_YAML" || { rm -f "$_restore"; _failed=1; } - else - _failed=1 - fi - _mihomo_reload_restore_dns "$_dns_backup" || _failed=1 - backend_remove_rules >/dev/null 2>&1 || _failed=1 - backend_apply_rules >/dev/null 2>&1 || _failed=1 - fi - return "$_failed" -} - -reload_service() -{ - if is_singbox_selected; then - if _singbox_running; then - # Use rc.common's transaction wrapper so the complete Clashoo service - # definition is rebuilt before the named instance is registered again. - # This intentionally reapplies Clashoo's own firewall/DNS state; calling - # start_service directly would skip that wrapper and procd setup. - stop_singbox_service >/dev/null 2>&1 - start - fi - elif _core_running; then - local _candidate _previous _response _dns_backup _source _pf_rc _error _peripheral_changed - _error="" - resolve_effective_tp_modes - _candidate="$(mktemp "${CLASH_CONFIG}/.reload-candidate.XXXXXX")" || { _log_runtime_error "Mihomo reload failed: cannot stage candidate"; return 1; } - _previous="$(mktemp "${CLASH_CONFIG}/.reload-previous.XXXXXX")" || { rm -f "$_candidate"; _log_runtime_error "Mihomo reload failed: cannot back up current config"; return 1; } - _response="$(mktemp /tmp/clashoo-reload-response.XXXXXX)" || { rm -f "$_candidate" "$_previous"; _log_runtime_error "Mihomo reload failed: cannot stage API response"; return 1; } - _dns_backup="$(mktemp "${CLASH_CONFIG}/.reload-dhcp.XXXXXX")" || { rm -f "$_candidate" "$_previous" "$_response"; _log_runtime_error "Mihomo reload failed: cannot back up DNS state"; return 1; } - _source="$(uci -q get clashoo.config.use_config 2>/dev/null)" - if [ ! -s "$_source" ]; then - _error="selected config is missing or empty" - elif ! cp "$_source" "$_candidate" || ! cp "$CONFIG_YAML" "$_previous" || - ! _mihomo_reload_save_dns "$_dns_backup"; then - _error="cannot back up current config or DNS state" - elif ! ( CONFIG_YAML="$_candidate"; CLASHOO_RELOAD_CANDIDATE=1; _start_prepare_config ) >/dev/null 2>&1 || - [ ! -s "$_candidate" ]; then - _error="candidate generation failed; check DNS and core settings" - fi - rm -f "${_candidate}.mixin" 2>/dev/null - if [ -n "$_error" ]; then - _log_runtime_error "Mihomo reload failed: ${_error}; current config preserved" - rm -f "$_candidate" "$_previous" "$_response" "$_dns_backup" - return 1 - fi - if ! _mihomo_proxy_dns_valid "$_candidate"; then - _log_runtime_error "Mihomo reload failed: node DNS policy or respect-rules requires a Proxy Node Domain Resolver; current config preserved" - rm -f "$_candidate" "$_previous" "$_response" "$_dns_backup" - return 1 - fi - if [ "$(uci -q get clashoo.config.core_only 2>/dev/null)" = "1" ]; then - SAFE_PATHS=/ _run_with_timeout 15 "$CLASH" -d "$CLASH_CONFIG" -f "$_candidate" -t >> "$CORE_LOG_PATH" 2>&1 - else - _run_with_timeout 15 "$CLASH" -d "$CLASH_CONFIG" -f "$_candidate" -t >> "$CORE_LOG_PATH" 2>&1 - fi - _pf_rc=$? - if [ "$_pf_rc" -ne 0 ]; then - if [ "$_pf_rc" -eq 124 ]; then - _error="Mihomo reload failed: candidate preflight timed out" - else - _error="Mihomo reload failed: candidate config invalid (exit ${_pf_rc}; see core log)" - fi - _log_runtime_error "$_error; current config preserved" - rm -f "$_candidate" "$_previous" "$_response" "$_dns_backup" - return 1 - fi - if ! _mihomo_reload_api "$_candidate" "$_response"; then - _error="Mihomo reload failed (curl ${MIHOMO_RELOAD_CURL_RC}, HTTP ${MIHOMO_RELOAD_HTTP_CODE})" - if _mihomo_reload_restore "$_previous" "$_response" "$_dns_backup" 0; then - _log_runtime_error "${_error}; previous config restored" - rm -f "$_candidate" "$_previous" "$_response" "$_dns_backup" - else - _log_runtime_error "${_error}; reload outcome unknown; candidate and backup retained" - rm -f "$_response" "$_dns_backup" - fi - return 1 - fi - _peripheral_changed=0 - if ! mv -f "$_candidate" "$CONFIG_YAML"; then - _error="Mihomo reload failed: cannot commit candidate config" - elif [ "$(uci -q get clashoo.config.core_only 2>/dev/null)" != "1" ]; then - _peripheral_changed=1 - if ! backend_remove_rules >/dev/null 2>&1 || ! backend_apply_rules >/dev/null 2>&1 || - ! yml_dns_change >/dev/null 2>&1 || ! _reload_dnsmasq >/dev/null 2>&1; then - _error="Mihomo reload failed: firewall or DNS update failed" - fi - fi - if [ -n "$_error" ]; then - if _mihomo_reload_restore "$_previous" "$_response" "$_dns_backup" "$_peripheral_changed"; then - _log_runtime_error "${_error}; previous config and settings restored" - rm -f "$_candidate" "$_previous" "$_response" "$_dns_backup" - else - _log_runtime_error "${_error}; rollback incomplete; previous config retained for recovery" - rm -f "$_candidate" "$_response" - fi - return 1 - fi - rm -f "$_previous" "$_response" "$_dns_backup" "${CONFIG_YAML}.dns-leak-nameserver" - runtime_state_record_preflight "mihomo" - runtime_run_health_check_settle >/dev/null 2>&1 - fi -} - -status_service() { - if _selected_core_running; then - echo "running" - else - echo "inactive" - fi -} diff --git a/clashoo/files/usr/share/clashoo/detect_core_arch.sh b/clashoo/files/usr/share/clashoo/detect_core_arch.sh deleted file mode 100755 index fbb3defd..00000000 --- a/clashoo/files/usr/share/clashoo/detect_core_arch.sh +++ /dev/null @@ -1,26 +0,0 @@ -#!/bin/sh - -[ -n "$(uci -q get clashoo.config.download_core 2>/dev/null)" ] && exit 0 - -raw="$(uname -m 2>/dev/null)" -[ -n "$raw" ] || raw="$(apk --print-arch 2>/dev/null)" -[ -n "$raw" ] || raw="$(opkg status libc 2>/dev/null | awk -F': ' '/^Architecture/{print $2; exit}')" -[ -n "$raw" ] || exit 0 - -case "$raw" in - x86_64|amd64) arch="amd64-compatible" ;; - aarch64*|arm64) arch="arm64" ;; - armv7*|arm_cortex-a[7-9]*|arm_cortex-a1[0-9]*) arch="armv7" ;; - armv6*|arm_cortex-a[56]*) arch="armv6" ;; - arm*) arch="armv5" ;; - i[3-6]86) arch="386" ;; - mips64el*) arch="mips64le" ;; - mips64*) arch="mips64" ;; - mipsel*) arch="mipsle" ;; - mips*) arch="mips" ;; - *) exit 0 ;; -esac - -uci -q set clashoo.config.download_core="$arch" -uci -q commit clashoo -exit 0 diff --git a/clashoo/files/usr/share/clashoo/diagnose_bypass.sh b/clashoo/files/usr/share/clashoo/diagnose_bypass.sh deleted file mode 100644 index 0e01a30d..00000000 --- a/clashoo/files/usr/share/clashoo/diagnose_bypass.sh +++ /dev/null @@ -1,181 +0,0 @@ -#!/bin/sh - -umask 077 - -CONFIG_YAML="${CONFIG_YAML:-/etc/clashoo/config.yaml}" -NFT_V4="${NFT_V4:-/usr/share/clashoo/nftables/geoip_cn.nft}" -NFT_V6="${NFT_V6:-/usr/share/clashoo/nftables/geoip6_cn.nft}" -MAX_CONN=200 - -TMPDIR_D="$(mktemp -d /tmp/.clashoo_diag.XXXXXX 2>/dev/null)" || exit 1 -trap 'rm -rf "$TMPDIR_D" 2>/dev/null' EXIT INT TERM - -uci_get() { - uci -q get "clashoo.config.$1" 2>/dev/null -} - -section() { - printf '\n===== %s =====\n' "$1" -} - -yesno() { - [ -n "$1" ] && [ "$1" != "0" ] && [ "$1" != "false" ] && echo "on" || echo "off" -} - -bool_on() { - case "$1" in - 1|true|TRUE|yes|on) return 0 ;; - *) return 1 ;; - esac -} - -bypass4="$(uci_get bypass_china)" -bypass6="$(uci_get bypass_china_ipv6)" -[ -n "$bypass6" ] || bypass6="$bypass4" - -section "配置摘要" -printf '服务开关 : %s\n' "$(yesno "$(uci_get enable)")" -printf '运行模式 : %s\n' "$(uci_get enhanced_mode)" -printf 'TCP / UDP : %s / %s\n' "$(uci_get tcp_mode)" "$(uci_get udp_mode)" -printf '大陆绕过 v4 : %s\n' "$(yesno "$bypass4")" -printf '大陆绕过 v6 : %s%s\n' "$(yesno "$bypass6")" \ - "$([ -z "$(uci_get bypass_china_ipv6)" ] && echo '(未设置,跟随 v4)')" -printf '接管端口 : %s' "$(uci_get bypass_port_mode)" -[ "$(uci_get bypass_port_mode)" = "custom" ] && printf ' (%s)' "$(uci_get bypass_port_custom)" -printf '\n' -printf 'IPv6 代理 : %s\n' "$(yesno "$(uci_get ipv6_proxy)")" -printf '阻断 QUIC : %s\n' "$(yesno "$(uci_get block_quic)")" - -if [ "$(uci_get bypass_port_mode)" = "common" ]; then - printf '\n注意: 接管端口为 common,只代理 22/53/80/443/8080/8443,\n' - printf ' 游戏与 P2P 常用的高位端口不会走代理。\n' -fi - -section "fake-ip 过滤" -if [ -s "$CONFIG_YAML" ]; then - if grep -qE '^[[:space:]]*fake-ip-filter:' "$CONFIG_YAML" 2>/dev/null; then - filter_mode="$(uci_get fake_ip_filter_mode)" - [ -n "$filter_mode" ] || filter_mode="$(yq -M e '(.dns."fake-ip-filter-mode" // "blacklist") | tostring' "$CONFIG_YAML" 2>/dev/null)" - if [ "$filter_mode" = "whitelist" ]; then - echo "白名单模式:列表中的域名使用 fake-IP" - elif grep -qiE 'rule-set:cn_domain|RULE-SET,[[:space:]]*cn_domain,[[:space:]]*real-ip' "$CONFIG_YAML" 2>/dev/null; then - echo "含 rule-set:cn_domain (国内域名返回真实 IP)" - else - echo "缺少 rule-set:cn_domain" - echo " 国内域名会拿到 fake-ip 走代理,与硬编码国内 IP 分成两条路。" - fi - else - echo "配置中无 fake-ip-filter" - fi -else - echo "找不到 $CONFIG_YAML" -fi - -section "内核分流规则" -if [ -s "$CONFIG_YAML" ]; then - echo "-- rules 末尾 5 条 --" - grep -E '^[[:space:]]*-[[:space:]]*["'"'"']?(GEOIP|RULE-SET|MATCH|IP-CIDR|DOMAIN)' "$CONFIG_YAML" 2>/dev/null | tail -5 -fi - -section "IP 库" -for f in "$NFT_V4" "$NFT_V6"; do - if [ -s "$f" ]; then - printf '%-46s %6s 条 %s\n' "$f" \ - "$(grep -cE '^[[:space:]]*[0-9a-fA-F].*/' "$f" 2>/dev/null)" \ - "$(date -r "$f" '+%Y-%m-%d %H:%M' 2>/dev/null)" - else - printf '%-46s 缺失\n' "$f" - fi -done -for f in /etc/clashoo/Country.mmdb /etc/clashoo/geoip.metadb; do - [ -f "$f" ] && printf '%-46s %s\n' "$f" "$(ls -lh "$f" 2>/dev/null | awk '{print $5}')" -done - -set_count() { - nft list set inet fw4 "$1" 2>/dev/null | tr ',' '\n' | grep -cE '[0-9a-fA-F]+[.:].*/' -} - -section "防火墙绕过规则" -if nft list sets inet fw4 2>/dev/null | grep -q clashoo_china; then - for ch in dstnat mangle_prerouting; do - nft -a list chain inet fw4 "$ch" 2>/dev/null | - grep -E '@clashoo_china6? ' | sed "s|^[[:space:]]*| ${ch}: |" - done - echo - echo "已加载元素数(nft auto-merge 会合并相邻网段,少于文件行数属正常):" - bool_on "$bypass4" && printf ' clashoo_china : %s\n' "$(set_count clashoo_china)" - bool_on "$bypass6" && printf ' clashoo_china6 : %s\n' "$(set_count clashoo_china6)" -else - echo "当前 nftables 中没有 clashoo_china 集合(绕过未启用或服务未运行)" -fi - -section "绕过命中检查" -if ! bool_on "$bypass4" && ! bool_on "$bypass6"; then - echo "两个绕过均未启用,所有被接管的流量都交给内核判定,无需检查" -else - SECRET="$(uci_get dash_pass)" - PORT="$(uci_get dash_port)" - LAN_IP="$(uci -q get network.lan.ipaddr 2>/dev/null | awk -F/ '{print $1}')" - [ -n "$LAN_IP" ] || LAN_IP="127.0.0.1" - CONN_JSON="$TMPDIR_D/connections.json" - - if [ -z "$PORT" ]; then - echo "未配置控制端口,跳过" - elif ! curl -m 5 -s -H "Authorization: Bearer ${SECRET}" \ - "http://${LAN_IP}:${PORT}/connections" -o "$CONN_JSON" 2>/dev/null; then - echo "无法访问内核 API (http://${LAN_IP}:${PORT}),跳过" - elif [ ! -s "$CONN_JSON" ]; then - echo "内核 API 返回为空,跳过" - else - jsonfilter -i "$CONN_JSON" -e '@["connections"][*]["metadata"]["destinationIP"]' \ - 2>/dev/null > "${CONN_JSON}.ip" - jsonfilter -i "$CONN_JSON" -e '@["connections"][*]["chains"][0]' \ - 2>/dev/null > "${CONN_JSON}.ch" - - total="$(wc -l < "${CONN_JSON}.ip" 2>/dev/null | tr -d ' ')" - [ -n "$total" ] || total=0 - - if [ "$total" -eq 0 ]; then - echo "当前无活动连接" - elif [ "$total" != "$(wc -l < "${CONN_JSON}.ch" 2>/dev/null | tr -d ' ')" ]; then - echo "内核 API 字段数不一致,跳过" - else - awk 'NR==FNR { a[FNR] = $0; next } { print a[FNR] "\t" $0 }' \ - "${CONN_JSON}.ip" "${CONN_JSON}.ch" 2>/dev/null \ - | awk -F'\t' '$2 != "DIRECT" && $1 != "" && $1 !~ /^(198\.18\.|::|fc00:|fd)/ { print $1 "\t" $2 }' \ - | sort -u | head -n "$MAX_CONN" > "${CONN_JSON}.chk" - - hit=0 - : > "${CONN_JSON}.bad" - while IFS="$(printf '\t')" read -r dip chain; do - [ -n "$dip" ] || continue - case "$dip" in - *:*) bool_on "$bypass6" || continue - set_name=clashoo_china6 ;; - *) bool_on "$bypass4" || continue - set_name=clashoo_china ;; - esac - if nft get element inet fw4 "$set_name" "{ $dip }" >/dev/null 2>&1; then - hit=$((hit + 1)) - printf ' %-40s -> %s\n' "$dip" "$chain" >> "${CONN_JSON}.bad" - fi - done < "${CONN_JSON}.chk" - - printf '活动连接 %s 条,其中走代理的去重目的地 %s 个(上限 %s)\n' \ - "$total" "$(wc -l < "${CONN_JSON}.chk" 2>/dev/null | tr -d ' ')" "$MAX_CONN" - if [ "$hit" -gt 0 ]; then - printf '命中绕过白名单却仍走代理: %s 个\n\n' "$hit" - head -20 "${CONN_JSON}.bad" - echo - echo "这些目的地在防火墙白名单内,本应直连,却出现在代理链路上。" - echo "可能是连接建立于规则变更之前,或该地址族的绕过规则未生效。" - else - echo "未发现白名单地址走代理的连接" - fi - rm -f "${CONN_JSON}.chk" "${CONN_JSON}.bad" 2>/dev/null - fi - rm -f "${CONN_JSON}.ip" "${CONN_JSON}.ch" 2>/dev/null - fi -fi - -printf '\n' diff --git a/clashoo/files/usr/share/clashoo/lib/core_log_guard.sh b/clashoo/files/usr/share/clashoo/lib/core_log_guard.sh deleted file mode 100644 index afd5450f..00000000 --- a/clashoo/files/usr/share/clashoo/lib/core_log_guard.sh +++ /dev/null @@ -1,28 +0,0 @@ -#!/bin/sh -# clashoo core log size guard -# 用法: core_log_guard.sh [logfile] -# -# core.log 落在 /var/log(= /tmp 下的 tmpfs),没有大小上限时一次 accept -# 失败风暴就能把它写到几百 MB,直接把 /tmp 写满(dnsmasq、配置生成、 -# cron 全部失效)。这里在超过上限时就地裁剪,只保留尾部内容。 -# 内核进程持有该文件的 O_APPEND fd,所以必须原地重写,不能替换 inode。 - -set -u - -LOG="${1:-/var/log/clashoo/core.log}" -MAX_KB="${CLASHOO_CORE_LOG_MAX_KB:-16384}" -KEEP_KB="${CLASHOO_CORE_LOG_KEEP_KB:-1024}" - -[ -f "$LOG" ] || exit 0 -size="$(wc -c <"$LOG" 2>/dev/null)" -case "${size:-}" in ''|*[!0-9]*) exit 0 ;; esac -[ "$size" -gt $((MAX_KB * 1024)) ] || exit 0 - -tmp="${LOG}.trim.$$" -if tail -c $((KEEP_KB * 1024)) "$LOG" >"$tmp" 2>/dev/null && cat "$tmp" >"$LOG" 2>/dev/null; then - rm -f "$tmp" -else - rm -f "$tmp" - : >"$LOG" 2>/dev/null || true -fi -exit 0 diff --git a/clashoo/files/usr/share/clashoo/lib/migrate_singbox.uc b/clashoo/files/usr/share/clashoo/lib/migrate_singbox.uc deleted file mode 100644 index a200b982..00000000 --- a/clashoo/files/usr/share/clashoo/lib/migrate_singbox.uc +++ /dev/null @@ -1,385 +0,0 @@ -#!/usr/bin/ucode - -'use strict'; - -import { readfile, writefile } from 'fs'; - -// Standalone sing-box config version-migration, used by the init.d core-only -// path to upgrade an imported config (momo/homeproxy/etc.) to the format the -// current sing-box core accepts, WITHOUT clashoo normalize/takeover. -// -// IMPORTANT: migrate_singbox() below is kept byte-for-byte in sync with the -// copy in luci-app-clashoo/.../luci.clashoo (the UI "migrate" button). If you -// change one, change the other. - -function migrate_singbox(cfg) { - // --- Fix DNS servers: address-based → type-based, remove detour --- - if (cfg.dns && cfg.dns.servers) { - cfg.dns.servers = map(cfg.dns.servers || [], function(srv) { - let addr = srv.address || ''; - let new_srv = {}; - let skip = { address: 1, detour: 1, address_resolver: 1, address_strategy: 1 }; - for (let k in srv) if (!skip[k]) new_srv[k] = srv[k]; - - if (addr === 'fakeip') { - new_srv.type = 'fakeip'; - } else if (addr === 'local' || addr === '') { - new_srv.type = new_srv.type || 'local'; - } else if (match(addr, /^rcode:\/\//) || addr === 'rcode') { - new_srv._rcode = true; // mark for removal, handled via dns rule action - } else if (match(addr, /^h3:\/\//)) { - let host = replace(replace(addr, /^h3:\/\//, ''), /\/.*$/, ''); - new_srv.type = 'h3'; new_srv.server = host; - } else if (match(addr, /^https:\/\//)) { - let host = replace(replace(addr, /^https:\/\//, ''), /\/.*$/, ''); - new_srv.type = 'https'; new_srv.server = host; - } else if (match(addr, /^tls:\/\//)) { - new_srv.type = 'tls'; new_srv.server = replace(addr, /^tls:\/\//, ''); - } else if (match(addr, /^tcp:\/\//)) { - new_srv.type = 'tcp'; new_srv.server = replace(addr, /^tcp:\/\//, ''); - } else if (addr && !new_srv.type) { - new_srv.type = 'udp'; new_srv.server = addr; // plain IP → UDP - } else if (addr) { - new_srv.address = addr; // unknown format, keep as-is - } - return new_srv; - }); - } - - // --- Remove rcode servers (unsupported in 1.12+ new format), convert referencing rules to reject --- - let rcode_tags = {}; - if (cfg.dns && cfg.dns.servers) { - let good = []; - for (let srv in cfg.dns.servers) { - if (srv._rcode) rcode_tags[srv.tag] = true; - else push(good, srv); - } - cfg.dns.servers = good; - } - if (cfg.dns && cfg.dns.rules && length(keys(rcode_tags)) > 0) { - cfg.dns.rules = map(cfg.dns.rules || [], function(rule) { - if (rule.server && rcode_tags[rule.server]) { - let r = {}; - for (let k in rule) if (k !== 'server' && k !== 'action') r[k] = rule[k]; - r.action = 'reject'; - return r; - } - return rule; - }); - } - - // --- Remove legacy dns.fakeip.enabled (1.12+ fakeip is configured via type:"fakeip" server) --- - if (cfg.dns && cfg.dns.fakeip) { - let fp = cfg.dns.fakeip; - let new_fp = {}; - for (let k in fp) if (k !== 'enabled') new_fp[k] = fp[k]; - if (length(keys(new_fp)) > 0) cfg.dns.fakeip = new_fp; - else delete cfg.dns['fakeip']; - } - - // --- Fix DNS rules: add action:"route" when server is set --- - if (cfg.dns && cfg.dns.rules) { - cfg.dns.rules = map(cfg.dns.rules || [], function(rule) { - if (rule.server && !rule.action) { - let r = {}; - for (let k in rule) r[k] = rule[k]; - r.action = 'route'; - return r; - } - return rule; - }); - } - - // --- Fix legacy special outbounds (block / dns types) --- - let special = {}; - if (cfg.outbounds) { - let kept = []; - for (let ob in cfg.outbounds) { - if (ob.type === 'block' || ob.type === 'dns') { - special[ob.tag] = ob.type; - } else { - push(kept, ob); - } - } - cfg.outbounds = kept; - } - - // Patch route rules that pointed to removed special outbounds - if (cfg.route && cfg.route.rules && length(keys(special)) > 0) { - cfg.route.rules = map(cfg.route.rules || [], function(rule) { - let sp = rule.outbound && special[rule.outbound]; - if (!sp) return rule; - let r = {}; - for (let k in rule) if (k !== 'outbound') r[k] = rule[k]; - r.action = (sp === 'dns') ? 'hijack-dns' : 'reject'; - return r; - }); - } - - // --- Migrate geoip/geosite database refs to rule_set (removed in sing-box 1.12) --- - let needed_rule_sets = {}; - - let migrate_geo_rule = function(rule) { - let has_geo = rule.geoip || rule.geosite; - if (!has_geo) return rule; - let r = {}; - let new_rs = []; - for (let k in rule) { - if (k === 'geoip') { - for (let n in rule[k]) { - let tag = 'geoip-' + n; - needed_rule_sets[tag] = 'https://cdn.jsdelivr.net/gh/SagerNet/sing-geoip@rule-set/geoip-' + n + '.srs'; - push(new_rs, tag); - } - } else if (k === 'geosite') { - for (let n in rule[k]) { - let tag = 'geosite-' + n; - needed_rule_sets[tag] = 'https://cdn.jsdelivr.net/gh/SagerNet/sing-geosite@rule-set/geosite-' + n + '.srs'; - push(new_rs, tag); - } - } else { - r[k] = rule[k]; - } - } - // Merge new rule_set tags with any existing ones - let existing_rs = type(r.rule_set) === 'array' ? r.rule_set : - (r.rule_set ? [r.rule_set] : []); - for (let t in new_rs) push(existing_rs, t); - r.rule_set = existing_rs; - return r; - }; - - if (cfg.route && cfg.route.rules) - cfg.route.rules = map(cfg.route.rules, migrate_geo_rule); - if (cfg.dns && cfg.dns.rules) - cfg.dns.rules = map(cfg.dns.rules, migrate_geo_rule); - - // download_detour must be DIRECT: at first start rule-sets aren't loaded, so - // routing it via a proxy deadlocks (DNS recursion -> sing-box FATAL). - let pick_dl_detour = function() { - if (cfg.outbounds) { - for (let ob in cfg.outbounds) { - if (ob && ob.type === 'direct' && ob.tag) return ob.tag; - } - } - return 'DIRECT'; - }; - - // Add rule_set download entries for each referenced geo tag - if (length(keys(needed_rule_sets)) > 0) { - if (!cfg.route) cfg.route = {}; - if (!cfg.route.rule_set) cfg.route.rule_set = []; - let existing_tags = {}; - for (let rs in cfg.route.rule_set) existing_tags[rs.tag] = true; - let dl_detour = pick_dl_detour(); - for (let tag in keys(needed_rule_sets)) { - if (!existing_tags[tag]) { - push(cfg.route.rule_set, { - tag: tag, - type: 'remote', - format: 'binary', - url: needed_rule_sets[tag], - download_detour: dl_detour - }); - } - } - } - - // --- Remove deprecated 'outbound' DNS rule items (fatal in sing-box 1.13) --- - // Replacement: set route.default_domain_resolver to the plain IP-based resolver - let dns_resolver_tag = ''; - if (cfg.dns && cfg.dns.servers) { - for (let srv in cfg.dns.servers) { - if ((srv.type === 'udp' || srv.type === 'local') && srv.server && - match(srv.server, /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/)) { - dns_resolver_tag = srv.tag; - break; - } - } - } - if (cfg.dns && cfg.dns.rules) { - let filtered = []; - for (let rule in cfg.dns.rules) { - if (!rule.outbound) push(filtered, rule); - } - cfg.dns.rules = filtered; - } - // Set route.default_domain_resolver (replaces outbound:any DNS routing) - if (dns_resolver_tag) { - if (!cfg.route) cfg.route = {}; - if (!cfg.route.default_domain_resolver) - cfg.route.default_domain_resolver = dns_resolver_tag; - } - - // --- Fix DNS servers with domain-name server field: add domain_resolver --- - // sing-box 1.12+ requires domain_resolver when server= is a hostname (not IP) - if (cfg.dns && cfg.dns.servers && dns_resolver_tag) { - let domain_types = { https: 1, h3: 1, tls: 1, tcp: 1 }; - cfg.dns.servers = map(cfg.dns.servers, function(srv) { - if (!domain_types[srv.type]) return srv; - if (!srv.server || match(srv.server, /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/)) return srv; - if (srv.domain_resolver) return srv; - let r = {}; - for (let k in srv) r[k] = srv[k]; - r.domain_resolver = dns_resolver_tag; - return r; - }); - } - - // --- Fix DNS rules referencing non-existent server tags → action: reject --- - if (cfg.dns && cfg.dns.servers && cfg.dns.rules) { - let valid_servers = {}; - for (let srv in cfg.dns.servers) valid_servers[srv.tag] = true; - cfg.dns.rules = map(cfg.dns.rules, function(rule) { - if (!rule.server || valid_servers[rule.server]) return rule; - let r = {}; - for (let k in rule) if (k !== 'server' && k !== 'action') r[k] = rule[k]; - r.action = 'reject'; - return r; - }); - } - - // --- Fix reject method: sing-box 1.14 rejects "dropped", only "default"/"drop" --- - if (cfg.dns && cfg.dns.rules) { - cfg.dns.rules = map(cfg.dns.rules, function(rule) { - if (rule.action !== 'reject' || !rule.method) return rule; - let m = rule.method; - if (m === 'dropped') m = 'drop'; - if (m !== 'default' && m !== 'drop') { - // unknown value: drop it, sing-box defaults to NXDOMAIN - let r = {}; - for (let k in rule) if (k !== 'method') r[k] = rule[k]; - return r; - } - if (m === rule.method) return rule; - let r = {}; - for (let k in rule) r[k] = rule[k]; - r.method = m; - return r; - }); - } - - // --- Migrate TUN inet4_address/inet6_address -> address array (1.12+), and - // strip legacy inbound fields removed in 1.13 (sniff / sniff_override_destination / - // sniff_timeout / domain_strategy). If any inbound had sniff on, prepend a - // { "action": "sniff" } route rule as the equivalent. --- - let had_sniff = false; - if (cfg.inbounds) { - cfg.inbounds = map(cfg.inbounds, function(ib) { - let r = {}; - let addrs = []; - for (let k in ib) { - if (k === 'inet4_address') { - if (type(ib[k]) === 'array') { for (let a in ib[k]) push(addrs, a); } - else push(addrs, ib[k]); - } else if (k === 'inet6_address') { - if (type(ib[k]) === 'array') { for (let a in ib[k]) push(addrs, a); } - else push(addrs, ib[k]); - } else if (k === 'sniff') { - if (ib[k]) had_sniff = true; - } else if (k === 'sniff_override_destination' || k === 'sniff_timeout' || - k === 'domain_strategy') { - // drop — moved to route.rules actions in 1.13 - } else { - r[k] = ib[k]; - } - } - if (length(addrs) > 0) r.address = addrs; - return r; - }); - } - if (had_sniff) { - if (!cfg.route) cfg.route = {}; - if (!cfg.route.rules) cfg.route.rules = []; - let has_sniff_rule = false; - for (let rl in cfg.route.rules) - if (rl.action === 'sniff') { has_sniff_rule = true; break; } - if (!has_sniff_rule) { - let new_rules = [ { action: 'sniff' } ]; - for (let rl in cfg.route.rules) push(new_rules, rl); - cfg.route.rules = new_rules; - } - } - - // --- sing-box 1.14 requires route.default_domain_resolver; add one if missing, - // preferring dns.final, else the first dns.servers entry with a tag. --- - if (cfg.route && !cfg.route.default_domain_resolver) { - let resolver_tag = ''; - if (cfg.dns && cfg.dns.final) resolver_tag = cfg.dns.final; - else if (cfg.dns && cfg.dns.servers) { - for (let srv in cfg.dns.servers) - if (srv.tag) { resolver_tag = srv.tag; break; } - } - if (resolver_tag) - cfg.route.default_domain_resolver = { server: resolver_tag }; - } - - // --- Remove dangling outbound refs from selectors/urltest, and drop airline - // pseudo-nodes. Two cases: (1) subconverter may reference a missing tag (e.g. - // REJECT); (2) "Traffic:.../Expire:.../quota" pseudo-nodes are real SS/Vmess - // outbounds (kept so the UI can read traffic/expiry) but don't forward — in a - // selector/urltest they win (0ms) and swallow all foreign traffic. --- - let is_pseudo_tag = function(t) { - if (!t) return false; - return match(t, /^Traffic[::]/) || - match(t, /^Expire[::]/) || - match(t, /剩余流量|剩余[::]/) || - match(t, /距离下次重置/) || - match(t, /到期(时间|日期)?[::]/) || - match(t, /官网[::]|网站[::]|套餐[::]?|客服[::]/) || - match(t, /QQ[群]?[::]/) || - match(t, /Telegram|TG群|官方群/) || - match(t, /续费|订阅地址|流量重置/); - }; - if (cfg.outbounds) { - let defined_tags = {}; - for (let ob in cfg.outbounds) defined_tags[ob.tag] = true; - cfg.outbounds = map(cfg.outbounds, function(ob) { - if ((ob.type !== 'selector' && ob.type !== 'urltest' && ob.type !== 'loadbalance') || - !ob.outbounds) return ob; - let valid = []; - for (let t in ob.outbounds) { - if (!defined_tags[t]) continue; - if (is_pseudo_tag(t)) continue; - push(valid, t); - } - if (length(valid) === length(ob.outbounds)) return ob; - let r = {}; - for (let k in ob) r[k] = ob[k]; - r.outbounds = valid; - return r; - }); - } - - // --- Force download_detour=DIRECT on every remote rule_set --- - // subconverter often emits download_detour="auto", but the proxy isn't ready at - // first start -> urltest deadlock ("fetch rule-set: deadline exceeded") -> FATAL. - // The srs URLs already use a CN-reachable mirror, so DIRECT is always correct. - if (cfg.route && cfg.route.rule_set) { - let dl_detour = pick_dl_detour(); - cfg.route.rule_set = map(cfg.route.rule_set, function(rs) { - if (!rs || rs.type !== 'remote') return rs; - let r = {}; - for (let k in rs) r[k] = rs[k]; - r.download_detour = dl_detour; - return r; - }); - } - - return cfg; -} - - -// ---- CLI entry: ucode migrate_singbox.uc ---- -let _path = ARGV[0] || ''; -if (!_path) { print("missing path\n"); exit(1); } -let _raw = readfile(_path); -if (!_raw) { print("read failed\n"); exit(1); } -let _cfg = json(_raw); -if (!_cfg) { print("json parse failed\n"); exit(1); } -let _before = sprintf('%J', _cfg); -_cfg = migrate_singbox(_cfg); -let _after = sprintf('%J', _cfg); -if (_before === _after) { print("nochange\n"); exit(0); } -if (writefile(_path, _after) === null) { print("write failed\n"); exit(1); } -print("migrated\n"); diff --git a/clashoo/files/usr/share/clashoo/lib/normalize_singbox_config.uc b/clashoo/files/usr/share/clashoo/lib/normalize_singbox_config.uc deleted file mode 100644 index cd6a1d3c..00000000 --- a/clashoo/files/usr/share/clashoo/lib/normalize_singbox_config.uc +++ /dev/null @@ -1,939 +0,0 @@ -#!/usr/bin/ucode - -'use strict'; - -import { readfile, writefile, access, popen } from 'fs'; - -let path = ARGV[0] || ''; -let redir_port = +(ARGV[1] || '7891'); -let tproxy_port = +(ARGV[2] || '7982'); -let mixed_port = +(ARGV[3] || '7890'); -let has_tun_device = (ARGV[4] || '1') == '1'; -if (has_tun_device && system('(ip tuntap add mode tun name cotuntest >/dev/null 2>&1 && ip link del cotuntest >/dev/null 2>&1)') != 0) - has_tun_device = false; - -// default 6666 must match fw4.sh CORE_ROUTING_MARK (0x1a0a) -let routing_mark = +(ARGV[5] || '6666'); -let dns_port = +(ARGV[6] || '1053'); -let dash_port = +(ARGV[7] || '9090'); -let dash_secret = ARGV[8] != null ? (ARGV[8] + '') : ''; - -if (!path) { - print("missing path\n"); - exit(1); -} - -let raw = readfile(path); -if (!raw) { - print("read failed\n"); - exit(1); -} - -let cfg = json(raw); -if (!cfg) { - print("json parse failed\n"); - exit(1); -} - -function s_len(s) { - return length(s || ''); -} - -function s_sub(s, start, count) { - if (count == null) - return substr(s || '', start); - return substr(s || '', start, count); -} - -function is_space(ch) { - return ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n'; -} - -function trim_s(s) { - s = (s == null) ? '' : (s + ''); - while (s_len(s) > 0 && is_space(s_sub(s, 0, 1))) - s = s_sub(s, 1); - while (s_len(s) > 0 && is_space(s_sub(s, s_len(s) - 1, 1))) - s = s_sub(s, 0, s_len(s) - 1); - return s; -} - -let default_interface = ''; -let _default_if_pipe = popen("ip -4 route show default 2>/dev/null | awk '{print $5; exit}'"); -if (_default_if_pipe) { - default_interface = trim_s(_default_if_pipe.read('all')); - _default_if_pipe.close(); -} - -function starts_with(s, prefix) { - return s_sub(s || '', 0, s_len(prefix)) == prefix; -} - -function find_char(s, ch) { - for (let i = 0; i < s_len(s); i++) - if (s_sub(s, i, 1) == ch) - return i; - return -1; -} - -function find_last_char(s, ch) { - for (let i = s_len(s) - 1; i >= 0; i--) - if (s_sub(s, i, 1) == ch) - return i; - return -1; -} - -function split_uci_words(line) { - let out = [], cur = '', quote = '', esc = false; - for (let i = 0; i < s_len(line); i++) { - let ch = s_sub(line, i, 1); - if (esc) { - cur += ch; - esc = false; - continue; - } - if (ch == '\\') { - esc = true; - continue; - } - if (quote) { - if (ch == quote) - quote = ''; - else - cur += ch; - continue; - } - if (ch == '"' || ch == "'") { - quote = ch; - continue; - } - if (is_space(ch)) { - if (s_len(cur) > 0) { - push(out, cur); - cur = ''; - } - continue; - } - cur += ch; - } - if (s_len(cur) > 0) - push(out, cur); - return out; -} - -function load_clashoo_uci() { - let uci_path = ARGV[9] || '/etc/config/clashoo'; - let txt = readfile(uci_path) || ''; - let sections = [], cur = null; - for (let line in split(txt, '\n')) { - line = trim_s(line); - if (!s_len(line) || starts_with(line, '#')) - continue; - let words = split_uci_words(line); - if (!length(words)) - continue; - if (words[0] == 'config') { - cur = { type: words[1] || '', name: words[2] || '', options: {}, lists: {} }; - push(sections, cur); - continue; - } - if (!cur || length(words) < 3) - continue; - if (words[0] == 'option') - cur.options[words[1]] = words[2]; - else if (words[0] == 'list') { - if (cur.lists[words[1]] == null) - cur.lists[words[1]] = []; - push(cur.lists[words[1]], words[2]); - } - } - return sections; -} - -let clashoo_uci = load_clashoo_uci(); - -function uci_config_section() { - for (let s in clashoo_uci) - if (s.type == 'clashoo' && (s.name == 'config' || s.name == '')) - return s; - return {}; -} - -let uci_cfg = uci_config_section(); - -function uci_opt(key, def) { - if (uci_cfg.options && uci_cfg.options[key] != null) - return uci_cfg.options[key]; - return def; -} - -function uci_list(key) { - if (uci_cfg.lists && uci_cfg.lists[key] != null) - return uci_cfg.lists[key]; - if (uci_cfg.options && uci_cfg.options[key] != null) - return [ uci_cfg.options[key] ]; - return []; -} - -function uci_sections(type_name) { - let out = []; - for (let s in clashoo_uci) - if (s.type == type_name) - push(out, s); - return out; -} - -function opt_bool(v, def) { - if (v == null || v == '') - return def; - return v === true || v == '1' || v == 'true' || v == 'yes' || v == 'on'; -} - -function normalize_dns_uri(address, protocol, port) { - address = trim_s(address || ''); - protocol = trim_s(protocol || ''); - port = trim_s(port || ''); - if (!s_len(address)) - return ''; - if (find_char(address, ':') >= 0 && find_char(address, '/') >= 0) - return address; - if (protocol == 'none') - protocol = ''; - if (protocol == 'dot') - protocol = 'tls://'; - else if (protocol == 'doh') - protocol = 'https://'; - else if (protocol == 'doq') - protocol = 'quic://'; - if (s_len(protocol) && !starts_with(protocol, 'udp://') && !starts_with(protocol, 'tcp://') && - !starts_with(protocol, 'tls://') && !starts_with(protocol, 'https://') && !starts_with(protocol, 'quic://')) - protocol += '://'; - return protocol + address + (s_len(port) ? ':' + port : ''); -} - -function direct_outbound_tag() { - for (let ob in (cfg.outbounds || [])) - if (ob && ob.type == 'direct' && s_len(ob.tag || '')) - return ob.tag; - return 'DIRECT'; -} - -function dns_server_obj(uri, tag, fallback_type) { - uri = normalize_dns_uri(uri || '', '', ''); - if (!s_len(uri)) - return null; - let scheme = fallback_type || 'udp'; - let rest = uri; - let p = -1; - for (let i = 0; i < s_len(uri) - 2; i++) { - if (s_sub(uri, i, 3) == '://') { - p = i; - break; - } - } - if (p >= 0) { - scheme = s_sub(uri, 0, p); - rest = s_sub(uri, p + 3); - } - if (scheme == 'dot') - scheme = 'tls'; - else if (scheme == 'doh') - scheme = 'https'; - else if (scheme == 'doq') - scheme = 'quic'; - - let path = ''; - let slash = find_char(rest, '/'); - if (slash >= 0) { - path = s_sub(rest, slash); - rest = s_sub(rest, 0, slash); - } - - let server = rest, server_port = null; - let colon = find_last_char(rest, ':'); - if (colon > 0 && find_char(rest, ']') < 0) { - server = s_sub(rest, 0, colon); - let n = +(s_sub(rest, colon + 1)); - if (n === n) - server_port = n; - } - - let obj = { type: scheme, tag: tag, server: server }; - if (server_port != null) - obj.server_port = server_port; - if (path && (scheme == 'https' || scheme == 'h3')) - obj.path = path; - if ((scheme == 'https' || scheme == 'tls' || scheme == 'quic') && tag != 'dns_resolver') - obj.domain_resolver = 'dns_resolver'; - /* sing-box 1.12+ DNS servers detour to the proxy by default, so a server - * resolving its own domain via dns_resolver loops -> "deadline exceeded". - * Force direct/resolver servers to DIRECT; only dns_proxy may use the proxy. */ - if (tag == 'dns_resolver' || tag == 'dns_direct' || tag == 'dns_foreign') - obj.detour = direct_outbound_tag(); - return obj; -} - -function dns_servers_by_role(role) { - let out = []; - for (let s in uci_sections('dnsservers')) { - if (!opt_bool(s.options.enabled, true)) - continue; - if ((s.options.ser_type || 'nameserver') != role) - continue; - let uri = normalize_dns_uri(s.options.ser_address || '', s.options.protocol || '', s.options.ser_port || ''); - if (s_len(uri)) - push(out, uri); - } - return out; -} - -function first_or(arr, fallback) { - return length(arr) ? arr[0] : fallback; -} - -function local_rule_set_path(tag) { - if (!s_len(tag)) - return ''; - let path = '/usr/share/clashoo/ruleset/' + tag + '.srs'; - if (access(path, 'r')) - return path; - if (tag == 'geolocation-cn' || tag == 'cn') { - path = '/usr/share/clashoo/ruleset/geosite-cn.srs'; - if (access(path, 'r')) - return path; - } - return ''; -} - -function keep_remote_rule_set(rs) { - return false; -} - -function normalize_rule_set_url(url) { - url = url || ''; - url = replace(url, /^https:\/\/gh-proxy\.com\//, ''); - let m = match(url, /^https:\/\/raw\.githubusercontent\.com\/([^\/]+)\/([^\/]+)\/([^\/]+)\/(.+)$/); - if (m) - return 'https://cdn.jsdelivr.net/gh/' + m[1] + '/' + m[2] + '@' + m[3] + '/' + m[4]; - m = match(url, /^https:\/\/github\.com\/([^\/]+)\/([^\/]+)\/raw\/refs\/heads\/([^\/]+)\/(.+)$/); - if (m) - return 'https://cdn.jsdelivr.net/gh/' + m[1] + '/' + m[2] + '@' + m[3] + '/' + m[4]; - return url; -} - -function has_route_rule_set(tag) { - for (let rs in (cfg.route || {}).rule_set || []) - if (rs && rs.tag == tag) - return true; - return false; -} - -function add_remote_rule_set(tag, url) { - cfg.route = cfg.route || {}; - cfg.route.rule_set = cfg.route.rule_set || []; - if (has_route_rule_set(tag)) - return; - push(cfg.route.rule_set, { - tag: tag, - type: 'remote', - format: 'binary', - url: url - }); -} - -function array_has_value(arr, val) { - if (type(arr) != 'array') - return false; - for (let item in arr) - if (item == val) - return true; - return false; -} - -let dnsmasq_uid = null; -let _dnsmasq_uid_pipe = popen("id -u dnsmasq 2>/dev/null"); -if (_dnsmasq_uid_pipe) { - let value = trim_s(_dnsmasq_uid_pipe.read('all')); - _dnsmasq_uid_pipe.close(); - if (match(value, /^[0-9]+$/)) - dnsmasq_uid = +value; -} - -function ensure_tun_dnsmasq_exclude(ib) { - if (dnsmasq_uid == null) - return; - let excludes = ib.exclude_uid; - if (type(excludes) != 'array') - excludes = excludes != null ? [ excludes ] : []; - if (!array_has_value(excludes, dnsmasq_uid)) - push(excludes, dnsmasq_uid); - ib.exclude_uid = excludes; -} - -function ensure_tun_cn_exclude(ib) { - let excludes = ib.route_exclude_address_set; - if (type(excludes) != 'array') - excludes = excludes ? [ excludes ] : []; - if (!array_has_value(excludes, 'cn-ip')) - push(excludes, 'cn-ip'); - ib.route_exclude_address_set = excludes; -} - -function prune_tun_cn_exclude_if_missing() { - if (has_route_rule_set('cn-ip')) - return; - for (let ib in cfg.inbounds || []) { - if (!ib || ib.type != 'tun') - continue; - let excludes = []; - for (let item in ib.route_exclude_address_set || []) - if (item != 'cn-ip') - push(excludes, item); - if (length(excludes)) - ib.route_exclude_address_set = excludes; - else - delete ib.route_exclude_address_set; - } -} - -function matcher_rule(matcher, server_tag) { - let r = { server: server_tag }; - if (starts_with(matcher, 'geosite:')) - r.rule_set = s_sub(matcher, 8); - else if (starts_with(matcher, 'rule_set:')) - r.rule_set = s_sub(matcher, 9); - else if (starts_with(matcher, 'domain:')) - r.domain = s_sub(matcher, 7); - else if (starts_with(matcher, 'domain-suffix:')) - r.domain_suffix = s_sub(matcher, 14); - else - r.domain_suffix = matcher; - return r; -} - -function apply_dns_from_uci() { - cfg.dns = cfg.dns || {}; - /* strip mihomo-style DNS fields (enable/ipv6/listen/fake-ip-filter/nameserver...) - * that leak in from YAML conversion; sing-box rejects them (Fatal). */ - let _mihomo_dns_fields = ['enable', 'ipv6', 'listen', 'fake-ip-filter', 'fake-ip-range', - 'enhanced-mode', 'nameserver', 'fallback', 'fallback-filter', - 'use-hosts', 'default-nameserver', 'proxy-server-nameserver', - 'direct-nameserver', 'nameserver-policy']; - for (let _i = 0; _i < length(_mihomo_dns_fields); _i++) - delete cfg.dns[_mihomo_dns_fields[_i]]; - /* strip mihomo-style experimental fields */ - let _mihomo_exp = ['sniff-tls-sni', 'sniff', 'sniffer']; - for (let _me = 0; _me < length(_mihomo_exp); _me++) - if (cfg.experimental && cfg.experimental[_mihomo_exp[_me]] != null) - delete cfg.experimental[_mihomo_exp[_me]]; - /* strip non-sing-box root-level fields */ - let _mihomo_root = ['clash-for-android', 'cfw-bypass', 'sniffer', 'profile', - 'geodata-mode', 'geodata-loader', 'geox-url', 'geo-auto-update', - 'geo-update-interval', 'tun', 'ipv6', 'interface-name', - 'port', 'socks-port', 'mixed-port', 'redir-port', 'tproxy-port', 'mode', 'allow-lan', 'log-level', 'external-controller', 'secret', 'bind-address', 'routing-mark', 'find-process-mode', 'tcp-concurrent', 'unified-delay', - 'keep-alive-interval', 'keep-alive-idle', 'disable-keep-alive']; - /* strip subconverter note fields and non-standard keys */ - let _subconv_fields = ['_note', '_sub_url', 'hosts', 'script', 'enable', 'fake-ip-filter', 'fake-ip-range']; - for (let _sf = 0; _sf < length(_subconv_fields); _sf++) - if (cfg[_subconv_fields[_sf]] != null) - delete cfg[_subconv_fields[_sf]]; - for (let _mr = 0; _mr < length(_mihomo_root); _mr++) - if (cfg[_mihomo_root[_mr]] != null) - delete cfg[_mihomo_root[_mr]]; - let bootstrap = uci_list('default_nameserver'); - if (!length(bootstrap)) - bootstrap = uci_list('defaul_nameserver'); - let resolver_uri = first_or(bootstrap, '223.5.5.5'); - let direct_uri = first_or(dns_servers_by_role('direct-nameserver'), first_or(dns_servers_by_role('proxy-server-nameserver'), 'https://doh.pub/dns-query')); - let proxy_uri = first_or(dns_servers_by_role('nameserver'), first_or(dns_servers_by_role('fallback'), 'https://1.1.1.1/dns-query')); - - let servers = []; - push(servers, dns_server_obj(resolver_uri, 'dns_resolver', 'udp')); - push(servers, dns_server_obj(direct_uri, 'dns_direct', 'udp')); - push(servers, dns_server_obj(proxy_uri, 'dns_proxy', 'tls')); - - let enhanced = uci_opt('enhanced_mode', 'fake-ip'); - if (enhanced == 'fake-ip') { - let fake_range = uci_opt('fake_ip_range', '198.18.0.1/16'); - push(servers, { - type: 'fakeip', - tag: 'dns_fakeip', - inet4_range: fake_range || '198.18.0.1/16', - inet6_range: 'fc00::/18' - }); - } - - let rules = []; - push(servers, { type: 'udp', tag: 'dns_foreign', server: '1.1.1.1' }); - if (enhanced == 'fake-ip') { - push(rules, { - rule_set: 'geolocation-!cn', - server: 'dns_fakeip' - }); - } - - let clean_servers = []; - for (let s in servers) - if (s) - push(clean_servers, s); - cfg.dns.servers = clean_servers; - cfg.dns.rules = rules; - - /* Keep bootstrap direct; proxy unmatched queries in strict mode. */ - if (opt_bool(uci_opt('dns_leak_protect', '0'), false)) { - cfg.dns.final = 'dns_proxy'; - if (!opt_bool(uci_opt('ipv6_proxy', '0'), false)) - unshift(cfg.dns.rules, { query_type: ['AAAA'], action: 'reject', method: 'drop' }); - } else - cfg.dns.final = 'dns_direct'; - - let ecs = trim_s(uci_opt('dns_ecs', '')); - if (s_len(ecs)) - cfg.dns.client_subnet = ecs; - else - delete cfg.dns.client_subnet; - - if (opt_bool(uci_opt('singbox_independent_cache', '0'), false)) - cfg.dns.independent_cache = true; - else - delete cfg.dns.independent_cache; - - /* sing-box 1.14 requires this (else Fatal); dns_resolver is DIRECT so first-start node lookups use direct DNS */ - cfg.route.default_domain_resolver = 'dns_resolver'; - } - -let inbounds = cfg.inbounds || []; -let normalized = []; -let has_redirect = false; -let has_tproxy = false; -let has_mixed = false; -let has_tun = false; -let has_dns_in = false; -let wants_tun = has_tun_device && (uci_opt('tcp_mode', '') == 'tun' || uci_opt('udp_mode', '') == 'tun'); -let tun_stack = uci_opt('stack', 'mixed') || 'mixed'; - -if (wants_tun) { - add_remote_rule_set('cn-ip', - 'https://github.com/MetaCubeX/meta-rules-dat/raw/refs/heads/sing/geo/geoip/cn.srs'); -} - -for (let ib in inbounds) { - if (!ib) - continue; - - if (ib.type == 'tun' || ib.tag == 'tun-in') { - /* Keep tun inbound only when the selected proxy mode actually uses TUN. */ - if (wants_tun && !has_tun) { - ib.type = 'tun'; - ib.tag = ib.tag || 'tun-in'; - if (!ib.address) - ib.address = [ '172.19.0.1/30', 'fdfe:dcba:9876::1/126' ]; - ib.auto_route = true; - ib.auto_redirect = true; - ib.auto_redirect_input_mark = '0x2023'; - ib.auto_redirect_output_mark = '0x2024'; - ib.strict_route = true; - ib.stack = tun_stack; - ensure_tun_dnsmasq_exclude(ib); - ensure_tun_cn_exclude(ib); - push(normalized, ib); - has_tun = true; - } - continue; - } - - if (ib.tag == 'redirect-in' || ib.type == 'redirect') { - if (has_redirect) - continue; - ib.type = 'redirect'; - ib.tag = 'redirect-in'; - ib.listen = '0.0.0.0'; - ib.listen_port = redir_port; - has_redirect = true; - push(normalized, ib); - continue; - } - - if (ib.tag == 'tproxy-in' || ib.type == 'tproxy') { - if (has_tproxy) - continue; - ib.type = 'tproxy'; - ib.tag = 'tproxy-in'; - ib.listen = '0.0.0.0'; - ib.listen_port = tproxy_port; - ib.network = 'udp'; - has_tproxy = true; - push(normalized, ib); - continue; - } - - if (ib.tag == 'mixed-in' || ib.type == 'mixed') { - if (has_mixed) - continue; - ib.type = 'mixed'; - ib.tag = 'mixed-in'; - ib.listen = '0.0.0.0'; - ib.listen_port = mixed_port; - has_mixed = true; - push(normalized, ib); - continue; - } - - if (ib.tag == 'dns-in') { - if (has_dns_in) - continue; - ib.type = 'direct'; - ib.tag = 'dns-in'; - ib.listen = '0.0.0.0'; - ib.listen_port = dns_port; - has_dns_in = true; - push(normalized, ib); - continue; - } - - push(normalized, ib); -} - -if (!has_redirect) { - push(normalized, { - type: 'redirect', - tag: 'redirect-in', - listen: '0.0.0.0', - listen_port: redir_port - }); -} - -if (!has_mixed) { - push(normalized, { - type: 'mixed', - tag: 'mixed-in', - listen: '0.0.0.0', - listen_port: mixed_port - }); -} - -if (wants_tun && !has_tun) { - let tun_ib = { - type: 'tun', - tag: 'tun-in', - address: [ '172.19.0.1/30', 'fdfe:dcba:9876::1/126' ], - auto_route: true, - auto_redirect: true, - auto_redirect_input_mark: '0x2023', - auto_redirect_output_mark: '0x2024', - strict_route: true, - stack: tun_stack - }; - ensure_tun_dnsmasq_exclude(tun_ib); - ensure_tun_cn_exclude(tun_ib); - push(normalized, tun_ib); -} - -if (!has_tproxy) { - push(normalized, { - type: 'tproxy', - tag: 'tproxy-in', - listen: '0.0.0.0', - listen_port: tproxy_port, - network: 'udp' - }); -} - -if (!has_dns_in) { - push(normalized, { - type: 'direct', - tag: 'dns-in', - listen: '0.0.0.0', - listen_port: dns_port - }); -} - -cfg.inbounds = normalized; - -for (let ob in (cfg.outbounds || [])) { - if (!ob || type(ob) != 'object') - continue; - - let t = ob.type || ''; - if (t == 'selector' || t == 'urltest' || t == 'fallback' || t == 'load_balance' || t == 'dns' || t == 'block') - continue; - - /* Clash SS obfs is plugin=obfs + plugin-opts object; sing-box wants - * plugin=obfs-local + "obfs=http;obfs-host=..." string. */ - if (ob.plugin == 'obfs') - ob.plugin = 'obfs-local'; - if (ob.plugin_opts != null && type(ob.plugin_opts) == 'object') { - let _parts = []; - let _map = { mode: 'obfs', host: 'obfs-host', uri: 'obfs-uri' }; - for (let _k in ob.plugin_opts) { - let _v = ob.plugin_opts[_k]; - if (type(_v) == 'object' || type(_v) == 'array') continue; - push(_parts, (_map[_k] || _k) + '=' + _v); - } - ob.plugin_opts = join(';', _parts); - } - if (ob.plugin != null && ob.plugin != 'obfs-local' && ob.plugin != 'v2ray-plugin' && ob.plugin != 'shadow-tls') { - delete ob.plugin; - delete ob.plugin_opts; - } - - /* Force ipv4_only on DIRECT outbound: most devices are IPv4-only egress, - * a CN domain resolving AAAA stalls on "network is unreachable". */ - if (ob.type == 'direct' && ob.tag == 'DIRECT') - ob.domain_resolver = { server: 'dns_resolver', strategy: 'ipv4_only' }; - - if (wants_tun) { - delete ob.routing_mark; - if (ob.type == 'direct' && ob.tag == 'DIRECT' && default_interface) - ob.bind_interface = ob.bind_interface || default_interface; - } else if (ob.routing_mark == null) - ob.routing_mark = routing_mark; - } - -/* Drop airline pseudo-nodes (Traffic:/Expire:/quota/官网/QQ/etc.) from selector/urltest lists. - * They're real SS/Vmess (kept so the UI reads traffic/expiry) but don't forward; in a - * selector/urltest they win and swallow foreign traffic ("CN ok, foreign out"). */ -let _is_pseudo_tag = function(t) { - if (!t) return false; - return match(t, /^Traffic[::]/) || match(t, /^Expire[::]/) || - match(t, /剩余流量|剩余[::]/) || match(t, /距离下次重置/) || - match(t, /到期(时间|日期)?[::]/) || - match(t, /官网[::]|网站[::]|套餐[::]?|客服[::]/) || - match(t, /QQ[群]?[::]/) || match(t, /Telegram|TG群|官方群/) || - match(t, /续费|订阅地址|流量重置/); -}; -for (let ob in (cfg.outbounds || [])) { - if (!ob || type(ob) != 'object') continue; - let t = ob.type || ''; - if (t != 'selector' && t != 'urltest' && t != 'fallback' && t != 'load_balance') continue; - if (type(ob.outbounds) != 'array') continue; - let cleaned = []; - for (let tag in ob.outbounds) if (!_is_pseudo_tag(tag)) push(cleaned, tag); - ob.outbounds = cleaned; -} - -cfg.route = cfg.route || {}; -cfg.route.rules = cfg.route.rules || []; -let has_dns_hijack = false; -for (let rule in cfg.route.rules) { - if (!rule || type(rule) != 'object') - continue; - if (rule.inbound == 'dns-in' && rule.action == 'hijack-dns') { - has_dns_hijack = true; - break; - } -} -if (!has_dns_hijack) { - unshift(cfg.route.rules, { - inbound: 'dns-in', - action: 'hijack-dns' - }); -} -cfg.route.auto_detect_interface = true; -apply_dns_from_uci(); - -/* DNS leak protection: reject DoT/DoQ (853) to force DNS through the core; after hijack-dns so the dns inbound survives */ -if (opt_bool(uci_opt('dns_leak_protect', '0'), false)) { - let _has_853 = false; - for (let _r in cfg.route.rules) { - if (_r && type(_r) == 'object' && _r.action == 'reject' && _r.port) { - if (type(_r.port) == 'array') { - for (let _p in _r.port) if (_p == 853) { _has_853 = true; break; } - } else if (_r.port == 853) { - _has_853 = true; - } - } - if (_has_853) break; - } - if (!_has_853) { - let _new_rules = []; - let _inserted = false; - for (let _ri = 0; _ri < length(cfg.route.rules); _ri++) { - push(_new_rules, cfg.route.rules[_ri]); - if (!_inserted && cfg.route.rules[_ri] && cfg.route.rules[_ri].action == 'hijack-dns') { - push(_new_rules, { port: [853], action: 'reject' }); - _inserted = true; - } - } - if (!_inserted) unshift(_new_rules, { port: [853], action: 'reject' }); - cfg.route.rules = _new_rules; - } -} - -/* ===== Custom routing rules (UCI: config addtype) -> route.rules, mirrors mihomo iprules.sh ===== - * User "domain/IP -> direct/proxy" rules from LuCI, inserted after the DNS funnel - * (hijack-dns / 853-reject) and before other rules, so overrides win without bypassing it. */ -let _proxy_outbound_tag = function() { - for (let ob in (cfg.outbounds || [])) - if (ob && ob.tag == '🚀 节点选择' && (ob.type == 'selector' || ob.type == 'urltest')) - return ob.tag; - for (let ob in (cfg.outbounds || [])) - if (ob && ob.type == 'selector' && s_len(ob.tag || '') && !_is_pseudo_tag(ob.tag)) - return ob.tag; - return direct_outbound_tag(); -}; -let _load_addtype_rules = function() { - let out = []; - let dtag = direct_outbound_tag(); - let ptag = null; - for (let s in uci_sections('addtype')) { - let o = s.options || {}; - let addr = trim_s(o.ipaaddr || ''); - let rtype = trim_s(o.type || ''); - let pg = trim_s(o.pgroup || ''); - if (!s_len(addr) || !s_len(rtype) || !s_len(pg)) - continue; - let r = {}; - if (rtype == 'DOMAIN') - r.domain = addr; - else if (rtype == 'DOMAIN-SUFFIX') - r.domain_suffix = addr; - else if (rtype == 'DOMAIN-KEYWORD') - r.domain_keyword = addr; - else if (rtype == 'IP-CIDR' || rtype == 'IP-CIDR6') - r.ip_cidr = addr; - else - continue; - if (pg == 'DIRECT') - r.outbound = dtag; - else { - if (ptag == null) - ptag = _proxy_outbound_tag(); - r.outbound = ptag; - } - push(out, r); - } - return out; -}; -let _addtype_rules = _load_addtype_rules(); -if (length(_addtype_rules)) { - let _nr = []; - let _ins = false; - for (let _i = 0; _i < length(cfg.route.rules); _i++) { - let _ru = cfg.route.rules[_i]; - let _dns_front = _ru && type(_ru) == 'object' && - (_ru.action == 'hijack-dns' || (_ru.action == 'reject' && _ru.port)); - if (!_ins && !_dns_front) { - for (let _cr in _addtype_rules) - push(_nr, _cr); - _ins = true; - } - push(_nr, _ru); - } - if (!_ins) - for (let _cr in _addtype_rules) - push(_nr, _cr); - cfg.route.rules = _nr; -} - -if (uci_opt('enhanced_mode', 'fake-ip') == 'fake-ip') { - add_remote_rule_set('geolocation-!cn', - 'https://github.com/MetaCubeX/meta-rules-dat/raw/refs/heads/sing/geo/geosite/geolocation-!cn.srs'); -} - -/* Local .srs -> local; remaining remote rule_sets must keep/get a download_detour. - * CN first-start deadlock: no srs -> fetch rules -> via auto-select -> urltest dials - * the proxy -> resolves its domain -> pulled into an unloaded rule_set by DNS rules -> deadline. - * The srs URLs use a CN-reachable mirror, so download_detour - * must be DIRECT (real direct-outbound tag if any, else 'DIRECT'). */ -let _pick_dl_detour = function() { - if (cfg.outbounds) { - for (let ob in cfg.outbounds) { - if (ob && ob.type == 'direct' && ob.tag) return ob.tag; - } - } - return 'DIRECT'; -}; -let _dl_detour = _pick_dl_detour(); -for (let rs in (cfg.route || {}).rule_set || []) { - if (!rs) continue; - if (rs.type != 'remote') { delete rs.download_detour; continue; } - let path = local_rule_set_path(rs.tag || ''); - if (rs.tag && access(path, 'r')) { - delete rs.url; delete rs.download_detour; rs.type = 'local'; rs.path = path; - continue; - } - if (keep_remote_rule_set(rs) && rs.url) { - rs.url = normalize_rule_set_url(rs.url); - rs.download_detour = _dl_detour; - continue; - } - /* No local cache -> skip this remote rule_set so a failed download doesn't block start. - * Rule-sets are fetched to /usr/share/clashoo/ruleset/ once proxied. */ - continue; - -} -/* filter out remote rule_sets with no local cache */ -let _clean_rs = []; -for (let _rsi = 0; _rsi < length(cfg.route.rule_set); _rsi++) { - let _rs = cfg.route.rule_set[_rsi]; - if (!_rs) continue; - if (_rs.type == 'remote' && _rs.url != null) { - let _local_path = local_rule_set_path(_rs.tag || ''); - if (!_rs.tag || !access(_local_path, 'r')) - if (keep_remote_rule_set(_rs) && _rs.url) { - _rs.url = normalize_rule_set_url(_rs.url); - _rs.download_detour = _dl_detour; - push(_clean_rs, _rs); - continue; - } else { - continue; /* no local cache -> drop from final list */ - } - /* has local cache -> convert to local */ - delete _rs.url; delete _rs.download_detour; _rs.type = 'local'; _rs.path = _local_path; - } - push(_clean_rs, _rs); -} -cfg.route.rule_set = _clean_rs; -prune_tun_cn_exclude_if_missing(); - - /* drop DNS/route rules referencing a removed rule_set, else sing-box FATAL: rule-set not found */ - let _existing_tags = {}; - for (let _rs in cfg.route.rule_set || []) if (_rs && _rs.tag) _existing_tags[_rs.tag] = true; - let _rule_has_ref = function(_r) { - if (!_r || type(_r) != 'object') return false; - if (_r.rule_set) { - if (type(_r.rule_set) == 'array') { for (let _t in _r.rule_set) if (!_existing_tags[_t]) return false; } - else if (!_existing_tags[_r.rule_set]) return false; - } - return true; - }; - /* clean dns.rules */ - if (cfg.dns && type(cfg.dns.rules) == 'array') { - let _clean_dns_rules = []; - for (let _dr in cfg.dns.rules) if (_rule_has_ref(_dr)) push(_clean_dns_rules, _dr); - cfg.dns.rules = _clean_dns_rules; - } - /* clean route.rules */ - if (cfg.route && type(cfg.route.rules) == 'array') { - let _clean_rt_rules = []; - for (let _rr in cfg.route.rules) if (_rule_has_ref(_rr)) push(_clean_rt_rules, _rr); - cfg.route.rules = _clean_rt_rules; - } - cfg.experimental = cfg.experimental || {}; -cfg.experimental.clash_api = cfg.experimental.clash_api || {}; -cfg.experimental.clash_api.external_controller = '0.0.0.0:' + dash_port; -cfg.experimental.clash_api.external_ui = '/etc/clashoo/dashboard'; -cfg.experimental.clash_api.secret = dash_secret; - -cfg.experimental.cache_file = { - enabled: true, - store_fakeip: true -}; - -/* OpenWrt already owns system time sync. Keep sing-box NTP disabled by - * default to avoid noisy IPv6 UDP/123 failures on IPv4-only routers. */ -cfg.ntp = cfg.ntp || {}; -cfg.ntp.enabled = false; - -cfg.log = cfg.log || {}; -cfg.log.output = '/var/log/clashoo/core.log'; -if (!cfg.log.level) - cfg.log.level = 'info'; - -if (writefile(path, sprintf('%J', cfg)) === null) { - print("write failed\n"); - exit(1); -} - -print("normalized\n"); diff --git a/clashoo/files/usr/share/clashoo/lib/templates/default.json b/clashoo/files/usr/share/clashoo/lib/templates/default.json deleted file mode 100644 index 84f1ee22..00000000 --- a/clashoo/files/usr/share/clashoo/lib/templates/default.json +++ /dev/null @@ -1,138 +0,0 @@ -{ - "log": { - "level": "info", - "timestamp": true - }, - "dns": { - "servers": [ - { "type": "tcp", "tag": "dns_proxy", "server": "1.1.1.1", "domain_resolver": "dns_resolver" }, - { "type": "https", "tag": "dns_direct", "server": "dns.alidns.com", "domain_resolver": "dns_resolver" }, - { "type": "udp", "tag": "dns_resolver", "server": "223.5.5.5" }, - { "type": "fakeip", "tag": "dns_fakeip", "inet4_range": "198.18.0.0/15", "inet6_range": "fc00::/18" } - ], - "rules": [ - { "rule_set": "geolocation-!cn", "query_type": ["A", "AAAA", "CNAME"], "server": "dns_fakeip" }, - { "query_type": ["A", "AAAA", "CNAME"], "invert": true, "action": "reject" } - ], - "final": "dns_direct" - }, - "ntp": { - "enabled": false, - "server": "time.apple.com", - "server_port": 123, - "interval": "30m" - }, - "inbounds": [ - { "type": "mixed", "tag": "mixed-in", "listen": "0.0.0.0", "listen_port": 2080 }, - { "type": "tun", "tag": "tun-in", "address": ["172.19.0.1/30"], "auto_route": true, "auto_redirect": true, "strict_route": true, "stack": "mixed", "route_exclude_address_set": ["cn-ip"] } - ], - "outbounds": [ - { - "type": "selector", "tag": "🚀 节点选择", - "outbounds": ["🌍 全部节点","♻️ 自动选择","♻️ 香港自动","♻️ 日本自动","♻️ 美国自动","♻️ 新加坡自动","♻️ 集合自动","🇭🇰 香港节点","🇯🇵 日本节点","🇺🇲 美国节点","🇸🇬 新加坡节点","🇺🇳 集合节点","DIRECT"], - "default": "🌍 全部节点" - }, - { "type": "selector", "tag": "▶️ YouTube", "outbounds": ["🚀 节点选择","♻️ 香港自动","♻️ 日本自动","♻️ 美国自动","♻️ 新加坡自动","♻️ 集合自动","♻️ 自动选择","🇭🇰 香港节点","🇯🇵 日本节点","🇺🇲 美国节点","🇸🇬 新加坡节点","🇺🇳 集合节点","🌍 全部节点","DIRECT"] }, - { "type": "selector", "tag": "🔍 Google", "outbounds": ["🚀 节点选择","♻️ 香港自动","♻️ 日本自动","♻️ 美国自动","♻️ 新加坡自动","♻️ 集合自动","♻️ 自动选择","🇭🇰 香港节点","🇯🇵 日本节点","🇺🇲 美国节点","🇸🇬 新加坡节点","🇺🇳 集合节点","🌍 全部节点","DIRECT"] }, - { "type": "selector", "tag": "🔮 OpenAI", "outbounds": ["🚀 节点选择","♻️ 香港自动","♻️ 日本自动","♻️ 美国自动","♻️ 新加坡自动","♻️ 集合自动","♻️ 自动选择","🇭🇰 香港节点","🇯🇵 日本节点","🇺🇲 美国节点","🇸🇬 新加坡节点","🇺🇳 集合节点","🌍 全部节点","DIRECT"] }, - { "type": "selector", "tag": "🧠 Claude", "outbounds": ["🚀 节点选择","♻️ 香港自动","♻️ 日本自动","♻️ 美国自动","♻️ 新加坡自动","♻️ 集合自动","♻️ 自动选择","🇭🇰 香港节点","🇯🇵 日本节点","🇺🇲 美国节点","🇸🇬 新加坡节点","🇺🇳 集合节点","🌍 全部节点","DIRECT"] }, - { "type": "selector", "tag": "🤖 Gemini", "outbounds": ["🚀 节点选择","♻️ 香港自动","♻️ 日本自动","♻️ 美国自动","♻️ 新加坡自动","♻️ 集合自动","♻️ 自动选择","🇭🇰 香港节点","🇯🇵 日本节点","🇺🇲 美国节点","🇸🇬 新加坡节点","🇺🇳 集合节点","🌍 全部节点","DIRECT"] }, - { "type": "selector", "tag": "🐦 Twitter", "outbounds": ["🚀 节点选择","♻️ 香港自动","♻️ 日本自动","♻️ 美国自动","♻️ 新加坡自动","♻️ 集合自动","♻️ 自动选择","🇭🇰 香港节点","🇯🇵 日本节点","🇺🇲 美国节点","🇸🇬 新加坡节点","🇺🇳 集合节点","🌍 全部节点","DIRECT"] }, - { "type": "selector", "tag": "📦 GitHub", "outbounds": ["🚀 节点选择","♻️ 香港自动","♻️ 日本自动","♻️ 美国自动","♻️ 新加坡自动","♻️ 集合自动","♻️ 自动选择","🇭🇰 香港节点","🇯🇵 日本节点","🇺🇲 美国节点","🇸🇬 新加坡节点","🇺🇳 集合节点","🌍 全部节点","DIRECT"] }, - { "type": "selector", "tag": "Ⓜ️ Microsoft", "outbounds": ["🚀 节点选择","♻️ 香港自动","♻️ 日本自动","♻️ 美国自动","♻️ 新加坡自动","♻️ 集合自动","♻️ 自动选择","🇭🇰 香港节点","🇯🇵 日本节点","🇺🇲 美国节点","🇸🇬 新加坡节点","🇺🇳 集合节点","🌍 全部节点","DIRECT"] }, - { "type": "selector", "tag": "🎵 TikTok", "outbounds": ["🚀 节点选择","♻️ 香港自动","♻️ 日本自动","♻️ 美国自动","♻️ 新加坡自动","♻️ 集合自动","♻️ 自动选择","🇭🇰 香港节点","🇯🇵 日本节点","🇺🇲 美国节点","🇸🇬 新加坡节点","🇺🇳 集合节点","🌍 全部节点","DIRECT"] }, - { "type": "selector", "tag": "📺 Netflix", "outbounds": ["🚀 节点选择","♻️ 香港自动","♻️ 日本自动","♻️ 美国自动","♻️ 新加坡自动","♻️ 集合自动","♻️ 自动选择","🇭🇰 香港节点","🇯🇵 日本节点","🇺🇲 美国节点","🇸🇬 新加坡节点","🇺🇳 集合节点","🌍 全部节点","DIRECT"] }, - { "type": "selector", "tag": "🎬 流媒体", "outbounds": ["🚀 节点选择","♻️ 香港自动","♻️ 日本自动","♻️ 美国自动","♻️ 新加坡自动","♻️ 集合自动","♻️ 自动选择","🇭🇰 香港节点","🇯🇵 日本节点","🇺🇲 美国节点","🇸🇬 新加坡节点","🇺🇳 集合节点","🌍 全部节点","DIRECT"] }, - { "type": "selector", "tag": "💳 PayPal", "outbounds": ["🚀 节点选择","♻️ 香港自动","♻️ 日本自动","♻️ 美国自动","♻️ 新加坡自动","♻️ 集合自动","♻️ 自动选择","🇭🇰 香港节点","🇯🇵 日本节点","🇺🇲 美国节点","🇸🇬 新加坡节点","🇺🇳 集合节点","🌍 全部节点","DIRECT"] }, - { "type": "selector", "tag": "📲 电报消息", "outbounds": ["🚀 节点选择","♻️ 香港自动","♻️ 日本自动","♻️ 美国自动","♻️ 新加坡自动","♻️ 集合自动","♻️ 自动选择","🇭🇰 香港节点","🇯🇵 日本节点","🇺🇲 美国节点","🇸🇬 新加坡节点","🇺🇳 集合节点","🌍 全部节点","DIRECT"] }, - { "type": "selector", "tag": "🍏 苹果服务", "outbounds": ["DIRECT","🚀 节点选择","♻️ 自动选择"] }, - { "type": "selector", "tag": "🎯 全球直连", "outbounds": ["DIRECT","🚀 节点选择","♻️ 自动选择"] }, - { "type": "selector", "tag": "🏠 私有网络", "outbounds": ["DIRECT","🚀 节点选择","♻️ 自动选择"] }, - { "type": "selector", "tag": "🌐 非中国", "outbounds": ["🚀 节点选择","♻️ 香港自动","♻️ 日本自动","♻️ 美国自动","♻️ 新加坡自动","♻️ 集合自动","♻️ 自动选择","🇭🇰 香港节点","🇯🇵 日本节点","🇺🇲 美国节点","🇸🇬 新加坡节点","🇺🇳 集合节点","🌍 全部节点","DIRECT"] }, - { "type": "selector", "tag": "🐟 漏网之鱼", "outbounds": ["🚀 节点选择","♻️ 香港自动","♻️ 日本自动","♻️ 美国自动","♻️ 新加坡自动","♻️ 集合自动","♻️ 自动选择","🇭🇰 香港节点","🇯🇵 日本节点","🇺🇲 美国节点","🇸🇬 新加坡节点","🇺🇳 集合节点","🌍 全部节点","DIRECT"] }, - - { "type": "selector", "tag": "🇭🇰 香港节点", "outbounds": ["__NODES_HK__"] }, - { "type": "selector", "tag": "🇯🇵 日本节点", "outbounds": ["__NODES_JP__"] }, - { "type": "selector", "tag": "🇺🇲 美国节点", "outbounds": ["__NODES_US__"] }, - { "type": "selector", "tag": "🇸🇬 新加坡节点","outbounds": ["__NODES_SG__"] }, - { "type": "selector", "tag": "🇺🇳 集合节点", "outbounds": ["__NODES_OTHER__"] }, - { "type": "selector", "tag": "🌍 全部节点", "outbounds": ["__NODES__"] }, - - { "type": "urltest", "tag": "♻️ 香港自动", "outbounds": ["__NODES_HK__"], "url": "https://www.gstatic.com/generate_204", "interval": "5m", "tolerance": 50, "interrupt_exist_connections": true }, - { "type": "urltest", "tag": "♻️ 日本自动", "outbounds": ["__NODES_JP__"], "url": "https://www.gstatic.com/generate_204", "interval": "5m", "tolerance": 50, "interrupt_exist_connections": true }, - { "type": "urltest", "tag": "♻️ 美国自动", "outbounds": ["__NODES_US__"], "url": "https://www.gstatic.com/generate_204", "interval": "5m", "tolerance": 50, "interrupt_exist_connections": true }, - { "type": "urltest", "tag": "♻️ 新加坡自动", "outbounds": ["__NODES_SG__"], "url": "https://www.gstatic.com/generate_204", "interval": "5m", "tolerance": 50, "interrupt_exist_connections": true }, - { "type": "urltest", "tag": "♻️ 集合自动", "outbounds": ["__NODES_OTHER__"], "url": "https://www.gstatic.com/generate_204", "interval": "5m", "tolerance": 50, "interrupt_exist_connections": true }, - { "type": "urltest", "tag": "♻️ 自动选择", "outbounds": ["__NODES__"], "url": "https://www.gstatic.com/generate_204", "interval": "10m", "tolerance": 50, "interrupt_exist_connections": true }, - - { "type": "direct", "tag": "DIRECT" } - ], - "route": { - "default_domain_resolver": "dns_resolver", - "rule_set": [ - { "tag": "openai", "type": "remote", "format": "binary", "url": "https://github.com/MetaCubeX/meta-rules-dat/raw/refs/heads/sing/geo/geosite/openai.srs", "download_detour": "DIRECT" }, - { "tag": "anthropic", "type": "remote", "format": "binary", "url": "https://github.com/MetaCubeX/meta-rules-dat/raw/refs/heads/sing/geo/geosite/anthropic.srs", "download_detour": "DIRECT" }, - { "tag": "google-gemini", "type": "remote", "format": "binary", "url": "https://github.com/MetaCubeX/meta-rules-dat/raw/refs/heads/sing/geo/geosite/google-gemini.srs", "download_detour": "DIRECT" }, - { "tag": "youtube", "type": "remote", "format": "binary", "url": "https://github.com/MetaCubeX/meta-rules-dat/raw/refs/heads/sing/geo/geosite/youtube.srs", "download_detour": "DIRECT" }, - { "tag": "google", "type": "remote", "format": "binary", "url": "https://github.com/MetaCubeX/meta-rules-dat/raw/refs/heads/sing/geo/geosite/google.srs", "download_detour": "DIRECT" }, - { "tag": "twitter", "type": "remote", "format": "binary", "url": "https://github.com/MetaCubeX/meta-rules-dat/raw/refs/heads/sing/geo/geosite/twitter.srs", "download_detour": "DIRECT" }, - { "tag": "github", "type": "remote", "format": "binary", "url": "https://github.com/MetaCubeX/meta-rules-dat/raw/refs/heads/sing/geo/geosite/github.srs", "download_detour": "DIRECT" }, - { "tag": "gitlab", "type": "remote", "format": "binary", "url": "https://github.com/MetaCubeX/meta-rules-dat/raw/refs/heads/sing/geo/geosite/gitlab.srs", "download_detour": "DIRECT" }, - { "tag": "microsoft", "type": "remote", "format": "binary", "url": "https://github.com/MetaCubeX/meta-rules-dat/raw/refs/heads/sing/geo/geosite/microsoft.srs", "download_detour": "DIRECT" }, - { "tag": "tiktok", "type": "remote", "format": "binary", "url": "https://github.com/MetaCubeX/meta-rules-dat/raw/refs/heads/sing/geo/geosite/tiktok.srs", "download_detour": "DIRECT" }, - { "tag": "netflix", "type": "remote", "format": "binary", "url": "https://github.com/MetaCubeX/meta-rules-dat/raw/refs/heads/sing/geo/geosite/netflix.srs", "download_detour": "DIRECT" }, - { "tag": "hulu", "type": "remote", "format": "binary", "url": "https://github.com/MetaCubeX/meta-rules-dat/raw/refs/heads/sing/geo/geosite/hulu.srs", "download_detour": "DIRECT" }, - { "tag": "disney", "type": "remote", "format": "binary", "url": "https://github.com/MetaCubeX/meta-rules-dat/raw/refs/heads/sing/geo/geosite/disney.srs", "download_detour": "DIRECT" }, - { "tag": "hbo", "type": "remote", "format": "binary", "url": "https://github.com/MetaCubeX/meta-rules-dat/raw/refs/heads/sing/geo/geosite/hbo.srs", "download_detour": "DIRECT" }, - { "tag": "amazon", "type": "remote", "format": "binary", "url": "https://github.com/MetaCubeX/meta-rules-dat/raw/refs/heads/sing/geo/geosite/amazon.srs", "download_detour": "DIRECT" }, - { "tag": "bahamut", "type": "remote", "format": "binary", "url": "https://github.com/MetaCubeX/meta-rules-dat/raw/refs/heads/sing/geo/geosite/bahamut.srs", "download_detour": "DIRECT" }, - { "tag": "paypal", "type": "remote", "format": "binary", "url": "https://github.com/MetaCubeX/meta-rules-dat/raw/refs/heads/sing/geo/geosite/paypal.srs", "download_detour": "DIRECT" }, - { "tag": "apple", "type": "remote", "format": "binary", "url": "https://github.com/MetaCubeX/meta-rules-dat/raw/refs/heads/sing/geo/geosite/apple.srs", "download_detour": "DIRECT" }, - { "tag": "geolocation-cn", "type": "remote", "format": "binary", "url": "https://github.com/MetaCubeX/meta-rules-dat/raw/refs/heads/sing/geo/geosite/geolocation-cn.srs", "download_detour": "DIRECT" }, - { "tag": "cn", "type": "remote", "format": "binary", "url": "https://github.com/MetaCubeX/meta-rules-dat/raw/refs/heads/sing/geo/geosite/cn.srs", "download_detour": "DIRECT" }, - { "tag": "geolocation-!cn", "type": "remote", "format": "binary", "url": "https://github.com/MetaCubeX/meta-rules-dat/raw/refs/heads/sing/geo/geosite/geolocation-!cn.srs", "download_detour": "DIRECT" }, - { "tag": "google-ip", "type": "remote", "format": "binary", "url": "https://github.com/MetaCubeX/meta-rules-dat/raw/refs/heads/sing/geo/geoip/google.srs", "download_detour": "DIRECT" }, - { "tag": "private-ip", "type": "remote", "format": "binary", "url": "https://github.com/MetaCubeX/meta-rules-dat/raw/refs/heads/sing/geo/geoip/private.srs", "download_detour": "DIRECT" }, - { "tag": "cn-ip", "type": "remote", "format": "binary", "url": "https://github.com/MetaCubeX/meta-rules-dat/raw/refs/heads/sing/geo/geoip/cn.srs", "download_detour": "DIRECT" }, - { "tag": "telegram-ip", "type": "remote", "format": "binary", "url": "https://github.com/MetaCubeX/meta-rules-dat/raw/refs/heads/sing/geo/geoip/telegram.srs", "download_detour": "DIRECT" } - ], - "rules": [ - { "action": "sniff" }, - { "clash_mode": "direct", "outbound": "DIRECT" }, - { "clash_mode": "global", "outbound": "♻️ 自动选择" }, - { "protocol": "dns", "action": "hijack-dns" }, - { "rule_set": "openai", "outbound": "🔮 OpenAI" }, - { "rule_set": "anthropic", "outbound": "🧠 Claude" }, - { "rule_set": "google-gemini", "outbound": "🤖 Gemini" }, - { "rule_set": "youtube", "outbound": "▶️ YouTube" }, - { "rule_set": "google", "outbound": "🔍 Google" }, - { "rule_set": "twitter", "outbound": "🐦 Twitter" }, - { "rule_set": "tiktok", "outbound": "🎵 TikTok" }, - { "rule_set": "netflix", "outbound": "📺 Netflix" }, - { "rule_set": ["hulu", "disney", "hbo", "amazon", "bahamut"], "outbound": "🎬 流媒体" }, - { "rule_set": "paypal", "outbound": "💳 PayPal" }, - { "rule_set": "microsoft", "outbound": "Ⓜ️ Microsoft" }, - { "rule_set": "apple", "outbound": "🍏 苹果服务" }, - { "rule_set": ["github", "gitlab"], "outbound": "📦 GitHub" }, - { "rule_set": "telegram-ip", "outbound": "📲 电报消息" }, - { "rule_set": "private-ip", "outbound": "🏠 私有网络" }, - { "rule_set": ["geolocation-cn", "cn"], "outbound": "🎯 全球直连" }, - { "rule_set": "cn-ip", "outbound": "🎯 全球直连" }, - { "domain_suffix": ["cn"], "outbound": "🎯 全球直连" }, - { "rule_set": "geolocation-!cn", "outbound": "🌐 非中国" }, - { "rule_set": "google-ip", "outbound": "🔍 Google" } - ], - "auto_detect_interface": true, - "final": "🐟 漏网之鱼" - }, - "experimental": { - "cache_file": { "enabled": true, "store_fakeip": true }, - "clash_api": { - "external_controller": "0.0.0.0:9090", - "external_ui": "dashboard", - "secret": "clashoo", - "external_ui_download_url": "https://github.com/MetaCubeX/metacubexd/archive/refs/heads/gh-pages.zip", - "external_ui_download_detour": "DIRECT" - } - } -} diff --git a/clashoo/files/usr/share/clashoo/lib/yaml2singbox.uc b/clashoo/files/usr/share/clashoo/lib/yaml2singbox.uc deleted file mode 100644 index 37e40c76..00000000 --- a/clashoo/files/usr/share/clashoo/lib/yaml2singbox.uc +++ /dev/null @@ -1,468 +0,0 @@ -#!/usr/bin/ucode -/* yaml2singbox.uc — convert mihomo/clash YAML proxies to sing-box outbounds - * Usage: ucode yaml2singbox.uc [template-json] [json-out] - * Supports: ss, vmess, vless, trojan, hysteria2, tuic. Others are skipped. - * "__NODES__" in the template selector outbounds is expanded to all node tags. */ - -'use strict'; - -import { readfile, writefile, popen } from 'fs'; - -const TPL_DEFAULT = '/usr/share/clashoo/lib/templates/default.json'; -const SUPPORTED = { - 'ss': 'shadowsocks', - 'shadowsocks':'shadowsocks', - 'vmess': 'vmess', - 'vless': 'vless', - 'trojan': 'trojan', - 'hysteria2': 'hysteria2', - 'hy2': 'hysteria2', - 'tuic': 'tuic' -}; - -function logerr(msg) { - warn(sprintf("[yaml2singbox] %s\n", msg)); -} - -function die(msg, code) { - logerr(msg); - exit(code || 1); -} - -/* ---------- YAML read (via yq) ---------- */ -function quote_sh(s) { - /* single-quote for shell; escape embedded quotes */ - return "'" + replace(s, "'", "'\\''") + "'"; -} - -function read_yaml_as_json(path) { - const cmd = sprintf("yq -o=json eval . %s 2>/dev/null", quote_sh(path)); - const h = popen(cmd, "r"); - if (!h) - die(sprintf("popen failed: %s", cmd)); - let buf = "", chunk; - while ((chunk = h.read(65536))) - buf += chunk; - h.close(); - if (!length(buf)) - die(sprintf("yq returned empty for %s (yaml loadable?)", path)); - const data = json(buf); - if (data === null) - die("json parse of yq output failed"); - return data; -} - -/* ---------- helpers ---------- */ -function pick(obj, ...keys) { - for (let k in keys) - if (obj[k] != null) - return obj[k]; - return null; -} - -function tobool(v) { - if (v === true || v === 'true' || v === 1 || v === '1') return true; - if (v === false || v === 'false' || v === 0 || v === '0') return false; - return null; -} - -function toint(v) { - if (v == null) return null; - let n = +v; - return (n === n) ? n : null; /* NaN check */ -} - -function strip_null(obj) { - if (type(obj) !== 'object') return obj; - const out = {}; - for (let k in obj) { - const v = obj[k]; - if (v == null) continue; - if (type(v) === 'object') { - const sv = strip_null(v); - if (length(sv) > 0) out[k] = sv; - } else if (type(v) === 'array') { - const arr = map(v, (x) => (type(x) === 'object') ? strip_null(x) : x); - if (length(arr) > 0) out[k] = arr; - } else { - out[k] = v; - } - } - return out; -} - -/* ---------- TLS block assembly ---------- */ -function build_tls(p) { - const enabled = tobool(p.tls) || (p.sni && length(p.sni) > 0) || (p.servername && length(p.servername) > 0); - if (!enabled) return null; - const tls = { - enabled: true, - server_name: pick(p, 'sni', 'servername'), - insecure: tobool(p['skip-cert-verify']) === true ? true : null, - alpn: p.alpn - }; - const reality = p['reality-opts']; - if (reality && type(reality) === 'object') { - tls.reality = { - enabled: true, - public_key: reality['public-key'], - short_id: reality['short-id'] - }; - } - const client_fp = p['client-fingerprint']; - if (client_fp) - tls.utls = { enabled: true, fingerprint: client_fp }; - return strip_null(tls); -} - -/* ---------- transport (ws / grpc / http) ---------- */ -function build_transport(p) { - const net = p.network; - if (!net || net === 'tcp') return null; - if (net === 'ws') { - const opts = p['ws-opts'] || {}; - return strip_null({ - type: 'ws', - path: opts.path, - headers: opts.headers, - max_early_data: toint(opts['max-early-data']), - early_data_header_name: opts['early-data-header-name'] - }); - } - if (net === 'grpc') { - const opts = p['grpc-opts'] || {}; - return { type: 'grpc', service_name: opts['grpc-service-name'] }; - } - if (net === 'http' || net === 'h2') { - const opts = p['h2-opts'] || p['http-opts'] || {}; - return strip_null({ - type: 'http', - host: opts.host || opts.Host, - path: opts.path - }); - } - if (net === 'httpupgrade') { - const opts = p['http-upgrade-opts'] || {}; - return strip_null({ type: 'httpupgrade', path: opts.path, host: opts.host }); - } - logerr(sprintf("unknown transport network '%s' for node '%s', ignored", net, p.name)); - return null; -} - -/* ---------- per-protocol conversion ---------- */ -function convert_ss(p) { - const plugin = p.plugin, popts = p['plugin-opts'] || {}; - let plugin_opts = null; - if (plugin && type(popts) === 'object') { - /* Field mapping: Clash simple-obfs -> sing-box obfs-local - * Clash: mode=http;host=xxx → sing-box: obfs=http;obfs-host=xxx */ - const FIELD_MAP = { - 'mode': 'obfs', - 'host': 'obfs-host', - 'uri': 'obfs-uri' - }; - const parts = []; - for (let k in popts) { - const v = popts[k]; - if (type(v) === 'object') continue; - push(parts, (FIELD_MAP[k] || k) + '=' + v); - } - plugin_opts = join(';', parts); - } - /* Clash "obfs" maps to sing-box plugin "obfs-local" */ - let sb_plugin = null; - if (plugin === 'obfs') sb_plugin = 'obfs-local'; - else if (plugin === 'v2ray-plugin') sb_plugin = 'v2ray-plugin'; - else if (plugin === 'shadow-tls') sb_plugin = 'shadow-tls'; - else if (plugin) sb_plugin = plugin; - - return strip_null({ - type: 'shadowsocks', - tag: p.name, - server: p.server, - server_port: toint(p.port), - method: p.cipher, - password: p.password, - plugin: sb_plugin, - plugin_opts: plugin_opts - }); -} - -function convert_vmess(p) { - return strip_null({ - type: 'vmess', - tag: p.name, - server: p.server, - server_port: toint(p.port), - uuid: p.uuid, - alter_id: toint(p.alterId) || 0, - security: p.cipher || 'auto', - tls: build_tls(p), - transport: build_transport(p) - }); -} - -function convert_vless(p) { - return strip_null({ - type: 'vless', - tag: p.name, - server: p.server, - server_port: toint(p.port), - uuid: p.uuid, - flow: p.flow, - tls: build_tls(p), - transport: build_transport(p) - }); -} - -function convert_trojan(p) { - return strip_null({ - type: 'trojan', - tag: p.name, - server: p.server, - server_port: toint(p.port), - password: p.password, - tls: build_tls(p) || { enabled: true, server_name: p.sni || p.server }, - transport: build_transport(p) - }); -} - -function convert_hysteria2(p) { - const obfs_pass = p['obfs-password']; - return strip_null({ - type: 'hysteria2', - tag: p.name, - server: p.server, - server_port: toint(p.port), - password: pick(p, 'password', 'auth'), - up_mbps: toint(p.up), - down_mbps: toint(p.down), - obfs: (p.obfs && obfs_pass) ? { type: p.obfs, password: obfs_pass } : null, - tls: build_tls(p) || { enabled: true, server_name: p.sni || p.server } - }); -} - -function convert_tuic(p) { - return strip_null({ - type: 'tuic', - tag: p.name, - server: p.server, - server_port: toint(p.port), - uuid: p.uuid, - password: p.password, - congestion_control: p['congestion-controller'] || p.congestion, - udp_relay_mode: p['udp-relay-mode'], - tls: build_tls(p) || { enabled: true, server_name: p.sni || p.server, alpn: p.alpn } - }); -} - -function convert_proxy(p) { - const sb_type = SUPPORTED[p.type]; - if (!sb_type) { - if (p.type && p.type !== 'select') - logerr(sprintf("skip unsupported type '%s' for '%s'", p.type, p.name)); - return null; - } - if (!p.server || !p.port || !p.name) { - logerr(sprintf("skip proxy missing server/port/name (type=%s)", p.type)); - return null; - } - switch (p.type) { - case 'ss': - case 'shadowsocks': return convert_ss(p); - case 'vmess': return convert_vmess(p); - case 'vless': return convert_vless(p); - case 'trojan': return convert_trojan(p); - case 'hysteria2': - case 'hy2': return convert_hysteria2(p); - case 'tuic': return convert_tuic(p); - } - return null; -} - -/* ---------- dedup (tag must be unique) ---------- */ -function dedupe_tags(nodes) { - const seen = {}; - for (let n in nodes) { - let base = n.tag, t = base, i = 2; - while (seen[t]) { - t = base + '_' + i; - i++; - } - n.tag = t; - seen[t] = true; - } - return nodes; -} - -/* Drop airline pseudo-nodes (Traffic:/Expire:/quota/官网/QQ etc.) from selectors - * and urltests. They're real outbounds (so the UI can read traffic/expiry) but - * don't forward — in a selector/urltest they win (0ms) and swallow all traffic. */ -function is_pseudo_node_tag(tag) { - if (!tag) return false; - const t = '' + tag; - const patterns = [ - /^Traffic[::]/i, - /^Expire[::]/i, - /剩余流量|剩余[::]/, - /距离下次重置/, - /到期(时间|日期)?[::]/, - /官网[::]/, - /网站[::]/, - /套餐[::]?/, - /客服[::]/, - /QQ[群]?[::]/i, - /Telegram|TG群|官方群/i, - /续费|订阅地址|流量重置/, - ]; - for (let re in patterns) if (match(t, re)) return true; - return false; -} - -/* ---------- detect region from tag -> 'HK'/'JP'/'US'/'SG'/'OTHER'/'' ---------- */ -function region_of(tag) { - if (!tag) return ''; - const t = '' + tag; - if (match(t, /港|🇭🇰|HK[^A-Za-z]|[^A-Za-z]HK|^HK$|[Hh]ong[Kk]/)) return 'HK'; - if (match(t, /日|🇯🇵|JP[^A-Za-z]|[^A-Za-z]JP|^JP$|[Jj]apan/)) return 'JP'; - if (match(t, /美|🇺🇸|US[^A-Za-z]|[^A-Za-z]US|^US$|[Uu]nited.?[Ss]tates|[Aa]merica/)) return 'US'; - if (match(t, /新加坡|🇸🇬|SG[^A-Za-z]|[^A-Za-z]SG|^SG$|[Ss]ingapore/)) return 'SG'; - if (match(t, /台湾|台|🇹🇼|TW[^A-Za-z]|[^A-Za-z]TW|^TW$|[Tt]aiwan|韩国|韩|🇰🇷|KR[^A-Za-z]|[^A-Za-z]KR|^KR$|[Kk]orea/)) return 'OTHER'; - return ''; -} - -/* ---------- expand __NODES__/__NODES_XX__ placeholders to real tags (dropping pseudo-nodes) ---------- */ -function expand_node_placeholder(outbounds, node_tags) { - const real_tags = []; - for (let t in node_tags) if (!is_pseudo_node_tag(t)) push(real_tags, t); - - /* bucket by region */ - let tags_hk = [], tags_jp = [], tags_us = [], tags_sg = [], tags_other = []; - for (let t in real_tags) { - const r = region_of(t); - if (r === 'HK') push(tags_hk, t); - else if (r === 'JP') push(tags_jp, t); - else if (r === 'US') push(tags_us, t); - else if (r === 'SG') push(tags_sg, t); - else if (r === 'OTHER') push(tags_other, t); - } - /* when a region has no nodes, fall back to all nodes (avoid empty outbounds) */ - if (!length(tags_hk)) tags_hk = real_tags; - if (!length(tags_jp)) tags_jp = real_tags; - if (!length(tags_us)) tags_us = real_tags; - if (!length(tags_sg)) tags_sg = real_tags; - if (!length(tags_other)) tags_other = real_tags; - - for (let ob in outbounds) { - if (ob.type !== 'selector' && ob.type !== 'urltest') continue; - if (!ob.outbounds || type(ob.outbounds) !== 'array') continue; - const expanded = []; - for (let item in ob.outbounds) { - let list = null; - if (item === '__NODES__') list = real_tags; - else if (item === '__NODES_HK__') list = tags_hk; - else if (item === '__NODES_JP__') list = tags_jp; - else if (item === '__NODES_US__') list = tags_us; - else if (item === '__NODES_SG__') list = tags_sg; - else if (item === '__NODES_OTHER__') list = tags_other; - if (list !== null) { for (let t in list) push(expanded, t); } - else { push(expanded, item); } - } - ob.outbounds = expanded; - } - return outbounds; -} - -/* ---------- proxy-providers ---------- */ -function resolve_providers(yaml) { - if (type(yaml['proxy-providers']) !== 'object') - return []; - const all = []; - for (let name in yaml['proxy-providers']) { - const p = yaml['proxy-providers'][name]; - if (p.type !== 'http' || !p.url) { - logerr(sprintf("provider '%s': skip (not http or no url)", name)); - continue; - } - const cmd = sprintf("wget -q -O- --timeout=20 %s 2>/dev/null | yq -o=json eval . 2>/dev/null", quote_sh(p.url)); - const h = popen(cmd, "r"); - if (!h) { logerr(sprintf("provider '%s': download failed", name)); continue; } - let buf = "", chunk; - while ((chunk = h.read(65536))) buf += chunk; - h.close(); - if (!length(buf)) { logerr(sprintf("provider '%s': empty response", name)); continue; } - const data = json(buf); - if (!data || type(data.proxies) !== 'array') { - logerr(sprintf("provider '%s': no proxies array in response", name)); - continue; - } - logerr(sprintf("provider '%s': %d proxies", name, length(data.proxies))); - for (let px in data.proxies) push(all, px); - } - return all; -} - -/* ---------- main ---------- */ -const yaml_path = ARGV[0]; -const tpl_path = ARGV[1] || TPL_DEFAULT; -const out_path = ARGV[2]; - -if (!yaml_path) - die("usage: ucode yaml2singbox.uc [template-json] [json-out]"); - -const yaml = read_yaml_as_json(yaml_path); - -let proxies = []; -if (type(yaml.proxies) === 'array') - proxies = yaml.proxies; -else - logerr("no inline proxies array, checking proxy-providers..."); - -if (type(yaml['proxy-providers']) === 'object') { - const pproxies = resolve_providers(yaml); - for (let p in pproxies) push(proxies, p); -} - -if (!length(proxies)) - die(sprintf("no proxies found in %s (inline or via providers)", yaml_path)); - -const tpl_raw = readfile(tpl_path); -if (!tpl_raw) - die(sprintf("cannot read template %s", tpl_path)); -const tpl = json(tpl_raw); -if (!tpl || type(tpl.outbounds) !== 'array') - die(sprintf("template %s has no outbounds[]", tpl_path)); - -/* convert proxies */ -const nodes = []; -let skipped = 0; -for (let p in proxies) { - const o = convert_proxy(p); - if (o) push(nodes, o); else skipped++; -} -dedupe_tags(nodes); - -if (!length(nodes)) - die(sprintf("no usable nodes converted from %d proxies (skipped=%d)", length(proxies), skipped)); - -logerr(sprintf("converted=%d skipped=%d", length(nodes), skipped)); - -/* prepend converted nodes to template outbounds */ -const final_outbounds = []; -for (let n in nodes) push(final_outbounds, n); -for (let ob in tpl.outbounds) push(final_outbounds, ob); - -/* expand __NODES__ placeholders */ -const node_tags = map(nodes, (n) => n.tag); -expand_node_placeholder(final_outbounds, node_tags); - -tpl.outbounds = final_outbounds; - -const out = sprintf("%.J\n", tpl); -if (out_path) { - if (!writefile(out_path, out)) - die(sprintf("writefile failed: %s", out_path)); - logerr(sprintf("wrote %s (%d bytes, %d nodes)", out_path, length(out), length(nodes))); -} else { - print(out); -} diff --git a/clashoo/files/usr/share/clashoo/migrate_fake_ip_filter.sh b/clashoo/files/usr/share/clashoo/migrate_fake_ip_filter.sh deleted file mode 100755 index 0cc4f362..00000000 --- a/clashoo/files/usr/share/clashoo/migrate_fake_ip_filter.sh +++ /dev/null @@ -1,42 +0,0 @@ -#!/bin/sh - -set -f - -[ "$(uci -q get clashoo.config.fake_ip_filter_migrated 2>/dev/null)" = "1" ] && exit 0 - -filters="$(uci -q get clashoo.config.fake_ip_filter 2>/dev/null)" -has_legacy=0 -for filter in $filters; do - [ "$filter" = "*.lan" ] && has_legacy=1 -done - -if [ "$has_legacy" = "1" ]; then - uci -q delete clashoo.config.fake_ip_filter - added_lan=0 - added_local=0 - for filter in $filters; do - case "$filter" in - '*.lan'|'+.lan') - if [ "$added_lan" = "0" ]; then - uci -q add_list clashoo.config.fake_ip_filter='+.lan' - added_lan=1 - fi - ;; - '+.local') - if [ "$added_local" = "0" ]; then - uci -q add_list clashoo.config.fake_ip_filter='+.local' - added_local=1 - fi - ;; - *) - uci -q add_list clashoo.config.fake_ip_filter="$filter" - ;; - esac - done - if [ "$added_local" = "0" ]; then - uci -q add_list clashoo.config.fake_ip_filter='+.local' - fi -fi - -uci -q set clashoo.config.fake_ip_filter_migrated='1' -uci -q commit clashoo diff --git a/clashoo/files/usr/share/clashoo/migrate_lan_acl.sh b/clashoo/files/usr/share/clashoo/migrate_lan_acl.sh deleted file mode 100644 index 750e3994..00000000 --- a/clashoo/files/usr/share/clashoo/migrate_lan_acl.sh +++ /dev/null @@ -1,38 +0,0 @@ -#!/bin/sh - -[ "$(uci -q get clashoo.config.acl_migrated 2>/dev/null)" = "1" ] && exit 0 -if uci -q show clashoo 2>/dev/null | grep -q '=lan_acl$'; then - uci -q set clashoo.config.acl_migrated='1' - uci -q commit clashoo - exit 0 -fi - -mode="$(uci -q get clashoo.config.access_control 2>/dev/null)" - -add_group() { - local dns="$1" proxy="$2" list_key="${3:-}" section value - - section="$(uci -q add clashoo lan_acl)" || exit 1 - uci -q set clashoo."$section".enabled='1' - uci -q set clashoo."$section".dns="$dns" - uci -q set clashoo."$section".proxy="$proxy" - if [ -n "$list_key" ]; then - for value in $(uci -q get clashoo.config."$list_key" 2>/dev/null); do - uci -q add_list clashoo."$section".ip="$value" - done - fi -} - -case "$mode" in - 1) - add_group 1 1 proxy_lan_ips - add_group 0 0 - ;; - 2) - add_group 0 0 reject_lan_ips - add_group 1 1 - ;; -esac - -uci -q set clashoo.config.acl_migrated='1' -uci -q commit clashoo diff --git a/clashoo/files/usr/share/clashoo/net/access_check.sh b/clashoo/files/usr/share/clashoo/net/access_check.sh deleted file mode 100755 index 6356d841..00000000 --- a/clashoo/files/usr/share/clashoo/net/access_check.sh +++ /dev/null @@ -1,89 +0,0 @@ -#!/bin/sh -# clashoo access check -# 用法: access_check.sh [mode] -# mode = direct | proxy(默认 proxy) -# direct: 经 openwrt 主干直连,不走任何代理 -# proxy: 走 clashoo 本地代理端口,验证核心出站 - -url="$1" -mode="${2:-proxy}" -[ -n "$url" ] || exit 1 - -attempts=1 -ok=0 -sum_ms=0 -last_code=000 - -url_host() { - printf '%s' "$1" | sed -n 's#^[a-zA-Z][a-zA-Z0-9+.-]*://\([^/:?#]*\).*$#\1#p' -} - -url_port() { - _u="$1" - _p="$(printf '%s' "$_u" | sed -n 's#^[a-zA-Z][a-zA-Z0-9+.-]*://[^/:?#]*:\([0-9][0-9]*\).*$#\1#p')" - [ -n "$_p" ] && { printf '%s' "$_p"; return; } - case "$_u" in - https://*) printf '443' ;; - http://*) printf '80' ;; - *) printf '443' ;; - esac -} - -run_with_timeout() { - _secs="$1" - shift - if command -v timeout >/dev/null 2>&1; then - timeout "$_secs" "$@" 2>/dev/null - else - "$@" 2>/dev/null - fi -} - -resolve_real_ip() { - _host="$1" - [ -n "$_host" ] || return 0 - for _dns in 223.5.5.5 119.29.29.29 1.1.1.1; do - _ip="$(run_with_timeout 1 nslookup "$_host" "$_dns" | awk '/^Address: /{print $2} /^Address [0-9]+: /{print $3}' | grep -E '^[0-9]+(\.[0-9]+){3}$' | tail -n1)" - [ -n "$_ip" ] && { printf '%s' "$_ip"; return; } - done -} - -set -- -4 -L --max-time 5 --connect-timeout 3 -s -o /dev/null -w '%{http_code} %{time_total}' -if [ "$mode" = "direct" ]; then - # 强制不走任何代理,避免误读 http_proxy 环境变量 - set -- "$@" --noproxy '*' - host="$(url_host "$url")" - port="$(url_port "$url")" - real_ip="$(resolve_real_ip "$host")" - [ -n "$host" ] && [ -n "$port" ] && [ -n "$real_ip" ] && set -- "$@" --resolve "${host}:${port}:${real_ip}" -else - proxy_port="$(uci get clashoo.config.mixed_port 2>/dev/null)" - [ -z "$proxy_port" ] && proxy_port="$(uci get clashoo.config.http_port 2>/dev/null)" - [ -z "$proxy_port" ] && proxy_port=7890 - set -- "$@" -x "http://127.0.0.1:${proxy_port}" -fi -set -- "$@" "$url" - -i=1 -while [ "$i" -le "$attempts" ]; do - out="$(curl "$@" 2>/dev/null || true)" - code="$(printf '%s' "$out" | awk '{print $1}')" - time_s="$(printf '%s' "$out" | awk '{print $2}')" - [ -n "$code" ] || code=000 - [ -n "$time_s" ] || time_s=0 - ms="$(awk -v t="$time_s" 'BEGIN{printf "%d", t*1000}')" - last_code="$code" - if [ "$code" = "200" ] || [ "$code" = "204" ] || [ "$code" = "301" ] || [ "$code" = "302" ]; then - ok=$((ok + 1)) - sum_ms=$((sum_ms + ms)) - fi - i=$((i + 1)) -done - -loss=$((attempts - ok)) -avg_ms=0 -if [ "$ok" -gt 0 ]; then - avg_ms=$((sum_ms / ok)) -fi - -echo "ok=$ok attempts=$attempts loss=$loss avg_ms=$avg_ms code=$last_code" diff --git a/clashoo/files/usr/share/clashoo/net/access_check_cache.sh b/clashoo/files/usr/share/clashoo/net/access_check_cache.sh deleted file mode 100755 index ff930eb0..00000000 --- a/clashoo/files/usr/share/clashoo/net/access_check_cache.sh +++ /dev/null @@ -1,195 +0,0 @@ -#!/bin/sh - -set -eu - -CACHE_DIR="/tmp/clashoo" -CACHE_FILE="/tmp/clashoo_check_cache" -LOCK_DIR="${CACHE_DIR}/access_check.lock" -LOCK_PID_FILE="${LOCK_DIR}/pid" -UPDATING_FLAG="${CACHE_DIR}/access_check_updating" -TMP_FILE="${CACHE_FILE}.tmp.$$" -DIAG_LOG="/tmp/clashoo_access_check.log" - -take_lock() { - mkdir "$LOCK_DIR" 2>/dev/null || return 1 - printf '%s\n' "$$" > "$LOCK_PID_FILE" 2>/dev/null - return 0 -} - -pid_is_cache_worker() { - [ -r "/proc/$1/cmdline" ] || return 1 - tr '\0' ' ' <"/proc/$1/cmdline" 2>/dev/null | grep -q 'access_check_cache\.sh' -} - -lock_is_dead() { - _pid="$(cat "$LOCK_PID_FILE" 2>/dev/null)" - case "$_pid" in - ''|*[!0-9]*) - [ -n "$(find "$LOCK_DIR" -maxdepth 0 -mmin +3 2>/dev/null)" ] - return $? - ;; - esac - [ ! -d "/proc/$_pid" ] && return 0 - ! pid_is_cache_worker "$_pid" -} - -mkdir -p "$CACHE_DIR" -if ! take_lock; then - lock_is_dead || exit 0 - rm -rf "$LOCK_DIR" >/dev/null 2>&1 - take_lock || exit 0 -fi -trap 'rm -rf "$LOCK_DIR" "$UPDATING_FLAG" "$TMP_FILE"' EXIT INT TERM -: > "$UPDATING_FLAG" - -safe_int() { - case "${1:-}" in - ''|*[!0-9]*) - printf '0' - ;; - *) - printf '%s' "$1" - ;; - esac -} - -safe_code() { - case "${1:-}" in - ''|*[!0-9A-Za-z]*) - printf '000' - ;; - *) - printf '%s' "$1" - ;; - esac -} - -parse_field() { - _line="$1" - _key="$2" - printf '%s\n' "$_line" | sed -n "s/.*${_key}=\\([^ ]*\\).*/\\1/p" -} - -probe_json() { - _line="$1" - _ok="$(safe_int "$(parse_field "$_line" "ok")")" - _attempts="$(safe_int "$(parse_field "$_line" "attempts")")" - _loss="$(safe_int "$(parse_field "$_line" "loss")")" - _avg_ms="$(safe_int "$(parse_field "$_line" "avg_ms")")" - _code="$(safe_code "$(parse_field "$_line" "code")")" - - _state="down" - if [ "$_ok" -ge "$_attempts" ] && [ "$_attempts" -gt 0 ]; then - if [ "$_avg_ms" -ge 2500 ]; then - _state="high_latency" - else - _state="ok" - fi - elif [ "$_ok" -gt 0 ]; then - _state="loss" - fi - - _ok_bool=false - [ "$_ok" -gt 0 ] && _ok_bool=true - - printf '{"ok":%s,"state":"%s","code":"%s","ok_count":%s,"attempts":%s,"loss":%s,"avg_ms":%s}' \ - "$_ok_bool" "$_state" "$_code" "$_ok" "$_attempts" "$_loss" "$_avg_ms" -} - -log_diag() { - _line="$(date '+%Y-%m-%d %H:%M:%S') $1" - printf '%s\n' "$_line" >>"$DIAG_LOG" 2>/dev/null - _n="$(wc -l <"$DIAG_LOG" 2>/dev/null || echo 0)" - if [ "${_n:-0}" -gt 200 ]; then - tail -n 100 "$DIAG_LOG" >"${DIAG_LOG}.tmp" 2>/dev/null && mv "${DIAG_LOG}.tmp" "$DIAG_LOG" 2>/dev/null - fi -} - -probe_run() { - _url="$1" - _mode="$2" - # nice + ionice:探测 IO/CPU 都低优先级,避免抢占 LuCI dispatcher - nice -n 19 /usr/share/clashoo/net/access_check.sh "$_url" "$_mode" 2>/dev/null || true -} - -proxy_port="$(uci -q get clashoo.config.mixed_port)" -[ -z "$proxy_port" ] && proxy_port="$(uci -q get clashoo.config.http_port)" -[ -z "$proxy_port" ] && proxy_port="7890" -tcp_mode="$(uci -q get clashoo.config.tcp_mode)" -[ -z "$tcp_mode" ] && tcp_mode="redirect" -udp_mode="$(uci -q get clashoo.config.udp_mode)" -[ -z "$udp_mode" ] && udp_mode="$tcp_mode" - -proxy_listening() { - # 检测 mixed-port 是否在 LISTEN(clashoo 未运行时立即标 proxy down,避免显示假绿) - if command -v ss >/dev/null 2>&1; then - ss -tln 2>/dev/null | awk -v p=":${proxy_port}" '$0 ~ "LISTEN" && index($4, p) {found=1; exit} END{exit !found}' - elif command -v netstat >/dev/null 2>&1; then - netstat -tln 2>/dev/null | awk -v p=":${proxy_port}" '$0 ~ "LISTEN" && index($4, p) {found=1; exit} END{exit !found}' - else - return 0 - fi -} - -# 并行探测,把 CPU 抢占窗口从串行 2s+ 压缩到最慢一路的耗时 -f_db="${TMP_FILE}.db" -f_dy="${TMP_FILE}.dy" -f_pb="${TMP_FILE}.pb" -f_py="${TMP_FILE}.py" -probe_run "https://www.douyin.com/generate_204" "direct" >"$f_db" & -probe_run "https://www.youtube.com/generate_204" "direct" >"$f_dy" & -if proxy_listening; then - proxy_skipped=0 - probe_run "https://www.douyin.com/generate_204" "proxy" >"$f_pb" & - probe_run "https://www.youtube.com/generate_204" "proxy" >"$f_py" & -else - # 代理端口未监听(clashoo 已停止),跳过探测,直接标 down - proxy_skipped=1 - echo "ok=0 attempts=1 loss=1 avg_ms=0 code=skip" >"$f_pb" - echo "ok=0 attempts=1 loss=1 avg_ms=0 code=skip" >"$f_py" -fi -wait -direct_bytedance="$(cat "$f_db" 2>/dev/null)" -direct_youtube="$(cat "$f_dy" 2>/dev/null)" -proxy_bytedance="$(cat "$f_pb" 2>/dev/null)" -proxy_youtube="$(cat "$f_py" 2>/dev/null)" -rm -f "$f_db" "$f_dy" "$f_pb" "$f_py" - -updated_at="$(date +%s)" - -probe_all_down() { - for _p in "$direct_bytedance" "$direct_youtube" "$proxy_bytedance" "$proxy_youtube"; do - case "$_p" in - ''|*"ok=0 "*) ;; - *) return 1 ;; - esac - done - return 0 -} - -if [ "$(uci -q get clashoo.config.access_check_debug)" = "1" ] || probe_all_down; then - log_diag "port=${proxy_port} proxy_skipped=${proxy_skipped} direct_bd=[${direct_bytedance}] direct_yt=[${direct_youtube}] proxy_bd=[${proxy_bytedance}] proxy_yt=[${proxy_youtube}]" -fi - -cat >"$TMP_FILE" </dev/null; then - old_pid="$(cat "$PID_FILE" 2>/dev/null)" - if [ -n "$old_pid" ] && [ -d "/proc/$old_pid" ] && \ - tr '\0' ' ' <"/proc/$old_pid/cmdline" 2>/dev/null | grep -q 'access_check_daemon\.sh'; then - exit 0 - fi - rm -rf "$LOCK_DIR" "$PID_FILE" >/dev/null 2>&1 - mkdir "$LOCK_DIR" 2>/dev/null || exit 0 -fi - -cleanup() { - rm -rf "$LOCK_DIR" "$PID_FILE" -} -trap cleanup EXIT -trap 'cleanup; exit 0' INT TERM - -echo "$$" >"$PID_FILE" - -while :; do - [ "$(uci -q get clashoo.config.enable 2>/dev/null)" = "1" ] || break - /usr/share/clashoo/net/access_check_cache.sh >/dev/null 2>&1 || true - # 每轮顺手卡一下 core.log 大小(tmpfs 很小,跑飞会写满 /tmp) - sh /usr/share/clashoo/lib/core_log_guard.sh >/dev/null 2>&1 || true - if [ -n "$INTERVAL_FIXED" ]; then - sleep "$INTERVAL_FIXED" - else - sleep 30 - fi -done diff --git a/clashoo/files/usr/share/clashoo/net/dns_auto_setup.sh b/clashoo/files/usr/share/clashoo/net/dns_auto_setup.sh deleted file mode 100644 index b1e22c8d..00000000 --- a/clashoo/files/usr/share/clashoo/net/dns_auto_setup.sh +++ /dev/null @@ -1,240 +0,0 @@ -#!/bin/sh - -APPLY=0 -TIMEOUT="${CLASHOO_DNS_TEST_TIMEOUT:-2}" -START_TS="$(date +%s 2>/dev/null || echo 0)" - -while [ $# -gt 0 ]; do - case "$1" in - --apply) APPLY=1 ;; - esac - shift -done - -json_escape() { - printf '%s' "$1" | sed 's/\\/\\\\/g; s/"/\\"/g' -} - -json_pair() { - printf '"%s":"%s"' "$1" "$(json_escape "$2")" -} - -is_ipv4() { - echo "$1" | grep -Eq '^[0-9]+(\.[0-9]+){3}$' -} - -append_unique() { - list="$1" - item="$2" - [ -n "$item" ] || { printf '%s' "$list"; return; } - case " $list " in - *" $item "*) printf '%s' "$list" ;; - *) printf '%s %s' "$list" "$item" ;; - esac -} - -current_default_nameservers() { - uci -q get clashoo.config.default_nameserver 2>/dev/null || true -} - -current_dns_servers() { - uci -q show clashoo 2>/dev/null | awk -F= ' - function clean(v) { - gsub(/^'\''|'\''$/, "", v); - return v; - } - /^clashoo\.@dnsservers\[[0-9]+\]\./ { - line=$1; - val=clean($2); - sub(/^clashoo\.@dnsservers\[/, "", line); - idx=line; - sub(/\].*$/, "", idx); - opt=line; - sub(/^[0-9]+\]\./, "", opt); - data[idx, opt]=val; - seen[idx]=1; - } - END { - for (idx in seen) { - if (data[idx, "enabled"] == "0") continue; - role=data[idx, "ser_type"]; - addr=data[idx, "ser_address"]; - proto=data[idx, "protocol"]; - port=data[idx, "ser_port"]; - if (addr == "") continue; - if (proto != "" && proto != "none" && addr !~ /^[a-zA-Z][a-zA-Z0-9+.-]*:\/\//) { - addr=proto addr; - if (port != "" && addr !~ /:[0-9]+$/) addr=addr ":" port; - } - print role "|" addr; - } - }' -} - -servers_for_role() { - role="$1" - current_dns_servers | awk -F'|' -v role="$role" '$1 == role { print $2 }' -} - -candidate_host_port() { - uri="$1" - default_port="$2" - hostport="${uri#*://}" - hostport="${hostport%%/*}" - host="${hostport%%:*}" - port="${hostport##*:}" - [ "$port" != "$hostport" ] || port="$default_port" - printf '%s %s\n' "$host" "$port" -} - -probe_tls() { - uri="$1" - set -- $(candidate_host_port "$uri" 853) - host="$1" - port="$2" - command -v nc >/dev/null 2>&1 || return 1 - nc -w "$TIMEOUT" "$host" "$port" >/dev/null 2>&1 -} - -probe_ip_dns() { - ip="$1" - domain="$2" - command -v nslookup >/dev/null 2>&1 || return 1 - nslookup "$domain" "$ip" >/dev/null 2>&1 -} - -probe_latency_ms() { - candidate="$1" - domain="$2" - if [ "${candidate#https://}" != "$candidate" ]; then - if printf '%s' "$candidate" | grep -q '?'; then - q="$candidate&name=$domain&type=A" - else - q="$candidate?name=$domain&type=A" - fi - command -v curl >/dev/null 2>&1 || return 1 - t="$(curl -fsS --connect-timeout "$TIMEOUT" --max-time "$TIMEOUT" \ - -H 'accept: application/dns-json' -o /dev/null -w '%{time_total}' "$q" 2>/dev/null)" || return 1 - printf '%s' "$t" | awk '{ms=$1*1000; if (ms<1) ms=1; printf "%d", ms}' - elif [ "${candidate#tls://}" != "$candidate" ]; then - probe_tls "$candidate" || return 1 - printf '900' - elif [ "${candidate#udp://}" != "$candidate" ]; then - probe_ip_dns "${candidate#udp://}" "$domain" || return 1 - printf '950' - elif [ "${candidate#tcp://}" != "$candidate" ]; then - probe_ip_dns "${candidate#tcp://}" "$domain" || return 1 - printf '950' - else - is_ipv4 "$candidate" && probe_ip_dns "$candidate" "$domain" || return 1 - printf '950' - fi -} - -select_best() { - list="$1" - domain="$2" - fallback="$3" - best="" - best_score=999999 - order=0 - for candidate in $list; do - order=$((order + 1)) - ms="$(probe_latency_ms "$candidate" "$domain")" || { FAILED_COUNT=$((FAILED_COUNT + 1)); continue; } - score=$((ms * 100 + order)) - if [ "$score" -lt "$best_score" ]; then - best="$candidate" - best_score="$score" - fi - done - [ -n "$best" ] || best="$fallback" - printf '%s' "$best" -} - -add_dnsserver() { - role="$1" - addr="$2" - proto="$3" - port="$4" - sec="$(uci -q add clashoo dnsservers)" || return 1 - [ -n "$sec" ] || return 1 - uci -q set clashoo."$sec".enabled='1' || return 1 - uci -q set clashoo."$sec".ser_type="$role" || return 1 - uci -q set clashoo."$sec".ser_address="$addr" || return 1 - uci -q set clashoo."$sec".protocol="$proto" || return 1 - if [ -n "$port" ]; then - uci -q set clashoo."$sec".ser_port="$port" || return 1 - fi - return 0 -} - -set_default_nameserver() { - uci -q delete clashoo.config.default_nameserver >/dev/null 2>&1 || true - uci -q add_list clashoo.config.default_nameserver="$1" || return 1 - return 0 -} - -apply_result() { - uci -q set clashoo.config.enable_dns='1' || { uci -q revert clashoo; return 1; } - set_default_nameserver "$BOOTSTRAP" || { uci -q revert clashoo; return 1; } - while uci -q delete clashoo.@dnsservers[0] >/dev/null 2>&1; do :; done - add_dnsserver 'nameserver' "$NAMESERVER" 'none' '' || { uci -q revert clashoo; return 1; } - add_dnsserver 'direct-nameserver' "$BOOTSTRAP" 'udp://' '' || { uci -q revert clashoo; return 1; } - add_dnsserver 'proxy-server-nameserver' "$PROXY_NS" 'none' '' || { uci -q revert clashoo; return 1; } - add_dnsserver 'fallback' "$FALLBACK_NS" 'none' '' || { uci -q revert clashoo; return 1; } - uci -q commit clashoo || { uci -q revert clashoo; return 1; } - return 0 -} - -is_domestic_dns() { - printf '%s' "$1" | grep -qE 'alidns|doh\.pub|dnspod|223\.5\.5\.5|223\.6\.6\.6|119\.29\.29\.29|119\.28\.28\.28|114\.114|180\.184|onedns' -} -is_overseas_dns() { - printf '%s' "$1" | grep -qE 'cloudflare|1\.1\.1\.1|1\.0\.0\.1|one\.one\.one\.one|dns\.google|8\.8\.8\.8|8\.8\.4\.4|9\.9\.9\.9|quad9|opendns|208\.67\.' -} - -FAILED_COUNT=0 -BOOTSTRAP_CANDIDATES="223.5.5.5 119.29.29.29 180.184.1.1" -DOMESTIC_CANDIDATES="https://dns.alidns.com/dns-query https://doh.pub/dns-query udp://223.5.5.5 udp://119.29.29.29" -FALLBACK_CANDIDATES="https://cloudflare-dns.com/dns-query https://dns.google/dns-query tls://1.1.1.1:853" - -for ns in $(current_default_nameservers); do - is_ipv4 "$ns" && BOOTSTRAP_CANDIDATES="$(append_unique "$BOOTSTRAP_CANDIDATES" "$ns")" -done -for ns in $(servers_for_role 'nameserver') $(servers_for_role 'direct-nameserver'); do - is_domestic_dns "$ns" && DOMESTIC_CANDIDATES="$(append_unique "$DOMESTIC_CANDIDATES" "$ns")" -done -for ns in $(servers_for_role 'fallback'); do - is_overseas_dns "$ns" && FALLBACK_CANDIDATES="$(append_unique "$FALLBACK_CANDIDATES" "$ns")" -done - -BOOTSTRAP="$(select_best "$BOOTSTRAP_CANDIDATES" www.baidu.com 223.5.5.5)" -NAMESERVER="$(select_best "$DOMESTIC_CANDIDATES" www.baidu.com https://dns.alidns.com/dns-query)" -PROXY_NS="tls://1.1.1.1:853" -FALLBACK_NS="$(select_best "$FALLBACK_CANDIDATES" www.google.com https://cloudflare-dns.com/dns-query)" - -APPLIED=false -if [ "$APPLY" = "1" ]; then - if apply_result; then - APPLIED=true - else - printf '{"success":false,"error":"apply_failed","message":"DNS 自动配置写入失败"}\n' - exit 1 - fi -fi - -END_TS="$(date +%s 2>/dev/null || echo "$START_TS")" -ELAPSED_MS=$(( (END_TS - START_TS) * 1000 )) - -printf '{' -printf '"success":true,' -printf '"applied":%s,' "$APPLIED" -printf '"restarted":false,' -json_pair bootstrap "$BOOTSTRAP"; printf ',' -json_pair nameserver "$NAMESERVER"; printf ',' -json_pair direct_nameserver "$BOOTSTRAP"; printf ',' -json_pair proxy_nameserver "$PROXY_NS"; printf ',' -json_pair fallback "$FALLBACK_NS"; printf ',' -printf '"failed_count":%s,' "$FAILED_COUNT" -printf '"elapsed_ms":%s' "$ELAPSED_MS" -printf '}\n' diff --git a/clashoo/files/usr/share/clashoo/net/fw4.sh b/clashoo/files/usr/share/clashoo/net/fw4.sh deleted file mode 100755 index 540c6b05..00000000 --- a/clashoo/files/usr/share/clashoo/net/fw4.sh +++ /dev/null @@ -1,898 +0,0 @@ -#!/bin/sh - -set -eu - -NFT_DIR="/var/run/clash" -SETS_RULES="${NFT_DIR}/fw4_sets.nft" -DSTNAT_RULES="${NFT_DIR}/fw4_dstnat.nft" -MANGLE_RULES="${NFT_DIR}/fw4_mangle.nft" -OUTPUT_RULES="${NFT_DIR}/fw4_output.nft" -BUILTIN_NFT_DIR="/usr/share/clashoo/nftables" -GEOIP_CN_NFT="${BUILTIN_NFT_DIR}/geoip_cn.nft" -GEOIP6_CN_NFT="${BUILTIN_NFT_DIR}/geoip6_cn.nft" -LOCAL_OUTPUT_TABLE="clashoo_local" -QUIC_BLOCK_TABLE="clashoo_quic" -# PROXY_FWMARK: inbound TPROXY mark, ip rule -> table PROXY_ROUTE_TABLE -> lo. -# CORE_ROUTING_MARK: mihomo outbound SO_MARK (= routing-mark in config). -# Must differ: otherwise mihomo egress is pulled to lo -> unreachable. -# When changing CORE_ROUTING_MARK, also update yum_change.sh routing_mark_dec. -PROXY_FWMARK="0x162" -PROXY_ROUTE_TABLE="0x162" -CORE_ROUTING_MARK="0x1a0a" # = 6666 -ACL_BYPASS_FWMARK="0x163" -SINGBOX_BYPASS_FWMARK="0x2024" -ACL_BYPASS_PREF="8998" -DNSMASQ_BYPASS_PREF="8999" - -uci_get() { - uci -q get "$1" 2>/dev/null || true -} - -bool_enabled() { - case "$1" in - 1|true|TRUE|yes|on) return 0 ;; - *) return 1 ;; - esac -} - -acl_bool() { - [ -n "$1" ] || return 0 - bool_enabled "$1" -} - -tun_available() { - ip tuntap add mode tun name cotuntest >/dev/null 2>&1 || return 1 - ip link del cotuntest >/dev/null 2>&1 || true - return 0 -} - -config_redir_port() { - uci_get clashoo.config.redir_port -} - -config_tproxy_port() { - local port - port="$(uci_get clashoo.config.tproxy_port)" - if [ -n "$port" ]; then - printf '%s\n' "$port" - else - config_redir_port - fi -} - -config_tcp_mode() { - uci_get clashoo.config.tcp_mode -} - -config_udp_mode() { - uci_get clashoo.config.udp_mode -} - -config_access_control() { - [ "$(uci_get clashoo.config.acl_migrated)" = "1" ] && { - printf '0\n' - return - } - uci_get clashoo.config.access_control -} - -acl_sections() { - uci -q show clashoo 2>/dev/null | sed -n 's/^clashoo\.\([^.=]*\)=lan_acl$/\1/p' -} - -acl_list() { - uci_get "$1" -} - -acl_sections_catchall_last() { - local section - for section in $(acl_sections); do - [ -z "$(acl_list "clashoo.${section}.ip")$(acl_list "clashoo.${section}.ip6")$(acl_list "clashoo.${section}.mac")" ] || printf '%s\n' "$section" - done - for section in $(acl_sections); do - [ -n "$(acl_list "clashoo.${section}.ip")$(acl_list "clashoo.${section}.ip6")$(acl_list "clashoo.${section}.mac")" ] || printf '%s\n' "$section" - done -} - -grouped_acl_enabled() { - local section - [ "$(uci_get clashoo.config.acl_migrated)" = "1" ] || return 1 - for section in $(acl_sections); do - [ "$(uci_get "clashoo.${section}.enabled")" != "0" ] && return 0 - done - return 1 -} - -acl_has_catchall() { - local section - for section in $(acl_sections); do - [ "$(uci_get "clashoo.${section}.enabled")" != "0" ] || continue - [ -z "$(acl_list "clashoo.${section}.ip")$(acl_list "clashoo.${section}.ip6")$(acl_list "clashoo.${section}.mac")" ] && return 0 - done - return 1 -} - -lan_acl_enabled() { - grouped_acl_enabled && return 0 - case "$(config_access_control)" in - 1|2) return 0 ;; - esac - return 1 -} - -config_enable_dns() { - uci_get clashoo.config.enable_dns -} - -config_dns_port() { - local port="" - if [ "$(uci_get clashoo.config.core_type)" != "singbox" ]; then - port="$(sed -n 's/^[[:space:]]*listen:.*:[[:space:]]*['"'"'"]*\([0-9]\{1,\}\)['"'"'"]*[[:space:]]*$/\1/p' /etc/clashoo/config.yaml 2>/dev/null | head -n1)" - fi - [ -n "$port" ] || port="$(uci_get clashoo.config.listen_port)" - printf '%s' "$port" | grep -Eq '^[0-9]+$' || port=1053 - printf '%s\n' "$port" -} - -lan_dns_split_enabled() { - lan_acl_enabled || return 1 - bool_enabled "$(config_enable_dns)" || return 1 - bool_enabled "$(config_ipv4_dns_hijack)" || bool_enabled "$(config_ipv6_dns_hijack)" -} - -tun_acl_enabled() { - lan_acl_enabled || return 1 - [ "$(config_tcp_mode)" = "tun" ] || [ "$(config_udp_mode)" = "tun" ] -} - -config_ipv4_dns_hijack() { - uci_get clashoo.config.ipv4_dns_hijack -} - -config_ipv6_dns_hijack() { - uci_get clashoo.config.ipv6_dns_hijack -} - -config_ipv4_proxy() { - uci_get clashoo.config.ipv4_proxy -} - -config_ipv6_proxy() { - uci_get clashoo.config.ipv6_proxy -} - -singbox_tun_active() { - [ "$(uci_get clashoo.config.core_type)" = "singbox" ] || return 1 - [ "$(config_tcp_mode)" = "tun" ] || [ "$(config_udp_mode)" = "tun" ] -} - -config_bypass_china() { - uci_get clashoo.config.bypass_china -} - -config_bypass_china_ipv6() { - local value - value="$(uci_get clashoo.config.bypass_china_ipv6)" - if [ -n "$value" ]; then - printf '%s\n' "$value" - else - config_bypass_china - fi -} - -config_block_quic() { - uci_get clashoo.config.block_quic -} - -config_bypass_port_mode() { - uci_get clashoo.config.bypass_port_mode -} - -config_bypass_port_custom() { - uci_get clashoo.config.bypass_port_custom -} - -config_legacy_bypass_port() { - uci_list clashoo.config.bypass_port -} - -config_proxy_tcp_dport() { - local mode custom legacy value - mode="$(config_bypass_port_mode)" - custom="$(config_bypass_port_custom)" - legacy="$(uci_get clashoo.config.proxy_tcp_dport)" - [ -z "$legacy" ] && legacy="$(config_legacy_bypass_port)" - - case "$mode" in - all) - # 空值在 render_port_match 中表示该协议的全部端口 - printf '%s\n' '' - ;; - common) - printf '%s\n' '22,53,80,443,8080,8443' - ;; - custom) - value="$custom" - [ -z "$value" ] && value="$legacy" - printf '%s\n' "$value" - ;; - *) - printf '%s\n' "$legacy" - ;; - esac -} - -config_proxy_udp_dport() { - local mode custom legacy value - mode="$(config_bypass_port_mode)" - custom="$(config_bypass_port_custom)" - legacy="$(uci_get clashoo.config.proxy_udp_dport)" - [ -z "$legacy" ] && legacy="$(config_legacy_bypass_port)" - - case "$mode" in - all) - printf '%s\n' '' - ;; - common) - printf '%s\n' '22,53,80,443,8080,8443' - ;; - custom) - value="$custom" - [ -z "$value" ] && value="$legacy" - printf '%s\n' "$value" - ;; - *) - printf '%s\n' "$legacy" - ;; - esac -} - -config_bypass_dscp() { - uci_list clashoo.config.bypass_dscp -} - -config_bypass_fwmark() { - uci_list clashoo.config.bypass_fwmark -} - -config_fake_ip_range6() { - local value - value="$(uci_get clashoo.config.fake_ip_range6)" - [ -n "$value" ] || value="fc00::/18" - [ "$(uci_get clashoo.config.enhanced_mode)" = "redir-host" ] && return 0 - bool_enabled "$(uci_get clashoo.config.enable_ipv6)" || return 0 - printf '%s\n' "$value" -} - -config_fake_ip_range() { - local value - value="$(uci_get clashoo.config.fake_ip_range)" - [ -n "$value" ] && { - printf '%s\n' "$value" - return - } - printf '198.18.0.1/16\n' -} - -uci_list() { - local key="$1" - uci -q show "$key" 2>/dev/null | sed -n "s/^${key}=//p" | sed "s/'//g" -} - -ensure_firewall_include() { - local name="$1" - local path="$2" - local chain="${3:-}" - local position="${4:-chain-pre}" - - uci -q batch <<-EOF >/dev/null - set firewall.${name}=include - set firewall.${name}.type='nftables' - set firewall.${name}.path='${path}' - set firewall.${name}.position='${position}' - $( [ -n "$chain" ] && printf "set firewall.%s.chain='%s'\n" "$name" "$chain" ) - commit firewall -EOF -} - -remove_firewall_include() { - local name="$1" - uci -q delete firewall."${name}" >/dev/null 2>&1 || true -} - -render_common_returns() { - local fake6 - fake6="$(config_fake_ip_range6)" - printf '%s\n' 'meta nfproto ipv4 ip daddr { 0.0.0.0/8, 10.0.0.0/8, 100.64.0.0/10, 127.0.0.0/8, 169.254.0.0/16, 172.16.0.0/12, 192.168.0.0/16, 224.0.0.0/4, 240.0.0.0/4 } return' - if [ -n "$fake6" ]; then - printf 'meta nfproto ipv6 ip6 daddr { ::1/128, fc00::/7, fe80::/10, ff00::/8 } ip6 daddr != %s return\n' "$fake6" - else - printf '%s\n' 'meta nfproto ipv6 ip6 daddr { ::1/128, fc00::/7, fe80::/10, ff00::/8 } return' - fi -} - -render_ip_elements() { - local list="$1" - local first=1 entry - for entry in $list; do - if [ "$first" -eq 0 ]; then - printf ', ' - fi - printf '%s' "$entry" - first=0 - done -} - -render_token_elements() { - printf '%s\n' "$1" | tr ',\t' ' ' | awk ' - BEGIN { first = 1 } - { - for (i = 1; i <= NF; i++) { - if ($i == "") - continue - if (!first) - printf ", " - printf "%s", $i - first = 0 - } - }' -} - -detect_coexist_fwmarks() { - # Merge co-installed proxy plugin fwmarks into bypass to avoid intercepting - # their traffic. Only when init.d exists (passwall:0x1 passwall2:0xff - # nikki:tproxy 0x80/tun 0x81 mask 0xff). - local marks="" - [ -x /etc/init.d/passwall ] && marks="$marks 0x1" - [ -x /etc/init.d/passwall2 ] && marks="$marks 0xff" - if [ -x /etc/init.d/nikki ]; then - local nm - nm="$(uci -q get nikki.routing.tproxy_fw_mark) $(uci -q get nikki.routing.tun_fw_mark)" - [ -z "$(echo "$nm" | tr -d ' ')" ] && nm="0x80 0x81" - marks="$marks $nm" - fi - printf '%s\n' "$marks" -} - -merge_fwmark_tokens() { - # Always bypass PROXY_FWMARK (inbound TPROXY) and CORE_ROUTING_MARK (core egress) - # so nft never traps them. Also merge co-installed plugin fwmarks for coexistence. - local coexist - coexist="$(detect_coexist_fwmarks)" - printf '%s %s %s %s\n' "$1" "$PROXY_FWMARK" "$CORE_ROUTING_MARK" "$coexist" | tr ',\t' ' ' | awk ' - BEGIN { first = 1 } - { - for (i = 1; i <= NF; i++) { - if ($i == "" || seen[$i]++) - continue - if (!first) - printf ", " - printf "%s", $i - first = 0 - } - }' -} - -render_port_match() { - local proto="$1" - local ports="$2" - local port_elements - - port_elements="$(render_token_elements "$ports")" - if [ -n "$port_elements" ]; then - printf 'meta l4proto %s %s dport { %s }' "$proto" "$proto" "$port_elements" - else - printf 'meta l4proto %s' "$proto" - fi -} - -render_acl_dns_rules() { - local redirect_port="$1" section ipv4 ipv6 mac ipv4_elements ipv6_elements mac_elements action - for section in $(acl_sections_catchall_last); do - [ "$(uci_get "clashoo.${section}.enabled")" != "0" ] || continue - if acl_bool "$(uci_get "clashoo.${section}.dns")"; then - action="counter redirect to :${redirect_port}" - elif singbox_tun_active; then - action="meta mark set ${SINGBOX_BYPASS_FWMARK} ct mark set meta mark counter return" - else - action="counter return" - fi - ipv4="$(acl_list "clashoo.${section}.ip")" - ipv6="$(acl_list "clashoo.${section}.ip6")" - mac="$(acl_list "clashoo.${section}.mac")" - ipv4_elements="$(render_ip_elements "$ipv4")" - ipv6_elements="$(render_ip_elements "$ipv6")" - mac_elements="$(render_ip_elements "$mac")" - - if [ -z "$ipv4_elements$ipv6_elements$mac_elements" ]; then - bool_enabled "$(config_ipv4_dns_hijack)" && printf 'meta nfproto ipv4 meta l4proto { tcp, udp } th dport 53 %s\n' "$action" - bool_enabled "$(config_ipv6_dns_hijack)" && printf 'meta nfproto ipv6 meta l4proto { tcp, udp } th dport 53 %s\n' "$action" - continue - fi - if [ -n "$ipv4_elements" ] && bool_enabled "$(config_ipv4_dns_hijack)"; then - printf 'meta nfproto ipv4 ip saddr { %s } meta l4proto { tcp, udp } th dport 53 %s\n' "$ipv4_elements" "$action" - fi - if [ -n "$ipv6_elements" ] && bool_enabled "$(config_ipv6_dns_hijack)"; then - printf 'meta nfproto ipv6 ip6 saddr { %s } meta l4proto { tcp, udp } th dport 53 %s\n' "$ipv6_elements" "$action" - fi - if [ -n "$mac_elements" ]; then - bool_enabled "$(config_ipv4_dns_hijack)" && printf 'meta nfproto ipv4 ether saddr { %s } meta l4proto { tcp, udp } th dport 53 %s\n' "$mac_elements" "$action" - bool_enabled "$(config_ipv6_dns_hijack)" && printf 'meta nfproto ipv6 ether saddr { %s } meta l4proto { tcp, udp } th dport 53 %s\n' "$mac_elements" "$action" - fi - done -} - -render_acl_proxy_rules() { - local mode="$1" proto="$2" port_match="$3" target_port="$4" - local section ipv4 ipv6 mac ipv4_elements ipv6_elements mac_elements enabled action4 action6 - - for section in $(acl_sections_catchall_last); do - [ "$(uci_get "clashoo.${section}.enabled")" != "0" ] || continue - enabled="$(uci_get "clashoo.${section}.proxy")" - case "$mode" in - redirect) - if acl_bool "$enabled"; then - if singbox_tun_active; then - action4="${port_match} ct mark set ${SINGBOX_BYPASS_FWMARK} counter redirect to :${target_port}" - else - action4="${port_match} counter redirect to :${target_port}" - fi - action6="$action4" - elif singbox_tun_active; then - action4="meta l4proto ${proto} meta mark set ${SINGBOX_BYPASS_FWMARK} ct mark set meta mark counter return" - action6="$action4" - else - action4="meta l4proto ${proto} counter return" - action6="$action4" - fi - ;; - tproxy) - if acl_bool "$enabled"; then - if singbox_tun_active; then - action4="${port_match} ct mark set ${SINGBOX_BYPASS_FWMARK} tproxy ip to :${target_port} meta mark set ${PROXY_FWMARK} counter accept" - action6="${port_match} ct mark set ${SINGBOX_BYPASS_FWMARK} tproxy ip6 to :${target_port} meta mark set ${PROXY_FWMARK} counter accept" - else - action4="${port_match} tproxy ip to :${target_port} meta mark set ${PROXY_FWMARK} counter accept" - action6="${port_match} tproxy ip6 to :${target_port} meta mark set ${PROXY_FWMARK} counter accept" - fi - elif singbox_tun_active; then - action4="meta l4proto ${proto} meta mark set ${SINGBOX_BYPASS_FWMARK} ct mark set meta mark counter return" - action6="$action4" - else - action4="meta l4proto ${proto} counter return" - action6="$action4" - fi - ;; - tun) - if acl_bool "$enabled"; then - action4="meta l4proto ${proto} counter return" - elif singbox_tun_active; then - action4="meta l4proto ${proto} meta mark set ${SINGBOX_BYPASS_FWMARK} ct mark set meta mark counter accept" - else - action4="meta l4proto ${proto} meta mark set ${ACL_BYPASS_FWMARK} counter accept" - fi - action6="$action4" - ;; - esac - - ipv4="$(acl_list "clashoo.${section}.ip")" - ipv6="$(acl_list "clashoo.${section}.ip6")" - mac="$(acl_list "clashoo.${section}.mac")" - ipv4_elements="$(render_ip_elements "$ipv4")" - ipv6_elements="$(render_ip_elements "$ipv6")" - mac_elements="$(render_ip_elements "$mac")" - - if [ -z "$ipv4_elements$ipv6_elements$mac_elements" ]; then - bool_enabled "$(config_ipv4_proxy)" && printf 'meta nfproto ipv4 %s\n' "$action4" - bool_enabled "$(config_ipv6_proxy)" && printf 'meta nfproto ipv6 %s\n' "$action6" - continue - fi - if [ -n "$ipv4_elements" ] && bool_enabled "$(config_ipv4_proxy)"; then - printf 'meta nfproto ipv4 ip saddr { %s } %s\n' "$ipv4_elements" "$action4" - fi - if [ -n "$ipv6_elements" ] && bool_enabled "$(config_ipv6_proxy)"; then - printf 'meta nfproto ipv6 ip6 saddr { %s } %s\n' "$ipv6_elements" "$action6" - fi - if [ -n "$mac_elements" ]; then - bool_enabled "$(config_ipv4_proxy)" && printf 'meta nfproto ipv4 ether saddr { %s } %s\n' "$mac_elements" "$action4" - bool_enabled "$(config_ipv6_proxy)" && printf 'meta nfproto ipv6 ether saddr { %s } %s\n' "$mac_elements" "$action6" - fi - done -} - -# Split proxied clients to the core DNS while ACL-bypassed clients use dnsmasq. -# Gated on UCI IPv4/IPv6 toggles. -# return 0: no output when both off, avoid set -e false-positive. -render_dns_hijack() { - local access_control="$1" redirect_port=53 - if lan_dns_split_enabled; then - redirect_port="$(config_dns_port)" - fi - if grouped_acl_enabled; then - render_acl_dns_rules "$redirect_port" - acl_has_catchall && return 0 - else - [ "$access_control" = "1" ] && printf '%s\n' 'ip saddr != @clash_proxy_lan return' - [ "$access_control" = "2" ] && printf '%s\n' 'ip saddr @clash_reject_lan return' - fi - bool_enabled "$(config_ipv4_dns_hijack)" && \ - printf '%s\n' "meta nfproto ipv4 meta l4proto { tcp, udp } th dport 53 counter redirect to :${redirect_port}" - bool_enabled "$(config_ipv6_dns_hijack)" && \ - printf '%s\n' "meta nfproto ipv6 meta l4proto { tcp, udp } th dport 53 counter redirect to :${redirect_port}" - return 0 -} - -apply_local_output_rule() { - local redir_port fake_ip_range tcp_mode bypass_fwmark bypass_china - local fwmark_elements fwmark_rule china_set china_rule dnsmasq_rule dnsmasq_uid - redir_port="$(config_redir_port)" - fake_ip_range="$(config_fake_ip_range)" - tcp_mode="$(config_tcp_mode)" - bypass_fwmark="$(config_bypass_fwmark)" - bypass_china="$(config_bypass_china)" - - # Keep local-output redirect usable when tun mode is selected but tun - # device is unavailable on the system. - if [ "$tcp_mode" = "tun" ] && ! tun_available; then - tcp_mode="redirect" - fi - - nft delete table ip ${LOCAL_OUTPUT_TABLE} >/dev/null 2>&1 || true - - # Only apply local output redirect when tcp_mode is redirect - [ "$tcp_mode" != "redirect" ] && return 0 - - # bypass mihomo's own marks (prevent self-hijack -> dead loop) - fwmark_rule="" - fwmark_elements="$(merge_fwmark_tokens "$bypass_fwmark")" - [ -n "$fwmark_elements" ] && fwmark_rule="meta mark { ${fwmark_elements} } return" - - # CN IP bypass (uses clashoo_china set from geoip_cn.nft) - china_set="" - china_rule="" - if bool_enabled "$bypass_china" && [ -s "$GEOIP_CN_NFT" ]; then - china_set="$(cat "$GEOIP_CN_NFT")" - china_rule="ip daddr @clashoo_china return" - fi - - dnsmasq_rule="" - if lan_dns_split_enabled; then - dnsmasq_uid="$(id -u dnsmasq 2>/dev/null)" - printf '%s' "$dnsmasq_uid" | grep -Eq '^[0-9]+$' && dnsmasq_rule="meta skuid ${dnsmasq_uid} return" - fi - - nft -f - </dev/null 2>&1 || true -} - -remove_acl_bypass_rules() { - local dnsmasq_uid - ip rule del pref "$ACL_BYPASS_PREF" fwmark "$ACL_BYPASS_FWMARK" lookup main >/dev/null 2>&1 || true - ip -6 rule del pref "$ACL_BYPASS_PREF" fwmark "$ACL_BYPASS_FWMARK" lookup main >/dev/null 2>&1 || true - dnsmasq_uid="$(id -u dnsmasq 2>/dev/null)" - if printf '%s' "$dnsmasq_uid" | grep -Eq '^[0-9]+$'; then - ip rule del pref "$DNSMASQ_BYPASS_PREF" uidrange "${dnsmasq_uid}-${dnsmasq_uid}" lookup main >/dev/null 2>&1 || true - ip -6 rule del pref "$DNSMASQ_BYPASS_PREF" uidrange "${dnsmasq_uid}-${dnsmasq_uid}" lookup main >/dev/null 2>&1 || true - fi -} - -apply_acl_bypass_rules() { - local dnsmasq_uid - remove_acl_bypass_rules - tun_acl_enabled || return 0 - ip rule add pref "$ACL_BYPASS_PREF" fwmark "$ACL_BYPASS_FWMARK" lookup main >/dev/null 2>&1 || true - ip -6 rule add pref "$ACL_BYPASS_PREF" fwmark "$ACL_BYPASS_FWMARK" lookup main >/dev/null 2>&1 || true - dnsmasq_uid="$(id -u dnsmasq 2>/dev/null)" - if printf '%s' "$dnsmasq_uid" | grep -Eq '^[0-9]+$'; then - ip rule add pref "$DNSMASQ_BYPASS_PREF" uidrange "${dnsmasq_uid}-${dnsmasq_uid}" lookup main >/dev/null 2>&1 || true - ip -6 rule add pref "$DNSMASQ_BYPASS_PREF" uidrange "${dnsmasq_uid}-${dnsmasq_uid}" lookup main >/dev/null 2>&1 || true - fi -} - -apply_block_quic_rule() { - local fake_ip_range china_set china_rule scope - nft delete table inet ${QUIC_BLOCK_TABLE} >/dev/null 2>&1 || true - bool_enabled "$(config_block_quic)" || return 0 - - fake_ip_range="$(config_fake_ip_range)" - china_set="" - scope="ip daddr ${fake_ip_range}" - if [ "$(uci_get clashoo.config.enhanced_mode)" != "fake-ip" ]; then - if bool_enabled "$(config_bypass_china)" && [ -s "$GEOIP_CN_NFT" ]; then - china_set="$(cat "$GEOIP_CN_NFT")" - china_rule="ip daddr @clashoo_china return" - fi - scope="" - fi - - nft -f - </dev/null 2>&1 || true -} - -write_empty_set() { - local set_name="$1" - local set_type="$2" - - printf 'set %s {\n\ttype %s;\n\tflags interval;\n\tauto-merge;\n}\n\n' "$set_name" "$set_type" -} - -append_set_from_file_or_empty() { - local file_path="$1" - local set_name="$2" - local set_type="$3" - - if [ -s "$file_path" ]; then - cat "$file_path" - printf '\n' - else - write_empty_set "$set_name" "$set_type" - fi -} - -generate_rules() { - local redir_port tproxy_port tcp_mode udp_mode access_control fake_ip_range proxy_lan_ips reject_lan_ips - local proxy_tcp_dport proxy_udp_dport bypass_dscp bypass_fwmark bypass_china bypass_china_ipv6 - local acl_catchall=0 - redir_port="$(config_redir_port)" - tproxy_port="$(config_tproxy_port)" - tcp_mode="$(config_tcp_mode)" - udp_mode="$(config_udp_mode)" - access_control="$(config_access_control)" - grouped_acl_enabled && acl_has_catchall && acl_catchall=1 - bypass_china="$(config_bypass_china)" - bypass_china_ipv6="$(config_bypass_china_ipv6)" - proxy_tcp_dport="$(config_proxy_tcp_dport)" - proxy_udp_dport="$(config_proxy_udp_dport)" - bypass_dscp="$(config_bypass_dscp)" - bypass_fwmark="$(config_bypass_fwmark)" - fake_ip_range="$(config_fake_ip_range)" - proxy_lan_ips="$(uci_list clashoo.config.proxy_lan_ips)" - reject_lan_ips="$(uci_list clashoo.config.reject_lan_ips)" - - # When tun device is unavailable, fall back to non-tun transparent modes - # so routing rules still take effect for sing-box redirect/tproxy inbounds. - if [ "$tcp_mode" = "tun" ] || [ "$udp_mode" = "tun" ]; then - if ! tun_available; then - [ "$tcp_mode" = "tun" ] && tcp_mode="redirect" - [ "$udp_mode" = "tun" ] && udp_mode="tproxy" - fi - fi - - mkdir -p "$NFT_DIR" - - # Build optional elements lines (nftables rejects empty elements = {}) - local proxy_elements reject_elements dscp_elements fwmark_elements - proxy_elements="$(render_ip_elements "$proxy_lan_ips")" - reject_elements="$(render_ip_elements "$reject_lan_ips")" - dscp_elements="$(render_token_elements "$bypass_dscp")" - fwmark_elements="$(merge_fwmark_tokens "$bypass_fwmark")" - tcp_match="$(render_port_match tcp "$proxy_tcp_dport")" - udp_match="$(render_port_match udp "$proxy_udp_dport")" - - { - printf 'set clashoo_localnetwork {\n\ttype ipv4_addr;\n\tflags interval;\n\tauto-merge;\n' - printf '\telements = { 0.0.0.0/8, 10.0.0.0/8, 100.64.0.0/10, 127.0.0.0/8, 169.254.0.0/16, 172.16.0.0/12, 192.168.0.0/16, 224.0.0.0/4, 240.0.0.0/4 }\n}\n\n' - - append_set_from_file_or_empty "$GEOIP_CN_NFT" clashoo_china ipv4_addr - append_set_from_file_or_empty "$GEOIP6_CN_NFT" clashoo_china6 ipv6_addr - - printf 'set clash_proxy_lan {\n\ttype ipv4_addr;\n\tflags interval;\n\tauto-merge;\n' - [ -n "$proxy_elements" ] && printf '\telements = { %s }\n' "$proxy_elements" - printf '}\n\n' - - printf 'set clash_reject_lan {\n\ttype ipv4_addr;\n\tflags interval;\n\tauto-merge;\n' - [ -n "$reject_elements" ] && printf '\telements = { %s }\n' "$reject_elements" - printf '}\n\n' - - if grouped_acl_enabled && [ "$tcp_mode" = "tun" ]; then - printf 'chain clashoo_acl_tun_tcp {\n' - render_acl_proxy_rules tun tcp "$tcp_match" "$tproxy_port" - printf '}\n\n' - fi - if grouped_acl_enabled && [ "$udp_mode" = "tun" ]; then - printf 'chain clashoo_acl_tun_udp {\n' - render_acl_proxy_rules tun udp "$udp_match" "$tproxy_port" - printf '}\n' - fi - } > "$SETS_RULES" - - : > "$OUTPUT_RULES" - - -# DNS hijack rules go atop DSTNAT_RULES: must run for all TCP modes - # (redirect/tproxy/tun) and BEFORE proxy redirect rules so port 53 is not stolen. - render_dns_hijack "$access_control" > "$DSTNAT_RULES" - - -# TCP rules: redirect mode appends proxy redirect; tproxy/tun skip this chain - case "$tcp_mode" in - redirect) - tcp_match="$(render_port_match tcp "$proxy_tcp_dport")" - cat >> "$DSTNAT_RULES" < "$MANGLE_RULES" - else - : > "$MANGLE_RULES" - fi -} - -apply_rules() { - generate_rules - ensure_firewall_include clash_fw4_sets "$SETS_RULES" '' table-pre - ensure_firewall_include clash_fw4_dstnat "$DSTNAT_RULES" dstnat - remove_firewall_include clash_fw4_output - if [ -s "$MANGLE_RULES" ]; then - _route_table_dec="$((PROXY_ROUTE_TABLE))" - ensure_firewall_include clash_fw4_mangle "$MANGLE_RULES" mangle_prerouting - ip rule show 2>/dev/null | grep -q "fwmark ${PROXY_FWMARK}.*lookup ${_route_table_dec}" || - ip rule add fwmark "$PROXY_FWMARK" table "$PROXY_ROUTE_TABLE" >/dev/null 2>&1 || true - ip route show table "$PROXY_ROUTE_TABLE" 2>/dev/null | grep -q 'local 0.0.0.0/0 dev lo' || - ip route add local 0.0.0.0/0 dev lo table "$PROXY_ROUTE_TABLE" >/dev/null 2>&1 || true - if bool_enabled "$(config_ipv6_proxy)"; then - ip -6 rule show 2>/dev/null | grep -q "fwmark ${PROXY_FWMARK}.*lookup ${_route_table_dec}" || - ip -6 rule add fwmark "$PROXY_FWMARK" table "$PROXY_ROUTE_TABLE" >/dev/null 2>&1 || true - ip -6 route show table "$PROXY_ROUTE_TABLE" 2>/dev/null | grep -q 'local default dev lo' || - ip -6 route add local ::/0 dev lo table "$PROXY_ROUTE_TABLE" >/dev/null 2>&1 || true - else - ip -6 rule del fwmark "$PROXY_FWMARK" table "$PROXY_ROUTE_TABLE" >/dev/null 2>&1 || true - ip -6 route del local ::/0 dev lo table "$PROXY_ROUTE_TABLE" >/dev/null 2>&1 || true - fi - else - remove_firewall_include clash_fw4_mangle - ip rule del fwmark "$PROXY_FWMARK" table "$PROXY_ROUTE_TABLE" >/dev/null 2>&1 || true - ip route del local 0.0.0.0/0 dev lo table "$PROXY_ROUTE_TABLE" >/dev/null 2>&1 || true - ip -6 rule del fwmark "$PROXY_FWMARK" table "$PROXY_ROUTE_TABLE" >/dev/null 2>&1 || true - ip -6 route del local ::/0 dev lo table "$PROXY_ROUTE_TABLE" >/dev/null 2>&1 || true - fi - /etc/init.d/firewall restart >/dev/null 2>&1 || /etc/init.d/firewall reload >/dev/null 2>&1 || true - apply_acl_bypass_rules - apply_local_output_rule - apply_block_quic_rule -} - -remove_rules() { - remove_acl_bypass_rules - remove_local_output_rule - remove_block_quic_rule - remove_firewall_include clash_fw4_sets - remove_firewall_include clash_fw4_dstnat - remove_firewall_include clash_fw4_output - remove_firewall_include clash_fw4_mangle - remove_firewall_include clash_fw4_forward - uci commit firewall >/dev/null 2>&1 || true - rm -f "$SETS_RULES" "$DSTNAT_RULES" "$OUTPUT_RULES" "$MANGLE_RULES" - ip rule del fwmark "$PROXY_FWMARK" table "$PROXY_ROUTE_TABLE" >/dev/null 2>&1 || true - ip route del local 0.0.0.0/0 dev lo table "$PROXY_ROUTE_TABLE" >/dev/null 2>&1 || true - ip -6 rule del fwmark "$PROXY_FWMARK" table "$PROXY_ROUTE_TABLE" >/dev/null 2>&1 || true - ip -6 route del local ::/0 dev lo table "$PROXY_ROUTE_TABLE" >/dev/null 2>&1 || true - /etc/init.d/firewall restart >/dev/null 2>&1 || /etc/init.d/firewall reload >/dev/null 2>&1 || true -} - -case "${1:-}" in - apply) - apply_rules - ;; - remove) - remove_rules - ;; - *) - echo "Usage: $0 {apply|remove}" >&2 - exit 1 - ;; -esac diff --git a/clashoo/files/usr/share/clashoo/net/log_format.awk b/clashoo/files/usr/share/clashoo/net/log_format.awk deleted file mode 100644 index 0813c3b7..00000000 --- a/clashoo/files/usr/share/clashoo/net/log_format.awk +++ /dev/null @@ -1,43 +0,0 @@ -# clashoo 运行日志格式化 -# 输出: MM-DD HH:MM:SS msg - -# mihomo 原生行: time="YYYY-MM-DDTHH:MM:SS..." level=... msg="..." -/^time="[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]T[0-9][0-9]:[0-9][0-9]:[0-9][0-9]/ { - # extract YYYY-MM-DD and HH:MM:SS - ts_date = substr($0, 12, 5) # MM-DD - ts_time = substr($0, 18, 8) # HH:MM:SS - utc_h = substr(ts_time, 1, 2) + 0 - cst_h = (utc_h + 8) % 24 - ts = sprintf("%s %02d:%s", ts_date, cst_h, substr(ts_time, 4)) - - prefix = "" - if (match($0, /level=warning /)) prefix = " [warn]" - else if (match($0, /level=error /)) prefix = " [err]" - else if (match($0, /level=fatal /)) prefix = " [fatal]" - - i = index($0, "msg=\"") - if (i > 0) { - rest = substr($0, i + 5) - sub(/"[[:space:]]*$/, "", rest) - print ts prefix " " rest - next - } - print ts " " $0 - next -} - -# log_msg 行: " YYYY-MM-DD HH:MM:SS - msg" → "MM-DD HH:MM:SS msg" -/^[[:space:]]+[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9][[:space:]]+[0-9][0-9]:[0-9][0-9]:[0-9][0-9]/ { - gsub(/^[[:space:]]+/, "") # trim leading space - ts_date = substr($0, 6, 5) # MM-DD - ts_time = substr($0, 12, 8) # HH:MM:SS - # remove "YYYY-MM-DD HH:MM:SS - " prefix - sub(/^[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9][[:space:]]+[0-9][0-9]:[0-9][0-9]:[0-9][0-9][[:space:]]*-[[:space:]]*/, "") - print ts_date " " ts_time " " $0 - next -} - -# 空行丢弃 -NF == 0 { next } - -{ print } diff --git a/clashoo/files/usr/share/clashoo/nftables/geoip6_cn.nft b/clashoo/files/usr/share/clashoo/nftables/geoip6_cn.nft deleted file mode 100644 index 5cd2612d..00000000 --- a/clashoo/files/usr/share/clashoo/nftables/geoip6_cn.nft +++ /dev/null @@ -1,3496 +0,0 @@ -set clashoo_china6 { - type ipv6_addr; - flags interval; - auto-merge; - elements = { - 2001:250::/30, - 2001:254::/33, - 2001:255::/32, - 2001:7fa:5::/48, - 2001:c68::/32, - 2001:cc0::/32, - 2001:da8::/32, - 2001:daa:1::/48, - 2001:daa:2::/47, - 2001:daa:4::/47, - 2001:daa:6::/48, - 2001:daa:9::/48, - 2001:dc7::/45, - 2001:dc7:9::/48, - 2001:dc7:a::/47, - 2001:dc7:c::/46, - 2001:dc7:10::/44, - 2001:dc7:20::/43, - 2001:dc7:40::/42, - 2001:dc7:80::/41, - 2001:dc7:100::/40, - 2001:dc7:200::/39, - 2001:dc7:400::/38, - 2001:dc7:800::/37, - 2001:dc7:1000::/36, - 2001:dc7:2000::/35, - 2001:dc7:4000::/34, - 2001:dc7:8000::/33, - 2001:dd8:1::/48, - 2001:dd9::/48, - 2001:df5:7800::/48, - 2001:4510:400::/40, - 2001:4510:1480::/41, - 2001:4511:1480::/41, - 2400:1040::/32, - 2400:1160::/32, - 2400:12c0::/32, - 2400:1340::/32, - 2400:1380::/32, - 2400:15c0::/32, - 2400:1640::/32, - 2400:16c0::/32, - 2400:1740::/32, - 2400:17c0::/32, - 2400:1840::/32, - 2400:18c0::/32, - 2400:1940::/32, - 2400:19a0::/32, - 2400:19c0::/32, - 2400:1a40::/32, - 2400:1ac0::/32, - 2400:1b40::/32, - 2400:1cc0::/32, - 2400:1d40::/32, - 2400:1dc0::/32, - 2400:1e40::/32, - 2400:1ec0::/32, - 2400:1f40::/32, - 2400:1fc0::/32, - 2400:3040::/32, - 2400:3140::/32, - 2400:3160::/32, - 2400:31c0::/32, - 2400:3200::/32, - 2400:32c0::/32, - 2400:3340::/32, - 2400:33c0::/32, - 2400:3440::/32, - 2400:34c0::/32, - 2400:3540::/32, - 2400:35c0::/32, - 2400:3600::/32, - 2400:3640::/32, - 2400:3660::/32, - 2400:36c0::/32, - 2400:38c0::/32, - 2400:39c0::/32, - 2400:3a00::/32, - 2400:3a40::/32, - 2400:3b40::/32, - 2400:3c40::/32, - 2400:3cc0::/32, - 2400:3e00::/32, - 2400:3f40::/32, - 2400:3f60::/46, - 2400:3f60:5::/48, - 2400:3f60:6::/47, - 2400:3f60:8::/45, - 2400:3f60:13::/48, - 2400:3f60:14::/46, - 2400:3f60:18::/45, - 2400:3f60:20::/43, - 2400:3f60:40::/42, - 2400:3f60:80::/41, - 2400:3f60:100::/40, - 2400:3f60:200::/39, - 2400:3f60:400::/38, - 2400:3f60:800::/37, - 2400:3f60:1000::/36, - 2400:3f60:2000::/35, - 2400:3f60:4000::/34, - 2400:3f60:8000::/33, - 2400:3fc0::/32, - 2400:4440::/32, - 2400:44c0::/32, - 2400:4540::/32, - 2400:4600::/32, - 2400:4640::/32, - 2400:46c0::/32, - 2400:4920::/32, - 2400:4bc0::/32, - 2400:4e00::/32, - 2400:4e40::/32, - 2400:5080::/32, - 2400:5280:1400::/38, - 2400:5280:1c00::/38, - 2400:5280:3400::/38, - 2400:5280:5000::/36, - 2400:5280:6000::/35, - 2400:5280:8000::/34, - 2400:5280:c000::/35, - 2400:5280:e000::/36, - 2400:5280:f000::/37, - 2400:5280:f800::/38, - 2400:5400::/32, - 2400:5580::/32, - 2400:55c0::/32, - 2400:55e0::/32, - 2400:5600::/32, - 2400:5640::/32, - 2400:56c0::/32, - 2400:57c0::/32, - 2400:5840::/32, - 2400:5a00::/32, - 2400:5a40::/32, - 2400:5a60::/41, - 2400:5a60:80::/42, - 2400:5a60:c0::/43, - 2400:5a60:e0::/44, - 2400:5a60:f0::/45, - 2400:5a60:f8::/46, - 2400:5a60:fc::/47, - 2400:5a60:fe::/48, - 2400:5a60:100::/40, - 2400:5a60:200::/39, - 2400:5a60:400::/38, - 2400:5a60:800::/37, - 2400:5a60:1000::/36, - 2400:5a60:2000::/35, - 2400:5a60:4000::/34, - 2400:5a60:8001::/48, - 2400:5a60:8002::/47, - 2400:5a60:8004::/46, - 2400:5a60:8008::/45, - 2400:5a60:8010::/44, - 2400:5a60:8020::/43, - 2400:5a60:8040::/42, - 2400:5a60:8080::/41, - 2400:5a60:8100::/40, - 2400:5a60:8200::/39, - 2400:5a60:8400::/38, - 2400:5a60:8800::/37, - 2400:5a60:9000::/36, - 2400:5a60:a000::/35, - 2400:5a60:c000::/34, - 2400:5ac0::/32, - 2400:5b40::/32, - 2400:5bc0::/32, - 2400:5c40::/32, - 2400:5c80::/32, - 2400:5cc0::/32, - 2400:5e20::/32, - 2400:5e80::/32, - 2400:5ee0::/32, - 2400:5fc0::/32, - 2400:6000::/32, - 2400:6040::/32, - 2400:60c0::/32, - 2400:61c0::/32, - 2400:6200::/32, - 2400:6600::/32, - 2400:6640::/32, - 2400:66a0::/32, - 2400:66c0::/32, - 2400:66e0::/32, - 2400:6740::/32, - 2400:67a0::/32, - 2400:67c0::/32, - 2400:6840::/32, - 2400:68c0::/32, - 2400:6940::/32, - 2400:69c0::/32, - 2400:6a00::/32, - 2400:6a40::/32, - 2400:6ac0::/32, - 2400:6b40::/32, - 2400:6bc0::/32, - 2400:6c40::/32, - 2400:6cc0::/32, - 2400:6d40::/32, - 2400:6da0::/32, - 2400:6dc0::/32, - 2400:6e00::/32, - 2400:6e40::/32, - 2400:6e60::/32, - 2400:6ec0::/32, - 2400:6f40::/32, - 2400:6f80::/32, - 2400:6fc0::/32, - 2400:7040::/32, - 2400:70a0::/32, - 2400:7100::/32, - 2400:7140::/32, - 2400:71c0::/32, - 2400:7200::/32, - 2400:7240::/32, - 2400:72c0::/32, - 2400:7340::/32, - 2400:73c0::/32, - 2400:73e0::/32, - 2400:7440::/32, - 2400:74c0::/32, - 2400:7540::/32, - 2400:75a0::/28, - 2400:75c0::/32, - 2400:7640::/32, - 2400:7680::/32, - 2400:76c0::/32, - 2400:7740::/32, - 2400:77c0::/32, - 2400:79c0::/32, - 2400:7ae0::/32, - 2400:7bc0::/32, - 2400:7f80::/32, - 2400:7fc0::/32, - 2400:8080::/32, - 2400:8200::/31, - 2400:82c0::/32, - 2400:8580::/32, - 2400:8600::/32, - 2400:86a0::/32, - 2400:86e0::/32, - 2400:8780::/32, - 2400:87c0::/32, - 2400:8840::/32, - 2400:8920::/32, - 2400:8980::/32, - 2400:89c0::/32, - 2400:8be0::/32, - 2400:8ce0::/32, - 2400:8e00::/32, - 2400:8e60::/32, - 2400:8f00::/32, - 2400:8f60::/32, - 2400:8fc0::/32, - 2400:9020::/32, - 2400:9040::/32, - 2400:9380:8001::/48, - 2400:9380:8003::/48, - 2400:9380:8021::/48, - 2400:9380:8040::/48, - 2400:9380:8140::/48, - 2400:9380:8201::/48, - 2400:9380:8301::/48, - 2400:9380:9001::/48, - 2400:9380:9009::/48, - 2400:9380:9020::/47, - 2400:9380:9050::/47, - 2400:9380:9060::/48, - 2400:9380:9071::/48, - 2400:9380:9080::/47, - 2400:9380:90b1::/48, - 2400:9380:90b2::/47, - 2400:9380:90b4::/46, - 2400:9380:9109::/48, - 2400:9380:9121::/48, - 2400:9380:9220::/47, - 2400:9380:9250::/47, - 2400:9380:9260::/48, - 2400:9380:9271::/48, - 2400:9380:9280::/47, - 2400:9380:9282::/48, - 2400:9380:92b1::/48, - 2400:9380:92b2::/47, - 2400:9380:92b4::/46, - 2400:93e0::/32, - 2400:9520::/32, - 2400:9580::/32, - 2400:95c0::/32, - 2400:95e0::/32, - 2400:9600::/32, - 2400:9620::/32, - 2400:98c0::/32, - 2400:9960::/32, - 2400:99e0::/32, - 2400:9a00::/32, - 2400:9ca0::/32, - 2400:9e00::/32, - 2400:a320::/32, - 2400:a380::/32, - 2400:a420::/32, - 2400:a480::/32, - 2400:a5a0::/32, - 2400:a6a0::/39, - 2400:a6a0:300::/40, - 2400:a6a0:400::/38, - 2400:a6a0:800::/37, - 2400:a6a0:1000::/36, - 2400:a6a0:2000::/35, - 2400:a6a0:4000::/34, - 2400:a6a0:8000::/33, - 2400:a780::/32, - 2400:a860::/32, - 2400:a8a0::/32, - 2400:a8c0::/32, - 2400:a900::/32, - 2400:a980::/29, - 2400:a9a0::/32, - 2400:abc0::/32, - 2400:ae00::/32, - 2400:b200::/32, - 2400:b500::/32, - 2400:b600::/32, - 2400:b620::/32, - 2400:b6c0::/32, - 2400:b700::/32, - 2400:b9a0::/32, - 2400:b9c0::/32, - 2400:ba00::/32, - 2400:be00::/32, - 2400:bf00::/32, - 2400:c200::/32, - 2400:c380::/32, - 2400:c840::/32, - 2400:c8c0::/32, - 2400:c940::/32, - 2400:c9c0::/32, - 2400:ca40::/32, - 2400:cac0::/32, - 2400:cb40::/32, - 2400:cb80::/33, - 2400:cb80:8000::/40, - 2400:cb80:8100::/43, - 2400:cb80:8120::/44, - 2400:cb80:8130::/45, - 2400:cb80:8138::/47, - 2400:cb80:813a::/48, - 2400:cb80:813c::/47, - 2400:cb80:813e::/48, - 2400:cb80:8140::/42, - 2400:cb80:8180::/41, - 2400:cb80:8200::/39, - 2400:cb80:8400::/38, - 2400:cb80:8800::/37, - 2400:cb80:9000::/36, - 2400:cb80:a000::/35, - 2400:cb80:c000::/34, - 2400:cbc0::/32, - 2400:cc40::/32, - 2400:cc80::/32, - 2400:ccc0::/32, - 2400:cd40::/32, - 2400:cda0::/32, - 2400:cdc0::/32, - 2400:ce00::/32, - 2400:ce40::/32, - 2400:cf40::/32, - 2400:cfc0::/32, - 2400:d0a0::/32, - 2400:d0c0::/32, - 2400:d100::/32, - 2400:d160::/32, - 2400:d1c0::/32, - 2400:d200::/32, - 2400:d300::/32, - 2400:d440::/32, - 2400:d600::/32, - 2400:d6a0::/32, - 2400:d6c0::/32, - 2400:d720::/32, - 2400:d780::/32, - 2400:d7a0::/32, - 2400:da00::/32, - 2400:da60::/32, - 2400:dd00::/28, - 2400:dd40::/32, - 2400:dda0::/32, - 2400:de00::/32, - 2400:de80::/32, - 2400:dee0::/32, - 2400:e0c0::/32, - 2400:e680::/32, - 2400:e7e0::/32, - 2400:e880::/32, - 2400:ebc0::/32, - 2400:ed60::/32, - 2400:eda0::/32, - 2400:edc0::/32, - 2400:ee00::/32, - 2400:eec0::/32, - 2400:ef40::/32, - 2400:f480::/32, - 2400:f5c0::/32, - 2400:f6e0::/32, - 2400:f720::/32, - 2400:f7c0::/32, - 2400:f840::/32, - 2400:f860::/32, - 2400:f980::/32, - 2400:fac0::/32, - 2400:fb40::/32, - 2400:fb60::/32, - 2400:fbc0::/32, - 2400:fc40::/32, - 2400:fcc0::/32, - 2400:fe00::/32, - 2401:20:100::/40, - 2401:20:200::/39, - 2401:20:400::/38, - 2401:20:800::/37, - 2401:20:1000::/39, - 2401:20:1200::/40, - 2401:20:1300::/43, - 2401:20:1320::/44, - 2401:20:1334::/46, - 2401:20:1338::/45, - 2401:20:1340::/42, - 2401:20:1380::/41, - 2401:20:1400::/38, - 2401:20:1800::/37, - 2401:20:2000::/40, - 2401:20:2100::/46, - 2401:20:2108::/45, - 2401:20:2110::/44, - 2401:20:2120::/43, - 2401:20:2140::/42, - 2401:20:2180::/41, - 2401:20:2200::/39, - 2401:20:2400::/38, - 2401:20:2800::/37, - 2401:20:3000::/36, - 2401:20:4000::/34, - 2401:20:8000::/33, - 2401:60::/32, - 2401:80::/32, - 2401:140::/32, - 2401:1c0::/32, - 2401:540::/32, - 2401:620::/32, - 2401:7c0::/32, - 2401:800::/32, - 2401:9c0::/32, - 2401:a00::/32, - 2401:a40::/32, - 2401:ac0::/32, - 2401:b40::/32, - 2401:ba0::/32, - 2401:bc0::/32, - 2401:c40::/32, - 2401:cc0::/32, - 2401:d40::/32, - 2401:e00::/32, - 2401:1000::/32, - 2401:1160::/32, - 2401:11c0::/32, - 2401:1200::/32, - 2401:12c0::/32, - 2401:1320::/32, - 2401:15c0::/32, - 2401:18c0::/32, - 2401:18e0::/28, - 2401:1940::/32, - 2401:19c0::/32, - 2401:1a40::/32, - 2401:1ac0::/32, - 2401:1c60::/32, - 2401:1ce0::/32, - 2401:1d40::/32, - 2401:1da0::/43, - 2401:1da0:30::/44, - 2401:1da0:40::/42, - 2401:1da0:80::/41, - 2401:1da0:100::/40, - 2401:1da0:200::/39, - 2401:1da0:400::/38, - 2401:1da0:800::/37, - 2401:1da0:1000::/36, - 2401:1da0:2000::/35, - 2401:1da0:4000::/34, - 2401:1da0:8000::/33, - 2401:1dc0::/32, - 2401:1de0::/32, - 2401:1e00::/32, - 2401:1ec0::/32, - 2401:1f40::/32, - 2401:2040::/32, - 2401:2080::/32, - 2401:23c0::/32, - 2401:2600::/32, - 2401:2780::/32, - 2401:2980::/32, - 2401:2a00:f000::/43, - 2401:2b40::/32, - 2401:2e00::/32, - 2401:2e20::/32, - 2401:3100::/32, - 2401:3380::/32, - 2401:33c0::/32, - 2401:3440::/32, - 2401:3480::/32, - 2401:34a0::/31, - 2401:34c0::/32, - 2401:3640::/32, - 2401:3780::/32, - 2401:3800::/32, - 2401:3880::/32, - 2401:3980::/32, - 2401:3a00::/32, - 2401:3a80::/32, - 2401:3b80::/32, - 2401:3c20::/32, - 2401:3c80::/32, - 2401:3d80::/32, - 2401:3e80::/32, - 2401:3f80::/32, - 2401:4080::/32, - 2401:4180::/32, - 2401:4280::/32, - 2401:4380::/32, - 2401:4480::/32, - 2401:4580::/32, - 2401:4680::/32, - 2401:4780::/32, - 2401:4880::/32, - 2401:4a80::/32, - 2401:4b00::/32, - 2401:4f80::/32, - 2401:5680::/32, - 2401:58a0::/32, - 2401:59c0::/32, - 2401:5b40::/32, - 2401:5c20::/32, - 2401:5c60::/32, - 2401:5c80::/32, - 2401:5fa0::/32, - 2401:70e0::/32, - 2401:7180::/32, - 2401:71c0::/32, - 2401:7240::/32, - 2401:7320::/32, - 2401:7360::/32, - 2401:73a0::/32, - 2401:7580::/32, - 2401:7660::/32, - 2401:7680::/32, - 2401:7700::/32, - 2401:7780::/32, - 2401:77e0::/32, - 2401:7820::/32, - 2401:7880::/32, - 2401:78e0::/32, - 2401:7980::/32, - 2401:7a00::/32, - 2401:7a80::/32, - 2401:7b80::/32, - 2401:7bc0::/32, - 2401:7c80::/32, - 2401:7cc0::/32, - 2401:7ce0::/32, - 2401:7d40::/32, - 2401:7d80::/32, - 2401:7e00::/32, - 2401:7f80::/32, - 2401:8200::/32, - 2401:82c0::/32, - 2401:8380::/32, - 2401:8540::/32, - 2401:8600::/32, - 2401:8680::/34, - 2401:8680:4000::/46, - 2401:8680:4008::/45, - 2401:8680:4010::/44, - 2401:8680:4020::/43, - 2401:8680:4040::/42, - 2401:8680:4080::/41, - 2401:8680:4100::/48, - 2401:8680:4103::/48, - 2401:8680:4104::/46, - 2401:8680:4108::/45, - 2401:8680:4110::/44, - 2401:8680:4120::/43, - 2401:8680:4140::/42, - 2401:8680:4180::/41, - 2401:8680:4200::/39, - 2401:8680:4400::/38, - 2401:8680:4800::/37, - 2401:8680:5000::/36, - 2401:8680:6000::/35, - 2401:8680:8000::/33, - 2401:8720::/32, - 2401:87e0::/32, - 2401:8820::/31, - 2401:8840::/32, - 2401:8be0::/32, - 2401:8d00::/47, - 2401:8d00:3::/48, - 2401:8d00:4::/46, - 2401:8d00:8::/45, - 2401:8d00:10::/46, - 2401:8d00:17::/48, - 2401:8d00:18::/45, - 2401:8d00:20::/43, - 2401:8d00:40::/42, - 2401:8d00:80::/41, - 2401:8d00:100::/40, - 2401:8d00:200::/39, - 2401:8d00:400::/38, - 2401:8d00:800::/37, - 2401:8d00:1000::/36, - 2401:8d00:2000::/35, - 2401:8d00:4000::/34, - 2401:8d00:8000::/33, - 2401:8da0::/32, - 2401:8f40::/32, - 2401:8fc0::/32, - 2401:90a0::/32, - 2401:9260::/32, - 2401:92a0::/32, - 2401:92e0::/32, - 2401:9340::/32, - 2401:95e0::/32, - 2401:9600::/32, - 2401:96c0::/32, - 2401:96e0::/32, - 2401:9720::/32, - 2401:9740::/32, - 2401:97a0::/32, - 2401:98c0::/32, - 2401:9a00::/32, - 2401:9ac0::/32, - 2401:9b20::/31, - 2401:9b40::/32, - 2401:9b60::/32, - 2401:9bc0::/32, - 2401:9ca0::/32, - 2401:9d20::/32, - 2401:9dc0::/32, - 2401:9e20::/32, - 2401:9e40::/32, - 2401:9f80::/32, - 2401:9fa0::/32, - 2401:a140::/32, - 2401:a2e0::/32, - 2401:a340::/32, - 2401:a3a0::/32, - 2401:a3c0::/32, - 2401:a4c0::/32, - 2401:a4e0::/32, - 2401:a540::/32, - 2401:a5c0::/32, - 2401:a620::/32, - 2401:a640::/32, - 2401:a6e0::/32, - 2401:a720::/32, - 2401:a940::/32, - 2401:a980::/32, - 2401:a9a0::/32, - 2401:aa00::/32, - 2401:aa20::/32, - 2401:aa40::/32, - 2401:ab60::/32, - 2401:aba0::/32, - 2401:acc0::/32, - 2401:ad40::/32, - 2401:adc0::/32, - 2401:afa0::/32, - 2401:b040::/32, - 2401:b180::/32, - 2401:b220::/32, - 2401:b340::/32, - 2401:b360::/32, - 2401:b400::/32, - 2401:b4c0::/32, - 2401:b4e0::/32, - 2401:b540::/32, - 2401:b580::/32, - 2401:b5a0::/32, - 2401:b600::/32, - 2401:b680::/32, - 2401:b6c0::/32, - 2401:b6e0::/32, - 2401:b7c0::/32, - 2401:b940::/32, - 2401:ba00::/32, - 2401:ba40::/32, - 2401:bb20::/32, - 2401:bc60::/31, - 2401:bda0::/32, - 2401:be00::/32, - 2401:bf20::/32, - 2401:c020::/32, - 2401:c200::/32, - 2401:c540::/32, - 2401:c600::/32, - 2401:c640::/32, - 2401:c6c0::/32, - 2401:c840::/32, - 2401:c8c0::/32, - 2401:ca00::/32, - 2401:ca20::/32, - 2401:cb80::/32, - 2401:cbe0::/32, - 2401:cc00::/32, - 2401:cc60::/32, - 2401:ce00::/32, - 2401:cf40::/32, - 2401:cfc0::/32, - 2401:cfe0::/32, - 2401:d060::/32, - 2401:d0c0::/32, - 2401:d0e0::/32, - 2401:d140::/32, - 2401:d180::/32, - 2401:d2c0::/32, - 2401:d340::/32, - 2401:d420::/32, - 2401:d780::/32, - 2401:d7e0::/32, - 2401:d8e0::/32, - 2401:d920::/28, - 2401:da00::/32, - 2401:dbe0::/32, - 2401:dd20::/32, - 2401:dd60::/32, - 2401:de00::/32, - 2401:dfe0::/32, - 2401:e020::/32, - 2401:e080::/32, - 2401:e0c0::/32, - 2401:e140::/32, - 2401:e240::/32, - 2401:e2c0::/32, - 2401:e340::/32, - 2401:e360::/32, - 2401:e620::/32, - 2401:e840::/32, - 2401:e8c0::/32, - 2401:e940::/32, - 2401:e9c0::/32, - 2401:ec00::/32, - 2401:ec40::/32, - 2401:f0a0::/32, - 2401:f0e0::/32, - 2401:f220::/32, - 2401:f300::/32, - 2401:f320::/32, - 2401:f3e0::/32, - 2401:f7c0::/32, - 2401:f860::/46, - 2401:f860:4::/47, - 2401:f860:6::/48, - 2401:f860:8::/47, - 2401:f860:a::/48, - 2401:f860:c::/46, - 2401:f860:10::/44, - 2401:f860:20::/43, - 2401:f860:40::/42, - 2401:f860:80::/45, - 2401:f860:89::/48, - 2401:f860:8a::/47, - 2401:f860:8c::/46, - 2401:f860:91::/48, - 2401:f860:93::/48, - 2401:f860:95::/48, - 2401:f860:96::/48, - 2401:f860:98::/45, - 2401:f860:a0::/43, - 2401:f860:c0::/43, - 2401:f860:e0::/44, - 2401:f860:f0::/46, - 2401:f860:f4::/47, - 2401:f860:f7::/48, - 2401:f860:f8::/45, - 2401:f860:200::/39, - 2401:f860:400::/38, - 2401:f860:800::/37, - 2401:f860:1000::/36, - 2401:f860:2000::/35, - 2401:f860:4000::/34, - 2401:f860:8000::/33, - 2401:fa80::/32, - 2401:fb80::/32, - 2401:fc60::/32, - 2401:fc80::/32, - 2401:ffc0::/32, - 2402:440::/32, - 2402:5c0::/32, - 2402:840::/32, - 2402:a60::/32, - 2402:c20::/32, - 2402:c60::/32, - 2402:e00::/32, - 2402:fc0::/32, - 2402:1000::/32, - 2402:1160::/32, - 2402:1440::/32, - 2402:14c0::/32, - 2402:1520::/32, - 2402:1600::/32, - 2402:16e0::/32, - 2402:1740::/32, - 2402:18a0::/32, - 2402:19c0::/32, - 2402:1be0::/32, - 2402:1c20::/32, - 2402:1f80::/32, - 2402:2000::/32, - 2402:20e0::/33, - 2402:20e0:8000::/34, - 2402:20e0:c000::/35, - 2402:20e0:e000::/36, - 2402:20e0:f001::/48, - 2402:20e0:f002::/47, - 2402:20e0:f004::/46, - 2402:20e0:f008::/45, - 2402:20e0:f010::/44, - 2402:20e0:f020::/43, - 2402:20e0:f040::/42, - 2402:20e0:f080::/41, - 2402:20e0:f100::/40, - 2402:20e0:f200::/39, - 2402:20e0:f400::/38, - 2402:20e0:f800::/37, - 2402:2280::/32, - 2402:2440::/32, - 2402:24c0::/32, - 2402:2540::/32, - 2402:2620::/32, - 2402:2640::/32, - 2402:2760::/32, - 2402:2a00::/32, - 2402:2b80::/32, - 2402:2bc0::/32, - 2402:2ca0::/32, - 2402:2d00::/32, - 2402:2d80::/32, - 2402:2e60::/32, - 2402:2e80::/32, - 2402:2f40::/32, - 2402:3040::/32, - 2402:3140::/32, - 2402:3180:4::/46, - 2402:3180:8::/45, - 2402:3180:10::/44, - 2402:3180:20::/43, - 2402:3180:40::/42, - 2402:3180:80::/41, - 2402:3180:100::/40, - 2402:3180:200::/39, - 2402:3180:400::/38, - 2402:3180:800::/37, - 2402:3180:1000::/36, - 2402:3180:2000::/35, - 2402:3180:4000::/34, - 2402:31c0::/32, - 2402:3240::/32, - 2402:32e0::/32, - 2402:3320::/32, - 2402:33a0::/32, - 2402:33c0::/32, - 2402:34e0::/32, - 2402:36e0::/32, - 2402:39c0::/32, - 2402:3a40::/32, - 2402:3ac0::/32, - 2402:3ba0::/32, - 2402:3c00::/32, - 2402:3d20:2000::/35, - 2402:3d20:4000::/34, - 2402:3d20:8000::/33, - 2402:3de0::/32, - 2402:3e00::/32, - 2402:3ec0::/32, - 2402:3f80::/32, - 2402:4060::/32, - 2402:4140::/32, - 2402:42c0::/32, - 2402:4340::/32, - 2402:43c0::/32, - 2402:4440::/32, - 2402:4500::/32, - 2402:4540::/32, - 2402:4820::/32, - 2402:4a00::/32, - 2402:4a40::/32, - 2402:4a80::/32, - 2402:4ac0::/32, - 2402:4b80::/32, - 2402:4bc0::/32, - 2402:4be0::/32, - 2402:4c40::/32, - 2402:4d60::/32, - 2402:4d80::/32, - 2402:4e00::/32, - 2402:4ec0::/32, - 2402:4f80::/32, - 2402:50a0::/32, - 2402:5180::/32, - 2402:51a0::/32, - 2402:5340::/32, - 2402:5820::/32, - 2402:5880::/32, - 2402:5920::/32, - 2402:5940::/32, - 2402:59c0::/32, - 2402:5a40::/32, - 2402:5b40::/32, - 2402:5bc0::/32, - 2402:5d00::/32, - 2402:5e00::/32, - 2402:5e40::/32, - 2402:5ec0::/32, - 2402:5f20::/32, - 2402:5f40::/32, - 2402:6060::/32, - 2402:6280::/32, - 2402:6320::/32, - 2402:64c0::/32, - 2402:66c0::/32, - 2402:6740::/32, - 2402:67c0::/32, - 2402:6960::/32, - 2402:6a00::/32, - 2402:6b40::/32, - 2402:6bc0::/32, - 2402:6e00::/32, - 2402:6e80::/32, - 2402:6f40::/32, - 2402:6fc0::/32, - 2402:7040::/32, - 2402:7060::/32, - 2402:7080::/32, - 2402:70a0::/29, - 2402:70c0::/32, - 2402:7140::/32, - 2402:71c0::/32, - 2402:7240::/32, - 2402:72a0::/32, - 2402:72c0::/32, - 2402:73e0::/32, - 2402:7540::/32, - 2402:75c0::/32, - 2402:7740::/32, - 2402:7820::/32, - 2402:7d00::/32, - 2402:7d80::/32, - 2402:7da0::/32, - 2402:7e20::/32, - 2402:7ee0::/32, - 2402:8180::/32, - 2402:8300::/32, - 2402:8380::/32, - 2402:85c0::/32, - 2402:8800::/32, - 2402:8840::/32, - 2402:8900::/32, - 2402:8940::/32, - 2402:89c0::/32, - 2402:8b40::/32, - 2402:8bc0::/32, - 2402:8cc0::/32, - 2402:8d40::/32, - 2402:8f40::/32, - 2402:8f80::/32, - 2402:9240::/32, - 2402:92c0::/32, - 2402:93c0::/32, - 2402:9440::/32, - 2402:9480::/32, - 2402:94c0::/32, - 2402:9580::/32, - 2402:95c0::/32, - 2402:9680::/32, - 2402:96c0::/32, - 2402:9840::/32, - 2402:98c0::/32, - 2402:9940::/32, - 2402:9a80::/32, - 2402:9b80::/32, - 2402:9f80::/32, - 2402:9fc0::/32, - 2402:a080::/32, - 2402:a180::/32, - 2402:a200::/32, - 2402:a240::/32, - 2402:a280::/32, - 2402:a380::/32, - 2402:a640::/32, - 2402:a680::/32, - 2402:a6c0::/32, - 2402:a840::/32, - 2402:a880::/32, - 2402:aa80::/32, - 2402:ab80::/32, - 2402:ae00::/32, - 2402:ae40::/32, - 2402:aec0::/32, - 2402:af80::/32, - 2402:afc0::/32, - 2402:b080::/32, - 2402:b200::/32, - 2402:b440::/32, - 2402:b6c0::/32, - 2402:b880::/32, - 2402:b8c0::/32, - 2402:b940:100::/40, - 2402:b940:400::/38, - 2402:b940:800::/37, - 2402:b940:1000::/36, - 2402:b940:2000::/35, - 2402:b940:4000::/34, - 2402:b940:8000::/33, - 2402:b980::/32, - 2402:ba80::/32, - 2402:bac0::/32, - 2402:bbc0::/32, - 2402:bf80::/32, - 2402:c280::/32, - 2402:c3c0::/32, - 2402:c5c0::/32, - 2402:c9c0::/32, - 2402:cc40::/32, - 2402:cf00::/32, - 2402:cf40::/32, - 2402:d040::/32, - 2402:d140::/32, - 2402:d2c0:3::/48, - 2402:d2c0:4::/46, - 2402:d2c0:8::/45, - 2402:d2c0:10::/44, - 2402:d2c0:20::/43, - 2402:d2c0:40::/42, - 2402:d2c0:80::/41, - 2402:d2c0:100::/40, - 2402:d2c0:200::/39, - 2402:d2c0:400::/38, - 2402:d2c0:800::/37, - 2402:d2c0:1000::/36, - 2402:d2c0:2000::/35, - 2402:d2c0:4000::/34, - 2402:d2c0:8000::/33, - 2402:d300::/32, - 2402:d340::/32, - 2402:d380::/32, - 2402:d5c0::/32, - 2402:d6c0::/32, - 2402:d740::/32, - 2402:d780::/32, - 2402:d880::/32, - 2402:d980::/32, - 2402:da40::/32, - 2402:db40::/34, - 2402:db40:4000::/36, - 2402:db40:5000::/37, - 2402:db40:5800::/40, - 2402:db40:5901::/48, - 2402:db40:5902::/47, - 2402:db40:5904::/46, - 2402:db40:5908::/45, - 2402:db40:5910::/44, - 2402:db40:5920::/43, - 2402:db40:5940::/42, - 2402:db40:5980::/41, - 2402:db40:5a00::/39, - 2402:db40:5c00::/38, - 2402:db40:6000::/35, - 2402:db40:8000::/33, - 2402:dcc0::/32, - 2402:de40::/32, - 2402:dec0::/32, - 2402:df40::/32, - 2402:dfc0::/32, - 2402:e040::/32, - 2402:e0c0::/32, - 2402:e140::/32, - 2402:e2c0::/32, - 2402:e3c0::/32, - 2402:e480::/32, - 2402:e540::/32, - 2402:e680::/32, - 2402:e740::/32, - 2402:e780::/32, - 2402:e7c0::/37, - 2402:e7c0:800::/38, - 2402:e7c0:1000::/36, - 2402:e7c0:2000::/35, - 2402:e7c0:4000::/34, - 2402:e7c0:8000::/33, - 2402:e880::/32, - 2402:e980::/32, - 2402:eb80::/32, - 2402:ec80::/32, - 2402:ed80::/32, - 2402:ef40::/32, - 2402:ef80::/32, - 2402:f000::/32, - 2402:f140::/32, - 2402:f480::/32, - 2402:f540::/32, - 2402:f580::/32, - 2402:f780::/32, - 2402:f8c0::/32, - 2402:f980::/32, - 2402:f9c0::/32, - 2402:fac0::/32, - 2402:fcc0::/32, - 2402:ff40::/32, - 2402:ffc0::/32, - 2403:600::/32, - 2403:700::/32, - 2403:7c0::/32, - 2403:800::/31, - 2403:980::/32, - 2403:a80::/32, - 2403:b80::/32, - 2403:c80::/32, - 2403:d80::/32, - 2403:e80::/32, - 2403:f00::/32, - 2403:f80::/32, - 2403:fc0::/32, - 2403:1180::/32, - 2403:1340::/32, - 2403:1440::/32, - 2403:1580::/32, - 2403:16c0::/32, - 2403:17c0::/32, - 2403:1980::/32, - 2403:1b80::/32, - 2403:1c80::/32, - 2403:1d80::/32, - 2403:1dc0::/32, - 2403:1e80::/32, - 2403:1ec0::/36, - 2403:1ec0:1000::/37, - 2403:1ec0:1800::/40, - 2403:1ec0:1901::/48, - 2403:1ec0:1902::/47, - 2403:1ec0:1904::/46, - 2403:1ec0:1908::/45, - 2403:1ec0:1950::/44, - 2403:1ec0:1960::/43, - 2403:1ec0:1980::/41, - 2403:1ec0:1a00::/39, - 2403:1ec0:1c00::/38, - 2403:1ec0:2000::/35, - 2403:1ec0:4000::/34, - 2403:1ec0:8000::/33, - 2403:1f80::/32, - 2403:2040::/32, - 2403:2080::/32, - 2403:2180::/32, - 2403:2240::/32, - 2403:2280::/32, - 2403:2380::/32, - 2403:2440::/32, - 2403:24c0::/32, - 2403:2580::/32, - 2403:25c0::/32, - 2403:2680::/32, - 2403:2740::/32, - 2403:2780::/32, - 2403:28c0::/32, - 2403:2940::/32, - 2403:2a00::/32, - 2403:2a40::/32, - 2403:2ac0::/32, - 2403:2b40::/32, - 2403:2bc0::/32, - 2403:2cc0::/32, - 2403:2f40::/32, - 2403:2fc0::/32, - 2403:3040::/32, - 2403:30c0::/32, - 2403:3140::/32, - 2403:3280::/32, - 2403:32c0::/32, - 2403:3380::/32, - 2403:3480::/32, - 2403:3580::/32, - 2403:3640::/32, - 2403:3680::/32, - 2403:36c0::/32, - 2403:3740::/32, - 2403:3780::/32, - 2403:37c0::/32, - 2403:3840::/32, - 2403:3880::/32, - 2403:38c0::/32, - 2403:3940::/32, - 2403:3980::/32, - 2403:39c0::/32, - 2403:3b80::/32, - 2403:3c40::/32, - 2403:3c80::/32, - 2403:3cc0::/32, - 2403:3d40::/32, - 2403:3d80::/32, - 2403:3dc0::/32, - 2403:3e80::/32, - 2403:3ec0::/32, - 2403:3f80::/32, - 2403:4080::/32, - 2403:4180::/32, - 2403:4280::/32, - 2403:4300::/32, - 2403:4380::/32, - 2403:4580::/32, - 2403:4680::/32, - 2403:4780::/32, - 2403:4840::/32, - 2403:4880::/32, - 2403:4980::/32, - 2403:4a40::/32, - 2403:4a80::/32, - 2403:4b40::/32, - 2403:4b80::/32, - 2403:4c80::/32, - 2403:4cc0::/32, - 2403:4d80::/32, - 2403:4ec0::/32, - 2403:5080::/32, - 2403:5280::/32, - 2403:5380::/32, - 2403:54c0::/32, - 2403:5540::/32, - 2403:5580::/32, - 2403:5640::/32, - 2403:5780::/32, - 2403:5980::/32, - 2403:5a80::/32, - 2403:5b40::/32, - 2403:5b80::/32, - 2403:5c80::/32, - 2403:5d80::/32, - 2403:5e40::/32, - 2403:5e80::/32, - 2403:5ec0::/32, - 2403:5f80::/32, - 2403:5fc0::/32, - 2403:6080::/32, - 2403:6180::/32, - 2403:6280::/32, - 2403:62c0::/32, - 2403:6380::/44, - 2403:6380:20::/44, - 2403:6380:33::/48, - 2403:6380:34::/46, - 2403:6380:38::/45, - 2403:6380:41::/48, - 2403:6380:44::/46, - 2403:6380:48::/45, - 2403:6380:50::/44, - 2403:6380:60::/43, - 2403:6380:80::/41, - 2403:6380:100::/40, - 2403:6380:200::/39, - 2403:6380:400::/38, - 2403:6380:800::/37, - 2403:6380:1000::/36, - 2403:6380:2000::/35, - 2403:6380:4000::/34, - 2403:6380:8000::/33, - 2403:6580::/32, - 2403:6680::/32, - 2403:6740::/32, - 2403:6780::/32, - 2403:6880::/32, - 2403:6980::/32, - 2403:6a00::/32, - 2403:6c80::/32, - 2403:6d40::/32, - 2403:6d80::/32, - 2403:6e80::/32, - 2403:6f40::/32, - 2403:6fc0::/32, - 2403:7040::/32, - 2403:7080::/32, - 2403:7180::/32, - 2403:7280::/32, - 2403:7380::/32, - 2403:7480::/32, - 2403:7540::/32, - 2403:7580::/32, - 2403:76c0::/32, - 2403:7700::/32, - 2403:78c0::/32, - 2403:7a80::/32, - 2403:7b00::/32, - 2403:7d80::/32, - 2403:7e80::/32, - 2403:7f80::/32, - 2403:8080::/32, - 2403:8180::/32, - 2403:8280::/32, - 2403:8380::/32, - 2403:83c0::/32, - 2403:8480::/32, - 2403:8580::/32, - 2403:8880::/32, - 2403:8900::/32, - 2403:8980::/32, - 2403:8a40::/32, - 2403:8a80::/32, - 2403:8b00::/32, - 2403:8b80::/32, - 2403:8c00::/32, - 2403:8c80::/32, - 2403:8d00::/32, - 2403:8d80::/32, - 2403:9080::/32, - 2403:9180::/32, - 2403:9280::/32, - 2403:9380::/32, - 2403:9480::/32, - 2403:9580::/32, - 2403:9680::/32, - 2403:9780::/32, - 2403:9880::/32, - 2403:9a80::/32, - 2403:9ac0::/32, - 2403:9b00::/32, - 2403:9b40::/32, - 2403:9b80::/32, - 2403:9c80::/32, - 2403:9d00::/32, - 2403:9d80::/32, - 2403:9e40::/32, - 2403:9e80::/32, - 2403:9ec0::/32, - 2403:9f80::/32, - 2403:a100::/32, - 2403:a140::/32, - 2403:a200::/32, - 2403:a300::/32, - 2403:a480::/32, - 2403:a580::/32, - 2403:a680::/32, - 2403:a6c0::/32, - 2403:a780::/32, - 2403:a880::/32, - 2403:a940::/32, - 2403:a980::/32, - 2403:a9c0::/32, - 2403:aa40::/32, - 2403:aa80::/32, - 2403:ab80::/32, - 2403:ac00::/32, - 2403:af80::/32, - 2403:b080::/32, - 2403:b180::/32, - 2403:b280::/32, - 2403:b380::/32, - 2403:b400::/32, - 2403:b480::/32, - 2403:b580::/32, - 2403:b680::/32, - 2403:b780::/32, - 2403:b880::/32, - 2403:b980::/32, - 2403:ba40::/32, - 2403:c040::/32, - 2403:c080::/32, - 2403:c100::/32, - 2403:c140::/32, - 2403:c180::/32, - 2403:c3c0::/32, - 2403:c440::/32, - 2403:c480::/32, - 2403:c4c0::/32, - 2403:c980::/32, - 2403:cdc0::/32, - 2403:cf80::/32, - 2403:d080::/32, - 2403:d180::/32, - 2403:d280::/32, - 2403:d2c0::/32, - 2403:d380::/32, - 2403:d400::/32, - 2403:d440::/32, - 2403:d480::/32, - 2403:d580::/32, - 2403:d680::/32, - 2403:d780::/32, - 2403:d7c0::/32, - 2403:d880::/32, - 2403:d980::/32, - 2403:d9c0::/32, - 2403:da80::/32, - 2403:dac0::/32, - 2403:db00::/32, - 2403:db80::/32, - 2403:dc80::/32, - 2403:dd80::/32, - 2403:de80::/32, - 2403:df80::/32, - 2403:e080::/32, - 2403:e180::/32, - 2403:e280::/32, - 2403:e300::/32, - 2403:e480::/32, - 2403:e500::/32, - 2403:e580::/32, - 2403:e640::/32, - 2403:e680::/32, - 2403:e700::/32, - 2403:e780::/32, - 2403:e7c0::/32, - 2403:e880::/32, - 2403:e980::/32, - 2403:ea80::/32, - 2403:eac0::/32, - 2403:eb80::/32, - 2403:ec80::/32, - 2403:ed00::/32, - 2403:ed40::/32, - 2403:ed80::/32, - 2403:ee80::/32, - 2403:ef80::/32, - 2403:f080::/32, - 2403:f100::/32, - 2403:f180::/32, - 2403:f240::/32, - 2403:f280::/32, - 2403:f300::/32, - 2403:f380::/32, - 2403:f4c0::/32, - 2403:f580::/32, - 2403:f740::/32, - 2403:f8c0::/32, - 2403:f980::/32, - 2403:fb00::/32, - 2403:fb80::/32, - 2403:fc40::/32, - 2403:fe40::/32, - 2403:fe80::/32, - 2403:fec0::/32, - 2403:ff80::/32, - 2403:ffc0::/31, - 2404:100::/32, - 2404:158::/32, - 2404:240::/32, - 2404:280::/32, - 2404:440::/32, - 2404:480::/32, - 2404:680::/32, - 2404:a80::/32, - 2404:b80::/32, - 2404:bc0::/32, - 2404:c40::/32, - 2404:d80::/32, - 2404:f00::/32, - 2404:f80::/32, - 2404:1080::/32, - 2404:10c0::/32, - 2404:1180::/32, - 2404:14c0::/32, - 2404:1880::/32, - 2404:1c80::/32, - 2404:1cc0::/32, - 2404:1d80::/39, - 2404:1d80:200::/44, - 2404:1d80:210::/47, - 2404:1d80:212::/48, - 2404:1d80:214::/46, - 2404:1d80:218::/45, - 2404:1d80:220::/43, - 2404:1d80:240::/42, - 2404:1d80:280::/41, - 2404:1d80:300::/40, - 2404:1d80:400::/38, - 2404:1d80:800::/37, - 2404:1d80:1000::/36, - 2404:1d80:2000::/35, - 2404:1d80:4000::/34, - 2404:1d80:8000::/33, - 2404:1e80::/32, - 2404:1f40::/32, - 2404:21c0::/32, - 2404:2280:1000::/36, - 2404:2280:2000::/35, - 2404:2280:4000::/36, - 2404:30c0::/32, - 2404:3140::/32, - 2404:31c0::/32, - 2404:3240::/32, - 2404:32c0::/32, - 2404:3300::/32, - 2404:3340::/32, - 2404:3480::/32, - 2404:35c0::/32, - 2404:3640::/32, - 2404:36c0::/32, - 2404:3700::/32, - 2404:3740::/32, - 2404:37c0::/32, - 2404:3840::/32, - 2404:3940::/32, - 2404:3f40::/32, - 2404:41c0::/32, - 2404:4540::/32, - 2404:4740::/32, - 2404:4d00::/32, - 2404:4dc0::/32, - 2404:51c0::/32, - 2404:5640::/32, - 2404:5a80::/32, - 2404:5b00::/32, - 2404:5d00::/32, - 2404:6000::/32, - 2404:6100::/32, - 2404:6380::/32, - 2404:6500::/32, - 2404:65c0::/32, - 2404:6a40::/32, - 2404:6f80::/32, - 2404:7100::/32, - 2404:7180::/32, - 2404:71c0::/32, - 2404:7240::/32, - 2404:74c0::/32, - 2404:7600::/32, - 2404:7740::/32, - 2404:7940::/32, - 2404:7d00::/32, - 2404:8040::/32, - 2404:80c0::/32, - 2404:8140::/32, - 2404:81c0::/32, - 2404:8480::/32, - 2404:8580::/32, - 2404:8700::/32, - 2404:8880::/32, - 2404:8a80::/32, - 2404:8dc0::/32, - 2404:9340::/32, - 2404:9b80::/32, - 2404:9c80::/32, - 2404:a000::/32, - 2404:a080::/32, - 2404:a0c0::/32, - 2404:a180::/32, - 2404:a240::/32, - 2404:a740::/32, - 2404:b100::/32, - 2404:b340::/32, - 2404:b3c0::/32, - 2404:b440::/32, - 2404:b4c0::/32, - 2404:b900::/32, - 2404:bbc0::/32, - 2404:bc40::/32, - 2404:c1c0::/32, - 2404:c240::/32, - 2404:c2c0::/32, - 2404:c300::/32, - 2404:c3c0::/32, - 2404:c440::/32, - 2404:c4c0::/32, - 2404:c540::/32, - 2404:c5c0::/32, - 2404:c940::/32, - 2404:c9c0::/32, - 2404:cd00::/32, - 2404:d040::/32, - 2404:d080::/32, - 2404:d140::/32, - 2404:d280::/32, - 2404:d3c0::/32, - 2404:d640::/32, - 2404:d6c0::/32, - 2404:d7c0::/32, - 2404:d840::/32, - 2404:dd80::/32, - 2404:df00::/32, - 2404:e280::/32, - 2404:e540::/32, - 2404:e780::/32, - 2404:e880::/32, - 2404:e8c0::/32, - 2404:eb80::/32, - 2404:ec40::/32, - 2404:ecc0::/32, - 2404:edc0::/32, - 2404:f040::/32, - 2404:f4c0:f000::/44, - 2404:f7c0::/32, - 2405:80::/32, - 2405:480::/32, - 2405:580::/32, - 2405:680::/32, - 2405:6c0:2::/47, - 2405:6c0:4::/46, - 2405:6c0:8::/45, - 2405:6c0:10::/44, - 2405:6c0:20::/43, - 2405:6c0:40::/42, - 2405:6c0:80::/41, - 2405:6c0:100::/40, - 2405:6c0:200::/39, - 2405:6c0:400::/38, - 2405:6c0:800::/37, - 2405:6c0:1000::/36, - 2405:6c0:2000::/35, - 2405:6c0:4000::/34, - 2405:6c0:8000::/33, - 2405:780::/32, - 2405:880::/32, - 2405:940::/32, - 2405:980::/32, - 2405:9c0::/32, - 2405:a80::/32, - 2405:b80::/32, - 2405:c80::/32, - 2405:d80::/32, - 2405:e80::/32, - 2405:f80::/32, - 2405:1080::/32, - 2405:1180::/32, - 2405:1280::/32, - 2405:1380::/32, - 2405:1480::/32, - 2405:1580::/32, - 2405:1680::/32, - 2405:18c0::/32, - 2405:1c80::/32, - 2405:1d80::/32, - 2405:1e80::/32, - 2405:1f80::/32, - 2405:1fc0::/32, - 2405:2080::/32, - 2405:2180::/32, - 2405:2280::/32, - 2405:2340::/32, - 2405:2380::/32, - 2405:2480::/32, - 2405:24c0::/32, - 2405:2580::/32, - 2405:2680::/32, - 2405:2780::/32, - 2405:2880::/32, - 2405:2980::/32, - 2405:2a80::/32, - 2405:2b80::/32, - 2405:2bc0::/32, - 2405:2c80::/32, - 2405:2d80::/32, - 2405:2e80::/32, - 2405:2ec0::/32, - 2405:2f40::/32, - 2405:2f80::/32, - 2405:3140::/32, - 2405:31c0::/32, - 2405:37c0::/32, - 2405:3880::/32, - 2405:3980::/32, - 2405:39c0::/32, - 2405:3a80::/32, - 2405:3ac0::/32, - 2405:3b00::/32, - 2405:3b80::/32, - 2405:3bc0::/32, - 2405:3c40::/32, - 2405:3c80::/32, - 2405:3d80::/32, - 2405:3e80::/32, - 2405:3f40::/32, - 2405:3f80::/32, - 2405:4080::/32, - 2405:4140::/32, - 2405:4180::/32, - 2405:41c0::/32, - 2405:4280::/32, - 2405:4380::/32, - 2405:4480::/32, - 2405:44c0::/32, - 2405:4540::/32, - 2405:4580::/32, - 2405:4680::/32, - 2405:4780::/32, - 2405:4880::/32, - 2405:4980::/32, - 2405:4a80::/32, - 2405:4b80::/32, - 2405:4d40::/32, - 2405:4e80::/32, - 2405:4f80::/32, - 2405:5080::/32, - 2405:5180::/32, - 2405:5240:400::/38, - 2405:5240:c00::/38, - 2405:5240:1000::/36, - 2405:5240:2000::/35, - 2405:5240:4000::/34, - 2405:5240:8000::/33, - 2405:5280::/32, - 2405:52c0::/32, - 2405:5380::/32, - 2405:5480::/32, - 2405:5580::/32, - 2405:5680::/32, - 2405:5780::/32, - 2405:57c0::/32, - 2405:5880::/32, - 2405:5980::/32, - 2405:5a80::/32, - 2405:5b80::/32, - 2405:5c80::/32, - 2405:5cc0::/32, - 2405:5d40::/32, - 2405:5d80::/32, - 2405:5dc0::/32, - 2405:5e80::/32, - 2405:5f80::/32, - 2405:6080::/32, - 2405:6180::/32, - 2405:6200::/32, - 2405:6880::/32, - 2405:68c0::/32, - 2405:6940::/32, - 2405:69c0::/32, - 2405:6a80::/32, - 2405:6b80::/32, - 2405:6c80::/32, - 2405:6d80::/32, - 2405:6e80::/32, - 2405:6f00::/32, - 2405:6f80::/32, - 2405:7040::/32, - 2405:7080::/32, - 2405:7180::/32, - 2405:7280::/32, - 2405:7380::/32, - 2405:7480::/32, - 2405:7580::/32, - 2405:7680::/32, - 2405:7780::/32, - 2405:7880::/32, - 2405:78c0::/32, - 2405:7980::/32, - 2405:79c0::/32, - 2405:7a80::/32, - 2405:7b80::/32, - 2405:7c80::/32, - 2405:7d40::/32, - 2405:7f40::/32, - 2405:7fc0::/32, - 2405:8280::/32, - 2405:8480::/32, - 2405:84c0::/34, - 2405:84c0:4000::/35, - 2405:84c0:6000::/37, - 2405:84c0:6800::/38, - 2405:84c0:6c00::/39, - 2405:84c0:6e00::/40, - 2405:84c0:7000::/36, - 2405:84c0:8000::/48, - 2405:84c0:8002::/48, - 2405:84c0:8006::/48, - 2405:84c0:800a::/47, - 2405:84c0:800c::/46, - 2405:84c0:8010::/48, - 2405:84c0:8019::/48, - 2405:84c0:801e::/47, - 2405:84c0:8020::/47, - 2405:84c0:8036::/47, - 2405:84c0:8038::/46, - 2405:84c0:803c::/47, - 2405:84c0:803e::/48, - 2405:84c0:8041::/48, - 2405:84c0:8042::/47, - 2405:84c0:8044::/47, - 2405:84c0:8048::/46, - 2405:84c0:804c::/47, - 2405:84c0:804e::/48, - 2405:84c0:8050::/48, - 2405:84c0:8053::/48, - 2405:84c0:8058::/45, - 2405:84c0:8061::/48, - 2405:84c0:8062::/47, - 2405:84c0:8064::/46, - 2405:84c0:8068::/45, - 2405:84c0:8070::/44, - 2405:84c0:8080::/41, - 2405:84c0:8100::/40, - 2405:84c0:8200::/39, - 2405:84c0:8400::/38, - 2405:84c0:8800::/37, - 2405:84c0:9000::/36, - 2405:84c0:a000::/40, - 2405:84c0:a101::/48, - 2405:84c0:a102::/47, - 2405:84c0:a104::/46, - 2405:84c0:a108::/45, - 2405:84c0:a110::/44, - 2405:84c0:a120::/43, - 2405:84c0:a140::/42, - 2405:84c0:a180::/41, - 2405:84c0:a200::/39, - 2405:84c0:a400::/38, - 2405:84c0:a800::/37, - 2405:84c0:b000::/36, - 2405:84c0:c000::/34, - 2405:8580::/32, - 2405:8680::/32, - 2405:8780::/32, - 2405:8880::/32, - 2405:8980::/32, - 2405:8a40::/32, - 2405:8a80::/32, - 2405:8ac0::/32, - 2405:8b80::/32, - 2405:8c80::/32, - 2405:8d80::/32, - 2405:8e80::/32, - 2405:8f80::/32, - 2405:9080::/32, - 2405:9180::/32, - 2405:9280::/32, - 2405:9300::/32, - 2405:9340::/32, - 2405:9380::/32, - 2405:93c0::/32, - 2405:9480::/32, - 2405:94c0::/32, - 2405:9580::/32, - 2405:9680::/32, - 2405:9700::/32, - 2405:9780::/32, - 2405:97c0::/32, - 2405:9880::/32, - 2405:9900::/32, - 2405:9980::/32, - 2405:99c0::/32, - 2405:9a80::/32, - 2405:9b00::/32, - 2405:9b80::/32, - 2405:9bc0::/32, - 2405:9e00::/32, - 2405:a240::/32, - 2405:a500::/32, - 2405:a680::/32, - 2405:a900::/32, - 2405:a980::/32, - 2405:aa80::/32, - 2405:ab00::/32, - 2405:ad00::/32, - 2405:af00::/32, - 2405:b100::/32, - 2405:b300::/32, - 2405:b7c0::/32, - 2405:b880::/32, - 2405:b980::/32, - 2405:bb00::/32, - 2405:bd00::/32, - 2405:bd80::/32, - 2405:bdc0::/32, - 2405:be80::/32, - 2405:bf00::/32, - 2405:c040::/32, - 2405:c280::/32, - 2405:c380::/32, - 2405:c480::/32, - 2405:c500::/32, - 2405:c580::/32, - 2405:c680::/32, - 2405:c780::/32, - 2405:c880::/32, - 2405:c980::/32, - 2405:ca80::/32, - 2405:cb80::/32, - 2405:cc80::/32, - 2405:cd80::/32, - 2405:ce80::/32, - 2405:d280::/32, - 2405:d4c0::/32, - 2405:d700::/32, - 2405:d900::/32, - 2405:df40::/32, - 2405:e000::/32, - 2405:e040::/32, - 2405:e1c0::/32, - 2405:e600::/32, - 2405:ef40::/30, - 2405:f340::/32, - 2405:f6c0::/32, - 2405:f940::/32, - 2405:fdc0::/32, - 2406:40::/32, - 2406:80::/32, - 2406:c0::/32, - 2406:140:400::/38, - 2406:140:c00::/38, - 2406:140:1000::/36, - 2406:140:2000::/35, - 2406:140:4000::/34, - 2406:140:8000::/33, - 2406:280::/32, - 2406:440::/32, - 2406:4c0::/32, - 2406:840::/48, - 2406:840:3::/48, - 2406:840:4::/46, - 2406:840:8::/45, - 2406:840:18::/45, - 2406:840:21::/48, - 2406:840:22::/47, - 2406:840:24::/46, - 2406:840:28::/45, - 2406:840:30::/44, - 2406:840:40::/46, - 2406:840:45::/48, - 2406:840:47::/48, - 2406:840:48::/45, - 2406:840:50::/44, - 2406:840:60::/44, - 2406:840:70::/45, - 2406:840:7a::/47, - 2406:840:7c::/46, - 2406:840:82::/47, - 2406:840:84::/46, - 2406:840:88::/45, - 2406:840:91::/48, - 2406:840:92::/47, - 2406:840:94::/46, - 2406:840:98::/45, - 2406:840:a0::/43, - 2406:840:c0::/42, - 2406:840:102::/48, - 2406:840:104::/46, - 2406:840:108::/45, - 2406:840:111::/48, - 2406:840:112::/47, - 2406:840:114::/46, - 2406:840:118::/45, - 2406:840:120::/43, - 2406:840:140::/42, - 2406:840:181::/48, - 2406:840:182::/47, - 2406:840:184::/46, - 2406:840:188::/45, - 2406:840:190::/44, - 2406:840:1a0::/43, - 2406:840:1c0::/42, - 2406:840:201::/48, - 2406:840:202::/47, - 2406:840:204::/46, - 2406:840:208::/45, - 2406:840:210::/44, - 2406:840:220::/43, - 2406:840:240::/42, - 2406:840:280::/42, - 2406:840:2c0::/43, - 2406:840:2e1::/48, - 2406:840:2e2::/47, - 2406:840:2e4::/46, - 2406:840:2e8::/45, - 2406:840:2f0::/44, - 2406:840:300::/41, - 2406:840:382::/47, - 2406:840:384::/46, - 2406:840:388::/45, - 2406:840:390::/44, - 2406:840:3a0::/43, - 2406:840:3c0::/47, - 2406:840:3c3::/48, - 2406:840:3c4::/46, - 2406:840:3c8::/45, - 2406:840:3d0::/44, - 2406:840:3e1::/48, - 2406:840:3e2::/47, - 2406:840:3e4::/46, - 2406:840:3e8::/45, - 2406:840:3f0::/44, - 2406:840:400::/44, - 2406:840:412::/47, - 2406:840:414::/46, - 2406:840:418::/45, - 2406:840:421::/48, - 2406:840:422::/47, - 2406:840:424::/46, - 2406:840:428::/45, - 2406:840:430::/44, - 2406:840:440::/42, - 2406:840:481::/48, - 2406:840:482::/47, - 2406:840:484::/46, - 2406:840:488::/45, - 2406:840:490::/44, - 2406:840:4a0::/43, - 2406:840:4c0::/42, - 2406:840:500::/42, - 2406:840:541::/48, - 2406:840:542::/47, - 2406:840:544::/46, - 2406:840:548::/45, - 2406:840:550::/44, - 2406:840:560::/43, - 2406:840:580::/41, - 2406:840:600::/41, - 2406:840:681::/48, - 2406:840:682::/47, - 2406:840:684::/46, - 2406:840:688::/45, - 2406:840:690::/44, - 2406:840:6a0::/43, - 2406:840:6c0::/48, - 2406:840:6c2::/47, - 2406:840:6c4::/46, - 2406:840:6c8::/45, - 2406:840:6d0::/44, - 2406:840:6e0::/43, - 2406:840:700::/44, - 2406:840:711::/48, - 2406:840:712::/47, - 2406:840:714::/46, - 2406:840:718::/45, - 2406:840:720::/43, - 2406:840:740::/42, - 2406:840:780::/41, - 2406:840:804::/47, - 2406:840:807::/48, - 2406:840:808::/45, - 2406:840:810::/44, - 2406:840:820::/43, - 2406:840:840::/48, - 2406:840:843::/48, - 2406:840:844::/46, - 2406:840:848::/45, - 2406:840:850::/44, - 2406:840:861::/48, - 2406:840:862::/47, - 2406:840:864::/46, - 2406:840:868::/45, - 2406:840:870::/44, - 2406:840:884::/46, - 2406:840:888::/45, - 2406:840:890::/44, - 2406:840:8a0::/43, - 2406:840:8c0::/42, - 2406:840:900::/40, - 2406:840:a01::/48, - 2406:840:a02::/47, - 2406:840:a04::/46, - 2406:840:a08::/45, - 2406:840:a12::/47, - 2406:840:a14::/46, - 2406:840:a18::/45, - 2406:840:a20::/44, - 2406:840:a30::/48, - 2406:840:a33::/48, - 2406:840:a34::/46, - 2406:840:a38::/45, - 2406:840:a40::/42, - 2406:840:a80::/41, - 2406:840:b00::/40, - 2406:840:c00::/47, - 2406:840:c03::/48, - 2406:840:c04::/46, - 2406:840:c08::/45, - 2406:840:c10::/44, - 2406:840:c20::/43, - 2406:840:c40::/43, - 2406:840:c61::/48, - 2406:840:c62::/47, - 2406:840:c64::/46, - 2406:840:c68::/45, - 2406:840:c70::/44, - 2406:840:c80::/43, - 2406:840:ca0::/44, - 2406:840:cb0::/45, - 2406:840:cb9::/48, - 2406:840:cba::/47, - 2406:840:cbc::/46, - 2406:840:cc0::/47, - 2406:840:cc3::/48, - 2406:840:cc4::/46, - 2406:840:cc8::/45, - 2406:840:cd0::/44, - 2406:840:ce0::/43, - 2406:840:d00::/40, - 2406:840:e00::/39, - 2406:840:1000::/48, - 2406:840:1002::/47, - 2406:840:1004::/46, - 2406:840:1008::/45, - 2406:840:1010::/44, - 2406:840:1020::/43, - 2406:840:1040::/42, - 2406:840:1080::/41, - 2406:840:1100::/40, - 2406:840:1200::/39, - 2406:840:1400::/38, - 2406:840:1801::/48, - 2406:840:1802::/47, - 2406:840:1804::/46, - 2406:840:1808::/45, - 2406:840:1810::/44, - 2406:840:1820::/43, - 2406:840:1840::/42, - 2406:840:1880::/41, - 2406:840:1900::/40, - 2406:840:1a00::/39, - 2406:840:1c00::/38, - 2406:840:2000::/39, - 2406:840:2200::/40, - 2406:840:2300::/41, - 2406:840:2381::/48, - 2406:840:2382::/47, - 2406:840:2384::/46, - 2406:840:2388::/45, - 2406:840:2390::/44, - 2406:840:23a0::/43, - 2406:840:23c0::/42, - 2406:840:2400::/38, - 2406:840:2801::/48, - 2406:840:2802::/47, - 2406:840:2804::/46, - 2406:840:2808::/45, - 2406:840:2810::/44, - 2406:840:2820::/43, - 2406:840:2840::/42, - 2406:840:2880::/48, - 2406:840:2882::/47, - 2406:840:2884::/46, - 2406:840:2888::/45, - 2406:840:2890::/44, - 2406:840:28a0::/43, - 2406:840:28c0::/42, - 2406:840:2900::/40, - 2406:840:2a00::/39, - 2406:840:2c00::/38, - 2406:840:3000::/37, - 2406:840:3801::/48, - 2406:840:3802::/47, - 2406:840:3804::/46, - 2406:840:3808::/45, - 2406:840:3810::/44, - 2406:840:3820::/43, - 2406:840:3840::/42, - 2406:840:3880::/41, - 2406:840:3900::/40, - 2406:840:3a00::/39, - 2406:840:3c00::/38, - 2406:840:4000::/40, - 2406:840:4102::/47, - 2406:840:4104::/46, - 2406:840:4108::/45, - 2406:840:4110::/44, - 2406:840:4120::/43, - 2406:840:4140::/42, - 2406:840:4180::/41, - 2406:840:4200::/40, - 2406:840:4300::/41, - 2406:840:4380::/42, - 2406:840:43c0::/43, - 2406:840:43e2::/47, - 2406:840:43e4::/46, - 2406:840:43e8::/45, - 2406:840:43f0::/44, - 2406:840:4400::/38, - 2406:840:4802::/47, - 2406:840:4804::/46, - 2406:840:4808::/45, - 2406:840:4810::/44, - 2406:840:4820::/43, - 2406:840:4840::/42, - 2406:840:4882::/47, - 2406:840:4884::/46, - 2406:840:4888::/45, - 2406:840:4890::/44, - 2406:840:48a0::/43, - 2406:840:48c0::/42, - 2406:840:4900::/40, - 2406:840:4a00::/39, - 2406:840:4c00::/38, - 2406:840:5000::/40, - 2406:840:5102::/47, - 2406:840:5104::/46, - 2406:840:5108::/45, - 2406:840:5110::/44, - 2406:840:5120::/43, - 2406:840:5140::/42, - 2406:840:5180::/41, - 2406:840:5200::/39, - 2406:840:5400::/38, - 2406:840:5802::/47, - 2406:840:5804::/46, - 2406:840:5808::/45, - 2406:840:5810::/44, - 2406:840:5820::/43, - 2406:840:5840::/43, - 2406:840:5862::/47, - 2406:840:5864::/46, - 2406:840:5868::/45, - 2406:840:5870::/44, - 2406:840:5882::/47, - 2406:840:5884::/46, - 2406:840:5888::/45, - 2406:840:5890::/44, - 2406:840:58a0::/43, - 2406:840:58c0::/42, - 2406:840:5900::/40, - 2406:840:5a00::/39, - 2406:840:5c02::/47, - 2406:840:5c04::/46, - 2406:840:5c08::/45, - 2406:840:5c10::/44, - 2406:840:5c20::/43, - 2406:840:5c40::/42, - 2406:840:5c80::/41, - 2406:840:5d00::/40, - 2406:840:5e00::/39, - 2406:840:6000::/35, - 2406:840:8000::/40, - 2406:840:8200::/39, - 2406:840:8400::/38, - 2406:840:8800::/37, - 2406:840:9010::/44, - 2406:840:9020::/43, - 2406:840:9040::/42, - 2406:840:9080::/41, - 2406:840:9101::/48, - 2406:840:9103::/48, - 2406:840:9104::/46, - 2406:840:9108::/45, - 2406:840:9113::/48, - 2406:840:9114::/46, - 2406:840:9118::/45, - 2406:840:9120::/43, - 2406:840:9140::/43, - 2406:840:9160::/44, - 2406:840:9170::/45, - 2406:840:9179::/48, - 2406:840:917a::/47, - 2406:840:917c::/46, - 2406:840:9180::/41, - 2406:840:9300::/40, - 2406:840:9400::/39, - 2406:840:9610::/44, - 2406:840:9630::/44, - 2406:840:9640::/43, - 2406:840:9660::/48, - 2406:840:9662::/47, - 2406:840:9664::/47, - 2406:840:9667::/48, - 2406:840:9668::/45, - 2406:840:9670::/44, - 2406:840:9690::/44, - 2406:840:96a0::/43, - 2406:840:96c0::/42, - 2406:840:9800::/46, - 2406:840:9808::/45, - 2406:840:9810::/45, - 2406:840:9818::/47, - 2406:840:981b::/48, - 2406:840:9820::/43, - 2406:840:9850::/44, - 2406:840:9860::/47, - 2406:840:9865::/48, - 2406:840:9866::/47, - 2406:840:9868::/45, - 2406:840:9870::/44, - 2406:840:9880::/41, - 2406:840:9900::/42, - 2406:840:9940::/43, - 2406:840:9960::/47, - 2406:840:9963::/48, - 2406:840:9965::/48, - 2406:840:9968::/46, - 2406:840:996d::/48, - 2406:840:996e::/47, - 2406:840:9970::/46, - 2406:840:9974::/47, - 2406:840:9976::/48, - 2406:840:9978::/45, - 2406:840:9981::/48, - 2406:840:9982::/47, - 2406:840:9984::/46, - 2406:840:9988::/45, - 2406:840:99a0::/43, - 2406:840:99c0::/42, - 2406:840:9a00::/39, - 2406:840:9c00::/39, - 2406:840:9e00::/41, - 2406:840:9e80::/42, - 2406:840:9ec0::/43, - 2406:840:9ee0::/44, - 2406:840:9f00::/41, - 2406:840:9f80::/42, - 2406:840:9fc0::/43, - 2406:840:9fe0::/44, - 2406:840:a000::/35, - 2406:840:c000::/37, - 2406:840:c800::/38, - 2406:840:cd00::/40, - 2406:840:ce00::/39, - 2406:840:e000::/41, - 2406:840:e090::/44, - 2406:840:e0a0::/43, - 2406:840:e0c0::/45, - 2406:840:e0c8::/46, - 2406:840:e0cc::/47, - 2406:840:e0ce::/48, - 2406:840:e0d0::/44, - 2406:840:e0e4::/48, - 2406:840:e0e6::/47, - 2406:840:e0e9::/48, - 2406:840:e0ea::/47, - 2406:840:e0ec::/46, - 2406:840:e0f0::/44, - 2406:840:e100::/45, - 2406:840:e108::/46, - 2406:840:e10c::/47, - 2406:840:e10e::/48, - 2406:840:e110::/44, - 2406:840:e120::/43, - 2406:840:e140::/45, - 2406:840:e148::/46, - 2406:840:e14c::/47, - 2406:840:e14e::/48, - 2406:840:e150::/44, - 2406:840:e160::/43, - 2406:840:e190::/44, - 2406:840:e1a0::/43, - 2406:840:e1c0::/42, - 2406:840:e210::/44, - 2406:840:e220::/43, - 2406:840:e240::/43, - 2406:840:e260::/44, - 2406:840:e271::/48, - 2406:840:e272::/47, - 2406:840:e274::/46, - 2406:840:e278::/46, - 2406:840:e27c::/47, - 2406:840:e27e::/48, - 2406:840:e290::/44, - 2406:840:e2a0::/43, - 2406:840:e2c0::/42, - 2406:840:e300::/48, - 2406:840:e305::/48, - 2406:840:e307::/48, - 2406:840:e308::/45, - 2406:840:e310::/44, - 2406:840:e320::/44, - 2406:840:e340::/44, - 2406:840:e350::/48, - 2406:840:e352::/47, - 2406:840:e355::/48, - 2406:840:e356::/47, - 2406:840:e358::/46, - 2406:840:e35c::/48, - 2406:840:e35e::/47, - 2406:840:e360::/43, - 2406:840:e380::/41, - 2406:840:e400::/40, - 2406:840:e500::/42, - 2406:840:e540::/43, - 2406:840:e560::/44, - 2406:840:e570::/45, - 2406:840:e578::/46, - 2406:840:e57c::/47, - 2406:840:e57f::/48, - 2406:840:e580::/41, - 2406:840:e610::/44, - 2406:840:e622::/47, - 2406:840:e624::/46, - 2406:840:e628::/45, - 2406:840:e630::/44, - 2406:840:e640::/43, - 2406:840:e660::/46, - 2406:840:e664::/47, - 2406:840:e668::/45, - 2406:840:e670::/44, - 2406:840:e680::/41, - 2406:840:e700::/43, - 2406:840:e730::/44, - 2406:840:e740::/42, - 2406:840:e780::/41, - 2406:840:e800::/45, - 2406:840:e808::/46, - 2406:840:e80c::/47, - 2406:840:e80e::/48, - 2406:840:e810::/44, - 2406:840:e820::/43, - 2406:840:e840::/45, - 2406:840:e848::/46, - 2406:840:e84c::/47, - 2406:840:e84e::/48, - 2406:840:e850::/44, - 2406:840:e860::/43, - 2406:840:e880::/41, - 2406:840:e900::/40, - 2406:840:ea00::/40, - 2406:840:eb06::/48, - 2406:840:eb09::/48, - 2406:840:eb0a::/47, - 2406:840:eb0c::/47, - 2406:840:eb0e::/48, - 2406:840:eb10::/44, - 2406:840:eb20::/43, - 2406:840:eb40::/42, - 2406:840:ebc0::/42, - 2406:840:ec00::/41, - 2406:840:ec80::/42, - 2406:840:ecc0::/43, - 2406:840:ecf0::/44, - 2406:840:ed00::/40, - 2406:840:ee00::/42, - 2406:840:ee42::/47, - 2406:840:ee45::/48, - 2406:840:ee46::/47, - 2406:840:ee48::/47, - 2406:840:ee4a::/48, - 2406:840:ee4c::/48, - 2406:840:ee4e::/47, - 2406:840:ee50::/44, - 2406:840:ee60::/43, - 2406:840:ee80::/43, - 2406:840:eea0::/44, - 2406:840:eeb0::/48, - 2406:840:eeb3::/48, - 2406:840:eeb4::/46, - 2406:840:eeb8::/45, - 2406:840:eec0::/43, - 2406:840:eee0::/46, - 2406:840:eee4::/48, - 2406:840:eee6::/47, - 2406:840:eee8::/45, - 2406:840:eef0::/44, - 2406:840:ef00::/41, - 2406:840:ef80::/42, - 2406:840:efc0::/43, - 2406:840:efe0::/44, - 2406:840:f000::/41, - 2406:840:f080::/43, - 2406:840:f0a0::/48, - 2406:840:f0a2::/47, - 2406:840:f0a4::/46, - 2406:840:f0a8::/47, - 2406:840:f0ab::/48, - 2406:840:f0ac::/46, - 2406:840:f0b0::/44, - 2406:840:f0c0::/42, - 2406:840:f101::/48, - 2406:840:f102::/47, - 2406:840:f104::/46, - 2406:840:f108::/45, - 2406:840:f110::/44, - 2406:840:f120::/43, - 2406:840:f140::/42, - 2406:840:f180::/41, - 2406:840:f200::/40, - 2406:840:f300::/43, - 2406:840:f320::/44, - 2406:840:f330::/46, - 2406:840:f334::/47, - 2406:840:f336::/48, - 2406:840:f338::/45, - 2406:840:f340::/42, - 2406:840:f390::/44, - 2406:840:f3a0::/43, - 2406:840:f3c0::/42, - 2406:840:f400::/48, - 2406:840:f403::/48, - 2406:840:f404::/46, - 2406:840:f408::/45, - 2406:840:f410::/44, - 2406:840:f420::/43, - 2406:840:f440::/45, - 2406:840:f448::/46, - 2406:840:f44c::/47, - 2406:840:f44e::/48, - 2406:840:f450::/44, - 2406:840:f460::/43, - 2406:840:f480::/41, - 2406:840:f500::/40, - 2406:840:f600::/42, - 2406:840:f640::/43, - 2406:840:f670::/44, - 2406:840:f680::/47, - 2406:840:f682::/48, - 2406:840:f684::/46, - 2406:840:f688::/45, - 2406:840:f690::/44, - 2406:840:f6a0::/43, - 2406:840:f6c0::/42, - 2406:840:f700::/40, - 2406:840:f800::/42, - 2406:840:f840::/43, - 2406:840:f864::/46, - 2406:840:f86a::/47, - 2406:840:f86d::/48, - 2406:840:f86e::/47, - 2406:840:f870::/44, - 2406:840:f880::/45, - 2406:840:f888::/48, - 2406:840:f88a::/47, - 2406:840:f88c::/46, - 2406:840:f890::/44, - 2406:840:f8a0::/43, - 2406:840:f8c0::/42, - 2406:840:f900::/41, - 2406:840:f980::/44, - 2406:840:f9a0::/43, - 2406:840:f9c0::/42, - 2406:840:fa00::/48, - 2406:840:fa02::/47, - 2406:840:fa04::/46, - 2406:840:fa08::/45, - 2406:840:fa10::/44, - 2406:840:fa20::/43, - 2406:840:fa41::/48, - 2406:840:fa42::/47, - 2406:840:fa44::/46, - 2406:840:fa48::/45, - 2406:840:fa50::/44, - 2406:840:fa70::/44, - 2406:840:fa81::/48, - 2406:840:fa82::/47, - 2406:840:fa84::/46, - 2406:840:fa88::/45, - 2406:840:fa90::/44, - 2406:840:faa0::/43, - 2406:840:fac0::/42, - 2406:840:fb00::/40, - 2406:840:fc14::/46, - 2406:840:fc18::/45, - 2406:840:fc24::/46, - 2406:840:fc28::/45, - 2406:840:fc34::/46, - 2406:840:fc38::/45, - 2406:840:fc44::/46, - 2406:840:fc48::/45, - 2406:840:fc54::/46, - 2406:840:fc58::/45, - 2406:840:fc64::/46, - 2406:840:fc68::/45, - 2406:840:fc74::/46, - 2406:840:fc78::/45, - 2406:840:fc80::/44, - 2406:840:fc94::/46, - 2406:840:fc98::/45, - 2406:840:fca4::/46, - 2406:840:fca8::/45, - 2406:840:fcb4::/46, - 2406:840:fcb8::/45, - 2406:840:fcc0::/44, - 2406:840:fcd1::/48, - 2406:840:fcd2::/47, - 2406:840:fcd4::/46, - 2406:840:fcd8::/45, - 2406:840:fce0::/44, - 2406:840:fcf6::/47, - 2406:840:fcf8::/45, - 2406:840:fd00::/43, - 2406:840:fd20::/44, - 2406:840:fd31::/48, - 2406:840:fd32::/47, - 2406:840:fd34::/46, - 2406:840:fd38::/45, - 2406:840:fd41::/48, - 2406:840:fd42::/47, - 2406:840:fd44::/48, - 2406:840:fd47::/48, - 2406:840:fd4a::/47, - 2406:840:fd4c::/46, - 2406:840:fd51::/48, - 2406:840:fd52::/47, - 2406:840:fd54::/48, - 2406:840:fd57::/48, - 2406:840:fd5a::/47, - 2406:840:fd5c::/46, - 2406:840:fd61::/48, - 2406:840:fd62::/47, - 2406:840:fd64::/48, - 2406:840:fd67::/48, - 2406:840:fd6a::/47, - 2406:840:fd6c::/46, - 2406:840:fd71::/48, - 2406:840:fd72::/47, - 2406:840:fd74::/48, - 2406:840:fd77::/48, - 2406:840:fd7a::/47, - 2406:840:fd7c::/46, - 2406:840:fd81::/48, - 2406:840:fd82::/47, - 2406:840:fd84::/48, - 2406:840:fd87::/48, - 2406:840:fd8a::/47, - 2406:840:fd8c::/46, - 2406:840:fd94::/46, - 2406:840:fd98::/46, - 2406:840:fd9c::/47, - 2406:840:fd9e::/48, - 2406:840:fda1::/48, - 2406:840:fda2::/47, - 2406:840:fda4::/46, - 2406:840:fda8::/45, - 2406:840:fdb1::/48, - 2406:840:fdb2::/47, - 2406:840:fdb4::/46, - 2406:840:fdb8::/45, - 2406:840:fdc1::/48, - 2406:840:fdc2::/47, - 2406:840:fdc4::/46, - 2406:840:fdc8::/45, - 2406:840:fdd0::/44, - 2406:840:fde0::/43, - 2406:840:fe00::/43, - 2406:840:fe20::/46, - 2406:840:fe24::/47, - 2406:840:fe26::/48, - 2406:840:fe28::/45, - 2406:840:fe30::/44, - 2406:840:fe40::/44, - 2406:840:fe52::/47, - 2406:840:fe54::/46, - 2406:840:fe58::/45, - 2406:840:fe60::/43, - 2406:840:fe80::/44, - 2406:840:fe95::/48, - 2406:840:fe9c::/48, - 2406:840:fe9f::/48, - 2406:840:fea0::/48, - 2406:840:fea9::/48, - 2406:840:feb0::/47, - 2406:840:feb2::/48, - 2406:840:feb4::/46, - 2406:840:feb8::/45, - 2406:840:fec1::/48, - 2406:840:fec6::/47, - 2406:840:fec8::/47, - 2406:840:fed0::/48, - 2406:840:fed2::/48, - 2406:840:fed5::/48, - 2406:840:fed6::/48, - 2406:840:fed9::/48, - 2406:840:feda::/48, - 2406:840:fede::/48, - 2406:840:fee0::/45, - 2406:840:fee8::/46, - 2406:840:feec::/48, - 2406:840:feee::/47, - 2406:840:feff::/48, - 2406:840:ff00::/40, - 2406:880::/32, - 2406:8c0::/32, - 2406:d80::/32, - 2406:e80::/32, - 2406:f80::/32, - 2406:1080::/32, - 2406:1100::/32, - 2406:1180::/32, - 2406:1280::/32, - 2406:1380::/32, - 2406:1480::/32, - 2406:1580::/32, - 2406:15c0::/32, - 2406:1680::/32, - 2406:1780::/32, - 2406:1880::/32, - 2406:1980::/32, - 2406:1a80::/32, - 2406:1b80::/32, - 2406:1c80::/32, - 2406:1d80::/32, - 2406:1e40::/32, - 2406:1e80::/32, - 2406:1f80::/32, - 2406:2080::/32, - 2406:2640::/32, - 2406:2700::/32, - 2406:2780::/32, - 2406:2880::/32, - 2406:2980::/32, - 2406:2a80::/32, - 2406:2b80::/32, - 2406:2c40::/32, - 2406:2c80::/32, - 2406:2d80::/32, - 2406:2e80::/32, - 2406:2f80::/32, - 2406:3080::/32, - 2406:3180::/32, - 2406:31c0::/32, - 2406:3280::/32, - 2406:3300::/32, - 2406:3340::/32, - 2406:3380::/32, - 2406:3480::/32, - 2406:34c0::/32, - 2406:3580::/32, - 2406:3640::/32, - 2406:3680::/32, - 2406:3700::/32, - 2406:3780::/32, - 2406:3880::/32, - 2406:3980::/32, - 2406:39c0::/32, - 2406:3ac0::/32, - 2406:3e80::/32, - 2406:3f80::/32, - 2406:4080::/32, - 2406:40c0::/32, - 2406:4180::/32, - 2406:4280::/32, - 2406:42c0::/32, - 2406:4340::/32, - 2406:4380::/32, - 2406:43c0::/32, - 2406:4480::/32, - 2406:4500::/32, - 2406:4680::/32, - 2406:4b80::/32, - 2406:4c80::/32, - 2406:4d00::/32, - 2406:4d80::/32, - 2406:4e80::/32, - 2406:4f00::/32, - 2406:4f80::/32, - 2406:5080::/32, - 2406:50c0::/32, - 2406:5180::/32, - 2406:5280::/32, - 2406:52c0::/32, - 2406:5340::/32, - 2406:5380::/32, - 2406:5480::/32, - 2406:5580::/32, - 2406:5680::/32, - 2406:5780::/32, - 2406:5840::/31, - 2406:5940::/32, - 2406:5980::/32, - 2406:5a40::/32, - 2406:5ac0::/32, - 2406:5b40::/32, - 2406:5d80::/32, - 2406:5e80::/32, - 2406:5f80::/32, - 2406:6080::/32, - 2406:6100::/32, - 2406:6180::/32, - 2406:61c0::/29, - 2406:6280::/32, - 2406:6300::/32, - 2406:6340::/32, - 2406:6380::/32, - 2406:6480::/32, - 2406:6500::/32, - 2406:6580::/32, - 2406:65c0::/32, - 2406:6640::/32, - 2406:6680::/32, - 2406:6780::/32, - 2406:6880::/32, - 2406:6980::/32, - 2406:6a80::/32, - 2406:6b80::/32, - 2406:6bc0::/32, - 2406:6c80::/32, - 2406:6d80::/32, - 2406:6e80::/32, - 2406:6f80::/32, - 2406:7080::/32, - 2406:7280::/32, - 2406:7380::/32, - 2406:7480::/32, - 2406:7580::/32, - 2406:7680::/32, - 2406:7780::/32, - 2406:7880::/32, - 2406:7980::/32, - 2406:7a80::/32, - 2406:7b80::/32, - 2406:7c80::/32, - 2406:7d00::/32, - 2406:7d80::/32, - 2406:7e80::/32, - 2406:7f80::/32, - 2406:7fc0::/32, - 2406:8080::/32, - 2406:8180::/32, - 2406:8280::/32, - 2406:8380::/32, - 2406:8480::/32, - 2406:8500::/32, - 2406:8580::/32, - 2406:8780::/32, - 2406:8880::/32, - 2406:8980::/32, - 2406:8a80::/32, - 2406:8b80::/32, - 2406:8c80::/32, - 2406:8d80::/32, - 2406:8e80::/32, - 2406:8f40::/32, - 2406:8f80::/32, - 2406:9200::/32, - 2406:9380::/32, - 2406:9480::/32, - 2406:94c0::/32, - 2406:9780::/32, - 2406:9d80::/32, - 2406:9e80::/32, - 2406:9f80::/32, - 2406:a080::/32, - 2406:a180::/32, - 2406:a280::/32, - 2406:a380::/32, - 2406:a480::/32, - 2406:a580::/32, - 2406:a680::/32, - 2406:a780::/32, - 2406:a7c0::/32, - 2406:a880::/32, - 2406:a8c0::/32, - 2406:a980::/32, - 2406:aa80::/32, - 2406:aac0::/32, - 2406:ab80::/32, - 2406:ac80::/32, - 2406:acc0::/32, - 2406:ad40::/32, - 2406:ad80::/32, - 2406:ae80::/32, - 2406:af80::/32, - 2406:b080::/32, - 2406:b640::/32, - 2406:b880::/32, - 2406:b980::/32, - 2406:ba80::/32, - 2406:bb80::/32, - 2406:bc80::/32, - 2406:bd40::/32, - 2406:bd80::/32, - 2406:bdc0::/32, - 2406:be80::/32, - 2406:bf80::/32, - 2406:c080::/32, - 2406:c180::/32, - 2406:c280::/32, - 2406:c340::/32, - 2406:c480::/32, - 2406:c580::/32, - 2406:c680::/32, - 2406:c780::/32, - 2406:c880::/32, - 2406:c900::/32, - 2406:c980::/32, - 2406:ca80::/32, - 2406:cac0::/32, - 2406:cb80::/32, - 2406:cc80::/32, - 2406:cd80::/32, - 2406:ce80::/32, - 2406:cf00::/30, - 2406:cf80::/32, - 2406:d080::/32, - 2406:d140::/33, - 2406:d140:c000::/34, - 2406:d180::/32, - 2406:d280::/32, - 2406:d2c0::/32, - 2406:d380::/32, - 2406:d440::/32, - 2406:d480::/32, - 2406:d580::/32, - 2406:d680::/32, - 2406:d780::/32, - 2406:d880::/32, - 2406:d980::/32, - 2406:db80::/32, - 2406:dc80::/32, - 2406:dd00::/32, - 2406:dd80:400::/38, - 2406:dd80:c00::/38, - 2406:dd80:1000::/36, - 2406:dd80:2000::/35, - 2406:dd80:4000::/34, - 2406:dd80:8000::/33, - 2406:de80::/32, - 2406:df80::/32, - 2406:e080::/32, - 2406:e180::/32, - 2406:e2c0::/32, - 2406:e380::/32, - 2406:e3c0::/32, - 2406:e500::/32, - 2406:e580::/32, - 2406:e680::/32, - 2406:e780::/32, - 2406:e8c0::/32, - 2406:ea40::/28, - 2406:f280::/32, - 2406:f300::/32, - 2406:f4c0::/32, - 2406:f7c0::/32, - 2406:f980::/32, - 2406:fc80::/32, - 2406:fd80::/32, - 2406:fe80::/32, - 2406:ff00::/32, - 2407:480::/32, - 2407:580::/32, - 2407:cc0::/32, - 2407:f40::/32, - 2407:17c0::/32, - 2407:1900::/32, - 2407:1d00::/32, - 2407:2280::/32, - 2407:2380::/32, - 2407:23c0::/32, - 2407:2780::/32, - 2407:2840::/32, - 2407:2ac0::/32, - 2407:31c0::/32, - 2407:3340::/32, - 2407:3540::/32, - 2407:3700::/32, - 2407:3740::/32, - 2407:37c0::/32, - 2407:3900::/32, - 2407:3f40::/32, - 2407:43c0::/32, - 2407:4440::/32, - 2407:4580::/32, - 2407:4680::/32, - 2407:4740::/32, - 2407:4880::/32, - 2407:4980::/32, - 2407:4a80::/32, - 2407:4c80::/32, - 2407:4d80::/32, - 2407:4e80::/32, - 2407:4f00::/32, - 2407:5380::/32, - 2407:53c0::/32, - 2407:5500::/32, - 2407:5780::/32, - 2407:5840::/32, - 2407:6040::/32, - 2407:6580::/32, - 2407:6c40::/32, - 2407:7680::/32, - 2407:7780::/32, - 2407:7880::/32, - 2407:7980::/32, - 2407:7c80::/32, - 2407:7d00::/32, - 2407:7d80::/32, - 2407:7e80::/32, - 2407:8880::/32, - 2407:8b80::/32, - 2407:8f40::/32, - 2407:9080::/32, - 2407:9180::/32, - 2407:94c0::/32, - 2407:9680::/32, - 2407:9980::/32, - 2407:9b40::/32, - 2407:9bc0::/32, - 2407:9f00::/32, - 2407:9f80::/32, - 2407:a040::/32, - 2407:a640::/32, - 2407:a7c0::/32, - 2407:a880::/32, - 2407:a940::/32, - 2407:ad80::/32, - 2407:ae80::/32, - 2407:af80::/32, - 2407:b080::/32, - 2407:b180::/32, - 2407:b280::/32, - 2407:b380::/32, - 2407:b580::/32, - 2407:b680::/32, - 2407:b780::/32, - 2407:b880::/32, - 2407:b980::/32, - 2407:ba00::/32, - 2407:ba80::/32, - 2407:bb80::/32, - 2407:bc00::/32, - 2407:bc80::/32, - 2407:bd80::/32, - 2407:bdc0::/32, - 2407:be80::/32, - 2407:bf80::/32, - 2407:c080::/32, - 2407:c380::/32, - 2407:c400::/32, - 2407:c480::/32, - 2407:c580::/32, - 2407:c680::/32, - 2407:c780::/32, - 2407:c880::/32, - 2407:c900::/32, - 2407:c980::/32, - 2407:cb80::/32, - 2407:cc80::/32, - 2407:cd80::/32, - 2407:ce80::/32, - 2407:cf80::/32, - 2407:d480::/32, - 2407:d580::/32, - 2407:d680::/32, - 2407:d780::/32, - 2407:d7c0::/32, - 2407:d880::/32, - 2407:d8c0::/32, - 2407:d980::/32, - 2407:d9c0::/32, - 2407:da80::/32, - 2407:db80::/32, - 2407:dc80::/32, - 2407:dd80::/32, - 2407:de80::/32, - 2407:df80::/32, - 2407:dfc0::/32, - 2407:e080::/32, - 2407:e180::/32, - 2407:e280::/32, - 2407:e380::/32, - 2407:e480::/32, - 2407:e580::/32, - 2407:e680::/32, - 2407:e780::/32, - 2407:e800::/32, - 2407:ea80::/32, - 2407:eb80::/32, - 2407:ec40::/32, - 2407:ec80::/32, - 2407:ecc0::/32, - 2407:ed80::/32, - 2407:ee80::/32, - 2407:ef80::/32, - 2407:f080::/32, - 2407:f180::/32, - 2407:f280::/32, - 2407:f380::/32, - 2407:f480::/32, - 2407:f580::/32, - 2407:f680::/32, - 2407:f780::/32, - 2407:f880::/32, - 2407:f980::/32, - 2407:fa80::/32, - 2407:fb80::/32, - 2407:fc80::/32, - 2407:fd80::/32, - 2408:4000::/28, - 2408:4010::/30, - 2408:4014::/31, - 2408:4016:1::/48, - 2408:4016:2::/47, - 2408:4016:4::/46, - 2408:4016:8::/45, - 2408:4016:10::/44, - 2408:4016:20::/43, - 2408:4016:40::/42, - 2408:4016:80::/41, - 2408:4016:100::/40, - 2408:4016:200::/39, - 2408:4016:400::/38, - 2408:4016:800::/37, - 2408:4016:1000::/36, - 2408:4016:2000::/35, - 2408:4016:4000::/34, - 2408:4016:8000::/33, - 2408:4017::/32, - 2408:4018::/29, - 2408:4020::/27, - 2408:4040::/26, - 2408:4080::/25, - 2408:4100::/24, - 2408:4200::/23, - 2408:6000::/24, - 2408:8000::/20, - 2409:1000::/20, - 2409:2000::/21, - 2409:6000::/20, - 2409:8000::/21, - 2409:8800::/22, - 2409:8c00::/25, - 2409:8c80::/30, - 2409:8c84::/32, - 2409:8c85::/34, - 2409:8c85:4000::/36, - 2409:8c85:5000::/38, - 2409:8c85:5400::/43, - 2409:8c85:5420::/44, - 2409:8c85:5430::/47, - 2409:8c85:5433::/48, - 2409:8c85:5434::/46, - 2409:8c85:5438::/45, - 2409:8c85:5440::/42, - 2409:8c85:5480::/41, - 2409:8c85:5500::/40, - 2409:8c85:5600::/39, - 2409:8c85:5800::/37, - 2409:8c85:6000::/35, - 2409:8c85:8000::/33, - 2409:8c86::/31, - 2409:8c88::/29, - 2409:8c90::/28, - 2409:8ca0::/27, - 2409:8cc0::/26, - 2409:8d00::/24, - 2409:8e00::/23, - 240a:2000::/24, - 240a:4000::/21, - 240a:6000::/24, - 240a:8000::/21, - 240a:a000::/20, - 240a:c000::/20, - 240b:2000::/22, - 240b:4000::/31, - 240b:4002::/36, - 240b:4002:1000::/44, - 240b:4002:1011::/48, - 240b:4002:1012::/47, - 240b:4002:1014::/46, - 240b:4002:1018::/45, - 240b:4002:1020::/43, - 240b:4002:1040::/42, - 240b:4002:1080::/41, - 240b:4002:1100::/40, - 240b:4002:1200::/39, - 240b:4002:1400::/38, - 240b:4002:1800::/37, - 240b:4002:2000::/35, - 240b:4002:4000::/34, - 240b:4002:8000::/33, - 240b:4004::/31, - 240b:4006::/48, - 240b:4006:1000::/43, - 240b:4006:1020::/44, - 240b:4006:1100::/44, - 240b:4006:1110::/45, - 240b:4006:1118::/46, - 240b:4007::/32, - 240b:4009::/32, - 240b:400b::/32, - 240b:400c::/30, - 240b:4010:fffe::/47, - 240b:4011::/32, - 240b:4012::/31, - 240b:4014::/30, - 240b:4018::/30, - 240b:401f::/32, - 240b:6000::/20, - 240b:8000::/21, - 240b:a000::/25, - 240b:e000::/26, - 240c:0:1::/48, - 240c:0:2::/47, - 240c:0:4::/46, - 240c:0:8::/45, - 240c:0:10::/44, - 240c:0:20::/43, - 240c:0:40::/42, - 240c:0:80::/41, - 240c:0:100::/40, - 240c:0:200::/39, - 240c:0:400::/38, - 240c:0:800::/37, - 240c:0:1000::/36, - 240c:0:2000::/35, - 240c:0:4000::/34, - 240c:0:8000::/33, - 240c:6:2::/48, - 240c:6:4::/46, - 240c:6:8::/45, - 240c:6:10::/44, - 240c:6:20::/43, - 240c:6:40::/42, - 240c:6:80::/41, - 240c:6:100::/40, - 240c:6:200::/39, - 240c:6:400::/38, - 240c:6:800::/37, - 240c:6:1000::/36, - 240c:6:2000::/35, - 240c:6:4000::/34, - 240c:6:8000::/33, - 240c:f::/48, - 240c:f:2::/47, - 240c:f:4::/46, - 240c:f:8::/45, - 240c:f:10::/44, - 240c:f:20::/43, - 240c:f:40::/42, - 240c:f:80::/41, - 240c:f:100::/40, - 240c:f:200::/39, - 240c:f:400::/38, - 240c:f:800::/37, - 240c:f:1000::/36, - 240c:f:2000::/35, - 240c:f:4000::/34, - 240c:f:8000::/33, - 240c:4000::/22, - 240c:8000::/21, - 240c:c000::/20, - 240d:4000::/21, - 240d:8000::/24, - 240e::/21, - 240e:800::/24, - 240e:900::/26, - 240e:940::/27, - 240e:960::/28, - 240e:970::/29, - 240e:978::/30, - 240e:97c::/32, - 240e:97d::/33, - 240e:97d:8001::/48, - 240e:97d:8002::/47, - 240e:97d:8004::/46, - 240e:97d:8008::/45, - 240e:97d:8010::/44, - 240e:97d:8020::/43, - 240e:97d:8040::/42, - 240e:97d:8080::/41, - 240e:97d:8100::/40, - 240e:97d:8200::/39, - 240e:97d:8400::/38, - 240e:97d:8800::/37, - 240e:97d:9000::/36, - 240e:97d:a000::/35, - 240e:97d:c000::/34, - 240e:97e::/31, - 240e:980::/25, - 240e:a00::/23, - 240e:c00::/22, - 240e:1000::/20, - 240e:2000::/19, - 240f:4000::/24, - 240f:8000::/24, - 240f:c000::/24, - 2602:f70d::/36, - 2605:9d80:8001::/48, - 2605:9d80:8011::/48, - 2605:9d80:8021::/48, - 2605:9d80:8031::/48, - 2605:9d80:8041::/48, - 2605:9d80:8081::/48, - 2605:9d80:9003::/48, - 2605:9d80:9013::/48, - 2605:9d80:9023::/48, - 2605:9d80:9033::/48, - 2605:9d80:9042::/48, - 2605:9d80:9071::/48, - 2605:9d80:9092::/48, - 2a03:f900::/29, - 2a04:3e00::/48, - 2a04:3e00:2::/47, - 2a04:3e00:4::/46, - 2a04:3e00:8::/45, - 2a04:3e00:10::/44, - 2a04:3e00:20::/43, - 2a04:3e00:40::/42, - 2a04:3e00:80::/41, - 2a04:3e00:100::/40, - 2a04:3e00:200::/39, - 2a04:3e00:400::/38, - 2a04:3e00:800::/37, - 2a04:3e00:1001::/48, - 2a04:3e00:1002::/47, - 2a04:3e00:1004::/46, - 2a04:3e00:1008::/45, - 2a04:3e00:1010::/44, - 2a04:3e00:1020::/43, - 2a04:3e00:1040::/42, - 2a04:3e00:1080::/41, - 2a04:3e00:1100::/40, - 2a04:3e00:1200::/39, - 2a04:3e00:1400::/38, - 2a04:3e00:1800::/37, - 2a04:3e00:2000::/35, - 2a04:3e00:4000::/34, - 2a04:3e00:8000::/33, - 2a04:3e01::/32, - 2a04:3e02::/31, - 2a04:3e04::/30, - 2a04:f580:8010::/47, - 2a04:f580:8090::/48, - 2a04:f580:8210::/47, - 2a04:f580:8290::/48, - 2a04:f580:9010::/48, - 2a04:f580:9012::/47, - 2a04:f580:9020::/48, - 2a04:f580:9040::/48, - 2a04:f580:9050::/48, - 2a04:f580:9060::/48, - 2a04:f580:9070::/48, - 2a04:f580:9210::/48, - 2a04:f580:9212::/47, - 2a04:f580:9220::/48, - 2a04:f580:9230::/48, - 2a04:f580:9240::/48, - 2a04:f580:9250::/48, - 2a04:f580:9260::/48, - 2a04:f580:9270::/48, - 2a04:f580:9280::/48, - 2a04:f580:9290::/48, - 2a05:1085::/32, - 2a0a:2840::/29, - 2a0a:d680::/37, - 2a0a:d680:800::/39, - 2a0a:d680:a00::/43, - 2a0a:d680:a20::/44, - 2a0a:d680:a30::/48, - 2a0a:d680:a32::/47, - 2a0a:d680:a34::/46, - 2a0a:d680:a38::/45, - 2a0a:d680:a40::/42, - 2a0a:d680:a80::/41, - 2a0a:d680:b00::/40, - 2a0a:d680:c00::/38, - 2a0a:d680:1000::/36, - 2a0a:d680:2000::/35, - 2a0a:d680:4000::/34, - 2a0a:d680:8000::/40, - 2a0a:d680:8102::/47, - 2a0a:d680:8104::/46, - 2a0a:d680:8108::/45, - 2a0a:d680:8110::/44, - 2a0a:d680:8120::/43, - 2a0a:d680:8140::/42, - 2a0a:d680:8180::/41, - 2a0a:d680:8200::/39, - 2a0a:d680:8400::/38, - 2a0a:d680:8800::/37, - 2a0a:d680:9000::/36, - 2a0a:d680:a000::/35, - 2a0a:d680:c000::/34, - 2a0a:d681::/33, - 2a0a:d681:8000::/34, - 2a0a:d681:c000::/35, - 2a0a:d681:e100::/40, - 2a0a:d681:e200::/39, - 2a0a:d681:e400::/38, - 2a0a:d681:e800::/37, - 2a0a:d681:f000::/36, - 2a0a:d682::/33, - 2a0a:d682:8000::/34, - 2a0a:d682:c000::/36, - 2a0a:d683::/32, - 2a0a:d684::/32, - 2a0a:d685::/40, - 2a0a:d685:100::/41, - 2a0a:d685:180::/42, - 2a0a:d685:1c0::/44, - 2a0a:d685:1d1::/48, - 2a0a:d685:1d2::/47, - 2a0a:d685:1d4::/46, - 2a0a:d685:1d8::/45, - 2a0a:d685:1e2::/47, - 2a0a:d685:1e4::/46, - 2a0a:d685:1e8::/45, - 2a0a:d685:1f0::/45, - 2a0a:d685:1f8::/47, - 2a0a:d685:1fa::/48, - 2a0a:d685:200::/48, - 2a0a:d685:202::/47, - 2a0a:d685:204::/46, - 2a0a:d685:208::/45, - 2a0a:d685:210::/44, - 2a0a:d685:220::/43, - 2a0a:d685:240::/42, - 2a0a:d685:280::/41, - 2a0a:d685:400::/38, - 2a0a:d685:800::/37, - 2a0a:d685:1000::/36, - 2a0a:d685:2000::/35, - 2a0a:d685:4000::/34, - 2a0a:d685:8000::/33, - 2a0a:d686::/32, - 2a0a:d687::/33, - 2a0a:d687:8000::/34, - 2a0a:d687:c000::/35, - 2a0a:d687:e000::/36, - 2a0a:d687:f000::/48, - 2a0a:d687:f002::/47, - 2a0a:d687:f006::/48, - 2a0a:d687:f009::/48, - 2a0a:d687:f00a::/47, - 2a0a:d687:f00c::/46, - 2a0a:d687:f010::/44, - 2a0a:d687:f020::/43, - 2a0a:d687:f040::/42, - 2a0a:d687:f080::/41, - 2a0a:d687:f100::/40, - 2a0a:d687:f200::/39, - 2a0a:d687:f400::/38, - 2a0a:d687:f800::/37, - 2a0c:b641:573::/48, - 2a0e:7580::/32, - 2a0e:7582::/31, - 2a0e:7584::/30, - 2a0e:aa06:49f::/48, - 2a0e:b107:740::/44, - 2a13:1800:1::/48, - 2a13:1800:2::/47, - 2a13:1800:4::/46, - 2a13:1800:8::/45, - 2a13:1800:11::/48, - 2a13:1800:12::/47, - 2a13:1800:14::/46, - 2a13:1800:18::/45, - 2a13:1800:20::/43, - 2a13:1800:40::/42, - 2a13:1800:90::/44, - 2a13:1800:a0::/43, - 2a13:1800:c0::/42, - 2a13:1800:100::/40, - 2a13:1800:200::/40, - 2a13:1800:310::/44, - 2a13:1800:320::/43, - 2a13:1800:340::/42, - 2a13:1800:380::/41, - 2a13:1800:400::/38, - 2a13:1800:800::/37, - 2a13:1800:1000::/36, - 2a13:1800:2000::/35, - 2a13:1800:4000::/34, - 2a13:1800:8000::/33, - 2a13:1801::/40, - 2a13:1801:100::/41, - 2a13:1801:1a0::/43, - 2a13:1801:1c0::/42, - 2a13:1801:210::/44, - 2a13:1801:220::/43, - 2a13:1801:240::/42, - 2a13:1801:280::/41, - 2a13:1801:300::/40, - 2a13:1801:400::/38, - 2a13:1801:800::/37, - 2a13:1801:1000::/36, - 2a13:1801:2000::/35, - 2a13:1801:4000::/34, - 2a13:1801:8000::/33, - 2a13:1802:20::/43, - 2a13:1802:40::/42, - 2a13:1802:80::/41, - 2a13:1802:100::/40, - 2a13:1802:200::/39, - 2a13:1802:400::/38, - 2a13:1802:800::/37, - 2a13:1802:1000::/36, - 2a13:1802:2000::/35, - 2a13:1802:4000::/34, - 2a13:1802:8000::/34, - 2a13:1802:c000::/48, - 2a13:1802:c002::/47, - 2a13:1802:c004::/46, - 2a13:1802:c008::/45, - 2a13:1802:c020::/43, - 2a13:1802:c040::/42, - 2a13:1802:c080::/41, - 2a13:1802:c100::/40, - 2a13:1802:c200::/39, - 2a13:1802:c400::/38, - 2a13:1802:c800::/37, - 2a13:1802:d000::/36, - 2a13:1802:e000::/35, - 2a13:1803::/32, - 2a13:1804::/30, - 2a13:8b40::/29, - 2c0f:f7a8:8011::/48, - 2c0f:f7a8:8050::/48, - 2c0f:f7a8:805f::/48, - 2c0f:f7a8:8150::/48, - 2c0f:f7a8:815f::/48, - 2c0f:f7a8:8211::/48, - 2c0f:f7a8:9041::/48 - } -} diff --git a/clashoo/files/usr/share/clashoo/nftables/geoip_cn.nft b/clashoo/files/usr/share/clashoo/nftables/geoip_cn.nft deleted file mode 100644 index 26ac0cf7..00000000 --- a/clashoo/files/usr/share/clashoo/nftables/geoip_cn.nft +++ /dev/null @@ -1,6529 +0,0 @@ -set clashoo_china { - type ipv4_addr; - flags interval; - auto-merge; - elements = { - 1.0.1.0/24, - 1.0.2.0/23, - 1.0.8.0/21, - 1.0.32.0/19, - 1.1.0.0/24, - 1.1.2.0/23, - 1.1.4.0/22, - 1.1.8.0/21, - 1.1.16.0/20, - 1.1.32.0/19, - 1.2.0.0/23, - 1.2.2.0/24, - 1.2.4.0/22, - 1.2.8.0/21, - 1.2.16.0/20, - 1.2.32.0/19, - 1.2.64.0/18, - 1.3.0.0/16, - 1.4.1.0/24, - 1.4.2.0/23, - 1.4.4.0/22, - 1.4.8.0/21, - 1.4.16.0/20, - 1.4.32.0/19, - 1.4.64.0/18, - 1.8.0.0/16, - 1.10.0.0/21, - 1.10.8.0/23, - 1.10.11.0/24, - 1.10.12.0/22, - 1.10.16.0/20, - 1.10.32.0/19, - 1.10.64.0/18, - 1.12.0.0/14, - 1.24.0.0/13, - 1.45.0.0/16, - 1.48.0.0/14, - 1.56.0.0/13, - 1.68.0.0/14, - 1.80.0.0/12, - 1.116.0.0/15, - 1.118.0.0/23, - 1.118.4.0/22, - 1.118.8.0/21, - 1.118.16.0/20, - 1.118.37.0/24, - 1.118.38.0/23, - 1.118.40.0/21, - 1.118.56.0/21, - 1.118.96.0/19, - 1.118.128.0/17, - 1.119.0.0/16, - 1.180.0.0/14, - 1.184.0.0/15, - 1.188.0.0/14, - 1.192.0.0/13, - 1.202.0.0/15, - 1.204.0.0/14, - 5.10.138.0/23, - 5.10.140.0/24, - 5.10.143.0/24, - 5.181.224.0/23, - 8.128.4.0/22, - 8.128.32.0/19, - 8.128.64.0/19, - 8.128.96.0/20, - 8.129.0.0/16, - 8.130.0.0/15, - 8.132.0.0/14, - 8.136.0.0/13, - 8.144.0.0/14, - 8.148.0.0/19, - 8.148.36.0/22, - 8.148.41.0/24, - 8.148.43.0/24, - 8.148.64.0/18, - 8.148.128.0/17, - 8.149.0.0/16, - 8.150.0.0/19, - 8.150.32.0/21, - 8.150.64.0/23, - 8.152.0.0/13, - 8.160.0.0/15, - 8.162.0.0/17, - 8.163.0.0/16, - 8.164.0.0/14, - 8.168.0.0/15, - 8.176.0.0/17, - 8.176.128.0/19, - 8.208.0.0/17, - 8.208.128.0/21, - 8.208.140.0/22, - 8.208.144.0/20, - 8.208.160.0/19, - 8.208.192.0/18, - 8.209.0.0/19, - 8.209.36.0/22, - 8.209.40.0/21, - 8.209.48.0/20, - 8.209.64.0/18, - 8.209.128.0/18, - 8.209.192.0/24, - 8.209.194.0/23, - 8.209.196.0/22, - 8.209.200.0/21, - 8.209.208.0/20, - 8.209.224.0/19, - 8.210.0.0/16, - 8.211.0.0/17, - 8.211.128.0/18, - 8.211.192.0/19, - 8.211.224.0/22, - 8.211.232.0/21, - 8.211.240.0/20, - 8.212.0.0/18, - 8.212.64.0/20, - 8.212.80.0/21, - 8.212.88.0/22, - 8.212.92.0/24, - 8.212.94.0/23, - 8.212.96.0/22, - 8.212.104.0/21, - 8.212.112.0/20, - 8.212.128.0/19, - 8.212.160.0/20, - 8.212.176.0/21, - 8.212.188.0/22, - 8.212.192.0/18, - 8.213.0.0/16, - 8.214.0.0/17, - 8.214.128.0/19, - 8.214.164.0/22, - 8.214.168.0/21, - 8.214.176.0/20, - 8.214.192.0/18, - 8.215.0.0/17, - 8.215.128.0/19, - 8.215.160.0/22, - 8.215.168.0/21, - 8.215.176.0/20, - 8.215.192.0/18, - 8.216.0.0/18, - 8.216.64.0/21, - 8.216.72.0/22, - 8.216.80.0/20, - 8.216.96.0/19, - 8.216.128.0/17, - 8.217.0.0/16, - 8.218.0.0/15, - 8.220.0.0/18, - 8.220.64.0/19, - 8.220.96.0/20, - 8.220.112.0/21, - 8.220.120.0/22, - 8.220.128.0/19, - 8.220.160.0/21, - 8.220.172.0/22, - 8.220.176.0/20, - 8.220.192.0/19, - 8.220.224.0/21, - 8.220.232.0/22, - 8.220.240.0/21, - 8.221.0.0/17, - 8.221.128.0/20, - 8.221.144.0/21, - 8.221.156.0/22, - 8.221.160.0/19, - 8.221.192.0/18, - 8.222.0.0/15, - 14.0.0.0/21, - 14.0.12.0/22, - 14.1.0.0/22, - 14.1.24.0/22, - 14.1.108.0/22, - 14.1.112.0/22, - 14.16.0.0/12, - 14.102.128.0/22, - 14.102.180.0/22, - 14.103.0.0/16, - 14.104.0.0/13, - 14.112.0.0/12, - 14.130.0.0/15, - 14.134.0.0/15, - 14.144.0.0/12, - 14.192.60.0/22, - 14.192.76.0/22, - 14.196.0.0/15, - 14.204.0.0/15, - 14.208.0.0/12, - 16.2.142.0/23, - 27.0.128.0/21, - 27.0.160.0/21, - 27.0.188.0/22, - 27.0.204.0/22, - 27.0.208.0/21, - 27.8.0.0/13, - 27.16.0.0/12, - 27.34.232.0/21, - 27.36.0.0/14, - 27.40.0.0/13, - 27.50.40.0/21, - 27.50.128.0/17, - 27.54.72.0/21, - 27.54.152.0/21, - 27.54.192.0/18, - 27.98.208.0/20, - 27.98.224.0/19, - 27.99.128.0/17, - 27.103.0.0/16, - 27.106.128.0/18, - 27.106.204.0/22, - 27.109.32.0/19, - 27.109.124.0/22, - 27.112.0.0/18, - 27.112.80.0/20, - 27.112.112.0/21, - 27.113.128.0/18, - 27.115.0.0/17, - 27.116.44.0/22, - 27.121.72.0/21, - 27.121.120.0/21, - 27.128.0.0/15, - 27.131.220.0/22, - 27.144.0.0/16, - 27.148.0.0/14, - 27.152.0.0/13, - 27.184.0.0/13, - 27.192.0.0/11, - 27.224.0.0/14, - 36.0.0.0/22, - 36.0.8.0/21, - 36.0.16.0/20, - 36.0.32.0/19, - 36.0.64.0/18, - 36.0.128.0/17, - 36.1.0.0/16, - 36.4.0.0/14, - 36.16.0.0/12, - 36.32.0.0/14, - 36.36.0.0/16, - 36.37.0.0/19, - 36.37.36.0/23, - 36.37.39.0/24, - 36.37.40.0/21, - 36.37.48.0/20, - 36.40.0.0/13, - 36.48.0.0/15, - 36.50.226.0/23, - 36.50.254.0/23, - 36.51.0.0/16, - 36.56.0.0/13, - 36.96.0.0/11, - 36.128.0.0/13, - 36.136.0.0/14, - 36.140.0.0/17, - 36.140.128.0/18, - 36.140.192.0/20, - 36.140.208.0/21, - 36.140.216.0/23, - 36.140.218.0/24, - 36.140.220.0/22, - 36.140.224.0/19, - 36.141.0.0/16, - 36.142.0.0/15, - 36.144.0.0/12, - 36.160.0.0/11, - 36.192.0.0/11, - 36.248.0.0/14, - 36.254.0.0/16, - 36.255.116.0/22, - 36.255.128.0/22, - 36.255.164.0/22, - 36.255.172.0/22, - 36.255.176.0/22, - 39.0.0.0/24, - 39.0.2.0/23, - 39.0.4.0/22, - 39.0.8.0/21, - 39.0.16.0/20, - 39.0.32.0/19, - 39.0.64.0/18, - 39.0.128.0/17, - 39.64.0.0/11, - 39.96.0.0/16, - 39.97.0.0/17, - 39.97.128.0/18, - 39.97.192.0/21, - 39.97.200.0/22, - 39.97.208.0/20, - 39.97.224.0/19, - 39.98.0.0/15, - 39.100.0.0/14, - 39.104.0.0/14, - 39.108.0.0/16, - 39.128.0.0/10, - 40.72.0.0/15, - 40.125.128.0/17, - 40.126.64.0/18, - 40.162.0.0/16, - 42.0.0.0/22, - 42.0.8.0/21, - 42.0.16.0/21, - 42.0.24.0/22, - 42.0.32.0/19, - 42.0.128.0/18, - 42.0.192.0/21, - 42.0.201.0/24, - 42.0.202.0/23, - 42.0.204.0/22, - 42.0.208.0/20, - 42.0.224.0/19, - 42.1.0.0/19, - 42.1.32.0/20, - 42.1.48.0/21, - 42.1.56.0/22, - 42.1.128.0/17, - 42.4.0.0/14, - 42.48.0.0/13, - 42.56.0.0/14, - 42.62.0.0/17, - 42.62.128.0/19, - 42.62.160.0/20, - 42.62.180.0/22, - 42.62.184.0/21, - 42.63.0.0/16, - 42.80.0.0/15, - 42.83.64.0/20, - 42.83.80.0/22, - 42.83.88.0/21, - 42.83.96.0/19, - 42.83.128.0/17, - 42.84.0.0/14, - 42.88.0.0/13, - 42.96.64.0/19, - 42.96.96.0/21, - 42.96.108.0/22, - 42.96.112.0/20, - 42.96.128.0/17, - 42.97.0.0/16, - 42.99.0.0/18, - 42.99.64.0/19, - 42.99.96.0/20, - 42.99.112.0/22, - 42.99.120.0/21, - 42.100.0.0/14, - 42.120.0.0/15, - 42.122.0.0/16, - 42.123.0.0/19, - 42.123.36.0/22, - 42.123.40.0/21, - 42.123.48.0/20, - 42.123.64.0/18, - 42.123.128.0/17, - 42.128.0.0/12, - 42.156.0.0/19, - 42.156.36.0/22, - 42.156.40.0/21, - 42.156.48.0/20, - 42.156.64.0/18, - 42.156.128.0/17, - 42.157.0.0/16, - 42.158.0.0/15, - 42.160.0.0/12, - 42.176.0.0/13, - 42.184.0.0/15, - 42.186.0.0/16, - 42.187.0.0/18, - 42.187.64.0/19, - 42.187.96.0/20, - 42.187.112.0/21, - 42.187.120.0/22, - 42.187.128.0/17, - 42.192.0.0/13, - 42.201.0.0/17, - 42.202.0.0/15, - 42.204.0.0/14, - 42.208.0.0/12, - 42.224.0.0/12, - 42.240.0.0/17, - 42.240.128.0/18, - 42.240.192.0/19, - 42.240.224.0/20, - 42.240.240.0/21, - 42.240.248.0/23, - 42.242.0.0/15, - 42.244.0.0/14, - 42.248.0.0/13, - 43.90.0.0/16, - 43.92.0.0/15, - 43.94.0.0/18, - 43.96.0.0/23, - 43.96.3.0/24, - 43.96.4.0/22, - 43.96.8.0/22, - 43.96.18.0/24, - 43.96.20.0/22, - 43.96.24.0/22, - 43.96.32.0/22, - 43.96.40.0/24, - 43.96.42.0/24, - 43.96.44.0/23, - 43.96.46.0/24, - 43.96.48.0/21, - 43.96.59.0/24, - 43.96.60.0/24, - 43.96.62.0/23, - 43.96.64.0/21, - 43.96.72.0/22, - 43.96.78.0/24, - 43.96.80.0/23, - 43.96.85.0/24, - 43.96.86.0/24, - 43.96.88.0/23, - 43.96.90.0/24, - 43.96.92.0/22, - 43.96.96.0/23, - 43.96.100.0/23, - 43.96.103.0/24, - 43.96.104.0/23, - 43.96.107.0/24, - 43.96.109.0/24, - 43.96.110.0/23, - 43.96.112.0/22, - 43.96.116.0/24, - 43.96.118.0/23, - 43.96.120.0/24, - 43.96.122.0/24, - 43.96.124.0/23, - 43.96.126.0/24, - 43.97.0.0/17, - 43.98.0.0/15, - 43.100.0.0/15, - 43.102.0.0/17, - 43.102.192.0/18, - 43.103.0.0/16, - 43.104.0.0/14, - 43.108.0.0/16, - 43.110.0.0/15, - 43.112.0.0/15, - 43.114.0.0/16, - 43.116.0.0/17, - 43.116.160.0/24, - 43.116.192.0/18, - 43.117.0.0/16, - 43.118.0.0/17, - 43.118.128.0/18, - 43.119.0.0/16, - 43.120.0.0/15, - 43.122.0.0/16, - 43.123.0.0/17, - 43.123.128.0/18, - 43.124.0.0/16, - 43.125.0.0/19, - 43.125.32.0/20, - 43.125.48.0/21, - 43.126.0.0/17, - 43.136.0.0/13, - 43.144.0.0/15, - 43.148.0.0/14, - 43.176.0.0/12, - 43.192.0.0/14, - 43.196.0.0/15, - 43.224.12.0/22, - 43.224.24.0/22, - 43.224.44.0/22, - 43.224.52.0/22, - 43.224.56.0/22, - 43.224.68.0/22, - 43.224.72.0/22, - 43.224.80.0/22, - 43.224.100.0/22, - 43.224.160.0/22, - 43.224.176.0/22, - 43.224.184.0/22, - 43.224.200.0/21, - 43.224.208.0/21, - 43.224.216.0/22, - 43.224.240.0/22, - 43.225.76.0/22, - 43.225.84.0/22, - 43.225.120.0/22, - 43.225.175.0/24, - 43.225.180.0/22, - 43.225.208.0/22, - 43.225.216.0/21, - 43.225.224.0/20, - 43.225.240.0/21, - 43.225.252.0/22, - 43.226.32.0/19, - 43.226.64.0/19, - 43.226.96.0/20, - 43.226.112.0/21, - 43.226.120.0/22, - 43.226.128.0/18, - 43.226.192.0/20, - 43.226.208.0/21, - 43.226.236.0/22, - 43.226.240.0/20, - 43.227.0.0/21, - 43.227.8.0/22, - 43.227.32.0/19, - 43.227.64.0/19, - 43.227.96.0/21, - 43.227.104.0/22, - 43.227.136.0/21, - 43.227.144.0/22, - 43.227.152.0/21, - 43.227.160.0/20, - 43.227.176.0/21, - 43.227.188.0/22, - 43.227.192.0/19, - 43.227.232.0/22, - 43.227.248.0/21, - 43.228.0.0/18, - 43.228.64.0/21, - 43.228.76.0/22, - 43.228.100.0/22, - 43.228.116.0/22, - 43.228.120.0/22, - 43.228.132.0/22, - 43.228.136.0/22, - 43.228.148.0/22, - 43.228.152.0/22, - 43.228.188.0/22, - 43.228.204.0/22, - 43.228.240.0/22, - 43.229.40.0/22, - 43.229.48.0/22, - 43.229.56.0/22, - 43.229.96.0/22, - 43.229.136.0/21, - 43.229.144.0/22, - 43.229.168.0/21, - 43.229.176.0/20, - 43.229.192.0/21, - 43.229.216.0/21, - 43.229.232.0/21, - 43.230.20.0/22, - 43.230.32.0/22, - 43.230.68.0/22, - 43.230.72.0/22, - 43.230.124.0/22, - 43.230.220.0/22, - 43.230.224.0/19, - 43.231.32.0/20, - 43.231.80.0/20, - 43.231.96.0/20, - 43.231.136.0/21, - 43.231.144.0/20, - 43.231.160.0/20, - 43.231.176.0/21, - 43.236.0.0/16, - 43.237.0.0/17, - 43.237.128.0/18, - 43.237.192.0/22, - 43.237.200.0/21, - 43.237.208.0/20, - 43.237.224.0/19, - 43.238.0.0/16, - 43.239.0.0/19, - 43.239.32.0/20, - 43.239.48.0/22, - 43.239.116.0/22, - 43.239.120.0/22, - 43.239.172.0/22, - 43.239.176.0/23, - 43.239.179.0/24, - 43.240.0.0/22, - 43.240.56.0/21, - 43.240.68.0/22, - 43.240.72.0/21, - 43.240.84.0/22, - 43.240.124.0/22, - 43.240.128.0/21, - 43.240.136.0/22, - 43.240.156.0/22, - 43.240.192.0/19, - 43.240.240.0/20, - 43.241.0.0/20, - 43.241.16.0/21, - 43.241.48.0/22, - 43.241.76.0/22, - 43.241.80.0/20, - 43.241.100.0/23, - 43.241.112.0/22, - 43.241.168.0/21, - 43.241.176.0/21, - 43.241.184.0/22, - 43.241.208.0/20, - 43.241.224.0/20, - 43.241.240.0/22, - 43.241.248.0/22, - 43.242.8.0/21, - 43.242.16.0/20, - 43.242.48.0/22, - 43.242.53.0/24, - 43.242.54.0/24, - 43.242.56.0/21, - 43.242.64.0/22, - 43.242.72.0/21, - 43.242.80.0/20, - 43.242.96.0/22, - 43.242.144.0/20, - 43.242.160.0/21, - 43.242.168.0/22, - 43.242.180.0/22, - 43.242.189.0/24, - 43.242.190.0/23, - 43.242.192.0/21, - 43.242.204.0/22, - 43.242.216.0/21, - 43.242.252.0/22, - 43.243.4.0/22, - 43.243.8.0/21, - 43.243.16.0/22, - 43.243.88.0/22, - 43.243.128.0/22, - 43.243.136.0/22, - 43.243.144.0/21, - 43.243.156.0/22, - 43.243.180.0/22, - 43.243.228.0/22, - 43.243.232.0/22, - 43.243.244.0/22, - 43.246.0.0/18, - 43.246.64.0/19, - 43.246.96.0/22, - 43.246.112.0/22, - 43.246.228.0/22, - 43.247.4.0/22, - 43.247.8.0/22, - 43.247.44.0/22, - 43.247.48.0/22, - 43.247.68.0/22, - 43.247.76.0/22, - 43.247.84.0/22, - 43.247.88.0/21, - 43.247.96.0/21, - 43.247.108.0/22, - 43.247.112.0/22, - 43.247.148.0/22, - 43.247.152.0/22, - 43.247.176.0/20, - 43.247.196.0/22, - 43.247.200.0/21, - 43.247.208.0/20, - 43.247.224.0/22, - 43.247.232.0/21, - 43.247.240.0/20, - 43.248.0.0/21, - 43.248.20.0/22, - 43.248.28.0/22, - 43.248.48.0/22, - 43.248.76.0/22, - 43.248.80.0/20, - 43.248.96.0/19, - 43.248.128.0/20, - 43.248.144.0/21, - 43.248.176.0/20, - 43.248.192.0/20, - 43.248.208.0/22, - 43.248.228.0/22, - 43.248.232.0/22, - 43.248.244.0/22, - 43.249.4.0/22, - 43.249.120.0/22, - 43.249.132.0/22, - 43.249.136.0/22, - 43.249.144.0/20, - 43.249.160.0/21, - 43.249.168.0/22, - 43.249.192.0/22, - 43.249.236.0/22, - 43.250.4.0/22, - 43.250.12.0/22, - 43.250.16.0/21, - 43.250.28.0/22, - 43.250.32.0/21, - 43.250.96.0/21, - 43.250.108.0/22, - 43.250.112.0/22, - 43.250.128.0/22, - 43.250.144.0/21, - 43.250.160.0/22, - 43.250.168.0/22, - 43.250.176.0/22, - 43.250.180.0/23, - 43.250.200.0/22, - 43.250.212.0/22, - 43.250.216.0/21, - 43.250.236.0/22, - 43.250.244.0/22, - 43.251.4.0/22, - 43.251.36.0/22, - 43.251.118.0/23, - 43.251.192.0/22, - 43.251.232.0/22, - 43.251.244.0/22, - 43.252.48.0/22, - 43.252.56.0/22, - 43.254.0.0/21, - 43.254.8.0/22, - 43.254.24.0/22, - 43.254.36.0/22, - 43.254.44.0/22, - 43.254.52.0/22, - 43.254.72.0/22, - 43.254.84.0/22, - 43.254.88.0/21, - 43.254.100.0/22, - 43.254.104.0/22, - 43.254.112.0/21, - 43.254.128.0/22, - 43.254.136.0/21, - 43.254.144.0/20, - 43.254.168.0/21, - 43.254.180.0/22, - 43.254.184.0/21, - 43.254.192.0/21, - 43.254.200.0/22, - 43.254.208.0/22, - 43.254.220.0/22, - 43.254.224.0/20, - 43.254.240.0/22, - 43.254.248.0/21, - 43.255.0.0/21, - 43.255.8.0/22, - 43.255.48.0/22, - 43.255.64.0/20, - 43.255.84.0/22, - 43.255.96.0/22, - 43.255.144.0/22, - 43.255.176.0/22, - 43.255.184.0/22, - 43.255.192.0/22, - 43.255.200.0/21, - 43.255.208.0/21, - 43.255.224.0/21, - 43.255.232.0/22, - 43.255.244.0/22, - 44.30.120.0/24, - 45.40.192.0/18, - 45.65.16.0/20, - 45.112.132.0/22, - 45.112.188.0/22, - 45.112.208.0/20, - 45.112.228.0/22, - 45.112.232.0/21, - 45.113.12.0/22, - 45.113.16.0/20, - 45.113.40.0/22, - 45.113.52.0/22, - 45.113.56.0/22, - 45.113.72.0/22, - 45.113.144.0/21, - 45.113.168.0/22, - 45.113.176.0/22, - 45.113.184.0/22, - 45.113.200.0/21, - 45.113.208.0/20, - 45.113.240.0/22, - 45.113.252.0/22, - 45.114.0.0/22, - 45.114.32.0/22, - 45.114.40.0/22, - 45.114.52.0/22, - 45.114.96.0/22, - 45.114.136.0/22, - 45.114.196.0/22, - 45.114.200.0/22, - 45.114.228.0/22, - 45.114.252.0/22, - 45.115.18.0/23, - 45.115.44.0/22, - 45.115.100.0/22, - 45.115.120.0/22, - 45.115.132.0/22, - 45.115.144.0/22, - 45.115.156.0/22, - 45.115.164.0/22, - 45.115.200.0/22, - 45.115.212.0/22, - 45.115.244.0/22, - 45.115.248.0/22, - 45.116.16.0/22, - 45.116.24.0/22, - 45.116.32.0/21, - 45.116.52.0/22, - 45.116.96.0/21, - 45.116.140.0/22, - 45.116.152.0/22, - 45.116.208.0/22, - 45.117.8.0/22, - 45.117.20.0/22, - 45.117.68.0/22, - 45.117.124.0/22, - 45.117.252.0/22, - 45.119.42.0/23, - 45.119.60.0/22, - 45.119.64.0/21, - 45.119.72.0/22, - 45.119.104.0/22, - 45.119.116.0/22, - 45.119.232.0/22, - 45.120.100.0/22, - 45.120.140.0/22, - 45.120.164.0/22, - 45.120.240.0/22, - 45.121.52.0/22, - 45.121.64.0/21, - 45.121.72.0/22, - 45.121.92.0/22, - 45.121.172.0/22, - 45.121.176.0/22, - 45.121.215.0/24, - 45.121.240.0/20, - 45.122.0.0/19, - 45.122.32.0/21, - 45.122.40.0/22, - 45.122.60.0/22, - 45.122.64.0/19, - 45.122.96.0/20, - 45.122.112.0/21, - 45.122.160.0/19, - 45.122.192.0/20, - 45.122.208.0/21, - 45.122.216.0/22, - 45.123.28.0/22, - 45.123.32.0/21, - 45.123.44.0/22, - 45.123.48.0/20, - 45.123.64.0/20, - 45.123.80.0/21, - 45.123.88.0/22, - 45.123.120.0/22, - 45.123.128.0/21, - 45.123.136.0/22, - 45.123.148.0/22, - 45.123.152.0/21, - 45.123.164.0/22, - 45.123.168.0/21, - 45.123.176.0/21, - 45.123.184.0/22, - 45.123.204.0/22, - 45.123.212.0/22, - 45.123.224.0/19, - 45.124.0.0/22, - 45.124.20.0/22, - 45.124.28.0/22, - 45.124.32.0/21, - 45.124.68.0/22, - 45.124.76.0/22, - 45.124.80.0/22, - 45.124.100.0/22, - 45.124.124.0/22, - 45.124.172.0/22, - 45.124.176.0/22, - 45.124.208.0/22, - 45.124.248.0/22, - 45.125.24.0/22, - 45.125.44.0/22, - 45.125.52.0/22, - 45.125.56.0/22, - 45.125.76.0/22, - 45.125.80.0/20, - 45.125.96.0/21, - 45.125.136.0/22, - 45.126.48.0/21, - 45.126.100.0/22, - 45.126.108.0/22, - 45.126.112.0/21, - 45.126.120.0/22, - 45.126.212.0/22, - 45.126.220.0/22, - 45.127.8.0/21, - 45.127.128.0/22, - 45.127.144.0/21, - 45.127.156.0/22, - 45.199.179.0/24, - 45.248.8.0/22, - 45.248.80.0/21, - 45.248.96.0/20, - 45.248.128.0/21, - 45.248.204.0/22, - 45.248.208.0/20, - 45.248.224.0/19, - 45.249.0.0/21, - 45.249.12.0/22, - 45.249.16.0/20, - 45.249.32.0/21, - 45.249.112.0/22, - 45.249.188.0/22, - 45.249.192.0/20, - 45.249.208.0/21, - 45.250.12.0/22, - 45.250.16.0/22, - 45.250.28.0/22, - 45.250.32.0/21, - 45.250.40.0/22, - 45.250.76.0/22, - 45.250.80.0/20, - 45.250.96.0/22, - 45.250.104.0/21, - 45.250.112.0/20, - 45.250.128.0/20, - 45.250.144.0/21, - 45.250.152.0/22, - 45.250.164.0/22, - 45.250.180.0/22, - 45.250.184.0/21, - 45.250.192.0/22, - 45.251.0.0/22, - 45.251.8.0/22, - 45.251.16.0/21, - 45.251.52.0/22, - 45.251.84.0/22, - 45.251.88.0/21, - 45.251.96.0/21, - 45.251.120.0/21, - 45.251.140.0/22, - 45.251.144.0/20, - 45.251.160.0/19, - 45.251.192.0/19, - 45.251.224.0/22, - 45.251.248.0/23, - 45.252.0.0/21, - 45.252.9.0/24, - 45.252.10.0/23, - 45.252.12.0/22, - 45.252.16.0/20, - 45.252.32.0/20, - 45.252.48.0/22, - 45.252.88.0/21, - 45.252.96.0/22, - 45.252.104.0/21, - 45.252.112.0/20, - 45.252.128.0/20, - 45.252.148.0/22, - 45.252.152.0/21, - 45.252.160.0/20, - 45.252.176.0/22, - 45.252.192.0/19, - 45.252.224.0/21, - 45.252.232.0/22, - 45.253.0.0/18, - 45.253.64.0/20, - 45.253.80.0/21, - 45.253.92.0/22, - 45.253.96.0/20, - 45.253.112.0/21, - 45.253.120.0/22, - 45.253.132.0/22, - 45.253.136.0/21, - 45.253.144.0/20, - 45.253.160.0/19, - 45.253.192.0/19, - 45.253.224.0/20, - 45.253.240.0/22, - 45.254.0.0/20, - 45.254.16.0/21, - 45.254.28.0/22, - 45.254.40.0/22, - 45.254.48.0/20, - 45.254.64.0/18, - 45.254.128.0/18, - 45.254.192.0/19, - 45.254.224.0/21, - 45.254.236.0/22, - 45.254.240.0/22, - 45.254.248.0/22, - 45.255.0.0/18, - 45.255.64.0/19, - 45.255.96.0/20, - 45.255.112.0/21, - 45.255.120.0/22, - 45.255.136.0/21, - 45.255.144.0/20, - 45.255.160.0/19, - 45.255.192.0/19, - 45.255.224.0/20, - 45.255.240.0/21, - 45.255.248.0/22, - 47.52.0.0/16, - 47.56.0.0/16, - 47.57.0.0/17, - 47.57.128.0/18, - 47.57.192.0/22, - 47.57.196.0/24, - 47.57.198.0/23, - 47.57.200.0/21, - 47.57.208.0/20, - 47.57.224.0/19, - 47.74.0.0/15, - 47.76.0.0/16, - 47.77.0.0/20, - 47.77.16.0/21, - 47.77.24.0/22, - 47.77.32.0/19, - 47.77.64.0/19, - 47.77.96.0/20, - 47.77.112.0/23, - 47.77.128.0/17, - 47.78.0.0/15, - 47.80.0.0/14, - 47.84.0.0/16, - 47.85.0.0/17, - 47.85.128.0/23, - 47.85.131.0/24, - 47.85.132.0/22, - 47.85.136.0/21, - 47.85.144.0/20, - 47.85.160.0/19, - 47.85.192.0/18, - 47.86.0.0/16, - 47.87.0.0/20, - 47.87.16.0/21, - 47.87.32.0/19, - 47.87.64.0/21, - 47.87.72.0/24, - 47.87.80.0/20, - 47.87.96.0/19, - 47.87.128.0/20, - 47.87.144.0/21, - 47.87.156.0/22, - 47.87.160.0/19, - 47.87.192.0/18, - 47.88.0.0/16, - 47.89.0.0/18, - 47.89.72.0/21, - 47.89.80.0/22, - 47.89.84.0/24, - 47.89.88.0/23, - 47.89.90.0/24, - 47.89.92.0/22, - 47.89.96.0/20, - 47.89.122.0/23, - 47.89.124.0/23, - 47.89.128.0/17, - 47.90.0.0/17, - 47.90.128.0/19, - 47.90.160.0/21, - 47.90.168.0/22, - 47.90.176.0/20, - 47.90.192.0/18, - 47.91.0.0/16, - 47.92.0.0/14, - 47.96.0.0/11, - 47.235.0.0/21, - 47.235.8.0/22, - 47.235.12.0/23, - 47.235.16.0/20, - 47.236.0.0/17, - 47.236.128.0/18, - 47.236.192.0/20, - 47.236.208.0/21, - 47.236.220.0/22, - 47.236.224.0/19, - 47.237.0.0/17, - 47.237.128.0/18, - 47.237.192.0/19, - 47.237.224.0/20, - 47.237.240.0/21, - 47.237.249.0/24, - 47.237.250.0/23, - 47.237.252.0/22, - 47.238.0.0/20, - 47.238.16.0/21, - 47.238.28.0/22, - 47.238.32.0/19, - 47.238.64.0/18, - 47.238.128.0/17, - 47.239.0.0/16, - 47.240.0.0/14, - 47.244.0.0/16, - 47.245.0.0/17, - 47.245.128.0/20, - 47.245.144.0/21, - 47.245.152.0/22, - 47.245.160.0/19, - 47.245.192.0/20, - 47.245.208.0/21, - 47.245.216.0/22, - 47.245.224.0/19, - 47.246.32.0/22, - 47.246.66.0/23, - 47.246.68.0/23, - 47.246.72.0/21, - 47.246.82.0/23, - 47.246.84.0/22, - 47.246.88.0/23, - 47.246.91.0/24, - 47.246.92.0/23, - 47.246.96.0/22, - 47.246.101.0/24, - 47.246.102.0/23, - 47.246.104.0/21, - 47.246.120.0/24, - 47.246.122.0/23, - 47.246.124.0/23, - 47.246.128.0/23, - 47.246.131.0/24, - 47.246.132.0/23, - 47.246.135.0/24, - 47.246.136.0/21, - 47.246.144.0/22, - 47.246.150.0/23, - 47.246.152.0/22, - 47.246.157.0/24, - 47.246.158.0/23, - 47.246.160.0/23, - 47.246.162.0/24, - 47.246.164.0/22, - 47.246.168.0/21, - 47.246.176.0/20, - 47.246.192.0/20, - 47.246.208.0/23, - 47.246.212.0/22, - 47.246.216.0/22, - 47.250.0.0/18, - 47.250.68.0/22, - 47.250.72.0/21, - 47.250.80.0/20, - 47.250.96.0/21, - 47.250.108.0/22, - 47.250.112.0/20, - 47.250.128.0/17, - 47.251.0.0/17, - 47.251.132.0/22, - 47.251.136.0/21, - 47.251.144.0/20, - 47.251.160.0/19, - 47.251.196.0/22, - 47.251.200.0/21, - 47.251.208.0/20, - 47.251.224.0/19, - 47.252.0.0/16, - 47.253.0.0/18, - 47.253.64.0/19, - 47.253.96.0/20, - 47.253.112.0/21, - 47.253.120.0/22, - 47.253.128.0/17, - 47.254.0.0/16, - 49.4.0.0/17, - 49.4.128.0/22, - 49.4.160.0/20, - 49.4.178.0/23, - 49.4.180.0/22, - 49.4.184.0/21, - 49.4.192.0/18, - 49.5.0.0/16, - 49.6.0.0/15, - 49.51.0.0/19, - 49.51.54.0/23, - 49.51.56.0/21, - 49.51.88.0/21, - 49.51.96.0/19, - 49.51.226.0/23, - 49.52.0.0/14, - 49.64.0.0/11, - 49.112.0.0/13, - 49.120.0.0/14, - 49.128.0.0/24, - 49.128.2.0/23, - 49.128.4.0/22, - 49.140.0.0/15, - 49.152.0.0/14, - 49.208.0.0/14, - 49.213.60.0/23, - 49.220.0.0/14, - 49.232.0.0/14, - 49.239.0.0/18, - 49.239.192.0/18, - 49.246.224.0/23, - 49.246.228.0/22, - 49.246.232.0/23, - 49.246.236.0/22, - 49.246.240.0/20, - 52.80.0.0/14, - 52.130.0.0/15, - 54.222.0.0/15, - 57.176.0.0/15, - 58.14.0.0/21, - 58.14.16.0/20, - 58.14.32.0/19, - 58.14.64.0/18, - 58.14.128.0/17, - 58.15.0.0/16, - 58.16.0.0/13, - 58.24.0.0/15, - 58.30.0.0/15, - 58.32.0.0/11, - 58.65.232.0/21, - 58.67.128.0/17, - 58.68.224.0/19, - 58.82.0.0/17, - 58.83.0.0/16, - 58.87.64.0/18, - 58.99.128.0/17, - 58.100.0.0/15, - 58.116.0.0/14, - 58.128.0.0/13, - 58.144.0.0/16, - 58.154.0.0/15, - 58.192.0.0/11, - 58.240.0.0/12, - 59.32.0.0/11, - 59.64.0.0/12, - 59.80.0.0/14, - 59.107.0.0/17, - 59.107.226.0/24, - 59.107.255.0/24, - 59.108.0.0/14, - 59.151.0.0/17, - 59.152.16.0/20, - 59.152.32.0/21, - 59.152.64.0/20, - 59.152.112.0/21, - 59.153.4.0/22, - 59.153.32.0/22, - 59.153.60.0/22, - 59.153.64.0/21, - 59.153.72.0/22, - 59.153.92.0/22, - 59.153.136.0/22, - 59.153.152.0/22, - 59.153.164.0/22, - 59.153.168.0/21, - 59.153.176.0/20, - 59.153.192.0/22, - 59.155.0.0/16, - 59.172.0.0/14, - 59.191.0.0/17, - 59.192.0.0/10, - 60.0.0.0/11, - 60.55.0.0/16, - 60.63.0.0/16, - 60.160.0.0/11, - 60.194.0.0/15, - 60.200.0.0/13, - 60.208.0.0/12, - 60.232.0.0/15, - 60.235.0.0/16, - 60.245.128.0/17, - 60.247.0.0/16, - 60.252.0.0/16, - 60.253.128.0/17, - 60.255.0.0/16, - 61.4.80.0/20, - 61.4.176.0/20, - 61.8.160.0/20, - 61.14.212.0/22, - 61.14.216.0/21, - 61.14.240.0/21, - 61.28.0.0/17, - 61.29.128.0/18, - 61.29.192.0/19, - 61.29.224.0/20, - 61.45.128.0/18, - 61.45.224.0/20, - 61.47.128.0/18, - 61.48.0.0/13, - 61.87.192.0/18, - 61.128.0.0/11, - 61.160.0.0/12, - 61.176.0.0/13, - 61.184.0.0/15, - 61.186.0.0/23, - 61.186.3.0/24, - 61.186.4.0/22, - 61.186.8.0/21, - 61.186.16.0/20, - 61.186.32.0/19, - 61.186.64.0/18, - 61.186.128.0/17, - 61.187.0.0/16, - 61.188.0.0/14, - 61.232.0.0/14, - 61.236.0.0/15, - 61.240.0.0/14, - 62.182.190.0/23, - 62.234.0.0/16, - 63.140.0.0/24, - 63.140.3.0/24, - 66.102.240.0/21, - 66.102.248.0/23, - 66.102.251.0/24, - 66.102.252.0/24, - 66.102.254.0/23, - 68.79.0.0/18, - 69.163.104.0/24, - 69.163.106.0/24, - 69.163.123.0/24, - 69.230.192.0/18, - 69.231.128.0/18, - 69.234.192.0/18, - 69.235.128.0/18, - 71.131.192.0/18, - 71.132.0.0/18, - 71.136.64.0/18, - 71.137.0.0/18, - 81.68.0.0/14, - 81.173.18.0/23, - 81.173.20.0/22, - 81.173.28.0/24, - 82.156.0.0/15, - 94.191.0.0/17, - 101.0.0.0/22, - 101.1.0.0/22, - 101.2.172.0/22, - 101.4.0.0/14, - 101.16.0.0/12, - 101.33.128.0/17, - 101.34.0.0/15, - 101.36.0.0/18, - 101.36.64.0/20, - 101.36.82.0/23, - 101.36.84.0/22, - 101.36.88.0/21, - 101.36.128.0/17, - 101.37.0.0/16, - 101.38.0.0/15, - 101.40.0.0/14, - 101.48.0.0/15, - 101.50.8.0/21, - 101.50.56.0/22, - 101.52.0.0/16, - 101.53.100.0/22, - 101.54.0.0/16, - 101.55.224.0/21, - 101.64.0.0/13, - 101.72.0.0/14, - 101.76.0.0/15, - 101.78.0.0/22, - 101.78.32.0/19, - 101.80.0.0/12, - 101.96.0.0/21, - 101.96.8.0/22, - 101.96.16.0/20, - 101.96.128.0/17, - 101.99.96.0/19, - 101.101.64.0/19, - 101.101.100.0/24, - 101.101.102.0/23, - 101.101.104.0/21, - 101.101.112.0/20, - 101.102.64.0/19, - 101.102.100.0/23, - 101.102.102.0/24, - 101.102.104.0/21, - 101.102.112.0/20, - 101.104.0.0/14, - 101.110.64.0/19, - 101.110.96.0/20, - 101.110.116.0/22, - 101.110.120.0/21, - 101.120.0.0/14, - 101.124.0.0/15, - 101.126.0.0/16, - 101.128.0.0/22, - 101.128.8.0/21, - 101.128.16.0/20, - 101.128.32.0/19, - 101.129.0.0/16, - 101.130.0.0/15, - 101.132.0.0/14, - 101.144.0.0/12, - 101.192.0.0/18, - 101.192.68.0/22, - 101.192.84.0/22, - 101.192.88.0/21, - 101.192.132.0/22, - 101.192.164.0/22, - 101.192.168.0/21, - 101.192.176.0/20, - 101.192.192.0/19, - 101.193.0.0/18, - 101.193.100.0/22, - 101.193.108.0/22, - 101.193.112.0/22, - 101.193.120.0/21, - 101.193.132.0/22, - 101.193.164.0/22, - 101.193.168.0/21, - 101.193.176.0/20, - 101.193.192.0/19, - 101.194.0.0/15, - 101.196.0.0/14, - 101.200.0.0/15, - 101.203.128.0/19, - 101.203.160.0/21, - 101.203.172.0/22, - 101.203.176.0/20, - 101.204.0.0/14, - 101.224.0.0/13, - 101.232.0.0/17, - 101.232.128.0/18, - 101.232.200.0/21, - 101.232.212.0/22, - 101.232.220.0/22, - 101.232.224.0/22, - 101.232.232.0/21, - 101.232.240.0/22, - 101.233.0.0/16, - 101.234.64.0/21, - 101.234.76.0/22, - 101.234.80.0/20, - 101.234.96.0/19, - 101.236.0.0/16, - 101.237.0.0/17, - 101.237.128.0/18, - 101.237.192.0/19, - 101.237.224.0/22, - 101.237.230.0/23, - 101.237.243.0/24, - 101.237.244.0/23, - 101.237.246.0/24, - 101.237.250.0/24, - 101.237.253.0/24, - 101.238.0.0/15, - 101.240.0.0/13, - 101.248.0.0/15, - 101.251.0.0/22, - 101.251.8.0/21, - 101.251.16.0/20, - 101.251.32.0/19, - 101.251.64.0/18, - 101.251.128.0/17, - 101.252.0.0/15, - 101.254.0.0/16, - 103.1.8.0/22, - 103.1.20.0/22, - 103.1.24.0/22, - 103.1.72.0/22, - 103.1.88.0/22, - 103.1.168.0/22, - 103.2.108.0/22, - 103.2.156.0/22, - 103.2.164.0/22, - 103.2.188.0/23, - 103.2.200.0/21, - 103.2.208.0/21, - 103.3.84.0/22, - 103.3.88.0/21, - 103.3.96.0/19, - 103.3.128.0/20, - 103.3.148.0/22, - 103.3.152.0/21, - 103.4.56.0/22, - 103.4.168.0/22, - 103.4.184.0/22, - 103.4.224.0/22, - 103.5.36.0/22, - 103.5.52.0/22, - 103.5.56.0/22, - 103.5.152.0/22, - 103.5.168.0/22, - 103.5.192.0/22, - 103.5.252.0/22, - 103.6.76.0/22, - 103.6.220.0/22, - 103.7.140.0/22, - 103.7.212.0/22, - 103.7.216.0/21, - 103.8.0.0/21, - 103.8.8.0/22, - 103.8.32.0/22, - 103.8.52.0/22, - 103.8.68.0/22, - 103.8.108.0/22, - 103.8.156.0/22, - 103.8.200.0/21, - 103.8.220.0/22, - 103.9.8.0/22, - 103.9.24.0/22, - 103.9.108.0/22, - 103.9.152.0/22, - 103.9.248.0/21, - 103.10.0.0/22, - 103.10.16.0/22, - 103.10.84.0/22, - 103.10.140.0/22, - 103.11.16.0/22, - 103.11.168.0/22, - 103.11.180.0/22, - 103.12.32.0/22, - 103.12.92.0/22, - 103.12.98.0/23, - 103.12.136.0/22, - 103.12.184.0/22, - 103.12.232.0/22, - 103.13.12.0/22, - 103.13.124.0/22, - 103.13.196.0/22, - 103.13.244.0/22, - 103.14.84.0/22, - 103.14.132.0/22, - 103.14.136.0/22, - 103.14.156.0/22, - 103.14.240.0/22, - 103.15.4.0/22, - 103.15.8.0/22, - 103.15.16.0/22, - 103.15.96.0/22, - 103.15.200.0/22, - 103.16.52.0/22, - 103.16.80.0/21, - 103.16.88.0/22, - 103.16.108.0/22, - 103.16.124.0/22, - 103.17.40.0/22, - 103.17.64.0/22, - 103.17.120.0/22, - 103.17.136.0/22, - 103.17.160.0/22, - 103.17.204.0/22, - 103.17.228.0/22, - 103.18.186.0/23, - 103.18.192.0/22, - 103.18.208.0/21, - 103.18.224.0/22, - 103.19.12.0/22, - 103.19.40.0/21, - 103.19.64.0/21, - 103.19.72.0/22, - 103.19.232.0/22, - 103.20.12.0/22, - 103.20.32.0/24, - 103.20.34.0/23, - 103.20.46.0/24, - 103.20.68.0/22, - 103.20.112.0/22, - 103.20.128.0/22, - 103.20.160.0/22, - 103.20.248.0/22, - 103.21.98.0/23, - 103.21.102.0/23, - 103.21.112.0/21, - 103.21.140.0/22, - 103.21.176.0/22, - 103.22.0.0/18, - 103.22.64.0/19, - 103.22.100.0/22, - 103.22.104.0/21, - 103.22.112.0/20, - 103.22.188.0/22, - 103.22.228.0/22, - 103.22.252.0/22, - 103.23.8.0/22, - 103.23.56.0/22, - 103.23.160.0/21, - 103.23.176.0/22, - 103.23.228.0/22, - 103.24.24.0/22, - 103.24.116.0/22, - 103.24.128.0/22, - 103.24.144.0/22, - 103.24.176.0/22, - 103.24.184.0/22, - 103.24.220.0/22, - 103.24.228.0/22, - 103.24.252.0/22, - 103.25.9.0/24, - 103.25.20.0/22, - 103.25.24.0/21, - 103.25.32.0/21, - 103.25.40.0/22, - 103.25.48.0/22, - 103.25.64.0/21, - 103.25.148.0/22, - 103.25.156.0/22, - 103.25.216.0/22, - 103.26.0.0/22, - 103.26.64.0/22, - 103.26.76.0/22, - 103.26.132.0/22, - 103.26.156.0/22, - 103.26.160.0/22, - 103.26.228.0/22, - 103.26.240.0/22, - 103.27.4.0/22, - 103.27.12.0/22, - 103.27.24.0/22, - 103.27.56.0/22, - 103.27.96.0/22, - 103.27.212.0/22, - 103.27.240.0/22, - 103.28.4.0/22, - 103.28.8.0/22, - 103.28.184.0/22, - 103.28.204.0/22, - 103.28.212.0/22, - 103.29.16.0/22, - 103.29.24.0/23, - 103.29.128.0/21, - 103.29.136.0/22, - 103.29.236.0/23, - 103.30.20.0/22, - 103.30.96.0/22, - 103.30.104.0/22, - 103.30.148.0/22, - 103.30.228.0/22, - 103.30.236.0/22, - 103.31.0.0/22, - 103.31.48.0/20, - 103.31.64.0/21, - 103.31.148.0/22, - 103.31.160.0/22, - 103.31.168.0/22, - 103.31.200.0/22, - 103.31.242.0/23, - 103.32.0.0/15, - 103.34.0.0/16, - 103.35.0.0/19, - 103.35.32.0/20, - 103.35.48.0/22, - 103.35.104.0/22, - 103.35.117.0/24, - 103.35.119.0/24, - 103.35.180.0/22, - 103.35.220.0/22, - 103.36.28.0/22, - 103.36.36.0/22, - 103.36.56.0/21, - 103.36.64.0/22, - 103.36.72.0/22, - 103.36.96.0/22, - 103.36.132.0/22, - 103.36.136.0/22, - 103.36.160.0/20, - 103.36.192.0/19, - 103.36.224.0/20, - 103.36.240.0/21, - 103.37.12.0/22, - 103.37.16.0/22, - 103.37.24.0/22, - 103.37.44.0/22, - 103.37.52.0/22, - 103.37.56.0/22, - 103.37.72.0/22, - 103.37.100.0/22, - 103.37.104.0/22, - 103.37.136.0/21, - 103.37.144.0/20, - 103.37.160.0/21, - 103.37.172.0/22, - 103.37.176.0/22, - 103.37.188.0/22, - 103.37.208.0/20, - 103.37.252.0/22, - 103.38.0.0/22, - 103.38.32.0/22, - 103.38.40.0/21, - 103.38.56.0/22, - 103.38.76.0/22, - 103.38.84.0/22, - 103.38.92.0/22, - 103.38.96.0/22, - 103.38.116.0/22, - 103.38.132.0/22, - 103.38.140.0/22, - 103.38.224.0/21, - 103.38.232.0/22, - 103.38.252.0/23, - 103.39.64.0/22, - 103.39.88.0/22, - 103.39.100.0/22, - 103.39.104.0/22, - 103.39.160.0/19, - 103.39.200.0/21, - 103.39.208.0/20, - 103.39.224.0/21, - 103.39.232.0/22, - 103.40.12.0/22, - 103.40.16.0/20, - 103.40.32.0/20, - 103.40.88.0/22, - 103.40.158.0/23, - 103.40.173.0/24, - 103.40.174.0/23, - 103.40.192.0/22, - 103.40.212.0/22, - 103.40.220.0/22, - 103.40.228.0/22, - 103.40.232.0/21, - 103.40.240.0/20, - 103.41.0.0/22, - 103.41.52.0/22, - 103.41.116.0/22, - 103.41.140.0/22, - 103.41.148.0/22, - 103.41.152.0/22, - 103.41.160.0/21, - 103.41.220.0/22, - 103.41.224.0/21, - 103.41.232.0/22, - 103.42.8.0/22, - 103.42.24.0/22, - 103.42.32.0/22, - 103.42.64.0/21, - 103.42.76.0/22, - 103.42.232.0/22, - 103.43.96.0/21, - 103.43.104.0/22, - 103.43.124.0/22, - 103.43.132.0/22, - 103.43.184.0/22, - 103.43.192.0/21, - 103.43.208.0/22, - 103.43.220.0/22, - 103.43.224.0/22, - 103.43.240.0/22, - 103.44.56.0/22, - 103.44.80.0/22, - 103.44.120.0/21, - 103.44.144.0/22, - 103.44.168.0/22, - 103.44.176.0/20, - 103.44.192.0/22, - 103.44.196.0/23, - 103.44.199.0/24, - 103.44.200.0/21, - 103.44.224.0/22, - 103.44.236.0/22, - 103.44.240.0/20, - 103.45.0.0/18, - 103.45.72.0/21, - 103.45.80.0/20, - 103.45.96.0/19, - 103.45.128.0/18, - 103.45.192.0/19, - 103.45.224.0/22, - 103.45.248.0/22, - 103.46.0.0/22, - 103.46.12.0/22, - 103.46.16.0/20, - 103.46.32.0/19, - 103.46.64.0/18, - 103.46.128.0/21, - 103.46.136.0/22, - 103.46.152.0/21, - 103.46.160.0/20, - 103.46.176.0/21, - 103.46.244.0/22, - 103.46.248.0/22, - 103.47.4.0/22, - 103.47.20.0/22, - 103.47.36.0/22, - 103.47.40.0/22, - 103.47.48.0/22, - 103.47.80.0/22, - 103.47.96.0/22, - 103.47.108.0/22, - 103.47.116.0/22, - 103.47.120.0/22, - 103.47.136.0/21, - 103.47.212.0/22, - 103.48.52.0/22, - 103.48.92.0/22, - 103.48.148.0/22, - 103.48.152.0/21, - 103.48.202.0/23, - 103.48.216.0/21, - 103.48.224.0/20, - 103.48.240.0/21, - 103.49.12.0/22, - 103.49.20.0/22, - 103.49.72.0/21, - 103.49.96.0/22, - 103.49.108.0/22, - 103.49.176.0/21, - 103.49.197.0/24, - 103.50.36.0/22, - 103.50.44.0/22, - 103.50.48.0/20, - 103.50.64.0/21, - 103.50.72.0/22, - 103.50.108.0/22, - 103.50.112.0/20, - 103.50.132.0/22, - 103.50.136.0/21, - 103.50.172.0/22, - 103.50.176.0/20, - 103.50.192.0/21, - 103.50.200.0/22, - 103.50.220.0/22, - 103.50.224.0/20, - 103.50.240.0/21, - 103.50.248.0/22, - 103.52.40.0/22, - 103.52.72.0/21, - 103.52.80.0/21, - 103.52.96.0/21, - 103.52.104.0/22, - 103.52.160.0/21, - 103.52.172.0/22, - 103.52.176.0/22, - 103.52.184.0/22, - 103.52.196.0/22, - 103.53.64.0/21, - 103.53.92.0/22, - 103.53.100.0/22, - 103.53.124.0/22, - 103.53.128.0/20, - 103.53.144.0/22, - 103.53.180.0/22, - 103.53.204.0/22, - 103.53.208.0/21, - 103.53.236.0/22, - 103.53.248.0/22, - 103.54.8.0/22, - 103.54.48.0/22, - 103.54.160.0/21, - 103.54.212.0/22, - 103.54.240.0/22, - 103.55.80.0/22, - 103.55.120.0/22, - 103.55.152.0/22, - 103.55.172.0/22, - 103.55.204.0/22, - 103.55.208.0/22, - 103.55.228.0/22, - 103.55.236.0/22, - 103.56.20.0/22, - 103.56.32.0/22, - 103.56.56.0/21, - 103.56.72.0/21, - 103.56.94.0/23, - 103.56.100.0/22, - 103.56.104.0/22, - 103.56.140.0/22, - 103.56.152.0/22, - 103.56.184.0/22, - 103.56.200.0/22, - 103.57.12.0/22, - 103.57.52.0/22, - 103.57.56.0/22, - 103.57.76.0/22, - 103.57.136.0/22, - 103.57.196.0/22, - 103.58.24.0/22, - 103.59.76.0/22, - 103.59.112.0/21, - 103.59.120.0/23, - 103.59.124.0/22, - 103.59.128.0/22, - 103.59.148.0/22, - 103.59.164.0/22, - 103.59.168.0/23, - 103.60.44.0/22, - 103.60.164.0/22, - 103.60.228.0/22, - 103.60.236.0/22, - 103.61.60.0/22, - 103.61.104.0/22, - 103.61.140.0/22, - 103.61.152.0/21, - 103.61.160.0/22, - 103.61.172.0/22, - 103.61.176.0/22, - 103.61.188.0/22, - 103.62.24.0/22, - 103.62.53.0/24, - 103.62.55.0/24, - 103.62.72.0/21, - 103.62.80.0/21, - 103.62.88.0/22, - 103.62.96.0/19, - 103.62.128.0/21, - 103.62.156.0/22, - 103.62.160.0/19, - 103.62.192.0/22, - 103.62.204.0/22, - 103.62.208.0/20, - 103.62.224.0/22, - 103.63.32.0/19, - 103.63.64.0/20, - 103.63.80.0/21, - 103.63.88.0/22, - 103.63.140.0/22, - 103.63.144.0/22, - 103.63.152.0/22, - 103.63.160.0/20, - 103.63.176.0/21, - 103.63.184.0/22, - 103.63.192.0/20, - 103.63.208.0/22, - 103.63.240.0/20, - 103.64.0.0/21, - 103.64.24.0/21, - 103.64.32.0/19, - 103.64.64.0/18, - 103.64.140.0/22, - 103.64.144.0/22, - 103.64.152.0/21, - 103.64.160.0/19, - 103.64.192.0/18, - 103.65.0.0/20, - 103.65.16.0/22, - 103.65.48.0/20, - 103.65.64.0/19, - 103.65.100.0/22, - 103.65.104.0/21, - 103.65.112.0/22, - 103.65.144.0/20, - 103.65.160.0/20, - 103.65.204.0/22, - 103.65.224.0/23, - 103.66.32.0/22, - 103.66.40.0/22, - 103.66.108.0/22, - 103.66.200.0/22, - 103.66.240.0/20, - 103.67.0.0/21, - 103.67.8.0/22, - 103.67.100.0/22, - 103.67.104.0/21, - 103.67.112.0/20, - 103.67.128.0/20, - 103.67.144.0/21, - 103.67.172.0/22, - 103.67.192.0/22, - 103.67.212.0/22, - 103.67.252.0/22, - 103.68.64.0/22, - 103.68.88.0/22, - 103.68.100.0/22, - 103.68.128.0/22, - 103.69.16.0/22, - 103.69.62.0/23, - 103.70.8.0/22, - 103.70.14.0/23, - 103.70.148.0/22, - 103.70.224.0/23, - 103.70.227.0/24, - 103.70.236.0/22, - 103.70.252.0/22, - 103.71.0.0/22, - 103.71.49.0/24, - 103.71.68.0/22, - 103.71.72.0/22, - 103.71.80.0/21, - 103.71.88.0/22, - 103.71.120.0/21, - 103.71.128.0/22, - 103.71.144.0/22, - 103.71.196.0/22, - 103.71.200.0/22, - 103.71.232.0/22, - 103.72.12.0/22, - 103.72.16.0/20, - 103.72.32.0/20, - 103.72.48.0/21, - 103.72.112.0/21, - 103.72.124.0/22, - 103.72.128.0/21, - 103.72.172.0/22, - 103.72.180.0/22, - 103.72.224.0/21, - 103.72.233.0/24, - 103.72.234.0/23, - 103.72.236.0/22, - 103.72.240.0/20, - 103.73.0.0/21, - 103.73.10.0/23, - 103.73.12.0/22, - 103.73.16.0/20, - 103.73.48.0/22, - 103.73.116.0/22, - 103.73.120.0/22, - 103.73.128.0/20, - 103.73.144.0/22, - 103.73.168.0/22, - 103.73.176.0/22, - 103.73.204.0/22, - 103.73.208.0/22, - 103.73.244.0/22, - 103.73.248.0/22, - 103.74.24.0/21, - 103.74.32.0/20, - 103.74.48.0/22, - 103.74.56.0/21, - 103.74.80.0/22, - 103.74.126.0/23, - 103.74.148.0/22, - 103.74.152.0/21, - 103.74.204.0/22, - 103.74.232.0/22, - 103.75.82.0/23, - 103.75.88.0/21, - 103.75.104.0/21, - 103.75.112.0/22, - 103.75.120.0/22, - 103.75.128.0/22, - 103.75.144.0/22, - 103.75.152.0/22, - 103.76.60.0/22, - 103.76.64.0/21, - 103.76.72.0/22, - 103.76.92.0/22, - 103.76.216.0/21, - 103.76.224.0/22, - 103.77.28.0/22, - 103.77.52.0/22, - 103.77.56.0/22, - 103.77.88.0/22, - 103.77.132.0/22, - 103.77.148.0/22, - 103.77.220.0/22, - 103.78.56.0/21, - 103.78.64.0/21, - 103.78.124.0/22, - 103.78.172.0/22, - 103.78.176.0/22, - 103.78.196.0/22, - 103.78.228.0/22, - 103.79.24.0/21, - 103.79.36.0/22, - 103.79.40.0/21, - 103.79.56.0/21, - 103.79.64.0/21, - 103.79.80.0/21, - 103.79.136.0/22, - 103.79.188.0/22, - 103.79.192.0/20, - 103.79.208.0/21, - 103.79.228.0/23, - 103.80.44.0/22, - 103.80.72.0/22, - 103.80.176.0/21, - 103.80.184.0/22, - 103.80.192.0/22, - 103.80.200.0/22, - 103.80.232.0/22, - 103.81.4.0/22, - 103.81.8.0/22, - 103.81.16.0/21, - 103.81.44.0/22, - 103.81.48.0/22, - 103.81.96.0/22, - 103.81.120.0/22, - 103.81.148.0/22, - 103.81.164.0/22, - 103.81.184.0/22, - 103.81.200.0/22, - 103.81.232.0/22, - 103.82.60.0/22, - 103.82.68.0/22, - 103.82.84.0/22, - 103.82.104.0/22, - 103.82.224.0/22, - 103.82.236.0/22, - 103.83.44.0/22, - 103.83.52.0/22, - 103.83.60.0/22, - 103.83.64.0/22, - 103.83.72.0/22, - 103.83.112.0/22, - 103.83.180.0/22, - 103.84.0.0/22, - 103.84.12.0/22, - 103.84.16.0/20, - 103.84.48.0/22, - 103.84.64.0/22, - 103.84.72.0/22, - 103.84.170.0/23, - 103.85.44.0/22, - 103.85.48.0/22, - 103.85.84.0/22, - 103.85.136.0/22, - 103.85.144.0/22, - 103.85.164.0/22, - 103.85.168.0/21, - 103.85.176.0/22, - 103.85.186.0/23, - 103.86.28.0/22, - 103.86.32.0/22, - 103.86.60.0/22, - 103.86.204.0/22, - 103.86.208.0/20, - 103.86.224.0/19, - 103.87.0.0/21, - 103.87.20.0/22, - 103.87.32.0/22, - 103.87.96.0/22, - 103.87.132.0/22, - 103.87.180.0/22, - 103.87.224.0/22, - 103.88.4.0/22, - 103.88.8.0/21, - 103.88.16.0/21, - 103.88.32.0/21, - 103.88.60.0/22, - 103.88.64.0/22, - 103.88.72.0/22, - 103.88.96.0/22, - 103.88.164.0/22, - 103.88.212.0/22, - 103.89.28.0/22, - 103.89.96.0/20, - 103.89.112.0/21, - 103.89.148.0/22, - 103.89.172.0/22, - 103.89.184.0/21, - 103.89.192.0/19, - 103.89.224.0/21, - 103.90.52.0/22, - 103.90.56.0/23, - 103.90.92.0/22, - 103.90.100.0/22, - 103.90.104.0/21, - 103.90.112.0/20, - 103.90.128.0/21, - 103.90.152.0/22, - 103.90.168.0/22, - 103.90.176.0/22, - 103.90.188.0/22, - 103.90.192.0/22, - 103.91.36.0/22, - 103.91.40.0/22, - 103.91.108.0/22, - 103.91.112.0/23, - 103.91.138.0/23, - 103.91.152.0/22, - 103.91.176.0/22, - 103.91.200.0/22, - 103.91.208.0/21, - 103.91.236.0/22, - 103.91.252.0/22, - 103.92.0.0/20, - 103.92.48.0/20, - 103.92.64.0/20, - 103.92.80.0/22, - 103.92.86.0/24, - 103.92.88.0/22, - 103.92.108.0/22, - 103.92.124.0/22, - 103.92.132.0/22, - 103.92.156.0/22, - 103.92.164.0/22, - 103.92.168.0/21, - 103.92.176.0/20, - 103.92.192.0/22, - 103.92.236.0/22, - 103.92.240.0/20, - 103.93.0.0/21, - 103.93.28.0/22, - 103.93.84.0/22, - 103.93.142.0/23, - 103.93.152.0/22, - 103.93.180.0/22, - 103.93.204.0/22, - 103.94.12.0/22, - 103.94.20.0/22, - 103.94.32.0/20, - 103.94.72.0/22, - 103.94.88.0/22, - 103.94.116.0/22, - 103.94.160.0/22, - 103.94.200.0/22, - 103.95.52.0/22, - 103.95.68.0/22, - 103.95.88.0/21, - 103.95.128.0/22, - 103.95.136.0/21, - 103.95.144.0/22, - 103.95.152.0/22, - 103.95.216.0/21, - 103.95.236.0/22, - 103.95.240.0/20, - 103.96.8.0/22, - 103.96.124.0/22, - 103.96.136.0/22, - 103.96.152.0/21, - 103.96.160.0/19, - 103.96.192.0/20, - 103.96.208.0/21, - 103.96.216.0/22, - 103.96.224.0/23, - 103.97.8.0/21, - 103.97.16.0/20, - 103.97.36.0/22, - 103.97.40.0/22, - 103.97.56.0/22, - 103.97.60.0/23, - 103.97.64.0/21, - 103.97.72.0/22, - 103.97.112.0/21, - 103.97.144.0/21, - 103.97.188.0/22, - 103.97.192.0/22, - 103.97.229.0/24, - 103.98.0.0/23, - 103.98.40.0/21, - 103.98.48.0/22, - 103.98.56.0/22, - 103.98.80.0/22, - 103.98.88.0/21, - 103.98.96.0/21, - 103.98.124.0/22, - 103.98.136.0/21, - 103.98.144.0/22, - 103.98.164.0/22, - 103.98.168.0/22, - 103.98.180.0/22, - 103.98.196.0/22, - 103.98.216.0/21, - 103.98.224.0/21, - 103.98.232.0/22, - 103.98.240.0/20, - 103.99.53.0/24, - 103.99.54.0/23, - 103.99.56.0/22, - 103.99.62.0/24, - 103.99.104.0/22, - 103.99.116.0/22, - 103.99.120.0/22, - 103.99.152.0/22, - 103.99.220.0/22, - 103.99.232.0/21, - 103.100.0.0/22, - 103.100.32.0/22, - 103.100.40.0/22, - 103.100.48.0/21, - 103.100.56.0/22, - 103.100.62.0/24, - 103.100.64.0/22, - 103.100.88.0/22, - 103.100.116.0/22, - 103.100.144.0/22, - 103.100.236.0/22, - 103.100.240.0/22, - 103.100.248.0/21, - 103.101.8.0/21, - 103.101.60.0/22, - 103.101.120.0/21, - 103.101.144.0/21, - 103.101.180.0/22, - 103.101.184.0/22, - 103.102.76.0/22, - 103.102.80.0/22, - 103.102.168.0/21, - 103.102.180.0/22, - 103.102.184.0/21, - 103.102.192.0/21, - 103.102.200.0/22, - 103.102.208.0/21, - 103.103.12.0/22, - 103.103.16.0/22, - 103.103.36.0/22, - 103.103.72.0/22, - 103.103.188.0/22, - 103.103.200.0/21, - 103.103.220.0/22, - 103.103.224.0/21, - 103.103.232.0/22, - 103.103.248.0/21, - 103.104.0.0/21, - 103.104.36.0/22, - 103.104.40.0/22, - 103.104.64.0/22, - 103.104.104.0/22, - 103.104.152.0/22, - 103.104.188.0/22, - 103.104.198.0/23, - 103.104.252.0/22, - 103.105.0.0/21, - 103.105.12.0/22, - 103.105.16.0/22, - 103.105.60.0/22, - 103.105.116.0/22, - 103.105.133.0/24, - 103.105.134.0/23, - 103.105.180.0/22, - 103.105.184.0/22, - 103.105.200.0/21, - 103.105.220.0/22, - 103.106.36.0/22, - 103.106.40.0/21, - 103.106.60.0/22, - 103.106.68.0/22, - 103.106.96.0/22, - 103.106.120.0/22, - 103.106.128.0/21, - 103.106.160.0/22, - 103.106.196.0/22, - 103.106.202.0/24, - 103.106.212.0/22, - 103.106.252.0/22, - 103.107.0.0/22, - 103.107.28.0/22, - 103.107.32.0/22, - 103.107.44.0/22, - 103.107.72.0/22, - 103.107.108.0/22, - 103.107.164.0/22, - 103.107.168.0/22, - 103.107.188.0/22, - 103.107.192.0/22, - 103.107.208.0/20, - 103.108.52.0/22, - 103.108.160.0/21, - 103.108.196.0/22, - 103.108.208.0/21, - 103.108.224.0/22, - 103.108.244.0/22, - 103.109.20.0/22, - 103.109.48.0/22, - 103.109.88.0/22, - 103.109.248.0/22, - 103.110.92.0/22, - 103.110.116.0/22, - 103.110.132.0/22, - 103.110.136.0/22, - 103.110.152.0/21, - 103.110.188.0/22, - 103.110.204.0/22, - 103.111.64.0/22, - 103.111.172.0/22, - 103.111.252.0/22, - 103.112.72.0/22, - 103.112.88.0/21, - 103.112.108.0/22, - 103.112.112.0/21, - 103.112.140.0/22, - 103.113.4.0/22, - 103.113.144.0/22, - 103.113.220.0/22, - 103.113.232.0/21, - 103.114.4.0/22, - 103.114.28.0/22, - 103.114.68.0/22, - 103.114.100.0/22, - 103.114.148.0/22, - 103.114.156.0/23, - 103.114.176.0/22, - 103.114.212.0/22, - 103.114.236.0/22, - 103.114.240.0/22, - 103.115.52.0/22, - 103.115.68.0/22, - 103.115.92.0/22, - 103.115.120.0/22, - 103.115.148.0/22, - 103.115.248.0/22, - 103.116.40.0/22, - 103.116.76.0/22, - 103.116.92.0/22, - 103.116.120.0/22, - 103.116.128.0/22, - 103.116.138.0/23, - 103.116.150.0/24, - 103.116.184.0/22, - 103.116.220.0/22, - 103.116.224.0/21, - 103.117.16.0/22, - 103.117.73.0/24, - 103.117.74.0/23, - 103.117.88.0/22, - 103.117.188.0/22, - 103.117.220.0/22, - 103.118.52.0/22, - 103.118.56.0/21, - 103.118.64.0/21, - 103.118.72.0/22, - 103.118.88.0/22, - 103.118.210.0/23, - 103.118.212.0/22, - 103.118.216.0/22, - 103.118.248.0/22, - 103.119.28.0/22, - 103.119.115.0/24, - 103.119.156.0/22, - 103.119.180.0/22, - 103.119.200.0/22, - 103.120.52.0/22, - 103.120.72.0/22, - 103.120.88.0/22, - 103.120.96.0/21, - 103.120.140.0/22, - 103.120.196.0/22, - 103.120.224.0/22, - 103.121.52.0/22, - 103.121.160.0/21, - 103.121.250.0/24, - 103.121.252.0/22, - 103.122.48.0/22, - 103.122.192.0/22, - 103.122.240.0/22, - 103.123.4.0/22, - 103.123.56.0/22, - 103.123.88.0/21, - 103.123.116.0/22, - 103.123.176.0/22, - 103.123.200.0/21, - 103.123.208.0/21, - 103.124.24.0/22, - 103.124.48.0/22, - 103.124.64.0/22, - 103.124.212.0/22, - 103.124.216.0/22, - 103.125.20.0/22, - 103.125.44.0/22, - 103.125.132.0/22, - 103.125.164.0/22, - 103.125.196.0/22, - 103.125.236.0/22, - 103.125.249.0/24, - 103.125.250.0/23, - 103.126.0.0/22, - 103.126.16.0/22, - 103.126.44.0/22, - 103.126.124.0/22, - 103.126.128.0/21, - 103.130.132.0/22, - 103.130.160.0/22, - 103.130.228.0/22, - 103.131.20.0/22, - 103.131.36.0/22, - 103.131.138.0/23, - 103.131.152.0/22, - 103.131.168.0/22, - 103.131.224.0/21, - 103.131.240.0/22, - 103.132.22.0/23, - 103.132.48.0/22, - 103.132.60.0/22, - 103.132.64.0/20, - 103.132.80.0/22, - 103.132.104.0/21, - 103.132.112.0/21, - 103.132.120.0/22, - 103.132.161.0/24, - 103.132.188.0/22, - 103.132.208.0/21, - 103.133.12.0/22, - 103.133.40.0/22, - 103.133.128.0/22, - 103.133.232.0/22, - 103.134.196.0/22, - 103.134.232.0/23, - 103.135.80.0/22, - 103.135.124.0/22, - 103.135.148.0/22, - 103.135.156.0/22, - 103.135.160.0/21, - 103.135.176.0/22, - 103.135.184.0/22, - 103.135.192.0/21, - 103.135.236.0/22, - 103.136.128.0/22, - 103.136.232.0/22, - 103.137.58.0/23, - 103.137.60.0/24, - 103.137.76.0/22, - 103.137.136.0/23, - 103.137.180.0/22, - 103.137.236.0/22, - 103.138.2.0/23, - 103.138.134.0/23, - 103.138.208.0/23, - 103.138.220.0/23, - 103.138.248.0/23, - 103.139.22.0/23, - 103.139.92.0/23, - 103.139.134.0/23, - 103.139.172.0/23, - 103.139.204.0/23, - 103.139.212.0/23, - 103.140.14.0/23, - 103.140.140.0/23, - 103.140.144.0/23, - 103.140.192.0/23, - 103.141.10.0/23, - 103.141.58.0/23, - 103.141.128.0/23, - 103.141.186.0/23, - 103.141.242.0/23, - 103.142.28.0/23, - 103.142.58.0/23, - 103.142.82.0/23, - 103.142.96.0/23, - 103.142.122.0/23, - 103.142.128.0/23, - 103.142.154.0/23, - 103.142.156.0/23, - 103.142.172.0/23, - 103.142.180.0/23, - 103.142.186.0/23, - 103.142.234.0/23, - 103.142.238.0/23, - 103.142.248.0/23, - 103.143.16.0/22, - 103.143.74.0/23, - 103.143.120.0/23, - 103.143.124.0/23, - 103.143.132.0/22, - 103.143.174.0/23, - 103.143.228.0/23, - 103.144.41.0/24, - 103.144.66.0/23, - 103.144.70.0/23, - 103.144.72.0/23, - 103.144.136.0/23, - 103.144.158.0/23, - 103.145.42.0/23, - 103.145.93.0/24, - 103.145.98.0/23, - 103.145.188.0/23, - 103.146.72.0/23, - 103.146.91.0/24, - 103.146.126.0/23, - 103.146.138.0/23, - 103.146.236.0/23, - 103.147.124.0/23, - 103.147.206.0/23, - 103.148.174.0/23, - 103.149.6.0/23, - 103.149.17.0/24, - 103.149.44.0/23, - 103.149.210.0/23, - 103.149.214.0/23, - 103.149.220.0/23, - 103.149.242.0/23, - 103.149.244.0/22, - 103.150.10.0/23, - 103.150.24.0/23, - 103.150.66.0/23, - 103.150.72.0/23, - 103.150.122.0/23, - 103.150.126.0/23, - 103.150.128.0/22, - 103.150.146.0/23, - 103.150.164.0/23, - 103.150.172.0/23, - 103.150.200.0/23, - 103.150.216.0/23, - 103.150.244.0/23, - 103.151.142.0/23, - 103.151.148.0/23, - 103.151.158.0/23, - 103.152.28.0/22, - 103.152.56.0/23, - 103.152.76.0/23, - 103.152.120.0/22, - 103.152.152.0/23, - 103.152.168.0/23, - 103.152.186.0/23, - 103.152.192.0/23, - 103.152.200.0/23, - 103.152.208.0/23, - 103.152.224.0/23, - 103.152.250.0/23, - 103.153.114.0/23, - 103.153.122.0/23, - 103.153.132.0/23, - 103.153.146.0/23, - 103.153.160.0/23, - 103.154.18.0/23, - 103.154.30.0/23, - 103.154.32.0/23, - 103.154.40.0/23, - 103.154.66.0/23, - 103.154.162.0/23, - 103.154.164.0/23, - 103.154.168.0/23, - 103.155.14.0/23, - 103.155.34.0/23, - 103.155.48.0/23, - 103.155.76.0/23, - 103.155.101.0/24, - 103.155.214.0/23, - 103.156.28.0/23, - 103.156.68.0/23, - 103.156.104.0/23, - 103.156.158.0/23, - 103.156.174.0/23, - 103.156.186.0/23, - 103.156.228.0/23, - 103.157.30.0/23, - 103.157.174.0/23, - 103.157.212.0/23, - 103.157.234.0/23, - 103.157.254.0/23, - 103.158.0.0/23, - 103.158.8.0/23, - 103.158.16.0/23, - 103.158.200.0/23, - 103.158.224.0/23, - 103.159.124.0/23, - 103.159.134.0/23, - 103.159.142.0/23, - 103.160.32.0/22, - 103.160.112.0/22, - 103.160.244.0/23, - 103.160.254.0/23, - 103.161.14.0/23, - 103.161.102.0/23, - 103.161.208.0/23, - 103.161.220.0/23, - 103.161.254.0/23, - 103.162.10.0/23, - 103.162.32.0/23, - 103.162.116.0/23, - 103.163.28.0/23, - 103.163.32.0/23, - 103.163.46.0/23, - 103.163.74.0/23, - 103.163.180.0/23, - 103.164.4.0/23, - 103.164.32.0/23, - 103.164.40.0/22, - 103.164.64.0/23, - 103.164.76.0/23, - 103.164.178.0/23, - 103.165.44.0/23, - 103.165.52.0/23, - 103.165.82.0/23, - 103.165.110.0/23, - 103.166.20.0/23, - 103.166.50.0/23, - 103.166.52.0/22, - 103.166.84.0/23, - 103.166.138.0/23, - 103.167.0.0/23, - 103.167.36.0/23, - 103.167.100.0/23, - 103.168.98.0/23, - 103.168.170.0/23, - 103.169.50.0/23, - 103.169.62.0/23, - 103.169.108.0/23, - 103.169.162.0/23, - 103.169.202.0/23, - 103.170.4.0/23, - 103.170.134.0/23, - 103.170.212.0/23, - 103.171.32.0/23, - 103.171.166.0/24, - 103.171.214.0/23, - 103.172.32.0/23, - 103.172.160.0/23, - 103.173.102.0/23, - 103.173.182.0/23, - 103.173.184.0/23, - 103.174.94.0/23, - 103.175.114.0/23, - 103.175.118.0/23, - 103.175.197.0/24, - 103.176.52.0/23, - 103.176.222.0/23, - 103.176.244.0/23, - 103.177.28.0/23, - 103.177.44.0/23, - 103.177.71.0/24, - 103.177.162.0/23, - 103.178.240.0/23, - 103.179.76.0/22, - 103.180.108.0/24, - 103.180.226.0/23, - 103.181.234.0/23, - 103.183.26.0/23, - 103.183.66.0/23, - 103.183.122.0/23, - 103.183.124.0/23, - 103.184.46.0/23, - 103.184.60.0/23, - 103.185.78.0/23, - 103.185.80.0/23, - 103.186.4.0/23, - 103.186.108.0/23, - 103.186.162.0/24, - 103.186.228.0/23, - 103.189.92.0/23, - 103.189.152.0/22, - 103.189.197.0/24, - 103.190.20.0/23, - 103.190.71.0/24, - 103.190.104.0/23, - 103.190.116.0/22, - 103.190.122.0/23, - 103.191.102.0/23, - 103.191.242.0/23, - 103.192.0.0/19, - 103.192.48.0/21, - 103.192.56.0/22, - 103.192.84.0/22, - 103.192.88.0/21, - 103.192.96.0/20, - 103.192.112.0/22, - 103.192.128.0/20, - 103.192.144.0/22, - 103.192.164.0/22, - 103.192.188.0/22, - 103.192.208.0/21, - 103.192.216.0/22, - 103.192.252.0/22, - 103.193.40.0/21, - 103.193.120.0/22, - 103.193.140.0/22, - 103.193.160.0/22, - 103.193.188.0/22, - 103.193.192.0/22, - 103.193.212.0/22, - 103.193.216.0/21, - 103.193.224.0/20, - 103.194.16.0/22, - 103.195.104.0/22, - 103.195.112.0/22, - 103.195.152.0/22, - 103.195.160.0/22, - 103.196.64.0/22, - 103.196.72.0/22, - 103.196.88.0/21, - 103.196.96.0/22, - 103.196.168.0/22, - 103.197.0.0/22, - 103.197.180.0/22, - 103.197.228.0/22, - 103.198.20.0/22, - 103.198.60.0/22, - 103.198.64.0/22, - 103.198.72.0/22, - 103.198.124.0/22, - 103.198.156.0/22, - 103.198.180.0/22, - 103.198.196.0/22, - 103.198.216.0/21, - 103.198.224.0/20, - 103.198.240.0/21, - 103.199.164.0/22, - 103.199.196.0/22, - 103.199.228.0/22, - 103.199.248.0/21, - 103.200.52.0/22, - 103.200.64.0/21, - 103.200.136.0/21, - 103.200.144.0/20, - 103.200.160.0/19, - 103.200.192.0/22, - 103.200.220.0/22, - 103.200.224.0/19, - 103.201.0.0/20, - 103.201.16.0/21, - 103.201.28.0/22, - 103.201.32.0/19, - 103.201.64.0/22, - 103.201.76.0/22, - 103.201.80.0/20, - 103.201.96.0/20, - 103.201.112.0/21, - 103.201.120.0/22, - 103.201.152.0/21, - 103.201.160.0/19, - 103.201.192.0/18, - 103.202.0.0/19, - 103.202.32.0/20, - 103.202.56.0/22, - 103.202.60.0/24, - 103.202.62.0/23, - 103.202.64.0/22, - 103.202.68.0/23, - 103.202.72.0/21, - 103.202.80.0/20, - 103.202.96.0/19, - 103.202.128.0/20, - 103.202.144.0/22, - 103.202.152.0/24, - 103.202.154.0/23, - 103.202.156.0/22, - 103.202.160.0/19, - 103.202.192.0/20, - 103.202.212.0/22, - 103.202.228.0/22, - 103.202.236.0/22, - 103.202.240.0/20, - 103.203.0.0/19, - 103.203.32.0/22, - 103.203.96.0/19, - 103.203.128.0/22, - 103.203.140.0/22, - 103.203.164.0/22, - 103.203.168.0/22, - 103.203.192.0/22, - 103.203.200.0/22, - 103.203.212.0/22, - 103.203.216.0/22, - 103.204.24.0/22, - 103.204.72.0/22, - 103.204.88.0/22, - 103.204.112.0/22, - 103.204.136.0/21, - 103.204.144.0/21, - 103.204.152.0/22, - 103.204.196.0/22, - 103.204.216.0/23, - 103.204.232.0/21, - 103.205.4.0/22, - 103.205.40.0/21, - 103.205.52.0/22, - 103.205.108.0/22, - 103.205.116.0/22, - 103.205.136.0/22, - 103.205.162.0/24, - 103.205.188.0/22, - 103.205.192.0/21, - 103.205.200.0/22, - 103.205.236.0/22, - 103.205.248.0/21, - 103.206.0.0/22, - 103.206.44.0/22, - 103.206.148.0/22, - 103.207.104.0/22, - 103.207.184.0/21, - 103.207.192.0/20, - 103.207.208.0/21, - 103.207.220.0/22, - 103.207.228.0/22, - 103.207.232.0/22, - 103.208.12.0/22, - 103.208.16.0/22, - 103.208.28.0/22, - 103.208.40.0/21, - 103.208.48.0/22, - 103.209.112.0/22, - 103.209.136.0/22, - 103.209.200.0/22, - 103.209.208.0/22, - 103.209.216.0/22, - 103.210.96.0/22, - 103.210.156.0/22, - 103.210.160.0/19, - 103.210.216.0/22, - 103.211.44.0/22, - 103.211.96.0/22, - 103.211.156.0/22, - 103.211.164.0/22, - 103.211.220.0/22, - 103.211.224.0/22, - 103.211.248.0/22, - 103.212.0.0/20, - 103.212.44.0/22, - 103.212.48.0/22, - 103.212.84.0/22, - 103.212.100.0/22, - 103.212.108.0/22, - 103.212.148.0/22, - 103.212.164.0/22, - 103.212.196.0/22, - 103.212.200.0/22, - 103.212.252.0/22, - 103.213.40.0/21, - 103.213.48.0/20, - 103.213.64.0/19, - 103.213.96.0/22, - 103.213.132.0/22, - 103.213.136.0/21, - 103.213.144.0/20, - 103.213.160.0/19, - 103.213.196.0/22, - 103.213.226.0/23, - 103.213.232.0/23, - 103.214.48.0/22, - 103.214.84.0/22, - 103.214.212.0/22, - 103.214.240.0/21, - 103.215.28.0/22, - 103.215.32.0/21, - 103.215.44.0/22, - 103.215.100.0/22, - 103.215.108.0/22, - 103.215.116.0/22, - 103.215.120.0/22, - 103.215.140.0/22, - 103.216.4.0/22, - 103.216.8.0/21, - 103.216.16.0/20, - 103.216.32.0/20, - 103.216.64.0/22, - 103.216.108.0/22, - 103.216.136.0/22, - 103.216.152.0/22, - 103.216.156.0/23, - 103.216.224.0/22, - 103.216.240.0/20, - 103.217.0.0/18, - 103.217.168.0/22, - 103.217.180.0/22, - 103.217.184.0/21, - 103.217.192.0/20, - 103.218.8.0/21, - 103.218.16.0/21, - 103.218.28.0/22, - 103.218.32.0/19, - 103.218.64.0/20, - 103.218.80.0/21, - 103.218.88.0/22, - 103.218.178.0/23, - 103.218.192.0/20, - 103.218.208.0/21, - 103.218.216.0/22, - 103.219.24.0/21, - 103.219.32.0/21, - 103.219.64.0/22, - 103.219.84.0/22, - 103.219.88.0/21, - 103.219.96.0/21, - 103.219.176.0/22, - 103.219.184.0/22, - 103.220.48.0/20, - 103.220.64.0/22, - 103.220.92.0/22, - 103.220.96.0/20, - 103.220.116.0/22, - 103.220.120.0/21, - 103.220.128.0/20, - 103.220.144.0/21, - 103.220.152.0/22, - 103.220.160.0/19, - 103.220.192.0/21, - 103.220.200.0/22, - 103.220.240.0/21, - 103.221.88.0/22, - 103.221.96.0/19, - 103.221.128.0/18, - 103.221.192.0/20, - 103.222.0.0/20, - 103.222.16.0/22, - 103.222.24.0/21, - 103.222.32.0/19, - 103.222.64.0/18, - 103.222.128.0/18, - 103.222.192.0/19, - 103.222.224.0/21, - 103.222.232.0/22, - 103.222.240.0/21, - 103.223.16.0/20, - 103.223.32.0/19, - 103.223.64.0/19, - 103.223.96.0/20, - 103.223.112.0/21, - 103.223.124.0/22, - 103.223.128.0/21, - 103.223.140.0/22, - 103.223.144.0/20, - 103.223.160.0/20, - 103.223.176.0/21, - 103.223.188.0/22, - 103.223.192.0/18, - 103.224.0.0/22, - 103.224.40.0/21, - 103.224.60.0/22, - 103.224.220.0/22, - 103.224.224.0/21, - 103.224.232.0/22, - 103.225.18.0/24, - 103.226.16.0/22, - 103.226.40.0/22, - 103.226.57.0/24, - 103.226.58.0/23, - 103.226.60.0/22, - 103.226.80.0/22, - 103.226.116.0/23, - 103.226.132.0/22, - 103.226.156.0/22, - 103.226.180.0/22, - 103.226.196.0/22, - 103.227.48.0/22, - 103.227.72.0/21, - 103.227.80.0/22, - 103.227.100.0/22, - 103.227.120.0/22, - 103.227.132.0/22, - 103.227.136.0/22, - 103.227.196.0/22, - 103.227.204.0/22, - 103.227.212.0/22, - 103.227.228.0/22, - 103.228.12.0/22, - 103.228.88.0/22, - 103.228.136.0/22, - 103.228.160.0/22, - 103.228.176.0/22, - 103.228.204.0/22, - 103.228.208.0/22, - 103.228.228.0/22, - 103.228.232.0/22, - 103.229.20.0/22, - 103.229.136.0/22, - 103.229.148.0/22, - 103.229.172.0/22, - 103.229.212.0/22, - 103.229.216.0/21, - 103.229.228.0/22, - 103.229.236.0/22, - 103.229.240.0/22, - 103.230.0.0/22, - 103.230.28.0/22, - 103.230.44.0/22, - 103.230.96.0/22, - 103.230.110.0/23, - 103.230.196.0/22, - 103.230.200.0/21, - 103.230.212.0/22, - 103.230.236.0/22, - 103.231.16.0/21, - 103.231.64.0/21, - 103.231.180.0/22, - 103.231.185.0/24, - 103.231.186.0/23, - 103.231.244.0/22, - 103.232.4.0/22, - 103.232.144.0/22, - 103.232.166.0/23, - 103.232.188.0/22, - 103.233.4.0/22, - 103.233.44.0/22, - 103.233.52.0/22, - 103.233.104.0/22, - 103.233.128.0/22, - 103.233.136.0/22, - 103.233.162.0/23, - 103.233.178.0/24, - 103.233.228.0/22, - 103.234.0.0/22, - 103.234.20.0/22, - 103.234.56.0/22, - 103.234.128.0/22, - 103.234.172.0/22, - 103.234.180.0/22, - 103.234.244.0/22, - 103.235.48.0/22, - 103.235.56.0/21, - 103.235.80.0/22, - 103.235.85.0/24, - 103.235.87.0/24, - 103.235.100.0/22, - 103.235.128.0/20, - 103.235.144.0/21, - 103.235.184.0/22, - 103.235.192.0/22, - 103.235.200.0/22, - 103.235.220.0/22, - 103.235.224.0/19, - 103.236.0.0/18, - 103.236.64.0/19, - 103.236.96.0/22, - 103.236.116.0/23, - 103.236.120.0/22, - 103.236.184.0/22, - 103.236.220.0/22, - 103.236.232.0/22, - 103.236.240.0/21, - 103.236.248.0/23, - 103.236.250.0/24, - 103.236.252.0/22, - 103.237.0.0/20, - 103.237.24.0/21, - 103.237.68.0/22, - 103.237.88.0/22, - 103.237.152.0/22, - 103.237.176.0/20, - 103.237.192.0/18, - 103.238.0.0/21, - 103.238.18.0/23, - 103.238.20.0/22, - 103.238.24.0/21, - 103.238.32.0/21, - 103.238.40.0/22, - 103.238.46.0/23, - 103.238.48.0/21, - 103.238.56.0/22, - 103.238.88.0/21, - 103.238.96.0/22, - 103.238.132.0/22, - 103.238.140.0/22, - 103.238.144.0/22, - 103.238.152.0/23, - 103.238.160.0/19, - 103.238.196.0/22, - 103.238.204.0/22, - 103.238.252.0/22, - 103.239.44.0/22, - 103.239.68.0/22, - 103.239.152.0/21, - 103.239.180.0/22, - 103.239.184.0/22, - 103.239.192.0/21, - 103.239.204.0/22, - 103.239.208.0/22, - 103.239.224.0/22, - 103.239.244.0/22, - 103.240.16.0/22, - 103.240.36.0/22, - 103.240.42.0/23, - 103.240.72.0/22, - 103.240.84.0/22, - 103.240.124.0/22, - 103.240.172.0/22, - 103.240.188.0/22, - 103.240.201.0/24, - 103.240.202.0/23, - 103.240.244.0/22, - 103.241.12.0/22, - 103.241.92.0/22, - 103.241.96.0/22, - 103.241.160.0/22, - 103.241.172.0/23, - 103.241.184.0/21, - 103.241.220.0/22, - 103.242.64.0/22, - 103.242.128.0/22, - 103.242.160.0/22, - 103.242.168.0/21, - 103.242.176.0/22, - 103.242.200.0/22, - 103.242.212.0/22, - 103.242.220.0/22, - 103.242.240.0/22, - 103.243.136.0/22, - 103.243.252.0/22, - 103.244.16.0/22, - 103.244.26.0/23, - 103.244.58.0/23, - 103.244.60.0/22, - 103.244.64.0/20, - 103.244.80.0/21, - 103.244.119.0/24, - 103.244.164.0/22, - 103.244.232.0/22, - 103.244.252.0/22, - 103.245.23.0/24, - 103.245.52.0/22, - 103.245.60.0/22, - 103.245.80.0/22, - 103.245.124.0/22, - 103.245.128.0/22, - 103.246.8.0/21, - 103.246.120.0/21, - 103.246.132.0/22, - 103.246.152.0/22, - 103.247.168.0/21, - 103.247.176.0/22, - 103.247.191.0/24, - 103.247.200.0/22, - 103.247.212.0/22, - 103.248.0.0/23, - 103.248.64.0/22, - 103.248.100.0/22, - 103.248.124.0/22, - 103.248.152.0/22, - 103.248.168.0/22, - 103.248.192.0/22, - 103.248.212.0/22, - 103.248.224.0/22, - 103.249.8.0/21, - 103.249.52.0/22, - 103.249.128.0/22, - 103.249.136.0/22, - 103.249.144.0/22, - 103.249.164.0/22, - 103.249.168.0/21, - 103.249.176.0/22, - 103.249.188.0/22, - 103.249.192.0/22, - 103.249.244.0/22, - 103.249.252.0/22, - 103.250.32.0/22, - 103.250.104.0/22, - 103.250.124.0/22, - 103.250.180.0/22, - 103.250.192.0/22, - 103.250.216.0/22, - 103.250.224.0/22, - 103.250.236.0/22, - 103.250.248.0/21, - 103.251.32.0/22, - 103.251.84.0/22, - 103.251.96.0/22, - 103.251.124.0/22, - 103.251.129.0/24, - 103.251.131.0/24, - 103.251.160.0/22, - 103.251.192.0/22, - 103.251.204.0/22, - 103.251.240.0/22, - 103.252.28.0/22, - 103.252.36.0/22, - 103.252.64.0/22, - 103.252.96.0/22, - 103.252.104.0/22, - 103.252.172.0/22, - 103.252.204.0/22, - 103.252.208.0/22, - 103.252.232.0/22, - 103.252.248.0/22, - 103.253.4.0/22, - 103.253.60.0/22, - 103.253.204.0/22, - 103.253.220.0/22, - 103.253.224.0/22, - 103.253.232.0/22, - 103.254.8.0/22, - 103.254.20.0/22, - 103.254.64.0/21, - 103.254.76.0/22, - 103.254.112.0/22, - 103.254.176.0/22, - 103.254.188.0/22, - 103.255.68.0/22, - 103.255.88.0/21, - 103.255.136.0/21, - 103.255.184.0/22, - 103.255.200.0/22, - 103.255.212.0/22, - 103.255.228.0/22, - 104.192.108.0/23, - 104.192.110.0/24, - 106.0.0.0/24, - 106.0.2.0/23, - 106.0.4.0/22, - 106.0.8.0/21, - 106.0.16.0/20, - 106.0.44.0/22, - 106.0.64.0/18, - 106.2.0.0/17, - 106.2.128.0/20, - 106.2.144.0/21, - 106.2.152.0/22, - 106.2.156.0/23, - 106.2.160.0/19, - 106.2.192.0/18, - 106.3.0.0/18, - 106.3.64.0/20, - 106.3.80.0/22, - 106.3.88.0/21, - 106.3.96.0/19, - 106.3.128.0/17, - 106.4.0.0/14, - 106.8.0.0/15, - 106.11.0.0/16, - 106.12.0.0/14, - 106.16.0.0/12, - 106.32.0.0/12, - 106.48.64.0/18, - 106.50.0.0/16, - 106.52.0.0/14, - 106.56.0.0/13, - 106.74.0.0/16, - 106.75.0.0/17, - 106.75.128.0/18, - 106.75.200.0/21, - 106.75.208.0/20, - 106.75.224.0/19, - 106.80.0.0/12, - 106.108.0.0/14, - 106.112.0.0/12, - 106.224.0.0/12, - 109.244.0.0/16, - 110.6.0.0/15, - 110.16.0.0/14, - 110.34.40.0/21, - 110.40.0.0/14, - 110.44.12.0/22, - 110.44.144.0/20, - 110.48.0.0/16, - 110.51.0.0/16, - 110.52.0.0/15, - 110.56.0.0/13, - 110.64.0.0/15, - 110.72.0.0/15, - 110.75.0.0/16, - 110.76.0.0/18, - 110.76.132.0/22, - 110.76.156.0/22, - 110.76.184.0/22, - 110.76.192.0/18, - 110.77.0.0/17, - 110.80.0.0/13, - 110.88.0.0/14, - 110.92.68.0/22, - 110.93.32.0/19, - 110.94.0.0/15, - 110.96.0.0/11, - 110.152.0.0/14, - 110.156.0.0/15, - 110.165.32.0/19, - 110.166.0.0/15, - 110.172.192.0/18, - 110.173.0.0/19, - 110.173.32.0/20, - 110.173.64.0/18, - 110.173.192.0/19, - 110.176.0.0/12, - 110.192.0.0/11, - 110.228.0.0/14, - 110.232.32.0/19, - 110.236.0.0/15, - 110.240.0.0/12, - 111.0.0.0/10, - 111.66.0.0/21, - 111.66.12.0/22, - 111.66.16.0/22, - 111.66.28.0/22, - 111.66.32.0/21, - 111.66.44.0/22, - 111.66.52.0/22, - 111.66.60.0/22, - 111.66.64.0/18, - 111.66.128.0/19, - 111.66.160.0/20, - 111.66.176.0/23, - 111.66.178.0/24, - 111.66.180.0/22, - 111.66.184.0/21, - 111.67.192.0/20, - 111.68.64.0/19, - 111.72.0.0/13, - 111.85.0.0/16, - 111.92.248.0/21, - 111.112.0.0/14, - 111.116.0.0/15, - 111.118.200.0/21, - 111.119.64.0/18, - 111.119.128.0/19, - 111.120.0.0/14, - 111.124.0.0/16, - 111.126.0.0/15, - 111.128.0.0/11, - 111.160.0.0/13, - 111.170.0.0/16, - 111.172.0.0/14, - 111.176.0.0/13, - 111.186.0.0/15, - 111.192.0.0/12, - 111.208.0.0/13, - 111.221.28.0/24, - 111.221.128.0/17, - 111.222.0.0/16, - 111.223.4.0/22, - 111.223.12.0/22, - 111.223.16.0/22, - 111.223.240.0/22, - 111.223.248.0/22, - 111.224.0.0/13, - 111.235.96.0/19, - 111.235.156.0/22, - 111.235.160.0/19, - 112.0.0.0/10, - 112.64.0.0/14, - 112.73.222.0/24, - 112.74.0.0/15, - 112.80.0.0/12, - 112.96.0.0/13, - 112.109.128.0/17, - 112.111.0.0/16, - 112.112.0.0/14, - 112.116.0.0/15, - 112.122.0.0/15, - 112.124.0.0/14, - 112.128.0.0/14, - 112.132.0.0/16, - 112.137.48.0/21, - 112.192.0.0/14, - 112.224.0.0/11, - 113.0.0.0/13, - 113.8.0.0/15, - 113.11.192.0/19, - 113.12.0.0/14, - 113.16.0.0/15, - 113.18.0.0/16, - 113.21.232.0/21, - 113.24.0.0/14, - 113.31.0.0/16, - 113.44.0.0/14, - 113.48.0.0/14, - 113.52.160.0/19, - 113.52.228.0/22, - 113.54.0.0/15, - 113.56.0.0/15, - 113.58.0.0/16, - 113.59.0.0/17, - 113.59.224.0/22, - 113.62.0.0/15, - 113.64.0.0/10, - 113.128.0.0/15, - 113.130.96.0/20, - 113.130.112.0/21, - 113.132.0.0/14, - 113.136.0.0/13, - 113.192.40.0/23, - 113.194.0.0/15, - 113.197.100.0/22, - 113.200.0.0/15, - 113.202.0.0/16, - 113.204.0.0/14, - 113.208.96.0/19, - 113.208.128.0/17, - 113.209.0.0/16, - 113.212.0.0/18, - 113.212.100.0/22, - 113.212.184.0/21, - 113.213.0.0/17, - 113.214.0.0/15, - 113.218.0.0/15, - 113.220.0.0/14, - 113.224.0.0/12, - 113.240.0.0/13, - 113.248.0.0/14, - 114.28.0.0/17, - 114.28.128.0/18, - 114.28.193.0/24, - 114.28.194.0/24, - 114.28.197.0/24, - 114.28.198.0/23, - 114.28.201.0/24, - 114.28.203.0/24, - 114.28.205.0/24, - 114.28.206.0/23, - 114.28.208.0/23, - 114.28.210.0/24, - 114.28.216.0/23, - 114.28.220.0/22, - 114.28.225.0/24, - 114.28.230.0/24, - 114.28.232.0/24, - 114.28.235.0/24, - 114.28.236.0/23, - 114.28.239.0/24, - 114.28.240.0/20, - 114.31.64.0/21, - 114.54.0.0/15, - 114.60.0.0/14, - 114.64.0.0/14, - 114.68.0.0/16, - 114.79.64.0/18, - 114.80.0.0/12, - 114.96.0.0/13, - 114.104.0.0/14, - 114.110.0.0/20, - 114.110.64.0/18, - 114.111.0.0/19, - 114.111.160.0/20, - 114.111.176.0/22, - 114.111.190.0/23, - 114.112.4.0/22, - 114.112.8.0/22, - 114.112.12.0/23, - 114.112.16.0/23, - 114.112.20.0/22, - 114.112.24.0/21, - 114.112.32.0/19, - 114.112.64.0/18, - 114.112.128.0/18, - 114.112.192.0/19, - 114.112.224.0/22, - 114.112.228.0/24, - 114.112.230.0/23, - 114.112.234.0/23, - 114.112.240.0/23, - 114.112.245.0/24, - 114.112.247.0/24, - 114.112.248.0/23, - 114.112.251.0/24, - 114.112.252.0/23, - 114.113.0.0/17, - 114.113.128.0/21, - 114.113.140.0/22, - 114.113.144.0/20, - 114.113.160.0/19, - 114.113.192.0/19, - 114.113.224.0/20, - 114.113.242.0/24, - 114.113.246.0/23, - 114.113.248.0/21, - 114.114.0.0/15, - 114.116.0.0/15, - 114.118.0.0/16, - 114.119.0.0/17, - 114.119.192.0/21, - 114.119.204.0/22, - 114.119.208.0/20, - 114.119.224.0/19, - 114.132.0.0/16, - 114.135.0.0/16, - 114.138.0.0/15, - 114.141.64.0/21, - 114.141.80.0/21, - 114.141.128.0/18, - 114.142.136.0/21, - 114.196.0.0/15, - 114.198.248.0/21, - 114.208.0.0/12, - 114.224.0.0/11, - 115.24.0.0/14, - 115.28.0.0/15, - 115.31.64.0/20, - 115.32.0.0/14, - 115.42.56.0/22, - 115.44.0.0/14, - 115.48.0.0/12, - 115.69.64.0/20, - 115.84.0.0/18, - 115.85.192.0/18, - 115.100.0.0/14, - 115.104.0.0/14, - 115.120.0.0/14, - 115.124.16.0/20, - 115.148.0.0/14, - 115.152.0.0/13, - 115.166.64.0/19, - 115.168.0.0/13, - 115.180.0.0/14, - 115.187.0.0/20, - 115.190.0.0/15, - 115.192.0.0/11, - 115.224.0.0/12, - 116.0.8.0/21, - 116.0.24.0/21, - 116.1.0.0/16, - 116.2.0.0/15, - 116.4.0.0/14, - 116.8.0.0/14, - 116.13.0.0/16, - 116.16.0.0/12, - 116.50.0.0/20, - 116.52.0.0/14, - 116.56.0.0/15, - 116.58.128.0/20, - 116.58.208.0/20, - 116.60.0.0/14, - 116.66.0.0/17, - 116.68.136.0/21, - 116.68.176.0/21, - 116.69.0.0/16, - 116.70.0.0/17, - 116.76.0.0/14, - 116.85.0.0/16, - 116.89.144.0/20, - 116.90.80.0/20, - 116.90.184.0/21, - 116.95.0.0/16, - 116.112.0.0/14, - 116.116.0.0/15, - 116.128.0.0/10, - 116.192.0.0/16, - 116.193.16.0/20, - 116.193.32.0/19, - 116.193.176.0/21, - 116.194.0.0/15, - 116.196.0.0/21, - 116.196.8.0/22, - 116.196.12.0/23, - 116.196.14.0/24, - 116.196.16.0/20, - 116.196.32.0/19, - 116.196.64.0/18, - 116.196.128.0/17, - 116.197.160.0/21, - 116.198.0.0/16, - 116.199.0.0/17, - 116.199.128.0/20, - 116.199.144.0/21, - 116.204.0.0/17, - 116.205.0.0/16, - 116.207.0.0/16, - 116.208.0.0/14, - 116.212.160.0/20, - 116.213.44.0/24, - 116.213.46.0/23, - 116.213.64.0/18, - 116.213.128.0/17, - 116.214.32.0/19, - 116.214.64.0/20, - 116.214.128.0/17, - 116.215.0.0/16, - 116.216.0.0/14, - 116.224.0.0/12, - 116.242.0.0/15, - 116.244.0.0/14, - 116.248.0.0/15, - 116.251.64.0/18, - 116.252.0.0/15, - 116.254.104.0/21, - 116.254.128.0/17, - 116.255.128.0/17, - 117.8.0.0/13, - 117.21.0.0/16, - 117.22.0.0/15, - 117.24.0.0/13, - 117.32.0.0/13, - 117.40.0.0/14, - 117.44.0.0/15, - 117.48.0.0/15, - 117.50.0.0/16, - 117.51.128.0/17, - 117.53.48.0/20, - 117.53.176.0/20, - 117.57.0.0/16, - 117.58.0.0/17, - 117.59.0.0/16, - 117.60.0.0/14, - 117.64.0.0/13, - 117.72.0.0/15, - 117.74.64.0/19, - 117.74.128.0/17, - 117.75.0.0/16, - 117.76.0.0/14, - 117.80.0.0/12, - 117.100.0.0/15, - 117.103.16.0/20, - 117.103.40.0/21, - 117.103.72.0/21, - 117.103.128.0/20, - 117.104.168.0/21, - 117.106.0.0/15, - 117.112.0.0/13, - 117.120.64.0/18, - 117.120.148.0/22, - 117.120.164.0/22, - 117.120.184.0/21, - 117.120.196.0/22, - 117.120.208.0/21, - 117.120.216.0/22, - 117.120.248.0/21, - 117.121.0.0/17, - 117.121.128.0/18, - 117.121.192.0/21, - 117.122.128.0/17, - 117.124.0.0/14, - 117.128.0.0/14, - 117.132.0.0/15, - 117.134.0.0/17, - 117.134.128.0/18, - 117.134.208.0/23, - 117.134.212.0/23, - 117.134.216.0/22, - 117.134.222.0/23, - 117.134.232.0/21, - 117.134.240.0/20, - 117.135.0.0/16, - 117.136.0.0/13, - 117.144.0.0/12, - 117.160.0.0/11, - 118.24.0.0/15, - 118.26.0.0/19, - 118.26.32.0/22, - 118.26.40.0/21, - 118.26.48.0/21, - 118.26.64.0/19, - 118.26.96.0/21, - 118.26.112.0/20, - 118.26.128.0/22, - 118.26.133.0/24, - 118.26.134.0/23, - 118.26.136.0/21, - 118.26.160.0/20, - 118.26.188.0/22, - 118.26.192.0/18, - 118.28.0.0/14, - 118.64.0.0/15, - 118.66.0.0/16, - 118.67.112.0/20, - 118.72.0.0/13, - 118.80.0.0/15, - 118.84.0.0/15, - 118.88.32.0/19, - 118.88.64.0/18, - 118.88.128.0/17, - 118.89.0.0/16, - 118.91.240.0/20, - 118.102.16.0/20, - 118.102.32.0/21, - 118.103.164.0/22, - 118.103.168.0/21, - 118.103.176.0/22, - 118.112.0.0/13, - 118.120.0.0/14, - 118.124.0.0/15, - 118.126.0.0/16, - 118.127.128.0/19, - 118.132.0.0/14, - 118.144.0.0/14, - 118.178.0.0/16, - 118.180.0.0/14, - 118.184.0.0/16, - 118.186.0.0/15, - 118.188.0.0/16, - 118.190.0.0/15, - 118.192.0.0/16, - 118.193.0.0/20, - 118.193.48.0/21, - 118.193.96.0/19, - 118.193.128.0/17, - 118.194.0.0/17, - 118.194.128.0/18, - 118.194.192.0/19, - 118.194.227.0/24, - 118.194.240.0/21, - 118.195.0.0/16, - 118.196.0.0/14, - 118.202.0.0/15, - 118.204.0.0/14, - 118.212.0.0/15, - 118.215.192.0/18, - 118.224.0.0/14, - 118.228.0.0/15, - 118.230.0.0/16, - 118.239.0.0/16, - 118.242.0.0/16, - 118.244.0.0/14, - 118.248.0.0/13, - 119.0.0.0/15, - 119.2.0.0/19, - 119.2.128.0/17, - 119.3.0.0/16, - 119.4.0.0/14, - 119.10.0.0/17, - 119.15.136.0/21, - 119.16.0.0/16, - 119.18.192.0/20, - 119.18.208.0/21, - 119.18.224.0/19, - 119.19.0.0/16, - 119.20.0.0/14, - 119.27.64.0/18, - 119.27.128.0/17, - 119.28.28.0/24, - 119.28.240.0/20, - 119.29.0.0/16, - 119.30.48.0/20, - 119.31.192.0/19, - 119.32.0.0/13, - 119.40.0.0/18, - 119.40.64.0/20, - 119.40.128.0/17, - 119.41.0.0/16, - 119.42.0.0/19, - 119.42.128.0/20, - 119.42.224.0/19, - 119.44.0.0/15, - 119.48.0.0/13, - 119.57.0.0/16, - 119.58.0.0/16, - 119.59.128.0/17, - 119.60.0.0/15, - 119.62.0.0/16, - 119.63.32.0/19, - 119.75.208.0/20, - 119.78.0.0/15, - 119.80.0.0/16, - 119.82.208.0/20, - 119.84.0.0/14, - 119.88.0.0/14, - 119.96.0.0/13, - 119.108.0.0/15, - 119.112.0.0/12, - 119.128.0.0/12, - 119.144.0.0/14, - 119.148.160.0/19, - 119.151.192.0/18, - 119.160.200.0/21, - 119.161.120.0/21, - 119.161.128.0/21, - 119.161.144.0/21, - 119.161.160.0/19, - 119.161.192.0/18, - 119.162.0.0/15, - 119.164.0.0/14, - 119.176.0.0/12, - 119.232.0.0/15, - 119.235.128.0/18, - 119.248.0.0/14, - 119.252.96.0/21, - 119.252.240.0/21, - 119.252.248.0/23, - 119.252.250.0/24, - 119.252.252.0/23, - 119.252.255.0/24, - 119.253.0.0/16, - 119.254.0.0/15, - 120.0.0.0/12, - 120.24.0.0/14, - 120.30.0.0/15, - 120.32.0.0/12, - 120.48.0.0/15, - 120.52.0.0/14, - 120.64.0.0/13, - 120.72.32.0/19, - 120.72.128.0/17, - 120.76.0.0/14, - 120.80.0.0/13, - 120.88.8.0/21, - 120.90.0.0/15, - 120.92.0.0/16, - 120.94.0.0/15, - 120.128.0.0/13, - 120.136.16.0/21, - 120.136.128.0/18, - 120.137.0.0/17, - 120.143.128.0/19, - 120.192.0.0/10, - 121.0.8.0/21, - 121.0.16.0/20, - 121.4.0.0/15, - 121.8.0.0/13, - 121.16.0.0/12, - 121.32.0.0/13, - 121.40.0.0/14, - 121.46.0.0/18, - 121.46.76.0/22, - 121.46.128.0/21, - 121.46.141.0/24, - 121.46.160.0/19, - 121.46.192.0/18, - 121.47.0.0/16, - 121.48.0.0/15, - 121.50.8.0/21, - 121.51.0.0/16, - 121.52.160.0/19, - 121.52.208.0/20, - 121.52.224.0/19, - 121.54.176.0/21, - 121.55.0.0/18, - 121.56.0.0/15, - 121.58.0.0/17, - 121.58.136.0/21, - 121.58.144.0/20, - 121.58.160.0/21, - 121.59.0.0/19, - 121.59.32.0/22, - 121.59.36.0/23, - 121.59.39.0/24, - 121.59.40.0/21, - 121.59.48.0/20, - 121.59.64.0/19, - 121.59.96.0/22, - 121.59.101.0/24, - 121.59.102.0/23, - 121.59.104.0/23, - 121.59.107.0/24, - 121.59.108.0/22, - 121.59.112.0/21, - 121.59.121.0/24, - 121.59.123.0/24, - 121.59.125.0/24, - 121.59.126.0/23, - 121.59.128.0/21, - 121.59.136.0/22, - 121.59.141.0/24, - 121.59.142.0/23, - 121.59.144.0/20, - 121.59.160.0/19, - 121.59.192.0/18, - 121.60.0.0/14, - 121.68.0.0/14, - 121.76.0.0/15, - 121.79.128.0/18, - 121.89.0.0/16, - 121.91.104.0/21, - 121.100.128.0/17, - 121.101.0.0/18, - 121.101.208.0/20, - 121.192.0.0/13, - 121.200.192.0/21, - 121.201.0.0/16, - 121.204.0.0/14, - 121.224.0.0/12, - 121.248.0.0/14, - 121.255.0.0/16, - 122.0.64.0/18, - 122.0.128.0/17, - 122.4.0.0/14, - 122.8.52.0/22, - 122.8.57.0/24, - 122.8.58.0/23, - 122.8.60.0/23, - 122.8.63.0/24, - 122.8.68.0/22, - 122.8.76.0/22, - 122.8.80.0/23, - 122.8.116.0/22, - 122.8.192.0/18, - 122.9.0.0/16, - 122.10.129.0/24, - 122.10.131.0/24, - 122.10.132.0/23, - 122.10.136.0/23, - 122.10.164.0/22, - 122.10.168.0/21, - 122.10.176.0/20, - 122.10.192.0/22, - 122.10.200.0/22, - 122.10.205.0/24, - 122.10.206.0/23, - 122.10.208.0/21, - 122.10.216.0/22, - 122.10.228.0/22, - 122.10.232.0/21, - 122.10.240.0/22, - 122.11.0.0/17, - 122.12.0.0/15, - 122.14.0.0/17, - 122.14.128.0/20, - 122.14.144.0/22, - 122.14.148.0/24, - 122.14.150.0/23, - 122.14.152.0/23, - 122.14.155.0/24, - 122.14.157.0/24, - 122.14.158.0/23, - 122.14.160.0/19, - 122.14.192.0/18, - 122.48.0.0/16, - 122.49.0.0/18, - 122.51.0.0/16, - 122.64.0.0/11, - 122.96.0.0/15, - 122.102.0.0/20, - 122.102.64.0/19, - 122.112.0.0/18, - 122.112.64.0/19, - 122.112.96.0/20, - 122.112.112.0/21, - 122.112.120.0/23, - 122.112.125.0/24, - 122.112.126.0/23, - 122.112.128.0/17, - 122.113.0.0/19, - 122.113.32.0/20, - 122.113.48.0/23, - 122.113.51.0/24, - 122.113.52.0/22, - 122.113.56.0/21, - 122.113.64.0/18, - 122.113.128.0/17, - 122.114.0.0/16, - 122.115.0.0/18, - 122.115.64.0/22, - 122.115.70.0/23, - 122.115.72.0/24, - 122.115.74.0/23, - 122.115.76.0/22, - 122.115.80.0/20, - 122.115.96.0/19, - 122.115.128.0/17, - 122.119.0.0/16, - 122.128.100.0/22, - 122.128.120.0/21, - 122.136.0.0/13, - 122.144.128.0/17, - 122.152.192.0/18, - 122.156.0.0/14, - 122.188.0.0/14, - 122.192.0.0/14, - 122.198.0.0/16, - 122.200.40.0/21, - 122.200.64.0/18, - 122.201.48.0/20, - 122.204.0.0/14, - 122.224.0.0/12, - 122.240.0.0/13, - 122.248.24.0/21, - 122.248.48.0/20, - 122.255.64.0/21, - 123.0.128.0/18, - 123.4.0.0/14, - 123.8.0.0/13, - 123.49.128.0/18, - 123.49.192.0/23, - 123.49.194.0/24, - 123.49.196.0/22, - 123.49.200.0/21, - 123.49.208.0/20, - 123.49.224.0/20, - 123.49.240.0/24, - 123.49.242.0/23, - 123.49.245.0/24, - 123.49.248.0/21, - 123.50.160.0/19, - 123.52.0.0/14, - 123.56.0.0/15, - 123.58.0.0/17, - 123.58.128.0/18, - 123.58.224.0/19, - 123.59.0.0/16, - 123.60.0.0/15, - 123.62.0.0/16, - 123.64.0.0/11, - 123.96.0.0/15, - 123.98.0.0/21, - 123.98.12.0/22, - 123.98.24.0/21, - 123.98.32.0/19, - 123.98.64.0/18, - 123.99.128.0/19, - 123.99.160.0/22, - 123.99.164.0/24, - 123.99.166.0/23, - 123.99.168.0/21, - 123.99.176.0/20, - 123.99.192.0/18, - 123.100.0.0/19, - 123.101.0.0/16, - 123.103.0.0/17, - 123.108.88.0/23, - 123.108.130.0/23, - 123.108.132.0/22, - 123.108.136.0/21, - 123.108.208.0/20, - 123.112.0.0/12, - 123.128.0.0/13, - 123.136.88.0/22, - 123.137.0.0/16, - 123.138.0.0/15, - 123.144.0.0/12, - 123.160.0.0/12, - 123.176.60.0/22, - 123.176.80.0/20, - 123.177.0.0/16, - 123.178.0.0/15, - 123.180.0.0/14, - 123.184.0.0/13, - 123.196.0.0/15, - 123.199.128.0/17, - 123.206.0.0/15, - 123.232.0.0/14, - 123.242.0.0/17, - 123.242.192.0/21, - 123.244.0.0/14, - 123.249.0.0/16, - 123.253.52.0/23, - 123.254.96.0/21, - 124.6.64.0/18, - 124.14.0.0/15, - 124.16.0.0/15, - 124.20.0.0/16, - 124.21.32.0/19, - 124.21.64.0/18, - 124.21.128.0/17, - 124.22.0.0/15, - 124.28.192.0/18, - 124.29.0.0/17, - 124.31.0.0/16, - 124.40.112.0/20, - 124.40.128.0/18, - 124.40.192.0/19, - 124.40.240.0/22, - 124.42.0.0/16, - 124.47.0.0/18, - 124.64.0.0/15, - 124.66.0.0/17, - 124.67.0.0/16, - 124.68.16.0/20, - 124.68.64.0/18, - 124.69.0.0/16, - 124.70.0.0/16, - 124.71.0.0/17, - 124.71.128.0/18, - 124.71.192.0/19, - 124.71.224.0/20, - 124.71.240.0/21, - 124.71.250.0/23, - 124.71.254.0/23, - 124.72.0.0/13, - 124.88.0.0/13, - 124.108.8.0/21, - 124.108.40.0/21, - 124.109.96.0/21, - 124.112.0.0/13, - 124.126.0.0/15, - 124.128.0.0/13, - 124.147.128.0/17, - 124.150.137.0/24, - 124.151.0.0/16, - 124.152.0.0/16, - 124.160.0.0/13, - 124.172.87.0/24, - 124.172.88.0/23, - 124.172.91.0/24, - 124.172.93.0/24, - 124.172.128.0/17, - 124.173.64.0/18, - 124.173.128.0/18, - 124.173.205.0/24, - 124.174.0.0/15, - 124.192.0.0/15, - 124.196.0.0/16, - 124.197.56.0/21, - 124.200.0.0/13, - 124.220.0.0/14, - 124.224.0.0/12, - 124.240.0.0/17, - 124.240.128.0/18, - 124.242.0.0/16, - 124.243.192.0/18, - 124.248.0.0/17, - 124.249.0.0/16, - 124.250.0.0/15, - 124.254.0.0/18, - 125.31.192.0/18, - 125.32.0.0/12, - 125.58.128.0/17, - 125.61.128.0/17, - 125.62.0.0/18, - 125.64.0.0/12, - 125.80.0.0/13, - 125.88.0.0/14, - 125.92.0.0/16, - 125.93.0.0/20, - 125.93.16.0/21, - 125.93.28.0/22, - 125.93.32.0/19, - 125.93.64.0/18, - 125.93.128.0/17, - 125.94.0.0/15, - 125.96.0.0/15, - 125.98.0.0/16, - 125.104.0.0/13, - 125.112.0.0/12, - 125.169.0.0/16, - 125.171.0.0/16, - 125.208.0.0/18, - 125.210.0.0/15, - 125.213.0.0/17, - 125.214.96.0/19, - 125.215.0.0/18, - 125.216.0.0/13, - 125.254.128.0/17, - 128.108.0.0/16, - 129.28.0.0/16, - 129.204.0.0/16, - 129.211.0.0/16, - 132.232.0.0/16, - 132.237.134.0/24, - 134.49.240.0/22, - 134.175.0.0/16, - 137.59.59.0/24, - 137.59.88.0/22, - 138.252.72.0/23, - 138.252.78.0/23, - 138.252.96.0/24, - 138.252.118.0/23, - 138.252.162.0/23, - 139.5.56.0/21, - 139.5.80.0/22, - 139.5.92.0/22, - 139.5.128.0/22, - 139.5.160.0/22, - 139.5.192.0/22, - 139.5.204.0/22, - 139.5.212.0/22, - 139.5.244.0/22, - 139.9.0.0/16, - 139.95.0.0/20, - 139.95.16.0/22, - 139.95.22.0/23, - 139.95.24.0/21, - 139.95.32.0/21, - 139.95.40.0/23, - 139.95.64.0/23, - 139.95.96.0/22, - 139.95.128.0/17, - 139.129.0.0/16, - 139.148.0.0/16, - 139.155.0.0/16, - 139.159.0.0/19, - 139.159.32.0/21, - 139.159.40.0/22, - 139.159.52.0/22, - 139.159.56.0/21, - 139.159.64.0/19, - 139.159.96.0/20, - 139.159.112.0/22, - 139.159.116.0/23, - 139.159.120.0/21, - 139.159.128.0/17, - 139.170.0.0/16, - 139.176.0.0/16, - 139.183.0.0/18, - 139.183.64.0/19, - 139.183.96.0/22, - 139.183.101.0/24, - 139.183.102.0/23, - 139.183.104.0/21, - 139.183.112.0/20, - 139.183.128.0/18, - 139.183.192.0/20, - 139.183.208.0/23, - 139.183.211.0/24, - 139.183.212.0/22, - 139.183.216.0/21, - 139.183.224.0/19, - 139.186.0.0/16, - 139.189.0.0/18, - 139.189.64.0/19, - 139.189.96.0/20, - 139.189.112.0/21, - 139.189.120.0/22, - 139.189.124.0/23, - 139.189.126.0/24, - 139.189.128.0/17, - 139.196.0.0/15, - 139.198.0.0/18, - 139.198.66.0/23, - 139.198.68.0/22, - 139.198.72.0/21, - 139.198.80.0/20, - 139.198.96.0/19, - 139.198.128.0/17, - 139.199.0.0/16, - 139.200.0.0/13, - 139.208.0.0/13, - 139.217.0.0/16, - 139.219.0.0/16, - 139.220.0.0/15, - 139.224.0.0/16, - 139.226.0.0/15, - 140.75.0.0/16, - 140.143.0.0/16, - 140.179.0.0/16, - 140.205.0.0/16, - 140.206.0.0/15, - 140.210.0.0/16, - 140.224.0.0/16, - 140.237.0.0/16, - 140.240.0.0/16, - 140.243.0.0/16, - 140.246.0.0/16, - 140.249.0.0/16, - 140.250.0.0/16, - 140.255.0.0/16, - 142.86.200.0/21, - 142.86.208.0/20, - 142.86.224.0/20, - 142.86.240.0/21, - 142.86.248.0/22, - 142.86.254.0/23, - 143.64.0.0/16, - 144.0.0.0/16, - 144.7.0.0/16, - 144.12.0.0/16, - 144.36.147.0/24, - 144.48.64.0/22, - 144.48.88.0/22, - 144.48.156.0/22, - 144.48.180.0/22, - 144.48.184.0/22, - 144.48.204.0/22, - 144.48.208.0/21, - 144.52.0.0/16, - 144.79.4.0/23, - 144.79.10.0/23, - 144.79.28.0/23, - 144.79.42.0/23, - 144.79.54.0/23, - 144.79.84.0/23, - 144.79.148.0/23, - 144.123.0.0/16, - 144.255.0.0/16, - 145.14.71.0/24, - 145.14.72.0/22, - 145.14.81.0/24, - 145.14.82.0/24, - 145.14.84.0/24, - 145.14.86.0/24, - 145.14.88.0/24, - 145.14.90.0/24, - 146.56.192.0/18, - 146.196.56.0/22, - 146.196.68.0/22, - 146.196.72.0/22, - 146.196.92.0/22, - 146.196.112.0/21, - 146.196.124.0/22, - 146.222.79.0/24, - 146.222.81.0/24, - 146.222.94.0/24, - 147.78.132.0/24, - 147.78.134.0/24, - 147.139.0.0/17, - 147.139.128.0/18, - 147.139.192.0/19, - 147.139.224.0/20, - 147.139.240.0/21, - 147.139.248.0/22, - 148.70.0.0/16, - 149.41.64.0/18, - 149.41.192.0/19, - 149.129.0.0/20, - 149.129.16.0/21, - 149.129.32.0/19, - 149.129.64.0/18, - 149.129.128.0/19, - 149.129.168.0/21, - 149.129.176.0/20, - 149.129.192.0/18, - 150.0.0.0/16, - 150.115.0.0/16, - 150.121.0.0/16, - 150.122.0.0/16, - 150.129.136.0/22, - 150.129.192.0/22, - 150.129.252.0/22, - 150.138.0.0/15, - 150.158.0.0/16, - 150.223.0.0/16, - 150.242.0.0/21, - 150.242.8.0/22, - 150.242.28.0/22, - 150.242.44.0/22, - 150.242.48.0/21, - 150.242.56.0/22, - 150.242.76.0/22, - 150.242.80.0/22, - 150.242.92.0/22, - 150.242.96.0/22, - 150.242.112.0/21, - 150.242.120.0/22, - 150.242.152.0/22, - 150.242.156.0/23, - 150.242.160.0/21, - 150.242.168.0/22, - 150.242.184.0/21, - 150.242.192.0/22, - 150.242.212.0/24, - 150.242.215.0/24, - 150.242.224.0/22, - 150.242.232.0/21, - 150.242.240.0/21, - 150.242.248.0/22, - 150.248.0.0/16, - 150.255.0.0/16, - 151.158.14.0/23, - 151.158.78.0/23, - 151.158.80.0/23, - 151.158.122.0/23, - 152.104.128.0/17, - 152.136.0.0/16, - 153.0.0.0/16, - 153.3.0.0/16, - 153.34.0.0/15, - 153.36.0.0/15, - 153.99.0.0/16, - 153.101.0.0/16, - 153.118.0.0/15, - 154.8.128.0/17, - 154.72.44.0/24, - 154.72.47.0/24, - 155.126.176.0/23, - 156.107.160.0/23, - 156.107.170.0/24, - 156.107.179.0/24, - 156.107.181.0/24, - 156.227.20.0/24, - 156.236.12.0/24, - 156.236.17.0/24, - 156.245.1.0/24, - 157.0.0.0/16, - 157.10.34.0/23, - 157.10.36.0/23, - 157.10.112.0/23, - 157.10.118.0/23, - 157.10.130.0/23, - 157.10.218.0/23, - 157.10.220.0/23, - 157.10.246.0/23, - 157.15.74.0/23, - 157.15.94.0/23, - 157.15.100.0/22, - 157.15.104.0/23, - 157.18.0.0/16, - 157.20.136.0/23, - 157.20.194.0/23, - 157.20.246.0/23, - 157.61.0.0/16, - 157.66.43.0/24, - 157.66.70.0/23, - 157.66.88.0/21, - 157.66.164.0/23, - 157.66.244.0/23, - 157.119.8.0/21, - 157.119.16.0/22, - 157.119.28.0/22, - 157.119.132.0/22, - 157.119.136.0/21, - 157.119.144.0/20, - 157.119.160.0/21, - 157.119.172.0/22, - 157.119.192.0/21, - 157.119.240.0/22, - 157.119.252.0/22, - 157.122.0.0/16, - 157.148.0.0/16, - 157.156.0.0/16, - 157.255.0.0/16, - 158.60.0.0/16, - 158.79.0.0/16, - 158.140.252.0/23, - 158.140.255.0/24, - 159.27.0.0/16, - 159.75.0.0/16, - 159.226.0.0/16, - 160.19.76.0/23, - 160.19.82.0/23, - 160.19.208.0/21, - 160.19.216.0/22, - 160.20.16.0/22, - 160.20.48.0/22, - 160.20.130.0/23, - 160.22.58.0/23, - 160.22.82.0/23, - 160.22.148.0/23, - 160.22.188.0/23, - 160.22.224.0/23, - 160.22.230.0/23, - 160.22.244.0/22, - 160.25.10.0/23, - 160.25.12.0/23, - 160.25.194.0/23, - 160.30.40.0/23, - 160.30.194.0/23, - 160.30.196.0/22, - 160.30.230.0/23, - 160.83.110.0/24, - 160.187.223.0/24, - 160.187.252.0/22, - 160.191.0.0/23, - 160.191.104.0/23, - 160.191.110.0/23, - 160.202.60.0/23, - 160.202.62.0/24, - 160.202.148.0/22, - 160.202.152.0/22, - 160.202.210.0/23, - 160.202.212.0/22, - 160.202.216.0/21, - 160.202.224.0/19, - 160.236.78.0/23, - 160.236.148.0/23, - 160.236.162.0/23, - 160.236.235.0/24, - 160.236.250.0/23, - 160.250.14.0/23, - 160.250.16.0/22, - 160.250.84.0/23, - 160.250.90.0/23, - 160.250.102.0/23, - 160.250.104.0/23, - 160.250.160.0/23, - 160.250.170.0/23, - 160.250.214.0/23, - 160.250.252.0/23, - 161.117.0.0/16, - 161.163.0.0/21, - 161.163.28.0/23, - 161.189.0.0/16, - 161.207.0.0/16, - 161.248.20.0/23, - 161.248.42.0/23, - 161.248.92.0/23, - 161.248.110.0/23, - 161.248.112.0/24, - 161.248.136.0/24, - 162.4.54.0/23, - 162.4.168.0/23, - 162.4.198.0/23, - 162.4.202.0/23, - 162.4.230.0/23, - 162.14.0.0/19, - 162.14.32.0/21, - 162.14.43.0/24, - 162.14.44.0/22, - 162.14.52.0/22, - 162.14.56.0/22, - 162.14.64.0/18, - 162.14.128.0/17, - 162.105.0.0/16, - 163.0.0.0/16, - 163.47.4.0/22, - 163.52.28.0/23, - 163.52.76.0/23, - 163.52.108.0/23, - 163.52.246.0/23, - 163.53.0.0/20, - 163.53.36.0/22, - 163.53.40.0/21, - 163.53.48.0/20, - 163.53.64.0/22, - 163.53.88.0/21, - 163.53.96.0/19, - 163.53.128.0/21, - 163.53.136.0/22, - 163.53.160.0/20, - 163.53.188.0/22, - 163.53.240.0/22, - 163.61.63.0/24, - 163.61.178.0/23, - 163.61.202.0/23, - 163.61.214.0/23, - 163.125.0.0/16, - 163.128.30.0/23, - 163.128.152.0/23, - 163.128.236.0/23, - 163.128.254.0/23, - 163.142.0.0/16, - 163.177.0.0/16, - 163.179.0.0/16, - 163.204.0.0/16, - 163.223.28.0/23, - 163.223.32.0/23, - 163.223.72.0/23, - 163.223.124.0/23, - 163.223.222.0/23, - 163.227.34.0/23, - 163.227.40.0/23, - 163.227.74.0/23, - 163.227.76.0/22, - 163.227.80.0/23, - 163.228.0.0/16, - 163.244.246.0/24, - 164.52.5.0/24, - 164.52.61.0/24, - 164.52.66.0/24, - 164.52.75.0/24, - 164.52.78.0/24, - 164.52.85.0/24, - 164.52.99.0/24, - 165.101.4.0/23, - 165.101.66.0/23, - 165.101.70.0/24, - 165.101.144.0/23, - 165.101.170.0/23, - 165.101.208.0/23, - 165.101.244.0/23, - 166.111.0.0/16, - 167.139.0.0/16, - 167.189.0.0/16, - 167.220.244.0/22, - 168.160.0.0/16, - 170.33.15.0/24, - 170.33.20.0/22, - 170.33.24.0/24, - 170.33.29.0/24, - 170.33.30.0/23, - 170.33.32.0/22, - 170.33.41.0/24, - 170.33.64.0/23, - 170.33.66.0/24, - 170.33.68.0/23, - 170.33.72.0/23, - 170.33.76.0/22, - 170.33.80.0/22, - 170.33.84.0/24, - 170.33.104.0/22, - 170.33.112.0/23, - 170.33.114.0/24, - 170.33.129.0/24, - 170.33.130.0/23, - 170.33.136.0/23, - 170.33.138.0/24, - 170.33.168.0/23, - 170.33.192.0/23, - 170.179.0.0/16, - 171.8.0.0/13, - 171.34.0.0/15, - 171.36.0.0/14, - 171.40.0.0/13, - 171.80.0.0/12, - 171.104.0.0/13, - 171.112.0.0/12, - 171.208.0.0/12, - 172.81.192.0/18, - 175.0.0.0/12, - 175.16.0.0/13, - 175.24.0.0/14, - 175.30.0.0/15, - 175.42.0.0/15, - 175.44.0.0/16, - 175.46.0.0/15, - 175.48.0.0/12, - 175.64.0.0/11, - 175.102.0.0/16, - 175.106.128.0/17, - 175.111.144.0/20, - 175.111.160.0/20, - 175.111.184.0/22, - 175.146.0.0/15, - 175.148.0.0/14, - 175.152.0.0/14, - 175.158.96.0/22, - 175.160.0.0/12, - 175.176.156.0/22, - 175.176.176.0/22, - 175.176.188.0/22, - 175.178.0.0/16, - 175.184.128.0/18, - 175.185.0.0/16, - 175.186.0.0/15, - 175.188.0.0/14, - 177.201.160.0/19, - 177.203.96.0/19, - 177.203.224.0/19, - 178.236.234.0/24, - 179.236.0.0/19, - 180.76.16.0/20, - 180.76.32.0/19, - 180.76.64.0/18, - 180.76.128.0/17, - 180.77.0.0/16, - 180.78.0.0/15, - 180.84.0.0/15, - 180.86.0.0/16, - 180.88.0.0/14, - 180.94.56.0/21, - 180.94.96.0/20, - 180.94.120.0/21, - 180.95.128.0/17, - 180.96.0.0/11, - 180.129.128.0/17, - 180.130.0.0/16, - 180.136.0.0/13, - 180.148.16.0/21, - 180.148.152.0/21, - 180.148.216.0/21, - 180.148.224.0/19, - 180.149.128.0/19, - 180.150.160.0/19, - 180.152.0.0/13, - 180.160.0.0/12, - 180.178.112.0/21, - 180.178.192.0/18, - 180.184.0.0/14, - 180.188.0.0/17, - 180.189.148.0/22, - 180.200.252.0/22, - 180.201.0.0/16, - 180.202.0.0/15, - 180.208.0.0/15, - 180.210.212.0/22, - 180.212.0.0/15, - 180.222.224.0/19, - 180.233.0.0/18, - 180.233.64.0/19, - 180.233.144.0/22, - 180.235.64.0/19, - 180.235.112.0/22, - 182.16.144.0/21, - 182.16.192.0/19, - 182.18.0.0/17, - 182.23.184.0/21, - 182.23.200.0/21, - 182.32.0.0/12, - 182.48.96.0/19, - 182.49.0.0/16, - 182.50.0.0/22, - 182.50.6.0/24, - 182.50.8.0/21, - 182.50.112.0/20, - 182.51.0.0/16, - 182.54.0.0/17, - 182.54.244.0/22, - 182.61.0.0/17, - 182.61.128.0/19, - 182.61.192.0/18, - 182.80.0.0/13, - 182.88.0.0/14, - 182.92.0.0/16, - 182.96.0.0/11, - 182.128.0.0/12, - 182.144.0.0/13, - 182.157.0.0/16, - 182.160.64.0/19, - 182.174.0.0/15, - 182.200.0.0/13, - 182.236.128.0/17, - 182.237.24.0/21, - 182.238.0.0/16, - 182.239.0.0/19, - 182.240.0.0/13, - 182.254.0.0/16, - 182.255.60.0/22, - 183.0.0.0/10, - 183.64.0.0/13, - 183.78.160.0/21, - 183.78.180.0/22, - 183.81.172.0/24, - 183.81.180.0/22, - 183.84.0.0/15, - 183.91.37.0/24, - 183.91.39.0/24, - 183.91.40.0/21, - 183.91.48.0/23, - 183.91.50.0/24, - 183.91.52.0/22, - 183.91.56.0/24, - 183.91.61.0/24, - 183.91.128.0/22, - 183.91.136.0/21, - 183.91.144.0/20, - 183.92.0.0/14, - 183.128.0.0/11, - 183.160.0.0/13, - 183.168.0.0/15, - 183.170.0.0/16, - 183.172.0.0/14, - 183.182.0.0/21, - 183.182.8.0/23, - 183.182.11.0/24, - 183.182.12.0/22, - 183.182.16.0/23, - 183.182.23.0/24, - 183.182.24.0/21, - 183.184.0.0/13, - 183.192.0.0/10, - 185.2.48.0/24, - 185.75.173.0/24, - 185.75.174.0/24, - 185.192.56.0/22, - 188.131.128.0/17, - 192.51.172.0/23, - 192.55.46.0/23, - 192.55.68.0/22, - 192.102.204.0/22, - 192.124.154.0/24, - 192.140.128.0/21, - 192.140.136.0/22, - 192.140.156.0/22, - 192.140.160.0/19, - 192.140.192.0/20, - 192.140.208.0/21, - 192.140.244.0/23, - 192.144.128.0/17, - 192.163.11.0/24, - 192.232.34.0/23, - 192.232.44.0/22, - 192.232.97.0/24, - 193.112.0.0/16, - 193.119.0.0/19, - 194.138.202.0/23, - 194.138.245.0/24, - 198.11.128.0/20, - 198.11.145.0/24, - 198.11.146.0/23, - 198.11.148.0/22, - 198.11.152.0/21, - 198.11.160.0/19, - 198.175.100.0/22, - 198.208.17.0/24, - 198.208.19.0/24, - 198.208.30.0/24, - 198.208.61.0/24, - 198.208.63.0/24, - 198.208.67.0/24, - 198.208.112.0/23, - 199.182.239.0/24, - 199.244.144.0/24, - 202.0.100.0/23, - 202.0.122.0/23, - 202.0.176.0/23, - 202.0.178.0/24, - 202.3.128.0/23, - 202.4.128.0/19, - 202.4.252.0/22, - 202.5.208.0/21, - 202.5.216.0/22, - 202.6.6.0/23, - 202.6.66.0/23, - 202.6.72.0/23, - 202.6.87.0/24, - 202.6.88.0/23, - 202.6.92.0/23, - 202.6.103.0/24, - 202.6.108.0/24, - 202.6.110.0/23, - 202.6.114.0/24, - 202.6.176.0/20, - 202.6.202.0/23, - 202.8.0.0/24, - 202.8.2.0/23, - 202.8.4.0/23, - 202.8.12.0/24, - 202.8.24.0/24, - 202.8.77.0/24, - 202.8.128.0/19, - 202.8.192.0/20, - 202.9.32.0/24, - 202.9.34.0/23, - 202.9.48.0/23, - 202.9.51.0/24, - 202.9.52.0/23, - 202.9.54.0/24, - 202.9.57.0/24, - 202.9.58.0/23, - 202.10.64.0/20, - 202.10.112.0/20, - 202.12.1.0/24, - 202.12.2.0/24, - 202.12.17.0/24, - 202.12.18.0/24, - 202.12.72.0/24, - 202.12.84.0/23, - 202.12.96.0/24, - 202.12.98.0/23, - 202.12.106.0/24, - 202.12.111.0/24, - 202.12.116.0/24, - 202.14.64.0/23, - 202.14.69.0/24, - 202.14.73.0/24, - 202.14.74.0/23, - 202.14.76.0/24, - 202.14.78.0/23, - 202.14.88.0/24, - 202.14.97.0/24, - 202.14.104.0/23, - 202.14.108.0/23, - 202.14.111.0/24, - 202.14.114.0/23, - 202.14.118.0/23, - 202.14.124.0/23, - 202.14.127.0/24, - 202.14.129.0/24, - 202.14.135.0/24, - 202.14.136.0/24, - 202.14.149.0/24, - 202.14.151.0/24, - 202.14.157.0/24, - 202.14.158.0/23, - 202.14.169.0/24, - 202.14.170.0/23, - 202.14.172.0/22, - 202.14.176.0/24, - 202.14.184.0/23, - 202.14.208.0/23, - 202.14.213.0/24, - 202.14.219.0/24, - 202.14.220.0/24, - 202.14.222.0/23, - 202.14.225.0/24, - 202.14.226.0/23, - 202.14.231.0/24, - 202.14.235.0/24, - 202.14.236.0/22, - 202.14.246.0/24, - 202.14.251.0/24, - 202.20.66.0/24, - 202.20.79.0/24, - 202.20.87.0/24, - 202.20.88.0/23, - 202.20.90.0/24, - 202.20.94.0/23, - 202.20.114.0/24, - 202.20.117.0/24, - 202.20.120.0/24, - 202.20.125.0/24, - 202.20.126.0/23, - 202.21.48.0/20, - 202.21.131.0/24, - 202.21.132.0/24, - 202.21.141.0/24, - 202.21.142.0/24, - 202.21.147.0/24, - 202.21.148.0/24, - 202.21.150.0/23, - 202.21.152.0/23, - 202.21.154.0/24, - 202.21.156.0/24, - 202.22.248.0/21, - 202.27.12.0/24, - 202.27.14.0/24, - 202.27.136.0/23, - 202.36.226.0/24, - 202.38.0.0/22, - 202.38.8.0/21, - 202.38.48.0/20, - 202.38.64.0/18, - 202.38.128.0/21, - 202.38.136.0/23, - 202.38.140.0/22, - 202.38.146.0/23, - 202.38.149.0/24, - 202.38.150.0/23, - 202.38.152.0/22, - 202.38.156.0/24, - 202.38.158.0/23, - 202.38.164.0/22, - 202.38.168.0/23, - 202.38.170.0/24, - 202.38.176.0/23, - 202.38.184.0/21, - 202.38.192.0/18, - 202.40.4.0/23, - 202.40.7.0/24, - 202.40.15.0/24, - 202.40.135.0/24, - 202.40.136.0/24, - 202.40.140.0/24, - 202.40.143.0/24, - 202.40.144.0/23, - 202.40.150.0/24, - 202.40.155.0/24, - 202.40.156.0/24, - 202.40.158.0/23, - 202.40.162.0/24, - 202.41.8.0/23, - 202.41.11.0/24, - 202.41.12.0/23, - 202.41.128.0/24, - 202.41.130.0/23, - 202.41.152.0/21, - 202.41.192.0/24, - 202.41.196.0/22, - 202.41.200.0/22, - 202.41.240.0/20, - 202.43.76.0/22, - 202.43.144.0/20, - 202.44.16.0/20, - 202.44.48.0/22, - 202.44.67.0/24, - 202.44.74.0/24, - 202.44.97.0/24, - 202.44.129.0/24, - 202.44.132.0/23, - 202.44.146.0/23, - 202.45.0.0/23, - 202.45.2.0/24, - 202.45.15.0/24, - 202.45.16.0/20, - 202.46.16.0/23, - 202.46.18.0/24, - 202.46.20.0/23, - 202.46.35.0/24, - 202.46.36.0/23, - 202.46.38.0/24, - 202.46.40.0/24, - 202.46.43.0/24, - 202.46.44.0/24, - 202.46.46.0/23, - 202.46.128.0/24, - 202.46.224.0/20, - 202.47.82.0/23, - 202.47.96.0/20, - 202.47.126.0/24, - 202.47.128.0/24, - 202.47.130.0/23, - 202.52.33.0/24, - 202.52.34.0/24, - 202.52.47.0/24, - 202.52.143.0/24, - 202.53.140.0/24, - 202.53.143.0/24, - 202.55.0.0/23, - 202.55.4.0/24, - 202.55.18.0/23, - 202.55.20.0/22, - 202.55.24.0/22, - 202.55.28.0/23, - 202.55.31.0/24, - 202.57.192.0/20, - 202.57.212.0/22, - 202.57.216.0/22, - 202.57.240.0/20, - 202.58.0.0/24, - 202.58.112.0/22, - 202.58.122.0/23, - 202.59.0.0/23, - 202.59.212.0/22, - 202.59.236.0/24, - 202.59.240.0/24, - 202.60.48.0/21, - 202.60.96.0/21, - 202.60.112.0/20, - 202.60.132.0/22, - 202.60.136.0/21, - 202.60.144.0/20, - 202.61.68.0/22, - 202.61.76.0/22, - 202.61.88.0/22, - 202.61.123.0/24, - 202.61.127.0/24, - 202.62.112.0/22, - 202.62.248.0/22, - 202.62.252.0/24, - 202.62.255.0/24, - 202.63.80.0/20, - 202.63.160.0/19, - 202.63.248.0/22, - 202.63.253.0/24, - 202.65.0.0/21, - 202.65.8.0/23, - 202.65.96.0/20, - 202.66.169.0/24, - 202.66.170.0/23, - 202.67.0.0/22, - 202.69.4.0/23, - 202.69.16.0/20, - 202.70.0.0/19, - 202.70.96.0/20, - 202.70.192.0/20, - 202.71.32.0/20, - 202.72.40.0/21, - 202.72.80.0/20, - 202.72.112.0/20, - 202.73.128.0/22, - 202.73.240.0/20, - 202.74.8.0/21, - 202.74.36.0/24, - 202.74.42.0/24, - 202.74.52.0/24, - 202.74.80.0/20, - 202.74.254.0/23, - 202.75.208.0/20, - 202.75.252.0/22, - 202.76.252.0/22, - 202.77.80.0/21, - 202.77.92.0/22, - 202.78.8.0/21, - 202.79.224.0/21, - 202.79.248.0/22, - 202.80.192.0/20, - 202.81.0.0/22, - 202.81.176.0/20, - 202.83.252.0/22, - 202.84.0.0/20, - 202.84.16.0/23, - 202.84.22.0/24, - 202.84.24.0/21, - 202.85.208.0/20, - 202.86.249.0/24, - 202.86.252.0/22, - 202.87.80.0/20, - 202.88.32.0/22, - 202.89.8.0/21, - 202.89.96.0/22, - 202.89.108.0/22, - 202.89.119.0/24, - 202.89.232.0/21, - 202.90.16.0/20, - 202.90.37.0/24, - 202.90.96.0/19, - 202.90.193.0/24, - 202.90.196.0/24, - 202.90.205.0/24, - 202.90.224.0/20, - 202.91.0.0/22, - 202.91.96.0/20, - 202.91.176.0/20, - 202.91.224.0/19, - 202.92.8.0/21, - 202.92.48.0/20, - 202.92.252.0/22, - 202.93.252.0/22, - 202.94.74.0/24, - 202.94.81.0/24, - 202.94.92.0/22, - 202.95.0.0/24, - 202.95.2.0/23, - 202.95.24.0/21, - 202.95.240.0/21, - 202.96.0.0/12, - 202.112.0.0/13, - 202.120.0.0/15, - 202.122.0.0/21, - 202.122.32.0/21, - 202.122.64.0/19, - 202.122.112.0/20, - 202.122.132.0/24, - 202.123.96.0/20, - 202.123.116.0/22, - 202.123.120.0/22, - 202.124.16.0/21, - 202.124.24.0/22, - 202.125.107.0/24, - 202.125.109.0/24, - 202.125.112.0/20, - 202.125.176.0/20, - 202.127.0.0/21, - 202.127.12.0/22, - 202.127.16.0/20, - 202.127.40.0/21, - 202.127.48.0/20, - 202.127.112.0/20, - 202.127.128.0/19, - 202.127.192.0/20, - 202.127.212.0/22, - 202.127.216.0/21, - 202.127.224.0/19, - 202.129.208.0/24, - 202.130.0.0/19, - 202.130.39.0/24, - 202.130.224.0/19, - 202.131.16.0/21, - 202.131.48.0/20, - 202.131.208.0/20, - 202.133.32.0/20, - 202.134.58.0/24, - 202.134.128.0/20, - 202.134.208.0/20, - 202.136.48.0/20, - 202.136.72.0/23, - 202.136.80.0/23, - 202.136.208.0/20, - 202.136.224.0/20, - 202.136.248.0/22, - 202.136.255.0/24, - 202.137.231.0/24, - 202.140.140.0/22, - 202.140.144.0/20, - 202.141.160.0/19, - 202.142.16.0/20, - 202.143.4.0/22, - 202.143.16.0/20, - 202.143.32.0/20, - 202.143.56.0/21, - 202.143.100.0/22, - 202.143.104.0/22, - 202.144.196.0/22, - 202.146.160.0/20, - 202.146.184.0/23, - 202.146.186.0/24, - 202.146.188.0/22, - 202.146.196.0/22, - 202.146.200.0/21, - 202.147.144.0/20, - 202.148.32.0/20, - 202.148.64.0/18, - 202.149.32.0/19, - 202.149.160.0/19, - 202.149.224.0/20, - 202.149.240.0/21, - 202.149.248.0/22, - 202.149.252.0/23, - 202.149.255.0/24, - 202.150.16.0/20, - 202.150.32.0/20, - 202.150.56.0/22, - 202.150.192.0/20, - 202.150.224.0/19, - 202.151.0.0/22, - 202.151.33.0/24, - 202.151.128.0/19, - 202.152.176.0/20, - 202.153.0.0/22, - 202.153.7.0/24, - 202.153.48.0/20, - 202.157.192.0/19, - 202.158.160.0/19, - 202.158.242.0/24, - 202.160.140.0/23, - 202.160.143.0/24, - 202.160.156.0/22, - 202.162.67.0/24, - 202.162.75.0/24, - 202.164.0.0/20, - 202.164.96.0/19, - 202.165.176.0/20, - 202.165.239.0/24, - 202.165.240.0/23, - 202.165.243.0/24, - 202.165.245.0/24, - 202.165.251.0/24, - 202.165.252.0/22, - 202.166.224.0/19, - 202.168.80.0/22, - 202.168.128.0/20, - 202.168.160.0/19, - 202.170.128.0/19, - 202.170.216.0/21, - 202.170.224.0/19, - 202.171.216.0/21, - 202.171.232.0/24, - 202.171.235.0/24, - 202.172.0.0/22, - 202.172.7.0/24, - 202.173.0.0/22, - 202.173.6.0/24, - 202.173.8.0/21, - 202.173.112.0/22, - 202.173.224.0/19, - 202.174.64.0/20, - 202.174.124.0/22, - 202.176.224.0/19, - 202.179.160.0/20, - 202.179.240.0/21, - 202.180.128.0/19, - 202.180.208.0/21, - 202.181.8.0/22, - 202.181.28.0/22, - 202.181.112.0/20, - 202.182.32.0/20, - 202.182.192.0/19, - 202.189.0.0/18, - 202.189.80.0/20, - 202.189.184.0/21, - 202.191.0.0/24, - 202.191.68.0/22, - 202.191.72.0/21, - 202.191.80.0/20, - 202.192.0.0/12, - 203.0.4.0/22, - 203.0.10.0/23, - 203.0.18.0/24, - 203.0.24.0/24, - 203.0.42.0/23, - 203.0.45.0/24, - 203.0.46.0/23, - 203.0.81.0/24, - 203.0.82.0/23, - 203.0.90.0/23, - 203.0.96.0/23, - 203.0.104.0/21, - 203.0.114.0/23, - 203.0.122.0/24, - 203.0.128.0/24, - 203.0.130.0/23, - 203.0.132.0/22, - 203.0.137.0/24, - 203.0.142.0/24, - 203.0.144.0/24, - 203.0.146.0/24, - 203.0.148.0/24, - 203.0.150.0/23, - 203.0.152.0/24, - 203.0.177.0/24, - 203.0.224.0/24, - 203.1.4.0/22, - 203.1.18.0/24, - 203.1.26.0/23, - 203.1.65.0/24, - 203.1.66.0/23, - 203.1.70.0/23, - 203.1.76.0/23, - 203.1.90.0/24, - 203.1.97.0/24, - 203.1.98.0/23, - 203.1.100.0/22, - 203.1.108.0/24, - 203.1.253.0/24, - 203.1.254.0/24, - 203.2.64.0/21, - 203.2.73.0/24, - 203.2.112.0/21, - 203.2.126.0/23, - 203.2.140.0/24, - 203.2.150.0/24, - 203.2.152.0/22, - 203.2.156.0/23, - 203.2.160.0/21, - 203.2.180.0/23, - 203.2.196.0/23, - 203.2.209.0/24, - 203.2.214.0/23, - 203.2.226.0/23, - 203.2.229.0/24, - 203.2.236.0/23, - 203.3.68.0/24, - 203.3.72.0/23, - 203.3.75.0/24, - 203.3.80.0/21, - 203.3.96.0/22, - 203.3.105.0/24, - 203.3.112.0/21, - 203.3.120.0/24, - 203.3.123.0/24, - 203.3.135.0/24, - 203.3.139.0/24, - 203.3.143.0/24, - 203.4.132.0/23, - 203.4.134.0/24, - 203.4.151.0/24, - 203.4.152.0/22, - 203.4.174.0/23, - 203.4.180.0/24, - 203.4.186.0/24, - 203.4.205.0/24, - 203.4.208.0/22, - 203.4.227.0/24, - 203.4.230.0/23, - 203.5.4.0/23, - 203.5.7.0/24, - 203.5.8.0/23, - 203.5.11.0/24, - 203.5.21.0/24, - 203.5.22.0/24, - 203.5.44.0/24, - 203.5.46.0/23, - 203.5.52.0/22, - 203.5.56.0/23, - 203.5.60.0/23, - 203.5.114.0/23, - 203.5.118.0/24, - 203.5.120.0/24, - 203.5.172.0/24, - 203.5.180.0/23, - 203.5.182.0/24, - 203.5.185.0/24, - 203.5.186.0/24, - 203.5.188.0/23, - 203.5.190.0/24, - 203.5.195.0/24, - 203.5.214.0/23, - 203.5.218.0/23, - 203.6.131.0/24, - 203.6.136.0/24, - 203.6.138.0/23, - 203.6.142.0/24, - 203.6.150.0/23, - 203.6.157.0/24, - 203.6.159.0/24, - 203.6.224.0/20, - 203.6.248.0/23, - 203.7.129.0/24, - 203.7.138.0/23, - 203.7.147.0/24, - 203.7.150.0/23, - 203.7.158.0/24, - 203.7.192.0/23, - 203.7.200.0/24, - 203.8.0.0/24, - 203.8.8.0/24, - 203.8.23.0/24, - 203.8.25.0/24, - 203.8.70.0/24, - 203.8.82.0/24, - 203.8.86.0/23, - 203.8.91.0/24, - 203.8.110.0/23, - 203.8.115.0/24, - 203.8.166.0/23, - 203.8.169.0/24, - 203.8.173.0/24, - 203.8.184.0/24, - 203.8.186.0/23, - 203.8.190.0/23, - 203.8.192.0/24, - 203.8.197.0/24, - 203.8.198.0/23, - 203.8.203.0/24, - 203.8.209.0/24, - 203.8.210.0/23, - 203.8.212.0/22, - 203.8.217.0/24, - 203.8.220.0/24, - 203.9.32.0/24, - 203.9.36.0/23, - 203.9.57.0/24, - 203.9.63.0/24, - 203.9.65.0/24, - 203.9.70.0/23, - 203.9.72.0/24, - 203.9.75.0/24, - 203.9.76.0/23, - 203.9.96.0/22, - 203.9.100.0/23, - 203.9.108.0/24, - 203.9.158.0/24, - 203.10.34.0/24, - 203.10.56.0/24, - 203.10.74.0/23, - 203.10.84.0/22, - 203.10.88.0/24, - 203.10.95.0/24, - 203.10.125.0/24, - 203.11.70.0/24, - 203.11.76.0/22, - 203.11.82.0/24, - 203.11.84.0/22, - 203.11.100.0/22, - 203.11.109.0/24, - 203.11.117.0/24, - 203.11.122.0/24, - 203.11.126.0/24, - 203.11.136.0/22, - 203.11.141.0/24, - 203.11.142.0/23, - 203.11.180.0/22, - 203.11.208.0/22, - 203.12.16.0/24, - 203.12.19.0/24, - 203.12.24.0/24, - 203.12.57.0/24, - 203.12.65.0/24, - 203.12.66.0/24, - 203.12.70.0/23, - 203.12.87.0/24, - 203.12.91.0/24, - 203.12.93.0/24, - 203.12.95.0/24, - 203.12.100.0/23, - 203.12.103.0/24, - 203.12.114.0/24, - 203.12.118.0/24, - 203.12.130.0/24, - 203.12.137.0/24, - 203.12.196.0/22, - 203.12.211.0/24, - 203.12.219.0/24, - 203.12.226.0/24, - 203.12.240.0/22, - 203.13.18.0/24, - 203.13.24.0/24, - 203.13.44.0/23, - 203.13.81.0/24, - 203.13.88.0/23, - 203.13.92.0/22, - 203.13.173.0/24, - 203.13.224.0/23, - 203.13.227.0/24, - 203.13.233.0/24, - 203.14.24.0/22, - 203.14.33.0/24, - 203.14.56.0/24, - 203.14.61.0/24, - 203.14.62.0/24, - 203.14.104.0/24, - 203.14.114.0/23, - 203.14.118.0/24, - 203.14.162.0/24, - 203.14.192.0/24, - 203.14.194.0/23, - 203.14.214.0/24, - 203.14.231.0/24, - 203.14.246.0/24, - 203.15.0.0/20, - 203.15.20.0/23, - 203.15.22.0/24, - 203.15.87.0/24, - 203.15.88.0/23, - 203.15.105.0/24, - 203.15.112.0/24, - 203.15.114.0/23, - 203.15.119.0/24, - 203.15.130.0/23, - 203.15.149.0/24, - 203.15.151.0/24, - 203.15.156.0/22, - 203.15.174.0/24, - 203.15.227.0/24, - 203.15.232.0/21, - 203.15.240.0/23, - 203.15.246.0/24, - 203.16.10.0/24, - 203.16.12.0/23, - 203.16.16.0/21, - 203.16.27.0/24, - 203.16.38.0/24, - 203.16.49.0/24, - 203.16.50.0/23, - 203.16.58.0/24, - 203.16.63.0/24, - 203.16.133.0/24, - 203.16.161.0/24, - 203.16.162.0/24, - 203.16.186.0/23, - 203.16.228.0/24, - 203.16.238.0/24, - 203.16.240.0/24, - 203.16.245.0/24, - 203.17.2.0/24, - 203.17.18.0/24, - 203.17.28.0/24, - 203.17.39.0/24, - 203.17.56.0/24, - 203.17.74.0/23, - 203.17.88.0/23, - 203.17.136.0/24, - 203.17.164.0/24, - 203.17.187.0/24, - 203.17.190.0/23, - 203.17.231.0/24, - 203.17.233.0/24, - 203.17.248.0/23, - 203.17.255.0/24, - 203.18.2.0/23, - 203.18.4.0/24, - 203.18.7.0/24, - 203.18.31.0/24, - 203.18.37.0/24, - 203.18.48.0/23, - 203.18.52.0/24, - 203.18.72.0/22, - 203.18.80.0/23, - 203.18.87.0/24, - 203.18.100.0/23, - 203.18.105.0/24, - 203.18.107.0/24, - 203.18.110.0/24, - 203.18.129.0/24, - 203.18.131.0/24, - 203.18.132.0/23, - 203.18.144.0/24, - 203.18.153.0/24, - 203.18.199.0/24, - 203.18.208.0/24, - 203.18.211.0/24, - 203.18.215.0/24, - 203.19.1.0/24, - 203.19.18.0/24, - 203.19.24.0/24, - 203.19.30.0/24, - 203.19.36.0/24, - 203.19.39.0/24, - 203.19.41.0/24, - 203.19.44.0/23, - 203.19.46.0/24, - 203.19.58.0/24, - 203.19.60.0/23, - 203.19.64.0/24, - 203.19.68.0/24, - 203.19.72.0/24, - 203.19.101.0/24, - 203.19.111.0/24, - 203.19.131.0/24, - 203.19.133.0/24, - 203.19.144.0/24, - 203.19.147.0/24, - 203.19.149.0/24, - 203.19.156.0/24, - 203.19.176.0/24, - 203.19.178.0/23, - 203.19.208.0/24, - 203.19.228.0/22, - 203.19.233.0/24, - 203.19.242.0/24, - 203.19.248.0/23, - 203.19.255.0/24, - 203.20.17.0/24, - 203.20.40.0/23, - 203.20.44.0/24, - 203.20.48.0/24, - 203.20.61.0/24, - 203.20.65.0/24, - 203.20.84.0/23, - 203.20.89.0/24, - 203.20.106.0/23, - 203.20.115.0/24, - 203.20.117.0/24, - 203.20.118.0/23, - 203.20.122.0/24, - 203.20.126.0/23, - 203.20.135.0/24, - 203.20.138.0/23, - 203.20.150.0/24, - 203.20.230.0/24, - 203.20.232.0/24, - 203.20.236.0/24, - 203.21.0.0/23, - 203.21.2.0/24, - 203.21.8.0/24, - 203.21.10.0/24, - 203.21.18.0/24, - 203.21.33.0/24, - 203.21.34.0/24, - 203.21.41.0/24, - 203.21.44.0/24, - 203.21.68.0/24, - 203.21.82.0/24, - 203.21.96.0/22, - 203.21.124.0/24, - 203.21.136.0/23, - 203.21.145.0/24, - 203.21.206.0/24, - 203.22.24.0/24, - 203.22.28.0/23, - 203.22.31.0/24, - 203.22.68.0/24, - 203.22.76.0/24, - 203.22.78.0/24, - 203.22.84.0/24, - 203.22.87.0/24, - 203.22.92.0/22, - 203.22.99.0/24, - 203.22.106.0/24, - 203.22.122.0/23, - 203.22.131.0/24, - 203.22.163.0/24, - 203.22.166.0/24, - 203.22.170.0/24, - 203.22.176.0/21, - 203.22.194.0/24, - 203.22.242.0/23, - 203.22.245.0/24, - 203.22.246.0/24, - 203.22.252.0/23, - 203.23.0.0/24, - 203.23.47.0/24, - 203.23.61.0/24, - 203.23.62.0/23, - 203.23.73.0/24, - 203.23.85.0/24, - 203.23.92.0/22, - 203.23.98.0/24, - 203.23.107.0/24, - 203.23.112.0/24, - 203.23.130.0/24, - 203.23.140.0/23, - 203.23.172.0/24, - 203.23.182.0/24, - 203.23.186.0/23, - 203.23.192.0/24, - 203.23.197.0/24, - 203.23.198.0/24, - 203.23.204.0/22, - 203.23.224.0/24, - 203.23.226.0/23, - 203.23.228.0/22, - 203.23.249.0/24, - 203.23.251.0/24, - 203.24.13.0/24, - 203.24.18.0/24, - 203.24.27.0/24, - 203.24.43.0/24, - 203.24.56.0/24, - 203.24.58.0/24, - 203.24.67.0/24, - 203.24.74.0/24, - 203.24.79.0/24, - 203.24.80.0/23, - 203.24.84.0/23, - 203.24.86.0/24, - 203.24.90.0/24, - 203.24.111.0/24, - 203.24.112.0/24, - 203.24.116.0/24, - 203.24.122.0/23, - 203.24.145.0/24, - 203.24.152.0/23, - 203.24.157.0/24, - 203.24.161.0/24, - 203.24.167.0/24, - 203.24.186.0/23, - 203.24.199.0/24, - 203.24.202.0/24, - 203.24.212.0/23, - 203.24.217.0/24, - 203.24.219.0/24, - 203.24.244.0/24, - 203.25.19.0/24, - 203.25.20.0/23, - 203.25.46.0/24, - 203.25.48.0/21, - 203.25.64.0/23, - 203.25.91.0/24, - 203.25.99.0/24, - 203.25.100.0/24, - 203.25.106.0/24, - 203.25.131.0/24, - 203.25.135.0/24, - 203.25.138.0/24, - 203.25.147.0/24, - 203.25.153.0/24, - 203.25.154.0/23, - 203.25.164.0/24, - 203.25.166.0/24, - 203.25.174.0/23, - 203.25.180.0/24, - 203.25.182.0/24, - 203.25.191.0/24, - 203.25.199.0/24, - 203.25.200.0/24, - 203.25.202.0/23, - 203.25.208.0/20, - 203.25.229.0/24, - 203.25.235.0/24, - 203.25.236.0/24, - 203.25.242.0/24, - 203.26.12.0/24, - 203.26.34.0/24, - 203.26.49.0/24, - 203.26.50.0/24, - 203.26.55.0/24, - 203.26.56.0/23, - 203.26.60.0/24, - 203.26.65.0/24, - 203.26.68.0/24, - 203.26.76.0/24, - 203.26.80.0/24, - 203.26.84.0/24, - 203.26.97.0/24, - 203.26.102.0/23, - 203.26.115.0/24, - 203.26.116.0/24, - 203.26.129.0/24, - 203.26.143.0/24, - 203.26.144.0/24, - 203.26.148.0/23, - 203.26.154.0/24, - 203.26.158.0/23, - 203.26.170.0/24, - 203.26.173.0/24, - 203.26.176.0/24, - 203.26.185.0/24, - 203.26.202.0/23, - 203.26.210.0/24, - 203.26.214.0/24, - 203.26.222.0/24, - 203.26.224.0/24, - 203.26.228.0/24, - 203.26.232.0/24, - 203.27.0.0/24, - 203.27.10.0/24, - 203.27.15.0/24, - 203.27.16.0/24, - 203.27.20.0/24, - 203.27.22.0/23, - 203.27.40.0/24, - 203.27.45.0/24, - 203.27.53.0/24, - 203.27.65.0/24, - 203.27.66.0/24, - 203.27.81.0/24, - 203.27.88.0/24, - 203.27.102.0/24, - 203.27.109.0/24, - 203.27.117.0/24, - 203.27.121.0/24, - 203.27.122.0/23, - 203.27.125.0/24, - 203.27.200.0/24, - 203.27.202.0/24, - 203.27.233.0/24, - 203.27.241.0/24, - 203.27.250.0/24, - 203.28.10.0/24, - 203.28.12.0/24, - 203.28.33.0/24, - 203.28.34.0/23, - 203.28.43.0/24, - 203.28.44.0/24, - 203.28.54.0/24, - 203.28.56.0/24, - 203.28.73.0/24, - 203.28.74.0/24, - 203.28.76.0/24, - 203.28.86.0/24, - 203.28.88.0/24, - 203.28.112.0/24, - 203.28.131.0/24, - 203.28.136.0/24, - 203.28.140.0/24, - 203.28.145.0/24, - 203.28.165.0/24, - 203.28.169.0/24, - 203.28.170.0/24, - 203.28.178.0/23, - 203.28.185.0/24, - 203.28.187.0/24, - 203.28.196.0/24, - 203.28.226.0/23, - 203.28.239.0/24, - 203.29.2.0/24, - 203.29.8.0/23, - 203.29.13.0/24, - 203.29.14.0/24, - 203.29.28.0/24, - 203.29.46.0/24, - 203.29.57.0/24, - 203.29.61.0/24, - 203.29.63.0/24, - 203.29.69.0/24, - 203.29.73.0/24, - 203.29.81.0/24, - 203.29.90.0/24, - 203.29.95.0/24, - 203.29.100.0/24, - 203.29.103.0/24, - 203.29.112.0/24, - 203.29.120.0/22, - 203.29.182.0/23, - 203.29.187.0/24, - 203.29.189.0/24, - 203.29.190.0/24, - 203.29.205.0/24, - 203.29.210.0/24, - 203.29.217.0/24, - 203.29.227.0/24, - 203.29.231.0/24, - 203.29.233.0/24, - 203.29.234.0/24, - 203.29.248.0/24, - 203.29.254.0/23, - 203.30.16.0/23, - 203.30.25.0/24, - 203.30.27.0/24, - 203.30.29.0/24, - 203.30.66.0/24, - 203.30.81.0/24, - 203.30.87.0/24, - 203.30.111.0/24, - 203.30.121.0/24, - 203.30.123.0/24, - 203.30.152.0/24, - 203.30.156.0/24, - 203.30.162.0/24, - 203.30.173.0/24, - 203.30.175.0/24, - 203.30.187.0/24, - 203.30.194.0/24, - 203.30.217.0/24, - 203.30.220.0/24, - 203.30.222.0/24, - 203.30.232.0/23, - 203.30.235.0/24, - 203.30.240.0/23, - 203.30.246.0/24, - 203.30.250.0/23, - 203.31.45.0/24, - 203.31.46.0/24, - 203.31.49.0/24, - 203.31.51.0/24, - 203.31.54.0/23, - 203.31.69.0/24, - 203.31.72.0/24, - 203.31.80.0/24, - 203.31.85.0/24, - 203.31.97.0/24, - 203.31.105.0/24, - 203.31.106.0/24, - 203.31.108.0/23, - 203.31.124.0/24, - 203.31.162.0/24, - 203.31.174.0/24, - 203.31.177.0/24, - 203.31.181.0/24, - 203.31.187.0/24, - 203.31.189.0/24, - 203.31.204.0/24, - 203.31.220.0/24, - 203.31.222.0/23, - 203.31.225.0/24, - 203.31.229.0/24, - 203.31.248.0/23, - 203.31.253.0/24, - 203.32.20.0/24, - 203.32.48.0/23, - 203.32.56.0/24, - 203.32.60.0/24, - 203.32.62.0/24, - 203.32.68.0/23, - 203.32.76.0/24, - 203.32.81.0/24, - 203.32.84.0/23, - 203.32.95.0/24, - 203.32.102.0/24, - 203.32.105.0/24, - 203.32.130.0/24, - 203.32.133.0/24, - 203.32.140.0/24, - 203.32.152.0/24, - 203.32.186.0/23, - 203.32.192.0/24, - 203.32.196.0/24, - 203.32.203.0/24, - 203.32.204.0/23, - 203.32.212.0/24, - 203.33.4.0/24, - 203.33.7.0/24, - 203.33.11.0/24, - 203.33.12.0/22, - 203.33.21.0/24, - 203.33.26.0/24, - 203.33.32.0/24, - 203.33.63.0/24, - 203.33.64.0/24, - 203.33.67.0/24, - 203.33.68.0/24, - 203.33.73.0/24, - 203.33.79.0/24, - 203.33.100.0/24, - 203.33.122.0/24, - 203.33.129.0/24, - 203.33.131.0/24, - 203.33.145.0/24, - 203.33.156.0/24, - 203.33.158.0/23, - 203.33.174.0/24, - 203.33.185.0/24, - 203.33.200.0/24, - 203.33.202.0/23, - 203.33.204.0/24, - 203.33.206.0/23, - 203.33.214.0/23, - 203.33.224.0/23, - 203.33.226.0/24, - 203.33.233.0/24, - 203.33.243.0/24, - 203.33.250.0/24, - 203.34.4.0/24, - 203.34.21.0/24, - 203.34.27.0/24, - 203.34.39.0/24, - 203.34.48.0/23, - 203.34.54.0/24, - 203.34.56.0/23, - 203.34.67.0/24, - 203.34.69.0/24, - 203.34.76.0/24, - 203.34.92.0/24, - 203.34.106.0/24, - 203.34.113.0/24, - 203.34.147.0/24, - 203.34.150.0/24, - 203.34.152.0/23, - 203.34.161.0/24, - 203.34.162.0/24, - 203.34.187.0/24, - 203.34.192.0/23, - 203.34.195.0/24, - 203.34.198.0/24, - 203.34.204.0/22, - 203.34.232.0/24, - 203.34.240.0/24, - 203.34.242.0/24, - 203.34.245.0/24, - 203.34.251.0/24, - 203.55.2.0/23, - 203.55.4.0/24, - 203.55.10.0/24, - 203.55.13.0/24, - 203.55.22.0/24, - 203.55.30.0/24, - 203.55.93.0/24, - 203.55.101.0/24, - 203.55.109.0/24, - 203.55.110.0/24, - 203.55.116.0/23, - 203.55.119.0/24, - 203.55.128.0/23, - 203.55.146.0/23, - 203.55.192.0/24, - 203.55.196.0/24, - 203.55.218.0/23, - 203.55.221.0/24, - 203.55.224.0/24, - 203.56.1.0/24, - 203.56.4.0/24, - 203.56.12.0/24, - 203.56.24.0/24, - 203.56.38.0/24, - 203.56.40.0/24, - 203.56.46.0/24, - 203.56.48.0/23, - 203.56.51.0/24, - 203.56.52.0/23, - 203.56.54.0/24, - 203.56.68.0/23, - 203.56.82.0/23, - 203.56.84.0/23, - 203.56.95.0/24, - 203.56.110.0/24, - 203.56.121.0/24, - 203.56.161.0/24, - 203.56.169.0/24, - 203.56.172.0/23, - 203.56.175.0/24, - 203.56.183.0/24, - 203.56.185.0/24, - 203.56.187.0/24, - 203.56.192.0/24, - 203.56.198.0/24, - 203.56.201.0/24, - 203.56.208.0/23, - 203.56.210.0/24, - 203.56.214.0/24, - 203.56.216.0/24, - 203.56.227.0/24, - 203.56.228.0/24, - 203.56.231.0/24, - 203.56.232.0/24, - 203.56.240.0/24, - 203.56.252.0/24, - 203.56.254.0/24, - 203.57.5.0/24, - 203.57.6.0/24, - 203.57.12.0/23, - 203.57.28.0/24, - 203.57.39.0/24, - 203.57.46.0/24, - 203.57.58.0/24, - 203.57.61.0/24, - 203.57.66.0/24, - 203.57.69.0/24, - 203.57.70.0/23, - 203.57.73.0/24, - 203.57.90.0/24, - 203.57.101.0/24, - 203.57.109.0/24, - 203.57.123.0/24, - 203.57.157.0/24, - 203.57.200.0/24, - 203.57.202.0/24, - 203.57.206.0/24, - 203.57.222.0/24, - 203.57.224.0/20, - 203.57.246.0/23, - 203.57.249.0/24, - 203.57.253.0/24, - 203.57.254.0/23, - 203.62.2.0/24, - 203.62.131.0/24, - 203.62.139.0/24, - 203.62.161.0/24, - 203.62.197.0/24, - 203.62.228.0/22, - 203.62.234.0/24, - 203.62.246.0/24, - 203.65.240.0/22, - 203.76.160.0/22, - 203.76.168.0/22, - 203.76.208.0/21, - 203.76.216.0/22, - 203.76.240.0/22, - 203.77.180.0/22, - 203.78.48.0/20, - 203.78.156.0/22, - 203.79.0.0/20, - 203.80.4.0/23, - 203.80.32.0/20, - 203.80.57.0/24, - 203.80.129.0/24, - 203.80.132.0/22, - 203.80.140.0/24, - 203.80.142.0/23, - 203.80.144.0/20, - 203.81.1.0/24, - 203.81.2.0/24, - 203.81.5.0/24, - 203.81.7.0/24, - 203.81.16.0/20, - 203.81.244.0/22, - 203.82.0.0/23, - 203.82.16.0/24, - 203.82.20.0/23, - 203.82.22.0/24, - 203.82.112.0/20, - 203.82.224.0/20, - 203.83.0.0/22, - 203.83.12.0/22, - 203.83.56.0/21, - 203.83.224.0/20, - 203.86.0.0/18, - 203.86.64.0/19, - 203.86.96.0/22, - 203.86.100.0/23, - 203.86.102.0/24, - 203.86.104.0/23, - 203.86.107.0/24, - 203.86.108.0/24, - 203.86.110.0/24, - 203.86.112.0/24, - 203.86.114.0/24, - 203.86.116.0/23, - 203.86.120.0/24, - 203.86.250.0/24, - 203.86.254.0/23, - 203.88.32.0/19, - 203.88.192.0/19, - 203.89.8.0/23, - 203.89.13.0/24, - 203.89.14.0/23, - 203.89.133.0/24, - 203.89.136.0/22, - 203.89.144.0/24, - 203.90.8.0/21, - 203.90.128.0/18, - 203.90.192.0/19, - 203.91.32.0/19, - 203.91.96.0/20, - 203.91.120.0/21, - 203.92.0.0/22, - 203.92.6.0/24, - 203.92.160.0/19, - 203.93.0.0/16, - 203.94.0.0/19, - 203.95.0.0/21, - 203.95.96.0/19, - 203.95.128.0/18, - 203.95.200.0/21, - 203.95.208.0/22, - 203.95.224.0/19, - 203.99.8.0/23, - 203.99.12.0/24, - 203.99.14.0/23, - 203.99.16.0/23, - 203.99.19.0/24, - 203.99.20.0/22, - 203.99.24.0/21, - 203.99.80.0/20, - 203.100.32.0/20, - 203.100.48.0/22, - 203.100.53.0/24, - 203.100.55.0/24, - 203.100.58.0/24, - 203.100.60.0/24, - 203.100.63.0/24, - 203.100.80.0/20, - 203.100.96.0/19, - 203.100.192.0/20, - 203.104.32.0/20, - 203.105.96.0/19, - 203.105.128.0/19, - 203.107.0.0/17, - 203.110.160.0/19, - 203.110.208.0/20, - 203.110.232.0/23, - 203.110.234.0/24, - 203.114.80.0/20, - 203.114.244.0/22, - 203.118.192.0/19, - 203.118.241.0/24, - 203.118.248.0/22, - 203.119.24.0/21, - 203.119.32.0/22, - 203.119.80.0/24, - 203.119.83.0/24, - 203.119.85.0/24, - 203.119.113.0/24, - 203.119.114.0/23, - 203.119.116.0/22, - 203.119.121.0/24, - 203.119.122.0/23, - 203.119.126.0/23, - 203.119.128.0/17, - 203.123.58.0/24, - 203.128.32.0/19, - 203.128.96.0/19, - 203.128.224.0/22, - 203.128.228.0/24, - 203.128.231.0/24, - 203.129.8.0/24, - 203.129.10.0/23, - 203.129.12.0/22, - 203.130.32.0/19, - 203.132.32.0/19, - 203.134.240.0/21, - 203.135.96.0/19, - 203.135.160.0/20, - 203.142.219.0/24, - 203.142.224.0/19, - 203.144.96.0/22, - 203.144.100.0/24, - 203.144.102.0/24, - 203.144.106.0/23, - 203.144.108.0/22, - 203.144.112.0/20, - 203.145.0.0/19, - 203.148.0.0/18, - 203.148.64.0/20, - 203.148.80.0/22, - 203.148.86.0/23, - 203.149.92.0/22, - 203.152.64.0/19, - 203.152.128.0/19, - 203.153.0.0/22, - 203.156.192.0/18, - 203.158.16.0/21, - 203.160.104.0/21, - 203.160.129.0/24, - 203.160.192.0/19, - 203.161.0.0/22, - 203.161.183.0/24, - 203.161.192.0/19, - 203.166.160.0/19, - 203.167.28.0/22, - 203.168.0.0/19, - 203.170.58.0/23, - 203.171.0.0/22, - 203.171.208.0/24, - 203.171.224.0/20, - 203.174.4.0/24, - 203.174.6.0/24, - 203.174.96.0/19, - 203.175.128.0/19, - 203.175.192.0/18, - 203.176.0.0/18, - 203.176.64.0/19, - 203.176.168.0/21, - 203.184.80.0/20, - 203.185.189.0/24, - 203.187.160.0/19, - 203.189.0.0/23, - 203.189.6.0/23, - 203.189.112.0/22, - 203.189.192.0/19, - 203.189.240.0/22, - 203.190.96.0/20, - 203.190.249.0/24, - 203.191.0.0/23, - 203.191.2.0/24, - 203.191.5.0/24, - 203.191.7.0/24, - 203.191.16.0/20, - 203.191.64.0/18, - 203.191.133.0/24, - 203.191.144.0/20, - 203.192.0.0/19, - 203.193.224.0/19, - 203.194.120.0/21, - 203.195.64.0/19, - 203.195.112.0/23, - 203.195.114.0/24, - 203.195.116.0/22, - 203.195.128.0/17, - 203.196.0.0/21, - 203.196.28.0/22, - 203.201.181.0/24, - 203.201.182.0/24, - 203.202.236.0/22, - 203.205.64.0/19, - 203.205.130.0/23, - 203.205.132.0/23, - 203.205.148.0/22, - 203.205.152.0/23, - 203.205.154.0/24, - 203.205.156.0/24, - 203.205.158.0/23, - 203.205.160.0/20, - 203.205.176.0/21, - 203.205.184.0/22, - 203.205.189.0/24, - 203.205.190.0/24, - 203.205.200.0/21, - 203.205.208.0/21, - 203.205.216.0/23, - 203.205.225.0/24, - 203.205.226.0/23, - 203.205.228.0/22, - 203.205.240.0/21, - 203.207.64.0/18, - 203.207.128.0/17, - 203.208.32.0/19, - 203.209.224.0/19, - 203.212.0.0/20, - 203.212.80.0/20, - 203.215.232.0/21, - 203.217.164.0/22, - 203.223.16.0/24, - 203.223.21.0/24, - 203.223.22.0/23, - 205.204.96.0/19, - 206.109.70.0/23, - 206.109.75.0/24, - 210.2.0.0/19, - 210.5.0.0/19, - 210.5.56.0/24, - 210.5.58.0/23, - 210.5.60.0/22, - 210.5.128.0/19, - 210.7.56.0/21, - 210.12.0.0/15, - 210.14.64.0/19, - 210.14.112.0/20, - 210.14.128.0/17, - 210.15.0.0/17, - 210.15.128.0/18, - 210.16.128.0/18, - 210.21.0.0/16, - 210.22.0.0/16, - 210.23.32.0/19, - 210.25.0.0/16, - 210.26.0.0/15, - 210.28.0.0/14, - 210.32.0.0/12, - 210.51.0.0/16, - 210.52.0.0/15, - 210.56.192.0/19, - 210.72.0.0/14, - 210.76.0.0/15, - 210.78.0.0/16, - 210.79.64.0/18, - 210.79.224.0/19, - 210.82.0.0/15, - 210.87.72.0/23, - 210.87.114.0/23, - 210.87.128.0/18, - 210.185.192.0/18, - 210.192.96.0/19, - 211.64.0.0/13, - 211.80.0.0/12, - 211.96.0.0/15, - 211.98.0.0/16, - 211.99.0.0/19, - 211.99.64.0/18, - 211.99.128.0/17, - 211.100.0.0/15, - 211.102.0.0/17, - 211.102.128.0/21, - 211.102.144.0/21, - 211.102.160.0/20, - 211.102.192.0/18, - 211.103.0.0/16, - 211.136.0.0/13, - 211.144.0.0/14, - 211.148.0.0/16, - 211.149.0.0/19, - 211.149.33.0/24, - 211.149.34.0/23, - 211.149.48.0/21, - 211.149.64.0/21, - 211.149.80.0/21, - 211.149.96.0/19, - 211.149.128.0/17, - 211.150.0.0/15, - 211.152.0.0/17, - 211.152.128.0/20, - 211.152.144.0/22, - 211.152.150.0/23, - 211.152.152.0/21, - 211.152.160.0/19, - 211.152.192.0/18, - 211.153.0.0/16, - 211.154.0.0/16, - 211.155.0.0/18, - 211.155.66.0/23, - 211.155.68.0/22, - 211.155.72.0/21, - 211.155.80.0/20, - 211.155.96.0/19, - 211.155.128.0/18, - 211.155.208.0/20, - 211.155.224.0/19, - 211.156.0.0/14, - 211.160.0.0/14, - 211.164.0.0/15, - 211.166.0.0/16, - 211.167.0.0/19, - 211.167.64.0/18, - 211.167.128.0/17, - 212.64.0.0/17, - 212.129.128.0/17, - 218.0.0.0/12, - 218.16.0.0/13, - 218.24.0.0/14, - 218.28.0.0/15, - 218.30.0.0/19, - 218.30.32.0/22, - 218.30.36.0/23, - 218.30.38.0/24, - 218.30.40.0/22, - 218.30.45.0/24, - 218.30.46.0/23, - 218.30.48.0/21, - 218.30.56.0/22, - 218.30.60.0/23, - 218.30.64.0/18, - 218.30.128.0/17, - 218.31.0.0/16, - 218.56.0.0/13, - 218.64.0.0/11, - 218.96.0.0/16, - 218.97.0.0/17, - 218.97.160.0/19, - 218.97.192.0/18, - 218.98.0.0/15, - 218.100.88.0/21, - 218.100.96.0/19, - 218.100.128.0/17, - 218.104.0.0/14, - 218.108.0.0/15, - 218.185.192.0/19, - 218.185.240.0/24, - 218.185.242.0/24, - 218.185.244.0/24, - 218.185.246.0/23, - 218.192.0.0/12, - 218.240.0.0/14, - 218.244.0.0/15, - 218.246.0.0/16, - 218.247.0.0/18, - 218.247.96.0/19, - 218.247.128.0/17, - 218.249.0.0/16, - 219.72.0.0/16, - 219.82.0.0/16, - 219.83.128.0/17, - 219.90.68.0/22, - 219.90.72.0/21, - 219.128.0.0/11, - 219.216.0.0/13, - 219.224.0.0/13, - 219.232.0.0/15, - 219.234.10.0/23, - 219.234.12.0/22, - 219.234.32.0/19, - 219.234.64.0/18, - 219.234.128.0/17, - 219.235.0.0/16, - 219.236.0.0/14, - 219.242.0.0/15, - 219.244.0.0/14, - 220.101.192.0/18, - 220.112.0.0/14, - 220.152.128.0/17, - 220.154.0.0/15, - 220.158.240.0/22, - 220.160.0.0/13, - 220.168.0.0/14, - 220.172.0.0/15, - 220.174.0.0/20, - 220.174.16.0/21, - 220.174.24.0/23, - 220.174.28.0/22, - 220.174.32.0/19, - 220.174.64.0/20, - 220.174.80.0/21, - 220.174.88.0/22, - 220.174.92.0/23, - 220.174.96.0/19, - 220.174.128.0/17, - 220.175.0.0/16, - 220.176.0.0/12, - 220.192.0.0/12, - 220.231.0.0/18, - 220.231.128.0/17, - 220.232.64.0/18, - 220.234.0.0/16, - 220.242.0.0/22, - 220.242.4.0/23, - 220.242.6.0/24, - 220.242.8.0/21, - 220.242.16.0/20, - 220.242.32.0/19, - 220.242.64.0/18, - 220.242.128.0/17, - 220.243.0.0/16, - 220.247.136.0/23, - 220.247.142.0/23, - 220.248.0.0/14, - 220.252.0.0/16, - 221.0.0.0/13, - 221.8.0.0/14, - 221.12.0.0/17, - 221.12.128.0/18, - 221.13.0.0/16, - 221.14.0.0/15, - 221.122.0.0/15, - 221.128.132.0/22, - 221.128.136.0/21, - 221.128.144.0/20, - 221.128.160.0/19, - 221.128.192.0/23, - 221.128.194.0/24, - 221.128.196.0/22, - 221.128.200.0/21, - 221.128.208.0/20, - 221.128.224.0/21, - 221.128.232.0/22, - 221.128.238.0/23, - 221.129.0.0/16, - 221.130.0.0/15, - 221.133.224.0/19, - 221.136.0.0/15, - 221.172.0.0/14, - 221.176.0.0/13, - 221.192.0.0/14, - 221.196.0.0/15, - 221.198.0.0/16, - 221.199.0.0/17, - 221.199.128.0/18, - 221.199.192.0/20, - 221.199.224.0/19, - 221.200.0.0/13, - 221.208.0.0/12, - 221.224.0.0/12, - 222.16.0.0/12, - 222.32.0.0/11, - 222.64.0.0/11, - 222.125.0.0/16, - 222.126.128.0/17, - 222.128.0.0/12, - 222.160.0.0/14, - 222.168.0.0/13, - 222.176.0.0/12, - 222.192.0.0/11, - 222.240.0.0/13, - 222.248.0.0/15, - 223.0.0.0/12, - 223.20.0.0/15, - 223.27.184.0/22, - 223.29.208.0/22, - 223.29.252.0/24, - 223.29.255.0/24, - 223.64.0.0/11, - 223.96.0.0/12, - 223.112.0.0/14, - 223.116.0.0/15, - 223.121.128.0/17, - 223.122.5.0/24, - 223.122.6.0/23, - 223.122.13.0/24, - 223.122.14.0/23, - 223.122.18.0/23, - 223.122.20.0/22, - 223.122.26.0/23, - 223.122.28.0/23, - 223.123.196.0/22, - 223.123.204.0/22, - 223.123.208.0/20, - 223.123.224.0/19, - 223.124.0.0/14, - 223.128.0.0/15, - 223.144.0.0/12, - 223.160.0.0/14, - 223.166.0.0/15, - 223.192.0.0/15, - 223.198.0.0/15, - 223.201.0.0/16, - 223.202.0.0/15, - 223.208.0.0/13, - 223.220.0.0/15, - 223.223.176.0/20, - 223.223.192.0/20, - 223.240.0.0/13, - 223.248.0.0/14, - 223.252.128.0/17, - 223.254.0.0/17, - 223.254.160.0/19, - 223.254.192.0/18, - 223.255.0.0/17, - 223.255.236.0/22, - 223.255.252.0/23 - } -} diff --git a/clashoo/files/usr/share/clashoo/rpc/rpc_async.sh b/clashoo/files/usr/share/clashoo/rpc/rpc_async.sh deleted file mode 100644 index ee00dfd4..00000000 --- a/clashoo/files/usr/share/clashoo/rpc/rpc_async.sh +++ /dev/null @@ -1,44 +0,0 @@ -#!/bin/sh - -ACTION="$1" -LOG_FILE="/tmp/clash_update.txt" - -log_line() { - printf '%s - %s\n' "$(date '+%Y-%m-%d %H:%M:%S')" "$1" >> "$LOG_FILE" -} - -run_init_async() { - local action="$1" - mkdir -p /tmp/lock >/dev/null 2>&1 - (flock /tmp/lock/clashoo_rpc_async.lock /etc/init.d/clashoo "$action" >/dev/null 2>&1 >"$LOG_FILE" 2>&1 &-; nohup /usr/share/clashoo/update/geoip.sh >/dev/null 2>&1 &2 - exit 1 - ;; -esac diff --git a/clashoo/files/usr/share/clashoo/ruleset/cn-ip.srs b/clashoo/files/usr/share/clashoo/ruleset/cn-ip.srs deleted file mode 100644 index ef9118fa..00000000 Binary files a/clashoo/files/usr/share/clashoo/ruleset/cn-ip.srs and /dev/null differ diff --git a/clashoo/files/usr/share/clashoo/ruleset/cn.mrs b/clashoo/files/usr/share/clashoo/ruleset/cn.mrs deleted file mode 100644 index 610f2d2d..00000000 Binary files a/clashoo/files/usr/share/clashoo/ruleset/cn.mrs and /dev/null differ diff --git a/clashoo/files/usr/share/clashoo/ruleset/geolocation-!cn.srs b/clashoo/files/usr/share/clashoo/ruleset/geolocation-!cn.srs deleted file mode 100644 index 6f26b898..00000000 Binary files a/clashoo/files/usr/share/clashoo/ruleset/geolocation-!cn.srs and /dev/null differ diff --git a/clashoo/files/usr/share/clashoo/ruleset/geosite-cn.srs b/clashoo/files/usr/share/clashoo/ruleset/geosite-cn.srs deleted file mode 100644 index 216609fe..00000000 Binary files a/clashoo/files/usr/share/clashoo/ruleset/geosite-cn.srs and /dev/null differ diff --git a/clashoo/files/usr/share/clashoo/ruleset/private-ip.srs b/clashoo/files/usr/share/clashoo/ruleset/private-ip.srs deleted file mode 100644 index f825d93c..00000000 Binary files a/clashoo/files/usr/share/clashoo/ruleset/private-ip.srs and /dev/null differ diff --git a/clashoo/files/usr/share/clashoo/runtime/backup.sh b/clashoo/files/usr/share/clashoo/runtime/backup.sh deleted file mode 100755 index 85bcc17c..00000000 --- a/clashoo/files/usr/share/clashoo/runtime/backup.sh +++ /dev/null @@ -1,21 +0,0 @@ -#!/bin/sh -. /lib/functions.sh - -CURL_GROUP_CACHE="/usr/share/clashbackup/clash_gorup.json" -CURL_NOW_CACHE="/usr/share/clashbackup/clash_now.json" -CURL_CACHE="/usr/share/clashbackup/clash_curl.json" -HISTORY_PATH="/usr/share/clashbackup/history" -SECRET=$(uci get clashoo.config.dash_pass 2>/dev/null) -LAN_IP=$(uci get network.lan.ipaddr 2>/dev/null |awk -F '/' '{print $1}' 2>/dev/null) -PORT=$(uci get clashoo.config.dash_port 2>/dev/null) - -curl -m 5 --retry 2 -w %{http_code}"\n" -H "Authorization: Bearer ${SECRET}" -H "Content-Type:application/json" -X GET http://"$LAN_IP":"$PORT"/proxies > "$CURL_CACHE" 2>/dev/null -if [ "$(sed -n '$p' "$CURL_CACHE" 2>/dev/null)" = "200" ]; then - if [ ! -d /usr/share/clashbackup ];then - mkdir -p /usr/share/clashbackup 2>/dev/null - fi - cat "$CURL_CACHE" |jsonfilter -e '@["proxies"][@.type="Selector"]["name"]' > "$CURL_GROUP_CACHE" 2>/dev/null - cat "$CURL_CACHE" |jsonfilter -e '@["proxies"][@.type="Selector"]["now"]' > "$CURL_NOW_CACHE" 2>/dev/null - awk 'NR==FNR{a[i]=$0;i++}NR>FNR{print a[j]"#*#"$0;j++}' "$CURL_GROUP_CACHE" "$CURL_NOW_CACHE" > "$HISTORY_PATH" 2>/dev/null -fi -rm -rf /usr/share/clashbackup/clash_*.json 2>/dev/null diff --git a/clashoo/files/usr/share/clashoo/runtime/clashoo.sh b/clashoo/files/usr/share/clashoo/runtime/clashoo.sh deleted file mode 100755 index 35d7ebfe..00000000 --- a/clashoo/files/usr/share/clashoo/runtime/clashoo.sh +++ /dev/null @@ -1,353 +0,0 @@ -#!/bin/sh - -REAL_LOG="/usr/share/clashoo/clashoo_real.txt" -UPDATE_LOG="/tmp/clash_update.txt" -LIST_FILE="/usr/share/clashbackup/confit_list.conf" -SUB_DIR="/usr/share/clashoo/config/sub" -TMP_PREFIX="/tmp/clash_sub_$$" -DEFAULT_SUB_UA='Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36' - -subtype="$(uci -q get clashoo.config.subcri 2>/dev/null)" -config_name_raw="$(uci -q get clashoo.config.config_name 2>/dev/null)" -lang="$(uci -q get luci.main.lang 2>/dev/null)" - -log_text() { - if [ "$lang" = "en" ]; then - echo "$1" >"$REAL_LOG" - else - echo "$2" >"$REAL_LOG" - fi -} - -log_update() { - printf ' %s - %s\n' "$(date '+%Y-%m-%d %H:%M:%S')" "$1" >>"$UPDATE_LOG" -} - -sanitize_name() { - local name - name="$1" - name="$(printf '%s' "$name" | tr 'A-Z' 'a-z')" - name="$(printf '%s' "$name" | sed -e 's/\.yaml$//' -e 's/\.yml$//')" - name="$(printf '%s' "$name" | tr ' /' '--')" - name="$(printf '%s' "$name" | sed -e 's/[^a-z0-9._-]/-/g' -e 's/--\+/-/g' -e 's/^[._-]*//' -e 's/[._-]*$//')" - printf '%s' "$name" -} - -sanitize_custom_name() { - local name - name="$1" - name="$(printf '%s' "$name" | sed -e 's/\.yaml$//' -e 's/\.yml$//')" - name="$(printf '%s' "$name" | tr ' /' '--')" - name="$(printf '%s' "$name" | sed -e 's/[\\]//g' -e 's/\.\.+/-/g' -e 's/--\+/-/g' -e 's/^[._-]*//' -e 's/[._-]*$//')" - printf '%s' "$name" -} - -url_decode() { - printf '%s' "$1" | sed 's/%/\\x/g' | xargs -0 printf '%b' 2>/dev/null || printf '%s' "$1" -} - -url_to_name() { - local url host qname decoded - url="$1" - - qname="$(printf '%s' "$url" | sed -n 's/.*[?&]filename=\([^&#]*\).*/\1/p')" - [ -n "$qname" ] || qname="$(printf '%s' "$url" | sed -n 's/.*[?&]name=\([^&#]*\).*/\1/p')" - if [ -n "$qname" ]; then - # URL decode then strip non-filename chars, keep CJK and alphanumeric - decoded="$(url_decode "$qname")" - decoded="$(printf '%s' "$decoded" | tr -d '\r\n' | sed -e 's/[[:space:]]/-/g' -e 's/[/\\:*?"<>|]//g' -e 's/\.yaml$//' -e 's/\.yml$//')" - [ -n "$decoded" ] && printf '%s' "$decoded" && return - fi - qname="$(sanitize_name "$qname")" - if [ -n "$qname" ]; then - printf '%s' "$qname" - return - fi - - host="$(printf '%s' "$url" | sed -e 's#^[a-zA-Z0-9+.-]*://##' -e 's#/.*$##' -e 's/:.*$//' -e 's#\..*$##')" - host="$(sanitize_name "$host")" - [ -n "$host" ] || host="sub" - printf '%s' "$host" -} - -next_available_name() { - local base try idx - base="$1" - base="$(printf '%s' "$base" | sed -e 's/\.yaml$//' -e 's/\.yml$//')" - base="$(printf '%s' "$base" | tr ' /' '--')" - base="$(printf '%s' "$base" | sed -e 's/[\\]//g' -e 's/\.\.+/-/g' -e 's/--\+/-/g' -e 's/^[._-]*//' -e 's/[._-]*$//')" - [ -n "$base" ] || base="sub" - - if [ ! -f "$SUB_DIR/${base}.yaml" ]; then - printf '%s' "$base" - return - fi - - idx=2 - while :; do - try="${base}-${idx}" - if [ ! -f "$SUB_DIR/${try}.yaml" ]; then - printf '%s' "$try" - return - fi - idx=$((idx + 1)) - done -} - -get_subscription_urls() { - uci -q show clashoo.config 2>/dev/null | awk -F"'" ' - /^clashoo.config.subscribe_url=/ { - if (NF >= 3) { - for (i = 2; i <= NF; i += 2) { - if (length($i) > 0) print $i - } - } else { - sub(/^clashoo.config.subscribe_url=/, "", $0) - if (length($0) > 0) print $0 - } - } - ' -} - -ensure_system_dns() { - local test_host - test_host="github.com" - if nslookup "$test_host" 127.0.0.1 >/dev/null 2>&1 || nslookup "$test_host" >/dev/null 2>&1; then - return 0 - fi - - uci delete dhcp.@dnsmasq[0].server >/dev/null 2>&1 - uci set dhcp.@dnsmasq[0].noresolv='0' >/dev/null 2>&1 - uci del_list dhcp.@dnsmasq[0].server='127.0.0.1#' >/dev/null 2>&1 - uci del_list dhcp.@dnsmasq[0].server='127.0.0.1#5300' >/dev/null 2>&1 - uci add_list dhcp.@dnsmasq[0].server='119.29.29.29' >/dev/null 2>&1 - uci add_list dhcp.@dnsmasq[0].server='223.5.5.5' >/dev/null 2>&1 - uci commit dhcp >/dev/null 2>&1 - /etc/init.d/dnsmasq restart >/dev/null 2>&1 - sleep 2 -} - -extract_host() { - printf '%s' "$1" | sed -e 's#^[a-zA-Z0-9+.-]*://##' -e 's#/.*$##' -e 's#:.*$##' -e 's#.*@##' -} - -resolve_via() { - local host dns - host="$1" - dns="$2" - nslookup "$host" "$dns" 2>/dev/null | awk ' - /^Address/ { - ip = $NF - if (ip ~ /^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$/ && - ip !~ /^127\./ && - ip !~ /^0\./ && - ip !~ /^198\.18\./ && - ip != "8.8.8.8" && ip != "8.8.4.4" && - ip != "1.1.1.1" && ip != "1.0.0.1" && - ip != "223.5.5.5" && ip != "223.6.6.6" && - ip != "119.29.29.29" && ip != "114.114.114.114") { - print ip - exit - } - }' -} - -curl_subscription() { - local url tmp hdr err ua host ip http_code rc - url="$1" - tmp="$2" - hdr="$3" - err="$4" - ua="$5" - host="$6" - ip="$7" - - rm -f "$tmp" "$hdr" "$err" >/dev/null 2>&1 - - set -- - if [ -n "$host" ] && [ -n "$ip" ]; then - set -- --resolve "$host:443:$ip" --resolve "$host:80:$ip" - fi - http_code="$(curl -sSL --connect-timeout 15 --max-time 60 \ - --speed-time 30 --speed-limit 1 --retry 2 \ - -H "User-Agent: ${ua}" -D "$hdr" -o "$tmp" \ - "$@" \ - -w '%{http_code}' "$url" 2>"$err")" - rc=$? - printf '%s\n' "$http_code" - return "$rc" -} - -download_subscription() { - local url target tmp hdr err rc http_code info_line ua err_msg - local host ip dns - url="$1" - target="$2" - tmp="${TMP_PREFIX}.yaml" - hdr="${TMP_PREFIX}.hdr" - err="${TMP_PREFIX}.err" - - ua="$(uci -q get clashoo.config.sub_ua 2>/dev/null)" - [ -n "$ua" ] || ua="$DEFAULT_SUB_UA" - - if command -v curl >/dev/null 2>&1; then - http_code="$(curl_subscription "$url" "$tmp" "$hdr" "$err" "$ua" "" "")" - rc=$? - - if [ "$rc" -ne 0 ] || [ "$http_code" = "000" ]; then - host="$(extract_host "$url")" - case "$host" in - ''|[-.]*|*[!A-Za-z0-9.-]*) host='' ;; - esac - if [ -n "$host" ]; then - for dns in 223.5.5.5 119.29.29.29 1.1.1.1 8.8.8.8; do - ip="$(resolve_via "$host" "$dns")" - [ -n "$ip" ] || continue - log_update "DNS 回退:${host} -> ${ip} (@${dns})" - http_code="$(curl_subscription "$url" "$tmp" "$hdr" "$err" "$ua" "$host" "$ip")" - rc=$? - [ "$rc" -eq 0 ] && [ "$http_code" = "200" ] && break - done - fi - fi - else - wget -q --timeout=20 \ - --user-agent="$ua" "$url" -O "$tmp" 2>"$err" - rc=$? - http_code="" - fi - - if [ "$rc" -ne 0 ]; then - err_msg="$(grep -a 'curl:' "$err" 2>/dev/null | tail -1)" - [ -z "$err_msg" ] && err_msg="$(tail -1 "$err" 2>/dev/null)" - log_update "下载失败:$(basename "$target") rc=${rc} ${err_msg}" - rm -f "$tmp" "$hdr" "$err" >/dev/null 2>&1 - return 1 - fi - - if [ -n "$http_code" ] && [ "$http_code" != "200" ]; then - log_update "下载失败:$(basename "$target") HTTP ${http_code}" - rm -f "$tmp" "$hdr" "$err" >/dev/null 2>&1 - return 1 - fi - - if ! grep -Eq '^(proxies|proxy-providers):' "$tmp" 2>/dev/null; then - log_update "校验失败:$(basename "$target") 内容不含 proxies/proxy-providers" - rm -f "$tmp" "$hdr" "$err" >/dev/null 2>&1 - return 1 - fi - - info_line="$(grep -i 'subscription-userinfo:' "$hdr" 2>/dev/null | head -1 | \ - sed 's/^[Ss]ubscription-[Uu]serinfo:[[:space:]]*//' | tr -d '\r')" - [ -n "$info_line" ] && printf '%s\n' "$info_line" > "${target}.info" || \ - rm -f "${target}.info" >/dev/null 2>&1 - - rm -f "$hdr" "$err" >/dev/null 2>&1 - mv "$tmp" "$target" >/dev/null 2>&1 || { - rm -f "$tmp" >/dev/null 2>&1 - return 1 - } - printf '%s\n' "$ua" >"${target}.ua" - - return 0 -} - -upsert_meta() { - local filename url typ tmpf - filename="$1" - url="$2" - typ="$3" - tmpf="${TMP_PREFIX}.list" - - [ -f "$LIST_FILE" ] || touch "$LIST_FILE" - awk -F '#' -v n="$filename" '$1 != n { print $0 }' "$LIST_FILE" >"$tmpf" - printf '%s#%s#%s\n' "$filename" "$url" "$typ" >>"$tmpf" - mv "$tmpf" "$LIST_FILE" -} - -cleanup_tmp() { - rm -f "${TMP_PREFIX}.yaml" "${TMP_PREFIX}.urls" "${TMP_PREFIX}.list" \ - "${TMP_PREFIX}.hdr" "${TMP_PREFIX}.err" >/dev/null 2>&1 -} - -trap cleanup_tmp EXIT INT TERM - -[ "$subtype" = "clash" ] || [ "$subtype" = "meta" ] || subtype="clash" - -mkdir -p "$SUB_DIR" /usr/share/clashbackup >/dev/null 2>&1 -[ -f "$LIST_FILE" ] || touch "$LIST_FILE" - -URLS_FILE="${TMP_PREFIX}.urls" -get_subscription_urls | sed '/^[[:space:]]*$/d' | awk '!seen[$0]++' >"$URLS_FILE" - -url_count="$(wc -l <"$URLS_FILE" 2>/dev/null | tr -d ' ')" -if [ -z "$url_count" ] || [ "$url_count" -eq 0 ]; then - log_update "未找到订阅链接" - log_text "No subscription URL found" "未找到订阅链接" - sleep 2 - log_text "Clash for OpenWRT" "Clash for OpenWRT" - exit 1 -fi - -ensure_system_dns -log_update "开始下载订阅(共 ${url_count} 条)" -log_text "Downloading subscription..." "开始下载订阅..." - -base_name="$(sanitize_custom_name "$config_name_raw")" -timestamp="$(date +%Y%m%d)" - -success=0 -failed=0 -idx=0 -first_file="" - -while IFS= read -r url; do - [ -n "$url" ] || continue - idx=$((idx + 1)) - - if [ -n "$base_name" ]; then - if [ "$url_count" -gt 1 ]; then - name_candidate="$(sanitize_name "${base_name}-${idx}")" - file_base="$(next_available_name "$name_candidate")" - else - file_base="$base_name" - fi - else - name_candidate="$(url_to_name "$url")-${timestamp}" - if [ "$url_count" -gt 1 ]; then - name_candidate="${name_candidate}-${idx}" - fi - file_base="$(next_available_name "$name_candidate")" - fi - - target_file="$SUB_DIR/${file_base}.yaml" - if download_subscription "$url" "$target_file"; then - upsert_meta "${file_base}.yaml" "$url" "$subtype" - log_update "订阅下载成功:${file_base}.yaml" - [ -n "$first_file" ] || first_file="$target_file" - success=$((success + 1)) - else - log_update "订阅下载失败:${file_base}.yaml" - failed=$((failed + 1)) - fi -done <"$URLS_FILE" - -if [ "$success" -gt 0 ]; then - use_config="$(uci -q get clashoo.config.use_config 2>/dev/null)" - if [ -z "$use_config" ] || [ ! -f "$use_config" ]; then - uci set clashoo.config.use_config="$first_file" - uci set clashoo.config.config_type='1' - uci commit clashoo - fi - log_text "Subscription download completed: ${success} success, ${failed} failed" "订阅下载完成:成功 ${success} 个,失败 ${failed} 个" - log_update "订阅下载完成:成功 ${success} 个,失败 ${failed} 个" - ret=0 -else - log_text "All subscription downloads failed" "订阅下载失败" - log_update "订阅下载失败:全部链接失败" - ret=1 -fi - -sleep 2 -log_text "Clash for OpenWRT" "Clash for OpenWRT" -exit "$ret" diff --git a/clashoo/files/usr/share/clashoo/runtime/dns_helpers.sh b/clashoo/files/usr/share/clashoo/runtime/dns_helpers.sh deleted file mode 100755 index b4fa6b42..00000000 --- a/clashoo/files/usr/share/clashoo/runtime/dns_helpers.sh +++ /dev/null @@ -1,389 +0,0 @@ -#!/bin/sh -# Shared DNS helpers for ClashOO runtime generators. Keep POSIX sh compatible. - -dns_trim() { - printf '%s' "$1" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//' -} - -dns_has_scheme() { - printf '%s' "$1" | grep -Eq '^[A-Za-z][A-Za-z0-9+.-]*://' -} - -dns_norm_protocol() { - case "$(dns_trim "${1:-}")" in - ''|'none') printf '' ;; - udp|'udp://') printf 'udp://' ;; - tcp|'tcp://') printf 'tcp://' ;; - dot|tls|'tls://') printf 'tls://' ;; - doh|https|'https://') printf 'https://' ;; - doq|quic|'quic://') printf 'quic://' ;; - *) printf '%s' "$1" ;; - esac -} - -dns_normalize_server() { - local address protocol port prefix - address=$(dns_trim "${1:-}") - protocol=$(dns_trim "${2:-}") - port=$(dns_trim "${3:-}") - - [ -n "$address" ] || return 0 - - if dns_has_scheme "$address"; then - printf '%s' "$address" - return 0 - fi - - prefix=$(dns_norm_protocol "$protocol") - if [ -n "$port" ]; then - printf '%s%s:%s' "$prefix" "$address" "$port" - else - printf '%s%s' "$prefix" "$address" - fi -} - -dns_yaml_sq() { - printf "%s" "$1" | sed "s/'/''/g" -} - -dns_yaml_list_item() { - local value - value=$(dns_yaml_sq "$1") - printf " - '%s'\n" "$value" -} - -# Route DNS upstreams by rules and preserve the original setting. -dns_mihomo_apply_respect_rules() { - local cfg="$1" enabled="${2:-0}" tmp="${1}.$$" - [ -f "$cfg" ] || return 0 - - awk -v enabled="$enabled" ' - function indent_len(s) { match(s, /[^ ]/); return RSTART ? RSTART - 1 : length(s) } - function spaces(n, out,i) { - out = "" - for (i = 0; i < n; i++) - out = out " " - return out - } - function trim_value(s) { - sub(/^[[:space:]]*/, "", s) - sub(/[[:space:]]*$/, "", s) - return s - } - function flush_dns( i, sp) { - if (!in_dns) - return - sp = spaces(child_indent > 0 ? child_indent : dns_indent + 2) - print dns_lines[1] - if (enabled == "1") { - print sp "# >>> clashoo:dns_leak_protect_respect_rules" - print sp "# original-respect-rules: " (original_value != "" ? original_value : "absent") - print sp "respect-rules: true" - print sp "# <<< clashoo:dns_leak_protect_respect_rules" - } else if (original_value != "" && original_value != "absent") { - print sp "respect-rules: " original_value - } - for (i = 2; i <= dns_n; i++) - print dns_lines[i] - in_dns = 0 - dns_n = 0 - } - - /^dns:[[:space:]]*$/ { - flush_dns() - in_dns = 1 - dns_indent = indent_len($0) - child_indent = -1 - dns_n = 1 - dns_lines[dns_n] = $0 - original_value = "" - in_marker = 0 - next - } - in_dns { - cur_indent = indent_len($0) - if ($0 ~ /^[^[:space:]#][^:]*:/ && cur_indent <= dns_indent) { - flush_dns() - print - next - } - if ($0 ~ /^[[:space:]]*#[[:space:]]*>>>[[:space:]]*clashoo:dns_leak_protect_respect_rules[[:space:]]*$/) { - in_marker = 1 - if (child_indent < 0) child_indent = cur_indent - next - } - if (in_marker) { - if ($0 ~ /^[[:space:]]*#[[:space:]]*original-respect-rules:[[:space:]]*/) { - value = $0 - sub(/^[[:space:]]*#[[:space:]]*original-respect-rules:[[:space:]]*/, "", value) - original_value = trim_value(value) - } - if ($0 ~ /^[[:space:]]*#[[:space:]]*<<<[[:space:]]*clashoo:dns_leak_protect_respect_rules[[:space:]]*$/) - in_marker = 0 - next - } - if ($0 ~ /^[[:space:]]*respect-rules:[[:space:]]*/) { - if (original_value == "") { - value = $0 - sub(/^[[:space:]]*respect-rules:[[:space:]]*/, "", value) - original_value = trim_value(value) - } - if (child_indent < 0) child_indent = cur_indent - next - } - if ($0 ~ /^[[:space:]]*[^#[:space:]][^:]*:/ && cur_indent > dns_indent && child_indent < 0) - child_indent = cur_indent - dns_lines[++dns_n] = $0 - next - } - { print } - END { flush_dns() } - ' "$cfg" > "$tmp" && mv "$tmp" "$cfg" - rm -f "$tmp" 2>/dev/null -} - -# Use fallback DNS for queries; keep bootstrap DNS unchanged. -dns_mihomo_apply_leak_nameservers() { - local cfg="$1" enabled="${2:-0}" state="${1}.dns-leak-nameserver" - local selected="${1}.dns-leak-selected" tmp="${1}.$$" - # The config is rebuilt from the selected subscription on every run. - # A saved nameserver from an earlier run must never replace its DNS. - rm -f "$state" 2>/dev/null - [ "$enabled" = "1" ] || return 0 - [ -f "$cfg" ] || return 0 - command -v yq >/dev/null 2>&1 || return 0 - - yq e -r '.dns.fallback[]' "$cfg" > "$selected" 2>/dev/null || true - if [ ! -s "$selected" ]; then - printf '%s\n' 'https://1.1.1.1/dns-query' 'https://8.8.8.8/dns-query' > "$selected" - fi - - awk -v selected="$selected" ' - function indent_len(s) { match(s, /[^ ]/); return RSTART ? RSTART - 1 : length(s) } - function spaces(n, out,i) { - out = "" - for (i = 0; i < n; i++) out = out " " - return out - } - function print_selected(sp, line) { - print sp "nameserver:" - while ((getline line < selected) > 0) - if (line != "") print sp " - " line - close(selected) - inserted = 1 - } - /^dns:[[:space:]]*$/ { - in_dns = 1 - dns_indent = indent_len($0) - child_indent = -1 - print - next - } - in_dns && /^[^[:space:]#][^:]*:/ { - if (!inserted) print_selected(spaces(child_indent > 0 ? child_indent : dns_indent + 2)) - in_dns = 0 - print - next - } - in_dns && /^[[:space:]]*[^#[:space:]][^:]*:/ && child_indent < 0 { - child_indent = indent_len($0) - } - in_dns && /^[[:space:]]*nameserver:/ { - ns_indent = indent_len($0) - rest = $0 - sub(/^[[:space:]]*nameserver:[[:space:]]*/, "", rest) - sub(/[[:space:]]*(#.*)?$/, "", rest) - print_selected(spaces(ns_indent)) - if (rest == "") skip_ns = 1 - next - } - skip_ns { - cur_indent = indent_len($0) - if ($0 ~ /^[[:space:]]*$/ || cur_indent > ns_indent) next - skip_ns = 0 - } - { print } - END { - if (in_dns && !inserted) - print_selected(spaces(child_indent > 0 ? child_indent : dns_indent + 2)) - } - ' "$cfg" > "$tmp" && mv "$tmp" "$cfg" - rm -f "$selected" "$tmp" 2>/dev/null -} - - -# handle mihomo dns block: -# - strip previous clashoo:dns_leak_protect injection markers (incl. the old -# geosite:gfw block written by older versions) -# - rewrite the ipv6: line from ipv6_value (skip when empty) -# No longer injects fallback-filter.geosite:gfw — mihomo deprecated it and a -# GeoSite.dat missing the gfw category froze startup (issue #25). See flush_dns. -# (The fallback-filter parsing vars below are now vestigial; clean up separately.) -dns_mihomo_apply_leak_dns_block() { - local cfg="$1" enabled="${2:-0}" ipv6_value="${3:-}" tmp="${1}.$$" - [ -f "$cfg" ] || return 0 - - awk -v enabled="$enabled" -v ipv6_value="$ipv6_value" ' - function indent_len(s) { match(s, /[^ ]/); return RSTART ? RSTART - 1 : length(s) } - function spaces(n, out,i) { - out = "" - for (i = 0; i < n; i++) - out = out " " - return out - } - function flush_dns( i, sp, ff_sp) { - if (!in_dns) - return - if (in_ff) ff_end = dns_n - sp = spaces(child_indent > 0 ? child_indent : dns_indent + 2) - ff_sp = (ff_child_indent > 0 ? spaces(ff_child_indent) : sp " ") - - print dns_lines[1] - if (ipv6_value != "") - print sp "ipv6: " ipv6_value - # NOTE: clashoo used to inject `fallback-filter.geosite: [gfw]` here, but - # mihomo deprecated fallback-filter.geosite ("replace with nameserver-policy, - # will be removed") AND it hard-fails preflight + freezes startup (~90s) when - # the downloaded GeoSite.dat lacks the gfw category (issue #25). Stop - # injecting it. DNS-leak protection still works via respect-rules / leak - # nameservers / DST-PORT,853,REJECT handled elsewhere. The marker strip below - # still removes any gfw block injected by older versions, so disabling / - # upgrading cleans it up. - for (i = 2; i <= dns_n; i++) - print dns_lines[i] - in_dns = 0 - dns_n = 0 - } - - /^[[:space:]]*#[[:space:]]*>>>[[:space:]]*clashoo:dns_leak_protect[[:space:]]*$/ { - in_marker = 1 - next - } - in_marker { - if ($0 ~ /^[[:space:]]*#[[:space:]]*<<<[[:space:]]*clashoo:dns_leak_protect[[:space:]]*$/) - in_marker = 0 - next - } - - /^dns:[[:space:]]*$/ { - flush_dns() - in_dns = 1 - dns_indent = indent_len($0) - child_indent = -1 - dns_n = 1 - dns_lines[dns_n] = $0 - has_ff = 0 - in_ff = 0 - in_ff_geosite = 0 - ff_indent = -1 - ff_child_indent = -1 - ff_geosite_indent = -1 - ff_has_gfw = 0 - ff_end = -1 - next - } - in_dns { - cur_indent = indent_len($0) - if ($0 ~ /^[^[:space:]#][^:]*:/ && cur_indent <= dns_indent) { - flush_dns() - print - next - } - if ($0 ~ /^[[:space:]]*[^#[:space:]][^:]*:/ && cur_indent > dns_indent && child_indent < 0) - child_indent = cur_indent - if (in_ff && cur_indent <= ff_indent) { - ff_end = dns_n - in_ff = 0 - in_ff_geosite = 0 - } - if (in_ff_geosite && cur_indent <= ff_geosite_indent) - in_ff_geosite = 0 - if ($0 ~ /^[[:space:]]*fallback-filter:[[:space:]]*$/) { - has_ff = 1 - in_ff = 1 - ff_indent = cur_indent - ff_child_indent = -1 - } else if (in_ff && $0 ~ /^[[:space:]]*[^#[:space:]][^:]*:/ && ff_child_indent < 0) { - ff_child_indent = cur_indent - } - if (in_ff && $0 ~ /^[[:space:]]*geosite:[[:space:]]*$/) { - in_ff_geosite = 1 - ff_geosite_indent = cur_indent - } else if (in_ff_geosite && $0 ~ /^[[:space:]]*-[[:space:]]*gfw([[:space:]]*(#.*)?)?$/) { - ff_has_gfw = 1 - } - if ($0 ~ /^[[:space:]]*ipv6:[[:space:]]*/) - next - dns_lines[++dns_n] = $0 - next - } - { print } - END { flush_dns() } - ' "$cfg" > "$tmp" && mv "$tmp" "$cfg" - rm -f "$tmp" 2>/dev/null -} - -# handle DST-PORT,853,REJECT injection into rules block -# only remove Clashoo marker block, never user original rules -dns_mihomo_apply_leak_rule() { - local cfg="$1" enabled="${2:-0}" tmp="${1}.$$" has_user_853 - [ -f "$cfg" ] || return 0 - - has_user_853=$(awk ' - /^[[:space:]]*#[[:space:]]*>>>[[:space:]]*clashoo:dns_leak_protect_rule[[:space:]]*$/ { - in_marker = 1 - next - } - in_marker { - if ($0 ~ /^[[:space:]]*#[[:space:]]*<<<[[:space:]]*clashoo:dns_leak_protect_rule[[:space:]]*$/) - in_marker = 0 - next - } - /^[[:space:]]*-[[:space:]]*DST-PORT,853,REJECT([[:space:]]*(#.*)?)?$/ { found = 1 } - END { print found ? 1 : 0 } - ' "$cfg") - - awk -v enabled="$enabled" -v has_user_853="$has_user_853" ' - BEGIN { inserted = 0; saw_rules = 0 } - /^[[:space:]]*#[[:space:]]*>>>[[:space:]]*clashoo:dns_leak_protect_rule[[:space:]]*$/ { - in_marker = 1 - next - } - in_marker { - if ($0 ~ /^[[:space:]]*#[[:space:]]*<<<[[:space:]]*clashoo:dns_leak_protect_rule[[:space:]]*$/) - in_marker = 0 - next - } - /^rules:[[:space:]]*$/ { - saw_rules = 1 - print - if (enabled == "1" && has_user_853 != "1") { - print " # >>> clashoo:dns_leak_protect_rule" - print " - DST-PORT,853,REJECT" - print " # <<< clashoo:dns_leak_protect_rule" - inserted = 1 - } - next - } - { print } - END { - if (enabled == "1" && has_user_853 != "1" && !inserted && !saw_rules) { - print "" - print "rules:" - print " # >>> clashoo:dns_leak_protect_rule" - print " - DST-PORT,853,REJECT" - print " # <<< clashoo:dns_leak_protect_rule" - } - } - ' "$cfg" > "$tmp" && mv "$tmp" "$cfg" - rm -f "$tmp" 2>/dev/null -} - -dns_mihomo_apply_leak_protect() { - local cfg="$1" enabled="${2:-0}" ipv6_value="${3:-}" - [ -f "$cfg" ] || return 0 - dns_mihomo_apply_leak_nameservers "$cfg" "$enabled" - dns_mihomo_apply_respect_rules "$cfg" "$enabled" - dns_mihomo_apply_leak_dns_block "$cfg" "$enabled" "$ipv6_value" - dns_mihomo_apply_leak_rule "$cfg" "$enabled" -} diff --git a/clashoo/files/usr/share/clashoo/runtime/dns_loopback_adapter.yq b/clashoo/files/usr/share/clashoo/runtime/dns_loopback_adapter.yq deleted file mode 100644 index 12d5851e..00000000 --- a/clashoo/files/usr/share/clashoo/runtime/dns_loopback_adapter.yq +++ /dev/null @@ -1,17 +0,0 @@ -. as $document | -strenv(CLASHOO_DNS_OLD_PORT) as $old_port | -strenv(CLASHOO_DNS_HOST_PATTERN) as $host_pattern | -(strenv(CLASHOO_DNS_REPLACEMENT) | split(" ") | map(select(length > 0))) as $replacement | -("(?i)^(?:[a-z][a-z0-9+.-]*://)?(?:" + $host_pattern + "):" + $old_port + "(?:$|[/#?])") as $old_loopback | -( - $document | - select((.dns."proxy-server-nameserver" | type) == "!!seq") | - ([.dns."proxy-server-nameserver"[] | select(type == "!!str" and test($old_loopback))] | length) as $match_count | - select($match_count > 0) | - .dns."proxy-server-nameserver" = - ([ - .dns."proxy-server-nameserver"[] | - select((type == "!!str" and test($old_loopback)) | not) | - select(. as $server | ($replacement | contains([$server])) | not) - ] + $replacement) -) // $document diff --git a/clashoo/files/usr/share/clashoo/runtime/dns_node_policy.uc b/clashoo/files/usr/share/clashoo/runtime/dns_node_policy.uc deleted file mode 100644 index aa523a09..00000000 --- a/clashoo/files/usr/share/clashoo/runtime/dns_node_policy.uc +++ /dev/null @@ -1,118 +0,0 @@ -#!/usr/bin/ucode -'use strict'; - -import { readfile } from 'fs'; - -// Mirror node-domain DNS policies from the subscription into -// proxy-server-nameserver-policy (issue #73). -// -// Airports publish their own resolver for node domains, e.g. -// nameserver-policy: -// "+.chylink.xyz": [tls://112.74.48.57:10853] -// which answers with domestic relay IPs. mihomo resolves *proxy server* domains -// through proxy-server-nameserver(-policy) and ignores nameserver-policy there, -// so that resolver is never used and node domains fall back to public DNS - -// which may return overseas CDN IPs that some lines cannot reach at all, leaving -// every node (AnyTLS is TCP-only) timing out. -// -// Input : CLASHOO_NODE_DNS_SOURCE_FILE = path to {"policies": {...}, "servers": [...]} -// (CLASHOO_NODE_DNS_SOURCE with the JSON itself is still accepted) -// Output: JSON map with only the policy entries matching a node server domain -// (nothing is printed when there is no match) - -let source = ''; -let source_file = getenv('CLASHOO_NODE_DNS_SOURCE_FILE') || ''; - -if (length(source_file)) { - try { - source = readfile(source_file) || ''; - } - catch (e) { - exit(0); - } -} -else { - source = getenv('CLASHOO_NODE_DNS_SOURCE') || ''; -} - -if (!length(source)) - exit(0); - -let parsed; - -try { - parsed = json(source); -} -catch (e) { - exit(0); -} - -if (type(parsed) != 'object') - exit(0); - -let policies = parsed.policies; -let servers = parsed.servers; - -if (type(policies) != 'object' || type(servers) != 'array') - exit(0); - -let domains = []; -let seen = {}; - -for (let server in servers) { - if (type(server) != 'string' || !length(server)) - continue; - server = lc(server); - if (seen[server]) - continue; - seen[server] = true; - push(domains, server); -} - -if (!length(domains)) - exit(0); - -// suffix match on a label boundary: node.example.com matches +.example.com -function domain_matches(key, domain) { - let key_len = length(key); - let domain_len = length(domain); - - if (!key_len || domain_len < key_len) - return false; - if (domain == key) - return true; - if (substr(domain, domain_len - key_len) != key) - return false; - return substr(domain, domain_len - key_len - 1, 1) == '.'; -} - -let result = {}; - -for (let key, value in policies) { - if (type(key) != 'string' || !length(key)) - continue; - - let lowered = lc(key); - let is_pattern = match(lowered, /^[+*]?\./) != null; - let domain = replace(lowered, /^\+\./, ''); - - domain = replace(domain, /^\*\./, ''); - domain = replace(domain, /^\./, ''); - - let matched = false; - - for (let candidate in domains) { - if (is_pattern ? domain_matches(domain, candidate) : (candidate == lowered)) { - matched = true; - break; - } - } - - if (matched) - result[key] = value; -} - -if (!length(keys(result))) - exit(0); - -print(sprintf('%J', result)); diff --git a/clashoo/files/usr/share/clashoo/runtime/iprules.sh b/clashoo/files/usr/share/clashoo/runtime/iprules.sh deleted file mode 100755 index 9f2e327c..00000000 --- a/clashoo/files/usr/share/clashoo/runtime/iprules.sh +++ /dev/null @@ -1,98 +0,0 @@ -#!/bin/sh -. /lib/functions.sh - - -TMP_PREFIX="/tmp/clashoo_iprules.$$" -CUSTOM_RULE_FILE="${TMP_PREFIX}.ipadd.conf" -RULE="${TMP_PREFIX}.rules_conf.yaml" -CLASH="${TMP_PREFIX}.conf.yaml" -CONFIG_YAML="${CLASHOO_CONFIG_YAML:-/etc/clashoo/config.yaml}" -CLASH_CONFIG="${TMP_PREFIX}.config.yaml" -trap 'rm -f "$CUSTOM_RULE_FILE" "$RULE" "$CLASH" "$CLASH_CONFIG"' EXIT - -[ -f "$CONFIG_YAML" ] || exit 0 - -. /usr/share/clashoo/runtime/primary_group.sh - - -# __PROXY__ placeholder -> primary proxy group (cached by RPC); -# fallback to GLOBAL (built-in mihomo group) -CACHED_PRIMARY_GROUP="$(uci -q get clashoo.config.primary_proxy_group)" -PRIMARY_GROUP="$(clashoo_resolve_primary_group "$CONFIG_YAML" "$CACHED_PRIMARY_GROUP")" -[ -n "$PRIMARY_GROUP" ] || PRIMARY_GROUP="GLOBAL" - -append=$(uci get clashoo.config.append_rules 2>/dev/null) -if [ "${append:-0}" -eq 1 ];then - - if [ -f $CLASH_CONFIG ];then - rm -rf $CLASH_CONFIG 2>/dev/null - fi - - cp $CONFIG_YAML $CLASH_CONFIG 2>/dev/null - if [ ! -z "$(grep "^Rule:" "$CLASH_CONFIG")" ]; then - sed -i "/^Rule:/i\#RULESTART#" $CLASH_CONFIG 2>/dev/null - elif [ ! -z "$(grep "^rules:" "$CLASH_CONFIG")" ]; then - sed -i "/^rules:/i\#RULESTART#" $CLASH_CONFIG 2>/dev/null - fi - sed -i -e "\$a#RULEEND#" $CLASH_CONFIG 2>/dev/null - - awk '/#RULESTART#/,/#RULEEND#/{print}' "$CLASH_CONFIG" 2>/dev/null |sed "s/\'//g" 2>/dev/null |sed 's/\"//g' 2>/dev/null |sed 's/\t/ /g' 2>/dev/null |grep '^ \{0,\}- '|awk -F '- ' '{print "- "$2}' | sed 's/^ \{0,\}//' 2>/dev/null |sed 's/ \{0,\}$//' 2>/dev/null >$RULE 2>&1 - - sed -i '/#RULESTART#/,/#RULEEND#/d' "$CLASH_CONFIG" 2>/dev/null - - sed -i -e "\$a " $CLASH_CONFIG 2>/dev/null - sed -i "1i\rules:" $RULE 2>/dev/null - cat $CLASH_CONFIG $RULE >$CLASH 2>/dev/null - mv $CLASH $CONFIG_YAML 2>/dev/null - rm -f $RULE $CLASH_CONFIG 2>/dev/null -fi - -# ===== custom routing rules (UCI: config addtype), decoupled ===== -# fields: type(DOMAIN|SUFFIX|KEYWORD|IP-CIDR), ipaaddr, pgroup, res(no-resolve) -# pgroup: DIRECT or __PROXY__ (resolved at injection) -rm -f "$CUSTOM_RULE_FILE" 2>/dev/null - -ipadd() -{ - local section="$1" - config_get "pgroup" "$section" "pgroup" "" - config_get "ipaaddr" "$section" "ipaaddr" "" - config_get "type" "$section" "type" "" - config_get "res" "$section" "res" "" - - [ -z "$type" ] && return - [ -z "$ipaaddr" ] && return - [ -z "$pgroup" ] && return - - [ "$pgroup" = "__PROXY__" ] && pgroup="$PRIMARY_GROUP" - - # quote whole rule (group name may contain spaces/emoji) - # so mixed indent with subscription rules does not break YAML parsing - if [ "${res}" = "1" ];then - echo "${RULE_INDENT}- \"$type,$ipaaddr,$pgroup,no-resolve\"" >> "$CUSTOM_RULE_FILE" - else - echo "${RULE_INDENT}- \"$type,$ipaaddr,$pgroup\"" >> "$CUSTOM_RULE_FILE" - fi -} - -# detect existing rules indent for alignment (default 2) -RULE_INDENT="$(awk '/^[[:space:]]*rules:/{f=1;next} f&&/^[[:space:]]*-/{match($0,/^[[:space:]]*/);print substr($0,1,RLENGTH);exit}' "$CONFIG_YAML" 2>/dev/null)" -[ -n "$RULE_INDENT" ] || RULE_INDENT=" " - -config_load "clashoo" -config_foreach ipadd "addtype" - -# clean previous injection block (idempotent) -sed -i '/#CUSTOMRULESTART#/,/#CUSTOMRULEEND#/d' "$CONFIG_YAML" 2>/dev/null - -if [ -f "$CUSTOM_RULE_FILE" ];then - sed -i -e "\$a#CUSTOMRULEEND#" "$CUSTOM_RULE_FILE" 2>/dev/null - if [ ! -z "$(grep "^ \{0,\}rules:" "$CONFIG_YAML")" ]; then - # 插在 rules: 段最前面,优先于订阅自带规则命中(纠错) - sed -i '/^ \{0,\}rules:/a\#CUSTOMRULESTART#' "$CONFIG_YAML" 2>/dev/null - else - echo "rules:" >> "$CONFIG_YAML" 2>/dev/null - echo "#CUSTOMRULESTART#" >> "$CONFIG_YAML" 2>/dev/null - fi - sed -i "/#CUSTOMRULESTART#/r${CUSTOM_RULE_FILE}" "$CONFIG_YAML" 2>/dev/null -fi diff --git a/clashoo/files/usr/share/clashoo/runtime/mixin.uc b/clashoo/files/usr/share/clashoo/runtime/mixin.uc deleted file mode 100644 index 6ace606f..00000000 --- a/clashoo/files/usr/share/clashoo/runtime/mixin.uc +++ /dev/null @@ -1,339 +0,0 @@ -#!/usr/bin/ucode -'use strict'; - -import { cursor } from 'uci'; -const uci = cursor(); - -function b(v) { - if (v == null || v == '' || v == '0' || v == 'false') return false; - if (v == '1' || v == 'true') return true; - return v; -} -function i(v, d) { let n = v != null ? int(v) : null; return n != null ? n : d; } -function s(v, d) { let t = trim(v || ''); return length(t) ? t : d; } -function a(k) { return uci.get('clashoo', 'config', k); } -function ab(k) { return b(a(k)); } - -const cfg = {}; - -/* ── 端口与基本设置 ─────────────────────────────────────── */ -let v; -v = i(a('http_port')); if (v != null) cfg['port'] = v; -v = i(a('socks_port')); if (v != null) cfg['socks-port'] = v; -v = i(a('redir_port')); if (v != null) cfg['redir-port'] = v; -v = i(a('mixed_port')); if (v != null) cfg['mixed-port'] = v; -v = i(a('tproxy_port')); if (v != null) cfg['tproxy-port'] = v; - -v = a('bind_addr'); -if (!v || v == '*') v = null; -if (v) cfg['bind-address'] = v; - -v = a('p_mode'); -if (v == 'script') v = 'rule'; -if (v) cfg['mode'] = v; - -cfg['log-level'] = s(a('level'), 'info'); -cfg['allow-lan'] = ab('allow_lan'); -cfg['ipv6'] = ab('enable_ipv6'); -cfg['routing-mark'] = 6666; -cfg['external-controller'] = '0.0.0.0:' + i(a('dash_port'), 9090); -cfg['external-ui'] = './dashboard'; -cfg['secret'] = s(a('dash_pass'), ''); - -v = a('interf'); -if (v && v != '0') cfg['interface-name'] = v; - -/* ── TUN ───────────────────────────────────────────────── */ -let tun_mode = i(a('tun_mode'), 0); -let tcp_mode = s(a('tcp_mode'), 'redirect'); -let udp_mode = s(a('udp_mode'), 'tproxy'); -let tun_enabled = (tun_mode == 1 || tcp_mode == 'tun' || udp_mode == 'tun'); -let acl_enabled = false; -uci.foreach('clashoo', 'lan_acl', function(sec) { - if (b(sec.enabled) != false) acl_enabled = true; -}); -if (!ab('acl_migrated')) { - let access_control = i(a('access_control'), 0); - acl_enabled = access_control == 1 || access_control == 2; -} -let tun_acl = tun_enabled && acl_enabled; - -cfg['tun'] = { - enable: tun_enabled, - stack: s(a('stack'), 'gvisor'), - 'auto-route': true, - 'auto-redirect': !tun_acl, - 'auto-detect-interface': true, -}; -let tun_mtu = a('tun_mtu'); -if (tun_mtu != null) cfg['tun']['mtu'] = int(tun_mtu); -if (ab('tun_gso')) { - cfg['tun']['gso'] = true; - cfg['tun']['gso-max-size'] = i(a('tun_gso_max_size'), 65536); -} -if (ab('tun_dns_hijack')) { - cfg['tun']['dns-hijack'] = ['any:53', 'tcp://any:53']; -} -if (!tun_enabled) { - cfg['tun']['enable'] = false; -} - -/* ── DNS ───────────────────────────────────────────────── */ -let dns_port = i(a('listen_port'), 1053); -cfg['dns'] = { - enable: b(a('enable_dns')) != false, - listen: '0.0.0.0:' + dns_port, - 'enhanced-mode': s(a('enhanced_mode'), 'fake-ip'), - 'fake-ip-range': s(a('fake_ip_range'), '198.18.0.1/16'), - 'fake-ip-filter': [], - ipv6: ab('enable_ipv6'), -}; -if (cfg['dns']['enhanced-mode'] == 'fake-ip' && ab('enable_ipv6')) - cfg['dns']['fake-ip-range6'] = s(a('fake_ip_range6'), 'fc00::/18'); -/* fake-ip-filter-mode: blacklist (default) | whitelist | rule */ -let filter_mode = s(a('fake_ip_filter_mode'), 'blacklist'); -if (filter_mode != 'blacklist') cfg['dns']['fake-ip-filter-mode'] = filter_mode; - -/* map geosite:cn to bundled cn.mrs rule-set so mihomo skips the 10MB geosite.dat */ -let need_cn_rs = false; -let keep_fakeip = length(s(getenv('CLASHOO_KEEP_FAKEIP_FILTER'), '')); -if (keep_fakeip) { - delete cfg['dns']['fake-ip-filter']; -} else { - let push_filter = function(f) { - f = trim(f || ''); - if (!length(f)) return; - if (filter_mode == 'rule') { - if (match(f, /,(fake-ip|real-ip)$/)) { push(cfg['dns']['fake-ip-filter'], f); return; } - if (index(f, ',') >= 0) { push(cfg['dns']['fake-ip-filter'], f + ',real-ip'); return; } - if (f == 'geosite:cn') { f = 'RULE-SET,cn_domain,real-ip'; need_cn_rs = true; } - else if (match(f, /^geosite:/)) { f = 'GEOSITE,' + substr(f, 8) + ',real-ip'; } - else if (match(f, /^rule-set:/)) { - let rs = substr(f, 9); - if (rs == 'cn_domain') need_cn_rs = true; - f = 'RULE-SET,' + rs + ',real-ip'; - } - else if (match(f, /^\+\./)) { f = 'DOMAIN-SUFFIX,' + substr(f, 2) + ',real-ip'; } - else if (match(f, /\*/)) { f = 'DOMAIN-WILDCARD,' + f + ',real-ip'; } - else { f = 'DOMAIN,' + f + ',real-ip'; } - } else { - if (f == 'geosite:cn') { f = 'rule-set:cn_domain'; need_cn_rs = true; } - else if (f == 'rule-set:cn_domain') need_cn_rs = true; - } - push(cfg['dns']['fake-ip-filter'], f); - }; - let filters = a('fake_ip_filter'); - if (type(filters) == 'array') { for (let f in filters) push_filter(f); } - else if (filters != null) push_filter(filters); -} - -/* fallback-filter(默认 geoip:false,防止冷启动依赖 MMDB) */ -cfg['dns']['fallback-filter'] = { geoip: ab('fallback_filter_geoip') }; - -let dns_present = {}; -for (let f in split(s(getenv('CLASHOO_DNS_PRESENT'), ''), ',')) - if (length(trim(f))) dns_present[trim(f)] = true; -let dns_force = {}; -for (let f in split(s(getenv('CLASHOO_DNS_FORCE'), ''), ',')) - if (length(trim(f))) dns_force[trim(f)] = true; -let dns_inherit_mode = s(getenv('CLASHOO_DNS_INHERIT_MODE'), ''); -let inherited_nameserver = json(s(getenv('CLASHOO_DNS_INHERIT_NAMESERVER'), '[]')); -if (type(inherited_nameserver) != 'array') { - if (inherited_nameserver != null && inherited_nameserver != '') - inherited_nameserver = [inherited_nameserver]; - else - inherited_nameserver = []; -} -let dns_role_fields = ['nameserver', 'proxy-server-nameserver', 'direct-nameserver', - 'default-nameserver', 'nameserver-policy', 'proxy-server-nameserver-policy', 'respect-rules']; -let had_user_dns_roles = false; -for (let f in dns_role_fields) - if (dns_present[f]) had_user_dns_roles = true; -if (length(keys(dns_force)) || !had_user_dns_roles) - cfg['dns']['x-clashoo-managed-dns'] = true; - -function dns_scheme(protocol) { - switch (trim(protocol || '')) { - case '': - case 'none': return ''; - case 'udp': case 'udp://': return 'udp://'; - case 'tcp': case 'tcp://': return 'tcp://'; - case 'dot': case 'tls': case 'tls://': return 'tls://'; - case 'doh': case 'https': case 'https://': return 'https://'; - case 'doq': case 'quic': case 'quic://': return 'quic://'; - default: return protocol; - } -} - -function dns_server(address, protocol, port) { - let addr = trim(address || ''); - if (!length(addr)) return null; - if (match(addr, /^[A-Za-z][A-Za-z0-9+.-]*:\/\//)) return addr; - let prefix = dns_scheme(protocol); - return length(trim(port || '')) ? prefix + addr + ':' + trim(port) : prefix + addr; -} - -let dns_roles = {}; -uci.foreach('clashoo', 'dnsservers', function(sec) { - if (b(sec.enabled) == false) return; - let role = s(sec.ser_type, 'nameserver'); - if (role == 'fallback' && cfg['dns']['enhanced-mode'] == 'fake-ip') return; - let srv = dns_server(sec.ser_address, sec.protocol, sec.ser_port); - if (!srv) return; - if (!dns_roles[role]) dns_roles[role] = []; - push(dns_roles[role], srv); -}); -for (let role in keys(dns_roles)) { - if (role == 'proxy-server-nameserver' && (dns_inherit_mode == 'inherit' || dns_inherit_mode == 'skip') && - !dns_present[role] && !dns_force[role]) continue; - if (!dns_present[role] || dns_force[role]) cfg['dns'][role] = dns_roles[role]; -} - -if (dns_inherit_mode == 'inherit' && length(inherited_nameserver) && - !dns_present['proxy-server-nameserver'] && !dns_force['proxy-server-nameserver']) - cfg['dns']['proxy-server-nameserver'] = inherited_nameserver; - -let bootstrap = a('default_nameserver'); -if (bootstrap == null) bootstrap = a('defaul_nameserver'); -if (type(bootstrap) != 'array') bootstrap = bootstrap != null ? [bootstrap] : []; -if (length(bootstrap) && (!dns_present['default-nameserver'] || dns_force['default-nameserver'])) - cfg['dns']['default-nameserver'] = bootstrap; - -let policies = {}; -let proxy_policies = {}; -uci.foreach('clashoo', 'dns_policy', function(sec) { - if (b(sec.enabled) == false) return; - let role = s(sec.policy_type, 'nameserver-policy'); - if (role != 'nameserver-policy' && role != 'proxy-server-nameserver-policy') return; - let matcher = trim(sec.matcher || ''); - let servers = sec.nameserver; - if (type(servers) != 'array') servers = servers != null ? [servers] : []; - if (!length(matcher) || !length(servers)) return; - if (matcher == 'geosite:cn') { matcher = 'rule-set:cn_domain'; need_cn_rs = true; } - if (role == 'nameserver-policy') policies[matcher] = servers; - else proxy_policies[matcher] = servers; -}); -if (length(keys(policies)) && (!dns_present['nameserver-policy'] || dns_force['nameserver-policy'])) - cfg['dns']['nameserver-policy'] = policies; -if (length(keys(proxy_policies)) && (!dns_present['proxy-server-nameserver-policy'] || dns_force['proxy-server-nameserver-policy'])) - cfg['dns']['proxy-server-nameserver-policy'] = proxy_policies; - -let respect_rules = a('dns_respect_rules') == null ? true : ab('dns_respect_rules'); -if (dns_force['respect-rules']) - cfg['dns']['respect-rules'] = respect_rules; -else if (respect_rules && length(cfg['dns']['proxy-server-nameserver'] || []) - && !dns_present['respect-rules'] && !dns_present['prefer-h3']) - cfg['dns']['respect-rules'] = true; - -/* profile */ -let store_selected = ab('selection_cache'); -/* fake-ip cache defaults ON to survive restarts; opt out with '0' */ -let store_fake = a('fake_ip_cache') == null ? true : ab('fake_ip_cache'); -if (store_selected || store_fake) { - cfg['profile'] = {}; - if (store_selected) cfg['profile']['store-selected'] = true; - if (store_fake) cfg['profile']['store-fake-ip'] = true; -} - -/* bundled cn.mrs rule-provider, referenced by fake-ip-filter rule-set:cn_domain */ -if (need_cn_rs) { - if (!cfg['rule-providers']) cfg['rule-providers'] = {}; - cfg['rule-providers']['cn_domain'] = { - type: 'file', - path: './ruleset/cn.mrs', - format: 'mrs', - behavior: 'domain', - }; -} - - - -/* ── authentication ────────────────────────────────── */ -if (ab('authentication')) { - cfg['authentication'] = []; - uci.foreach('clashoo', 'authentication', function(sec) { - if (b(sec.enabled) == false) return; - let user = trim(sec.username || ''); - let pass = trim(sec.password || ''); - if (user) push(cfg['authentication'], user + ':' + pass); - }); -} - -/* ── hosts ────────────────────────────────────────── */ -cfg['hosts'] = {}; -uci.foreach('clashoo', 'hosts', function(sec) { - if (b(sec.enabled) == false) return; - let domain = trim(sec.adress || ''); - let ip = trim(sec.ip || ''); - if (domain && ip) cfg['hosts'][domain] = ip; -}); -if (length(keys(cfg['hosts'])) == 0) delete cfg['hosts']; - -/* ── sniffer ──────────────────────────────────────── */ -if (ab('sniffer_streaming') && !length(s(getenv('CLASHOO_KEEP_SNIFFER'), ''))) { - cfg['sniffer'] = { - enable: true, - 'force-dns-mapping': true, - 'parse-pure-ip': true, - sniff: { - HTTP: { ports: [80, 8080], 'override-destination': true }, - TLS: { ports: [443, 8443], 'override-destination': true }, - QUIC: { ports: [443, 8443], 'override-destination': true }, - }, - 'force-domain': [ - '+.youtube.com', - '+.googlevideo.com', - '+.netflix.com', - '+.nflxvideo.net', - '+.disneyplus.com', - '+.hulu.com', - '+.hbomax.com', - ], - 'skip-domain': [ - '+.lan', - '+.local', - ], - }; -} - -/* ── Smart kernel injection ───────────────────────── */ -if (ab('smart_auto_switch')) { - /* Smart 策略注入:通过 proxy-groups 覆盖实现 */ -} - -/* ── ECS ──────────────────────────────────────────── */ -let ecs = s(a('dns_ecs')); -if (ecs) cfg['dns']['edns-client-subnet'] = ecs; - -/* ── cache_file / experimental ──────────────────── */ -cfg['experimental'] = { - 'cache_file': { enabled: true }, - 'clash_api': { - 'external-controller': '0.0.0.0:' + i(a('dash_port'), 9090), - 'external-ui': './dashboard', - 'secret': s(a('dash_pass'), ''), - }, -}; - - -/* ── 输出 JSON (不含 null/空对象) ─────────────────── */ -function clean(obj) { - if (type(obj) == 'array') { - let r = []; - for (let e in obj) { - e = clean(e); - if (e != null) push(r, e); - } - return length(r) ? r : null; - } - if (type(obj) == 'object') { - let r = {}; - for (let k in keys(obj)) { - let v = clean(obj[k]); - if (v != null) r[k] = v; - } - return length(keys(r)) ? r : null; - } - return obj; -} -print(clean(cfg)); diff --git a/clashoo/files/usr/share/clashoo/runtime/primary_group.sh b/clashoo/files/usr/share/clashoo/runtime/primary_group.sh deleted file mode 100755 index 997e941b..00000000 --- a/clashoo/files/usr/share/clashoo/runtime/primary_group.sh +++ /dev/null @@ -1,49 +0,0 @@ -#!/bin/sh - -clashoo_resolve_primary_group() { - local config_yaml="$1" - local cached_group="$2" - local group_rows - local resolved_group - - if [ "$cached_group" = "GLOBAL" ]; then - printf '%s\n' "GLOBAL" - return 0 - fi - - if [ ! -f "$config_yaml" ] || ! command -v yq >/dev/null 2>&1; then - printf '%s\n' "GLOBAL" - return 0 - fi - - group_rows="$(yq -M e -r '(."proxy-groups" // [])[] | [.name, .type] | @tsv' "$config_yaml" 2>/dev/null)" || { - printf '%s\n' "GLOBAL" - return 0 - } - - if [ -n "$cached_group" ] && printf '%s\n' "$group_rows" | - awk -F '\t' -v wanted="$cached_group" '$1 == wanted { found = 1; exit } END { exit !found }' - then - printf '%s\n' "$cached_group" - return 0 - fi - - resolved_group="$(printf '%s\n' "$group_rows" | awk -F '\t' ' - tolower($2) == "select" && - (index($1, "节点选择") || index($1, "代理") || index($1, "🚀") || tolower($1) ~ /proxy/) { - print $1 - exit - } - ')" - - if [ -z "$resolved_group" ]; then - resolved_group="$(printf '%s\n' "$group_rows" | awk -F '\t' ' - tolower($2) == "select" { - print $1 - exit - } - ')" - fi - - printf '%s\n' "${resolved_group:-GLOBAL}" -} diff --git a/clashoo/files/usr/share/clashoo/runtime/quic_fallback_guard.yq b/clashoo/files/usr/share/clashoo/runtime/quic_fallback_guard.yq deleted file mode 100644 index 59ee6074..00000000 --- a/clashoo/files/usr/share/clashoo/runtime/quic_fallback_guard.yq +++ /dev/null @@ -1,9 +0,0 @@ -# If every configured rule points to a proxy without UDP support, mihomo falls -# through to DIRECT. Reject only that otherwise-unmatched QUIC traffic so the -# client can retry over TCP; rules with a usable UDP target still win first. -with( - select(has("rules")) | - select((.rules | type) == "!!seq") | - select(([.rules[] | select(. == "AND,((NETWORK,UDP),(DST-PORT,443)),REJECT")] | length) == 0); - .rules += ["AND,((NETWORK,UDP),(DST-PORT,443)),REJECT"] -) diff --git a/clashoo/files/usr/share/clashoo/runtime/restore.sh b/clashoo/files/usr/share/clashoo/runtime/restore.sh deleted file mode 100755 index f5dd17f4..00000000 --- a/clashoo/files/usr/share/clashoo/runtime/restore.sh +++ /dev/null @@ -1,37 +0,0 @@ -#!/bin/sh - -if [ -f /usr/share/clashbackup/history ];then - -HISTORY_PATH="/usr/share/clashbackup/history" -SECRET=$(uci get clashoo.config.dash_pass 2>/dev/null) -LAN_IP=$(uci get network.lan.ipaddr 2>/dev/null |awk -F '/' '{print $1}' 2>/dev/null) -PORT=$(uci get clashoo.config.dash_port 2>/dev/null) -urlencode() { - if [ "$#" != 1 ]; then - return 1 - fi - printf '%s' "$1" | hexdump -v -e '1/1 "%u "' | awk ' - { - for (i = 1; i <= NF; i++) { - b = $i + 0 - if ((b >= 48 && b <= 57) || (b >= 65 && b <= 90) || - (b >= 97 && b <= 122) || b == 45 || b == 46 || - b == 95 || b == 126) - printf "%c", b - else - printf "%%%02X", b - } - }' -} -cat $HISTORY_PATH |while read line -do - if [ -z "$(echo $line |grep "#*#")" ]; then - continue - else - GORUP_NAME=$(urlencode "$(echo $line |awk -F '#*#' '{print $1}')") - NOW_NAME=$(echo $line |awk -F '#*#' '{print $3}') - curl -H "Authorization: Bearer ${SECRET}" -H "Content-Type:application/json" -X PUT -d '{"name":"'"$NOW_NAME"'"}' http://"$LAN_IP":"$PORT"/proxies/"$GORUP_NAME" >/dev/null 2>&1 - fi -done >/dev/null 2>&1 -curl -m 5 --retry 2 -H "Authorization: Bearer ${SECRET}" -H "Content-Type:application/json" -X DELETE http://"$LAN_IP":"$PORT"/connections >/dev/null 2>&1 -fi diff --git a/clashoo/files/usr/share/clashoo/runtime/sniffer_overrides.yq b/clashoo/files/usr/share/clashoo/runtime/sniffer_overrides.yq deleted file mode 100644 index 885d81af..00000000 --- a/clashoo/files/usr/share/clashoo/runtime/sniffer_overrides.yq +++ /dev/null @@ -1,28 +0,0 @@ -# Preserve every explicit user choice while restoring missing per-protocol defaults. -with( - .sniffer | - select((has("enable") | not) or (.enable == true)) | - select((has("override-destination") | not) or (."override-destination" == true)); - with( - select(has("force-dns-mapping") | not); - ."force-dns-mapping" = true - ) | - with( - select(has("parse-pure-ip") | not); - ."parse-pure-ip" = true - ) | - with( - .sniff | select(has("TLS")); - with( - .TLS | select(type == "!!map" and (has("override-destination") | not)); - ."override-destination" = true - ) - ) | - with( - .sniff | select(has("QUIC")); - with( - .QUIC | select(type == "!!map" and (has("override-destination") | not)); - ."override-destination" = true - ) - ) -) diff --git a/clashoo/files/usr/share/clashoo/server.list b/clashoo/files/usr/share/clashoo/server.list deleted file mode 100755 index 23dfb38d..00000000 --- a/clashoo/files/usr/share/clashoo/server.list +++ /dev/null @@ -1,63 +0,0 @@ -time.windows.com -time.nist.gov -time.apple.com -time.asia.apple.com -cn.ntp.org.cn -edu.ntp.org.cn -hk.ntp.org.cn -tw.ntp.org.cn -us.ntp.org.cn -sgp.ntp.org.cn -kr.ntp.org.cn -jp.ntp.org.cn -de.ntp.org.cn -ina.ntp.org.cn -0.openwrt.pool.ntp.org -1.openwrt.pool.ntp.org -2.openwrt.pool.ntp.org -3.openwrt.pool.ntp.org -ntp.aliyun.com -ntp1.aliyun.com -ntp2.aliyun.com -ntp3.aliyun.com -ntp4.aliyun.com -ntp5.aliyun.com -ntp6.aliyun.com -ntp7.aliyun.com -time1.aliyun.com -time2.aliyun.com -time3.aliyun.com -time4.aliyun.com -time5.aliyun.com -time6.aliyun.com -time7.aliyun.com -s1c.time.edu.cn -s2m.time.edu.cn -s1b.time.edu.cn -s1e.time.edu.cn -s2a.time.edu.cn -s2b.time.edu.cn -time1.apple.com -time2.apple.com -time3.apple.com -time4.apple.com -time5.apple.com -time6.apple.com -time7.apple.com -time1.google.com -time2.google.com -time3.google.com -time4.google.com -.music.163.com -.music.126.net -man.netease.com -api.iplay.163.com -ac.dun.163yun.com -mr.da.netease.com -crash.163.com -imap.163.com -msftconnecttest.com -msftncsi.com -captive.qq.com -ssl.ptlogin2.qq.com -login.qq.com diff --git a/clashoo/files/usr/share/clashoo/update/component_update.sh b/clashoo/files/usr/share/clashoo/update/component_update.sh deleted file mode 100755 index ba0b92bc..00000000 --- a/clashoo/files/usr/share/clashoo/update/component_update.sh +++ /dev/null @@ -1,649 +0,0 @@ -#!/bin/sh - -LOG_FILE="/tmp/clashoo_component_update.log" -RUN_FILE="/var/run/clashoo_component_update" -STATE_FILE="/tmp/clashoo_component_update_state" -TMP_DIR="/tmp/clashoo-component-update" -APK_UPGRADE_FLAG="/var/run/clashoo_package_upgrade" -FEED_BASE_URL="https://down.dllkids.xyz/openwrt-feed/clashoo" -GITHUB_API_URL="https://api.github.com/repos/kenzok8/openwrt-clashoo/releases/latest" -ENV_GITHUB_PROXY_PREFIX="${GITHUB_PROXY_PREFIX:-}" -UCI_GITHUB_PROXY_PREFIX="$(uci -q get clashoo.config.core_mirror_prefix 2>/dev/null)" -GITHUB_PROXY_PREFIX="${UCI_GITHUB_PROXY_PREFIX:-${ENV_GITHUB_PROXY_PREFIX:-https://ghfast.top/}}" -case "$GITHUB_PROXY_PREFIX" in - */) ;; - *) GITHUB_PROXY_PREFIX="${GITHUB_PROXY_PREFIX}/" ;; -esac -CONNECT_TIMEOUT="${CONNECT_TIMEOUT:-8}" -REQUEST_TIMEOUT="${REQUEST_TIMEOUT:-20}" -LOW_SPEED_TIME="${LOW_SPEED_TIME:-30}" -LOW_SPEED_LIMIT="${LOW_SPEED_LIMIT:-1024}" - -trap 'rm -f "$APK_UPGRADE_FLAG"' EXIT - -log() { - mkdir -p "$(dirname "$LOG_FILE")" "$(dirname "$STATE_FILE")" >/dev/null 2>&1 - printf '%s - %s\n' "$(date '+%Y-%m-%d %H:%M:%S')" "$*" >>"$LOG_FILE" - printf 'component=%s\nstatus=%s\nmessage=%s\n' "${COMPONENT:-}" "${STATUS:-running}" "$*" >"$STATE_FILE" -} - -finish() { - rc="$1" - msg="$2" - STATUS="success" - [ "$rc" -eq 0 ] || STATUS="failed" - log "$msg" - rm -f "$RUN_FILE" "$APK_UPGRADE_FLAG" - exit "$rc" -} - -# In kernel-only mode there is no transparent proxy, so component downloads -# would go out direct and stall behind the GFW. Route them through the running -# core (shared logic in proxy_lib.sh). Normal mode returns empty -> TPROXY. -# Guard the source: on a stale install missing proxy_lib.sh, an unguarded `.` -# under `set -e` kills the whole update silently (empty log, nothing happens). -# Fall back to no proxy detection (direct / TPROXY) instead of dying. -if [ -f /usr/share/clashoo/update/proxy_lib.sh ]; then - . /usr/share/clashoo/update/proxy_lib.sh -else - clashoo_detect_proxy() { :; } -fi -detect_proxy() { clashoo_detect_proxy; } - -fetch_text() { - url="$1" - proxy="$(detect_proxy)" - if command -v curl >/dev/null 2>&1; then - curl -fsSL --connect-timeout "$CONNECT_TIMEOUT" --max-time "$REQUEST_TIMEOUT" ${proxy:+--proxy "$proxy"} "$url" - return $? - fi - if command -v wget >/dev/null 2>&1; then - [ -n "$proxy" ] && { http_proxy="$proxy" https_proxy="$proxy" wget -qO- --timeout="$REQUEST_TIMEOUT" "$url"; return $?; } - wget -qO- --timeout="$REQUEST_TIMEOUT" "$url" - return $? - fi - return 127 -} - -download_file() { - url="$1" - out="$2" - proxy="$(detect_proxy)" - if command -v curl >/dev/null 2>&1; then - curl -fL --connect-timeout "$CONNECT_TIMEOUT" --speed-time "$LOW_SPEED_TIME" --speed-limit "$LOW_SPEED_LIMIT" ${proxy:+--proxy "$proxy"} "$url" -o "$out" - return $? - fi - if [ -n "$proxy" ]; then - http_proxy="$proxy" https_proxy="$proxy" wget -qO "$out" --timeout="$REQUEST_TIMEOUT" "$url" - return $? - fi - wget -qO "$out" --timeout="$REQUEST_TIMEOUT" "$url" -} - -download_url() { - url="$1" - case "$url" in - https://github.com/*) - printf '%s%s\n' "$GITHUB_PROXY_PREFIX" "$url" - ;; - *) - printf '%s\n' "$url" - ;; - esac -} - -root_free_kb() { - df -k / 2>/dev/null | awk 'NR==2 {print $4}' -} - -kb_to_mib() { - awk "BEGIN {printf \"%.0f\", (${1:-0}) / 1024}" -} - -ensure_root_space() { - need_kb="$1" - free_kb="$(root_free_kb)" - [ -n "$free_kb" ] || return 0 - [ "$free_kb" -ge "$need_kb" ] && return 0 - finish 1 "根分区空间不足:可用 $(kb_to_mib "$free_kb") MiB,至少需要 $(kb_to_mib "$need_kb") MiB" -} - -log_install_error() { - file="$1" - [ -s "$file" ] || return 0 - tail -8 "$file" 2>/dev/null | while IFS= read -r line; do - [ -n "$line" ] && log "$line" - done -} - -detect_manager() { - if command -v opkg >/dev/null 2>&1; then - echo opkg - return - fi - if command -v apk >/dev/null 2>&1; then - echo apk - return - fi - echo unsupported -} - -installed_package_version() { - pkg="$1" - if command -v opkg >/dev/null 2>&1; then - opkg status "$pkg" 2>/dev/null | awk -F': ' '/^Version:/{print $2; exit}' - return - fi - if command -v apk >/dev/null 2>&1; then - apk list -I "$pkg" 2>/dev/null | awk '{print $1; exit}' | sed -n "s/^${pkg}-//p" - fi -} - -package_installed() { - pkg="$1" - if command -v opkg >/dev/null 2>&1; then - opkg status "$pkg" 2>/dev/null | awk ' - $1 == "Status:" && $2 == "install" && $NF == "installed" { found = 1 } - END { exit !found } - ' - return - fi - apk info -e "$pkg" >/dev/null 2>&1 -} - -apk_install() { - proxy="$(detect_proxy)" - if [ -n "$proxy" ]; then - http_proxy="$proxy" https_proxy="$proxy" apk add --allow-untrusted --timeout 30 "$@" - else - apk add --allow-untrusted --timeout 30 "$@" - fi -} - -apk_bundle_install() { - printf '%s\n' "$$" >"$APK_UPGRADE_FLAG" - apk_install "$@" - rc=$? - rm -f "$APK_UPGRADE_FLAG" - return "$rc" -} - -verify_downloaded_package() { - file="$1" - [ -s "$file" ] || return 1 - if [ "$PM" = "apk" ]; then - apk verify --allow-untrusted "$file" >/dev/null 2>&1 - return - fi - gzip -t "$file" >/dev/null 2>&1 -} - -download_package_file() { - url="$1" - out="$2" - name="$3" - download_file "$(download_url "$url")" "$out" || finish 1 "下载 ${name} 失败" - verify_downloaded_package "$out" || finish 1 "${name} 文件校验失败" -} - -detect_arch() { - pm="$1" - if [ "$pm" = "opkg" ]; then - opkg print-architecture 2>/dev/null | awk '/^arch / {print $2}' | tail -n 1 - return - fi - # apk: DISTRIB_ARCH is authoritative (e.g. aarch64_cortex-a53); apk --print-arch - # only gives the generic "aarch64" which won't match the .apk package suffix. - if [ -r /etc/openwrt_release ]; then - a="$(sed -n "s/^DISTRIB_ARCH=['\"]\\([^'\"]*\\)['\"]$/\\1/p" /etc/openwrt_release | head -n 1)" - [ -n "$a" ] && { printf '%s\n' "$a"; return; } - fi - apk --print-arch 2>/dev/null -} - -detect_sdk() { - [ -r /etc/openwrt_release ] || return 1 - release="$(sed -n "s/^DISTRIB_RELEASE=['\"]\\([^'\"]*\\)['\"]$/\\1/p" /etc/openwrt_release | head -n 1)" - [ -n "$release" ] || return 1 - printf '%s\n' "$release" | grep -Eo '[0-9]+\.[0-9]+' | head -n 1 -} - -append_unique_word() { - value="$1" - list="$2" - [ -n "$value" ] || { - printf '%s\n' "$list" - return - } - case " $list " in - *" $value "*) ;; - *) list="${list}${list:+ }${value}" ;; - esac - printf '%s\n' "$list" -} - -build_sdk_candidates() { - pm="$1" - candidates="" - detected_sdk="$(detect_sdk || true)" - candidates="$(append_unique_word "$detected_sdk" "$candidates")" - - if [ "$pm" = "opkg" ]; then - for sdk in 24.10 23.05 22.03 21.02; do - candidates="$(append_unique_word "$sdk" "$candidates")" - done - else - for sdk in 25.12 24.10; do - candidates="$(append_unique_word "$sdk" "$candidates")" - done - fi - - printf '%s\n' "$candidates" -} - -find_manifest_value() { - key="$1" - manifest_text="$2" - printf '%s\n' "$manifest_text" | sed -n "s/^${key}=//p" | head -n 1 -} - -load_manifest_urls() { - sdk="$1" - arch="$2" - manifest_url="${FEED_BASE_URL}/${sdk}/${arch}/manifest-clashoo.txt" - manifest_text="$(fetch_text "$manifest_url" || true)" - [ -n "$manifest_text" ] || return 1 - - core_file="$(find_manifest_value "core" "$manifest_text")" - luci_file="$(find_manifest_value "luci" "$manifest_text")" - i18n_file="$(find_manifest_value "i18n" "$manifest_text")" - [ -n "$core_file" ] || return 1 - [ -n "$luci_file" ] || return 1 - case "$core_file" in *."$EXT") ;; *) return 1 ;; esac - case "$luci_file" in *."$EXT") ;; *) return 1 ;; esac - case "$i18n_file" in ""|*."$EXT") ;; *) return 1 ;; esac - - CORE_URL="${FEED_BASE_URL}/${sdk}/${arch}/${core_file}" - LUCI_URL="${FEED_BASE_URL}/${sdk}/${arch}/${luci_file}" - I18N_URL="" - [ -n "$i18n_file" ] && I18N_URL="${FEED_BASE_URL}/${sdk}/${arch}/${i18n_file}" - SOURCE_LABEL="R2 feed ${sdk}/${arch}" - return 0 -} - -load_github_urls() { - arch="$1" - ext="$2" - payload="$(fetch_text "$GITHUB_API_URL" || true)" - [ -n "$payload" ] || return 1 - - urls="$(printf '%s\n' "$payload" | sed -n 's/.*"browser_download_url":[[:space:]]*"\([^"]*\)".*/\1/p')" - [ -n "$urls" ] || return 1 - - if [ "$ext" = "apk" ]; then - CORE_URL="$(printf '%s\n' "$urls" | grep -E '/clashoo-[^-]+.*-r[0-9]+-'"$arch"'\.apk$' | head -n 1)" - LUCI_URL="$(printf '%s\n' "$urls" | grep -E '/luci-app-clashoo-[^-]+.*-r[0-9]+-('"$arch"'|all)\.apk$' | head -n 1)" - I18N_URL="$(printf '%s\n' "$urls" | grep -E '/luci-i18n-clashoo-zh-cn-[^-]+.*-r[0-9]+-('"$arch"'|all)\.apk$' | head -n 1)" - else - CORE_URL="$(printf '%s\n' "$urls" | grep -E '/clashoo_.*_'"$arch"'\.ipk$' | head -n 1)" - LUCI_URL="$(printf '%s\n' "$urls" | grep -E '/luci-app-clashoo_.*_all\.ipk$' | head -n 1)" - I18N_URL="$(printf '%s\n' "$urls" | grep -E '/luci-i18n-clashoo-zh-cn_.*_all\.ipk$' | head -n 1)" - fi - - [ -n "$CORE_URL" ] || return 1 - [ -n "$LUCI_URL" ] || return 1 - SOURCE_LABEL="GitHub latest" - return 0 -} - -# `~` 是版本里的预发布分隔符,而 release 资产文件名会把它换成 `.` -# (clashoo_2026.10.25.6780eee-r3_x86_64.ipk 对应已安装的 2026.10.25~6780eee-r3)。 -# 只比分隔符就会误判成「校验失败」,所以比较前统一归一化,解析时保持文件名原样。 -version_equal() { - [ -n "$1" ] && [ "$(printf '%s' "$1" | tr '~' '.')" = "$(printf '%s' "$2" | tr '~' '.')" ] -} - -package_version_from_url() { - file="${1##*/}" - case "$file" in - clashoo_*_"$ARCH".ipk) - v="${file#clashoo_}" - printf '%s\n' "${v%_${ARCH}.ipk}" - ;; - # 架构名本身可能带下划线(aarch64_generic / arm_cortex-a7_neon-vfpv4), - # 只截到版本号为止,否则尾巴会混进版本串。 - clashoo_*.ipk) printf '%s\n' "$file" | sed -n 's/^clashoo_\([^_]*\)_.*\.ipk$/\1/p' ;; - luci-app-clashoo_*.ipk) printf '%s\n' "$file" | sed -n 's/^luci-app-clashoo_\(.*\)_all\.ipk$/\1/p' ;; - luci-i18n-clashoo-zh-cn_*.ipk) printf '%s\n' "$file" | sed -n 's/^luci-i18n-clashoo-zh-cn_\(.*\)_all\.ipk$/\1/p' ;; - clashoo-*.apk) - printf '%s\n' "$file" | sed -n -e 's/^clashoo-\(.*-r[0-9][0-9]*\)-.*\.apk$/\1/p' -e 's/^clashoo-\(.*-r[0-9][0-9]*\)\.apk$/\1/p' | head -n 1 - ;; - luci-app-clashoo-*.apk) printf '%s\n' "$file" | sed -n -e 's/^luci-app-clashoo-\(.*-r[0-9][0-9]*\)-.*\.apk$/\1/p' -e 's/^luci-app-clashoo-\(.*-r[0-9][0-9]*\)\.apk$/\1/p' | head -n 1 ;; - luci-i18n-clashoo-zh-cn-*.apk) printf '%s\n' "$file" | sed -n -e 's/^luci-i18n-clashoo-zh-cn-\(.*-r[0-9][0-9]*\)-.*\.apk$/\1/p' -e 's/^luci-i18n-clashoo-zh-cn-\(.*-r[0-9][0-9]*\)\.apk$/\1/p' | head -n 1 ;; - *) printf '%s\n' "$file" ;; - esac -} - -resolve_bundle_urls() { - PM="$(detect_manager)" - [ "$PM" != "unsupported" ] || return 1 - ARCH="$(detect_arch "$PM")" - [ -n "$ARCH" ] || return 1 - EXT="ipk" - [ "$PM" = "apk" ] && EXT="apk" - - CORE_URL="" - LUCI_URL="" - I18N_URL="" - SOURCE_LABEL="" - - SDK_CANDIDATES="$(build_sdk_candidates "$PM")" - for sdk in $SDK_CANDIDATES; do - if load_manifest_urls "$sdk" "$ARCH"; then - return 0 - fi - done - - load_github_urls "$ARCH" "$EXT" -} - -backup_config() { - ts="$(date '+%Y%m%d-%H%M%S')" - BACKUP_DIR="/etc/clashoo/backup/component-upgrade-${ts}" - mkdir -p "$BACKUP_DIR/etc-config" "$BACKUP_DIR/etc-clashoo" >/dev/null 2>&1 || return 1 - [ -r /etc/config/clashoo ] && cp -a /etc/config/clashoo "$BACKUP_DIR/etc-config/clashoo" - # 只备份用户配置;Model.bin 等可重新下载的大文件不入备份,避免每次更新 - # 复制 ~5MB 的同一模型,把备份目录撑大、堆满本就紧张的根分区。 - for path in \ - /etc/clashoo/config.yaml \ - /etc/clashoo/config.json \ - /etc/clashoo/*.yaml \ - /etc/clashoo/*.yml \ - /etc/clashoo/*.json - do - [ -e "$path" ] || continue - cp -a "$path" "$BACKUP_DIR/etc-clashoo/" 2>/dev/null || true - done - log "已备份配置:${BACKUP_DIR}" - - # 只保留最近 1 个备份,删除更早的,避免无限堆积占满磁盘。 - ls -dt /etc/clashoo/backup/component-upgrade-* 2>/dev/null | tail -n +2 | while read -r _old; do - [ -n "$_old" ] && rm -rf "$_old" 2>/dev/null - done -} - -restore_config_backup() { - [ -n "${BACKUP_DIR:-}" ] || return 0 - [ -r "$BACKUP_DIR/etc-config/clashoo" ] && cp -a "$BACKUP_DIR/etc-config/clashoo" /etc/config/clashoo - if [ -d "$BACKUP_DIR/etc-clashoo" ]; then - mkdir -p /etc/clashoo - cp -a "$BACKUP_DIR/etc-clashoo/." /etc/clashoo/ 2>/dev/null || true - fi - uci commit clashoo >/dev/null 2>&1 || true -} - -clashoo_was_running() { - /etc/init.d/clashoo status >/dev/null 2>&1 && return 0 - return 1 -} - -restart_web_stack() { - # reload (not restart) rpcd so the LuCI login session survives a plugin - # update — rpcd restart drops every ubus session and forces a re-login - # (issue #12). reload still picks up the new ucode RPC backend. uhttpd needs - # nothing: updated static assets are served on the next request. - /etc/init.d/rpcd reload >/dev/null 2>&1 || true -} - -# which: clashoo(仅核心)/ luci(luci-app + 语言包)。两者拆开,clashoo -# 核心更新频率高于 LuCI,分别更新便于定位失败。 -run_pkg_update() { - which="$1" - log "正在检查组件包" - if ! resolve_bundle_urls; then - finish 1 "未找到适配当前设备的组件包" - fi - log "更新来源:${SOURCE_LABEL}" - - core_ver="$(package_version_from_url "$CORE_URL")" - luci_ver="$(package_version_from_url "$LUCI_URL")" - i18n_ver="" - [ -z "$I18N_URL" ] || i18n_ver="$(package_version_from_url "$I18N_URL")" - core_ver_before="$(installed_package_version clashoo)" - - apk_core_ready() { - package_installed clashoo && version_equal "$(installed_package_version clashoo)" "$core_ver" \ - && [ -x /etc/init.d/clashoo ] && [ -x /usr/share/clashoo/update/component_update.sh ] - } - - apk_luci_ready() { - package_installed luci-app-clashoo && version_equal "$(installed_package_version luci-app-clashoo)" "$luci_ver" \ - && { [ -z "$I18N_URL" ] || { package_installed luci-i18n-clashoo-zh-cn \ - && version_equal "$(installed_package_version luci-i18n-clashoo-zh-cn)" "$i18n_ver"; }; } \ - && [ -r /usr/share/luci/menu.d/luci-app-clashoo.json ] \ - && [ -r /usr/share/rpcd/ucode/luci.clashoo ] - } - - apk_bundle_ready() { - apk_core_ready && apk_luci_ready - } - - apk_update_ready() { - if [ "$which" = "clashoo" ]; then - apk_bundle_ready - else - package_installed clashoo && apk_luci_ready - fi - } - - if [ "$which" = "clashoo" ]; then - log "目标版本:Clashoo 核心 ${core_ver}" - cur_ver="$(installed_package_version clashoo)" - if [ "$PM" = "apk" ] && apk_update_ready; then - finish 0 "Clashoo 核心已是最新版本" - elif [ "$PM" != "apk" ] && version_equal "$cur_ver" "$core_ver"; then - finish 0 "Clashoo 核心已是最新版本" - fi - else - log "目标版本:客户端 ${luci_ver}" - cur_ver="$(installed_package_version luci-app-clashoo)" - if [ "$PM" = "apk" ] && apk_update_ready; then - finish 0 "客户端已是最新版本" - elif [ "$PM" != "apk" ] && version_equal "$cur_ver" "$luci_ver"; then - finish 0 "客户端已是最新版本" - fi - fi - - rm -rf "$TMP_DIR" - mkdir -p "$TMP_DIR" || finish 1 "创建临时目录失败" - - was_running=0 - clashoo_was_running && was_running=1 - backup_config || finish 1 "备份配置失败" - apk_core_file="" - - if [ "$PM" = "apk" ]; then - log "正在下载组件包" - if [ "$which" = "clashoo" ] || ! package_installed clashoo; then - ensure_root_space 98304 - download_package_file "$CORE_URL" "$TMP_DIR/core.${EXT}" "clashoo" - apk_core_file="$TMP_DIR/core.${EXT}" - fi - download_package_file "$LUCI_URL" "$TMP_DIR/luci.${EXT}" "luci-app-clashoo" - if [ -n "$I18N_URL" ]; then - download_package_file "$I18N_URL" "$TMP_DIR/i18n.${EXT}" "语言包" - fi - elif [ "$which" = "clashoo" ]; then - log "正在下载 Clashoo 核心" - download_package_file "$CORE_URL" "$TMP_DIR/core.${EXT}" "clashoo" - else - log "正在下载客户端(LuCI + 语言包)" - download_package_file "$LUCI_URL" "$TMP_DIR/luci.${EXT}" "luci-app-clashoo" - if [ -n "$I18N_URL" ]; then - download_package_file "$I18N_URL" "$TMP_DIR/i18n.${EXT}" "语言包" - fi - fi - - if [ "$PM" != "apk" ] && [ "$which" = "clashoo" ]; then - ensure_root_space 98304 - fi - - if [ "$which" = "clashoo" ]; then - log "正在安装 Clashoo 核心" - if [ "$PM" = "opkg" ]; then - opkg install --force-downgrade "$TMP_DIR/core.${EXT}" >"$TMP_DIR/install.log" 2>&1; rc=$? - else - apk_bundle_install ${apk_core_file:+"$apk_core_file"} "$TMP_DIR/luci.${EXT}" ${I18N_URL:+"$TMP_DIR/i18n.${EXT}"} >"$TMP_DIR/install.log" 2>&1; rc=$? - fi - else - log "正在安装客户端" - if [ "$PM" = "opkg" ]; then - opkg install --force-downgrade "$TMP_DIR/luci.${EXT}" ${I18N_URL:+"$TMP_DIR/i18n.${EXT}"} >"$TMP_DIR/install.log" 2>&1; rc=$? - else - apk_bundle_install ${apk_core_file:+"$apk_core_file"} "$TMP_DIR/luci.${EXT}" ${I18N_URL:+"$TMP_DIR/i18n.${EXT}"} >"$TMP_DIR/install.log" 2>&1; rc=$? - fi - fi - - if [ "$rc" -ne 0 ]; then - if [ "$PM" = "apk" ] && apk_update_ready; then - log "apk 报告了其它软件包的错误,本次组件已升级到目标版本" - rc=0 - else - log_install_error "$TMP_DIR/install.log" - log "安装失败,正在恢复配置备份" - restore_config_backup - finish "$rc" "组件更新失败,已停止操作,请查看组件更新日志" - fi - fi - - validation_failed() { - log "安装校验失败,正在恢复配置备份" - restore_config_backup - finish 1 "组件安装校验失败,已停止操作,请查看组件更新日志" - } - - if [ "$PM" = "apk" ]; then - if ! apk_update_ready; then - log "安装校验失败,正在安全重装组件包" - if [ -z "$apk_core_file" ] && ! package_installed clashoo; then - ensure_root_space 98304 - download_package_file "$CORE_URL" "$TMP_DIR/core.${EXT}" "clashoo" - apk_core_file="$TMP_DIR/core.${EXT}" - fi - apk_bundle_install --force-reinstall ${apk_core_file:+"$apk_core_file"} "$TMP_DIR/luci.${EXT}" \ - ${I18N_URL:+"$TMP_DIR/i18n.${EXT}"} >>"$TMP_DIR/install.log" 2>&1; repair_rc=$? - if [ "$repair_rc" -ne 0 ]; then - log_install_error "$TMP_DIR/install.log" - validation_failed - fi - apk_update_ready || validation_failed - fi - elif [ "$which" = "clashoo" ]; then - package_installed clashoo && version_equal "$(installed_package_version clashoo)" "$core_ver" \ - && [ -x /etc/init.d/clashoo ] && [ -x /usr/share/clashoo/update/component_update.sh ] \ - || validation_failed - else - package_installed luci-app-clashoo && version_equal "$(installed_package_version luci-app-clashoo)" "$luci_ver" \ - && [ -r /usr/share/luci/menu.d/luci-app-clashoo.json ] \ - && [ -r /usr/share/rpcd/ucode/luci.clashoo ] \ - || validation_failed - [ -z "$I18N_URL" ] || package_installed luci-i18n-clashoo-zh-cn || validation_failed - fi - - # APK component updates install the LuCI bundle in the same transaction. - if [ "$which" = "luci" ] || [ "$PM" = "apk" ]; then - log "正在刷新 LuCI 服务" - restart_web_stack - fi - core_ver_after="$(installed_package_version clashoo)" - restart_clashoo=0 - [ "$which" = "clashoo" ] && restart_clashoo=1 - [ "$PM" = "apk" ] && [ "$core_ver_before" != "$core_ver_after" ] && restart_clashoo=1 - if [ "$restart_clashoo" -eq 1 ] && [ "$was_running" -eq 1 ] && [ "$(uci -q get clashoo.config.enable 2>/dev/null)" = "1" ]; then - log "Clashoo 原本运行中,正在重启服务" - sh /usr/share/clashoo/rpc/rpc_async.sh restart >/dev/null 2>&1 || /etc/init.d/clashoo restart >/dev/null 2>&1 || true - elif [ "$restart_clashoo" -eq 1 ]; then - log "Clashoo 原本未运行,保持停止状态" - fi - - finish 0 "组件更新完成" -} - -run_core_update() { - dcore="$1" - label="$2" - log "正在更新 ${label}" - # Pass the target as an arg so core_download refreshes only that binary - # without switching the active kernel. It restarts only if the target is the - # currently-running core (see core_download.sh finalize). Switching kernels - # stays a separate, explicit user action. - touch /var/run/core_update - sh /usr/share/clashoo/update/core_download.sh "$dcore" >>/tmp/clash_update.txt 2>&1 - rc=$? - rm -f /var/run/core_update - [ "$rc" -eq 0 ] || finish "$rc" "${label} 更新失败" - finish 0 "${label} 更新完成" -} - -run_lgbm_update() { - log "正在更新 Smart LightGBM 模型" - sh /usr/share/clashoo/update/lgbm_update.sh >/tmp/lgbm_update.log 2>&1 - rc=$? - tail -5 /tmp/lgbm_update.log 2>/dev/null | while IFS= read -r line; do - [ -n "$line" ] && log "$line" - done - [ "$rc" -eq 0 ] || finish "$rc" "LightGBM 模型更新失败" - finish 0 "LightGBM 模型更新完成" -} - -run_china_update() { - log "正在更新大陆白名单" - sh /usr/share/clashoo/update/update_china_ip.sh >>/tmp/clash_update.txt 2>&1 - rc=$? - tail -6 /tmp/clash_update.txt 2>/dev/null | while IFS= read -r line; do - [ -n "$line" ] && printf '%s\n' "$line" | grep -q '白名单' && log "$line" - done - [ "$rc" -eq 0 ] || finish "$rc" "大陆白名单更新失败" - finish 0 "大陆白名单更新完成" -} - -run_geoip_update() { - log "正在更新 GeoIP / GeoSite" - touch /var/run/geoip_update - sh /usr/share/clashoo/update/geoip.sh >/tmp/geoip_update.txt 2>&1 - rc=$? - rm -f /var/run/geoip_update - tail -8 /tmp/geoip_update.txt 2>/dev/null | while IFS= read -r line; do - [ -n "$line" ] && log "$line" - done - [ "$rc" -eq 0 ] || finish "$rc" "GeoIP / GeoSite 更新失败" - finish 0 "GeoIP / GeoSite 更新完成" -} - -COMPONENT="${1:-}" -VARIANT="${2:-}" # mihomo/singbox: stable | alpha -[ -n "$COMPONENT" ] || { - echo "usage: $0 [stable|alpha]" - exit 2 -} - -mkdir -p "$(dirname "$RUN_FILE")" >/dev/null 2>&1 -printf '%s\n' "$COMPONENT" >"$RUN_FILE" -STATUS="running" -log "组件更新任务启动:${COMPONENT}${VARIANT:+ ($VARIANT)}" - -case "$COMPONENT" in - clashoo) run_pkg_update clashoo ;; - luci) run_pkg_update luci ;; - mihomo) - if [ "$VARIANT" = "alpha" ]; then run_core_update 3 "mihomo Alpha 版" - else run_core_update 2 "mihomo 稳定版"; fi ;; - singbox) - if [ "$VARIANT" = "alpha" ]; then run_core_update 5 "sing-box Alpha 版" - else run_core_update 4 "sing-box 稳定版"; fi ;; - smart) run_core_update 1 "mihomo Smart 版" ;; - lgbm) run_lgbm_update ;; - china) run_china_update ;; - geoip) run_geoip_update ;; - *) finish 2 "未知组件:${COMPONENT}" ;; -esac diff --git a/clashoo/files/usr/share/clashoo/update/core_download.sh b/clashoo/files/usr/share/clashoo/update/core_download.sh deleted file mode 100755 index 9407fd1a..00000000 --- a/clashoo/files/usr/share/clashoo/update/core_download.sh +++ /dev/null @@ -1,1233 +0,0 @@ -#!/bin/sh - -LOG_FILE="/tmp/clash_update.txt" -MODELTYPE=$(uci get clashoo.config.download_core 2>/dev/null) -# When invoked with a target dcore arg (the component "core update" button), -# download that core WITHOUT switching the active kernel — see finalize(). -# No arg = legacy callers (manual download_core RPC / boot) use the active dcore. -TARGET_DCORE="$1" -CORETYPE=${TARGET_DCORE:-$(uci get clashoo.config.dcore 2>/dev/null)} -MIRROR_PREFIX=$(uci get clashoo.config.core_mirror_prefix 2>/dev/null) -CUSTOM_CORE_URL=$(uci get clashoo.config.core_download_url 2>/dev/null) -SINGBOX_STABLE_TARGET="${CLASHOO_SINGBOX_STABLE_TARGET:-/usr/share/clashoo/bin/sing-box-stable}" -SINGBOX_ALPHA_TARGET="${CLASHOO_SINGBOX_ALPHA_TARGET:-/usr/share/clashoo/bin/sing-box-alpha}" -SINGBOX_TMP_TEMPLATE="${CLASHOO_SINGBOX_TMP_TEMPLATE:-/tmp/clashoo-singbox.XXXXXX}" -CORE_DOWNLOAD_LOCK_DIR="${CLASHOO_CORE_DOWNLOAD_LOCK_DIR:-/var/lock/clashoo-core-download.lock}" -CORE_DOWNLOAD_LOCK_HELD=0 -CORE_INSTALLED=0 -CONNECT_TIMEOUT=15 -REQUEST_TIMEOUT=30 -DOWNLOAD_TIMEOUT=60 -LOW_SPEED_TIME=15 -LOW_SPEED_LIMIT=32768 -ATTEMPTS_PER_MIRROR=1 -MAX_TOTAL_SECONDS=200 -TAG_FETCH_RETRIES=2 -START_TS=$(date +%s) - -write_log() { - echo " $(date "+%Y-%m-%d %H:%M:%S") - $1" >> "$LOG_FILE" -} - -core_download_pid_alive() { - local pid - pid="$1" - [ -d "/proc/$pid" ] && return 0 - kill -0 "$pid" >/dev/null 2>&1 -} - -acquire_core_download_lock() { - local owner parent - parent="$(dirname "$CORE_DOWNLOAD_LOCK_DIR")" - mkdir -p "$parent" >/dev/null 2>&1 || return 1 - while :; do - if mkdir "$CORE_DOWNLOAD_LOCK_DIR" 2>/dev/null; then - printf '%s\n' "$$" > "$CORE_DOWNLOAD_LOCK_DIR/pid" || { - rmdir "$CORE_DOWNLOAD_LOCK_DIR" >/dev/null 2>&1 || true - return 1 - } - CORE_DOWNLOAD_LOCK_HELD=1 - return 0 - fi - - if [ ! -e "$CORE_DOWNLOAD_LOCK_DIR/pid" ]; then - # A fresh owner creates the directory before writing its PID. Only - # remove an actually empty directory; otherwise treat it as busy. - if rmdir "$CORE_DOWNLOAD_LOCK_DIR" >/dev/null 2>&1; then - continue - fi - return 1 - fi - owner="$(sed -n '1p' "$CORE_DOWNLOAD_LOCK_DIR/pid" 2>/dev/null)" - case "$owner" in - '' ) return 1 ;; - *[!0-9]*) - rm -f "$CORE_DOWNLOAD_LOCK_DIR/pid" >/dev/null 2>&1 || return 1 - rmdir "$CORE_DOWNLOAD_LOCK_DIR" >/dev/null 2>&1 || return 1 - ;; - *) - if core_download_pid_alive "$owner"; then - return 1 - fi - rm -f "$CORE_DOWNLOAD_LOCK_DIR/pid" >/dev/null 2>&1 || return 1 - rmdir "$CORE_DOWNLOAD_LOCK_DIR" >/dev/null 2>&1 || return 1 - ;; - esac - done -} - -release_core_download_lock() { - local owner - [ "$CORE_DOWNLOAD_LOCK_HELD" = "1" ] || return 0 - owner="$(sed -n '1p' "$CORE_DOWNLOAD_LOCK_DIR/pid" 2>/dev/null)" - if [ "$owner" = "$$" ]; then - rm -f "$CORE_DOWNLOAD_LOCK_DIR/pid" >/dev/null 2>&1 - rmdir "$CORE_DOWNLOAD_LOCK_DIR" >/dev/null 2>&1 || true - fi - CORE_DOWNLOAD_LOCK_HELD=0 -} - -finalize() { - if [ "$CORE_INSTALLED" = "1" ]; then - if [ -n "$TARGET_DCORE" ]; then - # "core update" path: only refresh the binary. Apply (restart) only - # when we updated the kernel that is actually running, so updating - # smart / sing-box never hijacks the active kernel — and updating - # several cores doesn't rotate through a restart for each. Switching - # kernels stays a separate user action (set_core handles strategy). - if [ "$TARGET_DCORE" = "$(uci get clashoo.config.dcore 2>/dev/null)" ]; then - write_log "当前内核已更新,重启 Clashoo 生效" - if [ "$(uci -q get clashoo.config.enable 2>/dev/null)" = "1" ]; then - /etc/init.d/clashoo restart >/dev/null 2>&1 || write_log "重启 Clashoo 失败" - fi - else - write_log "内核二进制已更新(非当前内核,不切换、不重启)" - fi - else - # legacy callers (manual download_core RPC / boot): unchanged behavior - if [ "$CORETYPE" = "1" ]; then - uci set clashoo.config.core_type="mihomo" 2>/dev/null - uci set clashoo.config.smart_auto_switch="1" 2>/dev/null - uci commit clashoo 2>/dev/null - write_log "Smart 内核已就绪,自动启用 Smart 策略" - fi - write_log "内核已替换,重启 Clashoo" - if [ "$(uci -q get clashoo.config.enable 2>/dev/null)" = "1" ]; then - /etc/init.d/clashoo restart >/dev/null 2>&1 || write_log "重启 Clashoo 失败" - fi - fi - fi - rm -f /var/run/core_update >/dev/null 2>&1 - release_core_download_lock -} - -timed_out() { - now_ts=$(date +%s) - [ $((now_ts - START_TS)) -ge "$MAX_TOTAL_SECONDS" ] -} - -ensure_not_timed_out() { - if timed_out; then - write_log "下载超时(超过 ${MAX_TOTAL_SECONDS} 秒)" - return 1 - fi - return 0 -} - -normalize_prefix() { - p="$1" - [ -z "$p" ] && return - case "$p" in - */) printf '%s\n' "$p" ;; - *) printf '%s/\n' "$p" ;; - esac -} - -mirror_prefixes() { - # 默认源按 2026-04 实测排序:mirror.ghproxy.com 已挂、hub.gitmirror.com/git.886.be 全死、 - # gh.idayer.com/ghproxy.net 限速截断;只保留 gh-proxy.com + ghfast.top 两条快通道。 - # 末尾会自动追加裸 GitHub(download_with_mirrors 末尾会 push 一个空 prefix)。 - custom="$(normalize_prefix "$MIRROR_PREFIX")" - prefixes="" - for prefix in "$custom" "https://gh-proxy.com/" "https://ghfast.top/"; do - [ -n "$prefix" ] || continue - case " $prefixes " in - *" $prefix "*) ;; - *) prefixes="${prefixes}${prefixes:+ }${prefix}" ;; - esac - done - printf '%s\n' "$prefixes" -} - -prefixed_url() { - prefix="$1" - base_url="$2" - if [ -z "$prefix" ]; then - echo "$base_url" - else - echo "${prefix}${base_url}" - fi -} - -fetch_url_try() { - url="$1" - if command -v curl >/dev/null 2>&1; then - curl -fsSL --connect-timeout "$CONNECT_TIMEOUT" --max-time "$REQUEST_TIMEOUT" -A "Clash/OpenWRT" "$url" - return $? - fi - if command -v wget >/dev/null 2>&1; then - wget -qO- --timeout="$CONNECT_TIMEOUT" --user-agent="Clash/OpenWRT" "$url" - return $? - fi - return 127 -} - -# Route core downloads through the running core in kernel-only mode (shared -# logic in proxy_lib.sh: handles smart core + sing-box's own profile port). -if [ "${CLASHOO_CORE_DOWNLOAD_LIB_ONLY:-0}" = "1" ]; then - detect_proxy() { :; } -else - . /usr/share/clashoo/update/proxy_lib.sh - detect_proxy() { clashoo_detect_proxy; } -fi - -download_file_try() { - url="$1" - out="$2" - proxy="$3" - if command -v curl >/dev/null 2>&1; then - if [ -n "$proxy" ]; then - curl -fsSL --connect-timeout "$CONNECT_TIMEOUT" --max-time "$DOWNLOAD_TIMEOUT" --speed-time "$LOW_SPEED_TIME" --speed-limit "$LOW_SPEED_LIMIT" --retry 0 -A "Clash/OpenWRT" --proxy "$proxy" "$url" -o "$out" - else - curl -fsSL --connect-timeout "$CONNECT_TIMEOUT" --max-time "$DOWNLOAD_TIMEOUT" --speed-time "$LOW_SPEED_TIME" --speed-limit "$LOW_SPEED_LIMIT" --retry 0 -A "Clash/OpenWRT" "$url" -o "$out" - fi - return $? - fi - if command -v wget >/dev/null 2>&1; then - wget -q --timeout="$REQUEST_TIMEOUT" --user-agent="Clash/OpenWRT" "$url" -O "$out" - return $? - fi - return 127 -} - -head_url_try() { - url="$1" - if command -v curl >/dev/null 2>&1; then - curl -fsSIL --connect-timeout "$CONNECT_TIMEOUT" --max-time "$REQUEST_TIMEOUT" -A "Clash/OpenWRT" "$url" >/dev/null 2>&1 - return $? - fi - wget -q --spider --timeout="$CONNECT_TIMEOUT" --user-agent="Clash/OpenWRT" "$url" -} - -map_mihomo_arch() { - # 上游 amd64 默认 v3 微架构(要 AVX2)跑不起来;default 给 compatible 兜底 - case "$1" in - amd64-compatible) echo "linux-amd64-compatible" ;; - amd64-v1) echo "linux-amd64-v1" ;; - amd64-v2) echo "linux-amd64-v2" ;; - amd64-v3) echo "linux-amd64-v3" ;; - amd64|x86_64) echo "linux-amd64-compatible" ;; - arm64|aarch64*) echo "linux-arm64" ;; - armv7|arm_cortex-a[7-9]*|arm_cortex-a1[0-9]*) echo "linux-armv7" ;; - armv6|arm_cortex-a[56]*|arm_arm1176*) echo "linux-armv6" ;; - armv5|arm_cortex-a5*|arm_arm926*) echo "linux-armv5" ;; - 386|i[3-6]86|i386*) echo "linux-386" ;; - mipsle|mipsel_24kc) echo "linux-mipsle-softfloat" ;; - mips|mips_24kc) echo "linux-mips-softfloat" ;; - mips64le|mips64el_mips64r2) echo "linux-mips64le" ;; - mips64|mips64_mips64r2) echo "linux-mips64" ;; - riscv64) echo "linux-riscv64" ;; - *) echo "linux-amd64-compatible" ;; - esac -} - -map_singbox_arch() { - case "$1" in - amd64|amd64-compatible|amd64-v1|amd64-v2|amd64-v3) echo "amd64" ;; - arm64|aarch64*) echo "arm64" ;; - armv7|arm_cortex-a[7-9]*|arm_cortex-a1[0-9]*) echo "armv7" ;; - armv6|arm_cortex-a[56]*|arm_arm1176*) echo "armv6" ;; - armv5|arm_cortex-a5*|arm_arm926*) echo "armv5" ;; - 386|i[3-6]86|i386*) echo "386" ;; - mips|mips_24kc) echo "mips" ;; - mipsle|mipsel_24kc) echo "mipsle" ;; - mips64|mips64_mips64r2) echo "mips64" ;; - mips64le|mips64el_mips64r2) echo "mips64le" ;; - riscv64) echo "riscv64" ;; - *) echo "amd64" ;; - esac -} - -map_openwrt_arch() { - case "$1" in - amd64|amd64-compatible|amd64-v1|amd64-v2|amd64-v3|x86_64) echo "x86_64" ;; - arm64) echo "aarch64_generic" ;; - armv7) echo "arm_cortex-a7_neon-vfpv4" ;; - armv6) echo "arm_arm1176jzf-s_vfp" ;; - armv5) echo "arm_arm926ej-s" ;; - 386) echo "i386_pentium4" ;; - mipsle) echo "mipsel_24kc" ;; - mips) echo "mips_24kc" ;; - mips64le) echo "mips64el_mips64r2" ;; - mips64) echo "mips64_mips64r2" ;; - *) echo "" ;; - esac -} - -# Auto-detect normalized arch (MODELTYPE format) from the running device. -# Tries opkg → DISTRIB_ARCH → apk --print-arch → uname -m. -# Normalizes to MODELTYPE format (same vocabulary as luci.clashoo and system.js). -_auto_detect_modeltype() { - local raw norm - if command -v opkg >/dev/null 2>&1; then - raw="$(opkg print-architecture 2>/dev/null | awk '$1=="arch" && $2!="all" && $2!="noarch" {a=$2} END{print a}')" - fi - if [ -z "$raw" ] && [ -r /etc/openwrt_release ]; then - raw="$(sed -n "s/^DISTRIB_ARCH=['\"]\\([^'\"]*\\)['\"]$/\\1/p" /etc/openwrt_release | head -n 1)" - fi - if [ -z "$raw" ] && command -v apk >/dev/null 2>&1; then - raw="$(apk --print-arch 2>/dev/null)" - fi - [ -z "$raw" ] && raw="$(uname -m 2>/dev/null)" - [ -z "$raw" ] && return 1 - case "$raw" in - x86_64|amd64) norm="amd64-compatible" ;; - aarch64*|arm64) norm="arm64" ;; - armv7*|arm_cortex-a[7-9]*|arm_cortex-a1[0-9]*) norm="armv7" ;; - armv6*|arm_cortex-a[56]*|arm_arm1176*) norm="armv6" ;; - armv5*|arm_cortex-a5*|arm_arm926*) norm="armv5" ;; - arm*) norm="armv5" ;; - i[3-6]86|i386*) norm="386" ;; - mips64el*) norm="mips64le" ;; - mips64*) norm="mips64" ;; - mipsel*) norm="mipsle" ;; - mips*) norm="mips" ;; - riscv64*) norm="riscv64" ;; - esac - [ -z "$norm" ] && return 1 - echo "$norm" - return 0 -} - -_is_amd64_arch() { - case "$1" in - amd64-compatible|amd64-v1|amd64-v2|amd64-v3) return 0 ;; - *) return 1 ;; - esac -} - -append_unique_line() { - list="$1" - line="$2" - [ -z "$line" ] && { - printf '%s' "$list" - return - } - case " -$list -" in - *" -$line -"*) - printf '%s' "$list" - ;; - *) - if [ -n "$list" ]; then - printf '%s\n%s' "$list" "$line" - else - printf '%s' "$line" - fi - ;; - esac -} - -pick_highest_stable_tag() { - printf '%s\n' "$1" | sed '/^$/d;s/\r$//' | grep -E '^v[0-9]+([.][0-9]+){1,3}$' | sort -V | tail -n 1 -} - -pick_highest_prerelease_tag() { - printf '%s\n' "$1" | sed '/^$/d;s/\r$//' | grep -E '^v[0-9]+([.][0-9]+){1,3}-[0-9A-Za-z.-]+$' | sort -V | tail -n 1 -} - -extract_release_tags_by_prerelease() { - payload="$1" - is_prerelease="$2" - - if command -v jsonfilter >/dev/null 2>&1; then - printf '%s' "$payload" | jsonfilter -e "@[@.prerelease=${is_prerelease}].tag_name" 2>/dev/null - return - fi - - tags="$(printf '%s' "$payload" | grep -o '"tag_name"[[:space:]]*:[[:space:]]*"[^"]*"' | sed 's/.*"tag_name"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/')" - flags="$(printf '%s' "$payload" | grep -o '"prerelease"[[:space:]]*:[[:space:]]*[a-z]*' | sed 's/.*:[[:space:]]*//')" - [ -z "$tags" ] && return - [ -z "$flags" ] && return - - tags_file="/tmp/clashoo-tags-$$" - flags_file="/tmp/clashoo-pre-$$" - printf '%s\n' "$tags" > "$tags_file" - printf '%s\n' "$flags" > "$flags_file" - awk -v want="$is_prerelease" 'NR==FNR { t[FNR]=$0; next } $0==want { print t[FNR] }' "$tags_file" "$flags_file" - rm -f "$tags_file" "$flags_file" >/dev/null 2>&1 -} - -detect_openwrt_arch() { - local arch - if command -v opkg >/dev/null 2>&1; then - arch="$(opkg print-architecture 2>/dev/null | awk '$1=="arch" && $2!="all" && $2!="noarch" {a=$2} END{print a}')" - [ -n "$arch" ] && { echo "$arch"; return 0; } - fi - # DISTRIB_ARCH is authoritative for OpenWrt package arch naming. - # apk --print-arch may return "aarch64" while sing-box release assets - # use the full sub-arch (e.g. aarch64_generic / aarch64_cortex-a53). - if [ -r /etc/openwrt_release ]; then - arch="$(sed -n "s/^DISTRIB_ARCH=['\"]\\([^'\"]*\\)['\"]$/\\1/p" /etc/openwrt_release | head -n 1)" - [ -n "$arch" ] && { echo "$arch"; return 0; } - fi - if command -v apk >/dev/null 2>&1; then - arch="$(apk --print-arch 2>/dev/null)" - [ -n "$arch" ] && { echo "$arch"; return 0; } - fi - map_openwrt_arch "$MODELTYPE" -} - -singbox_target_path() { - case "$CORETYPE" in - 5) printf '%s\n' "$SINGBOX_ALPHA_TARGET" ;; - *) printf '%s\n' "$SINGBOX_STABLE_TARGET" ;; - esac -} - -extract_tar_file() { - local archive dest - archive="$1" - dest="$2" - case "$archive" in - *.gz) tar -xzf "$archive" -C "$dest" >/dev/null 2>&1 ;; - *.xz) tar -xJf "$archive" -C "$dest" >/dev/null 2>&1 || tar -xf "$archive" -C "$dest" >/dev/null 2>&1 ;; - *.zst) - if command -v unzstd >/dev/null 2>&1; then - unzstd -c "$archive" 2>/dev/null | tar -xf - -C "$dest" >/dev/null 2>&1 - elif command -v zstd >/dev/null 2>&1; then - zstd -dc "$archive" 2>/dev/null | tar -xf - -C "$dest" >/dev/null 2>&1 - else - return 1 - fi - ;; - *) tar -xf "$archive" -C "$dest" >/dev/null 2>&1 || tar -xzf "$archive" -C "$dest" >/dev/null 2>&1 ;; - esac -} - -extract_ar_data_tar() { - local archive dest offset name size member - archive="$1" - dest="$2" - offset=8 - [ "$(dd if="$archive" bs=8 count=1 2>/dev/null)" = '!' ] || return 1 - while :; do - # Read fixed-width ar fields directly. Do not put the full 60-byte - # header in command substitution: shell command substitution strips - # trailing newlines/spaces and makes length checks unreliable in ash. - name="$(dd if="$archive" bs=1 skip="$offset" count=16 2>/dev/null | sed 's/[[:space:]].*$//')" - name="${name%/}" - size="$(dd if="$archive" bs=1 skip=$((offset + 48)) count=10 2>/dev/null | tr -d '[:space:]')" - case "$size" in - ''|*[!0-9]*) return 1 ;; - esac - member="$dest/$name" - case "$name" in - data.tar.*) - dd if="$archive" of="$member" bs=1 skip=$((offset + 60)) count="$size" 2>/dev/null || return 1 - printf '%s\n' "$member" - return 0 - ;; - esac - offset=$((offset + 60 + size)) - [ $((offset % 2)) -eq 0 ] || offset=$((offset + 1)) - done -} - -extract_singbox_payload() { - local pkg rootdir outer workdir payload data_tar candidate - pkg="$1" - rootdir="$2" - outer="${rootdir}.outer" - workdir="$(dirname "$rootdir")" - payload="$workdir/sing-box.payload" - data_tar="" - rm -f "$payload" 2>/dev/null - rm -rf "$rootdir" "$outer" 2>/dev/null - if ! mkdir -p "$rootdir" "$outer"; then - rm -rf "$rootdir" "$outer" 2>/dev/null - return 1 - fi - - # IPK assets are ar/tar containers with a compressed data.tar.* member; - # official fallback archives contain sing-box directly below a version dir. - if tar -tf "$pkg" 2>/dev/null | grep -Eq '(^|/)data\.tar\.(gz|xz|zst)$'; then - extract_tar_file "$pkg" "$outer" || { - rm -rf "$rootdir" "$outer" 2>/dev/null - return 1 - } - for candidate in "$outer"/data.tar.*; do - [ -f "$candidate" ] || continue - data_tar="$candidate" - break - done - if [ -z "$data_tar" ] || ! extract_tar_file "$data_tar" "$rootdir"; then - rm -rf "$rootdir" "$outer" 2>/dev/null - return 1 - fi - else - data_tar="$(extract_ar_data_tar "$pkg" "$outer" 2>/dev/null || true)" - if [ -n "$data_tar" ]; then - if ! extract_tar_file "$data_tar" "$rootdir"; then - rm -rf "$rootdir" "$outer" 2>/dev/null - return 1 - fi - else - if ! extract_tar_file "$pkg" "$rootdir"; then - rm -rf "$rootdir" "$outer" 2>/dev/null - return 1 - fi - fi - fi - - candidate="$(find "$rootdir" -type f -name sing-box 2>/dev/null | head -n 1)" - if [ -n "$candidate" ] && [ -f "$candidate" ]; then - if ! cp -f "$candidate" "$payload"; then - rm -rf "$rootdir" "$outer" 2>/dev/null - return 1 - fi - rm -rf "$rootdir" "$outer" 2>/dev/null - printf '%s\n' "$payload" - return 0 - fi - rm -rf "$rootdir" "$outer" 2>/dev/null - return 1 -} - -cleanup_singbox_extract_workdir() { - local workdir rootdir - workdir="$1" - rootdir="$workdir/root" - rm -rf "$rootdir" "${rootdir}.outer" "$workdir" 2>/dev/null -} - -install_singbox_openwrt_asset() { - local pkg target workdir rootdir bin extract_rc rc - pkg="$1" - target="${2:-$(singbox_target_path)}" - workdir="$(mktemp -d "$SINGBOX_TMP_TEMPLATE" 2>/dev/null)" || return 1 - rootdir="$workdir/root" - bin="$(extract_singbox_payload "$pkg" "$rootdir")" - extract_rc=$? - if [ "$extract_rc" -eq 0 ]; then - install_with_rollback "$bin" "$target" "${VER:-}" - rc=$? - else - rc=1 - fi - cleanup_singbox_extract_workdir "$workdir" - return "$rc" -} - -install_singbox_tar_asset() { - local archive target workdir rootdir bin extract_rc rc - archive="$1" - target="${2:-$(singbox_target_path)}" - workdir="$(mktemp -d "$SINGBOX_TMP_TEMPLATE" 2>/dev/null)" || return 1 - rootdir="$workdir/root" - bin="$(extract_singbox_payload "$archive" "$rootdir")" - extract_rc=$? - if [ "$extract_rc" -eq 0 ]; then - install_with_rollback "$bin" "$target" "${VER:-}" - rc=$? - else - rc=1 - fi - cleanup_singbox_extract_workdir "$workdir" - return "$rc" -} - -fetch_latest_tag() { - repo="$1" - api_url="https://api.github.com/repos/${repo}/releases/latest" - list_api="https://api.github.com/repos/${repo}/releases?per_page=100" - web_url="https://github.com/${repo}/releases/latest" - candidates="" - - # Fast path: prefer official GitHub API first to avoid stale mirror cache. - p="" - ensure_not_timed_out || return 1 - u="$(prefixed_url "$p" "$api_url")" - i=1 - while [ "$i" -le "$TAG_FETCH_RETRIES" ]; do - ensure_not_timed_out || return 1 - tag="$(fetch_url_try "$u" | sed -n 's/.*"tag_name"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' | head -n 1)" - case "$tag" in - v*[-]*) - : - ;; - *) - [ -n "$tag" ] && echo "$tag" && return 0 - ;; - esac - sleep 1 - i=$((i + 1)) - done - - for p in $(mirror_prefixes); do - ensure_not_timed_out || return 1 - u="$(prefixed_url "$p" "$api_url")" - i=1 - while [ "$i" -le "$TAG_FETCH_RETRIES" ]; do - ensure_not_timed_out || return 1 - tag="$(fetch_url_try "$u" | sed -n 's/.*"tag_name"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' | head -n 1)" - case "$tag" in - v*[-]*) - # stable channel should ignore prerelease-like tags from stale mirrors - : - ;; - *) - candidates="$(append_unique_line "$candidates" "$tag")" - ;; - esac - sleep 1 - i=$((i + 1)) - done - done - - p="" - ensure_not_timed_out || return 1 - u="$(prefixed_url "$p" "$list_api")" - i=1 - while [ "$i" -le "$TAG_FETCH_RETRIES" ]; do - ensure_not_timed_out || return 1 - payload="$({ fetch_url_try "$u" || true; })" - tags="$(extract_release_tags_by_prerelease "$payload" false)" - best="$(pick_highest_stable_tag "$tags")" - [ -n "$best" ] && echo "$best" && return 0 - sleep 1 - i=$((i + 1)) - done - - for p in $(mirror_prefixes); do - ensure_not_timed_out || return 1 - u="$(prefixed_url "$p" "$list_api")" - i=1 - while [ "$i" -le "$TAG_FETCH_RETRIES" ]; do - ensure_not_timed_out || return 1 - payload="$({ fetch_url_try "$u" || true; })" - tags="$(extract_release_tags_by_prerelease "$payload" false)" - for tag in $tags; do - candidates="$(append_unique_line "$candidates" "$tag")" - done - sleep 1 - i=$((i + 1)) - done - done - - for p in $(mirror_prefixes); do - ensure_not_timed_out || return 1 - u="$(prefixed_url "$p" "$web_url")" - i=1 - while [ "$i" -le "$TAG_FETCH_RETRIES" ]; do - ensure_not_timed_out || return 1 - if command -v curl >/dev/null 2>&1; then - tag="$(curl -fsSIL --connect-timeout "$CONNECT_TIMEOUT" --max-time "$REQUEST_TIMEOUT" -A "Clash/OpenWRT" "$u" 2>/dev/null | sed -n 's#^[Ll]ocation: .*/releases/tag/\([^[:space:]\r]*\).*#\1#p' | head -n 1)" - else - tag="$(wget -S --spider --timeout="$CONNECT_TIMEOUT" --user-agent="Clash/OpenWRT" "$u" 2>&1 | sed -n 's#^ Location: .*/releases/tag/\([^[:space:]]*\).*#\1#p' | head -n 1)" - fi - case "$tag" in - v*[-]*) - : - ;; - *) - candidates="$(append_unique_line "$candidates" "$tag")" - ;; - esac - sleep 1 - i=$((i + 1)) - done - done - - releases_url="https://github.com/${repo}/releases" - for p in $(mirror_prefixes); do - ensure_not_timed_out || return 1 - u="$(prefixed_url "$p" "$releases_url")" - tag="$(fetch_url_try "$u" | sed -n 's#.*releases/tag/\(v[0-9][^\"/?]*\).*#\1#p' | head -n 1)" - case "$tag" in - v*[-]*) - : - ;; - *) - candidates="$(append_unique_line "$candidates" "$tag")" - ;; - esac - done - - # 终极兜底:直连 GitHub 爬取 releases 页面(镜像都失效时备用) - ensure_not_timed_out || return 1 - p="" - u="$(prefixed_url "$p" "$releases_url")" - tag="$(fetch_url_try "$u" 2>/dev/null | sed -n 's#.*releases/tag/\(v[0-9][^"/?]*\).*#\1#p' | head -n 1)" - case "$tag" in - v*[-]*) - ;; - *) - [ -n "$tag" ] && { echo "$tag"; return 0; } - ;; - esac - # 再试一次 releases/latest 的 302 跳转 - u="$(prefixed_url "$p" "$web_url")" - if command -v curl >/dev/null 2>&1; then - tag="$(curl -fsSIL --connect-timeout "$CONNECT_TIMEOUT" --max-time "$REQUEST_TIMEOUT" -A "Clash/OpenWRT" "$u" 2>/dev/null | sed -n 's#^[Ll]ocation: .*/releases/tag/\([^[:space:][:cntrl:]]*\).*#\1#p' | head -n 1)" - else - tag="$(wget -S --spider --timeout="$CONNECT_TIMEOUT" --user-agent="Clash/OpenWRT" "$u" 2>&1 | sed -n 's#^ Location: .*/releases/tag/\([^[:space:]]*\).*#\1#p' | head -n 1)" - fi - [ -n "$tag" ] && { echo "$tag"; return 0; } - -best="$(pick_highest_stable_tag "$candidates")" - [ -n "$best" ] && { - echo "$best" - return 0 - } - fallback="$(printf '%s\n' "$candidates" | sed '/^$/d' | head -n 1)" - [ -n "$fallback" ] && { - echo "$fallback" - return 0 - } - - return 1 -} - -fetch_prerelease_tag() { - repo="$1" - api_url="https://api.github.com/repos/${repo}/releases?per_page=100" - candidates="" - - # Fast path: official GitHub API first. - p="" - ensure_not_timed_out || return 1 - u="$(prefixed_url "$p" "$api_url")" - i=1 - while [ "$i" -le "$TAG_FETCH_RETRIES" ]; do - ensure_not_timed_out || return 1 - payload="$({ fetch_url_try "$u" || true; })" - tags="$(extract_release_tags_by_prerelease "$payload" true)" - best="$(pick_highest_prerelease_tag "$tags")" - [ -n "$best" ] && echo "$best" && return 0 - sleep 1 - i=$((i + 1)) - done - - for p in $(mirror_prefixes); do - ensure_not_timed_out || return 1 - u="$(prefixed_url "$p" "$api_url")" - i=1 - while [ "$i" -le "$TAG_FETCH_RETRIES" ]; do - ensure_not_timed_out || return 1 - payload="$({ fetch_url_try "$u" || true; })" - tags="$(extract_release_tags_by_prerelease "$payload" true)" - for tag in $tags; do - candidates="$(append_unique_line "$candidates" "$tag")" - done - sleep 1 - i=$((i + 1)) - done - done - - best="$(pick_highest_prerelease_tag "$candidates")" - [ -n "$best" ] && { - echo "$best" - return 0 - } - fallback="$(printf '%s\n' "$candidates" | sed '/^$/d' | head -n 1)" - [ -n "$fallback" ] && { - echo "$fallback" - return 0 - } - - return 1 -} - -fetch_expanded_asset_names() { - repo="$1" - tag="$2" - url="https://github.com/${repo}/releases/expanded_assets/${tag}" - - for p in $(mirror_prefixes) ""; do - ensure_not_timed_out || return 1 - u="$(prefixed_url "$p" "$url")" - assets="$(fetch_url_try "$u" | sed -n "s#.*releases/download/${tag}/\\([^\\\"?]*\\)\\\".*#\\1#p")" - [ -n "$assets" ] && printf '%s\n' "$assets" && return 0 - done - - return 1 -} - -pick_reachable_release_url() { - base_url="$1" - for p in $(mirror_prefixes) ""; do - ensure_not_timed_out || return 1 - u="$(prefixed_url "$p" "$base_url")" - if head_url_try "$u"; then - echo "$u" - return 0 - fi - done - return 1 -} - -pick_mihomo_asset_by_url() { - repo="$1" - tag="$2" - arch="$3" - channel="$4" - ver="${tag#v}" - candidates="" - - if [ "$channel" = "alpha" ] || [ "$channel" = "smart" ]; then - if [ "$arch" = "linux-amd64" ]; then - if [ "$channel" = "smart" ]; then - candidates="mihomo-linux-amd64-alpha-smart-*.gz mihomo-linux-amd64-compatible-alpha-smart-*.gz" - else - candidates="mihomo-linux-amd64-alpha-*.gz mihomo-linux-amd64-compatible-alpha-*.gz" - fi - else - [ "$channel" = "smart" ] && candidates="mihomo-${arch}-alpha-smart-*.gz" || candidates="mihomo-${arch}-alpha-*.gz" - fi - assets_html="$(fetch_expanded_asset_names "$repo" "$tag")" - if [ -n "$assets_html" ]; then - for a in $(printf '%s\n' "$assets_html"); do - for pat in $candidates; do - case "$a" in - $pat) - u="https://github.com/${repo}/releases/download/${tag}/${a}" - if pick_reachable_release_url "$u" >/dev/null 2>&1; then - echo "$a" - return 0 - fi - ;; - esac - done - done - fi - return 1 - fi - - if [ "$arch" = "linux-amd64" ]; then - candidates="mihomo-linux-amd64-v${ver}.gz mihomo-linux-amd64-compatible-v${ver}.gz" - else - candidates="mihomo-${arch}-v${ver}.gz" - fi - - for a in $candidates; do - u="https://github.com/${repo}/releases/download/${tag}/${a}" - if pick_reachable_release_url "$u" >/dev/null 2>&1; then - echo "$a" - return 0 - fi - done - - return 1 -} - -download_with_mirrors() { - base_url="$1" - outfile="$2" - verify_mode="${3:-gzip}" - proxy="$(detect_proxy)" - if [ -n "$proxy" ]; then - download_prefixes="__direct__ $(mirror_prefixes)" - else - download_prefixes="$(mirror_prefixes) __direct__" - fi - for p in $download_prefixes; do - [ "$p" = "__direct__" ] && p="" - ensure_not_timed_out || return 1 - u="$(prefixed_url "$p" "$base_url")" - i=1 - while [ "$i" -le "$ATTEMPTS_PER_MIRROR" ]; do - ensure_not_timed_out || return 1 - write_log "Downloading from ${u}" - rm -f "$outfile" 2>/dev/null - if download_file_try "$u" "$outfile" "$proxy"; then - case "$verify_mode" in - raw) - if [ -s "$outfile" ]; then - return 0 - fi - write_log "Downloaded file is empty from ${u}" - ;; - *) - if gzip -t "$outfile" >/dev/null 2>&1; then - return 0 - fi - write_log "Downloaded file is invalid gzip from ${u}" - ;; - esac - fi - sleep 1 - i=$((i + 1)) - done - done - return 1 -} - -pick_mihomo_asset() { - repo="$1" - tag="$2" - arch="$3" - channel="$4" - ver="${tag#v}" - candidates="" - release_assets="$(fetch_expanded_asset_names "$repo" "$tag")" - [ -z "$release_assets" ] && pick_mihomo_asset_by_url "$repo" "$tag" "$arch" "$channel" && return 0 - [ -z "$release_assets" ] && return 1 - - if [ "$channel" = "alpha" ] || [ "$channel" = "smart" ]; then - if [ "$arch" = "linux-amd64" ]; then - if [ "$channel" = "smart" ]; then - asset="$(printf '%s\n' "$release_assets" | sed -n 's#^\(mihomo-linux-amd64-alpha-smart-[0-9a-fA-F]\{7,\}\.gz\)$#\1#p' | head -n 1)" - [ -z "$asset" ] && asset="$(printf '%s\n' "$release_assets" | sed -n 's#^\(mihomo-linux-amd64-compatible-alpha-smart-[0-9a-fA-F]\{7,\}\.gz\)$#\1#p' | head -n 1)" - else - asset="$(printf '%s\n' "$release_assets" | sed -n 's#^\(mihomo-linux-amd64-alpha-[0-9a-fA-F]\{7,\}\.gz\)$#\1#p' | head -n 1)" - [ -z "$asset" ] && asset="$(printf '%s\n' "$release_assets" | sed -n 's#^\(mihomo-linux-amd64-compatible-alpha-[0-9a-fA-F]\{7,\}\.gz\)$#\1#p' | head -n 1)" - fi - else - if [ "$channel" = "smart" ]; then - asset="$(printf '%s\n' "$release_assets" | sed -n "s#^\\(mihomo-${arch}-alpha-smart-[0-9a-fA-F]\\{7,\\}\\.gz\\)$#\\1#p" | head -n 1)" - else - asset="$(printf '%s\n' "$release_assets" | sed -n "s#^\\(mihomo-${arch}-alpha-[0-9a-fA-F]\\{7,\\}\\.gz\\)$#\\1#p" | head -n 1)" - fi - fi - [ -n "$asset" ] && echo "$asset" && return 0 - pick_mihomo_asset_by_url "$repo" "$tag" "$arch" "$channel" - return $? - fi - - if [ "$arch" = "linux-amd64" ]; then - candidates="mihomo-linux-amd64-v${ver}.gz mihomo-linux-amd64-compatible-v${ver}.gz" - else - candidates="mihomo-${arch}-v${ver}.gz" - fi - - for a in $candidates; do - if printf '%s\n' "$release_assets" | grep -qx "$a"; then - echo "$a" - return 0 - fi - done - - pick_mihomo_asset_by_url "$repo" "$tag" "$arch" "$channel" - return $? - -} - -install_binary() { - local src dst dir staged - src="$1" - dst="$2" - dir="$(dirname "$dst")" - staged="$dir/.$(basename "$dst").tmp.$$" - mkdir -p "$dir" || return 1 - rm -f "$staged" - cp -f "$src" "$staged" || { - rm -f "$staged" - return 1 - } - chmod 755 "$staged" || { - rm -f "$staged" - return 1 - } - mv -f "$staged" "$dst" || { - rm -f "$staged" - return 1 - } -} - -backup_binary() { - dst="$1" - bak="${dst}.bak" - if [ -x "$dst" ]; then - cp -f "$dst" "$bak" 2>/dev/null || true - [ -f "$bak" ] || { write_log "备份旧内核失败(磁盘满?),跳过备份"; } - fi -} - -restore_binary() { - dst="$1" - bak="${dst}.bak" - if [ -f "$bak" ]; then - cp -f "$bak" "$dst" 2>/dev/null || return 1 - chmod 755 "$dst" 2>/dev/null || true - return 0 - fi - return 1 -} - -verify_binary() { - local bin - bin="$1" - [ -x "$bin" ] || return 1 - "$bin" -v >/dev/null 2>&1 && return 0 - "$bin" version >/dev/null 2>&1 && return 0 - return 1 -} - -verify_binary_version() { - local bin expected output actual - bin="$1" - expected="$2" - [ -n "$expected" ] || return 0 - output="$({ "$bin" version 2>/dev/null || "$bin" -v 2>/dev/null; } || true)" - [ -n "$output" ] || return 1 - actual="$(printf '%s\n' "$output" | sed -n 's/^[[:space:]]*sing-box[[:space:]][[:space:]]*version[[:space:]][[:space:]]*\([^[:space:]][^[:space:]]*\).*/\1/p' | head -n 1)" - [ -n "$actual" ] || return 1 - [ "$actual" = "$expected" ] -} - -installed_version_matches() { - version_file="$1" - expected_version="$2" - [ -r "$version_file" ] || return 1 - [ -n "$expected_version" ] || return 1 - [ "$(sed -n '1p' "$version_file" 2>/dev/null)" = "$expected_version" ] -} - -install_with_rollback() { - local tmpfile target expected_version - tmpfile="$1" - target="$2" - expected_version="${3:-}" - - chmod 755 "$tmpfile" 2>/dev/null - if ! verify_binary "$tmpfile" || ! verify_binary_version "$tmpfile" "$expected_version"; then - write_log "新内核预热校验失败,保留当前内核" - rm -f "$tmpfile" 2>/dev/null - return 1 - fi - - backup_binary "$target" - if ! install_binary "$tmpfile" "$target"; then - write_log "内核替换失败,回滚旧版本" - restore_binary "$target" >/dev/null 2>&1 || true - return 1 - fi - - rm -f "${target}.bak" 2>/dev/null - return 0 -} - -# Unit tests source the extraction helpers without entering the normal UCI and -# network download path. This hook has no effect in production execution. -if [ "${CLASHOO_CORE_DOWNLOAD_LIB_ONLY:-0}" = "1" ]; then - return 0 2>/dev/null || exit 0 -fi - -if ! acquire_core_download_lock; then - write_log "已有内核下载任务运行,拒绝并发执行" - exit 1 -fi -trap finalize EXIT - -# UCI template defaults to amd64-compatible. Auto-detect when MODELTYPE -# is missing, or when MODELTYPE is an amd64 variant but the device is not. -if [ -z "$MODELTYPE" ]; then - DETECTED="$(_auto_detect_modeltype)" - if [ -n "$DETECTED" ] && [ "$DETECTED" != "$MODELTYPE" ]; then - write_log "自动识别处理器架构:${DETECTED}" - MODELTYPE="$DETECTED" - uci set clashoo.config.download_core="$DETECTED" 2>/dev/null - uci commit clashoo 2>/dev/null - fi -elif _is_amd64_arch "$MODELTYPE"; then - DETECTED="$(_auto_detect_modeltype)" - if [ -n "$DETECTED" ] && [ "$DETECTED" != "$MODELTYPE" ] && ! _is_amd64_arch "$DETECTED"; then - write_log "UCI 架构为 ${MODELTYPE},但设备检测为 ${DETECTED},自动修正" - MODELTYPE="$DETECTED" - uci set clashoo.config.download_core="$DETECTED" 2>/dev/null - uci commit clashoo 2>/dev/null - fi -fi - -rm -f /tmp/clash.gz /tmp/clash /usr/share/clashoo/core_down_complete 2>/dev/null -touch /var/run/core_update 2>/dev/null -write_log "内核下载任务启动" -write_log "下载架构:${MODELTYPE:-未设置}" - -if [ -n "$CUSTOM_CORE_URL" ]; then - write_log "使用自定义内核下载链接" - URL="$CUSTOM_CORE_URL" - if [ "$CORETYPE" = "3" ]; then - TARGET="/usr/share/clashoo/bin/mihomo-alpha" - VERSION_FILE="/usr/share/clashoo/mihomo_version" - else - TARGET="/usr/share/clashoo/bin/mihomo-stable" - VERSION_FILE="/usr/share/clashoo/clash_meta_version" - fi - TAG="custom" - ASSET="custom" - VERSION_VALUE="custom-url" - - if ! download_file_try "$URL" /tmp/clash.gz "$(detect_proxy)"; then - write_log "自定义链接下载失败" - exit 1 - fi - - if ! gunzip -f /tmp/clash.gz; then - write_log "自定义内核解压失败" - exit 1 - fi - - if ! install_with_rollback /tmp/clash "$TARGET"; then - exit 1 - fi - CORE_INSTALLED=1 - printf '%s\n' "${VERSION_VALUE}" > "$VERSION_FILE" - touch /usr/share/clashoo/core_down_complete - write_log "内核更新完成(自定义链接)" - exit 0 -fi - -if [ "$CORETYPE" = "4" ] || [ "$CORETYPE" = "5" ]; then - SINGBOX_ARCH="$(map_singbox_arch "$MODELTYPE")" - OPENWRT_ARCH="$(detect_openwrt_arch)" - if [ "$CORETYPE" = "4" ]; then - write_log "已选择 sing-box 稳定版" - write_log "正在获取 GitHub Release 信息..." - TAG=$(fetch_latest_tag "SagerNet/sing-box") - [ -z "$TAG" ] && write_log "获取 sing-box 稳定版版本号失败" && exit 1 - else - write_log "已选择 sing-box 预发布版" - write_log "正在获取 GitHub Release 信息..." - TAG=$(fetch_prerelease_tag "SagerNet/sing-box") - [ -z "$TAG" ] && TAG=$(fetch_latest_tag "SagerNet/sing-box") - [ -z "$TAG" ] && write_log "获取 sing-box 预发布版版本号失败" && exit 1 - fi - VER="${TAG#v}" - SINGBOX_TARGET="$(singbox_target_path)" - installed=0 - - if [ -n "$OPENWRT_ARCH" ]; then - ASSET="sing-box_${VER}_openwrt_${OPENWRT_ARCH}.ipk" - URL="https://github.com/SagerNet/sing-box/releases/download/${TAG}/${ASSET}" - write_log "尝试提取 OpenWrt IPK 包: ${ASSET}" - if download_with_mirrors "$URL" /tmp/singbox-openwrt.ipk raw && install_singbox_openwrt_asset /tmp/singbox-openwrt.ipk "$SINGBOX_TARGET"; then - installed=1 - else - write_log "OpenWrt IPK 提取失败,尝试官方 musl tar 包" - fi - fi - - if [ "$installed" -ne 1 ]; then - for ASSET in "sing-box-${VER}-linux-${SINGBOX_ARCH}-musl.tar.gz" "sing-box-${VER}-linux-${SINGBOX_ARCH}.tar.gz"; do - URL="https://github.com/SagerNet/sing-box/releases/download/${TAG}/${ASSET}" - write_log "尝试下载 sing-box 归档包: ${ASSET}" - if download_with_mirrors "$URL" /tmp/singbox.tar.gz gzip && install_singbox_tar_asset /tmp/singbox.tar.gz "$SINGBOX_TARGET"; then - installed=1 - break - fi - done - fi - - if [ "$installed" -ne 1 ]; then - write_log "sing-box 下载或安装失败(可能是架构不匹配)" - exit 1 - fi - - CORE_INSTALLED=1 - # 稳定版与 Alpha 分路径保存,避免互相覆盖;版本文件保持兼容。 - if [ "$CORETYPE" = "4" ]; then - printf '%s\n' "$TAG" > "/usr/share/clashoo/singbox_stable_version" - else - printf '%s\n' "$TAG" > "/usr/share/clashoo/singbox_alpha_version" - fi - printf '%s\n' "$TAG" > "/usr/share/clashoo/singbox_version" - rm -f /tmp/singbox.tar.gz /tmp/singbox-openwrt.ipk - rm -rf /tmp/singbox-extract /tmp/singbox-openwrt-pkg /tmp/singbox-openwrt-root - touch /usr/share/clashoo/core_down_complete - write_log "sing-box 更新完成: $TAG" - exit 0 -fi - -if [ "$CORETYPE" = "1" ]; then - write_log "已选择内核通道:mihomo Smart 版(vernesong fork)" - TAG="Prerelease-Alpha" - write_log "正在获取 GitHub Release 信息..." - ASSET=$(pick_mihomo_asset "vernesong/mihomo" "$TAG" "$(map_mihomo_arch "$MODELTYPE")" "smart") - if [ -z "$ASSET" ]; then - ALT_TAG=$(fetch_prerelease_tag "vernesong/mihomo") - [ -n "$ALT_TAG" ] && TAG="$ALT_TAG" - ASSET=$(pick_mihomo_asset "vernesong/mihomo" "$TAG" "$(map_mihomo_arch "$MODELTYPE")" "smart") - fi - URL="https://github.com/vernesong/mihomo/releases/download/${TAG}/${ASSET}" - TARGET="/usr/bin/smart" - VERSION_FILE="/usr/share/clashoo/mihomo_version" - VERSION_VALUE="smart-$(printf '%s\n' "$ASSET" | sed -n 's#^mihomo-.*-alpha-smart-\([0-9a-fA-F]\{7,\}\)\.gz$#\1#p' | head -n 1)" - [ "$VERSION_VALUE" = "smart-" ] && VERSION_VALUE="smart-${TAG}" -elif [ "$CORETYPE" = "2" ]; then - write_log "已选择内核通道:稳定版" - write_log "正在获取 GitHub Release 信息..." - TAG=$(fetch_latest_tag "MetaCubeX/mihomo") - [ -z "$TAG" ] && write_log "获取稳定版版本号失败" && exit 1 - ASSET=$(pick_mihomo_asset "MetaCubeX/mihomo" "$TAG" "$(map_mihomo_arch "$MODELTYPE")" "stable") - URL="https://github.com/MetaCubeX/mihomo/releases/download/${TAG}/${ASSET}" - TARGET="/usr/share/clashoo/bin/mihomo-stable" - VERSION_FILE="/usr/share/clashoo/clash_meta_version" - VERSION_VALUE="$TAG" -else - write_log "已选择内核通道:预发布版" - TAG="Prerelease-Alpha" - write_log "正在获取 GitHub Release 信息..." - ASSET=$(pick_mihomo_asset "MetaCubeX/mihomo" "$TAG" "$(map_mihomo_arch "$MODELTYPE")" "alpha") - [ -z "$ASSET" ] && TAG=$(fetch_prerelease_tag "MetaCubeX/mihomo") - [ -z "$TAG" ] && TAG=$(fetch_latest_tag "MetaCubeX/mihomo") - [ -z "$TAG" ] && write_log "获取预发布版本号失败" && exit 1 - [ -z "$ASSET" ] && ASSET=$(pick_mihomo_asset "MetaCubeX/mihomo" "$TAG" "$(map_mihomo_arch "$MODELTYPE")" "alpha") - [ -z "$ASSET" ] && ASSET=$(pick_mihomo_asset "MetaCubeX/mihomo" "$TAG" "$(map_mihomo_arch "$MODELTYPE")" "stable") - URL="https://github.com/MetaCubeX/mihomo/releases/download/${TAG}/${ASSET}" - TARGET="/usr/share/clashoo/bin/mihomo-alpha" - VERSION_FILE="/usr/share/clashoo/mihomo_version" - VERSION_VALUE="$(printf '%s\n' "$ASSET" | sed -n 's#^mihomo-.*-alpha-\([0-9a-fA-F]\{7,\}\)\.gz$#\1#p' | head -n 1)" - [ -z "$VERSION_VALUE" ] && VERSION_VALUE="$TAG" -fi - -if [ -z "$TAG" ]; then - write_log "内核版本检查失败" - exit 1 -fi - -if [ -z "$ASSET" ]; then - write_log "未找到对应架构的内核文件(${MODELTYPE:-unknown} / ${TAG:-unknown})" - exit 1 -fi -write_log "版本标签:$TAG" -write_log "匹配内核文件:$ASSET" - -if [ -n "$TARGET_DCORE" ] && installed_version_matches "$VERSION_FILE" "$VERSION_VALUE" && verify_binary "$TARGET"; then - write_log "内核已是最新版本:$VERSION_VALUE" - exit 0 -fi - -write_log "开始下载内核" -if ! download_with_mirrors "$URL" /tmp/clash.gz; then - write_log "内核下载失败:所有镜像源均不可达(已尝试 gh-proxy.com / ghfast.top / 裸 GitHub)" - write_log "可设置自定义镜像前缀:uci set clashoo.config.core_mirror_prefix='https://your.mirror/' && uci commit clashoo" - exit 1 -fi - -if ! gunzip -f /tmp/clash.gz; then - write_log "内核解压失败" - exit 1 -fi - -if ! install_with_rollback /tmp/clash "$TARGET"; then - exit 1 -fi -CORE_INSTALLED=1 -printf '%s\n' "${VERSION_VALUE:-$TAG}" > "$VERSION_FILE" -touch /usr/share/clashoo/core_down_complete -write_log "内核更新完成" diff --git a/clashoo/files/usr/share/clashoo/update/geoip.sh b/clashoo/files/usr/share/clashoo/update/geoip.sh deleted file mode 100755 index 9c699e30..00000000 --- a/clashoo/files/usr/share/clashoo/update/geoip.sh +++ /dev/null @@ -1,282 +0,0 @@ -#!/bin/sh - -LOG_FILE="/tmp/geoip_update.txt" -TMP_DIR="/tmp/clash_geoip_$$" -MMDB_MIN_SIZE=2000000 -GEOSITE_MIN_SIZE=2000000 - -geoip_source="$(uci -q get clashoo.config.geoip_source 2>/dev/null)" -license_key="$(uci -q get clashoo.config.license_key 2>/dev/null)" - -cfg_mmdb_url="$(uci -q get clashoo.config.geoip_mmdb_url 2>/dev/null)" -cfg_geosite_url="$(uci -q get clashoo.config.geosite_url 2>/dev/null)" -cfg_geoip_dat_url="$(uci -q get clashoo.config.geoip_dat_url 2>/dev/null)" -cfg_geoip_asn_url="$(uci -q get clashoo.config.geoip_asn_url 2>/dev/null)" -require_geosite=0 -[ "$1" = "--require-geosite" ] && require_geosite=1 - -DEFAULT_MMDB_URL="https://raw.githubusercontent.com/Loyalsoldier/geoip/release/Country.mmdb" -DEFAULT_GEOSITE_URL="https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/release/geosite.dat" -DEFAULT_GEOIP_DAT_URL="https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/release/geoip.dat" -DEFAULT_GEOIP_ASN_URL="https://github.com/xishang0128/geoip/releases/download/latest/GeoLite2-ASN.mmdb" - -LOYALSOLDIER_MMDB_URL="https://raw.githubusercontent.com/Loyalsoldier/geoip/release/Country.mmdb" -LOYALSOLDIER_GEOSITE_URL="https://raw.githubusercontent.com/Loyalsoldier/v2ray-rules-dat/release/geosite.dat" -LOYALSOLDIER_GEOIP_DAT_URL="https://raw.githubusercontent.com/Loyalsoldier/v2ray-rules-dat/release/geoip.dat" - -# v2fly ships no Country.mmdb — borrow Loyalsoldier's for the mmdb slot -V2FLY_GEOSITE_URL="https://github.com/v2fly/domain-list-community/releases/latest/download/dlc.dat" -V2FLY_GEOIP_DAT_URL="https://github.com/v2fly/geoip/releases/latest/download/geoip.dat" - -log() { - echo " $(date '+%Y-%m-%d %H:%M:%S') - $1" >> "$LOG_FILE" -} - -cleanup() { - rm -rf "$TMP_DIR" >/dev/null 2>&1 - rm -f /var/run/geoip_update >/dev/null 2>&1 -} - -config_needs_geosite() { - _cfg="$(uci -q get clashoo.config.use_config 2>/dev/null)" - if [ -s "$_cfg" ] && grep -Eq "^[[:space:]]*-[[:space:]]*[\"']?GEOSITE,|^[[:space:]]*geosite:[[:space:]]*|^[[:space:]]*'geosite:|^[[:space:]]*-[[:space:]]*[\"']?geosite:" "$_cfg"; then - return 0 - fi - _cfg="/etc/clashoo/config.yaml" - [ -f "$_cfg" ] || return 1 - grep -Eq "^[[:space:]]*-[[:space:]]*[\"']?GEOSITE,|^[[:space:]]*geosite:[[:space:]]*|^[[:space:]]*'geosite:|^[[:space:]]*-[[:space:]]*[\"']?geosite:" "$_cfg" -} - -# Shared port detection (handles smart core + sing-box profile port); keep the -# local anonymity probe so we skip a coexisting plugin's auth-locked proxy. -. /usr/share/clashoo/update/proxy_lib.sh -detect_proxy() { - proxy="$(clashoo_detect_proxy)" - [ -n "$proxy" ] || return 0 - # Only use it if it actually proxies anonymously. A coexisting plugin - # (e.g. OpenClash on the same 7890) may hold this port behind auth and - # answer HTTP 407 — in that case fall through to the mirrors instead. - if command -v curl >/dev/null 2>&1; then - curl -fsS --proxy "$proxy" --connect-timeout 3 --max-time 5 -o /dev/null \ - http://www.gstatic.com/generate_204 >/dev/null 2>&1 || return 0 - fi - echo "$proxy" -} - -_fetch() { - url="$1"; target="$2"; proxy="$3" - if command -v curl >/dev/null 2>&1; then - if [ -n "$proxy" ]; then - curl --proxy "$proxy" -fsSL --connect-timeout 15 --max-time 120 -A "Clash/OpenWRT" "$url" -o "$target" - else - curl -fsSL --connect-timeout 15 --max-time 120 -A "Clash/OpenWRT" "$url" -o "$target" - fi - return $? - fi - wget -q --timeout=120 --user-agent="Clash/OpenWRT" "$url" -O "$target" -} - -# 多源拉取:本机代理 → 国内镜像(gh-proxy / ghfast / jsdelivr)→ 原 URL 兜底 -download_to() { - url="$1"; target="$2" - [ -z "$url" ] && return 1 - - proxy="$(detect_proxy)" - - if [ -n "$proxy" ]; then - _fetch "$url" "$target" "$proxy" && return 0 - fi - - case "$url" in - https://raw.githubusercontent.com/*) - rest="${url#https://raw.githubusercontent.com/}" - owner="${rest%%/*}"; r1="${rest#*/}" - repo="${r1%%/*}"; r2="${r1#*/}" - branch="${r2%%/*}"; path="${r2#*/}" - for m in \ - "https://gh-proxy.com/${url}" \ - "https://ghfast.top/${url}" \ - "https://cdn.jsdelivr.net/gh/${owner}/${repo}@${branch}/${path}"; do - _fetch "$m" "$target" "" && return 0 - done - ;; - https://github.com/*) - for m in \ - "https://gh-proxy.com/${url}" \ - "https://ghfast.top/${url}"; do - _fetch "$m" "$target" "" && return 0 - done - ;; - esac - - _fetch "$url" "$target" "" -} - -download_optional() { - url="$1" - target="$2" - name="$3" - tmp_target="${TMP_DIR}/$(basename "$target").tmp" - if [ -z "$url" ]; then - log "$name skip (url empty)" - return 0 - fi - rm -f "$tmp_target" >/dev/null 2>&1 - if download_to "$url" "$tmp_target"; then - mv -f "$tmp_target" "$target" >/dev/null 2>&1 || return 1 - chmod 644 "$target" >/dev/null 2>&1 - log "$name updated" - return 0 - fi - rm -f "$tmp_target" >/dev/null 2>&1 - log "$name update failed" - return 0 -} - -download_geosite() { - url="$1" - tmp_target="${TMP_DIR}/GeoSite.dat.tmp" - size=0 - if [ -z "$url" ]; then - log "GeoSite.dat skip (url empty)" - return 1 - fi - rm -f "$tmp_target" >/dev/null 2>&1 - if ! download_to "$url" "$tmp_target"; then - rm -f "$tmp_target" >/dev/null 2>&1 - log "GeoSite.dat update failed" - return 1 - fi - size=$(wc -c <"$tmp_target" 2>/dev/null) - if [ -z "$size" ] || [ "$size" -lt "$GEOSITE_MIN_SIZE" ]; then - log "GeoSite.dat download invalid or incomplete (${size:-0} bytes)" - rm -f "$tmp_target" >/dev/null 2>&1 - return 1 - fi - mv -f "$tmp_target" /etc/clashoo/GeoSite.dat >/dev/null 2>&1 || return 1 - cp -f /etc/clashoo/GeoSite.dat /etc/clashoo/geosite.dat >/dev/null 2>&1 || true - chmod 644 /etc/clashoo/GeoSite.dat /etc/clashoo/geosite.dat >/dev/null 2>&1 - log "GeoSite.dat updated" - return 0 -} - -download_mmdb() { - url="$1" - tmp_target="${TMP_DIR}/Country.mmdb.tmp" - size=0 - rm -f "$tmp_target" >/dev/null 2>&1 - if ! download_to "$url" "$tmp_target"; then - rm -f "$tmp_target" >/dev/null 2>&1 - return 1 - fi - size=$(wc -c <"$tmp_target" 2>/dev/null) - if [ -z "$size" ] || [ "$size" -lt "$MMDB_MIN_SIZE" ]; then - log "Country.mmdb download invalid or incomplete (${size:-0} bytes)" - rm -f "$tmp_target" >/dev/null 2>&1 - return 1 - fi - mv -f "$tmp_target" /etc/clashoo/Country.mmdb >/dev/null 2>&1 || return 1 - chmod 644 /etc/clashoo/Country.mmdb >/dev/null 2>&1 - return 0 -} - -trap cleanup EXIT INT TERM -mkdir -p "$TMP_DIR" /etc/clashoo >/dev/null 2>&1 - -rm -f /var/run/geoip_down_complete >/dev/null 2>&1 -: > /var/run/geoip_update -: > "$LOG_FILE" -log "GeoIP 更新任务启动" - -mmdb_url="" -geosite_url="" -geoip_dat_url="" -geoip_asn_url="" - -case "$geoip_source" in - 1) - if [ -z "$license_key" ]; then - log "MaxMind source selected but license key is empty" - exit 1 - fi - log "Updating Country.mmdb from MaxMind" - if ! download_to "https://download.maxmind.com/app/geoip_download?edition_id=GeoLite2-Country&license_key=${license_key}&suffix=tar.gz" "$TMP_DIR/geoip.tar.gz"; then - log "MaxMind download failed" - exit 1 - fi - if ! tar zxf "$TMP_DIR/geoip.tar.gz" -C "$TMP_DIR" >/dev/null 2>&1; then - log "MaxMind archive extract failed" - exit 1 - fi - mmdb_file="$(ls "$TMP_DIR"/GeoLite2-Country_*/GeoLite2-Country.mmdb 2>/dev/null | head -n 1)" - if [ -z "$mmdb_file" ] || [ ! -f "$mmdb_file" ]; then - log "MaxMind Country.mmdb not found in archive" - exit 1 - fi - cp -f "$mmdb_file" /etc/clashoo/Country.mmdb - chmod 644 /etc/clashoo/Country.mmdb >/dev/null 2>&1 - log "Country.mmdb updated" - ;; - 3) - # Loyalsoldier (default) - mmdb_url="$LOYALSOLDIER_MMDB_URL" - geosite_url="$LOYALSOLDIER_GEOSITE_URL" - geoip_dat_url="$LOYALSOLDIER_GEOIP_DAT_URL" - geoip_asn_url="$DEFAULT_GEOIP_ASN_URL" - ;; - 5) - # v2fly (mmdb borrowed from Loyalsoldier) - mmdb_url="$LOYALSOLDIER_MMDB_URL" - geosite_url="$V2FLY_GEOSITE_URL" - geoip_dat_url="$V2FLY_GEOIP_DAT_URL" - geoip_asn_url="$DEFAULT_GEOIP_ASN_URL" - ;; - 4) - # custom — asn falls back to default when left blank - mmdb_url="$cfg_mmdb_url" - geosite_url="$cfg_geosite_url" - geoip_dat_url="$cfg_geoip_dat_url" - geoip_asn_url="${cfg_geoip_asn_url:-$DEFAULT_GEOIP_ASN_URL}" - ;; - *) - mmdb_url="${cfg_mmdb_url:-$DEFAULT_MMDB_URL}" - geosite_url="${cfg_geosite_url:-$DEFAULT_GEOSITE_URL}" - geoip_dat_url="${cfg_geoip_dat_url:-$DEFAULT_GEOIP_DAT_URL}" - geoip_asn_url="${cfg_geoip_asn_url:-$DEFAULT_GEOIP_ASN_URL}" - ;; -esac - -if [ "$geoip_source" != "1" ]; then - log "Updating Country.mmdb" - if ! download_mmdb "$mmdb_url"; then - log "Country.mmdb download failed" - exit 1 - fi - log "Country.mmdb updated" - - if [ "$require_geosite" -eq 1 ] || config_needs_geosite; then - if ! download_geosite "$geosite_url"; then - exit 1 - fi - else - log "GeoSite.dat skip (no geosite reference in config)" - fi - download_optional "$geoip_dat_url" /etc/clashoo/geoip.dat "geoip.dat" - download_optional "$geoip_asn_url" /etc/clashoo/GeoLite2-ASN.mmdb "GeoLite2-ASN.mmdb" -fi - -if [ "$geoip_source" = "1" ] && { [ "$require_geosite" -eq 1 ] || config_needs_geosite; }; then - geosite_url="${cfg_geosite_url:-$DEFAULT_GEOSITE_URL}" - if ! download_geosite "$geosite_url"; then - exit 1 - fi -fi - -touch /var/run/geoip_down_complete >/dev/null 2>&1 - -if pidof mihomo >/dev/null 2>&1 || pidof clash-meta >/dev/null 2>&1; then - log "GeoIP update completed, apply on next Clashoo restart" -fi - -log "GeoIP update completed" -exit 0 diff --git a/clashoo/files/usr/share/clashoo/update/lgbm_update.sh b/clashoo/files/usr/share/clashoo/update/lgbm_update.sh deleted file mode 100755 index fa17a30c..00000000 --- a/clashoo/files/usr/share/clashoo/update/lgbm_update.sh +++ /dev/null @@ -1,52 +0,0 @@ -#!/bin/sh - -MODEL_PATH="/etc/clashoo/Model.bin" -TMP_PATH="/tmp/clash_Model.bin" -LOG_FILE="/tmp/lgbm_update.log" - -log() { - echo " $(date '+%Y-%m-%d %H:%M:%S') - $1" >> "$LOG_FILE" -} - -: > "$LOG_FILE" - -DOWNLOAD_URL=$(uci get clashoo.config.smart_lgbm_url 2>/dev/null) -[ -z "$DOWNLOAD_URL" ] && DOWNLOAD_URL="https://github.com/vernesong/mihomo/releases/download/LightGBM-Model/Model.bin" - -log "Start downloading LightGBM model from: $DOWNLOAD_URL" - -mkdir -p /etc/clashoo - -rm -f "$TMP_PATH" 2>/dev/null -if command -v curl >/dev/null 2>&1; then - curl -fL --connect-timeout 15 --max-time 120 -A "Clash/OpenWRT" "$DOWNLOAD_URL" -o "$TMP_PATH" 2>/dev/null - dl_rc=$? -elif command -v wget >/dev/null 2>&1; then - wget -q --timeout=30 -U "Clash/OpenWRT" "$DOWNLOAD_URL" -O "$TMP_PATH" 2>/dev/null - dl_rc=$? -else - log "No curl or wget found" - exit 1 -fi - -if [ "$dl_rc" -ne 0 ] || [ ! -s "$TMP_PATH" ]; then - log "Download failed (rc=$dl_rc)" - rm -f "$TMP_PATH" - exit 1 -fi - -if [ -f "$MODEL_PATH" ] && cmp -s "$TMP_PATH" "$MODEL_PATH"; then - log "Model unchanged, no update needed" - rm -f "$TMP_PATH" - exit 0 -fi - -mv "$TMP_PATH" "$MODEL_PATH" 2>/dev/null -if [ $? -ne 0 ]; then - log "Failed to install model to $MODEL_PATH" - rm -f "$TMP_PATH" - exit 1 -fi - -log "LightGBM model updated successfully" -exit 0 diff --git a/clashoo/files/usr/share/clashoo/update/maintenance_cron.sh b/clashoo/files/usr/share/clashoo/update/maintenance_cron.sh deleted file mode 100755 index 20eed4db..00000000 --- a/clashoo/files/usr/share/clashoo/update/maintenance_cron.sh +++ /dev/null @@ -1,37 +0,0 @@ -#!/bin/sh - -STATE_DIR="${CLASHOO_STATE_DIR:-/usr/share/clashbackup}" -UPDATE_SCRIPT="${CLASHOO_UPDATE_SCRIPT:-/usr/share/clashoo/update/update_all.sh}" -LOG_FILE="${CLASHOO_LOG_FILE:-/usr/share/clashoo/clashoo.txt}" -LOCK_DIR="${CLASHOO_LOCK_DIR:-/tmp/clashoo_maintenance.lock}" -NOW="${CLASHOO_NOW:-$(date +%s)}" - -stamp() { - tmp="$STATE_DIR/$1.tmp.$$" - printf 'last_run=%s\n' "$NOW" >"$tmp" && mv -f "$tmp" "$STATE_DIR/$1" -} - -due() { - hours="$(uci -q get "clashoo.config.$2")" - echo "$hours" | grep -Eq '^[0-9]+$' && [ "$hours" -ge 1 ] || hours=12 - last="$(sed -n 's/^last_run=//p' "$STATE_DIR/$1" 2>/dev/null | head -1)" - if ! echo "$last" | grep -Eq '^[0-9]+$' || [ "$last" -gt "$NOW" ]; then - stamp "$1" - return 1 - fi - [ $((NOW - last)) -ge $((hours * 3600)) ] -} - -mkdir -p "$STATE_DIR" || exit 0 -mkdir "$LOCK_DIR" 2>/dev/null || exit 0 -trap 'rmdir "$LOCK_DIR" >/dev/null 2>&1' EXIT INT TERM - -if [ "$(uci -q get clashoo.config.auto_update)" = "1" ] && due rule_update.status auto_update_time; then - CLASHOO_STATE_DIR="$STATE_DIR" sh "$UPDATE_SCRIPT" >/dev/null 2>&1 -fi - -if [ "$(uci -q get clashoo.config.auto_clear_log)" = "1" ] && due log_cleanup.status clear_time; then - : >"$LOG_FILE" - sh /usr/share/clashoo/lib/core_log_guard.sh >/dev/null 2>&1 - stamp log_cleanup.status -fi diff --git a/clashoo/files/usr/share/clashoo/update/panel_download.sh b/clashoo/files/usr/share/clashoo/update/panel_download.sh deleted file mode 100755 index 96c241a6..00000000 --- a/clashoo/files/usr/share/clashoo/update/panel_download.sh +++ /dev/null @@ -1,204 +0,0 @@ -#!/bin/sh - -REAL_LOG="/usr/share/clashoo/clashoo_real.txt" -panel="$1" -lang="$(uci -q get luci.main.lang 2>/dev/null)" -STATE_FILE="/tmp/clash_panel_download_state" -RUN_FILE="/var/run/panel_downloading" -DASHBOARD_LINK="/etc/clashoo/dashboard" - -[ -n "$panel" ] || panel="$(uci -q get clashoo.config.dashboard_panel 2>/dev/null)" -[ -n "$panel" ] || panel="zashboard" - -case "$panel" in - metacubexd) - URLS="https://github.com/MetaCubeX/metacubexd/archive/refs/heads/gh-pages.zip" - TARGET_DIR="/etc/clashoo/dashboard-metacubexd" - ;; - yacd) - URLS="https://github.com/MetaCubeX/Yacd-meta/archive/refs/heads/gh-pages.zip https://github.com/haishanh/yacd/archive/refs/heads/gh-pages.zip" - TARGET_DIR="/etc/clashoo/dashboard-yacd" - ;; - zashboard) - URLS="https://github.com/Zephyruso/zashboard/releases/latest/download/dist.zip https://github.com/Zephyruso/zashboard/releases/latest/download/dist-cdn-fonts.zip" - TARGET_DIR="/etc/clashoo/dashboard-zashboard" - ;; - razord) - URLS="https://github.com/MetaCubeX/Razord-meta/archive/refs/heads/gh-pages.zip https://github.com/ayanamist/clash-dashboard/archive/refs/heads/gh-pages.zip" - TARGET_DIR="/etc/clashoo/dashboard-razord" - ;; - *) - URLS="https://github.com/Zephyruso/zashboard/releases/latest/download/dist.zip https://github.com/Zephyruso/zashboard/releases/latest/download/dist-cdn-fonts.zip" - TARGET_DIR="/etc/clashoo/dashboard-zashboard" - panel="zashboard" - ;; -esac - -TMP_ROOT="/tmp/clash_panel_${panel}_$$" -ZIP_FILE="$TMP_ROOT/panel.zip" -UNPACK_DIR="$TMP_ROOT/unpack" - -UPDATE_LOG="/tmp/clash_update.txt" - -update_log() { - [ -n "$1" ] || return 0 - printf '%s - %s\n' "$(date '+%Y-%m-%d %H:%M:%S')" "$1" >>"$UPDATE_LOG" -} - -log_msg() { - if [ "$lang" = "en" ]; then - echo "$1" >"$REAL_LOG" - [ "$3" = "1" ] || update_log "$1" - else - echo "$2" >"$REAL_LOG" - [ "$3" = "1" ] || update_log "$2" - fi -} - -set_state() { - state="$1" - msg="$2" - echo "${state}:${panel}:${msg}" >"$STATE_FILE" -} - -cleanup() { - rm -rf "$TMP_ROOT" >/dev/null 2>&1 - rm -f "$RUN_FILE" >/dev/null 2>&1 -} - -# Route the panel download through the running core in kernel-only mode -# (shared logic in proxy_lib.sh). Normal mode returns empty -> TPROXY. -. /usr/share/clashoo/update/proxy_lib.sh -detect_proxy() { clashoo_detect_proxy; } - -download_zip() { - proxy="$(detect_proxy)" - for url in $URLS; do - if [ -n "$proxy" ] && command -v curl >/dev/null 2>&1 && - curl -fsSL --connect-timeout 15 --max-time 300 --retry 1 \ - --proxy "$proxy" -A "Clash/OpenWRT" "$url" -o "$ZIP_FILE"; then - return 0 - fi - if wget -q --timeout=60 --user-agent="Clash/OpenWRT" "$url" -O "$ZIP_FILE"; then - return 0 - fi - done - return 1 -} - -validate_zip_entries() { - entries="$TMP_ROOT/entries.txt" - if command -v unzip >/dev/null 2>&1; then - unzip -Z1 "$ZIP_FILE" >"$entries" 2>/dev/null || return 1 - elif command -v bsdtar >/dev/null 2>&1; then - bsdtar -tf "$ZIP_FILE" >"$entries" 2>/dev/null || return 1 - else - return 1 - fi - [ -s "$entries" ] || return 1 - awk ' - /^\// || /^[A-Za-z]:/ || /(^|\/)\.\.(\/|$)/ || /\\/ || /\r/ { bad = 1 } - END { exit bad } - ' "$entries" -} - -extract_zip() { - if command -v unzip >/dev/null 2>&1; then - unzip -oq "$ZIP_FILE" -d "$UNPACK_DIR" >/dev/null 2>&1 - return $? - fi - - if command -v busybox >/dev/null 2>&1 && busybox --list 2>/dev/null | grep -qx "unzip"; then - busybox unzip -oq "$ZIP_FILE" -d "$UNPACK_DIR" >/dev/null 2>&1 - return $? - fi - - if command -v bsdtar >/dev/null 2>&1; then - bsdtar -xf "$ZIP_FILE" -C "$UNPACK_DIR" >/dev/null 2>&1 - return $? - fi - - return 2 -} - -find_web_root() { - if [ -f "$UNPACK_DIR/index.html" ]; then - echo "$UNPACK_DIR" - return 0 - fi - - index_file="$(find "$UNPACK_DIR" -type f -name index.html 2>/dev/null | head -n 1)" - if [ -n "$index_file" ]; then - dirname "$index_file" - return 0 - fi - - return 1 -} - -activate_panel() { - rm -rf "$DASHBOARD_LINK" >/dev/null 2>&1 - ln -s "$TARGET_DIR" "$DASHBOARD_LINK" >/dev/null 2>&1 || cp -a "$TARGET_DIR" "$DASHBOARD_LINK" >/dev/null 2>&1 - rm -rf /www/luci-static/yacd >/dev/null 2>&1 - if [ "$panel" = "yacd" ]; then - ln -s "$TARGET_DIR" /www/luci-static/yacd >/dev/null 2>&1 - fi -} - -trap cleanup EXIT INT TERM -mkdir -p "$UNPACK_DIR" "$TARGET_DIR" >/dev/null 2>&1 -touch "$RUN_FILE" -set_state "downloading" "开始下载" - -log_msg "Downloading dashboard panel..." "正在下载面板..." -if ! download_zip; then - set_state "error" "下载失败" - log_msg "Dashboard panel download failed" "面板下载失败" - exit 1 -fi - -if ! validate_zip_entries; then - set_state "error" "压缩包路径无效" - log_msg "Dashboard panel archive has unsafe entries" "面板压缩包含不安全路径" - exit 1 -fi - -extract_zip -extract_rc=$? -if [ "$extract_rc" -ne 0 ]; then - if [ "$extract_rc" -eq 2 ]; then - set_state "error" "缺少解压工具" - log_msg "Panel unzip tool not found" "缺少解压工具,无法安装面板" - else - set_state "error" "解压失败" - log_msg "Dashboard panel unzip failed" "面板解压失败" - fi - exit 1 -fi - -if find "$UNPACK_DIR" ! -type d ! -type f | grep -q .; then - set_state "error" "压缩包文件类型无效" - log_msg "Dashboard panel archive has unsafe file types" "面板压缩包含不安全文件类型" - exit 1 -fi - -SRC_DIR="$(find_web_root)" -if [ -z "$SRC_DIR" ] || [ ! -f "$SRC_DIR/index.html" ]; then - set_state "error" "文件无效" - log_msg "Dashboard panel content invalid" "面板文件无效" - exit 1 -fi - -rm -rf "$TARGET_DIR"/* >/dev/null 2>&1 -cp -a "$SRC_DIR"/. "$TARGET_DIR"/ >/dev/null 2>&1 - -activate_panel - -uci set clashoo.config.dashboard_panel="$panel" >/dev/null 2>&1 -uci commit clashoo >/dev/null 2>&1 - -set_state "success" "安装成功" -log_msg "Dashboard panel installed" "面板安装完成" -sleep 1 -log_msg "Clashoo" "Clashoo" 1 -exit 0 diff --git a/clashoo/files/usr/share/clashoo/update/proxy_lib.sh b/clashoo/files/usr/share/clashoo/update/proxy_lib.sh deleted file mode 100644 index e9664420..00000000 --- a/clashoo/files/usr/share/clashoo/update/proxy_lib.sh +++ /dev/null @@ -1,80 +0,0 @@ -# shellcheck shell=sh -# Clashoo's sing-box is private; HomeProxy owns the public system binary. -CLASHOO_SINGBOX_BIN_DIR="/usr/share/clashoo/bin" -CLASHOO_SINGBOX_RUNTIME_CONFIG="/var/run/clashoo/sing-box/config.json" - -# Shared proxy detection for clashoo's own outbound requests. -# -# clashoo's self-initiated downloads (update checks, component/panel/core/geoip -# downloads, subscriptions) and health checks must reach GitHub through the -# running core, otherwise they leak out direct and stall behind the GFW. Route -# them through the core's mixed port whenever a core is running — in BOTH modes: -# - core-only mode deliberately skips TPROXY to coexist with other plugins; -# - normal mode used to rely on transparent redirect, but the router's OWN -# output redirect is fragile (e.g. PPPoE/GL.iNet stacks where Redirect to -# loopback never completes — issue #25), so don't depend on it. The explicit -# mixed port works on every network stack. -# When no core is running (e.g. bootstrapping the very first core download), -# returns empty so the caller falls back to direct / mirror sources. -# -# Port source depends on the running Clashoo kernel. The liveness gate uses the -# procd owner instead of a binary name, because other proxy plugins may run the -# same binaries: -# sing-box -> private runtime config mixed inbound -# (an imported profile may carry its own port) -# mihomo / clash-meta / smart -> /etc/clashoo/config.yaml mixed-port -# (a custom config's port may differ from uci) -# uci mixed_port is the last-resort fallback for both. -clashoo_running_core_type() { - _cdp_type="$(uci -q get clashoo.config.core_type 2>/dev/null)" - case "$_cdp_type" in - singbox) - _cdp_service="clashoo" - _cdp_filter='@.clashoo.instances.singbox.pid' - ;; - *) - _cdp_type="mihomo" - _cdp_service="clashoo" - _cdp_filter='@.clashoo.instances.*.pid' - ;; - esac - - _cdp_pid="$(ubus call service list "{\"name\":\"$_cdp_service\",\"verbose\":true}" 2>/dev/null \ - | jsonfilter -e "$_cdp_filter" 2>/dev/null | head -n1)" - [ -n "$_cdp_pid" ] && [ -d "/proc/$_cdp_pid" ] || return 1 - if [ "$_cdp_type" = "singbox" ]; then - local _cdp_exe _cdp_cmdline - _cdp_exe="$(readlink -f "/proc/$_cdp_pid/exe" 2>/dev/null)" - case "$_cdp_exe" in - "$CLASHOO_SINGBOX_BIN_DIR/sing-box-stable"|"$CLASHOO_SINGBOX_BIN_DIR/sing-box-alpha") ;; - *) - _cdp_cmdline="$(tr '\000' ' ' < "/proc/$_cdp_pid/cmdline" 2>/dev/null)" - case "$_cdp_cmdline" in - "$CLASHOO_SINGBOX_BIN_DIR/sing-box-stable"|"$CLASHOO_SINGBOX_BIN_DIR/sing-box-stable "*|"$CLASHOO_SINGBOX_BIN_DIR/sing-box-alpha"|"$CLASHOO_SINGBOX_BIN_DIR/sing-box-alpha "*) ;; - *) return 1 ;; - esac - ;; - esac - fi - printf '%s' "$_cdp_type" -} - -clashoo_detect_proxy() { - _cdp_type="$(clashoo_running_core_type)" || return 0 - _cdp_port="" - if [ "$_cdp_type" = "singbox" ]; then - _cdp_port="$(jsonfilter -i "$CLASHOO_SINGBOX_RUNTIME_CONFIG" \ - -e '@.inbounds[@.type="mixed"].listen_port' 2>/dev/null | head -n 1)" - else - # prefer mixed-port (HTTP+SOCKS) over plain port; a single two-pattern - # sed would return whichever appears first by line order, so loop by key - for _cdp_key in mixed-port port socks-port; do - _cdp_port="$(sed -n "s/^[[:space:]]*${_cdp_key}:[[:space:]]*\([0-9][0-9]*\).*/\1/p" \ - /etc/clashoo/config.yaml 2>/dev/null | head -n 1)" - [ -n "$_cdp_port" ] && break - done - fi - [ -n "$_cdp_port" ] || _cdp_port="$(uci -q get clashoo.config.mixed_port 2>/dev/null)" - [ -n "$_cdp_port" ] || return 0 - printf 'http://127.0.0.1:%s' "$_cdp_port" -} diff --git a/clashoo/files/usr/share/clashoo/update/subscription_update.sh b/clashoo/files/usr/share/clashoo/update/subscription_update.sh deleted file mode 100755 index 60827ed4..00000000 --- a/clashoo/files/usr/share/clashoo/update/subscription_update.sh +++ /dev/null @@ -1,385 +0,0 @@ -#!/bin/sh - -SUB_DIR="${CLASHOO_SUB_DIR:-/usr/share/clashoo/config/sub}" -SINGBOX_DIR="${CLASHOO_SINGBOX_DIR:-/usr/share/clashoo/config/singbox}" -BACKUP_DIR="${CLASHOO_BACKUP_DIR:-/usr/share/clashbackup}" -TEMPLATE_DIR="${CLASHOO_TEMPLATE_DIR:-/usr/share/clashoo/config/custom}" -LIST_FILE="${CLASHOO_LIST_FILE:-$BACKUP_DIR/confit_list.conf}" -BIND_FILE="${CLASHOO_BIND_FILE:-$BACKUP_DIR/template_bindings.conf}" -STATUS_FILE="${CLASHOO_STATUS_FILE:-$BACKUP_DIR/subscription_update.status}" -LOCK_DIR="${CLASHOO_LOCK_DIR:-/tmp/clashoo_subscription_update.lock}" -UPDATE_LOG="${CLASHOO_UPDATE_LOG:-/tmp/clash_update.txt}" -SERVICE_CMD="${CLASHOO_SERVICE_CMD:-/etc/init.d/clashoo}" -TMP_DIR="${CLASHOO_TMP_DIR:-/tmp}" -DEFAULT_SUB_UA='Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36' -DOWNLOAD_ERROR="" - -# Subscriptions are fetched direct first (many airports are domestic / geo-fence -# foreign exit IPs). Only used as a last-resort fallback, see download_to. -. /usr/share/clashoo/update/proxy_lib.sh - -updated=0 -unchanged=0 -failed=0 -skipped=0 -restart_needed=0 -started_at="$(date +%s)" -message="" -record_status=0 -[ "$1" = "--all" ] && record_status=1 - -log_update() { - printf ' %s - %s\n' "$(date '+%Y-%m-%d %H:%M:%S')" "$1" >>"$UPDATE_LOG" -} - -write_status() { - local tmp - mkdir -p "$(dirname "$STATUS_FILE")" >/dev/null 2>&1 - tmp="${STATUS_FILE}.tmp.$$" - cat >"$tmp" </dev/null 2>&1 -} - -if ! mkdir "$LOCK_DIR" >/dev/null 2>&1; then - exit 75 -fi -trap cleanup EXIT INT TERM -[ "$record_status" = "1" ] && write_status 1 0 - -safe_name() { - case "$1" in - ''|*/*|*..*) return 1 ;; - esac - return 0 -} - -extract_host() { - printf '%s' "$1" | sed -e 's#^[a-zA-Z0-9+.-]*://##' -e 's#/.*$##' -e 's#:.*$##' -e 's#.*@##' -} - -resolve_via() { - local host dns - host="$1" - dns="$2" - nslookup "$host" "$dns" 2>/dev/null | awk ' - /^Address/ { - ip = $NF - if (ip ~ /^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$/ && - ip !~ /^127\./ && ip !~ /^0\./ && ip !~ /^198\.18\./ && - ip != "8.8.8.8" && ip != "1.1.1.1" && - ip != "223.5.5.5" && ip != "119.29.29.29") { - print ip - exit - } - }' -} - -curl_download() { - local url out hdr ua host ip - url="$1" - out="$2" - hdr="$3" - ua="$4" - host="$5" - ip="$6" - if [ -n "$host" ] && [ -n "$ip" ]; then - curl -sSL --connect-timeout 15 --max-time 60 --speed-time 30 \ - --speed-limit 1 --retry 2 -A "$ua" -D "$hdr" -o "$out" \ - --resolve "$host:443:$ip" --resolve "$host:80:$ip" \ - -w '%{http_code}' "$url" 2>/dev/null - else - curl -sSL --connect-timeout 15 --max-time 60 --speed-time 30 \ - --speed-limit 1 --retry 2 -A "$ua" -D "$hdr" -o "$out" \ - -w '%{http_code}' "$url" 2>/dev/null - fi -} - -subscription_ua() { - local target ua - target="$1" - ua="" - [ -r "${target}.ua" ] && ua="$(sed -n '1p' "${target}.ua" 2>/dev/null)" - [ -n "$ua" ] || ua="$(uci -q get clashoo.config.sub_ua 2>/dev/null)" - [ -n "$ua" ] || ua="$DEFAULT_SUB_UA" - printf '%s' "$ua" -} - -save_subscription_ua() { - printf '%s\n' "$2" >"${1}.ua" -} - -curl_error() { - case "$1" in - 6) printf '%s' "DNS 解析失败" ;; - 7) printf '%s' "连接失败" ;; - 28) printf '%s' "连接超时" ;; - 35) printf '%s' "TLS 握手失败" ;; - 60) printf '%s' "证书校验失败" ;; - *) printf '网络错误(curl rc=%s)' "${1:-unknown}" ;; - esac -} - -download_to() { - local url out hdr ua code rc last_rc host dns ip proxy - url="$1" - out="$2" - hdr="$3" - ua="$4" - [ -n "$ua" ] || ua="$DEFAULT_SUB_UA" - DOWNLOAD_ERROR="" - - rm -f "$out" "$hdr" >/dev/null 2>&1 - if command -v curl >/dev/null 2>&1; then - code="$(curl_download "$url" "$out" "$hdr" "$ua" "" "")" - rc=$? - if [ "$rc" -eq 0 ] && [ "$code" = "200" ]; then - return 0 - fi - if [ "$rc" -eq 0 ] && [ -n "$code" ] && [ "$code" != "000" ]; then - DOWNLOAD_ERROR="HTTP ${code}" - return 1 - fi - last_rc="$rc" - host="$(extract_host "$url")" - for dns in 223.5.5.5 119.29.29.29 1.1.1.1 8.8.8.8; do - ip="$(resolve_via "$host" "$dns")" - [ -n "$ip" ] || continue - log_update "DNS 回退:${host} -> ${ip} (@${dns})" - code="$(curl_download "$url" "$out" "$hdr" "$ua" "$host" "$ip")" - rc=$? - [ "$rc" -eq 0 ] && [ "$code" = "200" ] && return 0 - if [ "$rc" -eq 0 ] && [ -n "$code" ] && [ "$code" != "000" ]; then - DOWNLOAD_ERROR="HTTP ${code}" - return 1 - fi - last_rc="$rc" - done - # Last resort: direct + DNS-override both failed, so the source may be - # GFW-blocked (e.g. a github-hosted sub). In kernel-only mode try once - # through the running core — nothing left to lose, and it won't disturb - # any airport that already answered direct. - proxy="$(clashoo_detect_proxy)" - if [ -n "$proxy" ]; then - log_update "代理兜底:通过本地核心重试订阅" - code="$(curl -sSL --connect-timeout 15 --max-time 60 --speed-time 30 \ - --speed-limit 1 --retry 1 -A "$ua" -D "$hdr" -o "$out" \ - --proxy "$proxy" -w '%{http_code}' "$url" 2>/dev/null)" - rc=$? - [ "$rc" -eq 0 ] && [ "$code" = "200" ] && return 0 - if [ "$rc" -eq 0 ] && [ -n "$code" ] && [ "$code" != "000" ]; then - DOWNLOAD_ERROR="HTTP ${code}" - return 1 - fi - last_rc="$rc" - fi - DOWNLOAD_ERROR="$(curl_error "$last_rc")" - return 1 - fi - wget -q --timeout=20 --user-agent="$ua" "$url" -O "$out" - rc=$? - [ "$rc" -eq 0 ] && return 0 - DOWNLOAD_ERROR="网络错误(wget rc=${rc})" - return 1 -} - -update_info() { - local hdr target info - hdr="$1" - target="$2" - info="$(grep -i 'subscription-userinfo:' "$hdr" 2>/dev/null | head -1 | \ - sed 's/^[Ss]ubscription-[Uu]serinfo:[[:space:]]*//' | tr -d '\r')" - if [ -n "$info" ]; then - printf '%s\n' "$info" >"${target}.info" - else - rm -f "${target}.info" >/dev/null 2>&1 - fi -} - -service_running() { - [ "$("$SERVICE_CMD" status 2>/dev/null)" = "running" ] -} - -template_output_name() { - local sub tpl - sub="$(printf '%s' "$1" | sed -e 's/\.[Yy][Aa][Mm][Ll]$//' -e 's/\.[Yy][Mm][Ll]$//' -e 's/[^A-Za-z0-9._-]/-/g')" - tpl="$(printf '%s' "$2" | sed -e 's/\.[Yy][Aa][Mm][Ll]$//' -e 's/\.[Yy][Mm][Ll]$//' -e 's/[^A-Za-z0-9._-]/-/g')" - printf '_merged_%s__%s.yaml' "${sub:-sub}" "${tpl:-template}" -} - -apply_template() { - local name target template merged merged_path use_config - name="$1" - target="$2" - [ -r "$BIND_FILE" ] || return 0 - [ -x /usr/share/clashoo/update/template_merge.sh ] || return 0 - template="$(awk -F '#' -v n="$name" '$1==n && ($3=="1" || $3=="true") {print $2; exit}' "$BIND_FILE")" - [ -n "$template" ] && [ -r "$TEMPLATE_DIR/$template" ] || return 0 - merged="$(template_output_name "$name" "$template")" - merged_path="$TEMPLATE_DIR/$merged" - if sh /usr/share/clashoo/update/template_merge.sh "$target" "$TEMPLATE_DIR/$template" "$merged_path" >/dev/null 2>&1; then - use_config="$(uci -q get clashoo.config.use_config 2>/dev/null)" - if [ "$use_config" = "$target" ] || [ "$use_config" = "$merged_path" ]; then - uci -q set clashoo.config.use_config="$merged_path" - uci -q set clashoo.config.config_type='3' - uci -q commit clashoo >/dev/null 2>&1 - restart_needed=1 - fi - else - log_update "模板生成失败:${name} <- ${template}" - fi -} - -update_mihomo() { - local name url typ target tmp hdr ua use_config config_type - name="$1" - url="$2" - typ="$3" - safe_name "$name" || return 1 - case "$typ" in clash|meta) ;; *) skipped=$((skipped + 1)); return 0 ;; esac - target="$SUB_DIR/$name" - [ -f "$target" ] || { skipped=$((skipped + 1)); return 0; } - tmp="$TMP_DIR/clashoo_sub_$$.yaml" - hdr="$TMP_DIR/clashoo_sub_$$.hdr" - ua="$(subscription_ua "$target")" - if ! download_to "$url" "$tmp" "$hdr" "$ua"; then - failed=$((failed + 1)) - log_update "更新失败(${DOWNLOAD_ERROR:-下载失败}):$name" - rm -f "$tmp" "$hdr" - return 1 - fi - if ! grep -Eq '^(proxies|proxy-providers):' "$tmp" 2>/dev/null; then - failed=$((failed + 1)) - log_update "更新失败(无效 Mihomo 配置):$name" - rm -f "$tmp" "$hdr" - return 1 - fi - if cmp -s "$tmp" "$target"; then - update_info "$hdr" "$target" - save_subscription_ua "$target" "$ua" - unchanged=$((unchanged + 1)) - rm -f "$tmp" "$hdr" - return 0 - fi - if ! mv "$tmp" "$target"; then - failed=$((failed + 1)) - rm -f "$hdr" - return 1 - fi - update_info "$hdr" "$target" - save_subscription_ua "$target" "$ua" - rm -f "$hdr" - updated=$((updated + 1)) - use_config="$(uci -q get clashoo.config.use_config 2>/dev/null)" - config_type="$(uci -q get clashoo.config.config_type 2>/dev/null)" - [ "$config_type" = "1" ] && [ "$use_config" = "$target" ] && restart_needed=1 - apply_template "$name" "$target" - log_update "更新完成:$name" -} - -valid_singbox() { - ucode -e 'import { readfile } from "fs"; let c = json(readfile(ARGV[0])); exit(type(c) == "object" && type(c.outbounds) == "array" && length(c.outbounds) > 0 ? 0 : 1);' "$1" >/dev/null 2>&1 -} - -update_singbox() { - local name target url tmp hdr ua active - name="$1" - safe_name "$name" || return 1 - target="$SINGBOX_DIR/$name" - [ -f "$target" ] && [ -r "$target.url" ] || { skipped=$((skipped + 1)); return 0; } - url="$(sed -n '1p' "$target.url")" - [ -n "$url" ] || { skipped=$((skipped + 1)); return 0; } - tmp="$TMP_DIR/clashoo_sb_$$.json" - hdr="$TMP_DIR/clashoo_sb_$$.hdr" - ua="$(subscription_ua "$target")" - if ! download_to "$url" "$tmp" "$hdr" "$ua"; then - failed=$((failed + 1)) - log_update "更新失败(${DOWNLOAD_ERROR:-下载失败}):$name" - rm -f "$tmp" "$hdr" - return 1 - fi - if ! valid_singbox "$tmp"; then - failed=$((failed + 1)) - log_update "更新失败(无效 sing-box 配置):$name" - rm -f "$tmp" "$hdr" - return 1 - fi - if cmp -s "$tmp" "$target"; then - update_info "$hdr" "$target" - save_subscription_ua "$target" "$ua" - unchanged=$((unchanged + 1)) - rm -f "$tmp" "$hdr" - return 0 - fi - if ! mv "$tmp" "$target"; then - failed=$((failed + 1)) - rm -f "$hdr" - return 1 - fi - update_info "$hdr" "$target" - save_subscription_ua "$target" "$ua" - rm -f "$hdr" - updated=$((updated + 1)) - active="$(uci -q get clashoo.config.singbox_active 2>/dev/null)" - [ "$active" = "$name" ] && restart_needed=1 - log_update "更新完成:$name" -} - -update_all() { - local name url typ url_file - if [ -r "$LIST_FILE" ]; then - while IFS='#' read -r name url typ _rest; do - [ -n "$name" ] && [ -n "$url" ] || continue - update_mihomo "$name" "$url" "$typ" || true - done <"$LIST_FILE" - fi - for url_file in "$SINGBOX_DIR"/*.url; do - [ -f "$url_file" ] || continue - name="$(basename "$url_file" .url)" - update_singbox "$name" || true - done -} - -case "$1" in - --all) - update_all - ;; - --mihomo) - line="$(awk -F '#' -v n="$2" '$1==n {print; exit}' "$LIST_FILE" 2>/dev/null)" - [ -n "$line" ] || { failed=1; message="subscription not found"; } - if [ -n "$line" ]; then - name="$(printf '%s' "$line" | awk -F '#' '{print $1}')" - url="$(printf '%s' "$line" | awk -F '#' '{print $2}')" - typ="$(printf '%s' "$line" | awk -F '#' '{print $3}')" - update_mihomo "$name" "$url" "$typ" || true - fi - ;; - --singbox) - update_singbox "$2" || true - ;; - *) - failed=1 - message="invalid arguments" - ;; -esac - -if [ "$restart_needed" = "1" ] && service_running; then - "$SERVICE_CMD" restart >/dev/null 2>&1 -fi - -finished_at="$(date +%s)" -[ -n "$message" ] || message="updated=$updated unchanged=$unchanged failed=$failed skipped=$skipped" -[ "$record_status" = "1" ] && write_status 0 "$finished_at" -[ "$failed" -eq 0 ] diff --git a/clashoo/files/usr/share/clashoo/update/subscription_update_cron.sh b/clashoo/files/usr/share/clashoo/update/subscription_update_cron.sh deleted file mode 100755 index 1f83307c..00000000 --- a/clashoo/files/usr/share/clashoo/update/subscription_update_cron.sh +++ /dev/null @@ -1,18 +0,0 @@ -#!/bin/sh - -STATUS_FILE="${CLASHOO_STATUS_FILE:-/usr/share/clashbackup/subscription_update.status}" -UPDATER="${CLASHOO_SUBSCRIPTION_UPDATER:-/usr/share/clashoo/update/subscription_update.sh}" -SERVICE_CMD="${CLASHOO_SERVICE_CMD:-/etc/init.d/clashoo}" -interval="$(uci -q get clashoo.config.subscription_update_interval 2>/dev/null)" -now="$(date +%s)" -last=0 - -[ "$(uci -q get clashoo.config.auto_subscription_update 2>/dev/null)" = "1" ] || exit 0 -"$SERVICE_CMD" status >/dev/null 2>&1 || exit 0 -echo "$interval" | grep -Eq '^[0-9]+$' || interval=72 -[ "$interval" -gt 0 ] || interval=72 -[ -r "$STATUS_FILE" ] && last="$(sed -n 's/^last_run=//p' "$STATUS_FILE" | head -1)" -echo "$last" | grep -Eq '^[0-9]+$' || last=0 - -[ $((now - last)) -ge $((interval * 3600)) ] || exit 0 -sh "$UPDATER" --all diff --git a/clashoo/files/usr/share/clashoo/update/template_merge.sh b/clashoo/files/usr/share/clashoo/update/template_merge.sh deleted file mode 100755 index 63be16c1..00000000 --- a/clashoo/files/usr/share/clashoo/update/template_merge.sh +++ /dev/null @@ -1,101 +0,0 @@ -#!/bin/sh - -set -eu - -SUB_FILE="${1:-}" -TEMPLATE_FILE="${2:-}" -OUT_FILE="${3:-}" -TMP_FILE="/tmp/clash_template_merge_$$.yaml" -TMP_FILE2="${TMP_FILE}.norm" -LOG_FILE="/tmp/clash_update.txt" - -log() { - printf ' %s - %s\n' "$(date '+%Y-%m-%d %H:%M:%S')" "$1" >>"$LOG_FILE" -} - -cleanup() { - rm -f "$TMP_FILE" "$TMP_FILE2" >/dev/null 2>&1 || true -} -trap cleanup EXIT INT TERM - -[ -n "$SUB_FILE" ] || { log "模板复写失败:缺少订阅文件参数"; exit 1; } -[ -n "$TEMPLATE_FILE" ] || { log "模板复写失败:缺少模板文件参数"; exit 1; } -[ -n "$OUT_FILE" ] || { log "模板复写失败:缺少输出文件参数"; exit 1; } - -[ -f "$SUB_FILE" ] || { log "模板复写失败:订阅文件不存在"; exit 1; } -[ -f "$TEMPLATE_FILE" ] || { log "模板复写失败:模板文件不存在"; exit 1; } - -if ! command -v yq >/dev/null 2>&1; then - log "模板复写失败:缺少 yq" - exit 1 -fi - -core_bin="" -for b in mihomo clash-meta clash; do - if command -v "$b" >/dev/null 2>&1; then - core_bin="$b" - break - fi -done - -mkdir -p "$(dirname "$OUT_FILE")" >/dev/null 2>&1 - -log "开始模板复写:$(basename "$SUB_FILE") <- $(basename "$TEMPLATE_FILE")" -export SUB_FILE TEMPLATE_FILE - -# template is base; load() forces single-doc; explode anchors first (yq 4.53+ breaks "<<") -yq -n ' - (load(strenv(SUB_FILE)) | explode(.)) as $sub | - (load(strenv(TEMPLATE_FILE)) | explode(.)) as $tpl | - ( - ($tpl * { - "proxies": (((($tpl.proxies // []) + ($sub.proxies // [])) | unique_by(.name))), - "proxy-providers": (($tpl."proxy-providers" // {}) * ($sub."proxy-providers" // {})) - }) - | .dns = ((.dns // {}) * { - "proxy-server-nameserver": ( - .dns."proxy-server-nameserver" - // $sub.dns."proxy-server-nameserver" - // $sub.dns.nameserver - // ["223.5.5.5", "119.29.29.29"] - ) - }) - ) -' >"$TMP_FILE" 2>/dev/null || { - log "模板复写失败:YAML 合并错误" - exit 1 -} - -# 兼容第三方模板中使用“直连”字样,统一转换为 Clash 内置 DIRECT。 -yq e ' - (.. | select(tag == "!!str")) |= sub("^直连$", "DIRECT") - | .rules = ((.rules // []) | map(sub(",直连,", ",DIRECT,") | sub(",直连$", ",DIRECT"))) -' "$TMP_FILE" >"$TMP_FILE2" 2>/dev/null || { - log "模板复写失败:直连别名标准化失败" - exit 1 -} -mv -f "$TMP_FILE2" "$TMP_FILE" >/dev/null 2>&1 || { - log "模板复写失败:中间文件写入失败" - exit 1 -} - -yq e '.' "$TMP_FILE" >/dev/null 2>&1 || { - log "模板复写失败:合并结果 YAML 无效" - exit 1 -} - -if [ -n "$core_bin" ]; then - "$core_bin" -t -f "$TMP_FILE" >/dev/null 2>&1 || { - log "模板复写失败:内核校验不通过" - exit 1 - } -fi - -mv -f "$TMP_FILE" "$OUT_FILE" >/dev/null 2>&1 || { - log "模板复写失败:写入输出文件失败" - exit 1 -} - -chmod 644 "$OUT_FILE" >/dev/null 2>&1 || true -log "模板复写完成:$(basename "$OUT_FILE")" -exit 0 diff --git a/clashoo/files/usr/share/clashoo/update/update.sh b/clashoo/files/usr/share/clashoo/update/update.sh deleted file mode 100755 index 0b0a8936..00000000 --- a/clashoo/files/usr/share/clashoo/update/update.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/sh - -config_name="${1:-$(uci -q get clashoo.config.config_update_name 2>/dev/null)}" -[ -n "$config_name" ] || exit 1 -exec sh /usr/share/clashoo/update/subscription_update.sh --mihomo "$config_name" diff --git a/clashoo/files/usr/share/clashoo/update/update_all.sh b/clashoo/files/usr/share/clashoo/update/update_all.sh deleted file mode 100755 index b743529d..00000000 --- a/clashoo/files/usr/share/clashoo/update/update_all.sh +++ /dev/null @@ -1,20 +0,0 @@ -#!/bin/sh - -UPDATE_LOG="/tmp/clash_update.txt" -STATE_DIR="${CLASHOO_STATE_DIR:-/usr/share/clashbackup}" - -log_update() { - printf ' %s - %s\n' "$(date '+%Y-%m-%d %H:%M:%S')" "$1" >>"$UPDATE_LOG" -} - -log_update "更新大陆白名单" -sh /usr/share/clashoo/update/update_china_ip.sh >> "$UPDATE_LOG" 2>&1 - -log_update "更新 GeoIP / GeoSite" -sh /usr/share/clashoo/update/geoip.sh >/dev/null 2>&1 - -mkdir -p "$STATE_DIR" -tmp="$STATE_DIR/rule_update.status.tmp.$$" -printf 'last_run=%s\n' "$(date +%s)" >"$tmp" && mv -f "$tmp" "$STATE_DIR/rule_update.status" - -exit 0 diff --git a/clashoo/files/usr/share/clashoo/update/update_china_ip.sh b/clashoo/files/usr/share/clashoo/update/update_china_ip.sh deleted file mode 100755 index 8d31b73d..00000000 --- a/clashoo/files/usr/share/clashoo/update/update_china_ip.sh +++ /dev/null @@ -1,237 +0,0 @@ -#!/bin/sh - -set -eu - -LOG_FILE="${LOG_FILE:-/tmp/clash_update.txt}" -NFT_DIR="${NFT_DIR:-/usr/share/clashoo/nftables}" -TARGET_V4="${NFT_DIR}/geoip_cn.nft" -TARGET_V6="${NFT_DIR}/geoip6_cn.nft" -FW4_SCRIPT="${FW4_SCRIPT:-/usr/share/clashoo/net/fw4.sh}" -PROC_ROOT="${PROC_ROOT:-/proc}" -SINGBOX_BIN_DIR="${SINGBOX_BIN_DIR:-/usr/share/clashoo/bin}" -TMP_ROOT="$(mktemp -d /tmp/clashoo_china_ip.XXXXXX)" -TMP_V4="$TMP_ROOT/china_ip.txt" -TMP_V6="$TMP_ROOT/china_ipv6.txt" -OUT_V4="$TMP_ROOT/geoip_cn.nft" -OUT_V6="$TMP_ROOT/geoip6_cn.nft" - -log() { - printf ' %s - %s\n' "$(date '+%Y-%m-%d %H:%M:%S')" "$1" >> "$LOG_FILE" -} - -bool_enabled() { - case "$1" in - 1|true|TRUE|yes|on) return 0 ;; - *) return 1 ;; - esac -} - -download_with_fallback() { - local url="$1" - local output="$2" - local ip - - if curl -fsSL --connect-timeout 10 --max-time 120 "$url" -o "$output"; then - return 0 - fi - - case "$url" in - https://ispip.clang.cn/*) - for ip in 182.247.248.127 103.220.64.183; do - if curl -fsSL --connect-timeout 10 --max-time 120 --resolve "ispip.clang.cn:443:${ip}" "$url" -o "$output"; then - log "DNS 异常,已使用 --resolve(${ip}) 回源下载" - return 0 - fi - done - ;; - esac - - return 1 -} - -cleanup() { - rm -rf "$TMP_ROOT" -} - -trap cleanup EXIT INT TERM - -render_nft_set() { - local source_file="$1" - local output_file="$2" - local set_name="$3" - local set_type="$4" - - awk -v set_name="$set_name" -v set_type="$set_type" ' - function valid_cidr(value, parts, octets, i, prefix) { - if (split(value, parts, "/") != 2 || parts[2] !~ /^[0-9]+$/) - return 0 - prefix = parts[2] + 0 - if (set_type == "ipv4_addr") { - if (prefix > 32 || split(parts[1], octets, ".") != 4) - return 0 - for (i = 1; i <= 4; i++) - if (octets[i] !~ /^[0-9]+$/ || length(octets[i]) > 3 || octets[i] + 0 > 255) - return 0 - return 1 - } - return set_type == "ipv6_addr" && prefix <= 128 && - parts[1] ~ /^[0-9A-Fa-f:]+$/ && index(parts[1], ":") > 0 - } - BEGIN { - print "set " set_name " {" - print "\ttype " set_type ";" - print "\tflags interval;" - print "\tauto-merge;" - print "\telements = {" - first = 1 - } - !/^[[:space:]]*$/ && !/^[[:space:]]*#/ { - gsub(/^[[:space:]]+|[[:space:]]+$/, "", $0) - if ($0 == "") - next - if (!valid_cidr($0)) { - if (!invalid) - printf "invalid CIDR at line %d\n", NR > "/dev/stderr" - invalid = 1 - next - } - if (!first) - print "," - printf "\t\t%s", $0 - first = 0 - } - END { - if (!first) - print "" - print "\t}" - print "}" - if (invalid || first) - exit 1 - } - ' "$source_file" > "$output_file" || return 1 - # nft catches malformed IPv6 forms and invalid network prefixes before replacement. - { printf 'table inet clashoo_validate {\n'; cat "$output_file"; printf '\n}\n'; } | - nft -c -f - >/dev/null 2>&1 -} - -url4="$(uci -q get clashoo.config.china_ip_url 2>/dev/null || true)" -url6="$(uci -q get clashoo.config.china_ipv6_url 2>/dev/null || true)" -bypass_china="$(uci -q get clashoo.config.bypass_china 2>/dev/null || true)" -bypass_china_ipv6="$(uci -q get clashoo.config.bypass_china_ipv6 2>/dev/null || true)" -[ -n "$bypass_china_ipv6" ] || bypass_china_ipv6="$bypass_china" - -[ -n "$url4" ] || url4='https://ispip.clang.cn/all_cn.txt' -[ -n "$url6" ] || url6='https://ispip.clang.cn/all_cn_ipv6.txt' - -mkdir -p "$NFT_DIR" - -log '开始更新大陆白名单' - -download_with_fallback "$url4" "$TMP_V4" -[ -s "$TMP_V4" ] || { - log '大陆 IPv4 白名单下载失败:返回为空' - exit 1 -} -changed=0 - -if ! render_nft_set "$TMP_V4" "$OUT_V4" clashoo_china ipv4_addr; then - log '大陆 IPv4 白名单包含无效 CIDR,保留原文件' - exit 1 -fi -if cmp -s "$OUT_V4" "$TARGET_V4"; then - log '大陆 IPv4 白名单内容无变化' -else - mv "$OUT_V4" "$TARGET_V4" - chmod 644 "$TARGET_V4" >/dev/null 2>&1 || true - changed=1 - log '大陆 IPv4 白名单更新完成' -fi - -if download_with_fallback "$url6" "$TMP_V6"; then - if [ -s "$TMP_V6" ]; then - if ! render_nft_set "$TMP_V6" "$OUT_V6" clashoo_china6 ipv6_addr; then - log '大陆 IPv6 白名单包含无效 CIDR,保留原文件' - exit 1 - fi - if cmp -s "$OUT_V6" "$TARGET_V6"; then - log '大陆 IPv6 白名单内容无变化' - else - mv "$OUT_V6" "$TARGET_V6" - chmod 600 "$TARGET_V6" >/dev/null 2>&1 || true - changed=1 - log '大陆 IPv6 白名单更新完成' - fi - else - log '大陆 IPv6 白名单下载为空,保留原文件' - fi -else - log '大陆 IPv6 白名单下载失败,保留原文件' -fi - -instance_pid() { - local service="$1" - local instance="${2:-}" - local filter - if [ -n "$instance" ]; then - filter="@.${service}.instances.${instance}.pid" - else - filter="@[\"${service}\"].instances.*.pid" - fi - ubus call service list "{\"name\":\"$service\",\"verbose\":true}" 2>/dev/null | - jsonfilter -e "$filter" 2>/dev/null | head -n1 -} - -pid_running() { - [ -n "$1" ] && [ -d "$PROC_ROOT/$1" ] -} - -singbox_pid_owns_private_binary() { - local pid="$1" exe cmdline - pid_running "$pid" || return 1 - exe="$(readlink -f "$PROC_ROOT/$pid/exe" 2>/dev/null)" - case "$exe" in - "$SINGBOX_BIN_DIR/sing-box-stable"|"$SINGBOX_BIN_DIR/sing-box-alpha") return 0 ;; - esac - cmdline="$(tr '\000' ' ' < "$PROC_ROOT/$pid/cmdline" 2>/dev/null)" - case "$cmdline" in - "$SINGBOX_BIN_DIR/sing-box-stable"|"$SINGBOX_BIN_DIR/sing-box-stable "*|"$SINGBOX_BIN_DIR/sing-box-alpha"|"$SINGBOX_BIN_DIR/sing-box-alpha "*) return 0 ;; - esac - return 1 -} - -selected_core_running() { - local name pid - if [ "$(uci -q get clashoo.config.core_type 2>/dev/null)" = "singbox" ]; then - name="clashoo" - pid="$(instance_pid "$name" singbox)" - singbox_pid_owns_private_binary "$pid" - return $? - else - name="clashoo" - fi - pid="$(instance_pid "$name")" - pid_running "$pid" -} - -firewall_managed() { - bool_enabled "$(uci -q get clashoo.config.enable 2>/dev/null)" || return 1 - [ "$(uci -q get clashoo.config.core_only 2>/dev/null)" = "1" ] && return 1 - selected_core_running -} - -if [ "$changed" -eq 0 ]; then - log '白名单内容未变,跳过防火墙重载' -elif ! firewall_managed; then - log '未接管防火墙(服务未运行或仅内核模式),仅更新白名单文件' -elif bool_enabled "$bypass_china" || bool_enabled "$bypass_china_ipv6"; then - if "$FW4_SCRIPT" apply >/dev/null 2>&1; then - log "大陆白名单规则已重载(IPv4=${bypass_china:-0},IPv6=${bypass_china_ipv6:-0})" - else - log '大陆白名单规则重载失败' - exit 1 - fi -else - log '大陆 IPv4/IPv6 绕过均未启用,仅更新白名单文件' -fi - -log '大陆白名单更新流程完成' diff --git a/clashoo/patches/001-skip-invalid-fakeip-domains.patch b/clashoo/patches/001-skip-invalid-fakeip-domains.patch deleted file mode 100644 index 9e3b042e..00000000 --- a/clashoo/patches/001-skip-invalid-fakeip-domains.patch +++ /dev/null @@ -1,91 +0,0 @@ ---- a/dns/middleware.go -+++ b/dns/middleware.go -@@ -12,6 +12,7 @@ import ( - icontext "github.com/metacubex/mihomo/context" - "github.com/metacubex/mihomo/log" - -+ M "github.com/metacubex/sing/common/metadata" - D "github.com/miekg/dns" - ) - -@@ -152,6 +153,9 @@ func withFakeIP(skipper *fakeip.Skipper, - q := r.Question[0] - - host := strings.TrimRight(q.Name, ".") -+ if !M.IsDomainName(host) { -+ return next(ctx, r) -+ } - if skipper.ShouldSkipped(host) { - return next(ctx, r) - } ---- /dev/null -+++ b/dns/middleware_test.go -@@ -0,0 +1,68 @@ -+package dns -+ -+import ( -+ "context" -+ "net/netip" -+ "testing" -+ -+ "github.com/metacubex/mihomo/component/fakeip" -+ icontext "github.com/metacubex/mihomo/context" -+ -+ D "github.com/miekg/dns" -+ "github.com/stretchr/testify/require" -+) -+ -+func TestWithFakeIPSkipsInvalidDomain(t *testing.T) { -+ pool, err := fakeip.New(fakeip.Options{ -+ IPNet: netip.MustParsePrefix("198.18.0.1/16"), -+ Size: 10, -+ }) -+ require.NoError(t, err) -+ -+ downstreamCalled := false -+ next := func(_ *icontext.DNSContext, request *D.Msg) (*D.Msg, error) { -+ downstreamCalled = true -+ response := new(D.Msg) -+ response.SetReply(request) -+ return response, nil -+ } -+ -+ request := new(D.Msg) -+ request.SetQuestion("n-relay-ipc-txc-nj-00.tplinkcloud.com.cn\\152.", D.TypeA) -+ response, err := withFakeIP(&fakeip.Skipper{}, pool, nil, 1)(next)(icontext.NewDNSContext(context.Background()), request) -+ -+ require.NoError(t, err) -+ require.True(t, downstreamCalled) -+ require.Empty(t, response.Answer) -+ _, mapped := pool.LookBack(netip.MustParseAddr("198.18.0.4")) -+ require.False(t, mapped) -+} -+ -+func TestWithFakeIPKeepsValidDomain(t *testing.T) { -+ pool, err := fakeip.New(fakeip.Options{ -+ IPNet: netip.MustParsePrefix("198.18.0.1/16"), -+ Size: 10, -+ }) -+ require.NoError(t, err) -+ -+ downstreamCalled := false -+ next := func(_ *icontext.DNSContext, request *D.Msg) (*D.Msg, error) { -+ downstreamCalled = true -+ response := new(D.Msg) -+ response.SetReply(request) -+ return response, nil -+ } -+ -+ request := new(D.Msg) -+ request.SetQuestion("n-relay-ipc-txc-nj-00.tplinkcloud.com.cn.", D.TypeA) -+ dnsCtx := icontext.NewDNSContext(context.Background()) -+ response, err := withFakeIP(&fakeip.Skipper{}, pool, nil, 1)(next)(dnsCtx, request) -+ -+ require.NoError(t, err) -+ require.False(t, downstreamCalled) -+ require.Len(t, response.Answer, 1) -+ require.Equal(t, icontext.DNSTypeFakeIP, dnsCtx.Type()) -+ host, mapped := pool.LookBack(netip.MustParseAddr("198.18.0.4")) -+ require.True(t, mapped) -+ require.Equal(t, "n-relay-ipc-txc-nj-00.tplinkcloud.com.cn", host) -+} diff --git a/ddns-go/Makefile b/ddns-go/Makefile index 9d7ccb7b..173aa1e2 100644 --- a/ddns-go/Makefile +++ b/ddns-go/Makefile @@ -1,45 +1,45 @@ # SPDX-License-Identifier: GPL-3.0-only # # Copyright (C) 2021-2026 sirpdboy -# +# include $(TOPDIR)/rules.mk PKG_NAME:=ddns-go -PKG_VERSION:=6.17.7 +PKG_VERSION:=6.17.1 PKG_RELEASE:=1 -PKG_VERSION:=6.17.7 + PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz PKG_SOURCE_URL:=https://codeload.github.com/jeessy2/ddns-go/tar.gz/v$(PKG_VERSION)? -PKG_HASH:=f7001004e092d9641aad5a94158e0b4cae4a53a7f5c7d96d5c6af3d246c56fcc +PKG_HASH:=05ae7ef07241113ee2cd861be530524f06856fc7368b84846db5137a477277ea -PKG_HASH:=f7001004e092d9641aad5a94158e0b4cae4a53a7f5c7d96d5c6af3d246c56fcc +PKG_LICENSE:=MIT PKG_LICENSE_FILES:=LICENSE -PKG_MAINTAINER:=Tianling Shen +PKG_MAINTAINER:=sirpdboy PKG_BUILD_DEPENDS:=golang/host PKG_BUILD_PARALLEL:=1 PKG_BUILD_FLAGS:=no-mips16 GO_PKG:=github.com/jeessy2/ddns-go/v6 -GO_PKG_LDFLAGS_X:=main.version=$(PKG_VERSION) +GO_PKG_LDFLAGS_X:=main.Version=$(PKG_VERSION) +GO_PKG_LDFLAGS:=$(GO_PKG_LDFLAGS_X) include $(INCLUDE_DIR)/package.mk include $(TOPDIR)/feeds/packages/lang/golang/golang-package.mk define Package/ddns-go - TITLE:=A Linux web GUI client of ddns-go SECTION:=net CATEGORY:=Network - SUBMENU:=Web Servers/Proxies - DEPENDS:=$(GO_ARCH_DEPENDS) +ca-bundle + SUBMENU:=IP Addresses and Names + TITLE:=Support IPV4 and IPV6 simple and easy-to-use IP binding domain name tool URL:=https://github.com/jeessy2/ddns-go + DEPENDS:=$(GO_ARCH_DEPENDS) +ca-bundle USERID:=ddns-go:ddns-go endef define Package/ddns-go/description - ddns-go is a automatically obtain your public IPv4 or IPv6 address and resolve it to the corresponding domain name service, - support Alidns Dnspod Cloudflare Hicloud Callback Baiducloud porkbun GoDaddy Google Domains. + A simple and easy-to-use IP binding domain name tool that supports IPV4 and IPV6. endef define Package/ddns-go/conffiles @@ -47,9 +47,10 @@ define Package/ddns-go/conffiles /etc/ddns-go/ddns-go-config.yaml endef + define Package/ddns-go/install $(call GoPackage/Package/Install/Bin,$(1)) - + $(INSTALL_DIR) $(1)/etc/init.d $(INSTALL_DIR) $(1)/etc/config $(INSTALL_BIN) $(CURDIR)/files/ddns-go.init $(1)/etc/init.d/ddns-go diff --git a/ddns-go/files/ddns-go.conf b/ddns-go/files/ddns-go.conf index 89b43d80..e13a09f6 100644 --- a/ddns-go/files/ddns-go.conf +++ b/ddns-go/files/ddns-go.conf @@ -1,9 +1,9 @@ config basic 'config' - option enabled '0' - option logger '1' - option port '9876' - option time '300' - option ctimes '5' - option skipverify '0' - option delay '0' - option dns '223.5.5.5' + option enabled '0' + option logger '1' + option port '9876' + option time '300' + option ctimes '5' + option skipverify '0' + option delay '0' + option dns '223.5.5.5' diff --git a/ddns-go/files/ddns-go.init b/ddns-go/files/ddns-go.init old mode 100755 new mode 100644 index d9389b6e..c478656e --- a/ddns-go/files/ddns-go.init +++ b/ddns-go/files/ddns-go.init @@ -1,6 +1,6 @@ #!/bin/sh /etc/rc.common # -# Copyright (C) 2021-2026 sirpdboy +# Copyright (C) 2021-2026 sirpdboy # # This file is part of ddns-go . # @@ -15,71 +15,70 @@ CONFDIR=/etc/ddns-go CONF=$CONFDIR/ddns-go-config.yaml init_yaml() { - [ -d "$CONFDIR" ] || mkdir -p "$CONFDIR" - chown -R ddns-go:ddns-go "$CONFDIR" - chmod 755 "$CONFDIR" - [ -f "$CONF" ] && chmod 644 "$CONF" + [ -d "$CONFDIR" ] || mkdir -p "$CONFDIR" + chown -R ddns-go:ddns-go "$CONFDIR" + chmod 755 "$CONFDIR" + [ -f "$CONF" ] && chmod 644 "$CONF" } build_args() { - local cfg="$1" - local args="-c $CONF" - - config_get port "$cfg" port '9876' - args="$args -l :$port" - - config_get time "$cfg" time '300' - [ -n "$time" ] && args="$args -f $time" - - config_get ctimes "$cfg" ctimes '5' - [ -n "$ctimes" ] && args="$args -cacheTimes $ctimes" - - config_get dns "$cfg" dns '223.5.5.5' - [ -n "$dns" ] && args="$args -dns $dns" - - config_get_bool noweb "$cfg" noweb 0 - [ "$noweb" -eq 1 ] && args="$args -noweb" - - config_get_bool skipverify "$cfg" skipverify 0 - [ "$skipverify" -eq 1 ] && args="$args -skipVerify" - - echo "$args" + local cfg="$1" + local args="-c $CONF" + + config_get port "$cfg" port '9876' + args="$args -l :$port" + + config_get time "$cfg" time '300' + [ -n "$time" ] && args="$args -f $time" + + config_get ctimes "$cfg" ctimes '5' + [ -n "$ctimes" ] && args="$args -cacheTimes $ctimes" + + config_get dns "$cfg" dns '223.5.5.5' + [ -n "$dns" ] && args="$args -dns $dns" + + config_get_bool noweb "$cfg" noweb 0 + [ "$noweb" -eq 1 ] && args="$args -noweb" + + config_get_bool skipverify "$cfg" skipverify 0 + [ "$skipverify" -eq 1 ] && args="$args -skipVerify" + + echo "$args" } start_instance() { - local cfg="$1" - local logger - config_get_bool enabled "$cfg" enabled 0 - [ "$enabled" -eq 0 ] && return 0 + local cfg="$1" + config_get_bool enabled "$cfg" enabled 0 + [ "$enabled" -eq 0 ] && return 0 + + config_get delay "$cfg" delay 0 + if [ "$delay" -gt 0 ]; then + local uptime=$(awk -F. '{print $1}' /proc/uptime) + [ "$uptime" -lt 120 ] && sleep "$delay" + fi + + init_yaml + + local args=$(build_args "$cfg") + + procd_open_instance + procd_set_param command $PROG $args - config_get delay "$cfg" delay 0 - if [ "$delay" -gt 0 ]; then - local uptime=$(awk -F. '{print $1}' /proc/uptime) - [ "$uptime" -lt 120 ] && sleep "$delay" - fi - - init_yaml - - local args=$(build_args "$cfg") - - procd_open_instance - procd_set_param command $PROG $args - - config_get_bool logger "$cfg" logger 1 - procd_set_param stdout "$logger" - procd_set_param stderr "$logger" - - procd_set_param user ddns-go - procd_set_param respawn - - procd_close_instance + procd_set_param stdout 1 + procd_set_param stderr 1 + procd_set_param log_level 7 + + procd_set_param user ddns-go + procd_set_param respawn + + procd_close_instance } start_service() { - config_load "$NAME" - config_foreach start_instance 'basic' + config_load "$NAME" + config_foreach start_instance 'basic' } service_triggers() { - procd_add_reload_trigger "$NAME" -} + procd_add_reload_trigger "$NAME" +} \ No newline at end of file diff --git a/doc/lucky1.png b/doc/lucky1.png new file mode 100644 index 00000000..a5b41b6e Binary files /dev/null and b/doc/lucky1.png differ diff --git a/doc/lucky2.png b/doc/lucky2.png new file mode 100644 index 00000000..ba4c026f Binary files /dev/null and b/doc/lucky2.png differ diff --git a/doc/lucky3.png b/doc/lucky3.png new file mode 100644 index 00000000..6fa7982f Binary files /dev/null and b/doc/lucky3.png differ diff --git a/doc/taskplan1.png b/doc/taskplan1.png deleted file mode 100644 index 1f8db7be..00000000 Binary files a/doc/taskplan1.png and /dev/null differ diff --git a/doc/taskplan2.png b/doc/taskplan2.png deleted file mode 100644 index edb45d6d..00000000 Binary files a/doc/taskplan2.png and /dev/null differ diff --git a/doc/taskplan3.png b/doc/taskplan3.png deleted file mode 100644 index d4794702..00000000 Binary files a/doc/taskplan3.png and /dev/null differ diff --git a/doc/view.png b/doc/view.png deleted file mode 100644 index 169e112f..00000000 Binary files a/doc/view.png and /dev/null differ diff --git a/doc/view2.png b/doc/view2.png deleted file mode 100644 index 9058c632..00000000 Binary files a/doc/view2.png and /dev/null differ diff --git a/luci-app-chatgpt-web/.github/workflows/main.yml b/luci-app-chatgpt-web/.github/workflows/main.yml deleted file mode 100644 index 3de4bc6d..00000000 --- a/luci-app-chatgpt-web/.github/workflows/main.yml +++ /dev/null @@ -1,49 +0,0 @@ -name: Build - -on: - push: - tags: - - v* - -jobs: - build: - name: Build ${{ matrix.arch }} - runs-on: ubuntu-latest - strategy: - fail-fast: false - matrix: - arch: - - - aarch64_generic - - i386_pentium-mmx - - loongarch64_generic - - mips_mips32 - - mipsel_24kc - - mipsel_mips32 - - x86_64 - - steps: - - uses: actions/checkout@main - with: - fetch-depth: 0 - - name: Building packages - uses: sbwml/openwrt-gh-action-sdk@go1.24 - env: - ARCH: ${{ matrix.arch }}-openwrt-24.10 - FEEDNAME: packages_ci - PACKAGES: luci-app-chatgpt-web - NO_REFRESH_CHECK: true - - - name: Upload artifacts - uses: actions/upload-artifact@v4 - with: - name: ${{ matrix.arch }} - path: bin/packages/${{ matrix.arch }}/packages_ci/*.ipk - - - name: Upload packages - uses: ncipollo/release-action@v1 - with: - token: ${{ secrets.GITHUB_TOKEN }} - allowUpdates: true - replacesArtifacts: true - artifacts: "bin/packages/${{ matrix.arch }}/packages_ci/*.ipk" diff --git a/luci-app-chatgpt-web/Makefile b/luci-app-chatgpt-web/Makefile deleted file mode 100644 index b5cae97b..00000000 --- a/luci-app-chatgpt-web/Makefile +++ /dev/null @@ -1,22 +0,0 @@ -# SPDX-License-Identifier: GPL-3.0-only -# -# Copyright (C) 2023-2025 sirpdboy https://github.com/sirpdboy/luci-app-chatgpt-web -# -# This is free software, licensed under the Apache License, Version 2.0 . -# -include $(TOPDIR)/rules.mk - -NAME:=chatgpt-web -PKG_NAME:=luci-app-$(NAME) -PKG_VERSION:=1.2.1 -PKG_RELEASE:=16 - -LUCI_TITLE:=LuCI Support for chatgpt-web Client -LUCI_PKGARCH:=all - -define Package/$(PKG_NAME)/conffiles -/etc/config/chatgpt-web -endef -include $(TOPDIR)/feeds/luci/luci.mk - -# call BuildPackage - OpenWrt buildroot signature diff --git a/luci-app-chatgpt-web/README.md b/luci-app-chatgpt-web/README.md deleted file mode 100644 index ab5de559..00000000 --- a/luci-app-chatgpt-web/README.md +++ /dev/null @@ -1,179 +0,0 @@ -## 访问数:![hello](https://views.whatilearened.today/views/github/sirpdboy/deplives.svg)[![](https://img.shields.io/badge/TG群-点击加入-FFFFFF.svg)](https://t.me/joinchat/AAAAAEpRF88NfOK5vBXGBQ) - - - -

-
luci-app-chatgpt-web
-

- -

-OpenWrt -Chrome -Safari -Firefox - GitHub release -Downloads -

- - -![screenshots](https://raw.githubusercontent.com/sirpdboy/openwrt/master/doc/说明1.jpg) - -请 **认真阅读完毕** 本页面,本页面包含注意事项和如何使用。 - -## 功能说明 - -luci-app-chatgpt Pure ChatGPT by OPENWRT based on OpenAI API - -luci-app-chatgpt 在OPENWRT上实现ChatGPT项目,基于OpenAI API - - - -- [luci-app-chatgpt](#功能说明) - - [特性](#特性) - - [编译方法](#编译方法) - - [使用方法](#使用方法) - - [自定义选项](#自定义选项)。 - - [说明](#说明) - - [界面](#界面) - - [捐助](#捐助) - - - -## 特性 - -- 无须第三依赖,直接使用官方API接口。 -- 支持复制/更新/刷新会话,语音输入,朗读等功能,以及众多[自定义选项](#自定义选项)。 -- 支持搜索会话,导入导出会话和设置,自定义头像,自定义系统角色等。 - -参考项目: -[markdown-it](https://github.com/markdown-it/markdown-it), -[highlight.js](https://github.com/highlightjs/highlight.js), -[github-markdown-css](https://github.com/sindresorhus/github-markdown-css), -[chatgpt-html](https://github.com/slippersheepig/chatgpt-html), -[markdown-it-copy](https://github.com/ReAlign/markdown-it-copy), -[markdown-it-texmath](https://github.com/goessner/markdown-it-texmath), -[awesome-chatgpt-prompts-zh](https://github.com/PlexPt/awesome-chatgpt-prompts-zh) - - -## 编译方法 - -- 将luci-app-chatgpt添加至 LEDE/OpenWRT 源码的方法。 - -### 下载源码方法: - - ```Brach - - # 下载源码 - - git clone https://github.com/sirpdboy/chatgpt-web.git package/luci-app-chatgpt - make menuconfig - - ``` -### 配置菜单 - - ```Brach - make menuconfig - # 找到 LuCI -> Applications, 选择 luci-app-chatgpt, 保存后退出。 - ``` - -### 编译 - - ```Brach - # 编译固件 - make package/luci-app-chatgpt/compile V=s - ``` - -## 使用方法 - - - 打开luci-app-chatgpt基本设置,填写API密钥、GPT模型、填写OpenAI接口、选择用户图像等。 - - - 可选GPT模型,默认gpt-3.5,当前使用gpt-4模型需通过openai的表单申请。 - - - OpenAI接口当本地可正常访问`api.openai.com`,填写`https://api.openai.com/` - - - 不可正常访问`api.openai.com`,填写其反代地址,注意:反代接口响应需添加跨域Header `Access-Control-Allow-Origin` - - - chatgpt-web页面就可以正常使用了,如果需要设置更多请看 自定义设置设置语音和系统角色等。 - -## 自定义选项 - -- 左边栏支持,清除对话,搜索会话,新建/重命名/删除(会话/文件夹)导出/导入/重置会话和设置数据,显示本地存储。 - -- 可选系统角色,默认不开启,有四个预设角色,后期会加入更多角色。 - -- 可选角色性格,默认灵活创新,对应接口文档的top_p参数。 - -- 可选回答质量,默认平衡,对应接口文档的temperature参数。 - -- 修改打字机速度,默认较快,值越大速度越快。 - -- 允许连续对话,默认开启,对话中包含上下文信息,会导致api费用增加。 - -- 允许长回复,默认关闭,**开启后可能导致api费用增加,并丢失大部分上下文,对于一些要发送`继续`才完整的回复,不用发`继续`了。** - -- 选择语音,默认Bing语音,支持Azure语音和系统语音,可分开设置提问语音和回答语音。 - -- 音量,默认最大。 - -- 语速,默认正常。 - -- 音调,默认正常。 - -- 允许连续朗读,默认开启,连续郎读到所有对话结束。 - -- 允许自动朗读,默认关闭,自动朗读新的回答。**(iOS需打开设置-自动播放视频预览,Mac上Safari需打开此网站的设置-允许全部自动播放)** - -- 支持语音输入,默认识别为普通话,可长按语音按钮修改识别选项。**语音识别必需条件:使用chrome内核系浏览器 + https网页或本地网页。** 如点击语音按钮没反应,可能是未授予麦克风权限或者没安装麦克风设备。 - - -## 说明 - --源码来源:https://github.com/sirpdboy/chatgpt-web --你可以随意使用其中的源码,但请注明出处。 - -![screenshots](https://raw.githubusercontent.com/sirpdboy/openwrt/master/doc/说明2.jpg) - -## 界面 - -![screenshots](./doc/chatgpt1.png) - -![screenshots](./doc/chatgpt2.png) - -![screenshots](./doc/chatgpt3.png) - - -## 使用与授权相关说明 - -- 本人开源的所有源码,任何引用需注明本处出处,如需修改二次发布必告之本人,未经许可不得做于任何商用用途。 - -# My other project - -- 路由安全看门狗 :https://github.com/sirpdboy/luci-app-watchdog -- 网络速度测试 :https://github.com/sirpdboy/luci-app-netspeedtest -- 计划任务插件(原定时设置) : https://github.com/sirpdboy/luci-app-taskplan -- 关机功能插件 : https://github.com/sirpdboy/luci-app-poweroffdevice -- opentopd主题 : https://github.com/sirpdboy/luci-theme-opentopd -- kucat酷猫主题: https://github.com/sirpdboy/luci-theme-kucat -- kucat酷猫主题设置工具: https://github.com/sirpdboy/luci-app-kucat-config -- NFT版上网时间控制插件: https://github.com/sirpdboy/luci-app-timecontrol -- 家长控制: https://github.com/sirpdboy/luci-theme-parentcontrol -- 定时限速: https://github.com/sirpdboy/luci-app-eqosplus -- 系统高级设置 : https://github.com/sirpdboy/luci-app-advanced -- ddns-go动态域名: https://github.com/sirpdboy/luci-app-ddns-go -- 进阶设置(系统高级设置+主题设置kucat/agron/opentopd): https://github.com/sirpdboy/luci-app-advancedplus -- 网络设置向导: https://github.com/sirpdboy/luci-app-netwizard -- 一键分区扩容: https://github.com/sirpdboy/luci-app-partexp -- lukcy大吉: https://github.com/sirpdboy/luci-app-lukcy - -## 捐助 - -![screenshots](https://raw.githubusercontent.com/sirpdboy/openwrt/master/doc/说明3.jpg) - -| 图飞了😂 | 图飞了😂 | -| :-----------------: | :-------------: | -|![xm1](https://raw.githubusercontent.com/sirpdboy/openwrt/master/doc/支付宝.png) | ![xm1](https://raw.githubusercontent.com/sirpdboy/openwrt/master/doc/微信.png) | - - - 图飞了😂 - - diff --git a/luci-app-chatgpt-web/doc/chatgpt1.png b/luci-app-chatgpt-web/doc/chatgpt1.png deleted file mode 100644 index f715b006..00000000 Binary files a/luci-app-chatgpt-web/doc/chatgpt1.png and /dev/null differ diff --git a/luci-app-chatgpt-web/doc/chatgpt2.png b/luci-app-chatgpt-web/doc/chatgpt2.png deleted file mode 100644 index 7de824a2..00000000 Binary files a/luci-app-chatgpt-web/doc/chatgpt2.png and /dev/null differ diff --git a/luci-app-chatgpt-web/doc/chatgpt3.png b/luci-app-chatgpt-web/doc/chatgpt3.png deleted file mode 100644 index 9d280941..00000000 Binary files a/luci-app-chatgpt-web/doc/chatgpt3.png and /dev/null differ diff --git a/luci-app-chatgpt-web/luasrc/controller/chatgpt-web.lua b/luci-app-chatgpt-web/luasrc/controller/chatgpt-web.lua deleted file mode 100644 index c100132c..00000000 --- a/luci-app-chatgpt-web/luasrc/controller/chatgpt-web.lua +++ /dev/null @@ -1,17 +0,0 @@ --- Copyright (C) 2023-2025 sirpdboy https://github.com/sirpdboy/luci-app-chatgpt-web --- Licensed to the public under the Apache License 2.0. - -module("luci.controller.chatgpt-web", package.seeall) - -function index() - if not nixio.fs.access("/etc/config/chatgpt-web") then - return - end - - local e = entry({"admin", "services", "chatgpt-web"}, alias("admin", "services", "chatgpt-web", "setting"),_("Chatgpt Web"), 20) - e.dependent=false - e.acl_depends = { "luci-app-chatgpt-web" } - entry({"admin", "services", "chatgpt-web", "setting"}, cbi("chatgpt-web"), _("Base Setting"), 10).leaf=true - entry({"admin", "services", "chatgpt-web", "chatgpt-web"}, cbi("chatgpt",{hideapplybtn=true, hidesavebtn=true, hideresetbtn=true}), _("Chatgpt Web"), 30).leaf=true -end - diff --git a/luci-app-chatgpt-web/luasrc/model/cbi/chatgpt-web.lua b/luci-app-chatgpt-web/luasrc/model/cbi/chatgpt-web.lua deleted file mode 100644 index 38f5e7da..00000000 --- a/luci-app-chatgpt-web/luasrc/model/cbi/chatgpt-web.lua +++ /dev/null @@ -1,36 +0,0 @@ --- Copyright (C) 2023-2025 sirpdboy https://github.com/sirpdboy/https://github.com/sirpdboy/luci-app-chatgpt-web - -local m, s ,o - -m = Map("chatgpt-web") -m.title = translate("Chatgpt Web") -m.description = translate("ChatGPT-Web is the version used on OPENWRT of OPENAI")..translate("
For specific usage, see:")..translate("GitHub @sirpdboy/chatgpt-web\ ") - -s = m:section(TypedSection, "basic", translate("Base Setting")) -s.addremove = false -s.anonymous = true - - -o = s:option(Value,"userpic",translate("Character images")) -o:value("girl.jpg",translate("girl")) -o:value("girl2.jpg",translate("girl2")) -o:value("girl3.jpg",translate("girl3")) -o:value("boy.jpg",translate("boy")) -o:value("boy2.jpg",translate("boy2")) -o:value("boy3.jpg",translate("boy3")) -o:value("dog.jpg",translate("dog")) -o:value("cartoon.jpg",translate("cartoon")) -o:value("cartoonboy.jpg",translate("cartoonboy")) -o:value("cartoonboy2.jpg",translate("cartoonboy2")) -o:value("cartoongirl.jpg",translate("cartoongirl")) -o:value("cartoongirl2.jpg",translate("cartoongirl2")) -o.rmempty = true -o.default="girl.jpg" - - -o=s:option(TextValue, "systemrole" ,translate("Default Role Settings")) -o.rows = 5 -o.rmempty=false - - -return m diff --git a/luci-app-chatgpt-web/luasrc/model/cbi/chatgpt.lua b/luci-app-chatgpt-web/luasrc/model/cbi/chatgpt.lua deleted file mode 100644 index 162de6d0..00000000 --- a/luci-app-chatgpt-web/luasrc/model/cbi/chatgpt.lua +++ /dev/null @@ -1,9 +0,0 @@ --- Copyright (C) 2023-2025 sirpdboy https://github.com/sirpdboy/luci-app-chatgpt-web -require("luci.util") -local m, s - -m = Map("chatgpt-web",translate("")) - -m:section(SimpleSection).template = "chatgpt-web" - -return m diff --git a/luci-app-chatgpt-web/luasrc/view/chatgpt-web.htm b/luci-app-chatgpt-web/luasrc/view/chatgpt-web.htm deleted file mode 100644 index 078e5ac7..00000000 --- a/luci-app-chatgpt-web/luasrc/view/chatgpt-web.htm +++ /dev/null @@ -1,6845 +0,0 @@ -<%# - Copyright 2023-2025 sirpdboy Wich https://github.com/sirpdboy/luci-app-chatgpt-web - Licensed to the public under the Apache License 2.0. --%> -<% -local fs = require "nixio.fs" -local dsp = require "luci.dispatcher" -local uci = luci.model.uci.cursor() -local apikeys = uci:get_first('chatgpt-web', 'basic', 'apikey') -local userpic = "/luci-static/chatgpt-web/user/" .. uci:get_first('chatgpt-web', 'basic', 'userpic') -local sysrole = uci:get_first('chatgpt-web', 'basic', 'systemrole') - --%> - -
- - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
-
-
ChatGPT
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
- - 4o - - -
-
-
- - -
- - -
-
-
-
- -
-
-
-
- - -
- - -
-
-
-
-
-
- - - -
-
-
-
-
- - - -
-
- - - -
-
-
-
-
-
ChatGPT
-
DeepSeek
-
Azure
-
Gemini
-
Claude
-
-
- -
-
-
-
ChatGPT
-
- -
-
-
-
-
- -
-
-
-
-
- -
-
-
- - - - -
- - - -
-
-
-
- - - - - - - - - - - - - - - - -
\ No newline at end of file diff --git a/luci-app-chatgpt-web/po/zh-cn/chatgpt-web.po b/luci-app-chatgpt-web/po/zh-cn/chatgpt-web.po deleted file mode 100644 index 91654dbd..00000000 --- a/luci-app-chatgpt-web/po/zh-cn/chatgpt-web.po +++ /dev/null @@ -1,71 +0,0 @@ -msgid "" -msgstr "Content-Type: text/plain; charset=UTF-8" - -msgid "chatgpt-web" -msgstr "ChatGPT-Web" - -msgid "ChatGPT-Web is the version used on OPENWRT of OPENAI" -msgstr "ChatGPT-Web是OPENAI的OPENWRT上使用的WEB版本,不需要第三方依赖,绿色安全直接使用OPENAI的API接口" - -msgid "Base Setting" -msgstr "基本设置" - -msgid "GPT Model" -msgstr "GPT模型" - -msgid "Character images" -msgstr "人物图像" - -msgid "boy" -msgstr "男生" - -msgid "boy2" -msgstr "男生2" - -msgid "boy3" -msgstr "男生3" - -msgid "girl" -msgstr "女生" - -msgid "girl2" -msgstr "女生2" - -msgid "girl3" -msgstr "女生3" - -msgid "dog" -msgstr "狗" - -msgid "cartoon" -msgstr "卡通图像" - -msgid "cartoonboy" -msgstr "卡通男孩" - -msgid "cartoonboy2" -msgstr "卡通小男孩" - -msgid "cartoongirl" -msgstr "卡通女生" - -msgid "cartoongirl2" -msgstr "卡通女生2" - -msgid "OpenAI interface" -msgstr "OpenAI接口" - -msgid "API Key" -msgstr "API密钥" - -msgid "Enter your own API key, and if you do not have one, enter the official website API to generate it:" -msgstr "输入自己的API密钥(sk-开头),没有的进官网API生成:" - -msgid "Click to open" -msgstr "点击前往" - -msgid "Default Role Settings" -msgstr "默认角色设置" - -msgid "
For specific usage, see:" -msgstr "
具体使用方法参见:" diff --git a/luci-app-chatgpt-web/po/zh_Hans/chatgpt-web.po b/luci-app-chatgpt-web/po/zh_Hans/chatgpt-web.po deleted file mode 100644 index 91654dbd..00000000 --- a/luci-app-chatgpt-web/po/zh_Hans/chatgpt-web.po +++ /dev/null @@ -1,71 +0,0 @@ -msgid "" -msgstr "Content-Type: text/plain; charset=UTF-8" - -msgid "chatgpt-web" -msgstr "ChatGPT-Web" - -msgid "ChatGPT-Web is the version used on OPENWRT of OPENAI" -msgstr "ChatGPT-Web是OPENAI的OPENWRT上使用的WEB版本,不需要第三方依赖,绿色安全直接使用OPENAI的API接口" - -msgid "Base Setting" -msgstr "基本设置" - -msgid "GPT Model" -msgstr "GPT模型" - -msgid "Character images" -msgstr "人物图像" - -msgid "boy" -msgstr "男生" - -msgid "boy2" -msgstr "男生2" - -msgid "boy3" -msgstr "男生3" - -msgid "girl" -msgstr "女生" - -msgid "girl2" -msgstr "女生2" - -msgid "girl3" -msgstr "女生3" - -msgid "dog" -msgstr "狗" - -msgid "cartoon" -msgstr "卡通图像" - -msgid "cartoonboy" -msgstr "卡通男孩" - -msgid "cartoonboy2" -msgstr "卡通小男孩" - -msgid "cartoongirl" -msgstr "卡通女生" - -msgid "cartoongirl2" -msgstr "卡通女生2" - -msgid "OpenAI interface" -msgstr "OpenAI接口" - -msgid "API Key" -msgstr "API密钥" - -msgid "Enter your own API key, and if you do not have one, enter the official website API to generate it:" -msgstr "输入自己的API密钥(sk-开头),没有的进官网API生成:" - -msgid "Click to open" -msgstr "点击前往" - -msgid "Default Role Settings" -msgstr "默认角色设置" - -msgid "
For specific usage, see:" -msgstr "
具体使用方法参见:" diff --git a/luci-app-chatgpt-web/root/etc/config/chatgpt-web b/luci-app-chatgpt-web/root/etc/config/chatgpt-web deleted file mode 100644 index a7a1636a..00000000 --- a/luci-app-chatgpt-web/root/etc/config/chatgpt-web +++ /dev/null @@ -1,8 +0,0 @@ - -config basic - option apiHost 'https://api.openai.com/' - option modelver 'gpt-3.5-turbo' - option userpic 'girl.jpg' - option apikey '' - option systemrole '你是一个乐于助人的专业助手,尽量简明扼要地回答' - diff --git a/luci-app-chatgpt-web/root/usr/share/rpcd/acl.d/luci-app-chatgpt-web.json b/luci-app-chatgpt-web/root/usr/share/rpcd/acl.d/luci-app-chatgpt-web.json deleted file mode 100644 index c8c06f50..00000000 --- a/luci-app-chatgpt-web/root/usr/share/rpcd/acl.d/luci-app-chatgpt-web.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "luci-app-chatgpt-web": { - "description": "Grant UCI access for luci-app-chatgpt-web", - "read": { - "uci": [ "chatgpt-web" ] - }, - "write": { - "uci": [ "chatgpt-web" ] - } - } -} diff --git a/luci-app-chatgpt-web/root/www/luci-static/chatgpt-web/11.11.1github.min.css b/luci-app-chatgpt-web/root/www/luci-static/chatgpt-web/11.11.1github.min.css deleted file mode 100644 index 275239a7..00000000 --- a/luci-app-chatgpt-web/root/www/luci-static/chatgpt-web/11.11.1github.min.css +++ /dev/null @@ -1,10 +0,0 @@ -pre code.hljs{display:block;overflow-x:auto;padding:1em}code.hljs{padding:3px 5px}/*! - Theme: GitHub - Description: Light theme as seen on github.com - Author: github.com - Maintainer: @Hirse - Updated: 2021-05-15 - - Outdated base version: https://github.com/primer/github-syntax-light - Current colors taken from GitHub's CSS -*/.hljs{color:#24292e;background:#fff}.hljs-doctag,.hljs-keyword,.hljs-meta .hljs-keyword,.hljs-template-tag,.hljs-template-variable,.hljs-type,.hljs-variable.language_{color:#d73a49}.hljs-title,.hljs-title.class_,.hljs-title.class_.inherited__,.hljs-title.function_{color:#6f42c1}.hljs-attr,.hljs-attribute,.hljs-literal,.hljs-meta,.hljs-number,.hljs-operator,.hljs-selector-attr,.hljs-selector-class,.hljs-selector-id,.hljs-variable{color:#005cc5}.hljs-meta .hljs-string,.hljs-regexp,.hljs-string{color:#032f62}.hljs-built_in,.hljs-symbol{color:#e36209}.hljs-code,.hljs-comment,.hljs-formula{color:#6a737d}.hljs-name,.hljs-quote,.hljs-selector-pseudo,.hljs-selector-tag{color:#22863a}.hljs-subst{color:#24292e}.hljs-section{color:#005cc5;font-weight:700}.hljs-bullet{color:#735c0f}.hljs-emphasis{color:#24292e;font-style:italic}.hljs-strong{color:#24292e;font-weight:700}.hljs-addition{color:#22863a;background-color:#f0fff4}.hljs-deletion{color:#b31d28;background-color:#ffeef0} \ No newline at end of file diff --git a/luci-app-chatgpt-web/root/www/luci-static/chatgpt-web/chatgpt-web.css b/luci-app-chatgpt-web/root/www/luci-static/chatgpt-web/chatgpt-web.css deleted file mode 100644 index 7a24e376..00000000 --- a/luci-app-chatgpt-web/root/www/luci-static/chatgpt-web/chatgpt-web.css +++ /dev/null @@ -1,2166 +0,0 @@ - - .chat_window { - display: flex; - width: 100%; - max-width: 1920px; - height: 888px; - border-radius: 8px; - background-color: rgba(255,255,255,0.5); - overflow: auto; - } - - .chat_window>.overlay { - width: 100%; - height: 100%; - position: absolute; - left: 0; - top: 0; - background-color: rgba(0, 0, 0, .3); - z-index: 90; - opacity: 0; - visibility: hidden; - cursor: pointer; - transition: all 120ms ease-in-out; - } - - .chat_window .mainContent .cbi-input-invalid { - color: var(--title-color); - border-bottom-color: var(--title-color); - } - - - @media screen and (min-width: 800px) { - - .mainContent { - width: calc(100% - 250px); - } - - .chat_window>.nav { - position: relative; - margin-left: -250px; - transition: margin-left 250ms; - transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); - } - - .show-nav .nav { - margin-left: 0; - } - - #sysDialog { - max-width: 600px; - } - - .sysContent { - display: flex; - } - - .sysSwitch { - flex-shrink: 0; - width: 160px; - } - - .sysSwitch>div { - padding-left: 6px; - } - - .sysDetail { - margin-left: 12px; - margin-top: 5px; - } - } - - @media screen and (max-width: 800px) { - - .mainContent { - width: 100%; - } - - .chat_window>.nav { - position: absolute !important; - left: -250px; - transition: left 250ms; - transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); - } - - .show-nav .nav { - left: 0; - box-shadow: rgba(0, 0, 0, 0.2) 0px 8px 10px -5px, rgba(0, 0, 0, 0.14) 0px 16px 24px 2px, rgba(0, 0, 0, 0.12) 0px 6px 30px 5px; - } - - .show-nav .overlay { - visibility: visible; - opacity: 1; - } - - #sysDialog { - max-width: 400px; - } - - .sysSwitch { - display: flex; - } - - .sysSwitch>div { - width: 50%; - justify-content: center; - } - - .sysDetail { - margin-top: 8px; - } - } - .full_window { - max-width: none; - max-height: none; - } - - .chat_window>.nav { - width: 250px; - background-color: rgba(var(--primary-rgbbody),1); - color: var(--body-color); - top: 0; - z-index: 99; - flex-shrink: 0; - display: flex; - flex-direction: column; - margin-left: -250px; - transition: left 120ms ease-in-out; - } - - .mainContent { - height: 100%; - position: relative; - width: 100%; - display: flex; - flex-direction: column; - flex: 1; - } - - .show-nav .nav { - margin-left: 0; - } - .show-nav .chatnav { - margin-left: 0; - box-shadow: rgba(0, 0, 0, 0.2) 0px 8px 10px -5px, rgba(0, 0, 0, 0.14) 0px 16px 24px 2px, rgba(0, 0, 0, 0.12) 0px 6px 30px 5px; - } - - .show-nav .overlay { - opacity: 1; - visibility: visible; - } - .top_menu { - width: 100%; - background-color: rgba(255,255,255,0.5); - height: 50px; - padding: 5px 0; - } - - .top_menu .toggler { - margin-left: 10px; - width: 40px; - height: 40px; - float: left; - padding: 5px 7px; - border-radius: 4px; - cursor: pointer; - -webkit-tap-highlight-color: transparent; - } - - .top_menu .toggler:hover { - background: #e0e0e0; - } - - .top_menu .toggler .button { - width: 26px; - height: 4px; - border-radius: 4px; - position: absolute; - pointer-events: none; - } - - .top_menu .toggler .button.close { - margin-top: 3px; - background-color: #000; - } - - .top_menu .toggler .button.minimize { - margin-top: 13px; - background-color: #000; - } - - .top_menu .toggler .button.maximize { - margin-top: 23px; - background-color: #000; - } - - .top_menu .title { - font-size: 20px; - height: 40px; - line-height: 40px; - position: relative; - pointer-events: none; - } - - #selector { - position: absolute; - top: 50%; - left: 50%; - padding: 0 4px 0 10px; - cursor: pointer; - font-size: 20px; - transform: translate(-50%, -50%); - pointer-events: auto; - border-radius: 4px; - -webkit-user-select: none; - user-select: none; - display: flex; - align-items: center; - } - - #selector:hover { - color: var(--title-color); - } - - #modelVer { - margin-left: 6px; - margin-right: 4px; - height: 40px; - line-height: 38px; - } - - .messages { - position: relative; - flex: 1; - overflow-x: hidden; - overflow-y: auto; - font-size: 16px; - width: 100%; - text-align: center; - } - - .messages::-webkit-scrollbar, - - #chatlog .markdown-body>pre::-webkit-scrollbar, - #chatlog .markdown-body>pre>code::-webkit-scrollbar, - #chatlog .responseBody pre>code::-webkit-scrollbar, - #setDialog::-webkit-scrollbar, - .allList::-webkit-scrollbar, - .sysDetail::-webkit-scrollbar, - #apiSelect::-webkit-scrollbar { - width: 10px; - height: 10px; - } - - .messages::-webkit-scrollbar-track, - - #chatlog .markdown-body>pre::-webkit-scrollbar-track, - #chatlog .markdown-body>pre>code::-webkit-scrollbar-track, - #chatlog .responseBody pre>code::-webkit-scrollbar-track, - #setDialog::-webkit-scrollbar-track, - .allList::-webkit-scrollbar-track, - .sysDetail::-webkit-scrollbar-track, - #apiSelect::-webkit-scrollbar-track { - background-clip: padding-box; - background: transparent; - border: none; - } - - .messages::-webkit-scrollbar-corner, - - #chatlog .markdown-body>pre::-webkit-scrollbar-corner, - #chatlog .markdown-body>pre>code::-webkit-scrollbar-corner, - #chatlog .responseBody pre>code::-webkit-scrollbar-corner, - #setDialog::-webkit-scrollbar-corner, - .allList::-webkit-scrollbar-corner, - .sysDetail::-webkit-scrollbar-corner, - #apiSelect::-webkit-scrollbar-corner { - background-color: transparent; - } - - .messages::-webkit-scrollbar-thumb, - - #chatlog .markdown-body>pre::-webkit-scrollbar-thumb, - #chatlog .markdown-body>pre>code::-webkit-scrollbar-thumb, - #chatlog .responseBody pre>code::-webkit-scrollbar-thumb, - #setDialog::-webkit-scrollbar-thumb, - .allList::-webkit-scrollbar-thumb, - .sysDetail::-webkit-scrollbar-thumb, - #apiSelect::-webkit-scrollbar-thumb { - background-color: rgba(0, 0, 0, 0.1); - background-clip: padding-box; - border: solid transparent; - border-radius: 10px; - } - - .messages::-webkit-scrollbar-thumb:hover, - - #chatlog .markdown-body>pre::-webkit-scrollbar-thumb:hover, - #chatlog .markdown-body>pre>code::-webkit-scrollbar-thumb:hover, - #chatlog .responseBody pre>code::-webkit-scrollbar-thumb:hover, - #setDialog::-webkit-scrollbar-thumb:hover, - .allList::-webkit-scrollbar-thumb:hover, - .sysDetail::-webkit-scrollbar-thumb:hover, - #apiSelect::-webkit-scrollbar-thumb:hover { - background-color: rgba(0, 0, 0, 0.4); - } - - #chatlog { - word-wrap: break-word; - text-align: start; - } - - #chatlog>div { - padding: 18px 40px 18px 54px; - } - .chatAvatar { - position: absolute; - width: 30px; - height: 30px; - border-radius: 2px; - } - - .request>.chatAvatar { - top: 18px; - left: 13px; - margin-top: 15px; - margin-bottom: 15px; - } - .response>.chatAvatar { - background: #10a37f; - top: 18px; - left: 13px; - margin-top: 15px; - margin-bottom: 15px; - } - - .gptAvatar>svg { - margin-top: 3px; - margin-left: 3px; - } - - .chatAvatar>img { - display: block; - width: 100%; - height: 100%; - border-radius: 2px; - } - - .modelAvatar>svg, - .chatAvatar>svg { - display: block; - margin-top: 4px; - margin-left: 4px; - } - - #chatlog .request { - position: relative; - background-color: var(--inputborder-color); - display: flex; - justify-content: center; - } - - - .response .responseBody { - display: flex; - justify-content: flex-end; - margin: 18px 45px 18px 20px; - font-size: 15px; - - } - .requestBody { - white-space: pre-wrap; - margin: 18px; - flex: 1; - } - - #chatlog .response { - background-color: var(--inputborder-color); - position: relative; - } - - .response .markdown-body { - margin: 18px 65px 18px 0px; - flex: 1; - font-size: 15px; - background-color: rgba(255,255,255,0)!important; - - } - - #chatlog .markdown-body a { - padding: 0 1px 0 2px; - } - - #chatlog .markdown-body pre { - overflow-x: auto; - padding: 10px; - position: relative; - white-space: pre-wrap; - background-color: var(--inputborder-color)!important; - - } - - #chatlog .markdown-body .mermaid { - margin-bottom: 8px; - padding: 0 10px 0 10px; - position: relative; - border-radius: 6px; - } - - .mermaid>svg { - cursor: pointer; - max-height: 600px; - display: block; - } - - #chatlog .markdown-body pre>code { - overflow-x: auto; - white-space: pre-wrap; - display: block; - } - - #chatlog .markdown-body ul { - list-style-type: disc; - } - - .m-mdic-copy-wrapper { - position: absolute; - top: 5px; - right: 16px; - -webkit-user-select: none; - user-select: none; - } - - .m-mdic-copy-wrapper span.u-mdic-copy-code_lang { - position: absolute; - top: 3px; - right: calc(100% + 4px); - font-family: system-ui; - font-size: 12px; - line-height: 18px; - color: #bbb; - } - - .m-mdic-copy-wrapper div.u-mdic-copy-notify { - position: absolute; - top: 0; - right: 0; - padding: 3px 6px; - border: 0; - border-radius: 3px; - background: none; - font-family: system-ui; - font-size: 12px; - line-height: 18px; - color: #555; - outline: none; - right: 100%; - padding-right: 4px; - } - - .m-mdic-copy-wrapper button.u-mdic-copy-btn { - position: relative; - top: 0; - right: 0; - padding: 3px 6px; - border: 0; - border-radius: 3px; - background: none; - font-family: system-ui; - font-size: 12px; - line-height: 18px; - color: #bbb; - outline: none; - cursor: pointer; - transition: color 0.2s; - } - - .m-mdic-copy-wrapper span.u-mdic-copy-code_lang::before, - .m-mdic-copy-wrapper div.u-mdic-copy-notify::before, - .m-mdic-copy-wrapper button.u-mdic-copy-btn::before { - content: attr(text); - } - - .m-mdic-copy-wrapper button.u-mdic-copy-btn:hover { - color: #555; - } - - #stopChat { - display: none; - margin: 0 auto; - margin-top: 3px; - width: 80px; - height: 32px; - text-align: center; - line-height: 32px; - color: white; - background: #f8b26a; - cursor: pointer; - border-radius: 3px; - position: sticky; - bottom: 2px; - justify-content: center; - align-items: center; - } - - #stopChat>svg { - margin-right: 8px; - } - - #stopChat:hover { - background: #f0aa60; - } - - .bottom_wrapper { - position: relative; - width: 100%; - padding: 10px 10px; - max-width: 91%; - margin: 0 auto; - } - - .bottom_wrapper .message_input_wrapper { - width: calc(100% - 134px); - position: relative; - text-align: left; - } - - .bottom_wrapper .message_input_wrapper .message_input_text { - border-radius: 4px; - border: none; - outline: none; - resize: none; - background-color: var(--inputborder-color); - height: 47px; - font-size: 16px; - max-height: 200px; - padding: 13px 0 13px 13px; - width: 100%!important; - display: block; - transition: background-color 250ms; - } - - .bottom_wrapper .message_input_wrapper .message_input_text:focus { - background-color: var(--inputborder-color); - } - - .bottom_wrapper .message_input_wrapper .message_input_text::-webkit-scrollbar { - display: none; - width: 0; - height: 0; - } - - #sendbutton { - width: 70px; - height: 47px; - font-size: 18px; - font-weight: bold; - color: #fff; - background-color: #7ac516; - padding: 0.5rem 0.5rem; - transition: all 0.2s linear; - position: absolute; - right: 65px; - bottom: 10px; - cursor: not-allowed; - } - - .activeSendBtn { - background-color: #99c959 !important; - cursor: pointer !important; - } - - .activeSendBtn:hover { - background-color: #90c050 !important; - } - - .clearConv { - position: absolute; - right: 10px; - bottom: 10px; - width: 47px; - padding: 0.5rem 0.5rem; - height: 47px; - } - - .clearConv>svg { - margin: 0 auto; - top: 50%; - left: 50%; - } - - .clearConv:hover { - background-color: var(--body-hover-bgcolor); - } - - .clearConv svg:first-child { - display: none; - } - - .clearConv svg:nth-child(2) { - display: block; - } - - .closeConv { - background: #e0e0e0;; - } - - .closeConv:hover { - background: #e8e8e8; - } - - .closeConv svg:first-child { - display: block; - } - - .closeConv svg:nth-child(2) { - display: none; - } - - .loaded>span { - display: inline-block; - } - - .loaded>svg { - display: none; - } - - .loading { - background: rgba(0,0,0,0) !important; - } - - .loading>span { - display: none; - } - - .loading>svg { - display: block; - } - - .switch-slide { - display: inline-block; - vertical-align: middle; - } - - .switch-slide-label { - display: block; - width: 38px; - height: 18px; - background: #909090; - border-radius: 30px; - cursor: pointer; - position: relative; - -webkit-transition: 0.3s ease; - transition: 0.3s ease; - } - - .switch-slide-label:after { - content: ""; - display: block; - width: 16px; - height: 16px; - border-radius: 100%; - background: #fff; - box-shadow: 0 1px 1px rgba(0, 0, 0, .1); - position: absolute; - left: 1px; - top: 1px; - -webkit-transform: translateZ(0); - transform: translateZ(0); - -webkit-transition: all 250ms; - transition: all 250ms; - } - - .switch-slide input:checked+label { - background: #99c959; - -webkit-transition: all 250ms; - transition: all 250ms; - } - - .switch-slide input:checked+label:after { - left: 21px; - } - - .settings { - padding: 0px 7px; - margin-top: -40px; - float: right; - border-radius: 4px; - cursor: pointer; - top: 5px; - } - - - .setBtn { - margin-left: 2px; - cursor: pointer; - padding: 5px; - border: none; - border-radius: 4px; - } - - .setBtn>svg { - display: block; - color: #909090; - } - - .setBtn:hover { - background: #e0e0e0;; - } - - #setting { - right: 15px; - } - - #toggleFull { - right: 56px; - } - - #toggleLight *, - #toggleFull * { - pointer-events: none; - } - - .showSetting { - background-color: var(--inputborder-color); - } - - .showModels { - background-color: var(--inputborder-color); - } - - .showModels>svg:last-child { - transform: scaleY(-1); - } - - #modelDialog { - position: absolute; - z-index: 2; - background: rgba(var(--primary-rgbbody), 1); - width: 240px; - left: 50%; - transform: translateX(-50%); - top: 46px; - overflow-y: auto; - max-height: calc(100% - 55px); - -webkit-user-select: none; - user-select: none; - border-radius: 4px; - padding: 8px 5px 8px 5px; - box-shadow: 0 0 6px rgba(0, 0, 0, 0.15); - } - - .modelSingle { - height: 40px; - border-radius: 3px; - cursor: pointer; - line-height: 40px; - display: flex; - align-items: center; - position: relative; - } - - .modelSingle * { - pointer-events: none; - } - - .modelSingle:hover { - background-color: var(--body-hover-bgcolor); - } - - .activeModel::before { - content: ""; - position: absolute; - right: 15px; - top: 7px; - width: 8px; - height: 16px; - border-style: solid; - border-width: 0 4px 4px 0; - transform: rotate(45deg); - } - - .modelAvatar { - margin-left: 6px; - margin-right: 10px; - width: 30px; - flex-shrink: 0; - border-radius: 2px; - height: 30px; - } - - #setDialog { - position: absolute; - z-index: 2; - background-color: rgba(var(--primary-rgbbody),1); - width: 320px; - right: 6px; - top: 46px; - overflow-y: auto; - max-height: calc(100% - 55px); - -webkit-user-select: none; - user-select: none; - border-radius: 5px; - padding: 8px 12px 8px 12px; - box-shadow: 0 0 6px rgba(0, 0, 0, 0.15); - } - - #setDialog input { - width: 100%; - } - - #setDialog .inlineTitle { - display: inline-block; - width: 80px; - line-height: 16px; - vertical-align: middle; - } - - #convOption, - #speechOption, - #speechDetail, - #recOption { - margin-bottom: 6px; - } - - #convOption>div, - #speechOption>div, - #speechDetail>div, - #recOption div { - margin-top: 10px; - } - - #voiceRecSetting select, #speechDetail select { - color: var(--title-color); - - } - .inputTextClass { - outline: none; - border-radius: 2px; - margin-top: 3px; - height: 32px; - font-size: 15px; - padding-left: 6px; - border: none; - } - - .areaTextClass { - width: 100%; - height: 150px; - white-space: normal; - resize: none; - padding: 6px; - } - - input[type="range"] { - -webkit-appearance: none; - appearance: none; - display: block; - margin: 4px 0 3px 0; - height: 8px; - background: #909090; - border-radius: 5px; - background-image: linear-gradient(#99c959, #99c959); - background-size: 100% 100%; - background-repeat: no-repeat; - } - - input[type="range"]::-webkit-slider-thumb { - -webkit-appearance: none; - height: 15px; - width: 15px; - border-radius: 50%; - background: #99c959; - cursor: ew-resize; - } - - input[type=range]::-webkit-slider-runnable-track { - -webkit-appearance: none; - box-shadow: none; - border: none; - background: transparent; - } - - .justSetLine { - display: flex; - justify-content: space-between; - align-items: center; - } - - .justSetBtn { - height: 32px; - border-radius: 3px; - line-height: 32px; - background-color: var(--inputborder-color); - text-align: center; - padding: 0px 8px; - display: flex; - justify-content: center; - align-items: center; - cursor: pointer; - } - - .justSetBtn:hover { - background-color: #d0d0d0; - } - - .justSetBtn>svg { - margin-right: 3px; - } - - .readyTestVoice>div:not(:first-child) { - display: none; - } - - .pauseTestVoice>div:nth-child(1), - .pauseTestVoice>div:nth-child(3) { - display: none; - } - - .resumeTestVoice>div:nth-child(1), - .resumeTestVoice>div:nth-child(2) { - display: none; - } - - .presetSelect>div { - display: inline-block; - } - - .presetSelect select { - outline: none; - border-radius: 3px; - width: 120px; - border-color: rgba(0, 0, 0, .3); - } - - .selectDef { - display: flex; - justify-content: space-between; - font-size: 13px; - color: #909090; - } - - #preSetSpeech { - width: 100%; - outline: none; - height: 30px; - line-height: 30px; - font-size: 14px; - margin-top: 5px; - border-radius: 3px; - border-color: rgba(0, 0, 0, .3); - } - - .mdOption { - position: absolute; - right: 0px; - top: 0; - width: 50px; - height: 100%; - pointer-events: none; - } - - .mdOption>div { - pointer-events: auto; - cursor: pointer; - } - - .mdOption svg * { - pointer-events: none; - } - - .refreshReq svg:not(:first-child) { - display: none; - } - - .halfRefReq svg:not(:nth-child(2)) { - display: none; - } - - .optionItems { - position: absolute; - bottom: -5px; - display: flex; - justify-content: space-between; - visibility: visible; - z-index: 1; - color: #808080; - } - - .optionItems:hover { - visibility: visible; - } - - .request:hover .optionItems, - .request:hover .voiceCls, - .response:hover .optionItems, - .response:hover .voiceCls { - visibility: visible; - } - - .optionItem { - border-radius: 10px; - height: 24px; - width: 32px; - border: 1px solid #e0e0e0;; - background-color: #f7f7f8; ; - display: flex !important; - justify-content: center; - align-items: center; - } - - .optionItem * { - pointer-events: none; - } - - .optionItem:hover { - background: #e0e0e0;; - } - - .voiceCls { - position: relative; - height: 100%; - visibility: visible; - display: flex; - align-items: center; - } - - .voiceCls>svg { - color: #c0c0c0; - display: block; - margin-left: 5px; - position: relative; - pointer-events: none; - } - - .voiceCls:hover>svg { - color: #808080; - } - - .showVoiceCls, - .showVoiceCls .markdown-body { - background: #e0e0e0 !important; - } - - .showVoiceCls .voiceCls { - visibility: visible !important; - } - - .showEditReq { - position: sticky !important; - top: 0; - bottom: 0; - z-index: 1; - } - - .showEditReq, - .showEditReq .markdown-body { - background: #e0e0e0 !important; - } - - .readyVoice svg:not(:first-child) { - display: none; - } - - .pauseVoice svg:not(:nth-child(2)) { - display: none; - } - - .resumeVoice svg:not(:nth-child(3)) { - display: none; - } - - #voiceTypes>span { - border-radius: 3px; - margin-left: 4px; - cursor: pointer; - color: var(--title-color); - padding: 1px 5px; - } - - #voiceTypes>span:hover { - background-color: var(--body-hover-bgcolor); - } - - .selVoiceType { - background-color: var(--inputborder-color); - } - - .navHeader { - width: 100%; - padding: 5px 10px; - display: flex; - justify-content: space-between; - } - - #newChat { - text-align: center; - width: 80%; - height: 40px; - border-radius: 3px; - background: var(--inputborder-color); - display: flex; - align-items: center; - justify-content: center; - -webkit-user-select: none; - user-select: none; - cursor: pointer; - flex: 1; - } - - .navHeader>div:hover { - background: var(--body-hover-bgcolor)!important; - } - - #newChat>svg { - margin-right: 2px; - } - - #newFolder { - height: 40px; - width: 40px; - margin-left: 10px; - border-radius: 3px; - background: var(--inputborder-color); - cursor: pointer; - position: relative; - -webkit-user-select: none; - user-select: none; - } - - #newFolder>svg { - display: block; - margin: 8px auto; - } - - .extraChat { - padding: 2px 10px 6px 10px; - position: relative; - } - - #searchChat { - width: 100%; - height: 36px; - padding-left: 10px; - padding-right: 16px; - font-size: 16px; - outline: none; - border: none; - background: var(--inputborder-color); - border-radius: 3px; - } - - #searchChat:focus { - background: var(--inputborder-color); - } - - #searchChat:placeholder-shown+#clearSearch { - display: none; - } - - #clearSearch { - position: absolute; - right: 12px; - top: 8px; - cursor: pointer; - } - - #clearSearch:hover { - color: var(--title-color); - } - - #clearSearch>svg { - display: block; - } - - .seledSearch { - background: var(--inputborder-color)!important; - } - - #matchCaseSearch { - position: absolute; - right: 12px; - top: 8px; - cursor: pointer; - border-radius: 3px; - color: var(--inputborder-color); - } - - #matchCaseSearch:hover { - background: var(--body-hover-bgcolor); - } - - #matchCaseSearch>svg { - display: block; - } - - .navFooter { - padding-bottom: 8px; - background: var(--inputborder-color); - } - - .navFooter .divider { - width: 100%; - border-top: 1px solid var(--inputborder-color); - margin: 4px 0; - } - - .navFunc { - padding-top: 5px; - display: flex; - justify-content: space-evenly; - } - - .navFunc svg { - display: block; - } - - .navFunc>div, - .navFunc>label { - border-radius: 20px; - text-align: center; - padding: 8px 8px; - font-size: 14px; - cursor: pointer; - } - - .navFunc>div:hover, - .navFunc>label:hover { - background: var(--body-hover-bgcolor); - } - - .navFooter .links { - text-align: center; - -webkit-user-select: none; - user-select: none; - } - - .navFooter .links a { - text-decoration: none; - } - - - .allList { - width: 100%; - flex: 1; - overflow-y: auto; - } - - #chatList { - min-height: 50px; - } - - .dragingLi { - filter: brightness(90%); - } - - .dragingChat { - background: #e8e8e8; - } - - .expandFolder>.headLi>svg { - transform: rotate(90deg); - } - - .expandFolder>.chatsInFolder { - display: block; - } - - .chatsInFolder { - display: none; - margin-left: 22px; - padding-left: 2px; - border-left: 1px solid #909090; ; - } - - .headLi, - .chatLi { - cursor: pointer; - width: 100%; - height: 50px; - display: flex; - justify-content: space-between; - align-items: center; - position: relative; - } - - .headLi *, - .chatLi * { - pointer-events: none; - } - - .headLi>svg, - .chatLi>svg { - margin-left: 10px; - pointer-events: none; - } - - .folderOption svg, - .chatOption svg { - pointer-events: auto; - } - - .headLi svg *, - .chatLi svg * { - pointer-events: none; - } - - .headLi .folderInfo { - position: absolute; - left: 40px; - height: 40px; - max-width: calc(100% - 115px); - } - - .chatLi .chatInfo { - position: absolute; - left: 45px; - height: 40px; - max-width: calc(100% - 100px); - } - - .folderInfo *, - .chatInfo * { - -webkit-user-select: none; - user-select: none; - } - - .chatInfo span { - background: var(--inputborder-color)!important; - } - - .headLi .folderName, - .chatLi .chatName { - text-overflow: ellipsis; - white-space: nowrap; - overflow: hidden; - line-height: 20px; - height: 20px; - } - - .headLi .folderNum, - .chatLi .chatPre { - text-overflow: ellipsis; - white-space: nowrap; - overflow: hidden; - font-size: 12px; - line-height: 20px; - height: 20px; - } - - .headLi .folderOption, - .chatLi .chatOption { - visibility: hidden; - display: flex; - margin-right: 5px; - } - - .folderLi .chatLi>svg { - margin-left: 5px; - } - - .folderLi .chatLi .chatInfo { - left: 35px; - max-width: calc(100% - 85px); - } - - .folderLi .chatLi #activeChatEdit { - left: 32px; - width: calc(100% - 60px) - } - - .folderLi:hover { - background: var(--body-hover-bgcolor)!important; - } - - .chatLi:hover { - background: var(--body-hover-bgcolor)!important; - } - - .headLi:hover .folderOption, - .chatLi:hover .chatOption { - visibility: visible !important; - } - - .activeFolder, - .activeChatLi { - background: var(--inputborder-color)!important; - } - - .activeChatLi .chatOption { - visibility: visible !important; - } - - .folderOption>svg:hover, - .chatOption>svg:hover { - color: var(--title-color); - } - - #activeChatEdit { - position: absolute; - left: 42px; - font-size: 16px; - border-radius: 2px; - color: var(--title-color); - background-color: rgba(var(--primary-rgbbody),1); - outline: none; - border: none; - pointer-events: auto; - height: 24px; - line-height: 24px; - width: calc(100% - 75px); - padding: 20px 3px; - z-index: 1; - } - - #loadMask { - position: fixed; - top: 0; - left: 0; - right: 0; - bottom: 0; - z-index: 100; - background-color: #edeff2; - } - - #loadMask>div { - position: absolute; - left: 50%; - top: 50%; - transform: translate(-50%, -50%); - text-align: center; - } - - @keyframes loading { - - 0%, - 100% { - transform: scale(0); - } - - 50% { - transform: scale(1); - } - } - - .loadingCSSIcon { - position: relative; - display: flex; - align-items: center; - justify-content: space-evenly; - } - - .loadingCSSIcon div { - width: 15%; - height: 0; - padding-bottom: 15%; - border-radius: 50%; - animation: loading 1s cubic-bezier(0.3, 0, 0.7, 1) infinite; - } - - .loadingCSSIcon div:nth-child(1) { - background: #e15b64; - animation-delay: -0.4s - } - - .loadingCSSIcon div:nth-child(2) { - background: #f8b26a; - animation-delay: -0.2s - } - - .loadingCSSIcon div:nth-child(3) { - background: #99c959; - animation-delay: 0s; - } - - #loadMask>div>:first-child { - font-size: 40px; - color: #909090; ; - } - - #loadMask>div>:last-child { - width: 140px; - height: 70px; - margin: 0 auto; - } - - #voiceRec { - position: absolute; - right: 0; - top: 0; - width: 47px; - height: 100%; - } - - .message_if_voice { - padding-right: 47px !important; - } - - #voiceRecIcon { - width: 100%; - height: 100%; - text-align: center; - cursor: pointer; - position: relative; - } - - #voiceRecIcon:hover>svg { - color: #808080; - } - - #voiceRecIcon>svg { - width: 38px; - height: 38px; - color: #b0b0b0; - position: absolute; - top: 50%; - left: 50%; - transform: translate(-50%, -50%); - } - - #voiceRecIcon>svg .animVoice { - display: none; - } - - .voiceRecing>svg { - color: #99c959 !important; - } - - .voiceRecing .animVoice { - display: inline !important; - transform-origin: 0 64%; - animation-duration: 1.5s; - animation-name: scaleVoice; - animation-timing-function: ease; - animation-iteration-count: infinite; - } - - .voiceLong .animVoice { - display: inline !important; - transform-origin: 0 64%; - animation-duration: 0.3s; - animation-name: longVoice; - animation-timing-function: ease-in-out; - animation-iteration-count: 1; - } - - @keyframes longVoice { - 0% { - transform: scaleY(0); - } - - 100% { - transform: scaleY(1); - } - } - - @keyframes scaleVoice { - 0% { - transform: scaleY(0.28); - } - - 20% { - transform: scaleY(0.60); - } - - 28% { - transform: scaleY(0.28); - } - - 36% { - transform: scaleY(0.45); - } - - 44% { - transform: scaleY(0.28); - } - - 52% { - transform: scaleY(0.45); - } - - 62% { - transform: scaleY(0.80); - } - - 72% { - transform: scaleY(0.80); - } - - 90% { - transform: scaleY(0.28); - } - - 100% { - transform: scaleY(0.28); - } - } - - #voiceRecSetting { - display: none; - position: absolute; - top: -70px; - left: -26px; - z-index: 1; - padding: 4px 4px; - -webkit-user-select: none; - user-select: none; - border-radius: 3px; - box-shadow: 0 0 6px rgba(0, 0, 0, 0.15); - } - - #voiceRecSetting select { - width: 102px; - outline: none; - height: 28px; - border-radius: 3px; - border-color: rgba(0, 0, 0, .3); - } - - .presetModelCls label { - margin-right: 8px; - } - - .presetModelCls select { - height: 30px; - line-height: 30px; - margin-top: 2px; - font-size: 15px; - } - - .modelSwitch, - .setSwitch { - display: flex; - } - - .modelSwitch { - margin-bottom: 10px; - -webkit-user-select: none; - user-select: none; - } - - .modelSwitch>div, - .setSwitch>div { - border-radius: 3px; - width: calc(100% / 3); - padding: 8px; - line-height: 1; - text-align: center; - cursor: pointer; - } - - .modelSwitch>div:hover, - .setSwitch>div:hover { - background-color: var(--body-hover-bgcolor); - } - - .activeSwitch { - background-color: var(--inputborder-color); - } - - .checkLoad { - height: 32px; - border-radius: 3px; - line-height: 32px; - background: #d0d0d0; - text-align: center; - display: flex; - justify-content: center; - cursor: pointer; - } - - .checkLoad:hover { - background: #c0c0c0; - } - - .voiceChecking { - background-color: #c0c0c0 !important; - } - - .voiceChecking>svg { - display: inline !important; - } - - .checkLoad>svg { - display: none; - margin-right: 8px; - height: 32px; - width: 64px; - } - - #preSetSystem { - height: 30px; - line-height: 30px; - } - - #sysMask { - display: none; - position: fixed; - z-index: 200; - top: 0; - left: 0; - bottom: 0; - right: 0; - cursor: pointer; - justify-content: center; - align-items: center; - background: rgba(0, 0, 0, .4); - -webkit-tap-highlight-color: transparent; - } - - #sysDialog { - position: relative; - background: rgba(var(--primary-rgbbody),1); - cursor: auto; - max-height: 100%; - width: 100%; - display: flex; - flex-direction: column; - border-radius: 4px; - padding: 20px; - } - - .sysTitle { - font-size: 20px; - font-weight: bold; - margin-bottom: 8px; - -webkit-user-select: none; - user-select: none; - } - - .sysSwitch, - .sysSwitch>div * { - pointer-events: none; - } - - .sysSwitch>div { - border-radius: 3px; - height: 32px; - line-height: 32px; - text-align: center; - cursor: pointer; - pointer-events: auto; - font-weight: bold; - display: flex; - align-items: center; - -webkit-user-select: none; - user-select: none; - } - - .sysSwitch>div>svg { - margin-right: 4px; - } - - .sysSwitch>div:hover { - background-color: var(--body-hover-bgcolor); - } - - .sysDetail { - overflow-y: auto; - flex: 1; - margin-top: 4px; - } - - #closeSet { - position: absolute; - right: 0px; - top: 0px; - cursor: pointer; - padding: 10px 14px; - } - - #closeSet:hover { - color: #000; - } - - .setContent { - margin-top: 8px; - } - - .setNotNormalFlow { - position: relative; - } - - .setTitle { - margin-bottom: 6px; - font-weight: bold; - -webkit-user-select: none; - user-select: none; - } - - .setDetail { - margin: 0 10px; - -webkit-user-select: none; - user-select: none; - } - - .autoSelect>label, - .autoSelect>input { - cursor: pointer; - } - - .dataDetail { - display: flex; - } - - .dataDetail svg { - margin-right: 4px; - } - - .dataDetail>div, - .dataDetail>label { - border-radius: 3px; - text-align: center; - padding: 6px 8px; - margin-right: 12px; - font-size: 15px; - cursor: pointer; - display: flex; - align-items: center; - justify-content: space-between; - } - - .dataDetail>div:hover, - .dataDetail>label:hover { - background-color: var(--body-hover-bgcolor); - } - - .keyOptionDetail { - display: flex; - margin-top: 10px; - } - - #resetHotKey { - display: flex; - align-items: center; - justify-content: space-between; - cursor: pointer; - font-size: 15px; - border-radius: 3px; - padding: 6px 8px; - margin-left: 90px; - } - - #resetHotKey>svg { - margin-right: 4px; - } - - #resetHotKey:hover { - background-color:var(--body-hover-bgcolor); - } - - .hotKeyDetail>div { - position: relative; - height: 30px; - margin-bottom: 2px; - } - - .hotKeyDetail label { - line-height: 30px; - } - - .hotKeyDetail select { - position: absolute; - left: 110px; - outline: none; - border-radius: 3px; - width: 120px; - border-color: rgba(0, 0, 0, .3); - height: 30px; - font-size: 15px; - } - - .avatarDetail { - display: flex; - margin-top: 2px; - } - - .avatarDetail img { - border-radius: 2px; - width: 32px; - height: 32px; - flex-shrink: 0; - margin-right: 10px; - margin-top: 2px; - } - - .inputDetail input { - outline: none; - border-radius: 3px; - padding-left: 8px; - font-size: 15px; - width: 100%; - height: 34px; - border: 1px solid rgba(0, 0, 0, .3); - } - - .themeDetail { - display: flex; - width: 180px; - justify-content: space-between; - pointer-events: none; - } - - .themeDetail svg { - display: block; - } - - .themeDetail>div { - pointer-events: auto; - border-radius: 20px; - text-align: center; - padding: 8px 8px; - font-size: 14px; - cursor: pointer; - } - - .themeDetail>div * { - pointer-events: none; - } - - .themeDetail>div:hover { - background-color: var(--body-hover-bgcolor); - } - - .darkTheme>div:first-child { - background-color: var(--inputborder-color); - } - - .lightTheme>div:nth-child(2) { - background-color: var(--inputborder-color); - } - - .autoTheme>div:nth-child(3) { - background-color: var(--inputborder-color); - } - - .langDetail { - width: 110px; - } - - .enLang>div:first-child { - background-color: var(--inputborder-color); - } - - .zhLang>div:nth-child(2) { - background-color: var(--inputborder-color); - } - - #customAutoSet input { - width: 100px; - height: 30px; - line-height: 30px; - font-size: 15px; - outline: none; - border: 1px solid rgba(0, 0, 0, .3); - text-align: center; - border-radius: 3px; - background: #fff; - color: #24292f; - } - - #customAutoSet label { - margin-right: 8px; - } - - .progressBar { - position: relative; - width: 100%; - height: 12px; - border-radius: 6px; - background: #e0e0e0; - overflow: hidden; - } - - .nowProgress { - position: absolute; - left: 0; - top: 0; - height: 12px; - min-width: 1px; - border-radius: 6px; - background: #99c959; - } - - .progressDetail { - display: flex; - justify-content: space-between; - font-size: 15px; - } - - .cursorCls { - background-color: var(--inputborder-color); - width: 4px; - animation: 1s cursor-blinker infinite step-start; - } - - @keyframes cursor-blinker { - 0% { - opacity: 0; - } - - 50% { - opacity: 1; - } - - 100% { - opacity: 0; - } - } - - .apiSelsContainer { - position: relative; - z-index: 1; - } - - #apiSelect { - position: absolute; - top: 64px; - padding: 4px 0; - width: calc(100% - 20px); - left: 10px; - box-shadow: 0 0 6px rgba(0, 0, 0, 0.15); - max-height: 180px; - overflow-y: auto; - -webkit-user-select: none; - user-select: none; - } - - #apiSelect>div { - pointer-events: auto; - cursor: pointer; - font-size: 15px; - padding: 6px 0 6px 8px; - height: 36px; - display: flex; - justify-content: space-between; - align-items: center; - } - - #apiSelect>div:hover { - background-color:var(--body-hover-bgcolor); - } - - #apiSelect>div>span { - height: 100%; - line-height: 23px; - overflow: hidden; - white-space: nowrap; - text-overflow: ellipsis; - } - - #apiSelect>div * { - pointer-events: none; - } - - .delApiOption:hover { - background-color: var(--body-hover-bgcolor); - } - - .delApiOption { - width: 36px; - height: 36px; - flex-shrink: 0; - pointer-events: auto !important; - } - - .delApiOption>svg { - margin: 6px; - display: block; - } - - @keyframes textInOut { - from { - opacity: 0; - } - - to { - opacity: 1; - } - } - - .response[data-loading="true"]>.responseBody>*:not(.cursorCls) { - animation: textInOut 0.48s ease-in-out forwards; - } - - .cotBtn { - width: 120px; - height: 32px; - font-size: 14px; - user-select: none; - background-color: var(--inputborder-color); - position: relative; - padding-left: 14px; - line-height: 32px; - border-radius: 8px; - margin-bottom: 12px; - cursor: pointer; - } - - .cotBtn:hover { - background-color: var(--body-hover-bgcolor); - } - - .cotBtn.endCot { - width: 142px; - } - - .cotBtn::after { - content: ''; - display: inline-block; - position: absolute; - right: 15px; - top: 14px; - width: 6px; - height: 6px; - transform: rotate(-45deg); - } - - .cotBtn.down::after { - top: 11px; - transform: rotate(135deg); - } - - .cotContent { - background-color: var(--inputborder-color); - padding-left: 12px; - font-size: 14px; - } - - .cotContent>:last-child { - margin-bottom: 12px !important; - } - - .hide { - display: none; - } - - - - - - - diff --git a/luci-theme-footstrap/htdocs/luci-static/footstrap/logo_48.png b/luci-theme-footstrap/htdocs/luci-static/footstrap/logo_48.png deleted file mode 100644 index ae7a6461..00000000 Binary files a/luci-theme-footstrap/htdocs/luci-static/footstrap/logo_48.png and /dev/null differ diff --git a/luci-theme-footstrap/htdocs/luci-static/footstrap/manifest.json b/luci-theme-footstrap/htdocs/luci-static/footstrap/manifest.json deleted file mode 100644 index 974777ad..00000000 --- a/luci-theme-footstrap/htdocs/luci-static/footstrap/manifest.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "name": "LuCI", - "start_url": "/cgi-bin/luci/", - "display": "standalone", - "background_color": "#f6f8fa", - "theme_color": "#f6f8fa", - "icons": [ - { - "src": "app-icon-192.png", - "sizes": "192x192", - "type": "image/png", - "purpose": "any maskable" - } - ] -} diff --git a/luci-theme-footstrap/htdocs/luci-static/resources/fs-appearance.js b/luci-theme-footstrap/htdocs/luci-static/resources/fs-appearance.js deleted file mode 100644 index 637bf893..00000000 --- a/luci-theme-footstrap/htdocs/luci-static/resources/fs-appearance.js +++ /dev/null @@ -1,637 +0,0 @@ -'use strict'; -'require baseclass'; -'require ui'; -'require fs-prefs as prefs'; -'require fs-axes as axes'; -'require fs-router as router'; -'require fs-assets as assets'; -'require fs-version as ver'; - -/* The Appearance controls: the DOM that presents the axes. It owns no preference: fs-prefs.js and - * fs-axes.js hold the axes and fs-version.js the version string. `view/footstrap/appearance.js` - * calls `renderStandalone()`, the whole surface this file ships. - * - * The version line makes no request and must not grow one: which version is installed is what this - * page answers, and which is available is the package manager's question. */ - -/* Colour readout. Two questions no stored value answers: what colour a role is right now (the - * palette's own while the axis is off) and what contrast it lands at. */ -let _probe = null; -function probeColor(expr) { - if (!_probe) { - /* Off-screen rather than display:none, so the reading does not depend on a display:none element - * computing `color` in every engine. Every declaration is !important: an app's CSS can style a - * plain
. */ - _probe = E('span', { 'id': 'fs-appearance-probe', 'aria-hidden': 'true' }); - _probe.style.cssText = 'position:fixed!important;left:-9999px!important;top:0!important;' - + 'width:0!important;height:0!important;overflow:hidden!important;' - + 'pointer-events:none!important;'; - document.body.appendChild(_probe); - } - /* cleared first: an expression the engine rejects leaves the previous colour standing, which - * would report a stale answer as a fresh one */ - _probe.style.setProperty('color', ''); - _probe.style.setProperty('color', expr, 'important'); - return getComputedStyle(_probe).color; -} - -/* A computed colour -> [r,g,b] 0..255, or null. Rasterised, not parsed: a computed `color` keeps the - * space it was authored in, so `oklch(0.54 0.19 300)` parses as three numbers in the wrong units - * (measured: #010078, graded "Too faint to read"). Painting one pixel makes the engine convert. */ -let _cx = null; -function rasterCtx() { - if (!_cx) { - const cv = document.createElement('canvas'); - cv.width = cv.height = 1; - _cx = cv.getContext('2d', { willReadFrequently: true }); - } - return _cx; -} -function parseColor(s) { - const cx = rasterCtx(); - /* fillStyle keeps the last value it could parse, so a colour this engine rejects would - * report the previous one as a fresh reading — the trap probeColor() clears for */ - cx.fillStyle = '#000'; - cx.fillStyle = String(s || ''); - cx.clearRect(0, 0, 1, 1); - cx.fillRect(0, 0, 1, 1); - const d = cx.getImageData(0, 0, 1, 1).data; - /* translucent: composite over nothing is meaningless for a readout */ - return d[3] === 255 ? [ d[0], d[1], d[2] ] : null; -} - -/* WCAG 2.x relative luminance and contrast ratio, on sRGB. Used only to report: the theme states - * what a colour costs and leaves the choice with the user, never correcting it (03-palettes.css - * derives the ink over a fill, which is a different question). */ -function luminance(rgb) { - const c = rgb.map((v) => { - const x = v / 255; - return (x <= .03928) ? (x / 12.92) : Math.pow((x + .055) / 1.055, 2.4); - }); - return (.2126 * c[0]) + (.7152 * c[1]) + (.0722 * c[2]); -} -function contrastRatio(fgExpr, bgExpr) { - const fg = parseColor(probeColor(fgExpr)), bg = parseColor(probeColor(bgExpr)); - if (!fg || !bg) return null; - const a = luminance(fg), b = luminance(bg); - return (Math.max(a, b) + .05) / (Math.min(a, b) + .05); -} - -function toHex(s) { - const rgb = parseColor(s) || [ 0, 0, 0 ]; - return '#' + rgb.map((v) => v.toString(16).padStart(2, '0')).join(''); -} - -/* One colour axis: a native swatch, a hex field and a button back to the palette's own colour. - * Reports through onPick as a hex string, or 0 for "back to the palette". */ -function colorControl(onPick, label, o) { - const swatch = E('input', { 'type': 'color', 'class': 'fs-color-swatch', 'aria-label': label }); - const field = E('input', { - 'type': 'text', 'class': 'fs-color-hex', 'spellcheck': 'false', 'autocomplete': 'off', - 'inputmode': 'text', 'maxlength': '7', 'aria-label': label - }); - const clear = E('button', { 'class': 'btn fs-color-clear', 'type': 'button' }, [ _('Palette', 'footstrap') ]); - const ratio = o.contrast ? E('div', { 'class': 'cbi-value-description fs-color-contrast' }) : null; - - let typed = false; - - /* Repaint everything that mirrors the axis. Called after every edit, and through the returned - * refresh() after a preset, palette switch or dark-mode flip — each changes what the palette's - * own colour is while this axis stays off. */ - function reflect(v) { - const live = probeColor(o.probe); - const hex = (typeof v === 'string') ? v : toHex(live); - swatch.value = hex; - /* do not fight the user mid-edit: `#0` is a legal prefix, and overwriting the field on - * every keystroke made the input impossible to type into */ - if (document.activeElement !== field) { field.value = hex; typed = false; } - /* the button back to the palette doubles as the axis state readout: enabled means the axis - * holds a colour of its own, disabled means the field shows the palette's */ - clear.disabled = !v; - if (!ratio) return; - const r = contrastRatio(o.contrast.fg, o.contrast.bg); - if (r === null) { ratio.hidden = true; ratio.removeAttribute('title'); return; } - /* The readout states what the ratio means; the number itself stays in the title. Thresholds are - * WCAG AA: 4.5:1 for body text, 3:1 for large text and for a UI shape. */ - const where = o.contrast.label; - const grade = (o.contrast.kind === 'shape') - ? ((r >= 3) - ? { cls: 'fs-contrast-aa', text: _('Clearly visible %s', 'footstrap').format(where) } - : { cls: 'fs-contrast-aa-large', text: _('Barely visible %s', 'footstrap').format(where) }) - : (r >= 4.5) - ? { cls: 'fs-contrast-aa', text: _('Easy to read %s', 'footstrap').format(where) } - : (r >= 3) - ? { cls: 'fs-contrast-aa-large', text: _('Hard to read %s — large text only', 'footstrap').format(where) } - : { cls: 'fs-contrast-low', text: _('Too faint to read %s', 'footstrap').format(where) }; - ratio.className = 'fs-color-contrast ' + grade.cls; - ratio.textContent = grade.text; - /* a pass says nothing: nine "easy to read" lines buried the one that was not */ - ratio.hidden = (grade.cls === 'fs-contrast-aa'); - ratio.title = _('Contrast %s:1 (WCAG AA wants %s:1 here)', 'footstrap') - .format(r.toFixed(1), (o.contrast.kind === 'shape') ? '3' : '4.5'); - } - - const pick = (v) => { onPick(v); reflect(v); }; - - swatch.addEventListener('input', () => pick(swatch.value.toLowerCase())); - /* commit on blur and Enter, not per keystroke: a half-typed `#0096` would repaint the page - * under the cursor. An unparseable value snaps back to what the axis holds, so the field - * cannot claim a colour the page is not painted in. An untouched field returns first, so a - * bare Tab-through never pins the shown palette colour on any of the 9 axes. */ - const commit = () => { - if (!typed) return; - const v = field.value.trim().toLowerCase(); - if ((/^#[0-9a-f]{6}$/).test(v)) pick(v); - /* re-read rather than a cached copy: the page can change what the axis holds behind this - * control (a preset, Reset to built-in), which a snapshot taken at build time would miss */ - else reflect(o.read()); - }; - field.addEventListener('input', () => { typed = true; }); - field.addEventListener('blur', commit); - field.addEventListener('keydown', (ev) => { if (ev.key === 'Enter') { ev.preventDefault(); commit(); } }); - clear.addEventListener('click', () => pick(0)); - - const wrap = E('div', { 'class': 'fs-colorctl' }, [ - E('div', { 'class': 'fs-color-row' }, [ swatch, field, clear ]) - ].concat(ratio ? [ ratio ] : [])); - /* the caller decides when this runs: probeColor() needs the document, and this control is not - * in it yet */ - wrap.fsRefresh = () => reflect(o.read()); - return wrap; -} - -/* Every stamp that moves a colour lands on :root, including head.ut's OS listener and an app - * rewriting data-darkmode, neither of which calls back here. */ -let _watch = null; -function unwatchColours() { - if (_watch) _watch.disconnect(); - _watch = null; -} -router.onNavigate(unwatchColours); -function watchColours(refresh) { - unwatchColours(); - _watch = new MutationObserver(refresh); - _watch.observe(document.documentElement, { - attributes: true, attributeFilter: [ 'data-darkmode', 'data-palette', 'data-wallpaper' ] - }); -} - -/* Build the page; renderStandalone() hands it over. Four tabs, most-used first: the colour scheme, - * the interface, the background with its glass and the colours nobody touches twice; Saving sits - * under them. Everything applies at once and is this browser's, in localStorage; only "Save to - * router" writes anything, pushing the current look to the router for other browsers. */ -function build() { - /* 24.10.0-24.10.2 have no ui.RangeSlider and a package from the feed still installs there (opkg does - * not version luci-base); one readable line beats the raw "not a constructor" TypeError. */ - if (!ui.RangeSlider) - return E('p', { 'class': 'alert-message warning' }, [ _('Footstrap needs OpenWrt 24.10.3 or newer.', 'footstrap') ]); - - /* every saved axis re-checks the Save button after applying, so it greys the moment this - * browser matches the saved default and un-greys when it diverges. Wrapped around the appliers - * because the controls call them directly and have no other seam back here. */ - const bump = (fn) => (v) => { fn(v); refreshSave(); }; - - /* Every colour control mirrors something it does not own: the palette's colour while its own - * axis is off, and the contrast that colour lands at. A palette switch or dark-mode flip moves - * all of it under controls nobody touched, so they refresh together. */ - const colourCtls = []; - const refreshColours = () => colourCtls.forEach((c) => c.fsRefresh()); - const repaint = (fn) => (v) => { fn(v); refreshColours(); }; - - /* One captioned row in LuCI's own shape: `.cbi-value` > `label.cbi-value-title` + - * `.cbi-value-field`, which base/30-forms.css and theme/60-inputs.css already lay out. `make` is - * handed the caption because each control needs it again as the aria-label of its inner - * input/select (a stock widget's wrapper div cannot carry a name). `o.desc` is a help line under - * the control, `o.extra` the rows with more than a control, `o.cls` marks the rows CSS singles out. */ - const group = (label, make, opts) => { - const o = opts || {}; - const desc = o.desc ? [ E('div', { 'class': 'cbi-value-description' }, [ o.desc ]) ] : []; - return E('div', { 'class': 'cbi-value' + (o.cls ? ' ' + o.cls : '') }, [ - E('label', { 'class': 'cbi-value-title' }, [ label ]), - E('div', { 'class': 'cbi-value-field' }, [ make(label) ].concat(desc, o.extra || [])) - ]); - }; - - /* the three literals every colour row repeats; a string literal survives minification intact */ - const CARD_BG = 'var(--fs-panel)', INK = 'var(--fs-text)', ON_CARD = _('on a card', 'footstrap'); - - /* A list of more than five, the palette, is a `ui.Select`; every number a `ui.RangeSlider`, already - * dressed by base/30-forms.css and theme/60-inputs.css (`ui.RangeSlider` reached openwrt-24.10 in - * 24.10.3). Listen for `widget-change`, the seam UIElement publishes, not an event on the inner - * element. RangeSlider also emits `widget-update` while the handle moves, which resizes the page - * under the drag; the appliers are idempotent, so wiring both costs nothing. */ - const selectCtl = (current, choices, apply, label) => { - /* an array of [value, label] pairs when a key is integer-like: Object.keys hoists it ahead of - * the authored order ('2020' rendered above Footstrap, the default); `sort` pins the order */ - const pairs = Array.isArray(choices) ? choices : Object.entries(choices); - const w = new ui.Select(String(current), Object.fromEntries(pairs), { widget: 'select', sort: pairs.map((p) => p[0]) }); - const node = w.render(); - node.querySelector('select, input').setAttribute('aria-label', label); - node.addEventListener('widget-change', () => apply(w.getValue())); - return node; - }; - - /* Two to three short choices are one row of pills, every choice in sight: native radios under one - * name, so the arrow keys move between them and a screen reader counts them; 80-appearance.css - * draws the pills. */ - let segSeq = 0; - const segCtl = (current, choices, apply, label) => { - const name = 'fs-ap-seg-' + (++segSeq); - const pairs = Array.isArray(choices) ? choices : Object.entries(choices); - return E('div', { 'class': 'fs-seg', 'role': 'radiogroup', 'aria-label': label }, pairs.map(([ v, text ]) => { - const input = E('input', { 'type': 'radio', 'name': name, 'value': v }); - input.checked = (String(current) === v); - input.addEventListener('change', () => { if (input.checked) apply(v); }); - return E('label', {}, [ input, E('span', {}, [ text ]) ]); - })); - }; - - const sliderCtl = (axis, apply, label, opts) => { - const o = opts || {}; - const w = new ui.RangeSlider(String(axis.current()), { - min: axis.min, max: axis.max, step: o.step || 1 - }); - const node = w.render(); - node.querySelector('select, input').setAttribute('aria-label', label); - const push = () => apply(parseInt(w.getValue(), 10)); - /* `live: false` for an axis whose value moves this control: Content width widens the column the - * page is drawn in, so applying mid-drag slides the handle from under the pointer and one small - * drag runs to the maximum. A keyboard user still applies at once (an arrow key fires `change`). */ - if (o.live !== false) node.addEventListener('widget-update', push); - node.addEventListener('widget-change', push); - return node; - }; - - const colourGroup = (label, axis, probe, contrast, opts = {}) => group(label, (lbl) => { - const ctl = colorControl(bump(axis.apply), lbl, { - probe: probe, - read: axis.current, - contrast: contrast - }); - colourCtls.push(ctl); - return ctl; - }, opts); - - /* a card is a stock `.cbi-section` under its own title; a tab pane is one whose title is its tab - * (ui.tabs reads data-tab-title); a subheading splits either in two */ - const card = (title, rows) => E('div', { 'class': 'cbi-section fs-ap-card' }, [ E('h3', {}, [ title ]) ].concat(rows)); - const pane = (name, title, rows) => E('div', { 'class': 'cbi-section fs-ap-card', 'data-tab': name, 'data-tab-title': title }, rows); - const sub = (title, cls) => E('div', { 'class': 'fs-ap-sub' + (cls ? ' ' + cls : '') }, [ E('h4', {}, [ title ]) ]); - - /* Every label here carries the 'footstrap' context: LuCI serves one merged catalogue and the first - * archive holding the hash wins, so a bare msgid is a global name any luci-app can win. */ - - /* ---- the colour scheme: what most visits come to change ---- */ - const scheme = pane('scheme', _('Colour scheme', 'footstrap'), [ - group(_('Mode', 'footstrap'), (label) => segCtl(prefs.currentMode(), [ - [ 'auto', _('Auto', 'footstrap') ], - [ 'light', _('Light', 'footstrap') ], - [ 'dark', _('Dark', 'footstrap') ] - ], bump(prefs.applyMode), label)), - - group(_('Palette', 'footstrap'), (label) => selectCtl(axes.palette.current(), [ - [ 'footstrap', 'Footstrap' ], - [ 'hicontrast', 'Hi-Contrast' ], - [ 'bootstrap', 'Bootstrap' ], - /* names another package, luci-theme-openwrt-2020, whose colourway this is */ - [ '2020', 'OpenWrt 2020' ], - [ 'forum', 'Forum' ] - ], bump(axes.palette.apply), label)), - - /* Accent recolours the accented controls (buttons, toggles, sliders, focus rings), not the - * canvas; any #rrggbb is taken. Read as text on a card, the use that fails first (as a fill it - * carries derived ink). */ - colourGroup(_('Accent', 'footstrap'), axes.accent, 'var(--fs-accent)', - { fg: 'var(--fs-accent)', bg: CARD_BG, label: ON_CARD }) - ]); - - /* ---- the interface ---- */ - const iface = pane('interface', _('Interface', 'footstrap'), [ - group(_('Layout', 'footstrap'), (label) => segCtl(prefs.currentLayout(), [ - [ 'sidebar', _('Sidebar', 'footstrap') ], - [ 'top', _('Top', 'footstrap') ] - ], bump(prefs.applyLayout), label)), - - /* always built and hidden by CSS in the top layout (:root[data-layout="top"] .fs-ap-submenus): - * the page is built once, so a currentLayout() branch would freeze it to the layout the page - * loaded in while CSS morphs the chrome live */ - group(_('Submenus', 'footstrap'), (label) => segCtl(prefs.currentAutoCollapse() ? 'on' : 'off', [ - [ 'off', _('Keep open', 'footstrap') ], - [ 'on', _('Auto-collapse', 'footstrap') ] - ], bump(prefs.applyAutoCollapse), label), { cls: 'fs-ap-submenus' }), - - group(_('Density', 'footstrap'), (label) => segCtl(axes.density.current(), [ - [ 'compact', _('Compact', 'footstrap') ], - [ 'normal', _('Normal', 'footstrap') ], - [ 'large', _('Large', 'footstrap') ] - ], bump(axes.density.apply), label)), - - /* the content column's own cap, separate from Density. The slider starts at the 1280px every - * page was designed against and only widens, which also keeps --fs-content-min (500px, what - * the sidebar-to-bar fold is measured against) out of reach by construction. */ - group(_('Content width', 'footstrap'), - (label) => sliderCtl(axes.contentWidth, bump(axes.contentWidth.apply), label, { step: 40, live: false })), - - group(_('Rounding', 'footstrap'), - (label) => sliderCtl(axes.radius, bump(axes.radius.apply), label)) - ]); - - /* ---- the background: the canvas, the wallpaper and the glass over it ---- - * The rows a value brings are siblings of the Wallpaper row: nested in its `.cbi-value-field` - * they started 216px right of every other control (measured on the router). They are hidden as - * a group, as stock pages do with a dependent field. The pills are the per-browser switch that - * keeps the Save button honest; Choose/Remove only swap the picture and never touch the axis. */ - const REMOVE = _('Remove', 'footstrap'); - const background = (() => { - const err = E('div', { 'class': 'fs-ap-err', 'role': 'alert', 'hidden': '' }); - const preview = E('img', { 'class': 'fs-ap-bgprev', 'alt': '', 'hidden': '' }); - const fileInput = E('input', { 'type': 'file', 'accept': 'image/*', 'style': 'display:none' }); - const chooseLabel = _('Choose image', 'footstrap'); - const chooseBtn = E('button', { 'class': 'btn cbi-button', 'type': 'button' }, [ chooseLabel ]); - const removeBtn = E('button', { 'class': 'btn cbi-button-remove', 'type': 'button', 'hidden': '' }, [ REMOVE ]); - - const patErr = E('div', { 'class': 'fs-ap-err', 'role': 'alert', 'hidden': '' }); - const patPreview = E('img', { 'class': 'fs-ap-bgprev', 'alt': '', 'hidden': '' }); - const patInput = E('input', { 'type': 'file', 'accept': 'image/svg+xml,.svg', 'style': 'display:none' }); - const patChooseLabel = _('Choose SVG', 'footstrap'); - const patChoose = E('button', { 'class': 'btn cbi-button', 'type': 'button' }, [ patChooseLabel ]); - const patRemove = E('button', { 'class': 'btn cbi-button-remove', 'type': 'button', 'hidden': '' }, [ REMOVE ]); - - /* Colours decides whether the file's own palette is kept or replaced by the theme's: a mask - * uses the alpha only, right for line art and wrong for artwork with its own colours. */ - const patRows = [ - group(_('Pattern', 'footstrap'), - () => E('div', { 'class': 'fs-ap-bgrow' }, [ patChoose, patRemove ]), - { extra: [ patInput, patPreview, patErr ] }), - group(_('Scale', 'footstrap'), (lbl) => sliderCtl(axes.patternSize, bump(axes.patternSize.apply), lbl, { step: 20 })), - group(_('Strength', 'footstrap'), (lbl) => sliderCtl(axes.patternStrength, bump(axes.patternStrength.apply), lbl, { step: 5 })), - group(_('Colours', 'footstrap'), (lbl) => segCtl(axes.patternInk.current(), [ - [ 'theme', _('Theme', 'footstrap') ], - [ 'original', _('As in file', 'footstrap') ] - ], bump(axes.patternInk.apply), lbl)) - ]; - /* Dim is an ordinary saved axis, so it is bump()-ed or the Save button misreports its status */ - const fileRows = [ - group(_('File', 'footstrap'), - () => E('div', { 'class': 'fs-ap-bgrow' }, [ chooseBtn, removeBtn ]), - { extra: [ fileInput, preview, err ] }), - group(_('Dim', 'footstrap'), (lbl) => sliderCtl(axes.photoDim, bump(axes.photoDim.apply), lbl, { step: 5 })) - ]; - - function reflect(tok) { - if (tok) { preview.src = axes.loginBg.url(tok); preview.hidden = false; removeBtn.hidden = false; } - else { preview.removeAttribute('src'); preview.hidden = true; removeBtn.hidden = true; } - } - function reflectPattern(tok) { - if (tok) { patPreview.src = axes.pattern.url(tok); patPreview.hidden = false; patRemove.hidden = false; } - else { patPreview.removeAttribute('src'); patPreview.hidden = true; patRemove.hidden = true; } - } - /* `hidden` on the row, which base/10-reset.css restates with !important (the UA's bare - * `[hidden]` loses to `.cbi-value`'s display). Hidden, not removed: each row holds a live - * control that a rebuild would freeze to its construction-time state. */ - function togglePanel(v) { - patRows.forEach((r) => { r.hidden = (v !== 'pattern'); }); - fileRows.forEach((r) => { r.hidden = (v !== 'file'); }); - } - reflect(axes.loginBg.current()); - reflectPattern(axes.pattern.current()); - togglePanel(axes.wallpaper.current()); - - const setWallpaper = (v) => { axes.wallpaper.apply(v); refreshSave(); togglePanel(v); }; - - /* Both uploads share one wiring (pick, upload, report, remove) and never move the Wallpaper - * pills, which the user may change mid-upload. The input is cleared on every change so - * re-picking the same file fires `change`; the label is restored in `finally`, or a failed - * upload leaves "Uploading…" standing. */ - const wireUploader = (u) => { - const fail = (e) => { u.err.textContent = String((e && e.message) || e); u.err.hidden = false; }; - u.choose.addEventListener('click', () => { u.err.hidden = true; u.input.click(); }); - u.input.addEventListener('change', () => { - const f = u.input.files && u.input.files[0]; - u.input.value = ''; - if (!f) return; - u.err.hidden = true; u.choose.disabled = true; - u.choose.textContent = _('Uploading…', 'footstrap'); - u.upload(f) - .then(u.reflect) - .catch(fail) - .finally(() => { u.choose.disabled = false; u.choose.textContent = u.label; }); - }); - u.remove.addEventListener('click', () => { - u.err.hidden = true; u.remove.disabled = true; - u.drop().then(() => u.reflect('')).catch(fail) - .finally(() => { u.remove.disabled = false; }); - }); - }; - - wireUploader({ - choose: patChoose, remove: patRemove, input: patInput, err: patErr, - label: patChooseLabel, reflect: reflectPattern, - upload: assets.uploadPattern, drop: assets.removePattern - }); - - wireUploader({ - choose: chooseBtn, remove: removeBtn, input: fileInput, err: err, - label: chooseLabel, reflect: reflect, - upload: assets.uploadLoginBg, drop: assets.removeLoginBg - }); - - /* The glass rows show only over a wallpaper (CSS: .fs-ap-glass), Material only while a - * surface is glass at all, Blur only for a material that blurs. An OS asking for less - * transparency or more contrast keeps the surfaces solid whatever the sliders say, and the - * page says so. */ - const glassRows = [ - sub(_('Transparency', 'footstrap'), 'fs-ap-glass'), - group(_('Card opacity', 'footstrap'), - (lbl) => sliderCtl(axes.cardOpacity, bump(axes.cardOpacity.apply), lbl, { step: 5 }), { - cls: 'fs-ap-glass', - desc: axes.glassBlocked() ? _('The system asks for less transparency or more contrast, so surfaces stay solid.', 'footstrap') : null - }), - group(_('Menu opacity', 'footstrap'), - (lbl) => sliderCtl(axes.barOpacity, bump(axes.barOpacity.apply), lbl, { step: 5 }), { cls: 'fs-ap-glass' }), - group(_('Material', 'footstrap'), (lbl) => segCtl(axes.material.current(), [ - [ 'flat', _('Flat', 'footstrap') ], - [ 'frosted', _('Frosted', 'footstrap') ], - [ 'acrylic', _('Acrylic', 'footstrap') ] - ], bump(axes.material.apply), lbl), { cls: 'fs-ap-glass fs-ap-material' }), - group(_('Blur', 'footstrap'), - (lbl) => sliderCtl(axes.blur, bump(axes.blur.apply), lbl, { step: 10 }), { cls: 'fs-ap-glass fs-ap-material fs-ap-blur' }) - ]; - - return pane('background', _('Background', 'footstrap'), [ - /* the canvas colour that tells routers apart; CSS hides it under a photo, which covers it */ - colourGroup(_('Tint', 'footstrap'), axes.tint, 'var(--fs-bg)', { - fg: 'var(--fs-text)', bg: 'var(--fs-bg)', label: _('on the canvas', 'footstrap') - }, { cls: 'fs-ap-tint', desc: _('Colours the page so you can tell routers apart.', 'footstrap') }), - - /* the strength half of the Tint, meaningful only in hue mode (a hex canvas has no chroma of - * ours to scale); CSS hides it otherwise. Not named "Density": the string is also the - * aria-label, so a screen reader would announce two rows under one name. */ - group(_('Tint strength', 'footstrap'), - (label) => sliderCtl(axes.tintStrength, bump(repaint(axes.tintStrength.apply)), label, { - step: 5 - }), { cls: 'fs-ap-tint fs-ap-tintstr' }), - - group(_('Wallpaper', 'footstrap'), (label) => segCtl(axes.wallpaper.current(), [ - [ 'off', _('Off', 'footstrap') ], - [ 'pattern', _('Pattern', 'footstrap') ], - [ 'file', _('File', 'footstrap') ] - ], setWallpaper, label)) - ].concat(patRows, fileRows, glassRows)); - })(); - - /* ---- the colours nobody touches twice: the last tab ---- - * The three status colours, then the surfaces: the sheet the UI is drawn on. Body text is read on - * each surface, so each reports --fs-text against itself; no ink is derived, since moving - * --fs-text would recolour what is measured against. The hairline takes the 3:1 UI-component - * threshold (a border is a shape). The rows are data because a string literal repeated eight - * times is not mangled by the minifier. */ - const colourRows = [ - ...[ - [ _('Good', 'footstrap'), axes.good, 'var(--fs-good)' ], - [ _('Warning', 'footstrap'), axes.warn, 'var(--fs-warn)' ], - [ _('Danger', 'footstrap'), axes.danger, 'var(--fs-danger)' ] - ].map(([ label, axis, ink ]) => - colourGroup(label, axis, ink, { fg: ink, bg: CARD_BG, label: ON_CARD })), - sub(_('Surfaces', 'footstrap')), - ...[ - [ _('Cards', 'footstrap'), axes.card, CARD_BG, INK, CARD_BG, ON_CARD ], - [ _('Controls', 'footstrap'), axes.control, 'var(--fs-panel2)', INK, 'var(--fs-panel2)', _('on a control', 'footstrap') ], - [ _('Sidebar and bar', 'footstrap'), axes.bar, 'var(--fs-bar-bg)', INK, 'var(--fs-bar-bg)', _('in the sidebar', 'footstrap') ], - [ _('Borders', 'footstrap'), axes.line, 'var(--fs-border)', 'var(--fs-border)', CARD_BG, ON_CARD, 'shape' ] - ].map(([ label, axis, probe, fg, bg, where, kind ]) => - colourGroup(label, axis, probe, { fg, bg, label: where, kind })) - ]; - - /* ---- saving: the router default and the version ---- - * Save writes the current look to /etc/config/footstrap over the scoped uci ACL. It does not - * change this browser (localStorage keeps overriding), so it only shows on a fresh browser. */ - /* each label is said twice in build(); hoisted, a msgid is paid once (24 B x2 -> 30 B) */ - const SAVE_TO_ROUTER = _('Save to router', 'footstrap'); - const RESET_TO_ROUTER = _('Reset to router', 'footstrap'); - const RESET_TO_BUILTIN = _('Reset to built-in', 'footstrap'); - const saveBtn = E('button', { 'class': 'btn cbi-button-action', 'type': 'button' }, [ SAVE_TO_ROUTER ]); - /* Two resets, because two things sit underneath a browser's tweaks: "Reset to router" clears them - * and lets every axis fall back to the router, "Reset to built-in" writes the theme's defaults - * explicitly. Neither touches /etc/config/footstrap. "Default" is not a label: it named the - * router's look in "Save as default" and the theme's in "Reset to default", three names for two - * states (forum topic 251930, post 92). */ - const resetSavedBtn = E('button', { 'class': 'btn', 'type': 'button' }, [ RESET_TO_ROUTER ]); - const resetBtn = E('button', { 'class': 'btn cbi-button-negative', 'type': 'button' }, [ RESET_TO_BUILTIN ]); - /* Save's only visible failure surface: the rpc rejecting (expired session 403, missing ACL, ubus - * down). A deleted config is not caught: commit no-ops and returns success (measured on the - * router); the package owns that file and the read side falls back to built-in defaults. */ - const saveErr = E('div', { 'class': 'fs-ap-err', 'role': 'alert', 'hidden': '' }); - - /* The Save button is the status: matching disables it, diverging enables it. A browser that - * refuses storage keeps its choices in fs-prefs's in-memory map, so the comparison stays honest; - * the note waits while a failed Save's error shows, or the .finally below would overwrite it. */ - function refreshSave() { - if (prefs.storageBroken() && saveErr.hidden) { - saveErr.textContent = _('This browser is not storing preferences (site data is blocked), so a change here lasts until you reload. Saving to the router still works and applies to every browser.', 'footstrap'); - saveErr.hidden = false; - } - const saved = axes.matchesSavedDefault(); - saveBtn.disabled = saved; - saveBtn.textContent = saved ? _('Saved to router', 'footstrap') : SAVE_TO_ROUTER; - } - saveBtn.addEventListener('click', () => { - saveBtn.disabled = true; - saveErr.hidden = true; - saveErr.title = ''; /* a stale rpc error would tooltip the storage note (measured: 'ubus code 6' over it) */ - axes.saveAsDefault() - /* on failure refreshSave re-enables the button so the user can retry; the usual cause - * is a stale session, which a reload fixes. The raw rpc error stays in a title - * tooltip. */ - .catch((e) => { - saveErr.textContent = _('Could not save to the router. Reload the page and try again.', 'footstrap'); - saveErr.title = String((e && e.message) || e); - saveErr.hidden = false; - }) - .finally(refreshSave); - }); - /* Two-click confirm on both: discarding local tweaks is destructive and a native confirm() is - * banned in this UI. Arming one disarms the other, so a primed button cannot be fired by a - * click meant for its neighbour. */ - let armed = null; - function disarm() { - if (!armed) return; - armed.btn.textContent = armed.label; - armed.btn.classList.remove('fs-ap-armed'); - armed = null; - } - function twoClick(btn, label, run) { - btn.addEventListener('click', () => { - if (armed && armed.btn === btn) { - disarm(); - run(); - location.reload(); - return; - } - disarm(); - armed = { btn: btn, label: label }; - btn.textContent = _('Confirm reset', 'footstrap'); - btn.classList.add('fs-ap-armed'); - }); - } - twoClick(resetSavedBtn, RESET_TO_ROUTER, axes.resetToSaved); - twoClick(resetBtn, RESET_TO_BUILTIN, axes.resetToBuiltin); - refreshSave(); /* correct label and enabled state before the first paint */ - - const versionLink = E('a', { - 'class': 'fs-ap-version', - 'href': ver.REPO_URL, - 'target': '_blank', - /* `noreferrer` alone: it implies noopener, and the theme's other outward links spell it - * that way */ - 'rel': 'noreferrer' - }, [ ver.label() ]); - - /* The theme's translations are their own packages, and nothing in a package manager can read `uci - * luci.main.lang` to fetch the right one. */ - const lang = (document.documentElement.getAttribute('lang') || '').trim(); - const untranslated = lang && lang !== 'en' && lang !== 'auto' && - _('Layout', 'footstrap') === 'Layout'; - const missing = untranslated ? E('div', { 'class': 'fs-ap-verrow fs-ap-i18n' }, [ - E('span', {}, [ _('This theme is not translated on this router yet.', 'footstrap') + ' ' ]), - E('code', {}, [ 'luci-i18n-footstrap-' + lang ]) - ]) : ''; - - const saving = card(_('Saving', 'footstrap'), [ - E('p', { 'class': 'fs-ap-lead' }, [ _('Footstrap theme settings apply at once and are stored permanently in this browser.', 'footstrap') ]), - E('div', { 'class': 'fs-ap-actrow' }, [ saveBtn, E('span', { 'class': 'fs-ap-actgap', 'aria-hidden': 'true' }), resetSavedBtn, resetBtn ]), - saveErr, - E('ul', { 'class': 'fs-ap-help' }, [ - E('li', {}, [ _('Save to router — store this look on the router. Browsers with a look of their own keep it.', 'footstrap') ]), - E('li', {}, [ _('Reset to router — drop this browser\'s changes and follow the router.', 'footstrap') ]), - E('li', {}, [ _('Reset to built-in — go back to the look the theme ships with.', 'footstrap') ]) - ]), - E('div', { 'class': 'fs-ap-footer' }, [ - E('div', { 'class': 'fs-ap-verrow' }, [ versionLink ]), - missing - ]) - ]); - - /* LuCI's own tab group, as on every tabbed form: it puts the strip before the panes and keeps - * the open tab for the session. A pane shown again re-reads its colours, which a palette or - * dark-mode change may have moved while it was hidden. */ - const panes = E('div', { 'class': 'fs-ap-panes' }, [ - scheme, - iface, - background, - pane('colours', _('Colours', 'footstrap'), colourRows) - ]); - const page = E('div', { 'class': 'fs-ap' }, [ panes, saving ]); - ui.tabs.initTabGroup(panes.childNodes); - panes.addEventListener('cbi-tab-active', refreshColours); - - Promise.resolve().then(refreshColours); - - watchColours(refreshColours); - return page; -} - -return baseclass.extend({ - /* the dispatched page's whole render(), called by view/footstrap/appearance.js */ - renderStandalone: () => Promise.resolve().then(build), -}); diff --git a/luci-theme-footstrap/htdocs/luci-static/resources/fs-assets.js b/luci-theme-footstrap/htdocs/luci-static/resources/fs-assets.js deleted file mode 100644 index 988c07e6..00000000 --- a/luci-theme-footstrap/htdocs/luci-static/resources/fs-assets.js +++ /dev/null @@ -1,291 +0,0 @@ -'use strict'; -'require baseclass'; -'require rpc'; -'require ui'; -'require fs-axes as axes'; - -/* fs-assets — putting a file on the router and taking it off again: the pattern and login-photo uploads, - * the SVG sanitizer, the rollback. A module of its own: only the Appearance page needs these ~4 KB. */ - -/* Hoisted: a string literal is not mangled, so each repeat is paid on flash; msgid stays literal - * for update-po.sh. */ -const MSG_UPLOAD_FAILED = _('Upload failed.', 'footstrap'); -const MSG_NOT_SVG = _('That file is not an SVG image.', 'footstrap'); -const MSG_BAD_IMAGE = _('Could not process the image.', 'footstrap'); -const MSG_PICK_SVG = _('Please choose an SVG file.', 'footstrap'); -/* One template, two numbers: a translator places both %d in one sentence instead of agreeing - * plurals. */ -const MSG_SANITIZED = _('Cleaned before upload: removed %d unsafe element(s) and %d external reference(s).', 'footstrap'); -const MSG_NOTHING_LEFT = _('That SVG had nothing left once the unsafe parts were removed.', 'footstrap'); - -/* ---- the pattern: an SVG the admin uploads, tiled and recoloured ---- - * Fixed path matched by the rpcd ACL, under /etc so an upgrade keeps it. Not the security boundary: a - * `curl` to cgi-upload skips every check below; a direct open is stopped by the CGI's - * `Content-Security-Policy: default-src 'none'; sandbox`. */ -const PAT_PATH = '/etc/footstrap/pattern.svg'; /* cgi-upload target; the ACL grants exactly this */ -const PAT_MAX = 512 * 1024; /* a tile that has to reach a router's flash and then every page load */ -/* What `_sanitizeSvg` removes, judged on the parsed document, not the text. Painted as an image nothing - * loads; these rules cover a direct open of the file: - * - elements: only the SVG namespace stays (`` ran same-origin), minus - * script, foreignObject, a ` - {% endif %} - - - {# - Lets an admin install this page as an app (icon, own window, no address bar), worth more - than a tab on the phone LuCI is opened from when the network is broken. Both files are - static, a theme having no dispatcher node to render them per request: start_url is - /cgi-bin/luci/, uhttpd's default (a moved LuCI opens the standard path), and - background/theme_color is the default palette's page colour, read once at install time. - .json, not .webmanifest: uhttpd's compiled-in MIME map has no entry for that extension, - so it answers application/octet-stream. - #} - - {# - iOS reads this link and never the manifest's icons array, and it scales the 192 square the - manifest also uses down to its own 180. One raster serves both. - #} - - {% if (dispatched?.css): %} - {# - The `css` property of the dispatched menu.d node: a stylesheet the server links for the - page instead of the view injecting one at module eval. `dispatched`, not `node`: the - dispatcher exports the resolved node as `dispatched` and never binds `node`, so no ucode - theme emitted this link until openwrt/luci#8920. That commit also adds `css: 'string'` to - the node schema; without it the property is filtered out and this stays false, as on 24.10 - and 25.12. Versioned, as uhttpd sends no Cache-Control. Not `data-fs-shell`: the sheet - belongs to one page, so the SPA router must judge and contain it like any app sheet. - #} - - {% endif %} - {% if (css): %} - {# - no `title` attribute: on a - {% endif %} - {# - The catalogue is a CGI spawn on the critical path (30 ms on the router) that delivers 13 - bytes at lang=en, where no en catalogue exists because the msgids already are English. - The process is the cost, so emit those bytes inline when the language has no catalogue - and keep the tag when it has. The probe mirrors the server: load_catalog() reads every - `*..lmo` in /usr/lib/lua/luci/i18n, so a router shipping an en catalogue still gets - the tag; deciding by language NAME would drop it. Fails open: a throwing probe keeps the - tag, as a missing catalogue renders English and reports nothing. - #} - {%- let has_catalog = true; - try { has_catalog = length(require('fs').glob(`/usr/lib/lua/luci/i18n/*.${dispatcher.lang}.lmo`)) > 0; } catch (e) {} %} - {% if (has_catalog): %} - - {% else %} - - {% endif %} - {# - the one asset stock LuCI leaves without a cache key. Must stay synchronous and un-deferred: - luci.js captures `window.cbi_init` in its constructor, and `defer` is not an option for the - catalogue above either — footer.ut runs `L.require('menu-footstrap')` inline while the - parser is still running, so a module's `_()` would race a deferred window.TR. - #} - - diff --git a/luci-theme-footstrap/ucode/template/themes/footstrap/partials/notice.ut b/luci-theme-footstrap/ucode/template/themes/footstrap/partials/notice.ut deleted file mode 100644 index c6227eab..00000000 --- a/luci-theme-footstrap/ucode/template/themes/footstrap/partials/notice.ut +++ /dev/null @@ -1,16 +0,0 @@ -{# - One top-of-content warning notice: heading, sentence and an optional "go fix it" button. The - `dispatcher.lookup` guard must not drift: `path` is looked up before it is linked, so a build - without that page, or a user without rights to it, gets the warning and no dead link. - include(…, { title, text }) for a plain notice; add { path, label } for the button. - title/text are emitted unescaped: they are `_()` results over strings this theme ships, not - request data. - Licensed to the public under the Apache License 2.0. --#} -
-

{{ title }}

-

{{ text }}

- {% if (path && dispatcher.lookup(path)): %} - - {% endif %} -
diff --git a/luci-theme-footstrap/ucode/template/themes/footstrap/sysauth.ut b/luci-theme-footstrap/ucode/template/themes/footstrap/sysauth.ut deleted file mode 100644 index 429ea5e5..00000000 --- a/luci-theme-footstrap/ucode/template/themes/footstrap/sysauth.ut +++ /dev/null @@ -1,185 +0,0 @@ -{# - The LOGIN page. - - Copyright 2008 Steven Barth - Copyright 2008-2012 Jo-Philipp Wich - Licensed to the public under the Apache License 2.0. - - It exists because the generic template includes the header WITHOUT `blank_page: true`: with no - theme-local sysauth the whole chrome renders around the login form with every control dead. - No departure here may drop a field the backend posts. - Do not re-introduce a `