luci: add sing-box server support
This commit is contained in:
parent
2638af0efa
commit
df8373f593
@ -45,15 +45,8 @@ e = t:option(DummyValue, "type", translate("Type"))
|
||||
e.cfgvalue = function(t, n)
|
||||
local v = Value.cfgvalue(t, n)
|
||||
if v then
|
||||
if v == "V2ray" or v == "Xray" then
|
||||
if v == "sing-box" or v == "V2ray" or v == "Xray" then
|
||||
local protocol = m:get(n, "protocol")
|
||||
if protocol == "vmess" then
|
||||
protocol = "VMess"
|
||||
elseif protocol == "vless" then
|
||||
protocol = "VLESS"
|
||||
else
|
||||
protocol = protocol:gsub("^%l",string.upper)
|
||||
end
|
||||
return v .. " -> " .. protocol
|
||||
end
|
||||
return v
|
||||
|
@ -0,0 +1,284 @@
|
||||
local m, s = ...
|
||||
|
||||
local api = require "luci.passwall.api"
|
||||
|
||||
local singbox_bin = api.finded_com("singbox")
|
||||
|
||||
if not singbox_bin then
|
||||
return
|
||||
end
|
||||
|
||||
local singbox_tags = luci.sys.exec(singbox_bin .. " version | grep 'Tags:' | awk '{print $2}'")
|
||||
|
||||
local type_name = "sing-box"
|
||||
|
||||
local option_prefix = "singbox_"
|
||||
|
||||
local function option_name(name)
|
||||
return option_prefix .. name
|
||||
end
|
||||
|
||||
local function rm_prefix_cfgvalue(self, section)
|
||||
if self.option:find(option_prefix) == 1 then
|
||||
return m:get(section, self.option:sub(1 + #option_prefix))
|
||||
end
|
||||
end
|
||||
local function rm_prefix_write(self, section, value)
|
||||
if s.fields["type"]:formvalue(arg[1]) == type_name then
|
||||
if self.option:find(option_prefix) == 1 then
|
||||
m:set(section, self.option:sub(1 + #option_prefix), value)
|
||||
end
|
||||
end
|
||||
end
|
||||
local function rm_prefix_remove(self, section, value)
|
||||
if s.fields["type"]:formvalue(arg[1]) == type_name then
|
||||
if self.option:find(option_prefix) == 1 then
|
||||
m:del(section, self.option:sub(1 + #option_prefix))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local ss_method_list = {
|
||||
"none", "aes-128-gcm", "aes-192-gcm", "aes-256-gcm", "chacha20-ietf-poly1305", "xchacha20-ietf-poly1305",
|
||||
"2022-blake3-aes-128-gcm", "2022-blake3-aes-256-gcm", "2022-blake3-chacha20-poly1305"
|
||||
}
|
||||
|
||||
-- [[ Sing-Box ]]
|
||||
|
||||
s.fields["type"]:value(type_name, "Sing-Box")
|
||||
|
||||
o = s:option(ListValue, option_name("protocol"), translate("Protocol"))
|
||||
o:value("socks", "Socks")
|
||||
o:value("http", "HTTP")
|
||||
o:value("shadowsocks", "Shadowsocks")
|
||||
o:value("vmess", "Vmess")
|
||||
o:value("vless", "VLESS")
|
||||
o:value("trojan", "Trojan")
|
||||
o:value("direct", "Direct")
|
||||
|
||||
o = s:option(Value, option_name("port"), translate("Listen Port"))
|
||||
o.datatype = "port"
|
||||
|
||||
o = s:option(Flag, option_name("auth"), translate("Auth"))
|
||||
o.validate = function(self, value, t)
|
||||
if value and value == "1" then
|
||||
local user_v = s.fields[option_name("username")]:formvalue(t) or ""
|
||||
local pass_v = s.fields[option_name("password")]:formvalue(t) or ""
|
||||
if user_v == "" or pass_v == "" then
|
||||
return nil, translate("Username and Password must be used together!")
|
||||
end
|
||||
end
|
||||
return value
|
||||
end
|
||||
o:depends({ [option_name("protocol")] = "socks" })
|
||||
o:depends({ [option_name("protocol")] = "http" })
|
||||
|
||||
o = s:option(Value, option_name("username"), translate("Username"))
|
||||
o:depends({ [option_name("auth")] = true })
|
||||
|
||||
o = s:option(Value, option_name("password"), translate("Password"))
|
||||
o.password = true
|
||||
o:depends({ [option_name("auth")] = true })
|
||||
o:depends({ [option_name("protocol")] = "shadowsocks" })
|
||||
|
||||
o = s:option(ListValue, option_name("d_protocol"), translate("Destination protocol"))
|
||||
o:value("tcp", "TCP")
|
||||
o:value("udp", "UDP")
|
||||
o:value("tcp,udp", "TCP,UDP")
|
||||
o:depends({ [option_name("protocol")] = "direct" })
|
||||
|
||||
o = s:option(Value, option_name("d_address"), translate("Destination address"))
|
||||
o:depends({ [option_name("protocol")] = "direct" })
|
||||
|
||||
o = s:option(Value, option_name("d_port"), translate("Destination port"))
|
||||
o.datatype = "port"
|
||||
o:depends({ [option_name("protocol")] = "direct" })
|
||||
|
||||
o = s:option(Value, option_name("decryption"), translate("Encrypt Method"))
|
||||
o.default = "none"
|
||||
o:depends({ [option_name("protocol")] = "vless" })
|
||||
|
||||
o = s:option(ListValue, option_name("ss_method"), translate("Encrypt Method"))
|
||||
o.not_rewrite = true
|
||||
for a, t in ipairs(ss_method_list) do o:value(t) end
|
||||
o:depends({ [option_name("protocol")] = "shadowsocks" })
|
||||
function o.cfgvalue(self, section)
|
||||
return m:get(section, "method")
|
||||
end
|
||||
function o.write(self, section, value)
|
||||
if s.fields["type"]:formvalue(arg[1]) == type_name then
|
||||
m:set(section, "method", value)
|
||||
end
|
||||
end
|
||||
|
||||
o = s:option(DynamicList, option_name("uuid"), translate("ID") .. "/" .. translate("Password"))
|
||||
for i = 1, 3 do
|
||||
o:value(api.gen_uuid(1))
|
||||
end
|
||||
o:depends({ [option_name("protocol")] = "vmess" })
|
||||
o:depends({ [option_name("protocol")] = "vless" })
|
||||
o:depends({ [option_name("protocol")] = "trojan" })
|
||||
|
||||
o = s:option(ListValue, option_name("flow"), translate("flow"))
|
||||
o.default = ""
|
||||
o:value("", translate("Disable"))
|
||||
o:value("xtls-rprx-vision")
|
||||
o:depends({ [option_name("protocol")] = "vless" })
|
||||
|
||||
o = s:option(Flag, option_name("tls"), translate("TLS"))
|
||||
o.default = 0
|
||||
o.validate = function(self, value, t)
|
||||
if value then
|
||||
if value == "1" then
|
||||
local ca = s.fields[option_name("tls_certificateFile")]:formvalue(t) or ""
|
||||
local key = s.fields[option_name("tls_keyFile")]:formvalue(t) or ""
|
||||
if ca == "" or key == "" then
|
||||
return nil, translate("Public key and Private key path can not be empty!")
|
||||
end
|
||||
end
|
||||
return value
|
||||
end
|
||||
end
|
||||
o:depends({ [option_name("protocol")] = "http" })
|
||||
o:depends({ [option_name("protocol")] = "shadowsocks" })
|
||||
o:depends({ [option_name("protocol")] = "vmess" })
|
||||
o:depends({ [option_name("protocol")] = "vless" })
|
||||
o:depends({ [option_name("protocol")] = "trojan" })
|
||||
|
||||
-- [[ TLS部分 ]] --
|
||||
|
||||
o = s:option(FileUpload, option_name("tls_certificateFile"), translate("Public key absolute path"), translate("as:") .. "/etc/ssl/fullchain.pem")
|
||||
o.default = m:get(s.section, "tls_certificateFile") or "/etc/config/ssl/" .. arg[1] .. ".pem"
|
||||
o:depends({ [option_name("tls")] = true })
|
||||
o.validate = function(self, value, t)
|
||||
if value and value ~= "" then
|
||||
if not nixio.fs.access(value) then
|
||||
return nil, translate("Can't find this file!")
|
||||
else
|
||||
return value
|
||||
end
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
o = s:option(FileUpload, option_name("tls_keyFile"), translate("Private key absolute path"), translate("as:") .. "/etc/ssl/private.key")
|
||||
o.default = m:get(s.section, "tls_keyFile") or "/etc/config/ssl/" .. arg[1] .. ".key"
|
||||
o:depends({ [option_name("tls")] = true })
|
||||
o.validate = function(self, value, t)
|
||||
if value and value ~= "" then
|
||||
if not nixio.fs.access(value) then
|
||||
return nil, translate("Can't find this file!")
|
||||
else
|
||||
return value
|
||||
end
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
o = s:option(ListValue, option_name("transport"), translate("Transport"))
|
||||
o:value("tcp", "TCP")
|
||||
o:value("http", "HTTP")
|
||||
o:value("ws", "WebSocket")
|
||||
o:value("quic", "QUIC")
|
||||
o:value("grpc", "gRPC")
|
||||
o:depends({ [option_name("protocol")] = "shadowsocks" })
|
||||
o:depends({ [option_name("protocol")] = "vmess" })
|
||||
o:depends({ [option_name("protocol")] = "vless" })
|
||||
o:depends({ [option_name("protocol")] = "trojan" })
|
||||
|
||||
-- [[ HTTP部分 ]]--
|
||||
|
||||
o = s:option(Value, option_name("http_host"), translate("HTTP Host"))
|
||||
o:depends({ [option_name("transport")] = "http" })
|
||||
|
||||
o = s:option(Value, option_name("http_path"), translate("HTTP Path"))
|
||||
o:depends({ [option_name("transport")] = "http" })
|
||||
|
||||
-- [[ WebSocket部分 ]]--
|
||||
|
||||
o = s:option(Value, option_name("ws_host"), translate("WebSocket Host"))
|
||||
o:depends({ [option_name("transport")] = "ws" })
|
||||
|
||||
o = s:option(Value, option_name("ws_path"), translate("WebSocket Path"))
|
||||
o:depends({ [option_name("transport")] = "ws" })
|
||||
|
||||
-- [[ gRPC部分 ]]--
|
||||
o = s:option(Value, option_name("grpc_serviceName"), "ServiceName")
|
||||
o:depends({ [option_name("transport")] = "grpc" })
|
||||
|
||||
o = s:option(Flag, option_name("bind_local"), translate("Bind Local"), translate("When selected, it can only be accessed locally, It is recommended to turn on when using reverse proxies or be fallback."))
|
||||
o.default = "0"
|
||||
|
||||
o = s:option(Flag, option_name("accept_lan"), translate("Accept LAN Access"), translate("When selected, it can accessed lan , this will not be safe!"))
|
||||
o.default = "0"
|
||||
|
||||
local nodes_table = {}
|
||||
for k, e in ipairs(api.get_valid_nodes()) do
|
||||
if e.node_type == "normal" and e.type == type_name then
|
||||
nodes_table[#nodes_table + 1] = {
|
||||
id = e[".name"],
|
||||
remarks = e["remark"]
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
o = s:option(ListValue, option_name("outbound_node"), translate("outbound node"))
|
||||
o:value("nil", translate("Close"))
|
||||
o:value("_socks", translate("Custom Socks"))
|
||||
o:value("_http", translate("Custom HTTP"))
|
||||
o:value("_iface", translate("Custom Interface"))
|
||||
for k, v in pairs(nodes_table) do o:value(v.id, v.remarks) end
|
||||
o.default = "nil"
|
||||
|
||||
o = s:option(Value, option_name("outbound_node_address"), translate("Address (Support Domain Name)"))
|
||||
o:depends({ [option_name("outbound_node")] = "_socks" })
|
||||
o:depends({ [option_name("outbound_node")] = "_http" })
|
||||
|
||||
o = s:option(Value, option_name("outbound_node_port"), translate("Port"))
|
||||
o.datatype = "port"
|
||||
o:depends({ [option_name("outbound_node")] = "_socks" })
|
||||
o:depends({ [option_name("outbound_node")] = "_http" })
|
||||
|
||||
o = s:option(Value, option_name("outbound_node_username"), translate("Username"))
|
||||
o:depends({ [option_name("outbound_node")] = "_socks" })
|
||||
o:depends({ [option_name("outbound_node")] = "_http" })
|
||||
|
||||
o = s:option(Value, option_name("outbound_node_password"), translate("Password"))
|
||||
o.password = true
|
||||
o:depends({ [option_name("outbound_node")] = "_socks" })
|
||||
o:depends({ [option_name("outbound_node")] = "_http" })
|
||||
|
||||
o = s:option(Value, option_name("outbound_node_iface"), translate("Interface"))
|
||||
o.default = "eth1"
|
||||
o:depends({ [option_name("outbound_node")] = "_iface" })
|
||||
|
||||
o = s:option(Flag, option_name("log"), translate("Log"))
|
||||
o.default = "1"
|
||||
o.rmempty = false
|
||||
|
||||
o = s:option(ListValue, option_name("loglevel"), translate("Log Level"))
|
||||
o.default = "info"
|
||||
o:value("debug")
|
||||
o:value("info")
|
||||
o:value("warn")
|
||||
o:value("error")
|
||||
o:depends({ [option_name("log")] = true })
|
||||
|
||||
for key, value in pairs(s.fields) do
|
||||
if key:find(option_prefix) == 1 then
|
||||
if not s.fields[key].not_rewrite then
|
||||
s.fields[key].cfgvalue = rm_prefix_cfgvalue
|
||||
s.fields[key].write = rm_prefix_write
|
||||
s.fields[key].remove = rm_prefix_remove
|
||||
end
|
||||
|
||||
local deps = s.fields[key].deps
|
||||
if #deps > 0 then
|
||||
for index, value in ipairs(deps) do
|
||||
deps[index]["type"] = type_name
|
||||
end
|
||||
else
|
||||
s.fields[key]:depends({ type = type_name })
|
||||
end
|
||||
end
|
||||
end
|
@ -140,6 +140,9 @@ local function start()
|
||||
elseif type == "SS-Rust" then
|
||||
config = require(require_dir .. "util_shadowsocks").gen_config_server(user)
|
||||
bin = ln_run("/usr/bin/ssserver", "ssserver", "-c " .. config_file, log_path)
|
||||
elseif type == "sing-box" then
|
||||
config = require(require_dir .. "util_sing-box").gen_config_server(user)
|
||||
bin = ln_run(api.get_app_path("singbox"), "sing-box", "run -c " .. config_file, log_path)
|
||||
elseif type == "V2ray" then
|
||||
config = require(require_dir .. "util_xray").gen_config_server(user)
|
||||
bin = ln_run(api.get_app_path("v2ray"), "v2ray", "run -c " .. config_file, log_path)
|
||||
|
@ -261,107 +261,167 @@ function gen_outbound(flag, node, tag, proxy_table)
|
||||
end
|
||||
|
||||
function gen_config_server(node)
|
||||
local settings = nil
|
||||
local routing = nil
|
||||
local outbounds = {
|
||||
{protocol = "freedom", tag = "direct"}, {protocol = "block", tag = "block"}
|
||||
{ type = "direct", tag = "direct" },
|
||||
{ type = "block", tag = "block" }
|
||||
}
|
||||
|
||||
if node.protocol == "vmess" or node.protocol == "vless" then
|
||||
if node.uuid then
|
||||
local clients = {}
|
||||
for i = 1, #node.uuid do
|
||||
clients[i] = {
|
||||
id = node.uuid[i],
|
||||
flow = ("vless" == node.protocol and "1" == node.tls and node.tlsflow) and node.tlsflow or nil
|
||||
}
|
||||
end
|
||||
settings = {
|
||||
clients = clients,
|
||||
decryption = node.decryption or "none"
|
||||
}
|
||||
end
|
||||
elseif node.protocol == "socks" then
|
||||
settings = {
|
||||
udp = ("1" == node.udp_forward) and true or false,
|
||||
auth = ("1" == node.auth) and "password" or "noauth",
|
||||
accounts = ("1" == node.auth) and {
|
||||
local tls = nil
|
||||
|
||||
if node.tls == "1" then
|
||||
tls = {
|
||||
enabled = true,
|
||||
certificate_path = node.tls_certificateFile,
|
||||
key_path = node.tls_keyFile,
|
||||
}
|
||||
end
|
||||
|
||||
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
|
||||
|
||||
if node.transport == "quic" then
|
||||
v2ray_transport = {
|
||||
type = "quic"
|
||||
}
|
||||
--没有额外的加密支持: 它基本上是重复加密。 并且 Xray-core 在这里与 v2ray-core 不兼容。
|
||||
end
|
||||
|
||||
if node.transport == "grpc" then
|
||||
v2ray_transport = {
|
||||
type = "grpc",
|
||||
serviceName = node.grpc_serviceName,
|
||||
}
|
||||
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 == "socks" then
|
||||
protocol_table = {
|
||||
users = (node.auth == "1") and {
|
||||
{
|
||||
user = node.username,
|
||||
pass = node.password
|
||||
username = node.username,
|
||||
password = node.password
|
||||
}
|
||||
} or nil
|
||||
}
|
||||
elseif node.protocol == "http" then
|
||||
settings = {
|
||||
allowTransparent = false,
|
||||
accounts = ("1" == node.auth) and {
|
||||
end
|
||||
|
||||
if node.protocol == "http" then
|
||||
protocol_table = {
|
||||
users = (node.auth == "1") and {
|
||||
{
|
||||
user = node.username,
|
||||
pass = node.password
|
||||
username = node.username,
|
||||
password = node.password
|
||||
}
|
||||
} or nil
|
||||
} or nil,
|
||||
tls = tls,
|
||||
}
|
||||
node.transport = "tcp"
|
||||
node.tcp_guise = "none"
|
||||
elseif node.protocol == "shadowsocks" then
|
||||
settings = {
|
||||
end
|
||||
|
||||
if node.protocol == "shadowsocks" then
|
||||
protocol_table = {
|
||||
method = node.method,
|
||||
password = node.password,
|
||||
ivCheck = ("1" == node.iv_check) and true or false,
|
||||
network = node.ss_network or "TCP,UDP"
|
||||
}
|
||||
elseif node.protocol == "trojan" then
|
||||
end
|
||||
|
||||
if node.protocol == "vmess" then
|
||||
if node.uuid then
|
||||
local clients = {}
|
||||
local users = {}
|
||||
for i = 1, #node.uuid do
|
||||
clients[i] = {
|
||||
password = node.uuid[i]
|
||||
users[i] = {
|
||||
name = node.uuid[i],
|
||||
uuid = node.uuid[i],
|
||||
alterId = 0,
|
||||
}
|
||||
end
|
||||
settings = {
|
||||
clients = clients
|
||||
protocol_table = {
|
||||
users = users,
|
||||
tls = tls,
|
||||
transport = v2ray_transport,
|
||||
}
|
||||
end
|
||||
elseif node.protocol == "dokodemo-door" then
|
||||
settings = {
|
||||
network = node.d_protocol,
|
||||
address = node.d_address,
|
||||
port = tonumber(node.d_port)
|
||||
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,
|
||||
tls = tls,
|
||||
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],
|
||||
uuid = node.uuid[i],
|
||||
}
|
||||
end
|
||||
protocol_table = {
|
||||
users = users,
|
||||
tls = tls,
|
||||
fallback = nil,
|
||||
fallback_for_alpn = nil,
|
||||
transport = v2ray_transport,
|
||||
}
|
||||
end
|
||||
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 node.fallback and node.fallback == "1" then
|
||||
local fallbacks = {}
|
||||
for i = 1, #node.fallback_list do
|
||||
local fallbackStr = node.fallback_list[i]
|
||||
if fallbackStr then
|
||||
local tmp = {}
|
||||
string.gsub(fallbackStr, '[^' .. "," .. ']+', function(w)
|
||||
table.insert(tmp, w)
|
||||
end)
|
||||
local dest = tmp[1] or ""
|
||||
local path = tmp[2]
|
||||
if dest:find("%.") then
|
||||
else
|
||||
dest = tonumber(dest)
|
||||
end
|
||||
fallbacks[i] = {
|
||||
path = path,
|
||||
dest = dest,
|
||||
xver = 1
|
||||
}
|
||||
end
|
||||
if protocol_table then
|
||||
for key, value in pairs(protocol_table) do
|
||||
inbound[key] = value
|
||||
end
|
||||
settings.fallbacks = fallbacks
|
||||
end
|
||||
|
||||
routing = {
|
||||
local route = {
|
||||
rules = {
|
||||
{
|
||||
type = "field",
|
||||
ip = {"10.0.0.0/8", "172.16.0.0/12", "192.168.0.0/16"},
|
||||
outboundTag = (node.accept_lan == nil or node.accept_lan == "0") and "block" or "direct"
|
||||
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"
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -370,14 +430,10 @@ function gen_config_server(node)
|
||||
local outbound = nil
|
||||
if node.outbound_node == "_iface" and node.outbound_node_iface then
|
||||
outbound = {
|
||||
protocol = "freedom",
|
||||
type = "direct",
|
||||
tag = "outbound",
|
||||
streamSettings = {
|
||||
sockopt = {
|
||||
mark = 255,
|
||||
interface = node.outbound_node_iface
|
||||
}
|
||||
}
|
||||
bind_interface = node.outbound_node_iface,
|
||||
routing_mark = 255,
|
||||
}
|
||||
sys.call("mkdir -p /tmp/etc/passwall/iface && touch /tmp/etc/passwall/iface/" .. node.outbound_node_iface)
|
||||
else
|
||||
@ -386,9 +442,8 @@ function gen_config_server(node)
|
||||
outbound_node_t = {
|
||||
type = node.type,
|
||||
protocol = node.outbound_node:gsub("_", ""),
|
||||
transport = "tcp",
|
||||
address = node.outbound_node_address,
|
||||
port = node.outbound_node_port,
|
||||
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,
|
||||
}
|
||||
@ -396,99 +451,31 @@ function gen_config_server(node)
|
||||
outbound = require("luci.passwall.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 = {
|
||||
loglevel = ("1" == node.log) and node.loglevel or "none"
|
||||
disabled = (not node or node.log == "0") and true or false,
|
||||
level = node.loglevel or "info",
|
||||
timestamp = true,
|
||||
--output = logfile,
|
||||
},
|
||||
-- 传入连接
|
||||
inbounds = {
|
||||
{
|
||||
listen = (node.bind_local == "1") and "127.0.0.1" or nil,
|
||||
port = tonumber(node.port),
|
||||
protocol = node.protocol,
|
||||
settings = settings,
|
||||
streamSettings = {
|
||||
network = node.transport,
|
||||
security = "none",
|
||||
tlsSettings = ("1" == node.tls) and {
|
||||
disableSystemRoot = false,
|
||||
certificates = {
|
||||
{
|
||||
certificateFile = node.tls_certificateFile,
|
||||
keyFile = node.tls_keyFile
|
||||
}
|
||||
}
|
||||
} or nil,
|
||||
tcpSettings = (node.transport == "tcp") and {
|
||||
acceptProxyProtocol = (node.acceptProxyProtocol and node.acceptProxyProtocol == "1") and true or false,
|
||||
header = {
|
||||
type = node.tcp_guise,
|
||||
request = (node.tcp_guise == "http") and {
|
||||
path = node.tcp_guise_http_path or {"/"},
|
||||
headers = {
|
||||
Host = node.tcp_guise_http_host or {}
|
||||
}
|
||||
} or nil
|
||||
}
|
||||
} or nil,
|
||||
kcpSettings = (node.transport == "mkcp") and {
|
||||
mtu = tonumber(node.mkcp_mtu),
|
||||
tti = tonumber(node.mkcp_tti),
|
||||
uplinkCapacity = tonumber(node.mkcp_uplinkCapacity),
|
||||
downlinkCapacity = tonumber(node.mkcp_downlinkCapacity),
|
||||
congestion = (node.mkcp_congestion == "1") and true or false,
|
||||
readBufferSize = tonumber(node.mkcp_readBufferSize),
|
||||
writeBufferSize = tonumber(node.mkcp_writeBufferSize),
|
||||
seed = (node.mkcp_seed and node.mkcp_seed ~= "") and node.mkcp_seed or nil,
|
||||
header = {type = node.mkcp_guise}
|
||||
} or nil,
|
||||
wsSettings = (node.transport == "ws") and {
|
||||
acceptProxyProtocol = (node.acceptProxyProtocol and node.acceptProxyProtocol == "1") and true or false,
|
||||
headers = (node.ws_host) and {Host = node.ws_host} or nil,
|
||||
path = node.ws_path
|
||||
} or nil,
|
||||
httpSettings = (node.transport == "h2") and {
|
||||
path = node.h2_path, host = node.h2_host
|
||||
} or nil,
|
||||
dsSettings = (node.transport == "ds") and {
|
||||
path = node.ds_path
|
||||
} or nil,
|
||||
quicSettings = (node.transport == "quic") and {
|
||||
security = node.quic_security,
|
||||
key = node.quic_key,
|
||||
header = {type = node.quic_guise}
|
||||
} or nil,
|
||||
grpcSettings = (node.transport == "grpc") and {
|
||||
serviceName = node.grpc_serviceName
|
||||
} or nil
|
||||
}
|
||||
}
|
||||
},
|
||||
-- 传出连接
|
||||
inbounds = { inbound },
|
||||
outbounds = outbounds,
|
||||
routing = routing
|
||||
route = route
|
||||
}
|
||||
|
||||
local alpn = {}
|
||||
if node.alpn then
|
||||
string.gsub(node.alpn, '[^' .. "," .. ']+', function(w)
|
||||
table.insert(alpn, w)
|
||||
end)
|
||||
end
|
||||
if alpn and #alpn > 0 then
|
||||
if config.inbounds[1].streamSettings.tlsSettings then
|
||||
config.inbounds[1].streamSettings.tlsSettings.alpn = alpn
|
||||
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
|
||||
|
||||
if "1" == node.tls then
|
||||
config.inbounds[1].streamSettings.security = "tls"
|
||||
end
|
||||
|
||||
return config
|
||||
end
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user