diff --git a/honk/Makefile b/honk/Makefile index ef5ac888..3640a34c 100644 --- a/honk/Makefile +++ b/honk/Makefile @@ -5,7 +5,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=honk -PKG_VERSION:=2026.11.02 +PKG_VERSION:=2026.11.03 PKG_RELEASE:=1 # Pinned honk-core revision (upstream daeuniverse/honk main), cross-compiled by @@ -14,10 +14,10 @@ PKG_RELEASE:=1 # assets behind CORE_COMMIT, so a plain feed build downloads and verifies them # without any generated file. A staged run may still override them through # honk/generated-stage.mk, which is generated and never committed. -CORE_COMMIT:=ce0380dc65d1eb933da7241bf88c287231efce70 +CORE_COMMIT:=77176ff8e8cc2b75385a7030dc376536c382574a # Immutable source asset tag holding this pin's core archives. -HONK_SOURCE_TAG?=source-41400973213 +HONK_SOURCE_TAG?=source-41594075839 HONK_SOURCE_URL?=https://github.com/kenzok8/openwrt-honk/releases/download/$(HONK_SOURCE_TAG) -include $(CURDIR)/generated-stage.mk @@ -25,9 +25,9 @@ HONK_SOURCE_URL?=https://github.com/kenzok8/openwrt-honk/releases/download/$(HON HONK_ASSET_X86_64?=honk-core-$(CORE_COMMIT)-x86_64.tar.gz HONK_ASSET_AARCH64?=honk-core-$(CORE_COMMIT)-aarch64.tar.gz HONK_ASSET_ARMV7?=honk-core-$(CORE_COMMIT)-armv7.tar.gz -HONK_HASH_X86_64?=cd465147cf1db1754a651be23d31124cca1cf8c1562744c4aacb37eff12acb43 -HONK_HASH_AARCH64?=28eb047028d0f5f9b8f6e4b44b0834ca3f5c8231b681b3b288b865abb5aa5f44 -HONK_HASH_ARMV7?=65ca485ceb09002bc96fd88c886f768483defd5ce3d0976136f0764028a6b875 +HONK_HASH_X86_64?=ad4801757f8b47505aa99cbdc47e4d606b8afe1a6269547d8073f68c20904a0e +HONK_HASH_AARCH64?=91a9a9929ec32d24de3c105f2a51d83a4975913a68e1446e57c2b1faf63adce6 +HONK_HASH_ARMV7?=a5b288c677698a44cc45084baf0bb67b1fb2b9ca624744a08d7a469093fc9870 # ARCH_PACKAGES is the package arch (e.g. arm_cortex-a7_neon-vfpv4); # ARCH is the CPU arch (x86_64/aarch64/arm) and coincides for 64-bit. diff --git a/luci-app-eqosplus/.github/workflows/main.yml b/luci-app-eqosplus/.github/workflows/main.yml deleted file mode 100644 index 3258ec29..00000000 --- a/luci-app-eqosplus/.github/workflows/main.yml +++ /dev/null @@ -1,47 +0,0 @@ -name: Build - -on: - push: - tags: - - v* - -jobs: - build: - name: Build ${{ matrix.arch }} - runs-on: ubuntu-latest - strategy: - fail-fast: false - matrix: - arch: - - aarch64_generic - - i386_pentium-mmx - - loongarch64_generic - - mips_mips32 - - mipsel_24kc - - mipsel_mips32 - - x86_64 - steps: - - uses: actions/checkout@main - with: - fetch-depth: 0 - - name: Building packages - uses: sbwml/openwrt-gh-action-sdk@go1.24 - env: - ARCH: ${{ matrix.arch }}-openwrt-24.10 - FEEDNAME: packages_ci - PACKAGES: luci-app-eqosplus - NO_REFRESH_CHECK: true - - - name: Upload artifacts - uses: actions/upload-artifact@v4 - with: - name: ${{ matrix.arch }} - path: bin/packages/${{ matrix.arch }}/packages_ci/*.ipk - - - name: Upload packages - uses: ncipollo/release-action@v1 - with: - token: ${{ secrets.GITHUB_TOKEN }} - allowUpdates: true - replacesArtifacts: true - artifacts: "bin/packages/${{ matrix.arch }}/packages_ci/*.ipk" diff --git a/luci-app-eqosplus/LICENSE b/luci-app-eqosplus/LICENSE deleted file mode 100644 index 574c7ac3..00000000 --- a/luci-app-eqosplus/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2025 sirpdboy - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/luci-app-eqosplus/Makefile b/luci-app-eqosplus/Makefile deleted file mode 100644 index 91e501b7..00000000 --- a/luci-app-eqosplus/Makefile +++ /dev/null @@ -1,39 +0,0 @@ -# -# Copyright (C) 2006-2017 OpenWrt.org# -# Copyright (C) 2022-2025 sirpdboy herboy2008@gmail.com https://github.com/sirpdboy/luci-app-eqosplus -# This is free software, licensed under the GNU General Public License v2. -# See /LICENSE for more information. -# - -include $(TOPDIR)/rules.mk - -THEME_NAME:=eqosplus -PKG_NAME:=luci-app-$(THEME_NAME) - -PKG_LICENSE:=Apache-2.0 - -LUCI_TITLE:=LuCI support for eqosplus. -LUCI_DESCRIPTION:=LuCI support for Easy eqosplus(Support speed limit based on IP address). -LUCI_DEPENDS:=+ip-full +tc +nftables +bc +kmod-ifb -LUCI_PKGARCH:=all - -PKG_VERSION:=1.3.0 -PKG_RELEASE:=20251128 -PKG_MAINTAINER:=sirpdboy - -define Build/Compile -endef - -define Package/$(PKG_NAME)/postinst -#!/bin/sh -rm -f /tmp/luci-* -endef - -define Package/$(PKG_NAME)/conffiles -/etc/config/eqosplus -endef - -include $(TOPDIR)/feeds/luci/luci.mk - -# call BuildPackage - OpenWrt buildroot signature - diff --git a/luci-app-eqosplus/README.md b/luci-app-eqosplus/README.md deleted file mode 100644 index d2707f57..00000000 --- a/luci-app-eqosplus/README.md +++ /dev/null @@ -1,91 +0,0 @@ -![hello](https://views.whatilearened.today/views/github/sirpdboy/deplives.svg) [![](https://img.shields.io/badge/TG群-点击加入-FFFFFF.svg)](https://t.me/joinchat/AAAAAEpRF88NfOK5vBXGBQ) - -

-
luci-app-eqosplus
-

- -

-OpenWrt -Chrome -Safari -Firefox - GitHub release -Downloads -

