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:
- 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:
- 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