mirror of
https://github.com/kiddin9/op-packages.git
synced 2026-11-02 14:53:56 +08:00
⛄ Sync 2026-10-22 00:07:59
This commit is contained in:
1 parent
31748c050e
commit
d047be4ede
22 files changed
+379
-173
No files matched your search
@@ -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 {
|
||||||
@@ -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
@@ -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
@@ -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
@@ -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)?
|
||||||
|
|||||||
@@ -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:= \
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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:= \
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 "فایل دانلود شده خالی است یا خطایی هنگام خواندن آن رخ داده است."
|
||||||
|
|
||||||
|
|||||||
@@ -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 "Загруженный файл пуст или произошла ошибка при чтении."
|
||||||
|
|
||||||
|
|||||||
@@ -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 "下载的文件为空或读取文件时发生错误。"
|
||||||
|
|
||||||
|
|||||||
@@ -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
@@ -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
@@ -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)?
|
||||||
|
|||||||
Reference in new issue
Block a user