This commit is contained in:
starry
2025-07-16 12:35:21 +00:00
commit 1f7b4314c3
49 changed files with 18341 additions and 0 deletions

556
proxy/duosk5-ss2022.sh Normal file
View File

@@ -0,0 +1,556 @@
#!/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