dotfiles/scripts/network-discovery.sh
rpriven 5b6af65def
Organize scripts and clean up dotfiles
Changes:
- Added 80+ scripts with organized structure
  - payloads/ for third-party pentesting tools
  - pentesting/ for custom security scripts
  - Daily drivers remain flat for fast access
- Converted wes() function to proper script
- Removed .sh extensions from pentesting scripts
- Cleaned up aliases (removed 31 redundant lines)
- Added kanata/, build artifacts to gitignore
- Removed old fre.sh scripts and empty a.out
- Updated configs: helix, tmux, zsh, ulauncher, redshift

Security: All sensitive data excluded via gitignore
2025-11-07 14:48:21 -07:00

476 lines
15 KiB
Bash
Executable file
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env bash
set -euo pipefail
# Script Name: network-discovery.sh
# Description: Discover devices on local network and highlight the newest device
# Version: 1.0.0
# Dependencies: arp-scan (or nmap), gum (optional but recommended)
# === Configuration ===
readonly SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
readonly VERSION="1.0.0"
readonly LOGFILE="${LOGFILE:-/tmp/$(basename "$0" .sh)-$$.log}"
# Ensure log file is writable
touch "$LOGFILE" 2>/dev/null || LOGFILE="/dev/null"
chmod 644 "$LOGFILE" 2>/dev/null || true
# Colors for output
readonly RED='\033[0;31m'
readonly GREEN='\033[0;32m'
readonly YELLOW='\033[1;33m'
readonly BLUE='\033[0;34m'
readonly CYAN='\033[0;36m'
readonly MAGENTA='\033[0;35m'
readonly BOLD='\033[1m'
readonly NC='\033[0m'
# === Logging Functions ===
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] [INFO] $*" | tee -a "$LOGFILE"
}
log_error() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] [ERROR] $*" | tee -a "$LOGFILE" >&2
}
log_warn() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] [WARN] $*" | tee -a "$LOGFILE"
}
# === Cleanup Handler ===
TEMP_FILES=()
cleanup() {
local exit_code=$?
# Clean temp files
for file in "${TEMP_FILES[@]}"; do
[[ -f "$file" ]] && rm -f "$file"
done
# Clean log file on successful completion
if [[ $exit_code -eq 0 ]] && [[ "$LOGFILE" != "/dev/null" ]]; then
rm -f "$LOGFILE" 2>/dev/null || true
fi
exit $exit_code
}
trap cleanup EXIT INT TERM
# === Dependency Checking ===
HAS_GUM=false
HAS_ARP_SCAN=false
SCAN_METHOD=""
check_dependencies() {
# Check for gum (optional) - check common locations
if command -v gum &>/dev/null; then
HAS_GUM=true
elif [[ -x "$HOME/go/bin/gum" ]]; then
HAS_GUM=true
export PATH="$HOME/go/bin:$PATH"
elif [[ -x "/home/e/go/bin/gum" ]]; then
HAS_GUM=true
export PATH="/home/e/go/bin:$PATH"
fi
# Check for scanning tools
if command -v arp-scan &>/dev/null; then
HAS_ARP_SCAN=true
SCAN_METHOD="arp-scan"
elif command -v nmap &>/dev/null; then
SCAN_METHOD="nmap"
log_warn "Using nmap (arp-scan recommended for better MAC detection)"
else
log_error "No network scanning tool found"
echo "Please install one of:"
echo " sudo apt install arp-scan (recommended)"
echo " sudo apt install nmap"
return 1
fi
return 0
}
# === UI Functions ===
show_header() {
clear
if [[ "$HAS_GUM" == "true" ]]; then
gum style \
--border thick \
--border-foreground 12 \
--align center \
--width 60 \
--margin "1" \
--padding "1 2" \
"🔍 NETWORK DEVICE DISCOVERY" \
"" \
"v${VERSION}" \
"Scanning local network..."
echo
else
echo -e "${BLUE}╔════════════════════════════════════════════════════╗${NC}"
echo -e "${BLUE}${NC} 🔍 ${BOLD}NETWORK DEVICE DISCOVERY${NC} ${BLUE}${NC}"
echo -e "${BLUE}${NC} ${BLUE}${NC}"
echo -e "${BLUE}${NC} v${VERSION} ${BLUE}${NC}"
echo -e "${BLUE}${NC} Scanning local network... ${BLUE}${NC}"
echo -e "${BLUE}╚════════════════════════════════════════════════════╝${NC}"
echo
fi
}
# === Network Functions ===
get_local_network() {
# Get the default gateway and derive network
local gateway
gateway=$(ip route | grep default | awk '{print $3}' | head -n1)
if [[ -z "$gateway" ]]; then
log_error "Could not determine default gateway"
return 1
fi
# Extract network (assumes /24)
local network
network=$(echo "$gateway" | cut -d. -f1-3)
echo "${network}.0/24"
}
scan_network_arp_scan() {
local network="$1"
local output_file="$2"
if [[ "$HAS_GUM" == "true" ]]; then
echo -e "${CYAN}🔍 Scanning network with arp-scan...${NC}"
(
sudo arp-scan --interface=eth0 --localnet 2>/dev/null || \
sudo arp-scan --interface=wlan0 --localnet 2>/dev/null || \
sudo arp-scan --localnet 2>/dev/null
) | tee "$output_file" &
local scan_pid=$!
# Spinner options: dot, pulse, points, minidot, line, jump, globe, moon, monkey, meter, hamburger
gum spin --spinner pulse --title "Scanning local network..." -- bash -c "while kill -0 $scan_pid 2>/dev/null; do sleep 0.1; done"
wait $scan_pid
else
echo -e "${CYAN}⏳ Scanning network with arp-scan...${NC}"
sudo arp-scan --localnet 2>/dev/null | tee "$output_file"
fi
}
scan_network_nmap() {
local network="$1"
local output_file="$2"
if [[ "$HAS_GUM" == "true" ]]; then
echo -e "${CYAN}🔍 Scanning network with nmap...${NC}"
(
sudo nmap -sn -PR "$network" 2>/dev/null
) | tee "$output_file" &
local scan_pid=$!
# Spinner options: dot, pulse, points, minidot, line, jump, globe, moon, monkey, meter, hamburger
gum spin --spinner pulse --title "Scanning local network..." -- bash -c "while kill -0 $scan_pid 2>/dev/null; do sleep 0.1; done"
wait $scan_pid
else
echo -e "${CYAN}⏳ Scanning network with nmap...${NC}"
sudo nmap -sn -PR "$network" 2>/dev/null | tee "$output_file"
fi
}
parse_arp_scan_results() {
local scan_file="$1"
local results_file="$2"
# Parse arp-scan output: IP, MAC, Vendor
# arp-scan format: 192.168.1.1 aa:bb:cc:dd:ee:ff Vendor Name
# Using pipe (|) as delimiter instead of comma to handle vendor names with commas
grep -E "([0-9]{1,3}\.){3}[0-9]{1,3}" "$scan_file" | \
grep -v "^Interface\|^Starting\|^Ending\|packets received" | \
awk '{
ip=$1
mac=$2
vendor=$3
for(i=4;i<=NF;i++) vendor=vendor" "$i
if(vendor=="") vendor="Unknown"
print ip"|"mac"|"vendor
}' > "$results_file"
}
parse_nmap_results() {
local scan_file="$1"
local results_file="$2"
# After nmap scan, check entire ARP cache for all discovered devices
log "Checking ARP cache for MAC addresses..."
# Get all IPs from nmap output
local found_ips=()
while read -r line; do
if [[ "$line" =~ "Nmap scan report for" ]]; then
local ip=$(echo "$line" | grep -oE '([0-9]{1,3}\.){3}[0-9]{1,3}')
[[ -n "$ip" ]] && found_ips+=("$ip")
fi
done < "$scan_file"
# Now get MAC addresses from ARP cache
for ip in "${found_ips[@]}"; do
# Check arp cache
local arp_line
arp_line=$(arp -n | grep "^$ip " 2>/dev/null)
if [[ -n "$arp_line" ]]; then
# Parse: 10.98.0.1 ether aa:bb:cc:dd:ee:ff C eth0
local mac
mac=$(echo "$arp_line" | awk '{print $3}')
# Try to get vendor info (might need additional lookup)
local vendor="Unknown"
if [[ "$mac" =~ ^([0-9a-fA-F]{2}:){5}[0-9a-fA-F]{2}$ ]]; then
# Valid MAC, try to identify device type
case "${mac:0:8}" in
"00:50:56"|"00:0c:29"|"00:05:69") vendor="VMware" ;;
"08:00:27") vendor="VirtualBox" ;;
"52:54:00") vendor="QEMU/KVM" ;;
*) vendor="Device" ;;
esac
fi
echo "${ip},${mac},${vendor}"
else
echo "${ip},Unknown,Unknown"
fi
done > "$results_file"
}
find_newest_device() {
local results_file="$1"
# Get current ARP cache with timestamps
local newest_ip=""
local newest_mac=""
local newest_vendor=""
local newest_age=999999
# Read results and check ARP cache age (using pipe delimiter)
while IFS='|' read -r ip mac vendor; do
[[ -z "$ip" ]] && continue
# Check if device is in ARP cache
if arp -n "$ip" &>/dev/null; then
# Most recently added device will be at the end of the list
# We'll use the last device found as "newest"
newest_ip="$ip"
newest_mac="$mac"
newest_vendor="$vendor"
fi
done < "$results_file"
# If no ARP cache method works, just take the last device from scan
if [[ -z "$newest_ip" ]]; then
local last_line
last_line=$(tail -n1 "$results_file")
newest_ip=$(echo "$last_line" | cut -d'|' -f1)
newest_mac=$(echo "$last_line" | cut -d'|' -f2)
newest_vendor=$(echo "$last_line" | cut -d'|' -f3)
fi
echo "${newest_ip}|${newest_mac}|${newest_vendor}"
}
display_results() {
local results_file="$1"
local newest_device="$2"
local newest_ip newest_mac newest_vendor
IFS='|' read -r newest_ip newest_mac newest_vendor <<< "$newest_device"
echo
if [[ "$HAS_GUM" == "true" ]]; then
gum style \
--border double \
--border-foreground 10 \
--padding "1" \
"📊 Discovered Devices"
echo
else
echo -e "${GREEN}╔══════════════════════════════════════════════════╗${NC}"
echo -e "${GREEN}${NC} 📊 Discovered Devices ${GREEN}${NC}"
echo -e "${GREEN}╚══════════════════════════════════════════════════╝${NC}"
echo
fi
# Header
printf "${BOLD}%-16s %-20s %-30s${NC}\n" "IP ADDRESS" "MAC ADDRESS" "VENDOR"
echo "────────────────────────────────────────────────────────────────────"
# Display all devices - use awk to do ALL the formatting
local device_count
device_count=$(wc -l < "$results_file" 2>/dev/null || echo 0)
# Use awk to format everything directly (avoids pipe/subshell issues)
awk -F '|' -v newest_ip="$newest_ip" \
-v MAGENTA="${MAGENTA}" -v CYAN="${CYAN}" -v YELLOW="${YELLOW}" \
-v GREEN="${GREEN}" -v BOLD="${BOLD}" -v NC="${NC}" \
'{
ip=$1
mac=$2
vendor=$3
if (ip == newest_ip) {
# Newest device - HIGHLIGHT IT!
printf "%s%s%-16s%s %s%s%-20s%s %s%-30s%s %s⭐ NEWEST%s\n", \
BOLD, MAGENTA, ip, NC, \
BOLD, CYAN, mac, NC, \
YELLOW, vendor, NC, \
GREEN, NC
} else {
printf "%-16s %-20s %-30s\n", ip, mac, vendor
}
}' "$results_file"
echo
echo -e "${BLUE}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
# Summary box
if [[ "$HAS_GUM" == "true" ]]; then
gum style \
--border rounded \
--border-foreground 10 \
--foreground 10 \
--padding "1" \
"✅ Scan Complete!" \
"" \
"Total devices found: ${device_count}" \
"Newest device: ${newest_ip}" \
"MAC Address: ${newest_mac}" \
"Vendor: ${newest_vendor}"
else
echo
echo -e "${GREEN}✅ Scan Complete!${NC}"
echo -e "${BOLD}Total devices found:${NC} ${device_count}"
echo
echo -e "${BOLD}${MAGENTA}Newest Device:${NC}"
echo -e " ${BOLD}IP:${NC} ${newest_ip}"
echo -e " ${BOLD}MAC:${NC} ${newest_mac}"
echo -e " ${BOLD}Vendor:${NC} ${newest_vendor}"
fi
echo
}
# === Usage Function ===
usage() {
cat << EOF
Usage: $(basename "$0") [OPTIONS]
Description:
Scan local network for devices and highlight the newest device
Options:
-h, --help Show this help message
-v, --verbose Enable verbose output
Examples:
sudo $(basename "$0")
sudo $(basename "$0") --verbose
Requirements:
- Must run with sudo (for network scanning)
- arp-scan or nmap installed
- gum (optional, for enhanced UI)
EOF
}
# === Main Logic ===
main() {
# Parse arguments
while [[ $# -gt 0 ]]; do
case "$1" in
-h|--help)
usage
exit 0
;;
-v|--verbose)
set -x
shift
;;
*)
log_error "Unknown option: $1"
usage
exit 1
;;
esac
done
# Check if running as root
if [[ $EUID -ne 0 ]]; then
log_error "This script must be run as root (for network scanning)"
echo "Please run: sudo $0"
exit 1
fi
# Check dependencies
check_dependencies || exit 2
# Show header
show_header
# Show arp-scan tip if using nmap
if [[ "$SCAN_METHOD" == "nmap" ]]; then
echo -e "${YELLOW}💡 Tip: Install arp-scan for better device detection${NC}"
echo -e "${YELLOW} Command: sudo apt install arp-scan${NC}"
echo
fi
# Get local network
log "Detecting local network..."
local network
network=$(get_local_network)
log "Network: $network"
echo -e "${BLUE} Network: ${BOLD}$network${NC}"
echo
# Create temp files
local scan_file results_file
scan_file=$(mktemp)
results_file=$(mktemp)
# Only add scan_file to cleanup - we need results_file until display is done
TEMP_FILES+=("$scan_file")
# Scan network
log "Scanning network with $SCAN_METHOD"
if [[ "$SCAN_METHOD" == "arp-scan" ]]; then
scan_network_arp_scan "$network" "$scan_file"
parse_arp_scan_results "$scan_file" "$results_file"
else
scan_network_nmap "$network" "$scan_file"
parse_nmap_results "$scan_file" "$results_file"
fi
# Check if we found any devices
if [[ ! -s "$results_file" ]]; then
log_error "No devices found on network"
exit 1
fi
# Find newest device
log "Analyzing results..."
local newest_device
newest_device=$(find_newest_device "$results_file")
# Display results
display_results "$results_file" "$newest_device"
# Clean up results file after display
rm -f "$results_file"
log "✅ Network discovery complete"
}
# Run main function
main "$@"