185 lines
8.1 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
# test-linux.sh — Linux 服务器全量指纹验证脚本
# 用途:验证所有 TCP/OS 层伪装 + Node.js proxy 状态
# 运行方式sudo bash test-linux.sh
#
# 注意sysctl 和 iptables 检查需要 sudo
set -euo pipefail
GREEN='\033[0;32m' RED='\033[0;31m' YELLOW='\033[1;33m' NC='\033[0m'
ok() { echo -e "${GREEN}$*${NC}"; }
fail() { echo -e "${RED}$*${NC}"; }
info() { echo -e "${YELLOW} $*${NC}"; }
PROXY_PORT="${PROXY_PORT:-3456}"
echo "══════════════════════════════════════════════"
echo " Linux 服务器指纹伪装验证"
echo "══════════════════════════════════════════════"
# ── 1. 时区 ────────────────────────────────────────────────
echo ""
echo "【1】系统时区"
TZ_NOW=$(timedatectl show -p Timezone --value 2>/dev/null || cat /etc/timezone 2>/dev/null || date +%Z)
echo " 当前时区: $TZ_NOW"
echo " 当前时间: $(date)"
if [[ "$TZ_NOW" == "America/New_York" ]]; then
ok "时区正确America/New_York"
else
fail "时区错误(应为 America/New_York当前: $TZ_NOW"
info "修复: sudo timedatectl set-timezone America/New_York"
fi
# ── 2. TCP 时间戳 ──────────────────────────────────────────
echo ""
echo "【2】TCP 时间戳(防 uptime 推算)"
TS=$(sysctl -n net.ipv4.tcp_timestamps 2>/dev/null || echo "unknown")
echo " net.ipv4.tcp_timestamps = $TS"
if [[ "$TS" == "0" ]]; then
ok "TCP 时间戳已禁用"
else
fail "TCP 时间戳未禁用(当前: $TS,应为 0"
info "修复: sudo sysctl -w net.ipv4.tcp_timestamps=0"
fi
# ── 3. TTL ─────────────────────────────────────────────────
echo ""
echo "【3】出站 TTLmacOS 特征)"
TTL=$(sysctl -n net.ipv4.ip_default_ttl 2>/dev/null || echo "unknown")
echo " net.ipv4.ip_default_ttl = $TTL"
if [[ "$TTL" == "64" ]]; then
ok "TTL=64macOS/Linux 标准值)"
else
fail "TTL 不为 64当前: $TTL"
fi
# ── 4. TCP Window Size ─────────────────────────────────────
echo ""
echo "【4】TCP Window SizemacOS 特征)"
RMEM=$(sysctl -n net.ipv4.tcp_rmem 2>/dev/null || echo "unknown")
echo " net.ipv4.tcp_rmem = $RMEM"
if [[ "$RMEM" == *"65535"* ]]; then
ok "Window Size 包含 65535macOS 特征)"
else
fail "Window Size 未伪装(应含 65535当前: $RMEM"
info "修复: sudo sysctl -w net.ipv4.tcp_rmem='4096 65535 6291456'"
fi
# ── 5. iptables 规则 ───────────────────────────────────────
echo ""
echo "【5】iptables 指纹防护链"
if iptables -L MG_FINGERPRINT -n 2>/dev/null | grep -q "MG:"; then
ok "MG_FINGERPRINT 链存在"
RULES=$(iptables -L MG_FINGERPRINT -n 2>/dev/null | grep -c "MG:" || echo 0)
echo " 规则数: $RULES"
else
fail "MG_FINGERPRINT 链不存在,运行 setup-firewall.sh apply"
fi
if iptables -t mangle -L MG_FINGERPRINT_TTL -n 2>/dev/null | grep -q "TTL"; then
ok "TTL mangle 链存在"
else
fail "TTL mangle 链不存在"
fi
# ── 6. QUIC 阻断验证 ───────────────────────────────────────
echo ""
echo "【6】QUIC/UDP 阻断"
if iptables -L MG_FINGERPRINT -n 2>/dev/null | grep -q "udp.*443.*DROP"; then
ok "UDP 443 QUIC 已阻断"
else
fail "UDP 443 未阻断"
fi
# ── 7. Node.js 版本 ────────────────────────────────────────
echo ""
echo "【7】Node.js 版本"
if command -v node &>/dev/null; then
NODE_VER=$(node --version)
echo " Node.js: $NODE_VER"
if [[ "$NODE_VER" == v22* ]]; then
ok "Node.js v22.x — 与 Claude CLI 版本匹配"
else
fail "Node.js 不是 v22.x当前: $NODE_VERJA4 指纹可能不匹配"
fi
else
info "Node.js 未在宿主机安装Docker 部署无需宿主机 Node"
fi
# ── 8. node-tls-proxy 健康 ─────────────────────────────────
echo ""
echo "【8】node-tls-proxy 健康(端口 $PROXY_PORT"
if curl -sf "http://127.0.0.1:${PROXY_PORT}/__health" -o /tmp/health.json 2>/dev/null; then
NODE_IN_PROXY=$(python3 -c "import json; d=json.load(open('/tmp/health.json')); print(d.get('node','?'))" 2>/dev/null)
SESSIONS=$(python3 -c "import json; d=json.load(open('/tmp/health.json')); print(d.get('sessions',0))" 2>/dev/null)
H2HOSTS=$(python3 -c "import json; d=json.load(open('/tmp/health.json')); print(','.join(d.get('h2Hosts',[])))" 2>/dev/null)
TELEMETRY=$(python3 -c "import json; d=json.load(open('/tmp/health.json')); print(d.get('telemetry','?'))" 2>/dev/null)
ok "Proxy 运行正常"
echo " Node版本: $NODE_IN_PROXY"
echo " Sessions: $SESSIONS"
echo " H2已建立: ${H2HOSTS:-(无,首次请求后会建立)}"
echo " 遥测: $TELEMETRY"
if [[ "$NODE_IN_PROXY" == v22* ]]; then
ok "Proxy 内置 Node.js v22.x ✅"
else
fail "Proxy 内置 Node 版本: $NODE_IN_PROXY(应为 v22.x"
fi
else
fail "Proxy 未响应(端口 $PROXY_PORT"
info "检查: docker ps | grep node-tls-proxy"
fi
# ── 9. Node.js JA4 指纹(在 proxy 容器内测) ──────────────
echo ""
echo "【9】Node.js JA4 TLS 指纹"
if docker ps --format '{{.Names}}' 2>/dev/null | grep -q "node-tls-proxy"; then
JA4=$(docker exec node-tls-proxy node -e "
const https = require('https');
https.get('https://tls.peet.ws/api/all', res => {
let d=''; res.on('data',c=>d+=c);
res.on('end',()=>{ try{console.log(JSON.parse(d).tls.ja4);}catch(e){console.log('err');} });
}).on('error',e=>console.log('err:'+e.message));
" 2>/dev/null || echo "exec_failed")
echo " Proxy JA4: $JA4"
if [[ "$JA4" == t13* ]]; then
ok "JA4 指纹正常TLS 1.3"
else
fail "JA4 获取失败: $JA4"
fi
elif command -v node &>/dev/null; then
JA4=$(node -e "
const https = require('https');
https.get('https://tls.peet.ws/api/all', res => {
let d=''; res.on('data',c=>d+=c);
res.on('end',()=>{ try{console.log(JSON.parse(d).tls.ja4);}catch(e){console.log('err');} });
}).on('error',e=>console.log('err:'+e.message));
" 2>/dev/null || echo "err")
echo " 宿主机 JA4: $JA4"
[[ "$JA4" == t13* ]] && ok "JA4 正常" || fail "JA4 失败"
else
info "跳过 JA4 测(无 docker exec 也无宿主机 node"
fi
# ── 10. 出口 IP 验证 ───────────────────────────────────────
echo ""
echo "【10】出口 IP 信息"
IP_INFO=$(curl -sf --max-time 5 "https://ipinfo.io/json" 2>/dev/null || echo '{}')
IP=$(echo "$IP_INFO" | python3 -c "import json,sys; d=json.load(sys.stdin); print(d.get('ip','?'))" 2>/dev/null)
ORG=$(echo "$IP_INFO" | python3 -c "import json,sys; d=json.load(sys.stdin); print(d.get('org','?'))" 2>/dev/null)
CITY=$(echo "$IP_INFO" | python3 -c "import json,sys; d=json.load(sys.stdin); print(d.get('city','?')+', '+d.get('region','?'))" 2>/dev/null)
echo " IP: $IP"
echo " ISP: $ORG"
echo " 城市: $CITY"
if echo "$ORG" | grep -qiE "residential|comcast|verizon|optimum|spectrum|altice|fios|att|xfinity"; then
ok "ISP 看起来是住宅宽带 ✅"
elif echo "$ORG" | grep -qiE "datacenter|hosting|cloud|amazon|google|microsoft|linode|vultr|digital"; then
fail "ISP 是数据中心 IP建议换住宅宽带"
else
info "ISP 未能自动判断,请人工核查: $ORG"
fi
echo ""
echo "══════════════════════════════════════════════"
echo " 验证完成"
echo "══════════════════════════════════════════════"