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

31
proxy/README.md Normal file
View File

@@ -0,0 +1,31 @@
#### 卸载xray
```
bash -c "$(curl -L https://github.com/XTLS/Xray-install/raw/main/install-release.sh)" @ remove --purge
```
- 一键安装L2TP
```
bash <(curl -sSL https://github.com/sky22333/shell/raw/main/proxy/l2tp.sh)
```
- 站群多IP源进源出节点脚本支持sk5和vless+tcp协议
```
bash <(curl -sSL https://github.com/sky22333/shell/raw/main/proxy/zhanqun.sh)
```
- 快速批量搭建二级代理脚本vmess入站sk5出站
```
bash <(curl -sSL https://github.com/sky22333/shell/raw/main/proxy/vmess-sk5.sh)
```
- 站群多IP源进源出节点脚本sk5协议
```
bash <(curl -sSL https://github.com/sky22333/shell/raw/main/proxy/duosocks.sh)
```
- 站群多IP源进源出节点脚本vmess+ws协议
```
bash <(curl -sSL https://github.com/sky22333/shell/raw/main/proxy/duovmess.sh)
```

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

578
proxy/duosk5-vmess.sh Normal file
View File

@@ -0,0 +1,578 @@
#!/bin/bash
# 批量搭建vmess+ws入站到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": [
{
"listen": "127.0.0.1",
"port": 9999,
"protocol": "vmess",
"settings": {
"clients": [
{
"id": "wss"
}
]
},
"streamSettings": {
"network": "ws",
"security": "none",
"wsSettings": {
"path": "/wss"
}
},
"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"
}
]
}
}
'
# 检查并安装curl
check_and_install_curl() {
if ! type curl &>/dev/null; then
echo -e "${yellow}正在安装curl...${none}"
apt update && apt install -yq curl
fi
}
# 检查并安装jq
check_and_install_jq() {
if ! type jq &>/dev/null; then
echo -e "${yellow}正在安装jq...${none}"
apt update && apt install -yq jq
fi
}
# 检查并安装uuid-runtime
check_and_install_uuid_runtime() {
if ! type uuidgen &>/dev/null; then
echo -e "${yellow}正在安装 uuid-runtime...${none}"
apt update && apt install -yq uuid-runtime
fi
}
# 检查并安装xray
check_and_install_xray() {
if ! type xray &>/dev/null; then
echo -e "${yellow}正在安装 xray...正在启用BBR...${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.4
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
}
# 获取本机公网 IP
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
}
# 生成带时间戳的vmess文件名(精确到秒)
get_vmess_filename() {
local timestamp=$(date +"%Y%m%d-%H点%M分%S秒")
echo "/home/${timestamp}-vmess.txt"
}
# 保存多个VMess节点到文件
save_multiple_vmess_links() {
local local_ip=$1
shift
local vmess_file=$(get_vmess_filename)
# 清空或创建文件
> "$vmess_file"
# 处理所有传入的节点信息
while [[ $# -gt 0 ]]; do
local port=$1
local id=$2
local path=$3
local index=$4
shift 4
# 获取对应的出站 SOCKS5 的 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" # 如果未找到对应的IP设置为默认值
fi
# 生成VMess链接
local vmess_link="vmess://$(echo -n "{\"v\":\"2\",\"ps\":\"$sk5_ip\",\"add\":\"$local_ip\",\"port\":$port,\"id\":\"$id\",\"aid\":0,\"net\":\"ws\",\"path\":\"$path\",\"type\":\"none\"}" | base64 -w 0)"
# 写入文件
echo "$vmess_link" >> "$vmess_file"
done
echo -e "${green}已将操作的所有节点保存至 $vmess_file${none}"
}
# 保存多个VMess节点到文件带自定义PS字段
save_multiple_vmess_links_with_ps() {
local local_ip=$1
shift
local vmess_file=$(get_vmess_filename)
# 清空或创建文件
> "$vmess_file"
# 处理所有传入的节点信息
while [[ $# -gt 0 ]]; do
local port=$1
local id=$2
local path=$3
local index=$4
local sk5_ip=$5 # 额外参数用于PS字段
shift 5
# 生成VMess链接使用自定义PS字段
local vmess_link="vmess://$(echo -n "{\"v\":\"2\",\"ps\":\"$sk5_ip\",\"add\":\"$local_ip\",\"port\":$port,\"id\":\"$id\",\"aid\":0,\"net\":\"ws\",\"path\":\"$path\",\"type\":\"none\"}" | base64 -w 0)"
# 写入文件
echo "$vmess_link" >> "$vmess_file"
done
echo -e "${green}已将操作的所有节点保存至 $vmess_file${none}"
}
# 保存所有VMess节点到文件
save_all_vmess_links() {
local local_ip=$(get_local_ip) # 获取本机IP
local vmess_file=$(get_vmess_filename)
# 清空或创建文件
> "$vmess_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 id=$(jq -r ".[$i].settings.clients[0].id" <<< "$config")
local path=$(jq -r ".[$i].streamSettings.wsSettings.path" <<< "$config")
# 获取对应的出站 SOCKS5 的 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" # 如果未找到对应的IP设置为默认值
fi
# 生成VMess链接
local vmess_link="vmess://$(echo -n "{\"v\":\"2\",\"ps\":\"$sk5_ip\",\"add\":\"$local_ip\",\"port\":$port,\"id\":\"$id\",\"aid\":0,\"net\":\"ws\",\"path\":\"$path\",\"type\":\"none\"}" | base64 -w 0)"
# 写入文件
echo "$vmess_link" >> "$vmess_file"
done
echo -e "${green}已将全部VMess节点保存至 $vmess_file${none}"
}
# 显示所有入站配置和 Vmess 链接以及对应的出站配置
show_inbound_configs() {
local local_ip=$(get_local_ip) # 获取本机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 id=$(jq -r ".[$i].settings.clients[0].id" <<< "$config")
local path=$(jq -r ".[$i].streamSettings.wsSettings.path" <<< "$config")
# 将节点地址设置为本机IP
local node_address="$local_ip"
# 获取sk5代理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" # 如果未找到对应的IP设置为默认值
fi
local vmess_link="vmess://$(echo -n "{\"v\":\"2\",\"ps\":\"$sk5_ip\",\"add\":\"$node_address\",\"port\":$port,\"id\":\"$id\",\"aid\":0,\"net\":\"ws\",\"path\":\"$path\",\"type\":\"none\"}" | base64 -w 0)"
echo -e "${yellow}节点: $(($i + 1))${none} - 端口: ${port}, Vmess 链接: ${vmess_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
# 保存所有VMess链接到文件
save_all_vmess_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"
local new_id=$(uuidgen)
# 解析代理信息 (格式: 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}"
# 添加入站配置(入站地址设置为 "0.0.0.0"
jq --argjson port "$new_port" --arg id "$new_id" --arg tag "$new_tag" '
.inbounds += [{
listen: "0.0.0.0",
port: $port,
protocol: "vmess",
settings: { clients: [{ id: $id }] },
streamSettings: { network: "ws", security: "none", wsSettings: { path: "/websocket" } },
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"
# 保存节点信息以便后续生成VMess链接
nodes_to_save+=("$new_port" "$new_id" "/websocket" "$((i+1))")
done
# 保存所有新添加的节点到一个文件
save_multiple_vmess_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" \
--argjson 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 |
(.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 --argjson port "$inbound_port" '.inbounds[] | select(.port == $port)' "$config_file")
if [[ -n "$inbound_config" ]]; then
local id=$(echo "$inbound_config" | jq -r '.settings.clients[0].id')
local path=$(echo "$inbound_config" | jq -r '.streamSettings.wsSettings.path')
local index=$(jq '.inbounds | map(select(.port != 9999)) | map(.port == '$inbound_port') | index(true)' "$config_file")
# 修复: 包含实际的SOCKS5 IP地址作为PS字段
nodes_to_save+=("$inbound_port" "$id" "$path" "$((index+1))" "$old_ip")
fi
else
echo -e "${red}更新配置失败!${none}"
rm -f "$temp_file"
continue
fi
done
# 保存所有修改的节点到一个文件使用新函数传递PS字段
if [[ ${#nodes_to_save[@]} -gt 0 ]]; then
save_multiple_vmess_links_with_ps "$local_ip" "${nodes_to_save[@]}"
fi
# 重启Xray服务使配置生效
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 --argjson port "$port" '.inbounds[] | select(.port == $port)' "$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 --argjson port "$port" 'del(.inbounds[] | select(.port == $port))' "$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. 新增vmess入站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_uuid_runtime
check_and_install_xray
create_default_config
get_local_ip
main_menu

469
proxy/duosk5.go Normal file
View File

@@ -0,0 +1,469 @@
package main
import (
"bufio"
"crypto/rand"
"encoding/json"
"fmt"
"io"
"net"
"net/http"
"os"
"os/exec"
"regexp"
"strconv"
"strings"
"time"
)
const (
// 颜色常量ANSI转义码
ColorReset = "\033[0m"
ColorRed = "\033[31m"
ColorGreen = "\033[32m"
ColorYellow = "\033[33m"
ColorCyan = "\033[36m"
// 构建CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags="-s -w" -o sk5 main.go
// 脚本过期时间以及其他变量
EXPIRE_DATE = "2025-06-08 02:01:01"
CONFIG_FILE = "/usr/local/etc/xray/config.json"
SOCKS_FILE = "/home/socks.txt"
XRAY_INSTALL_URL = "https://github.com/XTLS/Xray-install/raw/main/install-release.sh"
XRAY_VERSION = "v1.8.4"
START_PORT = 10001
)
// 彩色打印函数
func colorPrint(colorCode, format string, a ...interface{}) {
fmt.Printf(colorCode+format+ColorReset+"\n", a...)
}
// XrayConfig represents the Xray configuration structure
type XrayConfig struct {
Inbounds []Inbound `json:"inbounds"`
Outbounds []Outbound `json:"outbounds"`
Routing Routing `json:"routing"`
}
type Inbound struct {
Port int `json:"port"`
Protocol string `json:"protocol"`
Settings InboundSettings `json:"settings"`
StreamSettings StreamSettings `json:"streamSettings"`
Tag string `json:"tag"`
}
type InboundSettings struct {
Auth string `json:"auth"`
Accounts []Account `json:"accounts"`
UDP bool `json:"udp"`
IP string `json:"ip"`
}
type Account struct {
User string `json:"user"`
Pass string `json:"pass"`
}
type StreamSettings struct {
Network string `json:"network"`
}
type Outbound struct {
Protocol string `json:"protocol"`
Settings interface{} `json:"settings"`
SendThrough string `json:"sendThrough"`
Tag string `json:"tag"`
}
type Routing struct {
Rules []Rule `json:"rules"`
}
type Rule struct {
Type string `json:"type"`
InboundTag []string `json:"inboundTag"`
OutboundTag string `json:"outboundTag"`
}
type NodeInfo struct {
IP string
Port int
Username string
Password string
}
// generateRandomString generates a random string of specified length
func generateRandomString(length int) string {
const charset = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
b := make([]byte, length)
if _, err := rand.Read(b); err != nil {
panic(err)
}
for i := range b {
b[i] = charset[b[i]%byte(len(charset))]
}
return string(b)
}
// checkExpiration checks if the script has expired
func checkExpiration() error {
colorPrint(ColorCyan, "开始运行...")
// Get timestamp from cloudflare
resp, err := http.Get("https://www.cloudflare.com/cdn-cgi/trace")
if err != nil {
return fmt.Errorf("网络错误")
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
return fmt.Errorf("读取响应失败")
}
// Extract timestamp
re := regexp.MustCompile(`ts=(\d+)`)
matches := re.FindStringSubmatch(string(body))
if len(matches) < 2 {
return fmt.Errorf("无法解析时间")
}
timestamp, err := strconv.ParseInt(matches[1], 10, 64)
if err != nil {
return fmt.Errorf("时间转换失败")
}
// Convert to Beijing time
currentTime := time.Unix(timestamp, 0).In(time.FixedZone("CST", 8*3600))
expireTime, _ := time.ParseInLocation("2006-01-02 15:04:05", EXPIRE_DATE, time.FixedZone("CST", 8*3600))
if currentTime.After(expireTime) {
return fmt.Errorf("当前脚本已过期,请联系作者")
}
return nil
}
// commandExists checks if a command exists in PATH
func commandExists(cmd string) bool {
_, err := exec.LookPath(cmd)
return err == nil
}
// installJQ installs jq if not present
func installJQ() error {
if commandExists("jq") {
colorPrint(ColorGreen, "jq 已安装")
return nil
}
colorPrint(ColorYellow, "jq 未安装,正在安装 jq...")
// Detect OS
if _, err := os.Stat("/etc/debian_version"); err == nil {
// Debian/Ubuntu
cmd := exec.Command("bash", "-c", "apt update && apt install -yq jq")
return cmd.Run()
} else if _, err := os.Stat("/etc/redhat-release"); err == nil {
// RHEL/CentOS
cmd := exec.Command("yum", "install", "-y", "epel-release", "jq")
return cmd.Run()
}
return fmt.Errorf("无法确定系统发行版,请手动安装 jq")
}
// installXray installs Xray if not present
func installXray() error {
if commandExists("xray") {
colorPrint(ColorGreen, "Xray 已安装")
return nil
}
colorPrint(ColorYellow, "Xray 未安装,正在安装 Xray...")
cmd := exec.Command("bash", "-c", fmt.Sprintf("curl -L %s | bash -s install --version %s", XRAY_INSTALL_URL, XRAY_VERSION))
if err := cmd.Run(); err != nil {
return fmt.Errorf("Xray 安装失败: %v", err)
}
colorPrint(ColorGreen, "Xray 安装完成")
return nil
}
// getPublicIPv4 gets all public IPv4 addresses
func getPublicIPv4() ([]string, error) {
var publicIPs []string
// Get all network interfaces
interfaces, err := net.Interfaces()
if err != nil {
return nil, err
}
for _, iface := range interfaces {
if iface.Flags&net.FlagUp == 0 || iface.Flags&net.FlagLoopback != 0 {
continue
}
addrs, err := iface.Addrs()
if err != nil {
continue
}
for _, addr := range addrs {
if ipNet, ok := addr.(*net.IPNet); ok && !ipNet.IP.IsLoopback() {
if ipNet.IP.To4() != nil {
ip := ipNet.IP.String()
// Check if it's a public IP
if isPublicIP(ip) {
publicIPs = append(publicIPs, ip)
}
}
}
}
}
return publicIPs, nil
}
// isPublicIP checks if an IP is public
func isPublicIP(ip string) bool {
parsedIP := net.ParseIP(ip)
if parsedIP == nil {
return false
}
// Check for private IP ranges
privateRanges := []string{
"127.0.0.0/8", // loopback
"10.0.0.0/8", // private
"172.16.0.0/12", // private
"192.168.0.0/16", // private
"169.254.0.0/16", // link-local
}
for _, cidr := range privateRanges {
_, network, _ := net.ParseCIDR(cidr)
if network.Contains(parsedIP) {
return false
}
}
return true
}
// ensureSocksFileExists creates socks.txt if it doesn't exist
func ensureSocksFileExists() error {
if _, err := os.Stat(SOCKS_FILE); os.IsNotExist(err) {
colorPrint(ColorYellow, "socks.txt 文件不存在,正在创建...")
file, err := os.Create(SOCKS_FILE)
if err != nil {
return err
}
file.Close()
}
return nil
}
// saveNodeInfo saves node information to file and prints it
func saveNodeInfo(node NodeInfo) error {
// Print node info with colors
fmt.Printf(" IP: %s%s%s 端口: %s%d%s 用户名: %s%s%s 密码: %s%s%s\n",
ColorGreen, node.IP, ColorReset,
ColorGreen, node.Port, ColorReset,
ColorGreen, node.Username, ColorReset,
ColorGreen, node.Password, ColorReset)
// Save to file
file, err := os.OpenFile(SOCKS_FILE, os.O_APPEND|os.O_WRONLY, 0644)
if err != nil {
return err
}
defer file.Close()
_, err = fmt.Fprintf(file, "%s %d %s %s\n", node.IP, node.Port, node.Username, node.Password)
return err
}
// configureXray configures Xray with multiple IPs
func configureXray() error {
publicIPs, err := getPublicIPv4()
if err != nil {
return fmt.Errorf("获取公网IP失败: %v", err)
}
if len(publicIPs) == 0 {
return fmt.Errorf("未找到额外IP地址")
}
colorPrint(ColorCyan, "找到的公网 IPv4 地址: %v", publicIPs)
// Create initial config
config := XrayConfig{
Inbounds: []Inbound{},
Outbounds: []Outbound{},
Routing: Routing{
Rules: []Rule{},
},
}
// Configure each IP
port := START_PORT
for _, ip := range publicIPs {
colorPrint(ColorCyan, "正在配置 IP: %s 端口: %d", ip, port)
username := generateRandomString(8)
password := generateRandomString(8)
// Create inbound
inbound := Inbound{
Port: port,
Protocol: "socks",
Settings: InboundSettings{
Auth: "password",
Accounts: []Account{
{User: username, Pass: password},
},
UDP: true,
IP: "0.0.0.0",
},
StreamSettings: StreamSettings{
Network: "tcp",
},
Tag: fmt.Sprintf("in-%d", port),
}
// Create outbound
outbound := Outbound{
Protocol: "freedom",
Settings: map[string]interface{}{},
SendThrough: ip,
Tag: fmt.Sprintf("out-%d", port),
}
// Create routing rule
rule := Rule{
Type: "field",
InboundTag: []string{fmt.Sprintf("in-%d", port)},
OutboundTag: fmt.Sprintf("out-%d", port),
}
config.Inbounds = append(config.Inbounds, inbound)
config.Outbounds = append(config.Outbounds, outbound)
config.Routing.Rules = append(config.Routing.Rules, rule)
// Save node info
node := NodeInfo{
IP: ip,
Port: port,
Username: username,
Password: password,
}
if err := saveNodeInfo(node); err != nil {
return fmt.Errorf("保存节点信息失败: %v", err)
}
port++
}
// Write config file
configData, err := json.MarshalIndent(config, "", " ")
if err != nil {
return fmt.Errorf("序列化配置失败: %v", err)
}
if err := os.WriteFile(CONFIG_FILE, configData, 0644); err != nil {
return fmt.Errorf("写入配置文件失败: %v", err)
}
colorPrint(ColorGreen, "Xray 配置完成")
return nil
}
// restartXray restarts the Xray service
func restartXray() error {
colorPrint(ColorCyan, "正在重启 Xray 服务...")
// Restart service
cmd := exec.Command("systemctl", "restart", "xray")
if err := cmd.Run(); err != nil {
return fmt.Errorf("Xray 服务重启失败: %v", err)
}
// Enable service
cmd = exec.Command("systemctl", "enable", "xray")
if err := cmd.Run(); err != nil {
return fmt.Errorf("启用 Xray 服务失败: %v", err)
}
colorPrint(ColorGreen, "Xray 服务已重启")
return nil
}
// readUserInput reads user input for confirmation
func readUserInput(prompt string) string {
fmt.Print(prompt)
reader := bufio.NewReader(os.Stdin)
input, _ := reader.ReadString('\n')
return strings.TrimSpace(input)
}
func main() {
colorPrint(ColorCyan, "站群多IP源进源出sk5协议一键脚本")
colorPrint(ColorCyan, "当前为测试版,可以联系作者获取源码")
expireTime, err := time.ParseInLocation("2006-01-02 15:04:05", EXPIRE_DATE, time.FixedZone("CST", 8*3600))
if err == nil {
expireStr := fmt.Sprintf("%d年%d月%d日%d点%d分%d秒",
expireTime.Year(),
expireTime.Month(),
expireTime.Day(),
expireTime.Hour(),
expireTime.Minute(),
expireTime.Second())
colorPrint(ColorCyan, "脚本过期时间: %s", expireStr)
} else {
colorPrint(ColorYellow, "脚本过期时间解析失败")
}
fmt.Println()
// Check expiration
if err := checkExpiration(); err != nil {
colorPrint(ColorRed, "错误: %v", err)
os.Exit(1)
}
// Ensure socks file exists
if err := ensureSocksFileExists(); err != nil {
colorPrint(ColorRed, "创建socks文件失败: %v", err)
os.Exit(1)
}
// Install jq
if err := installJQ(); err != nil {
colorPrint(ColorRed, "安装jq失败: %v", err)
os.Exit(1)
}
// Install Xray
if err := installXray(); err != nil {
colorPrint(ColorRed, "安装Xray失败: %v", err)
os.Exit(1)
}
// Configure Xray
if err := configureXray(); err != nil {
colorPrint(ColorRed, "配置Xray失败: %v", err)
os.Exit(1)
}
// Restart Xray
if err := restartXray(); err != nil {
colorPrint(ColorRed, "重启Xray失败: %v", err)
os.Exit(1)
}
colorPrint(ColorGreen, "部署完成,所有节点信息已保存到 %s", SOCKS_FILE)
}

237
proxy/duosocks.sh Normal file
View File

@@ -0,0 +1,237 @@
#!/bin/bash
# 站群多IP源进源出节点脚本sk5协议
# 生成随机8位数的用户名和密码
generate_random_string() {
local length=8
tr -dc A-Za-z0-9 </dev/urandom | head -c $length
}
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 -sSL https://gh-proxy.com/https://github.com/sky22333/shell/raw/main/proxy/xray.sh); then
echo "Xray 安装失败,请检查网络连接或安装脚本。"
exit 1
fi
echo "Xray 安装完成。"
else
echo "Xray 已安装。"
fi
}
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}'
}
# 确保 socks.txt 文件存在,如果不存在则创建
ensure_socks_file_exists() {
if [ ! -f /home/socks.txt ]; then
echo "socks.txt 文件不存在,正在创建..."
touch /home/socks.txt
fi
}
print_node_info() {
local ip=$1
local port=$2
local username=$3
local password=$4
local outfile=${5:-/home/socks.txt}
echo -e " IP: \033[32m$ip\033[0m 端口: \033[32m$port\033[0m 用户名: \033[32m$username\033[0m 密码: \033[32m$password\033[0m"
echo "$ip $port $username $password" >> "$outfile"
}
configure_xray() {
public_ips=($(get_public_ipv4))
if [[ ${#public_ips[@]} -eq 0 ]]; then
echo "未找到额外IP地址退出..."
exit 1
fi
echo "找到的公网 IPv4 地址: ${public_ips[@]}"
config_file="/usr/local/etc/xray/config.json"
cat > $config_file <<EOF
{
"inbounds": [],
"outbounds": [],
"routing": {
"rules": []
}
}
EOF
# 配置 inbounds 和 outbounds
port=10001
for ip in "${public_ips[@]}"; do
echo "正在配置 IP: $ip 端口: $port"
# 此处用户名和密码可以改为固定值
username=$(generate_random_string)
password=$(generate_random_string)
jq --argjson port "$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"
print_node_info "$ip" "$port" "$username" "$password"
port=$((port + 1))
done
echo "Xray 配置完成。"
}
restart_xray() {
echo "正在重启 Xray 服务..."
if ! systemctl restart xray; then
echo "Xray 服务重启失败,请检查配置文件。"
exit 1
fi
systemctl enable xray
echo "Xray 服务已重启。"
}
add_mode=false
if [[ "$1" == "-add" ]]; then
add_mode=true
fi
main() {
ensure_socks_file_exists
install_jq
install_xray
if $add_mode; then
add_xray_nodes
else
config_file="/usr/local/etc/xray/config.json"
if [[ -f $config_file ]]; then
if jq -e '.inbounds[]? | select(.port==10001)' "$config_file" >/dev/null; then
echo "检测到已有节点配置,无需重复生成,如需添加节点请添加 -add命令"
exit 0
fi
fi
configure_xray
restart_xray
echo "部署完成,所有节点信息已保存到 /home/socks.txt"
fi
}
add_xray_nodes() {
public_ips=($(get_public_ipv4))
config_file="/usr/local/etc/xray/config.json"
if [[ ! -f $config_file ]]; then
echo "Xray 配置文件不存在,无法追加。"
exit 1
fi
# 获取已存在的IP
existing_ips=($(jq -r '.outbounds[].sendThrough' "$config_file" | grep -v null))
# 过滤出未添加的新IP
new_ips=()
for ip in "${public_ips[@]}"; do
found=false
for eip in "${existing_ips[@]}"; do
if [[ "$ip" == "$eip" ]]; then
found=true
break
fi
done
if ! $found; then
new_ips+=("$ip")
fi
done
if [[ ${#new_ips[@]} -eq 0 ]]; then
echo "没有新IP需要追加。"
return
fi
# 生成北京时间文件名
beijing_time=$(TZ=Asia/Shanghai date +"%Y%m%d_%H%M%S")
newfile="/home/socks_add_${beijing_time}.txt"
touch "$newfile"
# 找到当前最大端口
last_port=$(jq -r '.inbounds[].port' "$config_file" | sort -n | tail -1)
if [[ -z "$last_port" || "$last_port" == "null" ]]; then
port=10001
else
port=$((last_port + 1))
fi
for ip in "${new_ips[@]}"; do
echo "追加 IP: $ip 端口: $port"
username=$(generate_random_string)
password=$(generate_random_string)
jq --argjson port "$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"
print_node_info "$ip" "$port" "$username" "$password" "$newfile"
port=$((port + 1))
done
echo "Xray 追加完成,新增节点信息已保存到 $newfile"
restart_xray
}
main

141
proxy/duovmess.sh Normal file
View File

@@ -0,0 +1,141 @@
#!/bin/bash
# 站群多IP源进源出节点脚本vmess+ws协议
# 作者sky22333
install_jq() {
# 检查 jq 和 uuidgen 是否已安装
if ! command -v jq &> /dev/null || ! command -v uuidgen &> /dev/null; then
echo "未找到 jq 或 uuidgen正在安装依赖..."
if [[ -f /etc/debian_version ]]; then
apt update && apt install -yq jq uuid-runtime
elif [[ -f /etc/redhat-release ]]; then
yum install -y jq util-linux
else
echo "无法确定系统发行版,请手动安装 jq 和 uuid-runtime。"
exit 1
fi
else
echo "jq 和 uuidgen 都已安装。"
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
}
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}'
}
# 确保 vmess.txt 文件存在,如果不存在则创建
ensure_vmess_file() {
if [ ! -f /home/vmess.txt ]; then
echo "vmess.txt 文件不存在,正在创建..."
touch /home/vmess.txt
fi
}
print_node_links() {
local port=$1
local id=$2
local outbound_ip=$3
local link="vmess://$(echo -n "{\"v\":\"2\",\"ps\":\"$outbound_ip\",\"add\":\"$outbound_ip\",\"port\":\"$port\",\"id\":\"$id\",\"aid\":\"0\",\"net\":\"ws\",\"type\":\"none\",\"host\":\"\",\"path\":\"/ws\",\"tls\":\"none\"}" | base64 | tr -d '\n')"
echo -e "端口: $port, 节点链接: \033[32m$link\033[0m"
# 将 vmess 链接保存到 /home/vmess.txt 文件中,每行一个链接
echo "$link" >> /home/vmess.txt
}
configure_xray() {
public_ips=($(get_public_ipv4))
if [[ ${#public_ips[@]} -eq 0 ]]; then
echo "未找到任何公网 IPv4 地址,退出..."
exit 1
fi
echo "找到的公网 IPv4 地址: ${public_ips[@]}"
config_file="/usr/local/etc/xray/config.json"
cat > $config_file <<EOF
{
"inbounds": [],
"outbounds": [],
"routing": {
"rules": []
}
}
EOF
# 配置 inbounds 和 outbounds
port=10001
for ip in "${public_ips[@]}"; do
echo "正在配置 IP: $ip 端口: $port"
id=$(uuidgen)
jq --argjson port "$port" --arg ip "$ip" --arg id "$id" '.inbounds += [{
"port": $port,
"protocol": "vmess",
"settings": {
"clients": [{
"id": $id,
"alterId": 0
}]
},
"streamSettings": {
"network": "ws",
"wsSettings": {
"path": "/ws"
}
},
"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_links "$port" "$id" "$ip"
port=$((port + 1))
done
echo "Xray 配置完成。"
}
restart_xray() {
echo "正在重启 Xray 服务..."
if ! systemctl restart xray; then
echo "Xray 服务重启失败,请检查配置文件。"
exit 1
fi
systemctl enable xray
echo "Xray 服务已重启。"
}
main() {
ensure_vmess_file
install_jq
install_xray
configure_xray
restart_xray
echo "部署完成,所有节点信息已保存在 /home/vmess.txt"
}
main

564
proxy/l2tp.sh Normal file
View File

@@ -0,0 +1,564 @@
#!/usr/bin/env bash
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH
#=======================================================================#
# 系统支持: Debian 10 + / Ubuntu 18.04 + #
# 描述: L2TP VPN 自动安装脚本 #
# 基于Teddysun版本修改 #
#=======================================================================#
cur_dir=`pwd`
rootness(){
if [[ $EUID -ne 0 ]]; then
echo "错误: 此脚本必须以root身份运行!" 1>&2
exit 1
fi
}
tunavailable(){
if [[ ! -e /dev/net/tun ]]; then
echo "错误: TUN/TAP 不可用!" 1>&2
exit 1
fi
}
disable_selinux(){
if [ -s /etc/selinux/config ] && grep 'SELINUX=enforcing' /etc/selinux/config; then
sed -i 's/SELINUX=enforcing/SELINUX=disabled/g' /etc/selinux/config
setenforce 0
fi
}
get_opsy(){
[ -f /etc/os-release ] && awk -F'[= "]' '/PRETTY_NAME/{print $3,$4,$5}' /etc/os-release && return
[ -f /etc/lsb-release ] && awk -F'[="]+' '/DESCRIPTION/{print $2}' /etc/lsb-release && return
}
get_os_info(){
IP=$( ip addr | egrep -o '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}' | egrep -v "^192\.168|^172\.1[6-9]\.|^172\.2[0-9]\.|^172\.3[0-2]\.|^10\.|^127\.|^255\.|^0\." | head -n 1 )
[ -z ${IP} ] && IP=$( wget -qO- -t1 -T2 ipinfo.io/ip )
if [ -z ${IP} ]; then
IP=$( wget -qO- -t1 -T2 ifconfig.me )
fi
local cname=$( awk -F: '/model name/ {name=$2} END {print name}' /proc/cpuinfo | sed 's/^[ \t]*//;s/[ \t]*$//' )
local cores=$( awk -F: '/model name/ {core++} END {print core}' /proc/cpuinfo )
local freq=$( awk -F: '/cpu MHz/ {freq=$2} END {print freq}' /proc/cpuinfo | sed 's/^[ \t]*//;s/[ \t]*$//' )
local tram=$( free -m | awk '/Mem/ {print $2}' )
local swap=$( free -m | awk '/Swap/ {print $2}' )
local up=$( awk '{a=$1/86400;b=($1%86400)/3600;c=($1%3600)/60;d=$1%60} {printf("%d天 %d:%d:%d\n",a,b,c,d)}' /proc/uptime )
local load=$( w | head -1 | awk -F'load average:' '{print $2}' | sed 's/^[ \t]*//;s/[ \t]*$//' )
local opsy=$( get_opsy )
local arch=$( uname -m )
local lbit=$( getconf LONG_BIT )
local host=$( hostname )
local kern=$( uname -r )
echo "########## 系统信息 ##########"
echo
echo "CPU型号 : ${cname}"
echo "CPU核心数 : ${cores}"
echo "CPU频率 : ${freq} MHz"
echo "总内存大小 : ${tram} MB"
echo "总交换分区大小 : ${swap} MB"
echo "系统运行时间 : ${up}"
echo "平均负载 : ${load}"
echo "操作系统 : ${opsy}"
echo "系统架构 : ${arch} (${lbit} Bit)"
echo "内核版本 : ${kern}"
echo "主机名 : ${host}"
echo "IPv4地址 : ${IP}"
echo
echo "##################################"
}
check_sys(){
local checkType=$1
local value=$2
local release=''
local systemPackage=''
if cat /etc/issue | grep -Eqi "debian"; then
release="debian"
systemPackage="apt"
elif cat /etc/issue | grep -Eqi "ubuntu"; then
release="ubuntu"
systemPackage="apt"
elif cat /proc/version | grep -Eqi "debian"; then
release="debian"
systemPackage="apt"
elif cat /proc/version | grep -Eqi "ubuntu"; then
release="ubuntu"
systemPackage="apt"
else
echo "错误: 不支持的系统请使用Debian或Ubuntu系统"
exit 1
fi
if [[ ${checkType} == "sysRelease" ]]; then
if [ "$value" == "$release" ];then
return 0
else
return 1
fi
elif [[ ${checkType} == "packageManager" ]]; then
if [ "$value" == "$systemPackage" ];then
return 0
else
return 1
fi
fi
}
rand(){
index=0
str=""
for i in {a..z}; do arr[index]=${i}; index=`expr ${index} + 1`; done
for i in {A..Z}; do arr[index]=${i}; index=`expr ${index} + 1`; done
for i in {0..9}; do arr[index]=${i}; index=`expr ${index} + 1`; done
for i in {1..10}; do str="$str${arr[$RANDOM%$index]}"; done
echo ${str}
}
is_64bit(){
if [ `getconf WORD_BIT` = '32' ] && [ `getconf LONG_BIT` = '64' ] ; then
return 0
else
return 1
fi
}
versionget(){
if [ -f /etc/os-release ];then
grep -oE "[0-9.]+" /etc/os-release | head -1
else
grep -oE "[0-9.]+" /etc/issue
fi
}
debianversion(){
if check_sys sysRelease debian;then
local version=$( get_opsy )
local code=${1}
local main_ver=$( echo ${version} | sed 's/[^0-9]//g')
if [ "${main_ver}" == "${code}" ];then
return 0
else
return 1
fi
else
return 1
fi
}
version_check(){
if check_sys packageManager apt; then
if debianversion 5; then
echo "错误: Debian 5 不支持请重新安装OS并重试。"
exit 1
fi
fi
}
get_char(){
SAVEDSTTY=`stty -g`
stty -echo
stty cbreak
dd if=/dev/tty bs=1 count=1 2> /dev/null
stty -raw
stty echo
stty $SAVEDSTTY
}
preinstall_l2tp(){
echo
if [ -d "/proc/vz" ]; then
echo -e "\033[41;37m 警告: \033[0m 您的VPS基于OpenVZ内核可能不支持IPSec。"
echo "是否继续安装? (y/n)"
read -p "(默认: n)" agree
[ -z ${agree} ] && agree="n"
if [ "${agree}" == "n" ]; then
echo
echo "L2TP安装已取消。"
echo
exit 0
fi
fi
echo
echo "请输入IP范围:"
read -p "(默认范围: 192.168.18):" iprange
[ -z ${iprange} ] && iprange="192.168.18"
echo "请输入PSK密钥:"
read -p "(默认PSK: admin123@l2tp):" mypsk
[ -z ${mypsk} ] && mypsk="admin123@l2tp"
echo "请输入用户名:"
read -p "(默认用户名: admin123):" username
[ -z ${username} ] && username="admin123"
password=`rand`
echo "请输入 ${username} 的密码:"
read -p "(默认密码: ${password}):" tmppassword
[ ! -z ${tmppassword} ] && password=${tmppassword}
echo
echo "服务器IP: ${IP}"
echo "服务器本地IP: ${iprange}.1"
echo "客户端远程IP范围: ${iprange}.2-${iprange}.254"
echo "PSK密钥: ${mypsk}"
echo
echo "按任意键开始安装...或按Ctrl+C取消。"
char=`get_char`
}
# 安装依赖
install_l2tp(){
mknod /dev/random c 1 9
apt -y update
apt -yq install curl wget ppp xl2tpd libreswan
config_install
}
config_install(){
cat > /etc/ipsec.conf<<EOF
version 2.0
config setup
protostack=netkey
nhelpers=0
uniqueids=no
interfaces=%defaultroute
virtual_private=%v4:10.0.0.0/8,%v4:192.168.0.0/16,%v4:172.16.0.0/12,%v4:!${iprange}.0/24
conn l2tp-psk
rightsubnet=vhost:%priv
also=l2tp-psk-nonat
conn l2tp-psk-nonat
authby=secret
pfs=no
auto=add
keyingtries=3
rekey=no
ikelifetime=8h
keylife=1h
type=transport
left=%defaultroute
leftid=${IP}
leftprotoport=17/1701
right=%any
rightprotoport=17/%any
dpddelay=40
dpdtimeout=130
dpdaction=clear
sha2-truncbug=yes
EOF
cat > /etc/ipsec.secrets<<EOF
%any %any : PSK "${mypsk}"
EOF
cat > /etc/xl2tpd/xl2tpd.conf<<EOF
[global]
port = 1701
[lns default]
ip range = ${iprange}.2-${iprange}.254
local ip = ${iprange}.1
require chap = yes
refuse pap = yes
require authentication = yes
name = l2tpd
ppp debug = yes
pppoptfile = /etc/ppp/options.xl2tpd
length bit = yes
EOF
cat > /etc/ppp/options.xl2tpd<<EOF
ipcp-accept-local
ipcp-accept-remote
require-mschap-v2
ms-dns 8.8.8.8
ms-dns 8.8.4.4
noccp
auth
hide-password
idle 1800
mtu 1410
mru 1410
nodefaultroute
debug
proxyarp
connect-delay 5000
EOF
rm -f /etc/ppp/chap-secrets
cat > /etc/ppp/chap-secrets<<EOF
# Secrets for authentication using CHAP
# client server secret IP addresses
${username} l2tpd ${password} *
EOF
cp -pf /etc/sysctl.conf /etc/sysctl.conf.bak
sed -i 's/net.ipv4.ip_forward = 0/net.ipv4.ip_forward = 1/g' /etc/sysctl.conf
for each in `ls /proc/sys/net/ipv4/conf/`; do
echo "net.ipv4.conf.${each}.accept_source_route=0" >> /etc/sysctl.conf
echo "net.ipv4.conf.${each}.accept_redirects=0" >> /etc/sysctl.conf
echo "net.ipv4.conf.${each}.send_redirects=0" >> /etc/sysctl.conf
echo "net.ipv4.conf.${each}.rp_filter=0" >> /etc/sysctl.conf
done
sysctl -p
[ -f /etc/iptables.rules ] && cp -pf /etc/iptables.rules /etc/iptables.rules.old.`date +%Y%m%d`
# 确保IP变量已正确获取
if [ -z "${IP}" ]; then
IP=$(wget -qO- ipinfo.io/ip)
fi
cat > /etc/iptables.rules <<EOF
# Added by L2TP VPN script
*filter
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
-A INPUT -p icmp -j ACCEPT
-A INPUT -i lo -j ACCEPT
-A INPUT -p tcp --dport 22 -j ACCEPT
-A INPUT -p udp -m multiport --dports 500,4500,1701 -j ACCEPT
-A FORWARD -m state --state RELATED,ESTABLISHED -j ACCEPT
-A FORWARD -s ${iprange}.0/24 -j ACCEPT
COMMIT
*nat
:PREROUTING ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
:POSTROUTING ACCEPT [0:0]
-A POSTROUTING -s ${iprange}.0/24 -j SNAT --to-source ${IP}
COMMIT
EOF
# 创建rc.local文件如果不存在
if [ ! -f /etc/rc.local ]; then
cat > /etc/rc.local <<EOF
#!/bin/sh -e
#
# rc.local
#
# This script is executed at the end of each multiuser runlevel.
# Make sure that the script will "exit 0" on success or any other
# value on error.
#
# In order to enable or disable this script just change the execution
# bits.
#
# By default this script does nothing.
echo 1 > /proc/sys/net/ipv4/ip_forward
/usr/sbin/service ipsec start
/usr/sbin/service xl2tpd start
/sbin/iptables-restore < /etc/iptables.rules
exit 0
EOF
chmod +x /etc/rc.local
else
# 如果已存在rc.local则追加内容
sed -i '/^exit 0/d' /etc/rc.local
cat >> /etc/rc.local <<EOF
# Added by L2TP VPN script
echo 1 > /proc/sys/net/ipv4/ip_forward
/usr/sbin/service ipsec start
/usr/sbin/service xl2tpd start
/sbin/iptables-restore < /etc/iptables.rules
exit 0
EOF
fi
cat > /etc/network/if-up.d/iptables <<EOF
#!/bin/sh
/sbin/iptables-restore < /etc/iptables.rules
EOF
chmod +x /etc/network/if-up.d/iptables
if [ ! -f /etc/ipsec.d/cert9.db ]; then
echo > /var/tmp/libreswan-nss-pwd
certutil -N -f /var/tmp/libreswan-nss-pwd -d /etc/ipsec.d
rm -f /var/tmp/libreswan-nss-pwd
fi
update-rc.d -f xl2tpd defaults
# 启用并启动服务
systemctl enable ipsec
systemctl enable xl2tpd
echo 1 > /proc/sys/net/ipv4/ip_forward
/sbin/iptables-restore < /etc/iptables.rules
systemctl restart ipsec
systemctl restart xl2tpd
}
finally(){
cp -f ${cur_dir}/l2tp.sh /usr/bin/l2tp 2>/dev/null || true
echo "请稍候..."
sleep 3
ipsec verify
echo
echo "###############################################################"
echo "# L2TP 安装脚本 #"
echo "###############################################################"
echo
echo "默认用户名和密码如下:"
echo
echo "服务器IP: ${IP}"
echo "PSK密钥 : ${mypsk}"
echo "用户名 : ${username}"
echo "密码 : ${password}"
echo
echo "如果您想修改用户设置,请使用以下命令:"
echo "-a (添加用户)"
echo "-d (删除用户)"
echo "-l (列出所有用户)"
echo "-m (修改用户密码)"
echo
}
l2tp(){
clear
echo
echo "###############################################################"
echo "# L2TP 安装脚本 #"
echo "###############################################################"
echo
rootness
tunavailable
disable_selinux
version_check
get_os_info
preinstall_l2tp
install_l2tp
finally
}
list_users(){
if [ ! -f /etc/ppp/chap-secrets ];then
echo "错误: /etc/ppp/chap-secrets 文件未找到."
exit 1
fi
local line="+-------------------------------------------+\n"
local string=%20s
printf "${line}|${string} |${string} |\n${line}" 用户名 密码
grep -v "^#" /etc/ppp/chap-secrets | awk '{printf "|'${string}' |'${string}' |\n", $1,$3}'
printf ${line}
}
add_user(){
while :
do
read -p "请输入用户名:" user
if [ -z ${user} ]; then
echo "用户名不能为空"
else
grep -w "${user}" /etc/ppp/chap-secrets > /dev/null 2>&1
if [ $? -eq 0 ];then
echo "用户名 (${user}) 已存在。请重新输入用户名。"
else
break
fi
fi
done
pass=`rand`
echo "请输入 ${user} 的密码:"
read -p "(默认密码: ${pass}):" tmppass
[ ! -z ${tmppass} ] && pass=${tmppass}
echo "${user} l2tpd ${pass} *" >> /etc/ppp/chap-secrets
echo "用户 (${user}) 添加完成。"
}
del_user(){
while :
do
read -p "请输入要删除的用户名:" user
if [ -z ${user} ]; then
echo "用户名不能为空"
else
grep -w "${user}" /etc/ppp/chap-secrets >/dev/null 2>&1
if [ $? -eq 0 ];then
break
else
echo "用户名 (${user}) 不存在。请重新输入用户名。"
fi
fi
done
sed -i "/^\<${user}\>/d" /etc/ppp/chap-secrets
echo "用户 (${user}) 删除完成。"
}
mod_user(){
while :
do
read -p "请输入要修改密码的用户名:" user
if [ -z ${user} ]; then
echo "用户名不能为空"
else
grep -w "${user}" /etc/ppp/chap-secrets >/dev/null 2>&1
if [ $? -eq 0 ];then
break
else
echo "用户名 (${user}) 不存在。请重新输入用户名。"
fi
fi
done
pass=`rand`
echo "请输入 ${user} 的新密码:"
read -p "(默认密码: ${pass}):" tmppass
[ ! -z ${tmppass} ] && pass=${tmppass}
sed -i "/^\<${user}\>/d" /etc/ppp/chap-secrets
echo "${user} l2tpd ${pass} *" >> /etc/ppp/chap-secrets
echo "用户 ${user} 的密码已更改。"
}
# 主程序
action=$1
if [ -z ${action} ] && [ "`basename $0`" != "l2tp" ]; then
action=install
fi
case ${action} in
install)
l2tp 2>&1 | tee ${cur_dir}/l2tp.log
;;
-l|--list)
list_users
;;
-a|--add)
add_user
;;
-d|--del)
del_user
;;
-m|--mod)
mod_user
;;
-h|--help)
echo "用法: -l,--list 列出所有用户"
echo " -a,--add 添加用户"
echo " -d,--del 删除用户"
echo " -m,--mod 修改用户密码"
echo " -h,--help 打印此帮助信息"
;;
*)
echo "用法: [-l,--查看用户|-a,--添加用户|-d,--删除用户|-m,--修改密码|-h,--帮助信息]" && exit
;;
esac

569
proxy/singbox-zhanqun.sh Normal file
View File

@@ -0,0 +1,569 @@
#!/bin/bash
# sing-box站群多IP源进源出节点脚本 支持sk5和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 sing-box &> /dev/null; then
echo "sing-box 未安装,正在安装 sing-box..."
VERSION="1.11.5"
curl -Lo sing-box.deb "https://github.com/SagerNet/sing-box/releases/download/v${VERSION}/sing-box_${VERSION}_linux_amd64.deb"
if ! dpkg -i sing-box.deb; then
echo "sing-box 安装失败请检查dpkg输出。"
rm -f sing-box.deb
exit 1
fi
rm -f sing-box.deb
echo "sing-box 安装完成。"
else
echo "sing-box 已安装。"
fi
}
# 检查是否已有节点配置
check_existing_nodes() {
local config_file="/etc/sing-box/config.json"
# 如果配置文件不存在,则没有节点配置
if [ ! -f "$config_file" ]; then
return 1
fi
# 检查 route.rules 数组数量是否大于等于2
local rules_count=$(jq '.route.rules | length' "$config_file" 2>/dev/null)
# 如果jq命令失败或rules为空或小于2则认为没有足够节点配置
if [ -z "$rules_count" ] || [ "$rules_count" -lt 2 ]; then
return 1
fi
# 有2个及以上路由规则视为已有节点配置
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="/etc/sing-box/config.json"
if [ ! -f "$config_file" ]; then
echo ""
return
fi
jq -r '.outbounds[] | .inet4_bind_address' "$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="/etc/sing-box/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(.type == "socks") | {port: .listen_port, tag: .tag}' "$config_file")
if [ -z "$socks_nodes" ]; then
echo "未找到任何节点配置。"
return 1
fi
# 遍历所有Socks5节点查找对应的信息
for row in $(jq -r '.inbounds[] | select(.type == "socks") | @base64' "$config_file"); do
inbound=$(echo $row | base64 --decode)
local port=$(echo "$inbound" | jq -r '.listen_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) | .inet4_bind_address' "$config_file")
# 获取Socks5的用户名和密码
local username=$(echo "$inbound" | jq -r '.users[0].username')
local password=$(echo "$inbound" | jq -r '.users[0].password')
# 查找相应的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) | .users[0].uuid' "$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="/etc/sing-box/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="/etc/sing-box/config.json"
# 如果配置文件不存在,创建基础配置
if [ ! -f "$config_file" ]; then
cat > $config_file <<EOF
{
"inbounds": [],
"outbounds": [],
"route": {
"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 += [{
"type": "socks",
"tag": ("in-\($port)"),
"listen": "0.0.0.0",
"listen_port": $port,
"users": [{
"username": $username,
"password": $password
}]
}] | .outbounds += [{
"type": "direct",
"tag": ("out-\($port)"),
"inet4_bind_address": $ip
}] | .route.rules += [{
"inbound": ["in-\($port)"],
"outbound": "out-\($port)"
}]' "$config_file" > temp.json && mv temp.json "$config_file"
# 添加VLESS配置
jq --argjson port "$vless_port" --arg ip "$ip" --arg uuid "$uuid" '.inbounds += [{
"type": "vless",
"tag": ("in-\($port)"),
"listen": "0.0.0.0",
"listen_port": $port,
"users": [{
"uuid": $uuid
}]
}] | .outbounds += [{
"type": "direct",
"tag": ("out-\($port)"),
"inet4_bind_address": $ip
}] | .route.rules += [{
"inbound": ["in-\($port)"],
"outbound": "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="/etc/sing-box/config.json"
# 创建基础配置文件
cat > $config_file <<EOF
{
"inbounds": [],
"outbounds": [],
"route": {
"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 += [{
"type": "socks",
"tag": ("in-\($port)"),
"listen": "0.0.0.0",
"listen_port": $port,
"users": [{
"username": $username,
"password": $password
}]
}] | .outbounds += [{
"type": "direct",
"tag": ("out-\($port)"),
"inet4_bind_address": $ip
}] | .route.rules += [{
"inbound": ["in-\($port)"],
"outbound": "out-\($port)"
}]' "$config_file" > temp.json && mv temp.json "$config_file"
# 添加VLESS配置
jq --argjson port "$vless_port" --arg ip "$ip" --arg uuid "$uuid" '.inbounds += [{
"type": "vless",
"tag": ("in-\($port)"),
"listen": "0.0.0.0",
"listen_port": $port,
"users": [{
"uuid": $uuid
}]
}] | .outbounds += [{
"type": "direct",
"tag": ("out-\($port)"),
"inet4_bind_address": $ip
}] | .route.rules += [{
"inbound": ["in-\($port)"],
"outbound": "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 "sing-box 配置完成。"
}
modify_by_ip() {
local modify_file="/home/xiugai.txt"
if [ ! -f "$modify_file" ]; then
echo "修改文件 $modify_file 不存在,跳过修改操作。"
return
fi
echo "检测到修改文件开始根据IP修改节点..."
# 读取当前配置
local config_file="/etc/sing-box/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(.inet4_bind_address == $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(.inet4_bind_address == $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 type=$(jq -r --arg tag "$inbound_tag" '.inbounds[] | select(.tag == $tag) | .type' "$config_file")
if [[ "$type" == "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
.users[0].username = $username |
.users[0].password = $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
.users[0].uuid = $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 "正在重启 sing-box 服务..."
if ! systemctl restart sing-box; then
echo "sing-box 服务重启失败,请检查配置文件。"
exit 1
fi
systemctl enable sing-box
echo "sing-box 服务已重启。"
}
# 显示交互式菜单
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

270
proxy/vmess-sk5.sh Normal file
View File

@@ -0,0 +1,270 @@
#!/bin/bash
red='\e[31m'
yellow='\e[33m'
green='\e[32m'
none='\e[0m'
config_file="/usr/local/etc/xray/config.json"
default_config='
{
"inbounds": [
{
"listen": "127.0.0.1",
"port": 9999,
"protocol": "vmess",
"settings": {
"clients": [
{
"id": "sky22333"
}
]
},
"streamSettings": {
"network": "ws",
"security": "none",
"wsSettings": {
"path": "/sky22333"
}
},
"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"
}
]
}
}
'
# 检查并安装curl
check_and_install_curl() {
if ! type curl &>/dev/null; then
echo -e "${yellow}正在安装curl...${none}"
apt update && apt install -yq curl
fi
}
# 检查并安装jq
check_and_install_jq() {
if ! type jq &>/dev/null; then
echo -e "${yellow}正在安装jq...${none}"
apt update && apt install -yq jq
fi
}
# 检查并安装uuid-runtime
check_and_install_uuid_runtime() {
if ! type uuidgen &>/dev/null; then
echo -e "${yellow}正在安装 uuid-runtime...${none}"
apt update && apt install -yq uuid-runtime
fi
}
# 检查并安装xray
check_and_install_xray() {
if ! type xray &>/dev/null; then
echo -e "${yellow}正在安装 xray...${none}"
bash <(curl -L https://github.com/XTLS/Xray-install/raw/main/install-release.sh) install --version v1.8.4
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
}
# 获取本机公网 IP
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
}
# 显示所有入站配置和 Vmess 链接以及对应的出站配置(出战只显示地址、端口、用户名和密码)
show_inbound_configs() {
local local_ip=$(get_local_ip) # 获取本机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 id=$(jq -r ".[$i].settings.clients[0].id" <<< "$config")
local path=$(jq -r ".[$i].streamSettings.wsSettings.path" <<< "$config")
# 将节点地址设置为本机IP
local node_address="$local_ip"
local vmess_link="vmess://$(echo -n "{\"v\":\"2\",\"ps\":\"节点$(($i + 1))\",\"add\":\"$node_address\",\"port\":$port,\"id\":\"$id\",\"aid\":0,\"net\":\"ws\",\"path\":\"$path\",\"type\":\"none\"}" | base64 -w 0)"
echo -e "${yellow}节点: $(($i + 1))${none} - 端口: ${port}, Vmess 链接: ${vmess_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
}
# 添加新节点
add_new_nodes() {
read -p "请输入要添加的节点数量: " num_nodes
if ! [[ $num_nodes =~ ^[0-9]+$ ]]; then
echo -e "${red}错误!${none} 请输入有效的数量。\n"
return
fi
local max_port=$(jq '[.inbounds[].port] | max // 10000' "$config_file")
local start_port=$((max_port+1))
for ((i=0; i<num_nodes; i++)); do
local new_port=$((start_port+i))
local new_tag="inbound$new_port"
local new_outbound_tag="outbound$new_port"
local new_id=$(uuidgen)
# 用户输入出站代理信息
echo "配置第 $((i+1)) 个sk5出站 (入站端口是$new_port)"
read -p "请输入socks5出站地址, 端口, 用户名, 密码 (按顺序以空格分隔): " outbound_addr outbound_port outbound_user outbound_pass
# 添加入站配置(入站地址设置为 "0.0.0.0"
jq --argjson port "$new_port" --arg id "$new_id" --arg tag "$new_tag" '
.inbounds += [{
listen: "0.0.0.0",
port: $port,
protocol: "vmess",
settings: { clients: [{ id: $id }] },
streamSettings: { network: "ws", security: "none", wsSettings: { path: "/websocket" } },
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, 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"
done
echo -e "${green}已成功添加 $num_nodes 个节点。${none}"
systemctl restart xray
echo -e "${green}Xray 服务已重新启动。${none}"
}
# 删除特定端口号的节点
delete_node_by_port() {
read -p "请输入要删除的vmess节点端口号: " port_to_delete
if ! [[ $port_to_delete =~ ^[0-9]+$ ]]; then
echo -e "${red}错误!${none} 请输入有效的端口号。\n"
return
fi
local inbound_tag="inbound$port_to_delete"
local outbound_tag="outbound$port_to_delete"
# 删除入站配置
jq --argjson port "$port_to_delete" 'del(.inbounds[] | select(.port == $port))' "$config_file" > "$config_file.tmp" && mv "$config_file.tmp" "$config_file"
# 删除出站配置
jq --arg tag "$outbound_tag" 'del(.outbounds[] | select(.tag == $tag))' "$config_file" > "$config_file.tmp" && mv "$config_file.tmp" "$config_file"
# 删除路由规则
jq --arg inTag "$inbound_tag" --arg outTag "$outbound_tag" 'del(.routing.rules[] | select(.inboundTag[] == $inTag and .outboundTag == $outTag))' "$config_file" > "$config_file.tmp" && mv "$config_file.tmp" "$config_file"
echo -e "${green}已成功删除端口号为 $port_to_delete 的节点。${none}"
systemctl restart xray
echo -e "${green}Xray 服务已重新启动。${none}"
}
# 主菜单
main_menu() {
while true; do
echo -e "\n${green}sky22333-快速批量搭建二级代理脚本-管理菜单:${none}"
echo "1. 查看所有节点"
echo "2. 新增vmess入站sk5出站"
echo "3. 删除节点"
echo "4. 退出"
read -p "请输入选项: " choice
case $choice in
1) show_inbound_configs ;;
2) add_new_nodes ;;
3) delete_node_by_port ;;
4) break ;;
*) echo -e "${red}无效的选项,请重新选择。${none}" ;;
esac
done
}
# 调用主菜单函数
check_and_install_curl
check_and_install_jq
check_and_install_uuid_runtime
check_and_install_xray
create_default_config
get_local_ip
main_menu

86
proxy/vmess.sh Normal file
View File

@@ -0,0 +1,86 @@
#!/bin/bash
# 定义变量
SERVER_IP="192.168.12.23" # 目标服务器的IP地址
SERVER_PASSWORD="password" # 目标服务器的登录密码
NODE_NAME="美国独享" # 用于标识节点的名称
TARGET_DIR="/home/xray.txt"
green='\e[32m'
none='\e[0m'
config_file="/usr/local/etc/xray/config.json"
# 检查并安装依赖项
install_dependencies() {
if ! type jq &>/dev/null || ! type uuidgen &>/dev/null || ! type sshpass &>/dev/null; then
echo -e "${green}正在安装 jq, uuid-runtime 和 sshpass...${none}"
apt update && apt install -yq jq uuid-runtime sshpass
fi
if ! type xray &>/dev/null; then
echo -e "${green}正在安装 xray...${none}"
bash <(curl -L https://github.com/XTLS/Xray-install/raw/main/install-release.sh) install --version v1.8.4
fi
}
# 生成配置和传输逻辑
configure_and_transfer() {
PORT=$(shuf -i 10000-65535 -n 1)
UUID=$(uuidgen)
RANDOM_PATH=$(cat /dev/urandom | tr -dc 'a-z' | head -c 6)
cat > "$config_file" << EOF
{
"inbounds": [
{
"port": $PORT,
"protocol": "vmess",
"settings": {
"clients": [
{
"id": "$UUID"
}
]
},
"streamSettings": {
"network": "ws",
"wsSettings": {
"path": "/$RANDOM_PATH"
}
},
"listen": "0.0.0.0"
}
],
"outbounds": [
{
"protocol": "freedom",
"settings": {}
}
],
"routing": {
"rules": [
{
"type": "field",
"inboundTag": ["inbound0"],
"outboundTag": "direct"
}
]
}
}
EOF
local ip=$(curl -s http://ipinfo.io/ip)
local config="vmess://$(echo -n "{\"v\":\"2\",\"ps\":\"$NODE_NAME\",\"add\":\"$ip\",\"port\":$PORT,\"id\":\"$UUID\",\"aid\":\"0\",\"net\":\"ws\",\"path\":\"/$RANDOM_PATH\",\"type\":\"none\",\"host\":\"\",\"tls\":\"\"}" | base64 -w 0)"
echo -e "${green}Vmess-ws节点链接:${none}"
echo $config
echo $config > /tmp/xray_config.txt
sshpass -p "$SERVER_PASSWORD" ssh -o StrictHostKeyChecking=no root@$SERVER_IP "cat >> $TARGET_DIR" < /tmp/xray_config.txt
}
# 主执行逻辑
install_dependencies
configure_and_transfer
systemctl restart xray
systemctl enable xray
echo -e "${green}Xray 服务已启动。${none}"

182
proxy/xray.sh Normal file
View File

@@ -0,0 +1,182 @@
#!/usr/bin/env bash
# Xray 安装脚本(极简版)
# 固定版本 v1.8.4
# 支持通过 -p 参数设置 GitHub 加速前缀(如 https://gh-proxy.com/
# 仅适用于 Linux 系统,需 root 权限
XRAY_VERSION="v1.8.4"
XRAY_BIN_URL="github.com/XTLS/Xray-core/releases/download/${XRAY_VERSION}/Xray-linux-64.zip"
INSTALL_PATH="/usr/local/bin/xray"
SERVICE_PATH="/etc/systemd/system/xray.service"
CONFIG_PATH="/usr/local/etc/xray/config.json"
# github文件加速前缀
GH_PROXY="https://gh-proxy.com"
show_help() {
echo "用法: $0 [-p <gh-proxy前缀>] [-u|--uninstall]"
echo " -p 可选GitHub 文件加速前缀,如 https://gh-proxy.com"
echo " -u, --uninstall 卸载 Xray 及所有相关文件和服务"
echo "此脚本会自动下载安装 Xray ${XRAY_VERSION},并注册 systemd 服务。"
exit 0
}
# 检查 root 权限
if [[ "$(id -u)" -ne 0 ]]; then
echo "请以 root 用户运行此脚本。"
exit 1
fi
# 解析参数
while [[ $# -gt 0 ]]; do
case "$1" in
-p)
shift
GH_PROXY="$1"
;;
-u|--uninstall)
echo "正在卸载 Xray ..."
systemctl stop xray 2>/dev/null
systemctl disable xray 2>/dev/null
rm -f /usr/local/bin/xray
rm -rf /usr/local/etc/xray
rm -f /etc/systemd/system/xray.service
rm -rf /var/log/xray
systemctl daemon-reload
echo "Xray 及相关文件已卸载。"
exit 0
;;
-h|--help)
show_help
;;
*)
show_help
;;
esac
shift
done
# 自动安装依赖curl 和 unzip
install_pkg() {
PKG_NAME="$1"
if command -v apt >/dev/null 2>&1; then
apt update && apt install -y "$PKG_NAME"
elif command -v dnf >/dev/null 2>&1; then
dnf install -y "$PKG_NAME"
elif command -v yum >/dev/null 2>&1; then
yum install -y "$PKG_NAME"
elif command -v zypper >/dev/null 2>&1; then
zypper install -y "$PKG_NAME"
elif command -v pacman >/dev/null 2>&1; then
pacman -Sy --noconfirm "$PKG_NAME"
elif command -v emerge >/dev/null 2>&1; then
emerge -qv "$PKG_NAME"
else
echo "未检测到支持的包管理器,请手动安装 $PKG_NAME 后重试。"
exit 1
fi
}
for cmd in curl unzip; do
if ! command -v $cmd >/dev/null 2>&1; then
echo "缺少依赖: $cmd,正在尝试自动安装..."
install_pkg "$cmd"
if ! command -v $cmd >/dev/null 2>&1; then
echo "$cmd 安装失败,请手动安装后重试。"
exit 1
fi
fi
done
TMP_DIR="$(mktemp -d)"
ZIP_FILE="$TMP_DIR/xray.zip"
# 拼接加速前缀
if [[ -n "$GH_PROXY" ]]; then
DOWNLOAD_URL="${GH_PROXY%/}/$XRAY_BIN_URL"
else
DOWNLOAD_URL="https://$XRAY_BIN_URL"
fi
echo "下载 Xray: $DOWNLOAD_URL"
curl -L -o "$ZIP_FILE" "$DOWNLOAD_URL"
if [[ $? -ne 0 ]]; then
echo "下载失败,请检查网络或加速前缀。"
rm -rf "$TMP_DIR"
exit 1
fi
unzip -q "$ZIP_FILE" -d "$TMP_DIR"
if [[ $? -ne 0 ]]; then
echo "解压失败。"
rm -rf "$TMP_DIR"
exit 1
fi
install -m 755 "$TMP_DIR/xray" "$INSTALL_PATH"
# 生成 systemd 服务文件(与原脚本一致,自动适配 User 和权限)
INSTALL_USER="root"
if [[ -f '/usr/local/bin/xray' ]]; then
# 若已存在旧服务文件,尝试读取 User 字段
OLD_USER=$(grep '^[ \t]*User[ \t]*=' /etc/systemd/system/xray.service 2>/dev/null | tail -n 1 | awk -F = '{print $2}' | awk '{print $1}')
if [[ -n "$OLD_USER" ]]; then
INSTALL_USER="$OLD_USER"
fi
fi
if ! id "$INSTALL_USER" >/dev/null 2>&1; then
INSTALL_USER="root"
fi
INSTALL_USER_UID=$(id -u "$INSTALL_USER")
# 权限相关字段
temp_CapabilityBoundingSet="CapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_BIND_SERVICE"
temp_AmbientCapabilities="AmbientCapabilities=CAP_NET_ADMIN CAP_NET_BIND_SERVICE"
temp_NoNewPrivileges="NoNewPrivileges=true"
if [[ "$INSTALL_USER_UID" -eq 0 ]]; then
temp_CapabilityBoundingSet="#${temp_CapabilityBoundingSet}"
temp_AmbientCapabilities="#${temp_AmbientCapabilities}"
temp_NoNewPrivileges="#${temp_NoNewPrivileges}"
fi
cat > "$SERVICE_PATH" <<EOF
[Unit]
Description=Xray Service
Documentation=https://github.com/xtls
After=network.target nss-lookup.target
[Service]
User=$INSTALL_USER
${temp_CapabilityBoundingSet}
${temp_AmbientCapabilities}
${temp_NoNewPrivileges}
ExecStart=$INSTALL_PATH run -config $CONFIG_PATH
Restart=on-failure
RestartPreventExitStatus=23
LimitNPROC=10000
LimitNOFILE=1000000
[Install]
WantedBy=multi-user.target
EOF
chmod 644 "$SERVICE_PATH"
systemctl daemon-reload
# 生成最简配置文件
mkdir -p "$(dirname $CONFIG_PATH)"
echo '{}' > "$CONFIG_PATH"
# 启动并设置开机自启
systemctl enable xray
systemctl restart xray
sleep 1
if systemctl is-active --quiet xray; then
echo "Xray ${XRAY_VERSION} 安装并启动成功。"
else
echo "Xray 启动失败,请检查日志。"
fi
# 清理临时文件
rm -rf "$TMP_DIR"

629
proxy/zhanqun.sh Normal file
View File

@@ -0,0 +1,629 @@
#!/bin/bash
# 站群多IP源进源出节点脚本 支持sk5和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