2023-09-04 23:36:20 +08:00
|
|
|
|
module("luci.passwall2.util_sing-box", package.seeall)
|
|
|
|
|
local api = require "luci.passwall2.api"
|
|
|
|
|
local uci = api.uci
|
|
|
|
|
local sys = api.sys
|
|
|
|
|
local jsonc = api.jsonc
|
|
|
|
|
local appname = api.appname
|
|
|
|
|
local fs = api.fs
|
2023-10-10 09:11:00 +08:00
|
|
|
|
local CACHE_PATH = api.CACHE_PATH
|
2023-09-04 23:36:20 +08:00
|
|
|
|
|
|
|
|
|
local new_port
|
|
|
|
|
|
|
|
|
|
local function get_new_port()
|
|
|
|
|
if new_port then
|
|
|
|
|
new_port = tonumber(sys.exec(string.format("echo -n $(/usr/share/%s/app.sh get_new_port %s tcp)", appname, new_port + 1)))
|
|
|
|
|
else
|
|
|
|
|
new_port = tonumber(sys.exec(string.format("echo -n $(/usr/share/%s/app.sh get_new_port auto tcp)", appname)))
|
|
|
|
|
end
|
|
|
|
|
return new_port
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
function gen_outbound(flag, node, tag, proxy_table)
|
|
|
|
|
local result = nil
|
|
|
|
|
if node and node ~= "nil" then
|
|
|
|
|
local node_id = node[".name"]
|
|
|
|
|
if tag == nil then
|
|
|
|
|
tag = node_id
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
local proxy = 0
|
|
|
|
|
local proxy_tag = "nil"
|
|
|
|
|
if proxy_table ~= nil and type(proxy_table) == "table" then
|
|
|
|
|
proxy = proxy_table.proxy or 0
|
|
|
|
|
proxy_tag = proxy_table.tag or "nil"
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
if node.type == "sing-box" then
|
|
|
|
|
proxy = 0
|
|
|
|
|
if proxy_tag ~= "nil" then
|
|
|
|
|
node.detour = proxy_tag
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
if node.type ~= "sing-box" then
|
|
|
|
|
local relay_port = node.port
|
|
|
|
|
new_port = get_new_port()
|
|
|
|
|
local config_file = string.format("%s_%s_%s.json", flag, tag, new_port)
|
|
|
|
|
if tag and node_id and tag ~= node_id then
|
|
|
|
|
config_file = string.format("%s_%s_%s_%s.json", flag, tag, node_id, new_port)
|
|
|
|
|
end
|
|
|
|
|
sys.call(string.format('/usr/share/%s/app.sh run_socks "%s"> /dev/null',
|
|
|
|
|
appname,
|
|
|
|
|
string.format("flag=%s node=%s bind=%s socks_port=%s config_file=%s relay_port=%s",
|
|
|
|
|
new_port, --flag
|
|
|
|
|
node_id, --node
|
|
|
|
|
"127.0.0.1", --bind
|
|
|
|
|
new_port, --socks port
|
|
|
|
|
config_file, --config file
|
|
|
|
|
(proxy == 1 and relay_port) and tostring(relay_port) or "" --relay port
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
node = {
|
|
|
|
|
protocol = "socks",
|
|
|
|
|
address = "127.0.0.1",
|
|
|
|
|
port = new_port
|
|
|
|
|
}
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
result = {
|
|
|
|
|
_flag_tag = node_id,
|
|
|
|
|
_flag_proxy = proxy,
|
|
|
|
|
_flag_proxy_tag = proxy_tag,
|
|
|
|
|
tag = tag,
|
|
|
|
|
type = node.protocol,
|
|
|
|
|
server = node.address,
|
|
|
|
|
server_port = tonumber(node.port),
|
2024-02-26 00:20:11 +08:00
|
|
|
|
domain_strategy = node.domain_strategy,
|
2023-09-04 23:36:20 +08:00
|
|
|
|
detour = node.detour,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
local tls = nil
|
|
|
|
|
if node.tls == "1" then
|
|
|
|
|
local alpn = nil
|
|
|
|
|
if node.alpn and node.alpn ~= "default" then
|
|
|
|
|
alpn = {}
|
|
|
|
|
string.gsub(node.alpn, '[^' .. "," .. ']+', function(w)
|
|
|
|
|
table.insert(alpn, w)
|
|
|
|
|
end)
|
|
|
|
|
end
|
|
|
|
|
tls = {
|
|
|
|
|
enabled = true,
|
|
|
|
|
disable_sni = false, --不要在 ClientHello 中发送服务器名称.
|
|
|
|
|
server_name = node.tls_serverName, --用于验证返回证书上的主机名,除非设置不安全。它还包含在 ClientHello 中以支持虚拟主机,除非它是 IP 地址。
|
|
|
|
|
insecure = (node.tls_allowInsecure == "1") and true or false, --接受任何服务器证书。
|
|
|
|
|
alpn = alpn, --支持的应用层协议协商列表,按优先顺序排列。如果两个对等点都支持 ALPN,则选择的协议将是此列表中的一个,如果没有相互支持的协议则连接将失败。
|
|
|
|
|
--min_version = "1.2",
|
|
|
|
|
--max_version = "1.3",
|
2023-09-23 23:35:18 +08:00
|
|
|
|
ech = {
|
|
|
|
|
enabled = (node.ech == "1") and true or false,
|
|
|
|
|
config = (node.ech_config and node.ech_config:gsub("\\n","\n")) and node.ech_config:gsub("\\n","\n") or nil,
|
|
|
|
|
pq_signature_schemes_enabled = node.pq_signature_schemes_enabled and true or false,
|
|
|
|
|
dynamic_record_sizing_disabled = node.dynamic_record_sizing_disabled and true or false
|
|
|
|
|
},
|
2023-09-04 23:36:20 +08:00
|
|
|
|
utls = {
|
2023-09-05 16:22:53 +08:00
|
|
|
|
enabled = (node.utls == "1" or node.reality == "1") and true or false,
|
2023-09-04 23:36:20 +08:00
|
|
|
|
fingerprint = node.fingerprint or "chrome"
|
|
|
|
|
},
|
|
|
|
|
reality = {
|
|
|
|
|
enabled = (node.reality == "1") and true or false,
|
|
|
|
|
public_key = node.reality_publicKey,
|
|
|
|
|
short_id = node.reality_shortId
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
local mux = nil
|
|
|
|
|
if node.mux == "1" then
|
|
|
|
|
mux = {
|
|
|
|
|
enabled = true,
|
|
|
|
|
protocol = node.mux_type or "h2mux",
|
2023-12-08 16:24:00 +08:00
|
|
|
|
max_connections = ( (node.tcpbrutal == "1") and 1 ) or tonumber(node.mux_concurrency) or 4,
|
|
|
|
|
padding = (node.mux_padding == "1") and true or false,
|
2023-09-04 23:36:20 +08:00
|
|
|
|
--min_streams = 4,
|
|
|
|
|
--max_streams = 0,
|
2023-12-08 16:24:00 +08:00
|
|
|
|
brutal = {
|
|
|
|
|
enabled = (node.tcpbrutal == "1") and true or false,
|
|
|
|
|
up_mbps = tonumber(node.tcpbrutal_up_mbps) or 10,
|
|
|
|
|
down_mbps = tonumber(node.tcpbrutal_down_mbps) or 50,
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
end
|
|
|
|
|
|
2023-09-04 23:36:20 +08:00
|
|
|
|
local v2ray_transport = nil
|
|
|
|
|
|
|
|
|
|
if node.transport == "http" then
|
|
|
|
|
v2ray_transport = {
|
|
|
|
|
type = "http",
|
|
|
|
|
host = { node.http_host },
|
|
|
|
|
path = node.http_path or "/",
|
|
|
|
|
idle_timeout = (node.http_h2_health_check == "1") and node.http_h2_read_idle_timeout or nil,
|
|
|
|
|
ping_timeout = (node.http_h2_health_check == "1") and node.http_h2_health_check_timeout or nil,
|
|
|
|
|
}
|
|
|
|
|
--不强制执行 TLS。如果未配置 TLS,将使用纯 HTTP 1.1。
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
if node.transport == "ws" then
|
|
|
|
|
v2ray_transport = {
|
|
|
|
|
type = "ws",
|
|
|
|
|
path = node.ws_path or "/",
|
|
|
|
|
headers = (node.ws_host ~= nil) and { Host = node.ws_host } or nil,
|
|
|
|
|
max_early_data = tonumber(node.ws_maxEarlyData) or nil,
|
|
|
|
|
early_data_header_name = (node.ws_earlyDataHeaderName) and node.ws_earlyDataHeaderName or nil --要与 Xray-core 兼容,请将其设置为 Sec-WebSocket-Protocol。它需要与服务器保持一致。
|
|
|
|
|
}
|
|
|
|
|
end
|
|
|
|
|
|
2023-12-08 16:24:00 +08:00
|
|
|
|
if node.transport == "httpupgrade" then
|
|
|
|
|
v2ray_transport = {
|
|
|
|
|
type = "httpupgrade",
|
|
|
|
|
host = node.httpupgrade_host,
|
|
|
|
|
path = node.httpupgrade_path or "/",
|
|
|
|
|
}
|
|
|
|
|
end
|
|
|
|
|
|
2023-09-04 23:36:20 +08:00
|
|
|
|
if node.transport == "quic" then
|
|
|
|
|
v2ray_transport = {
|
|
|
|
|
type = "quic"
|
|
|
|
|
}
|
|
|
|
|
--没有额外的加密支持: 它基本上是重复加密。 并且 Xray-core 在这里与 v2ray-core 不兼容。
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
if node.transport == "grpc" then
|
|
|
|
|
v2ray_transport = {
|
|
|
|
|
type = "grpc",
|
2023-09-15 09:11:25 +08:00
|
|
|
|
service_name = node.grpc_serviceName,
|
2023-09-04 23:36:20 +08:00
|
|
|
|
idle_timeout = tonumber(node.grpc_idle_timeout) or nil,
|
|
|
|
|
ping_timeout = tonumber(node.grpc_health_check_timeout) or nil,
|
|
|
|
|
permit_without_stream = (node.grpc_permit_without_stream == "1") and true or nil,
|
|
|
|
|
}
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
local protocol_table = nil
|
|
|
|
|
|
|
|
|
|
if node.protocol == "socks" then
|
|
|
|
|
protocol_table = {
|
|
|
|
|
version = "5",
|
|
|
|
|
username = (node.username and node.password) and node.username or nil,
|
|
|
|
|
password = (node.username and node.password) and node.password or nil,
|
2024-02-01 09:14:28 +08:00
|
|
|
|
udp_over_tcp = node.uot == "1" and {
|
|
|
|
|
enabled = true,
|
|
|
|
|
version = 2
|
|
|
|
|
} or nil,
|
2023-09-04 23:36:20 +08:00
|
|
|
|
}
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
if node.protocol == "http" then
|
|
|
|
|
protocol_table = {
|
|
|
|
|
username = (node.username and node.password) and node.username or nil,
|
|
|
|
|
password = (node.username and node.password) and node.password or nil,
|
|
|
|
|
path = nil,
|
|
|
|
|
headers = nil,
|
|
|
|
|
tls = tls
|
|
|
|
|
}
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
if node.protocol == "shadowsocks" then
|
|
|
|
|
protocol_table = {
|
|
|
|
|
method = node.method or nil,
|
|
|
|
|
password = node.password or "",
|
2024-02-01 23:35:00 +08:00
|
|
|
|
plugin = (node.plugin_enabled and node.plugin) or nil,
|
|
|
|
|
plugin_opts = (node.plugin_enabled and node.plugin_opts) or nil,
|
2023-09-04 23:36:20 +08:00
|
|
|
|
udp_over_tcp = node.uot == "1" and {
|
|
|
|
|
enabled = true,
|
|
|
|
|
version = 2
|
|
|
|
|
} or nil,
|
|
|
|
|
multiplex = mux,
|
|
|
|
|
}
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
if node.protocol == "shadowsocksr" then
|
|
|
|
|
protocol_table = {
|
|
|
|
|
method = node.method or nil,
|
|
|
|
|
password = node.password or "",
|
|
|
|
|
obfs = node.ssr_obfs,
|
|
|
|
|
obfs_param = node.ssr_obfs_param,
|
|
|
|
|
protocol = node.ssr_protocol,
|
|
|
|
|
protocol_param = node.ssr_protocol_param,
|
|
|
|
|
}
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
if node.protocol == "trojan" then
|
|
|
|
|
protocol_table = {
|
|
|
|
|
password = node.password,
|
|
|
|
|
tls = tls,
|
|
|
|
|
multiplex = mux,
|
|
|
|
|
transport = v2ray_transport
|
|
|
|
|
}
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
if node.protocol == "vmess" then
|
|
|
|
|
protocol_table = {
|
|
|
|
|
uuid = node.uuid,
|
|
|
|
|
security = node.security,
|
2023-09-12 23:35:50 +08:00
|
|
|
|
alter_id = (node.alter_id) and tonumber(node.alter_id) or 0,
|
|
|
|
|
global_padding = (node.global_padding == "1") and true or false,
|
|
|
|
|
authenticated_length = (node.authenticated_length == "1") and true or false,
|
2023-09-04 23:36:20 +08:00
|
|
|
|
tls = tls,
|
|
|
|
|
packet_encoding = "", --UDP 包编码。(空):禁用 packetaddr:由 v2ray 5+ 支持 xudp:由 xray 支持
|
|
|
|
|
multiplex = mux,
|
|
|
|
|
transport = v2ray_transport,
|
|
|
|
|
}
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
if node.protocol == "vless" then
|
|
|
|
|
protocol_table = {
|
|
|
|
|
uuid = node.uuid,
|
2023-09-05 09:08:44 +08:00
|
|
|
|
flow = (node.tls == '1' and node.flow) and node.flow or nil,
|
2023-09-04 23:36:20 +08:00
|
|
|
|
tls = tls,
|
|
|
|
|
packet_encoding = "xudp", --UDP 包编码。(空):禁用 packetaddr:由 v2ray 5+ 支持 xudp:由 xray 支持
|
2023-09-11 23:36:26 +08:00
|
|
|
|
multiplex = mux,
|
2023-09-04 23:36:20 +08:00
|
|
|
|
transport = v2ray_transport,
|
|
|
|
|
}
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
if node.protocol == "wireguard" then
|
|
|
|
|
if node.wireguard_reserved then
|
|
|
|
|
local bytes = {}
|
|
|
|
|
if not node.wireguard_reserved:match("[^%d,]+") then
|
|
|
|
|
node.wireguard_reserved:gsub("%d+", function(b)
|
|
|
|
|
bytes[#bytes + 1] = tonumber(b)
|
|
|
|
|
end)
|
|
|
|
|
else
|
|
|
|
|
local result = api.bin.b64decode(node.wireguard_reserved)
|
|
|
|
|
for i = 1, #result do
|
|
|
|
|
bytes[i] = result:byte(i)
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
node.wireguard_reserved = #bytes > 0 and bytes or nil
|
|
|
|
|
end
|
|
|
|
|
protocol_table = {
|
|
|
|
|
system_interface = nil,
|
|
|
|
|
interface_name = nil,
|
|
|
|
|
local_address = node.wireguard_local_address,
|
|
|
|
|
private_key = node.wireguard_secret_key,
|
|
|
|
|
peer_public_key = node.wireguard_public_key,
|
|
|
|
|
pre_shared_key = node.wireguard_preSharedKey,
|
|
|
|
|
reserved = node.wireguard_reserved,
|
|
|
|
|
mtu = tonumber(node.wireguard_mtu),
|
|
|
|
|
}
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
if node.protocol == "hysteria" then
|
|
|
|
|
protocol_table = {
|
|
|
|
|
up_mbps = tonumber(node.hysteria_up_mbps),
|
|
|
|
|
down_mbps = tonumber(node.hysteria_down_mbps),
|
|
|
|
|
obfs = node.hysteria_obfs,
|
|
|
|
|
auth = (node.hysteria_auth_type == "base64") and node.hysteria_auth_password or nil,
|
|
|
|
|
auth_str = (node.hysteria_auth_type == "string") and node.hysteria_auth_password or nil,
|
|
|
|
|
recv_window_conn = tonumber(node.hysteria_recv_window_conn),
|
|
|
|
|
recv_window = tonumber(node.hysteria_recv_window),
|
|
|
|
|
disable_mtu_discovery = (node.hysteria_disable_mtu_discovery == "1") and true or false,
|
2023-09-07 16:21:36 +08:00
|
|
|
|
tls = {
|
|
|
|
|
enabled = true,
|
|
|
|
|
server_name = node.tls_serverName,
|
|
|
|
|
insecure = (node.tls_allowInsecure == "1") and true or false,
|
|
|
|
|
alpn = (node.hysteria_alpn and node.hysteria_alpn ~= "") and {
|
|
|
|
|
node.hysteria_alpn
|
2023-09-23 23:35:18 +08:00
|
|
|
|
} or nil,
|
|
|
|
|
ech = {
|
|
|
|
|
enabled = (node.ech == "1") and true or false,
|
|
|
|
|
config = (node.ech_config and node.ech_config:gsub("\\n","\n")) and node.ech_config:gsub("\\n","\n") or nil,
|
|
|
|
|
pq_signature_schemes_enabled = node.pq_signature_schemes_enabled and true or false,
|
|
|
|
|
dynamic_record_sizing_disabled = node.dynamic_record_sizing_disabled and true or false
|
|
|
|
|
}
|
2023-09-07 16:21:36 +08:00
|
|
|
|
}
|
2023-09-04 23:36:20 +08:00
|
|
|
|
}
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
if node.protocol == "shadowtls" then
|
|
|
|
|
protocol_table = {
|
|
|
|
|
version = tonumber(node.shadowtls_version),
|
|
|
|
|
password = (node.shadowtls_version == "2" or node.shadowtls_version == "3") and node.password or nil,
|
|
|
|
|
tls = tls,
|
|
|
|
|
}
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
if node.protocol == "tuic" then
|
|
|
|
|
protocol_table = {
|
|
|
|
|
uuid = node.uuid,
|
|
|
|
|
password = node.password,
|
|
|
|
|
congestion_control = node.tuic_congestion_control or "cubic",
|
|
|
|
|
udp_relay_mode = node.tuic_udp_relay_mode or "native",
|
|
|
|
|
udp_over_stream = false,
|
|
|
|
|
zero_rtt_handshake = (node.tuic_zero_rtt_handshake == "1") and true or false,
|
2023-09-09 01:03:20 +08:00
|
|
|
|
heartbeat = node.tuic_heartbeat .. "s",
|
2023-09-07 16:57:32 +08:00
|
|
|
|
tls = {
|
|
|
|
|
enabled = true,
|
|
|
|
|
server_name = node.tls_serverName,
|
|
|
|
|
insecure = (node.tls_allowInsecure == "1") and true or false,
|
2023-09-08 16:26:06 +08:00
|
|
|
|
alpn = (node.tuic_alpn and node.tuic_alpn ~= "") and {
|
|
|
|
|
node.tuic_alpn
|
|
|
|
|
} or nil,
|
2023-09-23 23:35:18 +08:00
|
|
|
|
ech = {
|
|
|
|
|
enabled = (node.ech == "1") and true or false,
|
|
|
|
|
config = (node.ech_config and node.ech_config:gsub("\\n","\n")) and node.ech_config:gsub("\\n","\n") or nil,
|
|
|
|
|
pq_signature_schemes_enabled = node.pq_signature_schemes_enabled and true or false,
|
|
|
|
|
dynamic_record_sizing_disabled = node.dynamic_record_sizing_disabled and true or false
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-09-04 23:36:20 +08:00
|
|
|
|
}
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
if node.protocol == "hysteria2" then
|
|
|
|
|
protocol_table = {
|
|
|
|
|
up_mbps = (node.hysteria2_up_mbps and tonumber(node.hysteria2_up_mbps)) and tonumber(node.hysteria2_up_mbps) or nil,
|
|
|
|
|
down_mbps = (node.hysteria2_down_mbps and tonumber(node.hysteria2_down_mbps)) and tonumber(node.hysteria2_down_mbps) or nil,
|
|
|
|
|
obfs = {
|
|
|
|
|
type = node.hysteria2_obfs_type,
|
|
|
|
|
password = node.hysteria2_obfs_password
|
|
|
|
|
},
|
|
|
|
|
password = node.hysteria2_auth_password or nil,
|
2023-09-07 16:57:32 +08:00
|
|
|
|
tls = {
|
|
|
|
|
enabled = true,
|
|
|
|
|
server_name = node.tls_serverName,
|
|
|
|
|
insecure = (node.tls_allowInsecure == "1") and true or false,
|
2023-09-23 23:35:18 +08:00
|
|
|
|
ech = {
|
|
|
|
|
enabled = (node.ech == "1") and true or false,
|
|
|
|
|
config = (node.ech_config and node.ech_config:gsub("\\n","\n")) and node.ech_config:gsub("\\n","\n") or nil,
|
|
|
|
|
pq_signature_schemes_enabled = node.pq_signature_schemes_enabled and true or false,
|
|
|
|
|
dynamic_record_sizing_disabled = node.dynamic_record_sizing_disabled and true or false
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-09-04 23:36:20 +08:00
|
|
|
|
}
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
if protocol_table then
|
|
|
|
|
for key, value in pairs(protocol_table) do
|
|
|
|
|
result[key] = value
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
return result
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
function gen_config_server(node)
|
|
|
|
|
local outbounds = {
|
|
|
|
|
{ type = "direct", tag = "direct" },
|
|
|
|
|
{ type = "block", tag = "block" }
|
|
|
|
|
}
|
|
|
|
|
|
2023-09-12 09:08:44 +08:00
|
|
|
|
local tls = {
|
|
|
|
|
enabled = true,
|
|
|
|
|
certificate_path = node.tls_certificateFile,
|
|
|
|
|
key_path = node.tls_keyFile,
|
|
|
|
|
}
|
2023-09-04 23:36:20 +08:00
|
|
|
|
|
2023-09-12 09:08:44 +08:00
|
|
|
|
if node.tls == "1" and node.reality == "1" then
|
|
|
|
|
tls.certificate_path = nil
|
|
|
|
|
tls.key_path = nil
|
|
|
|
|
tls.reality = {
|
2023-09-04 23:36:20 +08:00
|
|
|
|
enabled = true,
|
2023-09-12 09:08:44 +08:00
|
|
|
|
private_key = node.reality_private_key,
|
|
|
|
|
short_id = {
|
|
|
|
|
node.reality_shortId
|
|
|
|
|
},
|
|
|
|
|
handshake = {
|
|
|
|
|
server = node.reality_handshake_server,
|
|
|
|
|
server_port = tonumber(node.reality_handshake_server_port)
|
|
|
|
|
}
|
2023-09-04 23:36:20 +08:00
|
|
|
|
}
|
|
|
|
|
end
|
|
|
|
|
|
2023-09-23 23:35:18 +08:00
|
|
|
|
if node.tls == "1" and node.ech == "1" then
|
|
|
|
|
tls.ech = {
|
|
|
|
|
enabled = true,
|
|
|
|
|
key = (node.ech_key and node.ech_key:gsub("\\n","\n")) and node.ech_key:gsub("\\n","\n") or nil,
|
|
|
|
|
pq_signature_schemes_enabled = (node.pq_signature_schemes_enabled == "1") and true or false,
|
|
|
|
|
dynamic_record_sizing_disabled = (node.dynamic_record_sizing_disabled == "1") and true or false,
|
|
|
|
|
}
|
|
|
|
|
end
|
|
|
|
|
|
2023-12-30 23:35:03 +08:00
|
|
|
|
local mux = nil
|
|
|
|
|
if node.mux == "1" then
|
|
|
|
|
mux = {
|
|
|
|
|
enabled = true,
|
|
|
|
|
padding = (node.mux_padding == "1") and true or false,
|
|
|
|
|
brutal = {
|
|
|
|
|
enabled = (node.tcpbrutal == "1") and true or false,
|
|
|
|
|
up_mbps = tonumber(node.tcpbrutal_up_mbps) or 10,
|
|
|
|
|
down_mbps = tonumber(node.tcpbrutal_down_mbps) or 50,
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
end
|
|
|
|
|
|
2023-09-04 23:36:20 +08:00
|
|
|
|
local v2ray_transport = nil
|
|
|
|
|
|
|
|
|
|
if node.transport == "http" then
|
|
|
|
|
v2ray_transport = {
|
|
|
|
|
type = "http",
|
|
|
|
|
host = node.http_host,
|
|
|
|
|
path = node.http_path or "/",
|
|
|
|
|
}
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
if node.transport == "ws" then
|
|
|
|
|
v2ray_transport = {
|
|
|
|
|
type = "ws",
|
|
|
|
|
path = node.ws_path or "/",
|
|
|
|
|
headers = (node.ws_host ~= nil) and { Host = node.ws_host } or nil,
|
|
|
|
|
early_data_header_name = (node.ws_earlyDataHeaderName) and node.ws_earlyDataHeaderName or nil --要与 Xray-core 兼容,请将其设置为 Sec-WebSocket-Protocol。它需要与服务器保持一致。
|
|
|
|
|
}
|
|
|
|
|
end
|
|
|
|
|
|
2023-12-08 16:24:00 +08:00
|
|
|
|
if node.transport == "httpupgrade" then
|
|
|
|
|
v2ray_transport = {
|
|
|
|
|
type = "httpupgrade",
|
|
|
|
|
host = node.httpupgrade_host,
|
|
|
|
|
path = node.httpupgrade_path or "/",
|
|
|
|
|
}
|
|
|
|
|
end
|
|
|
|
|
|
2023-09-04 23:36:20 +08:00
|
|
|
|
if node.transport == "quic" then
|
|
|
|
|
v2ray_transport = {
|
|
|
|
|
type = "quic"
|
|
|
|
|
}
|
|
|
|
|
--没有额外的加密支持: 它基本上是重复加密。 并且 Xray-core 在这里与 v2ray-core 不兼容。
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
if node.transport == "grpc" then
|
|
|
|
|
v2ray_transport = {
|
|
|
|
|
type = "grpc",
|
2023-09-15 23:35:18 +08:00
|
|
|
|
service_name = node.grpc_serviceName,
|
2023-09-04 23:36:20 +08:00
|
|
|
|
}
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
local inbound = {
|
|
|
|
|
type = node.protocol,
|
|
|
|
|
tag = "inbound",
|
|
|
|
|
listen = (node.bind_local == "1") and "127.0.0.1" or "::",
|
|
|
|
|
listen_port = tonumber(node.port),
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
local protocol_table = nil
|
|
|
|
|
|
|
|
|
|
if node.protocol == "mixed" then
|
|
|
|
|
protocol_table = {
|
|
|
|
|
users = (node.auth == "1") and {
|
|
|
|
|
{
|
|
|
|
|
username = node.username,
|
|
|
|
|
password = node.password
|
|
|
|
|
}
|
|
|
|
|
} or nil,
|
|
|
|
|
set_system_proxy = false
|
|
|
|
|
}
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
if node.protocol == "socks" then
|
|
|
|
|
protocol_table = {
|
|
|
|
|
users = (node.auth == "1") and {
|
|
|
|
|
{
|
|
|
|
|
username = node.username,
|
|
|
|
|
password = node.password
|
|
|
|
|
}
|
|
|
|
|
} or nil
|
|
|
|
|
}
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
if node.protocol == "http" then
|
|
|
|
|
protocol_table = {
|
|
|
|
|
users = (node.auth == "1") and {
|
|
|
|
|
{
|
|
|
|
|
username = node.username,
|
|
|
|
|
password = node.password
|
|
|
|
|
}
|
|
|
|
|
} or nil,
|
2023-09-12 09:08:44 +08:00
|
|
|
|
tls = (node.tls == "1") and tls or nil,
|
2023-09-04 23:36:20 +08:00
|
|
|
|
}
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
if node.protocol == "shadowsocks" then
|
|
|
|
|
protocol_table = {
|
|
|
|
|
method = node.method,
|
|
|
|
|
password = node.password,
|
2023-12-08 16:24:00 +08:00
|
|
|
|
multiplex = mux,
|
2023-09-04 23:36:20 +08:00
|
|
|
|
}
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
if node.protocol == "vmess" then
|
|
|
|
|
if node.uuid then
|
|
|
|
|
local users = {}
|
|
|
|
|
for i = 1, #node.uuid do
|
|
|
|
|
users[i] = {
|
|
|
|
|
name = node.uuid[i],
|
|
|
|
|
uuid = node.uuid[i],
|
|
|
|
|
alterId = 0,
|
|
|
|
|
}
|
|
|
|
|
end
|
|
|
|
|
protocol_table = {
|
|
|
|
|
users = users,
|
2023-09-12 09:08:44 +08:00
|
|
|
|
tls = (node.tls == "1") and tls or nil,
|
2023-12-08 16:24:00 +08:00
|
|
|
|
multiplex = mux,
|
2023-09-04 23:36:20 +08:00
|
|
|
|
transport = v2ray_transport,
|
|
|
|
|
}
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
if node.protocol == "vless" then
|
|
|
|
|
if node.uuid then
|
|
|
|
|
local users = {}
|
|
|
|
|
for i = 1, #node.uuid do
|
|
|
|
|
users[i] = {
|
|
|
|
|
name = node.uuid[i],
|
|
|
|
|
uuid = node.uuid[i],
|
|
|
|
|
flow = node.flow,
|
|
|
|
|
}
|
|
|
|
|
end
|
|
|
|
|
protocol_table = {
|
|
|
|
|
users = users,
|
2023-09-12 09:08:44 +08:00
|
|
|
|
tls = (node.tls == "1") and tls or nil,
|
2023-12-08 16:24:00 +08:00
|
|
|
|
multiplex = mux,
|
2023-09-04 23:36:20 +08:00
|
|
|
|
transport = v2ray_transport,
|
|
|
|
|
}
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
if node.protocol == "trojan" then
|
|
|
|
|
if node.uuid then
|
|
|
|
|
local users = {}
|
|
|
|
|
for i = 1, #node.uuid do
|
|
|
|
|
users[i] = {
|
|
|
|
|
name = node.uuid[i],
|
2023-09-12 09:08:44 +08:00
|
|
|
|
password = node.uuid[i],
|
2023-09-04 23:36:20 +08:00
|
|
|
|
}
|
|
|
|
|
end
|
|
|
|
|
protocol_table = {
|
|
|
|
|
users = users,
|
2023-09-12 09:08:44 +08:00
|
|
|
|
tls = (node.tls == "1") and tls or nil,
|
2023-09-04 23:36:20 +08:00
|
|
|
|
fallback = nil,
|
|
|
|
|
fallback_for_alpn = nil,
|
2023-12-08 16:24:00 +08:00
|
|
|
|
multiplex = mux,
|
2023-09-04 23:36:20 +08:00
|
|
|
|
transport = v2ray_transport,
|
|
|
|
|
}
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
if node.protocol == "naive" then
|
|
|
|
|
protocol_table = {
|
|
|
|
|
users = {
|
|
|
|
|
{
|
|
|
|
|
username = node.username,
|
|
|
|
|
password = node.password
|
|
|
|
|
}
|
|
|
|
|
},
|
2023-09-12 09:08:44 +08:00
|
|
|
|
tls = tls
|
2023-09-04 23:36:20 +08:00
|
|
|
|
}
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
if node.protocol == "hysteria" then
|
2023-09-12 09:08:44 +08:00
|
|
|
|
tls.alpn = (node.hysteria_alpn and node.hysteria_alpn ~= "") and {
|
|
|
|
|
node.hysteria_alpn
|
|
|
|
|
} or nil
|
2023-09-04 23:36:20 +08:00
|
|
|
|
protocol_table = {
|
2023-09-07 16:21:36 +08:00
|
|
|
|
up = node.hysteria_up_mbps .. " Mbps",
|
|
|
|
|
down = node.hysteria_down_mbps .. " Mbps",
|
2023-09-04 23:36:20 +08:00
|
|
|
|
up_mbps = tonumber(node.hysteria_up_mbps),
|
|
|
|
|
down_mbps = tonumber(node.hysteria_down_mbps),
|
|
|
|
|
obfs = node.hysteria_obfs,
|
|
|
|
|
users = {
|
|
|
|
|
{
|
|
|
|
|
name = "user1",
|
|
|
|
|
auth = (node.hysteria_auth_type == "base64") and node.hysteria_auth_password or nil,
|
|
|
|
|
auth_str = (node.hysteria_auth_type == "string") and node.hysteria_auth_password or nil,
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
recv_window_conn = node.hysteria_recv_window_conn and tonumber(node.hysteria_recv_window_conn) or nil,
|
|
|
|
|
recv_window_client = node.hysteria_recv_window_client and tonumber(node.hysteria_recv_window_client) or nil,
|
|
|
|
|
max_conn_client = node.hysteria_max_conn_client and tonumber(node.hysteria_max_conn_client) or nil,
|
|
|
|
|
disable_mtu_discovery = (node.hysteria_disable_mtu_discovery == "1") and true or false,
|
2023-09-12 09:08:44 +08:00
|
|
|
|
tls = tls
|
2023-09-04 23:36:20 +08:00
|
|
|
|
}
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
if node.protocol == "tuic" then
|
2023-09-12 09:08:44 +08:00
|
|
|
|
tls.alpn = (node.tuic_alpn and node.tuic_alpn ~= "") and {
|
|
|
|
|
node.tuic_alpn
|
|
|
|
|
} or nil
|
2023-09-04 23:36:20 +08:00
|
|
|
|
protocol_table = {
|
|
|
|
|
users = {
|
|
|
|
|
{
|
|
|
|
|
name = "user1",
|
|
|
|
|
uuid = node.uuid,
|
|
|
|
|
password = node.password
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
congestion_control = node.tuic_congestion_control or "cubic",
|
|
|
|
|
zero_rtt_handshake = (node.tuic_zero_rtt_handshake == "1") and true or false,
|
|
|
|
|
heartbeat = node.tuic_heartbeat .. "s",
|
2023-09-12 09:08:44 +08:00
|
|
|
|
tls = tls
|
2023-09-04 23:36:20 +08:00
|
|
|
|
}
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
if node.protocol == "hysteria2" then
|
|
|
|
|
protocol_table = {
|
|
|
|
|
up_mbps = (node.hysteria2_ignore_client_bandwidth ~= "1" and node.hysteria2_up_mbps and tonumber(node.hysteria2_up_mbps)) and tonumber(node.hysteria2_up_mbps) or nil,
|
|
|
|
|
down_mbps = (node.hysteria2_ignore_client_bandwidth ~= "1" and node.hysteria2_down_mbps and tonumber(node.hysteria2_down_mbps)) and tonumber(node.hysteria2_down_mbps) or nil,
|
|
|
|
|
obfs = {
|
|
|
|
|
type = node.hysteria2_obfs_type,
|
|
|
|
|
password = node.hysteria2_obfs_password
|
|
|
|
|
},
|
|
|
|
|
users = {
|
|
|
|
|
{
|
|
|
|
|
name = "user1",
|
|
|
|
|
password = node.hysteria2_auth_password or nil,
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
ignore_client_bandwidth = (node.hysteria2_ignore_client_bandwidth == "1") and true or false,
|
2023-09-12 09:08:44 +08:00
|
|
|
|
tls = tls
|
2023-09-04 23:36:20 +08:00
|
|
|
|
}
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
if node.protocol == "direct" then
|
|
|
|
|
protocol_table = {
|
|
|
|
|
network = (node.d_protocol ~= "TCP,UDP") and node.d_protocol or nil,
|
|
|
|
|
override_address = node.d_address,
|
|
|
|
|
override_port = tonumber(node.d_port)
|
|
|
|
|
}
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
if protocol_table then
|
|
|
|
|
for key, value in pairs(protocol_table) do
|
|
|
|
|
inbound[key] = value
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
local route = {
|
|
|
|
|
rules = {
|
|
|
|
|
{
|
|
|
|
|
ip_cidr = { "10.0.0.0/8", "172.16.0.0/12", "192.168.0.0/16" },
|
|
|
|
|
outbound = (node.accept_lan == nil or node.accept_lan == "0") and "block" or "direct"
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if node.outbound_node and node.outbound_node ~= "nil" then
|
|
|
|
|
local outbound = nil
|
|
|
|
|
if node.outbound_node == "_iface" and node.outbound_node_iface then
|
|
|
|
|
outbound = {
|
|
|
|
|
type = "direct",
|
|
|
|
|
tag = "outbound",
|
|
|
|
|
bind_interface = node.outbound_node_iface,
|
|
|
|
|
routing_mark = 255,
|
|
|
|
|
}
|
|
|
|
|
sys.call("mkdir -p /tmp/etc/passwall2/iface && touch /tmp/etc/passwall2/iface/" .. node.outbound_node_iface)
|
|
|
|
|
else
|
|
|
|
|
local outbound_node_t = uci:get_all("passwall2", node.outbound_node)
|
|
|
|
|
if node.outbound_node == "_socks" or node.outbound_node == "_http" then
|
|
|
|
|
outbound_node_t = {
|
|
|
|
|
type = node.type,
|
|
|
|
|
protocol = node.outbound_node:gsub("_", ""),
|
|
|
|
|
address = node.outbound_node_address,
|
|
|
|
|
port = tonumber(node.outbound_node_port),
|
|
|
|
|
username = (node.outbound_node_username and node.outbound_node_username ~= "") and node.outbound_node_username or nil,
|
|
|
|
|
password = (node.outbound_node_password and node.outbound_node_password ~= "") and node.outbound_node_password or nil,
|
|
|
|
|
}
|
|
|
|
|
end
|
|
|
|
|
outbound = require("luci.passwall2.util_sing-box").gen_outbound(nil, outbound_node_t, "outbound")
|
|
|
|
|
end
|
|
|
|
|
if outbound then
|
|
|
|
|
route.final = "outbound"
|
|
|
|
|
table.insert(outbounds, 1, outbound)
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
local config = {
|
|
|
|
|
log = {
|
|
|
|
|
disabled = (not node or node.log == "0") and true or false,
|
|
|
|
|
level = node.loglevel or "info",
|
|
|
|
|
timestamp = true,
|
|
|
|
|
--output = logfile,
|
|
|
|
|
},
|
|
|
|
|
inbounds = { inbound },
|
|
|
|
|
outbounds = outbounds,
|
|
|
|
|
route = route
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for index, value in ipairs(config.outbounds) do
|
|
|
|
|
for k, v in pairs(config.outbounds[index]) do
|
|
|
|
|
if k:find("_") == 1 then
|
|
|
|
|
config.outbounds[index][k] = nil
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
return config
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
function gen_config(var)
|
|
|
|
|
local flag = var["-flag"]
|
|
|
|
|
local log = var["-log"] or "0"
|
|
|
|
|
local loglevel = var["-loglevel"] or "warn"
|
|
|
|
|
local logfile = var["-logfile"] or "/dev/null"
|
|
|
|
|
local node_id = var["-node"]
|
2024-02-01 09:14:28 +08:00
|
|
|
|
local server_host = var["-server_host"]
|
|
|
|
|
local server_port = var["-server_port"]
|
2023-09-04 23:36:20 +08:00
|
|
|
|
local tcp_proxy_way = var["-tcp_proxy_way"]
|
|
|
|
|
local redir_port = var["-redir_port"]
|
|
|
|
|
local local_socks_address = var["-local_socks_address"] or "0.0.0.0"
|
|
|
|
|
local local_socks_port = var["-local_socks_port"]
|
|
|
|
|
local local_socks_username = var["-local_socks_username"]
|
|
|
|
|
local local_socks_password = var["-local_socks_password"]
|
|
|
|
|
local local_http_address = var["-local_http_address"] or "0.0.0.0"
|
|
|
|
|
local local_http_port = var["-local_http_port"]
|
|
|
|
|
local local_http_username = var["-local_http_username"]
|
|
|
|
|
local local_http_password = var["-local_http_password"]
|
|
|
|
|
local dns_listen_port = var["-dns_listen_port"]
|
|
|
|
|
local direct_dns_udp_server = var["-direct_dns_udp_server"]
|
2023-09-15 09:11:25 +08:00
|
|
|
|
local direct_dns_udp_port = var["-direct_dns_udp_port"]
|
2023-09-04 23:36:20 +08:00
|
|
|
|
local direct_dns_query_strategy = var["-direct_dns_query_strategy"]
|
2023-10-10 09:11:00 +08:00
|
|
|
|
local direct_ipset = var["-direct_ipset"]
|
|
|
|
|
local direct_nftset = var["-direct_nftset"]
|
2023-09-04 23:36:20 +08:00
|
|
|
|
local remote_dns_udp_server = var["-remote_dns_udp_server"]
|
2023-09-15 09:11:25 +08:00
|
|
|
|
local remote_dns_udp_port = var["-remote_dns_udp_port"]
|
2023-09-04 23:36:20 +08:00
|
|
|
|
local remote_dns_tcp_server = var["-remote_dns_tcp_server"]
|
2023-09-15 09:11:25 +08:00
|
|
|
|
local remote_dns_tcp_port = var["-remote_dns_tcp_port"]
|
2023-09-04 23:36:20 +08:00
|
|
|
|
local remote_dns_doh_url = var["-remote_dns_doh_url"]
|
|
|
|
|
local remote_dns_doh_host = var["-remote_dns_doh_host"]
|
2023-09-15 09:11:25 +08:00
|
|
|
|
local remote_dns_doh_ip = var["-remote_dns_doh_ip"]
|
|
|
|
|
local remote_dns_doh_port = var["-remote_dns_doh_port"]
|
2023-09-26 16:23:24 +08:00
|
|
|
|
local remote_dns_detour = var["-remote_dns_detour"]
|
2023-09-04 23:36:20 +08:00
|
|
|
|
local remote_dns_query_strategy = var["-remote_dns_query_strategy"]
|
|
|
|
|
local remote_dns_fake = var["-remote_dns_fake"]
|
|
|
|
|
local dns_cache = var["-dns_cache"]
|
|
|
|
|
local tags = var["-tags"]
|
|
|
|
|
|
2023-09-18 16:23:25 +08:00
|
|
|
|
local dns_domain_rules = {}
|
2023-09-04 23:36:20 +08:00
|
|
|
|
local dns = nil
|
|
|
|
|
local inbounds = {}
|
|
|
|
|
local outbounds = {}
|
|
|
|
|
|
2023-10-10 09:11:00 +08:00
|
|
|
|
local CACHE_TEXT_FILE = CACHE_PATH .. "/cache_" .. flag .. ".txt"
|
|
|
|
|
|
2023-09-05 16:22:53 +08:00
|
|
|
|
local singbox_settings = uci:get_all(appname, "@global_singbox[0]") or {}
|
2023-09-04 23:36:20 +08:00
|
|
|
|
|
|
|
|
|
local route = {
|
|
|
|
|
rules = {},
|
|
|
|
|
geoip = {
|
2023-09-06 23:36:47 +08:00
|
|
|
|
path = singbox_settings.geoip_path or "/usr/share/singbox/geoip.db",
|
2023-09-04 23:36:20 +08:00
|
|
|
|
download_url = singbox_settings.geoip_url or nil,
|
|
|
|
|
download_detour = nil,
|
|
|
|
|
},
|
|
|
|
|
geosite = {
|
2023-09-06 23:36:47 +08:00
|
|
|
|
path = singbox_settings.geosite_path or "/usr/share/singbox/geosite.db",
|
2023-09-04 23:36:20 +08:00
|
|
|
|
download_url = singbox_settings.geosite_url or nil,
|
|
|
|
|
download_detour = nil,
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
local experimental = nil
|
|
|
|
|
|
2023-09-18 23:36:55 +08:00
|
|
|
|
local node = nil
|
2023-09-04 23:36:20 +08:00
|
|
|
|
if node_id then
|
2023-09-18 23:36:55 +08:00
|
|
|
|
node = uci:get_all(appname, node_id)
|
2023-09-04 23:36:20 +08:00
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
if local_socks_port then
|
|
|
|
|
local inbound = {
|
|
|
|
|
type = "socks",
|
|
|
|
|
tag = "socks-in",
|
|
|
|
|
listen = local_socks_address,
|
|
|
|
|
listen_port = tonumber(local_socks_port),
|
|
|
|
|
sniff = true
|
|
|
|
|
}
|
|
|
|
|
if local_socks_username and local_socks_password and local_socks_username ~= "" and local_socks_password ~= "" then
|
|
|
|
|
inbound.users = {
|
|
|
|
|
{
|
|
|
|
|
username = local_socks_username,
|
|
|
|
|
password = local_socks_password
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
end
|
|
|
|
|
table.insert(inbounds, inbound)
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
if local_http_port then
|
|
|
|
|
local inbound = {
|
|
|
|
|
type = "http",
|
|
|
|
|
tag = "http-in",
|
|
|
|
|
listen = local_http_address,
|
|
|
|
|
listen_port = tonumber(local_http_port)
|
|
|
|
|
}
|
|
|
|
|
if local_http_username and local_http_password and local_http_username ~= "" and local_http_password ~= "" then
|
|
|
|
|
inbound.users = {
|
|
|
|
|
{
|
|
|
|
|
username = local_http_username,
|
|
|
|
|
password = local_http_password
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
end
|
|
|
|
|
table.insert(inbounds, inbound)
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
if redir_port then
|
|
|
|
|
local inbound_tproxy = {
|
|
|
|
|
type = "tproxy",
|
|
|
|
|
tag = "tproxy",
|
|
|
|
|
listen = "::",
|
|
|
|
|
listen_port = tonumber(redir_port),
|
|
|
|
|
sniff = true,
|
|
|
|
|
sniff_override_destination = (singbox_settings.sniff_override_destination == "1") and true or false
|
|
|
|
|
}
|
|
|
|
|
if tcp_proxy_way ~= "tproxy" then
|
|
|
|
|
local inbound = {
|
|
|
|
|
type = "redirect",
|
|
|
|
|
tag = "redirect_tcp",
|
|
|
|
|
listen = "::",
|
|
|
|
|
listen_port = tonumber(redir_port),
|
|
|
|
|
sniff = true,
|
|
|
|
|
sniff_override_destination = (singbox_settings.sniff_override_destination == "1") and true or false,
|
|
|
|
|
}
|
|
|
|
|
table.insert(inbounds, inbound)
|
|
|
|
|
|
|
|
|
|
inbound_tproxy.tag = "tproxy_udp"
|
|
|
|
|
inbound_tproxy.network = "udp"
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
table.insert(inbounds, inbound_tproxy)
|
|
|
|
|
end
|
|
|
|
|
|
2023-09-18 23:36:55 +08:00
|
|
|
|
local default_outTag = nil
|
2023-09-04 23:36:20 +08:00
|
|
|
|
|
2023-09-18 23:36:55 +08:00
|
|
|
|
if node then
|
2024-02-01 09:14:28 +08:00
|
|
|
|
if server_host and server_port then
|
|
|
|
|
node.address = server_host
|
|
|
|
|
node.port = server_port
|
|
|
|
|
end
|
2024-02-27 00:21:27 +08:00
|
|
|
|
|
|
|
|
|
local function set_outbound_detour(node, outbound, outbounds_table, shunt_rule_name)
|
|
|
|
|
if not node or not outbound or not outbounds_table then return nil end
|
|
|
|
|
local default_outTag = outbound.tag
|
|
|
|
|
|
|
|
|
|
if node.shadowtls == "1" then
|
|
|
|
|
local _node = {
|
|
|
|
|
type = "sing-box",
|
|
|
|
|
protocol = "shadowtls",
|
|
|
|
|
shadowtls_version = node.shadowtls_version,
|
|
|
|
|
password = (node.shadowtls_version == "2" or node.shadowtls_version == "3") and node.shadowtls_password or nil,
|
|
|
|
|
address = node.address,
|
|
|
|
|
port = node.port,
|
|
|
|
|
tls = "1",
|
|
|
|
|
tls_serverName = node.shadowtls_serverName,
|
|
|
|
|
utls = node.shadowtls_utls,
|
|
|
|
|
fingerprint = node.shadowtls_fingerprint
|
|
|
|
|
}
|
|
|
|
|
local shadowtls_outbound = gen_outbound(nil, _node, outbound.tag .. "_shadowtls")
|
|
|
|
|
if shadowtls_outbound then
|
|
|
|
|
table.insert(outbounds_table, shadowtls_outbound)
|
|
|
|
|
outbound.detour = outbound.tag .. "_shadowtls"
|
|
|
|
|
outbound.server = nil
|
|
|
|
|
outbound.server_port = nil
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
if node.to_node then
|
|
|
|
|
local to_node = uci:get_all(appname, node.to_node)
|
|
|
|
|
if to_node then
|
|
|
|
|
local to_outbound = gen_outbound(nil, to_node)
|
|
|
|
|
if to_outbound then
|
|
|
|
|
if shunt_rule_name then
|
|
|
|
|
to_outbound.tag = outbound.tag
|
|
|
|
|
outbound.tag = node[".name"]
|
|
|
|
|
else
|
|
|
|
|
to_outbound.tag = outbound.tag .. " -> " .. to_outbound.tag
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
to_outbound.detour = outbound.tag
|
|
|
|
|
table.insert(outbounds_table, to_outbound)
|
|
|
|
|
default_outTag = to_outbound.tag
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
return default_outTag
|
|
|
|
|
end
|
|
|
|
|
|
2023-09-04 23:36:20 +08:00
|
|
|
|
if node.protocol == "_shunt" then
|
|
|
|
|
local rules = {}
|
|
|
|
|
|
|
|
|
|
local preproxy_enabled = node.preproxy_enabled == "1"
|
|
|
|
|
local preproxy_tag = "main"
|
|
|
|
|
local preproxy_node_id = node["main_node"]
|
|
|
|
|
local preproxy_node = preproxy_enabled and preproxy_node_id and uci:get_all(appname, preproxy_node_id) or nil
|
|
|
|
|
|
2024-03-17 19:17:01 +08:00
|
|
|
|
if preproxy_node_id and preproxy_node_id:find("Socks_") then
|
|
|
|
|
local socks_id = preproxy_node_id:sub(1 + #"Socks_")
|
|
|
|
|
local socks_node = uci:get_all(appname, socks_id) or nil
|
|
|
|
|
if socks_node then
|
|
|
|
|
local _node = {
|
|
|
|
|
type = "sing-box",
|
|
|
|
|
protocol = "socks",
|
|
|
|
|
address = "127.0.0.1",
|
|
|
|
|
port = socks_node.port,
|
|
|
|
|
uot = "1",
|
|
|
|
|
}
|
|
|
|
|
local preproxy_outbound = gen_outbound(flag, _node, preproxy_tag)
|
|
|
|
|
if preproxy_outbound then
|
|
|
|
|
table.insert(outbounds, preproxy_outbound)
|
|
|
|
|
else
|
|
|
|
|
preproxy_enabled = false
|
|
|
|
|
end
|
2023-09-04 23:36:20 +08:00
|
|
|
|
end
|
|
|
|
|
elseif preproxy_node and api.is_normal_node(preproxy_node) then
|
|
|
|
|
local preproxy_outbound = gen_outbound(flag, preproxy_node, preproxy_tag)
|
|
|
|
|
if preproxy_outbound then
|
2024-02-27 00:21:27 +08:00
|
|
|
|
set_outbound_detour(preproxy_node, preproxy_outbound, outbounds, preproxy_tag)
|
2023-09-04 23:36:20 +08:00
|
|
|
|
table.insert(outbounds, preproxy_outbound)
|
|
|
|
|
else
|
|
|
|
|
preproxy_enabled = false
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
2024-02-27 00:21:27 +08:00
|
|
|
|
local function gen_shunt_node(rule_name, _node_id)
|
2023-09-04 23:36:20 +08:00
|
|
|
|
if not rule_name then return nil, nil end
|
|
|
|
|
if not _node_id then _node_id = node[rule_name] or "nil" end
|
|
|
|
|
local rule_outboundTag
|
|
|
|
|
if _node_id == "_direct" then
|
|
|
|
|
rule_outboundTag = "direct"
|
|
|
|
|
elseif _node_id == "_blackhole" then
|
|
|
|
|
rule_outboundTag = "block"
|
|
|
|
|
elseif _node_id == "_default" and rule_name ~= "default" then
|
|
|
|
|
rule_outboundTag = "default"
|
2024-03-17 19:17:01 +08:00
|
|
|
|
elseif _node_id:find("Socks_") then
|
|
|
|
|
local socks_id = _node_id:sub(1 + #"Socks_")
|
|
|
|
|
local socks_node = uci:get_all(appname, socks_id) or nil
|
|
|
|
|
if socks_node then
|
|
|
|
|
local _node = {
|
|
|
|
|
type = "sing-box",
|
|
|
|
|
protocol = "socks",
|
|
|
|
|
address = "127.0.0.1",
|
|
|
|
|
port = socks_node.port,
|
|
|
|
|
uot = "1",
|
|
|
|
|
}
|
|
|
|
|
local _outbound = gen_outbound(flag, _node, rule_name)
|
|
|
|
|
if _outbound then
|
|
|
|
|
table.insert(outbounds, _outbound)
|
|
|
|
|
rule_outboundTag = rule_name
|
|
|
|
|
end
|
2023-09-04 23:36:20 +08:00
|
|
|
|
end
|
|
|
|
|
elseif _node_id ~= "nil" then
|
|
|
|
|
local _node = uci:get_all(appname, _node_id)
|
|
|
|
|
if not _node then return nil, nil end
|
|
|
|
|
|
|
|
|
|
if api.is_normal_node(_node) then
|
|
|
|
|
local proxy = preproxy_enabled and node[rule_name .. "_proxy_tag"] == preproxy_tag and _node_id ~= preproxy_node_id
|
|
|
|
|
local copied_outbound
|
|
|
|
|
for index, value in ipairs(outbounds) do
|
|
|
|
|
if value["_flag_tag"] == _node_id and value["_flag_proxy_tag"] == preproxy_tag then
|
|
|
|
|
copied_outbound = api.clone(value)
|
|
|
|
|
break
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
if copied_outbound then
|
|
|
|
|
copied_outbound.tag = rule_name
|
|
|
|
|
table.insert(outbounds, copied_outbound)
|
|
|
|
|
rule_outboundTag = rule_name
|
|
|
|
|
else
|
|
|
|
|
if proxy then
|
|
|
|
|
local pre_proxy = nil
|
|
|
|
|
if _node.type ~= "sing-box" then
|
|
|
|
|
pre_proxy = true
|
|
|
|
|
end
|
|
|
|
|
if pre_proxy then
|
|
|
|
|
new_port = get_new_port()
|
|
|
|
|
table.insert(inbounds, {
|
|
|
|
|
type = "direct",
|
|
|
|
|
tag = "proxy_" .. rule_name,
|
|
|
|
|
listen = "127.0.0.1",
|
|
|
|
|
listen_port = new_port,
|
|
|
|
|
override_address = _node.address,
|
|
|
|
|
override_port = tonumber(_node.port),
|
|
|
|
|
})
|
|
|
|
|
if _node.tls_serverName == nil then
|
|
|
|
|
_node.tls_serverName = _node.address
|
|
|
|
|
end
|
|
|
|
|
_node.address = "127.0.0.1"
|
|
|
|
|
_node.port = new_port
|
|
|
|
|
table.insert(rules, 1, {
|
|
|
|
|
inbound = {"proxy_" .. rule_name},
|
|
|
|
|
outbound = preproxy_tag,
|
|
|
|
|
})
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
local _outbound = gen_outbound(flag, _node, rule_name, { proxy = proxy and 1 or 0, tag = proxy and preproxy_tag or nil })
|
|
|
|
|
if _outbound then
|
2024-02-27 00:21:27 +08:00
|
|
|
|
set_outbound_detour(_node, _outbound, outbounds, rule_name)
|
2023-09-04 23:36:20 +08:00
|
|
|
|
table.insert(outbounds, _outbound)
|
|
|
|
|
rule_outboundTag = rule_name
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
elseif _node.protocol == "_iface" then
|
|
|
|
|
if _node.iface then
|
|
|
|
|
local _outbound = {
|
|
|
|
|
type = "direct",
|
|
|
|
|
tag = rule_name,
|
|
|
|
|
bind_interface = _node.iface,
|
|
|
|
|
routing_mark = 255,
|
|
|
|
|
}
|
|
|
|
|
table.insert(outbounds, _outbound)
|
|
|
|
|
rule_outboundTag = rule_name
|
|
|
|
|
sys.call("touch /tmp/etc/passwall2/iface/" .. _node.iface)
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
return rule_outboundTag
|
|
|
|
|
end
|
|
|
|
|
--default_node
|
|
|
|
|
local default_node_id = node.default_node or "_direct"
|
|
|
|
|
local default_outboundTag = gen_shunt_node("default", default_node_id)
|
|
|
|
|
--shunt rule
|
|
|
|
|
uci:foreach(appname, "shunt_rules", function(e)
|
|
|
|
|
local outboundTag = gen_shunt_node(e[".name"])
|
|
|
|
|
if outboundTag and e.remarks then
|
|
|
|
|
if outboundTag == "default" then
|
|
|
|
|
outboundTag = default_outboundTag
|
|
|
|
|
end
|
|
|
|
|
local protocols = nil
|
|
|
|
|
if e["protocol"] and e["protocol"] ~= "" then
|
|
|
|
|
protocols = {}
|
|
|
|
|
string.gsub(e["protocol"], '[^' .. " " .. ']+', function(w)
|
|
|
|
|
table.insert(protocols, w)
|
|
|
|
|
end)
|
|
|
|
|
end
|
2023-12-30 23:35:03 +08:00
|
|
|
|
|
|
|
|
|
local inboundTag = nil
|
|
|
|
|
if e["inbound"] and e["inbound"] ~= "" then
|
|
|
|
|
inboundTag = {}
|
|
|
|
|
if e["inbound"]:find("tproxy") then
|
|
|
|
|
if redir_port then
|
|
|
|
|
if tcp_proxy_way == "tproxy" then
|
|
|
|
|
table.insert(inboundTag, "tproxy")
|
|
|
|
|
else
|
|
|
|
|
table.insert(inboundTag, "redirect_tcp")
|
|
|
|
|
table.insert(inboundTag, "tproxy_udp")
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
if e["inbound"]:find("socks") then
|
|
|
|
|
if local_socks_port then
|
|
|
|
|
table.insert(inboundTag, "socks-in")
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
2023-09-04 23:36:20 +08:00
|
|
|
|
|
|
|
|
|
local rule = {
|
2023-12-30 23:35:03 +08:00
|
|
|
|
inbound = inboundTag,
|
2023-09-04 23:36:20 +08:00
|
|
|
|
outbound = outboundTag,
|
|
|
|
|
invert = false, --匹配反选
|
|
|
|
|
protocol = protocols
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if e.network then
|
|
|
|
|
local network = {}
|
|
|
|
|
string.gsub(e.network, '[^' .. "," .. ']+', function(w)
|
|
|
|
|
table.insert(network, w)
|
|
|
|
|
end)
|
|
|
|
|
rule.network = network
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
if e.source then
|
|
|
|
|
local source_geoip = {}
|
|
|
|
|
local source_ip_cidr = {}
|
|
|
|
|
string.gsub(e.source, '[^' .. " " .. ']+', function(w)
|
|
|
|
|
if w:find("geoip") == 1 then
|
|
|
|
|
table.insert(source_geoip, w)
|
|
|
|
|
else
|
|
|
|
|
table.insert(source_ip_cidr, w)
|
|
|
|
|
end
|
|
|
|
|
end)
|
|
|
|
|
rule.source_geoip = #source_geoip > 0 and source_geoip or nil
|
|
|
|
|
rule.source_ip_cidr = #source_ip_cidr > 0 and source_ip_cidr or nil
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
if e.sourcePort then
|
|
|
|
|
local source_port = {}
|
|
|
|
|
local source_port_range = {}
|
|
|
|
|
string.gsub(e.sourcePort, '[^' .. "," .. ']+', function(w)
|
|
|
|
|
if tonumber(w) and tonumber(w) >= 1 and tonumber(w) <= 65535 then
|
|
|
|
|
table.insert(source_port, tonumber(w))
|
|
|
|
|
else
|
|
|
|
|
table.insert(source_port_range, w)
|
|
|
|
|
end
|
|
|
|
|
end)
|
|
|
|
|
rule.source_port = #source_port > 0 and source_port or nil
|
|
|
|
|
rule.source_port_range = #source_port_range > 0 and source_port_range or nil
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
if e.port then
|
|
|
|
|
local port = {}
|
|
|
|
|
local port_range = {}
|
|
|
|
|
string.gsub(e.port, '[^' .. "," .. ']+', function(w)
|
|
|
|
|
if tonumber(w) and tonumber(w) >= 1 and tonumber(w) <= 65535 then
|
|
|
|
|
table.insert(port, tonumber(w))
|
|
|
|
|
else
|
|
|
|
|
table.insert(port_range, w)
|
|
|
|
|
end
|
|
|
|
|
end)
|
|
|
|
|
rule.port = #port > 0 and port or nil
|
|
|
|
|
rule.port_range = #port_range > 0 and port_range or nil
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
if e.domain_list then
|
2023-09-18 16:23:25 +08:00
|
|
|
|
local domain_table = {
|
|
|
|
|
outboundTag = outboundTag,
|
|
|
|
|
domain = {},
|
|
|
|
|
domain_suffix = {},
|
|
|
|
|
domain_keyword = {},
|
|
|
|
|
domain_regex = {},
|
|
|
|
|
geosite = {},
|
|
|
|
|
}
|
2023-09-04 23:36:20 +08:00
|
|
|
|
string.gsub(e.domain_list, '[^' .. "\r\n" .. ']+', function(w)
|
|
|
|
|
if w:find("geosite:") == 1 then
|
2023-09-18 16:23:25 +08:00
|
|
|
|
table.insert(domain_table.geosite, w:sub(1 + #"geosite:"))
|
2023-09-04 23:36:20 +08:00
|
|
|
|
elseif w:find("regexp:") == 1 then
|
2023-09-18 16:23:25 +08:00
|
|
|
|
table.insert(domain_table.domain_regex, w:sub(1 + #"regexp:"))
|
2023-09-04 23:36:20 +08:00
|
|
|
|
elseif w:find("full:") == 1 then
|
2023-09-18 16:23:25 +08:00
|
|
|
|
table.insert(domain_table.domain, w:sub(1 + #"full:"))
|
2023-09-04 23:36:20 +08:00
|
|
|
|
elseif w:find("domain:") == 1 then
|
2023-09-18 16:23:25 +08:00
|
|
|
|
table.insert(domain_table.domain, w:sub(1 + #"domain:"))
|
|
|
|
|
table.insert(domain_table.domain_suffix, "." .. w:sub(1 + #"domain:"))
|
2023-09-04 23:36:20 +08:00
|
|
|
|
else
|
2023-09-18 16:23:25 +08:00
|
|
|
|
table.insert(domain_table.domain_keyword, w)
|
2023-09-04 23:36:20 +08:00
|
|
|
|
end
|
|
|
|
|
end)
|
2023-09-18 16:23:25 +08:00
|
|
|
|
rule.domain = #domain_table.domain > 0 and domain_table.domain or nil
|
|
|
|
|
rule.domain_suffix = #domain_table.domain_suffix > 0 and domain_table.domain_suffix or nil
|
|
|
|
|
rule.domain_keyword = #domain_table.domain_keyword > 0 and domain_table.domain_keyword or nil
|
|
|
|
|
rule.domain_regex = #domain_table.domain_regex > 0 and domain_table.domain_regex or nil
|
|
|
|
|
rule.geosite = #domain_table.geosite > 0 and domain_table.geosite or nil
|
|
|
|
|
|
|
|
|
|
if outboundTag and outboundTag ~= "nil" then
|
2023-09-21 23:36:20 +08:00
|
|
|
|
table.insert(dns_domain_rules, api.clone(domain_table))
|
2023-09-18 16:23:25 +08:00
|
|
|
|
end
|
2023-09-04 23:36:20 +08:00
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
if e.ip_list then
|
|
|
|
|
local ip_cidr = {}
|
|
|
|
|
local geoip = {}
|
|
|
|
|
string.gsub(e.ip_list, '[^' .. "\r\n" .. ']+', function(w)
|
|
|
|
|
if w:find("geoip:") == 1 then
|
|
|
|
|
table.insert(geoip, w:sub(1 + #"geoip:"))
|
|
|
|
|
else
|
|
|
|
|
table.insert(ip_cidr, w)
|
|
|
|
|
end
|
|
|
|
|
end)
|
|
|
|
|
|
|
|
|
|
rule.ip_cidr = #ip_cidr > 0 and ip_cidr or nil
|
|
|
|
|
rule.geoip = #geoip > 0 and geoip or nil
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
table.insert(rules, rule)
|
|
|
|
|
end
|
|
|
|
|
end)
|
|
|
|
|
|
|
|
|
|
if default_outboundTag then
|
|
|
|
|
route.final = default_outboundTag
|
2023-09-18 23:36:55 +08:00
|
|
|
|
default_outTag = default_outboundTag
|
2023-09-04 23:36:20 +08:00
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
for index, value in ipairs(rules) do
|
|
|
|
|
table.insert(route.rules, rules[index])
|
|
|
|
|
end
|
2024-02-27 00:21:27 +08:00
|
|
|
|
elseif node.protocol == "_iface" then
|
|
|
|
|
if node.iface then
|
|
|
|
|
local outbound = {
|
|
|
|
|
type = "direct",
|
|
|
|
|
tag = node_id,
|
|
|
|
|
bind_interface = node.iface,
|
|
|
|
|
routing_mark = 255,
|
|
|
|
|
}
|
|
|
|
|
table.insert(outbounds, outbound)
|
|
|
|
|
default_outTag = outbound.tag
|
|
|
|
|
route.final = default_outTag
|
|
|
|
|
sys.call("touch /tmp/etc/passwall2/iface/" .. node.iface)
|
2023-09-04 23:36:20 +08:00
|
|
|
|
end
|
2024-02-27 00:21:27 +08:00
|
|
|
|
else
|
|
|
|
|
local outbound = gen_outbound(flag, node)
|
2023-09-04 23:36:20 +08:00
|
|
|
|
if outbound then
|
2024-02-27 00:21:27 +08:00
|
|
|
|
default_outTag = set_outbound_detour(node, outbound, outbounds)
|
2023-09-04 23:36:20 +08:00
|
|
|
|
table.insert(outbounds, outbound)
|
2024-02-23 09:08:40 +08:00
|
|
|
|
route.final = default_outTag
|
2023-09-04 23:36:20 +08:00
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
if dns_listen_port then
|
|
|
|
|
dns = {
|
|
|
|
|
servers = {},
|
|
|
|
|
rules = {},
|
|
|
|
|
disable_cache = (dns_cache and dns_cache == "0") and true or false,
|
|
|
|
|
disable_expire = false, --禁用 DNS 缓存过期。
|
|
|
|
|
independent_cache = false, --使每个 DNS 服务器的缓存独立,以满足特殊目的。如果启用,将轻微降低性能。
|
|
|
|
|
reverse_mapping = true, --在响应 DNS 查询后存储 IP 地址的反向映射以为路由目的提供域名。
|
|
|
|
|
fakeip = nil,
|
|
|
|
|
}
|
2023-09-15 09:11:25 +08:00
|
|
|
|
|
2023-09-18 16:23:25 +08:00
|
|
|
|
table.insert(dns.servers, {
|
|
|
|
|
tag = "block",
|
|
|
|
|
address = "rcode://success",
|
|
|
|
|
})
|
2023-09-09 23:35:09 +08:00
|
|
|
|
|
2023-09-15 09:11:25 +08:00
|
|
|
|
local remote_strategy = "prefer_ipv6"
|
|
|
|
|
if remote_dns_query_strategy == "UseIPv4" then
|
|
|
|
|
remote_strategy = "ipv4_only"
|
|
|
|
|
elseif remote_dns_query_strategy == "UseIPv6" then
|
|
|
|
|
remote_strategy = "ipv6_only"
|
|
|
|
|
end
|
2023-09-09 23:35:09 +08:00
|
|
|
|
|
2023-09-18 16:23:25 +08:00
|
|
|
|
local remote_server = {
|
|
|
|
|
tag = "remote",
|
2023-09-15 09:11:25 +08:00
|
|
|
|
address_strategy = "prefer_ipv4",
|
|
|
|
|
strategy = remote_strategy,
|
|
|
|
|
address_resolver = "direct",
|
2023-09-18 23:36:55 +08:00
|
|
|
|
detour = default_outTag,
|
2023-09-15 09:11:25 +08:00
|
|
|
|
}
|
2023-09-09 23:35:09 +08:00
|
|
|
|
|
2024-01-08 09:16:52 +08:00
|
|
|
|
if remote_dns_detour == "direct" then
|
|
|
|
|
remote_server.detour = "direct"
|
|
|
|
|
end
|
|
|
|
|
|
2023-09-15 09:11:25 +08:00
|
|
|
|
if remote_dns_udp_server then
|
|
|
|
|
local server_port = tonumber(remote_dns_udp_port) or 53
|
2023-09-18 16:23:25 +08:00
|
|
|
|
remote_server.address = "udp://" .. remote_dns_udp_server .. ":" .. server_port
|
2023-09-15 09:11:25 +08:00
|
|
|
|
end
|
2023-09-04 23:36:20 +08:00
|
|
|
|
|
2023-09-15 09:11:25 +08:00
|
|
|
|
if remote_dns_tcp_server then
|
|
|
|
|
local server_port = tonumber(remote_dns_tcp_port) or 53
|
2023-09-18 16:23:25 +08:00
|
|
|
|
remote_server.address = "tcp://" .. remote_dns_tcp_server .. ":" .. server_port
|
2023-09-15 09:11:25 +08:00
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
if remote_dns_doh_url then
|
2023-09-18 16:23:25 +08:00
|
|
|
|
remote_server.address = remote_dns_doh_url
|
2023-09-15 09:11:25 +08:00
|
|
|
|
end
|
|
|
|
|
|
2023-09-18 16:23:25 +08:00
|
|
|
|
if remote_server.address then
|
|
|
|
|
table.insert(dns.servers, remote_server)
|
2023-09-15 09:11:25 +08:00
|
|
|
|
end
|
|
|
|
|
|
2023-09-18 16:23:25 +08:00
|
|
|
|
local fakedns_tag = "remote_fakeip"
|
2023-09-15 09:11:25 +08:00
|
|
|
|
if remote_dns_fake then
|
|
|
|
|
dns.fakeip = {
|
|
|
|
|
enabled = true,
|
|
|
|
|
inet4_range = "198.18.0.0/16",
|
|
|
|
|
inet6_range = "fc00::/18",
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
table.insert(dns.servers, {
|
|
|
|
|
tag = fakedns_tag,
|
|
|
|
|
address = "fakeip",
|
|
|
|
|
strategy = remote_strategy,
|
|
|
|
|
})
|
|
|
|
|
|
2024-01-11 09:16:46 +08:00
|
|
|
|
if not experimental then
|
|
|
|
|
experimental = {}
|
2023-09-04 23:36:20 +08:00
|
|
|
|
end
|
2024-01-11 09:16:46 +08:00
|
|
|
|
experimental.cache_file = {
|
|
|
|
|
enabled = true,
|
|
|
|
|
store_fakeip = true,
|
|
|
|
|
path = "/tmp/singbox_passwall2_" .. flag .. ".db"
|
|
|
|
|
}
|
2023-09-15 09:11:25 +08:00
|
|
|
|
end
|
2023-09-04 23:36:20 +08:00
|
|
|
|
|
|
|
|
|
if direct_dns_udp_server then
|
2023-09-18 16:23:25 +08:00
|
|
|
|
local domain = {}
|
2023-09-04 23:36:20 +08:00
|
|
|
|
local nodes_domain_text = sys.exec('uci show passwall2 | grep ".address=" | cut -d "\'" -f 2 | grep "[a-zA-Z]$" | sort -u')
|
|
|
|
|
string.gsub(nodes_domain_text, '[^' .. "\r\n" .. ']+', function(w)
|
2023-09-18 16:23:25 +08:00
|
|
|
|
table.insert(domain, w)
|
2023-09-04 23:36:20 +08:00
|
|
|
|
end)
|
2023-09-18 16:23:25 +08:00
|
|
|
|
if #domain > 0 then
|
2023-09-21 23:36:20 +08:00
|
|
|
|
table.insert(dns_domain_rules, 1, {
|
2023-09-18 16:23:25 +08:00
|
|
|
|
outboundTag = "direct",
|
|
|
|
|
domain = domain
|
|
|
|
|
})
|
2023-09-15 09:11:25 +08:00
|
|
|
|
end
|
2023-09-04 23:36:20 +08:00
|
|
|
|
|
|
|
|
|
local direct_strategy = "prefer_ipv6"
|
|
|
|
|
if direct_dns_query_strategy == "UseIPv4" then
|
|
|
|
|
direct_strategy = "ipv4_only"
|
|
|
|
|
elseif direct_dns_query_strategy == "UseIPv6" then
|
|
|
|
|
direct_strategy = "ipv6_only"
|
|
|
|
|
end
|
|
|
|
|
|
2023-09-15 09:11:25 +08:00
|
|
|
|
local port = tonumber(direct_dns_udp_port) or 53
|
2023-09-04 23:36:20 +08:00
|
|
|
|
|
|
|
|
|
table.insert(dns.servers, {
|
2023-09-18 16:23:25 +08:00
|
|
|
|
tag = "direct",
|
2023-09-04 23:36:20 +08:00
|
|
|
|
address = "udp://" .. direct_dns_udp_server .. ":" .. port,
|
|
|
|
|
address_strategy = "prefer_ipv6",
|
|
|
|
|
strategy = direct_strategy,
|
|
|
|
|
detour = "direct",
|
|
|
|
|
})
|
|
|
|
|
end
|
2023-09-16 23:36:51 +08:00
|
|
|
|
|
2023-09-15 09:11:25 +08:00
|
|
|
|
local default_dns_flag = "remote"
|
|
|
|
|
if node_id and redir_port then
|
|
|
|
|
local node = uci:get_all(appname, node_id)
|
|
|
|
|
if node.protocol == "_shunt" then
|
|
|
|
|
if node.default_node == "_direct" then
|
|
|
|
|
default_dns_flag = "direct"
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
else default_dns_flag = "direct"
|
|
|
|
|
end
|
|
|
|
|
dns.final = default_dns_flag
|
2023-09-18 16:23:25 +08:00
|
|
|
|
|
|
|
|
|
--按分流顺序DNS
|
|
|
|
|
if dns_domain_rules and #dns_domain_rules > 0 then
|
|
|
|
|
for index, value in ipairs(dns_domain_rules) do
|
|
|
|
|
if value.outboundTag and (value.domain or value.domain_suffix or value.domain_keyword or value.domain_regex or value.geosite) then
|
|
|
|
|
local dns_rule = {
|
|
|
|
|
server = value.outboundTag,
|
|
|
|
|
domain = (value.domain and #value.domain > 0) and value.domain or nil,
|
|
|
|
|
domain_suffix = (value.domain_suffix and #value.domain_suffix > 0) and value.domain_suffix or nil,
|
|
|
|
|
domain_keyword = (value.domain_keyword and #value.domain_keyword > 0) and value.domain_keyword or nil,
|
|
|
|
|
domain_regex = (value.domain_regex and #value.domain_regex > 0) and value.domain_regex or nil,
|
|
|
|
|
geosite = (value.geosite and #value.geosite > 0) and value.geosite or nil,
|
|
|
|
|
disable_cache = false,
|
|
|
|
|
}
|
|
|
|
|
if value.outboundTag ~= "block" and value.outboundTag ~= "direct" then
|
|
|
|
|
dns_rule.server = "remote"
|
2023-12-30 23:35:03 +08:00
|
|
|
|
dns_rule.rewrite_ttl = 30
|
2024-01-08 09:16:52 +08:00
|
|
|
|
if value.outboundTag ~= "default" and remote_server.address and remote_dns_detour ~= "direct" then
|
2023-09-18 16:23:25 +08:00
|
|
|
|
local remote_dns_server = api.clone(remote_server)
|
|
|
|
|
remote_dns_server.tag = value.outboundTag
|
|
|
|
|
remote_dns_server.detour = value.outboundTag
|
|
|
|
|
table.insert(dns.servers, remote_dns_server)
|
|
|
|
|
dns_rule.server = remote_dns_server.tag
|
|
|
|
|
end
|
|
|
|
|
if remote_dns_fake then
|
|
|
|
|
local fakedns_dns_rule = api.clone(dns_rule)
|
|
|
|
|
fakedns_dns_rule.query_type = {
|
|
|
|
|
"A", "AAAA"
|
|
|
|
|
}
|
|
|
|
|
fakedns_dns_rule.server = fakedns_tag
|
|
|
|
|
fakedns_dns_rule.disable_cache = true
|
|
|
|
|
table.insert(dns.rules, fakedns_dns_rule)
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
table.insert(dns.rules, dns_rule)
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
2023-09-04 23:36:20 +08:00
|
|
|
|
|
|
|
|
|
table.insert(inbounds, {
|
|
|
|
|
type = "direct",
|
|
|
|
|
tag = "dns-in",
|
|
|
|
|
listen = "127.0.0.1",
|
|
|
|
|
listen_port = tonumber(dns_listen_port),
|
|
|
|
|
sniff = true,
|
|
|
|
|
})
|
|
|
|
|
table.insert(outbounds, {
|
|
|
|
|
type = "dns",
|
|
|
|
|
tag = "dns-out",
|
|
|
|
|
})
|
|
|
|
|
table.insert(route.rules, 1, {
|
|
|
|
|
protocol = "dns",
|
|
|
|
|
inbound = {
|
|
|
|
|
"dns-in"
|
|
|
|
|
},
|
|
|
|
|
outbound = "dns-out"
|
|
|
|
|
})
|
2023-10-10 09:11:00 +08:00
|
|
|
|
|
2024-01-18 09:15:34 +08:00
|
|
|
|
local content = flag .. node_id .. jsonc.stringify(route.rules)
|
2023-10-10 09:11:00 +08:00
|
|
|
|
if api.cacheFileCompareToLogic(CACHE_TEXT_FILE, content) == false then
|
|
|
|
|
--clear ipset/nftset
|
|
|
|
|
if direct_ipset then
|
|
|
|
|
string.gsub(direct_ipset, '[^' .. "," .. ']+', function(w)
|
|
|
|
|
sys.call("ipset -q -F " .. w)
|
|
|
|
|
end)
|
|
|
|
|
end
|
|
|
|
|
if direct_nftset then
|
|
|
|
|
string.gsub(direct_nftset, '[^' .. "," .. ']+', function(w)
|
2023-12-30 23:35:03 +08:00
|
|
|
|
local split = api.split(w, "#")
|
|
|
|
|
if #split > 3 then
|
|
|
|
|
local ip_type = split[1]
|
|
|
|
|
local family = split[2]
|
|
|
|
|
local table_name = split[3]
|
|
|
|
|
local set_name = split[4]
|
|
|
|
|
sys.call(string.format("nft flush set %s %s %s 2>/dev/null", family, table_name, set_name))
|
|
|
|
|
end
|
2023-10-10 09:11:00 +08:00
|
|
|
|
end)
|
|
|
|
|
end
|
|
|
|
|
end
|
2023-09-04 23:36:20 +08:00
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
if inbounds or outbounds then
|
|
|
|
|
local config = {
|
|
|
|
|
log = {
|
|
|
|
|
disabled = log == "0" and true or false,
|
|
|
|
|
level = loglevel,
|
|
|
|
|
timestamp = true,
|
|
|
|
|
output = logfile,
|
|
|
|
|
},
|
|
|
|
|
-- DNS
|
|
|
|
|
dns = dns,
|
|
|
|
|
-- 传入连接
|
|
|
|
|
inbounds = inbounds,
|
|
|
|
|
-- 传出连接
|
|
|
|
|
outbounds = outbounds,
|
|
|
|
|
-- 路由
|
|
|
|
|
route = route,
|
|
|
|
|
--实验性
|
|
|
|
|
experimental = experimental,
|
|
|
|
|
}
|
|
|
|
|
table.insert(outbounds, {
|
|
|
|
|
type = "direct",
|
|
|
|
|
tag = "direct",
|
|
|
|
|
routing_mark = 255,
|
|
|
|
|
domain_strategy = "prefer_ipv6",
|
|
|
|
|
})
|
|
|
|
|
table.insert(outbounds, {
|
|
|
|
|
type = "block",
|
|
|
|
|
tag = "block"
|
|
|
|
|
})
|
|
|
|
|
for index, value in ipairs(config.outbounds) do
|
|
|
|
|
for k, v in pairs(config.outbounds[index]) do
|
|
|
|
|
if k:find("_") == 1 then
|
|
|
|
|
config.outbounds[index][k] = nil
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
return jsonc.stringify(config, 1)
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
function gen_proto_config(var)
|
|
|
|
|
local local_socks_address = var["-local_socks_address"] or "0.0.0.0"
|
|
|
|
|
local local_socks_port = var["-local_socks_port"]
|
|
|
|
|
local local_socks_username = var["-local_socks_username"]
|
|
|
|
|
local local_socks_password = var["-local_socks_password"]
|
|
|
|
|
local local_http_address = var["-local_http_address"] or "0.0.0.0"
|
|
|
|
|
local local_http_port = var["-local_http_port"]
|
|
|
|
|
local local_http_username = var["-local_http_username"]
|
|
|
|
|
local local_http_password = var["-local_http_password"]
|
|
|
|
|
local server_proto = var["-server_proto"]
|
|
|
|
|
local server_address = var["-server_address"]
|
|
|
|
|
local server_port = var["-server_port"]
|
|
|
|
|
local server_username = var["-server_username"]
|
|
|
|
|
local server_password = var["-server_password"]
|
|
|
|
|
|
|
|
|
|
local inbounds = {}
|
|
|
|
|
local outbounds = {}
|
|
|
|
|
|
|
|
|
|
if local_socks_address and local_socks_port then
|
|
|
|
|
local inbound = {
|
|
|
|
|
type = "socks",
|
|
|
|
|
tag = "socks-in",
|
|
|
|
|
listen = local_socks_address,
|
|
|
|
|
listen_port = tonumber(local_socks_port),
|
|
|
|
|
}
|
|
|
|
|
if local_socks_username and local_socks_password and local_socks_username ~= "" and local_socks_password ~= "" then
|
|
|
|
|
inbound.users = {
|
|
|
|
|
username = local_socks_username,
|
|
|
|
|
password = local_socks_password
|
|
|
|
|
}
|
|
|
|
|
end
|
|
|
|
|
table.insert(inbounds, inbound)
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
if local_http_address and local_http_port then
|
|
|
|
|
local inbound = {
|
|
|
|
|
type = "http",
|
|
|
|
|
tag = "http-in",
|
|
|
|
|
tls = nil,
|
|
|
|
|
listen = local_http_address,
|
|
|
|
|
listen_port = tonumber(local_http_port),
|
|
|
|
|
}
|
|
|
|
|
if local_http_username and local_http_password and local_http_username ~= "" and local_http_password ~= "" then
|
|
|
|
|
inbound.users = {
|
|
|
|
|
{
|
|
|
|
|
username = local_http_username,
|
|
|
|
|
password = local_http_password
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
end
|
|
|
|
|
table.insert(inbounds, inbound)
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
if server_proto ~= "nil" and server_address ~= "nil" and server_port ~= "nil" then
|
|
|
|
|
local outbound = {
|
|
|
|
|
type = server_proto,
|
|
|
|
|
tag = "out",
|
|
|
|
|
server = server_address,
|
|
|
|
|
server_port = tonumber(server_port),
|
|
|
|
|
username = (server_username and server_password) and server_username or nil,
|
|
|
|
|
password = (server_username and server_password) and server_password or nil,
|
|
|
|
|
}
|
|
|
|
|
if outbound then table.insert(outbounds, outbound) end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
local config = {
|
|
|
|
|
log = {
|
|
|
|
|
disabled = true,
|
|
|
|
|
level = "warn",
|
|
|
|
|
timestamp = true,
|
|
|
|
|
},
|
|
|
|
|
-- 传入连接
|
|
|
|
|
inbounds = inbounds,
|
|
|
|
|
-- 传出连接
|
|
|
|
|
outbounds = outbounds,
|
|
|
|
|
}
|
|
|
|
|
return jsonc.stringify(config, 1)
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
function gen_dns_config(var)
|
|
|
|
|
local dns_listen_port = var["-dns_listen_port"]
|
|
|
|
|
local dns_query_strategy = var["-dns_query_strategy"]
|
|
|
|
|
local dns_out_tag = var["-dns_out_tag"]
|
|
|
|
|
local direct_dns_udp_server = var["-direct_dns_udp_server"]
|
2023-09-15 09:11:25 +08:00
|
|
|
|
local direct_dns_udp_port = var["-direct_dns_udp_port"]
|
2023-09-04 23:36:20 +08:00
|
|
|
|
local direct_dns_tcp_server = var["-direct_dns_tcp_server"]
|
2023-09-15 09:11:25 +08:00
|
|
|
|
local direct_dns_tcp_port = var["-direct_dns_tcp_port"]
|
2023-09-04 23:36:20 +08:00
|
|
|
|
local direct_dns_doh_url = var["-direct_dns_doh_url"]
|
|
|
|
|
local direct_dns_doh_host = var["-direct_dns_doh_host"]
|
2023-09-15 09:11:25 +08:00
|
|
|
|
local direct_dns_doh_ip = var["-direct_dns_doh_ip"]
|
|
|
|
|
local direct_dns_doh_port = var["-direct_dns_doh_port"]
|
2023-09-04 23:36:20 +08:00
|
|
|
|
local remote_dns_udp_server = var["-remote_dns_udp_server"]
|
2023-09-15 09:11:25 +08:00
|
|
|
|
local remote_dns_udp_port = var["-remote_dns_udp_port"]
|
2023-09-04 23:36:20 +08:00
|
|
|
|
local remote_dns_tcp_server = var["-remote_dns_tcp_server"]
|
2023-09-15 09:11:25 +08:00
|
|
|
|
local remote_dns_tcp_port = var["-remote_dns_tcp_port"]
|
2023-09-04 23:36:20 +08:00
|
|
|
|
local remote_dns_doh_url = var["-remote_dns_doh_url"]
|
|
|
|
|
local remote_dns_doh_host = var["-remote_dns_doh_host"]
|
2023-09-15 09:11:25 +08:00
|
|
|
|
local remote_dns_doh_ip = var["-remote_dns_doh_ip"]
|
|
|
|
|
local remote_dns_doh_port = var["-remote_dns_doh_port"]
|
2023-09-26 16:23:24 +08:00
|
|
|
|
local remote_dns_detour = var["-remote_dns_detour"]
|
2023-09-04 23:36:20 +08:00
|
|
|
|
local remote_dns_outbound_socks_address = var["-remote_dns_outbound_socks_address"]
|
|
|
|
|
local remote_dns_outbound_socks_port = var["-remote_dns_outbound_socks_port"]
|
|
|
|
|
local dns_cache = var["-dns_cache"]
|
|
|
|
|
local log = var["-log"] or "0"
|
|
|
|
|
local loglevel = var["-loglevel"] or "warn"
|
|
|
|
|
local logfile = var["-logfile"] or "/dev/null"
|
|
|
|
|
|
|
|
|
|
local inbounds = {}
|
|
|
|
|
local outbounds = {}
|
|
|
|
|
local dns = nil
|
|
|
|
|
local route = nil
|
|
|
|
|
|
|
|
|
|
if dns_listen_port then
|
|
|
|
|
route = {
|
|
|
|
|
rules = {}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dns = {
|
|
|
|
|
servers = {},
|
|
|
|
|
rules = {},
|
|
|
|
|
disable_cache = (dns_cache and dns_cache == "0") and true or false,
|
|
|
|
|
disable_expire = false, --禁用 DNS 缓存过期。
|
|
|
|
|
independent_cache = false, --使每个 DNS 服务器的缓存独立,以满足特殊目的。如果启用,将轻微降低性能。
|
|
|
|
|
reverse_mapping = true, --在响应 DNS 查询后存储 IP 地址的反向映射以为路由目的提供域名。
|
|
|
|
|
}
|
2023-09-26 16:23:24 +08:00
|
|
|
|
|
2023-09-04 23:36:20 +08:00
|
|
|
|
if dns_out_tag == "remote" then
|
2023-09-26 16:23:24 +08:00
|
|
|
|
local out_tag = nil
|
|
|
|
|
if remote_dns_detour == "direct" then
|
|
|
|
|
out_tag = "direct-out"
|
|
|
|
|
table.insert(outbounds, 1, {
|
|
|
|
|
type = "direct",
|
|
|
|
|
tag = out_tag,
|
|
|
|
|
routing_mark = 255,
|
|
|
|
|
domain_strategy = (dns_query_strategy and dns_query_strategy ~= "UseIP") and "ipv4_only" or "prefer_ipv6",
|
|
|
|
|
})
|
|
|
|
|
else
|
|
|
|
|
if remote_dns_outbound_socks_address and remote_dns_outbound_socks_port then
|
|
|
|
|
out_tag = "remote-out"
|
|
|
|
|
table.insert(outbounds, 1, {
|
|
|
|
|
type = "socks",
|
|
|
|
|
tag = out_tag,
|
|
|
|
|
server = remote_dns_outbound_socks_address,
|
|
|
|
|
server_port = tonumber(remote_dns_outbound_socks_port),
|
|
|
|
|
})
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
2023-09-04 23:36:20 +08:00
|
|
|
|
local server = {
|
|
|
|
|
tag = dns_out_tag,
|
|
|
|
|
address_strategy = "prefer_ipv4",
|
|
|
|
|
strategy = (dns_query_strategy and dns_query_strategy ~= "UseIP") and "ipv4_only" or "prefer_ipv6",
|
2023-09-26 16:23:24 +08:00
|
|
|
|
detour = out_tag,
|
2023-09-04 23:36:20 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if remote_dns_udp_server then
|
2023-09-15 09:11:25 +08:00
|
|
|
|
local server_port = tonumber(remote_dns_udp_port) or 53
|
2023-09-04 23:36:20 +08:00
|
|
|
|
server.address = "udp://" .. remote_dns_udp_server .. ":" .. server_port
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
if remote_dns_tcp_server then
|
2023-09-15 09:11:25 +08:00
|
|
|
|
local server_port = tonumber(remote_dns_tcp_port) or 53
|
|
|
|
|
server.address = "tcp://" .. remote_dns_tcp_server .. ":" .. server_port
|
2023-09-04 23:36:20 +08:00
|
|
|
|
end
|
|
|
|
|
|
2023-09-15 09:11:25 +08:00
|
|
|
|
if remote_dns_doh_url then
|
2023-09-04 23:36:20 +08:00
|
|
|
|
server.address = remote_dns_doh_url
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
table.insert(dns.servers, server)
|
|
|
|
|
|
2023-09-26 16:23:24 +08:00
|
|
|
|
route.final = out_tag
|
|
|
|
|
elseif dns_out_tag == "direct" then
|
|
|
|
|
local out_tag = "direct-out"
|
2023-09-04 23:36:20 +08:00
|
|
|
|
table.insert(outbounds, 1, {
|
2023-09-26 16:23:24 +08:00
|
|
|
|
type = "direct",
|
|
|
|
|
tag = out_tag,
|
|
|
|
|
routing_mark = 255,
|
|
|
|
|
domain_strategy = (dns_query_strategy and dns_query_strategy ~= "UseIP") and "ipv4_only" or "prefer_ipv6",
|
2023-09-04 23:36:20 +08:00
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
local server = {
|
|
|
|
|
tag = dns_out_tag,
|
|
|
|
|
address_strategy = "prefer_ipv6",
|
|
|
|
|
strategy = (dns_query_strategy and dns_query_strategy ~= "UseIP") and "ipv4_only" or "prefer_ipv6",
|
2023-09-26 16:23:24 +08:00
|
|
|
|
detour = out_tag,
|
2023-09-04 23:36:20 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if direct_dns_udp_server then
|
2023-09-15 09:11:25 +08:00
|
|
|
|
local server_port = tonumber(direct_dns_udp_port) or 53
|
2023-09-04 23:36:20 +08:00
|
|
|
|
server.address = "udp://" .. direct_dns_udp_server .. ":" .. server_port
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
if direct_dns_tcp_server then
|
2023-09-15 09:11:25 +08:00
|
|
|
|
local server_port = tonumber(direct_dns_tcp_port) or 53
|
|
|
|
|
server.address = "tcp://" .. direct_dns_tcp_server .. ":" .. server_port
|
2023-09-04 23:36:20 +08:00
|
|
|
|
end
|
|
|
|
|
|
2023-09-15 09:11:25 +08:00
|
|
|
|
if direct_dns_doh_url then
|
2023-09-04 23:36:20 +08:00
|
|
|
|
server.address = direct_dns_doh_url
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
table.insert(dns.servers, server)
|
2023-09-26 16:23:24 +08:00
|
|
|
|
|
|
|
|
|
route.final = out_tag
|
2023-09-04 23:36:20 +08:00
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
table.insert(inbounds, {
|
|
|
|
|
type = "direct",
|
|
|
|
|
tag = "dns-in",
|
|
|
|
|
listen = "127.0.0.1",
|
|
|
|
|
listen_port = tonumber(dns_listen_port),
|
|
|
|
|
sniff = true,
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
table.insert(outbounds, {
|
|
|
|
|
type = "dns",
|
|
|
|
|
tag = "dns-out",
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
table.insert(route.rules, 1, {
|
|
|
|
|
protocol = "dns",
|
|
|
|
|
inbound = {
|
|
|
|
|
"dns-in"
|
|
|
|
|
},
|
|
|
|
|
outbound = "dns-out"
|
|
|
|
|
})
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
if inbounds or outbounds then
|
|
|
|
|
local config = {
|
|
|
|
|
log = {
|
|
|
|
|
disabled = log == "0" and true or false,
|
|
|
|
|
level = loglevel,
|
|
|
|
|
timestamp = true,
|
|
|
|
|
output = logfile,
|
|
|
|
|
},
|
|
|
|
|
-- DNS
|
|
|
|
|
dns = dns,
|
|
|
|
|
-- 传入连接
|
|
|
|
|
inbounds = inbounds,
|
|
|
|
|
-- 传出连接
|
|
|
|
|
outbounds = outbounds,
|
|
|
|
|
-- 路由
|
|
|
|
|
route = route
|
|
|
|
|
}
|
|
|
|
|
return jsonc.stringify(config, 1)
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
_G.gen_config = gen_config
|
|
|
|
|
_G.gen_proto_config = gen_proto_config
|
|
|
|
|
_G.gen_dns_config = gen_dns_config
|
|
|
|
|
|
|
|
|
|
if arg[1] then
|
|
|
|
|
local func =_G[arg[1]]
|
|
|
|
|
if func then
|
|
|
|
|
print(func(api.get_function_args(arg)))
|
|
|
|
|
end
|
|
|
|
|
end
|