diff --git a/luci-app-kaiplus/Makefile b/luci-app-kaiplus/Makefile new file mode 100644 index 00000000..96487308 --- /dev/null +++ b/luci-app-kaiplus/Makefile @@ -0,0 +1,28 @@ +# +# Copyright (C) 2026 KaiPlus Contributors +# +# This is free software, licensed under the Apache License, Version 2.0 . +# + +include $(TOPDIR)/rules.mk + +LUCI_TITLE:=KaiPlus +PKG_VERSION:=1.0.0 +PKG_RELEASE:=1 +LUCI_DEPENDS:=+kaiplus +luci-compat +LUCI_MINIFY_CSS:=0 +LUCI_MINIFY_JS:=0 + +define Package/luci-app-kaiplus/conffiles +/etc/config/kaiplus +endef + +define Package/luci-app-kaiplus/postrm +#!/bin/sh +rm -f /tmp/luci-indexcache +exit 0 +endef + +include $(TOPDIR)/feeds/luci/luci.mk + +# call BuildPackage - OpenWrt buildroot signature diff --git a/luci-app-kaiplus/luasrc/controller/kaiplus.lua b/luci-app-kaiplus/luasrc/controller/kaiplus.lua new file mode 100644 index 00000000..769bd805 --- /dev/null +++ b/luci-app-kaiplus/luasrc/controller/kaiplus.lua @@ -0,0 +1,25 @@ +local http = require "luci.http" + +module("luci.controller.kaiplus", package.seeall) + +function index() + if not nixio.fs.access("/etc/config/kaiplus") then + return + end + local page + page = entry({"admin", "services", "kaiplus"}, cbi("kaiplus"), _("KaiPlus"), 100) + page.dependent = true + entry({"admin", "services", "kaiplus_status"}, call("kaiplus_status")) +end + +function kaiplus_status() + local sys = require "luci.sys" + local uci = require "luci.model.uci".cursor() + local port = uci:get_first("kaiplus", "kaiplus", "port", "8198") + local status = { + running = (sys.call("pidof kaiplus_bin >/dev/null") == 0), + port = port + } + luci.http.prepare_content("application/json") + luci.http.write_json(status) +end diff --git a/luci-app-kaiplus/luasrc/model/cbi/kaiplus.lua b/luci-app-kaiplus/luasrc/model/cbi/kaiplus.lua new file mode 100644 index 00000000..91de5648 --- /dev/null +++ b/luci-app-kaiplus/luasrc/model/cbi/kaiplus.lua @@ -0,0 +1,37 @@ +local m, s +local sys = require "luci.sys" + +m = Map("kaiplus", translate("KaiPlus"), translate("KaiPlus is an AI workspace and session service.")) +m:section(SimpleSection).template = "kaiplus/kaiplus_status" + +m.on_after_commit = function(self) + sys.call("/etc/init.d/kaiplus restart >/dev/null 2>&1 &") +end + +s = m:section(TypedSection, "kaiplus", translate("Global settings")) +s.addremove = false +s.anonymous = true + +s:option(Flag, "enabled", translate("Enable")).rmempty = false + +local kaiplus_model = require "luci.model.kaiplus" +local blocks = kaiplus_model.blocks() +local home = kaiplus_model.home() + +local data_dir = s:option(Value, "data_dir", translate("Data directory")) +data_dir.rmempty = false +data_dir.description = translate("Required. KaiPlus stores workspace, cache, config, and state under this directory.") + +local paths, default_path = kaiplus_model.find_paths(blocks, home, "Configs") +for _, val in pairs(paths) do + data_dir:value(val, val) +end +data_dir.default = default_path + +local port = s:option(Value, "port", translate("Web port")) +port.default = "8198" +port.rmempty = false +port.datatype = "port" +port.description = translate("Port for the KaiPlus web service.") + +return m diff --git a/luci-app-kaiplus/luasrc/model/kaiplus.lua b/luci-app-kaiplus/luasrc/model/kaiplus.lua new file mode 100644 index 00000000..b592386a --- /dev/null +++ b/luci-app-kaiplus/luasrc/model/kaiplus.lua @@ -0,0 +1,52 @@ +local jsonc = require "luci.jsonc" + +local kaiplus = {} + +kaiplus.blocks = function() + local f = io.popen("lsblk -s -f -b -o NAME,FSSIZE,MOUNTPOINT --json", "r") + local vals = {} + if f then + local ret = f:read("*all") + f:close() + local obj = jsonc.parse(ret) + for _, val in pairs(obj and obj["blockdevices"] or {}) do + local fsize = val["fssize"] + if fsize ~= nil and string.len(fsize) > 10 and val["mountpoint"] then + vals[#vals + 1] = val["mountpoint"] + end + end + end + return vals +end + +kaiplus.home = function() + local uci = require "luci.model.uci".cursor() + local home_dirs = {} + home_dirs["main_dir"] = uci:get_first("quickstart", "main", "main_dir", "/root") + home_dirs["Configs"] = uci:get_first("quickstart", "main", "conf_dir", home_dirs["main_dir"] .. "/Configs") + home_dirs["Public"] = uci:get_first("quickstart", "main", "pub_dir", home_dirs["main_dir"] .. "/Public") + home_dirs["Downloads"] = uci:get_first("quickstart", "main", "dl_dir", home_dirs["Public"] .. "/Downloads") + home_dirs["Caches"] = uci:get_first("quickstart", "main", "tmp_dir", home_dirs["main_dir"] .. "/Caches") + return home_dirs +end + +kaiplus.find_paths = function(blocks, home_dirs, path_name) + local default_path = home_dirs[path_name] .. "/KAIPlus" + local paths = {} + + if #blocks == 0 then + table.insert(paths, default_path) + else + for _, val in pairs(blocks) do + table.insert(paths, val .. "/" .. path_name .. "/KAIPlus") + end + local without_conf_dir = "/root/" .. path_name .. "/KAIPlus" + if default_path == without_conf_dir then + default_path = paths[1] + end + end + + return paths, default_path +end + +return kaiplus diff --git a/luci-app-kaiplus/luasrc/view/kaiplus/kaiplus_status.htm b/luci-app-kaiplus/luasrc/view/kaiplus/kaiplus_status.htm new file mode 100644 index 00000000..147688eb --- /dev/null +++ b/luci-app-kaiplus/luasrc/view/kaiplus/kaiplus_status.htm @@ -0,0 +1,21 @@ + + +
diff --git a/luci-app-ssr-plus/luasrc/controller/shadowsocksr.lua b/luci-app-ssr-plus/luasrc/controller/shadowsocksr.lua index 626e3e19..fa2322b1 100644 --- a/luci-app-ssr-plus/luasrc/controller/shadowsocksr.lua +++ b/luci-app-ssr-plus/luasrc/controller/shadowsocksr.lua @@ -1407,8 +1407,8 @@ function act_ping() iret = luci.sys.call("ipset add ss_spec_wan_ac " .. domain .. " 2>/dev/null") == 0 end end - -- Hysteria2 节点轻量 UDP 端口检测 - if proto:find("hysteria2") or type:find("hysteria2") then + -- Hysteria2、TUIC 节点轻量 UDP 端口检测 + if proto:find("hysteria2") or type:find("hysteria2") or proto:find("tuic") or type:find("tuic") then local udp_cmd = string.format("nping --udp -c 1 -p %d %s 2>/dev/null", port, domain) local udp_raw = luci.sys.exec(udp_cmd) or "" local udp_rtt = udp_raw:match("Avg rtt:%s*([0-9.]+)ms") diff --git a/luci-app-ssr-plus/root/usr/bin/ssr-rules b/luci-app-ssr-plus/root/usr/bin/ssr-rules index 7cabb5b0..8e52399e 100755 --- a/luci-app-ssr-plus/root/usr/bin/ssr-rules +++ b/luci-app-ssr-plus/root/usr/bin/ssr-rules @@ -136,6 +136,26 @@ check_ip_list_changed() { fi } +# Configure kernel parameters for TPROXY support +set_tproxy_sysctl() { + # Disable IPv4 rp_filter for TPROXY compatibility. + # rp_filter (Reverse Path Filtering) must be disabled for TPROXY to work properly + sysctl -w net.ipv4.conf.all.rp_filter=0 >/dev/null 2>&1 + sysctl -w net.ipv4.conf.default.rp_filter=0 >/dev/null 2>&1 + + # Disable redirects to prevent routing issues + # sysctl -w net.ipv4.conf.all.accept_redirects=0 >/dev/null 2>&1 + # sysctl -w net.ipv4.conf.all.send_redirects=0 >/dev/null 2>&1 + + # Disable rp_filter for all network interfaces + local f + for f in /proc/sys/net/ipv4/conf/*/rp_filter; do + echo 0 > "$f" 2>/dev/null + done + + loger 6 "TPROXY sysctl settings applied" +} + # Cleanup persistence and runtime module files cleanup_persistence_files() { if [ "$USE_NFT" != "1" ]; then @@ -807,6 +827,10 @@ ac_rule_iptables() { tp_rule() { [ -n "$TPROXY" ] || return 0 + + # Apply sysctl settings for TPROXY + set_tproxy_sysctl + if [ "$USE_NFT" = "1" ]; then tp_rule_nft else diff --git a/openlist2/Makefile b/openlist2/Makefile index 09262217..b0d3c3e7 100644 --- a/openlist2/Makefile +++ b/openlist2/Makefile @@ -7,13 +7,13 @@ include $(TOPDIR)/rules.mk PKG_NAME:=openlist2 -PKG_VERSION:=4.2.2 -PKG_WEB_VERSION:=4.2.2 +PKG_VERSION:=4.2.3 +PKG_WEB_VERSION:=4.2.3 PKG_RELEASE:=1 PKG_SOURCE:=openlist-$(PKG_VERSION).tar.gz PKG_SOURCE_URL:=https://codeload.github.com/OpenListTeam/OpenList/tar.gz/v$(PKG_VERSION)? -PKG_HASH:=4f630caffb625bfd8a8c6bd9f798f7b36bd6147932a450c0b9f6e3ac2979fdbe +PKG_HASH:=3b41170944b5fdbd59a6b1facf438a7f73549de19580858098deb32a797946e3 PKG_BUILD_DIR:=$(BUILD_DIR)/OpenList-$(PKG_VERSION) @@ -24,7 +24,7 @@ PKG_MAINTAINER:=sbwml