From tunpilot
Runs SSH diagnostics on proxy nodes: IPQuality for reputation (risk scores, blacklists, streaming unlock) and NetQuality for network performance (latency, speed, BGP, routing). Generates JSON health reports.
npx claudepluginhub buywatermelon/tunpilot --plugin tunpilotThis skill uses the workspace's default tool permissions.
Run dual-dimension diagnostics on proxy nodes via direct SSH from the local machine: [IPQuality](https://github.com/xykt/IPQuality) for IP reputation (risk scores, streaming unlock, blacklists) and [NetQuality](https://github.com/xykt/NetQuality) for network performance (BGP, latency, speed, routing). Both tools require zero API keys.
Deploys production Hysteria2 proxy nodes on Linux servers via SSH: probes capabilities, tunes performance/security, configures TLS, registers in TunPilot.
Runs ZDX deep trace diagnostics sessions to investigate network and device issues. Analyzes web probe metrics, cloud path topology, device health, top processes, and event timelines to pinpoint root causes.
Guides nmap-based network reconnaissance: fast full-port SYN scans, service/version detection, NSE scripts, and output parsing. Use for enumerating services and detecting vulnerabilities.
Share bugs, ideas, or general feedback.
Run dual-dimension diagnostics on proxy nodes via direct SSH from the local machine: IPQuality for IP reputation (risk scores, streaming unlock, blacklists) and NetQuality for network performance (BGP, latency, speed, routing). Both tools require zero API keys.
Prerequisites:
ssh_user or ssh_alias configured (and SSH key access from the local machine)tunpilot-diag wrapper installed on the node (auto-installed in Phase 2.0 if missing)jq curl bc netcat-openbsd dnsutils iproute2iperf3 mtr (plus speedtest, nexttrace auto-installed by the script with -y flag)Ask the user which node(s) to test. Use tunpilot node list to show available nodes if needed.
Accept:
ssh_user or ssh_alias configuredFor each target node, get ssh_alias, ssh_user, host, and ssh_port from the tunpilot node list result.
Resolve SSH target (use throughout this phase):
ssh_alias is set → use ssh <ssh_alias> (e.g., ssh bwg)ssh -p <ssh_port> <ssh_user>@<host>All SSH commands below use <ssh_target> as shorthand for the resolved target.
Verify tunpilot-diag is installed on each target node:
ssh <ssh_target> "tunpilot-diag --version"
If the command fails (not found), install it:
ssh <ssh_target> bash <<'INSTALL'
curl -fsSL https://raw.githubusercontent.com/Buywatermelon/tunpilot/main/scripts/tunpilot-diag.sh \
-o /usr/local/bin/tunpilot-diag
chmod +x /usr/local/bin/tunpilot-diag
tunpilot-diag --version
INSTALL
Also ensure diagnostic dependencies are installed:
ssh <ssh_target> "apt-get update -qq && apt-get install -y -qq jq curl bc netcat-openbsd dnsutils iproute2 iperf3 mtr"
tunpilot-diag supports subcommands:
tunpilot-diag all — full suite: IPQuality + NetQuality (~5-7 min) (default)tunpilot-diag ip — IP reputation only (~2-3 min)tunpilot-diag net — network performance only (~3-5 min)Run the full diagnostics suite (IPQuality + NetQuality):
ssh <ssh_target> "tunpilot-diag"
Output is two JSON lines on stdout:
{"type":"ipquality","data":{...}} — use the data field for report rendering{"type":"netquality","data":{...}} — use the data field for report renderingIf a check fails, the line will contain "error" instead of "data".
Single node: Use run_in_background so the agent is not blocked while diagnostics run. Tell the user diagnostics are running (~5-7 min). The agent will be automatically notified when the command completes.
Multiple nodes: Launch each node's diagnostics in parallel using separate run_in_background Bash calls. Each node runs independently via separate SSH sessions.
If the wrapper cannot be installed (e.g., permission issues, no curl), fall back to raw script execution with output filtering:
ssh <ssh_target> "export TERM=dumb; bash <(curl -sL IP.Check.Place) -j -4" 2>&1 \
| sed 's/\x1b\[[0-9;]*m//g' > /tmp/ipquality-<node>.txt
Then extract JSON from the raw output using Python:
python3 -c "
import json, sys
content = open('/tmp/ipquality-<node>.txt').read()
depth, start = 0, -1
for i, c in enumerate(content):
if c == '{' and start == -1: start, depth = i, 1
elif start >= 0:
depth += (c == '{') - (c == '}')
if depth == 0:
data = json.loads(content[start:i+1])
if 'Head' in data or 'Info' in data:
print(json.dumps(data)); break
start = -1
"
Repeat for NetQuality with Net.Check.Place and -j -4 -y flags.
For each node, present results in two sections: IP Quality first, then Network Quality.
| Item | Value |
|---|---|
| IP | {Head.IP} |
| Location | {Info.City.Name}, {Info.City.Subdivisions}, {Info.Region.Name} |
| ASN | AS{Info.ASN} — {Info.Organization} |
| IP Type | {Info.Type} (see classification guide below) |
| Timezone | {Info.TimeZone} |
Present what all 5 databases say about this IP's usage type:
| Database | Usage | Company |
|---|---|---|
| IPinfo | {Type.Usage.IPinfo} | {Type.Company.IPinfo} |
| ipregistry | {Type.Usage.ipregistry} | {Type.Company.ipregistry} |
| ipapi | {Type.Usage.ipapi} | {Type.Company.ipapi} |
| AbuseIPDB | {Type.Usage.AbuseIPDB} | — |
| IP2LOCATION | {Type.Usage.IP2LOCATION} | — |
Classification Guide:
| Chinese Label | English | Meaning | Quality Impact |
|---|---|---|---|
| 家宽 | Residential | ISP consumer line | Best — lowest detection risk, ideal for streaming and general use |
| 商业 | Business | Commercial/enterprise line | Good — some services may have minor restrictions |
| 机房 | Datacenter/Hosting | Server/cloud provider | Poor — most IP databases flag datacenter IPs, streaming services likely restrict |
| 教育 | Education | University/school network | Variable — depends on specific institution |
IP Type Guide:
| Chinese Label | English | Meaning |
|---|---|---|
| 原生IP | Native IP | IP registered to the local ISP in the server's country. Best for geo-restricted services |
| 广播IP | Broadcast/Anycast IP | IP announced via BGP from a different region than registration. May trigger geo-mismatch flags |
Consensus Analysis:
| Database | Score | Rating |
|---|---|---|
| IP2LOCATION | {Score.IP2LOCATION} | {rating} |
| SCAMALYTICS | {Score.SCAMALYTICS} | {rating} |
| ipapi | {Score.ipapi} | {rating} |
| AbuseIPDB | {Score.AbuseIPDB} | {rating} |
| IPQS | {Score.IPQS} | {rating} |
| DBIP | {Score.DBIP} | {rating} |
Score Interpretation Guide:
| Database | Low Risk | Medium Risk | High Risk | Notes |
|---|---|---|---|---|
| IP2LOCATION | 0-20 | 20-80 | 80-100 | Proxy score. Datacenter IPs often score 99 regardless of actual abuse |
| SCAMALYTICS | 0-20 | 20-50 | 50+ | Fraud score. Very sensitive to datacenter classification |
| ipapi | <1% | 1-10% | 10%+ | Threat percentage. Most clean IPs show <1% |
| AbuseIPDB | 0-10 | 10-50 | 50+ | Confidence of abuse. Based on user reports |
| IPQS | 0-30 | 30-75 | 75+ | Fraud score. "null" means API unreachable, not a risk indicator |
| DBIP | 0 | — | 1+ | Binary. 0 = clean, any positive value = flagged |
| Factor | Flagged By | Count |
|---|---|---|
| Proxy | {list providers where true, or "None"} | {N}/9 |
| VPN | {list providers where true, or "None"} | {N}/9 |
| Tor | {list providers where true, or "None"} | {N}/9 |
| Server/DC | {list providers where true, or "None"} | {N}/9 |
| Abuser | {list providers where true, or "None"} | {N}/9 |
| Robot | {list providers where true, or "None"} | {N}/9 |
Detection Pattern Analysis:
| Detection Count | Assessment | Impact |
|---|---|---|
| 0/9 flagged | Clean IP, excellent quality | No restrictions expected |
| 1-2/9 flagged | Borderline, likely false positive | Usually fine, most services won't block |
| 3-5/9 flagged | Moderate risk | Some services will flag or restrict, streaming may be limited |
| 6+/9 flagged | High risk | Most services will detect and restrict this IP |
| Service | Status | Region | Type |
|---|---|---|---|
| TikTok | {Media.TikTok.Status} | {Region} | {Type} |
| Disney+ | {Media.DisneyPlus.Status} | {Region} | {Type} |
| Netflix | {Media.Netflix.Status} | {Region} | {Type} |
| YouTube | {Media.Youtube.Status} | {Region} | {Type} |
| Amazon Prime | {Media.AmazonPrimeVideo.Status} | {Region} | {Type} |
| {Media.Reddit.Status} | {Region} | {Type} | |
| ChatGPT | {Media.ChatGPT.Status} | {Region} | {Type} |
Status meanings:
| Item | Status |
|---|---|
| Port 25 (SMTP) | {open/closed} |
| DNS Blacklist | {Clean}/{Total} clean, {Marked} marked, {Blacklisted} blacklisted |
Major mail providers:
| Provider | Reachable |
|---|---|
| Gmail | {yes/no} |
| Outlook | {yes/no} |
| Yahoo | {yes/no} |
| Apple | {yes/no} |
| {yes/no} | |
| 163 | {yes/no} |
| Item | Value |
|---|---|
| ASN | AS{BGP.ASN} — {BGP.Organization} |
| Prefix | {BGP.Prefix} ({BGP.IPinTotal} IPs total, {BGP.IPActive} active) |
| RIR | {BGP.RIR} |
| Country | {BGP.Country} |
| Registered | {BGP.RegDate} |
| Upstreams | {BGP.UpstreamsCount} |
| Peers | {BGP.PeersCount} |
| IX Count | {BGP.IXCount} |
| Item | Value |
|---|---|
| NAT Type | {Local.NAT} — {Local.NATDescribe} |
| Mapping | {Local.Mapping} |
| Filter | {Local.Filter} |
| TCP Congestion Control | {Local.TCPCongestionControl} |
| Queue Discipline | {Local.QueueDiscipline} |
NAT Type Interpretation:
| NAT Type | Chinese | Impact |
|---|---|---|
| Full Cone | 全锥形 | Best — ideal for P2P, gaming, and VoIP |
| Restricted Cone | 受限锥形 | Good — works for most applications |
| Port Restricted Cone | 端口受限锥形 | OK — some P2P may have issues |
| Symmetric | 对称型 | Worst — problematic for P2P and gaming, NAT traversal difficult |
TCP Congestion Control:
| Algorithm | Notes |
|---|---|
bbr | Recommended for proxy servers — best throughput on lossy/long-distance links |
cubic | Linux default — adequate but suboptimal for high-latency proxy use |
hybla | Designed for high-latency satellite links — good alternative for long-distance |
| ASN | Organization | Tier-1 | Upstream |
|---|---|---|---|
| {Connectivity[].ASN} | {Connectivity[].Org} | {IsTier1: Yes/No} | {IsUpstream: Yes/No} |
Highlight entries where IsUpstream is true — these are the node's direct transit providers.
Interpretation: More Tier-1 upstreams = better international connectivity and redundancy. A node with direct Tier-1 upstream (e.g., Cogent AS174, Lumen AS3356, NTT AS2914) typically has lower latency and more stable international routing.
Key Regions Summary (show these first):
| Province | CT (ms) | CU (ms) | CM (ms) |
|---|---|---|---|
| 北京 BJ | {CT.Average} | {CU.Average} | {CM.Average} |
| 上海 SH | {CT.Average} | {CU.Average} | {CM.Average} |
| 广东 GD | {CT.Average} | {CU.Average} | {CM.Average} |
| 浙江 ZJ | {CT.Average} | {CU.Average} | {CM.Average} |
| 江苏 JS | {CT.Average} | {CU.Average} | {CM.Average} |
| 四川 SC | {CT.Average} | {CU.Average} | {CM.Average} |
Latency Rating Guide:
| Range | Rating | User Experience |
|---|---|---|
| <50ms | Excellent | Imperceptible delay |
| 50-100ms | Good | Smooth browsing and video |
| 100-200ms | Fair | Noticeable on interactive apps |
| 200-500ms | Poor | Laggy, affects real-time use |
| >500ms / 0 | Timeout | Route broken or severely congested |
Analysis Instructions:
Full 31-Province Table (present when user asks for detailed view or "show all provinces"):
| Province | CT (ms) | CU (ms) | CM (ms) |
|---|---|---|---|
| {Delay[].Name} | {CT.Average} | {CU.Average} | {CM.Average} |
| ... | ... | ... | ... |
Convert raw values to Mbps if in bytes/s format: value / 1024 / 1024 * 8.
| City | Provider | Upload (Mbps) | Download (Mbps) |
|---|---|---|---|
| {Speedtest[].City} | {Speedtest[].Provider} | {SendSpeed} | {ReceiveSpeed} |
Convert raw values to Mbps if in bytes/s format: value / 1024 / 1024 * 8.
| City | Upload (Mbps) | Download (Mbps) | Send Retransmits | Recv Retransmits | Latency (ms) |
|---|---|---|---|---|---|
| {Transfer[].City} | {SendSpeed} | {ReceiveSpeed} | {SendRetransmits} | {ReceiveRetransmits} | {Delay.Average} |
Speed Rating:
| Speed | Rating |
|---|---|
| >50 Mbps | Excellent |
| 10-50 Mbps | Good |
| 1-10 Mbps | Fair |
| <1 Mbps | Poor |
Retransmit Analysis: High retransmit counts (>10000) indicate a congested or lossy path. This often points to throttling by intermediate ISPs or overloaded peering points.
Present a side-by-side comparison table:
| Item | {node1_name} | {node2_name} | ... |
|---|---|---|---|
| IP | {ip} | {ip} | |
| Location | {city, region} | {city, region} | |
| ASN | {asn} | {asn} | |
| IP Type | {type} | {type} | |
| Usage | {consensus} | {consensus} | |
| IP2LOCATION | {score} | {score} | |
| SCAMALYTICS | {score} | {score} | |
| Proxy Detection | {N}/9 | {N}/9 | |
| VPN Detection | {N}/9 | {N}/9 | |
| Netflix | {status} | {status} | |
| Disney+ | {status} | {status} | |
| YouTube | {status} | {status} | |
| ChatGPT | {status} | {status} | |
| TikTok | {status} | {status} | |
| Port 25 | {open/closed} | {open/closed} | |
| DNS Blacklist | {blacklisted} | {blacklisted} | |
| Best ISP | {CT/CU/CM} | {CT/CU/CM} | |
| Avg Latency (CT) | {ms} | {ms} | |
| Avg Latency (CU) | {ms} | {ms} | |
| Avg Latency (CM) | {ms} | {ms} | |
| HK Speed | {Mbps} | {Mbps} | |
| Tokyo Speed | {Mbps} | {Mbps} | |
| LA Speed | {Mbps} | {Mbps} |
Analyze each node and provide specific, actionable recommendations based on observed patterns. Don't use generic advice — reference actual data from the report.
Identify which pattern(s) apply to each node and explain accordingly:
Pattern: Premium Residential
Pattern: Standard Datacenter
Pattern: High-Quality Datacenter
Pattern: Compromised or Abused IP
Pattern: Port 25 Blocked (Common for Cloud)
Pattern: Premium Network
Pattern: CT-Optimized (CN2/CN2 GIA)
Pattern: CU-Optimized (AS9929/AS4837)
Pattern: CM-Optimized (CMIN2/CMI)
Pattern: Poor Routing
When comparing multiple nodes, explicitly state:
| Symptom | Cause | Fix |
|---|---|---|
SSH command failed (exit 255) | SSH connection refused or auth failed | Verify ssh_alias or ssh_user is correct, SSH key is set up, and the node is reachable. Test manually: ssh <ssh_target> "echo ok" |
SSH command failed (exit 1) with empty output | SSH connected but command failed | Check if bash is available on the node. Try: ssh <ssh_target> "which bash" |
| "Invalid input, script exited" | IPQuality script dependencies missing | Install deps: ssh <ssh_target> "apt-get update -qq && apt-get install -y -qq jq curl bc netcat-openbsd dnsutils iproute2" |
| "No JSON found in output" | Script ran but produced no JSON | Script may have failed silently. Run manually: ssh <ssh_target> "bash <(curl -sL IP.Check.Place) -j -4" and check output |
| IPQuality times out (>120s) | Slow network or DNS issues on node | Check node's internet connectivity: ssh <ssh_target> "curl -sL ifconfig.me". DNS blacklist check is usually the slowest part |
IPQS: null in scores | IPQS API unreachable from node | Not a problem — just means IPQS couldn't be queried. Other 5 score providers still give useful data |
| NetQuality timeout (>10 min) | Full mode too slow for this server | Use ping mode for quick latency check, or low mode to skip speedtest |
| iperf3 errors in NetQuality | iperf3 not installed on the node | Install: ssh <ssh_target> "apt-get update -qq && apt-get install -y -qq iperf3 mtr" |
| "speedtest not found" in NetQuality | speedtest CLI missing | Will be auto-installed on next run (the -y flag enables auto-install). If it persists, install manually: `ssh <ssh_target> "curl -s https://packagecloud.io/install/repositories/ookla/speedtest-cli/script.deb.sh |
| Command | Use When |
|---|---|
tunpilot node list | See all registered nodes and their ssh_alias/ssh_user config |
tunpilot health | Quick health check before running diagnostics |