diff --git a/luci-app-passwall/luasrc/controller/passwall.lua b/luci-app-passwall/luasrc/controller/passwall.lua index 2b2f8ca96..308e4efeb 100644 --- a/luci-app-passwall/luasrc/controller/passwall.lua +++ b/luci-app-passwall/luasrc/controller/passwall.lua @@ -334,10 +334,7 @@ function connect_status() local proxy_mode = uci:get(appname, "@global[0]", "tcp_proxy_mode") or "proxy" local localhost_proxy = uci:get(appname, "@global[0]", "localhost_proxy") or "1" local socks_server = (localhost_proxy == "0") and api.get_cache_var("GLOBAL_TCP_SOCKS_server") or "" - -- 兼容 curl 8.6 time_starttransfer 错误 - local curl_ver = api.get_bin_version_cache("/usr/bin/curl", "-V 2>/dev/null | head -n 1 | awk '{print $2}' | cut -d. -f1,2 | tr -d ' \n'") or "0" - url = (curl_ver == "8.6") and "-w %{http_code}:%{time_appconnect} https://" .. url - or "-w %{http_code}:%{time_starttransfer} http://" .. url + url = "-w %{http_code}:%{time_pretransfer} " .. url if socks_server and socks_server ~= "" then if (chn_list == "proxy" and gfw_list == "0" and proxy_mode ~= "proxy" and baidu ~= nil) or (chn_list == "0" and gfw_list == "0" and proxy_mode == "proxy") then -- 中国列表+百度 or 全局 diff --git a/luci-app-passwall/luasrc/model/cbi/passwall/client/global.lua b/luci-app-passwall/luasrc/model/cbi/passwall/client/global.lua index f1e1c4a97..52ee3d9c9 100644 --- a/luci-app-passwall/luasrc/model/cbi/passwall/client/global.lua +++ b/luci-app-passwall/luasrc/model/cbi/passwall/client/global.lua @@ -682,13 +682,36 @@ o.default = "proxy" o = s:taboption("Proxy", DummyValue, "switch_mode", " ") o.template = appname .. "/global/proxy" -o = s:taboption("Proxy", Flag, "localhost_proxy", translate("Localhost Proxy"), translate("When selected, localhost can transparent proxy.")) -o.default = "1" -o.rmempty = false +---- Check the transparent proxy component +local handle = io.popen("lsmod") +local mods = "" +if handle then + mods = handle:read("*a") or "" + handle:close() +end -o = s:taboption("Proxy", Flag, "client_proxy", translate("Client Proxy"), translate("When selected, devices in LAN can transparent proxy. Otherwise, it will not be proxy. But you can still use access control to allow the designated device to proxy.")) -o.default = "1" -o.rmempty = false +if (mods:find("REDIRECT") and mods:find("TPROXY")) or (mods:find("nft_redir") and mods:find("nft_tproxy")) then + o = s:taboption("Proxy", Flag, "localhost_proxy", translate("Localhost Proxy"), translate("When selected, localhost can transparent proxy.")) + o.default = "1" + o.rmempty = false + + o = s:taboption("Proxy", Flag, "client_proxy", translate("Client Proxy"), translate("When selected, devices in LAN can transparent proxy. Otherwise, it will not be proxy. But you can still use access control to allow the designated device to proxy.")) + o.default = "1" + o.rmempty = false +else + local html = string.format([[
%s
]], translate("Missing components, transparent proxy is unavailable.")) + o = s:taboption("Proxy", DummyValue, "localhost_proxy", translate("Localhost Proxy")) + o.rawhtml = true + function o.cfgvalue(self, section) + return html + end + + o = s:taboption("Proxy", DummyValue, "client_proxy", translate("Client Proxy")) + o.rawhtml = true + function o.cfgvalue(self, section) + return html + end +end o = s:taboption("Proxy", DummyValue, "_proxy_tips", " ") o.rawhtml = true diff --git a/luci-app-passwall/luasrc/model/cbi/passwall/client/other.lua b/luci-app-passwall/luasrc/model/cbi/passwall/client/other.lua index 2bdec526f..cc45708a3 100644 --- a/luci-app-passwall/luasrc/model/cbi/passwall/client/other.lua +++ b/luci-app-passwall/luasrc/model/cbi/passwall/client/other.lua @@ -124,7 +124,15 @@ if has_fw4 then o:value("1", "NFtables") end -if (os.execute("lsmod | grep -i REDIRECT >/dev/null") == 0 and os.execute("lsmod | grep -i TPROXY >/dev/null") == 0) or (os.execute("lsmod | grep -i nft_redir >/dev/null") == 0 and os.execute("lsmod | grep -i nft_tproxy >/dev/null") == 0) then +---- Check the transparent proxy component +local handle = io.popen("lsmod") +local mods = "" +if handle then + mods = handle:read("*a") or "" + handle:close() +end + +if (mods:find("REDIRECT") and mods:find("TPROXY")) or (mods:find("nft_redir") and mods:find("nft_tproxy")) then o = s:option(ListValue, "tcp_proxy_way", translate("TCP Proxy Way")) o.default = "redirect" o:value("redirect", "REDIRECT") @@ -142,7 +150,7 @@ if (os.execute("lsmod | grep -i REDIRECT >/dev/null") == 0 and os.execute("lsmod self.map:set(section, "tcp_proxy_way", value) end - if os.execute("lsmod | grep -i ip6table_mangle >/dev/null") == 0 or os.execute("lsmod | grep -i nft_tproxy >/dev/null") == 0 then + if mods:find("ip6table_mangle") or mods:find("nft_tproxy") then ---- IPv6 TProxy o = s:option(Flag, "ipv6_tproxy", translate("IPv6 TProxy"), "" .. translate( diff --git a/luci-app-passwall/luasrc/view/passwall/global/status.htm b/luci-app-passwall/luasrc/view/passwall/global/status.htm index 751475f61..e8d76ec4c 100644 --- a/luci-app-passwall/luasrc/view/passwall/global/status.htm +++ b/luci-app-passwall/luasrc/view/passwall/global/status.htm @@ -138,7 +138,7 @@ https://github.com/pure-css/pure/blob/master/LICENSE.md -
+
@@ -150,7 +150,7 @@ https://github.com/pure-css/pure/blob/master/LICENSE.md
-
+
@@ -162,7 +162,7 @@ https://github.com/pure-css/pure/blob/master/LICENSE.md
-
+
@@ -174,7 +174,7 @@ https://github.com/pure-css/pure/blob/master/LICENSE.md
-
+
diff --git a/luci-app-passwall/po/zh-cn/passwall.po b/luci-app-passwall/po/zh-cn/passwall.po index fd9b483a8..36dcf9c56 100644 --- a/luci-app-passwall/po/zh-cn/passwall.po +++ b/luci-app-passwall/po/zh-cn/passwall.po @@ -352,6 +352,9 @@ msgstr "客户端代理" msgid "When selected, devices in LAN can transparent proxy. Otherwise, it will not be proxy. But you can still use access control to allow the designated device to proxy." msgstr "当勾选时,局域网内的设备可以透明代理。否则,将不代理。但您仍然可以使用访问控制允许指定的设备代理。" +msgid "Missing components, transparent proxy is unavailable." +msgstr "缺少组件,透明代理不可用。" + msgid "Want different devices to use different proxy modes/ports/nodes? Please use access control." msgstr "希望不同设备使用不同的代理模式/端口/节点?请使用访问控制。" diff --git a/luci-app-passwall/root/usr/share/passwall/test.sh b/luci-app-passwall/root/usr/share/passwall/test.sh index 447ea5385..c589f8909 100755 --- a/luci-app-passwall/root/usr/share/passwall/test.sh +++ b/luci-app-passwall/root/usr/share/passwall/test.sh @@ -74,7 +74,7 @@ url_test_node() { fi sleep 1s local probeUrl=$(config_t_get global_other url_test_url https://www.google.com/generate_204) - result=$(curl --connect-timeout 3 --max-time 5 -o /dev/null -I -skL -w "%{http_code}:%{time_starttransfer}" -x ${curlx} "${probeUrl}") + result=$(curl --connect-timeout 3 --max-time 5 -o /dev/null -I -skL -w "%{http_code}:%{time_pretransfer}" -x ${curlx} "${probeUrl}") # 结束 SS 插件进程 local pid_file="/tmp/etc/${CONFIG}/url_test_${node_id}_plugin.pid" [ -s "$pid_file" ] && kill -9 "$(head -n 1 "$pid_file")" >/dev/null 2>&1 diff --git a/luci-app-xray/README.md b/luci-app-xray/README.md index 783e29fc2..a3384e393 100644 --- a/luci-app-xray/README.md +++ b/luci-app-xray/README.md @@ -38,7 +38,7 @@ Fork this repository and: * Create a release by pushing a tag * Wait until actions finish -* Use `opkg -i *` to install both ipks from Releases. +* Use `opkg -i *` to install all ipks from Releases. ## Enable preview app @@ -56,6 +56,7 @@ Some features are deprecated / unstable so they are placed in preview app. To en * 2025-07-27 fix: dynamic direct: only cover global servers; increase default timeout * 2025-08-20 fix: dynamic direct connection tracking * 2025-08-26 fix: dnsmasq global integration mode +* 2026-01-13 feat: feat: vless encryption; minor DNS tweaks; code cleanups ## Changelog since 3.5.0 diff --git a/luci-app-xray/core/root/usr/share/xray/feature/dns.mjs b/luci-app-xray/core/root/usr/share/xray/feature/dns.mjs index 3c46b8e34..c33335aec 100644 --- a/luci-app-xray/core/root/usr/share/xray/feature/dns.mjs +++ b/luci-app-xray/core/root/usr/share/xray/feature/dns.mjs @@ -34,14 +34,14 @@ function parse_ip_port(val, port_default) { function format_dns(method, val) { const parsed = parse_ip_port(val, 53); - if (method == "udp") { + if (method === "udp") { return { address: parsed["ip"], port: parsed["port"] }; } let url_suffix = ""; - if (substr(method, 0, 5) == "https") { + if (substr(method, 0, 5) === "https") { url_suffix = "/dns-query"; } return { @@ -50,11 +50,11 @@ function format_dns(method, val) { } function domain_rules(proxy, k) { - if (proxy[k] == null) { + if (proxy[k] === null) { return []; } return filter(proxy[k], function (x) { - if (substr(x, 0, 8) == "geosite:") { + if (substr(x, 0, 8) === "geosite:") { return geosite_existence; } return true; @@ -96,11 +96,27 @@ export function dns_server_inbounds(proxy) { export function dns_rules(proxy, tcp_hijack_inbound_tags, udp_hijack_inbound_tags) { const dns_port = int(proxy["dns_port"] || 5300); const dns_count = int(proxy["dns_count"] || 3); + const fast_dns = parse_ip_port(proxy["fast_dns"] || fallback_fast_dns, 53); + const secure_dns = parse_ip_port(proxy["secure_dns"] || fallback_secure_dns, 53); let dns_server_tags = []; for (let i = dns_port; i <= dns_port + dns_count; i++) { push(dns_server_tags, sprintf("dns_server_inbound:%d", i)); } let result = [ + { + type: "field", + inboundTag: ["dns_conf_inbound"], + ip: [fast_dns["ip"]], + port: `${fast_dns["port"]}`, + outboundTag: "dynamic_direct" + }, + { + type: "field", + inboundTag: ["dns_conf_inbound"], + ip: [secure_dns["ip"]], + port: `${secure_dns["port"]}`, + balancerTag: "udp_outbound_v4" + }, { type: "field", inboundTag: dns_server_tags, @@ -157,7 +173,7 @@ export function dns_conf(proxy, config, manual_tproxy, fakedns) { let domain_names_set = {}; let domain_extra_options = {}; - for (let server in filter(values(config), i => i[".type"] == "servers")) { + for (let server in filter(values(config), i => i[".type"] === "servers")) { if (iptoarr(server["server"])) { continue; } @@ -206,6 +222,20 @@ export function dns_conf(proxy, config, manual_tproxy, fakedns) { port: fast_dns_object["port"], domains: [...keys(domain_names_set), ...fast_domain_rules(proxy)], skipFallback: true, + expectIPs: function () { + let ips = []; + if (proxy["align_fast_dns_to_geoip_direct"] === "1") { + if (geoip_existence) { + const geoip_direct_code_list = map(proxy["geoip_direct_code_list"] || [], v => index(v, ":") > 0 ? v : `geoip:${v}`); + const geoip_direct_code_list_v6 = map(proxy["geoip_direct_code_list_v6"] || [], v => index(v, ":") > 0 ? v : `geoip:${v}`); + push(ips, ...geoip_direct_code_list, ...geoip_direct_code_list_v6); + } + } + if (length(ips) > 0) { + return uniq(ips); + } + return null; + }(), }, ]; @@ -228,7 +258,7 @@ export function dns_conf(proxy, config, manual_tproxy, fakedns) { for (let v in manual_tproxy) { if (v.domain_names != null) { for (let d in v.domain_names) { - if (index(v.source_addr, ":") == -1) { + if (index(v.source_addr, ":") === -1) { hosts[d] = [v.source_addr]; } } @@ -245,13 +275,13 @@ export function dns_conf(proxy, config, manual_tproxy, fakedns) { export function dns_direct_servers(config) { let result = []; - for (let server in filter(values(config), i => i[".type"] == "servers")) { + for (let server in filter(values(config), i => i[".type"] === "servers")) { if (iptoarr(server["server"])) { continue; } if (server["domain_resolve_dns"]) { if (index(server["domain_resolve_dns_method"], "local") > 1) { - push(result, parse_ip_port(server["domain_resolve_dns"])["ip"]); + push(result, parse_ip_port(server["domain_resolve_dns"])); } } } diff --git a/luci-app-xray/core/root/usr/share/xray/feature/fake_dns.mjs b/luci-app-xray/core/root/usr/share/xray/feature/fake_dns.mjs index d821d1d7e..f21ff29ca 100644 --- a/luci-app-xray/core/root/usr/share/xray/feature/fake_dns.mjs +++ b/luci-app-xray/core/root/usr/share/xray/feature/fake_dns.mjs @@ -7,7 +7,7 @@ export function fake_dns_domains(fakedns) { for (let f in fakedns) { push(domains, ...f["fake_dns_domain_names"]); } - if (length(domains) == 0) { + if (length(domains) === 0) { return []; } return [ diff --git a/luci-app-xray/core/root/usr/share/xray/feature/manual_tproxy.mjs b/luci-app-xray/core/root/usr/share/xray/feature/manual_tproxy.mjs index 0e7080ac1..4f43d8ea8 100644 --- a/luci-app-xray/core/root/usr/share/xray/feature/manual_tproxy.mjs +++ b/luci-app-xray/core/root/usr/share/xray/feature/manual_tproxy.mjs @@ -6,7 +6,7 @@ export function manual_tproxy_outbounds(config, manual_tproxy) { let result = []; for (let v in manual_tproxy) { let tcp_tag = "direct"; - if (v["force_forward_tcp"] == "1") { + if (v["force_forward_tcp"] === "1") { if (v["force_forward_server_tcp"] != null) { tcp_tag = `manual_tproxy:${v[".name"]}@tcp_outbound@force_forward:${v["force_forward_server_tcp"]}`; const force_forward_server_tcp = config[v["force_forward_server_tcp"]]; @@ -26,7 +26,7 @@ export function manual_tproxy_outbounds(config, manual_tproxy) { }); let udp_tag = "direct"; - if (v["force_forward_udp"] == "1") { + if (v["force_forward_udp"] === "1") { if (v["force_forward_server_udp"] != null) { udp_tag = `manual_tproxy:${v[".name"]}@udp_outbound@force_forward:${v["force_forward_server_udp"]}`; const force_forward_server_udp = config[v["force_forward_server_udp"]]; @@ -51,10 +51,10 @@ export function manual_tproxy_outbounds(config, manual_tproxy) { export function manual_tproxy_outbound_tags(manual_tproxy) { let result = []; for (let v in manual_tproxy) { - if (v["force_forward_tcp"] == "1") { + if (v["force_forward_tcp"] === "1") { push(result, `manual_tproxy:${v[".name"]}@tcp_outbound@force_forward:${v["force_forward_server_tcp"]}`); } - if (v["force_forward_udp"] == "1") { + if (v["force_forward_udp"] === "1") { push(result, `manual_tproxy:${v[".name"]}@udp_outbound@force_forward:${v["force_forward_server_udp"]}`); } } @@ -66,14 +66,14 @@ export function manual_tproxy_rules(manual_tproxy) { for (let v in manual_tproxy) { splice(result, 0, 0, { type: "field", - inboundTag: ["tproxy_tcp_inbound_v4", "socks_inbound", "https_inbound", "http_inbound"], + inboundTag: ["tproxy_tcp_inbound_v4", "tproxy_tcp_inbound_v6", "socks_inbound", "https_inbound", "http_inbound"], ip: [v["source_addr"]], port: v["source_port"], outboundTag: sprintf("manual_tproxy:%s@tcp_outbound", v[".name"]) }); splice(result, 0, 0, { type: "field", - inboundTag: ["tproxy_udp_inbound_v4"], + inboundTag: ["tproxy_udp_inbound_v4", "tproxy_udp_inbound_v6"], ip: [v["source_addr"]], port: v["source_port"], outboundTag: sprintf("manual_tproxy:%s@udp_outbound", v[".name"]) diff --git a/luci-app-xray/core/root/usr/share/xray/firewall_include.ut b/luci-app-xray/core/root/usr/share/xray/firewall_include.ut index f53aab5f9..9daac0e36 100644 --- a/luci-app-xray/core/root/usr/share/xray/firewall_include.ut +++ b/luci-app-xray/core/root/usr/share/xray/firewall_include.ut @@ -14,17 +14,15 @@ const udp6_enabled = length(general.udp_balancer_v6 || []) > 0; const uids_direct = uniq(general.uids_direct || []); const gids_direct = uniq(general.gids_direct || []); - let wan_bp_ips_no_dns = general.wan_bp_ips || []; - let wan_fw_ips_no_dns = general.wan_fw_ips || []; - push(wan_bp_ips_no_dns, split(general.fast_dns || "223.5.5.5:53", ":")[0]); - for (let i in dns_direct_servers(config)) { - push(wan_bp_ips_no_dns, i); - } - push(wan_fw_ips_no_dns, split(general.secure_dns || "8.8.8.8:53", ":")[0]); - const wan_bp_ips_v4 = filter(uniq(wan_bp_ips_no_dns), v => index(v, ":") == -1); - const wan_bp_ips_v6 = filter(uniq(wan_bp_ips_no_dns), v => index(v, ":") != -1); - const wan_fw_ips_v4 = filter(uniq(wan_fw_ips_no_dns), v => index(v, ":") == -1); - const wan_fw_ips_v6 = filter(uniq(wan_fw_ips_no_dns), v => index(v, ":") != -1); + let wan_bp_ips = uniq(general.wan_bp_ips || []); + let wan_fw_ips = uniq(general.wan_fw_ips || []); + let wan_bp_dns = dns_direct_servers(config); + const wan_bp_ips_v4 = filter(wan_bp_ips, v => index(v, ":") == -1); + const wan_bp_ips_v6 = filter(wan_bp_ips, v => index(v, ":") != -1); + const wan_fw_ips_v4 = filter(wan_fw_ips, v => index(v, ":") == -1); + const wan_fw_ips_v6 = filter(wan_fw_ips, v => index(v, ":") != -1); + const wan_bp_dns_v4 = filter(wan_bp_dns, v => index(v.ip, ":") == -1); + const wan_bp_dns_v6 = filter(wan_bp_dns, v => index(v.ip, ":") != -1); const transparent_default_port_policy = general.transparent_default_port_policy || "forwarded"; const wan_fw_tcp_ports = general.wan_fw_tcp_ports || []; const wan_fw_udp_ports = general.wan_fw_udp_ports || []; @@ -142,6 +140,28 @@ }(); %} +{% if (length(wan_bp_dns_v4) > 0): %} + set tp_spec_dp4_bp { + typeof ip daddr . udp dport + size {{ length(wan_bp_dns_v4) * 2 + 1 }} + flags interval + elements = { + {{ join(", ", uniq(map(wan_bp_dns_v4, v => `${v.ip} . ${v.port}`))) }} + } + } +{% endif %} + +{% if (length(wan_bp_dns_v6) > 0): %} + set tp_spec_dp6_bp { + typeof ip6 daddr . udp dport + size {{ length(wan_bp_dns_v6) * 2 + 1 }} + flags interval + elements = { + {{ join(", ", uniq(map(wan_bp_dns_v6, v => `${v.ip} . ${v.port}`))) }} + } + } +{% endif %} + set tp_spec_dv4_sp { type ipv4_addr size 32 @@ -508,6 +528,14 @@ {% if (length(manual_tproxy_source_ips) > 0): %} ip protocol tcp ip daddr @tp_spec_dv4_mt {{ counter }} goto tp_spec_lan_fw comment "Xray manual transparent proxy TCP" ip protocol udp ip daddr @tp_spec_dv4_mt {{ counter }} goto tp_spec_lan_fw comment "Xray manual transparent proxy UDP" +{% endif %} +{% if (length(wan_bp_dns_v4) > 0): %} + ip daddr . tcp dport @tp_spec_dp4_bp {{ counter }} accept + ip daddr . udp dport @tp_spec_dp4_bp {{ counter }} accept +{% endif %} +{% if (length(wan_bp_dns_v6) > 0): %} + ip6 daddr . tcp dport @tp_spec_dp6_bp {{ counter }} accept + ip6 daddr . udp dport @tp_spec_dp6_bp {{ counter }} accept {% endif %} {{ counter }} return } diff --git a/luci-app-xray/core/root/usr/share/xray/gen_config.uc b/luci-app-xray/core/root/usr/share/xray/gen_config.uc index 27b80fab8..98fd47cd0 100644 --- a/luci-app-xray/core/root/usr/share/xray/gen_config.uc +++ b/luci-app-xray/core/root/usr/share/xray/gen_config.uc @@ -285,4 +285,4 @@ function gen_config() { }); } -print(gen_config()); +printf("%.4J", gen_config()); diff --git a/luci-app-xray/core/root/usr/share/xray/geoip_list.pb b/luci-app-xray/core/root/usr/share/xray/geoip_list.pb deleted file mode 100644 index 1100406c6..000000000 Binary files a/luci-app-xray/core/root/usr/share/xray/geoip_list.pb and /dev/null differ diff --git a/luci-app-xray/core/root/usr/share/xray/protocol/vless.mjs b/luci-app-xray/core/root/usr/share/xray/protocol/vless.mjs index 135b42a22..c275595be 100644 --- a/luci-app-xray/core/root/usr/share/xray/protocol/vless.mjs +++ b/luci-app-xray/core/root/usr/share/xray/protocol/vless.mjs @@ -38,7 +38,7 @@ export function vless_outbound(server, tag) { email: server["username"], id: server["password"], flow: flow, - encryption: server["vless_encryption"] + encryption: server["vless_encryption"] || "none" } ] }; @@ -66,7 +66,7 @@ export function https_vless_inbound(proxy, config) { tag: "https_inbound", settings: { clients: map(proxy["web_server_password"], k => vless_inbound_user(k, flow)), - decryption: "none", + decryption: proxy["vless_decryption"] || "none", fallbacks: fallbacks(proxy, config) }, streamSettings: { diff --git a/luci-app-xray/core/root/www/luci-static/resources/view/xray/core.js b/luci-app-xray/core/root/www/luci-static/resources/view/xray/core.js index fcbb3ed0e..6f1e4c16b 100644 --- a/luci-app-xray/core/root/www/luci-static/resources/view/xray/core.js +++ b/luci-app-xray/core/root/www/luci-static/resources/view/xray/core.js @@ -242,20 +242,17 @@ return view.extend({ transport.init(o, ss, 'transport'); o.rmempty = false; - o = ss.taboption('transport', form.ListValue, 'dialer_proxy', _('Dialer Proxy'), _('Similar to ProxySettings.Tag')); - o.datatype = "uciname"; - o.value("disabled", _("Disabled")); - for (const v of uci.sections(config_data, "servers")) { - o.value(v[".name"], server_alias(v)); - } - o.modalonly = true; + let dialer_proxy = ss.taboption('transport', form.ListValue, 'dialer_proxy', _('Dialer Proxy'), _('Similar to ProxySettings.Tag')); + dialer_proxy.datatype = "uciname"; + dialer_proxy.value("disabled", _("Disabled")); + dialer_proxy.modalonly = true; ss.tab('custom', _('Custom Options')); - o = ss.taboption('custom', form.TextValue, 'custom_config', _('Custom Configurations'), _(`Configurations here override settings in the previous tabs with the following rules:
  1. Object values will be replaced recursively so settings in previous tabs matter.
  2. Arrays will be replaced entirely instead of being merged.
  3. Tag tag and mark streamSettings.sockopt.mark are ignored.
Aliases are not handled while merging configurations:
  1. Use tcpSettings instead of rawSettings.
  2. Use splithttpSettings instead of xhttpSettings.
Some transports like splithttp may use another streamSettings.sockopt:
  1. Read instructions here, and use ${firewall_mark} as sockopt.mark to avoid loopback traffic.
Override rules here may be changed later. Use this only for experimental or pre-release features.`)); + o = ss.taboption('custom', form.TextValue, 'custom_config', _('Custom Configurations'), _(`Configurations here override settings in the previous tabs with the following rules:
  • Object values will be replaced recursively so settings in previous tabs matter.
  • Arrays will be replaced entirely instead of being merged.
  • Tag tag and mark streamSettings.sockopt.mark are ignored.
Aliases are not handled while merging configurations:
  • Use tcpSettings instead of rawSettings.
  • Use splithttpSettings instead of xhttpSettings.
Some transports like splithttp may use another streamSettings.sockopt:Override rules here may be changed later. Use this only for experimental or pre-release features.`)); o.modalonly = true; o.monospace = true; - o.rows = 10; + o.rows = 12; o.validate = shared.validate_object; s.tab('inbounds', _('Inbounds')); @@ -465,13 +462,6 @@ return view.extend({ o.datatype = 'range(0, 50)'; o.placeholder = 3; - o = s.taboption('dns', form.ListValue, 'routing_domain_strategy', _('Routing Domain Strategy'), _("Domain resolution strategy when matching domain against rules. (For tproxy, this is effective only when sniffing is enabled.)")); - o.value("AsIs", "AsIs"); - o.value("IPIfNonMatch", "IPIfNonMatch"); - o.value("IPOnDemand", "IPOnDemand"); - o.default = "AsIs"; - o.rmempty = false; - s.tab('fake_dns', _('FakeDNS')); let tproxy_port_tcp_f4 = s.taboption('fake_dns', form.Value, 'tproxy_port_tcp_f4', _('Transparent proxy port (TCP4)')); @@ -613,24 +603,18 @@ return view.extend({ o = ss.option(form.Flag, 'force_forward_tcp', _('Force Forward (TCP)'), _('This destination must be forwarded through an outbound server.')); o.modalonly = true; - o = ss.option(form.ListValue, 'force_forward_server_tcp', _('Force Forward server (TCP)')); - o.depends("force_forward_tcp", "1"); - o.datatype = "uciname"; - for (const v of uci.sections(config_data, "servers")) { - o.value(v[".name"], server_alias(v)); - } - o.modalonly = true; + let force_forward_server_tcp = ss.option(form.ListValue, 'force_forward_server_tcp', _('Force Forward server (TCP)')); + force_forward_server_tcp.depends("force_forward_tcp", "1"); + force_forward_server_tcp.datatype = "uciname"; + force_forward_server_tcp.modalonly = true; o = ss.option(form.Flag, 'force_forward_udp', _('Force Forward (UDP)'), _('This destination must be forwarded through an outbound server.')); o.modalonly = true; - o = ss.option(form.ListValue, 'force_forward_server_udp', _('Force Forward server (UDP)')); - o.depends("force_forward_udp", "1"); - o.datatype = "uciname"; - for (const v of uci.sections(config_data, "servers")) { - o.value(v[".name"], server_alias(v)); - } - o.modalonly = true; + let force_forward_server_udp = ss.option(form.ListValue, 'force_forward_server_udp', _('Force Forward server (UDP)')); + force_forward_server_udp.depends("force_forward_udp", "1"); + force_forward_server_udp.datatype = "uciname"; + force_forward_server_udp.modalonly = true; s.tab('xray_server', _('HTTPS Server')); @@ -739,11 +723,8 @@ return view.extend({ ss.anonymous = true; ss.addremove = true; - o = ss.option(form.ListValue, "upstream", _("Upstream")); - o.datatype = "uciname"; - for (const v of uci.sections(config_data, "servers")) { - o.value(v[".name"], server_alias(v)); - } + let bridge_upstream = ss.option(form.ListValue, "upstream", _("Upstream")); + bridge_upstream.datatype = "uciname"; o = ss.option(form.Value, "domain", _("Domain")); o.rmempty = false; @@ -759,7 +740,7 @@ return view.extend({ custom_configuration_hook.rows = 20; const servers = uci.sections(config_data, "servers"); - for (let selection of [destination, fake_dns_forward_server_tcp, fake_dns_forward_server_udp, tcp_balancer_v4, tcp_balancer_v6, udp_balancer_v4, udp_balancer_v6]) { + for (let selection of [destination, fake_dns_forward_server_tcp, fake_dns_forward_server_udp, tcp_balancer_v4, tcp_balancer_v6, udp_balancer_v4, udp_balancer_v6, bridge_upstream, force_forward_server_tcp, force_forward_server_udp, dialer_proxy]) { if (servers.length == 0) { selection.value("direct", _("No server configured")); selection.readonly = true; diff --git a/luci-app-xray/core/root/www/luci-static/resources/view/xray/preview.js b/luci-app-xray/core/root/www/luci-static/resources/view/xray/preview.js index 1a6ca0450..72451c9a5 100644 --- a/luci-app-xray/core/root/www/luci-static/resources/view/xray/preview.js +++ b/luci-app-xray/core/root/www/luci-static/resources/view/xray/preview.js @@ -17,6 +17,7 @@ return view.extend({ s.anonymous = true; s.tab("dns_hijack", _("DNS Hijacking")); + s.taboption('dns_hijack', form.Flag, 'align_fast_dns_to_geoip_direct', _('Align Fast DNS & GeoIP Direct'), _("Return only IP adddresses from GeoIP Direct List for Fast DNS.")); let dnsmasq_integration_mode = s.taboption('dns_hijack', form.ListValue, 'dnsmasq_integration_mode', _('Dnsmasq Integration Mode'), _('Per Instance mode requires OpenWrt 24.10 or later versions.')); dnsmasq_integration_mode.value("global", _("Global")); @@ -72,6 +73,13 @@ return view.extend({ let direct_bittorrent = s.taboption('sniffing', form.Flag, 'direct_bittorrent', _('Bittorrent Direct'), _("If enabled, no bittorrent request will be forwarded through Xray.")); direct_bittorrent.depends("tproxy_sniffing", "1"); + let routing_domain_strategy = s.taboption('sniffing', form.ListValue, 'routing_domain_strategy', _('Routing Domain Strategy'), _("Domain resolution strategy when matching domain against rules. (For tproxy, this is effective only when sniffing is enabled.)")); + routing_domain_strategy.value("AsIs", "AsIs"); + routing_domain_strategy.value("IPIfNonMatch", "IPIfNonMatch"); + routing_domain_strategy.value("IPOnDemand", "IPOnDemand"); + routing_domain_strategy.depends("tproxy_sniffing", "1"); + routing_domain_strategy.default = "AsIs"; + s.tab('dynamic_direct', _('Dynamic Direct')); s.taboption('dynamic_direct', form.Flag, 'dynamic_direct_tcp4', _('Enable for IPv4 TCP'), _("This should improve performance with large number of connections.")); diff --git a/luci-app-xray/core/root/www/luci-static/resources/view/xray/protocol.js b/luci-app-xray/core/root/www/luci-static/resources/view/xray/protocol.js index 707f51688..723af2e77 100644 --- a/luci-app-xray/core/root/www/luci-static/resources/view/xray/protocol.js +++ b/luci-app-xray/core/root/www/luci-static/resources/view/xray/protocol.js @@ -214,10 +214,10 @@ function vmess_client(protocol, sub_section, tab_name) { function vless_client(protocol, sub_section, tab_name) { protocol.value("vless", "VLESS"); - let vless_encryption = sub_section.taboption(tab_name, form.ListValue, "vless_encryption", _("[vless] Encrypt Method")); + let vless_encryption = sub_section.taboption(tab_name, form.Value, "vless_encryption", _("[vless] Encrypt Method")); vless_encryption.depends("protocol", "vless"); - vless_encryption.value("none", "none"); - vless_encryption.rmempty = false; + vless_encryption.placeholder = "none"; + vless_encryption.rmempty = true; vless_encryption.modalonly = true; add_flow_and_stream_security_conf(sub_section, tab_name, "protocol", "vless", true, false); @@ -235,6 +235,12 @@ function http_client(protocol, sub_section, tab_name) { function vless_server(protocol, section, tab_name) { protocol.value("vless", "VLESS"); + + let vless_decryption = section.taboption(tab_name, form.Value, "vless_decryption", _("[vless] Decrypt Method")); + vless_decryption.depends("web_server_protocol", "vless"); + vless_decryption.placeholder = "none"; + vless_decryption.rmempty = true; + add_flow_and_stream_security_conf(section, tab_name, "web_server_protocol", "vless", true, true); } diff --git a/xray-core/Makefile b/xray-core/Makefile index e89af3c4e..f0419d8f0 100644 --- a/xray-core/Makefile +++ b/xray-core/Makefile @@ -1,12 +1,12 @@ include $(TOPDIR)/rules.mk PKG_NAME:=xray-core -PKG_VERSION:=25.12.8 +PKG_VERSION:=26.1.13 PKG_RELEASE:=1 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz PKG_SOURCE_URL:=https://codeload.github.com/XTLS/Xray-core/tar.gz/v$(PKG_VERSION)? -PKG_HASH:=d4519b2d9bb1871f4d7612aa7a8db1c451573b5a44ac824219bb44d63f404e61 +PKG_HASH:=c814c9b2e6c92e08d3db929792c56e2863a1a0e252c774ec048095efea6b67a1 PKG_MAINTAINER:=Tianling Shen PKG_LICENSE:=MPL-2.0