Skip to content

feat(explain): one-command flow, path check, readable report - #18

Merged
NycolazSec merged 1 commit into
mainfrom
feat/exposure-explain
Oct 10, 2026
Merged

NycolazSec merged 1 commit into
mainfrom
feat/exposure-explain

Conversation

@NycolazSec

Copy link
Copy Markdown
Owner

Summary

Follow-up to #17, from testing tcpcat explain against a real k3s/Docker host:

  • One command: tcpcat explain inventory.json probes the host itself (public address from the inventory; only listening ports, Kubernetes Service and node ports, plus --expect/--ports; slow, with retries). It refuses to run on the host itself. The inventory.json scan.json form still works.
  • Path check: before trusting results it probes control ports where nothing listens. If they answer, something on the path (VPN, hotspot, proxy, antivirus, anti-DDoS) answers for the host, and explain stops, naming the tunnel interface when the route goes through one. Found while testing through a VPN that answered on every port.
  • REFUSED class (listening but refused: REJECT rule, or a Docker port mapping with nothing behind it); a Kubernetes Service mapping a port now takes precedence over a local listener (external traffic is redirected before local delivery); NodePort-specific advice.
  • --expect accepts ranges (25565-25570); -v details expected/local ports.
  • Readable report: sections (to fix / firewall only / refused / public as expected / local folded into one line) and a verdict; inventory grouped the same way. Subcommands print the banner; the scan engine gets a Quiet option.

Checklist

  • I read CONTRIBUTING.md
  • gofmt -l . produces no output
  • go vet ./... passes
  • go test -race ./... passes
  • I added/updated tests for behavioral changes
  • I updated README.md/docs/ for user-facing changes
  • This change preserves the authorized-use guidance in NOTICE.md and does not add functionality whose primary purpose is unauthorized access, disruption, credential theft, persistence, or concealment of unlawful activity

Test plan

  • Unit tests: target selection, port selection, port-list ranges, control-port choice, REFUSED, Kubernetes precedence, NodePort advice.
  • Two-container Linux lab (target + separate scanner): honest path passes and reports EXPOSED / FIREWALL ONLY / LOCAL correctly; with an iptables rule answering every port, the path check fails and explain exits 2.
  • Real k3s + Docker + Pterodactyl host: ports attributed to sshd, mariadbd, docker-proxy containers, Traefik Service; stale Docker mappings reported as REFUSED; VPN interception detected and the tunnel interface named.

`tcpcat explain inventory.json` now probes the host by itself: it takes
the public address from the inventory and probes only the listening
ports, Kubernetes Service and node ports, plus --expect/--ports, slowly
and with retries. It refuses to run on the host itself (loopback path
would bypass the firewall). The scan-report form still works.

Before trusting results it probes control ports where nothing listens;
if they answer, a device on the path (VPN, hotspot, proxy, antivirus,
anti-DDoS) answers for the host and explain stops, naming the tunnel
interface when the route goes through one.

Also:
- REFUSED class: listening but refused (REJECT rule, or a Docker port
  mapping with nothing listening in the container)
- a Kubernetes Service mapping a port takes precedence over a local
  listener; NodePort-specific advice
- --expect accepts ranges (25565-25570); -v details expected/local ports
- sectioned report (to fix / firewall only / refused / public as
  expected / local) with a verdict; inventory grouped the same way
- subcommands print the banner; the scan engine gets a Quiet option
Comment thread cmd/tcpcat/explain.go
// the kernel would route target through, if any. Connecting a UDP socket
// only selects a route; nothing is sent.
func tunnelInterfaceFor(target string) (string, string) {
conn, err := net.Dial("udp", net.JoinHostPort(target, "9"))
@NycolazSec
NycolazSec merged commit cf7e315 into main Oct 10, 2026
3 of 5 checks passed
@github-actions github-actions Bot locked and limited conversation to collaborators Oct 10, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants