Files
vps-management-bot/scripts/stream-unlock.sh

646 lines
19 KiB
Bash
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/bin/bash
#
# Stream Unlock Installer
# 流媒体/AI 解锁一键脚本
#
# 解锁机:安装 sniproxy提供 DNS 解锁服务
# 被解锁机:安装 smartdns分流指定服务到解锁机
#
set -e
# 颜色定义
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'
# 服务域名配置
declare -A SERVICE_DOMAINS
# 流媒体全家桶
SERVICE_DOMAINS["stream"]="netflix.com netflix.net nflximg.com nflximg.net nflxvideo.net nflxext.com nflxso.net
disneyplus.com disney-plus.net dssott.com bamgrid.com
hbomax.com hbo.com hbogo.com hbonow.com
primevideo.com amazon.com amazon.co.jp amazon.co.uk
paramountplus.com cbs.com
peacocktv.com nbc.com
apple.com apple-tv.com
crunchyroll.com funimation.com
tvb.com tvbanywhere.com
bilibili.com bilibili.tv
iq.com iqiyi.com
youku.com"
# AI 服务
SERVICE_DOMAINS["ai"]="openai.com chatgpt.com ai.com
anthropic.com claude.ai
gemini.google.com generativelanguage.googleapis.com
copilot.microsoft.com
perplexity.ai
midjourney.com
character.ai
poe.com"
# 短视频
SERVICE_DOMAINS["shorts"]="tiktok.com tiktokv.com tiktokcdn.com tiktokcdn-us.com byteoversea.com musical.ly
youtube.com youtu.be ytimg.com googlevideo.com youtubei.googleapis.com youtube-nocookie.com"
# Spotify
SERVICE_DOMAINS["spotify"]="spotify.com scdn.co spotifycdn.com spotifycdn.net"
# 游戏相关
SERVICE_DOMAINS["game"]="playstation.com playstation.net psn.com
xbox.com xboxlive.com
nintendo.com nintendo.net
steam.com steampowered.com steamcommunity.com steamstatic.com
epicgames.com epicgames.net"
# ChatGPT 详细域名
SERVICE_DOMAINS["chatgpt"]="openai.com chatgpt.com ai.com oaistatic.com oaiusercontent.com auth0.openai.com"
# Claude 详细域名
SERVICE_DOMAINS["claude"]="anthropic.com claude.ai statsig.anthropic.com sentry.io"
# ============ 工具函数 ============
print_banner() {
echo -e "${BLUE}"
echo "╔═══════════════════════════════════════════╗"
echo "║ Stream Unlock Installer v1.0 ║"
echo "║ 流媒体/AI 解锁一键脚本 ║"
echo "╚═══════════════════════════════════════════╝"
echo -e "${NC}"
}
check_root() {
if [[ $EUID -ne 0 ]]; then
echo -e "${RED}请使用 root 用户运行此脚本${NC}"
exit 1
fi
}
detect_os() {
if [[ -f /etc/debian_version ]]; then
OS="debian"
PKG_MANAGER="apt"
elif [[ -f /etc/redhat-release ]]; then
OS="centos"
PKG_MANAGER="yum"
elif [[ -f /etc/arch-release ]]; then
OS="arch"
PKG_MANAGER="pacman"
else
# 尝试检测其他系统
if command -v apt &>/dev/null; then
OS="debian"
PKG_MANAGER="apt"
elif command -v yum &>/dev/null; then
OS="centos"
PKG_MANAGER="yum"
elif command -v pacman &>/dev/null; then
OS="arch"
PKG_MANAGER="pacman"
else
echo -e "${RED}不支持的系统,请手动安装 sniproxy${NC}"
echo -e "${YELLOW}支持的系统: Debian/Ubuntu, CentOS/RHEL, Arch Linux${NC}"
exit 1
fi
fi
echo -e "${GREEN}检测到系统: $OS${NC}"
}
get_public_ip() {
local ip=""
ip=$(curl -s4 ip.sb 2>/dev/null) || \
ip=$(curl -s4 ifconfig.me 2>/dev/null) || \
ip=$(curl -s4 api.ipify.org 2>/dev/null)
echo "$ip"
}
# ============ 解锁机安装 ============
install_sniproxy() {
echo -e "${GREEN}[解锁机] 安装 sniproxy...${NC}"
echo -e "${YELLOW}系统类型: $OS${NC}"
# 安装依赖
if [[ "$OS" == "debian" ]]; then
apt update
# 先尝试直接安装
if ! apt install -y sniproxy 2>/dev/null; then
echo -e "${YELLOW}sniproxy 不在默认仓库,从源码编译...${NC}"
# 安装编译依赖
apt install -y build-essential libev-dev libudns-dev pkg-config git
# 克隆并编译
cd /tmp
git clone https://github.com/dlundquist/sniproxy.git
cd sniproxy
./configure --prefix=/usr
make -j$(nproc)
make install
# 创建 systemd 服务
cat > /etc/systemd/system/sniproxy.service << 'SERVICE'
[Unit]
Description=sniproxy
After=network.target
[Service]
Type=forking
ExecStart=/usr/sbin/sniproxy -c /etc/sniproxy.conf
PIDFile=/var/run/sniproxy.pid
Restart=on-failure
[Install]
WantedBy=multi-user.target
SERVICE
systemctl daemon-reload
cd /
rm -rf /tmp/sniproxy
fi
apt install -y dnsmasq ufw
elif [[ "$OS" == "centos" ]]; then
yum install -y epel-release
yum install -y sniproxy dnsmasq firewalld
elif [[ "$OS" == "arch" ]]; then
pacman -Sy --noconfirm sniproxy dnsmasq ufw
else
echo -e "${RED}不支持的系统: $OS${NC}"
echo -e "${YELLOW}请手动安装 sniproxy 和 dnsmasq${NC}"
return 1
fi
# 备份原配置
[[ -f /etc/sniproxy.conf ]] && cp /etc/sniproxy.conf /etc/sniproxy.conf.bak
# 创建 sniproxy 配置
cat > /etc/sniproxy.conf << 'EOF'
user daemon
pidfile /var/run/sniproxy.pid
listener 80 {
proto http
access_log {
filename /var/log/sniproxy/http_access.log
}
}
listener 443 {
proto tls
access_log {
filename /var/log/sniproxy/https_access.log
}
}
table {
# 流媒体
netflix.* *
disneyplus.* *
hbo.* *
primevideo.* *
# AI
openai.* *
chatgpt.* *
anthropic.* *
claude.* *
gemini.* *
# 短视频
tiktok.* *
youtube.* *
ytimg.* *
# 默认
.* *
}
EOF
# 创建日志目录
mkdir -p /var/log/sniproxy
chmod 755 /var/log/sniproxy
# 配置防火墙
configure_firewall_unlocker
# 启动服务
systemctl enable sniproxy
systemctl restart sniproxy
echo -e "${GREEN}[解锁机] sniproxy 安装完成${NC}"
}
configure_firewall_unlocker() {
echo -e "${GREEN}[解锁机] 配置防火墙白名单...${NC}"
local allowed_ips=""
while true; do
read -p "输入要放行的被解锁机 IP输入 done 结束): " ip
[[ "$ip" == "done" ]] && break
[[ -z "$ip" ]] && continue
if [[ "$OS" == "debian" ]]; then
ufw allow from "$ip" to any port 80
ufw allow from "$ip" to any port 443
ufw allow from "$ip" to any port 53
else
firewall-cmd --permanent --add-rich-rule="rule family=ipv4 source address=$ip port protocol=tcp port=80 accept"
firewall-cmd --permanent --add-rich-rule="rule family=ipv4 source address=$ip port protocol=tcp port=443 accept"
firewall-cmd --permanent --add-rich-rule="rule family=ipv4 source address=$ip port protocol=udp port=53 accept"
fi
allowed_ips="$allowed_ips $ip"
echo -e "${GREEN}已添加: $ip${NC}"
done
# 开放本地 DNS
if [[ "$OS" == "debian" ]]; then
ufw allow 53/udp
ufw allow 53/tcp
ufw --force enable
else
firewall-cmd --permanent --add-port=53/udp
firewall-cmd --permanent --add-port=53/tcp
firewall-cmd --reload
fi
echo -e "${GREEN}[解锁机] 防火墙配置完成,已放行:$allowed_ips${NC}"
}
add_service_to_sniproxy() {
local service_type="$1"
local domains="${SERVICE_DOMAINS[$service_type]}"
if [[ -z "$domains" ]]; then
echo -e "${RED}未知服务类型: $service_type${NC}"
return 1
fi
echo -e "${GREEN}添加服务到 sniproxy: $service_type${NC}"
# 为每个域名添加规则
for domain in $domains; do
# 提取主域名作为模式
local pattern="${domain%%.*}.*"
# 检查是否已存在
if ! grep -q "$pattern" /etc/sniproxy.conf 2>/dev/null; then
# 在 table 块中添加
sed -i "/table {/a\\ $pattern *" /etc/sniproxy.conf
echo " 添加: $pattern"
else
echo " 已存在: $pattern"
fi
done
# 重启服务
systemctl restart sniproxy
echo -e "${GREEN}sniproxy 已重启${NC}"
}
# ============ 被解锁机安装 ============
install_smartdns() {
echo -e "${GREEN}[被解锁机] 安装 smartdns...${NC}"
# 方法1: 尝试 apt 安装
if [[ "$OS" == "debian" ]]; then
# 添加 smartdns 官方源或直接安装
if apt install -y smartdns 2>/dev/null; then
echo -e "${GREEN}通过 apt 安装 smartdns 成功${NC}"
else
echo -e "${YELLOW}apt 安装失败,尝试手动下载...${NC}"
# 获取最新版本
local latest_url=$(curl -s https://api.github.com/repos/pymumu/smartdns/releases/latest | grep 'browser_download_url.*x86_64-linux-all.tar.gz' | head -1 | cut -d'"' -f4)
if [[ -z "$latest_url" ]]; then
# 备用下载地址
latest_url="https://github.com/pymumu/smartdns/releases/download/Release45/smartdns.1.2024.08.08-1827.x86_64-linux-all.tar.gz"
fi
echo -e "${YELLOW}下载: $latest_url${NC}"
local tmp_dir="/tmp/smartdns"
mkdir -p "$tmp_dir"
cd "$tmp_dir"
if curl -sL "$latest_url" -o smartdns.tar.gz && tar -xzf smartdns.tar.gz; then
chmod +x smartdns
./smartdns install -u
else
echo -e "${RED}下载安装失败,请手动安装 smartdns${NC}"
echo -e "${YELLOW}参考: https://github.com/pymumu/smartdns${NC}"
return 1
fi
cd -
rm -rf "$tmp_dir"
fi
elif [[ "$OS" == "centos" ]]; then
# CentOS 尝试 yum 或手动下载
if ! yum install -y smartdns 2>/dev/null; then
local latest_url=$(curl -s https://api.github.com/repos/pymumu/smartdns/releases/latest | grep 'browser_download_url.*x86_64-linux-all.tar.gz' | head -1 | cut -d'"' -f4)
[[ -z "$latest_url" ]] && latest_url="https://github.com/pymumu/smartdns/releases/download/Release45/smartdns.1.2024.08.08-1827.x86_64-linux-all.tar.gz"
local tmp_dir="/tmp/smartdns"
mkdir -p "$tmp_dir"
cd "$tmp_dir"
curl -sL "$latest_url" -o smartdns.tar.gz && tar -xzf smartdns.tar.gz && chmod +x smartdns && ./smartdns install -u
cd -
rm -rf "$tmp_dir"
fi
else
echo -e "${RED}不支持的系统,请手动安装 smartdns${NC}"
return 1
fi
# 备份原配置
[[ -f /etc/smartdns/smartdns.conf ]] && cp /etc/smartdns/smartdns.conf /etc/smartdns/smartdns.conf.bak
# 创建基础配置
mkdir -p /etc/smartdns
cat > /etc/smartdns/smartdns.conf << 'EOF'
# SmartDNS 配置
# 监听端口
bind :53
# 上游 DNS
server 8.8.8.8 -group default
server 1.1.1.1 -group default
server 223.5.5.5 -group default
# 缓存配置
cache-size 4096
cache-persist yes
prefetch-domain yes
# 日志
log-level info
EOF
echo -e "${GREEN}[被解锁机] smartdns 安装完成${NC}"
}
configure_smartdns_unlocker() {
local unlocker_ip="$1"
local service_type="$2"
local domains="${SERVICE_DOMAINS[$service_type]}"
if [[ -z "$domains" ]]; then
echo -e "${RED}未知服务类型: $service_type${NC}"
return 1
fi
echo -e "${GREEN}配置分流规则: $service_type -> $unlocker_ip${NC}"
local conf_file="/etc/smartdns/smartdns.conf"
# 添加注释
echo "" >> "$conf_file"
echo "# $service_type 解锁规则 - $(date)" >> "$conf_file"
# 为每个域名添加 address 规则
for domain in $domains; do
echo "address /$domain/$unlocker_ip" >> "$conf_file"
echo " 添加: $domain -> $unlocker_ip"
done
echo -e "${GREEN}分流规则已添加${NC}"
}
restart_smartdns() {
systemctl daemon-reload
systemctl enable smartdns
systemctl restart smartdns
# 设置系统 DNS
if command -v resolvconf &>/dev/null; then
echo "nameserver 127.0.0.1" | resolvconf -a lo.smartdns
else
# 备份原 DNS 配置
cp /etc/resolv.conf /etc/resolv.conf.bak 2>/dev/null || true
echo "nameserver 127.0.0.1" > /etc/resolv.conf
# 防止被覆盖
chattr +i /etc/resolv.conf 2>/dev/null || true
fi
echo -e "${GREEN}smartdns 已启动并设为系统 DNS${NC}"
}
# ============ 服务选择菜单 ============
select_services() {
local selected=()
echo ""
echo -e "${YELLOW}选择要解锁的服务(可多选,空格分隔):${NC}"
echo " 1) 流媒体全家桶 (Netflix, Disney+, HBO, Prime...)"
echo " 2) AI 服务 (ChatGPT, Claude, Gemini...)"
echo " 3) 短视频 (TikTok, YouTube)"
echo " 4) Spotify"
echo " 5) 游戏服务 (Steam, PlayStation, Xbox...)"
echo " 6) ChatGPT 详细"
echo " 7) Claude 详细"
echo " 8) 全部"
echo ""
read -p "请输入选项 (如: 1 2 3): " choices
for choice in $choices; do
case $choice in
1) selected+=("stream") ;;
2) selected+=("ai") ;;
3) selected+=("shorts") ;;
4) selected+=("spotify") ;;
5) selected+=("game") ;;
6) selected+=("chatgpt") ;;
7) selected+=("claude") ;;
8) selected=("stream" "ai" "shorts" "spotify" "game" "chatgpt" "claude"); break ;;
*) echo -e "${RED}无效选项: $choice${NC}" ;;
esac
done
echo "${selected[@]}"
}
# ============ 主菜单 ============
menu_unlocker() {
clear
print_banner
local my_ip=$(get_public_ip)
echo -e "本机 IP: ${GREEN}$my_ip${NC}"
echo ""
echo -e "${YELLOW}[解锁机模式]${NC}"
echo " 1) 安装 sniproxy首次安装"
echo " 2) 添加被解锁机 IP 白名单"
echo " 3) 添加解锁服务"
echo " 4) 查看当前配置"
echo " 5) 卸载 sniproxy"
echo ""
read -p "请选择: " choice
case $choice in
1)
install_sniproxy
# 解锁机不需要选服务sniproxy 配置已包含常见域名
echo -e "${GREEN}解锁机配置完成!${NC}"
echo -e "${YELLOW}下一步:在被解锁机上运行此脚本,选择「被解锁机」模式${NC}"
;;
2)
configure_firewall_unlocker
;;
3)
local services=$(select_services)
for svc in $services; do
add_service_to_sniproxy "$svc"
done
;;
4)
echo -e "${GREEN}sniproxy 配置:${NC}"
cat /etc/sniproxy.conf 2>/dev/null || echo "配置文件不存在"
echo ""
echo -e "${GREEN}防火墙规则:${NC}"
if [[ "$OS" == "debian" ]]; then
ufw status
else
firewall-cmd --list-all
fi
;;
5)
echo -e "${RED}确定要卸载 sniproxy(y/n): ${NC}"
read -p "" confirm
[[ "$confirm" == "y" ]] && {
systemctl stop sniproxy
systemctl disable sniproxy
apt remove -y sniproxy 2>/dev/null || yum remove -y sniproxy 2>/dev/null
rm -f /etc/sniproxy.conf
echo -e "${GREEN}sniproxy 已卸载${NC}"
}
;;
*)
echo -e "${RED}无效选项${NC}"
;;
esac
}
menu_client() {
clear
print_banner
local my_ip=$(get_public_ip)
echo -e "本机 IP: ${GREEN}$my_ip${NC}"
echo ""
echo -e "${YELLOW}[被解锁机模式]${NC}"
echo " 1) 安装 smartdns 并配置分流(首次安装)"
echo " 2) 添加新的分流服务"
echo " 3) 查看当前配置"
echo " 4) 测试解锁"
echo " 5) 卸载 smartdns"
echo ""
read -p "请选择: " choice
case $choice in
1)
install_smartdns
echo ""
read -p "输入解锁机 IP: " unlocker_ip
[[ -z "$unlocker_ip" ]] && {
echo -e "${RED}解锁机 IP 不能为空${NC}"
return 1
}
local services=$(select_services)
for svc in $services; do
configure_smartdns_unlocker "$unlocker_ip" "$svc"
done
restart_smartdns
echo ""
echo -e "${GREEN}配置完成!${NC}"
echo "解锁机: $unlocker_ip"
echo "分流服务: $services"
;;
2)
local current_unlocker=$(grep "address /netflix.com/" /etc/smartdns/smartdns.conf 2>/dev/null | head -1 | awk -F'/' '{print $3}')
if [[ -z "$current_unlocker" ]]; then
read -p "输入解锁机 IP: " unlocker_ip
else
read -p "解锁机 IP [$current_unlocker]: " unlocker_ip
unlocker_ip=${unlocker_ip:-$current_unlocker}
fi
local services=$(select_services)
for svc in $services; do
configure_smartdns_unlocker "$unlocker_ip" "$svc"
done
restart_smartdns
;;
3)
echo -e "${GREEN}smartdns 配置:${NC}"
cat /etc/smartdns/smartdns.conf 2>/dev/null || echo "配置文件不存在"
;;
4)
echo -e "${GREEN}测试 DNS 解析...${NC}"
echo ""
echo "Netflix: $(dig +short netflix.com @127.0.0.1 2>/dev/null | head -1)"
echo "ChatGPT: $(dig +short chatgpt.com @127.0.0.1 2>/dev/null | head -1)"
echo "TikTok: $(dig +short tiktok.com @127.0.0.1 2>/dev/null | head -1)"
;;
5)
echo -e "${RED}确定要卸载 smartdns(y/n): ${NC}"
read -p "" confirm
[[ "$confirm" == "y" ]] && {
systemctl stop smartdns
systemctl disable smartdns
chattr -i /etc/resolv.conf 2>/dev/null || true
[[ -f /etc/resolv.conf.bak ]] && mv /etc/resolv.conf.bak /etc/resolv.conf
rm -rf /etc/smartdns
echo -e "${GREEN}smartdns 已卸载${NC}"
}
;;
*)
echo -e "${RED}无效选项${NC}"
;;
esac
}
# ============ 主入口 ============
main() {
check_root
detect_os
clear
print_banner
local my_ip=$(get_public_ip)
echo -e "本机 IP: ${GREEN}$my_ip${NC}"
echo ""
echo "请选择本机角色:"
echo " 1) 解锁机(我能解锁,帮别人解锁)"
echo " 2) 被解锁机(我不能解锁,用别人的解锁机)"
echo " 3) 退出"
echo ""
read -p "请选择: " mode
case $mode in
1) menu_unlocker ;;
2) menu_client ;;
3) exit 0 ;;
*) echo -e "${RED}无效选项${NC}" ;;
esac
}
main "$@"