v1.3.10 feat: add naive support and switch NekoBox export to Throne

- add naive to protocol selection, quick install, and reload flows
- generate naive inbound config with username/password authentication
- create and refresh 200-day certificates for naive when missing, expired, or SNI changes
- export naive nodes for ShadowRocket, V2RayN, Throne, and sing-box clients
- replace NekoBox subscription output with Throne-compatible links
- include TLS certificate data in Throne subscription links
- update client prompts and compatibility notes for naive and Throne

v1.3.10 feat: 增加 naive 支持并将 NekoBox 导出切换为 Throne

- 将 naive 加入协议选择、极速安装和重载流程
- 生成带用户名 / 密码认证的 naive 入站配置
- 在证书缺失、过期或 SNI 变化时自动生成 / 刷新 200 天证书
- 为 ShadowRocket、V2RayN、Throne 和 sing-box 客户端导出 naive 节点
- 将 NekoBox 订阅输出替换为 Throne 兼容链接
- 在 Throne 订阅链接中附带 TLS 证书数据
- 更新 naive 与 Throne 相关客户端提示和兼容性说明
This commit is contained in:
fscarmen
2026-04-27 13:06:08 +00:00
parent 272aaab85c
commit dbb79a77ad
3 changed files with 217 additions and 83 deletions
+12 -8
View File
@@ -24,16 +24,18 @@
* * * * * *
## 1.更新信息 ## 1.更新信息
2026.04.25 v1.3.10 Added native protocol, but client support is extremely limited, with Shadowrocket offering the best compatibility. For the sing-box core, you must use the -glibc or -musl version according to the requirements; refer to the official documentation for details: https://sing-box.sagernet.org/configuration/outbound/naive/; 增加 native 协议,支持该协议的客户端极少,Shadowrocket 支持最好。sing-box 内核需要按说明使用-glibc 或者 -musl 版本,详见官方说明 https://sing-box.sagernet.org/zh/configuration/outbound/naive/
2026.04.11 v1.3.9 1. remove pre-install UFW blocking logic, fallback to iptables when inactive; 2. avoid unnecessary sing-box restart for CDN / bandwidth / port hopping changes; 3. reduce redundant single-use functions; 1. 移除安装前 UFW 强制校验,inactive 自动回退 iptables; 2. 优选地址 / 带宽 / 端口跳跃修改不再重启 sing-box; 3. 清理单次调用函数,提升结构可读性 2026.04.11 v1.3.9 1. remove pre-install UFW blocking logic, fallback to iptables when inactive; 2. avoid unnecessary sing-box restart for CDN / bandwidth / port hopping changes; 3. reduce redundant single-use functions; 1. 移除安装前 UFW 强制校验,inactive 自动回退 iptables; 2. 优选地址 / 带宽 / 端口跳跃修改不再重启 sing-box; 3. 清理单次调用函数,提升结构可读性
2026.04.10 v1.3.8 1. Automatically detect UFW and switch rule management accordingly; 2. Merge the old -p (port change) functionality into -d (config editor), simplifying usage; 3. Remove the standalone -p / -P entry points entirely; 1. 自动检测 UFW 并切换规则管理方式; 2. 将原有 -p(修改端口)功能合并到 -d(配置修改),简化使用方式; 3. 完全移除独立的 -p / -P 入口
2026.04.09 v1.3.7 1. Add support for enabling/disabling Hysteria2 port hopping and modifying port ranges after installation (sb -d); 2. Allow customization of Hysteria2 upload/download bandwidth without reinstalling; 3. Enhance client configuration with proper Hysteria2 bandwidth (up/down) and port hopping parameters; 1. 支持安装后启用/禁用 Hysteria2 端口跳跃,并可修改端口范围 (sb -d); 2. 支持自定义 Hysteria2 上下行带宽,无需重新安装; 3. 完善客户端配置,补充 Hysteria2 上传/下载速率及端口跳跃参数
<details> <details>
<summary>历史更新 history(点击即可展开或收起)</summary> <summary>历史更新 history(点击即可展开或收起)</summary>
<br> <br>
>2026.04.10 v1.3.8 1. Automatically detect UFW and switch rule management accordingly; 2. Merge the old -p (port change) functionality into -d (config editor), simplifying usage; 3. Remove the standalone -p / -P entry points entirely; 1. 自动检测 UFW 并切换规则管理方式; 2. 将原有 -p(修改端口)功能合并到 -d(配置修改),简化使用方式; 3. 完全移除独立的 -p / -P 入口
>
>2026.04.09 v1.3.7 1. Add support for enabling/disabling Hysteria2 port hopping and modifying port ranges after installation (sb -d); 2. Allow customization of Hysteria2 upload/download bandwidth without reinstalling; 3. Enhance client configuration with proper Hysteria2 bandwidth (up/down) and port hopping parameters; 1. 支持安装后启用/禁用 Hysteria2 端口跳跃,并可修改端口范围 (sb -d); 2. 支持自定义 Hysteria2 上下行带宽,无需重新安装; 3. 完善客户端配置,补充 Hysteria2 上传/下载速率及端口跳跃参数
>
>2026.03.22 v1.3.6 1. Refactor: Support modification after installation (CDN, Reality SNI, node name, UUID/password, server IP); 2. Perf: Rewrite text() with bash nameref and pre-scanned TEXT_NEEDS_EVAL map to eliminate per-call grep subprocesses, significantly reducing repeated string-lookup overhead; 1. 重构:支持安装后多项修改(CDN、Reality SNI、节点名、UUID/密码、服务器 IP);2. 性能优化:用 bash nameref 和预扫描 TEXT_NEEDS_EVAL 关联数组重写 text() 函数,消除每次调用产生的 grep 子进程,大幅降低字符串查找开销 >2026.03.22 v1.3.6 1. Refactor: Support modification after installation (CDN, Reality SNI, node name, UUID/password, server IP); 2. Perf: Rewrite text() with bash nameref and pre-scanned TEXT_NEEDS_EVAL map to eliminate per-call grep subprocesses, significantly reducing repeated string-lookup overhead; 1. 重构:支持安装后多项修改(CDN、Reality SNI、节点名、UUID/密码、服务器 IP);2. 性能优化:用 bash nameref 和预扫描 TEXT_NEEDS_EVAL 关联数组重写 text() 函数,消除每次调用产生的 grep 子进程,大幅降低字符串查找开销
> >
>2026.03.14 v1.3.5 Performance: Optimize concurrent process execution to significantly accelerate script installation. 性能优化:优化并发进程执行,大幅提升脚本安装速度 >2026.03.14 v1.3.5 Performance: Optimize concurrent process execution to significantly accelerate script installation. 性能优化:优化并发进程执行,大幅提升脚本安装速度
@@ -136,7 +138,7 @@
## 2.项目特点: ## 2.项目特点:
* 一键部署多协议,可以单选、多选或全选 ShadowTLS v3 / XTLS Reality / Hysteria2 / Tuic V5 / ShadowSocks / Trojan / Vmess + ws / Vless + ws + tls / H2 Reality / gRPC Reality / AnyTLS, 总有一款适合你 * 一键部署多协议,可以单选、多选或全选 ShadowTLS v3 / XTLS Reality / Hysteria2 / Tuic V5 / ShadowSocks / Trojan / Vmess + ws / Vless + ws + tls / H2 Reality / gRPC Reality / AnyTLS / NaiveProxy, 总有一款适合你
* 所有协议均不需要域名,可选 Cloudflare Argo Tunnel 内网穿透以支持传统方式为 websocket 的协议 * 所有协议均不需要域名,可选 Cloudflare Argo Tunnel 内网穿透以支持传统方式为 websocket 的协议
* 节点信息输出到 V2rayN / Clash Verge / 小火箭 / Nekobox / Sing-box (SFI, SFA, SFM),订阅自动适配客户端,一个订阅 url 走天下 * 节点信息输出到 V2rayN / Clash Verge / 小火箭 / Nekobox / Sing-box (SFI, SFA, SFM),订阅自动适配客户端,一个订阅 url 走天下
* 自定义端口,适合有限开放端口的 nat 小鸡 * 自定义端口,适合有限开放端口的 nat 小鸡
@@ -372,7 +374,7 @@ bash <(wget -qO- https://raw.githubusercontent.com/fscarmen/sing-box/main/sing-b
| Key 大小写不敏感(Case Insensitive| Value | | Key 大小写不敏感(Case Insensitive| Value |
| --------------- | ----------- | | --------------- | ----------- |
| --LANGUAGE | c=中文; e=英文 | | --LANGUAGE | c=中文; e=英文 |
| --CHOOSE_PROTOCOLS | 可多选,如 bcdfk<br> a=全部<br> b=XTLS + reality<br> c=hysteria2<br> d=tuic<br> e=ShadowTLS<br> f=shadowsocks<br> g=trojan<br> h=vmess + ws<br> i=vless + ws + tls<br> j=H2 + reality<br> k=gRPC + reality<br> l=AnyTLS | | --CHOOSE_PROTOCOLS | 可多选,如 bcdfk<br> a=全部<br> b=XTLS + reality<br> c=hysteria2<br> d=tuic<br> e=ShadowTLS<br> f=shadowsocks<br> g=trojan<br> h=vmess + ws<br> i=vless + ws + tls<br> j=H2 + reality<br> k=gRPC + reality<br> l=AnyTLS<br> m=NaiveProxy |
| --START_PORT | 100 - 65520 | | --START_PORT | 100 - 65520 |
| --PORT_NGINX | n=不需要订阅,或者 100 - 65520 | | --PORT_NGINX | n=不需要订阅,或者 100 - 65520 |
| --SERVER_IP | IPv4 或 IPv6 地址,不需要中括号 | | --SERVER_IP | IPv4 或 IPv6 地址,不需要中括号 |
@@ -559,7 +561,8 @@ services:
``` ```
/etc/sing-box/ # 项目主体目录 /etc/sing-box/ # 项目主体目录
|-- cert # 存放证书文件目录 |-- cert # 存放证书文件目录
| |-- cert.pem # SSL/TLS 安全证书文件 | |-- cert.pem # SSL/TLS 安全证书文件(用于大部分协议)
| |-- cert_200.pem # SSL/TLS 安全证书文件(专用于 NaiveProxy 协议)
| `-- private.key # SSL/TLS 证书的私钥信息 | `-- private.key # SSL/TLS 证书的私钥信息
|-- conf # sing-box server 配置文件目录 |-- conf # sing-box server 配置文件目录
| |-- 00_log.json # 日志配置文件 | |-- 00_log.json # 日志配置文件
@@ -579,7 +582,8 @@ services:
| |-- 18_vless-ws-tls_inbounds.json # vless + ws + tls 协议配置文件 | |-- 18_vless-ws-tls_inbounds.json # vless + ws + tls 协议配置文件
| |-- 19_h2-reality_inbounds.json # Reality http2 协议配置文件 | |-- 19_h2-reality_inbounds.json # Reality http2 协议配置文件
| |-- 20_grpc-reality_inbounds.json # Reality gRPC 协议配置文件 | |-- 20_grpc-reality_inbounds.json # Reality gRPC 协议配置文件
| `-- 21_anytls_inbounds.json # AnyTLS 协议配置文件 | |-- 21_anytls_inbounds.json # AnyTLS 协议配置文件
| `-- 22_naive_inbounds.json # NaiveProxy 协议配置文件
|-- logs |-- logs
| `-- box.log # sing-box 运行日志文件 | `-- box.log # sing-box 运行日志文件
|-- subscribe # sing-box server 配置文件目录 |-- subscribe # sing-box server 配置文件目录
+3 -2
View File
@@ -12,8 +12,8 @@
LANGUAGE='' LANGUAGE=''
# 协议选择 / Protocol selection: # 协议选择 / Protocol selection:
# a 为全部协议,也可以选择 b-k 的任意组合 # a 为全部协议,也可以选择 b-m 的任意组合
# a for all protocols, or choose any combination from b-k # a for all protocols, or choose any combination from b-m
# b: VLESS + Reality # b: VLESS + Reality
# c: Hysteria2 # c: Hysteria2
# d: Tuic V5 # d: Tuic V5
@@ -25,6 +25,7 @@ LANGUAGE=''
# j: VLESS + H2 + Reality # j: VLESS + H2 + Reality
# k: VLESS + gRPC + Reality # k: VLESS + gRPC + Reality
# l: AnyTLS # l: AnyTLS
# m: NaiveProxy
CHOOSE_PROTOCOLS='' CHOOSE_PROTOCOLS=''
# 起始端口号,其他协议会依次递增 / Starting port number, other protocols will increment sequentially # 起始端口号,其他协议会依次递增 / Starting port number, other protocols will increment sequentially
+200 -71
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env bash #!/usr/bin/env bash
# 当前脚本版本号 # 当前脚本版本号
VERSION='v1.3.9 (2026.04.11)' VERSION='v1.3.10 (2026.04.25)'
# Github 反代加速代理 # Github 反代加速代理
GITHUB_PROXY=('https://hub.glowp.xyz/' 'https://proxy.vvvv.ee/') GITHUB_PROXY=('https://hub.glowp.xyz/' 'https://proxy.vvvv.ee/')
@@ -17,8 +17,8 @@ MAX_PORT=65520
MIN_HOPPING_PORT=10000 MIN_HOPPING_PORT=10000
MAX_HOPPING_PORT=65535 MAX_HOPPING_PORT=65535
TLS_SERVER_DEFAULT=addons.mozilla.org TLS_SERVER_DEFAULT=addons.mozilla.org
PROTOCOL_LIST=("XTLS + reality" "hysteria2" "tuic" "ShadowTLS" "shadowsocks" "trojan" "vmess + ws" "vless + ws + tls" "H2 + reality" "gRPC + reality" "AnyTLS") PROTOCOL_LIST=("XTLS + reality" "hysteria2" "tuic" "ShadowTLS" "shadowsocks" "trojan" "vmess + ws" "vless + ws + tls" "H2 + reality" "gRPC + reality" "AnyTLS" "naive")
NODE_TAG=("xtls-reality" "hysteria2" "tuic" "ShadowTLS" "shadowsocks" "trojan" "vmess-ws" "vless-ws-tls" "h2-reality" "grpc-reality" "anytls") NODE_TAG=("xtls-reality" "hysteria2" "tuic" "ShadowTLS" "shadowsocks" "trojan" "vmess-ws" "vless-ws-tls" "h2-reality" "grpc-reality" "anytls" "naive")
CONSECUTIVE_PORTS=${#PROTOCOL_LIST[@]} CONSECUTIVE_PORTS=${#PROTOCOL_LIST[@]}
CDN_DOMAIN=("skk.moe" "ip.sb" "time.is" "cfip.xxxxxxxx.tk" "bestcf.top" "cdn.2020111.xyz" "xn--b6gac.eu.org" "cf.090227.xyz") CDN_DOMAIN=("skk.moe" "ip.sb" "time.is" "cfip.xxxxxxxx.tk" "bestcf.top" "cdn.2020111.xyz" "xn--b6gac.eu.org" "cf.090227.xyz")
SUBSCRIBE_TEMPLATE="https://raw.githubusercontent.com/fscarmen/client_template/main" SUBSCRIBE_TEMPLATE="https://raw.githubusercontent.com/fscarmen/client_template/main"
@@ -39,8 +39,8 @@ mkdir -p "$TEMP_DIR"
E[0]="Language:\n 1. English (default) \n 2. 简体中文" E[0]="Language:\n 1. English (default) \n 2. 简体中文"
C[0]="${E[0]}" C[0]="${E[0]}"
E[1]="1. remove pre-install UFW blocking logic, fallback to iptables when inactive; 2. avoid unnecessary sing-box restart for CDN / bandwidth / port hopping changes; 3. reduce redundant single-use functions" E[1]="Added native protocol, but client support is extremely limited, with Shadowrocket offering the best compatibility. For the sing-box core, you must use the -glibc or -musl version according to the requirements; refer to the official documentation for details: https://sing-box.sagernet.org/configuration/outbound/naive/"
C[1]="1. 移除安装前 UFW 强制校验,inactive 自动回退 iptables; 2. 优选地址 / 带宽 / 端口跳跃修改不再重启 sing-box; 3. 清理单次调用函数,提升结构可读性" C[1]="增加 native 协议,支持该协议的客户端极少,Shadowrocket 支持最好。sing-box 内核需要按说明使用-glibc 或者 -musl 版本,详见官方说明 https://sing-box.sagernet.org/zh/configuration/outbound/naive/"
E[2]="Downloading Sing-box. Please wait a seconds ..." E[2]="Downloading Sing-box. Please wait a seconds ..."
C[2]="下载 Sing-box 中,请稍等 ..." C[2]="下载 Sing-box 中,请稍等 ..."
E[3]="Input errors up to 5 times.The script is aborted." E[3]="Input errors up to 5 times.The script is aborted."
@@ -145,8 +145,8 @@ E[52]="Please set the ip \[\${WS_SERVER_IP_SHOW}] to domain \[\${TYPE_HOST_DOMAI
C[52]="请在 Cloudflare 绑定 \[\${WS_SERVER_IP_SHOW}] 的域名为 \[\${TYPE_HOST_DOMAIN}], 并设置 origin rule 为 \[\${TYPE_PORT_WS}]" C[52]="请在 Cloudflare 绑定 \[\${WS_SERVER_IP_SHOW}] 的域名为 \[\${TYPE_HOST_DOMAIN}], 并设置 origin rule 为 \[\${TYPE_PORT_WS}]"
E[53]="Please select or enter the preferred domain or IP (Default: \${CDN_DOMAIN[0]}):" E[53]="Please select or enter the preferred domain or IP (Default: \${CDN_DOMAIN[0]}):"
C[53]="请选择或者填入优选域名或 IP (默认为: \${CDN_DOMAIN[0]}):" C[53]="请选择或者填入优选域名或 IP (默认为: \${CDN_DOMAIN[0]}):"
E[54]="The contents of the ShadowTLS configuration file need to be updated for the sing_box kernel." E[54]="Copy the following full certificate chain:"
C[54]="ShadowTLS 配置文件内容,需要更新 sing_box 内核" C[54]="复制以下固定证书链"
E[55]="The script runs today: \$TODAY. Total: \$TOTAL" E[55]="The script runs today: \$TODAY. Total: \$TOTAL"
C[55]="脚本当天运行次数: \$TODAY,累计运行次数: \$TOTAL" C[55]="脚本当天运行次数: \$TODAY,累计运行次数: \$TOTAL"
E[56]="Process ID" E[56]="Process ID"
@@ -199,8 +199,8 @@ E[79]="Please enter the port number of nginx. Must be \${MIN_PORT} - \${MAX_PORT
C[79]="请输入 nginx 端口号,必须是 \${MIN_PORT} - \${MAX_PORT} (默认为: \${PORT_NGINX_DEFAULT}):" C[79]="请输入 nginx 端口号,必须是 \${MIN_PORT} - \${MAX_PORT} (默认为: \${PORT_NGINX_DEFAULT}):"
E[80]="subscribe" E[80]="subscribe"
C[80]="订阅" C[80]="订阅"
E[81]="Adaptive Clash / V2rayN / NekoBox / ShadowRocket / SFI / SFA / SFM Clients" E[81]="Adaptive Clash / V2rayN / Throne / ShadowRocket / SFI / SFA / SFM Clients"
C[81]="自适应 Clash / V2rayN / NekoBox / ShadowRocket / SFI / SFA / SFM 客户端" C[81]="自适应 Clash / V2rayN / Throne / ShadowRocket / SFI / SFA / SFM 客户端"
E[82]="template" E[82]="template"
C[82]="模版" C[82]="模版"
E[83]="To uninstall Nginx press [y], it is not uninstalled by default:" E[83]="To uninstall Nginx press [y], it is not uninstalled by default:"
@@ -596,7 +596,7 @@ change_config() {
change_start_port change_start_port
return return
elif [ "$KEY" = "hy2bw" ]; then elif [ "$KEY" = "hy2bw" ]; then
# 修改 Hysteria2 带宽 - 内联实现 # 修改 Hysteria2 带宽
local HY2_UP HY2_DOWN local HY2_UP HY2_DOWN
while true; do while true; do
reading " $(text 141) " HY2_UP reading " $(text 141) " HY2_UP
@@ -614,7 +614,7 @@ change_config() {
export_list export_list
return return
elif [ "$KEY" = "hy2hopping" ]; then elif [ "$KEY" = "hy2hopping" ]; then
# 修改 Hysteria2 端口跳跃 - 内联实现 # 修改 Hysteria2 端口跳跃
check_port_hopping_nat check_port_hopping_nat
local OLD_START="$PORT_HOPPING_START" OLD_END="$PORT_HOPPING_END" local OLD_START="$PORT_HOPPING_START" OLD_END="$PORT_HOPPING_END"
hint "\n $(text 97) \n" hint "\n $(text 97) \n"
@@ -1197,11 +1197,11 @@ check_install() {
fi fi
fi fi
# 并发下载订阅模板 (clash, clash2, sing-box),在新安装和更换协议时会用到 # 并发下载订阅模板 (clash, clash2, sing-box-template),在新安装和更换协议时会用到
{ {
wget --no-check-certificate --continue -qO $TEMP_DIR/clash ${GH_PROXY}${SUBSCRIBE_TEMPLATE}/clash 2>/dev/null & wget --no-check-certificate --continue -qO $TEMP_DIR/clash ${GH_PROXY}${SUBSCRIBE_TEMPLATE}/clash 2>/dev/null &
wget --no-check-certificate --continue -qO $TEMP_DIR/clash2 ${GH_PROXY}${SUBSCRIBE_TEMPLATE}/clash2 2>/dev/null & wget --no-check-certificate --continue -qO $TEMP_DIR/clash2 ${GH_PROXY}${SUBSCRIBE_TEMPLATE}/clash2 2>/dev/null &
wget --no-check-certificate --continue -qO $TEMP_DIR/sing-box ${GH_PROXY}${SUBSCRIBE_TEMPLATE}/sing-box 2>/dev/null & wget --no-check-certificate --continue -qO $TEMP_DIR/sing-box-template ${GH_PROXY}${SUBSCRIBE_TEMPLATE}/sing-box 2>/dev/null &
wait wait
} & } &
@@ -1647,7 +1647,7 @@ sing-box_variables() {
STEP_NUM=0 STEP_NUM=0
# 预先用全选协议计算最大总步骤数,用于协议选择提示时显示 (1/?) # 预先用全选协议计算最大总步骤数,用于协议选择提示时显示 (1/?)
local _saved_protocols=("${INSTALL_PROTOCOLS[@]}") local _saved_protocols=("${INSTALL_PROTOCOLS[@]}")
INSTALL_PROTOCOLS=(b c d e f g h i j k l) INSTALL_PROTOCOLS=(b c d e f g h i j k l m)
calc_install_steps calc_install_steps
INSTALL_PROTOCOLS=("${_saved_protocols[@]}") INSTALL_PROTOCOLS=("${_saved_protocols[@]}")
@@ -1967,6 +1967,32 @@ add_port_hopping_ufw_block() {
' "$RULES_FILE" > "${TEMP_DIR}/$(basename "$RULES_FILE")" && mv "${TEMP_DIR}/$(basename "$RULES_FILE")" "$RULES_FILE" ' "$RULES_FILE" > "${TEMP_DIR}/$(basename "$RULES_FILE")" && mv "${TEMP_DIR}/$(basename "$RULES_FILE")" "$RULES_FILE"
} }
# 删除指定 UFW 规则文件中的 PortHopping NAT 规则块
del_port_hopping_ufw_block() {
local RULES_FILE=$1
local IP_VERSION=$2
local TEMP_RULES_FILE
[ ! -e "$RULES_FILE" ] && return 0
TEMP_RULES_FILE="${TEMP_DIR}/$(basename "$RULES_FILE")"
awk -v ip_version="$IP_VERSION" '
BEGIN { in_block=0 }
{
if ($0 ~ "^# Sing-box Family Bucket UFW NAT .* " ip_version " BEGIN$") {
in_block=1
next
}
if (in_block==1 && $0 ~ "^# Sing-box Family Bucket UFW NAT .* " ip_version " END$") {
in_block=0
next
}
if (in_block==0) print
}
' "$RULES_FILE" > "$TEMP_RULES_FILE" && mv "$TEMP_RULES_FILE" "$RULES_FILE"
}
# 删除 UFW PortHopping NAT 规则 # 删除 UFW PortHopping NAT 规则
del_port_hopping_ufw_rules() { del_port_hopping_ufw_rules() {
local UFW_BEFORE_RULES='/etc/ufw/before.rules' local UFW_BEFORE_RULES='/etc/ufw/before.rules'
@@ -2460,11 +2486,23 @@ ingress:
EOF EOF
} }
# 生成100年的自签证书,区分使用 IPv4 / IPv6 / 域名 # 生成自签证书,区分使用 IPv4 / IPv6 / 域名
# 默认同时更新 cert.pem(36500天) 和 cert_200.pem(200天)
# 传参 naive_only 时,仅检测 cert_200.pem 是否缺失 / 过期 / SNI 不一致,符合条件才更新
ssl_certificate() { ssl_certificate() {
local TLS_SERVER="$1" local TLS_SERVER="$1"
local CERT_MODE="$2"
local CERT_200_FILE="${WORK_DIR}/cert/cert_200.pem"
local CERT_200_SNI
[ ! -d ${WORK_DIR}/cert ] && mkdir -p ${WORK_DIR}/cert [ ! -d ${WORK_DIR}/cert ] && mkdir -p ${WORK_DIR}/cert
if [ "$CERT_MODE" != 'naive_only' ]; then
openssl ecparam -genkey -name prime256v1 -out ${WORK_DIR}/cert/private.key openssl ecparam -genkey -name prime256v1 -out ${WORK_DIR}/cert/private.key
elif [ ! -s ${WORK_DIR}/cert/private.key ] || [ ! -s ${WORK_DIR}/cert/cert.pem ]; then
CERT_MODE=''
openssl ecparam -genkey -name prime256v1 -out ${WORK_DIR}/cert/private.key
fi
cat > ${WORK_DIR}/cert/cert.conf << EOF cat > ${WORK_DIR}/cert/cert.conf << EOF
[req] [req]
@@ -2482,13 +2520,19 @@ subjectAltName = @alt_names
DNS = ${TLS_SERVER} DNS = ${TLS_SERVER}
EOF EOF
if [ "$CERT_MODE" != 'naive_only' ]; then
openssl req -new -x509 -days 36500 -key ${WORK_DIR}/cert/private.key -out ${WORK_DIR}/cert/cert.pem -config ${WORK_DIR}/cert/cert.conf -extensions v3_req openssl req -new -x509 -days 36500 -key ${WORK_DIR}/cert/private.key -out ${WORK_DIR}/cert/cert.pem -config ${WORK_DIR}/cert/cert.conf -extensions v3_req
openssl req -new -x509 -days 200 -key ${WORK_DIR}/cert/private.key -out ${WORK_DIR}/cert/cert_200.pem -config ${WORK_DIR}/cert/cert.conf -extensions v3_req
else
CERT_200_SNI=$(openssl x509 -noout -ext subjectAltName -in "$CERT_200_FILE" 2>/dev/null | awk -F 'DNS:' '/DNS:/{gsub(/,.*/, "", $2); print $2}')
if [ ! -s "$CERT_200_FILE" ] || ! openssl x509 -checkend 0 -noout -in "$CERT_200_FILE" >/dev/null 2>&1 || [ "$CERT_200_SNI" != "$TLS_SERVER" ]; then
openssl req -new -x509 -days 200 -key ${WORK_DIR}/cert/private.key -out ${WORK_DIR}/cert/cert_200.pem -config ${WORK_DIR}/cert/cert.conf -extensions v3_req
fi
fi
rm -f ${WORK_DIR}/cert/cert.conf rm -f ${WORK_DIR}/cert/cert.conf
} }
# 处理防火墙规则
# Nginx 配置文件 # Nginx 配置文件
export_nginx_conf_file() { export_nginx_conf_file() {
# 在添加协议,需要用到 nginx 的时候,先检测是否已经安装 # 在添加协议,需要用到 nginx 的时候,先检测是否已经安装
@@ -2831,6 +2875,9 @@ EOF
# 获取自签名证书的域名 # 获取自签名证书的域名
TLS_SERVER=$(openssl x509 -noout -ext subjectAltName -in ${WORK_DIR}/cert/cert.pem 2>/dev/null | awk -F 'DNS:' '/DNS:/{gsub(/,.*/, "", $2); print $2}') TLS_SERVER=$(openssl x509 -noout -ext subjectAltName -in ${WORK_DIR}/cert/cert.pem 2>/dev/null | awk -F 'DNS:' '/DNS:/{gsub(/,.*/, "", $2); print $2}')
# naive 在 -r 新增协议时,如 cert_200.pem 过期 / 缺失 / SNI 不一致则自动更新
[[ "${INSTALL_PROTOCOLS[@]}" =~ 'm' ]] && ssl_certificate "$TLS_SERVER" naive_only
# 生成 2022-blake3-aes-128-gcm 的 password # 生成 2022-blake3-aes-128-gcm 的 password
local SIP022_PASSWORD=${SIP022_PASSWORD:-"$(openssl rand -base64 16)"} local SIP022_PASSWORD=${SIP022_PASSWORD:-"$(openssl rand -base64 16)"}
@@ -3285,7 +3332,7 @@ EOF
"inbounds":[ "inbounds":[
{ {
"type":"anytls", "type":"anytls",
"tag":"${NODE_NAME[21]} anytls", "tag":"${NODE_NAME[21]} ${NODE_TAG[10]}",
"listen":"::", "listen":"::",
"listen_port":$PORT_ANYTLS, "listen_port":$PORT_ANYTLS,
"users":[ "users":[
@@ -3302,6 +3349,37 @@ EOF
} }
] ]
} }
EOF
fi
# 生成 naive 配置
CHECK_PROTOCOLS=$(asc "$CHECK_PROTOCOLS" ++)
if [[ "${INSTALL_PROTOCOLS[@]}" =~ "$CHECK_PROTOCOLS" ]]; then
[ -z "$PORT_NAIVE" ] && PORT_NAIVE=$[START_PORT+$(awk -v target=$CHECK_PROTOCOLS '{ for(i=1; i<=NF; i++) if($i == target) { print i-1; break } }' <<< "${INSTALL_PROTOCOLS[*]}")]
NODE_NAME[22]=${NODE_NAME[22]:-"$NODE_NAME_CONFIRM"} && UUID[22]=${UUID[22]:-"$UUID_CONFIRM"}
cat > ${WORK_DIR}/conf/22_${NODE_TAG[11]}_inbounds.json << EOF
{
"inbounds":[
{
"type":"naive",
"tag":"${NODE_NAME[22]} ${NODE_TAG[11]}",
"listen":"::",
"listen_port":$PORT_NAIVE,
"users":[
{
"username":"${UUID[22]}",
"password":"${UUID[22]}"
}
],
"tls":{
"enabled":true,
"certificate_path":"${WORK_DIR}/cert/cert_200.pem",
"key_path":"${WORK_DIR}/cert/private.key"
}
}
]
}
EOF EOF
fi fi
} }
@@ -3465,7 +3543,7 @@ EOF
# 获取原有各协议的参数,先清空所有的 key-value # 获取原有各协议的参数,先清空所有的 key-value
fetch_nodes_value() { fetch_nodes_value() {
unset NODE_NAME PORT_XTLS_REALITY UUID TLS_SERVER REALITY_PRIVATE REALITY_PUBLIC PORT_HYSTERIA2 PORT_TUIC TUIC_PASSWORD TUIC_CONGESTION_CONTROL PORT_SHADOWTLS SHADOWTLS_PASSWORD SHADOWSOCKS_METHOD PORT_SHADOWSOCKS PORT_TROJAN TROJAN_PASSWORD PORT_VMESS_WS VMESS_WS_PATH WS_SERVER_IP WS_SERVER_IP_SHOW VMESS_HOST_DOMAIN CDN PORT_VLESS_WS VLESS_WS_PATH VLESS_HOST_DOMAIN PORT_H2_REALITY PORT_GRPC_REALITY ARGO_DOMAIN PORT_ANYTLS SELF_SIGNED_FINGERPRINT_SHA256 SELF_SIGNED_FINGERPRINT_BASE64 unset NODE_NAME PORT_XTLS_REALITY UUID TLS_SERVER REALITY_PRIVATE REALITY_PUBLIC PORT_HYSTERIA2 PORT_TUIC TUIC_PASSWORD TUIC_CONGESTION_CONTROL PORT_SHADOWTLS SHADOWTLS_PASSWORD SHADOWSOCKS_METHOD PORT_SHADOWSOCKS PORT_TROJAN TROJAN_PASSWORD PORT_VMESS_WS VMESS_WS_PATH WS_SERVER_IP WS_SERVER_IP_SHOW VMESS_HOST_DOMAIN CDN PORT_VLESS_WS VLESS_WS_PATH VLESS_HOST_DOMAIN PORT_H2_REALITY PORT_GRPC_REALITY ARGO_DOMAIN PORT_ANYTLS PORT_NAIVE SELF_SIGNED_FINGERPRINT_SHA256 SELF_SIGNED_FINGERPRINT_BASE64
# 获取公共数据 # 获取公共数据
ls ${WORK_DIR}/conf/*-ws*inbounds.json >/dev/null 2>&1 && SERVER_IP=$(awk -F '"' '/"WS_SERVER_IP_SHOW"/{print $4; exit}' ${WORK_DIR}/conf/*-ws*inbounds.json) || SERVER_IP=$(grep -A1 '"tag"' ${WORK_DIR}/list | sed -E '/-ws(-tls)*",$/{N;d}' | awk -F '"' '/"server"/{count++; if (count == 1) {print $4; exit}}') ls ${WORK_DIR}/conf/*-ws*inbounds.json >/dev/null 2>&1 && SERVER_IP=$(awk -F '"' '/"WS_SERVER_IP_SHOW"/{print $4; exit}' ${WORK_DIR}/conf/*-ws*inbounds.json) || SERVER_IP=$(grep -A1 '"tag"' ${WORK_DIR}/list | sed -E '/-ws(-tls)*",$/{N;d}' | awk -F '"' '/"server"/{count++; if (count == 1) {print $4; exit}}')
@@ -3513,6 +3591,9 @@ fetch_nodes_value() {
# 获取 anytls key-value # 获取 anytls key-value
[ -s ${WORK_DIR}/conf/*_${NODE_TAG[10]}_inbounds.json ] && local JSON=$(cat ${WORK_DIR}/conf/*_${NODE_TAG[10]}_inbounds.json) && NODE_NAME[21]=$(sed -n "s/.*\"tag\":\"\(.*\) ${NODE_TAG[10]}.*/\1/p" <<< "$JSON") && PORT_ANYTLS=$(sed -n 's/.*"listen_port":\([0-9]\+\),/\1/gp' <<< "$JSON") && UUID[21]=$(awk -F '"' '/"password"/{print $4}' <<< "$JSON") [ -s ${WORK_DIR}/conf/*_${NODE_TAG[10]}_inbounds.json ] && local JSON=$(cat ${WORK_DIR}/conf/*_${NODE_TAG[10]}_inbounds.json) && NODE_NAME[21]=$(sed -n "s/.*\"tag\":\"\(.*\) ${NODE_TAG[10]}.*/\1/p" <<< "$JSON") && PORT_ANYTLS=$(sed -n 's/.*"listen_port":\([0-9]\+\),/\1/gp' <<< "$JSON") && UUID[21]=$(awk -F '"' '/"password"/{print $4}' <<< "$JSON")
# 获取 naive key-value
[ -s ${WORK_DIR}/conf/*_${NODE_TAG[11]}_inbounds.json ] && local JSON=$(cat ${WORK_DIR}/conf/*_${NODE_TAG[11]}_inbounds.json) && NODE_NAME[22]=$(sed -n "s/.*\"tag\":\"\(.*\) ${NODE_TAG[11]}.*/\1/p" <<< "$JSON") && PORT_NAIVE=$(sed -n 's/.*"listen_port":\([0-9]\+\),/\1/gp' <<< "$JSON") && UUID[22]=$(awk -F '"' '/"username"/{print $4; exit}' <<< "$JSON")
} }
# 获取 Argo 临时隧道域名 # 获取 Argo 临时隧道域名
@@ -3644,9 +3725,24 @@ export_list() {
local SELF_SIGNED_FINGERPRINT_SHA256=$(openssl x509 -fingerprint -noout -sha256 -in ${WORK_DIR}/cert/cert.pem | awk -F '=' '{print $NF}') local SELF_SIGNED_FINGERPRINT_SHA256=$(openssl x509 -fingerprint -noout -sha256 -in ${WORK_DIR}/cert/cert.pem | awk -F '=' '{print $NF}')
local SELF_SIGNED_FINGERPRINT_BASE64=$(openssl x509 -in ${WORK_DIR}/cert/cert.pem -pubkey -noout | openssl pkey -pubin -outform der | openssl dgst -sha256 -binary | openssl enc -base64) local SELF_SIGNED_FINGERPRINT_BASE64=$(openssl x509 -in ${WORK_DIR}/cert/cert.pem -pubkey -noout | openssl pkey -pubin -outform der | openssl dgst -sha256 -binary | openssl enc -base64)
local CERT_URL=$(awk '{printf "%s,", $0}' ${WORK_DIR}/cert/cert.pem | sed 's/,$//')
local CERT_200_URL=$(awk '{printf "%s,", $0}' ${WORK_DIR}/cert/cert_200.pem | sed 's/,$//')
# 从自签证书的 SAN 中读取当前使用的 SNI,优先取 SAN,退回到 CN # 从自签证书的 SAN 中读取当前使用的 SNI,优先取 SAN,退回到 CN
local TLS_SERVER=$(openssl x509 -noout -ext subjectAltName -in ${WORK_DIR}/cert/cert.pem 2>/dev/null | awk -F 'DNS:' '/DNS:/{gsub(/,.*/, "", $2); print $2}') local TLS_SERVER=$(openssl x509 -noout -ext subjectAltName -in ${WORK_DIR}/cert/cert.pem 2>/dev/null | awk -F 'DNS:' '/DNS:/{gsub(/,.*/, "", $2); print $2}')
# naive 协议的特殊处理
if [ -n "$PORT_NAIVE" ]; then
# 在 -n 查看节点时,如 cert_200.pem 过期 / 缺失 / SNI 不一致则自动更新
ssl_certificate "$TLS_SERVER" naive_only
# 读取 naive 自签证书并格式化为 JSON 字符串数组内容;多行/单行位置共用这一个变量
local CERT200_JSON=$(awk 'BEGIN{sep=""} {gsub(/\\/,"\\\\"); gsub(/"/,"\\\""); printf "%s\"%s\"", sep, $0; sep=",\n"}' "${WORK_DIR}/cert/cert_200.pem")
# 获取 naive 自签名证书的指纹
local SELF_SIGNED_200_FINGERPRINT_SHA256=$(openssl x509 -fingerprint -noout -sha256 -in ${WORK_DIR}/cert/cert_200.pem | awk -F '=' '{print $NF}')
fi
# 生成各订阅文件 # 生成各订阅文件
# 生成 Clash proxy providers 订阅文件 # 生成 Clash proxy providers 订阅文件
local CLASH_SUBSCRIBE='proxies:' local CLASH_SUBSCRIBE='proxies:'
@@ -3828,6 +3924,11 @@ vless://$(echo -n "auto:${UUID[20]}@${SERVER_IP_2}:${PORT_GRPC_REALITY}" | base6
" "
[ -n "$PORT_ANYTLS" ] && local SHADOWROCKET_SUBSCRIBE+=" [ -n "$PORT_ANYTLS" ] && local SHADOWROCKET_SUBSCRIBE+="
anytls://${UUID[21]}@${SERVER_IP_1}:${PORT_ANYTLS}?peer=${TLS_SERVER}&udp=1&hpkp=${SELF_SIGNED_FINGERPRINT_SHA256}#${NODE_NAME[21]// /%20}%20${NODE_TAG[10]} anytls://${UUID[21]}@${SERVER_IP_1}:${PORT_ANYTLS}?peer=${TLS_SERVER}&udp=1&hpkp=${SELF_SIGNED_FINGERPRINT_SHA256}#${NODE_NAME[21]// /%20}%20${NODE_TAG[10]}
"
[ -n "$PORT_NAIVE" ] && local SHADOWROCKET_SUBSCRIBE+="
http2://$(echo -n "${UUID[22]}:${UUID[22]}@${SERVER_IP_2}:${PORT_NAIVE}" | base64 -w0)?peer=${TLS_SERVER}&alpn=h2,http/1.1&padding=1&uot=2&hpkp=${SELF_SIGNED_200_FINGERPRINT_SHA256}#${NODE_NAME[22]// /%20}%20${NODE_TAG[11]}%20http2
http3://$(echo -n "${UUID[22]}:${UUID[22]}@${SERVER_IP_2}:${PORT_NAIVE}" | base64 -w0)?peer=${TLS_SERVER}&alpn=h3&padding=1&hpkp=${SELF_SIGNED_200_FINGERPRINT_SHA256}#${NODE_NAME[22]// /%20}%20${NODE_TAG[11]}%20http3
" "
echo -n "$SHADOWROCKET_SUBSCRIBE" | sed -E '/^[ ]*#|^--/d' | sed '/^$/d' | base64 -w0 > ${WORK_DIR}/subscribe/shadowrocket echo -n "$SHADOWROCKET_SUBSCRIBE" | sed -E '/^[ ]*#|^--/d' | sed '/^$/d' | base64 -w0 > ${WORK_DIR}/subscribe/shadowrocket
@@ -3850,28 +3951,24 @@ tuic://${UUID[13]}:${TUIC_PASSWORD}@${SERVER_IP_1}:${PORT_TUIC}?sni=${TLS_SERVER
[ -n "$PORT_SHADOWTLS" ] && local V2RAYN_SUBSCRIBE+=" [ -n "$PORT_SHADOWTLS" ] && local V2RAYN_SUBSCRIBE+="
---------------------------- ----------------------------
# $(text 54)
{ {
\"log\":{ \"log\": {
\"level\":\"warn\" \"level\": \"warn\"
}, },
\"inbounds\":[ \"inbounds\": [
{ {
\"listen\":\"127.0.0.1\", \"listen\": \"127.0.0.1\",
\"listen_port\":${PORT_SHADOWTLS}, \"listen_port\": ${PORT_SHADOWTLS},
\"sniff\":true,
\"sniff_override_destination\":false,
\"tag\": \"${PROTOCOL_LIST[3]}\", \"tag\": \"${PROTOCOL_LIST[3]}\",
\"type\":\"mixed\" \"type\": \"mixed\"
} }
], ],
\"outbounds\":[ \"outbounds\": [
{ {
\"detour\":\"shadowtls-out\", \"detour\": \"shadowtls-out\",
\"method\":\"$SHADOWTLS_METHOD\", \"method\": \"$SHADOWTLS_METHOD\",
\"password\":\"$SHADOWTLS_PASSWORD\", \"password\": \"$SHADOWTLS_PASSWORD\",
\"type\":\"shadowsocks\", \"type\": \"shadowsocks\",
\"udp_over_tcp\": false, \"udp_over_tcp\": false,
\"multiplex\": { \"multiplex\": {
\"enabled\": true, \"enabled\": true,
@@ -3882,20 +3979,20 @@ tuic://${UUID[13]}:${TUIC_PASSWORD}@${SERVER_IP_1}:${PORT_TUIC}?sni=${TLS_SERVER
} }
}, },
{ {
\"password\":\"${UUID[14]}\", \"password\": \"${UUID[14]}\",
\"server\":\"${SERVER_IP}\", \"server\": \"${SERVER_IP}\",
\"server_port\":${PORT_SHADOWTLS}, \"server_port\": ${PORT_SHADOWTLS},
\"tag\": \"shadowtls-out\", \"tag\": \"shadowtls-out\",
\"tls\":{ \"tls\": {
\"enabled\":true, \"enabled\": true,
\"server_name\":\"${TLS_SERVER}\", \"server_name\": \"${TLS_SERVER}\",
\"utls\": { \"utls\": {
\"enabled\": true, \"enabled\": true,
\"fingerprint\": \"firefox\" \"fingerprint\": \"firefox\"
} }
}, },
\"type\":\"shadowtls\", \"type\": \"shadowtls\",
\"version\":3 \"version\": 3
} }
] ]
}" }"
@@ -3955,51 +4052,61 @@ vless://${UUID[20]}@${SERVER_IP_1}:${PORT_GRPC_REALITY}?encryption=none&security
---------------------------- ----------------------------
anytls://${UUID[21]}@${SERVER_IP_1}:${PORT_ANYTLS}?security=tls&sni=${TLS_SERVER}&fp=firefox&insecure=1&allowInsecure=1&type=tcp#${NODE_NAME[21]// /%20}%20${NODE_TAG[10]}" anytls://${UUID[21]}@${SERVER_IP_1}:${PORT_ANYTLS}?security=tls&sni=${TLS_SERVER}&fp=firefox&insecure=1&allowInsecure=1&type=tcp#${NODE_NAME[21]// /%20}%20${NODE_TAG[10]}"
echo -n "$V2RAYN_SUBSCRIBE" | sed -E '/^[ ]*#|^[ ]+|^--|^\{|^\}/d' | sed '/^$/d' | base64 -w0 > ${WORK_DIR}/subscribe/v2rayn [ -n "$PORT_NAIVE" ] && local V2RAYN_SUBSCRIBE+="
----------------------------
naive+https://${UUID[22]}:${UUID[22]}@${SERVER_IP_1}:${PORT_NAIVE}?security=tls&sni=${TLS_SERVER}&insecure=0&allowInsecure=0&type=tcp&headerType=none#${NODE_NAME[22]// /%20}%20${NODE_TAG[11]}%20http2
----------------------------
naive+quic://${UUID[22]}:${UUID[22]}@${SERVER_IP_1}:${PORT_NAIVE}?security=tls&sni=${TLS_SERVER}&insecure=0&allowInsecure=0&type=tcp&headerType=none#${NODE_NAME[22]// /%20}%20${NODE_TAG[11]}%20quic
# 生成 NekoBox 订阅文件 # $(text 54)
[ -n "$PORT_XTLS_REALITY" ] && local NEKOBOX_SUBSCRIBE+=" $(cat ${WORK_DIR}/cert/cert_200.pem)
"
echo -n "$V2RAYN_SUBSCRIBE" | sed '/-----BEGIN CERTIFICATE-----/,/-----END CERTIFICATE-----/d' | sed -E '/^[ ]*#|^[ ]+|^\{|^\}/d' | sed '/^$/d' | base64 -w0 > ${WORK_DIR}/subscribe/v2rayn
# 生成 Throne 订阅文件
[ -n "$PORT_XTLS_REALITY" ] && local THRONE_SUBSCRIBE+="
---------------------------- ----------------------------
vless://${UUID[11]}@${SERVER_IP_1}:${PORT_XTLS_REALITY}?security=reality&sni=${TLS_SERVER}&fp=firefox&pbk=${REALITY_PUBLIC[11]}&type=tcp${VISION_FLOW}&encryption=none#${NODE_NAME[11]// /%20}%20${NODE_TAG[0]}" vless://${UUID[11]}@${SERVER_IP_1}:${PORT_XTLS_REALITY}?security=reality&sni=${TLS_SERVER}&fp=firefox&pbk=${REALITY_PUBLIC[11]}&type=tcp${VISION_FLOW}&encryption=none#${NODE_NAME[11]// /%20}%20${NODE_TAG[0]}"
if [ -n "$PORT_HYSTERIA2" ]; then if [ -n "$PORT_HYSTERIA2" ]; then
local NEKOBOX_PARAMS="insecure=1&sni=${TLS_SERVER}&upmbps=${HY2_UP}&downmbps=${HY2_DOWN}" local THRONE_PARAMS="insecure=1&security=tls&sni=${TLS_SERVER}&upmbps=${HY2_UP}&downmbps=${HY2_DOWN}&security=tls&tls_certificate=${CERT_URL}"
if [[ -n "$PORT_HOPPING_START" && -n "$PORT_HOPPING_END" ]]; then if [[ -n "$PORT_HOPPING_START" && -n "$PORT_HOPPING_END" ]]; then
NEKOBOX_PARAMS+="&mport=${PORT_HOPPING_START}-${PORT_HOPPING_END}&hop_interval=30" THRONE_PARAMS+="&mport=${PORT_HOPPING_START}-${PORT_HOPPING_END}&hop_interval=30"
fi fi
local NEKOBOX_SUBSCRIBE+=" local THRONE_SUBSCRIBE+="
---------------------------- ----------------------------
hy2://${UUID[12]}@${SERVER_IP_1}:${PORT_HYSTERIA2}?${NEKOBOX_PARAMS}#${NODE_NAME[12]// /%20}%20${NODE_TAG[1]}" hy2://${UUID[12]}@${SERVER_IP_1}:${PORT_HYSTERIA2}?${THRONE_PARAMS}#${NODE_NAME[12]// /%20}%20${NODE_TAG[1]}"
fi fi
[ -n "$PORT_TUIC" ] && local NEKOBOX_SUBSCRIBE+=" [ -n "$PORT_TUIC" ] && local THRONE_SUBSCRIBE+="
---------------------------- ----------------------------
tuic://${TUIC_PASSWORD}:${UUID[13]}@${SERVER_IP_1}:${PORT_TUIC}?congestion_control=$TUIC_CONGESTION_CONTROL&alpn=h3&sni=${TLS_SERVER}&udp_relay_mode=native&allow_insecure=1#${NODE_NAME[13]// /%20}%20${NODE_TAG[2]}" tuic://${TUIC_PASSWORD}:${UUID[13]}@${SERVER_IP_1}:${PORT_TUIC}?congestion_control=$TUIC_CONGESTION_CONTROL&alpn=h3&sni=${TLS_SERVER}&udp_relay_mode=native&allow_insecure=1&security=tls&tls_certificate=${CERT_URL}#${NODE_NAME[13]// /%20}%20${NODE_TAG[2]}"
[ -n "$PORT_SHADOWTLS" ] && local NEKOBOX_SUBSCRIBE+=" [ -n "$PORT_SHADOWTLS" ] && local THRONE_SUBSCRIBE+="
---------------------------- ----------------------------
nekoray://custom#$(echo -n "{\"_v\":0,\"addr\":\"127.0.0.1\",\"cmd\":[\"\"],\"core\":\"internal\",\"cs\":\"{\n \\\"password\\\": \\\"${UUID[14]}\\\",\n \\\"server\\\": \\\"${SERVER_IP_1}\\\",\n \\\"server_port\\\": ${PORT_SHADOWTLS},\n \\\"tag\\\": \\\"shadowtls-out\\\",\n \\\"tls\\\": {\n \\\"enabled\\\": true,\n \\\"server_name\\\": \\\"${TLS_SERVER}\\\"\n },\n \\\"type\\\": \\\"shadowtls\\\",\n \\\"version\\\": 3\n}\n\",\"mapping_port\":0,\"name\":\"1-tls-not-use\",\"port\":1080,\"socks_port\":0}" | base64 -w0) nekoray://custom#$(echo -n "{\"_v\":0,\"addr\":\"127.0.0.1\",\"cmd\":[\"\"],\"core\":\"internal\",\"cs\":\"{\n \\\"password\\\": \\\"${UUID[14]}\\\",\n \\\"server\\\": \\\"${SERVER_IP_1}\\\",\n \\\"server_port\\\": ${PORT_SHADOWTLS},\n \\\"tag\\\": \\\"shadowtls-out\\\",\n \\\"tls\\\": {\n \\\"enabled\\\": true,\n \\\"server_name\\\": \\\"${TLS_SERVER}\\\"\n },\n \\\"type\\\": \\\"shadowtls\\\",\n \\\"version\\\": 3\n}\n\",\"mapping_port\":0,\"name\":\"1-tls-not-use\",\"port\":1080,\"socks_port\":0}" | base64 -w0)
nekoray://shadowsocks#$(echo -n "{\"_v\":0,\"method\":\"$SHADOWTLS_METHOD\",\"name\":\"2-ss-not-use\",\"pass\":\"$SHADOWTLS_PASSWORD\",\"port\":0,\"stream\":{\"ed_len\":0,\"insecure\":false,\"mux_s\":0,\"net\":\"tcp\"},\"uot\":0}" | base64 -w0)" nekoray://shadowsocks#$(echo -n "{\"_v\":0,\"method\":\"$SHADOWTLS_METHOD\",\"name\":\"2-ss-not-use\",\"pass\":\"$SHADOWTLS_PASSWORD\",\"port\":0,\"stream\":{\"ed_len\":0,\"insecure\":false,\"mux_s\":0,\"net\":\"tcp\"},\"uot\":0}" | base64 -w0)"
[ -n "$PORT_SHADOWSOCKS" ] && local NEKOBOX_SUBSCRIBE+=" [ -n "$PORT_SHADOWSOCKS" ] && local THRONE_SUBSCRIBE+="
---------------------------- ----------------------------
ss://$(echo -n "${SHADOWSOCKS_METHOD}:${SHADOWSOCKS_PASSWORD}" | base64 -w0)@${SERVER_IP_1}:$PORT_SHADOWSOCKS#${NODE_NAME[15]// /%20}%20${NODE_TAG[4]}" ss://$(echo -n "${SHADOWSOCKS_METHOD}:${SHADOWSOCKS_PASSWORD}" | base64 -w0)@${SERVER_IP_1}:$PORT_SHADOWSOCKS#${NODE_NAME[15]// /%20}%20${NODE_TAG[4]}"
[ -n "$PORT_TROJAN" ] && local NEKOBOX_SUBSCRIBE+=" [ -n "$PORT_TROJAN" ] && local THRONE_SUBSCRIBE+="
---------------------------- ----------------------------
trojan://${TROJAN_PASSWORD}@${SERVER_IP_1}:$PORT_TROJAN?security=tls&sni=${TLS_SERVER}&allowInsecure=1&fp=firefox&type=tcp#${NODE_NAME[16]// /%20}%20${NODE_TAG[5]}" trojan://${TROJAN_PASSWORD}@${SERVER_IP_1}:$PORT_TROJAN?security=tls&sni=${TLS_SERVER}&allowInsecure=1&tls_certificate=${CERT_URL}&fp=firefox&type=tcp#${NODE_NAME[16]// /%20}%20${NODE_TAG[5]}"
if [ -n "$PORT_VMESS_WS" ]; then if [ -n "$PORT_VMESS_WS" ]; then
if [[ "${STATUS[1]}" =~ $(text 27)|$(text 28) ]] || [[ "$IS_ARGO" = 'is_argo' && "$NONINTERACTIVE_INSTALL" = 'noninteractive_install' ]]; then if [[ "${STATUS[1]}" =~ $(text 27)|$(text 28) ]] || [[ "$IS_ARGO" = 'is_argo' && "$NONINTERACTIVE_INSTALL" = 'noninteractive_install' ]]; then
NEKOBOX_SUBSCRIBE+=" THRONE_SUBSCRIBE+="
---------------------------- ----------------------------
vmess://$(echo -n "{\"add\":\"${CDN[17]}\",\"aid\":\"0\",\"host\":\"$ARGO_DOMAIN\",\"id\":\"${UUID[17]}\",\"net\":\"ws\",\"path\":\"/$VMESS_WS_PATH\",\"port\":\"80\",\"ps\":\"${NODE_NAME[17]} ${NODE_TAG[6]}\",\"scy\":\"auto\",\"sni\":\"\",\"tls\":\"\",\"type\":\"\",\"v\":\"2\"}" | base64 -w0)" vmess://$(echo -n "{\"add\":\"${CDN[17]}\",\"aid\":\"0\",\"host\":\"$ARGO_DOMAIN\",\"id\":\"${UUID[17]}\",\"net\":\"ws\",\"path\":\"/$VMESS_WS_PATH\",\"port\":\"80\",\"ps\":\"${NODE_NAME[17]} ${NODE_TAG[6]}\",\"scy\":\"auto\",\"sni\":\"\",\"tls\":\"\",\"type\":\"\",\"v\":\"2\"}" | base64 -w0)"
[ "$ARGO_TYPE" = 'is_token_argo' ] && NEKOBOX_SUBSCRIBE+=" [ "$ARGO_TYPE" = 'is_token_argo' ] && THRONE_SUBSCRIBE+="
# $(text 94) # $(text 94)
" "
else else
WS_SERVER_IP_SHOW=${WS_SERVER_IP[17]} && TYPE_HOST_DOMAIN=$VMESS_HOST_DOMAIN && TYPE_PORT_WS=$PORT_VMESS_WS && local NEKOBOX_SUBSCRIBE+=" WS_SERVER_IP_SHOW=${WS_SERVER_IP[17]} && TYPE_HOST_DOMAIN=$VMESS_HOST_DOMAIN && TYPE_PORT_WS=$PORT_VMESS_WS && local THRONE_SUBSCRIBE+="
---------------------------- ----------------------------
vmess://$(echo -n "{\"add\":\"${CDN[17]}\",\"aid\":\"0\",\"host\":\"$VMESS_HOST_DOMAIN\",\"id\":\"${UUID[17]}\",\"net\":\"ws\",\"path\":\"/$VMESS_WS_PATH\",\"port\":\"80\",\"ps\":\"${NODE_NAME[17]} ${NODE_TAG[6]}\",\"scy\":\"auto\",\"sni\":\"\",\"tls\":\"\",\"type\":\"\",\"v\":\"2\"}" | base64 -w0) vmess://$(echo -n "{\"add\":\"${CDN[17]}\",\"aid\":\"0\",\"host\":\"$VMESS_HOST_DOMAIN\",\"id\":\"${UUID[17]}\",\"net\":\"ws\",\"path\":\"/$VMESS_WS_PATH\",\"port\":\"80\",\"ps\":\"${NODE_NAME[17]} ${NODE_TAG[6]}\",\"scy\":\"auto\",\"sni\":\"\",\"tls\":\"\",\"type\":\"\",\"v\":\"2\"}" | base64 -w0)
@@ -4009,15 +4116,15 @@ vmess://$(echo -n "{\"add\":\"${CDN[17]}\",\"aid\":\"0\",\"host\":\"$VMESS_HOST_
if [ -n "$PORT_VLESS_WS" ]; then if [ -n "$PORT_VLESS_WS" ]; then
if [[ "${STATUS[1]}" =~ $(text 27)|$(text 28) ]] || [[ "$IS_ARGO" = 'is_argo' && "$NONINTERACTIVE_INSTALL" = 'noninteractive_install' ]]; then if [[ "${STATUS[1]}" =~ $(text 27)|$(text 28) ]] || [[ "$IS_ARGO" = 'is_argo' && "$NONINTERACTIVE_INSTALL" = 'noninteractive_install' ]]; then
local NEKOBOX_SUBSCRIBE+=" local THRONE_SUBSCRIBE+="
---------------------------- ----------------------------
vless://${UUID[18]}@${CDN[18]}:443?security=tls&sni=$ARGO_DOMAIN&type=ws&path=/$VLESS_WS_PATH?ed%3D2560&host=$ARGO_DOMAIN&encryption=zero#${NODE_NAME[18]// /%20}%20${NODE_TAG[7]}" vless://${UUID[18]}@${CDN[18]}:443?security=tls&sni=$ARGO_DOMAIN&type=ws&path=/$VLESS_WS_PATH?ed%3D2560&host=$ARGO_DOMAIN&encryption=zero#${NODE_NAME[18]// /%20}%20${NODE_TAG[7]}"
[ "$ARGO_TYPE" = 'is_token_argo' ] && NEKOBOX_SUBSCRIBE+=" [ "$ARGO_TYPE" = 'is_token_argo' ] && THRONE_SUBSCRIBE+="
# $(text 94) # $(text 94)
" "
else else
WS_SERVER_IP_SHOW=${WS_SERVER_IP[18]} && TYPE_HOST_DOMAIN=$VLESS_HOST_DOMAIN && TYPE_PORT_WS=$PORT_VLESS_WS && local NEKOBOX_SUBSCRIBE+=" WS_SERVER_IP_SHOW=${WS_SERVER_IP[18]} && TYPE_HOST_DOMAIN=$VLESS_HOST_DOMAIN && TYPE_PORT_WS=$PORT_VLESS_WS && local THRONE_SUBSCRIBE+="
---------------------------- ----------------------------
vless://${UUID[18]}@${CDN[18]}:443?security=tls&sni=$VLESS_HOST_DOMAIN&type=ws&path=/$VLESS_WS_PATH?ed%3D2560&host=$VLESS_HOST_DOMAIN&encryption=zero#${NODE_NAME[18]// /%20}%20${NODE_TAG[7]} vless://${UUID[18]}@${CDN[18]}:443?security=tls&sni=$VLESS_HOST_DOMAIN&type=ws&path=/$VLESS_WS_PATH?ed%3D2560&host=$VLESS_HOST_DOMAIN&encryption=zero#${NODE_NAME[18]// /%20}%20${NODE_TAG[7]}
@@ -4025,19 +4132,27 @@ vless://${UUID[18]}@${CDN[18]}:443?security=tls&sni=$VLESS_HOST_DOMAIN&type=ws&p
fi fi
fi fi
[ -n "$PORT_H2_REALITY" ] && local NEKOBOX_SUBSCRIBE+=" [ -n "$PORT_H2_REALITY" ] && local THRONE_SUBSCRIBE+="
---------------------------- ----------------------------
vless://${UUID[19]}@${SERVER_IP_1}:${PORT_H2_REALITY}?security=reality&sni=${TLS_SERVER}&alpn=h2&fp=firefox&pbk=${REALITY_PUBLIC[19]// /%20}&type=http&encryption=none#${NODE_NAME[19]// /%20}%20${NODE_TAG[8]}" vless://${UUID[19]}@${SERVER_IP_1}:${PORT_H2_REALITY}?security=reality&sni=${TLS_SERVER}&alpn=h2&fp=firefox&pbk=${REALITY_PUBLIC[19]// /%20}&type=http&encryption=none#${NODE_NAME[19]// /%20}%20${NODE_TAG[8]}"
[ -n "$PORT_GRPC_REALITY" ] && local NEKOBOX_SUBSCRIBE+=" [ -n "$PORT_GRPC_REALITY" ] && local THRONE_SUBSCRIBE+="
---------------------------- ----------------------------
vless://${UUID[20]}@${SERVER_IP_1}:${PORT_GRPC_REALITY}?security=reality&sni=${TLS_SERVER}&fp=firefox&pbk=${REALITY_PUBLIC[20]// /%20}&type=grpc&serviceName=grpc&encryption=none#${NODE_NAME[20]// /%20}%20${NODE_TAG[9]}" vless://${UUID[20]}@${SERVER_IP_1}:${PORT_GRPC_REALITY}?security=reality&sni=${TLS_SERVER}&fp=firefox&pbk=${REALITY_PUBLIC[20]// /%20}&type=grpc&serviceName=grpc&encryption=none#${NODE_NAME[20]// /%20}%20${NODE_TAG[9]}"
[ -n "$PORT_ANYTLS" ] && local NEKOBOX_SUBSCRIBE+=" [ -n "$PORT_ANYTLS" ] && local THRONE_SUBSCRIBE+="
---------------------------- ----------------------------
anytls://${UUID[21]}@${SERVER_IP_1}:${PORT_ANYTLS}?security=tls&sni=${TLS_SERVER}&insecure=1&fp=firefox#${NODE_NAME[21]// /%20}%20${NODE_TAG[10]}" anytls://${UUID[21]}@${SERVER_IP_1}:${PORT_ANYTLS}?idle_session_check_interval=30s&idle_session_timeout=30s&min_idle_session=5&insecure=1&security=tls&sni=${TLS_SERVER}&tls_certificate=${CERT_URL}&fp=firefox#${NODE_NAME[21]// /%20}%20${NODE_TAG[10]}"
echo -n "$NEKOBOX_SUBSCRIBE" | sed -E '/^[ ]*#|^--/d' | sed '/^$/d' | base64 -w0 > ${WORK_DIR}/subscribe/neko [ -n "$PORT_NAIVE" ] && {
local THRONE_SUBSCRIBE+="
----------------------------
naive+https://${UUID[22]}:${UUID[22]}@${SERVER_IP_1}:${PORT_NAIVE}?uot=1&security=tls&sni=${TLS_SERVER}&tls_certificate=${CERT_200_URL}#${NODE_NAME[22]// /%20}%20${NODE_TAG[11]}%20http2
----------------------------
naive+quic://${UUID[22]}:${UUID[22]}@${SERVER_IP_1}:${PORT_NAIVE}?congestion_control=bbr&security=tls&sni=${TLS_SERVER}&tls_certificate=${CERT_200_URL}#${NODE_NAME[22]// /%20}%20${NODE_TAG[11]}%20quic"
}
echo -n "$THRONE_SUBSCRIBE" | sed -E '/^[ ]*#|^--/d' | sed '/^$/d' | base64 -w0 > ${WORK_DIR}/subscribe/neko
# 生成 Sing-box 订阅文件 # 生成 Sing-box 订阅文件
[ -n "$PORT_XTLS_REALITY" ] && [ -n "$PORT_XTLS_REALITY" ] &&
@@ -4117,10 +4232,15 @@ anytls://${UUID[21]}@${SERVER_IP_1}:${PORT_ANYTLS}?security=tls&sni=${TLS_SERVER
local OUTBOUND_REPLACE+=" { \"type\": \"anytls\", \"tag\": \"${NODE_NAME[21]} ${NODE_TAG[10]}\", \"server\": \"${SERVER_IP}\", \"server_port\": ${PORT_ANYTLS}, \"password\": \"${UUID[21]}\", \"idle_session_check_interval\": \"30s\", \"idle_session_timeout\": \"30s\", \"min_idle_session\": 5, \"tls\": { \"enabled\": true, \"certificate_public_key_sha256\": [\"$SELF_SIGNED_FINGERPRINT_BASE64\"], \"server_name\": \"${TLS_SERVER}\", \"utls\": { \"enabled\": true, \"fingerprint\": \"firefox\" } } }," && local OUTBOUND_REPLACE+=" { \"type\": \"anytls\", \"tag\": \"${NODE_NAME[21]} ${NODE_TAG[10]}\", \"server\": \"${SERVER_IP}\", \"server_port\": ${PORT_ANYTLS}, \"password\": \"${UUID[21]}\", \"idle_session_check_interval\": \"30s\", \"idle_session_timeout\": \"30s\", \"min_idle_session\": 5, \"tls\": { \"enabled\": true, \"certificate_public_key_sha256\": [\"$SELF_SIGNED_FINGERPRINT_BASE64\"], \"server_name\": \"${TLS_SERVER}\", \"utls\": { \"enabled\": true, \"fingerprint\": \"firefox\" } } }," &&
local NODE_REPLACE+="\"${NODE_NAME[21]} ${NODE_TAG[10]}\"," local NODE_REPLACE+="\"${NODE_NAME[21]} ${NODE_TAG[10]}\","
[ -n "$PORT_NAIVE" ] &&
local OUTBOUND_REPLACE+=" { \"type\": \"naive\", \"tag\": \"${NODE_NAME[22]} ${NODE_TAG[11]} http2\", \"server\": \"${SERVER_IP}\", \"server_port\": ${PORT_NAIVE}, \"username\": \"${UUID[22]}\", \"password\": \"${UUID[22]}\", \"udp_over_tcp\": true, \"quic\": false, \"tls\": { \"enabled\": true, \"certificate\": [$(tr -d '\n' <<< "$CERT200_JSON")], \"server_name\": \"${TLS_SERVER}\" } }, { \"type\": \"naive\", \"tag\": \"${NODE_NAME[22]} ${NODE_TAG[11]} quic\", \"server\": \"${SERVER_IP}\", \"server_port\": ${PORT_NAIVE}, \"username\": \"${UUID[22]}\", \"password\": \"${UUID[22]}\", \"udp_over_tcp\": false, \"quic\": true, \"quic_congestion_control\": \"bbr\", \"tls\": { \"enabled\": true, \"certificate\": [$(tr -d '\n' <<< "$CERT200_JSON")], \"server_name\": \"${TLS_SERVER}\" } }," &&
local NODE_REPLACE+="\"${NODE_NAME[22]} ${NODE_TAG[11]} http2\",\"${NODE_NAME[22]} ${NODE_TAG[11]} quic\","
{ {
# 生成 sing-box SFM SFA SFI 订阅文件 # 生成 sing-box SFM SFA SFI 订阅文件
cat $TEMP_DIR/sing-box | sed "s#\"<OUTBOUND_REPLACE>\",#$OUTBOUND_REPLACE#; s#\"<NODE_REPLACE>\"#${NODE_REPLACE%,}#g" | ${WORK_DIR}/jq > ${WORK_DIR}/subscribe/sing-box [ ! -s "$TEMP_DIR/sing-box-template" ] && wget --no-check-certificate --continue -qO "$TEMP_DIR/sing-box-template" "${GH_PROXY}${SUBSCRIBE_TEMPLATE}/sing-box" 2>/dev/null
rm -f $TEMP_DIR/sing-box cat $TEMP_DIR/sing-box-template | sed "s#\"<OUTBOUND_REPLACE>\",#$OUTBOUND_REPLACE#; s#\"<NODE_REPLACE>\"#${NODE_REPLACE%,}#g" | ${WORK_DIR}/jq > ${WORK_DIR}/subscribe/sing-box
rm -f $TEMP_DIR/sing-box-template
} &>/dev/null } &>/dev/null
# 生成二维码 url 文件 # 生成二维码 url 文件
@@ -4177,10 +4297,10 @@ $(info "$(sed '1d' <<< "${CLASH_SUBSCRIBE}")")
******************************************* *******************************************
┌────────────────┐ ┌────────────────┐
│ │ │ │
$(warning "NekoBox") $(warning "Throne")
│ │ │ │
└────────────────┘ └────────────────┘
$(hint "${NEKOBOX_SUBSCRIBE}") $(hint "${THRONE_SUBSCRIBE}")
******************************************* *******************************************
┌────────────────┐ ┌────────────────┐
@@ -4210,7 +4330,7 @@ $SUBSCRIBE_ADDRESS/${UUID_CONFIRM}/qr
V2rayN $(text 80): V2rayN $(text 80):
$SUBSCRIBE_ADDRESS/${UUID_CONFIRM}/v2rayn") $SUBSCRIBE_ADDRESS/${UUID_CONFIRM}/v2rayn")
$(hint "NekoBox $(text 80): $(hint "Throne $(text 80):
$SUBSCRIBE_ADDRESS/${UUID_CONFIRM}/neko") $SUBSCRIBE_ADDRESS/${UUID_CONFIRM}/neko")
$(hint "Clash $(text 80): $(hint "Clash $(text 80):
@@ -4602,6 +4722,15 @@ change_protocols() {
unset PORT_ANYTLS unset PORT_ANYTLS
fi fi
# 获取 naive 端口
CHECK_PROTOCOLS=$(asc "$CHECK_PROTOCOLS" ++)
if [[ "${INSTALL_PROTOCOLS[@]}" =~ "$CHECK_PROTOCOLS" ]]; then
POSITION=$(awk -v target=$CHECK_PROTOCOLS '{ for(i=1; i<=NF; i++) if($i == target) { print i-1; break } }' <<< "${INSTALL_PROTOCOLS[*]}")
PORT_NAIVE=${REINSTALL_PORTS[POSITION]}
else
unset PORT_NAIVE
fi
# 停止 sing-box 服务 # 停止 sing-box 服务
cmd_systemctl disable sing-box cmd_systemctl disable sing-box