#!/usr/bin/env bash set -euo pipefail # Script Name: ports # Description: Enhanced port viewer with colors, filtering, and process info # Usage: ports # Show all ports (colorized) # ports -l # Listening only (most common) # ports -p # Show process names # ports 80 # Find what's on port 80 # ports tcp # TCP only # ports udp # UDP only VERSION="1.0.0" # Colors readonly GREEN='\033[0;32m' readonly YELLOW='\033[1;33m' readonly BLUE='\033[0;34m' readonly RED='\033[0;31m' readonly CYAN='\033[0;36m' readonly BOLD='\033[1m' readonly NC='\033[0m' show_help() { echo -e "\033[1mports\033[0m - Enhanced Port Viewer v${VERSION}" echo echo -e "\033[1mUSAGE:\033[0m" echo " ports [OPTIONS] [PORT|PROTOCOL]" echo echo -e "\033[1mOPTIONS:\033[0m" echo -e " \033[0;36m-l, --listen\033[0m Show listening ports only (default)" echo -e " \033[0;36m-a, --all\033[0m Show all connections" echo -e " \033[0;36m-p, --process\033[0m Show process names/PIDs" echo -e " \033[0;36m-n, --numeric\033[0m Don't resolve hostnames" echo -e " \033[0;36m-h, --help\033[0m Show this help message" echo echo -e "\033[1mFILTERS:\033[0m" echo " ports 80 # Show what's on port 80" echo " ports tcp # TCP connections only" echo " ports udp # UDP connections only" echo " ports 8000-9000 # Port range" echo echo -e "\033[1mEXAMPLES:\033[0m" echo " ports # Listening ports (colorized)" echo " ports -p # With process info" echo " ports -a # All connections" echo " ports 443 # What's on HTTPS port" echo " ports tcp -p # TCP with processes" echo echo -e "\033[1mCOLOR LEGEND:\033[0m" echo -e " \033[0;32mLISTEN\033[0m - Listening for connections" echo -e " \033[0;34mESTABLISHED\033[0m - Active connection" echo -e " \033[1;33mTIME_WAIT\033[0m - Connection closing" echo -e " \033[0;31mCLOSE_WAIT\033[0m - Waiting to close" } # Colorize state colorize_state() { local state=$1 case "$state" in LISTEN) echo -e "${GREEN}${state}${NC}" ;; ESTABLISHED) echo -e "${BLUE}${state}${NC}" ;; TIME_WAIT|CLOSE_WAIT) echo -e "${YELLOW}${state}${NC}" ;; SYN_SENT|SYN_RECV) echo -e "${CYAN}${state}${NC}" ;; *) echo "$state" ;; esac } # Check if port is "interesting" (not in common_ports) is_unusual_port() { local port=$1 local common_ports=(20 21 22 23 25 53 80 110 143 443 465 587 993 995 3306 5432 6379 8080 8443) for p in "${common_ports[@]}"; do if [[ "$port" == "$p" ]]; then return 1 fi done return 0 } # Parse arguments show_listen_only=true show_process=false numeric=true filter_proto="" filter_port="" while [[ $# -gt 0 ]]; do case $1 in -l|--listen) show_listen_only=true shift ;; -a|--all) show_listen_only=false shift ;; -p|--process) show_process=true shift ;; -n|--numeric) numeric=true shift ;; -h|--help) show_help exit 0 ;; tcp|TCP) filter_proto="tcp" shift ;; udp|UDP) filter_proto="udp" shift ;; [0-9]*) filter_port="$1" shift ;; *) echo -e "${RED}Error:${NC} Unknown option: $1" >&2 echo "Run 'ports --help' for usage information" >&2 exit 1 ;; esac done # Build ss command ss_cmd="ss -tuln" if [[ "$show_listen_only" == "false" ]]; then ss_cmd="ss -tun" fi if [[ "$show_process" == "true" ]]; then ss_cmd="sudo ss -tulnp" if [[ "$show_listen_only" == "false" ]]; then ss_cmd="sudo ss -tunp" fi fi # Execute and format output=$($ss_cmd) # Header echo -e "${BOLD}${CYAN}Active Ports${NC}" echo -e "${BOLD}────────────────────────────────────────────────────────────${NC}" # Parse and colorize output echo "$output" | awk -v show_proc="$show_process" -v filter_proto="$filter_proto" -v filter_port="$filter_port" ' NR==1 { next } # Skip header from ss { proto = $1 state = $2 local = $5 peer = $6 process = "" # Extract process info if available (last field) if (show_proc == "true" && NF >= 7) { for (i=7; i<=NF; i++) { process = process $i " " } } # Filter by protocol if (filter_proto != "" && tolower(proto) !~ tolower(filter_proto)) next # Extract port from local address split(local, parts, ":") port = parts[length(parts)] # Filter by port if (filter_port != "" && port != filter_port) next # Print formatted line printf "%-6s %-12s %-25s %-25s", proto, state, local, peer if (process != "") { printf " %s", process } printf "\n" } ' | while IFS= read -r line; do # Colorize based on state if [[ "$line" =~ LISTEN ]]; then echo -e "$line" | sed "s/LISTEN/${GREEN}LISTEN${NC}/" elif [[ "$line" =~ ESTABLISHED ]]; then echo -e "$line" | sed "s/ESTABLISHED/${BLUE}ESTABLISHED${NC}/" elif [[ "$line" =~ TIME_WAIT ]]; then echo -e "$line" | sed "s/TIME_WAIT/${YELLOW}TIME_WAIT${NC}/" elif [[ "$line" =~ CLOSE_WAIT ]]; then echo -e "$line" | sed "s/CLOSE_WAIT/${RED}CLOSE_WAIT${NC}/" else echo "$line" fi done # Summary echo echo -e "${BOLD}${CYAN}Summary:${NC}" total=$(echo "$output" | wc -l) echo " Total connections: $((total - 1))" if [[ "$show_listen_only" == "true" ]]; then echo -e " ${GREEN}Tip:${NC} Use 'ports -a' to see all connections" fi if [[ "$show_process" == "false" ]]; then echo -e " ${GREEN}Tip:${NC} Use 'ports -p' to see process information" fi