From d720f47888bd53dcba7ed3b93f9861dc7e24a6ac Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Tue, 29 Sep 2026 23:46:13 +0800 Subject: [PATCH] =?UTF-8?q?=F0=9F=8E=89=20Sync=202026-09-29=2023:46:13?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- clashoo/Makefile | 111 + clashoo/files/etc/config/clashoo | 156 + clashoo/files/etc/init.d/clashoo | 2507 +++++++ .../usr/share/clashoo/detect_core_arch.sh | 26 + .../usr/share/clashoo/diagnose_bypass.sh | 181 + .../usr/share/clashoo/lib/migrate_singbox.uc | 385 + .../clashoo/lib/normalize_singbox_config.uc | 939 +++ .../share/clashoo/lib/templates/default.json | 138 + .../usr/share/clashoo/lib/yaml2singbox.uc | 468 ++ .../share/clashoo/migrate_fake_ip_filter.sh | 42 + .../usr/share/clashoo/migrate_lan_acl.sh | 38 + .../usr/share/clashoo/net/access_check.sh | 89 + .../share/clashoo/net/access_check_cache.sh | 195 + .../share/clashoo/net/access_check_daemon.sh | 38 + .../usr/share/clashoo/net/dns_auto_setup.sh | 240 + clashoo/files/usr/share/clashoo/net/fw4.sh | 898 +++ .../usr/share/clashoo/net/log_format.awk | 43 + .../usr/share/clashoo/nftables/geoip6_cn.nft | 3414 +++++++++ .../usr/share/clashoo/nftables/geoip_cn.nft | 6212 +++++++++++++++++ .../files/usr/share/clashoo/rpc/rpc_async.sh | 44 + .../files/usr/share/clashoo/ruleset/cn-ip.srs | Bin 0 -> 36370 bytes .../files/usr/share/clashoo/ruleset/cn.mrs | Bin 0 -> 539699 bytes .../share/clashoo/ruleset/geolocation-!cn.srs | Bin 0 -> 166132 bytes .../usr/share/clashoo/ruleset/geosite-cn.srs | Bin 0 -> 27650 bytes .../usr/share/clashoo/ruleset/private-ip.srs | Bin 0 -> 144 bytes .../files/usr/share/clashoo/runtime/backup.sh | 21 + .../usr/share/clashoo/runtime/clashoo.sh | 347 + .../usr/share/clashoo/runtime/dns_helpers.sh | 451 ++ .../clashoo/runtime/dns_loopback_adapter.yq | 17 + .../usr/share/clashoo/runtime/iprules.sh | 98 + .../files/usr/share/clashoo/runtime/mixin.uc | 317 + .../share/clashoo/runtime/primary_group.sh | 49 + .../clashoo/runtime/quic_fallback_guard.yq | 9 + .../usr/share/clashoo/runtime/restore.sh | 31 + .../clashoo/runtime/sniffer_overrides.yq | 28 + clashoo/files/usr/share/clashoo/server.list | 63 + .../share/clashoo/update/component_update.sh | 642 ++ .../usr/share/clashoo/update/core_download.sh | 1233 ++++ .../files/usr/share/clashoo/update/geoip.sh | 267 + .../usr/share/clashoo/update/lgbm_update.sh | 52 + .../share/clashoo/update/maintenance_cron.sh | 36 + .../share/clashoo/update/panel_download.sh | 176 + .../usr/share/clashoo/update/proxy_lib.sh | 80 + .../clashoo/update/subscription_update.sh | 386 + .../update/subscription_update_cron.sh | 18 + .../share/clashoo/update/template_merge.sh | 101 + .../files/usr/share/clashoo/update/update.sh | 5 + .../usr/share/clashoo/update/update_all.sh | 20 + .../share/clashoo/update/update_china_ip.sh | 204 + .../001-skip-invalid-fakeip-domains.patch | 91 + luci-app-clashoo/Makefile | 100 + .../htdocs/luci-static/clashoo/logo.png | Bin 0 -> 210103 bytes .../resources/cm/addon/matchbrackets.js | 1 + .../luci-static/resources/cm/codemirror.css | 1 + .../luci-static/resources/cm/codemirror.js | 1 + .../resources/cm/mode/javascript.js | 1 + .../luci-static/resources/cm/mode/yaml.js | 1 + .../luci-static/resources/tools/clashoo.js | 264 + .../resources/view/clashoo/bytedance.svg | 12 + .../resources/view/clashoo/clashoo.css | 2097 ++++++ .../resources/view/clashoo/config.js | 1896 +++++ .../resources/view/clashoo/index.js | 4 + .../resources/view/clashoo/overview.js | 2030 ++++++ .../resources/view/clashoo/system.js | 1431 ++++ .../resources/view/clashoo/youtube.svg | 4 + luci-app-clashoo/po/templates/clashoo.pot | 1572 +++++ luci-app-clashoo/po/zh-cn/clashoo.po | 1579 +++++ luci-app-clashoo/po/zh_Hans | 1 + .../usr/share/clashoo/rpc/backup_archive.sh | 421 ++ .../share/luci/menu.d/luci-app-clashoo.json | 45 + .../share/rpcd/acl.d/luci-app-clashoo.json | 21 + .../root/usr/share/rpcd/ucode/luci.clashoo | 4649 ++++++++++++ scripts/gen-cn-nft.sh | 85 + scripts/gen-singbox-rulesets.sh | 57 + scripts/install.sh | 281 + scripts/uninstall.sh | 57 + 76 files changed, 37517 insertions(+) create mode 100644 clashoo/Makefile create mode 100644 clashoo/files/etc/config/clashoo create mode 100755 clashoo/files/etc/init.d/clashoo create mode 100755 clashoo/files/usr/share/clashoo/detect_core_arch.sh create mode 100644 clashoo/files/usr/share/clashoo/diagnose_bypass.sh create mode 100644 clashoo/files/usr/share/clashoo/lib/migrate_singbox.uc create mode 100644 clashoo/files/usr/share/clashoo/lib/normalize_singbox_config.uc create mode 100644 clashoo/files/usr/share/clashoo/lib/templates/default.json create mode 100644 clashoo/files/usr/share/clashoo/lib/yaml2singbox.uc create mode 100755 clashoo/files/usr/share/clashoo/migrate_fake_ip_filter.sh create mode 100644 clashoo/files/usr/share/clashoo/migrate_lan_acl.sh create mode 100755 clashoo/files/usr/share/clashoo/net/access_check.sh create mode 100755 clashoo/files/usr/share/clashoo/net/access_check_cache.sh create mode 100755 clashoo/files/usr/share/clashoo/net/access_check_daemon.sh create mode 100644 clashoo/files/usr/share/clashoo/net/dns_auto_setup.sh create mode 100755 clashoo/files/usr/share/clashoo/net/fw4.sh create mode 100644 clashoo/files/usr/share/clashoo/net/log_format.awk create mode 100644 clashoo/files/usr/share/clashoo/nftables/geoip6_cn.nft create mode 100644 clashoo/files/usr/share/clashoo/nftables/geoip_cn.nft create mode 100644 clashoo/files/usr/share/clashoo/rpc/rpc_async.sh create mode 100644 clashoo/files/usr/share/clashoo/ruleset/cn-ip.srs create mode 100644 clashoo/files/usr/share/clashoo/ruleset/cn.mrs create mode 100644 clashoo/files/usr/share/clashoo/ruleset/geolocation-!cn.srs create mode 100644 clashoo/files/usr/share/clashoo/ruleset/geosite-cn.srs create mode 100644 clashoo/files/usr/share/clashoo/ruleset/private-ip.srs create mode 100755 clashoo/files/usr/share/clashoo/runtime/backup.sh create mode 100755 clashoo/files/usr/share/clashoo/runtime/clashoo.sh create mode 100755 clashoo/files/usr/share/clashoo/runtime/dns_helpers.sh create mode 100644 clashoo/files/usr/share/clashoo/runtime/dns_loopback_adapter.yq create mode 100755 clashoo/files/usr/share/clashoo/runtime/iprules.sh create mode 100644 clashoo/files/usr/share/clashoo/runtime/mixin.uc create mode 100755 clashoo/files/usr/share/clashoo/runtime/primary_group.sh create mode 100644 clashoo/files/usr/share/clashoo/runtime/quic_fallback_guard.yq create mode 100755 clashoo/files/usr/share/clashoo/runtime/restore.sh create mode 100644 clashoo/files/usr/share/clashoo/runtime/sniffer_overrides.yq create mode 100755 clashoo/files/usr/share/clashoo/server.list create mode 100755 clashoo/files/usr/share/clashoo/update/component_update.sh create mode 100755 clashoo/files/usr/share/clashoo/update/core_download.sh create mode 100755 clashoo/files/usr/share/clashoo/update/geoip.sh create mode 100755 clashoo/files/usr/share/clashoo/update/lgbm_update.sh create mode 100755 clashoo/files/usr/share/clashoo/update/maintenance_cron.sh create mode 100755 clashoo/files/usr/share/clashoo/update/panel_download.sh create mode 100644 clashoo/files/usr/share/clashoo/update/proxy_lib.sh create mode 100755 clashoo/files/usr/share/clashoo/update/subscription_update.sh create mode 100755 clashoo/files/usr/share/clashoo/update/subscription_update_cron.sh create mode 100755 clashoo/files/usr/share/clashoo/update/template_merge.sh create mode 100755 clashoo/files/usr/share/clashoo/update/update.sh create mode 100755 clashoo/files/usr/share/clashoo/update/update_all.sh create mode 100755 clashoo/files/usr/share/clashoo/update/update_china_ip.sh create mode 100644 clashoo/patches/001-skip-invalid-fakeip-domains.patch create mode 100644 luci-app-clashoo/Makefile create mode 100644 luci-app-clashoo/htdocs/luci-static/clashoo/logo.png create mode 100644 luci-app-clashoo/htdocs/luci-static/resources/cm/addon/matchbrackets.js create mode 100644 luci-app-clashoo/htdocs/luci-static/resources/cm/codemirror.css create mode 100644 luci-app-clashoo/htdocs/luci-static/resources/cm/codemirror.js create mode 100644 luci-app-clashoo/htdocs/luci-static/resources/cm/mode/javascript.js create mode 100644 luci-app-clashoo/htdocs/luci-static/resources/cm/mode/yaml.js create mode 100644 luci-app-clashoo/htdocs/luci-static/resources/tools/clashoo.js create mode 100644 luci-app-clashoo/htdocs/luci-static/resources/view/clashoo/bytedance.svg create mode 100644 luci-app-clashoo/htdocs/luci-static/resources/view/clashoo/clashoo.css create mode 100644 luci-app-clashoo/htdocs/luci-static/resources/view/clashoo/config.js create mode 100644 luci-app-clashoo/htdocs/luci-static/resources/view/clashoo/index.js create mode 100644 luci-app-clashoo/htdocs/luci-static/resources/view/clashoo/overview.js create mode 100644 luci-app-clashoo/htdocs/luci-static/resources/view/clashoo/system.js create mode 100644 luci-app-clashoo/htdocs/luci-static/resources/view/clashoo/youtube.svg create mode 100644 luci-app-clashoo/po/templates/clashoo.pot create mode 100644 luci-app-clashoo/po/zh-cn/clashoo.po create mode 120000 luci-app-clashoo/po/zh_Hans create mode 100755 luci-app-clashoo/root/usr/share/clashoo/rpc/backup_archive.sh create mode 100644 luci-app-clashoo/root/usr/share/luci/menu.d/luci-app-clashoo.json create mode 100644 luci-app-clashoo/root/usr/share/rpcd/acl.d/luci-app-clashoo.json create mode 100755 luci-app-clashoo/root/usr/share/rpcd/ucode/luci.clashoo create mode 100644 scripts/gen-cn-nft.sh create mode 100755 scripts/gen-singbox-rulesets.sh create mode 100755 scripts/install.sh create mode 100755 scripts/uninstall.sh diff --git a/clashoo/Makefile b/clashoo/Makefile new file mode 100644 index 000000000..8b8087c8a --- /dev/null +++ b/clashoo/Makefile @@ -0,0 +1,111 @@ +include $(TOPDIR)/rules.mk + +PKG_NAME:=clashoo +PKG_SHORT_SHA:=63bd52e +PKG_COMMIT_DATE:=2026.09.27 + +PKG_VERSION:=$(PKG_COMMIT_DATE)~$(PKG_SHORT_SHA) +PKG_RELEASE:=1 + +PKG_SOURCE:=$(PKG_NAME)-alpha-$(PKG_SHORT_SHA).tar.gz +PKG_SOURCE_SUBDIR:=$(PKG_NAME)-alpha-$(PKG_SHORT_SHA) +PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-alpha-$(PKG_SHORT_SHA) +PKG_SOURCE_URL:=https://github.com/kenzok8/openwrt-clashoo/releases/download/mihomo-src +PKG_SOURCE_VERSION:=16a867c31778167b5297025cafd444ea8463b108 +PKG_HASH:=skip +PKG_BUILD_VERSION:=alpha-$(PKG_SHORT_SHA) + +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/bin + ln -sf /usr/bin/mihomo $(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/postinst +#!/bin/sh +if [ -z "$${IPKG_INSTROOT}" ]; then + [ -x /usr/bin/mihomo ] && [ ! -x /usr/bin/clash-meta ] && ln -sf /usr/bin/mihomo /usr/bin/clash-meta + 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 + /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 new file mode 100644 index 000000000..1b0e23920 --- /dev/null +++ b/clashoo/files/etc/config/clashoo @@ -0,0 +1,156 @@ + +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 '3' + 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 '3' + 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 new file mode 100755 index 000000000..b7e25ab9a --- /dev/null +++ b/clashoo/files/etc/init.d/clashoo @@ -0,0 +1,2507 @@ +#!/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/bin/mihomo-stable /usr/bin/mihomo /usr/bin/clash-meta /etc/clashoo/clash" +} + +_migrate_legacy_mihomo_stable() { + local legacy=/usr/bin/clash-meta version + [ -x /usr/bin/mihomo-stable ] && 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 + cp -f "$legacy" /usr/bin/mihomo-stable 2>/dev/null && chmod 0755 /usr/bin/mihomo-stable +} + +_fallback_missing_mihomo_core() { + local selected fallback + is_singbox_selected && return 0 + selected="$(uci -q get clashoo.config.core 2>/dev/null)" + case "$selected" in + 2) + [ -x /usr/bin/mihomo-stable ] && return 0 + [ -x /usr/bin/mihomo ] || return 0 + fallback=3 + ;; + 3) + [ -x /usr/bin/mihomo ] && return 0 + [ -x /usr/bin/mihomo-stable ] || return 0 + fallback=2 + ;; + *) return 0 ;; + esac + uci -q set clashoo.config.core="$fallback" + uci -q set clashoo.config.dcore="$fallback" + uci -q commit clashoo >/dev/null 2>&1 + if [ "$fallback" = "3" ]; then + log_msg "Stable core missing, falling back to Alpha" "稳定版内核缺失,自动回退到 Alpha" + else + log_msg "Alpha core missing, falling back to stable" "Alpha 内核缺失,自动回退到稳定版" + 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) + [ -x /usr/bin/mihomo-stable ] && echo /usr/bin/mihomo-stable && return + return 1 + ;; + 3|mihomo-alpha) + [ -x /usr/bin/mihomo ] && echo /usr/bin/mihomo && return + return 1 + ;; + esac + _detect_core +} + +core_supports_advanced_features() { + case "$CLASH" in + */mihomo|*/mihomo-stable|*/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. + rm -f /etc/init.d/._clash \ + /etc/init.d/._* \ + /etc/init.d/*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(){ +#=========================================================================================================================== + 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 '/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 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,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 +} + +_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() { +#=========================================================================================================================== + 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' /etc/clashoo/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:' /etc/clashoo/config.yaml && ! grep -q "^ \{0,\}listen:" /etc/clashoo/config.yaml; then + sed -i "/^dns:/a\ listen: 0.0.0.0:${dns_port}" /etc/clashoo/config.yaml 2>/dev/null + fi + 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 数据" + /usr/share/clashoo/update/geoip.sh >/dev/null 2>&1 + + 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 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 core not found, detected binary is unavailable: $CLASH" "找不到可用的 mihomo 内核: $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() { + # 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 + + _migrate_dns_roles >/dev/null 2>&1 + + enable_dns=$(uci get clashoo.config.enable_dns 2>/dev/null) + + if [ -z "$(grep -E "^ {0,}listen:" /etc/clashoo/config.yaml)" ] || [ -z "$(grep -E "^ {0,}enhanced-mode:" /etc/clashoo/config.yaml)" ] || [ -z "$(grep -E "^ {0,}dns:" /etc/clashoo/config.yaml)" ];then + + if [ "${enable_dns:-0}" -eq 0 ];then + uci set clashoo.config.enable_dns="1" && uci commit clashoo + log_msg "Enabling Custom Dns" "启用自定义DNS" + fi + + fi + + if { egrep -q '^ {0,}rule-providers:' "/etc/clashoo/config.yaml" || egrep -q '^ {0,}script:' "/etc/clashoo/config.yaml"; } && ! core_supports_advanced_features; then + if [ -x /usr/bin/mihomo ]; then + uci set clashoo.config.core="3" && uci commit clashoo + elif [ -x /usr/bin/mihomo-stable ]; then + uci set clashoo.config.core="2" && 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 + 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 [ -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 + yml_change >/dev/null 2>&1 + 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 + + _prepare_geo_bootstrap_mode + _remap_dns_system_nameserver >/dev/null 2>&1 + ensure_dns_cn_policy_fallback >/dev/null 2>&1 + + + if [ ! -f /etc/clashoo/config.yaml ];then + 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 + + # Sync processed config (with DNS listen injected) to mihomo working directory + 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)" +} + +_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-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="/" + + # 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=/ + 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 + _fallback_missing_mihomo_core + 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) & + +#=========================================================================================================================== +} + +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 + resolve_effective_tp_modes + runtime_state_record_preflight "mihomo" + backend_remove_rules 2>/dev/null + ( select_config && _start_prepare_config ) >/dev/null 2>&1 + # hot-reload via mihomo REST API (config + addtype rules), no process restart or tunnel drop + local _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 + curl -m 5 -H "Authorization: Bearer ${_ds}" -H "Content-Type: application/json" \ + -X PUT -d '{"path":"'"$CONFIG_YAML"'"}' \ + "http://${_lip}:${_dp}/configs?force=true" >/dev/null 2>&1 + backend_apply_rules 2>/dev/null + if [ "$(uci -q get clashoo.config.core_only 2>/dev/null)" != "1" ]; then + _reload_dnsmasq >/dev/null 2>&1 + fi + 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 new file mode 100755 index 000000000..fbb3defda --- /dev/null +++ b/clashoo/files/usr/share/clashoo/detect_core_arch.sh @@ -0,0 +1,26 @@ +#!/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 new file mode 100644 index 000000000..0e01a30d2 --- /dev/null +++ b/clashoo/files/usr/share/clashoo/diagnose_bypass.sh @@ -0,0 +1,181 @@ +#!/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/migrate_singbox.uc b/clashoo/files/usr/share/clashoo/lib/migrate_singbox.uc new file mode 100644 index 000000000..a200b982e --- /dev/null +++ b/clashoo/files/usr/share/clashoo/lib/migrate_singbox.uc @@ -0,0 +1,385 @@ +#!/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 new file mode 100644 index 000000000..cd6a1d3c4 --- /dev/null +++ b/clashoo/files/usr/share/clashoo/lib/normalize_singbox_config.uc @@ -0,0 +1,939 @@ +#!/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 new file mode 100644 index 000000000..84f1ee22e --- /dev/null +++ b/clashoo/files/usr/share/clashoo/lib/templates/default.json @@ -0,0 +1,138 @@ +{ + "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 new file mode 100644 index 000000000..37e40c766 --- /dev/null +++ b/clashoo/files/usr/share/clashoo/lib/yaml2singbox.uc @@ -0,0 +1,468 @@ +#!/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 new file mode 100755 index 000000000..0cc4f362d --- /dev/null +++ b/clashoo/files/usr/share/clashoo/migrate_fake_ip_filter.sh @@ -0,0 +1,42 @@ +#!/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 new file mode 100644 index 000000000..750e39940 --- /dev/null +++ b/clashoo/files/usr/share/clashoo/migrate_lan_acl.sh @@ -0,0 +1,38 @@ +#!/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 new file mode 100755 index 000000000..6356d8419 --- /dev/null +++ b/clashoo/files/usr/share/clashoo/net/access_check.sh @@ -0,0 +1,89 @@ +#!/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 new file mode 100755 index 000000000..ff930eb04 --- /dev/null +++ b/clashoo/files/usr/share/clashoo/net/access_check_cache.sh @@ -0,0 +1,195 @@ +#!/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 + 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 new file mode 100644 index 000000000..b1e22c8de --- /dev/null +++ b/clashoo/files/usr/share/clashoo/net/dns_auto_setup.sh @@ -0,0 +1,240 @@ +#!/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 new file mode 100755 index 000000000..540c6b051 --- /dev/null +++ b/clashoo/files/usr/share/clashoo/net/fw4.sh @@ -0,0 +1,898 @@ +#!/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 new file mode 100644 index 000000000..0813c3b78 --- /dev/null +++ b/clashoo/files/usr/share/clashoo/net/log_format.awk @@ -0,0 +1,43 @@ +# 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 new file mode 100644 index 000000000..ad0f24d8d --- /dev/null +++ b/clashoo/files/usr/share/clashoo/nftables/geoip6_cn.nft @@ -0,0 +1,3414 @@ +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:4c00::/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: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: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:7d00::/32, + 2402:7d80::/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::/42, + 2403:6380:41::/48, + 2403:6380:43::/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: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:8008::/45, + 2405:84c0:8010::/48, + 2405:84c0:8019::/48, + 2405:84c0:801c::/46, + 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:8060::/43, + 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:180::/41, + 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:a00::/44, + 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:9112::/47, + 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::/46, + 2406:840:9664::/47, + 2406:840:9667::/48, + 2406:840:9668::/45, + 2406:840:9670::/44, + 2406:840:9680::/41, + 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:9965::/48, + 2406:840:9968::/46, + 2406:840:996d::/48, + 2406:840:996e::/47, + 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::/46, + 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::/48, + 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:fef1::/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::/40, + 2408:4000:100::/47, + 2408:4000:103::/48, + 2408:4000:104::/46, + 2408:4000:108::/45, + 2408:4000:110::/44, + 2408:4000:120::/43, + 2408:4000:140::/42, + 2408:4000:180::/41, + 2408:4000:200::/39, + 2408:4000:400::/38, + 2408:4000:800::/37, + 2408:4000:1000::/36, + 2408:4000:2000::/35, + 2408:4000:4000::/34, + 2408:4000:8000::/33, + 2408:4001::/32, + 2408:4002::/31, + 2408:4004::/30, + 2408:4008::/29, + 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: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, + 2620:57:4004::/47, + 2804:1e48:9002::/48, + 2a03:f900::/29, + 2a04:3e00:1002::/48, + 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:9030::/48, + 2a04:f580:9040::/48, + 2a04:f580:9050::/48, + 2a04:f580:9060::/48, + 2a04:f580:9070::/48, + 2a04:f580:9080::/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::/43, + 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: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::/44, + 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 new file mode 100644 index 000000000..0a0ed205f --- /dev/null +++ b/clashoo/files/usr/share/clashoo/nftables/geoip_cn.nft @@ -0,0 +1,6212 @@ +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, + 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, + 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.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.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.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.188.0/22, + 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.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.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.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.92.0.0/14, + 47.96.0.0/11, + 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/15, + 59.82.0.0/16, + 59.83.0.0/17, + 59.83.144.0/20, + 59.83.160.0/20, + 59.83.192.0/19, + 59.83.224.0/21, + 59.83.232.0/22, + 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/22, + 59.153.173.0/24, + 59.153.174.0/23, + 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.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/23, + 103.5.194.0/24, + 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.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/19, + 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.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/23, + 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.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.169.216.0/24, + 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.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.132.0/22, + 103.235.136.0/21, + 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.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/15, + 110.42.0.0/20, + 110.42.16.0/24, + 110.42.18.0/23, + 110.42.20.0/22, + 110.42.24.0/21, + 110.42.32.0/19, + 110.42.64.0/18, + 110.42.128.0/17, + 110.43.0.0/16, + 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/15, + 110.98.0.0/16, + 110.100.0.0/14, + 110.104.0.0/13, + 110.112.0.0/13, + 110.120.0.0/16, + 110.121.0.0/22, + 110.121.8.0/21, + 110.121.16.0/20, + 110.121.32.0/19, + 110.121.64.0/18, + 110.121.128.0/17, + 110.122.0.0/15, + 110.124.0.0/14, + 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.232.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/15, + 114.66.0.0/17, + 114.66.224.0/22, + 114.66.236.0/22, + 114.66.240.0/20, + 114.67.0.0/16, + 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/22, + 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.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.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.207.0/24, + 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/24, + 119.59.130.0/24, + 119.59.132.0/22, + 119.59.136.0/21, + 119.59.144.0/20, + 119.59.160.0/19, + 119.59.192.0/18, + 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.152.0/23, + 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/24, + 121.59.110.0/23, + 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.112.0/21, + 122.8.124.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.197.0/24, + 123.49.198.0/23, + 123.49.200.0/21, + 123.49.208.0/20, + 123.49.224.0/21, + 123.49.232.0/22, + 123.49.236.0/24, + 123.49.240.0/24, + 123.49.242.0/23, + 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.68.176.0/20, + 124.68.224.0/20, + 124.68.244.0/22, + 124.68.248.0/21, + 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.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/20, + 140.210.16.0/21, + 140.210.24.0/22, + 140.210.28.0/23, + 140.210.30.0/24, + 140.210.32.0/19, + 140.210.64.0/18, + 140.210.128.0/17, + 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.192.0/19, + 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, + 148.70.0.0/16, + 149.41.64.0/18, + 149.41.192.0/19, + 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, + 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.42.0/23, + 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.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.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.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.217.0/24, + 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.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.63.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.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.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/23, + 202.144.198.0/24, + 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.208.0/21, + 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.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/23, + 203.107.2.0/24, + 203.107.4.0/22, + 203.107.8.0/21, + 203.107.16.0/20, + 203.107.32.0/19, + 203.107.69.0/24, + 203.107.70.0/23, + 203.107.72.0/21, + 203.107.80.0/20, + 203.107.96.0/19, + 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.225.0/24, + 203.128.226.0/23, + 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, + 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.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.4.0/22, + 223.122.12.0/22, + 223.122.18.0/23, + 223.122.20.0/22, + 223.122.26.0/23, + 223.122.28.0/22, + 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 new file mode 100644 index 000000000..ee00dfd43 --- /dev/null +++ b/clashoo/files/usr/share/clashoo/rpc/rpc_async.sh @@ -0,0 +1,44 @@ +#!/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 new file mode 100644 index 0000000000000000000000000000000000000000..bc53b98ffe7008bdb9809cfa4740a54a0b2e6a82 GIT binary patch literal 36370 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 Yb(FgxeQN3oVR9~YadA59&Nf^A0j|oUfdBvi literal 0 HcmV?d00001 diff --git a/clashoo/files/usr/share/clashoo/ruleset/cn.mrs b/clashoo/files/usr/share/clashoo/ruleset/cn.mrs new file mode 100644 index 0000000000000000000000000000000000000000..24308eda4cf7ffdd558baa94c92fa7e8cbbbb84e GIT binary patch literal 539699 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�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/mP) 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
  • hHPFLrvTf>@uozgYc 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
    A<3{Q-&$wPPPtS(6e5xF@iAki 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

    *kD zJRkA2w4LxR)zd80q8e{B20C_stl(nx29w6EIR#aX>VUb~dY%1@FpW5>ge~vY;@ELU zZ;(4VtIC;9a-$3v$gkv{58hqHvTd9Hx9EJM8lxX7D43D_ntJF~=e(q|?E zbwIRdx*|G-jknOb{rqOwp(O+n+C_VWE!0UF>dg%*p1Ct{-;Ytka}a-xr8CSC=IwVM zGkhrkLO{L0*Wb2y@&%z}D7f?F7zL?PXcW=6@|*ry>ULW37u{#%;gn-l$5i_sxPW2H z-6+~h2vuRRY&P~SWaMfHKZRN$XBBG2jIjAF?>1CUwP(D|e_k@HHk zm91cL_`dB0O4VP8pxQpli?J)A;gx*(6kKF`fdVOE+Y*GllDRHUzqmT|5+RFOwJ(&) z5fL6hmWtC#`p8?~Sbqf|A*kP~yvV`VnDHj(h!GdANVP^){jQ=bb}Ug-jjD zb5%9ex@uBI%7#5{e&yyA)sO}G- z-^B&;Iw^<|<;di%)kHD97&G-(OGz^;fD0v(!-O zt>{X1-NH{7++Ee5HI_dis>SPBmETwux&*n<08|ZYqZ_}Zs=hs)qaQ{_YW-Vo2OomXe^=UeAca(wOy=dHn7OSRbm@cBUSsSZ zvd^WOGd-s+3XApY1LbT^?atcflCCAK2=NX)C>0nG7Q3q99WMhaJSWn485S5XrQI^v z(w|O7&mhZb#q%}jFxI%J*%U#9uDvORmC-w?)}<@&Kgxb>twn0Fo2o5f$PUBUN=t|) zmf6V47DILR2&les*JFjaIgipv(U1c8HGRb|RW%h^3PEZ%^EaedgJ*YIDZH@$3IS4m zb9XEcx+D|qvNW_z&DTg`U~EpPRaMtDaczGet^P;OROq!eW;rN$#cP&kAg^?4`%p&! zE~8HTWi9NZeM6|UK6DCe$c-hwf(sE{tp2GmV9~50yUj_xAq7EHzz*@U#;t9q<%Mj! z3DkDtDGjRa0v)K6S$4OL^bdD|jckIvsL!n#4Y-@yh1(7>JO+YnTNMy3+bJVNux+Tg z=n2gLHr~n0s~VnFpNKYKHv|A1I-6)ljgf+k`Y34~I`X>*bI>43vjf@UtNrqd8mh~p zN30_Kg`QQpE80#Gs#i!8ittsnsUFaDEM=HPMXgUuq=Etp7AnGXO-Mk+K46`suzv?!m45TjR zyd@IQh^i(wM=sYUyQu`DL(wwGjCZaDRT^?6_IjYsA&MlsZp*h&q*Hv7(y~^1bN%}n zLZ18r3h+ZvRXuW8G^tLeOy8jS{~JmzEvPOsxVB7}Nys@=V4Nqr%irLQxUFptKv6a7 zR5kX|;?&ST-oWn*o_==#g0gRah_)CUyK0O3e^|N2P9%piqpD}oU;7Iy^ACkziz|F? z^V4ua<2t>$f}tm!08%SKug+jQ$-5m)BZwTS6&ux5cX+Zm;sM6nE zHEEn93pp;$NBd#gHm7fU#4C<0Wdkr&ES8 zh3kWe?-yDjO+CwL&yR&&RSEAJ-(5OZC&EJKf-u^z{`)neklBBwNsc&9Fy-or0nM6C zxOYqQzauqY7p^;1>IxlO@Fd&4&C3>=)Z(1?94nE-P87Sclkibt&=s~?IyE!^I zK?ki$2WMcOYP`O{(1wFf1nXIyp~yf521*$G>L|J%(VxL-f&n}4XmyQV)d7~`eU8of zU^Xf;Qp=*lqCa7PR&_wo>wxgXIyk!LXK>EoyrY{z94H(749>Ly_)q-31%dN3(DRPm zQ(e8L_FvxzeN`oBR0Bog;ooWQYEirUpTSZ63LHJ>T@gCkz8|On0@GPwFi@(5UzJKd z1H&1}c3$hFAG*Iy-vS7t2US(iKqbKk+w>LA;1GV~KdQ&o3)s&8aq0$1*%Z+j!|H<% zbf8K&>(LY3pjVTqf`XsH;hz8=rE@Ky`UWWfKv;l+9>kG6=ZIX3s|Y~FB4G$13{=Ac z$K6;PR7Gy=yupc6?+VzH%kI`RBj7GRI$PLg;yO?xXBuE{{D z>TFCII;-kYg|8aw9FvM1FF|II)#3UWty|gJ@f$CQpkLGRCby}}0wFko*6~#jh0p%G z>QhZg6&_WE67pW3tSaOQlVUxTE|QRe(H?=`1NG21HMvBCtL->44;A~~)AT^Ic+!j`Yhld_VaW!N%PTJVS3;fA(!ToS0?^7WHLoZs}KK zq0^B5ws^RT{Buig#i2F!DIN@82lrO^)C=Uh>D*eE+#i_ zx$r2Zh=2=nY}#&B#Knyf`6KzuSBl>>D-vkn>&6Ya=p>uvSKn3kFMO8}m1B(Q7YLEA zj8%z9B7cRdBD3`0x(`wHeG0{OJ&#!c(QDjm+J7-4y!v$05dy8kN3{{ww|h&f zlsQqZH<%x3PM`b^u02{+5nJdnvY$zMXrlcqJo=*uDxzQZnz*QXexP_P${3OB@)Bu3 z`mFJ6ye?`|6{;?9xiXt-(ukK~Y6sz}UFSvAW={{Oss=@-Qmv{gK;cj*@H=78ibeCJ zE<(_iS1P;FsHyqPOQ$jm5qE>I)jtC=aU zRF4D+Xh4B5zW|&7fMF+7vk+nu5Hlbp4HY;-KvKjk!5bV<f~@MbiyPQSI3lKD zjQsi@0cX4#?$0SiYgA-s*5OSzX}-#z96OA0eTwbYQEis1o$Rbne=gO(PLgUDA*ueU zrGAATy2AEA#?9Tj>O%0eE>)UfHpdoEQ8h9Nx+||}Rry`JEUv|BH`dXwssz`A>d(rI zJ50S)!r8eU!c1mW?sGMC(gQ5NPM10^ZF;4LxC24eB26__tFM%lVu=y@&$T+GP4g-# z2N^<_mgA*8NX+Q`lHB!ZRm9xI{q3f^syjmI?(T-gv3r|VB=Xg^*LJd#kVm-#6wc{98{72J|Q?RxWq$K_H-l{+rO9OwHd> z_2`LRO*-86@jQd5*}fk!{&W+`x}m7Hp7lJfqvTX?Ohx%jib=>y2Z%apN;j-v!RcZ$ zadJsL{V^f4p7ezi3fHru-ct9?pF^hd(-<{Dn$Th1VJRf{s}s$o)OxL$^-N&j2a9fz=!sv$1jkyfzgq*tYqVT@7Amb0!;_*0E{ z+qy%Y#!r;=#mU3GxQXwCKS6~`lNqsp<5KGLe=KyX&>LM}*VyS#q508a^s#HOcGaaX&c{GiS5+N2PNx#6s-m{4>dCK3>3an#axkBT zy5t-nx&CmD^h(p8PP>Gb$!;G1SrFJWmGr0p7ggr{?qw~#zMi_yLJ9N+Gk+zele!Vl zEjC>{x8R(eeQ^us(QfIl8P7;lC91^dR z{Nr@0S&DHQm!x(x8Ogad<9`*EQ7O)1iJeTZOICl!TRiX_!XEq#jBhsCv2>y$)}W&EX7APiL|y4JKw#g1;BIu5bRn(9bqQdtUs zdvS*Yq-#<$aXZyY2pO4dN%#?LZ=`dd!&aa4cE+fDcZvu3lCpHXEUZd#9XF?OlQDDY zOdqxkW)LOYxJ<{GLpj$b#n^8S^qpKxT3q4GQZ)#F!SC*FR^g1UGVCguTJ7GU3ayaB zI8^D=qZ+1S;TXL?1yL}jmAGV-DlP3)%k=c=9z$l}_UEjEWSB9?+bx>ZapRn>_gZSQ z!#gIhs3PLis?mRDIm1Abp+=>pmUC(fwP{m9jbW!vDbz`~R8d7j=#Ql4h+3N|HKK?y z8HP$Sxo&0LoLhdH_%~C#P4k9x>$Cv*@}av@$fZ^(d^YJfcgz>9F(U-Ff{g{zy0g;w zSc2q-AML=~4Ft>3Qa!9ot_8VVgN3?8;VUA|v<0WVH!;JmJS9`r+fyJ~#E?l8f}jGq zW)zMB4b;%4MeAH*j%T1w&>egXM3OrK1Vlso*U7zg?uu>B8Hw`il@-M&Rfnvdk55x$ zI@grcm7Z<5=xJGRDN<5LHwxv9#7+-MNA8l( zuA&ebTP=GIJ+*c_gZP@${;XjKw|$Q(h_+ystCXh9k?ymRsCaESCf~Z{M;gCZJ=0yu z)Ebd$VpI9bZl$GqMy>E`<-Y?GkBrqZffysBke|VuQ`{BgqpKr*iD_79ti?qp5-fHV zAE?2`2ga2$4h?_uOY>>T~+kz#_Xhj>_1&C>5Az#iFSraCh3Yv z#s9EOjJ=fhW->jDUA%D$y>M2NpLfdeLzhuc(J6^gl*kZ80h>q6n&jBcp5>4yyY>*X zZUKZCx`kN8k`vKCT;P+@8wNUrK~WS4LcVoBxW%rH^P>b=lpse4f?xtQ1#wdl{Aa?U#8)+ToNVJY{>GHH zNwI}8oDgg7YB&t6SF*;FDZiQL7s>VVMX4kJK+2o`Yi~@qZzg6qBh9qU?QhrG4S;Ixm0Des)Eg5ERW#)H zqLTSk2NC04cS6Aa6_TV`NIJhEjYqeRS))FGr`*vQ@%=j1J#pLjPV=8jxxShE_pFw; za|@wVdpwR^an2|mvHt5M%S%aNp`cYusVBb5n3TS`4f?Nf#Ye+^CZ1|uf3N>yvX|)Y z?uwK;B8*n`A1D$@vs%u$GYr#7$)q$DD&N+N(sabsh!GL3khY%G6)Aw?6y|;B)c?6+ z+Tt?)>h!aCA^*GLO8S$UE{cP@qSFRZO-YiFM%wFJ=ExWN%cM6~XN)$VlJtN;06UYw zmpIxzYSnQ07eTYzYg;fFl{rLN*d{;qNmZN2xX5`YJA?!bd^?O8~HIA zqYlgdwR%b;`Z0aYnNBIQnZ{o_c)nCy=oW6Gt)n5C0t(a_KaF-_XRnP`2yxdQe*`UZ z%U?zs+5)*v@aG4%=Zhe3>xNz&7}AUWN^%M`?Iqbb>I>l3@_ZE6x@}1vA7>@R}yiDv67ov*w~SZT{R^{m@zIU6on28!R8nQ zSir!zy+Lstd9=Avv5^Z;`j>=j#%O?=Q`#N`+6zCoccBnsrK*|?s4Bc3U*x+M6`)J$ zN=ccy$sr<3Od|72ojDVtB}$jkA#RRbNv3G0#ot7%m{c-ke9kC| zoap3vznALD%_x=iI~5UD#w=F)(kiJ1Q_|$rfgy!6FVOg_=e$hAB7Ot;CKx zgAy?jw{%>e>#1s~mJ#1Ta%$0~dg9(|SxuLmTgDixQ(ETI?kv{p&7)nKD;r`u>5`<5 z8D&2eiK1tT8r?dni%H7;ot(LwX-cE+XbDURwL}@0r&3zvBU7u7Q|8+f{v3*%YwOda z<{0&HMGjyPS6`YOU!CE46t8C27hXME%rQb;C4&AVzUpqb6BD+g zfMD>GKv1Kz>e>$L70ZmQXmSU2${w7~-xPYJy8hHH>hV0W1Ej;GKZP;rFfmrfm*%@7 zCe=P(m?x!>CvKi+@7{R-q!gmHSWS0}6lGF~wI%1DIN?cgRZw$J>EuG`HO?o)s9u~? zO=e$zr@E*`)k$^l#gNzJq`SGImU3#TGWqi}2ZLDZ$hmmkIi21dB>hvSWv?g|_}ARM z7_4$Iic);zDy;CQFvBj4gJKeBx2cpcbnqtHE;;d3haRL|s24l%iG0CYG zcGl8Mr~BObRj8R#`Ye)KQ{AW|lyptXfw4~QjADNdQP;Rh=LH~=f?fkfC|!7Yr9_s<-ar%Ct-)vL8XQma(cL? zL;7B1x++f7l~Kd5NU=0Y(7!45VMJjKwz|na%PAUW$ z1V@@bFQqtUjy71A8_E2Of=C)MJCOQb9EtI#ia4mMF8(uVn_vGB!gOKI&0iQry67Iy zj#R}AxDYpvo}RE%YksLj)z5!IgbhT_6w3YROS&r0*+!{b>FG#fC{u?2_2?UaE|PRT z*Hl$+RZXZlTP8D9WMpVTMYo9kunUD7I?A>(uq;1c69M>D!~gaS!dfW0CVnkigH2wq z5TySDtWWFQtQOLfZbKx7|Gki;_tR(83C}+SxZ=9p-5EC=3M)RT7hD-x{EsibJQ+jy z;oMa&)so)G6aFLV*Qh>`ez|f2)XVh*@>Wm$*X4iwzmJbkuHVJ{i$Hcf^@16-7J0ia z&tKcXG5*MZzwY)n?0?|}_ntGnmcE0BX~GRns#zyHEl z>M!7rJPJG=Mndm@mRZV-cLJ*(pG5Vif{8qhvXJ(l#ZoE^GnM>>Ra}i^^`$ay6Zc`X ziABFq>Re%*{xA0F(m&H;6i!~mw&q(IGWPz2fx?gY3x7h*zx3+nT(F`LbaT|sI&=KB zwq|lujUA#~Y|2fNumO)k2y$=X4rzyL)9j1$j`uPib4l!r8 z=x6W5%LP)zrX?AE4wd}3Ki*L=UQz6xS>1zHRgZV3px#|b-237t#LaI*2Ql5*tBEWww%(_aK zukfTjkB*!!HS@)i+bj9Ej9l(YwPIa@Q2v465eU0}MJQXSQhzF1;$Ll<9n04WHWN!& z2~)o(MN`<44V#jTxk>kx)@l(Bxjt=qUnb%@)tP137e)WVk|};3A-+Sj_#W@v<8e7Wg6{EE;Ym^lGa=>58&I~pf+ zugEMXF#npAky(p7(o6;AJdhSD}d8)LVY;;YpA z^|MK4QxgbR0NmxIWk>op0ZPO00KEoEr+3_Lv^~B`a%Ku38T~> zm7f|PHhVUXtc8}ndNPYe4Jih2P=C|*t)2EIiIdYBR`8L`LOxhXcDs>+AN3$8lm6iJ zjVj3~M!rBO``VLS=gpa)X4WZO6rw0Sa&x1qX9B1}3k3oClMsZLQyW19uES_Ee?$uS zgrGTn+U*ewr2ca1#02tw7R!hH60Pc1TOV1V3Gy3waYm2hqJ5L8ZOE8YLOz??)rQtb z0Rlw6DCCWAozzrMUTC0FTh8=Gm3H593JbKly0~z{mL;^B?Hi330GCr{~fCj)+ICD(-Sv!b}4A+6>3v`d=Q3>3+G@% z1p?;5g$)xr02IJw(Zo&}LIz;jiDR;kpSc@E|R6~lc2N~a;3Y35cy=r`{em;6wUyDI`pZCSdwvZ6e`V2 zFapykarIDERmXGB0Y2I95RM4cOFfpD5wBTY#Suoi-PZF#%Lm6P3smRssWHMnZ}!V- zG2sLSzCa+%pdj}|>&0jRj`YZ|StT&Mq`79X+43tI33!$BK)!B21?P{&9= z%@zJI8)O?cARYP8i#@EI+;WgZF{={Q*>>$caT}7<~9dlAj zgc)_h$?;Bi8UwB+cAqG#QKvYAkk-zYj z<*h7L>;FAF)G0hE^uM8)Wy(<_lT(3L$JOU=gu6?#wXY_%iizUX{>175?vTV8J6k1# z7CFtd^4;;+jU;7wPG+(9ppd^$SbP3h<~(BSOA%R!GL}xeyo$1;E7uIQlB&PqO7?V$ zn+Nus2^`-YX%TMbr|F`zBFe!pVC%1Us2rSr=*!h&;kdP>yN%vtf$1WB+nf$XK!i$qp{Ee>OlMUFWq2lQJWho(yRB!fIy=0U9D16R3BSCEw z=D@brd`z-~GbKoo6iSQFD>@RH$a)v? zAAyZ{O2>zYUJkluR6sCrI7J=j)91Rps0%L zusJ>bZ~&kkkYCxC1q?^ zW=38Sx%&l58YhzyLi$nR5eYK|rTYBlHdl=AOsC$r#eV0nl3-LoRtxjE>?2`}Rch}w z#LZ$9&SfOEP}4C=2ScM!p>z)ni!BxRPTUP$GrqZe`(vkYY^E;Xm-OPoA%Yx`SE4Qw zG-84%lGeNf2Y>-=?!*ZJ2@ac40V)Co!q1PFqJoGribIzc`AlLoLL9#V6}wK~!+Rz> zI|un_op){apXK|yvtVtz1zqTSujP83`cc0=*o}ZVD~9h4T|@X3A2_9-G8B|cN%g9ueti9o_mm-ERlFrP*>k z%f!V)OueC(Ob;0JRPxrSz2sn(3el~fon0Cs;Y%80W4g1c(u`;JpQ6S?jiYkyyuzn5 z8;dEYJHo9qN))0o;%2uviLgT*X0k_?^5$b(ZYSbC4fR7AWnz@fK5c6U^HQx0eBo0m zmrSxc77?w-P6`?B$Hix$zz}dKoG_ho_#jqckkKJpXP@Z>S-k|OaT)cUkZR%USEuKX z=zY!H!kwG8Zu}JLx*7Gl@u3Vd0304aU!oTJRqJKN8n*Fu6W`@evG>Gr&Qz}ihjdg` zkNi6D)kA-$f7CxkI8|MKc*v#eKPz3o)>7whoL+&>^7mAq$(P?K|0=ovb;K967=xD< zzYM@nn5zicB)#r2i+)kK{6VgJ<;^sd9K-B#shs`<|I@X_aRO|=L0<+&SvGK;oP|F- z6NMF4h%R?kL jJ^BRgk((cWlEVx2uAs+H+^NUZo$|X8my9jfD-d3-G=9Q+-wz!V zurM$OTF%J-I)1%+8;65HI`B{ zAro}%ICHJ1(2`%Ii&DD7rLW`b=y%4vrcO)1$Ba5NcW%@K_VC%Io5#+5alJKrK~gcy zu|uXYo>Hlmf*8GdaneFj+bS;P&L!&P5JP{_&g^T5F6pPgNL<+8 z3`^IX%nmkDjZvBjV#;FrA%=&NHr^`6DQMYA>=efjy%`7@WQk5ld8RRIXcM=bkiu7v zE%(G+zXe-}&V#NwAp>NH`h`Q%;JIedD1*l6Sf{YQ^jUnmsIK%4F~9J;moU2~<3B3I z75J7~Ipp~kxBUNNow?>>W<(e+t!S`yOu3?4xlE=sEpzDZ!kZXBQ)*+3Df=%9l}w9gF6E}_ zMIvfO)=M;P6w-J!Q|bGda&B=5c|MJ6a_x$#+(OLaOc|v#2utxy)$t)om+P{WOTM(> zmYGG~QdekVMyfT{g8e3+$k}D;Z zim9Ya)+v;m&iox0Wz!^;jJjHtl#!}fj(shSN~%RAvr;=bmpRK@$(dc}8FRWd<$9d0 z`U{HPIzb6>^U~6@)KDq*MACAnrqi^RV@k=mv}B5{_0~#i8F^glXsA+0l$*vZF)nJR znOxe%MYWb^ zT>V6#YVZ-_&T$)P>8CWBjkZbt=VB0LI^;S*JuazcgQdmh_7Y{_rr=`D54|V9tL9BX z$4Mj04AmN`oOqCz=RI6h2EVffDv*{O9pN?${1@(0Pi#=MX=z%N^X1|H{~pU zA)>yjTF{^1-txHu^3h?Xx2m$CUx$DB088rw1q_M=VFk^o7-*m@>rqma#RFA)bswlI zQhk>A-C4L)8;n=IQ$EKMQg%AU6iP#85oC}rX*(d{a|#EJAvhC&fGwGt4FCWL1T766 zPdfnOx`Uk*{zRk~FiL`+Yl}1PU|h#*e3+f1Hpu>ck5`t2`GYYqVw}g|bVkreV%ZL{ ze>(y|60iMl9C8UU>Ekv0(mV|fTx%mS z7WzG*y4>3g6$jj*+As{&oAUSj_Af7`NVod-v!Iw7@vpW#T|W6pAPLVoJde2gL8FBo zUzQ0d-y<+wRp~j%Y7GlxlTZVrCQdYH2+PSWA+fstY5dJC0{z8-3u4}V^UxnOzgI9= z@u1(Y4#*kf~$!ZDt#fq8t|jf1R! z_->gY%Cv7Nl2#;9__H3F+_`&qj13%T5obT6WLsSGg+(ir>$VJz9w<1^2}-IWB>S}n zU2Tgba)JRvs4|_ztG+m*v^#l6tguzaR%Nk1Xa(rR$~O`qA4gJRRJ;K&1)c=Xr2bqa zUT?gC$Hoe;nj?>Eek%I83qQ89wjV&+6}VJ80-kpIzXPBVnn9H0jqdh}=SK*1FeTpb zaWz&6qFC848Y6J4W#-jxq@(jw_;D~}QZ}Y=0X+e|)xy00$T#UdheIJF>mx47H<(`9 zyYiDFXD5L;-pjL>0+${YO4I{?zsrQ=0(nAnbi!K<)_ZBp!-klkN!>Zjah&NZbizW^ z0|0|xYZHyTx+kr%hxFPPr7A;1ir|x{cmPnmA-~@|?MY|_v@@~Fj6~pN!zV}UuY1Im z&Aqz;7yU*zYlpkx{3$w{3;gg+SfN%;0vYw|H%>933VgNuc&s!X@@51Qg{uoZ-quTJ z__bF(rS=UJ(DL0vF+#Xu^PUUm(-hbc_ruzUL%3-1w@gUN!~W_{Jj_}q(2G+i?FtW0 z6q6F(F!8?tm2@4C+%pQ@x7FvCjh>CQWJHFvbWTMtbgh|C1n-WQO)RYjWh({S@Qg5oU3O2zw~Y9V#9y;JLHM)62Oda9Dgzf00*KyqU{urUneIS} zOA^LhN#yLGnSqT4Yrgr_63UhiW?tZQD=nl2Q-$^8kn@*W6LB{Zv1bb9dY6foKrvK# zkuc0N!g9$Db=ilV&wz~6lbYLAvb}e{4 zK8~N3)nI4;M{PTAxoO4B-f1*2Cujy2lF~JyszNs?l$PqRT!Gk!nQ{GlL%8XJQZ} zux`YxO3T{FtW5toUa@F4KF<;)RCppFqz68QAomk2ejz55i(-W+XdS0V2{cCEj)xU z>@&qburpZJ;%L!k|I)d0sU;>MARv2C&lQ-fa4la%?Ni?z@oiEY9P&NPpoC}i;GML0 zCN&abnMmst$Pg&Ek-BOH)F##rNOE|N3Q>dUV%YLXb6_C2M6s!40G!kSM z4kb>g381uL3J8S_IYV+u0`evXgEo_0?2u~(FhL{4#ZY(Ybm$&hpb5<8@ANST_hRt_ zAUOqGa~OX2W0a2~BOTY~cmK=_KP+ZhWn^}=qH^>B7@s_-5`@IHjRF=*5xlm{9=}u! z;5xw-;Q9dZIdbNUNV>Jz9?n{xLn3(sluLAwgX-DvltW%kfVH|ot3x9r-Dnb#km`#s zfTzOkS-Sv6pTzVQj-T>e1 z8qsuX`j9p}ay$tjp(%))&-T3&N9sh1fCv(iAX=!woLErc?BdMwM+u6izTaqa&46x# z+mD(QyfRqzH;^%cg#{Yw;oc*MVh)V60q7B|uIL@pLoo{20-YCp4^sS98Q9r%_{?73 zj$;`e0h%fa*m77~c)9aIJAaLKHTWcfYB=L!@?v!)#kBl~&edqyOncc7r} z-jw0NbzEB>>x~sfb)blv$l1*8b4FJgo6x!nui*r0qq!P+PeFk7Ly0hA3oKZZB<#G~ zOwT2v+*t9I)JAvVoDOXHWQt)M2`C3cQ4<->ZG;71LYxxl0^Qncf3Z;NtHPW!KKTIB zZ?eJXq&&4Fo2{>3U}jQFOk}D5N>+NOJHcB*ilzuq)MnPXZ=i^b974R;=pS2LF?LF3 zhvW=}Rk(@Z9fX|*n+29^3BtN8&kwXe0_hQp?q(UZ$K!xBqhW7gO27vUctKvGANCK4 zIW!3e?aXc#bblr-*W*$Tnb*ah-83t;(_=ayo`x(w#RxP2&LDw+4#1?_ zj1eGFe3N(hl3mehkk-fY)om%p=?%4D$#OKaZXxU4cbn}OLzdPy9-q^XU8u@(H$st@ ztjCRG7;_q$`5|7p*gWVI`la0Ew)1$F#76DVO;!f!5RUwK6MdL$*q3R12VgOTq!=-v zJ`4wug~A1O7ZW%T7)=m_1bYsb&)lrHE`LR9OD*(e5T+*u7Rs>A1O^%7kcVN!^9{YJ zIfXexSQW|J1Pg9L0TxEqES{-sZS=Q>AqPc>FDS0V)wowf=UqzWn43flDMS5djM>AV z#Ewk=(x73>tLAjTCirU!rUVGU)D_pLWF4adDLRGm0l>{rrGpSPaIuk|b?b+%>?gm% zV#0Y*a3ZJOp^?iYfRN%u^`=@#mrhZ9TXcj8BU40A67ZJUYKT%#PPY`20t)UqWVE}l zC2S}b_Y)FDbkL(G8#dx`2-gvvfUM``P+V0~>s>?bXbTDWAwK<=iy(ogKPXB3Q^3Ch z61XX8*fzL`e5{2=!E9K=Iyu}E-lx#bn-(^sKivUb-30}|E`;gHA;6^)pnG)l8 z=`=qo9G9>ZW)gsuMv!9@%aNgL#|a0cPTy`d89(9vXAj*7%v&fV7evu+Iov=td?xT~ z&>B!vvJ!hQvrUe>s6EAKX?Xfa*L!ic1&HI`06R97d%73p`UNV_F!u!dhdDTbIOyOu z(waej<9gVl?_afFR=&;&#{_l}eZHtk%BAQO-&9mfAkfe)5eT218?y)f`wIZxHu`c{ zf=5@3@Fqf!xdKcm3+__PVz@kvT@0xxNVP4=?Ad1jWm#wB)?IR~+3vVnfhx{=$*fKp;57^k`=n#Lm@}qHwrUs!`_?kbtGhfCyun z_DG9yap3q|unP%FAI)8eEurvlrE4^jkQmA$vz6#i6k1Ak_vC;Uh$ehA=o1T z6jW+OcquAbl+RLu*UzaKdmfZHQD`rjy(atukcmt%`ZC`Xs2LLDCe4asCZo+XhbFm; zS=j=?>PV{keEa=n_2gQH6ug1c%Dlt)>{__nnX7qI*o#uNRC> zqw^w!sGAu{$X-5y>YSt_UXa=~p$GRzkT8Nech45KmqucKb{U<&uS?6}*1RjV#U>BI`b15NG5CdI+yV1T7p49uja4 zXt2)^YMU_YHdP}VlM}yMD(79&mqoH>4smkrxI(xt0B)7{y7{MEE!^?QEXqyOM#FbXZ_m}|7Wpwrl4~rk4*%pI9%WcS@hVo`r z0dtA_Vjv#-Nu`~&!&eRlBa!yTY@f6=qZ3jb;eL<#*$r`W9Db$)oSsn)lN@#kykiLP zXrkqyvKiN#Iw*3V7IaGpoGp4}gXgC95$sw+#DaM$w4!LZX)vM_ynDv37TvZ{3X--w z`(MuSIKJ#$NAXv`gs-`%Udts}SBd$pn}MWwX{8`1h;9XGeZP^-29PS!sg24A<4 zm(XCE99rqr?H1Ot3-Ju=Brt}UZ8_>^$7zwG#5o?9K?vm06ufR9q+=9T@+Zb3?b}<0 zzjPullir&21C=O8C_{T#1PYk3uG3rmnw8aoMmQEAd6;E8*1g7U$&h!J))plFU*BS-2p_u zo8QCrx%Vlt@zsjCVmO7scho;ixz<$S&;uYCv5KBJ35T2_hKnoMIElrWBOJ_wgcf5c z8wMVuxu$S!lgk-8yxb&d9Js55OCBIS!Jhk#5SXYC{+%_uHZcWRZgt-J8mxDJ4AraV5(+Pr*&{@2x01-8I6Lw`QrM#(yy4}RDe zL1e*5CV>Mu7D6l*ppP=I0R8w(7aH~m0^^QkN79x&fSQ7r0z=K7D`86gXjC<-{`R|}|2c~GjSC54^#8I@(%(7hbNpwZh**NO( zhZso-CeK<{1!+e*C2>*Y`b+j@h^*jfZ~%5xSP#v23Y~x*zAv!^jW)k4HlLEJB7bdk zYBYI67Akk*pJK$fI7oH9d}>A@apq6iwXCg=M{H0OO#_OkGJD@CK9D3>FX1=VYPBR@ zi{o)Y8u}j?b^{e1p;Hipvh>zb;H#CK1Uw&$T_*%_d*%PfLFyK6QhGIcw25{%Z8ODi zRh5F{3-!dBf1D&V0&AQusKx(`+xg%I%gt!q+@{UbvXrBc)5G4P<|^qxl+;hg2VMfr zy@kQ~_KBPkDwq}v?Ua_5C}7P%?YrZ8&FG$Yp5A$Q#CkNy9S{toga$ymU*8SXgM$~Q ze{}jY(LJ?K1>~=5R>RJ15h9V@(VJi}J;(ye5_ulrJySKQ5&n4v>dVofal-1VSy1RI zXvRf(O=ui|Savb2Ky`&)M5`c)VC$mka;&~Qij<`JD4Y!-EBdC*2$?jI=2`RytAd6R zcX0S|u)?WdDRA{)w$f~+*aPh|!^LrDC#GUUKrXDRZz_}LloIQ0g5tI-hu|oaX;7P3 zPvF=qO=C(P2GjrH(9MH)4RCo1bcgN^qkmA@TZ%v+2#4{wQW#?crA<4=Ija1L_C~ww z!!tIiKpDWxZ*1?bmFf)ojOcAyh7U3_EPg;~Ph&%tWYNB%gU#kRCnO^|C;3E5b10CO z`eD2lj^m0oO+5^~WNWX1kVCvcBmqq)eA;pyy)4H67s)`7!cmI z^q0*fA#6M0+s?%>vv)_hr>HWs=-oGAgr&fvF~js!uZYS~bMc7iz<3kaMednzm)fKA z0Pu0lZZPICk#g5}o7a+ZChF4D>$kB)DgN!>!evGvcprRF#M*AmuyB(AvWWXb1-&|L zdCzdHNPIdSu=}#|Vi2+;Vq$`Fw}MsA(!EpuQHUG|v2Nlafz{4ct$(+ZJ5pNeFYhz& z;?1%6)I&xur2-U!s8~Mr)Tk_|aPm???@uAVG2_vaX=B%-k#QPA{Rj!+&{#EsF_TBc zS5a4yOCrZLFH6Ib;U3=%qdY}tB+B!mQGi=c2+8gblE&c*;sc*8yjHUkImBK@@=ujc z5)VK)gC*j4h5zE!fQuj&v7Aku1;2CVsEE6W^$fm};Le1M=FO`UVG?&JkSg6BLMTej z?Rjys;3FOgaS4QN2tqPa-d{(vFmc_@kFL^12l(En|>pW?MvyD{6! zX)(G$rUjI1CE&S5y=@HnyEuN(H<-8Xfe+Q@k0t>RIM_|pmL8{%^k~1K%B_k@9)=BQ zLRY;15rZskA%NG*M?K1eQ#jsohph{CH&{)n_2ZCHM@kjU=PKvvQj>qBL&&+(jBDh6a@V8L5IpOjj zzG=Q(uF=|#pl%(48qA=Ya3OH1w?vO5OvKIa-(kamJNyPiOsVzb1;{Qsu|B4 zhVJ*obCMhe=$2Iw*qx5cOl`wtf`uQUs0utM+OC>-anZC5#Of|0dts-7V)@eRT4aOt zfGeutF__CVKweyAXO2nKSSdPzUl?;s- zxi?x&ka>p^6wLoRflz_be>)ssNmUKy#AD?tc!Tha)rT7G>&6gZAgE%Mm>q?99Q?%a z(v;ETT6P6PSM7LAxlc<{&|zCAkcYQ?yl&ZqT-jrWN7= z9}GBVgyCM+vtJ#HUXueQ{3PC67UCmod_x?>JgkRtN^OWV;SfL@GSu!nP|^VX+V!(DhVLhcT)(!N}_))!HPH0n1@Vy zzL(?|UDf%U?IZWRZ&4}c>BAJ}I&rwg19n^>vsyj~3Aj9F*~|x&Z0M(E;#xy&Ekz5& z1zrWOQG;qM?6|<4h!7kZIZ3~gapytClI(GLCNU*3NcYFnKm_$@51?H61Tff_wYFSd zBB)Meo8lXU8dzp&Rr4e`J`>45>UUs2TwLRU5a}zbFV9%+o1GI&I0GyTfBL+ik^*S!C8+QvJjxVL?A(4Jy%HMa?m96-ci9^A~&ocleZ9#Ea2;;=C z#Xp@|TW0GCfTiT!{qlPZz{Q*OUG zT|b_V#djj7sy+%|DxNEOJkd3PmvX*r=oZlVLBXcV=tJiq#|%lM$d`Dv^G)_fPy901Gp-@EOy)A;I`X+jom=s3Bj zD2$ye6(H@^jbX|WgpReu10?TdfbBPpLW^56`2+qV>;x$in#7JcLit!XI{hywQ|)h( zjc#jo*3ud@^+5$e0E?Dm zq->p35Q>DQ?NYUbAVXHOOyOkj8X4mps4He0Rti7Yx6FcRf!if?-LS{Gbuox+Z2hYfj$K65e{IW>H`l<_ zHXXL99d(%yP7U_;!a@ai*<7_*`WoeN(sVh+uYq~YftXY97+HzyHwTN%bsS7I#oH2s zK`3BOp~h=1cYB=I;YzT)G7Q@czF03BFiu%grvtty9%dK+&MCOtw}P1|UX7T36jM_i zn^pC8jSr+X8;~n)FG%DC*$m8Edo;OBYt-V+S%2J-xcuj zW`1p*408!-M8Ao1KR9P-CQ3M!xM>etLwzLz$>wSaLv4m1^>vi2i zbYUZfp@cil;?o$MJp~E13nC;XF)H|7mXN9y3sOx#AP)EM)9m`Sd_L)rgJ+@4;ul%gHMAN}1#`Y~@+3TX{V_J-FeOj2R?#xbBo8uE~!+YOp z#FAPyH@|X4-_HtZiCa}tX2UILDlQIQgV6PGKZYBa*@J-p8C>y=ZI z#}_)dMt$C_MPc8?lSTAlvHS%}mh;y;K6FEB%B28AG^z-K!(SPgeSC?*aD_YIDNP5@ zI?s4+qhJk+X+q;0b^{(iy1W>$8E16g9d8XcC7J>`tpImzKtDgB@IGeHvl5b>y58nWz$7Jhrzqj)y#} z7|V!lRY#jsooXyvIfMtew!tF};6Y`S)|-!i6vaFTFVIIj**fesG4c*h9jIwdU3oqA zwoH>64V>emF@kGMeI4fUMRZ3iDUou_mP!+z5H2x@WPT}8TGI$pc}MLO&)DS_!)_8PdKVt%M0oe|y$Kb6QBc^J8xg0_B(~QzUlK%^ zCc8!)7e3-G7%4=DrOoE<_CRq=0E!;+gyh&k%=kk}F3wi*qQ}`y1LKlewZe7zHi40@ z!qi8e6B~U)S4wW=Wx;RuNT~ZLVmS5gv#*N#fiu(wllh998~Ec5;i0wMJIdorjvU4} zvGr1(y7P1!yd?rSe5+Q8w5O+sdfe^5G08ysFdCYriSybr;wJQt@H{czJEvNJ0!d)N zs*lIa=_qobgqZ1t| z>!x>@2kPJzUGO!t-{vvR`%SgWVoAq{nx~h31(Qv+o5F0wVb=m7>*tT zw?VmcjnrA$E5=h4p=bZ4${$JGFj?mEO4zm5gYpjVSW>iA>Gybat7Fy&rIi(U0XF=s z8A|mAQ5~o(%XilJPE_-krtmIMSmUh&oZC&1c^rh4QhEUMbCC~1a3eSIqcDGa~GwdVTKn008HO*|-P5;|l8+vGc3c|`ZJS9goz2Bb+a>#1AeAH`=l`P*$9vBzg=sm)6|*_;jLk~YI$YXR!}49O%jF=2eiA(hPdm%LST1VjyYw>`!km*Hu1?G6{?<{6bfHusY$$ zqT1$Tc4a1h_H_Di3W*%qgE#O{jpP<0POj$^Yg1>qoZqs{{g2!LG$WufCS;2X7ci~- zd)>i7q@eNnAc;ewpF)9pdiEx>)s4|hf_1k*>-L{3`qTqHtpL;28|I1TdOeI))=rV>G#VLXdx7^>X3tH zT*9Z$S>I)J&PvWSx$t#+z1s(@7tBY&qcwrS_o{;K8cNn+E_Re0OO8`LCG?R6(D*At zWy{VwDQ!NwP1VDGP{PorPKey_O>CetYHYioii6ISs>3eBl0MCAW2D*zCSnHaGkRNq zTn=EU8b`TUqZL2vbB#eqWYHLJExouGQA3RG>K6oZ(PPzucksma8XnIQNi$+>4-ioe z^VjqqFIucl6wt^0TFsT1T}bnRbNLu|NkYv~t-bT#R^ zv>2KAp%_7}?+QYLqwz^)6*uRN&X3@6jbLjz9G84$V}LLFlfF5V_2zPO0wcVS#Q`GP zfk&d-jNHMIU>FB-hh_)X1S^iI8w-PFm}|ireNGAYxvx7nl(!R|9m=xC1x+v11H;4oF}N#!hVqDonS4iF#g4g zWv`+wpBglXaA5jaadxHaB@u&Iqrq42~&Wiw&4J5R&hbDdssjL^N1!h zxUUO$T{LIOr$nA7w1_dD0BjKkE#v@D_0}?0iQh?04pkZmHc_EcMPyYPfJOMH=V zC5dkRh`6iC8{pQ>nuQ2N2Pqs7ZDmVEm$-EXJ-NUrGfzkTm&G%5V4%>4s;KP~nvDI` z=T6A~d{d*G*mWk3CUE<0Y)vr5NuwW)mowZJbKMR@a)fmg_xSf3IrJ10m0?VH zG7^Vx>JZN=_K+jkCPwZ|wbD>xq~O&Ma)L_3E1rgjH*H5J{?t5y^ap*0-4~wF?XB=+ zxI}d;QWYyo!F!d%Z&9-1%reOOZ*~^LcT6BS21?xHtb25bPH_Z%${};0CX#0bE3FFV zx-y>i8@EEP^=PubjVNK)OJkB6d0N3%UfpKcTs=FUD`#9P)Nl#lDJG>My&XimLJo>L zkJVF?4I>_CACSip?fd4GO(K%cJF_IqFK_?|NdQPSIB2{c(u>Dw%8P+5mR2DMtk{H~ zUf}_B*}cUIOuzVks35_ZtFN(X#fdR4_iV%}5slP+0Kop8;3vj7Ko_7URo=ipe;L#7 zHBT6kbfEaOYkx^X4!sl(yDnmg^sOUj)+Q-NJ;y|)Z7#0PzJlIAQ^FYQb)yHz8F~IT7C<=DRCw%`TG^!xL=&)jq zK1j3@Z!x*}T_{X8xUOOjCoEswkeZ^kGIwe+?`$}7~b;lf{sQ3gg8QZj9NOD#8XLo?l=1A?rt ztb*^65Om>QpS?u^6Za5yXYDW_)gg-BU7{LI<4JbaRsoZsYu5srVr9HvZqhMm*~$8e z?h^*jiB`aQ@3^23EHcn_|z?-8?#XF>(gkuWt zXB;zwh4fo``1c6JY|=}}ZNzQ!bNMak`H5mk2~=qXm$~O3Y2geE4|UL!$I2`dO1}Dl zFLs?nh@}=(5{A8|&AeRGM~uM%Bu@MSIXey5$*Z7|yXi#v+~=v8p?Y(L(`x8Fr^78@ z8jw)N9-x@4M&LvcBR_{VcZ_k=CQS5IkYzrR?pb+v+FW5M77zoSVGP9v9$mB7FGmQ! zB9vGwxdIzT;m?t-fyp$WL)6k#kAz_my;&07NLAbgEp*39+QL+m*;nZN zAFHn2+PQuLOvVD5L&jk8)V_EI#Lft=*woiBA7C-907+<)iHxLE61t?jDN29+iH{K< zg?L&4{PlSQMlshgyD-o=0bw$zwqclQw@3|XKcQ+_iGAeikIj>bZu}oE>oKFT2P6bw zOK%`-`Az=H8*-J#m7Gk#X)K7Kf(j3O-_?9u`wemg;0YppJTfkjF7 zB9O}m4m#8~OBEQsGp>x=bMLVfbB9T70*)BzmN_tdT>h?<_}>IwYkDTSq!~qG9Lz*a z!$1R)P`W+v(1qwaAovOhC>$7$!;NGs9GTDd$bR=-{$Cxdjl{G^3bn-p z*jAy&sbVG6)U~OwV-W%Mi{2=9nkK_t)0dr9DMi4A1*Z<9D&Z=&s>zOm8jZAPp3xxd zRdo=t%v(KBpokC4eem9a=M*wQ$Bj!$R1CXEc-9fQF1n_RBM7A&d+WQl+&i)W7`qMpsVYro zhe{Cn{=I2j|CfB(S@bFWujvZ0OOl)>ebc0Q_zH?ats)LNZ;fuZ)zED$x3>BH4Q3>G zqp8*d&fX!Mwmm^ML8uhsHd8^i1bZOaM7XPZK==2->tWn9x~h_)GOjJ60w=5#()ux};uTTFlY(B!an*00iJNQ^q@LT5PK+K+mcs zx^qLg^-giye7x0H__S6!Bm?}l+M-^3t zd1^9-qha7`9sme9V#nTq$e_R~JtmG`k7yhtgJ4FuEVn=qfT$BVfzR|t@CB~6U^XkQ znN1tjxW?(~!D@nD#BZ@Y;(CEo^v8tI zb!pw&)lm&cG{eB3F`7-P3WuhJ-Nv15pnj<)G0geN1Pe5*f|($Uy9xwbQ_M04Q{lTk zlxmuaXrjUlbQrcMh%O>7(Cuj)S5%k)yx@n=X2t{({Ny~CUk~i)V4x%P5J$%J~9S9$rwnz zl9gM-LPdO8>);@W;F)%c`-RvS1#f= z>UMXV_?BXfRVJ)Y*;lBOT&Pi}%x+lXn1 zoZCm>cg}`M+e25%00aX9g#g<*X2EMv1CqGKCG|hi8S%y0XVk!ZO75=iHvP(1W4`V* z8_hT51BUB`GHe5sf!id=U_QB9axKBI3-v|tT|=C%Mec;v1{u^t4Rp-fJXUS_gL4z^$ zaMjsM0*!?q{@8>Pz>%>CL&a~)Mtrmwuh&bkKAyRuDkQMSp>GhAtSeuarXnTQAgD7K zert5JnuRJF<_#?=l#*v$8;!=n?^17?3gzClJ&KgaU61@}V;Hz^(prZd3maiI3R}pa z*4Z=bSXM0?&R<7s3U4unQwX#f?DEU?ok8GAO;vhB>E6^BeTwgfY)D!Ye0#j9njo^Z z=qglK&*ScUONk)4S|}U@*igwQK{I20l4qE^rmIWk3s>lLsdR`esAuFIPefiWT3r(p z%6&de&8kDys=V2X2IDO-QJQ9dTW3u3)J2Y@{lmOC?nt;tHU%tI36$qJ|u@N*&`wjP48O1qk z+;YtgyH6<&DTw;XyadS9sPs{82&Hrwh{Uh>yI~m2HIT^yv-qcr8Y@1S-KqXp{F{OKZC1DZsp>> zNQ5TBLIC0G&POs8C0Mbqq}&(noYWdx&c}b}&I#Af(m5y)<%x=FgrnV@R&#M?s`gvV zLxQBqA@QqrWkj-h*jjkMg(+8U)sOPg-^5zvsOdE`9rkj|`bf&CKW_m)-gTMcl-yO6 zxCR2zq!fg#yc_=c=J$uN1@#@aM=q{(?JLHo@=?)tKK63Ubql)vmYXv_ZQ9l=X4Gf$ zx9=0zAHp<;_F)Wa&lmvC4;0?b5I1;oa@ojFwF!4>yuxflUAE!em;KXtVa|46dIQ@f z1ZvA=C=eWf@}sbX3IT+++%07j5erB(uBB`mIt+`CEvrdh5YM3<|l!~#+sxvr48b?{<*hNW>8e4Z=qE5MiW7K8VaEpVu=P3 z%;j!$PPqR0F_2HQveDeX%GCU>RPUuvj?m!{ihaJYpI|nL|5t3-K<0+;Cb`pA0k@5- zE5j>)7{h{2VHNCehD4#$^>O(!j2yzhnR{ODoB1xnq>!!ji&DN|bDTH1+JME4-Ll^tTDu~t$=aO`F z&Pdl70uVSv=!$oX;QvVO47k!U>R@x&^0;xBrb?d$x2mw)z@`iJv}RR%OZI#gewBRV zLsSt_F&1(~WQ;{whlp?)R0~wv3Iwc$$|_ZjTb5X4p@T*yzf>`MoMI$_n>=%)t;87a z=%Osx;NAeZ?ds9krpZ`)Ls3L%hT)(R)SucfNYhd>>+Q6)$ew6q5YR1UsD&xK@PCbO zDnjE33|ZO_)q3H>1B}0Fb zDqiP|A@pc5f`+zlkXEe2V<$OEmr@j{i?~Z9LA9{rx|-&~l!Kh(ln;2nN^+_cXJJ+l z0pBi_2o16%8Y49QlmOt-qplU1B{D^At>hAwTuV^ja=Da+IP?@%7SslvI*3q>Tij!Z zIdV;?iNSqi^^n9oRSLKa{jIJfoPh35@|1O2y4aREgsEidOmxCup>Gw$Un81^tVbNi zmk2c_K{=KZH3_TSS=wQ8wBuu4LB}{$F%YcXeL8NWcXTPlSQdOvVY(KDc&&T1G~V8|UeohNZ=nP*Se6QPmN)VVW)lTf#$A5)nSd zuo6O0l|g~-XV##!pFjVr>I3JhQ$~WI$bfL zE2|E-Y21Pk3nJ`TW=+#z40Xe>2C@EpE>kTN@zq-XG2z#yBASCxgK^6Yc*4(=%Jp=q zcwlb9RdlEz19vG1200edG-WhAgD~>zJ(FS3Mky$XTSnhj)nQATAZ(lBQb;$QaVkLt zo5z+qT)53kkVBUuB4bzxiHspZn6W6xiVJ*6frvz~tpoQf537wk3!)9OV;$m%XrgrZ55J)LCr%peKhu`P1tEk^DYMp7O+0iFOk@&eflB-;Jr6Xw1tF5A z%vZtV@=R6J|CxXyx%~?zEN!?c>s8~KU-&ujy~`KrA8=yO^(gg72|fs6qX=9L-jQo* zf&PRwJN^%e%lGOUUL%Gk1UrB}f@F^Mb`g#A8 z7tddw?Sf*0c~a(l#Q@le_5mk>WNpUh5BNb1jr(@;`pa!Y`Qek7U94`V6l1smZr6x3 zTxaWh6%SDNJA+q*y5KkJpXImm@OKhe_8WW)*aN@s{F>DUg6w5qotIP6Oez(LSc+SF z7$&D*3fky){x{6)+KrO_bVc~xa`>UsnJK${MIgUhs1$yH1{-t;&z>flx|3}KDj(j& zSDY96toDEm5ODT=LQhbT#Piv~=M=8`40@d%?iPUlby|ABAF_%7%WqzeuX2oyoG z4H7{+MF0Rr*Ry%Pu^{5MliEQku=!~%t>0=XM|&yNBAil!f$I*XTx!6>AL=UnF=j$T z?t)5hwF^_)ujcG>i@@xHKXa(XTv+7;tDfm4nYfS|%cWEUOGhJPTP0|Y)g-8+>R1dj z+$rc`mi=OMp;k&5DD&s*XSCt5b5V{3o^R!VO5QmYw)0$Hjv!0hu4)k&Kn3xBeCCQO zhgeBtEukjeE@ESXAO$7_->xOKMtCC@1u0Bh0%kI~2TTZ2yiE-vc&5>o&fn70RBDXp z`i^C2nJt?qjDU=mh(wJchRc;Uu;#uip&Dr>PZ8FuRtn0-N6LiyfKJz zeFIn58>7IyTM@LS2^q4T{z+~YuKEM+TM;3aqRVbZG8b!vW``;X@Jk-d8Y@?BLG5&6 z&o|nxmk18g^#SH*D8ou?bIGh~cxEvjW;G` zLJpgHrO0gRQupjk|6DwDns`u&py#khQ3}P-4Di%v2(e5aZ641N)xCDliyA1BplTqm zdCe6`voWGEAVz=#iA5M(lzIXXM8mS!lhi}YHB=9XQ_`BYb|vjX(v`Vo&8Ex|0W}|q zuY-V_+!#f_qBc-?+>~ke+?q=_vc07skqE`-h_mQH#Ar)9mZg?78-=;E2Fvsm9tym6 z5ZusBn&hyfhtVOBH7Ok;drK;c5c!1={{nsEsQK$DZ2S$7exQcnvRzWTQr|Er1YNtc zD)u&Sp`X9k#iyp62lY}{oE)kk>xzU~gL z2;NglTSaP0amO)52}=0^r6<_lq_!k<+8cr{F{Nq~Nb4dd)P1`UDO|(2q^+Vu$TzC( z&aI^B-HVb^iwcqXge-=Zn|x=}A<{a3E5c8G&E@%;_oleE2%=GwOU-nKHg8F~g3gWO zEkZmg4T6iFI_A(ZU4$EjftgPgx|Pb+vqiXC8jePyof!vdH=YR@W59r*kOBk`a0d^Q zSaOTp2nAkQD$m96hn6~cKe?BhF5*R9d_`H?R5Tls_ya#GGxf>oVNyo(PcZ&TL(q-Z zoymYeh#sO|##iwF1B4nH5Of5ZXS`x%gBa_F6&e&HQWT6qB$%X*u*F;%D7wS8sa>Ic zT)T!_T_iomT*K|pnIkfZ5)BG-UeO97E${zd^4`MMmVydXY+F$Fc&eJ{R*@Jd4+=Bz zgfY5pT03|DfkXxsY|22jsnVvo21lrb={mo*T!UFRnx<55+64~b{?Wi<%hpsrRmA|e zXhY<|$`c@s#`~buBQ{!gUPd1;IB@?184U3X&E@he;F96?r7R?b_*1{N^)_ zB;~e4FFb^{;Z%ti6V0`IqUwFMm#to&pmr#1+PY&~M$s@W-7Ur(*7-0s%;3B~> zy!lg8*0>*bN_Tr6`T8D#hnfdz?lcfro})9zUH62Rl>*P7gdAD(%#rj^!+ zyQ!-xT#F9e3N=*m=HP7e`;oMC7)vXotk zY3&OtH7nQO&%~c4SimC>5|0WQn5UmzoeNzib8~Raf+s4NFl8E;vCd)Rp(St;L=ZG; zUprK~_QwTr$1jn{UrCBbav`X^=UvicV5#tSpvzm0;P2X&#p>RV_3oMvneIwTxpjRS z{lpa-jO8-p+NNx6REP)+no@ehQd+cTdo6n=zFmr05|BYZ9+Z8=hV3dIv}zoiPODGge#7KdM-NYGT_`Yd(4_$Z7npu(q~ zT17lp*~AjX`bt$_QS%yN4Z>1i)tn~R-C1gz7K)qKGKmX(+=Hw{yWY8JE}a>wf;TBf2s-1+?E-y*itQH$9WuUwlqkL^xAP zRnvTIgnr+hjT60tR^M?6QSYED&Nt$gBq^*h+~$EG47=b8P#`d%&eMSA^-X|AQev)Ce39Xmlwscm0dwbZz(;Rp!a zYQDX(e>N50x=RL4FK7dV++4GxyWNf1d7PV}GQ!-);oG@35zbz-^~#i7ad;xK`$~gf znlP;iFz5V#;Qy8O|Iip2y7~>hkuxLXp(+V>ako3dZa+@`^5c(-SGkLm?1AKWv-g0+ z&05QnxJ;Lxd1C7OdeWrO3*wIvZ%?X>9+>Y5p(=@JNitH#95_tuW(ES6%ZiAXT)k7y ze{fG%;=*R15`Bv}z=0=m6asqwO+H>pO7FL^uKIQ7EM0H^(|oHiPi|~b{e8Xnl$);= z+`jHx1ZWQSIa{4J@wH7!IBk{9*HBAL@~08PnT{f5a&GeqT`JycjCg`F-yVo*daE3I z@ik3_!%>brDPFdPn&(|f1atOHT$aiJ1_cD=7^rC-VbEOu3m28&?3SjWR zz*$+pW)6HeUJp4Shl9ZZ2{<5!1M=*3;NyaWg8%@dbHd2)1PA~Nvfu#$Tp-fsy2kx* zt%`8V0NC&xI``XaLAx=iujCK#QS5e~Wy}Gk{Am9mM4}-sC8sPiG&S*X+!>PP6hlvBmLSB}5EKuGuso%0KBnmi zEDd2sLQQ;b5km{&fIy(20*-gE#8;$~19`>Z>#R1XtkbOTYdMG58(us2&**Uh%Kv|U zB)!b9i#NMpNeYF(y|ZP~p=0y-d7)DKHiaz{~;ep~UE z7zO?i1mjCJgNk0K~I%FD&3G)X=7~p(S;BLPor7lQW=vnlB5ql(HjP|1YDO*WSZt1G<2C^ zaR2k6P1bEL6!))}#HJA!G{jT|J(w8p>o?wapQ!Wiy2Ko1C5Y(XAo_l`^sK&l{joK* zN>i24G6|CqpDCn#5qYAetxk|F_5`kUFxhn9uL!bUqO_9uI?30a;1;}2>$|Y>;o_eeVteYE{pWvi<6aOqtLs`l z%NJ+&R)$VTo0FG(dtOPUkocXHYP!i%PqtR>Pd0+o71qW7<5TTA`V;G4i=SL+a+92s zQ}+wArq!Mo+s#3>p8bFJ2k>FBLD;EKjFKpUt#bZF^yi7d*lAfW<57&3k`P)hmFhh~jJM)Zj)Do<^EeL}BjDIII4dfmzuAo?tx%GIix2-%e>*b!54=>ScurELEg9G9h z-d>{HUbNx`7YqR01YRx(3Z9VL#S3Tvobxlu9M0;PYO0HI&Wd4yT@<9~0Rsyt01R@# z4sag~_I*Us$*s%%JQyiIMer3a<}bn@J$Uzq~Ocafit_G^O>}tCsRCZpfDM zlsN0g=V8R2>XhD^4@%DZoyrX6wmRior58`-{uk087lq02KSaCLc`-k~T<*@Po=&{y zb|+8TAx~w#-Efy49h=!{{pV6}#nn95zEP>l4Cgna)%(o(vJAre!`lVq=tA3y!l(%;>(6!siq4Ko5OLl&Owo>f3Mr}f+K1*7n<1e2$7JoI>FwB{4&2*n= zd6*l~Up)_1Z`~`y|F;u<+F30-6GNY?mL$qu^9cqD0R+U{Bk>H#K9>xdEHa4z*{1AC z@xWlEv)SIUQi3G}aj-zo)28#bigU!D`13ndx1UMv$>8s@V|n6EN&mq2IjxSi=gd;c zf4a>D=e~39mScy4{2zo|VCfPe5ulamy4DAm)=tT@V`;U*jcCn_I2V3mKJ$_z#Ug$; zR(xl99%c34z5m`~sF7O~X^j55_TNYi? zr`?<)#qIf6{peW)9cuBf=L32Tc6GFn?bl6b{cX4I#csl|`Rjy1obrTUdh#rDNOMM; zql7LoH>f+dU-Gx0VZ{T)y*M7%{=Yp=Ow(uaOi9z1@q4*t=$hi}h1i^xe02f>0s}4k_-yw-@*n+{;JyUl2-p{4Bf+%8}V65IIxiy8LA0-m|i?ycDEEx_C7@X5ip;rEZPn$w2+dg{*j_sU#^ zL?%RnXwkfE@B~C;F;0oeL4j@aC{38=qqb(8b{sZU2MP+|TFZ7cA4w4?hd?gYxQ*HeK@=J(~^oYCJ{JElRlzuF)DuOs$Nb@<)bq=@f$71xHg76XzJNsT|TkaCIjMq8um zH#fSSIs%!(>itD-ZGs=_S+<30G02KuKeCjU;AvfXeg_CV;4eHNAmDbu!2|q4!2i6g zEc*2DYhOw1Zkft|)ILypuHWvzg94SsGfi^t6B7}QXvC4KDtO83@lGGE4maEjS$4V^ z-@d=B@yD;e;O|qs9r`TxT@!|MJDD#{#f_)>`JKk^)S#**HM@7wO;*2ZXKtK0s}}!< z*gdlR0?P?+Fyr)tL&vo)6+DaAzxbC_nVw}1uEyQ5JL_gL1|iTHgsKsVhNfY(i`F{u zeWm0#K;X$9@Wf*Q8-56>MUp?1O3%$T-y?ViKFpOVtt~WN}0XGBi4~84h z-U-R=>S<}9L4IS`->5^|ln_V$nIrwW5CtS$9el2HoBBT2lEQ9)Dwidcq88uRFt#A9 zdAb63bd+@6Aw)V%d7(sv@A{5fc8MS07(E5J0s%^2$~lTbfR7801Bbyt!6C5;cEr+1 zBK6&m?UoE+pg)1U23koWUu#jzEc1uXMxS)m530s{x7sol zaG}eXe-0SF9X>^d%eTWVQL&lPAO53UbNw&O81hb|rdm;Y=!u~|U|YQ4ay#lmFy=!e z>e+m`YqFFxFp1&zOtTnHMd%Ex1;W9gB5Nv{MVNsIJ%i9v@gUVMl^#K;h7yQo3Fr1b*L0mO3^3H2W7P|UM*))x_c?@lqHK{07F7+e>A6Q&^O;c?|G|v$DtjQ1d!WZZ6 zZ_?3}>Escm*1m8E^!9Tih2&}P+8=xha@Pt_Nqv&PHqfO*SQPl(bxY9~Uv~xnI+b7= zzohf0laZa9Rh^ZaE9DlLRQZ!yu5uYB+iPOkb?-Ay??q35{(cVK7*?Er6V>ZVWB2?z z0i`ypppxu?a&c`DmGae{Bs#L_8=BQ3c9)fX^wet&z|n@-;-4 zD$vR1X+lI2Y709+z#el13XaTjNbZz9fpSyZ$~E?JHPrqJ0K%OK)%qqf4t_n?`I)Z> z4;!gnZ@98c!^N2!Ej*imb*lt~-SOEZqpC|4di+j!f&kl#u5r|O*RQ};41vc*PclrU z0N;7uGSA(ABGmQ&x4#U&JBSe$!D@PtMQdNIH=LB&XPT*+e(6A*qBtMn8-_IrvfpO- z%%LA^(PbH|6LS6e9|#AU5<&XyEe)zOI4I=WXXh|~e&Xvue_PU}+8S1yTF;u7D;xkY z@MUQlN_qOEG@z<~rB^kJk6srt2y!>9!;xrAvfaO=u)Mr(0jmdy2u;w8Q`_DIm4pi|Umt^Q)!=5HaxFg2_nxKHRbHOKb!XN=cBXc_ zP-ir`5;7|HPQ-T$#RS`bCN*#!b5v7T{4V2N!A z8?#!)#1h|~{P5NoES|?%oVc@tXNMnR-N`ed{6oz0>xZDtcS2gb3 z$AR6Gg0LGHWQ5L};4eSv~PFZ1l@Ruptw z_K(6(7$&m(n0cjrK{q(_;|X;)Rr$smBPkS6W!i}&I%%=g&6}ec%Vg2jqYxGIA&i0RsZWK-Ivi07(ERgMnBufCDHD5QYck#0g{( za0(8A1quQN_Wt->kCMgbd^zXZ3>ysA;q!4m-6KTh1>CV21IfZ)9M3dKWi zg8OUtZXsWfirR07N%c_e?$mtSI83P#Yze2UANPEU4p|I4FThvZqUCQ4iUr~DSz{7t zuf-?)Q2e?P70VwK0t5sM0u;wE1aN`C0e&bjz!)DTIdnr5@OFZuE4FAHd92nRLa@bF(5N~96(iyby=`4cAjqluqali)f7iR~> zHaJMW>4D^ePcVTOyfAP)BL&dgy24Ne@ZoiiEHc{LjA1E~6WjvO(FH4;J+s1p z6!#iTY#PTDa<>bHZ;k?wGw7j&(4H?Rx4;2zU~p_B!yhOBMpP8~Dt8{D--^Y?Ra5<| z(_#BKxhc1w1YU<{1kCkqj`loymn(hOn8G*ina49s?CO`u%z)d9i-sbdonxQ%UueUv zYjpp|ao{_dOy=L{6$`=M0xdv3&T2tZn>Nuyel>%#}pP z%-)>Cruk)Tt~;hUQI>F_T&VQKWi{)grMy_ki0Nqyl`-s=0eJ}$Bimg>cQIE=^BC2E zPz2LHK!AWR*MHZ2ZchRfr2sc0J8$KRKXL(odO385Ckm4CF=nM><9SbcQfb8 zi!BXM@Z{%b-7A_qPo^|AhAq<+8Ads(DI!^1OSy`!=FtK5m^2UzeEo%AkZyzGe}G@0 zpm{^2ji!<}E&d8%3J$noa)&@E#;r$foiH%ClbaRG?H`;l@>V{u`Kp-us=;Fua7Q;w z{{s$i21WG7jB`vG9=}GToB@54)r^esqgiuhFpo$PLqZIj5(570YO?z_<>oVvUsWR^ zYzyWh$Q9wP4i8yz6@e7W@JDudH=9k$&aE!u(0#2HplY{KlAL>=?(}%!URC z*>2*MVQ(7>`-|PSz_AKHzyTC~XFx<`vw07oUmAzxjfC0HJF5SLE1-`92m}E5T8Spc zurN;DKwSI)q_X?qpwIydy9U#RUx6V!b}kHU1h{Qr0@(bKG4$4qwIFI)hA+;{Skl^>@Fd@#i6E3b9av0)WD!0YTvb7&s@ApM1o74~ai8LBR3fQX<|9a6tib z!MDK)0(ihgY8id?2n;Wf@=opZk-R~`!5##-0YQKQ0RqE4Ab?93FyRvz2s8^g0~dGz zfWc9`n+pJr4GJ5%7MvH@px^)$7y{SbK!Cva4WN-cTnYR;rz4L7%kKpta{B@P8M%bi zeOM5owflYCYL|}}Uk;-(zW*-(h9f-zhyWYfXj1etLhHUbz+r&Dz{)2;6B|1dbRt$w zKL(a6X=I995kF0XkZ^PEZukxE1TjvG@2hle2XyBg<1R4r6K}(Bwf47!xp9}La_1{>hWYtjwe{nRyZwq|jCnzY#`WHwy@oDC* zq{o}wV;utrsWJI0eX{dNYDP|@%O%6`Q+^JQ37sBQyKI$J z%?)R4G`XC=>nTTMT!I*H6>-r;5UVMuDkbp;R}n8_h@JSC^80<_(F z)O21op+1_gmt{^9;O5~QA1W7b$0p$05i|80c>&DqR#jx5A<00^5#W6`i1SgI{p#K`rJ6)Ykora?d+hJ3*Sy5?+ zDwG5zn_b$}s?v_27w62%OkD&!2kLUxkp!EHSIVLaTc&D_TgCWwamDRKtMsdU4(cJh9X|^SVDWWr`xlf%UtdU$|3x0@t4nm zUjBK{u*D|jX|nF-Dz5d7Mu4lFZBI8BQ#8!6DcKVSuBX?)BlNA%zKJ7F{jDr!J|2z5XrT?{28>bQ;6|gSHczw{#3j-d(b6%_u&G)0P=Un7c*+{8(#dpxTBZ=> z%CT)l*IVY3hj2$PYW{~$(`6xni*tz1Mr z)#C_atFG+zW+^UDqGMC@!xZ}1R?|Ico~mcwGi~x(%0e;Nk^n(TT}>d2Mk)oJx3X)4Sgc5q1I|q}$O*O((8^xgHQ`qi_ z_15P$-WqOQ8HUp`Yf7P4YRi#3xI<`PRq|Uq$G+bOoKkwLQ(b3g7OB%XcIM1q{Lh#- zbVnrf#r#Lje`NgZUxxL6nFhW28N-R@tXbwqK4Y<2h)@P+9L1!>Pc%#XhX01q7^`92 zO6CXrzpP>YCKhL|A^!Cf3jK~TY*ozi*dWJ3yuoxvHZK1o=2y#F!&&ZyoMLA;(=^MB zlXK;{-ceQ|TI~3FX44NHVC=bQi8 zwd%5ARwl6~`~#*h_K8crMdt9@8VVHx2#0p?9bd$kPY6Rr>6Kb;tsjL)N+jtUNyP$^*Bt#W}u8HGow2U8u0rDhOsT*ilY@K15%Q8(*r4m~#j*%X#vd!xBCyo2~m`|Cov;O9zsMYu^ z^;|;!8+MaBOPRFau(`>otEW|!8?(7epd-ZMS9VreBGfr*8e&uVVifetQv;u-=YdKw z;6ANdc-0i81PubHBJ&c|Wtg#$JA3yN-HMHI>@tm{4#Q5iL%0rZo~87wcbTc(&0EF1 zli0LxEtcHxQ6Pvcr)!zC{xn2S6U&)#7c-=B3f5zQ`dVRrJ*~HQ(Q&AUzoWfy( zZ?SPnTTO>gmqGD!CwLZf=c>J{zdd1wN+XQqb$ZAU7han8YUhWp&mf|p^~hmq>gty~ z7Q7$(7|t|*G#D@cQ**{n{D7Z9wXP2Ccg)Y+oLMy+;q}mM<&$s_qA)*ajpha%!LwDx z%G_Ve^*=#r`Uie}^$X@hBj)|W(ei-&AA9IWkFLJ%9N^4v$o!Xy#i=1X{bhxLnjVoi zZo|Mokld|5<%xYudbuN_iyQuR#W1VTQngnNT8F(c7<=BKtV<3q^crEXl}e{sBG2AMOFnHMi<8%njYVwROw?6lI7%nZ( zVYZN{YsK8cu)EztxL_CGg9emXH#n(VSgthixdc!k=%!Lq^DL$ z>%x~v(m|J6Qc_Xa+oYCN%!9PrPlP+aw^DF;g1 z@ZU=nr&mWSt`A8`aktl{FRK?$mEsHG-vZIcMN{0mwe`c`Sn4AZTOa3<%oX+8o0H#J z_r6}l{e#zwJo2-hE8z9VM!Uo(lnC9&nm_KRLq+-XPU|+o-mc(vwV%0_!~D~2UA$Ko zubsH%C^*&-0`8$mhegZ(Y?&0^px#y@WjsXbIrz6nj)eG?m(Ikf_=PimR9ovvbN}G3 z=s$dcc|Awd=9NX+lwn9v)7MFc`wd$%_!sUspm~{Hq`>^6d4I~8$^E8Gy^FA8IX;eM zM5-&~PNK6WR703FCEJ6fPw~3%ld8#G5gDf3n@k>OaY?IP70buSsT7!ZrXT!jzV#C&f`*V-< z!Z8o&O_h%sFt?A({EeBw%05;(#&G||zfNci%^YF0uk@SUpHkv(|NHy}_vLTapAb2s zh#~Zz@+X|XX?ky;wnKmd7rs|{b30vuuDwKTM=Z^W4}LQV@AFK$=m+&#V$l_I_EnaK zVGZMmIJ8DPLolvc|CvR^`ErAC{>hi_jg2Rm#WB9{4*Do1Hz_Wy(zH~kMdW+Fd&rvq zdmonguW!{f>OVoO^4T_M@aWJ!(`$`O{D6!``sl@r`)q#*_hpm{C($F1poqxLgW<6m zwrEA1FG`5BC#iGPv1PH_s7Q*a0ej#I9)XLDey3cLtP({zzC2e$RC>HsS zD!PdpGhA9bzjEd93`Ze5Pgw?@frlV0d6TATi^#YPL_|g>+=h9HAuTyDodavJCrz;md4nsM|Jj31zv9k^E=XWCOkgSU<+Iz}8l=N5XgY*;2MegQ zcW`=|)3HxeETYngKY4TX6X~CL)!dy`%}<8ERnxAzc?Hy1UMi-V1Faq@^oO+IXzOHzctsR8c0gnu;i00{bq`t zx-QvSA^PK$ebyQcw9z;-bxi->I#qHft~2wf89U|GmO~p=8LGXTX#6bky*SG1p*7|S zCbge-f3p2f&#tnyr>ros-8SM%B)pU~fP2S&FWIay%kPzx2u>P^D02^$%{r@hup zNr6uv|NMrT?LSl8@5pLnka603@_tZE3+i&qK?17RG!IQZt4aRNnQrRO(^tXw&%s@x z|E>sp+Jm>&3lICMkF%N zC5R%CQ3U}ZIgmvNiLh-o6}AsKCpnUkCm*s<5}G1*VA|R_eE((b-Qm$KSJwI%U!%tG z;1B7r@nR67)3xlGQ~X~!`GlN7SpI0Xd_}RbCSyO(ztWEP4?LJKJSZMeUjOi$A?}J4 zaCH4%^3ko{nX`XW{OC55v+-)ln13cI$7X|BKnGie*Foo+Tk49CO*i{uw(A4q#R~&j zdi`?B#y9PqXhlQW&C-20ZPjS1S&#jNIRA0>4Ip8k!=Rrp6TKKB0eDqc9@#6}fOV-v zWPt!7quU6dQ`!y`2=GP-Tx!V_XC&JtS*FCHRoGG<=s>q8n*|z-m515XD9I`kYL;C| zQI`;M%Ce=J%DJ`KB3FJ+)PCP(IP$0b57;G4%ac=FNcA5i2(U1(R6c5iSZ3zYgpOWm6d8EXO zyTbveoOFc`-zpB_49qA_# zHq7$S9%xYrDGtHn>T054Az~4TWHMX+oa9L2)_$YrnoSp6WToM_HP(Th7vLr1I0*r{ z=N1u))Y$XzrKm~-0eQ0pB9i|O713mi_Gm^Fz%|L899cfk%RBNeTah$$9^VX`Ak^d_ z!7g)Oa!YlsqZ0Ua>io3K0!qX((nh@{yi5>CtkN)$Ek$_oh@m*;r^mdcKX~j==j7L} zl&gg38hX2|b^OJhbZa%K5t^pQ&d)nm6S0!sk|7gY3c>^g5Ot2-N0_D@s<7=#Ctb8h z&viy){BDR`SaBTD#J8#NNvSmT^7(^oR5od{bk!loEqvOH=ZvMt2g09wKoqDrcY+mK zf&k`XtwM%Hrky9vHT0ydrCgt{Lplu)5|Um3;r!P{VO#*_W?Z8!p_TGvTcmhvG%kIK ziE-XA0L)7iA}B0^mbMAu(!t*}0s$R#2BxY&he(2g5LQvH+$e-*C4!N|Q9n~8;bd}e z2MC{V+Hq2#s_s=fg#0>6Wp8BQX+WAfj&$q$M9FhEag*oJ_`x26g z{)!Yy)?sr-@}_aY=QiAjx~?D{Mu> z|L$2mcUrzZil(VK_7<&ynySBXckFyAjvV*+$9AcdtUR5$xl|PokcLk2rf)%#cLBl? z^&L#}Nt1C-Ye}F_=IQf$_*2=EpG>%ap>_18&}#iiZEW$-)Zc2u(@VWvb)i`u3X@m-)dP` zTHpAb>MtH~e7jIoaI+!t+42;`D4NI=hsXv#r5(mn>12bf1JT4KX)K;5!ginrx@PD) z$suxqiZd)#q%6c`#!4vH9g%@fF(Axf96JnMC!4p&I?VExQ<6=Iu&0ZlVT`YpC<%!3 z%z1yN40M%#H_vy&y$!`r>Z-hl1XJ+EL?5;qm5VugyaQP6Jy-5H-taK%O-t(d$tGNb zG=|LQ989fQsBKdNwzT<7FpWb(6dUWU1?@zV!B5%pi#ZIm2rGZ;{lkdv}x{oOJ~hd2zBqAK-)RWW7Ick>wnib z!tU@H{1f}Oh58U?K(|R5RyWr%O{?+nXw#zv3l$pHSa8$A#thWJ)rOco-(iTapCv{V z%nc}G^w*|7VJ=jZOQi;x=MrY1WLFU%({j_fVfmh^QF^d#__wmYleDl>NtH0sm#o`))yxK5X{xdzs&!O z{IB5_0y&8=hA>c5>WYaR4(Y%b4el6-5=|qcNVBk2c+-qcz6fDV*djsD8Y=?)x&r)1 zA@SkZM=cY>t*A?_l$Lv3hM2D<-EOkry8P5nBpbSRM7^_r(A=Ae|2*5Bh7X}Hm~@d$ zJMb$9hB*Y!SsfVzdqXA!-kusQy(!bMU-6rISNV%=0V$n-UsR8PFoVFbHE3crKMcQhE%nia}c z`ui8NY1S5U{SG}6@#P_L`<4##NU10$ty5eNs?o#Ry5uJKMh4k&5;GrODPUh2{ttIM zbKW|1Gk^p+d8apr+?w*B)#~(y`vbHymT!j_;iYDa*=_Y~<3A|-&g#INV_Tova5DU3 z0akRMNcSo%i}NvGbFJ+xrhOl#@coo9tT>m;R6K1Yc?j7}3g=l4eH2#$pkPDc7-_6e zC$YU*J9WH?SShP~+W}Gk|15aly6jcj{K^|Wgws-P(}`?9I$v_W*%?R99z!vPtBl4b z6)I=s-|TX?+h+Cf^pF`Ub@Dd`f#8U8Vc}+1)hLn>xSQCPrl}aiLW@M`qfLLTvSLmp zb(Pivv$s!PLvl?mJ;P(goid!8pMWL@jPv%S?`*q(Gp4t}(eu{S)6R?QceK zpzbhnj5AYYq~y!M3GSPKEYED_D~62tnQD+fD_+jiEXByhG4zIcXYV?2_0AsDLvumQ ziJmA-No`Sw?=vpV@TL5n5BEL)X$Gi%hm`J*qPn-!EIFs?thY*~<6xv_4<$7+MT}Ec zReHM@T1nlmzxA4>Yc*Z>l=7q>h#XzeAr4eU>7rL+EvGejRw0=3{(z;lh@f^dVapWJ zlNN1 zN38ZEsY2^JUj#;wmVOBCWZeE07yH+yn5O~P_w9iAzz$H|p_`M9vYl{N;3-etf&F?S zmHmda<9oi3PQ}$tyw$#v8+OmF&4x|cWpW<-2_iD^ImIv_KyXb{o)QV=EN%(6OxXYg z0nX5NmJY=IWxs42<0JP3aX_9}rrS*GS{`guv8psJdq_(}6|_xVLy0skcfOpaEKN?C z)GJeDY#}qMl(sV0UG2XNsqUAxjiIEvs!UY^IW;qfy^`~8jk6JkoT**lgMTG>7Wd(9 zS$z{vg)cQNd#(h9$EU{=oS^AGqf-_dSWIE*9o<4tko)C%MSlDWbHQ3C6wHKYh`NMV zqEnQ1pkUlC{B@LgrrXY=d<>~=EG=56iO5EIGl{pl42;uE_;fL@IZ~_>7r0Cnk?t%- zd3Q@f#dwTquC|3UcuYitDjj8y4Zcn&!!$$5P~6B!pa?eu6m}CRg(Y>nNk%!P$OI;H z4u^tk!1?x3Osw0TkOqw4ugiPpT`5}sgFg=H`s*lDYnk%{zBUhH@09+He$i9-cZ17> zv(-WK>uYUtCBOLb-ge%K#}R*Go?PK>$v5=3u0*il!B;2II#)~}1s3vGbF=+h!juLg zBDoA66c7}QMu~@QXS>npDy=|CP);?>8tgDf$PqBkg{wE@AZA%z-{ayJ*^~~>q%*42 zEhEb{7DBK%P#eQPWiiPz)&rQuK{M+;W+1_tJ^F+o={73J7~FydkIXv|!GJ*F-o+SD z7qjX`1@Kk(a1AYFN6_}Y*xkx)3weJ%RSD>AgQ0 z-!j26O#`l!8=7a|3bcGz+ZS?rMam|O__~P2Uk^W@#+ttx(Wlqy+I1%6jo!SYE|=+$RrUqZfTm#rrOnv zb;>GgL9A;YHg|e~vnw);?oucf$TH;{2euV(WV#TG&?zFmjf3rbBhdg{gQ3na|0veB zK!thG9>KtrPF1N&%-U}{&8Cbr3wWgTScox_Wn`|!5Q&Rfj@2|x>E`rn*BZ13_$al( zMVNt_g}*_*-qaASvF@l6sOYWh~Sr^$NGqYy|PVHS#PX;i^jOR1Y(owCk#{4IDl_NJK^@i`Zb5xWe?fjLx(bf)1I!A;uU+Q$e==B7-7X1xe0H82H ztTXX;p}=n4u=uX{o7?WIej~AhOG9L)(P-|seKWzP=?PUKyU5FifhUYaof~$yySrIBcVm}lQq%H7SYL|^S~8`L!T5}t|oKc_4^mO_y+Ak07y zS*lpzp{qE=4Vyw$>YQaBI=B#~!`4*QP{oxYmBS}gEs{2_)bfzfr2*!ya|jFp4)6&r zoG^a98q&o=S*(Tc?17s*%dOJKrsqmi_0ItBj`CRseUr3Rg|bi>04n5NGDdLj5;AyxaB?% z&|2&}F$tA9yTSCrsK&)=8^)V)Chh~7SVOVpU6^Zq{UplO*?LQ=S(p%f-3H4}1BgiL z$=eeCKlUGcs6QJ@+jU}P8tPaFAsqr!g|jeru@X=-mey+B(Lt# z*KUZmq$%OhG9mgrlJMkXZ`^7#FqfdGl2e*OcTiSg(_|iFoI)rPdD1wgy(Ec?lC(Vt z=|AhWBcYcNLM7Xx%$8_EMp7a^hR#80%E|SC0%|OFb4kTNW43Xki0n|p6LL|{by4h0 zI>gVy|633e13{d7Q~hG;8Mi?&nz)*W-PMg3?C^I@_pfBvS9bZ_=Ng!V4;1_zzjrazLzp|Av4RI73J2xfvVCW1tG9&3B!8j~wKM8v&c$Gw9T{I2tq$ zgQG#EZ-M~$H$odFF*HZ{tpHV_Vcatq=ghZ>(dteWdZFD>VT`D&a9DXwt2g3x!oeYl zs^zRk)3ER-8Gh-ie{GQ{;YoNvu(3oqy!RM|DBP$Zumr7^Xi`(<2yrzH zP)<1pny8?uTB{5l#lt{NWfbnH{ATC{2-nK3bWQ~@XI(+nGklTEcc#ih2GmVsse4(9 zdxa1~hcECjaK*|YXz|q?zmk(AdjG9E67=hoKJA$&G^B{AFX>kfch?%*<^J0`>b&htlM&b+NdfbjA~%KzBLoBvDk zjSz!sHsL`6&f2De1~x^sRX?MwAC!TqfpTTs04~GRL*<&AC&(t@tLy?yrLi;YSpMnv zCymV=(-;G0;}8SST87V8-LZ7`lxEK{Q~oeQ)i~xF*`f}c%{<~K`X`mXtZ93cRST{3 zje2CO5g>Qg&t9kyI>i`8CRN|0(7PBzf*6ae1tPlgO5L6c6I)k>mXiBcrjeF-ngXt# z|D#CW(H}iEq~HLQ@(De_JrIf?!Z* z8=c1AV9?=uPZjxL#WYhI*32IbUwLN01-9b>8ew_XJ<;qzp_7(lTQ*o~lr91l2<9D0 zcuMEl6<4E(-SabhzpZ*x`OUQ&b;XEahTDibOXA)uUmbPBal}*NLVzC{`ALWUJiS5< zWGtGwpr*UF24q2~3E6_s|M>#g-u{RmUD+ee-Q5ER^xFVyc~}Qu?62>K_aoiRT~q0) zAu6?(4*wRy=TxPEHvKN*fE2DKYv}Ok*ST+D@kZuHZddQ~{1@c?hJyd_7bisXJFWKI zCN8;BWO^ju68?wB(@UCqeR)Ch6f*3w3Wx%n;-&|(G*iSvWG%>;dQawzUr|xCEq*WT zXMU&2NsEVk=dEC;yjeFS*(sST!es1#zz@I%g@6F+pAdgI644Le(h==Wz^%Q#ST-7S z)}fyf`z4rH64G;ZXo~&g_ik+#ACwgT68EOGOozmF76&7<rb_~ZHKg2~c1 zm_ll&D>l7eVoFmE^QxJabf~%;{oI)EX-*n%2a(a_ex03$F1h5;cA-oypC&}nvEt`Rr3Z{w6vOR|BM%4YSt6uPlE=yc^K z0(5N=<4##kW7;;`xCL2N@i=dai3y?xmf+5+`cmWUVb1oCn$A?Sh`6i>S0gCRLM+xa zIheFOYKam|0{<`g8bTmPn&#~c@DBtC@biF*bTzFI(G|C@@%UzqMm0<^Y>8+%n8a9` zMVs9PVS~munqbZu427n-MEA>+q#B(?> zhG4T;Cd2GiHP7k_s#&W#5G}As=%xHy4kfOKzydK4!Z(DJN!N{fI=B>*a_E@${gDI} zwDQe=?nZ!@r+y8~{0Kr%waBR(sJV%R&9hN_pxQSJK^APsPvQdL~R260HEDI?UA2K>T(ftN<41!h1(%C{cZ ziwtxK(?SU-&84M4mL|FidlcO=9-*${jzv7BVy=X}suW;FcRYQD6ckZuJhg=s(W}+g zC^RZ&WD>)$W?9WELzhBCbZuGBF`14jyuz9q zOaMo}RNlJar2Zt8r z81;2nm1{Tzg}W3|l!`cxq5&OSYN-VwjC9?~zu1=9Js4c%w&iOLR4nQ#ue}YqelP^{_=qD0y9eOZlUM=s|7y_>y za#LFkX~?WD!c)VIbmSX5uZ=cut@L?YYpsK`C$qY8E|ghalS@vL*@ya-V3uY{YzUGzF33F=w>I-SJ22a!ruKXUaj~$MC(JlM z3W6Tz(p{6(CPKQi_G~6a;*yI7O-v(lf4*|b_j9z4fIr!8l$&4gFUlmCPngmgy^q-a z%+S7O;}eGSf{h@B@rX*r-xqy@WYc!y(pBw$X#Kx&W2oKi%ss@%VZ_e~xDX4x`Rs?S zhA*F!_FgA4th7Miuz9yEjYq?8gZo9;s$KW^b#%g8ACAnr#l_UJ;z~1CeX9gvi_fT2o$>?K`Hw@+wr4+3zKORjKZ` zGynJc@eSAC*ztd36w+a{&9TQOiB`vU%7O~|AXd_W^qTUJdj7W?P^Lqsa@Hxx(i9%G zdr$fw1zW!XSMyIi3+{vXAZl3RXixq+-Axl*wqq-m&b~v$2(D+OUrmJ zRm|x_2)FE)^`W!$UNtbbn0;00i*Kwi&;P%PGwTZ_HH0;7ntH-AI>))w$<0;YY3lF^ zJ8J@xnaor@Xw>XxhAy`i5;Rd>2PU$$bjw;@s?fV7>1h+Fk8C1 zyCu|q&SUQ2VOLv<5$eT_03peD{~XfQR`(k%LpD)mm`Z^?78rfJhsHsbIY z`!cH9EdvWx%k#*ugL*LV0mB0UOPxg)o#XT#H#N?)0S4xq2$x@=9rt!TE!z3Mdm+D- zi~es&1>9V3`S^md?}a4)coCaU?QyOSE&XZoOvjo7ZU}=R7IB$TV9>^-cc+bu638n6kEqA?sgf>+$j_K`LI0WDUUm3M)-4-SqM%M zfJ%5f=nGr6CZ^o8kc~YHDVAWq4XEzE^r{B4oB9Pgm!YW$@)VWO7A_6;&YzIJ<8nQb z)Chib0$cadkn_%h2=WM@OWGm^1mu7mjN+{s_xFteV#JnRwck90|H+?04Dj)O-YeRM zjqN4*JQ?}Q`@di1=Wa2dkBn#wwzTm`nl@){a#K$vsCqrv ziSfZqK{O&!#nx;?4>1&n)6z?39DGZqMy=|hOYSY9=Qh*0p-B}&p)NC?#6zDc!^X4zPdYs>`w^nRdfLV4gQ|(l)j8%>7b^UHW^a!f+^O?w2jhSTU%v$ z6p>yQ6r>xLTbxi_il6am_Ecw%utSCIAt{%Z+LoL_n8yzFek4r#y;D}orb&+?$e}UG zyF+MD-}!+!2Ff=jEhR#il3F|>2uND7N`l5&(_GuM+%8Q5#-XM^WjhdL7^h(j<5zK= zx0Mz{(bFK@i6ynUUCx}iwd1>d>>o91mW$=_*CokA1cE`?4W)V#%LT*Iu>xZglV zGG;aZ^I~-fnf)~Ky&eX-bQ0uiQQ^_@|L{dM!K3Jx!U+`ryF|;cUY+fTO5}db`ZIRq zW*93~{Kc@z%{xES`4%-Pf;Qz(bnnLMA5agXNA{oHz*v`m*5=Vh*)i|DJ6xy3^RGse5y21yqs_nG zG1riY%Xxp)i8uMCF;YDFXF_=brb7LjFTp@rH_2SuVBSzy z*DAwYQnJ}-&J+ftNWTjAJ45jgjblu+j5Xu?UY2_)D_;MJskN`>f0H(hpBsu2WXtF_ z{Qvm&GUQ96SJE)ep(?mewJ$1SH6oxiX_z5l(4?0Dzdey);CDh@W(vWd0TQT7kg zhUlyrB}=%v-ukN%XtGmdvJymE*2%}J>frTuKZHQR2Cg{cbn;=tPRmZKtCyFj*nn+A z{J|)>rAyBHc0UuF&V0BHVx?{I_*P`QeOV3db$4);G3#z@w)s|aI-hRS%J&U?(g~a3 zd-!)Qe4bRXjL&%4t>0G>?dT0vl$-E=aYc87W^8_BwQaAxgy;j;Vcbw)OfYabIX&P7 zh6a7aVJClcU#80M+v!M=@i;R^H_FaQt`h&Ip#2q?fofKy;8NDPb3_{I0xfdGI4RdA@*8vELy@PCSz)Vd_F z8%0(cLDF#atBvED^-#-yK`+hK)&S0F^yT(ALnCBmBssH`dAZrp9cx{2Ydf25s_iAI z@?$vi?|sx0CM%Z~fnm!zaRoT$U@~muf=bw{++8hf(X0UjHr`69rP=6(_+O}#%IE^D z11n0z6BC=c7_`y6Hp3gY)G1aM;-fwGV_8tpFdQ&pK*K6r5rbVawsIc-E%a2w6JFMi zXMa1H&Q2SXRhQny?m)!Fpg_sYlaV(QieH&#NU@VvR1;TZB-En^Qpr? z7SmPSDeXAv7?s88GZwao%3c4oP;8t z(pbtbI&DEO6he`Ol=Kk970Y7DGNeVTyD)D0B2P*~Ql`|DMm#XqGTGy$TnQydLC#wy zl5F0sgbq{MIk>b+=+b-$dimw>8dH@JvD_$>w`}o{JmD(a)WN}A+E^pn(}nsHcA752 zwa6HbLUD=?!7PX8lw%bqrKcb&d4!D}y3|qeEuw}^hqxn4rNx|9ICmgmN(SW~w%}71 zImAEtO8 zC@pFln-U4zzNRU%LlZV)&noeztPj(jjtrXBl!z(vUnnC1L0g;#1lpMMA_gG(^+MYeMnx6y)6KwJ*X3=Ra+PK)nc+ z7URanadzT|uym5PRwGoHjJA}LQBE|lmFzI<(&|!Yfo_QddpWfv&teb24;#1{&1=qOXk~ke-B9%G<4Jru!KQGN4oL)9mT*??r%^Ue zO%JJYyA-qRIm3Z^Xk%M`rO&N~COdP2C0jWK%2Q9MVys4$Nev5A5^)qQqZmqLmgW?u zs<{g7Hmf(5Ev6W%sWeeuQetU~D(<*+-uhu!(fr*cW1-VW&2es8hO?Em!g&_7yec9U zHm_-LMokM_!hC5>Y8qZxkR$A1MYiVtd5f^)UB!Mi%kanKcpL6tM|`}VB{uTh+-ynR z%}Iv-0YUouukgR(PT$b?xoz`r=GaZ}et>RN1!2@@GUV%g$cFs8))-&1#IKaS)4;;V&N}UiWlu`zSiUwfYUW~aJZh~rAX${i?L9q|#RK8#D$CxsedgEb>;7%(yX z(qBQ2xMf7~Sn#a99515oM%0nGf-4`6p>K(id)`3~UqvuuBn|2l@AjrM_$ z&}t+%uLgYc_9IqL(F4cY+uc@Z!`%p8~nR! z5UOhX113yNV`j**muW4@?gixDkE|Zo|8qdVJOKoFz}j2sDgqwh;H)`8fZN@Pbx`0m zULT#mw1OZDt{})4((KtfTUuhtsyO1!806Aoq zeINjR;J0HedF&;C4G0+Kj)ZEiHUOPf*b;^l@-^DJ3Jc(eF4v5meF7r+Rvh32D3o^r zz^*_YD5WA|6i{&X5-?!k0R{d5!HIzj0=#?OSq?C8*qZ`8016Pm0|o&K0{nM?Ti^$g z-~j@BXK)Pui}B6{gK+kNK!9xk1ObZ_wim7sk`lO^!iyQ7VPbS@KC+>rC=nz5arCl# zE&vZ0<`O^%H1@Ar28rcRvneBlaV*Cjkf8j9C_pGQgA1{vYW1 z1k84C#?N-86U}$2N`yPqbTq(AP;`KR{{;aE2m%iNvz{&pP{)I2uL3UnnO@3@?{a1? zSJ!^YXAYR}fCDjwW7`D+$^`#`i<~iN@aYY*j4T(CF#r=kw!tKO@l$&$1OvVZUU0IR zeZT{*DY-d-pNxzQ1p;;+`Fi!ed2lbsWMN-NpF{6~ra-_EGFLaw?78%`yvFjOu7KS^ zK{y2+r3923P;tN+U;wrcfJnYdgdI@ee8(mGARYiy{P2it2SnRp5KFFf`o#+|`*p|U zQnGJ1-(x5EpRi9XbpFZiGn-A#w#C_k$?~fDgiYh%o2;JGtCU>qOfz#Rt0R@5w z90;7?2LWuaiS$5T*#j_bfC1z!J_Z;wN|*OHBaX>(09rt$zhtcD=)xx;;9rGs%y5KP5x2b@;{25|ow+z3avJLDGu zx&~?BRuuOaph6LxnIM1&P|@I^pg`opGIKMF^9&>d;Pye@1_t1EvIi(EhTnLY`Mm@P zFx(a3%Kv_dm>DFnoF})&2WqG-2rjaW@?-%3`;MB%p|Ze*x^!WCWt>`#o;HXZOW{qg ziwY2e`)v5Y+|RzjzX*8Unm;0_Qa&z&->QrInmDu-^c##u_(oLgn_|VCNaX-B)uA5% z0D+WJickfm07N37@YY}ue}bhS;JaX}z1++M6cof67e>DqXcTrTxL&9q^=$8pC|JM( z-+&jS0|*F!>b?u$eWwcse4iBvLh2{pFit`KAMydf>*H&;07~C&^Lep zH{_rn5i@*0toEp+=OHq2dkL_wG<8%O07fW%9~=&7Va}}MIIHVt#1R{v^$VcVoe?G8 zpTO; z4=}s$6B(s+%1#y=BG*;q{HA|*nRCV7#GQ@QEkXCb`!(Y5NN~4$u`B)~sxgMl5E9o- z0RjjpZ@%KLIHuDPLA^mG&Mx4^ik~Bulv2fsMZlRxe=Bx@Z-VDh3|(L&z%S@s5a7bV zjs5}$C@@}srVlLOf&#DK?j$JL=&a067cLtRGY)VE*k%h07PvqL!2Q}CJ7CD%0ncft zB7;Yemg{k`e!W_|wfkspb%)?Xe&*_KEZ*yh!4JMZ2Pg2?X(EDa9lsoIrCs0w3I#75 zG$Z(c!rt($gs}00%jBuO5y$SA)7!zMBwRqV58%P=1E&phWiATU$k8CYx@Dhu60OSg zWJlcHtFn_Ovsc1P(;Mq5%?7s4^zT`3*8uE)TI1*en$n6Pa2w7sh#vlghz%gXohU9q zz!4Auso-ZExC7P(_rbY;@cVte$-IfdE)=K%tb^qa7`Qg8H8I}c=B{`JSG^f=;l$4L zaON7x^h{}h(Y7L}O;c4y+sG4<*Oc&Ykl0O)h2bG&wkfzy^>3OfA-m(cXS0(~C6Vm+pe?0SIs4j)P|U`+^;BtYh6Qt;f#0T#Zu=ni2(z#Z_k4FdLnJm-X|`wQ591p&@}I$AOY=og9&(~bQOqiTsS zR>dtBvgUW?Vl1Cvu771}+cIrCer1A%Q+rDlEt&Q(pA6qX-K5Z+Rm(U%)0C2~gsI5C zJDneE|Hs_zCb)11umCz?c6<3Q))e4~UJxJvA`Eh4AV5ICUfs-&Ptf+1YX2~gi-8d` z7}}Zgs(5|ZG=0`7XnDknyVJ^_I=nVJIUj4Cbvv$=f6nJ&eAqLm2qRS04ZBqFVN{g) zG4pV_&wzrW2DcQ;4*r z1>3PxJJP{l@+@m24DtWNiRQQU%w!N(yLn(ZOGcH}3!;N{gs3k&5nkEUR>0c}fhp#LeJNdT_%)MB={-?3q+gj@j`MUG0#5Xfrm2BH? zh**3xX20lXCS{Xb6OtcEBatK%m`SavoOU;e)`QG_L@sMIfdElK(GT}l#PyG{JNEzUm7I-OYhRv(bKllc!pw3(_N zVsEk^f%!Q-Kc#QNU*CDp6o8U`-E(gzo3dl|F)dot$iZvZfh#uwl&$90$D+D zbp5&QX2_2Td;KjE3z){+@5DW(TS5{gXkh!7OBMtZ24fAxZb>+Lce+4`j`iqZ| z_w8Jj=To+LKXKv*8iroit4e!eM)1++b+gILg!uBw&6ub&)aCUj=Vf)b(|*MGiRST{ z-#ZH57IvzLn$S_4XV(U$&+uCw8Wuvxw#Q@m-#!dmCW04X23@I0y((ej}8& z9_99#=4F-4mb9QqQdUF!i6-`D<~#i|MO-7aVRD**E4h={$&j_AJo{Td66(YoH%EOn zWrFC^ds$VwSIHSF&mC!}n8u*{5{M>m51T*Z@G z1tteRRy<{9<`Xe?9hLAn%Vi^?`&(=XR0HFfmYNE;L8S~&3BjqqLig!v7b$krvYouU zwTYCh^cLH1ypWef;Kh0?Miw))Dpt%#`Nb=kyt9S5OL;K4M{Y&QnMhL3eOmMn!wg*> z7!tYvO2{sy8iv}2TiuW^Gizf%xXU?%t!#R2OAR6*8Us>r1w#QgO(8LW4=iU+H#>*q ztUoLCgc;aItg){t?wggA`6K%`B+g_dRdc?(2H)I?k>od9M+i>N%|1k&UBPf{_tT3{ zQb^-=x?+D*V%Qc~Tq(w~80;&$Rn>Rq*KfG5ckEv3pT^3F_kMc6bPBimVq~M;)%)9> zJaKZT3-zjP0WVLPj+(RALjLo?(4D1zNSg0=Gh`IC3Hf>lgf0uK!=~QhyJBT85_?P4zACY~(Qo`6nSn(6wa+zV!me>`%#8lYlc`V4&~?%~&#Mnxr=wrBl4Nf!9-tJkfACOGM zh3K|De1pDfr{@%nyhXK@C*Nx1|0(_>%?FWg&I-r; zS8AZ8S7(wDrw086^&mE(RMA5hay}&=8_u+hl1mJe=RX$O zU94MCYjd&ebvt{GFVh zzhp|loaI^G&g@I}z4ic(nI;lt`d?b%;6Bv-QDu%KM0Xxdj-S2E^8UsQ(P7Plnw|)=;*bjRAL3ZFrmEuvqeD;l>(H4)A4^IJo&^an?9Pr?PiLuMhSai z{={(PH+(s~vV&ElHZCFPv{ApMRrn<*8L&_y5*)EC+QPH)YZGyP+&&|i+SY^pMm7DQ zbo-gxV-tzl`CU7LCq-?|Xh`~;aD+Mky+O(B!dkH77q7)9?D$@yG{?}kgAf!X$7R_z z`(&N7*e>6|(H^3xeDi9ApHo0@D>Eepa>4+#osDn#Z(r=AxFo$<>Lhc3Ys3yoZMZ7u z5f4e)ajV?0qH!QhnHG_VC*Au1SCca$|8!tOFQ1_;$UBN0=Cjo|ltluN2nL;PiC`Hf z)zWcV*_yQEEB|XL1u8@=5wUS0LSx3-Z(jW5UQO?s@64Rh9yJ*Ge835cf3GcvA!Fto zKTQ*af5N@wJs*AX4a`@@p!-8F!4Y&V7C$HAJkuYNH<4LILP>D1a5mBWZFc(Uc5hyaQt%ZNDxgI*-QHG)vp2 zAAL*qTkmJQ3of_(Y~Vo%+`<I*-}0& z^|bpaS$%Z2KH`Y_Lt;S%@$>(VWw!vun))|41UUy25)vVJn>Ed-@d>Z{VKK_^-|8+I<>Hq zJXL~W@Zl8d8xKBhn_t5x)Mm>03Vc(Yhp^_;$rgLlEBw6@67&NR0=6G6XTi#z(2*-d zzwyjEM2{+T7Kp6ElQB;i@5uQ3#)7|*!C#Tv z-J#zk)6x}<1-5i^a}y}jjacU})JzFhv&4#>1`8EMbe$myzEu_@7L$p(C4j80W#TF3 z^17Np9G_DR$in7S>V|wZJBLYAdYCV;H7^vf#xkCV2+l#+)pt9{GEyS#Zw>^BiC{0^ zEF|RZNroT$iaj;AHV|O31I(^8TiX^lC3P)nsqWWTfQt`O5=Q_FzWUs5=+Na|dLYbP z4j4@gvfR{$I}>HT#X@b0lhWzEUR?<4Ql-{?FMgtL^NFkK7Q{7|vz#Z8Se_cd+s|3= zesZ(jMv&HjW;6K?t~ZUT*e_peqn@JCTz)cz>ahr7Y-rdH2pY2s5xfCe?^QCpf=X%r zcxS}@8NUx3wClsX`nFeG+P*Z$;~>d4z#mOlGK85K6)j8#I%Dm@=zB^qMX}Zp<>e1?SIcF^ zmCQAbi=z4z!ljT%3O5&AT?WF0e3hw7%#X&YrCgVJemI5seS<~Ye<32>5kCFh%Ivif zFC$pkySSbdYy#_c)bI7SL7kIo#7fFHcWOsF#2;CA+Ijbn-WgN7b6ZE=7~w49V4|SA zB%yJhFh-aTN}zAqDXCKn?JD#sAX8G%0^c%Kh@fW?VGe;vRP2l=Z{us#=5^-R7(plgsQDQ zB1B^7&GMTIx9EV2h^wYw<=)L|oQm+&_PaGa`CA03uA2Uzzg?-b`2Pq2^55x(Lazj zE|R}jqLt*)6-^~=x&@rV5IZRQqiw#RrexIgPF-|8Zb=P4{Hf~ZCFq9(RhS~q;s~B? z!!)7YD zwjeT2NtUUUFPr45ZunWt-yjJV@xe*}6)q=^aLOy9l13E(5mnjJSjgHk;3=A*?OeU@ z#?6tdr*@~d+lqDhh?2f*p8eeXD*Rj+WUSBRgeiKY`|*H4fD;TD7MSqUvRC)vG+18n z^&gmj+u0e0uE2(nwKY)SZg?CU+PMoH1{C}^@&acgctd!11Q^!q?^MIk^B`P39Mb*zQ%`G@egIwu{i1Nr-K=Tw1x2D-zSRz7Nu z$!%cU@^)xfpxmK*1-6fyV~#e|JA#`Jb{SRCI9FfrHw##>CO?bk*K_ZA`f7^WM3lFzD+IV86$BVK z1pE5O6R6;1mETC?Huq^v5Iw^j?t5kvt}wtW1#HLOqhRQBZ%No z7gs{S8W>?7M~ELGenO=Qi64OiCe78-1Dp!r5RQB>FmQkz1OON?I5^k=f&+mc5EK*;91I)?6ciW`902%21P1|z{F!yB8$Ez;=nflTnz`N!rCi5Gf2HB!CV%}8 z*k_j8hN#1e_d>^)|BKX^vU%H1p)(zCQJE%JGZ{saXu>z81o7S1^VR$^C2lm z_Hpu|^0Jb{{4g9$uqSSbqz!`Lc3}@1KiY^Y6nmYY&5AOscZplhyb>-+!)Z%m%4oSsQ?otS)oue`X#LAQl7wEH->yRD z{~kJ7)wVl4gy);AmkLWiMLbKmt6{)cAq8PZn0t-BUU$+|H*jw+s)OI@Y zs}er6;n#IKd?%8AS#OqqhA+FI_KV{%A*7CQs#8L_6XmzKS4b*=+{>eD9pCNQzmAzQNULbk|2L?eq2VSR8IQWVB z1qs0B0io(-bD^Nj!G!=-77U;U+zJ<<;1LW2CnSesQc0kMZn=7t#2z8T`yEx_yNy0*`ceVu$)& zP>-$3{FxX-ph!Mgrf{IyXS5MR?wspBirxJ-VECtd6-eNM zGe?_dqGfOT6*F(D!SpwNHfwGE+!eQ`E9jn6VFw+Y3fBw#!mCmEEW!jSzD-*TpMFiL z?e!$%r=}aaU!7aN*8B6#v8F{&Y^@u^pbm z>;u~_JTXjg0J3}&tQQU%w*KP(kw^G>{AR^(@G>L;C)_PzALYix|K_P>Fo+eIxcsc& zxa08wcP}=sxB!~(S;MfCOD;pda}IHjUuY$9#<-tM;zkps)_=dT8(SIY#fpUSBWJmh za(j%w@y==<^oa|hxbRP)8tO_TB$xsH#@*jAt}!sfEsPb-ig!kVlv@ymjzKXlL59fI zPcR52O>_pvZU(7^6(<%a#%H8Ehi*jUZ+?tLIUWXe_OG$->+a-kle(p~6Kc+xkDiOZgUEwHB=4Te9$9M=H97^sSIkBNsR5A*JmQM*rEC^ZR6=@H3 zDG%?KXerN%+=Ae%O`C)T1m{3R@v0A@i%S(rhSQORn}aIQ4@0yp2V31{^sMKXI}%Y-23!~Ni5nQ7(nigxG}LQ~rKOuj^@ zm1qwrQH;3pa~4H_1wx!CVp^YpkY>qQ9_5FO`R;E+zbT!l$=c-gNhI!fS|9!GoPmHH zZLVYE5yZhiChJ(sR+NoTHZq)2PCeDA`f}v7%!Pbht>mr~|Nm=$TAi;V;`5J;3;1r4HwM48=^qu92+%*q^H~l_>Ib9e9N1%) z_NSj?$A)pMDiI9O8Fry0IE7-1PF3R2lk-|^s+L)b$Z|1|WBYV|;{$!Sm8#%!#hKHS z@Xj57=83rzmx;Zjck)o|Cr8j3JY#6xMg$}%Bn#w=@bWe6O~`D=00&5Nk?YH7et&=B zYN+2!{qHMR+Nz$$txbO=5kvgRW}JbkU6K86tj!Hw+=Tc2UOnhWS3fd-N7#5Jw(&Ow z@!z$C>7Oy!R*kaZIOX*fr8y%m&?$ztaM=N=wYL!Q3~=q@T+8>iT-fkRDMf{&&irYtuNLkHHF?ZKS zxCT^+t_8S5DJ^>h*N@^$e|T%F@FUIn;A6tM`wFeW@Dmh$IX2DrS4iE@U+~w8u4p%B z33)ZeL#pxV8zoQ(bsOZ%tuV|-i z!isooh7yGm5FaTJAIF=l+$uVho1=NOMhB49IBOeE`}% zOgNuCwbz(R(4}Q=pbDL)R8{(FCC1-c4xFBhl}(@L>W6t-syyVo3280kq88zn!fZjD`pF6;qYJ-%;MaIW z#s<6a{Lc74$}llD-~m^z{syXdpSXJSx2tUTQ409xD5yS$4`lSejbgcE5k*pAo>EJc zB3TnJ>_p4mF+RH$VPEr_A-gvrgwak5)t<02MBP6mO=E&l#{oB#qKj@~89w}XSwE%FUe3Jn z0u-GxtpD7Af1;J|`U>i2pWra!)vKIgsRdh{pG08utV4 z2)z8u%dYuZ7%R+P1}g{coYHoCKI{e=Ipcm6nVzZDzVn_fxm2lrL$e@L;M=Ve_T1eG z5!ZLXk%4R|@Qu{dvQMbyZ$Gk*o{XJ3V{FPB|CtrwWrWC)lbmJPXSpzA?{AO>ae5uz zx~`9VSN?b;VJ7!2oPGnjbjl&_MyO5I%i<3{o&~P;r-&-1=g4aCZdq#VV^hX8q)3GK zcO2-w66M%+U4}b~HZ=OF%kR9*XS^6byl$Vd*S_Mz1hSij$qYum6ZzfTaP!vQpCj>+ zIi;BT)%K3MApy0ymw2~VTMRdA{6iy^<^6`;S^ER*-;h|>^Rm7~9)4FqfBxn(l)RJd zHDOaXiE$){i)*UKCI}+A)d~O2_Q5_h{NK&$b)f?S497!FFwqZA{c7JApuW%!GI-+nFmc!agcxf2o&u($_mf z5hdE%gK7jp+xg-ni|Cq4C((S2ly1sam_MES7>*xr5cnX!SdIUL+R*Rd?bQbFec@oH z+?yZ@HeLKE1sB8AKSb$-(*Fv9uHf4MmGQWgXrMMo#$>>MX?cL|>%wN}7cNl2x0>7} zoJt1hmRbEG5T2^(y&C>Co_2QomjqUYuuZd!CgEznDKaz+RHatKTETCBj5u#;b*CqR zeJ{y&Cg=QFxU6W-;cAY8HqhDMM3~q>fyP|~0u17Fvmr4iM-JTdh-g9p$?W(<7>)Ai zJxs4B(F-39H*A(9y>bnqGxvN|bJe*cw+?g&{N1r|efP7xp4wAhy^Ns1uKiZ&w3zeq z)uJ`ii3=RVuT!l|g1`_q__XjwHxXYA1pHM#*B~1>Fk?)RNGZbn1HY5H^HpdH{Rt%? zxEouDrR=i0FET@xm`YjDL;Y3V(D|^45*8^@!;F&*5eEecVWVlS+3c;7jnpnEWUX0G zcRV;S0K784(g2N5d@G|bl6LL1JF+*7M11XXqsaz^?xmT)Gzd3UE;HW5Qh%W`=rSG5 zgb*;O7tz;tb=Xd$ECq(GDi!L{m4wbeZtZK$y0ZxIh56tge z_UO$**8A;ZVlI7v>cH(T2kcJ#xdwk(*dJSAOa2*kxDC@1Tk*X|F7StXm4#a&^XpWu zmX>Phj`8xDyp1={HR=?UB2{-SwM8eH%v6YD6m9zU3JaQPOWa^rMJDDTH)cZdjU=vx ziQMYw1v1o>qsW&``d#bY)3f!8C45unq-^VZ`$!f;E?$M2QW@5&RNKu#V9I5IRF54* zJz~_|qvoE&BmV2bT?%;n(`za)rzV!~7O(NlYz=8prIJqSddXft4p(odiFV&XedBT! zI#nzWU2y%~&_C@0fo0Azpi~u^Wa%H76aJ=5!k{vSZ(C6<== zEU1LfGL96QzW5K!{)r(^j8KiLMA8SNa1GA}vV#By2Lw(d_5tYIBd{5+szSP^;3BF7 z_9#;-XmTT;WJ}GzrK2(A9%&H)v#Pc!LZEPktDf#TWg+GzD_O@n@V|WFa5Y&ot=H`Y zEUzrB2wWBj%xq!#%gagv2{b*FR+|RF*!>zt!z|w*V7}@h2B*ZYqC&a+Zud#KAz?QEgPDFN8OEKPFl8nN zWXWpfw1U4O5f?)mkr@Xz@)`{zswEvRb@=Zwun6?EY;p~IRDm_6gJ3mzHs$WY3w%Zi zyHeu{DsAZcYOwzyM$VMaxOoUWVI%KJcGGy_)d5BU$Eh)l7njqP;nGAP&Kq|cYo1HH zX$*Jo98?(X_($EL;?MVBUzQ()&3zZrtz1Py0!O@cRms6kLlMRjT-~Z_RLaws9;xT~ zU4~QG9F`&Z@=dlD6C%SRAeu*<_)?ka3q3J%XD}c?<2UxcZS1gn%!WraQd1OYP1s=& zKH)-e)&R)hEpdd3me!{YpRK)9^4HN z6ULd&H7_7jJNWB*Gt6Z$Q=xa)A%tlnk;XFHQmc)EnvBNKwuy_87OKRP*pj>zSLNM^2DTx=Q7_3|SFH@(n*S?ifwux0%?L$su>PTJZGTvXkiw$j^) z|4K3=dcT@u=PL5=bA8Vlf+nZ@&sE9Fe~)=JP7#b^unh*KZJ(D2cIt~Gw8BWcDHFW3e`UcBg7Yhj=K9oQ7wY{Viwd@EauZ3lT|T# zmf=`Wx9o1sX+IUrjNI8dJtcy{U(GA78y@Ug#Ea4p*m6r^4C6Pb?KM=&-nV>BQG`4a z=QzI_4tpG6oTvNzyNTfYHJ7dqy0f?uyWjQ4eRHF5PwbvJmD&{|{lq%4k=UHi}cw%iG zLeW`oX`DQ9_|qhyue`q|{oO8ERf&)c{yZTp*?|c|`L+lj5LaiyQ#PwADu%Y2d<@P?t3)3x~U@+M8n ztz75A4^uJxg0-w_&pxeyKB1uo#k{{sD`a51l94pHG?v-Yis&313@E4LV!x7`)||15 zwsE`Enc*09x0KKEwVpPKTQjNG-O}FdbW1#|;Sh(^FE#RH#O|6@A7TDf3Hi?noO3ke zRRTMk-pR;2ZOpX|Kp=3q&V#rFPiL;pYVFbz)(BIww7LZDw#-*Cj^GX9wemi*t%pe4 zLGQUiud6YVbyz|aMN?A^CQDoVkWpH$p$(zLX)dl;v9_gqR!Y~@&nhCFsqm+JfRYa+ zT$jJHdQ!_+e~~^|N-p~TTc9daeQkjVYE|o`Q*=xbmhrW}GeIY;bHbSt`w!uVZ5xSg zYq5-%lt%G}P~1T5ThVg|$a=youEBhyxNWi|#`4vac76M{FPqPYyc;Wo*_ru?TNd)0 zP%L3wm>_aeS30Q&Y-f+QKxCx=qDc`13|vj=ZUf}l?oWmBFR%d~jhFiGc1_ry(qtv`8fsx)15EXHEhKDIOKJT_QYqI96UAPB3%sx8LdpxE#u11iO_dyGUBme_k3?OuIZt{hRESmLI`edtz(w2iwv@2 zp;p3}CK^q0xNw;JDt&VGimuat}P9}LM1rU(x$ zjwc^xUF)bw7c&2-hAKhZ?*6HuoGeBqh5B5NVcGjn7$W2;*f;89+zB2U>k2qO=g?({im@O6Ng?lAPhu?Pi-_8+&2@xL8yn9Kiye3Ew=4!~LziAE0ToglA{Yc-U97^4D{* zDrq=h6Z=o9QBt|%D-_56Cr?S+C38w{NV1)i?^a`=Lo?*S-ZF9RC2jAgoXLL0ah=R7 zD7szOSE_ba7MeC2)ZAzsrl+6Ji!59=D@po3&21^y^plg9z2}$MDZ;0W?Y|9C1*tdg zFA|ngwgekfgxjOBSbo=e&t6W_Vb`TK-oASZ6U*=2Org`;$vfUh5*kO)`daBm#z@|% zrHnA9wsegIY}R7S8{8Lj?$lOF-gk#=SrHEU*{L=+1#IMipkScjWl*@0t1{H7`by;J zhQjL@&FY5mh2|;m7rcwTpXDwH#r0&;cZyLzTUt|HE7Qy#Rk)yqH;teKCN_)#IYbqs z)bv=|UB=K9DF;{DV=b`oTbEQ*sVbquBpD8y3ivI>7?|;rMV2ZI7rv${rE1%OMTI{Z zYq%;62nN`|=T=p*H~f*+SW3Y+PMHJO?pIHs$Rx;Oe6Qily@e9Y^|2WTvXye-0gE@i z9~pdp0I~}?lLnY915{<3S;S3M+GXxuVR|aH&ZXwyswzao7jj!bRi?>YW@Qnbi>9RV zg}tv+X1C^j>BT`?LK=nj3$ zBU+voncc?wcZ6VI&a?+z>T3-pnuic{Rwd@C{q!1^+5(wIo_NA7AVB9@EgN06%6LVE zBp)gW!G@nL*7D0KJ(Gy$Z^FeT8!`dayJI`e9tjlh67cx*G~*{QC|$uP!Ky@e?P^)Y z5g|+pGSaqpP-(ZzWg(P5g{!W>(F^oC@z;WGRB-#U|MB!Bei_JjS7EzTq?7fC%QaY%V z0|ACxP*JgrLopoIroLMSqGCGKm2U6U(48}ilvI6*(U#zO4h5s}W<>*ntO7Zf%crrf zhOp^Ry2WKcplW&UrEBwEnog^4el_CE)B^^1>a{dy+9Lj!{%B*$ChcKB1hv#x-R(is z8A;u&vDcIe!YpzMnP*^%fqS?#f<|Pa1~@^LQGY8gVz5={TC>fyga*|!rlC`Yz%Us# zouL0&>PUQwLT8@A4s1n^FFj5YY}B|-+BNi~U*kIr$byF=69nrqbrqajL>mD^8K|_? z8yX`OzCePb=BrqB+N2s8A!^9NBk4$IOCbyDBK(dZQBi$1P@6z=rm4S(`)V*W)Hh}j zX7vf3iLJI+Xjb*igZNuV7MUecJ0S&o=n2qhr^9>dD)3*%x?yLxohQ?v)8`!|6d~_2 zeX6*-u0rbWSjZLdAqP^pj=ZF~7;_@y-6-gGsz5_(u8X_)h^RGVRahPnsJwF}MLt%6 zSk-JTPd>g;zHWme9^V*7T1q*8l2tWKy1T84OQ1W?Te)Pow)FRa=}p-gG|QuJqW}Wv z43in25UbDRI{lO!i+%CSl#c;+m2WFLj+X5{t|1bE-&e=cB$deU}HH zN8h;N7-%R$az@&5Ge}~?N4NeLdbazC^d+^OVDe81``s#`Njc>yOfFR%?mD(O3qmlf zAfVPX-AJj5XqraTJfR?8yO;-9%5jI3Z()M*FKv5Xq4fqL{gZDFh4m7(MIX?Fe{0T~ z9z%>g=B%lIcheT(7z6@AG2EPWecS&xnmc(fcxAj@wZa&>2!fYfSAN1k_(kzfqCPK?<(5lbb-hRr@igpKU6 z4adInwEVtf^l+5xbB?Wlf-If?t?L>k^#p0QAKD}j3C4q}Y?;m5l`mbT_{*1_tPI#4 zI9-hiuVuI}ZV`l`gSMBkj>eNTNn-9NR(JjSQbR6I2;))-*DU37omWEnPDbINgNQDYE2`Pa%x>S!?!iRW@}u1fm>oDf6ql zys=cfmp+ej_H)jkR=H`&nT`r?vZ1>8nM`}+}*XBY^jGBUFa=j)kvjQF39`!H4Yk?N@F

    3pu4H)$wj6UF&-vdf%Mh!Z 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 literal 0 HcmV?d00001 diff --git a/clashoo/files/usr/share/clashoo/ruleset/geolocation-!cn.srs b/clashoo/files/usr/share/clashoo/ruleset/geolocation-!cn.srs new file mode 100644 index 0000000000000000000000000000000000000000..17ba01545e04a7e2dfab515078a7678660fc8c17 GIT binary patch literal 166132 zcmV(#K;*wuQd0tW+Pu9FbX&)HC;FSYgUbPUNe>`U0cpk^K#&a5vJ1(wOM9Jk0D&|_ z%PmBcevIq(fwJPtZqi5lxjoK1eLVvRPOd~3_C5wlK2qv`pC9sZ zFph89p``N4h0wNS>HCR*{X=W3et#>b8#~TF5}^OSR?Av{eDLC^`PL)tovi_!LT$?C za@lLWbvb`Oa1vWbPi@Xe>5oE{!UykGpaYVf2jINfx_C-$vF+AR)XZOymOc~mep?`} zf_V-QCfZAHeduT_dDR|4$qzEQ-YDU65Z5D4#gPLfM&f=f^G;`TPl{_vPD`zo3AT4sx3!OHvvw+ zk9@g!Uun>m?uZLDVHXxWraOF<0!jN3hvt<&{@LJKsVy_Pxw+%r*Bi$0aP5w|6|nEUXE_rUZuvdBr}hx2Dh9tFn_-hPzzEQ*f@(3W*gC zR04lt@PZArC&++e-8|7gIL`v11QO9|a~)&+ayP|U@Ne-k!Wl+*s`aI?(x7510@aH~ zJAu<}m|xluXjd_jrL+u6SwprxOhT!P8X)Uo*XW-Tgn$L6*HZ-d?V1-jzzv+yd0mrM z@HLg)UkB8D%V|}j2tiO4frKKX!QK!B-RaV*79_JF^6hu2l0`z!QzYFoM`dNvQjsyF zg$9g;FqHV_zH%d<_7*i;jCC_?($vVT-r_i==w*uIDBiYR`)8u1*Hj^Vg|v&1?VVv# zDk9o)mw9XS#QIk2+rWw%_;Y215~3*cY_QvNMdL&$sH92|svJNQuo6*BVlN1#(FiMp zSUA>peGDv3vaa4RAAi%7xYPyEx<;A|q1OY`9HPFjr7?{dj!^2_bxL~Im4+m)<_PR+ z1eRCc^)cCXc+*@d5K;!6oXu!12uK22z^_7m+5S_%KTc%Sha`Cp#N}(_myNgi ze4#!7sC3H$$yM^A_BqmS%Lj=v@PG8`b?6O$NTA3^x-|YFk)C=Vj8s=6Ci}RIlzns@ zf9gYKr#IFbdLIZ6CTlD&aE-d6MR2*;x+D96GZk0;%G{Qk#IC_M7w8IZax8LJrTtCE z09J>>91tgb9huhmotv)GT$+)y+g4=k*ZMDWs(t=^~^tEH0?YHI+_TBYUnOAD&H>KyG}k{HpVVOzb_!P z+~`&nCLiYIg|V)y72Yy!1{|>v-T-3w1QLYE0Qn?%%#0eBf~!ci(NLPsS^=^bjS5_`KgHyW{J-Hh@r2^iX?g+N!8!h$SXTS_An|ss_c!CrK+8 zshSGmiZu+@6(F-b2jCzi>XnvVhfuN8jzR{)<=`^uzYg*+dW9CQp#w?AGX$!U0vTaB z)}H|3I;mP)L8v6x0dx0x#un`|i4VG=0cSCNM~zI|nF~_N89gH|>e3jCWwD~2n_Pf2 zJlK2?NQt_VxbS4~Th{Q2ks?s{@&es0OL5&md6^)WLoz|!Dz${&#cDVhC5|MFn%G+e_=3WGRB~(+M2s#W^p0HG9Td4_}1)H z%Y|kk#QQQ2`XMnN#N`9d^09h zKvf4g7%{5>%sgDf0g0IvvHKVarpvFC;nppRZn5*m#vSr932435vkNP~qTI5tS3z<1 ziUhFW0eH8>L4v5!Y16d!BF*q=1DGa=&=54Re*f|*#Vj?T zEe+BPQ7#B|TARh}O4a6uP!tq@Dbs`xk%SUPebFS?MkQ-16TI{@gM*sp2Z>$ojXuIi zGYjE8Il}F;j9FB!2rxF|T1dn9>X^__v~|g8V!G|g(p&g64=k*t;p8d!esE-&3~p>N z5FKxAKL0~)!?a*I7o{*x&kLJLijXH-n99<7HE@9mT+C5C!*~?w7CM5tW(|xPA7EEO zFV`!%$=8uHpJxy_1&pgKq$YNzq@_9(TVkHPG@=uttybYH;tRGl+pM;zU&GKRVt8yI zOl@{XH6X6jz5q>Ys7&kTmx0d028u|8{2l^Hvx}=-J}5$mNJYGq&&5 !7vlA;D2WGVUYy-1Hmcw*u z`O7j$cP5tPMje?Xv3CPeDbZkpE6duYN+W4wb^c�~#6NRjibi?o05`1gRd+Zidt1 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Ξ0&bTh!+SkOZ* z6$O&!Z56y?Z@p)k#iy#aSj1+WPK3;rNYkz}6Rf?UIwmcLOV1q>nP+hDJ#+FtnQd=C zJvzQ;LU^5G9deDbSeC`u$XX*%smk|q;!wo)OkmM%7K>xTd?DUvE-<=6c(JJrqi`r}e6tumFL(5f%hNFN?^37Us{&au zOk*{zx9L{Y)_eTflaqpt!GVKlNslEFlB<5xfza26j>_xHJM)av^JiX8X1G&hdGm#6 z1Ki7%X=0Y+og3Uwq*=g4)g7$GNB@!U>4H$f&7j_y%$+OCUn=Tt|DLZn0|PM`KY1@b z0ChYEjtOO&*fB9c+@4`aHe%^pE=Xnvlq{s&1dY&=BoH5*Fs`NMJEO>EP)}}rq2j#v zwb7a(MzM*VYA7bgFTC1`?IexF{p0|iki_1K5AZT292wyC$NN(Eq=IO5HPO@L|C67a!{V7o7d!dSaKIFgY?kCEXsk#&EH4uD)EuHELbNipbAn=+;8IC z$!cmmW<>A=LqdPaB0AV%+(NT}ea&T^QkOMbRT_{>xvd^ah4Fk~{l1I&XFA_x5na;J zWae4z4BZaFZld6vxn(a~#CCT~_|!AC+wCSAJ1Z5hdfxe1oO4_YfrQ zuAnvI=RxLEO*js+_i_>*M+w3k<$;f_AzsTAvr^0+sAVGGd3jF}I6e=<&BV97HDOH- znG`7LM4}^7O3RiU_iJB@CRN+fbqFl)#C?~&u6E&& z69(w`rroh==hm`yX@xa(@#98!?FdI2jp)_$gjA++^i!yz`LC7E{O$q9*>toF4t%r)lDRqfM{^%}J_E)t9c{GQlm2Cn_LZ71^*6?u%q28j>}nOP5Ll3p|N_ap?pt4-h=6?QpN zK89$Qz+hO5GZY#RlH~9kgC@4$A`5?|uTN*oJ3Q^xSj4|UeH-3Pli;g2KBslq^ZNc#rcw_3T zL)j2e5&A$vJqGSPk=zSP{KPI^_OCuL6EPx|O3}UMtw=?YhIh+H=Ehs$<*@w-80mSR zM^UKi%xfD()VdDoCtzAxUk$%ea$J+F&5}hS zYRrvuwWUE;)5Gn2E~A6}E;yn>8XxFOr@6PHexZ|Zwa-A|RA;u+W*HHPwxcPzl|_3T z6N;i(J!rJ$)(>KCr=hAZX`go9OZZ@Gz-?G3+3_&T_TwqUyDfQ3^b;c@Adhcjw4FY% zoM#^TOSgRj$!CkIU>p=_Y1Lj?0%8o08pUx@le29&scoTC(wU!I>#?r7?gbwT?T((l zrO=G38Ou2>n9`1QYJ0JHm;LyH<$6u7OUehdvC?qtrO^Da7tFqYEk}s;)qYsk5~tZ>k|lFLBg{5`MAQf#s?SIe6$9cWYG+=+>ucLOS~~6 zegyl=(nAx-#a~(`H1?`ZQ^+n{YW%{PDN+q+n@ODf(EjU}muA)4on*N1WJ>**xw!B* zZS2gWQ`X95;7`IKjeUoF_dt$oZ!G=iXw`A)iGx~V=*X#P4v5E|XE|WS*5TaQ_<;c(m%}A;EnelQS6F$@QDicD`9wU7j9;&S|jyU4*W3Tnlky07R?0V2#_f~qE%fFa6(@pX) z;f||o>S&c%9-KY)WogAic-6zKiOfVy2w326Em?`mwz(p6$mfMZXY8Uji?x`+XWl@< zq>UKERZMsphoLh}5-h$@aiFuW9xFGXbitTRL}V6T)w}{>^l*ZdEQEN;#8t#?bUlfR%?FK7k6CI#NQ8NH9 z+FH=DTbmWsK(?V3f>2Zj;fpR#yh9VVa@wUgN?v07oG+{$l8;%}O+Re`Ii??-&*&xA z?La|1mZ;sY)!Gic0bwJ7jp!XEHks)&F6To&tB6O)Jr_(+IXGA3aNx=%P9(2|=d-J! z;+oM4`n$|Om-e7Y_j@J?C&EOdukV>Kbe)W2?AqjleEm|3u~_7sTaOK~7NieLJ($H1 z8O$XPp~%g-ALCVv!b+ri;NWbj96*V^VZ&!z>h!VVs8s52AbsyjxYwa680BOBq2_&G zNhj?Lv~uZ^0oYB1l2g6nKmYvt{%saZUeLAA+uUTkU43y)veK83{>&HiDaT>}-5sqH zoj&o0DwbxzCfMdnmiFVqEV(MH<((Qu@KdrL>1S*Nmn!Se%9?9M;Pd|-wwxD1n@w&x z-^zr%4`UZYhIp8Cg`cDU?|pC}MoP0Jb<@fswUY146ng_=)iaTPL#!$GH8f#fs^sQU zT2@CGAU5mpyr#W3P2>^QxuFieQ!V~bBEd7zyev-@@U~>G@X?UR+NF^3yvp<3$6kTGUGAtlc?HXziRkS^m%>%>-AcS9|%?~ z=C--rSu@fsRkmWa^{*EH{cnZE4Je0np7*PHrt~l=_|o^7MUrKiE>6->4LN^&2)y_C z!CGXUesrDrzTzfh^U112CWhCU0rs@|q&c%tkE1%5nT!hSCig}RuUy&k4zmft^~Ob1 zpKD&|$jYr3Di(>s4N<$^Wqf!u*~G?3ZX7<=IVw4-2mXM(a}}CY)tN(c;y~^dovPz# z&UEk^wq2{Jdv!RH$3EGmhlaz;-|v6$>WDnY+ScG&!00mHX8v0&_G^aze+OTT z*2900MX%#l>Jti)bAWiO{q1WW7_r7}lUeYI-sWl7O;hQ-z5hiMslI$K&3AYu7rS_v>I;xCO^ zPJ)xamSW?&+&h+4N45Nalzr`z%*XER?&S!O4Q)US5_Y+-{tc)-&v}17 zr@AMidZIsU3{oaYnWue(EUuD5JTFyVkOe@b2$_9OE+(vWj)NwdW4vzasD>B!PgxE% zCeqiqcXrvdToWm#$pQQVqy8fOA3|agUA4r15KaL{4lpZl|Tj>d|Ud&Pb0@US~7Uux)jx)p+%g(#c=znBl1# za*Z{qX#LD&X#~6DW7_OND#n!~DM}}H_p&&7Ts^7fA_EFZ+#cQ7fgXiX6<%e9sV7U7 z9W@Se3&zu4eb^?G0Ey;WIF%|Je}f8lUHj=VIB3)(2E3jL<=As=Y?ndXgeH8olyMKz z2i-xNj#uhWk!;p*=SE7%C3;tgcWTw_(^uEw6Tu#UBe53Q4Io!bk9f^Bu_^96If_6w zM&p}z6@NH6ZU|m2rc}JU?(|?lIi#{=QzCg*+JP5!AUUZ!(wHE4CQ@)Oh^$g)@+S}# zw|0$emvV*4XT6QJGv9&H7&C1iU#M=I^PW2*lGS2Gx78s!@iRr*gL&HB+x5Zy^#`(I z!sYVrkfMl1TC72i2fRd!J;m0@!p?~!7op?PUB8wyN+|b!?EIELubp(_Y_uMGrWzA> zbxsiiJ3NAafHEGc*GxCz&UQSus=G^Q_DTuD*33V+=sDe{C@l~16R7Ni?9iD)QX4xc zXT(xRDULcs>qK%5;+LxzY~&rrNO8fGn86tH0KhE12+~qGF&H-L+%N2 zCexVlvL!SrXR+OT>5(QV!66uPKKLrbx7EMO88?(4V90X(+gcRP&)^`Y)S)thknQW7 zY}oEr6H`+sXJ?uDv(CF0v6E>q&6vrCf@(W1N>K#a1ik+&;MODM$F_s$I58b)V)I56@GKK+0kPbk_;7Qy`^>g`MYM+NjH^=~9s+*2B`c7tgw%WBJymATw?EDD zF_B(p9$LDG&-QY{IpR{2PRW*>!NF?BI3KKzSt+aXEuG^)T%^u3vP`Yn-^r!qbfxsZOcVjU{sr_UNd`;55-xsy1+4 zJnkUsqauk;M1?i~b|h>y+hl_XVrQw89e4ml{8}VPn8SXpBCR^qbBILFkVkWn1l3^8 z^&T@QSY(&KY5Ou6Sc+LgM@(; zJ1s(c?FCz02D=lQe4enRd$4Pub2?MWHMGa$W@+MhCf3gEN8;GDWhC7FM{H;?M`{Iq z@(5yWbZ=u&Dmmndo<~l0b8Cht;Jy}{cSt4-NQiDGVW$1yklfChm=C(x%02i-8WG>67Yur&GFr$c$JNzqZp-aMI-a5y zXtgifGh_I@#Qx7gj#F;Sbu&-!pKjcoN7ZM}G|nBghb~>qgxSEjc!CK2wg^~+3^ulB|XV=IyqM)c@o3eG4ss-?hM2ZBVYs$uj9;+hFsdw zx}m$ASO(!B?y6`lRSfOtymC;-vFEJL-{PgtK<$Aq?I=6*y#M6kXu0hu=(>D6G*zGF ztlhAg4yU0C;+#VuUIo)L6X4sHGsH!RAUt4UMF;>+7G5ZC%^hZoy{@X zUv30Y=NzhE^h6GLPVh-Y3RGuSmmXfIpMgX7Cj+n?cOaAqgB=ctJ{wc^M(Q_wCnlpCc zq70J`PSU#d+h-D{w(+W@?b+>}f;oiBxV-cGNRN=OSSC_8N@dx+)T#&D9@41w>C%Yv zP)QlNQ)>Re5$Hv$)6_FN^w{&i4IF!y>d zEfbp4WccLUaqp6N2LVS|{Ro0`q!tP?@1x_6Og&_g6$@!Tt2`GRguQ5My;tSVoz5`G zW2W)07^C#BkV!~pGTcL=NFC%sVNa&65^kp6YgeHOHAC*&aJoh% z1qXggPa0Bn5{Hz`)~*EFPu7}RLz~#dP7dbw4Kj#v28;yf9d{*m&CP*c9)I9Q!H!o# zKLjo5+6oW0N>8ZasJ=Hs@OHbvjq+f1^hnD@P>^Z~cu z;KS_+OFmF+rzg4S=fdKYZwHe$Ir-5lTD=wB>JlcuTRxcZtQM9|5dk5x*hESrxlrK8 z3b{$Trxc3WO!At!r@Fd2cgaC!Qp(H2gGWoFT7g#Tb4pwJ3LnX3XhjZi{#V1Yh22mBxm1{<3aXMrFc$eZ4_BdJRt7A1% zmdmYb()k6?>jZ9N+?nKynH;6c*q`-~zX{GtiL=+%D5C@@)7w|+IVf^}TR&yC*aHe; zddc{-lG5R0C;zq1zh@ZtH0SKvf9(&cCn&!jz%~XxCDi&+D_U#cfBbA_w)6#}LP4(k zG4rYgsG8M;Dh|%4^nl2kDfT#N-;9fDpP`gwY3P@WhS{y_VTytF(-~$;P^IdX< zC=Rqaswg9qaf>NaL2q6^C$hg4lu)RMcdSqXaWEz}YXww_`ZlAhj-~6sJo8koVBX(H zdA&Um^wE`6f@?8kB5y(o2h=7t_MYn2s1pCe_aEQB|M1PAFc9fEgrNX;M6+>naPL5i0WG%m87(>ywfW@9*n&2jwP>Q8WX`)Fxha3|5NU8P<|9q z%Rw`T?DCWk)>81vszPiMeAy>5A!b2k6xYj7moNJL*SY6Ex$C#|D}2^RkMT>$%h%8E zXTI{6mB>HcEY|=5ajXowCr>RYc~;JAB~a@(x9|Ea1w$`06dhR|Y%dp&LFGc{C3_&h zQQJsmBCF)*a;4IZ<>Hua+$ovWWtZJoO+#7jw}fF|xaNe?RnqLw{%&OG=q(U76EkWZ zPAy@x&6dX2wZZy_=uyn$ykqmQe4dURp&?rvodbD;`dD13>Zi_w;=TgtJ6 zTG^NzOMpvx!c=0oO8{$WGM#dH+{I?7f)Bhr4bs|`F@TSmPf?|!Fpzz|OUiQwEz3yt zI~V9G0E86*wfOPgQ!mBTH*6EzAQ@r1kgqav*Fm^St{);zB&;1cKtIu!;{{Se{63#j z?QEAz>e7bVwC|cJRi9EVeBsmXGM~}CfCme%sP6EwBBA*Gf0~2*xBGpxLXzO(9MG7O zl|R0}HehQaO5*_`1PtA!jU`{#cM{MSLMxEc zp<5HhvRjRSf_Ki#9)=2ZCVvP_yacefPZ(!@j@xA(@>-fO~Rckncs zJN&bbCaGgDOVrijlOPrdvR9c2!zkB|dY~?c;08HTEQ1g=)`d}LNW}2XGC!QsN@0{w zqZGKtG!e&9gO>t@t!i#qIx0BzsZfjC(>jXwJVbeJkl+yOsb@}wy z2FuI$sW;Mkpujh$)yf+x$T)v&e9#8%u13xhWv_g7cQd$Osg!k}m2o5lM|!|lNyQ^( zexE?6RR#y{IbxF6i?B5(-6>JRhFUfGmQj9x<5QZxB=Kc=DMBGa9K6yxHN9RlYjtKC z4r$VLCX$dRm*AMyv1hkz6S=ceWoG)~A18iqE!wNjbyp}L%vcrhG8TpSE;SsldF$4b zjLy|9k+|5G2&&|5tiH(#dl1Q_O4Pg9>U)WtF;0i1Fe&DM2QxWu?8q5nV0YX-5+v-Q`#CD-N~KyFw1=x|&K!v=EEgo(N`LB4-@LgzvF1>tKNbz=!;iZyXKx{MVTS%&Afd<7k$xtG+yW%I`Owp< z313ZQMJn7tl|r}n9+>1Jyv%3wHC8&PM1-TU?3seru55E6fPGi(z04K%z$$8WZ&T(~ z4Rgl{y=qmtnZ}kVd-!V4&7XDYSf&f&;di1NI1VI-8)HZaLVglEvZ^7dVQ@`zedZO2j(5sWg3C;+rdBW7>X?aTi zG%C_kn$!y?sw_W`h%_T`Lpplm(OHz)@lw-N8xdYbaJL^N*Hell5u3p}r<6O>$Vw?8 zp;($I?y&n0F|Yx zskKj{#n2_O42J{odqGxCnWO8i#9|*QAgw|u?{o`S3er>YEMYW(D?zA@?MT_UzRt6| zm*0**h9J}fUkUYQ_#`JI;}o4^n3R*rD-N36JQRw#&@FUX@=5v7mW-&)P-@~HXy397 zNms0?vcxiRrvw!=5$yb{B}PXNaIm9P>I?(=If5=3RX6Y!6JIh@u;Q=he82XBpOkhU=V- zH{wH|!{;H2!4m}LK#{-nqkY_vW1?FLkbTE6PK)*IJ#pU?+Kon0fA>{9_q*{#n$ZsE zYHIJ5ksH@lx2V+jy?S2$hpu=or~!C_bn#h)hp^>B(flNSzUPEK@?E8RU!PQZIwv#F zL_t(rIFLycyL`%0GgFERcHRtIT^A6Wfd6t zgnI_h3(0eTxq$uZy^w`F!+EFsIyE8OgYjj>>6X?>)(j7!xdfjN-uzJCjm>a<6JuwDOL8X-4HaN4x|LqJ_!l9ka_gH%)<6`Nb5uRpza(?ucg~$ zhr*e0bm$|k@7-0FqYH|2ZPidTZj<-13O`@VJ;FnW06*PvU19_DfY!j-oX|pWjaDks0!t?xo3(ob5 zAWOLNlb_W*gkU=PxXOIk0zVh9T4c&xtg|L95(qu>q;H(&T@cNQyozo&V?=Ss6%l^R>>jEA=+u02;{o@pSnJ+yz>(DVY~n5ck!8UOI0z!^86p zk2a~Wx*5QT=;`?oy|2lbY!jVPWOC3^TMwsEf7QxIv)roneWv2VT%yMVL6!`W^c|BB z{hsMd6L%i8ECEBRxE;@xwDE}Q_df8IWXRrr^1h!BIH%5zpuD5^JNYz#Kw7LlX)mP+ zn|k#rVVUU~Nvf@3&zup$n%(+Ze#vE7r8-yMja_GZi(^X8fSHi$_g{axzO_8SS@Xp9r22k6e>4;*M3&B?&~nN6a%F8(%%lM8Rg$x)6ei|d{xLX^#pf?I zS?5Blx_wn>C+^hCWxO4S>ZH}pw| zsZ+O3@Np)*HbIR{N+^g{S~8?vT3S?s^j^DV89|&ty-@89aDHGXBbspta^XNiNhOda z&#-wr1%C92w+rgN&d@&4tJb9HV@Adr%hHZ4p2)0vKPD4dKo`B|0>Sm*o8sXjZN_8E z=uW&_7TKqO8!&2DXiEiqK`UQDCU$xVYTPZk0LaFtv0BJqCKs4Tvzd(7CX`MN^6-q3 z>LPIEz8o|rZK6irEq(3=YtT7RZh4{u;wthr@yJ{h`K$(CJGi;$hm+p!Nu+>%tS!an zI+6N3f0TW_SIs_m6&8nzjh2PSekXcw@@-9sZCg*7H-#tBwzf`NYgTKG1K#jh+jctF z0g5IRjzB8kdv^<|>64x}XrqES3`h~E%UaLMe3-`NJb>=lr6W!_b8eVfd14pc%Dl}6 zT%(vkns7J<3M9c1ReX?ENa~Y6NWy+i`X#IfmMR~YB@hjvUgDeqTWhXD3EK?b1(i2; zhzaSCFhf~^=qh{K8k|&AMb{fUC?ti0qZMZ^vt|zD*v*v@2%G98qGDOQ59qxs^FzRs z*nM~|@{#m*rkQtuF4scdHe>N$<=VYx@6)N?r++{H^AXr2`NN0jU>#gjbm&?W=)@m0 zD%!c^YI#!duB6|pFAv=#5{2-PD$k&FPh#Z@;_4RTb8Q-=`zQ~6d_d{NuUv@4wXml| zLz>hxgXFNus|;$B1D43Zxqsj+{sTdN(#Ea)Hc;7sor+)fTuOp4w1KTt&wXEQcIF3L z@E&mNmiGCEjG@$}AI6+)VDp8j^%8_<^sOZ-=e21s_(DjNx6cUWz2@*x2kRGn`}YN8 zstWq>)YejV?}Kuc(!v(gMn42TT%!{Y`ODb<7@_I6&mTX=b!Q)vkx%kPW9aZd|NN)x zw?F*nuTS^)pYrX`KZy?B|Nik0=owP!gBZB_jJBx-Col(>(|)l7=CD8On22fZpKVeV z*ebR;J5xqk)jZ#iJFfjb)I*R>bM|fmy;Vh0YqA50CRDmW-E0)wCs+m{C+c3bf7Dtx z-@x~VZ6rFp5_+<`!F%Vg8r1U2&|-n4qq4%e8iO|VNkuL0L~ zGK!mt&EWvoYm{U4PM0P3dc99LuobYln$Zs0-Rjs#Gs#xjT0s^ZGfJ-Nq9PrB#y0_U z(-+<=Qs823lcBdzjsxwOR|vu9rw5WcMIVfMC-^lHN~+b8vsJvc-xniZ5xzr%7kws3 zr5h~<_|+3lNBZlV-Z!pGIiHPGV!O?~w>Yb+f=8JY{}$bQzfI>=)e~goqVRs>Ql^AT z{;+Rb+sdzYZ@<;M>yG4nowLGGTCTb1*wQ4ob;(G*wQuhg)L%ykF8N9kHFYh3JbQM!3`Y={e4g`8+04?cDohLme?mmY7;XdrRKm6MqBMFYkqW zJ>Lxx{>#1U>$Uy4;oC{hAL;A0@qH;G9XG9E+_&L9`q)6RMc*c)#n~>1ml9(vmwmu) zZS&FJ<_}0s#LUs*7Wt%T5r}g!#PF~o4;+!x(fRg|W~xgGWiEk!CskYKX5V~09ywqA z&1G!bPj!E>Po%C4JBMf2ol z|JZz-svEE6#FMagL1;-ZQf>$pa;G^pTru~!CJxdjgC`!&W6o0Jr;w;lJenpUbl^rK z!-YCyepfWl#U>=*(Y)d{SNmT5qu*iuY)fReSZ@!GltMa^9@eBY6HykVl0U%sFolNK zE5dv4-mgpkzxVuKeo_DTi~r_L>iy$mxqg{)eTH8SKJSiuum0_UoiXvDg^c7YkNIB? z4}3B=`7iIm_?3z@l{w_Kpd?KrVt*!GhoGd5i_BXF*xB=RNSM`q0(L5jKCd4uine*2$;Y;Ojfa}i8( zXh+K>CmzM9?I^2{GSEbzTvrqw7*B`&Mmezey*E+v>K?*=Sfg$T89!+*v@pa}Ln!|y zsomVZbqcg>XP1!orKdz>o8uXW*XTewQLvkWGh6;=k;_QrwYE6ZAqg3r_2M0FrNgnK z<<1+4Q7f@iudCrOdE?;G>G4B^!w>?#)wsAw01K)j4CjO6L@lf)&S?aBwRCxgC_MXYkT@SDQXEixe~8_gL(UMApH#Z`$c=YIF8h__Gge!xvK;|TKyd+AY;P z0vb&yJ%F0nU5I=o#m=rd2g578nl4d?LFPPcgHT3TT4;jQ-I5oqGjgth4UMUuxM{VB zc1(&wlfCT`>StzHM}S6itTjvB;g|eBH%RQ{($O;lGn?ngiRY{UeHbDeiDe7B?=3aF zH1~oQkf@5}L|m~SO$5ua)V|eKuV&w5rcG}^rNqL>>&%}TPqYeD=1JTwowPja^nL^lz&OzCg9E!q(fIBn2H(GYMz*UTYQ~YT&lKF*QGX^dFpt z)YN*_hig4r0YyqkS(kh^Q*QB@!2s1Fisdn6F7-*(g$QkVm@b@T4`HlE6`w9FQ|G01 zDg25$vj)+*01|e*mdc3IoN95RiYg$QNO@0iwKoTec7nrz!M@;#p_COEo-~4;+r$DS zq~P{R-XHPydk*00=lYpjCzE}!ZHyoh4K>zlnE>g`zRRv*dpQSeVeLS(6Lp9L+VZFy z@Oca4XOL0%9Ybe?m`fc&IiqV%Rwg}xMG~l| z97-f5EV2od8%(TYU-i7?FDF8K+Epe%sF>{bU!j9~yae_t0ocs9PvlB;bvFED%th0< z)ZS>{Ly=JBL;7)5FteWocRrDpQL0~lm^hGn38`Ffxv;fUlS{FXNxD%_0;%RwmD9aT z9_QVr!i>-+=IRE@HW%Sea#QJEH8O3xf1!xb&+cKmPMdo0_r{1+10CxGxS{oasl6E zMdxCU(3zBEfUni(Hfqq6d}$e^w=8|Jw9M)U{79a1w}Kb0<7l+cX+$I##Jf@0PQ)%{ z=AN`BPlD^iI8o+aXmAdPu*5WcU_*J${4#OdYLrZOd$iAoVrOR_b)sQ@x!5$vuhkNL zW7vx-T$mtWOHl0QIWU)0=8DXd&cm@#JVw_Zzzcr2CLjo#z?RIck!H*MqdUIP{E%=3 z=Qu$qvA41gmpu=h^jp57M9}xu(41Rv=Y$BxY^WAS9ayE?)Lp-{b7Dg4q>L|n@2-3F zSMKd4X{S0EVy!u3xB=gZiBDoC87@d+>s*4=Rm%Qj#``#8&W-U}FPW%9ilAxSSGQQM zAfFKHMc(+KP-_aQ-MvvE&gXmQym{yh6~akpX3Dl26nm#jv$slqUWiXunwR2A!6_BE z6SbV}rb7VhCKol%i7worg3to2uegfPfW(&V91thT{PAxaN5ylmBK&UcL`r;G;WHFB zf0|E z#+fN$4kba-@7mCKv;srGr?4_7o0;<#C!$((flA*Fuznx!L$M8fC|CD8JO zA04hc$J|ZVp>{zqG`~|Mq{@>$$5lrbu?&k{WVDnNGEOjoWv(8Y=m22v=5H?!N(lp7 zoVanx>69Iki`=;Q)cY+@e|oF6nk@k#IMA`5|VjSYU{OE(eyVI`j__sbU(o=~kz z;jOAYM{hA?PL@(n$t*P zhO`8!3EzPcaq9+JUUL%LQl`Q3^erbqzg;T($NY+tFQ{^|?x@kjgU+meaD3q(Y+m$; z-?yI|{asca`Me3goCl04CTd@90;Rr;ZP5h1f5OKw;dA@G_d^-~Y_Dy*%C?cezx(0~ zaVl}0>)T#;>}Y!$5?9sK2Mw?gS-yINfqW-8p5fbLQ00%DM3A#@SWc?CT0{@WKEcDm z7s|Oz9f)xYeb?mR-d_t2cJ1?D!#et~;)Cwk->3 zUZ>$e?K1`9pMQ>5;vI3}>RNE_0Sg4}2Ow!_eTY-$!YXpQhVW5qspRrRB5iZb(Bz)` z-vh#R(w=5~{V`FU^{T6sMZ)Br*VWqU@L&D-GhHne`jtN(w7jol!U=X=zu*vI2Mu~X zG-1~X%JYHTtE-qhzNLxz7PKWyI2_V3uOKi=YrUzV{_^eJvf`a{#YaHWjyVa5 zr}}Vwusieck#z+IcKc$$um>6ekk0Ai~<<@wN9zzuA^|&8mmwzB4;=OF&tu zS9lM4DHCjC>Sd^`(lk7z?*w zlP)$&=xvGCg5S=yAXjHzipO*GlukiAnuOK+G-;p%Lk67t5-)xd1c$53l3G{~V_w2Y zl2WFwC@<}OLdq95%$@az}PwlqEmCw@MAm zE^)VZ!)P>-Jb#^F;ej1n4UmkCz0>ML^#S8oBDu#eMdu~4oae>X9S1T}nqh(ck*nn6 zIId-|ts%2vbx{)BFy{*umK*HVz`F>jKLP>xFuYmfyoI<#~mJHA;V(;QAiZF99-goFsdV^ERGqp%R8m)NeGWX?^a6-ad%|yqH z>1e6Tghxqh>*#9q)Cmt?>ufhZ1TM~fCt{^26kqHTeB-b8=BU>h)q5Ujr3w7D$p}gG z?*39cX2$9ib|0e>SDplzafO1#Q#-YcG=`_U@GF+1Ww5JFvJ0La{ES1zHSt{`$^D5E-y_}4RGvR_1yoov1?+z#x!3MxS!+FFlk`l;9$(9&a>a#o9NykWE;Fm*OOb~n z^Ie@s+7nC;H!&xb!?aNopD6YDRL&!{W)#leXxS*v*n)iTK-W~aP!5cj>}5%-TJi{? zZsqQtWu24UY5qyNCe#1HMc;Pf4$tI+pmfjJdm>Cw99Vkuef^D!P6@S!Ls9RYxdPmO z%kJa|F=gqMv@&Qi4bh^Ib1|*jm9=*wBet+@In?Y;Sm^LVBb!oKXfCZ%$#KY}OGk9L zo4=6e8ht2S#EsB-HJ*wlU7WT{UjSL%M1asQIMg6nm0W3A@1u&>ph!+iZdnuB*VUwU z#O)4PsNh&824x+9FyVU0BRfV55e?5A#)2<;?>4@*iK)VN6nCy>ZZgXmB2QSm>PhJ%CeTlX0qrSI&%OCJPy^cmV3cP@i z8^$2#_*w2@3y)X!G6Bb(eJ)}=27wKI{<%>$x9WNkzfQjw8ORCawC0n}OkslBrQ6-m z_l*K51dKevpCfUw;ssc5fE+8 zNc25r^y1;Y9SHEf)r0+)qIuT<&AU&Wxe?c$4l}Z?ukPj0U}fUUf){?w=UQjFhDhmz zst=SOn_K}2Cv-^$gP7K6$c$CEq!b`ZcGB+>y+$TH^zKnQX8sFI|n2sFegk z35virf0qyODcI9e1^mvr(IH$CNJgQxEAP>pK-)@jR3mduR}U*?73$|5l*_&grAfy# znGG}2FmLt!`JazMrq@pW>&ivF)H<%E;q34iS}JXca9J83`Pm)8Mdvn$);d<-9pi9m zkA}RR6XmSUtwpaLA$#XUPsq5BoDx2My3tNsF0%d7)vUPXgR754RjGGB;dPmiYR2*b znl!h9DCe|)#&fcz)fE+;r?33(yu`nCnag81wcKfKW%USy+jN7i-@QmmSZ4+`L7=6st;tePczfgC= zk_!@EwH$qO74cIw!2jB8`&*q0b9Q^D+A&E0oJ#?x!^HH-g^5MDZ`IY!|J>@|7WH;Y z>1xs^0!qhgsdHuImZI}o+gtZjF|f1DnLScxItxgc4Y43v0Pe>o{@+&zeJ}k;LUji% zq47S)GP$SjYHgA+y7Ovp^=!=$eVgONsuRBAP{Kxa)6Cz9T!jnD-FFb`wD1ogit%T)(_bdFZ3%I0jaMV-tM@A zS-bFHvS*OP?tlH-P%n7Reu0<8NKHF*<6bv*)>Q3^ zD=*YW*wDxqC4zgcsX3$Ydycj`*W)@HXZPWx>|L2J^FQ_rx!04$aiEO%ZgLaPS8w7W zV~p^A8T}vM`~Q9a-@Nhhd-gjoN{up-tv>Fhu6KdcjPDUt#dnXlRk--F>OdLG_jBHC zt{fqLhK5^~MDX!GcQ($!O^n0f_B=4Ejip*}mBas|?M=EQ*>Q9+=^U-F&_;SaJoW2t zNmo+lsiL27k1+rm6=OovYy1rWd+hnh7lQ6jp9nHe?7b*8v2FpTLa8X8 z!OiNWr|a)MER#~ym}{j#>Y!-mW6i<$&k!SIJ(rnMX-d!vSSVNqM0=*_=Fp~3k4wWI zKte!GItMVlFtp7=^BRG`uE9d3HQ2$5)U4HAR#AqFgP*zN+#A8vf!gFQ(Ls*$Fj>cl zqgO28(<}6k^>9hRo@742>;TR~!KDD3V5uQHO1QzORg;l&ts$K#s=JgA#WNg07Y>l7 zgq4sAt&p*)?m~l+$w4!#Nh@vp*mEBMI9H3EtM~%D^fEhnZRTq38Ow&g#!vvJ9@&UX zuGafR191P&yEYuBg{Ouk_nu?x;#DYW1@IOQfOy*o(mT_$5j#LBeui;ODdCuNC0KH8 zeY?b?Ktmjnr9qT2D|iZVEKX~NG-FLc$}l;zFz&&}#4KmR5d|;t=mFNid#}7&k^{zl zE(IKU9~wMbl1(sV@Xjj1Zkw%W1B9J0U{eJ+`@#@3c~2^20Wr1PktMjjVN#|+K&eQ9 zX@Y47-mr(x7FvlsLa&UP0)f`zLj+P;sc-=ArZd)auszlF?#jyx4goU3q8UBOl*cYa z#7bb8Tqz}6Mj(_%(b+d+BaLe%kfk)u13fdCCUHZY8yww&mhRIC4uGd~2?#8338E@Z zs4@`7cF$wQF$brYDzhHIodHr4sWB@c4T(L?vx&nt0Z_ml%uc-8;K>HERZu5?DUZ~B zDT5z!ut1(rb}_ii5GYah{@jy;C5Q?u*s(@z%)T;c!NIWrPtQ7Nv^ewJ1V`x+=(2b~ z5u5nTti?&nHd}{OV4R>fsWY#gj}w6UW(V%`G&%GT+5j|TC`}3C2EEoOgJO?i2MU4H z)bxbcK#dg+D`8rEa?m};p~0l0v*TX!NP!gNdQ%94C@9YW5;1|xIFLlAGzZSoW`CaB z9i*WG1YG@)?77D)CQe$C2dqdVz;tRxCe_rmg%@Ee^DFMjLFnlrh7x)*lLk+00xz+R zX`GBPH2CA3=ZB*bBBk5}W-o#UOB8`ea0@rPpVu}&H*l6Hi?!3Fnkl6PivrZ#P+G&v zy5kIUQ}+E^T&$3i%wXG08O5DPz(_-3f&-p+>8qy+LTF0Y@wBT#Dv=sxo8<$EwELn$ zRP7jM;>l4K0%dR{-Oz{qQlS-kbi&mY43HX_l2wVw&aDsNEqb0Hy^f(Hs#0xQ-R#&> zE}C`=Dye4$ynM)qUIt15#x*FE3VEB+CK7PFlK7nvNT~f6A&(#;LJb!KT0m)%uR6dc zba8e)4R_d@0LWsmYdS#929wm(f@|1#Z?i~>$8?%PudpB>>bFh2TZIJE(pM@bEmWHM z=D~Vr+05|TOUc+~Qy!Euyi&{-3x#AoaO)*eh@j{y%aS8TFcQer)rDXZk2z~X`qX2O zls)!99Q@AO(AQByqQoIHYH4PTBYI5^!Htr`{e|>oMEWQEG!>v`I-FxqjV>t>mka}1 zI22r=nmo(-_L4s8y^UO9i7%fCB<-u^~zy7>LhMnr3tuh^q?sN?9Q)zGRyl zF*LIyCKD)}iq@`3CFv^9@sq@Hyop;)>-qkePWtlcJ}v9KzJ5C8vW{gN!}_x1=@`^w z*`C7ff-r@=_%Y=$NSsm+QxLJFtb?M(|VXd_?S}P!P zvd((~pOXdOosqyfR0a!RTLn;I3lvWV)ga9wG z#+R2~4jF2X6NYPKHL%Hr%y!)3<0)?I5uXfzX9%Td`Re&WaE=X34%KVVW4p{RO$##6 zG|$%}e~s=JKAi(G6c2-S#r7m8Aj$W#TF+cW#L27|bq{!B+-9CEKA|194zYnFWD&@4 zsi6l|Gw=wotOk6K3W+MRg2vJpo?+$y7MR#4;i%JGVA9rWCtj?tR(;zcv3*)SKAI+N zQv=?qa)a`|C(NZp1Fb`^0mOy`5{oU#o?)l{1)c>A_Vj0~CS0BLv;*Bu3gVtI62v*p z{ZyaaG(l)qZvXT}-Elg5?=Pt`jr))6^0)oJWv4@Af#BDOP7~n>R$?%%XWG=T4Lw;r zNXV%PS~%<^$$*K`^UV@G>tA+t{D?3;AXjgO0ChnFhlBRF#C zHr|1@_?UKSaV+}0f?gTL4u2`*<0LszAa6Gw57Ml}*rvaS90W{AtIStk$2!f6fdty3z z2A%564OV+isXAFk?LwS2C#d#M$q^uV0#*| zo=Tu$0ILP7?pdcyB0Rtx0wSbd7nnhMjjDh>#2pfZF%A%G8U}2d?p)oN@*+$!X9~=- zj^MDAW_`^~CI>6PGvbUPY+2B*mu72jZw0MxjAIAEK^|a9JAieB4g&b8%+5t}-D$JfWHAQkvO@`b_ZI11 z8f6~AIH(CpMPxh;E*nQDw}dea*#Yr#W_l9-8<+v`6|Oj_QJt^<_dFLxlpbnsN~WaRmdY@4CEzn;o1%BTO*Gb7c${ zzuPGmDKo`3p4Rnz&QYCoH!zHC2KB^&F!ZYUYG?2m2QLtyI-EmlD8$yD6=}DY3X%sc zxi6fx>BEBy`v5&7s>gAHWrf!! zM1XfP1$&;rJhk}^7G{l_(sX#4nNphaXi&+RvuQS*2~>j97ka_$*mY@P@v>K~e$ zb!9q71D$~)_so*HnC>q%(d2+k6XycF=^A>q<~(r5qXoMLHd&V~Z8f2Am{|_V+?z2rfg&c2bMW`20sp@21^3v6+jhYv&LR_+%-YAQDBV+ea z3JG|lA@9w`=t-v>!wfP&w9|fzGc+s&Aqf=OBVuA%%$i2+^{0XWIMPaVg5$;F%|434 z2npO^Lo?2yXz>9w`EJ#Ly@Xam|0vW8lB5a9?tmO^cVTl)x32)A1$x-$3NXWf$%kxA z&ln0Nf-$0r!D9*Qxhf~)%Q__}7IsDwh%WB^J4#6dmEZz6UvmuLtOBqtT~oToD%K+O z6=sixEAmhT&^hU$thhAG9dapY97j!!eZtj}I5)+K&20CtBSd%cBiGc7JK+lC^I!!p zzS9?%!Q_1bqN!({q&720UBspCtJ{mwTOkK+ddvcF1MJ#}m%V{N3$nXec(#dwSAjCs zy*=)=y~Wg*@sf_xpb-S5EFMyi5(jv(uCy^2!LKUj$#>NVbpMpfTt;wuCSgs2AX5u4(#egE>vGfA$mb~U}`gi{!Nue(|>EI!h zCC2Q>l<+Vp5o#)-R}=?qw_89!Yk)jlO56<&_vFl$dJ2HCo+&3FEp874&SkIx?If_I z0TR~a0eYcc+qkE_(+o|QWIJGA*c0ENQoNML4scFRqJhxuL>l|I3>OAhYOQ$tcwe2E z(?eyN3{{uV-_-(a$wPtc2^B{vo}p)jk%AUPx+i#32D430V9&SZy=q*uuEw<|1FZX)wB&oYH za)C%V7V1$|hz+|91bZwE$yEb!ce!T-ToSGk#sWJk`?jq%u#l(O(C8E#_+~d@$WA6d z7boLD60M)aPDw_rDG^5Ni#c_1#eNpy>)+SS&WWs8T8W|-Oetg^$G~#u6;bS=nX6%f zp?g#?y9K~_Di2SBeJ#rHNJ9}cz87`uf%%#GYJbN!GVcx|;&^*|_OHUXO3~QnyAeuaiBa4cVbe=b$hOK)F${ly>lE4g`q`ofkn9GY1 z+G>xy5j8lL`Y6VeCQ6VQB-NAQ8oEgJr~g0TvPiGe;xh7jk2>9O>ZH_c%2> zD=?Qfqo@NB13j}rgT&#I?151Px((*B6hky(<3U(~vGlx|Kw}I*Aw`$%>;O3tpsUSd zb=3QuAP$7i0dRLcn40BuCQ%S4!P!Zo1$>prrvdhKb`~3k05XBVFRlQ=WMhN#6`hFP zM0j(~&T-mcr0#m(lx-t#2xs6_1hLV_%>l%#huoDBC9T~>r=-2%1?2#;uVDtIUAn9z zpx8iVg#|3e20LbG8b+b|X4Wv9nyeO|f>3gbn0uIkItN=*1PrM2p5_J)3W_CJQTw7I zbq6j7kkc840!}hu0<5L!BV_<8Fe9aAv#+>>h?)z-5lk|NLovpf$krHd7AILy19<4` zyqsX_r7Xe>P=nS$0A+R8b)~c&6=#^DtW8s)NzRJ~Jfi}xsR_4$J7s3v3E;Sc%K8b15e=Ddl-t%rNOzfYKj~|AvSFl19~q026*TNF73<{p4ZrO zouC_|5{R!zq@MDsaSAobJOxox$Wh6eY)B}c*)iK!%l!WLZJV`M&85+~HaZFQv?CD- z7RqP<6cICpb+V67MAoXBS%FMX@3A%FK_p)fC<)+*KX0#hp47=iLm1GEkD;LzdRdR3 z_+0FbKaE6Zd%N9my1hF&@vrMV4CjZ}5^tWLbQ?;PJ3F1W@;Dt|Usb0R5Q;XMgs@T? z;|$|Xq+U0OHK5_(xsVG8R?$#5ayR2fV|t29IKd_eB78h9yfvVJB$Si_MOfEnwbh+U zyG&F78{3a;U;=Y|ipKO$NYR*h4aMGbcAa%kU1~7K9FYJ65H`$MDd71Gwy0`Pp;@|R z7z2|5eD0PZt9>N@LU};-R?0{aKxty;_44~$_vY^p{`)(!Iw@eos-X;2)g2IM?rvA= z$f`pGXBilTo z;cNk?Cd4NwLOriAB$xs=P<$oKBXkowQJt zvyq?!2Q})D^3ssNsFRYAXaY>uWt%mi{Ja%Po?=`~@l2i_I!|+vBT(?C`4jIo<@tGd z-X348_`8%R#^>ny`P1|B{e66J<>q-H;&b)!k?)>Y#G5Fhd6-?J0$GX*oZ-YX^hN82 zLwTqw-7`)d^R>d6909o(ukWQX8fLX6a<7kFh6(c}Jf{o{(HdtqV{VW)V>VC`N&X1f zbgz0#)|ITbarU}`m+G1cAkYiu@h(Kp506Jq$40$Ht8TB-E+lhig+JH(TsNG2i&N!gA)`891KZq7)IQIw`=qYhb z&#PhF3~@knFt1b>(h)Rbkr-wmkT!AAVXzSB;uw$?Si>}eNpp{;fI0`Xg-Q|;cPZyi zghenEo9MMo^q_Ty(rj^!JyaMyy4I;_aK=$QP6Q0+jr+nYjy?Io+V{mayGt&0!(8Cg zGcFf`MCZ~>N}MTMMBb%Wh?x7@r3J{#7JMobH=)`PZ_!@X1d)ojXn97|zAP>}&hsp8 zA}Wh0;VnLN2kmToh1tA7btQoc+NP)yJ3uY%Ay(idDyio)vaWzanKM#A0>a~50FM!7 zH3JC?U}^9R3Ty(Fj{vhwa4vxWGd8lhIvL}$sgrNw!w8!!WMXtZIIVvBr7hU%Jt6}# zjmI`+6w`_^qJUu=z1$@(g;=~8FKd(`1~4;Jkl*Ocyv(OiPhlU& zPtg|_jxXEuvMz~UPB)w5#~021@nNbZWArQe=lk>NVLF9zx{226fxsx!5vE@2E;l8z z_V4Rk1Nb6wshf#0PQbpGFL^YMn1No#W)bGppx-9Z7>MSHdq6}5hz^_8Ja>0bk3BZ< z`FW3s1)Ajx2!X+f*(?~qI-@cn{M(Zc=kAl(IBU2Ed`(KuT8vX07<4sOmRwbKWSARSO zSYtEdoTP@Dk*xPVip>d%=4KN**FEdk!VZLNulU^~9>Q4;`EWQ0GP75a%toVjUoN~j zLlWm{tps)+FhlAIdqIWR_Rsq++NQ3duUMmH;5@`Ma(nUR+14I%)twhc-B&*=XZ79~ zFIkPUkWe@W6{e?utHp@av&gimvP82rOa9OJU=XTQ1qCV1?r zeK!fVFXCpjwO4V67l_-ofj{*GeAU1l)p5rv4&ZS!aWlrBwhdDQPf%Za3C5=fY^clY?W^4Q zWB|yca7Y0Jgsnv&=d?Cml&~@-9&)JTIHsEVhs?ef9Ef|WjPBTAhqVNE`~(Te9FiZP zTCm7_J2wcO;MfB*vcU#aC>E-@r$6qg!}_-cFTrUS+}AZ#ixRyF!!T49F`_#X9?()H z2*xFAq57b6M(mYhZRiC-EI1F)%=jeUUi{8xcY;uNFXV}&7?YAG@q;967V=q14WjsY z8RntaTZw5#`@-EzK`4=|yH8{NNeW9NlP6r_C&X2@5Q*{2GN|3(B0l9FLtt}NZ83!gcuFbC6M8wEwDEbpjuN73Ly`vE>Ley6n z8X!2GP#TH|h(}P%arTnMFPIjba9#$V9vmx2HDoAzrA45b7Kb*oBB_sLgoPIuU`;UB zpSQ%GopYoblX})!7fWglM*ko9&2s}lAaK0IO~}?o=muLnf-QLhL~&q@g0*1Nw#5s& zrJhf%VD|-eX`&Uw970l?DW&J6FXm8sU3fxwF~Qmd?O&5Z12WZ81!&V4qXG@CreP3m z@Gdp^980qqk%oqige*40Cq#e&=$5$5Mt7c#;biCX$_X9D1QqDa8NphO;EqS2Qc6z) zS){OS`o)l(MKJk6-%=O7k$%F z%|gf`x#QWbFN1+oFs6%5fX$;npFzd$vmp<2t>Q{bX&4{eVOj{Cw=gkt6GXUozoc7- z%1MXr=C<#dOHNh>*9`AVhMq&SV|bT>j*8DEQ!bA^djn#c0BTe2uIH*#%V|YFEykI! zc)V~1>^d@8TvWZ?`rx$gV`H%F-29g@69rkUDc^KcL}L!o4ZNK(xvKP{{P!2uFt z10V=~^;8TQaVCzDguO>=aBVoeDSQ&7^7B?_(okIV>uTLJ1XGsSR|87S6K$JCPZ-dm z4|wj1@%bEkG1^E^_n3OQc=ChfVzJQRJr*%(&>1C=F<8t%xhaz&_l$6}&9ca1P&l#+ z9&69q6O%+}_@~65H}5iH(zK|Bv58I-Y3o7~=(cc=*yNOzYDvWnkgX(}$ZLp7$Kw-l16B?dJqH7iyD?4y}W0fH=ClQd69h`ectxPF%pOCI7s| zY;We6Z6th1GN#NfP4(_Mu;a#MUw@SFZj7dl-IE&Rsr>x@%NsJnPdZ3N%Xbx$to1Z61R<$JNTt+lSlw`!frqJ0X|KI&T|Lxy@`19MB z!^h)oApU%B9)JCEu=Vxzm;Z7-{`4GFImzc6^Xb>Woc{Xd;8OVIKYeZeOvCu=m&42h zeLJel=cBp*^~ZC+-62K##axb_ZccX}ZhO<)-Q}N$%Ri6(pO0S-+y44~kK1qeU{`4ep zT-k2iTidn&aA|(>V`{JWXg*!v@PD~9d^)=ELx0#?zp(Fq{8K;WAKy>OsYLvIG>`8+ z`p@6DTpsx4AesvOc+ur0Z~yw`5a_)t*Op<~_G?%E&+i+)96neQeRCL&p~knd zq?+F{7Tw?ST;)vxZ3dG0Sm{mIw>6dX$M3pxd54>CwEOx{q4oIrXdd2q&pfI4NiDd&D_f5PSb_xrdBzhgJ|%fsb3a>ftG%GeQ7kuCLVswZ8|dTvY{2!|zjM4U?=;1Ab@A)rlz;i3F2^m# zo#Qj(_XB;s#!j#M`Td$U3$OjPY>EAJ{QO{^e(eMF%X`Dj?SHo)E}eU8oj<+L;VZrE zGe`b5yq(_v*R^TiYxwZ__WtS9uWzT%r`!97ws-sa_O3~Xe#`qdcP>)mczgHo*k;%d z<7xN(2hMGR;$JRJ4wvJHo6o2Bu66O!F8!ac?W46HzV*Cy;^yNIa>GsaRW8hO^T)5< zztYPkLF}CV<>2;I-|6L39crmxDeT_w_I<-&PJjK8%0AVdqw011!&i~%E6$?m&R-5+ zx$SqD>*lAk*-a4%8*BdF1y}kFcE61I^}&sP|3*`jwpTtH_;{4?p*Q^DeMJ7#d)uIU zSTOUK!{HC_?>Efy@}p9@viFdRukQR!0RJFlM@%Dm#`Kl*-y-Q-D&xmr{`GoF65%}5 z`O0Ruf4uwag|ydsHC7(h+s{XHdtu+}_)YiD;rE*Bdipd4ir2HhQ%2Ky7`q_<;og&c zlO+p(ooCOuJU%|QKD#$vuCn$jpq}md|4-jM+wbM%oaXlqJo|lrpPu3CNIY{Dy1e-D zkM9EI{YgRf%i#m&{5JDKttSiTk6)i8y8JjK*M_qn=5Gz{ZLg$0b4a*+_}0O%o&Vpj zC**U*I5tg`qVEcbG(%J>Pt%Ij$ozGsep&>HG681Jd|t=6L@2E(qr8rn*(S z@bh18{&@e_kJq_=rE)+#K6UB#9gF_w_covEOZ`EGy*K$Toqk~KfBd28n?iK&)DIl^ zNB!{2w}$oxgMXXT{FdVUCRW}gy)EvmJ_xLsuH383JHbQviqX2Rym>#ozJ57;xD32%?nD}i%WOt1UzG0v61FE3U; zypyoCwaN5%?`_h#<@QGk7W)&T_`CO(eY$d2AH*wjHe3Jpu1yGGe5=x?r2hsw!O3V=|{{VyBpp$)pue| z_GkBw`P$+C^>SDlqvdxA(6#2nZxyn>bfNmgxLgNWb)3fU+rDEFRsBJ*yd7`emGR%d zpYi$lZ361@&T_h5A9%Unzq}t6vcJc0SJ_zW#UMET2K8PEuukfyn{PVf{cs4k&HlLm zQE;t$S3j3dMAG-JZTJ;vHRbsa??<=&M;qo!pKaXte`^wKZA*2p z??~WEti6=y-+T7HkM4U`yuRTpekIDyAHTifb?UuNpFZDobRd<6B%g^Yyi} z(8KRYlZ@>6IT>kH;Kf4Ka%xX~f=o<3O zaxsU#{NH~t{k(RpTB-KS0bgsOD}4AfWp*P5664bv=Y;-?|8l@H2IN=rm+}3FKhx^` z#Ww!KmqSeJ_4zBTAte&tfoA{$1bn{SkRoLg zmJ$#`4OT;Awbk7<-PM1p8r@x(=~iS9X>yOtI2SIDP!v7iJ1#>gM0E!AlQp0W9@o@H z(MdWb*(5t)0-DlB&%Pv}smOXqIa!~id({JSB}K9G?q%L1Fw;|A_5JyMzwh@om{GFI zA8k?oTV8!X_9^pIR{Z$2?0`zAUzp`=PpC8q~(4zmpzHA;<$jLWb-b(Y4&*qORxr|cC?0qKp zBm3u0XY-13MNu-XR<2T!Zp!RsGg~ss4&|Agl2tNF&Q$u8%8oSOdlcn}^6AHCWd9-$ zA44IZQyfK6cJw~&e^Dv*!kLkw?o*V!l1~%6MLC^Ua-Om~uP9rUY(akW6OiiLyrks* z3-=33>!-x+zY_NR<4vwezbX>TeLqnlg}<9rGEc}#{bIPArWj*g&PwsB@ zcFet#*GkVsu%*Yy|IkaQVNp=MLCmKwkyx1cegT1CDVHI@ttQ1z0EVq z`{X%=TrS&}&nwDH@`P=Q()XOA9Ib41mCUny3QFd!orm*%iqb0lgps+QgxTJ#1WHAD zPRTmQ6=l3vru&a5pX+PgQIxloY)erx6{RmjwhguZiVRq5sP*r6DMyq$`9h`8dJ?6~ zlTf}d+e%}QOAl=+S9f9g;n?|i(slg5;2xz<+4)SN=lYKseXzHQw6;%CviV%P0Z?{t zF3a>OKmUhm=(E{pQz!G4p0hHn&;C>*`Y$o@Oe?bqq-^OOkhc1Mcs<{z6dspH=6{mM zC*cQr}XZ=~I*^)?QQkCeycD`i>|{t5wh)q zJX84DPv24gfl|(;wVhG7D$1_n_*7mxQpqik1xYfED!?wdzE*2|KKB^KE3Z~PRado_OJBq=u`e`OHnSCS}zaon%I8l z{I)&YOS!N3eOqPWXDYj1->vj1TNEY#;`PFJls@f@lDnACw%(&`|Dy70<@5QLqU_DI z@=B$3Md>T#B)up~Hg{2PNzbk*%F{=8Da!8mD~ckv?Nq+CO-VttMb^+eMfsMZ+-YSC zJC(wRWkNCq<#OwH4rG+R9fkb1^Gf#Ou|hVRtrVV7lr7E7bA6+mb&<&^Z*AMtk_p(W z^p)>iJHMm%MRv#8oRZtqQjTYp%&#ijTW6JQE?>#z#vUnKlx?qHYyE6R$^7L@;c8w{ zvX!$+p|bVh-~PO!D6h%@W_!i;9%XB()yh46G~1ebT7oKf)aSjgZ-?@FUfKD}XTJ7#DqH@AQrfYk^tF`3*Zo_+Cru9a$?Xk&lX;PzHs{8ck&9@ySMb->tCAsH}8MFS--Qt)IMJt zQub5^6-9ZjbaBT^mFyiw`RFF%mI_-y6;gz{oVwwNm~U-`L0WouurF<(2ERq{J0^BLt*MN#fZQ2d8y%#Ut) zDw9)wSy5U$v#0m8UanlooZp*&=J2sXCinN1orPR0bG&a`=F`t-3P<0p^lhEKrWEF; zKKKuwJOAz-fASS2`=WaG`RDT|o~^vAwrkrP1@&<2^lzQMlg}!dbIKLvxvejKX!6=C zN0rv;uk;=6%jBlAxg%dyp4l>~C@&WF{L@lKF}Ll1Z|3RDHotPBq9_Yj6lF_A`A$aG z`oTVBOJlW!U;K3bPn6T&d1@g0>B@UPS5UT}AA4)}@Y(Rj8+l1}mF&g*7vIXi z@1K42-zn-DWh(Qb?BU5X%4EKfxvVJXC;RfsM4zH$b||e}UrX|8-;0V;`mJYkf9*&% zpDFe4l{I`lcO;{n+49D#rHlFO8^5zHcjw=~_uBiuo7vIYo%?^XW4iL;D;4FM(x-e; zS1Q9_fAjM3Z0WO4ZM*PV?)4qY*)4^CwQl<=ckUf~wokb_)S8gO;92G3MU>0^^^adv&cDB<{Oiot=s#6{ zZ9w@aSGFH`5p7dWAJ}X%d0xpK{=0wB+OqZO)_bP3zV|47Kc74Bu3Y74{&V>Y z?;&?SedI*;Yrk0eVtLQRi-R9~@oydZ@@HP!@fBsqU)~VMwpCWW=QDZb)UG{f+lS5< zK0WcrZz+A~)t@f_C38Oe8((?jc`1j^=5mrQpZejYY`%7}pzO{cdG;LH^Cc-{-uTLk z!v*gR<+tgXfArKde@)rGH~X!Za$ENI?a2MiGvB#3_Qo5^cYbr%M}GTXwUj;Y+x_*w zlmD2R|CK`FSmmjI^D{>>*`?Ee{IFa;qHOu6hktqJ^S^^~2V0ZbzSbZ7%@;n9`}&?c zKl|n1xpG)}>%9f#xxbd{R^F{V(^L*$5vPytK1$!K?SJ(jD}}3t!sYy@kBgZ-O5f$D zTI$xqk^PzMw(whf-uIc}Q#)H=xKL;*ruEeS`l~gnZeBx=vZ5VOzIHM5f95W3$vt1WsO%ZISrG64jUVK%9oh4N%$7Zsmv=q& ztJyn${NBSKSGIlmm0!&MrLPWDUiv@g{=S##%UPd&2;NdIOe&xM&h9hYCg0eW{cz#C z?|bRoe|py!p8fE){h2M}J90-V`Pw(ODfv?V<@f#0E^o}({crQX0N&WQ*Wdoq-hYE8 zmB0M;_!p-XKl{6_-yT2zt>@k@6e?%87oItA=x-t+G7ZO#44m| zC;xNb_*dSO{guLBeR|vSzn~{yv5qTW?C*Q=3qyxK`mTTY)cs#7eBjJ~`kOmm`QNuq ze(+r%d$~3A|L!^avsYgJvhvg$!(V*P9Qf9;N+mr0p^J(VWS;%-u|4_sz4R}S9=9j* z3x()|;rGI$mI{5g}t$nYKUHGCDSlJzYul7}> zbXE>OZgJ0l^{M>%6WM(gMHvuNi@Wlb(^uh?5JD^s2q7*DA+GmBs0_&2K-oUIM_ht% zGTVYsnOGbUSGGb3r-fJom!{7_IM7m*CAm;;aP(s3c)qZ6QceVUDerbF8Kv^9lD^O6 zm26I4&t%0yF)u24sgqmNi__C^`tc6Ca|2@Ei3KQM17gqQ@d0r`i1&&s)0cK%d>IIF z_3D6_lzK9oQF7UI9IZ$NluZ>xUKUV6$x2DbX%z*6q&iCxM*urx7sZesG<@t5-_`lrO!sp}KRk1zC}m|lW~Ng&er9+_X`dPu`~szr;hJ`HQPVEG_bJyvJkKC7T3k4lW_m_eGs15b?M~p ziN)Om=d;I;v@RUY6proLH*x)y{d=cc{gp!Ns5lRI7Fv7qyZRRT`zFs6t{u*0a(#uP zxx(cWhYN?ZTc6#N-FIM@n3z_MTtB-wapv6R!o{t9JNGELW3X_#vVHd}&rU2H*mWBA zojY;l*w($fmHv~H7q9Q#*~(r~PAeH@_tE2-%GSyJ>0EYFIdggcv7>#vTZ_BTDg#@U zet4iiU)j~4d-;e`X%+f*ZSU*ryK??yUteM8k<+`5UfTX_M%n*L-|3xOPcA^X=VI&3 z`TiqQ$InkrD%*3HmX5!2;ONB*2eRkDk;y4>7EX)&Wg)t-A66H|0-Q)udsT>m1vm{; zye~}*EWiU0PIX?%7Fq)vVgU{anV#vXYx4KNb#ZC2A1pz5NnBCD^~IckaQY&I6NLe> z1dj*-2NtK~!ig*UQpCc^^yh(vDF~0j{sUrZLM+Il5(@)Yg?zKPna0i6h2F2FiQey% z#|}&{O-+e&aQd2<5^!P>?phc)w`=m%le-H2@Ysa7GO-9x^e@8W@Yn%(QXaMhr^L)g zCq4L0A<{Q;uj}#$?A0o)J-H%eOj>Y4Ty9mD;e>cFEv~0tPYqmw0z%~%{hbZ;K>tvP98Zru}^XlJhF7<^7InS z^eHEHUEP^N0#x=MzIqNy%7odoOVgJ+N3Q1tJUIa2$^J>v${rXH*DeTfM!<<9moJKi zscRP?oCenp05~C;_3X8!t!b8~PKyb#04EO|6Jl~{T3o-r9m0tvI3RXi-6!k%x)9gI zrF}MaG{q! z0uLX9$0XRlzln>k#KJ%aR>hkgOQK~u{o++vTN4{XO!Ujzm=c#oM{b|IC|P+?w4qfM z;ySFtlShQ;C`x}-h@^U{1L4$iORl-JwD)=noPAKjh(kCd&s(aA4bc?|gwT38EnbBX zJ}*SSw5X*Fbfl4Db+Oila9IeE!2YCXXLtHBj?+9&JkBS4d|l!x8Mu%ld_aDE^l>!c zzyeg1>8txDdUSbgT5N^z#I%5*N0ktAtGD!iuWI3JdSq(2eD#V6P77G;!Y3~d;e}rk zLUg9(`N{MmoS5BYWe6ueFTbg#)+b%j6(W&4N$DKv zUxhVk>~S$5AbKiRlD3#EgKjmOv{}x;3#bVGj2_-l7fR?6fSBSvcE) zDV%Czaj}q5D!U=99WCt59VsY%`J9r!*q7ae-I}I$3-GW^cZFzmQlWuamU2V&+ z?6laX2iB8bxmQIOrnQ@XtUlN*+oh^_J9YLHJk=4atLtJ#+^~{O`?{7`u8M9NdI+r! zoS9yN$9w1Zr#vUlK{$0uB-2V7X3>FSrDvk(Rl&x&%}~Mv@Pu4rb(U9T^agsSNVcAU zaA0u>R<9_T)lM&iu$ltqTw0I4(%N-RzM1Nsejs(}x&(_@d>oQmhgZenp6YFXNOV(l zU+$!>Zm~y36IZ7eCd7Ur#NKMkcnk7p2cGQjRlbxBC#1ewN<%%c2$!s-nykCtnXoz` z+UL@unR!j_+?fz!p_qDZbuH07*-k?PQjn*9_g>ZaY+gy@GS%M$`zAw9FFb~Sr>ff&j;X}8V3I(qChhI?5?4#$$F|CIe_ga;Rkj>S z2i;k@{l;Tv?e)`?nkGayWx(|Wrhxk9Cm~#uir}iOGHd0^XV;h8vukT|mRJ?yVG0vV zh*W91r}zx)Or@0xXE^)_gh};&ts9E=;sk`d)BTrVK@1#~#zA=e+SEY*bpH{tI8nJW zFnwX+G{J3KEIxV0`sHx}z_Z8#gRwk_#8-_(t1 zi%M5p9XI8JwO1`@Ex@8|1GY#yFDy)TQcI;Gt%*(>!s$hM)T$84YMZZh9x}EfY7Zsz zO?7IL^<^A8X@w_jz8A|WVJ$*;zLN&J1L0lRsfjj}diRtN; zV##z_o8)$C7EXxUDFIC+QnR<;VUt@{XSOQt%8qiQDsIA)8%sjmYCt$so0(Wo;B>e8 z2*!!b%Bkw@&T6MBQoesAZVDm(ObU0_>v6ERZ*`#qIh=J<{#&YkLnd9S`?u4Hpvwmm znZ8aN3clGLYvKm1CNr=tHA!O6rtB>H&1R#7(+6r|>7-O>o4O@!ekW^U>BPPslgpnA zx6|r-4l2~onO)IUMtUjFYTH>}l z`$?;t#$&w;;Y!!$vb77bBHOXNo>*&1Z8`ZkoOuMHSYPe9^g-?0w-U(VTC%e7U{$om zYWo|#jD4!taD{jv9ZEP{>29oUbcFb%Ekt{zZT0W&RiNa)yNlB&SKCSToAHBL(Y|rF zZ6zG`9!%84a>wdUi2EI}+8*dyk}IqP@~Jjlk#VuoNhZ~b%e@ByQf9Sb`@ZPdpApLs zQkk;SdD4%n?T#GBI_XfI^2Ka=_YF8xTN8`0Jv(EqtV$HLYoZH3DMTXM%EFShE|%M{ zY9+N5(XOp0mJE~CCZZ$DO}Z*8FX>j>wk)KtiPeppG6d2hi6yBT-IbM7?V5NkSzf;h zH}2KCpO_J%&0)7wqxZ$y+Y%gIyViA6f)UHh?XN9AgjRArBQ@NzWPU5@N*!Ml_h)LW z>+Loaw(^w)>01QFdcelA-pH!^9vm~drDID>O;S$I3KKa zWFJ|*)eo)PqV2BtBGuD)ABR(EN2m$WJ@t4{?7}vz-bf&v71b_W?asox_h9ud6yl~N zv)_j>mMopX__kQ6iG(Nc229rP{TYPoU1)9G5J{(&iZk)RezYN$+u~kIRk!(?NURO9 zmiDMc2&)o(*3#5+J1ySntUD#!zE}`#xMYd$f)MSQH0i5P=H=P~oZdQPb)eOTFcICZ z)u|?ryWqMIoi1ES9|Y7AI3uQJTmh}FErr6V&Z!q(>%duYx4+HdLpZr4zWeIWjl$6R+hTMR0(s2(!zTOd{!%xko>UgzVyAi!D?n1Hp2?+1g?kOv| zb;IgBSZl*hySnkGyqhHLk3-RJcWSE=!XnvNPvER=)fQK}?fcb7n@`M=TOHTxSjn3Z zZY<7LHxgJ&({xH2wBF$zXu~$_TJ2tXME3_0c%AC4jSggR<;L3bw}tpz!fwFY+P~tk zYxU-P+Fj}BtBL$Hv+_M5y4C86fNd**D`NSPoNn4(+Y(~q_cuBn>s%MEi1p6O1Ie$} zZShU`>z!FEu^(7sq1wI8XT(GMwzV|dh22}wx<`d*SMRzB{3M)(cWwCarj<4-ne_RN zSYLerp#`gts$vmVJFuOsi7x!+s#xxFINcE&T^r7}A(XIh-%DmYtD+50iMC91y9Q~G zW2KyQPdTbSnG&Zaie_-u0D)~_@nA- zC#kK^*el8E`ptEAs@PQOO z>ZAFj1L4PI(qDKju_rpq5AND>R(&up+SMD?POZJX+Ffs3_aL14c4zk1Y;7au2hm>n zJ^0DH_n^JeKEym3l=PpdB*yvPeH}2lsxZ5ilxFIDsti64UpAz@0%i^xv z=@wTKImE)*8Oe*w;vwf9_(>?*33O|n2JBc}C_0@4c3wzi0$0}Wt+k~9l`>#C5pPR+ zb**kvP1bJNsfe+X8@B8_58ANSS-sU>Pr6bfEw78WZ3ySvb_2q1ZzL|PF87{aJ)DVa z-C8;mto~V#_vA1x(pu==;ILau8*8-<*Am)Ix``z^3ADPk^+(Bn{CL-D^Kbv4BOA)> zaz}Kl>vsiQU2C6eyDva1VXKceWp4YEkHm6!Q=Z(vJ0mNz_t;Ae+b`8`e7aAFQ`)9lHy~z)kqV#`2ng;u~!%S-%hAYR3=yK?NjZT+5*T6i|@N?3|jk;oKOAAS?gZiuzpFkZgB(h==iCt2&%5}MF%bz>zR zzc(IdK?rX~4O?x_(cN3U?*@v>z?Et_uIAQ&ONwN{kG_?cEtMHjheX8{lpC$#^3E$H^hAV8!LaWcGGQdEO#2>78A>& z`@2=KA-@0c6IIcU#RIFooP6SiZ;HEJ-k$yS4Y7RlQEf$hPjvaIo3piUt+TNq$GPr` z=+u%IZivq6E$H61(?W`+Y`bBtB{SSw?}`q5Kzdkqlj>)d@3%!~{k7#Eu8Z$=W^cLe znNDpT&RFfPb-N9r{rmSJJY^-zx9&ri-xrA`Zaip+2MJtliw%jB&aWr1!>!vLxcuPJ zpMLyLt6e+3x!#6@8_BH)v$MD9@}E`P@NJRUqFr5;Rdsu|D;w{|&7`xk++ORz|5S)%#)a+9+u|Oq zuHBb(-WHFV9UH`b4+fpapsR%jp*o?= zj|T_Mxl(y(_~6Lsp|SDQ<+@=KtLOBb|Jd!pz#kkO1S&R&?F5`4RmUcALLLnwG&nfu z&ml%UIyg9p0t2a7TEyq$!Jw`U4weS%O-93mBaFD1a)V;dd{sk%?gS0hZ*Gb|q(8y_3j#@<1KAMzNf8nGPa z^F|aSO~=G>SrE<-BQ5pY4>;O9SKiSxJc^NS2Su&tiDsBGV_}3;TsJK@HH|kTn+4M3 zbdQE~o;b`8!e-rZ87TGKNl)W40ftFf&m*Mcx=CEQH7|{_C>}zXP?p|cJ5PewjHHQ{ z+`bVX(oNz>V8__7T^1rk#wbV~vRD{NWI6Kis1Y$t4azhljGM@IX<#|Nt`4exlWUj; z+(Bm8G+BMHRMriLvY=ER?v;;>{AS=A&B!x|5xRqen;F_n&`--xpsHZdCYa1M8CMM! zM4^TT!JuvuIwV~S`8d*f)Npt+8a}969wtmjq;4`!5CMLvfe{eSMOgzgBP4d+(B!885Z#~+Lst2m z&jZRdHev-#l>ms`L6t-SiB(OrNTV4^H%Eg_XUDa=LFI>oBV#NW8kPXnOgm^iL8~Ui zmcGSx)1_VzMr9c#jRbtYRPNo8!bWbH-XbGx%V0F3^6==`xXXv%!TdW_BlDgj#IhZ^ zI4%y4K3Vsp%gV#!JwT_Icr%Jee-z5>36^^oE!&s74INDDl-Maz@_9{{$GhHK5Xvpm zlQwhQOR>!Gn5yZfWv8Fw@}blk)7k_pZ!{l+JwOp67{g0LU6S6p% zdh^)uW?V)VO)Y535>d6(ESi?nW3>J_4u48Cn{jbi)qj*#HVrzYrR?ZZ=7)UqM$2~D zob<4WdIw0`HtkoR8TG;LxBvpfoakXrw%BQ=(#7#X1fU)l@y;2x*K^f=u3UjHVL=)|@#Xse_aR^G($V zg3zLrX_zwN1{{yNSkryX4VMK>^8q1D_YpxlBGe+3cnA{~5f)+Q$7qf)*1#SBC0Tcv zFs@^!`Hi4Cr#o{2=T^~lTpppireT*+M5xBGX@)UIHlyRNk4S)#2THPen3%OSGk>&}7{ZK4K^c>P65TNEAi~Hay6-lyp=t)9UeGK$#57#T zH!bXNR5u!RCu)r8j;GJp31T4%iOxbD5gkz!A{rpa;fQeCJsdLnHR6>XwH_OQU5vJU-MbTsj}=X&v%LEd6ksX`kag_-?j1J|7h|S!r`Yh|)^- z=0YCZOmnE;NIRpfWTZBFEt91+i|YoHupiP%TE;OZcG|UM7YXH3TqkyLh*&lYLYIZn z2ntlmtw^<;CaT8)0XU496Um^G--O0N7-Jm&zk!<>AqBLdzo-9V!ox8O0K&L3y}5e8?OHDh7Zcs@ILu_|Vw+ z2*yTv_spRf#u#>(ZPQBWQ^G^UZcxIAvm zg%n}ak<_3D4WftRdUv0F8G+?8%jc%;Fi#6&wP}vI5ek~cgHrg+ zg{r2LhN|IIeIc$DW$Cz5?F=K$LUoI3vXe6}s2f%g>clT1RWmFy2umPO*w@7VE^9c;*K6=lLj7S;MrXO3{fP7wbrsWTp`&tHbp}L}(G|m~oA; zAdD?9oNod|Cx9Ta2z1aLN(G&R2;VJG%Aug?)aQV ztf;e~xY4TI0;e$NNtj?a7=y5Q$;F^JSGU6j7LZ& z8u6jnPy@qa4rSx2hMCKFv!qGJZkBC>M2H1AbmJhj5h8489BGnELl)z>sS+AC>;?@@ zjfV401F<=T>lTYR3mnQ=QNyO`1|ep#=>$4)cuYK1x1CsJniRDJX*%;6X1=Bybyd^f zk>#mEh>O~$Y@m;YM!=&(5~Zdi!PAI{hP1kANm()1XhtBN?<8Ht^N4D?{L1r#X2evz zx3?D(R+pMH&~!?%6a+!2O1KfG$)E*kuF~bIBh%wD@ zwP7vIjnC(G9>|8uybx(PXyQ84RgJL5+&G;JOR78A2&^%wXQah;s@{iH%b|W)RL6fz z$pztjBSM5msE9@>LqyJlp~+zswTB%s0Sf77*ow4GAvIsy^zZgM40+WHdQZ> z!!+^74ILY{Z#fl zO^F{gnz}BvDUcnHVkR3LLxdrlhQwDHMbVh<0UZa?2z8O}81u**by*V;%Srp1^bh zWMWh2bvn=8rZpeSxz7oMy54WOjdVj!VIdj> z2pHwL$PXPku$4KP^PG?ZqT2|8q84%wfiYVP0}OZw!nyHA(+fFnsG-xaRg>$$_XCq5 z7r34cv@qaNOpP*T1VnS8Hb3YC5Fi%IQV!`bCFWcR0<1~qHq)_qa~_c5F2*_~%wV#T z0S$>JC%ceiA|*6%Oh!WFBTfNvjd(tEYyb?xVoI596g4LTAPD^+QZ>VNf)Mzjh7H#T zfU=-rTEIa8@=+KP$3+g6LKxHmU`PcP*C{6m`H~kvghQmWuo=bmx~EeF=0ej6sn3{4 z7^Rf!zNWjOKd56nq7I28x9$gS=xJ)$@HAToU@%172zWCvK#4eZLsE(t_%2X2YG{N+ zMtxLAa{$zR5TP(?GQA!HqM{HmuUKkw-$%spF~zY)fnS~jt}$3AW&{W_0b+(nn8hMz zs7@VD5p57|0EZFVYlIqY`oya{z8x~eLt;ftD>>yM<^-;48ptD|+H@=)hm1Qa_9Dy> z3pK1^le#g|o0QT-2d-EdVB=src5QZq!D zGgmGNW0lf*geZ%+9yC>KNc75?yoduWz<$HhiaMt{woGK%%yC`Gdz4ed3?f81rquBq&sHh18=h|(B%(128x9I| zq!NH44uDAl(qOS+TG$P2W~jwsj)?Cd8#z%O026>9(waD8W~8Zr8jaBR0~f?(9wAnb z2mp+d2GD>OsSax(#ERM=3G`t+r_Y;1K|vFxHW#n{l88lo<}=L1+%^sq6@v z0OJuFhpI_*n_BuI0FXf>I}f`7v1rIS^1+Df1*K@%;$Z`8MYm3d+3@g);kzY6Hsayo zk?}!1cgWZA7zO~jx(0^lhVj_&@ED`R*e#EM=J3$y5K?uMSS}5t5dgqw$N+Ui7l$K` zuCs9)4;#RsZXFPhmhd4^9xjgz-10y&D!@4$78bwCLxaN9*0*aaL z#uV{JM6lUtMg&`fXt)GM54i`i4mjW@G6_YR$Mr)C@FC35$x7 z3B53iHNB}DCg%ZSn2wFBI+mhio}*w`BcP~DRY!4AD~=OdB9zTB-({pon}ivNHuYF@ z{3g|qsgFf*q&LlY*dC2sgUo5;MGY5Kzi5}s+6bvruc&dK$DCo`FKWd)@ygyv`lQw^ zYi{5*i>5OMR5Jhpp&l=?d8GQxZ)h$x2rkxHgVl|Y1P-CD7Z67`N5;}&MapoMa#D5~ zpD#&~&M|X1k&PK~iv)6_t{Y*%3|VLf4Nc42#8b-H$*}H2tC< z20?LnWOV$=lQ^d*GgD2g+fwLCr6=2|rs{Rm^@32-4eRj}Y1z$mxq`AV2=yW@BGnr; zwYX>_ABP@7kvSe~^EN^*c0$ib46#_!HsS^~3Fi^jxXUn+ikx#f%LE)@Qa4N+TQ*1B zLztU^M6$spVR1%ugf?SKD7S%4k?Q)$WsOErM_PoD$!*MOalH2k(UxP7hfEd}ZHx(H z#FYIi#sCA?VBwWY6Oj9 z1On9$%AsmHkvcLy?l8w|5L+iPsQWR~7$_0nq6nB$z%pXEK`|)0p&3w3tD9b^`Cb{* z2$3L0w5Sok-qeadFKVvF!=h$l=IC)lFJp~q^Lo(-*ev3xSZ^Y!k)k3+hKzwxlq$4I zSrDtboG`q(uqo?-umy7TVM+h;4un~Bn z#SARxg{U|p6B1MG^P(CSM-WD;*86*uRLw;_>qTnQqK34vJ_mF<$D1RT?*tfxnxh#cg&#K3(IDi= z4J?`AQ1cvQxSaYiG5`-^I;!cK!J1JV$Z08*eb3ZPM+=<*MTX(VQEWCmQ1oPkQ4sKP zhA8vRpdL^yL`Y%_QRFb0fPnc78FLMrMv+s*CS^fM8z#JNQRezupoU(6NYS9h5#%u* za-FMYz(PF7V<|WhBXargZ9^#K;ddzlh}I8{xn=ji9Lkf@7B!N!-wpjD1sc!(tt?BDNbbEe{>iJl6|7 z4`DTIIDzT;!eVQ-mnD z9b}@p5QXtvlki3y%3BcEh=c_w5f)*Ca#k7{-{ho-GP`J+awb+eHr-}`5Dsyy&r<{_ zju~bywu+V?65?~$p$;Zm;JD^IKq@Dm{oo*Fn26un}kuXTYJc5$H(6J^-L@yCDhW&>PRyH3xhev=R*eEaU5z!P^7AE8VHPpIC259+2&vD{+vHTV`6jJHDxm#k}Z@{ z8@ZT=ZWyAl8FDwop2kQNhM^vYk&THQPKb%9Z(_s<@&Rf}r#zGRIzkbM8}neE`Jqf1 z4>4fWL=Gfrl{Buu6%Eu@%|8J|7s| z57kBlv`}+3M+YwDoLfN%f)FF%dG(OW4C`JPMQ#WfM#H1&pONie*O_lbSOdVoUUSZ2 zb;^Rk^Gii+07O`za$hwmi2_1L=bQ!rE@B#xu}1(zAOhwn4W;>k76OL`z+*ZHJ#7@L z9P5$?vC%->lk3S`NGt~QK=UJFxBvja%ZvmJVM27>iI6sLXch=81iX3-91P~2hy$Gf zhYV{tFqlDuped)mkZM5p{m_gI#{j+~Ys1%7tr*UivDQEy1F_@Ri*?Y%J^`%ZSpf(D zG3LNXNJbh5Z9POT2?<7~WuTDG`GGMPg<2TN&W#-un+ye3Sq)>x9IO%QAcg{`ZfLsc zm_T#5hOy5_%VA(P>ZYf=P2E>bhJB9_N|Dhh6M(hx5F>1G%uOo{jgUJY@|ljX>zSUW zBNxZc2xYMz6K0s*kYZfz2q^e93}@n_+BdQhMmzVay~1M+R|Cz&NFK zFAT;pM8@2 zG#&0}n6jphn#2Mas6LyMvsY6bX6Tfl7&t``5d=U007U>J z3P58-PIM}87;6B|7zMfoKn!fETcLr} z(BShU$RRAYG>rfa5Idx%6LE`${t%&7fCwgDWRr2tk3uj6nuykmKGCfqG&D5snq-&~ zgv}Jgkvmt`^sr0;0sasGZZre{B14n_cN`1>Fb;H&M@_X(ntUE0L)QT@!Fb?MHV$+k z7h9Z?gP;tC$^cMGLORZZ2%ve70Fw+kbE;o9X!~n!@P!Oqgq-l>Ux@quo)wi z{(mPmB&cBpfKu#oI**8M(pU?53^b3qS{x&T_#A0;WW-SsV-b!_6akOxmV+p6XeQ8^ z5jjK+u&0rR=1@K|f)M60H#{1dh+sr1bpQc|J4UFRHYn1h3}6jupp1*ECZL+;EppC@9bP)=4Z{F8UU?87pM#wOwn0br=#6e_~aM6&H zVMGWCdqxEvWU z$Og$_AUs_CSt6>x^JcHE&N0FUX%CWcb1$SPO`@ysmn>oDtZ@u2(E1g8o#^8&@r!QN zRLB&|$KNTe+NPOh-_jQ1p7-=T)Jwg%2IkDEE-#V9^*fPz{6|TmT=SajlMf0!sG|G! zALse*rlmup-cPTIJvPrr1|&2D`HRJE+wU5+Y_)DGSo42h-~BPw*A%!kzsmExr^BhI z-Y9IRuc;9&^X67(67hoeCJK_RYLo<}(3{QDPnWBrs^ z!W9m=q}{n+MabogHBw+n{qVgXxKcZ=OhSPwwD(ClenyeQN$sQ8&vUHgdbO}Fh0;PP z7-%`k#5BeICO-aSVb?m&|Hwy1k`LY{AJFD>pO}Q&U+M0ACJ7X3+HS7(qD*sGQeCJf z;d;pwJD=bS-{`ELck1fnqk(YU6%<<0J?Zfkb!PwSA>UU{dbtb-c z>cy}Yi9h&TQ~IT=9_|j8TRcnrJ1`AEEICTrx!8xzLss@9>3?bo!7x@5}(RR zuQ};eh-lW!oU-&YQ191h(1p-N$p4qZ^P(o#R&Rm}zmwZv6NT82y|cd~YCJWCG6Tiu zvQSy$vpoCkRj;a^*Q234*mdgZ5N_WX_1SA(x<(1a+IQ)bPzp61D>Ek9M8e&jLc?bH zut>PQyZtZa5P02QJcms}*N5>&5%0%7w4Outsd+M_zdC*VVd(|Cgv3#Dyxb=}ka=}o zF=vfk69j|p|IY^}w2ijZ=(QIA@F7Tdx^@)`yi+Q7APte2L*9Muo(TtfQI!AFEha(z(Q`s}`Aj;i%iuj*Z8%*ZdUG38KNd%Dl!z5(DXAJnrR zr=M~XIuhx$<|!`P{T=q!+7(1DcFwm|r(BOzIQx)Wmxpu8+Pl*~hwGV^9;NZ>ozV*S z6v)?oDf5PHlBRPHL28qByy_TYeVsRQzy9+DsIhOkU5-0_Z5;Sskfa5rt@W4^D_#^_ zRTm7SuWt6Y?yJ(ao&KC%?ue3`6q%$3leUcS-~IZiAN6!wo#LmqkDtFnjnZoj?bRN# zZcMVB-$z1(CpjGok@_i$b7>*S6E`wU!cZViY3@R44f*+Op;K7dCl;imb_j=qF<%v! zv{GI_qa}J|Gl9RBi*6Q5^$TC=lF%(DM{pnK@GM-`b4SfBA<`U!td=)8&S@o(!Dq8W^CkOtU7Nl82!EdY)B->%3Rx!G~xPtg@WNWuNzyJBNpZzL~ zh4(@PBJS9GT{|eOCRqiqeTYH80o^wwc0j8x!!j^%jUeoRD+USEy=36y+lMH%FS>_5 z%WGHB>pux4ZODfLlQPrAo_{nzxA+q^AXEhkW^g1V zkzfD)`Stzy`u_EIOzp3t&D{CA*Yl=9zC1>wrm$ogv+MtcM9jKhQ*29->Yld`Yi<2n zcNdaq>*Rux9`DIkeeV6=i|y^@18=pzmYaf-d$)h=Esi^wpxx{3V`6Rb2nVfsuh${S z7s-(WU0+vHA#Z!&9h{rov${*2JD|^A?Hdl5^68fItcfCor`f0tydf}U#uQZ`6%qBQ z3RfDNhMB>6nV_NW{$ypPP?r_z9peU33;RT&mLrJUL(TS*`;CVEn)h?m31w~#aJK97 zWTNK6v1j$+tf+m)y=iR#Yb@#8^<3s<4Zd+G!gq_uz6(pu$l058?E2a6RkjymSPP-* zVww9u04Nu5GahiJ5-XhRpdFIjquFk_5KEZ2RY6D5(w_q9+0<4REPhTgPo=c%&X57G z3Wb1GgEqJbNmGm1FR1H%G8~a3pwUZLw+dPc&zQ?LIgp#a6Tnokfn~+7?!&Zu*~!HH%!=wHWLA6!2b1N8gECyY zsCFD&06l;M2pdM6?+9Q=Cf7fTrv%>b^p-m@-CyLt(()A(@a6c{J5+4* zgk2payRzP(K2^nmuP;Q#+@Z_mVSxT+LJf{j%YaZ)V6DXH{+>YxfXnq0{U`AFL^%r6 z;Y$Z9AsLZ}Vw_RH%M6W7z>b`7t$*Fg;UYvNmW>;IO~*}K`{6H?R9ao2UekJWI-)kZL-C6pOyfWEPg4ml`VXI&r&V|Z+Gdtp^;}n#%_z23vK(j;ST)veC(*Q zYp#WksReR__)aCh@tddQ!C;uz5TNs{ue-83qs8;y>JhKWf1%>fv1xtf?SlJA&sO7w zyP_Rn33)MZnd{^357tpsa2vGexpqrnMyctF6@;4}0So$^7ngU3=Sz1Bj^t4HIZ7)b zZCLf!PGN3;n-|>QlLRry5%I`9D2m=~c=! zI|ea@-)pfAHvuD+L14bun|c*Tou-Wzp$)=FzxhdMGGWB=BD-WD>~5zAoQVOXW$(-G z82a^v^-oY>Um9Nt0T*t_d{1dTuDQE&tC1Xsykp%=$6QpdTUA1&kV@h)7pW{}gtoI! zf!C{3flvog>=O9JNvM;aLSYweLT3w45poCBZ>kA@cL|g!3WY|ARY>J2ohWLzOfVsO zQaF0rbrTeE)%QQ?zsMaEPQ#EJGOL%PQY@Za#vn(uEM=!su`R- z^sd632y03Ys2zaj+=hPQ{Szfp(xPO9lWKRP7uvjwV% z)V{b%#g)OM34G!2se9RfA(tk6Z7R$#kyh#NIhkx^K&07q*1S*vF4T@*C@-vc-2YW+ zMBIMYRdwf_2~#0<+m6Jw{pXABd~=#o=1$};qVUBug>+M(^b`qna96sB9=)Xd66WJ8 z(t2^;Q{qzsd61g4<}No5(4Ekd2Pl=bTuSfCf3gM1swE<~f;}T;Fx*qm)sp1vYX#!5 zxb4K|bavb?ds&B1hr=ra`;UbMyTYs>ZiND+@aF}WLTuAc+sRWh0n)syXA z#NJ!2foMOD%b10BIPkK~`*N~6za5kqh5AhwmuR{#?Em4c`kSwUMO5}M9xPf0VHLNKkkMUT#QL&fZ zaVEF$Pwcy@9_J+cCvja)3JCwvRogM$)ybJciEiJD*6KgPrpP6g>&ZJldMdaO9@j76 ztVVgSE^8JJWnN{6S^f3OlTrLsJFe)wJi80KGg~FS?Hh4K{AH@Etyh+Gf^9AI%Kb+2 z0nP593sV<_`;=+&N10VHPldWNCgi!Hp`d<*1>PH`?o05u?keZ1waUIYAAH@3a0QNq zdK%)5S809fM82gOfZt-Ka(~h;&$eN|>H;*baVxu|-L)y|bnS}kmR*SIZ&K{@bgj-c z-fNC%c}WO)*OLMx#I$0;Z$QdH+Kv$VM)c{o|VT^Tm_+f6QPd%wwa z(seuceW=n%W`;i~hT3~#x4)*)w?@zjXWoGxt+IWJHY=mdQSA$u165sj~FfHrt6P)ju5~qronAxc_#JY74X1ALf(5Wxb2KI&Q(4qw>1~$?Q$Hd4+~vh z|09NY8W-7?A`v~K%@eX)W)KjrF&~22?@Ozj#6r0`iY1yz@0la>h`{cOP&uUL5J2R4 ziHfbN5Ts>N*D>R|KqRQxf{LPfb5JK<>kX9F0`fUCWJ;lvy=%bZlMCObd~JWLHpqtV z4aOKqjJkQl;w_Y@AK#Q~Q=VUsg*M*7pG7k9IM%?~*I1kU2G|9;14-ykh&mq*?6H*E zmXiqbFo;r$!1><---1I#I5x8uj=otxENh z6)tC%i&7C$G2Rc}XXDiUk0vxP>iZD_&V93&>p*m9ma4!6IKN*gzon9VZV&}M68;84 z8<^q*;8DJE=D$ZVrlR}6L@de&LO_S>KDg>jVBhccObO&tj0vH%uDFUAI#jfV5W)_W z7k5G5;Z+r(*3`TZ2udjMr+elK_(C17;F*Y^f}1i zwd#|`^iXwper_Fh!#(1;BfbZdo~RxfJrjzvujzur6A^!a!_5Ck`)$uafb(s*ghWu6<5U@JsjUUDwxSIW2JC_X<+3Zve!clHZ!H_S#K z9h_M9CL$EdD=nS4Z(V2sX0(k{U{UGJ*uDUY(h=(ej9A3**fv;t_|`{74H~q&RG#v`)209KaVW=S_!JeiFQB$_ z4nH{|6^lPxxFwEId8arsD$>3nFEcvQoJLW@{MHS(=Eux91!97^jG#k`AOsCnyLY(O z_Qjs%$o={dAqt&|Rm|7s)Asg^G?Uig`-+Pr9IcpF+n)zls$nIS7m7HAgi8p2d?VnX z8W_bRCB90GfC|kS(TPRpN*lg|)~pavUlcR{U7EvwnI6CBaR$YSh~jT2sE>T?^M* zyo}yhqN=l-JHEupKqo$wBKMv9(I}Of&z!e}$4}e)9LzeUHLKBLPE)7=pGntsU^9V< z$a1>;9o4e%Kus83vvA0NEW6-h@yTJ1yBU)IQeSgpB#I}0B<>H#Mv?fTjZ2RvLc2yYowjNiN(9`=v8@a&)Ksx! zsZXv@EzHYRbDt-}-wrw<<39whj!XzK*3yq_IYUJ3-BR4-9^mrGX}C(k?z7Pin#=*P zS&#ZOm~>OaTHd0E=ddg_Sag$X$KrE^c$MZu-~tHY<4TUx&o zh?&myye31-2h&a!i-R->^fG!xQK037BLKd-ZlLVG8RUgb0CiII-)cj@hqY`I>p(>Q|t17I;}8jmi0Pj1E6AQ>kzG@E3Zc`9KuLmYnFj~|u7g71fAPC$MvU3}#}x0lT8+%U}*?ljr3)Q=cA%rnB( zDW?=>B-TJq81Hw&Pi&y?@s){4RkbZ{3VdkRMgs`+Mf(^uX2=})PYo0553|xt>6-aC za&l;iB4g;$Y_spZA=c+%P+C&;tJH)S)(Fhc z$)#3n6EZRD`VM!wnCdm=6plGJ3NGHPq_L$r9}zC4HriWg?L#-8mMgRgt~=){HMAp5 zIhz@A^>(Q3LT64TG5)ldA_U$DQ}461u96+Y1n-Mj+-fUcckIF6KKZyriAOvu`9?)F z>gLJh8h1mL#InR3Jj0 zs^+~IFH{yB5_AlnxI~oG_EEwX`$FaoA{B`Jk>Vx8Tj$fx^VZTcp)N5;cEM`A#Elm zY?W48xxw^Gc;Y`@(Iyi#-S+E5?$r_>=%2$j5}?$v>N5P6sfGW{@{G5~+4aQT;5-_h zWUlNqkd?zT?Wm^aY$vaZJz36~f7$NmZB)q|0OhJzoM&?353p!JTA2{TsTOt$^MkJE zSsN%Z8Nrf{$*b%mY9B@UTIwZ2>~)*s9ugreVg{pe0B9D$wZBWtNwQG2Jg;3-2M|L}Tp|>y<(w z@qzC!V?mkV<3~8Ti7`L|GEJzuno#mVO?mMF;$|cYrnM;UIu*0G7qO`UT24kF^w;_j zofU^H59mGXI#pvaxnxh*LGtM&C)>P7K+3vL5XuPBIZ|&J9rM0W#CFtnjCq5k@6>E(bbQp=-Hi zw2>~jq0xz{NtxB}JEo>iGUf^HC!EOTYO084JdS#*z3kmNvr7SgiR1JxXNK=3h!*G@ ze}MiS&e1+#l0a8t+_)y(|5=VF(6294(^yNWi6c;5RRVolQiOs~t_*aEi=ZTW$WY$~ zoKPgYqwWoc-5v#wFb_3=Rr2U#!xCTBP!!xqz;k0sHHDIDTb_uhKmRwvi?lg$f-L}B z$CV&vf-Pw6X0GjNIb)E5ge`4w5ZMgwzpyt3cqO6d3Hw%0o=-|E@@+5wL^0IqM19Jg z+tGnf2rj#K5tQY2Qrdjm%S;qQJx1Vs(eVwZ_n10<0MVoCEJRAHA5`-gPRugu*;0jG z7%zcr!6mqgxi|w+5$AugsQGLYqamgzBq*5Y%zJ%ZSXLke;MF=RcohOIpn`voKV{kI zc2Ti%pcTLY&v&9Y(ev7;B;cvfjBB8(X*ql=IP2*WzF6<{bj)TN)1Mp+enPq^ZoB_i zLox@K@LwKhI{$Q&n3ce%xua5mm8(M>&L@seIo4x)#u{%mAMxx4zyTC_e|=8bBBWm; ziI9}GJKeSr7+y=pVAbK;GT~VrDvMCfUrht$`ege>hjIz=6dVT)lX%TROgndhIAPf= z=%Mgb*nj4yG)#rCTy5VV)z7~8(VadOx72NVnt)+HLT=^hl{ z2@zBS_{Y5M-Iio#Lz@s1nSQIlcSGL-8H|`@vZdXP!zAYe9d z50p#I4ubN^qZj4gmHu~wiyoM;TQXUQE5lw7$zy$2^wHtYYApGNQ7-2(4ckYPMM^QD z&@ugmLze%{r!#g`D2#%P;i6fm7FOUEb+N{rKWZyASvcG3VcWLNJLlY=<`%<#IvPUG z;#T>VW=rL$RJ#JAap?g~blo%b27Irg=WXm?Y3hVR4Kq+V4W=L$CI=VV2Dku@9a~d4 zqVV|`cW#%QXjA+F>i498Z(rwy^yRnl$c)n3r_(qr2L_}9TK7a!!_vQ9Z9TOdywl{# zZKjxB5Z9W?QiRuOY50FXTIf`Wo1|-%`4w9>3h{N@lw3$lJL8UNN7&j&{Ul6N-sG2M zN+AtCOizwXm&%Q4Io%jt1pgD$ObOwv@_;P0Zjna-@7R(>{3lUDH-%7fh(lZ<dyNZYB^ACSY~GXA|N%^KP4lE#x0KfW5|Pu9u5TyrS=L z$5f&=lYOW2QcV#uW{7>+pF^t~)C^rv2|h%>jYliJ%eMI%Rr_XAzUYhzHMk)yxaY4{ z{cSdm9yliC=@dGe=9DfVnao?*%;-`-QxL!l;R4J)lY%tHoty<-J9F<13tjhYZyWrm zQCAAHfa97?a-_r=jmzMhq(M@6(yE+CO3u33jV$+&zo}1X<^%5P-y^1m+NnGz^t@oJ zO_{y8)LrDIjmVuW*7A=x#~M$0hS6ez)X_0!hnv?4X6Mp=qUW;SjCDmf-d-4M zBA|&SS^b~aAAIz@mEXo;l+D0G^_AgW>f7~lmmA}jpr$x`;PKvjLe`W5W_uAGsK;HY z&h~PheG1?t{sh13tsM&)fq-wd>mryh0CK!JPZ3+wgW(uI@r`qzrbP_ZcVVkj4|p z40ZFUV5N>!IWgS^3E$rrkD|HBpz)wv94vAHffC|nGB}~~EXr;FYDE0KKqVUe{)*`y zj}Bn4&*^LQvoGx(_on@&ld`a+4(vUWMXfoq=g2XD%3)jE zAJlV4QqJNyu!%O8HVsaY4wyFuO_t-^`{Sa}0F?`->|n-X79(oIU5tY4dKoiagL?hn z!O;d8P3r@jaboY=kZWJ_wS6Zp`FUJDmC+=yWpbFFNZS}0=wW-N*d`|gHB0@BAi6sx z9vTmE&*PHn(Ah4%jmI&Sp&AjW(UiO2L|#orQ}!IO?8F?-e#XAoV$nuHLF<)&Sdz&y zx1hQ~NXkc)6Gb9T(@3(ROj9)iJX6rjvX=`v&#Sh!bcgHM1?d%H4yyx^7)+g0Ee5#9 zxF(!#2fj0y4n*NfF9#w$l=WIIKlqqn+z&LFcO8@FXozzW# z{xf*~7)S6i9;`hA-O%=^wSHmJZIeNeZ*b=s`{dntj9p!P?Y-`MjoZOZH0w()^Klw` zPfCI2WYTtx;@maNJIlV$2{_Jh zOYk&JH7@XR)Y;tUD2jxKT_V5ccCf3G1Z^}@$D&a3*U9~c*)FI#T~n>pFvUM8)hDOK zPHNz4DpJDkHis!y%R&5*isWlhpt-V3XrqNY9HY5HqRn4!Mmq2vC|w zb%EX#$%fqa-xG+Hu$R2Euq9goB9w-3adE$r#im=BD7A5Itbz> z>-~)tJsHc!%u1Jq*jYRUhbYHN_=`#r>OM#(|%?sH3 z9e)--<~-A|qDi|}9(!+d$*ybfoW5az>MI zD(XZD>mmlHKAN1nA6=CxCi5<~(HXIfelL#a2!u9DOnl5{>rVyD(oKsH7PI=D;M$(a z(P*}zy+7i12-#vUZ~0~W_znxh+)+R>d%VY$aJ~)PV$iDUz@x!7H$soodoT++$sY?+ zK`OP0jv|5#EZh|VQ*&-Mvyvid-N6--aCc5MVF^89?_2E?B+*BVAldIK2aFJATSNPG zR6g8?2BaMZ<8WNL-PeGMK$Qpgs3)DonHh`58tz>?K1dN%6rVZfr<=Fcb6O3Gj6Dg>15pRjlPUdXpl(z0sL^N+45m>8!~PPGCu$_Bqnh! zaKm%VP${s{a$;8_xmIu%do!gS8JR}7k#4Cr&gSfj`E-8oYap{tqa0oS!Th^TGnvb6 z*f@4{ADR>knA$cXHlY@>>U${!A&f^jjBdtlbUF3KqRiPk>5g;nV?S9SD~zXInhG}I zz}}!gwLM5f$u$5ECvYfhx{)|d0j;a)WXG7}yiyF%D4kjYN$-8aYk6ZEDwz2qBwUQ# zxeJ$BCuD}3d4onh#)P|>?Ry**B<7JVE*bfZt`4-lOE$(-DMa9F;36^TJtH4%6Z+(? zL^YfdS3CNcmUs?(in(c@JcT)p>Zc_=^EMRKA$%Bw9)kZJD#4X#5pl>mj;Dj|(k5Uj zZD_!35`rm>gEpgYis5GeeXzYF9`{J0)to2(Jt1pY^`GM_^$7Sg_LfIe$~ph;xtC2u zIwp)W|D$=k9u0N;+0g`v6q)y2(_VQzyy*#h`-VRBy3yj67`vf&#*=AAx_cGn;sZ8`E3ZjY}rx6}X15 z=yL_>s-w5P3N<(W``ZM3YJRkb z+Gav;93~zEsP%c;=+)tVKL_A_(D{7|+o%>stK+u7=Qz1yNW1cUS$>ZSWsqZidn`l2 zR*lBTVT(>fB%A?hWB*Uiz+7AWW4?Z+pA=U0ryKOw=8bQ*N9o zEDOwIH}FRNU4$FK@9MjI+J%XyvSAaVJ8xLMtEZ*8b6cf{SB<{82s-Xu1Lt)U}?0U8fTXr?tGFvwP+DvMj>g(#z z(lBzyK+d}#qkPx!|37+(|2egP1MLT$zhgp(~KiAngw{dR)llw4% z_C%Wk^3d@WN$$gh-cpy!o`s#7W^*~>BfJlIbtj5FK!3EhV6=ZKw{fIn+QLp1Wz@+& z{w>7g*TIEq-=;!LP^Pzd)%I3gjLc zIi?l@iRpeIQQ{MPbX$sTMnOeLeN)1ZY^oDlsolf6Y}^0)f6KImcln9Vehe_ph(nl8 zikJLjx{lcKINN>^%83*wvcrfroM1--DQ6==IwtUc3;;E34XsmBv{T( zaAD5xhhTtim>6@_I73l?`*AX2Jcg!r?NVFKI6hAuM@ACpBf$j|qqRYcc`~?Pe-HR# zH$S=ZBf1R#k&tuvK{)=NP$B!_knCCUP zIk)if@ez&_!XFI$&Ckor z$f>9RHM%ocn055DWAqZsi&OH7b(8aSqYZQ|W5Gm>o<>q;RZVh!ZcSclNli(9fu@QA zHpPj$sSx$ac`DLzdfK|VnHh(>COF1Pr0l>|X;^|m;EXJ) zd>2no{?<=8B>XecBqVXPjka/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 new file mode 100755 index 000000000..32c3c777c --- /dev/null +++ b/clashoo/files/usr/share/clashoo/runtime/clashoo.sh @@ -0,0 +1,347 @@ +#!/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 extra_resolve http_code rc + url="$1" + tmp="$2" + hdr="$3" + err="$4" + ua="$5" + extra_resolve="$6" + + rm -f "$tmp" "$hdr" "$err" >/dev/null 2>&1 + + # shellcheck disable=SC2086 + 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" \ + $extra_resolve \ + -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 extra + 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")" + 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})" + extra="--resolve ${host}:443:${ip} --resolve ${host}:80:${ip}" + http_code="$(curl_subscription "$url" "$tmp" "$hdr" "$err" "$ua" "$extra")" + rc=$? + [ "$rc" -eq 0 ] && [ "$http_code" = "200" ] && break + done + fi + fi + else + wget -q --tries=4 --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 new file mode 100755 index 000000000..823fef247 --- /dev/null +++ b/clashoo/files/usr/share/clashoo/runtime/dns_helpers.sh @@ -0,0 +1,451 @@ +#!/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" current="${1}.dns-leak-current" tmp="${1}.$$" + [ -f "$cfg" ] || return 0 + command -v yq >/dev/null 2>&1 || return 0 + + if [ "$enabled" = "1" ]; then + 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 + yq e -r '.dns.nameserver[]' "$cfg" > "$current" 2>/dev/null || true + + if [ ! -f "$state" ] || + ! grep -q 'clashoo:dns_leak_protect_respect_rules' "$cfg" || + ! cmp -s "$current" "$selected"; then + awk ' + function indent_len(s) { match(s, /[^ ]/); return RSTART ? RSTART - 1 : length(s) } + /^dns:[[:space:]]*$/ { in_dns = 1; dns_indent = indent_len($0); next } + in_dns && /^[^[:space:]#][^:]*:/ { exit } + in_dns && /^[[:space:]]*nameserver:/ { + print + rest = $0 + sub(/^[[:space:]]*nameserver:[[:space:]]*/, "", rest) + sub(/[[:space:]]*(#.*)?$/, "", rest) + if (rest == "") { in_ns = 1; ns_indent = indent_len($0) } + next + } + in_ns { + cur_indent = indent_len($0) + if ($0 ~ /^[[:space:]]*$/ || cur_indent > ns_indent) { + print + next + } + exit + } + ' "$cfg" > "$state" + [ -s "$state" ] || printf '__ABSENT__\n' > "$state" + 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" + elif [ -f "$state" ]; then + awk -v state="$state" ' + function indent_len(s) { match(s, /[^ ]/); return RSTART ? RSTART - 1 : length(s) } + function print_original( line) { + if ((getline line < state) > 0 && line != "__ABSENT__") { + print line + while ((getline line < state) > 0) print line + } + close(state) + restored = 1 + } + /^dns:[[:space:]]*$/ { in_dns = 1; print; next } + in_dns && /^[^[:space:]#][^:]*:/ { + if (!restored) print_original() + in_dns = 0 + print + next + } + in_dns && /^[[:space:]]*nameserver:/ { + ns_indent = indent_len($0) + rest = $0 + sub(/^[[:space:]]*nameserver:[[:space:]]*/, "", rest) + sub(/[[:space:]]*(#.*)?$/, "", rest) + print_original() + 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 && !restored) print_original() } + ' "$cfg" > "$tmp" && mv "$tmp" "$cfg" + rm -f "$state" + fi + rm -f "$selected" "$current" "$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 new file mode 100644 index 000000000..12d5851e6 --- /dev/null +++ b/clashoo/files/usr/share/clashoo/runtime/dns_loopback_adapter.yq @@ -0,0 +1,17 @@ +. 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/iprules.sh b/clashoo/files/usr/share/clashoo/runtime/iprules.sh new file mode 100755 index 000000000..29b52b970 --- /dev/null +++ b/clashoo/files/usr/share/clashoo/runtime/iprules.sh @@ -0,0 +1,98 @@ +#!/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="/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 new file mode 100644 index 000000000..221a2fa9d --- /dev/null +++ b/clashoo/files/usr/share/clashoo/runtime/mixin.uc @@ -0,0 +1,317 @@ +#!/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) { + 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', '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 = {}; +uci.foreach('clashoo', 'dns_policy', function(sec) { + if (b(sec.enabled) == false) return; + if (s(sec.policy_type, 'nameserver-policy') != '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; } + policies[matcher] = servers; +}); +if (length(keys(policies)) && (!dns_present['nameserver-policy'] || dns_force['nameserver-policy'])) + cfg['dns']['nameserver-policy'] = 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 new file mode 100755 index 000000000..997e941bd --- /dev/null +++ b/clashoo/files/usr/share/clashoo/runtime/primary_group.sh @@ -0,0 +1,49 @@ +#!/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 new file mode 100644 index 000000000..59ee6074a --- /dev/null +++ b/clashoo/files/usr/share/clashoo/runtime/quic_fallback_guard.yq @@ -0,0 +1,9 @@ +# 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 new file mode 100755 index 000000000..4ce19ca62 --- /dev/null +++ b/clashoo/files/usr/share/clashoo/runtime/restore.sh @@ -0,0 +1,31 @@ +#!/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() { + local data + if [ "$#" != 1 ]; then + return 1 + fi + data=$(curl -s -o /dev/null -w %{url_effective} --get --data-urlencode "$1" "") + if [ ! -z "$data" ]; then + echo "${data##/?}" + fi + return 0 +} +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 \ No newline at end of file diff --git a/clashoo/files/usr/share/clashoo/runtime/sniffer_overrides.yq b/clashoo/files/usr/share/clashoo/runtime/sniffer_overrides.yq new file mode 100644 index 000000000..885d81afb --- /dev/null +++ b/clashoo/files/usr/share/clashoo/runtime/sniffer_overrides.yq @@ -0,0 +1,28 @@ +# 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 new file mode 100755 index 000000000..23dfb38d7 --- /dev/null +++ b/clashoo/files/usr/share/clashoo/server.list @@ -0,0 +1,63 @@ +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 new file mode 100755 index 000000000..2ad2eb2a3 --- /dev/null +++ b/clashoo/files/usr/share/clashoo/update/component_update.sh @@ -0,0 +1,642 @@ +#!/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" --tries=1 "$url"; return $?; } + wget -qO- --timeout="$REQUEST_TIMEOUT" --tries=1 "$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" --tries=1 "$url" + return $? + fi + wget -qO "$out" --timeout="$REQUEST_TIMEOUT" --tries=1 "$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 +} + +package_version_from_url() { + file="${1##*/}" + case "$file" in + clashoo_*_"$ARCH".ipk) + v="${file#clashoo_}" + v="${v%_${ARCH}.ipk}" + printf '%s\n' "$v" | sed 's/^\([0-9][0-9][0-9][0-9]\.[0-9][0-9]*\.[0-9][0-9]*\)\./\1~/' + ;; + clashoo_*.ipk) printf '%s\n' "$file" | sed -n 's/^clashoo_\(.*\)_[^_][^_]*\.ipk$/\1/p' | sed 's/^\([0-9][0-9][0-9][0-9]\.[0-9][0-9]*\.[0-9][0-9]*\)\./\1~/' ;; + 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) + v="$(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)" + printf '%s\n' "$v" | sed 's/^\([0-9][0-9][0-9][0-9]\.[0-9][0-9]*\.[0-9][0-9]*\)\./\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 && [ "$(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 && [ "$(installed_package_version luci-app-clashoo)" = "$luci_ver" ] \ + && { [ -z "$I18N_URL" ] || { package_installed luci-i18n-clashoo-zh-cn \ + && [ "$(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" ] && [ -n "$core_ver" ] && [ "$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" ] && [ -n "$luci_ver" ] && [ "$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 && [ "$(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 && [ "$(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 new file mode 100755 index 000000000..69e0f6f06 --- /dev/null +++ b/clashoo/files/usr/share/clashoo/update/core_download.sh @@ -0,0 +1,1233 @@ +#!/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" --no-check-certificate --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" --tries=1 --no-check-certificate --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" --no-check-certificate --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" --no-check-certificate --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" --no-check-certificate --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/bin/mihomo" + VERSION_FILE="/usr/share/clashoo/mihomo_version" + else + TARGET="/usr/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/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/bin/mihomo" + 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 new file mode 100755 index 000000000..a8bc66e6a --- /dev/null +++ b/clashoo/files/usr/share/clashoo/update/geoip.sh @@ -0,0 +1,267 @@ +#!/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)" + +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="/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 --no-check-certificate --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 0 + 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 0 + 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 0 + 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 config_needs_geosite; then + download_geosite "$geosite_url" + 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 + +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 new file mode 100755 index 000000000..6b96dbf0e --- /dev/null +++ b/clashoo/files/usr/share/clashoo/update/lgbm_update.sh @@ -0,0 +1,52 @@ +#!/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 --tries=2 --no-check-certificate -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 new file mode 100755 index 000000000..e0e4affbc --- /dev/null +++ b/clashoo/files/usr/share/clashoo/update/maintenance_cron.sh @@ -0,0 +1,36 @@ +#!/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" + 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 new file mode 100755 index 000000000..4519c4833 --- /dev/null +++ b/clashoo/files/usr/share/clashoo/update/panel_download.sh @@ -0,0 +1,176 @@ +#!/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 --no-check-certificate --user-agent="Clash/OpenWRT" "$url" -O "$ZIP_FILE"; then + return 0 + fi + done + return 1 +} + +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 + +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 + +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 new file mode 100644 index 000000000..e9664420d --- /dev/null +++ b/clashoo/files/usr/share/clashoo/update/proxy_lib.sh @@ -0,0 +1,80 @@ +# 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 new file mode 100755 index 000000000..49ef064f3 --- /dev/null +++ b/clashoo/files/usr/share/clashoo/update/subscription_update.sh @@ -0,0 +1,386 @@ +#!/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 --tries=4 --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() { + [ -n "${CLASHOO_SERVICE_CMD:-}" ] && return 0 + "$SERVICE_CMD" status >/dev/null 2>&1 +} + +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 new file mode 100755 index 000000000..1f83307c7 --- /dev/null +++ b/clashoo/files/usr/share/clashoo/update/subscription_update_cron.sh @@ -0,0 +1,18 @@ +#!/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 new file mode 100755 index 000000000..63be16c1b --- /dev/null +++ b/clashoo/files/usr/share/clashoo/update/template_merge.sh @@ -0,0 +1,101 @@ +#!/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 new file mode 100755 index 000000000..0b0a89360 --- /dev/null +++ b/clashoo/files/usr/share/clashoo/update/update.sh @@ -0,0 +1,5 @@ +#!/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 new file mode 100755 index 000000000..b743529d0 --- /dev/null +++ b/clashoo/files/usr/share/clashoo/update/update_all.sh @@ -0,0 +1,20 @@ +#!/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 new file mode 100755 index 000000000..3797e8f85 --- /dev/null +++ b/clashoo/files/usr/share/clashoo/update/update_china_ip.sh @@ -0,0 +1,204 @@ +#!/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_V4="/tmp/china_ip.txt.$$" +TMP_V6="/tmp/china_ipv6.txt.$$" +OUT_V4="/tmp/geoip_cn.nft.$$" +OUT_V6="/tmp/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 "$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 --resolve "ispip.clang.cn:443:${ip}" "$url" -o "$output"; then + log "DNS 异常,已使用 --resolve(${ip}) 回源下载" + return 0 + fi + done + ;; + esac + + return 1 +} + +cleanup() { + rm -f "$TMP_V4" "$TMP_V6" "$OUT_V4" "$OUT_V6" +} + +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" ' + 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 (!first) + print "," + printf "\t\t%s", $0 + first = 0 + } + END { + if (!first) + print "" + print "\t}" + print "}" + } + ' "$source_file" > "$output_file" +} + +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 + +render_nft_set "$TMP_V4" "$OUT_V4" clashoo_china ipv4_addr +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 + render_nft_set "$TMP_V6" "$OUT_V6" clashoo_china6 ipv6_addr + 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 new file mode 100644 index 000000000..9e3b042e5 --- /dev/null +++ b/clashoo/patches/001-skip-invalid-fakeip-domains.patch @@ -0,0 +1,91 @@ +--- 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/luci-app-clashoo/Makefile b/luci-app-clashoo/Makefile new file mode 100644 index 000000000..357d3e149 --- /dev/null +++ b/luci-app-clashoo/Makefile @@ -0,0 +1,100 @@ +include $(TOPDIR)/rules.mk + +PKG_NAME:=luci-app-clashoo +PKG_VERSION:=1.30.0 +PKG_RELEASE:=1 +PKG_MAINTAINER:=kenzok8 +PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME) + +include $(INCLUDE_DIR)/package.mk + +define Package/luci-app-clashoo + SECTION:=luci + CATEGORY:=LuCI + SUBMENU:=3. Applications + TITLE:=LuCI app for Clashoo + DEPENDS:=+luci-base +clashoo + PKGARCH:=all + MAINTAINER:=kenzok8 +endef + +define Package/luci-app-clashoo/description + LuCI web interface for Clashoo +endef + +define Build/Configure +endef + +define Build/Prepare + mkdir -p $(PKG_BUILD_DIR) + po2lmo ./po/zh-cn/clashoo.po $(PKG_BUILD_DIR)/clashoo.zh-cn.lmo +endef + +define Build/Compile +endef + +define Package/luci-app-clashoo/install + $(INSTALL_DIR) $(1)/usr/share/rpcd/ucode + $(INSTALL_DIR) $(1)/usr/share/rpcd/acl.d + $(INSTALL_DIR) $(1)/usr/share/clashoo/rpc + $(INSTALL_DIR) $(1)/usr/share/luci/menu.d + $(INSTALL_DIR) $(1)/www/luci-static/resources/tools + $(INSTALL_DIR) $(1)/www/luci-static/resources/view/clashoo + $(INSTALL_DIR) $(1)/www/luci-static/resources/cm/mode + $(INSTALL_DIR) $(1)/www/luci-static/resources/cm/addon + $(INSTALL_DIR) $(1)/www/luci-static/clashoo + + $(INSTALL_BIN) ./root/usr/share/rpcd/ucode/luci.clashoo $(1)/usr/share/rpcd/ucode/luci.clashoo + $(INSTALL_BIN) ./root/usr/share/clashoo/rpc/backup_archive.sh $(1)/usr/share/clashoo/rpc/backup_archive.sh + $(INSTALL_DATA) ./root/usr/share/rpcd/acl.d/luci-app-clashoo.json $(1)/usr/share/rpcd/acl.d/luci-app-clashoo.json + $(INSTALL_DATA) ./root/usr/share/luci/menu.d/luci-app-clashoo.json $(1)/usr/share/luci/menu.d/luci-app-clashoo.json + + $(INSTALL_DATA) ./htdocs/luci-static/resources/tools/clashoo.js $(1)/www/luci-static/resources/tools/clashoo.js + $(INSTALL_DATA) ./htdocs/luci-static/resources/view/clashoo/* $(1)/www/luci-static/resources/view/clashoo/ + $(INSTALL_DATA) ./htdocs/luci-static/resources/cm/codemirror.js $(1)/www/luci-static/resources/cm/codemirror.js + $(INSTALL_DATA) ./htdocs/luci-static/resources/cm/codemirror.css $(1)/www/luci-static/resources/cm/codemirror.css + $(INSTALL_DATA) ./htdocs/luci-static/resources/cm/mode/* $(1)/www/luci-static/resources/cm/mode/ + $(INSTALL_DATA) ./htdocs/luci-static/resources/cm/addon/* $(1)/www/luci-static/resources/cm/addon/ + $(INSTALL_DATA) ./htdocs/luci-static/clashoo/logo.png $(1)/www/luci-static/clashoo/logo.png +endef + +define Package/luci-app-clashoo/postinst +#!/bin/sh +if [ -z "$${IPKG_INSTROOT}" ]; then + rm -rf /tmp/luci-indexcache /tmp/luci-modulecache + # reload (not restart) rpcd so the LuCI login session survives the upgrade — + # rpcd restart drops every ubus session and forces a re-login (issue #12). + # reload still picks up the new ucode backend + ACL. uhttpd needs nothing: + # updated static assets are served on the next request. + /etc/init.d/rpcd reload >/dev/null 2>&1 || true +fi +exit 0 +endef + +define Package/luci-i18n-clashoo-zh-cn + SECTION:=luci + CATEGORY:=LuCI + TITLE:=luci-app-clashoo - Simplified Chinese (zh-cn) + DEPENDS:=luci-app-clashoo + DEFAULT:=LUCI_LANG_zh_Hans||(ALL&&m) + HIDDEN:=1 + PKGARCH:=all +endef + +define Package/luci-i18n-clashoo-zh-cn/install + $(INSTALL_DIR) $(1)/usr/lib/lua/luci/i18n + $(INSTALL_DATA) $(PKG_BUILD_DIR)/clashoo.zh-cn.lmo $(1)/usr/lib/lua/luci/i18n/clashoo.zh-cn.lmo +endef + +define Package/luci-i18n-clashoo-zh-cn/postinst +#!/bin/sh +if [ -z "$${IPKG_INSTROOT}" ]; then + # just clear the LuCI cache so the new translations load on next request; + # no service restart needed (and none that would drop the login session). + rm -rf /tmp/luci* +fi +exit 0 +endef + +$(eval $(call BuildPackage,luci-app-clashoo)) +$(eval $(call BuildPackage,luci-i18n-clashoo-zh-cn)) diff --git a/luci-app-clashoo/htdocs/luci-static/clashoo/logo.png b/luci-app-clashoo/htdocs/luci-static/clashoo/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..021e4c6928f33efccf47f2c4d29c1ef883137307 GIT binary patch literal 210103 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 o6aKt5f^llOr7|q_YW~dJ_PN~_` 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",")":"(<","[":"]>","]":"[<","{":"}>","}":"{<","<":">>",">":"<<"};function y(t){return t&&t.bracketRegex||/[(){}[\]]/}function f(t,e,n){var r=t.getLineHandle(e.line),i=e.ch-1,c=n&&n.afterCursor,a=(null==c&&(c=/(^| )cm-fat-cursor($| )/.test(t.getWrapperElement().className)),y(n)),c=!c&&0<=i&&a.test(r.text.charAt(i))&&p[r.text.charAt(i)]||a.test(r.text.charAt(i+1))&&p[r.text.charAt(++i)];if(!c)return null;a=">"==c.charAt(1)?1:-1;if(n&&n.strict&&0c))for(s==e.line&&(f=e.ch-(n<0?1:0));f!=m;f+=n){var g=u.charAt(f);if(h.test(g)&&(void 0===r||(t.getTokenTypeAt(k(s,f+1))||"")==(r||""))){var d=p[g];if(d&&">"==d.charAt(1)==0span::selection,.cm-fat-cursor .CodeMirror-line>span>span::selection{background:0 0}.cm-fat-cursor .CodeMirror-line::-moz-selection,.cm-fat-cursor .CodeMirror-line>span::-moz-selection,.cm-fat-cursor .CodeMirror-line>span>span::-moz-selection{background:0 0}.cm-fat-cursor{caret-color:transparent}@-moz-keyframes blink{50%{background-color:transparent}}@-webkit-keyframes blink{50%{background-color:transparent}}@keyframes blink{50%{background-color:transparent}}.cm-tab{display:inline-block;text-decoration:inherit}.CodeMirror-rulers{position:absolute;left:0;right:0;top:-50px;bottom:0;overflow:hidden}.CodeMirror-ruler{border-left:1px solid #ccc;top:0;bottom:0;position:absolute}.cm-s-default .cm-header{color:#00f}.cm-s-default .cm-quote{color:#090}.cm-negative{color:#d44}.cm-positive{color:#292}.cm-header,.cm-strong{font-weight:700}.cm-em{font-style:italic}.cm-link{text-decoration:underline}.cm-strikethrough{text-decoration:line-through}.cm-s-default .cm-keyword{color:#708}.cm-s-default .cm-atom{color:#219}.cm-s-default .cm-number{color:#164}.cm-s-default .cm-def{color:#00f}.cm-s-default .cm-variable-2{color:#05a}.cm-s-default .cm-type,.cm-s-default .cm-variable-3{color:#085}.cm-s-default .cm-comment{color:#a50}.cm-s-default .cm-string{color:#a11}.cm-s-default .cm-string-2{color:#f50}.cm-s-default .cm-meta{color:#555}.cm-s-default .cm-qualifier{color:#555}.cm-s-default .cm-builtin{color:#30a}.cm-s-default .cm-bracket{color:#997}.cm-s-default .cm-tag{color:#170}.cm-s-default .cm-attribute{color:#00c}.cm-s-default .cm-hr{color:#999}.cm-s-default .cm-link{color:#00c}.cm-s-default .cm-error{color:red}.cm-invalidchar{color:red}.CodeMirror-composing{border-bottom:2px solid}div.CodeMirror span.CodeMirror-matchingbracket{color:#0b0}div.CodeMirror span.CodeMirror-nonmatchingbracket{color:#a22}.CodeMirror-matchingtag{background:rgba(255,150,0,.3)}.CodeMirror-activeline-background{background:#e8f2ff}.CodeMirror{position:relative;overflow:hidden;background:#fff}.CodeMirror-scroll{overflow:scroll!important;margin-bottom:-50px;margin-right:-50px;padding-bottom:50px;height:100%;outline:0;position:relative;z-index:0}.CodeMirror-sizer{position:relative;border-right:50px solid transparent}.CodeMirror-gutter-filler,.CodeMirror-hscrollbar,.CodeMirror-scrollbar-filler,.CodeMirror-vscrollbar{position:absolute;z-index:6;display:none;outline:0}.CodeMirror-vscrollbar{right:0;top:0;overflow-x:hidden;overflow-y:scroll}.CodeMirror-hscrollbar{bottom:0;left:0;overflow-y:hidden;overflow-x:scroll}.CodeMirror-scrollbar-filler{right:0;bottom:0}.CodeMirror-gutter-filler{left:0;bottom:0}.CodeMirror-gutters{position:absolute;left:0;top:0;min-height:100%;z-index:3}.CodeMirror-gutter{white-space:normal;height:100%;display:inline-block;vertical-align:top;margin-bottom:-50px}.CodeMirror-gutter-wrapper{position:absolute;z-index:4;background:0 0!important;border:none!important}.CodeMirror-gutter-background{position:absolute;top:0;bottom:0;z-index:4}.CodeMirror-gutter-elt{position:absolute;cursor:default;z-index:4}.CodeMirror-gutter-wrapper ::selection{background-color:transparent}.CodeMirror-gutter-wrapper ::-moz-selection{background-color:transparent}.CodeMirror-lines{cursor:text;min-height:1px}.CodeMirror pre.CodeMirror-line,.CodeMirror pre.CodeMirror-line-like{-moz-border-radius:0;-webkit-border-radius:0;border-radius:0;border-width:0;background:0 0;font-family:inherit;font-size:inherit;margin:0;white-space:pre;word-wrap:normal;line-height:inherit;color:inherit;z-index:2;position:relative;overflow:visible;-webkit-tap-highlight-color:transparent;-webkit-font-variant-ligatures:contextual;font-variant-ligatures:contextual}.CodeMirror-wrap pre.CodeMirror-line,.CodeMirror-wrap pre.CodeMirror-line-like{word-wrap:break-word;white-space:pre-wrap;word-break:normal}.CodeMirror-linebackground{position:absolute;left:0;right:0;top:0;bottom:0;z-index:0}.CodeMirror-linewidget{position:relative;z-index:2;padding:.1px}.CodeMirror-rtl pre{direction:rtl}.CodeMirror-code{outline:0}.CodeMirror-gutter,.CodeMirror-gutters,.CodeMirror-linenumber,.CodeMirror-scroll,.CodeMirror-sizer{-moz-box-sizing:content-box;box-sizing:content-box}.CodeMirror-measure{position:absolute;width:100%;height:0;overflow:hidden;visibility:hidden}.CodeMirror-cursor{position:absolute;pointer-events:none}.CodeMirror-measure pre{position:static}div.CodeMirror-cursors{visibility:hidden;position:relative;z-index:3}div.CodeMirror-dragcursors{visibility:visible}.CodeMirror-focused div.CodeMirror-cursors{visibility:visible}.CodeMirror-selected{background:#d9d9d9}.CodeMirror-focused .CodeMirror-selected{background:#d7d4f0}.CodeMirror-crosshair{cursor:crosshair}.CodeMirror-line::selection,.CodeMirror-line>span::selection,.CodeMirror-line>span>span::selection{background:#d7d4f0}.CodeMirror-line::-moz-selection,.CodeMirror-line>span::-moz-selection,.CodeMirror-line>span>span::-moz-selection{background:#d7d4f0}.cm-searching{background-color:#ffa;background-color:rgba(255,255,0,.4)}.cm-force-border{padding-right:.1px}@media print{.CodeMirror div.CodeMirror-cursors{visibility:hidden}}.cm-tab-wrap-hack:after{content:''}span.CodeMirror-selectedtext{background:0 0} \ No newline at end of file diff --git a/luci-app-clashoo/htdocs/luci-static/resources/cm/codemirror.js b/luci-app-clashoo/htdocs/luci-static/resources/cm/codemirror.js new file mode 100644 index 000000000..9c78bd464 --- /dev/null +++ b/luci-app-clashoo/htdocs/luci-static/resources/cm/codemirror.js @@ -0,0 +1 @@ +!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e=e||self).CodeMirror=t()}(this,function(){"use strict";var e=navigator.userAgent,l=navigator.platform,d=/gecko\/\d/i.test(e),s=/MSIE \d/.test(e),a=/Trident\/(?:[7-9]|\d{2,})\..*rv:(\d+)/.exec(e),u=/Edge\/(\d+)/.exec(e),w=s||a||u,v=w&&(s?document.documentMode||6:+(u||a)[1]),x=!u&&/WebKit\//.test(e),s=x&&/Qt\/\d+\.\d+/.test(e),m=!u&&/Chrome\/(\d+)/.exec(e),V=m&&+m[1],K=/Opera\//.test(e),j=/Apple Computer/.test(navigator.vendor),c=/Mac OS X 1\d\D([8-9]|\d\d)\D/.test(e),X=/PhantomJS/.test(e),Y=j&&(/Mobile\/\w+/.test(e)||2t)return i;o.to==t&&(o.from!=o.to&&"before"==n?r=i:Fe=i),o.from==t&&(o.from!=o.to&&"before"!=n?r=i:Fe=i)}return null!=r?r:Fe}Ee=/[\u0590-\u05f4\u0600-\u06ff\u0700-\u08ac]/,Re=/[stwN]/,ze=/[LRr]/,Ie=/[Lb1n]/,Be=/[1n]/;var Ee,Re,ze,Ie,Be,Ge=function(e,t){var n="ltr"==t?"L":"R";if(0==e.length||"ltr"==t&&!Ee.test(e))return!1;for(var r,i=e.length,o=[],l=0;l=e.size)throw new Error("There is no line "+(t+e.first)+" in the document.");for(var n=e;!n.lines;)for(var r=0;;++r){var i=n.children[r],o=i.chunkSize();if(t=e.first&&tn?F(n,W(e,n).text.length):(e=W(e,(n=t).line).text.length,null==(t=n.ch)||e=this.string.length},g.prototype.sol=function(){return this.pos==this.lineStart},g.prototype.peek=function(){return this.string.charAt(this.pos)||void 0},g.prototype.next=function(){if(this.post},g.prototype.eatSpace=function(){for(var e=this.pos;/[\s\u00a0]/.test(this.string.charAt(this.pos));)++this.pos;return this.pos>e},g.prototype.skipToEnd=function(){this.pos=this.string.length},g.prototype.skipTo=function(e){e=this.string.indexOf(e,this.pos);if(-1e.options.maxHighlightLength&&ft(e.doc.mode,r.state),o=At(e,t,r),i&&(r.state=i),t.stateAfter=r.save(!i),t.styles=o.styles,o.classes?t.styleClasses=o.classes:t.styleClasses&&(t.styleClasses=null),n===e.doc.highlightFrontier&&(e.doc.modeFrontier=Math.max(e.doc.modeFrontier,++e.doc.highlightFrontier))),t.styles}function Wt(n,r,e){var t=n.doc,i=n.display;if(!t.mode.startState)return new Ot(t,!0,r);var o=function(e,t,n){for(var r,i,o=e.doc,l=n?-1:t-(e.doc.mode.innerMode?1e3:100),s=t;lt.first&&W(t,o-1).stateAfter,s=l?Ot.fromSaved(t,l,o):new Ot(t,gt(t.mode),o);return t.iter(o,r,function(e){Ht(n,e.text,s);var t=s.line;e.stateAfter=t==r-1||t%5==0||t>=i.viewFrom&&tt.start)return o}throw new Error("Mode "+e.name+" failed to advance stream.")}Ot.prototype.lookAhead=function(e){var t=this.doc.getLine(this.line+e);return null!=t&&e>this.maxLookAhead&&(this.maxLookAhead=e),t},Ot.prototype.baseToken=function(e){if(!this.baseTokens)return null;for(;this.baseTokens[this.baseTokenPos]<=e;)this.baseTokenPos+=2;var t=this.baseTokens[this.baseTokenPos+1];return{type:t&&t.replace(/( |^)overlay .*/,""),size:this.baseTokens[this.baseTokenPos]-e}},Ot.prototype.nextLine=function(){this.line++,0e.options.maxHighlightLength?(s=!1,l&&Ht(e,t,r,c.pos),c.pos=t.length,null):zt(Pt(n,c,r.state,h),o);if(!h||(d=h[0].name)&&(f="m-"+(f?d+" "+f:d)),!s||u!=f){for(;a=t:l.to>t),(r=r||[]).push(new Ut(s,l.from,o?null:l.to)))}return r}(n,r,o),s=function(e,t,n){var r;if(e)for(var i=0;i=t:l.to>t))&&(l.from!=t||"bookmark"!=s.type||n&&!l.marker.insertLeft)||(o=null==l.from||(s.inclusiveLeft?l.from<=t:l.frome.lastLine())return t;var n,r=W(e,t);if(!on(e,r))return t;for(;n=Jt(r);)r=n.find(1,!0).line;return H(r)+1}function on(e,t){var n=Gt&&t.markedSpans;if(n)for(var r,i=0;in.maxLineLength&&(n.maxLineLength=t,n.maxLine=e)})}var un=function(e,t,n){this.text=e,Yt(this,t),this.height=n?n(this):1};un.prototype.lineNo=function(){return H(this)},$e(un);var cn={},hn={};function dn(e,t){if(!e||/^\s*$/.test(e))return null;t=t.addModeClass?hn:cn;return t[e]||(t[e]=e.replace(/\S+/g,"cm-$&"))}function fn(e,t){var n=ne("span",null,null,x?"padding-right: .1px":null),r={pre:ne("pre",[n],"CodeMirror-line"),content:n,col:0,pos:0,cm:e,trailingSpace:!1,splitSpaces:e.getOption("lineWrapping")};t.measure={};for(var i=0;i<=(t.rest?t.rest.length:0);i++){var o=i?t.rest[i-1]:t.line,l=void 0,l=(r.pos=0,r.addToken=gn,function(e){if(null!=tt)return tt;var t=y(e,document.createTextNode("AخA")),n=le(t,0,1).getBoundingClientRect(),t=le(t,1,2).getBoundingClientRect();return te(e),n&&n.left!=n.right&&(tt=t.right-n.right<3)}(e.display.measure)&&(l=Ve(o,e.doc.direction))&&(r.addToken=function(h,d){return function(e,t,n,r,i,o,l){n=n?n+" cm-force-border":"cm-force-border";for(var s=e.pos,a=s+t.length;;){for(var u=void 0,c=0;cs&&u.from<=s);c++);if(u.to>=a)return h(e,t,n,r,i,o,l);h(e,t.slice(0,u.to-s),n,r,null,o,l),r=null,t=t.slice(u.to-s),s=u.to}}}(r.addToken,l)),r.map=[],t!=e.display.externalMeasured&&H(o));!function(e,t,n){var r=e.markedSpans,i=e.text,o=0;if(r)for(var l,s,a,u,c,h,d,f=i.length,p=0,g=1,m="",v=0;;){if(v==p){a=u=c=s="",h=d=null,v=1/0;for(var y=[],b=void 0,w=0;wp||C.collapsed&&x.to==p&&x.from==p)){if(null!=x.to&&x.to!=p&&v>x.to&&(v=x.to,u=""),C.className&&(a+=" "+C.className),C.css&&(s=(s?s+";":"")+C.css),C.startStyle&&x.from==p&&(c+=" "+C.startStyle),C.endStyle&&x.to==v&&(b=b||[]).push(C.endStyle,x.to),C.title&&((d=d||{}).title=C.title),C.attributes)for(var S in C.attributes)(d=d||{})[S]=C.attributes[S];C.collapsed&&(!h||qt(h.marker,C)<0)&&(h=x)}else x.from>p&&v>x.from&&(v=x.from)}if(b)for(var L=0;Ln)return{map:e.measure.maps[i],cache:e.measure.caches[i],before:!0}}}function zn(e,t,n,r){return Gn(e,Bn(e,t),n,r)}function In(e,t){if(t>=e.display.viewFrom&&t=e.lineN&&tt)&&(i=(o=a-s)-1,a<=t&&(l="right")),null!=i){if(r=e[u+2],s==a&&n==(r.insertLeft?"left":"right")&&(l=n),"left"==n&&0==i)for(;u&&e[u-2]==e[u-3]&&e[u-1].insertLeft;)r=e[2+(u-=3)],l="left";if("right"==n&&i==a-s)for(;u=i.text.length?(t=i.text.length,e="before"):t<=0&&(t=0,e="after"),!a)return s("before"==e?t-1:t,"before"==e);function u(e,t,n){return s(n?e-1:e,1==a[t].level!=n)}var c=Pe(a,t,e),h=Fe,c=u(t,c,"before"==e);return null!=h&&(c.other=u(t,h,"before"!=e)),c}function tr(e,t){var n=0,t=(t=E(e.doc,t),e.options.lineWrapping||(n=cr(e.display)*t.ch),W(e.doc,t.line)),e=ln(t)+Dn(e.display);return{left:n,right:n,top:e,bottom:e+t.height}}function nr(e,t,n,r,i){e=F(e,t,n);return e.xRel=i,r&&(e.outside=r),e}function rr(e,t,n){var r=e.doc;if((n+=e.display.viewOffset)<0)return nr(r.first,0,null,-1,-1);var i=bt(r,n),o=r.first+r.size-1;if(o=a.bottom?1:0)}return c=We(e.text,c,1),nr(t,c,g,f,r-p)}(e,l,i,t,n),a=function(e,t){var n,r=Gt&&e.markedSpans;if(r)for(var i=0;it)&&(!n||qt(n,o.marker)<0)&&(n=o.marker)}return n}(l,s.ch+(0r},i,e)}}function or(e,t,n,r){return ir(e,t,n=n||Bn(e,t),Zn(e,t,Gn(e,n,r),"line").top)}function lr(e,t,n,r){return!(e.bottom<=n)&&(e.top>n||(r?e.left:e.right)>t)}function sr(n,r,i,o,l,s,a){var e,t=He(function(e){var e=l[e],t=1!=e.level;return lr(er(n,F(i,t?e.to:e.from,t?"before":"after"),"line",r,o),s,a,!0)},0,l.length-1),u=l[t];return 0a&&(u=l[t-1])),u}function ar(e,t,n,r,i,o,l){for(var l=ir(e,t,r,l),s=l.begin,a=l.end,u=(/\s/.test(t.text.charAt(a-1))&&a--,null),c=null,h=0;h=a||f.to<=s||(d=(d=Gn(e,r,1!=f.level?Math.min(a,f.to)-1:Math.max(s,f.from)).right)a?{from:u.from,to:a,level:u.level}:u}function ur(e){if(null!=e.cachedTextHeight)return e.cachedTextHeight;if(null==Un){Un=M("pre",null,"CodeMirror-line-like");for(var t=0;t<49;++t)Un.appendChild(document.createTextNode("x")),Un.appendChild(M("br"));Un.appendChild(document.createTextNode("x"))}y(e.measure,Un);var n=Un.offsetHeight/50;return 3=e.display.viewTo)return null;if((t-=e.display.viewFrom)<0)return null;for(var n=e.display.view,r=0;rt)&&(o.updateLineNumbers=t),e.curOp.viewChanged=!0,t>=o.viewTo?Gt&&nn(e.doc,t)o.viewFrom?yr(e):(o.viewFrom+=r,o.viewTo+=r):t<=o.viewFrom&&n>=o.viewTo?yr(e):t<=o.viewFrom?(l=br(e,n,n+r,1))?(o.view=o.view.slice(l.index),o.viewFrom=l.lineN,o.viewTo+=r):yr(e):n>=o.viewTo?(l=br(e,t,t,-1))?(o.view=o.view.slice(0,l.index),o.viewTo=l.lineN):yr(e):(l=br(e,t,t,-1),i=br(e,n,n+r,1),l&&i?(o.view=o.view.slice(0,l.index).concat(yn(e,l.lineN,i.lineN)).concat(o.view.slice(i.index)),o.viewTo+=r):yr(e)),o.externalMeasured);l&&(n=i.lineN&&t=r.viewTo||null!=(i=r.view[mr(e,t)]).node&&-1==L(r=i.changes||(i.changes=[]),n)&&r.push(n)}function yr(e){e.display.viewFrom=e.display.viewTo=e.doc.first,e.display.view=[],e.display.viewOffset=0}function br(e,t,n,r){var i,o=mr(e,t),l=e.display.view;if(!Gt||n==e.doc.first+e.doc.size)return{index:o,lineN:n};for(var s=e.display.viewFrom,a=0;a=e.display.viewTo||s.to().linet||t==n&&l.to==t)&&(r(Math.max(l.from,t),Math.min(l.to,n),1==l.level?"rtl":"ltr",o),i=!0)}i||r(t,n,"ltr")}(C,g||0,null==m?b:m,function(e,t,n,r){var i,o,l,s,a,u="ltr"==n,c=w(e,u?"left":"right"),h=w(t-1,u?"right":"left"),d=null==g&&0==e,f=null==m&&t==b,p=0==r,r=!C||r==C.length-1;h.top-c.top<=3?(i=(k?d:f)&&p?S:(u?c:h).left,a=(k?f:d)&&r?L:(u?h:c).right,T(i,c.top,a-i,c.bottom)):(a=u?(o=k&&d&&p?S:c.left,l=k?L:x(e,n,"before"),s=k?S:x(t,n,"after"),k&&f&&r?L:h.right):(o=k?x(e,n,"before"):S,l=!k&&d&&p?L:c.right,s=!k&&f&&r?S:h.left,k?x(t,n,"after"):L),T(o,c.top,l-o,c.bottom),c.bottome.display.sizerWidth&&((a=Math.ceil(c/cr(e.display)))>e.display.maxLineLength&&(e.display.maxLineLength=a,e.display.maxLine=s.line,e.display.maxLineChanged=!0))}}2=o&&(i=bt(t,ln(W(t,n))-e.wrapper.clientHeight),o=n)),{from:i,to:Math.max(o,i+1)}}function Hr(e,t){var n=e.display,r=ur(e.display),i=(t.top<0&&(t.top=0),(e.curOp&&null!=e.curOp.scrollTop?e.curOp:n.scroller).scrollTop),o=En(e),l={},s=(t.bottom-t.top>o&&(t.bottom=t.top+o),e.doc.height+Wn(n)),a=t.tops-r,r=(t.topi+o&&((a=Math.min(t.top,(r?s:t.bottom)-o))!=i&&(l.scrollTop=a)),e.options.fixedGutter?0:n.gutters.offsetWidth),s=e.curOp&&null!=e.curOp.scrollLeft?e.curOp.scrollLeft:n.scroller.scrollLeft-r,o=Pn(e)-n.gutters.offsetWidth,i=t.right-t.left>o;return i&&(t.right=t.left+o),t.left<10?l.scrollLeft=0:t.lefto+s-3&&(l.scrollLeft=t.right+(i?0:10)-o),l}function Fr(e,t){null!=t&&(Rr(e),e.curOp.scrollTop=(null==e.curOp.scrollTop?e.doc:e.curOp).scrollTop+t)}function Pr(e){Rr(e);var t=e.getCursor();e.curOp.scrollToPos={from:t,to:t,margin:e.options.cursorScrollMargin}}function Er(e,t,n){null==t&&null==n||Rr(e),null!=t&&(e.curOp.scrollLeft=t),null!=n&&(e.curOp.scrollTop=n)}function Rr(e){var t=e.curOp.scrollToPos;t&&(e.curOp.scrollToPos=null,zr(e,tr(e,t.from),tr(e,t.to),t.margin))}function zr(e,t,n,r){t=Hr(e,{left:Math.min(t.left,n.left),top:Math.min(t.top,n.top)-r,right:Math.max(t.right,n.right),bottom:Math.max(t.bottom,n.bottom)+r});Er(e,t.scrollLeft,t.scrollTop)}function Ir(e,t){Math.abs(e.doc.scrollTop-t)<2||(d||ri(e,{top:t}),Br(e,t,!0),d&&ri(e),Qr(e,100))}function Br(e,t,n){t=Math.max(0,Math.min(e.display.scroller.scrollHeight-e.display.scroller.clientHeight,t)),e.display.scroller.scrollTop==t&&!n||(e.doc.scrollTop=t,e.display.scrollbars.setScrollTop(t),e.display.scroller.scrollTop!=t&&(e.display.scroller.scrollTop=t))}function Gr(e,t,n,r){t=Math.max(0,Math.min(t,e.display.scroller.scrollWidth-e.display.scroller.clientWidth)),(n?t==e.doc.scrollLeft:Math.abs(e.doc.scrollLeft-t)<2)&&!r||(e.doc.scrollLeft=t,li(e),e.display.scroller.scrollLeft!=t&&(e.display.scroller.scrollLeft=t),e.display.scrollbars.setScrollLeft(t))}function Ur(e){var t=e.display,n=t.gutters.offsetWidth,r=Math.round(e.doc.height+Wn(e.display));return{clientHeight:t.scroller.clientHeight,viewHeight:t.wrapper.clientHeight,scrollWidth:t.scroller.scrollWidth,clientWidth:t.scroller.clientWidth,viewWidth:t.wrapper.clientWidth,barLeft:e.options.fixedGutter?n:0,docHeight:r,scrollHeight:r+Fn(e)+t.barHeight,nativeBarWidth:t.nativeBarWidth,gutterWidth:n}}function Vr(e,t,n){this.cm=n;var r=this.vert=M("div",[M("div",null,null,"min-width: 1px")],"CodeMirror-vscrollbar"),i=this.horiz=M("div",[M("div",null,null,"height: 100%; min-height: 1px")],"CodeMirror-hscrollbar");r.tabIndex=i.tabIndex=-1,e(r),e(i),k(r,"scroll",function(){r.clientHeight&&t(r.scrollTop,"vertical")}),k(i,"scroll",function(){i.clientWidth&&t(i.scrollLeft,"horizontal")}),this.checkedZeroWidth=!1,w&&v<8&&(this.horiz.style.minHeight=this.vert.style.minWidth="18px")}function Kr(){}Vr.prototype.update=function(e){var t,n=e.scrollWidth>e.clientWidth+1,r=e.scrollHeight>e.clientHeight+1,i=e.nativeBarWidth;return r?(this.vert.style.display="block",this.vert.style.bottom=n?i+"px":"0",t=e.viewHeight-(n?i:0),this.vert.firstChild.style.height=Math.max(0,e.scrollHeight-e.clientHeight+t)+"px"):(this.vert.scrollTop=0,this.vert.style.display="",this.vert.firstChild.style.height="0"),n?(this.horiz.style.display="block",this.horiz.style.right=r?i+"px":"0",this.horiz.style.left=e.barLeft+"px",t=e.viewWidth-e.barLeft-(r?i:0),this.horiz.firstChild.style.width=Math.max(0,e.scrollWidth-e.clientWidth+t)+"px"):(this.horiz.style.display="",this.horiz.firstChild.style.width="0"),!this.checkedZeroWidth&&0=l.viewTo)||l.maxLineChanged&&o.options.lineWrapping,i.update=i.mustUpdate&&new ei(o,i.mustUpdate&&{top:i.scrollTop,ensure:i.scrollToPos},i.forceUpdate)}for(var s=0;s(i.defaultView.innerHeight||i.documentElement.clientHeight)&&(r=!1),null==r||X||(o=M("div","​",null,"position: absolute;\n top: "+(t.top-n.viewOffset-Dn(e.display))+"px;\n height: "+(t.bottom-t.top+Fn(e)+n.barHeight)+"px;\n left: "+t.left+"px; width: "+Math.max(2,t.right-t.left)+"px;"),e.display.lineSpace.appendChild(o),o.scrollIntoView(r),e.display.lineSpace.removeChild(o)))}(w,v));var S=b.maybeHiddenMarkers,L=b.maybeUnhiddenMarkers;if(S)for(var k=0;k=l.display.viewTo||(s=+new Date+l.options.workTime,a=Wt(l,c.highlightFrontier),u=[],c.iter(a.line,Math.min(c.first+c.size,l.display.viewTo+500),function(e){if(a.line>=l.display.viewFrom){for(var t=e.styles,n=e.text.length>l.options.maxHighlightLength?ft(c.mode,a.state):null,r=At(l,e,a,!0),n=(n&&(a.state=n),e.styles=r.styles,e.styleClasses),r=r.classes,i=(r?e.styleClasses=r:n&&(e.styleClasses=null),!t||t.length!=e.styles.length||n!=r&&(!n||!r||n.bgClass!=r.bgClass||n.textClass!=r.textClass)),o=0;!i&&os)return Qr(l,l.options.workDelay),!0}),c.highlightFrontier=a.line,c.modeFrontier=Math.max(c.modeFrontier,a.line),u.length&&h(l,function(){for(var e=0;e=n.viewFrom&&t.visible.to<=n.viewTo&&(null==n.updateLineNumbers||n.updateLineNumbers>=n.viewTo)&&n.renderedView==n.view&&0==wr(e))return!1;si(e)&&(yr(e),t.dims=hr(e));var i=r.first+r.size,o=Math.max(t.visible.from-e.options.viewportMargin,r.first),l=Math.min(i,t.visible.to+e.options.viewportMargin),r=(n.viewFroml&&n.viewTo-l<20&&(l=Math.min(i,n.viewTo)),Gt&&(o=nn(e.doc,o),l=rn(e.doc,l)),o!=n.viewFrom||l!=n.viewTo||n.lastWrapHeight!=t.wrapperHeight||n.lastWrapWidth!=t.wrapperWidth),i=(i=o,o=l,0==(c=(l=e).display).view.length||i>=c.viewTo||o<=c.viewFrom?(c.view=yn(l,i,o),c.viewFrom=i):(c.viewFrom>i?c.view=yn(l,i,c.viewFrom).concat(c.view):c.viewFromo&&(c.view=c.view.slice(0,mr(l,o)))),c.viewTo=o,n.viewOffset=ln(W(e.doc,n.viewFrom)),e.display.mover.style.top=n.viewOffset+"px",wr(e));if(!r&&0==i&&!t.force&&n.renderedView==n.view&&(null==n.updateLineNumbers||n.updateLineNumbers>=n.viewTo))return!1;var l=function(e){if(e.hasFocus())return null;if(!(n=N(ue(e)))||!re(e.display.lineDiv,n))return null;var t,n={activeElt:n};return window.getSelection&&(t=he(e).getSelection()).anchorNode&&t.extend&&re(e.display.lineDiv,t.anchorNode)&&(n.anchorNode=t.anchorNode,n.anchorOffset=t.anchorOffset,n.focusNode=t.focusNode,n.focusOffset=t.focusOffset),n}(e),s=(4=e.display.viewFrom&&t.visible.to<=e.display.viewTo)break;if(!ti(e,t))break;Ar(e);var i=Ur(e);xr(e),jr(e,i),oi(e,i),t.force=!1}t.signal(e,"update",e),e.display.viewFrom==e.display.reportedViewFrom&&e.display.viewTo==e.display.reportedViewTo||(t.signal(e,"viewportChange",e,e.display.viewFrom,e.display.viewTo),e.display.reportedViewFrom=e.display.viewFrom,e.display.reportedViewTo=e.display.viewTo)}function ri(e,t){var n,t=new ei(e,t);ti(e,t)&&(Ar(e),ni(e,t),n=Ur(e),xr(e),jr(e,n),oi(e,n),t.finish())}function ii(e){var t=e.gutters.offsetWidth;e.sizer.style.marginLeft=t+"px",b(e,"gutterChanged",e)}function oi(e,t){e.display.sizer.style.minHeight=t.docHeight+"px",e.display.heightForcer.style.top=t.docHeight+"px",e.display.gutters.style.height=t.docHeight+e.display.barHeight+Fn(e)+"px"}function li(e){var t=e.display,n=t.view;if(t.alignWidgets||t.gutters.firstChild&&e.options.fixedGutter){for(var r=dr(t)-t.scroller.scrollLeft+e.doc.scrollLeft,i=t.gutters.offsetWidth,o=r+"px",l=0;ll.clientWidth,a=l.scrollHeight>l.clientHeight;if(r&&s||n&&a){if(n&&C&&x)e:for(var u=t.target,c=o.view;u!=l;u=u.parentNode)for(var h=0;hs-(e.cm?e.cm.options.historyEventDelay:500)||"*"==t.origin.charAt(0)))&&(o=(o=l).lastOp==r?(Wi(o.done),z(o.done)):o.done.length&&!z(o.done).ranges?z(o.done):1l.undoDepth;)l.done.shift(),l.done[0].ranges||l.done.shift()}l.done.push(n),l.generation=++l.maxGeneration,l.lastModTime=l.lastSelTime=s,l.lastOp=l.lastSelOp=r,l.lastOrigin=l.lastSelOrigin=t.origin,i||O(e,"historyAdded")}function Fi(e,t,n,r){var i,o,l,s=e.history,a=r&&r.origin;n==s.lastSelOp||a&&s.lastSelOrigin==a&&(s.lastModTime==s.lastSelTime&&s.lastOrigin==a||(e=e,i=a,o=z(s.done),l=t,"*"==(i=i.charAt(0))||"+"==i&&o.ranges.length==l.ranges.length&&o.somethingSelected()==l.somethingSelected()&&new Date-e.history.lastSelTime<=(e.cm?e.cm.options.historyEventDelay:500)))?s.done[s.done.length-1]=t:Pi(t,s.done),s.lastSelTime=+new Date,s.lastSelOrigin=a,s.lastSelOp=n,r&&!1!==r.clearRedo&&Wi(s.undone)}function Pi(e,t){var n=z(t);n&&n.ranges&&n.equals(e)||t.push(e)}function Ei(t,n,e,r){var i=n["spans_"+t.id],o=0;t.iter(Math.max(t.first,e),Math.min(t.first+t.size,r),function(e){e.markedSpans&&((i=i||(n["spans_"+t.id]={}))[o]=e.markedSpans),++o})}function Ri(e,t){var n=t["spans_"+e.id];if(!n)return null;for(var r=[],i=0;i=t.ch:s.to>t.ch))){if(i&&(O(a,"beforeCursorEnter"),a.explicitlyCleared)){if(o.markedSpans){--l;continue}break}if(a.atomic){if(n){var s=a.find(r<0?1:-1),h=void 0;if((s=(r<0?c:u)?Qi(e,s,-r,s&&s.line==t.line?o:null):s)&&s.line==t.line&&(h=P(s,n))&&(r<0?h<0:0e.first?E(e,F(t.line-1)):null:0e.lastLine())){t.from.linei?{from:t.from,to:F(i,W(e,i).text.length),text:[t.text[0]],origin:t.origin}:t).removed=mt(e,t.from,t.to),n=n||xi(e,t),e.cm){var i=e.cm,o=t,l=r,s=i.doc,a=i.display,u=o.from,c=o.to,h=!1,d=u.line,f=(i.options.lineWrapping||(d=H(tn(W(s,u.line))),s.iter(d,c.line+1,function(e){if(e==a.maxLine)return h=!0})),-1a.maxLineLength&&(a.maxLine=e,a.maxLineLength=t,a.maxLineChanged=!0,h=!1)}),h&&(i.curOp.updateMaxLine=!0)),s),p=u.line;if(f.modeFrontier=Math.min(f.modeFrontier,p),!(f.highlightFrontiert.display.maxLineLength&&(t.display.maxLine=u,t.display.maxLineLength=c,t.display.maxLineChanged=!0)}null!=r&&t&&this.collapsed&&R(t,r,i+1),this.lines.length=0,this.explicitlyCleared=!0,this.atomic&&this.doc.cantEdit&&(this.doc.cantEdit=!1,t&&$i(t.doc)),t&&b(t,"markerCleared",t,this,r,i),n&&Zr(t),this.parent&&this.parent.clear()}},mo.prototype.find=function(e,t){var n,r;null==e&&"bookmark"==this.type&&(e=1);for(var i=0;i=e.ch)&&t.push(i.marker.parent||i.marker)}return t},findMarks:function(i,o,l){i=E(this,i),o=E(this,o);var s=[],a=i.line;return this.iter(i.line,o.line+1,function(e){var t=e.markedSpans;if(t)for(var n=0;n=r.to||null==r.from&&a!=i.line||null!=r.from&&a==o.line&&r.from>=o.ch||l&&!l(r.marker)||s.push(r.marker.parent||r.marker)}++a}),s},getAllMarks:function(){var r=[];return this.iter(function(e){var t=e.markedSpans;if(t)for(var n=0;nt&&(t=e.from),null!=e.to&&e.toe.text.length?null:t}function Ko(e,t,n){e=Vo(e,t.ch,n);return null==e?null:new F(t.line,e,n<0?"after":"before")}function jo(e,t,n,r,i){if(e){"rtl"==t.doc.direction&&(i=-i);var o,l,s,a,e=Ve(n,t.doc.direction);if(e)return o=i<0==(1==(e=i<0?z(e):e[0]).level)?"after":"before",0=n.text.length?(s.ch=n.text.length,s.sticky="before"):s.ch<=0&&(s.ch=0,s.sticky="after");var r=Pe(a,s.ch,s.sticky),i=a[r];if("ltr"==t.doc.direction&&i.level%2==0&&(0s.ch:i.from=i.from&&d>=c.begin))return new F(s.line,d,h?"before":"after")}function f(e,t,n){for(var r=function(e,t){return t?new F(s.line,u(e,1),"before"):new F(s.line,e,"after")};0<=e&&el.doc.first&&((n=W(l.doc,e.line-1).text)&&(e=new F(e.line,1),l.replaceRange(t.charAt(0)+l.doc.lineSeparator()+n.charAt(n.length-1),F(e.line-1,n.length-1),e,"+transpose")))),i.push(new G(e,e)));l.setSelections(i)})},newlineAndIndent:function(r){return h(r,function(){for(var e=(t=r.listSelections()).length-1;0<=e;e--)r.replaceRange(r.doc.lineSeparator(),t[e].anchor,t[e].head,"+input");for(var t=r.listSelections(),n=0;nc&&t.push(new G(F(s,c),F(s,we(u,l,n))))}t.length||t.push(new G(f,f)),U(g,vi(d,y.ranges.slice(0,v).concat(t),v),{origin:"*mouse",scroll:!1}),d.scrollIntoView(e)}else{var h,r=m,i=ul(d,e,p.unit),e=r.anchor,e=0=n.to||o.linea.bottom?20:0)&&setTimeout(I(d,function(){u==i&&(l.scroller.scrollTop+=r,e(t))}),50))}:n)(e)}),i=I(d,n);d.state.selectingText=i,k(l.wrapper.ownerDocument,"mousemove",r),k(l.wrapper.ownerDocument,"mouseup",i)})(i,s,o,a)):Qe(e)==h.scroller&&D(e):2==n?(t&&Gi(c.doc,t),setTimeout(function(){return h.input.focus()},20)):3==n&&(Q?c.display.input.onContextMenu(e):Mr(c)))))}function ul(e,t,n){if("char"==n)return new G(t,t);if("word"==n)return e.findWordAt(t);if("line"==n)return new G(F(t.line,0),E(e.doc,F(t.line+1,0)));n=n(e,t);return new G(n.from,n.to)}function cl(e,t,n,r){var i,o;if(t.touches)i=t.touches[0].clientX,o=t.touches[0].clientY;else try{i=t.clientX,o=t.clientY}catch(e){return!1}if(i>=Math.floor(e.display.gutters.getBoundingClientRect().right))return!1;r&&D(t);var l=e.display,r=l.lineDiv.getBoundingClientRect();if(o>r.bottom||!Ye(e,n))return qe(t);o-=r.top-l.viewOffset;for(var s=0;s=i)return O(e,n,e,bt(e.doc,o),e.display.gutterSpecs[s].className,t),qe(t)}}function hl(e,t){return cl(e,t,"gutterClick",!0)}function dl(e,t){var n,r;An(e.display,t)||(r=t,Ye(n=e,"gutterContextMenu")&&cl(n,r,"gutterContextMenu",!1))||A(e,t,"contextmenu")||Q||e.display.input.onContextMenu(t)}function fl(e){e.display.wrapper.className=e.display.wrapper.className.replace(/\s*cm-s-\S+/g,"")+e.options.theme.replace(/(^|\s)\s*/g," cm-s-"),Yn(e)}ol.prototype.compare=function(e,t,n){return this.time+400>e&&0==P(t,this.pos)&&n==this.button};var pl={toString:function(){return"CodeMirror.Init"}},gl={},ml={};function vl(e,t,n){!t!=!(n&&n!=pl)&&(n=e.display.dragFunctions,(t=t?k:T)(e.display.scroller,"dragstart",n.start),t(e.display.scroller,"dragenter",n.enter),t(e.display.scroller,"dragover",n.over),t(e.display.scroller,"dragleave",n.leave),t(e.display.scroller,"drop",n.drop))}function yl(e){e.options.lineWrapping?(ie(e.display.wrapper,"CodeMirror-wrap"),e.display.sizer.style.minWidth="",e.display.sizerWidth=null):(ee(e.display.wrapper,"CodeMirror-wrap"),an(e)),pr(e),R(e),Yn(e),setTimeout(function(){return jr(e)},100)}function p(e,t){var n=this;if(!(this instanceof p))return new p(e,t);this.options=t=t?fe(t):{},fe(gl,t,!1);var r,i=t.value,o=("string"==typeof i?i=new f(i,t.mode,null,t.lineSeparator,t.direction):t.mode&&(i.modeOption=t.mode),this.doc=i,new p.inputStyles[t.inputStyle](this)),e=this.display=new hi(e,i,o,t),l=(fl(e.wrapper.CodeMirror=this),t.lineWrapping&&(this.display.wrapper.className+=" CodeMirror-wrap"),$r(this),this.state={keyMaps:[],overlays:[],modeGen:0,overwrite:!1,delayingBlurEvent:!1,focused:!1,suppressEdits:!1,pasteIncoming:-1,cutIncoming:-1,selectingText:!1,draggingText:!1,highlight:new pe,keySeq:null,specialChars:null},t.autofocus&&!_&&e.input.focus(),w&&v<11&&setTimeout(function(){return n.display.input.reset(!0)},20),this),s=l.display;k(s.scroller,"mousedown",I(l,al)),k(s.scroller,"dblclick",w&&v<11?I(l,function(e){var t;A(l,e)||(!(t=gr(l,e))||hl(l,e)||An(l.display,e)||(D(e),e=l.findWordAt(t),Gi(l.doc,e.anchor,e.head)))}):function(e){return A(l,e)||D(e)}),k(s.scroller,"contextmenu",function(e){return dl(l,e)}),k(s.input.getField(),"contextmenu",function(e){s.scroller.contains(e.target)||dl(l,e)});var a,u={end:0};function c(){s.activeTouch&&(a=setTimeout(function(){return s.activeTouch=null},1e3),(u=s.activeTouch).end=+new Date)}function h(e,t){if(null==t.left)return 1;var n=t.left-e.left,t=t.top-e.top;return 400o.first?S(W(o,t-1).text,null,l):0:"add"==n?c=a+e.options.indentUnit:"subtract"==n?c=a-e.options.indentUnit:"number"==typeof n&&(c=a+n);var c=Math.max(0,c),h="",d=0;if(e.options.indentWithTabs)for(var f=Math.floor(c/l);f;--f)d+=l,h+="\t";if(dl,a=rt(t),u=null;if(s&&1l?"cut":"+input")});to(e.doc,f),b(e,"inputRead",e,f)}t&&!s&&kl(e,t),Pr(e),e.curOp.updateInput<2&&(e.curOp.updateInput=h),e.curOp.typing=!0,e.state.pasteIncoming=e.state.cutIncoming=-1}function Ll(e,t){var n=e.clipboardData&&e.clipboardData.getData("Text");return n&&(e.preventDefault(),t.isReadOnly()||t.options.disableInput||!t.hasFocus()||h(t,function(){return Sl(t,n,0,null,"paste")}),1)}function kl(e,t){if(e.options.electricChars&&e.options.smartIndent)for(var n=e.doc.sel,r=n.ranges.length-1;0<=r;r--){var i=n.ranges[r];if(!(100=n.first+n.size||(r=new F(e,r.ch,r.sticky),!(s=W(n,e))))return;r=jo(l,n.cm,s,r.line,a)}else r=t;return 1}if("char"==o||"codepoint"==o)u();else if("column"==o)u(!0);else if("word"==o||"group"==o)for(var c=null,h="group"==o,d=n.cm&&n.cm.getHelper(r,"wordChars"),f=!0;!(i<0)||u(!f);f=!1){var p=s.text.charAt(r.ch)||"\n",p=Ne(p,d)?"w":h&&"\n"==p?"n":!h||/\s/.test(p)?null:"p";if(!h||f||p||(p="s"),c&&c!=p){i<0&&(i=1,u(),r.sticky="after");break}if(p&&(c=p),0=s.height){l.hitSide=!0;break}o+=5*n}return l}function r(e){this.cm=e,this.lastAnchorNode=this.lastAnchorOffset=this.lastFocusNode=this.lastFocusOffset=null,this.polling=new pe,this.composing=null,this.gracePeriod=!1,this.readDOMTimeout=null}function Dl(e,t){var n=In(e,t.line);if(!n||n.hidden)return null;var r=W(e.doc,t.line),n=Rn(n,r,t.line),r=Ve(r,e.doc.direction),e="left",r=(r&&(e=Pe(r,t.ch)%2?"right":"left"),Kn(n.map,t.ch,e));return r.offset="right"==r.collapse?r.end:r.start,r}function Wl(e,t){return t&&(e.bad=!0),e}function Hl(e,t,n){var r;if(t==e.display.lineDiv){if(!(r=e.display.lineDiv.childNodes[n]))return Wl(e.clipPos(F(e.display.viewTo-1)),!0);t=null,n=0}else for(r=t;;r=r.parentNode){if(!r||r==e.display.lineDiv)return null;if(r.parentNode&&r.parentNode==e.display.lineDiv)break}for(var i=0;i=t.display.viewTo||n.line=t.display.viewFrom&&Dl(t,r)||{node:i[0].measure.map[2],offset:0},r=n.linet.firstLine()&&(i=F(i.line-1,W(t.doc,i.line-1).length)),r.ch==W(t.doc,r.line).text.length&&r.linen.viewTo-1)return!1;var o,l=i.line==n.viewFrom||0==(l=mr(t,i.line))?(e=H(n.view[0].line),n.view[0].node):(e=H(n.view[l].line),n.view[l-1].node.nextSibling),r=mr(t,r.line),n=r==n.view.length-1?(o=n.viewTo-1,n.lineDiv.lastChild):(o=H(n.view[r+1].line)-1,n.view[r+1].node.previousSibling);if(!l)return!1;for(var s=t.doc.splitLines(function(o,e,t,l,s){var n="",a=!1,u=o.doc.lineSeparator(),c=!1;function h(){a&&(n+=u,c&&(n+=u),a=c=!1)}function d(e){e&&(h(),n+=e)}for(;!function e(t){if(1==t.nodeType){var n=t.getAttribute("cm-text");if(n)d(n);else if(n=t.getAttribute("cm-marker"))(n=o.findMarks(F(l,0),F(s+1,0),(i=+n,function(e){return e.id==i}))).length&&(n=n[0].find(0))&&d(mt(o.doc,n.from,n.to).join(u));else if("false"!=t.getAttribute("contenteditable")&&(n=/^(pre|div|p|li|table|br)$/i.test(t.nodeName),/^br$/i.test(t.nodeName)||0!=t.textContent.length)){n&&h();for(var r=0;ri.ch&&p.charCodeAt(p.length-c-1)==g.charCodeAt(g.length-c-1);)u--,c++;s[s.length-1]=p.slice(0,p.length-c).replace(/^\u200b+/,""),s[0]=s[0].slice(u).replace(/\u200b+$/,"");r=F(e,u),l=F(o,a.length?z(a).length-c:0);return 1n&&(wl(this,i.head.line,e,!0),n=i.head.line,r==this.doc.sel.primIndex&&Pr(this));else{for(var o=i.from(),i=i.to(),l=Math.max(n,o.line),n=Math.min(this.lastLine(),i.line-(i.ch?0:1))+1,s=l;s>1;if((l?n[2*l-1]:0)>=o)i=l;else{if(!(n[2*l+1]l)&&e.top>t.offsetHeight?a=e.top-t.offsetHeight:e.bottom+t.offsetHeight<=l&&(a=e.bottom),u+t.offsetWidth>o&&(u=o-t.offsetWidth)),t.style.top=a+"px",t.style.left=t.style.right="","right"==i?(u=s.sizer.clientWidth-t.offsetWidth,t.style.right="0px"):("left"==i?u=0:"middle"==i&&(u=(s.sizer.clientWidth-t.offsetWidth)/2),t.style.left=u+"px"),n&&(r=this,l={left:u,top:a,right:u+t.offsetWidth,bottom:a+t.offsetHeight},null!=(l=Hr(r,l)).scrollTop&&Ir(r,l.scrollTop),null!=l.scrollLeft&&Gr(r,l.scrollLeft))},triggerOnKeyDown:t(nl),triggerOnKeyPress:t(il),triggerOnKeyUp:rl,triggerOnMouseDown:t(al),execCommand:function(e){if(Yo.hasOwnProperty(e))return Yo[e].call(null,this)},triggerElectric:t(function(e){kl(this,e)}),findPosH:function(e,t,n,r){for(var i=1,o=(t<0&&(i=-1,t=-t),E(this.doc,e)),l=0;l!?|~^@]/,J=/^@(context|id|value|language|type|container|list|set|reverse|index|base|vocab|graph)"/;function i(e,t,r){return H=e,D=r,t}function d(e,t){var a,r=e.next();if('"'==r||"'"==r)return t.tokenize=(a=r,function(e,t){var r,n=!1;if(U&&"@"==e.peek()&&e.match(J))return t.tokenize=d,i("jsonld-keyword","meta");for(;null!=(r=e.next())&&(r!=a||n);)n=!n&&"\\"==r;return n||(t.tokenize=d),i("string","string")}),t.tokenize(e,t);if("."==r&&e.match(/^\d[\d_]*(?:[eE][+\-]?[\d_]+)?/))return i("number","number");if("."==r&&e.match(".."))return i("spread","meta");if(/[\[\]{}\(\),;\:\.]/.test(r))return i(r);if("="==r&&e.eat(">"))return i("=>","operator");if("0"==r&&e.match(/^(?:x[\dA-Fa-f_]+|o[0-7_]+|b[01_]+)n?/))return i("number","number");if(/\d/.test(r))return e.match(/^[\d_]*(?:n|(?:\.[\d_]*)?(?:[eE][+\-]?[\d_]+)?)?/),i("number","number");if("/"==r)return e.eat("*")?(t.tokenize=K)(e,t):e.eat("/")?(e.skipToEnd(),i("comment","comment")):tt(e,t,1)?(function(e){for(var t,r=!1,n=!1;null!=(t=e.next());){if(!r){if("/"==t&&!n)return;"["==t?n=!0:n&&"]"==t&&(n=!1)}r=!r&&"\\"==t}}(e),e.match(/^\b(([gimyus])(?![gimyus]*\2))+\b/),i("regexp","string-2")):(e.eat("="),i("operator","operator",e.current()));if("`"==r)return(t.tokenize=L)(e,t);if("#"==r&&"!"==e.peek())return e.skipToEnd(),i("meta","meta");if("#"==r&&e.eatWhile(B))return i("variable","property");if("<"==r&&e.match("!--")||"-"==r&&e.match("->")&&!/\S/.test(e.string.slice(0,e.start)))return e.skipToEnd(),i("comment","comment");if(G.test(r))return">"==r&&t.lexical&&">"==t.lexical.type||(e.eat("=")?"!"!=r&&"="!=r||e.eat("="):/[<>*+\-|&?]/.test(r)&&(e.eat(r),">"==r&&e.eat(r))),"?"==r&&e.eat(".")?i("."):i("operator","operator",e.current());if(B.test(r)){e.eatWhile(B);r=e.current();if("."!=t.lastType){if(F.propertyIsEnumerable(r))return i((t=F[r]).type,t.style,r);if("async"==r&&e.match(/^(\s|\/\*([^*]|\*(?!\/))*?\*\/)*[\[\(\w]/,!1))return i("async","keyword",r)}return i("variable","variable",r)}}function K(e,t){for(var r,n=!1;r=e.next();){if("/"==r&&n){t.tokenize=d;break}n="*"==r}return i("comment","comment")}function L(e,t){for(var r,n=!1;null!=(r=e.next());){if(!n&&("`"==r||"$"==r&&e.eat("{"))){t.tokenize=d;break}n=!n&&"\\"==r}return i("quasi","string-2",e.current())}function Q(e,t){t.fatArrowAt&&(t.fatArrowAt=null);var r=e.string.indexOf("=>",e.start);if(!(r<0)){!u||(n=/:\s*(?:\w+(?:<[^>]*>|\[\])?|\{[^}]*\})\s*$/.exec(e.string.slice(e.start,r)))&&(r=n.index);for(var n,a=0,i=!1,o=r-1;0<=o;--o){var c=e.string.charAt(o),s="([{}])".indexOf(c);if(0<=s&&s<3){if(!a){++o;break}if(0==--a){"("==c&&(i=!0);break}}else if(3<=s&&s<6)++a;else if(B.test(c))i=!0;else if(/["'\/`]/.test(c))for(;;--o){if(0==o)return;if(e.string.charAt(o-1)==c&&"\\"!=e.string.charAt(o-2)){o--;break}}else if(i&&!a){++o;break}}i&&!a&&(t.fatArrowAt=o)}}var R={atom:!0,number:!0,variable:!0,string:!0,regexp:!0,this:!0,import:!0,"jsonld-keyword":!0};function X(e,t,r,n,a,i){this.indented=e,this.column=t,this.type=r,this.prev=a,this.info=i,null!=n&&(this.align=n)}function Y(e,t,r,n,a){var i=e.cc;for(c.state=e,c.stream=a,c.marked=null,c.cc=i,c.style=t,e.lexical.hasOwnProperty("align")||(e.lexical.align=!0);;)if((i.length?i.pop():o?x:b)(r,n)){for(;i.length&&i[i.length-1].lex;)i.pop()();return c.marked?c.marked:"variable"==r&&function(e,t){if(W){for(var r=e.localVars;r;r=r.next)if(r.name==t)return 1;for(var n=e.context;n;n=n.prev)for(r=n.vars;r;r=r.next)if(r.name==t)return 1}}(e,n)?"variable-2":t}}var c={state:null,column:null,marked:null,cc:null};function s(){for(var e=arguments.length-1;0<=e;e--)c.cc.push(arguments[e])}function p(){return s.apply(null,arguments),!0}function Z(e,t){for(var r=t;r;r=r.next)if(r.name==e)return 1}function a(e){var t=c.state;if(c.marked="def",W){if(t.context)if("var"==t.lexical.info&&t.context&&t.context.block){var r=function e(t,r){{var n;return r?r.block?(n=e(t,r.prev))?n==r.prev?r:new te(n,r.vars,!0):null:Z(t,r.vars)?r:new te(r.prev,new re(t,r.vars),!1):null}}(e,t.context);if(null!=r)return void(t.context=r)}else if(!Z(e,t.localVars))return void(t.localVars=new re(e,t.localVars));l.globalVars&&!Z(e,t.globalVars)&&(t.globalVars=new re(e,t.globalVars))}}function ee(e){return"public"==e||"private"==e||"protected"==e||"abstract"==e||"readonly"==e}function te(e,t,r){this.prev=e,this.vars=t,this.block=r}function re(e,t){this.name=e,this.next=t}var ne=new re("this",new re("arguments",null));function m(){c.state.context=new te(c.state.context,c.state.localVars,!1),c.state.localVars=ne}function ae(){c.state.context=new te(c.state.context,c.state.localVars,!0),c.state.localVars=null}function k(){c.state.localVars=c.state.context.vars,c.state.context=c.state.context.prev}function v(n,a){function e(){var e=c.state,t=e.indented;if("stat"==e.lexical.type)t=e.lexical.indented;else for(var r=e.lexical;r&&")"==r.type&&r.align;r=r.prev)t=r.indented;e.lexical=new X(t,c.stream.column(),n,null,e.lexical,a)}return e.lex=!0,e}function y(){var e=c.state;e.lexical.prev&&(")"==e.lexical.type&&(e.indented=e.lexical.indented),e.lexical=e.lexical.prev)}function w(r){return function e(t){return t==r?p():";"==r||"}"==t||")"==t||"]"==t?s():p(e)}}function b(e,t){return"var"==e?p(v("vardef",t),qe,w(";"),y):"keyword a"==e?p(v("form"),oe,b,y):"keyword b"==e?p(v("form"),b,y):"keyword d"==e?c.stream.match(/^\s*$/,!1)?p():p(v("stat"),g,w(";"),y):"debugger"==e?p(w(";")):"{"==e?p(v("}"),ae,be,y,k):";"==e?p():"if"==e?("else"==c.state.lexical.info&&c.state.cc[c.state.cc.length-1]==y&&c.state.cc.pop()(),p(v("form"),oe,b,y,Oe)):"function"==e?p(q):"for"==e?p(v("form"),ae,Pe,b,k,y):"class"==e||u&&"interface"==t?(c.marked="keyword",p(v("form","class"==e?e:t),Fe,y)):"variable"==e?u&&"declare"==t?(c.marked="keyword",p(b)):u&&("module"==t||"enum"==t||"type"==t)&&c.stream.match(/^\s*\w/,!1)?(c.marked="keyword","enum"==t?p(Ze):"type"==t?p(We,w("operator"),z,w(";")):p(v("form"),T,w("{"),v("}"),be,y,y)):u&&"namespace"==t?(c.marked="keyword",p(v("form"),x,b,y)):u&&"abstract"==t?(c.marked="keyword",p(b)):p(v("stat"),me):"switch"==e?p(v("form"),oe,w("{"),v("}","switch"),ae,be,y,y,k):"case"==e?p(x,w(":")):"default"==e?p(w(":")):"catch"==e?p(v("form"),m,ie,b,y,k):"export"==e?p(v("stat"),Ge,y):"import"==e?p(v("stat"),Ke,y):"async"==e?p(b):"@"==t?p(x,b):s(v("stat"),x,w(";"),y)}function ie(e){if("("==e)return p(S,w(")"))}function x(e,t){return ce(e,t,!1)}function h(e,t){return ce(e,t,!0)}function oe(e){return"("!=e?s():p(v(")"),g,w(")"),y)}function ce(e,t,r){if(c.state.fatArrowAt==c.stream.start){var n=r?fe:le;if("("==e)return p(m,v(")"),V(S,")"),y,w("=>"),n,k);if("variable"==e)return s(m,T,w("=>"),n,k)}var a,n=r?M:j;return R.hasOwnProperty(e)?p(n):"function"==e?p(q,n):"class"==e||u&&"interface"==t?(c.marked="keyword",p(v("form"),Be,y)):"keyword c"==e||"async"==e?p(r?h:x):"("==e?p(v(")"),g,w(")"),y,n):"operator"==e||"spread"==e?p(r?h:x):"["==e?p(v("]"),Ye,y,n):"{"==e?we(ve,"}",null,n):"quasi"==e?s(se,n):"new"==e?p((a=r,function(e){return"."==e?p(a?pe:de):"variable"==e&&u?p(Ie,a?M:j):s(a?h:x)})):p()}function g(e){return e.match(/[;\}\)\],]/)?s():s(x)}function j(e,t){return","==e?p(g):M(e,t,!1)}function M(e,t,r){var n=0==r?j:M,a=0==r?x:h;return"=>"==e?p(m,r?fe:le,k):"operator"==e?/\+\+|--/.test(t)||u&&"!"==t?p(n):u&&"<"==t&&c.stream.match(/^([^<>]|<[^<>]*>)*>\s*\(/,!1)?p(v(">"),V(z,">"),y,n):"?"==t?p(x,w(":"),a):p(a):"quasi"==e?s(se,n):";"!=e?"("==e?we(h,")","call",n):"."==e?p(ke,n):"["==e?p(v("]"),g,w("]"),y,n):u&&"as"==t?(c.marked="keyword",p(z,n)):"regexp"==e?(c.state.lastType=c.marked="operator",c.stream.backUp(c.stream.pos-c.stream.start-1),p(a)):void 0:void 0}function se(e,t){return"quasi"!=e?s():"${"!=t.slice(t.length-2)?p(se):p(g,ue)}function ue(e){if("}"==e)return c.marked="string-2",c.state.tokenize=L,p(se)}function le(e){return Q(c.stream,c.state),s("{"==e?b:x)}function fe(e){return Q(c.stream,c.state),s("{"==e?b:h)}function de(e,t){if("target"==t)return c.marked="keyword",p(j)}function pe(e,t){if("target"==t)return c.marked="keyword",p(M)}function me(e){return":"==e?p(y,b):s(j,w(";"),y)}function ke(e){if("variable"==e)return c.marked="property",p()}function ve(e,t){return"async"==e?(c.marked="property",p(ve)):"variable"!=e&&"keyword"!=c.style?"number"==e||"string"==e?(c.marked=U?"property":c.style+" property",p(A)):"jsonld-keyword"==e?p(A):u&&ee(t)?(c.marked="keyword",p(ve)):"["==e?p(x,E,w("]"),A):"spread"==e?p(h,A):"*"==t?(c.marked="keyword",p(ve)):":"==e?s(A):void 0:(c.marked="property","get"==t||"set"==t?p(ye):(u&&c.state.fatArrowAt==c.stream.start&&(e=c.stream.match(/^\s*:\s*/,!1))&&(c.state.fatArrowAt=c.stream.pos+e[0].length),p(A)))}function ye(e){return"variable"!=e?s(A):(c.marked="property",p(q))}function A(e){return":"==e?p(h):"("==e?s(q):void 0}function V(n,a,i){function o(e,t){var r;return(i?-1"),z):"quasi"==e?s(Ve,I):void 0}function je(e){if("=>"==e)return p(z)}function Me(e){return e.match(/[\}\)\]]/)?p():","==e||";"==e?p(Me):s(Ae,Me)}function Ae(e,t){return"variable"==e||"keyword"==c.style?(c.marked="property",p(Ae)):"?"==t||"number"==e||"string"==e?p(Ae):":"==e?p(z):"["==e?p(w("variable"),xe,w("]"),Ae):"("==e?s(C,Ae):e.match(/[;\}\)\],]/)?void 0:p()}function Ve(e,t){return"quasi"!=e?s():"${"!=t.slice(t.length-2)?p(Ve):p(z,Ee)}function Ee(e){if("}"==e)return c.marked="string-2",c.state.tokenize=L,p(Ve)}function ze(e,t){return"variable"==e&&c.stream.match(/^\s*[?:]/,!1)||"?"==t?p(ze):":"==e?p(z):"spread"==e?p(ze):s(z)}function I(e,t){return"<"==t?p(v(">"),V(z,">"),y,I):"|"==t||"."==e||"&"==t?p(z):"["==e?p(z,w("]"),I):"extends"==t||"implements"==t?(c.marked="keyword",p(z)):"?"==t?p(z,w(":"),z):void 0}function Ie(e,t){if("<"==t)return p(v(">"),V(z,">"),y,I)}function Te(){return s(z,$e)}function $e(e,t){if("="==t)return p(z)}function qe(e,t){return"enum"==t?(c.marked="keyword",p(Ze)):s(T,E,$,_e)}function T(e,t){return u&&ee(t)?(c.marked="keyword",p(T)):"variable"==e?(a(t),p()):"spread"==e?p(T):"["==e?we(Se,"]"):"{"==e?we(Ce,"}"):void 0}function Ce(e,t){return"variable"!=e||c.stream.match(/^\s*:/,!1)?("variable"==e&&(c.marked="property"),"spread"==e?p(T):"}"==e?s():"["==e?p(x,w("]"),w(":"),Ce):p(w(":"),T,$)):(a(t),p($))}function Se(){return s(T,$)}function $(e,t){if("="==t)return p(h)}function _e(e){if(","==e)return p(qe)}function Oe(e,t){if("keyword b"==e&&"else"==t)return p(v("form","else"),b,y)}function Pe(e,t){return"await"==t?p(Pe):"("==e?p(v(")"),Ne,y):void 0}function Ne(e){return"var"==e?p(qe,Ue):("variable"==e?p:s)(Ue)}function Ue(e,t){return")"==e?p():";"==e?p(Ue):"in"==t||"of"==t?(c.marked="keyword",p(x,Ue)):s(x,Ue)}function q(e,t){return"*"==t?(c.marked="keyword",p(q)):"variable"==e?(a(t),p(q)):"("==e?p(m,v(")"),V(S,")"),y,he,b,k):u&&"<"==t?p(v(">"),V(Te,">"),y,q):void 0}function C(e,t){return"*"==t?(c.marked="keyword",p(C)):"variable"==e?(a(t),p(C)):"("==e?p(m,v(")"),V(S,")"),y,he,k):u&&"<"==t?p(v(">"),V(Te,">"),y,C):void 0}function We(e,t){return"keyword"==e||"variable"==e?(c.marked="type",p(We)):"<"==t?p(v(">"),V(Te,">"),y):void 0}function S(e,t){return"@"==t&&p(x,S),"spread"==e?p(S):u&&ee(t)?(c.marked="keyword",p(S)):u&&"this"==e?p(E,$):s(T,E,$)}function Be(e,t){return("variable"==e?Fe:He)(e,t)}function Fe(e,t){if("variable"==e)return a(t),p(He)}function He(e,t){return"<"==t?p(v(">"),V(Te,">"),y,He):"extends"==t||"implements"==t||u&&","==e?("implements"==t&&(c.marked="keyword"),p(u?z:x,He)):"{"==e?p(v("}"),_,y):void 0}function _(e,t){return"async"==e||"variable"==e&&("static"==t||"get"==t||"set"==t||u&&ee(t))&&c.stream.match(/^\s+#?[\w$\xa1-\uffff]/,!1)?(c.marked="keyword",p(_)):"variable"==e||"keyword"==c.style?(c.marked="property",p(De,_)):"number"==e||"string"==e?p(De,_):"["==e?p(x,E,w("]"),De,_):"*"==t?(c.marked="keyword",p(_)):u&&"("==e?s(C,_):";"==e||","==e?p(_):"}"==e?p():"@"==t?p(x,_):void 0}function De(e,t){if("!"==t)return p(De);if("?"==t)return p(De);if(":"==e)return p(z,$);if("="==t)return p(h);e=c.state.lexical.prev;return s(e&&"interface"==e.info?C:q)}function Ge(e,t){return"*"==t?(c.marked="keyword",p(Xe,w(";"))):"default"==t?(c.marked="keyword",p(x,w(";"))):"{"==e?p(V(Je,"}"),Xe,w(";")):s(b)}function Je(e,t){return"as"==t?(c.marked="keyword",p(w("variable"))):"variable"==e?s(h,Je):void 0}function Ke(e){return"string"==e?p():"("==e?s(x):"."==e?s(j):s(Le,Qe,Xe)}function Le(e,t){return"{"==e?we(Le,"}"):("variable"==e&&a(t),"*"==t&&(c.marked="keyword"),p(Re))}function Qe(e){if(","==e)return p(Le,Qe)}function Re(e,t){if("as"==t)return c.marked="keyword",p(Le)}function Xe(e,t){if("from"==t)return c.marked="keyword",p(x)}function Ye(e){return"]"==e?p():s(V(h,"]"))}function Ze(){return s(v("form"),T,w("{"),v("}"),V(et,"}"),y,y)}function et(){return s(T,$)}function tt(e,t,r){return t.tokenize==d&&/^(?:operator|sof|keyword [bcd]|case|new|export|default|spread|[\[{}\(,;:]|=>)$/.test(t.lastType)||"quasi"==t.lastType&&/\{\s*$/.test(e.string.slice(0,e.pos-(r||0)))}return m.lex=ae.lex=!0,y.lex=k.lex=!0,{startState:function(e){e={tokenize:d,lastType:"sof",cc:[],lexical:new X((e||0)-f,0,"block",!1),localVars:l.localVars,context:l.localVars&&new te(null,null,!1),indented:e||0};return l.globalVars&&"object"==typeof l.globalVars&&(e.globalVars=l.globalVars),e},token:function(e,t){if(e.sol()&&(t.lexical.hasOwnProperty("align")||(t.lexical.align=!1),t.indented=e.indentation(),Q(e,t)),t.tokenize!=K&&e.eatSpace())return null;var r=t.tokenize(e,t);return"comment"==H?r:(t.lastType="operator"!=H||"++"!=D&&"--"!=D?H:"incdec",Y(t,r,H,D,e))},indent:function(e,t){if(e.tokenize==K||e.tokenize==L)return rt.Pass;if(e.tokenize!=d)return 0;var r,n=t&&t.charAt(0),a=e.lexical;if(!/^\s*else\b/.test(t))for(var i=e.cc.length-1;0<=i;--i){var o=e.cc[i];if(o==y)a=a.prev;else if(o!=Oe&&o!=k)break}for(;("stat"==a.type||"form"==a.type)&&("}"==n||(r=e.cc[e.cc.length-1])&&(r==j||r==M)&&!/^[,\.=+\-*:?[\(]/.test(t));)a=a.prev;var c,s=(a=N&&")"==a.type&&"stat"==a.prev.type?a.prev:a).type,u=n==s;return"vardef"==s?a.indented+("operator"==e.lastType||","==e.lastType?a.info.length+1:0):"form"==s&&"{"==n?a.indented:"form"==s?a.indented+f:"stat"==s?a.indented+(s=t,"operator"==(c=e).lastType||","==c.lastType||G.test(s.charAt(0))||/[,.]/.test(s.charAt(0))?N||f:0):"switch"!=a.info||u||0==l.doubleIndentSwitch?a.align?a.column+(u?0:1):a.indented+(u?0:f):a.indented+(/^(?:case|default)\b/.test(t)?f:2*f)},electricInput:/^\s*(?:case .*?:|default:|\{|\})$/,blockCommentStart:o?null:"/*",blockCommentEnd:o?null:"*/",blockCommentContinue:o?null:" * ",lineComment:o?null:"//",fold:"brace",closeBrackets:"()[]{}''\"\"``",helperType:o?"json":"javascript",jsonldMode:U,jsonMode:o,expressionAllowed:tt,skipExpression:function(e){Y(e,"atom","atom","true",new rt.StringStream("",2,null))}}}),rt.registerHelper("wordChars","javascript",/[\w$]/),rt.defineMIME("text/javascript","javascript"),rt.defineMIME("text/ecmascript","javascript"),rt.defineMIME("application/javascript","javascript"),rt.defineMIME("application/x-javascript","javascript"),rt.defineMIME("application/ecmascript","javascript"),rt.defineMIME("application/json",{name:"javascript",json:!0}),rt.defineMIME("application/x-json",{name:"javascript",json:!0}),rt.defineMIME("application/manifest+json",{name:"javascript",json:!0}),rt.defineMIME("application/ld+json",{name:"javascript",jsonld:!0}),rt.defineMIME("text/typescript",{name:"javascript",typescript:!0}),rt.defineMIME("application/typescript",{name:"javascript",typescript:!0})}); \ No newline at end of file diff --git a/luci-app-clashoo/htdocs/luci-static/resources/cm/mode/yaml.js b/luci-app-clashoo/htdocs/luci-static/resources/cm/mode/yaml.js new file mode 100644 index 000000000..a38d604c4 --- /dev/null +++ b/luci-app-clashoo/htdocs/luci-static/resources/cm/mode/yaml.js @@ -0,0 +1 @@ +!function(e){"object"==typeof exports&&"object"==typeof module?e(require("../../lib/codemirror")):"function"==typeof define&&define.amd?define(["../../lib/codemirror"],e):e(CodeMirror)}(function(e){"use strict";e.defineMode("yaml",function(){var n=new RegExp("\\b(("+["true","false","on","off","yes","no"].join(")|(")+"))$","i");return{token:function(e,i){var t=e.peek(),r=i.escaped;if(i.escaped=!1,"#"==t&&(0==e.pos||/\s/.test(e.string.charAt(e.pos-1))))return e.skipToEnd(),"comment";if(e.match(/^('([^']|\\.)*'?|"([^"]|\\.)*"?)/))return"string";if(i.literal&&e.indentation()>i.keyCol)return e.skipToEnd(),"string";if(i.literal&&(i.literal=!1),e.sol()){if(i.keyCol=0,i.pair=!1,i.pairStart=!1,e.match("---"))return"def";if(e.match("..."))return"def";if(e.match(/\s*-\s+/))return"meta"}if(e.match(/^(\{|\}|\[|\])/))return"{"==t?i.inlinePairs++:"}"==t?i.inlinePairs--:"["==t?i.inlineList++:i.inlineList--,"meta";if(0)\s*/))return i.literal=!0,"meta";if(e.match(/^\s*(\&|\*)[a-z0-9\._-]+\b/i))return"variable-2";if(0==i.inlinePairs&&e.match(/^\s*-?[0-9\.\,]+\s?$/))return"number";if(0'"%@`][^\s'":]|[^\s,\[\]{}#&*!|>'"%@`])[^#:]*(?=:($|\s))/)?(i.pair=!0,i.keyCol=e.indentation(),"atom"):i.pair&&e.match(/^:\s*/)?(i.pairStart=!0,"meta"):(i.pairStart=!1,i.escaped="\\"==t,e.next(),null)},startState:function(){return{pair:!1,pairStart:!1,keyCol:0,inlinePairs:0,inlineList:0,literal:!1,escaped:!1}},lineComment:"#",fold:"indent"}}),e.defineMIME("text/x-yaml","yaml"),e.defineMIME("text/yaml","yaml")}); \ No newline at end of file diff --git a/luci-app-clashoo/htdocs/luci-static/resources/tools/clashoo.js b/luci-app-clashoo/htdocs/luci-static/resources/tools/clashoo.js new file mode 100644 index 000000000..940623222 --- /dev/null +++ b/luci-app-clashoo/htdocs/luci-static/resources/tools/clashoo.js @@ -0,0 +1,264 @@ +'use strict'; +'require baseclass'; +'require rpc'; +'require ui'; + +(function () { + if (document.getElementById('clashoo-toast-style')) return; + var css = [ + '#clashoo-toast-stack{position:fixed;top:20px;right:20px;z-index:99999;display:flex;flex-direction:column;gap:8px;max-width:380px;pointer-events:none;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI","PingFang SC",sans-serif}', + '.clashoo-toast{background:rgba(33,37,41,.92);color:#fff;font-size:13px;line-height:1.5;padding:10px 14px;border-radius:8px;box-shadow:0 4px 14px rgba(0,0,0,.18);opacity:0;transform:translateX(24px);transition:opacity .25s ease,transform .25s ease;pointer-events:auto;cursor:pointer;word-break:break-word}', + '.clashoo-toast.show{opacity:1;transform:translateX(0)}', + '.clashoo-toast.err{background:rgba(198,40,40,.94)}', + '.clashoo-toast.ok{background:rgba(46,125,50,.94)}', + '.clashoo-toast a{color:#8ec5ff;text-decoration:underline}', + '.clashoo-toast a:hover{color:#b3d7ff}' + ].join(''); + var s = document.createElement('style'); + s.id = 'clashoo-toast-style'; + s.textContent = css; + document.head.appendChild(s); +})(); + +function _clashooToastStack() { + var el = document.getElementById('clashoo-toast-stack'); + if (!el) { + el = document.createElement('div'); + el.id = 'clashoo-toast-stack'; + document.body.appendChild(el); + } + return el; +} + +function _clashooLinkify(safeText) { + var logUrl = L.url('admin/services/clashoo/system'); + return safeText.replace(/(进度|日志)/g, + '
    $1'); +} + +function _clashooToast(msg, opts) { + opts = opts || {}; + var stack = _clashooToastStack(); + var el = document.createElement('div'); + el.className = 'clashoo-toast' + (opts.kind ? ' ' + opts.kind : ''); + var text; + if (msg && msg.nodeType === 1) text = msg.textContent || ''; + else if (typeof msg === 'string') text = msg; + else text = String(msg || ''); + var safe = text.replace(/&/g, '&').replace(//g, '>'); + el.innerHTML = _clashooLinkify(safe); + stack.appendChild(el); + requestAnimationFrame(function () { el.classList.add('show'); }); + + var dur = opts.duration || 3500; + var timer = null, remain = dur, start = 0; + function close() { + if (timer) { clearTimeout(timer); timer = null; } + el.classList.remove('show'); + setTimeout(function () { if (el.parentNode) el.parentNode.removeChild(el); }, 280); + } + function arm() { start = Date.now(); timer = setTimeout(close, remain); } + el.addEventListener('mouseenter', function () { + if (timer) { clearTimeout(timer); timer = null; remain = Math.max(800, remain - (Date.now() - start)); } + }); + el.addEventListener('mouseleave', arm); + el.addEventListener('click', function (ev) { + if (ev.target && ev.target.tagName === 'A') return; + close(); + }); + arm(); + return { close: close }; +} + +(function () { + if (!ui || ui._clashooPatched) return; + ui._clashooPatched = true; + var orig = ui.addNotification.bind(ui); + ui.addNotification = function (title, children, classes) { + try { + var text = ''; + var collect = function (c) { + if (c == null) return; + if (Array.isArray(c)) { c.forEach(collect); return; } + if (c.nodeType === 1) { text += (c.textContent || '') + ' '; return; } + text += String(c) + ' '; + }; + if (title) text += title + ' '; + collect(children); + text = text.trim(); + + var kind = ''; + var cls = classes ? String(classes) : ''; + if (/error|danger/i.test(cls) || /失败|错误/.test(text)) kind = 'err'; + else if (/success/i.test(cls) || /成功/.test(text)) kind = 'ok'; + + _clashooToast(text, { kind: kind }); + return null; + } catch (e) { + return orig(title, children, classes); + } + }; +})(); + +const callStatus = rpc.declare({ object: 'luci.clashoo', method: 'status', expect: {} }); +const callStart = rpc.declare({ object: 'luci.clashoo', method: 'start', expect: {} }); +const callStop = rpc.declare({ object: 'luci.clashoo', method: 'stop', expect: {} }); +const callReload = rpc.declare({ object: 'luci.clashoo', method: 'reload', expect: {} }); +const callRestart = rpc.declare({ object: 'luci.clashoo', method: 'restart', expect: {} }); +const callVersion = rpc.declare({ object: 'luci.clashoo', method: 'version', expect: {} }); +const callListProf = rpc.declare({ object: 'luci.clashoo', method: 'list_profiles', expect: {} }); +const callListConfigs = rpc.declare({ object: 'luci.clashoo', method: 'list_configs', expect: {} }); +const callSetConfig = rpc.declare({ object: 'luci.clashoo', method: 'set_config', params: ['name'], expect: {} }); +const callSetMode = rpc.declare({ object: 'luci.clashoo', method: 'set_mode', params: ['mode'], expect: {} }); +const callSetProxyMode = rpc.declare({ object: 'luci.clashoo', method: 'set_proxy_mode', params: ['mode'], expect: {} }); +const callSetCore = rpc.declare({ object: 'luci.clashoo', method: 'set_core', params: ['core', 'dcore', 'action'], expect: {} }); +const callSetPanel = rpc.declare({ object: 'luci.clashoo', method: 'set_panel', params: ['name'], expect: {} }); +const callUpdatePanel = rpc.declare({ object: 'luci.clashoo', method: 'update_panel', params: ['name'], expect: {} }); +const callPanelStatus = rpc.declare({ object: 'luci.clashoo', method: 'panel_status', expect: {} }); +const callReadLog = rpc.declare({ object: 'luci.clashoo', method: 'read_log', expect: {} }); +const callReadRealLog = rpc.declare({ object: 'luci.clashoo', method: 'read_real_log', expect: {} }); +const callClearLog = rpc.declare({ object: 'luci.clashoo', method: 'clear_log', expect: {} }); +const callReadUpdateLog = rpc.declare({ object: 'luci.clashoo', method: 'read_update_log', expect: {} }); +const callClearUpdateLog= rpc.declare({ object: 'luci.clashoo', method: 'clear_update_log', expect: {} }); +const callReadGeoipLog = rpc.declare({ object: 'luci.clashoo', method: 'read_geoip_log', expect: {} }); +const callClearGeoipLog = rpc.declare({ object: 'luci.clashoo', method: 'clear_geoip_log', expect: {} }); +const callReadCoreLog = rpc.declare({ object: 'luci.clashoo', method: 'read_core_log', expect: {} }); +const callClearCoreLog = rpc.declare({ object: 'luci.clashoo', method: 'clear_core_log', expect: {} }); +const callReadUpdateMergedLog = rpc.declare({ object: 'luci.clashoo', method: 'read_update_merged_log', expect: {} }); +const callClearUpdateMergedLog = rpc.declare({ object: 'luci.clashoo', method: 'clear_update_merged_log', expect: {} }); +const callGetCpuArch = rpc.declare({ object: 'luci.clashoo', method: 'get_cpu_arch', expect: {} }); +const callDownloadCore = rpc.declare({ object: 'luci.clashoo', method: 'download_core', expect: {} }); +const callUpdateGeoip = rpc.declare({ object: 'luci.clashoo', method: 'update_geoip', expect: {} }); +const callGetGeoipVersion = rpc.declare({ object: 'luci.clashoo', method: 'get_geoip_version', expect: {} }); +const callComponentStatus = rpc.declare({ object: 'luci.clashoo', method: 'component_status', expect: {} }); +const callComponentUpdate = rpc.declare({ object: 'luci.clashoo', method: 'component_update', params: ['component', 'variant'], expect: {} }); +const callComponentUpdateLog = rpc.declare({ object: 'luci.clashoo', method: 'component_update_log', expect: {} }); +const callComponentCheckUpdates = rpc.declare({ object: 'luci.clashoo', method: 'component_check_updates', expect: {} }); +const callUpdateChinaIp = rpc.declare({ object: 'luci.clashoo', method: 'update_china_ip', expect: {} }); +const callGetLogStatus = rpc.declare({ object: 'luci.clashoo', method: 'get_log_status', expect: {} }); +const callAccessCheck = rpc.declare({ object: 'luci.clashoo', method: 'access_check', expect: {} }); +const callAccessCheckRefresh= rpc.declare({ object: 'luci.clashoo', method: 'access_check_refresh',expect: {} }); +const callOverviewStats = rpc.declare({ object: 'luci.clashoo', method: 'overview_stats', expect: {} }); +const callOverview = rpc.declare({ object: 'luci.clashoo', method: 'overview', expect: {} }); +const callSmartFlushCache = rpc.declare({ object: 'luci.clashoo', method: 'smart_flush_cache', expect: {} }); +const callListSingboxProfiles = rpc.declare({ object: 'luci.clashoo', method: 'list_singbox_profiles', expect: {} }); +const callGetSingboxProfile = rpc.declare({ object: 'luci.clashoo', method: 'get_singbox_profile', params: ['name'], expect: {} }); +const callSaveSingboxProfileChunk = rpc.declare({ object: 'luci.clashoo', method: 'save_singbox_profile_chunk', params: ['name', 'content', 'index', 'total'], expect: {} }); +const callSetSingboxProfile = rpc.declare({ object: 'luci.clashoo', method: 'set_singbox_profile', params: ['name'], expect: {} }); +const callDeleteSingboxProfile = rpc.declare({ object: 'luci.clashoo', method: 'delete_singbox_profile', params: ['name'], expect: {} }); +const callCreateSingboxConfig = rpc.declare({ object: 'luci.clashoo', method: 'create_singbox_config', params: ['sub_url', 'name'], expect: {} }); +const callCommitConfig = rpc.declare({ object: 'luci.clashoo', method: 'commit_config', expect: {} }); +const callDnsAutoSetup = rpc.declare({ object: 'luci.clashoo', method: 'dns_auto_setup', expect: {} }); +const callFetchSingboxNative = rpc.declare({ object: 'luci.clashoo', method: 'fetch_singbox_native', params: ['url', 'name'], expect: {} }); +const callUpdateSingboxNative = rpc.declare({ object: 'luci.clashoo', method: 'update_singbox_native', params: ['name'], expect: {} }); + +// 把脚本输出的英文 log 行翻成中文(去掉前导时间戳) +function localizeLogLine(line) { + var msg = String(line || '').replace(/^\s*\d{4}-\d{2}-\d{2}\s+\d{2}:\d{2}:\d{2}\s*-?\s*/, ''); + var rules = [ + // LightGBM 模型更新 + [/^Start downloading LightGBM model from:?\s*(.*)$/i, _("Start downloading LightGBM model: $1")], + [/^Model unchanged, no update needed$/i, _("Model is already up to date")], + [/^LightGBM model updated successfully$/i, _("LightGBM model updated successfully")], + [/^Download failed \(rc=(\d+)\)$/i, _("Download failed (error code $1)")], + [/^Failed to install model to (.*)$/i, _("Model install failed: $1")], + [/^No curl or wget found$/i, _("curl or wget not found")], + // GeoIP / GeoSite 更新 + [/^Updating (.+)$/i, _("Updating $1")], + [/^(.+) updated$/i, _("$1 updated")], + [/^GeoIP update completed, apply on next Clashoo restart$/i, _("GeoIP update completed, applies after Clashoo restarts")], + [/^GeoIP update completed$/i, _("GeoIP update completed")], + [/^GeoIP update failed$/i, _("GeoIP update failed")], + // 通用 + [/^Download succeeded$/i, _("Download succeeded")], + [/^Already up to date$/i, _("Already up to date")] + ]; + for (var i = 0; i < rules.length; i++) { + if (rules[i][0].test(msg)) return msg.replace(rules[i][0], rules[i][1]); + } + return msg; +} + +return baseclass.extend({ + localizeLogLine: localizeLogLine, + status: function () { return L.resolveDefault(callStatus(), {}); }, + start: function () { return L.resolveDefault(callStart(), {}); }, + stop: function () { return L.resolveDefault(callStop(), {}); }, + reload: function () { return L.resolveDefault(callReload(), {}); }, + restart: function () { return L.resolveDefault(callRestart(), {}); }, + version: function () { return L.resolveDefault(callVersion(), {}); }, + + listProfiles: function () { return L.resolveDefault(callListProf(), { profiles: [] }).then(r => r.profiles || []); }, + listConfigs: function () { return L.resolveDefault(callListConfigs(), { configs: [], current: '' }); }, + setConfig: function (name) { return L.resolveDefault(callSetConfig(name), {}); }, + setMode: function (mode) { return L.resolveDefault(callSetMode(mode), {}); }, + setProxyMode: function (mode) { return L.resolveDefault(callSetProxyMode(mode), {}); }, + setCore: function (core, dcore, action) { return L.resolveDefault(callSetCore(core, dcore, action), {}); }, + setPanel: function (name) { return L.resolveDefault(callSetPanel(name), {}); }, + updatePanel: function (name) { return L.resolveDefault(callUpdatePanel(name || 'zashboard'), {}); }, + panelStatus: function () { return L.resolveDefault(callPanelStatus(), {}); }, + + readLog: function () { return L.resolveDefault(callReadLog(), { content: '' }).then(r => r.content || ''); }, + readRealLog: function () { return L.resolveDefault(callReadRealLog(), { content: '' }).then(r => r.content || ''); }, + clearLog: function () { return L.resolveDefault(callClearLog(), {}); }, + readUpdateLog: function () { return L.resolveDefault(callReadUpdateLog(), { content: '' }).then(r => r.content || ''); }, + clearUpdateLog: function () { return L.resolveDefault(callClearUpdateLog(), {}); }, + readGeoipLog: function () { return L.resolveDefault(callReadGeoipLog(), { content: '' }).then(r => r.content || ''); }, + clearGeoipLog: function () { return L.resolveDefault(callClearGeoipLog(), {}); }, + readCoreLog: function () { return L.resolveDefault(callReadCoreLog(), { content: '' }).then(r => r.content || ''); }, + clearCoreLog: function () { return L.resolveDefault(callClearCoreLog(), {}); }, + readUpdateMergedLog: function () { return L.resolveDefault(callReadUpdateMergedLog(), { content: '' }).then(r => r.content || ''); }, + clearUpdateMergedLog: function () { return L.resolveDefault(callClearUpdateMergedLog(), {}); }, + + getCpuArch: function () { return L.resolveDefault(callGetCpuArch(), { arch: '' }).then(r => r.arch || ''); }, + downloadCore: function (dcore, arch) { return L.resolveDefault(callDownloadCore({ dcore: dcore, arch: arch }), {}); }, + updateGeoip: function () { return L.resolveDefault(callUpdateGeoip(), {}); }, + getGeoipVersion: function () { return L.resolveDefault(callGetGeoipVersion(), { version: '' }); }, + componentStatus: function () { return L.resolveDefault(callComponentStatus(), { running: false, components: [] }); }, + componentUpdate: function (component, variant) { return L.resolveDefault(callComponentUpdate(component, variant || ''), { success: false }); }, + componentUpdateLog: function () { return L.resolveDefault(callComponentUpdateLog(), { running: false, content: '' }); }, + componentCheckUpdates: function () { return L.resolveDefault(callComponentCheckUpdates(), { ok: false, latest: {} }); }, + updateChinaIp: function () { return L.resolveDefault(callUpdateChinaIp(), {}); }, + getLogStatus: function () { return L.resolveDefault(callGetLogStatus(), {}); }, + accessCheck: function () { return L.resolveDefault(callAccessCheck(), {}); }, + accessCheckRefresh: function () { return L.resolveDefault(callAccessCheckRefresh(), { success: false }); }, + overviewStats: function () { return L.resolveDefault(callOverviewStats(), {}); }, + overview: function () { + return L.resolveDefault(callOverview(), { + status: {}, + stats: {}, + configs: { configs: [], current: '', core_type: '' }, + access: {} + }); + }, + smartFlushCache: function () { return L.resolveDefault(callSmartFlushCache(), { success: false }); }, + + listSingboxProfiles: function () { return L.resolveDefault(callListSingboxProfiles(), { profiles: [], active: '' }); }, + getSingboxProfile: function (name) { return L.resolveDefault(callGetSingboxProfile(name), {}); }, + saveSingboxProfile: function (name, content) { + var chunkSize = 24576; + var total = Math.max(1, Math.ceil((content || '').length / chunkSize)); + var index = 0; + + function sendNext() { + var chunk = (content || '').slice(index * chunkSize, (index + 1) * chunkSize); + return L.resolveDefault(callSaveSingboxProfileChunk(name, chunk, String(index), String(total)), {}).then(function (r) { + if (!r || !r.success) + return { success: false, error: (r && r.error) || 'upload_failed', message: (r && (r.message || r.error)) || _('Upload failed') }; + index++; + return index < total ? sendNext() : r; + }); + } + + return sendNext(); + }, + setSingboxProfile: function (name) { return L.resolveDefault(callSetSingboxProfile(name), {}); }, + deleteSingboxProfile: function (name) { return L.resolveDefault(callDeleteSingboxProfile(name), {}); }, + createSingboxConfig: function (url, name) { return L.resolveDefault(callCreateSingboxConfig(url, name), {}); }, + commitConfig: function () { return L.resolveDefault(callCommitConfig(), { success: false }); }, + dnsAutoSetup: function () { return L.resolveDefault(callDnsAutoSetup(), { success: false }); }, + fetchSingboxNative: function (url, name) { return L.resolveDefault(callFetchSingboxNative(url, name), {}); }, + updateSingboxNative: function (name) { return L.resolveDefault(callUpdateSingboxNative(name), {}); }, + + toast: _clashooToast +}); diff --git a/luci-app-clashoo/htdocs/luci-static/resources/view/clashoo/bytedance.svg b/luci-app-clashoo/htdocs/luci-static/resources/view/clashoo/bytedance.svg new file mode 100644 index 000000000..6bc2d5ecb --- /dev/null +++ b/luci-app-clashoo/htdocs/luci-static/resources/view/clashoo/bytedance.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/luci-app-clashoo/htdocs/luci-static/resources/view/clashoo/clashoo.css b/luci-app-clashoo/htdocs/luci-static/resources/view/clashoo/clashoo.css new file mode 100644 index 000000000..5587a0896 --- /dev/null +++ b/luci-app-clashoo/htdocs/luci-static/resources/view/clashoo/clashoo.css @@ -0,0 +1,2097 @@ +.cl-wrap { + --cl-primary-rgb: 0, 122, 255; + --primary-rgb: var(--cl-primary-rgb); + --cl-primary: var(--primary-color, rgba(var(--primary-rgb), 0.9)); + --cl-primary-border: rgba(var(--primary-rgb), 0.3); + --cl-primary-soft: rgba(var(--primary-rgb), 0.08); + --cl-primary-soft-hover: rgba(var(--primary-rgb), 0.14); + --cl-card-bg: rgba(128, 128, 128, 0.04); + --cl-card-border: rgba(128, 128, 128, 0.14); + --cl-surface-border: rgba(128, 128, 128, 0.14); + --cl-card-shadow: var(--card-shadow, 0 4px 20px rgba(0, 0, 0, 0.05)); + --cl-card-shadow-hover: var(--card-shadow, 0 4px 20px rgba(0, 0, 0, 0.05)); + --cl-radius: var(--border-radius, 12px); + --cl-title-color: var(--title-color, inherit); + --cl-field-color: var(--text-color, inherit); + --cl-placeholder: rgba(80, 88, 100, 0.55); + --cl-control-border: rgba(128, 128, 128, 0.18); + --cl-control-bg: rgba(128, 128, 128, 0.05); + --cl-input-bg: rgba(128, 128, 128, 0.05); + --cl-input-border: rgba(128, 128, 128, 0.2); + --cl-input-color: var(--text-color, inherit); + --cl-label-muted: var(--text-color, inherit); + --cl-live-shell-bg: rgba(128, 128, 128, 0.04); + --cl-live-card-bg: rgba(128, 128, 128, 0.05); + --cl-live-border: rgba(128, 128, 128, 0.14); + --cl-live-title: var(--title-color, inherit); + --cl-live-main: var(--text-color, inherit); + --cl-live-sub: var(--text-color, inherit); + --cl-live-foot: var(--text-color, inherit); + --cl-live-muted: rgba(var(--primary-rgb), 0.35); + --cl-live-zero: rgba(128, 128, 128, 0.5); + --cl-live-dot: var(--primary-color, rgba(var(--primary-rgb), 0.9)); + --cl-warn-color: var(--warning-color, var(--primary-color, rgba(var(--primary-rgb), 0.9))); + --cl-danger-color: var(--error-color, rgba(214, 92, 74, 0.95)); + --cl-chart-up: rgba(var(--primary-rgb), 0.86); + --cl-chart-down: rgba(var(--primary-rgb), 0.72); + --cl-chart-conn: rgba(var(--primary-rgb), 0.6); +} + +.cl-wrap.cl-theme-dark { + --cl-card-bg: rgba(255, 255, 255, 0.04); + --cl-card-border: rgba(255, 255, 255, 0.1); + --cl-surface-border: rgba(255, 255, 255, 0.14); + --cl-control-bg: rgba(255, 255, 255, 0.05); + --cl-input-bg: rgba(255, 255, 255, 0.05); + --cl-input-border: rgba(255, 255, 255, 0.16); + --cl-placeholder: rgba(200, 210, 220, 0.48); + --cl-live-shell-bg: rgba(255, 255, 255, 0.03); + --cl-live-card-bg: rgba(255, 255, 255, 0.04); + --cl-live-border: rgba(255, 255, 255, 0.12); +} + +.cl-wrap.cl-theme-light { + --cl-card-bg: #ffffff; + --cl-card-border: rgba(0, 0, 0, 0.12); + --cl-surface-border: rgba(0, 0, 0, 0.1); + --cl-control-bg: rgba(0, 0, 0, 0.03); + --cl-input-bg: #ffffff; + --cl-input-border: #c5c9d2; + --cl-live-shell-bg: rgba(0, 0, 0, 0.02); + --cl-live-card-bg: rgba(0, 0, 0, 0.03); + --cl-live-border: rgba(0, 0, 0, 0.12); + --cl-chart-up: rgba(120, 130, 145, 0.55); + --cl-chart-down: rgba(120, 130, 145, 0.4); + --cl-chart-conn: rgba(120, 130, 145, 0.32); +} + +@media (prefers-color-scheme: dark) { + .cl-wrap:not(.cl-theme-light) { + --cl-card-bg: rgba(255, 255, 255, 0.04); + --cl-card-border: rgba(255, 255, 255, 0.1); + --cl-surface-border: rgba(255, 255, 255, 0.14); + --cl-control-bg: rgba(255, 255, 255, 0.05); + --cl-input-bg: rgba(255, 255, 255, 0.05); + --cl-input-border: rgba(255, 255, 255, 0.16); + --cl-live-shell-bg: rgba(255, 255, 255, 0.03); + --cl-live-card-bg: rgba(255, 255, 255, 0.04); + --cl-live-border: rgba(255, 255, 255, 0.12); + } +} + +.cl-wrap .cl-card { + background: var(--cl-card-bg) !important; + border: 1px solid var(--cl-surface-border) !important; + border-radius: var(--border-radius, var(--cl-radius, 12px)) !important; + padding: 20px; + box-shadow: var(--card-shadow, var(--cl-card-shadow)) !important; + transition: all 0.3s ease; +} + +.cl-wrap .cl-card:hover { + box-shadow: var(--cl-card-shadow-hover); +} + +.cl-wrap.cl-overview-page .cl-cards > .cl-card { + padding: 14px 16px; +} + +.cl-wrap .cbi-map, +.cl-wrap .cbi-tabcontainer, +.cl-wrap .cbi-page-actions { + background: transparent; +} + +.cl-wrap .cbi-section > h3, +.cl-wrap .cl-section > h4 { + background: transparent !important; + border: 0 !important; + box-shadow: none !important; +} + +.cl-wrap .cl-ctrl, +.cl-wrap .cl-live-box, +.cl-wrap .cl-live-card { + border: 1px solid var(--cl-surface-border) !important; + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.03); +} + +.cl-wrap .cl-card-status .cl-card-head { + align-items: flex-start; +} + +/* 内核切换分段控件:紧凑分段,选中段实心主色高亮 + 白字。明暗自适应。 */ +.cl-wrap .cl-status-kernel { + display: inline-flex; + align-items: center; + gap: 2px; + padding: 2px; + border-radius: 8px; + border: 0; + background: rgba(128, 128, 128, 0.1); + box-shadow: none !important; +} + +.cl-wrap .cl-status-kernel .cl-core-btn { + height: 24px; + line-height: 24px; + min-width: 60px; + padding: 0 10px; + border: 0; + border-radius: 6px; + background: transparent; + box-shadow: none !important; + font-size: 11px; + font-weight: 500; + color: var(--cl-label-muted); + opacity: 0.6; + cursor: pointer; + transition: background-color 0.18s ease, color 0.18s ease, opacity 0.18s ease; +} + +.cl-wrap .cl-status-kernel .cl-core-btn:hover { + opacity: 0.85; +} + +/* 选中段实心色:固定青色,四主题(Bootstrap / Argon × 明暗)统一, + 略带向下变暗的渐变增加层次。 */ +.cl-wrap .cl-status-kernel .cl-core-btn.active, +.cl-wrap .cl-status-kernel .cl-core-btn.active:hover { + background: linear-gradient(#3886a1, #2f7288); + border-color: transparent; + color: #fff; + opacity: 1; + font-weight: 600; + box-shadow: 0 1px 2px rgba(0, 0, 0, 0.12) !important; +} + +.cl-wrap .cl-status-kernel .cl-core-btn:disabled { + cursor: not-allowed; +} + +.cl-wrap .cbi-checkbox input:disabled + label { + opacity: 0.4; + cursor: not-allowed; +} + +.cl-wrap .cl-status-kernel.is-busy { + opacity: 0.6; +} + +.cl-wrap .btn.cbi-button-action, +.cl-wrap .cbi-button-action { + background: var(--cl-primary-soft) !important; + border-color: var(--cl-primary-border) !important; + color: var(--cl-primary) !important; +} + +.cl-wrap .btn.cbi-button-action:hover, +.cl-wrap .cbi-button-action:hover { + background: rgba(var(--cl-primary-rgb), 0.2) !important; + border-color: transparent !important; + color: var(--cl-primary) !important; +} + +.cl-wrap .cl-live-box { + padding: 10px 12px; + border-color: var(--cl-live-border); + background: var(--cl-live-shell-bg); +} + +.cl-wrap .cbi-value-title, +.cl-wrap .cl-card .lbl, +.cl-wrap .cl-section h4 { + color: var(--cl-title-color); +} + +.cl-wrap .cbi-value-field input, +.cl-wrap .cbi-value-field select, +.cl-wrap .cbi-value-field textarea, +.cl-wrap input, +.cl-wrap select, +.cl-wrap textarea { + color: var(--cl-field-color); +} + +.cl-wrap input::placeholder, +.cl-wrap textarea::placeholder { + color: var(--cl-placeholder); +} + +.cl-wrap .cl-control-wrap { + width: min(100%, 400px); + max-width: 400px; +} + +.cl-wrap .cl-control-wrap .cbi-input-text, +.cl-wrap .cl-control-wrap .cbi-input-select, +.cl-wrap .cl-control-wrap select, +.cl-wrap .cl-control-wrap input[type="text"], +.cl-wrap .cl-control-wrap input[type="number"], +.cl-wrap .cl-control-wrap input[type="password"], +.cl-wrap .cl-control-wrap textarea { + max-width: 400px; + height: 38px; + box-sizing: border-box; + border: 1px solid var(--cl-control-border); + border-radius: 8px; + padding: 0 12px; + background: var(--cl-control-bg); +} + +.cl-wrap .cl-control-wrap textarea { + min-height: 76px; + height: auto; + padding: 8px 12px; +} + +.cl-wrap .cl-control-wrap .cbi-input-select, +.cl-wrap .cl-control-wrap select { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.cl-wrap .cl-live-grid { + gap: 14px; +} + +.cl-wrap .cl-live-card, +.cl-wrap .cl-stat-card { + height: 120px; + min-height: 120px; + max-height: 120px; + box-sizing: border-box; + border-color: var(--cl-live-border); + background: var(--cl-live-card-bg); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.05); + backdrop-filter: blur(2px); +} + +.cl-wrap .cl-live-title { + color: var(--cl-live-title); +} + +.cl-wrap .cl-card-mode .val { + display: block; + min-height: 0; + line-height: 1.35; +} + +.cl-wrap.cl-system-page .cbi-section, +.cl-wrap .cbi-section.cl-form-card { + background: var(--cl-card-bg); + border: 1px solid var(--cl-card-border); + border-radius: 12px; + padding: 20px; + margin-bottom: 20px !important; + box-shadow: var(--cl-card-shadow); + transition: all 0.3s ease; +} + +.cl-wrap.cl-system-page .cbi-section:hover, +.cl-wrap .cbi-section.cl-form-card:hover { + box-shadow: var(--cl-card-shadow-hover); +} + +.cl-wrap .cl-file-actions { + justify-content: flex-end; +} + +.cl-wrap .cl-mode-stack { + display: flex; + flex-direction: column; + gap: 6px; + justify-content: flex-start; + align-items: flex-start; + width: 100%; +} + +.cl-wrap .cl-mode-tag { + display: flex; + align-items: center; + justify-content: flex-start; + padding: 0; + border-radius: 0; + font-size: 11px; + line-height: 1.35; + background: transparent; + color: inherit; + opacity: 0.5; + width: max-content; + max-width: 100%; + text-align: left; +} + +.cl-wrap .cl-mode-tag-degraded { + color: var(--cl-warn-color); +} + +.cl-wrap .cl-mode-row { + display: flex; + justify-content: space-between; + gap: 8px; + align-items: baseline; + width: 100%; + max-width: 250px; +} + +.cl-wrap .cl-mode-proto { + font-size: 11px; + line-height: 1.35; + opacity: 0.78; + color: rgba(var(--cl-primary-rgb), 0.84); + text-align: left; + letter-spacing: 0.2px; + min-width: 42px; + flex: 0 0 42px; +} + +.cl-wrap .cl-mode-name { + font-size: 11px; + line-height: 1.35; + font-weight: 700; + color: var(--cl-title-color); + text-align: left; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + flex: 1 1 auto; +} + +.cl-wrap .cl-mode-suffix { + font-size: 11px; + line-height: 1.35; + text-align: right; + opacity: 0.5; + min-width: 34px; + flex: 0 0 34px; +} + +.cl-wrap .cl-mode-stack-line { + font-size: 11px; + line-height: 1.35; + font-weight: 600; + opacity: 0.78; +} + +.cl-wrap .cl-mode-degraded { + font-size: 10px; + line-height: 1.3; + color: #b56f00; + opacity: 0.92; +} + +.cl-wrap .cl-mode-meta { + font-size: 10px; + line-height: 1.3; + opacity: 0.65; +} + +body.dark .cl-wrap .cl-mode-tag, +body.dark .cl-wrap .cl-mode-tag, +body[data-theme="dark"] .cl-wrap .cl-mode-tag, +body[data-darkmode="1"] .cl-wrap .cl-mode-tag, +body[data-darkmode="true"] .cl-wrap .cl-mode-tag, +html.dark .cl-wrap .cl-mode-tag, +html.dark .cl-wrap .cl-mode-tag, +html[data-theme="dark"] .cl-wrap .cl-mode-tag, +html[data-bs-theme="dark"] .cl-wrap .cl-mode-tag, +html[data-darkmode="1"] .cl-wrap .cl-mode-tag, +html[data-darkmode="true"] .cl-wrap .cl-mode-tag { + background: transparent; + color: inherit; + opacity: 0.5; +} + +.cl-wrap.cl-config-page .cl-fixed-600 { + width: min(100%, 600px); + max-width: 600px; +} + +.cl-wrap.cl-config-page .cl-file-list { + width: 100%; +} + +.cl-wrap.cl-config-page .cl-panel .cbi-section { + background: transparent !important; + border: 0 !important; + border-bottom: 1px solid var(--cl-card-border) !important; + border-radius: 0 !important; + padding: 14px 0 18px; + margin-bottom: 12px !important; + box-shadow: none !important; +} + +.cl-wrap.cl-config-page .cl-section.cl-card, +.cl-wrap.cl-config-page .cl-panel.cl-card { + background: transparent !important; + border: 0 !important; + border-bottom: 1px solid var(--cl-card-border) !important; + border-radius: 0 !important; + box-shadow: none !important; + padding: 14px 0 18px !important; +} + +.cl-wrap.cl-config-page .cl-panel .cbi-section > h3 { + font-size: 1.15rem !important; + font-weight: 600 !important; + color: var(--title-color, var(--cl-title-color)); + margin-bottom: 12px !important; +} + +/* Title typography normalization: match template on Config(Proxy/DNS) + System pages */ +.cl-wrap.cl-config-page .cl-section h4, +.cl-wrap.cl-config-page .cl-panel .cbi-section > h3 { + font-size: 1.15rem !important; + line-height: 1.35 !important; + font-weight: 600 !important; + color: var(--title-color, var(--cl-title-color)) !important; + opacity: 1 !important; + letter-spacing: 0.1px !important; +} + +.cl-wrap.cl-system-page .cl-section h4, +.cl-wrap.cl-system-page .cl-panel .cbi-section > h3 { + font-size: 15px !important; + line-height: 1.35 !important; + font-weight: 700 !important; + color: var(--cl-title-color, inherit) !important; + opacity: 1 !important; + letter-spacing: 0 !important; +} + +.cl-wrap.cl-config-page .cbi-value-title { + color: var(--cl-label-muted) !important; + font-size: 13px !important; +} + +/* 表单说明文字统一弱化:明显比标题与字段标签暗,拉开视觉层次 */ +.cl-wrap.cl-config-page .cbi-value-description, +.cl-wrap.cl-config-page .cbi-section-descr, +.cl-wrap.cl-config-page .cbi-value-helptext, +.cl-wrap.cl-system-page .cbi-value-description, +.cl-wrap.cl-system-page .cbi-section-descr, +.cl-wrap.cl-system-page .cbi-value-helptext { + color: rgba(120, 130, 150, 0.9) !important; + font-size: 12px !important; +} + +.cl-wrap.cl-system-page .cl-tab, +.cl-wrap.cl-config-page .cl-tab { + font-size: 14px !important; + font-weight: 600 !important; + color: var(--title-color, var(--cl-title-color)) !important; + opacity: 1 !important; +} + +.cl-wrap.cl-system-page .cl-tab.active, +.cl-wrap.cl-config-page .cl-tab.active { + color: var(--title-color, var(--cl-title-color)) !important; + font-weight: 700 !important; +} + +.cl-wrap.cl-config-page .cl-panel .cbi-value-title { + color: var(--cl-label-muted); +} + +.cl-wrap.cl-config-page .cl-sub-url, +.cl-wrap.cl-config-page .cl-ctrl select, +.cl-wrap.cl-config-page .cl-ctrl .cbi-input-select, +.cl-wrap.cl-config-page .cl-control-wrap .cbi-input-text, +.cl-wrap.cl-config-page .cl-control-wrap .cbi-input-select, +.cl-wrap.cl-config-page .cl-control-wrap select, +.cl-wrap.cl-config-page .cl-control-wrap input[type="text"], +.cl-wrap.cl-config-page .cl-control-wrap input[type="number"], +.cl-wrap.cl-config-page .cl-control-wrap input[type="password"], +.cl-wrap.cl-config-page .cl-control-wrap textarea, +.cl-wrap.cl-config-page .cbi-value-field input:not([type="checkbox"]):not([type="radio"]):not([type="button"]):not([type="submit"]):not([type="reset"]):not([type="file"]), +.cl-wrap.cl-config-page .cbi-value-field select, +.cl-wrap.cl-config-page .cbi-value-field textarea { + background: rgba(128, 128, 128, 0.05) !important; + border: 0 !important; + border-bottom: 1px solid rgba(var(--primary-rgb, var(--cl-primary-rgb)), 0.2) !important; + color: var(--cl-input-color) !important; + border-radius: 0 !important; + box-shadow: none !important; +} + +.cl-wrap.cl-config-page .cl-sub-url, +.cl-wrap.cl-config-page .cl-ctrl select, +.cl-wrap.cl-config-page .cl-ctrl .cbi-input-select { + padding: 0 12px !important; + height: 38px !important; +} + +.cl-wrap.cl-config-page .cl-panel, +.cl-wrap.cl-system-page .cl-panel, +.cl-wrap.cl-config-page .cl-panel .cbi-section-node, +.cl-wrap.cl-system-page .cl-panel .cbi-section-node { + background: transparent !important; +} + +.cl-wrap.cl-system-page .cbi-section, +.cl-wrap.cl-system-page .cl-panel .cbi-section { + background: transparent !important; + border: 0 !important; + border-bottom: 1px solid var(--cl-card-border) !important; + border-radius: 0 !important; + box-shadow: none !important; + padding: 14px 0 18px !important; + margin-bottom: 12px !important; +} + +.cl-wrap.cl-config-page .cbi-value-field, +.cl-wrap.cl-system-page .cbi-value-field, +.cl-wrap.cl-config-page .cl-control-wrap, +.cl-wrap.cl-system-page .cl-control-wrap { + max-width: 600px !important; +} + +.cl-wrap.cl-config-page .cbi-value-title, +.cl-wrap.cl-system-page .cbi-value-title { + min-height: 38px; + display: flex; + align-items: center; +} + +.cl-wrap.cl-config-page .cbi-value-field input:not([type="checkbox"]):not([type="radio"]):not([type="button"]):not([type="submit"]):not([type="reset"]):not([type="file"]), +.cl-wrap.cl-config-page .cbi-value-field select, +.cl-wrap.cl-config-page .cbi-value-field textarea, +.cl-wrap.cl-config-page .cl-control-wrap .cbi-input-text, +.cl-wrap.cl-config-page .cl-control-wrap .cbi-input-select, +.cl-wrap.cl-config-page .cl-control-wrap select, +.cl-wrap.cl-config-page .cl-control-wrap input[type="text"], +.cl-wrap.cl-config-page .cl-control-wrap input[type="number"], +.cl-wrap.cl-config-page .cl-control-wrap input[type="password"], +.cl-wrap.cl-config-page .cl-control-wrap textarea { + max-width: 480px !important; + box-sizing: border-box; + padding: 0 10px !important; + border: 0 !important; + border-bottom: 1px solid rgba(var(--primary-rgb, var(--cl-primary-rgb)), 0.2) !important; + border-radius: 0 !important; + color: var(--cl-field-color) !important; + background: rgba(128, 128, 128, 0.05) !important; + box-shadow: none !important; +} + +.cl-wrap.cl-config-page .cbi-value-field textarea, +.cl-wrap.cl-system-page .cbi-value-field textarea { + min-height: 84px; + height: auto; + padding: 8px 10px !important; +} + +.cl-wrap.cl-config-page .cbi-value-field select, +.cl-wrap.cl-system-page .cbi-value-field select { + text-overflow: ellipsis; + white-space: nowrap; + overflow: hidden; +} + +.cl-wrap.cl-config-page .btn, +.cl-wrap.cl-config-page .cbi-button, +.cl-wrap.cl-system-page .btn, +.cl-wrap.cl-system-page .cbi-button { + border-radius: 8px !important; + box-shadow: none !important; +} + +.cl-wrap.cl-config-page .cbi-button-action, +.cl-wrap.cl-config-page .btn.cbi-button-action, +.cl-wrap.cl-system-page .cbi-button-action, +.cl-wrap.cl-system-page .btn.cbi-button-action { + background: var(--cl-primary-soft) !important; + border-color: var(--cl-primary-border) !important; + color: var(--cl-primary) !important; +} + +.cl-wrap.cl-config-page .cbi-button-add, +.cl-wrap.cl-config-page .btn.cbi-button-add, +.cl-wrap.cl-system-page .cbi-button-add, +.cl-wrap.cl-system-page .btn.cbi-button-add, +.cl-wrap.cl-config-page .cbi-button-positive, +.cl-wrap.cl-config-page .btn.cbi-button-positive, +.cl-wrap.cl-system-page .cbi-button-positive, +.cl-wrap.cl-system-page .btn.cbi-button-positive { + background: rgba(66, 186, 117, 0.12) !important; + border-color: rgba(66, 186, 117, 0.38) !important; + color: rgba(32, 132, 75, 0.94) !important; +} + +.cl-wrap.cl-config-page .cbi-button-negative, +.cl-wrap.cl-config-page .btn.cbi-button-negative, +.cl-wrap.cl-system-page .cbi-button-negative, +.cl-wrap.cl-system-page .btn.cbi-button-negative { + background: rgba(222, 86, 86, 0.08) !important; + border-color: rgba(222, 86, 86, 0.46) !important; + color: rgba(190, 62, 62, 0.92) !important; +} + +/* 中性按钮(检查更新 / 导出备份 / 导入还原):浅灰描边, + 避免落到主题原生深灰填充(Argon 浅色下尤为突兀)。明暗自适应。 */ +.cl-wrap.cl-config-page .cbi-button-neutral, +.cl-wrap.cl-config-page .btn.cbi-button-neutral, +.cl-wrap.cl-system-page .cbi-button-neutral, +.cl-wrap.cl-system-page .btn.cbi-button-neutral { + background: rgba(128, 128, 128, 0.1) !important; + border: 1px solid rgba(128, 128, 128, 0.24) !important; + color: var(--cl-label-muted) !important; + box-shadow: none !important; +} + +.cl-wrap.cl-config-page .cbi-button-neutral:hover, +.cl-wrap.cl-config-page .btn.cbi-button-neutral:hover, +.cl-wrap.cl-system-page .cbi-button-neutral:hover, +.cl-wrap.cl-system-page .btn.cbi-button-neutral:hover { + background: rgba(128, 128, 128, 0.18) !important; + border-color: rgba(128, 128, 128, 0.32) !important; +} + +/* Config page de-colorization: keep primary accents only */ +.cl-wrap.cl-config-page .cbi-button-action, +.cl-wrap.cl-config-page .btn.cbi-button-action, +.cl-wrap.cl-config-page .cbi-button-add, +.cl-wrap.cl-config-page .btn.cbi-button-add, +.cl-wrap.cl-config-page .cbi-button-positive, +.cl-wrap.cl-config-page .btn.cbi-button-positive, +.cl-wrap.cl-config-page .cbi-button-negative, +.cl-wrap.cl-config-page .btn.cbi-button-negative, +.cl-wrap.cl-config-page .cl-btn-update-sub, +.cl-wrap.cl-config-page .cl-btn-edit, +.cl-wrap.cl-config-page .cl-btn-switch, +.cl-wrap.cl-config-page .cl-btn-delete, +.cl-wrap.cl-config-page .cl-btn-template-upload, +.cl-wrap.cl-config-page .cl-btn-upload-config, +.cl-wrap.cl-config-page .cl-btn-sb-upload { + background: rgba(var(--primary-rgb, var(--cl-primary-rgb)), 0.1) !important; + border: 1px solid rgba(var(--primary-rgb, var(--cl-primary-rgb)), 0.28) !important; + color: var(--cl-primary) !important; + box-shadow: none !important; +} + +.cl-wrap.cl-config-page .cbi-button-action:hover, +.cl-wrap.cl-config-page .btn.cbi-button-action:hover, +.cl-wrap.cl-config-page .cbi-button-add:hover, +.cl-wrap.cl-config-page .btn.cbi-button-add:hover, +.cl-wrap.cl-config-page .cbi-button-positive:hover, +.cl-wrap.cl-config-page .btn.cbi-button-positive:hover, +.cl-wrap.cl-config-page .cbi-button-negative:hover, +.cl-wrap.cl-config-page .btn.cbi-button-negative:hover, +.cl-wrap.cl-config-page .cl-btn-update-sub:hover, +.cl-wrap.cl-config-page .cl-btn-edit:hover, +.cl-wrap.cl-config-page .cl-btn-switch:hover, +.cl-wrap.cl-config-page .cl-btn-delete:hover, +.cl-wrap.cl-config-page .cl-btn-template-upload:hover, +.cl-wrap.cl-config-page .cl-btn-upload-config:hover, +.cl-wrap.cl-config-page .cl-btn-sb-upload:hover { + background: rgba(var(--primary-rgb, var(--cl-primary-rgb)), 0.16) !important; + border-color: rgba(var(--primary-rgb, var(--cl-primary-rgb)), 0.4) !important; + color: var(--cl-primary) !important; +} + +.cl-wrap.cl-config-page .cl-file-item { + width: 100%; + box-sizing: border-box; + background: rgba(128, 128, 128, 0.04) !important; + border: 1px solid rgba(128, 128, 128, 0.16) !important; + box-shadow: none !important; +} + +.cl-wrap.cl-config-page .cl-file-item.is-active { + background: rgba(var(--primary-rgb, var(--cl-primary-rgb)), 0.08) !important; + border-color: rgba(var(--primary-rgb, var(--cl-primary-rgb)), 0.24) !important; +} + +.cl-wrap.cl-config-page .cl-file-meta { + justify-content: flex-start; +} + +.cl-wrap.cl-config-page .cl-file-name { + flex: 1; +} + +.cl-wrap.cl-config-page .cl-file-name-text { + color: var(--cl-label-muted) !important; +} + +.cl-wrap.cl-config-page .cl-file-size { + color: rgba(128, 128, 128, 0.62) !important; +} + +.cl-wrap.cl-config-page .cl-file-actions { + margin-left: auto; +} + +.cl-wrap.cl-config-page .cl-rewrite-wrap { + max-width: 600px; + background: transparent !important; + border: 0 !important; + border-radius: 0 !important; + box-shadow: none !important; + padding: 0 !important; +} + +.cl-wrap.cl-config-page .cl-rewrite-wrap .cl-sub-url, +.cl-wrap.cl-config-page .cl-rewrite-wrap .cbi-input-select, +.cl-wrap.cl-config-page .cl-rewrite-wrap select { + width: 100%; + max-width: 100%; +} + +.cl-wrap.cl-config-page .cl-template-row { + display: flex; + align-items: center; + gap: 10px; + width: 100%; +} + +.cl-wrap.cl-config-page .cl-template-select-wrap { + flex: 1; + min-width: 0; +} + +.cl-wrap.cl-config-page .cl-template-select { + width: 100%; + max-width: 100%; + text-overflow: ellipsis; +} + +.cl-wrap .cl-active-badge { + display: inline-flex; + align-items: center; + justify-content: center; + white-space: nowrap; + flex-shrink: 0; + background: rgba(var(--primary-rgb, var(--cl-primary-rgb)), 0.12); + color: var(--cl-primary); + border: 1px solid rgba(var(--primary-rgb, var(--cl-primary-rgb)), 0.24); +} + +body.dark .cl-wrap .cl-active-badge, +body.dark .cl-wrap .cl-active-badge, +body[data-theme="dark"] .cl-wrap .cl-active-badge, +html.dark .cl-wrap .cl-active-badge, +html.dark .cl-wrap .cl-active-badge, +html[data-theme="dark"] .cl-wrap .cl-active-badge, +html[data-bs-theme="dark"] .cl-wrap .cl-active-badge { + background: rgba(var(--primary-rgb, var(--cl-primary-rgb)), 0.18); + color: rgba(209, 227, 255, 0.95); + border-color: rgba(var(--primary-rgb, var(--cl-primary-rgb)), 0.3); +} + +.cl-wrap .cl-live-num { + font-size: 18px; + color: rgba(40, 48, 62, 0.88); +} + +.cl-wrap .cl-pass-wrap { + display: flex; + align-items: center; + gap: 8px; + /* 322 = 输入框 210(与面板端口/面板 UI 对齐)+ 两个 48px 按钮 + 两段 8px 间距 */ + width: min(100%, 322px); +} + +.cl-wrap .cl-pass-wrap input[type="password"], +.cl-wrap .cl-pass-wrap input[type="text"] { + flex: 1; + min-width: 0; +} + +.cl-wrap .cl-pass-btn { + flex-shrink: 0; + min-width: 48px; + padding: 4px 10px !important; + border-radius: 8px; +} + +.cl-wrap .cl-arch-badge-row { + display: inline-flex; + align-items: center; + gap: 8px; + flex-wrap: wrap; + margin-top: 2px; +} + +.cl-wrap .cl-arch-badge { + display: inline-flex; + align-items: center; + justify-content: center; + padding: 2px 10px; + border-radius: 999px; + font-size: 11px; + font-weight: 600; + line-height: 1.3; +} + +.cl-wrap .cl-arch-badge-sys { + background: rgba(0, 122, 255, 0.1); + color: rgba(0, 98, 214, 0.92); + border: 1px solid rgba(0, 122, 255, 0.24); +} + +.cl-wrap .cl-arch-badge-rec { + background: rgba(46, 170, 92, 0.12); + color: rgba(22, 122, 63, 0.92); + border: 1px solid rgba(46, 170, 92, 0.26); +} + +.cl-wrap .cl-arch-arrow { + font-size: 12px; + opacity: 0.62; +} + +.cl-wrap .cl-check-icon-wrap { + width: 18px; + height: 18px; + display: inline-flex; + align-items: center; + justify-content: center; + background: transparent !important; + border: none !important; + box-shadow: none !important; + border-radius: 0 !important; + overflow: hidden; + flex-shrink: 0; +} + +.cl-wrap .cl-check-icon-wrap .cl-check-icon { + width: 18px; + height: 18px; + object-fit: contain; + display: block; + background: transparent !important; + border: none !important; + box-shadow: none !important; +} + +.cl-wrap .cl-check-item img, +.cl-wrap .cl-check-main img { + background: transparent !important; + border: 0 !important; + box-shadow: none !important; + outline: 0 !important; +} + +.cl-wrap .cl-check-icon-wrap .cl-check-icon-fallback { + background: transparent; + border: 1px solid rgba(130, 140, 155, 0.4); + color: rgba(130, 140, 155, 0.9); +} + +body.dark .cl-wrap .cl-check-icon-wrap .cl-check-icon, +body.dark .cl-wrap .cl-check-icon-wrap .cl-check-icon, +body[data-theme="dark"] .cl-wrap .cl-check-icon-wrap .cl-check-icon, +html.dark .cl-wrap .cl-check-icon-wrap .cl-check-icon, +html.dark .cl-wrap .cl-check-icon-wrap .cl-check-icon, +html[data-theme="dark"] .cl-wrap .cl-check-icon-wrap .cl-check-icon, +html[data-bs-theme="dark"] .cl-wrap .cl-check-icon-wrap .cl-check-icon { + filter: saturate(0.82) brightness(1.08); +} + +body.dark .cl-wrap.cl-system-page .cl-section h4, +body.dark .cl-wrap.cl-system-page .cl-panel .cbi-section > h3, +body.dark .cl-wrap.cl-system-page .cl-section h4, +body.dark .cl-wrap.cl-system-page .cl-panel .cbi-section > h3, +html[data-theme="dark"] .cl-wrap.cl-system-page .cl-section h4, +html[data-theme="dark"] .cl-wrap.cl-system-page .cl-panel .cbi-section > h3, +html[data-bs-theme="dark"] .cl-wrap.cl-system-page .cl-section h4, +html[data-bs-theme="dark"] .cl-wrap.cl-system-page .cl-panel .cbi-section > h3 { + color: rgba(219, 227, 241, 0.92) !important; +} + +body.dark .cl-wrap.cl-system-page .cl-tab, +body.dark .cl-wrap.cl-config-page .cl-tab, +body.dark .cl-wrap.cl-system-page .cl-tab, +body.dark .cl-wrap.cl-config-page .cl-tab, +html[data-theme="dark"] .cl-wrap.cl-system-page .cl-tab, +html[data-theme="dark"] .cl-wrap.cl-config-page .cl-tab, +html[data-bs-theme="dark"] .cl-wrap.cl-system-page .cl-tab, +html[data-bs-theme="dark"] .cl-wrap.cl-config-page .cl-tab { + color: var(--title-color, var(--cl-title-color)) !important; + opacity: 0.88; +} + +body.dark .cl-wrap.cl-system-page .cl-tab.active, +body.dark .cl-wrap.cl-config-page .cl-tab.active, +body.dark .cl-wrap.cl-system-page .cl-tab.active, +body.dark .cl-wrap.cl-config-page .cl-tab.active, +html[data-theme="dark"] .cl-wrap.cl-system-page .cl-tab.active, +html[data-theme="dark"] .cl-wrap.cl-config-page .cl-tab.active, +html[data-bs-theme="dark"] .cl-wrap.cl-system-page .cl-tab.active, +html[data-bs-theme="dark"] .cl-wrap.cl-config-page .cl-tab.active { + color: var(--title-color, var(--cl-title-color)) !important; + opacity: 1; +} + +body.dark .cl-wrap .cl-arch-badge-sys, +body.dark .cl-wrap .cl-arch-badge-sys, +body[data-theme="dark"] .cl-wrap .cl-arch-badge-sys, +html.dark .cl-wrap .cl-arch-badge-sys, +html.dark .cl-wrap .cl-arch-badge-sys, +html[data-theme="dark"] .cl-wrap .cl-arch-badge-sys, +html[data-bs-theme="dark"] .cl-wrap .cl-arch-badge-sys { + background: rgba(122, 180, 255, 0.16); + color: rgba(208, 227, 255, 0.95); + border-color: rgba(122, 180, 255, 0.3); +} + +body.dark .cl-wrap .cl-arch-badge-rec, +body.dark .cl-wrap .cl-arch-badge-rec, +body[data-theme="dark"] .cl-wrap .cl-arch-badge-rec, +html.dark .cl-wrap .cl-arch-badge-rec, +html.dark .cl-wrap .cl-arch-badge-rec, +html[data-theme="dark"] .cl-wrap .cl-arch-badge-rec, +html[data-bs-theme="dark"] .cl-wrap .cl-arch-badge-rec { + background: rgba(104, 199, 135, 0.16); + color: rgba(198, 246, 211, 0.95); + border-color: rgba(104, 199, 135, 0.3); +} + +.cl-wrap.cl-system-page .cl-component-arch-sel { + background: rgba(46, 170, 92, 0.12) !important; + color: #24844d !important; + border-color: rgba(46, 170, 92, 0.28) !important; + font-weight: 700 !important; +} + +.cl-wrap.cl-system-page.cl-theme-dark .cl-component-arch-sel, +body.dark .cl-wrap.cl-system-page .cl-component-arch-sel, +body[data-theme="dark"] .cl-wrap.cl-system-page .cl-component-arch-sel, +html.dark .cl-wrap.cl-system-page .cl-component-arch-sel, +html[data-theme="dark"] .cl-wrap.cl-system-page .cl-component-arch-sel, +html[data-bs-theme="dark"] .cl-wrap.cl-system-page .cl-component-arch-sel { + background: rgba(104, 199, 135, 0.16) !important; + color: rgba(198, 246, 211, 0.95) !important; + border-color: rgba(104, 199, 135, 0.3) !important; +} + +.cl-wrap .cl-live-unit { + font-size: 11px; + margin-left: 3px; + color: var(--cl-live-sub); +} + +.cl-wrap .cl-live-foot { + color: var(--cl-live-foot); +} + +.cl-wrap .cl-live-line.up { + stroke: var(--cl-chart-up); +} + +.cl-wrap .cl-live-area.up { + fill: var(--cl-chart-up); +} + +.cl-wrap .cl-live-line.down { + stroke: var(--cl-chart-down); +} + +.cl-wrap .cl-live-area.down { + fill: var(--cl-chart-down); +} + +.cl-wrap .cl-live-line.conn { + stroke: var(--cl-chart-conn); +} + +.cl-wrap .cl-live-area.conn { + fill: var(--cl-chart-conn); +} + +.cl-wrap .cl-live-card.is-zero .cl-live-num, +.cl-wrap .cl-live-card.is-zero .cl-live-unit, +.cl-wrap .cl-live-card.is-zero .cl-live-foot { + opacity: 1; + color: var(--cl-live-zero); +} + +.cl-wrap .cl-live-card.is-zero .cl-live-num { + font-size: 16px; + text-shadow: none; +} + +.cl-wrap .cl-live-card.is-zero .cl-live-bg-chart { + opacity: 0; +} + +.cl-wrap .cl-live-card.is-active .cl-live-bg-chart { + opacity: 0.9; +} + +.cl-wrap .cl-live-card-up.is-active .cl-live-num { + text-shadow: 0 0 12px rgba(98, 176, 255, 0.34); +} + +.cl-wrap .cl-live-card-down.is-active .cl-live-num { + text-shadow: 0 0 12px rgba(155, 134, 255, 0.34); +} + +.cl-wrap .cl-live-card-conn.is-active .cl-live-num { + text-shadow: 0 0 12px rgba(102, 213, 155, 0.34); +} + +.cl-wrap .cl-live-card-up.is-hot .cl-live-num { + text-shadow: 0 0 18px rgba(98, 176, 255, 0.54); +} + +.cl-wrap .cl-live-card-down.is-hot .cl-live-num { + text-shadow: 0 0 18px rgba(155, 134, 255, 0.54); +} + +.cl-wrap .cl-live-card-conn.is-hot .cl-live-num { + text-shadow: 0 0 18px rgba(102, 213, 155, 0.54); +} + +.cl-wrap .cl-live-card.is-hot .cl-live-unit, +.cl-wrap .cl-live-card.is-hot .cl-live-foot { + color: rgba(245, 250, 255, 0.82); +} + +body.dark .cl-wrap .cl-live-num, +body.dark .cl-wrap .cl-live-num, +html[data-theme="dark"] .cl-wrap .cl-live-num, +html[data-bs-theme="dark"] .cl-wrap .cl-live-num { + color: rgba(243, 247, 255, 0.85); +} + +.cl-wrap .cl-check-latency { + font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", monospace; + font-variant-numeric: tabular-nums; +} + +.cl-wrap .cl-live-card.is-offline .cl-live-title, +.cl-wrap .cl-live-card.is-offline .cl-live-foot { + color: var(--cl-live-foot); +} + +@media (max-width: 640px) { + .cl-wrap .cl-live-grid { + grid-template-columns: 1fr !important; + gap: 10px; + } + + .cl-wrap .cl-live-card { + height: 120px; + min-height: 120px; + max-height: 120px; + } +} + +@media (max-width: 768px) { + .cl-wrap { + --cl-primary: rgba(88, 166, 255, 0.92); + --cl-primary-border: rgba(88, 166, 255, 0.48); + --cl-primary-soft: rgba(88, 166, 255, 0.12); + --cl-primary-soft-hover: rgba(88, 166, 255, 0.2); + } + + .cl-wrap input, + .cl-wrap select, + .cl-wrap textarea, + .cl-wrap .cbi-input-text, + .cl-wrap .cbi-input-select { + font-size: 13px !important; + height: auto !important; + line-height: 1.35 !important; + padding: 5px 8px !important; + } + + .cl-wrap .cbi-value-title, + .cl-wrap .cl-card .lbl, + .cl-wrap .cl-section h4 { + font-size: 14px !important; + font-weight: 700 !important; + margin-bottom: 5px !important; + } + + .cl-wrap.cl-form-page .cbi-value-field { + width: 100% !important; + } + + .cl-wrap.cl-form-page .cl-control-wrap { + width: 100% !important; + max-width: 100% !important; + } + + .cl-wrap.cl-form-page .cl-control-wrap .cbi-input-text, + .cl-wrap.cl-form-page .cl-control-wrap .cbi-input-select, + .cl-wrap.cl-form-page .cl-control-wrap select, + .cl-wrap.cl-form-page .cl-control-wrap input[type="text"], + .cl-wrap.cl-form-page .cl-control-wrap input[type="number"], + .cl-wrap.cl-form-page .cl-control-wrap input[type="password"], + .cl-wrap.cl-form-page .cl-control-wrap textarea { + width: 100% !important; + max-width: 100% !important; + padding: 5px 8px !important; + } + + .cl-wrap.cl-form-page .cl-control-wrap .cbi-input-select, + .cl-wrap.cl-form-page .cl-control-wrap select { + overflow: hidden !important; + text-overflow: ellipsis !important; + white-space: nowrap !important; + } + + .cl-wrap.cl-config-page .cl-fixed-600, + .cl-wrap.cl-config-page .cl-rewrite-wrap, + .cl-wrap.cl-config-page .cl-template-row, + .cl-wrap.cl-config-page .cl-template-select-wrap { + width: 100% !important; + max-width: 100% !important; + } + + .cl-wrap.cl-config-page .cl-template-row { + flex-wrap: wrap; + } + + .cl-wrap.cl-config-page .cl-btn-template-upload { + flex-shrink: 0; + } + + .cl-wrap .cl-active-badge { + white-space: nowrap !important; + flex-shrink: 0 !important; + } + + .cl-wrap .cl-pass-wrap { + width: 100% !important; + } +} + +/* ===== Denoise pass (small scope): config + overview ===== */ +.cl-wrap.cl-config-page, +.cl-wrap.cl-overview-page { + color: var(--text-color, inherit); +} + +.cl-wrap.cl-config-page .cl-card, +.cl-wrap.cl-config-page .cl-file-item, +.cl-wrap.cl-overview-page .cl-card, +.cl-wrap.cl-overview-page .cl-live-box, +.cl-wrap.cl-overview-page .cl-live-card, +.cl-wrap.cl-overview-page .cl-ctrl { + background: var(--cl-card-bg) !important; +} + +.cl-wrap.cl-config-page .cl-section h4, +.cl-wrap.cl-config-page .cbi-section > h3, +.cl-wrap.cl-overview-page .cl-card .lbl { + color: var(--title-color, var(--cl-title-color)) !important; + font-size: 0.95rem !important; + font-weight: 500 !important; + letter-spacing: 0 !important; +} + +.cl-wrap.cl-config-page .cl-section h4, +.cl-wrap.cl-config-page .cbi-section > h3 { + display: flex; + align-items: center; + gap: 8px; + margin-bottom: 8px !important; +} + +.cl-wrap.cl-config-page .cl-section h4::before, +.cl-wrap.cl-config-page .cbi-section > h3::before { + content: ''; + width: 3px; + height: 14px; + border-radius: 2px; + background: var(--primary-color, var(--cl-primary)); + flex: 0 0 3px; +} + +.cl-wrap.cl-config-page input:not([type="checkbox"]):not([type="radio"]):not([type="button"]):not([type="submit"]):not([type="reset"]):not([type="file"]), +.cl-wrap.cl-config-page select, +.cl-wrap.cl-config-page textarea, +.cl-wrap.cl-overview-page input:not([type="checkbox"]):not([type="radio"]):not([type="button"]):not([type="submit"]):not([type="reset"]):not([type="file"]), +.cl-wrap.cl-overview-page select, +.cl-wrap.cl-overview-page textarea { + background: var(--cl-input-bg) !important; + border: 1px solid var(--cl-input-border) !important; + border-radius: var(--border-radius, 8px) !important; + box-shadow: none !important; + color: var(--text-color, inherit) !important; +} + +.cl-wrap.cl-config-page .cl-file-name-text { + color: var(--text-color, inherit) !important; + opacity: 0.7; +} + +.cl-wrap.cl-config-page .cl-btn-template-upload, +.cl-wrap.cl-config-page .cl-btn-upload-config, +.cl-wrap.cl-config-page .cl-btn-sb-upload, +.cl-wrap.cl-config-page .cbi-button-action { + background: rgba(128, 128, 128, 0.1) !important; + color: var(--primary-color, var(--cl-primary)) !important; + border: 1px solid rgba(var(--primary-rgb, var(--cl-primary-rgb)), 0.28) !important; + box-shadow: none !important; +} + +.cl-wrap.cl-overview-page .cl-cards { + grid-template-columns: repeat(2, minmax(0, 1fr)) !important; +} + +.cl-wrap.cl-overview-page .cl-card-traffic .val { + font-size: inherit; + font-weight: 400; + word-break: normal; +} + +.cl-wrap.cl-overview-page .cl-card-traffic .cl-live-box { + padding: 0 !important; + border: 0 !important; + box-shadow: none !important; + background: transparent !important; +} + +.cl-wrap.cl-overview-page .cl-check-item img, +.cl-wrap.cl-overview-page .cl-check-main img, +.cl-wrap.cl-overview-page .cl-check-icon-wrap, +.cl-wrap.cl-overview-page .cl-check-icon { + background: transparent !important; + border: 0 !important; + box-shadow: none !important; +} + +.cl-wrap.cl-overview-page .cl-access-wrap { + margin-bottom: 12px; +} + +.cl-wrap.cl-overview-page .cl-status-note { + font-size: 11px; + margin-left: 6px; + color: var(--text-color, inherit); + opacity: 0.72; +} + +.cl-wrap.cl-overview-page .cl-status-note-pass { + color: #4aa065; + opacity: 0.92; +} + +.cl-wrap.cl-overview-page .cl-status-note-fail, +.cl-wrap.cl-overview-page .cl-status-note-degraded { + color: #b56f00; + opacity: 0.92; +} + +@media (max-width: 900px) { + .cl-wrap.cl-overview-page .cl-cards { + grid-template-columns: 1fr !important; + } +} + +/* ===== Overview unified theme-adaptive surfaces ===== */ +.cl-wrap.cl-overview-page { + background: transparent !important; + color: var(--text-color, inherit) !important; +} + +.cl-wrap.cl-overview-page .cl-card, +.cl-wrap.cl-overview-page .cl-live-box, +.cl-wrap.cl-overview-page .cl-live-card, +.cl-wrap.cl-overview-page .cl-ctrl, +.cl-wrap.cl-overview-page .cl-access-wrap { + background: var(--cl-card-bg) !important; + border: 1px solid var(--cl-surface-border) !important; + border-radius: var(--border-radius, 12px) !important; + box-shadow: var(--card-shadow, none) !important; +} + +.cl-wrap.cl-overview-page input:not([type="checkbox"]):not([type="radio"]):not([type="button"]):not([type="submit"]):not([type="reset"]):not([type="file"]), +.cl-wrap.cl-overview-page select, +.cl-wrap.cl-overview-page textarea, +.cl-wrap.cl-overview-page .cbi-input-select { + background: var(--cl-input-bg) !important; + border: 1px solid var(--cl-input-border) !important; + border-radius: var(--border-radius, 8px) !important; + color: var(--text-color, inherit) !important; +} + +.cl-wrap.cl-overview-page .cl-ctrl-row { + display: flex; + align-items: center; + gap: 8px; +} + +/* inline result of panel update (replaces the old toast) */ +.cl-wrap.cl-overview-page .cl-panel-status { + font-size: 13px; + line-height: 1.2; + white-space: nowrap; + opacity: 0; + transition: opacity .2s ease; +} +.cl-wrap.cl-overview-page .cl-panel-status.ok, +.cl-wrap.cl-overview-page .cl-panel-status.err { + opacity: 1; +} +.cl-wrap.cl-overview-page .cl-panel-status.ok { color: #16a34a; } +.cl-wrap.cl-overview-page .cl-panel-status.err { color: #dc2626; } + +.cl-wrap.cl-overview-page .cl-ctrl-row select, +.cl-wrap.cl-overview-page .cl-ctrl-row .cbi-input-select, +.cl-wrap.cl-overview-page .cl-btn-panel-update, +.cl-wrap.cl-overview-page .cl-btn-panel-open { + height: 32px !important; + line-height: 32px !important; + min-height: 32px !important; + margin: 0 !important; + box-sizing: border-box !important; +} + +.cl-wrap.cl-overview-page .cl-ctrl-row select, +.cl-wrap.cl-overview-page .cl-ctrl-row .cbi-input-select { + padding: 0 10px !important; + line-height: 28px !important; + font-size: 14px !important; + vertical-align: middle !important; +} + +.cl-wrap.cl-overview-page .cl-btn-panel-update, +.cl-wrap.cl-overview-page .cl-btn-panel-open { + padding: 0 12px !important; + border: 1px solid var(--cl-input-border) !important; + border-radius: 7px !important; + background: var(--cl-input-bg) !important; + color: var(--text-color, inherit) !important; + box-shadow: none !important; + display: inline-flex !important; + align-items: center !important; + justify-content: center !important; + text-decoration: none !important; +} + +.cl-wrap.cl-overview-page .cl-controls .cl-ctrl select, +.cl-wrap.cl-overview-page .cl-controls .cl-ctrl .cbi-input-select { + background: var(--cl-input-bg) !important; + border: 1px solid var(--cl-input-border) !important; + color: var(--text-color, inherit) !important; + height: 32px !important; + line-height: 32px !important; + min-height: 32px !important; + padding: 0 10px !important; + box-sizing: border-box !important; +} + +.cl-wrap.cl-overview-page .cl-card-mode .cl-mode-row { + display: grid !important; + grid-template-columns: 142px 83px 30px !important; + align-items: center !important; + column-gap: 4px !important; + width: 263px !important; + max-width: 100% !important; + margin: 0 !important; +} + +.cl-wrap.cl-overview-page .cl-card-mode .cl-mode-proto { + text-align: left !important; +} + +.cl-wrap.cl-overview-page .cl-card-mode .cl-mode-name { + text-align: left !important; + padding-right: 0 !important; + border-left: 0 !important; +} + +.cl-wrap.cl-overview-page .cl-card-mode .cl-mode-suffix { + text-align: left !important; + padding-right: 0 !important; + padding-left: 2px !important; + opacity: 0.62 !important; +} + +/* Unified title/body colors for overview (light + dark via theme vars) */ +.cl-wrap.cl-overview-page .cl-card .lbl, +.cl-wrap.cl-overview-page .cl-live-title, +.cl-wrap.cl-overview-page .cl-status-note, +.cl-wrap.cl-overview-page .cl-check-updated { + color: var(--title-color, var(--text-color, inherit)) !important; + opacity: 1 !important; +} + +.cl-wrap.cl-overview-page .cl-card .lbl { + font-size: 13px !important; + font-weight: 600 !important; +} + +.cl-wrap.cl-overview-page .cl-mode-name, +.cl-wrap.cl-overview-page .cl-live-num, +.cl-wrap.cl-overview-page .cl-live-unit, +.cl-wrap.cl-overview-page .cl-live-foot, +.cl-wrap.cl-overview-page .cl-check-latency, +.cl-wrap.cl-overview-page .cl-check-name, +.cl-wrap.cl-overview-page .cl-badge, +.cl-wrap.cl-overview-page .cl-ctrl label, +.cl-wrap.cl-overview-page .cl-ctrl, +.cl-wrap.cl-overview-page .cl-card .val, +.cl-wrap.cl-overview-page .cl-controls .cl-ctrl select, +.cl-wrap.cl-overview-page .cl-controls .cl-ctrl .cbi-input-select, +.cl-wrap.cl-overview-page .cl-btn-panel-update, +.cl-wrap.cl-overview-page .cl-btn-panel-open { + color: var(--text-color, inherit) !important; +} + +/* ===== Theme-system unification (light + dark) ===== */ +.cl-wrap .cl-card, +.cl-wrap .cl-live-box, +.cl-wrap .cl-live-card, +.cl-wrap .cl-ctrl, +.cl-wrap .cl-access-wrap { + background: var(--cl-card-bg) !important; + border: 1px solid var(--cl-surface-border) !important; + border-radius: var(--border-radius, var(--cl-radius, 12px)) !important; + box-shadow: var(--card-shadow, var(--cl-card-shadow)) !important; +} + +.cl-wrap input:not([type="checkbox"]):not([type="radio"]):not([type="button"]):not([type="submit"]):not([type="reset"]):not([type="file"]), +.cl-wrap select, +.cl-wrap textarea, +.cl-wrap .cbi-input-text, +.cl-wrap .cbi-input-select { + background: var(--cl-input-bg) !important; + border: 1px solid var(--cl-input-border) !important; + color: var(--text-color, inherit) !important; +} + +.cl-wrap .cbi-value-title, +.cl-wrap .cl-card .lbl, +.cl-wrap .cl-live-title, +.cl-wrap .cl-section > h4 { + color: var(--title-color, var(--text-color, inherit)) !important; +} + +.cl-wrap .cbi-section-descr, +.cl-wrap .cl-card .val, +.cl-wrap .cl-ctrl, +.cl-wrap .cl-status-note, +.cl-wrap .cl-check-updated { + color: var(--text-color, inherit) !important; +} + +.cl-wrap.cl-overview-page #cl-status-val .cl-status-note-fail, +.cl-wrap.cl-overview-page #cl-status-val .cl-status-note-degraded, +.cl-wrap.cl-overview-page .cl-card-mode .cl-mode-degraded { + color: #b56f00 !important; + opacity: 0.92 !important; +} + +.cl-wrap.cl-overview-page #cl-status-val .cl-status-note-pass { + color: #4aa065 !important; + opacity: 0.92 !important; +} + +.cl-wrap.cl-overview-page .cl-ctrl-row select, +.cl-wrap.cl-overview-page .cl-ctrl-row .cbi-input-select, +.cl-wrap.cl-overview-page .cl-btn-panel-update, +.cl-wrap.cl-overview-page .cl-btn-panel-open { + height: 32px !important; + min-height: 32px !important; + line-height: 32px !important; + vertical-align: middle !important; +} + +.cl-wrap.cl-overview-page .cl-config-row { + display: flex !important; + align-items: center !important; + gap: 8px !important; +} + +.cl-wrap.cl-overview-page .cl-config-row select, +.cl-wrap.cl-overview-page .cl-config-row .cbi-input-select { + flex: 1 1 auto !important; + min-width: 0 !important; +} + +.cl-wrap.cl-overview-page .cl-config-row .cl-btn-update-sub { + height: 32px !important; + min-height: 32px !important; + line-height: 32px !important; + padding: 0 12px !important; + margin: 0 !important; + border: 1px solid var(--cl-input-border) !important; + border-radius: var(--border-radius, 8px) !important; + background: var(--cl-input-bg) !important; + color: var(--text-color, inherit) !important; + box-shadow: none !important; + display: inline-flex !important; + align-items: center !important; + justify-content: center !important; + white-space: nowrap !important; +} + +/* ===== Config page consistency pass (subs/proxy/dns + sing-box profiles/wizard) ===== */ +.cl-wrap.cl-config-page #cl-panel-subs .cl-section.cl-card, +.cl-wrap.cl-config-page #cl-panel-profiles .cl-section.cl-card, +.cl-wrap.cl-config-page #cl-panel-wizard .cl-section.cl-card, +.cl-wrap.cl-config-page #cl-panel-proxy .cbi-section, +.cl-wrap.cl-config-page #cl-panel-dns .cbi-section { + background: var(--cl-card-bg) !important; + border: 1px solid var(--cl-surface-border) !important; + border-bottom: 1px solid var(--cl-surface-border) !important; + border-radius: var(--border-radius, var(--cl-radius, 12px)) !important; + box-shadow: var(--card-shadow, var(--cl-card-shadow)) !important; + padding: 16px 18px !important; + margin: 0 0 14px !important; +} + +.cl-wrap.cl-config-page #cl-panel-subs .cl-section > h4, +.cl-wrap.cl-config-page #cl-panel-profiles .cl-section > h4, +.cl-wrap.cl-config-page #cl-panel-wizard .cl-section > h4, +.cl-wrap.cl-config-page #cl-panel-proxy .cbi-section > h3, +.cl-wrap.cl-config-page #cl-panel-dns .cbi-section > h3 { + display: flex !important; + align-items: center !important; + gap: 8px !important; + margin: 0 0 12px !important; + background: transparent !important; + border: 0 !important; + box-shadow: none !important; + padding: 16px 20px !important; + font-size: 0.95rem !important; + font-weight: 600 !important; + color: var(--title-color, var(--cl-title-color)) !important; + opacity: 1 !important; +} + +.cl-wrap.cl-config-page #cl-panel-subs .cl-section > h4::before, +.cl-wrap.cl-config-page #cl-panel-profiles .cl-section > h4::before, +.cl-wrap.cl-config-page #cl-panel-wizard .cl-section > h4::before, +.cl-wrap.cl-config-page #cl-panel-proxy .cbi-section > h3::before, +.cl-wrap.cl-config-page #cl-panel-dns .cbi-section > h3::before { + content: '' !important; + width: 3px !important; + height: 14px !important; + border-radius: 2px !important; + background: var(--primary-color, var(--cl-primary)) !important; + flex: 0 0 3px !important; +} + +.cl-wrap.cl-config-page #cl-panel-proxy .cbi-value-title, +.cl-wrap.cl-config-page #cl-panel-dns .cbi-value-title { + color: var(--cl-label-muted) !important; +} + +.cl-wrap.cl-config-page #cl-panel-subs .cl-fixed-600, +.cl-wrap.cl-config-page #cl-panel-subs .cl-rewrite-wrap, +.cl-wrap.cl-config-page #cl-panel-profiles .cl-fixed-600, +.cl-wrap.cl-config-page #cl-panel-profiles .cl-sb-form, +.cl-wrap.cl-config-page #cl-panel-wizard .cl-fixed-600, +.cl-wrap.cl-config-page #cl-panel-wizard .cl-sb-form, +.cl-wrap.cl-config-page #cl-panel-proxy .cbi-value-field, +.cl-wrap.cl-config-page #cl-panel-dns .cbi-value-field, +.cl-wrap.cl-config-page #cl-panel-proxy .cl-control-wrap, +.cl-wrap.cl-config-page #cl-panel-dns .cl-control-wrap { + max-width: 600px !important; +} + +.cl-wrap.cl-config-page #cl-panel-subs .cl-sub-url, +.cl-wrap.cl-config-page #cl-panel-subs .cl-rewrite-wrap .cbi-input-select, +.cl-wrap.cl-config-page #cl-panel-subs .cl-rewrite-wrap select, +.cl-wrap.cl-config-page #cl-panel-wizard .cl-sub-url, +.cl-wrap.cl-config-page #cl-panel-profiles .cl-json-editor, +.cl-wrap.cl-config-page #cl-panel-proxy .cbi-value-field input:not([type="checkbox"]):not([type="radio"]):not([type="button"]):not([type="submit"]):not([type="reset"]):not([type="file"]), +.cl-wrap.cl-config-page #cl-panel-proxy .cbi-value-field select, +.cl-wrap.cl-config-page #cl-panel-proxy .cbi-value-field textarea, +.cl-wrap.cl-config-page #cl-panel-dns .cbi-value-field input:not([type="checkbox"]):not([type="radio"]):not([type="button"]):not([type="submit"]):not([type="reset"]):not([type="file"]), +.cl-wrap.cl-config-page #cl-panel-dns .cbi-value-field select, +.cl-wrap.cl-config-page #cl-panel-dns .cbi-value-field textarea { + background: var(--cl-input-bg) !important; + border: 1px solid var(--cl-input-border) !important; + border-bottom: 1px solid var(--cl-input-border) !important; + border-radius: var(--border-radius, 8px) !important; + color: var(--cl-input-color) !important; + box-shadow: none !important; + min-height: 38px !important; + padding: 0 12px !important; +} + +.cl-wrap.cl-config-page #cl-panel-subs .cl-rewrite-wrap textarea, +.cl-wrap.cl-config-page #cl-panel-proxy .cbi-value-field textarea, +.cl-wrap.cl-config-page #cl-panel-dns .cbi-value-field textarea { + min-height: 84px !important; + height: auto !important; + padding: 8px 12px !important; +} + +/* 大文件回退的原生 textarea 编辑器尺寸(CM 自带尺寸,不受此规则影响)*/ +.cl-wrap.cl-config-page #cl-panel-profiles .cl-json-editor, +.cl-wrap.cl-config-page #cl-panel-subs .cl-json-editor { + min-height: 420px !important; + height: auto !important; + padding: 10px 14px !important; + font-family: ui-monospace, "SFMono-Regular", Menlo, Monaco, Consolas, monospace !important; + font-size: 12.5px !important; + line-height: 1.6 !important; + resize: vertical !important; + white-space: pre !important; +} + +.cl-wrap.cl-config-page #cl-panel-subs .cl-file-item, +.cl-wrap.cl-config-page #cl-panel-profiles .cl-sub-list { + background: var(--cl-card-bg) !important; + border: 1px solid var(--cl-surface-border) !important; + border-radius: var(--border-radius, 8px) !important; + box-shadow: none !important; +} + +.cl-wrap.cl-config-page #cl-panel-subs .cl-rewrite-wrap, +.cl-wrap.cl-config-page #cl-panel-subs .cl-rewrite-group { + background: transparent !important; + border: 0 !important; + border-radius: 0 !important; + box-shadow: none !important; + padding-left: 0 !important; + padding-right: 0 !important; +} + +.cl-wrap.cl-config-page #cl-panel-subs .cl-rewrite-group-template, +.cl-wrap.cl-config-page #cl-panel-subs .cl-rewrite-group-input, +.cl-wrap.cl-config-page #cl-panel-subs .cl-template-row, +.cl-wrap.cl-config-page #cl-panel-subs .cl-template-select-wrap { + background: transparent !important; + border: 0 !important; + box-shadow: none !important; +} + +/* ===== System page consistency pass (kernel/rules/logs) ===== */ +.cl-wrap.cl-system-page #cl-panel-kernel .cbi-section, +.cl-wrap.cl-system-page #cl-panel-rules .cbi-section, +.cl-wrap.cl-system-page #cl-panel-kernel .cl-component-card, +.cl-wrap.cl-system-page #cl-panel-logs .cl-section.cl-card { + background: var(--cl-card-bg) !important; + border: 1px solid var(--cl-surface-border) !important; + border-bottom: 1px solid var(--cl-surface-border) !important; + border-radius: var(--border-radius, var(--cl-radius, 12px)) !important; + box-shadow: var(--card-shadow, var(--cl-card-shadow)) !important; + padding: 16px 18px !important; + margin: 0 0 14px !important; +} + +/* 组件更新外层容器:保持透明,让内容卡片与其他页面满宽对齐 */ +.cl-wrap.cl-system-page #cl-panel-kernel .cl-component-map { + background: transparent !important; + padding: 0 !important; + border-radius: 0 !important; + margin: 0 0 14px !important; +} + +.cl-wrap.cl-system-page #cl-panel-kernel .cbi-section > h3, +.cl-wrap.cl-system-page #cl-panel-kernel .cl-component-head > div > h4, +.cl-wrap.cl-system-page #cl-panel-rules .cbi-section > h3, +.cl-wrap.cl-system-page #cl-panel-logs .cl-section > h4 { + display: flex !important; + align-items: center !important; + gap: 8px !important; + margin: 0 0 12px !important; + padding: 0 !important; + background: transparent !important; + border: 0 !important; + box-shadow: none !important; + font-size: 0.95rem !important; + font-weight: 600 !important; + color: var(--title-color, var(--cl-title-color)) !important; + opacity: 1 !important; +} + +.cl-wrap.cl-system-page #cl-panel-kernel .cbi-section > h3::before, +.cl-wrap.cl-system-page #cl-panel-kernel .cl-component-head > div > h4::before, +.cl-wrap.cl-system-page #cl-panel-rules .cbi-section > h3::before, +.cl-wrap.cl-system-page #cl-panel-logs .cl-section > h4::before { + content: '' !important; + width: 3px !important; + height: 14px !important; + border-radius: 2px !important; + background: var(--primary-color, var(--cl-primary)) !important; + flex: 0 0 3px !important; +} + +.cl-wrap.cl-system-page #cl-panel-kernel .cbi-value-title, +.cl-wrap.cl-system-page #cl-panel-rules .cbi-value-title, +.cl-wrap.cl-system-page #cl-panel-kernel .cl-component-desc { + color: var(--cl-label-muted) !important; +} + +/* 备份与还原:按钮行,自动换行以适配移动端 */ +.cl-wrap.cl-system-page #cl-panel-kernel .cl-backup-actions { + display: flex; + flex-wrap: wrap; + gap: 8px; + margin-top: 12px; +} + +.cl-wrap.cl-system-page #cl-panel-kernel .cbi-value-field, +.cl-wrap.cl-system-page #cl-panel-rules .cbi-value-field, +.cl-wrap.cl-system-page #cl-panel-kernel .cl-control-wrap, +.cl-wrap.cl-system-page #cl-panel-rules .cl-control-wrap { + max-width: 600px !important; +} + +.cl-wrap.cl-system-page #cl-panel-kernel .cl-component-arch-row, +.cl-wrap.cl-system-page #cl-panel-kernel .cl-component-row, +.cl-wrap.cl-system-page #cl-panel-kernel .cl-component-log { + background: var(--cl-card-bg) !important; + border: 1px solid var(--cl-surface-border) !important; + border-radius: var(--border-radius, 8px) !important; + box-shadow: none !important; +} + +.cl-wrap.cl-system-page #cl-panel-kernel .cl-component-adv-bar { + background: var(--cl-control-bg) !important; + border: 1px solid var(--cl-control-border) !important; + border-radius: var(--border-radius, 8px) !important; +} + +.cl-wrap.cl-system-page #cl-panel-kernel .cl-component-adv-bar:hover { + background: var(--cl-primary-soft) !important; +} + +.cl-wrap.cl-system-page #cl-panel-kernel .cbi-value-field input:not([type="checkbox"]):not([type="radio"]):not([type="button"]):not([type="submit"]):not([type="reset"]):not([type="file"]), +.cl-wrap.cl-system-page #cl-panel-kernel .cbi-value-field select, +.cl-wrap.cl-system-page #cl-panel-kernel .cbi-value-field textarea, +.cl-wrap.cl-system-page #cl-panel-rules .cbi-value-field input:not([type="checkbox"]):not([type="radio"]):not([type="button"]):not([type="submit"]):not([type="reset"]):not([type="file"]), +.cl-wrap.cl-system-page #cl-panel-rules .cbi-value-field select, +.cl-wrap.cl-system-page #cl-panel-rules .cbi-value-field textarea { + background: var(--cl-input-bg) !important; + border: 1px solid var(--cl-input-border) !important; + border-bottom: 1px solid var(--cl-input-border) !important; + border-radius: var(--border-radius, 8px) !important; + color: var(--cl-input-color) !important; + box-shadow: none !important; + min-height: 38px !important; + padding: 0 12px !important; +} + +.cl-wrap.cl-system-page #cl-panel-kernel .cbi-value-field textarea, +.cl-wrap.cl-system-page #cl-panel-rules .cbi-value-field textarea { + min-height: 84px !important; + height: auto !important; + padding: 8px 12px !important; +} + +.cl-wrap.cl-system-page #cl-panel-logs .cl-log-area { + background: var(--cl-input-bg) !important; + border: 1px solid var(--cl-input-border) !important; + border-radius: var(--border-radius, 8px) !important; + color: var(--cl-field-color) !important; + box-shadow: none !important; +} + +.cl-wrap.cl-system-page #cl-panel-logs .cl-log-tab { + background: var(--cl-input-bg) !important; + border: 1px solid var(--cl-input-border) !important; + color: var(--cl-field-color) !important; + box-shadow: none !important; +} + +.cl-wrap.cl-system-page #cl-panel-logs .cl-log-tab.active { + background: rgba(var(--primary-rgb, var(--cl-primary-rgb)), 0.12) !important; + border-color: rgba(var(--primary-rgb, var(--cl-primary-rgb)), 0.24) !important; + color: var(--cl-primary) !important; +} + +/* ===== Final polish: remove traffic inner borders + minimalist selects ===== */ +.cl-wrap.cl-overview-page .cl-card-traffic .cl-live-box, +.cl-wrap.cl-overview-page .cl-card-traffic .cl-live-grid, +.cl-wrap.cl-overview-page .cl-card-traffic .cl-live-card, +.cl-wrap.cl-overview-page .cl-card-traffic .cl-stat-card { + border: none !important; + box-shadow: none !important; +} + +.cl-wrap.cl-overview-page .cl-card-traffic .cl-live-card, +.cl-wrap.cl-overview-page .cl-card-traffic .cl-stat-card { + background: var(--cl-live-card-bg) !important; +} + +.cl-wrap select, +.cl-wrap .cbi-input-select { + border-top: none !important; + border-left: none !important; + border-right: none !important; + border-bottom: 1px solid rgba(var(--primary-rgb, var(--cl-primary-rgb)), 0.2) !important; + border-radius: 0 !important; + box-shadow: none !important; +} + +.cl-wrap.cl-overview-page .cbi-input-select, +.cl-wrap.cl-overview-page .cl-ctrl-row select, +.cl-wrap.cl-overview-page .cl-controls .cl-ctrl select, +.cl-wrap.cl-overview-page .cl-controls .cl-ctrl .cbi-input-select, +.cl-wrap.cl-config-page #cl-panel-subs .cbi-input-select, +.cl-wrap.cl-config-page #cl-panel-subs select, +.cl-wrap.cl-config-page #cl-panel-proxy .cbi-value-field select, +.cl-wrap.cl-config-page #cl-panel-dns .cbi-value-field select, +.cl-wrap.cl-system-page #cl-panel-kernel .cbi-value-field select, +.cl-wrap.cl-system-page #cl-panel-rules .cbi-value-field select { + border-top: none !important; + border-left: none !important; + border-right: none !important; + border-bottom: 1px solid rgba(var(--primary-rgb, var(--cl-primary-rgb)), 0.2) !important; + border-radius: 0 !important; + box-shadow: none !important; +} + +.cl-wrap.cl-system-page #cl-panel-kernel .cl-component-arch-row .cl-component-arch-sel { + background: rgba(46, 170, 92, 0.12) !important; + color: #24844d !important; + border: 1px solid rgba(46, 170, 92, 0.28) !important; + border-radius: 6px !important; + box-shadow: none !important; + font-weight: 700 !important; +} + +.cl-wrap.cl-system-page.cl-theme-dark #cl-panel-kernel .cl-component-arch-row .cl-component-arch-sel, +body.dark .cl-wrap.cl-system-page #cl-panel-kernel .cl-component-arch-row .cl-component-arch-sel, +body[data-theme="dark"] .cl-wrap.cl-system-page #cl-panel-kernel .cl-component-arch-row .cl-component-arch-sel, +html.dark .cl-wrap.cl-system-page #cl-panel-kernel .cl-component-arch-row .cl-component-arch-sel, +html[data-theme="dark"] .cl-wrap.cl-system-page #cl-panel-kernel .cl-component-arch-row .cl-component-arch-sel, +html[data-bs-theme="dark"] .cl-wrap.cl-system-page #cl-panel-kernel .cl-component-arch-row .cl-component-arch-sel { + background: rgba(104, 199, 135, 0.16) !important; + color: rgba(198, 246, 211, 0.95) !important; + border-color: rgba(104, 199, 135, 0.3) !important; +} + +/* ===== Overview status spacing + semantic run state ===== */ +.cl-wrap.cl-overview-page .cl-card-head { + margin-bottom: 10px !important; +} + +.cl-wrap.cl-overview-page .cl-card .val { + display: block; + line-height: 1.55 !important; +} + +.cl-wrap.cl-overview-page #cl-status-val { + display: flex; + align-items: center; + gap: 8px; + flex-wrap: wrap; +} + +.cl-wrap.cl-overview-page #cl-status-val .cl-status-note { + margin-left: 0 !important; +} + +.cl-wrap.cl-overview-page .cl-status-state { + display: inline-flex; + align-items: center; + padding: 0 !important; + border: 0 !important; + border-radius: 0 !important; + background: transparent !important; + color: inherit; + font-size: 11px; + font-weight: 500; + line-height: 1.35; +} + +.cl-wrap.cl-overview-page .cl-status-state-run { + color: #24945f !important; +} + +.cl-wrap.cl-overview-page .cl-status-state-stop { + color: rgba(128, 128, 128, 0.9) !important; +} + +/* ─── Theme-override: force transparent bg on LuCI form elements ─── + 不论哪个主题(Argon / Bootstrap / Material 等),只要给表格行 / + form 行 / 列表项上了斑马纹,透过我们的透明元素就会显出底色杂色。 + 这里统一 reset 所有 LuCI 核心容器的背景,主题无关。 */ +.cl-wrap table tbody tr, +.cl-wrap table tbody tr:nth-of-type(2n), +.cl-wrap .table .tbody .tr, +.cl-wrap .table .tbody .tr:nth-of-type(2n), +.cl-wrap .cbi-value, +.cl-wrap .cbi-value:nth-of-type(2n), +.cl-wrap .cbi-rowstyle-1, +.cl-wrap .cbi-rowstyle-2, +.cl-wrap .cbi-section-table-row, +.cl-wrap .cbi-dynlist, +.cl-wrap .cbi-dynlist .item, +.cl-wrap .cbi-dynlist .item:nth-of-type(2n), +.cl-wrap .cbi-dynlist .add-item { + background: transparent !important; +} + +/* DynamicList items: config 页面不加外框(避免双框),system 页面 IP 主机需要外框 */ +.cl-wrap .cbi-dynlist .item { + color: inherit !important; + margin-bottom: 4px !important; +} +.cl-wrap.cl-system-page .cbi-dynlist .item { + border: 1px solid rgba(128, 128, 128, 0.22) !important; + border-radius: 6px !important; + padding: 4px 10px !important; +} +.cl-wrap .cbi-dynlist .item.flash { + animation: none !important; + background: rgba(var(--primary-rgb, 0, 122, 255), 0.08) !important; +} + +/* DynamicList 删除/添加按钮在暗色下对比度 */ +.cl-wrap .cbi-dynlist .item > span.close, +.cl-wrap .cbi-dynlist .item > .close { + color: #c96a5a !important; + opacity: 0.8; +} + +/* ─── Bug 4: 限制内联 Value 输入框宽度,不撑满父容器 ─── */ +.cl-wrap .cbi-value input[type="text"], +.cl-wrap .cbi-value input[type="password"], +.cl-wrap .cbi-value-field > .cbi-input-text, +.cl-wrap .cbi-value-field > input.cbi-input-text { + max-width: 480px; + box-sizing: border-box; +} + +/* issue #14: DynamicList 窄屏自适应 — 行宽跟容器走、输入框可收缩, + 避免删除(×)/添加(+)按钮在窄手机上被挤出屏幕。 + 仅在窄屏触发;桌面端沿用 LuCI 默认尺寸,避免不同 section 的父容器宽度差异 + 把 DynamicList 撑到 600/1450 等不同长度,造成同页上下输入框宽窄不一。 */ +@media (max-width: 768px) { + .cl-wrap .cbi-dynlist { + display: flex !important; + flex-direction: column; + width: 100%; + max-width: 100%; + box-sizing: border-box; + } + .cl-wrap .cbi-dynlist .item, + .cl-wrap .cbi-dynlist .add-item { + width: 100%; + max-width: 100%; + box-sizing: border-box; + } + .cl-wrap .cbi-dynlist .item > span { + flex: 1 1 auto; + min-width: 0; + overflow: hidden; + text-overflow: ellipsis; + } + .cl-wrap .cbi-dynlist .add-item { + display: flex; + align-items: center; + gap: 6px; + } + .cl-wrap .cbi-dynlist .add-item > .cbi-input-text, + .cl-wrap .cbi-dynlist .add-item > input[type="text"] { + flex: 1 1 auto; + min-width: 0; + max-width: 100% !important; + } +} + +/* 一键测速并应用:状态文案 — 浅色主题下与同页 .cbi-value-description + (Fake-IP / Redir-Host 单选描述)保持同色,视觉一致 */ +.cl-wrap.cl-theme-light .cl-dns-auto-status { + color: rgba(120, 130, 150, 0.9) !important; +} + +/* Smart 策略设置 — 行动按钮 + 当前版本说明(桌面端:横排,移动端:换行) */ +.cl-smart-action-row { + display: flex; + align-items: center; + gap: 10px; + flex-wrap: wrap; +} +.cl-smart-action-row .cl-hint { + word-break: break-word; + overflow-wrap: anywhere; +} +@media (max-width: 480px) { + .cl-smart-action-row { + gap: 8px; + } + .cl-smart-action-row .btn { + flex: 0 0 auto; + } + .cl-smart-action-row .cl-hint { + flex: 1 1 100%; + font-size: 12px; + line-height: 1.4; + } +} + +/* 按钮 + 版本时间戳纵向堆叠(按钮上方,版本浅绿小字在下) */ +.cl-btn-ver-wrap { + display: inline-flex; + flex-direction: column; + align-items: flex-start; + gap: 4px; +} +.cl-ver-tag { + font-size: 12px; + word-break: break-word; +} +.cl-ver-label { color: rgba(128, 128, 128, 0.6); } +.cl-ver-value { color: #4aa065; } + +/* GeoIP / 内核下载:按钮 + 版本文字横向同行 */ +.cl-btn-ver-row { + display: flex; + align-items: center; + gap: 10px; + flex-wrap: wrap; +} + +/* ══════════════════════════════════════════════════════════ + 浅色主题对比度修复 (Argon light / Bootstrap light) + - getThemeClass() 优先检测 dark.css 是否加载,返回 cl-theme-light + - overview 页面不在选择器内,不受影响 + - section 使用白卡片,外层容器保持透明满宽 + ══════════════════════════════════════════════════════════ */ + +/* 1. CSS 变量覆盖 — 实色值取代半透明,确保白底上清晰可见 */ +.cl-wrap.cl-theme-light.cl-config-page, +.cl-wrap.cl-theme-light.cl-system-page { + --cl-card-bg: #ffffff; + --cl-card-border: #d8dce6; + --cl-surface-border: #d8dce6; + --cl-card-shadow: 0 2px 8px rgba(0, 0, 0, 0.08); + --card-shadow: 0 2px 8px rgba(0, 0, 0, 0.08); + --cl-input-bg: #ffffff; + --cl-input-border: #c5c9d2; +} + +/* 2. 表单外层透明满宽:与订阅页一致,不额外压缩内容区 */ +.cl-wrap.cl-theme-light.cl-config-page .cbi-map, +.cl-wrap.cl-theme-light.cl-system-page .cbi-map { + background: transparent !important; + padding: 0 !important; + border-radius: 0 !important; + margin-top: 0 !important; +} + +/* 3. Section 白底 — config & system 页面共用 */ +.cl-wrap.cl-theme-light.cl-config-page .cl-panel .cbi-section, +.cl-wrap.cl-theme-light.cl-config-page .cl-section.cl-card, +.cl-wrap.cl-theme-light.cl-config-page .cl-panel.cl-card, +.cl-wrap.cl-theme-light.cl-system-page .cl-panel .cbi-section, +.cl-wrap.cl-theme-light.cl-system-page .cl-section.cl-card, +.cl-wrap.cl-theme-light.cl-system-page .cl-panel.cl-card { + background: #ffffff !important; + border: 1px solid #d8dce6 !important; + border-radius: 10px !important; + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.07) !important; + padding: 14px 18px 18px !important; + margin-bottom: 12px !important; +} + +/* 4. 输入框 / 下拉框 / 文本域 — 明确边框,白底文字清晰 */ +.cl-wrap.cl-theme-light.cl-config-page input:not([type="checkbox"]):not([type="radio"]):not([type="button"]):not([type="submit"]):not([type="reset"]):not([type="file"]), +.cl-wrap.cl-theme-light.cl-config-page select, +.cl-wrap.cl-theme-light.cl-config-page textarea, +.cl-wrap.cl-theme-light.cl-system-page input:not([type="checkbox"]):not([type="radio"]):not([type="button"]):not([type="submit"]):not([type="reset"]):not([type="file"]), +.cl-wrap.cl-theme-light.cl-system-page select, +.cl-wrap.cl-theme-light.cl-system-page textarea { + background: #ffffff !important; + border: 1px solid #c5c9d2 !important; + border-radius: 6px !important; + color: inherit !important; +} diff --git a/luci-app-clashoo/htdocs/luci-static/resources/view/clashoo/config.js b/luci-app-clashoo/htdocs/luci-static/resources/view/clashoo/config.js new file mode 100644 index 000000000..8a9bb6b5d --- /dev/null +++ b/luci-app-clashoo/htdocs/luci-static/resources/view/clashoo/config.js @@ -0,0 +1,1896 @@ +'use strict'; +'require view'; +'require form'; +'require uci'; +'require ui'; +'require rpc'; +'require tools.clashoo as clashoo'; + +function getThemeClass() { + var h = document.documentElement; + // Bootstrap: explicit data-bs-theme attribute wins first + if (h.dataset.bsTheme === 'dark') return 'cl-theme-dark'; + if (h.dataset.bsTheme === 'light') return 'cl-theme-light'; + // Argon: explicit darkmode attribute + if (h.dataset.darkmode === 'true') return 'cl-theme-dark'; + // Argon: dark.css loaded in document = dark mode active (most reliable) + var links = document.querySelectorAll('link[rel="stylesheet"]'); + for (var i = 0; i < links.length; i++) { + if (links[i].href && links[i].href.indexOf('dark.css') !== -1) return 'cl-theme-dark'; + } + // Generic: .dark class on root element + if (h.classList.contains('dark')) return 'cl-theme-dark'; + // Body background luminance (skip transparent/rgba backgrounds) + var bg = window.getComputedStyle(document.body).backgroundColor; + if (bg && bg.indexOf('rgba') === -1 && bg.indexOf('rgb') !== -1) { + var m = bg.match(/\d+/g); + if (m && m.length >= 3 && (parseInt(m[0]) + parseInt(m[1]) + parseInt(m[2])) / 3 < 100) return 'cl-theme-dark'; + } + return 'cl-theme-light'; +} + +var CSS = [ + '.cl-wrap{font-family:-apple-system,BlinkMacSystemFont,"Segoe UI","PingFang SC",sans-serif;--cl-card-border:rgba(128,128,128,.22);--cl-card-bg:rgba(128,128,128,.08);--cl-card-shadow:0 4px 12px rgba(0,0,0,.08);--cl-muted:rgba(74,85,104,.9);--cl-meta:var(--cl-muted);--cl-primary:rgba(0,122,255,.8);--cl-primary-border:rgba(0,122,255,.45);--cl-primary-soft:rgba(0,122,255,.08)}', + '.cl-tabs{display:flex;border-bottom:2px solid rgba(128,128,128,.15);margin-bottom:18px}', + '.cl-tab{padding:10px 20px;cursor:pointer;font-size:13px;opacity:.55;border-bottom:2px solid transparent;margin-bottom:-2px;transition:opacity .15s}', + '.cl-tab.active{opacity:1;border-bottom-color:currentColor;font-weight:600}', + '.cl-panel{display:none}.cl-panel.active{display:block}', + '.cl-sub-list{width:100%;border-collapse:collapse;margin:12px 0;font-size:13px;table-layout:fixed}', + '.cl-sub-list th,.cl-sub-list td{padding:8px 10px;border-bottom:1px solid rgba(128,128,128,.15);text-align:left;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}', + '.cl-sub-list th{font-size:11px;opacity:.55;font-weight:600}', + '.cl-sub-list th:nth-child(2),.cl-sub-list td:nth-child(2){width:72px}', + '.cl-sub-list th:nth-child(3),.cl-sub-list td:nth-child(3){width:220px;text-align:right;white-space:nowrap}', + '.cl-sub-url{border:1px solid rgba(128,128,128,.3);border-radius:6px;padding:8px 10px;width:100%;box-sizing:border-box;font-size:13px;margin-bottom:8px}', + '.cl-sub-traffic{margin-top:4px;font-size:11px;color:var(--cl-meta,var(--cl-muted,#666))}', + '.cl-sub-traffic-bar{height:4px;border-radius:2px;background:rgba(128,128,128,.18);margin-top:3px;overflow:hidden}', + '.cl-sub-traffic-fill{height:100%;border-radius:2px;background:var(--primary-color,#0b68dd);transition:width .3s}', + '.cl-sub-traffic-fill.cl-traffic-warn{background:#f59e0b}', + '.cl-sub-traffic-fill.cl-traffic-danger{background:#ef4444}', + '.cl-sub-expire{font-size:11px;color:var(--cl-meta,var(--cl-muted,#666));margin-top:2px}', + '.cl-sub-expire.cl-expire-soon{color:#f59e0b}', + '.cl-btn-sm{padding:4px 10px;font-size:12px;border-radius:4px;cursor:pointer}', + '.cl-section{margin-bottom:24px}', + '.cl-section h4{font-size:1.15rem;font-weight:600;margin-bottom:10px;color:var(--title-color,var(--cl-muted));opacity:.95}', + /* constrain form inputs on desktop, table stays full-width */ + '.cl-form-wrap{max-width:640px}', + '.cl-file-list{display:flex;flex-direction:column;gap:10px;margin-top:10px}', + '.cl-file-item{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:10px 12px;border:1px solid var(--cl-card-border);border-radius:8px;background:var(--cl-card-bg);box-shadow:var(--cl-card-shadow)}', + '.cl-file-item.is-active{background:rgba(var(--primary-rgb,0,122,255),.08);border-color:rgba(var(--primary-rgb,0,122,255),.2)}', + '.cl-file-meta{display:flex;flex:1;min-width:0;align-items:center;justify-content:space-between;gap:12px}', + '.cl-file-name{display:flex;align-items:center;gap:8px;min-width:0}', + '.cl-file-name-text{font-size:13px;font-weight:600;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}', + '.cl-sb-file-name{display:flex;align-items:center;gap:8px;min-width:0;white-space:normal !important;overflow:visible !important;text-overflow:clip !important}', + '.cl-sb-file-name .cl-file-name-text{min-width:0}', + '.cl-file-size{font-size:12px;color:var(--cl-meta);white-space:nowrap}', + '.cl-file-actions{display:flex;align-items:center;gap:8px;flex-shrink:0}', + '.cl-rewrite-wrap{max-width:760px;padding:0;border:0;background:transparent;box-shadow:none}', + '.cl-rewrite-group{display:flex;flex-direction:column;gap:8px}', + '.cl-rewrite-group-title{font-size:12px;font-weight:700;opacity:.68}', + '.cl-rw-divider{height:1px;background:rgba(128,128,128,.18);margin:10px 0}', + '.cl-rewrite-wrap .cl-sub-url,.cl-rewrite-wrap .cbi-input-select{padding:8px 12px;border-radius:6px;width:100%;box-sizing:border-box;margin-bottom:0}', + '.cl-rewrite-actions{margin-top:4px}', + '.cl-actions{display:flex;gap:8px;flex-wrap:wrap}', + '.cl-btn-update-sub{border-color:var(--cl-primary-border);color:var(--cl-primary)}', + '.cl-btn-switch{background:var(--cl-primary-soft);border:1px solid var(--cl-primary-border);color:var(--cl-primary)}', + '.cl-btn-switch:hover{background:rgba(0,122,255,.14);border-color:rgba(0,122,255,.62);color:rgba(0,96,220,.92)}', + '.cl-btn-delete{border:1px solid rgba(var(--primary-rgb,0,122,255),.32);color:var(--cl-primary);background:rgba(var(--primary-rgb,0,122,255),.1)}', + '.cl-btn-delete:hover{background:rgba(var(--primary-rgb,0,122,255),.16);border-color:rgba(var(--primary-rgb,0,122,255),.4);color:var(--cl-primary)}', + '.cl-btn-generate-switch{box-shadow:0 4px 10px rgba(0,0,128,.2)}', + '.cl-save-bar{display:flex;gap:8px;margin-top:14px;padding-top:12px;border-top:1px solid rgba(128,128,128,.15)}', + '.cl-dns-auto{display:flex;flex-direction:column;gap:8px;max-width:640px}', + '.cl-dns-auto-actions{display:flex;align-items:center;gap:10px;flex-wrap:wrap}', + '.cl-dns-auto-status{font-size:12px;color:var(--cl-meta);line-height:1.55}', + '.cl-dns-auto-result{display:grid;grid-template-columns:repeat(auto-fit,minmax(210px,1fr));gap:6px 14px;padding:8px 10px;border:1px solid var(--cl-card-border);border-radius:8px;background:var(--cl-card-bg);color:var(--cl-meta);font-size:12px;line-height:1.5}', + '.cl-dns-auto-result b{font-weight:700;opacity:.72;margin-right:4px}', + '.cl-sub-schedule{display:flex;flex-direction:column;gap:5px;max-width:760px;box-sizing:border-box;margin:2px 0 14px;padding:8px 2px 4px 6px}', + '.cl-sub-schedule-row{display:flex;align-items:center;gap:10px;flex-wrap:nowrap}', + '.cl-sub-schedule-toggle{display:inline-flex;align-items:center;gap:8px;height:30px;font-size:13px;font-weight:600;line-height:30px;cursor:pointer;white-space:nowrap}', + '.cl-sub-schedule-toggle input[type="checkbox"]{appearance:none!important;-webkit-appearance:none!important;position:static!important;top:auto!important;bottom:auto!important;width:16px!important;height:16px!important;min-width:16px!important;min-height:16px!important;margin:0!important;padding:0!important;border:1px solid rgba(128,128,128,.7)!important;border-radius:3px!important;background:transparent!important;box-shadow:none!important;vertical-align:middle!important;flex:0 0 16px}', + '.cl-sub-schedule-toggle input[type="checkbox"]:checked{border-color:var(--cl-primary)!important;background:var(--cl-primary) url("data:image/svg+xml,%3Csvg xmlns=%27http://www.w3.org/2000/svg%27 viewBox=%270 0 16 16%27%3E%3Cpath fill=%27none%27 stroke=%27white%27 stroke-width=%272.2%27 d=%27M3 8l3 3 7-7%27/%3E%3C/svg%3E") center/12px 12px no-repeat!important}', + '.cl-sub-schedule-status{font-size:11px;color:var(--cl-meta);line-height:1.45}', + '.cl-sub-schedule-interval{display:inline-flex;align-items:center;gap:6px;height:30px;font-size:12px;line-height:30px;color:var(--cl-meta);white-space:nowrap}', + '.cl-sub-schedule-interval input[type="number"]{width:52px!important;height:30px!important;min-height:30px!important;box-sizing:border-box!important;margin:0!important;padding:2px 6px!important;line-height:24px!important;text-align:center}', + '.cl-sub-schedule-row .btn,.cl-sub-schedule-row .cbi-button{height:30px!important;min-height:30px!important;box-sizing:border-box!important;padding:3px 10px!important;line-height:22px!important}', + '.cl-sub-schedule-row :disabled{cursor:not-allowed;opacity:.62}', + '.cl-section-toggle{font-size:12px;cursor:pointer;flex-shrink:0;margin-left:auto}', + '.cl-collapsible.cl-closed>*:not(h3){display:none!important}', + /* 折叠标题:通过 .clashoo-section-header wrapper class 上色,不裸改 LuCI 默认 h3 样式 */ + '.clashoo-section-header{display:flex!important;align-items:center;gap:8px;position:relative}', + '.clashoo-section-header::before{content:"";flex:0 0 3px;width:3px;height:14px;border-radius:2px;background:var(--primary-color,var(--cl-primary,#007aff))}', + '.cl-wrap .cbi-section-remove.right{background:transparent!important}', + '.cl-json-editor{width:100%;height:340px;font-family:monospace;font-size:11px;border:1px solid rgba(128,128,128,.25);border-radius:8px;padding:10px;box-sizing:border-box;resize:vertical;background:rgba(0,0,0,.02)}', + '.cl-editor-hdr{display:flex;align-items:center;gap:8px;margin-bottom:6px;font-size:12px;font-weight:600}', + /* CodeMirror 编辑器外观(小文件套 CM,大文件回退 cl-json-editor textarea)*/ + '.cl-cm-wrap{width:100%}', + '.cl-cm-host .CodeMirror{height:340px;border:1px solid rgba(128,128,128,.25);border-radius:8px;font-size:12px;font-family:monospace}', + '.cl-cm-host.cl-cm-dark .CodeMirror{background:#1e2228;color:#d4d4d4}', + '.cl-cm-host.cl-cm-dark .CodeMirror-gutters{background:#23282f;border-right:1px solid rgba(255,255,255,.08)}', + '.cl-cm-host.cl-cm-dark .CodeMirror-linenumber{color:#5c6370}', + '.cl-cm-host.cl-cm-dark .CodeMirror-cursor{border-left-color:#d4d4d4}', + '.cl-cm-host.cl-cm-dark .CodeMirror-selected{background:rgba(255,255,255,.12)}', + '.cl-cm-host.cl-cm-dark .CodeMirror-activeline-background{background:rgba(255,255,255,.04)}', + '.cl-cm-host.cl-cm-dark .cm-string{color:#ce9178}', + '.cl-cm-host.cl-cm-dark .cm-number{color:#b5cea8}', + '.cl-cm-host.cl-cm-dark .cm-keyword,.cl-cm-host.cl-cm-dark .cm-atom{color:#569cd6}', + '.cl-cm-host.cl-cm-dark .cm-property,.cl-cm-host.cl-cm-dark .cm-attribute{color:#9cdcfe}', + '.cl-cm-host.cl-cm-dark .cm-comment{color:#6a9955}', + '.cl-cm-host.cl-cm-dark .cm-meta,.cl-cm-host.cl-cm-dark .cm-def{color:#dcdcaa}', + '.cl-active-badge{font-size:10px;font-weight:700;padding:2px 7px;border-radius:10px;background:rgba(var(--primary-rgb,0,122,255),.12);color:var(--cl-primary)}', + '.cl-hint{font-size:11px;opacity:.45;margin-left:auto}', + /* hide auto-generated section IDs in TypedSection */ + '.cbi-section-table-titles .cbi-section-table-cell:first-child{display:none}', + '.cbi-section-table-row .cbi-section-table-cell:first-child{display:none}', + '.cl-mode-tabs{display:inline-flex;gap:4px;margin:6px 0}', + '.cl-mode-tab-active{font-weight:700}', + '.cl-panel .cbi-section>h3{font-size:13px !important;font-weight:600;margin-bottom:8px}', + '.cl-panel .cbi-value-title{font-size:13px !important}', + '.cl-panel .cbi-value-field input,.cl-panel .cbi-value-field select,.cl-panel .cbi-value-field textarea{font-size:13px !important}', + '.cl-panel .cbi-section-descr,.cl-panel .cbi-value-helptext{font-size:12px !important}', + '.cl-panel .cbi-section{margin-bottom:12px}', + '.cl-wrap .cbi-section>h3,.cl-wrap .cbi-value-title,.cl-wrap .cbi-section-descr,.cl-wrap .cbi-value-helptext{font-family:-apple-system,BlinkMacSystemFont,"Segoe UI","PingFang SC",sans-serif !important}', + '.cl-wrap .cbi-input-text,.cl-wrap .cbi-input-select,.cl-wrap select,.cl-wrap input,.cl-wrap textarea,.cl-wrap .btn,.cl-wrap .cbi-button{font-size:13px !important;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI","PingFang SC",sans-serif !important}', + '.cl-wrap .btn,.cl-wrap .cbi-button{padding:4px 10px;line-height:1.35}', + '.cl-sb-list td,.cl-sb-size{color:var(--cl-meta)}', + '@media(prefers-color-scheme:dark){.cl-wrap{--cl-card-border:rgba(255,255,255,.14);--cl-card-bg:rgba(255,255,255,.04);--cl-card-shadow:0 4px 12px rgba(0,0,0,.28);--cl-muted:rgba(220,228,244,.58);--cl-meta:rgba(220,228,244,.72)}}', + '.cl-theme-dark{--cl-card-border:rgba(255,255,255,.14);--cl-card-bg:rgba(255,255,255,.04);--cl-card-shadow:0 4px 12px rgba(0,0,0,.28);--cl-muted:rgba(220,228,244,.58);--cl-meta:rgba(220,228,244,.72)}', + '@media(max-width:680px){.cl-wrap{--cl-meta:#4b5870}.cl-sub-list.cl-sb-list td:first-child{white-space:normal;overflow:visible;text-overflow:clip}}', + '@media(max-width:680px){.cl-file-name-text,.cl-file-size,.cl-sub-traffic,.cl-sub-expire,.cl-sb-list td,.cl-sb-size,.cl-dns-auto-status,.cl-dns-auto-result{color:#4b5870!important}}', + '@media(max-width:680px){html body .cl-wrap .cl-file-item .cl-file-meta .cl-file-size{color:#4b5870!important}}', + '@media(max-width:680px){.cl-file-item{flex-direction:column;align-items:stretch;gap:8px}.cl-file-meta{flex-direction:column;align-items:stretch;gap:6px}.cl-file-name-text{white-space:normal;overflow-wrap:anywhere}.cl-file-actions{justify-content:flex-end}.cl-sub-expire,.cl-sub-traffic{white-space:normal}}', + '@media(max-width:680px){.cl-form-wrap{max-width:100%}}', + '@media(max-width:680px){.cl-dns-auto,.cl-dns-auto-result{max-width:100%;width:100%;box-sizing:border-box}.cl-dns-auto-result{grid-template-columns:1fr}}', + '@media(max-width:680px){.cl-sub-schedule{width:100%;padding:8px 0 4px 4px}.cl-sub-schedule-row{gap:8px;flex-wrap:wrap}.cl-sub-schedule-toggle{width:100%}.cl-sub-schedule-interval{gap:5px}.cl-sub-schedule-row .cbi-button-action{white-space:nowrap}}' +].join(''); + +var callListSubs = rpc.declare({ object: 'luci.clashoo', method: 'list_subscriptions', expect: {} }); +var callListDir = rpc.declare({ object: 'luci.clashoo', method: 'list_dir_files', params: ['type'], expect: {} }); +var callDownloadSubs = rpc.declare({ object: 'luci.clashoo', method: 'download_subs', expect: {} }); +var callDownloadSubsStatus = rpc.declare({ object: 'luci.clashoo', method: 'download_subs_status', expect: {} }); +var callUpdateSub = rpc.declare({ object: 'luci.clashoo', method: 'update_sub', params: ['name'], expect: {} }); +var callSubscriptionUpdateAll = rpc.declare({ object: 'luci.clashoo', method: 'subscription_update_all', expect: {} }); +var callSubscriptionUpdateStatus = rpc.declare({ object: 'luci.clashoo', method: 'subscription_update_status', expect: {} }); +var callSetSubscriptionUpdateSchedule = rpc.declare({ object: 'luci.clashoo', method: 'set_subscription_update_schedule', params: ['enabled', 'interval'], expect: {} }); +var callSetConfig = rpc.declare({ object: 'luci.clashoo', method: 'set_config', params: ['name'], expect: {} }); +var callDeleteCfg = rpc.declare({ object: 'luci.clashoo', method: 'delete_config', params: ['name', 'type'], expect: {} }); +var callUploadConfigChunk = rpc.declare({ object: 'luci.clashoo', method: 'upload_config_chunk', params: ['name', 'content', 'type', 'index', 'total'], expect: {} }); +var callReadOtherConfig = rpc.declare({ object: 'luci.clashoo', method: 'read_other_config', params: ['name', 'type'], expect: {} }); +var callListTemplates = rpc.declare({ object: 'luci.clashoo', method: 'list_templates', expect: {} }); +var callUploadTemplate= rpc.declare({ object: 'luci.clashoo', method: 'upload_template', params: ['name', 'content'], expect: {} }); +var callApplyRewrite = rpc.declare({ object: 'luci.clashoo', method: 'apply_rewrite', params: ['base_type','base_name','rewrite_type','rewrite_name','output_name','set_active'], expect: {} }); +var callFetchUrl = rpc.declare({ object: 'luci.clashoo', method: 'fetch_rewrite_url', params: ['url','name'], expect: {} }); +var callApplyTplUrl = rpc.declare({ object: 'luci.clashoo', method: 'apply_template_with_url', params: ['template_source','sub_url','output_name','set_active'], expect: {} }); +var callMigrateSbProfile = rpc.declare({ object: 'luci.clashoo', method: 'migrate_singbox_profile', params: ['name'], expect: {} }); +var callSmartFlushCache = rpc.declare({ object: 'luci.clashoo', method: 'smart_flush_cache', expect: {} }); +var callDetectPrimaryGroup = rpc.declare({ object: 'luci.clashoo', method: 'detect_primary_group', expect: {} }); + +function fastResolve(promise, timeoutMs, fallback) { + var t = new Promise(function (resolve) { + setTimeout(function () { resolve(fallback); }, timeoutMs); + }); + return Promise.race([L.resolveDefault(promise, fallback), t]); +} + +function uploadConfigContent(name, content, type) { + var chunkSize = 24576; + var total = Math.max(1, Math.ceil((content || '').length / chunkSize)); + var index = 0; + + function sendNext() { + var chunk = (content || '').slice(index * chunkSize, (index + 1) * chunkSize); + return L.resolveDefault(callUploadConfigChunk(name, chunk, type || '2', String(index), String(total)), {}).then(function (r) { + if (!r || !r.success) + throw new Error((r && (r.message || r.error)) || _("Upload failed")); + index++; + return index < total ? sendNext() : r; + }); + } + + return sendNext(); +} + +function loadUiState() { + return L.resolveDefault(uci.load('clashoo'), null).then(function () { + return { + core_type: uci.get('clashoo', 'config', 'core_type') || 'mihomo', + subscribe_url: uci.get('clashoo', 'config', 'subscribe_url') || '', + config_name: uci.get('clashoo', 'config', 'config_name') || '', + sub_ua: uci.get('clashoo', 'config', 'sub_ua') || '', + auto_subscription_update: uci.get('clashoo', 'config', 'auto_subscription_update') || '0', + subscription_update_interval: uci.get('clashoo', 'config', 'subscription_update_interval') || '72' + }; + }); +} + +function buildSubscriptionSchedule(uiData, initialStatus) { + var enabled = E('input', { + type: 'checkbox', + checked: uiData.auto_subscription_update === '1' ? '' : null + }); + var interval = E('input', { + type: 'number', + min: '1', + max: '8760', + value: uiData.subscription_update_interval || '72' + }); + var statusEl = E('div', { 'class': 'cl-sub-schedule-status' }); + var saveBtn, runBtn, timer; + + function syncScheduleState() { + interval.disabled = !enabled.checked; + } + + enabled.addEventListener('change', syncScheduleState); + + function renderStatus(st) { + st = st || {}; + if (st.running) { + statusEl.textContent = _("Updating all subscriptions…"); + return; + } + if (!st.last_run) { + statusEl.textContent = _("Only subscriptions with recorded source URLs are overwritten; no duplicate files are created."); + return; + } + var when = new Date(st.last_run * 1000).toLocaleString(); + statusEl.textContent = _("Last run: ") + when + _("; updated ") + (st.updated || 0) + + _(", unchanged ") + (st.unchanged || 0) + _(", failed ") + (st.failed || 0) + + _(", skipped ") + (st.skipped || 0) + '.'; + } + + function pollStatus() { + L.resolveDefault(callSubscriptionUpdateStatus(), {}).then(function (st) { + renderStatus(st); + if (!st.running) { + if (timer) clearInterval(timer); + timer = null; + runBtn.disabled = false; + runBtn.textContent = _("Update All Now"); + } + }); + } + + saveBtn = E('button', { + 'class': 'btn cbi-button cl-btn-sm', + click: function () { + var hours = parseInt(interval.value, 10); + if (!hours || hours < 1 || hours > 8760) { + ui.addNotification(null, E('p', _("Update interval must be 1 to 8760 hours"))); + return; + } + saveBtn.disabled = true; + L.resolveDefault(callSetSubscriptionUpdateSchedule(enabled.checked ? '1' : '0', String(hours)), {}).then(function (r) { + saveBtn.disabled = false; + ui.addNotification(null, E('p', r && r.success ? _("Scheduled update settings saved") : (_("Save failed: ") + ((r && r.message) || '')))); + }); + } + }, _("Save")); + + runBtn = E('button', { + 'class': 'btn cbi-button-action cl-btn-sm', + click: function () { + runBtn.disabled = true; + runBtn.textContent = _("Updating…"); + L.resolveDefault(callSubscriptionUpdateAll(), {}).then(function (r) { + if (!r || (!r.success && !r.running)) { + runBtn.disabled = false; + runBtn.textContent = _("Update All Now"); + ui.addNotification(null, E('p', _("Start failed: ") + ((r && r.message) || ''))); + return; + } + renderStatus({ running: true }); + timer = setInterval(pollStatus, 2000); + setTimeout(pollStatus, 500); + }); + } + }, _("Update All Now")); + + syncScheduleState(); + renderStatus(initialStatus); + return E('div', { 'class': 'cl-sub-schedule' }, [ + E('div', { 'class': 'cl-sub-schedule-row' }, [ + E('label', { 'class': 'cl-sub-schedule-toggle' }, [enabled, E('span', {}, _("Scheduled Subscription Update"))]), + E('div', { 'class': 'cl-sub-schedule-interval' }, [ + E('span', {}, _("Every")), + interval, + E('span', {}, _("hours")) + ]), + saveBtn, + runBtn + ]), + statusEl + ]); +} + +var SUB_UA_PRESETS = ['', 'clash', 'clash.meta', 'mihomo']; + +// 构造 UA 选择器:select 预设 + custom 切到 input +// 返回 { wrap, getValue() } +function buildUaPicker(initialValue) { + var presets = SUB_UA_PRESETS; + var isPreset = presets.indexOf(initialValue) !== -1; + var customVal = (!initialValue || isPreset) ? '' : initialValue; + var pickerVal = isPreset ? initialValue : (initialValue ? '__custom__' : ''); + + var customInput = E('input', { + 'class': 'cl-sub-url', + type: 'text', + placeholder: _("Custom User-Agent"), + value: customVal, + style: 'margin-top:0;' + (pickerVal === '__custom__' ? '' : 'display:none') + }); + + var selectEl = E('select', { + 'class': 'cbi-input-select cl-sub-url', + style: 'margin-top:0', + change: function (ev) { + customInput.style.display = (ev.target.value === '__custom__') ? '' : 'none'; + if (ev.target.value === '__custom__') customInput.focus(); + } + }, [ + E('option', { value: '', selected: pickerVal === '' ? '' : null }, _("Default")), + E('option', { value: 'clash', selected: pickerVal === 'clash' ? '' : null }, 'clash'), + E('option', { value: 'clash.meta', selected: pickerVal === 'clash.meta' ? '' : null }, 'clash.meta'), + E('option', { value: 'mihomo', selected: pickerVal === 'mihomo' ? '' : null }, 'mihomo'), + E('option', { value: '__custom__', selected: pickerVal === '__custom__' ? '' : null }, _("Customize...")) + ]); + + return { + wrap: E('div', { 'class': 'cl-ua-picker', style: 'display:flex;flex-direction:column;gap:6px;margin-top:0' }, [ + E('label', { style: 'font-size:12px;color:var(--text-secondary, #888)' }, _("User-Agent (UA)")), + selectEl, customInput, + E('div', { style: 'font-size:12px;color:var(--text-secondary, #888)' }, _("Keep the default if unsure.")) + ]), + getValue: function () { + return selectEl.value === '__custom__' ? customInput.value.trim() : selectEl.value; + } + }; +} + +function readSavedTab(key, fallback, allowed) { + var raw = ''; + if (window.location.hash) + raw = window.location.hash.replace(/^#/, ''); + if (!raw) { + try { raw = window.localStorage.getItem(key) || ''; } catch (e) {} + } + return allowed.indexOf(raw) >= 0 ? raw : fallback; +} + +function rememberTab(key, id) { + try { window.localStorage.setItem(key, id); } catch (e) {} + if (window.history && window.history.replaceState) + window.history.replaceState(null, '', '#' + id); + else + window.location.hash = id; +} + +function fmtBytes(b) { + b = parseInt(b) || 0; + if (b >= 1e12) return (b / 1e12).toFixed(2) + ' TB'; + if (b >= 1e9) return (b / 1e9).toFixed(2) + ' GB'; + if (b >= 1e6) return (b / 1e6).toFixed(1) + ' MB'; + return Math.round(b / 1e3) + ' KB'; +} +function fmtExpireDate(ts) { + if (!ts || ts === 0) return ''; + var d = new Date(ts * 1000); + var pad2 = function (n) { return n < 10 ? '0' + n : '' + n; }; + return d.getFullYear() + '-' + pad2(d.getMonth() + 1) + '-' + pad2(d.getDate()); +} +/* 渲染流量条;返回 DOM 节点或 null */ +function renderTrafficBar(used, total) { + total = parseInt(total) || 0; + if (total <= 0) return null; + used = parseInt(used) || 0; + var pct = Math.min(100, Math.round(used / total * 100)); + var fillCls = 'cl-sub-traffic-fill' + (pct >= 90 ? ' cl-traffic-danger' : pct >= 75 ? ' cl-traffic-warn' : ''); + return E('div', { 'class': 'cl-sub-traffic' }, [ + fmtBytes(used) + ' / ' + fmtBytes(total) + ' (' + pct + '%)', + E('div', { 'class': 'cl-sub-traffic-bar' }, [ + E('div', { 'class': fillCls, 'style': 'width:' + pct + '%' }) + ]) + ]); +} +/* 渲染到期文本;返回 DOM 节点或 null */ +function renderExpire(ts) { + if (!ts) return null; + var daysLeft = Math.ceil((ts * 1000 - Date.now()) / 86400000); + var cls = 'cl-sub-expire' + (daysLeft <= 7 ? ' cl-expire-soon' : ''); + return E('div', { 'class': cls }, + _("Expires: ") + fmtExpireDate(ts) + (daysLeft > 0 ? ' (' + daysLeft + _(" days)") : _(" (expired)"))); +} + +function decorateControlWraps(root) { + if (!root || !root.querySelectorAll) + return; + var fields = root.querySelectorAll('.cbi-value-field'); + for (var i = 0; i < fields.length; i++) { + if (fields[i] && fields[i].classList) + fields[i].classList.add('cl-control-wrap'); + } +} + +function clearClashooDirty() { + var applyPromise; + try { + applyPromise = (L.uci && typeof L.uci.callApply === 'function') + ? Promise.resolve(L.uci.callApply(0, false)).catch(function () {}) + : Promise.resolve(); + } catch (e) { applyPromise = Promise.resolve(); } + return applyPromise.then(function () { + try { + if (L.ui && L.ui.changes && L.ui.changes.changes) { + delete L.ui.changes.changes.clashoo; + var n = Object.keys(L.ui.changes.changes).length; + if (typeof L.ui.changes.renderChangeIndicator === 'function') + L.ui.changes.renderChangeIndicator(n); + else if (typeof L.ui.changes.setIndicator === 'function') + L.ui.changes.setIndicator(n); + } + } catch (e) {} + }); +} + +function saveCommitApplyMaybeReload(m, runningMsg, stoppedMsg) { + return clashoo.status() + .then(function (st) { return !!(st && st.running); }) + .catch(function () { return false; }) + .then(function (running) { + /* silent=true so the caller's catch reports validation errors once (no double popup) */ + return m.save(null, true) + .then(function () { return clashoo.commitConfig(); }) + .then(function () { + return running ? clashoo.reload() : { success: true, skipped: true }; + }) + .then(function () { return clearClashooDirty(); }) + .then(function () { + ui.addNotification(null, E('p', running ? runningMsg : stoppedMsg)); + window.setTimeout(function () { location.reload(); }, 300); + }); + }); +} + +function dnsAutoSummaryNode(res) { + if (!res || !res.success) + return E('div', { 'class': 'cl-dns-auto-status' }, _("No auto setup result yet")); + var elapsed = Math.max(0, parseInt(res.elapsed_ms || 0, 10)); + var failed = parseInt(res.failed_count || 0, 10); + return E('div', { 'class': 'cl-dns-auto-result' }, [ + E('span', [E('b', _("Domestic")), res.nameserver || '-']), + E('span', [E('b', _("Proxy")), res.proxy_nameserver || '-']), + E('span', [E('b', _("Fallback")), res.fallback || '-']), + E('span', [E('b', _("Bootstrap")), res.bootstrap || res.direct_nameserver || '-']), + E('span', [E('b', _("Time")), elapsed ? (elapsed / 1000).toFixed(1) + _(" seconds") : '-']), + E('span', [E('b', _("Failed")), failed + _(" candidates")]) + ]); +} + +function dnsAutoResultMessage(res) { + if (!res || !res.success) + return (res && res.message) || _("DNS auto setup failed"); + return res.restarted + ? _("DNS auto setup applied, service is restarting") + : _("DNS auto setup saved, service is not running"); +} + +function storeDnsAutoResult(res) { + try { + res._saved_at = Date.now(); + window.localStorage.setItem('clashoo.dns_auto.last', JSON.stringify(res)); + } catch (e) {} +} + +function readDnsAutoResult() { + try { + var raw = window.localStorage.getItem('clashoo.dns_auto.last') || ''; + return raw ? JSON.parse(raw) : null; + } catch (e) { + return null; + } +} + +function clearDnsAutoResult() { + try { window.localStorage.removeItem('clashoo.dns_auto.last'); } catch (e) {} +} + +function setDnsAutoStatus(statusEl, nodeOrText) { + statusEl.textContent = ''; + if (nodeOrText && nodeOrText.nodeType) + statusEl.appendChild(nodeOrText); + else + statusEl.textContent = nodeOrText || ''; +} + +function findCbiSection(root, title) { + var heads = root.querySelectorAll('.cbi-section > h3'); + for (var i = 0; i < heads.length; i++) { + if ((heads[i].textContent || '').trim() === title) + return heads[i].parentNode; + } + return null; +} + +function makeSectionCollapsible(root, title, open) { + var section = findCbiSection(root, title); + if (!section || section.classList.contains('cl-collapsible')) + return; + section.classList.add('cl-collapsible'); + if (!open) section.classList.add('cl-closed'); + var btn = E('button', { + 'class': 'btn cbi-button cl-section-toggle', + click: function (ev) { + ev.preventDefault(); + section.classList.toggle('cl-closed'); + btn.textContent = section.classList.contains('cl-closed') ? _("Expand") : _("Collapse"); + } + }, open ? _("Collapse") : _("Expand")); + var h3 = section.querySelector('h3'); + if (h3) { + h3.classList.add('clashoo-section-header'); + h3.appendChild(btn); + } +} + +/* ── CodeMirror 懒加载(资源打包在 luci-static/resources/cm/)── */ +var _cmLoad = null; +function loadCodeMirror() { + if (_cmLoad) return _cmLoad; + _cmLoad = new Promise(function (resolve, reject) { + var base = L.resource('cm'), ver = '?v=20260520'; + var link = document.createElement('link'); + link.rel = 'stylesheet'; + link.href = base + '/codemirror.css' + ver; + document.head.appendChild(link); + var inject = function (src) { + return new Promise(function (res, rej) { + var s = document.createElement('script'); + s.src = src; s.async = false; + s.onload = res; + s.onerror = function () { rej(new Error('load failed: ' + src)); }; + document.head.appendChild(s); + }); + }; + /* 核心先就位,mode/addon 注册在全局 CodeMirror 上 */ + inject(base + '/codemirror.js' + ver) + .then(function () { + return Promise.all([ + inject(base + '/mode/yaml.js' + ver), + inject(base + '/mode/javascript.js' + ver), + inject(base + '/addon/matchbrackets.js' + ver) + ]); + }) + .then(function () { + if (window.CodeMirror) resolve(); + else reject(new Error('CodeMirror not available')); + }) + .catch(reject); + }); + return _cmLoad; +} + +/* CodeMirror for files ≤512KB; fallback to textarea for oversized or failed load */ +function createConfigEditor(mode) { + var LARGE = 512 * 1024; + var ta = E('textarea', { + 'class': 'cl-json-editor', + placeholder: _("Configuration content appears here after selecting a file…") + }); + var host = E('div', { 'class': 'cl-cm-host', style: 'display:none' }); + var wrap = E('div', { 'class': 'cl-cm-wrap' }, [host, ta]); + var cm = null, usingCM = false; + + function showTextarea(content) { + usingCM = false; + ta.value = content; + ta.style.display = ''; + host.style.display = 'none'; + } + function showCM(content) { + usingCM = true; + cm.setValue(content); + ta.style.display = 'none'; + host.style.display = ''; + setTimeout(function () { cm.refresh(); }, 0); + } + + return { + el: wrap, + textarea: ta, + setValue: function (content) { + content = (content == null) ? '' : String(content); + if (content.length > LARGE) { showTextarea(content); return; } + if (cm) { showCM(content); return; } + loadCodeMirror().then(function () { + if (!cm && window.CodeMirror) { + cm = window.CodeMirror(host, { + value: '', mode: mode, + lineNumbers: true, matchBrackets: true, + lineWrapping: true, tabSize: 2, indentUnit: 2, + viewportMargin: 60 + }); + if (getThemeClass().indexOf('dark') >= 0) + host.classList.add('cl-cm-dark'); + } + if (cm) showCM(content); else showTextarea(content); + }).catch(function () { showTextarea(content); }); + }, + getValue: function () { + return (usingCM && cm) ? cm.getValue() : ta.value; + } + }; +} + +// 全局锁:内核操作互斥(切换配置 / 更新订阅 / 删除) +function clKernelBusy() { return !!document.body.getAttribute('data-cl-kernel-busy'); } +function clKernelLock() { + document.body.setAttribute('data-cl-kernel-busy', '1'); + document.querySelectorAll('.cl-btn-switch, .cl-btn-update-sub, .cl-btn-delete').forEach(function (b) { b.disabled = true; }); +} +function clKernelUnlock() { + document.body.removeAttribute('data-cl-kernel-busy'); + document.querySelectorAll('.cl-btn-switch, .cl-btn-update-sub, .cl-btn-delete').forEach(function (b) { b.disabled = false; }); +} + +return view.extend({ + _tab: null, + _sbTab: null, + + load: function () { + return Promise.all([ + fastResolve(callListSubs(), 1200, { subs: [], url: '' }), + fastResolve(callListDir('1'), 1200, { files: [] }), + fastResolve(callListDir('2'), 1200, { files: [] }), + fastResolve(callListDir('3'), 1200, { files: [] }), + fastResolve(callListTemplates(), 1200, { files: [] }), + fastResolve(loadUiState(), 1200, { core_type: 'mihomo', subscribe_url: '', config_name: '', sub_ua: '' }), + fastResolve(clashoo.listSingboxProfiles(), 1200, { profiles: [], active: '' }), + fastResolve(callSubscriptionUpdateStatus(), 1200, {}) + ]); + }, + + render: function (data) { + var self = this; + var subsData = data[0] || {}; + var subFiles = (data[1] && data[1].files) || []; + var upFiles = (data[2] && data[2].files) || []; + var customFiles= (data[3] && data[3].files) || []; + var tplFiles = (data[4] && data[4].files) || []; + var uiData = data[5] || { core_type: 'mihomo', subscribe_url: '', config_name: '', sub_ua: '' }; + var sbData = data[6] || { profiles: [], active: '' }; + var subscriptionUpdateStatus = data[7] || {}; + var coreType = uiData.core_type || 'mihomo'; + + if (!document.getElementById('cl-css')) { + var s = document.createElement('style'); + s.id = 'cl-css'; s.textContent = CSS; + document.head.appendChild(s); + } + if (!document.getElementById('cl-css-ext')) { + var link = document.createElement('link'); + link.id = 'cl-css-ext'; + link.rel = 'stylesheet'; + link.href = L.resource('view/clashoo/clashoo.css') + '?v=20260806a1'; + document.head.appendChild(link); + } else { + document.getElementById('cl-css-ext').href = L.resource('view/clashoo/clashoo.css') + '?v=20260806a1'; + } + + if (coreType === 'singbox') return this._renderSingbox(sbData, uiData, subscriptionUpdateStatus); + + var tabs = [ + { id: 'subs', label: _("Subscription") }, + { id: 'proxy', label: _("Proxy") }, + { id: 'dns', label: 'DNS' } + ]; + var allowedTabs = tabs.map(function (t) { return t.id; }); + this._tab = readSavedTab('clashoo.config.tab', this._tab || 'subs', allowedTabs); + rememberTab('clashoo.config.tab', this._tab); + var tabEls = {}; + var panelEls = {}; + + var subPanel = E('div', { 'class': 'cl-panel' + (this._tab === 'subs' ? ' active' : ''), id: 'cl-panel-subs' }, + this._buildSubsPanel(subsData, subFiles, upFiles, customFiles, tplFiles, uiData, subscriptionUpdateStatus) + ); + panelEls['subs'] = subPanel; + + var proxyPanel = E('div', { 'class': 'cl-panel' + (this._tab === 'proxy' ? ' active' : ''), id: 'cl-panel-proxy' }); + panelEls['proxy'] = proxyPanel; + + var dnsPanel = E('div', { 'class': 'cl-panel' + (this._tab === 'dns' ? ' active' : ''), id: 'cl-panel-dns' }); + panelEls['dns'] = dnsPanel; + + var built = { subs: true, proxy: false, dns: false }; + var ensureBuilt = function (id) { + if (built[id]) return; + if (id === 'proxy') self._buildProxyForm(proxyPanel); + else if (id === 'dns') self._buildDnsForm(dnsPanel); + built[id] = true; + }; + if (this._tab !== 'subs') ensureBuilt(this._tab); + + var tabBar = E('div', { 'class': 'cl-tabs' }, + tabs.map(function (t) { + var el = E('div', { + 'class': 'cl-tab' + (self._tab === t.id ? ' active' : ''), + click: function () { + ensureBuilt(t.id); + Object.keys(tabEls).forEach(function (k) { + tabEls[k].className = 'cl-tab' + (k === t.id ? ' active' : ''); + panelEls[k].className = 'cl-panel' + (k === t.id ? ' active' : ''); + }); + self._tab = t.id; + rememberTab('clashoo.config.tab', t.id); + } + }, t.label); + tabEls[t.id] = el; + return el; + }) + ); + + return E('div', { 'class': 'cl-wrap clashoo-container cl-config-page cl-form-page ' + getThemeClass() }, [tabBar, subPanel, proxyPanel, dnsPanel]); + }, + + _buildSubsPanel: function (subsData, subFiles, upFiles, customFiles, tplFiles, uiData, subscriptionUpdateStatus) { + var self = this; + var sanitizeText = function (v) { return (v == null || v === 'null') ? '' : String(v); }; + var subUrl = sanitizeText(uiData && uiData.subscribe_url); + var savedName = sanitizeText(uiData && uiData.config_name); + var savedUa = sanitizeText(uiData && uiData.sub_ua); + var subs = subsData.subs || []; + var safeText = function (v) { return (v == null || v === 'null') ? '' : String(v); }; + + var urlInput = E('input', { + 'class': 'cl-sub-url', + type: 'text', + placeholder: _("Subscription URLs (one per line)"), + value: subUrl + }); + + var nameInput = E('input', { + 'class': 'cl-sub-url', + type: 'text', + placeholder: _("File name (optional, blank to auto-generate)"), + value: savedName, + style: 'margin-top:0' + }); + + var uaPicker = buildUaPicker(savedUa); + + var dlStatusEl = E('div', { 'class': 'cl-update-status', style: 'margin-top:6px;font-size:12px;min-height:18px;line-height:1.4' }); + var setDlStatus = function (text, tone) { + dlStatusEl.textContent = text || ''; + dlStatusEl.style.color = tone === 'success' ? 'var(--success-color, #2e7d32)' + : tone === 'error' ? 'var(--error-color, #d32f2f)' + : tone === 'progress'? 'var(--tip-color, #1976d2)' + : ''; + }; + var stopDlPoll = function () { + if (self._subDlTimer) { clearInterval(self._subDlTimer); self._subDlTimer = null; } + }; + + var dlBtn = E('button', { + 'class': 'btn cbi-button-action cl-btn-sm', + click: function () { + if (!urlInput.value.trim()) { + setDlStatus(_("✗ Please enter a subscription URL first"), 'error'); + setTimeout(function () { setDlStatus(''); }, 4000); + return; + } + stopDlPoll(); + dlBtn.disabled = true; + dlBtn.textContent = _("Downloading…"); + setDlStatus(_("⏳ Submitting download task..."), 'progress'); + + var pollCount = 0; + var pollDl = function () { + pollCount++; + callDownloadSubsStatus().then(function (st) { + st = st || {}; + var raw = st.last_line || ''; + var line = clashoo.localizeLogLine(raw); + if (st.running) { + setDlStatus('⏳ ' + (line || _("Downloading subscription...")), 'progress'); + return; + } + /* sh has not flushed yet, wait a few polls */ + if (!raw && pollCount < 4) return; + stopDlPoll(); + /* 收尾行只有三种:「订阅下载完成:成功 N 个,失败 M 个」=成功(含"失败 0 个" + 字样,不能按"失败"判负);「订阅下载失败:全部链接失败」「未找到订阅链接」=失败 */ + var ok = /下载完成|completed/i.test(raw); + /* fail_detail carries the real cause(rc=/HTTP/校验失败): + all fail: show real cause; partial: summary + cause */ + var detail = st.fail_detail ? clashoo.localizeLogLine(st.fail_detail) : ''; + var shown = ok ? (line + (detail ? ' · ' + detail : '')) + : (detail || line || _("Subscription download failed")); + dlBtn.disabled = false; + dlBtn.textContent = _("Download Subscription"); + setDlStatus((ok ? '✓ ' : '✗ ') + shown, ok ? 'success' : 'error'); + setTimeout(function () { location.reload(); }, 1200); + }).catch(function () {}); + }; + + L.resolveDefault(uci.load('clashoo'), null) + .then(function () { + uci.set('clashoo', 'config', 'subscribe_url', urlInput.value); + uci.set('clashoo', 'config', 'config_name', nameInput.value.trim()); + uci.set('clashoo', 'config', 'sub_ua', uaPicker.getValue()); + return uci.save(); + }) + .then(function () { return clashoo.commitConfig(); }) + .then(function () { return clearClashooDirty(); }) + .then(function () { return L.resolveDefault(callDownloadSubs(), {}); }) + .then(function (r) { + if (r && r.running) setDlStatus(_("⏳ A download task is already running..."), 'progress'); + self._subDlTimer = setInterval(pollDl, 2000); + setTimeout(pollDl, 800); + }) + .catch(function (e) { + stopDlPoll(); + dlBtn.disabled = false; + dlBtn.textContent = _("Download Subscription"); + setDlStatus(_("✗ Start failed: ") + (e && e.message || e), 'error'); + }); + } + }, _("Download Subscription")); + + var subCards = subs.map(function (sub) { + var nameNodes = []; + if (sub.active) nameNodes.push(E('span', { 'class': 'cl-active-badge' }, _("Active"))); + nameNodes.push(E('span', { 'class': 'cl-file-name-text' }, safeText(sub.name))); + + var used = (parseInt(sub.sub_upload) || 0) + (parseInt(sub.sub_download) || 0); + var trafficEl = renderTrafficBar(used, sub.sub_total); + var expireEl = renderExpire(sub.sub_expire); + + return E('div', { 'class': 'cl-file-item' + (sub.active ? ' is-active' : '') }, [ + E('div', { 'class': 'cl-file-meta' }, [ + E('div', { 'class': 'cl-file-name' }, nameNodes), + E('div', { 'class': 'cl-file-size' }, safeText(sub.size)), + trafficEl, expireEl + ]), + E('div', { 'class': 'cl-file-actions' }, [ + E('button', { + 'class': 'btn cbi-button cl-btn-sm cl-btn-update-sub', + click: function (ev) { + var btn = ev.target; + if (btn.disabled || clKernelBusy()) return; + clKernelLock(); + btn.disabled = true; + btn.textContent = _("Updating…"); + L.resolveDefault(callUpdateSub(sub.name), {}).then(function (r) { + ui.addNotification(null, E('p', r.success ? sub.name + _(" update succeeded") : _("Update failed"))); + location.reload(); + }).catch(function () { + btn.disabled = false; + btn.textContent = _("Update"); + clKernelUnlock(); + }); + } + }, _("Update")), + E('button', { + 'class': 'btn cbi-button cl-btn-sm cl-btn-switch', + click: function (ev) { + var btn = ev.target; + if (btn.disabled || clKernelBusy()) return; + clKernelLock(); + btn.disabled = true; + btn.textContent = _("Loading…"); + L.resolveDefault(callSetConfig(sub.name), {}).then(function () { + location.reload(); + }).catch(function () { + btn.disabled = false; + btn.textContent = _("Switch Profile"); + clKernelUnlock(); + }); + } + }, _("Switch Profile")), + E('button', { + 'class': 'btn cbi-button cl-btn-sm cl-btn-delete', + click: function () { + if (!confirm(_("Delete ") + sub.name + '?')) return; + L.resolveDefault(callDeleteCfg(sub.name, '1'), {}).then(function () { location.reload(); }); + } + }, _("Delete")) + ]) + ]); + }); + + var uploadInput = E('input', { type: 'file', accept: '.yaml,.yml', style: 'display:none', id: 'cl-upload-input' }); + uploadInput.addEventListener('change', function (ev) { + var file = ev.target.files[0]; + if (!file) return; + var reader = new FileReader(); + reader.onload = function (e) { + uploadConfigContent(file.name, e.target.result, '2').then(function (r) { + ui.addNotification(null, E('p', _("Upload succeeded: ") + r.name)); + location.reload(); + }).catch(function (err) { + ui.addNotification(null, E('p', _("Upload failed: ") + (err && err.message ? err.message : err))); + }); + }; + reader.readAsText(file); + }); + + var mkSel = function (files, placeholder) { + return E('select', { 'class': 'cbi-input-select' }, + [E('option', { value: '' }, placeholder)].concat( + files.map(function (f) { return E('option', { value: f.name }, f.name); }) + ) + ); + }; + + /* ── 模板复写(注入订阅 URL 模式)── */ + var tplSel = mkSel(tplFiles, _("Select local template file")); + tplSel.classList.add('cl-template-select'); + tplSel.setAttribute('title', tplSel.value || ''); + tplSel.addEventListener('change', function () { tplSel.setAttribute('title', tplSel.value || ''); }); + + var tplUploadInput = E('input', { type: 'file', accept: '.yaml,.yml', style: 'display:none', id: 'cl-template-upload-input' }); + tplUploadInput.addEventListener('change', function (ev) { + var file = ev.target.files[0]; + if (!file) return; + var reader = new FileReader(); + reader.onload = function (e) { + L.resolveDefault(callUploadTemplate(file.name, e.target.result), {}).then(function (r) { + if (r && r.success) { + ui.addNotification(null, E('p', _("Template uploaded: ") + (r.name || file.name))); + location.reload(); + return; + } + ui.addNotification(null, E('p', _("Template upload failed: ") + ((r && (r.message || r.error)) || _("Unknown error")))); + }); + }; + reader.readAsText(file); + }); + + var tplUrlIn = E('input', { type: 'text', 'class': 'cl-sub-url', placeholder: _("Enter remote template URL, e.g. https://raw.githubusercontent.com/…/Clash.yaml") }); + var subUrlIn = E('input', { type: 'text', 'class': 'cl-sub-url', placeholder: _("Enter subscription URL (injected into template proxy-providers)") }); + var outNameIn = E('input', { type: 'text', 'class': 'cl-sub-url', placeholder: _("Output file name (without extension, blank to auto-fill)") }); + var rwMode = 'local'; + + function rwAutoFill() { + if (outNameIn.value) return; + var tpl = rwMode === 'local' ? tplSel.value.replace(/\.(yaml|yml)$/, '') : 'remote-tpl'; + if (tpl) outNameIn.value = tpl + '-rewrite'; + } + tplSel.addEventListener('change', rwAutoFill); + + var localPanel = E('div', { 'class': 'cl-rw-pane cl-rw-pane-local' }, [ + tplUploadInput, + E('div', { 'class': 'cl-template-row' }, [ + E('div', { 'class': 'cl-template-select-wrap' }, [tplSel]), + E('button', { + 'class': 'btn cbi-button cl-btn-sm cl-btn-template-upload', + click: function () { document.getElementById('cl-template-upload-input').click(); } + }, _("Upload YAML Template")) + ]) + ]); + var remotePanel = E('div', { 'class': 'cl-rw-pane cl-rw-pane-remote', style: 'display:none' }, [tplUrlIn]); + + var tabLocal = E('button', { 'class': 'btn cbi-button cl-btn-sm cl-mode-tab-active', + click: function () { + rwMode = 'local'; + localPanel.style.display = ''; remotePanel.style.display = 'none'; + tabLocal.classList.add('cl-mode-tab-active'); + tabRemote.classList.remove('cl-mode-tab-active'); + outNameIn.value = ''; + rwAutoFill(); + } + }, _("Local Template")); + var tabRemote = E('button', { 'class': 'btn cbi-button cl-btn-sm', + click: function () { + rwMode = 'remote'; + localPanel.style.display = 'none'; remotePanel.style.display = ''; + tabRemote.classList.add('cl-mode-tab-active'); + tabLocal.classList.remove('cl-mode-tab-active'); + outNameIn.value = ''; + } + }, _("Remote Template")); + + var rwApply = function (setActive) { + var tplSrc = rwMode === 'local' ? tplSel.value : tplUrlIn.value.trim(); + var subUrl = subUrlIn.value.trim(); + var out = outNameIn.value.trim(); + if (!tplSrc) { ui.addNotification(null, E('p', rwMode === 'local' ? _("Please select a local template file") : _("Please enter a remote template URL"))); return; } + if (!subUrl) { ui.addNotification(null, E('p', _("Please enter a subscription URL"))); return; } + if (!out) { ui.addNotification(null, E('p', _("Please enter an output file name"))); return; } + L.resolveDefault(callApplyTplUrl(tplSrc, subUrl, out, setActive ? '1' : '0'), {}).then(function (r) { + ui.addNotification(null, E('p', r && r.success ? (r.message || _("Generated: ") + r.output_name) : (_("Generate failed: ") + (r && r.message || _("Unknown error"))))); + if (r && r.success) location.reload(); + }); + }; + + /* ── 其他配置文件(上传 + 自定义/复写输出)── */ + var otherEditorTitle = E('span', { 'class': 'cl-editor-hdr' }, _("Select a configuration above to edit it here")); + var otherEd = createConfigEditor('yaml'); + var otherSaveBtn = E('button', { + 'class': 'btn cbi-button-action cl-btn-sm', + disabled: '', + click: function () { + var meta = otherEd.textarea.dataset; + if (!meta.name) return; + uploadConfigContent(meta.name, otherEd.getValue(), meta.type).then(function (r) { + if (r && r.success) ui.addNotification(null, E('p', meta.name + _(" saved"))); + else ui.addNotification(null, E('p', _("Save failed: ") + ((r && (r.message || r.error)) || ''))); + }).catch(function (err) { + ui.addNotification(null, E('p', _("Save failed: ") + (err && err.message ? err.message : err))); + }); + } + }, _("Save")); + + var otherEditorBox = E('div', { 'class': 'cl-section cl-card cl-sb-editor' }, [ + otherEditorTitle, + otherEd.el, + E('div', { 'class': 'cl-actions cl-sb-row-actions cl-sb-editor-actions' }, [ + otherSaveBtn, + E('span', { 'class': 'cl-hint' }, _("Click Save after editing; switching configuration automatically restarts the service")) + ]) + ]); + + function loadOtherEditor(name, type) { + otherEditorTitle.textContent = _("Editing: ") + name; + otherSaveBtn.removeAttribute('disabled'); + otherEd.textarea.dataset.name = name; + otherEd.textarea.dataset.type = type; + otherEd.setValue(_("Loading…")); + L.resolveDefault(callReadOtherConfig(name, type), {}).then(function (r) { + otherEd.setValue(r.content || ''); + }); + } + + var makeOtherCards = function (files, type) { + return files.map(function (f) { + var nameNodes = []; + if (f.active) nameNodes.push(E('span', { 'class': 'cl-active-badge' }, _("Active"))); + nameNodes.push(E('span', { 'class': 'cl-file-name-text' }, safeText(f.name))); + + return E('div', { 'class': 'cl-file-item' + (f.active ? ' is-active' : '') }, [ + E('div', { 'class': 'cl-file-meta' }, [ + E('div', { 'class': 'cl-file-name' }, nameNodes), + E('div', { 'class': 'cl-file-size' }, safeText(f.size)) + ]), + E('div', { 'class': 'cl-file-actions' }, [ + E('button', { + 'class': 'btn cbi-button cl-btn-sm cl-btn-edit', + click: function (ev) { + var btn = ev.target; + if (btn.disabled) return; + btn.disabled = true; + var orig = btn.textContent; + btn.textContent = _("Loading…"); + Promise.resolve(loadOtherEditor(f.name, type)).then(function () { + btn.disabled = false; + btn.textContent = orig; + }).catch(function () { + btn.disabled = false; + btn.textContent = orig; + }); + } + }, _("Edit")), + E('button', { + 'class': 'btn cbi-button cl-btn-sm cl-btn-switch', + click: function (ev) { + var btn = ev.target; + if (btn.disabled || clKernelBusy()) return; + clKernelLock(); + btn.disabled = true; + btn.textContent = _("Loading…"); + L.resolveDefault(callSetConfig(f.name), {}).then(function () { + location.reload(); + }).catch(function () { + btn.disabled = false; + btn.textContent = _("Switch Profile"); + clKernelUnlock(); + }); + } + }, _("Switch Profile")), + E('button', { + 'class': 'btn cbi-button cl-btn-sm cl-btn-delete', + click: function (ev) { + var btn = ev.target; + if (btn.disabled || clKernelBusy()) return; + if (!confirm(_("Delete ") + f.name + '?')) return; + clKernelLock(); + btn.disabled = true; + btn.textContent = _("Loading…"); + L.resolveDefault(callDeleteCfg(f.name, type), {}).then(function () { + location.reload(); + }).catch(function () { + btn.disabled = false; + btn.textContent = _("Delete"); + clKernelUnlock(); + }); + } + }, _("Delete")) + ]) + ]); + }); + }; + + var otherFiles = (upFiles || []).map(function(f){ return {f:f, t:'2'}; }) + .concat((customFiles || []).map(function(f){ return {f:f, t:'3'}; })); + + var otherCards = otherFiles.map(function(o) { + return makeOtherCards([o.f], o.t)[0]; + }); + + var sections = [ + E('div', { 'class': 'cl-section cl-card' }, [ + E('h4', {}, _("Subscription URL")), + E('div', { 'class': 'cl-form-wrap cl-fixed-600' }, [urlInput, nameInput, uaPicker.wrap, dlBtn, dlStatusEl]) + ]), + E('div', { 'class': 'cl-section cl-card' }, [ + E('h4', {}, _("Downloaded Subscriptions")), + buildSubscriptionSchedule(uiData, subscriptionUpdateStatus), + subs.length ? E('div', { 'class': 'cl-fixed-600' }, [ + E('div', { 'class': 'cl-file-list' }, subCards) + ]) + : E('p', { style: 'opacity:.5;font-size:13px' }, _("No subscriptions")) + ]), + E('div', { 'class': 'cl-section cl-card' }, [ + E('h4', {}, _("Upload Configuration File")), + uploadInput, + E('button', { + 'class': 'btn cbi-button cl-btn-sm cl-btn-upload-config', + click: function () { document.getElementById('cl-upload-input').click(); } + }, _("Select YAML file to upload")) + ]) + ]; + + if (otherFiles.length) { + sections.push(E('div', { 'class': 'cl-section cl-card' }, [ + E('h4', {}, _("Other Configuration Files (upload / overwrite output)")), + E('div', { 'class': 'cl-fixed-600' }, [ + E('div', { 'class': 'cl-file-list' }, otherCards) + ]) + ])); + sections.push(otherEditorBox); + } + + sections.push( + E('div', { 'class': 'cl-section cl-card' }, [ + E('h4', {}, _("Overwrite Settings")), + E('div', { 'class': 'cl-form-wrap cl-rewrite-wrap cl-fixed-600' }, [ + E('div', { 'class': 'cl-rewrite-group cl-rewrite-group-template' }, [ + E('div', { 'class': 'cl-rewrite-group-title' }, _("Template Selection")), + E('div', { 'class': 'cl-mode-tabs' }, [tabLocal, tabRemote]), + localPanel, + remotePanel + ]), + E('div', { 'class': 'cl-rw-divider' }), + E('div', { 'class': 'cl-rewrite-group cl-rewrite-group-input' }, [ + E('div', { 'class': 'cl-rewrite-group-title' }, _("Information Input")), + subUrlIn, + outNameIn, + E('div', { 'class': 'cl-actions cl-rewrite-actions' }, [ + E('button', { 'class': 'btn cbi-button cl-btn-sm', click: function(){ rwApply(false); } }, _("Generate Configuration")), + E('button', { 'class': 'btn cbi-button-action cl-btn-sm cl-btn-generate-switch', click: function(){ rwApply(true); } }, _("Apply Configuration")) + ]) + ]) + ]) + ]) + ); + + return sections.filter(function (n) { return n !== null && n !== undefined; }); + }, + + _buildProxyForm: function (container) { + var m = new form.Map('clashoo', '', ''); + var s, o; + + s = m.section(form.NamedSection, 'config', 'clashoo', _("Transparent Proxy")); + s.addremove = false; + o = s.option(form.ListValue, 'tcp_mode', _("TCP Mode")); + o.value('redirect', 'Redirect'); o.value('tproxy', 'TPROXY'); o.value('tun', 'TUN'); o.value('off', _("Off")); + o = s.option(form.ListValue, 'udp_mode', _("UDP Mode")); + o.value('tun', 'TUN'); o.value('tproxy', 'TPROXY'); o.value('off', _("Off")); + o = s.option(form.ListValue, 'stack', _("TUN Network Stack")); + o.value('system', 'System'); o.value('gvisor', 'gVisor'); o.value('mixed', 'Mixed'); + o.description = _("TUN stack is used when either TCP or UDP mode is TUN."); + o = s.option(form.Flag, 'disable_quic_gso', _("Disable QUIC GSO")); + o = s.option(form.Flag, 'block_quic', _("Block QUIC")); + o.description = _("Reject proxied UDP 443 so some apps fall back to TCP. Try only when downloads or video stall."); + o = s.option(form.Flag, 'ipv4_dns_hijack', _("IPv4 DNS Hijack")); + o = s.option(form.Flag, 'ipv6_dns_hijack', _("IPv6 DNS Hijack")); + o.description = _("Intercept IPv6 DNS traffic to prevent devices with hard-coded DNS from bypassing the traffic."); + o = s.option(form.Flag, 'ipv4_proxy', _("IPv4 Proxy")); + o = s.option(form.Flag, 'ipv6_proxy', _("IPv6 Proxy")); + o = s.option(form.Flag, 'fake_ip_ping_hijack', _("Virtual IP Ping Hijacking")); + o = s.option(form.Flag, 'dns_leak_protect', _("Prevent DNS Leaks")); + o.description = _("Regular domains use overseas DNS only and follow proxy rules; DoT/DoQ is blocked. Takes effect after restart.
    ") + + _("Warning: IPv6 resolution is also disabled when IPv6 Proxy is off, to keep the real address from leaking."); + o = s.option(form.Flag, 'core_only', _("Core Only (advanced)")); + o.description = _("Run only the core with your imported configuration, without taking over firewall / DNS / routing. Compatible with nikki, OpenClash, momo and homeproxy configurations.
    ") + + _("Prerequisite: The configuration must include transparent proxying (TUN auto-route or TProxy inbound). Takes effect after restart."); + + s = m.section(form.NamedSection, 'config', 'clashoo', _("Port Settings")); + s.addremove = false; + o = s.option(form.Flag, 'allow_lan', _("Allow LAN Access")); + o = s.option(form.Value, 'http_port', _("HTTP Port")); + o = s.option(form.Value, 'socks_port', _("SOCKS5 Port")); + o = s.option(form.Value, 'mixed_port', _("Mixed Port")); + o = s.option(form.Value, 'redir_port', _("Redirect Port")); + o = s.option(form.Value, 'tproxy_port', _("TPROXY Port")); + + s = m.section(form.NamedSection, 'config', 'clashoo', _("Smart Policy Settings")); + s.addremove = false; + + o = s.option(form.Flag, 'smart_auto_switch', _("Smart Policy Auto Switch")); + o.description = _("Automatically switch Url-test and Load-balance policy groups to Smart policy groups"); + + o = s.option(form.Value, 'smart_policy_priority', _("Policy Priority (weight bonus)")); + o.default = 'Premium:0.9;SG:1.3'; + o.placeholder = 'Premium:0.9;SG:1.3'; + o.rmempty = true; + o.description = _("Node weight bonus. <1 means lower priority, >1 means higher priority. Modify as needed; leave blank to skip policy-priority injection."); + + o = s.option(form.Flag, 'smart_prefer_asn', _("ASN Priority")); + o.description = _("Force ASN lookup and prefer target ASN information when selecting nodes for a more stable experience"); + + o = s.option(form.Flag, 'smart_uselightgbm', _("Enable LightGBM Model")); + o.description = _("Use LightGBM model to predict weights"); + + o = s.option(form.Flag, 'smart_collectdata', _("Collect Training Data")); + o.description = _("Collect node latency data for LightGBM model training"); + + o = s.option(form.Value, 'smart_collect_size', _("Training Data Size")); + o.datatype = 'uinteger'; + o.placeholder = '100'; + o.description = _("smart-collector-size, maximum retained training samples, default 100"); + + o = s.option(form.Value, 'smart_collect_rate', _("Sample Rate")); + o.datatype = 'uinteger'; + o.placeholder = '1'; + o.description = _("sample-rate, 1 = sample every latency test; increase to reduce sampling frequency"); + + o = s.option(form.Flag, 'smart_lgbm_auto_update', _("Auto Update Model")); + + o = s.option(form.Value, 'smart_lgbm_update_interval', _("Update interval (hours)")); + o.datatype = 'uinteger'; + o.placeholder = '72'; + o.description = _("Period for automatically fetching a new model; also controls the cron trigger frequency, default 72 hours"); + + o = s.option(form.Value, 'smart_lgbm_url', _("Model Download URL")); + o.placeholder = 'https://github.com/vernesong/mihomo/releases/download/LightGBM-Model/Model.bin'; + o.rmempty = true; + o.description = _("LightGBM model file download URL; leave blank to use the default official URL"); + + var sa = m.section(form.TypedSection, 'authentication', _("Proxy Authentication")); + sa.anonymous = true; sa.addremove = true; + o = sa.option(form.Value, 'username', _("Username")); + o = sa.option(form.Value, 'password', _("Password")); + + var sr = m.section(form.TypedSection, 'addtype', _("Custom Routing Rules"), + _("Correct routing by forcing a domain or IP to Direct or Proxy. These rules take priority over subscription rules and apply to both mihomo and sing-box.")); + sr.anonymous = true; sr.addremove = true; + o = sr.option(form.Value, 'ipaaddr', _("Domain / IP")); + /* allow empty so the default placeholder row never blocks saving other settings; + empty rule rows are pruned on save (pruneEmptyAddtype) instead of erroring */ + o.rmempty = true; + o.placeholder = _("example.com or 1.2.3.0/24"); + o = sr.option(form.ListValue, 'type', _("Type")); + o.value('DOMAIN-SUFFIX', _("Domain suffix (e.g. google.com)")); + o.value('DOMAIN', _("Exact domain (e.g. www.google.com)")); + o.value('DOMAIN-KEYWORD', _("Domain keyword (e.g. youtube)")); + o.value('IP-CIDR', _("IP / CIDR (e.g. 8.8.8.8/32)")); + o.default = 'DOMAIN-SUFFIX'; + o = sr.option(form.ListValue, 'pgroup', _("Target")); + o.value('DIRECT', _("Direct")); + o.value('__PROXY__', _("Proxy")); + o.default = 'DIRECT'; + o = sr.option(form.Flag, 'res', 'no-resolve'); + o.depends('type', 'IP-CIDR'); + o.description = _("IP rules do not trigger DNS resolution"); + + m.render().then(function (node) { + decorateControlWraps(node); + container.appendChild(node); + + // Smart section action buttons + var sections = node.querySelectorAll('.cbi-section'); + var smartSec; + for (var i = 0; i < sections.length; i++) { + var h3 = sections[i].querySelector('h3'); + if (h3 && h3.textContent.indexOf('Smart') >= 0) { smartSec = sections[i]; break; } + } + if (smartSec) { + var flushBtn = E('button', { 'class': 'btn cbi-button', 'click': function () { + flushBtn.disabled = true; + callSmartFlushCache().then(function (res) { + flushBtn.disabled = false; + ui.addNotification(null, E('p', (res && res.success) ? _("Smart cache cleared") : _("Cleanup failed (mihomo may not be running)"))); + }).catch(function () { flushBtn.disabled = false; }); + }}, _("Clear")); + smartSec.appendChild(E('div', { 'class': 'cbi-value' }, [ + E('label', { 'class': 'cbi-value-title' }, _("Clear Smart Cache")), + E('div', { 'class': 'cbi-value-field' }, [flushBtn]) + ])); + } + makeSectionCollapsible(node, _("Transparent Proxy"), true); + makeSectionCollapsible(node, _("Port Settings"), true); + makeSectionCollapsible(node, _("Smart Policy Settings"), false); + makeSectionCollapsible(node, _("Proxy Authentication"), false); + makeSectionCollapsible(node, _("Custom Routing Rules"), false); + + container.appendChild(E('div', { 'class': 'cl-save-bar' }, [ + E('button', { 'class': 'btn cbi-button', click: function () { + m.save(null, true).then(function () { return clashoo.commitConfig(); }) + .then(function () { return clearClashooDirty(); }) + .then(function () { location.reload(); }) + .catch(function (e) { ui.addNotification(null, E('p', _("Save failed: ") + (e.message || e))); }); + }}, _("Save Configuration")), + E('button', { 'class': 'btn cbi-button-action', click: function () { + // 保存前探测主代理组,供自定义分流规则的「代理」(__PROXY__) 解析(失败忽略,注入器回退 GLOBAL) + callDetectPrimaryGroup().catch(function () {}).then(function () { + return saveCommitApplyMaybeReload(m, _("Proxy configuration saved and service hot-reloaded"), _("Proxy configuration saved, service is not running")); + }).catch(function (e) { ui.addNotification(null, E('p', _("Operation failed: ") + (e.message || e))); }); + }}, _("Apply Configuration")) + ])); + }); + }, + + _buildDnsForm: function (container) { + var m = new form.Map('clashoo', '', ''); + var s, o; + + s = m.section(form.NamedSection, 'config', 'clashoo', _("Basic DNS")); + s.addremove = false; + o = s.option(form.DummyValue, '_dns_auto_setup', _("DNS Auto Setup")); + o.cfgvalue = function () { + var statusEl = E('div', { 'class': 'cl-dns-auto-status' }, []); + var last = readDnsAutoResult(); + if (last && last.success) + setDnsAutoStatus(statusEl, dnsAutoSummaryNode(last)); + else + statusEl.textContent = _("Automatically choose available DNS and update only upstream servers; split policies and advanced settings remain unchanged."); + if (last && last.success) + window.setTimeout(function () { + clearDnsAutoResult(); + statusEl.textContent = _("Automatically choose available DNS and update only upstream servers; split policies and advanced settings remain unchanged."); + }, 6000); + var btn = E('button', { + 'class': 'btn cbi-button-action', + click: function (ev) { + ev.preventDefault(); + btn.disabled = true; + setDnsAutoStatus(statusEl, _("Testing latency and writing upstream DNS…")); + clashoo.dnsAutoSetup() + .then(function (res) { + btn.disabled = false; + if (!res || !res.success) { + setDnsAutoStatus(statusEl, (res && res.message) || _("DNS auto setup failed")); + ui.addNotification(null, E('p', (res && res.message) || _("DNS auto setup failed"))); + return; + } + storeDnsAutoResult(res); + setDnsAutoStatus(statusEl, dnsAutoSummaryNode(res)); + ui.addNotification(null, E('p', dnsAutoResultMessage(res))); + window.setTimeout(function () { + clearDnsAutoResult(); + statusEl.textContent = _("Auto setup completed."); + }, 6000); + }) + .catch(function (e) { + btn.disabled = false; + setDnsAutoStatus(statusEl, _("DNS auto setup failed: ") + (e.message || e)); + ui.addNotification(null, E('p', _("DNS auto setup failed: ") + (e.message || e))); + }); + } + }, _("Test and Apply")); + return E('div', { 'class': 'cl-dns-auto' }, [ + E('div', { 'class': 'cl-dns-auto-actions' }, [btn]), + statusEl + ]); + }; + o.write = function () {}; + o = s.option(form.Flag, 'enable_dns', _("Enable DNS Module")); + o = s.option(form.Value, 'listen_port', _("DNS Listen Port")); + o.datatype = 'port'; + o = s.option(form.ListValue, 'enhanced_mode', _("Enhanced Mode")); + o.value('fake-ip', 'Fake-IP'); o.value('redir-host', 'Redir-Host'); + o.default = 'fake-ip'; + o.description = 'Fake-IP · ' + _("Recommended") + ' ' + + _("Fast resolution and accurate routing; China routing is handled by the core.") + '
    ' + + 'Redir-Host ' + + _("China traffic bypasses the core at firewall level; DNS behavior is slightly weaker. Choose as needed."); + o = s.option(form.Value, 'fake_ip_range', _("Fake-IP Range")); + o.default = '198.18.0.1/16'; + o.placeholder = '198.18.0.1/16'; + o.depends('enhanced_mode', 'fake-ip'); + o.remove = function () {}; + o = s.option(form.Flag, 'enable_ipv6', 'IPv6 DNS'); + + s = m.section(form.NamedSection, 'config', 'clashoo', _("Advanced DNS")); + s.addremove = false; + o = s.option(form.Flag, 'dnsforwader', _("Force DNS Forwarding")); + o.depends('enable_dns', '1'); + o = s.option(form.ListValue, 'fake_ip_filter_mode', _("Fake-IP Filter Mode")); + o.value('blacklist', _("Blocklist (listed items use real IP, default)")); + o.value('whitelist', _("Allowlist (only listed items use fake-IP)")); + o.value('rule', _("Rule mode (same syntax as rules)")); + o.default = 'blacklist'; + o.depends('enhanced_mode', 'fake-ip'); + + o = s.option(form.DynamicList, 'fake_ip_filter', _("Fake-IP Filter Domains")); + o.placeholder = '+.lan / geosite:cn / RULE-SET,cn_domain,real-ip'; + o.description = _("Blocklist mode: enter domains or shorthand like geosite:cn. Rule mode: entries are converted to rule syntax automatically, such as GEOSITE,cn,real-ip / RULE-SET,xxx,real-ip; usually add MATCH,fake-ip at the end as fallback. geosite:cn automatically uses built-in cn.mrs acceleration and avoids loading the 10MB geosite.dat. Allowlist mode drops the shipped defaults (they mean the opposite there), so enter your own domains."); + o.depends('enhanced_mode', 'fake-ip'); + o.remove = function () {}; + o = s.option(form.DynamicList, 'default_nameserver', 'Bootstrap DNS'); + o.placeholder = '223.5.5.5'; + o.description = _("Used to resolve DoH/DoT/DoQ server domains; plain IP DNS is recommended."); + o = s.option(form.Flag, 'dns_respect_rules', _("DNS Respect Rules")); + o.default = '1'; + o.description = _("DNS queries follow the routing rules, so overseas domains resolve through the proxy instead of a polluted result. Requires proxy-server-nameserver."); + o = s.option(form.Flag, 'dns_loopback_compat', _("OpenClash/Nikki Loopback DNS Compatibility")); + o.default = '0'; + o.description = _("Optional compatibility for normal managed mode. At runtime, replace only proxy node resolvers that point back to the imported configuration's own DNS listener with the proxy-server-nameserver setting. Core Only mode stays verbatim; the source configuration and unrelated local DNS services remain unchanged."); + o.depends('enable_dns', '1'); + o = s.option(form.Value, 'dns_ecs', _("ECS Client Subnet")); + o.placeholder = _("Recommended blank"); + o.description = _("mihomo writes the ecs parameter to DNS URLs; sing-box writes dns.client_subnet. Leave empty to skip."); + o.rmempty = true; + o = s.option(form.Flag, 'dns_ecs_override', _("Force ECS Override")); + o.default = '0'; + o = s.option(form.Flag, 'fallback_filter_geoip', _("Fallback GeoIP Filter")); + o.default = '0'; + o.description = _("Requires MMDB. If enabled while the local GeoIP database is missing, the core may fail to start. Usually not needed."); + o = s.option(form.DynamicList, 'fallback_filter_ipcidr', 'Fallback IP CIDR'); + o.placeholder = '240.0.0.0/4'; + o = s.option(form.Flag, 'singbox_independent_cache', _("sing-box Independent DNS Cache")); + o.default = '0'; + o.description = _("When enabled, direct / proxy / fallback roles each use an independent DNS cache. Useful when the same domain needs different resolver chains by routing. Usually not needed."); + + s = m.section(form.TypedSection, 'dnsservers', _("Upstream DNS")); + s.addremove = true; s.anonymous = true; + o = s.option(form.Flag, 'enabled', _("Enable")); + o.default = '1'; + o = s.option(form.ListValue, 'ser_type', _("Role")); + o.value('nameserver', _("Domestic Upstream DNS")); + o.value('direct-nameserver', _("Direct Domain Resolver")); + o.value('proxy-server-nameserver', _("Proxy Node Domain Resolver")); + o.value('fallback', _("Overseas Encrypted DNS (anti-pollution)")); + o.default = 'nameserver'; + o = s.option(form.Value, 'ser_address', _("DNS Address")); + o.placeholder = 'https://dns.alidns.com/dns-query / https://doh.pub/dns-query'; + o = s.option(form.ListValue, 'protocol', _("Protocol")); + o.value('none', _("Full URL / no protocol prefix")); + o.value('udp://', 'UDP'); + o.value('tcp://', 'TCP'); + o.value('tls://', 'DoT / TLS'); + o.value('https://', 'DoH / HTTPS'); + o.value('quic://', 'DoQ / QUIC'); + o.default = 'none'; + o = s.option(form.Value, 'ser_port', _("Port")); + o.placeholder = '853 / 784'; + o.rmempty = true; + + s = m.section(form.TypedSection, 'dns_policy', _("DNS Policy")); + s.addremove = true; s.anonymous = true; + o = s.option(form.Flag, 'enabled', _("Enable")); + o.default = '1'; + o = s.option(form.ListValue, 'policy_type', _("Policy Type")); + o.value('nameserver-policy', _("Domain Split DNS")); + o.value('proxy-server-nameserver-policy', _("Proxy Domain Split DNS")); + o.default = 'nameserver-policy'; + o = s.option(form.Value, 'matcher', _("Match Rule")); + o.placeholder = 'geosite:cn / domain:example.com / domain-suffix:google.com'; + o = s.option(form.DynamicList, 'nameserver', _("Use DNS")); + o.placeholder = 'udp://223.5.5.5'; + o.description = _("Example: geosite:cn uses https://dns.alidns.com/dns-query; geosite:geolocation-!cn uses https://cloudflare-dns.com/dns-query."); + + m.render().then(function (node) { + decorateControlWraps(node); + makeSectionCollapsible(node, _("Basic DNS"), true); + makeSectionCollapsible(node, _("Advanced DNS"), false); + makeSectionCollapsible(node, _("Upstream DNS"), false); + makeSectionCollapsible(node, _("DNS Policy"), false); + container.appendChild(node); + container.appendChild(E('div', { 'class': 'cl-save-bar' }, [ + E('button', { 'class': 'btn cbi-button', click: function () { + m.save(null, true).then(function () { return clashoo.commitConfig(); }) + .then(function () { return clearClashooDirty(); }) + .then(function () { location.reload(); }) + .catch(function (e) { ui.addNotification(null, E('p', _("Save failed: ") + (e.message || e))); }); + }}, _("Save Configuration")), + E('button', { 'class': 'btn cbi-button-action', click: function () { + saveCommitApplyMaybeReload(m, _("DNS configuration saved and service hot-reloaded"), _("DNS configuration saved, service is not running")) + .catch(function (e) { ui.addNotification(null, E('p', _("Operation failed: ") + (e.message || e))); }); + }}, _("Apply Configuration")) + ])); + }); + }, + + /* ── sing-box UI ── */ + + _renderSingbox: function (sbData, uiData, subscriptionUpdateStatus) { + var self = this; + var profiles = sbData.profiles || []; + var tabEls = {}, panelEls = {}; + + var tabs = [ + { id: 'profiles', label: _("Configuration Files") }, + { id: 'wizard', label: _("Quick Wizard") } + ]; + var allowedTabs = tabs.map(function (t) { return t.id; }); + this._sbTab = readSavedTab('clashoo.config.singbox.tab', this._sbTab || 'profiles', allowedTabs); + rememberTab('clashoo.config.singbox.tab', this._sbTab); + + var tabBar = E('div', { 'class': 'cl-tabs' }, + tabs.map(function (t) { + var el = E('div', { + 'class': 'cl-tab' + (self._sbTab === t.id ? ' active' : ''), + click: function () { + Object.keys(tabEls).forEach(function (k) { + tabEls[k].className = 'cl-tab' + (k === t.id ? ' active' : ''); + panelEls[k].className = 'cl-panel' + (k === t.id ? ' active' : ''); + }); + self._sbTab = t.id; + rememberTab('clashoo.config.singbox.tab', t.id); + } + }, t.label); + tabEls[t.id] = el; + return el; + }) + ); + + var profilesPanel = E('div', { 'class': 'cl-panel' + (this._sbTab === 'profiles' ? ' active' : ''), id: 'cl-panel-profiles' }, + self._buildSbProfilesPanel(profiles, sbData.active || '', uiData, subscriptionUpdateStatus)); + panelEls['profiles'] = profilesPanel; + + var wizardPanel = E('div', { 'class': 'cl-panel' + (this._sbTab === 'wizard' ? ' active' : ''), id: 'cl-panel-wizard' }, + self._buildSbWizardPanel()); + panelEls['wizard'] = wizardPanel; + + return E('div', { 'class': 'cl-wrap clashoo-container cl-config-page cl-form-page ' + getThemeClass() }, [tabBar, profilesPanel, wizardPanel]); + }, + + _buildSbProfilesPanel: function (profiles, activeProfile, uiData, subscriptionUpdateStatus) { + var self = this; + var safeText = function (v) { return (v == null || v === 'null') ? '' : String(v); }; + var formatJsonForEditor = function (content) { + try { + return JSON.stringify(JSON.parse(content || '{}'), null, 2) + '\n'; + } catch (e) { + return content || ''; + } + }; + + /* ── JSON editor (initially hidden) ── */ + var editorTitle = E('span', { 'class': 'cl-editor-hdr' }, _("Select a configuration above to edit it here")); + var ed = createConfigEditor({ name: 'javascript', json: true }); + var saveBtn = E('button', { + 'class': 'btn cbi-button-action cl-btn-sm', + disabled: '', + click: function () { + var name = ed.textarea.dataset.name; + if (!name) return; + clashoo.saveSingboxProfile(name, formatJsonForEditor(ed.getValue())).then(function (r) { + if (r.success) ui.addNotification(null, E('p', name + _(" saved"))); + else ui.addNotification(null, E('p', _("Save failed: ") + (r.message || r.error || ''))); + }); + } + }, _("Save")); + + var migrateBtn = E('button', { + 'class': 'btn cbi-button cl-btn-sm', + disabled: '', + click: function () { + var name = ed.textarea.dataset.name; + if (!name) return; + L.resolveDefault(callMigrateSbProfile(name), {}).then(function (r) { + if (r && r.success) { + var msg = r.changes && r.changes.length ? _("Fixed deprecated fields: ") + r.changes.join(', ') : _("Configuration is up to date; no fixes needed"); + ui.addNotification(null, E('p', msg)); + /* 重新加载编辑器内容 */ + clashoo.getSingboxProfile(name).then(function (gr) { ed.setValue(formatJsonForEditor(gr.content || '')); }); + } else { + ui.addNotification(null, E('p', _("Fix failed: ") + ((r && r.message) || ''))); + } + }); + } + }, _("Fix Deprecated Fields")); + + var editorBox = E('div', { 'class': 'cl-section cl-card cl-sb-card cl-sb-editor' }, [ + editorTitle, + ed.el, + E('div', { 'class': 'cl-actions cl-sb-row-actions cl-sb-editor-actions' }, [ + saveBtn, + migrateBtn, + E('span', { 'class': 'cl-hint' }, _("Click Save after editing; switching configuration automatically restarts the service")) + ]) + ]); + + function loadEditor(name) { + editorTitle.textContent = _("Editing: ") + name; + saveBtn.removeAttribute('disabled'); + migrateBtn.removeAttribute('disabled'); + ed.textarea.dataset.name = name; + ed.setValue(_("Loading…")); + clashoo.getSingboxProfile(name).then(function (r) { + ed.setValue(formatJsonForEditor(r.content || '')); + }); + } + + /* ── Profile table ── */ + var rows = profiles.length + ? profiles.map(function (p) { + var nameCell = [ + E('div', { 'class': 'cl-sb-file-name' }, [ + p.active ? E('span', { 'class': 'cl-active-badge' }, _("Active")) : '', + E('span', { 'class': 'cl-file-name-text' }, safeText(p.name)) + ]) + ]; + var trafficEl = renderTrafficBar(p.sub_used, p.sub_total); + var expireEl = renderExpire(p.sub_expire); + if (trafficEl) nameCell.push(trafficEl); + if (expireEl) nameCell.push(expireEl); + return E('tr', {}, [ + E('td', {}, nameCell), + E('td', { 'class': 'cl-sb-size' }, safeText(p.size) || '—'), + E('td', {}, [ + E('div', { 'class': 'cl-sb-row-actions' }, [ + p.source !== 'native' ? E('button', { + 'class': 'btn cbi-button cl-btn-sm cl-btn-sb-action cl-btn-sb-edit', + click: function () { loadEditor(p.name); } + }, _("Edit")) : '', + E('button', { + 'class': 'btn cbi-button-action cl-btn-sm cl-btn-sb-action cl-btn-sb-switch', + click: function () { + clashoo.setSingboxProfile(p.name).then(function (r) { + ui.addNotification(null, E('p', r.success ? _("Switched to ") + p.name : (_("Switch failed: ") + (r.message || '')))); + if (r.success) location.reload(); + }); + } + }, _("Switch Profile")), + p.source === 'native' && p.sub_url ? E('button', { + 'class': 'btn cbi-button cl-btn-sm cl-btn-sb-action', + click: function (ev) { + var btn = ev.currentTarget; + btn.disabled = true; + btn.textContent = _("Updating…"); + clashoo.updateSingboxNative(p.name).then(function (r) { + btn.disabled = false; + btn.textContent = _("Update"); + ui.addNotification(null, E('p', r.success ? (r.message || p.name + _(" updated")) : (_("Update failed: ") + (r.message || '')))); + if (r.success) location.reload(); + }); + } + }, _("Update")) : '', + E('button', { + 'class': 'btn cbi-button-negative cl-btn-sm cl-btn-sb-action cl-btn-sb-delete', + click: function () { + if (!confirm(_("Delete ") + p.name + '?')) return; + clashoo.deleteSingboxProfile(p.name).then(function () { location.reload(); }); + } + }, _("Delete")) + ]) + ]) + ]); + }) + : [E('tr', {}, [E('td', { 'class': 'cl-sb-empty', colspan: '3' }, _("No configuration files yet. Use Quick Wizard to generate one or upload a JSON file."))])]; + + /* ── Upload ── */ + var uploadInput = E('input', { type: 'file', accept: '.json', style: 'display:none', id: 'sb-upload' }); + uploadInput.addEventListener('change', function (ev) { + var file = ev.target.files[0]; + if (!file) return; + var reader = new FileReader(); + reader.onload = function (e) { + clashoo.saveSingboxProfile(file.name, e.target.result).then(function (r) { + if (r.success) { ui.addNotification(null, E('p', _("Upload succeeded: ") + r.name)); location.reload(); } + else ui.addNotification(null, E('p', _("Upload failed: ") + (r.message || r.error || ''))); + }); + }; + reader.readAsText(file); + }); + + return [ + E('div', { 'class': 'cl-section cl-card cl-sb-card' }, [ + E('h4', {}, _("Subscription Update")), + buildSubscriptionSchedule(uiData || {}, subscriptionUpdateStatus || {}) + ]), + E('div', { 'class': 'cl-section cl-card cl-sb-card' }, [ + E('h4', {}, _("sing-box Configuration Files")), + E('table', { 'class': 'cl-sub-list cl-sb-list' }, [ + E('thead', {}, E('tr', {}, [E('th', {}, _("File Name")), E('th', {}, _("Size")), E('th', {}, _("Actions"))])), + E('tbody', {}, rows) + ]), + uploadInput, + E('div', { 'class': 'cl-actions cl-sb-top-actions' }, [ + E('button', { + 'class': 'btn cbi-button-add cl-btn-sm cl-btn-sb-upload', + click: function () { document.getElementById('sb-upload').click(); } + }, _("Upload JSON Configuration")) + ]) + ]), + editorBox + ]; + }, + + _buildSbWizardPanel: function () { + var urlInput = E('input', { + 'class': 'cl-sub-url', + type: 'text', + placeholder: _("Paste subscription URL (supports vmess / vless / trojan, etc.)") + }); + var nameInput = E('input', { + 'class': 'cl-sub-url', + type: 'text', + placeholder: _("Configuration file name (optional, blank auto-generates singbox.json)"), + style: 'margin-top:0' + }); + var savedUa = ''; + try { savedUa = uci.get('clashoo', 'config', 'sub_ua') || ''; } catch (e) {} + // YAML 订阅转换走 mihomo 订阅流程(拉 yaml → yaml2singbox),UA 与 mihomo 共用 sub_ua + var convertUaPicker = buildUaPicker(savedUa); + + var genBtn, applyBtn; + function setBusy(busy, activeBtn) { + [genBtn, applyBtn].forEach(function (b) { + if (!b) return; + b.disabled = busy ? '' : null; + if (busy) { + if (!b.dataset.label) b.dataset.label = b.textContent; + if (b === activeBtn) + b.textContent = b._clBusyLabel || _("Processing…"); + } else if (b.dataset.label) { + b.textContent = b.dataset.label; + } + }); + } + function doCreate(setActive) { + var url = urlInput.value.trim(); + if (!url) { ui.addNotification(null, E('p', _("Please enter a subscription URL"))); return; } + setBusy(true, setActive ? applyBtn : genBtn); + // 保存 UA 到 UCI,后端 create_singbox_config 会读这个字段 + var uaPromise = L.resolveDefault(uci.load('clashoo'), null).then(function () { + uci.set('clashoo', 'config', 'sub_ua', convertUaPicker.getValue()); + return uci.save() + .then(function () { return clashoo.commitConfig(); }) + .then(function () { return clearClashooDirty(); }); + }).catch(function () {}); + uaPromise.then(function () { + return clashoo.createSingboxConfig(url, nameInput.value.trim()); + }) + .then(function (r) { + /* RPC 超时被 resolveDefault 兜底成 {},r.success 是 undefined。 + * 此时后端可能仍在跑(yaml2singbox 转 90 节点等),让用户直接刷新页 + * 看实际产物,而不是误报"失败"。 */ + if (!r || typeof r.success === 'undefined') { + ui.addNotification(null, E('p', _("Generation is taking longer, refreshing to show results…"))); + setBusy(false); + setTimeout(function () { location.reload(); }, 1500); + return; + } + if (!r.success) { + setBusy(false); + ui.addNotification(null, E('p', _("Generate failed: ") + (r.message || ''))); + return; + } + if (setActive) { + return clashoo.setSingboxProfile(r.name).then(function () { + ui.addNotification(null, E('p', r.message + _(", switched to active configuration"))); + location.reload(); + }); + } + ui.addNotification(null, E('p', r.message)); + location.reload(); + }).catch(function (e) { + setBusy(false); + ui.addNotification(null, E('p', _("Generate error: ") + (e && e.message || e))); + }); + } + + genBtn = E('button', { 'class': 'btn cbi-button cl-btn-sm', click: function () { doCreate(false); } }, _("Generate Configuration")); + applyBtn = E('button', { 'class': 'btn cbi-button-action cl-btn-sm', click: function () { doCreate(true); } }, _("Apply Configuration")); + genBtn._clBusyLabel = _("Generating…"); + applyBtn._clBusyLabel = _("Applying…"); + + /* ── native sing-box subscription card ── */ + // 注:原生 sing-box JSON 订阅不需要 UA 选项(机场按链接参数/路径区分格式) + var nativeUrlInput = E('input', { + 'class': 'cl-sub-url', + type: 'text', + placeholder: _("Paste native sing-box subscription URL (direct JSON response)") + }); + var nativeNameInput = E('input', { + 'class': 'cl-sub-url', + type: 'text', + placeholder: _("File name (optional, blank for automatic name)"), + style: 'margin-top:0' + }); + + var fetchBtn, fetchApplyBtn; + var fetchStatusEl = E('div', { 'class': 'cl-update-status', style: 'margin-top:6px;font-size:12px;min-height:18px;line-height:1.4' }); + var setFetchStatus = function (text, tone) { + fetchStatusEl.textContent = text || ''; + fetchStatusEl.style.color = tone === 'success' ? 'var(--success-color, #2e7d32)' + : tone === 'error' ? 'var(--error-color, #d32f2f)' + : tone === 'progress'? 'var(--tip-color, #1976d2)' + : ''; + }; + function setNativeBusy(busy) { + [fetchBtn, fetchApplyBtn].forEach(function (b) { + if (!b) return; + b.disabled = busy ? '' : null; + if (busy) { + if (!b.dataset.label) b.dataset.label = b.textContent; + b.textContent = _("Fetching…"); + } else if (b.dataset.label) { + b.textContent = b.dataset.label; + } + }); + } + function doFetchNative(setActive) { + var url = nativeUrlInput.value.trim(); + if (!url) { + setFetchStatus(_("✗ Please enter a subscription URL"), 'error'); + setTimeout(function () { setFetchStatus(''); }, 4000); + return; + } + setNativeBusy(true); + setFetchStatus(_("⏳ Fetching configuration..."), 'progress'); + clashoo.fetchSingboxNative(url, nativeNameInput.value.trim()) + .then(function (r) { + setNativeBusy(false); + if (!r || typeof r.success === 'undefined') { + setFetchStatus(_("⏳ Fetch timed out, refreshing to show results..."), 'progress'); + setTimeout(function () { location.reload(); }, 1500); + return; + } + if (!r.success) { + setFetchStatus(_("✗ Fetch failed: ") + (r.message || ''), 'error'); + return; + } + if (setActive) { + setFetchStatus('⏳ ' + r.message + _(", switching to active configuration..."), 'progress'); + return clashoo.setSingboxProfile(r.name).then(function () { + setFetchStatus('✓ ' + r.message + _(", switched to active configuration"), 'success'); + setTimeout(function () { location.reload(); }, 1200); + }); + } + setFetchStatus('✓ ' + r.message, 'success'); + setTimeout(function () { location.reload(); }, 1200); + }).catch(function (e) { + setNativeBusy(false); + setFetchStatus(_("✗ Fetch error: ") + (e && e.message || e), 'error'); + }); + } + + fetchBtn = E('button', { 'class': 'btn cbi-button cl-btn-sm', click: function () { doFetchNative(false); } }, _("Fetch Configuration")); + fetchApplyBtn = E('button', { 'class': 'btn cbi-button-action cl-btn-sm', click: function () { doFetchNative(true); } }, _("Fetch and Apply")); + + return [ + E('div', { 'class': 'cl-section cl-card cl-sb-card' }, [ + E('h4', {}, _("Node Subscription")), + E('div', { 'class': 'cl-form-wrap cl-fixed-600 cl-sb-form' }, [ + nativeUrlInput, nativeNameInput, + E('div', { 'class': 'cl-actions cl-sb-top-actions' }, [fetchBtn, fetchApplyBtn]), + fetchStatusEl + ]), + E('p', { 'class': 'cl-sb-note' }, + _("For providers that directly offer sing-box JSON subscriptions, or links already converted by external tools. After fetching, click Update on the corresponding item in the Configuration Files tab to fetch the latest configuration again.") + ) + ]), + E('div', { 'class': 'cl-section cl-card cl-sb-card' }, [ + E('h4', {}, _("YAML Subscription Conversion")), + E('div', { 'class': 'cl-form-wrap cl-fixed-600 cl-sb-form' }, [ + urlInput, nameInput, convertUaPicker.wrap, + E('div', { 'class': 'cl-actions cl-sb-top-actions' }, [ + genBtn, + applyBtn + ]) + ]), + E('p', { 'class': 'cl-sb-note' }, + _("Convert YAML subscriptions to sing-box JSON, automatically injecting TUN transparent proxy and China direct rules. Files with the same name are overwritten; use the same name when updating.") + ) + ]) + ]; + }, + + handleSaveApply: null, + handleSave: null, + handleReset: null +}); diff --git a/luci-app-clashoo/htdocs/luci-static/resources/view/clashoo/index.js b/luci-app-clashoo/htdocs/luci-static/resources/view/clashoo/index.js new file mode 100644 index 000000000..76167ca18 --- /dev/null +++ b/luci-app-clashoo/htdocs/luci-static/resources/view/clashoo/index.js @@ -0,0 +1,4 @@ +'use strict'; +'require view.clashoo.overview as overview'; + +return overview; diff --git a/luci-app-clashoo/htdocs/luci-static/resources/view/clashoo/overview.js b/luci-app-clashoo/htdocs/luci-static/resources/view/clashoo/overview.js new file mode 100644 index 000000000..504775903 --- /dev/null +++ b/luci-app-clashoo/htdocs/luci-static/resources/view/clashoo/overview.js @@ -0,0 +1,2030 @@ +'use strict'; +'require view'; +'require poll'; +'require ui'; +'require rpc'; +'require uci'; +'require tools.clashoo as clashoo'; + +var CSS = [ + '.cl-wrap{padding:8px 0}', + '.cl-wrap{font-family:-apple-system,BlinkMacSystemFont,"Segoe UI","PingFang SC",sans-serif}', + '.cl-wrap{--cl-live-title-color:rgba(40,50,68,.62);--cl-live-main-color:rgba(84,96,116,.92);--cl-live-sub-color:rgba(74,86,106,.72);--cl-live-foot-color:rgba(74,86,106,.72);--cl-live-zero-color:rgba(128,128,128,.5)}', + 'body.dark .cl-wrap,body.dark .cl-wrap,body[data-theme="dark"] .cl-wrap,body[data-darkmode="1"] .cl-wrap,body[data-darkmode="true"] .cl-wrap,html.dark .cl-wrap,html.dark .cl-wrap,html[data-theme="dark"] .cl-wrap,html[data-bs-theme="dark"] .cl-wrap,html[data-darkmode="1"] .cl-wrap,html[data-darkmode="true"] .cl-wrap{--cl-live-title-color:rgba(230,238,252,.74);--cl-live-main-color:rgba(228,236,248,.9);--cl-live-sub-color:rgba(208,219,238,.72);--cl-live-foot-color:rgba(208,219,238,.72)}', + '.cl-status-kernel{display:inline-flex;align-items:center;gap:2px;padding:2px;border-radius:8px;border:0;background:rgba(128,128,128,.1)}', + '.cl-status-kernel .cl-core-btn{height:24px;line-height:24px;min-width:60px;padding:0 10px;border:0;border-radius:6px;background:transparent;font-size:11px;font-weight:500;color:var(--cl-live-main-color);opacity:.6;cursor:pointer;transition:background-color .18s ease,color .18s ease,opacity .18s ease}', + '.cl-status-kernel .cl-core-btn.active{background:linear-gradient(#3886a1,#2f7288);border:0;color:#fff;opacity:1;font-weight:600;box-shadow:0 1px 2px rgba(0,0,0,.12)}', + '.cl-status-kernel .cl-core-btn:disabled{cursor:not-allowed}', + '.cl-status-kernel.is-busy{opacity:.6}', + '.cl-core-switch-wrap{display:flex;flex-direction:column;align-items:flex-start;gap:6px}', + '.cl-core-switch-hint{font-size:12px;line-height:1.35;color:rgba(74,86,106,.72)}', + 'body.dark .cl-core-switch-hint,html[data-theme="dark"] .cl-core-switch-hint,html[data-bs-theme="dark"] .cl-core-switch-hint{color:rgba(208,219,238,.72)}', + '.cl-cards{display:grid;grid-template-columns:repeat(3,1fr);gap:12px;margin-bottom:16px}', + '.cl-card{border:1px solid rgba(0,0,0,.05);border-radius:10px;padding:14px 16px;min-height:70px;box-shadow:0 4px 12px rgba(0,0,0,.03)}', + '.cl-card-head{display:flex;align-items:center;justify-content:space-between;gap:8px;margin-bottom:4px}', + '.cl-card .lbl{font-size:11px;opacity:.55;margin:0}', + '.cl-card-tools{display:flex;align-items:center;gap:6px}', + '.cl-icon-btn{border:0;background:transparent;padding:0;width:16px;height:16px;line-height:16px;font-size:13px;opacity:.55;cursor:pointer;display:inline-flex;align-items:center;justify-content:center;color:inherit}', + '.cl-icon-btn:hover{opacity:.9}', + '.cl-icon-btn.is-loading{animation:cl-spin 1s linear infinite;pointer-events:none;opacity:.75}', + '.cl-card .val{font-size:11px;font-weight:500;word-break:break-all}', + '.cl-card-mode .val{line-height:1.45;word-break:normal}', + '.cl-mode-stack{display:flex;flex-direction:column;gap:4px;justify-content:flex-start;align-items:flex-start}', + '.cl-mode-tag{display:flex;align-items:center;justify-content:flex-start;padding:0;border-radius:0;font-size:11px;line-height:1.35;background:transparent;color:inherit;opacity:.5;width:max-content;max-width:100%;text-align:left}', + 'body.dark .cl-mode-tag,body.dark .cl-mode-tag,body[data-theme="dark"] .cl-mode-tag,body[data-darkmode="1"] .cl-mode-tag,body[data-darkmode="true"] .cl-mode-tag,html.dark .cl-mode-tag,html.dark .cl-mode-tag,html[data-theme="dark"] .cl-mode-tag,html[data-bs-theme="dark"] .cl-mode-tag,html[data-darkmode="1"] .cl-mode-tag,html[data-darkmode="true"] .cl-mode-tag{background:transparent;color:inherit;opacity:.5}', + '.cl-mode-tag-degraded{color:#b56f00}', + '.cl-check-note{display:block;margin-top:6px;font-size:11px;line-height:1.45;opacity:.6;font-weight:400}', + '.cl-badge{display:inline-flex;align-items:center;justify-content:center;padding:2px 12px;border-radius:999px;font-size:11px;font-weight:700;line-height:1.2;background:transparent;border:1px solid transparent}', + '.cl-badge-run{background:transparent;color:#4aa065;border-color:rgba(74,160,101,.46)}', + '.cl-badge-stop{background:transparent;color:#df6e6e;border-color:rgba(223,110,110,.52)}', + '.cl-badge-sync{background:rgba(128,128,128,.08);color:rgba(128,128,128,.92);border-color:rgba(128,128,128,.35)}', + '.cl-service-tools{display:inline-flex;align-items:center;gap:8px;white-space:nowrap}', + '.cl-service-label{font-size:11px;font-weight:600;opacity:.62}', + '.cl-service-switch{position:relative;width:48px;height:26px;border:0;border-radius:999px;background:rgba(128,128,128,.22);padding:2px;box-shadow:none;cursor:pointer;transition:background .18s ease,opacity .18s ease}', + '.cl-service-switch .cl-service-knob{position:absolute;top:3px;left:3px;width:20px;height:20px;border-radius:50%;background:rgba(255,255,255,.94);box-shadow:0 1px 4px rgba(0,0,0,.18);transition:transform .18s ease,background .18s ease}', + '.cl-service-switch.is-on{background:rgba(74,160,101,.52)}', + '.cl-service-switch.is-on .cl-service-knob{transform:translateX(22px)}', + '.cl-service-switch:disabled{opacity:.48;cursor:not-allowed}', + '.cl-controls{display:grid;grid-template-columns:repeat(4,1fr);gap:10px;margin-bottom:16px}', + '.cl-ctrl{border:0 !important;border-radius:8px;padding:10px 12px;box-shadow:none !important;background:rgba(128,128,128,.04)}', + '.cl-ctrl label{display:block;font-size:11px;opacity:.55;margin-bottom:6px}', + '.cl-ctrl select{width:100%;font-size:13px;box-sizing:border-box}', + '.cl-ctrl-row{display:flex;gap:6px;align-items:center}', + '.cl-ctrl-row select{flex:1;min-width:0}', + '.cl-live-box{border:0 !important;border-radius:10px;padding:12px 14px;box-shadow:none !important;background:transparent}', + '.cl-traffic-wrap{margin-bottom:12px}', + '.cl-live-grid{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:12px}', + '.cl-live-card,.cl-stat-card{position:relative;height:120px;min-height:120px;max-height:120px;box-sizing:border-box;border:0 !important;border-radius:12px;overflow:hidden;box-shadow:0 2px 10px rgba(0,0,0,.03)}', + '.cl-live-content{position:relative;z-index:2;padding:11px 12px}', + '.cl-live-bg-chart{position:absolute;left:8px;right:8px;bottom:8px;height:42px;z-index:1;pointer-events:none;opacity:.92}', + '.cl-live-title{display:flex;align-items:center;gap:6px;font-size:12px;font-weight:600;margin-bottom:8px;color:var(--cl-live-title-color)}', + '.cl-live-main{display:flex;align-items:flex-end;gap:6px;line-height:1;margin-bottom:14px}', + '.cl-live-num{font-size:18px;font-weight:800;letter-spacing:-1px;color:var(--cl-live-main-color,rgba(84,96,116,.92));transition:color .18s ease,opacity .18s ease,text-shadow .22s ease,font-size .18s ease}', + '.cl-live-unit{font-size:11px;font-weight:600;margin-left:3px;padding-bottom:2px;color:var(--cl-live-sub-color,rgba(74,86,106,.72));transition:color .18s ease,opacity .18s ease}', + '.cl-live-svg{display:block;width:100%;height:100%}', + '.cl-live-line{fill:none;stroke-width:2.2;stroke-linecap:round;stroke-linejoin:round}', + '.cl-live-area{opacity:.16}', + '.cl-live-foot{font-size:11px;font-weight:500;color:var(--cl-live-foot-color,rgba(74,86,106,.72));transition:color .18s ease,opacity .18s ease}', + '.cl-live-card.is-active .cl-live-num{color:var(--cl-live-main-color,rgba(84,96,116,.92))!important}', + '.cl-live-card.is-zero .cl-live-num{font-size:16px;color:var(--cl-live-zero-color)!important;opacity:1;text-shadow:none}', + '.cl-live-card.is-zero .cl-live-unit,.cl-live-card.is-zero .cl-live-foot{color:var(--cl-live-zero-color)!important;opacity:1}', + '.cl-live-card.is-zero .cl-live-bg-chart{opacity:0!important}', + '.cl-live-card.is-zero .cl-live-line,.cl-live-card.is-zero .cl-live-area{stroke:transparent!important;fill:transparent!important}', + '.cl-card-access .val{font-size:11px;font-weight:500}', + '.cl-check-modern{display:flex;flex-direction:column;gap:10px}', + '.cl-check-group{display:flex;flex-direction:column;gap:6px}', + '.cl-check-group-title{font-size:11px;line-height:1;opacity:.55;font-weight:600;letter-spacing:.2px}', + '.cl-check-item{display:flex;align-items:center;justify-content:flex-start}', + '.cl-check-main{display:flex;align-items:center;gap:10px;min-width:0}', + '.cl-check-icon-wrap{width:18px;height:18px;display:inline-flex;align-items:center;justify-content:center;background:transparent!important;border:0!important;border-radius:0!important;box-shadow:none!important;padding:0!important;overflow:visible}', + '.cl-check-icon{width:18px;height:18px;object-fit:contain;display:block;flex-shrink:0;background:transparent!important;border:0!important;box-shadow:none!important;border-radius:0!important;padding:0!important;outline:0!important}', + '.cl-check-item img,.cl-check-main img{background:transparent!important;border:0!important;box-shadow:none!important;border-radius:0!important;padding:0!important;outline:0!important}', + '.cl-check-icon-fallback{width:18px;height:18px;display:inline-flex;align-items:center;justify-content:center;border-radius:50%;font-size:10px;font-weight:700;background:rgba(31,157,85,.12);color:#1f9d55;flex-shrink:0}', + '.cl-check-name{font-size:11px;line-height:1.2;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;width:100px;min-width:100px;max-width:100px;flex:0 0 100px}', + '.cl-check-latency{margin-left:20px;width:78px;min-width:78px;text-align:left;font-size:11px;font-weight:600;white-space:nowrap;font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono",monospace;font-variant-numeric:tabular-nums}', + '.cl-lat-green{color:#2aa85b}', + '.cl-lat-warn{color:#d39e00}', + '.cl-lat-red{color:#c96a5a}', + '.cl-signal{display:inline-flex;align-items:flex-end;justify-content:flex-start;gap:2px;width:30px;min-width:30px;margin-left:8px}', + '.cl-signal i{display:block;width:4px;border-radius:2px;background:rgba(120,120,120,.25)}', + '.cl-signal i:nth-child(1){height:6px}', + '.cl-signal i:nth-child(2){height:9px}', + '.cl-signal i:nth-child(3){height:12px}', + '.cl-signal i:nth-child(4){height:15px}', + '.cl-signal-green i.active{background:#2aa85b}', + '.cl-signal-warn i.active{background:#d39e00}', + '.cl-signal-red i.active{background:#c96a5a}', + '.cl-signal-offline{opacity:.78;transform:translateX(3px)}', + '.cl-check-updated{margin-top:6px;font-size:10px;line-height:1.3;opacity:.5}', + '.cl-check-skeleton{display:flex;flex-direction:column;gap:10px}', + '.cl-skel-row{display:flex;align-items:center;gap:10px}', + '.cl-skel-icon{width:18px;height:18px;border-radius:4px;background:rgba(128,128,128,.16)}', + '.cl-skel-line{height:10px;border-radius:999px;flex:1;background:linear-gradient(90deg,rgba(128,128,128,.10) 25%,rgba(128,128,128,.22) 50%,rgba(128,128,128,.10) 75%);background-size:220% 100%;animation:cl-shimmer 1.3s linear infinite}', + '.cl-skel-line.short{max-width:90px}', + '.cl-check-empty{font-size:12px;opacity:.55}', + '.cl-wrap .cbi-input-text,.cl-wrap .cbi-input-select,.cl-wrap select,.cl-wrap input,.cl-wrap textarea,.cl-wrap .btn,.cl-wrap .cbi-button{font-size:13px !important;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI","PingFang SC",sans-serif !important}', + '.cl-wrap .btn,.cl-wrap .cbi-button{padding:4px 10px;line-height:1.35}', + '@keyframes cl-fadein{from{opacity:0;transform:translateY(3px)}to{opacity:1;transform:translateY(0)}}', + '@keyframes cl-spin{to{transform:rotate(360deg)}}', + '@keyframes cl-shimmer{0%{background-position:220% 0}100%{background-position:-220% 0}}', + '.cl-op-msg{font-size:12px;font-weight:500;opacity:.85;animation:cl-fadein .25s ease}', + /* 简易节点面板(模态浮层)*/ + '.cl-pm-open{display:inline-flex;align-items:center;height:24px;line-height:1;padding:0;border:0 !important;background:transparent !important;box-shadow:none !important;font-size:12px;font-weight:500;color:var(--cl-primary,rgba(0,122,255,.9));cursor:pointer;white-space:nowrap}', + '.cl-pm-open:hover{opacity:.7}', + '#cl-core-switch-inline-wrap{display:flex;align-items:center;gap:14px;flex-wrap:wrap}', + '.cl-pm-mask{display:none;position:fixed;inset:0;background:rgba(0,0,0,.52);z-index:99998}', + '.cl-pm-mask.cl-on{display:block}', + '.cl-pm{display:none;position:fixed;top:50%;left:50%;transform:translate(-50%,-50%);width:min(900px,calc(100vw - 28px));max-height:calc(100vh - 56px);overflow:auto;background:#fff;color:#2a3142;border:1px solid rgba(0,0,0,.08);border-radius:12px;box-shadow:0 22px 60px rgba(0,0,0,.38);z-index:99999;padding:0 22px 18px;opacity:1}', + '.cl-pm.cl-on{display:block}', + '.cl-pm-mask.cl-theme-dark{background:rgba(0,0,0,.66)}', + '.cl-pm.cl-theme-dark{background:#1f242c;color:#e4ecf8;border-color:rgba(255,255,255,.12);box-shadow:0 22px 68px rgba(0,0,0,.62)}', + '.cl-pm-head{position:sticky;top:0;background:inherit;display:flex;align-items:center;justify-content:space-between;gap:12px;padding:15px 0 11px;border-bottom:1px solid rgba(128,128,128,.16)}', + '.cl-pm.cl-theme-dark .cl-pm-head{border-bottom-color:rgba(255,255,255,.12)}', + '.cl-pm-ttl{font-size:16px;font-weight:600;display:flex;align-items:baseline;gap:10px}', + '.cl-pm-st{font-size:12px;font-weight:500}', + '.cl-pm-acts{display:flex;gap:8px}', + '.cl-pm-close{font-size:12px;padding:5px 14px;border-radius:7px;border:1px solid rgba(128,128,128,.3);background:transparent;color:inherit;cursor:pointer}', + '.cl-pm.cl-theme-dark .cl-pm-close,.cl-pm.cl-theme-dark .cl-pm-test{background:#252a33;color:#e4ecf8;border-color:rgba(255,255,255,.24)}', + '.cl-pm-body{display:flex;flex-direction:column;gap:9px;padding-top:12px}', + '.cl-pm-empty{font-size:13px;opacity:.6;padding:34px 4px;text-align:center}', + '.cl-pm-row{display:flex;align-items:center;gap:12px;flex-wrap:wrap}', + '.cl-pm-name{flex:0 0 170px;text-align:right;font-size:13px;font-weight:500;display:flex;justify-content:flex-end;align-items:center;gap:6px;word-break:break-all}', + '.cl-pm-badge{font-size:10px;font-weight:600;padding:1px 6px;border-radius:8px;background:rgba(128,128,128,.16);opacity:.72;flex:none}', + '.cl-pm.cl-theme-dark .cl-pm-badge{background:rgba(255,255,255,.1);color:rgba(228,236,248,.82)}', + '.cl-pm-sel{flex:1;min-width:190px;font-size:13px;padding:7px 10px;border:1px solid rgba(128,128,128,.3);border-radius:8px;background:transparent;color:inherit}', + '.cl-pm-now{flex:1;min-width:190px;font-size:13px;padding:7px 10px;border:1px dashed rgba(128,128,128,.32);border-radius:8px;opacity:.78}', + '.cl-pm.cl-theme-dark .cl-pm-sel,.cl-pm.cl-theme-dark .cl-pm-now{background:#252a33;color:#e4ecf8;border-color:rgba(255,255,255,.22)}', + '.cl-pm.cl-theme-dark .cl-pm-sel option{background:#252a33;color:#e4ecf8}', + '.cl-pm-test{font-size:12px;padding:6px 13px;border-radius:7px;border:1px solid rgba(128,128,128,.3);background:transparent;color:inherit;cursor:pointer;flex:none}', + '.cl-pm-test[disabled]{opacity:.5;cursor:default}', + '.cl-dly{font-size:11px;font-weight:600}', + '.cl-dly-g{color:#2e9b51}', + '.cl-dly-y{color:#c98a16}', + '.cl-dly-r{color:#d65c4a}', + '.cl-dly-x{opacity:.4;font-weight:400}', + '@media(max-width:900px){.cl-cards{grid-template-columns:repeat(2,1fr)}.cl-controls{grid-template-columns:repeat(2,1fr)}}', + '@media(max-width:640px){.cl-live-grid{grid-template-columns:1fr}}', + '@media(max-width:480px){.cl-cards{grid-template-columns:1fr}.cl-controls{grid-template-columns:1fr}.cl-live-grid{grid-template-columns:1fr}}' +].join(''); + +var callUpdateCurrentSubscription = rpc.declare({ object: 'luci.clashoo', method: 'update_current_subscription', expect: {} }); +var callOverview = rpc.declare({ object: 'luci.clashoo', method: 'overview', expect: {} }); +var callProxiesList = rpc.declare({ object: 'luci.clashoo', method: 'proxies_list', expect: {} }); +var callProxySelect = rpc.declare({ object: 'luci.clashoo', method: 'proxy_select', params: ['group', 'name'], expect: {} }); +var callProxyDelay = rpc.declare({ object: 'luci.clashoo', method: 'proxy_delay', params: ['group'], expect: {} }); +function fastResolve(promise, timeoutMs, fallback) { + var t = new Promise(function (resolve) { + setTimeout(function () { resolve(fallback); }, timeoutMs); + }); + return Promise.race([L.resolveDefault(promise, fallback), t]); +} + +function rpcOverview() { + var fallback = { + status: {}, + stats: {}, + configs: { configs: [], current: '', core_type: '' }, + access: {} + }; + return L.resolveDefault(callOverview(), fallback); +} + +/* Progress message sequences — displayed step-by-step during async operations */ +var MSGS = { + mihomo: { + start: [ + _("Starting client"), + _("Checking configuration file"), + _("Setting mihomo network rules"), + _("Setting DNS forwarder / enabling custom DNS"), + _("Setting Cron scheduled tasks and starting process supervisor..."), + _("Restarting Dnsmasq"), + _("mihomo started successfully, please wait for servers to come online.") + ], + stop: [ + _("Stopping client..."), + _("Cleaning mihomo network rules"), + _("Disabling DNS cache"), + _("Stopping mihomo process supervisor"), + _("Removing Cron scheduled tasks"), + _("Restarting Dnsmasq") + ], + restart: [ + _("Restarting client..."), + _("Cleaning mihomo network rules"), + _("Stopping mihomo"), + _("Starting client"), + _("Checking configuration file"), + _("Setting mihomo network rules"), + _("Restarting Dnsmasq"), + _("mihomo restarted successfully, please wait for servers to come online.") + ] + }, + singbox: { + start: [ + _("Starting client"), + _("Checking configuration file"), + _("Setting sing-box network rules"), + _("Setting DNS forwarder / enabling custom DNS"), + _("Setting Cron scheduled tasks and starting process supervisor..."), + _("Restarting Dnsmasq"), + _("sing-box started successfully, please wait for servers to come online.") + ], + stop: [ + _("Stopping client..."), + _("Cleaning sing-box network rules"), + _("Disabling DNS cache"), + _("Stopping sing-box process supervisor"), + _("Removing Cron scheduled tasks"), + _("Restarting Dnsmasq") + ], + restart: [ + _("Restarting client..."), + _("Cleaning sing-box network rules"), + _("Stopping sing-box"), + _("Starting client"), + _("Checking configuration file"), + _("Setting sing-box network rules"), + _("Restarting Dnsmasq"), + _("sing-box restarted successfully, please wait for servers to come online.") + ] + } +}; + +// 全局锁:内核操作互斥(切换配置 / 更新订阅 / 删除) +function clKernelBusy() { return !!document.body.getAttribute('data-cl-kernel-busy'); } +function clKernelLock() { + document.body.setAttribute('data-cl-kernel-busy', '1'); + document.querySelectorAll('.cl-btn-switch, .cl-btn-update-sub, .cl-btn-delete, .cl-kernel-sel').forEach(function (b) { b.disabled = true; }); +} +function clKernelUnlock() { + document.body.removeAttribute('data-cl-kernel-busy'); + document.querySelectorAll('.cl-btn-switch, .cl-btn-update-sub, .cl-btn-delete, .cl-kernel-sel').forEach(function (b) { b.disabled = false; }); +} + +return view.extend({ + _busy: false, + _op: null, /* 'start' | 'stop' | 'restart' | null */ + _opTimers: null, /* array of setTimeout IDs for cleanup */ + _accessRefreshing: false, + _coreSwitchBusy: false, + _coreSwitchMsg: '', + _rtHistory: null, + + _lastAc: null, + _lastSt: null, + _lastCfgData: null, + + load: function () { + return Promise.resolve(null); + }, + + _overviewCacheKey: 'clashoo.overview.last', + + _readCachedOverview: function () { + try { + if (!window.sessionStorage) + return null; + var raw = window.sessionStorage.getItem(this._overviewCacheKey); + if (!raw) + return null; + var cached = JSON.parse(raw); + if (!cached || !cached._ts || (Date.now() - cached._ts) > 60000) + return null; + if (!cached.status || typeof cached.status.running !== 'boolean') + return null; + return cached; + } catch (e) { + return null; + } + }, + + _writeCachedOverview: function (ov) { + try { + if (!window.sessionStorage || !ov || !ov.status || typeof ov.status.running !== 'boolean') + return; + var copy = JSON.parse(JSON.stringify(ov)); + copy._ts = Date.now(); + window.sessionStorage.setItem(this._overviewCacheKey, JSON.stringify(copy)); + } catch (e) {} + }, + + _initialOverview: function () { + var core = uci.get('clashoo', 'config', 'core_type') || 'mihomo'; + var useConfig = uci.get('clashoo', 'config', 'use_config') || ''; + var singboxActive = uci.get('clashoo', 'config', 'singbox_active') || ''; + var slash = useConfig.lastIndexOf('/'); + var configName = slash >= 0 ? useConfig.slice(slash + 1) : useConfig; + if (core === 'singbox' && singboxActive) + configName = singboxActive; + + return { + status: { + loading: true, + running: null, + core_type: core, + dash_port: uci.get('clashoo', 'config', 'dash_port') || '9090', + dash_pass: uci.get('clashoo', 'config', 'dash_pass') || '', + panel_type: uci.get('clashoo', 'config', 'dashboard_panel') || 'zashboard', + proxy_mode: uci.get('clashoo', 'config', 'p_mode') || 'rule', + tcp_mode: uci.get('clashoo', 'config', 'tcp_mode') || 'tun', + udp_mode: uci.get('clashoo', 'config', 'udp_mode') || (uci.get('clashoo', 'config', 'tcp_mode') || 'tun'), + stack: uci.get('clashoo', 'config', 'stack') || 'system', + config: configName, + local_ip: location.hostname, + health_status: 'loading' + }, + stats: {}, + configs: { + configs: configName ? [configName] : [], + current: configName, + core_type: core + }, + access: { + updated_at: '0', + updating: true, + items: [] + } + }; + }, + + render: function (data) { + var ov = this._readCachedOverview() || this._initialOverview(); + var st = ov.status || {}; + var cfgData = ov.configs || { configs: [], current: '' }; + var ac = ov.access || {}; + var stats = ov.stats || {}; + + if (!document.getElementById('cl-css')) { + var s = document.createElement('style'); + s.id = 'cl-css'; s.textContent = CSS; + document.head.appendChild(s); + } + if (!document.getElementById('cl-css-ext')) { + var link = document.createElement('link'); + link.id = 'cl-css-ext'; + link.rel = 'stylesheet'; + link.href = L.resource('view/clashoo/clashoo.css') + '?v=20260806a1'; + document.head.appendChild(link); + } else { + document.getElementById('cl-css-ext').href = L.resource('view/clashoo/clashoo.css') + '?v=20260806a1'; + } + + this._lastSt = st; + this._lastCfgData = cfgData; + this._lastAc = ac; + this._overviewLoaded = false; + + var root = E('div', { 'class': 'cl-wrap clashoo-container cl-overview-page' }, [ + E('div', { 'class': 'cl-cards', id: 'cl-cards' }, this._cards(st, cfgData, ac)), + E('div', { 'class': 'cl-traffic-wrap', id: 'cl-traffic-wrap' }, [ + this._card(_("Traffic Monitor"), this._renderRealtimePanel(), 'cl-card-traffic') + ]), + E('div', { 'class': 'cl-controls', id: 'cl-controls' }, this._controls(st, cfgData)), + this._renderProxyModal() + ]); + this._rootEl = root; + this._applyThemeClass(); + this._observeThemeChanges(); + this._updateRealtimePanel(stats); + this._loadUciInBackground(); + + poll.add(L.bind(this._pollOverview, this), 5); + this._pollOverview(); + + return root; + }, + + _loadUciInBackground: function () { + var self = this; + setTimeout(function () { + L.resolveDefault(uci.load('clashoo'), null).then(function () { + if (self._overviewLoaded || !self._rootEl) + return; + var ov = self._initialOverview(); + self._lastCfgData = ov.configs || { configs: [], current: '' }; + + var controls = document.getElementById('cl-controls'); + if (controls) { + controls.innerHTML = ''; + self._controls(self._lastSt || ov.status || {}, self._lastCfgData).forEach(function (ctrl) { + controls.appendChild(ctrl); + }); + } + }); + }, 0); + }, + + _applyThemeClass: function () { + if (!this._rootEl || !this._rootEl.classList) + return; + var dark = this._isDarkUi(); + this._rootEl.classList.toggle('cl-theme-dark', !!dark); + this._rootEl.classList.toggle('cl-theme-light', !dark); + }, + + _observeThemeChanges: function () { + var self = this; + if (self._themeObserver) { + try { self._themeObserver.disconnect(); } catch (e0) {} + self._themeObserver = null; + } + if (self._themeMedia && self._themeMediaHandler) { + try { + if (self._themeMedia.removeEventListener) + self._themeMedia.removeEventListener('change', self._themeMediaHandler); + else if (self._themeMedia.removeListener) + self._themeMedia.removeListener(self._themeMediaHandler); + } catch (e00) {} + self._themeMedia = null; + self._themeMediaHandler = null; + } + if (typeof MutationObserver === 'undefined') + return self._applyThemeClass(); + + var obs = new MutationObserver(function (mutations) { + for (var i = 0; i < mutations.length; i++) { + var a = mutations[i] && mutations[i].attributeName; + if (!a) + continue; + if (a === 'class' || a === 'data-theme' || a === 'data-bs-theme' || a === 'data-darkmode') { + self._applyThemeClass(); + break; + } + } + }); + + var opt = { attributes: true, attributeFilter: ['class', 'data-theme', 'data-bs-theme', 'data-darkmode'] }; + try { obs.observe(document.documentElement, opt); } catch (e1) {} + if (document.body) { + try { obs.observe(document.body, opt); } catch (e2) {} + } + self._themeObserver = obs; + + if (window.matchMedia) { + var mq = window.matchMedia('(prefers-color-scheme: dark)'); + var handler = function () { self._applyThemeClass(); }; + try { + if (mq.addEventListener) + mq.addEventListener('change', handler); + else if (mq.addListener) + mq.addListener(handler); + } catch (e3) {} + self._themeMedia = mq; + self._themeMediaHandler = handler; + } + + self._applyThemeClass(); + }, + + _isDarkUi: function () { + var docEl = document.documentElement || {}; + var body = document.body || {}; + var theme = String( + (docEl.getAttribute && (docEl.getAttribute('data-theme') || docEl.getAttribute('data-bs-theme'))) || + (body.getAttribute && (body.getAttribute('data-theme') || body.getAttribute('data-bs-theme'))) || + '' + ).toLowerCase(); + var darkMode = String( + (docEl.getAttribute && docEl.getAttribute('data-darkmode')) || + (body.getAttribute && body.getAttribute('data-darkmode')) || + '' + ).toLowerCase(); + + if (theme === 'dark' || darkMode === '1' || darkMode === 'true') + return true; + if (theme === 'light' || darkMode === '0' || darkMode === 'false') + return false; + + var cls = String((docEl.className || '') + ' ' + (body.className || '')).toLowerCase(); + if (/(^|\s)(dark|theme-dark|darkmode)(\s|$)/.test(cls)) + return true; + if (/(^|\s)(light|theme-light)(\s|$)/.test(cls)) + return false; + + try { + var links = document.querySelectorAll('link[rel="stylesheet"]'); + for (var i = 0; i < links.length; i++) { + var href = String(links[i].href || '').toLowerCase(); + if (href.indexOf('dark.css') >= 0 || href.indexOf('darkmode') >= 0 || href.indexOf('argon-dark') >= 0) + return true; + } + } catch (e0) {} + + /* Fallback: inspect sidebar brightness for themes that don't expose standard attrs */ + try { + var byLuminance = function (node) { + if (!node) + return null; + var bg = window.getComputedStyle(node).backgroundColor || ''; + var rgb = String(bg).match(/\d+/g); + if (rgb && rgb.length >= 3) { + var sum = (parseInt(rgb[0], 10) || 0) + + (parseInt(rgb[1], 10) || 0) + + (parseInt(rgb[2], 10) || 0); + return sum < 380; + } + return null; + }; + + var sidebar = document.querySelector('.main-sidebar, .main-left, .sidebar, #mainmenu, #menubar, .left'); + var darkFromSidebar = byLuminance(sidebar); + if (darkFromSidebar != null) + return darkFromSidebar; + + var darkFromBody = byLuminance(body); + if (darkFromBody != null) + return darkFromBody; + } catch (e) {} + + if (window.matchMedia) + return !!window.matchMedia('(prefers-color-scheme: dark)').matches; + + return false; + }, + + _coreLabel: function (family, channel) { + if (!family) + return _("Not running"); + var f = family === 'singbox' ? 'sing-box' : 'mihomo'; + if (channel !== 'smart' && channel !== 'alpha') + return _(family === 'singbox' ? "sing-box Stable" : "mihomo Stable"); + var c = channel === 'smart' ? _("Smart") : _("Alpha"); + return f + ' ' + c; + }, + + _configuredChannel: function (family, st) { + var dcore = (st && st.dcore) || uci.get('clashoo', 'config', 'dcore') || '2'; + if (family === 'singbox') + return dcore === '5' ? 'alpha' : 'stable'; + if (dcore === '1') return 'smart'; + return dcore === '3' ? 'alpha' : 'stable'; + }, + + _currentCoreType: function (st) { + return (st && st.core_type) || uci.get('clashoo', 'config', 'core_type') || 'mihomo'; + }, + + _effectiveCore: function (st) { + var family = this._currentCoreType(st); + if (family === 'singbox') return 'singbox'; + /* 优先用 ubus status 实时返回的 dcore,避免 uci.get LuCI 缓存切换后滞后 */ + var dcore = (st && st.dcore) || uci.get('clashoo', 'config', 'dcore') || '2'; + return dcore === '1' ? 'smart' : 'mihomo'; + }, + + _refreshCoreSwitch: function () { + var wrap = document.getElementById('cl-core-switch-inline-wrap'); + if (!wrap) return; + wrap.innerHTML = ''; + wrap.appendChild(this._renderCoreSwitch(this._lastSt || {})); + wrap.appendChild(this._proxyTriggerBtn()); + }, + + _showCoreSwitchHint: function (msg) { + var self = this; + self._coreSwitchMsg = msg; + self._refreshCoreSwitch(); + setTimeout(function () { + if (self._coreSwitchMsg === msg) { + self._coreSwitchMsg = ''; + self._refreshCoreSwitch(); + } + }, 3500); + }, + + _switchCore: function (targetCore) { + var self = this; + if (self._coreSwitchBusy) + return Promise.resolve(); + + if (targetCore === 'smart' && self._lastSt && self._lastSt.has_smart === false) { + self._showCoreSwitchHint(_("Smart core not detected; updating the model will not install the core. Download the Smart build from the System page.")); + return Promise.resolve(); + } + + var currentEffective = self._effectiveCore(self._lastSt || {}); + if (targetCore === currentEffective) + return Promise.resolve(); + + var currentDcore = (self._lastSt && self._lastSt.dcore) || uci.get('clashoo', 'config', 'dcore') || '2'; + var rpcCore, nextDcore, targetLabel; + if (targetCore === 'smart') { + rpcCore = 'mihomo'; nextDcore = '1'; targetLabel = 'Smart'; + } else if (targetCore === 'singbox') { + rpcCore = 'singbox'; + if (currentDcore === '5' && self._lastSt.has_singbox_alpha) + nextDcore = '5'; + else if (currentDcore === '4' && self._lastSt.has_singbox_stable) + nextDcore = '4'; + else + nextDcore = self._lastSt.has_singbox_stable ? '4' : '5'; + targetLabel = 'sing-box'; + } else { + rpcCore = 'mihomo'; + if (currentDcore === '3' && self._lastSt.has_mihomo_alpha) + nextDcore = '3'; + else if (currentDcore === '2' && self._lastSt.has_mihomo_stable) + nextDcore = '2'; + else + nextDcore = self._lastSt.has_mihomo_stable ? '2' : '3'; + targetLabel = 'mihomo'; + } + + self._coreSwitchBusy = true; + self._coreSwitchMsg = _("Switching to ") + targetLabel + '...'; + self._refreshCoreSwitch(); + + return clashoo.setCore(rpcCore, nextDcore, 'apply') + .then(function (r) { + if (r && r.success === false && r.error === 'smart_core_missing') { + self._showCoreSwitchHint(_("Smart core not detected; updating the model will not install the core. Download the Smart build from the System page.")); + throw { soft: true }; + } + if (r && r.success === false && r.error === 'singbox_core_missing') { + self._showCoreSwitchHint(_("sing-box core not detected; download sing-box from the System page")); + throw { soft: true }; + } + if (r && r.success === false) + throw new Error(r.message || _("Core switch failed")); + self._lastSt = self._lastSt || {}; + self._lastSt.core_type = rpcCore; + self._lastSt.dcore = nextDcore; /* 乐观更新,避免重绘前 uci 缓存滞后 */ + if (!r || !r.restarting) { + self._lastSt.running = false; + self._lastSt.health_status = 'stopped'; + } + return r; + }) + .then(function (r) { + /* set_core auto-enables smart_auto_switch; init.d at boot + * smart_inject 会把 url-test/load-balance 转成 Smart 策略,无需手动操作。 */ + if (!r || !r.restarting) + self._coreSwitchMsg = _("Switched to ") + targetLabel + _(", click Start to take effect"); + self._refreshCoreSwitch(); + return new Promise(function (resolve) { setTimeout(resolve, 500); }); + }) + .then(function () { return self._pollStatus(); }) + .catch(function (e) { + if (e && e.soft) + return; + /* card already surfaces this via _coreSwitchMsg; no toast needed */ + self._coreSwitchMsg = _("Switch failed: ") + (e.message || e); + self._refreshCoreSwitch(); + }) + .then(function () { + self._coreSwitchBusy = false; + setTimeout(function () { + self._coreSwitchMsg = ''; + self._refreshCoreSwitch(); + }, 900); + }); + }, + + /* Inline panel-update feedback: button shows progress, status span shows result. + Replaces the old fire-and-forget toast so success/failure is visible in place. */ + _runPanelUpdate: function (panel, btn, statusEl) { + var self = this; + if (btn.disabled) return; + var label = self._panelLabel(panel); + var orig = btn.textContent; + self._panelUpdateBusy = true; /* pause overview poll so the rebuild won't wipe this feedback */ + btn.disabled = true; + btn.textContent = _("Downloading…"); + statusEl.textContent = ''; + statusEl.className = 'cl-panel-status'; + + var done = function (cls, text) { + self._panelUpdateBusy = false; + btn.disabled = false; + btn.textContent = orig; + statusEl.textContent = text; + statusEl.className = 'cl-panel-status ' + cls; + setTimeout(function () { + statusEl.textContent = ''; + statusEl.className = 'cl-panel-status'; + }, 6000); + }; + + var polls = 0; + var poll = function () { + clashoo.panelStatus().then(function (s) { + s = s || {}; + if (s.state === 'success') done('ok', '✓ ' + label + _(" updated")); + else if (s.state === 'error') done('err', '✗ ' + (s.msg || _("Update failed"))); + else if (polls++ >= 600) done('err', _("✗ Panel update timeout")); + else { + statusEl.textContent = s.msg || _("Downloading…"); + setTimeout(poll, 1200); + } + }); + }; + + clashoo.updatePanel(panel) + .then(function (r) { + if (r && r.busy) { + statusEl.textContent = r.message || _("Panel is downloading"); + setTimeout(poll, 600); + return; + } + if (!r || r.success === false) { + done('err', '✗ ' + ((r && r.message) || _("Submission failed"))); + return; + } + setTimeout(poll, 600); + }) + .catch(function () { done('err', _("✗ Submission failed")); }); + }, + + _renderCoreSwitch: function (st) { + var self = this; + var effective = this._effectiveCore(st); + var note = this._coreSwitchMsg || ''; + + var mkBtn = function (core, label) { + var active = core === effective; + var missingSmart = core === 'smart' && st && st.has_smart === false; + return E('button', { + type: 'button', + title: missingSmart ? _("Smart core not detected; updating the model will not install the core") : null, + 'class': 'cl-core-btn' + (active ? ' active' : ''), + disabled: self._coreSwitchBusy ? '' : null, + click: function (ev) { + ev.preventDefault(); + self._switchCore(core); + } + }, label); + }; + + var children = [ + E('div', { + 'class': 'cl-status-kernel' + (this._coreSwitchBusy ? ' is-busy' : ''), + title: note || null + }, [ + mkBtn('mihomo', 'Mihomo'), + mkBtn('smart', 'Smart'), + mkBtn('singbox', 'Sing-box') + ]) + ]; + if (note) + children.push(E('div', { 'class': 'cl-core-switch-hint' }, note)); + + return E('div', { 'class': 'cl-core-switch-wrap' }, children); + }, + + _proxyModeLabel: function (mode) { + var map = { rule: _("Rule"), global: _("Global"), direct: _("Direct") }; + return map[mode] || mode || '—'; + }, + + _panelLabel: function (name) { + var map = { + metacubexd: 'MetaCubeXD', + yacd: 'YACD', + zashboard: 'Zashboard', + razord: 'Razord' + }; + return map[name] || name || _("Panel"); + }, + + _renderServiceSwitch: function (st) { + var self = this; + var known = st && typeof st.running === 'boolean'; + var running = known && st.running === true; + var disabled = this._busy || !known || this._coreSwitchBusy; + return E('div', { 'class': 'cl-service-tools' }, [ + E('span', { 'class': 'cl-service-label' }, _("Enable Service")), + E('button', { + type: 'button', + title: !known ? _("Syncing runtime state") : (running ? _("Stop Service") : _("Start Service")), + 'aria-pressed': running ? 'true' : 'false', + 'class': 'cl-service-switch' + (running ? ' is-on' : ' is-off'), + disabled: disabled ? '' : null, + click: function (ev) { + ev.preventDefault(); + if (disabled) return; + return running ? self._stop() : self._start(); + } + }, [E('span', { 'class': 'cl-service-knob' })]) + ]); + }, + + _cards: function (st, cfgData, ac) { + var statusKnown = st && typeof st.running === 'boolean'; + var running = statusKnown && st.running === true; + var health = st.health_status || 'unknown'; + var configuredCoreLabel = this._coreLabel(st.core_type, this._configuredChannel(st.core_type, st)); + + var statusChildren = [ + !statusKnown + ? E('span', { 'class': 'cl-status-state cl-status-state-sync' }, _("Syncing")) + : running + ? E('span', { 'class': 'cl-status-state cl-status-state-run' }, _("Running 🟢")) + : E('span', { 'class': 'cl-status-state cl-status-state-stop' }, _("Stopped") + ' ⚪'), + E('span', { 'class': 'cl-status-note cl-status-note-core' }, configuredCoreLabel) + ]; + if (st.runtime_degraded) + statusChildren.push(E('span', { 'class': 'cl-status-note cl-status-note-degraded' }, _("Running degraded"))); + if (running && health === 'fail') + statusChildren.push(E('span', { 'class': 'cl-status-note cl-status-note-fail' }, _("Health check failed"))); + else if (running && health === 'pass') + statusChildren.push(E('span', { 'class': 'cl-status-note cl-status-note-pass' }, _("Health check passed"))); + var statusEl = E('span', { id: 'cl-status-val' }, statusChildren); + + return [ + this._card(_("Runtime Status"), statusEl, 'cl-card-status', + this._renderServiceSwitch(st)), + this._card(_("Core Switch"), + E('div', { id: 'cl-core-switch-inline-wrap' }, [ + this._renderCoreSwitch(st), + this._proxyTriggerBtn() + ]), + 'cl-card-kernel' + ), + this._card(_("Transparent Proxy"), this._renderTpMode(st), 'cl-card-mode'), + this._card(_("Access Check"), this._renderCheckStatus(st, ac), 'cl-card-access', this._renderAccessRefresh(ac)) + ]; + }, + + /* Directly update the status card content without rebuilding all cards */ + _showOpMsg: function (msg) { + var el = document.getElementById('cl-status-val'); + if (!el) return; + el.innerHTML = ''; + el.appendChild(E('span', { 'class': 'cl-op-msg' }, msg)); + }, + + /* Schedule message animation: space messages evenly over (totalMs - tailMs) */ + _startMsgAnim: function (messages, totalMs) { + var self = this; + var tailMs = 2500; /* last message stays visible for tailMs before poll */ + var spanMs = Math.max(totalMs - tailMs, 1000); + var stepMs = messages.length > 1 ? Math.floor(spanMs / (messages.length - 1)) : spanMs; + self._opTimers = []; + messages.forEach(function (msg, i) { + var t = setTimeout(function () { + self._showOpMsg(msg); + }, i * stepMs); + self._opTimers.push(t); + }); + }, + + _clearOpTimers: function () { + if (this._opTimers) { + this._opTimers.forEach(function (t) { clearTimeout(t); }); + this._opTimers = null; + } + }, + + _tpModeName: function (mode) { + var m = String(mode || '').toLowerCase(); + var map = { + redirect: 'Redirect', + redir: 'Redirect', + tproxy: 'TProxy', + tun: 'TUN', + off: _("Off") + }; + if (map[m]) return map[m]; + if (!mode) return '—'; + return String(mode); + }, + + _stackLabel: function (stack) { + var s = String(stack || '').toLowerCase(); + var map = { gvisor: 'gVisor', system: 'System', mixed: 'Mixed' }; + return map[s] || (stack ? String(stack) : 'System'); + }, + + _tpModeRows: function (st) { + var tcpRaw = st.tcp_node || st.effective_tcp_mode || st.tcp_mode || uci.get('clashoo', 'config', 'tcp_mode') || 'off'; + var udpRaw = st.udp_node || st.effective_udp_mode || st.udp_mode || uci.get('clashoo', 'config', 'udp_mode') || tcpRaw; + var stackRaw = st.stack_type || st.stack || uci.get('clashoo', 'config', 'stack') || 'system'; + var tunEnabled = String(tcpRaw).toLowerCase() === 'tun' || String(udpRaw).toLowerCase() === 'tun'; + + return { + rows: [ + { proto: 'TCP', mode: this._tpModeName(tcpRaw), suffix: String(tcpRaw).toLowerCase() === 'off' ? '' : _("Mode") }, + { proto: 'UDP', mode: this._tpModeName(udpRaw), suffix: String(udpRaw).toLowerCase() === 'off' ? '' : _("Mode") }, + { proto: _("Network Stack"), mode: tunEnabled ? this._stackLabel(stackRaw) : _("Not enabled"), suffix: tunEnabled ? _("Mode") : '' } + ] + }; + }, + + _isTpModeDegraded: function (st) { + if (!st) + return false; + + if (st.runtime_degraded) + return true; + + var tcp = String(st.tcp_mode || uci.get('clashoo', 'config', 'tcp_mode') || '').toLowerCase(); + var udp = String(st.udp_mode || uci.get('clashoo', 'config', 'udp_mode') || tcp).toLowerCase(); + var wantsTun = tcp === 'tun' || udp === 'tun'; + return wantsTun && String(st.has_tun_device) === '0'; + }, + + _renderTpMode: function (st) { + var data = this._tpModeRows(st); + var rows = data.rows.map(function (row) { + return E('div', { 'class': 'cl-mode-row' }, [ + E('span', { 'class': 'cl-mode-proto' }, row.proto), + E('span', { 'class': 'cl-mode-name' }, row.mode), + E('span', { 'class': 'cl-mode-suffix' }, row.suffix) + ]); + }); + if (this._isTpModeDegraded(st)) + rows.push(E('div', { 'class': 'cl-check-updated cl-mode-degraded' }, _("Degraded"))); + + return E('div', { id: 'cl-tpmode', 'class': 'cl-mode-stack' }, rows); + }, + + _renderAccessRefresh: function (ac) { + var self = this; + /* 核心未运行时访问检查无意义,强制不转圈,避免守护进程周期探测一直转 */ + var running = !!(this._lastSt && this._lastSt.running); + var loading = running && !!(this._accessRefreshing || (ac && ac.updating)); + return E('button', { + type: 'button', + id: 'cl-access-refresh', + title: _("Refresh Access Check"), + 'class': 'cl-icon-btn' + (loading ? ' is-loading' : ''), + click: function (ev) { + ev.preventDefault(); + ev.stopPropagation(); + self._manualRefreshAccess(); + } + }, '↻'); + }, + + _card: function (lbl, val, extraCls, tool) { + var head = [ + E('div', { 'class': 'lbl' }, lbl) + ]; + if (tool) + head.push(E('div', { 'class': 'cl-card-tools' }, [tool])); + + return E('div', { 'class': 'cl-card' + (extraCls ? (' ' + extraCls) : '') }, [ + E('div', { 'class': 'cl-card-head' }, head), + E('div', { 'class': 'val' }, [val]) + ]); + }, + + _toInt: function (v) { + var n = parseInt(v, 10); + return isFinite(n) && n > 0 ? n : 0; + }, + + /* ── 简易节点面板(模态浮层)── */ + _delayBadge: function (ms) { + ms = parseInt(ms, 10) || 0; + if (ms <= 0) return E('span', { 'class': 'cl-dly cl-dly-x' }, '—'); + var cls = ms < 100 ? 'cl-dly-g' : (ms < 300 ? 'cl-dly-y' : 'cl-dly-r'); + return E('span', { 'class': 'cl-dly ' + cls }, ms + 'ms'); + }, + + _pgTypeLabel: function (t) { + var m = { 'Selector': _("Selector"), 'URLTest': _("Url-test"), 'Fallback': _("Fallback"), + 'LoadBalance': _("Load-balance"), 'Relay': _("Relay") }; + return m[t] || t; + }, + + _proxyTriggerBtn: function () { + var self = this; + var btn = E('button', { 'class': 'cl-pm-open' }, _("Node Panel ›")); + btn.addEventListener('click', function () { self._openProxyModal(); }); + return btn; + }, + + _setPmStatus: function (text, tone) { + var el = this._pmStatusEl; + if (!el) return; + el.textContent = text || ''; + el.style.color = tone === 'ok' ? '#2e9b51' : (tone === 'err' ? '#d65c4a' : ''); + }, + + _renderProxyModal: function () { + var self = this; + var statusEl = E('span', { 'class': 'cl-pm-st' }, ''); + var body = E('div', { 'class': 'cl-pm-body', id: 'cl-pm-body' }, []); + this._pmStatusEl = statusEl; + this._pmBodyEl = body; + + var refreshBtn = E('button', { 'class': 'cl-pm-close' }, _("Refresh")); + refreshBtn.addEventListener('click', function () { self._loadProxies(); }); + var closeBtn = E('button', { 'class': 'cl-pm-close' }, _("Off")); + closeBtn.addEventListener('click', function () { self._closeProxyModal(); }); + + var modal = E('div', { 'class': 'cl-pm', id: 'cl-pm' }, [ + E('div', { 'class': 'cl-pm-head' }, [ + E('div', { 'class': 'cl-pm-ttl' }, [E('span', {}, _("Node Selection")), statusEl]), + E('div', { 'class': 'cl-pm-acts' }, [refreshBtn, closeBtn]) + ]), + body + ]); + modal.addEventListener('click', function (ev) { ev.stopPropagation(); }); + + var mask = E('div', { 'class': 'cl-pm-mask', id: 'cl-pm-mask' }, [modal]); + mask.addEventListener('click', function () { self._closeProxyModal(); }); + this._pmMask = mask; + this._pmModal = modal; + return mask; + }, + + _openProxyModal: function () { + var self = this; + if (!this._pmMask) return; + if (this._pmMask.parentNode !== document.body) + document.body.appendChild(this._pmMask); + var dark = this._isDarkUi(); + this._pmMask.classList.toggle('cl-theme-dark', !!dark); + this._pmModal.classList.toggle('cl-theme-dark', !!dark); + this._pmMask.classList.add('cl-on'); + this._pmModal.classList.add('cl-on'); + if (!this._pmEscBound) { + this._pmEscHandler = function (ev) { if (ev.key === 'Escape') self._closeProxyModal(); }; + document.addEventListener('keydown', this._pmEscHandler); + this._pmEscBound = true; + } + this._loadProxies(); + }, + + _closeProxyModal: function () { + if (this._pmMask) this._pmMask.classList.remove('cl-on'); + if (this._pmModal) this._pmModal.classList.remove('cl-on'); + if (this._pmEscBound) { + document.removeEventListener('keydown', this._pmEscHandler); + this._pmEscBound = false; + } + }, + + _loadProxies: function () { + var self = this; + var body = this._pmBodyEl; + if (!body) return; + var st = this._lastSt || {}; + if (!st.running) { + body.innerHTML = ''; + body.appendChild(E('div', { 'class': 'cl-pm-empty' }, _("Core is not running. Start it before switching nodes."))); + this._setPmStatus(_("Not running"), 'err'); + return; + } + body.innerHTML = ''; + body.appendChild(E('div', { 'class': 'cl-pm-empty' }, _("Loading…"))); + this._setPmStatus(_("Loading…"), ''); + callProxiesList().then(function (r) { + var b = self._pmBodyEl; + if (!b) return; + b.innerHTML = ''; + if (!r || !r.ok) { + b.appendChild(E('div', { 'class': 'cl-pm-empty' }, _("Cannot connect to core API. Check runtime status."))); + self._setPmStatus(_("Connection failed"), 'err'); + return; + } + var groups = r.groups || []; + if (!groups.length) { + b.appendChild(E('div', { 'class': 'cl-pm-empty' }, _("Current configuration has no manually switchable proxy groups"))); + self._setPmStatus(_("No proxy groups"), ''); + return; + } + groups.forEach(function (g) { b.appendChild(self._renderProxyGroup(g)); }); + self._setPmStatus(_("Ready · ") + groups.length + _(" groups"), 'ok'); + }).catch(function () { + var b = self._pmBodyEl; + if (b) { b.innerHTML = ''; b.appendChild(E('div', { 'class': 'cl-pm-empty' }, _("Load failed"))); } + self._setPmStatus(_("Load failed"), 'err'); + }); + }, + + _doProxySelect: function (group, name, onOk, onFail) { + callProxySelect(group, name).then(function (r) { + if (r && r.ok) { if (onOk) onOk(); } + else { + ui.addNotification(null, E('p', group + _(" switch failed: ") + ((r && r.message) || ''))); + if (onFail) onFail(); + } + }).catch(function () { + ui.addNotification(null, E('p', group + _(" switch error"))); + if (onFail) onFail(); + }); + }, + + _renderProxyGroup: function (g) { + var self = this; + var row = E('div', { 'class': 'cl-pm-row' }, [ + E('div', { 'class': 'cl-pm-name' }, [ + E('span', {}, g.name), + E('span', { 'class': 'cl-pm-badge' }, this._pgTypeLabel(g.type)) + ]) + ]); + + if (g.selectable) { + var members = g.members || []; + var prevVal = g.now; + var sel = E('select', { 'class': 'cl-pm-sel' }, + members.map(function (m) { + var label = m.name + (m.delay > 0 ? ' · ' + m.delay + 'ms' : ''); + return E('option', { value: m.name, selected: (m.name === g.now) ? '' : null }, label); + }) + ); + sel.addEventListener('change', function () { + var picked = sel.value; + sel.disabled = true; + self._doProxySelect(g.name, picked, + function () { prevVal = picked; sel.disabled = false; }, + function () { sel.value = prevVal; sel.disabled = false; }); + }); + row.appendChild(sel); + } else { + var dmap = {}; + (g.members || []).forEach(function (m) { dmap[m.name] = m.delay || 0; }); + row.appendChild(E('div', { 'class': 'cl-pm-now' }, [ + E('span', {}, (g.now || '—') + ' '), + this._delayBadge(dmap[g.now]) + ])); + } + + var testBtn = E('button', { 'class': 'cl-pm-test' }, _("Test Latency")); + testBtn.addEventListener('click', function () { + testBtn.disabled = true; + testBtn.textContent = _("Testing"); + callProxyDelay(g.name).then(function (r) { + testBtn.disabled = false; + testBtn.textContent = _("Test Latency"); + if (!r || !r.ok) { + ui.addNotification(null, E('p', g.name + _(" latency test failed: ") + ((r && r.message) || ''))); + return; + } + var fresh = { + name: g.name, type: g.type, now: g.now, selectable: g.selectable, + members: (g.members || []).map(function (m) { + return { name: m.name, delay: (r.delays && r.delays[m.name]) || m.delay || 0 }; + }) + }; + var newRow = self._renderProxyGroup(fresh); + if (row.parentNode) row.parentNode.replaceChild(newRow, row); + }).catch(function () { + testBtn.disabled = false; + testBtn.textContent = _("Test Latency"); + }); + }); + row.appendChild(testBtn); + return row; + }, + + _fmtRate: function (bytes) { + var b = this._toInt(bytes); + if (b >= 1024 * 1024) + return { value: (b / (1024 * 1024)).toFixed(2), unit: 'MB/s' }; + if (b >= 1024) + return { value: (b / 1024).toFixed(2), unit: 'kB/s' }; + return { value: '' + b, unit: 'B/s' }; + }, + + _fmtBytes: function (bytes) { + var b = this._toInt(bytes); + if (b >= 1024 * 1024 * 1024) + return (b / (1024 * 1024 * 1024)).toFixed(2) + ' GB'; + if (b >= 1024 * 1024) + return (b / (1024 * 1024)).toFixed(0) + ' MB'; + if (b >= 1024) + return (b / 1024).toFixed(0) + ' KB'; + return b + ' B'; + }, + + _fmtMiB: function (bytes) { + var b = this._toInt(bytes); + return (b / (1024 * 1024)).toFixed(0) + ' MiB'; + }, + + _initRealtimeHistory: function () { + if (!this._rtHistory) { + this._rtHistory = { up: [], down: [], conn: [] }; + } + }, + + _pushRealtimeSample: function (key, value) { + this._initRealtimeHistory(); + var hist = this._rtHistory[key] || (this._rtHistory[key] = []); + hist.push(this._toInt(value)); + if (hist.length > 36) + hist.shift(); + return hist; + }, + + _smoothPath: function (pts) { + if (!pts || !pts.length) + return ''; + if (pts.length === 1) + return 'M ' + pts[0].x.toFixed(1) + ' ' + pts[0].y.toFixed(1); + + var d = 'M ' + pts[0].x.toFixed(1) + ' ' + pts[0].y.toFixed(1); + for (var i = 0; i < pts.length - 1; i++) { + var p0 = i > 0 ? pts[i - 1] : pts[i]; + var p1 = pts[i]; + var p2 = pts[i + 1]; + var p3 = (i !== pts.length - 2) ? pts[i + 2] : p2; + + var cp1x = p1.x + (p2.x - p0.x) / 6; + var cp1y = p1.y + (p2.y - p0.y) / 6; + var cp2x = p2.x - (p3.x - p1.x) / 6; + var cp2y = p2.y - (p3.y - p1.y) / 6; + + d += ' C ' + + cp1x.toFixed(1) + ' ' + cp1y.toFixed(1) + ', ' + + cp2x.toFixed(1) + ' ' + cp2y.toFixed(1) + ', ' + + p2.x.toFixed(1) + ' ' + p2.y.toFixed(1); + } + return d; + }, + + _renderSparkline: function (points, tone) { + var w = 260, h = 42; + var vals = (points && points.length) ? points.slice() : [0]; + if (vals.length < 2) + vals.push(vals[0]); + + var max = 1; + for (var i = 0; i < vals.length; i++) { + if (vals[i] > max) + max = vals[i]; + } + + var n = vals.length; + var pts = []; + for (var j = 0; j < n; j++) { + var x = n === 1 ? 0 : (j * w / (n - 1)); + var y = h - ((vals[j] / max) * (h - 2)) - 1; + pts.push({ x: x, y: y }); + } + + var linePath = this._smoothPath(pts); + var areaPath = linePath + ' L ' + w.toFixed(1) + ' ' + h + ' L 0 ' + h + ' Z'; + + return E('svg', { 'class': 'cl-live-svg', viewBox: '0 0 ' + w + ' ' + h, preserveAspectRatio: 'none' }, [ + E('path', { 'class': 'cl-live-area ' + tone, d: areaPath }), + E('path', { 'class': 'cl-live-line ' + tone, d: linePath }) + ]); + }, + + _renderRealtimeCard: function (name, title) { + var mainId = 'cl-live-' + name + '-main'; + var unitId = 'cl-live-' + name + '-unit'; + var footId = 'cl-live-' + name + '-foot'; + var chartId = 'cl-live-' + name + '-chart'; + var titleChildren = [title]; + + return E('div', { 'class': 'cl-live-card cl-stat-card cl-live-card-' + name + ' is-zero', id: 'cl-live-' + name + '-card' }, [ + E('div', { 'class': 'cl-live-bg-chart', id: chartId }, [this._renderSparkline([0, 0], name)]), + E('div', { 'class': 'cl-live-content' }, [ + E('div', { 'class': 'cl-live-title' }, titleChildren), + E('div', { 'class': 'cl-live-main' }, [ + E('span', { 'class': 'cl-live-num', id: mainId }, '0'), + E('span', { 'class': 'cl-live-unit', id: unitId }, name === 'conn' ? '' : 'B/s') + ]), + E('div', { 'class': 'cl-live-foot', id: footId }, _("Waiting for data...")) + ]) + ]); + }, + + _renderRealtimePanel: function () { + this._initRealtimeHistory(); + return E('div', { 'class': 'cl-live-box' }, [ + E('div', { 'class': 'cl-live-grid' }, [ + this._renderRealtimeCard('up', _("Upload")), + this._renderRealtimeCard('down', _("Download")), + this._renderRealtimeCard('conn', _("Connections")) + ]) + ]); + }, + + _setLiveCardState: function (name, value, hotThreshold, online) { + var card = document.getElementById('cl-live-' + name + '-card'); + if (!card) return; + var cls = 'cl-live-card cl-stat-card cl-live-card-' + name; + if (name === 'conn' && !online) + cls += ' is-offline'; + if (value > 0) + cls += ' is-active'; + else + cls += ' is-zero'; + if (value >= hotThreshold) + cls += ' is-hot'; + card.className = cls; + }, + + _updateRealtimePanel: function (raw) { + var st = raw || {}; + var up = this._toInt(st.up); + var down = this._toInt(st.down); + var upTotal = this._toInt(st.up_total); + var downTotal = this._toInt(st.down_total); + var conn = this._toInt(st.connections); + var mem = this._toInt(st.memory_inuse); + var online = !!(st.ok && st.running); + + var upRate = this._fmtRate(up); + var downRate = this._fmtRate(down); + var upHist = this._pushRealtimeSample('up', up); + var downHist = this._pushRealtimeSample('down', down); + var connHist = this._pushRealtimeSample('conn', conn); + + var setText = function (id, text) { + var el = document.getElementById(id); + if (el) el.textContent = text; + }; + var setChart = L.bind(function (id, points, tone) { + var box = document.getElementById(id); + if (!box) return; + box.innerHTML = ''; + box.appendChild(this._renderSparkline(points, tone)); + }, this); + + setText('cl-live-up-main', upRate.value); + setText('cl-live-up-unit', upRate.unit); + setText('cl-live-up-foot', _("Total %s").replace('%s', this._fmtBytes(upTotal))); + setChart('cl-live-up-chart', upHist, 'up'); + + setText('cl-live-down-main', downRate.value); + setText('cl-live-down-unit', downRate.unit); + setText('cl-live-down-foot', _("Total %s").replace('%s', this._fmtBytes(downTotal))); + setChart('cl-live-down-chart', downHist, 'down'); + + setText('cl-live-conn-main', '' + conn); + setText('cl-live-conn-unit', ''); + setText('cl-live-conn-foot', _("Memory usage %s").replace('%s', this._fmtMiB(mem))); + setChart('cl-live-conn-chart', connHist, 'conn'); + + this._setLiveCardState('up', up, 512 * 1024, online); + this._setLiveCardState('down', down, 1024 * 1024, online); + this._setLiveCardState('conn', conn, 80, online); + + }, + + _probeLabel: function (key, probe) { + if (probe && probe.name) return String(probe.name); + if (probe && probe.title) return String(probe.title); + if (probe && probe.site) return String(probe.site); + var map = { + baidu: 'Baidu', + google: 'Google', + github: 'GitHub', + youtube: 'YouTube', + bytedance: _("ByteDance"), + cloudflare: 'Cloudflare', + bilibili: 'Bilibili', + taobao: 'Taobao' + }; + var k = String(key || '').toLowerCase(); + return map[k] || String(key || 'Unknown'); + }, + + _probeIcon: function (key, probe) { + if (probe && probe.icon) { + if (/^(https?:)?\//.test(probe.icon)) + return probe.icon; + return L.resource('view/clashoo/' + probe.icon); + } + var map = { + baidu: 'baidu.svg', + google: 'google.svg', + github: 'github.svg', + youtube: 'youtube.svg', + bytedance: 'bytedance.svg', + cloudflare: 'cloudflare.svg', + bilibili: 'bilibili.svg', + taobao: 'taobao.svg' + }; + var k = String(key || '').toLowerCase(); + return map[k] ? (L.resource('view/clashoo/' + map[k]) + '?v=20260421p') : null; + }, + + _probeGrade: function (probe) { + var ms = probe && probe.avg_ms != null ? parseInt(probe.avg_ms, 10) : + (probe && probe.ms != null ? parseInt(probe.ms, 10) : + (probe && probe.latency != null ? parseInt(probe.latency, 10) : NaN)); + var ok = !!(probe && (probe.ok === true || probe.state === 'ok' || probe.state === 'high_latency' || probe.state === 'loss')); + if (!ok || !isFinite(ms)) + return { + tone: 'red', + bars: 1, + text: (probe && probe.code === 'skip') ? 'Core down' : + ((probe && probe.code && probe.code !== '000') ? 'Offline' : 'Timeout'), + offline: true + }; + + if (ms <= 400) + return { tone: 'green', bars: 4, text: ms + 'ms' }; + if (ms <= 800) + return { tone: 'warn', bars: 3, text: ms + 'ms' }; + return { tone: 'red', bars: 2, text: ms + 'ms' }; + }, + + _renderSignalBars: function (grade) { + var bars = []; + for (var i = 0; i < 4; i++) { + bars.push(E('i', { 'class': i < grade.bars ? 'active' : '' })); + } + var cls = 'cl-signal cl-signal-' + grade.tone + (grade.offline ? ' cl-signal-offline' : ''); + return E('span', { 'class': cls }, bars); + }, + + _renderProbeIcon: function (icon, label) { + var wrap = E('span', { 'class': 'cl-check-icon-wrap' }); + if (!icon) { + wrap.appendChild(E('span', { 'class': 'cl-check-icon-fallback' }, (label || '?').charAt(0).toUpperCase())); + return wrap; + } + wrap.appendChild(E('img', { + 'class': 'cl-check-icon', + src: icon, + alt: label, + error: function (ev) { + var fb = E('span', { 'class': 'cl-check-icon-fallback' }, (label || '?').charAt(0).toUpperCase()); + if (ev.target && ev.target.parentNode) + ev.target.parentNode.replaceChild(fb, ev.target); + } + })); + return wrap; + }, + + _normalizeCheckItems: function (ac) { + if (!ac) return []; + if ((parseInt(ac.updated_at || '0', 10) || 0) <= 0 && ac.updating) + return []; + var self = this; + + var normalizeItems = function (source) { + if (!source) return []; + + if (Array.isArray(source)) { + return source.map(function (item, idx) { + var key = item.key || item.name || item.title || item.site || ('item_' + idx); + return { + key: key, + label: self._probeLabel(key, item), + icon: self._probeIcon(key, item), + probe: item + }; + }); + } + + var preferred = ['bytedance', 'youtube', 'google', 'github', 'baidu', 'cloudflare']; + var keys = Object.keys(source); + keys.sort(function (a, b) { + var ia = preferred.indexOf(a), ib = preferred.indexOf(b); + if (ia !== -1 || ib !== -1) { + if (ia === -1) return 1; + if (ib === -1) return -1; + return ia - ib; + } + return a.localeCompare(b); + }); + + return keys.map(function (key) { + var probe = source[key] || {}; + return { + key: key, + label: self._probeLabel(key, probe), + icon: self._probeIcon(key, probe), + probe: probe + }; + }); + }; + + if (Array.isArray(ac.items) && ac.items.length) + return normalizeItems(ac.items); + if (ac.proxy) + return normalizeItems(ac.proxy); + if (ac.direct) + return normalizeItems(ac.direct); + return []; + }, + + _renderCheckItem: function (item) { + var grade = this._probeGrade(item.probe || {}); + return E('div', { 'class': 'cl-check-item' }, [ + E('div', { 'class': 'cl-check-main' }, [ + this._renderProbeIcon(item.icon, item.label), + E('span', { 'class': 'cl-check-name site-name' }, item.label) + ]), + E('span', { 'class': 'cl-check-latency latency-val cl-lat-' + grade.tone }, grade.text), + this._renderSignalBars(grade) + ]); + }, + + _formatNumberText: function (tpl, n) { + return String(tpl).replace('%d', String(n)); + }, + + _lastCheckText: function (ts) { + var now = Math.floor(Date.now() / 1000); + var delta = now - (parseInt(ts, 10) || 0); + if (!isFinite(delta) || delta < 0) delta = 0; + if (delta < 5) return _("Last check: just now"); + if (delta < 60) return this._formatNumberText(_("Last check: %d seconds ago"), delta); + if (delta < 3600) return this._formatNumberText(_("Last check: %d minutes ago"), Math.floor(delta / 60)); + return this._formatNumberText(_("Last check: %d hours ago"), Math.floor(delta / 3600)); + }, + + _renderCheckUpdated: function (ac) { + if (!ac) return null; + var updatedAt = parseInt(ac.updated_at || '0', 10) || 0; + if (updatedAt <= 0) { + return E('div', { 'class': 'cl-check-updated' }, _("Last check: initializing")); + } + var msg = this._lastCheckText(updatedAt); + if (ac.updating && this._accessRefreshing) + msg += _(" (refreshing)"); + return E('div', { 'class': 'cl-check-updated' }, msg); + }, + + _renderCheckSkeleton: function () { + return E('div', { 'class': 'cl-check-skeleton' }, [ + E('div', { 'class': 'cl-skel-row' }, [ + E('span', { 'class': 'cl-skel-icon' }), + E('span', { 'class': 'cl-skel-line' }), + E('span', { 'class': 'cl-skel-line short' }) + ]), + E('div', { 'class': 'cl-skel-row' }, [ + E('span', { 'class': 'cl-skel-icon' }), + E('span', { 'class': 'cl-skel-line' }), + E('span', { 'class': 'cl-skel-line short' }) + ]), + E('div', { 'class': 'cl-check-updated' }, _("Last check: initializing")) + ]); + }, + + _renderCheckStatus: function (st, ac) { + var items = this._normalizeCheckItems(ac); + if (!items.length) { + return this._renderCheckSkeleton(); + } + + var self = this; + var children = items.map(function (item) { + return self._renderCheckItem(item); + }); + var updated = this._renderCheckUpdated(ac); + if (updated) children.push(updated); + return E('div', { 'class': 'cl-check-modern' }, children); + }, + + _controls: function (st, cfgData) { + var self = this; + var configs = (cfgData && cfgData.configs) ? cfgData.configs : []; + var current = (cfgData && cfgData.current) || ''; + var proxyMode = st.proxy_mode || 'rule'; + var tcpMode = String(st.tcp_mode || '').toLowerCase(); + var udpMode = String(st.udp_mode || tcpMode).toLowerCase(); + var stackMode = String(st.stack || '').toLowerCase(); + var tpMode = 'custom'; + + if (tcpMode === 'tun' && udpMode === 'tun' && stackMode === 'mixed') + tpMode = 'tun-mixed'; + else if (tcpMode === 'tun' && udpMode === 'tun' && stackMode === 'gvisor') + tpMode = 'tun-gvisor'; + else if (tcpMode === 'tun' && udpMode === 'tun') + tpMode = 'tun-system'; + else if (tcpMode === 'redirect' && udpMode === 'tproxy') + tpMode = 'fake-ip'; + var panelType = st.panel_type || 'zashboard'; + var panelUrl = this._dashboardUrl(st); + var panels = ['metacubexd', 'yacd', 'zashboard', 'razord']; + + var mkSel = function (opts, val, fn, extraCls) { + return E('select', { 'class': 'cbi-input-select' + (extraCls ? ' ' + extraCls : ''), change: fn }, + opts.map(function (o) { + return E('option', { value: o[0], selected: o[0] === val ? '' : null, disabled: o[2] ? '' : null }, o[1]); + })); + }; + var tpModeOptions = [['fake-ip','Fake-IP'],['tun-system','System'],['tun-gvisor','gVisor'],['tun-mixed','Mixed']]; + if (tpMode === 'custom') + tpModeOptions.unshift(['custom',_("Custom")]); + + var panelStatusEl = E('span', { 'class': 'cl-panel-status' }, ''); + + var panelSel = mkSel(panels.map(function (p) { + return [p, self._panelLabel(p)]; + }), panelType, function (ev) { + var next = ev.target.value; + var prev = panelType; + ev.target.disabled = true; + self._lastSt = self._lastSt || {}; + self._lastSt.panel_type = next; + clashoo.setPanel(next).then(function (r) { + if (r && r.error) + throw new Error(r.error); + return self._pollOverview(true); + }).catch(function (e) { + self._lastSt.panel_type = prev; + ev.target.value = prev; + ui.addNotification(null, E('p', _("Panel switch failed: ") + (e.message || e))); + }).then(function () { + ev.target.disabled = false; + }); + }); + + return [ + E('div', { 'class': 'cl-ctrl' }, [ + E('label', {}, _("Proxy Mode")), + mkSel([['rule',_("Rule")],['global',_("Global")],['direct',_("Direct")]], proxyMode, + function (ev) { + var sel = ev.target; + if (sel.disabled || clKernelBusy()) return; + clKernelLock(); + sel.disabled = true; + Promise.resolve(clashoo.setProxyMode(sel.value)).then(function () { + return self._pollOverview(true); + }).catch(function () {}).then(function () { + sel.disabled = false; + clKernelUnlock(); + }); + }, 'cl-kernel-sel') + ]), + E('div', { 'class': 'cl-ctrl' }, [ + E('label', {}, _("Run Mode")), + mkSel(tpModeOptions, tpMode, + function (ev) { + var mode = ev.target.value; + if (mode === 'custom') + return; + var sel = ev.target; + if (sel.disabled || clKernelBusy()) return; + clKernelLock(); + sel.disabled = true; + self._op = 'mode'; + self._lastSt = self._lastSt || {}; + if (mode === 'tun-mixed') { + self._lastSt.tcp_mode = 'tun'; + self._lastSt.udp_mode = 'tun'; + self._lastSt.stack = 'mixed'; + } else if (mode === 'tun-gvisor') { + self._lastSt.tcp_mode = 'tun'; + self._lastSt.udp_mode = 'tun'; + self._lastSt.stack = 'gvisor'; + } else if (mode === 'tun-system') { + self._lastSt.tcp_mode = 'tun'; + self._lastSt.udp_mode = 'tun'; + self._lastSt.stack = 'system'; + } else { + self._lastSt.tcp_mode = 'redirect'; + self._lastSt.udp_mode = 'tproxy'; + } + clashoo.setMode(mode).then(function (r) { + if (r && r.error) + ui.addNotification(null, E('p', _("Run mode setting failed: ") + r.error)); + return self._pollOverview(true); + }).catch(function (e) { + ui.addNotification(null, E('p', _("Run mode setting failed: ") + (e.message || e))); + }).then(function () { + self._op = null; + sel.disabled = false; + clKernelUnlock(); + }); + }, 'cl-kernel-sel') + ]), + E('div', { 'class': 'cl-ctrl' }, [ + E('label', {}, _("Configuration Files")), + E('div', { 'class': 'cl-ctrl-row cl-config-row' }, [ + mkSel(configs.length ? configs.map(function(c){return[c,c];}) : [['',_("(empty)")]], current, + function (ev) { + var sel = ev.target; + if (sel.disabled || clKernelBusy()) return; + var name = sel.value; + var prev = sel.getAttribute('data-cl-prev') || current; + clKernelLock(); + sel.disabled = true; + var setter = (st.core_type === 'singbox') + ? clashoo.setSingboxProfile(name) + : clashoo.setConfig(name); + setter + .then(function (r) { + if (r && r.error) { + ui.addNotification(null, E('p', _("Switch configuration failed: ") + r.error)); + sel.value = prev; + return; + } + sel.setAttribute('data-cl-prev', name); + }) + .catch(function (e) { + ui.addNotification(null, E('p', _("Switch configuration failed: ") + (e.message || e))); + sel.value = prev; + }) + .then(function () { + sel.disabled = false; + clKernelUnlock(); + /* force immediate state refresh so cards get new current */ + return self._pollOverview(true); + }); + }, 'cl-kernel-sel'), + E('button', { + 'class': 'btn cbi-button-action cl-btn-update-sub', + click: L.bind(function (ev) { this._updSubs(ev); }, this) + }, _("Update Subscription")) + ]) + ]), + E('div', { 'class': 'cl-ctrl' }, [ + E('label', {}, _("Dashboard")), + E('div', { 'class': 'cl-ctrl-row' }, [ + panelSel, + E('button', { + 'class': 'btn cbi-button cl-btn-panel-update', + click: function () { + self._runPanelUpdate(panelSel.value, this, panelStatusEl); + } + }, _("Update")), + panelStatusEl, + E('a', { + 'class': 'btn cbi-button cl-btn-panel-open', + href: panelUrl, + target: '_blank', + rel: 'noopener noreferrer', + click: function (ev) { + ev.preventDefault(); + window.open(self._dashboardUrl(self._lastSt || st), '_blank', 'noopener'); + } + }, _("Open Dashboard")) + ]) + ]) + ]; + }, + + _dashboardUrl: function (st) { + st = st || {}; + var dashPort = st.dash_port || + uci.get('clashoo', 'config', 'dash_port') || + uci.get('clashoo', 'config', 'dashboard_port') || + '9090'; + var host = location.hostname || st.local_ip || '127.0.0.1'; + var secret = st.dash_pass || + uci.get('clashoo', 'config', 'dash_pass') || + ''; + var params = [ + ['host', host], + ['hostname', host], + ['port', dashPort], + ['secret', secret] + ].map(function (kv) { + return encodeURIComponent(kv[0]) + '=' + encodeURIComponent(kv[1] || ''); + }).join('&'); + + return 'http://' + host + ':' + dashPort + '/ui/?' + params + '#/proxies'; + }, + + _pollOverview: function (force) { + this._applyThemeClass(); + if (!force && this._op) return Promise.resolve(); + if (!force && this._coreSwitchBusy) return Promise.resolve(); + if (!force && this._panelUpdateBusy) return Promise.resolve(); + if (!force && document.hidden) return Promise.resolve(); + var self = this; + return rpcOverview() + .then(function (ov) { + ov = ov || {}; + var st = ov.status || {}; + var cfgData = ov.configs || { configs: [], current: '' }; + var ac = ov.access || {}; + var stats = ov.stats || {}; + + /* force proxy probes down when stopped (skip daemon refresh) */ + if (!st.running && ac && ac.proxy) { + var downProbe = { ok: false, state: 'down', code: 'skip', ok_count: 0, attempts: 1, loss: 1, avg_ms: 0 }; + Object.keys(ac.proxy).forEach(function (k) { ac.proxy[k] = downProbe; }); + } + + self._overviewLoaded = true; + self._lastSt = st; + self._lastCfgData = cfgData; + self._lastAc = ac; + self._writeCachedOverview(ov); + self._refreshCoreSwitch(); + + /* only rebuild DOM on user-visible field changes, avoid flicker every 5s + 尤其是切换 tab 回到 overview 时缓存数据与首次 poll 数据通常一致 */ + var sig = JSON.stringify({ + running: st.running, + health: st.health_status, + proxy_mode: st.proxy_mode, + tcp_mode: st.tcp_mode, + udp_mode: st.udp_mode, + stack: st.stack_type || st.stack, + config: st.config, + core_type: st.core_type, + panel_type: st.panel_type, + dcore: st.dcore, + configs: cfgData.configs || [], + current: cfgData.current, + ac_updated: ac.updated_at, + ac_updating: ac.updating + }); + var skipRebuild = (sig === self._lastRenderSig); + self._lastRenderSig = sig; + + var cards = document.getElementById('cl-cards'); + if (!cards) return; + if (!skipRebuild) { + var newCards = self._cards(st, cfgData, ac); + cards.innerHTML = ''; + newCards.forEach(function (card) { cards.appendChild(card); }); + + var controls = document.getElementById('cl-controls'); + if (controls) { + controls.innerHTML = ''; + self._controls(st, cfgData).forEach(function (ctrl) { controls.appendChild(ctrl); }); + } + } + + self._updateRealtimePanel(stats); + }); + }, + + /* Compatibility wrapper for existing call sites */ + _pollStatus: function () { + return this._pollOverview(); + }, + + /* Slow poll for connectivity check — every 60s, network probes are expensive */ + _pollAccess: function () { + return this._pollOverview(true); + }, + + _refreshAccessCard: function () { + var cards = document.getElementById('cl-cards'); + if (!cards) return; + var st = this._lastSt || {}; + var ac = this._lastAc || {}; + var newCard = this._card(_("Access Check"), this._renderCheckStatus(st, ac), 'cl-card-access', this._renderAccessRefresh(ac)); + var oldCard = cards.querySelector('.cl-card-access'); + if (oldCard && oldCard.parentNode) { + oldCard.parentNode.replaceChild(newCard, oldCard); + } else { + cards.appendChild(newCard); + } + }, + + _manualRefreshAccess: function () { + var self = this; + if (self._accessRefreshing) return Promise.resolve(); + var previousUpdatedAt = parseInt((self._lastAc && self._lastAc.updated_at) || 0, 10) || 0; + self._accessRefreshing = true; + self._refreshAccessCard(); + + var trigger = (clashoo && typeof clashoo.accessCheckRefresh === 'function') + ? clashoo.accessCheckRefresh() + : Promise.resolve({ success: true }); + + return L.resolveDefault(trigger, { success: false }) + .then(function () { + return self._waitAccessRefresh(previousUpdatedAt); + }) + .catch(function () { + return self._pollAccess(); + }) + .then(function () { + self._accessRefreshing = false; + self._refreshAccessCard(); + }); + }, + + _waitAccessRefresh: function (previousUpdatedAt) { + var self = this; + var started = Date.now(); + var maxWait = 25000; + + function sleep(ms) { + return new Promise(function (resolve) { setTimeout(resolve, ms); }); + } + + function loop() { + return self._pollAccess().then(function () { + var ac = self._lastAc || {}; + var updatedAt = parseInt(ac.updated_at || 0, 10) || 0; + if (updatedAt > previousUpdatedAt && !ac.updating) + return; + if (!ac.updating && updatedAt > 0 && (Date.now() - started) > 2500) + return; + if ((Date.now() - started) >= maxWait) + return; + return sleep(700).then(loop); + }); + } + + return sleep(500).then(loop); + }, + + _pollRealtime: function () { + return this._pollOverview(); + }, + + /* health_detail → 用户看得懂的中文(参考 P2-F 字典;详细状态时只在状态卡上展示) */ + _friendlyHealth: function (detail) { + var map = { + 'boot_disabled': _("Stopped (not enabled at boot)"), + 'service_disabled': _("Service disabled"), + 'service_stopped': _("Service stopped"), + 'preflight:openclash_conflict': _("OpenClash is enabled; disable it first to avoid rule conflicts"), + 'preflight:config_missing': _("No configuration file found. Import a subscription or upload a configuration on the Configuration page first."), + 'preflight:missing_fw4_stack': _("System is missing nftables runtime"), + 'preflight:core_validation_failed': _("Core verification failed. Check System → Core."), + 'start:core_not_running': _("Core did not start within 15 seconds (procd is recovering)"), + 'start:singbox_service_failed': _("sing-box service failed to start. Check System → Log."), + 'init': _("Initializing…") + }; + return map[detail] || ''; + }, + + /* health_detail → 启动 / 停止 进度文字 */ + _opPhase: function (opKey, st) { + var hd = (st && st.health_detail) || ''; + if (opKey === 'stop') { + if (st && st.running === false) return _("Stopped") + ' ✓'; + return _("Stopping…"); + } + if (!st || st.running !== true) return _("Starting core…"); + if (hd === 'init') return _("Checking environment…"); + if (hd.indexOf('preflight:') === 0) return _("Checking environment…"); + if (hd.indexOf('start:') === 0) return this._friendlyHealth(hd) || _("Starting core…"); + if (st.health_status === 'pass') return _("Ready ✓"); + if (st.health_status === 'fail') return _("Started (") + (this._friendlyHealth(hd) || _("Health check failed")) + ')'; + return _("Health check in progress…"); + }, + + /* fn: fire-and-forget RPC + 秒速轮询直到状态到位 */ + /* toggle switch instantly (optimistic), do not wait for RPC */ + _svc: function (fn, opKey) { + if (this._busy) return Promise.resolve(); + + // preflight: refuse start when no profile selected. + // backend select_config also defends but toast is slow, UI would flash. + if (opKey === 'start' || opKey === 'restart') { + var st0 = this._lastSt || {}; + var hasConfig = !!(st0.config || st0.conf_path); + if (!hasConfig) { + ui.addNotification(null, E('p', _("No configuration file selected. Select or upload one on the Configuration page before starting.")), 'warning'); + return Promise.resolve(); + } + } + + this._busy = true; + var self = this; + self._op = opKey; + + /* 立即翻转 switch 视觉 */ + var btn = document.querySelector('.cl-service-switch'); + if (btn) { + var running = btn.getAttribute('aria-pressed') === 'true'; + var newRunning = opKey === 'start'; + if (newRunning !== running) { + btn.setAttribute('aria-pressed', newRunning ? 'true' : 'false'); + btn.className = 'cl-service-switch' + (newRunning ? ' is-on' : ' is-off'); + } + self._showOpMsg(opKey === 'stop' ? _("Stopping…") : _("Starting…")); + } + + var maxWait = opKey === 'stop' ? 15000 : 35000; + fn().catch(function () {}); /* fire-and-forget */ + + var started = Date.now(); + var pollTimer = null; + + function finish(finalMsg) { + if (pollTimer) { clearTimeout(pollTimer); pollTimer = null; } + if (finalMsg) self._showOpMsg(finalMsg); + self._busy = false; + self._op = null; + self._pollOverview(true); + } + + function pollOnce() { + L.resolveDefault(clashoo.status(), {}).then(function (st) { + st = st || {}; + var elapsed = Date.now() - started; + if (opKey === 'stop') { + if (st.running === false) return finish(_("Stopped") + ' ⚪'); + } else { + if (st.running === true) return finish(_("Running 🟢")); + if (st.health_status === 'fail') return finish(null); + } + if (elapsed >= maxWait) return finish(null); + pollTimer = setTimeout(pollOnce, 500); + }).catch(function () { + if (Date.now() - started < maxWait) pollTimer = setTimeout(pollOnce, 500); + else finish(null); + }); + } + pollTimer = setTimeout(pollOnce, 100); + }, + + _start: function () { return this._svc(function () { return clashoo.start(); }, 'start'); }, + _stop: function () { return this._svc(function () { return clashoo.stop(); }, 'stop'); }, + _restart: function () { return this._svc(function () { return clashoo.restart(); }, 'restart'); }, + + _updSubs: function (ev) { + var btn = ev && ev.target; + if (btn && btn.disabled) return Promise.resolve(); + if (clKernelBusy()) return Promise.resolve(); + clKernelLock(); + var origText = btn ? btn.textContent : ''; + if (btn) { btn.disabled = true; btn.textContent = _("Updating…"); } + return L.resolveDefault(callUpdateCurrentSubscription(), {}).then(function (r) { + if (r && r.reason === 'not_subscription') { + ui.addNotification(null, E('p', _("Current configuration is a custom file; no subscription update needed")), 'info'); + return; + } + ui.addNotification(null, E('p', r.success ? (r.message || _("Subscription updated successfully")) + : (_("Update failed: ") + (r.message || _("Current configuration has no recorded subscription URL"))))); + }).catch(function () {}).then(function () { + if (btn) { btn.disabled = false; btn.textContent = origText; } + clKernelUnlock(); + }); + }, + + handleSaveApply: null, + handleSave: null, + handleReset: null +}); + +reload_service() { + restart +} diff --git a/luci-app-clashoo/htdocs/luci-static/resources/view/clashoo/system.js b/luci-app-clashoo/htdocs/luci-static/resources/view/clashoo/system.js new file mode 100644 index 000000000..c1c982390 --- /dev/null +++ b/luci-app-clashoo/htdocs/luci-static/resources/view/clashoo/system.js @@ -0,0 +1,1431 @@ +'use strict'; +'require view'; +'require form'; +'require uci'; +'require ui'; +'require poll'; +'require rpc'; +'require fs'; +'require tools.clashoo as clashoo'; + +function getThemeClass() { + var h = document.documentElement; + // Bootstrap: explicit data-bs-theme attribute wins first + if (h.dataset.bsTheme === 'dark') return 'cl-theme-dark'; + if (h.dataset.bsTheme === 'light') return 'cl-theme-light'; + // Argon: explicit darkmode attribute + if (h.dataset.darkmode === 'true') return 'cl-theme-dark'; + // Argon: dark.css loaded in document = dark mode active (most reliable) + var links = document.querySelectorAll('link[rel="stylesheet"]'); + for (var i = 0; i < links.length; i++) { + if (links[i].href && links[i].href.indexOf('dark.css') !== -1) return 'cl-theme-dark'; + } + // Generic: .dark class on root element + if (h.classList.contains('dark')) return 'cl-theme-dark'; + // Body background luminance (skip transparent/rgba backgrounds) + var bg = window.getComputedStyle(document.body).backgroundColor; + if (bg && bg.indexOf('rgba') === -1 && bg.indexOf('rgb') !== -1) { + var m = bg.match(/\d+/g); + if (m && m.length >= 3 && (parseInt(m[0]) + parseInt(m[1]) + parseInt(m[2])) / 3 < 100) return 'cl-theme-dark'; + } + return 'cl-theme-light'; +} + +var callHostHints = rpc.declare({ + object: 'luci-rpc', + method: 'getHostHints', + expect: { '': {} } +}); + +var callBackupExportPrepare = rpc.declare({ object: 'luci.clashoo', method: 'backup_export_prepare', expect: {} }); +var callBackupExportCleanup = rpc.declare({ object: 'luci.clashoo', method: 'backup_export_cleanup', params: ['path'], expect: {} }); +var callBackupImportPrepare = rpc.declare({ object: 'luci.clashoo', method: 'backup_import_prepare', expect: {} }); +var callBackupImportChunk = rpc.declare({ object: 'luci.clashoo', method: 'backup_import_chunk', params: ['path', 'offset', 'data'], expect: {} }); +var callBackupImportCleanup = rpc.declare({ object: 'luci.clashoo', method: 'backup_import_cleanup', params: ['path'], expect: {} }); +var callBackupImportFile = rpc.declare({ object: 'luci.clashoo', method: 'backup_import_file', params: ['name', 'path'], expect: {} }); +var callBackupReset = rpc.declare({ object: 'luci.clashoo', method: 'backup_reset', expect: {} }); + +var CSS = [ + '.cl-wrap{font-family:-apple-system,BlinkMacSystemFont,"Segoe UI","PingFang SC",sans-serif}', + '.cl-tabs{display:flex;border-bottom:2px solid rgba(128,128,128,.15);margin-bottom:18px}', + '.cl-tab{padding:10px 20px;cursor:pointer;font-size:13px;opacity:.55;border-bottom:2px solid transparent;margin-bottom:-2px}', + '.cl-tab.active{opacity:1;border-bottom-color:currentColor;font-weight:600}', + '.cl-panel{display:none}.cl-panel.active{display:block}', + '.cl-section{margin-bottom:20px}', + '.cl-section h4{font-size:.95rem;font-weight:600;margin-bottom:10px;color:var(--title-color,rgba(92,102,120,.72));opacity:.95}', + '.cl-save-bar{display:flex;gap:8px;margin-top:14px;padding-top:12px;border-top:1px solid rgba(128,128,128,.15)}', + '.cl-actions{display:flex;gap:8px;flex-wrap:wrap;margin-top:10px}', + '.cl-log-area{font-family:monospace;font-size:11px;opacity:.75;max-height:300px;overflow-y:auto;border:1px solid rgba(128,128,128,.2);border-radius:8px;padding:10px;white-space:pre-wrap;margin-top:8px}', + '.cl-log-tabs{display:flex;gap:8px;margin-bottom:8px}', + '.cl-log-toolbar{display:flex;flex-wrap:wrap;align-items:center;gap:8px;margin-bottom:8px}', + '.cl-log-toolbar label{font-size:11px;display:inline-flex;align-items:center;gap:4px;cursor:pointer;margin:0}', + /* Argon shifts label>checkbox down (top:.4rem); reset so flex centers it */ + '.cl-log-toolbar input[type=checkbox]{position:static;top:auto;right:auto;margin:0}', + /* unify select + button heights so the row lines up */ + '.cl-log-toolbar>select,.cl-log-toolbar>button{height:26px;box-sizing:border-box;font-size:11px;line-height:1;padding:0 10px;margin:0}', + '.cl-log-tab{padding:4px 12px;border:1px solid rgba(128,128,128,.2);border-radius:20px;font-size:12px;cursor:pointer;opacity:.6}', + '.cl-log-tab.active{opacity:1;font-weight:600;background:rgba(128,128,128,.1)}', + '.cl-log-line{display:block;padding:1px 4px;border-radius:3px}', + /* Light theme: AA+ contrast on white bg (issue #16) */ + '.cl-log-line.cl-log-info{color:#1f6b3f}', + '.cl-log-line.cl-log-warn{color:#8b5a00}', + '.cl-log-line.cl-log-error{color:#c0392b;background:rgba(192,57,43,.06)}', + '.cl-log-line.cl-log-debug{color:#5a6270;opacity:.85}', + '.cl-log-line.cl-log-hidden{display:none}', + '.cl-log-ts{color:#5a6270;margin-right:8px}', + '.cl-log-msg{color:inherit}', + /* Dark theme overrides: original colors tuned for dark bg */ + '.cl-theme-dark .cl-log-line.cl-log-info{color:#7fc7a8}', + '.cl-theme-dark .cl-log-line.cl-log-warn{color:#e8b95a}', + '.cl-theme-dark .cl-log-line.cl-log-error{color:#ea7878;background:rgba(234,120,120,.06)}', + '.cl-theme-dark .cl-log-line.cl-log-debug{color:#7a8290;opacity:.7}', + '.cl-theme-dark .cl-log-ts{color:#6b7480}', + '.cl-dl-hint{margin-top:6px;font-size:12px;min-height:18px;line-height:1.4}', + '.cl-component-card{padding:16px 18px;border:1px solid var(--cl-surface-border,rgba(128,128,128,.14));border-radius:var(--border-radius,var(--cl-radius,12px));background:var(--cl-card-bg,#fff);box-shadow:var(--card-shadow,var(--cl-card-shadow));margin:0 14px 14px}', + '.cl-component-head{display:flex;align-items:flex-start;justify-content:space-between;gap:12px;margin-bottom:12px}', + '.cl-component-head h4{display:flex;align-items:center;gap:8px;margin:0 0 4px !important;padding:0 !important;font-size:0.95rem;font-weight:600;color:var(--title-color,var(--cl-title-color,inherit));background:transparent !important}', + '.cl-component-head h4:before{content:"";width:3px;height:14px;border-radius:2px;background:var(--primary-color,var(--cl-primary,#2f80ed));flex:0 0 3px}', + '.cl-component-adv{margin-top:10px}', + '.cl-component-adv-bar{display:flex;align-items:center;justify-content:space-between;padding:10px 12px;cursor:pointer;user-select:none;font-size:13px;font-weight:700;background:var(--cl-control-bg,rgba(128,128,128,.04));border:1px solid var(--cl-control-border,rgba(128,128,128,.14));border-radius:8px}', + '.cl-component-adv-bar:hover{background:var(--cl-primary-soft,rgba(0,122,255,.08))}', + '.cl-component-adv-chevron{font-size:16px;font-weight:700;opacity:.55;transition:transform .2s}', + '.cl-component-adv:not(.cl-closed) .cl-component-adv-chevron{transform:rotate(90deg)}', + '.cl-component-adv-body{margin-top:8px}', + '.cl-component-adv.cl-closed .cl-component-adv-body{display:none}', + '.cl-component-sub{font-size:12px;color:rgba(120,130,150,.9);line-height:1.45}', + '.cl-component-list{display:grid;gap:8px}', + '.cl-component-row{display:grid;grid-template-columns:minmax(170px,1.1fr) minmax(180px,1.5fr) minmax(130px,.9fr) auto;align-items:center;gap:10px;padding:10px 12px;border:1px solid var(--cl-surface-border,rgba(128,128,128,.14));border-radius:8px;background:var(--cl-card-bg,#fff)}', + '.cl-component-name{font-weight:700;font-size:13px}', + '.cl-component-desc{font-size:12px;color:rgba(120,130,150,.92);margin-top:2px}', + '.cl-component-version{font-size:12px;line-height:1.45;color:rgba(90,100,120,.95);word-break:break-word}', + '.cl-theme-dark .cl-component-version{color:rgba(210,220,235,.86)}', + '.cl-component-status{font-size:12px;line-height:1.45;color:rgba(90,100,120,.95)}', + '.cl-component-status.cl-st-running{color:#2f80ed}.cl-component-status.cl-st-success{color:#239b56}.cl-component-status.cl-st-failed{color:#d43f3a}', + '.cl-component-log{margin-top:10px;font-family:monospace;font-size:11px;white-space:pre-wrap;max-height:140px;overflow:auto;padding:9px;border:1px solid var(--cl-surface-border,rgba(128,128,128,.14));border-radius:8px;background:var(--cl-card-bg,#fff);color:#1f6b3f}', + '.cl-theme-dark .cl-component-log{color:#a3d9ad}', + '.cl-component-arch{margin-bottom:12px}', + '.cl-component-arch-row{display:flex;align-items:center;gap:10px;flex-wrap:wrap;padding:9px 12px;border:1px solid var(--cl-surface-border,rgba(128,128,128,.14));border-radius:8px;background:var(--cl-card-bg,#fff)}', + '.cl-component-arch-label{font-size:13px;font-weight:700}', + '.cl-component-arch-auto{font-size:12px;color:rgba(90,100,120,.82);line-height:1.2}', + '.cl-theme-dark .cl-component-arch-auto{color:rgba(210,220,235,.78)}', + '.cl-wrap .cl-component-arch-sel{font-size:12px!important;font-weight:700!important;padding:4px 9px!important;border:1px solid rgba(46,170,92,.28)!important;border-radius:6px!important;background:rgba(46,170,92,.12)!important;color:#24844d!important}', + '.cl-wrap.cl-theme-dark .cl-component-arch-sel{background:rgba(104,199,135,.16)!important;color:#c6f6d3!important;border-color:rgba(104,199,135,.3)!important}', + '.cl-component-arch-sel option{background:var(--background-color,#fff);color:inherit}', + '.cl-component-arch-hint{font-size:12px;color:rgba(120,130,150,.9)}', + '.cl-comp-var-box{display:inline-flex;gap:4px;margin-top:5px}', + '.cl-comp-var{font-size:11px;padding:2px 10px;border-radius:10px;border:1px solid rgba(128,128,128,.3);background:transparent;color:inherit;cursor:pointer;min-width:52px}', + '.cl-comp-var.on{background:rgba(var(--primary-rgb,0,122,255),.18);border-color:rgba(var(--primary-rgb,0,122,255),.64);color:var(--primary-color,#0b68dd);font-weight:800;box-shadow:0 0 0 1px rgba(var(--primary-rgb,0,122,255),.1) inset}', + '.cl-comp-updatable{font-size:10px;font-weight:700;color:#239b56;margin-left:2px}', + '@media(max-width:760px){.cl-component-head{display:block}.cl-component-head .btn{margin-top:10px}.cl-component-row{grid-template-columns:1fr;gap:6px}.cl-component-row .btn{width:auto;justify-self:start;padding-left:18px;padding-right:18px}}', + /* align form.Map font with config page */ + '.cl-panel .cbi-section>h3{font-size:13px !important;font-weight:600;margin-bottom:8px}', + '.cl-panel .cbi-value-title{font-size:13px !important}', + '.cl-panel .cbi-value-field input,.cl-panel .cbi-value-field select,.cl-panel .cbi-value-field textarea{font-size:13px !important}', + '.cl-panel .cbi-section-descr,.cl-panel .cbi-value-helptext{font-size:12px !important}', + '.cl-panel .cbi-section{margin-bottom:12px}', + '.cl-wrap .cbi-section>h3,.cl-wrap .cbi-value-title,.cl-wrap .cbi-section-descr,.cl-wrap .cbi-value-helptext{font-family:-apple-system,BlinkMacSystemFont,"Segoe UI","PingFang SC",sans-serif !important}', + '.cl-wrap .cbi-input-text,.cl-wrap .cbi-input-select,.cl-wrap select,.cl-wrap input,.cl-wrap textarea,.cl-wrap .btn,.cl-wrap .cbi-button{font-size:13px !important;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI","PingFang SC",sans-serif !important}', + '.cl-wrap .btn,.cl-wrap .cbi-button{padding:4px 10px;line-height:1.35}', + '#cbi-clashoo-lan_acl{overflow-x:visible!important}', + '#cbi-clashoo-lan_acl .cbi-section-table{display:flex;width:100%;overflow:visible!important;flex-direction:column;border:0!important}', + '#cbi-clashoo-lan_acl .cbi-section-thead{display:none}', + '#cbi-clashoo-lan_acl .cbi-section-tbody{display:flex;width:100%;flex-direction:column}', + '#cbi-clashoo-lan_acl .cbi-section-table-row{display:flex;width:100%;padding:14px 0;border-top:1px solid rgba(128,128,128,.16);flex-direction:column;align-items:stretch}', + '#cbi-clashoo-lan_acl .cbi-section-table-row:first-child{border-top:0}', + '#cbi-clashoo-lan_acl .cl-acl-empty-row,#cbi-clashoo-lan_acl .cl-acl-empty-row>*{border:0!important;box-shadow:none!important}', + '#cbi-clashoo-lan_acl .cl-acl-value{width:100%;border:0!important;box-sizing:border-box}', + '#cbi-clashoo-lan_acl .cl-acl-value .cbi-dropdown[open]>ul.dropdown{width:max-content;min-width:100%;max-width:calc(100vw - 48px)}', + '@media(max-width:600px){#cbi-clashoo-lan_acl .cl-acl-value .cbi-dropdown[open]>ul.dropdown{width:100%!important;min-width:0;max-width:100%}#cbi-clashoo-lan_acl .cl-acl-value .cbi-dropdown[open]>ul.dropdown>li{height:auto;white-space:normal;overflow-wrap:anywhere;line-height:1.35}}', + '#cbi-clashoo-lan_acl .cbi-section-actions{display:flex!important;justify-content:flex-end;width:auto!important;padding:8px 0 0!important;border:0!important}', + '#cbi-clashoo-lan_acl .cbi-section-actions>div{display:flex;gap:8px}', + '#cbi-clashoo-lan_acl .cbi-section-create{padding-top:10px}' +].join(''); + +/* component update: main area = clashoo/client only; rest in collapsible */ +var COMPONENT_MAIN_IDS = { clashoo: true, luci: true }; + +function fastResolve(promise, timeoutMs, fallback) { + var t = new Promise(function (resolve) { + setTimeout(function () { resolve(fallback); }, timeoutMs); + }); + return Promise.race([L.resolveDefault(promise, fallback), t]); +} + +function decorateSystemForm(root) { + if (!root || !root.querySelectorAll) + return; + + var fields = root.querySelectorAll('.cbi-value-field'); + for (var i = 0; i < fields.length; i++) { + if (fields[i] && fields[i].classList) + fields[i].classList.add('cl-control-wrap'); + } + + var sections = root.querySelectorAll('.cbi-section'); + for (var j = 0; j < sections.length; j++) { + if (sections[j] && sections[j].classList) + sections[j].classList.add('cl-form-card'); + } +} + +function normalizeLanAclLayout(root) { + var rows = root.querySelectorAll('#cbi-clashoo-lan_acl .cbi-section-table-row'); + for (var r = 0; r < rows.length; r++) { + if (!rows[r].querySelector('input, select, button, .cbi-dropdown')) + rows[r].classList.add('cl-acl-empty-row'); + } + + var cells = root.querySelectorAll('#cbi-clashoo-lan_acl .cbi-section-table-row > td.cbi-value-field:not(.cl-acl-value)'); + for (var i = 0; i < cells.length; i++) { + var cell = cells[i]; + var control = cell.firstElementChild; + if (!control) + continue; + + cell.parentElement.classList.add('cbi-section-node', 'cl-acl-node'); + + var field = document.createElement('div'); + field.className = 'cbi-value-field'; + field.appendChild(control); + + var label = document.createElement('label'); + label.className = 'cbi-value-title'; + label.textContent = cell.getAttribute('data-title') || ''; + + cell.textContent = ''; + cell.className = 'cbi-value cl-acl-value'; + cell.appendChild(label); + cell.appendChild(field); + } +} + +function syncLanAclControlWidth(root) { + var reference = root.querySelector('#cbi-clashoo-config-bypass_port_mode select'); + if (!reference) + return; + + var referenceWidth = reference.getBoundingClientRect().width; + if (!referenceWidth) + return; + + var section = root.querySelector('#cbi-clashoo-lan_acl'); + var sectionRect = section.getBoundingClientRect(); + var sectionStyle = window.getComputedStyle(section); + var contentRight = sectionRect.right - parseFloat(sectionStyle.paddingRight || 0); + var lists = root.querySelectorAll('#cbi-clashoo-lan_acl .cbi-dynlist'); + for (var i = 0; i < lists.length; i++) { + var left = lists[i].getBoundingClientRect().left; + var width = Math.min(referenceWidth, contentRight - left); + lists[i].style.width = Math.max(0, width) + 'px'; + lists[i].style.minWidth = '0'; + lists[i].style.maxWidth = 'none'; + + var controls = lists[i].querySelectorAll('.add-item, .cbi-dropdown'); + for (var j = 0; j < controls.length; j++) { + controls[j].style.width = '100%'; + controls[j].style.minWidth = '0'; + controls[j].style.maxWidth = '100%'; + controls[j].style.boxSizing = 'border-box'; + } + } +} + +function watchLanAclLayout(root) { + normalizeLanAclLayout(root); + syncLanAclControlWidth(root); + var observer = new MutationObserver(function () { + normalizeLanAclLayout(root); + syncLanAclControlWidth(root); + }); + observer.observe(root, { childList: true, subtree: true }); + window.addEventListener('resize', function () { + syncLanAclControlWidth(root); + }); +} + +function randomSecret(len) { + var chars = 'ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz23456789'; + var out = ''; + var n = Math.max(6, parseInt(len, 10) || 6); + for (var i = 0; i < n; i++) { + out += chars.charAt(Math.floor(Math.random() * chars.length)); + } + return out; +} + +function enhanceDashPasswordField(root) { + if (!root || !root.querySelector) + return; + + var input = root.querySelector('input[id$=".dash_pass"], input[name$=".dash_pass"]'); + if (!input || input.dataset.clEnhanced === '1') + return; + + input.dataset.clEnhanced = '1'; + input.type = 'password'; + input.autocomplete = 'new-password'; + + var parent = input.parentNode; + if (!parent) + return; + + /* Remove LuCI default password helper controls (e.g. stray "*" button) */ + var children = parent.children ? Array.prototype.slice.call(parent.children) : []; + children.forEach(function (el) { + if (!el || el === input) + return; + var tag = (el.tagName || '').toUpperCase(); + var isBtnLike = tag === 'BUTTON' + || (tag === 'INPUT' && String(el.type || '').toLowerCase() === 'button') + || ((el.className || '').indexOf('cbi-button') >= 0); + if (isBtnLike) + parent.removeChild(el); + }); + + var wrap = E('div', { 'class': 'cl-pass-wrap' }); + parent.insertBefore(wrap, input); + wrap.appendChild(input); + + var eyeBtn = E('button', { + type: 'button', + 'class': 'btn cbi-button cl-pass-btn', + title: _("Show/Hide"), + click: function (ev) { + ev.preventDefault(); + var show = input.type === 'password'; + input.type = show ? 'text' : 'password'; + eyeBtn.textContent = show ? '🙈' : '👁'; + } + }, '👁'); + + var genBtn = E('button', { + type: 'button', + 'class': 'btn cbi-button-action cl-pass-btn cl-pass-gen', + click: function (ev) { + ev.preventDefault(); + input.type = 'text'; + input.value = randomSecret(6); + eyeBtn.textContent = '🙈'; + input.dispatchEvent(new Event('change', { bubbles: true })); + } + }, _("Random")); + + wrap.appendChild(eyeBtn); + wrap.appendChild(genBtn); +} + +function clearClashooDirty() { + var applyPromise; + try { + applyPromise = (L.uci && typeof L.uci.callApply === 'function') + ? Promise.resolve(L.uci.callApply(0, false)).catch(function () {}) + : Promise.resolve(); + } catch (e) { applyPromise = Promise.resolve(); } + return applyPromise.then(function () { + try { + if (L.ui && L.ui.changes && L.ui.changes.changes) { + delete L.ui.changes.changes.clashoo; + var n = Object.keys(L.ui.changes.changes).length; + if (typeof L.ui.changes.renderChangeIndicator === 'function') + L.ui.changes.renderChangeIndicator(n); + else if (typeof L.ui.changes.setIndicator === 'function') + L.ui.changes.setIndicator(n); + } + } catch (e) {} + }); +} + +function saveCommitApplyMaybeReload(m, runningMsg, stoppedMsg) { + return clashoo.status() + .then(function (st) { return !!(st && st.running); }) + .catch(function () { return false; }) + .then(function (running) { + return m.save() + .then(function () { return clashoo.commitConfig(); }) + .then(function () { + return running ? clashoo.reload() : { success: true, skipped: true }; + }) + .then(function () { return clearClashooDirty(); }) + .then(function () { + ui.addNotification(null, E('p', running ? runningMsg : stoppedMsg)); + window.setTimeout(function () { location.reload(); }, 300); + }); + }); +} + +function coreChoiceFromConfig(coreType, dcore) { + if (coreType === 'singbox') + return dcore === '5' ? 'singbox-alpha' : 'singbox-stable'; + if (dcore === '1') return 'smart'; + if (dcore === '3') return 'mihomo-alpha'; + return 'mihomo-stable'; +} + +function coreChoiceTarget(choice) { + var targets = { + 'mihomo-stable': { core: 'mihomo', dcore: '2' }, + 'mihomo-alpha': { core: 'mihomo', dcore: '3' }, + 'smart': { core: 'mihomo', dcore: '1' }, + 'singbox-stable': { core: 'singbox', dcore: '4' }, + 'singbox-alpha': { core: 'singbox', dcore: '5' } + }; + return targets[choice] || targets['mihomo-stable']; +} + +function waitForCoreTarget(target, attempts, sawRestart) { + attempts = attempts == null ? 50 : attempts; + sawRestart = !!sawRestart; + return clashoo.status().then(function (st) { + st = st || {}; + var selected = st.core_type === target.core && String(st.dcore || '') === target.dcore; + var transitioning = !st.running || st.health_status === 'stopped' || st.health_status === 'starting'; + sawRestart = sawRestart || transitioning; + if (sawRestart && selected && st.running && st.health_status !== 'stopped' && st.health_status !== 'fail') + return st; + if (selected && st.health_status === 'fail') + throw new Error(_("The new core failed to start, please check the core log")); + if (attempts <= 0) + throw new Error(_("Timeout waiting for new core to start, please check the core log")); + return new Promise(function (resolve) { + setTimeout(resolve, 600); + }).then(function () { return waitForCoreTarget(target, attempts - 1, sawRestart); }); + }); +} + +// tab persistence (hash + localStorage), shared shape with config.js so save/apply +// reloads keep the active tab instead of snapping back to the first one +function readSavedTab(key, fallback, allowed) { + var raw = ''; + if (window.location.hash) + raw = window.location.hash.replace(/^#/, ''); + if (!raw) { + try { raw = window.localStorage.getItem(key) || ''; } catch (e) {} + } + return allowed.indexOf(raw) >= 0 ? raw : fallback; +} + +function rememberTab(key, id) { + try { window.localStorage.setItem(key, id); } catch (e) {} + if (window.history && window.history.replaceState) + window.history.replaceState(null, '', '#' + id); + else + window.location.hash = id; +} + +function readBackupSliceBase64(file, start, end) { + return new Promise(function (resolve, reject) { + var reader = new FileReader(); + reader.onload = function () { + var result = String(reader.result || ''); + var comma = result.indexOf(','); + if (comma < 0) + reject(new Error(_("Unable to read backup file"))); + else + resolve(result.substring(comma + 1)); + }; + reader.onerror = function () { + reject(reader.error || new Error(_("Unable to read backup file"))); + }; + reader.readAsDataURL(file.slice(start, end)); + }); +} + +function uploadBackupChunks(file, path) { + var offset = 0; + var chunkSize = 32 * 1024; + + function next() { + if (offset >= file.size) + return Promise.resolve(); + var end = Math.min(offset + chunkSize, file.size); + var expected = end; + return readBackupSliceBase64(file, offset, end) + .then(function (data) { return callBackupImportChunk(path, offset, data); }) + .then(function (r) { + if (!r || !r.success) + throw new Error((r && r.message) || _("Upload failed")); + if (parseInt(r.offset, 10) !== expected) + throw new Error(_("Upload offset mismatch")); + offset = expected; + return next(); + }); + } + + return next(); +} + +return view.extend({ + _tab: 'kernel', + _logTab: 'plugin', + + load: function () { + return Promise.all([ + fastResolve(clashoo.getCpuArch(), 5000, ''), + fastResolve(clashoo.getLogStatus(), 1200, {}), + fastResolve(clashoo.readLog(), 1200, ''), + uci.load('clashoo'), + fastResolve(L.resolveDefault(callHostHints(), {}), 1500, {}) + ]); + }, + + render: function (data) { + var self = this; + var cpuArch = data[0] || ''; + var logStatus = data[1] || {}; + var runLog = data[2] || ''; + var hostHints = data[4] || {}; + this._hostHints = hostHints; + + if (!document.getElementById('cl-css')) { + var s = document.createElement('style'); + s.id = 'cl-css'; s.textContent = CSS; + document.head.appendChild(s); + } + if (!document.getElementById('cl-css-ext')) { + var link = document.createElement('link'); + link.id = 'cl-css-ext'; + link.rel = 'stylesheet'; + link.href = L.resource('view/clashoo/clashoo.css') + '?v=20260806a1'; + document.head.appendChild(link); + } else { + document.getElementById('cl-css-ext').href = L.resource('view/clashoo/clashoo.css') + '?v=20260806a1'; + } + + // restore last-viewed tab so save/apply reloads stay put instead of jumping to kernel + this._tab = readSavedTab('clashoo.system.tab', this._tab || 'kernel', ['kernel', 'rules', 'logs']); + rememberTab('clashoo.system.tab', this._tab); + var tabs = [ + { id: 'kernel', label: _("Core and Data") }, + { id: 'rules', label: _("Rules and Control") }, + { id: 'logs', label: _("Log") } + ]; + var tabEls = {}, panelEls = {}; + + var tabBar = E('div', { 'class': 'cl-tabs' }, + tabs.map(function (t) { + var el = E('div', { + 'class': 'cl-tab' + (self._tab === t.id ? ' active' : ''), + click: function () { + Object.keys(tabEls).forEach(function (k) { + tabEls[k].className = 'cl-tab' + (k === t.id ? ' active' : ''); + panelEls[k].className = 'cl-panel' + (k === t.id ? ' active' : ''); + }); + self._tab = t.id; + rememberTab('clashoo.system.tab', t.id); + } + }, t.label); + tabEls[t.id] = el; + return el; + }) + ); + + var kernelPanel = E('div', { 'class': 'cl-panel' + (this._tab === 'kernel' ? ' active' : ''), id: 'cl-panel-kernel' }); + panelEls['kernel'] = kernelPanel; + this._buildComponentUpdatePanel(kernelPanel, cpuArch); + this._buildBackupPanel(kernelPanel); + this._buildKernelPanel(kernelPanel, cpuArch); + + var rulesPanel = E('div', { 'class': 'cl-panel' + (this._tab === 'rules' ? ' active' : ''), id: 'cl-panel-rules' }); + panelEls['rules'] = rulesPanel; + this._buildRulesForm(rulesPanel); + + var logsPanel = E('div', { 'class': 'cl-panel' + (this._tab === 'logs' ? ' active' : ''), id: 'cl-panel-logs' }, + this._buildLogsPanel(runLog) + ); + panelEls['logs'] = logsPanel; + + this._tabEls = tabEls; + this._panelEls = panelEls; + poll.add(L.bind(this._pollLogs, this), 8); + + return E('div', { 'class': 'cl-wrap clashoo-container cl-system-page cl-form-page ' + getThemeClass() }, [tabBar, kernelPanel, rulesPanel, logsPanel]); + }, + + _detectMihomoArch: function (raw) { + if (!raw) return ''; + if (raw === 'x86_64') return 'amd64-compatible'; + if (/^aarch64/.test(raw)) return 'arm64'; + if (/^armv7|^arm_cortex-a[7-9]|^arm_cortex-a1[0-9]/.test(raw)) return 'armv7'; + if (/^armv6|^arm_cortex-a[56]/.test(raw)) return 'armv6'; + if (/^arm/.test(raw)) return 'armv5'; + if (/^i[3-6]86/.test(raw)) return '386'; + if (/^mips64el/.test(raw)) return 'mips64le'; + if (/^mips64/.test(raw)) return 'mips64'; + if (/^mipsel/.test(raw)) return 'mipsle'; + if (/^mips/.test(raw)) return 'mips'; + return ''; + }, + + _buildComponentUpdatePanel: function (container, cpuArch) { + var self = this; + this._compCpuArch = cpuArch || ''; + this._compVariant = this._compVariant || {}; + this._compLatest = this._compLatest || {}; + var listEl = E('div', { 'class': 'cl-component-list' }); + var advListEl = E('div', { 'class': 'cl-component-list' }); + this._compAdvListEl = advListEl; + var logEl = E('div', { 'class': 'cl-component-log', style: 'display:none' }, ''); + this._compLogEl = logEl; + var archWrap = E('div', { 'class': 'cl-component-arch' }); + this._compArchWrap = archWrap; + var refreshBtn = E('button', { + 'class': 'btn cbi-button cbi-button-neutral', + click: function (ev) { + ev.preventDefault(); + refreshBtn.disabled = true; + refreshBtn.textContent = _("Checking…"); + self._refreshComponentUpdatePanel(listEl, logEl, true); + } + }, _("Check Updates")); + this._compRefreshBtn = refreshBtn; + + /* advanced: core/data, collapsed by default to keep page compact. + CPU arch stays outside — it decides core binary arch */ + var advWrap = E('div', { 'class': 'cl-component-adv cl-closed' }, [ + E('div', { 'class': 'cl-component-adv-bar' }, [ + E('span', {}, _("Advanced Settings (core / data components)")), + E('span', { 'class': 'cl-component-adv-chevron' }, '›') + ]), + E('div', { 'class': 'cl-component-adv-body' }, [advListEl]) + ]); + advWrap.firstChild.addEventListener('click', function () { + advWrap.classList.toggle('cl-closed'); + }); + + /* wrap in cl-component-map, reuse LuCI .cbi-map container + 浅色出现灰托盘、暗色满宽对齐,与下方表单卡片同构 */ + container.appendChild(E('div', { 'class': 'cl-component-map' }, [ + E('div', { 'class': 'cl-component-card' }, [ + E('div', { 'class': 'cl-component-head' }, [ + E('div', {}, [ + E('h4', {}, _("Component Updates")), + E('div', { 'class': 'cl-component-sub' }, _("Update components individually. Click Check Updates to refresh versions.")) + ]), + refreshBtn + ]), + archWrap, + listEl, + advWrap, + logEl + ]) + ])); + + this._refreshComponentUpdatePanel(listEl, logEl, false); + }, + + /* 备份与还原:折腾内核/配置前的兜底。导出当前配置为压缩包,避免 RPC 大包限制; + 还原默认配置则把 UCI 设置重置为出厂值(订阅/配置文件保留)。仅含配置,不含内核。 */ + _buildBackupPanel: function (container) { + var exportBtn = E('button', { 'class': 'btn cbi-button cbi-button-neutral' }, _("Export Backup")); + exportBtn.addEventListener('click', function (ev) { + ev.preventDefault(); + exportBtn.disabled = true; + var orig = exportBtn.textContent; + exportBtn.textContent = _("Exporting…"); + var done = function () { exportBtn.disabled = false; exportBtn.textContent = orig; }; + var exportPath = ''; + callBackupExportPrepare().then(function (r) { + if (!r || !r.success) { + throw new Error((r && r.message) || _("Unknown error")); + } + exportPath = r.path; + return fs.read_direct(r.path, 'blob').then(function (blob) { + return { blob: blob, filename: r.filename || 'clashoo-backup.tar.gz' }; + }); + }).then(function (download) { + var url = URL.createObjectURL(download.blob); + var a = E('a', { href: url, download: download.filename }); + document.body.appendChild(a); + a.click(); + document.body.removeChild(a); + setTimeout(function () { URL.revokeObjectURL(url); }, 1000); + clashoo.toast(_("Backup exported"), { kind: 'ok' }); + }).catch(function (e) { + clashoo.toast(_("Export failed: ") + (e.message || e), { kind: 'err' }); + }).finally(function () { + done(); + if (exportPath) + callBackupExportCleanup(exportPath).catch(function () {}); + }); + }); + + var importInput = E('input', { type: 'file', accept: '.tar.gz,.json', style: 'display:none' }); + var importBtn = E('button', { 'class': 'btn cbi-button cbi-button-neutral' }, _("Import Restore")); + importBtn.addEventListener('click', function (ev) { + ev.preventDefault(); + importInput.value = ''; + importInput.click(); + }); + importInput.addEventListener('change', function () { + var file = importInput.files && importInput.files[0]; + if (!file) + return; + var lower = String(file.name || '').toLowerCase(); + var maxSize = /\.json$/.test(lower) ? 8 * 1024 * 1024 + : /\.tar\.gz$/.test(lower) ? 32 * 1024 * 1024 : 0; + if (!maxSize) { + clashoo.toast(_("Import failed: ") + _("Only .tar.gz and legacy .json backup files are supported"), { kind: 'err' }); + importInput.value = ''; + return; + } + if (file.size > maxSize) { + clashoo.toast(_("Import failed: ") + _("Backup file is too large"), { kind: 'err' }); + importInput.value = ''; + return; + } + if (!confirm(_("Importing will overwrite all current configuration and settings with the backup. Existing subscriptions/configuration files will be replaced. Continue?"))) { + importInput.value = ''; + return; + } + importBtn.disabled = true; + var uploadPath = ''; + callBackupImportPrepare().then(function (r) { + if (!r || !r.success) + throw new Error((r && r.message) || _("Unknown error")); + uploadPath = r.path; + return uploadBackupChunks(file, uploadPath); + }).then(function () { + return callBackupImportFile(file.name, uploadPath); + }).then(function (r) { + if (r && r.success) + clashoo.toast(r.message || _("Backup restored, restarting service"), { kind: 'ok' }); + else + throw new Error((r && r.message) || _("Unknown error")); + }).catch(function (err) { + clashoo.toast(_("Import failed: ") + (err.message || err), { kind: 'err' }); + }).finally(function () { + if (uploadPath) + callBackupImportCleanup(uploadPath).catch(function () {}); + importBtn.disabled = false; + importInput.value = ''; + }); + }); + + var resetBtn = E('button', { 'class': 'btn cbi-button cbi-button-negative' }, _("Restore Defaults")); + resetBtn.addEventListener('click', function (ev) { + ev.preventDefault(); + if (!confirm(_("Restore Clashoo settings to factory defaults (subscriptions and configuration files are kept). Continue?"))) + return; + resetBtn.disabled = true; + var orig = resetBtn.textContent; + resetBtn.textContent = _("Restoring…"); + var done = function () { resetBtn.disabled = false; resetBtn.textContent = orig; }; + callBackupReset().then(function (r) { + done(); + if (r && r.success) + clashoo.toast(r.message || _("Factory defaults restored"), { kind: 'ok' }); + else + clashoo.toast(_("Restore failed: ") + ((r && r.message) || _("Unknown error")), { kind: 'err' }); + }).catch(function (e) { + done(); + clashoo.toast(_("Restore failed: ") + (e.message || e), { kind: 'err' }); + }); + }); + + container.appendChild(E('div', { 'class': 'cl-component-map' }, [ + E('div', { 'class': 'cl-component-card' }, [ + E('div', { 'class': 'cl-component-head' }, [ + E('div', {}, [ + E('h4', {}, _("Backup and Restore")), + E('div', { 'class': 'cl-component-sub' }, [ + _("Export a backup before changing cores or configuration, so it can be restored if needed. Includes configuration and settings only, not cores."), + E('br'), + E('strong', {}, _("Backup files contain subscription and node credentials. Store them securely.")) + ]) + ]) + ]), + importInput, + E('div', { 'class': 'cl-backup-actions' }, [exportBtn, importBtn, resetBtn]) + ]) + ])); + }, + + _replaceChildren: function (node, children) { + while (node.firstChild) + node.removeChild(node.firstChild); + children.forEach(function (child) { if (child) node.appendChild(child); }); + }, + + /* latest map key: mihomo/sing-box with variant; smart fixed; pkg by id */ + _compLatestKey: function (comp, variant) { + if (comp.id === 'smart') return 'smart'; + if (comp.variant) return comp.id + '_' + (variant || 'stable'); + return comp.id; + }, + + _compNorm: function (s) { + return String(s || '').toLowerCase().replace(/^v/, '').replace(/~/g, '.'); + }, + + _compVariantOf: function (comp) { + if (!comp.variant) return ''; + if (this._compVariant[comp.id]) return this._compVariant[comp.id]; + var inst = String(comp.installed_version || '').toLowerCase(); + return /(?:alpha|beta|rc|pre)/.test(inst) ? 'alpha' : 'stable'; + }, + + _compInstalledVersion: function (comp, variant) { + if (comp && comp.installed_versions && comp.installed_versions[variant]) + return comp.installed_versions[variant]; + if (comp && comp.variant) + return ''; + return (comp && comp.installed_version) || ''; + }, + + /* install != latest = updatable (alpha compared by hash)*/ + _compUpdatable: function (comp, latestMap) { + if (!comp) return false; + /* lgbm has no version; compare local vs remote model sha256 (kind=data skips generic path) */ + if (comp.id === 'lgbm') { + var rem = latestMap.lgbm, ins = comp.installed_version; + return !!(rem && ins && this._compNorm(rem) !== this._compNorm(ins)); + } + if (comp.kind === 'data') return false; + var variant = this._compVariantOf(comp); + var inst = this._compInstalledVersion(comp, variant); + if (!inst || inst === _("Not installed") || inst === _("Unknown")) return false; + var latest = latestMap[this._compLatestKey(comp, variant)]; + if (!latest) return false; + return this._compNorm(latest) !== this._compNorm(inst); + }, + + _componentStatusText: function (comp, globalRunning) { + if (comp.status === 'running') + return comp.message || _("Updating"); + if (comp.status === 'success') + return comp.message || _("Completed"); + if (comp.status === 'failed') + return comp.message || _("Failed"); + if (globalRunning) + return _("Wait for the current task to complete"); + return ''; + }, + + /* CPU arch: auto-detected + manual override (download_core UCI)*/ + _renderComponentArchRow: function (arch) { + var self = this; + arch = arch || {}; + var sys = arch.system || _("Unknown"); + var detected = this._detectMihomoArch(this._compCpuArch || sys) || ''; + var cur = arch.download_core || detected || ''; + var archList = ['amd64-compatible', 'amd64-v1', 'amd64-v2', 'amd64-v3', 'arm64', 'armv7', 'armv6', 'armv5', '386', 'mips', 'mipsle', 'mips64', 'mips64le']; + var opts = archList.map(function (a) { + return E('option', { value: a, selected: a === cur ? '' : null }, a); + }); + if (!cur) + opts.unshift(E('option', { value: '', selected: '' }, _("Not detected, please select"))); + var sel = E('select', { 'class': 'cl-component-arch-sel' }, opts); + sel.addEventListener('change', function () { + uci.set('clashoo', 'config', 'download_core', sel.value); + uci.save() + .then(function () { return clashoo.commitConfig(); }) + .then(function () { return clearClashooDirty(); }) + .then(function () { clashoo.toast(_("CPU architecture set to ") + sel.value, { kind: 'info' }); }) + .catch(function () {}); + /* re-render row: show hint when mismatched */ + if (self._compArchWrap) + self._replaceChildren(self._compArchWrap, + [self._renderComponentArchRow({ system: sys, download_core: sel.value })]); + }); + var row = [ + E('span', { 'class': 'cl-component-arch-label' }, _("CPU Architecture")), + E('span', { 'class': 'cl-component-arch-auto' }, _("Auto-detected")), + sel + ]; + /* no hint when auto-detected matches; only show when manual choice differs */ + if (detected && cur !== detected) + row.push(E('span', { 'class': 'cl-component-arch-hint' }, _("Recommended ") + detected + _(" (auto-detected by device)"))); + else if (!detected && !cur) + row.push(E('span', { 'class': 'cl-component-arch-hint' }, _("Could not detect the device architecture; select it manually before updating the core."))); + return E('div', { 'class': 'cl-component-arch-row' }, row); + }, + + _renderComponentRow: function (comp, globalRunning, latestMap, listEl, logEl) { + var self = this; + var statusText = this._componentStatusText(comp, globalRunning); + var inst = comp.installed_version || ''; + var instStable = !/(?:alpha|beta|rc|pre)/i.test(inst); + + /* mihomo / sing-box:行内稳定 / Alpha 切换 */ + var variant = ''; + var variantBox = null; + if (comp.variant) { + if (!self._compVariant[comp.id]) + self._compVariant[comp.id] = instStable ? 'stable' : 'alpha'; + variant = self._compVariant[comp.id]; + var mkV = function (v, label) { + var active = variant === v; + var b = E('button', { 'class': 'cl-comp-var' + (active ? ' on' : '') }, (active ? '✓ ' : '') + label); + b.addEventListener('click', function (ev) { + ev.preventDefault(); + self._compVariant[comp.id] = v; + self._refreshComponentUpdatePanel(listEl, logEl, false); + }); + return b; + }; + variantBox = E('div', { 'class': 'cl-comp-var-box' }, [mkV('stable', _("Stable")), mkV('alpha', 'Alpha')]); + inst = this._compInstalledVersion(comp, variant) || _("Not installed"); + } + var latest = latestMap[this._compLatestKey(comp, variant || this._compVariantOf(comp))]; + if (!statusText && latest) + statusText = _("Remote: %s").replace('%s', latest); + + /* 绿色「可更新」徽标:最新版与已装不一致时显示 */ + var badge = this._compUpdatable(comp, latestMap) + ? E('span', { 'class': 'cl-comp-updatable' }, _("Update available")) + : null; + + var btn = E('button', { + 'class': 'btn cbi-button cbi-button-apply', + disabled: globalRunning ? 'disabled' : null, + click: function (ev) { + ev.preventDefault(); + btn.disabled = true; + btn.textContent = _("Submitting"); + if (self._compLogEl) self._compLogEl.style.display = ''; + clashoo.componentUpdate(comp.id, variant).then(function (res) { + if (res && res.success) + clashoo.toast(_("Component update task submitted"), { kind: 'info' }); + else + clashoo.toast((res && res.message) || _("Failed to submit component update task"), { kind: 'error' }); + setTimeout(function () { self._refreshComponentUpdatePanel(listEl, logEl, false); }, 700); + }); + } + }, comp.status === 'running' ? _("Updating") : _("Update")); + + var verChildren = [E('span', {}, _("Current: %s").replace('%s', inst || _("Unknown")) + ' ')]; + if (badge) verChildren.push(badge); + var verBlock = [E('div', {}, verChildren)]; + if (variantBox) verBlock.push(variantBox); + + return E('div', { 'class': 'cl-component-row' }, [ + E('div', {}, [ + E('div', { 'class': 'cl-component-name' }, comp.name || comp.id), + E('div', { 'class': 'cl-component-desc' }, comp.description || '') + ]), + E('div', { 'class': 'cl-component-version' }, verBlock), + E('div', { 'class': 'cl-component-status cl-st-' + (comp.status || 'idle') }, statusText), + btn + ]); + }, + + _refreshComponentUpdatePanel: function (listEl, logEl, doCheck) { + var self = this; + if (this._componentPollTimer) { + clearTimeout(this._componentPollTimer); + this._componentPollTimer = null; + } + + clashoo.componentStatus().then(function (data) { + var comps = data.components || []; + if (self._compArchWrap) + self._replaceChildren(self._compArchWrap, [self._renderComponentArchRow(data.arch)]); + + var paint = function () { + var mainComps = [], advComps = []; + comps.forEach(function (comp) { + (COMPONENT_MAIN_IDS[comp.id] ? mainComps : advComps).push(comp); + }); + var render = function (comp) { + return self._renderComponentRow(comp, !!data.running, self._compLatest || {}, listEl, logEl); + }; + self._replaceChildren(listEl, mainComps.map(render)); + if (self._compAdvListEl) + self._replaceChildren(self._compAdvListEl, advComps.map(render)); + }; + paint(); + logEl.textContent = data.log || data.last_log || _("No component update logs yet"); + + if (data.running) { + /* 有任务运行:展开日志,取消收起计时 */ + if (self._compLogHideTimer) { + clearTimeout(self._compLogHideTimer); + self._compLogHideTimer = null; + } + logEl.style.display = ''; + self._componentPollTimer = setTimeout(function () { + self._refreshComponentUpdatePanel(listEl, logEl, false); + }, 2000); + } else { + /* 任务结束:日志若展开着,8 秒后自动收起 */ + if (logEl.style.display !== 'none' && !self._compLogHideTimer) { + self._compLogHideTimer = setTimeout(function () { + logEl.style.display = 'none'; + self._compLogHideTimer = null; + }, 8000); + } + if (doCheck) { + clashoo.componentCheckUpdates().then(function (r) { + self._compLatest = (r && r.latest) || {}; + paint(); + var n = comps.reduce(function (acc, c) { + return acc + (self._compUpdatable(c, self._compLatest) ? 1 : 0); + }, 0); + if (self._compRefreshBtn) { + self._compRefreshBtn.disabled = false; + self._compRefreshBtn.textContent = _("Check Updates"); + } + clashoo.toast(n > 0 ? _("%d updates available").replace('%d', String(n)) : _("All components are up to date"), + { kind: n > 0 ? 'info' : 'success' }); + }).catch(function () { + if (self._compRefreshBtn) { + self._compRefreshBtn.disabled = false; + self._compRefreshBtn.textContent = _("Check Updates"); + } + clashoo.toast(_("Failed to check updates, please check the network"), { kind: 'error' }); + }); + } + } + }); + }, + + _buildKernelPanel: function (container, cpuArch) { + var self = this; + var detectedArch = this._detectMihomoArch(cpuArch); + var m = new form.Map('clashoo', '', ''); + var s, o; + var originalCoreChoice = coreChoiceFromConfig( + uci.get('clashoo', 'config', 'core_type') || 'mihomo', + uci.get('clashoo', 'config', 'dcore') || '2' + ); + var selectedCoreChoice = originalCoreChoice; + + s = m.section(form.NamedSection, 'config', 'clashoo', _("Backend Core")); + s.addremove = false; + o = s.option(form.ListValue, '_core_choice', _("Core Type")); + o.value('mihomo-stable', _("mihomo Stable")); + o.value('mihomo-alpha', 'mihomo Alpha'); + o.value('smart', 'Smart'); + o.value('singbox-stable', _("sing-box Stable")); + o.value('singbox-alpha', 'sing-box Alpha'); + o.cfgvalue = function () { return originalCoreChoice; }; + o.write = function (sectionId, value) { selectedCoreChoice = value; }; + o.remove = function () {}; + o.description = ''; + var coreChoiceOption = o; + + s = m.section(form.NamedSection, 'config', 'clashoo', _("Dashboard Settings")); + s.addremove = false; + o = s.option(form.Value, 'dash_port', _("Dashboard Port")); + o.placeholder = '9090'; + o = s.option(form.Value, 'dash_pass', _("Access Secret")); + o.placeholder = 'clashoo'; + o = s.option(form.ListValue, 'dashboard_panel', _("Panel UI")); + ['metacubexd','yacd','zashboard','razord'].forEach(function(p){ o.value(p,p); }); + + s = m.section(form.NamedSection, 'config', 'clashoo', _("Core Download")); + s.addremove = false; + o = s.option(form.Value, 'core_mirror_prefix', _("GitHub acceleration prefix")); + o.placeholder = 'https://gh-proxy.com/'; + o.description = _("When downloading core/data components, this prefix will be used first (a slash is required at the end). Leave blank to use the built-in gh-proxy.com and ghfast.top alternative sources."); + o.rmempty = true; + + m.render().then(function (node) { + decorateSystemForm(node); + enhanceDashPasswordField(node); + container.appendChild(node); + + var saveKernelForm = function (applyNow) { + var choice = coreChoiceOption.formvalue('config') || selectedCoreChoice || originalCoreChoice; + var target = coreChoiceTarget(choice); + var changed = choice !== originalCoreChoice; + + return m.save() + .then(function () { return clashoo.commitConfig(); }) + .then(function () { + if (applyNow) + return clashoo.setCore(target.core, target.dcore, 'apply'); + if (changed) + return clashoo.setCore(target.core, target.dcore, 'save'); + return { success: true }; + }) + .then(function (res) { + if (!res || res.success === false) + throw new Error((res && res.message) || _("Failed to save core configuration")); + if (applyNow && res.restarting) + return waitForCoreTarget(target).then(function () { return res; }); + return res; + }) + .then(function (res) { + return clearClashooDirty().then(function () { return res; }); + }) + .then(function (res) { + var msg; + if (!applyNow) + msg = changed ? _("Core type saved, takes effect on next start or restart") : _("Configuration saved"); + else if (res.restarting) + msg = _("Configuration saved, switched and started selected core"); + else + msg = _("Configuration saved, service remains stopped"); + ui.addNotification(null, E('p', msg)); + window.setTimeout(function () { location.reload(); }, 300); + }); + }; + + container.appendChild(E('div', { 'class': 'cl-save-bar' }, [ + E('button', { 'class': 'cbi-button', click: function () { + saveKernelForm(false) + .catch(function (e) { ui.addNotification(null, E('p', _("Save failed: ") + (e.message || e))); }); + }}, _("Save Configuration")), + E('button', { 'class': 'btn cbi-button-action', click: function () { + saveKernelForm(true) + .catch(function (e) { ui.addNotification(null, E('p', _("Operation failed: ") + (e.message || e))); }); + }}, _("Apply Configuration")) + ])); + }); + }, + + _buildRulesForm: function (container) { + var m = new form.Map('clashoo', '', ''); + var s, o; + + s = m.section(form.NamedSection, 'config', 'clashoo', _("Bypass Rules")); + s.addremove = false; + o = s.option(form.Flag, 'bypass_china', _("Bypass China IPv4")); + o.default = '0'; + o.rmempty = false; + + o = s.option(form.Flag, 'bypass_china_ipv6', _("Bypass China IPv6")); + o.default = '0'; + o.rmempty = false; + o.cfgvalue = function (section_id) { + var value = uci.get('clashoo', section_id, 'bypass_china_ipv6'); + return (value != null) ? value : uci.get('clashoo', section_id, 'bypass_china'); + }; + + o = s.option(form.ListValue, 'bypass_port_mode', _("Bypass Ports")); + o.value('all', _("All Ports")); + o.value('common', _("Common Ports")); + o.value('custom', _("Custom")); + o.default = 'all'; + + o = s.option(form.Value, 'bypass_port_custom', _("Custom Ports")); + o.depends('bypass_port_mode', 'custom'); + o.placeholder = '22,53,80,443,8080,8443'; + o.datatype = 'string'; + o.rmempty = true; + + o = s.option(form.Flag, 'sniffer_streaming', _("Sniffer (streaming compatibility)")); + o.default = '1'; + o.rmempty = false; + o.description = _("When enabled, sniffer configuration is injected automatically to improve streaming domain detection and routing stability."); + + s = m.section(form.TableSection, 'lan_acl', _("Access Control")); + s.addremove = true; + s.anonymous = true; + s.sortable = true; + s.description = _("Rules are matched from top to bottom. Unmatched devices use DNS takeover and proxy by default. A rule with IPv4, IPv6 and MAC all empty matches every device."); + + var hints = this._hostHints || {}; + var hostOptions = [], host6Options = [], macOptions = []; + var seen = {}, seen6 = {}; + Object.keys(hints).forEach(function (mac) { + var h = hints[mac] || {}; + var macU = mac.toUpperCase(); + var addrs = h.ipaddrs || (h.ipv4 ? [h.ipv4] : []); + var addrs6 = h.ip6addrs || []; + var label = h.name || addrs[0] || addrs6[0] || ''; + addrs.forEach(function (ip) { + if (ip && !seen[ip]) { + seen[ip] = true; + hostOptions.push([ip, ip + ' (' + macU + ')']); + } + }); + addrs6.forEach(function (ip) { + if (ip && !seen6[ip]) { + seen6[ip] = true; + host6Options.push([ip, ip + ' (' + macU + ')']); + } + }); + macOptions.push([macU, label ? macU + ' (' + label + ')' : macU]); + }); + + o = s.option(form.Flag, 'enabled', _("Enable")); + o.default = '1'; + o.rmempty = false; + + o = s.option(form.DynamicList, 'ip', _("IPv4")); + o.placeholder = '192.168.1.100'; + o.datatype = 'ip4addr'; + hostOptions.forEach(function (kv) { o.value(kv[0], kv[1]); }); + + o = s.option(form.DynamicList, 'ip6', _("IPv6")); + o.placeholder = 'fd00::100'; + o.datatype = 'ip6addr'; + host6Options.forEach(function (kv) { o.value(kv[0], kv[1]); }); + + o = s.option(form.DynamicList, 'mac', _("MAC")); + o.placeholder = '00:11:22:33:44:55'; + o.datatype = 'macaddr'; + macOptions.forEach(function (kv) { o.value(kv[0], kv[1]); }); + + o = s.option(form.Flag, 'dns', _("DNS Takeover")); + o.default = '1'; + o.rmempty = false; + + o = s.option(form.Flag, 'proxy', _("Proxy")); + o.default = '1'; + o.rmempty = false; + + s = m.section(form.NamedSection, 'config', 'clashoo', _("Automation Tasks")); + s.addremove = false; + o = s.option(form.Flag, 'auto_update', _("Regularly update rule data")); + o.description = _("Rule data includes China allowlist (direct IP ranges) and GeoIP / GeoSite databases"); + o = s.option(form.Value, 'auto_update_time', _("Update interval (hours)")); + o = s.option(form.Flag, 'auto_clear_log', _("Scheduled Log Cleanup")); + o = s.option(form.Value, 'clear_time',_("Cleanup interval (hours)")); + o = s.option(form.ListValue, 'geoip_source', _("GeoIP Source")); + o.value('3', 'Loyalsoldier'); o.value('5', 'v2fly'); o.value('4', _("Custom")); + o.default = '3'; + o = s.option(form.Value, 'geoip_mmdb_url', 'Country.mmdb URL'); + o.depends('geoip_source', '4'); + o.placeholder = 'https://…/Country.mmdb'; + o = s.option(form.Value, 'geosite_url', 'geosite.dat URL'); + o.depends('geoip_source', '4'); + o.placeholder = 'https://…/geosite.dat'; + o = s.option(form.Value, 'geoip_dat_url', 'geoip.dat URL'); + o.depends('geoip_source', '4'); + o.placeholder = 'https://…/geoip.dat'; + + m.render().then(function (node) { + normalizeLanAclLayout(node); + decorateSystemForm(node); + container.appendChild(node); + watchLanAclLayout(node); + container.appendChild(E('div', { 'class': 'cl-save-bar' }, [ + E('button', { 'class': 'cbi-button', click: function () { + m.save().then(function () { return clashoo.commitConfig(); }) + .then(function () { return clearClashooDirty(); }) + .then(function () { location.reload(); }) + .catch(function (e) { ui.addNotification(null, E('p', _("Save failed: ") + (e.message || e))); }); + }}, _("Save Configuration")), + E('button', { 'class': 'btn cbi-button-action', click: function () { + saveCommitApplyMaybeReload(m, _("Configuration saved and service hot-reloaded"), _("Configuration saved, service is not running")) + .catch(function (e) { ui.addNotification(null, E('p', _("Operation failed: ") + (e.message || e))); }); + }}, _("Apply Configuration")) + ])); + }); + }, + + _buildLogsPanel: function (runLog) { + var self = this; + var logTypes = [ + { id: 'plugin', label: _("Plugin Log"), read: clashoo.readLog.bind(clashoo), clear: clashoo.clearLog.bind(clashoo) }, + { id: 'core', label: _("Core Log"), read: clashoo.readCoreLog.bind(clashoo), clear: clashoo.clearCoreLog.bind(clashoo) }, + { id: 'update', label: _("Update Log"), read: clashoo.readUpdateMergedLog.bind(clashoo), clear: clashoo.clearUpdateMergedLog.bind(clashoo) } + ]; + var MAX_LINES = 5000; + + var state = { autoScroll: true, paused: false, filter: '' }; + + function esc(s) { + return s.replace(/&/g, '&').replace(//g, '>').replace(/"/g, '"'); + } + + /* Expose helpers for _pollLogs */ + self._buildLogLine = buildLine; + self._applyLogFilter = applyFilter; + + /* parse level token; no keyword (e.g. mihomo info lines with [info] stripped) => info */ + function detectLevelToken(ln) { + var m = ln.match(/\b(DEBUG|INFO|WARN(?:ING)?|ERROR|FATAL|PANIC)\b/i); + if (!m) return 'info'; + var l = m[1].toUpperCase(); + if (l === 'DEBUG') return 'debug'; + if (l === 'INFO') return 'info'; + if (l.startsWith('WARN')) return 'warn'; + if (l === 'FATAL' || l === 'PANIC') return 'fatal'; + return 'error'; + } + function levelClass(token) { + if (token === 'debug') return 'cl-log-debug'; + if (token === 'warn') return 'cl-log-warn'; + if (token === 'error' || token === 'fatal') return 'cl-log-error'; + return 'cl-log-info'; + } + + var MONTHS = { Jan:'01',Feb:'02',Mar:'03',Apr:'04',May:'05',Jun:'06',Jul:'07',Aug:'08',Sep:'09',Oct:'10',Nov:'11',Dec:'12' }; + /* render a single line as colored HTML */ + function buildLine(ln) { + var token = detectLevelToken(ln); + var cls = levelClass(token); + var ts = '', msg = ln; + /* core syslog: Mon DD HH:MM:SS YYYY → MM-DD HH:MM:SS */ + var cm = ln.match(/^(\w{3})\s+(\d{1,2})\s+(\d{2}:\d{2}:\d{2})\s+\d{4}\s+\S+\.(\S+)\s+\S+\[\d+\]:\s+(.*)$/); + if (cm) { ts = (MONTHS[cm[1]] || cm[1]) + '-' + cm[2].padStart(2,'0') + ' ' + cm[3]; msg = cm[5] || ln; } + /* plugin / update: MM-DD HH:MM:SS [warn] message */ + else if (/^\d{2}-\d{2}\s+\d{2}:\d{2}:\d{2}\s/.test(ln)) { + ts = ln.substring(0,14); + msg = ln.substring(15); + /* update: MM-DD HH:MM:SS - message → strip dash */ + if (msg.indexOf(' - ') === 0) msg = msg.substring(3); + } + if (ts) { + return '

    ' + esc(ts) + '' + esc(msg) + '
    '; + } + return '
    ' + esc(ln) + '
    '; + } + + function renderLines(text) { + var lines = text.split('\n').filter(function(l) { return l; }); + var html = ''; + for (var i = 0; i < lines.length; i++) { + html += buildLine(lines[i]); + } + return html; + } + + function applyFilter() { + var f = state.filter; /* '' = all, else exact level: info/warn/error/fatal */ + var els = document.querySelectorAll('#cl-log-area .cl-log-line'); + for (var i = 0; i < els.length; i++) { + if (!f || els[i].getAttribute('data-level') === f) + els[i].classList.remove('cl-log-hidden'); + else + els[i].classList.add('cl-log-hidden'); + } + } + + var logTabEls = {}; + var logArea = E('div', { 'class': 'cl-log-area', id: 'cl-log-area' }); + logArea.innerHTML = runLog ? renderLines(runLog) : _("(empty)"); + + var clearBtn = null; + + function activateLogTab(id) { + var logType = logTypes.find(function (lt) { return lt.id === id; }) || logTypes[0]; + Object.keys(logTabEls).forEach(function (k) { + logTabEls[k].className = 'cl-log-tab' + (k === logType.id ? ' active' : ''); + }); + self._logTab = logType.id; + syncClearButton(); + return logType.read().then(function (content) { + logArea.innerHTML = (content && content.trim()) ? renderLines(content) : _("(empty)"); + applyFilter(); + if (state.autoScroll) logArea.scrollTop = logArea.scrollHeight; + }); + } + this._activateLogTab = activateLogTab; + + var logTabBar = E('div', { 'class': 'cl-log-tabs' }, + logTypes.map(function (lt) { + var el = E('span', { + 'class': 'cl-log-tab' + (self._logTab === lt.id ? ' active' : ''), + click: function () { activateLogTab(lt.id); } + }, lt.label); + logTabEls[lt.id] = el; + return el; + }) + ); + + var currentType = function () { + return logTypes.find(function (lt) { return lt.id === self._logTab; }) || logTypes[0]; + }; + + function syncClearButton() { + if (!clearBtn) return; + var ct = currentType(); + clearBtn.disabled = !ct.clear; + } + + /* ---- toolbar ---- */ + var cbAuto = E('input', { type: 'checkbox', checked: 'checked' }); + cbAuto.addEventListener('change', function () { state.autoScroll = cbAuto.checked; }); + + var cbPause = E('input', { type: 'checkbox' }); + cbPause.addEventListener('change', function () { state.paused = cbPause.checked; }); + + var selFilter = E('select', { 'class': 'cbi-button' }, [ + E('option', { value: '' }, _("All")), + E('option', { value: 'info' }, 'INFO'), + E('option', { value: 'warn' }, 'WARN'), + E('option', { value: 'error' }, 'ERROR'), + E('option', { value: 'fatal' }, 'FATAL') + ]); + selFilter.addEventListener('change', function () { + state.filter = selFilter.value; + applyFilter(); + }); + + var btnClearView = E('button', { 'class': 'cbi-button' }, _("Clear View")); + btnClearView.addEventListener('click', function () { logArea.innerHTML = ''; }); + + var btnDownload = E('button', { 'class': 'cbi-button' }, _("Download")); + btnDownload.addEventListener('click', function () { + var blob = new Blob([logArea.textContent || ''], { type: 'text/plain' }); + var url = URL.createObjectURL(blob); + var a = document.createElement('a'); + a.href = url; + a.download = 'clashoo-' + new Date().toISOString().replace(/[:.]/g, '-') + '.log'; + document.body.appendChild(a); a.click(); document.body.removeChild(a); + URL.revokeObjectURL(url); + }); + + clearBtn = E('button', { 'class': 'cbi-button' }, _("Clear File")); + clearBtn.addEventListener('click', function () { + var ct = currentType(); + if (!ct.clear) return; + if (!confirm(_("Clear the current log file? This cannot be undone."))) return; + ct.clear().then(function () { logArea.innerHTML = ''; }); + }); + syncClearButton(); + + var toolbar = E('div', { 'class': 'cl-log-toolbar' }, [ + E('label', {}, [cbAuto, _("Auto Scroll")]), + E('label', {}, [cbPause, _("Pause")]), + selFilter, + btnClearView, + btnDownload, + clearBtn + ]); + + return E('div', { 'class': 'cl-section cl-card cl-log-card' }, [ + E('h4', {}, _("Log")), + logTabBar, + toolbar, + logArea + ]); + }, + + _pollLogs: function () { + if (this._tab !== 'logs') return Promise.resolve(); + var self = this; + var el = document.getElementById('cl-log-area'); + if (!el) return Promise.resolve(); + var cbPause = el.parentNode.querySelector('input[type="checkbox"]:nth-of-type(2)'); + if (cbPause && cbPause.checked) return Promise.resolve(); + var logFns = { + plugin: clashoo.readLog.bind(clashoo), + core: clashoo.readCoreLog.bind(clashoo), + update: clashoo.readUpdateMergedLog.bind(clashoo) + }; + var readFn = logFns[this._logTab] || logFns.plugin; + return readFn().then(function (content) { + if (!content || !content.trim()) { el.innerHTML = _("(empty)"); return; } + var html = ''; + var lines = content.split('\n').filter(function(l) { return l; }); + for (var i = 0; i < lines.length; i++) { + html += self._buildLogLine(lines[i]); + } + el.innerHTML = html; + self._applyLogFilter(); + var cbAuto = el.parentNode.querySelector('input[type="checkbox"]:first-of-type'); + if (!cbAuto || cbAuto.checked) el.scrollTop = el.scrollHeight; + }); + }, + + _switchTab: function (id) { + var tabEls = this._tabEls || {}; + var panelEls = this._panelEls || {}; + Object.keys(tabEls).forEach(function (k) { + tabEls[k].className = 'cl-tab' + (k === id ? ' active' : ''); + panelEls[k].className = 'cl-panel' + (k === id ? ' active' : ''); + }); + this._tab = id; + rememberTab('clashoo.system.tab', id); + }, + + handleSaveApply: null, + handleSave: null, + handleReset: null +}); diff --git a/luci-app-clashoo/htdocs/luci-static/resources/view/clashoo/youtube.svg b/luci-app-clashoo/htdocs/luci-static/resources/view/clashoo/youtube.svg new file mode 100644 index 000000000..18ddde453 --- /dev/null +++ b/luci-app-clashoo/htdocs/luci-static/resources/view/clashoo/youtube.svg @@ -0,0 +1,4 @@ + + + + diff --git a/luci-app-clashoo/po/templates/clashoo.pot b/luci-app-clashoo/po/templates/clashoo.pot new file mode 100644 index 000000000..d31f14df6 --- /dev/null +++ b/luci-app-clashoo/po/templates/clashoo.pot @@ -0,0 +1,1572 @@ +msgid "" +msgstr "" +"Content-Type: text/plain; charset=UTF-8\n" + +msgid " (auto-detected by device)" +msgstr "" + +msgid " (expired)" +msgstr "" + +msgid " (refreshing)" +msgstr "" + +msgid " candidates" +msgstr "" + +msgid " days)" +msgstr "" + +msgid " files)" +msgstr "" + +msgid " groups" +msgstr "" + +msgid " latency test failed: " +msgstr "" + +msgid " saved" +msgstr "" + +msgid " seconds" +msgstr "" + +msgid " switch error" +msgstr "" + +msgid " switch failed: " +msgstr "" + +msgid " update succeeded" +msgstr "" + +msgid " updated" +msgstr "" + +msgid "$1 updated" +msgstr "" + +msgid "(empty)" +msgstr "" + +msgid ", click Start to take effect" +msgstr "" + +msgid ", failed " +msgstr "" + +msgid ", skipped " +msgstr "" + +msgid ", switched to active configuration" +msgstr "" + +msgid ", switching to active configuration..." +msgstr "" + +msgid ", unchanged " +msgstr "" + +msgid "; updated " +msgstr "" + +msgid "(empty)" +msgstr "" + +msgid "China traffic bypasses the core at firewall level; DNS behavior is slightly weaker. Choose as needed." +msgstr "" + +msgid "Fast resolution and accurate routing; China routing is handled by the core." +msgstr "" + +msgid "Note: Proxy node domains still use direct DNS for startup resolution, not for normal client domain queries.
    " +msgstr "" + +msgid "Prerequisite: The configuration must include transparent proxying (TUN auto-route or TProxy inbound). Restart after switching." +msgstr "" + +msgid "Warning: After enabling, IPv6 sites can only be accessed over IPv4; pure IPv6 networks may lose connectivity." +msgstr "" + +msgid "Access Check" +msgstr "" + +msgid "Access Control" +msgstr "" + +msgid "Access Secret" +msgstr "" + +msgid "Actions" +msgstr "" + +msgid "Active" +msgstr "" + +msgid "Advanced DNS" +msgstr "" + +msgid "Advanced Settings (core / data components)" +msgstr "" + +msgid "For providers that directly offer sing-box JSON subscriptions, or links already converted by external tools. After fetching, click Update on the corresponding item in the Configuration Files tab to fetch the latest configuration again." +msgstr "" + +msgid "All" +msgstr "" + +msgid "All components are up to date" +msgstr "" + +msgid "All Devices" +msgstr "" + +msgid "All Ports" +msgstr "" + +msgid "Allow LAN Access" +msgstr "" + +msgid "Allowlist" +msgstr "" + +msgid "Allowlist (only listed items use fake-IP)" +msgstr "" + +msgid "Alpha" +msgstr "" + +msgid "Already up to date" +msgstr "" + +msgid "Apply Configuration" +msgstr "" + +msgid "Applying…" +msgstr "" + +msgid "ASN Priority" +msgstr "" + +msgid "Auto Scroll" +msgstr "" + +msgid "Auto setup completed." +msgstr "" + +msgid "Auto Update Model" +msgstr "" + +msgid "Auto-detected" +msgstr "" + +msgid "Automatically choose available DNS and update only upstream servers; split policies and advanced settings remain unchanged." +msgstr "" + +msgid "Automatically switch Url-test and Load-balance policy groups to Smart policy groups" +msgstr "" + +msgid "Automation Tasks" +msgstr "" + +msgid "Backend Core" +msgstr "" + +msgid "Backup and Restore" +msgstr "" + +msgid "Backup file is too large" +msgstr "" + +msgid "Backup exported" +msgstr "" + +msgid "Backup exported (" +msgstr "" + +msgid "Backup files contain subscription and node credentials. Store them securely." +msgstr "" + +msgid "Backup restored, restarting service" +msgstr "" + +msgid "Basic DNS" +msgstr "" + +msgid "Block QUIC" +msgstr "" + +msgid "Blocklist" +msgstr "" + +msgid "Blocklist (listed items use real IP, default)" +msgstr "" + +msgid "Blocklist mode: enter domains or shorthand like geosite:cn. Rule mode: entries are converted to rule syntax automatically, such as GEOSITE,cn,real-ip / RULE-SET,xxx,real-ip; usually add MATCH,fake-ip at the end as fallback. geosite:cn automatically uses built-in cn.mrs acceleration and avoids loading the 10MB geosite.dat. Allowlist mode drops the shipped defaults (they mean the opposite there), so enter your own domains." +msgstr "" + +msgid "Bypass China IPv4" +msgstr "" + +msgid "Bypass China IPv6" +msgstr "" + +msgid "Bypass Ports" +msgstr "" + +msgid "Bypass Rules" +msgstr "" + +msgid "ByteDance" +msgstr "" + +msgid "Cannot connect to core API. Check runtime status." +msgstr "" + +msgid "Check and Update" +msgstr "" + +msgid "Check Updates" +msgstr "" + +msgid "Checking configuration file" +msgstr "" + +msgid "Checking environment…" +msgstr "" + +msgid "Checking…" +msgstr "" + +msgid "Cleaning mihomo network rules" +msgstr "" + +msgid "Cleaning sing-box network rules" +msgstr "" + +msgid "Cleanup failed (mihomo may not be running)" +msgstr "" + +msgid "Cleanup interval (hours)" +msgstr "" + +msgid "Clear" +msgstr "" + +msgid "Clear File" +msgstr "" + +msgid "Clear Smart Cache" +msgstr "" + +msgid "Clear the current log file? This cannot be undone." +msgstr "" + +msgid "Clear View" +msgstr "" + +msgid "Click Save after editing; switching configuration automatically restarts the service" +msgstr "" + +msgid "Collapse" +msgstr "" + +msgid "Collect node latency data for LightGBM model training" +msgstr "" + +msgid "Collect Training Data" +msgstr "" + +msgid "Common Ports" +msgstr "" + +msgid "Completed" +msgstr "" + +msgid "Component update task submitted" +msgstr "" + +msgid "Component Updates" +msgstr "" + +msgid "Configuration" +msgstr "" + +msgid "Configuration content appears here after selecting a file…" +msgstr "" + +msgid "Configuration file name (optional, blank auto-generates singbox.json)" +msgstr "" + +msgid "Configuration Files" +msgstr "" + +msgid "Configuration is up to date; no fixes needed" +msgstr "" + +msgid "Configuration saved" +msgstr "" + +msgid "Configuration saved and service hot-reloaded" +msgstr "" + +msgid "Configuration saved, service is not running" +msgstr "" + +msgid "Configuration saved, service remains stopped" +msgstr "" + +msgid "Configuration saved, switched and started selected core" +msgstr "" + +msgid "Connection failed" +msgstr "" + +msgid "Connections" +msgstr "" + +msgid "Convert YAML subscriptions to sing-box JSON, automatically injecting TUN transparent proxy and China direct rules. Files with the same name are overwritten; use the same name when updating." +msgstr "" + +msgid "Core and Data" +msgstr "" + +msgid "Core did not start within 15 seconds (procd is recovering)" +msgstr "" + +msgid "Core Download" +msgstr "" + +msgid "Core is not running. Start it before switching nodes." +msgstr "" + +msgid "Core Log" +msgstr "" + +msgid "Core Only (advanced)" +msgstr "" + +msgid "Core Switch" +msgstr "" + +msgid "Core switch failed" +msgstr "" + +msgid "Core Type" +msgstr "" + +msgid "Core type saved, takes effect on next start or restart" +msgstr "" + +msgid "Core verification failed. Check System → Core." +msgstr "" + +msgid "Correct routing by forcing a domain or IP to Direct or Proxy. These rules take priority over subscription rules and apply to both mihomo and sing-box." +msgstr "" + +msgid "CPU Architecture" +msgstr "" + +msgid "CPU architecture set to " +msgstr "" + +msgid "curl or wget not found" +msgstr "" + +msgid "Current configuration has no manually switchable proxy groups" +msgstr "" + +msgid "Current configuration has no recorded subscription URL" +msgstr "" + +msgid "Current configuration is a custom file; no subscription update needed" +msgstr "" + +msgid "Current version: " +msgstr "" + +msgid "Current: %s" +msgstr "" + +msgid "Custom" +msgstr "" + +msgid "Custom Ports" +msgstr "" + +msgid "Custom Routing Rules" +msgstr "" + +msgid "Custom User-Agent" +msgstr "" + +msgid "Customize..." +msgstr "" + +msgid "Dashboard" +msgstr "" + +msgid "Dashboard Port" +msgstr "" + +msgid "Dashboard Settings" +msgstr "" + +msgid "Default" +msgstr "" + +msgid "Degraded" +msgstr "" + +msgid "Delete" +msgstr "" + +msgid "Delete " +msgstr "" + +msgid "Direct" +msgstr "" + +msgid "Direct Domain Resolver" +msgstr "" + +msgid "Disable QUIC GSO" +msgstr "" + +msgid "Disabling DNS cache" +msgstr "" + +msgid "DNS Address" +msgstr "" + +msgid "DNS Auto Setup" +msgstr "" + +msgid "DNS auto setup applied, service is restarting" +msgstr "" + +msgid "DNS auto setup failed" +msgstr "" + +msgid "DNS auto setup failed: " +msgstr "" + +msgid "DNS auto setup saved, service is not running" +msgstr "" + +msgid "DNS configuration saved and service hot-reloaded" +msgstr "" + +msgid "DNS configuration saved, service is not running" +msgstr "" + +msgid "DNS Listen Port" +msgstr "" + +msgid "DNS Policy" +msgstr "" + +msgid "DNS queries follow the routing rules, so overseas domains resolve through the proxy instead of a polluted result. Requires proxy-server-nameserver." +msgstr "" + +msgid "DNS Respect Rules" +msgstr "" + +msgid "Domain / IP" +msgstr "" + +msgid "Domain keyword (e.g. youtube)" +msgstr "" + +msgid "Domain Split DNS" +msgstr "" + +msgid "Domain suffix (e.g. google.com)" +msgstr "" + +msgid "Domestic" +msgstr "" + +msgid "Domestic Upstream DNS" +msgstr "" + +msgid "Download" +msgstr "" + +msgid "Download failed (error code $1)" +msgstr "" + +msgid "Download Subscription" +msgstr "" + +msgid "Download succeeded" +msgstr "" + +msgid "Downloaded Subscriptions" +msgstr "" + +msgid "Downloading LightGBM model..." +msgstr "" + +msgid "Downloading subscription..." +msgstr "" + +msgid "Downloading..." +msgstr "" + +msgid "Downloading…" +msgstr "" + +msgid "ECS Client Subnet" +msgstr "" + +msgid "Edit" +msgstr "" + +msgid "Editing: " +msgstr "" + +msgid "Enable" +msgstr "" + +msgid "Enable DNS Module" +msgstr "" + +msgid "Enable LightGBM Model" +msgstr "" + +msgid "Enable Service" +msgstr "" + +msgid "Enhanced Mode" +msgstr "" + +msgid "Enter remote template URL, e.g. https://raw.githubusercontent.com/…/Clash.yaml" +msgstr "" + +msgid "Enter subscription URL (injected into template proxy-providers)" +msgstr "" + +msgid "Every" +msgstr "" + +msgid "Exact domain (e.g. www.google.com)" +msgstr "" + +msgid "example.com or 1.2.3.0/24" +msgstr "" + +msgid "Example: geosite:cn uses https://dns.alidns.com/dns-query; geosite:geolocation-!cn uses https://cloudflare-dns.com/dns-query." +msgstr "" + +msgid "Expand" +msgstr "" + +msgid "Expires: " +msgstr "" + +msgid "Export a backup before changing cores or configuration, so it can be restored if needed. Includes configuration and settings only, not cores." +msgstr "" + +msgid "Export Backup" +msgstr "" + +msgid "Export failed: " +msgstr "" + +msgid "Exporting…" +msgstr "" + +msgid "Factory defaults restored" +msgstr "" + +msgid "Failed" +msgstr "" + +msgid "Failed to check updates, please check the network" +msgstr "" + +msgid "Failed to save core configuration" +msgstr "" + +msgid "Failed to submit component update task" +msgstr "" + +msgid "Fake-IP Filter Domains" +msgstr "" + +msgid "Fake-IP Filter Mode" +msgstr "" + +msgid "Fake-IP Range" +msgstr "" + +msgid "Fallback" +msgstr "" + +msgid "Fallback GeoIP Filter" +msgstr "" + +msgid "Bootstrap" +msgstr "" + +msgid "Fetch and Apply" +msgstr "" + +msgid "Fetch Configuration" +msgstr "" + +msgid "Fetching…" +msgstr "" + +msgid "File Name" +msgstr "" + +msgid "File name (optional, blank for automatic name)" +msgstr "" + +msgid "File name (optional, blank to auto-generate)" +msgstr "" + +msgid "Fix Deprecated Fields" +msgstr "" + +msgid "Fix failed: " +msgstr "" + +msgid "Fixed deprecated fields: " +msgstr "" + +msgid "Force ASN lookup and prefer target ASN information when selecting nodes for a more stable experience" +msgstr "" + +msgid "Force DNS Forwarding" +msgstr "" + +msgid "Force ECS Override" +msgstr "" + +msgid "Full URL / no protocol prefix" +msgstr "" + +msgid "Generate Configuration" +msgstr "" + +msgid "Generate error: " +msgstr "" + +msgid "Generate failed: " +msgstr "" + +msgid "Generated: " +msgstr "" + +msgid "Generating…" +msgstr "" + +msgid "Generation is taking longer, refreshing to show results…" +msgstr "" + +msgid "GeoIP Source" +msgstr "" + +msgid "GeoIP update completed" +msgstr "" + +msgid "GeoIP update completed, applies after Clashoo restarts" +msgstr "" + +msgid "GeoIP update failed" +msgstr "" + +msgid "GitHub acceleration prefix" +msgstr "" + +msgid "Global" +msgstr "" + +msgid "Health check failed" +msgstr "" + +msgid "Health check in progress…" +msgstr "" + +msgid "Health check passed" +msgstr "" + +msgid "hours" +msgstr "" + +msgid "HTTP Port" +msgstr "" + +msgid "Import failed: " +msgstr "" + +msgid "Import Restore" +msgstr "" + +msgid "Importing will overwrite all current configuration and settings with the backup. Existing subscriptions/configuration files will be replaced. Continue?" +msgstr "" + +msgid "Information Input" +msgstr "" + +msgid "Initializing…" +msgstr "" + +msgid "Intercept IPv6 DNS traffic to prevent devices with hard-coded DNS from bypassing the traffic." +msgstr "" + +msgid "IP / CIDR (e.g. 8.8.8.8/32)" +msgstr "" + +msgid "IP Allowlist" +msgstr "" + +msgid "IP Blocklist" +msgstr "" + +msgid "IP rules do not trigger DNS resolution" +msgstr "" + +msgid "IPv4 DNS Hijack" +msgstr "" + +msgid "IPv4 Proxy" +msgstr "" + +msgid "IPv6 DNS Hijack" +msgstr "" + +msgid "IPv6 Proxy" +msgstr "" + +msgid "just now" +msgstr "" + +msgid "Keep the default if unsure." +msgstr "" + +msgid "LAN Control" +msgstr "" + +msgid "%d updates available" +msgstr "" + +msgid "Last check: initializing" +msgstr "" + +msgid "Last check: just now" +msgstr "" + +msgid "Last check: %d seconds ago" +msgstr "" + +msgid "Last check: %d minutes ago" +msgstr "" + +msgid "Last check: %d hours ago" +msgstr "" + +msgid "Last run: " +msgstr "" + +msgid "LightGBM model file download URL; leave blank to use the default official URL" +msgstr "" + +msgid "LightGBM model updated successfully" +msgstr "" + +msgid "Load failed" +msgstr "" + +msgid "Load-balance" +msgstr "" + +msgid "Loading…" +msgstr "" + +msgid "Local Template" +msgstr "" + +msgid "Log" +msgstr "" + +msgid "Match Rule" +msgstr "" + +msgid "Memory usage %s" +msgstr "" + +msgid "mihomo restarted successfully, please wait for servers to come online." +msgstr "" + +msgid "mihomo runs as-is for nikki/OpenClash compatibility; sing-box automatically upgrades old formats for momo/homeproxy compatibility.
    " +msgstr "" + +msgid "mihomo Stable" +msgstr "" + +msgid "mihomo started successfully, please wait for servers to come online." +msgstr "" + +msgid "mihomo writes the ecs parameter to DNS URLs; sing-box writes dns.client_subnet. Leave empty to skip." +msgstr "" + +msgid "Mixed Mode" +msgstr "" + +msgid "Mixed Port" +msgstr "" + +msgid "Mode" +msgstr "" + +msgid "Model Download URL" +msgstr "" + +msgid "Model install failed: $1" +msgstr "" + +msgid "Model is already up to date" +msgstr "" + +msgid "Model not installed" +msgstr "" + +msgid "Network Stack" +msgstr "" + +msgid "Network Stack Type" +msgstr "" + +msgid "No auto setup result yet" +msgstr "" + +msgid "No component update logs yet" +msgstr "" + +msgid "No configuration file found. Import a subscription or upload a configuration on the Configuration page first." +msgstr "" + +msgid "No configuration file selected. Select or upload one on the Configuration page before starting." +msgstr "" + +msgid "No configuration files yet. Use Quick Wizard to generate one or upload a JSON file." +msgstr "" + +msgid "No proxy groups" +msgstr "" + +msgid "No subscriptions" +msgstr "" + +msgid "Node Panel ›" +msgstr "" + +msgid "Node Selection" +msgstr "" + +msgid "Node Subscription" +msgstr "" + +msgid "Node weight bonus. <1 means lower priority, >1 means higher priority. Modify as needed; leave blank to skip policy-priority injection." +msgstr "" + +msgid "Not installed" +msgstr "" + +msgid "Not enabled" +msgstr "" + +msgid "Not running" +msgstr "" + +msgid "Off" +msgstr "" + +msgid "Only subscriptions with recorded source URLs are overwritten; no duplicate files are created." +msgstr "" + +msgid "Only .tar.gz and legacy .json backup files are supported" +msgstr "" + +msgid "Open Dashboard" +msgstr "" + +msgid "TUN stack is used when either TCP or UDP mode is TUN." +msgstr "" + +msgid "OpenClash is enabled; disable it first to avoid rule conflicts" +msgstr "" + +msgid "OpenClash/Nikki Loopback DNS Compatibility" +msgstr "" + +msgid "Operation failed: " +msgstr "" + +msgid "Optional compatibility for normal managed mode. At runtime, replace only proxy node resolvers that point back to the imported configuration's own DNS listener with the proxy-server-nameserver setting. Core Only mode stays verbatim; the source configuration and unrelated local DNS services remain unchanged." +msgstr "" + +msgid "Other Configuration Files (upload / overwrite output)" +msgstr "" + +msgid "Output file name (without extension, blank to auto-fill)" +msgstr "" + +msgid "Overseas" +msgstr "" + +msgid "Overseas Encrypted DNS (anti-pollution)" +msgstr "" + +msgid "Overview" +msgstr "" + +msgid "Overwrite Settings" +msgstr "" + +msgid "Panel" +msgstr "" + +msgid "Panel is downloading" +msgstr "" + +msgid "Panel switch failed: " +msgstr "" + +msgid "Panel UI" +msgstr "" + +msgid "Password" +msgstr "" + +msgid "Paste native sing-box subscription URL (direct JSON response)" +msgstr "" + +msgid "Paste subscription URL (supports vmess / vless / trojan, etc.)" +msgstr "" + +msgid "Pause" +msgstr "" + +msgid "Period for automatically fetching a new model; also controls the cron trigger frequency, default 72 hours" +msgstr "" + +msgid "Please enter a remote template URL" +msgstr "" + +msgid "Please enter a subscription URL" +msgstr "" + +msgid "Please enter an output file name" +msgstr "" + +msgid "Please select a local template file" +msgstr "" + +msgid "Plugin Log" +msgstr "" + +msgid "Policy Priority (weight bonus)" +msgstr "" + +msgid "Policy Type" +msgstr "" + +msgid "Port" +msgstr "" + +msgid "Port Settings" +msgstr "" + +msgid "Prevent DNS Leaks" +msgstr "" + +msgid "Processing…" +msgstr "" + +msgid "Protocol" +msgstr "" + +msgid "Proxy" +msgstr "" + +msgid "DNS Takeover" +msgstr "" + +msgid "IPv4" +msgstr "" + +msgid "IPv6" +msgstr "" + +msgid "MAC" +msgstr "" + +msgid "Rules are matched from top to bottom. Unmatched devices use DNS takeover and proxy by default." +msgstr "" + +msgid "Proxy Authentication" +msgstr "" + +msgid "Proxy configuration saved and service hot-reloaded" +msgstr "" + +msgid "Proxy configuration saved, service is not running" +msgstr "" + +msgid "Proxy Domain Split DNS" +msgstr "" + +msgid "Proxy Mode" +msgstr "" + +msgid "Proxy Node Domain Resolver" +msgstr "" + +msgid "Quick Wizard" +msgstr "" + +msgid "Random" +msgstr "" + +msgid "Ready · " +msgstr "" + +msgid "Ready ✓" +msgstr "" + +msgid "Recommended " +msgstr "" + +msgid "Recommended" +msgstr "" + +msgid "Recommended blank" +msgstr "" + +msgid "Redirect Port" +msgstr "" + +msgid "Refresh" +msgstr "" + +msgid "Refresh Access Check" +msgstr "" + +msgid "Regular domains only use overseas DNS and DNS connections follow proxy rules; DoT/DoQ (port 853) is blocked and IPv6 resolution is disabled. Takes effect after restart.
    " +msgstr "" + +msgid "Regularly update rule data" +msgstr "" + +msgid "Reject proxied UDP 443 so some apps fall back to TCP. Try only when downloads or video stall." +msgstr "" + +msgid "Relay" +msgstr "" + +msgid "Remote Template" +msgstr "" + +msgid "Remote: %s" +msgstr "" + +msgid "Removing Cron scheduled tasks" +msgstr "" + +msgid "Requires MMDB. If enabled while the local GeoIP database is missing, the core may fail to start. Usually not needed." +msgstr "" + +msgid "Restarting client..." +msgstr "" + +msgid "Restarting Dnsmasq" +msgstr "" + +msgid "Restore Clashoo settings to factory defaults (subscriptions and configuration files are kept). Continue?" +msgstr "" + +msgid "Restore Defaults" +msgstr "" + +msgid "Restore failed: " +msgstr "" + +msgid "Restoring…" +msgstr "" + +msgid "Role" +msgstr "" + +msgid "Rule" +msgstr "" + +msgid "Rule data includes China allowlist (direct IP ranges) and GeoIP / GeoSite databases" +msgstr "" + +msgid "Rule mode (same syntax as rules)" +msgstr "" + +msgid "Rules and Control" +msgstr "" + +msgid "Run Mode" +msgstr "" + +msgid "Run mode setting failed: " +msgstr "" + +msgid "Run only the core with your imported configuration, without taking over firewall / DNS / routing.
    " +msgstr "" + +msgid "Running degraded" +msgstr "" + +msgid "Running 🟢" +msgstr "" + +msgid "Runtime Status" +msgstr "" + +msgid "Sample Rate" +msgstr "" + +msgid "sample-rate, 1 = sample every latency test; increase to reduce sampling frequency" +msgstr "" + +msgid "Save" +msgstr "" + +msgid "Save Configuration" +msgstr "" + +msgid "Save failed: " +msgstr "" + +msgid "Scheduled Log Cleanup" +msgstr "" + +msgid "Scheduled Subscription Update" +msgstr "" + +msgid "Scheduled update settings saved" +msgstr "" + +msgid "Select a configuration above to edit it here" +msgstr "" + +msgid "Select local template file" +msgstr "" + +msgid "Select YAML file to upload" +msgstr "" + +msgid "Selector" +msgstr "" + +msgid "Service disabled" +msgstr "" + +msgid "Service stopped" +msgstr "" + +msgid "Setting Cron scheduled tasks and starting process supervisor..." +msgstr "" + +msgid "Setting DNS forwarder / enabling custom DNS" +msgstr "" + +msgid "Setting mihomo network rules" +msgstr "" + +msgid "Setting sing-box network rules" +msgstr "" + +msgid "Show/Hide" +msgstr "" + +msgid "sing-box Configuration Files" +msgstr "" + +msgid "sing-box core not detected; download sing-box from the System page" +msgstr "" + +msgid "sing-box Independent DNS Cache" +msgstr "" + +msgid "sing-box restarted successfully, please wait for servers to come online." +msgstr "" + +msgid "sing-box service failed to start. Check System → Log." +msgstr "" + +msgid "sing-box Stable" +msgstr "" + +msgid "sing-box started successfully, please wait for servers to come online." +msgstr "" + +msgid "Size" +msgstr "" + +msgid "Smart" +msgstr "" + +msgid "Smart cache cleared" +msgstr "" + +msgid "Smart core not detected; updating the model will not install the core" +msgstr "" + +msgid "Smart core not detected; updating the model will not install the core. Download the Smart build from the System page." +msgstr "" + +msgid "Smart Policy Auto Switch" +msgstr "" + +msgid "Smart Policy Settings" +msgstr "" + +msgid "smart-collector-size, maximum retained training samples, default 100" +msgstr "" + +msgid "Sniffer (streaming compatibility)" +msgstr "" + +msgid "SOCKS5 Port" +msgstr "" + +msgid "Stable" +msgstr "" + +msgid "Start downloading LightGBM model: $1" +msgstr "" + +msgid "Start failed: " +msgstr "" + +msgid "Start Service" +msgstr "" + +msgid "Started (" +msgstr "" + +msgid "Starting client" +msgstr "" + +msgid "Starting core…" +msgstr "" + +msgid "Starting…" +msgstr "" + +msgid "Stop Service" +msgstr "" + +msgid "Stopped (not enabled at boot)" +msgstr "" + +msgid "Stopped" +msgstr "" + +msgid "Stopping client..." +msgstr "" + +msgid "Stopping mihomo" +msgstr "" + +msgid "Stopping mihomo process supervisor" +msgstr "" + +msgid "Stopping sing-box" +msgstr "" + +msgid "Stopping sing-box process supervisor" +msgstr "" + +msgid "Stopping…" +msgstr "" + +msgid "Submission failed" +msgstr "" + +msgid "Submitting" +msgstr "" + +msgid "Subscription" +msgstr "" + +msgid "Subscription download failed" +msgstr "" + +msgid "Subscription Update" +msgstr "" + +msgid "Subscription updated successfully" +msgstr "" + +msgid "Subscription URL" +msgstr "" + +msgid "Subscription URLs (one per line)" +msgstr "" + +msgid "Switch" +msgstr "" + +msgid "Switch Profile" +msgstr "" + +msgid "Switch configuration failed: " +msgstr "" + +msgid "Switch failed: " +msgstr "" + +msgid "Switched to " +msgstr "" + +msgid "Switching to " +msgstr "" + +msgid "Syncing" +msgstr "" + +msgid "Syncing runtime state" +msgstr "" + +msgid "System" +msgstr "" + +msgid "System is missing nftables runtime" +msgstr "" + +msgid "Target" +msgstr "" + +msgid "TCP Mode" +msgstr "" + +msgid "Template Selection" +msgstr "" + +msgid "Template upload failed: " +msgstr "" + +msgid "Template uploaded: " +msgstr "" + +msgid "Test and Apply" +msgstr "" + +msgid "Test Latency" +msgstr "" + +msgid "Testing" +msgstr "" + +msgid "Testing latency and writing upstream DNS…" +msgstr "" + +msgid "The new core failed to start, please check the core log" +msgstr "" + +msgid "Time" +msgstr "" + +msgid "Timeout waiting for new core to start, please check the core log" +msgstr "" + +msgid "Total %s" +msgstr "" + +msgid "TPROXY Port" +msgstr "" + +msgid "Traffic Monitor" +msgstr "" + +msgid "Training Data Size" +msgstr "" + +msgid "Transparent Proxy" +msgstr "" + +msgid "TUN Mode" +msgstr "" + +msgid "TUN Network Stack" +msgstr "" + +msgid "Type" +msgstr "" + +msgid "UDP Mode" +msgstr "" + +msgid "Unknown" +msgstr "" + +msgid "Unknown error" +msgstr "" + +msgid "Update" +msgstr "" + +msgid "Update All Now" +msgstr "" + +msgid "Update available" +msgstr "" + +msgid "Update components individually. Click Check Updates to refresh versions." +msgstr "" + +msgid "Update failed" +msgstr "" + +msgid "Update failed: " +msgstr "" + +msgid "Update interval (hours)" +msgstr "" + +msgid "Update interval must be 1 to 8760 hours" +msgstr "" + +msgid "Update Log" +msgstr "" + +msgid "Update Model" +msgstr "" + +msgid "Update Subscription" +msgstr "" + +msgid "Update succeeded" +msgstr "" + +msgid "Updating" +msgstr "" + +msgid "Updating $1" +msgstr "" + +msgid "Updating all subscriptions…" +msgstr "" + +msgid "Updating…" +msgstr "" + +msgid "Unable to read backup file" +msgstr "" + +msgid "Upload" +msgstr "" + +msgid "Upload Configuration File" +msgstr "" + +msgid "Upload failed" +msgstr "" + +msgid "Upload failed: " +msgstr "" + +msgid "Upload offset mismatch" +msgstr "" + +msgid "Upload JSON Configuration" +msgstr "" + +msgid "Upload succeeded: " +msgstr "" + +msgid "Upload YAML Template" +msgstr "" + +msgid "Upstream DNS" +msgstr "" + +msgid "Url-test" +msgstr "" + +msgid "Use DNS" +msgstr "" + +msgid "Use LightGBM model to predict weights" +msgstr "" + +msgid "Used to resolve DoH/DoT/DoQ server domains; plain IP DNS is recommended." +msgstr "" + +msgid "User-Agent (UA)" +msgstr "" + +msgid "Username" +msgstr "" + +msgid "Virtual IP Ping Hijacking" +msgstr "" + +msgid "Wait for the current task to complete" +msgstr "" + +msgid "Waiting for data..." +msgstr "" + +msgid "When downloading core/data components, this prefix will be used first (a slash is required at the end). Leave blank to use the built-in gh-proxy.com and ghfast.top alternative sources." +msgstr "" + +msgid "When enabled, direct / proxy / fallback roles each use an independent DNS cache. Useful when the same domain needs different resolver chains by routing. Usually not needed." +msgstr "" + +msgid "When enabled, sniffer configuration is injected automatically to improve streaming domain detection and routing stability." +msgstr "" + +msgid "YAML Subscription Conversion" +msgstr "" + +msgid "⏳ A download task is already running..." +msgstr "" + +msgid "⏳ Fetch timed out, refreshing to show results..." +msgstr "" + +msgid "⏳ Fetching configuration..." +msgstr "" + +msgid "⏳ Starting update task..." +msgstr "" + +msgid "⏳ Submitting download task..." +msgstr "" + +msgid "✗ Fetch error: " +msgstr "" + +msgid "✗ Fetch failed: " +msgstr "" + +msgid "✗ Panel update timeout" +msgstr "" + +msgid "✗ Please enter a subscription URL" +msgstr "" + +msgid "✗ Please enter a subscription URL first" +msgstr "" + +msgid "✗ Start failed" +msgstr "" + +msgid "✗ Start failed: " +msgstr "" + +msgid "✗ Submission failed" +msgstr "" diff --git a/luci-app-clashoo/po/zh-cn/clashoo.po b/luci-app-clashoo/po/zh-cn/clashoo.po new file mode 100644 index 000000000..fe30cb1b9 --- /dev/null +++ b/luci-app-clashoo/po/zh-cn/clashoo.po @@ -0,0 +1,1579 @@ +msgid "" +msgstr "" +"Content-Type: text/plain; charset=UTF-8\n" +"Project-Id-Version: luci-app-clashoo\n" +"PO-Revision-Date: 2026-07-10 09:23+0800\n" +"Last-Translator: kenzok8 \n" +"Language-Team: Chinese (Simplified)\n" +"Language: zh_CN\n" +"MIME-Version: 1.0\n" +"Content-Transfer-Encoding: 8bit\n" + +msgid " (auto-detected by device)" +msgstr "(按设备自动检测)" + +msgid " (expired)" +msgstr "(已过期)" + +msgid " (refreshing)" +msgstr "(刷新中)" + +msgid " candidates" +msgstr " 个候选" + +msgid " days)" +msgstr " 天)" + +msgid " files)" +msgstr " 个文件)" + +msgid " groups" +msgstr " 组" + +msgid " latency test failed: " +msgstr " 测速失败: " + +msgid " saved" +msgstr " 已保存" + +msgid " seconds" +msgstr " 秒" + +msgid " switch error" +msgstr " 切换异常" + +msgid " switch failed: " +msgstr " 切换失败: " + +msgid " update succeeded" +msgstr " 更新成功" + +msgid " updated" +msgstr " 已更新" + +msgid "$1 updated" +msgstr "$1 已更新" + +msgid "(empty)" +msgstr "(空)" + +msgid ", click Start to take effect" +msgstr ",点击启动后生效" + +msgid ", failed " +msgstr ",失败 " + +msgid ", skipped " +msgstr ",跳过 " + +msgid ", switched to active configuration" +msgstr ",已切换为活动配置" + +msgid ", switching to active configuration..." +msgstr ",正在切换为活动配置..." + +msgid ", unchanged " +msgstr ",未变化 " + +msgid "; updated " +msgstr ";更新 " + +msgid "(empty)" +msgstr "(空)" + +msgid "China traffic bypasses the core at firewall level; DNS behavior is slightly weaker. Choose as needed." +msgstr "大陆流量在防火墙层直接绕过核心,DNS 体验略弱。按需选择。" + +msgid "Fast resolution and accurate routing; China routing is handled by the core." +msgstr "解析快、分流准,大陆分流由内核完成。" + +msgid "Prerequisite: The configuration must include transparent proxying (TUN auto-route or TProxy inbound). Takes effect after restart." +msgstr "前提:配置自带透明代理(TUN auto-route 或 TProxy 入站),重启生效。" + +msgid "Warning: IPv6 resolution is also disabled when IPv6 Proxy is off, to keep the real address from leaking." +msgstr "注意:「IPv6 代理」关闭时会一并停用 IPv6 解析,避免真实地址泄漏。" + +msgid "Not detected, please select" +msgstr "未检测到,请手动选择" + +msgid "Could not detect the device architecture; select it manually before updating the core." +msgstr "未能识别设备架构,更新内核前请先手动选择。" + +msgid "Access Check" +msgstr "访问检查" + +msgid "Access Control" +msgstr "访问控制" + +msgid "Access Secret" +msgstr "访问密钥" + +msgid "Actions" +msgstr "操作" + +msgid "Active" +msgstr "使用中" + +msgid "Advanced DNS" +msgstr "高级 DNS" + +msgid "Advanced Settings (core / data components)" +msgstr "高级设置(内核 / 数据组件)" + +msgid "For providers that directly offer sing-box JSON subscriptions, or links already converted by external tools. After fetching, click Update on the corresponding item in the Configuration Files tab to fetch the latest configuration again." +msgstr "适用于机场直接提供 sing-box JSON 格式订阅、或已用外部工具转换好的链接。拉取后可在「配置文件」标签的对应条目点击「更新」重新拉取最新配置。" + +msgid "All" +msgstr "全部" + +msgid "All components are up to date" +msgstr "所有组件已是最新" + +msgid "All Devices" +msgstr "所有设备" + +msgid "All Ports" +msgstr "所有端口" + +msgid "Allow LAN Access" +msgstr "允许局域网连接" + +msgid "Allowlist" +msgstr "白名单" + +msgid "Allowlist (only listed items use fake-IP)" +msgstr "白名单(仅列入走 fake-IP)" + +msgid "Alpha" +msgstr "Alpha 版" + +msgid "Already up to date" +msgstr "已是最新版本" + +msgid "Apply Configuration" +msgstr "应用配置" + +msgid "Applying…" +msgstr "应用中…" + +msgid "ASN Priority" +msgstr "ASN 优先" + +msgid "Auto Scroll" +msgstr "自动滚动" + +msgid "Auto setup completed." +msgstr "自动配置已完成。" + +msgid "Auto Update Model" +msgstr "自动更新模型" + +msgid "Auto-detected" +msgstr "自动识别" + +msgid "Automatically choose available DNS and update only upstream servers; split policies and advanced settings remain unchanged." +msgstr "自动选择可用 DNS,仅更新上游服务器;分流策略和高级设置保持不变。" + +msgid "Automatically switch Url-test and Load-balance policy groups to Smart policy groups" +msgstr "自动切换 Url-test、Load-balance 策略组到 Smart 策略组" + +msgid "Automation Tasks" +msgstr "自动化任务" + +msgid "Backend Core" +msgstr "后端核心" + +msgid "Backup and Restore" +msgstr "备份与还原" + +msgid "Backup file is too large" +msgstr "备份文件过大" + +msgid "Backup exported" +msgstr "备份已导出" + +msgid "Backup exported (" +msgstr "备份已导出(" + +msgid "Backup files contain subscription and node credentials. Store them securely." +msgstr "备份文件包含订阅和节点凭据,请妥善保管。" + +msgid "Backup restored, restarting service" +msgstr "已还原备份,正在重启服务" + +msgid "Basic DNS" +msgstr "基础 DNS" + +msgid "Block QUIC" +msgstr "阻断 QUIC" + +msgid "Blocklist" +msgstr "黑名单" + +msgid "Blocklist (listed items use real IP, default)" +msgstr "黑名单(列入走真 IP,默认)" + +msgid "Blocklist mode: enter domains or shorthand like geosite:cn. Rule mode: entries are converted to rule syntax automatically, such as GEOSITE,cn,real-ip / RULE-SET,xxx,real-ip; usually add MATCH,fake-ip at the end as fallback. geosite:cn automatically uses built-in cn.mrs acceleration and avoids loading the 10MB geosite.dat. Allowlist mode drops the shipped defaults (they mean the opposite there), so enter your own domains." +msgstr "黑名单模式:填域名或 geosite:cn 简写。规则模式:条目会自动转成 GEOSITE,cn,real-ip / RULE-SET,xxx,real-ip 这种与 rules 同语法的写法,末尾通常加一条 MATCH,fake-ip 兜底。填 geosite:cn 会自动改用内置 cn.mrs 加速,免加载 10MB geosite.dat。白名单模式下随包自带的默认项含义相反,会被跳过,请自行填写需要 Fake-IP 的域名。" + +msgid "Bypass China IPv4" +msgstr "大陆 IPv4 绕过" + +msgid "Bypass China IPv6" +msgstr "大陆 IPv6 绕过" + +msgid "Bypass Ports" +msgstr "绕过端口" + +msgid "Bypass Rules" +msgstr "绕过规则" + +msgid "ByteDance" +msgstr "字节跳动" + +msgid "Cannot connect to core API. Check runtime status." +msgstr "无法连接核心 API,请检查运行状态" + +msgid "Check and Update" +msgstr "检查并更新" + +msgid "Check Updates" +msgstr "检查更新" + +msgid "Checking configuration file" +msgstr "正在检查配置文件" + +msgid "Checking environment…" +msgstr "检查环境…" + +msgid "Checking…" +msgstr "检查中…" + +msgid "Cleaning mihomo network rules" +msgstr "清理 mihomo 网络规则" + +msgid "Cleaning sing-box network rules" +msgstr "清理 sing-box 网络规则" + +msgid "Cleanup failed (mihomo may not be running)" +msgstr "清理失败(mihomo 可能未运行)" + +msgid "Cleanup interval (hours)" +msgstr "清理间隔(小时)" + +msgid "Clear" +msgstr "清理" + +msgid "Clear File" +msgstr "清空文件" + +msgid "Clear Smart Cache" +msgstr "清理 Smart 缓存" + +msgid "Clear the current log file? This cannot be undone." +msgstr "确定要清空当前日志文件吗?此操作不可恢复。" + +msgid "Clear View" +msgstr "清空显示" + +msgid "Click Save after editing; switching configuration automatically restarts the service" +msgstr "编辑后点击保存;切换配置后服务将自动重启" + +msgid "Collapse" +msgstr "折叠" + +msgid "Collect node latency data for LightGBM model training" +msgstr "收集节点延迟数据供 LightGBM 模型训练" + +msgid "Collect Training Data" +msgstr "收集训练数据" + +msgid "Common Ports" +msgstr "常用端口" + +msgid "Completed" +msgstr "已完成" + +msgid "Component update task submitted" +msgstr "组件更新任务已提交" + +msgid "Component Updates" +msgstr "组件更新" + +msgid "Configuration" +msgstr "配置" + +msgid "Configuration content appears here after selecting a file…" +msgstr "选择配置文件后内容将显示在这里…" + +msgid "Configuration file name (optional, blank auto-generates singbox.json)" +msgstr "配置文件名(选填,留空自动生成 singbox.json)" + +msgid "Configuration Files" +msgstr "配置文件" + +msgid "Configuration is up to date; no fixes needed" +msgstr "配置已是最新,无需修复" + +msgid "Configuration saved" +msgstr "配置已保存" + +msgid "Configuration saved and service hot-reloaded" +msgstr "配置已保存并热重载服务" + +msgid "Configuration saved, service is not running" +msgstr "配置已保存,服务未启动" + +msgid "Configuration saved, service remains stopped" +msgstr "配置已保存,服务保持停止" + +msgid "Configuration saved, switched and started selected core" +msgstr "配置已保存,已切换并启动所选内核" + +msgid "Connection failed" +msgstr "连接失败" + +msgid "Connections" +msgstr "连接" + +msgid "Convert YAML subscriptions to sing-box JSON, automatically injecting TUN transparent proxy and China direct rules. Files with the same name are overwritten; use the same name when updating." +msgstr "将 YAML 订阅转换为 sing-box JSON,自动注入 TUN 透明代理与大陆直连规则。同名文件直接覆盖,更新时填相同名称即可。" + +msgid "Core and Data" +msgstr "内核与数据" + +msgid "Core did not start within 15 seconds (procd is recovering)" +msgstr "内核未在 15 秒内启动(procd 自愈中)" + +msgid "Core Download" +msgstr "内核下载" + +msgid "Core is not running. Start it before switching nodes." +msgstr "核心未运行,启动后可切换节点" + +msgid "Core Log" +msgstr "核心日志" + +msgid "Core Only (advanced)" +msgstr "仅内核(进阶)" + +msgid "Core Switch" +msgstr "内核切换" + +msgid "Core switch failed" +msgstr "切换内核失败" + +msgid "Core Type" +msgstr "核心类型" + +msgid "Core type saved, takes effect on next start or restart" +msgstr "内核类型已保存,下次启动或重启后生效" + +msgid "Core verification failed. Check System → Core." +msgstr "内核校验未通过,请到「系统 → 内核」检查" + +msgid "Correct routing by forcing a domain or IP to Direct or Proxy. These rules take priority over subscription rules and apply to both mihomo and sing-box." +msgstr "纠正分流:把某个域名或 IP 强制走「直连」或「代理」,规则优先于订阅自带规则,mihomo 与 sing-box 均生效。" + +msgid "CPU Architecture" +msgstr "处理器架构" + +msgid "CPU architecture set to " +msgstr "处理器架构已设为 " + +msgid "curl or wget not found" +msgstr "未找到 curl 或 wget" + +msgid "Current configuration has no manually switchable proxy groups" +msgstr "当前配置没有可手动切换的节点组" + +msgid "Current configuration has no recorded subscription URL" +msgstr "当前配置未记录订阅链接" + +msgid "Current configuration is a custom file; no subscription update needed" +msgstr "当前配置为自定义文件,无需更新订阅" + +msgid "Current version: " +msgstr "当前版本: " + +msgid "Current: %s" +msgstr "当前:%s" + +msgid "Custom" +msgstr "自定义" + +msgid "Custom Ports" +msgstr "自定义端口" + +msgid "Custom Routing Rules" +msgstr "自定义分流规则" + +msgid "Custom User-Agent" +msgstr "自定义 User-Agent" + +msgid "Customize..." +msgstr "自定义..." + +msgid "Dashboard" +msgstr "管理面板" + +msgid "Dashboard Port" +msgstr "面板端口" + +msgid "Dashboard Settings" +msgstr "管理面板配置" + +msgid "Default" +msgstr "默认" + +msgid "Degraded" +msgstr "降级运行" + +msgid "Delete" +msgstr "删除" + +msgid "Delete " +msgstr "删除 " + +msgid "Direct" +msgstr "直连" + +msgid "Direct Domain Resolver" +msgstr "直连域名解析" + +msgid "Disable QUIC GSO" +msgstr "禁用 QUIC GSO" + +msgid "Disabling DNS cache" +msgstr "禁用 DNS 缓存" + +msgid "DNS Address" +msgstr "DNS 地址" + +msgid "DNS Auto Setup" +msgstr "DNS 自动配置" + +msgid "DNS auto setup applied, service is restarting" +msgstr "DNS 自动配置已应用,服务正在重启" + +msgid "DNS auto setup failed" +msgstr "DNS 自动配置失败" + +msgid "DNS auto setup failed: " +msgstr "DNS 自动配置失败: " + +msgid "DNS auto setup saved, service is not running" +msgstr "DNS 自动配置已保存,服务未启动" + +msgid "DNS configuration saved and service hot-reloaded" +msgstr "DNS 配置已保存并热重载服务" + +msgid "DNS configuration saved, service is not running" +msgstr "DNS 配置已保存,服务未启动" + +msgid "DNS Listen Port" +msgstr "DNS 监听端口" + +msgid "DNS Policy" +msgstr "分流解析策略" + +msgid "DNS queries follow the routing rules, so overseas domains resolve through the proxy instead of a polluted result. Requires proxy-server-nameserver." +msgstr "DNS 查询按分流规则走,境外域名经代理解析,避免拿到污染结果。需要配置节点域名解析(proxy-server-nameserver)。" + +msgid "DNS Respect Rules" +msgstr "DNS 遵循分流规则" + +msgid "Domain / IP" +msgstr "域名 / IP" + +msgid "Domain keyword (e.g. youtube)" +msgstr "域名关键词(如 youtube)" + +msgid "Domain Split DNS" +msgstr "域名分流解析" + +msgid "Domain suffix (e.g. google.com)" +msgstr "域名后缀(如 google.com)" + +msgid "Domestic" +msgstr "国内" + +msgid "Domestic Upstream DNS" +msgstr "国内上游 DNS" + +msgid "Download" +msgstr "下载" + +msgid "Download failed (error code $1)" +msgstr "下载失败(错误码 $1)" + +msgid "Download Subscription" +msgstr "下载订阅" + +msgid "Download succeeded" +msgstr "下载成功" + +msgid "Downloaded Subscriptions" +msgstr "已下载订阅" + +msgid "Downloading LightGBM model..." +msgstr "正在下载 LightGBM 模型..." + +msgid "Downloading subscription..." +msgstr "正在下载订阅..." + +msgid "Downloading..." +msgstr "下载中..." + +msgid "Downloading…" +msgstr "下载中…" + +msgid "ECS Client Subnet" +msgstr "ECS 客户端子网" + +msgid "Edit" +msgstr "编辑" + +msgid "Editing: " +msgstr "编辑:" + +msgid "Enable" +msgstr "启用" + +msgid "Enable DNS Module" +msgstr "启用 DNS 模块" + +msgid "Enable LightGBM Model" +msgstr "启用 LightGBM 模型" + +msgid "Enable Service" +msgstr "启用服务" + +msgid "Enhanced Mode" +msgstr "增强模式" + +msgid "Enter remote template URL, e.g. https://raw.githubusercontent.com/…/Clash.yaml" +msgstr "输入远程模板 URL,例如 https://raw.githubusercontent.com/…/Clash.yaml" + +msgid "Enter subscription URL (injected into template proxy-providers)" +msgstr "输入订阅链接 URL(注入到模板的 proxy-providers)" + +msgid "Every" +msgstr "每" + +msgid "Exact domain (e.g. www.google.com)" +msgstr "精确域名(如 www.google.com)" + +msgid "example.com or 1.2.3.0/24" +msgstr "example.com 或 1.2.3.0/24" + +msgid "Example: geosite:cn uses https://dns.alidns.com/dns-query; geosite:geolocation-!cn uses https://cloudflare-dns.com/dns-query." +msgstr "示例:geosite:cn 使用 https://dns.alidns.com/dns-query;geosite:geolocation-!cn 使用 https://cloudflare-dns.com/dns-query。" + +msgid "Expand" +msgstr "展开" + +msgid "Expires: " +msgstr "到期:" + +msgid "Export a backup before changing cores or configuration, so it can be restored if needed. Includes configuration and settings only, not cores." +msgstr "折腾内核或配置前先导出一份,改坏了能一键导入还原。仅含配置与设置,不含内核。" + +msgid "Export Backup" +msgstr "导出备份" + +msgid "Export failed: " +msgstr "导出失败:" + +msgid "Exporting…" +msgstr "导出中…" + +msgid "Factory defaults restored" +msgstr "已还原出厂默认设置" + +msgid "Failed" +msgstr "失败" + +msgid "Failed to check updates, please check the network" +msgstr "检查更新失败,请检查网络" + +msgid "Failed to save core configuration" +msgstr "内核配置保存失败" + +msgid "Failed to submit component update task" +msgstr "组件更新任务提交失败" + +msgid "Fake-IP Filter Domains" +msgstr "Fake-IP 过滤域名" + +msgid "Fake-IP Filter Mode" +msgstr "Fake-IP 过滤模式" + +msgid "Fake-IP Range" +msgstr "Fake-IP 网段" + +msgid "Fallback" +msgstr "故障转移" + +msgid "Fallback GeoIP Filter" +msgstr "Fallback GeoIP 过滤" + +msgid "Bootstrap" +msgstr "引导 DNS" + +msgid "Fetch and Apply" +msgstr "拉取并应用" + +msgid "Fetch Configuration" +msgstr "拉取配置" + +msgid "Fetching…" +msgstr "拉取中…" + +msgid "File Name" +msgstr "文件名" + +msgid "File name (optional, blank for automatic name)" +msgstr "文件名(选填,留空自动命名)" + +msgid "File name (optional, blank to auto-generate)" +msgstr "文件名(选填,留空自动生成)" + +msgid "Fix Deprecated Fields" +msgstr "修复废弃字段" + +msgid "Fix failed: " +msgstr "修复失败: " + +msgid "Fixed deprecated fields: " +msgstr "已修复废弃字段: " + +msgid "Force ASN lookup and prefer target ASN information when selecting nodes for a more stable experience" +msgstr "选择节点时强制查找并优先使用目标的 ASN 信息,以获得更稳定的体验" + +msgid "Force DNS Forwarding" +msgstr "强制转发 DNS" + +msgid "Force ECS Override" +msgstr "强制覆盖 ECS" + +msgid "Full URL / no protocol prefix" +msgstr "完整 URL / 不补协议" + +msgid "Generate Configuration" +msgstr "生成配置" + +msgid "Generate error: " +msgstr "生成异常: " + +msgid "Generate failed: " +msgstr "生成失败: " + +msgid "Generated: " +msgstr "生成成功: " + +msgid "Generating…" +msgstr "生成中…" + +msgid "Generation is taking longer, refreshing to show results…" +msgstr "生成时间较长,正在刷新查看结果…" + +msgid "GeoIP Source" +msgstr "GeoIP 数据源" + +msgid "GeoIP update completed" +msgstr "GeoIP 更新完成" + +msgid "GeoIP update completed, applies after Clashoo restarts" +msgstr "GeoIP 更新完成,重启 Clashoo 后生效" + +msgid "GeoIP update failed" +msgstr "GeoIP 更新失败" + +msgid "GitHub acceleration prefix" +msgstr "GitHub 加速前缀" + +msgid "Global" +msgstr "全局" + +msgid "Health check failed" +msgstr "健康检查失败" + +msgid "Health check in progress…" +msgstr "健康检查中…" + +msgid "Health check passed" +msgstr "健康检查通过" + +msgid "hours" +msgstr "小时" + +msgid "HTTP Port" +msgstr "HTTP 端口" + +msgid "Import failed: " +msgstr "导入失败:" + +msgid "Import Restore" +msgstr "导入还原" + +msgid "Importing will overwrite all current configuration and settings with the backup. Existing subscriptions/configuration files will be replaced. Continue?" +msgstr "导入将用备份覆盖当前的全部配置与设置,原有的订阅/配置文件会被替换。确定继续吗?" + +msgid "Information Input" +msgstr "信息录入" + +msgid "Initializing…" +msgstr "初始化中…" + +msgid "Intercept IPv6 DNS traffic to prevent devices with hard-coded DNS from bypassing the traffic." +msgstr "拦截 IPv6 DNS 流量,防止写死 DNS 的设备绕过分流。" + +msgid "IP / CIDR (e.g. 8.8.8.8/32)" +msgstr "IP / CIDR(如 8.8.8.8/32)" + +msgid "IP Allowlist" +msgstr "IP白名单" + +msgid "IP Blocklist" +msgstr "IP黑名单" + +msgid "IP rules do not trigger DNS resolution" +msgstr "IP 规则不触发 DNS 解析" + +msgid "IPv4 DNS Hijack" +msgstr "IPv4 DNS 劫持" + +msgid "IPv4 Proxy" +msgstr "IPv4 代理" + +msgid "IPv6 DNS Hijack" +msgstr "IPv6 DNS 劫持" + +msgid "IPv6 Proxy" +msgstr "IPv6 代理" + +msgid "just now" +msgstr "刚刚" + +msgid "Keep the default if unsure." +msgstr "不确定时保持默认。" + +msgid "LAN Control" +msgstr "局域网控制" + +msgid "%d updates available" +msgstr "发现 %d 项可更新" + +msgid "Last check: initializing" +msgstr "上次检查:初始化中" + +msgid "Last check: just now" +msgstr "上次检查:刚刚" + +msgid "Last check: %d seconds ago" +msgstr "上次检查:%d 秒前" + +msgid "Last check: %d minutes ago" +msgstr "上次检查:%d 分钟前" + +msgid "Last check: %d hours ago" +msgstr "上次检查:%d 小时前" + +msgid "Last run: " +msgstr "上次执行:" + +msgid "LightGBM model file download URL; leave blank to use the default official URL" +msgstr "LightGBM 模型文件下载地址,留空使用默认官方地址" + +msgid "LightGBM model updated successfully" +msgstr "LightGBM 模型更新成功" + +msgid "Load failed" +msgstr "加载失败" + +msgid "Load-balance" +msgstr "负载均衡" + +msgid "Loading…" +msgstr "加载中…" + +msgid "Local Template" +msgstr "本地模板" + +msgid "Log" +msgstr "日志" + +msgid "Match Rule" +msgstr "匹配规则" + +msgid "Memory usage %s" +msgstr "内存使用 %s" + +msgid "mihomo restarted successfully, please wait for servers to come online." +msgstr "mihomo 重启成功,请等待服务器上线!" + +msgid "mihomo Stable" +msgstr "mihomo 稳定版" + +msgid "mihomo started successfully, please wait for servers to come online." +msgstr "mihomo 启动成功,请等待服务器上线!" + +msgid "mihomo writes the ecs parameter to DNS URLs; sing-box writes dns.client_subnet. Leave empty to skip." +msgstr "Mihomo 写入 DNS URL 的 ecs 参数;sing-box 写入 dns.client_subnet。清空则不写入。" + +msgid "Mixed Mode" +msgstr "Mixed 模式" + +msgid "Mixed Port" +msgstr "混合端口" + +msgid "Mode" +msgstr "模式" + +msgid "Model Download URL" +msgstr "模型下载 URL" + +msgid "Model install failed: $1" +msgstr "模型安装失败:$1" + +msgid "Model is already up to date" +msgstr "模型已是最新版本,无需更新" + +msgid "Model not installed" +msgstr "模型未安装" + +msgid "Network Stack" +msgstr "网络栈" + +msgid "Network Stack Type" +msgstr "网络栈类型" + +msgid "No auto setup result yet" +msgstr "暂无自动配置结果" + +msgid "No component update logs yet" +msgstr "暂无组件更新日志" + +msgid "No configuration file found. Import a subscription or upload a configuration on the Configuration page first." +msgstr "未找到配置文件,请先在「配置」页导入订阅或上传配置" + +msgid "No configuration file selected. Select or upload one on the Configuration page before starting." +msgstr "未选择配置文件,请先到「配置」页选择或上传后选中再启动" + +msgid "No configuration files yet. Use Quick Wizard to generate one or upload a JSON file." +msgstr "暂无配置文件,请使用快速向导生成或上传 JSON 文件" + +msgid "No proxy groups" +msgstr "无节点组" + +msgid "No subscriptions" +msgstr "暂无订阅" + +msgid "Node Panel ›" +msgstr "节点面板 ›" + +msgid "Node Selection" +msgstr "节点选择" + +msgid "Node Subscription" +msgstr "节点订阅" + +msgid "Node weight bonus. <1 means lower priority, >1 means higher priority. Modify as needed; leave blank to skip policy-priority injection." +msgstr "节点权重加成,<1 表示较低优先级,>1 表示较高优先级;可按需修改,留空则不注入 policy-priority" + +msgid "Not installed" +msgstr "未安装" + +msgid "Not enabled" +msgstr "未启用" + +msgid "Not running" +msgstr "未运行" + +msgid "Off" +msgstr "关闭" + +msgid "Only subscriptions with recorded source URLs are overwritten; no duplicate files are created." +msgstr "仅覆盖已记录来源链接的订阅,不会生成重复文件。" + +msgid "Only .tar.gz and legacy .json backup files are supported" +msgstr "仅支持 .tar.gz 和旧版 .json 备份文件" + +msgid "Open Dashboard" +msgstr "打开面板" + +msgid "TUN stack is used when either TCP or UDP mode is TUN." +msgstr "TCP 或 UDP 任意一个选择 TUN 时,该栈设置才会生效。" + +msgid "OpenClash is enabled; disable it first to avoid rule conflicts" +msgstr "OpenClash 已启用,请先停用以避免规则冲突" + +msgid "OpenClash/Nikki Loopback DNS Compatibility" +msgstr "OpenClash/Nikki 回环 DNS 兼容" + +msgid "Optional compatibility for normal managed mode. At runtime, replace only proxy node resolvers that point back to the imported configuration's own DNS listener with the proxy-server-nameserver setting. Core Only mode stays verbatim; the source configuration and unrelated local DNS services remain unchanged." +msgstr "用于普通接管模式的可选兼容功能。运行时仅把指回导入配置自身 DNS 监听的节点解析器替换为 proxy-server-nameserver(节点域名解析)的设置;仅内核模式保持原样,源配置和其他本地 DNS 服务不受影响。" + +msgid "Operation failed: " +msgstr "操作失败: " + +msgid "Other Configuration Files (upload / overwrite output)" +msgstr "其他配置文件(上传 / 覆写输出)" + +msgid "Output file name (without extension, blank to auto-fill)" +msgstr "输出文件名(不含扩展名,留空自动填写)" + +msgid "Overseas" +msgstr "境外" + +msgid "Overseas Encrypted DNS (anti-pollution)" +msgstr "国外加密 DNS(防污染)" + +msgid "Overview" +msgstr "概览" + +msgid "Overwrite Settings" +msgstr "覆写设置" + +msgid "Panel" +msgstr "面板" + +msgid "Panel is downloading" +msgstr "面板正在下载" + +msgid "Panel switch failed: " +msgstr "面板切换失败: " + +msgid "Panel UI" +msgstr "面板 UI" + +msgid "Password" +msgstr "密码" + +msgid "Paste native sing-box subscription URL (direct JSON response)" +msgstr "粘贴原生 sing-box 订阅链接(直接返回 JSON 的链接)" + +msgid "Paste subscription URL (supports vmess / vless / trojan, etc.)" +msgstr "粘贴订阅链接(支持 vmess / vless / trojan 等)" + +msgid "Pause" +msgstr "暂停" + +msgid "Period for automatically fetching a new model; also controls the cron trigger frequency, default 72 hours" +msgstr "自动拉取新模型的周期,同时决定 cron 触发频率,默认 72 小时" + +msgid "Please enter a remote template URL" +msgstr "请输入远程模板 URL" + +msgid "Please enter a subscription URL" +msgstr "请输入订阅链接 URL" + +msgid "Please enter an output file name" +msgstr "请填写输出文件名" + +msgid "Please select a local template file" +msgstr "请选择本地模板文件" + +msgid "Plugin Log" +msgstr "插件日志" + +msgid "Policy Priority (weight bonus)" +msgstr "Policy Priority(权重加成)" + +msgid "Policy Type" +msgstr "策略类型" + +msgid "Port" +msgstr "端口" + +msgid "Port Settings" +msgstr "端口配置" + +msgid "Prevent DNS Leaks" +msgstr "防 DNS 泄漏" + +msgid "Processing…" +msgstr "处理中…" + +msgid "Protocol" +msgstr "协议" + +msgid "Proxy" +msgstr "代理" + +msgid "DNS Takeover" +msgstr "DNS 接管" + +msgid "IPv4" +msgstr "IPv4" + +msgid "IPv6" +msgstr "IPv6" + +msgid "MAC" +msgstr "MAC" + +msgid "Rules are matched from top to bottom. Unmatched devices use DNS takeover and proxy by default. A rule with IPv4, IPv6 and MAC all empty matches every device." +msgstr "规则按从上到下的顺序匹配;未命中的设备默认接管 DNS 并走代理。IPv4、IPv6、MAC 全部留空的规则匹配所有设备。" + +msgid "Proxy Authentication" +msgstr "代理认证" + +msgid "Proxy configuration saved and service hot-reloaded" +msgstr "代理配置已保存并热重载服务" + +msgid "Proxy configuration saved, service is not running" +msgstr "代理配置已保存,服务未启动" + +msgid "Proxy Domain Split DNS" +msgstr "代理域名分流解析" + +msgid "Proxy Mode" +msgstr "代理模式" + +msgid "Proxy Node Domain Resolver" +msgstr "节点域名解析专用" + +msgid "Quick Wizard" +msgstr "快速向导" + +msgid "Random" +msgstr "随机" + +msgid "Ready · " +msgstr "就绪 · " + +msgid "Ready ✓" +msgstr "已就绪 ✓" + +msgid "Recommended " +msgstr "推荐 " + +msgid "Recommended" +msgstr "推荐" + +msgid "Recommended blank" +msgstr "推荐留空" + +msgid "Redirect Port" +msgstr "Redirect 端口" + +msgid "Refresh" +msgstr "刷新" + +msgid "Refresh Access Check" +msgstr "刷新访问检查" + +msgid "Regular domains use overseas DNS only and follow proxy rules; DoT/DoQ is blocked. Takes effect after restart.
    " +msgstr "普通域名只走境外 DNS 并遵守代理规则,阻断 DoT/DoQ。重启生效。
    " + +msgid "Regularly update rule data" +msgstr "定时更新规则数据" + +msgid "Reject proxied UDP 443 so some apps fall back to TCP. Try only when downloads or video stall." +msgstr "拒绝代理链路中的 UDP 443,让部分 App 回落 TCP。仅在下载/视频卡住时尝试开启。" + +msgid "Relay" +msgstr "链式代理" + +msgid "Remote Template" +msgstr "远程模板" + +msgid "Remote: %s" +msgstr "远端:%s" + +msgid "Removing Cron scheduled tasks" +msgstr "删除 Cron → 计划任务" + +msgid "Requires MMDB. If enabled while the local GeoIP database is missing, the core may fail to start. Usually not needed." +msgstr "依赖 MMDB;若启用但本地 GeoIP 数据库缺失,可能导致内核启动失败。一般无需开启。" + +msgid "Restarting client..." +msgstr "正在重启客户端..." + +msgid "Restarting Dnsmasq" +msgstr "重启 Dnsmasq 程序" + +msgid "Restore Clashoo settings to factory defaults (subscriptions and configuration files are kept). Continue?" +msgstr "将把 clashoo 的设置恢复为出厂默认值(订阅与配置文件保留)。确定继续吗?" + +msgid "Restore Defaults" +msgstr "还原默认配置" + +msgid "Restore failed: " +msgstr "还原失败:" + +msgid "Restoring…" +msgstr "还原中…" + +msgid "Role" +msgstr "角色" + +msgid "Rule" +msgstr "规则" + +msgid "Rule data includes China allowlist (direct IP ranges) and GeoIP / GeoSite databases" +msgstr "规则数据包含:大陆白名单(直连 IP 段)与 GeoIP / GeoSite 地理库" + +msgid "Rule mode (same syntax as rules)" +msgstr "规则模式(与 rules 同语法)" + +msgid "Rules and Control" +msgstr "规则与控制" + +msgid "Run Mode" +msgstr "运行模式" + +msgid "Run mode setting failed: " +msgstr "运行模式设置失败: " + +msgid "Run only the core with your imported configuration, without taking over firewall / DNS / routing. Compatible with nikki, OpenClash, momo and homeproxy configurations.
    " +msgstr "只用你导入的配置跑内核,不接管防火墙 / DNS / 路由,兼容 nikki、OpenClash、momo、homeproxy 配置。
    " + +msgid "Running degraded" +msgstr "已降级运行" + +msgid "Running 🟢" +msgstr "运行中 🟢" + +msgid "Runtime Status" +msgstr "运行状态" + +msgid "Sample Rate" +msgstr "采样率" + +msgid "sample-rate, 1 = sample every latency test; increase to reduce sampling frequency" +msgstr "sample-rate,1 = 每次测速都采样,调大可降低采集频率" + +msgid "Save" +msgstr "保存" + +msgid "Save Configuration" +msgstr "保存配置" + +msgid "Save failed: " +msgstr "保存失败: " + +msgid "Scheduled Log Cleanup" +msgstr "定时清理日志" + +msgid "Scheduled Subscription Update" +msgstr "定时更新订阅" + +msgid "Scheduled update settings saved" +msgstr "定时更新设置已保存" + +msgid "Select a configuration above to edit it here" +msgstr "选择上方配置后可在此处编辑" + +msgid "Select local template file" +msgstr "选择本地模板文件" + +msgid "Select YAML file to upload" +msgstr "选择 YAML 文件上传" + +msgid "Selector" +msgstr "选择器" + +msgid "Service disabled" +msgstr "服务已禁用" + +msgid "Service stopped" +msgstr "服务已停止" + +msgid "Setting Cron scheduled tasks and starting process supervisor..." +msgstr "设置 Cron → 计划任务,启动进程守护程序..." + +msgid "Setting DNS forwarder / enabling custom DNS" +msgstr "设置 DNS 转发器 / 启用自定义 DNS" + +msgid "Setting mihomo network rules" +msgstr "设置 mihomo 网络规则" + +msgid "Setting sing-box network rules" +msgstr "设置 sing-box 网络规则" + +msgid "Show/Hide" +msgstr "显示/隐藏" + +msgid "sing-box Configuration Files" +msgstr "sing-box 配置文件" + +msgid "sing-box core not detected; download sing-box from the System page" +msgstr "未检测到 sing-box 内核;请到系统页下载 sing-box" + +msgid "sing-box Independent DNS Cache" +msgstr "sing-box 独立 DNS 缓存" + +msgid "sing-box restarted successfully, please wait for servers to come online." +msgstr "sing-box 重启成功,请等待服务器上线!" + +msgid "sing-box service failed to start. Check System → Log." +msgstr "sing-box 服务启动失败,请到「系统 → 日志」查看" + +msgid "sing-box Stable" +msgstr "sing-box 稳定版" + +msgid "sing-box started successfully, please wait for servers to come online." +msgstr "sing-box 启动成功,请等待服务器上线!" + +msgid "Size" +msgstr "大小" + +msgid "Smart" +msgstr "Smart 版" + +msgid "Smart cache cleared" +msgstr "Smart 缓存已清理" + +msgid "Smart core not detected; updating the model will not install the core" +msgstr "未检测到 Smart 内核;更新模型不会安装内核" + +msgid "Smart core not detected; updating the model will not install the core. Download the Smart build from the System page." +msgstr "未检测到 Smart 内核;更新模型不会安装内核,请到系统页下载 Smart 版" + +msgid "Smart Policy Auto Switch" +msgstr "Smart 策略自动切换" + +msgid "Smart Policy Settings" +msgstr "Smart 策略设置" + +msgid "smart-collector-size, maximum retained training samples, default 100" +msgstr "smart-collector-size,最多保留的训练样本数,默认 100" + +msgid "Sniffer (streaming compatibility)" +msgstr "嗅探功能(流媒体兼容)" + +msgid "SOCKS5 Port" +msgstr "SOCKS5 端口" + +msgid "Stable" +msgstr "稳定版" + +msgid "Start downloading LightGBM model: $1" +msgstr "开始下载 LightGBM 模型:$1" + +msgid "Start failed: " +msgstr "启动失败: " + +msgid "Start Service" +msgstr "启动服务" + +msgid "Started (" +msgstr "已启动(" + +msgid "Starting client" +msgstr "启动客户端" + +msgid "Starting core…" +msgstr "启动内核…" + +msgid "Starting…" +msgstr "启动中…" + +msgid "Stop Service" +msgstr "停止服务" + +msgid "Stopped (not enabled at boot)" +msgstr "已停止(开机不自启动)" + +msgid "Stopped" +msgstr "已停止" + +msgid "Stopping client..." +msgstr "正在停止客户端..." + +msgid "Stopping mihomo" +msgstr "停止 mihomo" + +msgid "Stopping mihomo process supervisor" +msgstr "mihomo 停止进程守护程序" + +msgid "Stopping sing-box" +msgstr "停止 sing-box" + +msgid "Stopping sing-box process supervisor" +msgstr "sing-box 停止进程守护程序" + +msgid "Stopping…" +msgstr "停止中…" + +msgid "Submission failed" +msgstr "提交失败" + +msgid "Submitting" +msgstr "提交中" + +msgid "Subscription" +msgstr "订阅" + +msgid "Subscription download failed" +msgstr "订阅下载失败" + +msgid "Subscription Update" +msgstr "订阅更新" + +msgid "Subscription updated successfully" +msgstr "订阅更新成功" + +msgid "Subscription URL" +msgstr "订阅链接" + +msgid "Subscription URLs (one per line)" +msgstr "订阅链接(多条用换行分隔)" + +msgid "Switch" +msgstr "切换" + +msgid "Switch Profile" +msgstr "切换" + +msgid "Switch configuration failed: " +msgstr "切换配置失败: " + +msgid "Switch failed: " +msgstr "切换失败: " + +msgid "Switched to " +msgstr "已切换至 " + +msgid "Switching to " +msgstr "正在切换到 " + +msgid "Syncing" +msgstr "同步中" + +msgid "Syncing runtime state" +msgstr "正在同步运行状态" + +msgid "System" +msgstr "系统" + +msgid "System is missing nftables runtime" +msgstr "系统缺少 nftables 运行时" + +msgid "Target" +msgstr "走向" + +msgid "TCP Mode" +msgstr "TCP 模式" + +msgid "Template Selection" +msgstr "模板选择" + +msgid "Template upload failed: " +msgstr "模板上传失败: " + +msgid "Template uploaded: " +msgstr "模板上传成功: " + +msgid "Test and Apply" +msgstr "一键测速并应用" + +msgid "Test Latency" +msgstr "测速" + +msgid "Testing" +msgstr "测速中" + +msgid "Testing latency and writing upstream DNS…" +msgstr "正在测速并写入 DNS 上游…" + +msgid "The new core failed to start, please check the core log" +msgstr "新内核启动失败,请查看内核日志" + +msgid "Time" +msgstr "耗时" + +msgid "Timeout waiting for new core to start, please check the core log" +msgstr "等待新内核启动超时,请查看内核日志" + +msgid "Total %s" +msgstr "总计 %s" + +msgid "TPROXY Port" +msgstr "TPROXY 端口" + +msgid "Traffic Monitor" +msgstr "流量监控" + +msgid "Training Data Size" +msgstr "训练数据量" + +msgid "Transparent Proxy" +msgstr "透明代理" + +msgid "TUN Mode" +msgstr "TUN 模式" + +msgid "TUN Network Stack" +msgstr "TUN 网络栈" + +msgid "Type" +msgstr "类型" + +msgid "UDP Mode" +msgstr "UDP 模式" + +msgid "Unknown" +msgstr "未知" + +msgid "Unknown error" +msgstr "未知错误" + +msgid "Update" +msgstr "更新" + +msgid "Update All Now" +msgstr "立即更新全部" + +msgid "Update available" +msgstr "可更新" + +msgid "Update components individually. Click Check Updates to refresh versions." +msgstr "按组件单独更新,便于定位失败。点击「检查更新」刷新版本。" + +msgid "Update failed" +msgstr "更新失败" + +msgid "Update failed: " +msgstr "更新失败: " + +msgid "Update interval (hours)" +msgstr "更新间隔(小时)" + +msgid "Update interval must be 1 to 8760 hours" +msgstr "更新间隔必须为 1 到 8760 小时" + +msgid "Update Log" +msgstr "更新日志" + +msgid "Update Model" +msgstr "更新模型" + +msgid "Update Subscription" +msgstr "更新订阅" + +msgid "Update succeeded" +msgstr "更新成功" + +msgid "Updating" +msgstr "更新中" + +msgid "Updating $1" +msgstr "正在更新 $1" + +msgid "Updating all subscriptions…" +msgstr "正在更新全部订阅…" + +msgid "Updating…" +msgstr "更新中…" + +msgid "Unable to read backup file" +msgstr "无法读取备份文件" + +msgid "Upload" +msgstr "上传" + +msgid "Upload Configuration File" +msgstr "上传配置文件" + +msgid "Upload failed" +msgstr "上传失败" + +msgid "Upload failed: " +msgstr "上传失败: " + +msgid "Upload offset mismatch" +msgstr "上传偏移不匹配" + +msgid "Upload JSON Configuration" +msgstr "上传 JSON 配置" + +msgid "Upload succeeded: " +msgstr "上传成功: " + +msgid "Upload YAML Template" +msgstr "上传 YAML 模板" + +msgid "Upstream DNS" +msgstr "上游 DNS" + +msgid "Url-test" +msgstr "自动测速" + +msgid "Use DNS" +msgstr "使用 DNS" + +msgid "Use LightGBM model to predict weights" +msgstr "使用 LightGBM 模型来预测权重" + +msgid "Used to resolve DoH/DoT/DoQ server domains; plain IP DNS is recommended." +msgstr "用于解析 DoH/DoT/DoQ 服务器域名,建议填写纯 IP DNS。" + +msgid "User-Agent (UA)" +msgstr "用户代理(UA)" + +msgid "Username" +msgstr "用户名" + +msgid "Virtual IP Ping Hijacking" +msgstr "Fake-IP Ping 劫持" + +msgid "Wait for the current task to complete" +msgstr "等待当前任务完成" + +msgid "Waiting for data..." +msgstr "等待数据..." + +msgid "When downloading core/data components, this prefix will be used first (a slash is required at the end). Leave blank to use the built-in gh-proxy.com and ghfast.top alternative sources." +msgstr "内核 / 数据组件下载时优先走该前缀(末尾需带斜杠)。留空则使用内置 gh-proxy.com 与 ghfast.top 备选源。" + +msgid "When enabled, direct / proxy / fallback roles each use an independent DNS cache. Useful when the same domain needs different resolver chains by routing. Usually not needed." +msgstr "开启后,direct / proxy / fallback 等角色各自独立 DNS 缓存;适用于同一域名按分流走不同解析链的场景。一般无需开启。" + +msgid "When enabled, sniffer configuration is injected automatically to improve streaming domain detection and routing stability." +msgstr "启用后自动注入 sniffer 配置,提升流媒体域名识别与分流稳定性。" + +msgid "YAML Subscription Conversion" +msgstr "YAML 订阅转换" + +msgid "⏳ A download task is already running..." +msgstr "⏳ 已有下载任务进行中..." + +msgid "⏳ Fetch timed out, refreshing to show results..." +msgstr "⏳ 拉取超时,正在刷新查看结果..." + +msgid "⏳ Fetching configuration..." +msgstr "⏳ 正在拉取配置..." + +msgid "⏳ Starting update task..." +msgstr "⏳ 正在启动更新任务..." + +msgid "⏳ Submitting download task..." +msgstr "⏳ 正在提交下载任务..." + +msgid "✗ Fetch error: " +msgstr "✗ 拉取异常: " + +msgid "✗ Fetch failed: " +msgstr "✗ 拉取失败: " + +msgid "✗ Panel update timeout" +msgstr "✗ 面板更新超时" + +msgid "✗ Please enter a subscription URL" +msgstr "✗ 请填写订阅链接" + +msgid "✗ Please enter a subscription URL first" +msgstr "✗ 请先填写订阅链接" + +msgid "✗ Start failed" +msgstr "✗ 启动失败" + +msgid "✗ Start failed: " +msgstr "✗ 启动失败: " + +msgid "✗ Submission failed" +msgstr "✗ 提交失败" diff --git a/luci-app-clashoo/po/zh_Hans b/luci-app-clashoo/po/zh_Hans new file mode 120000 index 000000000..41451e4a1 --- /dev/null +++ b/luci-app-clashoo/po/zh_Hans @@ -0,0 +1 @@ +zh-cn \ No newline at end of file diff --git a/luci-app-clashoo/root/usr/share/clashoo/rpc/backup_archive.sh b/luci-app-clashoo/root/usr/share/clashoo/rpc/backup_archive.sh new file mode 100755 index 000000000..c600b36f6 --- /dev/null +++ b/luci-app-clashoo/root/usr/share/clashoo/rpc/backup_archive.sh @@ -0,0 +1,421 @@ +#!/bin/sh + +set -eu + +TMP_ROOT='/tmp/clashoo-backup' +RESTORE_LOCK_DIR="$TMP_ROOT/restore.lock" +IMPORT_LOCK_DIR="$TMP_ROOT/import.lock" +IMPORT_OWNER_FILE="$IMPORT_LOCK_DIR/path" +EXPORT_GUARD_DIR="$TMP_ROOT/export.lock" +MAX_ARCHIVE_BYTES=33554432 +MAX_EXTRACTED_BYTES=67108864 +MAX_TAR_BYTES=71303168 +MAX_EXTRACTED_KB=65536 +MAX_ENTRIES=2048 +WORK_DIR='' +EXTRACT_DIR='' +RESTORE_LOCKED=0 +EXPORT_GUARD_LOCKED=0 + +die() { + printf '%s\n' "$*" >&2 + exit 1 +} + +cleanup() { + case "$WORK_DIR" in + "$TMP_ROOT"/*) rm -rf "$WORK_DIR" ;; + esac + if [ "$RESTORE_LOCKED" -eq 1 ]; then + rmdir "$RESTORE_LOCK_DIR" >/dev/null 2>&1 || true + fi + if [ "$EXPORT_GUARD_LOCKED" -eq 1 ]; then + rmdir "$EXPORT_GUARD_DIR" >/dev/null 2>&1 || true + fi +} + +trap cleanup EXIT INT TERM + +is_safe_name() { + local name="$1" + [ -n "$name" ] || return 1 + case "$name" in + .*|*..*|*/*|*\\*|*' '*|*'#'*|*'?'*|*'*'*|*':'*) return 1 ;; + esac + ! printf '%s' "$name" | LC_ALL=C grep -q '[[:cntrl:]]' +} + +is_allowed_entry() { + local entry="$1" base + case "$entry" in + manifest.json|uci|meta/confit_list.conf|meta/template_bindings.conf) + return 0 + ;; + meta|config|config/sub|config/upload|config/custom|config/singbox|templates) + return 0 + ;; + config/sub/*) + base="${entry#config/sub/}" + is_safe_name "$base" + ;; + config/upload/*) + base="${entry#config/upload/}" + is_safe_name "$base" + ;; + config/custom/*) + base="${entry#config/custom/}" + is_safe_name "$base" + ;; + config/singbox/*) + base="${entry#config/singbox/}" + is_safe_name "$base" + ;; + templates/*) + base="${entry#templates/}" + is_safe_name "$base" + ;; + *) + return 1 + ;; + esac +} + +normalise_entry() { + local entry="$1" + while [ "${entry#./}" != "$entry" ]; do + entry="${entry#./}" + done + entry="${entry%/}" + printf '%s\n' "$entry" +} + +require_archive_path() { + case "$1" in + "$TMP_ROOT"/*) ;; + *) die '备份临时路径无效' ;; + esac +} + +ensure_tmp_root() { + local owner + [ ! -L "$TMP_ROOT" ] || die '备份临时目录不能是符号链接' + if [ -e "$TMP_ROOT" ]; then + [ -d "$TMP_ROOT" ] || die '备份临时路径不是目录' + owner="$(LC_ALL=C ls -nd "$TMP_ROOT" 2>/dev/null | awk '{ print $3 }')" + [ "$owner" = '0' ] || die '备份临时目录所有者异常' + else + mkdir -m 700 "$TMP_ROOT" || die '无法创建备份临时目录' + fi + chmod 700 "$TMP_ROOT" || die '无法保护备份临时目录' +} + +cleanup_stale_upload() { + local upload='' + if [ -d "$IMPORT_LOCK_DIR" ]; then + if [ -f "$IMPORT_OWNER_FILE" ] && + find "$IMPORT_OWNER_FILE" -mmin +15 | grep -q .; then + upload="$(sed -n '1p' "$IMPORT_OWNER_FILE" 2>/dev/null || true)" + case "$upload" in + "$TMP_ROOT"/import.??????) rm -f "$upload" "$upload.result" ;; + esac + rm -rf "$IMPORT_LOCK_DIR" + elif [ ! -f "$IMPORT_OWNER_FILE" ] && + find "$IMPORT_LOCK_DIR" -mmin +15 | grep -q .; then + rm -rf "$IMPORT_LOCK_DIR" + fi + fi + find "$TMP_ROOT" -maxdepth 1 -type f -name 'import.*' -mmin +15 \ + -exec rm -f {} \; 2>/dev/null || true +} + +new_upload() { + local upload + cleanup_stale_upload + mkdir "$IMPORT_LOCK_DIR" 2>/dev/null || die '已有备份正在上传,请稍后重试' + if ! upload="$(mktemp "$TMP_ROOT/import.XXXXXX")"; then + rmdir "$IMPORT_LOCK_DIR" >/dev/null 2>&1 || true + die '无法创建上传临时文件' + fi + if ! chmod 600 "$upload" || + ! printf '%s\n' "$upload" > "$IMPORT_OWNER_FILE" || + ! chmod 600 "$IMPORT_OWNER_FILE"; then + rm -f "$upload" "$IMPORT_OWNER_FILE" + rmdir "$IMPORT_LOCK_DIR" >/dev/null 2>&1 || true + die '无法保护上传临时文件' + fi + printf '%s\n' "$upload" +} + +new_export() { + local count file + if [ -d "$EXPORT_GUARD_DIR" ] && + find "$EXPORT_GUARD_DIR" -mmin +1 | grep -q .; then + rmdir "$EXPORT_GUARD_DIR" >/dev/null 2>&1 || true + fi + if ! mkdir "$EXPORT_GUARD_DIR" 2>/dev/null; then + sleep 1 + mkdir "$EXPORT_GUARD_DIR" 2>/dev/null || die '正在准备其他备份,请稍后重试' + fi + EXPORT_GUARD_LOCKED=1 + find "$TMP_ROOT" -maxdepth 1 -type f -name 'export.*' -mmin +15 \ + -exec rm -f {} \; 2>/dev/null || true + count="$(find "$TMP_ROOT" -maxdepth 1 -type f -name 'export.??????' | wc -l | tr -d ' ')" + [ "$count" -lt 2 ] || die '已有多个备份等待下载,请稍后重试' + file="$(mktemp "$TMP_ROOT/export.XXXXXX")" || die '无法创建导出临时文件' + chmod 600 "$file" || die '无法保护导出临时文件' + rmdir "$EXPORT_GUARD_DIR" || die '无法释放导出准备锁' + EXPORT_GUARD_LOCKED=0 + printf '%s\n' "$file" +} + +lock_restore() { + mkdir "$RESTORE_LOCK_DIR" 2>/dev/null || die '已有备份正在还原,请稍后重试' +} + +unlock_restore() { + rmdir "$RESTORE_LOCK_DIR" >/dev/null 2>&1 || true +} + +copy_regular() { + local root="$1" source="$2" relative="$3" parent + [ -f "$source" ] || return 0 + [ ! -L "$source" ] || die "拒绝备份符号链接: $source" + parent="${relative%/*}" + [ "$parent" = "$relative" ] || mkdir -p "$root/$parent" + cp "$source" "$root/$relative" +} + +copy_directory() { + local root="$1" source_dir="$2" prefix="$3" source base + [ -d "$source_dir" ] || return 0 + mkdir -p "$root/$prefix" + for source in "$source_dir"/*; do + [ -f "$source" ] || continue + [ ! -L "$source" ] || continue + base="${source##*/}" + is_safe_name "$base" || continue + cp "$source" "$root/$prefix/$base" + done +} + +copy_current_tree() { + local root="$1" + mkdir -p "$root" + copy_regular "$root" /etc/config/clashoo uci + copy_regular "$root" /usr/share/clashbackup/confit_list.conf meta/confit_list.conf + copy_regular "$root" /usr/share/clashbackup/template_bindings.conf meta/template_bindings.conf + copy_directory "$root" /usr/share/clashoo/config/sub config/sub + copy_directory "$root" /usr/share/clashoo/config/upload config/upload + copy_directory "$root" /usr/share/clashoo/config/custom config/custom + copy_directory "$root" /usr/share/clashoo/config/singbox config/singbox + copy_directory "$root" /etc/clashoo/templates templates +} + +write_manifest() { + local root="$1" host version created file + host="$(uname -n 2>/dev/null || true)" + version="$(sed -n '1p' /usr/share/clashoo/luci_version 2>/dev/null || true)" + created="$(date +%s)" + # jshn uses optional globals internally and is not nounset-safe. + set +u + . /usr/share/libubox/jshn.sh + json_init + json_add_string marker 'clashoo-backup-v2' + json_add_int created_at "$created" + json_add_string host "$host" + json_add_string app_version "$version" + json_add_array files + for file in $(cd "$root" && find . -type f | sed 's#^\./##' | sort); do + json_add_string '' "$file" + done + json_close_array + json_dump > "$root/manifest.json" + set -u +} + +validate_archive() { + local archive="$1" size validation_dir fifo tar_file gzip_pid head_rc gzip_rc tar_size list verbose raw entry mode type manifest_seen=0 entry_count=0 extracted_bytes extracted_kb marker + require_archive_path "$archive" + [ -f "$archive" ] || die '备份文件不存在' + size="$(wc -c < "$archive" | tr -d ' ')" + [ "$size" -gt 0 ] || die '备份文件为空' + [ "$size" -le "$MAX_ARCHIVE_BYTES" ] || die '备份文件超过 32MB' + + if [ -z "$WORK_DIR" ]; then + WORK_DIR="$(mktemp -d "$TMP_ROOT/validate.XXXXXX")" + fi + validation_dir="$WORK_DIR/validation" + mkdir -p "$validation_dir" + fifo="$validation_dir/archive.pipe" + tar_file="$validation_dir/archive.tar" + mkfifo "$fifo" || die '无法创建备份校验管道' + gzip -dc "$archive" > "$fifo" 2>/dev/null & + gzip_pid=$! + set +e + head -c "$((MAX_TAR_BYTES + 1))" "$fifo" > "$tar_file" 2>/dev/null + head_rc=$? + wait "$gzip_pid" + gzip_rc=$? + set -e + rm -f "$fifo" + tar_size="$(wc -c < "$tar_file" | tr -d ' ')" + [ "$tar_size" -le "$MAX_TAR_BYTES" ] || die '备份解压后超过 64MB' + [ "$head_rc" -eq 0 ] && [ "$gzip_rc" -eq 0 ] || die '备份压缩包损坏' + list="$validation_dir/list" + verbose="$validation_dir/verbose" + tar -tf "$tar_file" > "$list" 2>/dev/null || die '无法读取备份文件清单' + tar -tvf "$tar_file" > "$verbose" 2>/dev/null || die '无法读取备份文件类型' + + while IFS= read -r raw; do + entry_count=$((entry_count + 1)) + [ "$entry_count" -le "$MAX_ENTRIES" ] || die '备份文件条目过多' + entry="$(normalise_entry "$raw")" + [ -n "$entry" ] || continue + case "$entry" in + /*|*\\*) die '备份文件包含非法路径' ;; + esac + case "/$entry/" in + */../*|*/./*) die '备份文件包含目录穿越路径' ;; + esac + is_allowed_entry "$entry" || die "备份文件包含未知路径: $entry" + [ "$entry" = 'manifest.json' ] && manifest_seen=1 + done < "$list" + [ "$manifest_seen" -eq 1 ] || die '备份文件缺少 manifest.json' + + while IFS= read -r raw; do + mode="${raw%% *}" + type="$(printf '%s' "$mode" | cut -c 1)" + case "$type" in + -|d) ;; + *) die '备份文件包含链接或特殊文件' ;; + esac + done < "$verbose" + extracted_bytes="$(awk '$1 ~ /^-/ { total += $3 } END { printf "%.0f\n", total }' "$verbose")" + [ "$extracted_bytes" -le "$MAX_EXTRACTED_BYTES" ] || die '备份解压后超过 64MB' + + EXTRACT_DIR="$validation_dir/extract" + mkdir -p "$EXTRACT_DIR" + tar -xf "$tar_file" -C "$EXTRACT_DIR" >/dev/null 2>&1 || die '备份文件解压失败' + if find "$EXTRACT_DIR" -type l | grep -q .; then + die '备份文件包含符号链接' + fi + extracted_kb="$(du -sk "$EXTRACT_DIR" | cut -f 1)" + [ "$extracted_kb" -le "$MAX_EXTRACTED_KB" ] || die '备份解压后超过 64MB' + [ -f "$EXTRACT_DIR/manifest.json" ] || die '备份清单不是普通文件' + [ -f "$EXTRACT_DIR/uci" ] || die '备份文件缺少 UCI 配置' + marker="$(jsonfilter -i "$EXTRACT_DIR/manifest.json" -e '@.marker' 2>/dev/null || true)" + [ "$marker" = 'clashoo-backup-v2' ] || die '备份格式标记无效' +} + +clear_target_directories() { + local directory + for directory in \ + /usr/share/clashoo/config/sub \ + /usr/share/clashoo/config/upload \ + /usr/share/clashoo/config/custom \ + /usr/share/clashoo/config/singbox \ + /etc/clashoo/templates; do + mkdir -p "$directory" || return 1 + rm -rf "$directory"/* "$directory"/.[!.]* "$directory"/..?* || return 1 + done +} + +copy_tree_to_system() { + local root="$1" source base + clear_target_directories || return 1 + [ -f "$root/uci" ] && cp "$root/uci" /etc/config/clashoo || return 1 + rm -f /usr/share/clashbackup/confit_list.conf \ + /usr/share/clashbackup/template_bindings.conf || return 1 + if [ -f "$root/meta/confit_list.conf" ]; then + mkdir -p /usr/share/clashbackup || return 1 + cp "$root/meta/confit_list.conf" /usr/share/clashbackup/confit_list.conf || return 1 + fi + if [ -f "$root/meta/template_bindings.conf" ]; then + mkdir -p /usr/share/clashbackup || return 1 + cp "$root/meta/template_bindings.conf" /usr/share/clashbackup/template_bindings.conf || return 1 + fi + for source in "$root/config/sub"/*; do + [ -f "$source" ] || continue + base="${source##*/}" + cp "$source" "/usr/share/clashoo/config/sub/$base" || return 1 + done + for source in "$root/config/upload"/*; do + [ -f "$source" ] || continue + base="${source##*/}" + cp "$source" "/usr/share/clashoo/config/upload/$base" || return 1 + done + for source in "$root/config/custom"/*; do + [ -f "$source" ] || continue + base="${source##*/}" + cp "$source" "/usr/share/clashoo/config/custom/$base" || return 1 + done + for source in "$root/config/singbox"/*; do + [ -f "$source" ] || continue + base="${source##*/}" + cp "$source" "/usr/share/clashoo/config/singbox/$base" || return 1 + done + for source in "$root/templates"/*; do + [ -f "$source" ] || continue + base="${source##*/}" + cp "$source" "/etc/clashoo/templates/$base" || return 1 + done +} + +export_archive() { + local archive="$1" stage + require_archive_path "$archive" + WORK_DIR="$(mktemp -d "$TMP_ROOT/export.XXXXXX")" + stage="$WORK_DIR/stage" + copy_current_tree "$stage" + write_manifest "$stage" + tar -C "$stage" -czf "$archive" . + chmod 600 "$archive" + if ! sh "$0" validate "$archive"; then + rm -f "$archive" + die '生成的备份不符合还原限制' + fi + printf 'files=%s\n' "$(find "$stage" -type f | wc -l | tr -d ' ')" +} + +restore_archive() { + local upload="$1" lock_mode="${2:-acquire}" archive rollback restored + require_archive_path "$upload" + if [ "$lock_mode" = 'acquire' ]; then + lock_restore + RESTORE_LOCKED=1 + else + [ -d "$RESTORE_LOCK_DIR" ] || die '备份还原锁不存在' + fi + WORK_DIR="$(mktemp -d "$TMP_ROOT/restore.XXXXXX")" + archive="$WORK_DIR/import.tar.gz" + mv "$upload" "$archive" || die '无法接管已上传的备份文件' + validate_archive "$archive" + rollback="$WORK_DIR/rollback" + copy_current_tree "$rollback" + if ! copy_tree_to_system "$EXTRACT_DIR"; then + if copy_tree_to_system "$rollback" >/dev/null 2>&1; then + die '恢复写入失败,已回滚原配置' + fi + die '恢复写入失败,自动回滚也失败,请检查存储空间' + fi + restored="$(find "$EXTRACT_DIR" -type f ! -name manifest.json | wc -l | tr -d ' ')" + printf 'restored=%s\n' "$restored" +} + +ensure_tmp_root + +command="${1:-}" +archive="${2:-}" + +case "$command" in + prepare) cleanup_stale_upload ;; + new-upload) new_upload ;; + new-export) new_export ;; + lock) lock_restore ;; + unlock) unlock_restore ;; + export) export_archive "$archive" ;; + validate) validate_archive "$archive" ;; + restore) restore_archive "$archive" ;; + restore-held) restore_archive "$archive" held ;; + *) die '不支持的备份操作' ;; +esac diff --git a/luci-app-clashoo/root/usr/share/luci/menu.d/luci-app-clashoo.json b/luci-app-clashoo/root/usr/share/luci/menu.d/luci-app-clashoo.json new file mode 100644 index 000000000..c0c4761f8 --- /dev/null +++ b/luci-app-clashoo/root/usr/share/luci/menu.d/luci-app-clashoo.json @@ -0,0 +1,45 @@ +{ + "admin/services/clashoo": { + "title": "Clashoo", + "order": 90, + "action": { + "type": "firstchild" + }, + "depends": { + "acl": ["luci-app-clashoo"] + } + }, + "admin/services/clashoo/overview": { + "title": "Overview", + "order": 10, + "action": { + "type": "view", + "path": "clashoo/overview" + }, + "depends": { + "acl": ["luci-app-clashoo"] + } + }, + "admin/services/clashoo/config": { + "title": "Configuration", + "order": 20, + "action": { + "type": "view", + "path": "clashoo/config" + }, + "depends": { + "acl": ["luci-app-clashoo"] + } + }, + "admin/services/clashoo/system": { + "title": "System", + "order": 30, + "action": { + "type": "view", + "path": "clashoo/system" + }, + "depends": { + "acl": ["luci-app-clashoo"] + } + } +} diff --git a/luci-app-clashoo/root/usr/share/rpcd/acl.d/luci-app-clashoo.json b/luci-app-clashoo/root/usr/share/rpcd/acl.d/luci-app-clashoo.json new file mode 100644 index 000000000..8fc522aae --- /dev/null +++ b/luci-app-clashoo/root/usr/share/rpcd/acl.d/luci-app-clashoo.json @@ -0,0 +1,21 @@ +{ + "luci-app-clashoo": { + "description": "Grant access for luci-app-clashoo", + "read": { + "cgi-io": [ "download" ], + "file": { + "/tmp/clashoo-backup/export.*": [ "read" ] + }, + "uci": [ "clashoo" ], + "ubus": { + "luci.clashoo": [ "*" ] + } + }, + "write": { + "uci": [ "clashoo" ], + "ubus": { + "luci.clashoo": [ "*" ] + } + } + } +} diff --git a/luci-app-clashoo/root/usr/share/rpcd/ucode/luci.clashoo b/luci-app-clashoo/root/usr/share/rpcd/ucode/luci.clashoo new file mode 100755 index 000000000..2a9884d03 --- /dev/null +++ b/luci-app-clashoo/root/usr/share/rpcd/ucode/luci.clashoo @@ -0,0 +1,4649 @@ +#!/usr/bin/ucode + +'use strict'; + +import { access, popen, glob, readfile, writefile, stat, unlink, open } from 'fs'; +import { cursor } from 'uci'; + +const BINARY_PATHS = [ +'/usr/bin/mihomo-stable', +'/usr/bin/mihomo', +'/usr/bin/clash-meta', +'/usr/bin/clash', +'/etc/clashoo/clash' +]; + +const SMART_BINARY_PATHS = [ +'/usr/bin/smart', +'/etc/clashoo/clash', +'/usr/bin/clash' +]; + +const SINGBOX_BIN_DIR = '/usr/share/clashoo/bin'; +const SINGBOX_RUNTIME_DIR = '/var/run/clashoo/sing-box'; +const SINGBOX_RUNTIME_CONFIG = SINGBOX_RUNTIME_DIR + '/config.json'; +const SINGBOX_WORKDIR = SINGBOX_RUNTIME_DIR + '/work'; +const SINGBOX_BINARY_PATHS = [ +SINGBOX_BIN_DIR + '/sing-box-stable', +SINGBOX_BIN_DIR + '/sing-box-alpha' +]; + +const LOG_PATHS = [ +'/usr/share/clashoo/clashoo.txt', +'/var/log/clash.log', +'/var/log/clash/clash.log', +'/tmp/clash.log' +]; +const CORE_LOG_PATH = '/var/log/clashoo/core.log'; + +const CONFIG_DIRS = [ +{ path: '/usr/share/clashoo/config/sub', type: '1' }, +{ path: '/usr/share/clashoo/config/upload', type: '2' }, +{ path: '/usr/share/clashoo/config/custom', type: '3' } +]; + +const LIST_FILE = '/usr/share/clashbackup/confit_list.conf'; +const SUB_DIR = '/usr/share/clashoo/config/sub'; +const TEMPLATE_DIR = '/usr/share/clashoo/config/custom'; +const TEMPLATE_USER_DIR = '/etc/clashoo/templates'; +const TEMPLATE_BIND_FILE = '/usr/share/clashbackup/template_bindings.conf'; +const SINGBOX_DIR = '/usr/share/clashoo/config/singbox'; +const ACCESS_CACHE_FILE = '/tmp/clashoo_check_cache'; +const ACCESS_UPDATING_FLAG = '/tmp/clashoo/access_check_updating'; +const ACCESS_DAEMON_PID_FILE = '/tmp/clashoo/access_check_daemon.pid'; +const ACCESS_CACHE_TTL = 30; +const ACCESS_UPDATING_TTL = 60; +const OVERVIEW_STATS_CACHE_FILE = '/tmp/clashoo_overview_stats_cache.json'; +const COMPONENT_UPDATE_SCRIPT = '/usr/share/clashoo/update/component_update.sh'; +const COMPONENT_UPDATE_RUNNER = '/tmp/clashoo_component_update_runner.sh'; +const COMPONENT_UPDATE_RUN_FILE = '/var/run/clashoo_component_update'; +const COMPONENT_UPDATE_LOG_FILE = '/tmp/clashoo_component_update.log'; +const COMPONENT_UPDATE_STATE_FILE = '/tmp/clashoo_component_update_state'; +const SUBSCRIPTION_UPDATE_SCRIPT = '/usr/share/clashoo/update/subscription_update.sh'; +const SUBSCRIPTION_UPDATE_STATUS_FILE = '/usr/share/clashbackup/subscription_update.status'; +const SUBSCRIPTION_UPDATE_LOCK_DIR = '/tmp/clashoo_subscription_update.lock'; +const BACKUP_TMP_DIR = '/tmp/clashoo-backup'; +const BACKUP_IMPORT_LOCK_DIR = BACKUP_TMP_DIR + '/import.lock'; +const BACKUP_IMPORT_OWNER_FILE = BACKUP_IMPORT_LOCK_DIR + '/path'; +const BACKUP_JSON_ROLLBACK_FILE = BACKUP_TMP_DIR + '/json-rollback.tar.gz'; +const BACKUP_ARCHIVE_SCRIPT = '/usr/share/clashoo/rpc/backup_archive.sh'; +const BACKUP_MAX_ARCHIVE_SIZE = 32 * 1024 * 1024; +const BACKUP_MAX_JSON_SIZE = 8 * 1024 * 1024; +const BACKUP_MAX_CHUNK_SIZE = 40 * 1024; +const BACKUP_MAX_CHUNK_BASE64_SIZE = 55000; +const BACKUP_MAX_ENTRIES = 2048; + +function uci_get(pkg, sec, opt) { +let c = cursor(); +c.load(pkg); +return c.get(pkg, sec, opt) || ''; +} + +function shell_quote(s) { +return "'" + replace(s || '', /'/g, "'\\''") + "'"; +} + +function backup_tmp_ready() { +return system('sh ' + shell_quote(BACKUP_ARCHIVE_SCRIPT) + + ' prepare >/dev/null 2>&1') == 0; +} + +function safe_backup_temp_path(path, kind) { +if (kind != 'import' && kind != 'export') return ''; +let prefix = BACKUP_TMP_DIR + '/' + kind + '.'; +if (substr(path || '', 0, length(prefix)) != prefix) return ''; +let suffix = substr(path, length(prefix)); +if (length(suffix) != 6 || match(suffix, /[^A-Za-z0-9]/)) return ''; +return path; +} + +function safe_backup_upload_path(path) { +return safe_backup_temp_path(path, 'import'); +} + +function safe_backup_export_path(path) { +return safe_backup_temp_path(path, 'export'); +} + +function new_backup_temp_path(kind) { +if (kind != 'import' && kind != 'export') return ''; +let command = kind == 'import' ? 'new-upload' : 'new-export'; +let pp = popen('sh ' + shell_quote(BACKUP_ARCHIVE_SCRIPT) + ' ' + command + ' 2>/dev/null'); +if (!pp) return ''; +let path = trim(pp.read('all')); +pp.close(); +return safe_backup_temp_path(path, kind); +} + +function active_backup_upload(path) { +return !!path && trim(readfile(BACKUP_IMPORT_OWNER_FILE) || '') == path; +} + +function refresh_backup_upload(path) { +return active_backup_upload(path) && + writefile(BACKUP_IMPORT_OWNER_FILE, path + '\n') !== null; +} + +function release_backup_upload(path) { +if (!path) return; +unlink(path); +unlink(path + '.result'); +if (active_backup_upload(path)) { + unlink(BACKUP_IMPORT_OWNER_FILE); + system('rmdir ' + shell_quote(BACKUP_IMPORT_LOCK_DIR) + ' >/dev/null 2>&1'); +} +} + +function subscription_update_status_data() { +let out = { running: !!access(SUBSCRIPTION_UPDATE_LOCK_DIR, 'r') }; +if (!access(SUBSCRIPTION_UPDATE_STATUS_FILE, 'r')) return out; +let raw = readfile(SUBSCRIPTION_UPDATE_STATUS_FILE) || ''; +for (let line in split(raw, '\n')) { + let pos = index(line, '='); + if (pos <= 0) continue; + let key = substr(line, 0, pos); + let value = substr(line, pos + 1); + if (key == 'last_run' || key == 'finished_at' || key == 'updated' || + key == 'unchanged' || key == 'failed' || key == 'skipped') + out[key] = int(value) || 0; + else if (key == 'message') out.message = value; +} +return out; +} + +function dashboard_panel_dir(name) { +if (name == 'metacubexd') return '/etc/clashoo/dashboard-metacubexd'; +if (name == 'yacd') return '/etc/clashoo/dashboard-yacd'; +if (name == 'zashboard') return '/etc/clashoo/dashboard-zashboard'; +if (name == 'razord') return '/etc/clashoo/dashboard-razord'; +return '/etc/clashoo/dashboard-zashboard'; +} + +function activate_dashboard_panel(name) { +let dir = dashboard_panel_dir(name); +if (!access(dir + '/index.html', 'r')) +return false; +system('rm -rf /etc/clashoo/dashboard /www/luci-static/yacd >/dev/null 2>&1'); +system('ln -s ' + shell_quote(dir) + ' /etc/clashoo/dashboard >/dev/null 2>&1 || cp -a ' + shell_quote(dir) + ' /etc/clashoo/dashboard >/dev/null 2>&1'); +if (name == 'yacd') +system('ln -s ' + shell_quote(dir) + ' /www/luci-static/yacd >/dev/null 2>&1'); +return true; +} + +function get_core_type() { +let core_type = uci_get('clashoo', 'config', 'core_type'); +if (core_type == 'singbox') return 'singbox'; +return 'mihomo'; +} + +function get_core_channel(family) { +let dcore = uci_get('clashoo', 'config', 'dcore'); +let legacy = uci_get('clashoo', 'config', 'core'); +family = family || get_core_type(); + +if (family == 'singbox') +return dcore == '5' ? 'alpha' : 'stable'; + +if (dcore == '1' || legacy == '1') +return 'smart'; + +if (dcore == '3' || legacy == '3') +return 'alpha'; + +return 'stable'; +} + +function get_core_label(family, channel) { +family = family || get_core_type(); +channel = channel || get_core_channel(family); +let name = family == 'singbox' ? 'sing-box' : 'mihomo'; +return name + ' ' + (channel == 'smart' ? 'smart' : channel == 'alpha' ? 'alpha' : 'stable'); +} + +function get_mihomo_service_name() { +for (let name in ['clashoo', 'clash']) { + if (access('/etc/init.d/' + name, 'x')) return name; +} +return 'clash'; +} + +function get_service_name() { +return get_core_type() === 'singbox' ? 'clashoo' : get_mihomo_service_name(); +} + +// 只看 procd 自家实例 PID。pidof 会撞 openclash / nikki / passwall 的同名进程, +// 用 ubus 走 procd 真相来源;instance 为空时保留旧的 wildcard 行为。 +function procd_instance_pid(service, instance) { +let filter = instance ? '@.' + service + '.instances.' + instance + '.pid' : + '@["' + service + '"].instances.*.pid'; +let query = '{"name":"' + service + '","verbose":true}'; +let p = popen('ubus call service list ' + shell_quote(query) + + ' 2>/dev/null | jsonfilter -e ' + shell_quote(filter) + ' 2>/dev/null | head -n1'); +if (!p) return 0; +let s = trim(p.read('all')); +p.close(); +let pid = int(s) || 0; +if (pid > 0 && !access('/proc/' + pid, 'r')) pid = 0; +return pid; +} + +function clashoo_running() { return procd_instance_pid('clashoo') > 0; } + +function singbox_binary_path(path) { +return path == SINGBOX_BINARY_PATHS[0] || path == SINGBOX_BINARY_PATHS[1]; +} + +function singbox_pid_owns_private_binary(pid) { +if (!pid || !access('/proc/' + pid, 'r')) return false; +let p = popen('readlink -f ' + shell_quote('/proc/' + pid + '/exe') + ' 2>/dev/null'); +let exe = ''; +if (p) { + exe = trim(p.read('all') || ''); + p.close(); +} +if (singbox_binary_path(exe)) return true; +let cmdline = replace(readfile('/proc/' + pid + '/cmdline') || '', /\x00/g, ' '); +for (let path in SINGBOX_BINARY_PATHS) + if (cmdline == path || substr(cmdline, 0, length(path) + 1) == path + ' ') + return true; +return false; +} + +function singbox_running() { +let pid = procd_instance_pid('clashoo', 'singbox'); +return pid > 0 && singbox_pid_owns_private_binary(pid); +} + +function running_core_family() { +if (singbox_running()) return 'singbox'; +if (clashoo_running()) return 'mihomo'; +return ''; +} + +function find_binary_for_family(family) { +if (family === 'mihomo') { + let pid = procd_instance_pid('clashoo'); + if (pid > 0) { + let p = popen('readlink -f /proc/' + pid + '/exe 2>/dev/null'); + if (p) { + let running = trim(p.read('all')); + p.close(); + if (running && access(running, 'x')) return running; + } + } + let channel = get_core_channel('mihomo'); + if (channel == 'stable' && access('/usr/bin/mihomo-stable', 'x')) return '/usr/bin/mihomo-stable'; + if (channel == 'alpha' && access('/usr/bin/mihomo', 'x')) return '/usr/bin/mihomo'; + if (channel == 'smart') { + for (let path in SMART_BINARY_PATHS) + if (access(path, 'x')) return path; + } +} +let paths = family === 'singbox' ? SINGBOX_BINARY_PATHS : BINARY_PATHS; +for (let path in paths) +if (access(path, 'x')) return path; +return ''; +} + +function find_smart_binary() { +for (let path in SMART_BINARY_PATHS) +if (access(path, 'x')) return path; +return ''; +} + +function find_binary() { +let family = running_core_family() || get_core_type(); +let binary = find_binary_for_family(family); +if (binary) return binary; +if (family != get_core_type()) return find_binary_for_family(get_core_type()); +return ''; +} + +function read_first_line(path) { +if (!access(path, 'r')) return ''; +let content = readfile(path); +return content ? trim(split(content, '\n')[0] || '') : ''; +} + +function runtime_state_get(key) { +if (!key || !access('/tmp/clashoo/runtime_state', 'r')) return ''; +let content = readfile('/tmp/clashoo/runtime_state') || ''; +for (let line in split(content, '\n')) { +let pos = index(line, '='); +if (pos <= 0) continue; +if (substr(line, 0, pos) == key) +return trim(substr(line, pos + 1)); +} +return ''; +} + +function is_running() { +return running_core_family() != ''; +} + +function get_local_ip() { +let p = popen("ip -4 addr show br-lan 2>/dev/null | awk '/inet /{sub(/\\/.*/,\"\",$2); print $2; exit}'"); +if (!p) return ''; +let ip = trim(p.read('all')); +p.close(); +if (ip) return ip; +p = popen("dev=$(ip -4 route show default 2>/dev/null | awk '{print $5; exit}'); [ -n \"$dev\" ] && ip -4 addr show dev \"$dev\" 2>/dev/null | awk '/inet /{sub(/\\/.*/,\"\",$2); print $2; exit}'"); +if (!p) return ''; +ip = trim(p.read('all')); +p.close(); +return ip; +} + +function get_core_version(binary) { +if (!binary) return ''; +let cmd = match(binary, /sing-box(-[a-z]+)?$/) +? (shell_quote(binary) + ' version 2>&1 | head -1') +: (shell_quote(binary) + ' -v 2>&1 | head -1'); +let p = popen(cmd); +if (!p) return ''; +let v = trim(p.read('all')); +p.close(); +return v; +} + +function sync_legacy_core_fields(c) { +let family = c.get('clashoo', 'config', 'core_type') || 'mihomo'; +let dcore = c.get('clashoo', 'config', 'dcore') || '2'; +let legacy = '2'; + +if (family == 'singbox') +legacy = dcore == '5' ? '5' : '4'; +else +legacy = dcore == '1' ? '1' : dcore == '3' ? '3' : '2'; + +c.set('clashoo', 'config', 'core', legacy); +} + +function has_mihomo_stable() { +if (access('/usr/bin/mihomo-stable', 'x')) return true; +if (system("[ -x /usr/bin/clash-meta ] && [ ! -L /usr/bin/clash-meta ]") != 0) return false; +let version = get_core_version('/usr/bin/clash-meta'); +return !!version && !match(version, /(alpha|beta|rc|pre|smart)/i); +} + +function core_target_error(core, dcore) { +if (core == 'mihomo' && dcore == '1') { + if (find_smart_binary()) return null; + return { error: 'smart_core_missing', message: '未检测到 Smart 内核,请先在“组件更新”中安装 Smart' }; +} +if (core == 'mihomo' && dcore == '2') { + if (has_mihomo_stable()) return null; + return { error: 'mihomo_stable_missing', message: '未检测到 mihomo 稳定版,请先在“组件更新”中更新稳定版' }; +} +if (core == 'mihomo' && dcore == '3') { + if (access('/usr/bin/mihomo', 'x')) return null; + return { error: 'mihomo_alpha_missing', message: '未检测到 mihomo Alpha,请先在“组件更新”中更新 Alpha' }; +} +if (core == 'singbox' && dcore == '4') { + if (access(SINGBOX_BINARY_PATHS[0], 'x')) return null; + return { error: 'singbox_stable_missing', message: '未检测到 sing-box 稳定版,请先在“组件更新”中更新稳定版' }; +} +if (core == 'singbox' && dcore == '5') { + if (access(SINGBOX_BINARY_PATHS[1], 'x')) return null; + return { error: 'singbox_alpha_missing', message: '未检测到 sing-box Alpha,请先在“组件更新”中更新 Alpha' }; +} +return { error: 'invalid_core_target', message: '无效的内核类型与版本组合' }; +} + +function prepare_singbox_runtime() { +let active = uci_get('clashoo', 'config', 'singbox_active') || ''; +let src = active ? (SINGBOX_DIR + '/' + active) : SINGBOX_RUNTIME_CONFIG; +if (!access(src, 'r')) src = SINGBOX_RUNTIME_CONFIG; +if (!access(src, 'r')) + return { success: false, message: '请先生成或选择 sing-box 配置文件' }; + +system('mkdir -p ' + shell_quote(SINGBOX_RUNTIME_DIR) + ' ' + shell_quote(SINGBOX_WORKDIR) + ' >/dev/null 2>&1'); +let tmp = shell_read('mktemp ' + shell_quote(SINGBOX_RUNTIME_CONFIG + '.tmp.XXXXXX') + ' 2>/dev/null'); +if (!tmp) + return { success: false, message: '无法创建 sing-box 临时运行配置' }; + +let raw = readfile(src) || ''; +let cfg = raw ? json(raw) : null; +if (!cfg || type(cfg) != 'object') { + unlink(tmp); + return { success: false, message: 'sing-box 配置 JSON 无法解析' }; +} +cfg = migrate_singbox(cfg); +if (writefile(tmp, sprintf('%J\n', cfg)) === null) { + unlink(tmp); + return { success: false, message: '无法写入 sing-box 临时运行配置' }; +} + +if (uci_get('clashoo', 'config', 'core_only') != '1') { + if (system('command -v ucode >/dev/null 2>&1') != 0) { + unlink(tmp); + return { success: false, message: 'ucode is required to normalize sing-box runtime config' }; + } + let redir_port = uci_get('clashoo', 'config', 'redir_port') || '7891'; + let tproxy_port = uci_get('clashoo', 'config', 'tproxy_port') || '7982'; + let mixed_port = uci_get('clashoo', 'config', 'mixed_port') || '7890'; + let dns_port = uci_get('clashoo', 'config', 'listen_port') || '1053'; + let dash_port = uci_get('clashoo', 'config', 'dash_port') || '9090'; + let dash_pass = uci_get('clashoo', 'config', 'dash_pass') || ''; + let has_tun = system('(ip tuntap add mode tun name cotuntest >/dev/null 2>&1 && ip link del cotuntest >/dev/null 2>&1)') == 0 ? '1' : '0'; + let normalize_cmd = 'ucode /usr/share/clashoo/lib/normalize_singbox_config.uc ' + + shell_quote(tmp) + ' ' + + shell_quote(redir_port) + ' ' + + shell_quote(tproxy_port) + ' ' + + shell_quote(mixed_port) + ' ' + + shell_quote(has_tun) + ' ' + + shell_quote('6666') + ' ' + + shell_quote(dns_port) + ' ' + + shell_quote(dash_port) + ' ' + + shell_quote(dash_pass) + + ' >/dev/null 2>&1'; + if (system(normalize_cmd) != 0) { + unlink(tmp); + return { success: false, message: 'sing-box 运行配置规范化失败' }; + } +} + +if (system('mv -f ' + shell_quote(tmp) + ' ' + shell_quote(SINGBOX_RUNTIME_CONFIG) + ' >/dev/null 2>&1') != 0) { + unlink(tmp); + return { success: false, message: '无法提交 sing-box 运行配置' }; +} +return { success: true }; +} + +function detect_firewall_backend() { +if (system('command -v fw4 >/dev/null 2>&1') == 0) return 'fw4'; +if (system('command -v firewall >/dev/null 2>&1') == 0) return 'fw3'; +return ''; +} + +function detect_missing_fw4_tools() { +let missing = []; +if (system('command -v fw4 >/dev/null 2>&1') != 0) push(missing, 'fw4'); +if (system('command -v nft >/dev/null 2>&1') != 0) push(missing, 'nft'); +if (system('command -v ip >/dev/null 2>&1') != 0) push(missing, 'ip'); +return missing; +} + +function get_profiles() { +let profiles = []; +let dirs = ['/etc/clashoo/profiles']; + +function has_profile_name(arr, name) { +for (let i = 0; i < length(arr); i++) +if (arr[i] == name) return true; +return false; +} + +for (let dir in dirs) { +if (!access(dir, 'r')) continue; +for (let f in (glob(dir + '/*.yaml') || [])) { +let name = replace(f, dir + '/', ''); +if (name && name != 'config.yaml' && !has_profile_name(profiles, name)) +push(profiles, name); +} +if (length(profiles) > 0) break; +} +return profiles; +} + +function format_log_dates(text) { +return replace(text || '', /\d{4}-(\d{2}-\d{2}) /g, '$1 '); +} + +function format_update_log(text) { +let out = []; +for (let line in split(format_log_dates(text || ''), '\n')) { +line = trim(line || ''); +if (!line) continue; +if (index(line, '启动任务已触发') >= 0 || + index(line, '停止任务已触发') >= 0 || + index(line, '重启任务已触发') >= 0) + continue; +push(out, line); +} +return join('\n', out); +} + +function reformat_core_line(line) { +if (match(line, /^(===|---)/)) return line; +// Extract local time+date "May 26 23:16:18 2026" → "05-26 23:16:18" +let local_t = ''; +let syslog_tm = match(line, /^\w{3} (\d{1,2}) (\d{2}:\d{2}:\d{2}) \d{4}/); +if (syslog_tm) { + let months = { Jan:'01',Feb:'02',Mar:'03',Apr:'04',May:'05',Jun:'06',Jul:'07',Aug:'08',Sep:'09',Oct:'10',Nov:'11',Dec:'12' }; + let mon_match = match(line, /^\w{3}/); + let mon = mon_match ? months[mon_match[0]] || mon_match[0] : '??'; + local_t = mon + '-' + syslog_tm[1].padStart(2,'0') + ' ' + syslog_tm[2]; +} +// Strip syslog prefix "...process[pid]: " +let msg = replace(line, /^.*?\[\d+\]:\s*/, ''); +if (msg === line) msg = line; +// mihomo: time="YYYY-MM-DDTHH:MM:SS..." level=LEVEL msg="TEXT" +let mm = match(msg, /^time="\d{4}-(\d{2}-\d{2})T(\d{2}:\d{2}:\d{2})[^"]*"\s+level=(\w+)\s+msg="(.*)"\s*$/); +if (mm) { + let t = local_t ? local_t : mm[1] + ' '; + let h = +substr(mm[2], 0, 2); t += sprintf('%02d', (h + 8) % 24) + substr(mm[2], 2); + if (mm[3] === 'info') return t + ' ' + mm[4]; + return t + ' [' + mm[3] + '] ' + mm[4]; +} +// sing-box ISO "T" format: "YYYY-MM-DDTHH:MM:SS... LEVEL message" +let sm = match(msg, /^\d{4}-(\d{2}-\d{2})T(\d{2}:\d{2}:\d{2})[^ ]* +(\w+) +(.*)/); +if (sm) { + let t = local_t ? local_t : sm[1] + ' '; + let h = +substr(sm[2], 0, 2); t += sprintf('%02d', (h + 8) % 24) + substr(sm[2], 2); + let lvl = lc(sm[3]); + if (lvl === 'info') return t + ' ' + sm[4]; + return t + ' [' + lvl + '] ' + sm[4]; +} +// sing-box space format: "[+0000] YYYY-MM-DD HH:MM:SS LEVEL message" +let ss = match(msg, /^[+-]\d{4} \d{4}-\d{2}-\d{2} (\d{2}:\d{2}:\d{2}) +(\w+) +(.*)/); +if (ss) { + let t = local_t; + if (!t) { let h = +substr(ss[1], 0, 2); t = sprintf('%02d', (h + 8) % 24) + substr(ss[1], 2); } + let lvl = lc(ss[2]); + if (lvl === 'info') return t + ' ' + ss[3]; + return t + ' [' + lvl + '] ' + ss[3]; +} +// fallback: strip ISO timestamp, keep syslog time +msg = replace(msg, /\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}[^ ]*\s*/, ''); +return (local_t ? local_t + ' ' : '') + trim(msg); +} + +function get_log_content() { +// 统一用 awk 脚本简化 mihomo 原生日志 + log_msg 行格式 +let formatter = "awk -f /usr/share/clashoo/net/log_format.awk 2>/dev/null"; + +for (let path in LOG_PATHS) { +if (!access(path, 'r')) continue; +let p = popen("tail -300 '" + path + "' | " + formatter); +if (p) { let c = p.read('all'); p.close(); return c; } +} +if (get_core_type() == 'singbox') { +let p0 = popen("logread -e 'sing-box' 2>/dev/null | tail -300"); +if (p0) { +let c0 = trim(p0.read('all')); +p0.close(); +if (c0) return c0; +} +} +return ''; +} + +function format_core_log(content) { +content = content || ''; +let out = ['=== 核心日志 ===']; +// No server-side noise filtering: the UI level dropdown (全部/INFO/WARN/ERROR/FATAL) +// is the single filter, so "全部" really means all. Keep a generous cap so errors +// aren't pushed out by connection chatter. +let max_lines = 400; + +for (let line in split(content, '\n')) { +line = replace(line || '', /\x1b\[[0-9;]*m/g, ''); +line = trim(line || ''); +if (!line) continue; + +push(out, reformat_core_line(line)); +if (length(out) > max_lines + 1) shift(out); +} + + if (length(out) == 1) + push(out, '暂无核心日志'); + return join('\n', out); +} + +function list_config_files() { +let configs = []; +let subs = read_subscriptions(); + +function has_name(arr, n) { +for (let i = 0; i < length(arr); i++) +if (arr[i] == n) return true; +return false; +} + +function sub_has_name(n) { +for (let i = 0; i < length(subs); i++) { +if (subs[i].name == n) return true; +} +return false; +} + +for (let dir in CONFIG_DIRS) { +for (let f in (glob(dir.path + '/*.yaml') || [])) { +let name = replace(f, dir.path + '/', ''); +if (dir.type == '1') { +if (!sub_has_name(name)) +continue; +} +if (!has_name(configs, name)) push(configs, name); +} + +for (let f in (glob(dir.path + '/*.yml') || [])) { +let name = replace(f, dir.path + '/', ''); +if (dir.type == '1') { +if (!sub_has_name(name)) +continue; +} +if (!has_name(configs, name)) push(configs, name); +} +} + +let cur = get_current_config(); +if (cur && !has_name(configs, cur)) +push(configs, cur); + +return configs; +} + +function first_available_config(exclude_path) { +for (let dir in CONFIG_DIRS) { +for (let f in (glob(dir.path + '/*.yaml') || [])) { +if (f != exclude_path) +return { path: f, type: dir.type }; +} +for (let f in (glob(dir.path + '/*.yml') || [])) { +if (f != exclude_path) +return { path: f, type: dir.type }; +} +} +return null; +} + +function get_current_config(core_family) { +core_family = core_family || get_core_type(); + +if (core_family == 'singbox') { + let active = uci_get('clashoo', 'config', 'singbox_active') || ''; + let active_name = replace(active, /^.*\//, ''); + /* 文件已被删除时不返回 stale 名 */ + if (active_name && access(SINGBOX_DIR + '/' + active_name, 'r')) return active_name; + if (access(SINGBOX_RUNTIME_CONFIG, 'r')) return 'config.json'; + return ''; +} + +let use_config = uci_get('clashoo', 'config', 'use_config'); +let name = replace(use_config, /^.*\//, ''); +if (name && use_config && !access(use_config, 'r')) return ''; +return name; +} + +function get_display_config_name(core_family) { +core_family = core_family || get_core_type(); + +if (core_family == 'singbox') { + let active = uci_get('clashoo', 'config', 'singbox_active') || ''; + let active_name = replace(active, /^.*\//, ''); + if (active_name) { + if (match(active_name, /\.singbox\.json$/)) + return replace(active_name, /\.singbox\.json$/, '.json'); + return active_name; + } + if (access(SINGBOX_RUNTIME_CONFIG, 'r')) + return 'config.json'; + return 'config.json'; +} + +return get_current_config('mihomo'); +} + +function now_epoch_sec() { +let p = popen('date +%s 2>/dev/null'); +if (!p) return 0; +let raw = trim(p.read('all')); +p.close(); +return raw ? int(raw) : 0; +} + +function default_probe_result() { +return { +ok: false, +state: 'pending', +code: '000', +ok_count: 0, +attempts: 0, +loss: 0, +avg_ms: 0 +}; +} + +function default_access_payload(proxy_port, tcp_mode, udp_mode) { +return { +proxy_port: proxy_port || '7890', +tcp_mode: tcp_mode || 'redirect', +udp_mode: udp_mode || (tcp_mode || 'redirect'), +updated_at: 0, +stale: true, +updating: true, +last_checked_ago: -1, +direct: { +bytedance: default_probe_result(), +youtube: default_probe_result() +}, +proxy: { +bytedance: default_probe_result(), +youtube: default_probe_result() +} +}; +} + +function read_access_check_cache() { +if (!access(ACCESS_CACHE_FILE, 'r')) return null; +let raw = trim(readfile(ACCESS_CACHE_FILE) || ''); +if (!raw) return null; +let parsed = json(raw); +return parsed ? parsed : null; +} + +function access_cache_is_stale(cache, now) { +if (!cache || !cache.updated_at) return true; +let updated = int(cache.updated_at); +return updated <= 0 || (updated + ACCESS_CACHE_TTL) < now; +} + +function trigger_access_cache_refresh() { +system('mkdir -p /tmp/clashoo 2>/dev/null; : > ' + ACCESS_UPDATING_FLAG + ' 2>/dev/null; nice -n 19 sh /usr/share/clashoo/net/access_check_cache.sh >/dev/null 2>&1 &'); +} + +function access_check_is_updating(now) { +if (!access(ACCESS_UPDATING_FLAG, 'r')) return false; +let st = stat(ACCESS_UPDATING_FLAG); +let mtime = st ? int(st.mtime || 0) : 0; +if (mtime > 0 && now > 0 && (mtime + ACCESS_UPDATING_TTL) < now) { +unlink(ACCESS_UPDATING_FLAG); +return false; +} +return true; +} + +function access_check_daemon_running() { +if (!access(ACCESS_DAEMON_PID_FILE, 'r')) return false; +let pid = trim(readfile(ACCESS_DAEMON_PID_FILE) || ''); +if (!pid) return false; +if (!access('/proc/' + pid, 'r')) return false; +let cmd = readfile('/proc/' + pid + '/cmdline') || ''; +return index(cmd, 'access_check_daemon.sh') >= 0; +} + +function ensure_access_check_daemon() { +if (access_check_daemon_running()) return true; +system('nohup nice -n 19 sh /usr/share/clashoo/net/access_check_daemon.sh >/dev/null 2>&1 0 ? (now_epoch_sec() - payload.updated_at) : -1; +return payload; +} + +function get_cpu_arch() { +let p = popen("opkg status libc 2>/dev/null | grep Architecture | awk -F': ' '{print $2}'"); +if (!p) return ''; +let arch = trim(p.read('all')); +p.close(); +if (arch) return arch; +p = popen("apk --print-arch 2>/dev/null"); +if (!p) return ''; +arch = trim(p.read('all')); +p.close(); +return arch; +} + +function shell_read(cmd) { +let p = popen(cmd); +if (!p) return ''; +let out = trim(p.read('all') || ''); +p.close(); +return out; +} + +function pkg_version(pkg) { +let q = shell_quote(pkg); +return shell_read("if command -v opkg >/dev/null 2>&1; then opkg status " + q + " 2>/dev/null | awk -F': ' '/^Version:/{print $2; exit}'; elif command -v apk >/dev/null 2>&1; then apk list -I " + q + " 2>/dev/null | awk '{print $1; exit}' | sed -n 's/^" + pkg + "-//p'; fi"); +} + +// lgbm has no version; use a short sha256 of the model as its identifier (like Smart's hash) +function lgbm_local_ver() { +if (!stat('/etc/clashoo/Model.bin')) return ''; +return trim(shell_read("sha256sum /etc/clashoo/Model.bin 2>/dev/null | cut -c1-12") || ''); +} + +function file_mtime_label(path) { +let s = stat(path); +if (!s) return ''; +let ts = shell_read('date -d @' + s.mtime + ' "+%Y-%m-%d %H:%M:%S" 2>/dev/null || date -r ' + shell_quote(path) + ' "+%Y-%m-%d %H:%M:%S" 2>/dev/null'); +return ts || ('' + s.mtime); +} + +function read_component_state() { +let state = {}; +if (!access(COMPONENT_UPDATE_STATE_FILE, 'r')) return state; +let content = readfile(COMPONENT_UPDATE_STATE_FILE) || ''; +for (let line in split(content, '\n')) { +let pos = index(line, '='); +if (pos <= 0) continue; +state[substr(line, 0, pos)] = trim(substr(line, pos + 1)); +} +return state; +} + +function component_log_tail(lines) { +lines = lines || 80; +return shell_read('tail -' + int(lines) + ' ' + shell_quote(COMPONENT_UPDATE_LOG_FILE) + ' 2>/dev/null'); +} + +function component_last_log() { +return shell_read('tail -1 ' + shell_quote(COMPONENT_UPDATE_LOG_FILE) + ' 2>/dev/null'); +} + +// 从 `-v` / `version` 完整输出里抽短版本号: +// mihomo/smart "Mihomo Meta linux ..." → ;sing-box "sing-box version " → +function core_short_version(binary) { +let full = get_core_version(binary); +if (!full) return ''; +let m = match(full, /Meta[ \t]+([^ \t]+)/); +if (m) return m[1]; +m = match(full, /version[ \t]+([^ \t]+)/); +if (m) return m[1]; +return full; +} + +function component_installed_label(id) { +if (id == 'clashoo') return pkg_version('clashoo') || '未安装'; +if (id == 'luci') return pkg_version('luci-app-clashoo') || '未安装'; +if (id == 'mihomo') { +let bin = find_binary_for_family('mihomo'); +return bin ? (core_short_version(bin) || '已安装') : '未安装'; +} +if (id == 'smart') { +let bin = find_smart_binary(); +return bin ? (core_short_version(bin) || '已安装') : '未安装'; +} +if (id == 'singbox') { +let bin = find_binary_for_family('singbox'); +return bin ? (core_short_version(bin) || '已安装') : '未安装'; +} +if (id == 'lgbm') return lgbm_local_ver() || '未安装'; +if (id == 'china') return file_mtime_label('/usr/share/clashoo/nftables/geoip_cn.nft') || '未更新'; +if (id == 'geoip') return file_mtime_label('/etc/clashoo/Country.mmdb') || '未安装'; +return ''; +} + +function mihomo_alpha_label(ver) { +ver = ver || ''; +if (!ver) return ''; +if (match(ver, /^alpha-/)) return ver; +if (match(ver, /^[0-9a-fA-F]{7,}$/)) return 'alpha-' + ver; +return ver; +} + +function is_prerelease_label(ver) { +return !!match(ver || '', /(alpha|beta|rc|pre|smart)/i); +} + +function component_installed_versions(id) { +let out = {}; +if (id == 'mihomo') { + let stable = access('/usr/bin/mihomo-stable', 'x') ? read_first_line('/usr/share/clashoo/clash_meta_version') : ''; + if (!stable && access('/usr/bin/mihomo-stable', 'x')) stable = core_short_version('/usr/bin/mihomo-stable'); + if (is_prerelease_label(stable)) stable = ''; + let alpha = read_first_line('/usr/share/clashoo/mihomo_version'); + if (match(alpha, /^smart-/)) alpha = ''; + if (!alpha && access('/usr/bin/mihomo', 'x')) alpha = core_short_version('/usr/bin/mihomo'); + out.stable = stable || ''; + out.alpha = mihomo_alpha_label(alpha); + return out; +} +if (id == 'singbox') { + let stable = read_first_line('/usr/share/clashoo/singbox_stable_version'); + if (!stable && access(SINGBOX_BINARY_PATHS[0], 'x')) stable = core_short_version(SINGBOX_BINARY_PATHS[0]); + if (is_prerelease_label(stable)) stable = ''; + let alpha = read_first_line('/usr/share/clashoo/singbox_alpha_version'); + if (!alpha && access(SINGBOX_BINARY_PATHS[1], 'x')) alpha = core_short_version(SINGBOX_BINARY_PATHS[1]); + out.stable = stable || ''; + out.alpha = alpha || ''; + return out; +} +return out; +} + +const FEED_BASE = 'https://down.dllkids.xyz/openwrt-feed/clashoo'; +// bucket 多项目共用,按项目区分文件名免互相 sync 覆盖 +const FEED_MANIFEST_NAME = 'manifest-clashoo.txt'; +const GH_CLASHOO_REPO = 'kenzok8/openwrt-clashoo'; + +// 上游 amd64 默认是 AMD64-v3(要 AVX2),LXC/KVM 跑不起来;老值统一兜底 compatible +function normalize_mihomo_arch(a) { +if (!a) a = get_cpu_arch(); +if (!a) return 'amd64-compatible'; +if (a == 'amd64-compatible' || a == 'amd64-v1' || a == 'amd64-v2' || a == 'amd64-v3') return a; +if (a == 'amd64' || a == 'x86_64') return 'amd64-compatible'; +if (match(a, /^aarch64/)) return 'arm64'; +if (match(a, /^armv7|^arm_cortex-a[7-9]|^arm_cortex-a1[0-9]/)) return 'armv7'; +if (match(a, /^armv6|^arm_cortex-a[56]/)) return 'armv6'; +if (match(a, /^arm/) && a != 'arm64' && a != 'armv7' && a != 'armv6' && a != 'armv5') return 'armv5'; +if (match(a, /^i[3-6]86/)) return '386'; +if (match(a, /^mips64el/)) return 'mips64le'; +if (match(a, /^mips64/)) return 'mips64'; +if (match(a, /^mipsel/)) return 'mipsle'; +if (match(a, /^mips/) && a != 'mips64' && a != 'mipsle' && a != 'mips64le') return 'mips'; +return a; +} + +// alpha / smart 滚动版按 hash 比对;needle 用 -alpha- 边界,免 amd64 撞 amd64-compatible +function alpha_asset_ver(html, arch, kind) { +if (!html) return ''; +let needle = (kind == 'smart') + ? 'mihomo-linux-' + arch + '-alpha-smart-' + : 'mihomo-linux-' + arch + '-alpha-'; +for (let line in split(html, '\n')) { + if (index(line, needle) < 0) continue; + if (kind != 'smart' && index(line, '-alpha-smart-') >= 0) continue; + let m = (kind == 'smart') + ? match(line, /-(alpha-smart-[0-9A-Za-z]{6,})\.gz/) + : match(line, /-(alpha-[0-9a-f]{7,})\.gz/); + if (m) return m[1]; +} +return ''; +} + +// 从 release expanded_assets HTML 抽 clashoo / luci 版本号 +function gh_assets_versions(html) { +let out = {}; +if (!html) return out; +for (let line in split(html, '\n')) { + let m; + if (!out.clashoo) { + m = match(line, /(^|[\/" >])(clashoo_[^"<>\/ ]+_[^"<>\/ ]+\.ipk)/) || match(line, /(^|[\/" >])(clashoo-[^"<>\/ ]+\.apk)/); + if (m) { + let f = m[2]; + let v = match(f, /^clashoo_([^_]+)_.+\.ipk$/) || match(f, /^clashoo-(.+-r[0-9]+)-.+\.apk$/); + if (v) out.clashoo = v[1]; + } + } + if (!out.luci) { + m = match(line, /(^|[\/" >])(luci-app-clashoo_[^"<>\/ ]+_all\.ipk)/) || match(line, /(^|[\/" >])(luci-app-clashoo-[^"<>\/ ]+\.apk)/); + if (m) { + let f = m[2]; + let v = match(f, /^luci-app-clashoo_(.+)_all\.ipk$/) || match(f, /^luci-app-clashoo-(.+-r[0-9]+)-.+\.apk$/); + if (v) out.luci = v[1]; + } + } + if (out.clashoo && out.luci) break; +} +return out; +} + +// 并行抓取全部上游版本 —— 6+ 个 curl 串行会超 ubus 30s 上限,故全部 +// 后台并发,wait 后统一解析(总耗时 ≈ 最慢的单个请求)。 +// DISTRIB_RELEASE 可能是自定义串,不能当 SDK 版本;按包管理器试多个候选。 +function component_latest_versions() { +let latest = {}; +let core_arch = normalize_mihomo_arch(uci_get('clashoo', 'config', 'download_core') || ''); +let pkg_arch = trim(shell_read("opkg print-architecture 2>/dev/null | awk '/^arch /{print $2}' | tail -1") || ''); +if (!pkg_arch) pkg_arch = trim(shell_read('apk --print-arch 2>/dev/null') || ''); +let is_apk = !!trim(shell_read('command -v apk 2>/dev/null') || ''); +let sdks = is_apk ? ['25.12', '24.10'] : ['24.10', '23.05', '22.03', '21.02']; + +let dir = trim(shell_read('mktemp -d 2>/dev/null') || ''); +if (!dir) return latest; + +let GH = 'https://github.com/'; +// geoip 远端版本跟随当前 geoip_source:从生效的 mmdb 源 URL 解析出 GitHub 仓库; +// source=1 是 MaxMind(无 GitHub release),跳过 +let geoip_src = uci_get('clashoo', 'config', 'geoip_source') || ''; +let geoip_repo = ''; +if (geoip_src != '1') { + let mmdb_url = uci_get('clashoo', 'config', 'geoip_mmdb_url') || 'https://raw.githubusercontent.com/Loyalsoldier/geoip/release/Country.mmdb'; + let gm = match(mmdb_url, /github[a-z]*\.com\/([^\/]+)\/([^\/]+)/); + if (gm) geoip_repo = gm[1] + '/' + gm[2]; +} +// In kernel-only mode there is no TPROXY, so these github/api/B2 probes would +// leak out direct and stall at their -m timeout behind the GFW (the "检查更新 +// 半天不出反馈"). Route them through the running core, same as the download +// scripts (shared logic in proxy_lib.sh). Normal mode -> empty -> TPROXY. +let cdp = trim(shell_read('. /usr/share/clashoo/update/proxy_lib.sh; clashoo_detect_proxy 2>/dev/null') || ''); +let px = cdp ? ('--proxy ' + shell_quote(cdp) + ' ') : ''; +let cmd = ''; +cmd += "curl -fsS --connect-timeout 4 -o /dev/null -w '%{redirect_url}' -m 8 " + shell_quote(GH + 'MetaCubeX/mihomo/releases/latest') + ' >' + shell_quote(dir + '/ms') + ' 2>/dev/null &\n'; +cmd += "curl -fsS --connect-timeout 4 -o /dev/null -w '%{redirect_url}' -m 8 " + shell_quote(GH + 'SagerNet/sing-box/releases/latest') + ' >' + shell_quote(dir + '/ss') + ' 2>/dev/null &\n'; +cmd += 'curl -fsSL --connect-timeout 4 -m 8 ' + shell_quote(GH + 'MetaCubeX/mihomo/releases/expanded_assets/Prerelease-Alpha') + ' >' + shell_quote(dir + '/ma') + ' 2>/dev/null &\n'; +cmd += 'curl -fsSL --connect-timeout 4 -m 8 ' + shell_quote(GH + 'vernesong/mihomo/releases/expanded_assets/Prerelease-Alpha') + ' >' + shell_quote(dir + '/sm') + ' 2>/dev/null &\n'; +cmd += 'curl -fsSL --connect-timeout 4 -m 8 ' + shell_quote(GH + 'SagerNet/sing-box/releases.atom') + ' >' + shell_quote(dir + '/sa') + ' 2>/dev/null &\n'; +if (pkg_arch) + for (let sdk in sdks) + cmd += 'curl -fsSL --connect-timeout 4 -m 8 ' + shell_quote(FEED_BASE + '/' + sdk + '/' + pkg_arch + '/' + FEED_MANIFEST_NAME) + ' >' + shell_quote(dir + '/b_' + sdk) + ' 2>/dev/null &\n'; +// GitHub API 兜底,避免 expanded_assets 在部分网络下超时 +cmd += 'curl -fsSL --connect-timeout 4 -m 8 ' + shell_quote('https://api.github.com/repos/' + GH_CLASHOO_REPO + '/releases/latest') + ' >' + shell_quote(dir + '/gc') + ' 2>/dev/null &\n'; +// lgbm —— remote model sha256 from the release assets page (each asset lists its digest) +cmd += 'curl -fsSL --connect-timeout 4 -m 8 ' + shell_quote(GH + 'vernesong/mihomo/releases/expanded_assets/LightGBM-Model') + ' >' + shell_quote(dir + '/lg') + ' 2>/dev/null &\n'; +// geoip —— 源仓库 releases/latest 的 302 tag(多为日期串) +if (geoip_repo) + cmd += "curl -fsS --connect-timeout 4 -o /dev/null -w '%{redirect_url}' -m 8 " + shell_quote(GH + geoip_repo + '/releases/latest') + ' >' + shell_quote(dir + '/gi') + ' 2>/dev/null &\n'; +// inject the local-core proxy into every probe above (no-op when px is empty) +if (px) cmd = replace(cmd, 'curl ', 'curl ' + px); +cmd += 'wait\n'; +let pp = popen(cmd); +if (pp) { pp.read('all'); pp.close(); } + +let m; +// 稳定版 tag —— releases/latest 302 重定向 +m = match(readfile(dir + '/ms') || '', /\/tag\/([^\/?#\s]+)/); if (m) latest.mihomo_stable = m[1]; +m = match(readfile(dir + '/ss') || '', /\/tag\/([^\/?#\s]+)/); if (m) latest.singbox_stable = m[1]; +// sing-box alpha —— atom feed 第一个 prerelease tag(带 -alpha/-beta/-rc); +// SagerNet 稳定与 alpha 并行发布,atom 按时间排序,最新 entry 可能是稳定版(如 v1.13.13), +// 直接取第一个 entry 会让 alpha 通道误显示稳定版本号 +m = match(readfile(dir + '/sa') || '', /\/releases\/tag\/(v[^"?#\s]*-[^"?#\s]+)/); if (m) latest.singbox_alpha = m[1]; +// lgbm —— locate the configured asset in the assets page, then its sha256 digest +let lg_html = readfile(dir + '/lg') || ''; +let lg_url = uci_get('clashoo', 'config', 'smart_lgbm_url') || 'Model.bin'; +let lg_parts = split(lg_url, '/'); +let lg_asset = lg_parts[length(lg_parts) - 1] || 'Model.bin'; +let lg_pos = index(lg_html, '/' + lg_asset + '"'); +if (lg_pos >= 0) { + let lg_sha = match(substr(lg_html, lg_pos), /sha256:([0-9a-f]{12})/); + if (lg_sha) latest.lgbm = lg_sha[1]; +} +// geoip —— 源仓库最新 release tag(多为日期串 YYYYMMDDhhmm)→ YYYY-MM-DD +let gt = match(readfile(dir + '/gi') || '', /\/tag\/([^\/?#\s]+)/); +if (gt) { + let d8 = match(gt[1], /^(\d{4})(\d{2})(\d{2})/); + latest.geoip = d8 ? (d8[1] + '-' + d8[2] + '-' + d8[3]) : gt[1]; +} +// mihomo alpha / smart —— Prerelease-Alpha 资源清单的 hash +let v; +v = alpha_asset_ver(readfile(dir + '/ma') || '', core_arch, 'alpha'); if (v) latest.mihomo_alpha = v; +v = alpha_asset_ver(readfile(dir + '/sm') || '', core_arch, 'smart'); if (v) latest.smart = v; +// clashoo / luci —— R2 feed manifest,按 SDK 候选取第一个命中 +if (pkg_arch) +for (let sdk in sdks) { + let txt = readfile(dir + '/b_' + sdk); + if (!txt) continue; + let hit = false; + for (let line in split(txt, '\n')) { + let kv = match(trim(line), /^(core|luci)=(.+)$/); + if (!kv) continue; + let f = kv[2], mv; + if (kv[1] == 'core') { + mv = match(f, /^clashoo_([^_]+)_.+\.ipk$/) || match(f, /^clashoo-(.+-r[0-9]+)-.+\.apk$/); + if (mv) { latest.clashoo = mv[1]; hit = true; } + } else { + mv = match(f, /^luci-app-clashoo_([^_]+)_.+\.ipk$/) || match(f, /^luci-app-clashoo-(.+-r[0-9]+)-.+\.apk$/); + if (mv) latest.luci = mv[1]; + } + } + if (hit) break; +} +// R2 feed 缺啥用 GitHub 兜底 +if (!latest.clashoo || !latest.luci) { + let gh = gh_assets_versions(readfile(dir + '/gc') || ''); + if (!latest.clashoo && gh.clashoo) latest.clashoo = gh.clashoo; + if (!latest.luci && gh.luci) latest.luci = gh.luci; +} + +let rp = popen('rm -rf ' + shell_quote(dir)); if (rp) rp.close(); +return latest; +} + +function component_defs() { +return [ +{ id: 'clashoo', name: 'Clashoo 核心', description: 'mihomo 运行时与脚本', kind: 'pkg' }, +{ id: 'luci', name: '客户端', description: 'LuCI 界面与中文语言包', kind: 'pkg' }, +{ id: 'mihomo', name: 'mihomo 内核', description: 'Clash Meta 核心', kind: 'core', variant: true }, +{ id: 'singbox', name: 'sing-box 内核', description: 'sing-box 核心', kind: 'core', variant: true }, +{ id: 'smart', name: 'mihomo Smart', description: 'vernesong Smart 核心', kind: 'core' }, +{ id: 'lgbm', name: 'LightGBM 模型', description: 'Smart 策略模型文件', kind: 'data' }, +{ id: 'china', name: '大陆白名单', description: '大陆 IP 直连白名单', kind: 'data' }, +{ id: 'geoip', name: 'GeoIP / GeoSite', description: 'GeoIP / GeoSite 数据', kind: 'data' } +]; +} + +function valid_component_id(id) { +for (let comp in component_defs()) +if (comp.id == id) return true; +return false; +} + +function config_dir_by_type(type) { +if (type == '1' || type == 'sub') return '/usr/share/clashoo/config/sub'; +if (type == '2' || type == 'upload') return '/usr/share/clashoo/config/upload'; +if (type == '3' || type == 'custom') return '/usr/share/clashoo/config/custom'; +return ''; +} + +function safe_name(name) { +name = name || ''; +if (!name) return ''; +/* 拒绝前后导空白(不静默 trim,避免与可见名称偏差) */ +if (trim(name) != name) return ''; +/* 路径遍历防护 */ +if (index(name, '/') >= 0 || index(name, '\\') >= 0) return ''; +if (index(name, '..') >= 0) return ''; +if (substr(name, 0, 1) == '.') return ''; +/* 黑名单:# 注释、空格、? * : 等不安全/系统保留字符 */ +if (index(name, '#') >= 0) return ''; +if (index(name, ' ') >= 0) return ''; +if (index(name, '?') >= 0) return ''; +if (index(name, '*') >= 0) return ''; +if (index(name, ':') >= 0) return ''; +/* 拒绝 NUL 与换行/制表等控制字符(逐字节扫描,ucode 正则不支持 \x 转义) */ +let n = length(name); +for (let i = 0; i < n; i++) { +let ch = ord(name, i); +if (ch < 0x20) return ''; +} +/* 允许 Unicode(CJK 等)—— 不再用纯 ASCII 白名单 */ +return name; +} + +function ensure_yaml_name(name) { +name = safe_name(name); +if (!name) return ''; +if (!match(name, /\.(yaml|yml)$/)) +name = name + '.yaml'; +return name; +} + +function file_name_from_url(url) { +url = trim(url || ''); +if (!url) return ''; +url = replace(url, /[?#].*$/, ''); +let name = replace(url, /^.*\//, ''); +return ensure_yaml_name(name); +} + +function template_output_name(sub_name, tpl_name) { +let s = replace((sub_name || ''), /\.(yaml|yml)$/, ''); +let t = replace((tpl_name || ''), /\.(yaml|yml)$/, ''); +s = replace(s, /[^A-Za-z0-9._-]/g, '-'); +t = replace(t, /[^A-Za-z0-9._-]/g, '-'); +if (!s) s = 'sub'; +if (!t) t = 'template'; +return '_merged_' + s + '__' + t + '.yaml'; +} + +function template_search_dirs() { +return [TEMPLATE_DIR, '/usr/share/clashoo/config/template']; +} + +function find_template_path(name) { +name = ensure_yaml_name(name || ''); +if (!name) return ''; +for (let dir in template_search_dirs()) { +let p = dir + '/' + name; +if (access(p, 'r')) return p; +} +return ''; +} + +function trim_quotes(v) { +v = trim(v || ''); +v = replace(v, /^["']/, ''); +v = replace(v, /["']$/, ''); +return v; +} + +function parse_controller_port(value, fallback) { +value = trim(value || ''); +if (!value) return fallback || '9090'; +value = replace(value, /^https?:\/\//, ''); +value = replace(value, /\/.*$/, ''); +let m = match(value, /:([0-9]+)$/); +if (m && m[1]) return m[1]; +if (match(value, /^[0-9]+$/)) return value; +return fallback || '9090'; +} + +function parse_mihomo_api_auth(path) { +let info = { has_port: false, port: '', has_secret: false, secret: '' }; +if (!access(path, 'r')) return info; +let raw = readfile(path) || ''; +if (!raw) return info; + +for (let line in split(raw, '\n')) { + line = trim(line || ''); + if (!line) continue; + + let m_controller = match(line, /^external-controller:\s*(.+)$/); + if (m_controller && m_controller[1]) { + info.has_port = true; + info.port = parse_controller_port(trim_quotes(m_controller[1]), '9090'); + } + + let m_secret = match(line, /^secret:\s*(.*)$/); + if (m_secret) { + info.has_secret = true; + let secret = trim(m_secret[1] || ''); + info.secret = trim_quotes(secret); + } +} + +return info; +} + +function parse_singbox_api_auth(path) { +let info = { has_port: false, port: '', has_secret: false, secret: '' }; +if (!access(path, 'r')) return info; +let raw = readfile(path) || ''; +if (!raw) return info; + +let cfg = null; +try { + cfg = json(raw); +} catch (e) { + return info; +} + +let api = cfg?.experimental?.clash_api; +if (!api || type(api) != 'object') return info; + +let controller = api.external_controller || ''; +if (controller) { + info.has_port = true; + info.port = parse_controller_port(controller, '9090'); +} + +if (type(api.secret) != 'undefined' && api.secret !== null) { + info.has_secret = true; + info.secret = '' + api.secret; +} + +return info; +} + +function get_clash_api_auth() { +let c = cursor(); +c.load('clashoo'); +let auth = { + port: c.get('clashoo', 'config', 'dash_port') || '9090', + pass: c.get('clashoo', 'config', 'dash_pass') || '' +}; + +let family = running_core_family() || get_core_type(); +if (family == 'singbox') { + let sb = parse_singbox_api_auth(SINGBOX_RUNTIME_CONFIG); + if (sb.has_port) auth.port = sb.port || auth.port; + if (sb.has_secret) auth.pass = sb.secret || ''; +} else { + let mm = parse_mihomo_api_auth('/etc/clashoo/config.yaml'); + if (mm.has_port) auth.port = mm.port || auth.port; + if (mm.has_secret) auth.pass = mm.secret || ''; +} + +return auth; +} + +function api_unauthorized_payload(obj) { +if (!obj || type(obj) != 'object') return false; +let msg = '' + (obj.message || obj.error || ''); +return !!match(msg, /[Uu]nauthorized|[Ff]orbidden|401/); +} + +function mihomo_api_post(path) { +let api = get_clash_api_auth(); +let dash_port = api.port; +let dash_pass = api.pass; +let auth = dash_pass ? ('-H ' + shell_quote('Authorization: Bearer ' + dash_pass) + ' ') : ''; +let url = 'http://127.0.0.1:' + dash_port + path; +let cmd = 'curl -s -o /dev/null -w "%{http_code}" -m 10 -X POST ' + auth + shell_quote(url) + ' 2>/dev/null'; +let p = popen(cmd); +if (!p) return '000'; +let code = trim(p.read('all')); +p.close(); +return code || '000'; +} + +function clash_api_get(path, timeout) { +let api = get_clash_api_auth(); +let dash_port = api.port; +let dash_pass = api.pass; +let auth = dash_pass ? ('-H ' + shell_quote('Authorization: Bearer ' + dash_pass) + ' ') : ''; +let t = timeout || 4; +let url = 'http://127.0.0.1:' + dash_port + path; +let cmd = 'curl -s -m ' + t + ' ' + auth + shell_quote(url) + ' 2>/dev/null'; +let p = popen(cmd); +if (!p) return ''; +let raw = trim(p.read('all')); +p.close(); +return raw; +} + +function clash_api_json(path, timeout) { +let raw = clash_api_get(path, timeout); +if (!raw) return null; +try { + let obj = json(raw); + return obj ? obj : null; +} catch (e) { + /* Some endpoints can stream multiple JSON frames; parse first valid line */ + for (let line in split(raw, '\n')) { + line = trim(line || ''); + if (!line) continue; + try { + let obj2 = json(line); + if (obj2) return obj2; + } catch (e2) {} + } + return null; +} +} + +/* 百分号编码:clash API 路径里的组名常含 emoji/中文/空格,curl 不会自动编码 */ +function uri_encode(s) { +s = '' + (s || ''); +let out = ''; +for (let i = 0; i < length(s); i++) { + let ch = substr(s, i, 1); + let o = ord(ch); + if ((o >= 48 && o <= 57) || (o >= 65 && o <= 90) || (o >= 97 && o <= 122) || + o == 45 || o == 46 || o == 95 || o == 126) + out += ch; + else + out += sprintf('%%%02X', o); +} +return out; +} + +/* PUT + JSON body,用于切换 Selector 组(成功返回 204);返回 HTTP 状态码字符串 */ +function clash_api_put_json(path, body) { +let api = get_clash_api_auth(); +let auth = api.pass ? ('-H ' + shell_quote('Authorization: Bearer ' + api.pass) + ' ') : ''; +let url = 'http://127.0.0.1:' + api.port + path; +let payload = sprintf('%J', body); +let cmd = 'curl -s -o /dev/null -w "%{http_code}" -m 8 -X PUT ' + auth + + '-H ' + shell_quote('Content-Type: application/json') + ' ' + + '-d ' + shell_quote(payload) + ' ' + shell_quote(url) + ' 2>/dev/null'; +let p = popen(cmd); +if (!p) return '000'; +let code = trim(p.read('all')); +p.close(); +return code || '000'; +} + +function read_overview_stats_cache() { +let raw = trim(readfile(OVERVIEW_STATS_CACHE_FILE) || ''); +if (!raw) return {}; +try { + let obj = json(raw); + return obj ? obj : {}; +} catch (e) { + return {}; +} +} + +function write_overview_stats_cache(payload) { +if (!payload) return; +writefile(OVERVIEW_STATS_CACHE_FILE, sprintf('%J', payload)); +} + +function parse_sub_userinfo(raw) { +let info = { upload: 0, download: 0, total: 0, expire: 0 }; +if (!raw) return info; +for (let part in split(raw, ';')) { +let kv = split(trim(part), '='); +if (length(kv) == 2) { +let k = trim(kv[0]); +let v = int(trim(kv[1])) || 0; +if (k == 'upload' || k == 'download' || k == 'total' || k == 'expire') +info[k] = v; +} +} +return info; +} + +function read_subscriptions() { +let rows = []; +if (!access(LIST_FILE, 'r')) return rows; +let content = readfile(LIST_FILE) || ''; +for (let line in split(content, '\n')) { +line = trim(line); +if (!line) continue; +let parts = split(line, '#'); +if (length(parts) < 2) continue; +let name = trim(parts[0]); +let url = trim(parts[1]); +let typ = length(parts) > 2 ? trim(parts[2]) : 'clashoo'; +if (!name || !url) continue; +let info_path = SUB_DIR + '/' + name + '.info'; +let raw_info = access(info_path, 'r') ? trim(readfile(info_path) || '') : ''; +let ui = parse_sub_userinfo(raw_info); +push(rows, { name, url, type: typ, +sub_upload: ui.upload, sub_download: ui.download, +sub_total: ui.total, sub_expire: ui.expire }); +} +return rows; +} + +function build_configs_payload() { +let configs = []; +let subs = read_subscriptions(); +let core_type = get_core_type(); +let current = get_current_config(core_type); +let is_singbox = (core_type == 'singbox'); + +function has_cfg(n) { +for (let i = 0; i < length(configs); i++) +if (configs[i] == n) return true; +return false; +} + +if (is_singbox) { +/* sing-box 内核:只列出 .json 配置 */ +for (let f in (glob(SINGBOX_DIR + '/*.json') || [])) { +let n = replace(f, SINGBOX_DIR + '/', ''); +if (n && !has_cfg(n)) push(configs, n); +} +} else { +/* mihomo / smart 内核:只列出 .yaml / .yml 配置 */ +for (let row in subs) { +let n = row.name; +if (!n) continue; +if (!access('/usr/share/clashoo/config/sub/' + n, 'r')) continue; +if (!has_cfg(n)) push(configs, n); +} + +for (let f in (glob('/usr/share/clashoo/config/upload/*.yaml') || [])) { +let n = replace(f, '/usr/share/clashoo/config/upload/', ''); +if (n && !has_cfg(n)) push(configs, n); +} +for (let f in (glob('/usr/share/clashoo/config/upload/*.yml') || [])) { +let n = replace(f, '/usr/share/clashoo/config/upload/', ''); +if (n && !has_cfg(n)) push(configs, n); +} + +for (let f in (glob('/usr/share/clashoo/config/custom/*.yaml') || [])) { +let n = replace(f, '/usr/share/clashoo/config/custom/', ''); +if (n && !has_cfg(n)) push(configs, n); +} +for (let f in (glob('/usr/share/clashoo/config/custom/*.yml') || [])) { +let n = replace(f, '/usr/share/clashoo/config/custom/', ''); +if (n && !has_cfg(n)) push(configs, n); +} +} + +/* 仅当 current 真实存在于任一标准目录时才补到列表,避免删除文件后下拉框残留 */ +if (current && !has_cfg(current)) { +let exists = access('/usr/share/clashoo/config/sub/' + current, 'r') || + access('/usr/share/clashoo/config/upload/' + current, 'r') || + access('/usr/share/clashoo/config/custom/' + current, 'r') || + access(SINGBOX_DIR + '/' + current, 'r'); +if (exists) push(configs, current); +else current = ''; +} + +return { configs: configs, current: current, core_type: core_type }; +} + +function get_access_payload() { +let proxy_port = uci_get('clashoo', 'config', 'mixed_port') || uci_get('clashoo', 'config', 'http_port') || '7890'; +let tcp_mode = uci_get('clashoo', 'config', 'tcp_mode') || 'redirect'; +let udp_mode = uci_get('clashoo', 'config', 'udp_mode') || tcp_mode; +ensure_access_check_daemon(); +let now = now_epoch_sec(); +let cache = read_access_check_cache(); +let stale = access_cache_is_stale(cache, now); +let updating = access_check_is_updating(now); + +if ((stale || !cache) && !updating) { +trigger_access_cache_refresh(); +updating = true; +} + +if (!cache) +return default_access_payload(proxy_port, tcp_mode, udp_mode); + +return ensure_access_payload_shape(cache, proxy_port, tcp_mode, udp_mode, stale, updating); +} + +function read_template_bindings() { +let rows = []; +if (!access(TEMPLATE_BIND_FILE, 'r')) return rows; +let content = readfile(TEMPLATE_BIND_FILE) || ''; +for (let line in split(content, '\n')) { +line = trim(line || ''); +if (!line) continue; +let parts = split(line, '#'); +if (length(parts) < 2) continue; +let sub_name = ensure_yaml_name(parts[0] || ''); +let template_name = ensure_yaml_name(parts[1] || ''); +let enabled = length(parts) > 2 ? trim(parts[2] || '') : '1'; +if (!sub_name || !template_name) continue; +push(rows, { +sub_name, +template_name, +enabled: (enabled == '1' || enabled == 'true') ? '1' : '0' +}); +} +return rows; +} + +function write_template_bindings(rows) { +let lines = []; +for (let row in (rows || [])) { +if (!row || !row.sub_name || !row.template_name) continue; +push(lines, row.sub_name + '#' + row.template_name + '#' + (row.enabled == '1' ? '1' : '0')); +} +system('mkdir -p /usr/share/clashbackup'); +return writefile(TEMPLATE_BIND_FILE, join('\n', lines) + '\n') !== null; +} + +function find_template_binding(sub_name) { +for (let row in read_template_bindings()) { +if (row.sub_name == sub_name) return row; +} +return null; +} + +// Migrate sing-box config from pre-1.12 deprecated formats to 1.12+ format +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; +} + +function restore_backup_json_locked(raw) { +let rollback_ready = false; +try { +if (!raw) return { success: false, message: '备份内容为空' }; +if (length(raw) > BACKUP_MAX_JSON_SIZE) + return { success: false, message: '旧版 JSON 备份超过 8MB' }; +let obj = null; +try { obj = json(raw); } catch (e) { obj = null; } +if (type(obj) != 'object') + return { success: false, message: '备份文件格式错误,无法解析' }; +let manifest = obj.manifest; +if (type(manifest) != 'object' || manifest.marker != 'clashoo-backup-v1') + return { success: false, message: '这不是有效的 clashoo 备份文件' }; +let files = obj.files; +if (type(files) != 'object') + return { success: false, message: '备份文件缺少配置数据' }; + +let BACKUP_DIR_MAP = { + 'config/sub': '/usr/share/clashoo/config/sub', + 'config/upload': '/usr/share/clashoo/config/upload', + 'config/custom': '/usr/share/clashoo/config/custom', + 'config/singbox': SINGBOX_DIR, + 'templates': TEMPLATE_USER_DIR +}; +let BACKUP_FIXED_MAP = { + 'uci': '/etc/config/clashoo', + 'meta/confit_list.conf': LIST_FILE, + 'meta/template_bindings.conf': TEMPLATE_BIND_FILE +}; + +let plan = []; +let entry_count = 0; +for (let rel in files) { + entry_count++; + if (entry_count > BACKUP_MAX_ENTRIES) + return { success: false, message: '备份文件条目超过 2048 个' }; + let content = files[rel]; + if (type(content) != 'string') + return { success: false, message: '备份文件含非法数据项: ' + rel }; + if (BACKUP_FIXED_MAP[rel]) { + push(plan, { path: BACKUP_FIXED_MAP[rel], content: content }); + continue; + } + let slash = rindex(rel, '/'); + if (slash < 0) + return { success: false, message: '备份文件含未知数据项: ' + rel }; + let prefix = substr(rel, 0, slash); + let fname = substr(rel, slash + 1); + let dir = BACKUP_DIR_MAP[prefix]; + if (!dir) + return { success: false, message: '备份文件含未知数据项: ' + rel }; + if (!fname || safe_name(fname) != fname) + return { success: false, message: '备份文件含非法文件名: ' + rel }; + push(plan, { path: dir + '/' + fname, content: content }); +} + +unlink(BACKUP_JSON_ROLLBACK_FILE); +if (system('sh ' + shell_quote(BACKUP_ARCHIVE_SCRIPT) + ' export ' + + shell_quote(BACKUP_JSON_ROLLBACK_FILE) + ' >/dev/null 2>&1') != 0) { + unlink(BACKUP_JSON_ROLLBACK_FILE); + return { success: false, message: '无法创建还原前安全快照,未修改当前配置' }; +} +rollback_ready = true; + +let apply_error = ''; +for (let prefix in BACKUP_DIR_MAP) { + let d = BACKUP_DIR_MAP[prefix]; + if (system('mkdir -p ' + shell_quote(d)) != 0 || + system('rm -f ' + shell_quote(d) + '/* >/dev/null 2>&1') != 0) { + apply_error = '无法清空配置目录: ' + d; + break; + } +} +let written = 0; +for (let item in plan) { + if (apply_error) break; + let p = item.path; + let ps = rindex(p, '/'); + if (ps > 0 && system('mkdir -p ' + shell_quote(substr(p, 0, ps))) != 0) { + apply_error = '无法创建配置目录: ' + p; + break; + } + if (writefile(p, item.content) === null) { + apply_error = '写入失败: ' + p; + break; + } + written++; +} + +if (apply_error) { + let rollback_rc = system('sh ' + shell_quote(BACKUP_ARCHIVE_SCRIPT) + ' restore-held ' + + shell_quote(BACKUP_JSON_ROLLBACK_FILE) + ' >/dev/null 2>&1'); + unlink(BACKUP_JSON_ROLLBACK_FILE); + rollback_ready = false; + return { success: false, message: apply_error + + (rollback_rc == 0 ? ';已回滚原配置' : ';自动回滚失败,请检查存储空间') }; +} + +unlink(BACKUP_JSON_ROLLBACK_FILE); +rollback_ready = false; +system('sh /usr/share/clashoo/rpc/rpc_async.sh restart >/dev/null 2>&1'); +return { success: true, restored: written, + message: '已还原 ' + written + ' 个文件,正在重启服务' }; +} catch (e) { +if (rollback_ready) { + system('sh ' + shell_quote(BACKUP_ARCHIVE_SCRIPT) + ' restore-held ' + + shell_quote(BACKUP_JSON_ROLLBACK_FILE) + ' >/dev/null 2>&1'); + unlink(BACKUP_JSON_ROLLBACK_FILE); +} +return { success: false, message: '导入失败: ' + e }; +} +} + +function restore_backup_json(raw) { +if (!backup_tmp_ready()) + return { success: false, message: '备份临时目录不安全或无法创建' }; +if (system('sh ' + shell_quote(BACKUP_ARCHIVE_SCRIPT) + ' lock >/dev/null 2>&1') != 0) + return { success: false, message: '已有备份正在还原,请稍后重试' }; +let result = null; +try { + result = restore_backup_json_locked(raw); +} catch (e) { + result = { success: false, message: '导入失败: ' + e }; +} +system('sh ' + shell_quote(BACKUP_ARCHIVE_SCRIPT) + ' unlock >/dev/null 2>&1'); +return result; +} + +const methods = { +version: { +call: function() { +try { +let binary = find_binary(); +return { +app: read_first_line('/usr/share/clashoo/luci_version'), +core: get_core_version(binary), +binary: binary +}; +} catch (e) { +return { success: false, error: 'version_failed', message: '' + e }; +} +} +}, + +status: { +call: function() { +try { +let c = cursor(); +c.load('clashoo'); +let configured_core = get_core_type(); +let running = is_running(); +let proxy_mode = c.get('clashoo', 'config', 'p_mode') || 'rule'; +let conf_path = c.get('clashoo', 'config', 'use_config') || ''; +let panel_type = c.get('clashoo', 'config', 'dashboard_panel')|| 'zashboard'; +let tcp_mode = c.get('clashoo', 'config', 'tcp_mode') || 'tun'; +let udp_mode = c.get('clashoo', 'config', 'udp_mode') || tcp_mode; +let stack = c.get('clashoo', 'config', 'stack') || 'system'; +let api = get_clash_api_auth(); +let dash_port = api.port || (c.get('clashoo', 'config', 'dash_port') || '9090'); +let dash_pass = api.pass || ''; +let effective_tcp_mode = runtime_state_get('effective_tcp_mode') || tcp_mode; +let effective_udp_mode = runtime_state_get('effective_udp_mode') || udp_mode; +let runtime_degraded = runtime_state_get('degraded') == '1'; +let runtime_degrade_reason = runtime_state_get('degrade_reason') || ''; +let health_status = runtime_state_get('health_status') || (running ? 'unknown' : 'stopped'); +let health_detail = runtime_state_get('health_detail') || ''; +if (!running) { + health_status = 'stopped'; + if (health_detail != 'boot_disabled' && health_detail != 'service_disabled') + health_detail = 'service_stopped'; +} +let has_tun_device = runtime_state_get('has_tun_device'); +let local_ip = get_local_ip(); +let config = get_display_config_name(configured_core); +let slash = rindex(conf_path, '/'); +let conf_name = slash >= 0 ? substr(conf_path, slash + 1) : conf_path; +if (configured_core == 'singbox' && config) + conf_name = config; +let dcore = c.get('clashoo', 'config', 'dcore') || '2'; +return { running, dash_port, dash_pass, proxy_mode, conf_path: conf_name, config, + panel_type, tcp_mode, udp_mode, stack, + effective_tcp_mode, effective_udp_mode, + runtime_degraded, runtime_degrade_reason, + health_status, health_detail, has_tun_device, + core_type: configured_core, dcore, local_ip, + has_smart: !!find_smart_binary() }; +} catch (e) { +return { success: false, error: 'status_failed', message: '' + e }; +} +} +}, + +reload: { +call: function() { +let svc = get_service_name(); +return { success: system('service ' + svc + ' reload >/dev/null 2>&1') == 0 }; +} +}, + +restart: { +call: function() { +return { success: system('sh /usr/share/clashoo/rpc/rpc_async.sh restart >/dev/null 2>&1') == 0 }; +} +}, + +start: { +call: function() { +let c = cursor(); +c.load('clashoo'); +c.set('clashoo', 'config', 'enable', '1'); +c.commit('clashoo'); +system('/etc/init.d/clashoo enable >/dev/null 2>&1'); +system('sh /usr/share/clashoo/rpc/rpc_async.sh start >/dev/null 2>&1'); +return { success: true }; +} +}, + +stop: { +call: function() { +let c = cursor(); +c.load('clashoo'); +c.set('clashoo', 'config', 'enable', '0'); +c.commit('clashoo'); +system('sh /usr/share/clashoo/rpc/rpc_async.sh stop >/dev/null 2>&1'); +return { success: true }; +} +}, + +commit_config: { +call: function() { +let c = cursor(); +c.load('clashoo'); +sync_legacy_core_fields(c); +c.commit('clashoo'); +let rc = system('uci commit clashoo >/dev/null 2>&1'); +return { success: rc === 0 }; +} +}, + +dns_auto_setup: { +call: function() { +let running = is_running(); +let p = popen('sh /usr/share/clashoo/net/dns_auto_setup.sh --apply 2>/dev/null'); +if (!p) return { success: false, message: 'DNS 自动配置启动失败' }; +let raw = trim(p.read('all') || ''); +p.close(); +let res = null; +try { + res = raw ? json(raw) : null; +} catch (e) {} +if (!res || !res.success) +return res || { success: false, message: 'DNS 自动配置失败' }; +res.restarted = false; +if (running) { + system('sh /usr/share/clashoo/rpc/rpc_async.sh restart >/dev/null 2>&1'); + res.restarted = true; +} +return res; +} +}, + +set_mode: { +args: { mode: 'mode' }, +call: function(req) { + let mode = req.args?.mode || 'fake-ip'; + if (mode != 'fake-ip' && mode != 'tun-system' && mode != 'tun-gvisor' && mode != 'tun-mixed') + return { error: 'invalid mode' }; + let c = cursor(); c.load('clashoo'); + if (mode == 'tun-system' || mode == 'tun-gvisor' || mode == 'tun-mixed') { + c.set('clashoo', 'config', 'tun_mode', '1'); + c.set('clashoo', 'config', 'tcp_mode', 'tun'); + c.set('clashoo', 'config', 'udp_mode', 'tun'); + c.set('clashoo', 'config', 'stack', mode == 'tun-mixed' ? 'mixed' : (mode == 'tun-gvisor' ? 'gvisor' : 'system')); + c.set('clashoo', 'config', 'enable_udp', '1'); + c.set('clashoo', 'config', 'enhanced_mode', 'fake-ip'); +} else { + c.set('clashoo', 'config', 'tun_mode', '0'); + c.set('clashoo', 'config', 'tcp_mode', 'redirect'); + c.set('clashoo', 'config', 'udp_mode', 'tproxy'); + c.set('clashoo', 'config', 'enhanced_mode', 'fake-ip'); +} +c.commit('clashoo'); +system('uci commit clashoo >/dev/null 2>&1'); +if (is_running()) system('sh /usr/share/clashoo/rpc/rpc_async.sh restart >/dev/null 2>&1'); +return { success: true }; +} +}, + +set_proxy_mode: { +args: { mode: 'mode' }, +call: function(req) { +let mode = req.args?.mode || 'rule'; +if (mode != 'rule' && mode != 'global' && mode != 'direct') +return { error: 'invalid mode' }; +let c = cursor(); c.load('clashoo'); +c.set('clashoo', 'config', 'p_mode', mode); +c.commit('clashoo'); +if (is_running()) system('service ' + get_service_name() + ' restart >/dev/null 2>&1'); +return { success: true }; +} +}, + +set_core: { +args: { core: 'core', dcore: 'dcore', action: 'action' }, +call: function(req) { +let core = req.args?.core || 'mihomo'; +if (core == 'sing-box') core = 'singbox'; +let dcore = req.args?.dcore || ''; +let action = req.args?.action || 'stop'; +if (action != 'stop' && action != 'save' && action != 'apply') +return { success: false, error: 'invalid_action', message: '无效的内核切换动作' }; +let target_error = core_target_error(core, dcore); +if (target_error) +return { success: false, error: target_error.error, message: target_error.message }; + +let running_before = is_running(); + +let c = cursor(); c.load('clashoo'); +c.set('clashoo', 'config', 'core_type', core); +c.set('clashoo', 'config', 'dcore', dcore); +/* Smart 策略仅 Smart 内核(dcore=1)有意义。切到 Smart 时自动开启 + * smart_auto_switch;切回普通 mihomo / sing-box 时自动关闭,避免 + * Smart 模型字段误注入到非 Smart 配置。 */ +c.set('clashoo', 'config', 'smart_auto_switch', dcore === '1' ? '1' : '0'); +sync_legacy_core_fields(c); +c.commit('clashoo'); +system('uci commit clashoo >/dev/null 2>&1'); + +// Overview 旧调用默认 stop;System 页可显式 save 或 apply。 +// 所有耗时 init 操作仍由 rpc_async.sh + flock 串行化。 +let restarting = false; +if (action == 'save') { + // Persist only. The selected core takes effect on the next start/restart. +} +else if (running_before && action == 'stop') + system('sh /usr/share/clashoo/rpc/rpc_async.sh stop >/dev/null 2>&1'); +else if (running_before && action == 'apply') { + system('sh /usr/share/clashoo/rpc/rpc_async.sh restart >/dev/null 2>&1'); + restarting = true; +} + +return { success: true, core_type: core, dcore, + running_before, restarting, stopped: running_before && action == 'stop' }; +} +}, + +set_panel: { +args: { name: 'name' }, +call: function(req) { +let name = req.args?.name || 'zashboard'; +if (name != 'metacubexd' && name != 'yacd' && name != 'zashboard' && name != 'razord') +name = 'zashboard'; +let c = cursor(); c.load('clashoo'); +c.set('clashoo', 'config', 'dashboard_panel', name); +c.commit('clashoo'); +system('uci commit clashoo >/dev/null 2>&1'); +let activated = activate_dashboard_panel(name); +return { success: true, activated }; +} +}, + +update_panel: { +args: { name: 'name' }, +call: function(req) { +if (access('/var/run/panel_downloading', 'r')) +return { success: false, busy: true, message: '面板正在下载' }; +let name = req.args?.name || 'zashboard'; +if (name != 'metacubexd' && name != 'yacd' && name != 'zashboard' && name != 'razord') +name = 'zashboard'; +let c = cursor(); c.load('clashoo'); +c.set('clashoo', 'config', 'dashboard_panel', name); +c.commit('clashoo'); +system('uci commit clashoo >/dev/null 2>&1'); +let pretty = name; +if (name == 'metacubexd') pretty = 'MetaCubeXD'; +else if (name == 'yacd') pretty = 'YACD'; +else if (name == 'zashboard') pretty = 'Zashboard'; +else if (name == 'razord') pretty = 'Razord'; +system("printf '%s - 面板更新任务已提交: " + shell_quote(pretty) + "\\n' \"$(date '+%Y-%m-%d %H:%M:%S')\" >>/tmp/clash_update.txt"); +// seed an immediate state so the UI poller never reads a stale prior result +system("touch /var/run/panel_downloading; printf 'downloading:" + shell_quote(name) + ":开始下载' >/tmp/clash_panel_download_state"); +system("nohup sh /usr/share/clashoo/update/panel_download.sh " + shell_quote(name) + " >>/tmp/clash_update.txt 2>&1 = 0) { +state = substr(line, 0, i1); +let rest = substr(line, i1 + 1); +let i2 = index(rest, ':'); +if (i2 >= 0) { panel = substr(rest, 0, i2); msg = substr(rest, i2 + 1); } +else panel = rest; +} +return { downloading: downloading, state: state, panel: panel, msg: msg }; +} +}, + +list_configs: { +call: function() { +return build_configs_payload(); +} +}, + +set_config: { +args: { name: 'name' }, +call: function(req) { +let name = safe_name(req.args?.name || ''); +if (!name) return { error: 'missing name' }; + +if (match(name, /\.json$/)) { +let profile = SINGBOX_DIR + '/' + name; +if (!access(profile, 'r')) return { error: 'not found' }; + +let c = cursor(); +c.load('clashoo'); +c.set('clashoo', 'config', 'singbox_active', name); +c.commit('clashoo'); + +if (is_running() && (running_core_family() == 'singbox' || get_core_type() == 'singbox')) +system('service ' + get_service_name() + ' restart >/dev/null 2>&1'); + +return { success: true, family: 'singbox', current: name }; +} + +let found_path = ''; +let found_type = ''; +for (let dir in CONFIG_DIRS) { +let candidate = dir.path + '/' + name; +if (access(candidate, 'r')) { found_path = candidate; found_type = dir.type; break; } +} +if (!found_path) return { error: 'not found' }; +let c = cursor(); c.load('clashoo'); +c.set('clashoo', 'config', 'use_config', found_path); +c.set('clashoo', 'config', 'config_type', found_type); +c.commit('clashoo'); +if (is_running()) system('service ' + get_service_name() + ' restart >/dev/null 2>&1'); +return { success: true, family: 'mihomo', current: name }; +} +}, + +get_cpu_arch: { +call: function() { +return { arch: get_cpu_arch() }; +} +}, + +download_core: { +call: function(req) { +if (access('/var/run/core_update', 'r')) +return { success: true, started: false, running: true }; +let dc = req.args?.dcore || ''; +let arch = req.args?.arch || ''; +if (dc && dc != '0' && match(dc, /^[1-5]$/)) { + let c = cursor(); c.load('clashoo'); + c.set('clashoo', 'config', 'dcore', dc); + if (arch) c.set('clashoo', 'config', 'download_core', arch); + c.commit('clashoo'); + system('uci commit clashoo >/dev/null 2>&1'); +} +system("printf '%s - 内核下载任务已触发\\n' \"\$(date '+%Y-%m-%d %H:%M:%S')\" >>/tmp/clash_update.txt"); +system("nohup sh -c 'touch /var/run/core_update; sh /usr/share/clashoo/update/core_download.sh; rc=$?; rm -f /var/run/core_update; exit $rc' >/dev/null 2>&1 /dev/null 2>&1') == 0 }; +} +}, + +get_geoip_version: { +call: function() { +let f = '/etc/clashoo/Country.mmdb'; +let s = stat(f); +if (!s) return { version: '' }; +let p = popen('date -d @' + s.mtime + ' "+%Y-%m-%d %H:%M:%S" 2>/dev/null || date -r ' + shell_quote(f) + ' "+%Y-%m-%d %H:%M:%S" 2>/dev/null'); +let ts = ''; +if (p) { ts = trim(p.read('all')); p.close(); } +return { version: ts || ('' + s.mtime) }; +} +}, + +get_log_status: { +call: function() { +let core_updating = !!access('/var/run/core_update', 'r'); +let geoip_updating = !!access('/var/run/geoip_update', 'r'); +let p = popen("tail -8 /tmp/clash_update.txt 2>/dev/null"); +let core_log = ''; if (p) { core_log = trim(p.read('all')); p.close(); } +let p2 = popen("tail -5 /tmp/geoip_update.txt 2>/dev/null"); +let geoip_log = ''; if (p2) { geoip_log = trim(p2.read('all')); p2.close(); } +return { core_updating, geoip_updating, core_log, geoip_log }; +} +}, + +component_status: { +call: function() { +let running = !!access(COMPONENT_UPDATE_RUN_FILE, 'r'); +let state = read_component_state(); +let current = ''; +if (access(COMPONENT_UPDATE_RUN_FILE, 'r')) +current = trim(readfile(COMPONENT_UPDATE_RUN_FILE) || ''); +if (!current) current = state.component || ''; + +let comps = []; +for (let def in component_defs()) { +let status = 'idle'; +let message = ''; +if (running && current == def.id) { +status = 'running'; +message = state.message || component_last_log(); +} else if (!running && state.component == def.id && state.status) { +status = state.status; +message = state.message || ''; +} +push(comps, { +id: def.id, +name: def.name, +description: def.description, +kind: def.kind || '', +variant: !!def.variant, +installed_version: component_installed_label(def.id), +installed_versions: def.variant ? component_installed_versions(def.id) : {}, +status, +message +}); +} +return { +running, +current, +components: comps, + arch: { + system: trim(shell_read('uname -m 2>/dev/null') || ''), + // 老 arch 值归一化后再给前端 + download_core: uci_get('clashoo', 'config', 'download_core') + ? normalize_mihomo_arch(uci_get('clashoo', 'config', 'download_core')) + : '' + }, +last_log: component_last_log(), +log: component_log_tail(40) +}; +} +}, + +component_update: { +args: { component: 'component', variant: 'variant' }, +call: function(req) { +let component = req.args?.component || ''; +let variant = req.args?.variant || ''; +if (variant != 'stable' && variant != 'alpha') variant = ''; +if (!valid_component_id(component)) +return { success: false, error: 'invalid_component', message: '未知组件' }; +if (!access(COMPONENT_UPDATE_SCRIPT, 'x')) +return { success: false, error: 'missing_script', message: '组件更新脚本不存在' }; +if (access(COMPONENT_UPDATE_RUN_FILE, 'r')) +return { success: true, started: false, running: true, message: '已有组件更新任务运行中' }; + +if (writefile(COMPONENT_UPDATE_RUN_FILE, component + '\n') === null) +return { success: false, error: 'lock_failed', message: '无法创建组件更新锁' }; +system("printf '%s - 组件更新任务已提交: " + shell_quote(component) + "\\n' \"$(date '+%Y-%m-%d %H:%M:%S')\" >>" + shell_quote(COMPONENT_UPDATE_LOG_FILE)); +let cmd = 'cp ' + shell_quote(COMPONENT_UPDATE_SCRIPT) + ' ' + shell_quote(COMPONENT_UPDATE_RUNNER) + + ' && chmod +x ' + shell_quote(COMPONENT_UPDATE_RUNNER) + + ' && nohup sh ' + shell_quote(COMPONENT_UPDATE_RUNNER) + ' ' + shell_quote(component) + + (variant ? ' ' + shell_quote(variant) : '') + ' >/dev/null 2>&1 /dev/null"); +let content = ''; +if (p) { content = p.read('all'); p.close(); } +return { content }; +} +}, + +clear_update_log: { +call: function() { +return { success: writefile('/tmp/clash_update.txt', '') !== null }; +} +}, + +read_geoip_log: { +call: function() { +let p = popen("tail -300 /tmp/geoip_update.txt 2>/dev/null"); +let content = ''; +if (p) { content = p.read('all'); p.close(); } +return { content }; +} +}, + +clear_geoip_log: { +call: function() { +return { success: writefile('/tmp/geoip_update.txt', '') !== null }; +} +}, + +read_core_log: { +call: function() { +if (access(CORE_LOG_PATH, 'r')) { + let p0 = popen("tail -400 '" + CORE_LOG_PATH + "' 2>/dev/null"); + let c0 = ''; + if (p0) { c0 = p0.read('all'); p0.close(); } + return { content: format_core_log(c0) }; +} +let family = running_core_family() || get_core_type(); +let tag = (family === 'singbox') ? 'sing-box' : 'mihomo'; +let p = popen("logread -e '" + tag + "' 2>/dev/null | tail -400"); +let content = ''; +if (p) { content = p.read('all'); p.close(); } +if (!content) { +let p2 = popen("logread 2>/dev/null | grep -E '(sing-box|mihomo|clashoo)' | tail -400"); +if (p2) { content = p2.read('all'); p2.close(); } +} +return { content: format_core_log(content) }; +} +}, + +clear_core_log: { +call: function() { +let dir = '/var/log/clashoo'; +system('mkdir -p ' + shell_quote(dir) + ' >/dev/null 2>&1'); +return { success: writefile(CORE_LOG_PATH, '') !== null }; +} +}, + +read_update_merged_log: { +call: function() { +let p1 = popen("tail -200 /tmp/clash_update.txt 2>/dev/null"); +let c1 = ''; if (p1) { c1 = trim(p1.read('all')); p1.close(); } +let p2 = popen("tail -200 /tmp/geoip_update.txt 2>/dev/null"); +let c2 = ''; if (p2) { c2 = trim(p2.read('all')); p2.close(); } +let parts = []; +if (c1) push(parts, '=== 内核/面板/订阅更新 ===\n' + format_update_log(c1)); +if (c2) push(parts, '=== GeoIP 更新 ===\n' + format_update_log(c2)); +return { content: join('\n\n', parts) }; +} +}, + +clear_update_merged_log: { +call: function() { +writefile('/tmp/clash_update.txt', ''); +writefile('/tmp/geoip_update.txt', ''); +return { success: true }; +} +}, + +access_check: { +call: function() { +return get_access_payload(); +} +}, + +access_check_refresh: { +call: function() { +ensure_access_check_daemon(); +let updating = access_check_is_updating(now_epoch_sec()); +if (!updating) +trigger_access_cache_refresh(); +return { success: true, started: !updating }; +} +}, + +overview_stats: { +call: function() { +try { + let running = is_running(); + if (!running) + return { ok: false, running: false }; + + /* Fast path: /connections already contains totals + memory on current kernels */ + let conns0 = clash_api_json('/connections', 2); + if (api_unauthorized_payload(conns0)) conns0 = null; + + let conns = conns0 || {}; + let up_total = int(conns.uploadTotal || conns.upload_total || 0); + let down_total = int(conns.downloadTotal || conns.download_total || 0); + let up = int(conns.up || conns.upload || conns.upSpeed || conns.uploadSpeed || 0); + let down = int(conns.down || conns.download || conns.downSpeed || conns.downloadSpeed || 0); + let mem_inuse = int(conns.memory || conns.memory_inuse || conns.inuse || 0); + + let conn_count = 0; + if (conns && conns.connections) { + let n = int(conns.connections || 0); + if (n > 0) + conn_count = n; + else + for (let _ in conns.connections) + conn_count++; + } + if (conn_count <= 0) + conn_count = int(conns.connection || conns.connections_count || 0); + + /* Fallback: derive instantaneous rates from total deltas */ + if ((up <= 0 && down <= 0) && (up_total > 0 || down_total > 0)) { + let now = now_epoch_sec(); + let prev = read_overview_stats_cache(); + let prev_ts = int(prev.ts || 0); + let dt = now - prev_ts; + if (dt > 0 && dt < 120) { + let prev_up_total = int(prev.up_total || 0); + let prev_down_total = int(prev.down_total || 0); + if (up_total >= prev_up_total) + up = int((up_total - prev_up_total) / dt); + if (down_total >= prev_down_total) + down = int((down_total - prev_down_total) / dt); + } + write_overview_stats_cache({ + ts: now, + up_total: up_total, + down_total: down_total + }); + } + + let ok = !!(conns0 || up_total > 0 || down_total > 0 || conn_count > 0 || mem_inuse > 0); + return { + ok, + running: true, + up, + down, + up_total, + down_total, + connections: conn_count, + memory_inuse: mem_inuse + }; +} catch (e) { + return { + ok: false, + running: is_running(), + error: 'overview_stats_failed', + message: '' + e + }; +} +} +}, + +/* Aggregate poll endpoint: returns status + realtime stats in ONE rpcd invocation. + Critical: rpcd cold-starts ucode per call (~4s for this 2500-line script), + so combining avoids a 3x penalty when the page polls. */ +overview: { +call: function() { +try { + let c = cursor(); + c.load('clashoo'); + let configured_core = get_core_type(); + let running = is_running(); + let proxy_mode = c.get('clashoo', 'config', 'p_mode') || 'rule'; + let conf_path = c.get('clashoo', 'config', 'use_config') || ''; +let panel_type = c.get('clashoo', 'config', 'dashboard_panel')|| 'zashboard'; +let tcp_mode = c.get('clashoo', 'config', 'tcp_mode') || 'tun'; +let udp_mode = c.get('clashoo', 'config', 'udp_mode') || tcp_mode; +let stack = c.get('clashoo', 'config', 'stack') || 'system'; +let api = get_clash_api_auth(); + let dash_port = api.port || (c.get('clashoo', 'config', 'dash_port') || '9090'); + let dash_pass = api.pass || ''; + let effective_tcp_mode = runtime_state_get('effective_tcp_mode') || tcp_mode; + let effective_udp_mode = runtime_state_get('effective_udp_mode') || udp_mode; + let runtime_degraded = runtime_state_get('degraded') == '1'; + let runtime_degrade_reason = runtime_state_get('degrade_reason') || ''; + let health_status = runtime_state_get('health_status') || (running ? 'unknown' : 'stopped'); + let health_detail = runtime_state_get('health_detail') || ''; + if (!running) { + health_status = 'stopped'; + if (health_detail != 'boot_disabled' && health_detail != 'service_disabled') + health_detail = 'service_stopped'; + } + let has_tun_device = runtime_state_get('has_tun_device'); + let local_ip = get_local_ip(); + let config = get_display_config_name(configured_core); + let slash = rindex(conf_path, '/'); + let conf_name = slash >= 0 ? substr(conf_path, slash + 1) : conf_path; + if (configured_core == 'singbox' && config) conf_name = config; + let dcore = c.get('clashoo', 'config', 'dcore') || '2'; + + let status_payload = { running, dash_port, dash_pass, proxy_mode, conf_path: conf_name, config, + panel_type, tcp_mode, udp_mode, stack, + effective_tcp_mode, effective_udp_mode, + runtime_degraded, runtime_degrade_reason, + health_status, health_detail, has_tun_device, + core_type: configured_core, dcore, local_ip, + has_mihomo_stable: has_mihomo_stable(), + has_mihomo_alpha: !!access('/usr/bin/mihomo', 'x'), + has_singbox_stable: !!access(SINGBOX_BINARY_PATHS[0], 'x'), + has_singbox_alpha: !!access(SINGBOX_BINARY_PATHS[1], 'x'), + has_smart: !!find_smart_binary() }; + + let stats_payload = { ok: false, running: running }; + if (running) { + let conns0 = clash_api_json('/connections', 1); + if (api_unauthorized_payload(conns0)) conns0 = null; + let conns = conns0 || {}; + let up_total = int(conns.uploadTotal || conns.upload_total || 0); + let down_total = int(conns.downloadTotal || conns.download_total || 0); + let up = int(conns.up || conns.upload || conns.upSpeed || conns.uploadSpeed || 0); + let down = int(conns.down || conns.download || conns.downSpeed || conns.downloadSpeed || 0); + let mem_inuse = int(conns.memory || conns.memory_inuse || conns.inuse || 0); + let conn_count = 0; + if (conns && conns.connections) { + let n = int(conns.connections || 0); + if (n > 0) conn_count = n; + else for (let _ in conns.connections) conn_count++; + } + if (conn_count <= 0) conn_count = int(conns.connection || conns.connections_count || 0); + if ((up <= 0 && down <= 0) && (up_total > 0 || down_total > 0)) { + let now = now_epoch_sec(); + let prev = read_overview_stats_cache(); + let prev_ts = int(prev.ts || 0); + let dt = now - prev_ts; + if (dt > 0 && dt < 120) { + let prev_up_total = int(prev.up_total || 0); + let prev_down_total = int(prev.down_total || 0); + if (up_total >= prev_up_total) up = int((up_total - prev_up_total) / dt); + if (down_total >= prev_down_total) down = int((down_total - prev_down_total) / dt); + } + write_overview_stats_cache({ ts: now, up_total: up_total, down_total: down_total }); + } + stats_payload = { + ok: !!(conns0 || up_total > 0 || down_total > 0 || conn_count > 0 || mem_inuse > 0), + running: true, + up, down, up_total, down_total, + connections: conn_count, + memory_inuse: mem_inuse + }; + } + + let configs_payload = build_configs_payload(); + let access_payload = get_access_payload(); + + return { + status: status_payload, + stats: stats_payload, + configs: configs_payload, + access: access_payload + }; +} catch (e) { + return { + status: { running: false }, + stats: { ok: false, running: false }, + configs: { configs: [], current: '', core_type: get_core_type() }, + access: default_access_payload('7890', 'redirect', 'redirect'), + error: 'overview_failed', + message: '' + e + }; +} +} +}, + +capabilities: { +call: function() { +return { +backend: detect_firewall_backend(), +missing_fw4_tools: detect_missing_fw4_tools(), +has_singbox: !!find_binary_for_family('singbox'), +has_mihomo: !!access('/usr/bin/mihomo', 'x'), +has_mihomo_stable: has_mihomo_stable(), +has_smart: !!find_smart_binary(), +has_clash_meta: !!access('/usr/bin/clash-meta', 'x'), +has_builtin_core: !!access('/etc/clashoo/clash', 'x') +}; +} +}, + +list_subscriptions: { +call: function() { +let active = uci_get('clashoo', 'config', 'use_config'); +let active_name = replace(active, /^.*\//, ''); +let rows = read_subscriptions(); +for (let row in rows) { +let fi = stat(SUB_DIR + '/' + row.name); +row.mtime = fi ? ('' + fi.mtime) : null; +row.size = fi ? (int(fi.size / 1024) + ' KB') : null; +row.has_file = !!fi; +row.active = (row.name == active_name); +} +return { subs: rows, active: active_name }; +} +}, + +list_templates: { +call: function() { +let files = []; +let seen = {}; +for (let dir in template_search_dirs()) { +for (let f in (glob(dir + '/*.yaml') || [])) { +let name = replace(f, dir + '/', ''); +if (index(name, '_merged_') == 0 || seen[name]) continue; +seen[name] = 1; +let fi = stat(f); +push(files, { name, mtime: fi ? ('' + fi.mtime) : null, size: fi ? (int(fi.size / 1024) + ' KB') : null }); +} +for (let f in (glob(dir + '/*.yml') || [])) { +let name = replace(f, dir + '/', ''); +if (index(name, '_merged_') == 0 || seen[name]) continue; +seen[name] = 1; +let fi = stat(f); +push(files, { name, mtime: fi ? ('' + fi.mtime) : null, size: fi ? (int(fi.size / 1024) + ' KB') : null }); +} +} +return { files }; +} +}, + +list_template_bindings: { +call: function() { +return { bindings: read_template_bindings() }; +} +}, + +set_template_binding: { +args: { sub_name: 'sub_name', template_name: 'template_name', enabled: 'enabled' }, +call: function(req) { +let sub_name = ensure_yaml_name(req.args?.sub_name || ''); +let template_name = ensure_yaml_name(req.args?.template_name || ''); +let enabled = (req.args?.enabled || '') == '0' ? '0' : '1'; + +if (!sub_name) +return { success: false, error: 'invalid_sub_name', message: '订阅名称无效' }; + +if (!template_name) { +let keep = []; +for (let row in read_template_bindings()) { +if (row.sub_name != sub_name) +push(keep, row); +} +if (!write_template_bindings(keep)) +return { success: false, error: 'write_failed', message: '保存绑定失败' }; +return { success: true, message: '已移除模板绑定' }; +} + +if (!access(SUB_DIR + '/' + sub_name, 'r')) +return { success: false, error: 'sub_not_found', message: '订阅文件不存在' }; +if (!find_template_path(template_name)) +return { success: false, error: 'template_not_found', message: '模板文件不存在' }; + +let rows = read_template_bindings(); +let updated = false; +for (let i = 0; i < length(rows); i++) { +if (rows[i].sub_name != sub_name) continue; +rows[i].template_name = template_name; +rows[i].enabled = enabled; +updated = true; +break; +} +if (!updated) +push(rows, { sub_name, template_name, enabled }); + +if (!write_template_bindings(rows)) +return { success: false, error: 'write_failed', message: '保存绑定失败' }; + +return { success: true, message: '模板绑定已保存' }; +} +}, + +apply_template_for_sub: { +args: { sub_name: 'sub_name', template_name: 'template_name', set_active: 'set_active' }, +call: function(req) { +let sub_name = ensure_yaml_name(req.args?.sub_name || ''); +let template_name = ensure_yaml_name(req.args?.template_name || ''); +let set_active = (req.args?.set_active || '') == '1'; + +if (!sub_name) +return { success: false, error: 'invalid_sub_name', message: '订阅名称无效' }; + +let sub_path = SUB_DIR + '/' + sub_name; +if (!access(sub_path, 'r')) +return { success: false, error: 'sub_not_found', message: '订阅文件不存在' }; + +if (!template_name) { +let b = find_template_binding(sub_name); +if (!b || b.enabled != '1') +return { success: false, error: 'binding_not_found', message: '未找到启用的模板绑定' }; +template_name = b.template_name; +} + +let template_path = find_template_path(template_name); +if (!template_path) +return { success: false, error: 'template_not_found', message: '模板文件不存在' }; + +let output_name = template_output_name(sub_name, template_name); +let out_path = TEMPLATE_DIR + '/' + output_name; +let cmd = 'sh /usr/share/clashoo/update/template_merge.sh ' + + shell_quote(sub_path) + ' ' + + shell_quote(template_path) + ' ' + + shell_quote(out_path); + +if (system(cmd + ' >/dev/null 2>&1') != 0) +return { success: false, error: 'merge_failed', message: '模板复写生成失败,请检查模板内容' }; + +if (set_active) { +let c = cursor(); +c.load('clashoo'); +c.set('clashoo', 'config', 'use_config', out_path); +c.set('clashoo', 'config', 'config_type', '3'); +c.commit('clashoo'); +if (is_running()) +system('service ' + get_service_name() + ' restart >/dev/null 2>&1'); +} + +return { +success: true, +output_name, +output_path: out_path, +template_name, +message: '模板复写生成成功: ' + output_name +}; +} +}, + +apply_enabled_template_bindings: { +args: { set_active: 'set_active' }, +call: function(req) { +let set_active = (req.args?.set_active || '') == '1'; +let rows = read_template_bindings(); +let done = []; +let failed = []; + +for (let row in rows) { +if (row.enabled != '1') continue; +let sub_path = SUB_DIR + '/' + row.sub_name; +let template_path = find_template_path(row.template_name); +if (!access(sub_path, 'r') || !template_path) { +push(failed, row.sub_name); +continue; +} + +let output_name = template_output_name(row.sub_name, row.template_name); +let out_path = TEMPLATE_DIR + '/' + output_name; +let cmd = 'sh /usr/share/clashoo/update/template_merge.sh ' + + shell_quote(sub_path) + ' ' + + shell_quote(template_path) + ' ' + + shell_quote(out_path) + + ' >/dev/null 2>&1'; + +if (system(cmd) == 0) { +push(done, row.sub_name); +if (set_active) { +let current = uci_get('clashoo', 'config', 'use_config'); +if (replace(current || '', /^.*\//, '') == row.sub_name) { +let c = cursor(); +c.load('clashoo'); +c.set('clashoo', 'config', 'use_config', out_path); +c.set('clashoo', 'config', 'config_type', '3'); +c.commit('clashoo'); +} +} +} +else { +push(failed, row.sub_name); +} +} + +if (set_active && is_running()) +system('service ' + get_service_name() + ' restart >/dev/null 2>&1'); + +return { +success: length(failed) == 0, +done, +failed, +message: '模板生成完成: 成功 ' + length(done) + ',失败 ' + length(failed) +}; +} +}, + +list_dir_files: { +args: { type: 'type' }, +call: function(req) { +let type_map = { '1': '/usr/share/clashoo/config/sub', '2': '/usr/share/clashoo/config/upload', '3': '/usr/share/clashoo/config/custom' }; +let dir = type_map[req.args?.type || '2']; +if (!dir) return { files: [] }; +let active = uci_get('clashoo', 'config', 'use_config'); +let active_name = replace(active, /^.*\//, ''); +let files = []; +for (let f in (glob(dir + '/*.yaml') || [])) { +let name = replace(f, dir + '/', ''); +let fi = stat(f); +push(files, { +name, +mtime: fi ? ('' + fi.mtime) : null, +size: fi ? (int(fi.size / 1024) + ' KB') : null, +active: name == active_name +}); +} +for (let f in (glob(dir + '/*.yml') || [])) { +let name = replace(f, dir + '/', ''); +let fi = stat(f); +push(files, { +name, +mtime: fi ? ('' + fi.mtime) : null, +size: fi ? (int(fi.size / 1024) + ' KB') : null, +active: name == active_name +}); +} +return { files, active: active_name }; +} +}, + +delete_config: { +args: { name: 'name', type: 'type' }, +call: function(req) { +let name = safe_name(req.args?.name || ''); +let type = req.args?.type || '1'; +if (!name) return { error: 'missing name' }; +let type_map = { '1': SUB_DIR, '2': '/usr/share/clashoo/config/upload', '3': '/usr/share/clashoo/config/custom' }; +let dir = type_map[type] || SUB_DIR; +let target = dir + '/' + name; +let file_exists = !!access(target, 'r'); +let alt_name = name; +let alt_target = target; +let mirrored_template = null; + +if (type == '1' && match(name, /_new\.(yaml|yml)$/)) { +alt_name = replace(name, /_new\.(yaml|yml)$/, '.yaml'); +alt_target = dir + '/' + alt_name; +} + +if (type == '3' && file_exists) { +let user_template = TEMPLATE_USER_DIR + '/' + name; +if (access(user_template, 'r') && readfile(user_template) == readfile(target)) +mirrored_template = user_template; +} + +if (file_exists) { +if (unlink(target) === null) return { success: false, error: 'delete failed' }; +if (type == '1') { +unlink(target + '.info'); +unlink(target + '.url'); +unlink(target + '.ua'); +} +} +else if (type != '1') { +return { error: 'not found' }; +} + +if (mirrored_template) +unlink(mirrored_template); + +if (type == '1' && alt_target != target && access(alt_target, 'r')) { +unlink(alt_target); +unlink(alt_target + '.info'); +unlink(alt_target + '.url'); +unlink(alt_target + '.ua'); +} + +let c = cursor(); +c.load('clashoo'); +let active = c.get('clashoo', 'config', 'use_config') || ''; +if (active == target || (type == '1' && active == alt_target)) { +let fallback = first_available_config(target); +if (fallback) { +c.set('clashoo', 'config', 'use_config', fallback.path); +c.set('clashoo', 'config', 'config_type', fallback.type); +} +else { +c.delete('clashoo', 'config', 'use_config'); +c.delete('clashoo', 'config', 'config_type'); +} +c.commit('clashoo'); +if (is_running()) system('service ' + get_service_name() + ' restart >/dev/null 2>&1'); +} + +if (type == '1' && access(LIST_FILE, 'r')) { +let content = readfile(LIST_FILE) || ''; +let lines = []; +for (let l in split(content, '\n')) { +if (index(l, name + '#') == 0) +continue; +if (alt_name != name && index(l, alt_name + '#') == 0) +continue; +push(lines, l); +} +writefile(LIST_FILE, join('\n', lines)); +} +return { success: true }; +} +}, + +update_china_ip: { +call: function() { +/* Surface CN whitelist update progress in update log panel. */ + return { success: system('sh /usr/share/clashoo/rpc/rpc_async.sh update_china_ip >/dev/null 2>&1') == 0 }; +} +}, + +download_subs: { +call: function() { +// 已有下载任务在跑则不重复触发 +let pb = popen('ps w 2>/dev/null | grep "[c]lashoo/runtime/clashoo.sh" | head -1'); +let busy = ''; if (pb) { busy = trim(pb.read('all')); pb.close(); } +if (busy != '') return { success: true, started: false, running: true }; +// 清空进度日志后后台执行,前端轮询 download_subs_status 取实时进度 +system("printf '' >/tmp/clash_update.txt 2>/dev/null"); +system('sh /usr/share/clashoo/runtime/clashoo.sh >/dev/null 2>&1 &'); +return { success: true, started: true }; +} +}, + +download_subs_status: { +call: function() { +let p = popen('ps w 2>/dev/null | grep "[c]lashoo/runtime/clashoo.sh" | head -1'); +let line = ''; if (p) { line = trim(p.read('all')); p.close(); } +let running = (line && line != ''); +let last_line = ''; +let p2 = popen('tail -1 /tmp/clash_update.txt 2>/dev/null'); +if (p2) { last_line = trim(p2.read('all')); p2.close(); } +// 收尾行「订阅下载失败:全部链接失败」太笼统,额外捞最近一条带真因的 +// 失败行(下载失败 rc=/HTTP、校验失败 格式不符),让前端能显示具体原因 +let fail_detail = ''; +let p3 = popen("grep -aE '下载失败:.*(rc=|HTTP )|校验失败:' /tmp/clash_update.txt 2>/dev/null | tail -1"); +if (p3) { fail_detail = trim(p3.read('all')); p3.close(); } +return { running, last_line, fail_detail }; +} +}, + +/* ── 简易代理面板:代理 clash API(前端不直接碰 9090 / secret)── */ +proxies_list: { +call: function() { +let data = clash_api_json('/proxies', 6); +if (!data || !data.proxies) + return { ok: false, reason: 'unreachable' }; +let proxies = data.proxies; +let switchable = { 'Selector': 1 }; +let readonly = { 'URLTest': 1, 'Fallback': 1, 'LoadBalance': 1, 'Relay': 1 }; +let groups = []; +let order = []; +let global = proxies['GLOBAL']; +if (global && global.all && length(global.all)) { + for (let i = 0; i < length(global.all); i++) { + if (global.all[i] != 'GLOBAL') push(order, global.all[i]); + } +} else { + for (let gname in proxies) { + if (gname != 'GLOBAL') push(order, gname); + } +} +for (let i = 0; i < length(order); i++) { + let gname = order[i]; + let g = proxies[gname]; + if (!g || type(g) != 'object') continue; + let gt = g.type || ''; + if (!switchable[gt] && !readonly[gt]) continue; + if (gname == 'GLOBAL') continue; + let members = []; + for (let mn in (g.all || [])) { + let mp = proxies[mn]; + let delay = 0; + if (mp && mp.history && length(mp.history) > 0) + delay = mp.history[length(mp.history) - 1].delay || 0; + push(members, { name: mn, delay: delay }); + } + push(groups, { + name: gname, + type: gt, + now: g.now || '', + selectable: !!switchable[gt], + members: members + }); +} +return { ok: true, groups: groups }; +} +}, + +/* ── 探测主代理组:供自定义分流规则的「代理」(__PROXY__) 解析用 ── + * 取一个可切换的 Selector 组(优先名字像主代理组的,排除 GLOBAL),写入 + * clashoo.config.primary_proxy_group,iprules.sh 注入 mihomo 规则时引用。 */ +detect_primary_group: { +call: function() { +let data = clash_api_json('/proxies', 6); +if (!data || !data.proxies) + return { ok: false, reason: 'unreachable' }; +let proxies = data.proxies; +let first = ''; +let preferred = ''; +for (let gname in proxies) { + let g = proxies[gname]; + if (!g || type(g) != 'object') continue; + if ((g.type || '') != 'Selector') continue; + if (gname == 'GLOBAL') continue; + if (first == '') first = gname; + if (preferred == '' && match(gname, /节点选择|代理|Proxy|PROXY|🚀/)) + preferred = gname; +} +let grp = preferred != '' ? preferred : first; +if (grp == '') + return { ok: false, reason: 'no_selector' }; +let c = cursor(); +c.set('clashoo', 'config', 'primary_proxy_group', grp); +c.commit('clashoo'); +return { ok: true, group: grp }; +} +}, + +proxy_select: { +args: { group: 'group', name: 'name' }, +call: function(req) { +let group = trim(req.args?.group || ''); +let name = trim(req.args?.name || ''); +if (!group || !name) return { ok: false, message: '参数缺失' }; +let code = clash_api_put_json('/proxies/' + uri_encode(group), { name: name }); +if (code == '204' || code == '200') return { ok: true }; +if (code == '400') return { ok: false, code: code, message: '该节点不可选(组类型不支持或节点无效)' }; +return { ok: false, code: code, message: '切换失败 (HTTP ' + code + ')' }; +} +}, + +proxy_delay: { +args: { group: 'group' }, +call: function(req) { +let group = trim(req.args?.group || ''); +if (!group) return { ok: false, message: '参数缺失' }; +let path = '/group/' + uri_encode(group) + '/delay' + + '?url=' + uri_encode('https://www.gstatic.com/generate_204') + + '&timeout=3000'; +let data = clash_api_json(path, 14); +if (!data || type(data) != 'object') + return { ok: false, message: '测速失败或超时' }; +if (data.message) + return { ok: false, message: '' + data.message }; +return { ok: true, delays: data }; +} +}, + +update_sub: { +args: { name: 'name' }, +call: function(req) { +let name = req.args?.name || ''; +if (!name) return { error: 'missing name' }; +let rc = system('sh ' + shell_quote(SUBSCRIPTION_UPDATE_SCRIPT) + ' --mihomo ' + shell_quote(name) + ' >/dev/null 2>&1'); +if (rc != 0) { +return { success: false, code: rc, message: '更新失败: ' + name }; +} +return { success: true, code: rc, message: '更新完成: ' + name }; +} +}, + +update_current_subscription: { +call: function() { +let c = cursor(); c.load('clashoo'); +if (get_core_type() == 'singbox') { + let name = c.get('clashoo', 'config', 'singbox_active') || ''; + let path = SINGBOX_DIR + '/' + name; + if (!name || !access(path + '.url', 'r') || !trim(readfile(path + '.url') || '')) + return { success: false, reason: 'not_subscription', message: '当前配置未记录订阅链接' }; + let rc = system('sh ' + shell_quote(SUBSCRIPTION_UPDATE_SCRIPT) + ' --singbox ' + shell_quote(name) + ' >/dev/null 2>&1'); + return { success: rc == 0, code: rc, message: rc == 0 ? '当前订阅更新完成' : '当前订阅更新失败' }; +} + +let path = c.get('clashoo', 'config', 'use_config') || ''; +let slash = rindex(path, '/'); +let name = slash >= 0 ? substr(path, slash + 1) : path; +let found = false; +for (let sub in read_subscriptions()) { + if (sub.name == name && sub.url) { + found = true; + break; + } +} +if (!found) + return { success: false, reason: 'not_subscription', message: '当前配置未记录订阅链接' }; +let rc = system('sh ' + shell_quote(SUBSCRIPTION_UPDATE_SCRIPT) + ' --mihomo ' + shell_quote(name) + ' >/dev/null 2>&1'); +return { success: rc == 0, code: rc, message: rc == 0 ? '当前订阅更新完成' : '当前订阅更新失败' }; +} +}, + +subscription_update_all: { +call: function() { +if (access(SUBSCRIPTION_UPDATE_LOCK_DIR, 'r')) + return { success: false, running: true, message: '订阅更新正在运行' }; +let rc = system('sh ' + shell_quote(SUBSCRIPTION_UPDATE_SCRIPT) + ' --all >/dev/null 2>&1 &'); +return { success: rc == 0, running: rc == 0, message: rc == 0 ? '已开始更新全部订阅' : '启动失败' }; +} +}, + +subscription_update_status: { +call: function() { +return subscription_update_status_data(); +} +}, + +set_subscription_update_schedule: { +args: { enabled: 'enabled', interval: 'interval' }, +call: function(req) { +let enabled = req.args?.enabled == '1' ? '1' : '0'; +let interval_raw = '' + (req.args?.interval || ''); +if (!match(interval_raw, /^[0-9]+$/)) + return { success: false, message: '更新间隔必须为数字' }; +let interval = int(interval_raw); +if (interval < 1 || interval > 8760) + return { success: false, message: '更新间隔必须为 1 到 8760 小时' }; +let c = cursor(); c.load('clashoo'); +c.set('clashoo', 'config', 'auto_subscription_update', enabled); +c.set('clashoo', 'config', 'subscription_update_interval', '' + interval); +c.commit('clashoo'); +system('/etc/init.d/clashoo refresh_cron >/dev/null 2>&1'); +return { success: true, enabled: enabled, interval: interval }; +} +}, + +apply_template_with_url: { +args: { +template_source: 'template_source', +sub_url: 'sub_url', +output_name: 'output_name', +set_active: 'set_active' +}, +call: function(req) { +let tpl_src = trim(req.args?.template_source || ''); +let sub_url = trim(req.args?.sub_url || ''); +let output_name = ensure_yaml_name(req.args?.output_name || ''); +if (!output_name) output_name = 'tpl-rewrite.yaml'; +let uniq_name = replace(output_name, /\.(yaml|yml)$/, ''); +let set_active = (req.args?.set_active || '') == '1'; + +if (!tpl_src) +return { success: false, error: 'invalid_template', message: '模板来源不能为空' }; +if (!sub_url || !match(sub_url, /^https?:\/\//)) +return { success: false, error: 'invalid_sub_url', message: '订阅 URL 无效' }; + +let tmp_tpl = '/tmp/clashoo_tpl_in.yaml'; +let tmp_out = '/tmp/clashoo_tpl_out.yaml'; +let out_dir = '/usr/share/clashoo/config/custom'; +system('mkdir -p ' + shell_quote(out_dir)); + +/* 获取模板:远程 URL 或本地文件 */ +if (match(tpl_src, /^https?:\/\//)) { +let dl_cmd = '(curl -fL --connect-timeout 15 --max-time 60 ' + shell_quote(tpl_src) ++ ' -o ' + shell_quote(tmp_tpl) ++ ' || wget -O ' + shell_quote(tmp_tpl) + ' ' + shell_quote(tpl_src) ++ ') >/dev/null 2>&1'; +if (system(dl_cmd) != 0 || !access(tmp_tpl, 'r')) +return { success: false, error: 'download_failed', message: '远程模板下载失败' }; +} else { +let safe = safe_name(tpl_src); +let local_path = null; +let search_dirs = template_search_dirs(); +for (let i = 0; i < length(search_dirs); i++) { +if (access(search_dirs[i] + '/' + safe, 'r')) { local_path = search_dirs[i] + '/' + safe; break; } +} +if (!local_path) +return { success: false, error: 'template_not_found', message: '本地模板文件不存在' }; +if (system('cp -f ' + shell_quote(local_path) + ' ' + shell_quote(tmp_tpl)) != 0) +return { success: false, error: 'copy_failed', message: '读取本地模板失败' }; +} + +/* 用 yq 把所有 proxy-providers 条目的 url 替换为订阅链接 */ +if (system('command -v yq >/dev/null 2>&1') != 0) +return { success: false, error: 'missing_yq', message: '缺少 yq,无法注入订阅 URL' }; + + /* 先展开 YAML anchor(<<: *xxx),再注入订阅 URL */ + let exploded = tmp_tpl + ".exploded"; + system("yq ea \"explode(.)\" " + shell_quote(tmp_tpl) + " > " + shell_quote(exploded) + " 2>/dev/null"); + if (!access(exploded, "r")) { + system("cp -f " + shell_quote(tmp_tpl) + " " + shell_quote(exploded)); + } + /* 替换 proxy-providers.url 并把 provider 名改成唯一名(同步 proxy-groups 的 use)*/ + let inject_cmd = "URL=" + shell_quote(sub_url) + " NAME=" + shell_quote(uniq_name) + + " yq e '.[\"proxy-providers\"][].url = env(URL) | (.[\"proxy-providers\"] | keys | map({\"key\": ., \"value\": strenv(NAME) + \"-\" + .}) | from_entries) as $rename | .[\"proxy-providers\"] |= with_entries(.key = $rename[.key]) | (.[\"proxy-groups\"][] | select(has(\"use\")) | .use) |= map($rename[.] // .)' " + + shell_quote(exploded) + " > " + shell_quote(tmp_out); + if (system(inject_cmd) != 0 || !access(tmp_out, "r")) { + system("rm -f " + shell_quote(exploded)); + return { success: false, error: "inject_failed", message: "订阅 URL 注入失败" }; + } + system("rm -f " + shell_quote(exploded)); + +let out_path = out_dir + '/' + output_name; +if (system('mv -f ' + shell_quote(tmp_out) + ' ' + shell_quote(out_path)) != 0) +return { success: false, error: 'write_failed', message: '写入结果文件失败' }; + +/* 删除 respect-rules(模板可能设了但没提供 proxy-server-nameserver) */ +system("sed -i '/respect-rules/d' " + shell_quote(out_path) + " 2>/dev/null"); +system('rm -f ' + shell_quote(tmp_tpl)); + /* 只把独立引用项"直连"转成 DIRECT,组名里的"直连"不动 */ + system("sed -i 's/^\\( *- *\\)直连$/\\1DIRECT/' " + shell_quote(out_path) + " 2>/dev/null"); + system("yq e '(.proxy-groups[] | select(has(\"proxies\")) | .proxies) |= map(sub(\"^直连$\", \"DIRECT\"))' " + shell_quote(out_path) + " -i 2>/dev/null"); + /* 用 mixin.uc + yq merge 叠加 UCI 覆盖(端口、routing-mark、dns 等) */ + let mixin_script = "/usr/share/clashoo/runtime/mixin.uc"; + if (access(mixin_script, "r") && system("command -v yq >/dev/null 2>&1") == 0) { + let mixin_yaml = "/tmp/_clashoo_mixin.yaml"; + let merged_out = out_path + ".merged"; + system("ucode " + shell_quote(mixin_script) + " 2>/dev/null | yq -M -p json -o yaml > " + shell_quote(mixin_yaml) + " 2>/dev/null"); + system("yq -M eval-all '(. as $item ireduce ({}; . * $item)) as $m | [\"port\",\"socks-port\",\"redir-port\",\"tproxy-port\",\"mixed-port\",\"allow-lan\",\"bind-address\",\"mode\",\"log-level\",\"ipv6\",\"interface-name\",\"routing-mark\",\"external-controller\",\"external-ui\",\"secret\",\"tun\",\"listeners\",\"tunnels\",\"dns\",\"hosts\",\"profile\",\"geodata-mode\",\"geodata-loader\",\"geox-url\",\"proxy-providers\",\"proxies\",\"proxy-groups\",\"rule-providers\",\"rules\",\"sub-rules\",\"ntp\",\"authentication\",\"sniffer\",\"experimental\"] as $order | ($order | to_entries | map({\"key\": .value, \"value\": .key}) | from_entries) as $rank | $m | to_entries | sort_by(.key as $k | $rank[$k] // 999) | from_entries' " + shell_quote(out_path) + " " + shell_quote(mixin_yaml) + " > " + shell_quote(merged_out) + " 2>/dev/null"); + if (access(merged_out, "r")) { + system("mv -f " + shell_quote(merged_out) + " " + shell_quote(out_path)); + } + system("rm -f " + shell_quote(mixin_yaml)); + } + + + /* ── mihomo -t 预校验(搜所有 mihomo 变体)── */ + let _core_bin = ''; + for (let _cm in ['mihomo', 'clash-meta', 'clash']) { + if (system('command -v ' + _cm + ' >/dev/null 2>&1') == 0) { + _core_bin = _cm; + break; + } + } + if (_core_bin) { + let _ret = system(_core_bin + " -t -d /etc/clashoo -f " + shell_quote(out_path) + " 2>/tmp/clashoo_tpl_verify.txt"); + if (_ret != 0) { + let _err = trim(readfile('/tmp/clashoo_tpl_verify.txt') || '配置校验失败'); + system('rm -f ' + shell_quote(out_path) + ' /tmp/clashoo_tpl_verify.txt 2>/dev/null'); + return { success: false, error: 'validation_failed', message: '模板校验失败: ' + _err }; + } + system('rm -f /tmp/clashoo_tpl_verify.txt 2>/dev/null'); + } + +if (set_active) { +let c = cursor(); +c.load('clashoo'); +c.set('clashoo', 'config', 'use_config', out_path); +c.set('clashoo', 'config', 'config_type', '3'); +c.commit('clashoo'); +if (is_running()) +system('service ' + get_service_name() + ' restart >/dev/null 2>&1'); +} + +return { success: true, output_name, output_path: out_path, message: '模板已应用: ' + output_name }; +} +}, + +apply_rewrite: { +args: { +base_type: 'base_type', +base_name: 'base_name', +rewrite_type: 'rewrite_type', +rewrite_name: 'rewrite_name', +output_name: 'output_name', +set_active: 'set_active' +}, +call: function(req) { +let base_type = req.args?.base_type || ''; +let base_name = safe_name(req.args?.base_name || ''); +let rewrite_type = req.args?.rewrite_type || ''; +let rewrite_name = safe_name(req.args?.rewrite_name || ''); +let output_name = ensure_yaml_name(req.args?.output_name || ''); +let set_active = (req.args?.set_active || '') == '1'; + +let base_dir = config_dir_by_type(base_type); +let rewrite_dir = config_dir_by_type(rewrite_type); + +if (!base_dir || !base_name) +return { success: false, error: 'invalid_base', message: '主配置无效' }; +if (!rewrite_dir || !rewrite_name) +return { success: false, error: 'invalid_rewrite', message: '复写配置无效' }; + +let base_path = base_dir + '/' + base_name; +let rewrite_path = rewrite_dir + '/' + rewrite_name; + +if (!access(base_path, 'r')) +return { success: false, error: 'base_not_found', message: '主配置文件不存在' }; +if (!access(rewrite_path, 'r')) +return { success: false, error: 'rewrite_not_found', message: '复写配置文件不存在' }; + +if (!output_name) { +let stem = replace(base_name, /\.(yaml|yml)$/, ''); +output_name = stem + '_rewrite.yaml'; +} + +let out_dir = '/usr/share/clashoo/config/custom'; +let out_path = out_dir + '/' + output_name; +let tmp_path = '/tmp/clash_rewrite_merged.yaml'; + +system('mkdir -p ' + shell_quote(out_dir)); + +/* Template mode: when rewrite file comes from custom dir, always prefer template merge workflow. */ +if (rewrite_type == '3' || rewrite_type == 'custom' || rewrite_dir == '/usr/share/clashoo/config/custom') { +let tcmd = 'sh /usr/share/clashoo/update/template_merge.sh ' + + shell_quote(base_path) + ' ' + + shell_quote(rewrite_path) + ' ' + + shell_quote(out_path) + + ' >/dev/null 2>&1'; +if (system(tcmd) != 0) +return { success: false, error: 'merge_failed', message: '模板复写失败,请检查模板内容与订阅格式' }; +} +else { +if (system('command -v yq >/dev/null 2>&1') != 0) +return { success: false, error: 'missing_yq', message: '缺少 yq,无法执行复写' }; + +let cmd = "yq eval-all '(select(fileIndex == 0) | explode(.)) * (select(fileIndex == 1) | explode(.))' " ++ shell_quote(base_path) + ' ' + shell_quote(rewrite_path) ++ ' > ' + shell_quote(tmp_path); + +if (system(cmd) != 0 || !access(tmp_path, 'r')) +return { success: false, error: 'merge_failed', message: '复写合并失败,请检查 YAML 格式' }; + +if (system('yq e \'.\' ' + shell_quote(tmp_path) + ' >/dev/null 2>&1') != 0) { +system('rm -f ' + shell_quote(tmp_path)); +return { success: false, error: 'invalid_yaml', message: '复写结果 YAML 无效,请检查锚点/别名配置' }; +} + +let binary = find_binary(); +if (binary && system(shell_quote(binary) + ' -t -f ' + shell_quote(tmp_path) + ' >/dev/null 2>&1') != 0) { +system('rm -f ' + shell_quote(tmp_path)); +return { success: false, error: 'invalid_runtime_yaml', message: '复写结果与内核不兼容,请检查复写内容' }; +} + +if (system('mv -f ' + shell_quote(tmp_path) + ' ' + shell_quote(out_path)) != 0) +return { success: false, error: 'write_failed', message: '写入复写文件失败' }; +} + +if (set_active) { +let c = cursor(); +c.load('clashoo'); +c.set('clashoo', 'config', 'use_config', out_path); +c.set('clashoo', 'config', 'config_type', '3'); +c.commit('clashoo'); +if (is_running()) +system('service ' + get_service_name() + ' restart >/dev/null 2>&1'); +} + +return { +success: true, +output_name, +output_path: out_path, +message: '复写成功: ' + output_name +}; +} +}, + +fetch_rewrite_url: { +args: { url: 'url', name: 'name' }, +call: function(req) { +let url = trim(req.args?.url || ''); +let name = ensure_yaml_name(req.args?.name || ''); + +if (!url || !match(url, /^https?:\/\//)) +return { success: false, error: 'invalid_url', message: '无效的 URL' }; + +if (!name) +name = file_name_from_url(url); +if (!name) +name = 'rewrite-remote.yaml'; + +let out_dir = '/usr/share/clashoo/config/custom'; +let out_path = out_dir + '/' + name; +let tmp_path = '/tmp/rewrite_remote.yaml'; + +system('mkdir -p ' + shell_quote(out_dir)); + +let dl_cmd = '(curl -fL --connect-timeout 15 --max-time 90 ' + shell_quote(url) + ' -o ' + shell_quote(tmp_path) + + ' || wget -O ' + shell_quote(tmp_path) + ' ' + shell_quote(url) + ') >/dev/null 2>&1'; + +if (system(dl_cmd) != 0 || !access(tmp_path, 'r')) +return { success: false, error: 'download_failed', message: '远程复写文件下载失败' }; + +if (system('yq e \'.\' ' + shell_quote(tmp_path) + ' >/dev/null 2>&1') != 0) { +system('rm -f ' + shell_quote(tmp_path)); +return { success: false, error: 'invalid_yaml', message: '远程复写文件 YAML 格式无效' }; +} + +if (system('mv -f ' + shell_quote(tmp_path) + ' ' + shell_quote(out_path)) != 0) +return { success: false, error: 'write_failed', message: '保存远程复写文件失败' }; + +return { +success: true, +name, +path: out_path, +message: '远程复写文件已保存: ' + name +}; +} +}, + +read_other_config: { +args: { name: 'name', type: 'type' }, +call: function(req) { +let name = safe_name(req.args?.name || ''); +let type = req.args?.type || '2'; +if (!name) + return { error: 'invalid name' }; +let dir = config_dir_by_type(type); +if (!dir) return { error: 'invalid type' }; +let path = dir + '/' + name; +if (!access(path, 'r')) return { error: 'not found' }; +let s = stat(path); +if (s && s.size > 524288) return { error: 'too large' }; +return { content: readfile(path) || '', name }; +} +}, + +upload_config: { +args: { name: 'name', content: 'content', type: 'type' }, +call: function(req) { +let name = safe_name(ensure_yaml_name(req.args?.name || '')); +let content = req.args?.content || ''; +let type = req.args?.type || '2'; +if (!name) return { success: false, error: 'invalid_name', message: '文件名无效' }; +if (!content) return { success: false, error: 'empty_content', message: '文件内容为空' }; +let dir = config_dir_by_type(type); +if (!dir) dir = '/usr/share/clashoo/config/upload'; +system('mkdir -p ' + shell_quote(dir)); +let path = dir + '/' + name; +if (writefile(path, content) === null) +return { success: false, error: 'write_failed', message: '写入文件失败' }; +return { success: true, name, path }; +} +}, + +upload_config_chunk: { +args: { name: 'name', content: 'content', type: 'type', index: 'index', total: 'total' }, +call: function(req) { +let name = safe_name(ensure_yaml_name(req.args?.name || '')); +let content = req.args?.content; +let cfg_type = req.args?.type || '2'; +let index = int(req.args?.index || 0); +let total = int(req.args?.total || 0); +if (!name) return { success: false, error: 'invalid_name', message: '文件名无效' }; +if (type(content) != 'string') return { success: false, error: 'invalid_content', message: '文件内容无效' }; +if (total < 1 || index < 0 || index >= total) return { success: false, error: 'invalid_chunk', message: '上传分片无效' }; +if (total == 1 && !content) return { success: false, error: 'empty_content', message: '文件内容为空' }; +let dir = config_dir_by_type(cfg_type); +if (!dir) dir = '/usr/share/clashoo/config/upload'; +system('mkdir -p ' + shell_quote(dir)); +let path = dir + '/' + name; + +if (index == 0) { + if (writefile(path, content) === null) + return { success: false, error: 'write_failed', message: '写入文件失败' }; +} else { + let fp = open(path, 'a'); + if (!fp) return { success: false, error: 'write_failed', message: '打开文件失败' }; + let ok = fp.write(content); + fp.close(); + if (ok === null) return { success: false, error: 'write_failed', message: '写入文件失败' }; +} + +return { success: true, name, path, index, total, complete: index + 1 >= total }; +} +}, + +upload_template: { +args: { name: 'name', content: 'content' }, +call: function(req) { +let name = safe_name(ensure_yaml_name(req.args?.name || '')); +let content = req.args?.content || ''; +if (!name) +return { success: false, error: 'invalid_name', message: '模板文件名无效' }; +if (!content) +return { success: false, error: 'empty_content', message: '模板内容为空' }; + +system('mkdir -p ' + shell_quote(TEMPLATE_USER_DIR) + ' ' + shell_quote(TEMPLATE_DIR)); +let user_path = TEMPLATE_USER_DIR + '/' + name; +if (writefile(user_path, content) === null) +return { success: false, error: 'write_failed', message: '写入模板失败' }; + +let custom_path = TEMPLATE_DIR + '/' + name; +if (writefile(custom_path, content) === null) +return { success: false, error: 'mirror_failed', message: '写入模板镜像失败' }; + +return { success: true, name, path: user_path, mirror: custom_path }; +} +}, + +smart_flush_cache: { +call: function() { +let code = mihomo_api_post('/cache/smart/flush'); +return { success: (code == '204' || code == '200'), code }; +} +}, + +/* ── sing-box profile management ── */ + +list_singbox_profiles: { +call: function() { +let dir = '/usr/share/clashoo/config/singbox'; +system('mkdir -p ' + shell_quote(dir) + ' >/dev/null 2>&1'); +let active = uci_get('clashoo', 'config', 'singbox_active') || ''; + +// 把 "211.98 GB" / "1000 MB" 之类解析成字节数;返回 0 表示无法识别 +let parse_size_bytes = function(num_str, unit_str) { + let n = +num_str; + if (n != n) return 0; // NaN + let u = uc(unit_str || ''); + let mul = 1; + if (u == 'KB' || u == 'K') mul = 1024; + else if (u == 'MB' || u == 'M') mul = 1024 * 1024; + else if (u == 'GB' || u == 'G') mul = 1024 * 1024 * 1024; + else if (u == 'TB' || u == 'T') mul = 1024 * 1024 * 1024 * 1024; + return int(n * mul); +}; + +// busybox date 把 yyyy-mm-dd 转 unix ts;失败返回 0 +let ymd_to_ts = function(s) { + let p = popen('date -D %Y-%m-%d -d ' + shell_quote(s) + ' +%s 2>/dev/null'); + if (!p) return 0; + let v = trim(p.read('all')); + p.close(); + let n = +v; + return (n == n && n > 0) ? int(n) : 0; +}; + +// 优先读 .info 文件(Subscription-Userinfo 响应头),其次从 outbound tag 提取 +// 常见 tag:"Traffic: 211.98 GB | 1000 GB"、"Expire: 2026-08-15" +let extract_meta = function(path) { + // Primary: .info file saved during download (same format as mihomo) + let info_path = path + '.info'; + if (access(info_path, 'r')) { + let raw_info = trim(readfile(info_path) || ''); + if (raw_info) { + let ui = parse_sub_userinfo(raw_info); + let r = {}; + if (ui.total) { r.sub_total = ui.total; r.sub_used = ui.upload + ui.download; } + if (ui.expire) r.sub_expire = ui.expire; + if (r.sub_total || r.sub_expire) return r; + } + } + // Fallback: parse from outbound tags in JSON + let st = stat(path); + if (!st || st.size > 524288) return {}; + let raw = readfile(path); + if (!raw) return {}; + let obj = json(raw); + if (!obj || type(obj.outbounds) != 'array') return {}; + let used = 0, total = 0, expire = 0; + for (let ob in obj.outbounds) { + let tag = (ob && ob.tag) ? ob.tag : ''; + if (!tag) continue; + if (!total) { + let m = match(tag, /Traffic[::]\s*([0-9.]+)\s*([KMGT]?B)\s*[|\/]\s*([0-9.]+)\s*([KMGT]?B)/); + if (m) { + used = parse_size_bytes(m[1], m[2]); + total = parse_size_bytes(m[3], m[4]); + } + } + if (!expire) { + let m2 = match(tag, /Expire[::]\s*([0-9]{4}-[0-9]{1,2}-[0-9]{1,2})/); + if (m2) expire = ymd_to_ts(m2[1]); + } + if (total && expire) break; + } + let r = {}; + if (total) { r.sub_total = total; r.sub_used = used; } + if (expire) r.sub_expire = expire; + return r; +}; + +let files = []; +for (let f in (glob(dir + '/*.json') || [])) { + let name = replace(f, dir + '/', ''); + let fi = stat(f); + let entry = { + name, + mtime: fi ? ('' + fi.mtime) : null, + size: fi ? (int(fi.size / 1024) + ' KB') : null, + active: name == active + }; + let meta = extract_meta(f); + for (let k in meta) entry[k] = meta[k]; + let url_path = f + '.url'; + if (access(url_path, 'r')) { + entry.sub_url = trim(readfile(url_path) || ''); + entry.source = 'native'; + } else { + entry.source = 'local'; + } + push(files, entry); +} +return { profiles: files, active }; +} +}, + +get_singbox_profile: { +args: { name: 'name' }, +call: function(req) { +let name = req.args?.name || ''; +if (!name || index(name, '/') >= 0 || index(name, '..') >= 0) + return { error: 'invalid name' }; +let path = '/usr/share/clashoo/config/singbox/' + name; +if (!access(path, 'r')) return { error: 'not found' }; +let s = stat(path); +if (s && s.size > 524288) return { error: 'too large' }; +return { content: readfile(path) || '', name }; +} +}, + +save_singbox_profile: { +args: { name: 'name', content: 'content' }, +call: function(req) { +let name = req.args?.name || ''; +let content = req.args?.content || ''; +if (!name || index(name, '/') >= 0 || index(name, '..') >= 0) + return { success: false, error: 'invalid name' }; +if (!content) return { success: false, error: 'empty content' }; +if (!match(name, /\.json$/)) name = name + '.json'; +let dir = '/usr/share/clashoo/config/singbox'; +system('mkdir -p ' + shell_quote(dir) + ' >/dev/null 2>&1'); +let tmp = '/tmp/clashoo_sb_validate.json'; +writefile(tmp, content); +let binary = find_binary(); +if (binary && match(binary, /sing-box/)) { + if (system(shell_quote(binary) + ' check -c ' + shell_quote(tmp) + ' >/dev/null 2>&1') != 0) { + system('rm -f ' + shell_quote(tmp)); + return { success: false, error: 'invalid_config', message: 'sing-box 配置验证失败,请检查 JSON 格式' }; + } +} +system('rm -f ' + shell_quote(tmp)); +if (writefile(dir + '/' + name, content) === null) + return { success: false, error: 'write_failed', message: '写入文件失败' }; +return { success: true, name }; +} +}, + +save_singbox_profile_chunk: { +args: { name: 'name', content: 'content', index: 'index', total: 'total' }, +call: function(req) { +let name = req.args?.name || ''; +let content = req.args?.content; +let idx = int(req.args?.index || 0); +let total = int(req.args?.total || 0); +if (!name || index(name, '/') >= 0 || index(name, '..') >= 0) + return { success: false, error: 'invalid name' }; +if (!match(name, /\.json$/)) name = name + '.json'; +if (type(content) != 'string') return { success: false, error: 'invalid content' }; +if (total < 1 || idx < 0 || idx >= total) return { success: false, error: 'invalid chunk' }; +if (total == 1 && !content) return { success: false, error: 'empty content' }; +let dir = '/usr/share/clashoo/config/singbox'; +system('mkdir -p ' + shell_quote(dir) + ' >/dev/null 2>&1'); +let tmp = '/tmp/clashoo_sb_upload_' + name; +if (idx == 0) { + if (writefile(tmp, content) === null) + return { success: false, error: 'write_failed', message: '写入文件失败' }; +} else { + let fp = open(tmp, 'a'); + if (!fp) return { success: false, error: 'write_failed', message: '打开文件失败' }; + let ok = fp.write(content); + fp.close(); + if (ok === null) return { success: false, error: 'write_failed', message: '写入文件失败' }; +} +if (idx + 1 < total) + return { success: true, name, index: idx, total, complete: false }; +let binary = find_binary(); +if (binary && match(binary, /sing-box/)) { + if (system(shell_quote(binary) + ' check -c ' + shell_quote(tmp) + ' >/dev/null 2>&1') != 0) { + system('rm -f ' + shell_quote(tmp)); + return { success: false, error: 'invalid_config', message: 'sing-box 配置验证失败,请检查 JSON 格式' }; + } +} +if (system('cp -f ' + shell_quote(tmp) + ' ' + shell_quote(dir + '/' + name) + ' >/dev/null 2>&1') != 0) { + system('rm -f ' + shell_quote(tmp)); + return { success: false, error: 'write_failed', message: '写入文件失败' }; +} +system('rm -f ' + shell_quote(tmp)); +return { success: true, name, index: idx, total, complete: true }; +} +}, + +set_singbox_profile: { +args: { name: 'name' }, +call: function(req) { +let name = req.args?.name || ''; +if (!name || index(name, '/') >= 0 || index(name, '..') >= 0) + return { success: false, error: 'invalid name' }; +let src = '/usr/share/clashoo/config/singbox/' + name; +if (!access(src, 'r')) return { success: false, error: 'not found' }; +let c = cursor(); c.load('clashoo'); +c.set('clashoo', 'config', 'core_type', 'singbox'); +c.set('clashoo', 'config', 'singbox_active', name); +c.set('clashoo', 'config', 'enable', '1'); +sync_legacy_core_fields(c); +c.commit('clashoo'); +let prepared = prepare_singbox_runtime(); +if (!prepared.success) + return { success: false, error: 'prepare_failed', message: prepared.message || '无法准备 sing-box 运行环境' }; +if (is_running()) system('service ' + get_service_name() + ' restart >/dev/null 2>&1'); +return { success: true }; +} +}, + +delete_singbox_profile: { +args: { name: 'name' }, +call: function(req) { +let name = req.args?.name || ''; +if (!name || index(name, '/') >= 0 || index(name, '..') >= 0) + return { success: false, error: 'invalid name' }; +let path = '/usr/share/clashoo/config/singbox/' + name; +if (!access(path, 'r')) return { success: false, error: 'not found' }; +if (unlink(path) === null) return { success: false, error: 'delete_failed' }; +unlink(path + '.info'); +unlink(path + '.url'); +unlink(path + '.ua'); +let c = cursor(); c.load('clashoo'); +if (c.get('clashoo', 'config', 'singbox_active') == name) { + c.delete('clashoo', 'config', 'singbox_active'); + c.commit('clashoo'); +} +return { success: true }; +} +}, + +fetch_singbox_native: { +args: { url: 'url', name: 'name' }, +call: function(req) { +let sub_url = trim(req.args?.url || ''); +let name = trim(req.args?.name || ''); +if (!sub_url || !match(sub_url, /^https?:\/\//)) + return { success: false, message: '请输入有效的订阅链接(须以 http:// 或 https:// 开头)' }; +if (!name) name = 'singbox-native'; +name = replace(name, /\.json$/, ''); +name = replace(name, /[^A-Za-z0-9_.一-龥-]/g, '-'); +name = replace(name, /-+/g, '-'); +name = replace(name, /^[-.]|[-.]$/g, '') || 'singbox-native'; +let dir = '/usr/share/clashoo/config/singbox'; +system('mkdir -p ' + shell_quote(dir) + ' >/dev/null 2>&1'); +let final_name = name + '.json'; +let path = dir + '/' + final_name; +let tmp_json = '/tmp/clashoo_sb_native.json'; +let tmp_hdr = '/tmp/clashoo_sb_native.hdr'; +system('rm -f ' + shell_quote(tmp_json) + ' ' + shell_quote(tmp_hdr) + ' >/dev/null 2>&1'); +let sub_ua = uci_get('clashoo', 'config', 'sub_ua') || 'clash.meta'; +let dl_cmd = 'curl -fsSL --connect-timeout 8 --max-time 20' + + ' -D ' + shell_quote(tmp_hdr) + + ' -A ' + shell_quote(sub_ua) + + ' ' + shell_quote(sub_url) + + ' -o ' + shell_quote(tmp_json) + + ' >/dev/null 2>&1'; +if (system(dl_cmd) != 0 || !access(tmp_json, 'r')) { + system('rm -f ' + shell_quote(tmp_json) + ' ' + shell_quote(tmp_hdr) + ' >/dev/null 2>&1'); + return { success: false, message: '下载失败,请检查链接是否可访问' }; +} +let raw = readfile(tmp_json) || ''; +if (length(raw) < 10 || substr(trim(raw), 0, 1) !== '{') { + system('rm -f ' + shell_quote(tmp_json) + ' ' + shell_quote(tmp_hdr) + ' >/dev/null 2>&1'); + return { success: false, message: '下载内容不是 JSON,该链接可能不返回原生 sing-box 配置' }; +} +let cfg = json(raw); +if (!cfg || type(cfg) !== 'object') { + system('rm -f ' + shell_quote(tmp_json) + ' ' + shell_quote(tmp_hdr) + ' >/dev/null 2>&1'); + return { success: false, message: 'JSON 解析失败' }; +} +if (type(cfg.outbounds) !== 'array' || length(cfg.outbounds) == 0) { + system('rm -f ' + shell_quote(tmp_json) + ' ' + shell_quote(tmp_hdr) + ' >/dev/null 2>&1'); + return { success: false, message: '配置缺少 outbounds 字段,可能不是原生 sing-box 格式' }; +} +if (writefile(path, raw) === null) { + system('rm -f ' + shell_quote(tmp_json) + ' ' + shell_quote(tmp_hdr) + ' >/dev/null 2>&1'); + return { success: false, message: '保存失败' }; +} +writefile(path + '.url', sub_url); +writefile(path + '.ua', sub_ua); +if (access(tmp_hdr, 'r')) { + let hdr_raw = readfile(tmp_hdr) || ''; + for (let line in split(hdr_raw, '\n')) { + let ll = lc(trim(line)); + if (substr(ll, 0, 22) == 'subscription-userinfo:') { + let info_val = trim(substr(line, 22)); + if (info_val) writefile(path + '.info', info_val); + break; + } + } +} +system('rm -f ' + shell_quote(tmp_json) + ' ' + shell_quote(tmp_hdr) + ' >/dev/null 2>&1'); +return { success: true, name: final_name, message: '已拉取 ' + final_name }; +} +}, + +update_singbox_native: { +args: { name: 'name' }, +call: function(req) { +let name = req.args?.name || ''; +if (!name || index(name, '/') >= 0 || index(name, '..') >= 0) + return { success: false, message: 'invalid name' }; +let rc = system('sh ' + shell_quote(SUBSCRIPTION_UPDATE_SCRIPT) + ' --singbox ' + shell_quote(name) + ' >/dev/null 2>&1'); +return { success: rc == 0, code: rc, message: rc == 0 ? name + ' 已更新' : name + ' 更新失败' }; +} +}, + +migrate_singbox_profile: { +args: { name: 'name' }, +call: function(req) { +let name = req.args?.name || ''; +if (!name || index(name, '/') >= 0 || index(name, '..') >= 0) + return { success: false, error: 'invalid name' }; +let path = '/usr/share/clashoo/config/singbox/' + name; +if (!access(path, 'r')) return { success: false, error: 'not found' }; +let raw = readfile(path); +if (!raw) return { success: false, error: 'read_failed' }; +let cfg = json(raw); +if (!cfg) return { success: false, message: 'JSON 解析失败' }; + +let before = sprintf('%J', cfg); +cfg = migrate_singbox(cfg); +let after = sprintf('%J', cfg); + +/* 无变化 */ +if (before === after) { + let active_same = uci_get('clashoo', 'config', 'singbox_active') || ''; + if (active_same === name) { + let prepared_same = prepare_singbox_runtime(); + if (!prepared_same.success) + return { success: false, message: prepared_same.message || '运行配置准备失败' }; + if (is_running()) system('service ' + get_service_name() + ' restart >/dev/null 2>&1'); + } + return { success: true, changes: [] }; +} + +/* 写回 */ +if (writefile(path, after) === null) + return { success: false, message: '写入文件失败' }; + +/* 如果是激活配置,同步到私有运行时;init 仍会在重启时再次规范化。 */ +let active = uci_get('clashoo', 'config', 'singbox_active') || ''; +if (active === name) { + let prepared = prepare_singbox_runtime(); + if (!prepared.success) + return { success: false, message: prepared.message || '运行配置准备失败' }; + if (is_running()) system('service ' + get_service_name() + ' restart >/dev/null 2>&1'); +} + +return { success: true, changes: ['deprecated fields removed/updated'] }; +} +}, + +create_singbox_config: { +args: { sub_url: 'sub_url', name: 'name' }, +call: function(req) { +let sub_url = trim(req.args?.sub_url || ''); +let name = trim(req.args?.name || ''); +// dashboard 字段(port/secret)由 normalize_singbox_config.uc 在启动时强制覆盖为 UCI 值, +// 这里写入仅作占位,无实际生效途径,因此直接读 UCI 即可。 +let secret = uci_get('clashoo', 'config', 'dash_pass') || ''; +let ext_port = uci_get('clashoo', 'config', 'dash_port') || '9090'; + +if (!sub_url || !match(sub_url, /^https?:\/\//)) + return { success: false, error: 'invalid_url', message: '请输入有效的订阅链接' }; + +if (!name) name = 'singbox'; +name = replace(name, /\.json$/, ''); +name = replace(name, /[^A-Za-z0-9_.\u4e00-\u9fa5-]/g, '-'); +name = replace(name, /-+/g, '-'); +name = replace(name, /^[-.]|[-.]$/g, '') || 'singbox'; + +let dir = '/usr/share/clashoo/config/singbox'; +system('mkdir -p ' + shell_quote(dir) + ' >/dev/null 2>&1'); + +let final_name = name + '.json'; + +// Write sub_url to temp file to avoid shell injection in curl call +let tmp_url = '/tmp/.clashoo-sb-url'; +writefile(tmp_url, sub_url); + +let config_obj = null; +let downloaded_yaml = ''; +let preferred_yaml = uci_get('clashoo', 'config', 'use_config') || ''; +let prefer_template = (preferred_yaml && access(preferred_yaml, 'r') && match(preferred_yaml, /\.(yaml|yml)$/)) || + match(sub_url, /flag=Clash/i) || match(sub_url, /format=clash/i); + +function has_proxy_outbounds(obj) { + if (!obj || type(obj) !== 'object' || type(obj.outbounds) !== 'array') + return false; + for (let ob in obj.outbounds) { + let t = ob?.type || ''; + if (t && t != 'selector' && t != 'urltest' && t != 'direct' && t != 'block' && t != 'dns') + return true; + } + return false; +} + +// Step 1: Try URL variants that might return native sing-box JSON +// Many providers support flag=SingBox / format=singbox even if the URL has flag=Clash +let try_urls = [sub_url]; +// If URL has a Clash flag, also try the sing-box variant +if (match(sub_url, /flag=Clash/i)) + push(try_urls, replace(sub_url, /flag=Clash/i, 'flag=SingBox')); +else if (match(sub_url, /format=clash/i)) + push(try_urls, replace(sub_url, /format=clash/i, 'format=singbox')); + +if (!prefer_template) { + let probe_ua = uci_get('clashoo', 'config', 'sub_ua') || 'clash.meta'; + for (let try_url in try_urls) { + let p0 = popen('curl -sL --max-time 12 -A ' + shell_quote(probe_ua) + ' ' + shell_quote(try_url) + ' 2>/dev/null'); + let raw0 = p0 ? trim(p0.read('all')) : ''; + if (p0) p0.close(); + if (length(raw0) > 50 && substr(raw0, 0, 1) === '{') { + let obj = json(raw0); + if (has_proxy_outbounds(obj)) { + config_obj = obj; + break; + } + } + } +} + +// Step 2 (本地最快路径): 把 yaml 喂给 yaml2singbox,避免外部 subconverter 30s × 3 +// 把它前置后,常规 yaml 订阅在 5s 内就生成完,不会触发 LuCI RPC ~30s 超时。 +if (!config_obj && system('command -v ucode >/dev/null 2>&1') == 0 && + access('/usr/share/clashoo/lib/yaml2singbox.uc', 'r') && + access('/usr/share/clashoo/lib/templates/default.json', 'r')) { + let yaml_src = ''; + if (!(yaml_src && access(yaml_src, 'r') && match(yaml_src, /\.(yaml|yml)$/))) { + let tmp_yaml = '/tmp/clashoo_sb_sub.yaml'; + let tmp_hdr = '/tmp/clashoo_sb_sub.hdr'; + system('rm -f ' + shell_quote(tmp_hdr) + ' >/dev/null 2>&1'); + let conv_ua = uci_get('clashoo', 'config', 'sub_ua') || 'clash.meta'; + let dl_cmd = 'curl -fsSL --connect-timeout 8 --max-time 20 -D ' + shell_quote(tmp_hdr) + ' -A ' + shell_quote(conv_ua) + ' ' + shell_quote(sub_url) + ' -o ' + shell_quote(tmp_yaml) + ' >/dev/null 2>&1 || wget -q --user-agent=' + shell_quote(conv_ua) + ' -O ' + shell_quote(tmp_yaml) + ' ' + shell_quote(sub_url) + ' >/dev/null 2>&1'; + if (system(dl_cmd) == 0 && access(tmp_yaml, 'r')) { + yaml_src = tmp_yaml; + downloaded_yaml = tmp_yaml; + } + } + + if (yaml_src && access(yaml_src, 'r')) { + let tmp_json = '/tmp/clashoo_sb_from_yaml.json'; + let cv_cmd = 'ucode /usr/share/clashoo/lib/yaml2singbox.uc ' + + shell_quote(yaml_src) + ' ' + + shell_quote('/usr/share/clashoo/lib/templates/default.json') + ' ' + + shell_quote(tmp_json) + ' >/tmp/clashoo_yaml2sb.log 2>&1'; + if (system(cv_cmd) == 0 && access(tmp_json, 'r')) { + let raw3 = readfile(tmp_json); + let obj3 = raw3 ? json(raw3) : null; + if (has_proxy_outbounds(obj3)) + config_obj = obj3; + } + system('rm -f ' + shell_quote(tmp_json)); + } +} + +// Step 3: 本地 yaml2singbox 失败再走外部 subconverter(base64 ss/vmess 链接列表 +// yaml2singbox 不识别,要靠外部转换器)。每个 max-time 12s,最坏 36s 兜底。 +if (!config_obj) { + let converters = [ + ['https://sub.kidsqq.cn/singbox?selectedRules=%5B%22Location%3ACN%22%2C%22Private%22%2C%22Non-China%22%2C%22Github%22%2C%22Google%22%2C%22Youtube%22%2C%22AI%2BServices%22%2C%22Telegram%22%2C%22Ad%2BBlock%22%2C%22Streaming%22%2C%22Apple%22%2C%22Social%2BMedia%22%5D&customRules=%5B%5D&group_by_country=true', 'config'], + ['https://sub.xeton.dev/sub?target=singbox', 'url'], + ['https://api.v1.mk/sub?target=singbox', 'url'], + ]; + for (let cv in converters) { + let base = cv[0], param = cv[1]; + let p = popen('curl -sL --max-time 12 -G --data-urlencode ' + + shell_quote(param + '@' + tmp_url) + ' ' + + shell_quote(base) + ' 2>/dev/null'); + let raw = p ? trim(p.read('all')) : ''; + if (p) p.close(); + if (length(raw) < 50 || substr(raw, 0, 1) !== '{') continue; + let obj = json(raw); + if (has_proxy_outbounds(obj)) { + config_obj = obj; + break; + } + } +} + +system('rm -f ' + shell_quote(tmp_url)); +if (downloaded_yaml) + system('rm -f ' + shell_quote(downloaded_yaml)); + + + +let content; +let from_converter = false; + +if (config_obj) { + from_converter = true; + // Migrate deprecated fields to sing-box 1.12+ format + config_obj = migrate_singbox(config_obj); + // Patch experimental.clash_api into the converted config + if (!config_obj.experimental) config_obj.experimental = {}; + config_obj.experimental.clash_api = { + external_controller: '0.0.0.0:' + ext_port, + external_ui: '/etc/clashoo/dashboard', + secret: secret + }; + // cache_file disabled - can cause "timeout" on first run without pre-existing cache + // config_obj.experimental.cache_file = { enabled: true }; + if (!config_obj.log) config_obj.log = { level: 'info', timestamp: true }; + // OpenWrt owns time sync; avoid sing-box NTP IPv6 noise on IPv4-only routers. + config_obj.ntp = config_obj.ntp || {}; + config_obj.ntp.enabled = false; + + // Fix rule_set URLs: rewrite to jsDelivr CDN (accessible from China) + // Pattern: https://[gh-proxy.com/]https://github.com/{owner}/{repo}/raw/refs/heads/{branch}/{path} + // → https://cdn.jsdelivr.net/gh/{owner}/{repo}@{branch}/{path} + if (config_obj.route && config_obj.route.rule_set) { + config_obj.route.rule_set = map(config_obj.route.rule_set, function(rs) { + if (rs.type !== 'remote' || !rs.url) return rs; + let url = rs.url; + // Strip gh-proxy.com wrapper if present + url = replace(url, /^https:\/\/gh-proxy\.com\//, ''); + // Convert raw.githubusercontent.com/{owner}/{repo}/{branch}/{path} → jsDelivr + let m = match(url, /^https:\/\/raw\.githubusercontent\.com\/([^\/]+)\/([^\/]+)\/([^\/]+)\/(.+)$/); + if (m) { + url = 'https://cdn.jsdelivr.net/gh/' + m[1] + '/' + m[2] + '@' + m[3] + '/' + m[4]; + } + // Convert github.com/{owner}/{repo}/raw/refs/heads/{branch}/{path} → jsDelivr + if (!m) { + m = match(url, /^https:\/\/github\.com\/([^\/]+)\/([^\/]+)\/raw\/refs\/heads\/([^\/]+)\/(.+)$/); + if (m) { + url = 'https://cdn.jsdelivr.net/gh/' + m[1] + '/' + m[2] + '@' + m[3] + '/' + m[4]; + } + } + if (url === rs.url) return rs; + let r = {}; + for (let k in rs) r[k] = rs[k]; + r.url = url; + return r; + }); + } + content = sprintf('%J\n', config_obj); +} else { + // Fallback: generate a skeleton sing-box config (no proxies) + // User should upload a proper sing-box JSON config instead + function je(s) { + s = replace(s || '', /\\/g, '\\\\'); + s = replace(s, /"/g, '\\"'); + return s; + } + // 没拿到任何代理节点时给一个最小可启动骨架: + // 不依赖任何远程 rule_set(路由器纯净环境 DIRECT 拉 jsdelivr 会卡 → FATAL), + // 等用户在 LuCI 里替换/上传带节点的配置后再启用规则。 + content = +'{\n' + +' "log": { "level": "info", "timestamp": true },\n' + +' "_note": "subconverter unavailable - replace outbounds with your proxies",\n' + +' "_sub_url": "' + je(sub_url) + '",\n' + +' "dns": {\n' + +' "servers": [\n' + +' { "tag": "remote", "type": "https", "server": "1.1.1.1" },\n' + +' { "tag": "local", "type": "udp", "server": "223.5.5.5" }\n' + +' ],\n' + +' "rules": [\n' + +' { "clash_mode": "Global", "action": "route", "server": "remote" },\n' + +' { "clash_mode": "Direct", "action": "route", "server": "local" }\n' + +' ],\n' + +' "final": "local"\n' + +' },\n' + +' "inbounds": [\n' + +' { "type": "tun", "tag": "tun-in",\n' + +' "address": ["172.19.0.1/30", "fdfe:dcba:9876::1/126"],\n' + +' "auto_route": true, "strict_route": true }\n' + +' ],\n' + +' "outbounds": [\n' + +' { "type": "direct", "tag": "DIRECT" }\n' + +' ],\n' + +' "route": {\n' + +' "default_domain_resolver": { "server": "local" },\n' + +' "rules": [\n' + +' { "action": "sniff" },\n' + +' { "protocol": "dns", "action": "hijack-dns" },\n' + +' { "clash_mode": "Direct", "outbound": "DIRECT" }\n' + +' ],\n' + +' "final": "DIRECT",\n' + +' "auto_detect_interface": true\n' + +' },\n' + +' "experimental": {\n' + +' "clash_api": {\n' + +' "external_controller": "0.0.0.0:' + je(ext_port) + '",\n' + +' "external_ui": "/etc/clashoo/dashboard",\n' + +' "secret": "' + je(secret) + '"\n' + +' },\n' + +' "cache_file": { "enabled": true, "store_fakeip": true }\n' + +' }\n' + +'}\n'; +} + +let path = dir + '/' + final_name; +if (writefile(path, content) === null) + return { success: false, error: 'write_failed', message: '写入配置文件失败' }; + +// Save Subscription-Userinfo from captured HTTP headers as .json.info +let sb_hdr_file = '/tmp/clashoo_sb_sub.hdr'; +if (access(sb_hdr_file, 'r')) { + let hdr_raw = readfile(sb_hdr_file) || ''; + for (let line in split(hdr_raw, '\n')) { + let ll = lc(trim(line)); + if (substr(ll, 0, 22) == 'subscription-userinfo:') { + let info_val = trim(substr(line, 22)); + if (info_val) writefile(path + '.info', info_val); + break; + } + } + system('rm -f ' + shell_quote(sb_hdr_file) + ' >/dev/null 2>&1'); +} + +let msg = from_converter + ? '配置已从订阅生成: ' + final_name + : '订阅转换失败,已生成基础模板(请手动添加代理): ' + final_name; +return { success: true, name: final_name, path, message: msg }; +} +}, + +/* 备份导出:把 UCI 配置 + 各类配置文件打包成一个 JSON 对象返回。 + 仅含纯文本,前端存成 clashoo-backup-*.json。内核/GeoIP 体积大且可重下,不备。 */ +backup_export: { +call: function() { +try { +let BACKUP_DIR_MAP = { + 'config/sub': '/usr/share/clashoo/config/sub', + 'config/upload': '/usr/share/clashoo/config/upload', + 'config/custom': '/usr/share/clashoo/config/custom', + 'config/singbox': SINGBOX_DIR, + 'templates': TEMPLATE_USER_DIR +}; +let BACKUP_FIXED_MAP = { + 'uci': '/etc/config/clashoo', + 'meta/confit_list.conf': LIST_FILE, + 'meta/template_bindings.conf': TEMPLATE_BIND_FILE +}; +let MAX_TOTAL = 480 * 1024; +let files = {}; +let total = 0; +let add_file = function(rel, path) { + if (!access(path, 'r')) return true; + let s = stat(path); + if (s && s.type != 'file') return true; + let content = readfile(path); + if (content === null) return true; + total += length(content); + if (total > MAX_TOTAL) return false; + files[rel] = content; + return true; +}; + +for (let rel in BACKUP_FIXED_MAP) + if (!add_file(rel, BACKUP_FIXED_MAP[rel])) + return { success: false, message: '备份内容过大(超过 480KB)' }; + +for (let prefix in BACKUP_DIR_MAP) { + let d = BACKUP_DIR_MAP[prefix]; + for (let f in (glob(d + '/*') || [])) { + let base = substr(f, length(d) + 1); + if (!add_file(prefix + '/' + base, f)) + return { success: false, message: '备份内容过大(超过 480KB)' }; + } +} + +let host = ''; +let hp = popen('uname -n 2>/dev/null'); +if (hp) { host = trim(hp.read('all')); hp.close(); } + +return { + success: true, + manifest: { + marker: 'clashoo-backup-v1', + created_at: now_epoch_sec(), + host: host, + app_version: read_first_line('/usr/share/clashoo/luci_version') + }, + files: files +}; +} catch (e) { +return { success: false, message: '导出失败: ' + e }; +} +} +}, + +/* 大文件备份走 cgi-download:每次导出使用独立的随机路径。 */ +backup_export_prepare: { +call: function() { +let export_path = ''; +let result_path = ''; +try { + if (!backup_tmp_ready()) + return { success: false, message: '备份临时目录不安全或无法创建' }; + export_path = new_backup_temp_path('export'); + if (!export_path) + return { success: false, message: '无法创建导出临时文件' }; + result_path = export_path + '.result'; + let cmd = 'sh ' + shell_quote(BACKUP_ARCHIVE_SCRIPT) + + ' export ' + shell_quote(export_path) + + ' >' + shell_quote(result_path) + ' 2>&1'; + if (system(cmd) != 0) { + let detail = trim(readfile(result_path) || ''); + unlink(export_path); + unlink(result_path); + return { success: false, message: detail || '生成备份文件失败' }; + } + let info = stat(export_path); + if (!info || info.type != 'file' || info.size <= 0) { + unlink(export_path); + unlink(result_path); + return { success: false, message: '生成的备份文件无效' }; + } + let stamp = ''; + let dp = popen('date +%Y%m%d-%H%M 2>/dev/null'); + if (dp) { stamp = trim(dp.read('all')); dp.close(); } + unlink(result_path); + return { + success: true, + path: export_path, + filename: 'clashoo-backup-' + (stamp || now_epoch_sec()) + '.tar.gz', + size: info.size + }; +} catch (e) { + if (export_path) unlink(export_path); + if (result_path) unlink(result_path); + return { success: false, message: '导出失败: ' + e }; +} +} +}, + +backup_export_cleanup: { +args: { path: 'path' }, +call: function(req) { + if (!backup_tmp_ready()) + return { success: false }; + let export_path = safe_backup_export_path(req.args?.path || ''); + if (!export_path) + return { success: false }; + unlink(export_path); + unlink(export_path + '.result'); + return { success: true }; +} +}, + +backup_import_prepare: { +call: function() { + if (!backup_tmp_ready()) + return { success: false, message: '备份临时目录不安全或无法创建' }; + let path = new_backup_temp_path('import'); + return path + ? { success: true, path: path } + : { success: false, message: '无法创建上传临时文件' }; +} +}, + +/* 分块写入在 RPC 后端逐次校验偏移和总大小,超限时立即删除。 */ +backup_import_chunk: { +args: { path: 'path', offset: 0, data: 'data' }, +call: function(req) { +try { + let upload_path = safe_backup_upload_path(req.args?.path || ''); + let offset = int(req.args?.offset || 0); + let encoded = req.args?.data || ''; + if (!upload_path || offset < 0) + return { success: false, message: '上传参数无效' }; + if (!backup_tmp_ready()) + return { success: false, message: '备份临时目录不安全或无法访问' }; + if (!active_backup_upload(upload_path)) { + release_backup_upload(upload_path); + return { success: false, message: '上传会话已失效,请重新选择备份文件' }; + } + let info = stat(upload_path); + if (!info || info.type != 'file' || info.size != offset) + return { success: false, message: '上传偏移不匹配,请重新选择备份文件' }; + if (!encoded || length(encoded) > BACKUP_MAX_CHUNK_BASE64_SIZE) { + release_backup_upload(upload_path); + return { success: false, message: '上传分块过大' }; + } + let chunk = null; + try { chunk = b64dec(encoded); } catch (e) { chunk = null; } + if (chunk === null || length(chunk) <= 0 || length(chunk) > BACKUP_MAX_CHUNK_SIZE) { + release_backup_upload(upload_path); + return { success: false, message: '上传分块无效' }; + } + let next_offset = offset + length(chunk); + if (next_offset > BACKUP_MAX_ARCHIVE_SIZE) { + release_backup_upload(upload_path); + return { success: false, message: '备份文件超过 32MB' }; + } + let fp = open(upload_path, 'a'); + if (!fp) { + release_backup_upload(upload_path); + return { success: false, message: '无法写入上传临时文件' }; + } + let written = fp.write(chunk); + fp.close(); + if (written != length(chunk)) { + release_backup_upload(upload_path); + return { success: false, message: '上传分块写入不完整' }; + } + if (!refresh_backup_upload(upload_path)) { + release_backup_upload(upload_path); + return { success: false, message: '无法刷新上传会话' }; + } + return { success: true, offset: next_offset }; +} catch (e) { + let upload_path = safe_backup_upload_path(req.args?.path || ''); + if (upload_path && backup_tmp_ready()) release_backup_upload(upload_path); + return { success: false, message: '上传失败: ' + e }; +} +} +}, + +backup_import_cleanup: { +args: { path: 'path' }, +call: function(req) { + if (!backup_tmp_ready()) + return { success: false }; + let upload_path = safe_backup_upload_path(req.args?.path || ''); + if (!upload_path) + return { success: false }; + release_backup_upload(upload_path); + return { success: true }; +} +}, + +/* 备份导入:用备份快照覆盖当前配置。先全量校验路径白名单(拒绝目录遍历), + 通过后才清空目标目录并重写,最后异步重启服务。 */ +backup_import: { +args: { data: 'data' }, +call: function(req) { + return restore_backup_json(req.args?.data || ''); +} +}, + +/* 上传内容落到后端生成的随机临时路径,前端不能指定其他位置。 */ +backup_import_file: { +args: { name: 'name', path: 'path' }, +call: function(req) { +try { + let name = req.args?.name || ''; + let upload_path = safe_backup_upload_path(req.args?.path || ''); + if (!upload_path) + return { success: false, message: '上传临时路径无效' }; + if (!backup_tmp_ready()) + return { success: false, message: '备份临时目录不安全或无法访问' }; + if (!active_backup_upload(upload_path)) { + release_backup_upload(upload_path); + return { success: false, message: '上传会话已失效,请重新选择备份文件' }; + } + let info = stat(upload_path); + if (!info || info.type != 'file') { + release_backup_upload(upload_path); + return { success: false, message: '没有找到已上传的备份文件' }; + } + if (info.size <= 0) { + release_backup_upload(upload_path); + return { success: false, message: '备份文件为空' }; + } + + if (match(lc(name), /\.json$/)) { + if (info.size > BACKUP_MAX_JSON_SIZE) { + release_backup_upload(upload_path); + return { success: false, message: '旧版 JSON 备份超过 8MB' }; + } + let raw = readfile(upload_path); + release_backup_upload(upload_path); + if (raw === null) + return { success: false, message: '读取备份文件失败' }; + return restore_backup_json(raw); + } + + if (!match(lc(name), /\.tar\.gz$/)) { + release_backup_upload(upload_path); + return { success: false, message: '仅支持 .tar.gz 和旧版 .json 备份文件' }; + } + + let result_path = upload_path + '.result'; + unlink(result_path); + let cmd = 'sh ' + shell_quote(BACKUP_ARCHIVE_SCRIPT) + + ' restore ' + shell_quote(upload_path) + + ' >' + shell_quote(result_path) + ' 2>&1'; + let rc = system(cmd); + let detail = trim(readfile(result_path) || ''); + release_backup_upload(upload_path); + if (rc != 0) + return { success: false, message: detail || '还原备份失败' }; + system('sh /usr/share/clashoo/rpc/rpc_async.sh restart >/dev/null 2>&1'); + return { success: true, message: '备份已还原,正在重启服务' }; +} catch (e) { + let upload_path = safe_backup_upload_path(req.args?.path || ''); + if (upload_path && backup_tmp_ready()) release_backup_upload(upload_path); + return { success: false, message: '导入失败: ' + e }; +} +} +}, + +/* 还原默认:把出厂默认 UCI 覆盖回 /etc/config/clashoo,只重置设置, + 不动订阅/配置文件。出厂副本由 clashoo 包装在非 conffile 路径,永远最新。 */ +backup_reset: { +call: function() { +try { +let def = '/usr/share/clashoo/clashoo.default'; +if (!access(def, 'r')) + return { success: false, message: '出厂默认配置文件缺失,无法还原' }; +if (system('cp ' + shell_quote(def) + ' /etc/config/clashoo') != 0) + return { success: false, message: '写入默认配置失败' }; +system('sh /usr/share/clashoo/rpc/rpc_async.sh restart >/dev/null 2>&1'); +return { success: true, message: '已还原出厂默认设置,正在重启服务' }; +} catch (e) { +return { success: false, message: '还原失败: ' + e }; +} +} +} +}; + +return { 'luci.clashoo': methods }; + +reload_service() { + restart +} diff --git a/scripts/gen-cn-nft.sh b/scripts/gen-cn-nft.sh new file mode 100644 index 000000000..ea9055c99 --- /dev/null +++ b/scripts/gen-cn-nft.sh @@ -0,0 +1,85 @@ +#!/bin/sh + +set -eu + +ROOT_DIR="$(CDPATH= cd -- "$(dirname "$0")/.." && pwd)" +OUT_DIR="${ROOT_DIR}/clashoo/files/usr/share/clashoo/nftables" +TMP_DIR="$(mktemp -d)" +V2DAT_BIN="${V2DAT_BIN:-}" +GEOIP_DAT_URL="${GEOIP_DAT_URL:-https://testingcf.jsdelivr.net/gh/MetaCubeX/meta-rules-dat@release/geoip.dat}" +V2DAT_PKG="${V2DAT_PKG:-github.com/kenzok8/v2dat}" + +cleanup() { + rm -rf "$TMP_DIR" +} + +trap cleanup EXIT INT TERM + +ensure_v2dat() { + if [ -n "$V2DAT_BIN" ] && [ -x "$V2DAT_BIN" ]; then + return 0 + fi + if command -v v2dat >/dev/null 2>&1; then + V2DAT_BIN="$(command -v v2dat)" + return 0 + fi + export GOBIN="${TMP_DIR}/bin" + mkdir -p "$GOBIN" + go install "${V2DAT_PKG}@latest" + V2DAT_BIN="${GOBIN}/v2dat" +} + +render_nft_set() { + local family="$1" + local input_file="$2" + local output_file="$3" + local set_name="$4" + + awk -v set_name="$set_name" -v set_type="$family" ' + 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 (!first) + print "," + printf "\t\t%s", $0 + first = 0 + } + END { + if (!first) + print "" + print "\t}" + print "}" + } + ' "$input_file" > "$output_file" +} + +mkdir -p "$OUT_DIR" "${TMP_DIR}/out" +ensure_v2dat + +curl -fsSL "$GEOIP_DAT_URL" -o "${TMP_DIR}/geoip.dat" +"$V2DAT_BIN" unpack geoip -o "${TMP_DIR}/out" -f cn "${TMP_DIR}/geoip.dat" + +CN_TXT="$(find "${TMP_DIR}/out" -type f -name '*_cn.txt' | head -1)" +[ -n "${CN_TXT}" ] && [ -f "${CN_TXT}" ] || { + echo "failed to unpack CN CIDRs from geoip.dat" >&2 + exit 1 +} + +awk 'index($0, ":") == 0 { print }' "${CN_TXT}" > "${TMP_DIR}/cn_ipv4.txt" +awk 'index($0, ":") != 0 { print }' "${CN_TXT}" > "${TMP_DIR}/cn_ipv6.txt" + +render_nft_set ipv4_addr "${TMP_DIR}/cn_ipv4.txt" "${OUT_DIR}/geoip_cn.nft" clashoo_china +render_nft_set ipv6_addr "${TMP_DIR}/cn_ipv6.txt" "${OUT_DIR}/geoip6_cn.nft" clashoo_china6 + +echo "generated:" +echo " ${OUT_DIR}/geoip_cn.nft" +echo " ${OUT_DIR}/geoip6_cn.nft" diff --git a/scripts/gen-singbox-rulesets.sh b/scripts/gen-singbox-rulesets.sh new file mode 100755 index 000000000..ce5a7c805 --- /dev/null +++ b/scripts/gen-singbox-rulesets.sh @@ -0,0 +1,57 @@ +#!/bin/sh + +set -eu + +ROOT_DIR="$(CDPATH= cd -- "$(dirname "$0")/.." && pwd)" +RULESET_DIR="${ROOT_DIR}/clashoo/files/usr/share/clashoo/ruleset" +TMP_DIR="$(mktemp -d)" +GEOSITE_BASE="${GEOSITE_BASE:-https://cdn.jsdelivr.net/gh/MetaCubeX/meta-rules-dat@sing/geo/geosite}" +GEOIP_BASE="${GEOIP_BASE:-https://cdn.jsdelivr.net/gh/MetaCubeX/meta-rules-dat@sing/geo/geoip}" +# mihomo .mrs lives on the meta branch (binary, not .srs) +META_GEOSITE_BASE="${META_GEOSITE_BASE:-https://cdn.jsdelivr.net/gh/MetaCubeX/meta-rules-dat@meta/geo/geosite}" + +cleanup() { + rm -rf "$TMP_DIR" +} + +trap cleanup EXIT INT TERM + +fetch_ruleset() { + tag="$1" + base="$2" + remote_name="${3:-$tag}" + url="${base}/${remote_name}.srs" + tmp_file="${TMP_DIR}/${tag}.srs" + out_file="${RULESET_DIR}/${tag}.srs" + + echo "fetch ${tag}.srs" + curl -fsSL --retry 3 --retry-delay 2 "$url" -o "$tmp_file" + [ -s "$tmp_file" ] || { + echo "empty ruleset: $url" >&2 + exit 1 + } + mv "$tmp_file" "$out_file" +} + +mkdir -p "$RULESET_DIR" +rm -f "${RULESET_DIR}"/*.srs + +# Minimal built-in set: +# - geolocation-!cn: required by fake-ip DNS and broad non-CN routing. +# - geosite-cn: local alias for subscription tags geolocation-cn/cn. +# - cn-ip/private-ip: keep China/private IP direct without remote downloads. +fetch_ruleset "geolocation-!cn" "$GEOSITE_BASE" +fetch_ruleset "geosite-cn" "$GEOSITE_BASE" geolocation-cn +fetch_ruleset "private-ip" "$GEOIP_BASE" private +fetch_ruleset "cn-ip" "$GEOIP_BASE" cn + +# mihomo cn.mrs replaces geosite:cn in fake-ip-filter so the core skips geosite.dat +echo "fetch cn.mrs" +curl -fsSL --retry 3 --retry-delay 2 "${META_GEOSITE_BASE}/cn.mrs" -o "${TMP_DIR}/cn.mrs" +[ -s "${TMP_DIR}/cn.mrs" ] || { + echo "empty ruleset: ${META_GEOSITE_BASE}/cn.mrs" >&2 + exit 1 +} +mv "${TMP_DIR}/cn.mrs" "${RULESET_DIR}/cn.mrs" + +echo "generated sing-box rule sets in ${RULESET_DIR}" diff --git a/scripts/install.sh b/scripts/install.sh new file mode 100755 index 000000000..a36bed277 --- /dev/null +++ b/scripts/install.sh @@ -0,0 +1,281 @@ +#!/bin/sh + +set -eu + +FEED_BASE_URL="https://down.dllkids.xyz/openwrt-feed/clashoo" +GITHUB_API_URL="https://api.github.com/repos/kenzok8/openwrt-clashoo/releases/latest" +GITHUB_PROXY_PREFIX="${GITHUB_PROXY_PREFIX:-https://ghfast.top/}" +TMP_DIR="/tmp/clashoo-install" + +fetch_text() { + url="$1" + if command -v curl >/dev/null 2>&1; then + curl -fsSL "$url" + return $? + fi + if command -v wget >/dev/null 2>&1; then + wget -qO- "$url" + return $? + fi + return 127 +} + +download_file() { + url="$1" + out="$2" + if command -v curl >/dev/null 2>&1; then + curl -fL "$url" -o "$out" + return $? + fi + wget -qO "$out" "$url" +} + +download_url() { + url="$1" + case "$url" in + https://github.com/*) + printf '%s%s\n' "$GITHUB_PROXY_PREFIX" "$url" + ;; + *) + printf '%s\n' "$url" + ;; + esac +} + +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" +} + +detect_arch() { + pm="$1" + if [ "$pm" = "opkg" ]; then + opkg print-architecture | awk '/^arch / {print $2}' | tail -n 1 + return + fi + # apk --print-arch 只回 CPU family(如 aarch64),丢掉 subtarget 后缀; + # feed/release 产物用完整 target arch(aarch64_cortex-a53),优先读 DISTRIB_ARCH + distrib_arch="$(sed -n "s/^DISTRIB_ARCH=['\"]\([^'\"]*\)['\"].*/\1/p" /etc/openwrt_release 2>/dev/null | head -n 1)" + if [ -n "$distrib_arch" ]; then + printf '%s\n' "$distrib_arch" + else + apk --print-arch + fi +} + +detect_sdk() { + if [ ! -r /etc/openwrt_release ]; then + return 1 + fi + + release="$(sed -n "s/^DISTRIB_RELEASE=['\"]\\([^'\"]*\\)['\"]$/\\1/p" /etc/openwrt_release | head -n 1)" + [ -n "$release" ] || return 1 + + sdk="$(printf '%s\n' "$release" | grep -Eo '[0-9]+\.[0-9]+' | head -n 1)" + [ -n "$sdk" ] || return 1 + printf '%s\n' "$sdk" +} + +find_feed_filename() { + package_name="$1" + packages_text="$2" + printf '%s\n' "$packages_text" | awk -v pkg="$package_name" ' + $0 == "Package: " pkg { + in_pkg = 1 + next + } + in_pkg && /^Filename: / { + sub(/^Filename: /, "") + print + exit + } + in_pkg && /^$/ { + in_pkg = 0 + } + ' +} + +find_manifest_value() { + key="$1" + manifest_text="$2" + printf '%s\n' "$manifest_text" | sed -n "s/^${key}=//p" | 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" +} + +# Feed 结构:/// —— 与 dllkids setup.sh 对齐,不嵌 feedname 子目录 +feed_base_for() { + printf '%s/%s/%s' "$FEED_BASE_URL" "$1" "$2" +} + +load_manifest_urls() { + sdk="$1" + arch="$2" + base="$(feed_base_for "$sdk" "$arch")" + manifest_url="${base}/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 + + CORE_URL="${base}/${core_file}" + LUCI_URL="${base}/${luci_file}" + I18N_URL="" + [ -n "$i18n_file" ] && I18N_URL="${base}/${i18n_file}" + return 0 +} + +load_opkg_feed_urls() { + sdk="$1" + arch="$2" + base="$(feed_base_for "$sdk" "$arch")" + packages_url="${base}/Packages.gz" + packages_text="$(fetch_text "$packages_url" || true)" + if ! printf '%s' "$packages_text" | grep -q '^Package: '; then + return 1 + fi + + core_file="$(find_feed_filename "clashoo" "$packages_text")" + luci_file="$(find_feed_filename "luci-app-clashoo" "$packages_text")" + i18n_file="$(find_feed_filename "luci-i18n-clashoo-zh-cn" "$packages_text")" + + [ -n "$core_file" ] || return 1 + [ -n "$luci_file" ] || return 1 + + CORE_URL="${base}/${core_file}" + LUCI_URL="${base}/${luci_file}" + I18N_URL="" + [ -n "$i18n_file" ] && I18N_URL="${base}/${i18n_file}" + 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 + return 0 +} + +PM="$(detect_manager)" +if [ "$PM" = "unsupported" ]; then + echo "No supported package manager found (opkg/apk)." + exit 1 +fi + +ARCH="$(detect_arch "$PM")" +[ -n "$ARCH" ] || { echo "Cannot detect architecture"; exit 1; } + +SDK_CANDIDATES="$(build_sdk_candidates "$PM")" + +EXT="ipk" +[ "$PM" = "apk" ] && EXT="apk" + +CORE_URL="" +LUCI_URL="" +I18N_URL="" + +if [ -n "$SDK_CANDIDATES" ]; then + for SDK in $SDK_CANDIDATES; do + if load_manifest_urls "$SDK" "$ARCH"; then + echo "Using R2 feed manifest: ${SDK}/${ARCH}" + break + fi + if [ "$PM" = "opkg" ] && load_opkg_feed_urls "$SDK" "$ARCH"; then + echo "Using R2 feed: ${SDK}/${ARCH}" + break + fi + done +fi + +if [ -z "$CORE_URL" ] || [ -z "$LUCI_URL" ]; then + if load_github_urls "$ARCH" "$EXT"; then + echo "Using GitHub latest release" + else + echo "Cannot find required packages for arch: $ARCH" + echo "Detected package manager: $PM" + echo "Tried SDKs: $SDK_CANDIDATES" + exit 1 + fi +fi + +rm -rf "$TMP_DIR" +mkdir -p "$TMP_DIR" + +echo "Downloading packages..." +download_file "$(download_url "$CORE_URL")" "$TMP_DIR/core.${EXT}" +download_file "$(download_url "$LUCI_URL")" "$TMP_DIR/luci.${EXT}" +if [ -n "$I18N_URL" ]; then + download_file "$(download_url "$I18N_URL")" "$TMP_DIR/i18n.${EXT}" +fi + +echo "Installing packages with $PM..." +if [ "$PM" = "opkg" ]; then + # Refresh package lists so deps (yq, coreutils-nohup, kmod-*) resolve on fresh systems + opkg update || echo "Warning: opkg update failed, dependency resolution may break" + opkg install "$TMP_DIR/core.${EXT}" "$TMP_DIR/luci.${EXT}" ${I18N_URL:+"$TMP_DIR/i18n.${EXT}"} +else + apk update || echo "Warning: apk update failed, dependency resolution may break" + apk add --allow-untrusted "$TMP_DIR/core.${EXT}" "$TMP_DIR/luci.${EXT}" ${I18N_URL:+"$TMP_DIR/i18n.${EXT}"} +fi + +echo "Install complete." diff --git a/scripts/uninstall.sh b/scripts/uninstall.sh new file mode 100755 index 000000000..8f65c41fa --- /dev/null +++ b/scripts/uninstall.sh @@ -0,0 +1,57 @@ +#!/bin/sh + +set -eu + +echo "Stopping clashoo service..." +/etc/init.d/clashoo stop >/dev/null 2>&1 || true +/etc/init.d/clashoo disable >/dev/null 2>&1 || true + +core_still_installed() { + if command -v apk >/dev/null 2>&1; then + apk list -I 2>/dev/null | grep -q "^clashoo-[0-9]" + elif command -v opkg >/dev/null 2>&1; then + opkg list-installed 2>/dev/null | grep -q "^clashoo " + else + return 1 + fi +} + +if command -v opkg >/dev/null 2>&1; then + echo "Removing packages with opkg..." + opkg remove luci-i18n-clashoo-zh-cn luci-app-clashoo clashoo >/dev/null 2>&1 || true +elif command -v apk >/dev/null 2>&1; then + echo "Removing packages with apk..." + apk del luci-i18n-clashoo-zh-cn luci-app-clashoo clashoo >/dev/null 2>&1 || true +else + echo "No supported package manager found (opkg/apk), skip package removal." +fi + +# Always safe: purely runtime/temp files, never owned by the package manager. +echo "Cleaning runtime temp files..." +rm -rf /tmp/clashoo /tmp/clashoo-install /tmp/clashoo_* /tmp/luci* 2>/dev/null || true + +# CRITICAL: only delete package-owned files (config / init.d / dirs) when the +# core package was actually removed. If it's still installed - e.g. nikki, which +# depends on the clashoo-provided `mihomo`, blocks `apk del clashoo` - deleting +# these behind the package manager's back corrupts apk's state: the db keeps +# owning files that no longer exist, so a later same-version reinstall only +# writes `.apk-new` and never restores them, leaving the UI broken +# ("kernel not installed" / start stuck). Leave them in place instead. +if core_still_installed; then + echo "WARNING: 'clashoo' is still installed because other packages depend on it" + echo " (e.g. nikki depends on the clashoo-provided 'mihomo')." + echo " Kept /etc/config/clashoo, /etc/init.d/clashoo and /etc/clashoo intact" + echo " to avoid corrupting package state. Remove nikki first for a full" + echo " uninstall, or just reinstall clashoo to refresh it." +else + echo "Cleaning package files..." + rm -rf /etc/clashoo /usr/share/clashoo /usr/share/clashbackup 2>/dev/null || true + rm -f /etc/init.d/clashoo /etc/config/clashoo 2>/dev/null || true +fi + +/etc/init.d/rpcd restart >/dev/null 2>&1 || true +/etc/init.d/uhttpd restart >/dev/null 2>&1 || true +/etc/init.d/dnsmasq restart >/dev/null 2>&1 || true +/etc/init.d/firewall restart >/dev/null 2>&1 || true + +echo "Uninstall & reset complete."