mirror of
https://github.com/caiwx86/small-packages.git
synced 2026-11-05 09:54:11 +08:00
update 2026-11-03 23:44:20
This commit is contained in:
1 parent
22194cf4dd
commit
0350fcc2e5
37 files changed
+500
-1291
No files matched your search
+6
-6
@@ -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.
|
||||
|
||||
-47
@@ -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"
|
||||
@@ -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.
|
||||
@@ -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 <herboy2008@gmail.com>
|
||||
|
||||
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
|
||||
|
||||
@@ -1,91 +0,0 @@
|
||||
 [](https://t.me/joinchat/AAAAAEpRF88NfOK5vBXGBQ)
|
||||
|
||||
<h1 align="center">
|
||||
<br>luci-app-eqosplus<br>
|
||||
</h1>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://openwrt.org"><img alt="OpenWrt" src="https://img.shields.io/badge/OpenWrt-%E2%89%A519.07-ff0000?logo=openwrt&logoColor=white"></a>
|
||||
<a href="https://www.google.com/chrome/"><img alt="Chrome" src="https://img.shields.io/badge/Chrome-%E2%89%A5111-4285F3?logo=googlechrome&logoColor=white"></a>
|
||||
<a href="https://www.apple.com/safari/"><img alt="Safari" src="https://img.shields.io/badge/Safari-%E2%89%A516.4-000000?logo=safari&logoColor=white"></a>
|
||||
<a href="https://www.mozilla.org/firefox/"><img alt="Firefox" src="https://img.shields.io/badge/Firefox-%E2%89%A5128-FF7138?logo=firefoxbrowser&logoColor=white"></a>
|
||||
<a target="_blank" href="https://github.com/sirpdboy/luci-app-eqosplus/releases"> <img alt="GitHub release" src="https://img.shields.io/github/v/release/sirpdboy/luci-app-eqosplus"></a>
|
||||
<a href="https://github.com/sirpdboy/luci-app-eqosplus/releases"><img alt="Downloads" src="https://img.shields.io/github/downloads/sirpdboy/luci-app-eqosplus/total"></a>
|
||||
</p>
|
||||
|
||||
[中文] | [English](README.md)
|
||||
|
||||

|
||||
|
||||
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
|
||||
|
||||

|
||||
|
||||
|
||||
## interface
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
|
||||
# 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
|
||||
|
||||
| <img src="https://img.shields.io/badge/-Alipay-F5F5F5.svg" href="#赞助支持本项目-" height="25" alt="图飞了"/> | <img src="https://img.shields.io/badge/-WeChat-F5F5F5.svg" height="25" alt="图飞了" href="#赞助支持本项目-"/> |
|
||||
| :-----------------: | :-------------: |
|
||||
| |  |
|
||||
|
||||
<a href="#readme">
|
||||
<img src="https://img.shields.io/badge/-TOP-orange.svg" alt="no" title="Return TOP" align="right"/>
|
||||
</a>
|
||||
|
||||
 [](https://t.me/joinchat/AAAAAEpRF88NfOK5vBXGBQ)
|
||||
@@ -1,109 +0,0 @@
|
||||
 [](https://t.me/joinchat/AAAAAEpRF88NfOK5vBXGBQ)
|
||||
|
||||
<h1 align="center">
|
||||
<br>luci-app-eqosplus<br>
|
||||
</h1>
|
||||
|
||||
<p align="center">
|
||||
|
||||
<a target="_blank" href="https://github.com/sirpdboy/luci-app-eqosplus/releases">
|
||||
<img src="https://img.shields.io/github/release/sirpdboy/luci-app-eqosplus.svg?style=flat-square&label=luci-app-eqosplus&colorB=green">
|
||||
</a>
|
||||
</p>
|
||||
|
||||
[中文] | [English](README.md)
|
||||
|
||||

|
||||
|
||||
请 **认真阅读完毕** 本页面,本页面包含注意事项和如何使用。
|
||||
|
||||
## 功能说明:
|
||||
|
||||
### 定时限速1.2.2版
|
||||
#### 2023.7.19 定时限速1.2.2:增加更多日期:工作日和休息日,自定义日期1,2,3中间用逗号分隔;加入MAC地址限速,从此不用担心IPV6和IPV4的限速问题。
|
||||
|
||||
### 定时限速1.0版
|
||||
#### 2022.12.24 定时限速在eqos的加强版,加入定时限制等功能。
|
||||
|
||||
## 编译使用方法 [](#编译使用方法-)
|
||||
|
||||
将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://github.com/sirpdboy/luci-app-eqosplus
|
||||
|
||||
|
||||
- 你可以随意使用其中的源码,但请注明出处。
|
||||
|
||||

|
||||
|
||||
## 界面
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
# 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
|
||||
|
||||
## 捐助
|
||||
|
||||

|
||||
|
||||
| <img src="https://img.shields.io/badge/-支付宝-F5F5F5.svg" href="#赞助支持本项目-" height="25" alt="图飞了"/> | <img src="https://img.shields.io/badge/-微信-F5F5F5.svg" height="25" alt="图飞了" href="#赞助支持本项目-"/> |
|
||||
| :-----------------: | :-------------: |
|
||||
| |  |
|
||||
|
||||
<a href="#readme">
|
||||
<img src="https://img.shields.io/badge/-返回顶部-orange.svg" alt="图飞了" title="返回顶部" align="right"/>
|
||||
</a>
|
||||
|
||||
 [](https://t.me/joinchat/AAAAAEpRF88NfOK5vBXGBQ)
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 645 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 664 KiB |
@@ -1,19 +0,0 @@
|
||||
module("luci.controller.eqosplus", package.seeall)
|
||||
-- Copyright 2022-2023 sirpdboy <herboy2008@gmail.com>
|
||||
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
|
||||
@@ -1,190 +0,0 @@
|
||||
-- Copyright 2022-2023 sirpdboy <herboy2008@gmail.com>
|
||||
-- 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
|
||||
@@ -1,3 +0,0 @@
|
||||
<%+cbi/valueheader%>
|
||||
<font class="eqosplus_status"><%=pcdata(self:cfgvalue(section) or self.default or "")%></font>
|
||||
<%+cbi/valuefooter%>
|
||||
@@ -1,12 +0,0 @@
|
||||
<% include("cbi/map") %>
|
||||
<script type="text/javascript">//<![CDATA[
|
||||
XHR.poll(2, '<%=luci.dispatcher.build_url("admin", "control", "eqosplus", "status" )%>', null,
|
||||
function (x, result) {
|
||||
var status = document.getElementsByClassName('eqosplus_status')[0];
|
||||
status.setAttribute("style", "font-weight:bold;");
|
||||
status.setAttribute("color", result.status ? "green" : "red");
|
||||
status.innerHTML = result.status ? '<%=translate("RUNNING")%>' : '<%=translate("NOT RUNNING")%>';
|
||||
}
|
||||
)
|
||||
//]]>
|
||||
</script>
|
||||
@@ -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 ""
|
||||
|
||||
@@ -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限制用户上传/下载的网速。速度单位为<font color=\"red\"><b> MB/秒 </b></font>。"
|
||||
|
||||
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 "自动设置"
|
||||
|
||||
@@ -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 "自动设置"
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
#!/bin/sh
|
||||
[ "$ACTION" = "ifup" ] && [ "$INTERFACE" = "wan" ] && {
|
||||
sleep 5
|
||||
/etc/init.d/eqosplus restart
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -1,379 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Copyright (C) 2006 OpenWrt.org
|
||||
# Copyright 2022-2025 sirpdboy <herboy2008@gmail.com>
|
||||
|
||||
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
|
||||
@@ -1,63 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Copyright (C) 2006 OpenWrt.org
|
||||
# Copyright 2022-2025 sirpdboy <herboy2008@gmail.com>
|
||||
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
|
||||
@@ -1,11 +0,0 @@
|
||||
{
|
||||
"luci-app-eqosplus": {
|
||||
"description": "Grant UCI access for luci-app-eqosplus",
|
||||
"read": {
|
||||
"uci": [ "eqosplus" ]
|
||||
},
|
||||
"write": {
|
||||
"uci": [ "eqosplus" ]
|
||||
}
|
||||
}
|
||||
}
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 585 KiB |
@@ -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
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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 \
|
||||
|
||||
@@ -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("<a href='javascript:void(0)' onclick='javascript:fetchCertByName(this)'>%s</a>", "→ " .. 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"))
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)))
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
config lucky
|
||||
option enabled '1'
|
||||
option logger '1'
|
||||
option watchdog '0'
|
||||
option configdir '/etc/config/lucky.daji'
|
||||
@@ -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
|
||||
|
||||
Reference in new issue
Block a user