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) ## Installation notes (OpenWrt >= 21.02)
opkg update 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 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.3-r1_all.ipk opkg install /tmp/internet-detector_1.4.4-r1_all.ipk
rm /tmp/internet-detector_1.4.3-r1_all.ipk rm /tmp/internet-detector_1.4.4-r1_all.ipk
service internet-detector start service internet-detector start
service internet-detector enable 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 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.3-r1_all.ipk opkg install /tmp/luci-app-internet-detector_1.4.4-r1_all.ipk
rm /tmp/luci-app-internet-detector_1.4.3-r1_all.ipk rm /tmp/luci-app-internet-detector_1.4.4-r1_all.ipk
service rpcd restart service rpcd restart
i18n-ru: 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 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.3-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.3-r1_all.ipk rm /tmp/luci-i18n-internet-detector-ru_1.4.4-r1_all.ipk
## Screenshots: ## Screenshots:
@ -42,9 +42,9 @@ i18n-ru:
**Dependences:** modemmanager. **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 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.3-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.3-r1_all.ipk rm /tmp/internet-detector-mod-modem-restart_1.4.4-r1_all.ipk
service internet-detector restart service internet-detector restart
![](https://github.com/gSpotx2f/luci-app-internet-detector/blob/master/screenshots/04.jpg) ![](https://github.com/gSpotx2f/luci-app-internet-detector/blob/master/screenshots/04.jpg)
@ -53,9 +53,9 @@ i18n-ru:
**Dependences:** mailsend. **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 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.3-r1_all.ipk opkg install /tmp/internet-detector-mod-email_1.4.4-r1_all.ipk
rm /tmp/internet-detector-mod-email_1.4.3-r1_all.ipk rm /tmp/internet-detector-mod-email_1.4.4-r1_all.ipk
service internet-detector restart service internet-detector restart
![](https://github.com/gSpotx2f/luci-app-internet-detector/blob/master/screenshots/05.jpg) ![](https://github.com/gSpotx2f/luci-app-internet-detector/blob/master/screenshots/05.jpg)

View File

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

View File

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

View File

@ -5,7 +5,7 @@
include $(TOPDIR)/rules.mk include $(TOPDIR)/rules.mk
PKG_NAME:=internet-detector PKG_NAME:=internet-detector
PKG_VERSION:=1.4.3 PKG_VERSION:=1.4.4
PKG_RELEASE:=1 PKG_RELEASE:=1
PKG_MAINTAINER:=gSpot <https://github.com/gSpotx2f/luci-app-internet-detector> 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_provider 'opendns1'
option mod_public_ip_qtype '0' option mod_public_ip_qtype '0'
option mod_public_ip_interval '600' 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_public_ip_enable_ip_script '0'
option mod_email_enabled '0' option mod_email_enabled '0'
option mod_email_mode '0' option mod_email_mode '0'

View File

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

View File

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

View File

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

View File

@ -1038,6 +1038,30 @@ return view.extend({
o.value(3600, '1' + ' ' + _('hour')); o.value(3600, '1' + ' ' + _('hour'));
o.value(10800, '3' + ' ' + _('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 // timeout
o = s.taboption('public_ip', form.ListValue, o = s.taboption('public_ip', form.ListValue,
'mod_public_ip_timeout', _('Server response timeout') 'mod_public_ip_timeout', _('Server response timeout')

View File

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

View File

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

View File

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

View File

@ -1,9 +1,9 @@
local m, s, o local m, s, o
local uci = luci.model.uci.cursor() local uci = require "luci.model.uci".cursor()
local server_table = {} local server_table = {}
local type_table = {} local type_table = {}
local function is_finded(e) 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 end
uci:foreach("shadowsocksr", "servers", function(s) uci:foreach("shadowsocksr", "servers", function(s)
@ -203,6 +203,7 @@ for key, server_type in pairs(type_table) do
o:depends("server", key) o:depends("server", key)
end end
end end
o:depends({server = "same", disable = true})
-- Socks User -- Socks User
o = s:option(Value, "socks5_user", translate("Socks5 User"), translate("Only when Socks5 Auth Mode is password valid, Mandatory.")) 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) o:depends("server", key)
end end
end end
o:depends({server = "same", disable = true})
end end
-- Local Port -- Local Port

View File

@ -6,19 +6,29 @@ require "luci.sys"
require "luci.http" require "luci.http"
require "luci.jsonc" require "luci.jsonc"
require "luci.model.ipkg" require "luci.model.ipkg"
require "luci.model.uci"
local uci = require "luci.model.uci".cursor()
local m, s, o local m, s, o
local sid = arg[1] local sid = arg[1]
local uuid = luci.sys.exec("cat /proc/sys/kernel/random/uuid") local uuid = luci.sys.exec("cat /proc/sys/kernel/random/uuid")
-- 确保正确判断程序是否存在
local function is_finded(e) 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 end
local function is_installed(e) local function is_installed(e)
return luci.model.ipkg.installed(e) return luci.model.ipkg.installed(e)
end 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 server_table = {}
local encrypt_methods = { local encrypt_methods = {
-- ssr -- ssr
@ -79,7 +89,7 @@ local encrypt_methods_ss = {
"camellia-256-cfb", "camellia-256-cfb",
"salsa20", "salsa20",
"chacha20", "chacha20",
"chacha20-ietf" ]] "chacha20-ietf" ]]--
} }
local protocol = { local protocol = {
@ -146,8 +156,8 @@ end
if is_finded("ssr-redir") then if is_finded("ssr-redir") then
o:value("ssr", translate("ShadowsocksR")) o:value("ssr", translate("ShadowsocksR"))
end end
if is_finded("ss-local") or is_finded("ss-redir") or is_finded("sslocal") or is_finded("ssmanager") then if has_ss_rust or has_ss_libev then
o:value("ss", translate("Shadowsocks")) o:value("ss", translate("ShadowSocks"))
end end
if is_finded("trojan") then if is_finded("trojan") then
o:value("trojan", translate("Trojan")) o:value("trojan", translate("Trojan"))
@ -185,16 +195,44 @@ o:depends("type", "tun")
o.description = translate("Redirect traffic to this network interface") o.description = translate("Redirect traffic to this network interface")
-- 新增一个选择框,用于选择 Shadowsocks 版本 -- 新增一个选择框,用于选择 Shadowsocks 版本
o = s:option(ListValue, "ss_variant", translate("Shadowsocks Variant")) o = s:option(ListValue, "has_ss_type", string.format("<b><span style='color:red;'>%s</span></b>", translate("ShadowSocks Node Use Version")))
local isSSRust = is_finded("sslocal") or is_finded("ssmanager") o.description = translate("Selection ShadowSocks Node Use Version.")
local isSSLibev = is_finded("ss-local") or is_finded("ss-redir") -- 设置默认 Shadowsocks 版本
if isSSRust then -- 动态添加选项
o:value("isSSRust", translate("Shadowsocks-rust Version")) if has_ss_rust then
o:value("ss-rust", translate("ShadowSocks-rust Version"))
end end
if isSSLibev then if has_ss_libev then
o:value("isSSLibev", translate("Shadowsocks-libev Version")) 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 end
o:depends("type", "ss") 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 = s:option(ListValue, "v2ray_protocol", translate("V2Ray/XRay protocol"))
o:value("vless", translate("VLESS")) o:value("vless", translate("VLESS"))
@ -271,7 +309,12 @@ o:depends("type", "ssr")
o = s:option(ListValue, "encrypt_method_ss", translate("Encrypt Method")) o = s:option(ListValue, "encrypt_method_ss", translate("Encrypt Method"))
for _, v in ipairs(encrypt_methods_ss) do 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 end
o.rmempty = true o.rmempty = true
o:depends("type", "ss") o:depends("type", "ss")

View File

@ -3,11 +3,11 @@
-- Licensed to the public under the GNU General Public License v3. -- Licensed to the public under the GNU General Public License v3.
local m, s, sec, o 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 validation = require "luci.cbi.datatypes"
local function is_finded(e) 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 end
m = Map("shadowsocksr", translate("ShadowSocksR Plus+ Settings"), translate("<h3>Support SS/SSR/V2RAY/XRAY/TROJAN/NAIVEPROXY/SOCKS5/TUN etc.</h3>")) 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 end
o = sec:option(DummyValue, "encrypt_method", translate("Encrypt Method")) o = sec:option(DummyValue, "encrypt_method", translate("Encrypt Method"))
function o.cfgvalue(...) function o.cfgvalue(self, section)
local v = Value.cfgvalue(...) local method = self.map:get(section, "encrypt_method") or self.map:get(section, "encrypt_method_ss")
return v and v:upper() or "-" return method and method: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 "-"
end end
o = sec:option(DummyValue, "protocol", translate("Protocol")) o = sec:option(DummyValue, "protocol", translate("Protocol"))

View File

@ -1,10 +1,39 @@
-- Licensed to the public under the GNU General Public License v3. -- Licensed to the public under the GNU General Public License v3.
require "luci.http" require "luci.http"
require "luci.sys"
require "luci.dispatcher" require "luci.dispatcher"
require "luci.model.uci" require "luci.model.uci"
local m, s, o local uci = require "luci.model.uci".cursor()
local uci = luci.model.uci.cursor()
local m, s, o, node
local server_count = 0 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) uci:foreach("shadowsocksr", "servers", function(s)
server_count = server_count + 1 server_count = server_count + 1
end) end)
@ -48,6 +77,30 @@ o.default = 30
o.rmempty = true o.rmempty = true
o:depends("auto_update", "1") 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 = s:option(DynamicList, "subscribe_url", translate("Subscribe URL"))
o.rmempty = true o.rmempty = true

View File

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

View File

@ -87,8 +87,18 @@
} }
// set tr draggable // set tr draggable
function enableDragForTable(table_selecter, store) { function enableDragForTable(table_selector, store) {
var trs = document.querySelectorAll(table_selecter + " tr"); // 添加 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) { if (!trs || trs.length.length < 3) {
return; return;
} }
@ -104,12 +114,12 @@
ev.dataTransfer.dropEffect = "move"; ev.dataTransfer.dropEffect = "move";
} }
function moveToTop(id) { 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); cbi_row_drop(id, top.id, store);
} }
function moveToBottom(id) { function moveToBottom(id) {
console.log('moveToBottom:', id); //console.log('moveToBottom:', id);
var trList = document.querySelectorAll(table_selecter + " tr"); var trList = document.querySelectorAll(table_selector + " tr");
var bottom = trList[trList.length - 1]; var bottom = trList[trList.length - 1];
cbi_row_drop(id, bottom.id, store, true); cbi_row_drop(id, bottom.id, store, true);
} }

