Skip to content
KitploitKITPLOIT
ToolsExploitsBlog
Log in
Submit
ToolsExploitsBlog
Submit

Hacking, PenTest, and Cybersecurity Tools for Your Security Arsenal!

Kitploit is a directory of hacking, cybersecurity, and pentesting tools. Discover the latest project updates to find vulnerabilities, analyze systems, automate testing, and strengthen your security.

FeedsContactPrivacy© 2026 Kitploit

Tool Directory

Categories

View all categories
Loading categories
portclue — Explain why a Linux TCP port may or may not be reachable | Kitploit
Tools/GitHubGitHub/pbxqdown/portclue
Defensive ToolsContainer SecurityConfiguration AuditingInformation GatheringNetwork SecurityUtilities & Frameworks
GitHubpbxqdown/portclue

portclue

Explain why a Linux TCP port may or may not be reachable

View Repository
3287 days agoNot yet reviewed

Most Popular

View all →

Discover the most used tools by our community.

Explore all tools

Browse our collection of tools

View all tools →
Website
Share

PortClue

CI Release License Go

PortClue explains why a TCP port on a Linux machine may or may not be reachable. It turns socket, process, firewall, and Docker state into a short evidence chain instead of making you correlate ss, /proc, nftables, iptables, and docker inspect by hand.

PortClue demo: an overview of local TCP listeners, then the evidence chain for port 8080

Run it without a port to discover which local TCP endpoints deserve attention:

$ sudo portclue
LOCAL TCP LISTENERS

PORT    SERVICE                   CONFIDENCE BIND            OWNER       SOURCE BIND SCOPE
22      OpenSSH server            HIGH       0.0.0.0,::      ssh.service host   ALL_INTERFACES
8080    NGINX web server          HIGH       0.0.0.0,::      nginx       host   ALL_INTERFACES
8443    api service               MEDIUM     192.0.2.10      demo-api    docker SPECIFIC_INTERFACE
9000    Python HTTP server        MEDIUM     127.0.0.1       python3     host   LOOPBACK_ONLY

BIND SCOPE describes socket binding, not firewall reachability.
Run `portclue PORT` for the complete evidence chain and local exposure verdict.

ALL_INTERFACES, SPECIFIC_INTERFACE, and LOOPBACK_ONLY describe where a socket accepts traffic. They deliberately do not claim that a firewall permits it. Inspect a port for the full local firewall analysis:

$ sudo portclue 8080
POTENTIAL EXTERNAL EXPOSURE

TCP port 8080

  0.0.0.0:8080/tcp  [POTENTIAL]
    Service            NGINX web server
    Category           web
    Confidence         HIGH
    Identity evidence  executable basename matched "nginx"
    -> LISTEN             NETLINK_INET_DIAG reports socket inode 123456 bound to 0.0.0.0:8080/tcp
    -> OWNED              PID 4242 (nginx), systemd unit nginx.service
    -> ALL_INTERFACES     0.0.0.0 accepts traffic addressed to any local interface
    -> ACCEPT             nftables: a direct rule matches TCP destination port 8080 and returns accept

Unknown outside this machine:
  - router port forwarding
  - cloud firewall or security group
  - upstream NAT, including carrier-grade NAT

[!IMPORTANT] PortClue v0.1 is an early, conservative Linux prototype. POTENTIAL means the observed local path allows traffic; it does not claim that a port is reachable from the public internet. Unsupported firewall expressions produce UNKNOWN.

Why not ss or lsof

  • It does not need them. Listeners come from NETLINK_INET_DIAG, the same kernel interface ss uses, and process details from /proc. Nothing is parsed out of another tool's output, so a container with neither ss nor lsof still gets the listener and its owner. Firewall analysis does run nft or iptables-save, and reports UNKNOWN without them.
  • It answers the next question. ss -ltnp gives you the socket and the PID. Whether that bind is loopback-only, whether a firewall rule allows it, and whether the port is a Docker publish rather than a host listener is work you would otherwise do by hand.
  • It will not guess. A firewall rule PortClue cannot model gives UNKNOWN, never a confident wrong answer.

