Files
shell/proxy/socks-vless.sh
starry 1200c37643 add
2025-09-11 16:53:16 +08:00

630 lines
20 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
# 站群多IP源进源出节点脚本 socks和vless+tcp协议
# 生成随机8位数的用户名和密码
generate_random_string() {
local length=8
tr -dc A-Za-z0-9 </dev/urandom | head -c $length
}
# 生成随机UUID
generate_uuid() {
cat /proc/sys/kernel/random/uuid
}
# 获取当前北京时间,精确到秒
get_beijing_time() {
TZ=Asia/Shanghai date +"%Y年%m月%d日%H点%M分%S秒"
}
# 全局变量,保存当前操作使用的输出文件名
OUTPUT_FILE=""
# 初始化输出文件名
init_output_file() {
OUTPUT_FILE="/home/$(get_beijing_time).txt"
# 确保文件存在并清空内容
touch "$OUTPUT_FILE"
> "$OUTPUT_FILE"
echo "将使用输出文件: $OUTPUT_FILE"
}
install_jq() {
if ! command -v jq &> /dev/null; then
echo "jq 未安装,正在安装 jq..."
if [[ -f /etc/debian_version ]]; then
apt update && apt install -yq jq
elif [[ -f /etc/redhat-release ]]; then
yum install -y epel-release jq
else
echo "无法确定系统发行版,请手动安装 jq。"
exit 1
fi
else
echo "jq 已安装。"
fi
}
install_xray() {
if ! command -v xray &> /dev/null; then
echo "Xray 未安装,正在安装 Xray..."
if ! bash <(curl -L https://github.com/XTLS/Xray-install/raw/main/install-release.sh) install --version v1.8.4; then
echo "Xray 安装失败,请检查网络连接或安装脚本。"
exit 1
fi
echo "Xray 安装完成。"
else
echo "Xray 已安装。"
fi
}
# 检查是否已有节点配置
check_existing_nodes() {
local config_file="/usr/local/etc/xray/config.json"
# 如果配置文件不存在,则没有节点配置
if [ ! -f "$config_file" ]; then
return 1
fi
# 检查inbounds数量是否大于0
local inbounds_count=$(jq '.inbounds | length' "$config_file" 2>/dev/null)
# 如果jq命令失败或inbounds为空则认为没有节点配置
if [ -z "$inbounds_count" ] || [ "$inbounds_count" -eq 0 ]; then
return 1
fi
# 有节点配置
return 0
}
get_public_ipv4() {
ip -4 addr show | awk '/inet / {ip = $2; sub(/\/.*/, "", ip); if (ip !~ /^127\./ && ip !~ /^10\./ && ip !~ /^192\.168\./ && ip !~ /^169\.254\./ && ip !~ /^172\.(1[6-9]|2[0-9]|3[0-1])\./) print ip}'
}
# 获取已配置的IP列表
get_configured_ips() {
local config_file="/usr/local/etc/xray/config.json"
if [ ! -f "$config_file" ]; then
echo ""
return
fi
jq -r '.outbounds[] | .sendThrough' "$config_file" | sort | uniq
}
print_node_info() {
local ip=$1
local socks_port=$2
local vless_port=$3
local username=$4
local password=$5
local uuid=$6
echo -e " IP: \033[32m$ip\033[0m"
echo -e " Socks5 端口: \033[32m$socks_port\033[0m 用户名: \033[32m$username\033[0m 密码: \033[32m$password\033[0m"
echo -e " VLESS 端口: \033[32m$vless_port\033[0m UUID: \033[32m$uuid\033[0m"
# 构建vless链接使用IP作为备注
local vless_link="vless://$uuid@$ip:$vless_port?security=none&type=tcp#$ip"
# 保存节点信息到文件
echo "$ip:$socks_port:$username:$password————$vless_link" >> "$OUTPUT_FILE"
echo "节点信息已保存到 $OUTPUT_FILE"
}
# 导出所有节点配置
export_all_nodes() {
local config_file="/usr/local/etc/xray/config.json"
if [ ! -f "$config_file" ]; then
echo "Xray配置文件不存在无法导出节点信息。"
return 1
fi
# 初始化输出文件
init_output_file
echo "正在导出所有节点配置到 $OUTPUT_FILE..."
# 获取所有Socks5节点
local socks_nodes=$(jq -r '.inbounds[] | select(.protocol == "socks") | {port: .port, tag: .tag}' "$config_file")
if [ -z "$socks_nodes" ]; then
echo "未找到任何节点配置。"
return 1
fi
# 遍历所有Socks5节点查找对应的信息
for row in $(jq -r '.inbounds[] | select(.protocol == "socks") | @base64' "$config_file"); do
inbound=$(echo $row | base64 --decode)
local port=$(echo "$inbound" | jq -r '.port')
local tag=$(echo "$inbound" | jq -r '.tag')
# 查找对应的outbound以获取IP
local outbound_tag="out-$port"
local ip=$(jq -r --arg tag "$outbound_tag" '.outbounds[] | select(.tag == $tag) | .sendThrough' "$config_file")
# 获取Socks5的用户名和密码
local username=$(echo "$inbound" | jq -r '.settings.accounts[0].user')
local password=$(echo "$inbound" | jq -r '.settings.accounts[0].pass')
# 查找相应的VLESS节点
local vless_port=$((port + 1))
local vless_tag="in-$vless_port"
# 获取VLESS的UUID
local uuid=$(jq -r --arg tag "$vless_tag" '.inbounds[] | select(.tag == $tag) | .settings.clients[0].id' "$config_file")
if [ -n "$uuid" ]; then
# 构建vless链接使用IP作为备注
local vless_link="vless://$uuid@$ip:$vless_port?security=none&type=tcp#$ip"
# 输出节点信息
echo "$ip:$port:$username:$password————$vless_link" >> "$OUTPUT_FILE"
echo -e "已导出节点: \033[32m$ip\033[0m Socks5端口:\033[32m$port\033[0m VLESS端口:\033[32m$vless_port\033[0m"
fi
done
echo "所有节点导出完成,信息已保存到 $OUTPUT_FILE"
return 0
}
# 查找配置中未使用的端口号
find_next_unused_port() {
local config_file="/usr/local/etc/xray/config.json"
if [ ! -f "$config_file" ]; then
echo "10001" # 如果配置文件不存在从10001开始
return
fi
# 获取所有已使用的端口
local used_ports=$(jq -r '.inbounds[].port' "$config_file" | sort -n)
if [ -z "$used_ports" ]; then
echo "10001" # 如果没有已使用的端口从10001开始
return
fi
# 获取最大的端口号并加1
local max_port=$(echo "$used_ports" | tail -1)
local next_port=$((max_port + 1))
# 确保端口号是奇数用于socks5
if [ $((next_port % 2)) -eq 0 ]; then
next_port=$((next_port + 1))
fi
echo "$next_port"
}
# 添加新节点只添加未配置的IP
add_new_nodes() {
# 获取当前系统的所有公网IP
public_ips=($(get_public_ipv4))
if [[ ${#public_ips[@]} -eq 0 ]]; then
echo "未找到公网IP地址退出..."
return 1
fi
# 获取已经配置的IP列表
configured_ips=($(get_configured_ips))
# 初始化新IP列表
new_ips=()
# 比对IP找出未配置的IP
for ip in "${public_ips[@]}"; do
is_configured=false
for configured_ip in "${configured_ips[@]}"; do
if [[ "$ip" == "$configured_ip" ]]; then
is_configured=true
break
fi
done
if ! $is_configured; then
new_ips+=("$ip")
fi
done
# 检查是否有新的IP需要配置
if [[ ${#new_ips[@]} -eq 0 ]]; then
echo "所有IP都已配置无需添加新节点。"
return 0
fi
echo "发现 ${#new_ips[@]} 个未配置的IP: ${new_ips[@]}"
# 初始化输出文件
init_output_file
# 获取配置文件路径
config_file="/usr/local/etc/xray/config.json"
# 如果配置文件不存在,创建基础配置
if [ ! -f "$config_file" ]; then
cat > $config_file <<EOF
{
"inbounds": [],
"outbounds": [],
"routing": {
"rules": []
}
}
EOF
fi
# 获取下一个可用的端口
socks_port=$(find_next_unused_port)
echo "将从端口 $socks_port 开始配置新节点"
# 为每个新IP配置节点
for ip in "${new_ips[@]}"; do
echo "正在配置 IP: $ip"
# Socks5配置 (奇数端口)
username=$(generate_random_string)
password=$(generate_random_string)
# VLESS配置 (偶数端口)
vless_port=$((socks_port + 1))
uuid=$(generate_uuid)
# 添加Socks5配置
jq --argjson port "$socks_port" --arg ip "$ip" --arg username "$username" --arg password "$password" '.inbounds += [{
"port": $port,
"protocol": "socks",
"settings": {
"auth": "password",
"accounts": [{
"user": $username,
"pass": $password
}],
"udp": true,
"ip": "0.0.0.0"
},
"streamSettings": {
"network": "tcp"
},
"tag": ("in-\($port)")
}] | .outbounds += [{
"protocol": "freedom",
"settings": {},
"sendThrough": $ip,
"tag": ("out-\($port)")
}] | .routing.rules += [{
"type": "field",
"inboundTag": ["in-\($port)"],
"outboundTag": "out-\($port)"
}]' "$config_file" > temp.json && mv temp.json "$config_file"
# 添加VLESS配置
jq --argjson port "$vless_port" --arg ip "$ip" --arg uuid "$uuid" '.inbounds += [{
"port": $port,
"protocol": "vless",
"settings": {
"clients": [{
"id": $uuid,
"level": 0
}],
"decryption": "none"
},
"streamSettings": {
"network": "tcp"
},
"tag": ("in-\($port)")
}] | .outbounds += [{
"protocol": "freedom",
"settings": {},
"sendThrough": $ip,
"tag": ("out-\($port)")
}] | .routing.rules += [{
"type": "field",
"inboundTag": ["in-\($port)"],
"outboundTag": "out-\($port)"
}]' "$config_file" > temp.json && mv temp.json "$config_file"
# 输出节点信息
print_node_info "$ip" "$socks_port" "$vless_port" "$username" "$password" "$uuid"
# 增加端口号为下一个IP准备
socks_port=$((vless_port + 1))
done
echo "新节点配置完成,共添加了 ${#new_ips[@]} 个节点"
return 0
}
configure_xray() {
public_ips=($(get_public_ipv4))
if [[ ${#public_ips[@]} -eq 0 ]]; then
echo "未找到额外IP地址退出..."
exit 1
fi
echo "找到的公网 IPv4 地址: ${public_ips[@]}"
# 初始化输出文件
init_output_file
config_file="/usr/local/etc/xray/config.json"
# 创建基础配置文件
cat > $config_file <<EOF
{
"inbounds": [],
"outbounds": [],
"routing": {
"rules": []
}
}
EOF
# 初始端口
socks_port=10001
# 配置 inbounds 和 outbounds
for ip in "${public_ips[@]}"; do
echo "正在配置 IP: $ip"
# Socks5配置 (奇数端口)
username=$(generate_random_string)
password=$(generate_random_string)
# VLESS配置 (偶数端口)
vless_port=$((socks_port + 1))
uuid=$(generate_uuid)
# 添加Socks5配置
jq --argjson port "$socks_port" --arg ip "$ip" --arg username "$username" --arg password "$password" '.inbounds += [{
"port": $port,
"protocol": "socks",
"settings": {
"auth": "password",
"accounts": [{
"user": $username,
"pass": $password
}],
"udp": true,
"ip": "0.0.0.0"
},
"streamSettings": {
"network": "tcp"
},
"tag": ("in-\($port)")
}] | .outbounds += [{
"protocol": "freedom",
"settings": {},
"sendThrough": $ip,
"tag": ("out-\($port)")
}] | .routing.rules += [{
"type": "field",
"inboundTag": ["in-\($port)"],
"outboundTag": "out-\($port)"
}]' "$config_file" > temp.json && mv temp.json "$config_file"
# 添加VLESS配置
jq --argjson port "$vless_port" --arg ip "$ip" --arg uuid "$uuid" '.inbounds += [{
"port": $port,
"protocol": "vless",
"settings": {
"clients": [{
"id": $uuid,
"level": 0
}],
"decryption": "none"
},
"streamSettings": {
"network": "tcp"
},
"tag": ("in-\($port)")
}] | .outbounds += [{
"protocol": "freedom",
"settings": {},
"sendThrough": $ip,
"tag": ("out-\($port)")
}] | .routing.rules += [{
"type": "field",
"inboundTag": ["in-\($port)"],
"outboundTag": "out-\($port)"
}]' "$config_file" > temp.json && mv temp.json "$config_file"
# 输出节点信息
print_node_info "$ip" "$socks_port" "$vless_port" "$username" "$password" "$uuid"
# 增加端口号为下一个IP准备
socks_port=$((vless_port + 1))
done
echo "Xray 配置完成。"
}
modify_by_ip() {
local modify_file="/home/xiugai.txt"
if [ ! -f "$modify_file" ]; then
echo "修改文件 $modify_file 不存在,跳过修改操作。"
return
fi
echo "检测到修改文件开始根据IP修改节点..."
# 读取当前配置
local config_file="/usr/local/etc/xray/config.json"
if [ ! -f "$config_file" ]; then
echo "Xray配置文件不存在请先配置Xray。"
exit 1
fi
# 初始化输出文件
init_output_file
local modify_success=false
# 逐行读取修改文件中的IP
while IFS= read -r ip || [[ -n "$ip" ]]; do
# 跳过空行和注释行
[[ -z "$ip" || "$ip" =~ ^# ]] && continue
echo "正在处理IP: $ip"
# 查找此IP对应的出站配置
local ip_exists=$(jq --arg ip "$ip" '.outbounds[] | select(.sendThrough == $ip) | .tag' "$config_file")
if [[ -z "$ip_exists" ]]; then
echo "错误: IP $ip 在当前配置中未找到,停止脚本执行。"
exit 1
fi
# 找到对应的入站端口和标签
local outbound_tags=$(jq -r --arg ip "$ip" '.outbounds[] | select(.sendThrough == $ip) | .tag' "$config_file")
for outbound_tag in $outbound_tags; do
local port=$(echo $outbound_tag | cut -d'-' -f2)
local inbound_tag="in-$port"
# 检查协议类型
local protocol=$(jq -r --arg tag "$inbound_tag" '.inbounds[] | select(.tag == $tag) | .protocol' "$config_file")
if [[ "$protocol" == "socks" ]]; then
# 更新socks协议的用户名和密码
local username=$(generate_random_string)
local password=$(generate_random_string)
jq --arg tag "$inbound_tag" --arg username "$username" --arg password "$password" '
.inbounds[] |= if .tag == $tag then
.settings.accounts[0].user = $username |
.settings.accounts[0].pass = $password
else . end' "$config_file" > temp.json && mv temp.json "$config_file"
# 找到对应的vless端口
local vless_port=$((port + 1))
local vless_tag="in-$vless_port"
# 确认vless端口存在
local vless_exists=$(jq --arg tag "$vless_tag" '.inbounds[] | select(.tag == $tag) | .tag' "$config_file")
# 如果存在更新vless协议的UUID
if [[ -n "$vless_exists" ]]; then
local uuid=$(generate_uuid)
jq --arg tag "$vless_tag" --arg uuid "$uuid" '
.inbounds[] |= if .tag == $tag then
.settings.clients[0].id = $uuid
else . end' "$config_file" > temp.json && mv temp.json "$config_file"
# 构建vless链接使用IP作为备注
local vless_link="vless://$uuid@$ip:$vless_port?security=none&type=tcp#$ip"
# 保存修改后的节点信息
echo "$ip:$port:$username:$password————$vless_link" >> "$OUTPUT_FILE"
echo "已修改 IP: $ip 的Socks5(端口:$port)和VLESS(端口:$vless_port)配置"
modify_success=true
else
echo "警告: 未找到IP $ip 对应的VLESS配置"
fi
fi
done
done < "$modify_file"
if $modify_success; then
echo "节点修改完成,信息已保存到 $OUTPUT_FILE"
else
echo "未进行任何修改"
fi
}
restart_xray() {
echo "正在重启 Xray 服务..."
if ! systemctl restart xray; then
echo "Xray 服务重启失败,请检查配置文件。"
exit 1
fi
systemctl enable xray
echo "Xray 服务已重启。"
}
# 显示交互式菜单
show_menu() {
echo -e "\n\033[36m==== 站群多IP节点管理菜单 ====\033[0m"
echo -e "\033[33m1. 部署节点(首次部署)\033[0m"
echo -e "\033[33m2. 修改节点\033[0m"
echo -e "\033[33m3. 导出所有节点\033[0m"
echo -e "\033[33m4. 新增节点(自动添加未配置的IP)\033[0m"
echo -e "\033[33m0. 退出\033[0m"
echo -e "\033[36m==========================\033[0m"
read -p "请输入选项 [0-4]: " choice
case $choice in
1)
if check_existing_nodes; then
echo -e "\033[31m警告: 检测到已有节点配置!\033[0m"
echo -e "\033[31m选择此选项将会清空所有现有节点并重新部署所有IP的节点\033[0m"
echo -e "\033[31m如果您只想添加新的IP节点请使用选项4\033[0m"
read -p "是否确认清空所有节点并重新部署? (y/n): " confirm
if [[ "$confirm" != "y" && "$confirm" != "Y" ]]; then
echo "已取消操作"
show_menu
return
fi
fi
configure_xray
restart_xray
echo "节点部署完成"
;;
2)
echo "请确保 /home/xiugai.txt 文件中包含需要修改的IP地址列表每行一个IP"
read -p "是否继续修改? (y/n): " confirm
if [[ "$confirm" == "y" || "$confirm" == "Y" ]]; then
modify_by_ip
restart_xray
echo "节点修改完成"
fi
;;
3)
export_all_nodes
;;
4)
add_new_nodes
if [ $? -eq 0 ]; then
restart_xray
echo "新节点添加完成"
fi
;;
0)
echo "退出程序"
exit 0
;;
*)
echo "无效选项,请重新选择"
show_menu
;;
esac
}
# 主函数
main() {
# 检查是否已有节点配置
if check_existing_nodes; then
echo "检测到已有节点配置,跳过依赖安装..."
show_menu
else
echo "未检测到节点配置,开始安装必要依赖..."
install_jq
install_xray
show_menu
fi
}
main