luci-app-ssr-plus: bump to 183-5
Signed-off-by: CN_SZTL <cnsztl@project-openwrt.eu.org> Co-authored-by: Mattraks <16359027+Mattraks@users.noreply.github.com> Co-authored-by: lean <coolsnowwolf@gmail.com>
This commit is contained in:
parent
dca292d0f1
commit
70d79f7c79
@ -1,8 +1,8 @@
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=luci-app-ssr-plus
|
||||
PKG_VERSION:=182
|
||||
PKG_RELEASE:=9
|
||||
PKG_VERSION:=183
|
||||
PKG_RELEASE:=5
|
||||
|
||||
define Package/$(PKG_NAME)/conffiles
|
||||
/etc/config/shadowsocksr
|
||||
@ -41,11 +41,7 @@ config PACKAGE_$(PKG_NAME)_INCLUDE_Simple_Obfs
|
||||
|
||||
config PACKAGE_$(PKG_NAME)_INCLUDE_Trojan
|
||||
bool "Include Trojan"
|
||||
default y if i386||arm
|
||||
|
||||
config PACKAGE_$(PKG_NAME)_INCLUDE_Trojan_Go
|
||||
bool "Include Trojan-Go"
|
||||
default y if x86_64||aarch64
|
||||
default y if arm||mipsel
|
||||
|
||||
config PACKAGE_$(PKG_NAME)_INCLUDE_V2ray
|
||||
bool "Include V2ray"
|
||||
@ -69,7 +65,6 @@ PKG_CONFIG_DEPENDS:= \
|
||||
CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_ShadowsocksR_Server \
|
||||
CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_Simple_Obfs \
|
||||
CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_Trojan \
|
||||
CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_Trojan_Go \
|
||||
CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_V2ray \
|
||||
CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_V2ray_Plugin \
|
||||
CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_Xray
|
||||
@ -77,8 +72,8 @@ PKG_CONFIG_DEPENDS:= \
|
||||
LUCI_TITLE:=SS/SSR/V2Ray/Trojan/NaiveProxy/Socks5/Tun LuCI interface
|
||||
LUCI_PKGARCH:=all
|
||||
LUCI_DEPENDS:=+coreutils +coreutils-base64 +dns2socks +dnsmasq-full +ipset +ip-full \
|
||||
+iptables-mod-tproxy +lua +libuci-lua +microsocks +pdnsd-alt +tcping +resolveip \
|
||||
+shadowsocksr-libev-alt +wget-ssl \
|
||||
+iptables-mod-tproxy +ipt2socks-alt +lua +libuci-lua +microsocks +pdnsd-alt +tcping \
|
||||
+resolveip +shadowsocksr-libev-alt +wget-ssl \
|
||||
+PACKAGE_$(PKG_NAME)_INCLUDE_Kcptun:kcptun-client \
|
||||
+PACKAGE_$(PKG_NAME)_INCLUDE_NaiveProxy:naiveproxy \
|
||||
+PACKAGE_$(PKG_NAME)_INCLUDE_Redsocks2:redsocks2 \
|
||||
@ -89,9 +84,8 @@ LUCI_DEPENDS:=+coreutils +coreutils-base64 +dns2socks +dnsmasq-full +ipset +ip-f
|
||||
+PACKAGE_$(PKG_NAME)_INCLUDE_Simple_Obfs:simple-obfs \
|
||||
+PACKAGE_$(PKG_NAME)_INCLUDE_Trojan:trojan \
|
||||
+PACKAGE_$(PKG_NAME)_INCLUDE_Trojan:ipt2socks \
|
||||
+PACKAGE_$(PKG_NAME)_INCLUDE_Trojan_Go:trojan-go \
|
||||
+PACKAGE_$(PKG_NAME)_INCLUDE_V2ray_Plugin:v2ray-plugin \
|
||||
+PACKAGE_$(PKG_NAME)_INCLUDE_V2ray:v2ray \
|
||||
+PACKAGE_$(PKG_NAME)_INCLUDE_V2ray_Plugin:v2ray-plugin \
|
||||
+PACKAGE_$(PKG_NAME)_INCLUDE_Xray:xray
|
||||
|
||||
include $(TOPDIR)/feeds/luci/luci.mk
|
||||
|
||||
@ -65,6 +65,24 @@ local encrypt_methods_ss = {
|
||||
"chacha20-ietf"
|
||||
}
|
||||
|
||||
local encrypt_methods_v2ray_ss = {
|
||||
-- xray_ss
|
||||
"none",
|
||||
"plain",
|
||||
"aes-128-cfb",
|
||||
"aes-256-cfb",
|
||||
"chacha20",
|
||||
"chacha20-ietf",
|
||||
-- aead
|
||||
"aes-128-gcm",
|
||||
"aes-256-gcm",
|
||||
"chacha20-poly1305",
|
||||
"chacha20-ietf-poly1305",
|
||||
"aead_aes_128_gcm",
|
||||
"aead_aes_256_gcm",
|
||||
"aead_chacha20_poly1305"
|
||||
}
|
||||
|
||||
local protocol = {
|
||||
-- ssr
|
||||
"origin",
|
||||
@ -132,10 +150,9 @@ if is_finded("ss-redir") then
|
||||
o:value("ss", translate("Shadowsocks New Version"))
|
||||
end
|
||||
if is_finded("xray") or is_finded("v2ray") then
|
||||
o:value("vmess", translate("Vmess"))
|
||||
o:value("vless", translate("VLESS"))
|
||||
o:value("v2ray", translate("V2Ray/XRay"))
|
||||
end
|
||||
if is_finded("trojan")then
|
||||
if is_finded("trojan") then
|
||||
o:value("trojan", translate("Trojan"))
|
||||
end
|
||||
if is_finded("trojan-go") then
|
||||
@ -145,10 +162,13 @@ end
|
||||
if is_finded("naive") then
|
||||
o:value("naiveproxy", translate("NaiveProxy"))
|
||||
end
|
||||
if is_finded("redsocks2") then
|
||||
if is_finded("ipt2socks-alt") or is_finded("ipt2socks") then
|
||||
o:value("socks5", translate("Socks5"))
|
||||
end
|
||||
if is_finded("redsocks2") then
|
||||
o:value("tun", translate("Network Tunnel"))
|
||||
end
|
||||
|
||||
o.description = translate("Using incorrect encryption mothod may causes service fail to start")
|
||||
|
||||
o = s:option(Value, "alias", translate("Alias(optional)"))
|
||||
@ -162,13 +182,21 @@ end
|
||||
o:depends("type", "tun")
|
||||
o.description = translate("Redirect traffic to this network interface")
|
||||
|
||||
o = s:option(ListValue, "v2ray_protocol", translate("V2Ray/XRay protocol"))
|
||||
o:value("vmess", translate("VMess"))
|
||||
o:value("vless", translate("VLESS"))
|
||||
o:value("trojan", translate("Trojan"))
|
||||
o:value("shadowsocks", translate("Shadowsocks"))
|
||||
o:value("socks", translate("Socks"))
|
||||
o:value("http", translate("HTTP"))
|
||||
o:depends("type", "v2ray")
|
||||
|
||||
o = s:option(Value, "server", translate("Server Address"))
|
||||
o.datatype = "host"
|
||||
o.rmempty = false
|
||||
o:depends("type", "ssr")
|
||||
o:depends("type", "ss")
|
||||
o:depends("type", "vmess")
|
||||
o:depends("type", "vless")
|
||||
o:depends("type", "v2ray")
|
||||
o:depends("type", "trojan")
|
||||
o:depends("type", "naiveproxy")
|
||||
o:depends("type", "socks5")
|
||||
@ -179,8 +207,7 @@ o.datatype = "port"
|
||||
o.rmempty = false
|
||||
o:depends("type", "ssr")
|
||||
o:depends("type", "ss")
|
||||
o:depends("type", "vmess")
|
||||
o:depends("type", "vless")
|
||||
o:depends("type", "v2ray")
|
||||
o:depends("type", "trojan")
|
||||
o:depends("type", "naiveproxy")
|
||||
o:depends("type", "socks5")
|
||||
@ -190,11 +217,15 @@ o = s:option(Flag, "auth_enable", translate("Enable Authentication"))
|
||||
o.rmempty = false
|
||||
o.default = "0"
|
||||
o:depends("type", "socks5")
|
||||
o:depends({type = "v2ray", v2ray_protocol = "http"})
|
||||
o:depends({type = "v2ray", v2ray_protocol = "socks"})
|
||||
|
||||
o = s:option(Value, "username", translate("Username"))
|
||||
o.rmempty = true
|
||||
o:depends("type", "naiveproxy")
|
||||
o:depends({type = "socks5", auth_enable = true})
|
||||
o:depends({type = "v2ray", v2ray_protocol = "http", auth_enable = true})
|
||||
o:depends({type = "v2ray", v2ray_protocol = "socks", auth_enable = true})
|
||||
|
||||
o = s:option(Value, "password", translate("Password"))
|
||||
o.password = true
|
||||
@ -204,6 +235,10 @@ o:depends("type", "ss")
|
||||
o:depends("type", "trojan")
|
||||
o:depends("type", "naiveproxy")
|
||||
o:depends({type = "socks5", auth_enable = true})
|
||||
o:depends({type = "v2ray", v2ray_protocol = "http", auth_enable = true})
|
||||
o:depends({type = "v2ray", v2ray_protocol = "socks", auth_enable = true})
|
||||
o:depends({type = "v2ray", v2ray_protocol = "shadowsocks"})
|
||||
o:depends({type = "v2ray", v2ray_protocol = "trojan"})
|
||||
o:depends("type", "trojan-go")
|
||||
|
||||
o = s:option(ListValue, "encrypt_method", translate("Encrypt Method"))
|
||||
@ -220,6 +255,13 @@ end
|
||||
o.rmempty = true
|
||||
o:depends("type", "ss")
|
||||
|
||||
o = s:option(ListValue, "encrypt_method_v2ray_ss", translate("Encrypt Method"))
|
||||
for _, v in ipairs(encrypt_methods_v2ray_ss) do
|
||||
o:value(v)
|
||||
end
|
||||
o.rmempty = true
|
||||
o:depends({type = "v2ray", v2ray_protocol = "shadowsocks"})
|
||||
|
||||
-- Shadowsocks Plugin
|
||||
o = s:option(ListValue, "plugin", translate("Obfs"))
|
||||
o:value("none", translate("None"))
|
||||
@ -262,20 +304,20 @@ o = s:option(Value, "alter_id", translate("AlterId"))
|
||||
o.datatype = "port"
|
||||
o.default = 16
|
||||
o.rmempty = true
|
||||
o:depends("type", "vmess")
|
||||
o:depends({type = "v2ray", v2ray_protocol = "vmess"})
|
||||
|
||||
-- VmessId
|
||||
o = s:option(Value, "vmess_id", translate("Vmess/VLESS ID (UUID)"))
|
||||
o.rmempty = true
|
||||
o.default = uuid
|
||||
o:depends("type", "vmess")
|
||||
o:depends("type", "vless")
|
||||
o:depends({type = "v2ray", v2ray_protocol = "vmess"})
|
||||
o:depends({type = "v2ray", v2ray_protocol = "vless"})
|
||||
|
||||
-- VLESS Encryption
|
||||
o = s:option(Value, "vless_encryption", translate("VLESS Encryption"))
|
||||
o.rmempty = true
|
||||
o.default = "none"
|
||||
o:depends("type", "vless")
|
||||
o:depends({type = "v2ray", v2ray_protocol = "vless"})
|
||||
|
||||
-- 加密方式
|
||||
o = s:option(ListValue, "security", translate("Encrypt Method"))
|
||||
@ -283,7 +325,7 @@ for _, v in ipairs(securitys) do
|
||||
o:value(v, v:upper())
|
||||
end
|
||||
o.rmempty = true
|
||||
o:depends("type", "vmess")
|
||||
o:depends({type = "v2ray", v2ray_protocol = "vmess"})
|
||||
|
||||
-- 传输协议
|
||||
o = s:option(ListValue, "transport", translate("Transport"))
|
||||
@ -293,8 +335,7 @@ o:value("ws", "WebSocket")
|
||||
o:value("h2", "HTTP/2")
|
||||
o:value("quic", "QUIC")
|
||||
o.rmempty = true
|
||||
o:depends("type", "vmess")
|
||||
o:depends("type", "vless")
|
||||
o:depends("type", "v2ray")
|
||||
|
||||
trojan_transport = s:option(ListValue, "trojan_transport", translate("Transport"))
|
||||
trojan_transport:value("original", "Original")
|
||||
@ -469,8 +510,8 @@ o:depends("ss_aead", "1")
|
||||
o = s:option(Flag, "tls", translate("TLS"))
|
||||
o.rmempty = true
|
||||
o.default = "0"
|
||||
o:depends("type", "vmess")
|
||||
o:depends({type = "vless", xtls = false})
|
||||
o:depends({type = "v2ray", xtls = false})
|
||||
-- o:depends({type = "v2ray", v2ray_protocol = "vless", xtls = false})
|
||||
o:depends("type", "trojan")
|
||||
o:depends("type", "trojan-go")
|
||||
|
||||
@ -479,7 +520,10 @@ if is_finded("xray") then
|
||||
o = s:option(Flag, "xtls", translate("XTLS"))
|
||||
o.rmempty = true
|
||||
o.default = "0"
|
||||
o:depends({type = "vless", transport = "tcp", tls = false})
|
||||
o:depends({type = "v2ray", v2ray_protocol = "vless", transport = "tcp", tls = false})
|
||||
o:depends({type = "v2ray", v2ray_protocol = "vless", transport = "kcp", tls = false})
|
||||
o:depends({type = "v2ray", v2ray_protocol = "trojan", transport = "tcp", tls = false})
|
||||
o:depends({type = "v2ray", v2ray_protocol = "trojan", transport = "kcp", tls = false})
|
||||
end
|
||||
|
||||
-- Flow
|
||||
@ -522,8 +566,7 @@ o.description = translate("If true, allowss insecure connection at TLS client, e
|
||||
-- [[ Mux ]]--
|
||||
o = s:option(Flag, "mux", translate("Mux"))
|
||||
o.rmempty = false
|
||||
o:depends("type", "vmess")
|
||||
o:depends({type = "vless", xtls = false})
|
||||
o:depends({type = "v2ray", xtls = false})
|
||||
|
||||
o = s:option(Value, "concurrency", translate("Concurrency"))
|
||||
o.datatype = "uinteger"
|
||||
@ -537,10 +580,10 @@ o.rmempty = true
|
||||
o.default = "0"
|
||||
o:depends({type = "trojan", tls = true, insecure = false})
|
||||
o:depends({type = "trojan-go", tls = true, insecure = false})
|
||||
o:depends({type = "vmess", tls = true, insecure = false})
|
||||
o:depends({type = "vless", tls = true, insecure = false})
|
||||
o:depends({type = "vmess", xtls = true, insecure = false})
|
||||
o:depends({type = "vless", xtls = true, insecure = false})
|
||||
o:depends({type = "v2ray", v2ray_protocol = "vmess", tls = true, insecure = false})
|
||||
o:depends({type = "v2ray", v2ray_protocol = "vless", tls = true, insecure = false})
|
||||
o:depends({type = "v2ray", v2ray_protocol = "vmess", xtls = true, insecure = false})
|
||||
o:depends({type = "v2ray", v2ray_protocol = "vless", xtls = true, insecure = false})
|
||||
o.description = translate("If you have a self-signed certificate,please check the box")
|
||||
|
||||
o = s:option(DummyValue, "upload", translate("Upload"))
|
||||
|
||||
@ -131,7 +131,9 @@ function import_ssr_url(btn, urlname, sid) {
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.encrypt_method_ss')[0].value = method || "";
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.plugin')[0].value = plugin || "none";
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.plugin')[0].dispatchEvent(event);
|
||||
if (plugin != undefined) {
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.plugin_opts')[0].value = pluginOpts || "";
|
||||
}
|
||||
if (param != undefined) {
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.alias')[0].value = decodeURI(param);
|
||||
}
|
||||
@ -141,7 +143,6 @@ function import_ssr_url(btn, urlname, sid) {
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.type')[0].value = ssu[0];
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.type')[0].dispatchEvent(event);
|
||||
var team = sstr.split('@');
|
||||
console.log(param);
|
||||
var part1 = team[0].split(':');
|
||||
var part2 = team[1].split(':');
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.server')[0].value = part2[0];
|
||||
@ -196,8 +197,10 @@ function import_ssr_url(btn, urlname, sid) {
|
||||
url0 = ssu[1]
|
||||
}
|
||||
var sstr = url0;
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.type')[0].value = ssu[0];
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.type')[0].value = "v2ray";
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.type')[0].dispatchEvent(event);
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.v2ray_protocol')[0].value = "trojan";
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.v2ray_protocol')[0].dispatchEvent(event);
|
||||
var team = sstr.split('@');
|
||||
var password = team[0]
|
||||
var serverPart = team[1].split(':');
|
||||
@ -279,8 +282,10 @@ function import_ssr_url(btn, urlname, sid) {
|
||||
case "vmess":
|
||||
var sstr = b64DecodeUnicode(ssu[1]);
|
||||
var ploc = sstr.indexOf("/?");
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.type')[0].value = ssu[0];
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.type')[0].value = "v2ray";
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.type')[0].dispatchEvent(event);
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.v2ray_protocol')[0].value = "vmess";
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.v2ray_protocol')[0].dispatchEvent(event);
|
||||
var url0, param = "";
|
||||
if (ploc > 0) {
|
||||
url0 = sstr.substr(0, ploc);
|
||||
@ -337,8 +342,10 @@ function import_ssr_url(btn, urlname, sid) {
|
||||
url0 = ssu[1]
|
||||
}
|
||||
var sstr = url0;
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.type')[0].value = ssu[0];
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.type')[0].value = "v2ray";
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.type')[0].dispatchEvent(event);
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.v2ray_protocol')[0].value = "vless";
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.v2ray_protocol')[0].dispatchEvent(event);
|
||||
var team = sstr.split('@');
|
||||
var uuid = team[0]
|
||||
var serverPart = team[1].split(':');
|
||||
|
||||
@ -679,6 +679,9 @@ msgstr "禁止连接的域名"
|
||||
msgid "Obfuscate password (optional)"
|
||||
msgstr "混淆密码(可选)"
|
||||
|
||||
msgid "V2Ray/XRay protocol"
|
||||
msgstr "V2Ray/XRay 协议"
|
||||
|
||||
msgid "Camouflage Type"
|
||||
msgstr "伪装类型"
|
||||
|
||||
|
||||
@ -84,7 +84,7 @@ get_host_ip() {
|
||||
}
|
||||
|
||||
clean_log() {
|
||||
logsnum=$(cat $LOG_FILE 2>/dev/null | wc -l)
|
||||
local logsnum=$(cat $LOG_FILE 2>/dev/null | wc -l)
|
||||
[ "$logsnum" -gt 1000 ] && {
|
||||
echo "$(date "+%Y-%m-%d %H:%M:%S") 日志文件过长,清空处理!" >$LOG_FILE
|
||||
}
|
||||
@ -139,8 +139,8 @@ _exit() {
|
||||
}
|
||||
|
||||
first_type() {
|
||||
local path_name=${1}
|
||||
type -t -p "/bin/${path_name}" -p "${TMP_BIN_PATH}/${path_name}" -p "${path_name}" "$@" | head -n1
|
||||
local ret=$(which "/bin/${path_name}" "${TMP_BIN_PATH}/${path_name}" "${path_name}" "$@" | head -n1)
|
||||
echo ${ret:=$@}
|
||||
}
|
||||
|
||||
ln_start_bin() {
|
||||
@ -152,10 +152,14 @@ ln_start_bin() {
|
||||
ln -s "${file_func}" "${TMP_BIN_PATH}/${ln_name}" >/dev/null 2>&1
|
||||
file_func="${TMP_BIN_PATH}/${ln_name}"
|
||||
}
|
||||
[ -x "${file_func}" ] || echolog " - $(readlink ${file_func}) 没有执行权限,无法启动:${file_func} $*"
|
||||
[ -x "${file_func}" ] || echolog "$(readlink ${file_func}) 没有执行权限,无法启动:${file_func} $*"
|
||||
fi
|
||||
#echo "${file_func} $*" >&2
|
||||
[ -n "${file_func}" ] || echolog " - 找不到 ${ln_name},无法启动..."
|
||||
[ -x "${file_func}" ] || {
|
||||
echolog "找不到 ${file_func},无法启动..."
|
||||
echolog "-----------end------------"
|
||||
_exit 2
|
||||
}
|
||||
${file_func:-echolog " - ${ln_name}"} "$@" >/dev/null 2>&1 &
|
||||
}
|
||||
|
||||
@ -279,7 +283,7 @@ gen_config_file() { #server1 type2 code3 local_port4 socks_port5 threads5
|
||||
lua /usr/share/shadowsocksr/gen_config.lua $1 $mode $tmp_port >$shunt_dns_config_file
|
||||
fi
|
||||
;;
|
||||
vmess | vless)
|
||||
v2ray)
|
||||
lua /usr/share/shadowsocksr/gen_config.lua $1 $mode $4 $5 >$config_file
|
||||
;;
|
||||
trojan)
|
||||
@ -351,7 +355,7 @@ start_udp() {
|
||||
ln_start_bin $(first_type ${type}-redir) ${type}-redir -c $udp_config_file -U
|
||||
echolog "UDP TPROXY Relay:$(get_name $type) Started!"
|
||||
;;
|
||||
vmess | vless)
|
||||
v2ray)
|
||||
gen_config_file $UDP_RELAY_SERVER $type 2 $tmp_udp_port
|
||||
ln_start_bin $(first_type xray v2ray) v2ray -config $udp_config_file
|
||||
echolog "UDP TPROXY Relay:$($(first_type "xray" "v2ray") -version | head -1) Started!"
|
||||
@ -359,7 +363,7 @@ start_udp() {
|
||||
trojan) #client
|
||||
gen_config_file $UDP_RELAY_SERVER $type 2 $tmp_udp_local_port
|
||||
ln_start_bin $(first_type trojan-go trojan) $type --config $udp_config_file
|
||||
ln_start_bin $(first_type ipt2socks) ipt2socks -U -b 0.0.0.0 -4 -s 127.0.0.1 -p $tmp_udp_local_port -l $tmp_udp_port
|
||||
ln_start_bin $(first_type ipt2socks-alt ipt2socks) ipt2socks -U -b 0.0.0.0 -4 -s 127.0.0.1 -p $tmp_udp_local_port -l $tmp_udp_port
|
||||
echolog "UDP TPROXY Relay:$($(first_type trojan-go trojan) --version 2>&1 | head -1) Started!"
|
||||
;;
|
||||
trojan-go)
|
||||
@ -376,7 +380,7 @@ start_udp() {
|
||||
if [ "$(uci_get_by_name $UDP_RELAY_SERVER auth_enable 0)" == "1" ]; then
|
||||
local auth="-a $(uci_get_by_name $UDP_RELAY_SERVER username) -k $(uci_get_by_name $UDP_RELAY_SERVER password)"
|
||||
fi
|
||||
ln_start_bin $(first_type ipt2socks) ipt2socks $udp_config_file -U -4 -s $(uci_get_by_name $UDP_RELAY_SERVER server) -p $(uci_get_by_name $UDP_RELAY_SERVER server_port) -l $tmp_udp_port $auth
|
||||
ln_start_bin $(first_type ipt2socks-alt ipt2socks) ipt2socks $udp_config_file -U -4 -s $(uci_get_by_name $UDP_RELAY_SERVER server) -p $(uci_get_by_name $UDP_RELAY_SERVER server_port) -l $tmp_udp_port $auth
|
||||
#gen_config_file $UDP_RELAY_SERVER $type 2 $tmp_udp_port
|
||||
#ln_start_bin $(first_type redsocks2) redsocks2 -c $udp_config_file
|
||||
echolog "UDP TPROXY Relay:Socks5 REDIRECT/TPROXY Started!"
|
||||
@ -404,7 +408,7 @@ start_shunt() {
|
||||
ln_start_bin $(first_type dns2socks) dns2socks 127.0.0.1:$tmp_port 8.8.8.8:53 127.0.0.1:$tmp_shunt_dns_port -q
|
||||
echolog "shunt:$(get_name $type) Started!"
|
||||
;;
|
||||
vmess | vless)
|
||||
v2ray)
|
||||
if [ -n "$tmp_local_port" ]; then
|
||||
local tmp_port=$tmp_local_port
|
||||
else
|
||||
@ -444,7 +448,7 @@ start_shunt() {
|
||||
if [ "$(uci_get_by_name $SHUNT_SERVER auth_enable 0)" == "1" ]; then
|
||||
local auth="-a $(uci_get_by_name $SHUNT_SERVER username) -k $(uci_get_by_name $SHUNT_SERVER password)"
|
||||
fi
|
||||
ln_start_bin $(first_type ipt2socks) ipt2socks $shunt_config_file -R -4 -s $(uci_get_by_name $SHUNT_SERVER server) -p $(uci_get_by_name $SHUNT_SERVER server_port) -l $tmp_shunt_port $auth
|
||||
ln_start_bin $(first_type ipt2socks-alt ipt2socks) ipt2socks $shunt_config_file -R -4 -s $(uci_get_by_name $SHUNT_SERVER server) -p $(uci_get_by_name $SHUNT_SERVER server_port) -l $tmp_shunt_port $auth
|
||||
#gen_config_file $SHUNT_SERVER $type 3 $tmp_shunt_port
|
||||
#ln_start_bin $(first_type redsocks2) redsocks2 -c $shunt_config_file
|
||||
if [ -n "$tmp_local_port" ]; then
|
||||
@ -482,7 +486,7 @@ start_local() {
|
||||
ln_start_bin $(first_type ${type}-local) ${type}-local -c $local_config_file -u
|
||||
echolog "Global_Socks5:$(get_name $type) Started!"
|
||||
;;
|
||||
vmess | vless)
|
||||
v2ray)
|
||||
if [ "$_local" == "2" ]; then
|
||||
gen_config_file $LOCAL_SERVER $type 4 0 $local_port
|
||||
ln_start_bin $(first_type xray v2ray) v2ray -config $local_config_file
|
||||
@ -544,7 +548,7 @@ Start_Run() {
|
||||
done
|
||||
echolog "Main node:$(get_name $type) $threads Threads Started!"
|
||||
;;
|
||||
vmess | vless)
|
||||
v2ray)
|
||||
gen_config_file $GLOBAL_SERVER $type 1 $tcp_port $socks_port
|
||||
ln_start_bin $(first_type xray v2ray) v2ray -config $tcp_config_file
|
||||
echolog "Main node:$($(first_type xray v2ray) -version | head -1) Started!"
|
||||
@ -563,7 +567,7 @@ Start_Run() {
|
||||
if [ "$(uci_get_by_name $GLOBAL_SERVER auth_enable 0)" == "1" ]; then
|
||||
local auth="-a $(uci_get_by_name $GLOBAL_SERVER username) -k $(uci_get_by_name $GLOBAL_SERVER password)"
|
||||
fi
|
||||
ln_start_bin $(first_type ipt2socks) ipt2socks $tcp_config_file -R -4 -j $threads -s $(uci_get_by_name $GLOBAL_SERVER server) -p $(uci_get_by_name $GLOBAL_SERVER server_port) -l $tcp_port $auth
|
||||
ln_start_bin $(first_type ipt2socks-alt ipt2socks) ipt2socks $tcp_config_file -R -4 -j $threads -s $(uci_get_by_name $GLOBAL_SERVER server) -p $(uci_get_by_name $GLOBAL_SERVER server_port) -l $tcp_port $auth
|
||||
#gen_config_file $GLOBAL_SERVER $type 1 $tcp_port
|
||||
#for i in $(seq 1 $threads); do
|
||||
# ln_start_bin $(first_type redsocks2) redsocks2 -c $tcp_config_file
|
||||
@ -598,7 +602,6 @@ load_config() {
|
||||
case "$UDP_RELAY_SERVER" in
|
||||
nil)
|
||||
mode="tcp"
|
||||
ARG_OTA="-u"
|
||||
;;
|
||||
same)
|
||||
mode="tcp,udp"
|
||||
@ -619,6 +622,7 @@ load_config() {
|
||||
ARG_UDP="-U"
|
||||
ARG_OTA="-U"
|
||||
start_udp
|
||||
ARG_OTA=""
|
||||
mode="tcp"
|
||||
fi
|
||||
;;
|
||||
|
||||
@ -26,5 +26,8 @@ touch /etc/config/shadowsocksr
|
||||
if [ ! -s "/etc/config/shadowsocksr" ]; then
|
||||
/etc/init.d/shadowsocksr reset
|
||||
fi
|
||||
sed -i "s/option type 'vmess'"/"option type 'v2ray'\n\toption v2ray_protocol 'vmess'/g" /etc/config/shadowsocksr
|
||||
sed -i "s/option type 'vless'"/"option type 'v2ray'\n\toption v2ray_protocol 'vless'/g" /etc/config/shadowsocksr
|
||||
sed -i "s/option type 'trojan'"/"option type 'v2ray'\n\toption v2ray_protocol 'trojan'/g" /etc/config/shadowsocksr
|
||||
rm -rf /tmp/luci-modulecache /tmp/luci-indexcache
|
||||
exit 0
|
||||
|
||||
@ -1,10 +1,96 @@
|
||||
local ucursor = require "luci.model.uci".cursor()
|
||||
local ucursor = require"luci.model.uci".cursor()
|
||||
local json = require "luci.jsonc"
|
||||
local server_section = arg[1]
|
||||
local proto = arg[2]
|
||||
local local_port = arg[3] or "0"
|
||||
local socks_port = arg[4] or "0"
|
||||
local server = ucursor:get_all("shadowsocksr", server_section)
|
||||
local outbound_settings = nil
|
||||
function vmess_vless()
|
||||
outbound_settings = {
|
||||
vnext = {
|
||||
{
|
||||
address = server.server,
|
||||
port = tonumber(server.server_port),
|
||||
users = {
|
||||
{
|
||||
id = server.vmess_id,
|
||||
alterId = (server.v2ray_protocol == "vmess" or not server.v2ray_protocol) and tonumber(server.alter_id) or nil,
|
||||
security = (server.v2ray_protocol == "vmess" or not server.v2ray_protocol) and server.security or nil,
|
||||
encryption = (server.v2ray_protocol == "vless") and server.vless_encryption or nil,
|
||||
flow = (server.xtls == '1') and (server.vless_flow and server.vless_flow or "xtls-rprx-splice") or nil
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
end
|
||||
function trojan_shadowsocks()
|
||||
outbound_settings = {
|
||||
servers = {
|
||||
{
|
||||
address = server.server,
|
||||
port = tonumber(server.server_port),
|
||||
password = server.password,
|
||||
method = (server.v2ray_protocol == "shadowsocks") and server.encrypt_method_v2ray_ss or nil,
|
||||
flow = (server.v2ray_protocol == "trojan") and (server.xtls == '1') and (server.vless_flow and server.vless_flow or "xtls-rprx-splice") or nil
|
||||
}
|
||||
}
|
||||
}
|
||||
end
|
||||
function socks_http()
|
||||
outbound_settings = {
|
||||
--
|
||||
servers = {
|
||||
{
|
||||
--
|
||||
address = server.server,
|
||||
port = tonumber(server.server_port),
|
||||
users = (server.auth_enable == "1") and {
|
||||
{
|
||||
--
|
||||
user = server.username,
|
||||
pass = server.password
|
||||
}
|
||||
} or nil
|
||||
}
|
||||
}
|
||||
}
|
||||
end
|
||||
local outbound = {}
|
||||
function outbound:new(o)
|
||||
o = o or {}
|
||||
setmetatable(o, self)
|
||||
self.__index = self
|
||||
return o
|
||||
end
|
||||
function outbound:handleIndex(index)
|
||||
local switch = {
|
||||
vmess = function()
|
||||
vmess_vless()
|
||||
end,
|
||||
vless = function()
|
||||
vmess_vless()
|
||||
end,
|
||||
trojan = function()
|
||||
trojan_shadowsocks()
|
||||
end,
|
||||
shadowsocks = function()
|
||||
trojan_shadowsocks()
|
||||
end,
|
||||
socks = function()
|
||||
socks_http()
|
||||
end,
|
||||
http = function()
|
||||
socks_http()
|
||||
end
|
||||
}
|
||||
if switch[index] then
|
||||
switch[index]()
|
||||
end
|
||||
end
|
||||
local settings = outbound:new()
|
||||
settings:handleIndex(server.v2ray_protocol)
|
||||
local Xray = {
|
||||
log = {
|
||||
-- error = "/var/ssrplus.log",
|
||||
@ -12,6 +98,7 @@ local Xray = {
|
||||
},
|
||||
-- 传入连接
|
||||
inbound = (local_port ~= "0") and {
|
||||
-- listening
|
||||
port = tonumber(local_port),
|
||||
protocol = "dokodemo-door",
|
||||
settings = {network = proto, followRedirect = true},
|
||||
@ -20,6 +107,7 @@ local Xray = {
|
||||
-- 开启 socks 代理
|
||||
inboundDetour = (proto:find("tcp") and socks_port ~= "0") and {
|
||||
{
|
||||
-- socks
|
||||
protocol = "socks",
|
||||
port = tonumber(socks_port),
|
||||
settings = {auth = "noauth", udp = true}
|
||||
@ -27,40 +115,28 @@ local Xray = {
|
||||
} or nil,
|
||||
-- 传出连接
|
||||
outbound = {
|
||||
protocol = server.type,
|
||||
settings = {
|
||||
vnext = {
|
||||
{
|
||||
address = server.server,
|
||||
port = tonumber(server.server_port),
|
||||
users = {
|
||||
{
|
||||
id = server.vmess_id,
|
||||
alterId = (server.type == "vmess") and tonumber(server.alter_id) or nil,
|
||||
security = (server.type == "vmess") and server.security or nil,
|
||||
encryption = (server.type == "vless") and server.vless_encryption or nil,
|
||||
flow = (server.xtls == '1') and (server.vless_flow and server.vless_flow or "xtls-rprx-splice") or nil
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
protocol = server.v2ray_protocol or "vmess",
|
||||
settings = outbound_settings,
|
||||
-- 底层传输配置
|
||||
streamSettings = {
|
||||
network = server.transport,
|
||||
security = (server.xtls == '1') and "xtls" or (server.tls == '1') and "tls" or "none",
|
||||
network = server.transport or "tcp",
|
||||
security = (server.xtls == '1') and "xtls" or (server.tls == '1') and "tls" or nil,
|
||||
tlsSettings = (server.tls == '1' and (server.insecure == "1" or server.tls_host)) and {
|
||||
-- tls
|
||||
allowInsecure = (server.insecure == "1") and true or nil,
|
||||
serverName = server.tls_host
|
||||
} or nil,
|
||||
xtlsSettings = (server.xtls == '1' and (server.insecure == "1" or server.tls_host)) and {
|
||||
-- xtls
|
||||
allowInsecure = (server.insecure == "1") and true or nil,
|
||||
serverName = server.tls_host
|
||||
} or nil,
|
||||
tcpSettings = (server.transport == "tcp" and server.tcp_guise == "http") and {
|
||||
-- tcp
|
||||
header = {
|
||||
type = server.tcp_guise,
|
||||
request = {
|
||||
-- request
|
||||
path = {server.http_path} or {"/"},
|
||||
headers = {Host = {server.http_host} or {}}
|
||||
}
|
||||
@ -78,28 +154,34 @@ local Xray = {
|
||||
seed = server.seed or nil
|
||||
} or nil,
|
||||
wsSettings = (server.transport == "ws") and (server.ws_path or server.ws_host or server.tls_host) and {
|
||||
-- ws
|
||||
path = server.ws_path,
|
||||
headers = (server.ws_host or server.tls_host) and {
|
||||
-- headers
|
||||
Host = server.ws_host or server.tls_host
|
||||
} or nil
|
||||
} or nil,
|
||||
httpSettings = (server.transport == "h2") and {
|
||||
-- h2
|
||||
path = server.h2_path or "",
|
||||
host = {server.h2_host} or nil
|
||||
} or nil,
|
||||
quicSettings = (server.transport == "quic") and {
|
||||
-- quic
|
||||
security = server.quic_security,
|
||||
key = server.quic_key,
|
||||
header = {type = server.quic_guise}
|
||||
} or nil
|
||||
},
|
||||
mux = (server.mux == "1" and server.xtls ~= "1") and {
|
||||
-- mux
|
||||
enabled = true,
|
||||
concurrency = tonumber(server.concurrency)
|
||||
} or nil
|
||||
} or nil
|
||||
}
|
||||
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 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 = {
|
||||
log_level = 3,
|
||||
@ -125,12 +207,14 @@ local trojan = {
|
||||
session_ticket = (server.tls_sessionTicket == "1") and true or false
|
||||
},
|
||||
udp_timeout = 60,
|
||||
mux = (server.mux == "1") and {
|
||||
enabled = true,
|
||||
concurrency = tonumber(server.concurrency),
|
||||
idle_timeout = 60,
|
||||
} or nil,
|
||||
mux = (server.mux == "1") and {
|
||||
-- mux
|
||||
enabled = true,
|
||||
concurrency = tonumber(server.concurrency),
|
||||
idle_timeout = 60
|
||||
} or nil,
|
||||
tcp = {
|
||||
-- tcp
|
||||
no_delay = true,
|
||||
keep_alive = true,
|
||||
reuse_port = true,
|
||||
@ -154,55 +238,74 @@ local ss = {
|
||||
fast_open = (server.fast_open == "1") and true or false,
|
||||
reuse_port = true
|
||||
}
|
||||
if server.type == "ss" then
|
||||
if server.plugin and server.plugin ~= "none" then
|
||||
ss.plugin = server.plugin
|
||||
ss.plugin_opts = server.plugin_opts or nil
|
||||
local config = {}
|
||||
function config:new(o)
|
||||
o = o or {}
|
||||
setmetatable(o, self)
|
||||
self.__index = self
|
||||
return o
|
||||
end
|
||||
function config:handleIndex(index)
|
||||
local switch = {
|
||||
ss = function()
|
||||
if server.plugin and server.plugin ~= "none" then
|
||||
ss.plugin = server.plugin
|
||||
ss.plugin_opts = server.plugin_opts or nil
|
||||
end
|
||||
print(json.stringify(ss, 1))
|
||||
end,
|
||||
ssr = function()
|
||||
ss.protocol = server.protocol
|
||||
ss.protocol_param = server.protocol_param
|
||||
ss.method = server.encrypt_method
|
||||
ss.obfs = server.obfs
|
||||
ss.obfs_param = server.obfs_param
|
||||
print(json.stringify(ss, 1))
|
||||
end,
|
||||
v2ray = function()
|
||||
print(json.stringify(Xray, 1))
|
||||
end,
|
||||
trojan = function()
|
||||
print(json.stringify(trojan, 1))
|
||||
end,
|
||||
trojan_go = function()
|
||||
trojan.ssl.cipher = server.fingerprint == nil and cipher or (server.fingerprint == "disable" and cipher13 .. ":" .. cipher or "")
|
||||
trojan.ssl.cipher_tls13 = server.fingerprint == nil and cipher13 or nil
|
||||
trojan.ssl.fingerprint = (server.fingerprint ~= nil and server.fingerprint ~= "disable") and server.fingerprint or ""
|
||||
trojan.ssl.alpn = server.trojan_transport == 'ws' and {} or {"h2", "http/1.1"}
|
||||
if server.tls ~= "1" and server.trojan_transport == "original" then
|
||||
--
|
||||
trojan.ssl = nil
|
||||
trojan.transport_plugin = server.trojan_transport == "original" and {
|
||||
enabled = server.plugin_type ~= nil,
|
||||
type = server.plugin_type or "plaintext",
|
||||
command = server.plugin_type ~= "plaintext" and server.plugin_cmd or nil,
|
||||
option = server.plugin_type ~= "plaintext" and server.plugin_option or nil,
|
||||
arg = server.plugin_type ~= "plaintext" and {server.plugin_arg} or nil,
|
||||
env = {}
|
||||
} or nil
|
||||
end
|
||||
trojan.websocket = server.trojan_transport and server.trojan_transport:find('ws') and {
|
||||
--
|
||||
enabled = true,
|
||||
path = server.ws_path or "/",
|
||||
host = server.ws_host or (server.tls_host or server.server)
|
||||
} or nil
|
||||
trojan.shadowsocks = (server.ss_aead == "1") and {
|
||||
--
|
||||
enabled = true,
|
||||
method = server.ss_aead_method or "aead_aes_128_gcm",
|
||||
password = server.ss_aead_pwd or ""
|
||||
} or nil
|
||||
print(json.stringify(trojan, 1))
|
||||
end,
|
||||
naiveproxy = function()
|
||||
print(json.stringify(naiveproxy, 1))
|
||||
end
|
||||
}
|
||||
if switch[index] then
|
||||
switch[index]()
|
||||
end
|
||||
print(json.stringify(ss, 1))
|
||||
end
|
||||
if server.type == "ssr" then
|
||||
ss.protocol = server.protocol
|
||||
ss.protocol_param = server.protocol_param
|
||||
ss.method = server.encrypt_method
|
||||
ss.obfs = server.obfs
|
||||
ss.obfs_param = server.obfs_param
|
||||
print(json.stringify(ss, 1))
|
||||
end
|
||||
if server.type == "vless" or server.type == "vmess" then
|
||||
print(json.stringify(Xray, 1))
|
||||
end
|
||||
if server.type == "trojan" then
|
||||
print(json.stringify(trojan, 1))
|
||||
end
|
||||
if server.type == "trojan-go" then
|
||||
trojan.ssl.cipher = server.fingerprint == nil and cipher or (server.fingerprint == "disable" and cipher13 .. ":" .. cipher or "")
|
||||
trojan.ssl.cipher_tls13 = server.fingerprint == nil and cipher13 or nil
|
||||
trojan.ssl.fingerprint = (server.fingerprint ~= nil and server.fingerprint ~= "disable" ) and server.fingerprint or ""
|
||||
trojan.ssl.alpn = server.trojan_transport == 'ws' and {} or {"h2", "http/1.1"}
|
||||
if server.tls ~= "1" and server.trojan_transport == "original" then
|
||||
trojan.ssl = nil
|
||||
trojan.transport_plugin = server.trojan_transport == "original" and {
|
||||
enabled = server.plugin_type ~= nil,
|
||||
type = server.plugin_type or "plaintext",
|
||||
command = server.plugin_type ~= "plaintext" and server.plugin_cmd or nil,
|
||||
option = server.plugin_type ~= "plaintext" and server.plugin_option or nil,
|
||||
arg = server.plugin_type ~= "plaintext" and { server.plugin_arg } or nil,
|
||||
env = {}
|
||||
} or nil
|
||||
end
|
||||
trojan.websocket = server.trojan_transport and server.trojan_transport:find('ws') and {
|
||||
enabled = true,
|
||||
path = server.ws_path or "/",
|
||||
host = server.ws_host or (server.tls_host or server.server)
|
||||
} or nil
|
||||
trojan.shadowsocks = (server.ss_aead == "1") and {
|
||||
enabled = true,
|
||||
method = server.ss_aead_method or "aead_aes_128_gcm",
|
||||
password = server.ss_aead_pwd or ""
|
||||
} or nil
|
||||
print(json.stringify(trojan, 1))
|
||||
end
|
||||
if server.type == "naiveproxy" then
|
||||
print(json.stringify(naiveproxy, 1))
|
||||
end
|
||||
local f = config:new()
|
||||
f:handleIndex(server.type)
|
||||
|
||||
@ -121,7 +121,8 @@ local function processData(szType, content)
|
||||
result.alias = result.alias .. base64Decode(params.remarks)
|
||||
elseif szType == 'vmess' then
|
||||
local info = jsonParse(content)
|
||||
result.type = 'vmess'
|
||||
result.type = 'v2ray'
|
||||
result.v2ray_protocol = 'vmess'
|
||||
result.server = info.add
|
||||
result.server_port = info.port
|
||||
result.transport = info.net
|
||||
@ -231,7 +232,8 @@ local function processData(szType, content)
|
||||
local userinfo = hostInfo[1]
|
||||
local password = userinfo
|
||||
result.alias = UrlDecode(alias)
|
||||
result.type = "trojan"
|
||||
result.type = "v2ray"
|
||||
result.v2ray_protocol = "trojan"
|
||||
result.server = host[1]
|
||||
-- 按照官方的建议 默认验证ssl证书
|
||||
result.insecure = "0"
|
||||
@ -276,7 +278,8 @@ local function processData(szType, content)
|
||||
params[t[1]] = t[2]
|
||||
end
|
||||
result.alias = UrlDecode(alias)
|
||||
result.type = "vless"
|
||||
result.type = 'v2ray'
|
||||
result.v2ray_protocol = 'vless'
|
||||
result.server = host[1]
|
||||
result.server_port = query[1]
|
||||
result.vmess_id = uuid
|
||||
@ -457,11 +460,11 @@ local execute = function()
|
||||
end
|
||||
else
|
||||
if not old.alias then
|
||||
if not old.server or old.server_port then
|
||||
ucic:delete(name, old['.name'])
|
||||
else
|
||||
if old.server or old.server_port then
|
||||
old.alias = old.server .. ':' .. old.server_port
|
||||
log('忽略手动添加的节点: ' .. old.alias)
|
||||
else
|
||||
ucic:delete(name, old['.name'])
|
||||
end
|
||||
else
|
||||
log('忽略手动添加的节点: ' .. old.alias)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user