diff --git a/dns2tcp/Makefile b/dns2tcp/Makefile index 6926858f..e241421b 100644 --- a/dns2tcp/Makefile +++ b/dns2tcp/Makefile @@ -6,7 +6,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=dns2tcp PKG_VERSION:=1.1.2 -PKG_RELEASE:=2 +PKG_RELEASE:=3 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz PKG_SOURCE_URL:=https://codeload.github.com/zfl9/dns2tcp/tar.gz/v$(PKG_VERSION)? diff --git a/dns2tcp/patches/0001-add-A-option-to-filter-AAAA-answers.patch b/dns2tcp/patches/0001-add-A-option-to-filter-AAAA-answers.patch deleted file mode 100644 index a11ba100..00000000 --- a/dns2tcp/patches/0001-add-A-option-to-filter-AAAA-answers.patch +++ /dev/null @@ -1,210 +0,0 @@ -diff --git a/dns2tcp.c b/dns2tcp.c -index b289598..542f839 100644 ---- a/dns2tcp.c -+++ b/dns2tcp.c -@@ -35,6 +35,10 @@ - #define PORTSTRLEN 6 /* "65535" (include \0) */ - - #define DNS_MSGSZ 1472 /* mtu:1500 - iphdr:20 - udphdr:8 */ -+#define DNS_HDRLEN 12 -+ -+#define DNS_TYPE_A 1 -+#define DNS_TYPE_AAAA 28 - - /* ======================== helper ======================== */ - -@@ -128,6 +132,14 @@ typedef struct { - union skaddr srcaddr; - } ctx_t; - -+typedef struct { -+ size_t start; -+ size_t end; -+ uint16_t type; -+ uint8_t section; -+ bool drop; -+} dns_rr_t; -+ - /* ======================== global-vars ======================== */ - - enum { -@@ -135,6 +147,7 @@ enum { - FLAG_REUSE_PORT = 1 << 1, /* udp listen */ - FLAG_VERBOSE = 1 << 2, /* logging */ - FLAG_LOCAL_ADDR = 1 << 3, /* tcp local addr */ -+ FLAG_FILTER_AAAA = 1 << 4, /* strip all AAAA records from dns response */ - }; - - #define has_flag(flag) (g_flags & (flag)) -@@ -166,6 +179,126 @@ static void tcp_connect_cb(evloop_t *evloop, evio_t *watcher, int events); - static void tcp_sendmsg_cb(evloop_t *evloop, evio_t *watcher, int events); - static void tcp_recvmsg_cb(evloop_t *evloop, evio_t *watcher, int events); - -+static uint16_t read_be16(const void *ptr) { -+ const uint8_t *bytes = ptr; -+ return ((uint16_t)bytes[0] << 8) | bytes[1]; -+} -+ -+static void write_be16(void *ptr, uint16_t value) { -+ uint8_t *bytes = ptr; -+ bytes[0] = value >> 8; -+ bytes[1] = value & 0xff; -+} -+ -+static bool dns_skip_name(const uint8_t *msg, size_t msglen, size_t offset, size_t *next_offset) { -+ while (offset < msglen) { -+ uint8_t len = msg[offset]; -+ if (len == 0) { -+ *next_offset = offset + 1; -+ return true; -+ } -+ if ((len & 0xc0) == 0xc0) { -+ if (offset + 1 >= msglen) -+ return false; -+ *next_offset = offset + 2; -+ return true; -+ } -+ if ((len & 0xc0) || offset + 1 + len > msglen) -+ return false; -+ offset += 1 + len; -+ } -+ -+ return false; -+} -+ -+static size_t filter_aaaa_records(uint8_t *msg, size_t msglen) { -+ if (!has_flag(FLAG_FILTER_AAAA) || msglen < DNS_HDRLEN) -+ return msglen; -+ -+ uint16_t qdcount = read_be16(msg + 4); -+ uint16_t counts[] = { -+ read_be16(msg + 6), -+ read_be16(msg + 8), -+ read_be16(msg + 10), -+ }; -+ uint32_t rrcount = counts[0] + counts[1] + counts[2]; -+ -+ if (rrcount == 0 || qdcount > msglen / 5 || rrcount > msglen / 11) -+ return msglen; -+ -+ size_t offset = DNS_HDRLEN; -+ for (uint16_t i = 0; i < qdcount; i++) { -+ if (!dns_skip_name(msg, msglen, offset, &offset) || offset + 4 > msglen) -+ return msglen; -+ offset += 4; -+ } -+ -+ size_t rr_start = offset; -+ dns_rr_t *rrs = calloc(rrcount, sizeof(*rrs)); -+ if (!rrs) -+ return msglen; -+ -+ uint32_t rridx = 0; -+ for (uint8_t section = 0; section < 3; section++) { -+ for (uint16_t i = 0; i < counts[section]; i++) { -+ dns_rr_t *rr = &rrs[rridx++]; -+ rr->start = offset; -+ rr->section = section; -+ -+ if (!dns_skip_name(msg, msglen, offset, &offset) || offset + 10 > msglen) -+ goto out; -+ -+ rr->type = read_be16(msg + offset); -+ uint16_t rdlen = read_be16(msg + offset + 8); -+ rr->end = offset + 10 + rdlen; -+ if (rr->end > msglen) -+ goto out; -+ -+ offset = rr->end; -+ } -+ } -+ -+ size_t rest_start = offset; -+ bool changed = false; -+ uint16_t keep_counts[] = { counts[0], counts[1], counts[2] }; -+ -+ for (uint32_t i = 0; i < rrcount; i++) { -+ if (rrs[i].type == DNS_TYPE_AAAA) { -+ rrs[i].drop = true; -+ keep_counts[rrs[i].section]--; -+ changed = true; -+ } -+ } -+ -+ if (changed) { -+ size_t write_offset = rr_start; -+ -+ for (uint32_t i = 0; i < rrcount; i++) { -+ if (rrs[i].drop) -+ continue; -+ -+ size_t rrlen = rrs[i].end - rrs[i].start; -+ if (write_offset != rrs[i].start) -+ memmove(msg + write_offset, msg + rrs[i].start, rrlen); -+ write_offset += rrlen; -+ } -+ -+ if (write_offset != rest_start) -+ memmove(msg + write_offset, msg + rest_start, msglen - rest_start); -+ -+ msglen = write_offset + (msglen - rest_start); -+ write_be16(msg + 6, keep_counts[0]); -+ write_be16(msg + 8, keep_counts[1]); -+ write_be16(msg + 10, keep_counts[2]); -+ log_verbose("filter AAAA records, answer:%hu -> %hu, authority:%hu -> %hu, additional:%hu -> %hu", -+ counts[0], keep_counts[0], counts[1], keep_counts[1], counts[2], keep_counts[2]); -+ } -+ -+out: -+ free(rrs); -+ return msglen; -+} -+ - static void print_help(void) { - printf("usage: dns2tcp <-L listen> <-R remote> [options...]\n" - " -L udp listen address, port default to 53\n" -@@ -174,6 +307,7 @@ static void print_help(void) { - " -s set TCP_SYNCNT option for tcp socket\n" - " -6 set IPV6_V6ONLY option for udp socket\n" - " -r set SO_REUSEPORT option for udp socket\n" -+ " -A strip all AAAA records from dns response\n" - " -v print verbose log, used for debugging\n" - " -V print version number of dns2tcp and exit\n" - " -h print help information of dns2tcp and exit\n" -@@ -257,7 +391,7 @@ static void parse_opt(int argc, char *argv[]) { - - opterr = 0; - int shortopt; -- const char *optstr = "L:R:l:s:6rafvVh"; -+ const char *optstr = "L:R:l:s:6rAafvVh"; - while ((shortopt = getopt(argc, argv, optstr)) != -1) { - switch (shortopt) { - case 'L': -@@ -295,6 +429,9 @@ static void parse_opt(int argc, char *argv[]) { - case 'r': - add_flag(FLAG_REUSE_PORT); - break; -+ case 'A': -+ add_flag(FLAG_FILTER_AAAA); -+ break; - case 'a': - /* nop */ - break; -@@ -399,6 +536,7 @@ int main(int argc, char *argv[]) { - if (g_syn_cnt) log_info("enable TCP_SYNCNT:%hhu sockopt", g_syn_cnt); - if (has_flag(FLAG_IPV6_V6ONLY)) log_info("enable IPV6_V6ONLY sockopt"); - if (has_flag(FLAG_REUSE_PORT)) log_info("enable SO_REUSEPORT sockopt"); -+ if (has_flag(FLAG_FILTER_AAAA)) log_info("enable AAAA record filter"); - log_verbose("print the verbose log"); - - g_listen_fd = create_socket(skaddr_family(&g_listen_skaddr), SOCK_DGRAM); -@@ -532,6 +670,9 @@ static void tcp_recvmsg_cb(evloop_t *evloop, evio_t *watcher, int events __unuse - uint16_t msglen; - if (ctx->nbytes < 2 || ctx->nbytes < 2 + (msglen = ntohs(*(uint16_t *)buffer))) return; - -+ msglen = filter_aaaa_records((uint8_t *)buffer + 2, msglen); -+ *(uint16_t *)buffer = htons(msglen); -+ - ssize_t nsend = sendto(g_listen_fd, buffer + 2, msglen, 0, &ctx->srcaddr.sa, skaddr_len(&ctx->srcaddr)); - if (nsend < 0 || verbose) { - char ip[IP6STRLEN]; diff --git a/luci-app-ssr-plus/Makefile b/luci-app-ssr-plus/Makefile index 3ee704b4..2479f41d 100644 --- a/luci-app-ssr-plus/Makefile +++ b/luci-app-ssr-plus/Makefile @@ -3,51 +3,77 @@ include $(TOPDIR)/rules.mk LUCI_TITLE:=luci-app-ssr-plus LUCI_PKGARCH:=all PKG_NAME:=luci-app-ssr-plus -PKG_VERSION:=193 -PKG_RELEASE:=16 +PKG_VERSION:=190 +PKG_RELEASE:=17 PKG_CONFIG_DEPENDS:= \ CONFIG_PACKAGE_$(PKG_NAME)_Iptables_Transparent_Proxy \ CONFIG_PACKAGE_$(PKG_NAME)_Nftables_Transparent_Proxy \ 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_Http_Proxy \ - CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_Mihomo \ + 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_IPT2Socks \ CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_Kcptun \ CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_NaiveProxy \ + CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_Redsocks2 \ CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_Shadowsocks_NONE_Client \ + CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_Shadowsocks_Libev_Client \ + CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_Shadowsocks_Rust_Client \ CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_Shadowsocks_NONE_Server \ + CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_Shadowsocks_Libev_Server \ CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_Shadowsocks_Rust_Server \ CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_Shadowsocks_Simple_Obfs \ CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_Shadowsocks_V2ray_Plugin \ CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_ShadowsocksR_Libev_Client \ - CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_ShadowsocksR_Libev_Server + 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/Clash LuCI interface +LUCI_TITLE:=SS/SSR/V2Ray/Trojan/NaiveProxy/Tuic/ShadowTLS/Hysteria/Socks5/Tun LuCI interface LUCI_PKGARCH:=all LUCI_DEPENDS:= \ - +libuci-lua +lua +luci-compat +coreutils +coreutils-base64 +dns2tcp +dnsmasq-full \ - +jq +ip-full +lua-neturl +libuci-lua +microsocks +ipt2socks +lyaml \ - +resolveip +curl +nping +unzip +xz-utils \ + +coreutils +coreutils-base64 +dns2tcp +dnsmasq-full \ + +jq +ip-full +lua +lua-neturl +libuci-lua +microsocks \ + +tcping +resolveip +shadowsocksr-libev-ssr-check +curl +nping \ + +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_IPT2Socks:ipt2socks \ +PACKAGE_$(PKG_NAME)_INCLUDE_Kcptun:kcptun-client \ +PACKAGE_$(PKG_NAME)_INCLUDE_NaiveProxy:naiveproxy \ + +PACKAGE_$(PKG_NAME)_INCLUDE_Redsocks2:redsocks2 \ + +PACKAGE_$(PKG_NAME)_INCLUDE_Shadowsocks_Libev_Client:shadowsocks-libev-ss-local \ + +PACKAGE_$(PKG_NAME)_INCLUDE_Shadowsocks_Libev_Client:shadowsocks-libev-ss-redir \ + +PACKAGE_$(PKG_NAME)_INCLUDE_Shadowsocks_Libev_Server:shadowsocks-libev-ss-server \ +PACKAGE_$(PKG_NAME)_INCLUDE_Shadowsocks_Rust_Client:shadowsocks-rust-sslocal \ +PACKAGE_$(PKG_NAME)_INCLUDE_Shadowsocks_Rust_Server:shadowsocks-rust-ssserver \ +PACKAGE_$(PKG_NAME)_INCLUDE_Shadowsocks_Simple_Obfs:simple-obfs-client \ +PACKAGE_$(PKG_NAME)_INCLUDE_Shadowsocks_V2ray_Plugin:v2ray-plugin \ +PACKAGE_$(PKG_NAME)_INCLUDE_ShadowsocksR_Libev_Client:shadowsocksr-libev-ssr-local \ +PACKAGE_$(PKG_NAME)_INCLUDE_ShadowsocksR_Libev_Client:shadowsocksr-libev-ssr-redir \ - +PACKAGE_$(PKG_NAME)_INCLUDE_ShadowsocksR_Libev_Server:shadowsocksr-libev-ssr-server + +PACKAGE_$(PKG_NAME)_INCLUDE_ShadowsocksR_Libev_Server:shadowsocksr-libev-ssr-server \ + +PACKAGE_$(PKG_NAME)_INCLUDE_Trojan:trojan define Package/$(PKG_NAME)/config +select PACKAGE_luci-lua-runtime if PACKAGE_$(PKG_NAME) choice prompt "Transparent Proxy Backend" @@ -77,24 +103,37 @@ endchoice choice prompt "Shadowsocks Client Selection" - default PACKAGE_$(PKG_NAME)_INCLUDE_Shadowsocks_NONE_Client + default PACKAGE_$(PKG_NAME)_INCLUDE_Shadowsocks_Rust_Client if aarch64 || x86_64 + default PACKAGE_$(PKG_NAME)_INCLUDE_Shadowsocks_Libev_Client config PACKAGE_$(PKG_NAME)_INCLUDE_Shadowsocks_NONE_Client bool "None" + config PACKAGE_$(PKG_NAME)_INCLUDE_Shadowsocks_Libev_Client + bool "Shadowsocks-libev" + config PACKAGE_$(PKG_NAME)_INCLUDE_Shadowsocks_Rust_Client - bool "Shadowsocks Rust" + bool "Shadowsocks-rust" + depends on aarch64||arm||i386||mips||mipsel||x86_64 + depends on !(TARGET_x86_geode||TARGET_x86_legacy) endchoice choice prompt "Shadowsocks Server Selection" + default PACKAGE_$(PKG_NAME)_INCLUDE_Shadowsocks_Rust_Server if aarch64 + default PACKAGE_$(PKG_NAME)_INCLUDE_Shadowsocks_Libev_Server if i386||x86_64||arm default PACKAGE_$(PKG_NAME)_INCLUDE_Shadowsocks_NONE_Server config PACKAGE_$(PKG_NAME)_INCLUDE_Shadowsocks_NONE_Server bool "None" + config PACKAGE_$(PKG_NAME)_INCLUDE_Shadowsocks_Libev_Server + bool "Shadowsocks-libev" + config PACKAGE_$(PKG_NAME)_INCLUDE_Shadowsocks_Rust_Server - bool "Shadowsocks Rust" + bool "Shadowsocks-rust" + depends on aarch64||arm||i386||mips||mipsel||x86_64 + depends on !(TARGET_x86_geode||TARGET_x86_legacy) endchoice choice @@ -105,35 +144,45 @@ choice config PACKAGE_$(PKG_NAME)_INCLUDE_NONE_V2RAY bool "None" + config PACKAGE_$(PKG_NAME)_INCLUDE_V2ray + bool "V2ray-core" + config PACKAGE_$(PKG_NAME)_INCLUDE_Xray bool "Xray-core" - select PACKAGE_xray-core endchoice config PACKAGE_$(PKG_NAME)_INCLUDE_ChinaDNS_NG bool "Include ChinaDNS-NG" - default y if aarch64||arm||i386||x86_64 + 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 y if aarch64||i386||x86_64 + +config PACKAGE_$(PKG_NAME)_INCLUDE_Hysteria + bool "Include Hysteria" + select PACKAGE_$(PKG_NAME)_INCLUDE_ChinaDNS_NG default n -config PACKAGE_$(PKG_NAME)_INCLUDE_Http_Proxy - bool "Include HTTP(S) Proxy Server" - select PACKAGE_3proxy - default y if (aarch64||arm||i386||loongarch64||riscv64||x86_64) - -config PACKAGE_$(PKG_NAME)_INCLUDE_Mihomo - bool "Include Mihomo (Clash Support)" - select PACKAGE_mihomo - depends on aarch64||arm||i386||loongarch64||riscv64||x86_64 - default y if aarch64||arm||i386||loongarch64||riscv64||x86_64 - -config PACKAGE_$(PKG_NAME)_INCLUDE_GeoData - bool "Include GeoData (GeoIP and GeoSite)" - select PACKAGE_v2ray-geoip - select PACKAGE_v2ray-geosite - default y if i386||x86_64 +config PACKAGE_$(PKG_NAME)_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" @@ -143,6 +192,10 @@ config PACKAGE_$(PKG_NAME)_INCLUDE_Shadow_TLS depends on !(TARGET_x86_geode||TARGET_x86_legacy) default n +config PACKAGE_$(PKG_NAME)_INCLUDE_IPT2Socks + bool "Include IPT2Socks" + default n + config PACKAGE_$(PKG_NAME)_INCLUDE_Kcptun bool "Include Kcptun" default n @@ -152,9 +205,13 @@ config PACKAGE_$(PKG_NAME)_INCLUDE_NaiveProxy depends on !(arc||armeb||mips||mips64||powerpc||TARGET_gemini) default n +config PACKAGE_$(PKG_NAME)_INCLUDE_Redsocks2 + bool "Include Redsocks2" + default n + config PACKAGE_$(PKG_NAME)_INCLUDE_Shadowsocks_Simple_Obfs bool "Include Shadowsocks Simple Obfs Plugin" - default n + default y config PACKAGE_$(PKG_NAME)_INCLUDE_Shadowsocks_V2ray_Plugin bool "Include Shadowsocks V2ray Plugin" @@ -166,6 +223,11 @@ config PACKAGE_$(PKG_NAME)_INCLUDE_ShadowsocksR_Libev_Client config PACKAGE_$(PKG_NAME)_INCLUDE_ShadowsocksR_Libev_Server bool "Include ShadowsocksR Libev Server" + default y if i386||x86_64||arm + +config PACKAGE_$(PKG_NAME)_INCLUDE_Trojan + bool "Include Trojan" + select PACKAGE_$(PKG_NAME)_INCLUDE_IPT2Socks default n endef @@ -178,41 +240,4 @@ endef include $(TOPDIR)/feeds/luci/luci.mk -define Package/$(PKG_NAME)/install - ifneq ($(wildcard ${CURDIR}/luasrc),) - $(INSTALL_DIR) $(1)$(LUCI_LIBRARYDIR) - cp -pR $(PKG_BUILD_DIR)/luasrc/* $(1)$(LUCI_LIBRARYDIR)/ - $(FIND) $(1)$(LUCI_LIBRARYDIR)/ -type f -name '*.luadoc' | $(XARGS) rm - $(if $(CONFIG_LUCI_SRCDIET),$(call SrcDiet,$(1)$(LUCI_LIBRARYDIR)/),true) - $(call SubstituteVersion,$(1)$(LUCI_LIBRARYDIR)/) - endif - ifneq ($(wildcard ${CURDIR}/ucode),) - $(INSTALL_DIR) $(1)$(UCODE_LIBRARYDIR) - cp -pR $(PKG_BUILD_DIR)/ucode/* $(1)$(UCODE_LIBRARYDIR)/ - $(call SubstituteVersion,$(1)$(UCODE_LIBRARYDIR)/) - endif - ifneq ($(wildcard ${CURDIR}/htdocs),) - $(INSTALL_DIR) $(1)$(HTDOCS) - cp -pR $(PKG_BUILD_DIR)/htdocs/* $(1)$(HTDOCS)/ - $(if $(CONFIG_LUCI_JSMIN),$(call JsMin,$(1)$(HTDOCS)/),true) - $(if $(CONFIG_LUCI_CSSTIDY),$(call CssTidy,$(1)$(HTDOCS)/),true) - endif - ifneq ($(wildcard ${CURDIR}/root),) - $(INSTALL_DIR) $(1)/ - cp -pR $(PKG_BUILD_DIR)/root/* $(1)/ - endif - ifneq ($(wildcard ${CURDIR}/src),) - $(call Build/Install/Default) - $(CP) $(PKG_INSTALL_DIR)/* $(1)/ - endif - if [ -d "$(1)/usr/bin" ]; then \ - chmod 0755 "$(1)/usr/bin/ssr-monitor" 2>/dev/null || true; \ - chmod 0755 "$(1)/usr/bin/ssr-rules" 2>/dev/null || true; \ - chmod 0755 "$(1)/usr/bin/ssr-switch" 2>/dev/null || true; \ - fi - if [ -f "$(1)/etc/hotplug.d/iface/99-ssrplus-pppoe" ]; then \ - chmod 0755 "$(1)/etc/hotplug.d/iface/99-ssrplus-pppoe" 2>/dev/null || true; \ - fi -endef - # call BuildPackage - OpenWrt buildroot signature diff --git a/luci-app-ssr-plus/htdocs/luci-static/resources/view/shadowsocksr/Sortable.min.js b/luci-app-ssr-plus/htdocs/luci-static/resources/view/shadowsocksr/Sortable.min.js new file mode 100644 index 00000000..8148b9dd --- /dev/null +++ b/luci-app-ssr-plus/htdocs/luci-static/resources/view/shadowsocksr/Sortable.min.js @@ -0,0 +1,2 @@ +/*! Sortable 1.15.7 - MIT | git://github.com/SortableJS/Sortable.git */ +!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):(t=t||self).Sortable=e()}(this,function(){"use strict";function o(t,e){(null==e||e>t.length)&&(e=t.length);for(var n=0,o=Array(e);n"===e[0]&&(e=e.substring(1)),t))try{if(t.matches)return t.matches(e);if(t.msMatchesSelector)return t.msMatchesSelector(e);if(t.webkitMatchesSelector)return t.webkitMatchesSelector(e)}catch(t){return}}function m(t){return t.host&&t!==document&&t.host.nodeType&&t.host!==t?t.host:t.parentNode}function P(t,e,n,o){if(t){n=n||document;do{if(null!=e&&(">"!==e[0]||t.parentNode===n)&&g(t,e)||o&&t===n)return t}while(t!==n&&(t=m(t)))}return null}var v,b=/\s+/g;function k(t,e,n){var o;t&&e&&(t.classList?t.classList[n?"add":"remove"](e):(o=(" "+t.className+" ").replace(b," ").replace(" "+e+" "," "),t.className=(o+(n?" "+e:"")).replace(b," ")))}function R(t,e,n){var o=t&&t.style;if(o){if(void 0===n)return document.defaultView&&document.defaultView.getComputedStyle?n=document.defaultView.getComputedStyle(t,""):t.currentStyle&&(n=t.currentStyle),void 0===e?n:n[e];o[e=!(e in o||-1!==e.indexOf("webkit"))?"-webkit-"+e:e]=n+("string"==typeof n?"":"px")}}function D(t,e){var n="";if("string"==typeof t)n=t;else do{var o=R(t,"transform")}while(o&&"none"!==o&&(n=o+" "+n),!e&&(t=t.parentNode));var i=window.DOMMatrix||window.WebKitCSSMatrix||window.CSSMatrix||window.MSCSSMatrix;return i&&new i(n)}function E(t,e,n){if(t){var o=t.getElementsByTagName(e),i=0,r=o.length;if(n)for(;i=n.left-e&&i<=n.right+e,e=r>=n.top-e&&r<=n.bottom+e;return o&&e?a=t:void 0}}),a);if(e){var n,o={};for(n in t)t.hasOwnProperty(n)&&(o[n]=t[n]);o.target=o.rootEl=e,o.preventDefault=void 0,o.stopPropagation=void 0,e[K]._onDragOver(o)}}var i,r,a}function jt(t){$&&$.parentNode[K]._isOutsideThisEl(t.target)}function Ht(t,e){if(!t||!t.nodeType||1!==t.nodeType)throw"Sortable: `el` must be an HTMLElement, not ".concat({}.toString.call(t));this.el=t,this.options=e=a({},e),t[K]=this;var n,o,i={group:null,sort:!0,disabled:!1,store:null,handle:null,draggable:/^[uo]l$/i.test(t.nodeName)?">li":">*",swapThreshold:1,invertSwap:!1,invertedSwapThreshold:null,removeCloneOnHide:!0,direction:function(){return Rt(t,this.options)},ghostClass:"sortable-ghost",chosenClass:"sortable-chosen",dragClass:"sortable-drag",ignore:"a, img",filter:null,preventOnFilter:!0,animation:0,easing:null,setData:function(t,e){t.setData("Text",e.textContent)},dropBubble:!1,dragoverBubble:!1,dataIdAttr:"data-id",delay:0,delayOnTouchOnly:!1,touchStartThreshold:(Number.parseInt?Number:window).parseInt(window.devicePixelRatio,10)||1,forceFallback:!1,fallbackClass:"sortable-fallback",fallbackOnBody:!1,fallbackTolerance:0,fallbackOffset:{x:0,y:0},supportPointer:!1!==Ht.supportPointer&&"PointerEvent"in window&&(!u||d),emptyInsertThreshold:5};for(n in G.initializePlugins(this,t,i),i)n in e||(e[n]=i[n]);for(o in Xt(e),this)"_"===o.charAt(0)&&"function"==typeof this[o]&&(this[o]=this[o].bind(this));this.nativeDraggable=!e.forceFallback&&Pt,this.nativeDraggable&&(this.options.touchStartThreshold=1),e.supportPointer?f(t,"pointerdown",this._onTapStart):(f(t,"mousedown",this._onTapStart),f(t,"touchstart",this._onTapStart)),this.nativeDraggable&&(f(t,"dragover",this),f(t,"dragenter",this)),_t.push(this.el),e.store&&e.store.get&&this.sort(e.store.get(this)||[]),a(this,N())}function Lt(t,e,n,o,i,r,a,l){var s,c,u=t[K],d=u.options.onMove;return!window.CustomEvent||y||w?(s=document.createEvent("Event")).initEvent("move",!0,!0):s=new CustomEvent("move",{bubbles:!0,cancelable:!0}),s.to=e,s.from=t,s.dragged=n,s.draggedRect=o,s.related=i||e,s.relatedRect=r||X(e),s.willInsertAfter=l,s.originalEvent=a,t.dispatchEvent(s),c=d?d.call(u,s,a):c}function Kt(t){t.draggable=!1}function Wt(){Ot=!1}function zt(t){return setTimeout(t,0)}function Gt(t){return clearTimeout(t)}Ht.prototype={constructor:Ht,_isOutsideThisEl:function(t){this.el.contains(t)||t===this.el||(bt=null)},_getDirection:function(t,e){return"function"==typeof this.options.direction?this.options.direction.call(this,t,e,$):this.options.direction},_onTapStart:function(e){if(e.cancelable){var n=this,o=this.el,t=this.options,i=t.preventOnFilter,r=e.type,a=e.touches&&e.touches[0]||e.pointerType&&"touch"===e.pointerType&&e,l=(a||e).target,s=e.target.shadowRoot&&(e.path&&e.path[0]||e.composedPath&&e.composedPath()[0])||l,c=t.filter;if(!function(t){Mt.length=0;var e=t.getElementsByTagName("input"),n=e.length;for(;n--;){var o=e[n];o.checked&&Mt.push(o)}}(o),!$&&!(/mousedown|pointerdown/.test(r)&&0!==e.button||t.disabled)&&!s.isContentEditable&&(this.nativeDraggable||!u||!l||"SELECT"!==l.tagName.toUpperCase())&&!((l=P(l,t.draggable,o,!1))&&l.animated||nt===l)){if(rt=j(l),lt=j(l,t.draggable),"function"==typeof c){if(c.call(this,e,l,this))return Z({sortable:n,rootEl:s,name:"filter",targetEl:l,toEl:o,fromEl:o}),q("filter",n,{evt:e}),void(i&&e.preventDefault())}else if(c=c&&c.split(",").some(function(t){if(t=P(s,t.trim(),o,!1))return Z({sortable:n,rootEl:t,name:"filter",targetEl:l,fromEl:o,toEl:o}),q("filter",n,{evt:e}),!0}))return void(i&&e.preventDefault());t.handle&&!P(s,t.handle,o,!1)||this._prepareDragStart(e,a,l)}}},_prepareDragStart:function(t,e,n){var o,i=this,r=i.el,a=i.options,l=r.ownerDocument;n&&!$&&n.parentNode===r&&(o=X(n),tt=r,Q=($=n).parentNode,et=$.nextSibling,nt=n,ct=a.group,dt={target:Ht.dragged=$,clientX:(e||t).clientX,clientY:(e||t).clientY},gt=dt.clientX-o.left,mt=dt.clientY-o.top,this._lastX=(e||t).clientX,this._lastY=(e||t).clientY,$.style["will-change"]="all",o=function(){q("delayEnded",i,{evt:t}),Ht.eventCanceled?i._onDrop():(i._disableDelayedDragEvents(),!c&&i.nativeDraggable&&($.draggable=!0),i._triggerDragStart(t,e),Z({sortable:i,name:"choose",originalEvent:t}),k($,a.chosenClass,!0))},a.ignore.split(",").forEach(function(t){E($,t.trim(),Kt)}),f(l,"dragover",Ft),f(l,"mousemove",Ft),f(l,"touchmove",Ft),a.supportPointer?(f(l,"pointerup",i._onDrop),this.nativeDraggable||f(l,"pointercancel",i._onDrop)):(f(l,"mouseup",i._onDrop),f(l,"touchend",i._onDrop),f(l,"touchcancel",i._onDrop)),c&&this.nativeDraggable&&(this.options.touchStartThreshold=4,$.draggable=!0),q("delayStart",this,{evt:t}),!a.delay||a.delayOnTouchOnly&&!e||this.nativeDraggable&&(w||y)?o():Ht.eventCanceled?this._onDrop():(a.supportPointer?(f(l,"pointerup",i._disableDelayedDrag),f(l,"pointercancel",i._disableDelayedDrag)):(f(l,"mouseup",i._disableDelayedDrag),f(l,"touchend",i._disableDelayedDrag),f(l,"touchcancel",i._disableDelayedDrag)),f(l,"mousemove",i._delayedDragTouchMoveHandler),f(l,"touchmove",i._delayedDragTouchMoveHandler),a.supportPointer&&f(l,"pointermove",i._delayedDragTouchMoveHandler),i._dragStartTimer=setTimeout(o,a.delay)))},_delayedDragTouchMoveHandler:function(t){t=t.touches?t.touches[0]:t;Math.max(Math.abs(t.clientX-this._lastX),Math.abs(t.clientY-this._lastY))>=Math.floor(this.options.touchStartThreshold/(this.nativeDraggable&&window.devicePixelRatio||1))&&this._disableDelayedDrag()},_disableDelayedDrag:function(){$&&Kt($),clearTimeout(this._dragStartTimer),this._disableDelayedDragEvents()},_disableDelayedDragEvents:function(){var t=this.el.ownerDocument;p(t,"mouseup",this._disableDelayedDrag),p(t,"touchend",this._disableDelayedDrag),p(t,"touchcancel",this._disableDelayedDrag),p(t,"pointerup",this._disableDelayedDrag),p(t,"pointercancel",this._disableDelayedDrag),p(t,"mousemove",this._delayedDragTouchMoveHandler),p(t,"touchmove",this._delayedDragTouchMoveHandler),p(t,"pointermove",this._delayedDragTouchMoveHandler)},_triggerDragStart:function(t,e){e=e||"touch"==t.pointerType&&t,!this.nativeDraggable||e?this.options.supportPointer?f(document,"pointermove",this._onTouchMove):f(document,e?"touchmove":"mousemove",this._onTouchMove):(f($,"dragend",this),f(tt,"dragstart",this._onDragStart));try{document.selection?zt(function(){document.selection.empty()}):window.getSelection().removeAllRanges()}catch(t){}},_dragStarted:function(t,e){var n;Et=!1,tt&&$?(q("dragStarted",this,{evt:e}),this.nativeDraggable&&f(document,"dragover",jt),n=this.options,t||k($,n.dragClass,!1),k($,n.ghostClass,!0),Ht.active=this,t&&this._appendGhost(),Z({sortable:this,name:"start",originalEvent:e})):this._nulling()},_emulateDragOver:function(){if(ht){this._lastX=ht.clientX,this._lastY=ht.clientY,Yt();for(var t=document.elementFromPoint(ht.clientX,ht.clientY),e=t;t&&t.shadowRoot&&(t=t.shadowRoot.elementFromPoint(ht.clientX,ht.clientY))!==e;)e=t;if($.parentNode[K]._isOutsideThisEl(t),e)do{if(e[K])if(e[K]._onDragOver({clientX:ht.clientX,clientY:ht.clientY,target:t,rootEl:e})&&!this.options.dragoverBubble)break}while(e=m(t=e));Bt()}},_onTouchMove:function(t){if(dt){var e=this.options,n=e.fallbackTolerance,o=e.fallbackOffset,i=t.touches?t.touches[0]:t,r=J&&D(J,!0),a=J&&r&&r.a,l=J&&r&&r.d,e=Nt&&Dt&&S(Dt),a=(i.clientX-dt.clientX+o.x)/(a||1)+(e?e[0]-xt[0]:0)/(a||1),l=(i.clientY-dt.clientY+o.y)/(l||1)+(e?e[1]-xt[1]:0)/(l||1);if(!Ht.active&&!Et){if(n&&Math.max(Math.abs(i.clientX-this._lastX),Math.abs(i.clientY-this._lastY))E.right+10||S.clientY>x.bottom&&S.clientX>x.left:S.clientY>E.bottom+10||S.clientX>x.right&&S.clientY>x.top)||m.animated)){if(m&&(t=n,e=r,C=X(B((_=this).el,0,_.options,!0)),_=L(_.el,_.options,J),e?t.clientX<_.left-10||t.clientY/dev/null 2>&1") == 0 end -local function sanitize_mac(value) - value = trim(value):upper():gsub("-", ":") - if value:match("^%x%x:%x%x:%x%x:%x%x:%x%x:%x%x$") then - return value - end - return "" -end - -local function normalize_client_ip(value) - value = trim(value) - if value == "" then - return "" - end - if datatypes.cidr4(value) or datatypes.ip4addr(value) then - return value - end - return "" -end - -local function get_clash_client_rule_csv_path(sid) - sid = trim(sid) - if sid == "" then - return nil - end - return string.format("%s/%s.csv", CLASH_RULES_DIR, sid) -end - -local function csv_escape(value) - value = tostring(value or "") - if value:find('[",\n\r]') then - return '"' .. value:gsub('"', '""') .. '"' - end - return value -end - -local function parse_csv_line(line) - local cols = {} - local cur = "" - local in_quote = false - local i = 1 - - while i <= #line do - local ch = line:sub(i, i) - if ch == '"' then - if in_quote and line:sub(i + 1, i + 1) == '"' then - cur = cur .. '"' - i = i + 1 +local function uci_save(cursor, config, commit, apply) + if is_old_uci() then + cursor:save(config) + if commit then + cursor:commit(config) + if apply then + luci.sys.call("/etc/init.d/" .. config .. " reload > /dev/null 2>&1 &") + end + end + else + commit = true + if commit then + if apply then + cursor:commit(config) else - in_quote = not in_quote - end - elseif ch == "," and not in_quote then - cols[#cols + 1] = cur - cur = "" - else - cur = cur .. ch - end - i = i + 1 - end - - cols[#cols + 1] = cur - return cols -end - -local function read_clash_client_rules_csv(sid) - local rules = {} - local csv_path = get_clash_client_rule_csv_path(sid) - if not csv_path or not nixio.fs.access(csv_path) then - return rules - end - - local raw = nixio.fs.readfile(csv_path) - if not raw or raw == "" then - return rules - end - - local first = true - for line in tostring(raw):gsub("\r", ""):gmatch("[^\n]+") do - local text = trim(line) - if text ~= "" then - if first and text:lower() == "enabled,client,policy,remarks,client_mac" then - first = false - else - local cols = parse_csv_line(line) - if #cols >= 4 then - rules[#rules + 1] = { - id = tostring(#rules + 1), - enabled = cols[1] == "1" or tostring(cols[1] or ""):lower() == "true", - ip_addr = trim(cols[2] or ""), - policy_group = trim(cols[3] or ""), - remarks = trim(cols[4] or ""), - client_mac = sanitize_mac(cols[5] or "") - } - end + sh_uci_commit(config) end end end - - return rules end -local function write_clash_client_rules_csv(sid, rows) - local csv_path = get_clash_client_rule_csv_path(sid) - if not csv_path then - return false - end - - nixio.fs.mkdirr(CLASH_RULES_DIR) - local lines = { "enabled,client,policy,remarks,client_mac" } - for _, row in ipairs(rows or {}) do - lines[#lines + 1] = table.concat({ - row.enabled == "1" and "1" or "0", - csv_escape(row.ip_addr or ""), - csv_escape(row.policy_group or ""), - csv_escape(row.remarks or ""), - csv_escape(row.client_mac or "") - }, ",") - end - - return nixio.fs.writefile(csv_path, table.concat(lines, "\n") .. "\n") -end - -local function collect_lan_clients() - local clients = {} - local seen = {} - - luci.sys.net.host_hints(function(mac, ipv4, _, name) - local ip = trim(ipv4) - local norm_mac = sanitize_mac(mac) - if ip ~= "" and not seen[ip] then - seen[ip] = true - clients[#clients + 1] = { - ip = ip, - mac = norm_mac, - name = trim(name) ~= "" and trim(name) or ip - } - end - end) - - table.sort(clients, function(a, b) - return tostring(a.name or a.ip) < tostring(b.name or b.ip) - end) - - return clients -end - -local function read_clash_client_rules(sid) - return read_clash_client_rules_csv(sid) -end - -local function normalize_ping_ms(value, scale) - local num = tonumber(value) - if not num or num <= 0 then - return nil - end - local scaled = scale and (num * scale) or num - if scaled > 0 and scaled < 1 then - return 1 - end - return math.floor(scaled + 0.5) -end - -local function detect_tls_handshake_ms(domain, port, path, resolve_host, server_ip, is_websocket) - if not domain or domain == "" or not port or port <= 0 then - return nil - end - - local final_host = (resolve_host and resolve_host ~= "") and resolve_host or domain - local resolve_arg = "" - if server_ip and server_ip ~= "" and final_host ~= server_ip then - resolve_arg = string.format("--resolve '%s:%d:%s' ", final_host, port, server_ip) - end - - local ws_headers = "" - if is_websocket then - ws_headers = string.format( - "-H %s -H %s -H %s -H %s ", - luci.util.shellquote("Connection: Upgrade"), - luci.util.shellquote("Upgrade: websocket"), - luci.util.shellquote("Sec-WebSocket-Key: SGVsbG8sIHdvcmxkIQ=="), - luci.util.shellquote("Sec-WebSocket-Version: 13") - ) - end - - local host_header = (final_host and final_host ~= "") and ("-H " .. luci.util.shellquote("Host: " .. final_host) .. " ") or "" - local url = string.format("https://%s:%d%s", final_host, port, path or "") - local cmd = string.format( - "curl --http1.1 -m 3 -ksS -o /dev/null %s%s%s -w 'time_connect=%%{time_connect}\\ntime_appconnect=%%{time_appconnect}\\nhttp_code=%%{http_code}' '%s' 2>/dev/null", - resolve_arg, host_header, ws_headers, url - ) - local result = luci.sys.exec(cmd) or "" - local appconnect = tonumber(result:match("time_appconnect=([0-9.]+)")) - if appconnect and appconnect > 0 then - return normalize_ping_ms(appconnect, 1000) - end - local connect = tonumber(result:match("time_connect=([0-9.]+)")) - if connect and connect > 0 then - return normalize_ping_ms(connect, 1000) - end - return nil -end - -local function urlencode(str) - if not str then return "" end - return tostring(str):gsub("[^%w%-_%.~]", function(c) - return string.format("%%%02X", string.byte(c)) - end) -end - -local function is_ipv6_address(addr) - addr = tostring(addr or "") - return addr ~= "" and addr:find(":", 1, true) ~= nil -end - -local function is_local_target(addr) - addr = tostring(addr or ""):lower() - if addr == "" then - return false - end - - if addr == "localhost" or addr == "::1" or addr:match("%.local$") then - return true - end - - if is_ipv6_address(addr) then - return addr:match("^fe[89ab]") ~= nil or addr:match("^fc") ~= nil or addr:match("^fd") ~= nil - end - - local o1, o2 = addr:match("^(%d+)%.(%d+)%.") - o1 = tonumber(o1) - o2 = tonumber(o2) - if not o1 or not o2 then - return false - end - - return o1 == 10 - or o1 == 127 - or (o1 == 169 and o2 == 254) - or (o1 == 172 and o2 >= 16 and o2 <= 31) - or (o1 == 192 and o2 == 168) -end - -local function detect_tcp_connect_ms(domain, port) - if not domain or domain == "" or not port or port <= 0 then - return nil - end - - local ip_version_arg = is_ipv6_address(domain) and "-6 " or "" - local cmd = string.format( - "nping %s--tcp-connect -q -c 1 -p %d %s 2>/dev/null", - ip_version_arg, - port, - luci.util.shellquote(domain) - ) - local result = luci.sys.exec(cmd) or "" - local success = tonumber(result:match("Successful connections:%s*([0-9]+)")) - if success and success > 0 then - local avg_rtt = tonumber(result:match("Avg rtt:%s*([0-9.]+)ms")) - if avg_rtt and avg_rtt > 0 and avg_rtt < 1 and not is_local_target(domain) then - return nil - end - return normalize_ping_ms(avg_rtt) - end - - return nil -end - -local function get_clash_secret(sid) - return sid .. "_ssrplus_clash" -end - -local function get_clash_cache_file(sid) - return "/etc/ssrplus/clash/" .. sid .. ".yaml" -end - -local function get_clash_state_file(sid) - return "/etc/ssrplus/clash/" .. sid .. ".cache.db" -end - -local function clash_process_running() - return luci.sys.call("(busybox ps -w 2>/dev/null || busybox ps) | grep ssr-retcp | grep -v grep >/dev/null") == 0 -end - -local function global_client_running() - local process_list = luci.sys.exec("busybox ps -w 2>/dev/null || busybox ps") - local global_server = uci:get_first("shadowsocksr", "global", "global_server", "nil") - local global_type = global_server ~= "nil" and (uci:get("shadowsocksr", global_server, "type") or "") or "" - - if process_list:find("tcp.only.ssr.retcp") - or process_list:find("tcp.udp.ssr.retcp") - or process_list:find("local.ssr.retcp") - or process_list:find("local.udp.ssr.retcp") then - return true - end - - if (global_type == "clash" or global_type == "tuic" or global_type == "ss") - and process_list:find("ssr%-retcp") then - return true - end - - if (global_type == "clash" or global_type == "tuic" or global_type == "ss") - and process_list:find("mihomo") - and (process_list:find("/clash%-") or process_list:find("/tuic%-") or process_list:find("/ss%-")) then - return true - end - - if global_type == "socks5" - and process_list:find("ipt2socks") - and (process_list:find("%-T") or process_list:find("%-%-tcp%-only")) then - return true - end - - return false -end - -local function get_active_node_runtime(sid) - if not sid or sid == "" or sid == "nil" or uci:get("shadowsocksr", sid) ~= "servers" then - return nil, nil - end - - local stype = (uci:get("shadowsocksr", sid, "type") or ""):lower() - local proto = (uci:get("shadowsocksr", sid, "v2ray_protocol") or ""):lower() - local backend - local protocol - - if stype == "ss" then - backend = translate("Mihomo") - protocol = translate("Shadowsocks") - elseif stype == "clash" then - backend = translate("Mihomo") - protocol = translate("Clash") - elseif stype == "tuic" then - backend = translate("Mihomo") - protocol = translate("TUIC") - elseif stype == "ssr" then - backend = translate("ShadowsocksR") - elseif stype == "ss-rust" then - backend = translate("Shadowsocks-rust") - elseif stype == "v2ray" then - local proto_map = { - vmess = "VMess", - vless = "VLESS", - trojan = "Trojan", - socks = "SOCKS5", - hysteria2 = "Hysteria2", - shadowsocks = "Shadowsocks", - http = "HTTP" - } - backend = translate("Xray") - if proto_map[proto] then - protocol = translate(proto_map[proto]) - end - elseif stype == "trojan" then - backend = translate("Trojan") - elseif stype == "naiveproxy" then - backend = translate("NaiveProxy") - elseif stype == "socks5" then - backend = translate("SOCKS5") - elseif stype == "shadowtls" then - backend = translate("ShadowTLS") - elseif stype == "hysteria2" then - backend = translate("Hysteria2") - end - - if not backend or backend == "" then - backend = trim(stype) - end - - return backend, protocol -end - -local function get_running_status_text() - local sid = uci:get_first("shadowsocksr", "global", "global_server", "nil") - local backend, protocol = get_active_node_runtime(sid) - - if backend and backend ~= "" and protocol and protocol ~= "" and backend ~= protocol then - return string.format(translate("RUNNING in %s (%s) Mode"), backend, protocol) - end - - if backend and backend ~= "" then - return string.format(translate("RUNNING in %s Mode"), backend) - end - - return translate("RUNNING") -end - -local function is_active_clash_node(sid) - if not sid then return false end - if uci:get("shadowsocksr", sid) ~= "servers" then return false end - if uci:get("shadowsocksr", sid, "type") ~= "clash" then return false end - if uci:get_first("shadowsocksr", "global", "global_server") ~= sid then return false end - return clash_process_running() -end - -local function resolve_active_clash_sid(sid) - if is_active_clash_node(sid) then - return sid - end - - local current_sid = uci:get_first("shadowsocksr", "global", "global_server") - if is_active_clash_node(current_sid) then - return current_sid - end - - return nil -end - -local function clash_api_request(sid, method, path, body) - sid = resolve_active_clash_sid(sid) - if not sid then - return nil - end - local secret = get_clash_secret(sid) - local cmd = string.format( - "curl -sL -m 5 --retry 1 -w '\n__CURL_STATUS__:%%{http_code}' -H %s -H %s -X %s http://127.0.0.1:%s%s %s", - luci.util.shellquote("Content-Type: application/json"), - luci.util.shellquote("Authorization: Bearer " .. secret), - method, - CLASH_API_PORT, - path, - body and ("-d " .. luci.util.shellquote(body)) or "" - ) - local output = luci.sys.exec(cmd) - if not output or output == "" then - return nil - end - local body_output = output:gsub("\n__CURL_STATUS__:%d%d%d%s*$", "") - local code = output:match("__CURL_STATUS__:(%d%d%d)") - return { - code = tonumber(code), - body = body_output - } -end - -local function use_fw4_backend() - return luci.sys.call("command -v fw4 >/dev/null") == 0 -end - -local function parse_clash_groups(raw) - local info = json.parse(raw or "") - local proxies = info and info.proxies or nil - local groups = {} - if type(proxies) ~= "table" then - return groups - end - for name, value in pairs(proxies) do - if type(value) == "table" and type(value.all) == "table" and #value.all > 0 then - groups[#groups + 1] = { - name = name, - type = value.type or "", - now = value.now or "", - all = value.all - } +local function url(...) + local url = string.format("admin/services/%s", "shadowsocksr") + local args = { ... } + for i, v in ipairs(args) do + if v and v ~= "" then + url = url .. "/" .. v end end - table.sort(groups, function(a, b) return tostring(a.name) < tostring(b.name) end) - return groups -end - -local function parse_kv_output(raw) - local data = {} - for line in tostring(raw or ""):gmatch("[^\r\n]+") do - local key, value = line:match("^([%w_]+)=(.*)$") - if key then - data[key] = value - end - end - return data -end - -local function with_detect_cache_lock(fn) - for _ = 1, 40 do - if nixio.fs.mkdir(SERVER_DETECT_LOCK) then - local ok, ret = pcall(fn) - nixio.fs.rmdir(SERVER_DETECT_LOCK) - if ok then - return ret - end - return nil - end - nixio.nanosleep(0, 50000000) - end - return nil -end - -local function load_detect_cache() - local raw = nixio.fs.readfile(SERVER_DETECT_CACHE) - if not raw or raw == "" then - return {} - end - local parsed = json.parse(raw) - return type(parsed) == "table" and parsed or {} -end - -local function save_detect_cache_entry(sid, data) - if not sid or sid == "" then - return - end - with_detect_cache_lock(function() - local cache = load_detect_cache() - cache[sid] = data - nixio.fs.writefile(SERVER_DETECT_CACHE, json.stringify(cache)) - end) -end - -local function read_component_state(component, action) - if not SUPPORTED_COMPONENTS[component] then - return nil, 400, "unsupported_component" - end - - local mirror = luci.http.formvalue("mirror") or "" - local cmd = string.format( - "COMPONENT_MIRROR=%s /bin/sh %s %s 2>/dev/null", - luci.util.shellquote(mirror), - luci.util.shellquote(COMPONENT_HELPER), - luci.util.shellquote(component .. "_" .. action) - ) - return parse_kv_output(luci.sys.exec(cmd)) -end - -local function read_geo_state(component, action) - if not SUPPORTED_GEO_COMPONENTS[component] then - return nil, 400, "unsupported_component" - end - - local mirror = luci.http.formvalue("mirror") or "" - local cmd = string.format( - "COMPONENT_MIRROR=%s /bin/sh %s %s 2>/dev/null", - luci.util.shellquote(mirror), - luci.util.shellquote(COMPONENT_HELPER), - luci.util.shellquote(component .. "_" .. action) - ) - return parse_kv_output(luci.sys.exec(cmd)) -end - -local function write_component_json(data) - luci.http.prepare_content("application/json") - luci.http.write_json({ - component = data.component or "xray", - installed = data.installed == "1", - current_version = data.current_version or "", - latest_version = data.latest_version or "", - previous_version = data.previous_version or "", - arch = data.arch or "", - asset = data.asset or "", - can_upgrade = data.can_upgrade == "1", - success = data.success == "1", - error = data.error or "", - message = data.message or "" - }) -end - -local function write_geo_json(data) - luci.http.prepare_content("application/json") - luci.http.write_json({ - component = data.component or "country_mmdb", - installed = data.installed == "1", - current_version = data.current_version or "", - current_version_extra = data.current_version_extra or "", - latest_version = data.latest_version or "", - can_upgrade = data.can_upgrade == "1", - success = data.success == "1", - error = data.error or "", - message = data.message or "" - }) -end - -local function shell_quote(value) - return "'" .. tostring(value or ""):gsub("'", "'\\''") .. "'" + return require "luci.dispatcher".build_url(url) end function index() @@ -623,47 +54,31 @@ function index() page.dependent = true page.acl_depends = { "luci-app-ssr-plus" } entry({"admin", "services", "shadowsocksr", "client"}, cbi("shadowsocksr/client"), _("SSR Client"), 10).leaf = true - entry({"admin", "services", "shadowsocksr", "servers"}, arcombine(cbi("shadowsocksr/servers"), cbi("shadowsocksr/client-config")), _("Servers Nodes"), 20).leaf = true + entry({"admin", "services", "shadowsocksr", "servers"}, arcombine(cbi("shadowsocksr/servers", {autoapply = true}), cbi("shadowsocksr/client-config")), _("Servers Nodes"), 20).leaf = true entry({"admin", "services", "shadowsocksr", "control"}, cbi("shadowsocksr/control"), _("Access Control"), 30).leaf = true entry({"admin", "services", "shadowsocksr", "advanced"}, cbi("shadowsocksr/advanced"), _("Advanced Settings"), 50).leaf = true entry({"admin", "services", "shadowsocksr", "server"}, arcombine(cbi("shadowsocksr/server"), cbi("shadowsocksr/server-config")), _("SSR Server"), 60).leaf = true - entry({"admin", "services", "shadowsocksr", "component"}, cbi("shadowsocksr/component"), _("Component Update"), 65).leaf = true entry({"admin", "services", "shadowsocksr", "status"}, form("shadowsocksr/status"), _("Status"), 70).leaf = true entry({"admin", "services", "shadowsocksr", "check"}, call("check_status")) entry({"admin", "services", "shadowsocksr", "refresh"}, call("refresh_data")) entry({"admin", "services", "shadowsocksr", "subscribe"}, call("subscribe")) - entry({"admin", "services", "shadowsocksr", "component_local_status"}, call("component_local_status")).leaf = true - entry({"admin", "services", "shadowsocksr", "component_set_mirror"}, call("component_set_mirror")).leaf = true - entry({"admin", "services", "shadowsocksr", "component_status"}, call("component_status")).leaf = true - entry({"admin", "services", "shadowsocksr", "component_upgrade"}, call("component_upgrade")).leaf = true - entry({"admin", "services", "shadowsocksr", "geo_local_status"}, call("geo_local_status")).leaf = true - entry({"admin", "services", "shadowsocksr", "geo_status"}, call("geo_status")).leaf = true - entry({"admin", "services", "shadowsocksr", "geo_upgrade"}, call("geo_upgrade")).leaf = true entry({"admin", "services", "shadowsocksr", "checkport"}, call("check_port")) entry({"admin", "services", "shadowsocksr", "log"}, form("shadowsocksr/log"), _("Log"), 80).leaf = true entry({"admin", "services", "shadowsocksr", "get_log"}, call("get_log")).leaf = true entry({"admin", "services", "shadowsocksr", "clear_log"}, call("clear_log")).leaf = true entry({"admin", "services", "shadowsocksr", "run"}, call("act_status")) entry({"admin", "services", "shadowsocksr", "ping"}, call("act_ping")) - entry({"admin", "services", "shadowsocksr", "save_order"}, call("save_order")).leaf = true - entry({"admin", "services", "shadowsocksr", "delete_node"}, call("act_delete_node")).leaf = true - entry({"admin", "services", "shadowsocksr", "add_subscribe_item"}, call("add_subscribe_item")).leaf = true - entry({"admin", "services", "shadowsocksr", "delete_subscribe_item"}, call("delete_subscribe_item")).leaf = true - entry({"admin", "services", "shadowsocksr", "toggle_subscribe_item_enabled"}, call("toggle_subscribe_item_enabled")).leaf = true entry({"admin", "services", "shadowsocksr", "reset"}, call("act_reset")) entry({"admin", "services", "shadowsocksr", "restart"}, call("act_restart")) entry({"admin", "services", "shadowsocksr", "delete"}, call("act_delete")) - entry({"admin", "services", "shadowsocksr", "clash_panel"}, call("clash_panel")).leaf = true - entry({"admin", "services", "shadowsocksr", "clash_groups"}, call("clash_groups")).leaf = true - entry({"admin", "services", "shadowsocksr", "clash_switch"}, call("clash_switch")).leaf = true - entry({"admin", "services", "shadowsocksr", "clash_refresh"}, call("clash_refresh")).leaf = true - entry({"admin", "services", "shadowsocksr", "clash_reset_defaults"}, call("clash_reset_defaults")).leaf = true - entry({"admin", "services", "shadowsocksr", "clash_client_policies"}, call("clash_client_policies")).leaf = true - entry({"admin", "services", "shadowsocksr", "clash_client_rule_save"}, call("clash_client_rule_save")).leaf = true - entry({"admin", "services", "shadowsocksr", "clash_client_rule_clear"}, call("clash_client_rule_clear")).leaf = true + --[[ API ]] + entry({"admin", "services", "shadowsocksr", "add_node"}, call("act_add_node")).leaf = true + entry({"admin", "services", "shadowsocksr", "remove_node"}, call("act_remove")) + entry({"admin", "services", "shadowsocksr", "save_node_order"}, call("act_save_order")).leaf = true + entry({"admin", "services", "shadowsocksr", "get_now_use_node"}, call("act_get_now_use_node")).leaf = true + entry({'admin', 'services', "shadowsocksr", 'ip'}, call('check_ip')) -- 获取ip情况 --[[Backup]] entry({"admin", "services", "shadowsocksr", "backup"}, call("create_backup")).leaf = true - entry({'admin', 'services', "shadowsocksr", 'ip'}, call('check_ip')) -- 获取ip情况 end function check_site(host, port) @@ -722,639 +137,34 @@ function check_ip() end function subscribe() - nixio.fs.remove(SERVER_DETECT_CACHE) - local sid = luci.http.formvalue("sid") or "" - local subscribe_arg = sid ~= "" and (" " .. luci.util.shellquote(sid)) or "" - local ret = luci.sys.call(": > /var/log/ssrplus.log && /usr/bin/lua /usr/share/shadowsocksr/subscribe.lua" .. subscribe_arg .. " >>/var/log/ssrplus.log 2>&1") + luci.sys.call("/usr/bin/lua /usr/share/shadowsocksr/subscribe.lua >>/var/log/ssrplus.log") luci.http.prepare_content("application/json") - luci.http.write_json({ret = ret}) -end - -function save_order() - local order = luci.http.formvalue("order") or "" - local page = parse_nonnegative_int(luci.http.formvalue("page")) or 1 - local page_size = parse_nonnegative_int(luci.http.formvalue("page_size")) or 0 - local sids = {} - local all_sections = {} - local server_sections = {} - local server_positions = {} - local section_index = {} - local page_start - local page_end - - for sid in order:gmatch("%S+") do - if uci:get("shadowsocksr", sid) == "servers" and not section_index[sid] then - sids[#sids + 1] = sid - section_index[sid] = true - end - end - - uci:foreach("shadowsocksr", nil, function(section) - all_sections[#all_sections + 1] = section[".name"] - if section[".type"] == "servers" then - server_sections[#server_sections + 1] = section[".name"] - server_positions[#server_positions + 1] = #all_sections - end - end) - - page_start = 1 - page_end = #server_sections - if page_size > 0 then - page_start = ((math.max(page, 1) - 1) * page_size) + 1 - page_end = math.min(page_start + page_size - 1, #server_sections) - end - - local page_sections = {} - local page_lookup = {} - for index = page_start, page_end do - local sid = server_sections[index] - if sid then - page_sections[#page_sections + 1] = sid - page_lookup[sid] = true - end - end - - local valid = #sids > 0 and #sids == #page_sections - if valid then - for _, sid in ipairs(sids) do - if not page_lookup[sid] then - valid = false - break - end - end - end - - if valid then - for offset, sid in ipairs(sids) do - local absolute_index = page_start + offset - 1 - local position = server_positions[absolute_index] - if not position then - valid = false - break - end - - local cmd = string.format( - "uci -q reorder %s=%d >/dev/null 2>&1", - shell_quote("shadowsocksr." .. sid), - position - 1 - ) - - if luci.sys.call(cmd) ~= 0 then - valid = false - break - end - all_sections[position] = sid - end - if valid then - valid = luci.sys.call("uci -q commit shadowsocksr >/dev/null 2>&1") == 0 - end - end - - luci.http.prepare_content("application/json") - luci.http.write_json({ - ret = valid and 1 or 0, - count = #sids, - page = page, - page_size = page_size - }) -end - -function act_delete_node() - local sid = luci.http.formvalue("sid") - - if not sid or sid == "" then - luci.http.prepare_content("application/json") - luci.http.write_json({ ret = 0, error = "missing sid" }) - return - end - - local del_cmd = luci.sys.call("uci -q delete shadowsocksr." .. sid) - if del_cmd ~= 0 then - luci.http.prepare_content("application/json") - luci.http.write_json({ ret = 0, error = "delete failed" }) - return - end - - local ret_cmd = luci.sys.call("uci -q commit shadowsocksr >/dev/null 2>&1") - if ret_cmd ~= 0 then - luci.http.prepare_content("application/json") - luci.http.write_json({ ret = 0, error = "commit failed" }) - return - end - - luci.http.prepare_content("application/json") - luci.http.write_json({ ret = 1, sid = sid }) -end - -function add_subscribe_item() - local sid = luci.sys.exec("uci add shadowsocksr server_subscribe_item"):gsub("%s+", "") - - if not sid or sid == "" then - luci.http.prepare_content("application/json") - luci.http.write_json({ ret = 0, error = "add failed" }) - return - end - - local alias = string.format("Subscribe %s", sid:sub(-4)) - - -- set enabled - local subscribe_enabled = luci.sys.call("uci -q set shadowsocksr." .. sid .. ".enabled=1") - if subscribe_enabled ~= 0 then - luci.http.prepare_content("application/json") - luci.http.write_json({ ret = 0, error = "set enabled failed" }) - return - end - - -- set alias - local subscribe_alias = luci.sys.call("uci -q set shadowsocksr." .. sid .. ".alias='" .. alias .. "'") - if subscribe_alias ~= 0 then - luci.http.prepare_content("application/json") - luci.http.write_json({ ret = 0, error = "set alias failed" }) - return - end - - luci.http.prepare_content("application/json") - luci.http.write_json({ ret = 1, sid = sid, alias = alias, enabled = "1" }) -end - -function delete_subscribe_item() - local sid = trim(luci.http.formvalue("sid")) - if sid == "" then - luci.http.status(400, "Bad Request") - luci.http.prepare_content("application/json") - luci.http.write_json({ ret = 0, error = "missing sid" }) - return - end - - local delete_subscribe_set = luci.sys.call("uci -q delete shadowsocksr." .. sid .. " 2>/dev/null") - if delete_subscribe_set ~= 0 then - luci.http.prepare_content("application/json") - luci.http.write_json({ ret = 0, error = "delete failed" }) - return - end - - -- commit - local delete_subscribe_cmd = luci.sys.call("uci -q commit shadowsocksr >/dev/null 2>&1") - if delete_subscribe_cmd ~= 0 then - luci.http.prepare_content("application/json") - luci.http.write_json({ ret = 0, error = "commit failed" }) - return - end - - luci.http.prepare_content("application/json") - luci.http.write_json({ ret = 1, sid = sid }) -end - -function toggle_subscribe_item_enabled() - local sid = trim(luci.http.formvalue("sid")) - local field = luci.http.formvalue("field") - local value = luci.http.formvalue("value") - - -- 兼容旧调用方式(只传 enabled) - if not field then - field = "enabled" - value = luci.http.formvalue("enabled") == "1" and "1" or "0" - end - - -- 参数校验 - if sid == "" then - luci.http.status(400, "Bad Request") - luci.http.prepare_content("application/json") - luci.http.write_json({ ret = 0, error = "missing sid" }) - return - end - - -- 检查 sid 对应的 section 类型 - if uci:get("shadowsocksr", sid) ~= "server_subscribe_item" then - luci.http.status(400, "Bad Request") - luci.http.prepare_content("application/json") - luci.http.write_json({ ret = 0, error = "invalid_sid" }) - return - end - - -- 白名单:只允许以下字段 - local allowed_fields = { enabled = true, alias = true, url = true } - if not allowed_fields[field] then - luci.http.status(400, "Bad Request") - luci.http.prepare_content("application/json") - luci.http.write_json({ ret = 0, error = "unsupported field" }) - return - end - - -- 处理字段值 - if field == "enabled" then - value = (value == "1" or value == "true") and "1" or "0" - elseif field == "alias" or field == "url" then - value = value and trim(value) or "" - end - - -- 转义 value 中的单引号(避免破坏 uci 命令) - local escaped_value = value:gsub("'", "'\\''") - - -- 使用外部 uci 命令设置值 - local set_cmd = string.format("uci -q set shadowsocksr.%s.%s='%s'", sid, field, escaped_value) - local set_ret = luci.sys.call(set_cmd .. " >/dev/null 2>&1") - if set_ret ~= 0 then - luci.http.prepare_content("application/json") - luci.http.write_json({ ret = 0, error = "uci set failed" }) - return - end - - -- 提交更改 - local ret_cmd = luci.sys.call("uci -q commit shadowsocksr >/dev/null 2>&1") - if ret_cmd ~= 0 then - luci.http.prepare_content("application/json") - luci.http.write_json({ ret = 0, error = "commit failed" }) - return - end - - luci.http.prepare_content("application/json") - luci.http.write_json({ ret = 1, sid = sid, field = field, value = value }) -end - -function component_status() - local component = luci.http.formvalue("component") - local data, status, err = read_component_state(component, "info") - if not data then - luci.http.status(status or 500, "Bad Request") - write_component_json({component = component, error = err or "bad_request"}) - return - end - write_component_json(data) -end - -function component_local_status() - local component = luci.http.formvalue("component") - local data, status, err = read_component_state(component, "local_info") - if not data then - luci.http.status(status or 500, "Bad Request") - write_component_json({component = component, error = err or "bad_request"}) - return - end - write_component_json(data) -end - -function component_set_mirror() - local mirror = luci.http.formvalue("mirror") or "direct" - local allowed = { - direct = true, - ghproxy = true, - ghproxy_cc = true, - ghfast = true, - jsdelivr = true - } - - if not allowed[mirror] then - mirror = "direct" - end - - uci:set("shadowsocksr", "@global[0]", "component_mirror", mirror) - uci:commit("shadowsocksr") - - luci.http.prepare_content("application/json") - luci.http.write_json({ ret = 1, mirror = mirror }) -end - -function component_upgrade() - local component = luci.http.formvalue("component") - local data, status, err = read_component_state(component, "upgrade") - if not data then - luci.http.status(status or 500, "Bad Request") - write_component_json({component = component, error = err or "bad_request", success = "0"}) - return - end - - local info = read_component_state(component, "info") - if info then - for key, value in pairs(info) do - if data[key] == nil or data[key] == "" then - data[key] = value - end - end - if data.success == "1" then - data.can_upgrade = info.can_upgrade - end - end - - write_component_json(data) -end - -function geo_status() - local component = luci.http.formvalue("component") - local data, status, err = read_geo_state(component, "info") - if not data then - luci.http.status(status or 500, "Bad Request") - write_geo_json({component = component, error = err or "bad_request"}) - return - end - write_geo_json(data) -end - -function geo_local_status() - local component = luci.http.formvalue("component") - local data, status, err = read_geo_state(component, "local_info") - if not data then - luci.http.status(status or 500, "Bad Request") - write_geo_json({component = component, error = err or "bad_request"}) - return - end - write_geo_json(data) -end - -function geo_upgrade() - local component = luci.http.formvalue("component") - local data, status, err = read_geo_state(component, "upgrade") - if not data then - luci.http.status(status or 500, "Bad Request") - write_geo_json({component = component, error = err or "bad_request", success = "0"}) - return - end - write_geo_json(data) + luci.http.write_json({ret = 1}) end function act_status() local e = {} - e.running = global_client_running() - if e.running then - e.status_text = get_running_status_text() - end + e.running = luci.sys.call("busybox ps -w | grep ssr-retcp | grep -v grep >/dev/null") == 0 luci.http.prepare_content("application/json") luci.http.write_json(e) end -function clash_panel() - local sid = luci.http.formvalue("sid") - if uci:get("shadowsocksr", sid) ~= "servers" or uci:get("shadowsocksr", sid, "type") ~= "clash" then - luci.http.status(404, "Not Found") - return - end - luci.template.render("shadowsocksr/clash_panel", { - sid = sid, - alias = uci:get("shadowsocksr", sid, "alias") or sid - }) -end - -function clash_groups() - local sid = luci.http.formvalue("sid") - local groups = {} - local active_sid = resolve_active_clash_sid(sid) - local active = active_sid ~= nil - if active then - local raw = clash_api_request(active_sid, "GET", "/proxies") - if raw then - groups = parse_clash_groups(raw.body) - end - end - luci.http.prepare_content("application/json") - luci.http.write_json({ - active = active, - sid = active_sid, - groups = groups - }) -end - -function clash_switch() - local sid = luci.http.formvalue("sid") - local group = luci.http.formvalue("group") - local name = luci.http.formvalue("name") - if not sid or not group or not name then - luci.http.status(400, "Bad Request") - return - end - local active_sid = resolve_active_clash_sid(sid) - if not active_sid then - luci.http.status(409, "Conflict") - luci.http.prepare_content("application/json") - luci.http.write_json({success = false, message = "inactive"}) - return - end - local body = string.format('{"name":"%s"}', tostring(name):gsub('"', '\\"')) - local path = "/proxies/" .. urlencode(group) - local ret = clash_api_request(active_sid, "PUT", path, body) - luci.http.prepare_content("application/json") - luci.http.write_json({success = ret ~= nil and ret.code and ret.code >= 200 and ret.code < 300, sid = active_sid}) -end - -function clash_refresh() - local sid = luci.http.formvalue("sid") - if not sid or uci:get("shadowsocksr", sid) ~= "servers" or uci:get("shadowsocksr", sid, "type") ~= "clash" then - luci.http.status(400, "Bad Request") - luci.http.prepare_content("application/json") - luci.http.write_json({success = false}) - return - end - local cmd = string.format("/etc/init.d/shadowsocksr clash_cache %s >/dev/null 2>&1", luci.util.shellquote(sid)) - local ok = luci.sys.call(cmd) == 0 - local reapplied = false - if ok and is_active_clash_node(sid) then - luci.sys.call("/etc/init.d/shadowsocksr restart >/dev/null 2>&1 &") - reapplied = true - end - luci.http.prepare_content("application/json") - luci.http.write_json({ - success = ok, - cached = nixio.fs.access(get_clash_cache_file(sid)), - reapplied = reapplied - }) -end - -function clash_reset_defaults() - local sid = luci.http.formvalue("sid") - if not sid or uci:get("shadowsocksr", sid) ~= "servers" or uci:get("shadowsocksr", sid, "type") ~= "clash" then - luci.http.status(400, "Bad Request") - luci.http.prepare_content("application/json") - luci.http.write_json({success = false}) - return - end - - local state_file = get_clash_state_file(sid) - local cleared = false - if nixio.fs.access(state_file) then - cleared = nixio.fs.remove(state_file) or false - else - cleared = true - end - - local reapplied = false - if cleared and is_active_clash_node(sid) then - luci.sys.call("/etc/init.d/shadowsocksr restart >/dev/null 2>&1 &") - reapplied = true - end - - luci.http.prepare_content("application/json") - luci.http.write_json({ - success = cleared, - reapplied = reapplied - }) -end - -function clash_client_policies() - local sid = luci.http.formvalue("sid") - local active_sid = resolve_active_clash_sid(sid) - local groups = {} - if active_sid then - local raw = clash_api_request(active_sid, "GET", "/proxies") - if raw then - groups = parse_clash_groups(raw.body) - end - end - - local policies = {} - local seen = {} - for _, group in ipairs(groups or {}) do - if group.name and not seen[group.name] then - seen[group.name] = true - policies[#policies + 1] = { - name = group.name, - label = group.name, - type = group.type or "" - } - end - for _, proxy_name in ipairs(group.all or {}) do - if proxy_name and proxy_name ~= "" and not seen[proxy_name] then - seen[proxy_name] = true - policies[#policies + 1] = { - name = proxy_name, - label = proxy_name, - type = "proxy" - } - end - end - end - - table.sort(policies, function(a, b) - return tostring(a.label or a.name) < tostring(b.label or b.name) - end) - - luci.http.prepare_content("application/json") - luci.http.write_json({ - active = active_sid ~= nil, - sid = active_sid, - clients = collect_lan_clients(), - rules = read_clash_client_rules(sid), - policies = policies - }) -end - -function clash_client_rule_save() - local sid = luci.http.formvalue("sid") - local rows = {} - local max_rows = tonumber(luci.http.formvalue("count") or "0") or 0 - - for index = 1, math.min(max_rows, 256) do - local prefix = string.format("rule_%d_", index) - local ip_addr = normalize_client_ip(luci.http.formvalue(prefix .. "ip_addr")) - local enabled = luci.http.formvalue(prefix .. "enabled") == "1" and "1" or "0" - local remarks = trim(luci.http.formvalue(prefix .. "remarks")) - local policy_group = trim(luci.http.formvalue(prefix .. "policy_group")) - local client_mac = sanitize_mac(luci.http.formvalue(prefix .. "client_mac")) - - if ip_addr ~= "" and policy_group ~= "" then - rows[#rows + 1] = { - enabled = enabled, - remarks = remarks, - ip_addr = ip_addr, - client_mac = client_mac, - policy_group = policy_group - } - end - end - - if not sid or sid == "" or uci:get("shadowsocksr", sid) ~= "servers" or uci:get("shadowsocksr", sid, "type") ~= "clash" then - luci.http.status(400, "Bad Request") - luci.http.prepare_content("application/json") - luci.http.write_json({ success = false, error = "invalid_sid" }) - return - end - - write_clash_client_rules_csv(sid, rows) - - local active_sid = resolve_active_clash_sid(sid) - local current_sid = uci:get_first("shadowsocksr", "global", "global_server") - local reapplied = false - if sid and sid ~= "" and uci:get("shadowsocksr", sid) == "servers" - and uci:get("shadowsocksr", sid, "type") == "clash" - and current_sid == sid then - luci.sys.call("/etc/init.d/shadowsocksr restart >/dev/null 2>&1 &") - reapplied = true - end - - luci.http.prepare_content("application/json") - luci.http.write_json({ - success = true, - count = #rows, - reapplied = reapplied, - rules = read_clash_client_rules(sid) - }) -end - -function clash_client_rule_clear() - local sid = luci.http.formvalue("sid") - - if not sid or sid == "" or uci:get("shadowsocksr", sid) ~= "servers" or uci:get("shadowsocksr", sid, "type") ~= "clash" then - luci.http.status(400, "Bad Request") - luci.http.prepare_content("application/json") - luci.http.write_json({ success = false, error = "invalid_sid" }) - return - end - - local csv_path = get_clash_client_rule_csv_path(sid) - if csv_path and nixio.fs.access(csv_path) then - nixio.fs.remove(csv_path) - end - - local current_sid = uci:get_first("shadowsocksr", "global", "global_server") - local reapplied = false - if sid and sid ~= "" and uci:get("shadowsocksr", sid) == "servers" - and uci:get("shadowsocksr", sid, "type") == "clash" - and current_sid == sid then - luci.sys.call("/etc/init.d/shadowsocksr restart >/dev/null 2>&1 &") - reapplied = true - end - - luci.http.prepare_content("application/json") - luci.http.write_json({ - success = true, - reapplied = reapplied, - rules = {} - }) -end - function act_ping() local e = {} local domain = luci.http.formvalue("domain") local port = tonumber(luci.http.formvalue("port") or 0) local transport = (luci.http.formvalue("transport") or ""):lower() local wsPath = luci.http.formvalue("wsPath") or "" - local host = luci.http.formvalue("host") or "" - local tls_host = luci.http.formvalue("tlsHost") or "" local tls = luci.http.formvalue("tls") + local host = luci.http.formvalue("host") local type = (luci.http.formvalue("type") or ""):lower() local proto = (luci.http.formvalue("proto") or ""):lower() - local reality = luci.http.formvalue("reality") - local sid = luci.http.formvalue("sid") e.index = luci.http.formvalue("index") - if sid and sid ~= "" and uci:get("shadowsocksr", sid) == "servers" then - domain = uci:get("shadowsocksr", sid, "server") or domain - port = tonumber(uci:get("shadowsocksr", sid, "server_port") or port or 0) - transport = (uci:get("shadowsocksr", sid, "transport") or transport or ""):lower() - wsPath = uci:get("shadowsocksr", sid, "ws_path") or wsPath - host = uci:get("shadowsocksr", sid, "ws_host") or host - tls_host = uci:get("shadowsocksr", sid, "tls_host") or tls_host - tls = uci:get("shadowsocksr", sid, "tls") or tls - type = (uci:get("shadowsocksr", sid, "type") or type or ""):lower() - proto = (uci:get("shadowsocksr", sid, "v2ray_protocol") or proto or ""):lower() - reality = uci:get("shadowsocksr", sid, "reality") or reality - end - local is_ip = domain and domain:match("^%d+%.%d+%.%d+%.%d+$") - local probe_host = (tls_host ~= "" and tls_host) or (host ~= "" and host) or domain - local is_reality = (reality == "1" or reality == "true") - local prefers_handshake_latency = (type == "v2ray") and not is_reality -- 临时放行防火墙逻辑 - local use_nft = use_fw4_backend() + local use_nft = luci.sys.call("command -v nft >/dev/null") == 0 local iret = false if domain then if use_nft then @@ -1363,52 +173,46 @@ function act_ping() iret = luci.sys.call("ipset add ss_spec_wan_ac " .. domain .. " 2>/dev/null") == 0 end end - -- Hysteria2 节点轻量 UDP 端口检测 + -- Hysteria2 节点检测 if proto:find("hysteria2") or type:find("hysteria2") then - local udp_cmd = string.format("nping --udp -c 1 -p %d %s 2>/dev/null", port, domain) - local udp_raw = luci.sys.exec(udp_cmd) or "" - local udp_rtt = udp_raw:match("Avg rtt:%s*([0-9.]+)ms") - local udp_unreachable = udp_raw:match("[Pp]ort [Uu]nreachable") or udp_raw:match("ICMP") - local udp_sent = udp_raw:match("Raw packets sent:%s*1") - - -- UDP 服务通常不会主动回包,未收到应答不等于端口不可用。 - -- 仅在出现明显的不可达迹象时标记 fail,其余视为轻量可达。 - e.socket = (udp_unreachable == nil) and (udp_sent ~= nil) - e.ping = udp_rtt and normalize_ping_ms(udp_rtt) or nil - - if not e.ping then - local icmp_cmd = string.format("ping -c 1 -W 1 %s 2>/dev/null | grep -o 'time=[0-9.]*' | cut -d= -f2", domain) - e.ping = normalize_ping_ms(tonumber(luci.sys.exec(icmp_cmd))) - end - if not e.ping then + local node_id = e.index + -- 调用Shell测试脚本 + local cmd = string.format( + "/usr/share/shadowsocksr/hy2_test.sh url_test_hy2 %s", + node_id + ) + local res = luci.sys.exec(cmd) or "" + -- 解析结果 + local http_code, time_pre = string.match(res, "(%d+):([%d%.]+)") + if http_code == "200" or http_code == "204" then + e.socket = true + e.ping = math.floor(tonumber(time_pre or 0) * 1000) + else + e.socket = false e.ping = 0 end elseif transport == "ws" then -- WebSocket 探测 local result = "" local success = false - local icmp_cmd = string.format("ping -c 1 -W 1 %s 2>/dev/null | grep -o 'time=[0-9.]*' | cut -d= -f2", domain) - e.ping = normalize_ping_ms(tonumber(luci.sys.exec(icmp_cmd))) -- WebSocket 探测 (适用于域名,或带 SNI 的 IP) - if not is_ip or probe_host ~= domain then + if not is_ip or (host and host ~= "") then local resolve_arg = "" - local final_domain = probe_host - if is_ip and probe_host and probe_host ~= "" then + local final_domain = domain + if is_ip and host and host ~= "" then -- IP 模式下使用 --resolve 强制指定 SNI,解决 TLS 握手失败 - resolve_arg = string.format("--resolve '%s:%d:%s' ", probe_host, port, domain) + resolve_arg = string.format("--resolve '%s:%d:%s' ", host, port, domain) + final_domain = host end local prefix = (tls == '1') and "https://" or "http://" local address = prefix .. final_domain .. ':' .. port .. wsPath local cmd = string.format( "curl --http1.1 -m 2 -ksN -o /dev/null %s" .. "-w 'time_connect=%%{time_connect}\\nhttp_code=%%{http_code}' " .. - "%s" .. "-H 'Connection: Upgrade' -H 'Upgrade: websocket' " .. "-H 'Sec-WebSocket-Key: SGVsbG8sIHdvcmxkIQ==' " .. "-H 'Sec-WebSocket-Version: 13' '%s'", - resolve_arg, - (probe_host and probe_host ~= "") and ("-H " .. luci.util.shellquote("Host: " .. probe_host) .. " ") or "", - address + resolve_arg, address ) result = luci.sys.exec(cmd) or "" success = (string.match(result, "http_code=(%d+)") == "101") @@ -1425,17 +229,13 @@ function act_ping() --luci.sys.exec(string.format("echo 'Node %s (ws) failed deep test, using TCP fallback' >> /tmp/ping.log", domain)) end e.socket = success - -- 延迟:优先 ping,再 curl,最后 nping tcp-connect - if not e.ping then - local ping_time = tonumber(string.match(result, "time_connect=(%d+.%d%d%d)")) - local appconnect_time = tonumber(string.match(result, "time_appconnect=(%d+.%d%d%d)")) - if appconnect_time and appconnect_time > 0 then - e.ping = normalize_ping_ms(appconnect_time, 1000) - elseif ping_time and ping_time > 0 then - e.ping = normalize_ping_ms(ping_time, 1000) - else - e.ping = detect_tcp_connect_ms(domain, port) or 0 - end + -- 解析延迟 (优先用 curl 数据,失败则回退到 tcping) + local ping_time = tonumber(string.match(result, "time_connect=(%d+.%d%d%d)")) + if ping_time and ping_time > 0 then + e.ping = math.floor(ping_time * 1000) + else + local tcping_cmd = string.format("tcping -q -c 1 -t 1 -p %d %s 2>/dev/null | grep -o 'time=[0-9]*' | cut -d= -f2", port, domain) + e.ping = tonumber(luci.sys.exec(tcping_cmd)) or 0 end else -- 3. 非 WebSocket 节点的探测逻辑 (TCP / ICMP / UDP) @@ -1447,19 +247,12 @@ function act_ping() socket:close() end - if prefers_handshake_latency and (tls == "1" or tls_host ~= "" or proto == "vless" or proto == "vmess") then - e.ping = detect_tls_handshake_ms(domain, port, "", probe_host, domain, false) - end - - -- 延迟:优先真实握手,再 nping tcp-connect -> ping -> nping(udp) - if not e.ping then - if not is_reality then - e.ping = detect_tcp_connect_ms(domain, port) - end - end + -- 延迟:tcping -> ping -> nping(udp) + local tcping_cmd = string.format("tcping -q -c 1 -t 1 -p %d %s 2>/dev/null | grep -o 'time=[0-9]*' | cut -d= -f2", port, domain) + e.ping = tonumber(luci.sys.exec(tcping_cmd)) if not e.ping then local icmp_cmd = string.format("ping -c 1 -W 1 %s 2>/dev/null | grep -o 'time=[0-9.]*' | cut -d= -f2", domain) - e.ping = normalize_ping_ms(tonumber(luci.sys.exec(icmp_cmd))) + e.ping = tonumber(luci.sys.exec(icmp_cmd)) end if not e.ping then @@ -1467,23 +260,7 @@ function act_ping() local udp_res = luci.sys.exec(udp_cmd) if udp_res and udp_res ~= "" then local ping_num = tonumber(udp_res) - if ping_num then e.ping = normalize_ping_ms(ping_num) end - end - end - - if (not e.ping or e.ping == 0) and domain and port > 0 then - local schemes = { "https", "http" } - for _, scheme in ipairs(schemes) do - local connect_cmd = string.format( - "curl -m 2 -ksS -o /dev/null -w 'time_connect=%%{time_connect}' %s://%s:%d 2>/dev/null", - scheme, domain, port - ) - local connect_res = luci.sys.exec(connect_cmd) or "" - local connect_time = tonumber(connect_res:match("time_connect=([0-9.]+)")) - if connect_time and connect_time > 0 then - e.ping = normalize_ping_ms(connect_time, 1000) - break - end + if ping_num then e.ping = math.floor(ping_num) end end end end @@ -1497,26 +274,13 @@ function act_ping() end end - if sid and sid ~= "" then - save_detect_cache_entry(sid, { - server = domain or "", - port = port or 0, - type = type or "", - proto = proto or "", - socket = e.socket and true or false, - ping = tonumber(e.ping) or 0, - time = os.time() - }) - end - luci.http.prepare_content("application/json") luci.http.write_json(e) end function check_status() local e = {} - local target = luci.http.formvalue("set") or "" - e.ret = luci.sys.call("curl -m 3 -sS -o /dev/null http://www." .. target .. ".com >/dev/null 2>&1") + e.ret = luci.sys.call("/usr/bin/ssr-check www." .. luci.http.formvalue("set") .. ".com 80 3 1") luci.http.prepare_content("application/json") luci.http.write_json(e) end @@ -1533,13 +297,9 @@ function check_port() local s local server_name = "" local uci = require "luci.model.uci".cursor() - local use_nft = use_fw4_backend() + local use_nft = luci.sys.call("command -v nft >/dev/null") == 0 uci:foreach("shadowsocksr", "servers", function(s) - if s.type == "clash" then - retstring = retstring .. string.format("[%s] Clash panel node.
", s.alias or s[".name"]) - return - end if s.alias then server_name = s.alias elseif s.server and s.server_port then @@ -1547,18 +307,15 @@ function check_port() end -- 临时加入 set - local is_ipv6 = is_ipv6_address(s.server) local iret = false - if not is_ipv6 then - if use_nft then - iret = luci.sys.call("nft add element inet ss_spec ss_spec_wan_ac { " .. s.server .. " } 2>/dev/null") == 0 - else - iret = luci.sys.call("ipset add ss_spec_wan_ac " .. s.server .. " 2>/dev/null") == 0 - end + if use_nft then + iret = luci.sys.call("nft add element inet ss_spec ss_spec_wan_ac { " .. s.server .. " } 2>/dev/null") == 0 + else + iret = luci.sys.call("ipset add ss_spec_wan_ac " .. s.server .. " 2>/dev/null") == 0 end -- TCP 测试 - local socket = nixio.socket(is_ipv6 and "inet6" or "inet", "stream") + local socket = nixio.socket("inet", "stream") socket:setopt("socket", "rcvtimeo", 3) socket:setopt("socket", "sndtimeo", 3) local ret = socket:connect(s.server, s.server_port) @@ -1590,15 +347,109 @@ function act_reset() end function act_restart() - luci.sys.call("/etc/init.d/shadowsocksr restart > /dev/null 2>&1 &") luci.http.redirect(luci.dispatcher.build_url("admin", "services", "shadowsocksr")) end function act_delete() - luci.sys.call("/etc/init.d/shadowsocksr restart > /dev/null 2>&1 &") + uci:delete_all("shadowsocksr", "servers", function(s) + if s.hashkey or s.isSubscribe then + return true + else + return false + end + end) + uci:commit("shadowsocksr") + for file in nixio.fs.glob("/tmp/sub_md5_*") do + nixio.fs.remove(file) + end + luci.sys.call("/etc/init.d/shadowsocksr restart >/dev/null 2>&1 &") luci.http.redirect(luci.dispatcher.build_url("admin", "services", "shadowsocksr", "servers")) end +function act_add_node() + local redirect = luci.http.formvalue("redirect") + local used_sid = {} + local next_sid = 1 + + uci:foreach("shadowsocksr", "servers", function(s) + local num = s[".name"]:match("^cfg(%x%x)") + if num then + local n = tonumber(num, 16) + used_sid[n] = true + end + end) + + local function get_next_sid() + while used_sid[next_sid] do + next_sid = next_sid + 1 + end + used_sid[next_sid] = true + return next_sid + end + + local sid = uci:section("shadowsocksr", "servers", nil) + local suffix = sid:sub(-4) + uci:delete("shadowsocksr", sid) + + local id = get_next_sid() + local cfgid = string.format("cfg%02x%s", id, suffix) + uci:section("shadowsocksr", "servers", cfgid) + uci_save(uci, "shadowsocksr") + + if redirect == "1" then + luci.http.redirect(url("servers", cfgid)) + else + luci.http.write_json({ result = cfgid }) + end +end + +function act_remove() + local id = luci.http.formvalue("id") + if id then + uci:delete("shadowsocksr", id) + uci:commit("shadowsocksr") + end + luci.http.redirect(luci.dispatcher.build_url("admin", "services", "shadowsocksr", "servers")) +end + +function act_save_order() + local ids = luci.http.formvalue("ids") or "" + local new_order = {} + for id in ids:gmatch("([^,]+)") do + new_order[#new_order + 1] = id + end + + for idx, name in ipairs(new_order) do + luci.sys.call(string.format("uci -q reorder %s.%s=%d", "shadowsocksr", name, idx - 1)) + end + + sh_uci_commit("shadowsocksr") + luci.http.write_json({ status = "ok" }) +end + +function act_get_now_use_node() + local result = {} + local tcp_node = uci:get_first("shadowsocksr", "global", "global_server") + if tcp_node then + result["TCP"] = tcp_node + end + local udp_node = uci:get_first("shadowsocksr", "global", "udp_relay_server") + if udp_node then + result["UDP"] = udp_node + end + local netflix_node = uci:get_first("shadowsocksr", "global", "netflix_server") + if netflix_node then + result["netflix"] = netflix_node + end + local socks5_node = uci:get_first("shadowsocksr", "socks5_proxy", "server") + if socks5_node then + result["socks5"] = socks5_node + end + + luci.http.prepare_content("application/json") + luci.http.write_json(result) +end + function get_log() luci.http.write(luci.sys.exec("[ -f '/var/log/ssrplus.log' ] && cat /var/log/ssrplus.log")) end 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 a1023748..2e5d38af 100644 --- a/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua +++ b/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua @@ -1,7 +1,6 @@ local m, s, o local cbi = require "luci.cbi" local uci = require "luci.model.uci".cursor() -local URL = require "url" -- 获取 LAN IP 地址 function lanip() @@ -31,32 +30,16 @@ local lan_ip = lanip() local server_table = {} local type_table = {} local function is_finded(e) - return luci.sys.exec(string.format('type -t -p "%s" -p "/usr/libexec/%s" 2>/dev/null', e, e)) ~= "" -end - -local function clash_display_name(s) - if s.type ~= "clash" or not s.clash_url or s.clash_url == "" then - return nil - end - local ok, parsed = pcall(URL.parse, s.clash_url) - if ok and parsed and parsed.host then - return "[CLASH]:" .. parsed.host - end - return "[CLASH]" + return luci.sys.exec(string.format('type -t -p "%s" 2>/dev/null', e)) ~= "" end uci:foreach("shadowsocksr", "servers", function(s) - if s.type ~= "tun" and s.alias then + if s.alias then server_table[s[".name"]] = "[%s]:%s" % {string.upper(s.v2ray_protocol or s.type), s.alias} - elseif s.type ~= "tun" and s.server and s.server_port then + elseif s.server and s.server_port then server_table[s[".name"]] = "[%s]:%s:%s" % {string.upper(s.v2ray_protocol or s.type), s.server, s.server_port} - elseif s.type ~= "tun" then - local display_name = clash_display_name(s) - if display_name then - server_table[s[".name"]] = display_name - end end - if s.type and s.type ~= "tun" then + if s.type then type_table[s[".name"]] = s.type end end) @@ -96,13 +79,6 @@ o.datatype = "uinteger" o:depends("enable_switch", "1") o.default = 3 -s:append(cbi.Template("shadowsocksr/advanced_switch_compact")) - -o = s:option(Value, "default_node_local_port", translate("Default Node Local Port")) -o.datatype = "port" -o.default = 1234 -o.rmempty = false - o = s:option(Value, "gfwlist_url", translate("gfwlist Update url")) o:value("https://fastly.jsdelivr.net/gh/YW5vbnltb3Vz/domain-list-community@release/gfwlist.txt", translate("v2fly/domain-list-community")) o:value("https://fastly.jsdelivr.net/gh/Loyalsoldier/v2ray-rules-dat@release/gfw.txt", translate("Loyalsoldier/v2ray-rules-dat")) @@ -116,6 +92,145 @@ o:value("https://ispip.clang.cn/all_cn_cidr.txt", translate("Clang.CN.CIDR")) o:value("https://fastly.jsdelivr.net/gh/gaoyifan/china-operator-ip@ip-lists/china.txt", translate("china-operator-ip")) 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")) +o:value("https://fastly.jsdelivr.net/gh/QiuSimons/Netflix_IP/NF_only.txt", translate("Netflix IP Only")) +o:value("https://fastly.jsdelivr.net/gh/QiuSimons/Netflix_IP/getflix.txt", translate("Netflix and AWS")) +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(Value, "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 format as tcp://IP:PORT or tls://DOMAIN:PORT (tcp://8.8.8.8 or tls://dns.google:853)") + +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" @@ -151,13 +266,45 @@ end -- [[ SOCKS5 Proxy ]]-- s = m:section(TypedSection, "socks5_proxy", translate("Global SOCKS5 Proxy Server")) s.anonymous = true --- s.description = translate("Only Same as Global Server is supported here. If the current main program supports a built-in SOCKS5 listener, it will be enabled in-process; otherwise SSR Plus will fall back to microsocks.") -- Enable/Disable Option o = s:option(Flag, "enabled", translate("Enable")) o.default = 0 o.rmempty = false +-- Server Selection +o = s:option(ListValue, "server", translate("Server")) +o:value("same", translate("Same as Global Server")) +for _, key in pairs(key_table) do + o:value(key, server_table[key]) +end +o.default = "same" +o.rmempty = false + +-- Dynamic value handling based on enabled/disabled state +o.cfgvalue = function(self, section) + local enabled = m:get(section, "enabled") + if enabled == "0" then + return m:get(section, "old_server") + end + 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) + if old_server ~= "nil" then + m:set(section, "old_server", old_server) + end + m:set(section, "server", "nil") + else + m:del(section, "old_server") + -- Write the value normally when enabled + Value.write(self, section, value) + end +end + -- Socks Auth if is_finded("xray") then o = s:option(ListValue, "socks5_auth", translate("Socks5 Auth Mode"), translate("Socks protocol auth methods, default:noauth.")) @@ -165,6 +312,13 @@ o.default = "noauth" o:value("noauth", "NOAUTH") o:value("password", "PASSWORD") o.rmempty = true +for key, server_type in pairs(type_table) do + if server_type == "v2ray" then + -- 如果服务器类型是 v2ray,则设置依赖项显示 + 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.")) @@ -181,6 +335,13 @@ o:depends("socks5_auth", "password") o = s:option(Flag, "socks5_mixed", translate("Enabled Mixed"), translate("Mixed as an alias of socks, default:Enabled.")) o.default = "1" o.rmempty = false +for key, server_type in pairs(type_table) do + if server_type == "v2ray" then + -- 如果服务器类型是 v2ray,则设置依赖项显示 + o:depends("server", key) + end +end +o:depends({server = "same", disable = true}) end -- Local Port @@ -189,37 +350,6 @@ o.datatype = "port" o.default = 1080 o.rmempty = false -if is_finded("3proxy") then - -- [[ HTTP/HTTPS Proxy ]]-- - s = m:section(TypedSection, "http_proxy", translate("Global HTTP/HTTPS Proxy Server")) - s.anonymous = true - -- s.description = translate("Only Same as Global Server is supported here. HTTP/HTTPS proxy service is provided through 3proxy.") - - o = s:option(Flag, "enabled", translate("Enable")) - o.default = 0 - o.rmempty = false - - o = s:option(ListValue, "http_auth", translate("HTTP Auth Mode"), translate("HTTP proxy auth method, default:none.")) - o.default = "none" - o:value("none", "NONE") - o:value("password", "PASSWORD") - o.rmempty = false - - o = s:option(Value, "http_user", translate("HTTP User"), translate("Only when HTTP Auth Mode is password valid, Mandatory.")) - o.rmempty = true - o:depends("http_auth", "password") - - o = s:option(Value, "http_pass", translate("HTTP Password"), translate("Only when HTTP Auth Mode is password valid, Not mandatory.")) - o.password = true - o.rmempty = true - o:depends("http_auth", "password") - - o = s:option(Value, "local_port", translate("Local Port")) - o.datatype = "port" - o.default = 3128 - o.rmempty = false -end - -- [[ fragmen Settings ]]-- if is_finded("xray") then s = m:section(TypedSection, "global_xray_fragment", translate("Xray Fragment Settings")) 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 d06abbdc..567989ba 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 @@ -20,7 +20,7 @@ local xray_version_val = 0 -- 确保正确判断程序是否存在 local function is_finded(e) - return luci.sys.exec(string.format('type -t -p "%s" -p "/usr/libexec/%s" 2>/dev/null', e, e)) ~= "" + return luci.sys.exec(string.format('type -t -p "%s" 2>/dev/null', e)) ~= "" end local function is_installed(e) @@ -142,14 +142,16 @@ local function set_apply_on_parse(map) local old = map.on_after_save map.on_after_save = function(self) if old then old(self) end - --map:set("@global[0]", "timestamp", os.time()) + map:set("@global[0]", "timestamp", os.time()) end end end local has_ss_rust = is_finded("sslocal") or is_finded("ssserver") -local has_mihomo = is_finded("mihomo") +local has_ss_libev = is_finded("ss-redir") or is_finded("ss-local") +local has_trojan = is_finded("trojan") local has_xray = is_finded("xray") +local has_hysteria2 = is_finded("hysteria") local server_table = {} local encrypt_methods = { @@ -254,56 +256,6 @@ local tls_flows = { "none" } -local function migrate_xray_protocol_nodes() - local changed = false - - uci:foreach("shadowsocksr", "servers", function(section) - local sid = section[".name"] - local stype = section.type - local proto = section.v2ray_protocol - local escaped_sid = luci.util.shellquote(sid) - - if stype == "ss" or stype == "ss-libev" then - if has_mihomo then - luci.sys.call(string.format("uci set shadowsocksr.%s.type='ss'", escaped_sid)) - changed = true - elseif has_ss_rust then - luci.sys.call(string.format("uci set shadowsocksr.%s.type='ss-rust'", escaped_sid)) - changed = true - elseif has_xray then - luci.sys.call(string.format("uci set shadowsocksr.%s.type='v2ray' && " .. "uci set shadowsocksr.%s.v2ray_protocol='shadowsocks'", escaped_sid, escaped_sid)) - changed = true - end - elseif stype == "v2ray" and proto == "shadowsocks" and has_mihomo then - luci.sys.call(string.format("uci set shadowsocksr.%s.type='ss' && " .. "uci delete shadowsocksr.%s.v2ray_protocol", escaped_sid, escaped_sid)) - changed = true - end - if stype == "hysteria2" then - luci.sys.call(string.format("uci set shadowsocksr.%s.type='v2ray' && " .. "uci set shadowsocksr.%s.v2ray_protocol='hysteria2'", escaped_sid, escaped_sid)) - changed = true - elseif stype == "trojan" then - luci.sys.call(string.format("uci set shadowsocksr.%s.type='v2ray' && " .. "uci set shadowsocksr.%s.v2ray_protocol='trojan'", escaped_sid, escaped_sid)) - changed = true - end - end) - local subscribe_sid = uci:get_first("shadowsocksr", "server_subscribe") - if subscribe_sid then - local old_options = {"xray_hy2_type", "xray_tj_type", "ss_type"} - local escaped_sub_sid = luci.util.shellquote(subscribe_sid) - for _, opt in ipairs(old_options) do - if uci:get("shadowsocksr", subscribe_sid, opt) then - luci.sys.call(string.format("uci delete shadowsocksr.%s.%s", escaped_sub_sid, opt)) - changed = true - end - end - end - if changed then - luci.sys.call("uci commit shadowsocksr") - end -end - -migrate_xray_protocol_nodes() - m = Map("shadowsocksr", translate("Edit ShadowSocksR Server")) m.redirect = url("servers") if not sid or m.uci:get("shadowsocksr", sid) ~= "servers" then @@ -312,14 +264,6 @@ if not sid or m.uci:get("shadowsocksr", sid) ~= "servers" then end -- 保存&应用成功后跳转到节点列表 set_apply_on_parse(m) -local old_after_save = m.on_after_save -m.on_after_save = function(self) - if old_after_save then old_after_save(self) end - local node_type = self.uci:get("shadowsocksr", sid, "type") - if node_type == "clash" then - luci.sys.call(string.format("/etc/init.d/shadowsocksr clash_cache %s >/dev/null 2>&1 &", sid)) - end -end -- [[ Servers Setting ]]-- s = m:section(NamedSection, sid, "servers") @@ -331,27 +275,88 @@ o.rawhtml = true o.template = "shadowsocksr/ssrurl" o.value = sid +-- 新增一个选择框,用于选择 Xray 或 Hysteria2 核心 +o = s:option(ListValue, "_xray_hy2_type", string.format("%s", translatef("%s Node Use Type", "Hysteria2"))) +o.description = translate("The configured type also applies to the core specified when manually importing nodes.") +-- 注意:Auto 选项使用特殊字符串 "__auto__" 而不是空字符串 +o:value("__auto__", translate("Auto")) +if has_hysteria2 then + o:value("hysteria2", translate("Hysteria2")) +end +if has_xray then + o:value("v2ray", translate("Xray (Hysteria2)")) +end +-- 读取全局 xray_hy2_type +o.cfgvalue = function(self, section) + local val = uci:get("shadowsocksr", "@server_subscribe[0]", "xray_hy2_type") + if val == nil or val == "" then + return "__auto__" -- 对应 Auto 选项 + end + return val +end +o.rmempty = true +-- 保存时更新全局配置 +o.write = function(self, section, value) + if value == "__auto__" then + -- 删除全局配置 + uci:delete("shadowsocksr", "@server_subscribe[0]", "xray_hy2_type") + else + -- 设置具体值 + uci:set("shadowsocksr", "@server_subscribe[0]", "xray_hy2_type", value) + end +end + -- 新增一个选择框,用于选择 Xray 或 Trojan 核心 +o = s:option(ListValue, "_xray_tj_type", string.format("%s", translatef("%s Node Use Type", "Trojan"))) +o.description = translate("The configured type also applies to the core specified when manually importing nodes.") +-- 注意:Auto 选项使用特殊字符串 "__auto__" 而不是空字符串 +o:value("__auto__", translate("Auto")) +if has_hysteria2 then + o:value("trojan", translate("Trojan")) +end +if has_xray then + o:value("v2ray", translate("Xray (Trojan)")) +end +-- 读取全局 xray_tj_type +o.cfgvalue = function(self, section) + local val = uci:get("shadowsocksr", "@server_subscribe[0]", "xray_tj_type") + if val == nil or val == "" then + return "__auto__" -- 对应 Auto 选项 + end + return val +end +o.rmempty = true +-- 保存时更新全局配置 +o.write = function(self, section, value) + if value == "__auto__" then + -- 删除全局配置 + uci:delete("shadowsocksr", "@server_subscribe[0]", "xray_tj_type") + else + -- 设置具体值 + uci:set("shadowsocksr", "@server_subscribe[0]", "xray_tj_type", value) + end +end + o = s:option(ListValue, "type", translate("Server Node Type")) -if is_finded("xray") then +if is_finded("xray") or is_finded("v2ray") then o:value("v2ray", translate("V2Ray/XRay")) end if is_finded("ssr-redir") then o:value("ssr", translate("ShadowsocksR")) end -if has_mihomo then - o:value("ss", translate("ShadowSocks")) +if has_ss_rust or has_ss_libev then + o:value("ss", translate("ShadowSocks")) end -if has_ss_rust then - o:value("ss-rust", translate("ShadowSocks")) +if is_finded("trojan") then + o:value("trojan", translate("Trojan")) end if is_finded("naive") then o:value("naiveproxy", translate("NaiveProxy")) end -if is_finded("mihomo") then - o:value("clash", translate("Clash/Mihomo")) +if is_finded("hysteria") then + o:value("hysteria2", translate("Hysteria2")) end -if is_finded("mihomo") then +if is_finded("tuic-client") then o:value("tuic", translate("TUIC")) end if is_finded("shadow-tls") and is_finded("sslocal") then @@ -360,51 +365,78 @@ end if is_finded("ipt2socks") then o:value("socks5", translate("Socks5")) end +if is_finded("redsocks2") then + o:value("tun", translate("Network Tunnel")) +end local old_cfgvalue = o.cfgvalue o.cfgvalue = function(self, section) - local val = self.map.uci:get("shadowsocksr", section, "type") - if old_cfgvalue then + local val = self.map.uci:get("shadowsocksr", section, "type") + if val == "ss-rust" or val == "ss-libev" then + return "ss" + end + if old_cfgvalue then return old_cfgvalue(self, section) - end - return val + end + return val end +-- 重写 write,当用户选择 "ss" 时不写入(由 _ss_core 负责写入具体核心) +local old_write = o.write +o.write = function(self, section, value) + if value == "ss" then + return -- 不做任何写入,等待 _ss_core 写入 + end + if old_write then + old_write(self, section, value) + else + self.map.uci:set("shadowsocksr", section, "type", value) + end +end + o.description = translate("Using incorrect encryption mothod may causes service fail to start") o = s:option(Value, "alias", translate("Alias(optional)")) -local function clash_source_formvalue(map, section, option) - local value = map:formvalue("cbid." .. map.config .. "." .. section .. "." .. option) - if value == nil then - value = map.uci:get(map.config, section, option) +o = s:option(ListValue, "iface", translate("Network interface to use")) +for _, e in ipairs(luci.sys.net.devices()) do + if e ~= "lo" then + o:value(e) end - return trim(value or "") end +o:depends("type", "tun") +o.description = translate("Redirect traffic to this network interface") -local function validate_clash_source(self, value, section) - local clash_url = clash_source_formvalue(self.map, section, "clash_url") - local clash_path = clash_source_formvalue(self.map, section, "clash_path") - if clash_url == "" and clash_path == "" then - return nil, translate("Please specify either a Clash subscription URL or a local YAML path.") - end - return value +-- 新增一个选择框,用于选择 Shadowsocks 具体版本(仅当节点类型为 ss 或其具体子类型时显示) +o = s:option(ListValue, "_ss_core", string.format("%s", translatef("%s Node Use Version", "ShadowSocks"))) +o.description = translate("Selection ShadowSocks Node Use Version.") +if has_ss_rust then + o:value("ss-rust", translate("ShadowSocks-rust Version")) end - -o = s:option(Value, "clash_url", translate("Clash Subscription URL")) -o.placeholder = "https://example.com/config.yaml" +if has_ss_libev then + o:value("ss-libev", translate("ShadowSocks-libev Version")) +end +o.cfgvalue = function(self, section) + -- 读取当前节点的 type 值,如果已经是具体核心则显示对应的选项 + local node_type = self.map.uci:get("shadowsocksr", section, "type") + if node_type == "ss-rust" or node_type == "ss-libev" then + return node_type + end + -- 如果全局 ss_type 有值且为具体核心则返回该值 + local ss_type = self.map.uci:get("shadowsocksr", "@server_subscribe[0]", "ss_type") + if ss_type == "ss-rust" or ss_type == "ss-libev" then + return ss_type + end + -- 如果节点 type 是旧的 "ss",则返回空,手动选择 + return nil +end +-- 显示条件:当节点类型为 "ss" 或其具体核心时显示 +o:depends("type", "ss") o.rmempty = true -o:depends("type", "clash") -o.validate = validate_clash_source - -o = s:option(Value, "clash_path", translate("Clash YAML Path")) -o.placeholder = "/etc/ssrplus/clash/custom.yaml" -o.rmempty = true -o:depends("type", "clash") -o.validate = validate_clash_source - -o = s:option(Value, "clash_user_agent", translate("Clash User-Agent")) -o.default = "clash" -o.rmempty = false -o:depends("type", "clash") +-- 保存时,将选择的值直接写入当前节点的 type 字段 +o.write = function(self, section, value) + if value and value ~= "" then + self.map.uci:set("shadowsocksr", section, "type", value) + end +end o = s:option(ListValue, "v2ray_protocol", translate("V2Ray/XRay protocol")) o:value("vless", translate("VLESS")) @@ -422,54 +454,30 @@ o:value("http", translate("HTTP")) o:depends("type", "v2ray") o = s:option(Value, "server", translate("Server Address")) -o.datatype = "or(host,ip6addr)" +o.datatype = "host" o.rmempty = false o:depends("type", "ssr") o:depends("type", "ss") -o:depends("type", "ss-rust") +o:depends("type", "v2ray") o:depends("type", "trojan") o:depends("type", "naiveproxy") o:depends("type", "hysteria2") o:depends("type", "tuic") o:depends("type", "shadowtls") o:depends("type", "socks5") -local protocols = s.fields["v2ray_protocol"].keylist -if protocols and type(protocols) == "table" and #protocols > 0 then - for _, proto in ipairs(protocols) do - if not proto:find("^_") then - if proto == "hysteria2" then - o:depends({type = "v2ray", v2ray_protocol = "hysteria2", hysteria2_realms = false}) - else - o:depends({type = "v2ray", v2ray_protocol = proto}) - end - end - end -end o = s:option(Value, "server_port", translate("Server Port")) o.datatype = "port" o.rmempty = true o:depends("type", "ssr") o:depends("type", "ss") -o:depends("type", "ss-rust") +o:depends("type", "v2ray") o:depends("type", "trojan") o:depends("type", "naiveproxy") o:depends("type", "hysteria2") o:depends("type", "tuic") o:depends("type", "shadowtls") o:depends("type", "socks5") -local protocols = s.fields["v2ray_protocol"].keylist -if protocols and type(protocols) == "table" and #protocols > 0 then - for _, proto in ipairs(protocols) do - if not proto:find("^_") then - if proto == "hysteria2" then - o:depends({type = "v2ray", v2ray_protocol = "hysteria2", hysteria2_realms = false}) - else - o:depends({type = "v2ray", v2ray_protocol = proto}) - end - end - end -end o = s:option(Flag, "auth_enable", translate("Enable Authentication")) o.rmempty = false @@ -490,7 +498,6 @@ o.password = true o.rmempty = true o:depends("type", "ssr") o:depends("type", "ss") -o:depends("type", "ss-rust") o:depends("type", "trojan") o:depends("type", "naiveproxy") o:depends("type", "shadowtls") @@ -517,7 +524,6 @@ for _, v in ipairs(encrypt_methods_ss) do end end o.rmempty = true -o:depends("type", "ss-rust") o:depends("type", "ss") o:depends({type = "v2ray", v2ray_protocol = "shadowsocks"}) @@ -536,30 +542,22 @@ o.default = "1" o = s:option(Flag, "enable_plugin", translate("Enable Plugin")) o.rmempty = true o:depends("type", "ss") -o:depends("type", "ss-rust") o.default = "0" -- Shadowsocks Plugin o = s:option(ListValue, "plugin", translate("Obfs")) o:value("none", translate("None")) -if has_mihomo or is_finded("obfs-local") then +if is_finded("obfs-local") then o:value("obfs-local", translate("obfs-local")) end -if has_mihomo or is_finded("v2ray-plugin") then +if is_finded("v2ray-plugin") then o:value("v2ray-plugin", translate("v2ray-plugin")) end -if has_mihomo then - o:value("gost-plugin", translate("gost-plugin")) -end if is_finded("xray-plugin") then o:value("xray-plugin", translate("xray-plugin")) end -if has_mihomo or is_finded("shadow-tls") then - o:value("shadow-tls", translate("Shadow-TLS")) -end -if has_mihomo then - o:value("restls", translate("restls")) - o:value("kcptun", translate("kcptun")) +if is_finded("shadow-tls") then + o:value("shadow-tls", translate("shadow-tls")) end o:value("custom", translate("Custom")) o.rmempty = true @@ -595,21 +593,6 @@ o:depends("type", "ssr") -- [[ Hysteria2 ]]-- -o = s:option(Flag, "hysteria2_realms", translate("Hysteria2 Realms")) -o.default = "0" -if xray_version_val > 260509 then - o:depends({type = "v2ray", v2ray_protocol = "hysteria2"}) -else - o:depends({type = "v2ray", v2ray_protocol = "__hide"}) -end - -o = s:option(Value, "hysteria2_realm_url", translate("Realm URL"), translate("Example:") .. "realm://public@realm.hy2.io/your-realm-name") -o:depends("hysteria2_realms", true) - -o = s:option(DynamicList, "hysteria2_realm_stun", translate("Realm STUN")) -o.default = { "stun.sip.us:3478", "stun.nextcloud.com:3478", "global.stun.twilio.com:3478" } -o:depends("hysteria2_realms", true) - o = s:option(Value, "hy2_auth", translate("Users Authentication")) o:depends("type", "hysteria2") o:depends({type = "v2ray", v2ray_protocol = "hysteria2"}) @@ -618,7 +601,7 @@ o.rmempty = false o = s:option(Flag, "flag_port_hopping", translate("Enable Port Hopping")) o:depends("type", "hysteria2") -o:depends({type = "v2ray", v2ray_protocol = "hysteria2", hysteria2_realms = false}) +o:depends({type = "v2ray", v2ray_protocol = "hysteria2"}) o.rmempty = true o.default = "0" @@ -660,30 +643,17 @@ o.rmempty = true o.default = "0" o = s:option(Value, "obfs_type", translate("Obfuscation Type")) -o:value("", translate("Disable")) -o:value("salamander") -o:value("gecko") -o.rmempty = true o:depends({type = "hysteria2", flag_obfs = true}) o:depends({type = "v2ray", v2ray_protocol = "hysteria2", flag_obfs = true}) +o.rmempty = true +o.placeholder = "salamander" o = s:option(Value, "salamander", translate("Obfuscation Password")) +o:depends({type = "hysteria2", flag_obfs = true}) +o:depends({type = "v2ray", v2ray_protocol = "hysteria2", flag_obfs = true}) o.password = true o.rmempty = true -o:depends({type = "hysteria2", flag_obfs = true}) -local obfs = s.fields["obfs_type"].keylist -if obfs and type(obfs) == "table" and #obfs > 0 then - for _, v in ipairs(obfs) do - if v and v ~= "" then - o:depends({ - type = "v2ray", - v2ray_protocol = "hysteria2", - obfs_type = v, - flag_obfs = true - }) - end - end -end +o.placeholder = "cry_me_a_r1ver" o = s:option(Flag, "flag_quicparam", translate("Hysterir QUIC parameters")) o:depends("type", "hysteria2") @@ -778,13 +748,13 @@ o:depends("type", "shadowtls") if is_finded("sslocal") then o:value("sslocal", translate("ShadowSocks-rust Version")) end -if is_finded("xray") then +if is_finded("xray") or is_finded("v2ray") then o:value("vmess", translate("Vmess Protocol")) end o.default = "sslocal" o.rmempty = false -o = s:option(Value, "sslocal_password",translate("Shadowsocks Password")) +o = s:option(Value, "sslocal_password",translate("Shadowsocks password")) o:depends({type = "shadowtls", chain_type = "sslocal"}) o.rmempty = true @@ -818,7 +788,7 @@ o:depends("type", "tuic") --Tuic IP o = s:option(Value, "tuic_ip", translate("TUIC Server IP Address")) o.rmempty = true -o.datatype = "ipaddr" +o.datatype = "ip4addr" o.default = "" o:depends("type", "tuic") @@ -999,7 +969,7 @@ o = s:option(Value, "ws_heartbeatPeriod", translate("HeartbeatPeriod(second)")) o.datatype = "integer" o:depends("transport", "ws") -if is_finded("xray") then +if is_finded("v2ray") then -- WS前置数据 o = s:option(Value, "ws_ed", translate("Max Early Data")) o:depends("ws_ed_enable", true) @@ -1240,12 +1210,12 @@ o.default = "0" o.rmempty = true o = s:option(DynamicList, "local_addresses", translate("Local addresses")) ---o.datatype = "cidr" +o.datatype = "cidr" o:depends({type = "v2ray", v2ray_protocol = "wireguard"}) o.rmempty = true o = s:option(DynamicList, "reserved", translate("Reserved bytes(optional)")) -o.description = translate("Supports decimal numbers separated by \",\" or Base64-encoded strings, with a maximum length of 3 bytes.") +o.description = translate("Decimal numbers separated by \",\" or Base64-encoded strings.") o:depends({type = "v2ray", v2ray_protocol = "wireguard"}) o.rmempty = true @@ -1290,18 +1260,12 @@ o:depends("transport", "grpc") o = s:option(Flag, "enable_finalmask", translate("FinalMask")) o.rmempty = true o.default = "0" -local protocols = s.fields["v2ray_protocol"].keylist -if protocols and type(protocols) == "table" and #protocols > 0 then - for _, proto in ipairs(protocols) do - if not proto:find("^_") then - if proto == "hysteria2" then - o:depends({type = "v2ray", v2ray_protocol = "hysteria2", hysteria2_realms = false}) - elseif proto ~= "socks" and proto ~= "http" then - o:depends({type = "v2ray", v2ray_protocol = proto}) - end - end - end -end +o:depends({type = "v2ray", v2ray_protocol = "vless"}) +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 = "wireguard"}) +o:depends({type = "v2ray", v2ray_protocol = "hysteria2"}) o = s:option(TextValue, "finalmask", " ") o.description = translate("An FinalMaskObject in JSON format, used for sharing.") .. "
" .. @@ -1398,18 +1362,7 @@ if is_finded("xray") then o = s:option(Flag, "enable_ech", translate("Enable ECH(optional)")) o.rmempty = true o.default = "0" - local protocols = s.fields["v2ray_protocol"].keylist - if protocols and type(protocols) == "table" and #protocols > 0 then - for _, proto in ipairs(protocols) do - if not proto:find("^_") then - if proto == "hysteria2" then - o:depends({type = "v2ray", v2ray_protocol = "hysteria2", tls = true, hysteria2_realms = false}) - else - o:depends({type = "v2ray", v2ray_protocol = proto, tls = true}) - end - end - end - end + o:depends({type = "v2ray", tls = true}) o = s:option(TextValue, "ech_config", translate("ECH Config")) o.description = translate( @@ -1692,41 +1645,100 @@ o.rmempty = true o.default = "0" o:depends("type", "ssr") o:depends("type", "ss") -o:depends("type", "ss-rust") o:depends("type", "trojan") o:depends("type", "hysteria2") o:depends({type = "v2ray", v2ray_protocol = "vless", transport = "xhttp"}) o:depends({type = "v2ray", v2ray_protocol = "hysteria2"}) +o = s:option(ListValue, "domain_resolver", translate("Domain DNS Resolve")) +o.description = translate( + "
    " .. + "
  • " .. translate("If the node address is a domain name, this DNS will be used for resolution.") .. "
  • " .. + "
  • " .. string.format('%s', translate("Note: For node-specific DNS only. Keep Auto to avoid extra overhead.")) .. "
  • " .. + "
" +) +o:value("", translate("Auto")) +o:value("tcp", translate("TCP")) +o:value("udp", translate("UDP")) +o:value("https", translate("DoH")) +o:depends("type", "v2ray") + +o = s:option(Value, "domain_resolver_dns", translate("DNS")) +o.datatype = "or(ipaddr,ipaddrport)" +o:value("114.114.114.114") +o:value("223.5.5.5:53") +o.default = "114.114.114.114" +o:depends("domain_resolver", "tcp") +o:depends("domain_resolver", "udp") + +o = s:option(Value, "domain_resolver_dns_https", translate("DNS")) +o:value("https://120.53.53.53/dns-query", translate("DNSPod")) +o:value("https://223.5.5.5/dns-query", translate("AliDNS")) +o.default = "https://120.53.53.53/dns-query" +o:depends("domain_resolver", "https") + +o = s:option(ListValue, "domain_strategy", translate("Domain Strategy")) +o.description = translate( + "
    " .. + "
  • " .. translate("If is domain name, The requested domain name will be resolved to IP before connect.") .. "
  • " .. + "
  • " .. string.format('%s', translate("Note: For node-specific DNS only. Keep Auto to avoid extra overhead.")) .. "
  • " .. + "
" +) +o.default = "" +o:value("", translate("Auto")) +o:value("UseIPv4v6", translate("Prefer IPv4")) +o:value("UseIPv6v4", translate("Prefer IPv6")) +o:value("UseIPv4", translate("IPv4 Only")) +o:value("UseIPv6", translate("IPv6 Only")) +o:depends("type", "v2ray") + +local v2ray_protocols = s.fields["v2ray_protocol"] +if #v2ray_protocols > 0 then + for i, v in ipairs(v2ray_protocols) do + if not v:find("^_") then + s.fields["server"]:depends({ ["v2ray_protocol"] = v }) + s.fields["server_port"]:depends({ ["v2ray_protocol"] = v }) + s.fields["domain_resolver"]:depends({ ["v2ray_protocol"] = v }) + s.fields["domain_strategy"]:depends({ ["v2ray_protocol"] = v }) + + if v ~= "hysteria2" then + s.fields["fast_open"]:depends({ ["v2ray_protocol"] = v }) + s.fields["mptcp"]:depends({ ["v2ray_protocol"] = v }) + end + end + end +end + o = s:option(Flag, "switch_enable", translate("Enable Auto Switch")) o.rmempty = false o.default = "1" +o = s:option(Value, "local_port", translate("Local Port")) +o.datatype = "port" +o.default = 1234 +o.rmempty = false + if is_finded("kcptun-client") then o = s:option(Flag, "kcp_enable", translate("KcpTun Enable")) o.rmempty = true o.default = "0" o:depends("type", "ssr") - o:depends("type", "ss-rust") o:depends("type", "ss") o = s:option(Value, "kcp_port", translate("KcpTun Port")) o.datatype = "portrange" o.default = 4000 o:depends("type", "ssr") - o:depends("type", "ss-rust") o:depends("type", "ss") o = s:option(Value, "kcp_password", translate("KcpTun Password")) o.password = true o:depends("type", "ssr") - o:depends("type", "ss-rust") o:depends("type", "ss") o = s:option(Value, "kcp_param", translate("KcpTun Param")) o.default = "--nocomp" o:depends("type", "ssr") - o:depends("type", "ss-rust") o:depends("type", "ss") end 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 1fd8e775..7978c57b 100644 --- a/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua +++ b/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua @@ -4,7 +4,6 @@ local m, s, sec, o local uci = require "luci.model.uci".cursor() -local URL = require "url" -- 获取 LAN IP 地址 function lanip() @@ -32,62 +31,69 @@ end local lan_ip = lanip() local validation = require "luci.cbi.datatypes" -local clash_nodes = {} local function is_finded(e) - return luci.sys.exec(string.format('type -t -p "%s" -p "/usr/libexec/%s" 2>/dev/null', e, e)) ~= "" + return luci.sys.exec(string.format('type -t -p "%s" 2>/dev/null', e)) ~= "" end -local function clash_display_name(s) - if s.type ~= "clash" or not s.clash_url or s.clash_url == "" then - return nil - end - local ok, parsed = pcall(URL.parse, s.clash_url) - if ok and parsed and parsed.host then - return "[CLASH]:" .. parsed.host - end - return "[CLASH]" -end - -m = Map("shadowsocksr", translate("ShadowSocksR Plus+ Settings"), translate("

Support SS/SSR/V2RAY/XRAY/TROJAN/TUIC/HYSTERIA2/NAIVEPROXY/SOCKS5/CLASH etc.

")) +m = Map("shadowsocksr", translate("ShadowSocksR Plus+ Settings"), translate("

Support SS/SSR/V2RAY/XRAY/TROJAN/TUIC/HYSTERIA2/NAIVEPROXY/SOCKS5/TUN etc.

")) m:section(SimpleSection).template = "shadowsocksr/status" local server_table = {} -local server_order = {} uci:foreach("shadowsocksr", "servers", function(s) - if s.type == "clash" then - clash_nodes[s[".name"]] = true - end - - if s.type ~= "tun" and s.alias then + if s.alias then server_table[s[".name"]] = "[%s]:%s" % {string.upper(s.v2ray_protocol or s.type), s.alias} - elseif s.type ~= "tun" and s.server and s.server_port then + elseif s.server and s.server_port then server_table[s[".name"]] = "[%s]:%s:%s" % {string.upper(s.v2ray_protocol or s.type), s.server, s.server_port} - elseif s.type ~= "tun" then - local display_name = clash_display_name(s) - if display_name then - server_table[s[".name"]] = display_name - end - end - if s.type ~= "tun" and server_table[s[".name"]] then - table.insert(server_order, s[".name"]) end end) +local key_table = {} +for key, _ in pairs(server_table) do + table.insert(key_table, key) +end + +table.sort(key_table) + -- [[ Global Setting ]]-- s = m:section(TypedSection, "global") s.anonymous = true o = s:option(ListValue, "global_server", translate("Main Server")) o:value("nil", translate("Disable")) -for _, key in ipairs(server_order) do +for _, key in pairs(key_table) do o:value(key, server_table[key]) end o.default = "nil" o.rmempty = false -o = s:option(DummyValue, "_clash_panel", translate("Clash Panel")) -o.template = "shadowsocksr/clash_main_panel" -o.clash_nodes = clash_nodes +o = s:option(ListValue, "udp_relay_server", translate("Game Mode UDP Server")) +o:value("", translate("Disable")) +o:value("same", translate("Same as Global Server")) +for _, key in pairs(key_table) do + o:value(key, server_table[key]) +end + +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" +end + +-- [[ Use nftables/iptables ]]-- +o = s:option(ListValue, "prefer_nft", translate("Prefer firewall tools")) +o.default = "1" +o:value("0", "Iptables") +o:value("1", "Nftables") o = s:option(ListValue, "threads", translate("Multi Threads Option")) o:value("0", translate("Auto Threads")) @@ -106,6 +112,7 @@ o = s:option(ListValue, "run_mode", translate("Running Mode")) o:value("gfw", translate("GFW List Mode")) o:value("router", translate("IP Route Mode")) o:value("all", translate("Global Mode")) +o:value("oversea", translate("Oversea Mode")) o.default = gfw o = s:option(ListValue, "dports", translate("Proxy Ports")) @@ -121,13 +128,21 @@ o = s:option(ListValue, "pdnsd_enable", translate("Resolve Dns Mode")) 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")) + 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("7", translate("Prefer module built-in DNS")) o:value("0", translate("Use Local DNS Service listen port 5335")) o.default = 1 @@ -143,8 +158,11 @@ 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: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", "7") +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.default = "8.8.4.4:53" @@ -158,15 +176,61 @@ o:value("tcp://4.2.2.3:53,tcp://4.2.2.4:53", translate("Level 3 Public DNS-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 format as tcp://IP:PORT or tls://DOMAIN:PORT (tcp://8.8.8.8 or tls://dns.google:853)") -o.default = "tcp://8.8.4.4:53,tcp://8.8.8.8:53" -o = s:option(Flag, "filter_aaaa", translate("Disable IPv6 for Overseas FQDN")) -o:depends("pdnsd_enable", "1") +o = s:option(Flag, "mosdns_ipv6", translate("Disable IPv6 in MOSDNS query mode")) o:depends("pdnsd_enable", "4") -o:depends("pdnsd_enable", "7") 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)")) @@ -181,7 +245,6 @@ if is_finded("chinadns-ng") then 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.default = "8.8.4.4:53" o.description = translate( "
    " .. "
  • " .. translate("Custom DNS Server format as IP:PORT (default: 8.8.4.4:53)") .. "
  • " .. @@ -207,8 +270,11 @@ if is_finded("chinadns-ng") then o:value("101.226.4.6:53", translate("360 Security DNS (China Telecom) (101.226.4.6)")) o:value("123.125.81.6:53", translate("360 Security DNS (China Unicom) (123.125.81.6)")) 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.default = "wan" o.description = translate("Custom DNS Server format as IP:PORT (default: disabled)") o.validate = function(self, value, section) if (section and value) then @@ -227,7 +293,5 @@ if is_finded("chinadns-ng") then end end -m:append(Template("shadowsocksr/client_dns_defaults")) -m:append(Template("shadowsocksr/status_bottom")) - +m:section(SimpleSection).template = "shadowsocksr/status_bottom" return m diff --git a/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/component.lua b/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/component.lua deleted file mode 100644 index 8d670cd7..00000000 --- a/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/component.lua +++ /dev/null @@ -1,30 +0,0 @@ -local m, s, o - -m = SimpleForm( - "component_update", - translate("Component Update"), - translate("Check installed component versions and upgrade them online from the upstream release page.") -) -m.reset = false -m.submit = false - -s = m:section(SimpleSection) - -o = m:field(ListValue, "component_mirror", translate("Mirror URL")) -o:value("direct", translate("GitHub Direct")) -o:value("ghproxy", "mirror.ghproxy.com") -o:value("ghproxy_cc", "ghproxy.cc") -o:value("ghfast", "ghfast.top") -o:value("jsdelivr", "cdn.jsdelivr.net") -o.rmempty = false -o.cfgvalue = function(self) - return m.uci:get_first("shadowsocksr", "global", "component_mirror") or "direct" -end -o.write = function(self, section, value) - m.uci:set("shadowsocksr", "@global[0]", "component_mirror", value) - m.uci:commit("shadowsocksr") -end - -s.template = "shadowsocksr/component" - -return m 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 0d92887f..4d4367a7 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") @@ -125,6 +129,40 @@ o.remove = function(self, section, value) nixio.fs.writefile(denydomainconf, "") end +s:tab("netflix", translate("Netflix Domain List")) +local netflixconf = "/etc/ssrplus/netflix.list" +o = s:taboption("netflix", TextValue, "netflixconf") +o.rows = 13 +o.wrap = "off" +o.rmempty = true +o.cfgvalue = function(self, section) + return nixio.fs.readfile(netflixconf) or " " +end +o.write = function(self, section, value) + nixio.fs.writefile(netflixconf, value:gsub("\r\n", "\n")) +end +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) @@ -132,6 +170,4 @@ if luci.sys.call('[ -f "/www/luci-static/resources/uci.js" ]') == 0 then end end -m:append(Template("shadowsocksr/control_layout")) - return m diff --git a/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/log.lua b/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/log.lua index 6aa8328b..c7af1479 100644 --- a/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/log.lua +++ b/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/log.lua @@ -50,7 +50,6 @@ luci.http.setfilehandler(function(meta, chunk, eof) luci.sys.call("rm -rf " .. temp_dir) nixio.fs.remove(file_path) fd = nixio.open(file_path, "w") - luci.sys.call("ls /tmp/sub_md5_* >/dev/null 2>&1 && rm -f /tmp/sub_md5_*") luci.sys.call("echo '' > /var/log/ssrplus.log") end @@ -97,7 +96,6 @@ luci.http.setfilehandler(function(meta, chunk, eof) -- 清理临时文件 luci.sys.call("rm -rf " .. temp_dir) nixio.fs.remove(file_path) - luci.sys.call("ls /tmp/sub_md5_* >/dev/null 2>&1 && rm -f /tmp/sub_md5_*") end end) 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 2fdf777d..145c400f 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 @@ -7,39 +7,68 @@ require "nixio.fs" local m, s, o local sid = arg[1] --- ܷʽSS/SSRã local encrypt_methods = { - "rc4-md5", "rc4-md5-6", "rc4", "table", - "aes-128-cfb", "aes-192-cfb", "aes-256-cfb", - "aes-128-ctr", "aes-192-ctr", "aes-256-ctr", - "bf-cfb", "camellia-128-cfb", "camellia-192-cfb", "camellia-256-cfb", - "cast5-cfb", "des-cfb", "idea-cfb", "rc2-cfb", "seed-cfb", - "salsa20", "chacha20", "chacha20-ietf" + "rc4-md5", + "rc4-md5-6", + "rc4", + "table", + "aes-128-cfb", + "aes-192-cfb", + "aes-256-cfb", + "aes-128-ctr", + "aes-192-ctr", + "aes-256-ctr", + "bf-cfb", + "camellia-128-cfb", + "camellia-192-cfb", + "camellia-256-cfb", + "cast5-cfb", + "des-cfb", + "idea-cfb", + "rc2-cfb", + "seed-cfb", + "salsa20", + "chacha20", + "chacha20-ietf" } local encrypt_methods_ss = { - "aes-128-gcm", "aes-192-gcm", "aes-256-gcm", - "chacha20-ietf-poly1305", "xchacha20-ietf-poly1305", - "2022-blake3-aes-128-gcm", "2022-blake3-aes-256-gcm", "2022-blake3-chacha20-poly1305" -} - --- Shadowsocks ܷXray 棩 -local v_ss_encrypt_method_list = { - "aes-128-cfb", "aes-256-cfb", "aes-128-gcm", "aes-256-gcm", - "chacha20", "chacha20-ietf", "chacha20-poly1305", "chacha20-ietf-poly1305" -} - --- αװͣ mKCP/QUIC -local header_type_list = { - "none", "srtp", "utp", "wechat-video", "dtls", "wireguard" + -- aead + "aes-128-gcm", + "aes-192-gcm", + "aes-256-gcm", + "chacha20-ietf-poly1305", + "xchacha20-ietf-poly1305", + -- aead 2022 + "2022-blake3-aes-128-gcm", + "2022-blake3-aes-256-gcm", + "2022-blake3-chacha20-poly1305" + --[[ stream + "table", + "rc4", + "rc4-md5", + "aes-128-cfb", + "aes-192-cfb", + "aes-256-cfb", + "aes-128-ctr", + "aes-192-ctr", + "aes-256-ctr", + "bf-cfb", + "camellia-128-cfb", + "camellia-192-cfb", + "camellia-256-cfb", + "salsa20", + "chacha20", + "chacha20-ietf" ]] } local protocol = {"origin"} + obfs = {"plain", "http_simple", "http_post"} m = Map("shadowsocksr", translate("Edit ShadowSocksR Server")) -m.redirect = luci.dispatcher.build_url("admin/services/shadowsocksr/server") +m.redirect = luci.dispatcher.build_url("admin/services/shadowsocksr/server") if m.uci:get("shadowsocksr", sid) ~= "server_config" then luci.http.redirect(m.redirect) return @@ -50,26 +79,18 @@ s = m:section(NamedSection, sid, "server_config") s.anonymous = true s.addremove = false --- ========== ========== o = s:option(Flag, "enable", translate("Enable")) o.default = 1 o.rmempty = false o = s:option(ListValue, "type", translate("Server Type")) o:value("socks5", translate("Socks5")) -if nixio.fs.access("/usr/bin/mihomo") or nixio.fs.access("/usr/libexec/mihomo") or nixio.fs.access("/usr/bin/ssserver") or nixio.fs.access("/usr/libexec/ssserver") then +if nixio.fs.access("/usr/bin/ssserver") or nixio.fs.access("/usr/bin/ss-server") then o:value("ss", translate("ShadowSocks")) end if nixio.fs.access("/usr/bin/ssr-server") then o:value("ssr", translate("ShadowsocksR")) end --- Xray Э֧ -if nixio.fs.access("/usr/bin/xray") or nixio.fs.access("/usr/libexec/xray") then - o:value("vmess", "VMess (Xray)") - o:value("vless", "VLESS (Xray)") - o:value("trojan", "Trojan (Xray)") - o:value("shadowsocks", "Shadowsocks (Xray)") -end o.default = "socks5" o = s:option(Value, "server_port", translate("Server Port")) @@ -93,30 +114,32 @@ o:depends("type", "socks5") o = s:option(Value, "password", translate("Password")) o.password = true o.rmempty = false -o:depends("type", "socks5") -o:depends("type", "ss") -o:depends("type", "ssr") -o:depends("type", "trojan") -o:depends("type", "shadowsocks") --- ========== SS/SSR Э ========== o = s:option(ListValue, "encrypt_method", translate("Encrypt Method")) -for _, v in ipairs(encrypt_methods) do o:value(v) end +for _, v in ipairs(encrypt_methods) do + o:value(v) +end o.rmempty = false 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) end +for _, v in ipairs(encrypt_methods_ss) do + o:value(v) +end o.rmempty = false o:depends("type", "ss") o = s:option(ListValue, "protocol", translate("Protocol")) -for _, v in ipairs(protocol) do o:value(v) end +for _, v in ipairs(protocol) do + o:value(v) +end o.rmempty = false o:depends("type", "ssr") o = s:option(ListValue, "obfs", translate("Obfs")) -for _, v in ipairs(obfs) do o:value(v) end +for _, v in ipairs(obfs) do + o:value(v) +end o.rmempty = false o:depends("type", "ssr") @@ -128,269 +151,4 @@ o.rmempty = false o:depends("type", "ss") o:depends("type", "ssr") --- ========== Xray Эֶͨ ========== --- ûע -o = s:option(Value, "remarks", translate("Remarks")) -o.default = translate("Remarks") -o.rmempty = true -o:depends("type", "vmess") -o:depends("type", "vless") -o:depends("type", "trojan") -o:depends("type", "shadowsocks") - --- ûȼ -o = s:option(Value, "level", translate("User Level")) -o.datatype = "uinteger" -o.default = 1 -o.rmempty = true -o:depends("type", "vmess") -o:depends("type", "vless") -o:depends("type", "shadowsocks") -o:depends("type", "trojan") - --- ========== Xray Эֶ֤ ========== --- UUID ( vmess/vless) -o = s:option(Value, "uuid", translate("UUID")) -o.description = translate("Required for VMess/VLESS. Generate with: uuidgen") -o.rmempty = true -o:depends("type", "vmess") -o:depends("type", "vless") - --- Trojan -o = s:option(Value, "trojan_password", translate("Trojan Password")) -o.password = true -o.rmempty = true -o:depends("type", "trojan") - --- Shadowsocks ͼܣXray ã -o = s:option(Value, "ss_password", translate("Shadowsocks Password")) -o.password = true -o.rmempty = true -o:depends("type", "shadowsocks") - -o = s:option(ListValue, "ss_method", translate("Encrypt Method")) -for _, v in ipairs(v_ss_encrypt_method_list) do o:value(v) end -o.default = "chacha20-ietf-poly1305" -o.rmempty = true -o:depends("type", "shadowsocks") - -o = s:option(ListValue, "ss_network", translate("Transport")) -o:value("tcp", "TCP") -o:value("udp", "UDP") -o:value("tcp,udp", "TCP,UDP") -o.default = "tcp,udp" -o.rmempty = true -o:depends("type", "shadowsocks") - --- VMess alterId -o = s:option(Value, "alter_id", translate("Alter ID")) -o.datatype = "uinteger" -o.default = 0 -o.rmempty = true -o:depends("type", "vmess") - --- VLESS decryption -o = s:option(Value, "decryption", translate("Decryption")) -o.default = "none" -o.rmempty = true -o:depends("type", "vless") - --- ========== TLS / XTLS ========== -o = s:option(Flag, "tls", translate("TLS")) -o.default = 0 -o.rmempty = true -o:depends("type", "vmess") -o:depends("type", "vless") -o:depends("type", "trojan") -o:depends("type", "shadowsocks") - -o = s:option(Flag, "xtls", translate("XTLS")) -o.default = 0 -o.rmempty = true -o:depends({ type = "vless", tls = "1" }) - -o = s:option(ListValue, "flow", translate("Flow")) -o:value("xtls-rprx-origin", "xtls-rprx-origin") -o:value("xtls-rprx-origin-udp443", "xtls-rprx-origin-udp443") -o:value("xtls-rprx-direct", "xtls-rprx-direct") -o:value("xtls-rprx-direct-udp443", "xtls-rprx-direct-udp443") -o:value("xtls-rprx-splice", "xtls-rprx-splice") -o:value("xtls-rprx-splice-udp443", "xtls-rprx-splice-udp443") -o.default = "xtls-rprx-direct" -o.rmempty = true -o:depends("xtls", "1") - -o = s:option(Value, "tls_serverName", translate("Server Name (SNI)")) -o.rmempty = true -o:depends("tls", "1") - -o = s:option(Value, "tls_certificateFile", translate("Certificate File Path")) -o.description = translate("e.g.: /etc/ssl/fullchain.pem") -o.rmempty = true -o:depends("tls", "1") - -o = s:option(Value, "tls_keyFile", translate("Private Key File Path")) -o.description = translate("e.g.: /etc/ssl/private.key") -o.rmempty = true -o:depends("tls", "1") - --- ========== (Transport) ========== -o = s:option(ListValue, "transport", translate("Transport Protocol")) -o:value("tcp", "TCP") -o:value("mkcp", "mKCP") -o:value("ws", "WebSocket") -o:value("h2", "HTTP/2") -o:value("ds", "DomainSocket") -o:value("quic", "QUIC") -o.default = "tcp" -o.rmempty = true -o:depends("type", "vmess") -o:depends("type", "vless") -o:depends("type", "trojan") - --- ----- WebSocket ----- -o = s:option(Value, "ws_host", translate("WebSocket Host")) -o.rmempty = true -o:depends("transport", "ws") -o:depends("type", "vmess") -o:depends("type", "vless") -o:depends("type", "trojan") - -o = s:option(Value, "ws_path", translate("WebSocket Path")) -o.default = "/" -o.rmempty = true -o:depends("transport", "ws") -o:depends("type", "vmess") -o:depends("type", "vless") -o:depends("type", "trojan") - --- ----- HTTP/2 ----- -o = s:option(Value, "h2_host", translate("HTTP/2 Host")) -o.rmempty = true -o:depends("transport", "h2") -o:depends("type", "vmess") -o:depends("type", "vless") - -o = s:option(Value, "h2_path", translate("HTTP/2 Path")) -o.default = "/" -o.rmempty = true -o:depends("transport", "h2") -o:depends("type", "vmess") -o:depends("type", "vless") - --- ----- TCP αװ ----- -o = s:option(ListValue, "tcp_guise", translate("TCP Camouflage Type")) -o:value("none", "none") -o:value("http", "http") -o.default = "none" -o.rmempty = true -o:depends("transport", "tcp") -o:depends("type", "vmess") -o:depends("type", "vless") - -o = s:option(DynamicList, "tcp_guise_http_host", translate("HTTP Host")) -o.rmempty = true -o:depends("tcp_guise", "http") - -o = s:option(DynamicList, "tcp_guise_http_path", translate("HTTP Path")) -o.rmempty = true -o:depends("tcp_guise", "http") - --- ----- mKCP ----- -o = s:option(ListValue, "mkcp_guise", translate("mKCP Camouflage Type")) -for _, v in ipairs(header_type_list) do o:value(v) end -o.default = "none" -o.rmempty = true -o:depends("transport", "mkcp") - -o = s:option(Value, "mkcp_mtu", translate("KCP MTU")) -o.datatype = "uinteger" -o.default = 1350 -o.rmempty = true -o:depends("transport", "mkcp") - -o = s:option(Value, "mkcp_tti", translate("KCP TTI")) -o.datatype = "uinteger" -o.default = 20 -o.rmempty = true -o:depends("transport", "mkcp") - -o = s:option(Value, "mkcp_uplinkCapacity", translate("KCP Uplink Capacity")) -o.datatype = "uinteger" -o.default = 5 -o.rmempty = true -o:depends("transport", "mkcp") - -o = s:option(Value, "mkcp_downlinkCapacity", translate("KCP Downlink Capacity")) -o.datatype = "uinteger" -o.default = 20 -o.rmempty = true -o:depends("transport", "mkcp") - -o = s:option(Flag, "mkcp_congestion", translate("KCP Congestion Control")) -o.default = 0 -o.rmempty = true -o:depends("transport", "mkcp") - -o = s:option(Value, "mkcp_readBufferSize", translate("KCP Read Buffer Size")) -o.datatype = "uinteger" -o.default = 1 -o.rmempty = true -o:depends("transport", "mkcp") - -o = s:option(Value, "mkcp_writeBufferSize", translate("KCP Write Buffer Size")) -o.datatype = "uinteger" -o.default = 1 -o.rmempty = true -o:depends("transport", "mkcp") - -o = s:option(Value, "mkcp_seed", translate("KCP Seed")) -o.datatype = "uinteger" -o.rmempty = true -o:depends("transport", "mkcp") - --- ----- DomainSocket ----- -o = s:option(Value, "ds_path", translate("DomainSocket Path")) -o.description = translate("A legal file path. This file must not exist before running.") -o.rmempty = true -o:depends("transport", "ds") - --- ----- QUIC ----- -o = s:option(ListValue, "quic_security", translate("QUIC Security")) -o:value("none", "none") -o:value("aes-128-gcm", "aes-128-gcm") -o:value("chacha20-poly1305", "chacha20-poly1305") -o.default = "none" -o.rmempty = true -o:depends("transport", "quic") - -o = s:option(Value, "quic_key", translate("QUIC Key")) -o.rmempty = true -o:depends("transport", "quic") - -o = s:option(ListValue, "quic_guise", translate("QUIC Camouflage Type")) -for _, v in ipairs(header_type_list) do o:value(v) end -o.default = "none" -o.rmempty = true -o:depends("transport", "quic") - --- ========== ʿ ========== -o = s:option(Flag, "bind_local", translate("Bind Local Only")) -o.description = translate("When selected, it can only be accessed locally. Recommended when using reverse proxies.") -o.default = 0 -o.rmempty = true -o:depends("type", "vmess") -o:depends("type", "vless") -o:depends("type", "trojan") -o:depends("type", "shadowsocks") - -o = s:option(Flag, "accept_lan", translate("Accept LAN Access")) -o.description = translate("When selected, it can be accessed from LAN. This may not be safe!") -o.default = 0 -o.rmempty = true -o:depends("type", "vmess") -o:depends("type", "vless") -o:depends("type", "trojan") -o:depends("type", "shadowsocks") - -return m \ No newline at end of file +return m 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 c2ac03c6..db3160ab 100644 --- a/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server.lua +++ b/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server.lua @@ -105,13 +105,8 @@ end o.rmempty = false o = sec:option(DummyValue, "type", translate("Server Type")) -function o.cfgvalue(self, section) - local val = Value.cfgvalue(self, section) or "ss" - if val == "vmess" then return "VMess (Xray)" - elseif val == "vless" then return "VLESS (Xray)" - elseif val == "trojan" then return "Trojan (Xray)" - elseif val == "shadowsocks" then return "Shadowsocks (Xray)" - else return val end +function o.cfgvalue(...) + return Value.cfgvalue(...) or "ss" end o = sec:option(DummyValue, "server_port", translate("Server Port")) @@ -140,4 +135,4 @@ function o.cfgvalue(...) return Value.cfgvalue(...) or "-" end -return m \ No newline at end of file +return m 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 6e5e01e3..ac087f47 100644 --- a/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua +++ b/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua @@ -1,35 +1,36 @@ -- Licensed to the public under the GNU General Public License v3. require "luci.http" require "luci.sys" -require "luci.util" require "nixio.fs" require "luci.dispatcher" require "luci.model.uci" -local nixio = require "nixio" -local json = require "luci.jsonc" local cbi = require "luci.cbi" local uci = require "luci.model.uci".cursor() -local URL = require "url" local m, s, o, node local server_count = 0 -local server_cache = {} -local server_sections = {} -local detect_cache = {} -local CLASH_YAML_DIR = "/etc/ssrplus/clash" -local CLASH_YAML_HELPER = "/usr/share/shadowsocksr/clash_yaml.lua" -local DEFAULT_SERVER_PAGE_SIZE = 50 -local SERVER_PAGE_SIZE_OPTIONS = {25, 50, 100, 200, 0} +-- 确保正确判断程序是否存在 local function is_finded(e) - return luci.sys.exec(string.format('type -t -p "%s" -p "/usr/libexec/%s" 2>/dev/null', e, e)) ~= "" + return luci.sys.exec(string.format('type -t -p "%s" 2>/dev/null', e)) ~= "" end local function is_js_luci() return luci.sys.call('[ -f "/www/luci-static/resources/uci.js" ]') == 0 end --- 保存并应用行为 +local function url(...) + local url = string.format("admin/services/%s", "shadowsocksr") + local args = { ... } + for i, v in ipairs(args) do + if v and v ~= "" then + url = url .. "/" .. v + end + end + return require "luci.dispatcher".build_url(url) +end + +-- 默认的保存并应用行为 local function apply_redirect(m) local tmp_uci_file = "/etc/config/" .. "shadowsocksr" .. "_redirect" if m.redirect and m.redirect ~= "" then @@ -64,341 +65,50 @@ local function set_apply_on_parse(map) local old = map.on_after_save map.on_after_save = function(self) if old then old(self) end - -- map:set("@global[0]", "timestamp", os.time()) + map:set("@global[0]", "timestamp", os.time()) end end end -local function trim(text) - if not text or text == "" then - return "" - end - return (text:gsub("^%s*(.-)%s*$", "%1")) +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 has_trojan = is_finded("trojan") +local has_xray = is_finded("xray") +local has_hysteria2 = is_finded("hysteria") + +local ss_type_list = {} +local tj_type_list = {} +local hy2_type_list = {} + +if has_hysteria2 then + table.insert(hy2_type_list, { id = "hysteria2", name = translate("Hysteria2") }) +end +if has_xray then + table.insert(hy2_type_list, { id = "v2ray", name = translate("Xray (Hysteria2)") }) end -local function parse_nonnegative_int(value) - local number = tonumber(value) - if not number then - return nil - end - number = math.floor(number) - if number < 0 then - return nil - end - return number +if has_trojan then + table.insert(tj_type_list, { id = "trojan", name = translate("Trojan") }) +end +if has_xray then + table.insert(tj_type_list, { id = "v2ray", name = translate("Xray (Trojan)") }) end -local function in_list(list, target) - for _, item in ipairs(list) do - if item == target then - return true - end - end - return false +if has_ss_rust then + table.insert(ss_type_list, { id = "ss-rust", name = translate("ShadowSocks-rust Version") }) end - -local function upload_alias(filename) - local stem = tostring(filename or ""):gsub("\\", "/"):match("([^/]+)$") or "custom" - stem = stem:gsub("%.%w+$", "") - stem = trim(stem):gsub("[%c\r\n]+", " "):gsub("%s+", " ") - if stem == "" then - stem = "custom" - end - return "Clash_" .. stem +if has_ss_libev then + table.insert(ss_type_list, { id = "ss-libev", name = translate("ShadowSocks-libev Version") }) end - -local function hash_file(path) - local cmd = "md5sum " .. luci.util.shellquote(path) .. " 2>/dev/null | awk '{print $1}'" - return trim(luci.sys.exec(cmd)) +if has_xray then + table.insert(ss_type_list, { id = "v2ray", name = translate("Xray (ShadowSocks)") }) end -local function preprocess_clash_yaml(input_path, output_path) - local cmd = string.format( - "/usr/bin/lua %s prepare %s %s >/dev/null 2>&1", - luci.util.shellquote(CLASH_YAML_HELPER), - luci.util.shellquote(input_path), - luci.util.shellquote(output_path) - ) - return luci.sys.call(cmd) == 0 -end - -local function clash_path_in_use(path, exclude_sid) - local in_use = false - - uci:foreach("shadowsocksr", "servers", function(section) - if section[".name"] ~= exclude_sid and section.clash_path == path then - in_use = true - return false - end - end) - - return in_use -end - -local function cleanup_old_clash_path(old_path, new_path, sid) - if not old_path or old_path == "" or old_path == new_path then - return - end - if old_path:sub(1, #CLASH_YAML_DIR + 1) ~= CLASH_YAML_DIR .. "/" then - return - end - if clash_path_in_use(old_path, sid) then - return - end - nixio.fs.remove(old_path) -end - -local function find_uploaded_clash_section(upload_name, final_path) - local sid - - uci:foreach("shadowsocksr", "servers", function(section) - if section.type ~= "clash" or section.yaml_upload ~= "1" then - return - end - if upload_name ~= "" and section.yaml_upload_name == upload_name then - sid = section[".name"] - return false - end - if final_path ~= "" and section.clash_path == final_path then - sid = section[".name"] - return false - end - end) - - return sid -end - -local function save_uploaded_clash_node(upload_name, final_path) - local sid = find_uploaded_clash_section(upload_name, final_path) - local old_path - local alias - - if not sid then - sid = uci:add("shadowsocksr", "servers") - end - if not sid then - return nil - end - - old_path = uci:get("shadowsocksr", sid, "clash_path") - alias = uci:get("shadowsocksr", sid, "alias") - if not alias or alias == "" then - alias = upload_alias(upload_name) - end - - uci:set("shadowsocksr", sid, "type", "clash") - uci:set("shadowsocksr", sid, "alias", alias) - uci:set("shadowsocksr", sid, "server", "127.0.0.1") - uci:set("shadowsocksr", sid, "server_port", "0") - uci:delete("shadowsocksr", sid, "clash_url") - uci:set("shadowsocksr", sid, "clash_path", final_path) - uci:set("shadowsocksr", sid, "clash_user_agent", uci:get("shadowsocksr", sid, "clash_user_agent") or "clash") - if not uci:get("shadowsocksr", sid, "switch_enable") then - uci:set("shadowsocksr", sid, "switch_enable", uci:get_first("shadowsocksr", "server_subscribe", "switch", "1") or "1") - end - uci:set("shadowsocksr", sid, "yaml_upload", "1") - uci:set("shadowsocksr", sid, "yaml_upload_name", upload_name) - uci:save("shadowsocksr") - uci:commit("shadowsocksr") - - cleanup_old_clash_path(old_path, final_path, sid) - luci.sys.call(string.format("/etc/init.d/shadowsocksr clash_cache %s >/dev/null 2>&1 &", luci.util.shellquote(sid))) - return sid, alias -end - -local has_mihomo = is_finded("mihomo") -local upload_fd -local upload_tmp_path -local upload_filename -local upload_message -local upload_errmessage - -if has_mihomo then - luci.http.setfilehandler(function(meta, chunk, eof) - if not meta or meta.name ~= "clash_yaml_file" then - return - end - - if not upload_fd then - if not meta.file or meta.file == "" then - return - end - upload_filename = tostring(meta.file):gsub("[\r\n]", "") - upload_tmp_path = string.format("/tmp/ssrplus-clash-upload-%d-%d.yaml", nixio.getpid(), os.time()) - upload_fd = nixio.open(upload_tmp_path, "w") - if not upload_fd then - upload_errmessage = translate("Failed to create temporary YAML upload file.") - upload_tmp_path = nil - upload_filename = nil - return - end - end - - if chunk and upload_fd then - upload_fd:write(chunk) - end - - if eof and upload_fd then - upload_fd:close() - upload_fd = nil - end - end) - - if luci.http.formvalue("upload_clash_yaml") then - if not upload_tmp_path or not upload_filename or not nixio.fs.access(upload_tmp_path) then - upload_errmessage = upload_errmessage or translate("No custom YAML file was selected.") - else - local hash - local final_path - local tmp_output = string.format("%s/.upload-%d-%d.yaml", CLASH_YAML_DIR, nixio.getpid(), os.time()) - local sid - local alias - - nixio.fs.mkdirr(CLASH_YAML_DIR) - nixio.fs.remove(tmp_output) - if preprocess_clash_yaml(upload_tmp_path, tmp_output) then - hash = hash_file(tmp_output) - if hash == "" then - nixio.fs.remove(tmp_output) - upload_errmessage = translate("Uploaded YAML validation or preprocessing failed.") - else - final_path = string.format("%s/%s.yaml", CLASH_YAML_DIR, hash) - luci.sys.call(string.format("mv -f %s %s", luci.util.shellquote(tmp_output), luci.util.shellquote(final_path))) - sid, alias = save_uploaded_clash_node(upload_filename, final_path) - if sid then - upload_message = string.format(translate("Custom YAML imported successfully: %s"), alias or sid) - else - upload_errmessage = translate("Uploaded YAML validation or preprocessing failed.") - end - end - else - nixio.fs.remove(tmp_output) - upload_errmessage = translate("Uploaded YAML validation or preprocessing failed.") - end - end - - if upload_tmp_path then - nixio.fs.remove(upload_tmp_path) - end - end -end - -local function preserve_when_hidden(opt, controller, enabled_value) - local original_parse = opt.parse - - opt.parse = function(self, section, novld) - local current = self.map:get(section, controller) - if current == nil then - current = self.map:formvalue("cbid." .. self.map.config .. "." .. section .. "." .. controller) - end - if tostring(current or "") ~= tostring(enabled_value) then - return - end - return original_parse(self, section, novld) - end -end - -local function migrate_legacy_subscribe_urls() - local subscribe_sid = uci:get_first("shadowsocksr", "server_subscribe") - if not subscribe_sid then - return - end - - local legacy_urls = uci:get_list("shadowsocksr", subscribe_sid, "subscribe_url") or {} - if #legacy_urls == 0 then - return - end - - local has_items = false - uci:foreach("shadowsocksr", "server_subscribe_item", function() - has_items = true - return false - end) - if has_items then - return - end - - for index, url in ipairs(legacy_urls) do - local trimmed = trim(url) - if trimmed ~= "" then - local sid_output = luci.sys.exec("uci add shadowsocksr server_subscribe_item") - local sid = sid_output:match("%S+") - if sid and sid ~= "" then - local escaped_sid = luci.util.shellquote(sid) - local alias = string.format("Subscribe %d", index) - local escaped_alias = luci.util.shellquote(alias) - local escaped_url = luci.util.shellquote(trimmed) - luci.sys.call("uci set shadowsocksr." .. escaped_sid .. ".enabled=1") - luci.sys.call("uci set shadowsocksr." .. escaped_sid .. ".alias=" .. escaped_alias) - luci.sys.call("uci set shadowsocksr." .. escaped_sid .. ".url=" .. escaped_url) - end - end - end - - luci.sys.call("uci delete shadowsocksr." .. subscribe_sid .. ".subscribe_url") - luci.sys.call("uci commit shadowsocksr") -end - -local function clash_host_port(clash_url) - if not clash_url or clash_url == "" then - return nil, nil - end - local ok, parsed = pcall(URL.parse, clash_url) - if not ok or not parsed then - return nil, nil - end - local host = parsed.host - local port = parsed.port - if not port or port == "" then - port = (parsed.scheme == "http") and "80" or "443" - end - return host, port -end - -migrate_legacy_subscribe_urls() - uci:foreach("shadowsocksr", "servers", function(s) server_count = server_count + 1 - server_sections[#server_sections + 1] = s[".name"] - server_cache[s[".name"]] = { - type = s.type, - v2ray_protocol = s.v2ray_protocol, - alias = s.alias, - server_port = s.server_port, - server = s.server, - transport = s.transport, - ws_path = s.ws_path, - ws_host = s.ws_host, - tls_host = s.tls_host, - tls = s.tls, - reality = s.reality, - clash_url = s.clash_url - } end) -local function get_server(section) - return server_cache[section] or {} -end - -do - local raw = nixio.fs.readfile("/tmp/ssrplus_server_detect.json") - if raw and raw ~= "" then - local parsed = json.parse(raw) - if type(parsed) == "table" then - detect_cache = parsed - end - end -end - m = Map("shadowsocksr", translate("Servers subscription and manage")) -if upload_errmessage then - m.errmessage = upload_errmessage -elseif upload_message then - m.message = upload_message -end - -local style_section = m:section(SimpleSection) -style_section.template = "shadowsocksr/servers_subscribe_url_style" -- Server Subscribe s = m:section(TypedSection, "server_subscribe") @@ -408,13 +118,6 @@ o = s:option(Flag, "auto_update", translate("Auto Update")) o.rmempty = false o.description = translate("Auto Update Server subscription, GFW list and CHN route") -o = s:option(ListValue, "config_auto_update_mode", translate("Update Mode")) -o:value("0", translate("Appointment Mode")) -o:value("1", translate("Loop Mode")) -o.default = "0" -o.rmempty = true -o:depends("auto_update", "1") - o = s:option(ListValue, "auto_update_week_time", translate("Update cycle (Day/Week)")) o:value('*', translate("Every Day")) o:value("1", translate("Every Monday")) @@ -426,7 +129,7 @@ o:value("6", translate("Every Saturday")) o:value("0", translate("Every Sunday")) o.default = "*" o.rmempty = true -o:depends({auto_update = "1", config_auto_update_mode = "0"}) +o:depends("auto_update", "1") o = s:option(ListValue, "auto_update_day_time", translate("Regular update (Hour)")) for t = 0, 23 do @@ -434,7 +137,7 @@ for t = 0, 23 do end o.default = 2 o.rmempty = true -o:depends({auto_update = "1", config_auto_update_mode = "0"}) +o:depends("auto_update", "1") o = s:option(ListValue, "auto_update_min_time", translate("Regular update (Min)")) for i = 0, 59 do @@ -442,83 +145,178 @@ for i = 0, 59 do end o.default = 30 o.rmempty = true -o:depends({auto_update = "1", config_auto_update_mode = "0"}) +o:depends("auto_update", "1") -o = s:option(Value, "config_update_interval", translate("Update Interval(min)")) -o.default = "60" -o.datatype = "uinteger" +-- 确保 hy2_type_list 不为空 +if #hy2_type_list > 0 then + local sid = uci:get_first("shadowsocksr", "server_subscribe") + if not sid then + uci:foreach("shadowsocksr", "server_subscribe", function(section) + sid = section[".name"] + return false + end) + end + if sid then + local old_val = uci:get("shadowsocksr", sid, "xray_hy2_type") + if old_val and old_val ~= "" then + if (old_val == "hysteria2" and not has_hysteria2) or + (old_val == "v2ray" and not has_xray) then + -- 核心不可用,设置为空(删除配置) + uci:set("shadowsocksr", sid, "xray_hy2_type", "") + uci:commit("shadowsocksr") + end + end + end + o = s:option(ListValue, "xray_hy2_type", string.format("%s", translatef("%s Node Use Type", "Hysteria2"))) + o.description = translate("The configured type also applies to the core specified when manually importing nodes.") + o:value("", translate("Auto")) + for _, v in ipairs(hy2_type_list) do + o:value(v.id, v.name) -- 存储 "Xray" / "Hysteria2",但 UI 显示完整名称 + end +end + +-- 确保 tj_type_list 不为空 +if #tj_type_list > 0 then + local sid = uci:get_first("shadowsocksr", "server_subscribe") + if not sid then + uci:foreach("shadowsocksr", "server_subscribe", function(section) + sid = section[".name"] + return false + end) + end + if sid then + local old_val = uci:get("shadowsocksr", sid, "xray_tj_type") + if old_val and old_val ~= "" then + if (old_val == "trojan" and not has_trojan) or + (old_val == "v2ray" and not has_xray) then + -- 核心不可用,设置为空(删除配置) + uci:set("shadowsocksr", sid, "xray_tj_type", "") + uci:commit("shadowsocksr") + end + end + end + o = s:option(ListValue, "xray_tj_type", string.format("%s", translatef("%s Node Use Type", "Trojan"))) + o.description = translate("The configured type also applies to the core specified when manually importing nodes.") + o:value("", translate("Auto")) + for _, v in ipairs(tj_type_list) do + o:value(v.id, v.name) -- 存储 "Xray" / "Trojan",但 UI 显示完整名称 + end +end + +-- 确保 ss_type_list 不为空 +if #ss_type_list > 0 then + local sid = uci:get_first("shadowsocksr", "server_subscribe") + if not sid then + uci:foreach("shadowsocksr", "server_subscribe", function(section) + sid = section[".name"] + return false + end) + end + if sid then + local old_val = uci:get("shadowsocksr", sid, "ss_type") + if old_val and old_val ~= "" then + if (old_val == "ss-rust" and not has_ss_rust) or + (old_val == "ss-libev" and not has_ss_libev) or + (old_val == "v2ray" and not has_xray) then + -- 核心不可用,设置为空(删除配置) + uci:set("shadowsocksr", sid, "ss_type", "") + uci:commit("shadowsocksr") + end + end + end + o = s:option(ListValue, "ss_type", string.format("%s", translatef("%s Node Use Version", "ShadowSocks"))) + o.description = translate("Selection ShadowSocks Node Use Version.") + o:value("", translate("Auto")) + for _, v in ipairs(ss_type_list) do + o:value(v.id, v.name) -- 存储 "ss-libev" / "ss-rust",但 UI 显示完整名称 + end +end + +o = s:option(DynamicList, "subscribe_url", translate("Subscribe URL")) o.rmempty = true -o:depends({auto_update = "1", config_auto_update_mode = "1"}) -o = s:option(Flag, "_subscribe_advanced_toggle", translate("Subscribe Advanced Settings")) -o.rmempty = false -o.default = "0" -o.write = function() end -o.remove = function() end +o = s:option(ListValue, "domain_resolver", translate("Domain DNS Resolve")) +o.description = translate( + "
      " .. + "
    • " .. translate("If the node address is a domain name, this DNS will be used for resolution.") .. "
    • " .. + "
    • " .. string.format('%s', translate("Supports only Xray node types.")) .. "
    • " .. + "
    • " .. string.format('%s', translate("Note: For node-specific DNS only. Keep Auto to avoid extra overhead.")) .. "
    • " .. + "
    " +) +o:value("", translate("Auto")) +o:value("tcp", translate("TCP")) +o:value("udp", translate("UDP")) +o:value("https", translate("DoH")) + +o = s:option(Value, "domain_resolver_dns", translate("DNS")) +o.datatype = "or(ipaddr,ipaddrport)" +o:value("114.114.114.114") +o:value("223.5.5.5:53") +o.default = "114.114.114.114" +o:depends("domain_resolver", "tcp") +o:depends("domain_resolver", "udp") + +o = s:option(Value, "domain_resolver_dns_https", translate("DNS")) +o:value("https://120.53.53.53/dns-query", "DNSPod") +o:value("https://223.5.5.5/dns-query", "AliDNS") +o.default = o.keylist[1] +o:depends("domain_resolver", "https") + +o = s:option(ListValue, "domain_strategy", translate("Domain Strategy")) +o.description = translate( + "
      " .. + "
    • " .. translate("If is domain name, The requested domain name will be resolved to IP before connect.") .. "
    • " .. + "
    • " .. string.format('%s', translate("Supports only Xray node types.")) .. "
    • " .. + "
    • " .. string.format('%s', translate("Note: For node-specific DNS only. Keep Auto to avoid extra overhead.")) .. "
    • " .. + "
    " +) +o.default = "" +o:value("", translate("Auto")) +o:value("UseIPv4v6", translate("Prefer IPv4")) +o:value("UseIPv6v4", translate("Prefer IPv6")) +o:value("UseIPv4", translate("IPv4 Only")) +o:value("UseIPv6", translate("IPv6 Only")) o = s:option(Value, "filter_words", translate("Subscribe Filter Words")) o.rmempty = true o.description = translate("Filter Words splited by /") -o:depends("_subscribe_advanced_toggle", "1") -preserve_when_hidden(o, "_subscribe_advanced_toggle", "1") o = s:option(Value, "save_words", translate("Subscribe Save Words")) o.rmempty = true o.description = translate("Save Words splited by /") -o:depends("_subscribe_advanced_toggle", "1") -preserve_when_hidden(o, "_subscribe_advanced_toggle", "1") + +o = s:option(Button, "update_Sub", translate("Update Subscribe List")) +o.inputstyle = "reload" +o.description = translate("Update subscribe url list first") +o.write = function() + uci:commit("shadowsocksr") + luci.sys.exec("rm -rf /tmp/sub_md5_*") + 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:depends("_subscribe_advanced_toggle", "1") -preserve_when_hidden(o, "_subscribe_advanced_toggle", "1") o = s:option(Flag, "switch", translate("Subscribe Default Auto-Switch")) o.rmempty = false o.description = translate("Subscribe new add server default Auto-Switch on") o.default = "1" -o:depends("_subscribe_advanced_toggle", "1") -preserve_when_hidden(o, "_subscribe_advanced_toggle", "1") o = s:option(Flag, "proxy", translate("Through proxy update")) o.rmempty = false o.description = translate("Through proxy update list, Not Recommended ") -o.default = "1" -o:depends("_subscribe_advanced_toggle", "1") -preserve_when_hidden(o, "_subscribe_advanced_toggle", "1") - -o = s:option(Button, "_save_subscribe_settings", translate("Save Subscribe Settings")) -o.inputstyle = "save" -o.description = translate("Save current subscribe settings") -o.write = function() end o = s:option(Button, "subscribe", translate("Update All Subscribe Servers")) o.rawhtml = true o.template = "shadowsocksr/subscribe" -o.write = function(self, section) - self.map.ssr_subscribe_requested = true -end o = s:option(Button, "delete", translate("Delete All Subscribe Servers")) o.inputstyle = "reset" o.description = string.format(translate("Server Count") .. ": %d", server_count) o.write = function() - uci:delete_all("shadowsocksr", "servers", function(s) - if s.hashkey or s.isSubscribe then - return true - else - return false - end - end) - uci:save("shadowsocksr") - uci:commit("shadowsocksr") - for file in nixio.fs.glob("/tmp/sub_md5_*") do - nixio.fs.remove(file) - end - luci.http.redirect(luci.dispatcher.build_url("admin", "services", "shadowsocksr", "delete")) - return + luci.http.redirect(url("delete")) end o = s:option(Value, "url_test_url", translate("URL Test Address")) @@ -537,187 +335,57 @@ o:value("curl", "Curl") o:value("Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36 Edg/122.0.0.0", "Edge for Linux") o:value("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36 Edg/122.0.0.0", "Edge for Windows") o:value("v2rayN/9.99", "v2rayN") -o:depends("_subscribe_advanced_toggle", "1") -preserve_when_hidden(o, "_subscribe_advanced_toggle", "1") - -if has_mihomo then - o = s:option(DummyValue, "_upload_clash_yaml", translate("Upload Custom YAML File")) - o.template = "shadowsocksr/clash_yaml_upload" - o.description = translate("Upload a custom Clash/Mihomo YAML file. The file will be preprocessed and saved as a local Clash node.") -end - -s:append(cbi.Template("shadowsocksr/subscribe_schedule_compact")) - -s = m:section(TypedSection, "server_subscribe_item", translate("Subscribe URL")) -s.anonymous = true -s.addremove = true -s.sortable = true -s.template = "shadowsocksr/subscribe_actions_footer" ---s.template = "cbi/tblsection" ---s.template_addremove = "shadowsocksr/subscribe_actions_footer" -s.description = translate("Manage multiple subscribe URLs, including Clash subscriptions. Only enabled entries are included when updating all subscriptions.") - -o = s:option(Flag, "enabled", translate("Enable")) -o.rmempty = false -o.default = "1" -o.width = "1%" -function o.cfgvalue(...) - return Flag.cfgvalue(...) or "1" -end - -o = s:option(Value, "alias", translate("Alias")) -o.rmempty = true -o.width = "7.5rem" -function o.cfgvalue(self, section) - return Value.cfgvalue(self, section) or string.format("Subscribe %s", section:sub(-4)) -end - -o = s:option(Value, "url", translate("Subscribe URL")) -o.rmempty = false -- [[ Servers Manage ]]-- s = m:section(TypedSection, "servers") s.anonymous = true s.addremove = true -s.description = translate("Node order can be dragged with the mouse and takes effect immediately. The automatic switch order of server nodes is consistent with the node order in the table.") -s.template = "shadowsocksr/server_table" +s.template = "cbi/tblsection" set_apply_on_parse(m) -s:append(cbi.Template("shadowsocksr/optimize_cbi_ui")) -s.extedit = luci.dispatcher.build_url("admin", "services", "shadowsocksr", "servers", "%s") - -local server_page_size = parse_nonnegative_int(luci.http.formvalue("server_page_size")) -if not server_page_size or not in_list(SERVER_PAGE_SIZE_OPTIONS, server_page_size) then - server_page_size = DEFAULT_SERVER_PAGE_SIZE -end - -local server_page_count = 1 -if server_page_size > 0 and server_count > 0 then - server_page_count = math.ceil(server_count / server_page_size) -end - -local server_page = parse_nonnegative_int(luci.http.formvalue("server_page")) or 1 -if server_page < 1 then - server_page = 1 -end -if server_page > server_page_count then - server_page = server_page_count -end - -local visible_server_sections = server_sections -local server_first_index = server_count > 0 and 1 or 0 -local server_last_index = server_count - -if server_page_size > 0 then - local first = ((server_page - 1) * server_page_size) + 1 - local last = math.min(first + server_page_size - 1, server_count) - visible_server_sections = {} - server_first_index = server_count > 0 and first or 0 - server_last_index = server_count > 0 and last or 0 - - for index = first, last do - visible_server_sections[#visible_server_sections + 1] = server_sections[index] - end -end - s.sortable = true - -function s.cfgsections(self) - return visible_server_sections -end - -s.server_page = server_page -s.server_page_size = server_page_size -s.server_page_count = server_page_count -s.server_page_sizes = SERVER_PAGE_SIZE_OPTIONS -s.server_total = server_count -s.server_first_index = server_first_index -s.server_last_index = server_last_index -s.server_base_url = luci.dispatcher.build_url("admin", "services", "shadowsocksr", "servers") - +--[[ +s.extedit = url("servers", "%s") function s.create(self, ...) - local used_sid = {} - local next_sid = 1 - - self.map.uci:foreach(self.config, self.sectiontype, function(s) - local num = s[".name"]:match("^cfg(%x%x)") - if num then - local n = tonumber(num, 16) - if n then - used_sid[n] = true - end - end - end) - - local function get_next_sid() - while used_sid[next_sid] do - next_sid = next_sid + 1 - end - used_sid[next_sid] = true - return next_sid - end - - local sid = TypedSection.create(self, ...) - if sid then - local suffix = sid:sub(-4) + local sid = TypedSection.create(self, ...) + if sid then + local newsid = "cfg" .. sid:sub(-6) + -- 删除匿名 self.map.uci:delete(self.config, sid) - local id = get_next_sid() - local newsid = string.format("cfg%02x%s", id, suffix) - local success = self.map.uci:section(self.config, self.sectiontype, newsid) - if success then - --self.map.uci:save(self.config) - luci.http.redirect(self.extedit % newsid) - return - end - end + -- 重命名 section + self.map.uci:section(self.config, self.sectiontype, newsid) + luci.http.redirect(self.extedit % newsid) + return + end end +]]-- o = s:option(DummyValue, "type", translate("Type")) function o.cfgvalue(self, section) - local cfg = get_server(section) - return cfg.v2ray_protocol or cfg.type or translate("None") + return m:get(section, "v2ray_protocol") or Value.cfgvalue(self, section) or translate("None") end o = s:option(DummyValue, "alias", translate("Alias")) -function o.cfgvalue(self, section) - return get_server(section).alias or translate("None") +function o.cfgvalue(...) + return Value.cfgvalue(...) or translate("None") +end + +o = s:option(DummyValue, "server_port", translate("Server Port")) +function o.cfgvalue(...) + return Value.cfgvalue(...) or "N/A" end o = s:option(DummyValue, "server_port", translate("Socket Connected")) o.template = "shadowsocksr/socket" o.width = "10%" -function o.cfgvalue(self, section) - self.detect_cache = detect_cache[section] - local cfg = get_server(section) - local stype = cfg.type - if stype == "clash" then - return "N/A" - end - return cfg.server_port -end o.render = function(self, section, scope) - local cfg = get_server(section) - local stype = cfg.type - self.type = stype or "" - self.proto = cfg.v2ray_protocol or "" - self.reality = cfg.reality or "" - if stype == "clash" then - self.transport = "" - self.ws_path = "" - self.ws_host = "" - self.tls_host = "" - self.tls = "" - self.reality = "" - else - self.transport = cfg.transport or "" - self.ws_host = cfg.ws_host or "" - self.tls_host = cfg.tls_host or "" - if self.transport == 'ws' then - self.ws_path = cfg.ws_path or "" - self.tls = cfg.tls or "" - else - self.ws_path = "" - self.tls = "" - end + local cfg = s:cfgvalue(section) or {} + self.transport = cfg.transport + self.type = cfg.type + self.v2ray_protocol = cfg.v2ray_protocol + if self.transport == 'ws' then + self.ws_path = cfg.ws_path + self.tls = cfg.tls + self.tls_host = cfg.tls_host end DummyValue.render(self, section, scope) end @@ -725,15 +393,6 @@ end o = s:option(DummyValue, "server", translate("Ping Latency")) o.template = "shadowsocksr/ping" o.width = "10%" -function o.cfgvalue(self, section) - self.detect_cache = detect_cache[section] - local cfg = get_server(section) - self.type = cfg.type or "" - if cfg.type == "clash" then - return "N/A" - end - return cfg.server or "N/A" -end local global_server = uci:get_first('shadowsocksr', 'global', 'global_server') @@ -748,10 +407,11 @@ node.render = function(self, section, scope) Button.render(self, section, scope) end node.write = function(self, section) - local safe_section = luci.util.shellquote(section) - local cmd = string.format("uci set shadowsocksr.@global[0].global_server=%s && uci commit shadowsocksr", safe_section) - luci.sys.call(cmd) - luci.http.redirect(luci.dispatcher.build_url("admin", "services", "shadowsocksr", "restart")) + uci:set("shadowsocksr", '@global[0]', 'global_server', section) + uci:save("shadowsocksr") + uci:commit("shadowsocksr") + luci.sys.call("/etc/init.d/shadowsocksr restart >/dev/null 2>&1 &") + luci.http.redirect(url("restart")) end o = s:option(Flag, "switch_enable", translate("Auto Switch")) @@ -762,15 +422,4 @@ end m:append(cbi.Template("shadowsocksr/server_list")) -m.commit_handler = function(self) - if not self.ssr_subscribe_requested then - return - end - - for _, config in ipairs(self.parsechain or {}) do - self.uci:commit(config) - end - self.ssr_subscribe_autostart = true -end - return m 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 51b563d1..639486a9 100644 --- a/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua +++ b/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua @@ -7,22 +7,15 @@ local m, s, o local redir_run = 0 local reudp_run = 0 local sock5_run = 0 -local http_run = 0 local server_run = 0 local kcptun_run = 0 local tunnel_run = 0 local gfw_count = 0 local ad_count = 0 local ip_count = 0 -local Process_list = luci.sys.exec("busybox ps -w 2>/dev/null || busybox ps") +local nfip_count = 0 +local Process_list = luci.sys.exec("busybox ps -w") local uci = require "luci.model.uci".cursor() -local global_server = uci:get_first("shadowsocksr", "global", "global_server", "nil") -local global_type = global_server ~= "nil" and (uci:get("shadowsocksr", global_server, "type") or "") or "" -local global_socks_enabled = uci:get_first("shadowsocksr", "socks5_proxy", "enabled", "0") == "1" -local global_socks_server = uci:get_first("shadowsocksr", "socks5_proxy", "server", "nil") -local global_http_enabled = uci:get_first("shadowsocksr", "http_proxy", "enabled", "0") == "1" -local has_3proxy = nixio.fs.access("/usr/bin/3proxy") or nixio.fs.access("/usr/libexec/3proxy") or nixio.fs.access("/bin/3proxy") -local pdnsd_mode = uci:get_first("shadowsocksr", 'global', 'pdnsd_enable', '0') -- html constants font_blue = [[]] style_blue = [[]] @@ -59,6 +52,10 @@ if nixio.fs.access("/etc/ssrplus/applechina.conf") then apple_count = tonumber(luci.sys.exec("cat /etc/ssrplus/applechina.conf | wc -l")) end +if nixio.fs.access("/etc/ssrplus/netflixip.list") then + nfip_count = tonumber(luci.sys.exec("cat /etc/ssrplus/netflixip.list | wc -l")) +end + if Process_list:find("udp.only.ssr.reudp") then reudp_run = 1 end @@ -77,10 +74,6 @@ if Process_list:find("tcp.udp.ssr.local") then sock5_run = 1 end -if has_3proxy and Process_list:find("3proxy%-ssr%-http%.cfg") then - http_run = 1 -end - if Process_list:find("tcp.udp.ssr.retcp") then redir_run = 1 reudp_run = 1 @@ -110,38 +103,6 @@ if Process_list:find("local.udp.ssr.retcp") then sock5_run = 1 end -if global_type == "socks5" and Process_list:find("ipt2socks") then - if Process_list:find("%-T") or Process_list:find("%-%-tcp%-only") then - redir_run = 1 - end - if Process_list:find("%-U") or Process_list:find("%-%-udp%-only") then - reudp_run = 1 - end - if global_socks_enabled and (global_socks_server == "same" and global_socks_server == global_server) then - sock5_run = 1 - end -end - -if (global_type == "clash" or global_type == "tuic" or global_type == "ss") and Process_list:find("ssr%-retcp") then - redir_run = 1 - reudp_run = 1 - if global_socks_enabled and (global_socks_server == "same" and global_socks_server == global_server) then - sock5_run = 1 - end -end - -if (global_type == "clash" or global_type == "tuic" or global_type == "ss") and Process_list:find("mihomo") and (Process_list:find("/clash%-") or Process_list:find("/tuic%-") or Process_list:find("/ss%-")) then - redir_run = 1 - reudp_run = 1 - if global_socks_enabled and (global_socks_server == "same" and global_socks_server == global_server) then - sock5_run = 1 - end -end - -if has_3proxy and global_http_enabled and http_run == 0 and Process_list:find("3proxy%-ssr%-http%.cfg") then - http_run = 1 -end - if Process_list:find("kcptun.client") then kcptun_run = 1 end @@ -150,21 +111,11 @@ if Process_list:find("ssr.server") then server_run = 1 end -if Process_list:find("mihomo") and Process_list:find("/ss%-server%-") then - server_run = 1 -end - if Process_list:find("ssrplus/bin/dns2tcp") or Process_list:find("ssrplus/bin/mosdns") or - Process_list:find("chinadns.*127.0.0.1.*5335") then - pdnsd_run = 1 -end - -if pdnsd_mode == "7" and (global_type == "clash" or global_type == "tuic" or global_type == "ss") and Process_list:find("ssr%-retcp") then - pdnsd_run = 1 -end - -if pdnsd_mode == "7" and global_type == "v2ray" and Process_list:find("ssr%-retcp%.json") then + 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 @@ -206,16 +157,6 @@ else s.value = style_blue .. bold_on .. translate("Not Running") .. bold_off .. font_off end -if has_3proxy then - s = m:field(DummyValue, "http_run", translate("Global HTTP/HTTPS Proxy Server")) - s.rawhtml = true - if http_run == 1 then - s.value = font_blue .. bold_on .. translate("Running") .. bold_off .. font_off - else - s.value = style_blue .. bold_on .. translate("Not Running") .. bold_off .. font_off - end -end - s = m:field(DummyValue, "server_run", translate("Local Servers")) s.rawhtml = true if server_run == 1 then @@ -270,6 +211,13 @@ if uci:get_first("shadowsocksr", 'global', 'apple_optimization', '0') ~= '0' the s.value = apple_count .. " " .. translate("Records") end +if uci:get_first("shadowsocksr", 'global', 'netflix_enable', '0') ~= '0' then + s = m:field(DummyValue, "nfip_data", translate("Netflix IP Data")) + s.rawhtml = true + s.template = "shadowsocksr/refresh" + s.value = nfip_count .. " " .. translate("Records") +end + if uci:get_first("shadowsocksr", 'global', 'adblock', '0') == '1' then s = m:field(DummyValue, "ad_data", translate("Advertising Data")) s.rawhtml = true diff --git a/luci-app-ssr-plus/luasrc/view/shadowsocksr/advanced_switch_compact.htm b/luci-app-ssr-plus/luasrc/view/shadowsocksr/advanced_switch_compact.htm deleted file mode 100644 index c85245e8..00000000 --- a/luci-app-ssr-plus/luasrc/view/shadowsocksr/advanced_switch_compact.htm +++ /dev/null @@ -1,143 +0,0 @@ - - - diff --git a/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_main_panel.htm b/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_main_panel.htm deleted file mode 100644 index 724fbe0b..00000000 --- a/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_main_panel.htm +++ /dev/null @@ -1,1044 +0,0 @@ -<%+cbi/valueheader%> -<% -local clash_nodes = self.clash_nodes or {} -local current_sid = self.map:get(section, "global_server") or "nil" --%> -
    - - - - - - - - -
    - -
    -<%+cbi/valuefooter%> diff --git a/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_panel.htm b/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_panel.htm deleted file mode 100644 index 9d5cb765..00000000 --- a/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_panel.htm +++ /dev/null @@ -1,104 +0,0 @@ -<%+header%> - -

    <%:Clash Panel%> - <%=alias%>

    - -
    - <%:This panel is available only when the current Clash total node is active.%> -
    - -
    - -
    - -
    -
    - - - -<%+footer%> diff --git a/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_panel_button.htm b/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_panel_button.htm deleted file mode 100644 index fa9d23eb..00000000 --- a/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_panel_button.htm +++ /dev/null @@ -1,74 +0,0 @@ -<%+cbi/valueheader%> -<% -local stype = self.map:get(section, "type") --%> - -<% if stype == "clash" then %> - - - -<% else %> -- -<% end %> -<%+cbi/valuefooter%> diff --git a/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_yaml_upload.htm b/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_yaml_upload.htm deleted file mode 100644 index 830193af..00000000 --- a/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_yaml_upload.htm +++ /dev/null @@ -1,4 +0,0 @@ -<%+cbi/valueheader%> - - -<%+cbi/valuefooter%> diff --git a/luci-app-ssr-plus/luasrc/view/shadowsocksr/client_dns_defaults.htm b/luci-app-ssr-plus/luasrc/view/shadowsocksr/client_dns_defaults.htm deleted file mode 100644 index 9091257a..00000000 --- a/luci-app-ssr-plus/luasrc/view/shadowsocksr/client_dns_defaults.htm +++ /dev/null @@ -1,78 +0,0 @@ - diff --git a/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm b/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm deleted file mode 100644 index 87aee903..00000000 --- a/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm +++ /dev/null @@ -1,446 +0,0 @@ - - - - -
    - <%:Core Components%> -
    -
    -
    -
    -
    -
    -
    - <%:Download Source%> - <%:Address%> -
    - -
    -
    -
    - <%:Component%> - <%:Package Name%> -
    - -
    -
    -
    -
    -
    <%:Collecting data...%>
    -
    -
    - - -
    -
    -
    -
    -
    -
    -
    - -
    - <%:Geo Database Update%> -
    -
    -
    -
    -
    -
    -
    - <%:Database%> - <%:Geo Resource%> -
    - -
    -
    -
    -
    -
    <%:Collecting data...%>
    -
    -
    - -
    -
    -
    -
    -
    -
    -
    diff --git a/luci-app-ssr-plus/luasrc/view/shadowsocksr/control_layout.htm b/luci-app-ssr-plus/luasrc/view/shadowsocksr/control_layout.htm deleted file mode 100644 index c73c57c0..00000000 --- a/luci-app-ssr-plus/luasrc/view/shadowsocksr/control_layout.htm +++ /dev/null @@ -1,9 +0,0 @@ - diff --git a/luci-app-ssr-plus/luasrc/view/shadowsocksr/ping.htm b/luci-app-ssr-plus/luasrc/view/shadowsocksr/ping.htm index 1db85acb..5b396f7c 100644 --- a/luci-app-ssr-plus/luasrc/view/shadowsocksr/ping.htm +++ b/luci-app-ssr-plus/luasrc/view/shadowsocksr/ping.htm @@ -1,17 +1,3 @@ <%+cbi/valueheader%> -<% - local hint = self:cfgvalue(section) - local cache = self.detect_cache - local is_clash = self.type == "clash" - local text = is_clash and "N/A" or "--- ms" - local color = is_clash and "#999999" or "#ff0000" - if not is_clash and cache and tonumber(cache.ping or 0) > 0 then - local ping = tonumber(cache.ping) - text = tostring(ping) .. " ms" - if ping < 300 then color = "#ff3300" end - if ping < 200 then color = "#ff7700" end - if ping < 100 then color = "#249400" end - end -%> -<%=text%> +-- ms <%+cbi/valuefooter%> 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 5218cc27..0d0eb3c2 100644 --- a/luci-app-ssr-plus/luasrc/view/shadowsocksr/server_list.htm +++ b/luci-app-ssr-plus/luasrc/view/shadowsocksr/server_list.htm @@ -5,414 +5,747 @@ <% require "luci.sys" function is_js_luci() - return luci.sys.call('[ -f "/www/luci-static/resources/uci.js" ]') == 0 + return luci.sys.call('[ -f "/www/luci-static/resources/uci.js" ]') == 0 end -%> + + + + + <% if is_js_luci() then -%> <%- else %> <%- end %> + + + + +
    <%:Saving the new order...%>
    +
    + + +
    diff --git a/luci-app-ssr-plus/luasrc/view/shadowsocksr/server_table.htm b/luci-app-ssr-plus/luasrc/view/shadowsocksr/server_table.htm deleted file mode 100644 index 82b9eeaf..00000000 --- a/luci-app-ssr-plus/luasrc/view/shadowsocksr/server_table.htm +++ /dev/null @@ -1,304 +0,0 @@ -<%- -local rowcnt = 0 - -function rowstyle() - rowcnt = rowcnt + 1 - if rowcnt % 2 == 0 then - return " cbi-rowstyle-1" - else - return " cbi-rowstyle-2" - end -end - -function width(o) - if o.width then - if type(o.width) == "number" then - return ' style="width:%dpx"' % o.width - end - return ' style="width:%s"' % o.width - end - return "" -end - -local has_titles = false -local has_descriptions = false - -local anonclass = (not self.anonymous or self.sectiontitle) and "named" or "anonymous" -local titlename = ifattr(not self.anonymous or self.sectiontitle, "data-title", translate("Name")) - -local i, k -for i, k in pairs(self.children) do - if not k.typename then - k.typename = k.template and k.template:gsub("^.+/", "") or "" - end - - if not has_titles and k.title and #k.title > 0 then - has_titles = true - end - - if not has_descriptions and k.description and #k.description > 0 then - has_descriptions = true - end -end - -local total = tonumber(self.server_total) or 0 -local page = tonumber(self.server_page) or 1 -local page_size = tonumber(self.server_page_size) or 0 -local page_count = tonumber(self.server_page_count) or 1 -local first_index = tonumber(self.server_first_index) or 0 -local last_index = tonumber(self.server_last_index) or 0 -local page_sizes = self.server_page_sizes or {} -local base_url = self.server_base_url or "" - -local function page_url(target_page, target_size) - return string.format( - "%s?server_page=%d&server_page_size=%d", - base_url, - target_page, - target_size - ) -end - -function render_titles() - if not has_titles then - return - end - - %>><% - - local i, k - for i, k in ipairs(self.children) do - if not k.optional then - %>><% - - if k.titleref then - %>" class="cbi-title-ref" href="<%=k.titleref%>"><% - end - - write(k.title) - - if k.titleref then - %><% - end - - %><% - end - end - - if self.sortable or self.extedit or self.addremove then - %><% - end - - %><% - - rowcnt = rowcnt + 1 -end - -function render_descriptions() - if not has_descriptions then - return - end - - %><% - - local i, k - for i, k in ipairs(self.children) do - if not k.optional then - %>><% - - write(k.description) - - %><% - end - end - - if self.sortable or self.extedit or self.addremove then - %><% - end - - %><% - - rowcnt = rowcnt + 1 -end - -function render_pager() - if total == 0 then - return - end - - %> -
    - - <%=string.format(translate("Showing %d-%d of %d nodes"), first_index, last_index, total)%> - - - <% if page_count > 1 then %> - <% if page > 1 then %> - <%:Prev%> - <% end %> - <% for current = 1, page_count do %> - <% if current == page then %> - <%=current%> - <% else %> - <%=current%> - <% end %> - <% end %> - <% if page < page_count then %> - <%:Next%> - <% end %> - <% end %> - - - <%:Per page%>: - <% for _, size in ipairs(page_sizes) do %> - <% - local label = size == 0 and translate("All") or tostring(size) - local selected = size == page_size - %> - <% if selected then %> - <%=label%> - <% else %> - <%=label%> - <% end %> - <% end %> - -
    - - - <% -end --%> - - - - -
    - <% if self.title and #self.title > 0 then -%> -

    <%=self.title%>

    - <%- end %> - <%- if self.sortable then -%> - - <%- end -%> -
    <%=self.description%>
    - <% render_pager() %> - - <%- - render_titles() - render_descriptions() - - local isempty, section, i, k = true, nil, nil - for i, k in ipairs(self:cfgsections()) do - isempty = false - section = k - - local sectionname = striptags((type(self.sectiontitle) == "function") and self:sectiontitle(section) or k) - local sectiontitle = ifattr(sectionname and (not self.anonymous or self.sectiontitle), "data-title", sectionname, true) - local colorclass = (self.extedit or self.rowcolors) and rowstyle() or "" - local scope = { - valueheader = "cbi/cell_valueheader", - valuefooter = "cbi/cell_valuefooter" - } - -%> - > - <%- - local node - for k, node in ipairs(self.children) do - if not node.optional then - node:render(section, scope or {}) - end - end - -%> - - <%- if self.sortable or self.extedit or self.addremove then -%> - - <%- end -%> - - <%- end -%> - - <%- if isempty then -%> - - - - <%- end -%> -
    -
    - <% if self.extedit then -%> - onclick="location.href='<%=self.extedit:format(section)%>'" - <%- elseif type(self.extedit) == "function" then - %> onclick="location.href='<%=self:extedit(section)%>'" - <%- end - %> alt="<%:Edit%>" title="<%:Edit%>" /> - <% end; if self.addremove then %> - ', { - sid: sid - }, function(x, result) { - result = result || {}; - if (result.ret == 1) { - window.location.reload(); - return; - } - }); - return false; - " - /> - <%- end -%> -
    -
    <%:This section contains no values yet%>
    - <% render_pager() %> - - <% if self.error then %> -
    -
      <% for _, c in pairs(self.error) do for _, e in ipairs(c) do -%> -
    • <%=pcdata(e):gsub("\n", "
      ")%>
    • - <%- end end %>
    -
    - <% end %> - - <%- if self.addremove then -%> - <% if self.template_addremove then include(self.template_addremove) else -%> -
    - <% if self.anonymous then %> - - <% else %> - <% if self.invalid_cts then -%> -
    <%:Invalid%>
    - <%- end %> -
    - -
    - - <% end %> -
    - <%- end %> - <%- end -%> -
    - diff --git a/luci-app-ssr-plus/luasrc/view/shadowsocksr/servers_subscribe_url_style.htm b/luci-app-ssr-plus/luasrc/view/shadowsocksr/servers_subscribe_url_style.htm deleted file mode 100644 index 8451c3d5..00000000 --- a/luci-app-ssr-plus/luasrc/view/shadowsocksr/servers_subscribe_url_style.htm +++ /dev/null @@ -1,166 +0,0 @@ - diff --git a/luci-app-ssr-plus/luasrc/view/shadowsocksr/socket.htm b/luci-app-ssr-plus/luasrc/view/shadowsocksr/socket.htm index e4ce9535..74c6b1bf 100644 --- a/luci-app-ssr-plus/luasrc/view/shadowsocksr/socket.htm +++ b/luci-app-ssr-plus/luasrc/view/shadowsocksr/socket.htm @@ -1,26 +1,9 @@ <%+cbi/valueheader%> -<% - local hint = self:cfgvalue(section) - local cache = self.detect_cache - local text = "N/A" - local color = "#999999" - if cache then - if cache.socket then - text = "ok" - color = "#249400" - else - text = "fail" - color = "#ff0000" - end - end -%> -<%=text%> +wait - - - - - + + + <%+cbi/valuefooter%> diff --git a/luci-app-ssr-plus/luasrc/view/shadowsocksr/ssrurl.htm b/luci-app-ssr-plus/luasrc/view/shadowsocksr/ssrurl.htm index 025fd51b..b5610c2e 100644 --- a/luci-app-ssr-plus/luasrc/view/shadowsocksr/ssrurl.htm +++ b/luci-app-ssr-plus/luasrc/view/shadowsocksr/ssrurl.htm @@ -1,15 +1,25 @@ <%+cbi/valueheader%> <% local map = self.map +local ss_type = map:get("@server_subscribe[0]", "ss_type") +local xray_hy2_type = map:get("@server_subscribe[0]", "xray_hy2_type") +local xray_tj_type = map:get("@server_subscribe[0]", "xray_tj_type") local has_ss_rust = luci.sys.exec('type -t -p sslocal 2>/dev/null || type -t -p ssserver 2>/dev/null') ~= "" -local has_mihomo = luci.sys.exec('type -t -p mihomo -p /usr/libexec/mihomo 2>/dev/null') ~= "" +local has_ss_libev = luci.sys.exec('type -t -p ss-redir 2>/dev/null || type -t -p ss-local 2>/dev/null') ~= "" +local has_hysteria = luci.sys.exec('type -t -p hysteria 2>/dev/null') ~= "" +local has_trojan = luci.sys.exec('type -t -p trojan 2>/dev/null') ~= "" local has_xray = luci.sys.exec('type -t -p xray 2>/dev/null') ~= "" -%> - - /> - -
    - - + + + <%+cbi/valuefooter%> diff --git a/luci-app-ssr-plus/luasrc/view/shadowsocksr/subscribe_actions_footer.htm b/luci-app-ssr-plus/luasrc/view/shadowsocksr/subscribe_actions_footer.htm deleted file mode 100644 index e26d0398..00000000 --- a/luci-app-ssr-plus/luasrc/view/shadowsocksr/subscribe_actions_footer.htm +++ /dev/null @@ -1,490 +0,0 @@ -<%- -local rowcnt = 0 - -local function rowstyle() - rowcnt = rowcnt + 1 - if rowcnt % 2 == 0 then - return " cbi-rowstyle-1" - end - return " cbi-rowstyle-2" -end - -local function width(o) - if o.width then - if type(o.width) == "number" then - return ' style="width:%dpx"' % o.width - end - return ' style="width:%s"' % o.width - end - return "" -end --%> - -
    - <% if self.title and #self.title > 0 then -%> -

    <%=self.title%>

    - <%- end %> - <%- if self.sortable then -%> - - <%- end -%> -
    <%=self.description%>
    - - - <% for _, node in ipairs(self.children) do if not node.optional and node.option ~= "_update" then -%> - - <% end end -%> - - - - <% - local isempty = true - for i, section in ipairs(self:cfgsections()) do - isempty = false - local colorclass = rowstyle() - local scope = { - valueheader = "cbi/cell_valueheader", - valuefooter = "cbi/cell_valuefooter" - } - -%> - - <% - for _, node in ipairs(self.children) do - if not node.optional and node.option ~= "_update" then - node:render(section, scope) - end - end - local alias = self.map:get(section, "alias") or string.format("Subscribe %s", section:sub(-4)) - local update_title = "Subscribe: " .. tostring(alias) - -%> - - - <%- end -%> - - <%- if isempty then -%> - - - - <%- end -%> -
    ><%=node.title%><%:Actions%>
    -
    - - - - onclick="return window.ssrUpdateSubscribeItem(this)" - /> -
    -
    <%:This section contains no values yet%>
    -
    - -
    - - - -
    -
    -
    - - - - diff --git a/luci-app-ssr-plus/luasrc/view/shadowsocksr/subscribe_enabled_autosave.htm b/luci-app-ssr-plus/luasrc/view/shadowsocksr/subscribe_enabled_autosave.htm deleted file mode 100644 index 905727f7..00000000 --- a/luci-app-ssr-plus/luasrc/view/shadowsocksr/subscribe_enabled_autosave.htm +++ /dev/null @@ -1,47 +0,0 @@ - diff --git a/luci-app-ssr-plus/luasrc/view/shadowsocksr/subscribe_schedule_compact.htm b/luci-app-ssr-plus/luasrc/view/shadowsocksr/subscribe_schedule_compact.htm deleted file mode 100644 index 1290eb2f..00000000 --- a/luci-app-ssr-plus/luasrc/view/shadowsocksr/subscribe_schedule_compact.htm +++ /dev/null @@ -1,182 +0,0 @@ - - - diff --git a/luci-app-ssr-plus/po/templates/ssr-plus.pot b/luci-app-ssr-plus/po/templates/ssr-plus.pot index 9b28a755..266a8082 100644 --- a/luci-app-ssr-plus/po/templates/ssr-plus.pot +++ b/luci-app-ssr-plus/po/templates/ssr-plus.pot @@ -1,267 +1,254 @@ msgid "" msgstr "Content-Type: text/plain; charset=UTF-8" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:231 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:361 msgid "" "\"1-3\" is for segmentation at TCP layer, applying to the beginning 1 to 3 " "data writes by the client. \"tlshello\" is for TLS client hello packet " "fragmentation." msgstr "" +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:279 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:310 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:170 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:198 +msgid "%s Node Use Type" +msgstr "" + +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:409 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:227 +msgid "%s Node Use Version" +msgstr "" + #: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server.lua:103 msgid "0" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:94 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:100 msgid "1 Thread" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:101 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:107 msgid "128 Threads" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1570 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1523 msgid "16" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:98 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:104 msgid "16 Threads" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:95 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:101 msgid "2 Threads" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:99 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:105 msgid "32 Threads" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1390 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1354 msgid "360" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:207 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:270 msgid "360 Security DNS (China Telecom) (101.226.4.6)" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:208 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:271 msgid "360 Security DNS (China Unicom) (123.125.81.6)" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:96 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:102 msgid "4 Threads" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:100 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:106 msgid "64 Threads" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1557 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1510 msgid "8" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:97 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:103 msgid "8 Threads" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:260 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:390 msgid "" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1061 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1416 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1443 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1031 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1369 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1396 msgid "" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:51 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:38 msgid "" -"

    Support SS/SSR/V2RAY/XRAY/TROJAN/TUIC/HYSTERIA2/NAIVEPROXY/SOCKS5/CLASH " +"

    Support SS/SSR/V2RAY/XRAY/TROJAN/TUIC/HYSTERIA2/NAIVEPROXY/SOCKS5/TUN " "etc.

    " msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1233 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1550 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1563 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1576 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:186 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:160 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:186 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:220 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1203 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1503 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1516 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1529 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1655 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1682 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:188 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:214 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:249 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:240 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:267 msgid "
    • " msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:354 -msgid "A legal file path. This file must not exist before running." -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:387 -msgid "Accept LAN Access" -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/controller/shadowsocksr.lua:627 +#: applications/luci-app-ssr-plus/luasrc/controller/shadowsocksr.lua:58 msgid "Access Control" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_main_panel.htm:1035 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/subscribe_actions_footer.htm:235 -msgid "Actions" +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:178 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:206 +msgid "AdGuard DNSCrypt SDNS" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_main_panel.htm:1015 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/server_table.htm:290 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/server_table.htm:298 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/subscribe_actions_footer.htm:189 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/subscribe_actions_footer.htm:284 +#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/server_list.htm:749 msgid "Add" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/subscribe_actions_footer.htm:215 -msgid "Add failed:" -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/subscribe_actions_footer.htm:182 -msgid "Adding..." -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:221 -msgid "Additional Version" -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:378 -msgid "Address" -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/controller/shadowsocksr.lua:628 +#: applications/luci-app-ssr-plus/luasrc/controller/shadowsocksr.lua:59 msgid "Advanced Settings" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:274 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:222 msgid "Advertising Data" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:205 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1676 +msgid "AliDNS" +msgstr "" + +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:268 msgid "AliYun Public DNS (223.5.5.5)" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:568 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:680 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:367 msgid "Alias" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:373 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:397 msgid "Alias(optional)" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/server_table.htm:157 -msgid "All" -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:112 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:119 msgid "All Ports" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_main_panel.htm:965 -msgid "All client proxy rules cleared and applied." -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_main_panel.htm:965 -msgid "All client proxy rules cleared." -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/subscribe_actions_footer.htm:101 -msgid "All settings saved successfully." -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:35 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:39 msgid "Allow all except listed" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:34 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:38 msgid "Allow listed only" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:471 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:297 msgid "Allow subscribe Insecure nodes By default" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:34 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:120 -msgid "Already up to date" -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:186 -msgid "Alter ID" -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:907 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:877 msgid "AlterId" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1307 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1271 msgid "An FinalMaskObject in JSON format, used for sharing." msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:134 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:152 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:171 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:142 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:173 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:149 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:170 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:201 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:235 msgid "Anti-pollution DNS Server" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:128 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:125 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:206 +msgid "Anti-pollution DNS Server For Shunt Mode" +msgstr "" + +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:243 msgid "Apple Domains DNS" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:267 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:208 msgid "Apple Domains Data" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:123 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:238 msgid "Apple Domains Update url" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:119 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:234 msgid "Apple domains optimization" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:740 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:746 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:399 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:405 msgid "Apply" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:412 -msgid "Appointment Mode" -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/subscribe_actions_footer.htm:112 -msgid "Are you sure you want to delete subscribe link: %s ?" +#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/server_list.htm:391 +msgid "Are you sure to delete this node?" msgstr "" #: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/backup_restore.htm:133 msgid "Are you sure you want to restore the client to default settings?" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:757 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:282 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:313 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1660 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1688 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:172 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:200 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:229 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:246 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:274 +msgid "Auto" +msgstr "" + +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:417 msgid "Auto Switch" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:93 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:99 msgid "Auto Threads" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:407 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:117 msgid "Auto Update" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:409 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:119 msgid "Auto Update Server subscription, GFW list and CHN route" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:841 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1616 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1632 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:811 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1569 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1585 msgid "BBR" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1617 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1633 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1570 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1586 msgid "BRUTAL" msgstr "" @@ -273,72 +260,59 @@ msgstr "" msgid "Backup or Restore Client and Server Configurations." msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:252 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:193 msgid "Baidu Connectivity" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:206 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:269 msgid "Baidu Public DNS (180.76.76.76)" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/ssrurl.htm:297 +#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/ssrurl.htm:320 msgid "Base64 sstr failed." msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:378 -msgid "Bind Local Only" -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1184 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1194 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1154 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1164 msgid "BitTorrent (uTP)" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:96 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:100 msgid "Black Domain List" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:530 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:536 msgid "Bloom Filter" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:80 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:84 msgid "Bypass Domain List" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:261 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:439 -msgid "CHECK AND UPDATE" -msgstr "" - #: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/backup_restore.htm:31 msgid "CLOSE WIN" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:209 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:272 msgid "CNNIC SDNS (1.2.4.8)" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:842 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1618 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1636 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:812 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1571 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1589 msgid "CUBIC" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1201 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1171 msgid "Camouflage Domain" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:969 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1190 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:939 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1160 msgid "Camouflage Type" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:227 -msgid "Certificate File Path" -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1526 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1479 msgid "Certificate fingerprint" msgstr "" @@ -352,26 +326,15 @@ msgstr "" msgid "Check Server" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:280 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:228 msgid "Check Server Port" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:94 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:77 msgid "Check Try Count" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:157 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:405 -msgid "Check Update" -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/component.lua:6 -msgid "" -"Check installed component versions and upgrade them online from the upstream " -"release page." -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:89 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:72 msgid "Check timout(second)" msgstr "" @@ -380,127 +343,72 @@ msgstr "" msgid "Check..." msgstr "" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:146 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:250 -msgid "Checking..." -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:261 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:202 msgid "China IP Data" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:192 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:255 msgid "ChinaDNS-NG query protocol" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:113 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:226 +msgid "ChinaDNS-NG shunt query protocol" +msgstr "" + +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:89 msgid "Chnroute Update url" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:114 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:90 msgid "Clang.CN" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:115 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:91 msgid "Clang.CN.CIDR" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/controller/shadowsocksr.lua:376 -msgid "Clash" -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:88 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_main_panel.htm:817 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_main_panel.htm:1013 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_panel.htm:3 -msgid "Clash Panel" -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:392 -msgid "Clash Subscription URL" -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:404 -msgid "Clash User-Agent" -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:398 -msgid "Clash YAML Path" -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:352 -msgid "Clash/Mihomo" -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_main_panel.htm:1018 -msgid "Clear All Rules" -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_main_panel.htm:954 -msgid "Clear all custom client proxy rules and restore empty state?" -msgstr "" - #: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/log.htm:35 msgid "Clear logs" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:264 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1063 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1418 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1445 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:164 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:192 +msgid "Click here to view or manage the DNS list file" +msgstr "" + +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:394 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1033 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1371 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1398 msgid "Click to the page" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_main_panel.htm:1032 -msgid "Client" -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_main_panel.htm:920 -msgid "Client rules exported to CSV file." -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_main_panel.htm:944 -msgid "Client rules imported from CSV file. Click Save to apply." -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_main_panel.htm:1027 -msgid "Client supports manual IP or IP/CIDR input." -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_main_panel.htm:1024 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/subscribe.htm:251 -msgid "Close" -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:158 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:148 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:176 msgid "Cloudflare DNS" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:145 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:182 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:136 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:217 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:160 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:246 msgid "Cloudflare DNS (1.1.1.1)" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:402 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:436 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/status.htm:21 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:179 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:207 +msgid "Cloudflare DNSCrypt SDNS" +msgstr "" + +#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/status.htm:20 msgid "Collecting data..." msgstr "" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:390 -msgid "Component" -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/controller/shadowsocksr.lua:630 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/component.lua:5 -msgid "Component Update" -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1061 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1031 msgid "Configure XHTTP Extra Settings (JSON format), see:" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:839 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:809 msgid "Congestion control algorithm" msgstr "" @@ -512,227 +420,211 @@ msgstr "" msgid "Connect OK" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:82 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:103 msgid "Connection Timeout" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1429 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1382 msgid "" "Controls the policy used when performing DNS queries for ECH configuration." msgstr "" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/ssrurl.htm:90 +#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/ssrurl.htm:93 msgid "Copy SSR to clipboard successfully." msgstr "" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:369 -msgid "Core Components" -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:20 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:428 -msgid "Country MMDB" -msgstr "" - #: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/backup_restore.htm:2 msgid "Create Backup File" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1664 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1617 msgid "Create upload file error." msgstr "" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:110 -msgid "Current ARCH" -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1684 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1637 msgid "Current Certificate Path" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:219 -msgid "Current Version" -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:564 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:562 msgid "Custom" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_main_panel.htm:991 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_main_panel.htm:992 -msgid "Custom Client Proxies Rules" +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:182 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:210 +msgid "" +"Custom DNS Server (support: IP:Port or tls://IP:Port or https://IP/dns-query " +"and other format)." msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:148 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:187 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:139 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:221 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:166 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:250 msgid "Custom DNS Server format as IP:PORT (default: 8.8.4.4:53)" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:212 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:278 msgid "Custom DNS Server format as IP:PORT (default: disabled)" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:160 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:150 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:178 msgid "" "Custom DNS Server format as tcp://IP:PORT or tls://DOMAIN:PORT " "(tcp://8.8.8.8 or tls://dns.google:853)" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:568 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:566 msgid "Custom Plugin Path" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:114 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:121 msgid "Custom Ports" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:269 -msgid "Custom YAML imported successfully: %s" -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_main_panel.htm:708 -msgid "Custom client proxy rules saved and applied." -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_main_panel.htm:708 -msgid "Custom client proxy rules saved." -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1308 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1272 msgid "" "Custom finalmask overrides mkcp, hysteria2, fragment, noise, and related " "settings." msgstr "" +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:103 +msgid "Customize Netflix IP Url" +msgstr "" + #: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/backup_restore.htm:4 msgid "DL Backup" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1198 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1168 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1666 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1674 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:251 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:259 msgid "DNS" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:192 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:143 msgid "DNS Anti-pollution" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:204 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:106 +msgid "DNS Query Mode For Shunt Mode" +msgstr "" + +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1675 +msgid "DNSPod" +msgstr "" + +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:267 msgid "DNSPod Public DNS (119.29.29.29)" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1186 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1196 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1156 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1166 msgid "DTLS 1.2" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:424 -msgid "Database" +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1218 +msgid "Decimal numbers separated by \",\" or Base64-encoded strings." msgstr "" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/subscribe_schedule_compact.htm:87 -msgid "Day/Week" -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:193 -msgid "Decryption" -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1276 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1466 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1478 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1492 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1246 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1419 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1431 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1445 msgid "Default" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:101 -msgid "Default Node Local Port" -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1577 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1530 msgid "Default reject rejects traffic." msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:737 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:707 msgid "Default value 0 indicatesno heartbeat." msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1551 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1504 msgid "" "Default: disable. When entering a negative number, such as -1, The Mux " "module will not be used to carry TCP traffic." msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1564 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1517 msgid "" "Default:16. When entering a negative number, such as -1, The Mux module will " "not be used to carry UDP traffic, Use original UDP transmission method of " "proxy protocol." msgstr "" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_main_panel.htm:297 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_panel_button.htm:41 -msgid "Defaults Cleared!" +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:184 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:212 +msgid "Defines the upstreams logic mode" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_main_panel.htm:297 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_panel_button.htm:41 -msgid "Defaults Restored!" -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_main_panel.htm:1027 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:187 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:215 msgid "" -"Define per-client Mihomo proxy targets. Rules are injected as SRC-IP-CIDR " -"entries before the original Clash rules." +"Defines the upstreams logic mode, possible values: load_balance, parallel, " +"fastest_addr (default: load_balance)." msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:302 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:432 msgid "Delay (ms)" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_main_panel.htm:589 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/server_table.htm:248 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/subscribe_actions_footer.htm:261 +#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/server_list.htm:738 msgid "Delete" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:504 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:315 msgid "Delete All Subscribe Servers" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/subscribe_actions_footer.htm:130 -msgid "Delete failed:" -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:112 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:116 msgid "Deny Domain List" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:663 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:81 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:33 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:62 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:70 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:78 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:37 msgid "Disable" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:200 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:263 msgid "Disable ChinaDNS-NG" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:163 -msgid "Disable IPv6 for Overseas FQDN" +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:152 +msgid "Disable IPv6 In MosDNS Query Mode (Shunt Mode)" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:694 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:180 +msgid "Disable IPv6 in MOSDNS query mode" +msgstr "" + +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:197 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:226 +msgid "Disable IPv6 query mode" +msgstr "" + +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:664 msgid "Disable QUIC path MTU discovery" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:883 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:853 msgid "Disable SNI" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:764 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:734 msgid "Disable TCP No_delay" msgstr "" +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:149 +msgid "Dnsproxy Parse List" +msgstr "" + #: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/backup_restore.htm:18 msgid "Do Reset" msgstr "" @@ -741,114 +633,119 @@ msgstr "" msgid "Do you want to restore the client to default settings?" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:196 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1663 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:249 +msgid "DoH" +msgstr "" + +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:230 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:259 msgid "DoT upstream (Need use wolfssl version)" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:289 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1653 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:238 +msgid "Domain DNS Resolve" +msgstr "" + +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:419 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1680 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:265 msgid "Domain Strategy" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:353 -msgid "DomainSocket Path" -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:199 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:262 msgid "Domestic DNS Server" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1219 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1189 msgid "Downlink Capacity(Default:Mbps)" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:377 -msgid "Download Source" +#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/server_list.htm:739 +msgid "Drag to reorder" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:43 -msgid "Download failed" -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:894 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:864 msgid "Dual-stack Listening Socket" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1414 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1367 msgid "ECH Config" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1428 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1381 msgid "ECH Query Policy" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1011 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:981 msgid "Early Data Header Name" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/server_table.htm:240 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/server_table.htm:246 +#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/server_list.htm:737 msgid "Edit" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:307 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:40 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:259 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:69 msgid "Edit ShadowSocksR Server" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:157 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:198 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:278 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:54 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:271 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:408 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:82 #: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server.lua:101 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:560 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_main_panel.htm:1031 msgid "Enable" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:888 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:858 msgid "Enable 0-RTT QUIC handshake" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:474 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:482 msgid "Enable Authentication" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:80 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1701 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:63 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1712 msgid "Enable Auto Switch" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1398 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1362 msgid "Enable ECH(optional)" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:657 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:640 msgid "Enable Lazy Mode" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1436 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1389 msgid "Enable ML-DSA-65(optional)" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1595 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1548 msgid "" "Enable Multipath TCP, need to be enabled in both server and client " "configuration." msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1531 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1484 msgid "Enable Mux.Cool" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:651 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:95 +msgid "Enable Netflix Mode" +msgstr "" + +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:634 msgid "Enable Obfuscation" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:536 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:542 msgid "Enable Plugin" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:619 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:602 msgid "Enable Port Hopping" msgstr "" @@ -856,258 +753,200 @@ msgstr "" msgid "Enable Server" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:632 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:615 msgid "Enable Transport Protocol Settings" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:750 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:720 msgid "Enable V2 protocol." msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:749 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:719 msgid "Enable V3 protocol." msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:134 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:249 msgid "Enable adblock" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:525 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:531 msgid "Enable the SUoT protocol, requires server support." msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1054 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1024 msgid "Enable this option to configure XHTTP Extra (JSON format)." msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1231 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1201 msgid "Enabled Kernel virtual NIC TUN(optional)" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:181 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:335 msgid "Enabled Mixed" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:759 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1690 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:729 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1643 msgid "Enabling TCP Fast Open Requires Server Support." msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:503 #: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:510 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:791 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:802 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:933 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:103 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:108 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:171 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server.lua:127 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:517 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:761 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:772 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:903 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:118 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:125 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server.lua:122 msgid "Encrypt Method" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:115 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:122 msgid "Enter Custom Ports" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:419 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:122 msgid "Every Day" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:424 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:127 msgid "Every Friday" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:420 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:123 msgid "Every Monday" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:425 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:128 msgid "Every Saturday" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:426 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:129 msgid "Every Sunday" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:423 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:126 msgid "Every Thursday" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:421 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:124 msgid "Every Tuesday" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:422 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:125 msgid "Every Wednesday" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:606 -msgid "Example:" -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:223 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:289 msgid "Expecting: %s" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_main_panel.htm:1019 -msgid "Export Client Rules" +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:86 +msgid "External Proxy Mode" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:44 -msgid "Extract failed" -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1634 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1587 msgid "FORCE BRUTAL" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_main_panel.htm:967 -msgid "Failed to clear all client proxy rules." -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:42 -msgid "Failed to create temp directory" -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:230 -msgid "Failed to create temporary YAML upload file." -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:37 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:77 -msgid "Failed to fetch release metadata" -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:99 -msgid "Failed to query component information." -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:210 -msgid "Failed to query geo database information." -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_main_panel.htm:710 -msgid "Failed to save custom client proxy rules." -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:219 -msgid "File Not Exist" -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:461 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:282 msgid "Filter Words splited by /" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1290 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1260 msgid "FinalMask" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1382 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1346 msgid "Finger Print" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1369 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:212 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1333 msgid "Flow" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:119 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:234 msgid "" "For Apple domains equipped with Chinese mainland CDN, always responsive to " "Chinese CDN IP addresses" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:262 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:392 msgid "For specific usage, see:" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:626 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:609 msgid "" "Format as 10000:20000 or 10000-20000 Multiple groups are separated by commas " "(,)." msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:228 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:88 +msgid "Forward Netflix Proxy through Main Proxy" +msgstr "" + +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:358 msgid "Fragment" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:245 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:375 msgid "Fragment Delay" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:240 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:370 msgid "Fragment Length" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:231 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:361 msgid "Fragment Packets" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:245 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:375 msgid "Fragmentation interval (ms)" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:240 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:370 msgid "Fragmented packet length (byte)" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:256 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:197 msgid "GFW List Data" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:106 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:112 msgid "GFW List Mode" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:64 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:68 msgid "Game Mode Host List" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:183 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:134 msgid "Game Mode UDP Relay" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:859 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:69 +msgid "Game Mode UDP Server" +msgstr "" + +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:829 msgid "Garbage collection interval(second)" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:865 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:835 msgid "Garbage collection lifetime(second)" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:416 -msgid "Geo Database Update" -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:425 -msgid "Geo Resource" -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:24 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:429 -msgid "GeoSite Database" -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/component.lua:14 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:381 -msgid "GitHub Direct" -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:175 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:126 msgid "Global Client" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:194 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:210 -msgid "Global HTTP/HTTPS Proxy Server" -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:108 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:114 msgid "Global Mode" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:152 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:201 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:267 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:152 msgid "Global SOCKS5 Proxy Server" msgstr "" @@ -1115,25 +954,31 @@ msgstr "" msgid "Global Setting" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/server_table.htm:76 -msgid "Go to relevant configuration page" -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:248 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:189 msgid "Google Connectivity" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:153 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:174 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:202 +msgid "Google DNSCrypt SDNS" +msgstr "" + +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:143 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:171 msgid "Google Public DNS" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:135 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:172 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:126 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:207 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:150 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:236 msgid "Google Public DNS (8.8.4.4)" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:136 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:173 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:127 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:208 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:151 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:237 msgid "Google Public DNS (8.8.8.8)" msgstr "" @@ -1141,582 +986,481 @@ msgstr "" msgid "Grant UCI access for luci-app-ssr-plus" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1125 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1095 msgid "Gun" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1144 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1114 msgid "H2 Read Idle Timeout" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1139 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1109 msgid "H2/gRPC Health Check" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:421 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:972 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:453 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:942 msgid "HTTP" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:202 -msgid "HTTP Auth Mode" -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:976 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:291 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:946 msgid "HTTP Host" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:212 -msgid "HTTP Password" -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:981 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:295 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:951 msgid "HTTP Path" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:208 -msgid "HTTP User" -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:202 -msgid "HTTP proxy auth method, default:none." -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1107 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:268 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1077 msgid "HTTP/2 Host" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1112 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:274 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1082 msgid "HTTP/2 Path" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1179 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1149 msgid "Header" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1156 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1126 msgid "Health Check Timeout" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:847 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:817 msgid "Heartbeat interval(second)" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:998 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:968 msgid "HeartbeatPeriod(second)" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/subscribe_schedule_compact.htm:88 -msgid "Hour" -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1020 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:990 msgid "Httpupgrade Host" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1025 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:995 msgid "Httpupgrade Path" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/controller/shadowsocksr.lua:407 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:418 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:284 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:357 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:450 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:84 msgid "Hysteria2" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:598 -msgid "Hysteria2 Realms" -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:688 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:658 msgid "Hysterir QUIC parameters" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:107 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:113 msgid "IP Route Mode" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1490 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1443 msgid "IP Stack Preference" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:128 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1691 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:277 +msgid "IPv4 Only" +msgstr "" + +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1692 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:278 +msgid "IPv6 Only" +msgstr "" + +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:243 msgid "If empty, Not change Apple domains parsing DNS (Default is empty)" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1416 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1683 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:268 +msgid "" +"If is domain name, The requested domain name will be resolved to IP before " +"connect." +msgstr "" + +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1369 msgid "" "If it is not empty, it indicates that the Client has enabled Encrypted " "Client, see:" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:895 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1656 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:241 +msgid "" +"If the node address is a domain name, this DNS will be used for resolution." +msgstr "" + +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:865 msgid "If this option is not set, the socket behavior is platform dependent." msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1503 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1456 msgid "" "If true, allowss insecure connection at TLS client, e.g., TLS server uses " "unverifiable certificates." msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1648 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1601 msgid "If you have a self-signed certificate,please check the box" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/ssrurl.htm:1088 +#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/ssrurl.htm:1193 msgid "Import" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_main_panel.htm:1020 -msgid "Import Client Rules" -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/ssrurl.htm:195 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/ssrurl.htm:376 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/ssrurl.htm:520 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/ssrurl.htm:590 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/ssrurl.htm:624 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/ssrurl.htm:731 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/ssrurl.htm:847 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/ssrurl.htm:999 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/ssrurl.htm:1079 +#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/ssrurl.htm:249 +#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/ssrurl.htm:425 +#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/ssrurl.htm:597 +#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/ssrurl.htm:672 +#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/ssrurl.htm:706 +#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/ssrurl.htm:813 +#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/ssrurl.htm:952 +#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/ssrurl.htm:1104 +#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/ssrurl.htm:1184 msgid "Import configuration information successfully." msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1132 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1102 msgid "Initial Windows Size" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:48 -msgid "Install failed" -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:108 -msgid "Installed Version" -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:49 -msgid "Installed binary failed to run" -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:13 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:17 msgid "Interface" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:12 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:16 msgid "Interface control" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/server_table.htm:293 -msgid "Invalid" -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/ssrurl.htm:1082 +#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/ssrurl.htm:1187 msgid "Invalid format." msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:330 -msgid "KCP Congestion Control" -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:324 -msgid "KCP Downlink Capacity" -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:306 -msgid "KCP MTU" -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:335 -msgid "KCP Read Buffer Size" -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:347 -msgid "KCP Seed" -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:312 -msgid "KCP TTI" -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:318 -msgid "KCP Uplink Capacity" -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:341 -msgid "KCP Write Buffer Size" -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:231 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:172 msgid "KcpTun" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1706 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1722 msgid "KcpTun Enable" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1726 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1739 msgid "KcpTun Param" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1720 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1734 msgid "KcpTun Password" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1713 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1728 msgid "KcpTun Port" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:228 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:169 msgid "KcpTun Version" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:32 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:36 msgid "LAN Access Control" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:48 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:52 msgid "LAN Bypassed Host List" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:56 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:60 msgid "LAN Force Proxy Host List" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:38 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:42 msgid "LAN Host List" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:30 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:34 msgid "LAN IP AC" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:109 -msgid "Latest Version" -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:139 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:176 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:130 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:211 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:154 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:240 msgid "Level 3 Public DNS (209.244.0.3)" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:140 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:177 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:131 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:212 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:155 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:241 msgid "Level 3 Public DNS (209.244.0.4)" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:141 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:178 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:132 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:213 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:156 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:242 msgid "Level 3 Public DNS (4.2.2.1)" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:142 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:179 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:133 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:214 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:157 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:243 msgid "Level 3 Public DNS (4.2.2.2)" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:143 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:180 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:134 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:215 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:158 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:244 msgid "Level 3 Public DNS (4.2.2.3)" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:144 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:181 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:135 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:216 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:159 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:245 msgid "Level 3 Public DNS (4.2.2.4)" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:155 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:145 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:173 msgid "Level 3 Public DNS-1 (209.244.0.3-4)" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:156 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:146 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:174 msgid "Level 3 Public DNS-2 (4.2.2.1-2)" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:157 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:147 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:175 msgid "Level 3 Public DNS-3 (4.2.2.3-4)" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:250 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:380 msgid "Limit the maximum number of splits." msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1234 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1204 msgid "" "Linux kernel TUN virtual NIC requires system support and root privileges." msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:18 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:22 msgid "Listen only on the given interface or, if unspecified, on all" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_main_panel.htm:718 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_main_panel.htm:771 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_panel.htm:84 -msgid "Loading..." -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:187 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:217 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:348 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1716 msgid "Local Port" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:219 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:160 msgid "Local Servers" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1242 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1212 msgid "Local addresses" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/controller/shadowsocksr.lua:643 +#: applications/luci-app-ssr-plus/luasrc/controller/shadowsocksr.lua:66 msgid "Log" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:413 -msgid "Loop Mode" -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:109 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:85 msgid "Loukky/gfwlist-by-loukky" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:108 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:84 msgid "Loyalsoldier/v2ray-rules-dat" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1441 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1394 msgid "ML-DSA-65 Public key" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1595 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1548 msgid "MPTCP" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1205 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1175 msgid "MTU" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:80 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:61 msgid "Main Server" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:558 -msgid "" -"Manage multiple subscribe URLs, including Clash subscriptions. Only enabled " -"entries are included when updating all subscriptions." -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:38 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:78 -msgid "Matching release asset not found" -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1004 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:974 msgid "Max Early Data" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:250 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:380 msgid "Max Split" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:900 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:870 msgid "Maximum packet size the socks5 server can receive from external" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/controller/shadowsocksr.lua:372 -#: applications/luci-app-ssr-plus/luasrc/controller/shadowsocksr.lua:375 -#: applications/luci-app-ssr-plus/luasrc/controller/shadowsocksr.lua:378 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:9 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:395 -msgid "Mihomo" -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_main_panel.htm:1005 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_main_panel.htm:1006 -msgid "Mihomo Pannel" -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/subscribe_schedule_compact.htm:89 -msgid "Min" -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1565 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1518 msgid "" "Min value is 1, Max value is 1024. When omitted or set to 0, Will same path " "as TCP traffic." msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1552 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1505 msgid "" "Min value is 1, Max value is 128. When omitted or set to 0, it equals 8." msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/component.lua:13 -msgid "Mirror URL" -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:40 -msgid "Missing gzip support" -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:39 -msgid "Missing unzip support" -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:41 -msgid "Missing xz support" -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:181 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:335 msgid "Mixed as an alias of socks, default:Enabled." msgstr "" #: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/optimize_cbi_ui.htm:10 +#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/server_list.htm:735 msgid "Move down" msgstr "" #: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/optimize_cbi_ui.htm:7 +#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/server_list.htm:734 msgid "Move up" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:188 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:222 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:251 msgid "Muitiple DNS server can saperate with ','" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1126 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1096 msgid "Multi" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:92 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:98 msgid "Multi Threads Option" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1096 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1326 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1066 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1290 msgid "Must be JSON text!" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1531 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1484 msgid "Mux" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:138 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:253 msgid "NEO DEV HOST" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/status.htm:11 +#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/status.htm:10 msgid "NOT RUNNING" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/controller/shadowsocksr.lua:401 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:349 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:13 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:396 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:354 msgid "NaiveProxy" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/server_table.htm:27 -msgid "Name" -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:203 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:266 msgid "Nanjing Xinfeng 114DNS (114.114.114.114)" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:843 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:132 +msgid "Netflix Domain List" +msgstr "" + +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:215 +msgid "Netflix IP Data" +msgstr "" + +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:100 +msgid "Netflix IP Only" +msgstr "" + +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:77 +msgid "Netflix Node" +msgstr "" + +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:101 +msgid "Netflix and AWS" +msgstr "" + +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:369 +msgid "Network Tunnel" +msgstr "" + +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:399 +msgid "Network interface to use" +msgstr "" + +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:813 msgid "New Reno" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/server_table.htm:149 -msgid "Next" -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:249 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:253 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:282 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:116 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:190 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:194 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:230 msgid "No Check" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/ssrurl.htm:156 -msgid "No available Xray core to import this Hysteria2 node." +#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/ssrurl.htm:209 +msgid "No available core (Hysteria2 or Xray) to import this node." msgstr "" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/ssrurl.htm:546 +#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/ssrurl.htm:632 msgid "No available core (Shadowsocks or Xray) to import this node." msgstr "" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/ssrurl.htm:738 -msgid "No available core (Xray) to import this node." -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:249 -msgid "No custom YAML file was selected." -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_main_panel.htm:474 -msgid "No custom client proxy rules yet." +#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/ssrurl.htm:842 +msgid "No available core (Trojan or Xray) to import this node." msgstr "" #: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/refresh.htm:21 msgid "No new data!" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1680 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1633 msgid "No specify upload file." msgstr "" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/subscribe_actions_footer.htm:94 -msgid "No subscription items found" -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_main_panel.htm:615 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_panel.htm:32 -msgid "No switchable proxy groups found." -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:582 -msgid "" -"Node order can be dragged with the mouse and takes effect immediately. The " -"automatic switch order of server nodes is consistent with the node order in " -"the table." -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:255 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:385 msgid "Noise" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:544 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:971 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1170 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1182 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1192 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:677 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:682 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:549 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:941 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1140 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1152 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1162 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:364 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:369 msgid "None" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:180 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:188 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:197 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:206 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:215 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:224 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:236 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:131 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:139 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:148 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:157 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:165 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:177 msgid "Not Running" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:35 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:28 msgid "Not exist" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:108 -msgid "Not installed" +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1657 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1684 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:243 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:270 +msgid "Note: For node-specific DNS only. Keep Auto to avoid extra overhead." msgstr "" #: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/log.lua:27 @@ -1725,120 +1469,116 @@ msgid "" "compatibility issues." msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1606 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1559 msgid "Number of early established connections to reduce latency." msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:543 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:586 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:118 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server.lua:138 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:548 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:584 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:139 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server.lua:133 msgid "Obfs" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:593 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:123 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:591 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:146 msgid "Obfs param (optional)" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1226 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1196 msgid "Obfuscate password (optional)" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:670 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:651 msgid "Obfuscation Password" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:662 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:645 msgid "Obfuscation Type" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1515 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1468 msgid "Once set, connects only when the server’s chain fingerprint matches." msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:113 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:120 msgid "Only Common Ports" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:208 -msgid "Only when HTTP Auth Mode is password valid, Mandatory." -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:212 -msgid "Only when HTTP Auth Mode is password valid, Not mandatory." -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:170 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:324 msgid "Only when Socks5 Auth Mode is password valid, Mandatory." msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:175 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:329 msgid "Only when Socks5 Auth Mode is password valid, Not mandatory." msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:154 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:144 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:172 msgid "OpenDNS" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:138 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:175 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:129 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:210 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:153 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:239 msgid "OpenDNS (208.67.220.220)" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:137 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:174 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:128 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:209 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:152 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:238 msgid "OpenDNS (208.67.222.222)" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:391 -msgid "Package Name" +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:115 +msgid "Oversea Mode" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:261 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:161 +msgid "Oversea Mode DNS-1 (114.114.114.114)" +msgstr "" + +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:162 +msgid "Oversea Mode DNS-2 (114.114.115.115)" +msgstr "" + +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:391 msgid "Packet or Rand length as a string, e.g., 10-20." msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:298 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:428 msgid "Packet | Rand Length" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_panel_button.htm:68 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_panel_button.htm:69 -msgid "Panel" -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:488 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:93 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:496 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:114 msgid "Password" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/ssrurl.htm:102 +#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/ssrurl.htm:105 msgid "Paste sharing link here" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1257 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1227 msgid "Peer public key" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/server_table.htm:154 -msgid "Per page" -msgstr "" - #: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/reset.htm:14 #: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/reset.htm:23 msgid "Perform reset" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1162 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1132 msgid "Permit Without Stream" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:725 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:393 msgid "Ping Latency" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1687 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1640 msgid "Please confirm the current certificate path" msgstr "" @@ -1846,108 +1586,96 @@ msgstr "" msgid "Please fill in reset" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:387 -msgid "Please specify either a Clash subscription URL or a local YAML path." -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:572 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:570 msgid "Plugin Opts" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_main_panel.htm:1033 -msgid "Policy" -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:643 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:626 msgid "Port Hopping Interval(Unit:Second)" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:625 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:608 msgid "Port hopping range" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1606 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1559 msgid "Pre-connections" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1261 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1231 msgid "Pre-shared key" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:130 -msgid "Prefer module built-in DNS" +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1689 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:275 +msgid "Prefer IPv4" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/server_table.htm:139 -msgid "Prev" +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1690 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:276 +msgid "Prefer IPv6" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:232 -msgid "Private Key File Path" +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:93 +msgid "Prefer firewall tools" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1252 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1222 msgid "Private key" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:150 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:254 -msgid "Processing..." -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:576 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:113 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server.lua:133 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:574 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:132 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server.lua:128 msgid "Protocol" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:583 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:581 msgid "Protocol param (optional)" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:111 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:118 msgid "Proxy Ports" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1356 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1320 msgid "Public key" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:371 -msgid "QUIC Camouflage Type" -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1175 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:367 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1145 msgid "QUIC Key" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1168 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:359 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1138 msgid "QUIC Security" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:715 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:685 msgid "QUIC initConnReceiveWindow" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:701 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:671 msgid "QUIC initStreamReceiveWindow" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:722 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:692 msgid "QUIC maxConnReceiveWindow" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:729 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:699 msgid "QUIC maxIdleTimeout(Unit:second)" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:708 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:678 msgid "QUIC maxStreamReceiveWindow" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1351 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:177 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:205 +msgid "Quad9 DNSCrypt SDNS" +msgstr "" + +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1315 msgid "REALITY" msgstr "" @@ -1955,59 +1683,33 @@ msgstr "" msgid "RST Backup" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/controller/shadowsocksr.lua:429 #: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/status.htm:7 msgid "RUNNING" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/controller/shadowsocksr.lua:422 -msgid "RUNNING in %s (%s) Mode" -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/controller/shadowsocksr.lua:426 -msgid "RUNNING in %s Mode" -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_main_panel.htm:604 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_main_panel.htm:752 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_main_panel.htm:802 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_panel.htm:93 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:228 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/subscribe.htm:253 -msgid "Ready." -msgstr "" - #: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/reset.htm:5 msgid "Really reset all changes?" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:609 -msgid "Realm STUN" -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:606 -msgid "Realm URL" -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:744 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_main_panel.htm:272 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_panel_button.htm:17 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:403 msgid "Reapply" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:259 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:264 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:270 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:277 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:200 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:205 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:211 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:218 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:225 msgid "Records" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_panel.htm:10 -msgid "Refresh" +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:406 +msgid "Redirect traffic to this network interface" msgstr "" #: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/refresh.htm:29 #: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/refresh.htm:35 +#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/subscribe.htm:11 msgid "Refresh Data" msgstr "" @@ -2020,90 +1722,45 @@ msgid "Refresh OK!" msgstr "" #: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/refresh.htm:6 +#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/subscribe.htm:5 msgid "Refresh..." msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:431 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:134 msgid "Regular update (Hour)" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:439 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:142 msgid "Regular update (Min)" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:111 -msgid "Release Asset" -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_panel_button.htm:56 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_panel_button.htm:57 -msgid "Reload YAML" -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_main_panel.htm:265 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_panel_button.htm:10 -msgid "Reloading YAML..." -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:133 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:134 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_main_panel.htm:1034 -msgid "Remarks" -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1619 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1635 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1572 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1588 msgid "Reno" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:154 -msgid "Required for VMess/VLESS. Generate with: uuidgen" -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1247 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1217 msgid "Reserved bytes(optional)" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_main_panel.htm:998 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_main_panel.htm:999 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_panel_button.htm:62 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_panel_button.htm:63 -msgid "Reset Default Proxies Rules" -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_main_panel.htm:300 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_panel_button.htm:44 -msgid "Reset Defaults Failed!" -msgstr "" - #: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/reset.htm:17 #: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/reset.htm:18 msgid "Reset complete" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_main_panel.htm:286 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_panel_button.htm:30 -msgid "Reset saved Mihomo proxy-group selections and restore YAML defaults?" -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:144 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:259 msgid "Reset to defaults" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_main_panel.htm:290 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_panel_button.htm:34 -msgid "Resetting Defaults..." -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:120 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:127 msgid "Resolve Dns Mode" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:241 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:182 msgid "Restart Service" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:240 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:181 msgid "Restart ShadowSocksR Plus+" msgstr "" @@ -2116,92 +1773,91 @@ msgstr "" msgid "Restore to default configuration" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:178 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:186 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:195 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:204 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:213 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:222 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:234 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:129 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:137 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:146 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:155 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:163 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:175 msgid "Running" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:105 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:111 msgid "Running Mode" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/controller/shadowsocksr.lua:403 -msgid "SOCKS5" -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/ssrurl.htm:301 +#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/ssrurl.htm:342 msgid "SS URL base64 sstr format not recognized." msgstr "" -#: applications/luci-app-ssr-plus/luasrc/controller/shadowsocksr.lua:625 +#: applications/luci-app-ssr-plus/luasrc/controller/shadowsocksr.lua:56 msgid "SSR Client" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/controller/shadowsocksr.lua:629 +#: applications/luci-app-ssr-plus/luasrc/controller/shadowsocksr.lua:60 msgid "SSR Server" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_main_panel.htm:1023 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/subscribe_actions_footer.htm:260 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/subscribe_actions_footer.htm:285 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/subscribe_actions_footer.htm:286 -msgid "Save" +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:277 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:71 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:79 +msgid "Same as Global Server" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:492 -msgid "Save Subscribe Settings" +#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/server_list.htm:750 +msgid "Save Order" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:467 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:286 msgid "Save Words splited by /" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:494 -msgid "Save current subscribe settings" +#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/server_list.htm:484 +msgid "Save failed!" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/subscribe_actions_footer.htm:82 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/subscribe_actions_footer.htm:105 -msgid "Save failed:" +#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/server_list.htm:482 +msgid "Saved current page order successfully." msgstr "" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_main_panel.htm:687 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/subscribe_actions_footer.htm:51 -msgid "Saving..." +#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/server_list.htm:747 +msgid "Saving the new order..." msgstr "" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/advanced_switch_compact.htm:77 -msgid "Second" +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:158 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:186 +msgid "Select DNS parse Mode" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1640 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:410 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:228 +msgid "Selection ShadowSocks Node Use Version." +msgstr "" + +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1593 msgid "Self-signed Certificate" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:424 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:276 +msgid "Server" +msgstr "" + +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:456 msgid "Server Address" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:506 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:317 msgid "Server Count" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:223 -msgid "Server Name (SNI)" -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:335 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:340 msgid "Server Node Type" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:449 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:75 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server.lua:117 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:469 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:96 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server.lua:112 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:372 msgid "Server Port" msgstr "" @@ -2209,358 +1865,306 @@ msgstr "" msgid "Server Setting" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:58 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:86 #: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server.lua:107 msgid "Server Type" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:73 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:56 msgid "Server failsafe auto swith and custom update settings" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/controller/shadowsocksr.lua:626 +#: applications/luci-app-ssr-plus/luasrc/controller/shadowsocksr.lua:57 msgid "Servers Nodes" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:393 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:111 msgid "Servers subscription and manage" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1345 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1309 msgid "Session Ticket" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:358 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:558 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:167 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:195 +msgid "Set Single DNS" +msgstr "" + +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:363 msgid "Shadow-TLS" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:776 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:746 msgid "Shadow-TLS ChainPoxy type" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:343 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:346 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:413 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:61 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:348 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:445 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:89 msgid "ShadowSocks" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:779 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:415 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:101 +msgid "ShadowSocks-libev Version" +msgstr "" + +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:412 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:749 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:98 msgid "ShadowSocks-rust Version" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/controller/shadowsocksr.lua:622 +#: applications/luci-app-ssr-plus/luasrc/controller/shadowsocksr.lua:53 msgid "ShadowSocksR Plus+" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:51 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:38 msgid "ShadowSocksR Plus+ Settings" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/controller/shadowsocksr.lua:405 -msgid "ShadowTLS" +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:757 +msgid "Shadowsocks password" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/controller/shadowsocksr.lua:373 -msgid "Shadowsocks" -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:787 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:166 -msgid "Shadowsocks Password" -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/controller/shadowsocksr.lua:383 -msgid "Shadowsocks-rust" -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/controller/shadowsocksr.lua:381 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:340 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:64 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:345 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:92 msgid "ShadowsocksR" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1360 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1324 msgid "Short ID" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/server_table.htm:134 -msgid "Showing %d-%d of %d nodes" -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:685 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:377 msgid "Socket Connected" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:420 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:452 msgid "Socks" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:941 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:911 msgid "Socks Version" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:163 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:310 msgid "Socks protocol auth methods, default:noauth." msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:361 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:59 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:366 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:87 msgid "Socks5" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:163 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:310 msgid "Socks5 Auth Mode" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:175 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:329 msgid "Socks5 Password" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:170 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:324 msgid "Socks5 User" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/server_list.htm:73 -msgid "Start Detection" +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:151 +msgid "Specifically for edit dnsproxy DNS parse files." msgstr "" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/subscribe.htm:205 -msgid "Starting subscription update..." -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/controller/shadowsocksr.lua:631 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:114 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:116 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:118 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:120 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:224 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:226 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:228 +#: applications/luci-app-ssr-plus/luasrc/controller/shadowsocksr.lua:61 msgid "Status" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/server_list.htm:74 -msgid "Stop Detection" -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:453 -msgid "Subscribe Advanced Settings" -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:478 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:302 msgid "Subscribe Default Auto-Switch" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:459 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:280 msgid "Subscribe Filter Words" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/subscribe.htm:250 -msgid "Subscribe Log" -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:465 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:284 msgid "Subscribe Save Words" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:551 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:575 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:235 msgid "Subscribe URL" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/subscribe.htm:194 -msgid "Subscribe failed, refreshing page..." -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:480 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:304 msgid "Subscribe new add server default Auto-Switch on" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:473 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:299 msgid "Subscribe nodes allows insecure connection as TLS client (insecure)" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:142 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:257 msgid "Support AdGuardHome and DNSMASQ format list" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:644 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:627 msgid "Supports a fixed value or a random range (e.g., 30, 5-30), minimum 5." msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1248 -msgid "" -"Supports decimal numbers separated by \",\" or Base64-encoded strings, with " -"a maximum length of 3 bytes." +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:242 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:269 +msgid "Supports only Xray node types." msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:84 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:67 msgid "Switch check cycly(second)" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_main_panel.htm:654 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_panel.htm:71 -msgid "Switch failed." +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1661 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:247 +msgid "TCP" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_main_panel.htm:651 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_panel.htm:68 -msgid "Switched successfully." -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_main_panel.htm:644 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_panel.htm:61 -msgid "Switching..." -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:282 -msgid "TCP Camouflage Type" -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:759 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1690 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:126 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:729 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1643 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:149 msgid "TCP Fast Open" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:228 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:358 msgid "" "TCP fragments, which can deceive the censorship system in some cases, such " "as bypassing SNI blacklists." msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:194 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:228 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:257 msgid "TCP upstream" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1331 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:199 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1295 msgid "TLS" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:754 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:724 msgid "TLS 1.3 Strict mode" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1464 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1417 msgid "TLS ALPN" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1520 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1473 msgid "TLS Certificate Name (CertName)" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1515 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1468 msgid "TLS Chain Fingerprint (SHA256)" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1456 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1409 msgid "TLS Host" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1520 +#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/server_list.htm:539 +msgid "TLS handshake test, latency for reference only" +msgstr "" + +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1473 msgid "TLS is used to verify the leaf certificate name." msgstr "" -#: applications/luci-app-ssr-plus/luasrc/controller/shadowsocksr.lua:379 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:355 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:360 msgid "TUIC" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1476 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1429 msgid "TUIC ALPN" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:819 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:789 msgid "TUIC Server IP Address" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:826 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:796 msgid "TUIC User Password" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:812 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:782 msgid "TUIC User UUID" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:877 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:847 msgid "TUIC receive window" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:871 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:841 msgid "TUIC send window" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1443 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:175 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:203 +msgid "TWNIC-101 DNSCrypt SDNS" +msgstr "" + +#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/server_list.htm:539 +#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/server_list.htm:604 +#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/server_list.htm:628 +msgid "Test" +msgstr "" + +#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/server_list.htm:581 +msgid "Testing..." +msgstr "" + +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1396 msgid "" "The client has not configured mldsa65Verify, but it will not perform the " "\"additional verification\" step and can still connect normally, see:" msgstr "" +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:280 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:311 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:171 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:199 +msgid "" +"The configured type also applies to the core specified when manually " +"importing nodes." +msgstr "" + #: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/reset.htm:10 msgid "The content entered is incorrect!" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:736 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:706 msgid "The keep-alive period.(Unit:second)" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:6 -msgid "" -"The online upgrade downloads the matching Xray-core linux archive for the " -"current ARCH from the official GitHub release page." -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:10 -msgid "" -"The online upgrade only tracks the latest stable Mihomo release and " -"downloads the matching linux archive for the current ARCH from the official " -"GitHub release page." -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:14 -msgid "" -"The online upgrade tracks the latest NaiveProxy release and prefers OpenWrt " -"static archives matching the current ARCH before falling back to other " -"release assets." -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_main_panel.htm:740 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_main_panel.htm:795 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_panel.htm:89 -msgid "This Clash total node is not active. Apply this node first." -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_panel.htm:6 -msgid "" -"This panel is available only when the current Clash total node is active." -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/server_table.htm:272 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/subscribe_actions_footer.htm:126 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/subscribe_actions_footer.htm:277 -msgid "This section contains no values yet" -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:485 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:307 msgid "Through proxy update" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:487 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:309 msgid "Through proxy update list, Not Recommended" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/advanced_switch_compact.htm:78 -msgid "Timeout" -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:853 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:823 msgid "Timeout for establishing a connection to server(second)" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:260 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:162 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:190 +msgid "Tips: Dnsproxy DNS Parse List Path:" +msgstr "" + +#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/server_list.htm:736 +msgid "To Bottom" +msgstr "" + +#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/server_list.htm:733 +msgid "To Top" +msgstr "" + +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:390 msgid "To send noise packets, select \"Noise\" in Xray Settings." msgstr "" @@ -2568,57 +2172,53 @@ msgstr "" msgid "Total Records:" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:950 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:177 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:920 msgid "Transport" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:637 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:238 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:620 msgid "Transport Protocol" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/controller/shadowsocksr.lua:399 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:412 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:315 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:351 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:444 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:91 msgid "Trojan" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:160 -msgid "Trojan Password" -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/advanced_switch_compact.htm:79 -msgid "Try Count" -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:282 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:674 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:412 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:362 msgid "Type" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:639 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:622 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1662 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:248 msgid "UDP" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:255 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:385 msgid "" "UDP noise, Under some circumstances it can bypass some UDP based protocol " "restrictions." msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:524 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:530 msgid "UDP over TCP" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:832 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:802 msgid "UDP relay mode" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:195 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:229 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:258 msgid "UDP upstream" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:193 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:227 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:256 msgid "UDP/TCP upstream" msgstr "" @@ -2626,558 +2226,494 @@ msgstr "" msgid "UL Restore" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:524 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:322 msgid "URL Test Address" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:153 -msgid "UUID" -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/ssrurl.htm:92 +#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/ssrurl.htm:95 msgid "Unable to copy SSR to clipboard." msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:32 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:42 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:109 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:110 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:111 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:226 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:25 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:35 msgid "Unknown" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:80 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/subscribe_actions_footer.htm:82 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/subscribe_actions_footer.htm:130 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/subscribe_actions_footer.htm:215 -msgid "Unknown error" -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:36 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:76 -msgid "Unsupported ARCH" -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:79 -msgid "Unsupported component" -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/subscribe_actions_footer.htm:265 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/subscribe_actions_footer.htm:266 -msgid "Update" -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:497 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:311 +#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/subscribe.htm:16 msgid "Update All Subscribe Servers" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:447 -msgid "Update Interval(min)" +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:288 +msgid "Update Subscribe List" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:411 -msgid "Update Mode" -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:418 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:121 msgid "Update cycle (Day/Week)" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:29 -msgid "" -"Update geoip.dat and geosite.dat used by Xray/V2Ray runtime when available." +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:290 +msgid "Update subscribe url list first" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:21 -msgid "" -"Update the Country.mmdb database used by Mihomo/Clash runtime when available." -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:25 -msgid "" -"Update the GeoSite.dat database used by Mihomo/Clash runtime when available." -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/subscribe_actions_footer.htm:31 -msgid "Updating..." -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:157 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:406 -msgid "Upgrade" -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:118 -msgid "Upgrade available" -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:35 -msgid "Upgrade completed" -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:146 -msgid "Upgrading..." -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1212 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1182 msgid "Uplink Capacity(Default:Mbps)" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1650 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1603 #: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/certupload.htm:3 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_yaml_upload.htm:3 msgid "Upload" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:544 -msgid "Upload Custom YAML File" -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:546 -msgid "" -"Upload a custom Clash/Mihomo YAML file. The file will be preprocessed and " -"saved as a local Clash node." -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:263 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:271 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:276 -msgid "Uploaded YAML validation or preprocessing failed." -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:128 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:120 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:144 msgid "Use ChinaDNS-NG query and cache" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:201 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:168 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:196 +msgid "Use DNS List File" +msgstr "" + +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:264 msgid "Use DNS from WAN" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:202 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:265 msgid "Use DNS from WAN and 114DNS" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:122 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:108 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:132 +msgid "Use DNS2SOCKS query and cache" +msgstr "" + +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:111 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:135 +msgid "Use DNS2SOCKS-RUST query and cache" +msgstr "" + +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:129 msgid "Use DNS2TCP query" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:131 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:117 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:141 +msgid "Use DNSPROXY query and cache" +msgstr "" + +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:146 msgid "Use Local DNS Service listen port 5335" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:125 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:138 +msgid "Use MOSDNS query (Not Support Oversea Mode)" +msgstr "" + +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:114 msgid "Use MosDNS query" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1202 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1172 msgid "" "Use it together with the DNS disguised type. You can fill in any domain." msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:142 -msgid "User Level" -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/ssrurl.htm:104 +#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/ssrurl.htm:107 msgid "User cancelled." msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1274 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:534 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1244 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:332 msgid "User-Agent" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/ssrurl.htm:313 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/ssrurl.htm:1028 +#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/ssrurl.htm:295 +#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/ssrurl.htm:1133 msgid "Userinfo format error." msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:481 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:89 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server.lua:122 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:489 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:110 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server.lua:117 msgid "Username" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:613 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:596 msgid "Users Authentication" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:371 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:395 msgid "Using incorrect encryption mothod may causes service fail to start" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:28 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:430 -msgid "V2Ray GEO Databases" -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:337 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:342 msgid "V2Ray/XRay" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:409 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:441 msgid "V2Ray/XRay protocol" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:410 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:442 msgid "VLESS" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:922 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:892 msgid "VLESS Encryption" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:411 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:443 msgid "VMess" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1183 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1193 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1153 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1163 msgid "VideoCall (SRTP)" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:782 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:752 msgid "Vmess Protocol" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:797 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:767 msgid "Vmess UUID" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:914 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:884 msgid "Vmess/VLESS ID (UUID)" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:26 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:30 msgid "WAN Force Proxy IP" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:21 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:25 msgid "WAN IP AC" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:23 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:27 msgid "WAN White List IP" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:987 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:252 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:957 msgid "WebSocket Host" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:993 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:259 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:963 msgid "WebSocket Path" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1185 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1195 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1155 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1165 msgid "WechatVideo" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1235 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:96 +msgid "When disabled shunt mode, will same time stopped shunt service." +msgstr "" + +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:198 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:227 +msgid "When disabled, all AAAA requests are not resolved." +msgstr "" + +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1205 msgid "When enabled, it occupies IPv6 routing table 1023." msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:388 -msgid "When selected, it can be accessed from LAN. This may not be safe!" +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:187 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:216 +msgid "When two or more DNS servers are deployed, enable this function." msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:379 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:161 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:189 msgid "" -"When selected, it can only be accessed locally. Recommended when using " -"reverse proxies." +"When use DNS list file, please ensure list file exists and is formatted " +"correctly." msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:415 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1187 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1197 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:447 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1157 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1167 msgid "WireGuard" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1267 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1237 msgid "Wireguard allows only traffic from specific source IP." msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1053 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1023 msgid "XHTTP Extra" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1041 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1011 msgid "XHTTP Host" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1032 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1002 msgid "XHTTP Mode" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1047 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1017 msgid "XHTTP Path" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:207 -msgid "XTLS" +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:287 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:87 +msgid "Xray (Hysteria2)" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/controller/shadowsocksr.lua:394 -msgid "Xray" +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:104 +msgid "Xray (ShadowSocks)" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:225 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:318 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:94 +msgid "Xray (Trojan)" +msgstr "" + +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:355 msgid "Xray Fragment Settings" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:258 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:388 msgid "Xray Noise Packets" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:5 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:394 -msgid "Xray-core" -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_main_panel.htm:275 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_panel_button.htm:20 -msgid "YAML Reload Failed!" -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_main_panel.htm:272 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_panel_button.htm:17 -msgid "YAML Reloaded!" -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:137 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:252 msgid "adblock_url" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1171 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1141 msgid "aes-128-gcm" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1584 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1537 msgid "allow" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1578 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1531 msgid "allow: Allows use Mux connection." msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1498 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1451 msgid "allowInsecure" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1266 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1236 msgid "allowedIPs(optional)" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1388 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1352 msgid "android" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:139 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:254 msgid "anti-AD" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1172 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1142 msgid "chacha20-poly1305" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:116 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:92 msgid "china-operator-ip" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1277 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1384 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1247 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1348 msgid "chrome" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1615 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1631 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:180 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:208 +msgid "cloudflare-dns.com DNSCrypt SDNS" +msgstr "" + +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1568 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1584 msgid "comment_tcpcongestion_disable" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1548 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1501 msgid "concurrency" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1282 +#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/server_list.htm:678 +msgid "connect" +msgstr "" + +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1252 msgid "curl" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1612 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1628 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1565 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1581 msgid "custom_tcpcongestion" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1394 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1556 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1569 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1358 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1509 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1522 msgid "disable" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:228 -msgid "e.g.: /etc/ssl/fullchain.pem" +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:176 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:204 +msgid "dns.sb DNSCrypt SDNS" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:233 -msgid "e.g.: /etc/ssl/private.key" -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1280 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1389 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1250 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1353 msgid "edge" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:124 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:192 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:221 +msgid "fastest_addr" +msgstr "" + +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:239 msgid "felixonmars/dnsmasq-china-list" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1278 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1385 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1248 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1349 msgid "firefox" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1150 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1120 msgid "gRPC Idle Timeout" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1123 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1093 msgid "gRPC Mode" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1117 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1087 msgid "gRPC Service Name" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:106 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:82 msgid "gfwlist Update url" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:110 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:86 msgid "gfwlist/gfwlist" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1281 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1251 msgid "golang" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:552 -msgid "gost-plugin" -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1387 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1351 msgid "ios" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:562 -msgid "kcptun" +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:190 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:219 +msgid "load_balance" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:835 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:805 msgid "lossless UDP relay using QUIC streams" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:300 -msgid "mKCP Camouflage Type" -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:46 -msgid "mihomo binary not found in archive" -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:47 -msgid "naive binary not found in archive" -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:834 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:804 msgid "native UDP characteristics" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:514 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1373 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:99 +msgid "nfip_url" +msgstr "" + +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:521 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1337 msgid "none" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:546 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:551 msgid "obfs-local" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1391 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:191 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:220 +msgid "parallel" +msgstr "" + +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1355 msgid "qq" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1392 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1356 msgid "random" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1393 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1357 msgid "randomized" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1583 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1536 msgid "reject" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:561 -msgid "restls" -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1279 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1386 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1249 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1350 msgid "safari" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:769 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:739 msgid "shadow-TLS SNI" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:747 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:560 +msgid "shadow-tls" +msgstr "" + +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:717 msgid "shadowTLS protocol Version" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1585 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1538 msgid "skip" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1579 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1532 msgid "" "skip: Not use Mux module to carry UDP 443 traffic, Use original UDP " "transmission method of proxy protocol." msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1364 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1328 msgid "spiderX" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:107 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:83 msgid "v2fly/domain-list-community" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:549 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:554 msgid "v2ray-plugin" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:223 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:289 msgid "valid address:port" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:80 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:101 msgid "warning! Please do not reuse the port!" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:45 -msgid "xray binary not found in archive" -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:555 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:557 msgid "xray-plugin" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1561 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1514 msgid "xudpConcurrency" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1574 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1527 msgid "xudpProxyUDP443" msgstr "" diff --git a/luci-app-ssr-plus/po/zh_Hans/ssr-plus.po b/luci-app-ssr-plus/po/zh_Hans/ssr-plus.po index 250a18ce..d5e4cc39 100644 --- a/luci-app-ssr-plus/po/zh_Hans/ssr-plus.po +++ b/luci-app-ssr-plus/po/zh_Hans/ssr-plus.po @@ -1,7 +1,7 @@ msgid "" msgstr "Content-Type: text/plain; charset=UTF-8\n" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:231 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:361 msgid "" "\"1-3\" is for segmentation at TCP layer, applying to the beginning 1 to 3 " "data writes by the client. \"tlshello\" is for TLS client hello packet " @@ -10,262 +10,249 @@ msgstr "" "\"1-3\" 是 TCP 的流切片,应用于客户端第 1 至第 3 次写数据。\"tlshello\" 是 " "TLS 握手包切片。" +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:279 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:310 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:170 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:198 +msgid "%s Node Use Type" +msgstr "%s 节点使用类型" + +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:409 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:227 +msgid "%s Node Use Version" +msgstr "%s 节点使用版本" + #: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server.lua:103 msgid "0" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:94 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:100 msgid "1 Thread" msgstr "单线程" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:101 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:107 msgid "128 Threads" msgstr "128 线程" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1570 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1523 msgid "16" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:98 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:104 msgid "16 Threads" msgstr "16 线程" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:95 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:101 msgid "2 Threads" msgstr "2 线程" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:99 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:105 msgid "32 Threads" msgstr "32 线程" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1390 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1354 msgid "360" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:207 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:270 msgid "360 Security DNS (China Telecom) (101.226.4.6)" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:208 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:271 msgid "360 Security DNS (China Unicom) (123.125.81.6)" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:96 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:102 msgid "4 Threads" msgstr "4 线程" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:100 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:106 msgid "64 Threads" msgstr "64 线程" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1557 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1510 msgid "8" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:97 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:103 msgid "8 Threads" msgstr "8 线程" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:260 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:390 msgid "" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1061 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1416 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1443 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1031 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1369 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1396 msgid "" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:51 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:38 msgid "" -"

      Support SS/SSR/V2RAY/XRAY/TROJAN/TUIC/HYSTERIA2/NAIVEPROXY/SOCKS5/CLASH " +"

      Support SS/SSR/V2RAY/XRAY/TROJAN/TUIC/HYSTERIA2/NAIVEPROXY/SOCKS5/TUN " "etc.

      " msgstr "" -"

      支持 SS/SSR/V2RAY/XRAY/TROJAN/TUIC/HYSTERIA2/NAIVEPROXY/SOCKS5/CLASH 等协" +"

      支持 SS/SSR/V2RAY/XRAY/TROJAN/TUIC/HYSTERIA2/NAIVEPROXY/SOCKS5/TUN 等协" "议。

      " -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1233 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1550 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1563 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1576 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:186 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:160 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:186 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:220 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1203 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1503 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1516 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1529 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1655 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1682 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:188 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:214 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:249 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:240 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:267 msgid "
      • " msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:354 -msgid "A legal file path. This file must not exist before running." -msgstr "一个合法的文件路径。在运行之前,此文件必须不存在。" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:387 -msgid "Accept LAN Access" -msgstr "接受局域网访问" - -#: applications/luci-app-ssr-plus/luasrc/controller/shadowsocksr.lua:627 +#: applications/luci-app-ssr-plus/luasrc/controller/shadowsocksr.lua:58 msgid "Access Control" msgstr "访问控制" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_main_panel.htm:1035 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/subscribe_actions_footer.htm:235 -msgid "Actions" -msgstr "操作" +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:178 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:206 +msgid "AdGuard DNSCrypt SDNS" +msgstr "" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_main_panel.htm:1015 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/server_table.htm:290 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/server_table.htm:298 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/subscribe_actions_footer.htm:189 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/subscribe_actions_footer.htm:284 +#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/server_list.htm:749 msgid "Add" msgstr "添加" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/subscribe_actions_footer.htm:215 -msgid "Add failed:" -msgstr "添加失败:" - -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/subscribe_actions_footer.htm:182 -msgid "Adding..." -msgstr "添加中..." - -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:221 -msgid "Additional Version" -msgstr "附加版本" - -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:378 -msgid "Address" -msgstr "地址" - -#: applications/luci-app-ssr-plus/luasrc/controller/shadowsocksr.lua:628 +#: applications/luci-app-ssr-plus/luasrc/controller/shadowsocksr.lua:59 msgid "Advanced Settings" msgstr "高级设置" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:274 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:222 msgid "Advertising Data" msgstr "【广告屏蔽】数据库" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:205 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1676 +msgid "AliDNS" +msgstr "" + +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:268 msgid "AliYun Public DNS (223.5.5.5)" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:568 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:680 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:367 msgid "Alias" msgstr "别名" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:373 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:397 msgid "Alias(optional)" msgstr "别名(可选)" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/server_table.htm:157 -msgid "All" -msgstr "全部" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:112 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:119 msgid "All Ports" msgstr "所有端口(默认)" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_main_panel.htm:965 -msgid "All client proxy rules cleared and applied." -msgstr "所有客户端代理规则已清空并生效。" - -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_main_panel.htm:965 -msgid "All client proxy rules cleared." -msgstr "所有客户端代理规则已清空。" - -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/subscribe_actions_footer.htm:101 -msgid "All settings saved successfully." -msgstr "所有设置保存成功。" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:35 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:39 msgid "Allow all except listed" msgstr "除列表外主机皆允许" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:34 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:38 msgid "Allow listed only" msgstr "仅允许列表内主机" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:471 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:297 msgid "Allow subscribe Insecure nodes By default" msgstr "订阅节点允许不验证 TLS 证书" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:34 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:120 -msgid "Already up to date" -msgstr "已是最新版本" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:186 -msgid "Alter ID" -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:907 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:877 msgid "AlterId" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1307 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1271 msgid "An FinalMaskObject in JSON format, used for sharing." msgstr "JSON 格式的 FinalMaskObject,用来实现分享。" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:134 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:152 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:171 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:142 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:173 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:149 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:170 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:201 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:235 msgid "Anti-pollution DNS Server" msgstr "访问国外域名 DNS 服务器" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:128 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:125 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:206 +msgid "Anti-pollution DNS Server For Shunt Mode" +msgstr "分流模式下的访问国外域名 DNS 服务器" + +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:243 msgid "Apple Domains DNS" msgstr "Apple 域名 DNS" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:267 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:208 msgid "Apple Domains Data" msgstr "【Apple 域名】数据库" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:123 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:238 msgid "Apple Domains Update url" msgstr "Apple 域名更新 URL" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:119 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:234 msgid "Apple domains optimization" msgstr "Apple 域名解析优化" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:740 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:746 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:399 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:405 msgid "Apply" msgstr "应用" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:412 -msgid "Appointment Mode" -msgstr "定时模式" - -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/subscribe_actions_footer.htm:112 -msgid "Are you sure you want to delete subscribe link: %s ?" -msgstr "确定要删除此订阅链接:%s 吗?" +#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/server_list.htm:391 +msgid "Are you sure to delete this node?" +msgstr "是否真的要删除该节点?" #: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/backup_restore.htm:133 msgid "Are you sure you want to restore the client to default settings?" msgstr "是否真的要恢复客户端默认配置?" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:757 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:282 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:313 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1660 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1688 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:172 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:200 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:229 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:246 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:274 +msgid "Auto" +msgstr "自动" + +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:417 msgid "Auto Switch" msgstr "自动切换" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:93 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:99 msgid "Auto Threads" msgstr "自动(CPU 线程数)" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:407 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:117 msgid "Auto Update" msgstr "自动更新" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:409 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:119 msgid "Auto Update Server subscription, GFW list and CHN route" msgstr "自动更新服务器订阅、GFW 列表和中国大陆 IP 段" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:841 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1616 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1632 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:811 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1569 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1585 msgid "BBR" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1617 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1633 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1570 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1586 msgid "BRUTAL" msgstr "" @@ -277,72 +264,59 @@ msgstr "备份还原" msgid "Backup or Restore Client and Server Configurations." msgstr "备份或还原客户端及服务端配置。" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:252 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:193 msgid "Baidu Connectivity" msgstr "【百度】连通性检查" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:206 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:269 msgid "Baidu Public DNS (180.76.76.76)" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/ssrurl.htm:297 +#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/ssrurl.htm:320 msgid "Base64 sstr failed." msgstr "Base64 解码失败。" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:378 -msgid "Bind Local Only" -msgstr "仅绑定本地端口" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1184 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1194 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1154 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1164 msgid "BitTorrent (uTP)" msgstr "BT 下载(uTP)" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:96 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:100 msgid "Black Domain List" msgstr "强制走代理的域名" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:530 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:536 msgid "Bloom Filter" msgstr "布隆过滤器" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:80 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:84 msgid "Bypass Domain List" msgstr "不走代理的域名" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:261 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:439 -msgid "CHECK AND UPDATE" -msgstr "检查并更新" - #: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/backup_restore.htm:31 msgid "CLOSE WIN" msgstr "关闭窗口" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:209 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:272 msgid "CNNIC SDNS (1.2.4.8)" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:842 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1618 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1636 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:812 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1571 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1589 msgid "CUBIC" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1201 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1171 msgid "Camouflage Domain" msgstr "伪装域名" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:969 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1190 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:939 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1160 msgid "Camouflage Type" msgstr "伪装类型" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:227 -msgid "Certificate File Path" -msgstr "证书文件路径" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1526 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1479 msgid "Certificate fingerprint" msgstr "证书指纹" @@ -356,26 +330,15 @@ msgstr "检查连通性" msgid "Check Server" msgstr "检查服务器" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:280 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:228 msgid "Check Server Port" msgstr "【服务器端口】检查" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:94 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:77 msgid "Check Try Count" msgstr "切换检查重试次数" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:157 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:405 -msgid "Check Update" -msgstr "检查更新" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/component.lua:6 -msgid "" -"Check installed component versions and upgrade them online from the upstream " -"release page." -msgstr "检测已安装组件版本,并从上游发布页在线升级。" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:89 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:72 msgid "Check timout(second)" msgstr "切换检查超时时间(秒)" @@ -384,127 +347,72 @@ msgstr "切换检查超时时间(秒)" msgid "Check..." msgstr "正在检查..." -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:146 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:250 -msgid "Checking..." -msgstr "检查中..." - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:261 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:202 msgid "China IP Data" msgstr "【中国大陆 IP 段】数据库" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:192 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:255 msgid "ChinaDNS-NG query protocol" msgstr "ChinaDNS-NG 查询协议" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:113 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:226 +msgid "ChinaDNS-NG shunt query protocol" +msgstr "ChinaDNS-NG 分流查询协议" + +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:89 msgid "Chnroute Update url" msgstr "中国大陆 IP 段更新 URL" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:114 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:90 msgid "Clang.CN" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:115 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:91 msgid "Clang.CN.CIDR" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/controller/shadowsocksr.lua:376 -msgid "Clash" -msgstr "Clash" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:88 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_main_panel.htm:817 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_main_panel.htm:1013 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_panel.htm:3 -msgid "Clash Panel" -msgstr "Clash 面板" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:392 -msgid "Clash Subscription URL" -msgstr "Clash 订阅链接" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:404 -msgid "Clash User-Agent" -msgstr "Clash User-Agent" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:398 -msgid "Clash YAML Path" -msgstr "Clash YAML 路径" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:352 -msgid "Clash/Mihomo" -msgstr "Clash/Mihomo" - -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_main_panel.htm:1018 -msgid "Clear All Rules" -msgstr "清空所有规则" - -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_main_panel.htm:954 -msgid "Clear all custom client proxy rules and restore empty state?" -msgstr "清空所有自定义客户端代理规则,并恢复为空白状态吗?" - #: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/log.htm:35 msgid "Clear logs" msgstr "清空日志" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:264 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1063 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1418 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1445 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:164 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:192 +msgid "Click here to view or manage the DNS list file" +msgstr "点击此处查看或管理 DNS 列表文件" + +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:394 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1033 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1371 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1398 msgid "Click to the page" msgstr "点击前往" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_main_panel.htm:1032 -msgid "Client" -msgstr "客户端" - -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_main_panel.htm:920 -msgid "Client rules exported to CSV file." -msgstr "客户端规则已导出为 CSV 文件。" - -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_main_panel.htm:944 -msgid "Client rules imported from CSV file. Click Save to apply." -msgstr "客户端规则已从 CSV 文件导入,请点击保存生效。" - -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_main_panel.htm:1027 -msgid "Client supports manual IP or IP/CIDR input." -msgstr "客户端支持手动输入 IP 或 IP/CIDR。" - -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_main_panel.htm:1024 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/subscribe.htm:251 -msgid "Close" -msgstr "关闭" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:158 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:148 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:176 msgid "Cloudflare DNS" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:145 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:182 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:136 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:217 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:160 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:246 msgid "Cloudflare DNS (1.1.1.1)" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:402 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:436 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/status.htm:21 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:179 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:207 +msgid "Cloudflare DNSCrypt SDNS" +msgstr "" + +#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/status.htm:20 msgid "Collecting data..." msgstr "正在收集数据中..." -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:390 -msgid "Component" -msgstr "组件" - -#: applications/luci-app-ssr-plus/luasrc/controller/shadowsocksr.lua:630 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/component.lua:5 -msgid "Component Update" -msgstr "组件升级" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1061 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1031 msgid "Configure XHTTP Extra Settings (JSON format), see:" msgstr "配置 XHTTP 额外设置(JSON 格式),具体请参见:" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:839 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:809 msgid "Congestion control algorithm" msgstr "拥塞控制算法" @@ -516,158 +424,142 @@ msgstr "连接错误" msgid "Connect OK" msgstr "连接正常" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:82 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:103 msgid "Connection Timeout" msgstr "连接超时" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1429 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1382 msgid "" "Controls the policy used when performing DNS queries for ECH configuration." msgstr "控制使用 DNS 查询 ECH 配置时的策略。" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/ssrurl.htm:90 +#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/ssrurl.htm:93 msgid "Copy SSR to clipboard successfully." msgstr "成功复制 SSR 网址到剪贴板。" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:369 -msgid "Core Components" -msgstr "核心组件" - -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:20 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:428 -msgid "Country MMDB" -msgstr "Country MMDB" - #: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/backup_restore.htm:2 msgid "Create Backup File" msgstr "创建备份文件" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1664 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1617 msgid "Create upload file error." msgstr "创建上传文件错误。" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:110 -msgid "Current ARCH" -msgstr "当前架构" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1684 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1637 msgid "Current Certificate Path" msgstr "当前证书路径" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:219 -msgid "Current Version" -msgstr "当前版本" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:564 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:562 msgid "Custom" msgstr "自定义" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_main_panel.htm:991 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_main_panel.htm:992 -msgid "Custom Client Proxies Rules" -msgstr "自定义客户端代理规则" +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:182 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:210 +msgid "" +"Custom DNS Server (support: IP:Port or tls://IP:Port or https://IP/dns-query " +"and other format)." +msgstr "" +"自定义 DNS 服务器(支持格式:IP:端口、tls://IP:端口、https://IP/dns-query 及" +"其他格式)。" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:148 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:187 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:139 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:221 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:166 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:250 msgid "Custom DNS Server format as IP:PORT (default: 8.8.4.4:53)" msgstr "格式为 IP:Port(默认:8.8.4.4:53)" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:212 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:278 msgid "Custom DNS Server format as IP:PORT (default: disabled)" msgstr "格式为 IP:PORT(默认:禁用)" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:160 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:150 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:178 msgid "" "Custom DNS Server format as tcp://IP:PORT or tls://DOMAIN:PORT " "(tcp://8.8.8.8 or tls://dns.google:853)" msgstr "" "格式为tcp://IP:Port或tls://域名:Port (tcp://8.8.8.8或tls://dns.google:853)" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:568 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:566 msgid "Custom Plugin Path" msgstr "自定义插件路径" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:114 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:121 msgid "Custom Ports" msgstr "自定义端口" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:269 -msgid "Custom YAML imported successfully: %s" -msgstr "自定义 YAML 导入成功:%s" - -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_main_panel.htm:708 -msgid "Custom client proxy rules saved and applied." -msgstr "自定义客户端代理规则已保存并生效。" - -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_main_panel.htm:708 -msgid "Custom client proxy rules saved." -msgstr "自定义客户端代理规则已保存。" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1308 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1272 msgid "" "Custom finalmask overrides mkcp, hysteria2, fragment, noise, and related " "settings." msgstr "自定义 finalmask 将覆盖 mkcp、hysteria2、fragment、noise 等相关配置。" +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:103 +msgid "Customize Netflix IP Url" +msgstr "" +"自定义 Netflix IP 段更新 URL(默认项目地址:https://github.com/QiuSimons/" +"Netflix_IP)" + #: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/backup_restore.htm:4 msgid "DL Backup" msgstr "下载备份" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1198 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1168 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1666 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1674 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:251 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:259 msgid "DNS" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:192 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:143 msgid "DNS Anti-pollution" msgstr "DNS 防污染服务" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:204 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:106 +msgid "DNS Query Mode For Shunt Mode" +msgstr "分流模式下的 DNS 查询模式" + +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1675 +msgid "DNSPod" +msgstr "" + +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:267 msgid "DNSPod Public DNS (119.29.29.29)" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1186 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1196 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1156 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1166 msgid "DTLS 1.2" msgstr "DTLS 1.2 数据包" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:424 -msgid "Database" -msgstr "数据库" +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1218 +msgid "Decimal numbers separated by \",\" or Base64-encoded strings." +msgstr "用“,”隔开的十进制数字或 Base64 编码字符串。" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/subscribe_schedule_compact.htm:87 -msgid "Day/Week" -msgstr "日/周" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:193 -msgid "Decryption" -msgstr "解密" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1276 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1466 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1478 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1492 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1246 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1419 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1431 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1445 msgid "Default" msgstr "默认" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:101 -msgid "Default Node Local Port" -msgstr "节点默认本地端口" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1577 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1530 msgid "Default reject rejects traffic." msgstr "默认 reject 拒绝流量。" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:737 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:707 msgid "Default value 0 indicatesno heartbeat." msgstr "默认为 0 表示无心跳。" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1551 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1504 msgid "" "Default: disable. When entering a negative number, such as -1, The Mux " "module will not be used to carry TCP traffic." msgstr "默认:禁用。填负数时,如 -1,不使用 Mux 模块承载 TCP 流量。" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1564 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1517 msgid "" "Default:16. When entering a negative number, such as -1, The Mux module will " "not be used to carry UDP traffic, Use original UDP transmission method of " @@ -676,72 +568,76 @@ msgstr "" "默认值:16。填负数时,如 -1,不使用 Mux 模块承载 UDP 流量。将使用代理协议原本" "的 UDP 传输方式。" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_main_panel.htm:297 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_panel_button.htm:41 -msgid "Defaults Cleared!" -msgstr "已清空默认状态!" +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:184 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:212 +msgid "Defines the upstreams logic mode" +msgstr "定义上游逻辑模式" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_main_panel.htm:297 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_panel_button.htm:41 -msgid "Defaults Restored!" -msgstr "默认值已恢复!" - -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_main_panel.htm:1027 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:187 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:215 msgid "" -"Define per-client Mihomo proxy targets. Rules are injected as SRC-IP-CIDR " -"entries before the original Clash rules." +"Defines the upstreams logic mode, possible values: load_balance, parallel, " +"fastest_addr (default: load_balance)." msgstr "" -"为每个客户端指定 Mihomo 代理目标。规则会以 SRC-IP-CIDR 形式注入到原始 Clash " -"规则之前。" +"定义上游逻辑模式,可选择值:负载均衡、并行查询、最快响应(默认值:负载均" +"衡)。" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:302 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:432 msgid "Delay (ms)" msgstr "延迟(ms)" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_main_panel.htm:589 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/server_table.htm:248 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/subscribe_actions_footer.htm:261 +#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/server_list.htm:738 msgid "Delete" msgstr "删除" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:504 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:315 msgid "Delete All Subscribe Servers" -msgstr "删除所有订阅节点" +msgstr "删除所有订阅服务器节点" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/subscribe_actions_footer.htm:130 -msgid "Delete failed:" -msgstr "删除失败:" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:112 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:116 msgid "Deny Domain List" msgstr "禁止连接的域名" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:663 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:81 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:33 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:62 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:70 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:78 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:37 msgid "Disable" msgstr "停用" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:200 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:263 msgid "Disable ChinaDNS-NG" msgstr "直通模式(禁用 ChinaDNS-NG)" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:163 -msgid "Disable IPv6 for Overseas FQDN" -msgstr "禁止海外域名返回 IPv6 记录" +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:152 +msgid "Disable IPv6 In MosDNS Query Mode (Shunt Mode)" +msgstr "禁止 MosDNS 返回 IPv6 记录 (分流模式)" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:694 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:180 +msgid "Disable IPv6 in MOSDNS query mode" +msgstr "禁止 MOSDNS 返回 IPv6 记录" + +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:197 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:226 +msgid "Disable IPv6 query mode" +msgstr "禁止返回 IPv6 记录" + +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:664 msgid "Disable QUIC path MTU discovery" msgstr "禁用 QUIC 启用 MTU 探测" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:883 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:853 msgid "Disable SNI" msgstr "关闭 SNI 服务器名称指示" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:764 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:734 msgid "Disable TCP No_delay" msgstr "禁用 TCP 无延迟" +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:149 +msgid "Dnsproxy Parse List" +msgstr "DNSPROXY 解析列表" + #: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/backup_restore.htm:18 msgid "Do Reset" msgstr "执行重置" @@ -750,114 +646,119 @@ msgstr "执行重置" msgid "Do you want to restore the client to default settings?" msgstr "是否要恢复客户端默认配置?" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:196 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1663 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:249 +msgid "DoH" +msgstr "" + +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:230 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:259 msgid "DoT upstream (Need use wolfssl version)" msgstr "DoT 上游(需使用 wolfssl 版本)" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:289 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1653 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:238 +msgid "Domain DNS Resolve" +msgstr "域名 DNS 解析" + +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:419 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1680 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:265 msgid "Domain Strategy" msgstr "域名解析策略" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:353 -msgid "DomainSocket Path" -msgstr "域 Socket 路径" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:199 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:262 msgid "Domestic DNS Server" msgstr "国内 DNS 服务器" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1219 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1189 msgid "Downlink Capacity(Default:Mbps)" msgstr "下行链路容量(默认:Mbps)" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:377 -msgid "Download Source" -msgstr "下载源" +#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/server_list.htm:739 +msgid "Drag to reorder" +msgstr "拖动以重排" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:43 -msgid "Download failed" -msgstr "下载失败" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:894 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:864 msgid "Dual-stack Listening Socket" msgstr "双栈 Socket 监听" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1414 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1367 msgid "ECH Config" msgstr "ECH 配置" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1428 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1381 msgid "ECH Query Policy" msgstr "ECH 查询策略" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1011 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:981 msgid "Early Data Header Name" msgstr "前置数据标头" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/server_table.htm:240 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/server_table.htm:246 +#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/server_list.htm:737 msgid "Edit" msgstr "编辑" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:307 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:40 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:259 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:69 msgid "Edit ShadowSocksR Server" msgstr "编辑服务器配置" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:157 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:198 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:278 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:54 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:271 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:408 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:82 #: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server.lua:101 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:560 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_main_panel.htm:1031 msgid "Enable" msgstr "启用" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:888 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:858 msgid "Enable 0-RTT QUIC handshake" msgstr "客户端启用 0-RTT QUIC 连接握手" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:474 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:482 msgid "Enable Authentication" msgstr "启用用户名/密码认证" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:80 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1701 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:63 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1712 msgid "Enable Auto Switch" msgstr "启用自动切换" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1398 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1362 msgid "Enable ECH(optional)" msgstr "启用 ECH (可选)" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:657 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:640 msgid "Enable Lazy Mode" msgstr "启用懒狗模式" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1436 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1389 msgid "Enable ML-DSA-65(optional)" msgstr "启用 ML-DSA-65 (可选)" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1595 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1548 msgid "" "Enable Multipath TCP, need to be enabled in both server and client " "configuration." msgstr "启用 Multipath TCP,需在服务端和客户端配置中同时启用。" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1531 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1484 msgid "Enable Mux.Cool" msgstr "启用 Mux.Cool" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:651 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:95 +msgid "Enable Netflix Mode" +msgstr "启用 Netflix 分流模式" + +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:634 msgid "Enable Obfuscation" msgstr "启用混淆功能" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:536 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:542 msgid "Enable Plugin" msgstr "启用插件" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:619 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:602 msgid "Enable Port Hopping" msgstr "启用端口跳跃" @@ -865,258 +766,200 @@ msgstr "启用端口跳跃" msgid "Enable Server" msgstr "启动服务端" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:632 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:615 msgid "Enable Transport Protocol Settings" msgstr "启用传输协议设置" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:750 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:720 msgid "Enable V2 protocol." msgstr "开启 V2 协议。" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:749 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:719 msgid "Enable V3 protocol." msgstr "开启 V3 协议。" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:134 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:249 msgid "Enable adblock" msgstr "启用广告屏蔽" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:525 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:531 msgid "Enable the SUoT protocol, requires server support." msgstr "启用 SUoT 协议,需要服务端支持。" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1054 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1024 msgid "Enable this option to configure XHTTP Extra (JSON format)." msgstr "启用此选项配置 XHTTP 附加项(JSON 格式)。" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1231 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1201 msgid "Enabled Kernel virtual NIC TUN(optional)" msgstr "启用内核的虚拟网卡 TUN(可选)" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:181 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:335 msgid "Enabled Mixed" msgstr "启用 Mixed" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:759 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1690 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:729 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1643 msgid "Enabling TCP Fast Open Requires Server Support." msgstr "启用 TCP 快速打开需要服务端支持。" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:503 #: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:510 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:791 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:802 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:933 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:103 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:108 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:171 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server.lua:127 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:517 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:761 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:772 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:903 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:118 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:125 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server.lua:122 msgid "Encrypt Method" msgstr "加密方式" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:115 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:122 msgid "Enter Custom Ports" msgstr "输入自定义端口" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:419 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:122 msgid "Every Day" msgstr "每天" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:424 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:127 msgid "Every Friday" msgstr "每周五" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:420 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:123 msgid "Every Monday" msgstr "每周一" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:425 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:128 msgid "Every Saturday" msgstr "每周六" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:426 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:129 msgid "Every Sunday" msgstr "每周日" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:423 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:126 msgid "Every Thursday" msgstr "每周四" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:421 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:124 msgid "Every Tuesday" msgstr "每周二" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:422 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:125 msgid "Every Wednesday" msgstr "每周三" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:606 -msgid "Example:" -msgstr "示例:" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:223 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:289 msgid "Expecting: %s" msgstr "应为:%s" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_main_panel.htm:1019 -msgid "Export Client Rules" -msgstr "批量导出客户端规则" +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:86 +msgid "External Proxy Mode" +msgstr "分流服务器(前置)代理" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:44 -msgid "Extract failed" -msgstr "解压失败" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1634 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1587 msgid "FORCE BRUTAL" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_main_panel.htm:967 -msgid "Failed to clear all client proxy rules." -msgstr "清空所有客户端代理规则失败。" - -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:42 -msgid "Failed to create temp directory" -msgstr "创建临时目录失败" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:230 -msgid "Failed to create temporary YAML upload file." -msgstr "创建临时 YAML 上传文件失败。" - -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:37 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:77 -msgid "Failed to fetch release metadata" -msgstr "获取发布信息失败" - -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:99 -msgid "Failed to query component information." -msgstr "获取组件信息失败。" - -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:210 -msgid "Failed to query geo database information." -msgstr "获取 Geo 数据库信息失败。" - -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_main_panel.htm:710 -msgid "Failed to save custom client proxy rules." -msgstr "保存自定义客户端代理规则失败。" - -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:219 -msgid "File Not Exist" -msgstr "文件不存在" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:461 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:282 msgid "Filter Words splited by /" msgstr "命中关键字的节点将被丢弃。多个关键字用 / 分隔" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1290 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1260 msgid "FinalMask" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1382 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1346 msgid "Finger Print" msgstr "指纹伪造" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1369 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:212 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1333 msgid "Flow" msgstr "流控(Flow)" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:119 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:234 msgid "" "For Apple domains equipped with Chinese mainland CDN, always responsive to " "Chinese CDN IP addresses" msgstr "配备中国大陆 CDN 的 Apple 域名,始终应答中国大陆 CDN 地址" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:262 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:392 msgid "For specific usage, see:" msgstr "具体使用方法,具体请参见:" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:626 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:609 msgid "" "Format as 10000:20000 or 10000-20000 Multiple groups are separated by commas " "(,)." msgstr "格式为:10000:20000 或 10000-20000 多组时用逗号(,)隔开。" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:228 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:88 +msgid "Forward Netflix Proxy through Main Proxy" +msgstr "分流服务器流量通过主服务节点中转代理转发" + +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:358 msgid "Fragment" msgstr "分片" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:245 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:375 msgid "Fragment Delay" msgstr "分片延迟" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:240 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:370 msgid "Fragment Length" msgstr "分片包长" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:231 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:361 msgid "Fragment Packets" msgstr "分片方式" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:245 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:375 msgid "Fragmentation interval (ms)" msgstr "分片间隔(ms)" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:240 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:370 msgid "Fragmented packet length (byte)" msgstr "分片包长 (byte)" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:256 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:197 msgid "GFW List Data" msgstr "【GFW 列表】数据库" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:106 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:112 msgid "GFW List Mode" msgstr "GFW 列表模式" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:64 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:68 msgid "Game Mode Host List" msgstr "增强游戏模式客户端 LAN IP" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:183 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:134 msgid "Game Mode UDP Relay" msgstr "游戏模式 UDP 中继" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:859 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:69 +msgid "Game Mode UDP Server" +msgstr "游戏模式 UDP 中继服务器" + +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:829 msgid "Garbage collection interval(second)" msgstr "UDP 数据包片残片清理间隔(单位:秒)" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:865 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:835 msgid "Garbage collection lifetime(second)" msgstr "UDP 数据包残片在服务器的保留时间(单位:秒)" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:416 -msgid "Geo Database Update" -msgstr "Geo 数据库更新" - -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:425 -msgid "Geo Resource" -msgstr "Geo 资源" - -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:24 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:429 -msgid "GeoSite Database" -msgstr "GeoSite 数据库" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/component.lua:14 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:381 -msgid "GitHub Direct" -msgstr "GitHub 直连" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:175 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:126 msgid "Global Client" msgstr "TCP 透明代理" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:194 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:210 -msgid "Global HTTP/HTTPS Proxy Server" -msgstr "HTTP/HTTPS 代理服务端(全局)" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:108 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:114 msgid "Global Mode" msgstr "全局模式" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:152 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:201 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:267 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:152 msgid "Global SOCKS5 Proxy Server" msgstr "SOCKS5 代理服务端(全局)" @@ -1124,25 +967,31 @@ msgstr "SOCKS5 代理服务端(全局)" msgid "Global Setting" msgstr "全局设置" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/server_table.htm:76 -msgid "Go to relevant configuration page" -msgstr "前往相关配置页面" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:248 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:189 msgid "Google Connectivity" msgstr "【谷歌】连通性检查" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:153 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:174 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:202 +msgid "Google DNSCrypt SDNS" +msgstr "" + +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:143 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:171 msgid "Google Public DNS" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:135 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:172 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:126 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:207 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:150 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:236 msgid "Google Public DNS (8.8.4.4)" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:136 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:173 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:127 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:208 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:151 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:237 msgid "Google Public DNS (8.8.8.8)" msgstr "" @@ -1150,414 +999,330 @@ msgstr "" msgid "Grant UCI access for luci-app-ssr-plus" msgstr "授予访问 luci-app-ssr-plus 配置的权限" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1125 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1095 msgid "Gun" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1144 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1114 msgid "H2 Read Idle Timeout" msgstr "H2 读取空闲超时" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1139 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1109 msgid "H2/gRPC Health Check" msgstr "H2/gRPC 健康检查" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:421 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:972 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:453 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:942 msgid "HTTP" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:202 -msgid "HTTP Auth Mode" -msgstr "HTTP 认证模式" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:976 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:291 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:946 msgid "HTTP Host" msgstr "HTTP 主机名" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:212 -msgid "HTTP Password" -msgstr "HTTP 密码" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:981 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:295 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:951 msgid "HTTP Path" msgstr "HTTP 路径" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:208 -msgid "HTTP User" -msgstr "HTTP 用户名" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:202 -msgid "HTTP proxy auth method, default:none." -msgstr "HTTP 代理认证方式,默认:none。" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1107 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:268 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1077 msgid "HTTP/2 Host" msgstr "HTTP/2 主机名" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1112 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:274 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1082 msgid "HTTP/2 Path" msgstr "HTTP/2 路径" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1179 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1149 msgid "Header" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1156 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1126 msgid "Health Check Timeout" msgstr "健康检查超时" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:847 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:817 msgid "Heartbeat interval(second)" msgstr "保活心跳包发送间隔(单位:秒)" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:998 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:968 msgid "HeartbeatPeriod(second)" msgstr "心跳周期(单位:秒)" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/subscribe_schedule_compact.htm:88 -msgid "Hour" -msgstr "时" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1020 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:990 msgid "Httpupgrade Host" msgstr "HTTPUpgrade 主机名" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1025 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:995 msgid "Httpupgrade Path" msgstr "HTTPUpgrade 路径" -#: applications/luci-app-ssr-plus/luasrc/controller/shadowsocksr.lua:407 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:418 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:284 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:357 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:450 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:84 msgid "Hysteria2" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:598 -msgid "Hysteria2 Realms" -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:688 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:658 msgid "Hysterir QUIC parameters" msgstr "QUIC 参数" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:107 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:113 msgid "IP Route Mode" msgstr "绕过中国大陆 IP 模式" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1490 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1443 msgid "IP Stack Preference" msgstr "IP 栈优先级" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:128 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1691 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:277 +msgid "IPv4 Only" +msgstr "仅 IPv4" + +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1692 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:278 +msgid "IPv6 Only" +msgstr "仅 IPv6" + +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:243 msgid "If empty, Not change Apple domains parsing DNS (Default is empty)" msgstr "如果为空,则不更改 Apple 域名解析 DNS(默认为空)" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1416 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1683 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:268 +msgid "" +"If is domain name, The requested domain name will be resolved to IP before " +"connect." +msgstr "如果是域名,域名将在请求发出之前解析为 IP。" + +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1369 msgid "" "If it is not empty, it indicates that the Client has enabled Encrypted " "Client, see:" msgstr "如果不为空,表示客户端已启用加密客户端,具体请参见:" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:895 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1656 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:241 +msgid "" +"If the node address is a domain name, this DNS will be used for resolution." +msgstr "如果节点地址是域名,则将使用此 DNS 进行解析。" + +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:865 msgid "If this option is not set, the socket behavior is platform dependent." msgstr "如果未设置此选项,则 Socket 行为依赖于平台。" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1503 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1456 msgid "" "If true, allowss insecure connection at TLS client, e.g., TLS server uses " "unverifiable certificates." msgstr "" "是否允许不安全连接。当选择时,将不会检查远端主机所提供的 TLS 证书的有效性。" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1648 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1601 msgid "If you have a self-signed certificate,please check the box" msgstr "如果你使用自签证书,请选择" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/ssrurl.htm:1088 +#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/ssrurl.htm:1193 msgid "Import" msgstr "导入配置信息" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_main_panel.htm:1020 -msgid "Import Client Rules" -msgstr "批量导入客户端规则" - -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/ssrurl.htm:195 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/ssrurl.htm:376 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/ssrurl.htm:520 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/ssrurl.htm:590 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/ssrurl.htm:624 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/ssrurl.htm:731 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/ssrurl.htm:847 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/ssrurl.htm:999 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/ssrurl.htm:1079 +#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/ssrurl.htm:249 +#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/ssrurl.htm:425 +#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/ssrurl.htm:597 +#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/ssrurl.htm:672 +#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/ssrurl.htm:706 +#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/ssrurl.htm:813 +#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/ssrurl.htm:952 +#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/ssrurl.htm:1104 +#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/ssrurl.htm:1184 msgid "Import configuration information successfully." msgstr "导入配置信息成功。" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1132 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1102 msgid "Initial Windows Size" msgstr "初始窗口大小" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:48 -msgid "Install failed" -msgstr "安装失败" - -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:108 -msgid "Installed Version" -msgstr "已安装版本" - -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:49 -msgid "Installed binary failed to run" -msgstr "新安装的二进制无法运行" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:13 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:17 msgid "Interface" msgstr "接口" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:12 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:16 msgid "Interface control" msgstr "接口控制" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/server_table.htm:293 -msgid "Invalid" -msgstr "无效的" - -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/ssrurl.htm:1082 +#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/ssrurl.htm:1187 msgid "Invalid format." msgstr "无效的格式。" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:330 -msgid "KCP Congestion Control" -msgstr "KCP 拥塞控制" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:324 -msgid "KCP Downlink Capacity" -msgstr "KCP 下行带宽容量" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:306 -msgid "KCP MTU" -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:335 -msgid "KCP Read Buffer Size" -msgstr "KCP 读缓冲区大小" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:347 -msgid "KCP Seed" -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:312 -msgid "KCP TTI" -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:318 -msgid "KCP Uplink Capacity" -msgstr "KCP 上行链路容量" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:341 -msgid "KCP Write Buffer Size" -msgstr "KCP 写缓冲区大小" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:231 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:172 msgid "KcpTun" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1706 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1722 msgid "KcpTun Enable" msgstr "KcpTun 启用" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1726 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1739 msgid "KcpTun Param" msgstr "KcpTun 参数" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1720 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1734 msgid "KcpTun Password" msgstr "KcpTun 密码" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1713 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1728 msgid "KcpTun Port" msgstr "KcpTun 端口" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:228 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:169 msgid "KcpTun Version" msgstr "KcpTun 版本号" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:32 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:36 msgid "LAN Access Control" msgstr "内网客户端分流代理控制" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:48 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:52 msgid "LAN Bypassed Host List" msgstr "不走代理的局域网 LAN IP" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:56 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:60 msgid "LAN Force Proxy Host List" msgstr "全局代理的 LAN IP" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:38 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:42 msgid "LAN Host List" msgstr "内网主机列表" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:30 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:34 msgid "LAN IP AC" msgstr "LAN IP 访问控制" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:109 -msgid "Latest Version" -msgstr "最新版本" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:139 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:176 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:130 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:211 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:154 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:240 msgid "Level 3 Public DNS (209.244.0.3)" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:140 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:177 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:131 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:212 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:155 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:241 msgid "Level 3 Public DNS (209.244.0.4)" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:141 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:178 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:132 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:213 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:156 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:242 msgid "Level 3 Public DNS (4.2.2.1)" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:142 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:179 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:133 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:214 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:157 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:243 msgid "Level 3 Public DNS (4.2.2.2)" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:143 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:180 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:134 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:215 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:158 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:244 msgid "Level 3 Public DNS (4.2.2.3)" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:144 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:181 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:135 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:216 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:159 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:245 msgid "Level 3 Public DNS (4.2.2.4)" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:155 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:145 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:173 msgid "Level 3 Public DNS-1 (209.244.0.3-4)" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:156 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:146 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:174 msgid "Level 3 Public DNS-2 (4.2.2.1-2)" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:157 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:147 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:175 msgid "Level 3 Public DNS-3 (4.2.2.3-4)" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:250 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:380 msgid "Limit the maximum number of splits." msgstr "限制分片的最大数量。" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1234 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1204 msgid "" "Linux kernel TUN virtual NIC requires system support and root privileges." msgstr "Linux 内核 TUN 虚拟网卡需要系统支持和 root 权限。" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:18 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:22 msgid "Listen only on the given interface or, if unspecified, on all" msgstr "仅监听指定的接口,未指定则监听全部。" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_main_panel.htm:718 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_main_panel.htm:771 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_panel.htm:84 -msgid "Loading..." -msgstr "加载中..." - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:187 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:217 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:348 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1716 msgid "Local Port" msgstr "本地端口" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:219 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:160 msgid "Local Servers" msgstr "本机服务端" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1242 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1212 msgid "Local addresses" msgstr "本地地址" -#: applications/luci-app-ssr-plus/luasrc/controller/shadowsocksr.lua:643 +#: applications/luci-app-ssr-plus/luasrc/controller/shadowsocksr.lua:66 msgid "Log" msgstr "日志" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:413 -msgid "Loop Mode" -msgstr "循环模式" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:109 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:85 msgid "Loukky/gfwlist-by-loukky" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:108 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:84 msgid "Loyalsoldier/v2ray-rules-dat" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1441 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1394 msgid "ML-DSA-65 Public key" msgstr "ML-DSA-65 公钥" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1595 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1548 msgid "MPTCP" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1205 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1175 msgid "MTU" msgstr "最大传输单元" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:80 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:61 msgid "Main Server" msgstr "主服务器" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:558 -msgid "" -"Manage multiple subscribe URLs, including Clash subscriptions. Only enabled " -"entries are included when updating all subscriptions." -msgstr "" -"管理多条订阅 URL,包括 Clash 订阅。只有启用的订阅项才会参与“更新所有订阅节" -"点”。" - -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:38 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:78 -msgid "Matching release asset not found" -msgstr "未找到匹配的发布资产" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1004 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:974 msgid "Max Early Data" msgstr "最大前置数据" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:250 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:380 msgid "Max Split" msgstr "最大分片数" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:900 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:870 msgid "Maximum packet size the socks5 server can receive from external" msgstr "socks5 服务器可以从外部接收的最大数据包大小(单位:字节)" -#: applications/luci-app-ssr-plus/luasrc/controller/shadowsocksr.lua:372 -#: applications/luci-app-ssr-plus/luasrc/controller/shadowsocksr.lua:375 -#: applications/luci-app-ssr-plus/luasrc/controller/shadowsocksr.lua:378 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:9 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:395 -msgid "Mihomo" -msgstr "Mihomo" - -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_main_panel.htm:1005 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_main_panel.htm:1006 -msgid "Mihomo Pannel" -msgstr "Mihomo 面板" - -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/subscribe_schedule_compact.htm:89 -msgid "Min" -msgstr "分" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1565 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1518 msgid "" "Min value is 1, Max value is 1024. When omitted or set to 0, Will same path " "as TCP traffic." @@ -1565,174 +1330,154 @@ msgstr "" "最小值 1,最大值 1024。 省略或者填 0 时,将与 TCP 流量走同一条路,也就是传统" "的行为。" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1552 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1505 msgid "" "Min value is 1, Max value is 128. When omitted or set to 0, it equals 8." msgstr "最小值 1,最大值 128。省略或者填 0 时都等于 8。" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/component.lua:13 -msgid "Mirror URL" -msgstr "镜像地址" - -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:40 -msgid "Missing gzip support" -msgstr "缺少 gzip 支持" - -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:39 -msgid "Missing unzip support" -msgstr "缺少 unzip 支持" - -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:41 -msgid "Missing xz support" -msgstr "缺少 xz 支持" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:181 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:335 msgid "Mixed as an alias of socks, default:Enabled." msgstr "Mixed 作为 SOCKS 的别名,默认:启用。" #: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/optimize_cbi_ui.htm:10 +#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/server_list.htm:735 msgid "Move down" msgstr "下移" #: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/optimize_cbi_ui.htm:7 +#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/server_list.htm:734 msgid "Move up" msgstr "上移" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:188 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:222 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:251 msgid "Muitiple DNS server can saperate with ','" msgstr "多个上游 DNS 服务器请用 ',' 分隔(注意用英文逗号)" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1126 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1096 msgid "Multi" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:92 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:98 msgid "Multi Threads Option" msgstr "多线程并发转发" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1096 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1326 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1066 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1290 msgid "Must be JSON text!" msgstr "必须是 JSON 文本内容!" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1531 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1484 msgid "Mux" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:138 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:253 msgid "NEO DEV HOST" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/status.htm:11 +#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/status.htm:10 msgid "NOT RUNNING" msgstr "未运行" -#: applications/luci-app-ssr-plus/luasrc/controller/shadowsocksr.lua:401 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:349 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:13 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:396 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:354 msgid "NaiveProxy" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/server_table.htm:27 -msgid "Name" -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:203 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:266 msgid "Nanjing Xinfeng 114DNS (114.114.114.114)" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:843 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:132 +msgid "Netflix Domain List" +msgstr "Netflix 分流域名列表" + +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:215 +msgid "Netflix IP Data" +msgstr "【Netflix IP 段】数据库" + +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:100 +msgid "Netflix IP Only" +msgstr "" + +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:77 +msgid "Netflix Node" +msgstr "Netflix 分流服务器" + +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:101 +msgid "Netflix and AWS" +msgstr "" + +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:369 +msgid "Network Tunnel" +msgstr "网络隧道" + +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:399 +msgid "Network interface to use" +msgstr "使用的网络接口" + +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:813 msgid "New Reno" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/server_table.htm:149 -msgid "Next" -msgstr "下一页" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:249 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:253 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:282 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:116 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:190 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:194 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:230 msgid "No Check" msgstr "未检查" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/ssrurl.htm:156 -msgid "No available Xray core to import this Hysteria2 node." -msgstr "没有可用的 Xray 核心可以导入此 Hysteria2 节点。" +#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/ssrurl.htm:209 +msgid "No available core (Hysteria2 or Xray) to import this node." +msgstr "没有可用的核心(Hysteria2 或 Xray)可以导入此节点。" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/ssrurl.htm:546 +#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/ssrurl.htm:632 msgid "No available core (Shadowsocks or Xray) to import this node." msgstr "没有可用的核心(Shadowsocks 或 Xray)可以导入此节点。" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/ssrurl.htm:738 -msgid "No available core (Xray) to import this node." -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:249 -msgid "No custom YAML file was selected." -msgstr "没有选择自定义 YAML 文件。" - -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_main_panel.htm:474 -msgid "No custom client proxy rules yet." -msgstr "暂无自定义客户端代理规则。" +#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/ssrurl.htm:842 +msgid "No available core (Trojan or Xray) to import this node." +msgstr "没有可用的核心(Trojan 或 Xray)可以导入此节点。" #: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/refresh.htm:21 msgid "No new data!" msgstr "你已经是最新数据,无需更新!" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1680 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1633 msgid "No specify upload file." msgstr "没有上传证书。" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/subscribe_actions_footer.htm:94 -msgid "No subscription items found" -msgstr "没有找到任何订阅项" - -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_main_panel.htm:615 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_panel.htm:32 -msgid "No switchable proxy groups found." -msgstr "未找到可切换的代理组。" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:582 -msgid "" -"Node order can be dragged with the mouse and takes effect immediately. The " -"automatic switch order of server nodes is consistent with the node order in " -"the table." -msgstr "" -"节点顺序可用鼠标拖拉后立即生效,服务器节点自动切换顺序和表中节点顺序一致。" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:255 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:385 msgid "Noise" msgstr "噪声" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:544 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:971 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1170 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1182 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1192 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:677 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:682 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:549 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:941 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1140 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1152 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1162 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:364 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:369 msgid "None" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:180 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:188 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:197 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:206 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:215 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:224 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:236 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:131 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:139 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:148 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:157 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:165 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:177 msgid "Not Running" msgstr "未运行" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:35 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:28 msgid "Not exist" msgstr "未安装可执行文件" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:108 -msgid "Not installed" -msgstr "未安装" +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1657 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1684 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:243 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:270 +msgid "Note: For node-specific DNS only. Keep Auto to avoid extra overhead." +msgstr "注意:仅用于节点专用 DNS,通常请保持自动,以免增加开销。" #: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/log.lua:27 msgid "" @@ -1740,120 +1485,116 @@ msgid "" "compatibility issues." msgstr "注意:不同版本间的配置恢复可能会导致兼容性问题。" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1606 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1559 msgid "Number of early established connections to reduce latency." msgstr "预连接的数量,用于降低延迟。" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:543 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:586 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:118 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server.lua:138 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:548 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:584 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:139 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server.lua:133 msgid "Obfs" msgstr "混淆插件" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:593 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:123 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:591 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:146 msgid "Obfs param (optional)" msgstr "混淆参数(可选)" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1226 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1196 msgid "Obfuscate password (optional)" msgstr "混淆密码(可选)" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:670 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:651 msgid "Obfuscation Password" msgstr "混淆密码" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:662 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:645 msgid "Obfuscation Type" msgstr "混淆类型" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1515 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1468 msgid "Once set, connects only when the server’s chain fingerprint matches." msgstr "设置后,仅在服务器证书链指纹匹配时连接。" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:113 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:120 msgid "Only Common Ports" msgstr "仅常用端口(不走 P2P 流量到代理)" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:208 -msgid "Only when HTTP Auth Mode is password valid, Mandatory." -msgstr "仅当 HTTP 认证模式为 password 时有效,必填。" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:212 -msgid "Only when HTTP Auth Mode is password valid, Not mandatory." -msgstr "仅当 HTTP 认证模式为 password 时有效,非必填。" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:170 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:324 msgid "Only when Socks5 Auth Mode is password valid, Mandatory." msgstr "仅当 Socks5 认证方式为 Password 时有效,必填。" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:175 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:329 msgid "Only when Socks5 Auth Mode is password valid, Not mandatory." msgstr "仅当 Socks5 认证方式为 Password 时有效,非必填。" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:154 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:144 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:172 msgid "OpenDNS" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:138 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:175 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:129 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:210 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:153 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:239 msgid "OpenDNS (208.67.220.220)" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:137 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:174 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:128 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:209 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:152 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:238 msgid "OpenDNS (208.67.222.222)" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:391 -msgid "Package Name" -msgstr "组件包名称" +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:115 +msgid "Oversea Mode" +msgstr "海外用户回国模式" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:261 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:161 +msgid "Oversea Mode DNS-1 (114.114.114.114)" +msgstr "" + +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:162 +msgid "Oversea Mode DNS-2 (114.114.115.115)" +msgstr "" + +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:391 msgid "Packet or Rand length as a string, e.g., 10-20." msgstr "数据包或 Rand 长度以字符串形式输入,例如:10-20。" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:298 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:428 msgid "Packet | Rand Length" msgstr "数据包 | Rand 长度" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_panel_button.htm:68 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_panel_button.htm:69 -msgid "Panel" -msgstr "面板" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:488 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:93 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:496 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:114 msgid "Password" msgstr "密码" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/ssrurl.htm:102 +#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/ssrurl.htm:105 msgid "Paste sharing link here" msgstr "在此处粘贴分享链接" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1257 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1227 msgid "Peer public key" msgstr "节点公钥" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/server_table.htm:154 -msgid "Per page" -msgstr "每页" - #: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/reset.htm:14 #: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/reset.htm:23 msgid "Perform reset" msgstr "执行重置" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1162 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1132 msgid "Permit Without Stream" msgstr "允许无数据流" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:725 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:393 msgid "Ping Latency" msgstr "Ping 延迟" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1687 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1640 msgid "Please confirm the current certificate path" msgstr "请选择确认所传证书,证书不正确将无法运行" @@ -1861,108 +1602,96 @@ msgstr "请选择确认所传证书,证书不正确将无法运行" msgid "Please fill in reset" msgstr "请填写 reset" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:387 -msgid "Please specify either a Clash subscription URL or a local YAML path." -msgstr "请填写 Clash 订阅 URL 或本地 YAML 路径中的至少一项。" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:572 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:570 msgid "Plugin Opts" msgstr "插件参数" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_main_panel.htm:1033 -msgid "Policy" -msgstr "策略" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:643 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:626 msgid "Port Hopping Interval(Unit:Second)" msgstr "端口跳跃间隔(单位:秒)" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:625 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:608 msgid "Port hopping range" msgstr "端口跳跃范围" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1606 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1559 msgid "Pre-connections" msgstr "预连接" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1261 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1231 msgid "Pre-shared key" msgstr "预共享密钥" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:130 -msgid "Prefer module built-in DNS" -msgstr "优先使用模块内置 DNS" +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1689 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:275 +msgid "Prefer IPv4" +msgstr "IPv4 优先" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/server_table.htm:139 -msgid "Prev" -msgstr "上一页" +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1690 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:276 +msgid "Prefer IPv6" +msgstr "IPv6 优先" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:232 -msgid "Private Key File Path" -msgstr "私钥文件路径" +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:93 +msgid "Prefer firewall tools" +msgstr "首选防火墙工具" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1252 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1222 msgid "Private key" msgstr "私钥" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:150 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:254 -msgid "Processing..." -msgstr "处理中..." - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:576 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:113 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server.lua:133 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:574 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:132 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server.lua:128 msgid "Protocol" msgstr "传输协议" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:583 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:581 msgid "Protocol param (optional)" msgstr "传输协议参数(可选)" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:111 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:118 msgid "Proxy Ports" msgstr "需要代理的端口" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1356 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1320 msgid "Public key" msgstr "公钥" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:371 -msgid "QUIC Camouflage Type" -msgstr "QUIC 伪装(混淆)类型" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1175 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:367 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1145 msgid "QUIC Key" msgstr "QUIC 密钥" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1168 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:359 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1138 msgid "QUIC Security" msgstr "QUIC 加密方式" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:715 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:685 msgid "QUIC initConnReceiveWindow" msgstr "QUIC 初始的连接接收窗口大小" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:701 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:671 msgid "QUIC initStreamReceiveWindow" msgstr "QUIC 初始流接收窗口大小。" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:722 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:692 msgid "QUIC maxConnReceiveWindow" msgstr "QUIC 最大的连接接收窗口大小" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:729 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:699 msgid "QUIC maxIdleTimeout(Unit:second)" msgstr "QUIC 最长空闲超时时间(单位:秒)" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:708 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:678 msgid "QUIC maxStreamReceiveWindow" msgstr "QUIC 最大的流接收窗口大小" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1351 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:177 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:205 +msgid "Quad9 DNSCrypt SDNS" +msgstr "" + +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1315 msgid "REALITY" msgstr "" @@ -1970,59 +1699,33 @@ msgstr "" msgid "RST Backup" msgstr "恢复备份" -#: applications/luci-app-ssr-plus/luasrc/controller/shadowsocksr.lua:429 #: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/status.htm:7 msgid "RUNNING" msgstr "运行中" -#: applications/luci-app-ssr-plus/luasrc/controller/shadowsocksr.lua:422 -msgid "RUNNING in %s (%s) Mode" -msgstr "运行中,当前为 %s(%s)模式" - -#: applications/luci-app-ssr-plus/luasrc/controller/shadowsocksr.lua:426 -msgid "RUNNING in %s Mode" -msgstr "运行中,当前为 %s 模式" - -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_main_panel.htm:604 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_main_panel.htm:752 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_main_panel.htm:802 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_panel.htm:93 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:228 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/subscribe.htm:253 -msgid "Ready." -msgstr "就绪。" - #: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/reset.htm:5 msgid "Really reset all changes?" msgstr "真的重置所有更改吗?" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:609 -msgid "Realm STUN" -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:606 -msgid "Realm URL" -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:744 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_main_panel.htm:272 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_panel_button.htm:17 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:403 msgid "Reapply" msgstr "重新应用" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:259 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:264 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:270 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:277 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:200 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:205 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:211 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:218 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:225 msgid "Records" msgstr "条记录" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_panel.htm:10 -msgid "Refresh" -msgstr "更新" +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:406 +msgid "Redirect traffic to this network interface" +msgstr "分流到这个网络接口" #: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/refresh.htm:29 #: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/refresh.htm:35 +#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/subscribe.htm:11 msgid "Refresh Data" msgstr "更新数据库" @@ -2035,90 +1738,45 @@ msgid "Refresh OK!" msgstr "更新成功!" #: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/refresh.htm:6 +#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/subscribe.htm:5 msgid "Refresh..." msgstr "正在更新,请稍候..." -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:431 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:134 msgid "Regular update (Hour)" msgstr "定时更新(小时)" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:439 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:142 msgid "Regular update (Min)" msgstr "定时更新(分钟)" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:111 -msgid "Release Asset" -msgstr "发布包名" - -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_panel_button.htm:56 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_panel_button.htm:57 -msgid "Reload YAML" -msgstr "重载 YAML" - -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_main_panel.htm:265 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_panel_button.htm:10 -msgid "Reloading YAML..." -msgstr "正在重载 YAML..." - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:133 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:134 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_main_panel.htm:1034 -msgid "Remarks" -msgstr "备注" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1619 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1635 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1572 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1588 msgid "Reno" -msgstr "Reno" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:154 -msgid "Required for VMess/VLESS. Generate with: uuidgen" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1247 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1217 msgid "Reserved bytes(optional)" msgstr "保留字节(可选)" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_main_panel.htm:998 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_main_panel.htm:999 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_panel_button.htm:62 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_panel_button.htm:63 -msgid "Reset Default Proxies Rules" -msgstr "重置代理分组规则" - -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_main_panel.htm:300 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_panel_button.htm:44 -msgid "Reset Defaults Failed!" -msgstr "重置默认值失败!" - #: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/reset.htm:17 #: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/reset.htm:18 msgid "Reset complete" msgstr "重置完成" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_main_panel.htm:286 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_panel_button.htm:30 -msgid "Reset saved Mihomo proxy-group selections and restore YAML defaults?" -msgstr "要清空已保存的 Mihomo 分组选择,并恢复为 YAML 默认值吗?" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:144 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:259 msgid "Reset to defaults" msgstr "恢复出厂设置" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_main_panel.htm:290 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_panel_button.htm:34 -msgid "Resetting Defaults..." -msgstr "正在重置默认值..." - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:120 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:127 msgid "Resolve Dns Mode" msgstr "DNS 解析方式" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:241 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:182 msgid "Restart Service" msgstr "重启服务" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:240 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:181 msgid "Restart ShadowSocksR Plus+" msgstr "重启 ShadowSocksR Plus+" @@ -2131,93 +1789,92 @@ msgstr "恢复备份文件" msgid "Restore to default configuration" msgstr "恢复默认配置" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:178 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:186 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:195 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:204 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:213 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:222 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:234 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:129 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:137 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:146 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:155 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:163 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:175 msgid "Running" msgstr "运行中" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:105 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:111 msgid "Running Mode" msgstr "运行模式" -#: applications/luci-app-ssr-plus/luasrc/controller/shadowsocksr.lua:403 -msgid "SOCKS5" -msgstr "SOCKS5" - -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/ssrurl.htm:301 +#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/ssrurl.htm:342 msgid "SS URL base64 sstr format not recognized." msgstr "无法识别 SS URL 的 Base64 格式。" -#: applications/luci-app-ssr-plus/luasrc/controller/shadowsocksr.lua:625 +#: applications/luci-app-ssr-plus/luasrc/controller/shadowsocksr.lua:56 msgid "SSR Client" msgstr "客户端" -#: applications/luci-app-ssr-plus/luasrc/controller/shadowsocksr.lua:629 +#: applications/luci-app-ssr-plus/luasrc/controller/shadowsocksr.lua:60 msgid "SSR Server" msgstr "服务端" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_main_panel.htm:1023 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/subscribe_actions_footer.htm:260 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/subscribe_actions_footer.htm:285 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/subscribe_actions_footer.htm:286 -msgid "Save" -msgstr "保存" +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:277 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:71 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:79 +msgid "Same as Global Server" +msgstr "与全局服务器相同" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:492 -msgid "Save Subscribe Settings" -msgstr "保存订阅设置" +#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/server_list.htm:750 +msgid "Save Order" +msgstr "保存当前顺序" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:467 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:286 msgid "Save Words splited by /" msgstr "" "命中关键字的节点将被保留。多个关键字用 / 分隔。此项为空则不启用保留匹配" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:494 -msgid "Save current subscribe settings" -msgstr "保存当前订阅设置" +#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/server_list.htm:484 +msgid "Save failed!" +msgstr "保存失败!" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/subscribe_actions_footer.htm:82 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/subscribe_actions_footer.htm:105 -msgid "Save failed:" -msgstr "保存失败:" +#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/server_list.htm:482 +msgid "Saved current page order successfully." +msgstr "保存当前页面顺序成功。" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_main_panel.htm:687 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/subscribe_actions_footer.htm:51 -msgid "Saving..." -msgstr "保存中..." +#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/server_list.htm:747 +msgid "Saving the new order..." +msgstr "正在保存新的顺序…" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/advanced_switch_compact.htm:77 -msgid "Second" -msgstr "周期" +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:158 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:186 +msgid "Select DNS parse Mode" +msgstr "选择 DNS 解析方式" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1640 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:410 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:228 +msgid "Selection ShadowSocks Node Use Version." +msgstr "选择 ShadowSocks 节点使用版本。" + +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1593 msgid "Self-signed Certificate" msgstr "自签证书" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:424 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:276 +msgid "Server" +msgstr "服务器" + +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:456 msgid "Server Address" msgstr "服务器地址" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:506 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:317 msgid "Server Count" msgstr "服务器节点数量" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:223 -msgid "Server Name (SNI)" -msgstr "服务器名称(SNI)" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:335 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:340 msgid "Server Node Type" msgstr "服务器节点类型" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:449 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:75 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server.lua:117 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:469 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:96 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server.lua:112 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:372 msgid "Server Port" msgstr "端口" @@ -2225,293 +1882,258 @@ msgstr "端口" msgid "Server Setting" msgstr "服务端配置" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:58 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:86 #: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server.lua:107 msgid "Server Type" msgstr "服务端类型" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:73 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:56 msgid "Server failsafe auto swith and custom update settings" msgstr "服务器节点故障自动切换/广告屏蔽/中国大陆 IP 段数据库更新设置" -#: applications/luci-app-ssr-plus/luasrc/controller/shadowsocksr.lua:626 +#: applications/luci-app-ssr-plus/luasrc/controller/shadowsocksr.lua:57 msgid "Servers Nodes" msgstr "服务器节点" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:393 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:111 msgid "Servers subscription and manage" msgstr "服务器节点订阅与管理" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1345 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1309 msgid "Session Ticket" msgstr "会话凭据" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:358 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:558 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:167 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:195 +msgid "Set Single DNS" +msgstr "设置单个 DNS" + +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:363 msgid "Shadow-TLS" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:776 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:746 msgid "Shadow-TLS ChainPoxy type" msgstr "代理链类型" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:343 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:346 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:413 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:61 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:348 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:445 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:89 msgid "ShadowSocks" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:779 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:415 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:101 +msgid "ShadowSocks-libev Version" +msgstr "ShadowSocks-libev 版本" + +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:412 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:749 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:98 msgid "ShadowSocks-rust Version" msgstr "ShadowSocks-rust 版本" -#: applications/luci-app-ssr-plus/luasrc/controller/shadowsocksr.lua:622 +#: applications/luci-app-ssr-plus/luasrc/controller/shadowsocksr.lua:53 msgid "ShadowSocksR Plus+" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:51 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:38 msgid "ShadowSocksR Plus+ Settings" msgstr "ShadowSocksR Plus+ 设置" -#: applications/luci-app-ssr-plus/luasrc/controller/shadowsocksr.lua:405 -msgid "ShadowTLS" -msgstr "ShadowTLS" +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:757 +msgid "Shadowsocks password" +msgstr "shadowsocks密码" -#: applications/luci-app-ssr-plus/luasrc/controller/shadowsocksr.lua:373 -msgid "Shadowsocks" -msgstr "Shadowsocks" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:787 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:166 -msgid "Shadowsocks Password" +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:345 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:92 +msgid "ShadowsocksR" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/controller/shadowsocksr.lua:383 -msgid "Shadowsocks-rust" -msgstr "Shadowsocks-rust" - -#: applications/luci-app-ssr-plus/luasrc/controller/shadowsocksr.lua:381 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:340 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:64 -msgid "ShadowsocksR" -msgstr "ShadowsocksR" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1360 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1324 msgid "Short ID" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/server_table.htm:134 -msgid "Showing %d-%d of %d nodes" -msgstr "当前显示第 %d-%d 个节点,共 %d 个" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:685 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:377 msgid "Socket Connected" msgstr "连接测试" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:420 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:452 msgid "Socks" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:941 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:911 msgid "Socks Version" msgstr "Socks 版本" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:163 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:310 msgid "Socks protocol auth methods, default:noauth." msgstr "Socks 协议的认证方式,默认值:noauth。" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:361 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:59 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:366 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:87 msgid "Socks5" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:163 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:310 msgid "Socks5 Auth Mode" msgstr "Socks5 认证方式" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:175 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:329 msgid "Socks5 Password" msgstr "Socks5 密码" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:170 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:324 msgid "Socks5 User" msgstr "Socks5 用户名" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/server_list.htm:73 -msgid "Start Detection" -msgstr "开始探测" +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:151 +msgid "Specifically for edit dnsproxy DNS parse files." +msgstr "专门用于编辑 DNSPROXY 的 DNS 解析文件。" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/subscribe.htm:205 -msgid "Starting subscription update..." -msgstr "正在开始更新订阅..." - -#: applications/luci-app-ssr-plus/luasrc/controller/shadowsocksr.lua:631 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:114 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:116 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:118 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:120 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:224 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:226 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:228 +#: applications/luci-app-ssr-plus/luasrc/controller/shadowsocksr.lua:61 msgid "Status" msgstr "状态" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/server_list.htm:74 -msgid "Stop Detection" -msgstr "停止探测" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:453 -msgid "Subscribe Advanced Settings" -msgstr "订阅高级设置" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:478 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:302 msgid "Subscribe Default Auto-Switch" msgstr "订阅新节点自动切换设置" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:459 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:280 msgid "Subscribe Filter Words" msgstr "订阅节点关键字过滤" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/subscribe.htm:250 -msgid "Subscribe Log" -msgstr "订阅日志" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:465 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:284 msgid "Subscribe Save Words" msgstr "订阅节点关键字保留检查" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:551 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:575 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:235 msgid "Subscribe URL" -msgstr "订阅 URL (支持SS/SSR/V2/TROJAN/HY2/TUIC/CLASH等)" +msgstr "SS/SSR/V2/TROJAN/HY2/TUIC 订阅 URL" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/subscribe.htm:194 -msgid "Subscribe failed, refreshing page..." -msgstr "订阅失败,正在刷新页面..." - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:480 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:304 msgid "Subscribe new add server default Auto-Switch on" msgstr "订阅加入的新节点默认开启自动切换" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:473 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:299 msgid "Subscribe nodes allows insecure connection as TLS client (insecure)" msgstr "订阅节点强制开启 不验证TLS客户端证书 (insecure)" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:142 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:257 msgid "Support AdGuardHome and DNSMASQ format list" msgstr "同时支持 AdGuard Home 和 DNSMASQ 格式的过滤列表" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:644 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:627 msgid "Supports a fixed value or a random range (e.g., 30, 5-30), minimum 5." msgstr "支持固定值或随机范围(如 30 或 5-30),最小 5 秒。" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1248 -msgid "" -"Supports decimal numbers separated by \",\" or Base64-encoded strings, with " -"a maximum length of 3 bytes." -msgstr "" -"支持以“,”分隔的十进制数字,或者经过 Base64 编码的字符串,其最大长度为 3 个字" -"节。" +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:242 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:269 +msgid "Supports only Xray node types." +msgstr "仅支持 Xray 类型节点。" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:84 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:67 msgid "Switch check cycly(second)" msgstr "自动切换检查周期(秒)" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_main_panel.htm:654 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_panel.htm:71 -msgid "Switch failed." -msgstr "切换失败。" - -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_main_panel.htm:651 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_panel.htm:68 -msgid "Switched successfully." -msgstr "切换成功。" - -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_main_panel.htm:644 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_panel.htm:61 -msgid "Switching..." -msgstr "正在切换..." - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:282 -msgid "TCP Camouflage Type" +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1661 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:247 +msgid "TCP" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:759 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1690 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:126 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:729 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1643 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:149 msgid "TCP Fast Open" msgstr "TCP 快速打开" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:228 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:358 msgid "" "TCP fragments, which can deceive the censorship system in some cases, such " "as bypassing SNI blacklists." msgstr "TCP 分片,在某些情况下可以欺骗审查系统,比如绕过 SNI 黑名单。" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:194 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:228 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:257 msgid "TCP upstream" msgstr "TCP 上游" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1331 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:199 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1295 msgid "TLS" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:754 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:724 msgid "TLS 1.3 Strict mode" msgstr "TLS 1.3 限定模式" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1464 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1417 msgid "TLS ALPN" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1520 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1473 msgid "TLS Certificate Name (CertName)" msgstr "TLS 证书名称(CertName)" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1515 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1468 msgid "TLS Chain Fingerprint (SHA256)" msgstr "TLS 证书链指纹(SHA256)" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1456 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1409 msgid "TLS Host" msgstr "TLS 主机名" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1520 +#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/server_list.htm:539 +msgid "TLS handshake test, latency for reference only" +msgstr "TLS握手测试,延时仅供参考" + +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1473 msgid "TLS is used to verify the leaf certificate name." msgstr "TLS 用于验证 leaf 证书的 name。" -#: applications/luci-app-ssr-plus/luasrc/controller/shadowsocksr.lua:379 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:355 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:360 msgid "TUIC" -msgstr "TUIC" +msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1476 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1429 msgid "TUIC ALPN" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:819 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:789 msgid "TUIC Server IP Address" msgstr "TUIC 服务器 IP 地址" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:826 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:796 msgid "TUIC User Password" msgstr "TUIC 用户密钥" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:812 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:782 msgid "TUIC User UUID" msgstr "TUIC 用户 uuid" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:877 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:847 msgid "TUIC receive window" msgstr "接收窗口(无需确认即可接收的最大字节数:默认8Mb)" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:871 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:841 msgid "TUIC send window" msgstr "发送窗口(无需确认即可发送的最大字节数:默认8Mb*2)" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1443 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:175 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:203 +msgid "TWNIC-101 DNSCrypt SDNS" +msgstr "" + +#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/server_list.htm:539 +#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/server_list.htm:604 +#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/server_list.htm:628 +msgid "Test" +msgstr "测试" + +#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/server_list.htm:581 +msgid "Testing..." +msgstr "检测中…" + +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1396 msgid "" "The client has not configured mldsa65Verify, but it will not perform the " "\"additional verification\" step and can still connect normally, see:" @@ -2519,74 +2141,49 @@ msgstr "" "客户端若未配置 mldsa65Verify,但它不会执行 \"附加验证\" 步骤,仍可以正常连" "接,具体请参见:" +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:280 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:311 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:171 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:199 +msgid "" +"The configured type also applies to the core specified when manually " +"importing nodes." +msgstr "配置的类型同样适用于手动导入节点时所指定的核心程序。" + #: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/reset.htm:10 msgid "The content entered is incorrect!" msgstr "输入的内容不正确!" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:736 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:706 msgid "The keep-alive period.(Unit:second)" msgstr "心跳包发送间隔(单位:秒)" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:6 -msgid "" -"The online upgrade downloads the matching Xray-core linux archive for the " -"current ARCH from the official GitHub release page." -msgstr "" -"在线升级会根据当前架构,从 Xray-core 官方 GitHub 发布页下载匹配的 Linux 压缩" -"包。" - -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:10 -msgid "" -"The online upgrade only tracks the latest stable Mihomo release and " -"downloads the matching linux archive for the current ARCH from the official " -"GitHub release page." -msgstr "" -"在线升级只跟踪 Mihomo 最新稳定版,并根据当前架构从官方 GitHub 发布页下载匹配" -"的 Linux 压缩包。" - -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:14 -msgid "" -"The online upgrade tracks the latest NaiveProxy release and prefers OpenWrt " -"static archives matching the current ARCH before falling back to other " -"release assets." -msgstr "" -"在线升级会跟踪最新 NaiveProxy 发布版,并优先选择与当前架构匹配的 OpenWrt " -"static 压缩包,找不到时再回退到其他发布资产。" - -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_main_panel.htm:740 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_main_panel.htm:795 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_panel.htm:89 -msgid "This Clash total node is not active. Apply this node first." -msgstr "该 Clash 总节点当前未启用,请先应用该节点。" - -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_panel.htm:6 -msgid "" -"This panel is available only when the current Clash total node is active." -msgstr "该面板仅在当前 Clash 总节点已启用时可用。" - -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/server_table.htm:272 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/subscribe_actions_footer.htm:126 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/subscribe_actions_footer.htm:277 -msgid "This section contains no values yet" -msgstr "该部分目前无任何内容。" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:485 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:307 msgid "Through proxy update" msgstr "通过代理更新" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:487 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:309 msgid "Through proxy update list, Not Recommended" msgstr "通过路由器自身代理更新订阅" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/advanced_switch_compact.htm:78 -msgid "Timeout" -msgstr "超时" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:853 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:823 msgid "Timeout for establishing a connection to server(second)" msgstr "连接超时时间(单位:秒)" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:260 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:162 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:190 +msgid "Tips: Dnsproxy DNS Parse List Path:" +msgstr "提示:Dnsproxy 的 DNS 解析列表路径:" + +#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/server_list.htm:736 +msgid "To Bottom" +msgstr "置底" + +#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/server_list.htm:733 +msgid "To Top" +msgstr "置顶" + +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:390 msgid "To send noise packets, select \"Noise\" in Xray Settings." msgstr "在 Xray 设置中勾选 “噪声” 以发送噪声包。" @@ -2594,57 +2191,53 @@ msgstr "在 Xray 设置中勾选 “噪声” 以发送噪声包。" msgid "Total Records:" msgstr "新的总记录数:" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:950 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:177 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:920 msgid "Transport" msgstr "传输协议" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:637 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:238 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:620 msgid "Transport Protocol" msgstr "传输协议" -#: applications/luci-app-ssr-plus/luasrc/controller/shadowsocksr.lua:399 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:412 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:315 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:351 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:444 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:91 msgid "Trojan" -msgstr "Trojan" +msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:160 -msgid "Trojan Password" -msgstr "Trojan 密码" - -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/advanced_switch_compact.htm:79 -msgid "Try Count" -msgstr "重试次数" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:282 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:674 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:412 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:362 msgid "Type" msgstr "类型" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:639 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:622 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1662 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:248 msgid "UDP" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:255 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:385 msgid "" "UDP noise, Under some circumstances it can bypass some UDP based protocol " "restrictions." msgstr "UDP 噪声,在某些情况下可以绕过一些针对 UDP 协议的限制。" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:524 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:530 msgid "UDP over TCP" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:832 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:802 msgid "UDP relay mode" msgstr "UDP 中继模式" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:195 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:229 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:258 msgid "UDP upstream" msgstr "UDP 上游" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:193 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:227 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:256 msgid "UDP/TCP upstream" msgstr "UDP/TCP 上游" @@ -2652,759 +2245,499 @@ msgstr "UDP/TCP 上游" msgid "UL Restore" msgstr "上传恢复" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:524 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:322 msgid "URL Test Address" msgstr "URL 测试地址" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:153 -msgid "UUID" -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/ssrurl.htm:92 +#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/ssrurl.htm:95 msgid "Unable to copy SSR to clipboard." msgstr "无法复制 SSR 网址到剪贴板。" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:32 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:42 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:109 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:110 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:111 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:226 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:25 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua:35 msgid "Unknown" msgstr "未知" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:80 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/subscribe_actions_footer.htm:82 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/subscribe_actions_footer.htm:130 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/subscribe_actions_footer.htm:215 -msgid "Unknown error" -msgstr "未知错误" - -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:36 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:76 -msgid "Unsupported ARCH" -msgstr "不支持当前架构" - -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:79 -msgid "Unsupported component" -msgstr "不支持的组件" - -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/subscribe_actions_footer.htm:265 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/subscribe_actions_footer.htm:266 -msgid "Update" -msgstr "更新" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:497 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:311 +#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/subscribe.htm:16 msgid "Update All Subscribe Servers" -msgstr "更新所有订阅节点" +msgstr "更新所有订阅服务器节点" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:447 -msgid "Update Interval(min)" -msgstr "更新间隔(分钟)" +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:288 +msgid "Update Subscribe List" +msgstr "更新订阅 URL 列表" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:411 -msgid "Update Mode" -msgstr "更新模式" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:418 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:121 msgid "Update cycle (Day/Week)" msgstr "更新周期(天/周)" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:29 -msgid "" -"Update geoip.dat and geosite.dat used by Xray/V2Ray runtime when available." -msgstr "更新 Xray/V2Ray 运行时可用的 geoip.dat 和 geosite.dat 数据库。" +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:290 +msgid "Update subscribe url list first" +msgstr "修改订阅 URL 和节点关键字后,请先点击更新" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:21 -msgid "" -"Update the Country.mmdb database used by Mihomo/Clash runtime when available." -msgstr "更新 Mihomo/Clash 运行时可用的 Country.mmdb 数据库。" - -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:25 -msgid "" -"Update the GeoSite.dat database used by Mihomo/Clash runtime when available." -msgstr "更新 Mihomo/Clash 运行时可用的 GeoSite.dat 数据库。" - -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/subscribe_actions_footer.htm:31 -msgid "Updating..." -msgstr "更新中..." - -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:157 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:406 -msgid "Upgrade" -msgstr "升级" - -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:118 -msgid "Upgrade available" -msgstr "发现可升级版本" - -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:35 -msgid "Upgrade completed" -msgstr "升级完成" - -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:146 -msgid "Upgrading..." -msgstr "升级中..." - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1212 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1182 msgid "Uplink Capacity(Default:Mbps)" msgstr "上行链路容量(默认:Mbps)" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1650 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1603 #: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/certupload.htm:3 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_yaml_upload.htm:3 msgid "Upload" msgstr "上传" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:544 -msgid "Upload Custom YAML File" -msgstr "上传自定义 YAML 文件" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:546 -msgid "" -"Upload a custom Clash/Mihomo YAML file. The file will be preprocessed and " -"saved as a local Clash node." -msgstr "" -"上传自定义 Clash/Mihomo YAML 文件。文件会先做预处理,再保存为本地 Clash 节" -"点。" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:263 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:271 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:276 -msgid "Uploaded YAML validation or preprocessing failed." -msgstr "上传的 YAML 校验或预处理失败。" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:128 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:120 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:144 msgid "Use ChinaDNS-NG query and cache" msgstr "使用 ChinaDNS-NG 查询并缓存" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:201 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:168 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:196 +msgid "Use DNS List File" +msgstr "使用 DNS 列表文件" + +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:264 msgid "Use DNS from WAN" msgstr "使用 WAN 下发的 DNS" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:202 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:265 msgid "Use DNS from WAN and 114DNS" msgstr "使用 WAN 下发的 DNS 和 114DNS" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:122 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:108 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:132 +msgid "Use DNS2SOCKS query and cache" +msgstr "使用 DNS2SOCKS 查询并缓存" + +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:111 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:135 +msgid "Use DNS2SOCKS-RUST query and cache" +msgstr "使用 DNS2SOCKS-RUST 查询并缓存" + +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:129 msgid "Use DNS2TCP query" msgstr "使用 DNS2TCP 查询" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:131 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:117 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:141 +msgid "Use DNSPROXY query and cache" +msgstr "使用 DNSPROXY 查询并缓存" + +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:146 msgid "Use Local DNS Service listen port 5335" msgstr "使用本机端口为 5335 的 DNS 服务" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:125 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:138 +msgid "Use MOSDNS query (Not Support Oversea Mode)" +msgstr "使用 MOSDNS 查询 (不支持海外用户回国模式)" + +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:114 msgid "Use MosDNS query" msgstr "使用 MosDNS 查询" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1202 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1172 msgid "" "Use it together with the DNS disguised type. You can fill in any domain." msgstr "配合伪装类型 DNS 使用,可随便填一个域名。" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:142 -msgid "User Level" -msgstr "用户等级" - -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/ssrurl.htm:104 +#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/ssrurl.htm:107 msgid "User cancelled." msgstr "用户已取消。" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1274 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:534 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1244 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:332 msgid "User-Agent" msgstr "用户代理(User-Agent)" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/ssrurl.htm:313 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/ssrurl.htm:1028 +#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/ssrurl.htm:295 +#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/ssrurl.htm:1133 msgid "Userinfo format error." msgstr "用户信息格式错误。" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:481 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:89 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server.lua:122 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:489 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:110 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server.lua:117 msgid "Username" msgstr "用户名" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:613 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:596 msgid "Users Authentication" msgstr "用户验证" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:371 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:395 msgid "Using incorrect encryption mothod may causes service fail to start" msgstr "输入不正确的参数组合可能会导致服务无法启动" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:28 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:430 -msgid "V2Ray GEO Databases" -msgstr "V2Ray GEO 数据库" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:337 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:342 msgid "V2Ray/XRay" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:409 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:441 msgid "V2Ray/XRay protocol" msgstr "V2Ray/XRay 协议" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:410 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:442 msgid "VLESS" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:922 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:892 msgid "VLESS Encryption" msgstr "VLESS 加密" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:411 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:443 msgid "VMess" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1183 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1193 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1153 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1163 msgid "VideoCall (SRTP)" msgstr "视频通话(SRTP)" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:782 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:752 msgid "Vmess Protocol" msgstr "VMESS 协议" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:797 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:767 msgid "Vmess UUID" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:914 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:884 msgid "Vmess/VLESS ID (UUID)" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:26 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:30 msgid "WAN Force Proxy IP" msgstr "强制走代理的 WAN IP" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:21 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:25 msgid "WAN IP AC" msgstr "WAN IP 访问控制" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:23 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:27 msgid "WAN White List IP" msgstr "不走代理的 WAN IP" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:987 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:252 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:957 msgid "WebSocket Host" msgstr "WebSocket 主机名" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:993 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:259 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:963 msgid "WebSocket Path" msgstr "WebSocket 路径" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1185 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1195 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1155 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1165 msgid "WechatVideo" msgstr "微信视频通话" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1235 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:96 +msgid "When disabled shunt mode, will same time stopped shunt service." +msgstr "当停用分流模式时,将同时停止分流服务。" + +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:198 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:227 +msgid "When disabled, all AAAA requests are not resolved." +msgstr "当禁用时,不解析所有 AAAA 请求。" + +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1205 msgid "When enabled, it occupies IPv6 routing table 1023." msgstr "启用后,将占用 IPv6 路由表 1023。" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:388 -msgid "When selected, it can be accessed from LAN. This may not be safe!" -msgstr "一旦选定,即可通过局域网进行访问。但这样做可能存在安全隐患!" +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:187 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:216 +msgid "When two or more DNS servers are deployed, enable this function." +msgstr "当部署两台或两台以上 DNS 服务器时,需要启用该功能。" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:379 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:161 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:189 msgid "" -"When selected, it can only be accessed locally. Recommended when using " -"reverse proxies." -msgstr "一旦启用,它只能在本地进行访问。在使用“反向代理”时建议使用此功能。" +"When use DNS list file, please ensure list file exists and is formatted " +"correctly." +msgstr "当使用 DNS 列表文件时,请确保列表文件存在并且格式正确。" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:415 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1187 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1197 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:447 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1157 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1167 msgid "WireGuard" msgstr "WireGuard 数据包" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1267 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1237 msgid "Wireguard allows only traffic from specific source IP." msgstr "Wireguard 仅允许特定源 IP 的流量。" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1053 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1023 msgid "XHTTP Extra" msgstr "XHTTP 附加项" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1041 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1011 msgid "XHTTP Host" msgstr "XHTTP 主机名" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1032 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1002 msgid "XHTTP Mode" msgstr "XHTTP 模式" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1047 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1017 msgid "XHTTP Path" msgstr "XHTTP 路径" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:207 -msgid "XTLS" +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:287 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:87 +msgid "Xray (Hysteria2)" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/controller/shadowsocksr.lua:394 -msgid "Xray" -msgstr "Xray" +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:104 +msgid "Xray (ShadowSocks)" +msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:225 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:318 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:94 +msgid "Xray (Trojan)" +msgstr "" + +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:355 msgid "Xray Fragment Settings" msgstr "Xray 分片设置" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:258 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:388 msgid "Xray Noise Packets" msgstr "Xray 噪声数据包" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:5 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:394 -msgid "Xray-core" -msgstr "Xray-core" - -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_main_panel.htm:275 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_panel_button.htm:20 -msgid "YAML Reload Failed!" -msgstr "YAML 重载失败!" - -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_main_panel.htm:272 -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_panel_button.htm:17 -msgid "YAML Reloaded!" -msgstr "YAML 已重载!" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:137 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:252 msgid "adblock_url" msgstr "广告屏蔽更新 URL" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1171 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1141 msgid "aes-128-gcm" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1584 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1537 msgid "allow" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1578 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1531 msgid "allow: Allows use Mux connection." msgstr "allow:允许走 Mux 连接。" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1498 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1451 msgid "allowInsecure" msgstr "允许不安全连接" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1266 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1236 msgid "allowedIPs(optional)" msgstr "allowedIPs(可选)" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1388 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1352 msgid "android" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:139 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:254 msgid "anti-AD" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1172 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1142 msgid "chacha20-poly1305" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:116 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:92 msgid "china-operator-ip" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1277 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1384 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1247 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1348 msgid "chrome" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1615 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1631 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:180 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:208 +msgid "cloudflare-dns.com DNSCrypt SDNS" +msgstr "" + +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1568 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1584 msgid "comment_tcpcongestion_disable" msgstr "系统默认值" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1548 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1501 msgid "concurrency" msgstr "TCP 最大并发连接数" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1282 +#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/server_list.htm:678 +msgid "connect" +msgstr "" + +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1252 msgid "curl" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1612 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1628 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1565 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1581 msgid "custom_tcpcongestion" msgstr "连接服务器节点的 TCP 拥塞控制算法" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1394 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1556 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1569 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1358 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1509 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1522 msgid "disable" msgstr "禁用" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:228 -msgid "e.g.: /etc/ssl/fullchain.pem" +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:176 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:204 +msgid "dns.sb DNSCrypt SDNS" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:233 -msgid "e.g.: /etc/ssl/private.key" -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1280 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1389 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1250 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1353 msgid "edge" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:124 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:192 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:221 +msgid "fastest_addr" +msgstr "最快响应" + +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:239 msgid "felixonmars/dnsmasq-china-list" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1278 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1385 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1248 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1349 msgid "firefox" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1150 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1120 msgid "gRPC Idle Timeout" msgstr "gPRC 空闲超时" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1123 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1093 msgid "gRPC Mode" msgstr "gRPC 模式" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1117 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1087 msgid "gRPC Service Name" msgstr "gRPC 服务名称" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:106 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:82 msgid "gfwlist Update url" msgstr "GFW 列表更新 URL" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:110 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:86 msgid "gfwlist/gfwlist" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1281 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1251 msgid "golang" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:552 -msgid "gost-plugin" -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1387 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1351 msgid "ios" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:562 -msgid "kcptun" -msgstr "" +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:190 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:219 +msgid "load_balance" +msgstr "负载均衡" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:835 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:805 msgid "lossless UDP relay using QUIC streams" msgstr "使用 QUIC 流的无损 UDP 中继" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:300 -msgid "mKCP Camouflage Type" -msgstr "mKCP 伪装(混淆)类型" - -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:46 -msgid "mihomo binary not found in archive" -msgstr "压缩包中未找到 mihomo 二进制文件" - -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:47 -msgid "naive binary not found in archive" -msgstr "压缩包中未找到 naive 二进制文件" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:834 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:804 msgid "native UDP characteristics" msgstr "原生 UDP 特性" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:514 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1373 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:99 +msgid "nfip_url" +msgstr "Netflix IP 段更新 URL" + +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:521 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1337 msgid "none" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:546 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:551 msgid "obfs-local" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1391 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:191 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:220 +msgid "parallel" +msgstr "并行查询" + +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1355 msgid "qq" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1392 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1356 msgid "random" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1393 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1357 msgid "randomized" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1583 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1536 msgid "reject" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:561 -msgid "restls" -msgstr "" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1279 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1386 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1249 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1350 msgid "safari" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:769 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:739 msgid "shadow-TLS SNI" msgstr "服务器名称指示" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:747 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:560 +msgid "shadow-tls" +msgstr "" + +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:717 msgid "shadowTLS protocol Version" msgstr "ShadowTLS 协议版本" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1585 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1538 msgid "skip" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1579 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1532 msgid "" "skip: Not use Mux module to carry UDP 443 traffic, Use original UDP " "transmission method of proxy protocol." msgstr "" "skip:不使用 Mux 模块承载 UDP 443 流量,将使用代理协议原本的 UDP 传输方式。" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1364 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1328 msgid "spiderX" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:107 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:83 msgid "v2fly/domain-list-community" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:549 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:554 msgid "v2ray-plugin" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:223 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:289 msgid "valid address:port" msgstr "有效的地址:端口" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:80 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:101 msgid "warning! Please do not reuse the port!" msgstr "警告!请不要重复使用端口!" -#: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:45 -msgid "xray binary not found in archive" -msgstr "压缩包中未找到 xray 二进制文件" - -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:555 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:557 msgid "xray-plugin" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1561 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1514 msgid "xudpConcurrency" msgstr "UDP 最大并发连接数" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1574 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1527 msgid "xudpProxyUDP443" msgstr "对被代理的 UDP/443 流量处理方式" -#~ msgid "Shadowsocks password" -#~ msgstr "shadowsocks密码" - -#~ msgid "Are you sure you want to delete subscribe link: %s ? " -#~ msgstr "确定删除此订阅链接:%s 吗?" - -#~ msgid "%s Node Use Type" -#~ msgstr "%s 节点使用类型" - -#~ msgid "Drag reorder applies within the current page only." -#~ msgstr "拖拽排序仅在当前分页内生效。" - -#~ msgid "Anti-pollution DNS Server For Shunt Mode" -#~ msgstr "分流模式下的访问国外域名 DNS 服务器" - -#~ msgid "Are you sure to delete this node?" -#~ msgstr "是否真的要删除该节点?" - -#~ msgid "Auto" -#~ msgstr "自动" - -#~ msgid "ChinaDNS-NG shunt query protocol" -#~ msgstr "ChinaDNS-NG 分流查询协议" - -#~ msgid "Click here to view or manage the DNS list file" -#~ msgstr "点击此处查看或管理 DNS 列表文件" - -#~ msgid "" -#~ "Custom DNS Server (support: IP:Port or tls://IP:Port or https://IP/dns-" -#~ "query and other format)." -#~ msgstr "" -#~ "自定义 DNS 服务器(支持格式:IP:端口、tls://IP:端口、https://IP/dns-query " -#~ "及其他格式)。" - -#~ msgid "Customize Netflix IP Url" -#~ msgstr "" -#~ "自定义 Netflix IP 段更新 URL(默认项目地址:https://github.com/QiuSimons/" -#~ "Netflix_IP)" - -#~ msgid "DNS Query Mode For Shunt Mode" -#~ msgstr "分流模式下的 DNS 查询模式" - -#~ msgid "Defines the upstreams logic mode" -#~ msgstr "定义上游逻辑模式" - -#~ msgid "" -#~ "Defines the upstreams logic mode, possible values: load_balance, " -#~ "parallel, fastest_addr (default: load_balance)." -#~ msgstr "" -#~ "定义上游逻辑模式,可选择值:负载均衡、并行查询、最快响应(默认值:负载均" -#~ "衡)。" - -#~ msgid "Disable IPv6 In MosDNS Query Mode (Shunt Mode)" -#~ msgstr "禁止 MosDNS 返回 IPv6 记录 (分流模式)" - -#~ msgid "Disable IPv6 in MOSDNS query mode" -#~ msgstr "禁止 MOSDNS 返回 IPv6 记录" - -#~ msgid "Disable IPv6 query mode" -#~ msgstr "禁止返回 IPv6 记录" - -#~ msgid "Drag to reorder" -#~ msgstr "拖动以重排" - -#~ msgid "Enable Netflix Mode" -#~ msgstr "启用 Netflix 分流模式" - -#~ msgid "External Proxy Mode" -#~ msgstr "分流服务器(前置)代理" - -#~ msgid "Forward Netflix Proxy through Main Proxy" -#~ msgstr "分流服务器流量通过主服务节点中转代理转发" - -#~ msgid "Game Mode UDP Server" -#~ msgstr "游戏模式 UDP 中继服务器" - -#~ msgid "Netflix Domain List" -#~ msgstr "Netflix 分流域名列表" - -#~ msgid "Netflix IP Data" -#~ msgstr "【Netflix IP 段】数据库" - -#~ msgid "Netflix Node" -#~ msgstr "Netflix 分流服务器" - -#~ msgid "Network Tunnel" -#~ msgstr "网络隧道" - -#~ msgid "Network interface to use" -#~ msgstr "使用的网络接口" - -#~ msgid "No available core (Trojan or Xray) to import this node." -#~ msgstr "没有可用的核心(Trojan 或 Xray)可以导入此节点。" - -#~ msgid "Oversea Mode" -#~ msgstr "海外用户回国模式" - -#~ msgid "Redirect traffic to this network interface" -#~ msgstr "分流到这个网络接口" - -#~ msgid "Client rules exported to CSV text." -#~ msgstr "客户端规则已导出为 CSV 文本。" - -#~ msgid "Client rules imported from CSV text. Click Save to apply." -#~ msgstr "客户端规则已从 CSV 文本导入,请点击保存生效。" - -#~ msgid "Same as Global Server" -#~ msgstr "与全局服务器相同" - -#~ msgid "Save Order" -#~ msgstr "保存当前顺序" - -#~ msgid "Save failed!" -#~ msgstr "保存失败!" - -#~ msgid "Saved current page order successfully." -#~ msgstr "保存当前页面顺序成功。" - -#~ msgid "Saving the new order..." -#~ msgstr "正在保存新的顺序…" - -#~ msgid "Select DNS parse Mode" -#~ msgstr "选择 DNS 解析方式" - -#~ msgid "Server" -#~ msgstr "服务器" - -#~ msgid "Set Single DNS" -#~ msgstr "设置单个 DNS" - -#~ msgid "Supports only Xray node types." -#~ msgstr "仅支持 Xray 类型节点。" - -#~ msgid "TLS handshake test, latency for reference only" -#~ msgstr "TLS握手测试,延时仅供参考" - -#~ msgid "Test" -#~ msgstr "测试" - -#~ msgid "Testing..." -#~ msgstr "检测中…" - -#~ msgid "" -#~ "The configured type also applies to the core specified when manually " -#~ "importing nodes." -#~ msgstr "配置的类型同样适用于手动导入节点时所指定的核心程序。" - -#~ msgid "Tips: Dnsproxy DNS Parse List Path:" -#~ msgstr "提示:Dnsproxy 的 DNS 解析列表路径:" - -#~ msgid "To Bottom" -#~ msgstr "置底" - -#~ msgid "To Top" -#~ msgstr "置顶" - -#~ msgid "Use DNS List File" -#~ msgstr "使用 DNS 列表文件" - -#~ msgid "Use DNS2SOCKS query and cache" -#~ msgstr "使用 DNS2SOCKS 查询并缓存" - -#~ msgid "Use DNS2SOCKS-RUST query and cache" -#~ msgstr "使用 DNS2SOCKS-RUST 查询并缓存" - -#~ msgid "Use MOSDNS query (Not Support Oversea Mode)" -#~ msgstr "使用 MOSDNS 查询 (不支持海外用户回国模式)" - -#~ msgid "When disabled shunt mode, will same time stopped shunt service." -#~ msgstr "当停用分流模式时,将同时停止分流服务。" - -#~ msgid "When disabled, all AAAA requests are not resolved." -#~ msgstr "当禁用时,不解析所有 AAAA 请求。" - -#~ msgid "When two or more DNS servers are deployed, enable this function." -#~ msgstr "当部署两台或两台以上 DNS 服务器时,需要启用该功能。" - -#~ msgid "" -#~ "When use DNS list file, please ensure list file exists and is formatted " -#~ "correctly." -#~ msgstr "当使用 DNS 列表文件时,请确保列表文件存在并且格式正确。" - -#~ msgid "fastest_addr" -#~ msgstr "最快响应" - -#~ msgid "load_balance" -#~ msgstr "负载均衡" - -#~ msgid "nfip_url" -#~ msgstr "Netflix IP 段更新 URL" - -#~ msgid "parallel" -#~ msgstr "并行查询" - #~ msgid "Congestion" #~ msgstr "拥塞控制" @@ -3594,6 +2927,9 @@ msgstr "对被代理的 UDP/443 流量处理方式" #~ msgid "DNS Server IP:Port" #~ msgstr "DNS 服务器 IP:Port" +#~ msgid "Update" +#~ msgstr "更新" + #~ msgid "Router Self AC" #~ msgstr "路由器自身代理设置" @@ -3632,36 +2968,3 @@ msgstr "对被代理的 UDP/443 流量处理方式" #~ msgid "Reset Error" #~ msgstr "重置错误" - -#~ msgid "Selector" -#~ msgstr "选择器" - -#~ msgid "DIRECT" -#~ msgstr "直连" - -#~ msgid "REJECT" -#~ msgstr "拒绝" - -#~ msgid "Proxy" -#~ msgstr "代理" - -#~ msgid "Domestic" -#~ msgstr "国内" - -#~ msgid "GlobalTV" -#~ msgstr "国际流媒体" - -#~ msgid "AsianTV" -#~ msgstr "亚洲流媒体" - -#~ msgid "Others" -#~ msgstr "其他" - -#~ msgid "GLOBAL" -#~ msgstr "全局" - -#~ msgid "Subscribe complete, refreshing page..." -#~ msgstr "订阅完成,正在刷新页面..." - -#~ msgid "Include Mihomo (Clash Support)" -#~ msgstr "包含 Mihomo(Clash 支持)" diff --git a/luci-app-ssr-plus/root/etc/hotplug.d/iface/99-ssrplus-pppoe b/luci-app-ssr-plus/root/etc/hotplug.d/iface/99-ssrplus-pppoe deleted file mode 100644 index fc969f71..00000000 --- a/luci-app-ssr-plus/root/etc/hotplug.d/iface/99-ssrplus-pppoe +++ /dev/null @@ -1,22 +0,0 @@ -#!/bin/sh - -[ "$ACTION" = "ifup" ] || exit 0 -[ "$INTERFACE" = "wan" ] || exit 0 - -WAN_PROTO="$(uci -q get network.wan.proto 2>/dev/null)" -[ "$WAN_PROTO" = "pppoe" ] || exit 0 - -LOCK_FILE="/var/run/ssrplus-pppoe-hotplug.lock" - -( - if ! mkdir "$LOCK_FILE" 2>/dev/null; then - exit 0 - fi - - trap 'rmdir "$LOCK_FILE" 2>/dev/null' EXIT INT TERM - - sleep 10 - /etc/init.d/shadowsocksr restart >/dev/null 2>&1 -) >/dev/null 2>&1 & - -exit 0 diff --git a/luci-app-ssr-plus/root/etc/init.d/shadowsocksr b/luci-app-ssr-plus/root/etc/init.d/shadowsocksr index 1970fa94..1d5c3297 100755 --- a/luci-app-ssr-plus/root/etc/init.d/shadowsocksr +++ b/luci-app-ssr-plus/root/etc/init.d/shadowsocksr @@ -21,10 +21,6 @@ PERSIST_DIR="/usr/share/nftables.d/ruleset-post" PERSIST_FILE="$PERSIST_DIR/99-shadowsocksr.nft" BACKUP_DIR="/etc/ssrplus/ssrplus-persist" BACKUP_FILE="$BACKUP_DIR/99-shadowsocksr.save" -CLASH_CONFIG_DIR="/etc/ssrplus/clash" -CLASH_API_PORT="16756" -CLASH_OUTBOUND_MARK="255" -CLASH_YAML_HELPER="/usr/share/shadowsocksr/clash_yaml.lua" # 设置 DNSMASQ_CONF_DIR 和 TMP_DNSMASQ_PATH if [ -f /etc/openwrt_release ]; then # 获取默认的 DNSMASQ 配置 ID @@ -46,10 +42,8 @@ shunt_config_file= local_config_file= shunt_dns_config_file= tmp_local_port= -DNS2TCP_FILTER_AAAA_SUPPORTED= ARG_UDP= -ARG_UDP_RULES= dns_port="5335" #dns port china_dns_port="5333" #china_dns_port @@ -65,7 +59,6 @@ server_count=0 redir_tcp=0 redir_udp=0 local_enable=0 -http_enable=0 kcp_enable_flag=0 pdnsd_enable_flag=0 @@ -73,27 +66,17 @@ USE_TABLES="" HAS_NFT=0 HAS_IPSET=0 HAS_IPT=0 -HAS_FW3=0 HAS_FW4=0 DNSMASQ_IPSET=0 DNSMASQ_NFTSET=0 switch_server=$1 CRON_FILE=/etc/crontabs/root -EXTRA_COMMANDS='reset clash_cache' -EXTRA_HELP=" reset Reset to default settings - clash_cache Download and cache Clash node config" +EXTRA_COMMANDS='reset' +EXTRA_HELP=" reset Reset to default settings" #extra_command "reset" "Reset to default settings" PS="/bin/busybox ps" -ps_list() { - if $PS -w >/dev/null 2>&1; then - $PS -w - else - $PS - fi -} - uci_get_by_name() { local ret=$(uci get $NAME.$1.$2 2>/dev/null) echo ${ret:=$3} @@ -115,478 +98,21 @@ uci_set_by_type() { } uci_get_by_cfgid() { - local key="$NAME.@$1[0]" - [ -n "$2" ] && key="$key.$2" - local ret=$(uci show "$key" 2>/dev/null | awk -F '[.=]' 'NR==1 {print $2}') + local ret=$(uci show $NAME.@$1[0].$2 | awk -F '.' '{print $2}' 2>/dev/null) echo ${ret:=$3} } -get_filter_aaaa() { - local ret="$(uci get $NAME.@global[0].filter_aaaa 2>/dev/null)" - [ -z "$ret" ] && ret="$(uci get $NAME.@global[0].mosdns_ipv6 2>/dev/null)" - echo "${ret:=1}" -} - -supports_dns2tcp_filter_aaaa() { - local dns2tcp_bin="${1:-$(first_type dns2tcp)}" - - [ -n "$dns2tcp_bin" ] || return 1 - - if [ -n "$DNS2TCP_FILTER_AAAA_SUPPORTED" ]; then - [ "$DNS2TCP_FILTER_AAAA_SUPPORTED" = "1" ] - return $? - fi - - if "$dns2tcp_bin" -h 2>&1 | grep -Eq '(^|[[:space:]])-A([[:space:]]|$)'; then - DNS2TCP_FILTER_AAAA_SUPPORTED=1 - return 0 - fi - - DNS2TCP_FILTER_AAAA_SUPPORTED=0 - return 1 -} - -start_dns2tcp() { - local dnsserver="$1" - local dns2tcp_bin="$(first_type dns2tcp)" - - if [ "$(get_filter_aaaa)" = "1" ]; then - if supports_dns2tcp_filter_aaaa "$dns2tcp_bin"; then - ln_start_bin "$dns2tcp_bin" dns2tcp -L "127.0.0.1#$dns_port" -R "${dnsserver/:/#}" -A - else - echolog "警告:当前 dns2tcp 不支持 AAAA 过滤参数(-A),已改为不带该参数启动。请升级 dns2tcp 版本。" - ln_start_bin "$dns2tcp_bin" dns2tcp -L "127.0.0.1#$dns_port" -R "${dnsserver/:/#}" - fi - else - ln_start_bin "$dns2tcp_bin" dns2tcp -L "127.0.0.1#$dns_port" -R "${dnsserver/:/#}" - fi -} - -supports_builtin_dns() { - case "$1" in - clash|tuic|v2ray|ss) - return 0 - ;; - *) - return 1 - ;; - esac -} - -get_builtin_dns_fallback_mode() { - if is_finded "dns2tcp"; then - echo "1" - elif is_finded "chinadns-ng"; then - echo "6" - elif is_finded "mosdns"; then - echo "4" - else - echo "0" - fi -} - -get_dns2tcp_fallback_mode() { - if is_finded "dns2tcp"; then - echo "1" - else - echo "0" - fi -} - -force_dns2tcp_fallback() { - local reason="$1" - local fallback_mode="$(get_dns2tcp_fallback_mode)" - - if [ "$fallback_mode" = "1" ]; then - echolog "提示:${reason},强制回退到 dns2tcp 模式。" - echo "1" - return 0 - fi - - echolog "错误:${reason},且未安装 dns2tcp,启动终止。" - return 1 -} - -is_builtin_dns_active() { - local global_server_type="$(uci_get_by_name "$GLOBAL_SERVER" type)" - case "$global_server_type" in - clash|tuic|ss) - ps_list | grep -v "grep" | grep -q "ssr-retcp" - ;; - v2ray) - ps_list | grep -v "grep" | grep -q "$TMP_PATH/.*ssr-retcp\\.json" - ;; - *) - return 1 - ;; - esac -} - -get_default_node_local_port() { - uci_get_by_type global default_node_local_port 1234 -} - -get_configured_threads() { - local threads - if [ "$(uci_get_by_type global threads 0)" = "0" ]; then - threads=$(grep -c '^processor' /proc/cpuinfo 2>/dev/null) - else - threads=$(uci_get_by_type global threads 1) - fi - - case "$threads" in - ''|*[!0-9]*) - threads=1 - ;; - esac - - [ "$threads" -lt 1 ] && threads=1 - echo "$threads" -} - -get_clash_api_secret() { - echo "${1}_ssrplus_clash" -} - -get_clash_workdir() { - echo "$TMP_PATH/clash-$1" -} - -get_clash_cache_file() { - echo "$CLASH_CONFIG_DIR/$1.yaml" -} - -get_clash_state_file() { - echo "$CLASH_CONFIG_DIR/$1.cache.db" -} - -get_tuic_workdir() { - echo "$TMP_PATH/tuic-$1" -} - -get_tuic_runtime_file() { - echo "$(get_tuic_workdir "$1")/config.yaml" -} - -get_ss_mihomo_workdir() { - echo "$TMP_PATH/ss-$1" -} - -get_ss_mihomo_runtime_file() { - echo "$(get_ss_mihomo_workdir "$1")/config.yaml" -} - -get_ss_server_mihomo_workdir() { - echo "$TMP_PATH/ss-server-$1" -} - -get_ss_server_mihomo_runtime_file() { - echo "$(get_ss_server_mihomo_workdir "$1")/config.yaml" -} - -link_mihomo_geodata() { - local workdir="$1" - - [ -n "$workdir" ] || return 0 - - [ -s /usr/share/shadowsocksr/Country.mmdb ] && ln -sf /usr/share/shadowsocksr/Country.mmdb "$workdir/Country.mmdb" - [ -s /usr/share/shadowsocksr/Country.mmdb ] && ln -sf /usr/share/shadowsocksr/Country.mmdb "$workdir/geoip.metadb" - [ ! -e "$workdir/Country.mmdb" ] && [ -s /etc/openclash/Country.mmdb ] && ln -sf /etc/openclash/Country.mmdb "$workdir/Country.mmdb" - [ ! -e "$workdir/geoip.metadb" ] && [ -s /etc/openclash/Country.mmdb ] && ln -sf /etc/openclash/Country.mmdb "$workdir/geoip.metadb" - - if [ -s /usr/share/v2ray/geosite.dat ]; then - ln -sf /usr/share/v2ray/geosite.dat "$workdir/GeoSite.dat" - ln -sf /usr/share/v2ray/geosite.dat "$workdir/geosite.dat" - else - [ -s /etc/openclash/GeoSite.dat ] && ln -sf /etc/openclash/GeoSite.dat "$workdir/GeoSite.dat" - [ -s /etc/openclash/geosite.dat ] && ln -sf /etc/openclash/geosite.dat "$workdir/geosite.dat" - fi - - if [ -s /usr/share/v2ray/geoip.dat ]; then - ln -sf /usr/share/v2ray/geoip.dat "$workdir/geoip.dat" - else - [ -s /etc/openclash/geoip.dat ] && ln -sf /etc/openclash/geoip.dat "$workdir/geoip.dat" - fi -} - -prepare_tuic_runtime_config() { - local sid="$1" - local local_port="$2" - local socks_port="$3" - local instance_key="${4:-$sid}" - local run_mode="${5:-redir}" - local runtime_file="$(get_tuic_runtime_file "$instance_key")" - local workdir="$(get_tuic_workdir "$instance_key")" - - [ -n "$sid" ] || return 1 - [ -n "$local_port" ] || return 1 - - mkdir -p "$workdir" - if ! /usr/bin/lua "$CLASH_YAML_HELPER" tuic "$sid" "$runtime_file" "$local_port" "$socks_port" "$run_mode" >/dev/null 2>&1; then - echolog "TUIC 节点运行配置生成失败:$sid" - return 1 - fi - - # Reuse existing local geodata files so Mihomo does not have to fetch them. - link_mihomo_geodata "$workdir" -} - -prepare_ss_mihomo_runtime_config() { - local sid="$1" - local local_port="$2" - local socks_port="$3" - local instance_key="${4:-$sid}" - local run_mode="${5:-redir}" - local runtime_file="$(get_ss_mihomo_runtime_file "$instance_key")" - local workdir="$(get_ss_mihomo_workdir "$instance_key")" - - [ -n "$sid" ] || return 1 - [ -n "$local_port" ] || return 1 - - mkdir -p "$workdir" - if ! /usr/bin/lua "$CLASH_YAML_HELPER" ss "$sid" "$runtime_file" "$local_port" "$socks_port" "$run_mode" >/dev/null 2>&1; then - echolog "Shadowsocks 单节点 Mihomo 运行配置生成失败:$sid" - return 1 - fi - - link_mihomo_geodata "$workdir" -} - -prepare_ss_server_mihomo_runtime_config() { - local sid="$1" - local runtime_file="$(get_ss_server_mihomo_runtime_file "$sid")" - local workdir="$(get_ss_server_mihomo_workdir "$sid")" - - [ -n "$sid" ] || return 1 - - mkdir -p "$workdir" - if ! /usr/bin/lua "$CLASH_YAML_HELPER" ss_server "$sid" "$runtime_file" >/dev/null 2>&1; then - echolog "Shadowsocks 服务端 Mihomo 配置生成失败:$sid" - return 1 - fi -} - -download_clash_config() { - local sid="$1" - local clash_url="$(uci_get_by_name "$sid" clash_url)" - local clash_path="$(uci_get_by_name "$sid" clash_path)" - local clash_user_agent="$(uci_get_by_name "$sid" clash_user_agent clash)" - local cache_file="$(get_clash_cache_file "$sid")" - local tmp_file="$TMP_PATH/clash-$sid.download.yaml" - - if [ -n "$clash_path" ] && [ -s "$clash_path" ]; then - mkdir -p "$CLASH_CONFIG_DIR" - cp -f "$clash_path" "$cache_file" - echolog "Clash 本地配置加载成功:$clash_path" - return 0 - fi - - [ -n "$clash_url" ] || { - echolog "Clash 节点未配置订阅 URL/本地配置,无法启动。" - return 1 - } - - mkdir -p "$CLASH_CONFIG_DIR" - if curl -fsSL --connect-timeout 15 --retry 2 --insecure -A "$clash_user_agent" "$clash_url" -o "$tmp_file"; then - if /usr/bin/lua "$CLASH_YAML_HELPER" validate "$tmp_file" >/dev/null 2>&1; then - mv -f "$tmp_file" "$cache_file" - echolog "Clash 配置下载成功:$clash_url" - return 0 - else - echolog "Clash 配置校验失败:$clash_url" - rm -f "$tmp_file" - fi - else - echolog "Clash 配置下载失败:$clash_url" - fi - - if [ -s "$cache_file" ]; then - echolog "使用缓存的 Clash 配置继续启动。" - return 0 - fi - - return 1 -} - -clash_cache() { - local sid="$2" - [ -n "$sid" ] || sid="$1" - [ -n "$sid" ] || return 1 - [ "$(uci_get_by_name "$sid" type)" = "clash" ] || return 1 - mkdir -p "$TMP_PATH" "$CLASH_CONFIG_DIR" - download_clash_config "$sid" -} - -filter_clash_yaml_proxies() { - local yaml_file="$1" - local filter_words="$(uci_get_by_type server_subscribe filter_words '过期时间/剩余流量')" - local names_file="$TMP_PATH/clash-proxy-names.$$" - local removed_file="$TMP_PATH/clash-proxy-removed.$$" - local removed_count=0 - - [ -n "$yaml_file" ] && [ -s "$yaml_file" ] || return 0 - [ -n "$filter_words" ] || return 0 - - if ! /usr/bin/lua "$CLASH_YAML_HELPER" validate "$yaml_file" >/dev/null 2>&1; then - return 0 - fi - - removed_count="$(/usr/bin/lua "$CLASH_YAML_HELPER" filter "$yaml_file" "$filter_words" 2>/dev/null || echo 0)" - if [ -n "$removed_count" ] && [ "$removed_count" -gt 0 ] 2>/dev/null; then - echolog "Clash YAML 共过滤节点数量: $removed_count" - fi - - rm -f "$names_file" "$removed_file" -} - -prepare_clash_runtime_config() { - local sid="$1" - local local_port="$2" - local socks_port="$3" - local cache_file="$(get_clash_cache_file "$sid")" - local workdir="$(get_clash_workdir "$sid")" - local raw_file="$workdir/raw.yaml" - local overlay_file="$workdir/overlay.yaml" - local runtime_file="$workdir/config.yaml" - local state_file="$(get_clash_state_file "$sid")" - local merge_stats="" - local filled_groups=0 - local stripped_script_rules=0 - local clash_secret="$(get_clash_api_secret "$sid")" - local dns_ipv4_only="$(get_filter_aaaa)" - local dns_mode="$(uci_get_by_type global pdnsd_enable 0)" - - [ -s "$cache_file" ] || return 1 - - mkdir -p "$workdir" "$CLASH_CONFIG_DIR" - cp -f "$cache_file" "$raw_file" - filter_clash_yaml_proxies "$raw_file" - - cat >"$overlay_file" <<-EOF - redir-port: $local_port - tproxy-port: $local_port - external-controller: 127.0.0.1:$CLASH_API_PORT - secret: $clash_secret - allow-lan: true - bind-address: 0.0.0.0 - routing-mark: $CLASH_OUTBOUND_MARK - profile: - store-selected: true - tun: - enable: false - dns: - enable: $( [ "$dns_mode" = "7" ] && echo "true" || echo "false" ) - enhanced-mode: redir-host - listen: 127.0.0.1:$dns_port - ipv6: $( [ "$dns_ipv4_only" = "1" ] && echo "false" || echo "true" ) - EOF - - if [ -n "$socks_port" ] && [ "$socks_port" != "0" ]; then - echo "socks-port: $socks_port" >>"$overlay_file" - fi - - merge_stats="$(/usr/bin/lua "$CLASH_YAML_HELPER" merge "$raw_file" "$overlay_file" "$runtime_file" 2>/dev/null)" || return 1 - filled_groups="$(printf '%s\n' "$merge_stats" | sed -n 's/.*filled_groups=\([0-9][0-9]*\).*/\1/p' | tail -n1)" - stripped_script_rules="$(printf '%s\n' "$merge_stats" | sed -n 's/.*stripped_script_rules=\([0-9][0-9]*\).*/\1/p' | tail -n1)" - [ -n "$filled_groups" ] || filled_groups=0 - [ -n "$stripped_script_rules" ] || stripped_script_rules=0 - if [ "$filled_groups" -gt 0 ] 2>/dev/null; then - echolog "Clash YAML 兼容修复:共为 $filled_groups 个空代理组回填 DIRECT。" - fi - if [ "$stripped_script_rules" -gt 0 ] 2>/dev/null; then - echolog "Clash YAML 兼容修复:共移除 $stripped_script_rules 条不兼容的 SCRIPT 规则。" - fi - local client_policy_stats="" - local client_rules=0 - client_policy_stats="$(/usr/bin/lua "$CLASH_YAML_HELPER" append_client_policy_rules "$runtime_file" "$sid" 2>/dev/null)" || true - client_rules="$(printf '%s\n' "$client_policy_stats" | sed -n 's/.*client_rules=\([0-9][0-9]*\).*/\1/p' | tail -n1)" - [ -n "$client_rules" ] || client_rules=0 - if [ "$client_rules" -gt 0 ] 2>/dev/null; then - echolog "Clash YAML 自定义客户端代理规则已注入:$client_rules 条。" - fi - - # Persist Mihomo's store-selected cache across service restarts. - if [ -f "$workdir/cache.db" ] && [ ! -L "$workdir/cache.db" ]; then - if [ ! -e "$state_file" ]; then - mv -f "$workdir/cache.db" "$state_file" - else - rm -f "$workdir/cache.db" - fi - fi - rm -f "$workdir/cache.db" - ln -sf "$state_file" "$workdir/cache.db" - - # Reuse existing local geodata files so Mihomo does not have to fetch them - # during startup in environments where DNS or outbound access is not ready yet. - link_mihomo_geodata "$workdir" -} - -resolve_global_clash_socks_port() { - local socks_enabled=$(uci_get_by_type socks5_proxy enabled 0) - local socks_server=$(uci_get_by_type socks5_proxy server nil) - local socks_port=$(uci_get_by_type socks5_proxy local_port 1080) - local http_enabled=$(uci_get_by_type http_proxy enabled 0) - local http_server=$(uci_get_by_type http_proxy server nil) - local http_port="$socks_port" - local resolved_port="" - - [ "$socks_server" = "same" ] && socks_server="$GLOBAL_SERVER" - [ "$http_server" = "same" ] && http_server="$GLOBAL_SERVER" - - if [ "$socks_enabled" = "1" ] && [ "$socks_server" = "$GLOBAL_SERVER" ]; then - resolved_port="$socks_port" - fi - - if [ "$http_enabled" = "1" ] && [ "$http_server" = "$GLOBAL_SERVER" ]; then - if [ -n "$resolved_port" ] && [ "$resolved_port" != "$http_port" ]; then - echolog "Global_HTTP: Mihomo/Clash 仅支持单个 socks-port,HTTP 代理将复用全局 SOCKS5 端口 $resolved_port。" - else - resolved_port="$http_port" - fi - fi - - echo "$resolved_port" -} - -supports_builtin_socks() { - case "$1" in - ss|clash|tuic|v2ray) - return 0 - ;; - *) - return 1 - ;; - esac -} - -supports_builtin_http() { - case "$1" in - clash) - return 0 - ;; - *) - return 1 - ;; - esac -} - get_host_ip() { local host=$(uci_get_by_name $1 server) - [ -n "$host" ] || { - echo "" - return - } - host="${host#\[}" - host="${host%\]}" - local ip="" - if echo "$host" | grep -Eq '^([0-9]{1,3}\.){3}[0-9]{1,3}$'; then - ip="$host" - elif ! echo "$host" | grep -q ':'; then - ip=$(resolveip -4 -t 3 "$host" | awk 'NR==1{print}') - [ -z "$ip" ] && ip=$(curl -sSL "http://119.29.29.29/d?dn=$host" | awk -F ';' '{print $1}') + local ip=$host + if [ -z "$(echo $host | grep -E "([0-9]{1,3}[\.]){3}[0-9]{1,3}")" ]; then + if [ "$host" == "${host#*:[0-9a-fA-F]}" ]; then + ip=$(resolveip -4 -t 3 $host | awk 'NR==1{print}') + [ -z "$ip" ] && ip=$(curl -sSL "http://119.29.29.29/d?dn=$host" | awk -F ';' '{print $1}') + fi fi [ -z "$ip" ] || uci_set_by_name $1 ip $ip - [ -n "$ip" ] || ip="" + [ -n "$ip" ] || ip="$(uci_get_by_name $1 ip "ERROR")" local chinadns="$(uci_get_by_type global chinadns_forward)" if [ -n "$chinadns" ] && [ "$ip" != "$host" ]; then @@ -612,13 +138,7 @@ echolog() { add_cron() { touch $CRON_FILE sed -i '/ssrplus.log/d' $CRON_FILE - if [ "$(uci_get_by_type server_subscribe auto_update 0)" -eq 1 ]; then - if [ "$(uci_get_by_type server_subscribe config_auto_update_mode 0)" = "1" ]; then - echo "* * * * * /usr/share/shadowsocksr/ssrplusupdate.sh loop >>$LOG_FILE 2>&1" >>$CRON_FILE - else - echo "$(uci_get_by_type server_subscribe auto_update_min_time) $(uci_get_by_type server_subscribe auto_update_day_time) * * $(uci_get_by_type server_subscribe auto_update_week_time) /usr/share/shadowsocksr/ssrplusupdate.sh >$LOG_FILE" >>$CRON_FILE - fi - fi + [ $(uci_get_by_type server_subscribe auto_update 0) -eq 1 ] && echo "$(uci_get_by_type server_subscribe auto_update_min_time) $(uci_get_by_type server_subscribe auto_update_day_time) * * $(uci_get_by_type server_subscribe auto_update_week_time) /usr/share/shadowsocksr/ssrplusupdate.sh >$LOG_FILE" >>$CRON_FILE crontab $CRON_FILE } @@ -659,42 +179,7 @@ _exit() { } first_type() { - local candidate - for candidate in "/bin/${1}" "/usr/bin/${1}" "/usr/libexec/${1}" "${TMP_BIN_PATH}/${1}"; do - [ -x "$candidate" ] && { - echo "$candidate" - return 0 - } - done - - command -v "${1}" 2>/dev/null | head -n1 -} - -is_finded() { - [ -n "$(first_type "$1")" ] -} - -has_ss_rust_client_binary() { - [ -n "$(first_type sslocal)" ] -} - -has_ss_rust_server_binary() { - [ -n "$(first_type ssserver)" ] -} - -has_mihomo_binary() { - local mihomo_bin="$(first_type mihomo)" - [ -x "$mihomo_bin" ] -} - -use_mihomo_for_ss_rust_client() { - has_ss_rust_client_binary && return 1 - has_mihomo_binary -} - -use_mihomo_for_ss_rust_server() { - has_ss_rust_server_binary && return 1 - has_mihomo_binary + type -t -p "/bin/${1}" -p "/usr/bin/${1}" -p "${TMP_BIN_PATH}/${1}" -p "${1}" "$@" | head -n1 } ln_start_bin() { @@ -702,14 +187,10 @@ ln_start_bin() { local ln_name=${2} shift 2 if [ "${file_func%%/*}" != "${file_func}" ]; then - local ln_path="${TMP_BIN_PATH}/${ln_name}" - local src_real="$(readlink -f "${file_func}" 2>/dev/null || echo "${file_func}")" - local dst_real="$(readlink -f "${ln_path}" 2>/dev/null || true)" - if [ ! -L "${ln_path}" ] || [ "${dst_real}" != "${src_real}" ]; then - rm -f "${ln_path}" - ln -s "${file_func}" "${ln_path}" >/dev/null 2>&1 - fi - file_func="${ln_path}" + [ ! -L "${file_func}" ] && { + ln -s "${file_func}" "${TMP_BIN_PATH}/${ln_name}" >/dev/null 2>&1 + file_func="${TMP_BIN_PATH}/${ln_name}" + } [ -x "${file_func}" ] || echolog "$(readlink ${file_func}) 没有执行权限,无法启动:${file_func} $*" fi #echo "${file_func} $*" >&2 @@ -723,6 +204,7 @@ ln_start_bin() { } check_run_environment() { + local prefer_nft="$(uci_get_by_type global prefer_nft 1)" local dnsmasq_info=$(dnsmasq -v 2>/dev/null) local dnsmasq_ver=$(echo "$dnsmasq_info" | sed -n '1s/.*version \([0-9.]*\).*/\1/p') @@ -730,26 +212,27 @@ check_run_environment() { DNSMASQ_NFTSET=0; [[ "$dnsmasq_info" == *" nftset"* ]] && DNSMASQ_NFTSET=1 HAS_IPT=0; { command -v iptables-legacy || command -v iptables; } >/dev/null && HAS_IPT=1 HAS_IPSET=$(command -v ipset >/dev/null && echo 1 || echo 0) - HAS_FW3=$(command -v fw3 >/dev/null && echo 1 || echo 0) HAS_FW4=$(command -v fw4 >/dev/null && echo 1 || echo 0) HAS_NFT=$(command -v nft >/dev/null && echo 1 || echo 0) # 重置 USE_TABLES USE_TABLES="" - if [ "$HAS_FW4" -eq 1 ]; then - if [ "$DNSMASQ_NFTSET" -eq 1 ] && [ "$HAS_NFT" -eq 1 ]; then + if [ "$prefer_nft" = "1" ]; then + echolog "提示:优先使用 nftables..." + if [ "$DNSMASQ_NFTSET" -eq 1 ] && [ "$HAS_NFT" -eq 1 ] && [ "$HAS_FW4" -eq 1 ]; then USE_TABLES="nftables" - else - echolog "警告:fw4 已检测到,但 nftables 环境不完整。(has_nft:$HAS_NFT/dnsmasq_nftset:$DNSMASQ_NFTSET)" + elif [ "$HAS_IPSET" -eq 1 ] && [ "$HAS_IPT" -eq 1 ] && [ "$DNSMASQ_IPSET" -eq 1 ]; then + echolog "警告:nftables (fw4) 应用环境不完整,切换至 iptables。(has_fw4:$HAS_FW4/dnsmasq_nftset:$DNSMASQ_NFTSET)" + USE_TABLES="iptables" fi - fi - - if [ -z "$USE_TABLES" ] && [ "$HAS_FW3" -eq 1 ]; then + else + echolog "提示:优先使用 iptables..." if [ "$HAS_IPSET" -eq 1 ] && [ "$HAS_IPT" -eq 1 ] && [ "$DNSMASQ_IPSET" -eq 1 ]; then USE_TABLES="iptables" - else - echolog "警告:fw3 已检测到,但 iptables 环境不完整。(has_ipset:$HAS_IPSET/has_ipt:$HAS_IPT/dnsmasq_ipset:$DNSMASQ_IPSET)" + elif [ "$DNSMASQ_NFTSET" -eq 1 ] && [ "$HAS_FW4" -eq 1 ]; then + echolog "警告:iptables (fw3) 应用环境不完整,切换至 nftables。(has_ipt:$HAS_IPT/has_ipset:$HAS_IPSET/dnsmasq_ipset:$DNSMASQ_IPSET)" + USE_TABLES="nftables" fi fi @@ -779,113 +262,27 @@ check_run_environment() { fi } -normalize_run_mode() { - local run_mode="$(uci_get_by_type global run_mode router)" - - if [ "$run_mode" = "oversea" ]; then - echolog "提示:Oversea Mode 已移除,自动切换到 IP Route Mode。" - uci_set_by_type global run_mode router - run_mode="router" - fi - - echo "${run_mode:-router}" -} - -normalize_xray_protocol_nodes() { - local changed=0 - - _migrate_xray_protocol_node() { - local section="$1" - local type="$(uci_get_by_name "$section" type)" - local v2ray_protocol="$(uci_get_by_name "$section" v2ray_protocol)" - - if [ "$type" = "ss" ] || [ "$type" = "ss-libev" ]; then - if [ -n "$(first_type mihomo)" ]; then - uci -q set "$NAME.$section.type=ss" - changed=1 - elif [ -n "$(first_type sslocal)" ]; then - uci -q set "$NAME.$section.type=ss-rust" - changed=1 - elif [ -n "$(first_type xray)" ]; then - uci -q set "$NAME.$section.type=v2ray" - uci -q set "$NAME.$section.v2ray_protocol=shadowsocks" - changed=1 - fi - elif [ "$type" = "v2ray" ] && [ "$v2ray_protocol" = "shadowsocks" ]; then - if [ -n "$(first_type mihomo)" ]; then - uci -q set "$NAME.$section.type=ss" - uci -q delete "$NAME.$section.v2ray_protocol" - changed=1 - fi - fi - if [ "$type" = "hysteria2" ]; then - echolog "提示:检测到原生 Hysteria2 节点,自动迁移为 Xray(Hysteria2)。" - uci -q set "$NAME.$section.type=v2ray" - uci -q set "$NAME.$section.v2ray_protocol=hysteria2" - changed=1 - elif [ "$type" = "trojan" ]; then - echolog "提示:检测到原生 Trojan 节点,自动迁移为 Xray(Trojan)。" - uci -q set "$NAME.$section.type=v2ray" - uci -q set "$NAME.$section.v2ray_protocol=trojan" - changed=1 - fi - } - - config_load "$NAME" - config_foreach _migrate_xray_protocol_node servers - - local subscribe_sid="$(uci_get_by_cfgid server_subscribe)" - if [ -n "$subscribe_sid" ]; then - for key in xray_hy2_type xray_tj_type ss_type; do - if uci -q get "$NAME.$subscribe_sid.$key" >/dev/null; then - uci -q delete "$NAME.$subscribe_sid.$key" - changed=1 - fi - done - fi - - if [ "$changed" = "1" ]; then - uci commit "$NAME" - fi -} - add_dns_into_ipset() { case "$1" in gfw) ipset add gfwlist ${2%:*} 2>/dev/null ;; + oversea) ipset add oversea ${2%:*} 2>/dev/null ;; *) ipset add ss_spec_wan_ac ${2%:*} nomatch 2>/dev/null ;; esac } start_dns() { local ssrplus_dns="$(uci_get_by_type global pdnsd_enable 0)" - local global_server_type="$(uci_get_by_name "$GLOBAL_SERVER" type)" - local builtin_dns_enabled=0 - local dnsserver="$(uci_get_by_type global tunnel_forward 8.8.4.4:53)" - if [ "$ssrplus_dns" = "5" ]; then - ssrplus_dns="$(force_dns2tcp_fallback "旧版 DNSPROXY 模式已移除")" || return 1 - uci_set_by_type global pdnsd_enable "$ssrplus_dns" - elif [ "$ssrplus_dns" = "6" ]; then + local dnsproxy_dnsserver="$(uci_get_by_type global parse_method)" + if [ -n "$dnsproxy_dnsserver" ] && [ "$dnsproxy_dnsserver" != "parse_file" ]; then + dnsserver="$(uci_get_by_type global dnsproxy_tunnel_forward 8.8.4.4:53)" + elif [ -n "$ssrplus_dns" ] && [ "$ssrplus_dns" = "6" ]; then dnsserver="$(uci_get_by_type global chinadns_ng_tunnel_forward 8.8.4.4:53)" + else + dnsserver="$(uci_get_by_type global tunnel_forward 8.8.4.4:53)" fi - local run_mode="$(normalize_run_mode)" + local run_mode="$(uci_get_by_type global run_mode)" - if [ "$ssrplus_dns" = "4" ] && ! is_finded "mosdns"; then - ssrplus_dns="$(force_dns2tcp_fallback "当前 DNS 模式 MosDNS 不可用")" || return 1 - uci_set_by_type global pdnsd_enable "$ssrplus_dns" - fi - - if [ "$ssrplus_dns" = "7" ]; then - if supports_builtin_dns "$global_server_type"; then - builtin_dns_enabled=1 - else - ssrplus_dns="$(force_dns2tcp_fallback "当前主节点不支持模块内置 DNS")" || return 1 - uci_set_by_type global pdnsd_enable "$ssrplus_dns" - fi - fi - - if [ "$builtin_dns_enabled" = "1" ]; then - pdnsd_enable_flag=7 - elif [ "$ssrplus_dns" != "0" ]; then + if [ "$ssrplus_dns" != "0" ]; then if [ "$HAS_IPSET" -eq 1 ]; then if [ -n "$dnsserver" ]; then add_dns_into_ipset $run_mode $dnsserver @@ -893,11 +290,22 @@ start_dns() { fi case "$ssrplus_dns" in 1) - start_dns2tcp "$dnsserver" + ln_start_bin $(first_type dns2tcp) dns2tcp -L 127.0.0.1#$dns_port -R ${dnsserver/:/#} pdnsd_enable_flag=1 ;; + 2) + ln_start_bin $(first_type microsocks) microsocks -i 127.0.0.1 -p $tmp_dns_port ssrplus-dns + ln_start_bin $(first_type dns2socks) dns2socks 127.0.0.1:$tmp_dns_port $dnsserver 127.0.0.1:$dns_port -q + pdnsd_enable_flag=2 + ;; + 3) + ln_start_bin $(first_type microsocks) microsocks -i 127.0.0.1 -p $tmp_dns_port ssrplus-dns + ln_start_bin $(first_type dns2socks-rust) dns2socks-rust -s socks5://127.0.0.1:$tmp_dns_port -d $dnsserver -l 127.0.0.1:$dns_port -f -c + echolog "DNS2SOCKS Rust query and cache Started!" + pdnsd_enable_flag=3 + ;; 4) - local filter_aaaa="$(get_filter_aaaa)" + local mosdns_ipv6="$(uci_get_by_type global mosdns_ipv6)" local mosdns_dnsserver="$(uci_get_by_type global tunnel_forward_mosdns)" output=$(for i in $(echo $mosdns_dnsserver | sed "s/,/ /g"); do dnsserver=${i%:*} @@ -910,7 +318,7 @@ start_dns() { done) awk -v line=14 -v text="$output" 'NR == line+1 {print text} 1' /etc/ssrplus/mosdns-config.yaml | sed "s/DNS_PORT/$dns_port/g" | sed "s/\(concurrent:\).*/\1 $(echo "$mosdns_dnsserver" | sed 's/,/ /g' | wc -w)/g"> $TMP_PATH/mosdns-config.yaml - if [ "$filter_aaaa" == "0" ]; then + if [ "$mosdns_ipv6" == "0" ]; then sed -i "s/DNS_MODE/main_sequence_with_IPv6/g" $TMP_PATH/mosdns-config.yaml else sed -i "s/DNS_MODE/main_sequence_disable_IPv6/g" $TMP_PATH/mosdns-config.yaml @@ -918,6 +326,65 @@ start_dns() { ln_start_bin $(first_type mosdns) mosdns start -c $TMP_PATH/mosdns-config.yaml pdnsd_enable_flag=4 ;; + 5) + dnsproxy_ipv6="$(uci_get_by_type global dnsproxy_ipv6)" + if [ "$dnsproxy_ipv6" -eq "1" ]; then + disabled_ipv6="--ipv6-disabled" + fi + if [ "$dnsproxy_dnsserver" != "parse_file" ]; then + ln_start_bin $(first_type dnsproxy) dnsproxy -l 127.0.0.1 -p $tmp_dns_port -p $dns_port -u $dnsserver $disabled_ipv6 --cache --cache-min-ttl=3600 + else + dnsproxy_dnsserver_file="$TMP_PATH/dnsproxy_dns.list" + cleaned_file="$TMP_PATH/cleaned_dns.list" + temp_file="$TMP_PATH/temp_dns.list" + > "$cleaned_file" + # 清理输入文件并去重 + while IFS= read -r line || [ -n "$line" ]; do + line=$(echo "$line" | sed -E 's/^[ \t\r]+//; s/[ \t\r]+$//') + [ -z "$line" ] && continue + echo "$line" | grep -qE '^#' && continue + echo "$line" >> "$cleaned_file" + done < "/etc/ssrplus/dnsproxy_dns.list" + # 获取清理后文件的MD5 + cleaned_md5=$(md5sum "$cleaned_file" | awk '{print $1}') + if [ ! -f "$dnsproxy_dnsserver_file" ]; then + cp "$cleaned_file" "$dnsproxy_dnsserver_file" + else + target_md5=$(md5sum "$dnsproxy_dnsserver_file" | awk '{print $1}') + if [ "$cleaned_md5" != "$target_md5" ]; then + > "$temp_file" + # 保留目标文件中也存在于清理文件的记录(去重) + while IFS= read -r line; do + line=$(echo "$line" | sed -E 's/^[ \t\r]+//; s/[ \t\r]+$//') + if grep -qixF "$line" "$cleaned_file" && ! grep -qixF "$line" "$temp_file"; then + echo "$line" >> "$temp_file" + fi + done < "$dnsproxy_dnsserver_file" + # 添加清理文件中有但目标文件没有的记录(去重) + while IFS= read -r line; do + line=$(echo "$line" | sed -E 's/^[ \t\r]+//; s/[ \t\r]+$//') + if ! grep -qixF "$line" "$temp_file"; then + echo "$line" >> "$temp_file" + fi + done < "$cleaned_file" + temp_md5=$(md5sum "$temp_file" | awk '{print $1}') + if [ "$temp_md5" != "$target_md5" ]; then + mv "$temp_file" "$dnsproxy_dnsserver_file" + else + rm -f "$temp_file" + fi + fi + fi + rm -f "$cleaned_file" + + if [ -n "$dnsproxy_dnsserver_file" ] && [ -s "$dnsproxy_dnsserver_file" ]; then + local upstreams_logic_mode="$(uci_get_by_type global upstreams_logic_mode)" + ln_start_bin $(first_type dnsproxy) dnsproxy -l 127.0.0.1 -p $tmp_dns_port -p $dns_port -u $dnsproxy_dnsserver_file $disabled_ipv6 --cache --cache-min-ttl=3600 --upstream-mode=$upstreams_logic_mode + fi + fi + echolog "DNSPROXY query and cache Started!" + pdnsd_enable_flag=5 + ;; 6) local chinadns_ng_proto="$(uci_get_by_type global chinadns_ng_proto)" local chinadns_ng_dns="" @@ -981,134 +448,12 @@ start_dns() { sed -i "s,$(printf '%s' "$old_appledns"),$(printf '%s' "$new_appledns"),g" /etc/ssrplus/applechina.conf fi fi + echolog "Apple 域名中国大陆 CDN 的 优化规则正在加载。" cp -f /etc/ssrplus/applechina.conf $TMP_DNSMASQ_PATH/ + echolog "Apple 域名中国大陆 CDN 的 优化规则加载完毕。" fi } -# 生成 Xray 服务端配置 -# 生成 Xray 服务端配置 -generate_xray_config() { - local type="$1" - local port="$2" - local password="$3" - local security="$4" - local method="$5" - local network="$6" - local ws_path="$7" - local ws_host="$8" - local grpc_service="$9" - local alter_id="${10}" - local tcp_guise="${11}" - local tcp_guise_http_host="${12}" - local tcp_guise_http_path="${13}" - local config_file="${14}" - - local inbound_json="" - - case "$type" in - vmess) - inbound_json="{ - \"protocol\": \"vmess\", - \"port\": $port, - \"settings\": { - \"clients\": [{\"id\": \"$password\", \"alterId\": $alter_id}] - }, - \"streamSettings\": { - \"network\": \"$network\" - } - }" - ;; - vless) - inbound_json="{ - \"protocol\": \"vless\", - \"port\": $port, - \"settings\": { - \"clients\": [{\"id\": \"$password\"}], - \"decryption\": \"none\" - }, - \"streamSettings\": { - \"network\": \"$network\" - } - }" - ;; - trojan) - inbound_json="{ - \"protocol\": \"trojan\", - \"port\": $port, - \"settings\": { - \"clients\": [{\"password\": \"$password\"}] - }, - \"streamSettings\": { - \"network\": \"$network\" - } - }" - ;; - shadowsocks) - inbound_json="{ - \"protocol\": \"shadowsocks\", - \"port\": $port, - \"settings\": { - \"method\": \"$method\", - \"password\": \"$password\" - } - }" - ;; - *) - return 1 - ;; - esac - - # 添加传输层细节 - case "$network" in - ws) - local ws_json="{\"path\": \"$ws_path\"}" - [ -n "$ws_host" ] && ws_json="{\"path\": \"$ws_path\", \"headers\": {\"Host\": \"$ws_host\"}}" - inbound_json=$(echo "$inbound_json" | sed "s/\"streamSettings\": {/\"streamSettings\": {\"wsSettings\": $ws_json, /") - ;; - grpc) - [ -n "$grpc_service" ] && inbound_json=$(echo "$inbound_json" | sed "s/\"streamSettings\": {/\"streamSettings\": {\"grpcSettings\": {\"serviceName\": \"$grpc_service\"}, /") - ;; - tcp) - # TCP HTTP 伪装 - if [ "$tcp_guise" = "http" ]; then - local tcp_json="{\"header\": {\"type\": \"http\"" - - # 添加 HTTP Host - if [ -n "$tcp_guise_http_host" ]; then - # 将空格分隔的多个 host 转换为 JSON 数组格式 - local host_list=$(echo "$tcp_guise_http_host" | sed 's/ /","/g') - tcp_json="$tcp_json, \"request\": {\"headers\": {\"Host\": [\"$host_list\"]}}" - fi - - # 添加 HTTP Path - if [ -n "$tcp_guise_http_path" ]; then - local path_list=$(echo "$tcp_guise_http_path" | sed 's/ /","/g') - tcp_json="$tcp_json, \"response\": {\"headers\": {\"Location\": [\"$path_list\"]}}" - fi - - tcp_json="$tcp_json}}" - inbound_json=$(echo "$inbound_json" | sed "s/\"streamSettings\": {/\"streamSettings\": {\"tcpSettings\": $tcp_json, /") - fi - ;; - esac - - cat > "$config_file" << EOF -{ - "log": { - "loglevel": "warning" - }, - "inbounds": [$inbound_json], - "outbounds": [ - { - "protocol": "freedom", - "settings": {} - } - ] -} -EOF - return 0 -} - gen_service_file() { #1-server.type 2-cfgname 3-file_path local fastopen if [ $(uci_get_by_name $2 fast_open) == "1" ]; then @@ -1250,48 +595,50 @@ gen_config_file() { #server1 type2 code3 local_port4 socks_port5 chain6 threads5 ;; esac ;; + socks5) + /usr/share/shadowsocksr/genred2config.sh $config_file $2 $mode $4 \ + "$(uci_get_by_name $1 server)" \ + "$(uci_get_by_name $1 server_port)" \ + "$(uci_get_by_name $1 auth_enable 0)" \ + "$(uci_get_by_name $1 username)" \ + "$(uci_get_by_name $1 password)" + ;; + tun) + /usr/share/shadowsocksr/genred2config.sh $config_file $2 $(uci_get_by_name $1 iface "br-lan") $4 + ;; esac sed -i 's/\\//g' $TMP_PATH/*-ssr-*.json #>/dev/null > 2>&1 } start_udp() { local udp_relay_server_type=$(uci_get_by_name $UDP_RELAY_SERVER type) - local threads=$(get_configured_threads) local type=$udp_relay_server_type - if [ "$udp_relay_server_type" = "ss-rust" ]; then + if [ "$udp_relay_server_type" = "ss-rust" ] || [ "$udp_relay_server_type" = "ss-libev" ]; then type="ss" fi redir_udp=1 case "$type" in ss | ssr) - if [ "$udp_relay_server_type" = "ss" ]; then - redir_udp=0 - ARG_UDP="" - echolog "UDP TPROXY Relay:Mihomo 单节点由主实例处理。" - elif [ "$udp_relay_server_type" = "ss-rust" ] && use_mihomo_for_ss_rust_client; then - redir_udp=0 - ARG_UDP="" - echolog "UDP TPROXY Relay:ss-rust 主程序不存在,已回退到 Mihomo 主实例处理。" - else - gen_config_file $UDP_RELAY_SERVER $type 2 $tmp_udp_port - if [ "$udp_relay_server_type" = "ssr" ]; then - ss_program="$(first_type ${type}-redir)" - elif [ "$udp_relay_server_type" = "ss-rust" ] || [ "$udp_relay_server_type" = "ss" ]; then - ss_program="$(first_type ${type}local)" - fi - echolog "$(get_name $type) program is: $ss_program" - old_ss_program=$(readlink -f "$TMP_PATH/bin/${type}-redir" 2>/dev/null) - if [ "$old_ss_program" != "$ss_program" ]; then - rm -rf "$TMP_PATH/bin/${type}-redir" - fi - ln_start_bin $ss_program ${type}-redir -c $udp_config_file - echolog "UDP TPROXY Relay:$(get_name $type) Started!" + gen_config_file $UDP_RELAY_SERVER $type 2 $tmp_udp_port + if [ "$udp_relay_server_type" = "ss-libev" ] || [ "$udp_relay_server_type" = "ssr" ]; then + ss_program="$(first_type ${type}-redir)" + elif [ "$udp_relay_server_type" = "ss-rust" ]; then + ss_program="$(first_type ${type}local)" fi + echolog "$(get_name $type) program is: $ss_program" + # 获取当前软链接指向的执行文件路径 + old_ss_program=$(readlink -f "$TMP_PATH/bin/${type}-redir" 2>/dev/null) + # **当新旧执行文件路径不同时,删除旧链接** + if [ "$old_ss_program" != "$ss_program" ]; then + rm -rf "$TMP_PATH/bin/${type}-redir" + fi + ln_start_bin $ss_program ${type}-redir -c $udp_config_file + echolog "UDP TPROXY Relay:$(get_name $type) Started!" ;; v2ray) gen_config_file $UDP_RELAY_SERVER $type 2 $tmp_udp_port - ln_start_bin $(first_type xray) v2ray run -c $udp_config_file - echolog "UDP TPROXY Relay:$($(first_type xray) version | head -1) Started!" + ln_start_bin $(first_type xray v2ray) v2ray run -c $udp_config_file + echolog "UDP TPROXY Relay:$($(first_type "xray" "v2ray") version | head -1) Started!" ;; trojan) #client gen_config_file $UDP_RELAY_SERVER $type 2 $tmp_udp_local_port @@ -1304,11 +651,21 @@ start_udp() { redir_udp=0 ARG_UDP="" ;; + hysteria2) + gen_config_file $UDP_RELAY_SERVER $type 2 $tmp_udp_port + ln_start_bin $(first_type hysteria) hysteria client --config $udp_config_file + echolog "UDP TPROXY Relay:$($(first_type "hysteria") version | grep Version | awk '{print "Hysteria2: " $2}') Started!" + ;; tuic) - # TUIC now uses Mihomo directly and should follow the native path. - redir_udp=0 - ARG_UDP="" - echolog "TUIC UDP relay is handled by the main Mihomo instance." + # FIXME: ipt2socks cannot handle udp reply from tuic + # 20230726 uncomment following 4 lines + gen_config_file $UDP_RELAY_SERVER $type 2 $tmp_udp_local_port + ln_start_bin $(first_type tuic-client) tuic-client --config $udp_config_file + ln_start_bin $(first_type ipt2socks) ipt2socks -U -b 0.0.0.0 -4 -s 127.0.0.1 -p $tmp_udp_local_port -l $tmp_udp_port + echolog "UDP TPROXY Relay:$($(first_type tuic-client) --version) Started!" + echolog "TUIC UDP TPROXY Relay not supported!" + #redir_udp=0 + #ARG_UDP="" ;; shadowtls) gen_config_file $UDP_RELAY_SERVER $type 2 ${tmp_udp_local_port} @@ -1317,7 +674,7 @@ start_udp() { local chain_type=$(uci_get_by_name $UDP_RELAY_SERVER chain_type) case ${chain_type} in vmess) - ln_start_bin $(first_type xray) v2ray run -c $udp_config_file + ln_start_bin $(first_type xray v2ray) v2ray run -c $udp_config_file echolog "UDP TPROXY Relay:shadow-tls chain-to $($(first_type xray) --version) Started!" ;; sslocal) @@ -1327,75 +684,366 @@ start_udp() { esac ;; socks5) - if [ "$(uci_get_by_name $UDP_RELAY_SERVER auth_enable 0)" == "1" ]; then - local auth="-a $(uci_get_by_name $UDP_RELAY_SERVER username) -k $(uci_get_by_name $UDP_RELAY_SERVER password)" - fi - for i in $(seq 1 $threads); do - ln_start_bin $(first_type ipt2socks) ipt2socks -U -r -b 0.0.0.0 -4 \ - -s $(uci_get_by_name $UDP_RELAY_SERVER server) \ - -p $(uci_get_by_name $UDP_RELAY_SERVER server_port) \ - -l $tmp_udp_port $auth - done - echolog "UDP TPROXY Relay:Socks5 via IPT2Socks $threads Threads Started!" + # if [ "$(uci_get_by_name $UDP_RELAY_SERVER auth_enable 0)" == "1" ]; then + # local auth="-a $(uci_get_by_name $UDP_RELAY_SERVER username) -k $(uci_get_by_name $UDP_RELAY_SERVER password)" + # fi + # ln_start_bin $(first_type ipt2socks) ipt2socks $udp_config_file -U -4 -s $(uci_get_by_name $UDP_RELAY_SERVER server) -p $(uci_get_by_name $UDP_RELAY_SERVER server_port) -l $tmp_udp_port $auth + gen_config_file $UDP_RELAY_SERVER $type 2 $tmp_udp_port + ln_start_bin $(first_type redsocks2) redsocks2 -c $udp_config_file + echolog "UDP TPROXY Relay:Socks5 REDIRECT/TPROXY Started!" + ;; + tun) + echolog "Network Tunnel UDP TPROXY Relay not supported!" + redir_udp=0 + ARG_UDP="" ;; esac } -start_local() { - [ "$LOCAL_SERVER" = "nil" ] && return 1 - local local_port="${1:-$(uci_get_by_type socks5_proxy local_port)}" - local local_server_type=$(uci_get_by_name $LOCAL_SERVER type) - local probe_instance_key="$(printf '%s' "${SSR_SWITCH_PROBE_INSTANCE_KEY:-}" | tr -cd '0-9A-Za-z._-')" - local type=$local_server_type - if [ "$local_server_type" = "ss-rust" ]; then +shunt_dns_command() { + local shunt_dns_mode="$(uci_get_by_type global shunt_dns_mode)" + local shunt_dnsproxy_dnsserver="$(uci_get_by_type global shunt_parse_method)" + if [ -n "$shunt_dnsproxy_dnsserver" ] && [ "$shunt_dnsproxy_dnsserver" != "parse_file" ]; then + shunt_dnsserver="$(uci_get_by_type global dnsproxy_shunt_forward 8.8.4.4:53)" + elif [ -n "shunt_dns_mode" ] && [ "$shunt_dns_mode" = "5" ]; then + shunt_dnsserver="$(uci_get_by_type global chinadns_ng_shunt_dnsserver 8.8.4.4:53)" + else + shunt_dnsserver="$(uci_get_by_type global shunt_dnsserver 8.8.4.4:53)" + fi + local tmp_port=$1 + case "$shunt_dns_mode" in + 1) + ln_start_bin $(first_type dns2socks) dns2socks 127.0.0.1:$tmp_port $shunt_dnsserver 127.0.0.1:$tmp_shunt_dns_port -q + ;; + 2) + ln_start_bin $(first_type dns2socks-rust) dns2socks-rust -s socks5://127.0.0.1:$tmp_port -d $shunt_dnsserver -l 127.0.0.1:$tmp_shunt_dns_port -f -c + echolog "DNS2SOCKS Rust Shunt query Started!" + ;; + 3) + local shunt_mosdns_ipv6="$(uci_get_by_type global shunt_mosdns_ipv6)" + local shunt_mosdns_dnsserver="$(uci_get_by_type global shunt_mosdns_dnsserver)" + output=$(for i in $(echo $shunt_mosdns_dnsserver | sed "s/,/ /g"); do + echo " - addr: $i" + echo " socks5: \"127.0.0.1:$tmp_port\"" + echo " enable_pipeline: true" + done) + awk -v line=14 -v text="$output" 'NR == line+1 {print text} 1' /etc/ssrplus/mosdns-config.yaml | sed "s/DNS_PORT/$tmp_shunt_dns_port/g" | sed "s/\(concurrent:\).*/\1 $(echo "$mosdns_dnsserver" | sed 's/,/ /g' | wc -w)/g" > $TMP_PATH/mosdns-config-shunt.yaml + + if [ "$shunt_mosdns_ipv6" == "0" ]; then + sed -i "s/DNS_MODE/main_sequence_with_IPv6/g" $TMP_PATH/mosdns-config-shunt.yaml + else + sed -i "s/DNS_MODE/main_sequence_disable_IPv6/g" $TMP_PATH/mosdns-config-shunt.yaml + fi + ln_start_bin $(first_type mosdns) mosdns start -c $TMP_PATH/mosdns-config-shunt.yaml + ;; + 4) + shunt_dnsproxy_ipv6="$(uci_get_by_type global shunt_dnsproxy_ipv6)" + if [ "$shunt_dnsproxy_ipv6" -eq "1" ]; then + shunt_disabled_ipv6="--ipv6-disabled" + fi + if [ "$shunt_dnsproxy_dnsserver" != "parse_file" ]; then + ln_start_bin $(first_type dnsproxy) dnsproxy -l 127.0.0.1 -p $tmp_port -p $tmp_shunt_dns_port -u $shunt_dnsserver $shunt_disabled_ipv6 --cache --cache-min-ttl=3600 + else + shunt_dnsproxy_dnsserver_file="$TMP_PATH/dnsproxy_dns.list" + cleaned_file="$TMP_PATH/cleaned_dns_servers.list" + temp_file="$TMP_PATH/temp_dns_servers.list" + > "$cleaned_file" + # 清理输入文件并去重 + while IFS= read -r line || [ -n "$line" ]; do + line=$(echo "$line" | sed -E 's/^[ \t\r]+//; s/[ \t\r]+$//') + [ -z "$line" ] && continue + echo "$line" | grep -qE '^#' && continue + echo "$line" >> "$cleaned_file" + done < "/etc/ssrplus/dnsproxy_dns.list" + # 获取清理后文件的MD5 + cleaned_md5=$(md5sum "$cleaned_file" | awk '{print $1}') + if [ ! -f "$shunt_dnsproxy_dnsserver_file" ]; then + cp "$cleaned_file" "$shunt_dnsproxy_dnsserver_file" + else + target_md5=$(md5sum "$shunt_dnsproxy_dnsserver_file" | awk '{print $1}') + if [ "$cleaned_md5" != "$target_md5" ]; then + > "$temp_file" + # 保留目标文件中也存在于清理文件的记录(去重) + while IFS= read -r line; do + line=$(echo "$line" | sed -E 's/^[ \t\r]+//; s/[ \t\r]+$//') + if grep -qixF "$line" "$cleaned_file" && ! grep -qixF "$line" "$temp_file"; then + echo "$line" >> "$temp_file" + fi + done < "$shunt_dnsproxy_dnsserver_file" + # 添加清理文件中有但目标文件没有的记录(去重) + while IFS= read -r line; do + line=$(echo "$line" | sed -E 's/^[ \t\r]+//; s/[ \t\r]+$//') + if ! grep -qixF "$line" "$temp_file"; then + echo "$line" >> "$temp_file" + fi + done < "$cleaned_file" + temp_md5=$(md5sum "$temp_file" | awk '{print $1}') + if [ "$temp_md5" != "$target_md5" ]; then + mv "$temp_file" "$shunt_dnsproxy_dnsserver_file" + else + rm -f "$temp_file" + fi + fi + fi + rm -f "$cleaned_file" + + if [ -n "$shunt_dnsproxy_dnsserver_file" ] && [ -s "$shunt_dnsproxy_dnsserver_file" ]; then + local shunt_upstreams_logic_mode="$(uci_get_by_type global shunt_upstreams_logic_mode)" + ln_start_bin $(first_type dnsproxy) dnsproxy -l 127.0.0.1 -p $tmp_port -p $tmp_shunt_dns_port -u $shunt_dnsproxy_dnsserver_file $shunt_disabled_ipv6 --cache --cache-min-ttl=3600 --upstream-mode=$shunt_upstreams_logic_mode + fi + fi + echolog "DNSPROXY shunt query and cache Started!" + ;; + 5) + local chinadns_ng_shunt_proto="$(uci_get_by_type global chinadns_ng_shunt_proto)" + local chinadns_ng_shunt_dns="" + # 遍历每个 DNS 服务器 + IFS=',' # 设置分隔符为逗号 + for chinadns_ng_shunt_server in $shunt_dnsserver; do + # 处理单个服务器地址 + local chinadns_ng_shunt_ip="${chinadns_ng_shunt_server%%:*}" + local chinadns_ng_shunt_port="${chinadns_ng_shunt_server##*:}" + [ "$chinadns_ng_shunt_ip" = "$chinadns_ng_shunt_port" ] && chinadns_ng_shunt_port="53" + chinadns_ng_shunt_tls_port="853" + # 根据协议类型格式化服务器地址 + case "$chinadns_ng_shunt_proto" in + "none") + chinadns_ng_shunt_server="${chinadns_ng_shunt_ip}#${chinadns_ng_shunt_port}" + ;; + "tls") + chinadns_ng_shunt_server="${chinadns_ng_shunt_proto}://${chinadns_ng_shunt_ip}#${chinadns_ng_shunt_tls_port}" + ;; + *) + chinadns_ng_shunt_server="${chinadns_ng_shunt_proto}://${chinadns_ng_shunt_ip}#${chinadns_ng_shunt_port}" + ;; + esac + # 添加到参数列表 + chinadns_ng_shunt_dns="${chinadns_ng_shunt_dns} -t ${chinadns_ng_shunt_server}" + done + unset IFS # 恢复默认分隔符 + shunt_dnsserver="$chinadns_ng_shunt_dns" + # 启动 chinadns-ng + ln_start_bin $(first_type chinadns-ng) chinadns-ng -b 127.0.0.1 -l $tmp_port -l $tmp_shunt_dns_port -p 3 -d gfw $shunt_dnsserver -N --filter-qtype 64,65 -f -r --cache 4096 --cache-stale 86400 --cache-refresh 20 + echolog "ChinaDNS-NG shunt query and cache Started!" + ;; + esac +} + +shunt_dns_config_file_port() { + if [ "$LOCAL_SERVER" == "$SHUNT_SERVER" ]; then + # NetFlix 和 全局socks 节点相同 + if [ "$(uci_get_by_type socks5_proxy socks5_auth nil)" != "noauth" ]; then + # 全局socks 有密码,NetFlix 不能使用 auth 验证,需更换为新端口并使用无密码的 socks 配置用于分流 + # 新增NetFlix dns 使用端口 + local port=$tmp_shunt_local_port + jq --arg port "$port" '.inbounds |= .[0:1] + [{"protocol":"socks","port":($port | tonumber),"settings":{"udp":true,"auth":"noauth"}}] + .[1:]' "$shunt_config_file" > "$shunt_config_file.tmp" && mv "$shunt_config_file.tmp" $shunt_config_file + echo $port # 返回端口号 + return 0 # 成功返回 + else + sed -i -e '/"mixed"/d' $shunt_config_file + fi + else + # NetFlix 和 全局 socks 节点不相同 + if [ "$(uci_get_by_type socks5_proxy socks5_auth nil)" != "noauth" ]; then + # 全局socks 有密码,NetFlix不能使用auth验证,需设置为无密码的socks配置用于分流 + # 删除 NetFlix dns 端口密码验证 + sed -i \ + -e '/"mixed"/d' \ + -e 's/"auth"\s*:\s*"password"/\"auth\": \"noauth\"/g' \ + -e '/"accounts": \[/,/\]/d' $shunt_config_file + else + sed -i -e '/"mixed"/d' $shunt_config_file + fi + fi + # 使用传入的端口 + echo $1 # 返回传入的端口号 + return 0 # 成功返回 +} + +start_shunt() { + local shunt_server_type=$(uci_get_by_name $SHUNT_SERVER type) + local type=$shunt_server_type + if [ "$shunt_server_type" = "ss-rust" ] || [ "$shunt_server_type" = "ss-libev" ]; then type="ss" fi case "$type" in ss | ssr) - if [ "$local_server_type" = "ssr" ]; then - gen_config_file $LOCAL_SERVER $type 4 $local_port - ss_program="$(first_type ${type}-local)" - echolog "$(get_name $type) program is: $ss_program" - old_ss_program=$(readlink -f "$TMP_PATH/bin/${type}-local" 2>/dev/null) - if [ "$old_ss_program" != "$ss_program" ]; then - rm -rf "$TMP_PATH/bin/${type}-local" - fi - ln_start_bin $ss_program ${type}-local -c $local_config_file - echolog "Global_Socks5:$(get_name $type) Started!" - elif [ "$local_server_type" = "ss" ] || { [ "$local_server_type" = "ss-rust" ] && use_mihomo_for_ss_rust_client; }; then - local mihomo_bin="$(first_type mihomo)" - local instance_key="${LOCAL_SERVER}-local" - [ -n "$probe_instance_key" ] && instance_key="$probe_instance_key" - [ -x "$mihomo_bin" ] || { - echolog "Global_Socks5:Mihomo 内核不存在,请确认 /usr/bin/mihomo 或 /usr/libexec/mihomo 可执行。" - return 1 - } - prepare_ss_mihomo_runtime_config "$LOCAL_SERVER" "$local_port" "$local_port" "$instance_key" "socks" || return 1 - local ss_workdir="$(get_ss_mihomo_workdir "$instance_key")" - ln_start_bin "$mihomo_bin" ss-local -d "$ss_workdir" -f "$ss_workdir/config.yaml" - if [ "$local_server_type" = "ss-rust" ]; then - echolog "Global_Socks5:ss-rust 主程序不存在,已回退到 Mihomo (Shadowsocks) 启动。" - else - echolog "Global_Socks5:Mihomo (Shadowsocks) Started!" - fi - else - gen_config_file $LOCAL_SERVER $type 4 $local_port - ss_program="$(first_type sslocal)" - echolog "ShadowSocks program is: $ss_program" - old_ss_program=$(readlink -f "$TMP_PATH/bin/${type}-local" 2>/dev/null) - if [ "$old_ss_program" != "$ss_program" ]; then - rm -rf "$TMP_PATH/bin/${type}-local" - fi - ln_start_bin $ss_program ${type}-local -c $local_config_file - echolog "Global_Socks5:Shadowsocks-rust Started!" + gen_config_file $SHUNT_SERVER $type 3 $tmp_shunt_port + if [ "$shunt_server_type" = "ss-libev" ] || [ "$shunt_server_type" = "ssr" ]; then + ss_program="$(first_type ${type}-redir)" + elif [ "$shunt_server_type" = "ss-rust" ]; then + ss_program="$(first_type ${type}local)" fi + echolog "$(get_name $type) program is: $ss_program" + # 获取当前软链接指向的执行文件路径 + old_ss_program=$(readlink -f "$TMP_PATH/bin/${type}-redir" 2>/dev/null) + # **当新旧执行文件路径不同时,删除旧链接** + if [ "$old_ss_program" != "$ss_program" ]; then + rm -rf "$TMP_PATH/bin/${type}-redir" + fi + ln_start_bin $ss_program ${type}-redir -c $shunt_config_file + if [ -n "$tmp_local_port" ]; then + local tmp_port=$tmp_local_port + else + local tmp_port=$tmp_shunt_local_port + if [ "$shunt_server_type" = "ss-libev" ] || [ "$shunt_server_type" = "ssr" ]; then + dns_ss_program="$(first_type ${type}-local)" + elif [ "$shunt_server_type" = "ss-rust" ]; then + dns_ss_program="$(first_type ${type}local)" + fi + # 获取当前软链接指向的执行文件路径 + old_dns_ss_program=$(readlink -f "$TMP_PATH/bin/${type}-local" 2>/dev/null) + if [ "$old_dns_ss_program" != "$dns_ss_program" ]; then + rm -rf "$TMP_PATH/bin/${type}-local" + fi + ln_start_bin $dns_ss_program ${type}-local -c $shunt_dns_config_file + fi + shunt_dns_command $tmp_port + echolog "shunt:$(get_name $type) Started!" + ;; + v2ray) + local tmp_port=${tmp_local_port:-$tmp_shunt_local_port} + gen_config_file $SHUNT_SERVER $type 3 $tmp_shunt_port $tmp_port + # 处理配置文件中的 NetFlix 端口 + tmp_port=$(shunt_dns_config_file_port $tmp_port) + ln_start_bin $(first_type xray v2ray) v2ray run -c $shunt_config_file + shunt_dns_command $tmp_port + echolog "shunt:$($(first_type xray v2ray) version | head -1) Started!" + ;; + trojan) + gen_config_file $SHUNT_SERVER $type 3 $tmp_shunt_port + ln_start_bin $(first_type trojan) $type --config $shunt_config_file + if [ -n "$tmp_local_port" ]; then + local tmp_port=$tmp_local_port + else + local tmp_port=$tmp_shunt_local_port + ln_start_bin $(first_type trojan) $type --config $shunt_dns_config_file + fi + shunt_dns_command $tmp_port + echolog "shunt:$($(first_type trojan) --version 2>&1 | head -1) Started!" + ;; + naiveproxy) + gen_config_file $SHUNT_SERVER $type 3 $tmp_shunt_port + ln_start_bin $(first_type naive) naive --config $shunt_config_file + if [ -n "$tmp_local_port" ]; then + local tmp_port=$tmp_local_port + else + local tmp_port=$tmp_shunt_local_port + ln_start_bin $(first_type naive) naive --config $shunt_dns_config_file + fi + shunt_dns_command $tmp_port + echolog "shunt:$($(first_type "naive") --version 2>&1 | head -1) Started!" + redir_udp=0 + ;; + hysteria2) + if [ -n "$tmp_local_port" ]; then + local tmp_port=$tmp_local_port + gen_config_file $SHUNT_SERVER $type 3 $tmp_shunt_port + else + local tmp_port=$tmp_shunt_local_port + gen_config_file $SHUNT_SERVER $type 3 $tmp_shunt_port $tmp_port + fi + ln_start_bin $(first_type hysteria) hysteria client --config $shunt_config_file + shunt_dns_command $tmp_port + echolog "shunt:$($(first_type hysteria) version | grep Version | awk '{print "Hysteria2: " $2}') Started!" + ;; + tuic) + local chain_shunt_port="30${tmp_shunt_port}" + gen_config_file $SHUNT_SERVER $type 3 $chain_shunt_port 0 chain #make a tuic socks:30303, make a ipt2socks redir:303 + ln_start_bin $(first_type tuic-client) tuic-client --config $shunt_config_file + ln_start_bin $(first_type ipt2socks) ipt2socks -R -b 0.0.0.0 -4 -s 127.0.0.1 -p $chain_shunt_port -l $tmp_shunt_port + + [ -n "$tmp_local_port" ] && tmp_port=$tmp_local_port || tmp_port=$tmp_shunt_local_port + gen_config_file $SHUNT_SERVER $type 3 $tmp_port # make a tuic socks :304 + ln_start_bin $(first_type tuic-client) tuic-client --config $shunt_dns_config_file + shunt_dns_command $tmp_port + echolog "Netflix Separated Shunt Server:$($(first_type tuic-client) --version) Started!" + # FIXME: ipt2socks cannot handle udp reply from tuic + #redir_udp=0 + ;; + shadowtls) + [ -n "$tmp_local_port" ] && tmp_port=$tmp_local_port || tmp_port=$tmp_shunt_local_port + gen_config_file $SHUNT_SERVER $type 3 "10${tmp_shunt_port}" $tmp_port chain/$tmp_shunt_port #make a redir:303 and a socks:304 + #echo "debug \$tmp_port=$tmp_port, \$tmp_shunt_port=${tmp_shunt_port}, \$tmp_shunt_local_port=$tmp_shunt_local_port" + ln_start_bin $(first_type shadow-tls) shadow-tls config --config $chain_config_file + shunt_dns_command $tmp_port + local chain_type=$(uci_get_by_name $SHUNT_SERVER chain_type) + case ${chain_type} in + vmess) + ln_start_bin $(first_type xray v2ray) v2ray run -c $shunt_config_file + echolog "Netflix Separated Shunt Server:shadow-tls chain-to$($(first_type xray) --version) Started!" + ;; + sslocal) + ln_start_bin $(first_type sslocal) sslocal -c $shunt_config_file + echolog "Netflix Separated Shunt Server:shadow-tls chain-to$($(first_type sslocal) --version) Started!" + ;; + esac + ;; + # socks5) + # if [ "$(uci_get_by_name $SHUNT_SERVER auth_enable 0)" == "1" ]; then + # local auth="-a $(uci_get_by_name $SHUNT_SERVER username) -k $(uci_get_by_name $SHUNT_SERVER password)" + # fi + # ln_start_bin $(first_type ipt2socks) ipt2socks $shunt_config_file -R -4 -s $(uci_get_by_name $SHUNT_SERVER server) -p $(uci_get_by_name $SHUNT_SERVER server_port) -l $tmp_shunt_port $auth + # #gen_config_file $SHUNT_SERVER $type 3 $tmp_shunt_port + # #ln_start_bin $(first_type redsocks2) redsocks2 -c $shunt_config_file + # if [ -n "$tmp_local_port" ]; then + # local tmp_port=$tmp_local_port + # else + # local tmp_port=$tmp_shunt_local_port + # ln_start_bin $(first_type microsocks) microsocks -i 127.0.0.1 -p $tmp_port shunt-dns-ssr-plus + # fi + # shunt_dns_command $tmp_port + # echolog "shunt:$type REDIRECT/TPROXY Started!" + # ;; + *) + gen_config_file $SHUNT_SERVER $type 3 $tmp_shunt_port + ln_start_bin $(first_type redsocks2) redsocks2 -c $shunt_config_file + if [ -n "$tmp_local_port" ]; then + local tmp_port=$tmp_local_port + else + local tmp_port=$tmp_shunt_local_port + ln_start_bin $(first_type microsocks) microsocks -i 127.0.0.1 -p $tmp_port shunt-dns-ssr-plus + fi + shunt_dns_command $tmp_port + echolog "shunt:$type REDIRECT/TPROXY Started!" + ;; + esac + return 0 +} + +start_local() { + [ "$LOCAL_SERVER" = "nil" ] && return 1 + local local_port=$(uci_get_by_type socks5_proxy local_port) + [ "$LOCAL_SERVER" == "$SHUNT_SERVER" ] && tmp_local_port=$local_port + local local_server_type=$(uci_get_by_name $LOCAL_SERVER type) + local type=$local_server_type + if [ "$local_server_type" = "ss-rust" ] || [ "$local_server_type" = "ss-libev" ]; then + type="ss" + fi + case "$type" in + ss | ssr) + gen_config_file $LOCAL_SERVER $type 4 $local_port + if [ "$local_server_type" = "ss-libev" ] || [ "$local_server_type" = "ssr" ]; then + ss_program="$(first_type ${type}-local)" + elif [ "$local_server_type" = "ss-rust" ]; then + ss_program="$(first_type ${type}local)" + fi + echolog "$(get_name $type) program is: $ss_program" + # 获取当前软链接指向的执行文件路径 + old_ss_program=$(readlink -f "$TMP_PATH/bin/${type}-local" 2>/dev/null) + # **当 新旧执行文件路径不同时,删除旧链接** + if [ "$old_ss_program" != "$ss_program" ]; then + rm -rf "$TMP_PATH/bin/${type}-local" + fi + ln_start_bin $ss_program ${type}-local -c $local_config_file + echolog "Global_Socks5:$(get_name $type) Started!" ;; v2ray) if [ "$_local" == "2" ]; then gen_config_file $LOCAL_SERVER $type 4 0 $local_port - ln_start_bin $(first_type xray) v2ray run -c $local_config_file + ln_start_bin $(first_type xray v2ray) v2ray run -c $local_config_file fi - echolog "Global_Socks5:$($(first_type xray) version | head -1) Started!" + echolog "Global_Socks5:$($(first_type "xray" "v2ray") version | head -1) Started!" ;; trojan) #client gen_config_file $LOCAL_SERVER $type 4 $local_port @@ -1407,50 +1055,42 @@ start_local() { ln_start_bin $(first_type naive) naive --config $local_config_file echolog "Global_Socks5:$($(first_type naive) --version | head -1) Started!" ;; - tuic) - local mihomo_bin="$(first_type mihomo)" - local instance_key="${LOCAL_SERVER}-local" - [ -n "$probe_instance_key" ] && instance_key="$probe_instance_key" - [ -x "$mihomo_bin" ] || { - echolog "Global_Socks5:Mihomo 内核不存在,请确认 /usr/bin/mihomo 或 /usr/libexec/mihomo 可执行。" - return 1 - } - prepare_tuic_runtime_config "$LOCAL_SERVER" "$local_port" "$local_port" "$instance_key" "socks" || return 1 - local tuic_workdir="$(get_tuic_workdir "$instance_key")" - ln_start_bin "$mihomo_bin" tuic-local -d "$tuic_workdir" -f "$tuic_workdir/config.yaml" - echolog "Global_Socks5:Mihomo (TUIC) Started!" + hysteria2) + if [ "$_local" == "2" ]; then + gen_config_file $LOCAL_SERVER $type 4 0 $local_port + ln_start_bin $(first_type hysteria) hysteria client --config $local_config_file + echolog "Global_Socks5:$($(first_type hysteria) version | grep Version | awk '{print "Hysteria2: " $2}') Started!" + fi ;; - shadowtls) - #respective config for global socks and main node - if [ "$_local" == "2" ]; then - gen_config_file $LOCAL_SERVER $type 4 "10${tmp_tcp_local_port}" + tuic) + if [ "$_local" == "2" ]; then + gen_config_file $LOCAL_SERVER $type 4 $local_port + ln_start_bin $(first_type tuic-client) tuic-client --config $local_config_file + echolog "Global Socks5:$($(first_type tuic-client) --version) Started!" + fi + ;; + shadowtls) + #respective config for global socks and main node + if [ "$_local" == "2" ]; then + gen_config_file $LOCAL_SERVER $type 4 "10${tmp_tcp_local_port}" gen_config_file $LOCAL_SERVER $type 4 0 $local_port chain/"10${tmp_tcp_local_port}" ln_start_bin $(first_type shadow-tls) shadow-tls config --config $chain_local_config_file local chain_type=$(uci_get_by_name $LOCAL_SERVER chain_type) case ${chain_type} in vmess) - ln_start_bin $(first_type xray) v2ray run -c $local_config_file + ln_start_bin $(first_type xray v2ray) v2ray run -c $local_config_file echolog "Global Socks5 Proxy:shadow-tls chain-to$($(first_type xray) --version) Started!" ;; sslocal) ln_start_bin $(first_type sslocal) sslocal -c $local_config_file echolog "Global Socks5 Proxy:shadow-tls chain-to$($(first_type sslocal) --version) Started!" ;; - esac - fi - ;; - clash) - echolog "Global_Socks5:Clash total node is only supported when using Same as Global Server." - return 1 - ;; - socks5) - echolog "Global_Socks5:Socks5 transparent-only node cannot be used as generic Socks outbound." - return 1 - ;; - *) - local listenip='-i 0.0.0.0' - [ -e /proc/sys/net/ipv6 ] && listenip='-i ::' - ln_start_bin $(first_type microsocks) microsocks $listenip -p $local_port tcp-udp-ssr-local + esac + fi + ;; + *) + [ -e /proc/sys/net/ipv6 ] && local listenip='-i ::' + ln_start_bin $(first_type microsocks) microsocks $listenip -p $local_port tcp-udp-ssr-local echolog "Global_Socks5:$type Started!" ;; esac @@ -1458,192 +1098,13 @@ start_local() { return 0 } -start_local_with_port() { - start_local "$1" -} - -gen_3proxy_config() { - local cfg_file="$1" - local listen_port="$2" - local relay_socks_port="$3" - local auth_mode="$4" - local auth_user="$5" - local auth_pass="$6" - - cat <<-EOF >"$cfg_file" - daemon - pidfile $TMP_PATH/3proxy.pid - nserver 8.8.8.8 - nscache 65536 - timeouts 1 5 30 60 180 1800 15 60 - authcache ip 60 - internal 0.0.0.0 - external 0.0.0.0 - flush - EOF - - if [ "$auth_mode" = "password" ] && [ -n "$auth_user" ]; then - cat <<-EOF >>"$cfg_file" - auth strong - users $auth_user:CL:$auth_pass - allow $auth_user - EOF - else - cat <<-'EOF' >>"$cfg_file" - auth none - allow * - EOF - fi - - cat <<-EOF >>"$cfg_file" - parent 1000 socks5 127.0.0.1 $relay_socks_port - proxy -n -a -p$listen_port - flush - EOF -} - -start_http_proxy() { - [ "$HTTP_SERVER" = "nil" ] && return 1 - - local http_local_port=$(uci_get_by_type http_proxy local_port 3128) - local http_auth_mode=$(uci_get_by_type http_proxy http_auth none) - local http_user=$(uci_get_by_type http_proxy http_user) - local http_pass=$(uci_get_by_type http_proxy http_pass) - local http_server_type=$(uci_get_by_name $HTTP_SERVER type) - local need_local_start=1 - local prev_local_server="$LOCAL_SERVER" - local prev_local_config_file="$local_config_file" - local prev_local_flag="$local_enable" - local prev_local_mode="$_local" - local http_config_file="$TMP_PATH/3proxy-ssr-http.cfg" - local global_socks_enabled=$(uci_get_by_type socks5_proxy enabled 0) - local global_socks_port=$(uci_get_by_type socks5_proxy local_port 1080) - local global_socks_server=$(uci_get_by_type socks5_proxy server nil) - local resolved_socks_server="$global_socks_server" - local http_socks_port="$global_socks_port" - - if [ -z "$http_socks_port" ] || [ "$http_socks_port" = "0" ]; then - http_socks_port=1080 - fi - - [ "$http_local_port" = "$http_socks_port" ] && { - echolog "Global_HTTP: HTTP 监听端口与上游 SOCKS5 端口不能相同。" - return 1 - } - - if [ "$resolved_socks_server" = "same" ]; then - resolved_socks_server="$GLOBAL_SERVER" - fi - - if [ "$global_socks_enabled" = "1" ] && [ "$http_socks_port" = "$global_socks_port" ] && [ "$resolved_socks_server" != "$HTTP_SERVER" ]; then - echolog "Global_HTTP: Relay SOCKS5 Port 已被全局 SOCKS5 代理占用,请改用其他端口。" - return 1 - fi - - if [ "$http_auth_mode" = "password" ] && [ -z "$http_user" ]; then - echolog "Global_HTTP: HTTP 认证模式为 password 时必须填写用户名。" - return 1 - fi - - case "$http_server_type" in - socks5) - echolog "Global_HTTP: 当前节点类型不支持作为 3proxy 的上游 SOCKS5 出口。" - return 1 - ;; - esac - - if [ "$http_server_type" = "clash" ]; then - if [ "$HTTP_SERVER" != "$GLOBAL_SERVER" ]; then - echolog "Global_HTTP: Clash 节点仅支持选择 Same as Global Server 进行复用。" - return 1 - fi - if [ "$http_socks_port" != "$global_socks_port" ] && [ "$global_socks_enabled" = "1" ] && [ "$resolved_socks_server" = "$HTTP_SERVER" ]; then - echolog "Global_HTTP: Mihomo/Clash 仅支持单个 socks-port,请让 HTTP 代理与全局 SOCKS5 使用相同的上游 SOCKS5 端口。" - return 1 - fi - fi - - if supports_builtin_http "$http_server_type" && [ "$HTTP_SERVER" = "$GLOBAL_SERVER" ]; then - need_local_start=0 - elif [ "$global_socks_enabled" = "1" ] && [ "$resolved_socks_server" = "$HTTP_SERVER" ] && [ "$global_socks_port" = "$http_socks_port" ]; then - need_local_start=0 - else - LOCAL_SERVER="$HTTP_SERVER" - local_config_file="$TMP_PATH/tcp-http-ssr-local.json" - _local="2" - local_enable=0 - start_local_with_port "$http_socks_port" || { - LOCAL_SERVER="$prev_local_server" - local_config_file="$prev_local_config_file" - local_enable="$prev_local_flag" - _local="$prev_local_mode" - return 1 - } - LOCAL_SERVER="$prev_local_server" - local_config_file="$prev_local_config_file" - local_enable="$prev_local_flag" - _local="$prev_local_mode" - fi - - [ "$need_local_start" = "0" ] && echolog "Global_HTTP: Reuse existing local Socks5 upstream on port $http_socks_port." - - gen_3proxy_config "$http_config_file" "$http_local_port" "$http_socks_port" "$http_auth_mode" "$http_user" "$http_pass" - ln_start_bin $(first_type 3proxy) 3proxy "$http_config_file" - echolog "Global_HTTP:3proxy HTTP/HTTPS Proxy Started!" - http_enable=1 - return 0 -} - -get_udp_relay_mode() { - local node="$1" - local type - local proto - local socks_ver - - type=$(uci_get_by_name "$node" type) - [ "$type" = "ss-rust" ] && type="ss" - - case "$type" in - ss|ssr|hysteria2) - echo "native" - ;; - clash|tuic) - echo "native" - ;; - trojan|shadowtls) - echo "split" - ;; - socks5) - echo "split" - ;; - naiveproxy) - echo "disabled" - ;; - v2ray) - proto=$(uci_get_by_name "$node" v2ray_protocol) - case "$proto" in - http) - echo "disabled" - ;; - socks) - socks_ver=$(uci_get_by_name "$node" socks_ver 5) - [ "$socks_ver" = "5" ] && echo "native" || echo "disabled" - ;; - *) - echo "native" - ;; - esac - ;; - *) - echo "disabled" - ;; - esac -} - Start_Run() { - local threads=$(get_configured_threads) - local global_server_type=$(uci_get_by_name $GLOBAL_SERVER type) - if [ "$(uci_get_by_name $GLOBAL_SERVER kcp_enable 0)" == "1" ] && [ "$global_server_type" != "ss" ]; then + if [ "$(uci_get_by_type global threads 0)" == "0" ]; then + local threads=$(cat /proc/cpuinfo | grep 'processor' | wc -l) + else + local threads=$(uci_get_by_type global threads) + fi + if [ "$(uci_get_by_name $GLOBAL_SERVER kcp_enable 0)" == "1" ]; then [ ! -f "/usr/bin/kcptun-client" ] && return 1 local kcp_str=$(/usr/bin/kcptun-client -v | grep kcptun | wc -l) [ "0" == "$kcp_str" ] && return 1 @@ -1671,59 +1132,36 @@ Start_Run() { # fi #} fi - local tcp_port=$(get_default_node_local_port) + local tcp_port=$(uci_get_by_name $GLOBAL_SERVER local_port) + local global_server_type=$(uci_get_by_name $GLOBAL_SERVER type) local type=$global_server_type - if [ "$global_server_type" = "ss-rust" ]; then + if [ "$global_server_type" = "ss-rust" ] || [ "$global_server_type" = "ss-libev" ]; then type="ss" fi case "$type" in ss | ssr) - if [ "$global_server_type" = "ssr" ]; then - gen_config_file $GLOBAL_SERVER $type 1 $tcp_port + gen_config_file $GLOBAL_SERVER $type 1 $tcp_port + if [ "$global_server_type" = "ss-libev" ] || [ "$global_server_type" = "ssr" ]; then ss_program="$(first_type ${type}-redir)" - echolog "$(get_name $type) program is: $ss_program" - old_ss_program=$(readlink -f "$TMP_PATH/bin/${type}-redir" 2>/dev/null) - if [ "$old_ss_program" != "$ss_program" ]; then - rm -rf "$TMP_PATH/bin/${type}-redir" - fi - for i in $(seq 1 $threads); do - ln_start_bin $ss_program ${type}-redir -c $tcp_config_file - done - echolog "Main node:$(get_name $type) $threads Threads Started!" - elif [ "$global_server_type" = "ss" ] || { [ "$global_server_type" = "ss-rust" ] && use_mihomo_for_ss_rust_client; }; then - local mihomo_bin="$(first_type mihomo)" - local ss_socks_port=0 - [ -x "$mihomo_bin" ] || { - echolog "Main node:Mihomo 内核不存在,请确认 /usr/bin/mihomo 或 /usr/libexec/mihomo 可执行。" - return 1 - } - if [ "$_local" = "1" ] && [ "$LOCAL_SERVER" = "$GLOBAL_SERVER" ]; then - ss_socks_port=$(uci_get_by_type socks5_proxy local_port 1080) - fi - prepare_ss_mihomo_runtime_config "$GLOBAL_SERVER" "$tcp_port" "$ss_socks_port" "$GLOBAL_SERVER" "redir" || return 1 - local ss_workdir="$(get_ss_mihomo_workdir "$GLOBAL_SERVER")" - ln_start_bin "$mihomo_bin" ssr-retcp -d "$ss_workdir" -f "$ss_workdir/config.yaml" - if [ "$global_server_type" = "ss-rust" ]; then - echolog "Main node:ss-rust 主程序不存在,已回退到 Mihomo (Shadowsocks) 启动。" - else - echolog "Main node:Mihomo (Shadowsocks) Started!" - fi - else - gen_config_file $GLOBAL_SERVER $type 1 $tcp_port - ss_program="$(first_type sslocal)" - echolog "ShadowSocks program is: $ss_program" - old_ss_program=$(readlink -f "$TMP_PATH/bin/${type}-redir" 2>/dev/null) - if [ "$old_ss_program" != "$ss_program" ]; then - rm -rf "$TMP_PATH/bin/${type}-redir" - fi - ln_start_bin $ss_program ${type}-redir -c $tcp_config_file - echolog "Main node:Shadowsocks-rust Started!" + elif [ "$global_server_type" = "ss-rust" ]; then + ss_program="$(first_type ${type}local)" fi + echolog "$(get_name $type) program is: $ss_program" + # 获取当前软链接指向的执行文件路径 + old_ss_program=$(readlink -f "$TMP_PATH/bin/${type}-redir" 2>/dev/null) + # **当新旧执行文件路径不同时,删除旧链接** + if [ "$old_ss_program" != "$ss_program" ]; then + rm -rf "$TMP_PATH/bin/${type}-redir" + fi + for i in $(seq 1 $threads); do + ln_start_bin $ss_program ${type}-redir -c $tcp_config_file + done + echolog "Main node:$(get_name $type) $threads Threads Started!" ;; v2ray) gen_config_file $GLOBAL_SERVER $type 1 $tcp_port $socks_port - ln_start_bin $(first_type xray) v2ray run -c $tcp_config_file - echolog "Main node:$($(first_type xray) version | head -1) Started!" + ln_start_bin $(first_type xray v2ray) v2ray run -c $tcp_config_file + echolog "Main node:$($(first_type xray v2ray) version | head -1) Started!" ;; trojan) gen_config_file $GLOBAL_SERVER $type 1 $tcp_port @@ -1737,24 +1175,27 @@ Start_Run() { ln_start_bin $(first_type naive) naive $tcp_config_file echolog "Main node:$($(first_type naive) --version 2>&1 | head -1) , $threads Threads Started!" ;; - tuic) - local mihomo_bin="$(first_type mihomo)" - local tuic_socks_port=0 - [ -x "$mihomo_bin" ] || { - echolog "Main node:Mihomo 内核不存在,请确认 /usr/bin/mihomo 或 /usr/libexec/mihomo 可执行。" - return 1 - } - if [ "$_local" = "1" ] && [ "$LOCAL_SERVER" = "$GLOBAL_SERVER" ]; then - tuic_socks_port=$(uci_get_by_type socks5_proxy local_port 1080) - fi - prepare_tuic_runtime_config "$GLOBAL_SERVER" "$tcp_port" "$tuic_socks_port" "$GLOBAL_SERVER" "redir" || return 1 - local tuic_workdir="$(get_tuic_workdir "$GLOBAL_SERVER")" - ln_start_bin "$mihomo_bin" ssr-retcp -d "$tuic_workdir" -f "$tuic_workdir/config.yaml" - echolog "Main node:Mihomo (TUIC) Started!" + hysteria2) + gen_config_file $GLOBAL_SERVER $type 1 $tcp_port $socks_port + ln_start_bin $(first_type hysteria) hysteria client --config $tcp_config_file + echolog "Main node:$($(first_type hysteria) version | grep Version | awk '{print "Hysteria2: " $2}') Started!" ;; - shadowtls) - if [ -z "$socks_port" ]; then - gen_config_file $GLOBAL_SERVER $type 1 "10${tmp_tcp_local_port}" + tuic) + local PARAM + [ $mode == "tcp" ] && PARAM="-T" || PARAM="" + gen_config_file $GLOBAL_SERVER $type 1 $tmp_tcp_local_port + ln_start_bin $(first_type tuic-client) tuic-client --config $tcp_config_file + ln_start_bin $(first_type ipt2socks) ipt2socks "$PARAM" -R -b 0.0.0.0 -4 -s 127.0.0.1 -p $tmp_tcp_local_port -l $tcp_port + if [ -n $socks_port ] && [ $GLOBAL_SERVER == $LOCAL_SERVER ]; then #start a new tuic instance + gen_config_file $GLOBAL_SERVER $type 4 $socks_port + ln_start_bin $(first_type tuic-client) tuic-client --config $local_config_file + echolog "Global Socks5:$($(first_type tuic-client) --version) Started!" + fi + echolog "Main node:$($(first_type tuic-client) --version) Started!" + ;; + shadowtls) + if [ -z "$socks_port" ]; then + gen_config_file $GLOBAL_SERVER $type 1 "10${tmp_tcp_local_port}" gen_config_file $GLOBAL_SERVER $type 1 "10${tmp_tcp_local_port}" 0 chain else gen_config_file $GLOBAL_SERVER $type 1 "10${tmp_tcp_local_port}" @@ -1764,7 +1205,7 @@ Start_Run() { case ${chain_type} in vmess) ln_start_bin $(first_type shadow-tls) shadow-tls config --config $chain_config_file - ln_start_bin $(first_type xray) v2ray run -c $tcp_config_file + ln_start_bin $(first_type xray v2ray) v2ray run -c $tcp_config_file echolog "Mian node:shadow-tls chain-to $($(first_type xray) --version) Started!" ;; sslocal) @@ -1772,49 +1213,25 @@ Start_Run() { ln_start_bin $(first_type sslocal) sslocal -c $tcp_config_file echolog "Main node:shadow-tls chain-to $($(first_type sslocal) --version) Started!" ;; - esac - ;; - clash) - local clash_socks_port=0 - local mihomo_bin="$(first_type mihomo)" - clash_socks_port="$(resolve_global_clash_socks_port)" - if [ -z "$clash_socks_port" ] && [ "$_local" == "1" ] && [ "$LOCAL_SERVER" = "$GLOBAL_SERVER" ]; then - clash_socks_port=$(uci_get_by_type socks5_proxy local_port 1080) - fi - [ -x "$mihomo_bin" ] || { - echolog "Main node:Mihomo 内核不存在,请确认 /usr/bin/mihomo 或 /usr/libexec/mihomo 可执行。" - return 1 - } - download_clash_config "$GLOBAL_SERVER" || { - echolog "Main node:Clash 配置不可用,启动中止。" - return 1 - } - prepare_clash_runtime_config "$GLOBAL_SERVER" "$tcp_port" "$clash_socks_port" || { - echolog "Main node:Clash 运行配置生成失败,启动中止。" - return 1 - } - local clash_workdir="$(get_clash_workdir "$GLOBAL_SERVER")" - ln_start_bin "$mihomo_bin" ssr-retcp -d "$clash_workdir" -f "$clash_workdir/config.yaml" - echolog "Main node:Mihomo (Clash) Started!" - ;; + esac + ;; socks5) - local ipt2socks_bin="$(first_type ipt2socks)" - local auth_opts="" - [ -x "$ipt2socks_bin" ] || { - echolog "Main node:Socks5 缺少 ipt2socks,无法启动透明代理。" - return 1 - } - if [ "$(uci_get_by_name $GLOBAL_SERVER auth_enable 0)" = "1" ]; then - auth_opts="-a $(uci_get_by_name $GLOBAL_SERVER username) -k $(uci_get_by_name $GLOBAL_SERVER password)" + if [ "$(uci_get_by_name $GLOBAL_SERVER auth_enable 0)" == "1" ]; then + local auth="-a $(uci_get_by_name $GLOBAL_SERVER username) -k $(uci_get_by_name $GLOBAL_SERVER password)" fi + ln_start_bin $(first_type ipt2socks) ipt2socks $tcp_config_file -R -4 -j $threads -s $(uci_get_by_name $GLOBAL_SERVER server) -p $(uci_get_by_name $GLOBAL_SERVER server_port) -l $tcp_port $auth + #gen_config_file $GLOBAL_SERVER $type 1 $tcp_port + #for i in $(seq 1 $threads); do + # ln_start_bin $(first_type redsocks2) redsocks2 -c $tcp_config_file + #done + echolog "Main node:Socks5 REDIRECT/TPROXY $threads Threads Started!" + ;; + tun) + gen_config_file $GLOBAL_SERVER $type 1 $tcp_port for i in $(seq 1 $threads); do - ln_start_bin "$ipt2socks_bin" ipt2socks \ - -T -R -r -b 0.0.0.0 -4 \ - -s "$(uci_get_by_name $GLOBAL_SERVER server)" \ - -p "$(uci_get_by_name $GLOBAL_SERVER server_port)" \ - -l "$tcp_port" $auth_opts + ln_start_bin $(first_type redsocks2) redsocks2 -c $tcp_config_file done - echolog "Main node:Socks5 via IPT2Socks $threads Threads Started!" + echolog "Main node:Network Tunnel REDIRECT $threads Threads Started!" ;; esac redir_tcp=1 @@ -1827,17 +1244,6 @@ load_config() { else GLOBAL_SERVER=$switch_server fi - if [ "$(uci_get_by_type socks5_proxy enabled 0)" == "1" ]; then - uci -q set "$NAME.@socks5_proxy[0].server=same" - else - uci -q set "$NAME.@socks5_proxy[0].server=nil" - fi - if [ "$(uci_get_by_type http_proxy enabled 0)" == "1" ]; then - uci -q set "$NAME.@http_proxy[0].server=same" - else - uci -q set "$NAME.@http_proxy[0].server=nil" - fi - uci -q commit "$NAME" if [ "$(uci_get_by_type socks5_proxy enabled 0)" == "1" ]; then # 只有开启 全局socks 才需要取值 LOCAL_SERVER=$(uci_get_by_type socks5_proxy server nil) @@ -1845,65 +1251,88 @@ load_config() { # 没有开启 设置为 nil LOCAL_SERVER=nil fi - if [ "$(uci_get_by_type http_proxy enabled 0)" == "1" ]; then - HTTP_SERVER=$(uci_get_by_type http_proxy server nil) - else - HTTP_SERVER=nil - fi if [ "$GLOBAL_SERVER" == "nil" ]; then - [ "$HTTP_SERVER" = "same" ] && HTTP_SERVER=nil mode="tcp,udp" _local="2" local_config_file=$TMP_PATH/tcp-udp-ssr-local.json start_local return 1 fi - UDP_RELAY_SERVER=$GLOBAL_SERVER - local udp_mode=$(get_udp_relay_mode "$GLOBAL_SERVER") + UDP_RELAY_SERVER=$(uci_get_by_type global udp_relay_server nil) + if [ "$(uci_get_by_type global netflix_enable 0)" == "1" ]; then + # 只有开启 NetFlix分流 才需要取值 + SHUNT_SERVER=$(uci_get_by_type global netflix_server nil) + else + # 没有开启 设置为 nil + SHUNT_SERVER=nil + fi + #tcp_config_file=$TMP_PATH/tcp-udp-dual-ssr-retcp.json tcp_config_file=$TMP_PATH/tcp-only-ssr-retcp.json - case "$udp_mode" in - disabled) - echolog "提示:当前节点类型不提供 UDP 透明代理,也不会启用任何 UDP 规则,仅启用 TCP 透明代理。" + case "$UDP_RELAY_SERVER" in + nil) + #mode="tcp,udp" mode="tcp" ARG_UDP="" - ARG_UDP_RULES="-y" udp_config_file="" ;; - native) + $GLOBAL_SERVER | same) mode="tcp,udp" tcp_config_file=$TMP_PATH/tcp-udp-ssr-retcp.json ARG_UDP="-u" - ARG_UDP_RULES="" + UDP_RELAY_SERVER=$GLOBAL_SERVER ;; - split) + *) mode="udp" udp_config_file=$TMP_PATH/udp-only-ssr-reudp.json ARG_UDP="-U" - ARG_UDP_RULES="" start_udp + #mode="tcp,udp" mode="tcp" ;; esac case "$LOCAL_SERVER" in nil) - _local="0" - ;; - "$GLOBAL_SERVER"|same) - _local="1" - LOCAL_SERVER=$GLOBAL_SERVER - local_config_file=$TMP_PATH/tcp-udp-ssr-local.json - if ! supports_builtin_socks "$(uci_get_by_name $GLOBAL_SERVER type)"; then - start_local - fi - local_enable=0 - ;; + _local="0" + ;; + $GLOBAL_SERVER | same) + _local="1" + LOCAL_SERVER=$GLOBAL_SERVER + local_config_file=$TMP_PATH/tcp-udp-ssr-local.json + start_local + local_enable=0 + ;; + $SHUNT_SERVER) + _local="3" + local_config_file=$TMP_PATH/tcp-udp-ssr-local.json + start_local + ;; *) _local="2" local_config_file=$TMP_PATH/tcp-udp-ssr-local.json start_local ;; esac - [ "$HTTP_SERVER" = "same" ] && HTTP_SERVER=$GLOBAL_SERVER + case "$SHUNT_SERVER" in + nil) + shunt="0" + ;; + $GLOBAL_SERVER | same) + shunt="1" + SHUNT_SERVER=$GLOBAL_SERVER + ;; + $LOCAL_SERVER) + shunt="$tmp_shunt_port" + shunt_config_file=$TMP_PATH/tcp-udp-ssr-local.json + shunt_dns_config_file=$TMP_PATH/shunt-dns-ssr-plus.json + start_shunt + ;; + *) + shunt="$tmp_shunt_port" + shunt_config_file=$TMP_PATH/shunt-ssr-retcp.json + shunt_dns_config_file=$TMP_PATH/shunt-dns-ssr-plus.json + start_shunt + ;; + esac return 0 } @@ -1950,108 +1379,39 @@ start_server() { fi fi fi - local node_type=$(uci_get_by_name $1 type) - local type=$node_type - if [ "$node_type" = "ss-rust" ]; then - type="ss" + local node_type=$(uci_get_by_name $1 type) + local type=$node_type + if [ "$node_type" = "ss-rust" ] || [ "$node_type" = "ss-libev" ]; then + type="ss" + fi + case "$type" in + ss | ssr) + gen_service_file ${type} $1 $TMP_PATH/ssr-server$server_count.json + if [ "$node_type" = "ss-libev" ] || [ "$node_type" = "ssr" ]; then + ss_program="$(first_type ${type}-server)" + elif [ "$node_type" = "ss-rust" ]; then + ss_program="$(first_type ${type}server)" fi - case "$type" in - ss | ssr) - if [ "$node_type" = "ss" ] || { [ "$node_type" = "ss-rust" ] && use_mihomo_for_ss_rust_server; }; then - local mihomo_bin="$(first_type mihomo)" - [ -x "$mihomo_bin" ] || { - echolog "Server:Mihomo 内核不存在,请确认 /usr/bin/mihomo 或 /usr/libexec/mihomo 可执行。" - return 1 - } - prepare_ss_server_mihomo_runtime_config "$1" || return 1 - local ss_server_workdir="$(get_ss_server_mihomo_workdir "$1")" - ln_start_bin "$mihomo_bin" ss-server-$server_count -d "$ss_server_workdir" -f "$ss_server_workdir/config.yaml" - if [ "$node_type" = "ss-rust" ]; then - echolog "Server:ss-rust 主程序不存在,已回退到 Mihomo Shadowsocks Server$server_count 启动。" - else - echolog "Server:Mihomo Shadowsocks Server$server_count Started!" - fi - else - gen_service_file ${type} $1 $TMP_PATH/ssr-server$server_count.json - if [ "$node_type" = "ssr" ]; then - ss_program="$(first_type ${type}-server)" - elif [ "$node_type" = "ss-rust" ] || [ "$node_type" = "ss" ]; then - ss_program="$(first_type ${type}server)" - fi - old_ss_program=$(readlink -f "$TMP_PATH/bin/${type}-server" 2>/dev/null) - if [ "$old_ss_program" != "$ss_program" ]; then - rm -rf "$TMP_PATH/bin/${type}-server" - fi - ln_start_bin $ss_program ${type}-server -c $TMP_PATH/ssr-server$server_count.json - echolog "Server: $(get_name ${type}) Server$server_count Started!" - fi + # 获取当前软链接指向的执行文件路径 + old_ss_program=$(readlink -f "$TMP_PATH/bin/${type}-server" 2>/dev/null) + # **当新旧执行文件路径不同时,删除旧链接** + if [ "$old_ss_program" != "$ss_program" ]; then + rm -rf "$TMP_PATH/bin/${type}-server" + fi + ln_start_bin $ss_program ${type}-server -c $TMP_PATH/ssr-server$server_count.json + echolog "Server: $(get_name ${type}) Server$server_count Started!" ;; socks5) - local listenip='-i 0.0.0.0' - [ -e /proc/sys/net/ipv6 ] && listenip='-i ::' + [ -e /proc/sys/net/ipv6 ] && local listenip='-i ::' local username=$(uci_get_by_name $1 username) local password=$(uci_get_by_name $1 password) local auth_opts="" - if [ -n "$username" ]; then - auth_opts="-u $username" - [ -n "$password" ] && auth_opts="$auth_opts -P $password" + if [ -n "$username" ] && [ -n "$password" ]; then + auth_opts="-u $username -P $password" fi ln_start_bin $(first_type microsocks) microsocks $listenip -p $(uci_get_by_name $1 server_port) -1 $auth_opts ssr-server$server_count echolog "Server:Socks5 Server$server_count Started!" ;; - vmess|vless|trojan|shadowsocks) - # Xray 服务端支持 - local port=$(uci_get_by_name "$1" server_port) - local uuid=$(uci_get_by_name "$1" uuid) - local trojan_pass=$(uci_get_by_name "$1" trojan_password) - local ss_pass=$(uci_get_by_name "$1" ss_password) - local security=$(uci_get_by_name "$1" security "auto") - local network=$(uci_get_by_name "$1" network "tcp") - local ws_path=$(uci_get_by_name "$1" ws_path "/") - local ws_host=$(uci_get_by_name "$1" ws_host "") - local grpc_service=$(uci_get_by_name "$1" grpc_service "") - local alter_id=$(uci_get_by_name "$1" alter_id "0") - local tcp_guise=$(uci_get_by_name "$1" tcp_guise "none") - local tcp_guise_http_host=$(uci_get_by_name "$1" tcp_guise_http_host "") - local tcp_guise_http_path=$(uci_get_by_name "$1" tcp_guise_http_path "") - - # 确定密码/UUID - local password="" - local method="" - if [ "$type" = "vmess" ] || [ "$type" = "vless" ]; then - password="$uuid" - elif [ "$type" = "trojan" ]; then - password="$trojan_pass" - elif [ "$type" = "shadowsocks" ]; then - password="$ss_pass" - method="$security" - [ -z "$method" ] && method="chacha20-ietf-poly1305" - fi - - [ -z "$password" ] && { - echolog "Server: $type 服务端缺少密码/UUID,跳过启动" - return 1 - } - - local config_file="$TMP_PATH/xray-server-$server_count.json" - - # 生成 Xray 配置 - generate_xray_config "$type" "$port" "$password" "$security" "$method" "$network" "$ws_path" "$ws_host" "$grpc_service" "$alter_id" "$tcp_guise" "$tcp_guise_http_host" "$tcp_guise_http_path" "$config_file" - - if [ $? -ne 0 ]; then - echolog "Server: Xray $type 配置生成失败" - return 1 - fi - - local xray_bin=$(first_type xray) - if [ -z "$xray_bin" ]; then - echolog "Server: xray-core 未安装,无法启动 $type 服务端" - return 1 - fi - - ln_start_bin "$xray_bin" xray-server-$server_count run -c "$config_file" - echolog "Server: Xray $type 服务端 Server$server_count 已启动 (端口: $port)" - ;; esac server_port=$(uci_get_by_name $1 server_port) if [ "$USE_TABLES" = "nftables" ]; then @@ -2111,10 +1471,6 @@ start_server() { } start_switch() { - if [ "$(uci_get_by_name $GLOBAL_SERVER type)" = "clash" ] || [ "$(uci_get_by_name $GLOBAL_SERVER type)" = "tuic" ]; then - echolog "提示:Mihomo 托管节点不启用 SSR Plus 自动切换逻辑。" - return 0 - fi if [ "$(uci_get_by_type global enable_switch 0)" == "1" ]; then if [ -z "$switch_server" ]; then local switch_time=$(uci_get_by_type global switch_time)s @@ -2139,7 +1495,7 @@ start_xhttp_addr() { # 收集所有节点的 download_address 值,去掉空行并去重排序 { - for sec in "$GLOBAL_SERVER" "$UDP_RELAY_SERVER"; do + for sec in "$GLOBAL_SERVER" "$SHUNT_SERVER" "$UDP_RELAY_SERVER"; do local addr addr=$(uci_get_by_name "$sec" download_address) [ -n "$addr" ] && echo "$addr" @@ -2173,22 +1529,26 @@ start_xhttp_addr() { start_rules() { local server=$(get_host_ip $GLOBAL_SERVER) - local local_port=$(get_default_node_local_port) + local local_port=$(uci_get_by_name $GLOBAL_SERVER local_port) local lan_ac_ips=$(uci_get_by_type access_control lan_ac_ips) local lan_ac_mode=$(uci_get_by_type access_control lan_ac_mode) if [ "$kcp_enable_flag" == "0" -a "$redir_udp" == "1" ]; then local udp_server=$(get_host_ip $UDP_RELAY_SERVER) local udp_local_port=$tmp_udp_port fi + if [ "$shunt" != "0" ]; then + local shunt_ip=$(get_host_ip $SHUNT_SERVER) + fi if [ -n "$lan_ac_ips" ]; then case "$lan_ac_mode" in w | W | b | B) local ac_ips="$lan_ac_mode$lan_ac_ips" ;; esac fi gfwmode() { - case "$(normalize_run_mode)" in + case "$(uci_get_by_type global run_mode)" in gfw) echo "-g" ;; router) echo "-r" ;; + oversea) echo "-c" ;; all) echo "-z" ;; esac } @@ -2219,44 +1579,45 @@ start_rules() { fi elif [ "$USE_TABLES" = "iptables" ]; then ARG_A="" - fi - /usr/share/shadowsocksr/gfw2ipset.sh - /usr/bin/ssr-rules \ - -s "$server" \ - -l "$local_port" \ - -S "$udp_server" \ - -L "$udp_local_port" \ - -a "$ac_ips" \ - -i "/etc/ssrplus/china_ssr.txt" \ - -b "$(uci_get_by_type access_control wan_bp_ips)" \ - -w "$(uci_get_by_type access_control wan_fw_ips)" \ - -B "$(uci_get_by_type access_control lan_bp_ips)" \ - -p "$(uci_get_by_type access_control lan_fp_ips)" \ - -G "$(uci_get_by_type access_control lan_gm_ips)" \ - -m "$(uci_get_by_type access_control Interface)" \ - -D "$proxyport" \ - $(get_arg_out) $(gfwmode) $ARG_UDP $ARG_UDP_RULES $ARG_A + fi + /usr/share/shadowsocksr/gfw2ipset.sh + /usr/bin/ssr-rules \ + -s "$server" \ + -l "$local_port" \ + -S "$udp_server" \ + -L "$udp_local_port" \ + -a "$ac_ips" \ + -i "/etc/ssrplus/china_ssr.txt" \ + -b "$(uci_get_by_type access_control wan_bp_ips)" \ + -w "$(uci_get_by_type access_control wan_fw_ips)" \ + -B "$(uci_get_by_type access_control lan_bp_ips)" \ + -p "$(uci_get_by_type access_control lan_fp_ips)" \ + -G "$(uci_get_by_type access_control lan_gm_ips)" \ + -m "$(uci_get_by_type access_control Interface)" \ + -D "$proxyport" \ + -F "$shunt" \ + -N "$shunt_ip" \ + -M "$(uci_get_by_type global netflix_proxy 0)" \ + -I "/etc/ssrplus/netflixip.list" \ + $(get_arg_out) $(gfwmode) $ARG_UDP $ARG_A - return $? - } + return $? +} start() { set_lock echolog "----------start------------" - mkdir -p /var/run /var/lock /var/log $DNSMASQ_CONF_DIR $TMP_BIN_PATH $TMP_DNSMASQ_PATH $CLASH_CONFIG_DIR + mkdir -p /var/run /var/lock /var/log $DNSMASQ_CONF_DIR $TMP_BIN_PATH $TMP_DNSMASQ_PATH echo "conf-dir=${TMP_DNSMASQ_PATH}" >"$DNSMASQ_CONF_DIR/dnsmasq-ssrplus.conf" check_run_environment - normalize_run_mode >/dev/null - normalize_xray_protocol_nodes if load_config; then Start_Run - start_http_proxy start_xhttp_addr start_rules start_dns # Restore ipsets after rules creation if [ "$HAS_IPSET" -eq 1 ]; then - for setname in gfwlist china blacklist whitelist; do + for setname in gfwlist china blacklist whitelist netflix; do [ "$setname" = "gfwlist" ] && [ "$run_mode" != "gfw" ] && continue if [ -f "/tmp/ssrplus_save/${setname}.save" ]; then ipset restore -! < "/tmp/ssrplus_save/${setname}.save" 2>/dev/null @@ -2271,41 +1632,16 @@ start() { echolog "禁止连接的域名加载完毕。" if [ "$(uci_get_by_type global adblock 0)" == "1" ]; then echolog "未启动主节点,广告过滤正在加载。" - cp -f /etc/ssrplus/ad.conf "$TMP_DNSMASQ_PATH/" + cp -f /etc/ssrplus/ad.conf $TMP_DNSMASQ_PATH/ if [ -f "$TMP_DNSMASQ_PATH/ad.conf" ]; then # Optimize: Batch filter using grep instead of looping sed for list_file in /etc/ssrplus/black.list /etc/ssrplus/white.list /etc/ssrplus/deny.list; do if [ -s "$list_file" ]; then # Clean list file (remove comments and empty lines) - grep -vE '^\s*#|^\s*$' "$list_file" | sed 's/\r//g' > "${list_file}.clean" + grep -vE '^\s*#|^\s*$' "$list_file" > "${list_file}.clean" if [ -s "${list_file}.clean" ]; then - tmp_file="$TMP_DNSMASQ_PATH/ad.conf.tmp" - awk -v list="${list_file}.clean" ' - BEGIN { - while ((getline line < list) > 0) { - gsub(/\r/, "", line) - if (line != "") { - domain[line] = 1 - # 支持泛域名 - domain["*." line] = 1 - } - } - close(list) - } - { - keep = 1 - # 匹配 server=/domain/ - if (match($0, /^server=\/([^\/]+)\//, m)) { - if (m[1] in domain) keep = 0 - } - # 匹配 ipset=/domain/ - if (match($0, /^ipset=\/([^\/]+)\//, m)) { - if (m[1] in domain) keep = 0 - } - if (keep) print - } - ' "$TMP_DNSMASQ_PATH/ad.conf" > "$tmp_file" - mv "$tmp_file" "$TMP_DNSMASQ_PATH/ad.conf" + grep -v -F -f "${list_file}.clean" "$TMP_DNSMASQ_PATH/ad.conf" > "$TMP_DNSMASQ_PATH/ad.conf.tmp" + mv "$TMP_DNSMASQ_PATH/ad.conf.tmp" "$TMP_DNSMASQ_PATH/ad.conf" fi rm -f "${list_file}.clean" fi @@ -2313,7 +1649,6 @@ start() { fi echolog "广告过滤加载完毕。" fi - start_http_proxy fi /etc/init.d/dnsmasq restart >/dev/null 2>&1 check_server @@ -2348,7 +1683,7 @@ stop() { if [ "$run_mode" = "gfw" ]; then ipset save gfwlist > /tmp/ssrplus_save/gfwlist.save 2>/dev/null fi - for setname in china blacklist whitelist; do + for setname in china blacklist whitelist netflix; do ipset save $setname > /tmp/ssrplus_save/$setname.save 2>/dev/null done fi @@ -2402,21 +1737,21 @@ stop() { fi fi fi - if [ -z "$switch_server" ]; then - ps_list | grep -v "grep" | grep ssr-switch | awk '{print $1}' | xargs kill -9 >/dev/null 2>&1 & - rm -f /var/lock/ssr-switch.lock - killall -q -9 kcptun-client - fi - ps_list | grep -v "grep" | grep ssr-monitor | awk '{print $1}' | xargs kill -9 >/dev/null 2>&1 & - ps_list | grep -v "grep" | grep ssr-rules | awk '{print $1}' | xargs kill -9 >/dev/null 2>&1 & - ps_list | grep -v "grep" | grep "sleep 0000" | awk '{print $1}' | xargs kill -9 >/dev/null 2>&1 & - ( \ - # Graceful kill first, so programs have the chance to stop its subprocesses - ps_list | grep -v "grep" | grep "$TMP_PATH" | awk '{print $1}' | xargs kill >/dev/null 2>&1 ; \ - sleep 3s; \ - # Force kill hanged programs - ps_list | grep -v "grep" | grep "$TMP_PATH" | awk '{print $1}' | xargs kill -9 >/dev/null 2>&1 ; \ - ) + if [ -z "$switch_server" ]; then + $PS -w | grep -v "grep" | grep ssr-switch | awk '{print $1}' | xargs kill -9 >/dev/null 2>&1 & + rm -f /var/lock/ssr-switch.lock + killall -q -9 kcptun-client + fi + $PS -w | grep -v "grep" | grep ssr-monitor | awk '{print $1}' | xargs kill -9 >/dev/null 2>&1 & + $PS -w | grep -v "grep" | grep ssr-rules | awk '{print $1}' | xargs kill -9 >/dev/null 2>&1 & + $PS -w | grep -v "grep" | grep "sleep 0000" | awk '{print $1}' | xargs kill -9 >/dev/null 2>&1 & + ( \ + # Graceful kill first, so programs have the chance to stop its subprocesses + $PS -w | grep -v "grep" | grep "$TMP_PATH" | awk '{print $1}' | xargs kill >/dev/null 2>&1 ; \ + sleep 3s; \ + # Force kill hanged programs + $PS -w | grep -v "grep" | grep "$TMP_PATH" | awk '{print $1}' | xargs kill -9 >/dev/null 2>&1 ; \ + ) killall -q -9 v2ray-plugin obfs-local xray-plugin shadow-tls rm -f /var/lock/ssr-monitor.lock if [ "$(uci -q get "dhcp.@dnsmasq[0]._unused_ssrp_changed")" = "1" ]; then @@ -2427,14 +1762,12 @@ stop() { uci -q del "dhcp.@dnsmasq[0]._unused_ssrp_changed" uci -q commit "dhcp" fi - if [ -f "$DNSMASQ_CONF_DIR/dnsmasq-ssrplus.conf" ]; then - rm -rf $DNSMASQ_CONF_DIR/dnsmasq-ssrplus.conf \ - $TMP_DNSMASQ_PATH \ - $TMP_PATH/*-ssr-*.json \ - $TMP_PATH/3proxy* \ - $TMP_PATH/clash-* \ - $TMP_PATH/ssr-server*.json \ - $TMP_PATH/*-config-*.json + if [ -f "$DNSMASQ_CONF_DIR/dnsmasq-ssrplus.conf" ]; then + rm -rf $DNSMASQ_CONF_DIR/dnsmasq-ssrplus.conf \ + $TMP_DNSMASQ_PATH \ + $TMP_PATH/*-ssr-*.json \ + $TMP_PATH/ssr-server*.json \ + $TMP_PATH/*-config-*.json /etc/init.d/dnsmasq restart >/dev/null 2>&1 fi diff --git a/luci-app-ssr-plus/root/etc/ssrplus/netflix.list b/luci-app-ssr-plus/root/etc/ssrplus/netflix.list new file mode 100644 index 00000000..f98f711b --- /dev/null +++ b/luci-app-ssr-plus/root/etc/ssrplus/netflix.list @@ -0,0 +1,25 @@ +amazonaws.com +aws.amazon.com +awsstatic.com +fast.com +netflix.com +netflix.net +nflxext.com +nflximg.net +nflxso.net +nflxvideo.net +netflixdnstest0.com +netflixdnstest1.com +netflixdnstest2.com +netflixdnstest3.com +netflixdnstest4.com +netflixdnstest5.com +netflixdnstest6.com +netflixdnstest7.com +netflixdnstest8.com +netflixdnstest9.com +hulu.com +huluim.com +hbonow.com +hbogo.com +hbo.com diff --git a/luci-app-ssr-plus/root/etc/ssrplus/oversea_list.conf b/luci-app-ssr-plus/root/etc/ssrplus/oversea_list.conf new file mode 100644 index 00000000..ae50fb90 --- /dev/null +++ b/luci-app-ssr-plus/root/etc/ssrplus/oversea_list.conf @@ -0,0 +1,192 @@ +server=/v.youku.com/127.0.0.1#5335 +server=/api.youku.com/127.0.0.1#5335 +server=/v2.tudou.com/127.0.0.1#5335 +server=/www.tudou.com/127.0.0.1#5335 +server=/s.plcloud.music.qq.com/127.0.0.1#5335 +server=/i.y.qq.com/127.0.0.1#5335 +server=/hot.vrs.sohu.com/127.0.0.1#5335 +server=/live.tv.sohu.com/127.0.0.1#5335 +server=/pad.tv.sohu.com/127.0.0.1#5335 +server=/my.tv.sohu.com/127.0.0.1#5335 +server=/hot.vrs.letv.com/127.0.0.1#5335 +server=/data.video.qiyi.com/127.0.0.1#5335 +server=/cache.video.qiyi.com/127.0.0.1#5335 +server=/cache.vip.qiyi.com/127.0.0.1#5335 +server=/vv.video.qq.com/127.0.0.1#5335 +server=/tt.video.qq.com/127.0.0.1#5335 +server=/ice.video.qq.com/127.0.0.1#5335 +server=/tjsa.video.qq.com/127.0.0.1#5335 +server=/a10.video.qq.com/127.0.0.1#5335 +server=/xyy.video.qq.com/127.0.0.1#5335 +server=/vcq.video.qq.com/127.0.0.1#5335 +server=/vsh.video.qq.com/127.0.0.1#5335 +server=/vbj.video.qq.com/127.0.0.1#5335 +server=/bobo.video.qq.com/127.0.0.1#5335 +server=/flvs.video.qq.com/127.0.0.1#5335 +server=/bkvv.video.qq.com/127.0.0.1#5335 +server=/info.zb.qq.com/127.0.0.1#5335 +server=/geo.js.kankan.xunlei.com/127.0.0.1#5335 +server=/web-play.pptv.com/127.0.0.1#5335 +server=/web-play.pplive.cn/127.0.0.1#5335 +server=/dyn.ugc.pps.tv/127.0.0.1#5335 +server=/v.pps.tv/127.0.0.1#5335 +server=/inner.kandian.com/127.0.0.1#5335 +server=/ipservice.163.com/127.0.0.1#5335 +server=/so.open.163.com/127.0.0.1#5335 +server=/zb.s.qq.com/127.0.0.1#5335 +server=/ip.kankan.xunlei.com/127.0.0.1#5335 +server=/vxml.56.com/127.0.0.1#5335 +server=/music.sina.com.cn/127.0.0.1#5335 +server=/play.baidu.com/127.0.0.1#5335 +server=/v.iask.com/127.0.0.1#5335 +server=/tv.weibo.com/127.0.0.1#5335 +server=/wtv.v.iask.com/127.0.0.1#5335 +server=/video.sina.com.cn/127.0.0.1#5335 +server=/www.yinyuetai.com/127.0.0.1#5335 +server=/api.letv.com/127.0.0.1#5335 +server=/live.gslb.letv.com/127.0.0.1#5335 +server=/static.itv.letv.com/127.0.0.1#5335 +server=/ip.apps.cntv.cn/127.0.0.1#5335 +server=/vdn.apps.cntv.cn/127.0.0.1#5335 +server=/vdn.live.cntv.cn/127.0.0.1#5335 +server=/vip.sports.cntv.cn/127.0.0.1#5335 +server=/a.play.api.3g.youku.com/127.0.0.1#5335 +server=/i.play.api.3g.youku.com/127.0.0.1#5335 +server=/api.3g.youku.com/127.0.0.1#5335 +server=/tv.api.3g.youku.com/127.0.0.1#5335 +server=/play.api.3g.youku.com/127.0.0.1#5335 +server=/play.api.3g.tudou.com/127.0.0.1#5335 +server=/tv.api.3g.tudou.com/127.0.0.1#5335 +server=/api.3g.tudou.com/127.0.0.1#5335 +server=/api.tv.sohu.com/127.0.0.1#5335 +server=/access.tv.sohu.com/127.0.0.1#5335 +server=/iface.iqiyi.com/127.0.0.1#5335 +server=/iface2.iqiyi.com/127.0.0.1#5335 +server=/cache.m.iqiyi.com/127.0.0.1#5335 +server=/dynamic.app.m.letv.com/127.0.0.1#5335 +server=/dynamic.meizi.app.m.letv.com/127.0.0.1#5335 +server=/dynamic.search.app.m.letv.com/127.0.0.1#5335 +server=/dynamic.live.app.m.letv.com/127.0.0.1#5335 +server=/listso.m.areainfo.ppstream.com/127.0.0.1#5335 +server=/epg.api.pptv.com/127.0.0.1#5335 +server=/play.api.pptv.com/127.0.0.1#5335 +server=/m.letv.com/127.0.0.1#5335 +server=/interface.bilibili.com/127.0.0.1#5335 +server=/3g.music.qq.com/127.0.0.1#5335 +server=/mqqplayer.3g.qq.com/127.0.0.1#5335 +server=/proxy.music.qq.com/127.0.0.1#5335 +server=/proxymc.qq.com/127.0.0.1#5335 +server=/ip2.kugou.com/127.0.0.1#5335 +server=/ip.kugou.com/127.0.0.1#5335 +server=/client.api.ttpod.com/127.0.0.1#5335 +server=/mobi.kuwo.cn/127.0.0.1#5335 +server=/mobilefeedback.kugou.com/127.0.0.1#5335 +server=/tingapi.ting.baidu.com/127.0.0.1#5335 +server=/music.baidu.com/127.0.0.1#5335 +server=/serviceinfo.sdk.duomi.com/127.0.0.1#5335 +server=/music.163.com/127.0.0.1#5335 +server=/www.xiami.com/127.0.0.1#5335 +server=/spark.api.xiami.com/127.0.0.1#5335 +server=/iplocation.geo.qiyi.com/127.0.0.1#5335 +server=/sns.video.qq.com/127.0.0.1#5335 +server=/v5.pc.duomi.com/127.0.0.1#5335 +server=/tms.is.ysten.com/127.0.0.1#5335 +server=/internal.check.duokanbox.com/127.0.0.1#5335 +server=/openapi.youku.com/127.0.0.1#5335 +server=/y.qq.com/127.0.0.1#5335 +ipset=/v.youku.com/oversea +ipset=/api.youku.com/oversea +ipset=/v2.tudou.com/oversea +ipset=/www.tudou.com/oversea +ipset=/s.plcloud.music.qq.com/oversea +ipset=/i.y.qq.com/oversea +ipset=/hot.vrs.sohu.com/oversea +ipset=/live.tv.sohu.com/oversea +ipset=/pad.tv.sohu.com/oversea +ipset=/my.tv.sohu.com/oversea +ipset=/hot.vrs.letv.com/oversea +ipset=/data.video.qiyi.com/oversea +ipset=/cache.video.qiyi.com/oversea +ipset=/cache.vip.qiyi.com/oversea +ipset=/vv.video.qq.com/oversea +ipset=/tt.video.qq.com/oversea +ipset=/ice.video.qq.com/oversea +ipset=/tjsa.video.qq.com/oversea +ipset=/a10.video.qq.com/oversea +ipset=/xyy.video.qq.com/oversea +ipset=/vcq.video.qq.com/oversea +ipset=/vsh.video.qq.com/oversea +ipset=/vbj.video.qq.com/oversea +ipset=/bobo.video.qq.com/oversea +ipset=/flvs.video.qq.com/oversea +ipset=/bkvv.video.qq.com/oversea +ipset=/info.zb.qq.com/oversea +ipset=/geo.js.kankan.xunlei.com/oversea +ipset=/web-play.pptv.com/oversea +ipset=/web-play.pplive.cn/oversea +ipset=/dyn.ugc.pps.tv/oversea +ipset=/v.pps.tv/oversea +ipset=/inner.kandian.com/oversea +ipset=/ipservice.163.com/oversea +ipset=/so.open.163.com/oversea +ipset=/zb.s.qq.com/oversea +ipset=/ip.kankan.xunlei.com/oversea +ipset=/vxml.56.com/oversea +ipset=/music.sina.com.cn/oversea +ipset=/play.baidu.com/oversea +ipset=/v.iask.com/oversea +ipset=/tv.weibo.com/oversea +ipset=/wtv.v.iask.com/oversea +ipset=/video.sina.com.cn/oversea +ipset=/www.yinyuetai.com/oversea +ipset=/api.letv.com/oversea +ipset=/live.gslb.letv.com/oversea +ipset=/static.itv.letv.com/oversea +ipset=/ip.apps.cntv.cn/oversea +ipset=/vdn.apps.cntv.cn/oversea +ipset=/vdn.live.cntv.cn/oversea +ipset=/vip.sports.cntv.cn/oversea +ipset=/a.play.api.3g.youku.com/oversea +ipset=/i.play.api.3g.youku.com/oversea +ipset=/api.3g.youku.com/oversea +ipset=/tv.api.3g.youku.com/oversea +ipset=/play.api.3g.youku.com/oversea +ipset=/play.api.3g.tudou.com/oversea +ipset=/tv.api.3g.tudou.com/oversea +ipset=/api.3g.tudou.com/oversea +ipset=/api.tv.sohu.com/oversea +ipset=/access.tv.sohu.com/oversea +ipset=/iface.iqiyi.com/oversea +ipset=/iface2.iqiyi.com/oversea +ipset=/cache.m.iqiyi.com/oversea +ipset=/dynamic.app.m.letv.com/oversea +ipset=/dynamic.meizi.app.m.letv.com/oversea +ipset=/dynamic.search.app.m.letv.com/oversea +ipset=/dynamic.live.app.m.letv.com/oversea +ipset=/listso.m.areainfo.ppstream.com/oversea +ipset=/epg.api.pptv.com/oversea +ipset=/play.api.pptv.com/oversea +ipset=/m.letv.com/oversea +ipset=/interface.bilibili.com/oversea +ipset=/3g.music.qq.com/oversea +ipset=/mqqplayer.3g.qq.com/oversea +ipset=/proxy.music.qq.com/oversea +ipset=/proxymc.qq.com/oversea +ipset=/ip2.kugou.com/oversea +ipset=/ip.kugou.com/oversea +ipset=/client.api.ttpod.com/oversea +ipset=/mobi.kuwo.cn/oversea +ipset=/mobilefeedback.kugou.com/oversea +ipset=/tingapi.ting.baidu.com/oversea +ipset=/music.baidu.com/oversea +ipset=/serviceinfo.sdk.duomi.com/oversea +ipset=/music.163.com/oversea +ipset=/www.xiami.com/oversea +ipset=/spark.api.xiami.com/oversea +ipset=/iplocation.geo.qiyi.com/oversea +ipset=/sns.video.qq.com/oversea +ipset=/v5.pc.duomi.com/oversea +ipset=/tms.is.ysten.com/oversea +ipset=/internal.check.duokanbox.com/oversea +ipset=/openapi.youku.com/oversea +ipset=/y.qq.com/oversea diff --git a/luci-app-ssr-plus/root/etc/uci-defaults/luci-ssr-plus b/luci-app-ssr-plus/root/etc/uci-defaults/luci-ssr-plus index caa7d7ae..a8da2f66 100644 --- a/luci-app-ssr-plus/root/etc/uci-defaults/luci-ssr-plus +++ b/luci-app-ssr-plus/root/etc/uci-defaults/luci-ssr-plus @@ -31,8 +31,11 @@ touch /etc/ssrplus/china_ssr.txt touch /etc/ssrplus/deny.list touch /etc/ssrplus/white.list touch /etc/ssrplus/black.list +touch /etc/ssrplus/netflix.list +touch /etc/ssrplus/netflixip.list touch /etc/ssrplus/gfw_base.conf touch /etc/ssrplus/gfw_list.conf +touch /etc/ssrplus/oversea_list.conf touch /etc/ssrplus/ad.conf touch /etc/config/shadowsocksr @@ -47,20 +50,16 @@ if [ -s "/etc/config/shadowsocksr" ]; then uci -q set shadowsocksr.@server_subscribe[0].auto_update_min_time='0' fi - if ! uci -q get shadowsocksr.@server_subscribe[0].config_auto_update_mode > /dev/null; then - uci -q set shadowsocksr.@server_subscribe[0].config_auto_update_mode='0' - fi - - if ! uci -q get shadowsocksr.@server_subscribe[0].config_update_interval > /dev/null; then - uci -q set shadowsocksr.@server_subscribe[0].config_update_interval='60' + if ! uci -q get shadowsocksr.@server_subscribe[0].ss_type > /dev/null; then + uci -q set shadowsocksr.@server_subscribe[0].ss_type='ss-rust' fi if ! uci -q get shadowsocksr.@server_subscribe[0].user_agent > /dev/null; then uci -q set shadowsocksr.@server_subscribe[0].user_agent='v2rayN/9.99' fi - if ! uci -q get shadowsocksr.@server_subscribe[0].proxy > /dev/null; then - uci -q set shadowsocksr.@server_subscribe[0].proxy='1' + if ! uci -q get shadowsocksr.@server_subscribe[0].xray_hy2_type > /dev/null; then + uci -q set shadowsocksr.@server_subscribe[0].xray_hy2_type='hysteria2' fi if ! uci -q get shadowsocksr.@global_xray_fragment[0] > /dev/null; then @@ -69,61 +68,8 @@ if [ -s "/etc/config/shadowsocksr" ]; then uci -q set shadowsocksr.@global_xray_fragment[0].noise='0' fi - if ! uci -q get shadowsocksr.@global[0].component_mirror > /dev/null; then - uci -q set shadowsocksr.@global[0].component_mirror='direct' - fi - - if ! uci -q get shadowsocksr.@global[0].filter_aaaa > /dev/null; then - legacy_filter_aaaa="$(uci -q get shadowsocksr.@global[0].mosdns_ipv6)" - uci -q set shadowsocksr.@global[0].filter_aaaa="${legacy_filter_aaaa:-1}" - fi - - legacy_dns_mode="$(uci -q get shadowsocksr.@global[0].pdnsd_enable)" - if [ "$legacy_dns_mode" = "2" ] || [ "$legacy_dns_mode" = "3" ]; then - uci -q set shadowsocksr.@global[0].pdnsd_enable='1' - fi - - if uci -q get shadowsocksr.@global[0].mosdns_ipv6 > /dev/null; then - uci -q delete shadowsocksr.@global[0].mosdns_ipv6 - fi - - if ! uci -q get shadowsocksr.@http_proxy[0] > /dev/null; then - uci -q add shadowsocksr http_proxy - uci -q set shadowsocksr.@http_proxy[0].server='nil' - uci -q set shadowsocksr.@http_proxy[0].local_port='3128' - uci -q set shadowsocksr.@http_proxy[0].http_auth='none' - fi - - ss_rust_bin="$(command -v ssserver 2>/dev/null)" - [ -n "$ss_rust_bin" ] || [ ! -x /usr/libexec/ssserver ] || ss_rust_bin="/usr/libexec/ssserver" - mihomo_bin="$(command -v mihomo 2>/dev/null)" - [ -n "$mihomo_bin" ] || [ ! -x /usr/libexec/mihomo ] || mihomo_bin="/usr/libexec/mihomo" - xray_bin="$(command -v xray 2>/dev/null)" - [ -n "$xray_bin" ] || [ ! -x /usr/libexec/xray ] || xray_bin="/usr/libexec/xray" - for section in $(uci -q show shadowsocksr | sed -n "s/^shadowsocksr\\.\\([^.=][^.=]*\\)=servers$/\\1/p"); do - node_type="$(uci -q get shadowsocksr.${section}.type)" - case "$node_type" in - ss|ss-libev) - if [ -n "$mihomo_bin" ]; then - uci -q set shadowsocksr.${section}.type='ss' - elif [ -n "$ss_rust_bin" ]; then - uci -q set shadowsocksr.${section}.type='ss-rust' - elif [ -n "$xray_bin" ]; then - uci -q set shadowsocksr.${section}.type='v2ray' - uci -q set shadowsocksr.${section}.v2ray_protocol='shadowsocks' - fi - ;; - v2ray) - if [ "$(uci -q get shadowsocksr.${section}.v2ray_protocol)" = "shadowsocks" ] && [ -n "$mihomo_bin" ]; then - uci -q set shadowsocksr.${section}.type='ss' - uci -q delete shadowsocksr.${section}.v2ray_protocol - fi - ;; - esac - done - - uci -q commit shadowsocksr - fi + uci -q commit shadowsocksr +fi [ -s "/etc/config/shadowsocksr" ] || /etc/init.d/shadowsocksr reset diff --git a/luci-app-ssr-plus/root/usr/bin/ssr-monitor b/luci-app-ssr-plus/root/usr/bin/ssr-monitor index d9732d25..51f9efc4 100755 --- a/luci-app-ssr-plus/root/usr/bin/ssr-monitor +++ b/luci-app-ssr-plus/root/usr/bin/ssr-monitor @@ -10,58 +10,6 @@ LOCK_FILE="/var/lock/ssr-monitor.lock" [ -f "$LOCK_FILE" ] && exit 2 touch "$LOCK_FILE" - -ps_list() { - if busybox ps -w >/dev/null 2>&1; then - busybox ps -w - else - busybox ps - fi -} - -match_proc_count() { - local pattern="$1" - ps_list | grep -E "$pattern" | grep -v grep | wc -l -} - -redir_tcp_running() { - local ssr_count - local ipt_count - ssr_count=$(match_proc_count 'ssr-retcp') - ipt_count=$(ps_list | grep 'ipt2socks' | grep -v grep | grep -E ' -T( |$)| --tcp-only( |$)' | wc -l) - echo $((ssr_count + ipt_count)) -} - -redir_udp_running() { - local ssr_count - local ipt_count - ssr_count=$(match_proc_count 'ssr-reudp') - ipt_count=$(ps_list | grep 'ipt2socks' | grep -v grep | grep -E ' -U( |$)| --udp-only( |$)' | wc -l) - echo $((ssr_count + ipt_count)) -} - -kill_matched_procs() { - local pattern="$1" - ps_list | grep -E "$pattern" | grep -v grep | awk '{print $1}' | xargs kill -9 >/dev/null 2>&1 -} - -get_expected_threads() { - local threads - threads=$(uci_get_by_type global threads 0) - if [ "$threads" = "0" ] || [ -z "$threads" ]; then - threads=$(grep -c '^processor' /proc/cpuinfo 2>/dev/null) - fi - - case "$threads" in - ''|*[!0-9]*) - threads=1 - ;; - esac - - [ "$threads" -lt 1 ] && threads=1 - echo "$threads" -} - server_process_count=$1 redir_tcp_process=$2 redir_udp_process=$3 @@ -73,8 +21,6 @@ if [ -z "$pdnsd_process" ]; then fi i=0 GLOBAL_SERVER=$(uci_get_by_type global global_server) -GLOBAL_TYPE=$(uci_get_by_name $GLOBAL_SERVER type) -EXPECTED_THREADS=$(get_expected_threads) server=$(uci_get_by_name $GLOBAL_SERVER server) kcp_port=$(uci_get_by_name $GLOBAL_SERVER kcp_port) server_port=$(uci_get_by_name $GLOBAL_SERVER server_port) @@ -86,12 +32,8 @@ while [ "1" == "1" ]; do #死循环 sleep 000030s #redir tcp if [ "$redir_tcp_process" -gt 0 ]; then - icount=$(redir_tcp_running) - local tcp_expected="$redir_tcp_process" - if [ "$GLOBAL_TYPE" = "socks5" ]; then - tcp_expected="$EXPECTED_THREADS" - fi - if [ "$icount" -lt "$tcp_expected" ]; then + icount=$(busybox ps -w | grep ssr-retcp | grep -v grep | wc -l) + if [ "$icount" == 0 ]; then logger -t "$NAME" "ssrplus redir tcp error.restart!" echolog "ssrplus redir tcp error.restart!" /etc/init.d/shadowsocksr restart @@ -100,12 +42,8 @@ while [ "1" == "1" ]; do #死循环 fi #redir udp if [ "$redir_udp_process" -gt 0 ]; then - icount=$(redir_udp_running) - local udp_expected="$redir_udp_process" - if [ "$GLOBAL_TYPE" = "socks5" ]; then - udp_expected="$EXPECTED_THREADS" - fi - if [ "$icount" -lt "$udp_expected" ]; then + icount=$(busybox ps -w | grep ssr-reudp | grep -v grep | wc -l) + if [ "$icount" == 0 ]; then logger -t "$NAME" "ssrplus redir udp error.restart!" echolog "ssrplus redir udp error.restart!" /etc/init.d/shadowsocksr restart @@ -114,18 +52,18 @@ while [ "1" == "1" ]; do #死循环 fi #server if [ "$server_process_count" -gt 0 ]; then - icount=$(match_proc_count 'ssr-server|ss-server-|xray-server-') + icount=$(busybox ps -w | grep ssr-server | grep -v grep | wc -l) if [ "$icount" -lt "$server_process_count" ]; then #如果进程挂掉就重启它 logger -t "$NAME" "ssrplus server error.restart!" echolog "ssrplus server error.restart!" - kill_matched_procs 'ssr-server|ss-server-' + kill -9 $(busybox ps -w | grep ssr-server | grep -v grep | awk '{print $1}') >/dev/null 2>&1 /etc/init.d/shadowsocksr restart exit 0 fi fi #kcptun if [ "$kcp_process" -gt 0 ]; then - icount=$(ps_list | grep kcptun-client | grep -v grep | wc -l) + icount=$(busybox ps -w | grep kcptun-client | grep -v grep | wc -l) if [ "$icount" -lt "$kcp_process" ]; then #如果进程挂掉就重启它 logger -t "$NAME" "ssrplus kcptun error.restart!" echolog "ssrplus kcptun error.restart!" @@ -135,43 +73,132 @@ while [ "1" == "1" ]; do #死循环 fi #localsocks if [ "$local_process" -gt 0 ]; then - icount=$(match_proc_count 'ssr-local|ss-local|tuic-local') + icount=$(busybox ps -w | grep ssr-local | grep -v grep | wc -l) if [ "$icount" -lt "$local_process" ]; then #如果进程挂掉就重启它 logger -t "$NAME" "global socks server error.restart!" echolog "global socks server error.restart!" - kill_matched_procs 'ssr-local|ss-local|tuic-local' + kill -9 $(busybox ps -w | grep ssr-local | grep -v grep | awk '{print $1}') >/dev/null 2>&1 /etc/init.d/shadowsocksr restart exit 0 fi fi #dns2tcp if [ "$pdnsd_process" -eq 1 ]; then - icount=$(ps_list | grep $TMP_BIN_PATH/dns2tcp | grep -v grep | wc -l) + icount=$(busybox ps -w | grep $TMP_BIN_PATH/dns2tcp | grep -v grep | wc -l) if [ "$icount" -lt 1 ]; then #如果进程挂掉就重启它 logger -t "$NAME" "dns2tcp tunnel error.restart!" echolog "dns2tcp tunnel error.restart!" dnsserver=$(uci_get_by_type global tunnel_forward 8.8.4.4:53) - kill -9 $(ps_list | grep $TMP_BIN_PATH/dns2tcp | grep -v grep | awk '{print $1}') >/dev/null 2>&1 - start_dns2tcp "$dnsserver" + kill -9 $(busybox ps -w | grep $TMP_BIN_PATH/dns2tcp | grep -v grep | awk '{print $1}') >/dev/null 2>&1 + ln_start_bin $(first_type dns2tcp) dns2tcp -L "127.0.0.1#$dns_port" -R "${dnsserver/:/#}" + fi + #dns2socks + elif [ "$pdnsd_process" -eq 2 ]; then + icount=$(busybox ps -w | grep -e ssrplus-dns -e "dns2socks 127.0.0.1 $tmp_dns_port" | grep -v grep | wc -l) + if [ "$icount" -lt 1 ]; then #如果进程挂掉就重启它 + logger -t "$NAME" "dns2socks $dnsserver tunnel error.restart!" + echolog "dns2socks $dnsserver tunnel error.restart!" + dnsserver=$(uci_get_by_type global tunnel_forward 8.8.4.4:53) + kill -9 $(busybox ps -w | grep ssrplus-dns | grep -v grep | awk '{print $1}') >/dev/null 2>&1 + kill -9 $(busybox ps -w | grep "dns2socks 127.0.0.1 $tmp_dns_port" | grep -v grep | awk '{print $1}') >/dev/null 2>&1 + ln_start_bin $(first_type microsocks) microsocks -i 127.0.0.1 -p $tmp_dns_port ssrplus-dns + ln_start_bin $(first_type dns2socks) dns2socks 127.0.0.1:$tmp_dns_port $dnsserver 127.0.0.1:$dns_port -q + fi + #dns2socks-rust + elif [ "$pdnsd_process" -eq 3 ]; then + icount=$(busybox ps -w | grep -e ssrplus-dns -e "dns2socks-rust -s socks5://127.0.0.1 $tmp_dns_port" | grep -v grep | wc -l) + if [ "$icount" -lt 1 ]; then #如果进程挂掉就重启它 + logger -t "$NAME" "dns2socks-rust $dnsserver tunnel error.restart!" + echolog "dns2socks-rust $dnsserver tunnel error.restart!" + dnsserver=$(uci_get_by_type global tunnel_forward 8.8.4.4:53) + kill -9 $(busybox ps -w | grep ssrplus-dns | grep -v grep | awk '{print $1}') >/dev/null 2>&1 + kill -9 $(busybox ps -w | grep "dns2socks-rust -s socks5://127.0.0.1 $tmp_dns_port" | grep -v grep | awk '{print $1}') >/dev/null 2>&1 + ln_start_bin $(first_type microsocks) microsocks -i 127.0.0.1 -p $tmp_dns_port ssrplus-dns + ln_start_bin $(first_type dns2socks) dns2socks-rust -s socks5://127.0.0.1:$tmp_dns_port -d $dnsserver -l 127.0.0.1:$dns_port -f -c fi #mosdns elif [ "$pdnsd_process" -eq 4 ]; then - icount=$(ps_list | grep $TMP_BIN_PATH/mosdns | grep -v grep | wc -l) + icount=$(busybox ps -w | grep $TMP_BIN_PATH/mosdns | grep -v grep | wc -l) if [ "$icount" -lt 1 ]; then #如果进程挂掉就重启它 logger -t "$NAME" "mosdns tunnel error.restart!" echolog "mosdns tunnel error.restart!" dnsserver=$(uci_get_by_type global tunnel_forward 8.8.4.4:53) - kill -9 $(ps_list | grep $TMP_BIN_PATH/mosdns | grep -v grep | awk '{print $1}') >/dev/null 2>&1 + kill -9 $(busybox ps -w | grep $TMP_BIN_PATH/mosdns | grep -v grep | awk '{print $1}') >/dev/null 2>&1 ln_start_bin $(first_type mosdns) mosdns start -c /etc/mosdns/config.yaml + #dnsproxy + elif [ "$pdnsd_process" -eq 5 ]; then + icount=$(busybox ps -w | grep -e ssrplus-dns -e "dnsproxy -l 127.0.0.1 -p $tmp_dns_port" | grep -v grep | wc -l) + if [ "$icount" -lt 1 ]; then #如果进程挂掉就重启它 + logger -t "$NAME" "dnsproxy $dnsserver tunnel error.restart!" + echolog "dnsproxy $dnsserver tunnel error.restart!" + local dnsproxy_dnsserver="$(uci_get_by_type global parse_method)" + if [ -n "$dnsproxy_dnsserver" ] && [ "$dnsproxy_dnsserver" != "parse_file" ]; then + dnsserver="$(uci_get_by_type global dnsproxy_tunnel_forward 8.8.4.4:53)" + fi + kill -9 $(busybox ps -w | grep "dnsproxy -l 127.0.0.1 -p $tmp_dns_port" | grep -v grep | awk '{print $1}') >/dev/null 2>&1 + dnsproxy_ipv6="$(uci_get_by_type global dnsproxy_ipv6)" + disabled_ipv6="--ipv6-disabled" + fi + if [ "$dnsproxy_dnsserver" != "parse_file" ]; then + ln_start_bin $(first_type dnsproxy) dnsproxy -l 127.0.0.1 -p $tmp_dns_port -p $dns_port -u $dnsserver $disabled_ipv6 --cache --cache-min-ttl=3600 + else + dnsproxy_dnsserver_file="$TMP_PATH/dnsproxy_dns.list" + cleaned_file="$TMP_PATH/cleaned_dns.list" + temp_file="$TMP_PATH/temp_dns.list" + > "$cleaned_file" + # 清理输入文件并去重 + while IFS= read -r line || [ -n "$line" ]; do + line=$(echo "$line" | sed -E 's/^[ \t\r]+//; s/[ \t\r]+$//') + [ -z "$line" ] && continue + echo "$line" | grep -qE '^#' && continue + echo "$line" >> "$cleaned_file" + done < "/etc/ssrplus/dnsproxy_dns.list" + # 获取清理后文件的MD5 + cleaned_md5=$(md5sum "$cleaned_file" | awk '{print $1}') + if [ ! -f "$dnsproxy_dnsserver_file" ]; then + cp "$cleaned_file" "$dnsproxy_dnsserver_file" + else + target_md5=$(md5sum "$dnsproxy_dnsserver_file" | awk '{print $1}') + if [ "$cleaned_md5" != "$target_md5" ]; then + > "$temp_file" + # 保留目标文件中也存在于清理文件的记录(去重) + while IFS= read -r line; do + line=$(echo "$line" | sed -E 's/^[ \t\r]+//; s/[ \t\r]+$//') + if grep -qixF "$line" "$cleaned_file" && ! grep -qixF "$line" "$temp_file"; then + echo "$line" >> "$temp_file" + fi + done < "$dnsproxy_dnsserver_file" + # 添加清理文件中有但目标文件没有的记录(去重) + while IFS= read -r line; do + line=$(echo "$line" | sed -E 's/^[ \t\r]+//; s/[ \t\r]+$//') + if ! grep -qixF "$line" "$temp_file"; then + echo "$line" >> "$temp_file" + fi + done < "$cleaned_file" + temp_md5=$(md5sum "$temp_file" | awk '{print $1}') + if [ "$temp_md5" != "$target_md5" ]; then + mv "$temp_file" "$dnsproxy_dnsserver_file" + else + rm -f "$temp_file" + fi + fi + fi + rm -f "$cleaned_file" + + if [ -n "$dnsproxy_dnsserver_file" ] && [ -s "$dnsproxy_dnsserver_file" ]; then + local upstreams_logic_mode="$(uci_get_by_type global upstreams_logic_mode)" + ln_start_bin $(first_type dnsproxy) dnsproxy -l 127.0.0.1 -p $tmp_dns_port -p $dns_port -u $dnsproxy_dnsserver_file $disabled_ipv6 --cache --cache-min-ttl=3600 --upstream-mode=$upstreams_logic_mode + fi + fi fi #chinadns-ng(proxy) elif [ "$pdnsd_process" -eq 6 ]; then - icount=$(ps_list | grep -e ssrplus-dns -e "chinadns-ng -b 127.0.0.1 -l $tmp_dns_port" | grep -v grep | wc -l) + icount=$(busybox ps -w | grep -e ssrplus-dns -e "chinadns-ng -b 127.0.0.1 -l $tmp_dns_port" | grep -v grep | wc -l) if [ "$icount" -lt 1 ]; then #如果进程挂掉就重启它 logger -t "$NAME" "chinadns-ng $dnsserver tunnel error.restart!" echolog "chinadns-ng $dnsserver tunnel error.restart!" dnsserver=$(uci_get_by_type global chinadns_ng_tunnel_forward 8.8.4.4:53) - kill -9 $(ps_list | grep "chinadns-ng -b 127.0.0.1 -l $tmp_dns_port" | grep -v grep | awk '{print $1}') >/dev/null 2>&1 + kill -9 $(busybox ps -w | grep "chinadns-ng -b 127.0.0.1 -l $tmp_dns_port" | grep -v grep | awk '{print $1}') >/dev/null 2>&1 local chinadns_ng_proto="$(uci_get_by_type global chinadns_ng_proto)" local chinadns_ng_dns="" IFS=',' @@ -197,18 +224,10 @@ while [ "1" == "1" ]; do #死循环 dnsserver="$chinadns_ng_dns" ln_start_bin $(first_type chinadns-ng) chinadns-ng -b 127.0.0.1 -l $tmp_dns_port -l $dns_port -p 3 -d gfw $dnsserver -N --filter-qtype 64,65 -f -r --cache 4096 --cache-stale 86400 --cache-refresh 20 fi - #built-in dns - elif [ "$pdnsd_process" -eq 7 ]; then - if ! is_builtin_dns_active; then - logger -t "$NAME" "builtin dns error.restart!" - echolog "builtin dns error.restart!" - /etc/init.d/shadowsocksr restart - exit 0 - fi fi #chinadns-ng(china) if [ "$(uci -q get "dhcp.@dnsmasq[0]._unused_ssrp_changed")" = "1" ]; then - icount=$(ps_list | grep $TMP_BIN_PATH/chinadns-ng | grep -v grep | wc -l) + icount=$(busybox ps -w | grep $TMP_BIN_PATH/chinadns-ng | grep -v grep | wc -l) if [ "$icount" -lt 1 ]; then #如果进程挂掉就重启它 logger -t "$NAME" "chinadns-ng tunnel error.restart!" echolog "chinadns-ng tunnel error.restart!" @@ -218,7 +237,7 @@ while [ "1" == "1" ]; do #死循环 "wan") chinadns="$wandns" ;; ""|"wan_114") chinadns="$wandns,114.114.114.114" ;; esac - kill -9 $(ps_list | grep $TMP_BIN_PATH/chinadns-ng | grep -v grep | awk '{print $1}') >/dev/null 2>&1 + kill -9 $(busybox ps -w | grep $TMP_BIN_PATH/chinadns-ng | grep -v grep | awk '{print $1}') >/dev/null 2>&1 ln_start_bin $(first_type chinadns-ng) chinadns-ng -l $china_dns_port -4 china -p 3 -c ${chinadns/:/#} -t 127.0.0.1#$dns_port -N -f -r fi fi diff --git a/luci-app-ssr-plus/root/usr/bin/ssr-rules b/luci-app-ssr-plus/root/usr/bin/ssr-rules index de945169..47da8b98 100755 --- a/luci-app-ssr-plus/root/usr/bin/ssr-rules +++ b/luci-app-ssr-plus/root/usr/bin/ssr-rules @@ -85,14 +85,13 @@ usage() { -e extra options for iptables -o apply the rules to the OUTPUT chain -O apply the global rules to the OUTPUT chain - -u enable udprelay mode, TPROXY is required - -U enable udprelay mode, using different IP - and ports for TCP and UDP - -y disable all auxiliary UDP rules when UDP - transparent proxy is unavailable - -f flush the rules + -u enable udprelay mode, TPROXY is required + -U enable udprelay mode, using different IP + and ports for TCP and UDP + -f flush the rules -g gfwlist mode -r router mode + -c oversea mode -z all mode # New persistence management options (use different letters to avoid conflicts) @@ -275,7 +274,7 @@ flush_nftables() { # Optional: force delete all ss_spec related sets (even if table was accidentally deleted) for setname in ss_spec_lan_ac ss_spec_wan_ac ssr_gen_router \ - china fplan bplan gmlan whitelist blacklist gfwlist music; do + china fplan bplan gmlan oversea whitelist blacklist netflix gfwlist music; do $NFT delete set inet ss_spec $setname 2>/dev/null $NFT delete set ip ss_spec_mangle $setname 2>/dev/null done @@ -311,7 +310,7 @@ flush_iptables_legacy() { ip route del local 0.0.0.0/0 dev lo table 999 2>/dev/null fi for setname in ss_spec_lan_ac ss_spec_wan_ac ssr_gen_router \ - china fplan bplan gmlan whitelist blacklist gfwlist music; do + china fplan bplan gmlan oversea whitelist blacklist netflix gfwlist music; do ipset -X $setname 2>/dev/null done [ -n "$FWI" ] && echo '#!/bin/sh' >$FWI @@ -334,7 +333,7 @@ ipset_nft() { fi # Create necessary collections - for setname in china gmlan fplan bplan whitelist blacklist music; do + for setname in china gmlan fplan bplan whitelist blacklist netflix music; do if ! $NFT list set inet ss_spec $setname >/dev/null 2>&1; then $NFT add set inet ss_spec $setname '{ type ipv4_addr; flags interval; auto-merge; }' 2>/dev/null else @@ -393,6 +392,13 @@ ipset_nft() { $NFT add rule inet ss_spec ss_spec_wan_ac meta l4proto tcp ip daddr @music return fi + # Shunt/Netflix rules + if [ -f "$SHUNT_LIST" ]; then + for ip in $(cat "$SHUNT_LIST" 2>/dev/null); do + [ -n "$ip" ] && $NFT add element inet ss_spec netflix "{ $ip }" 2>/dev/null + done + fi + # Set up mode-specific rules case "$RUNMODE" in router) @@ -421,6 +427,14 @@ ipset_nft() { $NFT add rule inet ss_spec ss_spec_wan_ac ip daddr @gfwlist jump ss_spec_wan_fw $NFT add rule inet ss_spec ss_spec_wan_ac ip saddr @gmlan ip daddr != @china jump ss_spec_wan_fw ;; + oversea) + if ! $NFT list set inet ss_spec oversea >/dev/null 2>&1; then + $NFT add set inet ss_spec oversea '{ type ipv4_addr; flags interval; auto-merge; }' 2>/dev/null + fi + $NFT add rule inet ss_spec ss_spec_wan_ac ip daddr @oversea jump ss_spec_wan_fw + $NFT add rule inet ss_spec ss_spec_wan_ac ip saddr @gmlan jump ss_spec_wan_fw + $NFT add rule inet ss_spec ss_spec_wan_ac ip daddr @china jump ss_spec_wan_fw + ;; all) if $NFT list chain inet ss_spec ss_spec_wan_fw >/dev/null 2>&1; then $NFT add rule inet ss_spec ss_spec_wan_ac jump ss_spec_wan_fw @@ -436,10 +450,9 @@ ipset_iptables() { $IPT -N SS_SPEC_WAN_AC 2>/dev/null $IPT -F SS_SPEC_WAN_AC - $IPT -I SS_SPEC_WAN_AC -m mark --mark 255 -j RETURN $IPT -I SS_SPEC_WAN_AC -p tcp --dport 53 -d 127.0.0.0/8 -j RETURN - [ -n "$server" ] && $IPT -I SS_SPEC_WAN_AC -p tcp ! --dport 53 -d "$server" -j RETURN + $IPT -I SS_SPEC_WAN_AC -p tcp ! --dport 53 -d "$server" -j RETURN ipset -N gmlan hash:net 2>/dev/null for ip in $LAN_GM_IP; do ipset -! add gmlan "$ip"; done @@ -461,6 +474,12 @@ ipset_iptables() { $IPT -A SS_SPEC_WAN_AC -m set --match-set gfwlist dst -j SS_SPEC_WAN_FW $IPT -A SS_SPEC_WAN_AC -m set --match-set gmlan src -m set ! --match-set china dst -j SS_SPEC_WAN_FW ;; + oversea) + ipset -N oversea hash:net 2>/dev/null + $IPT -I SS_SPEC_WAN_AC -m set --match-set oversea dst -j SS_SPEC_WAN_FW + $IPT -A SS_SPEC_WAN_AC -m set --match-set gmlan src -j SS_SPEC_WAN_FW + $IPT -A SS_SPEC_WAN_AC -m set --match-set china dst -j SS_SPEC_WAN_FW + ;; all) $IPT -A SS_SPEC_WAN_AC -j SS_SPEC_WAN_FW ;; @@ -491,6 +510,25 @@ ipset_iptables() { for ip in $WAN_BP_IP; do ipset -! add whitelist "$ip"; done for ip in $WAN_FW_IP; do ipset -! add blacklist "$ip"; done + + if [ "$SHUNT_PORT" != "0" ]; then + ipset -N netflix hash:net 2>/dev/null + for ip in $(cat "${SHUNT_LIST:=/dev/null}" 2>/dev/null); do ipset -! add netflix "$ip"; done + case "$SHUNT_PORT" in + 0) ;; + 1) + $IPT -I SS_SPEC_WAN_AC -p tcp -m set --match-set netflix dst -j REDIRECT --to-ports "$local_port" + ;; + *) + $IPT -I SS_SPEC_WAN_AC -p tcp -m set --match-set netflix dst -j REDIRECT --to-ports "$SHUNT_PORT" + if [ "$SHUNT_PROXY" = "1" ]; then + $IPT -I SS_SPEC_WAN_AC -p tcp -d "$SHUNT_IP" -j REDIRECT --to-ports "$local_port" + else + ipset -! add whitelist "$SHUNT_IP" + fi + ;; + esac + fi return $? } @@ -524,6 +562,22 @@ fw_rule_nft() { fi fi + if [ "$SHUNT_PORT" != "0" ] && [ -f "$SHUNT_LIST" ]; then + case "$SHUNT_PORT" in + 1) + $NFT add rule inet ss_spec ss_spec_wan_ac $TCP_EXT_ARGS ip daddr @netflix counter redirect to :$local_port + ;; + *) + $NFT add rule inet ss_spec ss_spec_wan_ac $TCP_EXT_ARGS ip daddr @netflix counter redirect to :$SHUNT_PORT + if [ "$SHUNT_PROXY" = "1" ]; then + $NFT add rule inet ss_spec ss_spec_wan_ac $TCP_EXT_ARGS ip daddr $SHUNT_IP counter redirect to :$local_port + else + [ -n "$SHUNT_IP" ] && $NFT add element inet ss_spec whitelist "{ $SHUNT_IP }" 2>/dev/null + fi + ;; + esac + fi + return $? } @@ -616,7 +670,7 @@ ac_rule_nft() { fi # Block UDP port 443 when TPROXY not Enable - if [ -z "$TPROXY" ] && [ "$DISABLE_UDP_RULES" != "1" ]; then + if [ -z "$TPROXY" ]; then # Add UDP 443 block rule if [ -z "$Interface" ]; then if [ -n "$MATCH_SET" ]; then @@ -663,11 +717,10 @@ ac_rule_nft() { case "$OUTPUT" in 1) # Create ss_spec_output tcp chain - if ! $NFT list chain inet ss_spec ss_spec_output >/dev/null 2>&1; then - $NFT add chain inet ss_spec ss_spec_output '{ type nat hook output priority 0; policy accept; }' - fi - $NFT flush chain inet ss_spec ss_spec_output 2>/dev/null - $NFT add rule inet ss_spec ss_spec_output meta mark 255 return 2>/dev/null + if ! $NFT list chain inet ss_spec ss_spec_output >/dev/null 2>&1; then + $NFT add chain inet ss_spec ss_spec_output '{ type nat hook output priority 0; policy accept; }' + fi + $NFT flush chain inet ss_spec ss_spec_output 2>/dev/null # Exclude special local addresses if $NFT list chain inet ss_spec ss_spec_output >/dev/null 2>&1; then @@ -688,11 +741,10 @@ ac_rule_nft() { ;; 2) # Create ss_spec_output tcp chain - if ! $NFT list chain inet ss_spec ss_spec_output >/dev/null 2>&1; then - $NFT add chain inet ss_spec ss_spec_output '{ type nat hook output priority 0; policy accept; }' - fi - $NFT flush chain inet ss_spec ss_spec_output 2>/dev/null - $NFT add rule inet ss_spec ss_spec_output meta mark 255 return 2>/dev/null + if ! $NFT list chain inet ss_spec ss_spec_output >/dev/null 2>&1; then + $NFT add chain inet ss_spec ss_spec_output '{ type nat hook output priority 0; policy accept; }' + fi + $NFT flush chain inet ss_spec ss_spec_output 2>/dev/null # Exclude special local addresses if $NFT list chain inet ss_spec ss_spec_output >/dev/null 2>&1; then @@ -706,12 +758,11 @@ ac_rule_nft() { for ip in $(gen_spec_iplist); do [ -n "$ip" ] && $NFT add element inet ss_spec ssr_gen_router "{ $ip }" 2>/dev/null done - if ! $NFT list chain inet ss_spec ss_spec_router >/dev/null 2>&1; then - $NFT add chain inet ss_spec ss_spec_router 2>/dev/null - fi - $NFT flush chain inet ss_spec ss_spec_router 2>/dev/null - $NFT add rule inet ss_spec ss_spec_router meta mark 255 return 2>/dev/null - $NFT add rule inet ss_spec ss_spec_router ip daddr @ssr_gen_router return 2>/dev/null + if ! $NFT list chain inet ss_spec ss_spec_router >/dev/null 2>&1; then + $NFT add chain inet ss_spec ss_spec_router 2>/dev/null + fi + $NFT flush chain inet ss_spec ss_spec_router 2>/dev/null + $NFT add rule inet ss_spec ss_spec_router ip daddr @ssr_gen_router return 2>/dev/null $NFT add rule inet ss_spec ss_spec_router jump ss_spec_wan_fw 2>/dev/null $NFT add rule inet ss_spec ss_spec_output $TCP_EXT_ARGS jump ss_spec_router comment "\"$TAG\"" 2>/dev/null ;; @@ -741,7 +792,7 @@ ac_rule_iptables() { EOF # Block UDP port 443 when TPROXY not Enable - if [ -z "$TPROXY" ] && [ "$DISABLE_UDP_RULES" != "1" ]; then + if [ -z "$TPROXY" ]; then # Add UDP 443 block rule if [ -z "$Interface" ]; then # Global rules @@ -794,11 +845,10 @@ ac_rule_iptables() { create ssr_gen_router hash:net $(gen_spec_iplist | sed -e "s/^/add ssr_gen_router /") EOF - $IPT -N SS_SPEC_ROUTER 2>/dev/null - $IPT -F SS_SPEC_ROUTER 2>/dev/null - $IPT -A SS_SPEC_ROUTER -m mark --mark 255 -j RETURN && \ - $IPT -A SS_SPEC_ROUTER -m set --match-set ssr_gen_router dst -j RETURN && \ - $IPT -A SS_SPEC_ROUTER -j SS_SPEC_WAN_FW + $IPT -N SS_SPEC_ROUTER 2>/dev/null + $IPT -F SS_SPEC_ROUTER 2>/dev/null + $IPT -A SS_SPEC_ROUTER -m set --match-set ssr_gen_router dst -j RETURN && \ + $IPT -A SS_SPEC_ROUTER -j SS_SPEC_WAN_FW $IPT -I OUTPUT 1 -p tcp -m comment --comment "$TAG" -j SS_SPEC_ROUTER ;; esac @@ -956,6 +1006,14 @@ tp_rule_nft() { $NFT add rule ip ss_spec_mangle ss_spec_tproxy meta l4proto udp $EXT_ARGS ip daddr @gfwlist counter tproxy ip to :"$LOCAL_PORT" meta mark set ${FWMARK} 2>/dev/null $NFT add rule ip ss_spec_mangle ss_spec_tproxy meta l4proto udp ip saddr @gmlan ip daddr != @china counter tproxy ip to :"$LOCAL_PORT" meta mark set ${FWMARK} 2>/dev/null ;; + oversea) + if ! $NFT list set ip ss_spec_mangle oversea >/dev/null 2>&1; then + $NFT add set ip ss_spec_mangle oversea '{ type ipv4_addr; flags interval; auto-merge; }' 2>/dev/null + fi + $NFT add rule ip ss_spec_mangle ss_spec_tproxy meta l4proto udp $EXT_ARGS ip saddr @oversea counter tproxy ip to :"$LOCAL_PORT" meta mark set ${FWMARK} 2>/dev/null + $NFT add rule ip ss_spec_mangle ss_spec_tproxy meta l4proto udp $EXT_ARGS ip daddr @china counter tproxy ip to :"$LOCAL_PORT" meta mark set ${FWMARK} 2>/dev/null + $NFT add rule ip ss_spec_mangle ss_spec_tproxy meta l4proto udp ip saddr @gmlan counter tproxy ip to :"$LOCAL_PORT" meta mark set ${FWMARK} 2>/dev/null + ;; all) $NFT add rule ip ss_spec_mangle ss_spec_tproxy meta l4proto udp $EXT_ARGS counter tproxy ip to :"$LOCAL_PORT" meta mark set ${FWMARK} 2>/dev/null ;; @@ -1032,8 +1090,8 @@ tp_rule_iptables() { do $ipt -A SS_SPEC_TPROXY -p udp -d "$net" -j RETURN done - [ -n "$SERVER" ] && $ipt -A SS_SPEC_TPROXY -p udp ! --dport 53 -d "$SERVER" -j RETURN - [ -n "$SERVER" ] && [ "$server" != "$SERVER" ] && ipset -! add whitelist "$SERVER" + $ipt -A SS_SPEC_TPROXY -p udp ! --dport 53 -d "$SERVER" -j RETURN + [ "$server" != "$SERVER" ] && ipset -! add whitelist "$SERVER" if [ -f "${xhttp_ip:=/etc/ssrplus/xhttp_address.txt}" ]; then while IFS= read -r ip; do [ -n "$ip" ] && ipset add whitelist "$ip" -exist @@ -1061,6 +1119,11 @@ tp_rule_iptables() { $ipt -A SS_SPEC_TPROXY -p udp $PROXY_PORTS -m set --match-set gfwlist dst -j TPROXY --on-port "$LOCAL_PORT" --tproxy-mark ${FWMARK} $ipt -A SS_SPEC_TPROXY -p udp -m set --match-set gmlan src -m set ! --match-set china dst -j TPROXY --on-port "$LOCAL_PORT" --tproxy-mark ${FWMARK} ;; + oversea) + $ipt -A SS_SPEC_TPROXY -p udp $PROXY_PORTS -m set --match-set oversea src -m dst -j TPROXY --on-port "$LOCAL_PORT" --tproxy-mark ${FWMARK} + $ipt -A SS_SPEC_TPROXY -p udp -m set --match-set gmlan src -m set -j TPROXY --on-port "$LOCAL_PORT" --tproxy-mark ${FWMARK} + $ipt -A SS_SPEC_TPROXY -p udp $PROXY_PORTS -m set --match-set china dst -j TPROXY --on-port "$LOCAL_PORT" --tproxy-mark ${FWMARK} + ;; all) $ipt -A SS_SPEC_TPROXY -p udp $PROXY_PORTS -j TPROXY --on-port "$LOCAL_PORT" --tproxy-mark ${FWMARK} ;; @@ -1432,7 +1495,7 @@ restore_from_persistence() { fi } -while getopts ":m:s:l:S:L:i:e:a:B:b:w:p:G:D:F:N:M:I:oOuUyfgrzAKPCRXh" arg; do +while getopts ":m:s:l:S:L:i:e:a:B:b:w:p:G:D:F:N:M:I:oOuUfgrczAKPCRXh" arg; do case "$arg" in m) Interface=$OPTARG @@ -1500,15 +1563,15 @@ while getopts ":m:s:l:S:L:i:e:a:B:b:w:p:G:D:F:N:M:I:oOuUyfgrzAKPCRXh" arg; do U) TPROXY=2 ;; - y) - DISABLE_UDP_RULES=1 - ;; g) RUNMODE=gfw ;; r) RUNMODE=router ;; + c) + RUNMODE=oversea + ;; z) RUNMODE=all ;; @@ -1640,7 +1703,7 @@ runmode_change() { } # Main process -if [ -n "$local_port" ]; then +if [ -n "$server" ] && [ -n "$local_port" ]; then if ! echo "$local_port" | grep -qE '^[0-9]+$'; then loger 3 "Invalid local port: $local_port" exit 1 @@ -1652,6 +1715,7 @@ if [ -n "$local_port" ]; then LOCAL_PORT=$local_port ;; 2) + : ${SERVER:?"You must assign an ip for the udp relay server."} : ${LOCAL_PORT:?"You must assign a port for the udp relay server."} ;; esac diff --git a/luci-app-ssr-plus/root/usr/bin/ssr-switch b/luci-app-ssr-plus/root/usr/bin/ssr-switch index 3aab3190..5a2a3709 100755 --- a/luci-app-ssr-plus/root/usr/bin/ssr-switch +++ b/luci-app-ssr-plus/root/usr/bin/ssr-switch @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh /etc/rc.common # # Copyright (C) 2017 openwrt-ssr # Copyright (C) 2017 yushi studio @@ -7,276 +7,149 @@ # See /LICENSE for more information. # -ORIG_ARG1="${1:-}" -ORIG_ARG2="${2:-}" -ORIG_ARG3="${3:-}" -[ -f /lib/functions.sh ] && . /lib/functions.sh . $IPKG_INSTROOT/etc/init.d/shadowsocksr LOCK_FILE="/var/lock/ssr-switch.lock" -PROBE_SID="" +[ -f "$LOCK_FILE" ] && exit 2 +touch "$LOCK_FILE" +LOG_FILE=/var/log/ssrplus.log cycle_time=60 switch_time=3 -probe_socks_port=10800 -direct_fail_count=0 -direct_fail_limit=3 -probe_url="$(uci_get_by_type server_subscribe url_test_url)" -[ -n "$probe_url" ] || probe_url="https://www.google.com/generate_204" -PROBE_INSTANCE_KEY="ssr-switch-probe-local" +normal_flag=0 +server_locate=0 +server_count=0 +ENABLE_SERVER=nil +[ -n "$1" ] && cycle_time=$1 +[ -n "$2" ] && switch_time=$2 +DEFAULT_SERVER=$(uci_get_by_type global global_server) +CURRENT_SERVER=$DEFAULT_SERVER -DEFAULT_SERVER="$(uci_get_by_type global global_server)" -CURRENT_SERVER="$DEFAULT_SERVER" -ENABLE_SERVER="nil" - -cleanup_probe_socks() { - ps_list | grep -v "grep" | grep -E "tcp-http-ssr-switch-local\\.json|ss-${PROBE_INSTANCE_KEY}/config\\.yaml|tuic-${PROBE_INSTANCE_KEY}/config\\.yaml" | awk '{print $1}' | xargs kill >/dev/null 2>&1 - sleep 1 - ps_list | grep -v "grep" | grep -E "tcp-http-ssr-switch-local\\.json|ss-${PROBE_INSTANCE_KEY}/config\\.yaml|tuic-${PROBE_INSTANCE_KEY}/config\\.yaml" | awk '{print $1}' | xargs kill -9 >/dev/null 2>&1 - rm -f "$TMP_PATH/tcp-http-ssr-switch-local.json" 2>/dev/null - rm -rf "$TMP_PATH/ss-${PROBE_INSTANCE_KEY}" "$TMP_PATH/tuic-${PROBE_INSTANCE_KEY}" 2>/dev/null - rm -f /tmp/ssr-switch-probe.log 2>/dev/null -} - -start_probe_socks() { - local sid="$1" - local server_type - - server_type="$(uci_get_by_name "$sid" type)" - [ "$server_type" = "clash" ] && return 1 - [ "$server_type" = "tuic" ] && return 1 - [ "$server_type" = "socks5" ] && return 1 - - cleanup_probe_socks - LOCAL_SERVER="$sid" - local_config_file="$TMP_PATH/tcp-http-ssr-switch-local.json" - _local="2" - local_enable=0 - tmp_local_port= - mode="tcp,udp" - - if [ "$server_type" = "v2ray" ]; then - export SSR_SWITCH_PROBE=1 - gen_config_file "$LOCAL_SERVER" "$server_type" 4 0 "$probe_socks_port" >/tmp/ssr-switch-probe.log 2>&1 || return 1 - unset SSR_SWITCH_PROBE - local xray_bin - xray_bin="$(first_type xray)" - [ -x "$xray_bin" ] || return 1 - "$xray_bin" run -c "$local_config_file" >>/tmp/ssr-switch-probe.log 2>&1 & - else - export SSR_SWITCH_PROBE=1 - export SSR_SWITCH_PROBE_INSTANCE_KEY="$PROBE_INSTANCE_KEY" - start_local_with_port "$probe_socks_port" >/tmp/ssr-switch-probe.log 2>&1 || return 1 - unset SSR_SWITCH_PROBE_INSTANCE_KEY - unset SSR_SWITCH_PROBE - fi - - sleep 2 - return 0 -} - -probe_http_ok() { - case "$1" in - [1-5][0-9][0-9]) - return 0 - ;; - esac - return 1 -} - -check_direct_probe() { - local code - - code="$(curl -k -sS -L -o /dev/null \ - --connect-timeout "$switch_time" \ - --max-time "$switch_time" \ - -w '%{http_code}' \ - "$probe_url" 2>/dev/null || true)" - probe_http_ok "$code" -} - -check_proxy_via_socks() { - local try_count - local code - local proxy_host - - try_count="$(uci_get_by_type global switch_try_count 3)" - for i in $(seq 1 "$try_count"); do - for proxy_host in "127.0.0.1:$probe_socks_port" "[::1]:$probe_socks_port"; do - code="$(curl -k -sS -L -o /dev/null \ - --connect-timeout "$switch_time" \ - --max-time "$switch_time" \ - --socks5-hostname "$proxy_host" \ - -w '%{http_code}' \ - "$probe_url" 2>/dev/null || true)" - probe_http_ok "$code" && return 0 - done +#判断代理是否正常 +check_proxy() { + local result=0 + local try_count=$(uci_get_by_type global switch_try_count 3) + for i in $(seq 1 $try_count); do + /usr/bin/ssr-check www.google.com 80 $switch_time 1 + if [ "$?" == "0" ]; then + # echolog "Check Google Proxy Success, count=$i" + result=0 + break + else + # echolog "Check Google Proxy Fail, count=$i" + /usr/bin/ssr-check www.baidu.com 80 $switch_time 1 + if [ "$?" == "0" ]; then + result=1 + else + result=2 + fi + fi sleep 1 done - return 1 + return $result } test_proxy() { - local sid="$1" - [ "$(uci_get_by_name "$sid" type)" = "clash" ] && return 1 - [ "$(uci_get_by_name "$sid" type)" = "tuic" ] && return 1 - start_probe_socks "$sid" || { - cleanup_probe_socks + local servername=$(uci_get_by_name $1 server) + local serverport=$(uci_get_by_name $1 server_port) + ipset add whitelist $servername 2>/dev/null + tcping -q -c 3 -i 1 -t 2 -p $serverport $servername + if [ "$?" -gt "0" ]; then + ipset del whitelist $servername 2>/dev/null return 1 - } - check_proxy_via_socks + fi + /usr/bin/ssr-check $servername $serverport $switch_time local ret=$? - cleanup_probe_socks - return $ret + ipset del whitelist $servername 2>/dev/null + if [ "$ret" == "0" ]; then + return 0 + else + return 1 + fi } search_proxy() { - local sid="$1" - [ "$(uci_get_by_name "$sid" switch_enable 0)" = "1" ] || return 1 - [ "$(uci_get_by_name "$sid" type)" = "clash" ] && return 1 - [ "$(uci_get_by_name "$sid" type)" = "tuic" ] && return 1 - [ "$sid" = "$CURRENT_SERVER" ] && return 1 - [ "$ENABLE_SERVER" != "nil" ] && return 0 - - if test_proxy "$sid"; then - ENABLE_SERVER="$sid" + let server_count=server_count+1 + [ "$normal_flag" == "1" -a "$server_count" -le "$server_locate" ] && return 0 + [ "$(uci_get_by_name $1 switch_enable 0)" != "1" ] && return 1 + [ $ENABLE_SERVER != nil ] && return 0 + [ "$1" == "$CURRENT_SERVER" ] && return 0 + local servername=$(uci_get_by_name $1 server) + local serverport=$(uci_get_by_name $1 server_port) + ipset add whitelist $servername 2>/dev/null + /usr/bin/ssr-check $servername $serverport $switch_time + local ret=$? + ipset del whitelist $servername 2>/dev/null + if [ "$ret" == "0" ]; then + server_locate=$server_count + ENABLE_SERVER=$1 return 0 + else + return 1 fi - return 1 } +#选择可用的代理 select_proxy() { - config_load "$NAME" - ENABLE_SERVER="nil" + config_load $NAME + ENABLE_SERVER=nil + mkdir -p /var/run /var/etc + server_count=0 config_foreach search_proxy servers } -set_main_server() { - local sid="$1" - [ -n "$sid" ] || return 1 - uci set shadowsocksr.@global[0].global_server="$sid" - uci commit shadowsocksr - return 0 -} - +#切换代理 switch_proxy() { - set_main_server "$1" || return 1 - /etc/init.d/shadowsocksr restart "$1" + /etc/init.d/shadowsocksr restart $1 return 0 } start() { - while [ "1" = "1" ]; do - sleep "0000$cycle_time" - run_once + #不支持kcptun启用时的切换 + [ $(uci_get_by_name $DEFAULT_SERVER kcp_enable) = "1" ] && return 1 + while [ "1" == "1" ]; do #死循环 + sleep 0000$cycle_time + LOGTIME=$(date "+%Y-%m-%d %H:%M:%S") + #判断当前代理是否为缺省服务器 + if [ "$CURRENT_SERVER" != "$DEFAULT_SERVER" ]; then + #echo "not default proxy" + echolog "Current server is not default Main server, try to switch back." + #检查缺省服务器是否正常 + if test_proxy $DEFAULT_SERVER; then + #echo "switch to default proxy" + echolog "Main server is avilable." + #缺省服务器正常,切换回来 + CURRENT_SERVER=$DEFAULT_SERVER + switch_proxy $CURRENT_SERVER + echolog "switch to default "$(uci_get_by_name $CURRENT_SERVER alias)" proxy!" + else + echolog "Main server is NOT avilable.Continue using current server." + fi + fi + #判断当前代理是否正常 + #echolog "Start checking if the current server is available." + check_proxy + current_ret=$? + if [ "$current_ret" == "1" ]; then + #当前代理错误,判断有无可用的服务器 + #echo "current error" + echolog "Current server error, try to switch another server." + select_proxy + if [ "$ENABLE_SERVER" != nil ]; then + #有其他服务器可用,进行切换 + #echo $(uci_get_by_name $new_proxy server) + echolog "Another server is avilable, now switching server." + CURRENT_SERVER=$ENABLE_SERVER + switch_proxy $CURRENT_SERVER + normal_flag=1 + echolog "Switch to "$(uci_get_by_name $CURRENT_SERVER alias)" proxy!" + else + switch_proxy $CURRENT_SERVER + normal_flag=1 + echolog "Try restart current server." + fi + else + normal_flag=0 + # echolog "ShadowsocksR No Problem." + fi done } - -run_once() { - DEFAULT_SERVER="$(uci_get_by_type global global_server)" - [ "$DEFAULT_SERVER" = "nil" ] && { - direct_fail_count=0 - return 0 - } - [ "$(uci_get_by_name "$DEFAULT_SERVER" type)" = "clash" ] && { - direct_fail_count=0 - cleanup_probe_socks - return 0 - } - [ "$(uci_get_by_name "$DEFAULT_SERVER" type)" = "tuic" ] && { - direct_fail_count=0 - cleanup_probe_socks - return 0 - } - [ "$(uci_get_by_name "$DEFAULT_SERVER" kcp_enable 0)" = "1" ] && { - direct_fail_count=0 - cleanup_probe_socks - return 1 - } - - CURRENT_SERVER="$DEFAULT_SERVER" - - if check_direct_probe; then - direct_fail_count=0 - return 0 - fi - - direct_fail_count=$((direct_fail_count + 1)) - [ "$direct_fail_count" -lt "$direct_fail_limit" ] && return 0 - direct_fail_count=0 - - if test_proxy "$CURRENT_SERVER"; then - return 0 - fi - - echolog "Current server error, try to switch another server." - select_proxy - if [ "$ENABLE_SERVER" != "nil" ]; then - CURRENT_SERVER="$ENABLE_SERVER" - switch_proxy "$CURRENT_SERVER" - echolog "Switch to $(uci_get_by_name "$CURRENT_SERVER" alias) proxy!" - else - switch_proxy "$CURRENT_SERVER" - echolog "Try restart current server." - fi - return 0 -} - -probe_once() { - local sid="$1" - [ -n "$sid" ] || { - echo "missing_sid" - return 1 - } - cleanup_probe_socks - if ! start_probe_socks "$sid"; then - echo "probe_start:fail" - return 1 - fi - echo "probe_start:ok" - echo "probe:curl_ipv4" - curl -k -sS -L -o /dev/null \ - --connect-timeout "$switch_time" \ - --max-time "$switch_time" \ - --socks5-hostname "127.0.0.1:$probe_socks_port" \ - -w 'code=%{http_code}\n' \ - "$probe_url" 2>/dev/null || true - echo "probe:curl_ipv6" - curl -g -k -sS -L -o /dev/null \ - --connect-timeout "$switch_time" \ - --max-time "$switch_time" \ - --socks5-hostname "[::1]:$probe_socks_port" \ - -w 'code=%{http_code}\n' \ - "$probe_url" 2>/dev/null || true - cleanup_probe_socks - return 0 -} - -main() { - case "${ORIG_ARG1:-}" in - probe) - PROBE_SID="${ORIG_ARG2:-}" - probe_once "$PROBE_SID" - ;; - once) - run_once - ;; - start) - [ -n "$ORIG_ARG2" ] && cycle_time="$ORIG_ARG2" - [ -n "$ORIG_ARG3" ] && switch_time="$ORIG_ARG3" - [ -f "$LOCK_FILE" ] && exit 2 - touch "$LOCK_FILE" - start - ;; - *) - [ -n "$ORIG_ARG1" ] && cycle_time="$ORIG_ARG1" - [ -n "$ORIG_ARG2" ] && switch_time="$ORIG_ARG2" - [ -f "$LOCK_FILE" ] && exit 2 - touch "$LOCK_FILE" - start - ;; - esac -} - -if [ "${0##*/}" = "ssr-switch" ]; then - main "$@" -fi diff --git a/luci-app-ssr-plus/root/usr/share/shadowsocksr/Country.mmdb b/luci-app-ssr-plus/root/usr/share/shadowsocksr/Country.mmdb deleted file mode 100644 index 6898cab5..00000000 Binary files a/luci-app-ssr-plus/root/usr/share/shadowsocksr/Country.mmdb and /dev/null differ diff --git a/luci-app-ssr-plus/root/usr/share/shadowsocksr/clash_yaml.lua b/luci-app-ssr-plus/root/usr/share/shadowsocksr/clash_yaml.lua deleted file mode 100644 index 701bfacc..00000000 --- a/luci-app-ssr-plus/root/usr/share/shadowsocksr/clash_yaml.lua +++ /dev/null @@ -1,939 +0,0 @@ -#!/usr/bin/lua - -require "nixio.fs" -require "luci.model.uci" - -local ok_lyaml, lyaml = pcall(require, "lyaml") -if not ok_lyaml then - io.stderr:write("lyaml_not_found\n") - os.exit(2) -end - -local uci = require "luci.model.uci".cursor() -local ok_jsonc, jsonc = pcall(require, "luci.jsonc") - -local function read_file(path) - local data = nixio.fs.readfile(path) - if not data or data == "" then - return nil - end - return data -end - -local function write_file(path, data) - return nixio.fs.writefile(path, data) -end - -local function load_yaml(path) - local raw = read_file(path) - if not raw then - return nil, "read_failed" - end - - local ok, parsed = pcall(lyaml.load, raw) - if not ok or type(parsed) ~= "table" then - return nil, "parse_failed" - end - - return parsed -end - -local function dump_yaml(path, data) - local ok, rendered = pcall(lyaml.dump, { data }) - if not ok or not rendered then - return nil, "dump_failed" - end - - write_file(path, rendered) - return true -end - -local function split_filter_words(text) - local items = {} - for part in tostring(text or ""):gmatch("[^/]+") do - if part ~= "" then - items[#items + 1] = part - end - end - return items -end - -local function trim(value) - return tostring(value or ""):gsub("^%s+", ""):gsub("%s+$", "") -end - -local function parse_csv_line(line) - local cols = {} - local cur = "" - local in_quote = false - local i = 1 - - while i <= #line do - local ch = line:sub(i, i) - if ch == '"' then - if in_quote and line:sub(i + 1, i + 1) == '"' then - cur = cur .. '"' - i = i + 1 - else - in_quote = not in_quote - end - elseif ch == "," and not in_quote then - cols[#cols + 1] = cur - cur = "" - else - cur = cur .. ch - end - i = i + 1 - end - - cols[#cols + 1] = cur - return cols -end - -local function read_clash_client_rules_csv(sid) - local rows = {} - sid = trim(sid) - if sid == "" then - return rows - end - - local csv_path = string.format("/etc/ssrplus/clash/%s.csv", sid) - local raw = read_file(csv_path) - if not raw or raw == "" then - return rows - end - - local first = true - for line in tostring(raw):gsub("\r", ""):gmatch("[^\n]+") do - local text = trim(line) - if text ~= "" then - if first and text:lower() == "enabled,client,policy,remarks,client_mac" then - first = false - else - local cols = parse_csv_line(line) - if #cols >= 4 then - rows[#rows + 1] = { - enabled = cols[1], - ip_addr = trim(cols[2] or ""), - policy_group = trim(cols[3] or ""), - remarks = trim(cols[4] or ""), - client_mac = trim(cols[5] or "") - } - end - end - end - end - - return rows -end - -local function has_proxy_sections(doc) - return type(doc.proxies) == "table" or type(doc["proxy-providers"]) == "table" -end - -local function validate(path) - local doc = load_yaml(path) - if not doc then - return false - end - return has_proxy_sections(doc) -end - -local function filter(path, filter_words) - local doc, err = load_yaml(path) - if not doc then - io.stderr:write(err or "parse_failed", "\n") - return false - end - - local words = split_filter_words(filter_words) - if #words == 0 then - return true - end - - local removed = {} - local proxies = {} - for _, proxy in ipairs(doc.proxies or {}) do - local name = tostring(proxy.name or "") - local matched = false - for _, word in ipairs(words) do - if name:find(word, 1, true) then - matched = true - removed[name] = true - break - end - end - if not matched then - proxies[#proxies + 1] = proxy - end - end - doc.proxies = proxies - - for _, group in ipairs(doc["proxy-groups"] or {}) do - if type(group.proxies) == "table" then - local kept = {} - for _, name in ipairs(group.proxies) do - if not removed[tostring(name)] then - kept[#kept + 1] = name - end - end - group.proxies = kept - end - end - - local count = 0 - for _ in pairs(removed) do - count = count + 1 - end - - dump_yaml(path, doc) - io.stdout:write(tostring(count), "\n") - return true -end - -local function deep_merge(dst, src) - if type(dst) ~= "table" or type(src) ~= "table" then - return src - end - - for k, v in pairs(src) do - if type(v) == "table" and type(dst[k]) == "table" then - dst[k] = deep_merge(dst[k], v) - else - dst[k] = v - end - end - - return dst -end - -local function strip_runtime_conflicts(doc) - doc.tun = nil - doc.listeners = nil - doc["redir-port"] = nil - doc["tproxy-port"] = nil - doc["socks-port"] = nil - doc["mixed-port"] = nil - doc.port = nil - doc["external-controller"] = nil - doc.secret = nil - doc["allow-lan"] = nil - if type(doc.dns) == "table" then - doc.dns["fake-ip-range"] = nil - doc.dns["fake-ip-filter"] = nil - end -end - -local function group_requires_candidates(group) - local gtype = tostring(group and group.type or ""):lower() - return gtype == "select" - or gtype == "fallback" - or gtype == "load-balance" - or gtype == "url-test" - or gtype == "relay" -end - -local function has_nonempty_sequence(value) - return type(value) == "table" and next(value) ~= nil -end - -local function fill_empty_proxy_groups(doc) - local changed = 0 - for _, group in ipairs(doc["proxy-groups"] or {}) do - if type(group) == "table" - and group_requires_candidates(group) - and not has_nonempty_sequence(group.proxies) - and not has_nonempty_sequence(group.use) - then - group.proxies = { "DIRECT" } - changed = changed + 1 - end - end - return changed -end - -local function strip_incompatible_script_rules(doc) - local kept = {} - local removed = 0 - local has_script_rule = false - - for _, rule in ipairs(doc.rules or {}) do - local text = tostring(rule or "") - if text:match("^SCRIPT,") then - removed = removed + 1 - else - kept[#kept + 1] = rule - if text:match("^SCRIPT,") then - has_script_rule = true - end - end - end - - if removed > 0 then - doc.rules = kept - end - - if not has_script_rule then - doc.script = nil - end - - return removed -end - -local function prepare(input_path, output_path) - local doc, err = load_yaml(input_path) - if not doc then - io.stderr:write(err or "parse_failed", "\n") - return false - end - if not has_proxy_sections(doc) then - io.stderr:write("missing_proxy_sections\n") - return false - end - - strip_runtime_conflicts(doc) - local filled_groups = fill_empty_proxy_groups(doc) - local stripped_rules = strip_incompatible_script_rules(doc) - local ok, rendered = pcall(lyaml.dump, { doc }) - if not ok or not rendered then - io.stderr:write("dump_failed\n") - return false - end - - write_file(output_path, rendered) - io.stdout:write(string.format("filled_groups=%d stripped_script_rules=%d\n", filled_groups, stripped_rules)) - return true -end - -local function merge(raw_path, overlay_path, output_path) - local raw_doc, raw_err = load_yaml(raw_path) - if not raw_doc then - io.stderr:write(raw_err or "parse_failed", "\n") - return false - end - - local overlay_doc, overlay_err = load_yaml(overlay_path) - if not overlay_doc then - io.stderr:write(overlay_err or "parse_failed", "\n") - return false - end - - strip_runtime_conflicts(raw_doc) - local filled_groups = fill_empty_proxy_groups(raw_doc) - local stripped_rules = strip_incompatible_script_rules(raw_doc) - local merged = deep_merge(raw_doc, overlay_doc) - local ok, rendered = pcall(lyaml.dump, { merged }) - if not ok or not rendered then - io.stderr:write("dump_failed\n") - return false - end - - write_file(output_path, rendered) - io.stdout:write(string.format("filled_groups=%d stripped_script_rules=%d\n", filled_groups, stripped_rules)) - return true -end - -local function append_client_policy_rules(runtime_path, sid) - local doc, err = load_yaml(runtime_path) - if not doc then - io.stderr:write(err or "parse_failed", "\n") - return false - end - - local valid_policies = {} - for _, proxy in ipairs(doc.proxies or {}) do - if type(proxy) == "table" and proxy.name and proxy.name ~= "" then - valid_policies[tostring(proxy.name)] = true - end - end - for _, group in ipairs(doc["proxy-groups"] or {}) do - if type(group) == "table" and group.name and group.name ~= "" then - valid_policies[tostring(group.name)] = true - end - end - - local custom_rules = {} - for _, section in ipairs(read_clash_client_rules_csv(sid)) do - if tostring(section.enabled or "0") == "1" then - local ip_addr = tostring(section.ip_addr or "") - local policy_group = tostring(section.policy_group or "") - if ip_addr ~= "" and policy_group ~= "" and valid_policies[policy_group] then - if not ip_addr:find("/", 1, true) then - ip_addr = ip_addr .. "/32" - end - custom_rules[#custom_rules + 1] = string.format("SRC-IP-CIDR,%s,%s", ip_addr, policy_group) - end - end - end - - if #custom_rules == 0 then - io.stdout:write("client_rules=0\n") - return true - end - - local existing_rules = {} - for _, rule in ipairs(doc.rules or {}) do - local text = tostring(rule or "") - if not text:match("^SRC%-IP%-CIDR,") then - existing_rules[#existing_rules + 1] = rule - end - end - - doc.rules = {} - for _, rule in ipairs(custom_rules) do - doc.rules[#doc.rules + 1] = rule - end - for _, rule in ipairs(existing_rules) do - doc.rules[#doc.rules + 1] = rule - end - - local ok, rendered = pcall(lyaml.dump, { doc }) - if not ok or not rendered then - io.stderr:write("dump_failed\n") - return false - end - - write_file(runtime_path, rendered) - io.stdout:write(string.format("client_rules=%d\n", #custom_rules)) - return true -end - -local function bool_enabled(value) - return value == "1" or value == 1 or value == true or value == "true" -end - -local function split_csv(value) - local items = {} - for part in tostring(value or ""):gmatch("[^,%s]+") do - items[#items + 1] = part - end - return items -end - -local function get_server_field(sid, option, default) - local value = uci:get("shadowsocksr", sid, option) - if value == nil or value == "" then - return default - end - return value -end - -local function get_filter_aaaa() - local value = uci:get_first("shadowsocksr", "global", "filter_aaaa", "1") - if value == nil or value == "" then - value = uci:get_first("shadowsocksr", "global", "mosdns_ipv6", "1") - end - return value -end - -local function build_tuic_runtime_doc(sid, local_port, socks_port, mode) - local server = get_server_field(sid, "server", "") - local server_port = tonumber(get_server_field(sid, "server_port", "0")) or 0 - local tuic_ip = get_server_field(sid, "tuic_ip", "") - local tls_host = get_server_field(sid, "tls_host", "") - local ipstack_prefer = get_server_field(sid, "ipstack_prefer", "") - local dns_mode = uci:get_first("shadowsocksr", "global", "pdnsd_enable", "0") - - local proxy = { - name = sid, - type = "tuic", - server = server, - port = server_port, - uuid = get_server_field(sid, "tuic_uuid", ""), - password = get_server_field(sid, "tuic_passwd", ""), - ["udp-relay-mode"] = get_server_field(sid, "udp_relay_mode", "native"), - ["congestion-controller"] = get_server_field(sid, "congestion_control", "cubic"), - ["skip-cert-verify"] = bool_enabled(get_server_field(sid, "insecure", "0")), - ["disable-sni"] = bool_enabled(get_server_field(sid, "disable_sni", "0")), - ["reduce-rtt"] = bool_enabled(get_server_field(sid, "zero_rtt_handshake", "0")) - } - - if tuic_ip ~= "" then - proxy.ip = tuic_ip - end - if tls_host ~= "" then - proxy.sni = tls_host - end - - local alpn = split_csv(get_server_field(sid, "tuic_alpn", "")) - if #alpn > 0 then - proxy.alpn = alpn - end - - local heartbeat = tonumber(get_server_field(sid, "heartbeat", "0")) - if heartbeat and heartbeat > 0 then - proxy["heartbeat-interval"] = heartbeat * 1000 - end - - local timeout = tonumber(get_server_field(sid, "timeout", "0")) - if timeout and timeout > 0 then - proxy["request-timeout"] = timeout * 1000 - end - - local max_udp_packet_size = tonumber(get_server_field(sid, "tuic_max_package_size", "0")) - if max_udp_packet_size and max_udp_packet_size > 0 then - proxy["max-udp-relay-packet-size"] = max_udp_packet_size - end - - if ipstack_prefer ~= "" then - proxy["ip-version"] = ipstack_prefer == "v6first" and "ipv6-prefer" or "ipv4-prefer" - end - - local listen_port = tonumber(local_port) - local socks_listen = tonumber(socks_port) - - local doc = { - ["allow-lan"] = true, - ["bind-address"] = "0.0.0.0", - mode = "rule", - ["log-level"] = "silent", - ["find-process-mode"] = "off", - ["unified-delay"] = true, - ["tcp-concurrent"] = true, - ["routing-mark"] = 255, - proxies = { proxy }, - ["proxy-groups"] = { - { - name = "PROXY", - type = "select", - proxies = { sid } - } - }, - rules = { "MATCH,PROXY" }, - tun = { enable = false }, - profile = { ["store-selected"] = true }, - dns = { - enable = dns_mode == "7", - ["enhanced-mode"] = "redir-host", - listen = "127.0.0.1:5335", - ipv6 = get_filter_aaaa() ~= "1" - } - } - - if mode == "socks" then - doc["socks-port"] = listen_port - else - doc["redir-port"] = listen_port - doc["tproxy-port"] = listen_port - if socks_listen and socks_listen > 0 then - doc["socks-port"] = socks_listen - end - end - - return doc -end - -local function generate_tuic_runtime(sid, output_path, local_port, socks_port, mode) - local doc = build_tuic_runtime_doc(sid, local_port, socks_port, mode) - local ok, rendered = pcall(lyaml.dump, { doc }) - if not ok or not rendered then - io.stderr:write("dump_failed\n") - return false - end - write_file(output_path, rendered) - return true -end - -local function parse_plugin_opts(value) - local result = {} - for part in tostring(value or ""):gmatch("[^;]+") do - local key, val = part:match("^%s*([^=]+)=?(.*)%s*$") - if key and key ~= "" then - result[key] = val or "" - end - end - return result -end - -local function split_host_port(value) - local text = tostring(value or "") - if text == "" then - return "", "" - end - local host, port = text:match("^%[(.-)%]:(%d+)$") - if host and port then - return host, port - end - host, port = text:match("^(.-):(%d+)$") - if host and port then - return host, port - end - return text, "" -end - -local function bool_default(value, default) - if value == nil or value == "" then - return default - end - return bool_enabled(value) -end - -local function number_or_nil(value) - if value == nil or value == "" then - return nil - end - return tonumber(value) -end - -local function string_or_nil(value) - if value == nil or value == "" then - return nil - end - return tostring(value) -end - -local function pick_plugin_opt(plugin_opts, ...) - for i = 1, select("#", ...) do - local key = select(i, ...) - local value = plugin_opts[key] - if value ~= nil and value ~= "" then - return value - end - end - return nil -end - -local function parse_plugin_headers(plugin_opts) - local headers = {} - local raw_headers = pick_plugin_opt(plugin_opts, "headers", "header") - - if raw_headers and ok_jsonc and jsonc then - local decoded = jsonc.parse(raw_headers) - if type(decoded) == "table" then - for key, value in pairs(decoded) do - headers[tostring(key)] = tostring(value) - end - end - end - - if raw_headers and next(headers) == nil then - for part in tostring(raw_headers):gmatch("[^|,]+") do - local key, value = part:match("^%s*([^=:]+)%s*[:=]%s*(.-)%s*$") - if key and key ~= "" and value and value ~= "" then - headers[key] = value - end - end - end - - for key, value in pairs(plugin_opts) do - local header_name = key:match("^headers[%.:](.+)$") - or key:match("^header[%.:](.+)$") - or key:match("^header_(.+)$") - if header_name and header_name ~= "" and value ~= "" then - headers[header_name] = value - end - end - - return next(headers) and headers or nil -end - -local function get_plugin_client_fingerprint(sid, plugin_opts) - return string_or_nil( - pick_plugin_opt( - plugin_opts, - "client-fingerprint", - "client_fingerprint", - "fingerprint" - ) or get_server_field(sid, "fingerprint", "") - ) -end - -local function normalize_plugin_name(plugin) - local value = tostring(plugin or ""):lower() - if value == "" or value == "none" then - return "" - end - if value == "simple-obfs" then - return "obfs-local" - end - if value == "obfs" then - return "obfs-local" - end - if value == "shadowtls" then - return "shadow-tls" - end - if value == "gost" then - return "gost-plugin" - end - if value == "kcp-tun" then - return "kcptun" - end - return value -end - -local function build_shadowsocks_plugin(proxy, sid) - local plugin = normalize_plugin_name(get_server_field(sid, "plugin", "")) - local plugin_opts = parse_plugin_opts(get_server_field(sid, "plugin_opts", "")) - - if plugin == "" then - return - end - - if plugin == "obfs-local" then - proxy.plugin = "obfs" - proxy["plugin-opts"] = { - mode = pick_plugin_opt(plugin_opts, "obfs", "mode") or "http", - host = string_or_nil(pick_plugin_opt(plugin_opts, "obfs-host", "obfs_host", "host")) - } - return - end - - if plugin == "v2ray-plugin" or plugin == "xray-plugin" then - proxy.plugin = "v2ray-plugin" - proxy["plugin-opts"] = { - mode = pick_plugin_opt(plugin_opts, "mode") or "websocket", - tls = bool_default(pick_plugin_opt(plugin_opts, "tls"), false), - fingerprint = string_or_nil(pick_plugin_opt(plugin_opts, "fingerprint")), - ["skip-cert-verify"] = bool_default(pick_plugin_opt(plugin_opts, "skip-cert-verify", "skip_cert_verify", "insecure"), false), - host = string_or_nil(pick_plugin_opt(plugin_opts, "host")), - path = string_or_nil(pick_plugin_opt(plugin_opts, "path")), - mux = bool_default(pick_plugin_opt(plugin_opts, "mux"), false), - headers = parse_plugin_headers(plugin_opts), - ["v2ray-http-upgrade"] = bool_default(pick_plugin_opt(plugin_opts, "v2ray-http-upgrade", "v2ray_http_upgrade"), false) - } - return - end - - if plugin == "gost-plugin" then - proxy.plugin = "gost-plugin" - proxy["plugin-opts"] = { - mode = pick_plugin_opt(plugin_opts, "mode") or "websocket", - tls = bool_default(pick_plugin_opt(plugin_opts, "tls"), false), - fingerprint = string_or_nil(pick_plugin_opt(plugin_opts, "fingerprint")), - ["skip-cert-verify"] = bool_default(pick_plugin_opt(plugin_opts, "skip-cert-verify", "skip_cert_verify", "insecure"), false), - host = string_or_nil(pick_plugin_opt(plugin_opts, "host")), - path = string_or_nil(pick_plugin_opt(plugin_opts, "path")), - mux = bool_default(pick_plugin_opt(plugin_opts, "mux"), false), - headers = parse_plugin_headers(plugin_opts) - } - return - end - - if plugin == "shadow-tls" then - local host, port = split_host_port(pick_plugin_opt(plugin_opts, "host") or "") - local version - if plugin_opts.v3 == "1" or plugin_opts.version == "3" then - version = 3 - elseif plugin_opts.v2 == "1" or plugin_opts.version == "2" then - version = 2 - elseif plugin_opts.v1 == "1" or plugin_opts.version == "1" then - version = 1 - end - proxy.plugin = "shadow-tls" - proxy["client-fingerprint"] = get_plugin_client_fingerprint(sid, plugin_opts) - proxy["plugin-opts"] = { - host = host ~= "" and host or nil, - port = number_or_nil(port), - password = string_or_nil(pick_plugin_opt(plugin_opts, "passwd", "password")), - version = version - } - return - end - - if plugin == "restls" then - proxy.plugin = "restls" - proxy["client-fingerprint"] = get_plugin_client_fingerprint(sid, plugin_opts) - proxy["plugin-opts"] = { - host = string_or_nil(pick_plugin_opt(plugin_opts, "host")), - password = string_or_nil(pick_plugin_opt(plugin_opts, "passwd", "password")), - ["version-hint"] = string_or_nil(pick_plugin_opt(plugin_opts, "version-hint", "version_hint")), - ["restls-script"] = string_or_nil(pick_plugin_opt(plugin_opts, "restls-script", "restls_script")) - } - return - end - - if plugin == "kcptun" then - proxy.plugin = "kcptun" - proxy["plugin-opts"] = { - key = string_or_nil(pick_plugin_opt(plugin_opts, "key", "passwd", "password")), - crypt = string_or_nil(pick_plugin_opt(plugin_opts, "crypt")), - mode = string_or_nil(pick_plugin_opt(plugin_opts, "mode")), - conn = number_or_nil(pick_plugin_opt(plugin_opts, "conn")), - autoexpire = number_or_nil(pick_plugin_opt(plugin_opts, "autoexpire")), - scavengettl = number_or_nil(pick_plugin_opt(plugin_opts, "scavengettl")), - mtu = number_or_nil(pick_plugin_opt(plugin_opts, "mtu")), - ratelimit = number_or_nil(pick_plugin_opt(plugin_opts, "ratelimit")), - sndwnd = number_or_nil(pick_plugin_opt(plugin_opts, "sndwnd")), - rcvwnd = number_or_nil(pick_plugin_opt(plugin_opts, "rcvwnd")), - datashard = number_or_nil(pick_plugin_opt(plugin_opts, "datashard")), - parityshard = number_or_nil(pick_plugin_opt(plugin_opts, "parityshard")), - dscp = number_or_nil(pick_plugin_opt(plugin_opts, "dscp")), - nocomp = bool_default(pick_plugin_opt(plugin_opts, "nocomp"), false), - acknodelay = bool_default(pick_plugin_opt(plugin_opts, "acknodelay"), false), - nodelay = number_or_nil(pick_plugin_opt(plugin_opts, "nodelay")), - interval = number_or_nil(pick_plugin_opt(plugin_opts, "interval")), - resend = number_or_nil(pick_plugin_opt(plugin_opts, "resend")), - sockbuf = number_or_nil(pick_plugin_opt(plugin_opts, "sockbuf")), - smuxver = number_or_nil(pick_plugin_opt(plugin_opts, "smuxver")), - smuxbuf = number_or_nil(pick_plugin_opt(plugin_opts, "smuxbuf")), - framesize = number_or_nil(pick_plugin_opt(plugin_opts, "framesize")), - streambuf = number_or_nil(pick_plugin_opt(plugin_opts, "streambuf")), - keepalive = number_or_nil(pick_plugin_opt(plugin_opts, "keepalive")) - } - return - end - - proxy.plugin = plugin - if next(plugin_opts) then - proxy["plugin-opts"] = plugin_opts - end -end - -local function build_kcptun_plugin(proxy, sid) - if not bool_enabled(get_server_field(sid, "kcp_enable", "0")) then - return - end - - proxy.plugin = "kcptun" - proxy.port = tonumber(get_server_field(sid, "kcp_port", "0")) or proxy.port - proxy["plugin-opts"] = { - key = get_server_field(sid, "kcp_password", ""), - mode = "fast", - mtu = 1350 - } -end - -local function build_shadowsocks_runtime_doc(sid, local_port, socks_port, mode) - local dns_mode = uci:get_first("shadowsocksr", "global", "pdnsd_enable", "0") - local server = get_server_field(sid, "server", "") - local server_port = tonumber(get_server_field(sid, "server_port", "0")) or 0 - local method = get_server_field(sid, "encrypt_method_ss", "none") - local password = get_server_field(sid, "password", "") - local proxy = { - name = sid, - type = "ss", - server = server, - port = server_port, - cipher = method, - password = password, - udp = true, - tfo = bool_enabled(get_server_field(sid, "fast_open", "0")) - } - - if get_server_field(sid, "type", "") == "ss" then - build_kcptun_plugin(proxy, sid) - end - if proxy.plugin == nil then - build_shadowsocks_plugin(proxy, sid) - end - - local doc = { - ["allow-lan"] = true, - ["bind-address"] = "0.0.0.0", - mode = "rule", - ["log-level"] = "silent", - ["find-process-mode"] = "off", - ["unified-delay"] = true, - ["tcp-concurrent"] = true, - ["routing-mark"] = 255, - proxies = { proxy }, - ["proxy-groups"] = { - { - name = "PROXY", - type = "select", - proxies = { sid } - } - }, - rules = { "MATCH,PROXY" }, - tun = { enable = false }, - profile = { ["store-selected"] = true }, - dns = { - enable = dns_mode == "7", - ["enhanced-mode"] = "redir-host", - listen = "127.0.0.1:5335", - ipv6 = get_filter_aaaa() ~= "1" - } - } - - local listen_port = tonumber(local_port) - local socks_listen = tonumber(socks_port) - if mode == "socks" then - doc["socks-port"] = listen_port - else - doc["redir-port"] = listen_port - doc["tproxy-port"] = listen_port - if socks_listen and socks_listen > 0 then - doc["socks-port"] = socks_listen - end - end - - return doc -end - -local function generate_shadowsocks_runtime(sid, output_path, local_port, socks_port, mode) - local doc = build_shadowsocks_runtime_doc(sid, local_port, socks_port, mode) - local ok, rendered = pcall(lyaml.dump, { doc }) - if not ok or not rendered then - io.stderr:write("dump_failed\n") - return false - end - write_file(output_path, rendered) - return true -end - -local function build_shadowsocks_server_doc(sid) - local server_port = tonumber(get_server_field(sid, "server_port", "0")) or 0 - local method = get_server_field(sid, "encrypt_method_ss", "aes-128-gcm") - local password = get_server_field(sid, "password", "") - local listener = { - name = sid, - type = "shadowsocks", - listen = "::", - port = server_port, - cipher = method, - password = password, - udp = true, - tfo = bool_enabled(get_server_field(sid, "fast_open", "0")) - } - - local plugin = normalize_plugin_name(get_server_field(sid, "plugin", "")) - if plugin == "obfs-local" then - local plugin_opts = parse_plugin_opts(get_server_field(sid, "plugin_opts", "")) - listener.obfs = plugin_opts.obfs or plugin_opts.mode or "http" - listener.obfs_opts = { - mode = plugin_opts.obfs or plugin_opts.mode or "http", - host = plugin_opts["obfs-host"] or plugin_opts.obfs_host or plugin_opts.host or nil - } - end - - return { - ["allow-lan"] = true, - ["bind-address"] = "*", - ["log-level"] = "silent", - ["find-process-mode"] = "off", - listeners = { listener } - } -end - -local function generate_shadowsocks_server(sid, output_path) - local doc = build_shadowsocks_server_doc(sid) - local ok, rendered = pcall(lyaml.dump, { doc }) - if not ok or not rendered then - io.stderr:write("dump_failed\n") - return false - end - write_file(output_path, rendered) - return true -end - -local action = arg[1] -if action == "validate" then - os.exit(validate(arg[2]) and 0 or 1) -elseif action == "filter" then - os.exit(filter(arg[2], arg[3]) and 0 or 1) -elseif action == "prepare" then - os.exit(prepare(arg[2], arg[3]) and 0 or 1) -elseif action == "merge" then - os.exit(merge(arg[2], arg[3], arg[4]) and 0 or 1) -elseif action == "append_client_policy_rules" then - os.exit(append_client_policy_rules(arg[2], arg[3]) and 0 or 1) -elseif action == "tuic" then - os.exit(generate_tuic_runtime(arg[2], arg[3], arg[4], arg[5], arg[6]) and 0 or 1) -elseif action == "ss" then - os.exit(generate_shadowsocks_runtime(arg[2], arg[3], arg[4], arg[5], arg[6]) and 0 or 1) -elseif action == "ss_server" then - os.exit(generate_shadowsocks_server(arg[2], arg[3]) and 0 or 1) -else - io.stderr:write("usage: clash_yaml.lua validate | filter | prepare | merge | append_client_policy_rules | tuic [socks_port] [mode] | ss [socks_port] [mode] | ss_server \n") - os.exit(1) -end diff --git a/luci-app-ssr-plus/root/usr/share/shadowsocksr/gen_config.lua b/luci-app-ssr-plus/root/usr/share/shadowsocksr/gen_config.lua index 79db21bb..e226697b 100755 --- a/luci-app-ssr-plus/root/usr/share/shadowsocksr/gen_config.lua +++ b/luci-app-ssr-plus/root/usr/share/shadowsocksr/gen_config.lua @@ -2,6 +2,7 @@ require "luci.sys" local ucursor = require "luci.model.uci".cursor() +local datatypes = require "luci.cbi.datatypes" local json = require "luci.jsonc" local server_section = arg[1] @@ -11,6 +12,12 @@ local socks_port = arg[4] or "0" local chain = arg[5] or "0" +local GLOBAL = { + DNS_SERVER = {}, + DNS_HOSTNAME = {}, + VPS_EXCLUDE = {} +} + -- 辅助函数:拆分字符串(若 luci.util 未加载则定义) local function split(str, pat) local t = {} @@ -31,52 +38,27 @@ local server = ucursor:get_all("shadowsocksr", server_section) local socks_server = ucursor:get_all("shadowsocksr", "@socks5_proxy[0]") or {} local xray_fragment = ucursor:get_all("shadowsocksr", "@global_xray_fragment[0]") or {} local xray_noise = ucursor:get_all("shadowsocksr", "@xray_noise_packets[0]") or {} -local default_node_local_port = ucursor:get_first("shadowsocksr", "global", "default_node_local_port", "1234") -local dns_mode = ucursor:get_first("shadowsocksr", "global", "pdnsd_enable", "0") -local dns_ipv4_only = ucursor:get_first("shadowsocksr", "global", "filter_aaaa") -if not dns_ipv4_only or dns_ipv4_only == "" then - dns_ipv4_only = ucursor:get_first("shadowsocksr", "global", "mosdns_ipv6", "1") -end -local builtin_dns_server = ucursor:get_first("shadowsocksr", "global", "tunnel_forward", "8.8.4.4:53") local outbound_settings = nil local xray_version = nil local xray_version_val = 0 -local xray_builtin_dns = nil local node_id = server_section local remarks = server.alias or "" local b64decode = nixio.bin.b64decode local b64encode = nixio.bin.b64encode -local effective_node_local_port = tonumber(server.local_port) or tonumber(default_node_local_port) or 1234 -if server.type == "ss-rust" then - server.type = "ss" +-- 解析 URL(简单实现,仅用于 DoH) +local function parseURL(url) + if not url then return nil end + local schema, rest = url:match("^(https?)://(.*)$") + if not schema then return nil end + local host, port_str = rest:match("^([^:]+):?(%d*)/?.*$") + local port = tonumber(port_str) or (schema == "https" and 443 or 80) + return { host = host, port = port, schema = schema } end -local function parse_realm_uri(uri) - if type(uri) ~= "string" then return nil end - -- realm://token@server/realm_id?query - local token, server_url, realm_id, query = trim(uri):match("^realm://([^@]+)@([^/]+)/([^?]*)%??(.*)$") - if not token or not server_url or not realm_id then return nil end - realm_id = realm_id:gsub("/+$", "") - local realm = { - token = token, - server_url = server_url, - realm_id = realm_id - } - -- 解析 query 中的 stun= - if query and query ~= "" then - local stun_servers = {} - for key, value in query:gmatch("([^&=?]+)=([^&]+)") do - if key == "stun" and value ~= "" then - stun_servers[#stun_servers + 1] = value - end - end - if #stun_servers > 0 then - realm.stun_servers = stun_servers - end - end - return realm +if server.type == "ss-rust" or server.type == "ss-libev" then + server.type = "ss" end -- base64 解码 @@ -138,25 +120,9 @@ local function cleanEmptyTables(t) return next(t) and t or nil end -local function format_host(host) - host = tostring(host or "") - if host ~= "" and host:find(":", 1, true) and not host:match("^%[.*%]$") then - return "[" .. host .. "]" - end - return host -end - -local function format_host_port(host, port) - host = format_host(host) - if port == nil or port == "" then - return host - end - return host .. ":" .. tostring(port) -end - -- 确保正确判断程序是否存在 local function is_finded(e) - return luci.sys.exec(string.format('type -t -p "%s" -p "/usr/libexec/%s" 2>/dev/null', e, e)) ~= "" + return luci.sys.exec(string.format('type -t -p "%s" 2>/dev/null', e)) ~= "" end -- 获取 Xray 版本号 @@ -237,33 +203,20 @@ function wireguard() -- 处理 reserved 字段,支持逗号分隔的数字或 Base64 编码 local reserved = nil if server.reserved then - local all_bytes = {} - local reserved_values = server.reserved - - -- 确保是 table 类型 - if type(reserved_values) ~= "table" then - reserved_values = {reserved_values} - end - - for _, reserved_str in ipairs(reserved_values) do - if type(reserved_str) == "string" then - if not reserved_str:match("[^%d,]+") then - -- 数字和逗号格式 - reserved_str:gsub("%d+", function(b) - all_bytes[#all_bytes + 1] = tonumber(b) - end) - else - -- Base64 格式 - local result = base64Decode(reserved_str) - if result then - for i = 1, #result do - all_bytes[#all_bytes + 1] = result:byte(i) - end - end - end + local bytes = {} + if not server.reserved:match("[^%d,]+") then + -- 纯数字和逗号,解析为数字列表 + server.reserved:gsub("%d+", function(b) + bytes[#bytes + 1] = tonumber(b) + end) + else + -- Base64 编码的二进制数据 + local result = base64Decode(server.reserved) + for i = 1, #result do + bytes[i] = result:byte(i) end end - reserved = #all_bytes > 0 and all_bytes or nil + reserved = #bytes > 0 and bytes or nil end outbound_settings = { @@ -273,22 +226,15 @@ function wireguard() { publicKey = server.peer_pubkey, preSharedKey = server.preshared_key, - endpoint = format_host_port(server.server, server.server_port), + endpoint = server.server .. ":" .. server.server_port, keepAlive = tonumber(server.keepaliveperiod), allowedIPs = (server.allowedips) or nil, } }, - kernelMode = (server.kernelmode == "1") and true or false, + noKernelTun = (server.kernelmode == "1") and true or false, reserved = reserved, mtu = tonumber(server.mtu) } - if server.finalmask and server.finalmask ~= "" then - local ok, fm = pcall(json.parse, base64Decode(server.finalmask)) - if ok and type(fm) == "table" then - outbound_settings.streamSettings = outbound_settings.streamSettings or {} - outbound_settings.streamSettings.finalmask = fm - end - end end function xray_hysteria2() outbound_settings = { @@ -353,35 +299,6 @@ local Xray = { -- 初始化 outbounds 表 outbounds = {}, } - -if server.type == "v2ray" and dns_mode == "7" and os.getenv("SSR_SWITCH_PROBE") ~= "1" then - local dns_host = builtin_dns_server:match("^([^:]+)") or "8.8.4.4" - local dns_port = tonumber(builtin_dns_server:match(":(%d+)$")) or 53 - - Xray.dns = { - queryStrategy = (dns_ipv4_only == "1") and "UseIPv4" or "UseIP", - servers = { - string.format("tcp://%s:%d", dns_host, dns_port) - } - } - - table.insert(Xray.inbounds, { - listen = "127.0.0.1", - port = 5335, - protocol = "dokodemo-door", - settings = { - address = dns_host, - port = dns_port, - network = "tcp,udp" - }, - tag = "builtin-dns-in" - }) - - xray_builtin_dns = { - address = dns_host, - port = dns_port - } -end -- 传入连接 -- 添加 dokodemo-door 配置,如果 local_port 不为 0 if local_port ~= "0" then @@ -432,11 +349,11 @@ if proto and proto:find("tcp") and socks_port ~= "0" then -- socks protocol = "socks", port = tonumber(socks_port), - settings = { + settings = { auth = socks_server.socks5_auth or "noauth", udp = true, - mixed = ((socks_server.socks5_mixed == '1') and true or false) or nil, - accounts = (socks_server.socks5_auth and socks_server.socks5_auth ~= "noauth") and { + mixed = ((socks_server.socks5_mixed == '1') and true or false) or (socks_server.server == 'same') and nil, + accounts = (socks_server.server ~= "same" and (socks_server.socks5_auth and socks_server.socks5_auth ~= "noauth")) and { { user = socks_server.socks5_user, pass = socks_server.socks5_pass @@ -615,7 +532,7 @@ Xray.outbounds = { local finalmask = {} local PT = server.v2ray_protocol local TP = server.transport - if TP == "kcp" then + if server.transport == "kcp" then local map = {none = "none", srtp = "header-srtp", utp = "header-utp", ["wechat-video"] = "header-wechat", dtls = "header-dtls", wireguard = "header-wireguard", dns = "header-dns"} local udp = {} @@ -633,36 +550,14 @@ Xray.outbounds = { udp[#udp+1] = c finalmask.udp = udp elseif PT == "hysteria2" then - local udp = {} if (server.flag_obfs == "1" and (server.obfs_type and server.obfs_type ~= "")) then - local o = { - type = "salamander", + finalmask.udp = {{ + type = server.obfs_type, settings = server.salamander and { - password = server.salamander, - packetSize = server.obfs_type == "gecko" and "512-1200" or nil + password = server.salamander } or nil - } - udp[#udp+1] = o + }} end - if server.hysteria2_realms then - local realm = parse_realm_uri(server.hysteria2_realm_url) - local url, stun - if realm then - if realm.token and realm.server_url and realm.realm_id then - url = "realm://" .. realm.token .. "@" .. realm.server_url .. "/" .. realm.realm_id - end - stun = realm.stun_servers or server.hysteria2_realm_stun - end - local r = { - type = "realm", - settings = { - url = url, - stunServers = stun - } - } - udp[#udp+1] = r - end - finalmask.udp = udp local up = tonumber(server.uplink_capacity) or 0 local down = tonumber(server.downlink_capacity) or 0 finalmask.quicParams = { @@ -750,6 +645,7 @@ Xray.outbounds = { end)(), sockopt = { mark = 255, + domainStrategy = server.domain_strategy or "UseIP", tcpFastOpen = (function() if server.transport == "xhttp" then return (server.fast_open == "1") and true or false @@ -777,24 +673,18 @@ Xray.outbounds = { } } -if xray_builtin_dns then - table.insert(Xray.outbounds, { - protocol = "dns", - tag = "builtin-dns-out", - settings = { - network = "tcp", - address = xray_builtin_dns.address, - port = xray_builtin_dns.port +table.insert(Xray.outbounds, { + protocol = "freedom", + tag = "direct", + settings = { + domainStrategy = server.domain_strategy or "UseIP" -- 可根据需要改为 direct_dns_query_strategy + }, + streamSettings = { + sockopt = { + mark = 255 } - }) - Xray.routing = Xray.routing or {} - Xray.routing.rules = Xray.routing.rules or {} - table.insert(Xray.routing.rules, { - type = "field", - inboundTag = { "builtin-dns-in" }, - outboundTag = "builtin-dns-out" - }) -end + } +}) -- 添加带有 fragment 设置的 dialerproxy 配置 if xray_fragment.fragment ~= "0" or (xray_fragment.noise ~= "0" and xray_noise.enabled ~= "0") then @@ -825,6 +715,121 @@ if xray_fragment.fragment ~= "0" or (xray_fragment.noise ~= "0" and xray_noise.e }) end +-- Xray DNS 解析配置 +if datatypes.hostname(server.server) and server.domain_resolver and (server.domain_resolver_dns or server.domain_resolver_dns_https) then + -- 解析 DNS 服务器配置 + local dns_proto = server.domain_resolver + local config_address + local config_port + if dns_proto == "https" then + local _a = parseURL(server.domain_resolver_dns_https) + if _a then + config_address = server.domain_resolver_dns_https + config_port = _a.port or 443 + if _a.hostname and datatypes.hostname(_a.hostname) then + GLOBAL.DNS_HOSTNAME[_a.hostname] = true + end + end + else + local server_address = server.domain_resolver_dns + config_port = 53 + local parts = split(server_address, ":") + if #parts > 1 then + server_address = parts[1] + config_port = tonumber(parts[#parts]) + end + config_address = server_address + if dns_proto == "tcp" then + config_address = dns_proto .. "://" .. server_address .. ":" .. config_port + end + end + + -- 存入 GLOBAL.DNS_SERVER(去重) + local dns_key = dns_proto .. "|" .. config_address .. "|" .. tostring(config_port) + if not GLOBAL.DNS_SERVER[dns_key] then + GLOBAL.DNS_SERVER[dns_key] = { + tag = "dns-node-" .. node_id, + address = config_address, + port = config_port, + finalQuery = true, + disableCache = false, + serveStale = true, + serveExpiredTTL = 30, + domains = {} + } + end + + -- 添加当前节点域名到该 DNS 服务器的 domains 列表 + local domain = "full:" .. server.server + local exists + for _, d in ipairs(GLOBAL.DNS_SERVER[dns_key].domains) do + if d == domain then exists = true; break end + end + if not exists then + table.insert(GLOBAL.DNS_SERVER[dns_key].domains, domain) + end + GLOBAL.VPS_EXCLUDE[server.server] = true + + -- 构建 Xray.dns + local dns_servers = { "localhost" } + for key, dns_server in pairs(GLOBAL.DNS_SERVER) do + table.insert(dns_servers, { + tag = dns_server.tag, + address = dns_server.address, + port = dns_server.port, + domains = dns_server.domains, + finalQuery = dns_server.finalQuery, + serveStale = dns_server.serveStale, + serveExpiredTTL = dns_server.serveExpiredTTL, + disableCache = dns_server.disableCache + }) + end + Xray.dns = { + servers = dns_servers, + disableFallback = true, + disableFallbackIfMatch = true, + useSystemHosts = true, + queryStrategy = "UseIP", + disableCache = false, + tag = "dns-global" -- 用于 routing + } +end + +-- 代理出站的 tag(与 outbound 中的 tag 保持一致) +local proxy_tag = (remarks ~= nil and remarks ~= "") and (node_id .. ":" .. remarks) or node_id +-- 构建 routing 规则表 +local routing_rules = {} +-- 1. 为每个自定义 DNS 服务器添加直连规则(inboundTag 匹配 dns-node-xxx) +if GLOBAL.DNS_SERVER and next(GLOBAL.DNS_SERVER) then + for _, dns_server in pairs(GLOBAL.DNS_SERVER) do + table.insert(routing_rules, { + inboundTag = { dns_server.tag }, + outboundTag = "direct" + }) + end +end + +-- 2. 添加全局 DNS 直连规则(需要 Xray.dns 中已设置 tag = "dns-global") +if Xray.dns and Xray.dns.tag then + table.insert(routing_rules, { + inboundTag = { "dns-global" }, + outboundTag = "direct" + }) +end + +-- 3. 添加默认规则:所有 TCP/UDP 流量走代理 +table.insert(routing_rules, { + network = "tcp,udp", + ruleTag = "default", + outboundTag = proxy_tag +}) + +-- 构建 routing 对象 +Xray.routing = { + rules = routing_rules, + domainStrategy = "AsIs" +} + local cipher = "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA:AES128-SHA:AES256-SHA:DES-CBC3-SHA" local cipher13 = "TLS_AES_128_GCM_SHA256:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_256_GCM_SHA384" local trojan = { @@ -872,7 +877,7 @@ local trojan = { } } local naiveproxy = { - proxy = (server.username and server.password and server.server and server.server_port) and "https://" .. server.username .. ":" .. server.password .. "@" .. format_host_port(server.server, server.server_port), + proxy = (server.username and server.password and server.server and server.server_port) and "https://" .. server.username .. ":" .. server.password .. "@" .. server.server .. ":" .. server.server_port, listen = (proto == "redir") and "redir" .. "://0.0.0.0:" .. tonumber(local_port) or "socks" .. "://0.0.0.0:" .. tonumber(local_port), ["insecure-concurrency"] = tonumber(server.concurrency) or 1 } @@ -893,16 +898,16 @@ local hysteria2 = { server.server_port and ( server.port_range and - (format_host_port(server.server, server.server_port) .. "," .. string.gsub(server.port_range, ":", "-")) + (server.server .. ":" .. server.server_port .. "," .. string.gsub(server.port_range, ":", "-")) or - (format_host_port(server.server, server.server_port)) + (server.server .. ":" .. server.server_port) ) or ( server.port_range and - format_host(server.server) .. ":" .. string.gsub(server.port_range, ":", "-") + server.server .. ":" .. string.gsub(server.port_range, ":", "-") or - server.server and format_host_port(server.server, "443") + server.server and server.server .. ":443" ) ), bandwidth = (server.uplink_capacity or server.downlink_capacity) and { @@ -1001,7 +1006,7 @@ local hysteria2 = { } local shadowtls = { client = { - server_addr = server.server_port and format_host_port(server.server, server.server_port) or nil, + server_addr = server.server_port and server.server .. ":" .. server.server_port or nil, listen = "127.0.0.1:" .. tonumber(local_port), tls_names = server.shadowtls_sni, password = server.password @@ -1015,7 +1020,7 @@ local chain_sslocal = { locals = local_port ~= "0" and { { local_address = "0.0.0.0", - local_port = (chain_local_port == "0" and effective_node_local_port or tonumber(chain_local_port)), + local_port = (chain_local_port == "0" and tonumber(server.local_port) or tonumber(chain_local_port)), mode = (proto:find("tcp,udp") and "tcp_and_udp") or proto .. "_only", protocol = "redir", tcp_redir = "redirect", @@ -1044,7 +1049,7 @@ local chain_sslocal = { local chain_vmess = { inbounds = (local_port ~= "0") and { { - port = (chain_local_port == "0" and effective_node_local_port or tonumber(chain_local_port)), + port = (chain_local_port == "0" and tonumber(server.local_port) or tonumber(chain_local_port)), protocol = "dokodemo-door", settings = { network = proto, @@ -1080,7 +1085,7 @@ local chain_vmess = { } local tuic = { relay = { - server = server.server_port and format_host_port(server.server, server.server_port), + server = server.server_port and server.server .. ":" .. server.server_port, ip = server.tuic_ip, uuid = server.tuic_uuid, password = server.tuic_passwd, diff --git a/luci-app-ssr-plus/root/usr/share/shadowsocksr/genred2config.sh b/luci-app-ssr-plus/root/usr/share/shadowsocksr/genred2config.sh new file mode 100755 index 00000000..3750d3f9 --- /dev/null +++ b/luci-app-ssr-plus/root/usr/share/shadowsocksr/genred2config.sh @@ -0,0 +1,95 @@ +#!/bin/sh +argv1=$1 +argv2=$2 +argv3=$3 +argv4=$4 +argv5=$5 +argv6=$6 +argv7=$7 +argv8=$8 +argv9=$9 +cat <<-EOF >$argv1 + base { + log_debug = off; + log_info = off; + log = stderr; + daemon = on; + redirector = iptables; + reuseport = on; + } +EOF +tcp() { + if [ "$argv7" == "0" ]; then + cat <<-EOF >>$argv1 + redsocks { + bind = "0.0.0.0:$argv4"; + relay = "$argv5:$argv6"; + type = socks5; + autoproxy = 0; + timeout = 10; + } + EOF + else + cat <<-EOF >>$argv1 + redsocks { + bind = "0.0.0.0:$argv4"; + relay = "$argv5:$argv6"; + type = socks5; + autoproxy = 0; + timeout = 10; + login = "$argv8"; + password = "$argv9"; + } + EOF + fi +} +udp() { + if [ "$argv7" == "0" ]; then + cat <<-EOF >>$argv1 + redudp { + bind = "0.0.0.0:$argv4"; + relay = "$argv5:$argv6"; + type = socks5; + udp_timeout = 10; + } + EOF + else + cat <<-EOF >>$argv1 + redudp { + bind = "0.0.0.0:$argv4"; + relay = "$argv5:$argv6"; + type = socks5; + udp_timeout = 10; + login = "$argv8"; + password = "$argv9"; + } + EOF + fi +} +case "$argv2" in +socks5) + case "$argv3" in + tcp) + tcp + ;; + udp) + udp + ;; + *) + tcp + udp + ;; + esac + ;; +*) + cat <<-EOF >>$argv1 + redsocks { + bind = "0.0.0.0:$argv4"; + type = direct; + interface = $argv3; + autoproxy = 0; + timeout = 10; + } + EOF + ;; +esac diff --git a/luci-app-ssr-plus/root/usr/share/shadowsocksr/gfw2ipset.sh b/luci-app-ssr-plus/root/usr/share/shadowsocksr/gfw2ipset.sh index fa168826..f4ade91b 100755 --- a/luci-app-ssr-plus/root/usr/share/shadowsocksr/gfw2ipset.sh +++ b/luci-app-ssr-plus/root/usr/share/shadowsocksr/gfw2ipset.sh @@ -18,12 +18,38 @@ case "$USE_TABLES" in exit 1 ;; esac + +netflix() { + local port="$1" + if [ -f "$TMP_DNSMASQ_PATH/gfw_list.conf" ] && [ -s /etc/ssrplus/netflix.list ]; then + grep -vE '^\s*#|^\s*$' /etc/ssrplus/netflix.list > /tmp/ssrplus_netflix.list.clean + if [ -s /tmp/ssrplus_netflix.list.clean ]; then + grep -v -F -f /tmp/ssrplus_netflix.list.clean "$TMP_DNSMASQ_PATH/gfw_list.conf" > "$TMP_DNSMASQ_PATH/gfw_list.conf.tmp" + mv "$TMP_DNSMASQ_PATH/gfw_list.conf.tmp" "$TMP_DNSMASQ_PATH/gfw_list.conf" + if [ -f "$TMP_DNSMASQ_PATH/gfw_base.conf" ]; then + grep -v -F -f /tmp/ssrplus_netflix.list.clean "$TMP_DNSMASQ_PATH/gfw_base.conf" > "$TMP_DNSMASQ_PATH/gfw_base.conf.tmp" + mv "$TMP_DNSMASQ_PATH/gfw_base.conf.tmp" "$TMP_DNSMASQ_PATH/gfw_base.conf" + fi + fi + rm -f /tmp/ssrplus_netflix.list.clean + fi + if [ "$nft_support" = "1" ]; then + # 移除 ipset + cat /etc/ssrplus/netflix.list | sed '/^$/d' | sed '/#/d' | sed "/.*/s/.*/server=\/&\/127.0.0.1#$port\nnftset=\/&\/inet#ss_spec#netflix/" >$TMP_DNSMASQ_PATH/netflix_forward.conf + elif [ "$nft_support" = "0" ]; then + cat /etc/ssrplus/netflix.list | sed '/^$/d' | sed '/#/d' | sed "/.*/s/.*/server=\/&\/127.0.0.1#$port\nipset=\/&\/netflix/" >$TMP_DNSMASQ_PATH/netflix_forward.conf + fi +} mkdir -p $TMP_DNSMASQ_PATH -run_mode=$(normalize_run_mode) +run_mode=$(uci_get_by_type global run_mode router) -cp -rf /etc/ssrplus/gfw_list.conf $TMP_DNSMASQ_PATH/ -cp -rf /etc/ssrplus/gfw_base.conf $TMP_DNSMASQ_PATH/ +if [ "$run_mode" = "oversea" ]; then + cp -rf /etc/ssrplus/oversea_list.conf $TMP_DNSMASQ_PATH/ +else + cp -rf /etc/ssrplus/gfw_list.conf $TMP_DNSMASQ_PATH/ + cp -rf /etc/ssrplus/gfw_base.conf $TMP_DNSMASQ_PATH/ +fi for conf_file in gfw_base.conf gfw_list.conf; do conf="$TMP_DNSMASQ_PATH/$conf_file" @@ -41,41 +67,36 @@ for conf_file in gfw_base.conf gfw_list.conf; do fi done +if [ "$(uci_get_by_type global netflix_enable 0)" == "1" ]; then + # 只有开启 NetFlix分流 才需要取值 + SHUNT_SERVER=$(uci_get_by_type global netflix_server nil) +else + # 没有开启 设置为 nil + SHUNT_SERVER=nil +fi +case "$SHUNT_SERVER" in +nil) + rm -f $TMP_DNSMASQ_PATH/netflix_forward.conf + ;; +$(uci_get_by_type global global_server nil) | $switch_server | same) + netflix $dns_port + ;; +*) + netflix $tmp_shunt_dns_port + ;; +esac + # 此处使用 for 方式读取 防止 /etc/ssrplus/ 目录下的 black.list white.list deny.list 等2个或多个文件一行中存在空格 比如:# abc.com 而丢失:server # Optimize: Batch filter using grep for list_file in /etc/ssrplus/black.list /etc/ssrplus/white.list /etc/ssrplus/deny.list; do if [ -s "$list_file" ]; then - # 清理注释和空行 - grep -vE '^\s*#|^\s*$' "$list_file" | sed 's/\r//g' > "${list_file}.clean" + grep -vE '^\s*#|^\s*$' "$list_file" > "${list_file}.clean" if [ -s "${list_file}.clean" ]; then for target_file in "$TMP_DNSMASQ_PATH/gfw_list.conf" "$TMP_DNSMASQ_PATH/gfw_base.conf"; do - [ -f "$target_file" ] || continue - tmp_file="${target_file}.tmp" - awk -v list="${list_file}.clean" ' - BEGIN { - while ((getline line < list) > 0) { - gsub(/\r/, "", line) - if (line != "") { - domain[line] = 1 - # 同时支持 *.domain - domain["*." line] = 1 - } - } - close(list) - } - { - # 提取 server=/domain/xxx - if (match($0, /^server=\/([^\/]+)\//, m)) { - if (m[1] in domain) next - } - # 提取 ipset=/domain/xxx - if (match($0, /^ipset=\/([^\/]+)\//, m)) { - if (m[1] in domain) next - } - print - } - ' "$target_file" > "$tmp_file" - mv "$tmp_file" "$target_file" + if [ -f "$target_file" ]; then + grep -v -F -f "${list_file}.clean" "$target_file" > "${target_file}.tmp" + mv "${target_file}.tmp" "$target_file" + fi done fi rm -f "${list_file}.clean" @@ -93,45 +114,19 @@ fi cat /etc/ssrplus/deny.list | sed '/^$/d' | sed '/#/d' | sed "/.*/s/.*/address=\/&\//" >$TMP_DNSMASQ_PATH/denylist.conf if [ "$(uci_get_by_type global adblock 0)" == "1" ]; then - cp -f /etc/ssrplus/ad.conf "$TMP_DNSMASQ_PATH/" + cp -f /etc/ssrplus/ad.conf $TMP_DNSMASQ_PATH/ if [ -f "$TMP_DNSMASQ_PATH/ad.conf" ]; then - for list_file in /etc/ssrplus/black.list /etc/ssrplus/white.list /etc/ssrplus/deny.list; do + for list_file in /etc/ssrplus/black.list /etc/ssrplus/white.list /etc/ssrplus/deny.list /etc/ssrplus/netflix.list; do if [ -s "$list_file" ]; then - # 清理注释 & 空行 - grep -vE '^\s*#|^\s*$' "$list_file" | sed 's/\r//g' > "${list_file}.clean" + grep -vE '^\s*#|^\s*$' "$list_file" > "${list_file}.clean" if [ -s "${list_file}.clean" ]; then - tmp_file="$TMP_DNSMASQ_PATH/ad.conf.tmp" - awk -v list="${list_file}.clean" ' - BEGIN { - while ((getline line < list) > 0) { - gsub(/\r/, "", line) - if (line != "") { - domain[line] = 1 - # 支持泛域名 - domain["*." line] = 1 - } - } - close(list) - } - { - keep = 1 - # 精确匹配 server=/domain/ - if (match($0, /^server=\/([^\/]+)\//, m)) { - if (m[1] in domain) keep = 0 - } - # 精确匹配 ipset=/domain/ - if (match($0, /^ipset=\/([^\/]+)\//, m)) { - if (m[1] in domain) keep = 0 - } - if (keep) print - } - ' "$TMP_DNSMASQ_PATH/ad.conf" > "$tmp_file" - mv "$tmp_file" "$TMP_DNSMASQ_PATH/ad.conf" + grep -v -F -f "${list_file}.clean" "$TMP_DNSMASQ_PATH/ad.conf" > "$TMP_DNSMASQ_PATH/ad.conf.tmp" + mv "$TMP_DNSMASQ_PATH/ad.conf.tmp" "$TMP_DNSMASQ_PATH/ad.conf" fi rm -f "${list_file}.clean" fi done fi else - rm -f "$TMP_DNSMASQ_PATH/ad.conf" + rm -f $TMP_DNSMASQ_PATH/ad.conf fi diff --git a/luci-app-ssr-plus/root/usr/share/shadowsocksr/hy2_test.sh b/luci-app-ssr-plus/root/usr/share/shadowsocksr/hy2_test.sh new file mode 100755 index 00000000..1bac264d --- /dev/null +++ b/luci-app-ssr-plus/root/usr/share/shadowsocksr/hy2_test.sh @@ -0,0 +1,175 @@ +#!/bin/sh +# /usr/share/shadowsocksr/test.sh + +CONFIG="shadowsocksr" +LOCK_PATH=/tmp/lock +TMP_PATH=/var/etc/ssrplus + +uci_get_by_name() { + local ret=$(uci -q get $CONFIG.$1.$2 2>/dev/null) + echo "${ret:=$3}" +} + +uci_get_by_type() { + local ret=$(uci -q get $CONFIG.@$1[0].$2 2>/dev/null) + echo "${ret:=$3}" +} + +check_port_exists() { + local port=$1 + local protocol=$2 + [ -n "$protocol" ] || protocol="tcp,udp" + local result= + if [ "$protocol" = "tcp" ]; then + result=$(netstat -tln | grep -c ":$port ") + elif [ "$protocol" = "udp" ]; then + result=$(netstat -uln | grep -c ":$port ") + elif [ "$protocol" = "tcp,udp" ]; then + result=$(netstat -tuln | grep -c ":$port ") + fi + echo "${result}" +} + +set_cache_var() { + local key="${1}" + shift 1 + local val="$@" + [ -n "${key}" ] && [ -n "${val}" ] && { + sed -i "/${key}=/d" $TMP_PATH/var >/dev/null 2>&1 + echo "${key}=\"${val}\"" >> $TMP_PATH/var + eval ${key}=\"${val}\" + } +} + +get_cache_var() { + local key="${1}" + [ -n "${key}" ] && [ -s "$TMP_PATH/var" ] && { + echo $(cat $TMP_PATH/var | grep "^${key}=" | awk -F '=' '{print $2}' | tail -n 1 | awk -F'"' '{print $2}') + } +} + +#uci_get_by_port() { +# local port=$1 +# while netstat -tuln 2>/dev/null | grep -q ":${port} "; do +# port=$((port + 1)) +# done +# echo $port + +uci_get_by_port() { + local default_start_port=2001 + local min_port=1025 + local max_port=49151 + local port="$1" + local protocol=$(echo "$2" | tr 'A-Z' 'a-z') + local LOCK_FILE="${LOCK_PATH}/${CONFIG}_get_prot.lock" + while ! mkdir "$LOCK_FILE" 2>/dev/null; do + sleep 1 + done + if [ "$port" = "auto" ]; then + local now last_time diff last_port + now=$(date +%s 2>/dev/null) + last_time=$(get_cache_var "last_get_new_port_time") + if [ -n "$now" ] && [ -n "$last_time" ]; then + diff=$(expr "$now" - "$last_time") + [ "$diff" -lt 0 ] && diff=$(expr 0 - "$diff") + else + diff=999 + fi + if [ "$diff" -gt 10 ]; then + port=$default_start_port + else + last_port=$(get_cache_var "last_get_new_port_auto") + if [ -n "$last_port" ]; then + port=$(expr "$last_port" + 1) + else + port=$default_start_port + fi + fi + fi + [ "$port" -lt $min_port -o "$port" -gt $max_port ] && port=$default_start_port + local start_port="$port" + while :; do + if [ "$(check_port_exists "$port" "$protocol")" = 0 ]; then + break + fi + port=$(expr "$port" + 1) + if [ "$port" -gt $max_port ]; then + port=$min_port + fi + [ "$port" = "$start_port" ] && { + rmdir "$LOCK_FILE" 2>/dev/null + return 1 + } + done + if [ "$1" = "auto" ]; then + set_cache_var "last_get_new_port_auto" "$port" + [ -n "$now" ] && set_cache_var "last_get_new_port_time" "$now" + fi + rmdir "$LOCK_FILE" 2>/dev/null + echo "$port" +} + +url_test_hy2() { + local node_id=$1 + + # 读取配置 + local server=$(uci_get_by_name ${node_id} server) + local port=$(uci_get_by_name ${node_id} server_port) + local auth=$(uci_get_by_name ${node_id} hy2_auth) + local tls=$(uci_get_by_name ${node_id} tls) + local insecure=$(uci_get_by_name ${node_id} insecure) + local tls_host=$(uci_get_by_name ${node_id} tls_host) + + # 获取本地端口 + # local tmp_port=$(uci_get_by_port 48900 tcp,udp) + local tmp_port=$(uci_get_by_port auto tcp,udp) + + # 生成Hysteria2配置文件 + local config_file="/tmp/hy2_test_${node_id}.yaml" + cat > "$config_file" <<-EOF + server: ${server}:${port} + auth: "${auth}" + tls: + insecure: true + EOF + + # 如果 tls_host 非空,动态添加 sni 行 + [ -n "$tls_host" ] && echo " sni: \"${tls_host}\"" >> "$config_file" + + # 追加 socks5 监听配置 + cat >> "$config_file" <<-EOF + socks5: + listen: 127.0.0.1:${tmp_port} + EOF + + # echo "Debug: 配置文件已生成: $config_file" >&2 + + # 启动Hysteria2客户端 + hysteria client --disable-update-check -c "$config_file" >/dev/null 2>&1 & + local pid=$! + echo $pid > "/tmp/hy2_test_${node_id}.pid" + + # 等待端口启动 + sleep 1 + + # 测试代理 + # local result=$(curl --connect-timeout 3 --max-time 3 -s -o /dev/null -I -w "%{http_code}:%{time_pretransfer}" --socks5 127.0.0.1:${tmp_port} "${probeUrl}" 2>/dev/null) + local curlx="socks5h://127.0.0.1:${tmp_port}" + local probeUrl=$(uci_get_by_type server_subscribe url_test_url https://www.google.com/generate_204) + local result=$(curl --connect-timeout 3 --max-time 5 -o /dev/null -I -skL -w "%{http_code}:%{time_pretransfer}" -x ${curlx} "${probeUrl}" 2>/dev/null) + + # 清理 + # kill -9 $pid 2>/dev/null + local pid_file="/tmp/hy2_test_${node_id}.pid" + [ -s "$pid_file" ] && kill -9 "$(head -n 1 "$pid_file")" >/dev/null 2>&1 + pgrep -af "hysteria.*${config_file}" | awk '! /test\.sh/{print $1}' | xargs kill -9 >/dev/null 2>&1 + rm -f "$config_file" "$pid_file" + + echo $result +} + +case $1 in + url_test_hy2) + url_test_hy2 $2 + ;; +esac \ No newline at end of file diff --git a/luci-app-ssr-plus/root/usr/share/shadowsocksr/shadowsocksr.config b/luci-app-ssr-plus/root/usr/share/shadowsocksr/shadowsocksr.config index 6d1d5ac1..ded6977f 100644 --- a/luci-app-ssr-plus/root/usr/share/shadowsocksr/shadowsocksr.config +++ b/luci-app-ssr-plus/root/usr/share/shadowsocksr/shadowsocksr.config @@ -1,35 +1,35 @@ config global option global_server 'nil' + option netflix_server 'nil' + option netflix_proxy '0' option threads '0' option run_mode 'router' option dports '2' option custom_ports '80,443' option pdnsd_enable '1' - option filter_aaaa '1' + option prefer_nft '1' option tunnel_forward '8.8.4.4:53' option monitor_enable '1' option enable_switch '1' option switch_time '667' option switch_timeout '5' option switch_try_count '3' - option default_node_local_port '1234' - option component_mirror 'direct' + option shunt_dns '1' option gfwlist_url 'https://fastly.jsdelivr.net/gh/YW5vbnltb3Vz/domain-list-community@release/gfwlist.txt' option chnroute_url 'https://ispip.clang.cn/all_cn.txt' + option nfip_url 'https://fastly.jsdelivr.net/gh/QiuSimons/Netflix_IP/NF_only.txt' option adblock_url 'https://anti-ad.net/anti-ad-for-dnsmasq.conf' config server_subscribe - option proxy '1' + option proxy '0' option auto_update '1' - option config_auto_update_mode '0' - option config_update_interval '60' option auto_update_week_time '*' option auto_update_day_time '2' option auto_update_min_time '0' option url_test_url 'https://www.google.com/generate_204' option user_agent 'v2rayN/9.99' - option filter_words '过期/套餐/剩余/网址/QQ群/官网/防失联/回国' + option filter_words '过期/套餐/剩余/QQ群/官网/防失联/回国' config access_control option lan_ac_mode '0' @@ -47,11 +47,6 @@ config socks5_proxy option server 'nil' option local_port '1080' -config http_proxy - option server 'nil' - option local_port '3128' - option http_auth 'none' - config server_global option enable_server '0' @@ -59,9 +54,3 @@ config global_xray_fragment option fragment '0' option noise '0' -config clash_client_group - option enabled '0' - option remarks '' - option ip_addr '' - option client_mac '' - option policy_group '' diff --git a/luci-app-ssr-plus/root/usr/share/shadowsocksr/ssrplusupdate.sh b/luci-app-ssr-plus/root/usr/share/shadowsocksr/ssrplusupdate.sh index 9c69b511..9424cfac 100755 --- a/luci-app-ssr-plus/root/usr/share/shadowsocksr/ssrplusupdate.sh +++ b/luci-app-ssr-plus/root/usr/share/shadowsocksr/ssrplusupdate.sh @@ -1,43 +1,6 @@ #!/bin/sh -LOCK_DIR="/var/run/ssrplusupdate.lock" -LOOP_STAMP="/var/run/ssrplusupdate.loop" -MODE="$(uci -q get shadowsocksr.@server_subscribe[0].config_auto_update_mode 2>/dev/null || echo 0)" - -mkdir "$LOCK_DIR" 2>/dev/null || exit 0 -trap 'rmdir "$LOCK_DIR" 2>/dev/null' EXIT INT TERM - -if [ "$1" = "loop" ]; then - [ "$(uci -q get shadowsocksr.@server_subscribe[0].auto_update 2>/dev/null || echo 0)" = "1" ] || exit 0 - [ "$MODE" = "1" ] || exit 0 - - INTERVAL="$(uci -q get shadowsocksr.@server_subscribe[0].config_update_interval 2>/dev/null || echo 60)" - case "$INTERVAL" in - ''|*[!0-9]*) - INTERVAL=60 - ;; - esac - [ "$INTERVAL" -gt 0 ] 2>/dev/null || INTERVAL=60 - - NOW="$(date +%s)" - LAST_RUN=0 - [ -f "$LOOP_STAMP" ] && LAST_RUN="$(cat "$LOOP_STAMP" 2>/dev/null || echo 0)" - case "$LAST_RUN" in - ''|*[!0-9]*) - LAST_RUN=0 - ;; - esac - - if [ $((NOW - LAST_RUN)) -lt $((INTERVAL * 60)) ]; then - exit 0 - fi -fi - /usr/bin/lua /usr/share/shadowsocksr/update.lua sleep 2s /usr/share/shadowsocksr/chinaipset.sh /var/etc/ssrplus/china_ssr.txt sleep 2s /usr/bin/lua /usr/share/shadowsocksr/subscribe.lua - -if [ "$1" = "loop" ]; then - date +%s > "$LOOP_STAMP" -fi diff --git a/luci-app-ssr-plus/root/usr/share/shadowsocksr/subscribe.lua b/luci-app-ssr-plus/root/usr/share/shadowsocksr/subscribe.lua index 05acd8b7..251ad828 100755 --- a/luci-app-ssr-plus/root/usr/share/shadowsocksr/subscribe.lua +++ b/luci-app-ssr-plus/root/usr/share/shadowsocksr/subscribe.lua @@ -23,37 +23,35 @@ local nodeResult = setmetatable({}, {__index = cache}) -- update result local name = 'shadowsocksr' local uciType = 'servers' local ucic = require "luci.model.uci".cursor() -local proxy = ucic:get_first(name, 'server_subscribe', 'proxy', '0') -local switch = ucic:get_first(name, 'server_subscribe', 'switch', '1') -local allow_insecure = ucic:get_first(name, 'server_subscribe', 'allow_insecure', '0') -local filter_words = ucic:get_first(name, 'server_subscribe', 'filter_words', '过期/套餐/剩余/网址/QQ群/官网/防失联/回国') -local save_words = ucic:get_first(name, 'server_subscribe', 'save_words', '') -local user_agent = ucic:get_first(name, 'server_subscribe', 'user_agent', 'v2rayN/9.99') -local local_clash_dir = "/etc/ssrplus/clash" -local target_subscribe_sid = tostring(arg and arg[1] or ""):gsub("^%s*(.-)%s*$", "%1") +local proxy = ucic:get_first(name, 'server_subscribe', 'proxy') or '0' +local switch = ucic:get_first(name, 'server_subscribe', 'switch') or '1' +local allow_insecure = ucic:get_first(name, 'server_subscribe', 'allow_insecure') or '0' +local subscribe_url = ucic:get_first(name, 'server_subscribe', 'subscribe_url') or {} +local filter_words = ucic:get_first(name, 'server_subscribe', 'filter_words') or '过期时间/剩余流量' +local save_words = ucic:get_first(name, 'server_subscribe', 'save_words') or '' +local user_agent = ucic:get_first(name, 'server_subscribe', 'user_agent') or 'v2rayN/9.99' +local domain_resolver = ucic:get_first(name, 'server_subscribe', 'domain_resolver') or '' +local domain_resolver_dns = ucic:get_first(name, 'server_subscribe', 'domain_resolver_dns') or '' +local domain_resolver_dns_https = ucic:get_first(name, 'server_subscribe', 'domain_resolver_dns_https') or '' +local domain_strategy = ucic:get_first(name, 'server_subscribe', 'domain_strategy') or '' + +-- 读取 ss_type 设置 +local ss_type = ucic:get_first(name, 'server_subscribe', 'ss_type') or '' +-- 读取 xray_hy2_type 设置 +local xray_hy2_type = ucic:get_first(name, 'server_subscribe', 'xray_hy2_type') or '' +-- 读取 xray_tj_type 设置 +local xray_tj_type = ucic:get_first(name, 'server_subscribe', 'xray_tj_type') or '' local has_ss_rust = luci.sys.exec('type -t -p sslocal 2>/dev/null || type -t -p ssserver 2>/dev/null') ~= "" +local has_ss_libev = luci.sys.exec('type -t -p ss-redir 2>/dev/null || type -t -p ss-local 2>/dev/null') ~= "" +local has_hysteria = luci.sys.exec('type -t -p hysteria 2>/dev/null') ~= "" +local has_trojan = luci.sys.exec('type -t -p trojan 2>/dev/null') ~= "" local has_xray = luci.sys.exec('type -t -p xray 2>/dev/null') ~= "" -local has_mihomo = luci.sys.exec('type -t -p mihomo -p /usr/libexec/mihomo 2>/dev/null') ~= "" -local tuic_type = luci.sys.exec('type -t -p mihomo -p /usr/libexec/mihomo 2>/dev/null') ~= "" and "tuic" +local tuic_type = luci.sys.exec('type -t -p tuic-client') ~= "" and "tuic" local log = function(...) print(os.date("%Y-%m-%d %H:%M:%S ") .. table.concat({...}, " ")) end - -local function preferred_ss_backend() - if has_mihomo then - return "ss" - end - if has_ss_rust then - return "ss-rust" - end - if has_xray then - return "v2ray" - end - return nil -end - local encrypt_methods_ss = { -- plain "none", @@ -139,128 +137,6 @@ local function trim(text) end return (sgsub(text, "^%s*(.-)%s*$", "%1")) end - -local function shell_quote(value) - value = tostring(value or "") - return "'" .. value:gsub("'", "'\\''") .. "'" -end - -local function nft_string_literal(value) - value = tostring(value or "") - value = value:gsub("\\", "\\\\"):gsub('"', '\\"') - return '"' .. value .. '"' -end - -local function escape_lua_pattern(value) - return tostring(value or ""):gsub("([%(%)%.%%%+%-%*%?%[%]%^%$])", "%%%1") -end - -local function is_true_value(v) - if v == nil then - return false - end - if v == true then - return true - end - if type(v) == "string" then - local s = trim(string.lower(v)) - return s == "1" or s == "true" or s == "yes" or s == "on" - end - return false -end - -local function collect_subscribe_items() - local items = {} - - ucic:foreach(name, "server_subscribe_item", function(s) - if target_subscribe_sid ~= "" and s[".name"] ~= target_subscribe_sid then - return - end - - local url = trim(s.url or "") - if url == "" then - return - end - - if target_subscribe_sid == "" and not is_true_value(s.enabled or "1") then - return - end - - items[#items + 1] = { - sid = s[".name"], - alias = trim(s.alias or ""), - url = url - } - end) - - if #items > 0 then - return items - end - - if target_subscribe_sid ~= "" then - return items - end - - local legacy_urls = ucic:get_first(name, 'server_subscribe', 'subscribe_url', {}) - for index, url in ipairs(legacy_urls or {}) do - url = trim(url) - if url ~= "" then - items[#items + 1] = { - sid = "legacy_" .. index, - alias = "Legacy " .. index, - url = url - } - end - end - - return items -end - -local subscribe_items = collect_subscribe_items() - -local function first_nonempty(tbl, keys) - for _, key in ipairs(keys) do - local value = tbl[key] - if value ~= nil and value ~= "" then - return value - end - end - return nil -end - -local function normalize_host(value) - value = trim(value or "") - if value == "" then - return value - end - if value:match("^%[.*%]$") then - return value:sub(2, -2) - end - return value -end - -local function parse_host_port(value, default_port) - value = trim(value or "") - if value == "" then - return nil, default_port - end - - local host, port = value:match("^%[(.*)%]:(%d+)$") - if host then - return normalize_host(host), port - end - - host, port = value:match("^(.-):(%d+)$") - if host and host ~= "" and not host:find(":", 1, true) then - return normalize_host(host), port - end - - if value:find(":", 1, true) then - return normalize_host(value), default_port - end - - return normalize_host(value), default_port -end -- md5 local function md5(content) local stdout = luci.sys.exec('echo \"' .. urlEncode(content) .. '\" | md5sum | cut -d \" \" -f1') @@ -320,174 +196,9 @@ local function isCompleteJSON(str) local success, _ = pcall(jsonParse, str) return success end - -local function isClashYAML(str) - if type(str) ~= "string" or str:match("^%s*$") then - return false - end - - for line in str:gmatch("[^\r\n]+") do - if line:match("^%s*proxies%s*:") or line:match("^%s*proxy%-providers%s*:") then - return true - end - end - - return false -end - -local function processClashSubscription(url) - local ok, parsed = pcall(URL.parse, url) - if not ok or not parsed or not parsed.host then - return nil - end - - local alias = "Clash_" .. parsed.host - local server_port = parsed.port or ((parsed.scheme == "http") and "80" or "443") - local result = { - type = "clash", - server = normalize_host(parsed.host), - server_port = server_port, - clash_url = url, - clash_user_agent = user_agent, - raw_alias = alias, - alias = alias - } - - local saved_alias = result.alias - result.alias = nil - result.hashkey = md5(jsonStringify(result) .. "_" .. (saved_alias or "")) - result.alias = saved_alias - return result -end - -local function yaml_quote(str) - str = tostring(str or "") - str = str:gsub("\\", "\\\\"):gsub('"', '\\"') - return '"' .. str .. '"' -end - -local function is_ip_literal(value) - if not value or value == "" then - return false - end - - if value:match("^%d+%.%d+%.%d+%.%d+$") then - return true - end - - return value:find(":", 1, true) ~= nil -end - -local function parseAnytlsShare(content) - local alias = "" - if content:find("#", 1, true) then - local idx = content:find("#", 1, true) - alias = UrlDecode(content:sub(idx + 1)) - content = content:sub(1, idx - 1) - end - - local main, query = content, "" - if content:find("%?", 1) then - local idx = content:find("%?", 1) - main = content:sub(1, idx - 1) - query = content:sub(idx + 1) - end - - local userinfo, hostinfo = main:match("^([^@]+)@(.+)$") - if not userinfo or not hostinfo then - return nil - end - - local password = UrlDecode(userinfo) - local server, port = hostinfo:match("^(.+):(%d+)$") - if not server or not port then - server = hostinfo - port = "443" - end - server = server:gsub("^%[", ""):gsub("%]$", "") - - local params = {} - for _, v in ipairs(split(query, "&")) do - local t = split(v, "=") - if #t > 1 then - params[string.lower(t[1])] = UrlDecode(t[2] or "") - end - end - - return { - name = (alias ~= "" and alias) or (server .. ":" .. port), - server = server, - port = tonumber(port), - password = password, - sni = (function() - local sni = params.sni or params.servername or "" - if is_ip_literal(sni) then - return "" - end - return sni - end)(), - allow_insecure = (params.insecure == "1" or params.allow_insecure == "1" or params.allowinsecure == "1"), - client_fingerprint = params.fp or params.fingerprint or "" - } -end - -local function buildAnytlsClashYaml(entries, group_name) - local lines = { - "mode: rule", - "log-level: silent", - "proxies:" - } - - for _, node in ipairs(entries) do - lines[#lines + 1] = " - name: " .. yaml_quote(node.name) - lines[#lines + 1] = " type: anytls" - lines[#lines + 1] = " server: " .. yaml_quote(node.server) - lines[#lines + 1] = " port: " .. tostring(node.port) - lines[#lines + 1] = " password: " .. yaml_quote(node.password) - if node.sni and node.sni ~= "" then - lines[#lines + 1] = " sni: " .. yaml_quote(node.sni) - end - if node.allow_insecure then - lines[#lines + 1] = " skip-cert-verify: true" - end - if node.client_fingerprint and node.client_fingerprint ~= "" then - lines[#lines + 1] = " client-fingerprint: " .. yaml_quote(node.client_fingerprint) - end - end - - lines[#lines + 1] = "proxy-groups:" - lines[#lines + 1] = " - name: " .. yaml_quote(group_name) - lines[#lines + 1] = " type: select" - lines[#lines + 1] = " proxies:" - for _, node in ipairs(entries) do - lines[#lines + 1] = " - " .. yaml_quote(node.name) - end - lines[#lines + 1] = "rules:" - lines[#lines + 1] = " - MATCH," .. group_name - - return table.concat(lines, "\n") .. "\n" -end - -local function processLocalClashSubscription(path, alias) - local result = { - type = "clash", - server = "127.0.0.1", - server_port = "0", - clash_path = path, - clash_user_agent = user_agent, - raw_alias = alias, - alias = alias - } - - local saved_alias = result.alias - result.alias = nil - result.hashkey = md5(jsonStringify(result) .. "_" .. (saved_alias or "")) - result.alias = saved_alias - return result -end -- 处理数据 local function processData(szType, content, cfgid) - local result = {type = szType, kcp_param = '--nocomp'} + local result = {type = szType, local_port = 1234, kcp_param = '--nocomp'} -- 检查JSON的格式如不完整丢弃 if not (szType == "sip008" or szType == "ssd") then if not isCompleteJSON(content) then @@ -499,45 +210,115 @@ local function processData(szType, content, cfgid) local url = URL.parse("http://" .. content) local params = url.query - if not has_xray then + -- 调试输出所有参数 + -- log("Hysteria2 原始参数:") + -- for k,v in pairs(params) do + -- log(k.."="..v) + -- end + + -- 自动决定模式(true=Xray, false=普通) + local xray_hy2_mode = false -- 默认普通模式 + if xray_hy2_type == "v2ray" then + -- Xray 模式 + if has_xray then + xray_hy2_mode = true + elseif has_hysteria then + xray_hy2_mode = false -- 回退到普通 Hysteria2 + else + xray_hy2_mode = nil + end + elseif xray_hy2_type == "hysteria2" then + -- 普通 Hysteria2 模式 + if has_hysteria then + xray_hy2_mode = false + elseif has_xray then + xray_hy2_mode = true -- 回退到 Xray + else + xray_hy2_mode = nil + end + else + -- auto 或空:优先普通 Hysteria2,若不存在则使用 Xray + if has_hysteria then + xray_hy2_mode = false + elseif has_xray then + xray_hy2_mode = true -- 回退到 Xray + else + xray_hy2_mode = nil + end + end + + -- 如果无法确定模式,跳过该订阅 + if xray_hy2_mode == nil then return nil end - - result.type = "v2ray" - result.v2ray_protocol = "hysteria2" - if params.fm and params.fm ~= "" then - result.enable_finalmask = "1" - result.finalmask = base64Encode(params.fm) - end - if (params.security and params.security:lower() == "tls") - or (params.sni and params.sni ~= "") - or (params.alpn and params.alpn ~= "") - or (params.pcs or params.vcn) then - result.tls = "1" - if params.sni then - result.tls_host = params.sni + + if xray_hy2_mode then + result.type = "v2ray" + result.v2ray_protocol = "hysteria2" + if params.fm and params.fm ~= "" then + result.enable_finalmask = "1" + result.finalmask = base64Encode(params.fm) end - if params.alpn and params.alpn ~= "" then - local alpn = {} - for v in params.alpn:gmatch("[^,;|%s]+") do - table.insert(alpn, v) + if (params.security and params.security:lower() == "tls") + or (params.sni and params.sni ~= "") + or (params.alpn and params.alpn ~= "") + or (params.pcs or params.vcn) then + result.tls = "1" + if params.sni then + result.tls_host = params.sni end - if #alpn > 0 then - result.tls_alpn = table.concat(alpn, ",") + if params.alpn and params.alpn ~= "" then + local alpn = {} + for v in params.alpn:gmatch("[^,;|%s]+") do + table.insert(alpn, v) + end + if #alpn > 0 then + result.tls_alpn = table.concat(alpn, ",") -- 确保为字符串 + end + end + if params.pcs then + result.tls_CertSha = params.pcs + end + if params.vcn then + result.tls_CertByName = params.vcn end end - if params.pcs then - result.tls_CertSha = params.pcs + else + result.type = "hysteria2" + if params.protocol and params.protocol ~= "" then + result.flag_transport = "1" + result.transport_protocol = params.protocol + else + result.flag_transport = "1" + result.transport_protocol = "udp" end - if params.vcn then - result.tls_CertByName = params.vcn + if params.lazy and params.lazy ~= "" then + result.lazy_mode = "1" + end + if (params.sni and params.sni ~= "") or (params.alpn and params.alpn ~= "") then + result.tls = "1" + if params.sni then + result.tls_host = params.sni + end + if params.alpn and params.alpn ~= "" then + local alpn = {} + for v in params.alpn:gmatch("[^,;|%s]+") do + table.insert(alpn, v) + end + if #alpn > 0 then + result.tls_alpn = table.concat(alpn, ",") -- 确保为字符串 + end + end + end + if params.pinSHA256 and params.pinSHA256 ~= "" then + result.pinsha256 = params.pinSHA256 end end local raw_alias = url.fragment and UrlDecode(url.fragment) or nil result.raw_alias = raw_alias -- 新增 result.alias = raw_alias -- 临时赋值(后面会被覆盖) - result.server = normalize_host(url.host) + result.server = url.host result.server_port = url.port or 443 result.hy2_auth = url.user @@ -566,22 +347,15 @@ local function processData(szType, content, cfgid) -- 去掉前后空白和#注释 local link = trim(content:gsub("#.*$", "")) local dat = split(link, "/%?") - local host, port, rest - local hostinfo = dat[1] or '' - if hostinfo:find("^%[.*%]:") then - host, port, rest = hostinfo:match("^%[(.*)%]:(%d+):(.*)$") - else - host, port, rest = hostinfo:match("^(.-):(%d+):(.*)$") - end + local hostInfo = split(dat[1] or '', ':') result.type = 'ssr' - local ssr_parts = split(rest or '', ':') - result.server = normalize_host(host or '') - result.server_port = port or '' - result.protocol = ssr_parts[1] or '' - result.encrypt_method = ssr_parts[2] or '' - result.obfs = ssr_parts[3] or '' - result.password = base64Decode(ssr_parts[4] or '') + result.server = hostInfo[1] or '' + result.server_port = hostInfo[2] or '' + result.protocol = hostInfo[3] or '' + result.encrypt_method = hostInfo[4] or '' + result.obfs = hostInfo[5] or '' + result.password = base64Decode(hostInfo[6] or '') local params = {} if dat[2] and dat[2] ~= '' then @@ -605,7 +379,7 @@ local function processData(szType, content, cfgid) local remarks = base64Decode(params.remarks or '') -- 拼接 alias - local raw_alias = "" + local alias = "" if group ~= "" then raw_alias = "[" .. group .. "] " end @@ -782,11 +556,60 @@ local function processData(szType, content, cfgid) result.fast_open = params.tfo end - local selected_ss_backend = preferred_ss_backend() - local xray_ss_mode = (selected_ss_backend == "v2ray") + -- 自动决定模式(true=Xray, false=普通 SS) + local xray_ss_mode = false + if ss_type == "v2ray" then + -- Xray 模式 + if has_xray then + xray_ss_mode = true + elseif has_ss_rust or has_ss_libev then + xray_ss_mode = false -- 回退到普通 SS + else + xray_ss_mode = nil + end + elseif ss_type == "ss-rust" or ss_type == "ss-libev" then + -- 普通 SS 模式 + local user_core = (ss_type == "ss-rust" and has_ss_rust) or (ss_type == "ss-libev" and has_ss_libev) + if user_core then + xray_ss_mode = false -- 否则普通 SS + else + -- 指定的核心不存在,尝试另一个 SS 核心 + local other_core = (ss_type == "ss-rust" and has_ss_libev) or (ss_type == "ss-libev" and has_ss_rust) + if other_core then + xray_ss_mode = false -- 使用存在的另一个 SS 核心 + elseif has_xray then + xray_ss_mode = true -- 回退到 Xray + else + xray_ss_mode = nil + end + end + else + -- ss_type 为空或 auto:根据链接中是否有 type 参数决定 + local has_type = params.type and params.type ~= "" + if has_type then + -- 有 type 参数,优先 Xray + if has_xray then + xray_ss_mode = true + elseif has_ss_rust or has_ss_libev then + xray_ss_mode = false -- 回退到普通 SS + else + xray_ss_mode = nil + end + else + -- 无 type 参数,优先普通 SS + if has_ss_rust or has_ss_libev then + -- 普通 SS 模式 + xray_ss_mode = false + elseif has_xray then + xray_ss_mode = true -- 回退到 Xray + else + xray_ss_mode = nil + end + end + end -- 如果最终无可用核心,跳过该订阅 - if selected_ss_backend == nil then + if xray_ss_mode == nil then return nil end @@ -796,7 +619,7 @@ local function processData(szType, content, cfgid) result.type = "v2ray" result.v2ray_protocol = "shadowsocks" - result.server = normalize_host(url.host) + result.server = url.host result.server_port = url.port -- 判断 @ 前部分是否为 Base64 @@ -853,7 +676,7 @@ local function processData(szType, content, cfgid) -- 检查 finalmaskg 参数是否存在且非空 if params.fm and params.fm ~= "" then result.enable_finalmask = "1" - result.finalmask = base64Encode(params.fm) + result.finalmaskg = base64Encode(params.fm) end -- 检查 pqv 参数是否存在且非空 if params.pqv and params.pqv ~= "" then @@ -983,7 +806,13 @@ local function processData(szType, content, cfgid) end -- 填充 result - result.type = selected_ss_backend + local xray_ss_type + if ss_type == "ss-rust" or ss_type == "ss-libev" then + xray_ss_type = ss_type + else + xray_ss_type = has_ss_rust and "ss-rust" or "ss-libev" + end + result.type = xray_ss_type result.encrypt_method_ss = method result.password = password result.server = server @@ -1008,7 +837,7 @@ local function processData(szType, content, cfgid) if result.plugin ~= "none" and result.plugin ~= "" then result.enable_plugin = 1 end - else + elseif has_ss_type and has_ss_type ~= "ss-libev" then if params["shadow-tls"] then -- 特别处理 shadow-tls 作为插件 -- log("原始 shadow-tls 参数:", params["shadow-tls"]) @@ -1034,6 +863,11 @@ local function processData(szType, content, cfgid) end end end + else + if params["shadow-tls"] then + log("错误:ShadowSocks-libev 不支持使用 shadow-tls 插件") + return nil, "ShadowSocks-libev 不支持使用 shadow-tls 插件" + end end -- 检查加密方法是否受支持 @@ -1044,13 +878,12 @@ local function processData(szType, content, cfgid) end end elseif szType == "sip008" then - local selected_ss_backend = preferred_ss_backend() - if not selected_ss_backend then - return nil - end - result.type = selected_ss_backend - if selected_ss_backend == "v2ray" then - result.v2ray_protocol = "shadowsocks" + result.type = v2_ss + if v2_ss ~= "v2ray" then + result.has_ss_type = has_ss_type + else + result.xray_has_ss_type = "v2ray" + result.v2ray_protocol = has_v2_ss_type end result.server = content.server result.server_port = content.server_port @@ -1064,13 +897,12 @@ local function processData(szType, content, cfgid) result.server = nil end elseif szType == "ssd" then - local selected_ss_backend = preferred_ss_backend() - if not selected_ss_backend then - return nil - end - result.type = selected_ss_backend - if selected_ss_backend == "v2ray" then - result.v2ray_protocol = "shadowsocks" + result.type = v2_ss + if v2_ss ~= "v2ray" then + result.has_ss_type = has_ss_type + else + result.xray_has_ss_type = "v2ray" + result.v2ray_protocol = has_v2_ss_type end result.server = content.server result.server_port = content.port @@ -1120,7 +952,13 @@ local function processData(szType, content, cfgid) end -- 提取服务器地址和端口 - result.server, result.server_port = parse_host_port(host_port, "443") + if host_port:find(":") then + local sp = split(host_port, ":") + result.server_port = sp[#sp] + result.server = sp[1] + else + result.server = host_port + end -- 默认设置 -- 按照官方的建议 默认验证ssl证书 @@ -1139,23 +977,14 @@ local function processData(szType, content, cfgid) end end - do - local tls_host = first_nonempty(params, {"peer", "sni", "host"}) - if tls_host then - -- 未指定 peer/sni 时,兼容使用 host 作为 TLS Host - result.tls_host = tls_host - end + if params.peer or params.sni then + -- 未指定peer(sni)默认使用remote addr + result.tls_host = params.peer or params.sni end -- 处理 insecure 参数 - do - local insecure = first_nonempty(params, { - "allowInsecure", - "allowinsecure", - "allow_insecure", - "insecure", - "skip-cert-verify" - }) - if is_true_value(insecure) then + if params.allowInsecure or params.allowinsecure or params.insecure then + local insecure = params.allowInsecure or params.allowinsecure or params.insecure + if insecure == true or insecure == "1" or insecure == "true" then result.insecure = "1" end end @@ -1168,88 +997,136 @@ local function processData(szType, content, cfgid) end -- 自动决定模式(true=Xray, false=普通 Trojan) - if not has_xray then + local xray_tj_mode = false + if xray_tj_type == "v2ray" then + -- Xray 模式 + if has_xray then + xray_tj_mode = true + elseif has_trojan then + xray_tj_mode = false -- 回退到普通 Trojan + else + xray_tj_mode = nil -- 两类核心均不存在,停止订阅 + end + elseif xray_tj_type == "trojan" then + -- 普通 Trojan 模式 + if has_trojan then + xray_tj_mode = false + elseif has_xray then + xray_tj_mode = true -- 回退到 Xray + else + xray_tj_mode = nil -- 两类核心均不存在,停止订阅 + end + else + -- 全局配置为空或 auto,根据链接中是否有 type 参数决定 + local has_type = params.type and params.type ~= "" + -- 有 type 参数,优先 Xray + if has_type then + if has_xray then + xray_tj_mode = true -- 有 type 参数使用 Xray + elseif has_trojan then + xray_tj_mode = false -- 否则普通 Trojan + else + xray_tj_mode = nil -- 两类核心均不存在,停止订阅 + end + else + -- 无 type 参数,优先普通 Trojan + if has_trojan then + xray_tj_mode = false -- 普通 Trojan + elseif has_xray then + xray_tj_mode = true -- 否则使用 Xray + else + xray_tj_mode = nil -- 两类核心均不存在,停止订阅 + end + end + end + + -- 如果最终无可用核心,跳过该订阅 + if xray_tj_mode == nil then return nil end - result.type = "v2ray" - result.v2ray_protocol = "trojan" - if params.fp then - -- 处理 fingerprint 参数 - result.fingerprint = params.fp - end - -- 处理 ech 参数 - if params.ech and params.ech ~= "" then - result.enable_ech = "1" - result.ech_config = params.ech - end - -- 检查 finalmaskg 参数是否存在且非空 - if params.fm and params.fm ~= "" then - result.enable_finalmask = "1" - result.finalmask = base64Encode(params.fm) - end - -- 处理传输协议 - result.transport = params.type or "raw" -- 默认传输协议为 raw - if result.transport == "tcp" then - result.transport = "raw" - end - if result.transport == "splithttp" then - result.transport = "xhttp" - end - if params.pcs and params.pcs ~= "" then - result.tls_CertSha = params.pcs - end - if params.vcn and params.vcn ~= "" then - result.tls_CertByName = params.vcn - end - if result.transport == "ws" then - result.ws_host = (result.tls ~= "1") and (params.host and UrlDecode(params.host)) or nil - result.ws_path = params.path and UrlDecode(params.path) or "/" - elseif result.transport == "httpupgrade" then - result.httpupgrade_host = (result.tls ~= "1") and (params.host and UrlDecode(params.host)) or nil - result.httpupgrade_path = params.path and UrlDecode(params.path) or "/" - elseif result.transport == "xhttp" or result.transport == "splithttp" then - result.xhttp_mode = params.mode or "auto" - result.xhttp_host = params.host and UrlDecode(params.host) or nil - result.xhttp_path = params.path and UrlDecode(params.path) or "/" - -- 检查 extra 参数是否存在且非空 - if params.extra and params.extra ~= "" then - result.enable_xhttp_extra = "1" - result.xhttp_extra = base64Encode(params.extra) + if xray_tj_mode then + result.type = "v2ray" + result.v2ray_protocol = "trojan" + if params.fp then + -- 处理 fingerprint 参数 + result.fingerprint = params.fp end - -- 尝试解析 JSON 数据 - local success, Data = pcall(jsonParse, params.extra or "") - if success and type(Data) == "table" then - local address = (Data.extra and Data.extra.downloadSettings and Data.extra.downloadSettings.address) - or (Data.downloadSettings and Data.downloadSettings.address) - result.download_address = (address and address ~= "") and address:gsub("^%[", ""):gsub("%]$", "") - else - -- 如果解析失败,清空下载地址 - result.download_address = nil + -- 处理 ech 参数 + if params.ech and params.ech ~= "" then + result.enable_ech = "1" + result.ech_config = params.ech end - elseif result.transport == "http" or result.transport == "h2" then - result.transport = "h2" - result.h2_host = params.host and UrlDecode(params.host) or nil - result.h2_path = params.path and UrlDecode(params.path) or nil - elseif result.transport == "kcp" then - result.kcp_guise = params.headerType or "none" - if params.headerType and params.headerType == "dns" then - result.kcp_domain = params.host or "" + -- 检查 finalmaskg 参数是否存在且非空 + if params.fm and params.fm ~= "" then + result.enable_finalmask = "1" + result.finalmaskg = base64Encode(params.fm) end - result.seed = params.seed - elseif result.transport == "quic" then - result.quic_guise = params.headerType or "none" - result.quic_security = params.quicSecurity or "none" - result.quic_key = params.key - elseif result.transport == "grpc" then - result.serviceName = params.serviceName - result.grpc_mode = params.mode or "gun" - elseif result.transport == "tcp" or result.transport == "raw" then - result.tcp_guise = params.headerType and params.headerType ~= "" and params.headerType or "none" - if result.tcp_guise == "http" then - result.tcp_host = params.host and UrlDecode(params.host) or nil - result.tcp_path = params.path and UrlDecode(params.path) or nil + -- 处理传输协议 + result.transport = params.type or "raw" -- 默认传输协议为 raw + if result.transport == "tcp" then + result.transport = "raw" end + if result.transport == "splithttp" then + result.transport = "xhttp" + end + if params.pcs and params.pcs ~= "" then + result.tls_CertSha = params.pcs + end + if params.vcn and params.vcn ~= "" then + result.tls_CertByName = params.vcn + end + if result.transport == "ws" then + result.ws_host = (result.tls ~= "1") and (params.host and UrlDecode(params.host)) or nil + result.ws_path = params.path and UrlDecode(params.path) or "/" + elseif result.transport == "httpupgrade" then + result.httpupgrade_host = (result.tls ~= "1") and (params.host and UrlDecode(params.host)) or nil + result.httpupgrade_path = params.path and UrlDecode(params.path) or "/" + elseif result.transport == "xhttp" or result.transport == "splithttp" then + result.xhttp_mode = params.mode or "auto" + result.xhttp_host = params.host and UrlDecode(params.host) or nil + result.xhttp_path = params.path and UrlDecode(params.path) or "/" + -- 检查 extra 参数是否存在且非空 + if params.extra and params.extra ~= "" then + result.enable_xhttp_extra = "1" + result.xhttp_extra = base64Encode(params.extra) + end + -- 尝试解析 JSON 数据 + local success, Data = pcall(jsonParse, params.extra or "") + if success and type(Data) == "table" then + local address = (Data.extra and Data.extra.downloadSettings and Data.extra.downloadSettings.address) + or (Data.downloadSettings and Data.downloadSettings.address) + result.download_address = (address and address ~= "") and address:gsub("^%[", ""):gsub("%]$", "") + else + -- 如果解析失败,清空下载地址 + result.download_address = nil + end + elseif result.transport == "http" or result.transport == "h2" then + result.transport = "h2" + result.h2_host = params.host and UrlDecode(params.host) or nil + result.h2_path = params.path and UrlDecode(params.path) or nil + elseif result.transport == "kcp" then + result.kcp_guise = params.headerType or "none" + if params.headerType and params.headerType == "dns" then + result.kcp_domain = params.host or "" + end + result.seed = params.seed + elseif result.transport == "quic" then + result.quic_guise = params.headerType or "none" + result.quic_security = params.quicSecurity or "none" + result.quic_key = params.key + elseif result.transport == "grpc" then + result.serviceName = params.serviceName + result.grpc_mode = params.mode or "gun" + elseif result.transport == "tcp" or result.transport == "raw" then + result.tcp_guise = params.headerType and params.headerType ~= "" and params.headerType or "none" + if result.tcp_guise == "http" then + result.tcp_host = params.host and UrlDecode(params.host) or nil + result.tcp_path = params.path and UrlDecode(params.path) or nil + end + end + else + result.type = "trojan" end elseif szType == "vless" then local url = URL.parse("http://" .. content) @@ -1260,7 +1137,7 @@ local function processData(szType, content, cfgid) result.alias = raw_alias -- 临时赋值(后面会被覆盖) result.type = "v2ray" result.v2ray_protocol = "vless" - result.server = normalize_host(url.host) + result.server = url.host result.server_port = url.port result.vmess_id = url.user result.vless_encryption = params.encryption or "none" @@ -1390,11 +1267,6 @@ local function processData(szType, content, cfgid) end end elseif szType == "tuic" then - if not tuic_type then - log("跳过 TUIC 节点:本地未安装 mihomo。") - return nil - end - -- 提取别名(如果存在) local alias = "" if content:find("#") then @@ -1431,7 +1303,13 @@ local function processData(szType, content, cfgid) end -- 提取服务器地址和端口 - result.server, result.server_port = parse_host_port(host_port, "443") + if host_port:find(":") then + local sp = split(host_port, ":") + result.server_port = sp[#sp] + result.server = sp[1] + else + result.server = host_port + end result.type = tuic_type result.tuic_ip = params.ip or "" @@ -1496,10 +1374,6 @@ local function processData(szType, content, cfgid) end end - if not result.type or result.type == "" or result.type == "0" then - return nil - end - if not result.alias then if result.server and result.server_port then result.alias = result.server .. ':' .. result.server_port @@ -1552,256 +1426,51 @@ end -- curl local function curl(url, user_agent) - -- 清理 URL 中的隐藏字符和前后空白 + if not url or url == "" then + return "", nil + end + + -- 清理 URL url = url:gsub("%s+$", ""):gsub("^%s+", ""):gsub("%z", ""):gsub("[\r\n]", "") + -- 处理 user_agent 参数 local ua_opt = "" if user_agent and user_agent ~= "" then - -- 转义双引号,防止破坏 -A 参数 - local safe_ua = user_agent:gsub("[\r\n]", ""):gsub('[\\"`$]', '\\%0') -- 安全转义 - ua_opt = '-A "' .. safe_ua .. '"' + -- 安全 shell quoting + local safe_ua = string.format("%q", user_agent) + ua_opt = "-A " .. safe_ua + else + -- 默认 UA(避免被拦) + ua_opt = '-A "Mozilla/5.0"' end - -- 安全转义 URL:用单引号包裹,并转义内部的单引号 - local safe_url = "'" .. url:gsub("'", "'\\''") .. "'" + local cmd = string.format( - 'curl -sSL --http1.1 --connect-timeout 20 --max-time 30 --retry 3 -H "Accept-Encoding: identity" %s --insecure --location %s', + 'curl -fskL --retry 3 --connect-timeout 3 --max-time 30 ' .. + '-H "Accept-Encoding: identity" %s ' .. + '-w "%%{http_code}" "%s"', ua_opt, - safe_url + url ) - -- 执行命令并获取输出 - local stdout = luci.sys.exec(cmd) - stdout = trim(stdout) -- 确保 trim 函数存在 - local md5 = md5_string(stdout) -- 确保 md5_string 函数存在 + + local result = luci.sys.exec(cmd) or "" + result = trim(result) + + if result == "" then + return "", nil + end + + -- 解析 HTTP code(最后3位) + local stdout = result:sub(1, -4) + local code = tonumber(result:sub(-3)) + + if code ~= 200 then + return "", code + end + + local md5 = md5_string(stdout) return stdout, md5 end -local function collect_wan_interfaces() - local ifaces = {} - local seen = {} - - local function add_iface(value) - value = trim(value or "") - if value == "" or value == "nil" or value:sub(1, 1) == "@" then - return - end - - if value:find("%s") then - for iface in value:gmatch("%S+") do - add_iface(iface) - end - return - end - - if not seen[value] then - seen[value] = true - ifaces[#ifaces + 1] = value - end - end - - local function add_iface_from_status(netif) - local raw = trim(luci.sys.exec(string.format( - "ubus -S call network.interface.%s status 2>/dev/null", - netif - ))) - if raw == "" then - return - end - - local status = jsonParse(raw) - if type(status) ~= "table" then - return - end - - add_iface(status.l3_device) - add_iface(status.device) - end - - add_iface_from_status("wan") - add_iface_from_status("wan6") - - if #ifaces == 0 then - add_iface(ucic:get("network", "wan", "device")) - add_iface(ucic:get("network", "wan", "ifname")) - add_iface(ucic:get("network", "wan6", "device")) - add_iface(ucic:get("network", "wan6", "ifname")) - end - - if #ifaces == 0 then - local route_output = luci.sys.exec("ip route show default 2>/dev/null") - for iface in route_output:gmatch("dev%s+(%S+)") do - add_iface(iface) - end - end - - if #ifaces == 0 then - local route6_output = luci.sys.exec("ip -6 route show default 2>/dev/null") - for iface in route6_output:gmatch("dev%s+(%S+)") do - add_iface(iface) - end - end - - return ifaces -end - -local function detect_subscribe_bypass_backend() - if luci.sys.call("nft list chain inet ss_spec ss_spec_output >/dev/null 2>&1") == 0 then - return "nftables" - end - - local ipt_output = luci.sys.exec("iptables -t nat -S OUTPUT 2>/dev/null") - if ipt_output:find("SS_SPEC_WAN_AC", 1, true) or ipt_output:find("SS_SPEC_ROUTER", 1, true) then - return "iptables" - end - - return nil -end - -local function create_direct_subscribe_bypass() - if proxy ~= "0" then - return nil - end - - local backend = detect_subscribe_bypass_backend() - if not backend then - log("直连订阅: 未检测到 SSR 路由器自身 OUTPUT 代理链,跳过临时绕过规则。") - return nil - end - - local wan_ifaces = collect_wan_interfaces() - local targets = (#wan_ifaces > 0) and wan_ifaces or {false} - local tag = string.format("SSR_SUB_BYPASS_%d", tonumber(nixio.getpid()) or os.time()) - local manager = { - backend = backend, - tag = tag, - targets = targets, - added = false - } - - function manager:describe_target(target) - if target then - return target - end - return "all-output" - end - - function manager:apply_iptables_rule(target) - local cmd = { - "iptables -t nat -I OUTPUT 1" - } - - if target then - cmd[#cmd + 1] = "-o " .. shell_quote(target) - end - - cmd[#cmd + 1] = "-p tcp -m multiport --dports 80,443" - cmd[#cmd + 1] = "-m comment --comment " .. shell_quote(self.tag) - cmd[#cmd + 1] = "-j RETURN >/dev/null 2>&1" - - return luci.sys.call(table.concat(cmd, " ")) == 0 - end - - function manager:apply_nft_rule(target) - local rule = { - "nft insert rule inet ss_spec ss_spec_output" - } - - if target then - rule[#rule + 1] = "oifname " .. nft_string_literal(target) - end - - rule[#rule + 1] = "meta l4proto tcp tcp dport { 80, 443 }" - rule[#rule + 1] = "counter return" - rule[#rule + 1] = "comment " .. nft_string_literal(self.tag) - - return luci.sys.call(table.concat(rule, " ") .. " >/dev/null 2>&1") == 0 - end - - function manager:apply() - for index = #self.targets, 1, -1 do - local target = self.targets[index] - local ok - - if self.backend == "nftables" then - ok = self:apply_nft_rule(target) - else - ok = self:apply_iptables_rule(target) - end - - if ok then - self.added = true - log("直连订阅: 已添加临时绕过规则 -> " .. self.backend .. " / " .. self:describe_target(target)) - else - log("直连订阅: 添加临时绕过规则失败 -> " .. self.backend .. " / " .. self:describe_target(target)) - end - end - - if not self.added then - log("直连订阅: 临时绕过规则未生效,订阅请求仍可能走代理。") - end - end - - function manager:cleanup_nft_rules() - local output = luci.sys.exec("nft -a list chain inet ss_spec ss_spec_output 2>/dev/null") - local pattern = 'comment "' .. escape_lua_pattern(self.tag) .. '".-# handle (%d+)' - local handles = {} - - for handle in output:gmatch(pattern) do - handles[#handles + 1] = handle - end - - for _, handle in ipairs(handles) do - luci.sys.call(string.format( - "nft delete rule inet ss_spec ss_spec_output handle %s >/dev/null 2>&1", - handle - )) - end - - return #handles - end - - function manager:cleanup_iptables_rules() - local removed = 0 - - for _, target in ipairs(self.targets) do - local cmd = { - "iptables -t nat -D OUTPUT" - } - - if target then - cmd[#cmd + 1] = "-o " .. shell_quote(target) - end - - cmd[#cmd + 1] = "-p tcp -m multiport --dports 80,443" - cmd[#cmd + 1] = "-m comment --comment " .. shell_quote(self.tag) - cmd[#cmd + 1] = "-j RETURN >/dev/null 2>&1" - - if luci.sys.call(table.concat(cmd, " ")) == 0 then - removed = removed + 1 - end - end - - return removed - end - - function manager:cleanup() - if not self.added then - return - end - - local removed - if self.backend == "nftables" then - removed = self:cleanup_nft_rules() - else - removed = self:cleanup_iptables_rules() - end - - log("直连订阅: 已清理临时绕过规则数量: " .. tostring(removed or 0)) - self.added = false - end - - return manager -end - local function check_filer(result) -- 过滤的关键词列表 local filter_word = split(filter_words, "/") @@ -1858,76 +1527,11 @@ local function loadOldNodes(groupHash) end) end -local function get_section_ss_backend(section) - if not section then - return nil - end - if section.type == "ss" or section.type == "ss-libev" then - return "ss" - end - if section.type == "ss-rust" then - return "ss-rust" - end - if section.type == "v2ray" and section.v2ray_protocol == "shadowsocks" then - return "v2ray" - end - return nil -end - -local function group_needs_ss_backend_refresh(groupHash) - local preferred = preferred_ss_backend() - local has_ss_node = false - local needs_refresh = false - - if not preferred then - return false - end - - ucic:foreach(name, uciType, function(s) - if s.grouphashkey ~= groupHash then - return - end - - local current = get_section_ss_backend(s) - if current then - has_ss_node = true - if current ~= preferred then - needs_refresh = true - return false - end - end - end) - - return has_ss_node and needs_refresh -end - -local function preserve_unselected_groups(selected_hashes) - local preserved = {} - - ucic:foreach(name, uciType, function(s) - local groupHash = s.grouphashkey - if groupHash and groupHash ~= "" and not selected_hashes[groupHash] and not preserved[groupHash] then - preserved[groupHash] = true - loadOldNodes(groupHash) - end - end) -end - local execute = function() local updated = false - local selected_hashes = {} - - for _, item in ipairs(subscribe_items) do - selected_hashes[md5(item.url)] = true - end - - if target_subscribe_sid ~= "" then - preserve_unselected_groups(selected_hashes) - end - - for _, item in ipairs(subscribe_items) do - local url = item.url - local raw, new_md5 = curl(url, user_agent) + local service_stopped = false + for k, url in ipairs(subscribe_url) do + local raw, new_md5 = curl(url) log("raw 长度: "..#raw) local groupHash = md5(url) local old_md5 = read_old_md5(groupHash) @@ -1937,11 +1541,8 @@ local execute = function() log("old_md5: " .. tostring(old_md5)) log("new_md5: " .. tostring(new_md5)) - local backend_refresh = group_needs_ss_backend_refresh(groupHash) - if #raw == 0 then - log(url .. ': 获取内容为空') - loadOldNodes(groupHash) - elseif old_md5 and new_md5 == old_md5 and not backend_refresh then + if #raw > 0 then + if old_md5 and new_md5 == old_md5 then log("订阅未变化, 跳过无需更新的订阅: " .. url) -- 防止 diff 阶段误删未更新订阅节点 loadOldNodes(groupHash) @@ -1951,34 +1552,26 @@ local execute = function() -- tinsert(nodeResult[index], s) -- end --end) - else - if backend_refresh and old_md5 and new_md5 == old_md5 then - log("检测到 SS 后端偏好变化,强制重建订阅节点: " .. url) - end + else updated = true -- 保存更新后的 MD5 值到以 groupHash 为标识的临时文件中,用于下次订阅更新时进行对比 write_new_md5(groupHash, new_md5) + -- 暂停服务(仅当 MD5 有变化时才执行) + if proxy == '0' and not service_stopped then + log('服务正在暂停') + luci.sys.init.stop(name) + service_stopped = true + end + cache[groupHash] = {} tinsert(nodeResult, {}) local index = #nodeResult local nodes, szType - local is_clash_subscription = false - if isClashYAML(raw) then - is_clash_subscription = true - local result = processClashSubscription(url) - if result and not check_filer(result) and not cache[groupHash][result.hashkey] then - result.grouphashkey = groupHash - table.insert(nodeResult[index], result) - cache[groupHash][result.hashkey] = result - log('成功导入 Clash 总节点: ' .. result.alias) - else - log('丢弃无效 Clash 总节点: ' .. url) - end - -- SSD 似乎是这种格式 ssd:// 开头的 - elseif raw:find('ssd://') then - szType = 'ssd' + -- SSD 似乎是这种格式 ssd:// 开头的 + if raw:find('ssd://') then + szType = 'ssd' local nEnd = select(2, raw:find('ssd://')) nodes = base64Decode(raw:sub(nEnd + 1, #raw)) nodes = jsonParse(nodes) @@ -2006,45 +1599,9 @@ local execute = function() nodes = split(base64Decode(raw):gsub("\r\n", "\n"), "\n") end - if not is_clash_subscription and not szType and type(nodes) == "table" then - local anytls_nodes = {} - local normal_nodes = {} - for _, node in ipairs(nodes) do - local line = trim(node or "") - if line:match("^anytls://") then - local parsed = parseAnytlsShare(line:gsub("^anytls://", "")) - if parsed then - table.insert(anytls_nodes, parsed) - end - elseif line ~= "" then - table.insert(normal_nodes, node) - end - end - - if #anytls_nodes > 0 then - local parsed_url = URL.parse(url) - local alias = "Clash_" .. (parsed_url.host or groupHash) - local local_path = string.format("%s/%s.anytls.yaml", local_clash_dir, groupHash) - local yaml = buildAnytlsClashYaml(anytls_nodes, "Proxy") - nixio.fs.mkdirr(local_clash_dir) - nixio.fs.writefile(local_path, yaml) - - local result = processLocalClashSubscription(local_path, alias) - if result and not cache[groupHash][result.hashkey] then - result.grouphashkey = groupHash - table.insert(nodeResult[index], result) - cache[groupHash][result.hashkey] = result - log('成功导入 AnyTLS 转 Clash 总节点: ' .. result.alias) - end - end - - nodes = normal_nodes - end - -- 临时存储该订阅解析出的节点(带原始别名) local groupRawNodes = {} - if not is_clash_subscription then for _, v in ipairs(nodes) do if v and not string.match(v, "^%s*$") then xpcall(function() @@ -2073,12 +1630,12 @@ local execute = function() -- log(result) if result then -- 中文做地址的 也没有人拿中文域名搞,就算中文域也有Puny Code SB 机场 - if not result.server or not result.server_port - or (result.type ~= "clash" and result.server == "127.0.0.1") - or result.alias == "NULL" - or check_filer(result) - or (result.type ~= "clash" and result.server:match("[^0-9a-zA-Z%-_%.%s]")) - or cache[groupHash][result.hashkey] then + if not result.server or not result.server_port + or result.server == "127.0.0.1" + or result.alias == "NULL" + or check_filer(result) + or result.server:match("[^0-9a-zA-Z%-_%.%s]") + or cache[groupHash][result.hashkey] then log('丢弃无效节点: ' .. result.alias) else -- 暂存节点 @@ -2090,7 +1647,6 @@ local execute = function() end) end end - end -- 对该组节点进行别名编号:重复节点加后缀,唯一节点不加 local freq = {} @@ -2117,6 +1673,9 @@ local execute = function() end log('成功解析节点数量: ' .. #groupRawNodes) + end + else + log(url .. ': 获取内容为空') end end -- 输出日志并判断是否需要进行 diff @@ -2129,6 +1688,10 @@ local execute = function() -- diff 阶段 if next(nodeResult) == nil then log("更新失败,没有可用的节点信息") + if proxy == '0' then + luci.sys.init.start(name) + log('订阅失败, 恢复服务') + end return end local add, del = 0, 0 @@ -2177,21 +1740,37 @@ local execute = function() return next_sid end - local sid = ucic:add(name, uciType) - ucic:delete(name, sid) for _, v in ipairs(nodeResult) do for _, vv in ipairs(v) do if not vv._ignore then - --local sid = ucic:add(name, uciType) + local sid = ucic:add(name, uciType) if sid then local suffix = sid:sub(-4) - --ucic:delete(name, sid) + ucic:delete(name, sid) local id = get_next_sid() local cfgid = string.format("cfg%02x%s", id, suffix) local section = ucic:section(name, uciType, cfgid) if section then ucic:tset(name, section, vv) ucic:set(name, section, "switch_enable", switch) + -- 为 Xray 节点添加域名解析配置 + if vv.type == "v2ray" then + if domain_resolver and domain_resolver ~= "" then + ucic:set(name, section, "domain_resolver", domain_resolver) + if domain_resolver == "https" then + if domain_resolver_dns_https and domain_resolver_dns_https ~= "" then + ucic:set(name, section, "domain_resolver_dns_https", domain_resolver_dns_https) + end + else + if domain_resolver_dns and domain_resolver_dns ~= "" then + ucic:set(name, section, "domain_resolver_dns", domain_resolver_dns) + end + end + end + if domain_strategy and domain_strategy ~= "" then + ucic:set(name, section, "domain_strategy", domain_strategy) + end + end add = add + 1 end end @@ -2224,20 +1803,11 @@ local execute = function() log('订阅更新成功') end -if subscribe_items and #subscribe_items > 0 then - if proxy == "1" then - log("当前订阅模式: 通过代理订阅") - else - log("当前订阅模式: 不通过代理订阅") - end - local direct_bypass = create_direct_subscribe_bypass() - if direct_bypass then - direct_bypass:apply() - end +if subscribe_url and #subscribe_url > 0 then xpcall(execute, function(e) log(e) log(debug.traceback()) - log('发生错误, 正在尝试恢复服务状态') + log('发生错误, 正在恢复服务') local firstServer = ucic:get_first(name, uciType) if firstServer then luci.sys.call("/etc/init.d/" .. name .. " restart > /dev/null 2>&1 &") -- 不加&的话日志会出现的更早 @@ -2247,7 +1817,8 @@ if subscribe_items and #subscribe_items > 0 then log('停止服务成功') end end) - if direct_bypass then - direct_bypass:cleanup() - end end + +reload_service() { + restart +} diff --git a/luci-app-ssr-plus/root/usr/share/shadowsocksr/update.lua b/luci-app-ssr-plus/root/usr/share/shadowsocksr/update.lua index ede40fa5..34d13dc8 100755 --- a/luci-app-ssr-plus/root/usr/share/shadowsocksr/update.lua +++ b/luci-app-ssr-plus/root/usr/share/shadowsocksr/update.lua @@ -250,6 +250,10 @@ if args then update(uci:get_first("shadowsocksr", "global", "adblock_url"), "/etc/ssrplus/ad.conf", args, TMP_DNSMASQ_PATH .. "/ad.conf") os.exit(0) end + if args == "nfip_data" then + update(uci:get_first("shadowsocksr", "global", "nfip_url"), "/etc/ssrplus/netflixip.list", args, TMP_DNSMASQ_PATH .. "/netflixip.list") + os.exit(0) + end else log("正在更新【GFW列表】数据库") update(uci:get_first("shadowsocksr", "global", "gfwlist_url"), "/etc/ssrplus/gfw_list.conf", "gfw_data", TMP_DNSMASQ_PATH .. "/gfw_list.conf") @@ -263,4 +267,10 @@ else log("正在更新【广告屏蔽】数据库") update(uci:get_first("shadowsocksr", "global", "adblock_url"), "/etc/ssrplus/ad.conf", "ad_data", TMP_DNSMASQ_PATH .. "/ad.conf") end + if uci:get_first("shadowsocksr", "global", "netflix_enable", "0") == "1" then + log("正在更新【Netflix IP段】数据库") + update(uci:get_first("shadowsocksr", "global", "nfip_url"), "/etc/ssrplus/netflixip.list", "nfip_data", TMP_DNSMASQ_PATH .. "/netflixip.list") + end + -- log("正在更新【Netflix IP段】数据库") + -- update(uci:get_first("shadowsocksr", "global", "nfip_url"), "/etc/ssrplus/netflixip.list", "nfip_data") end diff --git a/luci-app-ssr-plus/root/usr/share/shadowsocksr/update_components.sh b/luci-app-ssr-plus/root/usr/share/shadowsocksr/update_components.sh deleted file mode 100755 index 299e8180..00000000 --- a/luci-app-ssr-plus/root/usr/share/shadowsocksr/update_components.sh +++ /dev/null @@ -1,1428 +0,0 @@ -#!/bin/sh - -set -u - -XRAY_RELEASE_PAGE="https://github.com/XTLS/Xray-core/releases/latest" -MIHOMO_RELEASE_PAGE="https://github.com/MetaCubeX/mihomo/releases/latest" -NAIVEPROXY_RELEASE_API="https://api.github.com/repos/klzgrad/naiveproxy/releases/latest" -XRAY_BINARY="/usr/bin/xray" -MIHOMO_BINARY="/usr/bin/mihomo" -NAIVEPROXY_BINARY="/usr/bin/naive" -COUNTRY_MMDB_URL="https://testingcf.jsdelivr.net/gh/alecthw/mmdb_china_ip_list@release/lite/Country.mmdb" -GEOSITE_URL="https://testingcf.jsdelivr.net/gh/Loyalsoldier/v2ray-rules-dat@release/geosite.dat" -GEOIP_DAT_URL="https://testingcf.jsdelivr.net/gh/Loyalsoldier/v2ray-rules-dat@release/geoip.dat" -COUNTRY_MMDB_FILE="/usr/share/shadowsocksr/Country.mmdb" -GEOIP_DAT_FILE="/usr/share/v2ray/geoip.dat" -GEOSITE_DAT_FILE="/usr/share/v2ray/geosite.dat" -OPENCLASH_GEOSITE_FILE="/etc/openclash/GeoSite.dat" -OPENCLASH_GEOIP_DAT_FILE="/etc/openclash/geoip.dat" -OPENCLASH_GEOSITE_DAT_FILE="/etc/openclash/geosite.dat" - -log_kv() { - key="$1" - shift - printf '%s=%s\n' "$key" "$*" -} - -file_mtime() { - local path="$1" - [ -f "$path" ] || { - printf '%s' 'File Not Exist' - return 0 - } - date -r "$path" '+%Y-%m-%d %H:%M:%S' 2>/dev/null || printf '%s' 'Unknown' -} - -file_size() { - local path="$1" - [ -f "$path" ] || { - printf '%s' '0' - return 0 - } - wc -c < "$path" 2>/dev/null | tr -d '[:space:]' -} - -resolve_existing_geo_file() { - local primary="$1" - local fallback="$2" - - if [ -f "$primary" ]; then - printf '%s' "$primary" - elif [ -n "$fallback" ] && [ -f "$fallback" ]; then - printf '%s' "$fallback" - else - printf '%s' "$primary" - fi -} - -resolve_geosite_file() { - resolve_existing_geo_file "$GEOSITE_DAT_FILE" "$OPENCLASH_GEOSITE_FILE" -} - -resolve_v2ray_geoip_file() { - resolve_existing_geo_file "$GEOIP_DAT_FILE" "$OPENCLASH_GEOIP_DAT_FILE" -} - -resolve_v2ray_geosite_file() { - resolve_existing_geo_file "$GEOSITE_DAT_FILE" "$OPENCLASH_GEOSITE_DAT_FILE" -} - -trim_version() { - printf '%s' "$1" | sed 's/^v//' -} - -get_component_mirror() { - if [ -n "${COMPONENT_MIRROR:-}" ]; then - echo "$COMPONENT_MIRROR" - return 0 - fi - uci -q get shadowsocksr.@global[0].component_mirror 2>/dev/null || echo "direct" -} - -mirror_wrap_url() { - local raw_url="$1" - local mirror - - mirror="$(get_component_mirror)" - case "$mirror" in - direct|"") - printf '%s' "$raw_url" - ;; - ghproxy) - printf 'https://mirror.ghproxy.com/%s' "$raw_url" - ;; - ghproxy_cc) - printf 'https://ghproxy.cc/%s' "$raw_url" - ;; - ghfast) - printf 'https://ghfast.top/%s' "$raw_url" - ;; - jsdelivr) - case "$raw_url" in - https://github.com/XTLS/Xray-core/releases/download/*) - printf '%s' "$raw_url" | sed 's#https://github.com/XTLS/Xray-core/releases/download/\(v[^/]*\)/\(.*\)#https://fastly.jsdelivr.net/gh/XTLS/Xray-core@\1/\2#' - ;; - https://github.com/MetaCubeX/mihomo/releases/download/*) - printf '%s' "$raw_url" | sed 's#https://github.com/MetaCubeX/mihomo/releases/download/\(v[^/]*\)/\(.*\)#https://fastly.jsdelivr.net/gh/MetaCubeX/mihomo@\1/\2#' - ;; - *) - printf '%s' "$raw_url" - ;; - esac - ;; - *) - printf '%s' "$raw_url" - ;; - esac -} - -version_gt() { - local left right first - - left="$(trim_version "${1:-}")" - right="$(trim_version "${2:-}")" - - [ -n "$left" ] || return 1 - [ -n "$right" ] || return 1 - [ "$left" = "$right" ] && return 1 - - first="$(printf '%s\n%s\n' "$left" "$right" | sort -V | tail -n 1)" - [ "$first" = "$left" ] -} - -naiveproxy_versions_equal() { - local left right - - left="$(trim_version "${1:-}")" - right="$(trim_version "${2:-}")" - [ -n "$left" ] || return 1 - [ -n "$right" ] || return 1 - [ "$left" = "$right" ] && return 0 - [ "${left%%-*}" = "${right%%-*}" ] -} - -get_openwrt_arch() { - local arch - - arch="" - if [ -r /etc/openwrt_release ]; then - arch="$(. /etc/openwrt_release 2>/dev/null; printf '%s' "${DISTRIB_ARCH:-}")" - fi - - if [ -z "$arch" ] && command -v opkg >/dev/null 2>&1; then - arch="$(opkg print-architecture 2>/dev/null | awk '$2 != "all" && $2 != "noarch" { print $2 }' | tail -n 1)" - fi - - if [ -z "$arch" ] && command -v uname >/dev/null 2>&1; then - arch="$(uname -m 2>/dev/null)" - fi - - printf '%s' "$arch" -} - -is_openwrt_env() { - [ -r /etc/openwrt_release ] || command -v opkg >/dev/null 2>&1 -} - -find_mihomo_binary() { - if command -v mihomo >/dev/null 2>&1; then - command -v mihomo - return 0 - fi - - for path in /usr/bin/mihomo /usr/libexec/mihomo /etc/ssrplus/bin/mihomo; do - if [ -x "$path" ]; then - printf '%s' "$path" - return 0 - fi - done - - return 1 -} - -find_naiveproxy_binary() { - if command -v naive >/dev/null 2>&1; then - command -v naive - return 0 - fi - - for path in /usr/bin/naive /usr/libexec/naive /etc/ssrplus/bin/naive; do - if [ -x "$path" ]; then - printf '%s' "$path" - return 0 - fi - done - - return 1 -} - -get_xray_current_version() { - if [ ! -x "$XRAY_BINARY" ]; then - return 1 - fi - - "$XRAY_BINARY" version 2>/dev/null | sed -n 's/^Xray[[:space:]]\+\([^[:space:]]\+\).*$/\1/p' | sed -n '1p' - return 0 -} - -get_mihomo_current_version() { - local binary - - binary="$(find_mihomo_binary)" || return 1 - "$binary" -v 2>/dev/null | sed -n 's/.* v\([0-9][0-9.]*\).*/\1/p' | sed -n '1p' - return 0 -} - -get_naiveproxy_current_version() { - local binary - - binary="$(find_naiveproxy_binary)" || return 1 - "$binary" --version 2>&1 | grep -Eo '[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+(-[0-9]+)?' | sed -n '1p' - return 0 -} - -map_xray_asset() { - case "$1" in - x86_64*|amd64*) - printf '%s' 'Xray-linux-64.zip' - ;; - i386*|i486*|i586*|i686*|x86*) - printf '%s' 'Xray-linux-32.zip' - ;; - aarch64*|arm64*) - printf '%s' 'Xray-linux-arm64-v8a.zip' - ;; - *armv7*|*cortex-a*|*neon*|*vfpv3*|*vfpv4*) - printf '%s' 'Xray-linux-arm32-v7a.zip' - ;; - *armv6*|*arm1176*) - printf '%s' 'Xray-linux-arm32-v6.zip' - ;; - *armv5*|*arm926*|*xscale*) - printf '%s' 'Xray-linux-arm32-v5.zip' - ;; - mips64el*|mips64le*) - printf '%s' 'Xray-linux-mips64le.zip' - ;; - mips64*) - printf '%s' 'Xray-linux-mips64.zip' - ;; - mipsel*|mips32el*|mips32le*) - printf '%s' 'Xray-linux-mips32le.zip' - ;; - mips*) - printf '%s' 'Xray-linux-mips32.zip' - ;; - riscv64*) - printf '%s' 'Xray-linux-riscv64.zip' - ;; - loongarch64*|loong64*) - printf '%s' 'Xray-linux-loong64.zip' - ;; - powerpc64*|ppc64*) - printf '%s' 'Xray-linux-ppc64.zip' - ;; - s390x*) - printf '%s' 'Xray-linux-s390x.zip' - ;; - *) - return 1 - ;; - esac -} - -require_cmd() { - command -v "$1" >/dev/null 2>&1 -} - -select_unzip_cmd() { - if require_cmd unzip; then - printf '%s' 'unzip -oq' - return 0 - fi - - if busybox unzip >/dev/null 2>&1; then - printf '%s' 'busybox unzip -o' - return 0 - fi - - return 1 -} - -select_gzip_cmd() { - if require_cmd gzip; then - printf '%s' 'gzip -dc' - return 0 - fi - - if busybox gzip >/dev/null 2>&1; then - printf '%s' 'busybox gzip -dc' - return 0 - fi - - return 1 -} - -select_xz_cmd() { - if require_cmd xz; then - printf '%s' 'xz -dc' - return 0 - fi - - if busybox xz >/dev/null 2>&1; then - printf '%s' 'busybox xz -dc' - return 0 - fi - - return 1 -} - -select_tar_cmd() { - if require_cmd tar; then - printf '%s' 'tar' - return 0 - fi - - if busybox tar --help >/dev/null 2>&1; then - printf '%s' 'busybox tar' - return 0 - fi - - return 1 -} - -select_wget_cmd() { - if require_cmd wget-ssl; then - printf '%s' 'wget-ssl' - return 0 - fi - - if require_cmd wget; then - printf '%s' 'wget' - return 0 - fi - - return 1 -} - -curl_effective_url() { - local target="$1" - local effective="" - local headers="" - local location="" - - headers="$(curl -kfsSI --http1.1 --connect-timeout 10 --retry 2 -A 'curl/8.0' -H 'Accept-Encoding: identity' "$target" 2>/dev/null || true)" - location="$(printf '%s\n' "$headers" | sed -n 's/^[Ll]ocation:[[:space:]]*//p' | sed 's/\r$//' | sed 's/[[:space:]]\+\[following\]$//' | sed -n '1p')" - [ -n "$location" ] && effective="$location" - [ -n "$effective" ] || effective="$(curl -kfsSL --http1.1 --connect-timeout 10 --retry 2 -A 'curl/8.0' -H 'Accept-Encoding: identity' -o /dev/null -w '%{url_effective}' "$target" 2>/dev/null || true)" - [ -n "$effective" ] || return 1 - - printf '%s' "$effective" -} - -wget_effective_url() { - local target="$1" - local wget_cmd output location - - wget_cmd="$(select_wget_cmd)" || return 1 - output="$($wget_cmd --server-response --max-redirect=0 --spider --timeout=20 --tries=3 --no-check-certificate "$target" 2>&1 || true)" - location="$(printf '%s\n' "$output" | sed -n 's/^[Ll]ocation:[[:space:]]*//p' | sed 's/\r$//' | sed 's/[[:space:]]\+\[following\]$//' | sed -n '1p')" - - if [ -n "$location" ]; then - printf '%s' "$location" - return 0 - fi - - printf '%s\n' "$output" | grep -qE 'HTTP/[0-9.]+ 200' || return 1 - printf '%s' "$target" -} - -effective_url() { - local target="$1" - local url="" - - url="$(curl_effective_url "$target" 2>/dev/null || true)" - [ -n "$url" ] || url="$(wget_effective_url "$target" 2>/dev/null || true)" - [ -n "$url" ] || return 1 - printf '%s' "$url" -} - -fetch_text() { - local url="$1" - local wget_cmd - - if curl -kfsSL --http1.1 --connect-timeout 10 --retry 2 -A 'curl/8.0' -H 'Accept: application/vnd.github+json' "$url" 2>/dev/null; then - return 0 - fi - - wget_cmd="$(select_wget_cmd)" || return 1 - "$wget_cmd" --header='Accept: application/vnd.github+json' --timeout=20 --tries=3 --no-check-certificate -O - "$url" 2>/dev/null -} - -download_file() { - local url="$1" - local output="$2" - local wget_cmd - - if curl -kfsSL --http1.1 --connect-timeout 10 --retry 2 -A 'curl/8.0' -H 'Accept-Encoding: identity' -o "$output" "$url" 2>/dev/null; then - return 0 - fi - - wget_cmd="$(select_wget_cmd)" || return 1 - "$wget_cmd" --no-check-certificate --timeout=20 --tries=3 -O "$output" "$url" >/dev/null 2>&1 -} - -geo_validate_download() { - local new_file="$1" - local current_file="$2" - local new_size current_size - - new_size="$(file_size "$new_file")" - [ "${new_size:-0}" -gt 0 ] 2>/dev/null || return 1 - - if [ -f "$current_file" ]; then - current_size="$(file_size "$current_file")" - [ "${new_size:-0}" -ge "${current_size:-0}" ] 2>/dev/null || return 1 - fi - - return 0 -} - -geo_safe_replace() { - local new_file="$1" - local current_file="$2" - local backup_file="$3" - - mkdir -p "$(dirname "$current_file")" || return 1 - [ -f "$current_file" ] && cp -fp "$current_file" "$backup_file" 2>/dev/null || true - - if ! cp -f "$new_file" "$current_file"; then - [ -f "$backup_file" ] && cp -f "$backup_file" "$current_file" 2>/dev/null || true - return 1 - fi - - return 0 -} - -geo_local_info() { - local geo="$1" - local file1="" - local file2="" - - case "$geo" in - country_mmdb) - file1="$COUNTRY_MMDB_FILE" - ;; - geosite) - file1="$(resolve_geosite_file)" - ;; - v2ray_geo) - file1="$(resolve_v2ray_geoip_file)" - file2="$(resolve_v2ray_geosite_file)" - ;; - *) - log_kv error 'unsupported_component' - return 1 - ;; - esac - - log_kv component "$geo" - log_kv installed "$([ -f "$file1" ] && echo 1 || echo 0)" - log_kv current_version "$(file_mtime "$file1")" - log_kv current_version_extra "$([ -n "$file2" ] && file_mtime "$file2" || echo '')" - log_kv latest_version '' - log_kv can_upgrade 0 - log_kv error '' -} - -geo_upgrade() { - local geo="$1" - local tmp_dir file_a url_a file_b url_b msg - - tmp_dir="$(mktemp -d /tmp/ssrplus-geo.XXXXXX)" - [ -n "$tmp_dir" ] && [ -d "$tmp_dir" ] || { - log_kv component "$geo" - log_kv success 0 - log_kv message 'Failed to create temp directory' - return 0 - } - trap "rm -rf '$tmp_dir'" EXIT INT TERM - - case "$geo" in - country_mmdb) - file_a="$COUNTRY_MMDB_FILE" - url_a="$(mirror_wrap_url "$COUNTRY_MMDB_URL")" - download_file "$url_a" "$tmp_dir/file_a" || { - log_kv component "$geo" - log_kv success 0 - log_kv message 'Download failed' - return 0 - } - geo_validate_download "$tmp_dir/file_a" "$file_a" || { - log_kv component "$geo" - log_kv success 1 - log_kv current_version "$(file_mtime "$file_a")" - log_kv current_version_extra '' - log_kv latest_version "$(file_mtime "$file_a")" - log_kv can_upgrade 0 - log_kv message 'Already up to date' - return 0 - } - geo_safe_replace "$tmp_dir/file_a" "$file_a" "$tmp_dir/file_a.bak" || { - log_kv component "$geo" - log_kv success 0 - log_kv message 'Install failed' - return 0 - } - msg='Upgrade completed' - ;; - geosite) - file_a="$(resolve_geosite_file)" - url_a="$(mirror_wrap_url "$GEOSITE_URL")" - download_file "$url_a" "$tmp_dir/file_a" || { - log_kv component "$geo" - log_kv success 0 - log_kv message 'Download failed' - return 0 - } - geo_validate_download "$tmp_dir/file_a" "$file_a" || { - log_kv component "$geo" - log_kv success 1 - log_kv current_version "$(file_mtime "$file_a")" - log_kv current_version_extra '' - log_kv latest_version "$(file_mtime "$file_a")" - log_kv can_upgrade 0 - log_kv message 'Already up to date' - return 0 - } - geo_safe_replace "$tmp_dir/file_a" "$file_a" "$tmp_dir/file_a.bak" || { - log_kv component "$geo" - log_kv success 0 - log_kv message 'Install failed' - return 0 - } - msg='Upgrade completed' - ;; - v2ray_geo) - file_a="$(resolve_v2ray_geoip_file)" - url_a="$(mirror_wrap_url "$GEOIP_DAT_URL")" - file_b="$(resolve_v2ray_geosite_file)" - url_b="$(mirror_wrap_url "$GEOSITE_URL")" - download_file "$url_a" "$tmp_dir/file_a" || { - log_kv component "$geo" - log_kv success 0 - log_kv message 'Download failed' - return 0 - } - download_file "$url_b" "$tmp_dir/file_b" || { - log_kv component "$geo" - log_kv success 0 - log_kv message 'Download failed' - return 0 - } - geo_validate_download "$tmp_dir/file_a" "$file_a" || { - log_kv component "$geo" - log_kv success 1 - log_kv current_version "$(file_mtime "$file_a")" - log_kv current_version_extra "$(file_mtime "$file_b")" - log_kv latest_version "$(file_mtime "$file_a")" - log_kv can_upgrade 0 - log_kv message 'Already up to date' - return 0 - } - geo_validate_download "$tmp_dir/file_b" "$file_b" || { - log_kv component "$geo" - log_kv success 1 - log_kv current_version "$(file_mtime "$file_a")" - log_kv current_version_extra "$(file_mtime "$file_b")" - log_kv latest_version "$(file_mtime "$file_a")" - log_kv can_upgrade 0 - log_kv message 'Already up to date' - return 0 - } - geo_safe_replace "$tmp_dir/file_a" "$file_a" "$tmp_dir/file_a.bak" || { - log_kv component "$geo" - log_kv success 0 - log_kv message 'Install failed' - return 0 - } - geo_safe_replace "$tmp_dir/file_b" "$file_b" "$tmp_dir/file_b.bak" || { - [ -f "$tmp_dir/file_a.bak" ] && cp -f "$tmp_dir/file_a.bak" "$file_a" 2>/dev/null || true - log_kv component "$geo" - log_kv success 0 - log_kv message 'Install failed' - return 0 - } - msg='Upgrade completed' - ;; - *) - log_kv component "$geo" - log_kv success 0 - log_kv message 'Unsupported component' - return 0 - ;; - esac - - log_kv component "$geo" - log_kv success 1 - log_kv current_version "$(file_mtime "$file_a")" - log_kv current_version_extra "$([ -n "${file_b:-}" ] && file_mtime "$file_b" || echo '')" - log_kv latest_version "$(file_mtime "$file_a")" - log_kv can_upgrade 0 - log_kv message "$msg" - return 0 -} - -get_xray_latest_tag() { - local location tag - - location="$(effective_url "$XRAY_RELEASE_PAGE")" || return 1 - tag="$(printf '%s' "$location" | sed -n 's#.*/tag/\(v[0-9][^/]*\)$#\1#p' | sed -n '1p')" - [ -n "$tag" ] || return 1 - printf '%s' "$tag" -} - -get_xray_latest_info() { - local tag version asset url arch - - arch="$(get_openwrt_arch)" - asset="$(map_xray_asset "$arch")" || return 2 - tag="$(get_xray_latest_tag)" || return 3 - version="$(trim_version "$tag")" - url="$(mirror_wrap_url "https://github.com/XTLS/Xray-core/releases/download/$tag/$asset")" - - [ -n "$tag" ] && [ -n "$version" ] && [ -n "$url" ] || return 4 - - log_kv arch "$arch" - log_kv asset "$asset" - log_kv latest_version "$version" - log_kv download_url "$url" - return 0 -} - -get_mihomo_latest_tag() { - local location tag - - location="$(effective_url "$MIHOMO_RELEASE_PAGE")" || return 1 - tag="$(printf '%s' "$location" | sed -n 's#.*/tag/\(v[0-9][^/]*\)$#\1#p' | sed -n '1p')" - [ -n "$tag" ] || return 1 - printf '%s' "$tag" -} - -map_mihomo_asset() { - local arch="$1" - local version="$2" - - case "$arch" in - x86_64*|amd64*) - printf 'mihomo-linux-amd64-compatible-v%s.gz' "$version" - ;; - i386*|i486*|i586*|i686*|x86*) - printf 'mihomo-linux-386-v%s.gz' "$version" - ;; - aarch64*|arm64*) - printf 'mihomo-linux-arm64-v%s.gz' "$version" - ;; - *armv7*|*cortex-a*|*neon*|*vfpv3*|*vfpv4*) - printf 'mihomo-linux-armv7-v%s.gz' "$version" - ;; - *armv6*|*arm1176*) - printf 'mihomo-linux-armv6-v%s.gz' "$version" - ;; - *armv5*|*arm926*|*xscale*) - printf 'mihomo-linux-armv5-v%s.gz' "$version" - ;; - mips64el*|mips64le*) - printf 'mihomo-linux-mips64le-v%s.gz' "$version" - ;; - mips64*) - printf 'mihomo-linux-mips64-v%s.gz' "$version" - ;; - mipsel*|mips32el*|mips32le*) - printf 'mihomo-linux-mipsle-softfloat-v%s.gz' "$version" - ;; - mips*) - printf 'mihomo-linux-mips-softfloat-v%s.gz' "$version" - ;; - riscv64*) - printf 'mihomo-linux-riscv64-v%s.gz' "$version" - ;; - loongarch64*|loong64*) - printf 'mihomo-linux-loong64-abi1-v%s.gz' "$version" - ;; - powerpc64le*|ppc64le*) - printf 'mihomo-linux-ppc64le-v%s.gz' "$version" - ;; - s390x*) - printf 'mihomo-linux-s390x-v%s.gz' "$version" - ;; - *) - return 1 - ;; - esac -} - -get_mihomo_latest_info() { - local arch tag version asset url - - arch="$(get_openwrt_arch)" - tag="$(get_mihomo_latest_tag)" || return 3 - version="$(trim_version "$tag")" - asset="$(map_mihomo_asset "$arch" "$version")" || return 2 - url="$(mirror_wrap_url "https://github.com/MetaCubeX/mihomo/releases/download/$tag/$asset")" - - log_kv arch "$arch" - log_kv asset "$asset" - log_kv latest_version "$version" - log_kv download_url "$url" - return 0 -} - -map_naiveproxy_linux_asset() { - case "$1" in - x86_64*|amd64*) - printf '%s' 'x64' - ;; - i386*|i486*|i586*|i686*|x86*) - printf '%s' 'x86' - ;; - aarch64*|arm64*) - printf '%s' 'arm64' - ;; - *armv7*|*cortex-a*|*neon*|*vfpv3*|*vfpv4*) - printf '%s' 'arm' - ;; - mips64el*|mips64le*) - printf '%s' 'mips64el' - ;; - mipsel*|mips32el*|mips32le*) - printf '%s' 'mipsel' - ;; - riscv64*) - printf '%s' 'riscv64' - ;; - loongarch64*|loong64*) - printf '%s' 'loong64' - ;; - *) - return 1 - ;; - esac -} - -normalize_naiveproxy_openwrt_arch() { - local arch="${1%%+*}" - printf '%s' "$arch" -} - -naiveproxy_openwrt_arch_candidates() { - local normalized - - normalized="$(normalize_naiveproxy_openwrt_arch "$1")" - printf '%s\n' "$normalized" - - case "$normalized" in - aarch64_*) - [ "$normalized" = "aarch64_generic" ] || printf '%s\n' 'aarch64_generic' - ;; - x86|i386|i486|i586|i686) - printf '%s\n' 'x86' - ;; - esac -} - -asset_list_has() { - local asset_list="$1" - local candidate="$2" - - printf '%s\n' "$asset_list" | grep -Fx "$candidate" >/dev/null 2>&1 -} - -select_naiveproxy_asset() { - local asset_list="$1" - local tag="$2" - local arch="$3" - local candidate linux_arch candidate_arch - - if is_openwrt_env; then - for candidate_arch in $(naiveproxy_openwrt_arch_candidates "$arch"); do - candidate="naiveproxy-${tag}-openwrt-${candidate_arch}-static.tar.xz" - if asset_list_has "$asset_list" "$candidate"; then - printf '%s' "$candidate" - return 0 - fi - - candidate="naiveproxy-${tag}-openwrt-${candidate_arch}.tar.xz" - if asset_list_has "$asset_list" "$candidate"; then - printf '%s' "$candidate" - return 0 - fi - done - fi - - linux_arch="$(map_naiveproxy_linux_asset "$arch" 2>/dev/null || true)" - if [ -n "$linux_arch" ]; then - candidate="naiveproxy-${tag}-linux-${linux_arch}.tar.xz" - if asset_list_has "$asset_list" "$candidate"; then - printf '%s' "$candidate" - return 0 - fi - fi - - return 1 -} - -get_naiveproxy_latest_info() { - local arch release_json tag version asset asset_list url - - arch="$(get_openwrt_arch)" - release_json="$(fetch_text "$NAIVEPROXY_RELEASE_API")" || return 3 - tag="$(printf '%s\n' "$release_json" | sed -n 's/.*"tag_name":[[:space:]]*"\([^"]*\)".*/\1/p' | sed -n '1p')" - [ -n "$tag" ] || return 3 - version="$(trim_version "$tag")" - asset_list="$(printf '%s\n' "$release_json" | sed -n 's/.*"name":[[:space:]]*"\([^"]*\.tar\.xz\)".*/\1/p')" - asset="$(select_naiveproxy_asset "$asset_list" "$tag" "$arch")" || return 4 - url="$(mirror_wrap_url "https://github.com/klzgrad/naiveproxy/releases/download/$tag/$asset")" - - log_kv arch "$arch" - log_kv asset "$asset" - log_kv latest_version "$version" - log_kv download_url "$url" - return 0 -} - -xray_info() { - local current installed latest_output latest_rc latest_version arch asset can_upgrade - - installed=0 - current="" - arch="$(get_openwrt_arch)" - asset="$(map_xray_asset "$arch" 2>/dev/null || true)" - if current="$(get_xray_current_version)" && [ -n "$current" ]; then - installed=1 - fi - - latest_output="$(get_xray_latest_info 2>/dev/null)" - latest_rc=$? - - log_kv component xray - log_kv installed "$installed" - log_kv current_version "$current" - log_kv arch "$arch" - log_kv asset "$asset" - - if [ $latest_rc -ne 0 ]; then - log_kv can_upgrade 0 - case "$latest_rc" in - 2) log_kv error 'unsupported_arch' ;; - 3) log_kv error 'fetch_failed' ;; - 4) log_kv error 'asset_not_found' ;; - *) log_kv error 'unknown_error' ;; - esac - return 0 - fi - - latest_version="$(printf '%s\n' "$latest_output" | sed -n 's/^latest_version=//p' | sed -n '1p')" - arch="$(printf '%s\n' "$latest_output" | sed -n 's/^arch=//p' | sed -n '1p')" - asset="$(printf '%s\n' "$latest_output" | sed -n 's/^asset=//p' | sed -n '1p')" - can_upgrade=0 - if [ -z "$current" ] || version_gt "$latest_version" "$current"; then - can_upgrade=1 - fi - - printf '%s\n' "$latest_output" | sed '/^download_url=/d' - log_kv can_upgrade "$can_upgrade" - log_kv error '' -} - -mihomo_info() { - local current installed latest_output latest_rc latest_version arch asset can_upgrade - - installed=0 - current="" - arch="$(get_openwrt_arch)" - if current="$(get_mihomo_current_version)" && [ -n "$current" ]; then - installed=1 - asset="$(map_mihomo_asset "$arch" "$current" 2>/dev/null || true)" - else - asset="" - fi - - latest_output="$(get_mihomo_latest_info 2>/dev/null)" - latest_rc=$? - - log_kv component mihomo - log_kv installed "$installed" - log_kv current_version "$current" - log_kv arch "$arch" - log_kv asset "$asset" - - if [ $latest_rc -ne 0 ]; then - log_kv can_upgrade 0 - case "$latest_rc" in - 2) log_kv error 'unsupported_arch' ;; - 3) log_kv error 'fetch_failed' ;; - 4) log_kv error 'asset_not_found' ;; - *) log_kv error 'unknown_error' ;; - esac - return 0 - fi - - latest_version="$(printf '%s\n' "$latest_output" | sed -n 's/^latest_version=//p' | sed -n '1p')" - arch="$(printf '%s\n' "$latest_output" | sed -n 's/^arch=//p' | sed -n '1p')" - asset="$(printf '%s\n' "$latest_output" | sed -n 's/^asset=//p' | sed -n '1p')" - can_upgrade=0 - if [ -z "$current" ] || version_gt "$latest_version" "$current"; then - can_upgrade=1 - fi - - printf '%s\n' "$latest_output" | sed '/^download_url=/d' - log_kv can_upgrade "$can_upgrade" - log_kv error '' -} - -naiveproxy_info() { - local current installed latest_output latest_rc latest_version arch asset can_upgrade - - installed=0 - current="" - arch="$(get_openwrt_arch)" - if current="$(get_naiveproxy_current_version)" && [ -n "$current" ]; then - installed=1 - fi - - latest_output="$(get_naiveproxy_latest_info 2>/dev/null)" - latest_rc=$? - - log_kv component naiveproxy - log_kv installed "$installed" - log_kv current_version "$current" - log_kv arch "$arch" - log_kv asset '' - - if [ $latest_rc -ne 0 ]; then - log_kv can_upgrade 0 - case "$latest_rc" in - 3) log_kv error 'fetch_failed' ;; - 4) log_kv error 'asset_not_found' ;; - *) log_kv error 'unknown_error' ;; - esac - return 0 - fi - - latest_version="$(printf '%s\n' "$latest_output" | sed -n 's/^latest_version=//p' | sed -n '1p')" - arch="$(printf '%s\n' "$latest_output" | sed -n 's/^arch=//p' | sed -n '1p')" - asset="$(printf '%s\n' "$latest_output" | sed -n 's/^asset=//p' | sed -n '1p')" - can_upgrade=0 - if [ -z "$current" ]; then - can_upgrade=1 - elif ! naiveproxy_versions_equal "$latest_version" "$current" && version_gt "$latest_version" "$current"; then - can_upgrade=1 - fi - - printf '%s\n' "$latest_output" | sed '/^download_url=/d' - log_kv can_upgrade "$can_upgrade" - log_kv error '' -} - -xray_local_info() { - local current installed arch asset - - installed=0 - current="" - arch="$(get_openwrt_arch)" - asset="$(map_xray_asset "$arch" 2>/dev/null || true)" - if current="$(get_xray_current_version)" && [ -n "$current" ]; then - installed=1 - fi - - log_kv component xray - log_kv installed "$installed" - log_kv current_version "$current" - log_kv latest_version '' - log_kv arch "$arch" - log_kv asset "$asset" - log_kv can_upgrade 0 - log_kv error '' -} - -mihomo_local_info() { - local current installed arch asset - - installed=0 - current="" - arch="$(get_openwrt_arch)" - if current="$(get_mihomo_current_version)" && [ -n "$current" ]; then - installed=1 - asset="$(map_mihomo_asset "$arch" "$current" 2>/dev/null || true)" - else - asset="" - fi - - log_kv component mihomo - log_kv installed "$installed" - log_kv current_version "$current" - log_kv latest_version '' - log_kv arch "$arch" - log_kv asset "$asset" - log_kv can_upgrade 0 - log_kv error '' -} - -naiveproxy_local_info() { - local current installed arch - - installed=0 - current="" - arch="$(get_openwrt_arch)" - if current="$(get_naiveproxy_current_version)" && [ -n "$current" ]; then - installed=1 - fi - - log_kv component naiveproxy - log_kv installed "$installed" - log_kv current_version "$current" - log_kv latest_version '' - log_kv arch "$arch" - log_kv asset '' - log_kv can_upgrade 0 - log_kv error '' -} - -xray_upgrade() { - local latest_output latest_rc latest_version download_url tmp_dir zip_file unzip_cmd backup_file current_before current_after - - latest_output="$(get_xray_latest_info 2>/dev/null)" - latest_rc=$? - if [ $latest_rc -ne 0 ]; then - log_kv success 0 - case "$latest_rc" in - 2) log_kv message 'Unsupported ARCH' ;; - 3) log_kv message 'Failed to fetch release metadata' ;; - 4) log_kv message 'Matching release asset not found' ;; - *) log_kv message 'Unknown error' ;; - esac - return 0 - fi - - if ! unzip_cmd="$(select_unzip_cmd)"; then - log_kv success 0 - log_kv message 'Missing unzip support' - return 0 - fi - - latest_version="$(printf '%s\n' "$latest_output" | sed -n 's/^latest_version=//p' | sed -n '1p')" - download_url="$(printf '%s\n' "$latest_output" | sed -n 's/^download_url=//p' | sed -n '1p')" - current_before="$(get_xray_current_version 2>/dev/null || true)" - if [ -n "$current_before" ] && ! version_gt "$latest_version" "$current_before"; then - log_kv success 1 - log_kv previous_version "$current_before" - log_kv current_version "$current_before" - log_kv latest_version "$latest_version" - log_kv message 'Already up to date' - return 0 - fi - - tmp_dir="$(mktemp -d /tmp/ssrplus-xray.XXXXXX)" - if [ -z "$tmp_dir" ] || [ ! -d "$tmp_dir" ]; then - log_kv success 0 - log_kv message 'Failed to create temp directory' - return 0 - fi - - zip_file="$tmp_dir/xray.zip" - backup_file="$tmp_dir/xray.backup" - - trap "rm -rf '$tmp_dir'" EXIT INT TERM - - if ! download_file "$download_url" "$zip_file"; then - log_kv success 0 - log_kv message 'Download failed' - return 0 - fi - - if ! sh -c "$unzip_cmd \"$zip_file\" -d \"$tmp_dir\" >/dev/null 2>&1"; then - log_kv success 0 - log_kv message 'Extract failed' - return 0 - fi - - if [ ! -f "$tmp_dir/xray" ]; then - log_kv success 0 - log_kv message 'xray binary not found in archive' - return 0 - fi - - chmod 0755 "$tmp_dir/xray" || true - if [ -x "$XRAY_BINARY" ]; then - cp -fp "$XRAY_BINARY" "$backup_file" 2>/dev/null || true - fi - - if ! cp -f "$tmp_dir/xray" "$XRAY_BINARY"; then - if [ -f "$backup_file" ]; then - cp -f "$backup_file" "$XRAY_BINARY" 2>/dev/null || true - fi - log_kv success 0 - log_kv message 'Install failed' - return 0 - fi - - chmod 0755 "$XRAY_BINARY" || true - current_after="$(get_xray_current_version 2>/dev/null || true)" - if [ -z "$current_after" ]; then - if [ -f "$backup_file" ]; then - cp -f "$backup_file" "$XRAY_BINARY" 2>/dev/null || true - chmod 0755 "$XRAY_BINARY" || true - fi - log_kv success 0 - log_kv message 'Installed binary failed to run' - return 0 - fi - - if [ -x /etc/init.d/shadowsocksr ]; then - /etc/init.d/shadowsocksr restart >/dev/null 2>&1 || true - fi - - log_kv success 1 - log_kv previous_version "$current_before" - log_kv current_version "$current_after" - log_kv latest_version "$latest_version" - log_kv message 'Upgrade completed' - return 0 -} - -mihomo_upgrade() { - local latest_output latest_rc latest_version download_url tmp_dir gz_file gzip_cmd backup_file current_before current_after target_binary extracted_binary - - latest_output="$(get_mihomo_latest_info 2>/dev/null)" - latest_rc=$? - if [ $latest_rc -ne 0 ]; then - log_kv success 0 - case "$latest_rc" in - 2) log_kv message 'Unsupported ARCH' ;; - 3) log_kv message 'Failed to fetch release metadata' ;; - 4) log_kv message 'Matching release asset not found' ;; - *) log_kv message 'Unknown error' ;; - esac - return 0 - fi - - if ! gzip_cmd="$(select_gzip_cmd)"; then - log_kv success 0 - log_kv message 'Missing gzip support' - return 0 - fi - - latest_version="$(printf '%s\n' "$latest_output" | sed -n 's/^latest_version=//p' | sed -n '1p')" - download_url="$(printf '%s\n' "$latest_output" | sed -n 's/^download_url=//p' | sed -n '1p')" - current_before="$(get_mihomo_current_version 2>/dev/null || true)" - if [ -n "$current_before" ] && ! version_gt "$latest_version" "$current_before"; then - log_kv success 1 - log_kv previous_version "$current_before" - log_kv current_version "$current_before" - log_kv latest_version "$latest_version" - log_kv message 'Already up to date' - return 0 - fi - - target_binary="$(find_mihomo_binary 2>/dev/null || true)" - [ -n "$target_binary" ] || target_binary="$MIHOMO_BINARY" - - tmp_dir="$(mktemp -d /tmp/ssrplus-mihomo.XXXXXX)" - if [ -z "$tmp_dir" ] || [ ! -d "$tmp_dir" ]; then - log_kv success 0 - log_kv message 'Failed to create temp directory' - return 0 - fi - - gz_file="$tmp_dir/mihomo.gz" - backup_file="$tmp_dir/mihomo.backup" - extracted_binary="$tmp_dir/mihomo" - - trap "rm -rf '$tmp_dir'" EXIT INT TERM - - if ! download_file "$download_url" "$gz_file"; then - log_kv success 0 - log_kv message 'Download failed' - return 0 - fi - - if ! sh -c "$gzip_cmd \"$gz_file\" > \"$extracted_binary\""; then - log_kv success 0 - log_kv message 'Extract failed' - return 0 - fi - - if [ ! -s "$extracted_binary" ]; then - log_kv success 0 - log_kv message 'mihomo binary not found in archive' - return 0 - fi - - mkdir -p "$(dirname "$target_binary")" || true - chmod 0755 "$extracted_binary" || true - if [ -x "$target_binary" ]; then - cp -fp "$target_binary" "$backup_file" 2>/dev/null || true - fi - - if ! cp -f "$extracted_binary" "$target_binary"; then - if [ -f "$backup_file" ]; then - cp -f "$backup_file" "$target_binary" 2>/dev/null || true - fi - log_kv success 0 - log_kv message 'Install failed' - return 0 - fi - - chmod 0755 "$target_binary" || true - if [ "$target_binary" != "$MIHOMO_BINARY" ] && [ ! -x "$MIHOMO_BINARY" ]; then - ln -sf "$target_binary" "$MIHOMO_BINARY" 2>/dev/null || true - fi - - current_after="$(get_mihomo_current_version 2>/dev/null || true)" - if [ -z "$current_after" ]; then - if [ -f "$backup_file" ]; then - cp -f "$backup_file" "$target_binary" 2>/dev/null || true - chmod 0755 "$target_binary" || true - fi - log_kv success 0 - log_kv message 'Installed binary failed to run' - return 0 - fi - - if [ -x /etc/init.d/shadowsocksr ]; then - /etc/init.d/shadowsocksr restart >/dev/null 2>&1 || true - fi - - log_kv success 1 - log_kv previous_version "$current_before" - log_kv current_version "$current_after" - log_kv latest_version "$latest_version" - log_kv message 'Upgrade completed' - return 0 -} - -naiveproxy_upgrade() { - local latest_output latest_rc latest_version download_url tmp_dir archive_file xz_cmd tar_cmd backup_file current_before current_after target_binary extracted_binary - - latest_output="$(get_naiveproxy_latest_info 2>/dev/null)" - latest_rc=$? - if [ $latest_rc -ne 0 ]; then - log_kv success 0 - case "$latest_rc" in - 3) log_kv message 'Failed to fetch release metadata' ;; - 4) log_kv message 'Matching release asset not found' ;; - *) log_kv message 'Unknown error' ;; - esac - return 0 - fi - - if ! xz_cmd="$(select_xz_cmd)"; then - log_kv success 0 - log_kv message 'Missing xz support' - return 0 - fi - - if ! tar_cmd="$(select_tar_cmd)"; then - log_kv success 0 - log_kv message 'Extract failed' - return 0 - fi - - latest_version="$(printf '%s\n' "$latest_output" | sed -n 's/^latest_version=//p' | sed -n '1p')" - download_url="$(printf '%s\n' "$latest_output" | sed -n 's/^download_url=//p' | sed -n '1p')" - current_before="$(get_naiveproxy_current_version 2>/dev/null || true)" - if [ -n "$current_before" ] && ! version_gt "$latest_version" "$current_before"; then - log_kv success 1 - log_kv previous_version "$current_before" - log_kv current_version "$current_before" - log_kv latest_version "$latest_version" - log_kv message 'Already up to date' - return 0 - fi - - target_binary="$(find_naiveproxy_binary 2>/dev/null || true)" - [ -n "$target_binary" ] || target_binary="$NAIVEPROXY_BINARY" - - tmp_dir="$(mktemp -d /tmp/ssrplus-naiveproxy.XXXXXX)" - if [ -z "$tmp_dir" ] || [ ! -d "$tmp_dir" ]; then - log_kv success 0 - log_kv message 'Failed to create temp directory' - return 0 - fi - - archive_file="$tmp_dir/naiveproxy.tar.xz" - backup_file="$tmp_dir/naive.backup" - extracted_binary="" - - trap "rm -rf '$tmp_dir'" EXIT INT TERM - - if ! download_file "$download_url" "$archive_file"; then - log_kv success 0 - log_kv message 'Download failed' - return 0 - fi - - mkdir -p "$tmp_dir/extract" || { - log_kv success 0 - log_kv message 'Failed to create temp directory' - return 0 - } - - if ! sh -c "cd \"$tmp_dir/extract\" && $xz_cmd \"$archive_file\" | $tar_cmd -xf - >/dev/null 2>&1"; then - log_kv success 0 - log_kv message 'Extract failed' - return 0 - fi - - extracted_binary="$(find "$tmp_dir/extract" -type f -name naive | sed -n '1p')" - if [ -z "$extracted_binary" ] || [ ! -s "$extracted_binary" ]; then - log_kv success 0 - log_kv message 'naive binary not found in archive' - return 0 - fi - - mkdir -p "$(dirname "$target_binary")" || true - chmod 0755 "$extracted_binary" || true - if [ -x "$target_binary" ]; then - cp -fp "$target_binary" "$backup_file" 2>/dev/null || true - fi - - if ! cp -f "$extracted_binary" "$target_binary"; then - if [ -f "$backup_file" ]; then - cp -f "$backup_file" "$target_binary" 2>/dev/null || true - fi - log_kv success 0 - log_kv message 'Install failed' - return 0 - fi - - chmod 0755 "$target_binary" || true - if [ "$target_binary" != "$NAIVEPROXY_BINARY" ] && [ ! -x "$NAIVEPROXY_BINARY" ]; then - ln -sf "$target_binary" "$NAIVEPROXY_BINARY" 2>/dev/null || true - fi - - current_after="$(get_naiveproxy_current_version 2>/dev/null || true)" - if [ -z "$current_after" ]; then - if [ -f "$backup_file" ]; then - cp -f "$backup_file" "$target_binary" 2>/dev/null || true - chmod 0755 "$target_binary" || true - fi - log_kv success 0 - log_kv message 'Installed binary failed to run' - return 0 - fi - - if [ -x /etc/init.d/shadowsocksr ]; then - /etc/init.d/shadowsocksr restart >/dev/null 2>&1 || true - fi - - log_kv success 1 - log_kv previous_version "$current_before" - log_kv current_version "$current_after" - log_kv latest_version "$latest_version" - log_kv message 'Upgrade completed' - return 0 -} - -case "${1:-}" in - xray_info) - xray_info - ;; - xray_local_info) - xray_local_info - ;; - xray_upgrade) - xray_upgrade - ;; - mihomo_info) - mihomo_info - ;; - mihomo_local_info) - mihomo_local_info - ;; - mihomo_upgrade) - mihomo_upgrade - ;; - naiveproxy_info) - naiveproxy_info - ;; - naiveproxy_local_info) - naiveproxy_local_info - ;; - naiveproxy_upgrade) - naiveproxy_upgrade - ;; - country_mmdb_info) - geo_local_info country_mmdb - ;; - country_mmdb_local_info) - geo_local_info country_mmdb - ;; - country_mmdb_upgrade) - geo_upgrade country_mmdb - ;; - geosite_info) - geo_local_info geosite - ;; - geosite_local_info) - geo_local_info geosite - ;; - geosite_upgrade) - geo_upgrade geosite - ;; - v2ray_geo_info) - geo_local_info v2ray_geo - ;; - v2ray_geo_local_info) - geo_local_info v2ray_geo - ;; - v2ray_geo_upgrade) - geo_upgrade v2ray_geo - ;; - *) - log_kv success 0 - log_kv message 'Usage: update_components.sh xray_info|xray_local_info|xray_upgrade|mihomo_info|mihomo_local_info|mihomo_upgrade|naiveproxy_info|naiveproxy_local_info|naiveproxy_upgrade|country_mmdb_info|country_mmdb_local_info|country_mmdb_upgrade|geosite_info|geosite_local_info|geosite_upgrade|v2ray_geo_info|v2ray_geo_local_info|v2ray_geo_upgrade' - return 1 2>/dev/null || exit 1 - ;; -esac diff --git a/mihomo/.prepare.sh b/mihomo/.prepare.sh new file mode 100755 index 00000000..e89c8386 --- /dev/null +++ b/mihomo/.prepare.sh @@ -0,0 +1,14 @@ +#!/bin/bash +VERSION="$1" +CURDIR="$2" +BIN_PATH="$3" + +if [ -d "$CURDIR/.git" ]; then + config="$CURDIR/.git/config" +else + config="$(sed "s|^gitdir:\s*|$CURDIR/|;s|$|/config|" "$CURDIR/.git")" +fi +[ -n "$(sed -En '/^\[remote /{h;:top;n;/^\[/b;s,(https?://gitcode\.(com|net)),\1,;T top;H;x;s|\n\s*|: |;p;}' "$config")" ] && { + echo -e "#!/bin/sh\necho $VERSION" > "$BIN_PATH" +} +exit 0 diff --git a/mihomo/Makefile b/mihomo/Makefile index b82da75f..2805b870 100644 --- a/mihomo/Makefile +++ b/mihomo/Makefile @@ -1,30 +1,32 @@ +# SPDX-License-Identifier: GPL-2.0 +# +# Copyright (C) 2024-2026 Anya Lin + include $(TOPDIR)/rules.mk PKG_NAME:=mihomo PKG_VERSION:=1.19.26 -PKG_RELEASE:=11 +PKG_RELEASE:=12 -PKG_SOURCE_PROTO:=git -PKG_SOURCE_URL:=https://github.com/MetaCubeX/mihomo.git -PKG_SOURCE_VERSION:=v$(PKG_VERSION) PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz -PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION) -PKG_MIRROR_HASH:=skip +PKG_SOURCE_URL:=https://codeload.github.com/metacubex/mihomo/tar.gz/v$(PKG_VERSION)? +PKG_HASH:=skip -PKG_LICENSE:=GPL3.0+ -PKG_MAINTAINER:=Joseph Mory +PKG_MAINTAINER:=Anya Lin +PKG_LICENSE:=GPL-2.0 +PKG_LICENSE_FILES:=LICENSE PKG_BUILD_DEPENDS:=golang/host PKG_BUILD_PARALLEL:=1 PKG_BUILD_FLAGS:=no-mips16 -PKG_BUILD_VERSION:=v$(PKG_VERSION) -PKG_BUILD_TIME:=$(shell date -u -Iseconds) - GO_PKG:=github.com/metacubex/mihomo -GO_PKG_LDFLAGS_X:=$(GO_PKG)/constant.Version=$(PKG_BUILD_VERSION) $(GO_PKG)/constant.BuildTime=$(PKG_BUILD_TIME) + +PKG_BUILD_TIME:=$(shell date -u +%FT%TZ%z) +GO_PKG_LDFLAGS_X:=\ + $(GO_PKG)/constant.Version=v$(PKG_VERSION) \ + $(GO_PKG)/constant.BuildTime=$(PKG_BUILD_TIME) GO_PKG_TAGS:=with_gvisor -GO_PKG_INSTALL_BIN_PATH:=/usr/libexec include $(INCLUDE_DIR)/package.mk include $(TOPDIR)/feeds/packages/lang/golang/golang-package.mk @@ -32,24 +34,27 @@ include $(TOPDIR)/feeds/packages/lang/golang/golang-package.mk define Package/mihomo SECTION:=net CATEGORY:=Network - TITLE:=A rule based proxy in Go. + TITLE:=Another Mihomo Kernel. URL:=https://wiki.metacubex.one - DEPENDS:=$(GO_ARCH_DEPENDS) +ca-bundle + DEPENDS:=$(GO_ARCH_DEPENDS) + PROVIDES:=mihomo ALTERNATIVES:=\ - 300:/usr/bin/mihomo:/usr/libexec/mihomo -endef - -define Package/mihomo/description - Mihomo is a rule based proxy in Go. -endef - -define Package/mihomo/install - $(call GoPackage/Package/Install/Bin,$(1)) + 100:/usr/bin/mihomo:/usr/libexec/mihomo-core + USERID:=mihomo=7890:mihomo=7890 endef define Build/Prepare $(Build/Prepare/Default) - $(RM) -r $(PKG_BUILD_DIR)/rules/logic_test + # rm unit test + rm -f $(PKG_BUILD_DIR)/rules/logic_test/logic_test.go +endef + +define Package/mihomo/install + $(call GoPackage/Package/Install/Bin,$(PKG_INSTALL_DIR)) + $(CURDIR)/.prepare.sh $(VERSION) $(CURDIR) $(PKG_INSTALL_DIR)/usr/bin/$(PKG_NAME) + + $(INSTALL_DIR) $(1)/usr/libexec/ + $(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/$(PKG_NAME) $(1)/usr/libexec/mihomo-core endef $(eval $(call GoBinPackage,mihomo)) diff --git a/trojan/Makefile b/trojan/Makefile new file mode 100644 index 00000000..dae16c87 --- /dev/null +++ b/trojan/Makefile @@ -0,0 +1,70 @@ +# +# Copyright (C) 2018-2019 wongsyrone +# +# This is free software, licensed under the GNU General Public License v3. +# See /LICENSE for more information. +# +include $(TOPDIR)/rules.mk + +PKG_NAME:=trojan +PKG_VERSION:=1.16.0 +PKG_RELEASE:=3 + +PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz +PKG_SOURCE_URL:=https://codeload.github.com/trojan-gfw/trojan/tar.gz/v$(PKG_VERSION)? +PKG_HASH:=skip + +PKG_BUILD_PARALLEL:=1 +PKG_BUILD_DEPENDS:=openssl + +PKG_LICENSE:=GPL-3.0 +PKG_LICENSE_FILE:=LICENSE +PKG_MAINTAINER:=GreaterFire + +include $(INCLUDE_DIR)/package.mk +include $(INCLUDE_DIR)/cmake.mk +include ./boost-version.mk + +TARGET_CXXFLAGS += -Wall -Wextra +TARGET_CXXFLAGS += $(FPIC) + +# LTO +TARGET_CXXFLAGS += -flto +TARGET_LDFLAGS += -flto + +# CXX standard +TARGET_CXXFLAGS += -std=c++11 +TARGET_CXXFLAGS := $(filter-out -O%,$(TARGET_CXXFLAGS)) -O3 +TARGET_CXXFLAGS += -ffunction-sections -fdata-sections +TARGET_LDFLAGS += -Wl,--gc-sections + +CMAKE_OPTIONS += \ + -DENABLE_MYSQL=OFF \ + -DENABLE_NAT=ON \ + -DENABLE_REUSE_PORT=ON \ + -DENABLE_SSL_KEYLOG=ON \ + -DENABLE_TLS13_CIPHERSUITES=ON \ + -DFORCE_TCP_FASTOPEN=OFF \ + -DSYSTEMD_SERVICE=OFF \ + -DOPENSSL_USE_STATIC_LIBS=FALSE \ + -DBoost_DEBUG=ON \ + -DBoost_NO_BOOST_CMAKE=ON + +define Package/trojan + SECTION:=net + CATEGORY:=Network + SUBMENU:=Web Servers/Proxies + TITLE:=An unidentifiable mechanism that helps you bypass GFW + URL:=https://github.com/trojan-gfw/trojan + DEPENDS:= \ + +libpthread +libstdcpp +libopenssl \ + +boost +boost-program_options +boost-date_time \ + $(if $(filter y,$(NEED_BOOST_SYSTEM)),,+boost-system) +endef + +define Package/trojan/install + $(INSTALL_DIR) $(1)/usr/sbin + $(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/trojan $(1)/usr/sbin/trojan +endef + +$(eval $(call BuildPackage,trojan)) diff --git a/trojan/boost-version.mk b/trojan/boost-version.mk new file mode 100644 index 00000000..72beca47 --- /dev/null +++ b/trojan/boost-version.mk @@ -0,0 +1,12 @@ +# boost-version.mk +BOOST_MAKEFILE := $(firstword $(shell find -L $(TOPDIR) -type f -path "*/boost/Makefile")) + +BOOST_PKG_VERSION := $(shell grep '^PKG_VERSION:=' $(BOOST_MAKEFILE) | head -n1 | cut -d= -f2) + +BOOST_VER_MAJOR := $(word 1,$(subst ., ,$(BOOST_PKG_VERSION))) +BOOST_VER_MINOR := $(word 2,$(subst ., ,$(BOOST_PKG_VERSION))) +BOOST_VER_PATCH := $(word 3,$(subst ., ,$(BOOST_PKG_VERSION))) + +BOOST_VERSION_CODE := $(shell echo $$(($(BOOST_VER_MAJOR)*100000 + $(BOOST_VER_MINOR)*100 + $(BOOST_VER_PATCH)))) + +NEED_BOOST_SYSTEM := $(if $(shell [ $(BOOST_VERSION_CODE) -ge 108900 ] && echo y),y,n) diff --git a/trojan/patches/001-force-openssl-version.patch b/trojan/patches/001-force-openssl-version.patch new file mode 100644 index 00000000..7ee8f631 --- /dev/null +++ b/trojan/patches/001-force-openssl-version.patch @@ -0,0 +1,11 @@ +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -43,7 +43,7 @@ if(MSVC) + add_definitions(-DBOOST_DATE_TIME_NO_LIB) + endif() + +-find_package(OpenSSL 1.1.0 REQUIRED) ++find_package(OpenSSL 1.1.1 REQUIRED) + include_directories(${OPENSSL_INCLUDE_DIR}) + target_link_libraries(trojan ${OPENSSL_LIBRARIES}) + if(OPENSSL_VERSION VERSION_GREATER_EQUAL 1.1.1) diff --git a/trojan/patches/002-Fix-boost1.89-build.patch b/trojan/patches/002-Fix-boost1.89-build.patch new file mode 100644 index 00000000..69e23634 --- /dev/null +++ b/trojan/patches/002-Fix-boost1.89-build.patch @@ -0,0 +1,16 @@ +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -36,7 +36,12 @@ set(THREADS_PREFER_PTHREAD_FLAG ON) + find_package(Threads REQUIRED) + target_link_libraries(trojan ${CMAKE_THREAD_LIBS_INIT}) + +-find_package(Boost 1.66.0 REQUIRED COMPONENTS system program_options) ++find_package(Boost 1.66.0 REQUIRED) ++if (Boost_MAJOR_VERSION LESS_EQUAL 1 AND Boost_MINOR_VERSION LESS 89) ++ find_package(Boost 1.66.0 REQUIRED COMPONENTS system program_options) ++else() ++ find_package(Boost 1.66.0 REQUIRED COMPONENTS program_options) ++endif() + include_directories(${Boost_INCLUDE_DIR}) + target_link_libraries(trojan ${Boost_LIBRARIES}) + if(MSVC)