What it reads

  • TCP listeners through NETLINK_INET_DIAG, not by scraping ss output
  • process ownership, executable, command line, cgroup, and network namespace through /proc
  • systemd unit descriptions from installed unit files and active socket triggers through systemctl show
  • nftables through nft --json list ruleset
  • iptables through iptables-save when nftables is unavailable
  • Docker published ports through the local Docker Engine HTTP API, including image and labels

Service identity

PortClue identifies what a port belongs to before explaining exposure. Evidence is ranked in this order:

  1. observed executable, systemd unit, and active socket trigger;
  2. Docker image, container name, and labels;
  3. the embedded curated service catalog;
  4. the local /etc/services port convention.

An actual owner always overrides a conventional port name. If only the port convention is known, the identity is explicitly marked LOW confidence. The embedded catalog is stored in internal/identify/catalog.json and ships inside the single binary; PortClue does not download identity data at runtime.

PortClue is read-only. It does not connect to the queried port, scan another host, change firewall rules, stop processes or containers, upload data, or run a daemon.

Install

Install script (recommended)

Runs on Linux (amd64 and arm64). The script downloads the matching GitHub Release archive, verifies SHA256SUMS, and installs a single binary. It does not modify shell config.

User install (default, no root). Installs to ~/.local/bin, owned by you:

curl -fsSL https://raw.githubusercontent.com/pbxqdown/portclue/v0.1.2/scripts/install.sh | sh
portclue

A user install runs without root and reports the evidence available to your account, noting what is missing. This is enough to explore listeners and Docker mappings. Because sudo does not search ~/.local/bin and this binary is writable by your user, do not run this copy with sudo.

System install (root-owned, for sudo portclue). PortClue reads the most complete evidence (restricted /proc, full firewall state) as root. For that, install a root-owned binary into /usr/local/bin (the script uses sudo only for the final install step, not for downloading or extracting):

curl -fsSL https://raw.githubusercontent.com/pbxqdown/portclue/v0.1.2/scripts/install.sh | sh -s -- --system
sudo portclue

Optional overrides: PORTCLUE_VERSION=0.1.2 (no leading v) and PORTCLUE_INSTALL_DIR for either mode.

Uninstall:

# user install
rm ~/.local/bin/portclue
# system install
sudo rm /usr/local/bin/portclue
# or, matching how you installed:
curl -fsSL https://raw.githubusercontent.com/pbxqdown/portclue/v0.1.2/scripts/install.sh | sh -s -- --uninstall
curl -fsSL https://raw.githubusercontent.com/pbxqdown/portclue/v0.1.2/scripts/install.sh | sh -s -- --system --uninstall

Release archive

Download the matching portclue-VERSION-linux-ARCH.tar.gz and SHA256SUMS from GitHub Releases, verify the checksum, then install:

sha256sum -c SHA256SUMS --ignore-missing
tar -xzf portclue-0.1.2-linux-amd64.tar.gz   # or linux-arm64
sudo install -m 0755 portclue-0.1.2-linux-amd64/portclue /usr/local/bin/portclue
portclue --version

Architecture mapping:

uname -mArchive
x86_64linux-amd64
aarch64, arm64linux-arm64

Each archive includes the binary, README, Apache-2.0 license, and third-party notices.

Go install

Requires Linux and Go 1.25+:

go install github.com/pbxqdown/portclue/cmd/[email protected]

This puts the binary in $(go env GOPATH)/bin. Prefer the checksum-verified release archive or install script when you want reproducible install artifacts.

Build and run from source

Requirements: Linux and Go 1.25 or newer.

go build -o portclue ./cmd/portclue
./portclue
./portclue --json
./portclue 8080
./portclue --json 8080

Overview mode accepts optional filters (ignored fields stay unconstrained):

Download Tool