diff --git a/luci-app-ssr-plus/Makefile b/luci-app-ssr-plus/Makefile index e154a41cc..507fb656c 100644 --- a/luci-app-ssr-plus/Makefile +++ b/luci-app-ssr-plus/Makefile @@ -4,7 +4,7 @@ LUCI_TITLE:=luci-app-ssr-plus LUCI_PKGARCH:=all PKG_NAME:=luci-app-ssr-plus PKG_VERSION:=196 -PKG_RELEASE:=91 +PKG_RELEASE:=92 PKG_CONFIG_DEPENDS:= \ CONFIG_PACKAGE_$(PKG_NAME)_Iptables_Transparent_Proxy \ 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 bfb92e1d0..cd3e59b86 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 @@ -472,6 +472,7 @@ end o:value("shadowsocks", translate("ShadowSocks")) if is_finded("xray") then o:value("wireguard", translate("WireGuard")) + o:value("naive", "NaiveProxy (Xray / Cronet)") end if is_finded("xray") then o:value("hysteria2", translate("Hysteria2")) @@ -543,6 +544,7 @@ o:depends({type = "v2ray", v2ray_protocol = "socks"}) o = s:option(Value, "username", translate("Username")) o.rmempty = true o:depends("type", "naiveproxy") +o:depends({type = "v2ray", v2ray_protocol = "naive"}) o:depends({type = "socks5", auth_enable = true}) o:depends({type = "v2ray", v2ray_protocol = "http", auth_enable = true}) o:depends({type = "v2ray", v2ray_protocol = "socks", auth_enable = true}) @@ -562,6 +564,7 @@ o:depends({type = "v2ray", v2ray_protocol = "socks", socks_ver = "5", auth_enabl o:depends({type = "v2ray", v2ray_protocol = "shadowsocks"}) o:depends({type = "v2ray", v2ray_protocol = "trojan"}) o:depends({type = "v2ray", v2ray_protocol = "anytls"}) +o:depends({type = "v2ray", v2ray_protocol = "naive"}) for _, field in ipairs({ {"anytls_idle_session_check_interval", "Idle session check interval (seconds)", "30"}, @@ -1584,7 +1587,10 @@ o:depends("xtls", true) o:depends("reality", true) o.rmempty = true +o:depends({type = "v2ray", v2ray_protocol = "naive"}) + -- TLS ALPN + o = s:option(ListValue, "tls_alpn", translate("TLS ALPN")) o.default = "" o:value("", translate("Default")) @@ -1852,4 +1858,23 @@ if is_finded("kcptun-client") then o:depends("type", "ss") end + +-- Naive uses Cronet TLS and multiplexing, independently of Xray stream TLS. +for _, field in ipairs({ + {"naive_quic", "Naive HTTP/3 (QUIC)"}, + {"naive_udp_over_tcp", "Naive UDP over TCP (server support required)"} +}) do + o = s:option(Flag, field[1], translate(field[2])) + o.default = "0" + o:depends({type = "v2ray", v2ray_protocol = "naive"}) +end +for _, field in ipairs({ + {"naive_certificate_file", "Naive trusted CA certificate file"}, + {"naive_ech_config", "Naive ECH config list (base64)"} +}) do + o = s:option(Value, field[1], translate(field[2])) + o.rmempty = true + o:depends({type = "v2ray", v2ray_protocol = "naive"}) +end + return m 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 4c8fcca1d..0afbfc551 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 @@ -72,6 +72,9 @@ then o:value("trojan", "Trojan (Mihomo/Xray)") o:value("shadowsocks", "Shadowsocks (Mihomo/Xray)") end +if nixio.fs.access("/usr/bin/xray") or nixio.fs.access("/usr/libexec/xray") then + o:value("naive", "NaiveProxy (Xray)") +end o.default = "socks5" o = s:option(Value, "server_port", translate("Server Port")) @@ -91,11 +94,13 @@ o:depends("type", "ssr") o = s:option(Value, "username", translate("Username")) o.rmempty = false o:depends("type", "socks5") +o:depends("type", "naive") o = s:option(Value, "password", translate("Password")) o.password = true o.rmempty = false o:depends("type", "socks5") +o:depends("type", "naive") o:depends("type", "ss") o:depends("type", "ssr") o:depends("type", "trojan") @@ -231,12 +236,16 @@ o.description = translate("e.g.: /etc/ssl/fullchain.pem") o.rmempty = true o:depends("tls", "1") +o:depends("type", "naive") + 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:depends("type", "naive") + o = s:option(ListValue, "transport", translate("Transport Protocol")) o:value("tcp", "TCP") o:value("mkcp", "mKCP") @@ -395,4 +404,11 @@ o:depends("type", "vless") o:depends("type", "trojan") o:depends("type", "shadowsocks") +o = s:option(ListValue, "naive_alpn", translate("Naive transport")) +o:value("h2", "HTTP/2") +o:value("h3", "HTTP/3") +o:value("h2,h3", "HTTP/2 + HTTP/3") +o.default = "h2" +o:depends("type", "naive") + return m \ No newline at end of file diff --git a/luci-app-ssr-plus/po/templates/ssr-plus.pot b/luci-app-ssr-plus/po/templates/ssr-plus.pot index baaf4cd8f..ce5cdf347 100644 --- a/luci-app-ssr-plus/po/templates/ssr-plus.pot +++ b/luci-app-ssr-plus/po/templates/ssr-plus.pot @@ -3378,3 +3378,18 @@ msgstr "" msgid "Minimum idle sessions" msgstr "" + +msgid "Naive HTTP/3 (QUIC)" +msgstr "" + +msgid "Naive UDP over TCP (server support required)" +msgstr "" + +msgid "Naive trusted CA certificate file" +msgstr "" + +msgid "Naive ECH config list (base64)" +msgstr "" + +msgid "Naive transport" +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 831ac7fe1..903ae55eb 100644 --- a/luci-app-ssr-plus/po/zh_Hans/ssr-plus.po +++ b/luci-app-ssr-plus/po/zh_Hans/ssr-plus.po @@ -3885,3 +3885,18 @@ msgstr "国内 IPv6 地址库更新地址" msgid "China IPv6 Data" msgstr "国内 IPv6 地址库" + +msgid "Naive HTTP/3 (QUIC)" +msgstr "Naive HTTP/3(QUIC)" + +msgid "Naive UDP over TCP (server support required)" +msgstr "Naive UDP over TCP(需要服务端支持)" + +msgid "Naive trusted CA certificate file" +msgstr "Naive 信任的 CA 证书文件" + +msgid "Naive ECH config list (base64)" +msgstr "Naive ECH 配置列表(Base64)" + +msgid "Naive transport" +msgstr "Naive 传输协议" diff --git a/luci-app-ssr-plus/root/etc/init.d/shadowsocksr b/luci-app-ssr-plus/root/etc/init.d/shadowsocksr index 98d34df52..972d0239f 100755 --- a/luci-app-ssr-plus/root/etc/init.d/shadowsocksr +++ b/luci-app-ssr-plus/root/etc/init.d/shadowsocksr @@ -992,6 +992,8 @@ use_mihomo_for_ss_rust_server() { } start_v2ray_with_mihomo() { + # Naive requires the Cronet-enabled Xray build. Never fall back to Mihomo. + [ "$(uci_get_by_name "$1" v2ray_protocol)" = "naive" ] && return 1 local sid="$1" local local_port="$2" local socks_port="$3" @@ -1796,7 +1798,7 @@ start_udp() { ;; v2ray) enable_mihomo=$(uci_get_by_type server_subscribe enable_mihomo "") - if [ "$enable_mihomo" = "1" ] && has_mihomo_binary; then + if [ "$(uci_get_by_name "$UDP_RELAY_SERVER" v2ray_protocol)" != "naive" ] && [ "$enable_mihomo" = "1" ] && has_mihomo_binary; then redir_udp=0 ARG_UDP="" echolog "UDP TPROXY Relay:V2Ray/Xray 单节点由主 Mihomo 实例处理。" @@ -1809,7 +1811,7 @@ start_udp() { echolog "UDP TPROXY Relay:$($(first_type xray) version | head -1) Started!" else # Xray 不存在但 Mihomo 存在,回退到 Mihomo(当 enable_mihomo=0 时) - if has_mihomo_binary; then + if [ "$(uci_get_by_name "$UDP_RELAY_SERVER" v2ray_protocol)" != "naive" ] && has_mihomo_binary; then redir_udp=0 ARG_UDP="" echolog "UDP TPROXY Relay:Xray 内核不存在,已回退到 Mihomo 内核启动。" @@ -2249,6 +2251,10 @@ get_udp_relay_mode() { v2ray) proto=$(uci_get_by_name "$node" v2ray_protocol) case "$proto" in + naive) + [ "$(uci_get_by_name "$node" naive_udp_over_tcp 0)" = "1" ] && echo "native" || echo "disabled" + ;; + http) echo "disabled" ;; @@ -2736,6 +2742,16 @@ start_server() { fi echolog "Server:Socks5 Server$server_count Started!" ;; + naive) + xray_bin="$(first_type xray)" + [ -x "$xray_bin" ] || return 1 + config_file="$TMP_PATH/xray-server-$server_count.json" + lua /usr/share/shadowsocksr/gen_naive_server.lua "$1" > "$config_file" || return 1 + "$xray_bin" run -test -c "$config_file" >> /var/ssrplus.log 2>&1 || return 1 + ln_start_bin "$xray_bin" xray-server-$server_count run -c "$config_file" + echolog "Server: Xray NaiveProxy Server$server_count Started!" + ;; + vmess|vless|trojan|shadowsocks) # Xray 服务端支持 port=$(uci_get_by_name "$1" server_port) 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 9284efc95..3accbf240 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 @@ -375,6 +375,19 @@ function outbound:handleIndex(index) wireguard = function() wireguard() end, + naive = function() + outbound_settings = { + address = server.server, port = tonumber(server.server_port), + username = server.username, password = server.password, + serverName = server.tls_host, + certificateFile = server.naive_certificate_file, + quic = server.naive_quic == "1", + udpOverTcp = server.naive_udp_over_tcp == "1", + insecureConcurrency = tonumber(server.naive_concurrency), + quicCongestionControl = server.naive_quic_congestion, + echConfigList = server.naive_ech_config + } + end, anytls = function() outbound_settings = { address = server.server, @@ -878,6 +891,13 @@ Xray.outbounds = { } } +-- Cronet owns TLS and multiplexing. Preserve Xray socket marks and dialer chains. +if server.v2ray_protocol == "naive" then + local ob = Xray.outbounds[1] + ob.streamSettings = { network = "raw", sockopt = ob.streamSettings.sockopt } + ob.mux = nil +end + if xray_builtin_dns then table.insert(Xray.outbounds, { protocol = "dns", diff --git a/luci-app-ssr-plus/root/usr/share/shadowsocksr/gen_naive_server.lua b/luci-app-ssr-plus/root/usr/share/shadowsocksr/gen_naive_server.lua new file mode 100644 index 000000000..2b7fe86bd --- /dev/null +++ b/luci-app-ssr-plus/root/usr/share/shadowsocksr/gen_naive_server.lua @@ -0,0 +1,20 @@ +#!/usr/bin/lua +local uci = require("luci.model.uci").cursor() +local json = require "luci.jsonc" +local s = assert(uci:get_all("shadowsocksr", arg[1]), "missing server section") +assert(s.username and s.username ~= "" and s.password and s.password ~= "", "Naive credentials required") +assert(s.tls_certificateFile and s.tls_keyFile, "Naive TLS certificate and key required") +local alpn = {} +local selected = s.naive_alpn or "h2" +assert(selected == "h2" or selected == "h3" or selected == "h2,h3", "invalid Naive transport") +for value in selected:gmatch("[^,]+") do alpn[#alpn + 1] = value end +print(json.stringify({ + log = {loglevel = "warning"}, + inbounds = {{listen = "::", port = assert(tonumber(s.server_port)), protocol = "naive", + settings = {users = {{username = s.username, password = s.password}}}, + streamSettings = {network = "naive", security = "tls", tlsSettings = { + alpn = alpn, certificates = {{certificateFile = s.tls_certificateFile, keyFile = s.tls_keyFile}} + }} + }}, + outbounds = {{protocol = "freedom", settings = {}}} +}, 1)) diff --git a/luci-app-vantage/Makefile b/luci-app-vantage/Makefile index 676db6e55..5e1c25223 100644 --- a/luci-app-vantage/Makefile +++ b/luci-app-vantage/Makefile @@ -10,8 +10,8 @@ include $(TOPDIR)/rules.mk PKG_NAME:=luci-app-vantage -PKG_VERSION:=1.0.8 -PKG_RELEASE:=15 +PKG_VERSION:=1.0.9 +PKG_RELEASE:=16 PKG_LICENSE:=GPL-3.0-or-later LUCI_TITLE:=Vantage dashboard diff --git a/luci-app-vantage/htdocs/luci-static/resources/vantage/model.js b/luci-app-vantage/htdocs/luci-static/resources/vantage/model.js index 26a563609..ebeb56131 100644 --- a/luci-app-vantage/htdocs/luci-static/resources/vantage/model.js +++ b/luci-app-vantage/htdocs/luci-static/resources/vantage/model.js @@ -214,7 +214,7 @@ return baseclass.extend({ if (d && d.devtype === 'dsa' && d['hw-tc-offload'] && d.conduit && devs[d.conduit]) statsDev = d.conduit; - var route = defRoute(pick); + var route = defRoute(pick), via = route && route.nexthop; return { iface: pick.interface, l3dev: l3, @@ -228,7 +228,9 @@ return baseclass.extend({ speed: d ? this.parseSpeed(d.speed) : null, ipv4: arr(pick['ipv4-address']).map(function(a) { return a && a.address ? a.address + '/' + a.mask : null; }).filter(Boolean), ipv6: arr(pick['ipv6-address']).map(function(a) { return a && a.address ? a.address + '/' + a.mask : null; }).filter(Boolean), - gateway: route && route.nexthop && route.nexthop !== '0.0.0.0' ? route.nexthop : null, + gateway: via && via !== '0.0.0.0' && via !== '::' ? via : null, + /* a tunnel's default route has no next hop: routed, without a gateway address */ + defaultRoute: !!route, dns: arr(pick['dns-server']).filter(function(s) { return typeof s === 'string'; }), stats: d && d.statistics ? d.statistics : null }; diff --git a/luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js b/luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js index 3d7222a30..b189a58e7 100644 --- a/luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js +++ b/luci-app-vantage/htdocs/luci-static/resources/view/vantage/overview.js @@ -1427,7 +1427,7 @@ return view.extend({ updateHero: function() { var self = this, m = this.m, st = this.st, h = this.hero, up = m.uplink, upR = st.uplinkRate, d = m.device; txt(h.gwKicker, up && up.isWan ? _('Internet') : _('Gateway')); - txt(h.gwTitle, up && up.gateway ? up.gateway : _('No default route')); + txt(h.gwTitle, up && up.gateway ? up.gateway : up && up.defaultRoute ? up.l3dev : _('No default route')); txt(h.gwSub, up && up.dns.length ? _('DNS %s').format(up.dns[0]) : _('Reachability not probed')); txt(h.dnVal, upR ? fmt.bitsParts(upR.rx).v : fmt.DASH); diff --git a/luci-app-vantage/po/templates/vantage.pot b/luci-app-vantage/po/templates/vantage.pot index cef305aa5..2e3a94f2a 100644 --- a/luci-app-vantage/po/templates/vantage.pot +++ b/luci-app-vantage/po/templates/vantage.pot @@ -1332,7 +1332,7 @@ msgstr "" msgid "Open network" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/model.js:488 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/model.js:490 msgid "OpenWrt device" msgstr "" @@ -1464,7 +1464,7 @@ msgstr "" msgid "Reverse DNS of its address" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/model.js:500 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/model.js:502 msgid "Root (overlay)" msgstr "" @@ -1605,7 +1605,7 @@ msgstr "" msgid "Tbit/s" msgstr "" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/model.js:500 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/model.js:502 msgid "Temporary (RAM)" msgstr "" diff --git a/luci-app-vantage/po/zh_Hans/vantage.po b/luci-app-vantage/po/zh_Hans/vantage.po index 5693350f1..913eae55d 100644 --- a/luci-app-vantage/po/zh_Hans/vantage.po +++ b/luci-app-vantage/po/zh_Hans/vantage.po @@ -1348,7 +1348,7 @@ msgstr "对互联网开放:%d" msgid "Open network" msgstr "开放网络" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/model.js:488 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/model.js:490 msgid "OpenWrt device" msgstr "OpenWrt 设备" @@ -1484,7 +1484,7 @@ msgstr "" msgid "Reverse DNS of its address" msgstr "其地址的反向 DNS" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/model.js:500 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/model.js:502 msgid "Root (overlay)" msgstr "Root(overlay)" @@ -1625,7 +1625,7 @@ msgstr "系统设置" msgid "Tbit/s" msgstr "Tbit/s" -#: luci-app-vantage/htdocs/luci-static/resources/vantage/model.js:500 +#: luci-app-vantage/htdocs/luci-static/resources/vantage/model.js:502 msgid "Temporary (RAM)" msgstr "临时(RAM)" diff --git a/luci-theme-vantage/Makefile b/luci-theme-vantage/Makefile index 7212a28f9..aa3495456 100644 --- a/luci-theme-vantage/Makefile +++ b/luci-theme-vantage/Makefile @@ -10,8 +10,8 @@ include $(TOPDIR)/rules.mk PKG_NAME:=luci-theme-vantage -PKG_VERSION:=1.0.8 -PKG_RELEASE:=20 +PKG_VERSION:=1.0.9 +PKG_RELEASE:=21 PKG_LICENSE:=GPL-3.0-or-later LUCI_TITLE:=Vantage theme diff --git a/meow/Makefile b/meow/Makefile index 1b4534382..b3c21bf3e 100644 --- a/meow/Makefile +++ b/meow/Makefile @@ -6,7 +6,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=meow PKG_VERSION:=0.25.0 -PKG_RELEASE:=13 +PKG_RELEASE:=14 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz PKG_SOURCE_URL:=https://codeload.github.com/meow-rs/meow-rs/tar.gz/v$(PKG_VERSION)? @@ -17,7 +17,7 @@ PKG_MAINTAINER:=Max Lv PKG_LICENSE:=MIT PKG_LICENSE_FILES:=LICENSE -PKG_BUILD_DEPENDS:=rust/host cmake/host +PKG_BUILD_DEPENDS:=rust/host PKG_BUILD_PARALLEL:=1 include $(INCLUDE_DIR)/package.mk