View File

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

View File

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

View File

@ -166,7 +166,7 @@ _exit() {
} }
first_type() { 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() { ln_start_bin() {
@ -258,7 +258,7 @@ start_dns() {
fi fi
fi fi
fi fi
if [ "$(uci_get_by_type global apple_optimization 1)" == "1" ]; then if [ "$(uci_get_by_type global apple_optimization 1)" == "1" ]; then
local new_appledns="$(uci_get_by_type global apple_dns)" local new_appledns="$(uci_get_by_type global apple_dns)"
if [ -n "$new_appledns" ]; then if [ -n "$new_appledns" ]; then
@ -320,7 +320,7 @@ gen_service_file() { #1-server.type 2-cfgname 3-file_path
get_name() { get_name() {
case "$1" in case "$1" in
ss) echo "Shadowsocks" ;; ss) echo "ShadowSocks" ;;
ssr) echo "ShadowsocksR" ;; ssr) echo "ShadowsocksR" ;;
esac esac
} }
@ -432,11 +432,23 @@ gen_config_file() { #server1 type2 code3 local_port4 socks_port5 chain6 threads5
start_udp() { start_udp() {
local type=$(uci_get_by_name $UDP_RELAY_SERVER type) 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 redir_udp=1
case "$type" in case "$type" in
ss | ssr) ss | ssr)
gen_config_file $UDP_RELAY_SERVER $type 2 $tmp_udp_port 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 ln_start_bin $ss_program ${type}-redir -c $udp_config_file
echolog "UDP TPROXY Relay:$(get_name $type) Started!" echolog "UDP TPROXY Relay:$(get_name $type) Started!"
;; ;;
@ -540,7 +552,7 @@ shunt_dns_config_file_port() {
# 全局socks 有密码NetFlix 不能使用 auth 验证,需更换为新端口并使用无密码的 socks 配置用于分流 # 全局socks 有密码NetFlix 不能使用 auth 验证,需更换为新端口并使用无密码的 socks 配置用于分流
# 新增NetFlix dns 使用端口 # 新增NetFlix dns 使用端口
local port=$tmp_shunt_local_port 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 # 返回端口号 echo $port # 返回端口号
return 0 # 成功返回 return 0 # 成功返回
else else
@ -566,16 +578,38 @@ shunt_dns_config_file_port() {
start_shunt() { start_shunt() {
local type=$(uci_get_by_name $SHUNT_SERVER type) local type=$(uci_get_by_name $SHUNT_SERVER type)
local has_ss_type=$(uci_get_by_type server_subscribe ss_type)
case "$type" in case "$type" in
ss | ssr) ss | ssr)
gen_config_file $SHUNT_SERVER $type 3 $tmp_shunt_port 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 ln_start_bin $ss_program ${type}-redir -c $shunt_config_file
if [ -n "$tmp_local_port" ]; then if [ -n "$tmp_local_port" ]; then
local tmp_port=$tmp_local_port local tmp_port=$tmp_local_port
else else
local tmp_port=$tmp_shunt_local_port 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 fi
shunt_dns_command $tmp_port shunt_dns_command $tmp_port
echolog "shunt:$(get_name $type) Started!" echolog "shunt:$(get_name $type) Started!"
@ -695,10 +729,22 @@ start_local() {
local local_port=$(uci_get_by_type socks5_proxy local_port) local local_port=$(uci_get_by_type socks5_proxy local_port)
[ "$LOCAL_SERVER" == "$SHUNT_SERVER" ] && tmp_local_port=$local_port [ "$LOCAL_SERVER" == "$SHUNT_SERVER" ] && tmp_local_port=$local_port
local type=$(uci_get_by_name $LOCAL_SERVER type) local type=$(uci_get_by_name $LOCAL_SERVER type)
local has_ss_type=$(uci_get_by_type server_subscribe ss_type)
case "$type" in case "$type" in
ss | ssr) ss | ssr)
gen_config_file $LOCAL_SERVER $type 4 $local_port 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 ln_start_bin $ss_program ${type}-local -c $local_config_file
echolog "Global_Socks5:$(get_name $type) Started!" echolog "Global_Socks5:$(get_name $type) Started!"
;; ;;
@ -789,12 +835,24 @@ Start_Run() {
fi fi
local tcp_port=$(uci_get_by_name $GLOBAL_SERVER local_port) local tcp_port=$(uci_get_by_name $GLOBAL_SERVER local_port)
local type=$(uci_get_by_name $GLOBAL_SERVER type) local type=$(uci_get_by_name $GLOBAL_SERVER type)
local has_ss_type=$(uci_get_by_type server_subscribe ss_type)
case "$type" in case "$type" in
ss | ssr) ss | ssr)
gen_config_file $GLOBAL_SERVER $type 1 $tcp_port 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 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 done
echolog "Main node:$(get_name $type) $threads Threads Started!" echolog "Main node:$(get_name $type) $threads Threads Started!"
;; ;;
@ -1000,10 +1058,22 @@ start_server() {
fi fi
fi fi
local type=$(uci_get_by_name $1 type) local type=$(uci_get_by_name $1 type)
local has_ss_type=$(uci_get_by_type server_subscribe ss_type)
case "$type" in case "$type" in
ss | ssr) ss | ssr)
gen_service_file ${type} $1 $TMP_PATH/ssr-server$server_count.json 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!" echolog "Server: $(get_name ${type}) Server$server_count Started!"
;; ;;
socks5) socks5)
@ -1201,7 +1271,12 @@ stop() {
uci -q commit "dhcp" uci -q commit "dhcp"
fi fi
if [ -f "$DNSMASQ_CONF_DIR/dnsmasq-ssrplus.conf" ]; then 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 /etc/init.d/dnsmasq restart >/dev/null 2>&1
fi fi
del_cron del_cron
@ -1216,3 +1291,4 @@ reset() {
cp /usr/share/shadowsocksr/shadowsocksr.config /etc/config/shadowsocksr cp /usr/share/shadowsocksr/shadowsocksr.config /etc/config/shadowsocksr
unset_lock unset_lock
} }

