Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 36 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,29 +4,49 @@

`wiump` is a small app written in Rust to find which process is using a given port. The app scans TCP and UDP ports and returns the process name and PID.

### Installation

#### Precompiled Binaries

Download the latest precompiled binary for your platform from the [releases page](https://github.com/patrickdappollonio/wiump/releases).

#### Homebrew (macOS and Linux)

Simply install the `wiump` formula by tapping my personal tap:

```bash
brew install patrickdappollonio/tap/wiump
```

### Usage

`wiump` will scan all ports and display a table of all the ports and their associated processes. Here's an example of the output:

```bash
$ wiump
PORT UID USER STATUS PROTOCOL PROCESS_NAME LOCAL REMOTE
53 101 systemd-resolve LISTEN TCP systemd-resolve 127.0.0.53:53 0.0.0.0:0
53 unknown unknown LISTEN TCP unknown 10.255.255.254:53 0.0.0.0:0
5000 1000 patrick LISTEN TCP6 http-server :::5000 :::0
35972 1000 patrick ESTABLISHED TCP node 127.0.0.1:35972 127.0.0.1:39945
35976 1000 patrick ESTABLISHED TCP node 127.0.0.1:35976 127.0.0.1:39945
39945 1000 patrick LISTEN TCP node 127.0.0.1:39945 0.0.0.0:0
39945 1000 patrick ESTABLISHED TCP node 127.0.0.1:39945 127.0.0.1:35972
39945 1000 patrick ESTABLISHED TCP node 127.0.0.1:39945 127.0.0.1:35976
PORT PID UID USER STATUS PROTOCOL PROCESS_NAME LOCAL REMOTE
53 101 101 systemd-resolve LISTEN TCP systemd-resolved 127.0.0.53:53 0.0.0.0:0
80 1234 1000 webdev LISTEN TCP nginx 0.0.0.0:80 0.0.0.0:0
443 1234 1000 webdev LISTEN TCP nginx 0.0.0.0:443 0.0.0.0:0
3000 5678 1000 webdev LISTEN TCP node 127.0.0.1:3000 0.0.0.0:0
5432 999 999 postgres LISTEN TCP postgres 127.0.0.1:5432 0.0.0.0:0
8080 9012 1000 webdev LISTEN TCP6 java :::8080 :::0
22 0 0 root LISTEN TCP sshd 0.0.0.0:22 0.0.0.0:0
```

If provided with a port using `-p` or `--port`, it will display information just for that resource. For example, `wiump -p 5000` will show you that my [`http-server`](https://github.com/patrickdappollonio/http-server) is using that port:
If provided with a port using `-p` or `--port`, it will display information just for that resource. For example, `wiump -p 3000` will show you that a `node` process is using that port:

```bash
$ wiump --port 5000
Port 5000/TCP6:
Local Address: :::5000
Remote Address: :::0
$ wiump --port 3000
Port 3000/TCP:
Local Address: 127.0.0.1:3000
Remote Address: 0.0.0.0:0
State: LISTEN
Process: http-server (PID: 7386)
UID: 1000 (User: patrick)
Process: node (PID: 5678)
Command: node server.js
Executable: /usr/bin/node
Working Directory: /home/webdev/myapp
UID: 1000 (User: webdev)
```

Or, for port 53, you'll get the following (note the use of `sudo` to be able to fetch process names from other users):
Expand Down
34 changes: 23 additions & 11 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,10 +72,11 @@ fn get_sockets(sys: &System, addr: AddressFamilyFlags) -> Result<Vec<SocketInfo>
cwd,
}
} else {
let name = "unknown".to_string();
ProcessInfo {
pid,
uid: None,
name: "unknown".to_string(),
name,
cmd: Vec::new(),
exe: PathBuf::new(),
cwd: PathBuf::new(),
Expand Down Expand Up @@ -249,7 +250,12 @@ fn main() -> Result<()> {
println!(" Local Address: {local}");
println!(" Remote Address: {remote}");
println!(" State: {state_str}");
println!(" Process: {proc_name} (PID: {pid})");
let display_name = if pid == 0 && proc_name == "unknown" {
"unknown, likely a \"kernel\" process"
} else {
&proc_name
};
println!(" Process: {display_name} (PID: {pid})");

// Show detailed process information
if !cmd.is_empty() {
Expand All @@ -262,7 +268,12 @@ fn main() -> Result<()> {
println!(" Working Directory: {}", cwd.display());
}

println!(" UID: {uid_str} (User: {user})");
let display_user = if pid == 0 && user == "unknown" {
"unknown, likely \"kernel\""
} else {
&user
};
println!(" UID: {uid_str} (User: {display_user})");
println!();
}
}
Expand All @@ -277,14 +288,14 @@ fn main() -> Result<()> {
// Header with detailed information
writeln!(
tw,
"PORT\tUID\tUSER\tSTATUS\tPROTOCOL\tPROCESS_NAME\tCOMMAND\tLOCAL\tREMOTE"
"PORT\tPID\tUID\tUSER\tSTATUS\tPROTOCOL\tPROCESS_NAME\tCOMMAND\tLOCAL\tREMOTE"
)
.map_err(|e| anyhow::anyhow!("Failed to write to output: {}", e))?;
for s in tcp_sockets {
let proto_str = get_protocol_string(s.family);
let state_str = tcp_state_to_str(&s.state);

let (_pid, proc_name, uid_opt, cmd) = if let Some(proc_info) = s.processes.first() {
let (pid, proc_name, uid_opt, cmd) = if let Some(proc_info) = s.processes.first() {
(
proc_info.pid,
proc_info.name.clone(),
Expand All @@ -304,8 +315,9 @@ fn main() -> Result<()> {

writeln!(
tw,
"{}\t{}\t{}\t{}\t{}\t{}\t{}\t{}\t{}",
"{}\t{}\t{}\t{}\t{}\t{}\t{}\t{}\t{}\t{}",
s.local_port,
pid,
uid_str,
user,
state_str,
Expand All @@ -318,17 +330,17 @@ fn main() -> Result<()> {
.map_err(|e| anyhow::anyhow!("Failed to write to output: {}", e))?;
}
} else {
// Header: PORT, UID, USER, STATUS, PROTOCOL, PROCESS_NAME, LOCAL, REMOTE
// Header: PORT, PID, UID, USER, STATUS, PROTOCOL, PROCESS_NAME, LOCAL, REMOTE
writeln!(
tw,
"PORT\tUID\tUSER\tSTATUS\tPROTOCOL\tPROCESS_NAME\tLOCAL\tREMOTE"
"PORT\tPID\tUID\tUSER\tSTATUS\tPROTOCOL\tPROCESS_NAME\tLOCAL\tREMOTE"
)
.map_err(|e| anyhow::anyhow!("Failed to write to output: {}", e))?;
for s in tcp_sockets {
let proto_str = get_protocol_string(s.family);
let state_str = tcp_state_to_str(&s.state);

let (_pid, proc_name, uid_opt) = if let Some(proc_info) = s.processes.first() {
let (pid, proc_name, uid_opt) = if let Some(proc_info) = s.processes.first() {
(proc_info.pid, proc_info.name.clone(), proc_info.uid)
} else {
(0, "unknown".to_string(), None)
Expand All @@ -341,8 +353,8 @@ fn main() -> Result<()> {

writeln!(
tw,
"{}\t{}\t{}\t{}\t{}\t{}\t{}\t{}",
s.local_port, uid_str, user, state_str, proto_str, proc_name, local, remote
"{}\t{}\t{}\t{}\t{}\t{}\t{}\t{}\t{}",
s.local_port, pid, uid_str, user, state_str, proto_str, proc_name, local, remote
)
.map_err(|e| anyhow::anyhow!("Failed to write to output: {}", e))?;
}
Expand Down
Loading