include $(TOPDIR)/rules.mk PKG_NAME:=isp-split PKG_VERSION:=0.4.1 PKG_RELEASE:=7 PKG_LICENSE:=MIT PKG_LICENSE_FILES:=LICENSE PKG_MAINTAINER:=jihebube include $(INCLUDE_DIR)/package.mk # 线路体检(linecheck)自 0.3.0 起随包发货,默认 1。 # 1 = 完整功能(默认,正式发行版走这条路径); # 0 = 构建期物理剥离:实现、CLI、conf 键、LuCI 页/菜单、socat 依赖全部不进包。 # 小闪存 / 特殊渠道的可选剥离版,必须显式指定 FEATURE_LINECHECK=0。 # 这是构建期开关,不是运行时开关:0 的产物里没有可被重新打开的代码。 FEATURE_LINECHECK?=1 define Package/isp-split SECTION:=net CATEGORY:=Network SUBMENU:=Routing and Redirection TITLE:=ISP-aware policy routing for mwan3 (nftables) # 注意:这里故意不写 +mwan3 依赖。 # 官方 feed 的 mwan3 是 iptables 版(2.12.5),写 +mwan3 会错误地拉进它; # Kwrt 源里 nft 版的包名是 mwan3-nft,与其他源命名不一致。 # nftables 版 mwan3 是硬性前提,由 install.sh 与 router-preflight 检查, # 并在 description 里说明。 DEPENDS:=+nftables +curl +mwan3-nft $(if $(filter 1,$(FEATURE_LINECHECK)),+socat) PKGARCH:=all endef define Package/isp-split/description Route traffic by the ISP that owns the destination address. Builds mutually exclusive nftables sets from daily-updated Chinese ISP CIDR data and wires them into mwan3-nft rules. REQUIRES the nftables port of mwan3 (>= 3.6.0): - Kwrt: apk add mwan3-nft (软件源里自带) - 上游: 用 https://github.com/dl12345/mwan3 替换官方 feed 的 iptables 版 mwan3 (2.12.5),或从 Release 下载 endef define Build/Prepare rm -rf $(PKG_BUILD_DIR) mkdir -p $(PKG_BUILD_DIR) $(CP) ./files $(PKG_BUILD_DIR)/files # 只调用仓库里那一份 strip-linecheck.sh(随包内 strip-linecheck.sh 逐字节 # 一致),不再手抄 sed:F7 的泄漏就是 SDK 侧另抄一份、覆盖不全造成的。 # 脚本自己会做标记配对、零残留、CSS `.lc-*` 与 sh -n 断言。 if [ "$(FEATURE_LINECHECK)" != "1" ]; then \ sh $(CURDIR)/strip-linecheck.sh $(PKG_BUILD_DIR)/files; \ fi endef define Build/Compile endef define Package/isp-split/conffiles /etc/isp-split.conf endef # opkg 升级会以 prerm upgrade 调用;apk 的 prerm 只映射到 pre-deinstall。 # 升级时绝不能 uninstall:数据目录、mwan3 规则都必须保留。 define Package/isp-split/prerm #!/bin/sh [ -n "$${IPKG_INSTROOT}" ] && exit 0 case "$${1:-}" in upgrade|pre-upgrade|*upgrade*) exit 0 ;; esac if [ -x /usr/sbin/isp-split ]; then /usr/sbin/isp-split uninstall >/dev/null 2>&1 || true fi exit 0 endef # 卸载后的兜底清理。正常路径是 prerm 里的 `isp-split uninstall`(它调 # /usr/lib/isp-split/teardown.sh,与 scripts/install.sh --uninstall 同一份实现)。 # 但 opkg/apk 会先删包文件再跑 postrm,那时 teardown.sh 已经不在盘上, # 所以这里必须自带一份等价的内联清单 —— 这是"三条路径同源"的唯一例外, # 由 tools/selftest.sh 第 21 节做锚点双向核对:teardown.sh 的 runtime 锚点 # 必须逐条出现在本块里,本块也不许出现清单外的清理动作。 define Package/isp-split/postrm #!/bin/sh [ -n "$${IPKG_INSTROOT}" ] && exit 0 case "$${1:-}" in upgrade|pre-upgrade|*upgrade*) exit 0 ;; esac # 共享实现在盘上就用它(少数包管理器/强制删除会在删文件前跑 postrm)。 if [ -f /usr/lib/isp-split/teardown.sh ]; then sh /usr/lib/isp-split/teardown.sh all exit $$? fi if [ -f /etc/crontabs/root ]; then # mktemp 而不是固定 /tmp 名:PID 可预测,符号链接能抢占(SEC-1) _cron_tmp=$$(mktemp /etc/.isp-split-cron.XXXXXX) || _cron_tmp="" if [ -n "$$_cron_tmp" ]; then grep -v 'isp-split' /etc/crontabs/root > "$$_cron_tmp" 2>/dev/null || true mv -f "$$_cron_tmp" /etc/crontabs/root 2>/dev/null || rm -f "$$_cron_tmp" fi /etc/init.d/cron restart >/dev/null 2>&1 || true fi nft delete counter inet mwan3 isp_fallback >/dev/null 2>&1 || true # B-5:状态文件已改名 dnsmasq.confdir.migrated(记的是迁移后的清理值)。 # 旧名 dnsmasq.confdir.orig 兼容读一次。 _state=/etc/isp-split/state/dnsmasq.confdir.migrated [ -f "$$_state" ] || _state=/etc/isp-split/state/dnsmasq.confdir.orig if [ -f "$$_state" ]; then _orig=$$(head -1 "$$_state" 2>/dev/null) if [ -n "$$_orig" ]; then uci -q set "dhcp.@dnsmasq[0].confdir=$$_orig" 2>/dev/null || true else uci -q delete dhcp.@dnsmasq[0].confdir 2>/dev/null || true fi uci -q commit dhcp 2>/dev/null || true rm -f /etc/isp-split/state/dnsmasq.confdir.migrated \ /etc/isp-split/state/dnsmasq.confdir.orig 2>/dev/null || true fi # BUG-6:OpenClash 接管时 dnsmasq 实际加载的是 /var/etc/dnsmasq.conf.* # 里 conf-dir= 指向的目录,必须按同一来源清理,不能只删 /tmp/dnsmasq.d。 for _f in /var/etc/dnsmasq.conf.*; do [ -f "$$_f" ] || continue sed -n 's/^[[:space:]]*conf-dir=//p' "$$_f" 2>/dev/null | while IFS= read -r _line; do for _d in $$_line; do _d=$${_d%%,*} while [ "$$_d" != "/" ] && [ "$${_d%/}" != "$$_d" ]; do _d=$${_d%/} done [ -n "$$_d" ] && rm -f "$$_d/isp-split.conf" 2>/dev/null || true done done done rm -f /tmp/dnsmasq.d/isp-split.conf /etc/isp-split/dnsmasq.d/isp-split.conf 2>/dev/null || true # F-14:install.sh 留下的 /etc/isp-split.conf.bak.* 与主配置一并清掉(与 teardown.sh # 同策略:默认删,逐条打印由 teardown.sh 负责;这里只兜底)。 rm -f /etc/isp-split.conf /etc/isp-split.conf.bak.* 2>/dev/null || true rm -rf /etc/isp-split 2>/dev/null || true exit 0 endef # 显式指定权限,不依赖源文件的权限位——固件里脚本不可执行会很难查 define Package/isp-split/install $(INSTALL_DIR) $(1)/usr/sbin $(INSTALL_DIR) $(1)/usr/lib/isp-split $(INSTALL_DIR) $(1)/etc/init.d $(INSTALL_DIR) $(1)/etc/uci-defaults $(INSTALL_DIR) $(1)/etc/isp-split/data $(INSTALL_BIN) $(PKG_BUILD_DIR)/files/usr/sbin/isp-split $(1)/usr/sbin/isp-split $(INSTALL_BIN) $(PKG_BUILD_DIR)/files/etc/init.d/isp-split $(1)/etc/init.d/isp-split $(INSTALL_BIN) $(PKG_BUILD_DIR)/files/usr/lib/isp-split/build.sh $(1)/usr/lib/isp-split/build.sh $(INSTALL_BIN) $(PKG_BUILD_DIR)/files/etc/uci-defaults/99-isp-split $(1)/etc/uci-defaults/99-isp-split # F-14:卸载清理的唯一实现。prerm(isp-split uninstall)与 # scripts/install.sh --uninstall 都调它;postrm 在二进制先被删掉时 # 用内联等价清单兜底(锚点由 selftest 第 21 节双向核对)。 $(INSTALL_BIN) $(PKG_BUILD_DIR)/files/usr/lib/isp-split/teardown.sh $(1)/usr/lib/isp-split/teardown.sh # 环境体检的判据实现(doctor 子命令与 tools/router-preflight.sh 共用一份)。 # 与 teardown.sh 同理:漏装 = 设备上 `isp-split doctor` 直接拒绝运行。 $(INSTALL_DATA) $(PKG_BUILD_DIR)/files/usr/lib/isp-split/doctor.sh $(1)/usr/lib/isp-split/doctor.sh $(INSTALL_DATA) $(PKG_BUILD_DIR)/files/usr/lib/isp-split/cidr2range.awk $(1)/usr/lib/isp-split/cidr2range.awk $(INSTALL_DATA) $(PKG_BUILD_DIR)/files/usr/lib/isp-split/merge.awk $(1)/usr/lib/isp-split/merge.awk $(INSTALL_DATA) $(PKG_BUILD_DIR)/files/usr/lib/isp-split/exclude.awk $(1)/usr/lib/isp-split/exclude.awk $(INSTALL_DATA) $(PKG_BUILD_DIR)/files/usr/lib/isp-split/range2cidr.awk $(1)/usr/lib/isp-split/range2cidr.awk $(INSTALL_DATA) $(PKG_BUILD_DIR)/files/usr/lib/isp-split/rules-splice.awk $(1)/usr/lib/isp-split/rules-splice.awk $(INSTALL_DATA) $(PKG_BUILD_DIR)/files/usr/lib/isp-split/badcidr.awk $(1)/usr/lib/isp-split/badcidr.awk $(INSTALL_DATA) $(PKG_BUILD_DIR)/files/usr/lib/isp-split/ispdiff.awk $(1)/usr/lib/isp-split/ispdiff.awk if [ -f $(PKG_BUILD_DIR)/files/usr/lib/isp-split/lc-run ]; then \ $(INSTALL_BIN) $(PKG_BUILD_DIR)/files/usr/lib/isp-split/lc-run $(1)/usr/lib/isp-split/lc-run; \ fi $(INSTALL_CONF) $(PKG_BUILD_DIR)/files/etc/isp-split.conf $(1)/etc/isp-split.conf endef $(eval $(call BuildPackage,isp-split))