mirror of
https://github.com/kiddin9/op-packages.git
synced 2026-11-13 07:57:52 +08:00
🎨 Sync 2026-06-04 22:17:22
This commit is contained in:
1 parent
d4045244be
commit
e50963f221
71 files changed
+15700
-6848
No files matched your search
@@ -2,7 +2,6 @@
|
||||
|
||||
require "luci.sys"
|
||||
local ucursor = require "luci.model.uci".cursor()
|
||||
local datatypes = require "luci.cbi.datatypes"
|
||||
local json = require "luci.jsonc"
|
||||
|
||||
local server_section = arg[1]
|
||||
@@ -12,12 +11,6 @@ local socks_port = arg[4] or "0"
|
||||
|
||||
local chain = arg[5] or "0"
|
||||
|
||||
local GLOBAL = {
|
||||
DNS_SERVER = {},
|
||||
DNS_HOSTNAME = {},
|
||||
VPS_EXCLUDE = {}
|
||||
}
|
||||
|
||||
-- 辅助函数:拆分字符串(若 luci.util 未加载则定义)
|
||||
local function split(str, pat)
|
||||
local t = {}
|
||||
@@ -38,27 +31,52 @@ local server = ucursor:get_all("shadowsocksr", server_section)
|
||||
local socks_server = ucursor:get_all("shadowsocksr", "@socks5_proxy[0]") or {}
|
||||
local xray_fragment = ucursor:get_all("shadowsocksr", "@global_xray_fragment[0]") or {}
|
||||
local xray_noise = ucursor:get_all("shadowsocksr", "@xray_noise_packets[0]") or {}
|
||||
local default_node_local_port = ucursor:get_first("shadowsocksr", "global", "default_node_local_port", "1234")
|
||||
local dns_mode = ucursor:get_first("shadowsocksr", "global", "pdnsd_enable", "0")
|
||||
local dns_ipv4_only = ucursor:get_first("shadowsocksr", "global", "filter_aaaa")
|
||||
if not dns_ipv4_only or dns_ipv4_only == "" then
|
||||
dns_ipv4_only = ucursor:get_first("shadowsocksr", "global", "mosdns_ipv6", "1")
|
||||
end
|
||||
local builtin_dns_server = ucursor:get_first("shadowsocksr", "global", "tunnel_forward", "8.8.4.4:53")
|
||||
local outbound_settings = nil
|
||||
local xray_version = nil
|
||||
local xray_version_val = 0
|
||||
local xray_builtin_dns = nil
|
||||
|
||||
local node_id = server_section
|
||||
local remarks = server.alias or ""
|
||||
local b64decode = nixio.bin.b64decode
|
||||
local b64encode = nixio.bin.b64encode
|
||||
local effective_node_local_port = tonumber(server.local_port) or tonumber(default_node_local_port) or 1234
|
||||
|
||||
-- 解析 URL(简单实现,仅用于 DoH)
|
||||
local function parseURL(url)
|
||||
if not url then return nil end
|
||||
local schema, rest = url:match("^(https?)://(.*)$")
|
||||
if not schema then return nil end
|
||||
local host, port_str = rest:match("^([^:]+):?(%d*)/?.*$")
|
||||
local port = tonumber(port_str) or (schema == "https" and 443 or 80)
|
||||
return { host = host, port = port, schema = schema }
|
||||
if server.type == "ss-rust" then
|
||||
server.type = "ss"
|
||||
end
|
||||
|
||||
if server.type == "ss-rust" or server.type == "ss-libev" then
|
||||
server.type = "ss"
|
||||
local function parse_realm_uri(uri)
|
||||
if type(uri) ~= "string" then return nil end
|
||||
-- realm://token@server/realm_id?query
|
||||
local token, server_url, realm_id, query = trim(uri):match("^realm://([^@]+)@([^/]+)/([^?]*)%??(.*)$")
|
||||
if not token or not server_url or not realm_id then return nil end
|
||||
realm_id = realm_id:gsub("/+$", "")
|
||||
local realm = {
|
||||
token = token,
|
||||
server_url = server_url,
|
||||
realm_id = realm_id
|
||||
}
|
||||
-- 解析 query 中的 stun=
|
||||
if query and query ~= "" then
|
||||
local stun_servers = {}
|
||||
for key, value in query:gmatch("([^&=?]+)=([^&]+)") do
|
||||
if key == "stun" and value ~= "" then
|
||||
stun_servers[#stun_servers + 1] = value
|
||||
end
|
||||
end
|
||||
if #stun_servers > 0 then
|
||||
realm.stun_servers = stun_servers
|
||||
end
|
||||
end
|
||||
return realm
|
||||
end
|
||||
|
||||
-- base64 解码
|
||||
@@ -120,9 +138,25 @@ local function cleanEmptyTables(t)
|
||||
return next(t) and t or nil
|
||||
end
|
||||
|
||||
local function format_host(host)
|
||||
host = tostring(host or "")
|
||||
if host ~= "" and host:find(":", 1, true) and not host:match("^%[.*%]$") then
|
||||
return "[" .. host .. "]"
|
||||
end
|
||||
return host
|
||||
end
|
||||
|
||||
local function format_host_port(host, port)
|
||||
host = format_host(host)
|
||||
if port == nil or port == "" then
|
||||
return host
|
||||
end
|
||||
return host .. ":" .. tostring(port)
|
||||
end
|
||||
|
||||
-- 确保正确判断程序是否存在
|
||||
local function is_finded(e)
|
||||
return luci.sys.exec(string.format('type -t -p "%s" 2>/dev/null', e)) ~= ""
|
||||
return luci.sys.exec(string.format('type -t -p "%s" -p "/usr/libexec/%s" 2>/dev/null', e, e)) ~= ""
|
||||
end
|
||||
|
||||
-- 获取 Xray 版本号
|
||||
@@ -203,20 +237,33 @@ function wireguard()
|
||||
-- 处理 reserved 字段,支持逗号分隔的数字或 Base64 编码
|
||||
local reserved = nil
|
||||
if server.reserved then
|
||||
local bytes = {}
|
||||
if not server.reserved:match("[^%d,]+") then
|
||||
-- 纯数字和逗号,解析为数字列表
|
||||
server.reserved:gsub("%d+", function(b)
|
||||
bytes[#bytes + 1] = tonumber(b)
|
||||
end)
|
||||
else
|
||||
-- Base64 编码的二进制数据
|
||||
local result = base64Decode(server.reserved)
|
||||
for i = 1, #result do
|
||||
bytes[i] = result:byte(i)
|
||||
local all_bytes = {}
|
||||
local reserved_values = server.reserved
|
||||
|
||||
-- 确保是 table 类型
|
||||
if type(reserved_values) ~= "table" then
|
||||
reserved_values = {reserved_values}
|
||||
end
|
||||
|
||||
for _, reserved_str in ipairs(reserved_values) do
|
||||
if type(reserved_str) == "string" then
|
||||
if not reserved_str:match("[^%d,]+") then
|
||||
-- 数字和逗号格式
|
||||
reserved_str:gsub("%d+", function(b)
|
||||
all_bytes[#all_bytes + 1] = tonumber(b)
|
||||
end)
|
||||
else
|
||||
-- Base64 格式
|
||||
local result = base64Decode(reserved_str)
|
||||
if result then
|
||||
for i = 1, #result do
|
||||
all_bytes[#all_bytes + 1] = result:byte(i)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
reserved = #bytes > 0 and bytes or nil
|
||||
reserved = #all_bytes > 0 and all_bytes or nil
|
||||
end
|
||||
|
||||
outbound_settings = {
|
||||
@@ -226,15 +273,22 @@ function wireguard()
|
||||
{
|
||||
publicKey = server.peer_pubkey,
|
||||
preSharedKey = server.preshared_key,
|
||||
endpoint = server.server .. ":" .. server.server_port,
|
||||
endpoint = format_host_port(server.server, server.server_port),
|
||||
keepAlive = tonumber(server.keepaliveperiod),
|
||||
allowedIPs = (server.allowedips) or nil,
|
||||
}
|
||||
},
|
||||
noKernelTun = (server.kernelmode == "1") and true or false,
|
||||
kernelMode = (server.kernelmode == "1") and true or false,
|
||||
reserved = reserved,
|
||||
mtu = tonumber(server.mtu)
|
||||
}
|
||||
if server.finalmask and server.finalmask ~= "" then
|
||||
local ok, fm = pcall(json.parse, base64Decode(server.finalmask))
|
||||
if ok and type(fm) == "table" then
|
||||
outbound_settings.streamSettings = outbound_settings.streamSettings or {}
|
||||
outbound_settings.streamSettings.finalmask = fm
|
||||
end
|
||||
end
|
||||
end
|
||||
function xray_hysteria2()
|
||||
outbound_settings = {
|
||||
@@ -299,6 +353,35 @@ local Xray = {
|
||||
-- 初始化 outbounds 表
|
||||
outbounds = {},
|
||||
}
|
||||
|
||||
if server.type == "v2ray" and dns_mode == "7" and os.getenv("SSR_SWITCH_PROBE") ~= "1" then
|
||||
local dns_host = builtin_dns_server:match("^([^:]+)") or "8.8.4.4"
|
||||
local dns_port = tonumber(builtin_dns_server:match(":(%d+)$")) or 53
|
||||
|
||||
Xray.dns = {
|
||||
queryStrategy = (dns_ipv4_only == "1") and "UseIPv4" or "UseIP",
|
||||
servers = {
|
||||
string.format("tcp://%s:%d", dns_host, dns_port)
|
||||
}
|
||||
}
|
||||
|
||||
table.insert(Xray.inbounds, {
|
||||
listen = "127.0.0.1",
|
||||
port = 5335,
|
||||
protocol = "dokodemo-door",
|
||||
settings = {
|
||||
address = dns_host,
|
||||
port = dns_port,
|
||||
network = "tcp,udp"
|
||||
},
|
||||
tag = "builtin-dns-in"
|
||||
})
|
||||
|
||||
xray_builtin_dns = {
|
||||
address = dns_host,
|
||||
port = dns_port
|
||||
}
|
||||
end
|
||||
-- 传入连接
|
||||
-- 添加 dokodemo-door 配置,如果 local_port 不为 0
|
||||
if local_port ~= "0" then
|
||||
@@ -349,11 +432,11 @@ if proto and proto:find("tcp") and socks_port ~= "0" then
|
||||
-- socks
|
||||
protocol = "socks",
|
||||
port = tonumber(socks_port),
|
||||
settings = {
|
||||
settings = {
|
||||
auth = socks_server.socks5_auth or "noauth",
|
||||
udp = true,
|
||||
mixed = ((socks_server.socks5_mixed == '1') and true or false) or (socks_server.server == 'same') and nil,
|
||||
accounts = (socks_server.server ~= "same" and (socks_server.socks5_auth and socks_server.socks5_auth ~= "noauth")) and {
|
||||
mixed = ((socks_server.socks5_mixed == '1') and true or false) or nil,
|
||||
accounts = (socks_server.socks5_auth and socks_server.socks5_auth ~= "noauth") and {
|
||||
{
|
||||
user = socks_server.socks5_user,
|
||||
pass = socks_server.socks5_pass
|
||||
@@ -529,7 +612,7 @@ Xray.outbounds = {
|
||||
local finalmask = {}
|
||||
local PT = server.v2ray_protocol
|
||||
local TP = server.transport
|
||||
if server.transport == "kcp" then
|
||||
if TP == "kcp" then
|
||||
local map = {none = "none", srtp = "header-srtp", utp = "header-utp", ["wechat-video"] = "header-wechat",
|
||||
dtls = "header-dtls", wireguard = "header-wireguard", dns = "header-dns"}
|
||||
local udp = {}
|
||||
@@ -547,14 +630,36 @@ Xray.outbounds = {
|
||||
udp[#udp+1] = c
|
||||
finalmask.udp = udp
|
||||
elseif PT == "hysteria2" then
|
||||
local udp = {}
|
||||
if (server.flag_obfs == "1" and (server.obfs_type and server.obfs_type ~= "")) then
|
||||
finalmask.udp = {{
|
||||
type = server.obfs_type,
|
||||
local o = {
|
||||
type = "salamander",
|
||||
settings = server.salamander and {
|
||||
password = server.salamander
|
||||
password = server.salamander,
|
||||
packetSize = server.obfs_type == "gecko" and "512-1200" or nil
|
||||
} or nil
|
||||
}}
|
||||
}
|
||||
udp[#udp+1] = o
|
||||
end
|
||||
if server.hysteria2_realms then
|
||||
local realm = parse_realm_uri(server.hysteria2_realm_url)
|
||||
local url, stun
|
||||
if realm then
|
||||
if realm.token and realm.server_url and realm.realm_id then
|
||||
url = "realm://" .. realm.token .. "@" .. realm.server_url .. "/" .. realm.realm_id
|
||||
end
|
||||
stun = realm.stun_servers or server.hysteria2_realm_stun
|
||||
end
|
||||
local r = {
|
||||
type = "realm",
|
||||
settings = {
|
||||
url = url,
|
||||
stunServers = stun
|
||||
}
|
||||
}
|
||||
udp[#udp+1] = r
|
||||
end
|
||||
finalmask.udp = udp
|
||||
local up = tonumber(server.uplink_capacity) or 0
|
||||
local down = tonumber(server.downlink_capacity) or 0
|
||||
finalmask.quicParams = {
|
||||
@@ -642,7 +747,6 @@ Xray.outbounds = {
|
||||
end)(),
|
||||
sockopt = {
|
||||
mark = 255,
|
||||
domainStrategy = server.domain_strategy or "UseIP",
|
||||
tcpFastOpen = (function()
|
||||
if server.transport == "xhttp" then
|
||||
return (server.fast_open == "1") and true or false
|
||||
@@ -670,18 +774,24 @@ Xray.outbounds = {
|
||||
}
|
||||
}
|
||||
|
||||
table.insert(Xray.outbounds, {
|
||||
protocol = "freedom",
|
||||
tag = "direct",
|
||||
settings = {
|
||||
domainStrategy = server.domain_strategy or "UseIP" -- 可根据需要改为 direct_dns_query_strategy
|
||||
},
|
||||
streamSettings = {
|
||||
sockopt = {
|
||||
mark = 255
|
||||
if xray_builtin_dns then
|
||||
table.insert(Xray.outbounds, {
|
||||
protocol = "dns",
|
||||
tag = "builtin-dns-out",
|
||||
settings = {
|
||||
network = "tcp",
|
||||
address = xray_builtin_dns.address,
|
||||
port = xray_builtin_dns.port
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
Xray.routing = Xray.routing or {}
|
||||
Xray.routing.rules = Xray.routing.rules or {}
|
||||
table.insert(Xray.routing.rules, {
|
||||
type = "field",
|
||||
inboundTag = { "builtin-dns-in" },
|
||||
outboundTag = "builtin-dns-out"
|
||||
})
|
||||
end
|
||||
|
||||
-- 添加带有 fragment 设置的 dialerproxy 配置
|
||||
if xray_fragment.fragment ~= "0" or (xray_fragment.noise ~= "0" and xray_noise.enabled ~= "0") then
|
||||
@@ -712,121 +822,6 @@ if xray_fragment.fragment ~= "0" or (xray_fragment.noise ~= "0" and xray_noise.e
|
||||
})
|
||||
end
|
||||
|
||||
-- Xray DNS 解析配置
|
||||
if datatypes.hostname(server.server) and server.domain_resolver and (server.domain_resolver_dns or server.domain_resolver_dns_https) then
|
||||
-- 解析 DNS 服务器配置
|
||||
local dns_proto = server.domain_resolver
|
||||
local config_address
|
||||
local config_port
|
||||
if dns_proto == "https" then
|
||||
local _a = parseURL(server.domain_resolver_dns_https)
|
||||
if _a then
|
||||
config_address = server.domain_resolver_dns_https
|
||||
config_port = _a.port or 443
|
||||
if _a.hostname and datatypes.hostname(_a.hostname) then
|
||||
GLOBAL.DNS_HOSTNAME[_a.hostname] = true
|
||||
end
|
||||
end
|
||||
else
|
||||
local server_address = server.domain_resolver_dns
|
||||
config_port = 53
|
||||
local parts = split(server_address, ":")
|
||||
if #parts > 1 then
|
||||
server_address = parts[1]
|
||||
config_port = tonumber(parts[#parts])
|
||||
end
|
||||
config_address = server_address
|
||||
if dns_proto == "tcp" then
|
||||
config_address = dns_proto .. "://" .. server_address .. ":" .. config_port
|
||||
end
|
||||
end
|
||||
|
||||
-- 存入 GLOBAL.DNS_SERVER(去重)
|
||||
local dns_key = dns_proto .. "|" .. config_address .. "|" .. tostring(config_port)
|
||||
if not GLOBAL.DNS_SERVER[dns_key] then
|
||||
GLOBAL.DNS_SERVER[dns_key] = {
|
||||
tag = "dns-node-" .. node_id,
|
||||
address = config_address,
|
||||
port = config_port,
|
||||
finalQuery = true,
|
||||
disableCache = false,
|
||||
serveStale = true,
|
||||
serveExpiredTTL = 30,
|
||||
domains = {}
|
||||
}
|
||||
end
|
||||
|
||||
-- 添加当前节点域名到该 DNS 服务器的 domains 列表
|
||||
local domain = "full:" .. server.server
|
||||
local exists
|
||||
for _, d in ipairs(GLOBAL.DNS_SERVER[dns_key].domains) do
|
||||
if d == domain then exists = true; break end
|
||||
end
|
||||
if not exists then
|
||||
table.insert(GLOBAL.DNS_SERVER[dns_key].domains, domain)
|
||||
end
|
||||
GLOBAL.VPS_EXCLUDE[server.server] = true
|
||||
|
||||
-- 构建 Xray.dns
|
||||
local dns_servers = { "localhost" }
|
||||
for key, dns_server in pairs(GLOBAL.DNS_SERVER) do
|
||||
table.insert(dns_servers, {
|
||||
tag = dns_server.tag,
|
||||
address = dns_server.address,
|
||||
port = dns_server.port,
|
||||
domains = dns_server.domains,
|
||||
finalQuery = dns_server.finalQuery,
|
||||
serveStale = dns_server.serveStale,
|
||||
serveExpiredTTL = dns_server.serveExpiredTTL,
|
||||
disableCache = dns_server.disableCache
|
||||
})
|
||||
end
|
||||
Xray.dns = {
|
||||
servers = dns_servers,
|
||||
disableFallback = true,
|
||||
disableFallbackIfMatch = true,
|
||||
useSystemHosts = true,
|
||||
queryStrategy = "UseIP",
|
||||
disableCache = false,
|
||||
tag = "dns-global" -- 用于 routing
|
||||
}
|
||||
end
|
||||
|
||||
-- 代理出站的 tag(与 outbound 中的 tag 保持一致)
|
||||
local proxy_tag = (remarks ~= nil and remarks ~= "") and (node_id .. ":" .. remarks) or node_id
|
||||
-- 构建 routing 规则表
|
||||
local routing_rules = {}
|
||||
-- 1. 为每个自定义 DNS 服务器添加直连规则(inboundTag 匹配 dns-node-xxx)
|
||||
if GLOBAL.DNS_SERVER and next(GLOBAL.DNS_SERVER) then
|
||||
for _, dns_server in pairs(GLOBAL.DNS_SERVER) do
|
||||
table.insert(routing_rules, {
|
||||
inboundTag = { dns_server.tag },
|
||||
outboundTag = "direct"
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
-- 2. 添加全局 DNS 直连规则(需要 Xray.dns 中已设置 tag = "dns-global")
|
||||
if Xray.dns and Xray.dns.tag then
|
||||
table.insert(routing_rules, {
|
||||
inboundTag = { "dns-global" },
|
||||
outboundTag = "direct"
|
||||
})
|
||||
end
|
||||
|
||||
-- 3. 添加默认规则:所有 TCP/UDP 流量走代理
|
||||
table.insert(routing_rules, {
|
||||
network = "tcp,udp",
|
||||
ruleTag = "default",
|
||||
outboundTag = proxy_tag
|
||||
})
|
||||
|
||||
-- 构建 routing 对象
|
||||
Xray.routing = {
|
||||
rules = routing_rules,
|
||||
domainStrategy = "AsIs"
|
||||
}
|
||||
|
||||
local cipher = "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA:AES128-SHA:AES256-SHA:DES-CBC3-SHA"
|
||||
local cipher13 = "TLS_AES_128_GCM_SHA256:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_256_GCM_SHA384"
|
||||
local trojan = {
|
||||
@@ -874,7 +869,7 @@ local trojan = {
|
||||
}
|
||||
}
|
||||
local naiveproxy = {
|
||||
proxy = (server.username and server.password and server.server and server.server_port) and "https://" .. server.username .. ":" .. server.password .. "@" .. server.server .. ":" .. server.server_port,
|
||||
proxy = (server.username and server.password and server.server and server.server_port) and "https://" .. server.username .. ":" .. server.password .. "@" .. format_host_port(server.server, server.server_port),
|
||||
listen = (proto == "redir") and "redir" .. "://0.0.0.0:" .. tonumber(local_port) or "socks" .. "://0.0.0.0:" .. tonumber(local_port),
|
||||
["insecure-concurrency"] = tonumber(server.concurrency) or 1
|
||||
}
|
||||
@@ -895,16 +890,16 @@ local hysteria2 = {
|
||||
server.server_port and
|
||||
(
|
||||
server.port_range and
|
||||
(server.server .. ":" .. server.server_port .. "," .. string.gsub(server.port_range, ":", "-"))
|
||||
(format_host_port(server.server, server.server_port) .. "," .. string.gsub(server.port_range, ":", "-"))
|
||||
or
|
||||
(server.server .. ":" .. server.server_port)
|
||||
(format_host_port(server.server, server.server_port))
|
||||
)
|
||||
or
|
||||
(
|
||||
server.port_range and
|
||||
server.server .. ":" .. string.gsub(server.port_range, ":", "-")
|
||||
format_host(server.server) .. ":" .. string.gsub(server.port_range, ":", "-")
|
||||
or
|
||||
server.server and server.server .. ":443"
|
||||
server.server and format_host_port(server.server, "443")
|
||||
)
|
||||
),
|
||||
bandwidth = (server.uplink_capacity or server.downlink_capacity) and {
|
||||
@@ -1003,7 +998,7 @@ local hysteria2 = {
|
||||
}
|
||||
local shadowtls = {
|
||||
client = {
|
||||
server_addr = server.server_port and server.server .. ":" .. server.server_port or nil,
|
||||
server_addr = server.server_port and format_host_port(server.server, server.server_port) or nil,
|
||||
listen = "127.0.0.1:" .. tonumber(local_port),
|
||||
tls_names = server.shadowtls_sni,
|
||||
password = server.password
|
||||
@@ -1017,7 +1012,7 @@ local chain_sslocal = {
|
||||
locals = local_port ~= "0" and {
|
||||
{
|
||||
local_address = "0.0.0.0",
|
||||
local_port = (chain_local_port == "0" and tonumber(server.local_port) or tonumber(chain_local_port)),
|
||||
local_port = (chain_local_port == "0" and effective_node_local_port or tonumber(chain_local_port)),
|
||||
mode = (proto:find("tcp,udp") and "tcp_and_udp") or proto .. "_only",
|
||||
protocol = "redir",
|
||||
tcp_redir = "redirect",
|
||||
@@ -1046,7 +1041,7 @@ local chain_sslocal = {
|
||||
local chain_vmess = {
|
||||
inbounds = (local_port ~= "0") and {
|
||||
{
|
||||
port = (chain_local_port == "0" and tonumber(server.local_port) or tonumber(chain_local_port)),
|
||||
port = (chain_local_port == "0" and effective_node_local_port or tonumber(chain_local_port)),
|
||||
protocol = "dokodemo-door",
|
||||
settings = {
|
||||
network = proto,
|
||||
@@ -1082,7 +1077,7 @@ local chain_vmess = {
|
||||
}
|
||||
local tuic = {
|
||||
relay = {
|
||||
server = server.server_port and server.server .. ":" .. server.server_port,
|
||||
server = server.server_port and format_host_port(server.server, server.server_port),
|
||||
ip = server.tuic_ip,
|
||||
uuid = server.tuic_uuid,
|
||||
password = server.tuic_passwd,
|
||||
|
||||
Reference in new issue
Block a user