mirror of
https://github.com/caiwx86/small-packages.git
synced 2026-11-01 00:15:13 +08:00
Compare commits
87
Commits
4ecfeaea15
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7ae707aaa6 | ||
|
|
54d5be6086 | ||
|
|
f202e2088f | ||
|
|
33877ad635 | ||
|
|
cc69bd0f95 | ||
|
|
beac9fdb5a | ||
|
|
d6b7af2a48 | ||
|
|
9c17634d78 | ||
|
|
2f8de8b88d | ||
|
|
4d8fedd7c6 | ||
|
|
a406d6528c | ||
|
|
4c2363b0c6 | ||
|
|
170f9b0957 | ||
|
|
bd061545ed | ||
|
|
617f7ca2a6 | ||
|
|
d6cc6efa77 | ||
|
|
a2da411394 | ||
|
|
daaa6d2406 | ||
|
|
4e01b07aa7 | ||
|
|
ec960a1df0 | ||
|
|
ce2c617af4 | ||
|
|
11e98dacca | ||
|
|
5c0c622001 | ||
|
|
c75ec11645 | ||
|
|
595111c0e8 | ||
|
|
1de7579d69 | ||
|
|
6ef9b7e09f | ||
|
|
880eb38e4c | ||
|
|
7a2d332eaf | ||
|
|
ba8090b29d | ||
|
|
e14489bd54 | ||
|
|
ef3dd5ef36 | ||
|
|
300b28d2ef | ||
|
|
a4813b97a5 | ||
|
|
c405cd4402 | ||
|
|
82331a7c2e | ||
|
|
7a316664d6 | ||
|
|
a1a00fc6d1 | ||
|
|
4596096d87 | ||
|
|
9f80d5fed4 | ||
|
|
511f8cbd60 | ||
|
|
43a8c343a1 | ||
|
|
dd96a29afe | ||
|
|
cb2fdad301 | ||
|
|
8e341971ff | ||
|
|
530405f036 | ||
|
|
5a3dad58e1 | ||
|
|
5b56b0238b | ||
|
|
43b8c7d729 | ||
|
|
f601b769ca | ||
|
|
d1352f3b3d | ||
|
|
855b91c0fd | ||
|
|
64e40c30b9 | ||
|
|
5f89ba5c98 | ||
|
|
5a3acab7d3 | ||
|
|
cd9aae293c | ||
|
|
384296452c | ||
|
|
bcc9ceb04a | ||
|
|
97ae9f68da | ||
|
|
7b88b273d0 | ||
|
|
8971d1aa5c | ||
|
|
ba0a17863f | ||
|
|
e8f9e08c4a | ||
|
|
5d73e6f09a | ||
|
|
6ef6eec405 | ||
|
|
45632307c8 | ||
|
|
e4cee331e9 | ||
|
|
b31a5c3878 | ||
|
|
907a158127 | ||
|
|
3d5ff73d1e | ||
|
|
e22304fb46 | ||
|
|
77395e0373 | ||
|
|
4c14ad0233 | ||
|
|
96cbd4833e | ||
|
|
d37965131a | ||
|
|
38830964e1 | ||
|
|
d695fe6395 | ||
|
|
22202d10ca | ||
|
|
098d214aef | ||
|
|
a118e282d9 | ||
|
|
f6dde6fe3d | ||
|
|
35e3e3404d | ||
|
|
f0ef5fcc0f | ||
|
|
1f8bbc1db6 | ||
|
|
dae92bde98 | ||
|
|
648031eba2 | ||
|
|
f1fdcb16b0 |
No files matched your search
@@ -88,7 +88,8 @@ jobs:
|
||||
git_clone https://github.com/kiddin9/aria2 aria2
|
||||
git_clone https://github.com/kiddin9/autoshare && mvdir autoshare
|
||||
git_clone https://github.com/kiddin9/luci-app-wizard
|
||||
git_clone https://github.com/kiddin9/openwrt-adguardhome && mvdir openwrt-adguardhome
|
||||
#git_clone https://github.com/kiddin9/openwrt-adguardhome && mvdir openwrt-adguardhome
|
||||
git_clone https://github.com/w9315273/luci-app-adguardhome
|
||||
git_clone https://github.com/kiddin9/openwrt-clouddrive2 && mvdir openwrt-clouddrive2
|
||||
git_clone https://github.com/kiddin9/openwrt-filebrowser && mvdir openwrt-filebrowser
|
||||
) &
|
||||
@@ -153,16 +154,23 @@ jobs:
|
||||
# luci-app-daed daed
|
||||
# git_sparse_clone kix https://github.com/QiuSimons/luci-app-dae \
|
||||
# luci-app-dae dae
|
||||
git_sparse_clone master https://github.com/xiaoxiao29/luci-app-adguardhome \
|
||||
AdGuardHome
|
||||
git_sparse_clone master https://github.com/kenzok8/small \
|
||||
dae daed luci-app-daede
|
||||
git_sparse_clone master https://github.com/QiuSimons/luci-app-honk \
|
||||
honk luci-app-honk
|
||||
git_sparse_clone main https://github.com/djylb/nps-openwrt \
|
||||
npc luci-app-npc
|
||||
git_sparse_clone main https://github.com/smallprogram/openwrt-ghfu \
|
||||
luci-app-ghfu
|
||||
git_clone https://github.com/svenshi/luci-app-oxidns
|
||||
git_clone https://github.com/caiwx86/openwrt-oxidns oxidns
|
||||
git_clone https://github.com/eamonxg/luci-theme-shadcn
|
||||
git_clone https://github.com/eamonxg/luci-theme-aurora
|
||||
git_clone https://github.com/eamonxg/luci-app-aurora-config
|
||||
git_clone https://github.com/VizzleTF/luci-theme-footstrap
|
||||
git_sparse_clone main https://github.com/VizzleTF/luci-theme-footstrap \
|
||||
luci-theme-footstrap
|
||||
git_clone https://github.com/sirpdboy/luci-app-chatgpt-web
|
||||
git_clone https://github.com/sirpdboy/luci-app-eqosplus
|
||||
git_sparse_clone master "https://github.com/coolsnowwolf/lede" package/wwan package/lean package/network/services/shellsync package/qca/shortcut-fe && cp -rf wwan/*/* ./ ; rm -Rf wwan
|
||||
|
||||
@@ -0,0 +1,149 @@
|
||||
#
|
||||
# Copyright (C) 2015-2016 OpenWrt.org
|
||||
#
|
||||
# This is free software, licensed under the GNU General Public License v2.
|
||||
# See /LICENSE.txt for more information.
|
||||
#
|
||||
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=AdGuardHome
|
||||
PKG_VERSION:=0.107.79
|
||||
PKG_RELEASE:=1
|
||||
|
||||
# 上游自 v0.107 起为“单二进制 + go:embed 前端”:前端由 client_v2 (npm/webpack)
|
||||
# 构建到源码根的 build/ 目录,再由 main.go 的 //go:embed build 打包进二进制。
|
||||
# 这里使用官方 codeload 源码包(比 git clone 快,且可用 PKG_HASH 校验收包)。
|
||||
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
|
||||
PKG_SOURCE_URL:=https://codeload.github.com/AdguardTeam/AdGuardHome/tar.gz/v$(PKG_VERSION)?
|
||||
PKG_HASH:=5f4fa119f24ea741bb8cecfa74203165fe6b86b904cef05ff429fb227b07d425
|
||||
PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-$(PKG_VERSION)
|
||||
|
||||
PKG_LICENSE:=GPL-3.0-only
|
||||
PKG_LICENSE_FILES:=LICENSE.txt
|
||||
PKG_MAINTAINER:=Yang Feng <yangfeng229@gmail.com>
|
||||
|
||||
PKG_CONFIG_DEPENDS:=CONFIG_ADGUARDHOME_COMPRESS_UPX
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# 工具链说明
|
||||
#
|
||||
# 本包不使用 OpenWrt 的 golang/host 与 node/host:
|
||||
# * AdGuardHome 的 go.mod 要求 go >= 1.26.6,而 OpenWrt 24.10 的 golang feed
|
||||
# 仍是 1.23.x;
|
||||
# * node/host 需要从源码编译 Node,代价极高。
|
||||
# 因此直接调用外部工具链(默认优先取容器内预装的 ~/.openwrt/tools),
|
||||
# 可用下列变量覆盖:
|
||||
# ADGH_GO Go 可执行文件(需 >= 1.26)
|
||||
# ADGH_NODE_DIR 含 node/npm 的目录
|
||||
# ADGH_NPM npm 可执行文件
|
||||
# ADGH_NPM_REGISTRY npm 源(默认 npmmirror,国内更快)
|
||||
# ADGH_GOPROXY Go 模块代理(默认 goproxy.cn)
|
||||
# 工具链准备方式见 .devcontainer/README.md。
|
||||
# ---------------------------------------------------------------------------
|
||||
ADGH_TOOLS_DIR ?= $(HOME)/.openwrt/tools
|
||||
ADGH_GO ?= $(if $(wildcard $(ADGH_TOOLS_DIR)/go/bin/go),$(ADGH_TOOLS_DIR)/go/bin/go,go)
|
||||
ADGH_NODE_DIR ?= $(if $(wildcard $(ADGH_TOOLS_DIR)/node/bin/node),$(ADGH_TOOLS_DIR)/node/bin,$(if $(wildcard /usr/bin/node),/usr/bin,/usr/local/bin))
|
||||
ADGH_NPM ?= $(ADGH_NODE_DIR)/npm
|
||||
ADGH_NPM_REGISTRY ?= https://registry.npmmirror.com
|
||||
ADGH_GOPROXY ?= https://goproxy.cn,direct
|
||||
|
||||
# OpenWrt ARCH -> GOARCH:纯 Go 交叉编译(CGO_ENABLED=0),无需 target 工具链
|
||||
ifeq ($(ARCH),x86_64)
|
||||
ADGH_GOARCH:=amd64
|
||||
else ifeq ($(ARCH),i386)
|
||||
ADGH_GOARCH:=386
|
||||
else ifneq ($(filter aarch64%,$(ARCH)),)
|
||||
ADGH_GOARCH:=arm64
|
||||
else ifneq ($(filter arm%,$(ARCH)),)
|
||||
ADGH_GOARCH:=arm
|
||||
ADGH_GOARM:=$(if $(findstring _v5,$(ARCH)),5,$(if $(findstring _v6,$(ARCH)),6,7))
|
||||
else ifneq ($(filter mips64el%,$(ARCH)),)
|
||||
ADGH_GOARCH:=mips64le
|
||||
ADGH_GOMIPS:=softfloat
|
||||
else ifneq ($(filter mipsel%,$(ARCH)),)
|
||||
ADGH_GOARCH:=mipsle
|
||||
ADGH_GOMIPS:=softfloat
|
||||
else ifneq ($(filter mips64%,$(ARCH)),)
|
||||
ADGH_GOARCH:=mips64
|
||||
ADGH_GOMIPS:=softfloat
|
||||
else ifneq ($(filter mips%,$(ARCH)),)
|
||||
ADGH_GOARCH:=mips
|
||||
ADGH_GOMIPS:=softfloat
|
||||
else ifneq ($(filter riscv64%,$(ARCH)),)
|
||||
ADGH_GOARCH:=riscv64
|
||||
else ifneq ($(filter powerpc64%,$(ARCH)),)
|
||||
ADGH_GOARCH:=ppc64
|
||||
else ifneq ($(filter powerpc%,$(ARCH)),)
|
||||
ADGH_GOARCH:=ppc
|
||||
else
|
||||
ADGH_GOARCH:=unsupported
|
||||
endif
|
||||
|
||||
ADGH_VERSION_PKG:=github.com/AdguardTeam/AdGuardHome/internal/version
|
||||
ADGH_LDFLAGS:=-s -w \
|
||||
-X $(ADGH_VERSION_PKG).version=v$(PKG_VERSION) \
|
||||
-X $(ADGH_VERSION_PKG).channel=release \
|
||||
-X $(ADGH_VERSION_PKG).committime=$(if $(SOURCE_DATE_EPOCH),$(SOURCE_DATE_EPOCH),0) \
|
||||
$(if $(ADGH_GOARM),-X $(ADGH_VERSION_PKG).goarm=$(ADGH_GOARM)) \
|
||||
$(if $(ADGH_GOMIPS),-X $(ADGH_VERSION_PKG).gomips=$(ADGH_GOMIPS))
|
||||
|
||||
include $(INCLUDE_DIR)/package.mk
|
||||
|
||||
define Package/AdGuardHome
|
||||
SECTION:=net
|
||||
CATEGORY:=Network
|
||||
TITLE:=Network-wide ads and trackers blocking DNS server
|
||||
URL:=https://github.com/AdguardTeam/AdGuardHome
|
||||
DEPENDS:=+ca-bundle
|
||||
endef
|
||||
|
||||
define Package/AdGuardHome/description
|
||||
Free and open source, powerful network-wide ads and trackers blocking DNS server.
|
||||
endef
|
||||
|
||||
define Package/$(PKG_NAME)/config
|
||||
config ADGUARDHOME_COMPRESS_UPX
|
||||
bool "Compress executable files with UPX"
|
||||
default n
|
||||
endef
|
||||
|
||||
define Build/Compile
|
||||
@if ! $(ADGH_GO) version 2>/dev/null | grep -qE 'go1\.(2[6-9]|[3-9][0-9])'; then \
|
||||
echo "ERROR: AdGuardHome $(PKG_VERSION) 需要 Go >= 1.26(go.mod 要求 1.26.6)"; \
|
||||
echo " 当前工具链: $$($(ADGH_GO) version 2>&1)"; \
|
||||
echo " 可用 ADGH_GO=/path/to/go 指定,准备方法见 .devcontainer/README.md"; \
|
||||
exit 1; \
|
||||
fi
|
||||
@echo "AdGuardHome: 构建前端 client_v2 (npm)"
|
||||
cd $(PKG_BUILD_DIR)/client_v2 && \
|
||||
PATH="$(ADGH_NODE_DIR):$(PATH)" $(ADGH_NPM) ci \
|
||||
--registry=$(ADGH_NPM_REGISTRY) --no-audit --no-fund && \
|
||||
PATH="$(ADGH_NODE_DIR):$(PATH)" $(ADGH_NPM) run build-prod
|
||||
@echo "AdGuardHome: 编译后端 (GOARCH=$(ADGH_GOARCH))"
|
||||
cd $(PKG_BUILD_DIR) && \
|
||||
CGO_ENABLED=0 GOOS=linux GOARCH=$(ADGH_GOARCH) \
|
||||
GOARM=$(ADGH_GOARM) GOMIPS=$(ADGH_GOMIPS) \
|
||||
GOPROXY=$(ADGH_GOPROXY) GOTOOLCHAIN=local \
|
||||
$(ADGH_GO) build -trimpath -ldflags "$(ADGH_LDFLAGS)" \
|
||||
-o $(PKG_BUILD_DIR)/AdGuardHome .
|
||||
ifeq ($(CONFIG_ADGUARDHOME_COMPRESS_UPX),y)
|
||||
@if [ -x $(STAGING_DIR_HOST)/bin/upx ]; then \
|
||||
$(STAGING_DIR_HOST)/bin/upx --lzma --best $(PKG_BUILD_DIR)/AdGuardHome; \
|
||||
else \
|
||||
echo "WARNING: upx 不可用,跳过压缩"; \
|
||||
fi
|
||||
endif
|
||||
endef
|
||||
|
||||
# luci 插件默认使用 /etc/config/adGuardConfig/AdGuardHome(uci: binpath),
|
||||
# 因此二进制装到该路径;/usr/bin/AdGuardHome 以符号链接提供命令行入口,
|
||||
# 避免在 ipk 里重复打包 40MB 的二进制。
|
||||
define Package/AdGuardHome/install
|
||||
$(INSTALL_DIR) $(1)/etc/config/adGuardConfig
|
||||
$(INSTALL_BIN) $(PKG_BUILD_DIR)/AdGuardHome $(1)/etc/config/adGuardConfig/AdGuardHome
|
||||
$(INSTALL_DIR) $(1)/usr/bin
|
||||
$(LN) /etc/config/adGuardConfig/AdGuardHome $(1)/usr/bin/AdGuardHome
|
||||
endef
|
||||
|
||||
$(eval $(call BuildPackage,AdGuardHome))
|
||||
+5
-2
@@ -9,7 +9,7 @@
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=brlaser
|
||||
PKG_VERSION:=v3
|
||||
PKG_VERSION:=3
|
||||
PKG_RELEASE:=1
|
||||
|
||||
PKG_SOURCE_URL:=https://github.com/pdewacht/brlaser.git
|
||||
@@ -17,11 +17,14 @@ PKG_SOURCE_PROTO:=git
|
||||
PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION)
|
||||
PKG_SOURCE_VERSION:=2a49e3287c70c254e7e3ac9dabe9d6a07218c3fa
|
||||
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)-$(PKG_SOURCE_VERSION).tar.gz
|
||||
PKG_MIRROR_HASH:=skip
|
||||
|
||||
PKG_FIXUP:=autoreconf
|
||||
|
||||
PKG_INSTALL:=1
|
||||
|
||||
# Add CMAKE_POLICY_VERSION_MINIMUM to handle CMake 3.5+ compatibility
|
||||
CMAKE_OPTIONS += -DCMAKE_POLICY_VERSION_MINIMUM=3.5
|
||||
|
||||
include $(INCLUDE_DIR)/package.mk
|
||||
include $(INCLUDE_DIR)/cmake.mk
|
||||
|
||||
|
||||
+4
-4
@@ -1,8 +1,8 @@
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=clashoo
|
||||
PKG_SHORT_SHA:=5019cc0
|
||||
PKG_COMMIT_DATE:=2026.09.19
|
||||
PKG_SHORT_SHA:=e4dd968
|
||||
PKG_COMMIT_DATE:=2026.10.08
|
||||
|
||||
PKG_VERSION:=$(PKG_COMMIT_DATE)~$(PKG_SHORT_SHA)
|
||||
PKG_RELEASE:=2
|
||||
@@ -11,8 +11,8 @@ 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:=5019cc090ed7cafb76643f964a76b1e97aee2985
|
||||
PKG_HASH:=52f127d0125a3fb8e17dc7fe48c8f01e831fbc56cf4c86d7674a11c990e71848
|
||||
PKG_SOURCE_VERSION:=e4dd968de9e10ecc6770acfafd306edeb578eb52
|
||||
PKG_HASH:=d566a425f6c87b3f0b9e252fc22df040909662ef7fc387a199203f805231bda9
|
||||
PKG_BUILD_VERSION:=alpha-$(PKG_SHORT_SHA)
|
||||
|
||||
PKG_LICENSE:=GPL3.0+
|
||||
|
||||
@@ -6,6 +6,10 @@ 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
|
||||
|
||||
@@ -67,11 +71,76 @@ _compute_start_wait() {
|
||||
fi
|
||||
}
|
||||
|
||||
# Wait up to $1 seconds for $2 (mihomo|sing-box) to be alive AND stable.
|
||||
# Returns 0 if alive at end of window, 1 if dead/never-started.
|
||||
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() {
|
||||
ubus call service list "{\"name\":\"sing-box\",\"verbose\":true}" 2>/dev/null \
|
||||
| jsonfilter -e '@["sing-box"].instances.*.pid' 2>/dev/null | head -n1
|
||||
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() {
|
||||
@@ -80,20 +149,6 @@ _singbox_running() {
|
||||
[ -n "$_pid" ] && [ -d "/proc/$_pid" ]
|
||||
}
|
||||
|
||||
_wait_core_alive() {
|
||||
local max="${1:-6}" want="${2:-mihomo}" i=0
|
||||
while [ "$i" -lt "$max" ]; do
|
||||
sleep 1
|
||||
if [ "$want" = "sing-box" ] || [ "$want" = "singbox" ]; then
|
||||
_singbox_running && return 0
|
||||
else
|
||||
_core_running && return 0
|
||||
fi
|
||||
i=$((i + 1))
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
# 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() {
|
||||
@@ -249,35 +304,46 @@ sync_legacy_core_field() {
|
||||
}
|
||||
|
||||
prepare_singbox_runtime() {
|
||||
local active src redir_port tproxy_port mixed_port dns_port
|
||||
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 /etc/sing-box /usr/share/sing-box "$(dirname "$CORE_LOG_PATH")" >/dev/null 2>&1
|
||||
rm -f /usr/share/sing-box/cache.db >/dev/null 2>&1
|
||||
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" /etc/sing-box/config.json >/dev/null 2>&1 || return 1
|
||||
elif [ ! -r /etc/sing-box/config.json ]; 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
|
||||
|
||||
# Core-only: skip clashoo normalize/takeover. Still version-migrate the
|
||||
# imported config so an older-format config (e.g. from momo/homeproxy or a
|
||||
# subscription) is accepted by the current sing-box core. The migrate is
|
||||
# idempotent — a config already in the current format is left unchanged.
|
||||
if [ "$(uci -q get clashoo.config.core_only 2>/dev/null)" = "1" ]; then
|
||||
[ -x /usr/bin/ucode ] && ucode /usr/share/clashoo/lib/migrate_singbox.uc /etc/sing-box/config.json >/dev/null 2>&1
|
||||
uci -q set sing-box.main.enabled='1'
|
||||
uci -q set sing-box.main.user='root'
|
||||
uci -q set sing-box.main.conffile='/etc/sing-box/config.json'
|
||||
uci -q set sing-box.main.workdir='/usr/share/sing-box'
|
||||
uci -q commit sing-box >/dev/null 2>&1
|
||||
return 0
|
||||
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 command -v ucode >/dev/null 2>&1; then
|
||||
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)"
|
||||
@@ -294,44 +360,31 @@ prepare_singbox_runtime() {
|
||||
# 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 \
|
||||
/etc/sing-box/config.json "$redir_port" "$tproxy_port" "$mixed_port" "$has_tun_device" "6666" "$dns_port" "$dash_port" "$dash_pass" >/dev/null 2>&1 || {
|
||||
"$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
|
||||
|
||||
uci -q set sing-box.main.enabled='1'
|
||||
uci -q set sing-box.main.user='root'
|
||||
uci -q set sing-box.main.conffile='/etc/sing-box/config.json'
|
||||
uci -q set sing-box.main.workdir='/usr/share/sing-box'
|
||||
uci -q commit sing-box >/dev/null 2>&1
|
||||
mv -f "$tmp_config" "$SINGBOX_RUNTIME_CONFIG" >/dev/null 2>&1 || {
|
||||
rm -f "$tmp_config" >/dev/null 2>&1
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
_sync_singbox_binary() {
|
||||
# Sync /usr/bin/sing-box to the dcore-selected channel (stable/alpha), coexisting via separate paths.
|
||||
local dcore src
|
||||
dcore="$(uci -q get clashoo.config.dcore 2>/dev/null)"
|
||||
case "$dcore" in
|
||||
4) src="/usr/bin/sing-box-stable" ;;
|
||||
5) src="/usr/bin/sing-box-alpha" ;;
|
||||
*) return 0 ;;
|
||||
esac
|
||||
[ -x "$src" ] || return 0
|
||||
[ "$src" -ef /usr/bin/sing-box ] && return 0
|
||||
ln -sf "$src" /usr/bin/sing-box
|
||||
}
|
||||
|
||||
start_singbox_service() {
|
||||
_sync_singbox_binary
|
||||
if [ ! -x /usr/bin/sing-box ]; then
|
||||
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 /usr/bin/sing-box -c /etc/sing-box/config.json check >> "$CORE_LOG_PATH" 2>&1
|
||||
_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)"
|
||||
@@ -344,20 +397,29 @@ start_singbox_service() {
|
||||
fi
|
||||
return 1
|
||||
fi
|
||||
/etc/init.d/sing-box start >/dev/null 2>&1
|
||||
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() {
|
||||
uci -q set sing-box.main.enabled='0' && uci -q commit sing-box >/dev/null 2>&1 || true
|
||||
|
||||
# Stop via /etc/init.d/sing-box stop (deregisters procd). Never pidof sing-box — co-installed plugins may share the binary.
|
||||
[ -x /etc/init.d/sing-box ] && /etc/init.d/sing-box stop >/dev/null 2>&1 || true
|
||||
|
||||
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
|
||||
[ -d "/proc/$_pid" ] || return 0
|
||||
_singbox_running || return 0
|
||||
sleep 1
|
||||
_wait=$((_wait + 1))
|
||||
done
|
||||
@@ -1939,9 +2001,11 @@ _finish_geo_bootstrap() {
|
||||
|
||||
|
||||
_start_validate_core() {
|
||||
local core bin
|
||||
core="$(uci -q get clashoo.config.core 2>/dev/null)"
|
||||
if is_singbox_selected; then
|
||||
if [ ! -x /usr/bin/sing-box ]; 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
|
||||
@@ -2168,10 +2232,6 @@ _start_launch_core() {
|
||||
}
|
||||
|
||||
boot(){
|
||||
# sing-box is managed by Clashoo when selected; keep its own init.d from
|
||||
# starting independently before Clashoo has prepared config/firewall/DNS.
|
||||
uci -q set sing-box.main.enabled='0' && uci -q commit sing-box >/dev/null 2>&1 || true
|
||||
|
||||
if [ "$(uci -q get clashoo.config.enable 2>/dev/null)" = "1" ]; then
|
||||
runtime_state_reset
|
||||
runtime_state_set "health_status" "starting"
|
||||
@@ -2251,15 +2311,27 @@ start_service(){
|
||||
else
|
||||
log_msg "Core-only mode: skipping firewall/DNS takeover" "仅内核模式:跳过防火墙与 DNS 接管"
|
||||
fi
|
||||
# Sync-wait: if sing-box dies within window, roll back applied state.
|
||||
# /etc/init.d/sing-box start forks immediately so we can poll here.
|
||||
if ! _wait_core_alive "$(_compute_start_wait)" sing-box; then
|
||||
# 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_died_after_apply"
|
||||
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"
|
||||
return 1
|
||||
fi
|
||||
(exec 1000>&-; runtime_run_health_check_settle >/dev/null 2>&1) &
|
||||
) &
|
||||
echo "Clashoo" > "$REAL_LOG"
|
||||
return 0
|
||||
fi
|
||||
@@ -2397,12 +2469,12 @@ reload_service()
|
||||
{
|
||||
if is_singbox_selected; then
|
||||
if _singbox_running; then
|
||||
resolve_effective_tp_modes
|
||||
runtime_state_record_preflight "singbox"
|
||||
prepare_singbox_runtime >/dev/null 2>&1
|
||||
/etc/init.d/sing-box restart >/dev/null 2>&1
|
||||
singbox_dns_change >/dev/null 2>&1
|
||||
runtime_run_health_check_settle >/dev/null 2>&1
|
||||
# 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
|
||||
|
||||
@@ -6,19 +6,15 @@ set clashoo_china6 {
|
||||
2001:250::/30,
|
||||
2001:254::/33,
|
||||
2001:255::/32,
|
||||
2001:256::/32,
|
||||
2001:678:12b8::/48,
|
||||
2001:678:12c4::/48,
|
||||
2001:678:12cc::/48,
|
||||
2001:67c:a1c::/48,
|
||||
2001:67c:ebc::/48,
|
||||
2001:67c:2c1c::/48,
|
||||
2001:7fa:5::/48,
|
||||
2001:7fa:10::/48,
|
||||
2001:c68::/32,
|
||||
2001:cc0::/32,
|
||||
2001:da8::/31,
|
||||
2001:daa::/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,
|
||||
@@ -36,64 +32,11 @@ set clashoo_china6 {
|
||||
2001:dc7:4000::/34,
|
||||
2001:dc7:8000::/33,
|
||||
2001:dd8:1::/48,
|
||||
2001:dd8:5::/48,
|
||||
2001:dd9::/48,
|
||||
2001:df0:423::/48,
|
||||
2001:df0:9c0::/48,
|
||||
2001:df0:1bc0::/48,
|
||||
2001:df0:25c0::/48,
|
||||
2001:df0:2e00::/48,
|
||||
2001:df0:2e80::/48,
|
||||
2001:df0:85c0::/48,
|
||||
2001:df0:9d40::/48,
|
||||
2001:df0:ac40::/48,
|
||||
2001:df0:bf80::/48,
|
||||
2001:df0:d880::/48,
|
||||
2001:df0:f8c0::/48,
|
||||
2001:df1:5280::/48,
|
||||
2001:df1:5b80::/48,
|
||||
2001:df1:6180::/48,
|
||||
2001:df1:d180::/48,
|
||||
2001:df1:f480::/48,
|
||||
2001:df2:5780::/48,
|
||||
2001:df2:8bc0::/48,
|
||||
2001:df2:a580::/48,
|
||||
2001:df2:c240::/48,
|
||||
2001:df2:d4c0::/48,
|
||||
2001:df3:15c0::/48,
|
||||
2001:df3:7440::/48,
|
||||
2001:df3:a680::/48,
|
||||
2001:df3:c680::/48,
|
||||
2001:df3:d0c0::/48,
|
||||
2001:df3:ef80::/48,
|
||||
2001:df4:1880::/48,
|
||||
2001:df4:2780::/48,
|
||||
2001:df4:2e80::/48,
|
||||
2001:df4:3d80::/48,
|
||||
2001:df4:4b80::/48,
|
||||
2001:df4:4d80::/48,
|
||||
2001:df4:c180::/48,
|
||||
2001:df4:c580::/48,
|
||||
2001:df4:e140::/48,
|
||||
2001:df4:e142::/47,
|
||||
2001:df5:2fc0::/48,
|
||||
2001:df5:4cc0::/48,
|
||||
2001:df5:5f80::/48,
|
||||
2001:df5:7800::/48,
|
||||
2001:df6:100::/48,
|
||||
2001:df6:5d00::/48,
|
||||
2001:df6:6800::/48,
|
||||
2001:df6:f400::/48,
|
||||
2001:df7:2b80::/48,
|
||||
2001:df7:6600::/48,
|
||||
2001:e08::/32,
|
||||
2001:e18::/32,
|
||||
2001:e80::/32,
|
||||
2001:e88::/32,
|
||||
2001:f38::/32,
|
||||
2001:f88::/32,
|
||||
2001:4438::/32,
|
||||
2001:4510::/29,
|
||||
2001:4510:400::/40,
|
||||
2001:4510:1480::/41,
|
||||
2001:4511:1480::/41,
|
||||
2400:1040::/32,
|
||||
2400:1160::/32,
|
||||
2400:12c0::/32,
|
||||
@@ -1012,6 +955,7 @@ set clashoo_china6 {
|
||||
2402:7540::/32,
|
||||
2402:75c0::/32,
|
||||
2402:7740::/32,
|
||||
2402:7820::/32,
|
||||
2402:7d00::/32,
|
||||
2402:7d80::/32,
|
||||
2402:8180::/32,
|
||||
@@ -1185,12 +1129,7 @@ set clashoo_china6 {
|
||||
2403:e80::/32,
|
||||
2403:f00::/32,
|
||||
2403:f80::/32,
|
||||
2403:fc0:400::/38,
|
||||
2403:fc0:c00::/38,
|
||||
2403:fc0:1000::/36,
|
||||
2403:fc0:2000::/35,
|
||||
2403:fc0:4000::/34,
|
||||
2403:fc0:8000::/33,
|
||||
2403:fc0::/32,
|
||||
2403:1180::/32,
|
||||
2403:1340::/32,
|
||||
2403:1440::/32,
|
||||
@@ -1291,7 +1230,6 @@ set clashoo_china6 {
|
||||
2403:4cc0::/32,
|
||||
2403:4d80::/32,
|
||||
2403:4ec0::/32,
|
||||
2403:5040::/32,
|
||||
2403:5080::/32,
|
||||
2403:5280::/32,
|
||||
2403:5380::/32,
|
||||
@@ -1317,11 +1255,10 @@ set clashoo_china6 {
|
||||
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:70::/44,
|
||||
2403:6380:80::/41,
|
||||
2403:6380:100::/40,
|
||||
2403:6380:200::/39,
|
||||
@@ -1824,7 +1761,8 @@ set clashoo_china6 {
|
||||
2405:84c0:8000::/48,
|
||||
2405:84c0:8002::/48,
|
||||
2405:84c0:8006::/48,
|
||||
2405:84c0:8008::/45,
|
||||
2405:84c0:800a::/47,
|
||||
2405:84c0:800c::/46,
|
||||
2405:84c0:8010::/48,
|
||||
2405:84c0:8019::/48,
|
||||
2405:84c0:801c::/46,
|
||||
@@ -1997,7 +1935,13 @@ set clashoo_china6 {
|
||||
2406:840:118::/45,
|
||||
2406:840:120::/43,
|
||||
2406:840:140::/42,
|
||||
2406:840:180::/41,
|
||||
2406:840:181::/48,
|
||||
2406:840:182::/47,
|
||||
2406:840:184::/46,
|
||||
2406:840:188::/45,
|
||||
2406:840:190::/44,
|
||||
2406:840:1a0::/43,
|
||||
2406:840:1c0::/42,
|
||||
2406:840:201::/48,
|
||||
2406:840:202::/47,
|
||||
2406:840:204::/46,
|
||||
@@ -2277,7 +2221,6 @@ set clashoo_china6 {
|
||||
2406:840:9103::/48,
|
||||
2406:840:9104::/46,
|
||||
2406:840:9108::/45,
|
||||
2406:840:9111::/48,
|
||||
2406:840:9112::/47,
|
||||
2406:840:9114::/46,
|
||||
2406:840:9118::/45,
|
||||
@@ -2299,7 +2242,9 @@ set clashoo_china6 {
|
||||
2406:840:9667::/48,
|
||||
2406:840:9668::/45,
|
||||
2406:840:9670::/44,
|
||||
2406:840:9680::/41,
|
||||
2406:840:9690::/44,
|
||||
2406:840:96a0::/43,
|
||||
2406:840:96c0::/42,
|
||||
2406:840:9800::/46,
|
||||
2406:840:9808::/45,
|
||||
2406:840:9810::/45,
|
||||
@@ -2316,6 +2261,7 @@ set clashoo_china6 {
|
||||
2406:840:9900::/42,
|
||||
2406:840:9940::/43,
|
||||
2406:840:9960::/47,
|
||||
2406:840:9963::/48,
|
||||
2406:840:9965::/48,
|
||||
2406:840:9968::/46,
|
||||
2406:840:996d::/48,
|
||||
@@ -2337,7 +2283,10 @@ set clashoo_china6 {
|
||||
2406:840:9fc0::/43,
|
||||
2406:840:9fe0::/44,
|
||||
2406:840:a000::/35,
|
||||
2406:840:c000::/36,
|
||||
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,
|
||||
@@ -2346,7 +2295,7 @@ set clashoo_china6 {
|
||||
2406:840:e0cc::/47,
|
||||
2406:840:e0ce::/48,
|
||||
2406:840:e0d0::/44,
|
||||
2406:840:e0e4::/46,
|
||||
2406:840:e0e6::/47,
|
||||
2406:840:e0e9::/48,
|
||||
2406:840:e0ea::/47,
|
||||
2406:840:e0ec::/46,
|
||||
@@ -2520,10 +2469,6 @@ set clashoo_china6 {
|
||||
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,
|
||||
@@ -2684,7 +2629,6 @@ set clashoo_china6 {
|
||||
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,
|
||||
@@ -3115,7 +3059,6 @@ set clashoo_china6 {
|
||||
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,
|
||||
@@ -3281,10 +3224,39 @@ set clashoo_china6 {
|
||||
2605:9d80:9042::/48,
|
||||
2605:9d80:9071::/48,
|
||||
2605:9d80:9092::/48,
|
||||
2620:57:4004::/48,
|
||||
2620:57:4004::/47,
|
||||
2804:1e48:9002::/48,
|
||||
2a03:f900::/29,
|
||||
2a04:3e00::/48,
|
||||
2a04:3e00:2::/47,
|
||||
2a04:3e00:4::/46,
|
||||
2a04:3e00:8::/45,
|
||||
2a04:3e00:10::/44,
|
||||
2a04:3e00:20::/43,
|
||||
2a04:3e00:40::/42,
|
||||
2a04:3e00:80::/41,
|
||||
2a04:3e00:100::/40,
|
||||
2a04:3e00:200::/39,
|
||||
2a04:3e00:400::/38,
|
||||
2a04:3e00:800::/37,
|
||||
2a04:3e00:1001::/48,
|
||||
2a04:3e00:1002::/48,
|
||||
2a04:3e00:1004::/46,
|
||||
2a04:3e00:1008::/45,
|
||||
2a04:3e00:1010::/44,
|
||||
2a04:3e00:1020::/43,
|
||||
2a04:3e00:1040::/42,
|
||||
2a04:3e00:1080::/41,
|
||||
2a04:3e00:1100::/40,
|
||||
2a04:3e00:1200::/39,
|
||||
2a04:3e00:1400::/38,
|
||||
2a04:3e00:1800::/37,
|
||||
2a04:3e00:2000::/35,
|
||||
2a04:3e00:4000::/34,
|
||||
2a04:3e00:8000::/33,
|
||||
2a04:3e01::/32,
|
||||
2a04:3e02::/31,
|
||||
2a04:3e04::/30,
|
||||
2a04:f580:8010::/47,
|
||||
2a04:f580:8090::/48,
|
||||
2a04:f580:8210::/47,
|
||||
@@ -3346,7 +3318,9 @@ set clashoo_china6 {
|
||||
2a0a:d681:e200::/39,
|
||||
2a0a:d681:e400::/38,
|
||||
2a0a:d681:e800::/37,
|
||||
2a0a:d681:f000::/36,
|
||||
2a0a:d681:f000::/37,
|
||||
2a0a:d681:f800::/38,
|
||||
2a0a:d681:fe00::/40,
|
||||
2a0a:d682::/33,
|
||||
2a0a:d682:8000::/34,
|
||||
2a0a:d682:c000::/36,
|
||||
|
||||
@@ -435,6 +435,7 @@ set clashoo_china {
|
||||
43.241.48.0/22,
|
||||
43.241.76.0/22,
|
||||
43.241.80.0/20,
|
||||
43.241.100.0/23,
|
||||
43.241.112.0/22,
|
||||
43.241.168.0/21,
|
||||
43.241.176.0/21,
|
||||
@@ -955,7 +956,6 @@ set clashoo_china {
|
||||
61.29.128.0/18,
|
||||
61.29.192.0/19,
|
||||
61.29.224.0/20,
|
||||
61.29.251.0/24,
|
||||
61.45.128.0/18,
|
||||
61.45.224.0/20,
|
||||
61.47.128.0/18,
|
||||
@@ -998,7 +998,6 @@ set clashoo_china {
|
||||
71.132.0.0/18,
|
||||
71.136.64.0/18,
|
||||
71.137.0.0/18,
|
||||
74.122.26.0/23,
|
||||
81.68.0.0/14,
|
||||
81.173.18.0/23,
|
||||
81.173.20.0/22,
|
||||
@@ -1906,6 +1905,7 @@ set clashoo_china {
|
||||
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,
|
||||
@@ -1956,6 +1956,7 @@ set clashoo_china {
|
||||
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,
|
||||
@@ -2325,7 +2326,6 @@ set clashoo_china {
|
||||
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,
|
||||
@@ -3063,71 +3063,7 @@ set clashoo_china {
|
||||
111.235.160.0/19,
|
||||
112.0.0.0/10,
|
||||
112.64.0.0/14,
|
||||
112.73.66.0/24,
|
||||
112.73.68.0/24,
|
||||
112.73.70.0/24,
|
||||
112.73.74.0/24,
|
||||
112.73.76.0/24,
|
||||
112.73.79.0/24,
|
||||
112.73.92.0/24,
|
||||
112.73.97.0/24,
|
||||
112.73.98.0/23,
|
||||
112.73.100.0/22,
|
||||
112.73.106.0/23,
|
||||
112.73.108.0/24,
|
||||
112.73.110.0/24,
|
||||
112.73.112.0/23,
|
||||
112.73.115.0/24,
|
||||
112.73.116.0/24,
|
||||
112.73.120.0/24,
|
||||
112.73.122.0/24,
|
||||
112.73.124.0/23,
|
||||
112.73.127.0/24,
|
||||
112.73.128.0/23,
|
||||
112.73.130.0/24,
|
||||
112.73.132.0/23,
|
||||
112.73.136.0/24,
|
||||
112.73.139.0/24,
|
||||
112.73.140.0/24,
|
||||
112.73.143.0/24,
|
||||
112.73.145.0/24,
|
||||
112.73.146.0/23,
|
||||
112.73.148.0/22,
|
||||
112.73.152.0/22,
|
||||
112.73.157.0/24,
|
||||
112.73.158.0/23,
|
||||
112.73.160.0/24,
|
||||
112.73.163.0/24,
|
||||
112.73.166.0/23,
|
||||
112.73.168.0/24,
|
||||
112.73.170.0/24,
|
||||
112.73.173.0/24,
|
||||
112.73.174.0/24,
|
||||
112.73.178.0/24,
|
||||
112.73.181.0/24,
|
||||
112.73.182.0/24,
|
||||
112.73.190.0/24,
|
||||
112.73.192.0/23,
|
||||
112.73.196.0/24,
|
||||
112.73.199.0/24,
|
||||
112.73.200.0/23,
|
||||
112.73.205.0/24,
|
||||
112.73.207.0/24,
|
||||
112.73.209.0/24,
|
||||
112.73.210.0/24,
|
||||
112.73.213.0/24,
|
||||
112.73.218.0/24,
|
||||
112.73.224.0/24,
|
||||
112.73.228.0/24,
|
||||
112.73.231.0/24,
|
||||
112.73.232.0/23,
|
||||
112.73.235.0/24,
|
||||
112.73.238.0/24,
|
||||
112.73.242.0/23,
|
||||
112.73.244.0/23,
|
||||
112.73.247.0/24,
|
||||
112.73.250.0/23,
|
||||
112.73.254.0/24,
|
||||
112.73.232.0/24,
|
||||
112.74.0.0/15,
|
||||
112.80.0.0/12,
|
||||
112.96.0.0/13,
|
||||
@@ -3413,11 +3349,11 @@ set clashoo_china {
|
||||
117.132.0.0/15,
|
||||
117.134.0.0/17,
|
||||
117.134.128.0/18,
|
||||
117.134.205.0/24,
|
||||
117.134.207.0/24,
|
||||
117.134.208.0/23,
|
||||
117.134.212.0/23,
|
||||
117.134.216.0/21,
|
||||
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,
|
||||
@@ -3769,7 +3705,6 @@ set clashoo_china {
|
||||
123.49.236.0/24,
|
||||
123.49.240.0/24,
|
||||
123.49.242.0/23,
|
||||
123.49.245.0/24,
|
||||
123.49.248.0/21,
|
||||
123.50.160.0/19,
|
||||
123.52.0.0/14,
|
||||
@@ -3907,8 +3842,6 @@ set clashoo_china {
|
||||
125.92.0.0/16,
|
||||
125.93.0.0/20,
|
||||
125.93.16.0/21,
|
||||
125.93.24.0/23,
|
||||
125.93.26.0/24,
|
||||
125.93.28.0/22,
|
||||
125.93.32.0/19,
|
||||
125.93.64.0/18,
|
||||
@@ -4032,7 +3965,6 @@ set clashoo_china {
|
||||
142.86.224.0/20,
|
||||
142.86.240.0/21,
|
||||
142.86.248.0/22,
|
||||
142.86.253.0/24,
|
||||
142.86.254.0/23,
|
||||
143.64.0.0/16,
|
||||
144.0.0.0/16,
|
||||
@@ -4077,7 +4009,8 @@ set clashoo_china {
|
||||
147.78.132.0/24,
|
||||
147.78.134.0/24,
|
||||
148.70.0.0/16,
|
||||
149.41.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,
|
||||
@@ -4258,6 +4191,7 @@ set clashoo_china {
|
||||
163.52.28.0/23,
|
||||
163.52.76.0/23,
|
||||
163.52.108.0/23,
|
||||
163.52.246.0/23,
|
||||
163.53.0.0/20,
|
||||
163.53.36.0/22,
|
||||
163.53.40.0/21,
|
||||
@@ -4469,7 +4403,6 @@ set clashoo_china {
|
||||
183.184.0.0/13,
|
||||
183.192.0.0/10,
|
||||
185.2.48.0/24,
|
||||
185.2.51.0/24,
|
||||
185.75.173.0/24,
|
||||
185.75.174.0/24,
|
||||
185.192.56.0/22,
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -153,21 +153,25 @@ resolve_via() {
|
||||
}
|
||||
|
||||
curl_subscription() {
|
||||
local url tmp hdr err ua extra_resolve http_code rc
|
||||
local url tmp hdr err ua host ip http_code rc
|
||||
url="$1"
|
||||
tmp="$2"
|
||||
hdr="$3"
|
||||
err="$4"
|
||||
ua="$5"
|
||||
extra_resolve="$6"
|
||||
host="$6"
|
||||
ip="$7"
|
||||
|
||||
rm -f "$tmp" "$hdr" "$err" >/dev/null 2>&1
|
||||
|
||||
# shellcheck disable=SC2086
|
||||
set --
|
||||
if [ -n "$host" ] && [ -n "$ip" ]; then
|
||||
set -- --resolve "$host:443:$ip" --resolve "$host:80:$ip"
|
||||
fi
|
||||
http_code="$(curl -sSL --connect-timeout 15 --max-time 60 \
|
||||
--speed-time 30 --speed-limit 1 --retry 2 \
|
||||
-H "User-Agent: ${ua}" -D "$hdr" -o "$tmp" \
|
||||
$extra_resolve \
|
||||
"$@" \
|
||||
-w '%{http_code}' "$url" 2>"$err")"
|
||||
rc=$?
|
||||
printf '%s\n' "$http_code"
|
||||
@@ -176,7 +180,7 @@ curl_subscription() {
|
||||
|
||||
download_subscription() {
|
||||
local url target tmp hdr err rc http_code info_line ua err_msg
|
||||
local host ip dns extra
|
||||
local host ip dns
|
||||
url="$1"
|
||||
target="$2"
|
||||
tmp="${TMP_PREFIX}.yaml"
|
||||
@@ -187,25 +191,27 @@ download_subscription() {
|
||||
[ -n "$ua" ] || ua="$DEFAULT_SUB_UA"
|
||||
|
||||
if command -v curl >/dev/null 2>&1; then
|
||||
http_code="$(curl_subscription "$url" "$tmp" "$hdr" "$err" "$ua" "")"
|
||||
http_code="$(curl_subscription "$url" "$tmp" "$hdr" "$err" "$ua" "" "")"
|
||||
rc=$?
|
||||
|
||||
if [ "$rc" -ne 0 ] || [ "$http_code" = "000" ]; then
|
||||
host="$(extract_host "$url")"
|
||||
case "$host" in
|
||||
''|[-.]*|*[!A-Za-z0-9.-]*) host='' ;;
|
||||
esac
|
||||
if [ -n "$host" ]; then
|
||||
for dns in 223.5.5.5 119.29.29.29 1.1.1.1 8.8.8.8; do
|
||||
ip="$(resolve_via "$host" "$dns")"
|
||||
[ -n "$ip" ] || continue
|
||||
log_update "DNS 回退:${host} -> ${ip} (@${dns})"
|
||||
extra="--resolve ${host}:443:${ip} --resolve ${host}:80:${ip}"
|
||||
http_code="$(curl_subscription "$url" "$tmp" "$hdr" "$err" "$ua" "$extra")"
|
||||
http_code="$(curl_subscription "$url" "$tmp" "$hdr" "$err" "$ua" "$host" "$ip")"
|
||||
rc=$?
|
||||
[ "$rc" -eq 0 ] && [ "$http_code" = "200" ] && break
|
||||
done
|
||||
fi
|
||||
fi
|
||||
else
|
||||
wget -q --tries=4 --timeout=20 \
|
||||
wget -q --timeout=20 \
|
||||
--user-agent="$ua" "$url" -O "$tmp" 2>"$err"
|
||||
rc=$?
|
||||
http_code=""
|
||||
|
||||
@@ -101,8 +101,25 @@ 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;
|
||||
f = trim(f || '');
|
||||
if (!length(f)) return;
|
||||
if (filter_mode == 'rule') {
|
||||
if (match(f, /,(fake-ip|real-ip)$/)) { push(cfg['dns']['fake-ip-filter'], f); return; }
|
||||
if (index(f, ',') >= 0) { push(cfg['dns']['fake-ip-filter'], f + ',real-ip'); return; }
|
||||
if (f == 'geosite:cn') { f = 'RULE-SET,cn_domain,real-ip'; need_cn_rs = true; }
|
||||
else if (match(f, /^geosite:/)) { f = 'GEOSITE,' + substr(f, 8) + ',real-ip'; }
|
||||
else if (match(f, /^rule-set:/)) {
|
||||
let rs = substr(f, 9);
|
||||
if (rs == 'cn_domain') need_cn_rs = true;
|
||||
f = 'RULE-SET,' + rs + ',real-ip';
|
||||
}
|
||||
else if (match(f, /^\+\./)) { f = 'DOMAIN-SUFFIX,' + substr(f, 2) + ',real-ip'; }
|
||||
else if (match(f, /\*/)) { f = 'DOMAIN-WILDCARD,' + f + ',real-ip'; }
|
||||
else { f = 'DOMAIN,' + f + ',real-ip'; }
|
||||
} else {
|
||||
if (f == 'geosite:cn') { f = 'rule-set:cn_domain'; need_cn_rs = true; }
|
||||
else if (f == 'rule-set:cn_domain') need_cn_rs = true;
|
||||
}
|
||||
push(cfg['dns']['fake-ip-filter'], f);
|
||||
};
|
||||
let filters = a('fake_ip_filter');
|
||||
|
||||
@@ -7,15 +7,21 @@ 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
|
||||
printf '%s' "$1" | hexdump -v -e '1/1 "%u "' | awk '
|
||||
{
|
||||
for (i = 1; i <= NF; i++) {
|
||||
b = $i + 0
|
||||
if ((b >= 48 && b <= 57) || (b >= 65 && b <= 90) ||
|
||||
(b >= 97 && b <= 122) || b == 45 || b == 46 ||
|
||||
b == 95 || b == 126)
|
||||
printf "%c", b
|
||||
else
|
||||
printf "%%%02X", b
|
||||
}
|
||||
}'
|
||||
}
|
||||
cat $HISTORY_PATH |while read line
|
||||
do
|
||||
@@ -28,4 +34,4 @@ do
|
||||
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
|
||||
fi
|
||||
@@ -58,8 +58,8 @@ fetch_text() {
|
||||
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"
|
||||
[ -n "$proxy" ] && { http_proxy="$proxy" https_proxy="$proxy" wget -qO- --timeout="$REQUEST_TIMEOUT" "$url"; return $?; }
|
||||
wget -qO- --timeout="$REQUEST_TIMEOUT" "$url"
|
||||
return $?
|
||||
fi
|
||||
return 127
|
||||
@@ -74,10 +74,10 @@ download_file() {
|
||||
return $?
|
||||
fi
|
||||
if [ -n "$proxy" ]; then
|
||||
http_proxy="$proxy" https_proxy="$proxy" wget -qO "$out" --timeout="$REQUEST_TIMEOUT" --tries=1 "$url"
|
||||
http_proxy="$proxy" https_proxy="$proxy" wget -qO "$out" --timeout="$REQUEST_TIMEOUT" "$url"
|
||||
return $?
|
||||
fi
|
||||
wget -qO "$out" --timeout="$REQUEST_TIMEOUT" --tries=1 "$url"
|
||||
wget -qO "$out" --timeout="$REQUEST_TIMEOUT" "$url"
|
||||
}
|
||||
|
||||
download_url() {
|
||||
@@ -377,7 +377,6 @@ restore_config_backup() {
|
||||
|
||||
clashoo_was_running() {
|
||||
/etc/init.d/clashoo status >/dev/null 2>&1 && return 0
|
||||
/etc/init.d/sing-box status >/dev/null 2>&1 && return 0
|
||||
return 1
|
||||
}
|
||||
|
||||
|
||||
@@ -9,6 +9,11 @@ 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
|
||||
@@ -24,6 +29,64 @@ 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
|
||||
@@ -55,6 +118,7 @@ finalize() {
|
||||
fi
|
||||
fi
|
||||
rm -f /var/run/core_update >/dev/null 2>&1
|
||||
release_core_download_lock
|
||||
}
|
||||
|
||||
timed_out() {
|
||||
@@ -112,7 +176,7 @@ fetch_url_try() {
|
||||
return $?
|
||||
fi
|
||||
if command -v wget >/dev/null 2>&1; then
|
||||
wget -qO- --timeout="$CONNECT_TIMEOUT" --no-check-certificate --user-agent="Clash/OpenWRT" "$url"
|
||||
wget -qO- --timeout="$CONNECT_TIMEOUT" --user-agent="Clash/OpenWRT" "$url"
|
||||
return $?
|
||||
fi
|
||||
return 127
|
||||
@@ -120,8 +184,12 @@ fetch_url_try() {
|
||||
|
||||
# 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).
|
||||
. /usr/share/clashoo/update/proxy_lib.sh
|
||||
detect_proxy() { clashoo_detect_proxy; }
|
||||
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"
|
||||
@@ -136,7 +204,7 @@ download_file_try() {
|
||||
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"
|
||||
wget -q --timeout="$REQUEST_TIMEOUT" --user-agent="Clash/OpenWRT" "$url" -O "$out"
|
||||
return $?
|
||||
fi
|
||||
return 127
|
||||
@@ -148,7 +216,7 @@ head_url_try() {
|
||||
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"
|
||||
wget -q --spider --timeout="$CONNECT_TIMEOUT" --user-agent="Clash/OpenWRT" "$url"
|
||||
}
|
||||
|
||||
map_mihomo_arch() {
|
||||
@@ -323,60 +391,163 @@ detect_openwrt_arch() {
|
||||
map_openwrt_arch "$MODELTYPE"
|
||||
}
|
||||
|
||||
install_singbox_openwrt_asset() {
|
||||
local pkg work rootdir
|
||||
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)" = '!<arch>' ] || 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"
|
||||
work="/tmp/singbox-openwrt-pkg"
|
||||
rootdir="/tmp/singbox-openwrt-root"
|
||||
|
||||
rm -rf "$work" "$rootdir" 2>/dev/null
|
||||
mkdir -p "$work" "$rootdir"
|
||||
|
||||
tar -xzf "$pkg" -C "$work" >/dev/null 2>&1 || return 1
|
||||
[ -f "$work/data.tar.gz" ] || return 1
|
||||
tar -xzf "$work/data.tar.gz" -C "$rootdir" >/dev/null 2>&1 || return 1
|
||||
[ -f "$rootdir/usr/bin/sing-box" ] || return 1
|
||||
|
||||
if ! install_with_rollback "$rootdir/usr/bin/sing-box" "/usr/bin/sing-box"; then
|
||||
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
|
||||
|
||||
if [ -f "$rootdir/etc/init.d/sing-box" ]; then
|
||||
cp -f "$rootdir/etc/init.d/sing-box" /etc/init.d/sing-box >/dev/null 2>&1 || true
|
||||
chmod 755 /etc/init.d/sing-box >/dev/null 2>&1 || true
|
||||
# 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
|
||||
|
||||
if [ -f "$rootdir/etc/config/sing-box" ] && [ ! -f /etc/config/sing-box ]; then
|
||||
cp -f "$rootdir/etc/config/sing-box" /etc/config/sing-box >/dev/null 2>&1 || true
|
||||
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
|
||||
|
||||
if [ -f "$rootdir/etc/sing-box/config.json" ] && [ ! -f /etc/sing-box/config.json ]; then
|
||||
mkdir -p /etc/sing-box >/dev/null 2>&1
|
||||
cp -f "$rootdir/etc/sing-box/config.json" /etc/sing-box/config.json >/dev/null 2>&1 || true
|
||||
fi
|
||||
|
||||
rm -rf "$work" "$rootdir" >/dev/null 2>&1
|
||||
return 0
|
||||
rm -rf "$rootdir" "$outer" 2>/dev/null
|
||||
return 1
|
||||
}
|
||||
|
||||
install_singbox_openwrt_apk_asset() {
|
||||
local pkg
|
||||
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"
|
||||
command -v apk >/dev/null 2>&1 || return 1
|
||||
apk add --allow-untrusted --force-overwrite "$pkg" >/dev/null 2>&1 || return 1
|
||||
[ -x /usr/bin/sing-box ] || return 1
|
||||
return 0
|
||||
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 bin
|
||||
local archive target workdir rootdir bin extract_rc rc
|
||||
archive="$1"
|
||||
rm -rf /tmp/singbox-extract >/dev/null 2>&1
|
||||
mkdir -p /tmp/singbox-extract
|
||||
tar -xzf "$archive" -C /tmp/singbox-extract >/dev/null 2>&1 || return 1
|
||||
bin="$(find /tmp/singbox-extract -name 'sing-box' -type f 2>/dev/null | head -n 1)"
|
||||
[ -n "$bin" ] || return 1
|
||||
install_with_rollback "$bin" "/usr/bin/sing-box"
|
||||
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() {
|
||||
@@ -466,7 +637,7 @@ fetch_latest_tag() {
|
||||
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)"
|
||||
tag="$(wget -S --spider --timeout="$CONNECT_TIMEOUT" --user-agent="Clash/OpenWRT" "$u" 2>&1 | sed -n 's#^ Location: .*/releases/tag/\([^[:space:]]*\).*#\1#p' | head -n 1)"
|
||||
fi
|
||||
case "$tag" in
|
||||
v*[-]*)
|
||||
@@ -513,7 +684,7 @@ fetch_latest_tag() {
|
||||
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)"
|
||||
tag="$(wget -S --spider --timeout="$CONNECT_TIMEOUT" --user-agent="Clash/OpenWRT" "$u" 2>&1 | sed -n 's#^ Location: .*/releases/tag/\([^[:space:]]*\).*#\1#p' | head -n 1)"
|
||||
fi
|
||||
[ -n "$tag" ] && { echo "$tag"; return 0; }
|
||||
|
||||
@@ -756,12 +927,25 @@ pick_mihomo_asset() {
|
||||
}
|
||||
|
||||
install_binary() {
|
||||
local src dst dir staged
|
||||
src="$1"
|
||||
dst="$2"
|
||||
mkdir -p "$(dirname "$dst")"
|
||||
rm -f "$dst"
|
||||
mv "$src" "$dst"
|
||||
chmod 755 "$dst"
|
||||
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() {
|
||||
@@ -785,6 +969,7 @@ restore_binary() {
|
||||
}
|
||||
|
||||
verify_binary() {
|
||||
local bin
|
||||
bin="$1"
|
||||
[ -x "$bin" ] || return 1
|
||||
"$bin" -v >/dev/null 2>&1 && return 0
|
||||
@@ -792,6 +977,18 @@ verify_binary() {
|
||||
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"
|
||||
@@ -801,11 +998,13 @@ installed_version_matches() {
|
||||
}
|
||||
|
||||
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"; then
|
||||
if ! verify_binary "$tmpfile" || ! verify_binary_version "$tmpfile" "$expected_version"; then
|
||||
write_log "新内核预热校验失败,保留当前内核"
|
||||
rm -f "$tmpfile" 2>/dev/null
|
||||
return 1
|
||||
@@ -822,6 +1021,18 @@ install_with_rollback() {
|
||||
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
|
||||
@@ -844,7 +1055,6 @@ 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
|
||||
trap finalize EXIT
|
||||
write_log "内核下载任务启动"
|
||||
write_log "下载架构:${MODELTYPE:-未设置}"
|
||||
|
||||
@@ -898,28 +1108,17 @@ if [ "$CORETYPE" = "4" ] || [ "$CORETYPE" = "5" ]; then
|
||||
[ -z "$TAG" ] && write_log "获取 sing-box 预发布版版本号失败" && exit 1
|
||||
fi
|
||||
VER="${TAG#v}"
|
||||
SINGBOX_TARGET="$(singbox_target_path)"
|
||||
installed=0
|
||||
|
||||
if [ -n "$OPENWRT_ARCH" ]; then
|
||||
if command -v apk >/dev/null 2>&1; then
|
||||
ASSET="sing-box_${VER}_openwrt_${OPENWRT_ARCH}.apk"
|
||||
URL="https://github.com/SagerNet/sing-box/releases/download/${TAG}/${ASSET}"
|
||||
write_log "优先尝试 OpenWrt APK 包: ${ASSET}"
|
||||
if download_with_mirrors "$URL" /tmp/singbox-openwrt.apk raw && install_singbox_openwrt_apk_asset /tmp/singbox-openwrt.apk; then
|
||||
installed=1
|
||||
else
|
||||
write_log "OpenWrt APK 包安装失败,尝试 OpenWrt IPK 包"
|
||||
fi
|
||||
fi
|
||||
if [ "$installed" -ne 1 ]; 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; then
|
||||
installed=1
|
||||
else
|
||||
write_log "OpenWrt IPK 包安装失败,尝试 tar 包兜底"
|
||||
fi
|
||||
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
|
||||
|
||||
@@ -927,7 +1126,7 @@ if [ "$CORETYPE" = "4" ] || [ "$CORETYPE" = "5" ]; 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; then
|
||||
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
|
||||
@@ -940,16 +1139,14 @@ if [ "$CORETYPE" = "4" ] || [ "$CORETYPE" = "5" ]; then
|
||||
fi
|
||||
|
||||
CORE_INSTALLED=1
|
||||
# 稳定版与 Alpha 分路径归档,避免互相覆盖;同时保留旧字段供老逻辑读
|
||||
# 稳定版与 Alpha 分路径保存,避免互相覆盖;版本文件保持兼容。
|
||||
if [ "$CORETYPE" = "4" ]; then
|
||||
cp -f /usr/bin/sing-box /usr/bin/sing-box-stable 2>/dev/null
|
||||
printf '%s\n' "$TAG" > "/usr/share/clashoo/singbox_stable_version"
|
||||
else
|
||||
cp -f /usr/bin/sing-box /usr/bin/sing-box-alpha 2>/dev/null
|
||||
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 /tmp/singbox-openwrt.apk
|
||||
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"
|
||||
|
||||
@@ -67,7 +67,7 @@ _fetch() {
|
||||
fi
|
||||
return $?
|
||||
fi
|
||||
wget -q --timeout=120 --no-check-certificate --user-agent="Clash/OpenWRT" "$url" -O "$target"
|
||||
wget -q --timeout=120 --user-agent="Clash/OpenWRT" "$url" -O "$target"
|
||||
}
|
||||
|
||||
# 多源拉取:本机代理 → 国内镜像(gh-proxy / ghfast / jsdelivr)→ 原 URL 兜底
|
||||
|
||||
@@ -22,7 +22,7 @@ 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
|
||||
wget -q --timeout=30 -U "Clash/OpenWRT" "$DOWNLOAD_URL" -O "$TMP_PATH" 2>/dev/null
|
||||
dl_rc=$?
|
||||
else
|
||||
log "No curl or wget found"
|
||||
|
||||
@@ -79,13 +79,29 @@ download_zip() {
|
||||
--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
|
||||
if wget -q --timeout=60 --user-agent="Clash/OpenWRT" "$url" -O "$ZIP_FILE"; then
|
||||
return 0
|
||||
fi
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
validate_zip_entries() {
|
||||
entries="$TMP_ROOT/entries.txt"
|
||||
if command -v unzip >/dev/null 2>&1; then
|
||||
unzip -Z1 "$ZIP_FILE" >"$entries" 2>/dev/null || return 1
|
||||
elif command -v bsdtar >/dev/null 2>&1; then
|
||||
bsdtar -tf "$ZIP_FILE" >"$entries" 2>/dev/null || return 1
|
||||
else
|
||||
return 1
|
||||
fi
|
||||
[ -s "$entries" ] || return 1
|
||||
awk '
|
||||
/^\// || /^[A-Za-z]:/ || /(^|\/)\.\.(\/|$)/ || /\\/ || /\r/ { bad = 1 }
|
||||
END { exit bad }
|
||||
' "$entries"
|
||||
}
|
||||
|
||||
extract_zip() {
|
||||
if command -v unzip >/dev/null 2>&1; then
|
||||
unzip -oq "$ZIP_FILE" -d "$UNPACK_DIR" >/dev/null 2>&1
|
||||
@@ -141,6 +157,12 @@ if ! download_zip; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! validate_zip_entries; then
|
||||
set_state "error" "压缩包路径无效"
|
||||
log_msg "Dashboard panel archive has unsafe entries" "面板压缩包含不安全路径"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
extract_zip
|
||||
extract_rc=$?
|
||||
if [ "$extract_rc" -ne 0 ]; then
|
||||
@@ -154,6 +176,12 @@ if [ "$extract_rc" -ne 0 ]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if find "$UNPACK_DIR" ! -type d ! -type f | grep -q .; then
|
||||
set_state "error" "压缩包文件类型无效"
|
||||
log_msg "Dashboard panel archive has unsafe file types" "面板压缩包含不安全文件类型"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
SRC_DIR="$(find_web_root)"
|
||||
if [ -z "$SRC_DIR" ] || [ ! -f "$SRC_DIR/index.html" ]; then
|
||||
set_state "error" "文件无效"
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
# 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
|
||||
@@ -16,7 +20,7 @@
|
||||
# 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 -> /etc/sing-box/config.json mixed inbound
|
||||
# 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)
|
||||
@@ -25,11 +29,8 @@ clashoo_running_core_type() {
|
||||
_cdp_type="$(uci -q get clashoo.config.core_type 2>/dev/null)"
|
||||
case "$_cdp_type" in
|
||||
singbox)
|
||||
# Clashoo owns this service only after it has configured the
|
||||
# packaged sing-box init script for its own runtime config.
|
||||
[ "$(uci -q get sing-box.main.conffile 2>/dev/null)" = "/etc/sing-box/config.json" ] || return 1
|
||||
_cdp_service="sing-box"
|
||||
_cdp_filter='@["sing-box"].instances.*.pid'
|
||||
_cdp_service="clashoo"
|
||||
_cdp_filter='@.clashoo.instances.singbox.pid'
|
||||
;;
|
||||
*)
|
||||
_cdp_type="mihomo"
|
||||
@@ -41,6 +42,20 @@ clashoo_running_core_type() {
|
||||
_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"
|
||||
}
|
||||
|
||||
@@ -48,7 +63,7 @@ clashoo_detect_proxy() {
|
||||
_cdp_type="$(clashoo_running_core_type)" || return 0
|
||||
_cdp_port=""
|
||||
if [ "$_cdp_type" = "singbox" ]; then
|
||||
_cdp_port="$(jsonfilter -i /etc/sing-box/config.json \
|
||||
_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
|
||||
|
||||
@@ -188,7 +188,7 @@ download_to() {
|
||||
DOWNLOAD_ERROR="$(curl_error "$last_rc")"
|
||||
return 1
|
||||
fi
|
||||
wget -q --tries=4 --timeout=20 --user-agent="$ua" "$url" -O "$out"
|
||||
wget -q --timeout=20 --user-agent="$ua" "$url" -O "$out"
|
||||
rc=$?
|
||||
[ "$rc" -eq 0 ] && return 0
|
||||
DOWNLOAD_ERROR="网络错误(wget rc=${rc})"
|
||||
@@ -209,8 +209,7 @@ update_info() {
|
||||
}
|
||||
|
||||
service_running() {
|
||||
[ -n "${CLASHOO_SERVICE_CMD:-}" ] && return 0
|
||||
"$SERVICE_CMD" status >/dev/null 2>&1
|
||||
[ "$("$SERVICE_CMD" status 2>/dev/null)" = "running" ]
|
||||
}
|
||||
|
||||
template_output_name() {
|
||||
|
||||
@@ -7,12 +7,13 @@ 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}"
|
||||
RUNTIME_STATE_FILE="${RUNTIME_STATE_FILE:-/tmp/clashoo/runtime_state}"
|
||||
PROC_ROOT="${PROC_ROOT:-/proc}"
|
||||
TMP_V4="/tmp/china_ip.txt.$$"
|
||||
TMP_V6="/tmp/china_ipv6.txt.$$"
|
||||
OUT_V4="/tmp/geoip_cn.nft.$$"
|
||||
OUT_V6="/tmp/geoip6_cn.nft.$$"
|
||||
SINGBOX_BIN_DIR="${SINGBOX_BIN_DIR:-/usr/share/clashoo/bin}"
|
||||
TMP_ROOT="$(mktemp -d /tmp/clashoo_china_ip.XXXXXX)"
|
||||
TMP_V4="$TMP_ROOT/china_ip.txt"
|
||||
TMP_V6="$TMP_ROOT/china_ipv6.txt"
|
||||
OUT_V4="$TMP_ROOT/geoip_cn.nft"
|
||||
OUT_V6="$TMP_ROOT/geoip6_cn.nft"
|
||||
|
||||
log() {
|
||||
printf ' %s - %s\n' "$(date '+%Y-%m-%d %H:%M:%S')" "$1" >> "$LOG_FILE"
|
||||
@@ -30,14 +31,14 @@ download_with_fallback() {
|
||||
local output="$2"
|
||||
local ip
|
||||
|
||||
if curl -fsSL "$url" -o "$output"; then
|
||||
if curl -fsSL --connect-timeout 10 --max-time 120 "$url" -o "$output"; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
case "$url" in
|
||||
https://ispip.clang.cn/*)
|
||||
for ip in 182.247.248.127 103.220.64.183; do
|
||||
if curl -fsSL --resolve "ispip.clang.cn:443:${ip}" "$url" -o "$output"; then
|
||||
if curl -fsSL --connect-timeout 10 --max-time 120 --resolve "ispip.clang.cn:443:${ip}" "$url" -o "$output"; then
|
||||
log "DNS 异常,已使用 --resolve(${ip}) 回源下载"
|
||||
return 0
|
||||
fi
|
||||
@@ -49,7 +50,7 @@ download_with_fallback() {
|
||||
}
|
||||
|
||||
cleanup() {
|
||||
rm -f "$TMP_V4" "$TMP_V6" "$OUT_V4" "$OUT_V6"
|
||||
rm -rf "$TMP_ROOT"
|
||||
}
|
||||
|
||||
trap cleanup EXIT INT TERM
|
||||
@@ -61,6 +62,21 @@ render_nft_set() {
|
||||
local set_type="$4"
|
||||
|
||||
awk -v set_name="$set_name" -v set_type="$set_type" '
|
||||
function valid_cidr(value, parts, octets, i, prefix) {
|
||||
if (split(value, parts, "/") != 2 || parts[2] !~ /^[0-9]+$/)
|
||||
return 0
|
||||
prefix = parts[2] + 0
|
||||
if (set_type == "ipv4_addr") {
|
||||
if (prefix > 32 || split(parts[1], octets, ".") != 4)
|
||||
return 0
|
||||
for (i = 1; i <= 4; i++)
|
||||
if (octets[i] !~ /^[0-9]+$/ || length(octets[i]) > 3 || octets[i] + 0 > 255)
|
||||
return 0
|
||||
return 1
|
||||
}
|
||||
return set_type == "ipv6_addr" && prefix <= 128 &&
|
||||
parts[1] ~ /^[0-9A-Fa-f:]+$/ && index(parts[1], ":") > 0
|
||||
}
|
||||
BEGIN {
|
||||
print "set " set_name " {"
|
||||
print "\ttype " set_type ";"
|
||||
@@ -73,6 +89,12 @@ render_nft_set() {
|
||||
gsub(/^[[:space:]]+|[[:space:]]+$/, "", $0)
|
||||
if ($0 == "")
|
||||
next
|
||||
if (!valid_cidr($0)) {
|
||||
if (!invalid)
|
||||
printf "invalid CIDR at line %d\n", NR > "/dev/stderr"
|
||||
invalid = 1
|
||||
next
|
||||
}
|
||||
if (!first)
|
||||
print ","
|
||||
printf "\t\t%s", $0
|
||||
@@ -83,8 +105,13 @@ render_nft_set() {
|
||||
print ""
|
||||
print "\t}"
|
||||
print "}"
|
||||
if (invalid || first)
|
||||
exit 1
|
||||
}
|
||||
' "$source_file" > "$output_file"
|
||||
' "$source_file" > "$output_file" || return 1
|
||||
# nft catches malformed IPv6 forms and invalid network prefixes before replacement.
|
||||
{ printf 'table inet clashoo_validate {\n'; cat "$output_file"; printf '\n}\n'; } |
|
||||
nft -c -f - >/dev/null 2>&1
|
||||
}
|
||||
|
||||
url4="$(uci -q get clashoo.config.china_ip_url 2>/dev/null || true)"
|
||||
@@ -107,7 +134,10 @@ download_with_fallback "$url4" "$TMP_V4"
|
||||
}
|
||||
changed=0
|
||||
|
||||
render_nft_set "$TMP_V4" "$OUT_V4" clashoo_china ipv4_addr
|
||||
if ! render_nft_set "$TMP_V4" "$OUT_V4" clashoo_china ipv4_addr; then
|
||||
log '大陆 IPv4 白名单包含无效 CIDR,保留原文件'
|
||||
exit 1
|
||||
fi
|
||||
if cmp -s "$OUT_V4" "$TARGET_V4"; then
|
||||
log '大陆 IPv4 白名单内容无变化'
|
||||
else
|
||||
@@ -119,7 +149,10 @@ 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 ! render_nft_set "$TMP_V6" "$OUT_V6" clashoo_china6 ipv6_addr; then
|
||||
log '大陆 IPv6 白名单包含无效 CIDR,保留原文件'
|
||||
exit 1
|
||||
fi
|
||||
if cmp -s "$OUT_V6" "$TARGET_V6"; then
|
||||
log '大陆 IPv6 白名单内容无变化'
|
||||
else
|
||||
@@ -136,29 +169,43 @@ else
|
||||
fi
|
||||
|
||||
instance_pid() {
|
||||
ubus call service list "{\"name\":\"$1\",\"verbose\":true}" 2>/dev/null |
|
||||
jsonfilter -e "@[\"$1\"].instances.*.pid" 2>/dev/null | head -n1
|
||||
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" ]
|
||||
}
|
||||
|
||||
clashoo_manages_singbox() {
|
||||
[ -r "$RUNTIME_STATE_FILE" ] || return 1
|
||||
grep -qx 'configured_core=singbox' "$RUNTIME_STATE_FILE" 2>/dev/null || return 1
|
||||
case "$(sed -n 's/^health_detail=//p' "$RUNTIME_STATE_FILE" 2>/dev/null | head -n1)" in
|
||||
service_stopped|service_disabled|boot_disabled|preflight:*|start:*) return 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
|
||||
return 0
|
||||
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
|
||||
bool_enabled "$(uci -q get sing-box.main.enabled 2>/dev/null)" || return 1
|
||||
clashoo_manages_singbox || return 1
|
||||
name="sing-box"
|
||||
name="clashoo"
|
||||
pid="$(instance_pid "$name" singbox)"
|
||||
singbox_pid_owns_private_binary "$pid"
|
||||
return $?
|
||||
else
|
||||
name="clashoo"
|
||||
fi
|
||||
|
||||
+4
-4
@@ -5,13 +5,13 @@
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=dae
|
||||
PKG_VERSION:=2026.09.20
|
||||
PKG_RELEASE:=3
|
||||
PKG_VERSION:=2026.09.24
|
||||
PKG_RELEASE:=2
|
||||
|
||||
PKG_SOURCE:=dae-src-2026.09.20-2a846ee5a7e4.tar.gz
|
||||
PKG_SOURCE:=dae-src-2026.09.24-17135da7c881.tar.gz
|
||||
PKG_SOURCE_URL:=https://github.com/kenzok8/openwrt-daede/releases/download/dae-src
|
||||
PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION)
|
||||
PKG_HASH:=2a846ee5a7e40f2548f261bc3a0a5e4b1abe0f8324fa147354f574f7c410202c
|
||||
PKG_HASH:=17135da7c881800738cc63566160d4ee6d59a8a70ae5043b8005c5d189b05752
|
||||
|
||||
PKG_LICENSE:=AGPL-3.0-only
|
||||
PKG_LICENSE_FILE:=LICENSE
|
||||
|
||||
+1
-1
@@ -20,7 +20,7 @@ start_service() {
|
||||
local config_file
|
||||
config_get config_file "config" "config_file" "/etc/dae/config.dae"
|
||||
|
||||
"$PROG" validate -c "$config_file" || return 1
|
||||
DAE_LOCATION_ASSET="/usr/share/v2ray" "$PROG" validate -c "$config_file" || return 1
|
||||
|
||||
local log_maxbackups log_maxsize
|
||||
config_get log_maxbackups "config" "log_maxbackups" "1"
|
||||
|
||||
+4
-4
@@ -5,13 +5,13 @@
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=daed
|
||||
PKG_VERSION:=2026.09.20
|
||||
PKG_RELEASE:=4
|
||||
PKG_VERSION:=2026.09.24
|
||||
PKG_RELEASE:=2
|
||||
|
||||
PKG_SOURCE:=daed-src-2026.09.20-d00211e69e94.tar.gz
|
||||
PKG_SOURCE:=daed-src-2026.09.24-527bb166b1ae.tar.gz
|
||||
PKG_SOURCE_URL:=https://github.com/kenzok8/openwrt-daede/releases/download/daed-src
|
||||
PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION)
|
||||
PKG_HASH:=d00211e69e94dba09b0f3ab67251b0dad880c7b90fbf55840d3abe576b4453c2
|
||||
PKG_HASH:=527bb166b1aea6a54330ebbc8be5b0418baed74636b838aeaa78c17b70f2f996
|
||||
|
||||
PKG_LICENSE:=AGPL-3.0-only MIT
|
||||
PKG_LICENSE_FILES:=LICENSE wing/LICENSE
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
From: kenzok8 <kenzok8@noreply>
|
||||
Date: 2026-06-23
|
||||
Subject: [PATCH] daed: detach BPF hooks when stopping from dashboard
|
||||
|
||||
Detach BPF hooks when the dashboard stops dae through EmptyConfig.
|
||||
Reported: https://github.com/kenzok8/openwrt-daede/issues/13
|
||||
---
|
||||
--- a/dae/run.go
|
||||
+++ b/dae/run.go
|
||||
@@ -138,6 +138,13 @@
|
||||
/* dae-wing start */
|
||||
newConf := newReloadMsg.Config
|
||||
/* dae-wing end */
|
||||
+
|
||||
+ // openwrt-daede: dashboard stop reloads to EmptyConfig; detach hooks.
|
||||
+ if newConf == EmptyConfig {
|
||||
+ if e := c.DetachBpfHooks(); e != nil {
|
||||
+ log.Errorln("[Stop] DetachBpfHooks:", e)
|
||||
+ }
|
||||
+ }
|
||||
// New logger.
|
||||
oldLogOutput := log.Out
|
||||
log = logrus.New()
|
||||
@@ -1,18 +0,0 @@
|
||||
From: kenzok8 <kenzok8@noreply>
|
||||
Date: 2026-06-29
|
||||
Subject: [PATCH] daed: use bounded probes for manual latency tests
|
||||
|
||||
Use the existing bounded probe for manual dashboard latency tests.
|
||||
Reported: https://github.com/kenzok8/openwrt-daede/issues/20
|
||||
---
|
||||
--- a/graphql/service/node/latency_mutation_utils.go
|
||||
+++ b/graphql/service/node/latency_mutation_utils.go
|
||||
@@ -108,7 +108,7 @@ func testSingleNodeLatency(option *diale
|
||||
}
|
||||
defer d.Close()
|
||||
|
||||
- result, err := d.ProbeLatency()
|
||||
+ result, err := d.ProbeLatencyFast()
|
||||
if err != nil {
|
||||
msg := err.Error()
|
||||
resolver.MessageV = &msg
|
||||
@@ -1,76 +1,80 @@
|
||||
From: kenzok8 <kenzok8@noreply>
|
||||
Date: 2026-09-23
|
||||
Subject: [PATCH] daed: bound startup network wait on new wing
|
||||
|
||||
Return an error after 60 seconds and retry on the next generation.
|
||||
---
|
||||
diff --git a/dae/run.go b/dae/run.go
|
||||
index d8f86c2..a0a665d 100644
|
||||
index 7c9a5cc..7f00748 100644
|
||||
--- a/dae/run.go
|
||||
+++ b/dae/run.go
|
||||
@@ -32,7 +32,8 @@ var ChReloadConfigs = make(chan *ReloadMessage)
|
||||
var GracefullyExit = make(chan struct{})
|
||||
var EmptyConfig *daeConfig.Config
|
||||
var c *control.ControlPlane
|
||||
@@ -19,6 +19,7 @@ import (
|
||||
"github.com/daeuniverse/dae/control"
|
||||
"github.com/daeuniverse/dae/pkg/config_parser"
|
||||
"github.com/daeuniverse/dae/pkg/logger"
|
||||
+ "github.com/daeuniverse/outbound/netproxy"
|
||||
"github.com/daeuniverse/outbound/protocol/direct"
|
||||
"github.com/mohae/deepcopy"
|
||||
"github.com/sirupsen/logrus"
|
||||
@@ -43,7 +44,8 @@ var EmptyConfig *daeConfig.Config
|
||||
// active is the generation currently serving traffic. It is nil before the
|
||||
// first generation is ready and while a reload has retired the old one.
|
||||
var active atomic.Pointer[control.ControlPlane]
|
||||
-var onceWaitingNetwork sync.Once
|
||||
+var waitingNetworkMu sync.Mutex
|
||||
+var networkReady bool
|
||||
|
||||
func init() {
|
||||
sections, err := config_parser.Parse(`global{} routing{}`)
|
||||
@@ -52,6 +53,19 @@ func ControlPlane() (*control.ControlPlane, error) {
|
||||
@@ -64,6 +66,19 @@ func ControlPlane() (*control.ControlPlane, error) {
|
||||
return c, nil
|
||||
}
|
||||
|
||||
+func waitForNetwork(log *logrus.Logger) error {
|
||||
+func waitForNetwork(log *logrus.Logger, directDialer netproxy.Dialer) error {
|
||||
+ waitingNetworkMu.Lock()
|
||||
+ defer waitingNetworkMu.Unlock()
|
||||
+ if networkReady {
|
||||
+ return nil
|
||||
+ }
|
||||
+ if err := WaitForNetwork(log); err != nil {
|
||||
+ if err := WaitForNetwork(log, directDialer); err != nil {
|
||||
+ return err
|
||||
+ }
|
||||
+ networkReady = true
|
||||
+ return nil
|
||||
+}
|
||||
+
|
||||
func Run(log *logrus.Logger, conf *daeConfig.Config, externGeoDataDirs []string, disableTimestamp bool, dry bool) (err error) {
|
||||
defer close(GracefullyExit)
|
||||
// Not really run dae.
|
||||
@@ -221,6 +235,9 @@ func newControlPlane(log *logrus.Logger, bpf interface{}, dnsCache map[string]*c
|
||||
|
||||
// Deep copy to prevent modification.
|
||||
conf = deepcopy.Copy(conf).(*daeConfig.Config)
|
||||
+ if bpf == nil {
|
||||
+ control.PurgeStaleTCFilters(log)
|
||||
+ }
|
||||
|
||||
// Init Direct Dialers.
|
||||
direct.InitDirectDialers(conf.Global.FallbackResolver)
|
||||
@@ -228,9 +245,9 @@ func newControlPlane(log *logrus.Logger, bpf interface{}, dnsCache map[string]*c
|
||||
// generation is one control plane with its listener. retired is set before
|
||||
// the plane is torn down so a Serve error from a plane that is being replaced
|
||||
// is not mistaken for the active datapath dying.
|
||||
@@ -345,9 +360,9 @@ func newControlPlane(log *logrus.Logger, dnsCache map[string]*control.DnsCache,
|
||||
|
||||
if !conf.Global.DisableWaitingNetwork && len(conf.Global.WanInterface) > 0 {
|
||||
// Wait for network for WAN ready.
|
||||
- onceWaitingNetwork.Do(func() {
|
||||
- WaitForNetwork(log)
|
||||
- WaitForNetwork(log, directDialers.Symmetric)
|
||||
- })
|
||||
+ if err = waitForNetwork(log); err != nil {
|
||||
+ if err = waitForNetwork(log, directDialers.Symmetric); err != nil {
|
||||
+ return nil, err
|
||||
+ }
|
||||
}
|
||||
|
||||
/// Get subscription -> nodeList mapping.
|
||||
diff --git a/dae/utils.go b/dae/utils.go
|
||||
index 65965a2..dc43cbc 100644
|
||||
index 2b4f6bf..93efb7e 100644
|
||||
--- a/dae/utils.go
|
||||
+++ b/dae/utils.go
|
||||
@@ -94,8 +94,9 @@ func preprocessWanInterfaceAuto(params *daeConfig.Config) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
-func WaitForNetwork(log *logrus.Logger) {
|
||||
+func WaitForNetwork(log *logrus.Logger) error {
|
||||
-func WaitForNetwork(log *logrus.Logger, directDialer netproxy.Dialer) {
|
||||
+func WaitForNetwork(log *logrus.Logger, directDialer netproxy.Dialer) error {
|
||||
epo := 5 * time.Second
|
||||
+ deadline := time.Now().Add(60 * time.Second)
|
||||
client := http.Client{
|
||||
Transport: &http.Transport{
|
||||
DialContext: func(ctx context.Context, network, addr string) (c net.Conn, err error) {
|
||||
@@ -115,6 +116,9 @@ func WaitForNetwork(log *logrus.Logger) {
|
||||
@@ -114,6 +115,9 @@ func WaitForNetwork(log *logrus.Logger, directDialer netproxy.Dialer) {
|
||||
}
|
||||
log.Infoln("Waiting for network...")
|
||||
for i := 0; ; i++ {
|
||||
@@ -80,7 +84,7 @@ index 65965a2..dc43cbc 100644
|
||||
resp, err := client.Get(cmd.CheckNetworkLinks[i%len(cmd.CheckNetworkLinks)])
|
||||
if err != nil {
|
||||
log.Debugln("CheckNetwork:", err)
|
||||
@@ -134,4 +138,5 @@ func WaitForNetwork(log *logrus.Logger) {
|
||||
@@ -133,4 +137,5 @@ func WaitForNetwork(log *logrus.Logger, directDialer netproxy.Dialer) {
|
||||
time.Sleep(epo)
|
||||
}
|
||||
log.Infoln("Network online.")
|
||||
|
||||
@@ -1,22 +1,9 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: kenzok8 <kenzok8@noreply>
|
||||
Date: 2026-09-23
|
||||
Subject: [PATCH] daed: strictly reconcile subscription updates
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
订阅更新按节点链接精确对账,普通组里的失效节点删除,fixed 组固定节点转成独立节点保留。
|
||||
|
||||
数据库提交后按运行状态应用配置,补齐并发地址校验、导入失败回滚和 reload 超时恢复。
|
||||
Reconcile nodes by link, preserve fixed-group nodes, and apply committed changes.
|
||||
---
|
||||
cmd/run.go | 6 +-
|
||||
graphql/mutation.go | 9 +-
|
||||
graphql/root_schema.go | 2 +-
|
||||
graphql/service/config/mutation_utils.go | 59 ++++-
|
||||
.../service/subscription/mutation_utils.go | 181 +++++++++++----
|
||||
.../subscription/mutation_utils_test.go | 212 ++++++++++++++++++
|
||||
6 files changed, 408 insertions(+), 61 deletions(-)
|
||||
create mode 100644 graphql/service/subscription/mutation_utils_test.go
|
||||
|
||||
diff --git a/cmd/run.go b/cmd/run.go
|
||||
index 7dce577..978f46c 100644
|
||||
--- a/cmd/run.go
|
||||
@@ -43,10 +30,10 @@ index 7dce577..978f46c 100644
|
||||
}
|
||||
|
||||
diff --git a/graphql/mutation.go b/graphql/mutation.go
|
||||
index fcbf440..adb747c 100644
|
||||
index af065fd..d462ecc 100644
|
||||
--- a/graphql/mutation.go
|
||||
+++ b/graphql/mutation.go
|
||||
@@ -256,14 +256,7 @@ func (r *MutationResolver) SelectConfig(args *struct {
|
||||
@@ -256,16 +256,7 @@ func (r *MutationResolver) SelectConfig(args *struct {
|
||||
func (r *MutationResolver) Run(args *struct {
|
||||
Dry bool
|
||||
}) (int32, error) {
|
||||
@@ -56,7 +43,9 @@ index fcbf440..adb747c 100644
|
||||
- tx.Rollback()
|
||||
- return 0, err
|
||||
- }
|
||||
- tx.Commit()
|
||||
- if err = tx.Commit().Error; err != nil {
|
||||
- return 0, fmt.Errorf("commit run: %w", err)
|
||||
- }
|
||||
- return ret, nil
|
||||
+ return config.Run(context.TODO(), args.Dry)
|
||||
}
|
||||
@@ -76,7 +65,7 @@ index 8b82db6..a96cace 100644
|
||||
|
||||
# updateSubscriptionLink is to update the subscription link without re-fetching nodes.
|
||||
diff --git a/graphql/service/config/mutation_utils.go b/graphql/service/config/mutation_utils.go
|
||||
index fd61554..feb94d3 100644
|
||||
index e6bf9da..8ab756b 100644
|
||||
--- a/graphql/service/config/mutation_utils.go
|
||||
+++ b/graphql/service/config/mutation_utils.go
|
||||
@@ -21,6 +21,7 @@ import (
|
||||
@@ -163,7 +152,7 @@ index fd61554..feb94d3 100644
|
||||
|
||||
// Running -> false
|
||||
diff --git a/graphql/service/subscription/mutation_utils.go b/graphql/service/subscription/mutation_utils.go
|
||||
index e55e65b..e01a342 100644
|
||||
index 7e6dc08..e87bf78 100644
|
||||
--- a/graphql/service/subscription/mutation_utils.go
|
||||
+++ b/graphql/service/subscription/mutation_utils.go
|
||||
@@ -18,6 +18,7 @@ import (
|
||||
@@ -174,7 +163,7 @@ index e55e65b..e01a342 100644
|
||||
"github.com/daeuniverse/dae-wing/graphql/service/node"
|
||||
"github.com/daeuniverse/dae/common/subscription"
|
||||
"github.com/go-co-op/gocron"
|
||||
@@ -171,8 +172,9 @@ func AutoUpdateVersionByIds(d *gorm.DB, ids []uint) (err error) {
|
||||
@@ -175,8 +176,9 @@ func AutoUpdateVersionByIds(d *gorm.DB, ids []uint) (err error) {
|
||||
}
|
||||
|
||||
var (
|
||||
@@ -186,7 +175,7 @@ index e55e65b..e01a342 100644
|
||||
)
|
||||
|
||||
func UpdateAll(ctx context.Context) {
|
||||
@@ -258,68 +260,161 @@ func Update(ctx context.Context, _id graphql.ID) (r *Resolver, err error) {
|
||||
@@ -262,68 +264,161 @@ func Update(ctx context.Context, _id graphql.ID) (r *Resolver, err error) {
|
||||
return &Resolver{Subscription: m}, nil
|
||||
}
|
||||
|
||||
@@ -212,7 +201,7 @@ index e55e65b..e01a342 100644
|
||||
- tx := db.BeginTx(ctx)
|
||||
- defer func() {
|
||||
- if err == nil {
|
||||
- tx.Commit()
|
||||
- err = tx.Commit().Error
|
||||
+ current := make(map[string]struct{}, len(existing))
|
||||
+ var staleIds []uint
|
||||
+ for _, n := range existing {
|
||||
@@ -303,7 +292,7 @@ index e55e65b..e01a342 100644
|
||||
}
|
||||
- hasAnyCandidate := false
|
||||
for _, r := range result {
|
||||
- if r.Error == nil {
|
||||
- if r.Error == nil || *r.Error == node.DuplicatedError.Error() {
|
||||
- hasAnyCandidate = true
|
||||
- break
|
||||
+ if r.Error != nil {
|
||||
@@ -388,7 +377,7 @@ index e55e65b..e01a342 100644
|
||||
return &m, nil
|
||||
}
|
||||
|
||||
@@ -399,6 +494,8 @@ func UpdateLink(ctx context.Context, _id graphql.ID, link string) (r *Resolver,
|
||||
@@ -406,6 +501,8 @@ func UpdateLink(ctx context.Context, _id graphql.ID, link string) (r *Resolver,
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -397,11 +386,11 @@ index e55e65b..e01a342 100644
|
||||
|
||||
tx := db.BeginTx(ctx)
|
||||
defer func() {
|
||||
diff --git a/graphql/service/subscription/mutation_utils_test.go b/graphql/service/subscription/mutation_utils_test.go
|
||||
diff --git a/graphql/service/subscription/reconcile_patch_test.go b/graphql/service/subscription/reconcile_patch_test.go
|
||||
new file mode 100644
|
||||
index 0000000..18ff9b9
|
||||
--- /dev/null
|
||||
+++ b/graphql/service/subscription/mutation_utils_test.go
|
||||
+++ b/graphql/service/subscription/reconcile_patch_test.go
|
||||
@@ -0,0 +1,212 @@
|
||||
+/*
|
||||
+ * SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
@@ -1,44 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
Subject: [PATCH] daed: apply subscription cron changes without restart
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
改 cron 后先提交事务再重建调度器。
|
||||
|
||||
原来在事务里就去重建,调度器另开连接读到的还是旧表达式,必须重启 daed 才生效。
|
||||
---
|
||||
graphql/service/subscription/mutation_utils.go | 12 +++++++++---
|
||||
1 file changed, 9 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/graphql/service/subscription/mutation_utils.go b/graphql/service/subscription/mutation_utils.go
|
||||
index e2aec32..4f6bcfc 100644
|
||||
--- a/graphql/service/subscription/mutation_utils.go
|
||||
+++ b/graphql/service/subscription/mutation_utils.go
|
||||
@@ -561,10 +561,12 @@ func UpdateCron(ctx context.Context, _id graphql.ID, cronExp string, cronEnable
|
||||
}
|
||||
|
||||
tx := db.BeginTx(ctx)
|
||||
+ if tx.Error != nil {
|
||||
+ return nil, tx.Error
|
||||
+ }
|
||||
+ committed := false
|
||||
defer func() {
|
||||
- if err == nil {
|
||||
- tx.Commit()
|
||||
- } else {
|
||||
+ if !committed {
|
||||
tx.Rollback()
|
||||
}
|
||||
}()
|
||||
@@ -583,6 +585,10 @@ func UpdateCron(ctx context.Context, _id graphql.ID, cronExp string, cronEnable
|
||||
}).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
+ if err = tx.Commit().Error; err != nil {
|
||||
+ return nil, err
|
||||
+ }
|
||||
+ committed = true
|
||||
|
||||
// Update scheduler
|
||||
RemoveUpdateScheduler(id)
|
||||
@@ -0,0 +1,28 @@
|
||||
From: kenzok8 <kenzok8@noreply>
|
||||
Date: 2026-09-23
|
||||
Subject: [PATCH] daed: keep reload callbacks nonblocking
|
||||
|
||||
A timed-out request must not block the daemon when reload later finishes.
|
||||
---
|
||||
diff --git a/graphql/service/config/mutation_utils.go b/graphql/service/config/mutation_utils.go
|
||||
index 5996eaa..64229e8 100644
|
||||
--- a/graphql/service/config/mutation_utils.go
|
||||
+++ b/graphql/service/config/mutation_utils.go
|
||||
@@ -298,7 +298,7 @@ func ApplyIfRunning(ctx context.Context) error {
|
||||
func runLocked(ctx context.Context, noLoad bool) (n int32, err error) {
|
||||
//// Dry run.
|
||||
if noLoad {
|
||||
- ch := make(chan error)
|
||||
+ ch := make(chan error, 1)
|
||||
reloadMsg := &dae.ReloadMessage{
|
||||
Config: dae.EmptyConfig,
|
||||
Callback: ch,
|
||||
@@ -523,7 +523,7 @@ func runLocked(ctx context.Context, noLoad bool) (n int32, err error) {
|
||||
readTx = nil
|
||||
|
||||
/// Reload with current config.
|
||||
- chReloadCallback := make(chan error)
|
||||
+ chReloadCallback := make(chan error, 1)
|
||||
reloadMsg := &dae.ReloadMessage{
|
||||
Config: c,
|
||||
Callback: chReloadCallback,
|
||||
@@ -1,837 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: kenzok8 <kenzok8@gmail.com>
|
||||
Date: Sun, 20 Sep 2026 16:59:23 +0800
|
||||
Subject: [PATCH] Adapt wing to new dae core
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
改动:适配新核心生命周期,并修复空配置停止和重载回滚。
|
||||
|
||||
原因:旧接口删除且新控制面交接流程已改变。
|
||||
---
|
||||
dae-core/config/marshal.go | 5 +
|
||||
dae/run.go | 402 +++++++++++++-----
|
||||
dae/run_handoff_test.go | 33 ++
|
||||
dae/runtime.go | 6 +-
|
||||
dae/utils.go | 9 +-
|
||||
db/node_utils.go | 3 +-
|
||||
graphql/service/config/mutation_utils.go | 9 +-
|
||||
graphql/service/node/latency_cache.go | 2 +-
|
||||
.../service/node/latency_mutation_utils.go | 59 ++-
|
||||
graphql/service/routing/resolver.go | 2 +-
|
||||
10 files changed, 415 insertions(+), 115 deletions(-)
|
||||
create mode 100644 dae/run_handoff_test.go
|
||||
|
||||
diff --git a/dae-core/config/marshal.go b/dae-core/config/marshal.go
|
||||
index f68006a..69a5325 100644
|
||||
--- a/dae-core/config/marshal.go
|
||||
+++ b/dae-core/config/marshal.go
|
||||
@@ -42,6 +42,11 @@ type Marshaller struct {
|
||||
buf bytes.Buffer
|
||||
}
|
||||
|
||||
+// Bytes returns the serialized section buffer without exposing mutable state.
|
||||
+func (m *Marshaller) Bytes() []byte {
|
||||
+ return m.buf.Bytes()
|
||||
+}
|
||||
+
|
||||
func (m *Marshaller) writeLine(depth int, line string) {
|
||||
if depth < 0 {
|
||||
depth = 0
|
||||
diff --git a/dae/run.go b/dae/run.go
|
||||
index a0a665d..96b579c 100644
|
||||
--- a/dae/run.go
|
||||
+++ b/dae/run.go
|
||||
@@ -6,6 +6,8 @@
|
||||
package dae
|
||||
|
||||
import (
|
||||
+ "context"
|
||||
+ "errors"
|
||||
"fmt"
|
||||
"net/netip"
|
||||
"runtime"
|
||||
@@ -28,6 +30,22 @@ type ReloadMessage struct {
|
||||
Callback chan<- error
|
||||
}
|
||||
|
||||
+func closeReloadResources(closers ...func() error) error {
|
||||
+ var errs error
|
||||
+ for _, closeResource := range closers {
|
||||
+ if closeResource != nil {
|
||||
+ errs = errors.Join(errs, closeResource())
|
||||
+ }
|
||||
+ }
|
||||
+ return errs
|
||||
+}
|
||||
+
|
||||
+func notifyReloadCallback(callback chan<- error, err error) {
|
||||
+ if callback != nil {
|
||||
+ callback <- err
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
var ChReloadConfigs = make(chan *ReloadMessage)
|
||||
var GracefullyExit = make(chan struct{})
|
||||
var EmptyConfig *daeConfig.Config
|
||||
@@ -77,88 +95,115 @@ func Run(log *logrus.Logger, conf *daeConfig.Config, externGeoDataDirs []string,
|
||||
case nil:
|
||||
break dryLoop
|
||||
default:
|
||||
- newConf.Callback <- nil
|
||||
+ notifyReloadCallback(newConf.Callback, nil)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// New c.
|
||||
- c, err = newControlPlane(log, nil, nil, conf, externGeoDataDirs)
|
||||
+ processSessions := control.NewSessionManager(context.Background())
|
||||
+ defer func() { _ = processSessions.Close() }()
|
||||
+ c, err = newControlPlane(context.Background(), log, nil, nil, conf, externGeoDataDirs, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
+ if err = c.AttachSessionManager(processSessions); err != nil {
|
||||
+ _ = c.Close()
|
||||
+ return err
|
||||
+ }
|
||||
+ datapathDetached := false
|
||||
+ if conf == EmptyConfig {
|
||||
+ if err = c.DetachBpfHooks(); err != nil {
|
||||
+ _ = c.Close()
|
||||
+ return fmt.Errorf("detach initial empty datapath: %w", err)
|
||||
+ }
|
||||
+ datapathDetached = true
|
||||
+ }
|
||||
|
||||
- // Serve tproxy TCP/UDP server util signals.
|
||||
var listener *control.Listener
|
||||
+ if err = control.GetDaeNetns().With(func() error {
|
||||
+ var listenErr error
|
||||
+ listener, listenErr = c.Listen(conf.Global.TproxyPort)
|
||||
+ if listenErr != nil {
|
||||
+ return listenErr
|
||||
+ }
|
||||
+ return listener.ValidateCurrentNetns()
|
||||
+ }); err != nil {
|
||||
+ if listener != nil {
|
||||
+ _ = listener.Close()
|
||||
+ }
|
||||
+ _ = c.Close()
|
||||
+ return fmt.Errorf("listen in dae netns: %w", err)
|
||||
+ }
|
||||
+ readyChan := make(chan bool, 1)
|
||||
+ serveDone := make(chan error, 1)
|
||||
+ go func() { serveDone <- c.Serve(readyChan, listener) }()
|
||||
+ if !<-readyChan {
|
||||
+ serveErr := <-serveDone
|
||||
+ _ = closeReloadResources(listener.Close, c.Close)
|
||||
+ if serveErr == nil {
|
||||
+ serveErr = fmt.Errorf("initial control plane was not ready")
|
||||
+ }
|
||||
+ return serveErr
|
||||
+ }
|
||||
+ log.Infoln("Ready")
|
||||
go func() {
|
||||
- readyChan := make(chan bool, 1)
|
||||
- go func() {
|
||||
- <-readyChan
|
||||
- log.Infoln("Ready")
|
||||
- }()
|
||||
- control.GetDaeNetns().With(func() error {
|
||||
- if listener, err = c.ListenAndServe(readyChan, conf.Global.TproxyPort); err != nil {
|
||||
- log.Errorln("ListenAndServe:", err)
|
||||
- }
|
||||
- return err
|
||||
- })
|
||||
- // Exit
|
||||
+ if serveErr := <-serveDone; serveErr != nil {
|
||||
+ log.WithError(serveErr).Errorln("control plane serve stopped")
|
||||
+ }
|
||||
ChReloadConfigs <- nil
|
||||
}()
|
||||
reloading := false
|
||||
- /* dae-wing start */
|
||||
- var errReload error
|
||||
- var chCallback chan<- error
|
||||
- /* dae-wing end */
|
||||
loop:
|
||||
for newReloadMsg := range ChReloadConfigs {
|
||||
switch newReloadMsg {
|
||||
case nil:
|
||||
- /* dae-wing start */
|
||||
- // We will receive nil after control plane being Closed.
|
||||
- // We'll judge if we are in a reloading.
|
||||
- /* dae-wing end */
|
||||
-
|
||||
if reloading {
|
||||
- if listener == nil {
|
||||
- // Failed to listen. Exit.
|
||||
- break loop
|
||||
- }
|
||||
- // Serve.
|
||||
+ // The old generation's Serve loop reports its shutdown after the
|
||||
+ // candidate has already taken over the cloned listener.
|
||||
reloading = false
|
||||
- log.Warnln("[Reload] Serve")
|
||||
- readyChan := make(chan bool, 1)
|
||||
- go func() {
|
||||
- if err := c.Serve(readyChan, listener); err != nil {
|
||||
- log.Errorln("ListenAndServe:", err)
|
||||
- }
|
||||
- // Exit
|
||||
- ChReloadConfigs <- nil
|
||||
- }()
|
||||
- <-readyChan
|
||||
- log.Warnln("[Reload] Finished")
|
||||
- /* dae-wing start */
|
||||
- chCallback <- errReload
|
||||
- /* dae-wing end */
|
||||
+ continue
|
||||
} else {
|
||||
- // Listening error.
|
||||
break loop
|
||||
}
|
||||
default:
|
||||
// Reload signal.
|
||||
log.Warnln("[Reload] Received reload signal; prepare to reload")
|
||||
|
||||
- /* dae-wing start */
|
||||
newConf := newReloadMsg.Config
|
||||
- /* dae-wing end */
|
||||
-
|
||||
- // openwrt-daede: dashboard stop reloads to EmptyConfig; detach hooks.
|
||||
- if newConf == EmptyConfig {
|
||||
- if e := c.DetachBpfHooks(); e != nil {
|
||||
- log.Errorln("[Stop] DetachBpfHooks:", e)
|
||||
+ if datapathDetached && newConf == EmptyConfig {
|
||||
+ notifyReloadCallback(newReloadMsg.Callback, nil)
|
||||
+ continue
|
||||
+ }
|
||||
+ oldC := c
|
||||
+ wasStopped := datapathDetached
|
||||
+ failReload := func(cause, cleanupErr error) error {
|
||||
+ cause = errors.Join(cause, cleanupErr)
|
||||
+ if cleanupErr == nil && wasStopped {
|
||||
+ if detachErr := oldC.DetachBpfHooks(); detachErr != nil {
|
||||
+ cause = errors.Join(cause, fmt.Errorf("restore stopped datapath: %w", detachErr))
|
||||
+ cleanupErr = detachErr
|
||||
+ } else {
|
||||
+ datapathDetached = true
|
||||
+ }
|
||||
}
|
||||
+ notifyReloadCallback(newReloadMsg.Callback, cause)
|
||||
+ if cleanupErr != nil {
|
||||
+ return cause
|
||||
+ }
|
||||
+ return nil
|
||||
}
|
||||
+ if wasStopped {
|
||||
+ if restoreErr := oldC.RestoreDatapathForReloadRollback(); restoreErr != nil {
|
||||
+ if fatalErr := failReload(fmt.Errorf("prepare stopped datapath: %w", restoreErr), nil); fatalErr != nil {
|
||||
+ return fatalErr
|
||||
+ }
|
||||
+ continue
|
||||
+ }
|
||||
+ datapathDetached = false
|
||||
+ }
|
||||
+
|
||||
// New logger.
|
||||
oldLogOutput := log.Out
|
||||
log = logrus.New()
|
||||
@@ -167,65 +212,223 @@ loop:
|
||||
log.SetOutput(oldLogOutput) // FIXME: THIS IS A HACK.
|
||||
logrus.SetOutput(oldLogOutput)
|
||||
|
||||
- // New control plane.
|
||||
- obj := c.EjectBpf()
|
||||
var dnsCache map[string]*control.DnsCache
|
||||
if conf.Dns.IpVersionPrefer == newConf.Dns.IpVersionPrefer {
|
||||
// Only keep dns cache when ip version preference not change.
|
||||
dnsCache = c.CloneDnsCache()
|
||||
}
|
||||
- log.Warnln("[Reload] Load new control plane")
|
||||
- newC, err := newControlPlane(log, obj, dnsCache, newConf, externGeoDataDirs)
|
||||
+ log.Warnln("[Reload] Prepare new control plane")
|
||||
+ freshState, err := c.SnapshotFreshDatapathState()
|
||||
if err != nil {
|
||||
- /* dae-wing start */
|
||||
- errReload = err
|
||||
- /* dae-wing end */
|
||||
-
|
||||
- log.WithFields(logrus.Fields{
|
||||
- "err": err,
|
||||
- }).Errorln("[Reload] Failed to reload; try to roll back configuration")
|
||||
- // Load last config back.
|
||||
- newC, err = newControlPlane(log, obj, dnsCache, conf, externGeoDataDirs)
|
||||
- if err != nil {
|
||||
- obj.Close()
|
||||
- c.Close()
|
||||
- log.WithFields(logrus.Fields{
|
||||
- "err": err,
|
||||
- }).Fatalln("[Reload] Failed to roll back configuration")
|
||||
+ if fatalErr := failReload(err, nil); fatalErr != nil {
|
||||
+ return fatalErr
|
||||
}
|
||||
- newConf = conf
|
||||
- log.Errorln("[Reload] Last reload failed; rolled back configuration")
|
||||
- } else {
|
||||
- log.Warnln("[Reload] Stopped old control plane")
|
||||
-
|
||||
- /* dae-wing start */
|
||||
- errReload = nil
|
||||
- /* dae-wing end */
|
||||
+ continue
|
||||
}
|
||||
+ newC, err := newControlPlane(context.Background(), log, freshState, dnsCache, newConf, externGeoDataDirs, true)
|
||||
+ if err == nil {
|
||||
+ err = newC.AttachSessionManager(processSessions)
|
||||
+ }
|
||||
+ if err != nil {
|
||||
+ var cleanupErr error
|
||||
+ if newC != nil {
|
||||
+ cleanupErr = newC.Close()
|
||||
+ }
|
||||
+ if fatalErr := failReload(err, cleanupErr); fatalErr != nil {
|
||||
+ return fatalErr
|
||||
+ }
|
||||
+ continue
|
||||
+ }
|
||||
+ stagedListener, err := listener.Clone()
|
||||
+ if err != nil {
|
||||
+ if fatalErr := failReload(fmt.Errorf("clone listener: %w", err), newC.Close()); fatalErr != nil {
|
||||
+ return fatalErr
|
||||
+ }
|
||||
+ continue
|
||||
+ }
|
||||
+ if err = oldC.StopDNSListener(); err != nil {
|
||||
+ cleanupErr := closeReloadResources(stagedListener.Close, newC.Close, oldC.RestartDNSListener)
|
||||
+ if fatalErr := failReload(fmt.Errorf("stop old DNS listener: %w", err), cleanupErr); fatalErr != nil {
|
||||
+ return fatalErr
|
||||
+ }
|
||||
+ continue
|
||||
+ }
|
||||
+ dnsStopped := true
|
||||
+ readyChan := make(chan bool, 1)
|
||||
+ serveDone := make(chan error, 1)
|
||||
+ go func() { serveDone <- newC.Serve(readyChan, stagedListener) }()
|
||||
+ ready := <-readyChan
|
||||
+ if !ready {
|
||||
+ serveErr := <-serveDone
|
||||
+ if serveErr == nil {
|
||||
+ serveErr = fmt.Errorf("prepared control plane was not ready")
|
||||
+ }
|
||||
+ cleanupErr := closeReloadResources(
|
||||
+ stagedListener.Close,
|
||||
+ newC.Close,
|
||||
+ oldC.RestartDNSListener,
|
||||
+ )
|
||||
+ dnsStopped = false
|
||||
+ if fatalErr := failReload(serveErr, cleanupErr); fatalErr != nil {
|
||||
+ return fatalErr
|
||||
+ }
|
||||
+ continue
|
||||
+ }
|
||||
+ hookPrepared := false
|
||||
+ provisionalOwner := false
|
||||
+ hookFlipCommitted := false
|
||||
+ hookSetAdopted := false
|
||||
+ flowDatapathAdopted := false
|
||||
+ rollbackCleanupFailed := false
|
||||
+ rollbackCandidate := func(cause error) error {
|
||||
+ var rollbackErr error
|
||||
+ addRollbackErr := func(err error) {
|
||||
+ if err != nil {
|
||||
+ rollbackCleanupFailed = true
|
||||
+ rollbackErr = errors.Join(rollbackErr, err)
|
||||
+ }
|
||||
+ }
|
||||
+ if flowDatapathAdopted {
|
||||
+ addRollbackErr(oldC.AdoptProcessFlowDatapath(newC))
|
||||
+ }
|
||||
+ if hookSetAdopted {
|
||||
+ if ownerErr := newC.RestorePreparedTCHookSet(oldC); ownerErr != nil {
|
||||
+ rollbackCleanupFailed = true
|
||||
+ return errors.Join(cause, rollbackErr, fmt.Errorf("restore TC HookSet owner: %w", ownerErr))
|
||||
+ }
|
||||
+ }
|
||||
+ if hookFlipCommitted {
|
||||
+ addRollbackErr(newC.RollbackPreparedBpfHookFlip())
|
||||
+ }
|
||||
+ if hookPrepared && !hookSetAdopted && !hookFlipCommitted {
|
||||
+ addRollbackErr(newC.ClearPreparedTCHookHandoff())
|
||||
+ }
|
||||
+ if provisionalOwner {
|
||||
+ newC.UnregisterProvisionalRoutingEpochExecutionOwner()
|
||||
+ }
|
||||
+ addRollbackErr(newC.DetachBpfHooks())
|
||||
+ addRollbackErr(stagedListener.Close())
|
||||
+ addRollbackErr(newC.Close())
|
||||
+ if dnsStopped {
|
||||
+ addRollbackErr(oldC.RestartDNSListener())
|
||||
+ dnsStopped = false
|
||||
+ }
|
||||
+ return errors.Join(cause, rollbackErr)
|
||||
+ }
|
||||
+ if err = newC.PrepareTCHookHandoff(oldC); err != nil {
|
||||
+ rollbackErr := rollbackCandidate(err)
|
||||
+ if rollbackCleanupFailed {
|
||||
+ notifyReloadCallback(newReloadMsg.Callback, rollbackErr)
|
||||
+ return rollbackErr
|
||||
+ }
|
||||
+ if fatalErr := failReload(rollbackErr, nil); fatalErr != nil {
|
||||
+ return fatalErr
|
||||
+ }
|
||||
+ continue
|
||||
+ }
|
||||
+ hookPrepared = true
|
||||
+ if err = newC.RegisterProvisionalRoutingEpochExecutionOwner(); err != nil {
|
||||
+ rollbackErr := rollbackCandidate(err)
|
||||
+ if rollbackCleanupFailed {
|
||||
+ notifyReloadCallback(newReloadMsg.Callback, rollbackErr)
|
||||
+ return rollbackErr
|
||||
+ }
|
||||
+ if fatalErr := failReload(rollbackErr, nil); fatalErr != nil {
|
||||
+ return fatalErr
|
||||
+ }
|
||||
+ continue
|
||||
+ }
|
||||
+ provisionalOwner = true
|
||||
+ if err = newC.CommitPreparedBpfHookFlip(); err != nil {
|
||||
+ rollbackErr := rollbackCandidate(err)
|
||||
+ if rollbackCleanupFailed {
|
||||
+ notifyReloadCallback(newReloadMsg.Callback, rollbackErr)
|
||||
+ return rollbackErr
|
||||
+ }
|
||||
+ if fatalErr := failReload(rollbackErr, nil); fatalErr != nil {
|
||||
+ return fatalErr
|
||||
+ }
|
||||
+ continue
|
||||
+ }
|
||||
+ hookFlipCommitted = true
|
||||
+ if err = newC.AdoptPreparedTCHookSet(oldC); err != nil {
|
||||
+ rollbackErr := rollbackCandidate(err)
|
||||
+ if rollbackCleanupFailed {
|
||||
+ notifyReloadCallback(newReloadMsg.Callback, rollbackErr)
|
||||
+ return rollbackErr
|
||||
+ }
|
||||
+ if fatalErr := failReload(rollbackErr, nil); fatalErr != nil {
|
||||
+ return fatalErr
|
||||
+ }
|
||||
+ continue
|
||||
+ }
|
||||
+ hookSetAdopted = true
|
||||
+ if err = newC.AdoptProcessFlowDatapath(oldC); err != nil {
|
||||
+ rollbackErr := rollbackCandidate(err)
|
||||
+ if rollbackCleanupFailed {
|
||||
+ notifyReloadCallback(newReloadMsg.Callback, rollbackErr)
|
||||
+ return rollbackErr
|
||||
+ }
|
||||
+ if fatalErr := failReload(rollbackErr, nil); fatalErr != nil {
|
||||
+ return fatalErr
|
||||
+ }
|
||||
+ continue
|
||||
+ }
|
||||
+ flowDatapathAdopted = true
|
||||
+ newC.UnregisterProvisionalRoutingEpochExecutionOwner()
|
||||
+ provisionalOwner = false
|
||||
+ if err = newC.FinalizePreparedTCHooks(); err != nil {
|
||||
+ fatalErr := errors.Join(fmt.Errorf("finalize prepared TC hooks: %w", err), closeReloadResources(
|
||||
+ listener.Close,
|
||||
+ stagedListener.Close,
|
||||
+ newC.Close,
|
||||
+ oldC.Close,
|
||||
+ ))
|
||||
+ notifyReloadCallback(newReloadMsg.Callback, fatalErr)
|
||||
+ return fatalErr
|
||||
+ }
|
||||
+ hookPrepared = false
|
||||
+ hookFlipCommitted = false
|
||||
+ hookSetAdopted = false
|
||||
|
||||
- // Inject bpf objects into the new control plane life-cycle.
|
||||
- newC.InjectBpf(obj)
|
||||
-
|
||||
- // Prepare new context.
|
||||
- oldC := c
|
||||
+ oldListener := listener
|
||||
c = newC
|
||||
conf = newConf
|
||||
+ listener = stagedListener
|
||||
+ datapathDetached = false
|
||||
+ retireErr := closeReloadResources(oldListener.Close, oldC.Close)
|
||||
+ if newConf == EmptyConfig {
|
||||
+ if retireErr != nil {
|
||||
+ fatalErr := errors.Join(fmt.Errorf("retire previous control plane: %w", retireErr), closeReloadResources(stagedListener.Close, newC.Close))
|
||||
+ notifyReloadCallback(newReloadMsg.Callback, fatalErr)
|
||||
+ return fatalErr
|
||||
+ }
|
||||
+ if detachErr := newC.DetachBpfHooks(); detachErr != nil {
|
||||
+ fatalErr := errors.Join(fmt.Errorf("detach stopped datapath: %w", detachErr), closeReloadResources(stagedListener.Close, newC.Close))
|
||||
+ notifyReloadCallback(newReloadMsg.Callback, fatalErr)
|
||||
+ return fatalErr
|
||||
+ }
|
||||
+ datapathDetached = true
|
||||
+ } else if retireErr != nil {
|
||||
+ log.WithError(retireErr).Warnln("[Reload] Failed to close old control plane")
|
||||
+ }
|
||||
reloading = true
|
||||
- /* dae-wing start */
|
||||
- chCallback = newReloadMsg.Callback
|
||||
- /* dae-wing end */
|
||||
-
|
||||
- // Ready to close.
|
||||
- oldC.Close()
|
||||
+ notifyReloadCallback(newReloadMsg.Callback, nil)
|
||||
+ go func(done <-chan error) {
|
||||
+ if serveErr := <-done; serveErr != nil {
|
||||
+ log.WithError(serveErr).Errorln("control plane serve stopped")
|
||||
+ }
|
||||
+ ChReloadConfigs <- nil
|
||||
+ }(serveDone)
|
||||
}
|
||||
}
|
||||
- if e := c.Close(); e != nil {
|
||||
+ if e := closeReloadResources(listener.Close, c.Close); e != nil {
|
||||
return fmt.Errorf("close control plane: %w", e)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
-func newControlPlane(log *logrus.Logger, bpf interface{}, dnsCache map[string]*control.DnsCache, conf *daeConfig.Config, externGeoDataDirs []string) (c *control.ControlPlane, err error) {
|
||||
+func newControlPlane(ctx context.Context, log *logrus.Logger, bpf interface{}, dnsCache map[string]*control.DnsCache, conf *daeConfig.Config, externGeoDataDirs []string, prepared bool) (c *control.ControlPlane, err error) {
|
||||
|
||||
// Print configuration.
|
||||
if log.IsLevelEnabled(logrus.DebugLevel) {
|
||||
@@ -239,10 +442,6 @@ func newControlPlane(log *logrus.Logger, bpf interface{}, dnsCache map[string]*c
|
||||
control.PurgeStaleTCFilters(log)
|
||||
}
|
||||
|
||||
- // Init Direct Dialers.
|
||||
- direct.InitDirectDialers(conf.Global.FallbackResolver)
|
||||
- netutils.FallbackDns = netip.MustParseAddrPort(conf.Global.FallbackResolver)
|
||||
-
|
||||
if !conf.Global.DisableWaitingNetwork && len(conf.Global.WanInterface) > 0 {
|
||||
// Wait for network for WAN ready.
|
||||
if err = waitForNetwork(log); err != nil {
|
||||
@@ -266,7 +465,10 @@ func newControlPlane(log *logrus.Logger, bpf interface{}, dnsCache map[string]*c
|
||||
}
|
||||
|
||||
// New dae control plane.
|
||||
- c, err = control.NewControlPlane(
|
||||
+ directDialers := direct.NewDirectDialers(conf.Global.FallbackResolver)
|
||||
+ systemDNSResolver := netutils.NewSystemDNSResolver(netip.MustParseAddrPort(conf.Global.FallbackResolver))
|
||||
+ c, err = control.NewControlPlaneWithContextOptions(
|
||||
+ ctx,
|
||||
log,
|
||||
bpf,
|
||||
dnsCache,
|
||||
@@ -276,6 +478,14 @@ func newControlPlane(log *logrus.Logger, bpf interface{}, dnsCache map[string]*c
|
||||
&conf.Global,
|
||||
&conf.Dns,
|
||||
externGeoDataDirs,
|
||||
+ control.ControlPlaneBuildOptions{
|
||||
+ DelayDatapathCommit: prepared,
|
||||
+ DelayDNSListenerStart: prepared,
|
||||
+ IsReload: prepared || bpf != nil,
|
||||
+ DirectDialer: directDialers.Symmetric,
|
||||
+ FullconeDirectDialer: directDialers.Fullcone,
|
||||
+ SystemDNSResolver: systemDNSResolver,
|
||||
+ },
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
diff --git a/dae/run_handoff_test.go b/dae/run_handoff_test.go
|
||||
new file mode 100644
|
||||
index 0000000..0ffb2ec
|
||||
--- /dev/null
|
||||
+++ b/dae/run_handoff_test.go
|
||||
@@ -0,0 +1,33 @@
|
||||
+package dae
|
||||
+
|
||||
+import (
|
||||
+ "errors"
|
||||
+ "reflect"
|
||||
+ "testing"
|
||||
+)
|
||||
+
|
||||
+func TestCloseReloadResourcesOrder(t *testing.T) {
|
||||
+ var got []string
|
||||
+ err := closeReloadResources(
|
||||
+ func() error { got = append(got, "old-listener"); return nil },
|
||||
+ func() error { got = append(got, "staged-listener"); return nil },
|
||||
+ func() error { got = append(got, "new-control-plane"); return nil },
|
||||
+ func() error { got = append(got, "old-control-plane"); return nil },
|
||||
+ )
|
||||
+ if err != nil {
|
||||
+ t.Fatalf("closeReloadResources() error = %v", err)
|
||||
+ }
|
||||
+ want := []string{"old-listener", "staged-listener", "new-control-plane", "old-control-plane"}
|
||||
+ if !reflect.DeepEqual(got, want) {
|
||||
+ t.Fatalf("close order = %v, want %v", got, want)
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+func TestCloseReloadResourcesJoinsErrors(t *testing.T) {
|
||||
+ one := errors.New("old listener")
|
||||
+ two := errors.New("old control plane")
|
||||
+ err := closeReloadResources(func() error { return one }, func() error { return two })
|
||||
+ if !errors.Is(err, one) || !errors.Is(err, two) {
|
||||
+ t.Fatalf("joined error = %v, want both close errors", err)
|
||||
+ }
|
||||
+}
|
||||
diff --git a/dae/runtime.go b/dae/runtime.go
|
||||
index 2ab0d68..af46089 100644
|
||||
--- a/dae/runtime.go
|
||||
+++ b/dae/runtime.go
|
||||
@@ -30,18 +30,16 @@ type RuntimeOverview struct {
|
||||
}
|
||||
|
||||
func GetRuntimeOverview(windowSec int, maxPoints int) (*RuntimeOverview, error) {
|
||||
- activeTCPConnections := 0
|
||||
ctl, err := ControlPlane()
|
||||
+ var snapshot control.RuntimeStatsSnapshot
|
||||
if err != nil {
|
||||
if !errors.Is(err, ErrControlPlaneNotInit) {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
- activeTCPConnections = ctl.ActiveTCPConnections()
|
||||
+ snapshot = ctl.SnapshotRuntimeStats(windowSec, maxPoints)
|
||||
}
|
||||
|
||||
- snapshot := control.SnapshotRuntimeStats(activeTCPConnections, control.DefaultUdpEndpointPool.Count(), windowSec, maxPoints)
|
||||
-
|
||||
samples := make([]RuntimeTrafficSample, 0, len(snapshot.Samples))
|
||||
for _, sample := range snapshot.Samples {
|
||||
samples = append(samples, RuntimeTrafficSample{
|
||||
diff --git a/dae/utils.go b/dae/utils.go
|
||||
index dc43cbc..ca61c85 100644
|
||||
--- a/dae/utils.go
|
||||
+++ b/dae/utils.go
|
||||
@@ -32,8 +32,11 @@ var (
|
||||
EmptyGlobalSection = `global {}`
|
||||
)
|
||||
|
||||
-func NecessaryOutbounds(routing *daeConfig.Routing) (outbounds []string) {
|
||||
- f := daeConfig.FunctionOrStringToFunction(routing.Fallback)
|
||||
+func NecessaryOutbounds(routing *daeConfig.Routing) (outbounds []string, err error) {
|
||||
+ f, err := daeConfig.ParseFunctionOrString(routing.Fallback)
|
||||
+ if err != nil {
|
||||
+ return nil, err
|
||||
+ }
|
||||
outbounds = append(outbounds, f.Name)
|
||||
for _, r := range routing.Rules {
|
||||
outbound := r.Outbound.Name
|
||||
@@ -42,7 +45,7 @@ func NecessaryOutbounds(routing *daeConfig.Routing) (outbounds []string) {
|
||||
}
|
||||
outbounds = append(outbounds, outbound)
|
||||
}
|
||||
- return daeCommon.Deduplicate(outbounds)
|
||||
+ return daeCommon.Deduplicate(outbounds), nil
|
||||
}
|
||||
|
||||
func ParseConfig(globalSection *string, dnsSection *string, routingSection *string) (*daeConfig.Config, error) {
|
||||
diff --git a/db/node_utils.go b/db/node_utils.go
|
||||
index b7b43b8..7ca8fc3 100644
|
||||
--- a/db/node_utils.go
|
||||
+++ b/db/node_utils.go
|
||||
@@ -6,6 +6,7 @@
|
||||
package db
|
||||
|
||||
import (
|
||||
+ "context"
|
||||
"strings"
|
||||
|
||||
"github.com/daeuniverse/dae-wing/common"
|
||||
@@ -25,7 +26,7 @@ func NewNodeModel(link string, tag *string, subscriptionId *uint) (*Node, error)
|
||||
}
|
||||
_tag = *tag
|
||||
}
|
||||
- d, err := dialer.NewFromLink(&dialer.GlobalOption{
|
||||
+ d, err := dialer.NewFromLinkContext(context.Background(), &dialer.GlobalOption{
|
||||
Log: logrus.StandardLogger(),
|
||||
}, dialer.InstanceOption{DisableCheck: false}, link, _tag)
|
||||
if err != nil {
|
||||
diff --git a/graphql/service/config/mutation_utils.go b/graphql/service/config/mutation_utils.go
|
||||
index 59f0ebd..c7d6b78 100644
|
||||
--- a/graphql/service/config/mutation_utils.go
|
||||
+++ b/graphql/service/config/mutation_utils.go
|
||||
@@ -298,7 +298,7 @@ func ApplyIfRunning(ctx context.Context) error {
|
||||
func runLocked(ctx context.Context, noLoad bool) (n int32, err error) {
|
||||
//// Dry run.
|
||||
if noLoad {
|
||||
- ch := make(chan error)
|
||||
+ ch := make(chan error, 1)
|
||||
reloadMsg := &dae.ReloadMessage{
|
||||
Config: dae.EmptyConfig,
|
||||
Callback: ch,
|
||||
@@ -384,7 +384,10 @@ func runLocked(ctx context.Context, noLoad bool) (n int32, err error) {
|
||||
}
|
||||
/// Fill in necessary groups and nodes.
|
||||
// Find groups needed by routing.
|
||||
- outbounds := dae.NecessaryOutbounds(&c.Routing)
|
||||
+ outbounds, err := dae.NecessaryOutbounds(&c.Routing)
|
||||
+ if err != nil {
|
||||
+ return 0, err
|
||||
+ }
|
||||
var groups []db.Group
|
||||
q = d.Model(&db.Group{}).
|
||||
Where("name in ?", outbounds).
|
||||
@@ -523,7 +526,7 @@ func runLocked(ctx context.Context, noLoad bool) (n int32, err error) {
|
||||
readTx = nil
|
||||
|
||||
/// Reload with current config.
|
||||
- chReloadCallback := make(chan error)
|
||||
+ chReloadCallback := make(chan error, 1)
|
||||
reloadMsg := &dae.ReloadMessage{
|
||||
Config: c,
|
||||
Callback: chReloadCallback,
|
||||
diff --git a/graphql/service/node/latency_cache.go b/graphql/service/node/latency_cache.go
|
||||
index ba66794..e0ec91e 100644
|
||||
--- a/graphql/service/node/latency_cache.go
|
||||
+++ b/graphql/service/node/latency_cache.go
|
||||
@@ -162,7 +162,7 @@ func refreshLatencyCache(ctx context.Context) error {
|
||||
return err
|
||||
}
|
||||
|
||||
- results := testLatencyResultsForNodes(option, nodes)
|
||||
+ results := testLatencyResultsForNodes(ctx, option, nodes)
|
||||
storeLatencyResults(results)
|
||||
|
||||
if ctl, err := dae.ControlPlane(); err == nil {
|
||||
diff --git a/graphql/service/node/latency_mutation_utils.go b/graphql/service/node/latency_mutation_utils.go
|
||||
index 056f9fa..5026b33 100644
|
||||
--- a/graphql/service/node/latency_mutation_utils.go
|
||||
+++ b/graphql/service/node/latency_mutation_utils.go
|
||||
@@ -8,6 +8,8 @@ package node
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
+ "net/netip"
|
||||
+ "strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
@@ -15,6 +17,7 @@ import (
|
||||
"github.com/daeuniverse/dae-wing/dae"
|
||||
"github.com/daeuniverse/dae-wing/db"
|
||||
dialer "github.com/daeuniverse/dae/component/outbound/dialer"
|
||||
+ "github.com/daeuniverse/outbound/netproxy"
|
||||
"github.com/graph-gophers/graphql-go"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
@@ -32,12 +35,12 @@ func TestLatencies(ctx context.Context, ids *[]graphql.ID) ([]*LatencyResolver,
|
||||
return nil, err
|
||||
}
|
||||
|
||||
- results := testLatencyResultsForNodes(option, nodes)
|
||||
+ results := testLatencyResultsForNodes(ctx, option, nodes)
|
||||
storeLatencyResults(results)
|
||||
return results, nil
|
||||
}
|
||||
|
||||
-func testLatencyResultsForNodes(option *dialer.GlobalOption, nodes []db.Node) []*LatencyResolver {
|
||||
+func testLatencyResultsForNodes(ctx context.Context, option *dialer.GlobalOption, nodes []db.Node) []*LatencyResolver {
|
||||
results := make([]*LatencyResolver, len(nodes))
|
||||
sem := make(chan struct{}, latencyProbeConcurrency)
|
||||
var wg sync.WaitGroup
|
||||
@@ -51,7 +54,7 @@ func testLatencyResultsForNodes(option *dialer.GlobalOption, nodes []db.Node) []
|
||||
defer func() { <-sem }()
|
||||
|
||||
node := nodes[index]
|
||||
- results[index] = testSingleNodeLatency(option, &node)
|
||||
+ results[index] = testSingleNodeLatency(ctx, option, &node)
|
||||
}()
|
||||
}
|
||||
|
||||
@@ -93,14 +96,14 @@ func latencyProbeNodes(ctx context.Context, ids *[]graphql.ID) ([]db.Node, error
|
||||
return nodes, nil
|
||||
}
|
||||
|
||||
-func testSingleNodeLatency(option *dialer.GlobalOption, node *db.Node) *LatencyResolver {
|
||||
+func testSingleNodeLatency(ctx context.Context, option *dialer.GlobalOption, node *db.Node) *LatencyResolver {
|
||||
resolver := &LatencyResolver{
|
||||
NodeID: node.ID,
|
||||
AliveVal: false,
|
||||
TestedAtV: time.Now(),
|
||||
}
|
||||
|
||||
- d, err := dialer.NewFromLink(option, dialer.InstanceOption{DisableCheck: false}, node.Link, "")
|
||||
+ d, err := dialer.NewFromLinkContext(ctx, option, dialer.InstanceOption{DisableCheck: false}, node.Link, "")
|
||||
if err != nil {
|
||||
msg := err.Error()
|
||||
resolver.MessageV = &msg
|
||||
@@ -108,7 +111,7 @@ func testSingleNodeLatency(option *dialer.GlobalOption, node *db.Node) *LatencyR
|
||||
}
|
||||
defer d.Close()
|
||||
|
||||
- result, err := d.ProbeLatencyFast()
|
||||
+ result, err := probeLatencyFast(ctx, d)
|
||||
if err != nil {
|
||||
msg := err.Error()
|
||||
resolver.MessageV = &msg
|
||||
@@ -128,3 +131,47 @@ func testSingleNodeLatency(option *dialer.GlobalOption, node *db.Node) *LatencyR
|
||||
}
|
||||
return resolver
|
||||
}
|
||||
+
|
||||
+func probeLatencyFast(ctx context.Context, d *dialer.Dialer) (*dialer.LatencyProbeResult, error) {
|
||||
+ opt, err := d.TcpCheckOptionRaw.Option()
|
||||
+ if err != nil {
|
||||
+ return nil, err
|
||||
+ }
|
||||
+ network, err := netproxy.ParseMagicNetwork(d.TcpCheckOptionRaw.ResolverNetwork)
|
||||
+ if err != nil {
|
||||
+ return nil, err
|
||||
+ }
|
||||
+ result := &dialer.LatencyProbeResult{CheckedAt: time.Now()}
|
||||
+ var messages []string
|
||||
+ for _, probe := range []struct {
|
||||
+ index int
|
||||
+ ip netip.Addr
|
||||
+ }{
|
||||
+ {index: dialer.IdxTcp4, ip: opt.Ip4},
|
||||
+ {index: dialer.IdxTcp6, ip: opt.Ip6},
|
||||
+ } {
|
||||
+ if !probe.ip.IsValid() {
|
||||
+ continue
|
||||
+ }
|
||||
+ probeCtx, cancel := context.WithTimeout(ctx, 1500*time.Millisecond)
|
||||
+ started := time.Now()
|
||||
+ ok, probeErr := d.HttpCheck(probeCtx, probe.index, opt.Url, probe.ip, opt.Method, network.Mark, network.Mptcp)
|
||||
+ cancel()
|
||||
+ if ok {
|
||||
+ latency := time.Since(started)
|
||||
+ if !result.Alive || latency < result.Latency {
|
||||
+ result.Latency = latency
|
||||
+ }
|
||||
+ result.Alive = true
|
||||
+ } else if probeErr != nil {
|
||||
+ messages = append(messages, probeErr.Error())
|
||||
+ }
|
||||
+ }
|
||||
+ if !result.Alive {
|
||||
+ result.Message = strings.Join(messages, "; ")
|
||||
+ if result.Message == "" {
|
||||
+ result.Message = "no latency result"
|
||||
+ }
|
||||
+ }
|
||||
+ return result, nil
|
||||
+}
|
||||
diff --git a/graphql/service/routing/resolver.go b/graphql/service/routing/resolver.go
|
||||
index 7822d64..3ed61aa 100644
|
||||
--- a/graphql/service/routing/resolver.go
|
||||
+++ b/graphql/service/routing/resolver.go
|
||||
@@ -41,7 +41,7 @@ func (r *Resolver) Selected() bool {
|
||||
return r.Model.Selected
|
||||
}
|
||||
|
||||
-func (r *Resolver) ReferenceGroups() (outbounds []string) {
|
||||
+func (r *Resolver) ReferenceGroups() (outbounds []string, err error) {
|
||||
return dae.NecessaryOutbounds(r.DaeRouting)
|
||||
}
|
||||
|
||||
+2
-2
@@ -1,12 +1,12 @@
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=docker
|
||||
PKG_VERSION:=29.8.1
|
||||
PKG_VERSION:=29.9.0
|
||||
PKG_RELEASE:=1
|
||||
|
||||
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
|
||||
PKG_SOURCE_URL:=https://codeload.github.com/docker/cli/tar.gz/v$(PKG_VERSION)?
|
||||
PKG_HASH:=55bcae5053f0914118d229658e2ac3a877dbdead6cb2c322e525d0c1e8bf78d2
|
||||
PKG_HASH:=853af65a119a538d7402515ad8d8f907effc5abe805b0dd6631ad4b2ecf26d5b
|
||||
PKG_BUILD_DIR:=$(BUILD_DIR)/cli-$(PKG_VERSION)
|
||||
PKG_GIT_SHORT_COMMIT:=$(shell $(CURDIR)/git-short-commit.sh 'github.com/docker/cli' 'v$(PKG_VERSION)' '$(TMP_DIR)/git-short-commit/$(PKG_NAME)-$(PKG_VERSION)')
|
||||
|
||||
|
||||
+2
-2
@@ -1,7 +1,7 @@
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=dockerd
|
||||
PKG_VERSION:=29.8.1
|
||||
PKG_VERSION:=29.9.0
|
||||
PKG_RELEASE:=1
|
||||
PKG_LICENSE:=Apache-2.0
|
||||
PKG_LICENSE_FILES:=LICENSE
|
||||
@@ -10,7 +10,7 @@ PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
|
||||
PKG_GIT_URL:=github.com/moby/moby
|
||||
PKG_GIT_REF:=docker-v$(PKG_VERSION)
|
||||
PKG_SOURCE_URL:=https://codeload.$(PKG_GIT_URL)/tar.gz/$(PKG_GIT_REF)?
|
||||
PKG_HASH:=94be9d6940b613676335fc494e617b4acf98676435b3744f32649ed72114bd58
|
||||
PKG_HASH:=ee76bfc375c4e498e2405a26b2b0792eb3dd999a96b9f521af16989c3b95e9ac
|
||||
PKG_GIT_SHORT_COMMIT:=$(shell $(CURDIR)/git-short-commit.sh '$(PKG_GIT_URL)' '$(PKG_GIT_REF)' '$(TMP_DIR)/git-short-commit/$(PKG_NAME)-$(PKG_VERSION)')
|
||||
|
||||
PKG_MAINTAINER:=Gerard Ryan <G.M0N3Y.2503@gmail.com>
|
||||
|
||||
+3
-3
@@ -9,9 +9,9 @@ PKG_RELEASE:=1
|
||||
|
||||
PKG_SOURCE_PROTO:=git
|
||||
PKG_SOURCE_URL:=https://gn.googlesource.com/gn.git
|
||||
PKG_SOURCE_DATE:=2026-09-17
|
||||
PKG_SOURCE_VERSION:=127dd2a6d582528d6d61c4d838dc17385ef31abd
|
||||
PKG_MIRROR_HASH:=932ef98a571d8bef6b26aca792154d989863a5746e4ceded2d37c9190793d1a0
|
||||
PKG_SOURCE_DATE:=2026-10-02
|
||||
PKG_SOURCE_VERSION:=3fef1f00031be0d3505e5338ca671ea3752e6fd8
|
||||
PKG_MIRROR_HASH:=d5bfd72bd48ec013df53d5457556261c02a18a3dd83e5786dcc3f3a367750feb
|
||||
|
||||
PKG_LICENSE:=BSD 3-Clause
|
||||
PKG_LICENSE_FILES:=LICENSE
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
#ifndef OUT_LAST_COMMIT_POSITION_H_
|
||||
#define OUT_LAST_COMMIT_POSITION_H_
|
||||
|
||||
#define LAST_COMMIT_POSITION_NUM 2575
|
||||
#define LAST_COMMIT_POSITION "2575 (127dd2a6d582)"
|
||||
#define LAST_COMMIT_POSITION_NUM 2590
|
||||
#define LAST_COMMIT_POSITION "2590 (3fef1f00031b)"
|
||||
|
||||
#endif // OUT_LAST_COMMIT_POSITION_H_
|
||||
+104
@@ -0,0 +1,104 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=honk
|
||||
PKG_VERSION:=2026.10.9_pre3
|
||||
PKG_RELEASE:=1
|
||||
|
||||
# Raw upstream release tag. It keeps the dots in qualifiers (e.g. v0.0.1.beta.49)
|
||||
# because that is what the GitHub release asset name uses.
|
||||
HONK_RELEASE_TAG:=debug.2026.10.9.native-api.3
|
||||
HONK_ASSET_TAG:=debug
|
||||
|
||||
# SHA256 of each release tarball, kept in sync by scripts/update_honk_version.sh.
|
||||
HONK_HASH_X86_64:=179dac725195f04899ae871b9fbcf47deec4b99f6b30c539296d31fdcd9a8c2e
|
||||
HONK_HASH_AARCH64:=6bcf738b8c618d9c87a412fa3dbb976e041349f6614ebd1ea2c7044ede3a4d48
|
||||
|
||||
PKG_LICENSE:=AGPL-3.0-only
|
||||
PKG_LICENSE_FILE:=LICENSE
|
||||
PKG_MAINTAINER:=luci-app-honk maintainers
|
||||
|
||||
ifeq ($(ARCH),x86_64)
|
||||
HONK_TARGET:=x86_64-unknown-linux-musl
|
||||
HONK_HASH:=$(HONK_HASH_X86_64)
|
||||
else ifeq ($(ARCH),aarch64)
|
||||
HONK_TARGET:=aarch64-unknown-linux-musl
|
||||
HONK_HASH:=$(HONK_HASH_AARCH64)
|
||||
endif
|
||||
|
||||
# Default to the stock-malloc build: lower RSS high-water on small gateways.
|
||||
# Use an empty suffix to switch back to the mimalloc build (faster QUIC).
|
||||
HONK_SUFFIX:=-stock
|
||||
HONK_ASSET:=honk-core-$(HONK_ASSET_TAG)-$(HONK_TARGET)$(HONK_SUFFIX).tar.gz
|
||||
|
||||
PKG_SOURCE:=$(HONK_ASSET)
|
||||
PKG_SOURCE_URL:=https://github.com/Glassyiris/honk/releases/download/$(HONK_RELEASE_TAG)/
|
||||
PKG_HASH:=$(HONK_HASH)
|
||||
|
||||
include $(INCLUDE_DIR)/package.mk
|
||||
|
||||
define Package/honk
|
||||
SECTION:=net
|
||||
CATEGORY:=Network
|
||||
SUBMENU:=Web Servers/Proxies
|
||||
TITLE:=honk - eBPF transparent proxy engine (dae-compatible)
|
||||
URL:=https://github.com/Glassyiris/honk
|
||||
DEPENDS:=@(x86_64||aarch64) \
|
||||
+ca-bundle +ip-full \
|
||||
+kmod-sched-core +kmod-sched-bpf +kmod-veth +kmod-nft-queue \
|
||||
+v2ray-geoip +v2ray-geosite \
|
||||
+@KERNEL_XDP_SOCKETS \
|
||||
+HONK_USE_VMLINUX_BTF:vmlinux-btf
|
||||
endef
|
||||
|
||||
define Package/honk/config
|
||||
choice
|
||||
prompt "BTF source for CO-RE"
|
||||
default HONK_USE_KERNEL_BTF
|
||||
depends on PACKAGE_honk
|
||||
|
||||
config HONK_USE_KERNEL_BTF
|
||||
bool "Use kernel BTF (integrated)"
|
||||
depends on KERNEL_DEBUG_INFO_BTF
|
||||
|
||||
config HONK_USE_VMLINUX_BTF
|
||||
bool "Use vmlinux-btf package"
|
||||
endchoice
|
||||
endef
|
||||
|
||||
define Package/honk/conffiles
|
||||
/etc/honk/config.dae
|
||||
/etc/honk/config.d/
|
||||
/etc/honk/state/
|
||||
/etc/config/honk
|
||||
endef
|
||||
|
||||
define Build/Prepare
|
||||
mkdir -p $(PKG_BUILD_DIR)
|
||||
$(TAR) -xzf $(DL_DIR)/$(PKG_SOURCE) -C $(PKG_BUILD_DIR) --strip-components=1
|
||||
endef
|
||||
|
||||
define Build/Compile
|
||||
true
|
||||
endef
|
||||
|
||||
define Package/honk/install
|
||||
$(INSTALL_DIR) $(1)/usr/bin
|
||||
$(INSTALL_BIN) $(PKG_BUILD_DIR)/honk-core $(1)/usr/bin/honk-core
|
||||
|
||||
$(INSTALL_DIR) $(1)/etc/honk/config.d
|
||||
$(INSTALL_CONF) $(CURDIR)/files/config.dae $(1)/etc/honk/config.dae
|
||||
$(INSTALL_CONF) $(CURDIR)/files/config.d/node.dae $(1)/etc/honk/config.d/node.dae
|
||||
$(INSTALL_CONF) $(CURDIR)/files/config.d/route.dae $(1)/etc/honk/config.d/route.dae
|
||||
$(INSTALL_CONF) $(CURDIR)/files/config.d/dns.dae $(1)/etc/honk/config.d/dns.dae
|
||||
$(INSTALL_CONF) $(CURDIR)/files/config.d/api.dae $(1)/etc/honk/config.d/api.dae
|
||||
|
||||
$(INSTALL_DIR) $(1)/etc/config
|
||||
$(INSTALL_CONF) $(CURDIR)/files/honk.config $(1)/etc/config/honk
|
||||
|
||||
$(INSTALL_DIR) $(1)/etc/init.d
|
||||
$(INSTALL_BIN) $(CURDIR)/files/honk.init $(1)/etc/init.d/honk
|
||||
endef
|
||||
|
||||
$(eval $(call BuildPackage,honk))
|
||||
Whitespace-only changes.
@@ -0,0 +1,23 @@
|
||||
# dns.dae
|
||||
dns {
|
||||
bind: 'tcp+udp://[::]:53530'
|
||||
client_subnet: auto
|
||||
#ipversion_prefer: 4
|
||||
upstream {
|
||||
local: 'udp://127.0.0.1:53' -> direct
|
||||
remote: 'tcp+udp://one.one.one.one:53'
|
||||
}
|
||||
routing {
|
||||
request {
|
||||
qtype(https) -> reject
|
||||
qname(geosite: gfw) -> remote
|
||||
fallback: local
|
||||
}
|
||||
response {
|
||||
upstream(remote) -> accept
|
||||
qname(geosite: private) -> accept
|
||||
ip(geoip: cn) -> accept
|
||||
fallback: remote
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
# node.dae
|
||||
node {
|
||||
node1: 'xxx'
|
||||
node2: 'xxx'
|
||||
}
|
||||
|
||||
subscription {
|
||||
# 短形式:默认 86400s 刷新一次
|
||||
sub: 'http://sub'
|
||||
|
||||
# 短形式 + UA:仍然只能默认 86400s
|
||||
sub_ua: 'http://sub'(honk/1.0 like)
|
||||
|
||||
# 块形式:可以自定义定时刷新周期
|
||||
sub2: {
|
||||
url: 'http://sub'
|
||||
ua: 'honk/1.0'
|
||||
interval: '10000s' # 每 10000 秒刷新一次
|
||||
}
|
||||
|
||||
# 禁用定期刷新
|
||||
sub3: {
|
||||
url: 'http://sub'
|
||||
interval: 0
|
||||
}
|
||||
}
|
||||
|
||||
group {
|
||||
proxy {
|
||||
filter: subtag(sub) && !name(keyword: 'ExpireAt:')
|
||||
filter: name(node1, node2)
|
||||
policy: score
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
# route.dae
|
||||
routing {
|
||||
pname(dnsmasq, zerotier-one) -> direct(must)
|
||||
dip(224.0.0.0/3, 'ff00::/8', geoip: private) -> direct
|
||||
domain(geosite: category-bank-cn, geosite: boc@!cn, geosite: synology) -> direct
|
||||
|
||||
# block quic, if u node has poor quic support, enable this line
|
||||
# l4proto(udp) && dport(443) -> block
|
||||
|
||||
domain(geosite: spotify) -> proxy
|
||||
domain(geosite: category-doh) -> proxy
|
||||
domain(geosite: tiktok) -> proxy
|
||||
domain(geosite: category-ai-!cn, geosite: github) -> proxy
|
||||
domain(geosite: gfw) -> proxy
|
||||
|
||||
dip(geoip: telegram) -> proxy
|
||||
|
||||
dip(geoip: cn) -> direct
|
||||
# geoip:cn always using chiness asn, can use domain rule to override
|
||||
# domain(geosite: cn) -> direct
|
||||
|
||||
# using proxy for ssh, http, https, and common ports, avoid (bt, or other p2p)
|
||||
# dport(22, 80, 443, 8080, 6443, 9090) -> proxy
|
||||
|
||||
# fallback: direct
|
||||
fallback: proxy
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
# config.dae
|
||||
# Load all honk files placed in ./config.d/.
|
||||
include {
|
||||
config.d/*.dae
|
||||
}
|
||||
|
||||
global {
|
||||
log_level: warn
|
||||
check_interval: 600s
|
||||
check_tolerance: 30ms
|
||||
lan_interface: br-lan
|
||||
wan_interface: auto
|
||||
auto_config_kernel_parameter: true
|
||||
disable_waiting_network: false
|
||||
data_dir: '/etc/honk'
|
||||
log_file: '/var/log/honk/honk.log'
|
||||
store_subscribe: true
|
||||
# if u not using dns bind, set dial_mode to domain++ prefer
|
||||
dial_mode: domain
|
||||
bootstrap_resolver: '223.5.5.5:53'
|
||||
tcp_check_url: 'https://www.gstatic.com/generate_204'
|
||||
tcp_check_http_method: HEAD
|
||||
udp_check_dns: 'dns.google.com:53', '8.8.8.8', '2001:4860:4860::8888'
|
||||
}
|
||||
|
||||
assets {
|
||||
geodata {
|
||||
geosite: 'https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/release/geosite.dat'
|
||||
geoip: 'https://raw.githubusercontent.com/QiuSimons/geoip-moedove/refs/heads/main/geoip.dat'
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
|
||||
config honk 'config'
|
||||
option enabled '0'
|
||||
option advanced '0'
|
||||
option dashboard 'none'
|
||||
option config_file '/etc/honk/config.dae'
|
||||
|
||||
@@ -0,0 +1,122 @@
|
||||
#!/bin/sh /etc/rc.common
|
||||
|
||||
USE_PROCD=1
|
||||
START=96
|
||||
STOP=10
|
||||
|
||||
extra_command "hot_reload" "Hot-reload service"
|
||||
|
||||
CONF="honk"
|
||||
PROG="/usr/bin/honk-core"
|
||||
# honk-core hardcodes dae-compatible datapath names (dae0/dae0peer + daens);
|
||||
# these are the real interface/netns names, not leftover dae config.
|
||||
HONK_HOST_IFACE="dae0"
|
||||
HONK_PEER_IFACE="dae0peer"
|
||||
HONK_NETNS_NAME="daens"
|
||||
HONK_NETNS_PATH="/run/netns/$HONK_NETNS_NAME"
|
||||
RESOLV_HONK="/tmp/resolv.conf.honk"
|
||||
|
||||
set_chmod_640() {
|
||||
mkdir -p /etc/honk/config.d /etc/honk/state /var/log/honk
|
||||
chmod -R u=rwX,go= /etc/honk 2>/dev/null || true
|
||||
chmod 700 /etc/honk /etc/honk/config.d /etc/honk/state 2>/dev/null || true
|
||||
}
|
||||
|
||||
cleanup_netns() {
|
||||
ip netns del "$HONK_NETNS_NAME" 2>/dev/null || true
|
||||
umount "$HONK_NETNS_PATH" 2>/dev/null || true
|
||||
rm -f "$HONK_NETNS_PATH" 2>/dev/null || true
|
||||
ip link del "$HONK_HOST_IFACE" 2>/dev/null || true
|
||||
ip link del "$HONK_PEER_IFACE" 2>/dev/null || true
|
||||
}
|
||||
|
||||
hijack_resolv_conf() {
|
||||
grep -q ' /tmp/resolv\.conf ' /proc/mounts && return 0
|
||||
|
||||
local dns_list WANS
|
||||
. /lib/functions/network.sh
|
||||
unset -v __NETWORK_CACHE
|
||||
__network_ifstatus WANS "" "[@.route[@.target='0.0.0.0' && !@.table]].interface" 2>/dev/null
|
||||
set -- $WANS
|
||||
|
||||
if [ $# -eq 1 ]; then
|
||||
dns_list=$(ubus call "network.interface.$1" status 2>/dev/null | \
|
||||
jsonfilter -e '@["dns-server"][*]' 2>/dev/null)
|
||||
if [ -z "$dns_list" ] && [ -f "/tmp/resolv.conf.d/resolv.conf.auto" ]; then
|
||||
dns_list=$(awk '/^nameserver/{print $2}' "/tmp/resolv.conf.d/resolv.conf.auto")
|
||||
fi
|
||||
fi
|
||||
|
||||
[ -z "$dns_list" ] && dns_list="119.29.29.29 223.5.5.5"
|
||||
|
||||
[ -f /tmp/resolv.conf ] || touch /tmp/resolv.conf
|
||||
grep -E '^(search|domain) ' /tmp/resolv.conf > "$RESOLV_HONK" 2>/dev/null
|
||||
|
||||
for dns in $dns_list; do
|
||||
echo "nameserver $dns" >> "$RESOLV_HONK"
|
||||
done
|
||||
|
||||
mount --bind "$RESOLV_HONK" /tmp/resolv.conf
|
||||
mount -o remount,ro,bind /tmp/resolv.conf
|
||||
}
|
||||
|
||||
restore_resolv_conf() {
|
||||
while grep -q ' /tmp/resolv\.conf ' /proc/mounts; do
|
||||
mount -o remount,rw,bind /tmp/resolv.conf 2>/dev/null
|
||||
umount /tmp/resolv.conf 2>/dev/null || break
|
||||
done
|
||||
rm -f "$RESOLV_HONK"
|
||||
}
|
||||
|
||||
start_service() {
|
||||
local enabled config_file
|
||||
|
||||
config_load "$CONF"
|
||||
config_get_bool enabled "config" "enabled" "0"
|
||||
[ "$enabled" -eq "1" ] || return 1
|
||||
|
||||
config_get config_file "config" "config_file" "/etc/honk/config.dae"
|
||||
|
||||
if [ ! -x "$PROG" ]; then
|
||||
logger -t honk "not starting: $PROG is missing or not executable"
|
||||
return 1
|
||||
fi
|
||||
|
||||
set_chmod_640
|
||||
cleanup_netns
|
||||
hijack_resolv_conf
|
||||
|
||||
procd_open_instance "$CONF"
|
||||
procd_set_param env DAE_LOCATION_ASSET="/usr/share/v2ray"
|
||||
procd_set_param command "$PROG" --config "$config_file"
|
||||
procd_set_param netdev "$HONK_HOST_IFACE" "$HONK_PEER_IFACE"
|
||||
procd_set_param limits core="unlimited"
|
||||
procd_set_param limits nofile="1000000 1000000"
|
||||
procd_set_param term_timeout 8
|
||||
procd_set_param respawn 3600 5 5
|
||||
procd_set_param stderr 1
|
||||
procd_close_instance
|
||||
}
|
||||
|
||||
service_stopped() {
|
||||
restore_resolv_conf
|
||||
cleanup_netns
|
||||
}
|
||||
|
||||
reload_service() {
|
||||
stop
|
||||
start
|
||||
}
|
||||
|
||||
service_triggers() {
|
||||
procd_add_reload_trigger "$CONF"
|
||||
}
|
||||
|
||||
hot_reload() {
|
||||
set_chmod_640
|
||||
if /etc/init.d/honk running; then
|
||||
"$PROG" reload
|
||||
else
|
||||
start
|
||||
fi
|
||||
}
|
||||
+2
-2
@@ -5,12 +5,12 @@
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=hysteria
|
||||
PKG_VERSION:=2.12.3
|
||||
PKG_VERSION:=2.13.0
|
||||
PKG_RELEASE:=1
|
||||
|
||||
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
|
||||
PKG_SOURCE_URL:=https://codeload.github.com/apernet/hysteria/tar.gz/app/v$(PKG_VERSION)?
|
||||
PKG_HASH:=2679b76ab9cacbfd7574a48453325843865a347f1925858c4fb4fee3be132147
|
||||
PKG_HASH:=dfde427a93a0dc5ff65ddc1e239df3b1def54bf33f8b137c571daa7b27ecddd0
|
||||
PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-app-v$(PKG_VERSION)
|
||||
|
||||
PKG_LICENSE:=MIT
|
||||
|
||||
@@ -6,7 +6,7 @@ include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=internet-detector-mod-email
|
||||
PKG_VERSION:=1.7.4
|
||||
PKG_RELEASE:=1
|
||||
PKG_RELEASE:=2
|
||||
PKG_MAINTAINER:=gSpot <https://github.com/gSpotx2f/luci-app-internet-detector>
|
||||
|
||||
include $(INCLUDE_DIR)/package.mk
|
||||
|
||||
@@ -6,7 +6,7 @@ include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=internet-detector-mod-modem-restart
|
||||
PKG_VERSION:=1.7.4
|
||||
PKG_RELEASE:=1
|
||||
PKG_RELEASE:=2
|
||||
PKG_MAINTAINER:=gSpot <https://github.com/gSpotx2f/luci-app-internet-detector>
|
||||
|
||||
include $(INCLUDE_DIR)/package.mk
|
||||
|
||||
@@ -6,7 +6,7 @@ include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=internet-detector-mod-telegram
|
||||
PKG_VERSION:=1.7.4
|
||||
PKG_RELEASE:=1
|
||||
PKG_RELEASE:=2
|
||||
PKG_MAINTAINER:=gSpot <https://github.com/gSpotx2f/luci-app-internet-detector>
|
||||
|
||||
include $(INCLUDE_DIR)/package.mk
|
||||
|
||||
+1
-1
@@ -57,7 +57,7 @@ function httpRequest(url, proxyType, proxyHost, proxyPort, proxyUser, proxyPassw
|
||||
if(length(r) > 0) {
|
||||
retCode = r[0];
|
||||
}
|
||||
data = replace(data, retCodeRegexp, '');
|
||||
data = trim(replace(data, retCodeRegexp, ''));
|
||||
}
|
||||
}
|
||||
return { retCode, data };
|
||||
|
||||
@@ -6,7 +6,7 @@ include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=internet-detector
|
||||
PKG_VERSION:=1.7.4
|
||||
PKG_RELEASE:=1
|
||||
PKG_RELEASE:=2
|
||||
PKG_MAINTAINER:=gSpot <https://github.com/gSpotx2f/luci-app-internet-detector>
|
||||
|
||||
include $(INCLUDE_DIR)/package.mk
|
||||
@@ -62,6 +62,8 @@ define Package/$(PKG_NAME)/install
|
||||
$(INSTALL_DATA) ./files/usr/lib/lua/internet-detector/modules/mod_public_ip.lua $(1)/usr/lib/lua/internet-detector/modules/mod_public_ip.lua
|
||||
$(INSTALL_DATA) ./files/usr/lib/lua/internet-detector/modules/mod_user_scripts.lua $(1)/usr/lib/lua/internet-detector/modules/mod_user_scripts.lua
|
||||
$(INSTALL_DATA) ./files/usr/lib/lua/internet-detector/modules/mod_regular_script.lua $(1)/usr/lib/lua/internet-detector/modules/mod_regular_script.lua
|
||||
$(INSTALL_DIR) $(1)/lib/upgrade/keep.d
|
||||
$(INSTALL_DATA) ./files/lib/upgrade/keep.d/internet-detector $(1)/lib/upgrade/keep.d/internet-detector
|
||||
endef
|
||||
|
||||
define Package/$(PKG_NAME)/postinst
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
/etc/internet-detector/*
|
||||
@@ -27,39 +27,39 @@ get_enabled_anonymous_secs() {
|
||||
ipt_rule() {
|
||||
if [ "$1" = "add" ]; then
|
||||
iptables -w -t mangle -I OUTPUT -p udp -m multiport --sports 500,4500 -m comment --comment "${ipt_comment}" -j RETURN 2>/dev/null
|
||||
iptables -w -I input_rule -p udp -m multiport --dports 500,4500 -m comment --comment "${ipt_comment}" -j ACCEPT 2>/dev/null
|
||||
iptables -w -I forwarding_rule -m policy --dir in --pol ipsec --proto esp -m comment --comment "${ipt_comment}" -j ACCEPT 2>/dev/null
|
||||
iptables -w -I forwarding_rule -m policy --dir out --pol ipsec --proto esp -m comment --comment "${ipt_comment}" -j ACCEPT 2>/dev/null
|
||||
iptables -w -I INPUT -p udp -m multiport --dports 500,4500 -m comment --comment "${ipt_comment}" -j ACCEPT 2>/dev/null
|
||||
iptables -w -I FORWARD -m policy --dir in --pol ipsec --proto esp -m comment --comment "${ipt_comment}" -j ACCEPT 2>/dev/null
|
||||
iptables -w -I FORWARD -m policy --dir out --pol ipsec --proto esp -m comment --comment "${ipt_comment}" -j ACCEPT 2>/dev/null
|
||||
|
||||
ip6tables -w -t mangle -I OUTPUT -p udp -m multiport --sports 500,4500 -m comment --comment "${ipt_comment}" -j RETURN 2>/dev/null
|
||||
ip6tables -w -I input_rule -p udp -m multiport --dports 500,4500 -m comment --comment "${ipt_comment}" -j ACCEPT 2>/dev/null
|
||||
ip6tables -w -I forwarding_rule -m policy --dir in --pol ipsec --proto esp -m comment --comment "${ipt_comment}" -j ACCEPT 2>/dev/null
|
||||
ip6tables -w -I forwarding_rule -m policy --dir out --pol ipsec --proto esp -m comment --comment "${ipt_comment}" -j ACCEPT 2>/dev/null
|
||||
ip6tables -w -I INPUT -p udp -m multiport --dports 500,4500 -m comment --comment "${ipt_comment}" -j ACCEPT 2>/dev/null
|
||||
ip6tables -w -I FORWARD -m policy --dir in --pol ipsec --proto esp -m comment --comment "${ipt_comment}" -j ACCEPT 2>/dev/null
|
||||
ip6tables -w -I FORWARD -m policy --dir out --pol ipsec --proto esp -m comment --comment "${ipt_comment}" -j ACCEPT 2>/dev/null
|
||||
|
||||
if [ "${vt_type}" = "L2TP" ]; then
|
||||
iptables -w -t mangle -I OUTPUT -p udp --sport 1701 -m comment --comment "${ipt_comment}" -j RETURN 2>/dev/null
|
||||
iptables -w -I input_rule -p udp --dport 1701 -m comment --comment "${ipt_comment}" -j ACCEPT 2>/dev/null
|
||||
iptables -w -I input_rule -s ${l2tp_localip%.*}.0/24 -m comment --comment "${ipt_comment}" -j ACCEPT 2>/dev/null
|
||||
iptables -w -I input_rule -d ${l2tp_localip%.*}.0/24 -m comment --comment "${ipt_comment}" -j ACCEPT 2>/dev/null
|
||||
iptables -w -I forwarding_rule -s ${l2tp_localip%.*}.0/24 -m comment --comment "${ipt_comment}" -j ACCEPT 2>/dev/null
|
||||
iptables -w -I forwarding_rule -d ${l2tp_localip%.*}.0/24 -m comment --comment "${ipt_comment}" -j ACCEPT 2>/dev/null
|
||||
iptables -w -I output_rule -s ${l2tp_localip%.*}.0/24 -m comment --comment "${ipt_comment}" -j ACCEPT 2>/dev/null
|
||||
iptables -w -I output_rule -d ${l2tp_localip%.*}.0/24 -m comment --comment "${ipt_comment}" -j ACCEPT 2>/dev/null
|
||||
iptables -w -t nat -I postrouting_rule -s ${l2tp_localip%.*}.0/24 -m comment --comment "${ipt_comment}" -j FULLCONENAT 2>/dev/null
|
||||
[ "$?" != "0" ] && iptables -w -t nat -I postrouting_rule -s ${l2tp_localip%.*}.0/24 -m comment --comment "${ipt_comment}" -j MASQUERADE 2>/dev/null
|
||||
iptables -w -t nat -I postrouting_rule -d ${l2tp_localip%.*}.0/24 -m comment --comment "${ipt_comment}" -j FULLCONENAT 2>/dev/null
|
||||
[ "$?" != "0" ] && iptables -w -t nat -I postrouting_rule -d ${l2tp_localip%.*}.0/24 -m comment --comment "${ipt_comment}" -j MASQUERADE 2>/dev/null
|
||||
iptables -w -I INPUT -p udp --dport 1701 -m comment --comment "${ipt_comment}" -j ACCEPT 2>/dev/null
|
||||
iptables -w -I INPUT -s ${l2tp_localip%.*}.0/24 -m comment --comment "${ipt_comment}" -j ACCEPT 2>/dev/null
|
||||
iptables -w -I INPUT -d ${l2tp_localip%.*}.0/24 -m comment --comment "${ipt_comment}" -j ACCEPT 2>/dev/null
|
||||
iptables -w -I FORWARD -s ${l2tp_localip%.*}.0/24 -m comment --comment "${ipt_comment}" -j ACCEPT 2>/dev/null
|
||||
iptables -w -I FORWARD -d ${l2tp_localip%.*}.0/24 -m comment --comment "${ipt_comment}" -j ACCEPT 2>/dev/null
|
||||
iptables -w -I OUTPUT -s ${l2tp_localip%.*}.0/24 -m comment --comment "${ipt_comment}" -j ACCEPT 2>/dev/null
|
||||
iptables -w -I OUTPUT -d ${l2tp_localip%.*}.0/24 -m comment --comment "${ipt_comment}" -j ACCEPT 2>/dev/null
|
||||
iptables -w -t nat -I POSTROUTING -s ${l2tp_localip%.*}.0/24 -m comment --comment "${ipt_comment}" -j FULLCONENAT 2>/dev/null
|
||||
[ "$?" != "0" ] && iptables -w -t nat -I POSTROUTING -s ${l2tp_localip%.*}.0/24 -m comment --comment "${ipt_comment}" -j MASQUERADE 2>/dev/null
|
||||
iptables -w -t nat -I POSTROUTING -d ${l2tp_localip%.*}.0/24 -m comment --comment "${ipt_comment}" -j FULLCONENAT 2>/dev/null
|
||||
[ "$?" != "0" ] && iptables -w -t nat -I POSTROUTING -d ${l2tp_localip%.*}.0/24 -m comment --comment "${ipt_comment}" -j MASQUERADE 2>/dev/null
|
||||
else
|
||||
iptables -w -I input_rule -s ${vt_clientip} -m comment --comment "${ipt_comment}" -j ACCEPT 2>/dev/null
|
||||
iptables -w -I input_rule -d ${vt_clientip} -m comment --comment "${ipt_comment}" -j ACCEPT 2>/dev/null
|
||||
iptables -w -I forwarding_rule -s ${vt_clientip} -m comment --comment "${ipt_comment}" -j ACCEPT 2>/dev/null
|
||||
iptables -w -I forwarding_rule -d ${vt_clientip} -m comment --comment "${ipt_comment}" -j ACCEPT 2>/dev/null
|
||||
iptables -w -I output_rule -s ${vt_clientip} -m comment --comment "${ipt_comment}" -j ACCEPT 2>/dev/null
|
||||
iptables -w -I output_rule -d ${vt_clientip} -m comment --comment "${ipt_comment}" -j ACCEPT 2>/dev/null
|
||||
iptables -w -t nat -I postrouting_rule -s ${vt_clientip} -m comment --comment "${ipt_comment}" -j FULLCONENAT 2>/dev/null
|
||||
[ "$?" != "0" ] && iptables -w -t nat -I postrouting_rule -s ${vt_clientip} -m comment --comment "${ipt_comment}" -j MASQUERADE 2>/dev/null
|
||||
iptables -w -t nat -I postrouting_rule -d ${vt_clientip} -m comment --comment "${ipt_comment}" -j FULLCONENAT 2>/dev/null
|
||||
[ "$?" != "0" ] && iptables -w -t nat -I postrouting_rule -d ${vt_clientip} -m comment --comment "${ipt_comment}" -j MASQUERADE 2>/dev/null
|
||||
iptables -w -I INPUT -s ${vt_clientip} -m comment --comment "${ipt_comment}" -j ACCEPT 2>/dev/null
|
||||
iptables -w -I INPUT -d ${vt_clientip} -m comment --comment "${ipt_comment}" -j ACCEPT 2>/dev/null
|
||||
iptables -w -I FORWARD -s ${vt_clientip} -m comment --comment "${ipt_comment}" -j ACCEPT 2>/dev/null
|
||||
iptables -w -I FORWARD -d ${vt_clientip} -m comment --comment "${ipt_comment}" -j ACCEPT 2>/dev/null
|
||||
iptables -w -I OUTPUT -s ${vt_clientip} -m comment --comment "${ipt_comment}" -j ACCEPT 2>/dev/null
|
||||
iptables -w -I OUTPUT -d ${vt_clientip} -m comment --comment "${ipt_comment}" -j ACCEPT 2>/dev/null
|
||||
iptables -w -t nat -I POSTROUTING -s ${vt_clientip} -m comment --comment "${ipt_comment}" -j FULLCONENAT 2>/dev/null
|
||||
[ "$?" != "0" ] && iptables -w -t nat -I POSTROUTING -s ${vt_clientip} -m comment --comment "${ipt_comment}" -j MASQUERADE 2>/dev/null
|
||||
iptables -w -t nat -I POSTROUTING -d ${vt_clientip} -m comment --comment "${ipt_comment}" -j FULLCONENAT 2>/dev/null
|
||||
[ "$?" != "0" ] && iptables -w -t nat -I POSTROUTING -d ${vt_clientip} -m comment --comment "${ipt_comment}" -j MASQUERADE 2>/dev/null
|
||||
|
||||
|
||||
uci -q batch <<-EOF >/dev/null
|
||||
@@ -80,13 +80,13 @@ ipt_rule() {
|
||||
$1 -w -D $2 $index 2>/dev/null
|
||||
done
|
||||
}
|
||||
ipt_del "iptables -w" "input_rule"
|
||||
ipt_del "iptables -w" "forwarding_rule"
|
||||
ipt_del "iptables -w" "output_rule"
|
||||
ipt_del "iptables -w -t nat" "postrouting_rule"
|
||||
ipt_del "iptables -w" "INPUT"
|
||||
ipt_del "iptables -w" "FORWARD"
|
||||
ipt_del "iptables -w" "OUTPUT"
|
||||
ipt_del "iptables -w -t nat" "POSTROUTING"
|
||||
ipt_del "iptables -w -t mangle" "OUTPUT"
|
||||
ipt_del "ip6tables -w" "input_rule"
|
||||
ipt_del "ip6tables -w" "forwarding_rule"
|
||||
ipt_del "ip6tables -w" "INPUT"
|
||||
ipt_del "ip6tables -w" "FORWARD"
|
||||
ipt_del "ip6tables -w -t mangle" "OUTPUT"
|
||||
uci -q batch <<-EOF >/dev/null
|
||||
delete network.ipsec_server
|
||||
@@ -123,6 +123,7 @@ gen_include() {
|
||||
$(extract_rules6 filter)
|
||||
$(extract_rules6 mangle)
|
||||
EOT
|
||||
exit 0
|
||||
EOF
|
||||
return 0
|
||||
}
|
||||
|
||||
@@ -5,9 +5,16 @@ uci -q batch <<-EOF >/dev/null
|
||||
set firewall.luci_app_ipsec_server=include
|
||||
set firewall.luci_app_ipsec_server.type=script
|
||||
set firewall.luci_app_ipsec_server.path=/var/etc/ipsecvpn.include
|
||||
set firewall.luci_app_ipsec_server.reload=1
|
||||
EOF
|
||||
|
||||
if [ -x "/sbin/fw3" ] && [ ! -L "/sbin/fw3" ]; then
|
||||
uci -q set firewall.luci_app_ipsec_server.reload='1'
|
||||
else
|
||||
uci -q delete firewall.luci_app_ipsec_server.reload
|
||||
uci -q delete firewall.luci_app_ipsec_server.fw4_compatible
|
||||
fi
|
||||
uci commit firewall
|
||||
|
||||
/etc/init.d/ipsec disable 2>/dev/null
|
||||
/etc/init.d/ipsec stop 2>/dev/null
|
||||
/etc/init.d/xl2tpd disable 2>/dev/null
|
||||
|
||||
@@ -129,11 +129,11 @@ start_instance() {
|
||||
cat <<-EOF >> ${TMP_OVPN_PATH}/${cfgid}/iptables_add.sh
|
||||
${TMP_OVPN_PATH}/${cfgid}/iptables_del.sh
|
||||
#允许服务端配置静态路由表访问内网
|
||||
iptables -w -t nat -I postrouting_rule -s \$(cat ${TMP_OVPN_PATH}/${cfgid}/network)/\$(cat ${TMP_OVPN_PATH}/${cfgid}/mask) -m comment --comment "${c_dev}" -j MASQUERADE
|
||||
iptables -w -t nat -I postrouting_rule -o ${c_dev} -m comment --comment "${c_dev}" -j MASQUERADE
|
||||
iptables -w -I input_rule -s \$(cat ${TMP_OVPN_PATH}/${cfgid}/network)/\$(cat ${TMP_OVPN_PATH}/${cfgid}/mask) -m comment --comment "${c_dev}" -j ${c_allow_access_action}
|
||||
iptables -w -I forwarding_rule -i ${c_dev} -m comment --comment "${c_dev}" -j ACCEPT
|
||||
iptables -w -I forwarding_rule -o ${c_dev} -m comment --comment "${c_dev}" -j ACCEPT
|
||||
iptables -w -t nat -I POSTROUTING -s \$(cat ${TMP_OVPN_PATH}/${cfgid}/network)/\$(cat ${TMP_OVPN_PATH}/${cfgid}/mask) -m comment --comment "${c_dev}" -j MASQUERADE
|
||||
iptables -w -t nat -I POSTROUTING -o ${c_dev} -m comment --comment "${c_dev}" -j MASQUERADE
|
||||
iptables -w -I INPUT -s \$(cat ${TMP_OVPN_PATH}/${cfgid}/network)/\$(cat ${TMP_OVPN_PATH}/${cfgid}/mask) -m comment --comment "${c_dev}" -j ${c_allow_access_action}
|
||||
iptables -w -I FORWARD -i ${c_dev} -m comment --comment "${c_dev}" -j ACCEPT
|
||||
iptables -w -I FORWARD -o ${c_dev} -m comment --comment "${c_dev}" -j ACCEPT
|
||||
EOF
|
||||
|
||||
cat <<-EOF >> ${TMP_OVPN_PATH}/${cfgid}/iptables_del.sh
|
||||
@@ -143,9 +143,9 @@ start_instance() {
|
||||
\$1 -w -D \$2 \$index 2>/dev/null
|
||||
done
|
||||
}
|
||||
ipt_del "iptables -w" "input_rule"
|
||||
ipt_del "iptables -w" "forwarding_rule"
|
||||
ipt_del "iptables -w -t nat" "postrouting_rule"
|
||||
ipt_del "iptables -w" "INPUT"
|
||||
ipt_del "iptables -w" "FORWARD"
|
||||
ipt_del "iptables -w -t nat" "POSTROUTING"
|
||||
EOF
|
||||
|
||||
cat <<-EOF >> ${TMP_OVPN_PATH}/${cfgid}/ipchange.sh
|
||||
@@ -162,6 +162,7 @@ start_instance() {
|
||||
|
||||
cat <<-EOF >> /var/etc/${CONFIG}.include
|
||||
${TMP_OVPN_PATH}/${cfgid}/iptables_add.sh
|
||||
exit 0
|
||||
EOF
|
||||
|
||||
local c_routes=$(uci -q get ${CONFIG}.${cfgid}.routes)
|
||||
|
||||
@@ -5,8 +5,15 @@ uci -q batch <<-EOF >/dev/null
|
||||
set firewall.openvpn_client=include
|
||||
set firewall.openvpn_client.type=script
|
||||
set firewall.openvpn_client.path=/var/etc/luci-app-openvpn-client.include
|
||||
set firewall.openvpn_client.reload=1
|
||||
EOF
|
||||
|
||||
if [ -x "/sbin/fw3" ] && [ ! -L "/sbin/fw3" ]; then
|
||||
uci -q set firewall.openvpn_client.reload='1'
|
||||
else
|
||||
uci -q delete firewall.openvpn_client.reload
|
||||
uci -q delete firewall.openvpn_client.fw4_compatible
|
||||
fi
|
||||
uci commit firewall
|
||||
|
||||
rm -rf /tmp/luci-*cache
|
||||
exit 0
|
||||
@@ -23,13 +23,13 @@ ipt_flag="OpenVPN Server"
|
||||
|
||||
ipt_rule() {
|
||||
if [ "$1" = "add" ]; then
|
||||
iptables -w -t nat -I postrouting_rule -s ${ip_segment%.*}.0/${ip_prefix} -m comment --comment "${ipt_flag}" -j MASQUERADE 2>/dev/null
|
||||
iptables -w -I forwarding_rule -s ${ip_segment%.*}.0/${ip_prefix} -m comment --comment "${ipt_flag}" -j ACCEPT 2>/dev/null
|
||||
iptables -w -I input_rule -p ${proto} --dport ${port} -m comment --comment "${ipt_flag}" -j ACCEPT 2>/dev/null
|
||||
iptables -w -t nat -I POSTROUTING -s ${ip_segment%.*}.0/${ip_prefix} -m comment --comment "${ipt_flag}" -j MASQUERADE 2>/dev/null
|
||||
iptables -w -I FORWARD -s ${ip_segment%.*}.0/${ip_prefix} -m comment --comment "${ipt_flag}" -j ACCEPT 2>/dev/null
|
||||
iptables -w -I INPUT -p ${proto} --dport ${port} -m comment --comment "${ipt_flag}" -j ACCEPT 2>/dev/null
|
||||
iptables -w -t mangle -I OUTPUT -p ${proto} --sport ${port} -m comment --comment "${ipt_flag}" -j RETURN 2>/dev/null
|
||||
|
||||
[ "${ipv6}" -eq 1 ] && {
|
||||
ip6tables -w -I input_rule -p ${proto} --dport ${port} -m comment --comment "${ipt_flag}" -j ACCEPT 2>/dev/null
|
||||
ip6tables -w -I INPUT -p ${proto} --dport ${port} -m comment --comment "${ipt_flag}" -j ACCEPT 2>/dev/null
|
||||
ip6tables -w -t mangle -I OUTPUT -p ${proto} --sport ${port} -m comment --comment "${ipt_flag}" -j RETURN 2>/dev/null
|
||||
}
|
||||
else
|
||||
@@ -39,11 +39,11 @@ ipt_rule() {
|
||||
$1 -w -D $2 $index 2>/dev/null
|
||||
done
|
||||
}
|
||||
ipt_del "iptables" "forwarding_rule"
|
||||
ipt_del "iptables" "input_rule"
|
||||
ipt_del "iptables -t nat" "postrouting_rule"
|
||||
ipt_del "iptables" "FORWARD"
|
||||
ipt_del "iptables" "INPUT"
|
||||
ipt_del "iptables -t nat" "POSTROUTING"
|
||||
ipt_del "iptables -t mangle" "OUTPUT"
|
||||
ipt_del "ip6tables" "input_rule"
|
||||
ipt_del "ip6tables" "INPUT"
|
||||
ipt_del "ip6tables -t mangle" "OUTPUT"
|
||||
fi
|
||||
}
|
||||
@@ -72,6 +72,7 @@ gen_include() {
|
||||
$(extract_rules 6 mangle)
|
||||
EOT
|
||||
}
|
||||
exit 0
|
||||
EOF
|
||||
return 0
|
||||
}
|
||||
|
||||
@@ -8,12 +8,6 @@ done
|
||||
uci -q commit firewall
|
||||
|
||||
uci -q batch <<-EOF >/dev/null
|
||||
delete firewall.openvpn_server
|
||||
set firewall.openvpn_server=include
|
||||
set firewall.openvpn_server.type=script
|
||||
set firewall.openvpn_server.path=/var/etc/luci-app-openvpn-server.include
|
||||
set firewall.openvpn_server.reload=1
|
||||
|
||||
delete firewall.ovpn_server
|
||||
set firewall.ovpn_server=zone
|
||||
set firewall.ovpn_server.name='ovpn_server'
|
||||
@@ -26,8 +20,20 @@ uci -q batch <<-EOF >/dev/null
|
||||
set firewall.lantoovpnserver=forwarding
|
||||
set firewall.lantoovpnserver.src='lan'
|
||||
set firewall.lantoovpnserver.dest='ovpn_server'
|
||||
commit firewall
|
||||
|
||||
delete firewall.openvpn_server
|
||||
set firewall.openvpn_server=include
|
||||
set firewall.openvpn_server.type=script
|
||||
set firewall.openvpn_server.path=/var/etc/luci-app-openvpn-server.include
|
||||
EOF
|
||||
|
||||
if [ -x "/sbin/fw3" ] && [ ! -L "/sbin/fw3" ]; then
|
||||
uci -q set firewall.openvpn_server.reload='1'
|
||||
else
|
||||
uci -q delete firewall.openvpn_server.reload
|
||||
uci -q delete firewall.openvpn_server.fw4_compatible
|
||||
fi
|
||||
uci commit firewall
|
||||
|
||||
rm -rf /tmp/luci-*cache
|
||||
exit 0
|
||||
@@ -21,8 +21,9 @@ localip=$(config_t_get service localip 10.0.1.1)
|
||||
|
||||
ipt_rule() {
|
||||
if [ "$1" = "add" ]; then
|
||||
iptables -t nat -I postrouting_rule -s ${localip%.*}.0/24 -m comment --comment "${ipt_flag}" -j MASQUERADE 2>/dev/null
|
||||
iptables -I forwarding_rule -s ${localip%.*}.0/24 -m comment --comment "${ipt_flag}" -j ACCEPT 2>/dev/null
|
||||
iptables -w -t nat -I POSTROUTING -s ${localip%.*}.0/24 -m comment --comment "${ipt_flag}" -j MASQUERADE 2>/dev/null
|
||||
iptables -w -t nat -I POSTROUTING -d ${localip%.*}.0/24 -m comment --comment "${ipt_flag}" -j MASQUERADE 2>/dev/null
|
||||
iptables -w -I FORWARD -s ${localip%.*}.0/24 -m comment --comment "${ipt_flag}" -j ACCEPT 2>/dev/null
|
||||
else
|
||||
ipt_del() {
|
||||
for i in $(seq 1 $($1 -nL $2 | grep -c "${ipt_flag}")); do
|
||||
@@ -30,8 +31,8 @@ ipt_rule() {
|
||||
$1 -w -D $2 $index 2>/dev/null
|
||||
done
|
||||
}
|
||||
ipt_del "iptables" "forwarding_rule"
|
||||
ipt_del "iptables -t nat" "postrouting_rule"
|
||||
ipt_del "iptables" "FORWARD"
|
||||
ipt_del "iptables -t nat" "POSTROUTING"
|
||||
fi
|
||||
}
|
||||
|
||||
@@ -49,6 +50,7 @@ gen_include() {
|
||||
$(extract_rules filter)
|
||||
$(extract_rules nat)
|
||||
EOT
|
||||
exit 0
|
||||
EOF
|
||||
return 0
|
||||
}
|
||||
|
||||
@@ -5,8 +5,15 @@ uci -q batch <<-EOF >/dev/null
|
||||
set firewall.luci_app_pppoe_server=include
|
||||
set firewall.luci_app_pppoe_server.type=script
|
||||
set firewall.luci_app_pppoe_server.path=/var/etc/luci-app-pppoe-server.include
|
||||
set firewall.luci_app_pppoe_server.reload=1
|
||||
EOF
|
||||
|
||||
if [ -x "/sbin/fw3" ] && [ ! -L "/sbin/fw3" ]; then
|
||||
uci -q set firewall.luci_app_pppoe_server.reload='1'
|
||||
else
|
||||
uci -q delete firewall.luci_app_pppoe_server.reload
|
||||
uci -q delete firewall.luci_app_pppoe_server.fw4_compatible
|
||||
fi
|
||||
uci commit firewall
|
||||
|
||||
rm -rf /tmp/luci-*cache
|
||||
exit 0
|
||||
@@ -18,10 +18,11 @@ get_enabled_anonymous_secs() {
|
||||
|
||||
ipt_rule() {
|
||||
if [ "$1" = "add" ]; then
|
||||
iptables -t nat -I postrouting_rule -s ${localip%.*}.0/24 -m comment --comment "${ipt_flag}" -j MASQUERADE 2>/dev/null
|
||||
iptables -I forwarding_rule -s ${localip%.*}.0/24 -m comment --comment "${ipt_flag}" -j ACCEPT 2>/dev/null
|
||||
iptables -I input_rule -p tcp --dport 1723 -m comment --comment "${ipt_flag}" -j ACCEPT 2>/dev/null
|
||||
iptables -t mangle -I OUTPUT -p tcp --sport 1723 -m comment --comment "${ipt_flag}" -j RETURN 2>/dev/null
|
||||
iptables -w -t nat -I POSTROUTING -s ${localip%.*}.0/24 -m comment --comment "${ipt_flag}" -j MASQUERADE 2>/dev/null
|
||||
iptables -w -t nat -I POSTROUTING -d ${localip%.*}.0/24 -m comment --comment "${ipt_flag}" -j MASQUERADE 2>/dev/null
|
||||
iptables -w -I FORWARD -s ${localip%.*}.0/24 -m comment --comment "${ipt_flag}" -j ACCEPT 2>/dev/null
|
||||
iptables -w -I INPUT -p tcp --dport 1723 -m comment --comment "${ipt_flag}" -j ACCEPT 2>/dev/null
|
||||
iptables -w -t mangle -I OUTPUT -p tcp --sport 1723 -m comment --comment "${ipt_flag}" -j RETURN 2>/dev/null
|
||||
else
|
||||
ipt_del() {
|
||||
for i in $(seq 1 $($1 -nL $2 | grep -c "${ipt_flag}")); do
|
||||
@@ -29,9 +30,9 @@ ipt_rule() {
|
||||
$1 -w -D $2 $index 2>/dev/null
|
||||
done
|
||||
}
|
||||
ipt_del "iptables" "forwarding_rule"
|
||||
ipt_del "iptables" "input_rule"
|
||||
ipt_del "iptables -t nat" "postrouting_rule"
|
||||
ipt_del "iptables" "FORWARD"
|
||||
ipt_del "iptables" "INPUT"
|
||||
ipt_del "iptables -t nat" "POSTROUTING"
|
||||
ipt_del "iptables -t mangle" "OUTPUT"
|
||||
fi
|
||||
}
|
||||
@@ -50,6 +51,7 @@ gen_include() {
|
||||
$(extract_rules filter)
|
||||
$(extract_rules nat)
|
||||
EOT
|
||||
exit 0
|
||||
EOF
|
||||
return 0
|
||||
}
|
||||
|
||||
@@ -5,9 +5,16 @@ uci -q batch <<-EOF >/dev/null
|
||||
set firewall.luci_app_pptp_server=include
|
||||
set firewall.luci_app_pptp_server.type=script
|
||||
set firewall.luci_app_pptp_server.path=/var/etc/pptpd.include
|
||||
set firewall.luci_app_pptp_server.reload=1
|
||||
EOF
|
||||
|
||||
if [ -x "/sbin/fw3" ] && [ ! -L "/sbin/fw3" ]; then
|
||||
uci -q set firewall.luci_app_pptp_server.reload='1'
|
||||
else
|
||||
uci -q delete firewall.luci_app_pptp_server.reload
|
||||
uci -q delete firewall.luci_app_pptp_server.fw4_compatible
|
||||
fi
|
||||
uci commit firewall
|
||||
|
||||
/etc/init.d/pptpd disable 2>/dev/null
|
||||
/etc/init.d/pptpd stop 2>/dev/null
|
||||
rm -rf /tmp/luci-*cache
|
||||
|
||||
@@ -55,6 +55,7 @@ gen_include() {
|
||||
iptables-restore -n <<-EOT
|
||||
$(extract_rules filter)
|
||||
EOT
|
||||
exit 0
|
||||
EOF
|
||||
return 0
|
||||
}
|
||||
|
||||
@@ -5,9 +5,16 @@ uci -q batch <<-EOF >/dev/null
|
||||
set firewall.luci_app_softethervpn=include
|
||||
set firewall.luci_app_softethervpn.type=script
|
||||
set firewall.luci_app_softethervpn.path=/var/etc/luci-app-softethervpn.include
|
||||
set firewall.luci_app_softethervpn.reload=1
|
||||
EOF
|
||||
|
||||
if [ -x "/sbin/fw3" ] && [ ! -L "/sbin/fw3" ]; then
|
||||
uci -q set firewall.luci_app_softethervpn.reload='1'
|
||||
else
|
||||
uci -q delete firewall.luci_app_softethervpn.reload
|
||||
uci -q delete firewall.luci_app_softethervpn.fw4_compatible
|
||||
fi
|
||||
uci commit firewall
|
||||
|
||||
/etc/init.d/softethervpnserver stop 2>/dev/null
|
||||
/etc/init.d/softethervpnserver disable 2>/dev/null
|
||||
|
||||
|
||||
@@ -49,6 +49,7 @@ gen_include() {
|
||||
iptables-restore -n <<-EOT
|
||||
$(extract_rules filter)
|
||||
EOT
|
||||
exit 0
|
||||
EOF
|
||||
return 0
|
||||
}
|
||||
|
||||
@@ -5,9 +5,16 @@ uci -q batch <<-EOF >/dev/null
|
||||
set firewall.ssr_mudb_server=include
|
||||
set firewall.ssr_mudb_server.type=script
|
||||
set firewall.ssr_mudb_server.path=/var/etc/ssr_mudb_server.include
|
||||
set firewall.ssr_mudb_server.reload=1
|
||||
EOF
|
||||
|
||||
if [ -x "/sbin/fw3" ] && [ ! -L "/sbin/fw3" ]; then
|
||||
uci -q set firewall.ssr_mudb_server.reload='1'
|
||||
else
|
||||
uci -q delete firewall.ssr_mudb_server.reload
|
||||
uci -q delete firewall.ssr_mudb_server.fw4_compatible
|
||||
fi
|
||||
uci commit firewall
|
||||
|
||||
chmod a+x /usr/share/ssr_mudb_server/* >/dev/null 2>&1
|
||||
cp -rf /usr/bin/python3 /usr/bin/python
|
||||
rm -rf /tmp/luci-*cache
|
||||
|
||||
@@ -81,6 +81,7 @@ start(){
|
||||
iptables_w -t nat -I TIMECONTROL -i $interface -j TIMECONTROL_RULES
|
||||
iptables_w -t nat -I PREROUTING -j TIMECONTROL
|
||||
echo "/etc/init.d/${CONFIG} restart" > "/var/etc/${CONFIG}.include"
|
||||
echo "exit 0" >> "/var/etc/${CONFIG}.include"
|
||||
}
|
||||
|
||||
stop(){
|
||||
|
||||
@@ -5,8 +5,15 @@ uci -q batch <<-EOF >/dev/null
|
||||
set firewall.luci_app_timecontrol=include
|
||||
set firewall.luci_app_timecontrol.type=script
|
||||
set firewall.luci_app_timecontrol.path=/var/etc/luci-app-timecontrol.include
|
||||
set firewall.luci_app_timecontrol.reload=1
|
||||
EOF
|
||||
|
||||
if [ -x "/sbin/fw3" ] && [ ! -L "/sbin/fw3" ]; then
|
||||
uci -q set firewall.luci_app_timecontrol.reload='1'
|
||||
else
|
||||
uci -q delete firewall.luci_app_timecontrol.reload
|
||||
uci -q delete firewall.luci_app_timecontrol.fw4_compatible
|
||||
fi
|
||||
uci commit firewall
|
||||
|
||||
rm -rf /tmp/luci-*cache
|
||||
exit 0
|
||||
@@ -192,6 +192,7 @@ add_rule()
|
||||
|
||||
mkdir -p /var/etc
|
||||
echo -e "/etc/init.d/adbyby restart" > "/var/etc/adbyby.include"
|
||||
echo -e "exit 0" >> "/var/etc/adbyby.include"
|
||||
}
|
||||
|
||||
del_rule()
|
||||
|
||||
@@ -1,26 +1,29 @@
|
||||
#!/bin/sh
|
||||
|
||||
uci -q batch <<-EOF >/dev/null
|
||||
delete ucitrack.@adbyby[-1]
|
||||
add ucitrack adbyby
|
||||
set ucitrack.@adbyby[-1].init=adbyby
|
||||
commit ucitrack
|
||||
delete firewall.adblock
|
||||
add firewall rule
|
||||
rename firewall.@rule[-1]="adblock"
|
||||
set firewall.@rule[-1].name="adblock"
|
||||
set firewall.@rule[-1].target="DROP"
|
||||
set firewall.@rule[-1].src="wan"
|
||||
set firewall.@rule[-1].proto="tcp"
|
||||
set firewall.@rule[-1].dest_port="8118"
|
||||
|
||||
delete firewall.adbyby
|
||||
set firewall.adbyby=include
|
||||
set firewall.adbyby.type=script
|
||||
set firewall.adbyby.path=/var/etc/adbyby.include
|
||||
set firewall.adbyby.reload=1
|
||||
delete firewall.adblock
|
||||
add firewall rule
|
||||
rename firewall.@rule[-1]="adblock"
|
||||
set firewall.@rule[-1].name="adblock"
|
||||
set firewall.@rule[-1].target="DROP"
|
||||
set firewall.@rule[-1].src="wan"
|
||||
set firewall.@rule[-1].proto="tcp"
|
||||
set firewall.@rule[-1].dest_port="8118"
|
||||
commit firewall
|
||||
EOF
|
||||
|
||||
if [ -x "/sbin/fw3" ] && [ ! -L "/sbin/fw3" ]; then
|
||||
uci -q set firewall.adbyby.reload='1'
|
||||
else
|
||||
uci -q delete firewall.adbyby.reload
|
||||
uci -q delete firewall.adbyby.fw4_compatible
|
||||
fi
|
||||
uci commit firewall
|
||||
|
||||
mkdir -p /etc/dnsmasq.d
|
||||
|
||||
/etc/init.d/adbyby stop
|
||||
|
||||
@@ -1,12 +1,5 @@
|
||||
#!/bin/sh
|
||||
touch /etc/config/arpbind
|
||||
|
||||
uci -q batch <<-EOF >/dev/null
|
||||
delete ucitrack.@arpbind[-1]
|
||||
add ucitrack arpbind
|
||||
set ucitrack.@arpbind[-1].init=arpbind
|
||||
commit ucitrack
|
||||
EOF
|
||||
|
||||
rm -f /tmp/luci-indexcache
|
||||
exit 0
|
||||
@@ -1,11 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
uci -q batch <<-EOF >/dev/null
|
||||
delete ucitrack.@autoreboot[-1]
|
||||
add ucitrack autoreboot
|
||||
set ucitrack.@autoreboot[-1].init=autoreboot
|
||||
commit ucitrack
|
||||
EOF
|
||||
|
||||
rm -rf /tmp/luci-*
|
||||
exit 0
|
||||
@@ -1,11 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
uci -q batch <<-EOF >/dev/null
|
||||
delete ucitrack.@baidupcs-web[-1]
|
||||
add ucitrack baidupcs-web
|
||||
set ucitrack.@baidupcs-web[-1].init=baidupcs-web
|
||||
commit ucitrack
|
||||
EOF
|
||||
|
||||
rm -f /tmp/luci-indexcache
|
||||
exit 0
|
||||
@@ -1,11 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
uci -q batch <<-EOF >/dev/null
|
||||
delete ucitrack.@cifs[-1]
|
||||
add ucitrack cifs
|
||||
set ucitrack.@cifs[-1].init=cifs
|
||||
commit ucitrack
|
||||
EOF
|
||||
|
||||
rm -f /tmp/luci-indexcache
|
||||
exit 0
|
||||
@@ -1,11 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
uci -q batch <<-EOF >/dev/null
|
||||
delete ucitrack.@frp[-1]
|
||||
add ucitrack frp
|
||||
set ucitrack.@frp[-1].init=frp
|
||||
commit ucitrack
|
||||
EOF
|
||||
|
||||
rm -f /tmp/luci-indexcache
|
||||
exit 0
|
||||
@@ -1,11 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
uci -q batch <<-EOF >/dev/null
|
||||
delete ucitrack.@frps[-1]
|
||||
add ucitrack frps
|
||||
set ucitrack.@frps[-1].init=frps
|
||||
commit ucitrack
|
||||
EOF
|
||||
|
||||
rm -rf /tmp/luci-indexcache /tmp/luci-modulecache
|
||||
exit 0
|
||||
@@ -1,11 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
uci -q batch <<-EOF >/dev/null
|
||||
delete ucitrack.@mwan3helper[-1]
|
||||
add ucitrack mwan3helper
|
||||
set ucitrack.@mwan3helper[-1].init=mwan3helper
|
||||
commit ucitrack
|
||||
EOF
|
||||
|
||||
rm -f /tmp/luci*
|
||||
exit 0
|
||||
@@ -1,12 +1,5 @@
|
||||
#!/bin/sh
|
||||
|
||||
uci -q batch <<-EOF >/dev/null
|
||||
delete ucitrack.@nfs[-1]
|
||||
add ucitrack nfs
|
||||
set ucitrack.@nfs[-1].init=nfs
|
||||
commit ucitrack
|
||||
EOF
|
||||
|
||||
/etc/init.d/nfs enable && /etc/init.d/nfs restart
|
||||
|
||||
rm -f /tmp/luci-indexcache
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
uci -q batch <<-EOF >/dev/null
|
||||
delete ucitrack.@nps[-1]
|
||||
add ucitrack nps
|
||||
set ucitrack.@nps[-1].init=nps
|
||||
commit ucitrack
|
||||
EOF
|
||||
|
||||
rm -f /tmp/luci-indexcache
|
||||
exit 0
|
||||
@@ -1,12 +1,5 @@
|
||||
#!/bin/sh
|
||||
|
||||
uci -q batch <<-EOF >/dev/null
|
||||
delete ucitrack.@qbittorrent[-1]
|
||||
add ucitrack qbittorrent
|
||||
set ucitrack.@qbittorrent[-1].init=qbittorrent
|
||||
commit ucitrack
|
||||
EOF
|
||||
|
||||
mkdir /opt
|
||||
|
||||
rm -f /tmp/luci-indexcache*
|
||||
|
||||
@@ -1,12 +1,5 @@
|
||||
#!/bin/sh
|
||||
touch /etc/config/syncdial
|
||||
|
||||
uci -q batch <<-EOF >/dev/null
|
||||
delete ucitrack.@syncdial[-1]
|
||||
add ucitrack syncdial
|
||||
set ucitrack.@syncdial[-1].exec='/bin/genwancfg'
|
||||
commit ucitrack
|
||||
EOF
|
||||
|
||||
rm -f /tmp/luci-indexcache
|
||||
exit 0
|
||||
@@ -1,12 +1,5 @@
|
||||
#!/bin/sh
|
||||
|
||||
uci -q batch <<-EOF >/dev/null
|
||||
delete ucitrack.@turboacc[-1]
|
||||
add ucitrack turboacc
|
||||
set ucitrack.@turboacc[-1].init=turboacc
|
||||
commit ucitrack
|
||||
EOF
|
||||
|
||||
[ -n "$(lsmod | grep mtkhnat)" ] && \
|
||||
uci set turboacc.config.sw_flow='0' && \
|
||||
uci set turboacc.config.hw_flow='0'
|
||||
|
||||
@@ -1,12 +1,5 @@
|
||||
#!/bin/sh
|
||||
|
||||
uci -q batch <<-EOF >/dev/null
|
||||
delete ucitrack.@usb_printer[-1]
|
||||
add ucitrack usb_printer
|
||||
set ucitrack.@usb_printer[-1].init=usb_printer
|
||||
commit ucitrack
|
||||
EOF
|
||||
|
||||
[ -f /etc/init.d/p910nd ] && /etc/init.d/p910nd disable
|
||||
|
||||
exit 0
|
||||
@@ -1,11 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
uci -q batch <<-EOF >/dev/null
|
||||
delete ucitrack.@uugamebooster[-1]
|
||||
add ucitrack uugamebooster
|
||||
set ucitrack.@uugamebooster[-1].init=uugamebooster
|
||||
commit ucitrack
|
||||
EOF
|
||||
|
||||
rm -f /tmp/luci-indexcache
|
||||
exit 0
|
||||
@@ -1,11 +1,6 @@
|
||||
#!/bin/sh
|
||||
|
||||
uci -q batch <<-EOF >/dev/null
|
||||
delete ucitrack.@vlmcsd[-1]
|
||||
add ucitrack vlmcsd
|
||||
set ucitrack.@vlmcsd[-1].init=kms
|
||||
commit ucitrack
|
||||
|
||||
delete firewall.kms
|
||||
add firewall rule
|
||||
rename firewall.@rule[-1]="kms"
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
uci -q batch <<-EOF >/dev/null
|
||||
delete ucitrack.@vsftpd[-1]
|
||||
add ucitrack vsftpd
|
||||
set ucitrack.@vsftpd[-1].init=vsftpd
|
||||
commit ucitrack
|
||||
EOF
|
||||
|
||||
rm -f /tmp/luci-vsftpd
|
||||
exit 0
|
||||
@@ -5,10 +5,16 @@ uci -q batch <<-EOF >/dev/null
|
||||
set firewall.wrtbwmon=include
|
||||
set firewall.wrtbwmon.type=script
|
||||
set firewall.wrtbwmon.path='/etc/wrtbwmon.include'
|
||||
set firewall.wrtbwmon.reload=1
|
||||
commit firewall
|
||||
EOF
|
||||
|
||||
if [ -x "/sbin/fw3" ] && [ ! -L "/sbin/fw3" ]; then
|
||||
uci -q set firewall.wrtbwmon.reload='1'
|
||||
else
|
||||
uci -q delete firewall.wrtbwmon.reload
|
||||
uci -q delete firewall.wrtbwmon.fw4_compatible
|
||||
fi
|
||||
uci commit firewall
|
||||
|
||||
/etc/init.d/wrtbwmon enable
|
||||
/etc/init.d/wrtbwmon start
|
||||
exit 0
|
||||
@@ -1,6 +0,0 @@
|
||||
uci batch <<EOF
|
||||
delete ucitrack.@xlnetacc[-1]
|
||||
add ucitrack xlnetacc
|
||||
set ucitrack.@xlnetacc[-1].init=xlnetacc
|
||||
commit ucitrack
|
||||
EOF
|
||||
@@ -1,18 +1,19 @@
|
||||
#!/bin/sh
|
||||
|
||||
uci -q batch <<-EOF >/dev/null
|
||||
delete ucitrack.@zerotier[-1]
|
||||
add ucitrack zerotier
|
||||
set ucitrack.@zerotier[-1].init=zerotier
|
||||
commit ucitrack
|
||||
|
||||
delete firewall.zerotier
|
||||
set firewall.zerotier=include
|
||||
set firewall.zerotier.type=script
|
||||
set firewall.zerotier.path=/etc/zerotier.start
|
||||
set firewall.zerotier.reload=1
|
||||
commit firewall
|
||||
EOF
|
||||
|
||||
if [ -x "/sbin/fw3" ] && [ ! -L "/sbin/fw3" ]; then
|
||||
uci -q set firewall.zerotier.reload='1'
|
||||
else
|
||||
uci -q delete firewall.zerotier.reload
|
||||
uci -q delete firewall.zerotier.fw4_compatible
|
||||
fi
|
||||
uci commit firewall
|
||||
|
||||
rm -f /tmp/luci-indexcache
|
||||
exit 0
|
||||
@@ -6,10 +6,10 @@ START=90
|
||||
start(){
|
||||
if [ ! -f "/tmp/vlmcsd.pid" ]; then
|
||||
/usr/bin/vlmcsd -i /etc/vlmcsd/vlmcsd.ini -p /tmp/vlmcsd.pid -L 0.0.0.0:1688
|
||||
iptables -D input_rule -p tcp --dport 1688 -j ACCEPT
|
||||
iptables -A input_rule -p tcp --dport 1688 -j ACCEPT
|
||||
iptables -w -D INPUT -p tcp --dport 1688 -j ACCEPT
|
||||
iptables -w -A INPUT -p tcp --dport 1688 -j ACCEPT
|
||||
sed -i '/## luci-app-vlmcsd/d' /etc/firewall.user
|
||||
echo "iptables -A input_rule -p tcp --dport 1688 -j ACCEPT ## luci-app-vlmcsd" >> /etc/firewall.user
|
||||
echo "iptables -w -A INPUT -p tcp --dport 1688 -j ACCEPT ## luci-app-vlmcsd" >> /etc/firewall.user
|
||||
echo "KMS Server has started."
|
||||
else
|
||||
echo "KMS Server has already started."
|
||||
@@ -23,7 +23,7 @@ stop(){
|
||||
pid=`cat /tmp/vlmcsd.pid`
|
||||
kill $pid
|
||||
rm -f /tmp/vlmcsd.pid
|
||||
iptables -D input_rule -p tcp --dport 1688 -j ACCEPT
|
||||
iptables -w -D INPUT -p tcp --dport 1688 -j ACCEPT
|
||||
sed -i '/## luci-app-vlmcsd/d' /etc/firewall.user
|
||||
echo "KMS Server has stopped."
|
||||
fi
|
||||
|
||||
@@ -61,10 +61,6 @@ define Package/luci-app-adguardhome/prerm
|
||||
if [ -z "$${IPKG_INSTROOT}" ]; then
|
||||
/etc/init.d/AdGuardHome disable
|
||||
/etc/init.d/AdGuardHome stop
|
||||
uci -q batch <<-EOF >/dev/null 2>&1
|
||||
delete ucitrack.@AdGuardHome[-1]
|
||||
commit ucitrack
|
||||
EOF
|
||||
fi
|
||||
exit 0
|
||||
endef
|
||||
|
||||
@@ -63,13 +63,18 @@ set_iptable()
|
||||
local ipv6_server=$1
|
||||
local tcp_server=$2
|
||||
uci -q batch <<-EOF >/dev/null 2>&1
|
||||
delete firewall.AdGuardHome
|
||||
delete firewall.AdGuardHome
|
||||
set firewall.AdGuardHome=include
|
||||
set firewall.AdGuardHome.type=script
|
||||
set firewall.AdGuardHome.path=/usr/share/AdGuardHome/firewall.start
|
||||
set firewall.AdGuardHome.reload=1
|
||||
commit firewall
|
||||
EOF
|
||||
if [ -x "/sbin/fw3" ] && [ ! -L "/sbin/fw3" ]; then
|
||||
uci -q set firewall.AdGuardHome.reload='1'
|
||||
else
|
||||
uci -q delete firewall.AdGuardHome.reload
|
||||
uci -q delete firewall.AdGuardHome.fw4_compatible
|
||||
fi
|
||||
uci commit firewall
|
||||
|
||||
[ "$tcp_server" == "1" ] && iptables -t nat -I PREROUTING 1 -m comment --comment "AdGuardHome" -p tcp --dport 53 -j REDIRECT --to-ports $AdGuardHome_PORT
|
||||
iptables -t nat -I PREROUTING 1 -m comment --comment "AdGuardHome" -p udp --dport 53 -j REDIRECT --to-ports $AdGuardHome_PORT
|
||||
@@ -83,7 +88,7 @@ EOF
|
||||
clear_iptable()
|
||||
{
|
||||
uci -q batch <<-EOF >/dev/null 2>&1
|
||||
delete firewall.AdGuardHome
|
||||
delete firewall.AdGuardHome
|
||||
commit firewall
|
||||
EOF
|
||||
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
uci -q batch <<-EOF >/dev/null 2>&1
|
||||
delete ucitrack.@AdGuardHome[-1]
|
||||
add ucitrack AdGuardHome
|
||||
set ucitrack.@AdGuardHome[-1].init=AdGuardHome
|
||||
commit ucitrack
|
||||
delete AdGuardHome.AdGuardHome.ucitracktest
|
||||
EOF
|
||||
|
||||
rm -f /tmp/luci-indexcache
|
||||
exit 0
|
||||
@@ -1,4 +1,4 @@
|
||||
{
|
||||
"config": "adguardhome",
|
||||
"init": "adguardhome"
|
||||
"config": "AdGuardHome",
|
||||
"init": "AdGuardHome"
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
name: build-apk
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- 'v*'
|
||||
- 'dev-*'
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
env:
|
||||
TARGET: x86
|
||||
SUBTARGET: 64
|
||||
PKG_DIR_NAME: luci-app-adguardhome
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: 检出代码
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: 安装依赖
|
||||
run: |
|
||||
sudo apt update
|
||||
sudo apt install -y build-essential clang flex bison g++ gawk \
|
||||
gcc-multilib g++-multilib gettext git libncurses5-dev libssl-dev \
|
||||
python3-setuptools rsync swig unzip zlib1g-dev file wget zstd jq
|
||||
|
||||
- name: 下载 SDK
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
||||
echo "🔍 获取 OpenWrt 25.12 最新版本..."
|
||||
LATEST_TAG=$(
|
||||
curl -fsSL https://api.github.com/repos/openwrt/openwrt/releases?per_page=50 \
|
||||
| jq -r '.[].tag_name' \
|
||||
| grep -E '^v25\.12\.[0-9]+(-rc[0-9]+)?$' \
|
||||
| sort -V \
|
||||
| tail -n 1
|
||||
)
|
||||
|
||||
if [[ -z "${LATEST_TAG}" || "${LATEST_TAG}" == "null" ]]; then
|
||||
echo "❌ 获取 OpenWrt 25.12.x tag 失败"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
RELEASE="${LATEST_TAG#v}"
|
||||
echo "检测到 25.12 系列最新版本: ${RELEASE}"
|
||||
|
||||
echo "📥 下载 SDK..."
|
||||
BASE="https://downloads.openwrt.org/releases/${RELEASE}/targets/${TARGET}/${SUBTARGET}/"
|
||||
SDK_TARBALL=$(curl -fsSL "$BASE" | grep -o 'openwrt-sdk-[^"]*\.tar\.zst' | head -n1)
|
||||
mkdir -p _sdk
|
||||
wget -q "${BASE}${SDK_TARBALL}" -O _sdk/sdk.tar.zst
|
||||
tar --zstd -xf _sdk/sdk.tar.zst -C _sdk
|
||||
SDK_DIR="$(find "$PWD/_sdk" -maxdepth 1 -type d -name 'openwrt-sdk-*' -print -quit)"
|
||||
echo "SDK_DIR=${SDK_DIR}" >> "$GITHUB_ENV"
|
||||
echo "✅ SDK 已解压到: ${SDK_DIR}"
|
||||
|
||||
- name: 构建包
|
||||
run: |
|
||||
cd "$SDK_DIR"
|
||||
|
||||
mkdir -p package/${PKG_DIR_NAME}
|
||||
rsync -a --delete "$GITHUB_WORKSPACE/" "package/${PKG_DIR_NAME}/" \
|
||||
--exclude '.git*' --exclude '_sdk'
|
||||
|
||||
./scripts/feeds update -a
|
||||
./scripts/feeds install luci-base tar
|
||||
|
||||
touch .config
|
||||
sed -i -E '/^(# )?CONFIG_(ALL|ALL_KMODS|ALL_NONSHARED|PACKAGE_TAR_XZ|PACKAGE_luci-app-adguardhome)(=| is not set)/d' .config
|
||||
printf '%s\n' \
|
||||
'CONFIG_ALL=n' \
|
||||
'CONFIG_ALL_KMODS=n' \
|
||||
'CONFIG_ALL_NONSHARED=n' \
|
||||
'# CONFIG_PACKAGE_TAR_XZ is not set' \
|
||||
'CONFIG_PACKAGE_luci-app-adguardhome=y' >> .config
|
||||
make defconfig
|
||||
if ! grep -Eq '^CONFIG_PACKAGE_luci-app-adguardhome=(y|m)$' .config; then
|
||||
echo '::error::luci-app-adguardhome was not enabled after make defconfig'
|
||||
grep -n 'luci-app-adguardhome' .config || true
|
||||
sed -n '/^[[:space:]]*config PACKAGE_luci-app-adguardhome$/,/^[[:space:]]*help/p' tmp/.config-package.in
|
||||
exit 1
|
||||
fi
|
||||
|
||||
make package/compile -j"$(nproc)" V=sc
|
||||
|
||||
- name: 上传产物
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: pkg-${{ github.ref_name }}
|
||||
path: _sdk/**/bin/packages/**/${{ env.PKG_DIR_NAME }}*
|
||||
if-no-files-found: error
|
||||
|
||||
- name: 发布到 Releases
|
||||
uses: softprops/action-gh-release@v3
|
||||
with:
|
||||
tag_name: ${{ github.ref_name }}
|
||||
prerelease: ${{ startsWith(github.ref_name, 'dev-') }}
|
||||
make_latest: ${{ startsWith(github.ref_name, 'dev-') && 'false' || 'true' }}
|
||||
files: _sdk/**/bin/packages/**/${{ env.PKG_DIR_NAME }}*
|
||||
@@ -0,0 +1 @@
|
||||
.DS_Store
|
||||
@@ -1,56 +1,86 @@
|
||||
# Copyright (C) 2018-2019 Lienol
|
||||
#
|
||||
# This is free software, licensed under the Apache License, Version 2.0 .
|
||||
# Copyright (C) 2025 w9315273
|
||||
#
|
||||
# This is free software, licensed under the MIT License.
|
||||
#
|
||||
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=luci-app-adguardhome
|
||||
PKG_VERSION:=1.8-20221120
|
||||
PKG_VERSION:=2.4.1
|
||||
PKG_RELEASE:=1
|
||||
PKG_MAINTAINER:=<https://github.com/rufengsuixing/luci-app-adguardhome>
|
||||
|
||||
LUCI_TITLE:=LuCI app for adguardhome
|
||||
LUCI_DEPENDS:=+!wget&&!curl&&!wget-ssl:curl +adguardhome
|
||||
LUCI_PKGARCH:=all
|
||||
LUCI_DESCRIPTION:=LuCI support for adguardhome
|
||||
PKG_LICENSE:=MIT
|
||||
PKG_LICENSE_FILES:=LICENSE
|
||||
PKG_MAINTAINER:=w9315273
|
||||
PKG_BUILD_DEPENDS:=luci-base/host
|
||||
|
||||
include $(INCLUDE_DIR)/package.mk
|
||||
|
||||
define Package/luci-app-adguardhome
|
||||
SECTION:=luci
|
||||
CATEGORY:=LuCI
|
||||
SUBMENU:=3. Applications
|
||||
TITLE:=LuCI app for AdGuardHome
|
||||
PKG_MAINTAINER:=https://github.com/w9315273/luci-app-adguardhome
|
||||
PKGARCH:=all
|
||||
DEPENDS:=+luci-base +rpcd-mod-ucode +uclient-fetch +tar
|
||||
endef
|
||||
|
||||
define Package/luci-app-adguardhome/description
|
||||
LuCI support for AdGuardHome (nftables-based DNS redirect).
|
||||
This package does NOT include the AdGuardHome core binary.
|
||||
endef
|
||||
|
||||
define Build/Prepare
|
||||
endef
|
||||
|
||||
define Build/Compile
|
||||
endef
|
||||
|
||||
define Package/luci-app-adguardhome/conffiles
|
||||
/usr/share/AdGuardHome/links.txt
|
||||
/etc/config/AdGuardHome
|
||||
endef
|
||||
|
||||
define Package/luci-app-adguardhome/install
|
||||
cp -pR ./root/* $(1)/
|
||||
|
||||
$(INSTALL_DIR) $(1)/usr/lib/lua/luci/i18n
|
||||
po2lmo ./po/zh-cn/AdGuardHome.po \
|
||||
$(1)/usr/lib/lua/luci/i18n/AdGuardHome.zh-cn.lmo
|
||||
endef
|
||||
|
||||
define Package/luci-app-adguardhome/postinst
|
||||
#!/bin/sh
|
||||
/etc/init.d/AdGuardHome enable >/dev/null 2>&1
|
||||
enable=$(uci get AdGuardHome.AdGuardHome.enabled 2>/dev/null)
|
||||
if [ "$enable" == "1" ]; then
|
||||
/etc/init.d/AdGuardHome reload >/dev/null 2>&1
|
||||
fi
|
||||
rm -f /tmp/luci-indexcache
|
||||
rm -f /tmp/luci-modulecache/*
|
||||
[ -n "$${IPKG_INSTROOT}" ] && exit 0
|
||||
|
||||
/etc/init.d/AdGuardHome enable >/dev/null 2>&1
|
||||
|
||||
enable=$$(uci get AdGuardHome.AdGuardHome.enabled 2>/dev/null)
|
||||
if [ "$$enable" = "1" ]; then
|
||||
/etc/init.d/AdGuardHome reload
|
||||
fi
|
||||
|
||||
rm -f /tmp/luci-indexcache
|
||||
rm -f /tmp/luci-modulecache/*
|
||||
/etc/init.d/rpcd reload
|
||||
|
||||
exit 0
|
||||
endef
|
||||
|
||||
define Package/luci-app-adguardhome/prerm
|
||||
#!/bin/sh
|
||||
if [ -z "$${IPKG_INSTROOT}" ]; then
|
||||
/etc/init.d/AdGuardHome disable
|
||||
/etc/init.d/AdGuardHome stop >/dev/null 2>&1
|
||||
uci -q batch <<-EOF >/dev/null 2>&1
|
||||
delete ucitrack.@AdGuardHome[-1]
|
||||
commit ucitrack
|
||||
/etc/init.d/AdGuardHome disable
|
||||
/etc/init.d/AdGuardHome stop 2>/dev/null || true
|
||||
|
||||
uci -q batch <<-EOF >/dev/null 2>&1
|
||||
delete ucitrack.@AdGuardHome[-1]
|
||||
commit ucitrack
|
||||
EOF
|
||||
fi
|
||||
|
||||
exit 0
|
||||
endef
|
||||
|
||||
define Package/luci-app-adguardhome/postrm
|
||||
#!/bin/sh
|
||||
rm -rf /etc/AdGuardHome/
|
||||
exit 0
|
||||
endef
|
||||
|
||||
include $(TOPDIR)/feeds/luci/luci.mk
|
||||
|
||||
# call BuildPackage - OpenWrt buildroot signature
|
||||
$(eval $(call BuildPackage,luci-app-adguardhome))
|
||||
@@ -1,93 +1,39 @@
|
||||
# luci-app-adguardhome
|
||||
复杂的AdGuardHome的openwrt的luci界面
|
||||
|
||||
- 可以管理网页端口
|
||||
- luci下载/更新核心版本(支持自定义链接下载)
|
||||
- 如果为tar.gz文件需要与官方的文件结构一致
|
||||
- 或者直接为主程序二进制
|
||||
- upx 压缩核心(xz依赖,脚本自动下载,如果opkg源无法连接,请在编译时加入此包)
|
||||
- dns重定向
|
||||
- 作为dnsmasq的上游服务器(在AGH中统计到的ip都为127.0.0.1,无法统计客户端及对应调整设置,ssr-plus正常)
|
||||
- 重定向53端口到 AdGuardHome(ipv6需要开启ipv6 nat redirect 否则如果客户端使用ipv6过滤无效,不以dnsmasq为上游ssr-plus失效)
|
||||
- 使用53端口替换 dnsmasq(需要设置AGH的dnsip为0.0.0.0, AGH和dnsmasq的端口将被交换,不以dnsmasq为上游ssr-plus失效)
|
||||
- 自定义执行文件路径(支持tmp,每次重启后自动下载bin)
|
||||
- 自定义配置文件路径
|
||||
- 自定义工作路径
|
||||
- 自定义运行日志路径
|
||||
- gfwlist 删除/添加/定义上游dns服务器 另外安利一下https://github.com/rufengsuixing/luci-app-autoipsetadder
|
||||
- 修改网页登陆密码
|
||||
- 倒序/正序 查看/删除/备份 每3秒更新显示运行日志 + 本地浏览器时区转换
|
||||
- 手动修改配置文件
|
||||
- 支持yaml编辑器
|
||||
- 模板快速配置
|
||||
- 系统升级保留勾选文件
|
||||
- 开机启动后当网络准备好时重启adh(3分钟超时,主要用于防止过滤器更新失败)
|
||||
- 关机时备份勾选的工作目录中的文件(须知:在ipk更新的时候也会触发备份)
|
||||
- 计划任务(以下为默认值,时间和参数可以在计划任务中调整)
|
||||
- 自动更新核心(最好谨慎使用)(3:30/天)
|
||||
- 自动截短查询日志 (每小时 限制到2000行)
|
||||
- 自动截短运行日志(3:30/天 限制到2000行)
|
||||
- 自动更新ipv6主机并重启adh (每小时,无更新不重启)
|
||||
- 自动更新gfw列表并重启adh (3:30/天,无更新不重启)
|
||||
#### 已知问题:
|
||||
- db数据库不支持放在不支持mmap的文件系统上比如 jffs2 data-stk-oo,请修改工作目录,本软件如果检测到jffs2会自动ln(软连接)到/tmp,将会导致重启丢失dns数据库
|
||||
- ~~AdGuardHome 不支持ipset 设置,在使用ipset的情况下,无法替代dnsmasq只能作为dnsmasq上游存在,如果你想要这个功能就去投票吧<br>
|
||||
https://github.com/AdguardTeam/AdGuardHome/issues/1191~~
|
||||
- 反馈出现大量127.0.0.1查询了localhost的请求,问题出现原因是ddns插件,如果不用ddns插件,请删除或者注释掉\etc\hotplug.d\iface\95-ddns的内容,如果还有其他来自本机的异常查询情况,高级玩家可以使用kmod来查找原因https://github.com/rufengsuixing/kmod-plog-port
|
||||
- 如果出现需要多次提交才有反应的现象请及时提交issue
|
||||
#### 使用方法
|
||||
- 下载release,使用opkg安装即可
|
||||
- 或者编译op时clone本项目加入软件包并勾选
|
||||
#### 关于压缩
|
||||
本着较真的想法,我测试了在jffs2的压缩文件系统上进行upx压缩结果的内存占用与空间占用(单位kb,使用最好压缩)<br>
|
||||
文件大小<br>
|
||||
源文件 14112 使用upx 压缩后 5309 <br>
|
||||
实际占用 6260 使用upx 压缩后 5324 差值为 936<br>
|
||||
VmRSS运存占用值<br>
|
||||
不压缩 14380 使用upx 压缩后 18496 差值 -4116 <br>
|
||||
对于压缩文件系统来说开启收益有,但不大<br>
|
||||
如果是非压缩文件系统,性价比还是比较高的<br>
|
||||
所以压缩是用运存空间来换rom空间,觉得值得就可以开启
|
||||
#### 关于ssr配合
|
||||
- 方法一gfw代理:dns重定向-作为dnsmasq的上游服务器
|
||||
- 方法二gfw代理:手动设置adh上游dns为自己即127.0.0.1:[自己监听的端口],然后使用 dns重定向-使用53端口替换dnsmasq,(因为端口互换后就是dnsmasq为上游了)
|
||||
- 方法三国外ip代理:任意重定向方式,adh加入gfw列表,开启计划任务定时更新gfw即可
|
||||
- 方法四gfw代理:dns重定向-重定向53端口到AdGuardHome,设置adh上游dns 为127.0.0.1:53
|
||||
#### 项目已经基本稳定,有bug欢迎主动反馈
|
||||
基于原版 `luci-app-adguardhome` 修改,主要针对现代 OpenWrt 环境进行了 `nftables` 适配,并从 **v2.4.0** 开始完成 LuCI 前端 JavaScript 化。
|
||||
|
||||
Complex openwrt AdGuardHome luci
|
||||
当前 `main` 分支为 JavaScript 版本,旧版 Lua 实现保留在 [`lua`](https://github.com/w9315273/luci-app-adguardhome/tree/lua) 分支。
|
||||
|
||||
- can manage browser port
|
||||
- download/update core in luci
|
||||
- compress core with upx
|
||||
- redirect dns
|
||||
- as the upstream of dnsmasq
|
||||
- redirect port 53 to AdGuardHome(ipv6 need to install ipv6 nat redirect or if client use ipv6 redirect is invalid)
|
||||
- replace dnsmasq with port 53 (need to set AGH,dnsip=0.0.0.0,the port of dnsmasq and AGH will be exchange)
|
||||
- change bin path
|
||||
- change config path
|
||||
- change work dir(support tmp,auto redownload after reboot)
|
||||
- change runtime log path
|
||||
- gfwlist query to specific dns server
|
||||
- modify browser login passord
|
||||
- Positive/reverse order see/del/backup runtime log which update every 3 second
|
||||
- modify config manually(support yaml editor)
|
||||
- use template to fast config(when no config file)
|
||||
- Keep bin file and config when system upgrade (database and querylog can be choose)
|
||||
- when boot wait for network access (3min timeout)
|
||||
- backup workdir when shutdown
|
||||
#### known issues:
|
||||
- db database not support filesystem which not support mmap such as jffs2 and data-stk-oo,please modify work dir,if jffs2 is found,will auto ln (soft link)the dbs to /tmp ,will lost dns database after reboot
|
||||
- ~~AdGuardhome not support ipset,when we use ipset ,it can\`t be the repacement of dnsmasq but the upstream of dnsmasq ,if you want it,vote for it.<br>
|
||||
https://github.com/AdguardTeam/AdGuardHome/issues/1191<br>~~
|
||||
- find so many localhost query from 127.0.0.1,the ddns plugin is the reason,if you don\`t use ddns, please remove or comment \etc\hotplug.d\iface\95-ddns
|
||||
#### usage
|
||||
- download release,install it with opkg
|
||||
- or when make op,clone the code to the package path and set it as y or m
|
||||
## 主要变化
|
||||
|
||||
#### pic
|
||||
example in zh-cn:<br>
|
||||

|
||||

|
||||

|
||||

|
||||
### v2.4.0 — LuCI JavaScript 迁移
|
||||
|
||||
从 **v2.4.0** 开始,LuCI 页面由传统 Lua CBI / HTM 架构迁移至 JavaScript。
|
||||
|
||||
- LuCI 页面由 Lua CBI / HTM 迁移到 JavaScript
|
||||
- 后端接口迁移到 `rpcd + ucode`
|
||||
- 使用 LuCI RPC ACL 控制前后端权限
|
||||
- 删除旧的 `luasrc/controller`、`luasrc/model/cbi` 和 HTM 页面
|
||||
- 保留原有 AdGuardHome 配置方式与主要功能
|
||||
- 优化 YAML 配置编辑与配置检查
|
||||
|
||||
### nftables DNS 重定向
|
||||
|
||||
将原版的 DNS 重定向实现从 `iptables` 迁移到 `nftables`,核心使用方式保持不变。
|
||||
|
||||
### WAN 设备排除
|
||||
|
||||
从 **v2.2.0** 开始,可直接在 LuCI 界面的 **WAN 接口** 选项中选择需要排除的网卡,无需手动编辑 `adguardhome.nft.tpl`。
|
||||
|
||||
该选项仅在 **「重定向」模式** 下生效,用于避免将来自公网接口的 DNS 请求重定向到本机,从而防止 AdGuardHome 被暴露为公共 DNS 解析器。
|
||||
|
||||
请仅选择直接面向公网的接口,例如:
|
||||
|
||||
- `eth0`
|
||||
- `pppoe-wan`
|
||||
|
||||
## 界面
|
||||
|
||||
<img width="677" height="695" src="https://github.com/user-attachments/assets/4b436eec-8e05-4bf6-82d9-a972164e9659" />
|
||||
|
||||
<img width="536" height="714" src="https://github.com/user-attachments/assets/575c2d6c-e289-425d-91b9-faf01b5a7262" />
|
||||
@@ -0,0 +1,34 @@
|
||||
#!/bin/sh
|
||||
set -e
|
||||
|
||||
REPO="w9315273/luci-app-adguardhome"
|
||||
|
||||
echo "Getting latest version..."
|
||||
TAG=$(uclient-fetch -qO- "https://api.github.com/repos/${REPO}/releases/latest" 2>/dev/null \
|
||||
| sed -n 's/.*"tag_name":[[:space:]]*"\([^"]*\)".*/\1/p' | head -n1)
|
||||
|
||||
[ -n "$TAG" ] || { echo "ERROR: Failed to get latest version"; exit 1; }
|
||||
|
||||
case "$TAG" in
|
||||
*-*) ;;
|
||||
*) echo "ERROR: Unexpected tag format: $TAG"; exit 1 ;;
|
||||
esac
|
||||
|
||||
VERSION=${TAG#v}
|
||||
VERSION=${VERSION%-*}-r${VERSION##*-}
|
||||
|
||||
URL="https://github.com/${REPO}/releases/download/${TAG}/luci-app-adguardhome-${VERSION}.apk"
|
||||
|
||||
echo "Version: $VERSION"
|
||||
echo "Downloading..."
|
||||
trap 'rm -f /tmp/agh.apk' EXIT
|
||||
uclient-fetch -qO /tmp/agh.apk "$URL"
|
||||
|
||||
echo "Installing..."
|
||||
apk add --allow-untrusted /tmp/agh.apk
|
||||
|
||||
echo "Refreshing LuCI..."
|
||||
rm -f /tmp/luci-indexcache /tmp/luci-modulecache/* 2>/dev/null
|
||||
/etc/init.d/rpcd reload >/dev/null 2>&1
|
||||
|
||||
echo "Done."
|
||||
@@ -1,147 +0,0 @@
|
||||
module("luci.controller.AdGuardHome",package.seeall)
|
||||
local fs=require"nixio.fs"
|
||||
local http=require"luci.http"
|
||||
local uci=require"luci.model.uci".cursor()
|
||||
function index()
|
||||
entry({"admin", "services", "AdGuardHome"},alias("admin", "services", "AdGuardHome", "base"),_("AdGuard Home"), 10).dependent = true
|
||||
entry({"admin","services","AdGuardHome","base"},cbi("AdGuardHome/base"),_("Base Setting"),1).leaf = true
|
||||
entry({"admin","services","AdGuardHome","log"},form("AdGuardHome/log"),_("Log"),2).leaf = true
|
||||
entry({"admin","services","AdGuardHome","manual"},cbi("AdGuardHome/manual"),_("Manual Config"),3).leaf = true
|
||||
entry({"admin","services","AdGuardHome","status"},call("act_status")).leaf=true
|
||||
entry({"admin", "services", "AdGuardHome", "check"}, call("check_update"))
|
||||
entry({"admin", "services", "AdGuardHome", "doupdate"}, call("do_update"))
|
||||
entry({"admin", "services", "AdGuardHome", "getlog"}, call("get_log"))
|
||||
entry({"admin", "services", "AdGuardHome", "dodellog"}, call("do_dellog"))
|
||||
entry({"admin", "services", "AdGuardHome", "reloadconfig"}, call("reload_config"))
|
||||
entry({"admin", "services", "AdGuardHome", "gettemplateconfig"}, call("get_template_config"))
|
||||
end
|
||||
function get_template_config()
|
||||
local b
|
||||
local d=""
|
||||
local rcauto=uci:get("dhcp","@dnsmasq[0]","resolvfile")
|
||||
if (rcauto == nil) then
|
||||
for fle in fs.dir("/var/etc") do
|
||||
if fle ~="." and fle ~=".."then
|
||||
tf="/var/etc/"..fle
|
||||
if string.match(tf,"/var/etc/dnsmasq.conf.") then
|
||||
if tf and fs.access(tf) then
|
||||
for le in io.lines(tf) do
|
||||
sf=string.match (le,"^resolv%-file=(%S+)")
|
||||
if (sf ~=nil) then
|
||||
rcauto=sf
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
if rcauto and fs.access(rcauto) then
|
||||
for cnt in io.lines(rcauto) do
|
||||
b=string.match (cnt,"^[^#]*nameserver%s+([^%s]+)$")
|
||||
if (b~=nil) then
|
||||
d=d.." - "..b.."\n"
|
||||
end
|
||||
end
|
||||
end
|
||||
local f=io.open("/usr/share/AdGuardHome/AdGuardHome_template.yaml", "r+")
|
||||
local tbl = {}
|
||||
local a=""
|
||||
while (1) do
|
||||
a=f:read("*l")
|
||||
if (a=="#bootstrap_dns") then
|
||||
a=d
|
||||
elseif (a=="#upstream_dns") then
|
||||
a=d
|
||||
elseif (a==nil) then
|
||||
break
|
||||
end
|
||||
table.insert(tbl, a)
|
||||
end
|
||||
f:close()
|
||||
http.prepare_content("text/plain; charset=utf-8")
|
||||
http.write(table.concat(tbl, "\n"))
|
||||
end
|
||||
function reload_config()
|
||||
fs.remove("/tmp/AdGuardHometmpconfig.yaml")
|
||||
http.prepare_content("application/json")
|
||||
http.write('')
|
||||
end
|
||||
function act_status()
|
||||
local e={}
|
||||
local binpath=uci:get("AdGuardHome","AdGuardHome","binpath")
|
||||
e.running=luci.sys.call("pgrep "..binpath.." >/dev/null")==0
|
||||
e.redirect=(fs.readfile("/var/run/AdGredir")=="1")
|
||||
http.prepare_content("application/json")
|
||||
http.write_json(e)
|
||||
end
|
||||
function do_update()
|
||||
fs.writefile("/var/run/lucilogpos","0")
|
||||
http.prepare_content("application/json")
|
||||
http.write('')
|
||||
local arg
|
||||
if luci.http.formvalue("force") == "1" then
|
||||
arg="force"
|
||||
else
|
||||
arg=""
|
||||
end
|
||||
if fs.access("/var/run/update_core") then
|
||||
if arg=="force" then
|
||||
luci.sys.exec("kill $(pgrep /usr/share/AdGuardHome/update_core.sh) ; sh /usr/share/AdGuardHome/update_core.sh "..arg.." >/tmp/AdGuardHome_update.log 2>&1 &")
|
||||
end
|
||||
else
|
||||
luci.sys.exec("sh /usr/share/AdGuardHome/update_core.sh "..arg.." >/tmp/AdGuardHome_update.log 2>&1 &")
|
||||
end
|
||||
end
|
||||
function get_log()
|
||||
local logfile=uci:get("AdGuardHome","AdGuardHome","logfile")
|
||||
if (logfile==nil) then
|
||||
http.write("no log available\n")
|
||||
return
|
||||
elseif (logfile=="syslog") then
|
||||
if not fs.access("/var/run/AdGuardHomesyslog") then
|
||||
luci.sys.exec("(/usr/share/AdGuardHome/getsyslog.sh &); sleep 1;")
|
||||
end
|
||||
logfile="/tmp/AdGuardHometmp.log"
|
||||
fs.writefile("/var/run/AdGuardHomesyslog","1")
|
||||
elseif not fs.access(logfile) then
|
||||
http.write("")
|
||||
return
|
||||
end
|
||||
http.prepare_content("text/plain; charset=utf-8")
|
||||
local fdp
|
||||
if fs.access("/var/run/lucilogreload") then
|
||||
fdp=0
|
||||
fs.remove("/var/run/lucilogreload")
|
||||
else
|
||||
fdp=tonumber(fs.readfile("/var/run/lucilogpos")) or 0
|
||||
end
|
||||
local f=io.open(logfile, "r+")
|
||||
f:seek("set",fdp)
|
||||
local a=f:read(2048000) or ""
|
||||
fdp=f:seek()
|
||||
fs.writefile("/var/run/lucilogpos",tostring(fdp))
|
||||
f:close()
|
||||
http.write(a)
|
||||
end
|
||||
function do_dellog()
|
||||
local logfile=uci:get("AdGuardHome","AdGuardHome","logfile")
|
||||
fs.writefile(logfile,"")
|
||||
http.prepare_content("application/json")
|
||||
http.write('')
|
||||
end
|
||||
function check_update()
|
||||
http.prepare_content("text/plain; charset=utf-8")
|
||||
local fdp=tonumber(fs.readfile("/var/run/lucilogpos")) or 0
|
||||
local f=io.open("/tmp/AdGuardHome_update.log", "r+")
|
||||
f:seek("set",fdp)
|
||||
local a=f:read(2048000) or ""
|
||||
fdp=f:seek()
|
||||
fs.writefile("/var/run/lucilogpos",tostring(fdp))
|
||||
f:close()
|
||||
if fs.access("/var/run/update_core") then
|
||||
http.write(a)
|
||||
else
|
||||
http.write(a.."\0")
|
||||
end
|
||||
end
|
||||
@@ -1,360 +0,0 @@
|
||||
require("luci.sys")
|
||||
require("luci.util")
|
||||
require("io")
|
||||
local m,s,o,o1
|
||||
local fs=require"nixio.fs"
|
||||
local uci=require"luci.model.uci".cursor()
|
||||
local configpath=uci:get("AdGuardHome","AdGuardHome","configpath") or "/etc/AdGuardHome.yaml"
|
||||
local binpath=uci:get("AdGuardHome","AdGuardHome","binpath") or "/usr/bin/AdGuardHome"
|
||||
httpport=uci:get("AdGuardHome","AdGuardHome","httpport") or "3000"
|
||||
m = Map("AdGuardHome", "AdGuard Home")
|
||||
m.description = translate("Free and open source, powerful network-wide ads & trackers blocking DNS server.")
|
||||
m:section(SimpleSection).template = "AdGuardHome/AdGuardHome_status"
|
||||
|
||||
s = m:section(TypedSection, "AdGuardHome")
|
||||
s.anonymous=true
|
||||
s.addremove=false
|
||||
---- enable
|
||||
o = s:option(Flag, "enabled", translate("Enable"))
|
||||
o.default = 0
|
||||
o.optional = false
|
||||
---- httpport
|
||||
o =s:option(Value,"httpport",translate("Browser management port"))
|
||||
o.placeholder=3000
|
||||
o.default=3000
|
||||
o.datatype="port"
|
||||
o.optional = false
|
||||
o.description = translate("<input type=\"button\" style=\"width:210px;border-color:Teal; text-align:center;font-weight:bold;color:Green;\" value=\"AdGuardHome Web:"..httpport.."\" onclick=\"window.open('http://'+window.location.hostname+':"..httpport.."/')\"/>")
|
||||
---- update warning not safe
|
||||
local binmtime=uci:get("AdGuardHome","AdGuardHome","binmtime") or "0"
|
||||
local e=""
|
||||
if not fs.access(configpath) then
|
||||
e=e.." "..translate("no config")
|
||||
end
|
||||
if not fs.access(binpath) then
|
||||
e=e.." "..translate("no core")
|
||||
else
|
||||
local version=uci:get("AdGuardHome","AdGuardHome","version")
|
||||
local testtime=fs.stat(binpath,"mtime")
|
||||
if testtime~=tonumber(binmtime) or version==nil then
|
||||
local tmp=luci.sys.exec(binpath.." --version 2>/dev/null | grep -m 1 -E '[0-9]+[.][Bbeta0-9\.\-]+' -o")
|
||||
version=string.sub(tmp, 1, -2)
|
||||
if version=="" then version="core error" end
|
||||
uci:set("AdGuardHome","AdGuardHome","version",version)
|
||||
uci:set("AdGuardHome","AdGuardHome","binmtime",testtime)
|
||||
uci:commit("AdGuardHome")
|
||||
end
|
||||
e=version..e
|
||||
end
|
||||
o=s:option(Button,"restart",translate("Update"))
|
||||
o.inputtitle=translate("Update core version")
|
||||
o.template = "AdGuardHome/AdGuardHome_check"
|
||||
o.showfastconfig=(not fs.access(configpath))
|
||||
o.description=string.format(translate("core version:").."<strong><font id=\"updateversion\" color=\"green\">%s </font></strong>",e)
|
||||
---- port warning not safe
|
||||
local port=luci.sys.exec("awk '/^dns:/ {found_dns=1} found_dns && /^ port:/ {print $2; exit}' "..configpath.." 2>nul")
|
||||
if (port=="") then port="?" end
|
||||
---- Redirect
|
||||
o = s:option(ListValue, "redirect", port..translate("Redirect"), translate("AdGuardHome redirect mode"))
|
||||
o.placeholder = "none"
|
||||
o:value("none", translate("none"))
|
||||
o:value("dnsmasq-upstream", translate("Run as dnsmasq upstream server"))
|
||||
o:value("redirect", translate("Redirect 53 port to AdGuardHome"))
|
||||
o:value("exchange", translate("Use port 53 replace dnsmasq"))
|
||||
o.default = "none"
|
||||
o.optional = true
|
||||
---- bin path
|
||||
o = s:option(Value, "binpath", translate("Bin Path"), translate("AdGuardHome Bin path if no bin will auto download"))
|
||||
o.default = "/usr/bin/AdGuardHome"
|
||||
o.datatype = "string"
|
||||
o.optional = false
|
||||
o.rmempty=false
|
||||
o.validate=function(self, value)
|
||||
if value=="" then return nil end
|
||||
if fs.stat(value,"type")=="dir" then
|
||||
fs.rmdir(value)
|
||||
end
|
||||
if fs.stat(value,"type")=="dir" then
|
||||
if (m.message) then
|
||||
m.message =m.message.."\nerror!bin path is a dir"
|
||||
else
|
||||
m.message ="error!bin path is a dir"
|
||||
end
|
||||
return nil
|
||||
end
|
||||
return value
|
||||
end
|
||||
--- arch
|
||||
o = s:option(ListValue, "arch", translate("choose Arch for download"))
|
||||
o:value("",translate("Auto"))
|
||||
o:value("386",translate("i386"))
|
||||
o:value("amd64",translate("x86_64"))
|
||||
o:value("armv5",translate("armv5"))
|
||||
o:value("armv6",translate("armv6"))
|
||||
o:value("armv7",translate("armv7"))
|
||||
o:value("arm64",translate("aarch64"))
|
||||
o:value("mips_softfloat",translate("mips"))
|
||||
o:value("mips64_softfloat",translate("mips64"))
|
||||
o:value("mipsle_softfloat",translate("mipsel"))
|
||||
o:value("mips64le_softfloat",translate("mips64el"))
|
||||
o:value("ppc64le",translate("powerpc64"))
|
||||
o.description=translate("Need to save to config first before downloading.")
|
||||
o.default=""
|
||||
o.rmempty=true
|
||||
|
||||
--- upx
|
||||
o = s:option(ListValue, "upxflag", translate("use upx to compress bin after download"))
|
||||
o:value("", translate("none"))
|
||||
o:value("-1", translate("compress faster"))
|
||||
o:value("-9", translate("compress better"))
|
||||
o:value("--best", translate("compress best(can be slow for big files)"))
|
||||
o:value("--brute", translate("try all available compression methods & filters [slow]"))
|
||||
o:value("--ultra-brute", translate("try even more compression variants [very slow]"))
|
||||
o.default = ""
|
||||
o.description=translate("bin use less space,but may have compatibility issues")
|
||||
o.rmempty = true
|
||||
---- config path
|
||||
o = s:option(Value, "configpath", translate("Config Path"), translate("AdGuardHome config path"))
|
||||
o.default = "/etc/AdGuardHome.yaml"
|
||||
o.datatype = "string"
|
||||
o.optional = false
|
||||
o.rmempty=false
|
||||
o.validate=function(self, value)
|
||||
if value==nil then return nil end
|
||||
if fs.stat(value,"type")=="dir" then
|
||||
fs.rmdir(value)
|
||||
end
|
||||
if fs.stat(value,"type")=="dir" then
|
||||
if m.message then
|
||||
m.message =m.message.."\nerror!config path is a dir"
|
||||
else
|
||||
m.message ="error!config path is a dir"
|
||||
end
|
||||
return nil
|
||||
end
|
||||
return value
|
||||
end
|
||||
---- work dir
|
||||
o = s:option(Value, "workdir", translate("Work dir"), translate("AdGuardHome work dir include rules,audit log and database"))
|
||||
o.default = "/etc/AdGuardHome"
|
||||
o.datatype = "string"
|
||||
o.optional = false
|
||||
o.rmempty=false
|
||||
o.validate=function(self, value)
|
||||
if value=="" then return nil end
|
||||
if fs.stat(value,"type")=="reg" then
|
||||
if m.message then
|
||||
m.message =m.message.."\nerror!work dir is a file"
|
||||
else
|
||||
m.message ="error!work dir is a file"
|
||||
end
|
||||
return nil
|
||||
end
|
||||
if string.sub(value, -1)=="/" then
|
||||
return string.sub(value, 1, -2)
|
||||
else
|
||||
return value
|
||||
end
|
||||
end
|
||||
---- log file
|
||||
o = s:option(Value, "logfile", translate("Runtime log file"), translate("AdGuardHome runtime Log file if 'syslog': write to system log;if empty no log"))
|
||||
o.datatype = "string"
|
||||
o.rmempty = true
|
||||
o.validate=function(self, value)
|
||||
if fs.stat(value,"type")=="dir" then
|
||||
fs.rmdir(value)
|
||||
end
|
||||
if fs.stat(value,"type")=="dir" then
|
||||
if m.message then
|
||||
m.message =m.message.."\nerror!log file is a dir"
|
||||
else
|
||||
m.message ="error!log file is a dir"
|
||||
end
|
||||
return nil
|
||||
end
|
||||
return value
|
||||
end
|
||||
---- debug
|
||||
o = s:option(Flag, "verbose", translate("Verbose log"))
|
||||
o.default = 0
|
||||
o.optional = true
|
||||
---- gfwlist
|
||||
local a
|
||||
if fs.access(configpath) then
|
||||
a=luci.sys.call("grep -m 1 -q programadd "..configpath)
|
||||
else
|
||||
a=1
|
||||
end
|
||||
if (a==0) then
|
||||
a="Added"
|
||||
else
|
||||
a="Not added"
|
||||
end
|
||||
o=s:option(Button,"gfwdel",translate("Del gfwlist"),translate(a))
|
||||
o.optional = true
|
||||
o.inputtitle=translate("Del")
|
||||
o.write=function()
|
||||
luci.sys.exec("sh /usr/share/AdGuardHome/gfw2adg.sh del 2>&1")
|
||||
luci.http.redirect(luci.dispatcher.build_url("admin","services","AdGuardHome"))
|
||||
end
|
||||
o=s:option(Button,"gfwadd",translate("Add gfwlist"),translate(a))
|
||||
o.optional = true
|
||||
o.inputtitle=translate("Add")
|
||||
o.write=function()
|
||||
luci.sys.exec("sh /usr/share/AdGuardHome/gfw2adg.sh 2>&1")
|
||||
luci.http.redirect(luci.dispatcher.build_url("admin","services","AdGuardHome"))
|
||||
end
|
||||
if fs.access(configpath) then
|
||||
a=luci.sys.call("grep -m 1 -q ipset.txt "..configpath)
|
||||
else
|
||||
a=1
|
||||
end
|
||||
if (a==0) then
|
||||
a="Added"
|
||||
else
|
||||
a="Not added"
|
||||
end
|
||||
o=s:option(Button,"gfwipsetdel",translate("Del gfwlist")..translate("(ipset only)"),translate(a))
|
||||
o.optional = true
|
||||
o.inputtitle=translate("Del")
|
||||
o.write=function()
|
||||
luci.sys.exec("sh /usr/share/AdGuardHome/gfwipset2adg.sh del 2>&1")
|
||||
luci.http.redirect(luci.dispatcher.build_url("admin","services","AdGuardHome"))
|
||||
end
|
||||
o=s:option(Button,"gfwipsetadd",translate("Add gfwlist")..translate("(ipset only)"),translate(a).." "..translate("will set to name gfwlist"))
|
||||
o.optional = true
|
||||
o.inputtitle=translate("Add")
|
||||
o.write=function()
|
||||
luci.sys.exec("sh /usr/share/AdGuardHome/gfwipset2adg.sh 2>&1")
|
||||
luci.http.redirect(luci.dispatcher.build_url("admin","services","AdGuardHome"))
|
||||
end
|
||||
o = s:option(Value, "gfwupstream", translate("Gfwlist upstream dns server"), translate("Gfwlist domain upstream dns service")..translate(a))
|
||||
o.default = "tcp://208.67.220.220:5353"
|
||||
o.datatype = "string"
|
||||
o.optional = true
|
||||
---- chpass
|
||||
o = s:option(Value, "hashpass", translate("Change browser management password"), translate("Press load culculate model and culculate finally save/apply"))
|
||||
o.default = ""
|
||||
o.datatype = "string"
|
||||
o.template = "AdGuardHome/AdGuardHome_chpass"
|
||||
o.optional = true
|
||||
---- upgrade protect
|
||||
o = s:option(MultiValue, "upprotect", translate("Keep files when system upgrade"))
|
||||
o:value("$binpath",translate("core bin"))
|
||||
o:value("$configpath",translate("config file"))
|
||||
o:value("$logfile",translate("log file"))
|
||||
o:value("$workdir/data/sessions.db",translate("sessions.db"))
|
||||
o:value("$workdir/data/stats.db",translate("stats.db"))
|
||||
o:value("$workdir/data/querylog.json",translate("querylog.json"))
|
||||
o:value("$workdir/data/filters",translate("filters"))
|
||||
o.widget = "checkbox"
|
||||
o.default = nil
|
||||
o.optional=true
|
||||
---- wait net on boot
|
||||
o = s:option(Flag, "waitonboot", translate("On boot when network ok restart"))
|
||||
o.default = 1
|
||||
o.optional = true
|
||||
---- backup workdir on shutdown
|
||||
local workdir=uci:get("AdGuardHome","AdGuardHome","workdir") or "/etc/AdGuardHome"
|
||||
o = s:option(MultiValue, "backupfile", translate("Backup workdir files when shutdown"))
|
||||
o1 = s:option(Value, "backupwdpath", translate("Backup workdir path"))
|
||||
local name
|
||||
o:value("filters","filters")
|
||||
o:value("stats.db","stats.db")
|
||||
o:value("querylog.json","querylog.json")
|
||||
o:value("sessions.db","sessions.db")
|
||||
o1:depends ("backupfile", "filters")
|
||||
o1:depends ("backupfile", "stats.db")
|
||||
o1:depends ("backupfile", "querylog.json")
|
||||
o1:depends ("backupfile", "sessions.db")
|
||||
for name in fs.glob(workdir.."/data/*")
|
||||
do
|
||||
name=fs.basename (name)
|
||||
if name~="filters" and name~="stats.db" and name~="querylog.json" and name~="sessions.db" then
|
||||
o:value(name,name)
|
||||
o1:depends ("backupfile", name)
|
||||
end
|
||||
end
|
||||
o.widget = "checkbox"
|
||||
o.default = nil
|
||||
o.optional=false
|
||||
o.description=translate("Will be restore when workdir/data is empty")
|
||||
----backup workdir path
|
||||
|
||||
o1.default = "/etc/AdGuardHome"
|
||||
o1.datatype = "string"
|
||||
o1.optional = false
|
||||
o1.validate=function(self, value)
|
||||
if fs.stat(value,"type")=="reg" then
|
||||
if m.message then
|
||||
m.message =m.message.."\nerror!backup dir is a file"
|
||||
else
|
||||
m.message ="error!backup dir is a file"
|
||||
end
|
||||
return nil
|
||||
end
|
||||
if string.sub(value,-1)=="/" then
|
||||
return string.sub(value, 1, -2)
|
||||
else
|
||||
return value
|
||||
end
|
||||
end
|
||||
|
||||
----Crontab
|
||||
o = s:option(MultiValue, "crontab", translate("Crontab task"),translate("Please change time and args in crontab"))
|
||||
o:value("autoupdate",translate("Auto update core"))
|
||||
o:value("cutquerylog",translate("Auto tail querylog"))
|
||||
o:value("cutruntimelog",translate("Auto tail runtime log"))
|
||||
o:value("autohost",translate("Auto update ipv6 hosts and restart adh"))
|
||||
o:value("autogfw",translate("Auto update gfwlist and restart adh"))
|
||||
o:value("autogfwipset",translate("Auto update ipset list and restart adh"))
|
||||
o.widget = "checkbox"
|
||||
o.default = nil
|
||||
o.optional=true
|
||||
|
||||
----downloadtarge
|
||||
o = s:option(ListValue, "tagname", translate("Choose Release Version for download"))
|
||||
o:value("release",translate("Release(Default)"))
|
||||
o:value("beta",translate("Beta"))
|
||||
o.description=translate("If this option is modified, please confirm the download links")
|
||||
o.default="release"
|
||||
o.rmempty=true
|
||||
|
||||
----downloadpath
|
||||
o = s:option(TextValue, "downloadlinks",translate("Download links for update"))
|
||||
o.optional = false
|
||||
o.rows = 4
|
||||
o.wrap = "soft"
|
||||
o.cfgvalue = function(self, section)
|
||||
return fs.readfile("/usr/share/AdGuardHome/links.txt")
|
||||
end
|
||||
o.write = function(self, section, value)
|
||||
fs.writefile("/usr/share/AdGuardHome/links.txt", value:gsub("\r\n", "\n"))
|
||||
end
|
||||
fs.writefile("/var/run/lucilogpos","0")
|
||||
function m.on_commit(map)
|
||||
if (fs.access("/var/run/AdGserverdis")) then
|
||||
io.popen("/etc/init.d/AdGuardHome reload &")
|
||||
return
|
||||
end
|
||||
local ucitracktest=uci:get("AdGuardHome","AdGuardHome","ucitracktest")
|
||||
if ucitracktest=="1" then
|
||||
return
|
||||
elseif ucitracktest=="0" then
|
||||
io.popen("/etc/init.d/AdGuardHome reload &")
|
||||
else
|
||||
if (fs.access("/var/run/AdGlucitest")) then
|
||||
uci:set("AdGuardHome","AdGuardHome","ucitracktest","0")
|
||||
io.popen("/etc/init.d/AdGuardHome reload &")
|
||||
else
|
||||
fs.writefile("/var/run/AdGlucitest","")
|
||||
if (ucitracktest=="2") then
|
||||
uci:set("AdGuardHome","AdGuardHome","ucitracktest","1")
|
||||
else
|
||||
uci:set("AdGuardHome","AdGuardHome","ucitracktest","2")
|
||||
end
|
||||
end
|
||||
uci:commit("AdGuardHome")
|
||||
end
|
||||
end
|
||||
return m
|
||||
Loaded 100 of 918 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user