View File

@ -10,6 +10,7 @@ require "luci.util"
require "luci.sys" require "luci.sys"
require "luci.jsonc" require "luci.jsonc"
require "luci.model.ipkg" require "luci.model.ipkg"
-- these global functions are accessed all the time by the event handler -- these global functions are accessed all the time by the event handler
-- so caching them is worth the effort -- so caching them is worth the effort
local tinsert = table.insert local tinsert = table.insert
@ -21,15 +22,24 @@ local cache = {}
local nodeResult = setmetatable({}, {__index = cache}) -- update result local nodeResult = setmetatable({}, {__index = cache}) -- update result
local name = 'shadowsocksr' local name = 'shadowsocksr'
local uciType = 'servers' 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 proxy = ucic:get_first(name, 'server_subscribe', 'proxy', '0')
local switch = ucic:get_first(name, 'server_subscribe', 'switch', '1') local switch = ucic:get_first(name, 'server_subscribe', 'switch', '1')
local allow_insecure = ucic:get_first(name, 'server_subscribe', 'allow_insecure', '0') local allow_insecure = ucic:get_first(name, 'server_subscribe', 'allow_insecure', '0')
local subscribe_url = ucic:get_first(name, 'server_subscribe', 'subscribe_url', {}) local subscribe_url = ucic:get_first(name, 'server_subscribe', 'subscribe_url', {})
local filter_words = ucic:get_first(name, 'server_subscribe', 'filter_words', '过期时间/剩余流量') local filter_words = ucic:get_first(name, 'server_subscribe', 'filter_words', '过期时间/剩余流量')
local save_words = ucic:get_first(name, 'server_subscribe', 'save_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" -- 读取 ss_type 设置
local ss_variant = luci.sys.exec('type -t -p sslocal') ~= "" and "isSSRust" or luci.sys.exec('type -t -p ss-redir') ~= "" and "isSSLibev" 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 v2_tj = luci.sys.exec('type -t -p trojan') ~= "" and "trojan" or "v2ray"
local log = function(...) local log = function(...)
print(os.date("%Y-%m-%d %H:%M:%S ") .. table.concat({...}, " ")) 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.alias = UrlDecode(alias)
result.type = v2_ss result.type = v2_ss
result.v2ray_protocol = (v2_ss == "v2ray") and "shadowsocks" or nil 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.encrypt_method_ss = method
result.password = password result.password = password
result.server = host[1] result.server = host[1]
@ -771,3 +781,4 @@ if subscribe_url and #subscribe_url > 0 then
end end
end) end)
end end

View File

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