macOS: Find Processes Using a Specific Remote Port
I find this script useful for debugging which processes are talking to which remote port.
cat > ~/netmon.sh </dev/null || echo "unknown"
else
echo "-"
fi
}
# Function to color-code based on state
get_state_color() {
local state=$1
case "$state" in
"ESTABLISHED")
echo "${GREEN}"
;;
"LISTEN")
echo "${BLUE}"
;;
"TIME_WAIT")
echo "${YELLOW}"
;;
"CLOSE_WAIT")
echo "${MAGENTA}"
;;
"SYN_SENT"|"SYN_RCVD")
echo "${CYAN}"
;;
"FIN_WAIT"*)
echo "${GRAY}"
;;
"CLOSING"|"LAST_ACK")
echo "${RED}"
;;
*)
echo "${WHITE}"
;;
esac
}
# Function to split address into IP and port
split_address() {
local addr=$1
local ip=""
local port=""
if [[ "$addr" == "*"* ]]; then
ip="*"
port="*"
elif [[ "$addr" =~ ^([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})\.([0-9]+)$ ]]; then
# IPv4 address with port (format: x.x.x.x.port)
ip="${match[1]}"
port="${match[2]}"
elif [[ "$addr" =~ ^(.*):([0-9]+)$ ]]; then
# Handle IPv6 format or hostname:port
ip="${match[1]}"
port="${match[2]}"
elif [[ "$addr" =~ ^(.*)\.(well-known|[a-z]+)$ ]]; then
# Handle named services
ip="${match[1]}"
port="${match[2]}"
else
ip="$addr"
port="-"
fi
echo "$ip|$port"
}
# Function to check if connection matches filters
matches_filter() {
local remote_ip=$1
local remote_port=$2
# Check port filter
if [ -n "$FILTER_PORT" ] && [ "$remote_port" != "$FILTER_PORT" ]; then
return 1
fi
# Check IP filter
if [ -n "$FILTER_IP" ]; then
# Handle partial IP matching
if [[ "$remote_ip" != *"$FILTER_IP"* ]]; then
return 1
fi
fi
return 0
}
# Function to display connections
show_connections() {
clear
# Header
echo -e "${BOLD}${WHITE}=== Network Connections Monitor ===${NC}"
echo -e "${BOLD}${WHITE}$(date '+%Y-%m-%d %H:%M:%S')${NC}"
# Show active filters
if [ -n "$FILTER_PORT" ] || [ -n "$FILTER_IP" ]; then
echo -e "${YELLOW}Active Filters:${NC}"
[ -n "$FILTER_PORT" ] && echo -e " Remote Port: ${BOLD}$FILTER_PORT${NC}"
[ -n "$FILTER_IP" ] && echo -e " Remote IP: ${BOLD}$FILTER_IP${NC}"
fi
echo ""
# Legend
echo -e "${BOLD}Color Legend:${NC}"
echo -e " ${GREEN}●${NC} ESTABLISHED ${BLUE}●${NC} LISTEN ${YELLOW}●${NC} TIME_WAIT"
echo -e " ${CYAN}●${NC} SYN_SENT/RCVD ${MAGENTA}●${NC} CLOSE_WAIT ${RED}●${NC} CLOSING/LAST_ACK"
echo -e " ${GRAY}●${NC} FIN_WAIT ${WHITE}●${NC} OTHER/UDP"
echo ""
# Table header
printf "${BOLD}%-6s %-22s %-22s %-7s %-12s %-8s %-30s${NC}\n" \
"PROTO" "LOCAL ADDRESS" "REMOTE IP" "R.PORT" "STATE" "PID" "PROCESS"
echo "$(printf '%.0s-' {1..120})"
# Temporary file for storing connections
TMPFILE=$(mktemp)
# Get TCP connections with netstat
# Note: On macOS, we need sudo to see process info for all connections
if command -v sudo >/dev/null 2>&1; then
# Try with sudo first (will show all processes)
sudo netstat -anp tcp 2>/dev/null | grep -E '^tcp' > "$TMPFILE" 2>/dev/null || \
netstat -an -p tcp 2>/dev/null | grep -E '^tcp' > "$TMPFILE"
else
netstat -an -p tcp 2>/dev/null | grep -E '^tcp' > "$TMPFILE"
fi
# Process TCP connections
while IFS= read -r line; do
# Parse netstat output (macOS format)
proto=$(echo "$line" | awk '{print $1}')
local_addr=$(echo "$line" | awk '{print $4}')
remote_addr=$(echo "$line" | awk '{print $5}')
state=$(echo "$line" | awk '{print $6}')
# Split remote address into IP and port
IFS='|' read -r remote_ip remote_port <</dev/null | grep -v PID | head -1 | awk '{print $2}')
if [ -z "$pid" ]; then
pid="-"
process="-"
else
process=$(get_process_name "$pid")
fi
else
pid="-"
process="-"
fi
# Get color based on state
color=$(get_state_color "$state")
# Format and print
printf "${color}%-6s %-22s %-22s %-7s %-12s %-8s %-30s${NC}\n" \
"$proto" \
"${local_addr:0:22}" \
"${remote_ip:0:22}" \
"${remote_port:0:7}" \
"$state" \
"$pid" \
"${process:0:30}"
done /dev/null 2>&1; then
sudo netstat -anp udp 2>/dev/null | grep -E '^udp' > "$TMPFILE" 2>/dev/null || \
netstat -an -p udp 2>/dev/null | grep -E '^udp' > "$TMPFILE"
else
netstat -an -p udp 2>/dev/null | grep -E '^udp' > "$TMPFILE"
fi
# Process UDP connections
while IFS= read -r line; do
# Parse netstat output for UDP
proto=$(echo "$line" | awk '{print $1}')
local_addr=$(echo "$line" | awk '{print $4}')
remote_addr=$(echo "$line" | awk '{print $5}')
# Split remote address into IP and port
IFS='|' read -r remote_ip remote_port <</dev/null | grep -v PID | head -1 | awk '{print $2}')
if [ -z "$pid" ]; then
pid="-"
process="-"
else
process=$(get_process_name "$pid")
fi
else
pid="-"
process="-"
fi
# White color for UDP
printf "${WHITE}%-6s %-22s %-22s %-7s %-12s %-8s %-30s${NC}\n" \
"$proto" \
"${local_addr:0:22}" \
"${remote_ip:0:22}" \
"${remote_port:0:7}" \
"$state" \
"$pid" \
"${process:0:30}"
done < "$TMPFILE"
# Clean up
rm -f "$TMPFILE"
# Footer
echo ""
echo "$(printf '%.0s-' {1..120})"
echo -e "${BOLD}Press Ctrl+C to exit${NC} | Refreshing every 5 seconds..."
# Show filter hint if no filters active
if [ -z "$FILTER_PORT" ] && [ -z "$FILTER_IP" ]; then
echo -e "${GRAY}Tip: Use --port PORT or --ip IP to filter connections${NC}"
fi
}
# Trap Ctrl+C to exit cleanly
trap 'echo -e "\n${BOLD}Exiting...${NC}"; exit 0' INT
# Main loop
echo -e "${BOLD}${CYAN}Starting Network Connection Monitor...${NC}"
echo -e "${YELLOW}Note: Run with sudo for complete process information${NC}"
# Show active filters on startup
if [ -n "$FILTER_PORT" ] || [ -n "$FILTER_IP" ]; then
echo -e "${GREEN}Filtering enabled:${NC}"
[ -n "$FILTER_PORT" ] && echo -e " Remote Port: ${BOLD}$FILTER_PORT${NC}"
[ -n "$FILTER_IP" ] && echo -e " Remote IP: ${BOLD}$FILTER_IP${NC}"
fi
sleep 2
while true; do
show_connections
sleep 5
done
EOF
chmod +x ~/netmon.sh Example Usuage:
# Show all connections
./netmon.sh
# Filter by port
./netmon.sh --port 443
# Filter by IP
./netmon.sh --ip 142.251
# Run with sudo for full process information
sudo ./netmon.sh --port 443