update 2024-02-20 09:09:52

This commit is contained in:
github-actions[bot] 2024-02-20 09:09:52 +08:00
parent 257bc92008
commit f6e2b0b447
16 changed files with 243 additions and 93 deletions

View File

@ -6,7 +6,7 @@ include $(TOPDIR)/rules.mk
PKG_NAME:=UnblockNeteaseMusic PKG_NAME:=UnblockNeteaseMusic
PKG_BASE_VERSION:=0.27.4-patch.1 PKG_BASE_VERSION:=0.27.4-patch.1
PKG_RELEASE:=$(AUTORELEASE) PKG_RELEASE:=1
PKG_SOURCE_PROTO:=git PKG_SOURCE_PROTO:=git
PKG_SOURCE_URL:=https://github.com/UnblockNeteaseMusic/server.git PKG_SOURCE_URL:=https://github.com/UnblockNeteaseMusic/server.git

View File

@ -6,7 +6,7 @@ include $(TOPDIR)/rules.mk
PKG_NAME:=brook PKG_NAME:=brook
PKG_VERSION:=20240214 PKG_VERSION:=20240214
PKG_RELEASE:=$(AUTORELEASE) PKG_RELEASE:=1
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
PKG_SOURCE_URL:=https://codeload.github.com/txthinking/brook/tar.gz/v$(PKG_VERSION)? PKG_SOURCE_URL:=https://codeload.github.com/txthinking/brook/tar.gz/v$(PKG_VERSION)?

View File

@ -5,7 +5,7 @@
include $(TOPDIR)/rules.mk include $(TOPDIR)/rules.mk
PKG_NAME:=luci-app-passwall2 PKG_NAME:=luci-app-passwall2
PKG_VERSION:=1.25-5 PKG_VERSION:=1.26-1
PKG_RELEASE:= PKG_RELEASE:=
PKG_CONFIG_DEPENDS:= \ PKG_CONFIG_DEPENDS:= \

View File

@ -141,9 +141,25 @@ if has_xray then
s_xray.anonymous = true s_xray.anonymous = true
s_xray.addremove = false 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 = s_xray:option(Flag, "sniffing", translate("Sniffing"), translate("When using the shunt, must be enabled, otherwise the shunt will invalid."))
o.default = 1 o.default = 1
o.rmempty = false
o = s_xray:option(Flag, "route_only", translate("Sniffing Route Only")) o = s_xray:option(Flag, "route_only", translate("Sniffing Route Only"))
o.default = 0 o.default = 0

View File

