#!/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 接收窗口约 65535(Linux 服务器默认 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