diff --git a/luci-app-ssr-plus/Makefile b/luci-app-ssr-plus/Makefile
index 3a0b05549..ce23c1464 100644
--- a/luci-app-ssr-plus/Makefile
+++ b/luci-app-ssr-plus/Makefile
@@ -2,16 +2,21 @@ include $(TOPDIR)/rules.mk
PKG_NAME:=luci-app-ssr-plus
PKG_VERSION:=189
-PKG_RELEASE:=3
+PKG_RELEASE:=7
PKG_CONFIG_DEPENDS:= \
CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_NONE_V2RAY \
CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_V2ray \
CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_Xray \
CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_ChinaDNS_NG \
+ CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_DNS2SOCKS \
+ CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_DNS2SOCKS_RUST \
+ CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_DNS2TCP \
+ CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_DNSPROXY \
+ CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_MosDNS \
CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_Hysteria \
CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_Tuic_Client \
- CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_Shadow-TLS \
+ CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_Shadow_TLS \
CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_IPT2Socks \
CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_Kcptun \
CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_NaiveProxy \
@@ -29,23 +34,24 @@ PKG_CONFIG_DEPENDS:= \
CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_ShadowsocksR_Libev_Server \
CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_Trojan
-LUCI_TITLE:=SS/SSR/V2Ray/Trojan/NaiveProxy/TUIC/ShadowTLS/Hysteria/Socks5/Tun LuCI interface
+LUCI_TITLE:=SS/SSR/V2Ray/Trojan/NaiveProxy/Tuic/ShadowTLS/Hysteria/Socks5/Tun LuCI interface
LUCI_PKGARCH:=all
LUCI_DEPENDS:= \
- +coreutils +coreutils-base64 +dns2socks +dns2tcp +dnsmasq-full +ipset +kmod-ipt-nat \
+ +coreutils +coreutils-base64 +dns2tcp +dnsmasq-full +@PACKAGE_dnsmasq_full_ipset +ipset +kmod-ipt-nat +jq \
+ip-full +iptables +iptables-mod-tproxy +lua +lua-neturl +libuci-lua +microsocks \
- +tcping +resolveip +shadowsocksr-libev-ssr-check +uclient-fetch \
- +PACKAGE_$(PKG_NAME)_INCLUDE_libustream-mbedtls:libustream-mbedtls \
- +PACKAGE_$(PKG_NAME)_INCLUDE_libustream-openssl:libustream-openssl \
- +PACKAGE_$(PKG_NAME)_INCLUDE_libustream-wolfssl:libustream-wolfssl \
+ +tcping +resolveip +shadowsocksr-libev-ssr-check +wget-ssl \
+PACKAGE_$(PKG_NAME)_INCLUDE_V2ray:curl \
+PACKAGE_$(PKG_NAME)_INCLUDE_V2ray:v2ray-core \
+PACKAGE_$(PKG_NAME)_INCLUDE_Xray:curl \
+PACKAGE_$(PKG_NAME)_INCLUDE_Xray:xray-core \
+PACKAGE_$(PKG_NAME)_INCLUDE_ChinaDNS_NG:chinadns-ng \
+ +PACKAGE_$(PKG_NAME)_INCLUDE_DNS2SOCKS:dns2socks \
+ +PACKAGE_$(PKG_NAME)_INCLUDE_DNS2SOCKS_RUST:dns2socks-rust \
+ +PACKAGE_$(PKG_NAME)_INCLUDE_DNSPROXY:dnsproxy \
+ +PACKAGE_$(PKG_NAME)_INCLUDE_MosDNS:mosdns \
+PACKAGE_$(PKG_NAME)_INCLUDE_Hysteria:hysteria \
+PACKAGE_$(PKG_NAME)_INCLUDE_Tuic_Client:tuic-client \
- +PACKAGE_$(PKG_NAME)_INCLUDE_Shadow-TLS:shadow-tls \
+ +PACKAGE_$(PKG_NAME)_INCLUDE_Shadow_TLS:shadow-tls \
+PACKAGE_$(PKG_NAME)_INCLUDE_IPT2Socks:ipt2socks \
+PACKAGE_$(PKG_NAME)_INCLUDE_Kcptun:kcptun-client \
+PACKAGE_$(PKG_NAME)_INCLUDE_NaiveProxy:naiveproxy \
@@ -65,20 +71,7 @@ LUCI_DEPENDS:= \
define Package/$(PKG_NAME)/config
-
-choice
- prompt "Uclient SSL Lib Selection"
- default PACKAGE_$(PKG_NAME)_INCLUDE_libustream-openssl
-
- config PACKAGE_$(PKG_NAME)_INCLUDE_libustream-mbedtls
- bool "libustream-mbedtls"
-
- config PACKAGE_$(PKG_NAME)_INCLUDE_libustream-openssl
- bool "libustream-openssl"
-
- config PACKAGE_$(PKG_NAME)_INCLUDE_PACKAGE_libustream-wolfssl
- bool "libustream-wolfssl"
-endchoice
+select PACKAGE_luci-lib-ipkg if PACKAGE_$(PKG_NAME)
choice
prompt "Shadowsocks Client Selection"
@@ -134,21 +127,37 @@ config PACKAGE_$(PKG_NAME)_INCLUDE_ChinaDNS_NG
bool "Include ChinaDNS-NG"
default n
+config PACKAGE_$(PKG_NAME)_INCLUDE_DNS2SOCKS
+ bool "Include DNS2socks"
+ default y
+
+config PACKAGE_$(PKG_NAME)_INCLUDE_DNS2SOCKS_RUST
+ bool "Include DNS2socks-Rust"
+ default n
+
+config PACKAGE_$(PKG_NAME)_INCLUDE_DNSPROXY
+ bool "Include DNSproxy"
+ default n
+
+config PACKAGE_$(PKG_NAME)_INCLUDE_MosDNS
+ bool "Include MosDNS"
+ default n
+
config PACKAGE_$(PKG_NAME)_INCLUDE_Hysteria
bool "Include Hysteria"
select PACKAGE_$(PKG_NAME)_INCLUDE_ChinaDNS_NG
default n
config PACKAGE_$(PKG_NAME)_INCLUDE_Tuic_Client
- bool "Include tuic-client"
+ bool "Include Tuic-Client"
select PACKAGE_$(PKG_NAME)_INCLUDE_ChinaDNS_NG
select PACKAGE_$(PKG_NAME)_INCLUDE_IPT2Socks
depends on aarch64||arm||i386||x86_64
depends on !(TARGET_x86_geode||TARGET_x86_legacy)
default n
-config PACKAGE_$(PKG_NAME)_INCLUDE_Shadow-TLS
- bool "Include shadow-TLS"
+config PACKAGE_$(PKG_NAME)_INCLUDE_Shadow_TLS
+ bool "Include Shadow-TLS"
select PACKAGE_$(PKG_NAME)_INCLUDE_ChinaDNS_NG
select PACKAGE_$(PKG_NAME)_INCLUDE_Shadowsocks_Rust_Client
depends on aarch64||arm||x86_64
diff --git a/luci-app-ssr-plus/luasrc/controller/shadowsocksr.lua b/luci-app-ssr-plus/luasrc/controller/shadowsocksr.lua
index 75e141feb..636566c85 100644
--- a/luci-app-ssr-plus/luasrc/controller/shadowsocksr.lua
+++ b/luci-app-ssr-plus/luasrc/controller/shadowsocksr.lua
@@ -96,7 +96,7 @@ function check_port()
local retstring = "
"
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
diff --git a/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua b/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua
index 3c96aad9d..95aad5832 100644
--- a/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua
+++ b/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua
@@ -1,9 +1,27 @@
local m, s, o
-local uci = luci.model.uci.cursor()
+local uci = require "luci.model.uci".cursor()
+
+-- 获取 LAN IP 地址
+function lanip()
+ local lan_ip
+ lan_ip = luci.sys.exec("uci -q get network.lan.ipaddr 2>/dev/null | awk -F '/' '{print $1}' | tr -d '\n'")
+
+ if not lan_ip or lan_ip == "" then
+ lan_ip = luci.sys.exec("ip address show $(uci -q -p /tmp/state get network.lan.ifname || uci -q -p /tmp/state get network.lan.device) | grep -w 'inet' | grep -Eo 'inet [0-9\.]+' | awk '{print $2}' | head -1 | tr -d '\n'")
+ end
+
+ if not lan_ip or lan_ip == "" then
+ lan_ip = luci.sys.exec("ip addr show | grep -w 'inet' | grep 'global' | grep -Eo 'inet [0-9\.]+' | awk '{print $2}' | head -n 1 | tr -d '\n'")
+ end
+
+ return lan_ip
+end
+
+local lan_ip = lanip()
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)
@@ -66,6 +84,7 @@ o:value("https://fastly.jsdelivr.net/gh/gaoyifan/china-operator-ip@ip-lists/chin
o.default = "https://ispip.clang.cn/all_cn.txt"
o = s:option(Flag, "netflix_enable", translate("Enable Netflix Mode"))
+o.description = translate("When disabled shunt mode, will same time stopped shunt service.")
o.rmempty = false
o = s:option(Value, "nfip_url", translate("nfip_url"))
@@ -75,6 +94,134 @@ o.default = "https://fastly.jsdelivr.net/gh/QiuSimons/Netflix_IP/NF_only.txt"
o.description = translate("Customize Netflix IP Url")
o:depends("netflix_enable", "1")
+o = s:option(ListValue, "shunt_dns_mode", translate("DNS Query Mode For Shunt Mode"))
+if is_finded("dns2socks") then
+ o:value("1", translate("Use DNS2SOCKS query and cache"))
+end
+if is_finded("dns2socks-rust") then
+ o:value("2", translate("Use DNS2SOCKS-RUST query and cache"))
+end
+if is_finded("mosdns") then
+ o:value("3", translate("Use MosDNS query"))
+end
+if is_finded("dnsproxy") then
+ o:value("4", translate("Use DNSPROXY query and cache"))
+end
+if is_finded("chinadns-ng") then
+ o:value("5", translate("Use ChinaDNS-NG query and cache"))
+end
+o:depends("netflix_enable", "1")
+o.default = 1
+
+o = s:option(Value, "shunt_dnsserver", translate("Anti-pollution DNS Server For Shunt Mode"))
+o:value("8.8.4.4:53", translate("Google Public DNS (8.8.4.4)"))
+o:value("8.8.8.8:53", translate("Google Public DNS (8.8.8.8)"))
+o:value("208.67.222.222:53", translate("OpenDNS (208.67.222.222)"))
+o:value("208.67.220.220:53", translate("OpenDNS (208.67.220.220)"))
+o:value("209.244.0.3:53", translate("Level 3 Public DNS (209.244.0.3)"))
+o:value("209.244.0.4:53", translate("Level 3 Public DNS (209.244.0.4)"))
+o:value("4.2.2.1:53", translate("Level 3 Public DNS (4.2.2.1)"))
+o:value("4.2.2.2:53", translate("Level 3 Public DNS (4.2.2.2)"))
+o:value("4.2.2.3:53", translate("Level 3 Public DNS (4.2.2.3)"))
+o:value("4.2.2.4:53", translate("Level 3 Public DNS (4.2.2.4)"))
+o:value("1.1.1.1:53", translate("Cloudflare DNS (1.1.1.1)"))
+o:depends("shunt_dns_mode", "1")
+o:depends("shunt_dns_mode", "2")
+o.description = translate("Custom DNS Server format as IP:PORT (default: 8.8.4.4:53)")
+o.datatype = "ip4addrport"
+
+o = s:option(ListValue, "shunt_mosdns_dnsserver", translate("Anti-pollution DNS Server"))
+o:value("tcp://8.8.4.4:53,tcp://8.8.8.8:53", translate("Google Public DNS"))
+o:value("tcp://208.67.222.222:53,tcp://208.67.220.220:53", translate("OpenDNS"))
+o:value("tcp://209.244.0.3:53,tcp://209.244.0.4:53", translate("Level 3 Public DNS-1 (209.244.0.3-4)"))
+o:value("tcp://4.2.2.1:53,tcp://4.2.2.2:53", translate("Level 3 Public DNS-2 (4.2.2.1-2)"))
+o:value("tcp://4.2.2.3:53,tcp://4.2.2.4:53", translate("Level 3 Public DNS-3 (4.2.2.3-4)"))
+o:value("tcp://1.1.1.1:53,tcp://1.0.0.1:53", translate("Cloudflare DNS"))
+o:depends("shunt_dns_mode", "3")
+o.description = translate("Custom DNS Server for MosDNS")
+
+o = s:option(Flag, "shunt_mosdns_ipv6", translate("Disable IPv6 In MosDNS Query Mode (Shunt Mode)"))
+o:depends("shunt_dns_mode", "3")
+o.rmempty = false
+o.default = "0"
+
+if is_finded("dnsproxy") then
+ o = s:option(ListValue, "shunt_parse_method", translate("Select DNS parse Mode"))
+ o.description = translate(
+ "
"
+ )
+ o:value("single_dns", translate("Set Single DNS"))
+ o:value("parse_file", translate("Use DNS List File"))
+ o:depends("shunt_dns_mode", "4")
+ o.rmempty = true
+ o.default = "single_dns"
+
+ o = s:option(Value, "dnsproxy_shunt_forward", translate("Anti-pollution DNS Server"))
+ o:value("sdns://AgUAAAAAAAAABzguOC40LjQgsKKKE4EwvtIbNjGjagI2607EdKSVHowYZtyvD9iPrkkHOC44LjQuNAovZG5zLXF1ZXJ5", translate("Google DNSCrypt SDNS"))
+ o:value("sdns://AgcAAAAAAAAAACC2vD25TAYM7EnyCH8Xw1-0g5OccnTsGH9vQUUH0njRtAxkbnMudHduaWMudHcKL2Rucy1xdWVyeQ", translate("TWNIC-101 DNSCrypt SDNS"))
+ o:value("sdns://AgcAAAAAAAAADzE4NS4yMjIuMjIyLjIyMiAOp5Svj-oV-Fz-65-8H2VKHLKJ0egmfEgrdPeAQlUFFA8xODUuMjIyLjIyMi4yMjIKL2Rucy1xdWVyeQ", translate("dns.sb DNSCrypt SDNS"))
+ o:value("sdns://AgMAAAAAAAAADTE0OS4xMTIuMTEyLjkgsBkgdEu7dsmrBT4B4Ht-BQ5HPSD3n3vqQ1-v5DydJC8SZG5zOS5xdWFkOS5uZXQ6NDQzCi9kbnMtcXVlcnk", translate("Quad9 DNSCrypt SDNS"))
+ o:value("sdns://AQMAAAAAAAAAETk0LjE0MC4xNC4xNDo1NDQzINErR_JS3PLCu_iZEIbq95zkSV2LFsigxDIuUso_OQhzIjIuZG5zY3J5cHQuZGVmYXVsdC5uczEuYWRndWFyZC5jb20", translate("AdGuard DNSCrypt SDNS"))
+ o:value("sdns://AgcAAAAAAAAABzEuMC4wLjGgENk8mGSlIfMGXMOlIlCcKvq7AVgcrZxtjon911-ep0cg63Ul-I8NlFj4GplQGb_TTLiczclX57DvMV8Q-JdjgRgSZG5zLmNsb3VkZmxhcmUuY29tCi9kbnMtcXVlcnk", translate("Cloudflare DNSCrypt SDNS"))
+ o:value("sdns://AgcAAAAAAAAADjEwNC4xNi4yNDkuMjQ5ABJjbG91ZGZsYXJlLWRucy5jb20KL2Rucy1xdWVyeQ", translate("cloudflare-dns.com DNSCrypt SDNS"))
+ o:depends("shunt_parse_method", "single_dns")
+ o.description = translate("Custom DNS Server (support: IP:Port or tls://IP:Port or https://IP/dns-query and other format).")
+
+ o = s:option(ListValue, "shunt_upstreams_logic_mode", translate("Defines the upstreams logic mode"))
+ o.description = translate(
+ "" ..
+ "- " .. translate("Defines the upstreams logic mode, possible values: load_balance, parallel, fastest_addr (default: load_balance).") .. "
" .. "- " .. translate("When two or more DNS servers are deployed, enable this function.") .. "
" ..
+ "
"
+ )
+ o:value("load_balance", translate("load_balance"))
+ o:value("parallel", translate("parallel"))
+ o:value("fastest_addr", translate("fastest_addr"))
+ o:depends("shunt_parse_method", "parse_file")
+ o.rmempty = true
+ o.default = "load_balance"
+
+ o = s:option(Flag, "shunt_dnsproxy_ipv6", translate("Disable IPv6 query mode"))
+ o.description = translate("When disabled, all AAAA requests are not resolved.")
+ o:depends("shunt_parse_method", "single_dns")
+ o:depends("shunt_parse_method", "parse_file")
+ o.rmempty = false
+ o.default = "1"
+end
+
+if is_finded("chinadns-ng") then
+ o = s:option(Value, "chinadns_ng_shunt_dnsserver", translate("Anti-pollution DNS Server For Shunt Mode"))
+ o:value("8.8.4.4:53", translate("Google Public DNS (8.8.4.4)"))
+ o:value("8.8.8.8:53", translate("Google Public DNS (8.8.8.8)"))
+ o:value("208.67.222.222:53", translate("OpenDNS (208.67.222.222)"))
+ o:value("208.67.220.220:53", translate("OpenDNS (208.67.220.220)"))
+ o:value("209.244.0.3:53", translate("Level 3 Public DNS (209.244.0.3)"))
+ o:value("209.244.0.4:53", translate("Level 3 Public DNS (209.244.0.4)"))
+ o:value("4.2.2.1:53", translate("Level 3 Public DNS (4.2.2.1)"))
+ o:value("4.2.2.2:53", translate("Level 3 Public DNS (4.2.2.2)"))
+ o:value("4.2.2.3:53", translate("Level 3 Public DNS (4.2.2.3)"))
+ o:value("4.2.2.4:53", translate("Level 3 Public DNS (4.2.2.4)"))
+ o:value("1.1.1.1:53", translate("Cloudflare DNS (1.1.1.1)"))
+ o:depends("shunt_dns_mode", "5")
+ o.description = translate(
+ "" ..
+ "- " .. translate("Custom DNS Server format as IP:PORT (default: 8.8.4.4:53)") .. "
" ..
+ "- " .. translate("Muitiple DNS server can saperate with ','") .. "
" ..
+ "
"
+ )
+
+ o = s:option(ListValue, "chinadns_ng_shunt_proto", translate("ChinaDNS-NG shunt query protocol"))
+ o:value("none", translate("UDP/TCP upstream"))
+ o:value("tcp", translate("TCP upstream"))
+ o:value("udp", translate("UDP upstream"))
+ o:value("tls", translate("DoT upstream (Need use wolfssl version)"))
+ o:depends("shunt_dns_mode", "5")
+end
+
o = s:option(Flag, "apple_optimization", translate("Apple domains optimization"), translate("For Apple domains equipped with Chinese mainland CDN, always responsive to Chinese CDN IP addresses"))
o.rmempty = false
o.default = "1"
@@ -130,15 +277,15 @@ o.rmempty = false
o.cfgvalue = function(self, section)
local enabled = m:get(section, "enabled")
if enabled == "0" then
- return m:get(section, "old_server") or "same"
+ return m:get(section, "old_server")
end
- return Value.cfgvalue(self, section) or "same" -- Default to `same` when enabled
+ return Value.cfgvalue(self, section)-- Default to `same` when enabled
end
o.write = function(self, section, value)
local enabled = m:get(section, "enabled")
if enabled == "0" then
- local old_server = Value.cfgvalue(self, section) or "same"
+ local old_server = Value.cfgvalue(self, section)
if old_server ~= "nil" then
m:set(section, "old_server", old_server)
end
@@ -163,6 +310,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."))
@@ -185,6 +333,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
@@ -248,6 +397,7 @@ o = s:option(ListValue, "type", translate("Type"))
o.default = "base64"
o:value("rand", "rand")
o:value("str", "str")
+o:value("hex", "hex")
o:value("base64", "base64")
o = s:option(Value, "domainStrategy", translate("Domain Strategy"))
diff --git a/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua b/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua
index 3db565373..42b2b0f69 100644
--- a/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua
+++ b/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua
@@ -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 = {
@@ -134,7 +144,7 @@ s = m:section(NamedSection, sid, "servers")
s.anonymous = true
s.addremove = false
-o = s:option(DummyValue, "ssr_url", "SS/SSR/V2RAY/TROJAN URL")
+o = s:option(DummyValue, "ssr_url", "SS/SSR/V2RAY/TROJAN/HYSTERIA2 URL")
o.rawhtml = true
o.template = "shadowsocksr/ssrurl"
o.value = sid
@@ -146,11 +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") then
- o:value("ss", translate("Shadowsocks-libev Version"))
-end
-if is_finded("sslocal") or is_finded("ssmanager") then
- o:value("ss", translate("Shadowsocks-rust Version"))
+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"))
@@ -159,7 +166,7 @@ if is_finded("naive") then
o:value("naiveproxy", translate("NaiveProxy"))
end
if is_finded("hysteria") then
- o:value("hysteria", translate("Hysteria"))
+ o:value("hysteria2", translate("Hysteria2"))
end
if is_finded("tuic-client") then
o:value("tuic", translate("TUIC"))
@@ -187,11 +194,51 @@ end
o:depends("type", "tun")
o.description = translate("Redirect traffic to this network interface")
+-- 新增一个选择框,用于选择 Shadowsocks 版本
+o = s:option(ListValue, "has_ss_type", string.format("%s", 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 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"))
o:value("vmess", translate("VMess"))
o:value("trojan", translate("Trojan"))
-o:value("shadowsocks", translate("Shadowsocks"))
+o:value("shadowsocks", translate("ShadowSocks"))
if is_finded("xray") then
o:value("wireguard", translate("WireGuard"))
end
@@ -207,7 +254,7 @@ o:depends("type", "ss")
o:depends("type", "v2ray")
o:depends("type", "trojan")
o:depends("type", "naiveproxy")
-o:depends("type", "hysteria")
+o:depends("type", "hysteria2")
o:depends("type", "tuic")
o:depends("type", "shadowtls")
o:depends("type", "socks5")
@@ -220,7 +267,7 @@ o:depends("type", "ss")
o:depends("type", "v2ray")
o:depends("type", "trojan")
o:depends("type", "naiveproxy")
-o:depends("type", "hysteria")
+o:depends("type", "hysteria2")
o:depends("type", "tuic")
o:depends("type", "shadowtls")
o:depends("type", "socks5")
@@ -262,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")
@@ -279,8 +331,14 @@ o.rmempty = true
o:depends({type = "v2ray", v2ray_protocol = "shadowsocks"})
o.default = "1"
+-- [[ Enable Shadowsocks Plugin ]]--
+o = s:option(Flag, "enable_plugin", translate("Enable Plugin"))
+o.rmempty = true
+o:depends("type", "ss")
+o.default = "0"
+
-- Shadowsocks Plugin
-o = s:option(Value, "plugin", translate("Obfs"))
+o = s:option(ListValue, "plugin", translate("Obfs"))
o:value("none", translate("None"))
if is_finded("obfs-local") then
o:value("obfs-local", translate("obfs-local"))
@@ -291,12 +349,17 @@ end
if is_finded("xray-plugin") then
o:value("xray-plugin", translate("xray-plugin"))
end
+o:value("custom", translate("Custom"))
o.rmempty = true
-o:depends("type", "ss")
+o:depends({enable_plugin = true})
+
+o = s:option(Value, "custom_plugin", translate("Custom Plugin Path"))
+o.placeholder = "/path/to/custom-plugin"
+o:depends({plugin = "custom"})
o = s:option(Value, "plugin_opts", translate("Plugin Opts"))
o.rmempty = true
-o:depends("type", "ss")
+o:depends({enable_plugin = true})
o = s:option(ListValue, "protocol", translate("Protocol"))
for _, v in ipairs(protocol) do
@@ -321,100 +384,101 @@ o:depends("type", "ssr")
-- [[ Hysteria2 ]]--
o = s:option(Value, "hy2_auth", translate("Users Authentication"))
-o:depends("type", "hysteria")
+o:depends("type", "hysteria2")
o.rmempty = false
o = s:option(Flag, "flag_port_hopping", translate("Enable Port Hopping"))
-o:depends("type", "hysteria")
+o:depends("type", "hysteria2")
o.rmempty = true
o.default = "0"
-o = s:option(Value, "port_range", translate("Port Range"))
-o:depends({type = "hysteria", flag_port_hopping = true})
-o.datatype = "portrange"
+o = s:option(Value, "port_range", translate("Port hopping range"))
+o.description = translate("Format as 10000:20000 or 10000-20000 Multiple groups are separated by commas (,).")
+o:depends({type = "hysteria2", flag_port_hopping = true})
+--o.datatype = "portrange"
o.rmempty = true
o = s:option(Flag, "flag_transport", translate("Enable Transport Protocol Settings"))
-o:depends("type", "hysteria")
+o:depends("type", "hysteria2")
o.rmempty = true
o.default = "0"
o = s:option(ListValue, "transport_protocol", translate("Transport Protocol"))
-o:depends({type = "hysteria", flag_transport = true})
+o:depends({type = "hysteria2", flag_transport = true})
o:value("udp", translate("UDP"))
o.default = "udp"
o.rmempty = true
o = s:option(Value, "hopinterval", translate("Port Hopping Interval(Unit:Second)"))
-o:depends({type = "hysteria", flag_transport = true, flag_port_hopping = true})
+o:depends({type = "hysteria2", flag_transport = true, flag_port_hopping = true})
o.datatype = "uinteger"
o.rmempty = true
o.default = "30"
o = s:option(Flag, "flag_obfs", translate("Enable Obfuscation"))
-o:depends("type", "hysteria")
+o:depends("type", "hysteria2")
o.rmempty = true
o.default = "0"
o = s:option(Flag, "lazy_mode", translate("Enable Lazy Mode"))
-o:depends("type", "hysteria")
+o:depends("type", "hysteria2")
o.rmempty = true
o.default = "0"
o = s:option(Value, "obfs_type", translate("Obfuscation Type"))
-o:depends({type = "hysteria", flag_obfs = "1"})
+o:depends({type = "hysteria2", flag_obfs = "1"})
o.rmempty = true
o.default = "salamander"
o = s:option(Value, "salamander", translate("Obfuscation Password"))
-o:depends({type = "hysteria", flag_obfs = "1"})
+o:depends({type = "hysteria2", flag_obfs = "1"})
o.rmempty = true
o.default = "cry_me_a_r1ver"
o = s:option(Flag, "flag_quicparam", translate("Hysterir QUIC parameters"))
-o:depends("type", "hysteria")
+o:depends("type", "hysteria2")
o.rmempty = true
o.default = "0"
o = s:option(Flag, "disablepathmtudiscovery", translate("Disable QUIC path MTU discovery"))
-o:depends({type = "hysteria",flag_quicparam = "1"})
+o:depends({type = "hysteria2",flag_quicparam = "1"})
o.rmempty = true
o.default = false
--[[Hysteria2 QUIC parameters setting]]
o = s:option(Value, "initstreamreceivewindow", translate("QUIC initStreamReceiveWindow"))
-o:depends({type = "hysteria", flag_quicparam = "1"})
+o:depends({type = "hysteria2", flag_quicparam = "1"})
o.datatype = "uinteger"
o.rmempty = true
o.default = "8388608"
o = s:option(Value, "maxstreamseceivewindow", translate("QUIC maxStreamReceiveWindow"))
-o:depends({type = "hysteria", flag_quicparam = "1"})
+o:depends({type = "hysteria2", flag_quicparam = "1"})
o.datatype = "uinteger"
o.rmempty = true
o.default = "8388608"
o = s:option(Value, "initconnreceivewindow", translate("QUIC initConnReceiveWindow"))
-o:depends({type = "hysteria", flag_quicparam = "1"})
+o:depends({type = "hysteria2", flag_quicparam = "1"})
o.datatype = "uinteger"
o.rmempty = true
o.default = "20971520"
o = s:option(Value, "maxconnreceivewindow", translate("QUIC maxConnReceiveWindow"))
-o:depends({type = "hysteria", flag_quicparam = "1"})
+o:depends({type = "hysteria2", flag_quicparam = "1"})
o.datatype = "uinteger"
o.rmempty = true
o.default = "20971520"
o = s:option(Value, "maxidletimeout", translate("QUIC maxIdleTimeout(Unit:second)"))
-o:depends({type = "hysteria", flag_quicparam = "1"})
+o:depends({type = "hysteria2", flag_quicparam = "1"})
o.rmempty = true
o.datatype = "uinteger"
o.default = "30"
o = s:option(Value, "keepaliveperiod", translate("The keep-alive period.(Unit:second)"))
o.description = translate("Default value 0 indicatesno heartbeat.")
-o:depends({type = "hysteria", flag_quicparam = "1"})
+o:depends({type = "hysteria2", flag_quicparam = "1"})
o:depends({type = "v2ray", v2ray_protocol = "wireguard"})
o.rmempty = true
o.datatype = "uinteger"
@@ -454,7 +518,7 @@ o.default = ""
o = s:option(ListValue, "chain_type", translate("Shadow-TLS ChainPoxy type"))
o:depends("type", "shadowtls")
if is_finded("sslocal") then
- o:value("sslocal", translate("Shadowsocks-rust Version"))
+ o:value("sslocal", translate("ShadowSocks-rust Version"))
end
if is_finded("xray") or is_finded("v2ray") then
o:value("vmess", translate("Vmess Protocol"))
@@ -888,14 +952,14 @@ o.rmempty = true
o = s:option(Value, "uplink_capacity", translate("Uplink Capacity(Default:Mbps)"))
o.datatype = "uinteger"
o:depends("transport", "kcp")
-o:depends("type", "hysteria")
+o:depends("type", "hysteria2")
o.default = 5
o.rmempty = true
o = s:option(Value, "downlink_capacity", translate("Downlink Capacity(Default:Mbps)"))
o.datatype = "uinteger"
o:depends("transport", "kcp")
-o:depends("type", "hysteria")
+o:depends("type", "hysteria2")
o.default = 20
o.rmempty = true
@@ -968,7 +1032,7 @@ o:depends({type = "v2ray", v2ray_protocol = "shadowsocks", reality = false})
o:depends({type = "v2ray", v2ray_protocol = "socks", socks_ver = "5", reality = false})
o:depends({type = "v2ray", v2ray_protocol = "http", reality = false})
o:depends("type", "trojan")
-o:depends("type", "hysteria")
+o:depends("type", "hysteria2")
-- [[ TLS部分 ]] --
o = s:option(Flag, "tls_sessionTicket", translate("Session Ticket"))
@@ -1055,12 +1119,12 @@ o.rmempty = true
o = s:option(Flag, "insecure", translate("allowInsecure"))
o.rmempty = false
o:depends("tls", true)
-o:depends("type", "hysteria")
+o:depends("type", "hysteria2")
o.description = translate("If true, allowss insecure connection at TLS client, e.g., TLS server uses unverifiable certificates.")
-- [[ Hysteria2 TLS pinSHA256 ]] --
o = s:option(Value, "pinsha256", translate("Certificate fingerprint"))
-o:depends({type = "hysteria", insecure = true })
+o:depends({type = "hysteria2", insecure = true })
o.rmempty = true
@@ -1076,6 +1140,7 @@ o:depends({type = "v2ray", v2ray_protocol = "vless", transport = "splithttp"})
o:depends({type = "v2ray", v2ray_protocol = "vless", transport = "h2"})
o:depends({type = "v2ray", v2ray_protocol = "vless", transport = "quic"})
o:depends({type = "v2ray", v2ray_protocol = "vless", transport = "grpc"})
+o:depends({type = "v2ray", v2ray_protocol = "vmess"})
o:depends({type = "v2ray", v2ray_protocol = "trojan"})
o:depends({type = "v2ray", v2ray_protocol = "shadowsocks"})
o:depends({type = "v2ray", v2ray_protocol = "socks"})
@@ -1167,7 +1232,7 @@ o = s:option(Flag, "certificate", translate("Self-signed Certificate"))
o.rmempty = true
o.default = "0"
o:depends("type", "tuic")
-o:depends({type = "hysteria", insecure = false})
+o:depends({type = "hysteria2", insecure = false})
o:depends({type = "trojan", tls = true, insecure = false})
o:depends({type = "v2ray", v2ray_protocol = "vmess", tls = true, insecure = false})
o:depends({type = "v2ray", v2ray_protocol = "vless", tls = true, insecure = false})
@@ -1209,9 +1274,9 @@ end
o = s:option(Value, "certpath", translate("Current Certificate Path"))
o:depends("certificate", 1)
-o:value("/etc/ssl/private/ca.pem")
+o:value("/etc/ssl/private/ca.crt")
o.description = translate("Please confirm the current certificate path")
-o.default = "/etc/ssl/private/ca.pem"
+o.default = "/etc/ssl/private/ca.crt"
o = s:option(Flag, "fast_open", translate("TCP Fast Open"), translate("Enabling TCP Fast Open Requires Server Support."))
o.rmempty = true
@@ -1219,7 +1284,7 @@ o.default = "0"
o:depends("type", "ssr")
o:depends("type", "ss")
o:depends("type", "trojan")
-o:depends("type", "hysteria")
+o:depends("type", "hysteria2")
o = s:option(Flag, "switch_enable", translate("Enable Auto Switch"))
o.rmempty = false
@@ -1255,3 +1320,5 @@ if is_finded("kcptun-client") then
end
return m
+
+
diff --git a/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua b/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua
index b24183eec..c6194fa8b 100644
--- a/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua
+++ b/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua
@@ -3,11 +3,28 @@
-- 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()
+-- 获取 LAN IP 地址
+function lanip()
+ local lan_ip
+ lan_ip = luci.sys.exec("uci -q get network.lan.ipaddr 2>/dev/null | awk -F '/' '{print $1}' | tr -d '\n'")
+
+ if not lan_ip or lan_ip == "" then
+ lan_ip = luci.sys.exec("ip address show $(uci -q -p /tmp/state get network.lan.ifname || uci -q -p /tmp/state get network.lan.device) | grep -w 'inet' | grep -Eo 'inet [0-9\.]+' | awk '{print $2}' | head -1 | tr -d '\n'")
+ end
+
+ if not lan_ip or lan_ip == "" then
+ lan_ip = luci.sys.exec("ip addr show | grep -w 'inet' | grep 'global' | grep -Eo 'inet [0-9\.]+' | awk '{print $2}' | head -n 1 | tr -d '\n'")
+ end
+
+ return lan_ip
+end
+
+local lan_ip = lanip()
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"))
@@ -48,20 +65,20 @@ for _, key in pairs(key_table) do
o:value(key, server_table[key])
end
-if uci:get_first("shadowsocksr", 'global', 'netflix_enable', '0') ~= '0' then
-o = s:option(ListValue, "netflix_server", translate("Netflix Node"))
-o:value("nil", translate("Disable"))
-o:value("same", translate("Same as Global Server"))
-for _, key in pairs(key_table) do
- o:value(key, server_table[key])
-end
-o.default = "nil"
-o.rmempty = false
+if uci:get_first("shadowsocksr", 'global', 'netflix_enable', '0') == '1' then
+ o = s:option(ListValue, "netflix_server", translate("Netflix Node"))
+ o:value("nil", translate("Disable"))
+ o:value("same", translate("Same as Global Server"))
+ for _, key in pairs(key_table) do
+ o:value(key, server_table[key])
+ end
+ o.default = "nil"
+ o.rmempty = false
-o = s:option(Flag, "netflix_proxy", translate("External Proxy Mode"))
-o.rmempty = false
-o.description = translate("Forward Netflix Proxy through Main Proxy")
-o.default = "0"
+ o = s:option(Flag, "netflix_proxy", translate("External Proxy Mode"))
+ o.rmempty = false
+ o.description = translate("Forward Netflix Proxy through Main Proxy")
+ o.default = "0"
end
o = s:option(ListValue, "threads", translate("Multi Threads Option"))
@@ -94,8 +111,24 @@ cp.placeholder = "e.g., 80,443,8080"
o.default = 1
o = s:option(ListValue, "pdnsd_enable", translate("Resolve Dns Mode"))
-o:value("1", translate("Use DNS2TCP query"))
-o:value("2", translate("Use DNS2SOCKS query and cache"))
+if is_finded("dns2tcp") then
+ o:value("1", translate("Use DNS2TCP query"))
+end
+if is_finded("dns2socks") then
+ o:value("2", translate("Use DNS2SOCKS query and cache"))
+end
+if is_finded("dns2socks-rust") then
+ o:value("3", translate("Use DNS2SOCKS-RUST query and cache"))
+end
+if is_finded("mosdns") then
+ o:value("4", translate("Use MOSDNS query (Not Support Oversea Mode)"))
+end
+if is_finded("dnsproxy") then
+ o:value("5", translate("Use DNSPROXY query and cache"))
+end
+if is_finded("chinadns-ng") then
+ o:value("6", translate("Use ChinaDNS-NG query and cache"))
+end
o:value("0", translate("Use Local DNS Service listen port 5335"))
o.default = 1
@@ -115,10 +148,102 @@ o:value("114.114.114.114:53", translate("Oversea Mode DNS-1 (114.114.114.114)"))
o:value("114.114.115.115:53", translate("Oversea Mode DNS-2 (114.114.115.115)"))
o:depends("pdnsd_enable", "1")
o:depends("pdnsd_enable", "2")
+o:depends("pdnsd_enable", "3")
o.description = translate("Custom DNS Server format as IP:PORT (default: 8.8.4.4:53)")
o.datatype = "ip4addrport"
+o = s:option(ListValue, "tunnel_forward_mosdns", translate("Anti-pollution DNS Server"))
+o:value("tcp://8.8.4.4:53,tcp://8.8.8.8:53", translate("Google Public DNS"))
+o:value("tcp://208.67.222.222:53,tcp://208.67.220.220:53", translate("OpenDNS"))
+o:value("tcp://209.244.0.3:53,tcp://209.244.0.4:53", translate("Level 3 Public DNS-1 (209.244.0.3-4)"))
+o:value("tcp://4.2.2.1:53,tcp://4.2.2.2:53", translate("Level 3 Public DNS-2 (4.2.2.1-2)"))
+o:value("tcp://4.2.2.3:53,tcp://4.2.2.4:53", translate("Level 3 Public DNS-3 (4.2.2.3-4)"))
+o:value("tcp://1.1.1.1:53,tcp://1.0.0.1:53", translate("Cloudflare DNS"))
+o:depends("pdnsd_enable", "4")
+o.description = translate("Custom DNS Server for MosDNS")
+
+o = s:option(Flag, "mosdns_ipv6", translate("Disable IPv6 in MOSDNS query mode"))
+o:depends("pdnsd_enable", "4")
+o.rmempty = false
+o.default = "1"
+
+if is_finded("dnsproxy") then
+ o = s:option(ListValue, "parse_method", translate("Select DNS parse Mode"))
+ o.description = translate(
+ ""
+ )
+ o:value("single_dns", translate("Set Single DNS"))
+ o:value("parse_file", translate("Use DNS List File"))
+ o:depends("pdnsd_enable", "5")
+ o.rmempty = true
+ o.default = "single_dns"
+
+ o = s:option(Value, "dnsproxy_tunnel_forward", translate("Anti-pollution DNS Server"))
+ o:value("sdns://AgUAAAAAAAAABzguOC40LjQgsKKKE4EwvtIbNjGjagI2607EdKSVHowYZtyvD9iPrkkHOC44LjQuNAovZG5zLXF1ZXJ5", translate("Google DNSCrypt SDNS"))
+ o:value("sdns://AgcAAAAAAAAAACC2vD25TAYM7EnyCH8Xw1-0g5OccnTsGH9vQUUH0njRtAxkbnMudHduaWMudHcKL2Rucy1xdWVyeQ", translate("TWNIC-101 DNSCrypt SDNS"))
+ o:value("sdns://AgcAAAAAAAAADzE4NS4yMjIuMjIyLjIyMiAOp5Svj-oV-Fz-65-8H2VKHLKJ0egmfEgrdPeAQlUFFA8xODUuMjIyLjIyMi4yMjIKL2Rucy1xdWVyeQ", translate("dns.sb DNSCrypt SDNS"))
+ o:value("sdns://AgMAAAAAAAAADTE0OS4xMTIuMTEyLjkgsBkgdEu7dsmrBT4B4Ht-BQ5HPSD3n3vqQ1-v5DydJC8SZG5zOS5xdWFkOS5uZXQ6NDQzCi9kbnMtcXVlcnk", translate("Quad9 DNSCrypt SDNS"))
+ o:value("sdns://AQMAAAAAAAAAETk0LjE0MC4xNC4xNDo1NDQzINErR_JS3PLCu_iZEIbq95zkSV2LFsigxDIuUso_OQhzIjIuZG5zY3J5cHQuZGVmYXVsdC5uczEuYWRndWFyZC5jb20", translate("AdGuard DNSCrypt SDNS"))
+ o:value("sdns://AgcAAAAAAAAABzEuMC4wLjGgENk8mGSlIfMGXMOlIlCcKvq7AVgcrZxtjon911-ep0cg63Ul-I8NlFj4GplQGb_TTLiczclX57DvMV8Q-JdjgRgSZG5zLmNsb3VkZmxhcmUuY29tCi9kbnMtcXVlcnk", translate("Cloudflare DNSCrypt SDNS"))
+ o:value("sdns://AgcAAAAAAAAADjEwNC4xNi4yNDkuMjQ5ABJjbG91ZGZsYXJlLWRucy5jb20KL2Rucy1xdWVyeQ", translate("cloudflare-dns.com DNSCrypt SDNS"))
+ o:depends("parse_method", "single_dns")
+ o.description = translate("Custom DNS Server (support: IP:Port or tls://IP:Port or https://IP/dns-query and other format).")
+
+ o = s:option(ListValue, "upstreams_logic_mode", translate("Defines the upstreams logic mode"))
+ o.description = translate(
+ "" ..
+ "- " .. translate("Defines the upstreams logic mode, possible values: load_balance, parallel, fastest_addr (default: load_balance).") .. "
" ..
+ "- " .. translate("When two or more DNS servers are deployed, enable this function.") .. "
" ..
+ "
"
+ )
+ o:value("load_balance", translate("load_balance"))
+ o:value("parallel", translate("parallel"))
+ o:value("fastest_addr", translate("fastest_addr"))
+ o:depends("parse_method", "parse_file")
+ o.rmempty = true
+ o.default = "load_balance"
+
+ o = s:option(Flag, "dnsproxy_ipv6", translate("Disable IPv6 query mode"))
+ o.description = translate("When disabled, all AAAA requests are not resolved.")
+ o:depends("parse_method", "single_dns")
+ o:depends("parse_method", "parse_file")
+ o.rmempty = false
+ o.default = "1"
+end
+
if is_finded("chinadns-ng") then
+ o = s:option(Value, "chinadns_ng_tunnel_forward", translate("Anti-pollution DNS Server"))
+ o:value("8.8.4.4:53", translate("Google Public DNS (8.8.4.4)"))
+ o:value("8.8.8.8:53", translate("Google Public DNS (8.8.8.8)"))
+ o:value("208.67.222.222:53", translate("OpenDNS (208.67.222.222)"))
+ o:value("208.67.220.220:53", translate("OpenDNS (208.67.220.220)"))
+ o:value("209.244.0.3:53", translate("Level 3 Public DNS (209.244.0.3)"))
+ o:value("209.244.0.4:53", translate("Level 3 Public DNS (209.244.0.4)"))
+ o:value("4.2.2.1:53", translate("Level 3 Public DNS (4.2.2.1)"))
+ o:value("4.2.2.2:53", translate("Level 3 Public DNS (4.2.2.2)"))
+ o:value("4.2.2.3:53", translate("Level 3 Public DNS (4.2.2.3)"))
+ o:value("4.2.2.4:53", translate("Level 3 Public DNS (4.2.2.4)"))
+ o:value("1.1.1.1:53", translate("Cloudflare DNS (1.1.1.1)"))
+ o:depends("pdnsd_enable", "6")
+ o.description = translate(
+ "" ..
+ "- " .. translate("Custom DNS Server format as IP:PORT (default: 8.8.4.4:53)") .. "
" ..
+ "- " .. translate("Muitiple DNS server can saperate with ','") .. "
" ..
+ "
"
+ )
+
+ o = s:option(ListValue, "chinadns_ng_proto", translate("ChinaDNS-NG query protocol"))
+ o:value("none", translate("UDP/TCP upstream"))
+ o:value("tcp", translate("TCP upstream"))
+ o:value("udp", translate("UDP upstream"))
+ o:value("tls", translate("DoT upstream (Need use wolfssl version)"))
+ o:depends("pdnsd_enable", "6")
+
o = s:option(Value, "chinadns_forward", translate("Domestic DNS Server"))
o:value("", translate("Disable ChinaDNS-NG"))
o:value("wan", translate("Use DNS from WAN"))
@@ -132,6 +257,9 @@ if is_finded("chinadns-ng") then
o:value("1.2.4.8:53", translate("CNNIC SDNS (1.2.4.8)"))
o:depends({pdnsd_enable = "1", run_mode = "router"})
o:depends({pdnsd_enable = "2", run_mode = "router"})
+ o:depends({pdnsd_enable = "3", run_mode = "router"})
+ o:depends({pdnsd_enable = "5", run_mode = "router"})
+ o:depends({pdnsd_enable = "6", run_mode = "router"})
o.description = translate("Custom DNS Server format as IP:PORT (default: disabled)")
o.validate = function(self, value, section)
if (section and value) then
diff --git a/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua b/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua
index 956f8959d..4d4367a7d 100644
--- a/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua
+++ b/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua
@@ -3,6 +3,10 @@ require "nixio.fs"
require "luci.sys"
local m, s, o
+local function is_finded(e)
+ return luci.sys.exec(string.format('type -t -p "%s" 2>/dev/null', e)) ~= ""
+end
+
m = Map("shadowsocksr")
s = m:section(TypedSection, "access_control")
@@ -141,6 +145,24 @@ o.remove = function(self, section, value)
nixio.fs.writefile(netflixconf, "")
end
+if is_finded("dnsproxy") then
+ s:tab("dnsproxy", translate("Dnsproxy Parse List"))
+ local dnsproxyconf = "/etc/ssrplus/dnsproxy_dns.list"
+ o = s:taboption("dnsproxy", TextValue, "dnsproxyconf", "", "" .. translate("Specifically for edit dnsproxy DNS parse files.") .. "")
+ o.rows = 13
+ o.wrap = "off"
+ o.rmempty = true
+ o.cfgvalue = function(self, section)
+ return nixio.fs.readfile(dnsproxyconf) or " "
+ end
+ o.write = function(self, section, value)
+ nixio.fs.writefile(dnsproxyconf, value:gsub("\r\n", "\n"))
+ end
+ o.remove = function(self, section, value)
+ nixio.fs.writefile(dnsproxyconf, "")
+ end
+end
+
if luci.sys.call('[ -f "/www/luci-static/resources/uci.js" ]') == 0 then
m.apply_on_parse = true
function m.on_apply(self)
diff --git a/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua b/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua
index f9ac268ea..145c400f8 100644
--- a/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua
+++ b/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua
@@ -86,7 +86,7 @@ o.rmempty = false
o = s:option(ListValue, "type", translate("Server Type"))
o:value("socks5", translate("Socks5"))
if nixio.fs.access("/usr/bin/ssserver") or nixio.fs.access("/usr/bin/ss-server") then
- o:value("ss", translate("Shadowsocks"))
+ o:value("ss", translate("ShadowSocks"))
end
if nixio.fs.access("/usr/bin/ssr-server") then
o:value("ssr", translate("ShadowsocksR"))
@@ -143,7 +143,7 @@ end
o.rmempty = false
o:depends("type", "ssr")
-o = s:option(Value, "obfs_param", translate("Obfs param(optional)"))
+o = s:option(Value, "obfs_param", translate("Obfs param (optional)"))
o:depends("type", "ssr")
o = s:option(Flag, "fast_open", translate("TCP Fast Open"))
diff --git a/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server.lua b/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server.lua
index 6ef44c080..db3160ab4 100644
--- a/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server.lua
+++ b/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server.lua
@@ -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"))
diff --git a/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua b/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua
index a7166abdb..ac1bbc6f2 100644
--- a/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua
+++ b/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua
@@ -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("%s", 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
@@ -67,6 +120,11 @@ o.write = function()
luci.http.redirect(luci.dispatcher.build_url("admin", "services", "shadowsocksr", "servers"))
end
+o = s:option(Flag, "allow_insecure", translate("Allow subscribe Insecure nodes By default"))
+o.rmempty = false
+o.description = translate("Subscribe nodes allows insecure connection as TLS client (insecure)")
+o.default = "0"
+
o = s:option(Flag, "switch", translate("Subscribe Default Auto-Switch"))
o.rmempty = false
o.description = translate("Subscribe new add server default Auto-Switch on")
diff --git a/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua b/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua
index 83a88a2a4..9f0eff11e 100644
--- a/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua
+++ b/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua
@@ -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 = [[]]
style_blue = [[]]
@@ -92,7 +92,11 @@ if Process_list:find("ssr.server") then
server_run = 1
end
-if Process_list:find("ssrplus/bin/dns2tcp") or (Process_list:find("ssrplus.dns") and Process_list:find("dns2socks.127.0.0.1.*127.0.0.1.5335")) then
+if Process_list:find("ssrplus/bin/dns2tcp") or
+ Process_list:find("ssrplus/bin/mosdns") or
+ Process_list:find("dnsproxy.*127.0.0.1.*5335") or
+ Process_list:find("chinadns.*127.0.0.1.*5335") or
+ (Process_list:find("ssrplus.dns") and Process_list:find("dns2socks.*127.0.0.1.*127.0.0.1.5335")) then
pdnsd_run = 1
end
diff --git a/luci-app-ssr-plus/luasrc/view/shadowsocksr/server_list.htm b/luci-app-ssr-plus/luasrc/view/shadowsocksr/server_list.htm
index 259cb7fff..ed7148f8f 100644
--- a/luci-app-ssr-plus/luasrc/view/shadowsocksr/server_list.htm
+++ b/luci-app-ssr-plus/luasrc/view/shadowsocksr/server_list.htm
@@ -4,7 +4,7 @@
-%>
diff --git a/luci-app-ssr-plus/luasrc/view/shadowsocksr/ssrurl.htm b/luci-app-ssr-plus/luasrc/view/shadowsocksr/ssrurl.htm
index b8f9db40f..04f28960c 100644
--- a/luci-app-ssr-plus/luasrc/view/shadowsocksr/ssrurl.htm
+++ b/luci-app-ssr-plus/luasrc/view/shadowsocksr/ssrurl.htm
@@ -1,6 +1,12 @@
<%+cbi/valueheader%>
+<%
+local map = self.map
+local ss_type = map:get("@server_subscribe[0]", "ss_type")
+-%>