1868 lines
62 KiB
Bash
1868 lines
62 KiB
Bash
#!/usr/bin/env bash
|
||
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
|
||
export PATH
|
||
|
||
#=================================================
|
||
# System Required: CentOS/Debian/Ubuntu
|
||
# Description: Shadowsocks Rust 管理脚本
|
||
# Author: 翠花
|
||
# WebSite: https://about.nange.cn
|
||
#=================================================
|
||
|
||
# 当前脚本版本号
|
||
sh_ver="1.5.3"
|
||
|
||
# Shadowsocks Rust 相关路径
|
||
SS_Folder="/etc/ss-rust"
|
||
SS_File="/usr/local/bin/ss-rust"
|
||
SS_Conf="/etc/ss-rust/config.json"
|
||
SS_Now_ver_File="/etc/ss-rust/ver.txt"
|
||
|
||
# BBR 配置文件
|
||
BBR_Local="/etc/sysctl.d/local.conf"
|
||
|
||
# Shadow TLS 相关路径
|
||
STLS_Folder="/etc/shadowtls"
|
||
STLS_File="/usr/local/bin/shadow-tls"
|
||
STLS_Conf="/etc/shadowtls/config.json"
|
||
STLS_Now_ver_File="/etc/shadowtls/ver.txt"
|
||
|
||
Green_font_prefix="\033[32m" && Red_font_prefix="\033[31m" && Green_background_prefix="\033[42;37m" && Red_background_prefix="\033[41;37m" && Font_color_suffix="\033[0m" && Yellow_font_prefix="\033[0;33m"
|
||
Info="${Green_font_prefix}[信息]${Font_color_suffix}"
|
||
Error="${Red_font_prefix}[错误]${Font_color_suffix}"
|
||
Tip="${Yellow_font_prefix}[注意]${Font_color_suffix}"
|
||
|
||
check_root(){
|
||
if [[ $EUID != 0 ]]; then
|
||
echo -e "${Error} 当前非ROOT账号(或没有ROOT权限),无法继续操作,请更换ROOT账号或使用 ${Green_background_prefix}sudo su${Font_color_suffix} 命令获取临时ROOT权限(执行后可能会提示输入当前账号的密码)。"
|
||
exit 1
|
||
fi
|
||
}
|
||
|
||
check_sys(){
|
||
if [[ -f /etc/redhat-release ]]; then
|
||
release="centos"
|
||
elif cat /etc/issue | grep -q -E -i "debian"; then
|
||
release="debian"
|
||
elif cat /etc/issue | grep -q -E -i "ubuntu"; then
|
||
release="ubuntu"
|
||
elif cat /etc/issue | grep -q -E -i "centos|red hat|redhat"; then
|
||
release="centos"
|
||
elif cat /proc/version | grep -q -E -i "debian"; then
|
||
release="debian"
|
||
elif cat /proc/version | grep -q -E -i "ubuntu"; then
|
||
release="ubuntu"
|
||
elif cat /proc/version | grep -q -E -i "centos|red hat|redhat"; then
|
||
release="centos"
|
||
fi
|
||
}
|
||
|
||
sys_arch() {
|
||
uname=$(uname -m)
|
||
if [[ "$uname" == "i686" ]] || [[ "$uname" == "i386" ]]; then
|
||
arch="i686"
|
||
elif [[ "$uname" == *"armv7"* ]] || [[ "$uname" == "armv6l" ]]; then
|
||
arch="arm"
|
||
elif [[ "$uname" == *"armv8"* ]] || [[ "$uname" == "aarch64" ]]; then
|
||
arch="aarch64"
|
||
else
|
||
arch="x86_64"
|
||
fi
|
||
}
|
||
|
||
#开启系统 TCP Fast Open
|
||
enable_systfo() {
|
||
kernel=$(uname -r | awk -F . '{print $1}')
|
||
if [ "$kernel" -ge 3 ]; then
|
||
echo 3 >/proc/sys/net/ipv4/tcp_fastopen
|
||
[[ ! -e $BBR_Local ]] && echo "fs.file-max = 51200
|
||
net.core.rmem_max = 67108864
|
||
net.core.wmem_max = 67108864
|
||
net.core.rmem_default = 65536
|
||
net.core.wmem_default = 65536
|
||
net.core.netdev_max_backlog = 4096
|
||
net.core.somaxconn = 4096
|
||
net.ipv4.tcp_syncookies = 1
|
||
net.ipv4.tcp_tw_reuse = 1
|
||
net.ipv4.tcp_tw_recycle = 0
|
||
net.ipv4.tcp_fin_timeout = 30
|
||
net.ipv4.tcp_keepalive_time = 1200
|
||
net.ipv4.ip_local_port_range = 10000 65000
|
||
net.ipv4.tcp_max_syn_backlog = 4096
|
||
net.ipv4.tcp_max_tw_buckets = 5000
|
||
net.ipv4.tcp_fastopen = 3
|
||
net.ipv4.tcp_rmem = 4096 87380 67108864
|
||
net.ipv4.tcp_wmem = 4096 65536 67108864
|
||
net.ipv4.tcp_mtu_probing = 1
|
||
net.ipv4.tcp_ecn=1
|
||
net.core.default_qdisc=fq
|
||
net.ipv4.tcp_congestion_control = bbr" >>/etc/sysctl.d/local.conf && sysctl --system >/dev/null 2>&1
|
||
else
|
||
echo -e "$Error系统内核版本过低,无法支持 TCP Fast Open !"
|
||
fi
|
||
}
|
||
|
||
check_installed_status(){
|
||
[[ ! -e ${SS_File} ]] && echo -e "${Error} Shadowsocks Rust 没有安装,请检查!" && exit 1
|
||
}
|
||
|
||
check_status(){
|
||
status=`systemctl status ss-rust | grep Active | awk '{print $3}' | cut -d "(" -f2 | cut -d ")" -f1`
|
||
}
|
||
|
||
check_new_ver(){
|
||
new_ver=$(wget -qO- https://api.github.com/repos/shadowsocks/shadowsocks-rust/releases| jq -r '[.[] | select(.prerelease == false) | select(.draft == false) | .tag_name] | .[0]')
|
||
[[ -z ${new_ver} ]] && echo -e "${Error} Shadowsocks Rust 最新版本获取失败!" && exit 1
|
||
echo -e "${Info} 检测到 Shadowsocks Rust 最新版本为 [ ${new_ver} ]"
|
||
}
|
||
|
||
check_ver_comparison(){
|
||
now_ver=$(cat ${SS_Now_ver_File})
|
||
if [[ "${now_ver}" != "${new_ver}" ]]; then
|
||
echo -e "${Info} 发现 Shadowsocks Rust 已有新版本 [ ${new_ver} ],旧版本 [ ${now_ver} ]"
|
||
read -e -p "是否更新 ? [Y/n]:" yn
|
||
[[ -z "${yn}" ]] && yn="y"
|
||
if [[ $yn == [Yy] ]]; then
|
||
check_status
|
||
# [[ "$status" == "running" ]] && systemctl stop ss-rust
|
||
\cp "${SS_Conf}" "/tmp/config.json"
|
||
# rm -rf ${SS_Folder}
|
||
download
|
||
mv -f "/tmp/config.json" "${SS_Conf}"
|
||
restart
|
||
fi
|
||
else
|
||
echo -e "${Info} 当前 Shadowsocks Rust 已是最新版本 [ ${new_ver} ] !" && exit 1
|
||
fi
|
||
}
|
||
|
||
# 官方源
|
||
stable_download() {
|
||
echo -e "${Info} 默认开始下载官方源 Shadowsocks Rust ……"
|
||
wget --no-check-certificate -N "https://github.com/shadowsocks/shadowsocks-rust/releases/download/${new_ver}/shadowsocks-${new_ver}.${arch}-unknown-linux-gnu.tar.xz"
|
||
if [[ ! -e "shadowsocks-${new_ver}.${arch}-unknown-linux-gnu.tar.xz" ]]; then
|
||
echo -e "${Error} Shadowsocks Rust 官方源下载失败!"
|
||
return 1 && exit 1
|
||
else
|
||
tar -xvf "shadowsocks-${new_ver}.${arch}-unknown-linux-gnu.tar.xz"
|
||
fi
|
||
if [[ ! -e "ssserver" ]]; then
|
||
echo -e "${Error} Shadowsocks Rust 解压失败!"
|
||
echo -e "${Error} Shadowsocks Rust 安装失败 !"
|
||
return 1 && exit 1
|
||
else
|
||
rm -rf "shadowsocks-${new_ver}.${arch}-unknown-linux-gnu.tar.xz"
|
||
chmod +x ssserver
|
||
mv -f ssserver "${SS_File}"
|
||
rm sslocal ssmanager ssservice ssurl
|
||
echo "${new_ver}" > ${SS_Now_ver_File}
|
||
|
||
echo -e "${Info} Shadowsocks Rust 主程序下载安装完毕!"
|
||
return 0
|
||
fi
|
||
}
|
||
|
||
# 备用源
|
||
backup_download() {
|
||
echo -e "${Info} 试图请求 备份源(旧版本) Shadowsocks Rust ……"
|
||
wget --no-check-certificate -N "https://raw.githubusercontent.com/xOS/Others/master/shadowsocks-rust/v1.14.1/shadowsocks-v1.14.1.${arch}-unknown-linux-gnu.tar.xz"
|
||
if [[ ! -e "shadowsocks-v1.14.1.${arch}-unknown-linux-gnu.tar.xz" ]]; then
|
||
echo -e "${Error} Shadowsocks Rust 备份源(旧版本) 下载失败!"
|
||
return 1 && exit 1
|
||
else
|
||
tar -xvf "shadowsocks-v1.14.1.${arch}-unknown-linux-gnu.tar.xz"
|
||
fi
|
||
if [[ ! -e "ssserver" ]]; then
|
||
echo -e "${Error} Shadowsocks Rust 备份源(旧版本) 解压失败 !"
|
||
echo -e "${Error} Shadowsocks Rust 备份源(旧版本) 安装失败 !"
|
||
return 1 && exit 1
|
||
else
|
||
rm -rf "shadowsocks-v1.14.1.${arch}-unknown-linux-gnu.tar.xz"
|
||
chmod +x ssserver
|
||
mv -f ssserver "${SS_File}"
|
||
rm sslocal ssmanager ssservice ssurl
|
||
echo "v1.14.1" > ${SS_Now_ver_File}
|
||
echo -e "${Info} Shadowsocks Rust 备份源(旧版本) 主程序下载安装完毕!"
|
||
return 0
|
||
fi
|
||
}
|
||
|
||
download() {
|
||
if [[ ! -e "${SS_Folder}" ]]; then
|
||
mkdir "${SS_Folder}"
|
||
# else
|
||
# [[ -e "${SS_File}" ]] && rm -rf "${SS_File}"
|
||
fi
|
||
stable_download
|
||
if [[ $? != 0 ]]; then
|
||
backup_download
|
||
fi
|
||
}
|
||
|
||
# Shadow TLS 官方源下载
|
||
stable_download_stls() {
|
||
echo -e "${Info} 默认开始下载官方源 Shadow TLS ……"
|
||
wget --no-check-certificate -N "https://github.com/ihciah/shadow-tls/releases/download/${stls_new_ver}/shadow-tls-${arch}-unknown-linux-musl"
|
||
if [[ ! -e "shadow-tls-${arch}-unknown-linux-musl" ]]; then
|
||
echo -e "${Error} Shadow TLS 官方源下载失败!"
|
||
return 1 && exit 1
|
||
else
|
||
chmod +x "shadow-tls-${arch}-unknown-linux-musl"
|
||
mv -f "shadow-tls-${arch}-unknown-linux-musl" "${STLS_File}"
|
||
echo "${stls_new_ver}" > ${STLS_Now_ver_File}
|
||
echo -e "${Info} Shadow TLS 主程序下载安装完毕!"
|
||
return 0
|
||
fi
|
||
}
|
||
|
||
download_stls() {
|
||
if [[ ! -e "${STLS_Folder}" ]]; then
|
||
mkdir "${STLS_Folder}"
|
||
fi
|
||
stable_download_stls
|
||
}
|
||
|
||
# Shadow TLS 配置相关函数
|
||
set_stls_port(){
|
||
while true
|
||
do
|
||
echo -e "${Tip} Shadow TLS 端口需与防火墙端口一致!"
|
||
echo -e "请输入 Shadow TLS 端口 [1-65535]"
|
||
read -e -p "(默认:8443):" stls_port
|
||
[[ -z "${stls_port}" ]] && stls_port="8443"
|
||
echo $((${stls_port}+0)) &>/dev/null
|
||
if [[ $? -eq 0 ]]; then
|
||
if [[ ${stls_port} -ge 1 ]] && [[ ${stls_port} -le 65535 ]]; then
|
||
echo && echo "========================================"
|
||
echo -e "Shadow TLS 端口:${Red_background_prefix} ${stls_port} ${Font_color_suffix}"
|
||
echo "========================================" && echo
|
||
break
|
||
else
|
||
echo "输入错误, 请输入正确的端口。"
|
||
fi
|
||
else
|
||
echo "输入错误, 请输入正确的端口。"
|
||
fi
|
||
done
|
||
}
|
||
|
||
set_stls_password(){
|
||
echo "请输入 Shadow TLS 密码 [0-9][a-z][A-Z]"
|
||
read -e -p "(默认:随机生成):" stls_password
|
||
[[ -z "${stls_password}" ]] && stls_password=$(< /dev/urandom tr -dc 'a-zA-Z0-9' | head -c 16)
|
||
echo && echo "========================================"
|
||
echo -e "Shadow TLS 密码:${Red_background_prefix} ${stls_password} ${Font_color_suffix}"
|
||
echo "========================================" && echo
|
||
}
|
||
|
||
set_stls_sni(){
|
||
echo "请输入 Shadow TLS SNI 域名"
|
||
read -e -p "(默认:cloudflare.com):" stls_sni
|
||
[[ -z "${stls_sni}" ]] && stls_sni="cloudflare.com"
|
||
echo && echo "========================================"
|
||
echo -e "Shadow TLS SNI:${Red_background_prefix} ${stls_sni} ${Font_color_suffix}"
|
||
echo "========================================" && echo
|
||
}
|
||
|
||
set_stls_fastopen(){
|
||
echo -e "是否开启 Shadow TLS TCP Fast Open ?
|
||
========================================
|
||
${Green_font_prefix} 1.${Font_color_suffix} 开启 ${Green_font_prefix} 2.${Font_color_suffix} 关闭
|
||
========================================"
|
||
read -e -p "(默认:1.开启):" stls_fastopen_choice
|
||
[[ -z "${stls_fastopen_choice}" ]] && stls_fastopen_choice="1"
|
||
if [[ ${stls_fastopen_choice} == "1" ]]; then
|
||
stls_fastopen="true"
|
||
else
|
||
stls_fastopen="false"
|
||
fi
|
||
echo && echo "========================================"
|
||
echo -e "Shadow TLS FastOpen:${Red_background_prefix} ${stls_fastopen} ${Font_color_suffix}"
|
||
echo "========================================" && echo
|
||
}
|
||
|
||
set_stls_strict(){
|
||
echo -e "是否开启 Shadow TLS Strict 模式 ?
|
||
========================================
|
||
${Green_font_prefix} 1.${Font_color_suffix} 开启 ${Green_font_prefix} 2.${Font_color_suffix} 关闭
|
||
========================================"
|
||
read -e -p "(默认:1.开启):" stls_strict_choice
|
||
[[ -z "${stls_strict_choice}" ]] && stls_strict_choice="1"
|
||
if [[ ${stls_strict_choice} == "1" ]]; then
|
||
stls_strict="true"
|
||
else
|
||
stls_strict="false"
|
||
fi
|
||
echo && echo "========================================"
|
||
echo -e "Shadow TLS Strict:${Red_background_prefix} ${stls_strict} ${Font_color_suffix}"
|
||
echo "========================================" && echo
|
||
}
|
||
|
||
set_stls_tls_wildcard_sni(){
|
||
echo -e "请选择 Shadow TLS Wildcard SNI 模式:
|
||
========================================
|
||
${Green_font_prefix} 1.${Font_color_suffix} authed (默认)
|
||
${Green_font_prefix} 2.${Font_color_suffix} off
|
||
${Green_font_prefix} 3.${Font_color_suffix} all
|
||
========================================"
|
||
read -e -p "(默认:1.authed):" stls_tls_wildcard_sni_choice
|
||
[[ -z "${stls_tls_wildcard_sni_choice}" ]] && stls_tls_wildcard_sni_choice="1"
|
||
case "${stls_tls_wildcard_sni_choice}" in
|
||
1) stls_tls_wildcard_sni="authed" ;;
|
||
2) stls_tls_wildcard_sni="off" ;;
|
||
3) stls_tls_wildcard_sni="all" ;;
|
||
*) stls_tls_wildcard_sni="authed" ;;
|
||
esac
|
||
echo && echo "========================================"
|
||
echo -e "TLS Wildcard SNI:${Red_background_prefix} ${stls_tls_wildcard_sni} ${Font_color_suffix}"
|
||
echo "========================================" && echo
|
||
}
|
||
|
||
set_stls_fallback(){
|
||
echo "请输入 Shadow TLS 回退域名"
|
||
read -e -p "(默认:cloud.tencent.com:443):" stls_fallback
|
||
[[ -z "${stls_fallback}" ]] && stls_fallback="cloud.tencent.com:443"
|
||
echo && echo "========================================"
|
||
echo -e "Shadow TLS 回退域名:${Red_background_prefix} ${stls_fallback} ${Font_color_suffix}"
|
||
echo "========================================" && echo
|
||
}
|
||
|
||
service(){
|
||
echo "
|
||
[Unit]
|
||
Description= Shadowsocks Rust Service
|
||
After=network-online.target
|
||
Wants=network-online.target systemd-networkd-wait-online.service
|
||
[Service]
|
||
LimitNOFILE=32767
|
||
Type=simple
|
||
User=root
|
||
Restart=on-failure
|
||
RestartSec=5s
|
||
DynamicUser=true
|
||
ExecStartPre=/bin/sh -c 'ulimit -n 51200'
|
||
ExecStart=${SS_File} -c ${SS_Conf}
|
||
[Install]
|
||
WantedBy=multi-user.target" > /etc/systemd/system/ss-rust.service
|
||
systemctl enable --now ss-rust
|
||
echo -e "${Info} Shadowsocks Rust 服务配置完成!"
|
||
}
|
||
|
||
service_stls(){
|
||
cat > /etc/systemd/system/shadowtls.service<<-EOF
|
||
[Unit]
|
||
Description=Shadow TLS Service
|
||
After=network-online.target
|
||
Wants=network-online.target systemd-networkd-wait-online.service
|
||
|
||
[Service]
|
||
LimitNOFILE=32767
|
||
Type=simple
|
||
User=root
|
||
Restart=on-failure
|
||
RestartSec=5s
|
||
Environment=MONOIO_FORCE_LEGACY_DRIVER=1
|
||
ExecStartPre=/bin/sh -c 'ulimit -n 51200'
|
||
ExecStart=${STLS_File} config --config ${STLS_Conf}
|
||
|
||
[Install]
|
||
WantedBy=multi-user.target
|
||
EOF
|
||
systemctl enable --now shadowtls
|
||
echo -e "${Info} Shadow TLS 服务配置完成!"
|
||
}
|
||
|
||
installation_dependency(){
|
||
if [[ ${release} == "centos" ]]; then
|
||
yum update
|
||
yum install jq gzip wget curl unzip xz openssl -y
|
||
else
|
||
apt-get update
|
||
apt-get install jq gzip wget curl unzip xz-utils openssl -y
|
||
fi
|
||
\cp -f /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
|
||
}
|
||
|
||
write_config(){
|
||
cat > ${SS_Conf}<<-EOF
|
||
{
|
||
"server": "::",
|
||
"server_port": ${port},
|
||
"password": "${password}",
|
||
"method": "${cipher}",
|
||
"fast_open": ${tfo},
|
||
"mode": "tcp_and_udp",
|
||
"user":"nobody",
|
||
"timeout":300,
|
||
"nameserver":"1.1.1.1"
|
||
}
|
||
EOF
|
||
}
|
||
|
||
write_stls_config(){
|
||
# 设置默认值
|
||
[[ -z "${stls_fastopen}" ]] && stls_fastopen="true"
|
||
[[ -z "${stls_strict}" ]] && stls_strict="true"
|
||
[[ -z "${stls_tls_wildcard_sni}" ]] && stls_tls_wildcard_sni="authed"
|
||
[[ -z "${stls_fallback}" ]] && stls_fallback="cloud.tencent.com:443"
|
||
|
||
# 构建 dispatch 配置
|
||
if [[ -z "${stls_dispatch}" ]]; then
|
||
# 没有现有配置,使用默认配置
|
||
# SNI 域名对应的目标地址也使用相同的域名:443
|
||
stls_dispatch_config="\"${stls_sni}\": \"${stls_sni}:443\",
|
||
\"captive.apple.com\": \"captive.apple.com:443\""
|
||
else
|
||
# 有现有配置,需要智能更新 SNI
|
||
if [[ ! -z "${stls_sni}" && -e ${STLS_Conf} ]]; then
|
||
# 查找需要更新的 SNI(排除 captive.apple.com)
|
||
old_sni=$(cat ${STLS_Conf}|jq -r '.server.tls_addr.dispatch | keys[] | select(. != "captive.apple.com")' 2>/dev/null | head -1)
|
||
if [[ ! -z "${old_sni}" && "${old_sni}" != "null" && "${old_sni}" != "${stls_sni}" ]]; then
|
||
# 需要替换旧的 SNI 为新的 SNI,同时更新键和值
|
||
echo -e "${Info} 更新主要 SNI 从 ${old_sni} 到 ${stls_sni}"
|
||
|
||
# 使用 jq 来精确替换键和值
|
||
stls_dispatch_config=$(cat ${STLS_Conf} | jq -r --arg old_sni "${old_sni}" --arg new_sni "${stls_sni}" '
|
||
.server.tls_addr.dispatch |
|
||
to_entries |
|
||
map(if .key == $old_sni then (.key = $new_sni | .value = ($new_sni + ":443")) else . end) |
|
||
map("\"\(.key)\": \"\(.value)\"") |
|
||
join(",\n ")
|
||
' 2>/dev/null)
|
||
|
||
# 如果 jq 处理失败,回退到字符串替换
|
||
if [[ -z "${stls_dispatch_config}" || "${stls_dispatch_config}" == "null" ]]; then
|
||
echo -e "${Info} jq 处理失败,使用字符串替换"
|
||
# 先替换键,再替换对应的值
|
||
stls_dispatch_config=$(echo "${stls_dispatch}" | sed "s/\"${old_sni}\": \"[^\"]*\"/\"${stls_sni}\": \"${stls_sni}:443\"/g")
|
||
fi
|
||
else
|
||
# 如果没有找到需要更新的 SNI,或者 SNI 已经是正确的,直接使用现有配置
|
||
stls_dispatch_config="${stls_dispatch}"
|
||
fi
|
||
else
|
||
stls_dispatch_config="${stls_dispatch}"
|
||
fi
|
||
fi
|
||
|
||
# 调试信息(可选,用于排查问题)
|
||
# echo -e "${Info} 调试信息:"
|
||
# echo -e " stls_sni: ${stls_sni}"
|
||
# echo -e " stls_dispatch_config: ${stls_dispatch_config}"
|
||
|
||
cat > ${STLS_Conf}<<-EOF
|
||
{
|
||
"disable_nodelay": false,
|
||
"fastopen": ${stls_fastopen},
|
||
"v3": true,
|
||
"strict": ${stls_strict},
|
||
"server": {
|
||
"listen": "0.0.0.0:${stls_port}",
|
||
"server_addr": "127.0.0.1:${port}",
|
||
"tls_addr": {
|
||
"wildcard_sni": "${stls_tls_wildcard_sni}",
|
||
"dispatch": {
|
||
${stls_dispatch_config}
|
||
},
|
||
"fallback": "${stls_fallback}"
|
||
},
|
||
"password": "${stls_password}",
|
||
"wildcard_sni": "authed"
|
||
}
|
||
}
|
||
EOF
|
||
|
||
# 验证配置文件是否正确生成
|
||
if [[ -e ${STLS_Conf} ]]; then
|
||
# 检查配置文件是否为有效的 JSON
|
||
if ! jq . ${STLS_Conf} >/dev/null 2>&1; then
|
||
echo -e "${Error} Shadow TLS 配置文件格式错误!"
|
||
return 1
|
||
fi
|
||
echo -e "${Info} Shadow TLS 配置文件写入成功"
|
||
|
||
# 显示当前配置的 SNI
|
||
current_sni=$(cat ${STLS_Conf}|jq -r '.server.tls_addr.dispatch | keys[0]' 2>/dev/null)
|
||
if [[ ! -z "${current_sni}" && "${current_sni}" != "null" ]]; then
|
||
echo -e "${Info} 当前配置的 SNI: ${Green_font_prefix}${current_sni}${Font_color_suffix}"
|
||
fi
|
||
else
|
||
echo -e "${Error} Shadow TLS 配置文件写入失败!"
|
||
return 1
|
||
fi
|
||
}
|
||
|
||
read_config(){
|
||
[[ ! -e ${SS_Conf} ]] && echo -e "${Error} Shadowsocks Rust 配置文件不存在!" && exit 1
|
||
port=$(cat ${SS_Conf}|jq -r '.server_port')
|
||
password=$(cat ${SS_Conf}|jq -r '.password')
|
||
cipher=$(cat ${SS_Conf}|jq -r '.method')
|
||
tfo=$(cat ${SS_Conf}|jq -r '.fast_open')
|
||
}
|
||
|
||
read_stls_config(){
|
||
[[ ! -e ${STLS_Conf} ]] && echo -e "${Error} Shadow TLS 配置文件不存在!" && exit 1
|
||
stls_port=$(cat ${STLS_Conf}|jq -r '.server.listen' | grep -oE '[0-9]+$')
|
||
stls_password=$(cat ${STLS_Conf}|jq -r '.server.password')
|
||
stls_sni=$(cat ${STLS_Conf}|jq -r '.server.tls_addr.dispatch | keys[0]')
|
||
stls_fastopen=$(cat ${STLS_Conf}|jq -r '.fastopen')
|
||
stls_strict=$(cat ${STLS_Conf}|jq -r '.strict')
|
||
stls_tls_wildcard_sni=$(cat ${STLS_Conf}|jq -r '.server.tls_addr.wildcard_sni')
|
||
stls_fallback=$(cat ${STLS_Conf}|jq -r '.server.tls_addr.fallback')
|
||
# 读取完整的 dispatch 配置
|
||
stls_dispatch=$(cat ${STLS_Conf}|jq -r '.server.tls_addr.dispatch | to_entries | map("\"\(.key)\": \"\(.value)\"") | join(",\n ")')
|
||
}
|
||
|
||
set_port(){
|
||
while true
|
||
do
|
||
echo -e "${Tip} 本步骤不涉及系统防火墙端口操作,请手动放行相应端口!"
|
||
echo -e "请输入 Shadowsocks Rust 端口 [1-65535]"
|
||
read -e -p "(默认:2525):" port
|
||
[[ -z "${port}" ]] && port="2525"
|
||
echo $((${port}+0)) &>/dev/null
|
||
if [[ $? -eq 0 ]]; then
|
||
if [[ ${port} -ge 1 ]] && [[ ${port} -le 65535 ]]; then
|
||
echo && echo "========================================"
|
||
echo -e "端口:${Red_background_prefix} ${port} ${Font_color_suffix}"
|
||
echo "========================================" && echo
|
||
break
|
||
else
|
||
echo "输入错误, 请输入正确的端口。"
|
||
fi
|
||
else
|
||
echo "输入错误, 请输入正确的端口。"
|
||
fi
|
||
done
|
||
}
|
||
|
||
set_tfo(){
|
||
echo -e "是否开启 TCP Fast Open ?
|
||
========================================
|
||
${Green_font_prefix} 1.${Font_color_suffix} 开启 ${Green_font_prefix} 2.${Font_color_suffix} 关闭
|
||
========================================"
|
||
read -e -p "(默认:1.开启):" tfo
|
||
[[ -z "${tfo}" ]] && tfo="1"
|
||
if [[ ${tfo} == "1" ]]; then
|
||
tfo=true
|
||
enable_systfo
|
||
else
|
||
tfo=false
|
||
fi
|
||
echo && echo "=================================="
|
||
echo -e "TCP Fast Open 开启状态:${Red_background_prefix} ${tfo} ${Font_color_suffix}"
|
||
echo "==================================" && echo
|
||
}
|
||
|
||
set_password(){
|
||
echo "请输入 Shadowsocks Rust 密码 [0-9][a-z][A-Z]"
|
||
read -e -p "(默认:随机生成):" password
|
||
# 当用户未输入密码时,执行默认生成逻辑
|
||
if [[ -z "${password}" ]]; then
|
||
# 判断是否为2022系列加密
|
||
if [[ ${cipher} == "2022-blake3-aes-256-gcm" || ${cipher} == "2022-blake3-chacha20-poly1305" ]]; then
|
||
# 2022系列必须使用指定长度的Base64密钥
|
||
echo -e "${Tip} 为 ${cipher} 生成 32 字节 Base64 密钥..."
|
||
password=$(openssl rand -base64 32)
|
||
elif [[ ${cipher} == "2022-blake3-aes-128-gcm" ]]; then
|
||
# 2022系列必须使用指定长度的Base64密钥
|
||
echo -e "${Tip} 为 ${cipher} 生成 16 字节 Base64 密钥..."
|
||
password=$(openssl rand -base64 16)
|
||
else
|
||
# 其他加密方式,生成一个普通的16位字母和数字的随机密码
|
||
echo -e "${Tip} 为 ${cipher} 生成 16 位随机密码 (非Base64)..."
|
||
password=$(< /dev/urandom tr -dc 'a-zA-Z0-9' | head -c 16)
|
||
fi
|
||
fi
|
||
echo && echo "========================================"
|
||
echo -e "密码:${Red_font_prefix} ${password} ${Font_color_suffix}"
|
||
echo "========================================" && echo
|
||
}
|
||
|
||
set_cipher(){
|
||
echo -e "请选择 Shadowsocks Rust 加密方式
|
||
========================================
|
||
${Green_font_prefix} 1.${Font_color_suffix} aes-128-gcm ${Green_font_prefix}(默认)${Font_color_suffix}
|
||
${Green_font_prefix} 2.${Font_color_suffix} aes-256-gcm ${Green_font_prefix}(推荐)${Font_color_suffix}
|
||
${Green_font_prefix} 3.${Font_color_suffix} chacha20-ietf-poly1305 ${Green_font_prefix}${Font_color_suffix}
|
||
${Green_font_prefix} 4.${Font_color_suffix} plain ${Red_font_prefix}(不推荐)${Font_color_suffix}
|
||
${Green_font_prefix} 5.${Font_color_suffix} none ${Red_font_prefix}(不推荐)${Font_color_suffix}
|
||
${Green_font_prefix} 6.${Font_color_suffix} table
|
||
${Green_font_prefix} 7.${Font_color_suffix} aes-128-cfb
|
||
${Green_font_prefix} 8.${Font_color_suffix} aes-256-cfb
|
||
${Green_font_prefix} 9.${Font_color_suffix} aes-256-ctr
|
||
${Green_font_prefix}10.${Font_color_suffix} camellia-256-cfb
|
||
${Green_font_prefix}11.${Font_color_suffix} rc4-md5
|
||
${Green_font_prefix}12.${Font_color_suffix} chacha20-ietf
|
||
========================================
|
||
${Tip} AEAD 2022 加密(须v1.15.0及以上版本且密码须经过Base64加密)
|
||
========================================
|
||
${Green_font_prefix}13.${Font_color_suffix} 2022-blake3-aes-128-gcm ${Green_font_prefix}(推荐)${Font_color_suffix}
|
||
${Green_font_prefix}14.${Font_color_suffix} 2022-blake3-aes-256-gcm ${Green_font_prefix}(推荐)${Font_color_suffix}
|
||
${Green_font_prefix}15.${Font_color_suffix} 2022-blake3-chacha20-poly1305
|
||
========================================
|
||
${Tip} 如需其它加密方式请手动修改配置文件 !" && echo
|
||
read -e -p "(默认: 1. aes-128-gcm):" cipher
|
||
[[ -z "${cipher}" ]] && cipher="1"
|
||
if [[ ${cipher} == "1" ]]; then
|
||
cipher="aes-128-gcm"
|
||
elif [[ ${cipher} == "2" ]]; then
|
||
cipher="aes-256-gcm"
|
||
elif [[ ${cipher} == "3" ]]; then
|
||
cipher="chacha20-ietf-poly1305"
|
||
elif [[ ${cipher} == "4" ]]; then
|
||
cipher="plain"
|
||
elif [[ ${cipher} == "5" ]]; then
|
||
cipher="none"
|
||
elif [[ ${cipher} == "6" ]]; then
|
||
cipher="table"
|
||
elif [[ ${cipher} == "7" ]]; then
|
||
cipher="aes-128-cfb"
|
||
elif [[ ${cipher} == "8" ]]; then
|
||
cipher="aes-256-cfb"
|
||
elif [[ ${cipher} == "9" ]]; then
|
||
cipher="aes-256-ctr"
|
||
elif [[ ${cipher} == "10" ]]; then
|
||
cipher="camellia-256-cfb"
|
||
elif [[ ${cipher} == "11" ]]; then
|
||
cipher="arc4-md5"
|
||
elif [[ ${cipher} == "12" ]]; then
|
||
cipher="chacha20-ietf"
|
||
elif [[ ${cipher} == "13" ]]; then
|
||
cipher="2022-blake3-aes-128-gcm"
|
||
elif [[ ${cipher} == "14" ]]; then
|
||
cipher="2022-blake3-aes-256-gcm"
|
||
elif [[ ${cipher} == "15" ]]; then
|
||
cipher="2022-blake3-chacha20-poly1305"
|
||
else
|
||
cipher="aes-128-gcm"
|
||
fi
|
||
echo && echo "========================================"
|
||
echo -e "加密:${Red_background_prefix} ${cipher} ${Font_color_suffix}"
|
||
echo "========================================" && echo
|
||
}
|
||
|
||
set_config(){
|
||
check_installed_status
|
||
echo && echo -e "你要做什么?
|
||
========================================
|
||
${Green_font_prefix}1.${Font_color_suffix} 修改 端口配置
|
||
${Green_font_prefix}2.${Font_color_suffix} 修改 加密配置
|
||
${Green_font_prefix}3.${Font_color_suffix} 修改 密码配置
|
||
${Green_font_prefix}4.${Font_color_suffix} 修改 TFO 配置
|
||
========================================
|
||
${Green_font_prefix}5.${Font_color_suffix} 修改 全部配置" && echo
|
||
read -e -p "(默认:取消):" modify
|
||
[[ -z "${modify}" ]] && echo "已取消..." && exit 1
|
||
if [[ "${modify}" == "1" ]]; then
|
||
read_config
|
||
set_port
|
||
cipher=${cipher}
|
||
password=${password}
|
||
tfo=${tfo}
|
||
write_config
|
||
restart
|
||
elif [[ "${modify}" == "2" ]]; then
|
||
read_config
|
||
set_cipher
|
||
port=${port}
|
||
password=${password}
|
||
tfo=${tfo}
|
||
write_config
|
||
restart
|
||
elif [[ "${modify}" == "3" ]]; then
|
||
read_config
|
||
cipher=${cipher}
|
||
set_password
|
||
port=${port}
|
||
tfo=${tfo}
|
||
write_config
|
||
restart
|
||
elif [[ "${modify}" == "4" ]]; then
|
||
read_config
|
||
set_tfo
|
||
cipher=${cipher}
|
||
port=${port}
|
||
password=${password}
|
||
write_config
|
||
restart
|
||
elif [[ "${modify}" == "5" ]]; then
|
||
read_config
|
||
set_port
|
||
set_cipher
|
||
set_password
|
||
set_tfo
|
||
write_config
|
||
restart
|
||
else
|
||
echo -e "${Error} 请输入正确的数字(1-5)" && exit 1
|
||
fi
|
||
}
|
||
|
||
install(){
|
||
[[ -e ${SS_File} ]] && echo -e "${Error} 检测到 Shadowsocks Rust 已安装!" && exit 1
|
||
echo -e "${Info} 开始设置 配置..."
|
||
set_port
|
||
set_cipher
|
||
set_password
|
||
set_tfo
|
||
echo -e "${Info} 开始安装/配置 依赖..."
|
||
installation_dependency
|
||
echo -e "${Info} 开始下载/安装..."
|
||
check_new_ver
|
||
download
|
||
echo -e "${Info} 开始安装系统服务脚本..."
|
||
service
|
||
echo -e "${Info} 开始写入 配置文件..."
|
||
write_config
|
||
echo -e "${Info} 所有步骤 安装完毕,开始启动..."
|
||
start
|
||
echo -e "${Info} Shadowsocks Rust 安装完成!"
|
||
|
||
# 询问是否继续安装 Shadow TLS
|
||
echo && echo -e "${Tip} 是否继续安装 Shadow TLS 流量伪装?"
|
||
read -e -p "(默认: N 不安装) [y/N]: " install_stls_choice
|
||
[[ -z "${install_stls_choice}" ]] && install_stls_choice="n"
|
||
|
||
if [[ ${install_stls_choice} == [Yy] ]]; then
|
||
echo -e "${Info} 开始安装 Shadow TLS..."
|
||
install_stls_after_ss
|
||
else
|
||
echo -e "${Info} 跳过 Shadow TLS 安装,显示 Shadowsocks Rust 配置..."
|
||
view_ss_only
|
||
fi
|
||
}
|
||
|
||
install_stls(){
|
||
[[ -e ${STLS_File} ]] && echo -e "${Error} 检测到 Shadow TLS 已安装!" && exit 1
|
||
|
||
# 检查 Shadowsocks Rust 是否已安装
|
||
if [[ ! -e ${SS_File} ]]; then
|
||
echo -e "${Error} 检测到 Shadowsocks Rust 尚未安装!"
|
||
echo -e "${Info} Shadow TLS 需要配合 Shadowsocks Rust 使用。"
|
||
echo -e "${Info} 建议先安装 Shadowsocks Rust,再安装 Shadow TLS。"
|
||
echo && read -e -p "是否现在安装 Shadowsocks Rust?[Y/n]:" install_ss_choice
|
||
[[ -z "${install_ss_choice}" ]] && install_ss_choice="Y"
|
||
if [[ ${install_ss_choice} == [Yy] ]]; then
|
||
echo -e "${Info} 开始安装 Shadowsocks Rust..."
|
||
install
|
||
echo -e "${Info} Shadowsocks Rust 安装完成,现在开始安装 Shadow TLS..."
|
||
else
|
||
echo -e "${Info} 已取消安装,返回上级菜单..."
|
||
shadowtls_menu
|
||
return
|
||
fi
|
||
fi
|
||
|
||
echo -e "${Info} 开始设置 Shadow TLS 配置..."
|
||
read_config # 读取现有 SS 配置
|
||
|
||
# 使用交互式配置,每项都有默认值
|
||
echo -e "${Info} 请配置 Shadow TLS 参数(可直接回车使用默认值):"
|
||
|
||
set_stls_port
|
||
set_stls_password
|
||
set_stls_sni
|
||
set_stls_fastopen
|
||
set_stls_strict
|
||
set_stls_tls_wildcard_sni
|
||
set_stls_fallback
|
||
manage_stls_dispatch
|
||
|
||
echo -e "${Info} 开始下载/安装 Shadow TLS..."
|
||
check_stls_new_ver
|
||
download_stls
|
||
echo -e "${Info} 开始安装 Shadow TLS 服务脚本..."
|
||
service_stls
|
||
echo -e "${Info} 开始写入 Shadow TLS 配置文件..."
|
||
write_stls_config
|
||
echo -e "${Info} Shadow TLS 安装完毕,开始启动..."
|
||
start_stls
|
||
echo -e "${Info} Shadow TLS 安装完成!显示完整配置信息..."
|
||
view_combined_config_with_return
|
||
}
|
||
|
||
install_stls_after_ss(){
|
||
echo -e "${Info} 开始设置 Shadow TLS 配置..."
|
||
read_config # 读取现有 SS 配置
|
||
|
||
# 使用交互式配置,每项都有默认值
|
||
echo -e "${Info} 请配置 Shadow TLS 参数(可直接回车使用默认值):"
|
||
|
||
set_stls_port
|
||
set_stls_password
|
||
set_stls_sni
|
||
set_stls_fastopen
|
||
set_stls_strict
|
||
set_stls_tls_wildcard_sni
|
||
set_stls_fallback
|
||
manage_stls_dispatch
|
||
|
||
echo -e "${Info} 开始下载/安装 Shadow TLS..."
|
||
check_stls_new_ver
|
||
download_stls
|
||
echo -e "${Info} 开始安装 Shadow TLS 服务脚本..."
|
||
service_stls
|
||
echo -e "${Info} 开始写入 Shadow TLS 配置文件..."
|
||
write_stls_config
|
||
echo -e "${Info} Shadow TLS 安装完毕,开始启动..."
|
||
start_stls
|
||
echo -e "${Info} Shadow TLS 安装完成!显示完整配置信息..."
|
||
view_combined_config_with_return
|
||
}
|
||
|
||
view(){
|
||
check_installed_status
|
||
read_config
|
||
getipv4
|
||
getipv6
|
||
link_qr
|
||
clear && echo
|
||
echo -e "Shadowsocks Rust 配置:"
|
||
echo -e "————————————————————————————————————————"
|
||
[[ "${ipv4}" != "IPv4_Error" ]] && echo -e " 地址:${Green_font_prefix}${ipv4}${Font_color_suffix}"
|
||
[[ "${ipv6}" != "IPv6_Error" ]] && echo -e " 地址:${Green_font_prefix}${ipv6}${Font_color_suffix}"
|
||
echo -e " 端口:${Green_font_prefix}${port}${Font_color_suffix}"
|
||
echo -e " 密码:${Green_font_prefix}${password}${Font_color_suffix}"
|
||
echo -e " 加密:${Green_font_prefix}${cipher}${Font_color_suffix}"
|
||
echo -e " TFO :${Green_font_prefix}${tfo}${Font_color_suffix}"
|
||
echo -e "————————————————————————————————————————"
|
||
[[ ! -z "${link_ipv4}" ]] && echo -e "${link_ipv4}"
|
||
[[ ! -z "${link_ipv6}" ]] && echo -e "${link_ipv6}"
|
||
echo -e "—————————————————————————"
|
||
echo -e "${Info} Surge 配置:"
|
||
if [[ "${ipv4}" != "IPv4_Error" ]]; then
|
||
echo -e "$(uname -n) = ss, ${ipv4},${port}, encrypt-method=${cipher}, password=${password}, tfo=${tfo}, udp-relay=true, ecn=true"
|
||
else
|
||
echo -e "$(uname -n) = ss, ${ipv6},${port}, encrypt-method=${cipher}, password=${password}, tfo=${tfo}, udp-relay=true, ecn=true"
|
||
fi
|
||
echo -e "—————————————————————————"
|
||
echo && echo -n " 按回车键返回主菜单..." && read
|
||
start_menu
|
||
}
|
||
|
||
view_ss_only(){
|
||
check_installed_status
|
||
read_config
|
||
getipv4
|
||
getipv6
|
||
link_qr
|
||
clear && echo
|
||
echo -e "Shadowsocks Rust 配置:"
|
||
echo -e "————————————————————————————————————————"
|
||
[[ "${ipv4}" != "IPv4_Error" ]] && echo -e " 地址:${Green_font_prefix}${ipv4}${Font_color_suffix}"
|
||
[[ "${ipv6}" != "IPv6_Error" ]] && echo -e " 地址:${Green_font_prefix}${ipv6}${Font_color_suffix}"
|
||
echo -e " 端口:${Green_font_prefix}${port}${Font_color_suffix}"
|
||
echo -e " 密码:${Green_font_prefix}${password}${Font_color_suffix}"
|
||
echo -e " 加密:${Green_font_prefix}${cipher}${Font_color_suffix}"
|
||
echo -e " TFO :${Green_font_prefix}${tfo}${Font_color_suffix}"
|
||
echo -e "————————————————————————————————————————"
|
||
[[ ! -z "${link_ipv4}" ]] && echo -e "${link_ipv4}"
|
||
[[ ! -z "${link_ipv6}" ]] && echo -e "${link_ipv6}"
|
||
echo -e "—————————————————————————"
|
||
echo -e "${Info} Surge 配置:"
|
||
if [[ "${ipv4}" != "IPv4_Error" ]]; then
|
||
echo -e "$(uname -n) = ss, ${ipv4},${port}, encrypt-method=${cipher}, password=${password}, tfo=${tfo}, udp-relay=true, ecn=true"
|
||
else
|
||
echo -e "$(uname -n) = ss, ${ipv6},${port}, encrypt-method=${cipher}, password=${password}, tfo=${tfo}, udp-relay=true, ecn=true"
|
||
fi
|
||
echo -e "—————————————————————————"
|
||
echo && echo -n " 按回车键返回主菜单..." && read
|
||
start_menu
|
||
}
|
||
|
||
view_combined_config(){
|
||
local menu_source="$1" # 接收调用来源参数
|
||
check_installed_status
|
||
read_config
|
||
getipv4
|
||
getipv6
|
||
link_qr
|
||
clear && echo
|
||
|
||
echo -e "完整配置信息:"
|
||
echo -e "========================================"
|
||
|
||
# 显示 Shadow TLS + SS 配置
|
||
if [[ -e ${STLS_File} ]]; then
|
||
read_stls_config
|
||
echo -e "${Info} Shadow TLS + Shadowsocks Rust 配置:"
|
||
echo -e "————————————————————————————————————————"
|
||
[[ "${ipv4}" != "IPv4_Error" ]] && echo -e " 服务器:${Green_font_prefix}${ipv4}${Font_color_suffix}"
|
||
[[ "${ipv6}" != "IPv6_Error" ]] && echo -e " 服务器:${Green_font_prefix}${ipv6}${Font_color_suffix}"
|
||
echo -e " Shadow TLS 端口:${Green_font_prefix}${stls_port}${Font_color_suffix}"
|
||
echo -e " Shadow TLS 密码:${Green_font_prefix}${stls_password}${Font_color_suffix}"
|
||
echo -e " Shadow TLS SNI:${Green_font_prefix}${stls_sni}${Font_color_suffix}"
|
||
echo -e " SS 本地端口:${Green_font_prefix}${port}${Font_color_suffix}"
|
||
echo -e " SS 密码:${Green_font_prefix}${password}${Font_color_suffix}"
|
||
echo -e " SS 加密:${Green_font_prefix}${cipher}${Font_color_suffix}"
|
||
echo -e "————————————————————————————————————————"
|
||
echo -e "${Info} Shadow TLS + SS Surge 配置:"
|
||
if [[ "${ipv4}" != "IPv4_Error" ]]; then
|
||
echo -e "$(uname -n) = ss, ${ipv4}, ${stls_port}, encrypt-method=${cipher}, password=${password}, shadow-tls-password=${stls_password}, shadow-tls-sni=${stls_sni}, shadow-tls-version=3, tfo=${tfo}, udp-relay=true, ecn=true, udp-port=${port}"
|
||
else
|
||
echo -e "$(uname -n) = ss, ${ipv6}, ${stls_port}, encrypt-method=${cipher}, password=${password}, shadow-tls-password=${stls_password}, shadow-tls-sni=${stls_sni}, shadow-tls-version=3, tfo=${tfo}, udp-relay=true, ecn=true, udp-port=${port}"
|
||
fi
|
||
echo && echo -e "========================================"
|
||
fi
|
||
|
||
# 显示纯 SS 配置
|
||
echo -e "${Info} 原始 Shadowsocks Rust 配置:"
|
||
echo -e "————————————————————————————————————————"
|
||
[[ "${ipv4}" != "IPv4_Error" ]] && echo -e " 地址:${Green_font_prefix}${ipv4}${Font_color_suffix}"
|
||
[[ "${ipv6}" != "IPv6_Error" ]] && echo -e " 地址:${Green_font_prefix}${ipv6}${Font_color_suffix}"
|
||
echo -e " 端口:${Green_font_prefix}${port}${Font_color_suffix}"
|
||
echo -e " 密码:${Green_font_prefix}${password}${Font_color_suffix}"
|
||
echo -e " 加密:${Green_font_prefix}${cipher}${Font_color_suffix}"
|
||
echo -e "————————————————————————————————————————"
|
||
[[ ! -z "${link_ipv4}" ]] && echo -e "${link_ipv4}"
|
||
[[ ! -z "${link_ipv6}" ]] && echo -e "${link_ipv6}"
|
||
echo -e "—————————————————————————"
|
||
echo -e "${Info} 原始 SS Surge 配置:"
|
||
if [[ "${ipv4}" != "IPv4_Error" ]]; then
|
||
echo -e "$(uname -n) = ss, ${ipv4}, ${port}, encrypt-method=${cipher}, password=${password}, tfo=${tfo}, udp-relay=true, ecn=true"
|
||
fi
|
||
echo -e "========================================"
|
||
|
||
# 根据调用来源返回到相应菜单
|
||
if [[ "$menu_source" == "shadowtls" ]]; then
|
||
echo && echo -n " 按回车键返回 Shadow TLS 菜单..." && read
|
||
shadowtls_menu
|
||
else
|
||
echo && echo -n " 按回车键返回主菜单..." && read
|
||
start_menu
|
||
fi
|
||
}
|
||
|
||
view_combined_config_with_return(){
|
||
check_installed_status
|
||
read_config
|
||
getipv4
|
||
getipv6
|
||
link_qr
|
||
clear && echo
|
||
|
||
echo -e "完整配置信息:"
|
||
echo -e "========================================"
|
||
|
||
# 显示 Shadow TLS + SS 配置
|
||
if [[ -e ${STLS_File} ]]; then
|
||
read_stls_config
|
||
echo -e "${Info} Shadow TLS + Shadowsocks Rust 配置:"
|
||
echo -e "————————————————————————————————————————"
|
||
[[ "${ipv4}" != "IPv4_Error" ]] && echo -e " 服务器:${Green_font_prefix}${ipv4}${Font_color_suffix}"
|
||
[[ "${ipv6}" != "IPv6_Error" ]] && echo -e " 服务器:${Green_font_prefix}${ipv6}${Font_color_suffix}"
|
||
echo -e " Shadow TLS 端口:${Green_font_prefix}${stls_port}${Font_color_suffix}"
|
||
echo -e " Shadow TLS 密码:${Green_font_prefix}${stls_password}${Font_color_suffix}"
|
||
echo -e " Shadow TLS SNI:${Green_font_prefix}${stls_sni}${Font_color_suffix}"
|
||
echo -e " SS 本地端口:${Green_font_prefix}${port}${Font_color_suffix}"
|
||
echo -e " SS 密码:${Green_font_prefix}${password}${Font_color_suffix}"
|
||
echo -e " SS 加密:${Green_font_prefix}${cipher}${Font_color_suffix}"
|
||
echo -e "————————————————————————————————————————"
|
||
echo -e "${Info} Shadow TLS + SS Surge 配置:"
|
||
if [[ "${ipv4}" != "IPv4_Error" ]]; then
|
||
echo -e "$(uname -n) = ss, ${ipv4}, ${stls_port}, encrypt-method=${cipher}, password=${password}, shadow-tls-password=${stls_password}, shadow-tls-sni=${stls_sni}, shadow-tls-version=3, tfo=${tfo}, ecn=true, udp-relay=true, udp-port=${port}"
|
||
else
|
||
echo -e "$(uname -n) = ss, ${ipv6}, ${stls_port}, encrypt-method=${cipher}, password=${password}, shadow-tls-password=${stls_password}, shadow-tls-sni=${stls_sni}, shadow-tls-version=3, tfo=${tfo}, ecn=true, udp-relay=true, udp-port=${port}"
|
||
fi
|
||
echo && echo -e "========================================"
|
||
fi
|
||
|
||
# 显示纯 SS 配置
|
||
echo -e "${Info} 原始 Shadowsocks Rust 配置:"
|
||
echo -e "————————————————————————————————————————"
|
||
[[ "${ipv4}" != "IPv4_Error" ]] && echo -e " 地址:${Green_font_prefix}${ipv4}${Font_color_suffix}"
|
||
[[ "${ipv6}" != "IPv6_Error" ]] && echo -e " 地址:${Green_font_prefix}${ipv6}${Font_color_suffix}"
|
||
echo -e " 端口:${Green_font_prefix}${port}${Font_color_suffix}"
|
||
echo -e " 密码:${Green_font_prefix}${password}${Font_color_suffix}"
|
||
echo -e " 加密:${Green_font_prefix}${cipher}${Font_color_suffix}"
|
||
echo -e "————————————————————————————————————————"
|
||
[[ ! -z "${link_ipv4}" ]] && echo -e "${link_ipv4}"
|
||
[[ ! -z "${link_ipv6}" ]] && echo -e "${link_ipv6}"
|
||
echo -e "—————————————————————————"
|
||
echo -e "${Info} SS Surge 配置:"
|
||
if [[ "${ipv4}" != "IPv4_Error" ]]; then
|
||
echo -e "$(uname -n) = ss, ${ipv4}, ${port}, encrypt-method=${cipher}, password=${password}, tfo=${tfo}, udp-relay=true, ecn=true"
|
||
fi
|
||
echo -e "========================================"
|
||
echo && echo -n " 按回车键继续..." && read
|
||
}
|
||
|
||
# 综合 Shadow TLS 配置函数
|
||
set_stls_config(){
|
||
check_stls_installed_status
|
||
read_config
|
||
read_stls_config
|
||
|
||
echo && echo -e "你要修改哪项 Shadow TLS 配置?
|
||
========================================
|
||
${Green_font_prefix}1.${Font_color_suffix} 修改 端口配置
|
||
${Green_font_prefix}2.${Font_color_suffix} 修改 密码配置
|
||
${Green_font_prefix}3.${Font_color_suffix} 修改 Shadow TLS SNI 域名
|
||
${Green_font_prefix}4.${Font_color_suffix} 修改 FastOpen 配置
|
||
${Green_font_prefix}5.${Font_color_suffix} 修改 Strict 模式配置
|
||
${Green_font_prefix}6.${Font_color_suffix} 修改 TLS Wildcard SNI 配置
|
||
${Green_font_prefix}7.${Font_color_suffix} 修改 回退域名配置
|
||
${Green_font_prefix}8.${Font_color_suffix} 管理 Dispatch 分发配置
|
||
========================================
|
||
${Green_font_prefix}9.${Font_color_suffix} 修改 全部配置" && echo
|
||
read -e -p "(默认:取消):" modify
|
||
[[ -z "${modify}" ]] && echo "已取消..." && return
|
||
|
||
case "${modify}" in
|
||
1)
|
||
set_stls_port
|
||
write_stls_config
|
||
restart_stls
|
||
;;
|
||
2)
|
||
set_stls_password
|
||
write_stls_config
|
||
restart_stls
|
||
;;
|
||
3)
|
||
set_stls_sni
|
||
write_stls_config
|
||
restart_stls
|
||
;;
|
||
4)
|
||
set_stls_fastopen
|
||
write_stls_config
|
||
restart_stls
|
||
;;
|
||
5)
|
||
set_stls_strict
|
||
write_stls_config
|
||
restart_stls
|
||
;;
|
||
6)
|
||
set_stls_tls_wildcard_sni
|
||
write_stls_config
|
||
restart_stls
|
||
;;
|
||
7)
|
||
set_stls_fallback
|
||
write_stls_config
|
||
restart_stls
|
||
;;
|
||
8)
|
||
manage_stls_dispatch
|
||
if [[ ! -z "${stls_dispatch}" ]]; then
|
||
write_stls_config
|
||
restart_stls
|
||
fi
|
||
;;
|
||
9)
|
||
set_stls_port
|
||
set_stls_password
|
||
set_stls_sni
|
||
set_stls_fastopen
|
||
set_stls_strict
|
||
set_stls_tls_wildcard_sni
|
||
set_stls_fallback
|
||
manage_stls_dispatch
|
||
write_stls_config
|
||
restart_stls
|
||
;;
|
||
*)
|
||
echo -e "${Error} 请输入正确的数字(1-9)"
|
||
set_stls_config
|
||
;;
|
||
esac
|
||
}
|
||
|
||
# Dispatch 管理的简化版本
|
||
manage_stls_dispatch(){
|
||
echo -e "${Info} 当前 dispatch 配置:"
|
||
if [[ -e ${STLS_Conf} ]]; then
|
||
echo -e "${Green_font_prefix}$(cat ${STLS_Conf}|jq -r '.server.tls_addr.dispatch | to_entries | map(" \(.key) -> \(.value)") | join("\n")')${Font_color_suffix}"
|
||
else
|
||
echo -e " ${stls_sni} -> 1.1.1.1:443"
|
||
echo -e " captive.apple.com -> captive.apple.com:443"
|
||
fi
|
||
|
||
echo && echo -e "是否需要修改 dispatch 配置?
|
||
========================================
|
||
${Green_font_prefix} 1.${Font_color_suffix} 使用默认配置(推荐)
|
||
${Green_font_prefix} 2.${Font_color_suffix} 自定义配置所有条目
|
||
========================================"
|
||
read -e -p "(默认:1.使用默认):" dispatch_choice
|
||
[[ -z "${dispatch_choice}" ]] && dispatch_choice="1"
|
||
|
||
if [[ "${dispatch_choice}" == "1" ]]; then
|
||
# 使用默认配置,确保使用当前设置的 SNI
|
||
echo -e "${Info} 使用默认 dispatch 配置,SNI: ${stls_sni}"
|
||
# 不设置 stls_dispatch,让 write_stls_config 使用默认逻辑
|
||
stls_dispatch=""
|
||
elif [[ "${dispatch_choice}" == "2" ]]; then
|
||
echo -e "${Info} 重新配置 dispatch 条目"
|
||
echo "请输入 dispatch 配置 (每行格式: 域名:目标地址,回车结束):"
|
||
echo "示例: cloudflare.com:1.1.1.1:443"
|
||
|
||
local dispatch_entries=""
|
||
local line_count=0
|
||
while true; do
|
||
read -e -p "条目 $((line_count+1)) (直接回车结束):" dispatch_entry
|
||
if [[ -z "${dispatch_entry}" ]]; then
|
||
break
|
||
fi
|
||
|
||
if [[ "${dispatch_entry}" =~ ^([^:]+):(.+)$ ]]; then
|
||
local sni="${BASH_REMATCH[1]}"
|
||
local target="${BASH_REMATCH[2]}"
|
||
|
||
if [[ ${line_count} -gt 0 ]]; then
|
||
dispatch_entries="${dispatch_entries},
|
||
"
|
||
fi
|
||
dispatch_entries="${dispatch_entries}\"${sni}\": \"${target}\""
|
||
line_count=$((line_count+1))
|
||
else
|
||
echo -e "${Error} 格式错误,请使用格式: 域名:目标地址"
|
||
fi
|
||
done
|
||
|
||
if [[ ${line_count} -gt 0 ]]; then
|
||
stls_dispatch="${dispatch_entries}"
|
||
echo -e "${Info} 已配置 ${line_count} 个 dispatch 条目"
|
||
else
|
||
echo -e "${Info} 没有输入条目,使用默认 dispatch 配置"
|
||
# 不设置 stls_dispatch,让 write_stls_config 使用默认逻辑
|
||
stls_dispatch=""
|
||
fi
|
||
fi
|
||
}
|
||
|
||
# 增强版 Dispatch 管理(支持单条增删改)
|
||
manage_stls_dispatch_advanced(){
|
||
echo -e "${Info} 当前 dispatch 配置:"
|
||
if [[ -e ${STLS_Conf} ]]; then
|
||
echo -e "${Green_font_prefix}$(cat ${STLS_Conf}|jq -r '.server.tls_addr.dispatch | to_entries | map(" \(.key) -> \(.value)") | join("\n")')${Font_color_suffix}"
|
||
else
|
||
echo -e " ${stls_sni} -> 1.1.1.1:443"
|
||
echo -e " captive.apple.com -> captive.apple.com:443"
|
||
fi
|
||
|
||
echo && echo -e "请选择 dispatch 管理操作:
|
||
========================================
|
||
${Green_font_prefix} 1.${Font_color_suffix} 保持当前配置
|
||
${Green_font_prefix} 2.${Font_color_suffix} 添加新条目
|
||
${Green_font_prefix} 3.${Font_color_suffix} 删除指定条目
|
||
${Green_font_prefix} 4.${Font_color_suffix} 修改指定条目
|
||
${Green_font_prefix} 5.${Font_color_suffix} 重新配置所有条目
|
||
========================================"
|
||
read -e -p "(默认:1.保持当前):" dispatch_choice
|
||
[[ -z "${dispatch_choice}" ]] && dispatch_choice="1"
|
||
|
||
case "${dispatch_choice}" in
|
||
1)
|
||
echo -e "${Info} 保持当前配置"
|
||
;;
|
||
2)
|
||
add_dispatch_entry
|
||
;;
|
||
3)
|
||
delete_dispatch_entry
|
||
;;
|
||
4)
|
||
modify_dispatch_entry
|
||
;;
|
||
5)
|
||
reconfigure_all_dispatch
|
||
;;
|
||
*)
|
||
echo -e "${Error} 输入错误,保持当前配置"
|
||
;;
|
||
esac
|
||
}
|
||
|
||
# 添加 dispatch 条目
|
||
add_dispatch_entry(){
|
||
echo -e "${Info} 添加新的 dispatch 条目"
|
||
read -e -p "请输入域名 (如: example.com):" new_sni
|
||
if [[ -z "${new_sni}" ]]; then
|
||
echo -e "${Error} 域名不能为空"
|
||
return
|
||
fi
|
||
|
||
read -e -p "请输入目标地址 (如: 1.1.1.1:443):" new_target
|
||
if [[ -z "${new_target}" ]]; then
|
||
echo -e "${Error} 目标地址不能为空"
|
||
return
|
||
fi
|
||
|
||
# 获取当前 dispatch 配置
|
||
if [[ -e ${STLS_Conf} ]]; then
|
||
current_dispatch=$(cat ${STLS_Conf}|jq -r '.server.tls_addr.dispatch | to_entries | map("\"\(.key)\": \"\(.value)\"") | join(",\n ")')
|
||
stls_dispatch="${current_dispatch},
|
||
\"${new_sni}\": \"${new_target}\""
|
||
else
|
||
stls_dispatch="\"${stls_sni}\": \"1.1.1.1:443\",
|
||
\"captive.apple.com\": \"captive.apple.com:443\",
|
||
\"${new_sni}\": \"${new_target}\""
|
||
fi
|
||
|
||
echo -e "${Info} 已添加条目: ${new_sni} -> ${new_target}"
|
||
}
|
||
|
||
# 删除 dispatch 条目
|
||
delete_dispatch_entry(){
|
||
if [[ ! -e ${STLS_Conf} ]]; then
|
||
echo -e "${Error} 配置文件不存在"
|
||
return
|
||
fi
|
||
|
||
echo -e "${Info} 当前 dispatch 条目:"
|
||
# 显示带编号的列表
|
||
local domains=($(cat ${STLS_Conf}|jq -r '.server.tls_addr.dispatch | keys[]'))
|
||
local targets=($(cat ${STLS_Conf}|jq -r '.server.tls_addr.dispatch | to_entries | map(.value) | .[]'))
|
||
|
||
if [[ ${#domains[@]} -eq 0 ]]; then
|
||
echo -e "${Error} 没有可删除的条目"
|
||
return
|
||
fi
|
||
|
||
for i in "${!domains[@]}"; do
|
||
echo -e " ${Green_font_prefix}$((i+1)).${Font_color_suffix} ${domains[i]} -> ${targets[i]}"
|
||
done
|
||
|
||
read -e -p "请输入要删除的条目编号 (1-${#domains[@]}):" del_num
|
||
if [[ -z "${del_num}" ]] || [[ ${del_num} -lt 1 ]] || [[ ${del_num} -gt ${#domains[@]} ]]; then
|
||
echo -e "${Error} 输入的编号无效"
|
||
return
|
||
fi
|
||
|
||
# 重新构建 dispatch 配置,排除删除的条目
|
||
local del_domain="${domains[$((del_num-1))]}"
|
||
local new_entries=""
|
||
local count=0
|
||
|
||
for i in "${!domains[@]}"; do
|
||
if [[ "${domains[i]}" != "${del_domain}" ]]; then
|
||
if [[ ${count} -gt 0 ]]; then
|
||
new_entries="${new_entries},
|
||
"
|
||
fi
|
||
new_entries="${new_entries}\"${domains[i]}\": \"${targets[i]}\""
|
||
count=$((count+1))
|
||
fi
|
||
done
|
||
|
||
if [[ ${count} -eq 0 ]]; then
|
||
# 如果删除后没有条目,使用默认配置
|
||
stls_dispatch="\"${stls_sni}\": \"1.1.1.1:443\",
|
||
\"captive.apple.com\": \"captive.apple.com:443\""
|
||
else
|
||
stls_dispatch="${new_entries}"
|
||
fi
|
||
|
||
echo -e "${Info} 已删除条目: ${del_domain}"
|
||
}
|
||
|
||
# 修改 dispatch 条目
|
||
modify_dispatch_entry(){
|
||
if [[ ! -e ${STLS_Conf} ]]; then
|
||
echo -e "${Error} 配置文件不存在"
|
||
return
|
||
fi
|
||
|
||
echo -e "${Info} 当前 dispatch 条目:"
|
||
# 显示带编号的列表
|
||
local domains=($(cat ${STLS_Conf}|jq -r '.server.tls_addr.dispatch | keys[]'))
|
||
local targets=($(cat ${STLS_Conf}|jq -r '.server.tls_addr.dispatch | to_entries | map(.value) | .[]'))
|
||
|
||
if [[ ${#domains[@]} -eq 0 ]]; then
|
||
echo -e "${Error} 没有可修改的条目"
|
||
return
|
||
fi
|
||
|
||
for i in "${!domains[@]}"; do
|
||
echo -e " ${Green_font_prefix}$((i+1)).${Font_color_suffix} ${domains[i]} -> ${targets[i]}"
|
||
done
|
||
|
||
read -e -p "请输入要修改的条目编号 (1-${#domains[@]}):" mod_num
|
||
if [[ -z "${mod_num}" ]] || [[ ${mod_num} -lt 1 ]] || [[ ${mod_num} -gt ${#domains[@]} ]]; then
|
||
echo -e "${Error} 输入的编号无效"
|
||
return
|
||
fi
|
||
|
||
local mod_domain="${domains[$((mod_num-1))]}"
|
||
local mod_target="${targets[$((mod_num-1))]}"
|
||
|
||
echo -e "${Info} 当前条目: ${mod_domain} -> ${mod_target}"
|
||
read -e -p "请输入新的域名 (直接回车保持不变):" new_domain
|
||
read -e -p "请输入新的目标地址 (直接回车保持不变):" new_target
|
||
|
||
[[ -z "${new_domain}" ]] && new_domain="${mod_domain}"
|
||
[[ -z "${new_target}" ]] && new_target="${mod_target}"
|
||
|
||
# 重新构建 dispatch 配置
|
||
local new_entries=""
|
||
for i in "${!domains[@]}"; do
|
||
if [[ ${i} -gt 0 ]]; then
|
||
new_entries="${new_entries},
|
||
"
|
||
fi
|
||
|
||
if [[ ${i} -eq $((mod_num-1)) ]]; then
|
||
new_entries="${new_entries}\"${new_domain}\": \"${new_target}\""
|
||
else
|
||
new_entries="${new_entries}\"${domains[i]}\": \"${targets[i]}\""
|
||
fi
|
||
done
|
||
|
||
stls_dispatch="${new_entries}"
|
||
echo -e "${Info} 已修改条目: ${mod_domain} -> ${mod_target} => ${new_domain} -> ${new_target}"
|
||
}
|
||
|
||
# 重新配置所有 dispatch 条目
|
||
reconfigure_all_dispatch(){
|
||
echo -e "${Info} 重新配置所有 dispatch 条目"
|
||
echo "请输入 dispatch 配置 (每行格式: 域名:目标地址,回车结束):"
|
||
echo "示例: cloudflare.com:1.1.1.1:443"
|
||
|
||
local dispatch_entries=""
|
||
local line_count=0
|
||
while true; do
|
||
read -e -p "条目 $((line_count+1)) (直接回车结束):" dispatch_entry
|
||
if [[ -z "${dispatch_entry}" ]]; then
|
||
break
|
||
fi
|
||
|
||
if [[ "${dispatch_entry}" =~ ^([^:]+):(.+)$ ]]; then
|
||
local sni="${BASH_REMATCH[1]}"
|
||
local target="${BASH_REMATCH[2]}"
|
||
|
||
if [[ ${line_count} -gt 0 ]]; then
|
||
dispatch_entries="${dispatch_entries},
|
||
"
|
||
fi
|
||
dispatch_entries="${dispatch_entries}\"${sni}\": \"${target}\""
|
||
line_count=$((line_count+1))
|
||
else
|
||
echo -e "${Error} 格式错误,请使用格式: 域名:目标地址"
|
||
fi
|
||
done
|
||
|
||
if [[ ${line_count} -gt 0 ]]; then
|
||
stls_dispatch="${dispatch_entries}"
|
||
echo -e "${Info} 已配置 ${line_count} 个 dispatch 条目"
|
||
else
|
||
echo -e "${Info} 使用默认 dispatch 配置"
|
||
stls_dispatch="\"${stls_sni}\": \"1.1.1.1:443\",
|
||
\"captive.apple.com\": \"captive.apple.com:443\""
|
||
fi
|
||
}
|
||
|
||
start(){
|
||
check_installed_status
|
||
check_status
|
||
if [[ "$status" == "running" ]]; then
|
||
echo -e "${Info} Shadowsocks Rust 已在运行!"
|
||
else
|
||
systemctl start ss-rust
|
||
check_status
|
||
if [[ "$status" == "running" ]]; then
|
||
echo -e "${Info} Shadowsocks Rust 启动成功!"
|
||
else
|
||
echo -e "${Error} Shadowsocks Rust 启动失败!"
|
||
exit 1
|
||
fi
|
||
fi
|
||
sleep 3s
|
||
}
|
||
|
||
start_stls(){
|
||
check_stls_installed_status
|
||
check_stls_status
|
||
if [[ "$stls_status" == "running" ]]; then
|
||
echo -e "${Info} Shadow TLS 已在运行!"
|
||
else
|
||
systemctl start shadowtls
|
||
check_stls_status
|
||
if [[ "$stls_status" == "running" ]]; then
|
||
echo -e "${Info} Shadow TLS 启动成功!"
|
||
else
|
||
echo -e "${Error} Shadow TLS 启动失败!"
|
||
exit 1
|
||
fi
|
||
fi
|
||
sleep 3s
|
||
}
|
||
|
||
stop(){
|
||
check_installed_status
|
||
check_status
|
||
[[ !"$status" == "running" ]] && echo -e "${Error} Shadowsocks Rust 没有运行,请检查!" && exit 1
|
||
systemctl stop ss-rust
|
||
sleep 3s
|
||
start_menu
|
||
}
|
||
|
||
stop_stls(){
|
||
check_stls_installed_status
|
||
check_stls_status
|
||
[[ !"$stls_status" == "running" ]] && echo -e "${Error} Shadow TLS 没有运行,请检查!" && exit 1
|
||
systemctl stop shadowtls
|
||
sleep 3s
|
||
}
|
||
|
||
restart(){
|
||
check_installed_status
|
||
systemctl restart ss-rust
|
||
echo -e "${Info} Shadowsocks Rust 重启完毕 !"
|
||
sleep 3s
|
||
start_menu
|
||
}
|
||
|
||
restart_stls(){
|
||
check_stls_installed_status
|
||
systemctl restart shadowtls
|
||
echo -e "${Info} Shadow TLS 重启完毕 !"
|
||
sleep 3s
|
||
}
|
||
|
||
update(){
|
||
check_installed_status
|
||
check_new_ver
|
||
check_ver_comparison
|
||
echo -e "${Info} Shadowsocks Rust 更新完毕!"
|
||
sleep 3s
|
||
start_menu
|
||
}
|
||
|
||
update_stls(){
|
||
check_stls_installed_status
|
||
check_stls_new_ver
|
||
check_stls_ver_comparison
|
||
echo -e "${Info} Shadow TLS 更新完毕!"
|
||
sleep 3s
|
||
}
|
||
|
||
# 脚本更新函数
|
||
update_sh(){
|
||
echo -e "当前版本为 [ ${sh_ver} ],开始检测最新版本..."
|
||
sh_new_ver=$(wget --no-check-certificate -qO- "https://raw.githubusercontent.com/xOS/Shadowsocks-Rust/master/ss-rust.sh"|grep 'sh_ver="'|awk -F "=" '{print $NF}'|sed 's/\"//g'|head -1)
|
||
[[ -z ${sh_new_ver} ]] && echo -e "${Error} 检测最新版本失败 !" && start_menu
|
||
if [[ ${sh_new_ver} != ${sh_ver} ]]; then
|
||
echo -e "发现新版本[ ${sh_new_ver} ],是否更新?[Y/n]"
|
||
read -p "(默认:y):" yn
|
||
[[ -z "${yn}" ]] && yn="y"
|
||
if [[ ${yn} == [Yy] ]]; then
|
||
wget -O ss-rust.sh --no-check-certificate https://raw.githubusercontent.com/xOS/Shadowsocks-Rust/master/ss-rust.sh && chmod +x ss-rust.sh
|
||
echo -e "脚本已更新为最新版本[ ${sh_new_ver} ]!"
|
||
echo -e "3s后执行新脚本"
|
||
sleep 3s
|
||
bash ss-rust.sh
|
||
else
|
||
echo && echo " 已取消..." && echo
|
||
sleep 3s
|
||
start_menu
|
||
fi
|
||
else
|
||
echo -e "当前已是最新版本[ ${sh_new_ver} ] !"
|
||
sleep 3s
|
||
start_menu
|
||
fi
|
||
sleep 3s
|
||
bash ss-rust.sh
|
||
}
|
||
|
||
uninstall(){
|
||
check_installed_status
|
||
echo "确定要卸载 Shadowsocks Rust ? (y/N)"
|
||
echo
|
||
read -e -p "(默认:n):" unyn
|
||
[[ -z ${unyn} ]] && unyn="n"
|
||
if [[ ${unyn} == [Yy] ]]; then
|
||
check_status
|
||
[[ "$status" == "running" ]] && systemctl stop ss-rust
|
||
systemctl disable ss-rust
|
||
rm -rf "${SS_Folder}"
|
||
rm -rf "${SS_File}"
|
||
echo && echo "Shadowsocks Rust 卸载完成!" && echo
|
||
else
|
||
echo && echo "卸载已取消..." && echo
|
||
fi
|
||
sleep 3s
|
||
start_menu
|
||
}
|
||
|
||
uninstall_stls(){
|
||
check_stls_installed_status
|
||
echo "确定要卸载 Shadow TLS ? (y/N)"
|
||
echo
|
||
read -e -p "(默认:n):" unyn
|
||
[[ -z ${unyn} ]] && unyn="n"
|
||
if [[ ${unyn} == [Yy] ]]; then
|
||
check_stls_status
|
||
[[ "$stls_status" == "running" ]] && systemctl stop shadowtls
|
||
systemctl disable shadowtls
|
||
rm -rf "${STLS_Folder}"
|
||
rm -rf "${STLS_File}"
|
||
rm -f "/etc/systemd/system/shadowtls.service"
|
||
systemctl daemon-reload
|
||
echo && echo "Shadow TLS 卸载完成!" && echo
|
||
else
|
||
echo && echo "卸载已取消..." && echo
|
||
fi
|
||
sleep 3s
|
||
}
|
||
|
||
getipv4(){
|
||
ipv4=$(wget -qO- -4 -t1 -T2 ipinfo.io/ip)
|
||
if [[ -z "${ipv4}" ]]; then
|
||
ipv4=$(wget -qO- -4 -t1 -T2 api.ip.sb/ip)
|
||
if [[ -z "${ipv4}" ]]; then
|
||
ipv4=$(wget -qO- -4 -t1 -T2 members.3322.org/dyndns/getip)
|
||
if [[ -z "${ipv4}" ]]; then
|
||
ipv4="IPv4_Error"
|
||
fi
|
||
fi
|
||
fi
|
||
}
|
||
|
||
getipv6(){
|
||
ipv6=$(wget -qO- -6 -t1 -T2 ifconfig.co)
|
||
if [[ -z "${ipv6}" ]]; then
|
||
ipv6="IPv6_Error"
|
||
fi
|
||
}
|
||
|
||
urlsafe_base64(){
|
||
date=$(echo -n "$1"|base64|sed ':a;N;s/\n/ /g;ta'|sed 's/ //g;s/=//g;s/+/-/g;s/\//_/g')
|
||
echo -e "${date}"
|
||
}
|
||
|
||
link_qr(){
|
||
if [[ "${ipv4}" != "IPv4_Error" ]]; then
|
||
SSbase64=$(urlsafe_base64 "${cipher}:${password}@${ipv4}:${port}")
|
||
SSurl="ss://${SSbase64}"
|
||
SSQRcode="https://cli.im/api/qrcode/code?text=${SSurl}"
|
||
link_ipv4=" 链接 [IPv4]:${Red_font_prefix}${SSurl}${Font_color_suffix} \n 二维码[IPv4]:${Red_font_prefix}${SSQRcode}${Font_color_suffix}"
|
||
fi
|
||
if [[ "${ipv6}" != "IPv6_Error" ]]; then
|
||
SSbase64=$(urlsafe_base64 "${cipher}:${password}@${ipv6}:${port}")
|
||
SSurl="ss://${SSbase64}"
|
||
SSQRcode="https://cli.im/api/qrcode/code?text=${SSurl}"
|
||
link_ipv6=" 链接 [IPv6]:${Red_font_prefix}${SSurl}${Font_color_suffix} \n 二维码[IPv6]:${Red_font_prefix}${SSQRcode}${Font_color_suffix}"
|
||
fi
|
||
}
|
||
|
||
before_start_menu(){
|
||
echo && echo -n " 任意键继续..." && read
|
||
start_menu
|
||
}
|
||
|
||
before_shadowtls_menu(){
|
||
echo && echo -n " 任意键继续..." && read
|
||
shadowtls_menu
|
||
}
|
||
|
||
# Shadow TLS 状态和版本检查函数
|
||
check_stls_installed_status(){
|
||
[[ ! -e ${STLS_File} ]] && echo -e "${Error} Shadow TLS 没有安装,请检查!" && exit 1
|
||
}
|
||
|
||
check_stls_status(){
|
||
stls_status=`systemctl status shadowtls | grep Active | awk '{print $3}' | cut -d "(" -f2 | cut -d ")" -f1`
|
||
}
|
||
|
||
check_stls_new_ver(){
|
||
stls_new_ver=$(wget -qO- https://api.github.com/repos/ihciah/shadow-tls/releases| jq -r '[.[] | select(.prerelease == false) | select(.draft == false) | .tag_name] | .[0]')
|
||
[[ -z ${stls_new_ver} ]] && echo -e "${Error} Shadow TLS 最新版本获取失败!" && exit 1
|
||
echo -e "${Info} 检测到 Shadow TLS 最新版本为 [ ${stls_new_ver} ]"
|
||
}
|
||
|
||
check_stls_ver_comparison(){
|
||
stls_now_ver=$(cat ${STLS_Now_ver_File})
|
||
if [[ "${stls_now_ver}" != "${stls_new_ver}" ]]; then
|
||
echo -e "${Info} 发现 Shadow TLS 已有新版本 [ ${stls_new_ver} ],旧版本 [ ${stls_now_ver} ]"
|
||
read -e -p "是否更新 ? [Y/n]:" yn
|
||
[[ -z "${yn}" ]] && yn="y"
|
||
if [[ $yn == [Yy] ]]; then
|
||
check_stls_status
|
||
\cp "${STLS_Conf}" "/tmp/stls_config.json"
|
||
download_stls
|
||
mv -f "/tmp/stls_config.json" "${STLS_Conf}"
|
||
restart_stls
|
||
fi
|
||
else
|
||
echo -e "${Info} 当前 Shadow TLS 已是最新版本 [ ${stls_new_ver} ] !" && exit 1
|
||
fi
|
||
}
|
||
|
||
# Shadow TLS 专用菜单
|
||
shadowtls_menu(){
|
||
check_root
|
||
check_sys
|
||
sys_arch
|
||
|
||
# 检查 Shadow TLS 安装状态
|
||
if [[ -e ${STLS_File} ]]; then
|
||
check_stls_status
|
||
if [[ "$stls_status" == "running" ]]; then
|
||
stls_status_show="${Green_font_prefix}已安装${Font_color_suffix} 且 ${Green_font_prefix}运行中${Font_color_suffix}"
|
||
else
|
||
stls_status_show="${Green_font_prefix}已安装${Font_color_suffix} 但 ${Yellow_font_prefix}未运行${Font_color_suffix}"
|
||
fi
|
||
else
|
||
stls_status_show="${Red_font_prefix}未安装${Font_color_suffix}"
|
||
fi
|
||
|
||
clear
|
||
echo -e "Shadow TLS 管理菜单 ${Red_font_prefix}[v${sh_ver}]${Font_color_suffix}
|
||
|
||
==================状态==================
|
||
Shadow TLS : [${stls_status_show}]
|
||
========================================
|
||
${Green_font_prefix}0.${Font_color_suffix} 更新脚本
|
||
==================菜单==================
|
||
${Green_font_prefix}1.${Font_color_suffix} 安装 Shadow TLS
|
||
${Green_font_prefix}2.${Font_color_suffix} 更新 Shadow TLS
|
||
${Green_font_prefix}3.${Font_color_suffix} 卸载 Shadow TLS
|
||
————————————————————————————————————————
|
||
${Green_font_prefix}4.${Font_color_suffix} 启动 Shadow TLS
|
||
${Green_font_prefix}5.${Font_color_suffix} 停止 Shadow TLS
|
||
${Green_font_prefix}6.${Font_color_suffix} 重启 Shadow TLS
|
||
————————————————————————————————————————
|
||
${Green_font_prefix}7.${Font_color_suffix} 修改 Shadow TLS 配置
|
||
${Green_font_prefix}8.${Font_color_suffix} 查看 Shadow TLS 配置
|
||
${Green_font_prefix}9.${Font_color_suffix} 查看 Shadow TLS 状态
|
||
————————————————————————————————————————
|
||
${Green_font_prefix}10.${Font_color_suffix} 查看完整配置信息
|
||
${Green_font_prefix}11.${Font_color_suffix} 返回主菜单
|
||
————————————————————————————————————————
|
||
${Green_font_prefix}00.${Font_color_suffix} 退出脚本
|
||
========================================" && echo
|
||
|
||
read -e -p " 请输入数字 [0-11]:" stls_num
|
||
case "$stls_num" in
|
||
1)
|
||
install_stls
|
||
shadowtls_menu
|
||
;;
|
||
2)
|
||
update_stls
|
||
shadowtls_menu
|
||
;;
|
||
3)
|
||
uninstall_stls
|
||
shadowtls_menu
|
||
;;
|
||
4)
|
||
start_stls
|
||
shadowtls_menu
|
||
;;
|
||
5)
|
||
stop_stls
|
||
shadowtls_menu
|
||
;;
|
||
6)
|
||
restart_stls
|
||
shadowtls_menu
|
||
;;
|
||
7)
|
||
set_stls_config
|
||
shadowtls_menu
|
||
;;
|
||
8)
|
||
view_stls_only
|
||
;;
|
||
9)
|
||
view_stls_status
|
||
;;
|
||
10)
|
||
view_combined_config shadowtls
|
||
;;
|
||
11)
|
||
start_menu
|
||
;;
|
||
0)
|
||
update_sh
|
||
;;
|
||
00)
|
||
exit 1
|
||
;;
|
||
*)
|
||
echo -e "${Error} 请输入正确数字 [0-11] (退出输入00)"
|
||
sleep 5s
|
||
shadowtls_menu
|
||
;;
|
||
esac
|
||
}
|
||
|
||
# 查看 Shadowsocks Rust 状态函数
|
||
view_ss_status(){
|
||
check_installed_status
|
||
|
||
echo -e "${Info} 正在获取 Shadowsocks Rust 状态信息..."
|
||
echo
|
||
echo "=================================="
|
||
echo -e " Shadowsocks Rust 服务状态"
|
||
echo "=================================="
|
||
|
||
systemctl status ss-rust
|
||
|
||
echo "=================================="
|
||
echo
|
||
read -e -p "按回车键返回主菜单..."
|
||
start_menu
|
||
}
|
||
|
||
# 查看 Shadow TLS 状态函数
|
||
view_stls_status(){
|
||
check_stls_installed_status
|
||
|
||
echo -e "${Info} 正在获取 Shadow TLS 状态信息..."
|
||
echo
|
||
echo "=================================="
|
||
echo -e " Shadow TLS 服务状态"
|
||
echo "=================================="
|
||
|
||
systemctl status shadowtls
|
||
|
||
echo "=================================="
|
||
echo
|
||
read -e -p "按回车键返回 Shadow TLS 菜单..."
|
||
shadowtls_menu
|
||
}
|
||
|
||
# 查看 Shadow TLS 配置函数
|
||
view_stls_only(){
|
||
check_stls_installed_status
|
||
echo -e "${Info} 正在获取 Shadow TLS 配置信息..."
|
||
echo
|
||
echo "=================================="
|
||
echo -e " Shadow TLS 配置信息"
|
||
echo "=================================="
|
||
|
||
if [[ -f "$STLS_Conf" ]]; then
|
||
cat "$STLS_Conf"
|
||
else
|
||
echo -e "${Error} Shadow TLS 配置文件不存在!"
|
||
fi
|
||
|
||
echo "=================================="
|
||
echo
|
||
read -e -p "按回车键返回 Shadow TLS 菜单..."
|
||
shadowtls_menu
|
||
}
|
||
|
||
# 主菜单函数
|
||
start_menu(){
|
||
echo -e "${Info} 正在启动 Shadowsocks Rust 管理脚本..."
|
||
check_root
|
||
echo -e "${Info} 权限检查完成,正在检测系统..."
|
||
check_sys
|
||
echo -e "${Info} 系统检测完成,正在检测架构..."
|
||
sys_arch
|
||
echo -e "${Info} 架构检测完成,正在检查服务状态..."
|
||
|
||
# 检查安装状态
|
||
if [[ -e ${SS_File} ]]; then
|
||
check_status
|
||
if [[ "$status" == "running" ]]; then
|
||
ss_status_show="${Green_font_prefix}已安装${Font_color_suffix} 且 ${Green_font_prefix}运行中${Font_color_suffix}"
|
||
else
|
||
ss_status_show="${Green_font_prefix}已安装${Font_color_suffix} 但 ${Yellow_font_prefix}未运行${Font_color_suffix}"
|
||
fi
|
||
else
|
||
ss_status_show="${Red_font_prefix}未安装${Font_color_suffix}"
|
||
fi
|
||
|
||
# 检查 Shadow TLS 安装状态
|
||
if [[ -e ${STLS_File} ]]; then
|
||
check_stls_status
|
||
if [[ "$stls_status" == "running" ]]; then
|
||
stls_status_show="${Green_font_prefix}已安装${Font_color_suffix} 且 ${Green_font_prefix}运行中${Font_color_suffix}"
|
||
else
|
||
stls_status_show="${Green_font_prefix}已安装${Font_color_suffix} 但 ${Yellow_font_prefix}未运行${Font_color_suffix}"
|
||
fi
|
||
else
|
||
stls_status_show="${Red_font_prefix}未安装${Font_color_suffix}"
|
||
fi
|
||
|
||
clear
|
||
echo -e "Shadowsocks Rust 管理脚本 ${Red_font_prefix}[v${sh_ver}]${Font_color_suffix}
|
||
|
||
==================状态==================
|
||
Shadowsocks Rust : [${ss_status_show}]
|
||
Shadow TLS : [${stls_status_show}]
|
||
========================================
|
||
${Green_font_prefix}0.${Font_color_suffix} 更新脚本
|
||
==================菜单==================
|
||
${Green_font_prefix}1.${Font_color_suffix} 安装 Shadowsocks Rust
|
||
${Green_font_prefix}2.${Font_color_suffix} 更新 Shadowsocks Rust
|
||
${Green_font_prefix}3.${Font_color_suffix} 卸载 Shadowsocks Rust
|
||
————————————————————————————————————————
|
||
${Green_font_prefix}4.${Font_color_suffix} 启动 Shadowsocks Rust
|
||
${Green_font_prefix}5.${Font_color_suffix} 停止 Shadowsocks Rust
|
||
${Green_font_prefix}6.${Font_color_suffix} 重启 Shadowsocks Rust
|
||
————————————————————————————————————————
|
||
${Green_font_prefix}7.${Font_color_suffix} 配置 Shadowsocks Rust 相关
|
||
${Green_font_prefix}8.${Font_color_suffix} 查看 Shadowsocks Rust 配置
|
||
${Green_font_prefix}9.${Font_color_suffix} 查看 Shadowsocks Rust 状态
|
||
========================================
|
||
${Green_font_prefix}10.${Font_color_suffix} 配置 Shadow TLS 相关
|
||
${Green_font_prefix}11.${Font_color_suffix} 查看完整配置信息
|
||
————————————————————————————————————————
|
||
${Green_font_prefix}00.${Font_color_suffix} 退出脚本
|
||
========================================" && echo
|
||
read -e -p " 请输入数字 [0-11]:" num
|
||
case "$num" in
|
||
1)
|
||
install
|
||
;;
|
||
2)
|
||
update
|
||
start_menu
|
||
;;
|
||
3)
|
||
uninstall
|
||
start_menu
|
||
;;
|
||
4)
|
||
start
|
||
start_menu
|
||
;;
|
||
5)
|
||
stop
|
||
start_menu
|
||
;;
|
||
6)
|
||
restart
|
||
start_menu
|
||
;;
|
||
7)
|
||
set_config
|
||
;;
|
||
8)
|
||
view
|
||
;;
|
||
9)
|
||
view_ss_status
|
||
;;
|
||
10)
|
||
shadowtls_menu
|
||
;;
|
||
11)
|
||
view_combined_config
|
||
;;
|
||
0)
|
||
update_sh
|
||
;;
|
||
00)
|
||
exit 1
|
||
;;
|
||
*)
|
||
echo -e "${Error} 请输入正确数字 [0-11] (退出输入00)"
|
||
sleep 5s
|
||
start_menu
|
||
;;
|
||
esac
|
||
}
|
||
|
||
# 脚本执行入口
|
||
start_menu
|