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( + "" + ) + 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( + "" + ) + + 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( + "" + ) + 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( + "" + ) + + 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") +-%>