- -[中文] | [English](README.md) - -![screenshots](https://raw.githubusercontent.com/sirpdboy/openwrt/master/doc/说明1.jpg) - -Please read this page carefully, which includes precautions and instructions on how to use it. - -## Enhanced version of EQOS with timed speed limit and added features such as timed limit. - -### Method for downloading source code: - - ```Brach - # downloading - git clone https://github.com/sirpdboy/luci-app-eqosplus package/luci-app-eqosplus - make menuconfig - ``` -### Configuration Menu - ```Brach - make menuconfig - # find LuCI -> Applications, select luci-app-eqosplus, save and exit - ``` -### compile - - ```Brach - # compile - make package/luci-app-eqosplus/compile V=s - ``` - - -## describe - -- luci-app-eqosplus : https://github.com/sirpdboy/luci-app-eqosplus - -![screenshots](https://raw.githubusercontent.com/sirpdboy/openwrt/master/doc/说明2.jpg) - - -## interface - -![screenshots](./doc/eqosplus0.png) - -![screenshots](./doc/eqosplus1.png) - -![screenshots](https://raw.githubusercontent.com/sirpdboy/openwrt/master/doc/eqosplus.png) - -![screenshots](https://raw.githubusercontent.com/sirpdboy/openwrt/master/doc/eqosplus2.png) - - -# My other project - -- Watch Dog : https://github.com/sirpdboy/luci-app-watchdog -- Net Speedtest : https://github.com/sirpdboy/luci-app-netspeedtest -- Task Plan : https://github.com/sirpdboy/luci-app-taskplan -- Power Off Device : https://github.com/sirpdboy/luci-app-poweroffdevice -- OpentoPD Theme : https://github.com/sirpdboy/luci-theme-opentopd -- KuCat Theme : https://github.com/sirpdboy/luci-theme-kucat -- KuCat Theme Config : https://github.com/sirpdboy/luci-app-kucat-config -- NFT Time Control : https://github.com/sirpdboy/luci-app-timecontrol -- Parent Control: https://github.com/sirpdboy/luci-theme-parentcontrol -- Eqos Plus: https://github.com/sirpdboy/luci-app-eqosplus -- Advanced : https://github.com/sirpdboy/luci-app-advanced -- ddns-go : https://github.com/sirpdboy/luci-app-ddns-go -- Advanced Plus): https://github.com/sirpdboy/luci-app-advancedplus -- Net Wizard: https://github.com/sirpdboy/luci-app-netwizard -- Part Exp: https://github.com/sirpdboy/luci-app-partexp -- Lukcy: https://github.com/sirpdboy/luci-app-lukcy - -## HELP - -| 图飞了 | 图飞了 | -| :-----------------: | :-------------: | -|![xm1](https://raw.githubusercontent.com/sirpdboy/openwrt/master/doc/支付宝.png) | ![xm1](https://raw.githubusercontent.com/sirpdboy/openwrt/master/doc/微信.png) | - - - no - - -![hello](https://visitor-badge-deno.deno.dev/sirpdboy.sirpdboy.svg) [![](https://img.shields.io/badge/TGGroup-ClickJoin-FFFFFF.svg)](https://t.me/joinchat/AAAAAEpRF88NfOK5vBXGBQ) diff --git a/luci-app-eqosplus/README_CN.md b/luci-app-eqosplus/README_CN.md deleted file mode 100644 index 8da16627..00000000 --- a/luci-app-eqosplus/README_CN.md +++ /dev/null @@ -1,109 +0,0 @@ -![hello](https://views.whatilearened.today/views/github/sirpdboy/deplives.svg) [![](https://img.shields.io/badge/TG群-点击加入-FFFFFF.svg)](https://t.me/joinchat/AAAAAEpRF88NfOK5vBXGBQ) - -

-
luci-app-eqosplus
-

- -

- - - - -

- -[中文] | [English](README.md) - -![screenshots](https://raw.githubusercontent.com/sirpdboy/openwrt/master/doc/说明1.jpg) - -请 **认真阅读完毕** 本页面,本页面包含注意事项和如何使用。 - -## 功能说明: - -### 定时限速1.2.2版 -#### 2023.7.19 定时限速1.2.2:增加更多日期:工作日和休息日,自定义日期1,2,3中间用逗号分隔;加入MAC地址限速,从此不用担心IPV6和IPV4的限速问题。 - -### 定时限速1.0版 -#### 2022.12.24 定时限速在eqos的加强版,加入定时限制等功能。 - -## 编译使用方法 [![](https://img.shields.io/badge/-编译使用方法-F5F5F5.svg)](#编译使用方法-) - -将luci-app-eqosplus添加至 LEDE/OpenWRT 源码的方法。 - -### 下载源码方法一: -编辑源码文件夹根目录feeds.conf.default并加入如下内容: - -```Brach - # feeds获取源码: - src-git eqosplus https://github.com/sirpdboy/luci-app-eqosplus - ``` - ```Brach - # 更新feeds,并安装主题: - scripts/feeds update eqosplus - scripts/feeds install luci-app-eqosplus - ``` - -### 下载源码方法: - ```Brach - # 下载源码 - git clone https://github.com/sirpdboy/luci-app-eqosplus package/luci-app-eqosplus - make menuconfig - ``` -### 配置菜单 - ```Brach - make menuconfig - # 找到 LuCI -> Applications, 选择 luci-app-eqosplus, 保存后退出。 - ``` -### 编译 - ```Brach - # 编译固件 - make package/luci-app-eqosplus/compile V=s - ``` - -## 说明 [![](https://img.shields.io/badge/-说明-F5F5F5.svg)](#说明-) - -源码来源:https://github.com/sirpdboy/luci-app-eqosplus - - -- 你可以随意使用其中的源码,但请注明出处。 - -![screenshots](https://raw.githubusercontent.com/sirpdboy/openwrt/master/doc/说明2.jpg) - -## 界面 - -![screenshots](https://raw.githubusercontent.com/sirpdboy/openwrt/master/doc/eqosplus.png) - -![screenshots](https://raw.githubusercontent.com/sirpdboy/openwrt/master/doc/eqosplus2.png) - -# My other project - -- 路由安全看门狗 :https://github.com/sirpdboy/luci-app-watchdog -- 网络速度测试 :https://github.com/sirpdboy/luci-app-netspeedtest -- 计划任务插件(原定时设置) : https://github.com/sirpdboy/luci-app-taskplan -- 关机功能插件 : https://github.com/sirpdboy/luci-app-poweroffdevice -- opentopd主题 : https://github.com/sirpdboy/luci-theme-opentopd -- kucat酷猫主题: https://github.com/sirpdboy/luci-theme-kucat -- kucat酷猫主题设置工具: https://github.com/sirpdboy/luci-app-kucat-config -- NFT版上网时间控制插件: https://github.com/sirpdboy/luci-app-timecontrol -- 家长控制: https://github.com/sirpdboy/luci-theme-parentcontrol -- 定时限速: https://github.com/sirpdboy/luci-app-eqosplus -- 系统高级设置 : https://github.com/sirpdboy/luci-app-advanced -- ddns-go动态域名: https://github.com/sirpdboy/luci-app-ddns-go -- 进阶设置(系统高级设置+主题设置kucat/agron/opentopd): https://github.com/sirpdboy/luci-app-advancedplus -- 网络设置向导: https://github.com/sirpdboy/luci-app-netwizard -- 一键分区扩容: https://github.com/sirpdboy/luci-app-partexp -- lukcy大吉: https://github.com/sirpdboy/luci-app-lukcy - -## 捐助 - -![screenshots](https://raw.githubusercontent.com/sirpdboy/openwrt/master/doc/说明3.jpg) - -| 图飞了 | 图飞了 | -| :-----------------: | :-------------: | -|![xm1](https://raw.githubusercontent.com/sirpdboy/openwrt/master/doc/支付宝.png) | ![xm1](https://raw.githubusercontent.com/sirpdboy/openwrt/master/doc/微信.png) | - - - 图飞了 - - -![](https://visitor-badge-deno.deno.dev/sirpdboy.sirpdboy.svg) [![](https://img.shields.io/badge/TG群-点击加入-FFFFFF.svg)](https://t.me/joinchat/AAAAAEpRF88NfOK5vBXGBQ) - diff --git a/luci-app-eqosplus/doc/eqosplus0.png b/luci-app-eqosplus/doc/eqosplus0.png deleted file mode 100644 index 978f4abd..00000000 Binary files a/luci-app-eqosplus/doc/eqosplus0.png and /dev/null differ diff --git a/luci-app-eqosplus/doc/eqosplus1.png b/luci-app-eqosplus/doc/eqosplus1.png deleted file mode 100644 index c603fcda..00000000 Binary files a/luci-app-eqosplus/doc/eqosplus1.png and /dev/null differ diff --git a/luci-app-eqosplus/luasrc/controller/eqosplus.lua b/luci-app-eqosplus/luasrc/controller/eqosplus.lua deleted file mode 100644 index cbe01b70..00000000 --- a/luci-app-eqosplus/luasrc/controller/eqosplus.lua +++ /dev/null @@ -1,19 +0,0 @@ -module("luci.controller.eqosplus", package.seeall) --- Copyright 2022-2023 sirpdboy -function index() - if not nixio.fs.access("/etc/config/eqosplus") then return end - entry({"admin", "control"}, firstchild(), "Control", 44).dependent = false - - local e = entry({"admin", "control", "eqosplus"}, cbi("eqosplus"), _("Eqosplus"), 10) - e.dependent=false - e.acl_depends = { "luci-app-eqosplus" } - entry({"admin", "control", "eqosplus", "status"}, call("act_status")).leaf = true -end - -function act_status() - local sys = require "luci.sys" - local e = {} - e.status = sys.call(" busybox ps -w | grep eqosplus | grep -v grep >/dev/null ") == 0 - luci.http.prepare_content("application/json") - luci.http.write_json(e) -end diff --git a/luci-app-eqosplus/luasrc/model/cbi/eqosplus.lua b/luci-app-eqosplus/luasrc/model/cbi/eqosplus.lua deleted file mode 100644 index 32c3433c..00000000 --- a/luci-app-eqosplus/luasrc/model/cbi/eqosplus.lua +++ /dev/null @@ -1,190 +0,0 @@ --- Copyright 2022-2023 sirpdboy --- Licensed to the public under the Apache License 2.0. -local sys = require "luci.sys" -local ifaces = sys.net:devices() -local WADM = require "luci.tools.webadmin" -local ipc = require "luci.ip" -local a, t, e - -a = Map("eqosplus", translate("Network speed limit")) -a.description = translate("Users can limit the network speed for uploading/downloading through MAC, IP, and IP segments (192.168.110.00-192.168.10.200). The speed unit is MB/second.") -a.template = "eqosplus/index" - -t = a:section(TypedSection, "eqosplus") -t.anonymous = true - -e = t:option(DummyValue, "eqosplus_status", translate("Status")) -e.template = "eqosplus/eqosplus" -e.value = translate("Collecting data...") - - -ipi = t:option(ListValue, "ifname", translate("Interface"), translate("Set the interface used for restriction, use pppoe-wan for dialing, use WAN hardware interface for DHCP mode (such as eth1), and use br-lan for bypass mode")) -ipi.default = "1" -ipi:value(1,translate("Automatic settings")) -ipi:value("br-lan", translate("br-lan (LAN Bridge)")) -local function get_wan_interfaces() - local result = {} - local ubus = require "ubus" - - local conn = ubus.connect() - if not conn then - return result - end - - local network_status = conn:call("network.interface", "dump", {}) - for _, iface in ipairs(network_status.interface) do - if iface.interface:match("^wan") or iface.interface:match("^pppoe") or iface.proto == "pppoe" then - local dev = iface.l3_device or iface.device - if dev then - table.insert(result, { - name = dev, - proto = iface.proto, - logical_name = iface.interface - }) - end - end - end - - conn:close() - return result -end - -local wan_ifaces = get_wan_interfaces() -for _, iface in ipairs(wan_ifaces) do - ipi:value(iface.name, translate(iface.name) .. (iface.proto == "pppoe" and " (PPPoE)" or " (WAN)")) -end - -t = a:section(TypedSection, "device") -t.template = "cbi/tblsection" -t.anonymous = true -t.addremove = true - -comment = t:option(Value, "comment", translate("Comment")) -comment.size = 8 - -e = t:option(Flag, "enable", translate("Enabled")) -e.rmempty = false -e.size = 4 - -ip = t:option(Value, "mac", translate("IP/MAC")) -ip.size = 8 - -local function get_devices() - local devices = {} - local seen_ips = {} - local ubus = require "ubus" - local conn = ubus.connect() - - local function get_hostname(ip) - local f = io.popen("nslookup "..ip.." 2>/dev/null | grep 'name =' | cut -d'=' -f2 | sed 's/\\.$//'") - if f then - local name = f:read("*l") - f:close() - if name and name ~= "" then - return name:match("^%s*(.-)%s*$") - end - end - local leases_file = io.open("/tmp/dhcp.leases", "r") - if leases_file then - for line in leases_file:lines() do - local mac, ip_lease, _, hostname = line:match("^(%S+)%s+(%S+)%s+(%S+)%s+(%S+)") - if ip_lease == ip and hostname ~= "*" then - leases_file:close() - return hostname - end - end - leases_file:close() - end - return "unknown" - end - if conn then - local leases = conn:call("dhcp", "ipv4leases", {}) or {} - for _, lease in ipairs(leases) do - if lease.ipaddr and lease.mac then - local hostname = lease.hostname or get_hostname(lease.ipaddr) - devices[#devices+1] = { - ip = lease.ipaddr, - mac = lease.mac:upper(), - hostname = hostname, - display = string.format("%s (%s) - %s", lease.ipaddr, lease.mac:upper(), hostname) - } - seen_ips[lease.ipaddr] = true - end - end - conn:close() - end - local arp_cmd = io.popen("ip -4 neigh show dev br-lan 2>/dev/null") - if arp_cmd then - for line in arp_cmd:lines() do - local ip_addr, mac = line:match("^(%S+)%s+.+%s+(%S+)%s+") - if ip_addr and mac and mac ~= "00:00:00:00:00:00" and not seen_ips[ip_addr] then - mac = mac:upper() - local hostname = get_hostname(ip_addr) - devices[#devices+1] = { - ip = ip_addr, - mac = mac, - hostname = hostname, - display = string.format("%s (%s) - %s", ip_addr, mac, hostname) - } - seen_ips[ip_addr] = true - end - end - arp_cmd:close() - end - table.sort(devices, function(a, b) return a.ip < b.ip end) - return devices -end - -local devices = get_devices() -for _, dev in ipairs(devices) do - ip:value(dev.ip, dev.display) -end -dl = t:option(Value, "download", translate("Downloads")) -dl.default = '0.1' -dl.size = 4 - -ul = t:option(Value, "upload", translate("Uploads")) -ul.default = '0.1' -ul.size = 4 -function validate_time(self, value, section) - local hh, mm, ss - hh, mm, ss = string.match (value, "^(%d?%d):(%d%d)$") - hh = tonumber (hh) - mm = tonumber (mm) - if hh and mm and hh <= 23 and mm <= 59 then - return value - else - return nil, "Time HH:MM or space" - end -end - -e = t:option(Value, "timestart", translate("Start control time")) -e.placeholder = '00:00' -e.default = '00:00' -e.validate = validate_time -e.rmempty = true -e.size = 4 - -e = t:option(Value, "timeend", translate("Stop control time")) -e.placeholder = '00:00' -e.default = '00:00' -e.validate = validate_time -e.rmempty = true -e.size = 4 - -week=t:option(Value,"week",translate("Week Day(1~7)")) -week.rmempty = true -week:value('0',translate("Everyday")) -week:value(1,translate("Monday")) -week:value(2,translate("Tuesday")) -week:value(3,translate("Wednesday")) -week:value(4,translate("Thursday")) -week:value(5,translate("Friday")) -week:value(6,translate("Saturday")) -week:value(7,translate("Sunday")) -week:value('1,2,3,4,5',translate("Workday")) -week:value('6,7',translate("Rest Day")) -week.default='0' -week.size = 6 - -return a diff --git a/luci-app-eqosplus/luasrc/view/eqosplus/eqosplus.htm b/luci-app-eqosplus/luasrc/view/eqosplus/eqosplus.htm deleted file mode 100644 index 4445143f..00000000 --- a/luci-app-eqosplus/luasrc/view/eqosplus/eqosplus.htm +++ /dev/null @@ -1,3 +0,0 @@ -<%+cbi/valueheader%> -<%=pcdata(self:cfgvalue(section) or self.default or "")%> -<%+cbi/valuefooter%> \ No newline at end of file diff --git a/luci-app-eqosplus/luasrc/view/eqosplus/index.htm b/luci-app-eqosplus/luasrc/view/eqosplus/index.htm deleted file mode 100644 index c4b8a072..00000000 --- a/luci-app-eqosplus/luasrc/view/eqosplus/index.htm +++ /dev/null @@ -1,12 +0,0 @@ -<% include("cbi/map") %> - \ No newline at end of file diff --git a/luci-app-eqosplus/po/templates/eqosplus.pot b/luci-app-eqosplus/po/templates/eqosplus.pot deleted file mode 100644 index 151cee8d..00000000 --- a/luci-app-eqosplus/po/templates/eqosplus.pot +++ /dev/null @@ -1,61 +0,0 @@ - -msgid "Eqosplus" -msgstr "" - -msgid "Network speed limit" -msgstr "" - -msgid "Running state" -msgstr "" - -msgid "Not running" -msgstr "" - -msgid "Running" -msgstr "" - -msgid "Users can limit the network speed for uploading/downloading through MAC, IP, and IP segments (192.168.110.00-192.168.10.200). The speed unit is MB/second." -msgstr "" - -msgid "MAC/IP" -msgstr "" - -msgid "Downloads" -msgstr "" - -msgid "Uploads" -msgstr "" - -msgid "Comment" -msgstr "" - -msgid "Upload bandwidth(Mbit/s)" -msgstr "" - -msgid "Download bandwidth(Mbit/s)" -msgstr "" - -msgid "Start control time" -msgstr "" - -msgid "Stop control time" -msgstr "" - -msgid "Week Day(1~7)" -msgstr "" - -msgid "Suggested feedback:" -msgstr "" - -msgid "Set the interface used for restriction, use pppoe-wan for dialing, use WAN hardware interface for DHCP mode (such as eth1), and use br-lan for bypass mode" -msgstr "" - -msgid "Rest Day" -msgstr "" - -msgid "Workday" -msgstr "" - -msgid "Automatic settings" -msgstr "" - diff --git a/luci-app-eqosplus/po/zh-cn/eqosplus.po b/luci-app-eqosplus/po/zh-cn/eqosplus.po deleted file mode 100644 index 0fa56393..00000000 --- a/luci-app-eqosplus/po/zh-cn/eqosplus.po +++ /dev/null @@ -1,61 +0,0 @@ - -msgid "Eqosplus" -msgstr "定时限速" - -msgid "Network speed limit" -msgstr "定时网速限制" - -msgid "Running state" -msgstr "运行状态" - -msgid "Not running" -msgstr "未运行" - -msgid "Running" -msgstr "已运行" - -msgid "Users can limit the network speed for uploading/downloading through MAC, IP.The speed unit is MB/second." -msgstr "可以通过MAC,IP限制用户上传/下载的网速。速度单位为 MB/秒 。" - -msgid "MAC/IP" -msgstr "MAC/IP" - -msgid "Downloads" -msgstr "下载速度" - -msgid "Uploads" -msgstr "上传速度" - -msgid "Comment" -msgstr "备注" - -msgid "Upload bandwidth(Mbit/s)" -msgstr "上传总带宽(Mbit/s)" - -msgid "Download bandwidth(Mbit/s)" -msgstr "下载总带宽(Mbit/s)" - -msgid "Start control time" -msgstr "起控时间" - -msgid "Stop control time" -msgstr "停控时间" - -msgid "Week Day(1~7)" -msgstr "星期(1~7)" - -msgid "Suggested feedback:" -msgstr "建议反馈:" - -msgid "Set the interface used for restriction, use pppoe-wan for dialing, use WAN hardware interface for DHCP mode (such as eth1), and use br-lan for bypass mode" -msgstr "设定用来限制网络速度的接口,拨号使用pppoe-wan,DHCP模式使用WAN口的硬件接口(如:eth1),通用使用br-lan接口" - -msgid "Rest Day" -msgstr "休息日" - -msgid "Workday" -msgstr "工作日" - -msgid "Automatic settings" -msgstr "自动设置" - diff --git a/luci-app-eqosplus/po/zh_Hans/eqosplus.po b/luci-app-eqosplus/po/zh_Hans/eqosplus.po deleted file mode 100644 index 840559fc..00000000 --- a/luci-app-eqosplus/po/zh_Hans/eqosplus.po +++ /dev/null @@ -1,61 +0,0 @@ - -msgid "Eqosplus" -msgstr "定时限速" - -msgid "Network speed limit" -msgstr "定时网速限制" - -msgid "Running state" -msgstr "运行状态" - -msgid "Not running" -msgstr "未运行" - -msgid "Running" -msgstr "已运行" - -msgid "Users can limit the network speed for uploading/downloading through MAC, IP, and IP segments (192.168.110.00-192.168.10.200). The speed unit is MB/second." -msgstr "用户可以通过MAC、IP、IP段(192.168.10.100-192.168.10.200),限制上传/下载的网络速度。速度单位为MB/秒。。" - -msgid "MAC/IP" -msgstr "MAC/IP" - -msgid "Downloads" -msgstr "下载速度" - -msgid "Uploads" -msgstr "上传速度" - -msgid "Comment" -msgstr "备注" - -msgid "Upload bandwidth(Mbit/s)" -msgstr "上传总带宽(Mbit/s)" - -msgid "Download bandwidth(Mbit/s)" -msgstr "下载总带宽(Mbit/s)" - -msgid "Start control time" -msgstr "起控时间" - -msgid "Stop control time" -msgstr "停控时间" - -msgid "Week Day(1~7)" -msgstr "星期(1~7)" - -msgid "Suggested feedback:" -msgstr "建议反馈:" - -msgid "Set the interface used for restriction, use pppoe-wan for dialing, use WAN hardware interface for DHCP mode (such as eth1), and use br-lan for bypass mode" -msgstr "设定用来限制网络速度的接口,拨号使用pppoe-wan,DHCP模式使用WAN口的硬件接口(如:eth1),通用使用br-lan接口" - -msgid "Rest Day" -msgstr "休息日" - -msgid "Workday" -msgstr "工作日" - -msgid "Automatic settings" -msgstr "自动设置" - diff --git a/luci-app-eqosplus/root/etc/config/eqosplus b/luci-app-eqosplus/root/etc/config/eqosplus deleted file mode 100644 index 722434ae..00000000 --- a/luci-app-eqosplus/root/etc/config/eqosplus +++ /dev/null @@ -1,25 +0,0 @@ - -config eqosplus - option enabled '0' - option download '1000' - option upload '30' - option ifname '1' - -config device - option timestart '00:00' - option week '0' - option download '1' - option timeend '23:55' - option upload '1' - option mac '192.168.10.10' - option enable '0' - -config device - option mac '192.168.10.10-192.168.10.200' - option timestart '00:00' - option timeend '00:00' - option week '0' - option download '0.1' - option upload '0.1' - option enable '0' - diff --git a/luci-app-eqosplus/root/etc/hotplug.d/iface/10-eqosplus b/luci-app-eqosplus/root/etc/hotplug.d/iface/10-eqosplus deleted file mode 100644 index 91059ec8..00000000 --- a/luci-app-eqosplus/root/etc/hotplug.d/iface/10-eqosplus +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/sh -[ "$ACTION" = "ifup" ] && [ "$INTERFACE" = "wan" ] && { - sleep 5 - /etc/init.d/eqosplus restart -} \ No newline at end of file diff --git a/luci-app-eqosplus/root/etc/init.d/eqosplus b/luci-app-eqosplus/root/etc/init.d/eqosplus deleted file mode 100644 index f74b5fdd..00000000 --- a/luci-app-eqosplus/root/etc/init.d/eqosplus +++ /dev/null @@ -1,54 +0,0 @@ -#!/bin/sh /etc/rc.common -# -# Copyright (C) 2025 sirpdboy herboy2008@gmail.com https://github.com/sirpdboy/luci-app-eqosplus -# - -START=99 -USE_PROCD=1 - -NAME=eqosplus -LOCK="/var/lock/$NAME.lock" -CR=/etc/crontabs/root - -start_instance() { - procd_open_instance - procd_set_param command /usr/bin/eqosplusctrl - procd_set_param respawn - procd_set_param stderr 1 - procd_close_instance -} - -_eqosplus_start() { - if [ "$(grep -c 'option enable .1.' /etc/config/$NAME 2>/dev/null)" -gt "0" ]; then - if [ x$(uci -q get turboacc.config.sw_flow) = 'x1' ] || [ x$(uci -q get turboacc.config.sfe_flow) = 'x1' ] ;then - uci -q set turboacc.config.sw_flow='0' - uci -q set turboacc.config.sfe_flow='0' - uci -q set turboacc.config.hw_flow='0' - uci commit turboacc - /etc/init.d/turboacc restart - fi - touch $LOCK - eqosplus start - start_instance - (crontab -l ; echo "00 1 * * * /etc/init.d/eqosplus start") | sort - | uniq - | crontab - - fi -} - -start_service(){ - [ -f $LOCK ] && exit - stop_service - _eqosplus_start - rm -f $LOCK -} - -service_triggers() { - procd_add_reload_trigger 'eqosplus' -} - -stop_service(){ - kill -9 $(busybox ps -w | grep 'eqosplusctrl' | grep -v 'grep' | awk '{print $1}') >/dev/null 2>&1 - sed -i '/eqosplus/d' $CR >/dev/null 2>&1 - rm -f $LOCK 2>/dev/null - eqosplus stop -} - diff --git a/luci-app-eqosplus/root/etc/uci-defaults/luci-eqosplus b/luci-app-eqosplus/root/etc/uci-defaults/luci-eqosplus deleted file mode 100644 index f22cd0c6..00000000 --- a/luci-app-eqosplus/root/etc/uci-defaults/luci-eqosplus +++ /dev/null @@ -1,13 +0,0 @@ -#!/bin/sh -chmod +x /etc/init.d/eqosplus /usr/bin/eqosplus* -uci -q batch <<-EOF >/dev/null - delete ucitrack.@eqosplus[-1] - add ucitrack eqosplus - set ucitrack.@eqosplus[-1].init=eqosplus - commit ucitrack -EOF - -[ -s /etc/config/eqosplus ] || echo "config eqosplus" > /etc/config/eqosplus - -rm -f /tmp/luci-indexcache -exit 0 diff --git a/luci-app-eqosplus/root/usr/bin/eqosplus b/luci-app-eqosplus/root/usr/bin/eqosplus deleted file mode 100644 index 721fafa0..00000000 --- a/luci-app-eqosplus/root/usr/bin/eqosplus +++ /dev/null @@ -1,379 +0,0 @@ -#!/bin/bash - -# Copyright (C) 2006 OpenWrt.org -# Copyright 2022-2025 sirpdboy - -crrun=$1 -crid=$2 -NAME=eqosplus -IDLIST="/var/$NAME.idlist" -LOCK="/var/lock/$NAME.lock" -TMPID="/var/$NAME.tmpid" -LOG="/var/$NAME_log.log" -# idlist=`uci show $NAME | grep "enable='1'" | grep "device" | grep -oE '\[.*?\]' | grep -o '[0-9]' ` - - -if [ x$(uci get $NAME.@$NAME[0].ifname 2>/dev/null) = 'x1' ]; then - ifname=$(uci -q get network.lan.ifname) - [ "x$ifname" = "x" ] && ifname="device" || ifname="ifname" - dev=$(uci -q get network.wan.$ifname) - [ ! "$dev" ] && dev=br-lan -else - dev=$(uci -q get $NAME.@$NAME[0].ifname 2>/dev/null) - [ ! "$dev" ] && dev=br-lan -fi - -bin_nft=$(which nft) -bin_tc=$(which tc) -bin_ip=$(which ip) -DEBUG=1 - -nft_type() { - if command -v nft >/dev/null; then - nftables_ver="true" - fi -} - -# Debug functions -dbg_nft() { - [ "${DEBUG:-0}" -eq 0 ] || echo "DEBUG: nft $*" - $bin_nft "$@" -} - -dbg_tc() { - [ "${DEBUG:-0}" -eq 0 ] || echo "DEBUG: tc $*" - $bin_tc "$@" -} - -dbg_ip() { - [ "${DEBUG:-0}" -eq 0 ] || echo "DEBUG: ip $*" - $bin_ip "$@" -} - -is_macaddr() { - ret=1 - if echo "$1" | grep -qE '^([0-9A-Fa-f]{2}[-:]){5}[0-9A-Fa-f]{2}$'; then - ret=0 - fi - return $ret -} - -# 数值比较函数 -is_gt_zero() { - local value=$1 - # 使用bc进行浮点数比较 - echo "$value > 0" | bc -l 2>/dev/null | grep -q 1 -} - -# 转换为kbit -to_kbit() { - local mb=$1 - # MB/s 转 kbit/s: 1 MB/s = 8192 kbit/s - echo "scale=0; $mb * 8192 / 1" | bc 2>/dev/null || echo "0" -} - -# Default commands -tc="dbg_tc" -ip="dbg_ip" -nft="dbg_nft" - -nft_type - -stop_qos() { - for face in $(tc qdisc show 2>/dev/null | grep htb | awk '{print $5}'); do - $tc qdisc del dev $face root 2>/dev/null - done - - $tc qdisc del dev ${dev} root 2>/dev/null - $tc qdisc del dev ${dev}_ifb root 2>/dev/null - $tc qdisc del dev ${dev} ingress 2>/dev/null - $ip link del dev ${dev}_ifb 2>/dev/null 2>&1 - - if [ -n "$nftables_ver" ]; then - $nft delete table inet ${NAME} 2>/dev/null - $nft delete table bridge ${NAME} 2>/dev/null - fi - - echo "" > "$IDLIST" 2>/dev/null -} - -init_qosplus() { - - insmod sch_htb 2>/dev/null - insmod act_mirred 2>/dev/null - insmod ifb 2>/dev/null - - $ip link del dev ${dev}_ifb 2>/dev/null - $ip link add dev ${dev}_ifb name ${dev}_ifb type ifb - $ip link set dev ${dev}_ifb up - - $tc qdisc del dev ${dev} root 2>/dev/null - $tc qdisc add dev ${dev} root handle 1:0 htb default 1 - $tc class add dev ${dev} parent 1:0 classid 1:1 htb rate 1000mbit ceil 1000mbit - - $tc qdisc del dev ${dev}_ifb root 2>/dev/null - $tc qdisc add dev ${dev}_ifb root handle 1:0 htb default 1 - $tc class add dev ${dev}_ifb parent 1:0 classid 1:1 htb rate 1000mbit ceil 1000mbit - lanipaddr=$(uci -q get network.lan.ipaddr 2>/dev/null | awk -F '.' '{print $1"."$2"."$3".0/24"}') - if [ -n "$lanipaddr" ]; then - $tc filter add dev $dev parent 1:0 protocol ip prio 1 u32 match ip src "$lanipaddr" match ip dst "$lanipaddr" flowid 1:1 - $tc filter add dev ${dev}_ifb parent 1:0 protocol ip prio 1 u32 match ip src "$lanipaddr" match ip dst "$lanipaddr" flowid 1:1 - fi - $tc qdisc del dev ${dev} ingress 2>/dev/null - $tc qdisc add dev ${dev} ingress - $tc filter add dev ${dev} parent ffff: protocol all prio 2 u32 match u32 0 0 flowid 1:1 action mirred egress redirect dev ${dev}_ifb - - if [ -n "$nftables_ver" ]; then - $nft delete table inet ${NAME} 2>/dev/null - $nft delete table bridge ${NAME} 2>/dev/null - - $nft add table inet ${NAME} - - $nft add chain inet ${NAME} mark_forward { type filter hook forward priority -200\; policy accept\; } - $nft add chain inet ${NAME} mark_output { type filter hook output priority -200\; policy accept\; } - $nft add chain inet ${NAME} mark_postrouting { type filter hook postrouting priority -200\; policy accept\; } - fi - - return 0 -} - - -del_id() { - local list_id=$1 - id=$((list_id * 10 + 1000)) - [ "${DEBUG:-0}" -eq 0 ] || echo "D: del_id $@ --$id --$mac" - $tc filter del dev ${dev} parent 1: handle 800::$(printf "%x" $id) 2>/dev/null - $tc class del dev ${dev} parent 1:1 classid 1:$id 2>/dev/null - $tc filter del dev ${dev}_ifb parent 1: handle 800::$(printf "%x" $id) 2>/dev/null - $tc class del dev ${dev}_ifb parent 1:1 classid 1:$id 2>/dev/null - mac=$(uci -q get $NAME.@device[$list_id].mac 2>/dev/null) - if [ -n "$nftables_ver" ] && [ -n "$mac" ]; then - if is_macaddr "$mac"; then - $nft delete rule inet ${NAME} mark_forward ether saddr $mac counter 2>/dev/null - $nft delete rule inet ${NAME} mark_output ether saddr $mac counter 2>/dev/null - $nft delete rule inet ${NAME} mark_postrouting ether saddr $mac counter 2>/dev/null - else - Z=$(echo $mac | awk -F '[/]' '{print $2}') - [ -n "$Z" ] && mac=$(echo $mac | awk -F '[/]' '{print $1}') || Z=32 - $nft delete rule inet ${NAME} mark_forward ip saddr $mac/$Z counter 2>/dev/null - $nft delete rule inet ${NAME} mark_output ip saddr $mac/$Z counter 2>/dev/null - $nft delete rule inet ${NAME} mark_postrouting ip saddr $mac/$Z counter 2>/dev/null - fi - fi -} - -add_mac() { - local list_id=$1 - id=$((list_id * 10 + 1000)) - M0=$(echo $mac | cut -d : -f 1)$(echo $mac | cut -d : -f 2) - M1=$(echo $mac | cut -d : -f 3)$(echo $mac | cut -d : -f 4) - M2=$(echo $mac | cut -d : -f 5)$(echo $mac | cut -d : -f 6) - [ "${DEBUG:-0}" -eq 0 ] || echo "D: add_mac $@ --id:$id --mac:$mac M012--$M0-$M1-$M2" - - if is_gt_zero "$UL"; then - if [ -n "$nftables_ver" ]; then - $nft add rule inet ${NAME} mark_forward ether saddr $mac counter meta mark set $id - $nft add rule inet ${NAME} mark_output ether saddr $mac counter meta mark set $id - $nft add rule inet ${NAME} mark_postrouting ether saddr $mac counter meta mark set $id - fi - $tc class add dev ${dev}_ifb parent 1:1 classid 1:$id htb rate "${UL}kbit" ceil "${UL}kbit" prio $id burst 15k cburst 15k - $tc qdisc add dev ${dev}_ifb parent 1:$id handle ${id}: sfq perturb 10 - - $tc filter add dev ${dev}_ifb parent 1: protocol ip prio $id handle $id fw flowid 1:$id - - $tc filter add dev ${dev}_ifb parent 1: protocol ip prio $((id + 100)) u32 \ - match u16 0x0800 0xFFFF at -2 \ - match u16 0x${M2} 0xFFFF at -4 \ - match u32 0x${M0}${M1} 0xFFFFFFFF at -8 \ - flowid 1:$id - fi - if is_gt_zero "$DL"; then - $tc class add dev ${dev} parent 1:1 classid 1:$id htb rate "${DL}kbit" ceil "${DL}kbit" prio $id burst 15k cburst 15k - $tc qdisc add dev ${dev} parent 1:$id handle ${id}: sfq perturb 10 - - $tc filter add dev ${dev} parent 1: protocol ip prio $id u32 \ - match u16 0x0800 0xFFFF at -2 \ - match u32 0x${M1}${M2} 0xFFFFFFFF at -12 \ - match u16 0x${M0} 0xFFFF at -14 \ - flowid 1:$id - fi -} - -add_ip() { - local list_id=$1 - id=$((list_id * 10 + 1000)) - [ "${DEBUG:-0}" -eq 0 ] || echo "D: add_ip $@ --$id --$mac" - - Z=$(echo $mac | awk -F '[/]' '{print $2}') - [ -n "$Z" ] && mac=$(echo $mac | awk -F '[/]' '{print $1}') || Z=32 - if is_gt_zero "$UL"; then - if [ -n "$nftables_ver" ]; then - $nft add rule inet ${NAME} mark_forward ip saddr $mac/$Z counter meta mark set $id - $nft add rule inet ${NAME} mark_output ip saddr $mac/$Z counter meta mark set $id - $nft add rule inet ${NAME} mark_postrouting ip saddr $mac/$Z counter meta mark set $id - fi - $tc class add dev ${dev}_ifb parent 1:1 classid 1:$id htb rate "${UL}kbit" ceil "${UL}kbit" prio $id burst 15k cburst 15k - $tc qdisc add dev ${dev}_ifb parent 1:$id handle ${id}: sfq perturb 10 - $tc filter add dev ${dev}_ifb parent 1: protocol ip prio $id handle $id fw flowid 1:$id - $tc filter add dev ${dev}_ifb parent 1:0 prio $((id + 100)) protocol ip u32 \ - match ip src "$mac"/"$Z" \ - flowid 1:$id - fi - if is_gt_zero "$DL"; then - $tc class add dev ${dev} parent 1:1 classid 1:$id htb rate "${DL}kbit" ceil "${DL}kbit" prio $id burst 15k cburst 15k - $tc qdisc add dev ${dev} parent 1:$id handle ${id}: sfq perturb 10 - $tc filter add dev ${dev} parent 1:0 prio $id protocol ip u32 \ - match ip dst "$mac"/"$Z" \ - flowid 1:$id - fi -} - -check_time() { - local start=$1 - local end=$2 - local current=$(date +%H%M) - local start_min=$((10#${start:0:2}*60 + 10#${start:3:2})) - local end_min=$((10#${end:0:2}*60 + 10#${end:3:2})) - local current_min=$((10#${current:0:2}*60 + 10#${current:2:2})) - - if [[ $start_min -lt $end_min ]]; then - [[ $current_min -ge $start_min && $current_min -lt $end_min ]] - else - [[ $current_min -ge $start_min || $current_min -lt $end_min ]] - fi -} - -check_list() { - local i=$1 - local start_time=$(uci -q get $NAME.@device[$i].timestart 2>/dev/null) - local end_time=$(uci -q get $NAME.@device[$i].timeend 2>/dev/null) - local wweek=$(uci -q get $NAME.@device[$i].week 2>/dev/null) - local current_weekday=$(date +%u) - [ -z "$start_time" ] && [ -z "$end_time" ] && [ -z "$wweek" ] && return 0 - - if [ -n "$wweek" ] && [ "$wweek" != "0" ]; then - local day_match=0 - for day in $(echo $wweek | tr ',' ' '); do - [ "$day" -eq "$current_weekday" ] && day_match=1 && break - done - [ "$day_match" -eq 0 ] && return 1 - fi - - if [ -n "$start_time" ] && [ -n "$end_time" ]; then - check_time "$start_time" "$end_time" || return 1 - fi - - return 0 -} - -case "$crrun" in - "stop") - stop_qos - ;; - "start") - stop_qos > /dev/null 2>&1 - sleep 2 - init_qosplus - idlist=$(uci show $NAME 2>/dev/null | grep "enable='1'" | grep "device" | grep -oE '\[.*?\]' | grep -o '[0-9]' | sort -nu | sed -e 's/^/!/g' -e 's/$/!/g' > $IDLIST; cat $IDLIST 2>/dev/null | sed -e 's/!//g') - - if [ ! -s "$IDLIST" ]; then - return 1 - fi - - device_count=0 - for list in $(echo $idlist | sed -e 's/!//g'); do - if check_list $list; then - mac=$(uci -q get $NAME.@device[$list].mac 2>/dev/null) - download_mb=$(uci -q get $NAME.@device[$list].download 2>/dev/null) - upload_mb=$(uci -q get $NAME.@device[$list].upload 2>/dev/null) - comment=$(uci -q get $NAME.@device[$list].comment 2>/dev/null) - - # 转换为kbit - DL=$(to_kbit "$download_mb") - UL=$(to_kbit "$upload_mb") - - if [ -n "$mac" ]; then - if is_macaddr "$mac"; then - add_mac $list >>$LOG - echo "✅ MAC限速: $comment ($mac) - 下载:${download_mb}MB/s(${DL}kbit/s) 上传:${upload_mb}MB/s(${UL}kbit/s)" >>$LOG - else - add_ip $list >>$LOG - echo "✅ IP限速: $comment ($mac) - 下载:${download_mb}MB/s(${DL}kbit/s) 上传:${upload_mb}MB/s(${UL}kbit/s)" >>$LOG - fi - device_count=$((device_count + 1)) - fi - else - [ -f "$IDLIST" ] && [ $(grep "!${list}!" "$IDLIST" 2>/dev/null | wc -l) -gt 0 ] && { - del_id $list >>$LOG - sed -i "/!$list!/d" "$IDLIST" >/dev/null 2>&1 - comment=$(uci -q get $NAME.@device[$list].comment 2>/dev/null) - } - fi - done - echo "EQOSPLUS限速服务启动完成,共配置 $device_count 个设备" >>$LOG - echo "" - echo "当前限速状态:" >>$LOG - tc -s class show dev $dev | grep "rate" | head -5 >>$LOG - tc -s class show dev ${dev}_ifb | grep "rate" | head -5 >>$LOG - - ;; - "add") - echo "➕ 添加限速规则..." - for list in $(echo $crid | sed -e 's/!//g' | sed 's/,/ /g'); do - mac=$(uci -q get $NAME.@device[$list].mac 2>/dev/null) - download_mb=$(uci -q get $NAME.@device[$list].download 2>/dev/null) - upload_mb=$(uci -q get $NAME.@device[$list].upload 2>/dev/null) - comment=$(uci -q get $NAME.@device[$list].comment 2>/dev/null) - DL=$(to_kbit "$download_mb") - UL=$(to_kbit "$upload_mb") - - if is_macaddr $mac; then - add_mac $list - echo "✅ 添加MAC限速: $comment ($mac)" >>$LOG - else - add_ip $list - echo "✅ 添加IP限速: $comment ($mac)" >>$LOG - fi - done - ;; - "del") - for list in $(echo $crid | sed -e 's/!//g' | sed 's/,/ /g'); do - comment=$(uci -q get $NAME.@device[$list].comment 2>/dev/null) - mac=$(uci -q get $NAME.@device[$list].mac 2>/dev/null) - del_id $list - done - ;; - "status") - echo "EQOSPLUS限速服务状态" - echo "### 网络接口: $dev ###" - echo "# 下载队列统计 #" - tc -s qdisc show dev $dev 2>/dev/null || echo "无下载队列" - echo "# 下载类统计 #" - tc -s class show dev $dev 2>/dev/null | grep -E "class htb|rate [0-9]" || echo "无下载类" - echo "# 下载过滤器 #" - tc -s filter show dev $dev parent 1: 2>/dev/null | head -10 || echo "无下载过滤器" - - echo "### 虚拟接口: ${dev}_ifb ###" - echo "# 上传队列统计 #" - tc -s qdisc show dev ${dev}_ifb 2>/dev/null || echo "无上传队列" - echo "# 上传类统计 #" - tc -s class show dev ${dev}_ifb 2>/dev/null | grep -E "class htb|rate [0-9]" || echo "无上传类" - echo "# 上传过滤器 #" - tc -s filter show dev ${dev}_ifb parent 1: 2>/dev/null | head -10 || echo "无上传过滤器" - - if [ -n "$nftables_ver" ]; then - echo "### NFTables规则 ###" - nft list table inet ${NAME} 2>/dev/null || echo "没有NFTables规则" - else - echo "NFTables不可用" - fi - - # 显示流量统计 - echo "### 流量统计 ###" - echo "下载流量:" - tc -s class show dev $dev 2>/dev/null | grep "Sent" | head -5 - echo "上传流量:" - tc -s class show dev ${dev}_ifb 2>/dev/null | grep "Sent" | head -5 - ;; - -esac \ No newline at end of file diff --git a/luci-app-eqosplus/root/usr/bin/eqosplusctrl b/luci-app-eqosplus/root/usr/bin/eqosplusctrl deleted file mode 100644 index 9b5721d6..00000000 --- a/luci-app-eqosplus/root/usr/bin/eqosplusctrl +++ /dev/null @@ -1,63 +0,0 @@ -#!/bin/sh - -# Copyright (C) 2006 OpenWrt.org -# Copyright 2022-2025 sirpdboy -NAME=eqosplus -IDLIST="/var/$NAME.idlist" -TMPID="/var/$NAME.tmpid" - -idlist=`uci show $NAME | grep "enable='1'" | grep "device" | grep -oE '\[.*?\]' | grep -o '[0-9]' ` - -check_list() { - i=$1 - checki='0' - start_time=$(uci -q get $NAME.@device[$i].timestart 2>/dev/null) - end_time=$(uci -q get $NAME.@device[$i].timeend 2>/dev/null) - wweek=`uci -q get $NAME.@device[$i].week ` - current_time=$(date +%H:%M) - current_weekday=$(date +%u) - for ww in `echo $wweek | sed 's/,/ /g' `; do - if [ $current_weekday = $ww ] || [ 'x0' = x$ww ] ;then - [ "$start_time" = "$end_time" ] && checki='1' || { - if [ "$start_time" \< "$end_time" ]; then - if [ "$current_time" \> "$start_time" ] && [ "$current_time" \< "$end_time" ] ; then - checki='1' - fi - else - if [ "$start_time" \> "$end_time" ] ; then - if [ "$current_time" \< "$start_time" ] && [ "$current_time" \> "$end_time" ] ; then - checki='1' - fi - fi - fi - } - fi - done - return -} - -idlistusr(){ - checki='0' - [ -s $IDLIST ] || touch $IDLIST - for list in $idlist ;do - check_list $list - if [ $checki == '1' ] ; then - [ `cat $IDLIST 2>/dev/null | grep "!${list}!" | wc -l ` -gt 0 ] || { - eqosplus add $list - echo "!${list}!" >> $IDLIST ; cat $IDLIST | sort | uniq > $TMPID ;cat $TMPID >$IDLIST ;rm -rf $TMPID - } - else - [ `cat $IDLIST 2>/dev/null | grep "!${list}!" | wc -l ` -gt 0 ] && { - eqosplus del $list - sed -i "/!$list!/d" $IDLIST >/dev/null 2>&1 - } - fi - done -} - - -while :;do - sleep 30 - idlistusr - sleep 30 -done \ No newline at end of file diff --git a/luci-app-eqosplus/root/usr/share/rpcd/acl.d/luci-app-eqosplus.json b/luci-app-eqosplus/root/usr/share/rpcd/acl.d/luci-app-eqosplus.json deleted file mode 100644 index b879f4de..00000000 --- a/luci-app-eqosplus/root/usr/share/rpcd/acl.d/luci-app-eqosplus.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "luci-app-eqosplus": { - "description": "Grant UCI access for luci-app-eqosplus", - "read": { - "uci": [ "eqosplus" ] - }, - "write": { - "uci": [ "eqosplus" ] - } - } -} diff --git a/luci-app-eqosplus/界面.png b/luci-app-eqosplus/界面.png deleted file mode 100644 index d346c698..00000000 Binary files a/luci-app-eqosplus/界面.png and /dev/null differ diff --git a/luci-app-honk/Makefile b/luci-app-honk/Makefile index 781bfab5..0d00360a 100644 --- a/luci-app-honk/Makefile +++ b/luci-app-honk/Makefile @@ -5,18 +5,18 @@ include $(TOPDIR)/rules.mk PKG_NAME:=luci-app-honk -PKG_VERSION:=2026.11.02 +PKG_VERSION:=2026.11.03 PKG_RELEASE:=1 PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME) -PKG_SOURCE:=doona-08b2a3e1-567a62ed5cac.tar.gz +PKG_SOURCE:=doona-46e153cf-c6229ba102e8.tar.gz # Each package Makefile is evaluated on its own, so this tag is defined here too # instead of relying on the honk package's variable. It must match honk/Makefile: # scripts/check.sh enforces that. -HONK_SOURCE_TAG?=source-41400973213 +HONK_SOURCE_TAG?=source-41594075839 PKG_SOURCE_URL?=https://github.com/kenzok8/openwrt-honk/releases/download/$(HONK_SOURCE_TAG) PKG_SOURCE_SUBDIR:=doona -PKG_HASH:=567a62ed5cac88be540d73d9b41b09b309538b7cedc3b69d56fef880a084d96e +PKG_HASH:=c6229ba102e867407540b3ec220595eff6ed63d7ae0037377432281977c9cf86 -include $(CURDIR)/generated-doona-stage.mk diff --git a/luci-app-passwall/Makefile b/luci-app-passwall/Makefile index 9b5f1882..0a0d6b22 100644 --- a/luci-app-passwall/Makefile +++ b/luci-app-passwall/Makefile @@ -7,7 +7,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=luci-app-passwall -PKG_VERSION:=26.10.29 +PKG_VERSION:=26.11.3 PKG_RELEASE:=1 PKG_PO_VERSION:=$(PKG_VERSION) diff --git a/luci-app-passwall/luasrc/view/passwall/haproxy/js.htm b/luci-app-passwall/luasrc/view/passwall/haproxy/js.htm index e943a205..ceaa16b5 100644 --- a/luci-app-passwall/luasrc/view/passwall/haproxy/js.htm +++ b/luci-app-passwall/luasrc/view/passwall/haproxy/js.htm @@ -64,8 +64,9 @@ local appname = map.config const lastVal = lastInput.value.trim(); const secondLastVal = secondLastInput.value.trim(); - const lbssHiddenInput = lastRow.querySelector("div.cbi-dropdown > div > input[type='hidden'][name$='.lbss']"); - if (!lbssHiddenInput) { + const lbssInput = lastRow.querySelector("input[type='text'][name$='.lbss']"); + const hasNodeSelected = lbssInput && lbssInput.value && lbssInput.value.trim() !== ""; + if (!hasNodeSelected) { if (lastVal !== secondLastVal && secondLastVal !== "" && secondLastVal !== "0") { lastInput.value = secondLastVal; } diff --git a/luci-app-passwall2/Makefile b/luci-app-passwall2/Makefile index 90245ead..57b72e6c 100644 --- a/luci-app-passwall2/Makefile +++ b/luci-app-passwall2/Makefile @@ -6,7 +6,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=luci-app-passwall2 -PKG_VERSION:=26.10.29 +PKG_VERSION:=26.11.3 PKG_RELEASE:=1 PKG_PO_VERSION:=$(PKG_VERSION) diff --git a/luci-app-passwall2/luasrc/view/passwall2/haproxy/js.htm b/luci-app-passwall2/luasrc/view/passwall2/haproxy/js.htm index e943a205..ceaa16b5 100644 --- a/luci-app-passwall2/luasrc/view/passwall2/haproxy/js.htm +++ b/luci-app-passwall2/luasrc/view/passwall2/haproxy/js.htm @@ -64,8 +64,9 @@ local appname = map.config const lastVal = lastInput.value.trim(); const secondLastVal = secondLastInput.value.trim(); - const lbssHiddenInput = lastRow.querySelector("div.cbi-dropdown > div > input[type='hidden'][name$='.lbss']"); - if (!lbssHiddenInput) { + const lbssInput = lastRow.querySelector("input[type='text'][name$='.lbss']"); + const hasNodeSelected = lbssInput && lbssInput.value && lbssInput.value.trim() !== ""; + if (!hasNodeSelected) { if (lastVal !== secondLastVal && secondLastVal !== "" && secondLastVal !== "0") { lastInput.value = secondLastVal; } diff --git a/luci-app-ssr-plus/Makefile b/luci-app-ssr-plus/Makefile index af5a2aee..890556ff 100644 --- a/luci-app-ssr-plus/Makefile +++ b/luci-app-ssr-plus/Makefile @@ -20,6 +20,7 @@ PKG_CONFIG_DEPENDS:= \ CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_Kcptun \ CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_NaiveProxy \ CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_Shadowsocks_NONE_Client \ + CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_Shadowsocks_Rust_Client \ CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_Shadowsocks_NONE_Server \ CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_Shadowsocks_Rust_Server \ CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_Shadowsocks_Simple_Obfs \ diff --git a/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua b/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua index 263064b3..919644f2 100644 --- a/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua +++ b/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua @@ -479,6 +479,9 @@ end if is_finded("xray") then o:value("hysteria2", translate("Hysteria2")) end +if is_finded("xray") then + o:value("masque", translate("MASQUE")) +end if is_finded("xray") or is_finded("mihomo") then o:value("snell", translate("Snell")) end @@ -495,6 +498,7 @@ o:depends("type", "ss-rust") o:depends("type", "trojan") o:depends("type", "naiveproxy") o:depends("type", "hysteria2") +o:depends("type", "masque") o:depends("type", "tuic") o:depends("type", "shadowtls") o:depends("type", "socks5") @@ -520,6 +524,7 @@ o:depends("type", "ss-rust") o:depends("type", "trojan") o:depends("type", "naiveproxy") o:depends("type", "hysteria2") +o:depends("type", "masque") o:depends("type", "tuic") o:depends("type", "shadowtls") o:depends("type", "socks5") @@ -542,6 +547,7 @@ o.default = "0" o:depends("type", "socks5") o:depends({type = "v2ray", v2ray_protocol = "http"}) o:depends({type = "v2ray", v2ray_protocol = "socks"}) +o:depends({type = "v2ray", v2ray_protocol = "masque"}) o = s:option(Value, "username", translate("Username")) o.rmempty = true @@ -550,6 +556,7 @@ o:depends({type = "v2ray", v2ray_protocol = "naive"}) o:depends({type = "socks5", auth_enable = true}) o:depends({type = "v2ray", v2ray_protocol = "http", auth_enable = true}) o:depends({type = "v2ray", v2ray_protocol = "socks", auth_enable = true}) +o:depends({type = "v2ray", v2ray_protocol = "masque", auth_enable = true}) o = s:option(Value, "password", translate("Password")) o.password = true @@ -563,6 +570,7 @@ o:depends("type", "shadowtls") o:depends({type = "socks5", auth_enable = true}) o:depends({type = "v2ray", v2ray_protocol = "http", auth_enable = true}) o:depends({type = "v2ray", v2ray_protocol = "socks", socks_ver = "5", auth_enable = true}) +o:depends({type = "v2ray", v2ray_protocol = "masque", auth_enable = true}) o:depends({type = "v2ray", v2ray_protocol = "shadowsocks"}) o:depends({type = "v2ray", v2ray_protocol = "trojan"}) o:depends({type = "v2ray", v2ray_protocol = "anytls"}) @@ -581,6 +589,56 @@ for _, field in ipairs({ o:depends({type = "v2ray", v2ray_protocol = "anytls"}) end +-- [[ MASQUE ]] -- +o = s:option(Flag, "masque_warp", "WARP") +o.default = "0" +o:depends({type = "v2ray", v2ray_protocol = "masque"}) + +for _, field in ipairs({ + { "masque_warp_private_key", translate("WARP Device Private Key") }, + { "masque_warp_public_key", translate("WARP Endpoint Public Key") } +}) do + o = s:option(TextValue, field[1], field[2]) + o.rows = 3 + o.wrap = "off" + o:depends({type = "v2ray", v2ray_protocol = "masque", masque_warp = "1"}) + o.cfgvalue = function(self, section) + return (m:get(section, self.option) or ""):gsub("\\n", "\n") + end + o.validate = function(self, value) + return trim(value):gsub("\r\n?", "\n"):gsub("\n", "\\n") + end +end + +o = s:option(DynamicList, "masque_warp_address", "WARP " .. translate("Local Address")) +o:depends({type = "v2ray", v2ray_protocol = "masque", masque_warp = "1"}) + +o = s:option(Value, "masque_path", translate("MASQUE Path")) +o:depends({type = "v2ray", v2ray_protocol = "masque"}) + +o = s:option(TextValue, "masque_headers", translate("Custom HTTP Headers")) +o.rows = 5 +o.wrap = "off" +o:depends({type = "v2ray", v2ray_protocol = "masque"}) +o.cfgvalue = function(self, section) + return (m:get(section, "masque_headers") or ""):gsub("\\n", "\n") +end +o.validate = function(self, value) + value = trim(value):gsub("\r\n", "\n"):gsub("\r", "\n") + local headers = {} + for line in value:gmatch("[^\n]+") do + if trim(line) ~= "" then + local key = line:match("^%s*([^:]+):") + key = key and trim(key):lower() + if not key or not key:match("^[!#$%%&'*+%.%^_`|~%w%-]+$") or headers[key] or key == "host" or key == "capsule-protocol" then + return nil, translate("Not true format, please re-enter!") .. " (" .. line .. ")" + end + headers[key] = true + end + end + return value:gsub("\n", "\\n") +end + o = s:option(Value, "snell_psk", translate("Snell PSK")) o.password = true o.rmempty = true @@ -1501,6 +1559,7 @@ o:depends("transport", "ws") o:depends("transport", "httpupgrade") o:depends("transport", "xhttp") o:depends("transport", "grpc") +o:depends("v2ray_protocol", "masque") --[[ FinalMask部分 ]]-- o = s:option(Flag, "enable_finalmask", translate("FinalMask")) @@ -1591,6 +1650,7 @@ o:depends({type = "v2ray", v2ray_protocol = "vmess", reality = false}) o:depends({type = "v2ray", v2ray_protocol = "trojan", reality = false}) o:depends({type = "v2ray", v2ray_protocol = "shadowsocks", reality = false}) o:depends({type = "v2ray", v2ray_protocol = "hysteria2", reality = false}) +o:depends({type = "v2ray", v2ray_protocol = "masque", reality = false}) o:depends({type = "v2ray", v2ray_protocol = "anytls", reality = false}) o:depends({type = "v2ray", v2ray_protocol = "socks", socks_ver = "5", reality = false}) o:depends({type = "v2ray", v2ray_protocol = "http", reality = false}) @@ -1649,8 +1709,17 @@ if is_finded("xray") then o:value("randomized", translate("randomized")) o:value("unsafe", translate("unsafe")) o:value("", translate("disable")) - o:depends({type = "v2ray", tls = true}) - o:depends({type = "v2ray", reality = true}) + local protocols = s.fields["v2ray_protocol"].keylist + if protocols and type(protocols) == "table" and #protocols > 0 then + for _, proto in ipairs(protocols) do + if not proto:find("^_") then + if proto ~= "masque" then + o:depends({type = "v2ray", v2ray_protocol = proto, tls = true}) + o:depends({type = "v2ray", v2ray_protocol = proto, reality = true}) + end + end + end + end o = s:option(Flag, "enable_ech", translate("Enable ECH(optional)")) o.rmempty = true @@ -1730,6 +1799,8 @@ o:value("h3,h2") o:value("http/1.1") o:value("h2,http/1.1") o:value("h3,h2,http/1.1") +o:depends("type", "trojan") +o:depends("type", "hysteria2") o:depends("tls", true) -- TUIC ALPN @@ -1782,6 +1853,23 @@ if xray_version_val >= 260131 then string.format("%s", "→ " .. translate("Fetch Manually")) end +o = s:option(Flag, "masque_certificate", translate("TLS Certificate (PEM)")) +o.default = "0" +o:depends({type = "v2ray", v2ray_protocol = "masque", tls = true}) + +o = s:option(TextValue, "masque_certificate_pem", " ", translate("Full certificate (chain), PEM format.")) +o.default = "" +o.rows = 5 +o.wrap = "off" +o:depends("masque_certificate", 1) +o.cfgvalue = function(self, section) + return (m:get(section, "masque_certificate_pem") or ""):gsub("\\n", "\n") +end +o.validate = function(self, value) + value = trim(value):gsub("\r\n", "\n"):gsub("\r", "\n"):gsub("[ \t]*\n[ \t]*", "\n"):gsub("\n+", "\n") + return value:gsub("\n", "\\n") +end + -- [[ Hysteria2 TLS pinSHA256 ]] -- o = s:option(Value, "pinsha256", translate("Certificate fingerprint")) o:depends("type", "hysteria2") @@ -1861,6 +1949,7 @@ o:depends({type = "v2ray", v2ray_protocol = "trojan"}) o:depends({type = "v2ray", v2ray_protocol = "shadowsocks"}) o:depends({type = "v2ray", v2ray_protocol = "socks"}) o:depends({type = "v2ray", v2ray_protocol = "http"}) +o:depends({type = "v2ray", v2ray_protocol = "masque"}) -- [[ TESTPRE ]]-- o = s:option(Value, "preconns", translate("Pre-connections"), translate("Number of early established connections to reduce latency.")) @@ -1956,6 +2045,7 @@ o:depends("type", "ss-rust") o:depends("type", "trojan") o:depends("type", "hysteria2") o:depends({type = "v2ray", v2ray_protocol = "vless", transport = "xhttp"}) +o:depends({type = "v2ray", v2ray_protocol = "masque"}) o:depends({type = "v2ray", v2ray_protocol = "hysteria2"}) o = s:option(Flag, "switch_enable", translate("Enable Auto Switch")) diff --git a/luci-app-ssr-plus/root/usr/share/shadowsocksr/gen_config.lua b/luci-app-ssr-plus/root/usr/share/shadowsocksr/gen_config.lua index e4d127fe..e549f947 100755 --- a/luci-app-ssr-plus/root/usr/share/shadowsocksr/gen_config.lua +++ b/luci-app-ssr-plus/root/usr/share/shadowsocksr/gen_config.lua @@ -584,10 +584,20 @@ Xray.outbounds = { return server.insecure == "1" end)(), serverName = server.tls_host, - certificates = server.certificate and { - usage = "verify", - certificateFile = server.certpath - } or nil, + certificates = (function() + if server.masque_certificate == "1" and server.masque_certificate_pem and server.masque_certificate_pem ~= "" then + return { + certificate = split(server.masque_certificate_pem:gsub("\\n", "\n"), "\n"), + usage = "verify" + } + elseif server.certificate == "1" and server.certpath and server.certpath ~= "" then + return { + usage = "verify", + certificateFile = server.certpath + } + end + return nil + end)(), pinnedPeerCertSha256 = (function() if xray_version_val < 260131 then return nil end if not server.tls_CertSha then return "" end @@ -712,6 +722,28 @@ Xray.outbounds = { initial_windows_size = server.initial_windows_size and tonumber(server.initial_windows_size) or nil, user_agent = server.user_agent } or nil, + masqueSettings = (server.v2ray_protocol == "masque") and { + path = (server.masque_path and server.masque_path ~= "") and server.masque_path or nil, + warp = (server.masque_warp == "1") and { + privateKey = (server.masque_warp_private_key or ""):gsub("\\n", "\n"), + publicKey = (server.masque_warp_public_key or ""):gsub("\\n", "\n"), + address = server.masque_warp_address + } or nil, + headers = (function() + local headers = {} + if server.auth_enable == "1" and server.masque_warp ~= "1" and ((server.username and server.username ~= "") or (server.password and server.password ~= "")) then + headers["authorization"] = "Basic " .. base64Encode((server.username or "") .. ":" .. (server.password or "")) + end + if server.user_agent and server.user_agent ~= "" then + headers["user-agent"] = server.user_agent + end + for line in (server.masque_headers or ""):gsub("\\n", "\n"):gmatch("[^\r\n]+") do + local key, value = line:match("^%s*([^:]+):%s*(.-)%s*$") + if key then headers[trim(key):lower()] = value end + end + return next(headers) and headers or nil + end)() + } or nil, hysteriaSettings = (server.v2ray_protocol == "hysteria2") and { -- hysteria2 version = 2, @@ -922,7 +954,7 @@ Xray.outbounds = { tcpFastOpen = (function() if server.transport == "xhttp" then return (server.fast_open == "1") and true or false - elseif server.v2ray_protocol == "hysteria2" then + elseif server.v2ray_protocol == "hysteria2" or server.v2ray_protocol == "masque" then return (server.fast_open == "1") and true or nil else return nil @@ -936,7 +968,7 @@ Xray.outbounds = { ((remarks and remarks ~= "") and (node_id .. "." .. remarks) or ("direct" .. "." .. node_id)) or nil } } or nil, - mux = (server.v2ray_protocol ~= "hysteria2" and server.v2ray_protocol ~= "wireguard" and server.v2ray_protocol ~= "anytls") and { + mux = (server.v2ray_protocol ~= "hysteria2" and server.v2ray_protocol ~= "wireguard" and server.v2ray_protocol ~= "anytls" and server.v2ray_protocol ~= "masque") and { -- mux enabled = (server.mux == "1"), -- Mux concurrency = (server.mux == "1" and (tonumber(server.concurrency) or -1)) or nil, -- TCP 最大并发连接数 @@ -1027,7 +1059,7 @@ if xray_fragment.fragment ~= "0" or (xray_fragment.noise ~= "0" and xray_noise.e tcpFastOpen = (function() if server.transport == "xhttp" then return (server.fast_open == "1") and true or false - elseif server.v2ray_protocol == "hysteria2" then + elseif server.v2ray_protocol == "hysteria2" or server.v2ray_protocol == "masque" then return (server.fast_open == "1") and true or nil else return nil diff --git a/lucky/Makefile b/lucky/Makefile index 26dcb1c6..ce257bb6 100644 --- a/lucky/Makefile +++ b/lucky/Makefile @@ -61,6 +61,10 @@ define Package/$(PKG_NAME)/description Main functions of Lucky: dynamic domain name ddns-go service, socat,reverse proxy ,wake on lan endef +define Package/$(PKG_NAME)/conffiles +/etc/config/lucky +endef + define Build/Prepare [ ! -f $(PKG_BUILD_DIR)/$(PKG_NAME)_$(PKG_VERSION)_Linux_$(LUCKY_ARCH).tar.gz ] && wget https://github.com/gdy666/lucky/releases/download/v$(PKG_VERSION)/$(PKG_NAME)_$(PKG_VERSION)_Linux_$(LUCKY_ARCH).tar.gz -O $(PKG_BUILD_DIR)/$(PKG_NAME)_$(PKG_VERSION)_Linux_$(LUCKY_ARCH).tar.gz tar -xzvf $(PKG_BUILD_DIR)/$(PKG_NAME)_$(PKG_VERSION)_Linux_$(LUCKY_ARCH).tar.gz -C $(PKG_BUILD_DIR) @@ -72,6 +76,20 @@ endef define Package/$(PKG_NAME)/install $(INSTALL_DIR) $(1)/usr/bin $(INSTALL_BIN) $(PKG_BUILD_DIR)/lucky $(1)/usr/bin/lucky + $(INSTALL_DIR) $(1)/usr/libexec + $(INSTALL_BIN) ./files/lucky-call $(1)/usr/libexec/lucky-call + $(INSTALL_BIN) ./files/lucky-watchdog $(1)/usr/libexec/lucky-watchdog + $(INSTALL_DIR) $(1)/usr/share/lucky + echo '$(LUCKY_ARCH)' > $(1)/usr/share/lucky/arch + $(INSTALL_DIR) $(1)/etc/init.d + $(INSTALL_BIN) ./files/lucky.init $(1)/etc/init.d/lucky + $(INSTALL_DIR) $(1)/etc/config + $(INSTALL_CONF) ./files/luckyuci $(1)/etc/config/lucky +endef + +define Package/$(PKG_NAME)/postinst +#!/bin/sh +[ -n "$${IPKG_INSTROOT}" ] || /usr/libexec/lucky-watchdog sync endef $(eval $(call BuildPackage,$(PKG_NAME))) diff --git a/lucky/files/lucky-call b/lucky/files/lucky-call new file mode 100644 index 00000000..15f286c0 --- /dev/null +++ b/lucky/files/lucky-call @@ -0,0 +1,129 @@ +#!/bin/sh +# SPDX-License-Identifier: MIT + +PROG=/usr/bin/lucky +INIT=/etc/init.d/lucky +DEFAULT_CONFIG_DIR=/etc/config/lucky.daji +RESET_LOCK_DIR=/var/lock/lucky-reset-auth.lock + +fail() { + echo "$1" >&2 + exit "${2:-1}" +} + +config_dir() { + local value newline + value="$(uci -q get lucky.@lucky[0].configdir)" + [ -n "$value" ] || value="$DEFAULT_CONFIG_DIR" + newline=' +' + case "$value" in + *"$newline"* | //* | / | /proc | /proc/* | /sys | /sys/* | /dev | /dev/* | /run | /run/* | */../* | */.. | */./* | */.) ;; + /*) + printf '%s\n' "$value" + return 0 + ;; + esac + fail "Lucky config directory is unsafe" 2 +} + +require_program() { + [ -x "$PROG" ] || fail "Lucky is not installed" 127 +} + +set_conf() { + local key="$1" + local value="$2" + local dir + dir="$(config_dir)" || exit $? + require_program + if [ -n "$value" ]; then + "$PROG" -setconf -key "$key" -value "$value" -cd "$dir" + else + "$PROG" -setconf -key "$key" -cd "$dir" + fi +} + +service_action() { + local action="$1" + local enabled + case "$action" in + start | restart) enabled=1 ;; + stop) enabled=0 ;; + *) fail "Unsupported service action" 2 ;; + esac + uci -q set "lucky.@lucky[0].enabled=$enabled" || fail "Unable to update Lucky service state" + uci commit lucky || fail "Unable to save Lucky service state" + "$INIT" "$action" +} + +case "$1" in +info) + [ "$#" -eq 1 ] || fail "Usage: lucky-call info" 2 + require_program + exec "$PROG" -info + ;; +base) + [ "$#" -eq 1 ] || fail "Usage: lucky-call base" 2 + dir="$(config_dir)" || exit $? + require_program + exec "$PROG" -baseConfInfo -cd "$dir" + ;; +status) + [ "$#" -eq 1 ] || fail "Usage: lucky-call status" 2 + if ubus call service list '{"name":"lucky"}' 2> /dev/null | + jsonfilter -e '@.lucky.instances.*.running' 2> /dev/null | grep -qx true; then + echo true + else + echo false + fi + ;; +arch) + [ "$#" -eq 1 ] || fail "Usage: lucky-call arch" 2 + if [ -r /usr/share/lucky/arch ]; then + exec sed -n '1p' /usr/share/lucky/arch + fi + exec uname -m + ;; +service) + [ "$#" -eq 2 ] || fail "Usage: lucky-call service start|stop|restart" 2 + service_action "$2" + ;; +set-port) + [ "$#" -eq 2 ] || fail "Usage: lucky-call set-port PORT" 2 + case "$2" in *[!0-9]* | '') fail "Port must be an integer from 1 to 65535" 2 ;; esac + [ "$2" -ge 1 ] 2> /dev/null && [ "$2" -le 65535 ] 2> /dev/null || fail "Port must be an integer from 1 to 65535" 2 + set_conf AdminWebListenPort "$2" + ;; +set-safe-url) + [ "$#" -eq 2 ] || fail "Usage: lucky-call set-safe-url /path" 2 + [ "${#2}" -le 256 ] || fail "Safe URL is too long" 2 + case "$2" in *[[:space:]]*) fail "Safe URL must not contain whitespace" 2 ;; '' | /*) ;; *) fail "Safe URL must be empty or begin with /" 2 ;; esac + set_conf SetSafeURL "$2" + ;; +set-internet) + [ "$#" -eq 2 ] || fail "Usage: lucky-call set-internet true|false" 2 + case "$2" in true | false) ;; *) fail "Internet access must be true or false" 2 ;; esac + set_conf AllowInternetaccess "$2" + ;; +reset-auth) + [ "$#" -eq 1 ] || fail "Usage: lucky-call reset-auth" 2 + mkdir "$RESET_LOCK_DIR" 2> /dev/null || fail "Another credential reset is already running" + trap 'rmdir "$RESET_LOCK_DIR" 2>/dev/null' EXIT HUP INT TERM + password="$(dd if=/dev/urandom bs=12 count=1 2> /dev/null | hexdump -v -e '1/1 "%02x"')" + [ "${#password}" -eq 24 ] || fail "Unable to generate a secure password" + set_conf AllowInternetaccess false > /dev/null || fail "Unable to disable Internet access before resetting credentials" + "$INIT" stop || fail "Unable to stop Lucky before resetting credentials" + set_conf AdminAccount admin > /dev/null || fail "Unable to reset the admin account" + set_conf AdminPassword "$password" > /dev/null || fail "The account changed, but the password update failed" + if "$INIT" restart; then + restarted=true + else + restarted=false + fi + printf '{"account":"admin","password":"%s","restarted":%s}\n' "$password" "$restarted" + ;; +*) + fail "Unsupported Lucky operation" 2 + ;; +esac diff --git a/lucky/files/lucky-watchdog b/lucky/files/lucky-watchdog new file mode 100644 index 00000000..47aee641 --- /dev/null +++ b/lucky/files/lucky-watchdog @@ -0,0 +1,100 @@ +#!/bin/sh +# SPDX-License-Identifier: MIT + +# Only this exact entry belongs to us. Never remove user-created Lucky jobs. +ENTRY='* * * * * [ -x /usr/libexec/lucky-watchdog ] && /usr/libexec/lucky-watchdog check # lucky-watchdog' +ROOT_CRONTAB=/etc/crontabs/root +temporary= + +fail() { + echo "$1" >&2 + exit 1 +} + +configured() { + case "$(uci -q get lucky.@lucky[0].watchdog)" in 1 | on | true | yes) return 0 ;; *) return 1 ;; esac +} + +scheduled() { + grep -qxF "$ENTRY" "$ROOT_CRONTAB" 2> /dev/null +} + +status() { + local enabled=false installed=false paused=false cron_running=false + configured && enabled=true + scheduled && installed=true + [ -e /var/run/lucky.stopped ] && paused=true + case "$(uci -q get lucky.@lucky[0].enabled)" in 1 | on | true | yes) ;; *) paused=true ;; esac + pidof crond > /dev/null && cron_running=true + printf '{"enabled":%s,"scheduled":%s,"paused":%s,"cron_running":%s}\n' "$enabled" "$installed" "$paused" "$cron_running" +} + +sync_cron() { + local enabled="$1" + # An unconfigured installation does not require cron or touch its files. + [ "$enabled" = 1 ] || scheduled || return 0 + [ ! -L "$ROOT_CRONTAB" ] || fail "Refusing a symlinked root crontab" + [ ! -e "$ROOT_CRONTAB" ] || [ -f "$ROOT_CRONTAB" ] || fail "Invalid root crontab" + command -v crontab > /dev/null || fail "Cron is not installed" + temporary="$(mktemp -d /tmp/lucky-watchdog.XXXXXX)" || fail "Cannot prepare crontab" + if [ -e "$ROOT_CRONTAB" ]; then + cat "$ROOT_CRONTAB" > "$temporary/before" || fail "Cannot read crontab" + else + : > "$temporary/before" + fi + # awk also handles a final line without a newline before appending our job. + awk -v entry="$ENTRY" '$0 != entry { print }' "$temporary/before" > "$temporary/after" || fail "Cannot prepare crontab" + [ "$enabled" = 1 ] && printf '%s\n' "$ENTRY" >> "$temporary/after" + if ! cmp -s "$temporary/before" "$temporary/after"; then + if [ -e "$ROOT_CRONTAB" ]; then + cmp -s "$temporary/before" "$ROOT_CRONTAB" || fail "Crontab changed; please retry" + else + [ ! -s "$temporary/before" ] || fail "Crontab changed; please retry" + fi + crontab -u root "$temporary/after" || fail "Cannot install crontab" + fi + if [ "$enabled" = 1 ]; then + /etc/init.d/cron enable || fail "Cannot enable cron" + pidof crond > /dev/null || /etc/init.d/cron start || fail "Cannot start cron" + fi +} + +[ "$#" -eq 1 ] || fail "Usage: lucky-watchdog status|enable|disable|sync|remove|check" +case "$1" in +check) + # Avoid a transient process named "lucky" being mistaken for the core by + # other maintenance helpers using pidof. rc.common still takes procd's lock. + exec /bin/sh /etc/rc.common /etc/init.d/lucky watchdog + ;; +status) + status + exit 0 + ;; +enable | disable | sync | remove) ;; +*) fail "Unsupported watchdog operation" ;; +esac + +umask 077 +exec 9> /var/lock/lucky-watchdog.lock +flock -x 9 || fail "Cannot lock watchdog settings" +trap '[ -z "$temporary" ] || { rm -f "$temporary/before" "$temporary/after"; rmdir "$temporary"; }' EXIT + +case "$1" in +enable | disable) + enabled=0 + [ "$1" = enable ] && enabled=1 + # Set the option only after the cron update succeeds. A failed enable never + # starts recovery; a failed disable still leaves the old setting visible. + sync_cron "$enabled" + uci -q set "lucky.@lucky[0].watchdog=$enabled" && uci commit lucky || fail "Cannot save watchdog settings" + status + ;; +sync) + enabled=0 + configured && enabled=1 + sync_cron "$enabled" + ;; +remove) + sync_cron 0 + ;; +esac diff --git a/lucky/files/lucky.init b/lucky/files/lucky.init new file mode 100644 index 00000000..94b7e9a3 --- /dev/null +++ b/lucky/files/lucky.init @@ -0,0 +1,96 @@ +#!/bin/sh /etc/rc.common +# SPDX-License-Identifier: MIT + +START=99 +STOP=15 +USE_PROCD=1 +EXTRA_COMMANDS="watchdog" +EXTRA_HELP=" watchdog Recover an unexpectedly stopped service" + +PROG=/usr/bin/lucky +DEFAULT_CONFIG_DIR=/etc/config/lucky.daji +STOP_MARKER=/var/run/lucky.stopped +WATCHDOG_LAST=/var/run/lucky-watchdog.last + +validate_config_dir() { + local newline + newline=' +' + case "$1" in + *"$newline"* | //* | / | /proc | /proc/* | /sys | /sys/* | /dev | /dev/* | /run | /run/* | */../* | */.. | */./* | */.) ;; + /*) return 0 ;; + *) ;; + esac + logger -t lucky -p daemon.err "Rejected unsafe config directory: $1" + return 1 +} + +start_instance() { + local section="$1" + local enabled config_dir logger_enabled + + config_get_bool enabled "$section" enabled 0 + [ "$enabled" -eq 1 ] || return 0 + + config_get config_dir "$section" configdir "$DEFAULT_CONFIG_DIR" + config_get_bool logger_enabled "$section" logger 1 + validate_config_dir "$config_dir" || return 1 + umask 077 + mkdir -p "$config_dir" || return 1 + + procd_open_instance "$section" + procd_set_param command "$PROG" -cd "$config_dir" + procd_set_param respawn 3600 5 5 + procd_set_param stderr 1 + [ "$logger_enabled" -eq 1 ] && procd_set_param stdout 1 + procd_set_param file /etc/config/lucky + procd_close_instance +} + +start_service() { + rm -f "$STOP_MARKER" + [ "$WATCHDOG_RECOVERY" = 1 ] || rm -f "$WATCHDOG_LAST" + config_load lucky + config_foreach start_instance lucky +} + +stop_service() { + # rc.common serializes both stop and watchdog with procd's service lock. + # Write before stopping: maintenance must never race with a cron recovery. + umask 077 + : > "$STOP_MARKER" +} + +watchdog() { + local service now last + procd_lock + [ ! -e "$STOP_MARKER" ] || return 0 + case "$(uci -q get lucky.@lucky[0].watchdog)" in 1 | on | true | yes) ;; *) return 0 ;; esac + case "$(uci -q get lucky.@lucky[0].enabled)" in 1 | on | true | yes) ;; *) return 0 ;; esac + [ -x "$PROG" ] || return 0 + # Query the supervisor without executing the core; fail closed if ubus fails. + service="$(ubus -t 3 call service list '{"name":"lucky"}')" || return 0 + if printf '%s\n' "$service" | jsonfilter -e '@.lucky.instances.*.running' | grep -qx true; then + return 0 + fi + pidof lucky > /dev/null && return 0 + # Repeated OOMs or a broken binary must not trigger a restart every minute. + read -r now _ < /proc/uptime + now="${now%%.*}" + last="$(cat "$WATCHDOG_LAST" 2> /dev/null)" + case "$last" in '' | *[!0-9]*) last=0 ;; esac + [ "$last" -eq 0 ] || [ "$((now - last))" -ge 300 ] || return 0 + umask 077 + printf '%s\n' "$now" > "$WATCHDOG_LAST" || return 1 + logger -t lucky -p daemon.notice "Watchdog recovering unexpectedly stopped Lucky service" + WATCHDOG_RECOVERY=1 start +} + +reload_service() { + stop + start +} + +service_triggers() { + procd_add_reload_trigger lucky +} diff --git a/lucky/files/luckyuci b/lucky/files/luckyuci new file mode 100644 index 00000000..60c7f75a --- /dev/null +++ b/lucky/files/luckyuci @@ -0,0 +1,5 @@ +config lucky + option enabled '1' + option logger '1' + option watchdog '0' + option configdir '/etc/config/lucky.daji' diff --git a/v2ray-geodata/Makefile b/v2ray-geodata/Makefile index 9dd97177..cfe9609d 100644 --- a/v2ray-geodata/Makefile +++ b/v2ray-geodata/Makefile @@ -21,13 +21,13 @@ define Download/geoip HASH:=eedb24b3b9fcba27e06b92c0428dab90d9496083091ae4cf39e11387fd99d0e2 endef -GEOSITE_VER:=20261102203016 +GEOSITE_VER:=20261103081536 GEOSITE_FILE:=dlc.dat.$(GEOSITE_VER) define Download/geosite URL:=https://github.com/v2fly/domain-list-community/releases/download/$(GEOSITE_VER)/ URL_FILE:=dlc.dat FILE:=$(GEOSITE_FILE) - HASH:=78188a409b130ea5537a56941cca0d2f88d33f4a5e3a1bc0a7c2db5681ff4c0b + HASH:=4c64d3eecd7231e63c66a1be33fe0cd9d4e0e942d6284ab2553e9ee242756879 endef GEOSITE_IRAN_VER:=202610230802