@ -43,9 +43,11 @@ function gen_outbound(flag, node, tag, proxy_table)
local proxy = 0 local proxy = 0
local proxy_tag = "nil" local proxy_tag = "nil"
local fragment = nil
if proxy_table ~= nil and type(proxy_table) == "table" then if proxy_table ~= nil and type(proxy_table) == "table" then
proxy = proxy_table.proxy or 0 proxy = proxy_table.proxy or 0
proxy_tag = proxy_table.tag or "nil" proxy_tag = proxy_table.tag or "nil"
fragment = proxy_table.fragment or nil
end end
if node.type == "Xray" then if node.type == "Xray" then
@ -130,6 +132,7 @@ function gen_outbound(flag, node, tag, proxy_table)
mark = 255, mark = 255,
tcpMptcp = (node.tcpMptcp == "1") and true or nil, tcpMptcp = (node.tcpMptcp == "1") and true or nil,
tcpNoDelay = (node.tcpNoDelay == "1") and true or nil, tcpNoDelay = (node.tcpNoDelay == "1") and true or nil,
dialerProxy = fragment and "fragment" or nil
}, },
network = node.transport, network = node.transport,
security = node.stream_security, security = node.stream_security,
@ -639,7 +642,7 @@ function gen_config(var)
end end
if is_new_blc_node then if is_new_blc_node then
local blc_node = uci:get_all(appname, blc_node_id) 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 if outbound then
table.insert(outbounds, outbound) table.insert(outbounds, outbound)
valid_nodes[#valid_nodes + 1] = blc_node_tag valid_nodes[#valid_nodes + 1] = blc_node_tag
@ -717,7 +720,7 @@ function gen_config(var)
preproxy_enabled = false preproxy_enabled = false
end end
elseif preproxy_node and api.is_normal_node(preproxy_node) then 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 if preproxy_outbound then
table.insert(outbounds, preproxy_outbound) table.insert(outbounds, preproxy_outbound)
else else
@ -819,7 +822,14 @@ function gen_config(var)
}) })
end end
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 if _outbound then
table.insert(outbounds, _outbound) table.insert(outbounds, _outbound)
if proxy then preproxy_used = true end if proxy then preproxy_used = true end
@ -998,7 +1008,7 @@ function gen_config(var)
sys.call("touch /tmp/etc/passwall2/iface/" .. node.iface) sys.call("touch /tmp/etc/passwall2/iface/" .. node.iface)
end end
else else
outbound = gen_outbound(flag, node) outbound = gen_outbound(flag, node, nil, { fragment = xray_settings.fragment == "1" or nil })
end end
if outbound then table.insert(outbounds, outbound) end if outbound then table.insert(outbounds, outbound) end
routing = { 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, { table.insert(outbounds, {
protocol = "freedom", protocol = "freedom",
tag = "direct", tag = "direct",

View File

@ -1449,3 +1449,27 @@ msgstr "禁用 TLS 记录的自适应大小调整"
msgid "Enable Multipath TCP, need to be enabled in both server and client configuration." msgid "Enable Multipath TCP, need to be enabled in both server and client configuration."
msgstr "启用 Multipath TCP需在服务端和客户端配置中同时启用。" 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"

View File

@ -323,33 +323,39 @@ o = s:option(Value, "hy2_auth", translate("Users Authentication"))
o:depends("type", "hysteria") o:depends("type", "hysteria")
o.rmempty = false o.rmempty = false
o = s:option(ListValue, "transport_protocol", translate("Protocol")) o = s:option(Flag, "flag_port_hopping", translate("Enable Port Hopping"))
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:depends("type", "hysteria") o:depends("type", "hysteria")
o.rmempty = true o.rmempty = true
o.default = "0" o.default = "0"
o = s:option(Value, "hopinterval", translate("Port Hopping Interval(Unit:Second)")) o = s:option(Value, "port_range", translate("Port Range"))
o:depends({type = "hysteria", port_hopping = true}) 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.datatype = "uinteger"
o.rmempty = true o.rmempty = true
o.default = "30" o.default = "30"
o = s:option(Value, "port_range", translate("Port Range")) o = s:option(Flag, "flag_obfs", translate("Enable Obfuscation"))
o:depends({type = "hysteria", port_hopping = true})
o.rmempty = true
o = s:option(Flag, "lazy_mode", translate("Enable Lazy Mode"))
o:depends("type", "hysteria") o:depends("type", "hysteria")
o.rmempty = true o.rmempty = true
o.default = "0" 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:depends("type", "hysteria")
o.rmempty = true o.rmempty = true
o.default = "0" o.default = "0"
@ -369,6 +375,11 @@ o:depends("type", "hysteria")
o.rmempty = true o.rmempty = true
o.default = "0" 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]] --[[Hysteria2 QUIC parameters setting]]
o = s:option(Value, "initstreamreceivewindow", translate("QUIC initStreamReceiveWindow")) o = s:option(Value, "initstreamreceivewindow", translate("QUIC initStreamReceiveWindow"))
o:depends({type = "hysteria", flag_quicparam = "1"}) o:depends({type = "hysteria", flag_quicparam = "1"})
@ -406,11 +417,6 @@ o.rmempty = true
o.datatype = "uinteger" o.datatype = "uinteger"
o.default = "10" 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 ]] --[[ Shadow-TLS Options ]]
o = s:option(ListValue, "shadowtls_protocol", translate("shadowTLS protocol Version")) o = s:option(ListValue, "shadowtls_protocol", translate("shadowTLS protocol Version"))
@ -902,9 +908,7 @@ o:depends("reality", true)
o.rmempty = true o.rmempty = true
o = s:option(DynamicList, "tls_alpn", translate("TLS ALPN")) o = s:option(DynamicList, "tls_alpn", translate("TLS ALPN"))
o:depends("tls", true) o:depends({type = "tuic", tls = true})
o:depends("type", "tuic")
o:depends("type", "hysteria")
o.rmempty = true o.rmempty = true
-- [[ allowInsecure ]]-- -- [[ allowInsecure ]]--
@ -1187,7 +1191,7 @@ if is_finded("kcptun-client") then
o:depends("type", "ss") o:depends("type", "ss")
o = s:option(Value, "kcp_port", translate("KcpTun Port")) o = s:option(Value, "kcp_port", translate("KcpTun Port"))
o.datatype = "port" o.datatype = "portrange"
o.default = 4000 o.default = 4000
o:depends("type", "ssr") o:depends("type", "ssr")
o:depends("type", "ss") o:depends("type", "ss")

