557 lines
20 KiB
Bash
557 lines
20 KiB
Bash
#!/bin/bash
|
||
# 批量搭建ss2022入站到sk5出站代理
|
||
# 读取sk5文件实现批量导入出站
|
||
# 作者sky22333
|
||
|
||
red='\e[31m'
|
||
yellow='\e[33m'
|
||
green='\e[32m'
|
||
none='\e[0m'
|
||
config_file="/usr/local/etc/xray/config.json"
|
||
default_config='
|
||
{
|
||
"inbounds": [
|
||
{
|
||
"port": 9999,
|
||
"protocol": "shadowsocks",
|
||
"settings": {
|
||
"method": "2022-blake3-aes-256-gcm",
|
||
"password": "75ENbpfSCyzUdZnLRjVGexaQxVPdCLw5T4RXbTGRQ/Q=",
|
||
"network": "tcp,udp"
|
||
},
|
||
"tag": "inbound0"
|
||
}
|
||
],
|
||
"outbounds": [
|
||
{
|
||
"protocol": "socks",
|
||
"settings": {
|
||
"servers": [
|
||
{
|
||
"address": "127.0.0.2",
|
||
"port": 2222,
|
||
"users": [
|
||
{
|
||
"user": "admin123",
|
||
"pass": "admin333"
|
||
}
|
||
]
|
||
}
|
||
]
|
||
},
|
||
"tag": "outbound0"
|
||
}
|
||
],
|
||
"routing": {
|
||
"rules": [
|
||
{
|
||
"type": "field",
|
||
"inboundTag": ["inbound0"],
|
||
"outboundTag": "outbound0"
|
||
}
|
||
]
|
||
}
|
||
}
|
||
'
|
||
|
||
check_and_install_curl() {
|
||
if ! type curl &>/dev/null; then
|
||
echo -e "${yellow}正在安装curl...${none}"
|
||
apt update && apt install -yq curl
|
||
fi
|
||
}
|
||
|
||
check_and_install_jq() {
|
||
if ! type jq &>/dev/null; then
|
||
echo -e "${yellow}正在安装jq...${none}"
|
||
apt update && apt install -yq jq
|
||
fi
|
||
}
|
||
|
||
check_and_install_openssl() {
|
||
if ! type openssl &>/dev/null; then
|
||
echo -e "${yellow}正在安装 openssl...${none}"
|
||
apt update && apt install -yq openssl
|
||
fi
|
||
}
|
||
|
||
check_and_install_xray() {
|
||
if ! type xray &>/dev/null; then
|
||
echo -e "${yellow}正在安装 xray...${none}"
|
||
sudo ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
|
||
bash <(curl -L https://github.com/XTLS/Xray-install/raw/main/install-release.sh) install --version v1.8.13
|
||
fi
|
||
}
|
||
|
||
check_existing_inbound_config() {
|
||
if grep -q '"tag":' "$config_file"; then
|
||
return 0
|
||
else
|
||
return 1
|
||
fi
|
||
}
|
||
|
||
create_default_config() {
|
||
if ! check_existing_inbound_config; then
|
||
echo "$default_config" > "$config_file"
|
||
echo -e "${green}已创建默认配置文件。${none}"
|
||
else
|
||
echo -e "${yellow}入站配置已存在,跳过创建默认配置文件。${none}"
|
||
fi
|
||
}
|
||
|
||
get_local_ip() {
|
||
local ip=$(curl -s http://ipinfo.io/ip)
|
||
if [[ $ip =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
|
||
echo "$ip"
|
||
else
|
||
echo "无法自动获取公网IP地址,请手动输入。"
|
||
read -p "请输入您的公网IP地址: " manual_ip
|
||
if [[ $manual_ip =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
|
||
echo "$manual_ip"
|
||
else
|
||
echo "输入的IP地址格式不正确,请重新运行脚本并输入有效的公网IP地址。"
|
||
exit 1
|
||
fi
|
||
fi
|
||
}
|
||
|
||
get_ss_filename() {
|
||
local timestamp=$(date +"%Y%m%d-%H点%M分%S秒")
|
||
echo "/home/${timestamp}-ss.txt"
|
||
}
|
||
|
||
generate_ss_link() {
|
||
local server=$1
|
||
local port=$2
|
||
local method=$3
|
||
local password=$4
|
||
local ps=$5
|
||
|
||
local password_urlencoded=$(echo -n "$password" | xxd -p | tr -d '\n' | sed 's/\(..\)/%\1/g')
|
||
|
||
local base64_part=$(echo -n "${method}:${password}" | base64 -w 0)
|
||
echo "ss://${base64_part}@${server}:${port}#${ps}"
|
||
}
|
||
|
||
save_multiple_ss_links() {
|
||
local local_ip=$1
|
||
shift
|
||
local ss_file=$(get_ss_filename)
|
||
|
||
> "$ss_file"
|
||
|
||
while [[ $# -gt 0 ]]; do
|
||
local port=$1
|
||
local password=$2
|
||
local method=$3
|
||
local index=$4
|
||
shift 4
|
||
local sk5_ip=$(jq -r ".outbounds | map(select(.tag == \"outbound${port}\")) | .[0].settings.servers[0].address" "$config_file")
|
||
if [[ -z "$sk5_ip" ]]; then
|
||
sk5_ip="未知IP"
|
||
fi
|
||
|
||
local ss_link=$(generate_ss_link "$local_ip" "$port" "$method" "$password" "$sk5_ip")
|
||
|
||
echo "$ss_link" >> "$ss_file"
|
||
done
|
||
|
||
echo -e "${green}已将操作的所有节点保存至 $ss_file${none}"
|
||
}
|
||
|
||
save_multiple_ss_links_with_ps() {
|
||
local local_ip=$1
|
||
shift
|
||
local ss_file=$(get_ss_filename)
|
||
|
||
> "$ss_file"
|
||
|
||
while [[ $# -gt 0 ]]; do
|
||
local port=$1
|
||
local password=$2
|
||
local method=$3
|
||
local index=$4
|
||
local sk5_ip=$5
|
||
shift 5
|
||
|
||
local ss_link=$(generate_ss_link "$local_ip" "$port" "$method" "$password" "$sk5_ip")
|
||
|
||
echo "$ss_link" >> "$ss_file"
|
||
done
|
||
|
||
echo -e "${green}已将操作的所有节点保存至 $ss_file${none}"
|
||
}
|
||
|
||
save_all_ss_links() {
|
||
local local_ip=$(get_local_ip)
|
||
local ss_file=$(get_ss_filename)
|
||
|
||
> "$ss_file"
|
||
|
||
local config=$(jq '.inbounds | map(select(.port != 9999))' "$config_file")
|
||
local length=$(jq '. | length' <<< "$config")
|
||
|
||
for ((i = 0; i < length; i++)); do
|
||
local port=$(jq -r ".[$i].port" <<< "$config")
|
||
local method=$(jq -r ".[$i].settings.method" <<< "$config")
|
||
local password=$(jq -r ".[$i].settings.password" <<< "$config")
|
||
|
||
local sk5_ip=$(jq -r ".outbounds | map(select(.tag == \"outbound${port}\")) | .[0].settings.servers[0].address" "$config_file")
|
||
if [[ -z "$sk5_ip" ]]; then
|
||
sk5_ip="未知IP"
|
||
fi
|
||
|
||
# 生成SS链接
|
||
local ss_link=$(generate_ss_link "$local_ip" "$port" "$method" "$password" "$sk5_ip")
|
||
|
||
# 写入文件
|
||
echo "$ss_link" >> "$ss_file"
|
||
done
|
||
|
||
echo -e "${green}已将全部Shadowsocks节点保存至 $ss_file${none}"
|
||
}
|
||
|
||
show_inbound_configs() {
|
||
local local_ip=$(get_local_ip)
|
||
|
||
local config=$(jq '.inbounds | map(select(.port != 9999))' "$config_file")
|
||
local outbounds=$(jq '.outbounds' "$config_file")
|
||
echo -e "${green}入站节点配置:${none}"
|
||
|
||
local length=$(jq '. | length' <<< "$config")
|
||
for ((i = 0; i < length; i++)); do
|
||
local port=$(jq -r ".[$i].port" <<< "$config")
|
||
local method=$(jq -r ".[$i].settings.method" <<< "$config")
|
||
local password=$(jq -r ".[$i].settings.password" <<< "$config")
|
||
|
||
local node_address="$local_ip"
|
||
|
||
local sk5_ip=$(jq -r ".outbounds | map(select(.tag == \"outbound${port}\")) | .[0].settings.servers[0].address" "$config_file")
|
||
if [[ -z "$sk5_ip" ]]; then
|
||
sk5_ip="未知IP"
|
||
fi
|
||
|
||
local ss_link=$(generate_ss_link "$node_address" "$port" "$method" "$password" "$sk5_ip")
|
||
|
||
echo -e "${yellow}节点: $(($i + 1))${none} - 端口: ${port}, Shadowsocks 链接: ${ss_link}"
|
||
|
||
# 构造出站配置的标签
|
||
local outbound_tag="outbound$port"
|
||
|
||
# 根据构造的标签查找对应的出站配置
|
||
local outbound_config=$(jq --arg tag "$outbound_tag" '.[] | select(.tag == $tag) | .settings.servers[] | {address, port, user: .users[0].user, pass: .users[0].pass}' <<< "$outbounds")
|
||
|
||
if [[ ! -z $outbound_config ]]; then
|
||
echo -e "${green}出站配置:${none} 地址: $(jq -r '.address' <<< "$outbound_config"), 端口: $(jq -r '.port' <<< "$outbound_config"), 用户名: $(jq -r '.user' <<< "$outbound_config"), 密码: $(jq -r '.pass' <<< "$outbound_config")"
|
||
else
|
||
echo -e "${red}未找到对应的出站配置。${none}"
|
||
fi
|
||
done
|
||
|
||
save_all_ss_links
|
||
}
|
||
|
||
add_new_nodes() {
|
||
local sk5_file="/home/sk5.txt"
|
||
|
||
# 检查sk5.txt文件是否存在
|
||
if [ ! -f "$sk5_file" ]; then
|
||
echo -e "${red}错误!${none} $sk5_file 文件不存在。"
|
||
return
|
||
fi
|
||
|
||
# 读取sk5.txt文件中的代理信息
|
||
local sk5_proxies=()
|
||
while IFS= read -r line || [[ -n "$line" ]]; do
|
||
# 忽略空行
|
||
if [[ -z "$line" ]]; then
|
||
continue
|
||
fi
|
||
sk5_proxies+=("$line")
|
||
done < "$sk5_file"
|
||
|
||
local proxy_count=${#sk5_proxies[@]}
|
||
if [ $proxy_count -eq 0 ]; then
|
||
echo -e "${red}错误!${none} 未在 $sk5_file 中找到有效的代理配置。"
|
||
return
|
||
fi
|
||
|
||
echo -e "${green}从 $sk5_file 读取到 $proxy_count 个代理配置。${none}"
|
||
read -p "是否要导入全部配置?(y/n): " confirm
|
||
|
||
if [[ "$confirm" != "y" && "$confirm" != "Y" ]]; then
|
||
read -p "请输入要导入的代理数量 (最大 $proxy_count): " num_to_import
|
||
if ! [[ $num_to_import =~ ^[0-9]+$ ]] || [ $num_to_import -le 0 ] || [ $num_to_import -gt $proxy_count ]; then
|
||
echo -e "${red}错误!${none} 输入数量无效。"
|
||
return
|
||
fi
|
||
else
|
||
num_to_import=$proxy_count
|
||
fi
|
||
|
||
local max_port=$(jq '[.inbounds[].port] | max // 10000' "$config_file")
|
||
local start_port=$((max_port+1))
|
||
local local_ip=$(get_local_ip)
|
||
local nodes_to_save=()
|
||
|
||
for ((i=0; i<num_to_import; i++)); do
|
||
local new_port=$((start_port+i))
|
||
local new_tag="inbound$new_port"
|
||
local new_outbound_tag="outbound$new_port"
|
||
# 为Shadowsocks 2022生成密钥
|
||
local new_password=$(openssl rand -base64 32)
|
||
local method="2022-blake3-aes-256-gcm" # 使用默认的Shadowsocks 2022加密方法
|
||
|
||
# 解析代理信息 (格式: IP:端口:用户名:密码)
|
||
IFS=':' read -r outbound_addr outbound_port outbound_user outbound_pass <<< "${sk5_proxies[$i]}"
|
||
|
||
if [[ -z "$outbound_addr" || -z "$outbound_port" || -z "$outbound_user" || -z "$outbound_pass" ]]; then
|
||
echo -e "${red}警告:${none} 代理 #$((i+1)) 格式无效,终止脚本运行: ${sk5_proxies[$i]}"
|
||
exit 1
|
||
fi
|
||
|
||
echo -e "${yellow}配置入站端口 $new_port 连接到代理 $outbound_addr:$outbound_port${none}"
|
||
|
||
# 添加Shadowsocks入站配置
|
||
jq --argjson port "$new_port" --arg password "$new_password" --arg method "$method" --arg tag "$new_tag" '
|
||
.inbounds += [{
|
||
listen: "0.0.0.0",
|
||
port: $port,
|
||
protocol: "shadowsocks",
|
||
settings: {
|
||
method: $method,
|
||
password: $password,
|
||
network: "tcp,udp"
|
||
},
|
||
tag: $tag
|
||
}]' "$config_file" > "$config_file.tmp" && mv "$config_file.tmp" "$config_file"
|
||
|
||
# 添加出站配置
|
||
jq --arg tag "$new_outbound_tag" --arg addr "$outbound_addr" --argjson port "$outbound_port" --arg user "$outbound_user" --arg pass "$outbound_pass" '
|
||
.outbounds += [{
|
||
protocol: "socks",
|
||
settings: { servers: [{ address: $addr, port: $port | tonumber, users: [{ user: $user, pass: $pass }] }] },
|
||
tag: $tag
|
||
}]' "$config_file" > "$config_file.tmp" && mv "$config_file.tmp" "$config_file"
|
||
|
||
# 添加路由规则
|
||
jq --arg inTag "$new_tag" --arg outTag "$new_outbound_tag" '
|
||
.routing.rules += [{ type: "field", inboundTag: [$inTag], outboundTag: $outTag }]
|
||
' "$config_file" > "$config_file.tmp" && mv "$config_file.tmp" "$config_file"
|
||
|
||
# 保存节点信息以便后续生成SS链接
|
||
nodes_to_save+=("$new_port" "$new_password" "$method" "$((i+1))")
|
||
done
|
||
|
||
# 保存所有新添加的节点到一个文件
|
||
save_multiple_ss_links "$local_ip" "${nodes_to_save[@]}"
|
||
|
||
echo -e "${green}已成功添加 $num_to_import 个节点。${none}"
|
||
sudo systemctl restart xray
|
||
echo -e "${green}Xray 服务已重新启动。${none}"
|
||
}
|
||
|
||
# 根据xiugai.txt文件修改SOCKS5出站代理
|
||
modify_socks5_outbound() {
|
||
local modify_file="/home/xiugai.txt"
|
||
|
||
# 检查xiugai.txt文件是否存在
|
||
if [ ! -f "$modify_file" ]; then
|
||
echo -e "${red}错误!${none} $modify_file 文件不存在。"
|
||
return
|
||
fi
|
||
|
||
# 读取xiugai.txt文件中的代理信息
|
||
local modify_proxies=()
|
||
while IFS= read -r line || [[ -n "$line" ]]; do
|
||
# 忽略空行
|
||
if [[ -z "$line" ]]; then
|
||
continue
|
||
fi
|
||
modify_proxies+=("$line")
|
||
done < "$modify_file"
|
||
|
||
# 检查是否读取到代理
|
||
local proxy_count=${#modify_proxies[@]}
|
||
if [ $proxy_count -eq 0 ]; then
|
||
echo -e "${red}错误!${none} 未在 $modify_file 中找到有效的代理配置。"
|
||
return
|
||
fi
|
||
|
||
echo -e "${green}从 $modify_file 读取到 $proxy_count 个代理配置。${none}"
|
||
local local_ip=$(get_local_ip)
|
||
local nodes_to_save=()
|
||
|
||
# 处理每个要修改的代理
|
||
for proxy in "${modify_proxies[@]}"; do
|
||
IFS=':' read -r old_ip new_port new_user new_pass <<< "$proxy"
|
||
|
||
if [[ -z "$old_ip" || -z "$new_port" || -z "$new_user" || -z "$new_pass" ]]; then
|
||
echo -e "${red}警告:${none} 代理格式无效,终止脚本运行: $proxy"
|
||
exit 1
|
||
fi
|
||
|
||
# 查找匹配的出站节点
|
||
local outbound_config=$(jq --arg ip "$old_ip" '.outbounds[] | select(.protocol == "socks" and .settings.servers[0].address == $ip) | {tag: .tag, address: .settings.servers[0].address, port: .settings.servers[0].port, user: .settings.servers[0].users[0].user, pass: .settings.servers[0].users[0].pass}' "$config_file")
|
||
|
||
if [[ -z "$outbound_config" ]]; then
|
||
echo -e "${red}警告:${none} 未找到IP地址为 $old_ip 的SOCKS5出站节点,终止脚本运行"
|
||
exit 1
|
||
fi
|
||
|
||
local tag=$(echo "$outbound_config" | jq -r '.tag')
|
||
local old_port=$(echo "$outbound_config" | jq -r '.port')
|
||
local old_user=$(echo "$outbound_config" | jq -r '.user')
|
||
local old_pass=$(echo "$outbound_config" | jq -r '.pass')
|
||
|
||
echo -e "${yellow}找到匹配的出站节点:${none} 标签=$tag, 旧IP=$old_ip, 旧端口=$old_port, 旧用户名=$old_user, 旧密码=$old_pass"
|
||
echo -e "${green}将更新为:${none} 新IP=$old_ip, 新端口=$new_port, 新用户名=$new_user, 新密码=$new_pass"
|
||
|
||
# 更新SOCKS5出站配置
|
||
local temp_file=$(mktemp)
|
||
jq --arg tag "$tag" \
|
||
--arg ip "$old_ip" \
|
||
--arg port "$new_port" \
|
||
--arg user "$new_user" \
|
||
--arg pass "$new_pass" \
|
||
'(.outbounds[] | select(.tag == $tag) | .settings.servers[0].address) = $ip |
|
||
(.outbounds[] | select(.tag == $tag) | .settings.servers[0].port) = ($port | tonumber) |
|
||
(.outbounds[] | select(.tag == $tag) | .settings.servers[0].users[0].user) = $user |
|
||
(.outbounds[] | select(.tag == $tag) | .settings.servers[0].users[0].pass) = $pass' \
|
||
"$config_file" > "$temp_file"
|
||
|
||
if [ $? -eq 0 ] && [ -s "$temp_file" ]; then
|
||
mv "$temp_file" "$config_file"
|
||
echo -e "${green}成功修改SOCKS5出站节点配置!${none}"
|
||
|
||
# 查找对应的入站配置并保存节点信息
|
||
local inbound_port=${tag//outbound/}
|
||
local inbound_config=$(jq --arg port "$inbound_port" '.inbounds[] | select(.port == ($port | tonumber))' "$config_file")
|
||
if [[ -n "$inbound_config" ]]; then
|
||
local method=$(echo "$inbound_config" | jq -r '.settings.method')
|
||
local password=$(echo "$inbound_config" | jq -r '.settings.password')
|
||
local index=$(jq --arg port "$inbound_port" '.inbounds | map(select(.port != 9999)) | map(.port == ($port | tonumber)) | index(true)' "$config_file")
|
||
|
||
# 包含实际的SOCKS5 IP地址作为PS字段
|
||
nodes_to_save+=("$inbound_port" "$password" "$method" "$((index+1))" "$old_ip")
|
||
fi
|
||
else
|
||
echo -e "${red}更新配置失败!${none}"
|
||
rm -f "$temp_file"
|
||
continue
|
||
fi
|
||
done
|
||
|
||
if [[ ${#nodes_to_save[@]} -gt 0 ]]; then
|
||
save_multiple_ss_links_with_ps "$local_ip" "${nodes_to_save[@]}"
|
||
fi
|
||
|
||
sudo chmod 755 /usr/local/etc/xray/config.json
|
||
sudo systemctl restart xray
|
||
echo -e "${green}Xray 服务已重新启动。${none}"
|
||
}
|
||
|
||
# 根据xiugai.txt文件删除节点
|
||
delete_nodes_by_ip() {
|
||
local modify_file="/home/xiugai.txt"
|
||
|
||
# 检查xiugai.txt文件是否存在
|
||
if [ ! -f "$modify_file" ]; then
|
||
echo -e "${red}错误!${none} $modify_file 文件不存在。"
|
||
return
|
||
fi
|
||
|
||
# 读取xiugai.txt文件中的代理信息
|
||
local modify_proxies=()
|
||
while IFS= read -r line || [[ -n "$line" ]]; do
|
||
# 忽略空行
|
||
if [[ -z "$line" ]]; then
|
||
continue
|
||
fi
|
||
# 只提取IP部分
|
||
IFS=':' read -r ip _ <<< "$line"
|
||
modify_proxies+=("$ip")
|
||
done < "$modify_file"
|
||
|
||
# 检查是否读取到IP
|
||
local ip_count=${#modify_proxies[@]}
|
||
if [ $ip_count -eq 0 ]; then
|
||
echo -e "${red}错误!${none} 未在 $modify_file 中找到有效的IP地址。"
|
||
return
|
||
fi
|
||
|
||
echo -e "${green}从 $modify_file 读取到 $ip_count 个IP地址。${none}"
|
||
|
||
# 处理每个要删除的IP
|
||
for ip in "${modify_proxies[@]}"; do
|
||
# 查找匹配的出站节点
|
||
local outbound_config=$(jq --arg ip "$ip" '.outbounds[] | select(.protocol == "socks" and .settings.servers[0].address == $ip) | {tag: .tag, port: .settings.servers[0].port}' "$config_file")
|
||
|
||
if [[ -z "$outbound_config" ]]; then
|
||
echo -e "${red}警告:${none} 未找到IP地址为 $ip 的SOCKS5出站节点,终止脚本运行"
|
||
exit 1
|
||
fi
|
||
|
||
local outbound_tag=$(echo "$outbound_config" | jq -r '.tag')
|
||
|
||
# 从outbound_tag中提取端口号(假设格式为"outbound端口号")
|
||
local port=${outbound_tag#outbound}
|
||
|
||
echo -e "${yellow}找到匹配的节点:${none} 出站标签=$outbound_tag, IP=$ip, 端口=$port"
|
||
|
||
# 查找对应的入站配置
|
||
local inbound_config=$(jq --arg port "$port" '.inbounds[] | select(.port == ($port | tonumber))' "$config_file")
|
||
|
||
if [[ -z "$inbound_config" ]]; then
|
||
echo -e "${red}警告:${none} 未找到对应端口 $port 的入站配置,继续删除出站配置"
|
||
else
|
||
local inbound_tag=$(echo "$inbound_config" | jq -r '.tag')
|
||
echo -e "${yellow}找到对应的入站配置:${none} 标签=$inbound_tag"
|
||
|
||
# 删除入站配置
|
||
jq --arg port "$port" 'del(.inbounds[] | select(.port == ($port | tonumber)))' "$config_file" > "$config_file.tmp" && mv "$config_file.tmp" "$config_file"
|
||
|
||
# 删除路由规则(使用实际的inbound_tag而不是构造的标签)
|
||
jq --arg inTag "$inbound_tag" 'del(.routing.rules[] | select(.inboundTag[] == $inTag))' "$config_file" > "$config_file.tmp" && mv "$config_file.tmp" "$config_file"
|
||
fi
|
||
|
||
# 删除出站配置
|
||
jq --arg tag "$outbound_tag" 'del(.outbounds[] | select(.tag == $tag))' "$config_file" > "$config_file.tmp" && mv "$config_file.tmp" "$config_file"
|
||
|
||
echo -e "${green}已成功删除IP地址为 $ip 的节点。${none}"
|
||
done
|
||
|
||
sudo systemctl restart xray
|
||
echo -e "${green}Xray 服务已重新启动。${none}"
|
||
}
|
||
|
||
main_menu() {
|
||
while true; do
|
||
echo -e "\n${green}快速批量搭建二级代理脚本-管理菜单:${none}"
|
||
echo "1. 查看所有节点"
|
||
echo "2. 新增Shadowsocks入站sk5出站(从/home/sk5.txt文件导入)"
|
||
echo "3. 删除节点(根据/home/xiugai.txt文件匹配)"
|
||
echo "4. 修改SOCKS5出站节点(根据/home/xiugai.txt文件匹配)"
|
||
echo "5. 退出"
|
||
read -p "请输入选项: " choice
|
||
|
||
case $choice in
|
||
1) show_inbound_configs ;;
|
||
2) add_new_nodes ;;
|
||
3) delete_nodes_by_ip ;;
|
||
4) modify_socks5_outbound ;;
|
||
5) break ;;
|
||
*) echo -e "${red}无效的选项,请重新选择。${none}" ;;
|
||
esac
|
||
done
|
||
}
|
||
|
||
check_and_install_curl
|
||
check_and_install_jq
|
||
check_and_install_openssl
|
||
check_and_install_xray
|
||
create_default_config
|
||
get_local_ip
|
||
main_menu
|