Files
warp/menu.sh
T
fscarmen 3f6f857642 v3.2.4 Fix: correct wireproxy dual-stack WARP handling and DNS strategy
- Fix wireproxy WARP network detection for dual-stack environments
- Set wireproxy DNS resolve strategy to auto

Fix: 修复 wireproxy 双栈 WARP 网络获取与 DNS 策略

- 修复 wireproxy 获取双栈 WARP 网络的问题
- 将 wireproxy DNS 解析策略设置为 auto
2026-04-28 09:14:46 +00:00

2721 lines
124 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.
#!/usr/bin/env bash
# 当前脚本版本号
VERSION='3.2.4'
# 环境变量用于在Debian或Ubuntu操作系统中设置非交互式(noninteractive)安装模式
export DEBIAN_FRONTEND=noninteractive
# Github 反代加速代理
GITHUB_PROXY=('https://v6.gh-proxy.org/' 'https://gh-proxy.com/' 'https://hub.glowp.xyz/' 'https://proxy.vvvv.ee/' 'https://ghproxy.lvedong.eu.org/')
trap cleanup_temp EXIT
trap on_interrupt_exit INT QUIT TERM
E[0]="\n Language:\n 1. English (default) \n 2. 简体中文"
C[0]="${E[0]}"
E[1]="1. Fix wireproxy WARP network detection for dual-stack environments; 2. Set wireproxy DNS resolve strategy to auto"
C[1]="1. 修复 wireproxy 获取双栈 WARP 网络的问题; 2. 将 wireproxy DNS 解析策略设置为 auto"
E[2]="The script must be run as root, you can enter sudo -i and then download and run again. Feedback: [https://github.com/fscarmen/warp-sh/issues]"
C[2]="必须以root方式运行脚本,可以输入 sudo -i 后重新下载运行,问题反馈:[https://github.com/fscarmen/warp-sh/issues]"
E[3]="The TUN module is not loaded. You should turn it on in the control panel. Ask the supplier for more help. Feedback: [https://github.com/fscarmen/warp-sh/issues]"
C[3]="没有加载 TUN 模块,请在管理后台开启或联系供应商了解如何开启,问题反馈:[https://github.com/fscarmen/warp-sh/issues]"
E[4]="Current operating system is: \$SYSTEM, Linux Client only supports Ubuntu, Debian and CentOS. The script is aborted. Feedback: [https://github.com/fscarmen/warp-sh/issues]"
C[4]="当前操作系统是: \$SYSTEM。 Linux Client 只支持 Ubuntu, Debian 和 CentOS,脚本中止,问题反馈:[https://github.com/fscarmen/warp-sh/issues]"
E[5]="The script supports Debian, Ubuntu, CentOS, Fedora, Arch or Alpine systems only. Feedback: [https://github.com/fscarmen/warp-sh/issues]"
C[5]="本脚本只支持 Debian、Ubuntu、CentOS、Fedora、Arch 或 Alpine 系统,问题反馈:[https://github.com/fscarmen/warp-sh/issues]"
E[6]="warp h (help)\n warp n (Get the WARP IP)\n warp o (Turn off WARP temporarily)\n warp u (Turn off and uninstall WARP interface and Socks5 Linux Client)\n warp b (Upgrade kernel, turn on BBR, change Linux system)\n warp v (Sync the latest version)\n warp r (Connect/Disconnect WARP Linux Client)\n warp 4/6 (Add WARP IPv4/IPv6 interface)\n warp d (Add WARP dualstack interface IPv4 + IPv6)\n warp c (Install WARP Linux Client and set to proxy mode)\n warp l (Install WARP Linux Client and set to WARP mode)\n warp i (Change the WARP IP to support Netflix)\n warp e (Install Iptables + dnsmasq + ipset solution)\n warp w (Install WireProxy solution)\n warp y (Connect/Disconnect WireProxy socks5)\n warp k (Switch between kernel and wireguard-go-reserved)\n warp g (Switch between warp global and non-global)\n warp s 4/6/d (Set stack proiority: IPv4 / IPv6 / VPS default)\n"
C[6]="warp h (帮助菜单)\n warp n (获取 WARP IP)\n warp o (临时warp开关)\n warp u (卸载 WARP 网络接口和 Socks5 Client)\n warp b (升级内核、开启BBR及DD)\n warp v (同步脚本至最新版本)\n warp r (WARP Linux Client 开关)\n warp 4/6 (WARP IPv4/IPv6 单栈)\n warp d (WARP 双栈)\n warp c (安装 WARP Linux Client,开启 Socks5 代理模式)\n warp l (安装 WARP Linux Client,开启 WARP 模式)\n warp i (更换支持 Netflix 的IP)\n warp e (安装 Iptables + dnsmasq + ipset 解决方案)\n warp w (安装 WireProxy 解决方案)\n warp y (WireProxy socks5 开关)\n warp k (切换 wireguard 内核 / wireguard-go-reserved)\n warp g (切换 warp 全局 / 非全局)\n warp s 4/6/d (优先级: IPv4 / IPv6 / VPS default)\n"
E[7]="Install dependence-list:"
C[7]="安装依赖列表:"
E[8]="All dependencies already exist and do not need to be installed additionally."
C[8]="所有依赖已存在,不需要额外安装"
E[9]="Port must be 1000-65535. Please re-input\(\${i} times remaining\):"
C[9]="端口必须为 1000-65535,请重新输入\(剩余\${i}次\):"
E[10]="wireguard-tools installation failed, The script is aborted. Feedback: [https://github.com/fscarmen/warp-sh/issues]"
C[10]="wireguard-tools 安装失败,脚本中止,问题反馈:[https://github.com/fscarmen/warp-sh/issues]"
E[11]="Maximum \${j} attempts to get WARP IP..."
C[11]="后台获取 WARP IP 中,最大尝试\${j}次……"
E[12]="Try \${i}"
C[12]="第\${i}次尝试"
E[13]="There have been more than \${j} failures. The script is aborted. Attach the above error message. Feedback: [https://github.com/fscarmen/warp-sh/issues]"
C[13]="失败已超过\${j}次,脚本中止,附上以上错误提示,问题反馈:[https://github.com/fscarmen/warp-sh/issues]"
E[14]="Got the WARP\$TYPE IP successfully"
C[14]="已成功获取 WARP\$TYPE 网络"
E[15]="WARP is turned off. It could be turned on again by [warp o]"
C[15]="已暂停 WARP,再次开启可以用 warp o"
E[16]="The script specifically adds WARP network interface for VPS, detailed:[https://github.com/fscarmen/warp-sh]\n Features:\n\t • Support WARP+ account. Third-party scripts is use to upgrade kernel.\n\t • Not only menus, but commands with option.\n\t • Support system: Ubuntu 16.04、18.04、20.04、22.04,Debian 9、10、11,CentOS 7、8、9, Alpine, Arch Linux 3.\n\t • Support architecture: AMD,ARM and s390x\n\t • Automatically select four WireGuard solutions. Performance: Kernel with WireGuard integration > Install kernel module > wireguard-go\n\t • Suppert WARP Linux client.\n\t • Output WARP status, IP region and asn\n"
C[16]="本项目专为 VPS 添加 warp 网络接口,详细说明: [https://github.com/fscarmen/warp-sh]\n 脚本特点:\n\t • 支持 WARP+ 账户,附带升级内核 BBR 脚本\n\t • 普通用户友好的菜单,进阶者通过后缀选项快速搭建\n\t • 智能判断操作系统: Ubuntu 、Debian 、CentOS、 Alpine 和 Arch Linux,请务必选择 LTS 系统\n\t • 支持硬件结构类型: AMD、 ARM 和 s390x\n\t • 结合 Linux 版本和虚拟化方式,自动优选4个 WireGuard 方案。网络性能方面: 内核集成 WireGuard > 安装内核模块 > wireguard-go\n\t • 支持 WARP Linux Socks5 Client\n\t • 输出执行结果,提示是否使用 WARP IP ,IP 归属地和线路提供商\n"
E[17]="Version"
C[17]="脚本版本"
E[18]="New features"
C[18]="功能新增"
E[19]="System infomation"
C[19]="系统信息"
E[20]="Operating System"
C[20]="当前操作系统"
E[21]="Kernel"
C[21]="内核"
E[22]="Architecture"
C[22]="处理器架构"
E[23]="Virtualization"
C[23]="虚拟化"
E[24]="Client is on"
C[24]="Client 已开启"
E[25]="Port change to \$PORT succeeded."
C[25]="端口成功更换至 \$PORT"
E[26]="\${MODE_BEFORE} ---\> \${MODE_AFTER}, Confirm press [y] :"
C[26]="\${MODE_BEFORE} ---\> \${MODE_AFTER} 确认请按 [y] :"
E[27]="Local Socks5"
C[27]="本地 Socks5"
E[28]="Congratulations! WARP\$TYPE is turned on."
C[28]="恭喜!WARP\$TYPE 已开启"
E[29]="Input errors up to 5 times.The script is aborted."
C[29]="输入错误达5次,脚本退出"
E[30]="Client is not installed."
C[30]="Client 未安装"
E[31]="Client is installed. Disconnected."
C[31]="Client 已安装, 断开状态"
E[32]="Step 1/3: Install dependencies..."
C[32]="进度 1/3: 安装系统依赖……"
E[33]="Step 2/3: WARP configuration file has been processed"
C[33]="进度 2/3: 已处理好 WARP 配置文件"
E[34]="Failed to change port. Feedback: [https://github.com/fscarmen/warp-sh/issues]"
C[34]="更换端口不成功,问题反馈:[https://github.com/fscarmen/warp-sh/issues]"
E[35]="Change the WARP IP to support Netflix (warp i)"
C[35]="更换支持 Netflix 的 IP (warp i)"
E[36]="1. Brush WARP IPv4\n 2. Brush WARP IPv6 (default)"
C[36]="1. 刷 WARP IPv4\n 2. 刷 WARP IPv6 (默认)"
E[37]="Checking VPS infomation..."
C[37]="检查环境中……"
E[38]="Create shortcut [warp] successfully"
C[38]="创建快捷 warp 指令成功"
E[39]="Running WARP"
C[39]="运行 WARP"
E[40]="Menu choose"
C[40]="菜单选项"
E[41]="Spend time: \$(( end - start )) seconds.\\\n The script runs today: \$TODAY. Total: \$TOTAL"
C[41]="总耗时: \$(( end - start ))秒,脚本当天运行次数: \$TODAY,累计运行次数: \$TOTAL"
E[42]="Curren architecture \$(uname -m) is not supported. Feedback: [https://github.com/fscarmen/warp-sh/issues]"
C[42]="当前架构 \$(uname -m) 暂不支持,问题反馈:[https://github.com/fscarmen/warp-sh/issues]"
E[43]="Run again with warp [option] [lisence], such as"
C[43]="再次运行用 warp [option] [lisence],如"
E[44]="WARP installation failed. Feedback: [https://github.com/fscarmen/warp-sh/issues]"
C[44]="WARP 安装失败,问题反馈:[https://github.com/fscarmen/warp-sh/issues]"
E[45]="WARP interface, Linux Client and Wireproxy have been completely deleted!"
C[45]="WARP 网络接口、 Linux Client 和 Wireproxy 已彻底删除!"
E[46]="Working mode: \$GLOBAL_OR_NOT"
C[46]="工作模式: \$GLOBAL_OR_NOT"
E[47]="Upgrade kernel, turn on BBR, change Linux system by other authors [ylx2016],[https://github.com/ylx2016/Linux-NetSpeed]"
C[47]="BBR、DD脚本用的[ylx2016]的成熟作品,地址[https://github.com/ylx2016/Linux-NetSpeed],请熟知"
E[48]="Run script"
C[48]="安装脚本"
E[49]="Return to main menu"
C[49]="回退主目录"
E[50]="Choose:"
C[50]="请选择:"
E[51]="Please enter the correct number"
C[51]="请输入正确数字"
E[52]="Fail to establish CloudflareWARP interface. Feedback: [https://github.com/fscarmen/warp-sh/issues]"
C[52]="创建 CloudflareWARP 网络接口失败,问题反馈:[https://github.com/fscarmen/warp-sh/issues]"
E[53]="Uninstall Socks5 Proxy Client was complete."
C[53]="Socks5 Proxy Client 卸载成功"
E[54]="\$(date +'%F %T') Region: \$REGION Done. IPv\$NF: \$WAN \$COUNTRY \$ASNORG. Retest after 1 hour. Brush ip runing time:\$DAY days \$HOUR hours \$MIN minutes \$SEC seconds"
C[54]="\$(date +'%F %T') 区域 \$REGION 解锁成功,IPv\$NF: \$WAN \$COUNTRY \$ASNORG1 小时后重新测试,刷 IP 运行时长: \$DAY 天 \$HOUR 时 \$MIN 分 \$SEC 秒"
E[55]="\$(date +'%F %T') Try \${i}. Failed. IPv\$NF: \$WAN \$COUNTRY \$ASNORG. Retry after \${j} seconds. Brush ip runing time:\$DAY days \$HOUR hours \$MIN minutes \$SEC seconds"
C[55]="\$(date +'%F %T') 尝试第\${i}次,解锁失败,IPv\$NF: \$WAN \$COUNTRY \$ASNORG\${j}秒后重新测试,刷 IP 运行时长: \$DAY 天 \$HOUR 时 \$MIN 分 \$SEC 秒"
E[56]="The current Netflix region is \$REGION. Confirm press [y] . If you want another regions, please enter the two-digit region abbreviation. \(such as hk,sg. Default is \$REGION\):"
C[56]="当前 Netflix 地区是:\$REGION,需要解锁当前地区请按 [y], 如需其他地址请输入两位地区简写 \(如 hk ,sg,默认:\$REGION\):"
E[57]="Install iptable + dnsmasq + ipset. Let WARP only take over the streaming media traffic (Not available for ipv6 only) (bash menu.sh e)"
C[57]="安装 iptable + dnsmasq + ipset,让 WARP IPv4 only 接管流媒体流量 (不适用于 IPv6 only VPS) (bash menu.sh e)"
E[58]="Local network interface: CloudflareWARP"
C[58]="本地网络接口: CloudflareWARP"
E[59]="WARP\$TYPE Interface is on"
C[59]="WARP\$TYPE 网络接口已开启"
E[60]="WARP Interface is on"
C[60]="WARP 网络接口已开启"
E[61]="WARP Interface is off"
C[61]="WARP 网络接口未开启"
E[62]="Uninstall WARP Interface was complete."
C[62]="WARP 网络接口卸载成功"
E[63]="Change Client or WireProxy port"
C[63]="更改 Client 或 WireProxy 端口"
E[64]="Successfully synchronized the latest version"
C[64]="成功!已同步最新脚本,版本号"
E[65]="Upgrade failed. Feedback:[https://github.com/fscarmen/warp-sh/issues]"
C[65]="升级失败,问题反馈:[https://github.com/fscarmen/warp-sh/issues]"
E[66]="Add WARP IPv4 interface to \${NATIVE[n]} VPS \(bash menu.sh 4\)"
C[66]="为 \${NATIVE[n]} 添加 WARP IPv4 网络接口 \(bash menu.sh 4\)"
E[67]="Add WARP IPv6 interface to \${NATIVE[n]} VPS \(bash menu.sh 6\)"
C[67]="为 \${NATIVE[n]} 添加 WARP IPv6 网络接口 \(bash menu.sh 6\)"
E[68]="Add WARP dualstack interface to \${NATIVE[n]} VPS \(bash menu.sh d\)"
C[68]="为 \${NATIVE[n]} 添加 WARP 双栈网络接口 \(bash menu.sh d\)"
E[69]="Native dualstack"
C[69]="原生双栈"
E[70]="WARP dualstack"
C[70]="WARP 双栈"
E[71]="Turn on WARP (warp o)"
C[71]="打开 WARP (warp o)"
E[72]="Turn off, uninstall WARP interface, Linux Client and WireProxy (warp u)"
C[72]="永久关闭 WARP 网络接口,并删除 WARP、 Linux Client 和 WireProxy (warp u)"
E[73]="Upgrade kernel, turn on BBR, change Linux system (warp b)"
C[73]="升级内核、安装BBR、DD脚本 (warp b)"
E[74]="Please choose the priority:\n 1. IPv4\n 2. IPv6\n 3. Use initial settings (default)"
C[74]="请选择优先级别:\n 1. IPv4\n 2. IPv6\n 3. 使用 VPS 初始设置 (默认)"
E[75]="Sync the latest version (warp v)"
C[75]="同步最新版本 (warp v)"
E[76]="Exit"
C[76]="退出脚本"
E[77]="Turn off WARP (warp o)"
C[77]="暂时关闭 WARP (warp o)"
E[78]=""
C[78]=""
E[79]="Do you uninstall the following dependencies \(if any\)? Please note that this will potentially prevent other programs that are using the dependency from working properly.\\\n\\\n \$UNINSTALL_DEPENDENCIES_LIST"
C[79]="是否卸载以下依赖\(如有\)?请注意,这将有可能使其他正在使用该依赖的程序不能正常工作\\\n\\\n \$UNINSTALL_DEPENDENCIES_LIST"
E[80]="Professional one-click script for WARP to unblock streaming media (Supports multi-platform, multi-mode and TG push)"
C[80]="WARP 解锁 Netflix 等流媒体专业一键(支持多平台、多方式和 TG 通知)"
E[81]="Step 3/3: Searching for the best MTU value is ready."
C[81]="进度 3/3: 寻找 MTU 最优值已完成"
E[82]="Install CloudFlare Client and set mode to Proxy (bash menu.sh c)"
C[82]="安装 CloudFlare Client 并设置为 Proxy 模式 (bash menu.sh c)"
E[83]="Step 1/3: Installing WARP Client..."
C[83]="进度 1/3: 安装 Client……"
E[84]="Step 2/3: Setting Client Mode"
C[84]="进度 2/3: 设置 Client 模式"
E[85]="Client was installed.\n connect/disconnect by [warp r].\n uninstall by [warp u]"
C[85]="Linux Client 已安装\n 连接/断开: warp r\n 卸载: warp u"
E[86]="Client is working. Socks5 proxy listening on: \$(ss -nltp | grep -E 'warp|wireproxy' | awk '{print \$4}')"
C[86]="Linux Client 正常运行中。 Socks5 代理监听:\$(ss -nltp | grep -E 'warp|wireproxy' | awk '{print \$4}')"
E[87]="Fail to establish Socks5 proxy. Feedback: [https://github.com/fscarmen/warp-sh/issues]"
C[87]="创建 Socks5 代理失败,问题反馈:[https://github.com/fscarmen/warp-sh/issues]"
E[88]="Connect the client (warp r)"
C[88]="连接 Client (warp r)"
E[89]="Disconnect the client (warp r)"
C[89]="断开 Client (warp r)"
E[90]="Client is connected"
C[90]="Client 已连接"
E[91]="Client is disconnected. It could be connect again by [warp r]"
C[91]="已断开 Client,再次连接可以用 warp r"
E[92]="(!!! Already installed, do not select.)"
C[92]="(!!! 已安装,请勿选择)"
E[93]="Client is not installed."
C[93]="Client 未安装"
E[94]="Congratulations! WARP\$CLIENT_AC Linux Client is working."
C[94]="恭喜!WARP\$CLIENT_AC Linux Client 工作中"
E[95]="Global"
C[95]="全局"
E[96]="Non-global"
C[96]="非全局"
E[97]="IPv\$PRIO priority"
C[97]="IPv\$PRIO 优先"
E[98]="Uninstall Wireproxy was complete."
C[98]="Wireproxy 卸载成功"
E[99]="WireProxy is connected"
C[99]="WireProxy 已连接"
E[100]="Cannot detect any IPv4 or IPv6. The script is aborted. Feedback: [https://github.com/fscarmen/warp-sh/issues]"
C[100]="检测不到任何 IPv4 或 IPv6。脚本中止,问题反馈:[https://github.com/fscarmen/warp-sh/issues]"
E[101]="Client support amd64 and arm64 only. Curren architecture \$ARCHITECTURE. Official Support List: [https://pkg.cloudflareclient.com/packages/cloudflare-warp]. The script is aborted. Feedback: [https://github.com/fscarmen/warp-sh/issues]"
C[101]="Client 只支持 amd64 和 arm64 架构,当前架构 \$ARCHITECTURE,官方支持列表: [https://pkg.cloudflareclient.com/packages/cloudflare-warp]。脚本中止,问题反馈:[https://github.com/fscarmen/warp-sh/issues]"
E[102]="Client is only supported on CentOS 8 and above. Official Support List: [https://pkg.cloudflareclient.com]. The script is aborted. Feedback: [https://github.com/fscarmen/warp-sh/issues]"
C[102]="Client 只支持 CentOS 8 或以上系统,官方支持列表: [https://pkg.cloudflareclient.com]。脚本中止,问题反馈:[https://github.com/fscarmen/warp-sh/issues]"
E[103]="Port \$PORT is in use. Please input another Port\(\${i} times remaining\):"
C[103]="\$PORT 端口占用中,请使用另一端口\(剩余\${i}次\):"
E[104]="Please customize the Client port (1000-65535. Default to 40000 if it is blank):"
C[104]="请自定义 Client 端口号 (1000-65535,如果不输入,会默认: 40000):"
E[105]="Switch \${WARP_BEFORE[m]} to \${WARP_AFTER1[m]} \${SHORTCUT1[m]}"
C[105]="\${WARP_BEFORE[m]} 转为 \${WARP_AFTER1[m]} \${SHORTCUT1[m]}"
E[106]="Switch \${WARP_BEFORE[m]} to \${WARP_AFTER2[m]} \${SHORTCUT2[m]}"
C[106]="\${WARP_BEFORE[m]} 转为 \${WARP_AFTER2[m]} \${SHORTCUT2[m]}"
E[107]="Failed registration, using a preset free account."
C[107]="注册失败,使用预设的免费账户"
E[145]="The configuration file warp.conf cannot be found. The script is aborted. Feedback: [https://github.com/fscarmen/warp-sh/issues]"
C[145]="找不到配置文件 warp.conf,脚本中止,问题反馈:[https://github.com/fscarmen/warp-sh/issues]"
E[109]="Socks5 Proxy Client is working now. WARP IPv4 and dualstack interface could not be switch to. The script is aborted. Feedback: [https://github.com/fscarmen/warp-sh/issues]"
C[109]="Socks5 代理正在运行中,不能转为 WARP IPv4 或者双栈网络接口,脚本中止,问题反馈:[https://github.com/fscarmen/warp-sh/issues]"
E[110]="Socks5 Proxy Client is working now. WARP IPv4 and dualstack interface could not be installed. The script is aborted. Feedback: [https://github.com/fscarmen/warp-sh/issues]"
C[110]="Socks5 代理正在运行中,WARP IPv4 或者双栈网络接口不能安装,脚本中止,问题反馈:[https://github.com/fscarmen/warp-sh/issues]"
E[111]="Cannot switch to the same form as the current one."
C[111]="不能切换为当前一样的形态"
E[112]="Not available for IPv6 only VPS"
C[112]="IPv6 only VPS 不能使用此方案"
E[113]="Install wireproxy. Wireguard client that exposes itself as a socks5 proxy or tunnels (bash menu.sh w)"
C[113]="安装 wireproxy,让 WARP 在本地创建一个 socks5 代理 (bash menu.sh w)"
E[114]="Congratulations! Wireproxy is working."
C[114]="恭喜!Wireproxy 工作中"
E[115]="WARP, WARP Linux Client, WireProxy hasn't been installed yet. The script is aborted.\n"
C[115]="WARP, WARP Linux Client, WireProxy 均未安装,脚本退出\n"
E[116]="1. WARP Linux Client account\n 2. WireProxy account"
C[116]="1. WARP Linux Client 账户\n 2. WireProxy 账户"
E[117]="1. WARP account\n 2. WireProxy account"
C[117]="1. WARP 账户\n 2. WireProxy 账户"
E[118]="1. WARP account\n 2. WARP Linux Client account"
C[118]="1. WARP 账户\n 2. WARP Linux Client 账户"
E[119]="1. WARP account\n 2. WARP Linux Client account\n 3. WireProxy account"
C[119]="1. WARP 账户\n 2. WARP Linux Client 账户\n 3. WireProxy 账户"
E[120]="WARP has not been installed yet."
C[120]="WARP 还未安装"
E[121]="(!!! Only supports amd64 and arm64, do not select.)"
C[121]="(!!! 只支持 amd64 和 arm64,请勿选择)"
E[122]="WireProxy has not been installed yet."
C[122]="WireProxy 还未安装"
E[123]="WireProxy is disconnected. It could be connect again by [warp y]"
C[123]="已断开 Wireproxy,再次连接可以用 warp y"
E[124]="WireProxy is on"
C[124]="WireProxy 已开启"
E[125]="WireProxy is not installed."
C[125]="WireProxy 未安装"
E[126]="WireProxy is installed and disconnected"
C[126]="WireProxy 已安装,状态为断开连接"
E[127]="Connect the Wireproxy (warp y)"
C[127]="连接 Wireproxy (warp y)"
E[128]="Disconnect the Wireproxy (warp y)"
C[128]="断开 Wireproxy (warp y)"
E[129]="WireProxy Solution. A wireguard client that exposes itself as a socks5 proxy or tunnels. Adapted from the mature works of [pufferffish],[https://github.com/pufferffish/wireproxy]"
C[129]="WireProxy,让 WARP 在本地建议一个 socks5 代理。改编自 [pufferffish] 的成熟作品,地址[https://github.com/pufferffish/wireproxy],请熟知"
E[130]="WireProxy was installed.\n connect/disconnect by [warp y]\n uninstall by [warp u]"
C[130]="WireProxy 已安装\n 连接/断开: warp y\n 卸载: warp u"
E[131]="WARP iptable was installed.\n connect/disconnect by [warp o]\n uninstall by [warp u]"
C[131]="WARP iptable 已安装\n 连接/断开: warp o\n 卸载: warp u"
E[132]="Install CloudFlare Client and set mode to WARP (bash menu.sh l)"
C[132]="安装 CloudFlare Client 并设置为 WARP 模式 (bash menu.sh l)"
E[133]="Confirm all uninstallation please press [y], other keys do not uninstall by default:"
C[133]="确认全部卸载请按 [y],其他键默认不卸载:"
E[134]="Uninstall dependencies were complete."
C[134]="依赖卸载成功"
E[135]="No suitable solution was found for modifying the warp configuration file warp.conf and the script aborted. When you see this message, please send feedback on the bug to:[https://github.com/fscarmen/warp-sh/issues]"
C[135]="没有找到适合的方案用于修改 warp 配置文件 warp.conf,脚本中止。当你看到此信息,请把该 bug 反馈至:[https://github.com/fscarmen/warp-sh/issues]"
E[136]="Can only be run using \$KERNEL_OR_WIREGUARD_GO."
C[136]="只能使用 \$KERNEL_OR_WIREGUARD_GO 运行"
E[137]="Install using:\n 1. wireguard kernel (default)\n 2. wireguard-go with reserved"
C[137]="请选择 wireguard 方式:\n 1. wireguard 内核 (默认)\n 2. wireguard-go with reserved"
E[138]="\${WIREGUARD_BEFORE} ---\> \${WIREGUARD_AFTER}. Confirm press [y] :"
C[138]="\${WIREGUARD_BEFORE} ---\> \${WIREGUARD_AFTER} 确认请按 [y] :"
E[139]="Working mode:\n 1. Global (default)\n 2. Non-global"
C[139]="工作模式:\n 1. 全局 (默认)\n 2. 非全局"
# 自定义字体彩色,read 函数
warning() { echo -e "\033[31m\033[01m$*\033[0m"; } # 红色
error() { echo -e "\033[31m\033[01m$*\033[0m" && exit 1; } # 红色
info() { echo -e "\033[32m\033[01m$*\033[0m"; } # 绿色
hint() { echo -e "\033[33m\033[01m$*\033[0m"; } # 黄色
reading() { read -rp "$(info "$1")" "$2"; }
# 清理临时文件
cleanup_temp() {
rm -f /tmp/{ip,wireguard-go-*,best_mtu,statistics,cdn_proxy} 2>/dev/null
}
# 中断信号处理
on_interrupt_exit() {
cleanup_temp
echo -e '\n'
exit 1
}
# 预处理:扫描 E/C 数组,把含 $ 的条目下标记录到关联数组,避免 text() 每次调用都启动 grep 子进程
declare -A TEXT_NEEDS_EVAL
for _text_i in "${!E[@]}"; do
[[ "${E[${_text_i}]}" == *'$'* || "${C[${_text_i}]}" == *'$'* ]] && TEXT_NEEDS_EVAL[${_text_i}]=1
done
unset _text_i
# text <index>:输出当前语言对应的字符串,含 $ 变量的条目用 eval 展开,其余直接 printf
text() {
local -n _text_arr="${L}" # nameref 指向 E 或 C,零子进程
local _text_val="${_text_arr[$*]}"
if [[ -n "${TEXT_NEEDS_EVAL[$*]}" ]]; then
eval "printf '%s' \"${_text_val}\""
else
printf '%s' "${_text_val}"
fi
}
# 检测是否需要启用 Github CDN,如能直接连通 api.github.com,则不使用
check_cdn() {
local PROXY CODE PID CMD
local _WAIT_COUNT=120
local PIDS=()
local API_URL='https://api.github.com/repos/fscarmen/warp-sh/releases'
# 确定下载工具:优先 wget,次选 curl
if command -v wget >/dev/null 2>&1; then
CMD='wget'
elif command -v curl >/dev/null 2>&1; then
CMD='curl'
else
GH_PROXY=''
return
fi
# 获取 HTTP 状态码
get_code() {
local url=$1
if [ "$CMD" = 'wget' ]; then
wget -qT5 -O /dev/null --server-response "$url" 2>&1 | awk '/HTTP\//{code=$2} END{print code}'
else
curl -skL -w "%{http_code}" "$url" -o /dev/null
fi
}
# 直连检测
CODE=$(get_code "$API_URL")
if [ "$CODE" = '200' ]; then
GH_PROXY=''
return
fi
# 并发探测代理
for PROXY in "${GITHUB_PROXY[@]}"; do
{
CODE=$(get_code "${PROXY}${API_URL}")
[ "$CODE" = '200' ] && [ ! -e "/tmp/cdn_proxy" ] && printf '%s' "$PROXY" > "/tmp/cdn_proxy"
} &
PIDS+=("$!")
done
# 等第一个返回 200 的代理,超时则回退为直连,避免无限等待卡死
while [ ! -e "/tmp/cdn_proxy" ] && [ "$_WAIT_COUNT" -gt 0 ]; do
sleep 0.05
(( _WAIT_COUNT-- )) || true
done
[ -e "/tmp/cdn_proxy" ] && GH_PROXY=$(cat "/tmp/cdn_proxy") || GH_PROXY=''
# 清理后台任务和临时文件
for PID in "${PIDS[@]}"; do kill "$PID" >/dev/null 2>&1 || true; done
for PID in "${PIDS[@]}"; do wait "$PID" 2>/dev/null || true; done
rm -f "/tmp/cdn_proxy"
}
# 脚本当天及累计运行次数统计
statistics_of_run-times() {
local UPDATE_OR_GET=$1
local SCRIPT=$2
if grep -q 'update' <<< "$UPDATE_OR_GET"; then
{ wget --no-check-certificate -qO- --timeout=3 "https://stat.cloudflare.now.cc/api/updateStats?script=${SCRIPT}" > /tmp/statistics; }&
elif grep -q 'get' <<< "$UPDATE_OR_GET"; then
[ -s /tmp/statistics ] && [[ $(cat /tmp/statistics) =~ \"todayCount\":([0-9]+),\"totalCount\":([0-9]+) ]] && local TODAY="${BASH_REMATCH[1]}" && local TOTAL="${BASH_REMATCH[2]}" && rm -f /tmp/statistics
info " $(text 41) "
fi
}
# 选择语言,先判断 /etc/wireguard/language 里的语言选择,没有的话再让用户选择,默认英语。处理中文显示的问题
select_language() {
UTF8_LOCALE=$(locale -a 2>/dev/null | grep -iEm1 "UTF-8|utf8")
[ -n "$UTF8_LOCALE" ] && export LC_ALL="$UTF8_LOCALE" LANG="$UTF8_LOCALE" LANGUAGE="$UTF8_LOCALE"
if [ -s /etc/wireguard/language ]; then
L=$(cat /etc/wireguard/language)
else
L=E && [[ -z "$OPTION" || "$OPTION" = [aclehdpbviw46sg] ]] && hint " $(text 0) \n" && reading " $(text 50) " LANGUAGE
[ "$LANGUAGE" = 2 ] && L=C
fi
}
# 必须以root运行脚本
check_root() {
[ "$(id -u)" != 0 ] && error " $(text 2) "
}
# 判断虚拟化
check_virt() {
if [ "$1" = 'Alpine' ]; then
VIRT=$(virt-what | tr '\n' ' ')
else
[ "$(type -p systemd-detect-virt)" ] && VIRT=$(systemd-detect-virt)
[[ -z "$VIRT" && -x "$(type -p hostnamectl)" ]] && VIRT=$(hostnamectl | awk '/Virtualization:/{print $NF}')
fi
}
# 多方式判断操作系统,试到有值为止。只支持 Debian 10/11、Ubuntu 18.04/20.04 或 CentOS 7/8 ,如非上述操作系统,退出脚本
check_operating_system() {
if [ -s /etc/os-release ]; then
SYS="$(awk -F= '/^PRETTY_NAME=/{gsub(/"/,"",$2);print $2;exit}' /etc/os-release)"
elif [ -x "$(type -p hostnamectl)" ]; then
SYS="$(awk -F: '/System/{sub(/^[ \t]+/,"",$2);print $2;exit}' < <(hostnamectl))"
elif [ -x "$(type -p lsb_release)" ]; then
SYS="$(lsb_release -sd)"
elif [ -s /etc/lsb-release ]; then
SYS="$(awk -F= '/^DISTRIB_DESCRIPTION=/{gsub(/"/,"",$2);print $2;exit}' /etc/lsb-release)"
elif [ -s /etc/redhat-release ]; then
SYS="$(awk '{print;exit}' /etc/redhat-release)"
elif [ -s /etc/issue ]; then
SYS="$(awk '{print;exit}' /etc/issue)"
fi
# 自定义 Alpine 系统若干函数
alpine_warp_restart() {
wg-quick down warp >/dev/null 2>&1
wg-quick up warp >/dev/null 2>&1
}
alpine_warp_enable() {
echo -e "/usr/bin/tun.sh\nwg-quick up warp" > /etc/local.d/warp.start
chmod +x /etc/local.d/warp.start
rc-update add local
wg-quick up warp >/dev/null 2>&1
}
REGEX=("debian" "ubuntu" "centos|red hat|kernel|alma|rocky" "alpine" "arch linux|endeavouros" "fedora")
RELEASE=("Debian" "Ubuntu" "CentOS" "Alpine" "Arch" "Fedora")
PACKAGE_UPDATE=("apt -y update" "apt -y update" "yum -y update --skip-broken" "apk update -f" "pacman -Sy" "dnf -y update")
PACKAGE_INSTALL=("apt -y install" "apt -y install" "yum -y install" "apk add -f" "pacman -S --noconfirm" "dnf -y install")
PACKAGE_UNINSTALL=("apt -y autoremove" "apt -y autoremove" "yum -y autoremove" "apk del -f" "pacman -Rcnsu --noconfirm" "dnf -y autoremove")
SYSTEMCTL_START=("systemctl start wg-quick@warp" "systemctl start wg-quick@warp" "systemctl start wg-quick@warp" "wg-quick up warp" "systemctl start wg-quick@warp" "systemctl start wg-quick@warp")
SYSTEMCTL_RESTART=("systemctl restart wg-quick@warp" "systemctl restart wg-quick@warp" "systemctl restart wg-quick@warp" "alpine_warp_restart" "systemctl restart wg-quick@warp" "systemctl restart wg-quick@warp")
SYSTEMCTL_ENABLE=("systemctl enable --now wg-quick@warp" "systemctl enable --now wg-quick@warp" "systemctl enable --now wg-quick@warp" "alpine_warp_enable" "systemctl enable --now wg-quick@warp" "systemctl enable --now wg-quick@warp")
for int in "${!REGEX[@]}"; do
[[ "${SYS,,}" =~ ${REGEX[int]} ]] && SYSTEM="${RELEASE[int]}" && break
done
# 针对各厂运的订制系统
if [ -z "$SYSTEM" ]; then
[ -x "$(type -p yum)" ] && int=2 && SYSTEM='CentOS' || error " $(text 5) "
fi
# 判断主 Linux 版本
MAJOR_VERSION=$(awk '{gsub(/[^0-9.]/,"");print int($0)}' <<< "$SYS")
}
# 安装系统依赖及定义 ping 指令
check_dependencies() {
# 对于 alpine 系统,升级库并重新安装依赖
if [ "$SYSTEM" = 'Alpine' ]; then
CHECK_WGET=$(wget 2>&1 | head -n 1)
grep -qi 'busybox' <<< "$CHECK_WGET" && ${PACKAGE_INSTALL[int]} wget >/dev/null 2>&1
DEPS_CHECK=("ping" "curl" "grep" "bash" "ip" "virt-what")
DEPS_INSTALL=("iputils-ping" "curl" "grep" "bash" "iproute2" "virt-what")
else
# 对于三大系统需要的依赖
DEPS_CHECK=("ping" "wget" "curl" "systemctl" "ip")
DEPS_INSTALL=("iputils-ping" "wget" "curl" "systemctl" "iproute2")
fi
for g in "${!DEPS_CHECK[@]}"; do
[ ! -x "$(type -p ${DEPS_CHECK[g]})" ] && [[ ! "${DEPS[@]}" =~ "${DEPS_INSTALL[g]}" ]] && DEPS+=(${DEPS_INSTALL[g]})
done
if [ "${#DEPS[@]}" -ge 1 ]; then
info "\n $(text 7) ${DEPS[@]} \n"
${PACKAGE_UPDATE[int]} >/dev/null 2>&1
${PACKAGE_INSTALL[int]} ${DEPS[@]} >/dev/null 2>&1
else
info "\n $(text 8) \n"
fi
PING6='ping -6' && [ -x "$(type -p ping6)" ] && PING6='ping6'
}
# 获取 warp 账户信息
warp_api(){
local RUN=$1
local FILE_PATH=$2
if [ -s "$FILE_PATH" ]; then
# 官方 api 文件,默认存放路径为 /etc/wireguard/warp-account.conf
if grep -q 'client_id' $FILE_PATH; then
local WARP_DEVICE_ID=$(awk -F '"' '/"id"/ {print $4; exit}' "$FILE_PATH")
local WARP_TOKEN=$(awk -F '"' '/"token"/ {print $4; exit}' "$FILE_PATH")
local WARP_CLIENT_ID=$(awk -F '"' '/client_id/ {print $4; exit}' "$FILE_PATH")
# client 文件,默认存放路径为 /var/lib/cloudflare-warp/reg.json
elif grep -q 'registration_id' $FILE_PATH; then
local WARP_DEVICE_ID=$(sed 's/.*registration_id":"\([^"]\+\)".*/\1/' "$FILE_PATH")
local WARP_TOKEN=$(sed 's/.*api_token":"\([^"]\+\)".*/\1/' "$FILE_PATH")
fi
fi
case "$RUN" in
register )
local ACCOUNT=$(curl --retry 50 --retry-delay 1 --max-time 2 --silent --location --fail "https://warp.cloudflare.nyc.mn/?run=register")
grep -q '"id"' <<< "$ACCOUNT" && echo "$ACCOUNT" ||
echo '{
"id": "b0fe9b24-3396-486e-a12d-c194dbbb7bfb",
"type": "a",
"model": "PC",
"name": "",
"key": "rizJSrjeCO51ck8Rmj9YwstFnf6M9rJKZIXFQo3y8j8=",
"private_key": "hTk06uwwXhZx3RVqtug3MQ0RSodzdM/U5z/M5NIbh4c=",
"account": {
"id": "5a43e4b3-2e13-46b9-9437-2abe55cd5f4b",
"account_type": "free",
"created": "2025-12-02T16:44:10.752518443Z",
"updated": "2025-12-02T16:44:10.752518443Z",
"premium_data": 0,
"quota": 0,
"usage": 0,
"warp_plus": true,
"referral_count": 0,
"referral_renewal_countdown": 0,
"role": "child",
"license": "36L7Pg9E-j6Jp2x04-I40UQ39C",
"ttl": "2026-03-02T16:44:10.752514723Z"
},
"config": {
"client_id": "lzaY",
"reserved": [
151,
54,
152
],
"peers": [
{
"public_key": "bmXOC+F1FxEMF9dyiK2H5/1SUtzH0JuVo51h2wPfgyo=",
"endpoint": {
"v4": "162.159.192.5:0",
"v6": "[2606:4700:d0::a29f:c005]:0",
"host": "engage.cloudflareclient.com:2408",
"ports": [
2408,
500,
1701,
4500
]
}
}
],
"interface": {
"addresses": {
"v4": "172.16.0.2",
"v6": "2606:4700:110:8921:bf06:c4d7:40b7:8afd"
}
},
"services": {
"http_proxy": "172.16.0.1:2480"
}
},
"token": "50d988c2-b5fb-c829-42dd-a33a960ea734",
"warp_enabled": false,
"waitlist_enabled": false,
"created": "2025-12-02T16:44:10.327083841Z",
"updated": "2025-12-02T16:44:10.327083841Z",
"tos": "2025-12-02T16:44:10.272Z",
"place": 0,
"locale": "zh-CN",
"enabled": true,
"install_id": "095iylvdl1trz7ukonr00g",
"fcm_token": "095iylvdl1trz7ukonr00g:APA91ba32nwi5zphdi3ercafxodyjr6iwlrrgb919l2gcm4h5irun8y8nsuhbdmc0kufcxhopvonqql4gllld8nsjaavi17hf7yfl5qhdpz03oq4u69ngu0s5hyo6wxiy4luk8xeenf1",
"serial_number": "095iylvdl1trz7ukonr00g",
"policy": {
"always_include": [
{
"ip": "162.159.197.4"
},
{
"ip": "2606:4700:102::4"
}
],
"always_exclude": [
{
"ip": "162.159.197.3"
},
{
"ip": "2606:4700:102::3"
}
],
"post_quantum": "enabled_with_downgrades",
"tunnel_protocol": "masque"
}
}'
;;
cancel )
# 只保留 Teams 或者预设账户,删除其他账户
if ! grep -oqE '"id":[ ]+("(t.[A-F0-9a-f]{8}-[A-F0-9a-f]{4}-[A-F0-9a-f]{4}-[A-F0-9a-f]{4}-[A-F0-9a-f]{12})|b0fe9b24-3396-486e-a12d-c194dbbb7bfb")' $FILE_PATH; then
curl --request DELETE "https://api.cloudflareclient.com/v0a2158/reg/${WARP_DEVICE_ID}" \
--head \
--silent \
--location \
--header 'User-Agent: okhttp/3.12.1' \
--header 'CF-Client-Version: a-6.10-2158' \
--header 'Content-Type: application/json' \
--header "Authorization: Bearer ${WARP_TOKEN}" | awk '/HTTP/{print $(NF-1)}'
fi
;;
esac
}
# 聚合 IP api 函数。由于 ip.sb 会对某些 ip 访问报 error code: 1015,所以使用备用 IP api: ifconfig.co
ip_info() {
local CHECK_46="$1"
if [[ "$2" =~ ^[0-9]+$ ]]; then
local INTERFACE_SOCK5="--proxy socks5h://127.0.0.1:$2"
elif [[ "$2" =~ ^[[:alnum:]]+$ ]]; then
local INTERFACE_SOCK5="--interface $2"
fi
[ "$L" = 'C' ] && local IS_CHINESE=${IS_CHINESE:-'?lang=zh-CN'}
# 对于查 socks5 代理的 IP,需要用另一个 IP api
if grep -q 'socks5' <<< "$INTERFACE_SOCK5"; then
local WAN=$(curl -s -A a --retry 2 $INTERFACE_SOCK5 https://api-ipv${CHECK_46}.ip.sb/ip) &&
local IP_JSON=$(curl -sm2 --retry 2 https://ip.cloudflare.nyc.mn/${WAN}${IS_CHINESE}) &&
grep -qi '"isp".*Cloudflare' <<< "$IP_JSON" && local IP_TRACE='on'
else
local IP_JSON=$(curl --retry 2 -ksm2 $INTERFACE_SOCK5 -$CHECK_46 https://ip.cloudflare.nyc.mn${IS_CHINESE}) &&
local IP_TRACE=$(awk -F '"' '/"warp"/{print $4}' <<< "$IP_JSON") &&
local WAN=$(awk -F '"' '/"ip"/{print $4}' <<< "$IP_JSON")
fi
if grep -q '"ip"' <<< "$IP_JSON"; then
local COUNTRY=$(awk -F '"' '/"country"/{print $4}' <<< "$IP_JSON")
local ASNORG=$(awk -F '"' '/"isp"/{print $4}' <<< "$IP_JSON")
fi
echo "{ \"trace\": \"$IP_TRACE\", \"ip\": \"$WAN\", \"country\": \"$COUNTRY\", \"asnorg\": \"$ASNORG\" }"
}
# 根据场景传参调用自定义 IP api
ip_case() {
local CHECK_46="$1"
[ -n "$2" ] && local CHECK_TYPE="$2"
[ "$3" = 'non-global' ] && local CHECK_NONGLOBAL='warp'
if [ "$CHECK_TYPE" = "warp" ]; then
fetch_4() {
unset IP_RESULT4 COUNTRY4 ASNORG4 TRACE4
local IP_RESULT4=$(ip_info 4 "$CHECK_NONGLOBAL")
TRACE4=$(sed -n 's/.*"trace":[ ]*"\([^"]*\)".*/\1/p' <<< "$IP_RESULT4")
WAN4=$(sed -n 's/.*"ip":[ ]*"\([^"]*\)".*/\1/p' <<< "$IP_RESULT4")
COUNTRY4=$(sed -n 's/.*"country":[ ]*"\([^"]*\)".*/\1/p' <<< "$IP_RESULT4")
ASNORG4=$(sed -n 's/.*"asnorg":[ ]*"\([^"]*\)".*/\1/p' <<< "$IP_RESULT4")
}
fetch_6() {
unset IP_RESULT6 COUNTRY6 ASNORG6 TRACE6
local IP_RESULT6=$(ip_info 6 "$CHECK_NONGLOBAL")
TRACE6=$(sed -n 's/.*"trace":[ ]*"\([^"]*\)".*/\1/p' <<< "$IP_RESULT6")
WAN6=$(sed -n 's/.*"ip":[ ]*"\([^"]*\)".*/\1/p' <<< "$IP_RESULT6")
COUNTRY6=$(sed -n 's/.*"country":[ ]*"\([^"]*\)".*/\1/p' <<< "$IP_RESULT6")
ASNORG6=$(sed -n 's/.*"asnorg":[ ]*"\([^"]*\)".*/\1/p' <<< "$IP_RESULT6")
}
case "$CHECK_46" in
4|6 )
fetch_${CHECK_46}
;;
d|u )
# 如在非全局模式,根据 AllowedIPs 的 v4、v6 情况再查 ip 信息;如在全局模式下则全部查
if [ -e /etc/wireguard/warp.conf ] && grep -q '^Table' /etc/wireguard/warp.conf; then
grep -q "^#.*0\.\0\/0" 2>/dev/null /etc/wireguard/warp.conf || fetch_4
grep -q "^#.*\:\:\/0" 2>/dev/null /etc/wireguard/warp.conf || fetch_6
else
fetch_4
fetch_6
fi
;;
esac
elif [ "$CHECK_TYPE" = "wireproxy" ]; then
fetch_4() {
unset IP_RESULT4 WIREPROXY_TRACE4 WIREPROXY_WAN4 WIREPROXY_COUNTRY4 WIREPROXY_ASNORG4 ACCOUNT AC
local IP_RESULT4=$(ip_info 4 "$WIREPROXY_PORT")
WIREPROXY_TRACE4=$(sed -n 's/.*"trace":[ ]*"\([^"]*\)".*/\1/p' <<< "$IP_RESULT4")
WIREPROXY_WAN4=$(sed -n 's/.*"ip":[ ]*"\([^"]*\)".*/\1/p' <<< "$IP_RESULT4")
WIREPROXY_COUNTRY4=$(sed -n 's/.*"country":[ ]*"\([^"]*\)".*/\1/p' <<< "$IP_RESULT4")
WIREPROXY_ASNORG4=$(sed -n 's/.*"asnorg":[ ]*"\([^"]*\)".*/\1/p' <<< "$IP_RESULT4")
}
fetch_6() {
unset IP_RESULT6 WIREPROXY_TRACE6 WIREPROXY_WAN6 WIREPROXY_COUNTRY6 WIREPROXY_ASNORG6 ACCOUNT AC
local IP_RESULT6=$(ip_info 6 "$WIREPROXY_PORT")
WIREPROXY_TRACE6=$(sed -n 's/.*"trace":[ ]*"\([^"]*\)".*/\1/p' <<< "$IP_RESULT6")
WIREPROXY_WAN6=$(sed -n 's/.*"ip":[ ]*"\([^"]*\)".*/\1/p' <<< "$IP_RESULT6")
WIREPROXY_COUNTRY6=$(sed -n 's/.*"country":[ ]*"\([^"]*\)".*/\1/p' <<< "$IP_RESULT6")
WIREPROXY_ASNORG6=$(sed -n 's/.*"asnorg":[ ]*"\([^"]*\)".*/\1/p' <<< "$IP_RESULT6")
}
unset WIREPROXY_SOCKS5 WIREPROXY_PORT
WIREPROXY_SOCKS5=$(ss -nltp | awk '/"wireproxy"/{print $4}')
WIREPROXY_PORT=$(cut -d: -f2 <<< "$WIREPROXY_SOCKS5")
case "$CHECK_46" in
4|6 )
fetch_$CHECK_46
[ "$(eval echo "\$WIREPROXY_TRACE$CHECK_46")" = plus ] && WIREPROXY_ACCOUNT='+' || WIREPROXY_ACCOUNT=' Free'
;;
d )
fetch_4
fetch_6
[[ "$WIREPROXY_TRACE4$WIREPROXY_TRACE6" =~ 'plus' ]] && WIREPROXY_ACCOUNT='+' || WIREPROXY_ACCOUNT=' Free'
esac
elif [ "$CHECK_TYPE" = "client" ]; then
fetch_4(){
unset IP_RESULT4 CLIENT_TRACE4 CLIENT_WAN4 CLIENT_COUNTRY4 CLIENT_ASNORG4 CLIENT_ACCOUNT CLIENT_AC
local IP_RESULT4=$(ip_info 4 "$CLIENT_PORT")
CLIENT_TRACE4=$(sed -n 's/.*"trace":[ ]*"\([^"]*\)".*/\1/p' <<< "$IP_RESULT4")
CLIENT_WAN4=$(sed -n 's/.*"ip":[ ]*"\([^"]*\)".*/\1/p' <<< "$IP_RESULT4")
CLIENT_COUNTRY4=$(sed -n 's/.*"country":[ ]*"\([^"]*\)".*/\1/p' <<< "$IP_RESULT4")
CLIENT_ASNORG4=$(sed -n 's/.*"asnorg":[ ]*"\([^"]*\)".*/\1/p' <<< "$IP_RESULT4")
}
fetch_6(){
unset IP_RESULT6 CLIENT_TRACE6 CLIENT_WAN6 CLIENT_COUNTRY6 CLIENT_ASNORG6 CLIENT_ACCOUNT CLIENT_AC
local IP_RESULT6=$(ip_info 6 "$CLIENT_PORT")
CLIENT_TRACE6=$(sed -n 's/.*"trace":[ ]*"\([^"]*\)".*/\1/p' <<< "$IP_RESULT6")
CLIENT_WAN6=$(sed -n 's/.*"ip":[ ]*"\([^"]*\)".*/\1/p' <<< "$IP_RESULT6")
CLIENT_COUNTRY6=$(sed -n 's/.*"country":[ ]*"\([^"]*\)".*/\1/p' <<< "$IP_RESULT6")
CLIENT_ASNORG6=$(sed -n 's/.*"asnorg":[ ]*"\([^"]*\)".*/\1/p' <<< "$IP_RESULT6")
}
unset CLIENT_SOCKS5 CLIENT_PORT
CLIENT_SOCKS5=$(ss -nltp | awk '/"warp-svc"/{print $4}')
CLIENT_PORT=$(cut -d: -f2 <<< "$CLIENT_SOCKS5")
if [ "$CHECK_46" = 'd' ]; then
fetch_4
fetch_6
else
fetch_$CHECK_46
fi
local CLIENT_ACCOUNT=$(warp-cli --accept-tos registration show 2>/dev/null | awk '/type/{print $3}')
[ "$CLIENT_ACCOUNT" = Limited ] && CLIENT_AC='+' || CLIENT_AC=' Free'
elif [ "$CHECK_TYPE" = "is_luban" ]; then
fetch_4(){
unset IP_RESULT4 CFWARP_COUNTRY4 CFWARP_ASNORG4 CFWARP_TRACE4 CFWARP_WAN4 CLIENT_ACCOUNT CLIENT_AC
local IP_RESULT4=$(ip_info 4 CloudflareWARP)
CFWARP_TRACE4=$(sed -n 's/.*"trace":[ ]*"\([^"]*\)".*/\1/p' <<< "$IP_RESULT4")
CFWARP_WAN4=$(sed -n 's/.*"ip":[ ]*"\([^"]*\)".*/\1/p' <<< "$IP_RESULT4")
CFWARP_COUNTRY4=$(sed -n 's/.*"country":[ ]*"\([^"]*\)".*/\1/p' <<< "$IP_RESULT4")
CFWARP_ASNORG4=$(sed -n 's/.*"asnorg":[ ]*"\([^"]*\)".*/\1/p' <<< "$IP_RESULT4")
}
fetch_6(){
unset IP_RESULT6 CFWARP_COUNTRY6 CFWARP_ASNORG6 CFWARP_TRACE6 CFWARP_WAN6 CLIENT_ACCOUNT CLIENT_AC
local IP_RESULT6=$(ip_info 6 CloudflareWARP)
CFWARP_TRACE6=$(sed -n 's/.*"trace":[ ]*"\([^"]*\)".*/\1/p' <<< "$IP_RESULT6")
CFWARP_WAN6=$(sed -n 's/.*"ip":[ ]*"\([^"]*\)".*/\1/p' <<< "$IP_RESULT6")
CFWARP_COUNTRY6=$(sed -n 's/.*"country":[ ]*"\([^"]*\)".*/\1/p' <<< "$IP_RESULT6")
CFWARP_ASNORG6=$(sed -n 's/.*"asnorg":[ ]*"\([^"]*\)".*/\1/p' <<< "$IP_RESULT6")
}
if [ "$CHECK_46" = 'd' ]; then
fetch_4
fetch_6
else
fetch_$CHECK_46
fi
local CLIENT_ACCOUNT=$(warp-cli --accept-tos registration show 2>/dev/null | awk '/type/{print $3}')
[ "$CLIENT_ACCOUNT" = Limited ] && CLIENT_AC='+' || CLIENT_AC=' Free'
fi
}
# 帮助说明
help() { hint " $(text 6) "; }
# IPv4 / IPv6 优先设置
stack_priority() {
[ "$OPTION" = s ] && case "$PRIORITY_SWITCH" in
4 )
PRIORITY=1
;;
6 )
PRIORITY=2
;;
d )
:
;;
* )
hint "\n $(text 74) \n" && reading " $(text 50) " PRIORITY
esac
[ -e /etc/gai.conf ] && sed -i '/^precedence \:\:ffff\:0\:0/d;/^label 2002\:\:\/16/d' /etc/gai.conf
case "$PRIORITY" in
1 )
echo "precedence ::ffff:0:0/96 100" >> /etc/gai.conf
;;
2 )
echo "label 2002::/16 2" >> /etc/gai.conf
;;
esac
}
# IPv4 / IPv6 优先结果
result_priority() {
PRIO=(0 0)
if [ -e /etc/gai.conf ]; then
grep -qsE "^precedence[ ]+::ffff:0:0/96[ ]+100" /etc/gai.conf && PRIO[0]=1
grep -qsE "^label[ ]+2002::/16[ ]+2" /etc/gai.conf && PRIO[1]=1
fi
case "${PRIO[*]}" in
'1 0' )
PRIO=4
;;
'0 1' )
PRIO=6
;;
* )
[[ "$(curl -ksm8 --user-agent Mozilla https://www.cloudflare.com/cdn-cgi/trace | awk -F '=' '/^ip/{print $NF}')" =~ ^([0-9]{1,3}\.){3} ]] && PRIO=4 || PRIO=6
esac
PRIORITY_NOW=$(text 97)
# 如是快捷方式切换优先级别的话,显示结果
[ "$OPTION" = s ] && hint "\n $PRIORITY_NOW \n"
}
# 更换 Netflix IP 时确认期望区域
input_region() {
if [ -n "$NF" ]; then
REGION=$(curl --user-agent "${UA_Browser}" -$NF $GLOBAL -fs --max-time 10 http://www.cloudflare.com/cdn-cgi/trace | awk -F '=' '/^loc/{print $NF}')
elif [ -n "$WIREPROXY_PORT" ]; then
REGION=$(curl --user-agent "${UA_Browser}" --proxy socks5h://127.0.0.1:$WIREPROXY_PORT -fs --max-time 10 http://www.cloudflare.com/cdn-cgi/trace | awk -F '=' '/^loc/{print $NF}')
elif [ -n "$INTERFACE" ]; then
REGION=$(curl --user-agent "${UA_Browser}" $INTERFACE -fs --max-time 10 http://www.cloudflare.com/cdn-cgi/trace | awk -F '=' '/^loc/{print $NF}')
else
REGION='US'
fi
reading " $(text 56) " EXPECT
until [[ -z "$EXPECT" || "${EXPECT,,}" = 'y' || "${EXPECT,,}" =~ ^[a-z]{2}$ ]]; do
reading " $(text 56) " EXPECT
done
[[ -z "$EXPECT" || "${EXPECT,,}" = 'y' ]] && EXPECT="${REGION^^}"
}
# 更换支持 Netflix WARP IP 改编自 [luoxue-bot] 的成熟作品,地址[https://github.com/luoxue-bot/warp_auto_change_ip]
change_ip() {
check_unlock() {
ARGS=$1;
{
curl $ARGS --user-agent "${UA_Browser}" --include -SsL --max-time 10 --tlsv1.3 "$URL_ORIGINAL";
curl $ARGS --user-agent "${UA_Browser}" --include -SsL --max-time 10 --tlsv1.3 "$URL_REGIONAL";
} 2>&1 | awk '
# NR==1 表示处理第一行数据,设置 u 为 1 表示开始处理第一个 URL 的结果
NR==1 { u=1 }
# 如果检测到 HTTP/2 200 且 c 尚未设置,说明第一个测试页面连接成功
/HTTP\/2 200/ && u && !c { c=1 }
# 如果页面源码中包含 og:video 标签,说明可以播放该视频 (v=1 代表全解锁)
/og:video/ { v=1 }
# 匹配页面源码中的 "requestCountry" 字段,提取区域 ID (如 HK, US, TW)
{
if (u && !r && match($0, /"requestCountry":\{"supportedLocales":\[[^]]+\],"id":"[^"]+"/)) {
s = substr($0, RSTART, RLENGTH);
sub(/.*"id":"*/, "", s);
sub(/".*/, "", s);
r = s
}
}
# 打印最终的 JSON 结果
END {
print "{";
print " \"connect\": " (c ? "true" : "false") ",";
if (c) {
print " \"Netflix\": \"" (v ? "Yes" : "Originals Only") "\",";
print " \"region\": \"" r "\""
};
print "}"
}
'
}
change_stack() {
hint "\n $(text 36) \n" && reading " $(text 50) " NETFLIX
[ "$NETFLIX" = 1 ] && { NF='4'; SOCKS5_NF='-4'; } || { NF='6'; SOCKS5_NF=''; }
}
change_warp() {
warp_restart() {
warning " $(text 55) "
wg | grep -q '^interface:' && wg-quick down warp >/dev/null 2>&1
warp_api "cancel" "/etc/wireguard/warp-account.conf" >/dev/null 2>&1
warp_api "register" > /etc/wireguard/warp-account.conf 2>/dev/null
local PRIVATEKEY="$(grep 'private_key' /etc/wireguard/warp-account.conf | cut -d\" -f4)"
local ADDRESS6="$(grep '"v6.*"$' /etc/wireguard/warp-account.conf | cut -d\" -f4)"
local CLIENT_ID="$(awk '/"reserved": \[/{flag=1; printf "["; next} flag && /\]/{printf "]"; flag=0; print ""; next} flag {gsub(/[ \t\n\r]/,""); printf "%s", $0}' /etc/wireguard/warp-account.conf)"
[ -s /etc/wireguard/warp.conf ] && sed -i "s#\(PrivateKey[ ]\+=[ ]\+\).*#\1$PRIVATEKEY#g; s#\(Address[ ]\+=[ ]\+\).*\(/128$\)#\1$ADDRESS6\2#g; s#\(.*Reserved[ ]\+=[ ]\+\).*#\1$CLIENT_ID#g" /etc/wireguard/warp.conf
ss -nltp | grep dnsmasq >/dev/null 2>&1 && systemctl restart dnsmasq >/dev/null 2>&1
wg-quick up warp >/dev/null 2>&1
sleep $j
}
unset T4 T6
grep -q "^#.*0\.\0\/0" 2>/dev/null /etc/wireguard/warp.conf && T4=0 || T4=1
grep -q "^#.*\:\:\/0" 2>/dev/null /etc/wireguard/warp.conf && T6=0 || T6=1
case "$T4$T6" in
01 )
NF='6'
;;
10 )
NF='4'
;;
11 )
change_stack
esac
# 检测[全局]或[非全局]
grep -q '^Table' /etc/wireguard/warp.conf && GLOBAL='--interface warp'
[ -z "$EXPECT" ] && input_region
i=0; j=10
while true; do
(( i++ )) || true
ip_now=$(date +%s); RUNTIME=$((ip_now - ip_start)); DAY=$(( RUNTIME / 86400 )); HOUR=$(( (RUNTIME % 86400 ) / 3600 )); MIN=$(( (RUNTIME % 86400 % 3600) / 60 )); SEC=$(( RUNTIME % 86400 % 3600 % 60 ))
[ "$GLOBAL" = '--interface warp' ] && ip_case "$NF" warp non-global || ip_case "$NF" warp
WAN=$(eval echo \$WAN$NF) && COUNTRY=$(eval echo \$COUNTRY$NF) && ASNORG=$(eval echo \$ASNORG$NF)
unset RESULT REGION
local RESULT=$(check_unlock "-$NF $GLOBAL")
local REGION=$(awk -F '"' '/region/{print $4}' <<< "${RESULT}")
REGION=${REGION:-'US'}
grep -q '"Yes"' <<< "${RESULT}" && grep -qi "$EXPECT" <<< "$REGION" && info " $(text 54) " && i=0 && sleep 1h || warp_restart
done
}
change_client() {
client_restart() {
local CLIENT_MODE=$(warp-cli --accept-tos settings | awk '/Mode:/{for (i=0; i<NF; i++) if ($i=="Mode:") {print $(i+1)}}')
case "$CLIENT_MODE" in
Warp )
warning " $(text 55) " && warp-cli --accept-tos registration delete >/dev/null 2>&1
rule_del >/dev/null 2>&1
warp-cli --accept-tos registration new >/dev/null 2>&1
sleep $j
rule_add >/dev/null 2>&1
;;
WarpProxy )
warning " $(text 55) "
warp-cli --accept-tos registration delete >/dev/null 2>&1
warp-cli --accept-tos registration new >/dev/null 2>&1
sleep $j
esac
}
change_stack
if [ "$(warp-cli --accept-tos settings | awk '/Mode:/{for (i=0; i<NF; i++) if ($i=="Mode:") {print $(i+1)}}')" = 'WarpProxy' ]; then
[ -z "$EXPECT" ] && input_region
i=0; j=10
while true; do
(( i++ )) || true
ip_now=$(date +%s); RUNTIME=$((ip_now - ip_start)); DAY=$(( RUNTIME / 86400 )); HOUR=$(( (RUNTIME % 86400 ) / 3600 )); MIN=$(( (RUNTIME % 86400 % 3600) / 60 )); SEC=$(( RUNTIME %86400 % 3600 % 60 ))
ip_case "$NF" client
WAN=$(eval echo "\$CLIENT_WAN$NF") && ASNORG=$(eval echo "\$CLIENT_ASNORG$NF") && COUNTRY=$(eval echo "\$CLIENT_COUNTRY$NF")
unset RESULT REGION
local RESULT=$(check_unlock "$SOCKS5_NF -sx socks5h://127.0.0.1:$CLIENT_PORT")
local REGION=$(awk -F '"' '/region/{print $4}' <<< "${RESULT}")
REGION=${REGION:-'US'}
grep -q '"Yes"' <<< "${RESULT}" && grep -qi "$EXPECT" <<< "$REGION" && info " $(text 54) " && i=0 && sleep 1h || client_restart
done
else
[ -z "$EXPECT" ] && input_region
i=0; j=10
while true; do
(( i++ )) || true
ip_now=$(date +%s); RUNTIME=$((ip_now - ip_start)); DAY=$(( RUNTIME / 86400 )); HOUR=$(( (RUNTIME % 86400 ) / 3600 )); MIN=$(( (RUNTIME % 86400 % 3600) / 60 )); SEC=$(( RUNTIME % 86400 % 3600 % 60 ))
ip_case "$NF" is_luban
WAN=$(eval echo "\$CFWARP_WAN$NF") && COUNTRY=$(eval echo "\$CFWARP_COUNTRY$NF") && ASNORG=$(eval echo "\$CFWARP_ASNORG$NF")
unset RESULT REGION
local RESULT=$(check_unlock "$INTERFACE -sx socks5h://127.0.0.1:$CLIENT_PORT")
local REGION=$(awk -F '"' '/region/{print $4}' <<< "${RESULT}")
REGION=${REGION:-'US'}
grep -q '"Yes"' <<< "${RESULT}" && grep -qi "$EXPECT" <<< "$REGION" && info " $(text 54) " && i=0 && sleep 1h || client_restart
done
fi
}
change_wireproxy() {
wireproxy_restart() { warning " $(text 55) " && systemctl restart wireproxy; sleep $j; }
change_stack
[ -z "$EXPECT" ] && input_region
i=0; j=3
while true; do
(( i++ )) || true
ip_now=$(date +%s); RUNTIME=$((ip_now - ip_start)); DAY=$(( RUNTIME / 86400 )); HOUR=$(( (RUNTIME % 86400 ) / 3600 )); MIN=$(( (RUNTIME % 86400 % 3600) / 60 )); SEC=$(( RUNTIME % 86400 % 3600 % 60 ))
ip_case "$NF" wireproxy
WAN=$(eval echo "\$WIREPROXY_WAN$NF") && ASNORG=$(eval echo "\$WIREPROXY_ASNORG$NF") && COUNTRY=$(eval echo "\$WIREPROXY_COUNTRY$NF")
unset RESULT REGION
local RESULT=$(check_unlock "$SOCKS5_NF -sx socks5h://127.0.0.1:$WIREPROXY_PORT")
local REGION=$(awk -F '"' '/region/{print $4}' <<< "${RESULT}")
REGION=${REGION:-'US'}
grep -q '"Yes"' <<< "${RESULT}" && grep -qi "$EXPECT" <<< "$REGION" && info " $(text 54) " && i=0 && sleep 1h || wireproxy_restart
done
}
# 设置时区,让时间戳时间准确,显示脚本运行时长,中文为 GMT+8,英文为 UTC; 设置 UA
ip_start=$(date +%s)
[ "$SYSTEM" != Alpine ] && ( [ "$L" = C ] && timedatectl set-timezone Asia/Shanghai || timedatectl set-timezone UTC )
# 定义测试的两个 URL
# 81280792 通常是全球自制剧 (Netflix Original)
# 70143836 通常是非全球授权剧 (如 Breaking Bad),用于检测是否全解锁
local URL_ORIGINAL="https://www.netflix.com/title/81280792"
local URL_REGIONAL="https://www.netflix.com/title/70143836"
local UA_Browser="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.87 Safari/537.36"
# 根据 WARP interface 、 Client 和 Wireproxy 的安装情况判断刷 IP 的方式
INSTALL_CHECK=("wg-quick" "warp-cli" "wireproxy")
CASE_RESAULT=("0 0 0" "0 0 1" "0 1 0" "0 1 1" "1 0 0" "1 0 1" "1 1 0" "1 1 1")
SHOW_CHOOSE=("$(text 115)" "" "" "$(text 116)" "" "$(text 117)" "$(text 118)" "$(text 119)")
CHANGE_IP1=("" "change_wireproxy" "change_client" "change_client" "change_warp" "change_warp" "change_warp" "change_warp")
CHANGE_IP2=("" "" "" "change_wireproxy" "" "change_wireproxy" "change_client" "change_client")
CHANGE_IP3=("" "" "" "" "" "" "" "change_wireproxy")
for a in ${!INSTALL_CHECK[@]}; do
[ -x "$(type -p ${INSTALL_CHECK[a]})" ] && INSTALL_RESULT[a]=1 || INSTALL_RESULT[a]=0
done
for b in ${!CASE_RESAULT[@]}; do
[[ "${INSTALL_RESULT[@]}" = "${CASE_RESAULT[b]}" ]] && break
done
case "$b" in
0 )
error " $(text 115) "
;;
1|2|4 )
${CHANGE_IP1[b]}
;;
* )
hint "\n ${SHOW_CHOOSE[b]} \n" && reading " $(text 50) " MODE
case "$MODE" in
[1-3] )
$(eval echo "\${CHANGE_IP$MODE[b]}")
;;
* )
warning " $(text 51) [1-3] "; sleep 1; change_ip
esac
esac
}
# 安装BBR
bbrInstall() {
echo -e "\n==============================================================\n"
info " $(text 47) "
echo -e "\n==============================================================\n"
hint " 1. $(text 48) "
[ "$OPTION" != b ] && hint " 0. $(text 49) \n" || hint " 0. $(text 76) \n"
reading " $(text 50) " BBR
case "$BBR" in
1 )
wget --no-check-certificate -N "${GH_PROXY}https://raw.githubusercontent.com/ylx2016/Linux-NetSpeed/master/tcp.sh" && chmod +x tcp.sh && ./tcp.sh
;;
0 )
[ "$OPTION" != b ] && menu || exit
;;
* )
warning " $(text 51) [0-1]"; sleep 1; bbrInstall
esac
}
# 关闭 WARP 网络接口,并删除 WARP
uninstall() {
unset IP4 IP6 WAN4 WAN6 COUNTRY4 COUNTRY6 ASNORG4 ASNORG6
# 卸载 WARP
uninstall_warp() {
wg-quick down warp >/dev/null 2>&1
systemctl disable --now wg-quick@warp >/dev/null 2>&1; sleep 3
[ -x "$(type -p rpm)" ] && rpm -e wireguard-tools 2>/dev/null
systemctl restart systemd-resolved >/dev/null 2>&1; sleep 3
warp_api "cancel" "/etc/wireguard/warp-account.conf" >/dev/null 2>&1
rm -rf /usr/bin/wireguard-go /usr/bin/warp /etc/dnsmasq.d/warp.conf /usr/bin/wireproxy /etc/local.d/warp.start
[ -e /etc/gai.conf ] && sed -i '/^precedence \:\:ffff\:0\:0/d;/^label 2002\:\:\/16/d' /etc/gai.conf
[ -e /usr/bin/tun.sh ] && rm -f /usr/bin/tun.sh
[ -e /etc/crontab ] && sed -i '/tun.sh/d' /etc/crontab
[ -e /etc/iproute2/rt_tables ] && sed -i "/250 warp/d" /etc/iproute2/rt_tables
[ -e /etc/resolv.conf.origin ] && mv -f /etc/resolv.conf.origin /etc/resolv.conf
}
# 卸载 Linux Client
uninstall_client() {
[ "$(warp-cli --accept-tos settings | awk '/Mode:/{for (i=0; i<NF; i++) if ($i=="Mode:") {print $(i+1)}}')" = 'Warp' ] && rule_del >/dev/null 2>&1
warp-cli --accept-tos disconnect >/dev/null 2>&1
warp-cli --accept-tos registration delete >/dev/null 2>&1
systemctl disable --now warp-svc >/dev/null 2>&1
${PACKAGE_UNINSTALL[int]} cloudflare-warp 2>/dev/null
rm -rf /usr/bin/wireguard-go /usr/bin/warp $HOME/.local/share/warp /usr/share/keyrings/cloudflare-warp-archive-keyring.gpg /etc/apt/sources.list.d/cloudflare-client.list /etc/yum.repos.d/cloudflare-warp.repo
}
# 卸载 Wireproxy
uninstall_wireproxy() {
if [ "$SYSTEM" = Alpine ]; then
rc-update del wireproxy default
rc-service wireproxy stop >/dev/null 2>&1
rm -f /etc/init.d/wireproxy
else
systemctl disable --now wireproxy
fi
warp_api "cancel" "/etc/wireguard/warp-account.conf" >/dev/null 2>&1
rm -rf /usr/bin/wireguard-go /usr/bin/warp /etc/dnsmasq.d/warp.conf /usr/bin/wireproxy /lib/systemd/system/wireproxy.service
[ -e /etc/gai.conf ] && sed -i '/^precedence \:\:ffff\:0\:0/d;/^label 2002\:\:\/16/d' /etc/gai.conf
[ -e /usr/bin/tun.sh ] && rm -f /usr/bin/tun.sh && sed -i '/tun.sh/d' /etc/crontab
}
# 如已安装 warp_unlock 项目,先行卸载
[ -e /usr/bin/warp_unlock.sh ] && bash <(curl -sSL https://gitlab.com/fscarmen/warp_unlock/-/raw/main/unlock.sh) -U -$L
# 根据已安装情况执行卸载任务并显示结果
[[ "$SYSTEM" = 'Ubuntu' && "$MAJOR_VERSION" -ge 24 ]] && RESOLVER_PKG=resolvconf || RESOLVER_PKG=openresolv
UNINSTALL_CHECK=("wg-quick" "warp-cli" "wireproxy")
UNINSTALL_DO=("uninstall_warp" "uninstall_client" "uninstall_wireproxy")
UNINSTALL_DEPENDENCIES=("wireguard-tools $RESOLVER_PKG " "" " $RESOLVER_PKG ")
UNINSTALL_NOT_ARCH=("wireguard-dkms " "" "wireguard-dkms $RESOLVER_PKG ")
UNINSTALL_DNSMASQ=("ipset dnsmasq $RESOLVER_PKG ")
UNINSTALL_RESULT=("$(text 62)" "$(text 53)" "$(text 98)")
for i in ${!UNINSTALL_CHECK[@]}; do
[ -x "$(type -p ${UNINSTALL_CHECK[i]})" ] && UNINSTALL_DO_LIST[i]=1 && UNINSTALL_DEPENDENCIES_LIST+=${UNINSTALL_DEPENDENCIES[i]}
[[ $SYSTEM != "Arch" && $(dkms status 2>/dev/null) =~ wireguard ]] && UNINSTALL_DEPENDENCIES_LIST+=${UNINSTALL_NOT_ARCH[i]}
[ -e /etc/dnsmasq.d/warp.conf ] && UNINSTALL_DEPENDENCIES_LIST+=${UNINSTALL_DNSMASQ[i]}
done
# 列出依赖,确认是手动还是自动卸载
UNINSTALL_DEPENDENCIES_LIST=$(awk '{for(i=1;i<=NF;i++) if(!seen[$i]++) printf("%s%s",(c++?" ":""),$i)}' <<< "$UNINSTALL_DEPENDENCIES_LIST")
[ "$UNINSTALL_DEPENDENCIES_LIST" != '' ] && hint "\n $(text 79) \n" && reading " $(text 133) " CONFIRM_UNINSTALL
# 卸载核心程序
for i in ${!UNINSTALL_CHECK[@]}; do
[[ "${UNINSTALL_DO_LIST[i]}" = 1 ]] && ( ${UNINSTALL_DO[i]}; info " ${UNINSTALL_RESULT[i]} " )
done
# 删除本脚本安装在 /etc/wireguard/ 下的所有文件,如果删除后目录为空,一并把目录删除
if [ -s /usr/bin/wg-quick.origin ]; then
# 检查是否需要还原wg-quick.origin文件
grep -q '^#[[:space:]]\+add_if$' /usr/bin/wg-quick.origin && sed -i 's/#\([[:space:]]\+add_if\)/\1/; /wireguard-go "$INTERFACE"/d' /usr/bin/wg-quick.origin
mv -f /usr/bin/wg-quick.origin /usr/bin/wg-quick
fi
rm -f /usr/bin/wg-quick.{origin,reserved}
rm -f /tmp/{best_mtu,wireguard-go-*}
rm -f /etc/wireguard/{warp-account.conf,warp_unlock.sh,warp.conf,up,down,proxy.conf,menu.sh,language,NonGlobalUp.sh,NonGlobalDown.sh}
[[ -e /etc/wireguard && -z "$(ls -A /etc/wireguard/)" ]] && rmdir /etc/wireguard
# 选择自动卸载依赖执行以下
[[ "$UNINSTALL_DEPENDENCIES_LIST" != '' && "${CONFIRM_UNINSTALL,,}" = 'y' ]] && ( ${PACKAGE_UNINSTALL[int]} $UNINSTALL_DEPENDENCIES_LIST 2>/dev/null; info " $(text 134) \n" )
# 显示卸载结果
systemctl restart systemd-resolved >/dev/null 2>&1; sleep 3
ip_case u warp
info " $(text 45)\n IPv4: $WAN4 $COUNTRY4 $ASNORG4\n IPv6: $WAN6 $COUNTRY6 $ASNORG6 "
}
# 同步脚本至最新版本
ver() {
mkdir -p /tmp; rm -f /tmp/menu.sh
wget -O /tmp/menu.sh https://gitlab.com/fscarmen/warp/-/raw/main/menu.sh
if [ -s /tmp/menu.sh ]; then
mv /tmp/menu.sh /etc/wireguard/
chmod +x /etc/wireguard/menu.sh
ln -sf /etc/wireguard/menu.sh /usr/bin/warp
info " $(text 64):$(grep ^VERSION /etc/wireguard/menu.sh | sed "s/.*=//g") $(text 18):$(grep "${L}\[1\]" /etc/wireguard/menu.sh | cut -d \" -f2) "
else
error " $(text 65) "
fi
exit
}
# 由于warp bug,有时候获取不了ip地址,加入刷网络脚本手动运行,并在定时任务加设置 VPS 重启后自动运行,i=当前尝试次数,j=要尝试的次数
net() {
local NO_OUTPUT="$1"
unset IP4 IP6 WAN4 WAN6 COUNTRY4 COUNTRY6 ASNORG4 ASNORG6 WARPSTATUS4 WARPSTATUS6 TYPE
[ ! -x "$(type -p wg-quick)" ] && error " $(text 10) "
[ ! -e /etc/wireguard/warp.conf ] && error " $(text 108) "
local i=1; local j=5
hint " $(text 11)\n $(text 12) "
[ "$SYSTEM" != Alpine ] && [[ $(systemctl is-active wg-quick@warp) != 'active' ]] && wg-quick down warp >/dev/null 2>&1
${SYSTEMCTL_START[int]} >/dev/null 2>&1
wg-quick up warp >/dev/null 2>&1
ss -nltp | grep dnsmasq >/dev/null 2>&1 && systemctl restart dnsmasq >/dev/null 2>&1
PING6='ping -6' && [ -x "$(type -p ping6)" ] && PING6='ping6'
LAN4=$(ip route get 192.168.193.10 2>/dev/null | awk '{for (i=0; i<NF; i++) if ($i=="src") {print $(i+1)}}')
LAN6=$(ip route get 2606:4700:d0::a29f:c001 2>/dev/null | awk '{for (i=0; i<NF; i++) if ($i=="src") {print $(i+1)}}')
if [[ $(ip link show | awk -F': ' '{print $2}') =~ warp ]]; then
grep -q '#Table' /etc/wireguard/warp.conf && GLOBAL_OR_NOT="$(text 95)" || GLOBAL_OR_NOT="$(text 96)"
if grep -q '^AllowedIPs.*:\:\/0' 2>/dev/null /etc/wireguard/warp.conf; then
local NET_6_NONGLOBAL=1
ip_case 6 warp non-global
else
[[ "$LAN6" =~ ^[a-f0-9:]{1,}$ ]] && $PING6 -c2 -w10 2606:4700:d0::a29f:c001 >/dev/null 2>&1 && local NET_6_NONGLOBAL=0 && ip_case 6 warp
fi
if grep -q '^AllowedIPs.*0\.\0\/0' 2>/dev/null /etc/wireguard/warp.conf; then
local NET_4_NONGLOBAL=1
ip_case 4 warp non-global
else
[[ "$LAN4" =~ ^([0-9]{1,3}\.){3} ]] && ping -c2 -W3 162.159.192.1 >/dev/null 2>&1 && local NET_4_NONGLOBAL=0 && ip_case 4 warp
fi
else
[[ "$LAN6" =~ ^[a-f0-9:]{1,}$ ]] && INET6=1 && $PING6 -c2 -w10 2606:4700:d0::a29f:c001 >/dev/null 2>&1 && local NET_6_NONGLOBAL=0 && ip_case 6 warp
[[ "$LAN4" =~ ^([0-9]{1,3}\.){3} ]] && INET4=1 && ping -c2 -W3 162.159.192.1 >/dev/null 2>&1 && local NET_4_NONGLOBAL=0 && ip_case 4 warp
fi
until [[ "$TRACE4$TRACE6" =~ on|plus ]]; do
(( i++ )) || true
hint " $(text 12) "
${SYSTEMCTL_RESTART[int]} >/dev/null 2>&1
ss -nltp | grep dnsmasq >/dev/null 2>&1 && systemctl restart dnsmasq >/dev/null 2>&1
case "$NET_6_NONGLOBAL" in
0 )
ip_case 6 warp
;;
1 )
ip_case 6 warp non-global
esac
case "$NET_4_NONGLOBAL" in
0 )
ip_case 4 warp
;;
1 )
ip_case 4 warp non-global
esac
if [ "$i" = "$j" ]; then
wg-quick down warp >/dev/null 2>&1
ERROR_MESSAGE=$(wg-quick up warp 2>&1)
wg-quick down warp >/dev/null 2>&1
[ -s /etc/resolv.conf.origin ] && cp -f /etc/resolv.conf.origin /etc/resolv.conf
echo -e " ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓\n $(text 20): $SYS\n\n $(text 21):$(uname -r) \n\n $(text 40): ${MENU_OPTION[MENU_CHOOSE]} \n\n $ERROR_MESSAGE\n ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ "
error " $(text 13) "
fi
done
if [[ "$TRACE4$TRACE6" =~ on|plus ]]; then
[[ "$TRACE4$TRACE6" =~ plus ]] && TYPE='+' || TYPE=' Free'
info " $(text 14), $(text 46) "
[ "$NO_OUTPUT" != 'no_output' ] && info " IPv4:$WAN4 $COUNTRY4 $ASNORG4\n IPv6:$WAN6 $COUNTRY6 $ASNORG6 "
fi
}
# WARP 开关,先检查是否已安装,再根据当前状态转向相反状态
onoff() {
[ ! -x "$(type -p wg-quick)" ] && error " $(text 120) "
wg show warp >/dev/null 2>&1 && (wg-quick down warp >/dev/null 2>&1; info " $(text 15) ") || net
}
# Client 开关,先检查是否已安装,再根据当前状态转向相反状态
client_onoff() {
[ ! -x "$(type -p warp-cli)" ] && error " $(text 93) "
if [ "$(warp-cli --accept-tos status | awk '/Status update/{for (i=0; i<NF; i++) if ($i=="update:") {print $(i+1)}}')" = 'Connected' ]; then
local CLIENT_MODE=$(warp-cli --accept-tos settings | awk '/Mode:/{for (i=0; i<NF; i++) if ($i=="Mode:") {print $(i+1)}}')
[ "$CLIENT_MODE" = 'Warp' ] && rule_del >/dev/null 2>&1
warp-cli --accept-tos disconnect >/dev/null 2>&1
info " $(text 91) " && exit 0
else
warp-cli --accept-tos connect >/dev/null 2>&1
local CLIENT_MODE=$(warp-cli --accept-tos settings | awk '/Mode:/{for (i=0; i<NF; i++) if ($i=="Mode:") {print $(i+1)}}')
if [ "$CLIENT_MODE" = 'WarpProxy' ]; then
wait_for socks5 >/dev/null 2>&1
ip_case d client
local CLIENT_ACCOUNT=$(warp-cli --accept-tos registration show 2>/dev/null | awk '/type/{print $3}')
[ "$CLIENT_ACCOUNT" = Limited ] && CLIENT_AC='+'
[[ $(ss -nltp | awk '{print $NF}' | awk -F \" '{print $2}') =~ warp-svc ]] && info " $(text 90)\n $(text 27): $CLIENT_SOCKS5\n WARP$CLIENT_AC IPv4: $CLIENT_WAN4 $CLIENT_COUNTRY4 $CLIENT_ASNORG4\n WARP$CLIENT_AC IPv6: $CLIENT_WAN6 $CLIENT_COUNTRY6 $CLIENT_ASNORG6 "
exit 0
elif [ "$CLIENT_MODE" = 'Warp' ]; then
wait_for interface >/dev/null 2>&1
rule_add >/dev/null 2>&1
ip_case d is_luban
local CLIENT_ACCOUNT=$(warp-cli --accept-tos registration show 2>/dev/null | awk '/type/{print $3}')
[ "$CLIENT_ACCOUNT" = Limited ] && CLIENT_AC='+'
[[ $(ip link show | awk -F': ' '{print $2}') =~ CloudflareWARP ]] && info " $(text 90)\n WARP$CLIENT_AC IPv4: $CFWARP_WAN4 $CFWARP_COUNTRY4 $CFWARP_ASNORG4\n WARP$CLIENT_AC IPv6: $CFWARP_WAN6 $CFWARP_COUNTRY6 $CFWARP_ASNORG6 "
exit 0
fi
fi
}
# WireProxy 开关,先检查是否已安装,再根据当前状态转向相反状态
wireproxy_onoff() {
local NO_OUTPUT="$1"
[ ! -x "$(type -p wireproxy)" ] && error " $(text 122) " || IS_PUFFERFFISH=is_pufferffish
if ss -nltp | awk '{print $NF}' | awk -F \" '{print $2}' | grep -q wireproxy; then
[ "$SYSTEM" = Alpine ] && rc-service wireproxy stop >/dev/null 2>&1 || systemctl stop wireproxy
[[ ! $(ss -nltp | awk '{print $NF}' | awk -F \" '{print $2}') =~ wireproxy ]] && info " $(text 123) "
else
local i=1; local j=5
hint " $(text 11)\n $(text 12) "
[ "$SYSTEM" = Alpine ] && rc-service wireproxy start >/dev/null 2>&1 || systemctl start wireproxy; sleep 1
ip_case d wireproxy
until [[ "$WIREPROXY_TRACE4$WIREPROXY_TRACE6" =~ on|plus ]]; do
(( i++ )) || true
hint " $(text 12) "
[ "$SYSTEM" = Alpine ] && rc-service wireproxy restart >/dev/null 2>&1 || systemctl restart wireproxy; sleep 1
ip_case d wireproxy
if [[ "$i" -gt "$j" ]]; then
[ "$SYSTEM" = Alpine ] && rc-service wireproxy stop >/dev/null 2>&1 || systemctl stop wireproxy
error " $(text 13) "
fi
done
if [[ "$NO_OUTPUT" != 'no_output' && "$WIREPROXY_TRACE4$WIREPROXY_TRACE6" =~ on|plus ]]; then
[[ $(ss -nltp | awk '{print $NF}' | awk -F \" '{print $2}') =~ wireproxy ]] && info " $(text 99)\n $(text 27): $WIREPROXY_SOCKS5\n WARP$WIREPROXY_ACCOUNT\n IPv4: $WIREPROXY_WAN4 $WIREPROXY_COUNTRY4 $WIREPROXY_ASNORG4\n IPv6: $WIREPROXY_WAN6 $WIREPROXY_COUNTRY6 $WIREPROXY_ASNORG6"
fi
fi
}
# 检查系统 WARP 单双栈情况。为了速度,先检查 warp 配置文件里的情况,再判断 trace
check_stack() {
if [ -e /etc/wireguard/warp.conf ]; then
grep -q "^#.*0\.\0\/0" 2>/dev/null /etc/wireguard/warp.conf && T4=0 || T4=1
grep -q "^#.*\:\:\/0" 2>/dev/null /etc/wireguard/warp.conf && T6=0 || T6=1
else
case "$TRACE4" in
off )
T4='0'
;;
'on'|'plus' )
T4='1'
esac
case "$TRACE6" in
off )
T6='0'
;;
'on'|'plus' )
T6='1'
esac
fi
CASE=("@0" "0@" "0@0" "@1" "0@1" "1@" "1@0" "1@1" "@")
for m in ${!CASE[@]}; do
[ "$T4"@"$T6" = "${CASE[m]}" ] && break
done
WARP_BEFORE=("" "" "" "WARP IPv6 only" "WARP IPv6" "WARP IPv4 only" "WARP IPv4" "$(text 70)")
WARP_AFTER1=("" "" "" "WARP IPv4" "WARP IPv4" "WARP IPv6" "WARP IPv6" "WARP IPv4")
WARP_AFTER2=("" "" "" "$(text 70)" "$(text 70)" "$(text 70)" "$(text 70)" "WARP IPv6")
TO1=("" "" "" "014" "014" "106" "106" "114")
TO2=("" "" "" "01D" "01D" "10D" "10D" "116")
SHORTCUT1=("" "" "" "(warp 4)" "(warp 4)" "(warp 6)" "(warp 6)" "(warp 4)")
SHORTCUT2=("" "" "" "(warp d)" "(warp d)" "(warp d)" "(warp d)" "(warp 6)")
# 判断用于检测 NAT VSP,以选择正确配置文件
if [ "$m" -le 3 ]; then
NAT=("0@1@" "1@0@1" "1@1@1" "0@1@1")
for n in ${!NAT[@]}; do [ "$IPV4@$IPV6@$INET4" = "${NAT[n]}" ] && break; done
NATIVE=("IPv6 only" "IPv4 only" "$(text 69)" "NAT IPv4")
CONF1=("014" "104" "114" "11N4")
CONF2=("016" "106" "116" "11N6")
CONF3=("01D" "10D" "11D" "11ND")
elif [ "$m" = 8 ]; then
error "\n $(text 100) \n"
fi
}
# 对于 CentOS 9 / AlmaLinux 9 / RockyLinux 9 及类似的系统,由于 wg-quick 不能对 openresolv 进行操作,所以直接处理 /etc/resolv.conf 文件
centos9_resolv() {
local EXECUTE=$1
local STACK=$2
if [ "$EXECUTE" = 'backup' ]; then
cp -f /etc/resolv.conf{,.origin}
elif [ "$EXECUTE" = 'generate' ]; then
[ "$STACK" = '0' ] && echo -e "# Generated by WARP script\nnameserver 2606:4700:4700::1111\nnameserver 2001:4860:4860::8888\nnameserver 2001:4860:4860::8844\nnameserver 1.1.1.1\nnameserver 8.8.8.8\nnameserver 8.8.4.4" > /etc/resolv.conf || echo -e "# Generated by WARP script\nnameserver 1.1.1.1\nnameserver 8.8.8.8\nnameserver 8.8.4.4\nnameserver 2606:4700:4700::1111\nnameserver 2001:4860:4860::8888\nnameserver 2001:4860:4860::8844" > /etc/resolv.conf
elif [ "$EXECUTE" = 'restore' ]; then
[ -s /etc/resolv.conf.origin ] && mv -f /etc/resolv.conf.origin /etc/resolv.conf
fi
}
# 单双栈在线互换。先看菜单是否有选择,再看传参数值,再没有显示2个可选项
stack_switch() {
# WARP 单双栈切换选项
SWITCH014="/AllowedIPs/s/#//g;s/^.*\:\:\/0/#&/g"
SWITCH01D="/AllowedIPs/s/#//g"
SWITCH106="/AllowedIPs/s/#//g;s/^.*0\.\0\/0/#&/g"
SWITCH10D="/AllowedIPs/s/#//g"
SWITCH114="/AllowedIPs/s/^.*\:\:\/0/#&/g"
SWITCH116="/AllowedIPs/s/^.*0\.\0\/0/#&/g"
[[ "$CLIENT" = [35] && "$SWITCHCHOOSE" = [4D] ]] && error " $(text 109) "
check_stack
if [[ "$MENU_CHOOSE" = [12] ]]; then
TO=$(eval echo "\${TO$MENU_CHOOSE[m]}")
elif [[ "$SWITCHCHOOSE" = [46D] ]]; then
[[ "$T4@$T6@$SWITCHCHOOSE" =~ '1@0@4'|'0@1@6'|'1@1@D' ]] && error "\n $(text 111) \n" || TO="$T4$T6$SWITCHCHOOSE"
fi
[ "${#TO}" != 3 ] && error " $(text 135) " || sed -i "$(eval echo "\$SWITCH$TO")" /etc/wireguard/warp.conf
${SYSTEMCTL_RESTART[int]}; sleep 1
net
}
# 内核 / wireguard-go with reserved 在线互换
kernel_reserved_switch() {
# 先判断是否可以转换
case "$KERNEL_ENABLE@$WIREGUARD_GO_ENABLE" in
0@1 )
KERNEL_OR_WIREGUARD_GO='wireguard-go with reserved' && error "\n $(text 136) \n"
;;
1@0 )
KERNEL_OR_WIREGUARD_GO='wireguard kernel' && error "\n $(text 136) \n"
;;
1@1 )
if grep -q '^#[[:space:]]*add_if' /usr/bin/wg-quick; then
WIREGUARD_BEFORE='wireguard-go with reserved'; WIREGUARD_AFTER='wireguard kernel'; local CP_FILE=origin
else
WIREGUARD_BEFORE='wireguard kernel'; WIREGUARD_AFTER='wireguard-go with reserved'; local CP_FILE=reserved
fi
reading "\n $(text 138) " CONFIRM_WIREGUARD_CHANGE
if [ "${CONFIRM_WIREGUARD_CHANGE,,}" = 'y' ]; then
wg-quick down warp >/dev/null 2>&1
ln -sf /usr/bin/wg-quick.$CP_FILE /usr/bin/wg-quick
net
else
exit
fi
esac
}
# 全局 / 非全局 在线互换
working_mode_switch() {
# 先判断当前工作模式
if grep -q '#Table' /etc/wireguard/warp.conf; then
MODE_BEFORE="$(text 95)"; MODE_AFTER="$(text 96)"
else
MODE_BEFORE="$(text 96)"; MODE_AFTER="$(text 95)"
fi
reading "\n $(text 26) " CONFIRM_MODE_CHANGE
if [ "${CONFIRM_MODE_CHANGE,,}" = 'y' ]; then
wg-quick down warp >/dev/null 2>&1
[ "$MODE_AFTER" = "$(text 96)" ] && sed -i "/Table/s/#//g;/NonGlobal/s/#//g" /etc/wireguard/warp.conf || sed -i "s/^Table/#Table/g; /NonGlobal/s/^/#&/g" /etc/wireguard/warp.conf
net
else
exit
fi
}
# 检测系统信息
check_system_info() {
info " $(text 37) "
# 判断是否有加载 wireguard 内核,如没有先尝试是否可以加载,再重新判断一次
if [ ! -e /sys/module/wireguard ]; then
[ -s /lib/modules/$(uname -r)/kernel/drivers/net/wireguard/wireguard.ko* ] && [ -x "$(type -p lsmod)" ] && ! lsmod | grep -q wireguard && [ -x "$(type -p modprobe)" ] && modprobe wireguard
[ -e /sys/module/wireguard ] && KERNEL_ENABLE=1 || KERNEL_ENABLE=0
else
KERNEL_ENABLE=1
fi
# 必须加载 TUN 模块,先尝试在线打开 TUN。尝试成功放到启动项,失败作提示并退出脚本
TUN=$(cat /dev/net/tun 2>&1)
if [[ "$TUN" =~ 'in bad state'|'处于错误状态' ]]; then
WIREGUARD_GO_ENABLE=1
else
cat >/usr/bin/tun.sh << EOF
#!/usr/bin/env bash
mkdir -p /dev/net
mknod /dev/net/tun c 10 200 2>/dev/null
[ ! -e /dev/net/tun ] && exit 1
chmod 0666 /dev/net/tun
EOF
chmod +x /usr/bin/tun.sh
/usr/bin/tun.sh
TUN=$(cat /dev/net/tun 2>&1)
if [[ "$TUN" =~ 'in bad state'|'处于错误状态' ]]; then
WIREGUARD_GO_ENABLE=1
[ "$SYSTEM" != Alpine ] && echo "@reboot root bash /usr/bin/tun.sh" >> /etc/crontab
else
WIREGUARD_GO_ENABLE=0
rm -f /usr/bin/tun.sh
fi
fi
# 判断机器原生状态类型
IPV4=0; IPV6=0
LAN4=$(ip route get 192.168.193.10 2>/dev/null | awk '{for (i=0; i<NF; i++) if ($i=="src") {print $(i+1)}}')
LAN6=$(ip route get 2606:4700:d0::a29f:c001 2>/dev/null | awk '{for (i=0; i<NF; i++) if ($i=="src") {print $(i+1)}}')
# 先查是否非局,优先 warp IP,再原生 IP
if [[ $(ip link show | awk -F': ' '{print $2}') =~ warp ]]; then
GLOBAL_OR_NOT="$(text 96)"
if grep -q '^AllowedIPs.*:\:\/0' 2>/dev/null /etc/wireguard/warp.conf; then
STACK=-6 && ip_case 6 warp non-global
else
[[ "$LAN6" != "::1" && "$LAN6" =~ ^[a-f0-9:]+$ ]] && INET6=1 && $PING6 -c2 -w10 2606:4700:d0::a29f:c001 >/dev/null 2>&1 && IPV6=1 && STACK=-6 && ip_case 6 warp
fi
if grep -q '^AllowedIPs.*0\.\0\/0' 2>/dev/null /etc/wireguard/warp.conf; then
STACK=-4 && ip_case 4 warp non-global
else
[[ "$LAN4" =~ ^([0-9]{1,3}\.){3} ]] && INET4=1 && ping -c2 -W3 162.159.192.1 >/dev/null 2>&1 && IPV4=1 && STACK=-4 && ip_case 4 warp
fi
else
[[ "$LAN6" != "::1" && "$LAN6" =~ ^[a-f0-9:]+$ ]] && INET6=1 && $PING6 -c2 -w10 2606:4700:d0::a29f:c001 >/dev/null 2>&1 && IPV6=1 && STACK=-6 && ip_case 6 warp
[[ "$LAN4" =~ ^([0-9]{1,3}\.){3} ]] && INET4=1 && ping -c2 -W3 162.159.192.1 >/dev/null 2>&1 && IPV4=1 && STACK=-4 && ip_case 4 warp
fi
# 判断当前 WARP 状态,决定变量 PLAN,变量 PLAN 含义:1=单栈 2=双栈 3=WARP已开启
[[ "$TRACE4$TRACE6" =~ on|plus ]] && PLAN=3 || PLAN=$((IPV4+IPV6))
# 判断处理器架构
case $(uname -m) in
aarch64 )
ARCHITECTURE=arm64
;;
x86_64 )
ARCHITECTURE=amd64
;;
s390x )
ARCHITECTURE=s390x; CLIENT_NOT_ALLOWED_ARCHITECTURE="$(text 121)"
;;
* )
error " $(text 42) "
esac
# 判断当前 Linux Client 状态,决定变量 CLIENT,变量 CLIENT 含义:0=未安装 1=已安装未激活 2=状态激活 3=Client proxy 已开启 5=Client warp 已开启
CLIENT=0
if [ -x "$(type -p warp-cli)" ]; then
CLIENT=1 && CLIENT_INSTALLED="$(text 92)"
[ "$(systemctl is-enabled warp-svc)" = enabled ] && CLIENT=2
if [[ "$CLIENT" = 2 && "$(systemctl is-active warp-svc)" = 'active' ]]; then
local CLIENT_ACCOUNT=$(warp-cli --accept-tos registration show 2>/dev/null | awk '/type/{print $3}')
[ "$CLIENT_ACCOUNT" = Limited ] && CLIENT_AC='+'
local CLIENT_MODE=$(warp-cli --accept-tos settings | awk '/Mode:/{for (i=0; i<NF; i++) if ($i=="Mode:") {print $(i+1)}}')
case "$CLIENT_MODE" in
WarpProxy )
[[ "$(ss -nltp | awk '{print $NF}' | awk -F \" '{print $2}')" =~ warp-svc ]] && CLIENT=3 && ip_case d client
;;
Warp )
[[ "$(ip link show | awk -F': ' '{print $2}')" =~ CloudflareWARP ]] && CLIENT=5 && ip_case d is_luban
esac
fi
fi
# 判断当前 WireProxy 状态,决定变量 WIREPROXY,变量 WIREPROXY 含义:0=未安装,1=已安装,断开状态,2=Client 已开启
WIREPROXY=0
if [ -x "$(type -p wireproxy)" ]; then
WIREPROXY=1
[ "$WIREPROXY" = 1 ] && WIREPROXY_INSTALLED="$(text 92)" && [[ "$(ss -nltp | awk '{print $NF}' | awk -F \" '{print $2}')" =~ wireproxy ]] && WIREPROXY=2 && ip_case d wireproxy
fi
}
rule_add() {
ip -4 rule show | grep -q "from 172.16.0.2 lookup 51820" || ip -4 rule add from 172.16.0.2 lookup 51820
ip link show CloudflareWARP >/dev/null 2>&1 && ip -4 route add default dev CloudflareWARP table 51820 2>/dev/null
ip -4 rule show | grep -q "from all lookup main suppress_prefixlength 0" || ip -4 rule add table main suppress_prefixlength 0
ip -6 rule show | grep -q "oif CloudflareWARP lookup 51820" || ip -6 rule add oif CloudflareWARP lookup 51820
ip link show CloudflareWARP >/dev/null 2>&1 && ip -6 route add default dev CloudflareWARP table 51820 2>/dev/null
ip -6 rule show | grep -q "from all lookup main suppress_prefixlength 0" || ip -6 rule add table main suppress_prefixlength 0
}
rule_del() {
ip -4 rule show | grep -q "from 172.16.0.2" && ip -4 rule delete from 172.16.0.2 lookup 51820
ip -4 rule show | grep -q "suppress_prefixlength 0" && ip -4 rule delete table main suppress_prefixlength 0
ip -6 rule show | grep -q "oif CloudflareWARP" && ip -6 rule delete oif CloudflareWARP lookup 51820
ip -6 rule show | grep -q "suppress_prefixlength 0" && ip -6 rule delete table main suppress_prefixlength 0
}
# 输入 Linux Client 端口,先检查默认的40000是否被占用,限制4-5位数字,准确匹配空闲端口
input_port() {
i=5
PORT=40000
ss -nltp | awk '{print $4}' | awk -F: '{print $NF}' | grep -qw $PORT && reading " $(text 103) " PORT || reading " $(text 104) " PORT
PORT=${PORT:-'40000'}
until grep -qE "^[1-9][0-9]{3,4}$" <<< $PORT && [[ "$PORT" -ge 1000 && "$PORT" -le 65535 ]] && [[ ! $(ss -nltp) =~ :"$PORT"[[:space:]] ]]; do
(( i-- )) || true
[ "$i" = 0 ] && error " $(text 29) "
if grep -qwE "^[1-9][0-9]{3,4}$" <<< $PORT; then
if [[ "$PORT" -ge 1000 && "$PORT" -le 65535 ]]; then
ss -nltp | awk '{print $4}' | awk -F: '{print $NF}' | grep -qw $PORT && reading " $(text 103) " PORT
else
reading " $(text 9) " PORT
PORT=${PORT:-'40000'}
fi
else
reading " $(text 9) " PORT
PORT=${PORT:-'40000'}
fi
done
}
# Linux Client 或 WireProxy 端口
change_port() {
socks5_port() { input_port; warp-cli --accept-tos proxy port "$PORT"; }
wireproxy_port() {
input_port
sed -i "s/BindAddress.*/BindAddress = 127.0.0.1:$PORT/g" /etc/wireguard/proxy.conf
systemctl restart wireproxy
}
INSTALL_CHECK=("$CLIENT" "$WIREPROXY")
CASE_RESAULT=("0 1" "1 0" "1 1")
SHOW_CHOOSE=("" "" "$(text 116)")
CHANGE_PORT1=("wireproxy_port" "socks5_port" "socks5_port")
CHANGE_PORT2=("" "" "wireproxy_port")
for e in ${!INSTALL_CHECK[@]}; do
[[ "${INSTALL_CHECK[e]}" -gt 1 ]] && INSTALL_RESULT[e]=1 || INSTALL_RESULT[e]=0
done
for f in ${!CASE_RESAULT[@]}; do
[[ "${INSTALL_RESULT[@]}" = "${CASE_RESAULT[f]}" ]] && break
done
case "$f" in
0|1 )
${CHANGE_PORT1[f]}
wait_for $PORT
ss -nltp | grep -q ":$PORT" && info " $(text 25) " || error " $(text 34) "
;;
2 )
hint " ${SHOW_CHOOSE[f]} " && reading " $(text 50) " MODE
case "$MODE" in
[1-2] )
$(eval echo "\${CHANGE_IP$MODE[f]}")
wait_for $PORT
ss -nltp | grep -q ":$PORT" && info " $(text 25) " || error " $(text 34) "
;;
* )
warning " $(text 51) [1-2] "; sleep 1; change_port
esac
esac
}
# 选用 iptables+dnsmasq+ipset 方案执行
iptables_solution() {
${PACKAGE_INSTALL[int]} ipset dnsmasq resolvconf mtr
# 创建 dnsmasq 规则文件
cat >/etc/dnsmasq.d/warp.conf << EOF
#!/usr/bin/env bash
server=1.1.1.1
server=8.8.8.8
# ----- WARP ----- #
# > Youtube Premium
server=/googlevideo.com/8.8.8.8
server=/youtube.com/8.8.8.8
server=/youtubei.googleapis.com/8.8.8.8
server=/fonts.googleapis.com/8.8.8.8
server=/yt3.ggpht.com/8.8.8.8
server=/gstatic.com/8.8.8.8
# > Custom ChatGPT
ipset=/openai.com/warp
ipset=/ai.com/warp
ipset=/chatgpt.com/warp
# > IP api
ipset=/ip.sb/warp
ipset=/ip.gs/warp
ipset=/ifconfig.co/warp
ipset=/ip-api.com/warp
# > Custom Website
ipset=/www.cloudflare.com/warp
ipset=/googlevideo.com/warp
ipset=/youtube.com/warp
ipset=/youtubei.googleapis.com/warp
ipset=/fonts.googleapis.com/warp
ipset=/yt3.ggpht.com/warp
# > Netflix
ipset=/fast.com/warp
ipset=/netflix.com/warp
ipset=/netflix.net/warp
ipset=/nflxext.com/warp
ipset=/nflximg.com/warp
ipset=/nflximg.net/warp
ipset=/nflxso.net/warp
ipset=/nflxvideo.net/warp
ipset=/239.255.255.250/warp
# > TVBAnywhere+
ipset=/uapisfm.tvbanywhere.com.sg/warp
# > Disney+
ipset=/bamgrid.com/warp
ipset=/disney-plus.net/warp
ipset=/disneyplus.com/warp
ipset=/dssott.com/warp
ipset=/disneynow.com/warp
ipset=/disneystreaming.com/warp
ipset=/cdn.registerdisney.go.com/warp
# > TikTok
ipset=/byteoversea.com/warp
ipset=/ibytedtos.com/warp
ipset=/ipstatp.com/warp
ipset=/muscdn.com/warp
ipset=/musical.ly/warp
ipset=/tiktok.com/warp
ipset=/tik-tokapi.com/warp
ipset=/tiktokcdn.com/warp
ipset=/tiktokv.com/warp
EOF
# 创建 PostUp 和 PreDown
cat >/etc/wireguard/up << EOF
#!/usr/bin/env bash
ipset create warp hash:ip
iptables -t mangle -N fwmark
iptables -t mangle -A PREROUTING -j fwmark
iptables -t mangle -A OUTPUT -j fwmark
iptables -t mangle -A fwmark -m set --match-set warp dst -j MARK --set-mark 2
ip rule add fwmark 2 table warp
ip route add default dev warp table warp
iptables -t nat -A POSTROUTING -m mark --mark 0x2 -j MASQUERADE
iptables -t mangle -A POSTROUTING -o warp -p tcp -m tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu
EOF
cat >/etc/wireguard/down << EOF
#!/usr/bin/env bash
iptables -t mangle -D PREROUTING -j fwmark
iptables -t mangle -D OUTPUT -j fwmark
iptables -t mangle -D fwmark -m set --match-set warp dst -j MARK --set-mark 2
ip rule del fwmark 2 table warp
iptables -t mangle -D POSTROUTING -o warp -p tcp -m tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu
iptables -t nat -D POSTROUTING -m mark --mark 0x2 -j MASQUERADE
iptables -t mangle -F fwmark
iptables -t mangle -X fwmark
sleep 2
ipset destroy warp
EOF
chmod +x /etc/wireguard/up /etc/wireguard/down
# 修改 warp.conf 和 warp.conf 文件
sed -i "s/^Post.*/#&/g; /Table/s/#//g; /Table/a\PostUp = /etc/wireguard/up\nPredown = /etc/wireguard/down" /etc/wireguard/warp.conf
[ "$m" = 0 ] && sed -i "2i server=2606:4700:4700::1111\nserver=2001:4860:4860::8888\nserver=2001:4860:4860::8844" /etc/dnsmasq.d/warp.conf
! grep -q 'warp' /etc/iproute2/rt_tables && echo '250 warp' >>/etc/iproute2/rt_tables
systemctl disable systemd-resolved --now >/dev/null 2>&1 && sleep 2
systemctl enable dnsmasq --now >/dev/null 2>&1 && sleep 2
}
# 寻找最佳 MTU
best_mtu() {
# 反复测试最佳 MTU。 Wireguard Header:IPv4=60 bytes,IPv6=80 bytes1280 ≤ MTU ≤ 1420。 ping = 8(ICMP回显示请求和回显应答报文格式长度) + 20(IP首部) 。
# 详细说明:<[WireGuard] Header / MTU sizes for Wireguard>:https://lists.zx2c4.com/pipermail/wireguard/2017-December/002201.html
# MTU 初始范围(适用于 WireGuard 等封装,IPv4/IPv6 都保守选 1280-1420
local MIN_MTU=1280
local MAX_MTU=1500
local TEST_IP
local PING_CMD
local BEST_MTU=1280
if [ "$IPV4$IPV6" = "01" ]; then
TEST_IP="2606:4700:d0::a29f:c001"
PING_CMD="$PING6"
else
TEST_IP="162.159.192.1"
PING_CMD="ping"
fi
# 二分查找能 ping 通的最大 MTU(不碎片)
while [ $((MIN_MTU <= MAX_MTU)) -eq 1 ]; do
local MID_MTU=$(( (MIN_MTU + MAX_MTU) / 2 ))
if $PING_CMD -c1 -W1 -s $MID_MTU -M do "$TEST_IP" >/dev/null 2>&1; then
BEST_MTU=$MID_MTU
MIN_MTU=$((MID_MTU + 1)) # 尝试更大值
else
MAX_MTU=$((MID_MTU - 1)) # 减小范围
fi
done
# 最终微调确认 BEST_MTU 是最大可用值
for (( i=BEST_MTU+1; i<=1420; i++ )); do
if $PING_CMD -c1 -W1 -s $i -M do "$TEST_IP" >/dev/null 2>&1; then
BEST_MTU=$i
else
break
fi
done
# 返回最终 MTU(按需减包头)——可自定义减多少
# WireGuard+28 是 IP+UDP-60 / -80 是安全包头(例如 wireguard + extra overhead
grep -q ':' <<< "$TEST_IP" && BEST_MTU=$((BEST_MTU + 28 - 80)) || BEST_MTU=$((BEST_MTU + 28 - 60))
# 确保范围安全
[ "$BEST_MTU" -lt 1280 ] && BEST_MTU=1280
[ "$BEST_MTU" -gt 1420 ] && BEST_MTU=1420
echo "$BEST_MTU" > /tmp/best_mtu
}
# 寻找最佳 Endpoint,根据 v4 / v6 情况下载 endpoint 库
best_endpoint() {
# Removed best endpoint feature to adapt to official adjustments
# Use default endpoint: engage.cloudflareclient.com:2408
echo "engage.cloudflareclient.com:2408" > /tmp/best_endpoint
}
# WARP 或 WireProxy 安装
install() {
# 后台下载 wireguard-go 两个版本
{ wget --no-check-certificate $STACK -qO /tmp/wireguard-go-20230223 https://gitlab.com/fscarmen/warp/-/raw/main/wireguard-go/wireguard-go-linux-$ARCHITECTURE-20230223 && chmod +x /tmp/wireguard-go-20230223; }&
{ wget --no-check-certificate $STACK -qO /tmp/wireguard-go-20201118 https://gitlab.com/fscarmen/warp/-/raw/main/wireguard-go/wireguard-go-linux-$ARCHITECTURE-20201118 && chmod +x /tmp/wireguard-go-20201118; }&
# 根据之前判断的情况,让用户选择使用 wireguard 内核还是 wireguard-go serverd; 若为 wireproxy 方案则跳过此步
if [ "$IS_PUFFERFFISH" != 'is_pufferffish' ]; then
case "$KERNEL_ENABLE@$WIREGUARD_GO_ENABLE" in
0@0 )
error " $(text 3) "
;;
0@1 )
KERNEL_OR_WIREGUARD_GO='wireguard-go with reserved' && info "\n $(text 136) "
;;
1@0 )
KERNEL_OR_WIREGUARD_GO='wireguard kernel' && info "\n $(text 136) "
;;
1@1 )
hint "\n $(text 137) \n" && reading " $(text 50) " KERNEL_OR_WIREGUARD_GO_CHOOSE
KERNEL_OR_WIREGUARD_GO='wireguard kernel' && [ "$KERNEL_OR_WIREGUARD_GO_CHOOSE" = 2 ] && KERNEL_OR_WIREGUARD_GO='wireguard-go with reserved'
esac
fi
# Warp 工作模式: 全局或非全局,在 dnsmasq / wireproxy 方案下不选择
if [[ "$IS_ANEMONE" != 'is_anemone' && "$IS_PUFFERFFISH" != 'is_pufferffish' ]]; then
[ -z "$GLOBAL_OR_NOT_CHOOSE" ] && hint "\n $(text 139) \n" && reading " $(text 50) " GLOBAL_OR_NOT_CHOOSE
GLOBAL_OR_NOT="$(text 95)" && [ "$GLOBAL_OR_NOT_CHOOSE" = 2 ] && GLOBAL_OR_NOT="$(text 96)"
fi
# WireProxy 禁止重复安装,自定义 Port
if [ "$IS_PUFFERFFISH" = 'is_pufferffish' ]; then
ss -nltp | grep -q wireproxy && error " $(text 130) " || input_port
# iptables 禁止重复安装,不适用于 IPv6 only VPS
elif [ "$IS_ANEMONE" = 'is_anemone' ]; then
[ -e /etc/dnsmasq.d/warp.conf ] && error " $(text 131) "
[ "$m" = 0 ] && error " $(text 112) " || CONF=${CONF1[n]}
fi
# CONF 参数如果不是3位或4位, 即检测不出正确的配置参数, 脚本退出
[[ "$IS_PUFFERFFISH" != 'is_pufferffish' && "${#CONF}" != [34] ]] && error " $(text 135) "
# 先删除之前安装,可能导致失败的文件
rm -rf /usr/bin/wireguard-go /etc/wireguard/warp-account.conf
# 选择优先使用 IPv4 /IPv6 网络
[ "$IS_PUFFERFFISH" != 'is_pufferffish' ] && hint "\n $(text 74) \n" && reading " $(text 50) " PRIORITY
# 脚本开始时间
start=$(date +%s)
# 如果是 IPv6 only 机器,备份原 dns 文件,再使用 nat64
[ "$m" = 0 ] && cp -f /etc/resolv.conf{,.origin} && echo -e "nameserver 2a00:1098:2b::1\nnameserver 2a01:4f9:c010:3f02::1\nnameserver 2a01:4f8:c2c:123f::1\nnameserver 2a00:1098:2c::1" > /etc/resolv.conf
# 注册 WARP 账户 (将生成 warp-account.conf 文件保存账户信息)
{
# 如安装 WireProxy ,尽量下载官方的最新版本,如官方 WireProxy 下载不成功,将使用 cdn,以更好的支持双栈和大陆 VPS。并添加执行权限
if [ "$IS_PUFFERFFISH" = 'is_pufferffish' ]; then
wireproxy_latest=$(wget --no-check-certificate -qO- -T1 -t1 $STACK "${GH_PROXY}https://api.github.com/repos/pufferffish/wireproxy/releases/latest" | awk -F [v\"] '/tag_name/{print $5; exit}')
wireproxy_latest=${wireproxy_latest:-'1.0.9'}
wget --no-check-certificate -T10 -t1 $STACK -O wireproxy.tar.gz ${GH_PROXY}https://github.com/pufferffish/wireproxy/releases/download/v"$wireproxy_latest"/wireproxy_linux_"$ARCHITECTURE".tar.gz ||
wget --no-check-certificate $STACK -O wireproxy.tar.gz https://gitlab.com/fscarmen/warp/-/raw/main/wireproxy/wireproxy_linux_"$ARCHITECTURE".tar.gz
[ -x "$(type -p tar)" ] || ${PACKAGE_INSTALL[int]} tar 2>/dev/null || ( ${PACKAGE_UPDATE[int]}; ${PACKAGE_INSTALL[int]} tar 2>/dev/null )
tar xzf wireproxy.tar.gz -C /usr/bin/; rm -f wireproxy.tar.gz
fi
# 注册 WARP 账户 ( warp-account.conf )。
mkdir -p /etc/wireguard/ >/dev/null 2>&1
warp_api "register" > /etc/wireguard/warp-account.conf 2>/dev/null
# 生成 WireGuard 配置文件 (warp.conf)
if [ -s /etc/wireguard/warp-account.conf ]; then
cat > /etc/wireguard/warp.conf <<EOF
[Interface]
PrivateKey = $(awk -F'"' '/"private_key"/ {print $4; exit}' /etc/wireguard/warp-account.conf)
Address = 172.16.0.2/32
Address = $(awk -F'"' '/"v6"[[:space:]]*:/ && $4 !~ /^\[/ {print $4; exit}' /etc/wireguard/warp-account.conf)/128
DNS = 8.8.8.8
MTU = 1280
#Reserved = $(awk '/"reserved": \[/{flag=1; printf "["; next} flag && /\]/{printf "]"; flag=0; print ""; next} flag {gsub(/[ \t\n\r]/,""); printf "%s", $0}' /etc/wireguard/warp-account.conf)
#Table = off
#PostUp = /etc/wireguard/NonGlobalUp.sh
#PostDown = /etc/wireguard/NonGlobalDown.sh
[Peer]
PublicKey = bmXOC+F1FxEMF9dyiK2H5/1SUtzH0JuVo51h2wPfgyo=
AllowedIPs = 0.0.0.0/0
AllowedIPs = ::/0
Endpoint = engage.cloudflareclient.com:2408
EOF
chmod 600 /etc/wireguard/warp.conf
cat > /etc/wireguard/NonGlobalUp.sh <<EOF
sleep 5
ip -4 rule add from 172.16.0.2 lookup 51820
ip -4 rule add table main suppress_prefixlength 0
ip -4 route add default dev warp table 51820
ip -6 rule add oif warp lookup 51820
ip -6 rule add table main suppress_prefixlength 0
ip -6 route add default dev warp table 51820
EOF
cat > /etc/wireguard/NonGlobalDown.sh <<EOF
ip -4 rule delete oif warp lookup 51820
ip -4 rule delete table main suppress_prefixlength 0
ip -6 rule delete oif warp lookup 51820
ip -6 rule delete table main suppress_prefixlength 0
EOF
chmod +x /etc/wireguard/NonGlobal*.sh
info "\n $(text 33) \n"
fi
}&
# 对于 IPv4 only VPS 开启 IPv6 支持
# 感谢 P3terx 大神项目这块的技术指导。项目:https://github.com/P3TERX/warp.sh/blob/main/warp.sh
{
[ "$IPV4$IPV6" = 10 ] && [[ $(sysctl -a 2>/dev/null | grep 'disable_ipv6.*=.*1') || $(grep -s "disable_ipv6.*=.*1" /etc/sysctl.{conf,d/*} ) ]] &&
(sed -i '/disable_ipv6/d' /etc/sysctl.{conf,d/*}
echo 'net.ipv6.conf.all.disable_ipv6 = 0' >/etc/sysctl.d/ipv6.conf
sysctl -w net.ipv6.conf.all.disable_ipv6=0)
}&
# 后台设置优先使用 IPv4 /IPv6 网络
{ stack_priority; }&
# 根据系统选择需要安装的依赖
info "\n $(text 32) \n"
case "$SYSTEM" in
Debian )
local DEBIAN_VERSION=$(echo $SYS | sed "s/[^0-9.]//g" | cut -d. -f1)
# 添加 backports 源,之后才能安装 wireguard-tools
if [ "$DEBIAN_VERSION" = '9' ]; then
echo "deb http://deb.debian.org/debian/ unstable main" > /etc/apt/sources.list.d/unstable-wireguard.list
echo -e "Package: *\nPin: release a=unstable\nPin-Priority: 150\n" > /etc/apt/preferences.d/limit-unstable
elif [[ "$DEBIAN_VERSION" =~ ^(10|11)$ ]]; then
echo "deb http://archive.debian.org/debian $(awk -F '=' '/VERSION_CODENAME/{print $2}' /etc/os-release)-backports main" > /etc/apt/sources.list.d/backports.list
else
echo "deb http://deb.debian.org/debian $(awk -F '=' '/VERSION_CODENAME/{print $2}' /etc/os-release)-backports main" > /etc/apt/sources.list.d/backports.list
fi
# 获取最新的软件包列表和更新已安装软件包的信息
${PACKAGE_UPDATE[int]}
# 安装一些必要的网络工具包和wireguard-tools (Wire-Guard 配置工具:wg、wg-quick)
${PACKAGE_INSTALL[int]} --no-install-recommends net-tools openresolv dnsutils iptables
[ "$IS_PUFFERFFISH" != 'is_pufferffish' ] && ${PACKAGE_INSTALL[int]} --no-install-recommends wireguard-tools
;;
Ubuntu )
# Ubuntu 24.04 及以上版本使用 resolvconf,以下版本则使用 openresolv
[ "$MAJOR_VERSION" -ge 24 ] && RESOLVER_PKG='resolvconf' || RESOLVER_PKG='openresolv'
# 获取最新的软件包列表和更新已安装软件包的信息
${PACKAGE_UPDATE[int]}
# 安装一些必要的网络工具包和 wireguard-tools (Wire-Guard 配置工具:wg、wg-quick)
${PACKAGE_INSTALL[int]} --no-install-recommends net-tools $RESOLVER_PKG dnsutils iptables
[ "$IS_PUFFERFFISH" != 'is_pufferffish' ] && ${PACKAGE_INSTALL[int]} --no-install-recommends wireguard-tools
;;
CentOS|Fedora )
# 安装一些必要的网络工具包和wireguard-tools (Wire-Guard 配置工具:wg、wg-quick)
[ "$SYSTEM" = 'CentOS' ] && ${PACKAGE_INSTALL[int]} epel-release
${PACKAGE_INSTALL[int]} net-tools iptables
[ "$IS_PUFFERFFISH" != 'is_pufferffish' ] && ${PACKAGE_INSTALL[int]} wireguard-tools
# 升级所有包同时也升级软件和系统内核
${PACKAGE_UPDATE[int]}
# s390x wireguard-tools 安装
[ "$ARCHITECTURE" = s390x ] && [ ! -x "$(type -p wg)" ] && rpm -i https://mirrors.cloud.tencent.com/epel/8/Everything/s390x/Packages/w/wireguard-tools-1.0.20210914-1.el8.s390x.rpm
# CentOS Stream 9 需要安装 resolvconf
[[ "$SYSTEM" = CentOS && "$(expr "$SYS" : '.*\s\([0-9]\{1,\}\)\.*')" = 9 ]] && [ ! -x "$(type -p resolvconf)" ] &&
wget $STACK -P /usr/sbin ${GH_PROXY}https://github.com/fscarmen/warp/releases/download/resolvconf/resolvconf && chmod +x /usr/sbin/resolvconf
;;
Alpine )
# 安装一些必要的网络工具包和wireguard-tools (Wire-Guard 配置工具:wg、wg-quick)
${PACKAGE_INSTALL[int]} net-tools iproute2 openresolv openrc iptables ip6tables
[ "$IS_PUFFERFFISH" != 'is_pufferffish' ] && ${PACKAGE_INSTALL[int]} wireguard-tools
;;
Arch )
# 安装一些必要的网络工具包和wireguard-tools (Wire-Guard 配置工具:wg、wg-quick)
${PACKAGE_INSTALL[int]} openresolv
[ "$IS_PUFFERFFISH" != 'is_pufferffish' ] && ${PACKAGE_INSTALL[int]} wireguard-tools
esac
# 在不是 wireproxy 方案的前提下,先判断是否一定要用 wireguard kernel,如果不是,修改 wg-quick 文件,以使用 wireguard-go reserved 版
if [ "$IS_PUFFERFFISH" != 'is_pufferffish' ]; then
if [ "$WIREGUARD_GO_ENABLE" = '1' ]; then
# 则根据 wireguard-tools 版本判断下载 wireguard-go reserved 版本: wg < v1.0.20210223 , wg-go-reserved = v0.0.20201118-reserved; wg >= v1.0.20210223 , wg-go-reserved = v0.0.20230223-reserved
local WIREGUARD_TOOLS_VERSION=$(wg --version | sed "s#.* v1\.0\.\([0-9]\+\) .*#\1#g")
[[ "$WIREGUARD_TOOLS_VERSION" < 20210223 ]] && mv /tmp/wireguard-go-20201118 /usr/bin/wireguard-go || mv /tmp/wireguard-go-20230223 /usr/bin/wireguard-go
rm -f /tmp/wireguard-go-*
# 为了兼容 Arch 及相关系统,wg-quick 在 set_dns 和 unset_dns 函数中加入 resolvconf -u
grep -q "Arch" <<< "$SYSTEM" && ! grep -q 'cmd resolvconf -u' /usr/bin/wg-quick && sed -i '/\[\[ \${#DNS\[@\]} -gt 0 \]\] || return 0/a\ cmd resolvconf -u' /usr/bin/wg-quick
# 如果用户选择使用 wireguard-go reserved 版本,则修改 wg-quick 文件
cp -f /usr/bin/wg-quick{,.origin}
if [ "$KERNEL_ENABLE" = '1' ]; then
mv -f /usr/bin/wg-quick /usr/bin/wg-quick.reserved
grep -q '^#[[:space:]]*add_if' /usr/bin/wg-quick.reserved || sed -i '/add_if$/ {s/^/# /; N; s/\n/&\twireguard-go "$INTERFACE"\n/}' /usr/bin/wg-quick.reserved
[ "$KERNEL_OR_WIREGUARD_GO" = 'wireguard-go with reserved' ] && ln -sf /usr/bin/wg-quick.reserved /usr/bin/wg-quick || ln -sf /usr/bin/wg-quick.origin /usr/bin/wg-quick
else
grep -q '^#[[:space:]]*add_if' /usr/bin/wg-quick.origin || sed -i '/add_if$/ {s/^/# /; N; s/\n/&\twireguard-go "$INTERFACE"\n/}' /usr/bin/wg-quick.origin
ln -sf /usr/bin/wg-quick.origin /usr/bin/wg-quick
fi
fi
fi
wait
# WARP 配置修改,172.17.0.0/24 这段是用于 Docker 的
MODIFY014="s/\(DNS[ ]\+=[ ]\+\).*/\12606:4700:4700::1111,2001:4860:4860::8888,2001:4860:4860::8844,1.1.1.1,8.8.8.8,8.8.4.4/g;7 s/^/PostUp = ip -6 rule add from $LAN6 lookup main\nPostDown = ip -6 rule delete from $LAN6 lookup main\nPostUp = ip -4 rule add from 172.17.0.0\/24 lookup main\nPostDown = ip -4 rule delete from 172.17.0.0\/24 lookup main\n\n/;s/^.*\:\:\/0/#&/g;\$a\PersistentKeepalive = 30"
MODIFY016="s/\(DNS[ ]\+=[ ]\+\).*/\12606:4700:4700::1111,2001:4860:4860::8888,2001:4860:4860::8844,1.1.1.1,8.8.8.8,8.8.4.4/g;7 s/^/PostUp = ip -6 rule add from $LAN6 lookup main\nPostDown = ip -6 rule delete from $LAN6 lookup main\nPostUp = ip -4 rule add from 172.17.0.0\/24 lookup main\nPostDown = ip -4 rule delete from 172.17.0.0\/24 lookup main\n\n/;s/^.*0\.\0\/0/#&/g;\$a\PersistentKeepalive = 30"
MODIFY01D="s/\(DNS[ ]\+=[ ]\+\).*/\12606:4700:4700::1111,2001:4860:4860::8888,2001:4860:4860::8844,1.1.1.1,8.8.8.8,8.8.4.4/g;7 s/^/PostUp = ip -6 rule add from $LAN6 lookup main\nPostDown = ip -6 rule delete from $LAN6 lookup main\nPostUp = ip -4 rule add from 172.17.0.0\/24 lookup main\nPostDown = ip -4 rule delete from 172.17.0.0\/24 lookup main\n\n/;\$a\PersistentKeepalive = 30"
MODIFY104="s/\(DNS[ ]\+=[ ]\+\).*/\11.1.1.1,8.8.8.8,8.8.4.4,2606:4700:4700::1111,2001:4860:4860::8888,2001:4860:4860::8844/g;7 s/^/PostUp = ip -4 rule add from $LAN4 lookup main\nPostDown = ip -4 rule delete from $LAN4 lookup main\nPostUp = ip -4 rule add from 172.17.0.0\/24 lookup main\nPostDown = ip -4 rule delete from 172.17.0.0\/24 lookup main\n\n/;s/^.*\:\:\/0/#&/g;\$a\PersistentKeepalive = 30"
MODIFY106="s/\(DNS[ ]\+=[ ]\+\).*/\11.1.1.1,8.8.8.8,8.8.4.4,2606:4700:4700::1111,2001:4860:4860::8888,2001:4860:4860::8844/g;7 s/^/PostUp = ip -4 rule add from $LAN4 lookup main\nPostDown = ip -4 rule delete from $LAN4 lookup main\nPostUp = ip -4 rule add from 172.17.0.0\/24 lookup main\nPostDown = ip -4 rule delete from 172.17.0.0\/24 lookup main\n\n/;s/^.*0\.\0\/0/#&/g;\$a\PersistentKeepalive = 30"
MODIFY10D="s/\(DNS[ ]\+=[ ]\+\).*/\11.1.1.1,8.8.8.8,8.8.4.4,2606:4700:4700::1111,2001:4860:4860::8888,2001:4860:4860::8844/g;7 s/^/PostUp = ip -4 rule add from $LAN4 lookup main\nPostDown = ip -4 rule delete from $LAN4 lookup main\nPostUp = ip -4 rule add from 172.17.0.0\/24 lookup main\nPostDown = ip -4 rule delete from 172.17.0.0\/24 lookup main\n\n/;\$a\PersistentKeepalive = 30"
MODIFY114="s/\(DNS[ ]\+=[ ]\+\).*/\11.1.1.1,8.8.8.8,8.8.4.4,2606:4700:4700::1111,2001:4860:4860::8888,2001:4860:4860::8844/g;7 s/^/PostUp = ip -4 rule add from $LAN4 lookup main\nPostDown = ip -4 rule delete from $LAN4 lookup main\nPostUp = ip -6 rule add from $LAN6 lookup main\nPostDown = ip -6 rule delete from $LAN6 lookup main\nPostUp = ip -4 rule add from 172.17.0.0\/24 lookup main\nPostDown = ip -4 rule delete from 172.17.0.0\/24 lookup main\n\n/;s/^.*\:\:\/0/#&/g;\$a\PersistentKeepalive = 30"
MODIFY116="s/\(DNS[ ]\+=[ ]\+\).*/\11.1.1.1,8.8.8.8,8.8.4.4,2606:4700:4700::1111,2001:4860:4860::8888,2001:4860:4860::8844/g;7 s/^/PostUp = ip -4 rule add from $LAN4 lookup main\nPostDown = ip -4 rule delete from $LAN4 lookup main\nPostUp = ip -6 rule add from $LAN6 lookup main\nPostDown = ip -6 rule delete from $LAN6 lookup main\nPostUp = ip -4 rule add from 172.17.0.0\/24 lookup main\nPostDown = ip -4 rule delete from 172.17.0.0\/24 lookup main\n\n/;s/^.*0\.\0\/0/#&/g;\$a\PersistentKeepalive = 30"
MODIFY11D="s/\(DNS[ ]\+=[ ]\+\).*/\11.1.1.1,8.8.8.8,8.8.4.4,2606:4700:4700::1111,2001:4860:4860::8888,2001:4860:4860::8844/g;7 s/^/PostUp = ip -4 rule add from $LAN4 lookup main\nPostDown = ip -4 rule delete from $LAN4 lookup main\nPostUp = ip -6 rule add from $LAN6 lookup main\nPostDown = ip -6 rule delete from $LAN6 lookup main\nPostUp = ip -4 rule add from 172.17.0.0\/24 lookup main\nPostDown = ip -4 rule delete from 172.17.0.0\/24 lookup main\n\n/;\$a\PersistentKeepalive = 30"
MODIFY11N4="s/\(DNS[ ]\+=[ ]\+\).*/\11.1.1.1,8.8.8.8,8.8.4.4,2606:4700:4700::1111,2001:4860:4860::8888,2001:4860:4860::8844/g;7 s/^/PostUp = ip -4 rule add from $LAN4 lookup main\nPostDown = ip -4 rule delete from $LAN4 lookup main\nPostUp = ip -6 rule add from $LAN6 lookup main\nPostDown = ip -6 rule delete from $LAN6 lookup main\nPostUp = ip -4 rule add from 172.17.0.0\/24 lookup main\nPostDown = ip -4 rule delete from 172.17.0.0\/24 lookup main\n\n/;s/^.*\:\:\/0/#&/g;\$a\PersistentKeepalive = 30"
MODIFY11N6="s/\(DNS[ ]\+=[ ]\+\).*/\11.1.1.1,8.8.8.8,8.8.4.4,2606:4700:4700::1111,2001:4860:4860::8888,2001:4860:4860::8844/g;7 s/^/PostUp = ip -4 rule add from $LAN4 lookup main\nPostDown = ip -4 rule delete from $LAN4 lookup main\nPostUp = ip -6 rule add from $LAN6 lookup main\nPostDown = ip -6 rule delete from $LAN6 lookup main\nPostUp = ip -4 rule add from 172.17.0.0\/24 lookup main\nPostDown = ip -4 rule delete from 172.17.0.0\/24 lookup main\n\n/;s/^.*0\.\0\/0/#&/g;\$a\PersistentKeepalive = 30"
MODIFY11ND="s/\(DNS[ ]\+=[ ]\+\).*/\11.1.1.1,8.8.8.8,8.8.4.4,2606:4700:4700::1111,2001:4860:4860::8888,2001:4860:4860::8844/g;7 s/^/PostUp = ip -4 rule add from $LAN4 lookup main\nPostDown = ip -4 rule delete from $LAN4 lookup main\nPostUp = ip -6 rule add from $LAN6 lookup main\nPostDown = ip -6 rule delete from $LAN6 lookup main\nPostUp = ip -4 rule add from 172.17.0.0\/24 lookup main\nPostDown = ip -4 rule delete from 172.17.0.0\/24 lookup main\n\n/;\$a\PersistentKeepalive = 30"
# 修改配置文件
sed -i "$(eval echo "\$MODIFY$CONF")" /etc/wireguard/warp.conf
[ -e /tmp/best_mtu ] && MTU=$(cat /tmp/best_mtu) && rm -f /tmp/best_mtu && sed -i "s/MTU.*/MTU = $MTU/g" /etc/wireguard/warp.conf
# 根据选择,处理 warp 是否全局代理
[ "$GLOBAL_OR_NOT" = "$(text 96)" ] && sed -i "/Table/s/#//g;/NonGlobal/s/#//g" /etc/wireguard/warp.conf
info "\n $(text 81) \n"
# 对于 CentOS 9 / AlmaLinux 9 / RockyLinux 9 及类似系统的处理
if [ "${SYSTEM}_${MAJOR_VERSION}" = 'CentOS_9' ]; then
centos9_resolv backup
centos9_resolv generate $m
sed -i 's/^\(DNS[[:space:]]=.*\)/#\1/' /etc/wireguard/warp.conf
fi
if [ "$IS_PUFFERFFISH" = 'is_pufferffish' ]; then
# 默认 Endpoint 和 DNS 默认 IPv4 和 双栈的,如是 IPv6 修改默认值
local ENDPOINT=$(awk '/^Endpoint/{print $NF}' /etc/wireguard/warp.conf)
local MTU=$(awk '/^MTU/{print $NF}' /etc/wireguard/warp.conf)
local FREE_ADDRESS6=$(awk '/^Address.*128$/{print $NF}' /etc/wireguard/warp.conf)
local FREE_PRIVATEKEY=$(awk '/PrivateKey/{print $NF}' /etc/wireguard/warp.conf)
[ "$m" = 0 ] && local DNS='2606:4700:4700::1111,2001:4860:4860::8888,2001:4860:4860::8844,1.1.1.1,8.8.8.8,8.8.4.4' || local DNS='1.1.1.1,8.8.8.8,8.8.4.4,2606:4700:4700::1111,2001:4860:4860::8888,2001:4860:4860::8844'
# 创建 Wireproxy 配置文件
cat > /etc/wireguard/proxy.conf << EOF
# The [Interface] and [Peer] configurations follow the same semantics and meaning
# of a wg-quick configuration. To understand what these fields mean, please refer to:
# https://wiki.archlinux.org/title/WireGuard#Persistent_configuration
# https://www.wireguard.com/#simple-network-interface
# The subnet should be /32 and /128 for IPv4 and v6 respectively
[Interface]
Address = 172.16.0.2/32, $FREE_ADDRESS6
MTU = $MTU
PrivateKey = $FREE_PRIVATEKEY
DNS = $DNS
[Peer]
PublicKey = bmXOC+F1FxEMF9dyiK2H5/1SUtzH0JuVo51h2wPfgyo=
# PresharedKey = UItQuvLsyh50ucXHfjF0bbR4IIpVBd74lwKc8uIPXXs= (optional)
Endpoint = $ENDPOINT
# PersistentKeepalive = 25 (optional)
# TCPClientTunnel is a tunnel listening on your machine,
# and it forwards any TCP traffic received to the specified target via wireguard.
# Flow:
# <an app on your LAN> --> localhost:25565 --(wireguard)--> play.cubecraft.net:25565
#[TCPClientTunnel]
#BindAddress = 127.0.0.1:25565
#Target = play.cubecraft.net:25565
# TCPServerTunnel is a tunnel listening on wireguard,
# and it forwards any TCP traffic received to the specified target via local network.
# Flow:
# <an app on your wireguard network> --(wireguard)--> 172.16.31.2:3422 --> localhost:25545
#[TCPServerTunnel]
#ListenPort = 3422
#Target = localhost:25545
# STDIOTunnel is a tunnel connecting the standard input and output of the wireproxy
# process to the specified TCP target via wireguard.
# This is especially useful to use wireproxy as a ProxyCommand parameter in openssh
# For example:
# ssh -o ProxyCommand='wireproxy -c myconfig.conf' ssh.myserver.net
# Flow:
# Piped command -->(wireguard)--> ssh.myserver.net:22
#[STDIOTunnel]
#Target = ssh.myserver.net:22
# Socks5 creates a socks5 proxy on your LAN, and all traffic would be routed via wireguard.
[Socks5]
BindAddress = 127.0.0.1:$PORT
# Socks5 authentication parameters, specifying username and password enables
# proxy authentication.
#Username = ...
# Avoid using spaces in the password field
#Password = ...
# http creates a http proxy on your LAN, and all traffic would be routed via wireguard.
#[http]
#BindAddress = 127.0.0.1:25345
# HTTP authentication parameters, specifying username and password enables
# proxy authentication.
#Username = ...
# Avoid using spaces in the password field
#Password = ...
# Specifying certificate and key enables HTTPS
#CertFile = ...
#KeyFile = ...
[Resolve]
# Set DNS Resovle Strategy
# `ipv4`: Prioritize A records.
# `ipv6`: Prioritize AAAA records .
# `auto` (Default): If the WireGuard interface has IPv4 address only, it's equivalent to `ipv4`, otherwise it's equivalent to `ipv6`.
ResolveStrategy = auto
EOF
# 创建 WireProxy systemd 进程守护
if [ "$SYSTEM" = Alpine ]; then
cat > /etc/init.d/wireproxy << EOF
#!/sbin/openrc-run
description="WireProxy for WARP"
command="/usr/bin/wireproxy"
command_args="-c /etc/wireguard/proxy.conf"
command_background=true
pidfile="/var/run/wireproxy.pid"
EOF
chmod +x /etc/init.d/wireproxy
else
cat > /lib/systemd/system/wireproxy.service << EOF
[Unit]
Description=WireProxy for WARP
After=network.target
Documentation=https://github.com/fscarmen/warp-sh
Documentation=https://github.com/pufferffish/wireproxy
[Service]
ExecStart=/usr/bin/wireproxy -c /etc/wireguard/proxy.conf
RemainAfterExit=yes
Restart=always
[Install]
WantedBy=multi-user.target
EOF
fi
# 保存好配置文件
mv -f $0 /etc/wireguard/menu.sh >/dev/null 2>&1
# 创建再次执行的软链接快捷方式,再次运行可以用 warp 指令,设置默认语言
chmod +x /etc/wireguard/menu.sh >/dev/null 2>&1
ln -sf /etc/wireguard/menu.sh /usr/bin/warp && info " $(text 38) "
echo "$L" >/etc/wireguard/language
# 开启 wireproxy
wireproxy_onoff no_output
# 设置开机启动 wireproxy
[ "$SYSTEM" = Alpine ] && rc-update add wireproxy default || systemctl enable --now wireproxy
sleep 1
# 结果提示,脚本运行时间,次数统计
end=$(date +%s)
info " $(text 114) "
statistics_of_run-times get
info " $(text 27): $WIREPROXY_SOCKS5\n WARP$WIREPROXY_ACCOUNT\n IPv4: $WIREPROXY_WAN4 $WIREPROXY_COUNTRY4 $WIREPROXY_ASNORG4\n IPv6: $WIREPROXY_WAN6 $WIREPROXY_COUNTRY6 $WIREPROXY_ASNORG6"
echo -e "\n==============================================================\n"
hint " $(text 43) \n" && help
else
[ "$IS_ANEMONE" = 'is_anemone' ] && ( iptables_solution; systemctl restart dnsmasq >/dev/null 2>&1 )
# 创建再次执行的软链接快捷方式,再次运行可以用 warp 指令,设置默认语言
mv -f $0 /etc/wireguard/menu.sh >/dev/null 2>&1
chmod +x /etc/wireguard/menu.sh >/dev/null 2>&1
ln -sf /etc/wireguard/menu.sh /usr/bin/warp && info " $(text 38) "
echo "$L" >/etc/wireguard/language
# 自动刷直至成功( warp bug,有时候获取不了ip地址),重置之前的相关变量值,记录新的 IPv4 和 IPv6 地址和归属地,IPv4 / IPv6 优先级别
info " $(text 39) "
unset IP4 IP6 WAN4 WAN6 COUNTRY4 COUNTRY6 ASNORG4 ASNORG6 TRACE4 TRACE6 PLUS4 PLUS6 WARPSTATUS4 WARPSTATUS6
net no_output
# 显示 IPv4 / IPv6 优先结果
result_priority
# 设置开机启动 warp
${SYSTEMCTL_ENABLE[int]} >/dev/null 2>&1
# 结果提示,脚本运行时间,次数统计
end=$(date +%s)
echo -e "\n==============================================================\n"
info " IPv4: $WAN4 $COUNTRY4 $ASNORG4 "
info " IPv6: $WAN6 $COUNTRY6 $ASNORG6 "
info " $(text 28) "
statistics_of_run-times get
info " $PRIORITY_NOW , $(text 46) "
echo -e "\n==============================================================\n"
hint " $(text 43) \n" && help
[[ "$TRACE4$TRACE6" = offoff ]] && warning " $(text 44) "
fi
}
# 等待进程运行结果函数
wait_for() {
local WHAT=$1
local TIME_OUT=0
local MAX_TIME=30
until [ "$TIME_OUT" -gt "$MAX_TIME" ]; do
((TIME_OUT++))
case "$WHAT" in
interface )
grep -q 'CloudflareWARP' <<< "$(ip link show | awk -F': ' '{print $2}')" && echo "OK" && return
;;
socks5 )
grep -q 'warp-svc' <<< "$(ss -nltp | awk '{print $NF}' | awk -F \" '{print $2}')" && echo "OK" && return
;;
[0-9]* )
grep -q ":$WHAT" <<< "$(ss -nltp)" && echo "OK" && return
;;
esac
sleep 1
done
echo "NO"
}
client_install() {
settings() {
# 如果是 Warp 模式,进程守护添加 rule_add 和 rule_del
[ "$IS_LUBAN" = 'is_luban' ] && sed -i '/ExecStart=\/bin\/warp-svc/a\ExecStartPost=warp z\nExecStop=warp x' /usr/lib/systemd/system/warp-svc.service && systemctl daemon-reload
info " $(text 84) "
while true; do
((REGISTER_ERROR_TIME++))
warp-cli --accept-tos registration new >/dev/null 2>&1
local REGISTRATION_SHOW=$(warp-cli --accept-tos registration show 2>/dev/null)
if [[ "$REGISTRATION_SHOW" =~ "ID:" ]]; then
break
# 注册失败,给予一个免费账户。
elif [[ "$REGISTER_ERROR_TIME" -gt 10 || "$REGISTRATION_SHOW" =~ 'Error: Missing registration' ]]; then
[ ! -d /var/lib/cloudflare-warp ] && mkdir -p /var/lib/cloudflare-warp
echo '{"registration_id":"317b5a76-3da1-469f-88d6-c3b261da9f10","api_token":"11111111-1111-1111-1111-111111111111","secret_key":"CNUysnWWJmFGTkqYtg/wpDfURUWvHB8+U1FLlVAIB0Q=","public_key":"DuOi83pAIsbJMP3CJpxq6r3LVGHtqLlzybEIvbczRjo=","override_codes":null}' > /var/lib/cloudflare-warp/reg.json
echo '{"own_public_key":"DuOi83pAIsbJMP3CJpxq6r3LVGHtqLlzybEIvbczRjo=","registration_id":"317b5a76-3da1-469f-88d6-c3b261da9f10","time_created":{"secs_since_epoch":1692163041,"nanos_since_epoch":81073202},"interface":{"v4":"172.16.0.2","v6":"2606:4700:110:8d4e:cef9:30c2:6d4a:f97b"},"endpoints":[{"v4":"162.159.192.7:2408","v6":"[2606:4700:d0::a29f:c007]:2408"},{"v4":"162.159.192.7:500","v6":"[2606:4700:d0::a29f:c007]:500"},{"v4":"162.159.192.7:1701","v6":"[2606:4700:d0::a29f:c007]:1701"},{"v4":"162.159.192.7:4500","v6":"[2606:4700:d0::a29f:c007]:4500"}],"public_key":"bmXOC+F1FxEMF9dyiK2H5/1SUtzH0JuVo51h2wPfgyo=","account":{"account_type":"free","id":"7e0e6c80-24c5-49ba-ba3d-087f45fcd1e9","license":"n01H3Cf4-3Za40C7b-5qOs0c42"},"policy":null,"valid_until":"2023-08-17T05:17:21.081073724Z","alternate_networks":null,"dex_tests":null,"custom_cert_settings":null}' > /var/lib/cloudflare-warp/conf.json
warp-cli --accept-tos disconnect >/dev/null 2>&1
warp-cli --accept-tos connect >/dev/null 2>&1
sleep 1
[[ $(warp-cli --accept-tos registration show) =~ 'Free' ]] && warning "\n $(text 107) \n"
break
else
sleep 2
fi
done
wait
# 关闭隧道 qlog logging
warp-cli --accept-tos debug qlog disable >/dev/null 2>&1
# 判断安装模式: IS_LUBAN=is_luban 为 warp interface 模式,否则为 socks5 proxy 模式
if [ "$IS_LUBAN" = 'is_luban' ]; then
i=1; j=3
hint " $(text 11)\n $(text 12) "
warp-cli --accept-tos tunnel ip add-range 0.0.0.0/0 >/dev/null 2>&1
warp-cli --accept-tos tunnel ip add-range ::0/0 >/dev/null 2>&1
warp-cli --accept-tos mode warp >/dev/null 2>&1
warp-cli --accept-tos connect >/dev/null 2>&1
grep -q 'NO' <<< "$(wait_for interface)" && error " $(text 52) "
rule_add >/dev/null 2>&1
ip_case d is_luban
until [[ -n "$CFWARP_WAN4" && -n "$CFWARP_WAN6" ]]; do
(( i++ )) || true
hint " $(text 12) "
warp-cli --accept-tos disconnect >/dev/null 2>&1
rule_del >/dev/null 2>&1
sleep 2
warp-cli --accept-tos connect >/dev/null 2>&1
grep -q 'NO' <<< "$(wait_for interface)" && error " $(text 52) "
rule_add >/dev/null 2>&1
ip_case d is_luban
if [ "$i" = "$j" ]; then
warp-cli --accept-tos disconnect >/dev/null 2>&1
rule_del >/dev/null 2>&1
error " $(text 13) "
fi
done
info " $(text 14) "
else
warp-cli --accept-tos mode proxy >/dev/null 2>&1
warp-cli --accept-tos proxy port "$PORT" >/dev/null 2>&1
warp-cli --accept-tos connect >/dev/null 2>&1
grep -q 'OK' <<< "$(wait_for socks5)" && info " $(text 86) " || error " $(text 87) "
fi
}
# 禁止安装的情况: 1. 重复安装; 2. 非 AMD64 CPU 架构; 3. 非 Ubuntu / Debian / CentOS 系统
[ "$CLIENT" -ge 2 ] && error " $(text 85) "
[[ ! "$ARCHITECTURE" =~ ^(arm64|amd64)$ ]] && error " $(text 101) "
[[ ! "$SYSTEM" =~ Ubuntu|Debian|CentOS ]] && error " $(text 4) "
# CentOS 7 及以下的系统安装不了 Client
[[ "$SYSTEM" = 'CentOS' && "$(expr "$SYS" : '.*\s\([0-9]\{1,\}\)\.*')" -le 7 ]] && error " $(text 102) "
# 安装 WARP Linux Client
[ "$IS_LUBAN" != 'is_luban' ] && input_port
start=$(date +%s)
mkdir -p /etc/wireguard/ >/dev/null 2>&1
if [ "$CLIENT" = 0 ]; then
info " $(text 83) "
if grep -q "CentOS\|Fedora" <<< "$SYSTEM"; then
curl -fsSl https://pkg.cloudflareclient.com/cloudflare-warp-ascii.repo | tee /etc/yum.repos.d/cloudflare-warp.repo
else
local VERSION_CODENAME=$(awk -F '=' '/VERSION_CODENAME/{print $2}' /etc/os-release)
[ -x "$(type -p gpg)" ] || ${PACKAGE_INSTALL[int]} gnupg 2>/dev/null
curl -fsSL https://pkg.cloudflareclient.com/pubkey.gpg | gpg --yes --dearmor --output /usr/share/keyrings/cloudflare-warp-archive-keyring.gpg
echo "deb [signed-by=/usr/share/keyrings/cloudflare-warp-archive-keyring.gpg] https://pkg.cloudflareclient.com/ $VERSION_CODENAME main" | tee /etc/apt/sources.list.d/cloudflare-client.list
fi
${PACKAGE_UPDATE[int]}
${PACKAGE_INSTALL[int]} cloudflare-warp
[ "$(systemctl is-active warp-svc)" != active ] && ( systemctl start warp-svc; sleep 2 )
# warp-cli 只连这个路径,这是一个 AF_UNIX socket
until [ -e /run/cloudflare-warp/warp_service ]; do
sleep 2
done
settings
elif [[ "$CLIENT" = '2' && $(warp-cli --accept-tos status 2>/dev/null) =~ 'Registration missing' ]]; then
[ "$(systemctl is-active warp-svc)" != active ] && ( systemctl start warp-svc; sleep 2 )
settings
else
warning " $(text 85) "
fi
# 创建再次执行的软链接快捷方式,再次运行可以用 warp 指令,设置默认语言
mv -f $0 /etc/wireguard/menu.sh >/dev/null 2>&1
chmod +x /etc/wireguard/menu.sh >/dev/null 2>&1
ln -sf /etc/wireguard/menu.sh /usr/bin/warp && info " $(text 38) "
echo "$L" >/etc/wireguard/language
# 结果提示,脚本运行时间,次数统计
local CLIENT_ACCOUNT=$(warp-cli --accept-tos registration show 2>/dev/null | awk '/type/{print $3}')
[ "$CLIENT_ACCOUNT" = Limited ] && CLIENT_AC='+'
if [ "$IS_LUBAN" = 'is_luban' ]; then
end=$(date +%s)
echo -e "\n==============================================================\n"
info " $(text 94) "
statistics_of_run-times get
info " WARP$CLIENT_AC IPv4: $CFWARP_WAN4 $CFWARP_COUNTRY4 $CFWARP_ASNORG4\n WARP$CLIENT_AC IPv6: $CFWARP_WAN6 $CFWARP_COUNTRY6 $CFWARP_ASNORG6 "
else
ip_case d client
end=$(date +%s)
echo -e "\n==============================================================\n"
info " $(text 94) "
statistics_of_run-times get
info " $(text 27): $CLIENT_SOCKS5\n WARP$CLIENT_AC IPv4: $CLIENT_WAN4 $CLIENT_COUNTRY4 $CLIENT_ASNORG4\n WARP$CLIENT_AC IPv6: $CLIENT_WAN6 $CLIENT_COUNTRY6 $CLIENT_ASNORG6 "
fi
echo -e "\n==============================================================\n"
hint " $(text 43) \n" && help
}
# iptables+dnsmasq+ipset 方案,IPv6 only 不适用
stream_solution() {
[ "$m" = 0 ] && error " $(text 112) "
echo -e "\n==============================================================\n"
info " $(text 139) "
echo -e "\n==============================================================\n"
hint " 1. $(text 48) "
[ "$OPTION" != e ] && hint " 0. $(text 49) \n" || hint " 0. $(text 76) \n"
reading " $(text 50) " IPTABLES
case "$IPTABLES" in
1 )
CONF=${CONF1[n]}; IS_ANEMONE=is_anemone; install
;;
0 )
[ "$OPTION" != e ] && menu || exit
;;
* )
warning " $(text 51) [0-1]"; sleep 1; stream_solution
esac
}
# wireproxy 方案
wireproxy_solution() {
ss -nltp | grep -q wireproxy && error " $(text 130) "
echo -e "\n==============================================================\n"
info " $(text 129) "
echo -e "\n==============================================================\n"
hint " 1. $(text 48) "
[ "$OPTION" != w ] && hint " 0. $(text 49) \n" || hint " 0. $(text 76) \n"
reading " $(text 50) " WIREPROXY_CHOOSE
case "$WIREPROXY_CHOOSE" in
1 )
IS_PUFFERFFISH=is_pufferffish; install
;;
0 )
[ "$OPTION" != w ] && menu || exit
;;
* )
warning " $(text 51) [0-1]"; sleep 1; wireproxy_solution
esac
}
# 判断当前 WARP 网络接口及 Client 的运行状态,并对应的给菜单和动作赋值
menu_setting() {
if [[ "$CLIENT" -gt 1 || "$WIREPROXY" -gt 0 ]]; then
[ "$CLIENT" -lt 3 ] && MENU_OPTION[1]="1. $(text 88)" || MENU_OPTION[1]="1. $(text 89)"
[ "$WIREPROXY" -lt 2 ] && MENU_OPTION[2]="2. $(text 127)" || MENU_OPTION[2]="2. $(text 128)"
MENU_OPTION[3]="3. $(text 63)"
ACTION[1]() { client_onoff; }
ACTION[2]() { wireproxy_onoff; }
ACTION[3]() { change_port; }
else
check_stack
case "$m" in
[0-2] )
MENU_OPTION[1]="1. $(text 66)"
MENU_OPTION[2]="2. $(text 67)"
MENU_OPTION[3]="3. $(text 68)"
ACTION[1]() { CONF=${CONF1[n]}; install; }
ACTION[2]() { CONF=${CONF2[n]}; install; }
ACTION[3]() { CONF=${CONF3[n]}; install; }
;;
* )
MENU_OPTION[1]="1. $(text 105)"
MENU_OPTION[2]="2. $(text 106)"
ACTION[1]() { stack_switch; }
ACTION[2]() { stack_switch; }
# case * 分支只有2个菜单项,后续从第3项开始
[ -e /etc/dnsmasq.d/warp.conf ] && IPTABLE_INSTALLED="$(text 92)"
wg show warp >/dev/null 2>&1 && MENU_OPTION[3]="3. $(text 77)" || MENU_OPTION[3]="3. $(text 71)"
if [ -e /etc/wireguard/warp.conf ]; then
grep -q '#Table' /etc/wireguard/warp.conf && GLOBAL_OR_NOT="$(text 95)" || GLOBAL_OR_NOT="$(text 96)"
fi
MENU_OPTION[4]="4. ${CLIENT_INSTALLED}${CLIENT_NOT_ALLOWED_ARCHITECTURE}$(text 82)"
MENU_OPTION[5]="5. $(text 35)"
MENU_OPTION[6]="6. $(text 72)"
MENU_OPTION[7]="7. $(text 73)"
MENU_OPTION[8]="8. $(text 75)"
MENU_OPTION[9]="9. $(text 80)"
MENU_OPTION[10]="10. ${IPTABLE_INSTALLED}$(text 57)"
MENU_OPTION[11]="11. ${WIREPROXY_INSTALLED}$(text 113)"
MENU_OPTION[12]="12. ${CLIENT_INSTALLED}${CLIENT_NOT_ALLOWED_ARCHITECTURE}$(text 132)"
MENU_OPTION[0]="0. $(text 76)"
ACTION[3]() { OPTION=o; onoff; }
ACTION[4]() { client_install; }; ACTION[5]() { change_ip; }; ACTION[6]() { uninstall; }; ACTION[7]() { bbrInstall; }; ACTION[8]() { ver; };
ACTION[9]() { bash <(curl -sSL https://gitlab.com/fscarmen/warp_unlock/-/raw/main/unlock.sh) -$L; };
ACTION[10]() { IS_ANEMONE=is_anemone ;install; };
ACTION[11]() { IS_PUFFERFFISH=is_pufferffish; install; };
ACTION[12]() { IS_LUBAN=is_luban; client_install; };
ACTION[0]() { exit; }
return
esac
fi
[ -e /etc/dnsmasq.d/warp.conf ] && IPTABLE_INSTALLED="$(text 92)"
wg show warp >/dev/null 2>&1 && MENU_OPTION[4]="4. $(text 77)" || MENU_OPTION[4]="4. $(text 71)"
if [ -e /etc/wireguard/warp.conf ]; then
grep -q '#Table' /etc/wireguard/warp.conf && GLOBAL_OR_NOT="$(text 95)" || GLOBAL_OR_NOT="$(text 96)"
fi
MENU_OPTION[5]="5. ${CLIENT_INSTALLED}${CLIENT_NOT_ALLOWED_ARCHITECTURE}$(text 82)"
MENU_OPTION[6]="6. $(text 35)"
MENU_OPTION[7]="7. $(text 72)"
MENU_OPTION[8]="8. $(text 73)"
MENU_OPTION[9]="9. $(text 75)"
MENU_OPTION[10]="10. $(text 80)"
MENU_OPTION[11]="11. ${IPTABLE_INSTALLED}$(text 57)"
MENU_OPTION[12]="12. ${WIREPROXY_INSTALLED}$(text 113)"
MENU_OPTION[13]="13. ${CLIENT_INSTALLED}${CLIENT_NOT_ALLOWED_ARCHITECTURE}$(text 132)"
MENU_OPTION[0]="0. $(text 76)"
ACTION[4]() { OPTION=o; onoff; }
ACTION[5]() { client_install; }; ACTION[6]() { change_ip; }; ACTION[7]() { uninstall; }; ACTION[8]() { bbrInstall; }; ACTION[9]() { ver; };
ACTION[10]() { bash <(curl -sSL https://gitlab.com/fscarmen/warp_unlock/-/raw/main/unlock.sh) -$L; };
ACTION[11]() { IS_ANEMONE=is_anemone ;install; };
ACTION[12]() { IS_PUFFERFFISH=is_pufferffish; install; };
ACTION[13]() { IS_LUBAN=is_luban; client_install; };
ACTION[0]() { exit; }
}
# 显示菜单
menu() {
clear
# hint " $(text 16) "
echo -e "======================================================================================================================\n"
info " $(text 17):$VERSION\n $(text 18):$(text 1)\n $(text 19):\n\t $(text 20):$SYS\n\t $(text 21):$(uname -r)\n\t $(text 22):$ARCHITECTURE\n\t $(text 23):$VIRT "
info "\t IPv4: $WAN4 $COUNTRY4 $ASNORG4 "
info "\t IPv6: $WAN6 $COUNTRY6 $ASNORG6 "
case "$TRACE4$TRACE6" in
*plus* )
info "\t $(text 59)\t $PLUSINFO\n\t $(text 46) "
;;
*on* )
info "\t $(text 60)\n\t $(text 46) "
esac
[ "$PLAN" != 3 ] && info "\t $(text 61) "
case "$CLIENT" in
0 )
info "\t $(text 30) "
;;
1|2 )
info "\t $(text 31) "
;;
3 )
info "\t WARP$CLIENT_AC $(text 24)\t $(text 27): $CLIENT_SOCKS5\n\t WARP$CLIENT_AC IPv4: $CLIENT_WAN4 $CLIENT_COUNTRY4 $CLIENT_ASNORG4\n\t WARP$CLIENT_AC IPv6: $CLIENT_WAN6 $CLIENT_COUNTRY6 $CLIENT_ASNORG6 "
;;
5 )
info "\t WARP$CLIENT_AC $(text 24)\t $(text 58)\n\t WARP$CLIENT_AC IPv4: $CFWARP_WAN4 $CFWARP_COUNTRY4 $CFWARP_ASNORG4\n\t WARP$CLIENT_AC IPv6: $CFWARP_WAN6 $CFWARP_COUNTRY6 $CFWARP_ASNORG6 "
esac
case "$WIREPROXY" in
0 )
info "\t $(text 125) "
;;
1 )
info "\t $(text 126) "
;;
2 )
info "\t WARP$WIREPROXY_ACCOUNT $(text 124)\t $(text 27): $WIREPROXY_SOCKS5\n\t IPv4: $WIREPROXY_WAN4 $WIREPROXY_COUNTRY4 $WIREPROXY_ASNORG4\n\t IPv6: $WIREPROXY_WAN6 $WIREPROXY_COUNTRY6 $WIREPROXY_ASNORG6 "
esac
echo -e "\n======================================================================================================================\n"
for ((h=1; h<${#MENU_OPTION[*]}; h++)); do hint " ${MENU_OPTION[h]} "; done
hint " ${MENU_OPTION[0]} "
reading "\n $(text 50) " MENU_CHOOSE
# 输入必须是数字且少于等于最大可选项
if [[ $MENU_CHOOSE =~ ^[0-9]{1,2}$ ]] && (( $MENU_CHOOSE >= 0 && $MENU_CHOOSE < ${#MENU_OPTION[*]} )); then
ACTION[$MENU_CHOOSE]
else
warning " $(text 51) [0-$((${#MENU_OPTION[*]}-1))] " && sleep 1 && menu
fi
}
# 传参选项 OPTION: 1=为 IPv4 或者 IPv6 补全另一栈WARP; 2=安装双栈 WARP; u=卸载 WARP; b=升级内核、开启BBR及DD; o=WARP开关; 其他或空值=菜单界面
[ "$1" != '[option]' ] && OPTION="${1,,}"
# 不同选项的逻辑
case "$OPTION" in
s )
[[ "${2,,}" = [46d] ]] && PRIORITY_SWITCH="${2,,}"
;;
i )
[[ "${2,,}" =~ ^[a-z]{2}$ ]] && EXPECT="${2,,}"
esac
# 主程序运行 1/3
check_cdn
statistics_of_run-times update menu.sh 2>/dev/null
select_language
check_operating_system
# 设置部分后缀 1/3
case "$OPTION" in
h )
help; exit 0
;;
z )
wait_for interface; rule_add; exit 0
;;
x )
rule_del; exit 0
;;
i )
change_ip; exit 0
;;
s )
stack_priority; result_priority; exit 0
esac
# 主程序运行 2/3
check_root
# 设置部分后缀 2/3
case "$OPTION" in
b )
bbrInstall; exit 0
;;
u )
uninstall; exit 0
;;
v )
ver; exit 0
;;
n )
net; exit 0
;;
o )
onoff; exit 0
;;
r )
client_onoff; exit 0
;;
y )
wireproxy_onoff; exit 0
esac
# 主程序运行 3/3
# 在卸载模式下不调用check_dependencies
[[ "$OPTION" != "u" ]] && check_dependencies
check_virt $SYSTEM
check_system_info
# 提前准备最佳 MTU
[[ ${CLIENT} = 0 && ${WIREPROXY} = 0 && ! -s /etc/wireguard/warp.conf ]] && { best_mtu; }&
menu_setting
# 设置部分后缀 3/3
case "$OPTION" in
# 在已运行 Linux Client 前提下,不能安装 WARP IPv4 或者双栈网络接口。如已经运行 WARP ,参数 4,6,d 从原来的安装改为切换
[46d] )
if [ -e /etc/wireguard/warp.conf ]; then
SWITCHCHOOSE="${OPTION^^}"
stack_switch
else
case "$OPTION" in
4 )
[[ "$CLIENT" = [35] ]] && error " $(text 110) "
CONF=${CONF1[n]}
;;
6 )
CONF=${CONF2[n]}
;;
d )
[[ "$CLIENT" = [35] ]] && error " $(text 110) "
CONF=${CONF3[n]}
esac
install
fi
;;
c )
client_install
;;
l )
IS_LUBAN=is_luban && client_install
;;
e )
stream_solution
;;
w )
wireproxy_solution
;;
k )
kernel_reserved_switch
;;
g )
[ ! -e /etc/wireguard/warp.conf ] && ( GLOBAL_OR_NOT_CHOOSE=2 && CONF=${CONF3[n]} && install; true ) || working_mode_switch
;;
* )
menu
esac