View File

@ -181,6 +181,9 @@ msgstr "注意: 如果服务器使用 userpass 验证,格式必须是 userna
msgid "Enable Port Hopping" msgid "Enable Port Hopping"
msgstr "启用端口跃迁" msgstr "启用端口跃迁"
msgid "Enable Transport Protocol Settings"
msgstr "启用传输协议设置"
msgid "Port Range" msgid "Port Range"
msgstr "端口范围值" msgstr "端口范围值"

View File

@ -433,7 +433,7 @@ start_udp() {
hysteria) hysteria)
gen_config_file $UDP_RELAY_SERVER $type 2 $tmp_udp_port gen_config_file $UDP_RELAY_SERVER $type 2 $tmp_udp_port
ln_start_bin $(first_type hysteria) hysteria client --config $udp_config_file 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) tuic)
# FIXME: ipt2socks cannot handle udp reply from tuic # FIXME: ipt2socks cannot handle udp reply from tuic
@ -564,7 +564,7 @@ start_shunt() {
fi fi
ln_start_bin $(first_type hysteria) hysteria client --config $shunt_config_file ln_start_bin $(first_type hysteria) hysteria client --config $shunt_config_file
shunt_dns_command 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) tuic)
local chain_shunt_port="30${tmp_shunt_port}" local chain_shunt_port="30${tmp_shunt_port}"
@ -663,7 +663,7 @@ start_local() {
if [ "$_local" == "2" ]; then if [ "$_local" == "2" ]; then
gen_config_file $LOCAL_SERVER $type 4 0 $local_port gen_config_file $LOCAL_SERVER $type 4 0 $local_port
ln_start_bin $(first_type hysteria) hysteria client --config $local_config_file 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 fi
;; ;;
tuic) tuic)
@ -758,7 +758,7 @@ Start_Run() {
hysteria) hysteria)
gen_config_file $GLOBAL_SERVER $type 1 $tcp_port $socks_port gen_config_file $GLOBAL_SERVER $type 1 $tcp_port $socks_port
ln_start_bin $(first_type hysteria) hysteria client --config $tcp_config_file 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) tuic)
local PARAM local PARAM

View File

