Files
clash-for-linux-install/script/common.sh
T

340 lines
11 KiB
Bash
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/bin/bash
# shellcheck disable=SC2034
# shellcheck disable=SC2155
[ -n "$BASH_VERSION" ] && set +o noglob
[ -n "$ZSH_VERSION" ] && setopt glob
URL_GH_PROXY='https://gh-proxy.com/'
URL_CLASH_UI="http://board.zash.run.place"
SCRIPT_BASE_DIR='./script'
RESOURCES_BASE_DIR='./resources'
RESOURCES_CONFIG="${RESOURCES_BASE_DIR}/config.yaml"
RESOURCES_CONFIG_MIXIN="${RESOURCES_BASE_DIR}/mixin.yaml"
ZIP_BASE_DIR="${RESOURCES_BASE_DIR}/zip"
ZIP_CLASH="${ZIP_BASE_DIR}/clash*.gz"
ZIP_MIHOMO="${ZIP_BASE_DIR}/mihomo*.gz"
ZIP_YQ="${ZIP_BASE_DIR}/yq*.tar.gz"
ZIP_SUBCONVERTER="${ZIP_BASE_DIR}/subconverter*.tar.gz"
ZIP_UI="${ZIP_BASE_DIR}/yacd.tar.xz"
CLASH_BASE_DIR='/opt/clash'
CLASH_SCRIPT_DIR="${CLASH_BASE_DIR}/$(basename $SCRIPT_BASE_DIR)"
CLASH_CONFIG_URL="${CLASH_BASE_DIR}/url"
CLASH_CONFIG_RAW="${CLASH_BASE_DIR}/$(basename $RESOURCES_CONFIG)"
CLASH_CONFIG_RAW_BAK="${CLASH_CONFIG_RAW}.bak"
CLASH_CONFIG_MIXIN="${CLASH_BASE_DIR}/$(basename $RESOURCES_CONFIG_MIXIN)"
CLASH_CONFIG_RUNTIME="${CLASH_BASE_DIR}/runtime.yaml"
CLASH_UPDATE_LOG="${CLASH_BASE_DIR}/clashupdate.log"
BIN_BASE_DIR="${CLASH_BASE_DIR}/bin"
BIN_CLASH="${BIN_BASE_DIR}/clash"
BIN_MIHOMO="${BIN_BASE_DIR}/mihomo"
BIN_YQ="${BIN_BASE_DIR}/yq"
BIN_SUBCONVERTER_DIR="${BIN_BASE_DIR}/subconverter"
BIN_SUBCONVERTER_CONFIG="$BIN_SUBCONVERTER_DIR/pref.yml"
BIN_SUBCONVERTER_PORT="25500"
BIN_SUBCONVERTER="${BIN_SUBCONVERTER_DIR}/subconverter"
BIN_SUBCONVERTER_LOG="${BIN_SUBCONVERTER_DIR}/latest.log"
_get_var() {
# 定时任务路径
{
local os_info=$(cat /etc/os-release)
echo "$os_info" | grep -iqsE "rhel|centos" && {
CLASH_CRON_TAB="/var/spool/cron/root"
}
echo "$os_info" | grep -iqsE "debian|ubuntu" && {
CLASH_CRON_TAB="/var/spool/cron/crontabs/root"
}
}
# rc文件路径
{
local home=$HOME
[ -n "$SUDO_USER" ] && home=$(awk -F: -v user="$SUDO_USER" '$1==user{print $6}' /etc/passwd)
BASH_RC_ROOT='/root/.bashrc'
BASH_RC_USER="${home}/.bashrc"
}
# 内核bin路径
{
[ -f "$BIN_MIHOMO" ] && {
BIN_KERNEL=$BIN_MIHOMO
}
[ -f "$BIN_CLASH" ] && {
BIN_KERNEL=$BIN_CLASH
}
BIN_KERNEL_NAME=$(basename "$BIN_KERNEL")
}
}
_get_var
# shellcheck disable=SC2086
_set_rc() {
[ "$BASH_RC_ROOT" = "$BASH_RC_USER" ] && unset BASH_RC_USER
case "$1" in
set)
[ -n "$(tail -n 1 "$BASH_RC_ROOT")" ] && echo >>"$BASH_RC_ROOT"
[ -n "$(tail -n 1 "$BASH_RC_USER" >&/dev/null)" ] && echo >>"$BASH_RC_USER"
echo "source $CLASH_SCRIPT_DIR/common.sh && source $CLASH_SCRIPT_DIR/clashctl.sh" |
tee -a $BASH_RC_ROOT $BASH_RC_USER >&/dev/null
;;
unset)
sed -i "\|$CLASH_SCRIPT_DIR|d" $BASH_RC_ROOT $BASH_RC_USER
;;
esac
}
# 默认集成、安装mihomo内核
# 移除/删除mihomo:下载安装clash内核
# shellcheck disable=SC2086
function _get_kernel() {
[ -f $ZIP_CLASH ] && {
ZIP_KERNEL=$ZIP_CLASH
BIN_KERNEL=$BIN_CLASH
}
[ -f $ZIP_MIHOMO ] && {
ZIP_KERNEL=$ZIP_MIHOMO
BIN_KERNEL=$BIN_MIHOMO
}
[ ! -f $ZIP_MIHOMO ] && [ ! -f $ZIP_CLASH ] && {
local arch=$(uname -m)
_failcat "${ZIP_BASE_DIR}:未检测到可用的内核压缩包"
_download_clash "$arch"
ZIP_KERNEL=$ZIP_CLASH
BIN_KERNEL=$BIN_CLASH
}
BIN_KERNEL_NAME=$(basename "$BIN_KERNEL")
_okcat "安装内核:$BIN_KERNEL_NAME"
}
_get_random_port() {
local randomPort
while :; do
randomPort=$((RANDOM % 64512 + 1024))
grep -q "$(printf ":%04X" $randomPort)" /proc/net/tcp || {
echo $randomPort
break
}
done
}
function _get_kernel_port() {
local mixed_port=$(sudo $BIN_YQ '.mixed-port // ""' $CLASH_CONFIG_RUNTIME)
local ext_addr=$(sudo $BIN_YQ '.external-controller // ""' $CLASH_CONFIG_RUNTIME)
local ext_port=${ext_addr##*:}
MIXED_PORT=${mixed_port:-7890}
UI_PORT=${ext_port:-9090}
# 端口占用场景
local port
for port in $MIXED_PORT $UI_PORT; do
_is_bind "$port" && {
[ "$port" = "$MIXED_PORT" ] && {
local newPort=$(_get_random_port)
local msg="端口占用:${MIXED_PORT} 🎲 随机分配:$newPort"
sudo "$BIN_YQ" -i ".mixed-port = $newPort" $CLASH_CONFIG_RUNTIME
MIXED_PORT=$newPort
_failcat '🎯' "$msg"
continue
}
[ "$port" = "$UI_PORT" ] && {
newPort=$(_get_random_port)
msg="端口占用:${UI_PORT} 🎲 随机分配:$newPort"
sudo "$BIN_YQ" -i ".external-controller = \"0.0.0.0:$newPort\"" $CLASH_CONFIG_RUNTIME
UI_PORT=$newPort
_failcat '🎯' "$msg"
}
}
done
}
function _get_color() {
local hex="${1#\#}"
local r=$((16#${hex:0:2}))
local g=$((16#${hex:2:2}))
local b=$((16#${hex:4:2}))
printf "\e[38;2;%d;%d;%dm" "$r" "$g" "$b"
}
_get_color_msg() {
local color=$(_get_color "$1")
local msg=$2
local reset="\033[0m"
printf "%b%s%b\n" "$color" "$msg" "$reset"
}
function _okcat() {
local color=#c8d6e5
local emoji=😼
[ $# -gt 1 ] && emoji=$1 && shift
local msg="${emoji} $1"
_get_color_msg "$color" "$msg" && return 0
}
function _failcat() {
local color=#fd79a8
local emoji=😾
[ $# -gt 1 ] && emoji=$1 && shift
local msg="${emoji} $1"
_get_color_msg "$color" "$msg" >&2 && return 1
}
function _error_quit() {
[ $# -gt 0 ] && {
local color=#f92f60
local emoji=📢
[ $# -gt 1 ] && emoji=$1 && shift
local msg="${emoji} $1"
_get_color_msg "$color" "$msg"
}
exec $SHELL
}
_is_bind() {
sudo awk '{print $2}' /proc/net/tcp | grep -qsi ":$(printf "%x" "$1")"
}
function _is_root() {
[ "$(whoami)" = "root" ]
}
function _valid_env() {
_is_root || _error_quit "需要 root 或 sudo 权限执行"
[ "$(ps -p $$ -o comm=)" != "bash" ] && _error_quit "当前终端不是 bash"
[ "$(ps -p 1 -o comm=)" != "systemd" ] && _error_quit "系统不具备 systemd"
}
function _valid_config() {
[ -e "$1" ] && [ "$(wc -l <"$1")" -gt 1 ] && {
local test_cmd="$BIN_KERNEL -d $(dirname "$1") -f $1 -t"
local fail_msg
fail_msg=$($test_cmd) || {
$test_cmd
echo "$fail_msg" | grep -qs "unsupport proxy type" && _error_quit "不支持的代理协议,请安装 mihomo 内核"
}
}
}
_download_clash() {
local arch=$1
local url sha256sum
case "$arch" in
x86_64)
url=https://downloads.clash.wiki/ClashPremium/clash-linux-amd64-2023.08.17.gz
sha256sum='92380f053f083e3794c1681583be013a57b160292d1d9e1056e7fa1c2d948747'
;;
*86*)
url=https://downloads.clash.wiki/ClashPremium/clash-linux-386-2023.08.17.gz
sha256sum='254125efa731ade3c1bf7cfd83ae09a824e1361592ccd7c0cccd2a266dcb92b5'
;;
armv*)
url=https://downloads.clash.wiki/ClashPremium/clash-linux-armv5-2023.08.17.gz
sha256sum='622f5e774847782b6d54066f0716114a088f143f9bdd37edf3394ae8253062e8'
;;
aarch64)
url=https://downloads.clash.wiki/ClashPremium/clash-linux-arm64-2023.08.17.gz
sha256sum='c45b39bb241e270ae5f4498e2af75cecc0f03c9db3c0db5e55c8c4919f01afdd'
;;
*)
_error_quit "未知的架构版本:$arch,请自行下载对应版本至 ${ZIP_BASE_DIR} 目录下:https://downloads.clash.wiki/ClashPremium/"
;;
esac
_okcat '⏳' "正在下载:clash:${arch} 架构..."
local clash_zip="${ZIP_BASE_DIR}/$(basename $url)"
curl \
--progress-bar \
--show-error \
--fail \
--insecure \
--connect-timeout 15 \
--retry 1 \
--output "$clash_zip" \
"$url"
echo $sha256sum "$clash_zip" | sha256sum -c ||
_error_quit "下载失败:请自行下载对应版本至 ${ZIP_BASE_DIR} 目录下:https://downloads.clash.wiki/ClashPremium/"
}
function _download_config() {
_download_raw_config() {
local dest=$1
local url=$2
local agent='Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:130.0) Gecko/20100101 Firefox/130.0'
sudo curl \
--silent \
--show-error \
--insecure \
--connect-timeout 4 \
--retry 1 \
--user-agent "$agent" \
--output "$dest" \
"$url" ||
sudo wget \
--no-verbose \
--no-check-certificate \
--timeout 3 \
--tries 1 \
--user-agent "$agent" \
--output-document "$dest" \
"$url"
}
_download_convert_config() {
local dest=$1
local url=$2
_start_convert
local convert_url=$(
target='clash'
base_url="http://127.0.0.1:${BIN_SUBCONVERTER_PORT}/sub"
curl \
--get \
--silent \
--output /dev/null \
--data-urlencode "target=$target" \
--data-urlencode "url=$url" \
--write-out '%{url_effective}' \
"$base_url"
)
_download_raw_config "$dest" "$convert_url"
_stop_convert
}
local dest=$1
local url=$2
[ "${url:0:4}" = 'file' ] && return 0
_download_raw_config "$dest" "$url" || return 1
_okcat '🍃' '下载成功:内核验证配置...'
_valid_config "$dest" || {
_failcat '🍂' "验证失败:尝试订阅转换..."
_download_convert_config "$dest" "$url" || _failcat '🍂' "转换失败:请检查日志:$BIN_SUBCONVERTER_LOG"
}
}
_start_convert() {
_is_bind $BIN_SUBCONVERTER_PORT && {
local newPort=$(_get_random_port)
_failcat '🎯' "端口占用:$BIN_SUBCONVERTER_PORT 🎲 随机分配:$newPort"
[ ! -e $BIN_SUBCONVERTER_CONFIG ] && {
sudo /bin/mv -f $BIN_SUBCONVERTER_DIR/pref.example.yml $BIN_SUBCONVERTER_CONFIG
}
sudo $BIN_YQ -i ".server.port = $newPort" $BIN_SUBCONVERTER_CONFIG
BIN_SUBCONVERTER_PORT=$newPort
}
local start=$(date +%s)
# 子shell运行,屏蔽kill时的输出
(sudo $BIN_SUBCONVERTER 2>&1 | sudo tee $BIN_SUBCONVERTER_LOG >/dev/null &)
while ! _is_bind "$BIN_SUBCONVERTER_PORT" >&/dev/null; do
sleep 0.05s
local now=$(date +%s)
[ $((now - start)) -gt 1 ] && _error_quit "订阅转换服务未启动,请检查日志:$BIN_SUBCONVERTER_LOG"
done
}
_stop_convert() {
pkill -9 -f $BIN_SUBCONVERTER >&/dev/null
}