Port inuse function from bash to Go
This commit is contained in:
286
.bashrc
286
.bashrc
@@ -70,292 +70,6 @@ alias gcb='git checkout -b'
|
||||
alias kubectl="minikube kubectl --"
|
||||
alias zed=zeditor
|
||||
|
||||
# Check if a specific port is in use with detailed process information
|
||||
inuse() {
|
||||
# Color definitions
|
||||
local RED='\033[0;31m'
|
||||
local GREEN='\033[0;32m'
|
||||
local YELLOW='\033[1;33m'
|
||||
local BLUE='\033[0;34m'
|
||||
local CYAN='\033[0;36m'
|
||||
local BOLD='\033[1m'
|
||||
local NC='\033[0m' # No Color
|
||||
|
||||
# Input validation
|
||||
if [ $# -eq 0 ]; then
|
||||
echo -e "${RED}Usage:${NC} inuse <port_number>"
|
||||
echo -e "${YELLOW} inuse --list${NC}"
|
||||
echo -e "${YELLOW} inuse --help${NC}"
|
||||
echo -e "${YELLOW}Example:${NC} inuse 80"
|
||||
echo -e "${YELLOW} inuse --list${NC}"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Handle --help option
|
||||
if [ "$1" = "--help" ] || [ "$1" = "-h" ]; then
|
||||
echo -e "${CYAN}${BOLD}inuse - Check if a port is in use${NC}"
|
||||
echo
|
||||
echo -e "${BOLD}USAGE:${NC}"
|
||||
echo -e " inuse <port_number> Check if a specific port is in use"
|
||||
echo -e " inuse --list, -l List all Docker services with listening ports"
|
||||
echo -e " inuse --help, -h Show this help message"
|
||||
echo
|
||||
echo -e "${BOLD}EXAMPLES:${NC}"
|
||||
echo -e " ${GREEN}inuse 80${NC} Check if port 80 is in use"
|
||||
echo -e " ${GREEN}inuse 3000${NC} Check if port 3000 is in use"
|
||||
echo -e " ${GREEN}inuse --list${NC} Show all Docker services with ports"
|
||||
echo
|
||||
echo -e "${BOLD}DESCRIPTION:${NC}"
|
||||
echo -e " The inuse function checks if a specific port is in use and identifies"
|
||||
echo -e " the process using it. It can detect regular processes, Docker containers"
|
||||
echo -e " with published ports, and containers using host networking."
|
||||
echo
|
||||
echo -e "${BOLD}OUTPUT:${NC}"
|
||||
echo -e " ${GREEN}✓${NC} Port is in use - shows process name, PID, and Docker info if applicable"
|
||||
echo -e " ${RED}✗${NC} Port is free"
|
||||
echo -e " ${YELLOW}⚠${NC} Port is in use but process cannot be identified"
|
||||
echo
|
||||
return 0
|
||||
fi
|
||||
|
||||
# Handle --list option
|
||||
if [ "$1" = "--list" ] || [ "$1" = "-l" ]; then
|
||||
if ! command -v docker >/dev/null 2>&1; then
|
||||
echo -e "${RED}Error:${NC} Docker is not available"
|
||||
return 1
|
||||
fi
|
||||
|
||||
echo -e "${CYAN}${BOLD}Docker Services with Listening Ports:${NC}"
|
||||
echo
|
||||
|
||||
# Get all running containers
|
||||
local containers=$(docker ps --format "{{.Names}}" 2>/dev/null)
|
||||
if [ -z "$containers" ]; then
|
||||
echo -e "${YELLOW}No running Docker containers found${NC}"
|
||||
return 0
|
||||
fi
|
||||
|
||||
local found_services=false
|
||||
while IFS= read -r container; do
|
||||
# Get port mappings for this container
|
||||
local ports=$(docker port "$container" 2>/dev/null)
|
||||
if [ -n "$ports" ]; then
|
||||
# Get container image name (clean it up)
|
||||
local image=$(docker inspect "$container" 2>/dev/null | grep -o '"Image": *"[^"]*"' | cut -d'"' -f4 | head -1)
|
||||
local clean_image=$(echo "$image" | sed 's/sha256:[a-f0-9]*/[image-hash]/' | sed 's/^.*\///')
|
||||
|
||||
echo -e "${GREEN}📦 ${BOLD}$container${NC} ${CYAN}($clean_image)${NC}"
|
||||
|
||||
# Parse and display ports nicely
|
||||
echo "$ports" | while IFS= read -r port_line; do
|
||||
if [[ "$port_line" =~ ([0-9]+)/(tcp|udp).*0\.0\.0\.0:([0-9]+) ]]; then
|
||||
local container_port="${BASH_REMATCH[1]}"
|
||||
local protocol="${BASH_REMATCH[2]}"
|
||||
local host_port="${BASH_REMATCH[3]}"
|
||||
echo -e "${CYAN} ├─ Port ${BOLD}$host_port${NC}${CYAN} → $container_port ($protocol)${NC}"
|
||||
elif [[ "$port_line" =~ ([0-9]+)/(tcp|udp).*\[::\]:([0-9]+) ]]; then
|
||||
local container_port="${BASH_REMATCH[1]}"
|
||||
local protocol="${BASH_REMATCH[2]}"
|
||||
local host_port="${BASH_REMATCH[3]}"
|
||||
echo -e "${CYAN} ├─ Port ${BOLD}$host_port${NC}${CYAN} → $container_port ($protocol) [IPv6]${NC}"
|
||||
fi
|
||||
done
|
||||
echo
|
||||
found_services=true
|
||||
fi
|
||||
done <<< "$containers"
|
||||
|
||||
# Also check for host networking containers
|
||||
local host_containers=$(docker ps --format "{{.Names}}" --filter "network=host" 2>/dev/null)
|
||||
if [ -n "$host_containers" ]; then
|
||||
echo -e "${YELLOW}${BOLD}Host Networking Containers:${NC}"
|
||||
while IFS= read -r container; do
|
||||
local image=$(docker inspect "$container" 2>/dev/null | grep -o '"Image": *"[^"]*"' | cut -d'"' -f4 | head -1)
|
||||
local clean_image=$(echo "$image" | sed 's/sha256:[a-f0-9]*/[image-hash]/' | sed 's/^.*\///')
|
||||
echo -e "${YELLOW}🌐 ${BOLD}$container${NC} ${CYAN}($clean_image)${NC} ${YELLOW}- uses host networking${NC}"
|
||||
done <<< "$host_containers"
|
||||
echo
|
||||
found_services=true
|
||||
fi
|
||||
|
||||
if [ "$found_services" = false ]; then
|
||||
echo -e "${YELLOW}No Docker services with exposed ports found${NC}"
|
||||
fi
|
||||
|
||||
return 0
|
||||
fi
|
||||
|
||||
local port="$1"
|
||||
|
||||
# Validate port number
|
||||
if ! [[ "$port" =~ ^[0-9]+$ ]] || [ "$port" -lt 1 ] || [ "$port" -gt 65535 ]; then
|
||||
echo -e "${RED}Error:${NC} Invalid port number. Must be between 1 and 65535."
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Check if port is in use first
|
||||
local port_in_use=false
|
||||
if command -v ss >/dev/null 2>&1; then
|
||||
if ss -tulpn 2>/dev/null | grep -q ":$port "; then
|
||||
port_in_use=true
|
||||
fi
|
||||
elif command -v netstat >/dev/null 2>&1; then
|
||||
if netstat -tulpn 2>/dev/null | grep -q ":$port "; then
|
||||
port_in_use=true
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ "$port_in_use" = false ]; then
|
||||
echo -e "${RED}✗ Port $port is FREE${NC}"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Port is in use, now find what's using it
|
||||
local found_process=false
|
||||
|
||||
# Method 1: Try netstat first (most reliable for PID info)
|
||||
if command -v netstat >/dev/null 2>&1; then
|
||||
local netstat_result=$(netstat -tulpn 2>/dev/null | grep ":$port ")
|
||||
if [ -n "$netstat_result" ]; then
|
||||
while IFS= read -r line; do
|
||||
local pid=$(echo "$line" | awk '{print $7}' | cut -d'/' -f1)
|
||||
local process_name=$(echo "$line" | awk '{print $7}' | cut -d'/' -f2)
|
||||
local protocol=$(echo "$line" | awk '{print $1}')
|
||||
|
||||
if [[ "$pid" =~ ^[0-9]+$ ]] && [ -n "$process_name" ]; then
|
||||
# Check if it's a Docker container
|
||||
local docker_info=""
|
||||
if command -v docker >/dev/null 2>&1; then
|
||||
# Check for docker-proxy
|
||||
if [ "$process_name" = "docker-proxy" ]; then
|
||||
local container_name=$(docker ps --format "{{.Names}}" --filter "publish=$port" 2>/dev/null | head -1)
|
||||
if [ -n "$container_name" ]; then
|
||||
docker_info=" ${CYAN}(Docker: $container_name)${NC}"
|
||||
else
|
||||
docker_info=" ${CYAN}(Docker proxy)${NC}"
|
||||
fi
|
||||
else
|
||||
# Check if process is in a container by examining cgroup
|
||||
if [ -f "/proc/$pid/cgroup" ] && grep -q docker "/proc/$pid/cgroup" 2>/dev/null; then
|
||||
local container_id=$(cat "/proc/$pid/cgroup" 2>/dev/null | grep docker | grep -o '[a-f0-9]\{64\}' | head -1)
|
||||
if [ -n "$container_id" ]; then
|
||||
local container_name=$(docker inspect "$container_id" 2>/dev/null | grep -o '"Name": *"[^"]*"' | cut -d'"' -f4 | sed 's/^\/*//' | head -1)
|
||||
if [ -n "$container_name" ]; then
|
||||
docker_info=" ${CYAN}(Docker: $container_name)${NC}"
|
||||
else
|
||||
docker_info=" ${CYAN}(Docker: ${container_id:0:12})${NC}"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
echo -e "${GREEN}✓ Port $port ($protocol) in use by ${BOLD}$process_name${NC} ${GREEN}as PID ${BOLD}$pid${NC}$docker_info"
|
||||
found_process=true
|
||||
fi
|
||||
done <<< "$netstat_result"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Method 2: Try ss if netstat didn't work
|
||||
if [ "$found_process" = false ] && command -v ss >/dev/null 2>&1; then
|
||||
local ss_result=$(ss -tulpn 2>/dev/null | grep ":$port ")
|
||||
if [ -n "$ss_result" ]; then
|
||||
while IFS= read -r line; do
|
||||
local pid=$(echo "$line" | grep -o 'pid=[0-9]*' | cut -d'=' -f2)
|
||||
local protocol=$(echo "$line" | awk '{print $1}')
|
||||
|
||||
if [[ "$pid" =~ ^[0-9]+$ ]]; then
|
||||
local process_name=$(ps -p "$pid" -o comm= 2>/dev/null)
|
||||
if [ -n "$process_name" ]; then
|
||||
# Check for Docker container
|
||||
local docker_info=""
|
||||
if command -v docker >/dev/null 2>&1; then
|
||||
if [ "$process_name" = "docker-proxy" ]; then
|
||||
local container_name=$(docker ps --format "{{.Names}}" --filter "publish=$port" 2>/dev/null | head -1)
|
||||
if [ -n "$container_name" ]; then
|
||||
docker_info=" ${CYAN}(Docker: $container_name)${NC}"
|
||||
else
|
||||
docker_info=" ${CYAN}(Docker proxy)${NC}"
|
||||
fi
|
||||
elif [ -f "/proc/$pid/cgroup" ] && grep -q docker "/proc/$pid/cgroup" 2>/dev/null; then
|
||||
local container_id=$(cat "/proc/$pid/cgroup" 2>/dev/null | grep docker | grep -o '[a-f0-9]\{64\}' | head -1)
|
||||
if [ -n "$container_id" ]; then
|
||||
local container_name=$(docker inspect "$container_id" 2>/dev/null | grep -o '"Name": *"[^"]*"' | cut -d'"' -f4 | sed 's/^\/*//' | head -1)
|
||||
if [ -n "$container_name" ]; then
|
||||
docker_info=" ${CYAN}(Docker: $container_name)${NC}"
|
||||
else
|
||||
docker_info=" ${CYAN}(Docker: ${container_id:0:12})${NC}"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
echo -e "${GREEN}✓ Port $port ($protocol) in use by ${BOLD}$process_name${NC} ${GREEN}as PID ${BOLD}$pid${NC}$docker_info"
|
||||
found_process=true
|
||||
fi
|
||||
fi
|
||||
done <<< "$ss_result"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Method 3: Try fuser as last resort
|
||||
if [ "$found_process" = false ] && command -v fuser >/dev/null 2>&1; then
|
||||
local fuser_pids=$(fuser "$port/tcp" 2>/dev/null)
|
||||
if [ -n "$fuser_pids" ]; then
|
||||
for pid in $fuser_pids; do
|
||||
if [[ "$pid" =~ ^[0-9]+$ ]]; then
|
||||
local process_name=$(ps -p "$pid" -o comm= 2>/dev/null)
|
||||
if [ -n "$process_name" ]; then
|
||||
echo -e "${GREEN}✓ Port $port (tcp) in use by ${BOLD}$process_name${NC} ${GREEN}as PID ${BOLD}$pid${NC}"
|
||||
found_process=true
|
||||
break
|
||||
fi
|
||||
fi
|
||||
done
|
||||
fi
|
||||
fi
|
||||
|
||||
# Method 4: Check for Docker containers more accurately
|
||||
if [ "$found_process" = false ] && command -v docker >/dev/null 2>&1; then
|
||||
# First, try to find containers with published ports matching our port
|
||||
local container_with_port=$(docker ps --format "{{.Names}}" --filter "publish=$port" 2>/dev/null | head -1)
|
||||
if [ -n "$container_with_port" ]; then
|
||||
local image=$(docker inspect "$container_with_port" 2>/dev/null | grep -o '"Image": *"[^"]*"' | cut -d'"' -f4 | head -1)
|
||||
echo -e "${GREEN}✓ Port $port in use by Docker container ${BOLD}$container_with_port${NC} ${CYAN}(published port, image: $image)${NC}"
|
||||
found_process=true
|
||||
else
|
||||
# Only check host networking containers if we haven't found anything else
|
||||
local host_containers=$(docker ps --format "{{.Names}}" --filter "network=host" 2>/dev/null)
|
||||
if [ -n "$host_containers" ]; then
|
||||
local host_container_count=$(echo "$host_containers" | wc -l)
|
||||
if [ "$host_container_count" -eq 1 ]; then
|
||||
# Only one host networking container, likely candidate
|
||||
local image=$(docker inspect "$host_containers" 2>/dev/null | grep -o '"Image": *"[^"]*"' | cut -d'"' -f4 | head -1)
|
||||
echo -e "${YELLOW}⚠ Port $port possibly in use by Docker container ${BOLD}$host_containers${NC} ${CYAN}(host networking, image: $image)${NC}"
|
||||
found_process=true
|
||||
else
|
||||
# Multiple host networking containers, can't determine which one
|
||||
echo -e "${YELLOW}⚠ Port $port is in use, multiple Docker containers using host networking:${NC}"
|
||||
while IFS= read -r container; do
|
||||
local image=$(docker inspect "$container" 2>/dev/null | grep -o '"Image": *"[^"]*"' | cut -d'"' -f4 | head -1)
|
||||
echo -e "${CYAN} - $container (image: $image)${NC}"
|
||||
done <<< "$host_containers"
|
||||
found_process=true
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
# If we still haven't found the process, show a generic message
|
||||
if [ "$found_process" = false ]; then
|
||||
echo -e "${YELLOW}⚠ Port $port is in use but unable to identify the process${NC}"
|
||||
echo -e "${CYAN} This might be due to insufficient permissions or the process being in a different namespace${NC}"
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
# random string (Syntax: random <length>)
|
||||
alias random='openssl rand -base64'
|
||||
|
||||
|
748
config/ansible/tasks/global/utils/inuse.go
Normal file
748
config/ansible/tasks/global/utils/inuse.go
Normal file
@@ -0,0 +1,748 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Color constants for terminal output
|
||||
const (
|
||||
Red = "\033[0;31m"
|
||||
Green = "\033[0;32m"
|
||||
Yellow = "\033[1;33m"
|
||||
Blue = "\033[0;34m"
|
||||
Cyan = "\033[0;36m"
|
||||
Bold = "\033[1m"
|
||||
NC = "\033[0m" // No Color
|
||||
)
|
||||
|
||||
// ProcessInfo holds information about a process using a port
|
||||
type ProcessInfo struct {
|
||||
PID int
|
||||
ProcessName string
|
||||
Protocol string
|
||||
DockerInfo string
|
||||
}
|
||||
|
||||
// DockerContainer represents a Docker container
|
||||
type DockerContainer struct {
|
||||
Name string
|
||||
Image string
|
||||
Ports []PortMapping
|
||||
Network string
|
||||
}
|
||||
|
||||
// PortMapping represents a port mapping
|
||||
type PortMapping struct {
|
||||
ContainerPort int
|
||||
HostPort int
|
||||
Protocol string
|
||||
IPv6 bool
|
||||
}
|
||||
|
||||
func main() {
|
||||
if len(os.Args) < 2 {
|
||||
showUsage()
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
arg := os.Args[1]
|
||||
|
||||
switch arg {
|
||||
case "--help", "-h":
|
||||
showHelp()
|
||||
case "--list", "-l":
|
||||
listDockerServices()
|
||||
default:
|
||||
port, err := strconv.Atoi(arg)
|
||||
if err != nil || port < 1 || port > 65535 {
|
||||
fmt.Printf("%sError:%s Invalid port number. Must be between 1 and 65535.\n", Red, NC)
|
||||
os.Exit(1)
|
||||
}
|
||||
checkPort(port)
|
||||
}
|
||||
}
|
||||
|
||||
func showUsage() {
|
||||
fmt.Printf("%sUsage:%s inuse <port_number>\n", Red, NC)
|
||||
fmt.Printf("%s inuse --list%s\n", Yellow, NC)
|
||||
fmt.Printf("%s inuse --help%s\n", Yellow, NC)
|
||||
fmt.Printf("%sExample:%s inuse 80\n", Yellow, NC)
|
||||
fmt.Printf("%s inuse --list%s\n", Yellow, NC)
|
||||
}
|
||||
|
||||
func showHelp() {
|
||||
fmt.Printf("%s%sinuse - Check if a port is in use%s\n\n", Cyan, Bold, NC)
|
||||
fmt.Printf("%sUSAGE:%s\n", Bold, NC)
|
||||
fmt.Printf(" inuse <port_number> Check if a specific port is in use\n")
|
||||
fmt.Printf(" inuse --list, -l List all Docker services with listening ports\n")
|
||||
fmt.Printf(" inuse --help, -h Show this help message\n\n")
|
||||
fmt.Printf("%sEXAMPLES:%s\n", Bold, NC)
|
||||
fmt.Printf(" %sinuse 80%s Check if port 80 is in use\n", Green, NC)
|
||||
fmt.Printf(" %sinuse 3000%s Check if port 3000 is in use\n", Green, NC)
|
||||
fmt.Printf(" %sinuse --list%s Show all Docker services with ports\n\n", Green, NC)
|
||||
fmt.Printf("%sDESCRIPTION:%s\n", Bold, NC)
|
||||
fmt.Printf(" The inuse function checks if a specific port is in use and identifies\n")
|
||||
fmt.Printf(" the process using it. It can detect regular processes, Docker containers\n")
|
||||
fmt.Printf(" with published ports, and containers using host networking.\n\n")
|
||||
fmt.Printf("%sOUTPUT:%s\n", Bold, NC)
|
||||
fmt.Printf(" %s✓%s Port is in use - shows process name, PID, and Docker info if applicable\n", Green, NC)
|
||||
fmt.Printf(" %s✗%s Port is free\n", Red, NC)
|
||||
fmt.Printf(" %s⚠%s Port is in use but process cannot be identified\n", Yellow, NC)
|
||||
}
|
||||
|
||||
func listDockerServices() {
|
||||
if !isDockerAvailable() {
|
||||
fmt.Printf("%sError:%s Docker is not available\n", Red, NC)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
fmt.Printf("%s%sDocker Services with Listening Ports:%s\n\n", Cyan, Bold, NC)
|
||||
|
||||
containers := getRunningContainers()
|
||||
if len(containers) == 0 {
|
||||
fmt.Printf("%sNo running Docker containers found%s\n", Yellow, NC)
|
||||
return
|
||||
}
|
||||
|
||||
foundServices := false
|
||||
for _, container := range containers {
|
||||
if len(container.Ports) > 0 {
|
||||
cleanImage := cleanImageName(container.Image)
|
||||
fmt.Printf("%s📦 %s%s%s %s(%s)%s\n", Green, Bold, container.Name, NC, Cyan, cleanImage, NC)
|
||||
|
||||
for _, port := range container.Ports {
|
||||
ipv6Marker := ""
|
||||
if port.IPv6 {
|
||||
ipv6Marker = " [IPv6]"
|
||||
}
|
||||
fmt.Printf("%s ├─ Port %s%d%s%s → %d (%s)%s%s\n",
|
||||
Cyan, Bold, port.HostPort, NC, Cyan, port.ContainerPort, port.Protocol, ipv6Marker, NC)
|
||||
}
|
||||
fmt.Println()
|
||||
foundServices = true
|
||||
}
|
||||
}
|
||||
|
||||
// Check for host networking containers
|
||||
hostContainers := getHostNetworkingContainers()
|
||||
if len(hostContainers) > 0 {
|
||||
fmt.Printf("%s%sHost Networking Containers:%s\n", Yellow, Bold, NC)
|
||||
for _, container := range hostContainers {
|
||||
cleanImage := cleanImageName(container.Image)
|
||||
fmt.Printf("%s🌐 %s%s%s %s(%s)%s %s- uses host networking%s\n",
|
||||
Yellow, Bold, container.Name, NC, Cyan, cleanImage, NC, Yellow, NC)
|
||||
}
|
||||
fmt.Println()
|
||||
foundServices = true
|
||||
}
|
||||
|
||||
if !foundServices {
|
||||
fmt.Printf("%sNo Docker services with exposed ports found%s\n", Yellow, NC)
|
||||
}
|
||||
}
|
||||
|
||||
func checkPort(port int) {
|
||||
// Check if port is in use first
|
||||
if !isPortInUse(port) {
|
||||
fmt.Printf("%s✗ Port %d is FREE%s\n", Red, port, NC)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// Port is in use, now find what's using it
|
||||
process := findProcessUsingPort(port)
|
||||
if process != nil {
|
||||
dockerInfo := ""
|
||||
if process.DockerInfo != "" {
|
||||
dockerInfo = " " + process.DockerInfo
|
||||
}
|
||||
fmt.Printf("%s✓ Port %d (%s) in use by %s%s%s %sas PID %s%d%s%s\n",
|
||||
Green, port, process.Protocol, Bold, process.ProcessName, NC, Green, Bold, process.PID, NC, dockerInfo)
|
||||
return
|
||||
}
|
||||
|
||||
// Check if it's a Docker container
|
||||
containerInfo := findDockerContainerUsingPort(port)
|
||||
if containerInfo != "" {
|
||||
fmt.Printf("%s✓ Port %d in use by Docker container %s\n", Green, port, containerInfo)
|
||||
return
|
||||
}
|
||||
|
||||
// If we still haven't found the process, check for host networking containers more thoroughly
|
||||
hostNetworkProcess := findHostNetworkingProcess(port)
|
||||
if hostNetworkProcess != "" {
|
||||
fmt.Printf("%s✓ Port %d likely in use by %s\n", Green, port, hostNetworkProcess)
|
||||
return
|
||||
}
|
||||
|
||||
// If we still haven't found the process
|
||||
fmt.Printf("%s⚠ Port %d is in use but unable to identify the process%s\n", Yellow, port, NC)
|
||||
|
||||
if isDockerAvailable() {
|
||||
hostContainers := getHostNetworkingContainers()
|
||||
if len(hostContainers) > 0 {
|
||||
fmt.Printf("%s Note: Found Docker containers using host networking:%s\n", Cyan, NC)
|
||||
for _, container := range hostContainers {
|
||||
cleanImage := cleanImageName(container.Image)
|
||||
fmt.Printf("%s - %s (%s)%s\n", Cyan, container.Name, cleanImage, NC)
|
||||
}
|
||||
fmt.Printf("%s These containers share the host's network, so one of them might be using this port%s\n", Cyan, NC)
|
||||
} else {
|
||||
fmt.Printf("%s This might be due to insufficient permissions or the process being in a different namespace%s\n", Cyan, NC)
|
||||
}
|
||||
} else {
|
||||
fmt.Printf("%s This might be due to insufficient permissions or the process being in a different namespace%s\n", Cyan, NC)
|
||||
}
|
||||
}
|
||||
|
||||
func isPortInUse(port int) bool {
|
||||
// Try ss first
|
||||
if isCommandAvailable("ss") {
|
||||
cmd := exec.Command("ss", "-tulpn")
|
||||
output, err := cmd.Output()
|
||||
if err == nil {
|
||||
portPattern := fmt.Sprintf(":%d ", port)
|
||||
return strings.Contains(string(output), portPattern)
|
||||
}
|
||||
}
|
||||
|
||||
// Try netstat as fallback
|
||||
if isCommandAvailable("netstat") {
|
||||
cmd := exec.Command("netstat", "-tulpn")
|
||||
output, err := cmd.Output()
|
||||
if err == nil {
|
||||
portPattern := fmt.Sprintf(":%d ", port)
|
||||
return strings.Contains(string(output), portPattern)
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func findProcessUsingPort(port int) *ProcessInfo {
|
||||
// Method 1: Try netstat
|
||||
if process := tryNetstat(port); process != nil {
|
||||
return process
|
||||
}
|
||||
|
||||
// Method 2: Try ss
|
||||
if process := trySS(port); process != nil {
|
||||
return process
|
||||
}
|
||||
|
||||
// Method 3: Try lsof
|
||||
if process := tryLsof(port); process != nil {
|
||||
return process
|
||||
}
|
||||
|
||||
// Method 4: Try fuser
|
||||
if process := tryFuser(port); process != nil {
|
||||
return process
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func tryNetstat(port int) *ProcessInfo {
|
||||
if !isCommandAvailable("netstat") {
|
||||
return nil
|
||||
}
|
||||
|
||||
cmd := exec.Command("netstat", "-tulpn")
|
||||
output, err := cmd.Output()
|
||||
if err != nil {
|
||||
// Try with sudo if available
|
||||
if isCommandAvailable("sudo") {
|
||||
cmd = exec.Command("sudo", "netstat", "-tulpn")
|
||||
output, err = cmd.Output()
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
scanner := bufio.NewScanner(strings.NewReader(string(output)))
|
||||
portPattern := fmt.Sprintf(":%d ", port)
|
||||
|
||||
for scanner.Scan() {
|
||||
line := scanner.Text()
|
||||
if strings.Contains(line, portPattern) {
|
||||
fields := strings.Fields(line)
|
||||
if len(fields) >= 7 {
|
||||
pidProcess := fields[6]
|
||||
parts := strings.Split(pidProcess, "/")
|
||||
if len(parts) >= 2 {
|
||||
if pid, err := strconv.Atoi(parts[0]); err == nil {
|
||||
processName := parts[1]
|
||||
protocol := fields[0]
|
||||
dockerInfo := getDockerInfo(pid, processName, port)
|
||||
return &ProcessInfo{
|
||||
PID: pid,
|
||||
ProcessName: processName,
|
||||
Protocol: protocol,
|
||||
DockerInfo: dockerInfo,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func trySS(port int) *ProcessInfo {
|
||||
if !isCommandAvailable("ss") {
|
||||
return nil
|
||||
}
|
||||
|
||||
cmd := exec.Command("ss", "-tulpn")
|
||||
output, err := cmd.Output()
|
||||
if err != nil {
|
||||
// Try with sudo if available
|
||||
if isCommandAvailable("sudo") {
|
||||
cmd = exec.Command("sudo", "ss", "-tulpn")
|
||||
output, err = cmd.Output()
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
scanner := bufio.NewScanner(strings.NewReader(string(output)))
|
||||
portPattern := fmt.Sprintf(":%d ", port)
|
||||
pidRegex := regexp.MustCompile(`pid=(\d+)`)
|
||||
|
||||
for scanner.Scan() {
|
||||
line := scanner.Text()
|
||||
if strings.Contains(line, portPattern) {
|
||||
matches := pidRegex.FindStringSubmatch(line)
|
||||
if len(matches) >= 2 {
|
||||
if pid, err := strconv.Atoi(matches[1]); err == nil {
|
||||
processName := getProcessName(pid)
|
||||
if processName != "" {
|
||||
fields := strings.Fields(line)
|
||||
protocol := ""
|
||||
if len(fields) > 0 {
|
||||
protocol = fields[0]
|
||||
}
|
||||
dockerInfo := getDockerInfo(pid, processName, port)
|
||||
return &ProcessInfo{
|
||||
PID: pid,
|
||||
ProcessName: processName,
|
||||
Protocol: protocol,
|
||||
DockerInfo: dockerInfo,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func tryLsof(port int) *ProcessInfo {
|
||||
if !isCommandAvailable("lsof") {
|
||||
return nil
|
||||
}
|
||||
|
||||
cmd := exec.Command("lsof", "-i", fmt.Sprintf(":%d", port), "-n", "-P")
|
||||
output, err := cmd.Output()
|
||||
if err != nil {
|
||||
// Try with sudo if available
|
||||
if isCommandAvailable("sudo") {
|
||||
cmd = exec.Command("sudo", "lsof", "-i", fmt.Sprintf(":%d", port), "-n", "-P")
|
||||
output, err = cmd.Output()
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
scanner := bufio.NewScanner(strings.NewReader(string(output)))
|
||||
for scanner.Scan() {
|
||||
line := scanner.Text()
|
||||
if strings.Contains(line, "LISTEN") {
|
||||
fields := strings.Fields(line)
|
||||
if len(fields) >= 2 {
|
||||
processName := fields[0]
|
||||
if pid, err := strconv.Atoi(fields[1]); err == nil {
|
||||
dockerInfo := getDockerInfo(pid, processName, port)
|
||||
return &ProcessInfo{
|
||||
PID: pid,
|
||||
ProcessName: processName,
|
||||
Protocol: "tcp",
|
||||
DockerInfo: dockerInfo,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func tryFuser(port int) *ProcessInfo {
|
||||
if !isCommandAvailable("fuser") {
|
||||
return nil
|
||||
}
|
||||
|
||||
cmd := exec.Command("fuser", fmt.Sprintf("%d/tcp", port))
|
||||
output, err := cmd.Output()
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
pids := strings.Fields(string(output))
|
||||
for _, pidStr := range pids {
|
||||
if pid, err := strconv.Atoi(strings.TrimSpace(pidStr)); err == nil {
|
||||
processName := getProcessName(pid)
|
||||
if processName != "" {
|
||||
return &ProcessInfo{
|
||||
PID: pid,
|
||||
ProcessName: processName,
|
||||
Protocol: "tcp",
|
||||
DockerInfo: "",
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func getProcessName(pid int) string {
|
||||
cmd := exec.Command("ps", "-p", strconv.Itoa(pid), "-o", "comm=")
|
||||
output, err := cmd.Output()
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
return strings.TrimSpace(string(output))
|
||||
}
|
||||
|
||||
func getDockerInfo(pid int, processName string, port int) string {
|
||||
if !isDockerAvailable() {
|
||||
return ""
|
||||
}
|
||||
|
||||
// Check if it's docker-proxy (handle truncated names like "docker-pr")
|
||||
if processName == "docker-proxy" || strings.HasPrefix(processName, "docker-pr") {
|
||||
containerName := getContainerByPublishedPort(port)
|
||||
if containerName != "" {
|
||||
image := getContainerImage(containerName)
|
||||
cleanImage := cleanImageName(image)
|
||||
return fmt.Sprintf("%s(Docker: %s, image: %s)%s", Cyan, containerName, cleanImage, NC)
|
||||
}
|
||||
return fmt.Sprintf("%s(Docker proxy)%s", Cyan, NC)
|
||||
}
|
||||
|
||||
// Check if process is in a Docker container using cgroup
|
||||
containerInfo := getContainerByPID(pid)
|
||||
if containerInfo != "" {
|
||||
return fmt.Sprintf("%s(Docker: %s)%s", Cyan, containerInfo, NC)
|
||||
}
|
||||
|
||||
// Check if this process might be in a host networking container
|
||||
hostContainer := checkHostNetworkingContainer(pid, processName)
|
||||
if hostContainer != "" {
|
||||
return fmt.Sprintf("%s(Docker host network: %s)%s", Cyan, hostContainer, NC)
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
func getContainerByPID(pid int) string {
|
||||
cgroupPath := fmt.Sprintf("/proc/%d/cgroup", pid)
|
||||
file, err := os.Open(cgroupPath)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
scanner := bufio.NewScanner(file)
|
||||
containerIDRegex := regexp.MustCompile(`[a-f0-9]{64}`)
|
||||
|
||||
for scanner.Scan() {
|
||||
line := scanner.Text()
|
||||
if strings.Contains(line, "docker") {
|
||||
matches := containerIDRegex.FindStringSubmatch(line)
|
||||
if len(matches) > 0 {
|
||||
containerID := matches[0]
|
||||
containerName := getContainerNameByID(containerID)
|
||||
if containerName != "" {
|
||||
return containerName
|
||||
}
|
||||
return containerID[:12]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
func findDockerContainerUsingPort(port int) string {
|
||||
if !isDockerAvailable() {
|
||||
return ""
|
||||
}
|
||||
|
||||
// Check for containers with published ports
|
||||
cmd := exec.Command("docker", "ps", "--format", "{{.Names}}", "--filter", fmt.Sprintf("publish=%d", port))
|
||||
output, err := cmd.Output()
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
containerName := strings.TrimSpace(string(output))
|
||||
if containerName != "" {
|
||||
image := getContainerImage(containerName)
|
||||
cleanImage := cleanImageName(image)
|
||||
return fmt.Sprintf("%s%s%s %s(published port, image: %s)%s", Bold, containerName, NC, Cyan, cleanImage, NC)
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
func isDockerAvailable() bool {
|
||||
return isCommandAvailable("docker")
|
||||
}
|
||||
|
||||
func isCommandAvailable(command string) bool {
|
||||
_, err := exec.LookPath(command)
|
||||
return err == nil
|
||||
}
|
||||
|
||||
func getRunningContainers() []DockerContainer {
|
||||
if !isDockerAvailable() {
|
||||
return nil
|
||||
}
|
||||
|
||||
cmd := exec.Command("docker", "ps", "--format", "{{.Names}}")
|
||||
output, err := cmd.Output()
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
var containers []DockerContainer
|
||||
scanner := bufio.NewScanner(strings.NewReader(string(output)))
|
||||
|
||||
for scanner.Scan() {
|
||||
containerName := strings.TrimSpace(scanner.Text())
|
||||
if containerName != "" {
|
||||
container := DockerContainer{
|
||||
Name: containerName,
|
||||
Image: getContainerImage(containerName),
|
||||
Ports: getContainerPorts(containerName),
|
||||
}
|
||||
containers = append(containers, container)
|
||||
}
|
||||
}
|
||||
|
||||
return containers
|
||||
}
|
||||
|
||||
func getHostNetworkingContainers() []DockerContainer {
|
||||
if !isDockerAvailable() {
|
||||
return nil
|
||||
}
|
||||
|
||||
cmd := exec.Command("docker", "ps", "--format", "{{.Names}}", "--filter", "network=host")
|
||||
output, err := cmd.Output()
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
var containers []DockerContainer
|
||||
scanner := bufio.NewScanner(strings.NewReader(string(output)))
|
||||
|
||||
for scanner.Scan() {
|
||||
containerName := strings.TrimSpace(scanner.Text())
|
||||
if containerName != "" {
|
||||
container := DockerContainer{
|
||||
Name: containerName,
|
||||
Image: getContainerImage(containerName),
|
||||
Network: "host",
|
||||
}
|
||||
containers = append(containers, container)
|
||||
}
|
||||
}
|
||||
|
||||
return containers
|
||||
}
|
||||
|
||||
func getContainerImage(containerName string) string {
|
||||
cmd := exec.Command("docker", "inspect", containerName)
|
||||
output, err := cmd.Output()
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
var inspectData []map[string]interface{}
|
||||
if err := json.Unmarshal(output, &inspectData); err != nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
if len(inspectData) > 0 {
|
||||
if image, ok := inspectData[0]["Config"].(map[string]interface{})["Image"].(string); ok {
|
||||
return image
|
||||
}
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
func getContainerPorts(containerName string) []PortMapping {
|
||||
cmd := exec.Command("docker", "port", containerName)
|
||||
output, err := cmd.Output()
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
var ports []PortMapping
|
||||
scanner := bufio.NewScanner(strings.NewReader(string(output)))
|
||||
portRegex := regexp.MustCompile(`(\d+)/(tcp|udp) -> 0\.0\.0\.0:(\d+)`)
|
||||
ipv6PortRegex := regexp.MustCompile(`(\d+)/(tcp|udp) -> \[::\]:(\d+)`)
|
||||
|
||||
for scanner.Scan() {
|
||||
line := scanner.Text()
|
||||
|
||||
// Check for IPv4
|
||||
if matches := portRegex.FindStringSubmatch(line); len(matches) >= 4 {
|
||||
containerPort, _ := strconv.Atoi(matches[1])
|
||||
protocol := matches[2]
|
||||
hostPort, _ := strconv.Atoi(matches[3])
|
||||
|
||||
ports = append(ports, PortMapping{
|
||||
ContainerPort: containerPort,
|
||||
HostPort: hostPort,
|
||||
Protocol: protocol,
|
||||
IPv6: false,
|
||||
})
|
||||
}
|
||||
|
||||
// Check for IPv6
|
||||
if matches := ipv6PortRegex.FindStringSubmatch(line); len(matches) >= 4 {
|
||||
containerPort, _ := strconv.Atoi(matches[1])
|
||||
protocol := matches[2]
|
||||
hostPort, _ := strconv.Atoi(matches[3])
|
||||
|
||||
ports = append(ports, PortMapping{
|
||||
ContainerPort: containerPort,
|
||||
HostPort: hostPort,
|
||||
Protocol: protocol,
|
||||
IPv6: true,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return ports
|
||||
}
|
||||
|
||||
func getContainerByPublishedPort(port int) string {
|
||||
cmd := exec.Command("docker", "ps", "--format", "{{.Names}}", "--filter", fmt.Sprintf("publish=%d", port))
|
||||
output, err := cmd.Output()
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
return strings.TrimSpace(string(output))
|
||||
}
|
||||
|
||||
func getContainerNameByID(containerID string) string {
|
||||
cmd := exec.Command("docker", "inspect", containerID)
|
||||
output, err := cmd.Output()
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
var inspectData []map[string]interface{}
|
||||
if err := json.Unmarshal(output, &inspectData); err != nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
if len(inspectData) > 0 {
|
||||
if name, ok := inspectData[0]["Name"].(string); ok {
|
||||
return strings.TrimPrefix(name, "/")
|
||||
}
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
func cleanImageName(image string) string {
|
||||
// Remove SHA256 hashes
|
||||
shaRegex := regexp.MustCompile(`sha256:[a-f0-9]*`)
|
||||
cleaned := shaRegex.ReplaceAllString(image, "[image-hash]")
|
||||
|
||||
// Remove registry prefixes, keep only the last part
|
||||
parts := strings.Split(cleaned, "/")
|
||||
if len(parts) > 0 {
|
||||
return parts[len(parts)-1]
|
||||
}
|
||||
|
||||
return cleaned
|
||||
}
|
||||
|
||||
func findHostNetworkingProcess(port int) string {
|
||||
if !isDockerAvailable() {
|
||||
return ""
|
||||
}
|
||||
|
||||
// Get all host networking containers
|
||||
hostContainers := getHostNetworkingContainers()
|
||||
|
||||
for _, container := range hostContainers {
|
||||
// Check if this container might be using the port
|
||||
if isContainerUsingPort(container.Name, port) {
|
||||
cleanImage := cleanImageName(container.Image)
|
||||
return fmt.Sprintf("%s%s%s %s(Docker host network: %s)%s", Bold, container.Name, NC, Cyan, cleanImage, NC)
|
||||
}
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
func isContainerUsingPort(containerName string, port int) bool {
|
||||
// Try to execute netstat inside the container to see if it's listening on the port
|
||||
cmd := exec.Command("docker", "exec", containerName, "sh", "-c",
|
||||
fmt.Sprintf("netstat -tlnp 2>/dev/null | grep ':%d ' || ss -tlnp 2>/dev/null | grep ':%d '", port, port))
|
||||
output, err := cmd.Output()
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
return len(output) > 0
|
||||
}
|
||||
|
||||
func checkHostNetworkingContainer(pid int, processName string) string {
|
||||
if !isDockerAvailable() {
|
||||
return ""
|
||||
}
|
||||
|
||||
// Get all host networking containers and check if any match this process
|
||||
hostContainers := getHostNetworkingContainers()
|
||||
|
||||
for _, container := range hostContainers {
|
||||
// Try to find this process inside the container
|
||||
cmd := exec.Command("docker", "exec", container.Name, "sh", "-c",
|
||||
fmt.Sprintf("ps -o pid,comm | grep '%s' | grep -q '%d\\|%s'", processName, pid, processName))
|
||||
err := cmd.Run()
|
||||
if err == nil {
|
||||
cleanImage := cleanImageName(container.Image)
|
||||
return fmt.Sprintf("%s (%s)", container.Name, cleanImage)
|
||||
}
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
@@ -15,9 +15,7 @@
|
||||
"host": "desktop",
|
||||
"projects": [
|
||||
{
|
||||
"paths": [
|
||||
"/home/menno/.dotfiles"
|
||||
]
|
||||
"paths": ["/home/menno/.dotfiles"]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
Reference in New Issue
Block a user