diff --git a/UnblockNeteaseMusic/Makefile b/UnblockNeteaseMusic/Makefile index a05bbf16d..f5fba0a56 100644 --- a/UnblockNeteaseMusic/Makefile +++ b/UnblockNeteaseMusic/Makefile @@ -6,7 +6,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=UnblockNeteaseMusic PKG_BASE_VERSION:=0.27.4-patch.1 -PKG_RELEASE:=$(AUTORELEASE) +PKG_RELEASE:=1 PKG_SOURCE_PROTO:=git PKG_SOURCE_URL:=https://github.com/UnblockNeteaseMusic/server.git diff --git a/brook/Makefile b/brook/Makefile index 469defe43..4e2e15ab5 100644 --- a/brook/Makefile +++ b/brook/Makefile @@ -6,7 +6,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=brook PKG_VERSION:=20240214 -PKG_RELEASE:=$(AUTORELEASE) +PKG_RELEASE:=1 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz PKG_SOURCE_URL:=https://codeload.github.com/txthinking/brook/tar.gz/v$(PKG_VERSION)? diff --git a/luci-app-passwall2/Makefile b/luci-app-passwall2/Makefile index 428b2245b..f473ed261 100644 --- a/luci-app-passwall2/Makefile +++ b/luci-app-passwall2/Makefile @@ -5,7 +5,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=luci-app-passwall2 -PKG_VERSION:=1.25-5 +PKG_VERSION:=1.26-1 PKG_RELEASE:= PKG_CONFIG_DEPENDS:= \ diff --git a/luci-app-passwall2/luasrc/model/cbi/passwall2/client/other.lua b/luci-app-passwall2/luasrc/model/cbi/passwall2/client/other.lua index 275380518..0c03cf3db 100644 --- a/luci-app-passwall2/luasrc/model/cbi/passwall2/client/other.lua +++ b/luci-app-passwall2/luasrc/model/cbi/passwall2/client/other.lua @@ -141,9 +141,25 @@ if has_xray then s_xray.anonymous = true s_xray.addremove = false + o = s_xray:option(Flag, "fragment", translate("Fragment"), translate("TCP fragments, which can deceive the censorship system in some cases, such as bypassing SNI blacklists.")) + o.default = 0 + + o = s_xray:option(ListValue, "fragment_packets", translate("Fragment Packets"), translate(" \"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.")) + o.default = "tlshello" + o:value("1-3", "1-3") + o:value("tlshello", "tlshello") + o:depends("fragment", true) + + o = s_xray:option(Value, "fragment_length", translate("Fragment Length"), translate("Fragmented packet length (byte)")) + o.default = "10-20" + o:depends("fragment", true) + + o = s_xray:option(Value, "fragment_interval", translate("Fragment Interval"), translate("Fragmentation interval (ms)")) + o.default = "10-20" + o:depends("fragment", true) + o = s_xray:option(Flag, "sniffing", translate("Sniffing"), translate("When using the shunt, must be enabled, otherwise the shunt will invalid.")) o.default = 1 - o.rmempty = false o = s_xray:option(Flag, "route_only", translate("Sniffing Route Only")) o.default = 0 diff --git a/luci-app-passwall2/luasrc/passwall2/util_xray.lua b/luci-app-passwall2/luasrc/passwall2/util_xray.lua index fcbfb4452..676271308 100644 --- a/luci-app-passwall2/luasrc/passwall2/util_xray.lua +++ b/luci-app-passwall2/luasrc/passwall2/util_xray.lua @@ -43,9 +43,11 @@ function gen_outbound(flag, node, tag, proxy_table) local proxy = 0 local proxy_tag = "nil" + local fragment = nil if proxy_table ~= nil and type(proxy_table) == "table" then proxy = proxy_table.proxy or 0 proxy_tag = proxy_table.tag or "nil" + fragment = proxy_table.fragment or nil end if node.type == "Xray" then @@ -130,6 +132,7 @@ function gen_outbound(flag, node, tag, proxy_table) mark = 255, tcpMptcp = (node.tcpMptcp == "1") and true or nil, tcpNoDelay = (node.tcpNoDelay == "1") and true or nil, + dialerProxy = fragment and "fragment" or nil }, network = node.transport, security = node.stream_security, @@ -639,7 +642,7 @@ function gen_config(var) end if is_new_blc_node then local blc_node = uci:get_all(appname, blc_node_id) - local outbound = gen_outbound(flag, blc_node, blc_node_tag) + local outbound = gen_outbound(flag, blc_node, blc_node_tag, { fragment = xray_settings.fragment == "1" or nil }) if outbound then table.insert(outbounds, outbound) valid_nodes[#valid_nodes + 1] = blc_node_tag @@ -717,7 +720,7 @@ function gen_config(var) preproxy_enabled = false end elseif preproxy_node and api.is_normal_node(preproxy_node) then - local preproxy_outbound = gen_outbound(flag, preproxy_node, preproxy_tag) + local preproxy_outbound = gen_outbound(flag, preproxy_node, preproxy_tag, { fragment = xray_settings.fragment == "1" or nil }) if preproxy_outbound then table.insert(outbounds, preproxy_outbound) else @@ -819,7 +822,14 @@ function gen_config(var) }) end end - local _outbound = gen_outbound(flag, _node, rule_name, { proxy = proxy and 1 or 0, tag = proxy and preproxy_tag or nil }) + local proxy_table = { + proxy = proxy and 1 or 0, + tag = proxy and preproxy_tag or nil + } + if xray_settings.fragment == "1" and not proxy_table.tag then + proxy_table.fragment = true + end + local _outbound = gen_outbound(flag, _node, rule_name, proxy_table) if _outbound then table.insert(outbounds, _outbound) if proxy then preproxy_used = true end @@ -998,7 +1008,7 @@ function gen_config(var) sys.call("touch /tmp/etc/passwall2/iface/" .. node.iface) end else - outbound = gen_outbound(flag, node) + outbound = gen_outbound(flag, node, nil, { fragment = xray_settings.fragment == "1" or nil }) end if outbound then table.insert(outbounds, outbound) end routing = { @@ -1340,6 +1350,28 @@ function gen_config(var) -- } } } + + if xray_settings.fragment == "1" then + table.insert(outbounds, { + protocol = "freedom", + tag = "fragment", + settings = { + domainStrategy = (direct_dns_query_strategy and direct_dns_query_strategy ~= "") and direct_dns_query_strategy or "UseIP", + fragments = { + packets = (xray_settings.fragment_packets and xray_settings.fragment_packets ~= "") and xray_settings.fragment_packets, + length = (xray_settings.fragment_length and xray_settings.fragment_length ~= "") and xray_settings.fragment_length, + interval = (xray_settings.fragment_interval and xray_settings.fragment_interval ~= "") and xray_settings.fragment_interval + } + }, + streamSettings = { + sockopt = { + mark = 255, + tcpNoDelay = true + } + } + }) + end + table.insert(outbounds, { protocol = "freedom", tag = "direct", diff --git a/luci-app-passwall2/po/zh-cn/passwall2.po b/luci-app-passwall2/po/zh-cn/passwall2.po index 869b0dfb0..2211a3163 100644 --- a/luci-app-passwall2/po/zh-cn/passwall2.po +++ b/luci-app-passwall2/po/zh-cn/passwall2.po @@ -1449,3 +1449,27 @@ msgstr "禁用 TLS 记录的自适应大小调整" msgid "Enable Multipath TCP, need to be enabled in both server and client configuration." msgstr "启用 Multipath TCP,需在服务端和客户端配置中同时启用。" + +msgid "Fragment" +msgstr "分片" + +msgid "TCP fragments, which can deceive the censorship system in some cases, such as bypassing SNI blacklists." +msgstr "TCP 分片,在某些情况下可以欺骗审查系统,比如绕过 SNI 黑名单。" + +msgid "Fragment Packets" +msgstr "分片方式" + +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 " \"1-3\" 是 TCP 的流切片,应用于客户端第 1 至第 3 次写数据。\"tlshello\" 是 TLS 握手包切片。" + +msgid "Fragment Length" +msgstr "分片包长" + +msgid "Fragmented packet length (byte)" +msgstr "分片包长 (byte)" + +msgid "Fragment Interval" +msgstr "分片间隔" + +msgid "Fragmentation interval (ms)" +msgstr "分片间隔(ms)" 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 3bdb464cc..eb716f062 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 @@ -323,33 +323,39 @@ o = s:option(Value, "hy2_auth", translate("Users Authentication")) o:depends("type", "hysteria") o.rmempty = false -o = s:option(ListValue, "transport_protocol", translate("Protocol")) -o:depends("type", "hysteria") -o:value("udp", translate("udp")) -o.default = "udp" -o.rmempty = true - -o = s:option(Flag, "port_hopping", translate("Enable Port Hopping")) +o = s:option(Flag, "flag_port_hopping", translate("Enable Port Hopping")) o:depends("type", "hysteria") o.rmempty = true o.default = "0" -o = s:option(Value, "hopinterval", translate("Port Hopping Interval(Unit:Second)")) -o:depends({type = "hysteria", port_hopping = true}) +o = s:option(Value, "port_range", translate("Port Range")) +o:depends({type = "hysteria", flag_port_hopping = true}) +o.datatype = "portrange" +o.rmempty = true + +o = s:option(Flag, "flag_transport", translate("Enable Transport Protocol Settings")) +o:depends("type", "hysteria") +o.rmempty = true +o.default = "0" + +o = s:option(ListValue, "transport_protocol", translate("Transport Protocol")) +o:depends({type = "hysteria", flag_transport = true}) +o:value("udp", translate("UDP")) +o.default = "udp" +o.rmempty = true + +o = s:option(Value, "hopinterval", translate("Hop Interval(Unit:Second)")) +o:depends({type = "hysteria", flag_transport = true, flag_port_hopping = true}) o.datatype = "uinteger" o.rmempty = true o.default = "30" -o = s:option(Value, "port_range", translate("Port Range")) -o:depends({type = "hysteria", port_hopping = true}) -o.rmempty = true - -o = s:option(Flag, "lazy_mode", translate("Enable Lazy Mode")) +o = s:option(Flag, "flag_obfs", translate("Enable Obfuscation")) o:depends("type", "hysteria") o.rmempty = true o.default = "0" -o = s:option(Flag, "flag_obfs", translate("Enable Obfuscation")) +o = s:option(Flag, "lazy_mode", translate("Lazy Mode")) o:depends("type", "hysteria") o.rmempty = true o.default = "0" @@ -369,6 +375,11 @@ o:depends("type", "hysteria") o.rmempty = true o.default = "0" +o = s:option(Flag, "disablepathmtudiscovery", translate("Disable QUIC path MTU discovery.")) +o:depends({type = "hysteria",flag_quicparam = "1"}) +o.rmempty = true +o.default = false + --[[Hysteria2 QUIC parameters setting]] o = s:option(Value, "initstreamreceivewindow", translate("QUIC initStreamReceiveWindow")) o:depends({type = "hysteria", flag_quicparam = "1"}) @@ -406,11 +417,6 @@ o.rmempty = true o.datatype = "uinteger" o.default = "10" -o = s:option(Flag, "disablepathmtudiscovery", translate("Disable Path MTU discovery")) -o:depends({type = "hysteria", flag_quicparam = "1"}) -o.rmempty = true -o.default = false - --[[ Shadow-TLS Options ]] o = s:option(ListValue, "shadowtls_protocol", translate("shadowTLS protocol Version")) @@ -902,9 +908,7 @@ o:depends("reality", true) o.rmempty = true o = s:option(DynamicList, "tls_alpn", translate("TLS ALPN")) -o:depends("tls", true) -o:depends("type", "tuic") -o:depends("type", "hysteria") +o:depends({type = "tuic", tls = true}) o.rmempty = true -- [[ allowInsecure ]]-- @@ -1187,7 +1191,7 @@ if is_finded("kcptun-client") then o:depends("type", "ss") o = s:option(Value, "kcp_port", translate("KcpTun Port")) - o.datatype = "port" + o.datatype = "portrange" o.default = 4000 o:depends("type", "ssr") o:depends("type", "ss") diff --git a/luci-app-ssr-plus/po/zh-cn/ssr-plus.po b/luci-app-ssr-plus/po/zh-cn/ssr-plus.po index 8d3bdd7ea..6e70883ee 100644 --- a/luci-app-ssr-plus/po/zh-cn/ssr-plus.po +++ b/luci-app-ssr-plus/po/zh-cn/ssr-plus.po @@ -181,6 +181,9 @@ msgstr "注意: 如果服务器使用 userpass 验证,格式必须是 userna msgid "Enable Port Hopping" msgstr "启用端口跃迁" +msgid "Enable Transport Protocol Settings" +msgstr "启用传输协议设置" + msgid "Port Range" msgstr "端口范围值" diff --git a/luci-app-ssr-plus/root/etc/init.d/shadowsocksr b/luci-app-ssr-plus/root/etc/init.d/shadowsocksr index a9a7e57a8..9f2690243 100755 --- a/luci-app-ssr-plus/root/etc/init.d/shadowsocksr +++ b/luci-app-ssr-plus/root/etc/init.d/shadowsocksr @@ -433,7 +433,7 @@ start_udp() { hysteria) 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 | awk '{print "Hhysteria2: " $2}' | head -9 | tail +9) Started!" + echolog "UDP TPROXY Relay:$($(first_type "hysteria") version | grep Version | awk '{print "Hysteria2:" $2}') Started!" ;; tuic) # FIXME: ipt2socks cannot handle udp reply from tuic @@ -564,7 +564,7 @@ start_shunt() { fi ln_start_bin $(first_type hysteria) hysteria client --config $shunt_config_file shunt_dns_command - echolog "shunt:$($(first_type hysteria) version | awk '{print "Hhysteria2: " $2}' | head -9 | tail +9) Started!" + echolog "shunt:$($(first_type hysteria) version | grep Version | awk '{print "Hysteria2:" $2})' Started!" ;; tuic) local chain_shunt_port="30${tmp_shunt_port}" @@ -663,7 +663,7 @@ start_local() { 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 | awk '{print "Hhysteria2: " $2}' | head -9 | tail +9) Started!" + echolog "Global_Socks5:$($(first_type hysteria) version | grep Version | awk '{print "Hysteria2:" $2}') Started!" fi ;; tuic) @@ -758,7 +758,7 @@ Start_Run() { hysteria) 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 | awk '{print "Hhysteria2: " $2}' | head -9 | tail +9) Started!" + echolog "Main node:$($(first_type hysteria) version | grep Version | awk '{print "Hysteria2:" $2}') Started!" ;; tuic) local PARAM 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 02603c3cf..91498b0bf 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 @@ -392,7 +392,7 @@ local ss = { reuse_port = true } local hysteria = { - server = (server.port_range and (server.server .. ":" .. server.port_range)) or (server.server_port and (server.server .. ":" .. server.server_port)), + server = (server.server_port and (server.port_range and (server.server .. ":" .. server.server_port .. "," .. server.port_range) or server.server .. ":" .. server.server_port) or (server.port_range and server.server .. ":" .. server.port_range or server.server .. ":443")), bandwidth = { up = tonumber(server.uplink_capacity) and tonumber(server.uplink_capacity) .. " mbps" or nil, down = tonumber(server.downlink_capacity) and tonumber(server.downlink_capacity) .. " mbps" or nil @@ -401,12 +401,13 @@ local hysteria = { listen = "0.0.0.0:" .. tonumber(socks_port), disable_udp = false } or nil, - transport = { - type = server.transport_protocol, - udp = { - hopInterval = tonumber(server.hopinterval) and tonumber(server.hopinterval) .. "s" or "30s" - } - }, + transport = (server.transport_protocol) and { + type = (server.transport_protocol) or udp, + udp = (server.port_range and (server.hopinterval) and { + hopInterval = (server.port_range and (tonumber(server.hopinterval) .. "s") or nil) + } or nil) + } or nil, + --[[ tcpTProxy = (proto:find("tcp") and local_port ~= "0") and { listen = "0.0.0.0:" .. tonumber(local_port) diff --git a/luci-app-xray/README.md b/luci-app-xray/README.md index 1456259dc..2ea2ccf78 100644 --- a/luci-app-xray/README.md +++ b/luci-app-xray/README.md @@ -44,6 +44,7 @@ Fork this repository and: * 2024-02-18 chore: optimize code style; bump version * 2024-02-19 fix: several DNS related validation +* 2024-02-20 fix: domain match priority; stricter resolve options; socks / http auth ## Changelog since 3.3.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 9f6bb4080..7375a0a19 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 @@ -9,18 +9,42 @@ const fallback_secure_dns = "8.8.8.8:53"; const fallback_default_dns = "1.1.1.1:53"; const geosite_existence = access("/usr/share/xray/geosite.dat") || false; -function split_ipv4_host_port(val, port_default) { - const result = match(val, /^([0-9\.]+):([0-9]+)$/); - if (result == null) { +function parse_ip_port(val, port_default) { + const split_dot = split(val, "."); + if (length(split_dot) > 1) { + const split_ipv4 = split(val, ":"); return { - address: val, - port: int(port_default) + ip: split_ipv4[0], + port: int(split_ipv4[1]) + }; + } + const split_ipv6_port = split(val, "]:"); + if (length(split_ipv6_port) == 2) { + return { + ip: ltrim(split_ipv6_port[0], "["), + port: int(split_ipv6_port[1]), }; } - return { - address: result[1], - port: int(result[2]) + ip: val, + port: port_default + }; +} + +function format_dns(method, val) { + const parsed = parse_ip_port(val, 53); + if (method == "udp") { + return { + address: parsed["ip"], + port: parsed["port"] + }; + } + let url_suffix = ""; + if (substr(method, 0, 5) == "https") { + url_suffix = "/dns-query"; + } + return { + address: `${method}://${val}${url_suffix}` }; } @@ -52,7 +76,7 @@ export function dns_server_inbounds(proxy) { let result = []; const dns_port = int(proxy["dns_port"] || 5300); const dns_count = int(proxy["dns_count"] || 3); - const default_dns = split_ipv4_host_port(proxy["default_dns"] || fallback_default_dns, 53); + const default_dns = format_dns("udp", proxy["default_dns"] || fallback_default_dns); for (let i = dns_port; i <= dns_port + dns_count; i++) { push(result, { port: i, @@ -126,8 +150,8 @@ export function dns_server_outbounds(proxy) { }; export function dns_conf(proxy, config, manual_tproxy, fakedns) { - const fast_dns_object = split_ipv4_host_port(proxy["fast_dns"] || fallback_fast_dns, 53); - const default_dns_object = split_ipv4_host_port(proxy["default_dns"] || fallback_default_dns, 53); + const fast_dns_object = format_dns("udp", proxy["fast_dns"] || fallback_fast_dns); + const default_dns_object = format_dns("udp", proxy["default_dns"] || fallback_default_dns); let domain_names_set = {}; let domain_extra_options = {}; @@ -137,7 +161,7 @@ export function dns_conf(proxy, config, manual_tproxy, fakedns) { continue; } if (server["domain_resolve_dns"]) { - domain_extra_options[server["server"]] = server["domain_resolve_dns"]; + domain_extra_options[server["server"]] = `${server["domain_resolve_dns_method"] || "udp"};${server["domain_resolve_dns"]}`; } else { domain_names_set[`domain:${server["server"]}`] = true; } @@ -147,17 +171,21 @@ export function dns_conf(proxy, config, manual_tproxy, fakedns) { for (let k in keys(domain_extra_options)) { const v = domain_extra_options[k]; let original = resolve_merged[v] || []; - push(original, k); + push(original, `domain:${k}`); resolve_merged[v] = original; } let servers = [ ...fake_dns_domains(fakedns), ...map(keys(resolve_merged), function (k) { - let i = split_ipv4_host_port(k); - i["domains"] = uniq(resolve_merged[k]); - i["skipFallback"] = true; - return i; + const dns_split = split(k, ";"); + const resolve_dns_object = format_dns(dns_split[0], dns_split[1]); + return { + address: resolve_dns_object["address"], + port: resolve_dns_object["port"], + domains: uniq(resolve_merged[k]), + skipFallback: true, + }; }), default_dns_object, { @@ -169,7 +197,7 @@ export function dns_conf(proxy, config, manual_tproxy, fakedns) { ]; if (length(secure_domain_rules(proxy)) > 0) { - const secure_dns_object = split_ipv4_host_port(proxy["secure_dns"] || fallback_secure_dns, 53); + const secure_dns_object = format_dns("udp", proxy["secure_dns"] || fallback_secure_dns); push(servers, { address: secure_dns_object["address"], port: secure_dns_object["port"], @@ -199,3 +227,18 @@ export function dns_conf(proxy, config, manual_tproxy, fakedns) { queryStrategy: "UseIP" }; }; + +export function dns_direct_servers(config) { + let result = []; + 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"]); + } + } + } + return result; +}; 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 8361a540f..a03d40576 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 @@ -3,6 +3,7 @@ "use strict"; import { stat } from "fs"; import { load_config } from "./common/config.mjs"; + import { dns_direct_servers } from "./feature/dns.mjs"; const ignore_tp_spec_def_gw = stat("/usr/share/xray/ignore_tp_spec_def_gw"); const config = load_config(); const general = config[filter(keys(config), k => config[k][".type"] == "general")[0]]; @@ -16,6 +17,9 @@ 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); diff --git a/luci-app-xray/core/root/usr/share/xray/protocol/http.mjs b/luci-app-xray/core/root/usr/share/xray/protocol/http.mjs index 8c80c65c7..b340243ec 100644 --- a/luci-app-xray/core/root/usr/share/xray/protocol/http.mjs +++ b/luci-app-xray/core/root/usr/share/xray/protocol/http.mjs @@ -6,6 +6,15 @@ export function http_outbound(server, tag) { const stream_settings_object = stream_settings(server, "http", tag); const stream_settings_result = stream_settings_object["stream_settings"]; const dialer_proxy = stream_settings_object["dialer_proxy"]; + let users = null; + if (server["username"] && server["password"]) { + users = [ + { + user: server["username"], + pass: server["password"], + } + ]; + } return { outbound: { protocol: "http", @@ -15,12 +24,7 @@ export function http_outbound(server, tag) { { address: server["server"], port: int(server["server_port"]), - users: [ - { - user: server["username"], - pass: server["password"], - } - ] + users: users } ] }, diff --git a/luci-app-xray/core/root/usr/share/xray/protocol/socks.mjs b/luci-app-xray/core/root/usr/share/xray/protocol/socks.mjs index 95c8619c1..4d11a696c 100644 --- a/luci-app-xray/core/root/usr/share/xray/protocol/socks.mjs +++ b/luci-app-xray/core/root/usr/share/xray/protocol/socks.mjs @@ -6,6 +6,15 @@ export function socks_outbound(server, tag) { const stream_settings_object = stream_settings(server, "socks", tag); const stream_settings_result = stream_settings_object["stream_settings"]; const dialer_proxy = stream_settings_object["dialer_proxy"]; + let users = null; + if (server["username"] && server["password"]) { + users = [ + { + user: server["username"], + pass: server["password"], + } + ]; + } return { outbound: { protocol: "socks", @@ -15,12 +24,7 @@ export function socks_outbound(server, tag) { { address: server["server"], port: int(server["server_port"]), - users: [ - { - user: server["username"], - pass: server["password"], - } - ] + users: users } ] }, 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 9b0b408bb..59ecde180 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 @@ -42,14 +42,15 @@ function list_folded_format(config_data, k, noun, max_chars, mapping, empty) { }; } -function destination_format(config_data, k, max_chars, null_itatic) { - const null_placeholder = function () { - if (null_itatic) { - return `${_("direct")}`; +function destination_format(config_data, k, e, max_chars) { + return function (s) { + if (e) { + if (!uci.get(config_data, s, e)) { + return `${_("use global settings")}`; + } } - return _("direct"); - }(); - return list_folded_format(config_data, k, "outbounds", max_chars, v => uci.get(config_data, v, "alias"), null_placeholder); + return list_folded_format(config_data, k, "outbounds", max_chars, v => uci.get(config_data, v, "alias"), `${_("direct")}`)(s); + }; } function extra_outbound_format(config_data, s, select_item) { @@ -191,16 +192,6 @@ return view.extend({ o.datatype = 'host'; o.rmempty = false; - o = ss.taboption('general', form.ListValue, 'domain_strategy', _('Domain Strategy'), _("Whether to use IPv4 or IPv6 address if Server Hostname is a domain.")); - o.value("UseIP"); - o.value("UseIPv4"); - o.value("UseIPv6"); - o.default = "UseIP"; - o.modalonly = true; - - o = ss.taboption('general', form.Value, 'domain_resolve_dns', _('Resolve Domain via DNS'), _("Specify a DNS to resolve server hostname. Be careful of possible recursion.")); - o.modalonly = true; - o = ss.taboption('general', form.Value, 'server_port', _('Server Port')); o.datatype = 'port'; o.rmempty = false; @@ -212,6 +203,29 @@ return view.extend({ o.modalonly = true; o.rmempty = false; + ss.tab('resolving', _("Server Hostname Resolving")); + + o = ss.taboption('resolving', form.ListValue, 'domain_strategy', _('Domain Strategy'), _("Whether to use IPv4 or IPv6 address if Server Hostname is a domain.")); + o.value("UseIP"); + o.value("UseIPv4"); + o.value("UseIPv6"); + o.default = "UseIP"; + o.modalonly = true; + + o = ss.taboption('resolving', form.Value, 'domain_resolve_dns', _('Resolve Domain via DNS'), _("Specify a DNS to resolve server hostname. Be careful of possible recursion.")); + o.datatype = "or(ipaddr, ipaddrport(1))"; + o.modalonly = true; + + o = ss.taboption('resolving', form.ListValue, 'domain_resolve_dns_method', _('Resolve Domain DNS Method'), _("Effective when DNS above is set. Direct methods will bypass Xray completely so it may get blocked.")); + o.value("udp", _("UDP")); + o.value("quic+local", _("DNS over QUIC (direct)")); + o.value("tcp", _("TCP")); + o.value("tcp+local", _("TCP (direct)")); + o.value("https", _("DNS over HTTPS")); + o.value("https+local", _("DNS over HTTPS (direct)")); + o.default = "UseIP"; + o.modalonly = true; + ss.tab('protocol', _('Protocol Settings')); o = ss.taboption('protocol', form.ListValue, "protocol", _("Protocol")); @@ -299,7 +313,7 @@ return view.extend({ let destination = extra_inbounds.option(form.MultiValue, 'destination', _('Destination'), _("Select multiple outbounds for load balancing. If none selected, requests will be sent via direct outbound.")); destination.depends("specify_outbound", "1"); destination.datatype = "uciname"; - destination.textvalue = destination_format(config_data, "destination", 60, true); + destination.textvalue = destination_format(config_data, "destination", "specify_outbound", 60); let balancer_strategy = extra_inbounds.option(form.Value, 'balancer_strategy', _('Balancer Strategy'), _('Strategy leastPing requires observatory (see "Extra Options" tab) to be enabled.')); balancer_strategy.depends("specify_outbound", "1"); @@ -499,11 +513,11 @@ return view.extend({ let fake_dns_forward_server_tcp = fs.option(form.MultiValue, 'fake_dns_forward_server_tcp', _('Force Forward server (TCP)')); fake_dns_forward_server_tcp.datatype = "uciname"; - fake_dns_forward_server_tcp.textvalue = destination_format(config_data, "fake_dns_forward_server_tcp", 40, true); + fake_dns_forward_server_tcp.textvalue = destination_format(config_data, "fake_dns_forward_server_tcp", null, 40); let fake_dns_forward_server_udp = fs.option(form.MultiValue, 'fake_dns_forward_server_udp', _('Force Forward server (UDP)')); fake_dns_forward_server_udp.datatype = "uciname"; - fake_dns_forward_server_udp.textvalue = destination_format(config_data, "fake_dns_forward_server_udp", 40, true); + fake_dns_forward_server_udp.textvalue = destination_format(config_data, "fake_dns_forward_server_udp", null, 40); let fake_dns_balancer_strategy = fs.option(form.Value, 'fake_dns_balancer_strategy', _('Balancer Strategy'), _('Strategy leastPing requires observatory (see "Extra Options" tab) to be enabled.')); fake_dns_balancer_strategy.value("random");