⛄ Sync 2026-10-22 00:07:59

This commit is contained in:
github-actions[bot] committed 2026-10-22 00:07:59 +08:00
1 parent 31748c050e
commit d047be4ede
22 files changed
+379 -173

No files matched your search

+1 -1
View File
@@ -2,7 +2,7 @@ include $(TOPDIR)/rules.mk
PKG_NAME:=beszel PKG_NAME:=beszel
PKG_VERSION:=0.21.0 PKG_VERSION:=0.21.0
PKG_RELEASE:=12 PKG_RELEASE:=13
PKG_SOURCE:=beszel-$(PKG_VERSION).tar.gz PKG_SOURCE:=beszel-$(PKG_VERSION).tar.gz
PKG_SOURCE_URL:=https://codeload.github.com/henrygd/beszel/tar.gz/v$(PKG_VERSION)? PKG_SOURCE_URL:=https://codeload.github.com/henrygd/beszel/tar.gz/v$(PKG_VERSION)?
@@ -1,14 +1,14 @@
From 128555126155413ce32b134435c425ad9bb24501 Mon Sep 17 00:00:00 2001 From 70f6bfc114b419ad1d1d999c4e74906c1ebc3819 Mon Sep 17 00:00:00 2001
From: Jackie Han <jackie.han@gmail.com> From: Jackie Han <jackie.han@gmail.com>
Date: Wed, 14 Oct 2026 07:40:03 +0800 Date: Wed, 21 Oct 2026 22:20:40 +0800
Subject: [PATCH] Refactor collect function to handle wireless devices Subject: [PATCH] Refactor WiFi collection logic for Linux
--- ---
agent/wifi/wifi_linux.go | 111 ++++++++++++++++++++++++++++++++++++--- agent/wifi/wifi_linux.go | 164 ++++++++++++++++++++++++++++++++++++---
1 file changed, 105 insertions(+), 6 deletions(-) 1 file changed, 152 insertions(+), 12 deletions(-)
diff --git a/agent/wifi/wifi_linux.go b/agent/wifi/wifi_linux.go diff --git a/agent/wifi/wifi_linux.go b/agent/wifi/wifi_linux.go
index 926d658fe..ea42b1f2b 100644 index 926d658fef..1ba134e69c 100644
--- a/agent/wifi/wifi_linux.go --- a/agent/wifi/wifi_linux.go
+++ b/agent/wifi/wifi_linux.go +++ b/agent/wifi/wifi_linux.go
@@ -5,8 +5,12 @@ package wifi @@ -5,8 +5,12 @@ package wifi
@@ -24,36 +24,38 @@ index 926d658fe..ea42b1f2b 100644
"time" "time"
"github.com/henrygd/beszel/internal/entities/system" "github.com/henrygd/beszel/internal/entities/system"
@@ -99,15 +103,110 @@ func hasWirelessDevice(dir string) bool { @@ -99,36 +103,172 @@ func hasWirelessDevice(dir string) bool {
} }
func collect(ctx context.Context) map[string]system.WiFi { func collect(ctx context.Context) map[string]system.WiFi {
- if !hasWirelessDevice(wiphyClassDir) { - if !hasWirelessDevice(wiphyClassDir) {
- return nil + var client linuxClient
+ results := make(map[string]system.WiFi)
+
+ if hasWirelessDevice(wiphyClassDir) { + if hasWirelessDevice(wiphyClassDir) {
+ if client, err := newNL80211Client(); err == nil { + if c, err := newNL80211Client(); err == nil {
+ for k, v := range collectLinux(ctx, client) { + client = c
+ results[k] = v + defer client.Close()
+ }
+ client.Close()
+ } + }
} + }
- client, err := newNL80211Client() + return collectLinuxWithAP(ctx, client, runIwinfo)
- if err != nil { +}
+ +
+ if _, err := exec.LookPath("iwinfo"); err == nil { +type iwinfoCommand func(context.Context, ...string) ([]byte, error)
+ for k, v := range collectOpenWrtAP(ctx) { +
+ results[k] = v +func runIwinfo(ctx context.Context, args ...string) ([]byte, error) {
+ } + return exec.CommandContext(ctx, "iwinfo", args...).Output()
+}
+
+func collectLinuxWithAP(ctx context.Context, client linuxClient, iwinfo iwinfoCommand) map[string]system.WiFi {
+ results, aps := collectLinux(ctx, client)
+ for k, v := range collectOpenWrtAP(ctx, aps, iwinfo) {
+ results[k] = v
+ } + }
+ +
+ if len(results) == 0 { + if len(results) == 0 {
return nil return nil
} }
- defer client.Close() - client, err := newNL80211Client()
- return collectLinux(ctx, client) - if err != nil {
+ return results + return results
+} +}
+ +
@@ -61,7 +63,7 @@ index 926d658fe..ea42b1f2b 100644
+ iwinfoIfaceRe = regexp.MustCompile(`(?m)^(\S+)[ \t]+ESSID:`) + iwinfoIfaceRe = regexp.MustCompile(`(?m)^(\S+)[ \t]+ESSID:`)
+ iwinfoModeRe = regexp.MustCompile(`Mode:[ \t]*Master`) + iwinfoModeRe = regexp.MustCompile(`Mode:[ \t]*Master`)
+ iwinfoSSIDRe = regexp.MustCompile(`ESSID:\s*"([^"]+)"`) + iwinfoSSIDRe = regexp.MustCompile(`ESSID:\s*"([^"]+)"`)
+ iwinfoAssocRe = regexp.MustCompile(`(?m)^(?:[0-9a-fA-F]{2}[:-]){5}[0-9a-fA-F]{2}.*?(-?\d+)\s+dBm`) + iwinfoAssocRe = regexp.MustCompile(`(?m)^(?:[0-9a-fA-F]{2}[:-]){5}[0-9a-fA-F]{2}[ \t]+(-?\d+)[ \t]+dBm`)
+) +)
+ +
+type iwinfoBlock struct { +type iwinfoBlock struct {
@@ -112,25 +114,49 @@ index 926d658fe..ea42b1f2b 100644
+ return math.Round(float64(sum) / float64(count)), true + return math.Round(float64(sum) / float64(count)), true
+} +}
+ +
+func collectOpenWrtAP(ctx context.Context) map[string]system.WiFi { +// A nil aps requests discovery for drivers without a usable nl80211 inventory.
+// An empty, non-nil aps means enumeration succeeded and found no APs.
+func collectOpenWrtAP(ctx context.Context, aps []string, iwinfo iwinfoCommand) map[string]system.WiFi {
+ if ctx.Err() != nil || (aps != nil && len(aps) == 0) {
return nil
}
- defer client.Close()
- return collectLinux(ctx, client)
+ results := make(map[string]system.WiFi) + results := make(map[string]system.WiFi)
+ + var blocks []iwinfoBlock
+ out, err := exec.CommandContext(ctx, "iwinfo").Output() + if aps == nil {
+ if err != nil && len(out) == 0 { + out, err := iwinfo(ctx)
+ return results + if err != nil && len(out) == 0 {
+ return results
+ }
+ blocks = splitIwinfoBlocks(string(out))
+ } else {
+ for _, name := range aps {
+ blocks = append(blocks, iwinfoBlock{name: name})
+ }
+ } + }
+ +
+ for _, b := range splitIwinfoBlocks(string(out)) { + for _, b := range blocks {
+ if ctx.Err() != nil { + if ctx.Err() != nil {
+ return results + return results
+ } + }
+ if aps != nil {
+ out, err := iwinfo(ctx, b.name, "info")
+ if err != nil {
+ continue
+ }
+ b.text = string(out)
+ }
+ ssid, isAP := parseIwinfoInfo(b.text) + ssid, isAP := parseIwinfoInfo(b.text)
+ if !isAP { + if !isAP {
+ continue + continue
+ } + }
+ +
+ reading := system.WiFi{SSID: validSSID(ssid)} + reading := system.WiFi{SSID: validSSID(ssid), AP: true}
+ if assocOut, err := exec.CommandContext(ctx, "iwinfo", b.name, "assoclist").Output(); err == nil { + if ctx.Err() != nil {
+ return results
+ }
+ if assocOut, err := iwinfo(ctx, b.name, "assoclist"); err == nil {
+ if avg, ok := parseAssocRSSI(string(assocOut)); ok { + if avg, ok := parseAssocRSSI(string(assocOut)); ok {
+ reading.Signal = &avg + reading.Signal = &avg
+ } + }
@@ -140,4 +166,52 @@ index 926d658fe..ea42b1f2b 100644
+ return results + return results
} }
func collectLinux(ctx context.Context, client linuxClient) map[string]system.WiFi { -func collectLinux(ctx context.Context, client linuxClient) map[string]system.WiFi {
+// collectLinux returns station readings and AP names from a single interface
+// query. A nil AP list signals that iwinfo discovery may be needed.
+func collectLinux(ctx context.Context, client linuxClient) (map[string]system.WiFi, []string) {
result := make(map[string]system.WiFi)
- if ctx.Err() != nil {
- return result
+ if ctx.Err() != nil || client == nil {
+ return result, nil
}
if deadline, ok := ctx.Deadline(); ok {
if client.SetDeadline(deadline) != nil {
- return result
+ return result, nil
}
}
interfaces, err := client.Interfaces()
if err != nil {
- return result
+ return result, nil
}
+ var aps []string
for _, iface := range interfaces {
if ctx.Err() != nil {
break
}
- if iface == nil || iface.Type != native.InterfaceTypeStation || iface.Name == "" {
+ if iface == nil || iface.Name == "" {
+ continue
+ }
+ // Only an inventory with at least one named interface is usable.
+ // Empty dumps can also come from unsupported proprietary drivers.
+ if aps == nil {
+ aps = make([]string, 0)
+ }
+ if iface.Type == native.InterfaceTypeAP {
+ aps = append(aps, iface.Name)
+ }
+ if iface.Type != native.InterfaceTypeStation {
continue
}
// GET_SCAN reads the kernel's BSS cache, without triggering a scan.
@@ -151,5 +291,5 @@ func collectLinux(ctx context.Context, client linuxClient) map[string]system.WiF
}
result[iface.Name] = reading
}
- return result
+ return result, aps
}
@@ -0,0 +1,33 @@
From 79f5586adcfce5015dbce7d77eb4e7e76daed913 Mon Sep 17 00:00:00 2001
From: Jackie Han <jackie.han@gmail.com>
Date: Wed, 21 Oct 2026 23:01:05 +0800
Subject: [PATCH] Enhance WiFi struct documentation
Updated WiFi struct documentation to clarify its purpose and behavior regarding access points and associated clients.
---
internal/entities/system/system.go | 9 ++++++---
1 file changed, 6 insertions(+), 3 deletions(-)
diff --git a/internal/entities/system/system.go b/internal/entities/system/system.go
index b6b6168f0..b24735e83 100644
--- a/internal/entities/system/system.go
+++ b/internal/entities/system/system.go
@@ -11,12 +11,15 @@ import (
"github.com/henrygd/beszel/internal/entities/systemd"
)
-// WiFi describes a currently connected station interface. Keys in WiFi maps are
-// OS interface identities, not SSIDs. Signal is native dBm only; nil means the
-// OS confirmed association but could not supply RSSI (never convert quality %).
+// WiFi describes a currently connected station interface, or an access point
+// when AP is set. Keys in WiFi maps are OS interface identities, not SSIDs.
+// Signal is native dBm only; nil means the OS confirmed association but could
+// not supply RSSI (never convert quality %). For an AP, Signal is the average
+// RSSI of associated clients, and nil means no client reported one.
type WiFi struct {
SSID string `json:"s,omitempty" cbor:"0,keyasint,omitempty"`
Signal *float64 `json:"r,omitempty" cbor:"1,keyasint,omitempty"`
+ AP bool `json:"a,omitzero" cbor:"2,keyasint,omitempty"`
}
type Stats struct {
+2 -2
View File
@@ -5,8 +5,8 @@
include $(TOPDIR)/rules.mk include $(TOPDIR)/rules.mk
PKG_NAME:=cloudflared-next PKG_NAME:=cloudflared-next
PKG_VERSION:=2026.10.2 PKG_VERSION:=2026.10.3
PKG_RELEASE:=5 PKG_RELEASE:=6
# Architecture mapping for pre-built binaries # Architecture mapping for pre-built binaries
ifeq ($(ARCH),x86_64) ifeq ($(ARCH),x86_64)
+6 -3
View File
@@ -5,8 +5,8 @@
include $(TOPDIR)/rules.mk include $(TOPDIR)/rules.mk
PKG_NAME:=gately PKG_NAME:=gately
PKG_VERSION:=0.5.4 PKG_VERSION:=0.5.5.1
PKG_RELEASE:=4 PKG_RELEASE:=5
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
PKG_SOURCE_URL:=https://codeload.github.com/wangwanjie/gately/tar.gz/v$(PKG_VERSION)? PKG_SOURCE_URL:=https://codeload.github.com/wangwanjie/gately/tar.gz/v$(PKG_VERSION)?
@@ -20,11 +20,14 @@ PKG_BUILD_DEPENDS:=golang/host node/host node-pnpm/host
PKG_BUILD_PARALLEL:=1 PKG_BUILD_PARALLEL:=1
PKG_BUILD_FLAGS:=no-mips16 PKG_BUILD_FLAGS:=no-mips16
BUILD_DATE:=$(shell date -u -d "@$(SOURCE_DATE_EPOCH)" +"%Y-%m-%dT%H:%M:%SZ" 2>/dev/null || date -u +"%Y-%m-%dT%H:%M:%SZ")
GO_PKG:=github.com/wangwanjie/gately GO_PKG:=github.com/wangwanjie/gately
GO_PKG_BUILD_PKG:=$(GO_PKG)/cmd/gately GO_PKG_BUILD_PKG:=$(GO_PKG)/cmd/gately
GO_PKG_LDFLAGS_X:=\ GO_PKG_LDFLAGS_X:=\
$(GO_PKG)/internal/version.Version=v$(PKG_VERSION) \ $(GO_PKG)/internal/version.Version=v$(PKG_VERSION) \
$(GO_PKG)/internal/version.Commit=$(PKG_VERSION) $(GO_PKG)/internal/version.Commit=$(PKG_VERSION) \
$(GO_PKG)/internal/version.BuildDate=$(BUILD_DATE)
include $(INCLUDE_DIR)/package.mk include $(INCLUDE_DIR)/package.mk
include $(TOPDIR)/feeds/packages/lang/golang/golang-package.mk include $(TOPDIR)/feeds/packages/lang/golang/golang-package.mk
+2 -2
View File
@@ -8,8 +8,8 @@
include $(TOPDIR)/rules.mk include $(TOPDIR)/rules.mk
PKG_NAME:=go-ethereum PKG_NAME:=go-ethereum
PKG_VERSION:=1.17.8 PKG_VERSION:=1.17.9
PKG_RELEASE:=12 PKG_RELEASE:=13
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
PKG_SOURCE_URL:=https://codeload.github.com/ethereum/go-ethereum/tar.gz/v${PKG_VERSION}? PKG_SOURCE_URL:=https://codeload.github.com/ethereum/go-ethereum/tar.gz/v${PKG_VERSION}?
+2 -2
View File
@@ -5,8 +5,8 @@
include $(TOPDIR)/rules.mk include $(TOPDIR)/rules.mk
PKG_NAME:=gost PKG_NAME:=gost
PKG_VERSION:=3.3.0 PKG_VERSION:=3.3.1
PKG_RELEASE:=5 PKG_RELEASE:=6
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
PKG_SOURCE_URL:=https://codeload.github.com/go-gost/gost/tar.gz/v$(PKG_VERSION)? PKG_SOURCE_URL:=https://codeload.github.com/go-gost/gost/tar.gz/v$(PKG_VERSION)?
+1 -1
View File
@@ -8,7 +8,7 @@ include $(TOPDIR)/rules.mk
PKG_NAME:=luci-app-passwall PKG_NAME:=luci-app-passwall
PKG_VERSION:=26.10.16 PKG_VERSION:=26.10.16
PKG_RELEASE:=343 PKG_RELEASE:=344
PKG_PO_VERSION:=$(PKG_VERSION) PKG_PO_VERSION:=$(PKG_VERSION)
PKG_CONFIG_DEPENDS:= \ PKG_CONFIG_DEPENDS:= \
+41 -2
View File
@@ -277,6 +277,16 @@ function md5_string(str)
return md5 return md5
end end
-- 校验文件 SHA256
function verify_sha256(file, digest)
if type(digest) ~= "string" then return false end
local expected = digest:match("^sha256:(%x+)$")
if not expected or #expected ~= 64 then return false end
local code, output = exec_call("sha256sum " .. util.shellquote(file))
local actual = output:match("^(%x+)%s")
return code == 0 and actual ~= nil and actual:lower() == expected:lower()
end
--提取URL中的域名和端口(no ip) --提取URL中的域名和端口(no ip)
function get_domain_port_from_url(url) function get_domain_port_from_url(url)
local scheme, domain, port = string.match(url, "^(https?)://([%w%.%-]+):?(%d*)") local scheme, domain, port = string.match(url, "^(https?)://([%w%.%-]+):?(%d*)")
@@ -298,9 +308,14 @@ function resolve_domain(domain, dns)
address = (address or dns):gsub("^%[(.-)%]$", "%1") address = (address or dns):gsub("^%[(.-)%]$", "%1")
port = port or "53" port = port or "53"
local server = datatypes.ip6addr(address) and ("[" .. address .. "]") or address local server = datatypes.ip6addr(address) and ("[" .. address .. "]") or address
local dns_servers = {server .. ":" .. port, address .. "#" .. port, "223.5.5.5"}
local version = sys.exec("LC_ALL=C busybox nslookup -v 2>&1"):match("BusyBox v(%d+%.%d+%.%d+)")
if version and compare_versions(version, "<", "1.35.0") then
dns_servers[1], dns_servers[2] = dns_servers[2], dns_servers[1]
end
local rc, result local rc, result
for _, dns_server in ipairs({server .. ":" .. port, address .. "#" .. port, "223.5.5.5"}) do for _, dns_server in ipairs(dns_servers) do
rc, result = exec_call_as_gid("LC_ALL=C nslookup " .. util.shellquote(domain) .. " " .. util.shellquote(dns_server), DIRECT_GID) rc, result = exec_call_as_gid("LC_ALL=C busybox nslookup " .. util.shellquote(domain) .. " " .. util.shellquote(dns_server), DIRECT_GID)
local ips, seen, answer = {}, {}, false local ips, seen, answer = {}, {}, false
for line in result:gmatch("[^\r\n]+") do for line in result:gmatch("[^\r\n]+") do
if line:match("^%s*Name:") then answer = true end if line:match("^%s*Name:") then answer = true end
@@ -1212,6 +1227,17 @@ local function check_path(app_name)
} }
end end
local function cache_update_digests(app_name, assets)
local digests = {}
for _, asset in ipairs(assets) do
if asset.browser_download_url and type(asset.digest) == "string" then
digests[asset.browser_download_url] = asset.digest
end
end
fs.mkdirr(CACHE_PATH)
fs.writefile(CACHE_PATH .. "/update_" .. app_name .. ".json", jsonc.stringify(digests))
end
function to_check(arch, app_name) function to_check(arch, app_name)
local result = check_path(app_name) local result = check_path(app_name)
if result.code ~= 0 then if result.code ~= 0 then
@@ -1276,6 +1302,7 @@ function to_check(arch, app_name)
} }
end end
cache_update_digests(app_name, {asset})
return { return {
code = 0, code = 0,
has_update = has_update, has_update = has_update,
@@ -1296,6 +1323,12 @@ function to_download(app_name, url, size, task_id, keep_files)
return {code = 1, error = i18n.translate("Download url is required.")} return {code = 1, error = i18n.translate("Download url is required.")}
end end
local digests = jsonc.parse(fs.readfile(CACHE_PATH .. "/update_" .. app_name .. ".json") or "{}")
local digest = type(digests) == "table" and digests[url]
if type(digest) ~= "string" then
return {code = 1, error = i18n.translate("File verification failed.")}
end
if not keep_files then remove("/tmp/" .. app_name .. "_download.*") end if not keep_files then remove("/tmp/" .. app_name .. "_download.*") end
local tmp_file local tmp_file
@@ -1334,6 +1367,11 @@ function to_download(app_name, url, size, task_id, keep_files)
} }
end end
if not verify_sha256(tmp_file, digest) then
exec("/bin/rm", {"-f", tmp_file})
return {code = 1, error = i18n.translate("File verification failed.")}
end
return {code = 0, file = tmp_file, zip = com[app_name].zipped } return {code = 0, file = tmp_file, zip = com[app_name].zipped }
end end
@@ -1541,6 +1579,7 @@ function to_check_self()
if not main or not i18n_package then if not main or not i18n_package then
return {code = 1, error = i18n.translate("Get remote version info failed.")} return {code = 1, error = i18n.translate("Get remote version info failed.")}
end end
cache_update_digests(appname, {main, i18n_package})
return { return {
code = 0, has_update = has_update, local_version = local_version, code = 0, has_update = has_update, local_version = local_version,
remote_version = remote_version, html_url = release.html_url, remote_version = remote_version, html_url = release.html_url,
@@ -86,7 +86,7 @@ local com = self.com
var app = btn.getAttribute('data-update-app'); var app = btn.getAttribute('data-update-app');
var detailId = app === appname ? appname + '-check_btn' : '_' + app + '-check_btn'; var detailId = app === appname ? appname + '-check_btn' : '_' + app + '-check_btn';
var ckeckDetailElm = document.getElementById(detailId + '-detail'); var ckeckDetailElm = document.getElementById(detailId + '-detail');
if (app === appname && !checking) errorMessage = errorMessage ? updateFailedText : unknownErrorText; if (app === appname && !checking && !errorMessage) errorMessage = unknownErrorText;
if (errorMessage && ckeckDetailElm) { if (errorMessage && ckeckDetailElm) {
ckeckDetailElm.textContent = errorMessage ckeckDetailElm.textContent = errorMessage
} }
+3
View File
@@ -1547,6 +1547,9 @@ msgstr "请指定下载地址。"
msgid "File download failed or timed out: %s" msgid "File download failed or timed out: %s"
msgstr "文件下载失败或超时:%s" msgstr "文件下载失败或超时:%s"
msgid "File verification failed."
msgstr "文件校验失败"
msgid "File path required." msgid "File path required."
msgstr "请指定文件路径。" msgstr "请指定文件路径。"
@@ -565,31 +565,25 @@ local function fetch_geofile(geo_name, geo_type, url)
local sha_url = url:gsub((down_filename:gsub("(%W)", "%%%1")), down_filename .. ".sha256sum") local sha_url = url:gsub((down_filename:gsub("(%W)", "%%%1")), down_filename .. ".sha256sum")
local sha_path = tmp_path .. ".sha256sum" local sha_path = tmp_path .. ".sha256sum"
local function verify_sha256(sha_file) local digest
return sys.call("sha256sum -c " .. sha_file .. " > /dev/null 2>&1") == 0
end
local sha_verify = select(1, curl(sha_url, sha_path)) == 0 local sha_verify = select(1, curl(sha_url, sha_path)) == 0
if sha_verify then if sha_verify then
local f = io.open(sha_path, "r") local f = io.open(sha_path, "r")
if f then if f then
local content = f:read("*l") local content = f:read("*l")
f:close() f:close()
if content then local hash = content and content:match("^(%x+)%s")
content = content:gsub("(%x+)%s+.+", "%1 " .. tmp_path) if hash and #hash == 64 then
f = io.open(sha_path, "w") digest = "sha256:" .. hash
if f then
f:write(content)
f:close()
end
end end
end end
if fs.access(asset_path) then if not digest then
sys.call(string.format("cp -f %s %s", asset_path, tmp_path)) log(geo_type .. " SHA256 校验信息无效,更新失败。")
if verify_sha256(sha_path) then return 1
log(geo_type .. " 版本一致,无需更新。") end
return 0 if fs.access(asset_path) and api.verify_sha256(asset_path, digest) then
end log(geo_type .. " 版本一致,无需更新。")
return 0
end end
end end
@@ -605,7 +599,7 @@ local function fetch_geofile(geo_name, geo_type, url)
end end
if sret_tmp == 0 then if sret_tmp == 0 then
if sha_verify then if sha_verify then
if verify_sha256(sha_path) then if api.verify_sha256(tmp_path, digest) then
sys.call(string.format("mkdir -p %s && mv -f %s %s", backup_path, asset_path, backup_path)) sys.call(string.format("mkdir -p %s && mv -f %s %s", backup_path, asset_path, backup_path))
sys.call(string.format("mkdir -p %s && mv -f %s %s", asset_location, tmp_path, asset_path)) sys.call(string.format("mkdir -p %s && mv -f %s %s", asset_location, tmp_path, asset_path))
reboot = 1 reboot = 1
+1 -1
View File
@@ -7,7 +7,7 @@ include $(TOPDIR)/rules.mk
PKG_NAME:=luci-app-passwall2 PKG_NAME:=luci-app-passwall2
PKG_VERSION:=26.10.20 PKG_VERSION:=26.10.20
PKG_RELEASE:=148 PKG_RELEASE:=149
PKG_PO_VERSION:=$(PKG_VERSION) PKG_PO_VERSION:=$(PKG_VERSION)
PKG_CONFIG_DEPENDS:= \ PKG_CONFIG_DEPENDS:= \
+43 -2
View File
@@ -307,6 +307,16 @@ function md5_string(str)
return md5 return md5
end end
-- Verify the SHA256 hash of a file.
function verify_sha256(file, digest)
if type(digest) ~= "string" then return false end
local expected = digest:match("^sha256:(%x+)$")
if not expected or #expected ~= 64 then return false end
local code, output = exec_call("sha256sum " .. util.shellquote(file))
local actual = output:match("^(%x+)%s")
return code == 0 and actual ~= nil and actual:lower() == expected:lower()
end
-- Extract the domain name and port from the URL (no IP address). -- Extract the domain name and port from the URL (no IP address).
function get_domain_port_from_url(url) function get_domain_port_from_url(url)
local scheme, domain, port = string.match(url, "^(https?)://([%w%.%-]+):?(%d*)") local scheme, domain, port = string.match(url, "^(https?)://([%w%.%-]+):?(%d*)")
@@ -328,9 +338,14 @@ function resolve_domain(domain, dns)
address = (address or dns):gsub("^%[(.-)%]$", "%1") address = (address or dns):gsub("^%[(.-)%]$", "%1")
port = port or "53" port = port or "53"
local server = datatypes.ip6addr(address) and ("[" .. address .. "]") or address local server = datatypes.ip6addr(address) and ("[" .. address .. "]") or address
local dns_servers = {server .. ":" .. port, address .. "#" .. port, "223.5.5.5"}
local version = sys.exec("LC_ALL=C busybox nslookup -v 2>&1"):match("BusyBox v(%d+%.%d+%.%d+)")
if version and compare_versions(version, "<", "1.35.0") then
dns_servers[1], dns_servers[2] = dns_servers[2], dns_servers[1]
end
local rc, result local rc, result
for _, dns_server in ipairs({server .. ":" .. port, address .. "#" .. port, "223.5.5.5"}) do for _, dns_server in ipairs(dns_servers) do
rc, result = exec_call_as_gid("LC_ALL=C nslookup " .. util.shellquote(domain) .. " " .. util.shellquote(dns_server), DIRECT_GID) rc, result = exec_call_as_gid("LC_ALL=C busybox nslookup " .. util.shellquote(domain) .. " " .. util.shellquote(dns_server), DIRECT_GID)
local ips, seen, answer = {}, {}, false local ips, seen, answer = {}, {}, false
for line in result:gmatch("[^\r\n]+") do for line in result:gmatch("[^\r\n]+") do
if line:match("^%s*Name:") then answer = true end if line:match("^%s*Name:") then answer = true end
@@ -1224,6 +1239,17 @@ local function check_path(app_name)
} }
end end
local function cache_update_digests(app_name, assets)
local digests = {}
for _, asset in ipairs(assets) do
if asset.browser_download_url and type(asset.digest) == "string" then
digests[asset.browser_download_url] = asset.digest
end
end
fs.mkdirr(CACHE_PATH)
fs.writefile(CACHE_PATH .. "/update_" .. app_name .. ".json", jsonc.stringify(digests))
end
function to_check(arch, app_name) function to_check(arch, app_name)
local result = check_path(app_name) local result = check_path(app_name)
if result.code ~= 0 then if result.code ~= 0 then
@@ -1288,6 +1314,7 @@ function to_check(arch, app_name)
} }
end end
cache_update_digests(app_name, {asset})
return { return {
code = 0, code = 0,
has_update = has_update, has_update = has_update,
@@ -1308,6 +1335,12 @@ function to_download(app_name, url, size, task_id, keep_files)
return {code = 1, error = i18n.translate("Download url is required.")} return {code = 1, error = i18n.translate("Download url is required.")}
end end
local digests = jsonc.parse(fs.readfile(CACHE_PATH .. "/update_" .. app_name .. ".json") or "{}")
local digest = type(digests) == "table" and digests[url]
if type(digest) ~= "string" then
return {code = 1, error = i18n.translate("File verification failed.")}
end
if not keep_files then sys.call("/bin/rm -f /tmp/".. app_name .."_download.*") end if not keep_files then sys.call("/bin/rm -f /tmp/".. app_name .."_download.*") end
local tmp_file local tmp_file
@@ -1346,6 +1379,11 @@ function to_download(app_name, url, size, task_id, keep_files)
} }
end end
if not verify_sha256(tmp_file, digest) then
exec("/bin/rm", {"-f", tmp_file})
return {code = 1, error = i18n.translate("File verification failed.")}
end
return {code = 0, file = tmp_file, zip = com[app_name].zipped } return {code = 0, file = tmp_file, zip = com[app_name].zipped }
end end
@@ -1586,6 +1624,9 @@ function to_check_self()
selected[#selected + 1] = found[code] selected[#selected + 1] = found[code]
end end
if not main then return {code = 1, error = i18n.translate("Get remote version info failed.")} end if not main then return {code = 1, error = i18n.translate("Get remote version info failed.")} end
local assets = {main}
for _, asset in ipairs(selected) do assets[#assets + 1] = asset end
cache_update_digests(appname, assets)
return { return {
code = 0, has_update = compare_versions(local_version, "<", remote_version), code = 0, has_update = compare_versions(local_version, "<", remote_version),
local_version = local_version, remote_version = remote_version, html_url = release.html_url, local_version = local_version, remote_version = remote_version, html_url = release.html_url,
@@ -86,7 +86,7 @@ local com = self.com
var app = btn.getAttribute('data-update-app'); var app = btn.getAttribute('data-update-app');
var detailId = app === appname ? appname + '-check_btn' : '_' + app + '-check_btn'; var detailId = app === appname ? appname + '-check_btn' : '_' + app + '-check_btn';
var ckeckDetailElm = document.getElementById(detailId + '-detail'); var ckeckDetailElm = document.getElementById(detailId + '-detail');
if (app === appname && !checking) errorMessage = errorMessage ? updateFailedText : unknownErrorText; if (app === appname && !checking && !errorMessage) errorMessage = unknownErrorText;
if (errorMessage && ckeckDetailElm) { if (errorMessage && ckeckDetailElm) {
ckeckDetailElm.textContent = errorMessage ckeckDetailElm.textContent = errorMessage
} }
+6
View File
@@ -1549,6 +1549,9 @@ msgstr "URL دانلود الزامی است."
msgid "File download failed or timed out: %s" msgid "File download failed or timed out: %s"
msgstr "دانلود فایل ناموفق بود یا زمان آن تمام شد: %s" msgstr "دانلود فایل ناموفق بود یا زمان آن تمام شد: %s"
msgid "File verification failed."
msgstr "تأیید فایل ناموفق بود."
msgid "File path required." msgid "File path required."
msgstr "مسیر فایل الزامی است." msgstr "مسیر فایل الزامی است."
@@ -2285,6 +2288,9 @@ msgstr "شروع به‌روزرسانی قوانین..."
msgid "Download file size verification error. Original file size: %sB. Downloaded file size: %sB." msgid "Download file size verification error. Original file size: %sB. Downloaded file size: %sB."
msgstr "خطای تأیید اندازه فایل دانلود شده. اندازه فایل اصلی: %sB. اندازه فایل دانلود شده: %sB." msgstr "خطای تأیید اندازه فایل دانلود شده. اندازه فایل اصلی: %sB. اندازه فایل دانلود شده: %sB."
msgid "%s SHA256 verification information is invalid. Update failed."
msgstr "اطلاعات تأیید SHA256 برای %s نامعتبر است. به‌روزرسانی ناموفق بود."
msgid "Downloaded file is empty or an error occurred while reading it." msgid "Downloaded file is empty or an error occurred while reading it."
msgstr "فایل دانلود شده خالی است یا خطایی هنگام خواندن آن رخ داده است." msgstr "فایل دانلود شده خالی است یا خطایی هنگام خواندن آن رخ داده است."
+6
View File
@@ -1550,6 +1550,9 @@ msgstr "Необходимо указать URL для загрузки."
msgid "File download failed or timed out: %s" msgid "File download failed or timed out: %s"
msgstr "Ошибка загрузки файла или тайм-аут: %s" msgstr "Ошибка загрузки файла или тайм-аут: %s"
msgid "File verification failed."
msgstr "Ошибка проверки файла."
msgid "File path required." msgid "File path required."
msgstr "Необходимо указать путь к файлу." msgstr "Необходимо указать путь к файлу."
@@ -2286,6 +2289,9 @@ msgstr "Начало обновления правил..."
msgid "Download file size verification error. Original file size: %sB. Downloaded file size: %sB." msgid "Download file size verification error. Original file size: %sB. Downloaded file size: %sB."
msgstr "Ошибка проверки размера файла. Исходный размер: %sB, загруженный: %sB." msgstr "Ошибка проверки размера файла. Исходный размер: %sB, загруженный: %sB."
msgid "%s SHA256 verification information is invalid. Update failed."
msgstr "Недопустимые данные проверки SHA256 для %s. Обновление не выполнено."
msgid "Downloaded file is empty or an error occurred while reading it." msgid "Downloaded file is empty or an error occurred while reading it."
msgstr "Загруженный файл пуст или произошла ошибка при чтении." msgstr "Загруженный файл пуст или произошла ошибка при чтении."
+6
View File
@@ -1541,6 +1541,9 @@ msgstr "请指定下载地址。"
msgid "File download failed or timed out: %s" msgid "File download failed or timed out: %s"
msgstr "文件下载失败或超时:%s" msgstr "文件下载失败或超时:%s"
msgid "File verification failed."
msgstr "文件校验失败"
msgid "File path required." msgid "File path required."
msgstr "请指定文件路径。" msgstr "请指定文件路径。"
@@ -2271,6 +2274,9 @@ msgstr "开始更新规则..."
msgid "Download file size verification error. Original file size: %sB. Downloaded file size: %sB." msgid "Download file size verification error. Original file size: %sB. Downloaded file size: %sB."
msgstr "下载文件大小校验出错,原始文件大小 %sB,下载文件大小:%sB。" msgstr "下载文件大小校验出错,原始文件大小 %sB,下载文件大小:%sB。"
msgid "%s SHA256 verification information is invalid. Update failed."
msgstr "%s SHA256 校验信息无效,更新失败。"
msgid "Downloaded file is empty or an error occurred while reading it." msgid "Downloaded file is empty or an error occurred while reading it."
msgstr "下载的文件为空或读取文件时发生错误。" msgstr "下载的文件为空或读取文件时发生错误。"
+6
View File
@@ -1541,6 +1541,9 @@ msgstr "請指定下載地址。"
msgid "File download failed or timed out: %s" msgid "File download failed or timed out: %s"
msgstr "文件下載失敗或超時:%s" msgstr "文件下載失敗或超時:%s"
msgid "File verification failed."
msgstr "檔案校驗失敗"
msgid "File path required." msgid "File path required."
msgstr "請指定文件路径。" msgstr "請指定文件路径。"
@@ -2277,6 +2280,9 @@ msgstr "開始更新規則..."
msgid "Download file size verification error. Original file size: %sB. Downloaded file size: %sB." msgid "Download file size verification error. Original file size: %sB. Downloaded file size: %sB."
msgstr "下載檔案大小校驗出錯,原始檔案大小 %sB,下載檔案大小:%sB。" msgstr "下載檔案大小校驗出錯,原始檔案大小 %sB,下載檔案大小:%sB。"
msgid "%s SHA256 verification information is invalid. Update failed."
msgstr "%s SHA256 校驗資訊無效,更新失敗。"
msgid "Downloaded file is empty or an error occurred while reading it." msgid "Downloaded file is empty or an error occurred while reading it."
msgstr "下載的文件為空或讀取文件時發生錯誤。" msgstr "下載的文件為空或讀取文件時發生錯誤。"
@@ -116,31 +116,25 @@ local function fetch_geofile(geo_name, geo_type, url)
local sha_url = url:gsub((down_filename:gsub("(%W)", "%%%1")), down_filename .. ".sha256sum") local sha_url = url:gsub((down_filename:gsub("(%W)", "%%%1")), down_filename .. ".sha256sum")
local sha_path = tmp_path .. ".sha256sum" local sha_path = tmp_path .. ".sha256sum"
local function verify_sha256(sha_file) local digest
return sys.call("sha256sum -c " .. sha_file .. " > /dev/null 2>&1") == 0
end
local sha_verify, _ = curl(sha_url, sha_path) == 200 local sha_verify, _ = curl(sha_url, sha_path) == 200
if sha_verify then if sha_verify then
local f = io.open(sha_path, "r") local f = io.open(sha_path, "r")
if f then if f then
local content = f:read("*l") local content = f:read("*l")
f:close() f:close()
if content then local hash = content and content:match("^(%x+)%s")
content = content:gsub("(%x+)%s+.+", "%1 " .. tmp_path) if hash and #hash == 64 then
f = io.open(sha_path, "w") digest = "sha256:" .. hash
if f then
f:write(content)
f:close()
end
end end
end end
if fs.access(asset_path) then if not digest then
sys.call(string.format("cp -f %s %s", asset_path, tmp_path)) log(1, api.i18n.translatef("%s SHA256 verification information is invalid. Update failed.", geo_type))
if verify_sha256(sha_path) then return 1
log(1, api.i18n.translatef("%s version is the same and does not need to be updated.", geo_type)) end
return 0 if fs.access(asset_path) and api.verify_sha256(asset_path, digest) then
end log(1, api.i18n.translatef("%s version is the same and does not need to be updated.", geo_type))
return 0
end end
end end
@@ -156,7 +150,7 @@ local function fetch_geofile(geo_name, geo_type, url)
end end
if sret_tmp == 200 then if sret_tmp == 200 then
if sha_verify then if sha_verify then
if verify_sha256(sha_path) then if api.verify_sha256(tmp_path, digest) then
sys.call(string.format("mkdir -p %s && mv -f %s %s", backup_path, asset_path, backup_path)) sys.call(string.format("mkdir -p %s && mv -f %s %s", backup_path, asset_path, backup_path))
sys.call(string.format("mkdir -p %s && mv -f %s %s", asset_location, tmp_path, asset_path)) sys.call(string.format("mkdir -p %s && mv -f %s %s", asset_location, tmp_path, asset_path))
reboot = 1 reboot = 1
+84 -83
View File
@@ -1,64 +1,60 @@
# SPDX-License-Identifier: GPL-3.0-or-later
# #
# Copyright (c) 2018-2023 Nick Peng (pymumu@gmail.com) # Copyright (c) 2018-2026 Nick Peng (pymumu@gmail.com)
# This is free software, licensed under the GNU General Public License v3.
#
include $(TOPDIR)/rules.mk include $(TOPDIR)/rules.mk
PKG_NAME:=smartdns PKG_NAME:=smartdns
PKG_VERSION:=48.4 PKG_VERSION:=48.4
PKG_RELEASE:=8 PKG_RELEASE:=9
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz PKG_SOURCE_VERSION:=21c940edc65520849ba03544c5cf8d9cf326e680
PKG_SOURCE_URL:=https://codeload.github.com/pymumu/smartdns/tar.gz/Release$(PKG_VERSION)? PKG_SOURCE:=$(PKG_NAME)-$(PKG_SOURCE_VERSION).tar.gz
PKG_SOURCE_URL:=https://codeload.github.com/pymumu/smartdns/tar.gz
PKG_SOURCE_URL_FILE:=$(PKG_SOURCE_VERSION)
PKG_HASH:=skip PKG_HASH:=skip
PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-Release$(PKG_VERSION) PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-$(PKG_SOURCE_VERSION)
SMARTDNS_WEBUI_SOURCE_VERSION:=1c06fee693434ec7c71f06010d3f87416baba9f0
SMARTDNS_WEBUI_SOURCE:=$(PKG_NAME)-webui-$(SMARTDNS_WEBUI_SOURCE_VERSION).tar.gz
SMARTDNS_WEBUI_SOURCE_URL:=https://codeload.github.com/pymumu/smartdns-webui/tar.gz
SMARTDNS_WEBUI_SOURCE_URL_FILE:=$(SMARTDNS_WEBUI_SOURCE_VERSION)
SMARTDNS_WEBUI_HASH:=7a698dd4826750869429e83d91ce99a4e474d0809588a7f4124ef86875be9b1f
PKG_MAINTAINER:=Nick Peng <pymumu@gmail.com> PKG_MAINTAINER:=Nick Peng <pymumu@gmail.com>
PKG_LICENSE:=GPL-3.0-or-later PKG_LICENSE:=GPL-3.0-or-later
PKG_LICENSE_FILES:=LICENSE PKG_LICENSE_FILES:=LICENSE
PKG_CPE_ID:=cpe:/a:pymumu:smartdns
PKG_CONFIG_DEPENDS:=CONFIG_PACKAGE_smartdns-ui
PKG_BUILD_DEPENDS:=PACKAGE_smartdns-ui:node/host PACKAGE_smartdns-ui:rust-bindgen/host
PKG_BUILD_PARALLEL:=1 PKG_BUILD_PARALLEL:=1
RUST_PKG_FEATURES:=build-release # node compile is slow, so do not use it, download node manually.
RUST_PKG_LOCKED:=0 # PACKAGE_smartdns-ui:node/host
PKG_BUILD_DEPENDS:=PACKAGE_smartdns-ui:rust/host
include $(INCLUDE_DIR)/package.mk
include $(TOPDIR)/feeds/packages/lang/rust/rust-package.mk include $(TOPDIR)/feeds/packages/lang/rust/rust-package.mk
include $(INCLUDE_DIR)/package.mk
MAKE_VARS += VER=$(PKG_VERSION)
MAKE_PATH:=src MAKE_PATH:=src
MAKE_VARS+= VER=$(PKG_VERSION) WITH_ZLIB=0
define Package/smartdns/Default define Package/smartdns/default
SECTION:=net SECTION:=net
CATEGORY:=Network CATEGORY:=Network
SUBMENU:=IP Addresses and Names SUBMENU:=IP Addresses and Names
TITLE:=smartdns
URL:=https://www.github.com/pymumu/smartdns/ URL:=https://www.github.com/pymumu/smartdns/
endef endef
define Package/smartdns define Package/smartdns
$(call Package/smartdns/Default) $(Package/smartdns/default)
TITLE+= server TITLE:=smartdns server
DEPENDS:=+i386:libatomic +libopenssl DEPENDS:=+libpthread +libopenssl +libatomic +zlib
endef endef
define Package/smartdns/description define Package/smartdns/description
SmartDNS is a local DNS server which accepts DNS query requests from local network clients, SmartDNS is a local DNS server which accepts DNS query requests from local network clients,
gets DNS query results from multiple upstream DNS servers concurrently, and returns the fastest IP to clients. gets DNS query results from multiple upstream DNS servers concurrently, and returns the fastest IP to clients.
Unlike dnsmasq's all-servers, smartdns returns the fastest IP, and encrypt DNS queries with DoT or DoH. Unlike dnsmasq's all-servers, smartdns returns the fastest IP, and encrypt DNS queries with DoT or DoH.
endef
define Package/smartdns-ui
$(call Package/smartdns/Default)
TITLE+= dashboard
DEPENDS:=+smartdns $(RUST_ARCH_DEPENDS) @!i386
endef
define Package/smartdns-ui/description
A dashboard ui for smartdns server.
endef endef
define Package/smartdns/conffiles define Package/smartdns/conffiles
@@ -70,73 +66,78 @@ define Package/smartdns/conffiles
/etc/smartdns/domain-forwarding.list /etc/smartdns/domain-forwarding.list
endef endef
define Download/smartdns-webui
PROTO:=git
URL:=https://github.com/pymumu/smartdns-webui.git
SOURCE_DATE:=2026-07-29
SOURCE_VERSION:=1c06fee693434ec7c71f06010d3f87416baba9f0
MIRROR_HASH:=1b718d1288f6ddbdd80e3a948dda1693fd7bc8079fdb65be121f64f23ce53849
SUBDIR:=smartdns-webui-$$$$(subst -,.,$$$$(SOURCE_DATE))~$$$$(call version_abbrev,$$$$(SOURCE_VERSION))
FILE:=$$(SUBDIR).tar.zst
endef
define Build/Prepare
$(call Build/Prepare/Default)
ifneq ($(CONFIG_PACKAGE_smartdns-ui),)
$(eval $(call Download,smartdns-webui))
$(eval $(Download/smartdns-webui))
mkdir -p $(PKG_BUILD_DIR)/smartdns-webui
zstdcat $(DL_DIR)/$(FILE) | tar -C $(PKG_BUILD_DIR)/smartdns-webui $(TAR_OPTIONS) --strip-components=1
endif
endef
define Build/Compile
$(call Build/Compile/Default)
ifneq ($(CONFIG_PACKAGE_smartdns-ui),)
( \
pushd $(PKG_BUILD_DIR) ; \
pushd smartdns-webui ; \
npm install ; \
npm run build ; \
popd ; \
pushd plugin/smartdns-ui ; \
$(CARGO_PKG_CONFIG_VARS) \
MAKEFLAGS="$(PKG_JOBS)" \
WITH_ZLIB=0 \
TARGET_CFLAGS="$(filter-out -O%,$(TARGET_CFLAGS)) $(RUSTC_CFLAGS)" \
BINDGEN_EXTRA_CLANG_ARGS="--sysroot=$(TOOLCHAIN_ROOT_DIR)" \
cargo build -v --profile $(CARGO_PKG_PROFILE) \
$(if $(strip $(RUST_PKG_FEATURES)),--features "$(strip $(RUST_PKG_FEATURES))") \
$(if $(filter --jobserver%,$(PKG_JOBS)),,-j1) \
$(CARGO_PKG_ARGS) ; \
popd ; \
popd ; \
)
endif
endef
define Package/smartdns/install define Package/smartdns/install
$(INSTALL_DIR) $(1)/usr/sbin $(1)/etc/config $(1)/etc/init.d $(INSTALL_DIR) $(1)/usr/sbin $(1)/etc/config $(1)/etc/init.d
$(INSTALL_DIR) $(1)/etc/smartdns $(1)/etc/smartdns/domain-set $(1)/etc/smartdns/conf.d/ $(INSTALL_DIR) $(1)/etc/smartdns $(1)/etc/smartdns/domain-set $(1)/etc/smartdns/conf.d/
$(INSTALL_DIR) $(1)/etc/smartdns/ip-set $(1)/etc/smartdns/download
$(INSTALL_BIN) $(PKG_BUILD_DIR)/src/smartdns $(1)/usr/sbin/smartdns $(INSTALL_BIN) $(PKG_BUILD_DIR)/src/smartdns $(1)/usr/sbin/smartdns
$(INSTALL_BIN) $(PKG_BUILD_DIR)/package/openwrt/files/etc/init.d/smartdns $(1)/etc/init.d/smartdns $(INSTALL_BIN) $(PKG_BUILD_DIR)/package/openwrt/files/etc/init.d/smartdns $(1)/etc/init.d/smartdns
$(INSTALL_CONF) $(PKG_BUILD_DIR)/package/openwrt/address.conf $(1)/etc/smartdns/address.conf $(INSTALL_CONF) $(PKG_BUILD_DIR)/package/openwrt/address.conf $(1)/etc/smartdns/address.conf
$(INSTALL_CONF) $(PKG_BUILD_DIR)/package/openwrt/blacklist-ip.conf $(1)/etc/smartdns/blacklist-ip.conf $(INSTALL_CONF) $(PKG_BUILD_DIR)/package/openwrt/blacklist-ip.conf $(1)/etc/smartdns/blacklist-ip.conf
$(INSTALL_CONF) $(PKG_BUILD_DIR)/package/openwrt/custom.conf $(1)/etc/smartdns/custom.conf $(INSTALL_CONF) $(PKG_BUILD_DIR)/package/openwrt/custom.conf $(1)/etc/smartdns/custom.conf
$(INSTALL_CONF) $(PKG_BUILD_DIR)/package/openwrt/domain-block.list $(1)/etc/smartdns/domain-block.list
$(INSTALL_CONF) $(PKG_BUILD_DIR)/package/openwrt/domain-forwarding.list $(1)/etc/smartdns/domain-forwarding.list
$(INSTALL_CONF) $(PKG_BUILD_DIR)/package/openwrt/files/etc/config/smartdns $(1)/etc/config/smartdns $(INSTALL_CONF) $(PKG_BUILD_DIR)/package/openwrt/files/etc/config/smartdns $(1)/etc/config/smartdns
endef endef
define Package/smartdns-ui
$(Package/smartdns/default)
TITLE:=smartdns dashboard
DEPENDS:=+smartdns $(RUST_ARCH_DEPENDS)
endef
define Package/smartdns-ui/description
A dashboard ui for smartdns server.
endef
define Package/smartdns-ui/conffiles
/etc/config/smartdns
endef
define Package/smartdns-ui/install define Package/smartdns-ui/install
$(INSTALL_DIR) $(1)/usr/lib $(INSTALL_DIR) $(1)/usr/lib
$(INSTALL_DIR) $(1)/usr/share/smartdns $(INSTALL_DIR) $(1)/etc/smartdns/conf.d/
$(CP) $(PKG_BUILD_DIR)/plugin/smartdns-ui/target/$(RUSTC_TARGET_ARCH)/$(CARGO_PKG_PROFILE)/libsmartdns_ui.so $(1)/usr/lib/smartdns_ui.so $(INSTALL_DIR) $(1)/usr/share/smartdns/wwwroot
$(CP) $(PKG_BUILD_DIR)/smartdns-webui/out $(1)/usr/share/smartdns/wwwroot $(INSTALL_BIN) $(PKG_BUILD_DIR)/plugin/smartdns-ui/target/smartdns_ui.so $(1)/usr/lib/smartdns_ui.so
$(CP) $(PKG_BUILD_DIR)/smartdns-webui/out/* $(1)/usr/share/smartdns/wwwroot
endef
define Build/Compile/smartdns-webui
which npm || (echo "npm not found, please install npm first" && exit 1)
npm install --prefix $(PKG_BUILD_DIR)/smartdns-webui/
npm run build --prefix $(PKG_BUILD_DIR)/smartdns-webui/
endef
define Build/Compile/smartdns-ui
cargo install --force --locked bindgen-cli
CARGO_BUILD_ARGS="$(if $(strip $(RUST_PKG_FEATURES)),--features "$(strip $(RUST_PKG_FEATURES))") --profile $(CARGO_PKG_PROFILE)"
+$(CARGO_PKG_VARS) CARGO_BUILD_ARGS="$(CARGO_BUILD_ARGS)" CC=$(TARGET_CC) \
PATH="$$(PATH):$(CARGO_HOME)/bin" \
AWS_LC_SYS_CFLAGS="-O0" \
make -C $(PKG_BUILD_DIR)/plugin/smartdns-ui
endef
define Download/smartdns-webui
FILE:=$(SMARTDNS_WEBUI_SOURCE)
URL:=$(SMARTDNS_WEBUI_SOURCE_URL)
URL_FILE:=$(SMARTDNS_WEBUI_SOURCE_URL_FILE)
HASH:=skip
endef
$(eval $(call Download,smartdns-webui))
ifdef CONFIG_PACKAGE_smartdns-ui
define Build/Prepare
$(call Build/Prepare/Default)
$(INSTALL_DIR) $(PKG_BUILD_DIR)/smartdns-webui
$(TAR) -C $(PKG_BUILD_DIR)/smartdns-webui --strip-components=1 -xf $(DL_DIR)/$(SMARTDNS_WEBUI_SOURCE)
endef
endif
define Build/Compile
$(call Build/Compile/Default,smartdns)
ifdef CONFIG_PACKAGE_smartdns-ui
$(call Build/Compile/smartdns-ui)
$(call Build/Compile/smartdns-webui)
endif
endef endef
$(eval $(call BuildPackage,smartdns)) $(eval $(call BuildPackage,smartdns))
$(eval $(call RustBinPackage,smartdns-ui))
$(eval $(call BuildPackage,smartdns-ui)) $(eval $(call BuildPackage,smartdns-ui))
+2 -2
View File
@@ -1,8 +1,8 @@
include $(TOPDIR)/rules.mk include $(TOPDIR)/rules.mk
PKG_NAME:=Xray-core PKG_NAME:=Xray-core
PKG_VERSION:=26.10.17 PKG_VERSION:=26.10.21
PKG_RELEASE:=26 PKG_RELEASE:=27
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
PKG_SOURCE_URL:=https://codeload.github.com/XTLS/Xray-core/tar.gz/v$(PKG_VERSION)? PKG_SOURCE_URL:=https://codeload.github.com/XTLS/Xray-core/tar.gz/v$(PKG_VERSION)?