sub2api/antigravity/firewall/setup-firewall.sh
win 324483eabd
Some checks failed
CI / test (push) Failing after 3s
CI / golangci-lint (push) Failing after 4s
Security Scan / backend-security (push) Failing after 6s
Security Scan / frontend-security (push) Failing after 5s
feat: TCP Window Size 伪装 + CLI 版本自动追踪
firewall.sh:
- TCP Window Size 设为 65535(macOS 默认,Linux 服务器默认 29200)
- 持久化到 /etc/sysctl.conf

maintenance/update-cli-version.sh:
- 从 npm registry 获取 @anthropic-ai/claude-code 最新版本
- 自动更新 proxy.js 中的 CLI_VERSION
- 支持 --check(仅检查)/ --force VER(强制指定)
- 建议 cron 每天 03:00 ET 运行
2026-03-25 11:55:24 +08:00

205 lines
8.2 KiB
Bash
Executable File
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/bin/bash
# sub2api Antigravity — 指纹防泄露 + macOS 特征伪装规则
#
# 功能:
# 1. QUIC/UDP 阻断 — 强制走 TCP/TLS
# 2. 出站 TCP 443 限制 — 只有 nodeproxy 用户能直连
# 3. IPv6 阻断 — 消除 IPv6 泄露
# 4. TCP TTL 伪装 — 改为 64匹配 macOS/Linux对抗 OS 识别)
# 5. TCP 时间戳重写 — 禁用内核时间戳,防止通过 TCP TS 推算 uptime/系统时间
# 6. 系统时区设置 — 设为 America/Los_Angeles加州时区匹配目标用户群
#
# 用法:
# sudo bash setup-firewall.sh [apply|remove|status|timezone]
#
# 前置条件:
# - Node.js proxy 以专用用户 "nodeproxy" 运行
# - 创建用户: sudo useradd -r -s /usr/sbin/nologin nodeproxy
set -euo pipefail
NODE_PROXY_USER="${MG_NODE_PROXY_USER:-nodeproxy}"
CHAIN_NAME="MG_FINGERPRINT"
TARGET_TZ="America/New_York"
log() { echo "[$(date '+%H:%M:%S')] $*"; }
# ─── 时区设置 ────────────────────────────────────────────────────────
set_timezone() {
log "Setting system timezone to $TARGET_TZ ..."
if command -v timedatectl &>/dev/null; then
timedatectl set-timezone "$TARGET_TZ"
log " timedatectl: timezone set to $(timedatectl show -p Timezone --value)"
elif [ -f "/usr/share/zoneinfo/$TARGET_TZ" ]; then
ln -sf "/usr/share/zoneinfo/$TARGET_TZ" /etc/localtime
echo "$TARGET_TZ" > /etc/timezone
log " /etc/localtime -> $TARGET_TZ"
else
log " WARNING: Cannot set timezone — timedatectl not found and zoneinfo missing"
fi
}
# ─── TCP 时间戳禁用 ──────────────────────────────────────────────────
# Linux TCP 时间戳会随系统 uptime 线性增长,对方可通过测量 TS 差值
# 推算服务器启动时间,识破"全天候在线的服务器"特征。
# 禁用后 TCP TS 选项不再发送,无法通过 TS 推断 uptime。
disable_tcp_timestamps() {
log "Disabling TCP timestamps (anti-uptime fingerprinting)..."
sysctl -w net.ipv4.tcp_timestamps=0 > /dev/null
# 持久化(防止重启后恢复)
if ! grep -q "net.ipv4.tcp_timestamps" /etc/sysctl.conf 2>/dev/null; then
echo "net.ipv4.tcp_timestamps=0" >> /etc/sysctl.conf
log " Written to /etc/sysctl.conf"
else
sed -i 's/net.ipv4.tcp_timestamps=.*/net.ipv4.tcp_timestamps=0/' /etc/sysctl.conf
log " Updated in /etc/sysctl.conf"
fi
log " TCP timestamps: DISABLED"
}
enable_tcp_timestamps() {
sysctl -w net.ipv4.tcp_timestamps=1 > /dev/null
sed -i 's/net.ipv4.tcp_timestamps=.*/net.ipv4.tcp_timestamps=1/' /etc/sysctl.conf 2>/dev/null || true
log " TCP timestamps: ENABLED (restored)"
}
# ─── iptables 规则 ───────────────────────────────────────────────────
apply_rules() {
log "Applying fingerprint firewall rules..."
# 验证用户存在
if ! id "$NODE_PROXY_USER" &>/dev/null; then
log "ERROR: User '$NODE_PROXY_USER' does not exist."
log "Create it: sudo useradd -r -s /usr/sbin/nologin $NODE_PROXY_USER"
exit 1
fi
# 创建自定义链(幂等)
iptables -N "$CHAIN_NAME" 2>/dev/null || iptables -F "$CHAIN_NAME"
# === Rule 1: QUIC 阻断 ===
iptables -A "$CHAIN_NAME" -p udp --dport 443 -j DROP \
-m comment --comment "MG: block QUIC/HTTP3 UDP 443"
iptables -A "$CHAIN_NAME" -p udp --dport 4433 -j DROP \
-m comment --comment "MG: block QUIC alt UDP 4433"
# === Rule 2: 允许 nodeproxy 出站 TCP 443 ===
iptables -A "$CHAIN_NAME" -p tcp --dport 443 \
-m owner --uid-owner "$NODE_PROXY_USER" -j ACCEPT \
-m comment --comment "MG: allow nodeproxy TCP 443"
# === Rule 3: 阻止其他进程直连 TCP 443 ===
iptables -A "$CHAIN_NAME" -p tcp --dport 443 -j REJECT --reject-with tcp-reset \
-m comment --comment "MG: block non-proxy TCP 443"
# 挂载到 OUTPUT幂等
if ! iptables -C OUTPUT -j "$CHAIN_NAME" 2>/dev/null; then
iptables -A OUTPUT -j "$CHAIN_NAME"
fi
# === Rule 4: IPv6 全面阻断 ===
ip6tables -N "${CHAIN_NAME}_V6" 2>/dev/null || ip6tables -F "${CHAIN_NAME}_V6"
ip6tables -A "${CHAIN_NAME}_V6" -o lo -j ACCEPT \
-m comment --comment "MG: allow IPv6 loopback"
ip6tables -A "${CHAIN_NAME}_V6" -j DROP \
-m comment --comment "MG: block all IPv6 outbound"
if ! ip6tables -C OUTPUT -j "${CHAIN_NAME}_V6" 2>/dev/null; then
ip6tables -A OUTPUT -j "${CHAIN_NAME}_V6"
fi
# === Rule 5: TCP TTL 伪装 (macOS TTL = 64) ===
# macOS 和 Linux 默认 TTL 都是 64但数据中心 Linux 有些发行版是 128。
# 强制设为 64 确保一致,并防止"服务器离对方 0 跳"露馅。
iptables -t mangle -N "${CHAIN_NAME}_TTL" 2>/dev/null || iptables -t mangle -F "${CHAIN_NAME}_TTL"
iptables -t mangle -A "${CHAIN_NAME}_TTL" -p tcp --dport 443 \
-j TTL --ttl-set 64 \
-m comment --comment "MG: spoof TTL=64 (macOS)"
if ! iptables -t mangle -C OUTPUT -j "${CHAIN_NAME}_TTL" 2>/dev/null; then
iptables -t mangle -A OUTPUT -j "${CHAIN_NAME}_TTL"
fi
log "Firewall rules applied successfully."
log " - UDP 443/4433: BLOCKED (QUIC)"
log " - TCP 443: ONLY '$NODE_PROXY_USER' allowed"
log " - IPv6 outbound: BLOCKED"
log " - TCP TTL: FORCED to 64 (macOS spoof)"
# === TCP Window Size 伪装 (macOS 特征) ===
# macOS 初始 TCP 接收窗口约 65535Linux 服务器默认 29200
# 可被 p0f/Akamai 等工具区分。调整为 macOS 典型值。
log "Spoofing TCP Window Size (macOS: 65535)..."
sysctl -w net.ipv4.tcp_rmem="4096 65535 6291456" > /dev/null
sysctl -w net.ipv4.tcp_wmem="4096 65535 6291456" > /dev/null
# 持久化
for param in "net.ipv4.tcp_rmem=4096 65535 6291456" "net.ipv4.tcp_wmem=4096 65535 6291456"; do
key="${param%%=*}"
if grep -q "$key" /etc/sysctl.conf 2>/dev/null; then
sed -i "s|${key}=.*|${param}|" /etc/sysctl.conf
else
echo "$param" >> /etc/sysctl.conf
fi
done
log " TCP Window Size: SET to 65535 (macOS spoof)"
# === TCP 时间戳禁用 ===
disable_tcp_timestamps
# === 时区设置 ===
set_timezone
log ""
log "=== All anti-fingerprint measures applied ==="
log " OS Fingerprint: TTL=64, Window=65535 (macOS)"
log " TCP Timestamps: Disabled (anti-uptime leak)"
log " Timezone: $TARGET_TZ"
}
remove_rules() {
log "Removing fingerprint firewall rules..."
iptables -D OUTPUT -j "$CHAIN_NAME" 2>/dev/null || true
ip6tables -D OUTPUT -j "${CHAIN_NAME}_V6" 2>/dev/null || true
iptables -t mangle -D OUTPUT -j "${CHAIN_NAME}_TTL" 2>/dev/null || true
iptables -F "$CHAIN_NAME" 2>/dev/null || true
iptables -X "$CHAIN_NAME" 2>/dev/null || true
ip6tables -F "${CHAIN_NAME}_V6" 2>/dev/null || true
ip6tables -X "${CHAIN_NAME}_V6" 2>/dev/null || true
iptables -t mangle -F "${CHAIN_NAME}_TTL" 2>/dev/null || true
iptables -t mangle -X "${CHAIN_NAME}_TTL" 2>/dev/null || true
enable_tcp_timestamps
log "Firewall rules removed."
}
show_status() {
log "=== IPv4 MG_FINGERPRINT chain ==="
iptables -L "$CHAIN_NAME" -n -v 2>/dev/null || echo "(not found)"
echo
log "=== IPv4 mangle TTL chain ==="
iptables -t mangle -L "${CHAIN_NAME}_TTL" -n -v 2>/dev/null || echo "(not found)"
echo
log "=== IPv6 MG_FINGERPRINT_V6 chain ==="
ip6tables -L "${CHAIN_NAME}_V6" -n -v 2>/dev/null || echo "(not found)"
echo
log "=== TCP Timestamps ==="
sysctl net.ipv4.tcp_timestamps
echo
log "=== System Timezone ==="
timedatectl show -p Timezone --value 2>/dev/null || cat /etc/timezone 2>/dev/null || echo "(unknown)"
echo
log "=== Current TTL (outbound) ==="
sysctl net.ipv4.ip_default_ttl
}
case "${1:-apply}" in
apply) apply_rules ;;
remove) remove_rules ;;
status) show_status ;;
timezone) set_timezone ;;
*)
echo "Usage: $0 [apply|remove|status|timezone]"
exit 1
;;
esac