@ -392,7 +392,7 @@ local ss = {
reuse_port = true reuse_port = true
} }
local hysteria = { 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 = { bandwidth = {
up = tonumber(server.uplink_capacity) and tonumber(server.uplink_capacity) .. " mbps" or nil, 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 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), listen = "0.0.0.0:" .. tonumber(socks_port),
disable_udp = false disable_udp = false
} or nil, } or nil,
transport = { transport = (server.transport_protocol) and {
type = server.transport_protocol, type = (server.transport_protocol) or udp,
udp = { udp = (server.port_range and (server.hopinterval) and {
hopInterval = tonumber(server.hopinterval) and tonumber(server.hopinterval) .. "s" or "30s" hopInterval = (server.port_range and (tonumber(server.hopinterval) .. "s") or nil)
} } or nil)
}, } or nil,
--[[ --[[
tcpTProxy = (proto:find("tcp") and local_port ~= "0") and { tcpTProxy = (proto:find("tcp") and local_port ~= "0") and {
listen = "0.0.0.0:" .. tonumber(local_port) listen = "0.0.0.0:" .. tonumber(local_port)

View File

@ -44,6 +44,7 @@ Fork this repository and:
* 2024-02-18 chore: optimize code style; bump version * 2024-02-18 chore: optimize code style; bump version
* 2024-02-19 fix: several DNS related validation * 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 ## Changelog since 3.3.0

View File

@ -9,18 +9,42 @@ const fallback_secure_dns = "8.8.8.8:53";
const fallback_default_dns = "1.1.1.1:53"; const fallback_default_dns = "1.1.1.1:53";
const geosite_existence = access("/usr/share/xray/geosite.dat") || false; const geosite_existence = access("/usr/share/xray/geosite.dat") || false;
function split_ipv4_host_port(val, port_default) { function parse_ip_port(val, port_default) {
const result = match(val, /^([0-9\.]+):([0-9]+)$/); const split_dot = split(val, ".");
if (result == null) { if (length(split_dot) > 1) {
const split_ipv4 = split(val, ":");
return { return {
address: val, ip: split_ipv4[0],
port: int(port_default) 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 { return {
address: result[1], ip: val,
port: int(result[2]) 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 = []; let result = [];
const dns_port = int(proxy["dns_port"] || 5300); const dns_port = int(proxy["dns_port"] || 5300);
const dns_count = int(proxy["dns_count"] || 3); 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++) { for (let i = dns_port; i <= dns_port + dns_count; i++) {
push(result, { push(result, {
port: i, port: i,
@ -126,8 +150,8 @@ export function dns_server_outbounds(proxy) {
}; };
export function dns_conf(proxy, config, manual_tproxy, fakedns) { 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 fast_dns_object = format_dns("udp", proxy["fast_dns"] || fallback_fast_dns);
const default_dns_object = split_ipv4_host_port(proxy["default_dns"] || fallback_default_dns, 53); const default_dns_object = format_dns("udp", proxy["default_dns"] || fallback_default_dns);
let domain_names_set = {}; let domain_names_set = {};
let domain_extra_options = {}; let domain_extra_options = {};
@ -137,7 +161,7 @@ export function dns_conf(proxy, config, manual_tproxy, fakedns) {
continue; continue;
} }
if (server["domain_resolve_dns"]) { 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 { } else {
domain_names_set[`domain:${server["server"]}`] = true; 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)) { for (let k in keys(domain_extra_options)) {
const v = domain_extra_options[k]; const v = domain_extra_options[k];
let original = resolve_merged[v] || []; let original = resolve_merged[v] || [];
push(original, k); push(original, `domain:${k}`);
resolve_merged[v] = original; resolve_merged[v] = original;
} }
let servers = [ let servers = [
...fake_dns_domains(fakedns), ...fake_dns_domains(fakedns),
...map(keys(resolve_merged), function (k) { ...map(keys(resolve_merged), function (k) {
let i = split_ipv4_host_port(k); const dns_split = split(k, ";");
i["domains"] = uniq(resolve_merged[k]); const resolve_dns_object = format_dns(dns_split[0], dns_split[1]);
i["skipFallback"] = true; return {
return i; address: resolve_dns_object["address"],
port: resolve_dns_object["port"],
domains: uniq(resolve_merged[k]),
skipFallback: true,
};
}), }),
default_dns_object, default_dns_object,
{ {
@ -169,7 +197,7 @@ export function dns_conf(proxy, config, manual_tproxy, fakedns) {
]; ];
if (length(secure_domain_rules(proxy)) > 0) { 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, { push(servers, {
address: secure_dns_object["address"], address: secure_dns_object["address"],
port: secure_dns_object["port"], port: secure_dns_object["port"],
@ -199,3 +227,18 @@ export function dns_conf(proxy, config, manual_tproxy, fakedns) {
queryStrategy: "UseIP" 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;
};

View File

@ -3,6 +3,7 @@
"use strict"; "use strict";
import { stat } from "fs"; import { stat } from "fs";
import { load_config } from "./common/config.mjs"; 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 ignore_tp_spec_def_gw = stat("/usr/share/xray/ignore_tp_spec_def_gw");
const config = load_config(); const config = load_config();
const general = config[filter(keys(config), k => config[k][".type"] == "general")[0]]; 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_bp_ips_no_dns = general.wan_bp_ips || [];
let wan_fw_ips_no_dns = general.wan_fw_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]); 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]); 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_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_bp_ips_v6 = filter(uniq(wan_bp_ips_no_dns), v => index(v, ":") != -1);

View File

@ -6,6 +6,15 @@ export function http_outbound(server, tag) {
const stream_settings_object = stream_settings(server, "http", tag); const stream_settings_object = stream_settings(server, "http", tag);
const stream_settings_result = stream_settings_object["stream_settings"]; const stream_settings_result = stream_settings_object["stream_settings"];
const dialer_proxy = stream_settings_object["dialer_proxy"]; const dialer_proxy = stream_settings_object["dialer_proxy"];
let users = null;
if (server["username"] && server["password"]) {
users = [
{
user: server["username"],
pass: server["password"],
}
];
}
return { return {
outbound: { outbound: {
protocol: "http", protocol: "http",
@ -15,12 +24,7 @@ export function http_outbound(server, tag) {
{ {
address: server["server"], address: server["server"],
port: int(server["server_port"]), port: int(server["server_port"]),
users: [ users: users
{
user: server["username"],
pass: server["password"],
}
]
} }
] ]
}, },

View File

@ -6,6 +6,15 @@ export function socks_outbound(server, tag) {
const stream_settings_object = stream_settings(server, "socks", tag); const stream_settings_object = stream_settings(server, "socks", tag);
const stream_settings_result = stream_settings_object["stream_settings"]; const stream_settings_result = stream_settings_object["stream_settings"];
const dialer_proxy = stream_settings_object["dialer_proxy"]; const dialer_proxy = stream_settings_object["dialer_proxy"];
let users = null;
if (server["username"] && server["password"]) {
users = [
{
user: server["username"],
pass: server["password"],
}
];
}
return { return {
outbound: { outbound: {
protocol: "socks", protocol: "socks",
@ -15,12 +24,7 @@ export function socks_outbound(server, tag) {
{ {
address: server["server"], address: server["server"],
port: int(server["server_port"]), port: int(server["server_port"]),
users: [ users: users
{
user: server["username"],
pass: server["password"],
}
]
} }
] ]
}, },

View File

@ -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) { function destination_format(config_data, k, e, max_chars) {
const null_placeholder = function () { return function (s) {
if (null_itatic) { if (e) {
return `<i>${_("direct")}</i>`; if (!uci.get(config_data, s, e)) {
return `<i>${_("use global settings")}</i>`;
}
} }
return _("direct"); return list_folded_format(config_data, k, "outbounds", max_chars, v => uci.get(config_data, v, "alias"), `<i>${_("direct")}</i>`)(s);
}(); };
return list_folded_format(config_data, k, "outbounds", max_chars, v => uci.get(config_data, v, "alias"), null_placeholder);
} }
function extra_outbound_format(config_data, s, select_item) { function extra_outbound_format(config_data, s, select_item) {
@ -191,16 +192,6 @@ return view.extend({
o.datatype = 'host'; o.datatype = 'host';
o.rmempty = false; 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 = ss.taboption('general', form.Value, 'server_port', _('Server Port'));
o.datatype = 'port'; o.datatype = 'port';
o.rmempty = false; o.rmempty = false;
@ -212,6 +203,29 @@ return view.extend({
o.modalonly = true; o.modalonly = true;
o.rmempty = false; 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')); ss.tab('protocol', _('Protocol Settings'));
o = ss.taboption('protocol', form.ListValue, "protocol", _("Protocol")); 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.")); 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.depends("specify_outbound", "1");
destination.datatype = "uciname"; 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 <code>leastPing</code> requires observatory (see "Extra Options" tab) to be enabled.')); let balancer_strategy = extra_inbounds.option(form.Value, 'balancer_strategy', _('Balancer Strategy'), _('Strategy <code>leastPing</code> requires observatory (see "Extra Options" tab) to be enabled.'));
balancer_strategy.depends("specify_outbound", "1"); 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)')); 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.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)')); 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.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 <code>leastPing</code> requires observatory (see "Extra Options" tab) to be enabled.')); let fake_dns_balancer_strategy = fs.option(form.Value, 'fake_dns_balancer_strategy', _('Balancer Strategy'), _('Strategy <code>leastPing</code> requires observatory (see "Extra Options" tab) to be enabled.'));
fake_dns_balancer_strategy.value("random"); fake_dns_balancer_strategy.value("random");