|
|
|
#!/bin/bash |
|
# Filename: ~/usr/local/bin/show-network-devices.sh |
|
# LAN Device Viewer (ping sweep + ARP) |
|
|
|
# Detect LAN interface and subnet |
|
LAN_IFACE=$(ip route get 1 | awk '{print $5; exit}') |
|
LAN_SUBNET=$(ip -4 addr show "$LAN_IFACE" | awk '/inet /{print $2}') |
|
LAN_SUBNET_PREFIX=$(echo "$LAN_SUBNET" | cut -d/ -f1 | sed 's/\.[0-9]*$//') |
|
|
|
# OUI vendor lookup |
|
get_vendor() { |
|
local mac="$1" |
|
[[ -z "$mac" || "$mac" == "-" ]] && return |
|
local oui=$(echo "$mac" | tr -d ':' | tr '[:lower:]' '[:upper:]' | cut -c1-6) |
|
if [[ -f /usr/share/nmap/nmap-mac-prefixes ]]; then |
|
grep -i "^$oui" /usr/share/nmap/nmap-mac-prefixes 2>/dev/null | awk '{$1=""; print substr($0,2)}' |
|
fi |
|
} |
|
|
|
# Get hostname via nmap (fast) |
|
get_hostname() { |
|
local ip="$1" |
|
nmap -sn --max-retries 1 --host-timeout 2s "$ip" 2>/dev/null | awk '/Nmap scan report/{print $5; exit}' |
|
} |
|
|
|
# Get live devices |
|
get_live_devices() { |
|
echo "Pinging subnet..." |
|
for ip in $(seq 1 254); do |
|
ping -c 1 -W 1 "$LAN_SUBNET_PREFIX.$ip" >/dev/null 2>&1 & |
|
done |
|
wait |
|
|
|
echo "Reading ARP table..." |
|
timeout=10 |
|
while [[ $timeout -gt 0 ]]; do |
|
mapfile -t devs < <(ip -4 neigh show dev "$LAN_IFACE" | grep -E "REACHABLE|STALE" | awk '{print $1, $3}') |
|
[[ ${#devs[@]} -ge 3 ]] && break |
|
sleep 1 |
|
((timeout--)) |
|
done |
|
echo "Found ${#devs[@]} reachable devices" |
|
|
|
# Own machine at top |
|
self_ip=$(ip -4 addr show "$LAN_IFACE" | awk '/inet /{print $2}' | cut -d/ -f1) |
|
self_mac=$(ip link show "$LAN_IFACE" | awk '/link\/ether/ {print $2}') |
|
self_name=$(hostname) |
|
devices+=("$self_ip $self_mac $self_name") |
|
|
|
# Process ARP entries |
|
echo "Resolving hostnames..." |
|
for d in "${devs[@]}"; do |
|
ip_only=$(echo "$d" | awk '{print $1}') |
|
mac=$(echo "$d" | awk '{print $2}') |
|
[[ "$ip_only" == "$self_ip" ]] && continue |
|
[[ -z "$mac" ]] && mac="-" |
|
|
|
hostname=$(get_hostname "$ip_only") |
|
[[ -z "$hostname" || "$hostname" == "$ip_only" ]] && hostname="-" |
|
|
|
vendor=$(get_vendor "$mac") |
|
[[ -z "$vendor" ]] && vendor="-" |
|
|
|
devices+=("$ip_only $mac $hostname $vendor") |
|
done |
|
} |
|
|
|
# Scan all devices |
|
scan_devices() { |
|
for ip in $(seq 1 254); do |
|
ping -c 1 -W 1 "$LAN_SUBNET_PREFIX.$ip" >/dev/null 2>&1 & |
|
done |
|
wait |
|
sleep 1 |
|
|
|
mapfile -t all_devs < <(ip neigh show dev "$LAN_IFACE" | grep -v ":" | awk '{print $1, $5}') |
|
} |
|
|
|
# Display devices |
|
display_devices() { |
|
local list=("$@") |
|
printf "%-4s %-15s %-20s %-25s %-25s\n" "#" "IP" "MAC" "HOSTNAME" "VENDOR" |
|
echo "-----------------------------------------------------------------------------------------------------------------" |
|
|
|
for i in "${!list[@]}"; do |
|
parts=(${list[$i]}) |
|
ip="${parts[0]}" |
|
mac="${parts[1]:--}" |
|
hostname="${parts[2]:--}" |
|
vendor="${parts[3]:--}" |
|
|
|
if [[ "$vendor" == "-" ]] && [[ "$mac" != "-" ]]; then |
|
vendor=$(get_vendor "$mac") |
|
[[ -z "$vendor" ]] && vendor="-" |
|
fi |
|
|
|
if [[ " ${devices[*]} " =~ "$ip" ]]; then |
|
color="\e[1;32m" |
|
else |
|
color="\e[1;31m" |
|
fi |
|
|
|
printf "${color}%-4s %-15s %-20s %-25s %-25s\e[0m\n" "$((i+1))" "$ip" "$mac" "$hostname" "$vendor" |
|
done |
|
} |
|
|
|
# Main loop |
|
while true; do |
|
clear |
|
echo -e "\e[1;36m=== LAN Devices ===\e[0m" |
|
echo -e "Interface: $LAN_IFACE | Subnet: $LAN_SUBNET" |
|
echo "" |
|
|
|
get_live_devices |
|
if [ ${#devices[@]} -eq 0 ]; then |
|
echo "No live devices detected." |
|
else |
|
display_devices "${devices[@]}" |
|
fi |
|
|
|
echo "" |
|
echo "Enter 0 to scan ALL devices" |
|
echo "Enter number to show IP" |
|
echo "Press Enter or Ctrl+C to exit" |
|
echo -n "> " |
|
read -r choice |
|
|
|
[[ -z "$choice" ]] && break |
|
|
|
if [[ "$choice" == "0" ]]; then |
|
echo -e "\e[1;34mScanning all devices on LAN...\e[0m" |
|
scan_devices |
|
|
|
all_devs_display=("$self_ip $self_mac $self_name") |
|
for entry in "${all_devs[@]}"; do |
|
ip_only=$(echo "$entry" | awk '{print $1}') |
|
[[ "$ip_only" == "$self_ip" ]] && continue |
|
all_devs_display+=("$entry - -") |
|
done |
|
|
|
display_devices "${all_devs_display[@]}" |
|
echo -n "Press Enter to continue..." |
|
read -r |
|
|
|
elif [[ "$choice" =~ ^[0-9]+$ ]] && (( choice >= 1 && choice <= ${#devices[@]} )); then |
|
ip=$(echo "${devices[$((choice-1))]}" | awk '{print $1}') |
|
echo "$ip" |
|
echo -n "Press Enter to continue..." |
|
read -r |
|
else |
|
break |
|
fi |
|
done |