update 2025-03-24 00:24:10

This commit is contained in:
kenzok8 2025-03-24 00:24:10 +08:00
parent 7dd00fbc87
commit 617908f5b8
24 changed files with 430 additions and 147 deletions

View File

@ -15,22 +15,22 @@ Internet-detector is an application for checking the availability of the Interne
## Installation notes (OpenWrt >= 21.02)
opkg update
wget --no-check-certificate -O /tmp/internet-detector_1.4.3-r1_all.ipk https://github.com/gSpotx2f/packages-openwrt/raw/master/current/internet-detector_1.4.3-r1_all.ipk
opkg install /tmp/internet-detector_1.4.3-r1_all.ipk
rm /tmp/internet-detector_1.4.3-r1_all.ipk
wget --no-check-certificate -O /tmp/internet-detector_1.4.4-r1_all.ipk https://github.com/gSpotx2f/packages-openwrt/raw/master/current/internet-detector_1.4.4-r1_all.ipk
opkg install /tmp/internet-detector_1.4.4-r1_all.ipk
rm /tmp/internet-detector_1.4.4-r1_all.ipk
service internet-detector start
service internet-detector enable
wget --no-check-certificate -O /tmp/luci-app-internet-detector_1.4.3-r1_all.ipk https://github.com/gSpotx2f/packages-openwrt/raw/master/current/luci-app-internet-detector_1.4.3-r1_all.ipk
opkg install /tmp/luci-app-internet-detector_1.4.3-r1_all.ipk
rm /tmp/luci-app-internet-detector_1.4.3-r1_all.ipk
wget --no-check-certificate -O /tmp/luci-app-internet-detector_1.4.4-r1_all.ipk https://github.com/gSpotx2f/packages-openwrt/raw/master/current/luci-app-internet-detector_1.4.4-r1_all.ipk
opkg install /tmp/luci-app-internet-detector_1.4.4-r1_all.ipk
rm /tmp/luci-app-internet-detector_1.4.4-r1_all.ipk
service rpcd restart
i18n-ru:
wget --no-check-certificate -O /tmp/luci-i18n-internet-detector-ru_1.4.3-r1_all.ipk https://github.com/gSpotx2f/packages-openwrt/raw/master/current/luci-i18n-internet-detector-ru_1.4.3-r1_all.ipk
opkg install /tmp/luci-i18n-internet-detector-ru_1.4.3-r1_all.ipk
rm /tmp/luci-i18n-internet-detector-ru_1.4.3-r1_all.ipk
wget --no-check-certificate -O /tmp/luci-i18n-internet-detector-ru_1.4.4-r1_all.ipk https://github.com/gSpotx2f/packages-openwrt/raw/master/current/luci-i18n-internet-detector-ru_1.4.4-r1_all.ipk
opkg install /tmp/luci-i18n-internet-detector-ru_1.4.4-r1_all.ipk
rm /tmp/luci-i18n-internet-detector-ru_1.4.4-r1_all.ipk
## Screenshots:
@ -42,9 +42,9 @@ i18n-ru:
**Dependences:** modemmanager.
wget --no-check-certificate -O /tmp/internet-detector-mod-modem-restart_1.4.3-r1_all.ipk https://github.com/gSpotx2f/packages-openwrt/raw/master/current/internet-detector-mod-modem-restart_1.4.3-r1_all.ipk
opkg install /tmp/internet-detector-mod-modem-restart_1.4.3-r1_all.ipk
rm /tmp/internet-detector-mod-modem-restart_1.4.3-r1_all.ipk
wget --no-check-certificate -O /tmp/internet-detector-mod-modem-restart_1.4.4-r1_all.ipk https://github.com/gSpotx2f/packages-openwrt/raw/master/current/internet-detector-mod-modem-restart_1.4.4-r1_all.ipk
opkg install /tmp/internet-detector-mod-modem-restart_1.4.4-r1_all.ipk
rm /tmp/internet-detector-mod-modem-restart_1.4.4-r1_all.ipk
service internet-detector restart
![](https://github.com/gSpotx2f/luci-app-internet-detector/blob/master/screenshots/04.jpg)
@ -53,9 +53,9 @@ i18n-ru:
**Dependences:** mailsend.
wget --no-check-certificate -O /tmp/internet-detector-mod-email_1.4.3-r1_all.ipk https://github.com/gSpotx2f/packages-openwrt/raw/master/current/internet-detector-mod-email_1.4.3-r1_all.ipk
opkg install /tmp/internet-detector-mod-email_1.4.3-r1_all.ipk
rm /tmp/internet-detector-mod-email_1.4.3-r1_all.ipk
wget --no-check-certificate -O /tmp/internet-detector-mod-email_1.4.4-r1_all.ipk https://github.com/gSpotx2f/packages-openwrt/raw/master/current/internet-detector-mod-email_1.4.4-r1_all.ipk
opkg install /tmp/internet-detector-mod-email_1.4.4-r1_all.ipk
rm /tmp/internet-detector-mod-email_1.4.4-r1_all.ipk
service internet-detector restart
![](https://github.com/gSpotx2f/luci-app-internet-detector/blob/master/screenshots/05.jpg)

View File

@ -5,7 +5,7 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=internet-detector-mod-email
PKG_VERSION:=1.4.3
PKG_VERSION:=1.4.4
PKG_RELEASE:=1
PKG_MAINTAINER:=gSpot <https://github.com/gSpotx2f/luci-app-internet-detector>

View File

@ -5,7 +5,7 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=internet-detector-mod-modem-restart
PKG_VERSION:=1.4.3
PKG_VERSION:=1.4.4
PKG_RELEASE:=1
PKG_MAINTAINER:=gSpot <https://github.com/gSpotx2f/luci-app-internet-detector>

View File

@ -5,7 +5,7 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=internet-detector
PKG_VERSION:=1.4.3
PKG_VERSION:=1.4.4
PKG_RELEASE:=1
PKG_MAINTAINER:=gSpot <https://github.com/gSpotx2f/luci-app-internet-detector>

View File

@ -28,7 +28,9 @@ config instance 'internet'
option mod_public_ip_provider 'opendns1'
option mod_public_ip_qtype '0'
option mod_public_ip_interval '600'
option mod_public_ip_timeout '3'
option mod_public_ip_interval_failed '60'
option mod_public_ip_request_attempts '2'
option mod_public_ip_timeout '2'
option mod_public_ip_enable_ip_script '0'
option mod_email_enabled '0'
option mod_email_mode '0'

View File

@ -76,11 +76,11 @@ function Module:init(t)
end
end
function Module:SetTriggerTimer(t)
function Module:setTriggerTimer(t)
self.writeValue(t.ledTriggerFile, "timer")
end
function Module:SetTriggerNone(t)
function Module:setTriggerNone(t)
self.writeValue(t.ledTriggerFile, "none")
end
@ -92,12 +92,12 @@ function Module:getCurrentTrigger(t)
end
function Module:on(t)
self:SetTriggerNone(t)
self:setTriggerNone(t)
self.writeValue(t.ledBrightnessFile, t.ledMaxBrightness)
end
function Module:off(t)
self:SetTriggerNone(t)
self:setTriggerNone(t)
self.writeValue(t.ledBrightnessFile, 0)
end
@ -120,7 +120,7 @@ function Module:ledRunFunc(t, currentStatus)
end
elseif t.ledAction1 == 3 then
if not self:getCurrentTrigger(t) then
self:SetTriggerTimer(t)
self:setTriggerTimer(t)
end
end
else
@ -134,7 +134,7 @@ function Module:ledRunFunc(t, currentStatus)
end
elseif t.ledAction2 == 3 then
if not self:getCurrentTrigger(t) then
self:SetTriggerTimer(t)
self:setTriggerTimer(t)
end
end
end

View File

@ -4,23 +4,25 @@ local stdlib = require("posix.stdlib")
local unistd = require("posix.unistd")
local Module = {
name = "mod_public_ip",
runPrio = 50,
config = {
noModules = false,
debug = false,
name = "mod_public_ip",
runPrio = 50,
config = {
noModules = false,
debug = false,
serviceConfig = {
iface = nil,
},
},
syslog = function(level, msg) return true end,
writeValue = function(filePath, str) return false end,
readValue = function(filePath) return nil end,
port = 53,
runInterval = 600,
runIntervalFailed = 60,
timeout = 3,
providers = {
syslog = function(level, msg) return true end,
writeValue = function(filePath, str) return false end,
readValue = function(filePath) return nil end,
port = 53,
runInterval = 600,
runIntervalFailed = 60,
runIntervalDNSFailed = 1,
requestAttempts = 2,
timeout = 3,
providers = {
opendns1 = {
name = "opendns1", host = "myip.opendns.com",
server = "208.67.222.222", server6 = "2620:119:35::35",
@ -52,16 +54,18 @@ local Module = {
port = 53, queryType = "TXT", queryType6 = "TXT",
},
},
ipScript = "",
enableIpScript = false,
status = nil,
_provider = nil,
_qtype = false,
_currentIp = nil,
_enabled = false,
_counter = 0,
_interval = 600,
_DNSPacket = nil,
ipScript = "",
enableIpScript = false,
status = nil,
_provider = nil,
_qtype = false,
_currentIp = nil,
_lastResolvedIp = nil,
_enabled = false,
_counter = 0,
_DNSFalseCounter = 0,
_interval = 600,
_DNSPacket = nil,
}
function Module:runIpScript()
@ -306,7 +310,7 @@ function Module:decodeMessage(message)
return retTable
end
function Module:resolveIP()
function Module:requestIP()
local res
local qtype = self._qtype and self._provider.queryType6 or self._provider.queryType
local server = self._qtype and self._provider.server6 or self._provider.server
@ -324,7 +328,7 @@ function Module:resolveIP()
end
else
self.syslog("warning", string.format(
"%s: DNS error when requesting an IP address", self.name))
"%s: UDP error when requesting an IP address", self.name))
end
return res
@ -334,6 +338,12 @@ function Module:init(t)
if t.interval ~= nil then
self.runInterval = tonumber(t.interval)
end
if t.interval_failed ~= nil then
self.runIntervalFailed = tonumber(t.interval_failed)
end
if t.request_attempts ~= nil then
self.requestAttempts = tonumber(t.request_attempts)
end
if t.timeout ~= nil then
self.timeout = tonumber(t.timeout)
end
@ -352,10 +362,12 @@ function Module:init(t)
if t.qtype ~= nil then
self._qtype = (tonumber(t.qtype) ~= 0)
end
self._currentIp = nil
self._DNSPacket = nil
self._interval = self.runInterval
self._enabled = true
self._currentIp = nil
self._lastResolvedIp = nil
self._DNSPacket = nil
self._interval = self.runInterval
self._DNSFalseCounter = 0
self._enabled = true
end
function Module:run(currentStatus, lastStatus, timeDiff, timeNow, inetChecked)
@ -365,33 +377,44 @@ function Module:run(currentStatus, lastStatus, timeDiff, timeNow, inetChecked)
if currentStatus == 0 then
if self._counter == 0 or self._counter >= self._interval or currentStatus ~= lastStatus then
local ip = self:resolveIP()
local ip = self:requestIP()
if not ip then
ip = ""
self._interval = self.runIntervalFailed
ip = ""
self._DNSFalseCounter = self._DNSFalseCounter + 1
if self._DNSFalseCounter >= self.requestAttempts then
self._interval = self.runIntervalFailed
self._DNSFalseCounter = 0
else
self._interval = self.runIntervalDNSFailed
end
else
self._interval = self.runInterval
self._interval = self.runInterval
self._DNSFalseCounter = 0
end
if ip ~= self._currentIp then
self.status = ip
self.syslog(
"notice",
string.format("%s: public IP address %s", self.name, (ip == "") and "Undefined" or ip)
)
if self._counter > 0 then
self:runIpScript()
if ip ~= "" then
if self._counter > 0 and ip ~= self._lastResolvedIp then
self.syslog(
"notice",
string.format("%s: public IP address changed to %s", self.name, ip)
)
self:runIpScript()
end
self._lastResolvedIp = ip
end
end
self._currentIp = ip
self._counter = 0
end
else
self._currentIp = nil
self.status = self._currentIp
self._counter = 0
self._interval = self.runInterval
self._currentIp = nil
self.status = self._currentIp
self._DNSFalseCounter = 0
self._counter = 0
self._interval = self.runInterval
end
self._counter = self._counter + timeDiff
end

View File

@ -5,7 +5,7 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=luci-app-internet-detector
PKG_VERSION:=1.4.3
PKG_VERSION:=1.4.4
PKG_RELEASE:=1
LUCI_TITLE:=LuCI support for internet-detector
LUCI_DEPENDS:=+internet-detector

View File

@ -1038,6 +1038,30 @@ return view.extend({
o.value(3600, '1' + ' ' + _('hour'));
o.value(10800, '3' + ' ' + _('hour'));
// interval_failed
o = s.taboption('public_ip', form.ListValue,
'mod_public_ip_interval_failed', _('Failed interval'),
_('Interval between IP address requests if the IP address is not defined.')
);
o.default = '60';
o.modalonly = true;
o.value(30, '30' + ' ' + _('sec'));
o.value(60, '1' + ' ' + _('min'));
o.value(180, '3' + ' ' + _('min'));
o.value(300, '5' + ' ' + _('min'));
o.value(600, '10' + ' ' + _('min'));
// request_attempts
o = s.taboption('public_ip', form.ListValue,
'mod_public_ip_request_attempts', _('Attempts'),
_('Number of attempts to request an IP address.')
);
o.default = '2'
o.modalonly = true;
for(let i = 1; i <= 3; i++) {
o.value(i);
};
// timeout
o = s.taboption('public_ip', form.ListValue,
'mod_public_ip_timeout', _('Server response timeout')

View File

@ -44,6 +44,9 @@ msgstr "Сообщение будет отправлено при подключ
msgid "An error has occurred"
msgstr "Произошла ошибка"
msgid "Attempts"
msgstr "Попытки"
msgid "Big: 248 bytes"
msgstr "Большой: 248 байт"
@ -149,11 +152,8 @@ msgstr "Включен"
msgid "Expecting:"
msgstr "Ожидается:"
msgid "Public IP"
msgstr "Публичный IP"
msgid "Public IP address"
msgstr "Публичный IP адрес"
msgid "Failed interval"
msgstr "Интервал при неудаче"
msgid "Failed to get %s init status: %s"
msgstr "Не удалось получить статус инициализации %s: %s"
@ -216,6 +216,9 @@ msgstr "Статус Интернет"
msgid "Interval between IP address requests."
msgstr "Интервал между запросами IP адреса."
msgid "Interval between IP address requests if the IP address is not defined."
msgstr "Интервал между запросами IP адреса, если IP адрес не определён."
msgid "Jumbo: 9000 bytes"
msgstr "Гигантский: 9000 байт"
@ -282,6 +285,9 @@ msgstr "Нет доступных <abbr title=\"Светодиод\">LED</abbr>.
msgid "Not scheduled"
msgstr "Не запланирован"
msgid "Number of attempts to request an IP address."
msgstr "Количество попыток запроса IP адреса"
msgid "Off"
msgstr "Выключить"
@ -332,6 +338,12 @@ msgstr "Регулярный скрипт"
msgid "Polling interval"
msgstr "Интервал опроса"
msgid "Public IP"
msgstr "Публичный IP"
msgid "Public IP address"
msgstr "Публичный IP адрес"
msgid "Reboot device"
msgstr "Перезагрузка устройства"

View File

@ -32,6 +32,9 @@ msgstr ""
msgid "An error has occurred"
msgstr ""
msgid "Attempts"
msgstr ""
msgid "Big: 248 bytes"
msgstr ""
@ -137,10 +140,7 @@ msgstr ""
msgid "Expecting:"
msgstr ""
msgid "Public IP"
msgstr ""
msgid "Public IP address"
msgid "Failed interval"
msgstr ""
msgid "Failed to get %s init status: %s"
@ -202,6 +202,9 @@ msgstr ""
msgid "Interval between IP address requests."
msgstr ""
msgid "Interval between IP address requests if the IP address is not defined."
msgstr ""
msgid "Jumbo: 9000 bytes"
msgstr ""
@ -260,6 +263,9 @@ msgstr ""
msgid "Not scheduled"
msgstr ""
msgid "Number of attempts to request an IP address."
msgstr ""
msgid "Off"
msgstr ""
@ -307,6 +313,12 @@ msgstr ""
msgid "Polling interval"
msgstr ""
msgid "Public IP"
msgstr ""
msgid "Public IP address"
msgstr ""
msgid "Reboot device"
msgstr ""

View File

@ -96,7 +96,7 @@ function check_port()
local retstring = "<br /><br />"
local s
local server_name = ""
local uci = luci.model.uci.cursor()
local uci = require "luci.model.uci".cursor()
local iret = 1
uci:foreach("shadowsocksr", "servers", function(s)
if s.alias then

View File

@ -1,9 +1,9 @@
local m, s, o
local uci = luci.model.uci.cursor()
local uci = require "luci.model.uci".cursor()
local server_table = {}
local type_table = {}
local function is_finded(e)
return luci.sys.exec('type -t -p "%s"' % e) ~= "" and true or false
return luci.sys.exec(string.format('type -t -p "%s" 2>/dev/null', e)) ~= ""
end
uci:foreach("shadowsocksr", "servers", function(s)
@ -203,6 +203,7 @@ for key, server_type in pairs(type_table) do
o:depends("server", key)
end
end
o:depends({server = "same", disable = true})
-- Socks User
o = s:option(Value, "socks5_user", translate("Socks5 User"), translate("Only when Socks5 Auth Mode is password valid, Mandatory."))
@ -225,6 +226,7 @@ for key, server_type in pairs(type_table) do
o:depends("server", key)
end
end
o:depends({server = "same", disable = true})
end
-- Local Port

View File

@ -6,19 +6,29 @@ require "luci.sys"
require "luci.http"
require "luci.jsonc"
require "luci.model.ipkg"
require "luci.model.uci"
local uci = require "luci.model.uci".cursor()
local m, s, o
local sid = arg[1]
local uuid = luci.sys.exec("cat /proc/sys/kernel/random/uuid")
-- 确保正确判断程序是否存在
local function is_finded(e)
return luci.sys.exec('type -t -p "%s"' % e) ~= "" and true or false
return luci.sys.exec(string.format('type -t -p "%s" 2>/dev/null', e)) ~= ""
end
local function is_installed(e)
return luci.model.ipkg.installed(e)
end
local has_ss_rust = is_finded("sslocal") or is_finded("ssserver")
local has_ss_libev = is_finded("ss-redir") or is_finded("ss-local")
-- 读取当前存储的 ss_type
local ss_type = uci:get_first("shadowsocksr", "server_subscribe", "ss_type")
local server_table = {}
local encrypt_methods = {
-- ssr
@ -79,7 +89,7 @@ local encrypt_methods_ss = {
"camellia-256-cfb",
"salsa20",
"chacha20",
"chacha20-ietf" ]]
"chacha20-ietf" ]]--
}
local protocol = {
@ -146,8 +156,8 @@ end
if is_finded("ssr-redir") then
o:value("ssr", translate("ShadowsocksR"))
end
if is_finded("ss-local") or is_finded("ss-redir") or is_finded("sslocal") or is_finded("ssmanager") then
o:value("ss", translate("Shadowsocks"))
if has_ss_rust or has_ss_libev then
o:value("ss", translate("ShadowSocks"))
end
if is_finded("trojan") then
o:value("trojan", translate("Trojan"))
@ -185,16 +195,44 @@ o:depends("type", "tun")
o.description = translate("Redirect traffic to this network interface")
-- 新增一个选择框,用于选择 Shadowsocks 版本
o = s:option(ListValue, "ss_variant", translate("Shadowsocks Variant"))
local isSSRust = is_finded("sslocal") or is_finded("ssmanager")
local isSSLibev = is_finded("ss-local") or is_finded("ss-redir")
if isSSRust then
o:value("isSSRust", translate("Shadowsocks-rust Version"))
o = s:option(ListValue, "has_ss_type", string.format("<b><span style='color:red;'>%s</span></b>", translate("ShadowSocks Node Use Version")))
o.description = translate("Selection ShadowSocks Node Use Version.")
-- 设置默认 Shadowsocks 版本
-- 动态添加选项
if has_ss_rust then
o:value("ss-rust", translate("ShadowSocks-rust Version"))
end
if isSSLibev then
o:value("isSSLibev", translate("Shadowsocks-libev Version"))
if has_ss_libev then
o:value("ss-libev", translate("ShadowSocks-libev Version"))
end
-- 设置默认值
if ss_type == "ss-rust" then
o.default = "ss-rust"
elseif ss_type == "ss-libev" then
o.default = "ss-libev"
end
o:depends("type", "ss")
o.write = function(self, section, value)
-- 更新 Shadowsocks 节点的 has_ss_type
uci:foreach("shadowsocksr", "servers", function(s)
local node_type = uci:get("shadowsocksr", s[".name"], "type") -- 获取节点类型
if node_type == "ss" then -- 仅修改 Shadowsocks 节点
local old_value = uci:get("shadowsocksr", s[".name"], "has_ss_type")
if old_value ~= value then
uci:set("shadowsocksr", s[".name"], "has_ss_type", value)
end
end
end)
-- 更新 server_subscribe 的 ss_type
local old_value = uci:get("shadowsocksr", "server_subscribe", "ss_type")
if old_value ~= value then
uci:set("shadowsocksr", "@server_subscribe[0]", "ss_type", value)
end
-- 更新当前 section 的 has_ss_type
Value.write(self, section, value)
end
o = s:option(ListValue, "v2ray_protocol", translate("V2Ray/XRay protocol"))
o:value("vless", translate("VLESS"))
@ -271,7 +309,12 @@ o:depends("type", "ssr")
o = s:option(ListValue, "encrypt_method_ss", translate("Encrypt Method"))
for _, v in ipairs(encrypt_methods_ss) do
o:value(v)
if v == "none" then
o.default = "none"
o:value("none", translate("none"))
else
o:value(v, translate(v))
end
end
o.rmempty = true
o:depends("type", "ss")

View File

@ -3,11 +3,11 @@
-- Licensed to the public under the GNU General Public License v3.
local m, s, sec, o
local uci = luci.model.uci.cursor()
local uci = require "luci.model.uci".cursor()
local validation = require "luci.cbi.datatypes"
local function is_finded(e)
return luci.sys.exec('type -t -p "%s"' % e) ~= "" and true or false
return luci.sys.exec(string.format('type -t -p "%s" 2>/dev/null', e)) ~= ""
end
m = Map("shadowsocksr", translate("ShadowSocksR Plus+ Settings"), translate("<h3>Support SS/SSR/V2RAY/XRAY/TROJAN/NAIVEPROXY/SOCKS5/TUN etc.</h3>"))

View File

@ -120,15 +120,9 @@ function o.cfgvalue(...)
end
o = sec:option(DummyValue, "encrypt_method", translate("Encrypt Method"))
function o.cfgvalue(...)
local v = Value.cfgvalue(...)
return v and v:upper() or "-"
end
o = sec:option(DummyValue, "encrypt_method_ss", translate("Encrypt Method"))
function o.cfgvalue(...)
local v = Value.cfgvalue(...)
return v and v:upper() or "-"
function o.cfgvalue(self, section)
local method = self.map:get(section, "encrypt_method") or self.map:get(section, "encrypt_method_ss")
return method and method:upper() or "-"
end
o = sec:option(DummyValue, "protocol", translate("Protocol"))

View File

@ -1,10 +1,39 @@
-- Licensed to the public under the GNU General Public License v3.
require "luci.http"
require "luci.sys"
require "luci.dispatcher"
require "luci.model.uci"
local m, s, o
local uci = luci.model.uci.cursor()
local uci = require "luci.model.uci".cursor()
local m, s, o, node
local server_count = 0
-- 确保正确判断程序是否存在
local function is_finded(e)
return luci.sys.exec(string.format('type -t -p "%s" 2>/dev/null', e)) ~= ""
end
local has_ss_rust = is_finded("sslocal") or is_finded("ssserver")
local has_ss_libev = is_finded("ss-redir") or is_finded("ss-local")
local ss_type_list = {}
if has_ss_rust then
table.insert(ss_type_list, { id = "ss-rust", name = translate("ShadowSocks-rust Version") })
end
if has_ss_libev then
table.insert(ss_type_list, { id = "ss-libev", name = translate("ShadowSocks-libev Version") })
end
-- 如果用户没有手动设置,则自动选择
if ss_type == "" then
if has_ss_rust then
ss_type = "ss-rust"
elseif has_ss_libev then
ss_type = "ss-libev"
end
end
uci:foreach("shadowsocksr", "servers", function(s)
server_count = server_count + 1
end)
@ -48,6 +77,30 @@ o.default = 30
o.rmempty = true
o:depends("auto_update", "1")
-- 确保 ss_type_list 不为空
if #ss_type_list > 0 then
o = s:option(ListValue, "ss_type", string.format("<b><span style='color:red;'>%s</span></b>", translate("ShadowSocks Node Use Version")))
o.description = translate("Selection ShadowSocks Node Use Version.")
for _, v in ipairs(ss_type_list) do
o:value(v.id, v.name) -- 存储 "ss-libev" / "ss-rust",但 UI 显示完整名称
end
o.default = ss_type -- 设置默认值
o.write = function(self, section, value)
-- 更新 Shadowsocks 节点的 has_ss_type
uci:foreach("shadowsocksr", "servers", function(s)
local node_type = uci:get("shadowsocksr", s[".name"], "type") -- 获取节点类型
if node_type == "ss" then -- 仅修改 Shadowsocks 节点
local old_value = uci:get("shadowsocksr", s[".name"], "has_ss_type")
if old_value ~= value then
uci:set("shadowsocksr", s[".name"], "has_ss_type", value)
end
end
end)
-- 更新当前 section 的 ss_type
Value.write(self, section, value)
end
end
o = s:option(DynamicList, "subscribe_url", translate("Subscribe URL"))
o.rmempty = true

View File

@ -15,7 +15,7 @@ local ad_count = 0
local ip_count = 0
local nfip_count = 0
local Process_list = luci.sys.exec("busybox ps -w")
local uci = luci.model.uci.cursor()
local uci = require "luci.model.uci".cursor()
-- html constants
font_blue = [[<b style=color:green>]]
style_blue = [[<b style=color:red>]]

View File

@ -87,8 +87,18 @@
}
// set tr draggable
function enableDragForTable(table_selecter, store) {
var trs = document.querySelectorAll(table_selecter + " tr");
function enableDragForTable(table_selector, store) {
// 添加 CSS 样式
const style = document.createElement("style");
style.textContent = `
tr[draggable="true"] {
cursor: move;
user-select: none;
}
`;
document.head.appendChild(style);
var trs = document.querySelectorAll(table_selector + " tr");
if (!trs || trs.length.length < 3) {
return;
}
@ -104,12 +114,12 @@
ev.dataTransfer.dropEffect = "move";
}
function moveToTop(id) {
var top = document.querySelectorAll(table_selecter + " tr")[2];
var top = document.querySelectorAll(table_selector + " tr")[2];
cbi_row_drop(id, top.id, store);
}
function moveToBottom(id) {
console.log('moveToBottom:', id);
var trList = document.querySelectorAll(table_selecter + " tr");
//console.log('moveToBottom:', id);
var trList = document.querySelectorAll(table_selector + " tr");
var bottom = trList[trList.length - 1];
cbi_row_drop(id, bottom.id, store, true);
}

View File

@ -1,6 +1,12 @@
<%+cbi/valueheader%>
<%
local map = self.map
local ss_type = map:get("@server_subscribe[0]", "ss_type")
-%>
<script type="text/javascript">
//<![CDATA[
let ss_type = "<%=ss_type%>"
function padright(str, cnt, pad) {
return str + Array(cnt + 1).join(pad);
}
@ -133,14 +139,17 @@ function import_ssr_url(btn, urlname, sid) {
if (sipIndex != -1) {
// SIP002
var userInfo = b64decsafe(url0.substr(0, sipIndex));
// console.log("userInfo:", userInfo); // 打印解析后的 userInfo
var temp = url0.substr(sipIndex + 1).split("/?");
var serverInfo = temp[0].split(":");
var server = serverInfo[0];
var port = serverInfo[1].replace("/","");
var method, password, enable_plugin, plugin, pluginOpts;
// 解析 plugin 参数
if (temp[1]) {
var pluginInfo = decodeURIComponent(temp[1]);
// 使用正則匹配 plugin 參數
// 使用正则匹配 plugin 参数
var pluginNameInfo = pluginInfo.match(/plugin=([^&]+)/);
if (pluginNameInfo) {
var pluginParams = pluginNameInfo[1].split(";");
@ -148,20 +157,25 @@ function import_ssr_url(btn, urlname, sid) {
pluginOpts = pluginParams.length > 0 ? pluginParams.join(";") : "";
}
}
// 解析 userInfo解析加密方法和密码
var userInfoSplitIndex = userInfo.indexOf(":");
if (userInfoSplitIndex != -1) {
method = userInfo.substr(0, userInfoSplitIndex);
password = userInfo.substr(userInfoSplitIndex + 1);
if (userInfoSplitIndex !== -1) {
method = userInfo.substr(0, userInfoSplitIndex); // 提取加密方法
password = userInfo.substr(userInfoSplitIndex + 1); // 提取密码
if (!method || method.trim() === "") {
method = "none"; // 如果加密方法为空,设置为 "none"
}
}
var has_ss_type = (ss_type === "ss-rust") ? "ss-rust" : "ss-libev";
document.getElementsByName('cbid.shadowsocksr.' + sid + '.type')[0].value = ssu[0];
document.getElementsByName('cbid.shadowsocksr.' + sid + '.type')[0].dispatchEvent(event);
document.getElementsByName('cbid.shadowsocksr.' + sid + '.ss_variant')[0].value =
(ssu[0] === "ss") ? "isSSRust" : "isSSLibev";
document.getElementsByName('cbid.shadowsocksr.' + sid + '.ss_variant')[0].dispatchEvent(event);
document.getElementsByName('cbid.shadowsocksr.' + sid + '.has_ss_type')[0].value = has_ss_type;
document.getElementsByName('cbid.shadowsocksr.' + sid + '.has_ss_type')[0].dispatchEvent(event);
document.getElementsByName('cbid.shadowsocksr.' + sid + '.server')[0].value = server;
document.getElementsByName('cbid.shadowsocksr.' + sid + '.server_port')[0].value = port;
document.getElementsByName('cbid.shadowsocksr.' + sid + '.password')[0].value = password || "";
document.getElementsByName('cbid.shadowsocksr.' + sid + '.encrypt_method_ss')[0].value = method || "";
document.getElementsByName('cbid.shadowsocksr.' + sid + '.encrypt_method_ss')[0].value = method;
document.getElementsByName('cbid.shadowsocksr.' + sid + '.encrypt_method_ss')[0].dispatchEvent(event);
if (plugin && plugin !== "none") {
document.getElementsByName('cbid.shadowsocksr.' + sid + '.enable_plugin')[0].checked = true; // 设置 enable_plugin 为 true
document.getElementsByName('cbid.shadowsocksr.' + sid + '.enable_plugin')[0].dispatchEvent(event); // 触发事件
@ -185,10 +199,14 @@ function import_ssr_url(btn, urlname, sid) {
var team = sstr.split('@');
var part1 = team[0].split(':');
var part2 = team[1].split(':');
document.getElementsByName('cbid.shadowsocksr.' + sid + '.server')[0].value = part2[0];
document.getElementsByName('cbid.shadowsocksr.' + sid + '.server_port')[0].value = part2[1];
document.getElementsByName('cbid.shadowsocksr.' + sid + '.password')[0].value = part1[1];
document.getElementsByName('cbid.shadowsocksr.' + sid + '.encrypt_method_ss')[0].value = part1[0];
var method = (part1[0] && part1[0].trim() !== "") ? part1[0].trim() : "none";
var password = part1[1] || "";
var server = part2[0];
var port = part2[1];
document.getElementsByName('cbid.shadowsocksr.' + sid + '.server')[0].value = server;
document.getElementsByName('cbid.shadowsocksr.' + sid + '.server_port')[0].value = port;
document.getElementsByName('cbid.shadowsocksr.' + sid + '.password')[0].value = password;
document.getElementsByName('cbid.shadowsocksr.' + sid + '.encrypt_method_ss')[0].value = method;
if (param != undefined) {
document.getElementsByName('cbid.shadowsocksr.' + sid + '.alias')[0].value = decodeURI(param);
}

View File

@ -222,14 +222,17 @@ msgstr "服务器名称指示"
msgid "Shadow-TLS ChainPoxy type"
msgstr "代理链类型"
msgid "Shadowsocks Variant"
msgstr "shadowsocks 变体"
msgid "ShadowSocks Node Use Version"
msgstr "ShadowSocks 节点使用版本"
msgid "Shadowsocks-rust Version"
msgstr "shadowsocks rust 版本"
msgid "Selection ShadowSocks Node Use Version."
msgstr "选择 ShadowSocks 节点使用版本。"
msgid "Shadowsocks-libev Version"
msgstr "Shadowsocks-libev 版本"
msgid "ShadowSocks-libev Version"
msgstr "ShadowSocks-libev 版本"
msgid "ShadowSocks-rust Version"
msgstr "ShadowSocks-rust 版本"
msgid "Vmess Protocol"
msgstr "VMESS 协议"

View File

@ -166,7 +166,7 @@ _exit() {
}
first_type() {
type -t -p "/bin/${1}" -p "${TMP_BIN_PATH}/${1}" -p "${1}" "$@" | head -n1
type -t -p "/bin/${1}" -p "/usr/bin/${1}" -p "${TMP_BIN_PATH}/${1}" -p "${1}" "$@" | head -n1
}
ln_start_bin() {
@ -258,7 +258,7 @@ start_dns() {
fi
fi
fi
if [ "$(uci_get_by_type global apple_optimization 1)" == "1" ]; then
local new_appledns="$(uci_get_by_type global apple_dns)"
if [ -n "$new_appledns" ]; then
@ -320,7 +320,7 @@ gen_service_file() { #1-server.type 2-cfgname 3-file_path
get_name() {
case "$1" in
ss) echo "Shadowsocks" ;;
ss) echo "ShadowSocks" ;;
ssr) echo "ShadowsocksR" ;;
esac
}
@ -432,11 +432,23 @@ gen_config_file() { #server1 type2 code3 local_port4 socks_port5 chain6 threads5
start_udp() {
local type=$(uci_get_by_name $UDP_RELAY_SERVER type)
local has_ss_type=$(uci_get_by_type server_subscribe ss_type)
redir_udp=1
case "$type" in
ss | ssr)
gen_config_file $UDP_RELAY_SERVER $type 2 $tmp_udp_port
ss_program="$(first_type ${type}local ${type}-redir)"
if [ "$has_ss_type" = "ss-libev" -o "$type" = "ssr" ]; then
ss_program="$(first_type ${type}-redir)"
elif [ "$has_ss_type" = "ss-rust" ]; then
ss_program="$(first_type ${type}local)"
fi
echolog "$(get_name $type) program is: $ss_program"
# 获取当前软链接指向的执行文件路径
old_ss_program=$(readlink -f "$TMP_PATH/bin/${type}-redir" 2>/dev/null)
# **当新旧执行文件路径不同时,删除旧链接**
if [ "$old_ss_program" != "$ss_program" ]; then
rm -rf "$TMP_PATH/bin/${type}-redir"
fi
ln_start_bin $ss_program ${type}-redir -c $udp_config_file
echolog "UDP TPROXY Relay:$(get_name $type) Started!"
;;
@ -540,7 +552,7 @@ shunt_dns_config_file_port() {
# 全局socks 有密码NetFlix 不能使用 auth 验证,需更换为新端口并使用无密码的 socks 配置用于分流
# 新增NetFlix dns 使用端口
local port=$tmp_shunt_local_port
jq --arg port "$port" '.inbounds |= .[0:1] + [{"protocol":"socks","port":($port | tonumber),"settings":{"udp":true,"auth":"noauth"}}] + .[1:]' "$shunt_config_file" > "$shunt_config_file.tmp" && mv "$shunt_config_file.tmp" $shunt_config_file
jq --arg port "$port" '.inbounds |= .[0:1] + [{"protocol":"socks","port":($port | tonumber),"settings":{"udp":true,"auth":"noauth"}}] + .[1:]' "$shunt_config_file" > "$shunt_config_file.tmp" && mv "$shunt_config_file.tmp" $shunt_config_file
echo $port # 返回端口号
return 0 # 成功返回
else
@ -566,16 +578,38 @@ shunt_dns_config_file_port() {
start_shunt() {
local type=$(uci_get_by_name $SHUNT_SERVER type)
local has_ss_type=$(uci_get_by_type server_subscribe ss_type)
case "$type" in
ss | ssr)
gen_config_file $SHUNT_SERVER $type 3 $tmp_shunt_port
ss_program="$(first_type ${type}local ${type}-redir)"
if [ "$has_ss_type" = "ss-libev" -o "$type" = "ssr" ]; then
ss_program="$(first_type ${type}-redir)"
elif [ "$has_ss_type" = "ss-rust" ]; then
ss_program="$(first_type ${type}local)"
fi
echolog "$(get_name $type) program is: $ss_program"
# 获取当前软链接指向的执行文件路径
old_ss_program=$(readlink -f "$TMP_PATH/bin/${type}-redir" 2>/dev/null)
# **当新旧执行文件路径不同时,删除旧链接**
if [ "$old_ss_program" != "$ss_program" ]; then
rm -rf "$TMP_PATH/bin/${type}-redir"
fi
ln_start_bin $ss_program ${type}-redir -c $shunt_config_file
if [ -n "$tmp_local_port" ]; then
local tmp_port=$tmp_local_port
else
local tmp_port=$tmp_shunt_local_port
ln_start_bin $(first_type ${type}local ${type}-local) ${type}-local -c $shunt_dns_config_file
if [ "$has_ss_type" = "ss-libev" -o "$type" = "ssr" ]; then
dns_ss_program="$(first_type ${type}-local)"
elif [ "$has_ss_type" = "ss-rust" ]; then
dns_ss_program="$(first_type ${type}local)"
fi
# 获取当前软链接指向的执行文件路径
old_dns_ss_program=$(readlink -f "$TMP_PATH/bin/${type}-local" 2>/dev/null)
if [ "$old_dns_ss_program" != "$dns_ss_program" ]; then
rm -rf "$TMP_PATH/bin/${type}-local"
fi
ln_start_bin $dns_ss_program ${type}-local -c $shunt_dns_config_file
fi
shunt_dns_command $tmp_port
echolog "shunt:$(get_name $type) Started!"
@ -695,10 +729,22 @@ start_local() {
local local_port=$(uci_get_by_type socks5_proxy local_port)
[ "$LOCAL_SERVER" == "$SHUNT_SERVER" ] && tmp_local_port=$local_port
local type=$(uci_get_by_name $LOCAL_SERVER type)
local has_ss_type=$(uci_get_by_type server_subscribe ss_type)
case "$type" in
ss | ssr)
gen_config_file $LOCAL_SERVER $type 4 $local_port
ss_program="$(first_type ${type}local ${type}-local)"
if [ "$has_ss_type" = "ss-libev" -o "$type" = "ssr" ]; then
ss_program="$(first_type ${type}-local)"
elif [ "$has_ss_type" = "ss-rust" ]; then
ss_program="$(first_type ${type}local)"
fi
echolog "$(get_name $type) program is: $ss_program"
# 获取当前软链接指向的执行文件路径
old_ss_program=$(readlink -f "$TMP_PATH/bin/${type}-local" 2>/dev/null)
# **当 新旧执行文件路径不同时,删除旧链接**
if [ "$old_ss_program" != "$ss_program" ]; then
rm -rf "$TMP_PATH/bin/${type}-local"
fi
ln_start_bin $ss_program ${type}-local -c $local_config_file
echolog "Global_Socks5:$(get_name $type) Started!"
;;
@ -789,12 +835,24 @@ Start_Run() {
fi
local tcp_port=$(uci_get_by_name $GLOBAL_SERVER local_port)
local type=$(uci_get_by_name $GLOBAL_SERVER type)
local has_ss_type=$(uci_get_by_type server_subscribe ss_type)
case "$type" in
ss | ssr)
gen_config_file $GLOBAL_SERVER $type 1 $tcp_port
ss_program="$(first_type ${type}local ${type}-redir)"
if [ "$has_ss_type" = "ss-libev" -o "$type" = "ssr" ]; then
ss_program="$(first_type ${type}-redir)"
elif [ "$has_ss_type" = "ss-rust" ]; then
ss_program="$(first_type ${type}local)"
fi
echolog "$(get_name $type) program is: $ss_program"
# 获取当前软链接指向的执行文件路径
old_ss_program=$(readlink -f "$TMP_PATH/bin/${type}-redir" 2>/dev/null)
# **当新旧执行文件路径不同时,删除旧链接**
if [ "$old_ss_program" != "$ss_program" ]; then
rm -rf "$TMP_PATH/bin/${type}-redir"
fi
for i in $(seq 1 $threads); do
ln_start_bin "$ss_program" ${type}-redir -c $tcp_config_file
ln_start_bin $ss_program ${type}-redir -c $tcp_config_file
done
echolog "Main node:$(get_name $type) $threads Threads Started!"
;;
@ -1000,10 +1058,22 @@ start_server() {
fi
fi
local type=$(uci_get_by_name $1 type)
local has_ss_type=$(uci_get_by_type server_subscribe ss_type)
case "$type" in
ss | ssr)
gen_service_file ${type} $1 $TMP_PATH/ssr-server$server_count.json
ln_start_bin $(first_type ${type}server ${type}-server) ${type}-server -c $TMP_PATH/ssr-server$server_count.json
if [ "$has_ss_type" = "ss-libev" -o "$type" = "ssr" ]; then
ss_program="$(first_type ${type}-server)"
elif [ "$has_ss_type" = "ss-rust" ]; then
ss_program="$(first_type ${type}server)"
fi
# 获取当前软链接指向的执行文件路径
old_ss_program=$(readlink -f "$TMP_PATH/bin/${type}-server" 2>/dev/null)
# **当新旧执行文件路径不同时,删除旧链接**
if [ "$old_ss_program" != "$ss_program" ]; then
rm -rf "$TMP_PATH/bin/${type}-server"
fi
ln_start_bin $ss_program ${type}-server -c $TMP_PATH/ssr-server$server_count.json
echolog "Server: $(get_name ${type}) Server$server_count Started!"
;;
socks5)
@ -1201,7 +1271,12 @@ stop() {
uci -q commit "dhcp"
fi
if [ -f "$DNSMASQ_CONF_DIR/dnsmasq-ssrplus.conf" ]; then
rm -rf $DNSMASQ_CONF_DIR/dnsmasq-ssrplus.conf $TMP_DNSMASQ_PATH $TMP_PATH/*-ssr-*.json $TMP_PATH/ssr-server*.json
rm -rf $DNSMASQ_CONF_DIR/dnsmasq-ssrplus.conf \
$TMP_DNSMASQ_PATH \
$TMP_PATH/*-ssr-*.json \
$TMP_PATH/ssr-server*.json \
$TMP_PATH/*-config-*.json
/etc/init.d/dnsmasq restart >/dev/null 2>&1
fi
del_cron
@ -1216,3 +1291,4 @@ reset() {
cp /usr/share/shadowsocksr/shadowsocksr.config /etc/config/shadowsocksr
unset_lock
}

View File

@ -10,6 +10,7 @@ require "luci.util"
require "luci.sys"
require "luci.jsonc"
require "luci.model.ipkg"
-- these global functions are accessed all the time by the event handler
-- so caching them is worth the effort
local tinsert = table.insert
@ -21,15 +22,24 @@ local cache = {}
local nodeResult = setmetatable({}, {__index = cache}) -- update result
local name = 'shadowsocksr'
local uciType = 'servers'
local ucic = luci.model.uci.cursor()
local ucic = require "luci.model.uci".cursor()
local proxy = ucic:get_first(name, 'server_subscribe', 'proxy', '0')
local switch = ucic:get_first(name, 'server_subscribe', 'switch', '1')
local allow_insecure = ucic:get_first(name, 'server_subscribe', 'allow_insecure', '0')
local subscribe_url = ucic:get_first(name, 'server_subscribe', 'subscribe_url', {})
local filter_words = ucic:get_first(name, 'server_subscribe', 'filter_words', '过期时间/剩余流量')
local save_words = ucic:get_first(name, 'server_subscribe', 'save_words', '')
local v2_ss = luci.sys.exec('type -t -p sslocal ss-redir') ~= "" and "ss" or "v2ray"
local ss_variant = luci.sys.exec('type -t -p sslocal') ~= "" and "isSSRust" or luci.sys.exec('type -t -p ss-redir') ~= "" and "isSSLibev"
-- 读取 ss_type 设置
local ss_type = ucic:get_first(name, 'server_subscribe', 'ss_type')
-- 根据 ss_type 选择对应的程序
local ss_program = ""
if ss_type == "ss-rust" then
ss_program = "sslocal" -- Rust 版本使用 sslocal
elseif ss_type == "ss-libev" then
ss_program = "ss-redir" -- Libev 版本使用 ss-redir
end
local v2_ss = luci.sys.exec('type -t -p ' .. ss_program .. ' 2>/dev/null') ~= "" and "ss" or "v2ray"
local has_ss_type = luci.sys.exec('type -t -p ' .. ss_program .. ' 2>/dev/null') ~= "" and ss_type
local v2_tj = luci.sys.exec('type -t -p trojan') ~= "" and "trojan" or "v2ray"
local log = function(...)
print(os.date("%Y-%m-%d %H:%M:%S ") .. table.concat({...}, " "))
@ -279,7 +289,7 @@ local function processData(szType, content)
result.alias = UrlDecode(alias)
result.type = v2_ss
result.v2ray_protocol = (v2_ss == "v2ray") and "shadowsocks" or nil
result.ss_variant = ss_variant
result.has_ss_type = has_ss_type
result.encrypt_method_ss = method
result.password = password
result.server = host[1]
@ -771,3 +781,4 @@ if subscribe_url and #subscribe_url > 0 then
end
end)
end

View File

@ -8,7 +8,7 @@ require "luci.sys"
require "luci.model.uci"
local icount = 0
local args = arg[1]
local uci = luci.model.uci.cursor()
local uci = require "luci.model.uci".cursor()
-- 以下设置更新数据库至 DNSMASQ 配置路径
-- 获取 DNSMASQ 配置 ID