Created
August 8, 2025 14:58
-
-
Save lilithebowman/8a1c4346981b4e083ff13d625d319a2a to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
# findpeers.sh - Discover peers on your subnet when connected to WiFi | |
# Usage: ./findpeers.sh [options] | |
set -e | |
# Colors for output | |
RED='\033[0;31m' | |
GREEN='\033[0;32m' | |
YELLOW='\033[1;33m' | |
BLUE='\033[0;34m' | |
CYAN='\033[0;36m' | |
NC='\033[0m' # No Color | |
# Default values | |
FAST_SCAN=false | |
VERBOSE=false | |
SHOW_HELP=false | |
PING_TIMEOUT=1 | |
NMAP_AVAILABLE=false | |
# Check if nmap is available | |
if command -v nmap >/dev/null 2>&1; then | |
NMAP_AVAILABLE=true | |
fi | |
show_help() { | |
echo "findpeers.sh - Discover peers on your subnet when connected to WiFi" | |
echo "" | |
echo "Usage: $0 [options]" | |
echo "" | |
echo "Options:" | |
echo " -f, --fast Fast scan (ping only, no port scanning)" | |
echo " -v, --verbose Verbose output" | |
echo " -h, --help Show this help message" | |
echo "" | |
echo "Requirements:" | |
echo " - Must be connected to WiFi" | |
echo " - nmap (optional, for enhanced scanning)" | |
echo "" | |
echo "Install nmap with: brew install nmap" | |
} | |
# Parse command line arguments | |
while [[ $# -gt 0 ]]; do | |
case $1 in | |
-f|--fast) | |
FAST_SCAN=true | |
shift | |
;; | |
-v|--verbose) | |
VERBOSE=true | |
shift | |
;; | |
-h|--help) | |
show_help | |
exit 0 | |
;; | |
*) | |
echo "Unknown option: $1" | |
show_help | |
exit 1 | |
;; | |
esac | |
done | |
log_verbose() { | |
if [[ "$VERBOSE" == true ]]; then | |
echo -e "${CYAN}[VERBOSE]${NC} $1" | |
fi | |
} | |
log_info() { | |
echo -e "${BLUE}[INFO]${NC} $1" | |
} | |
log_success() { | |
echo -e "${GREEN}[SUCCESS]${NC} $1" | |
} | |
log_warning() { | |
echo -e "${YELLOW}[WARNING]${NC} $1" | |
} | |
log_error() { | |
echo -e "${RED}[ERROR]${NC} $1" | |
} | |
# Check if connected to WiFi | |
check_wifi_connection() { | |
log_verbose "Checking WiFi connection..." | |
# Get WiFi interface name | |
WIFI_INTERFACE=$(networksetup -listallhardwareports | awk '/Wi-Fi|AirPort/{getline; print $2}' | head -1) | |
if [[ -z "$WIFI_INTERFACE" ]]; then | |
log_error "No WiFi interface found" | |
exit 1 | |
fi | |
log_verbose "WiFi interface: $WIFI_INTERFACE" | |
# Check if WiFi interface has an IP address (more reliable than networksetup) | |
WIFI_IP=$(ifconfig "$WIFI_INTERFACE" | grep 'inet ' | awk '{print $2}' | head -1) | |
if [[ -z "$WIFI_IP" ]]; then | |
log_error "WiFi interface has no IP address. Please connect to a WiFi network first." | |
exit 1 | |
fi | |
# Try to get network name, but don't fail if we can't | |
WIFI_STATUS=$(networksetup -getairportnetwork "$WIFI_INTERFACE" 2>/dev/null) | |
if [[ "$WIFI_STATUS" == *"You are not associated with an AirPort network"* ]] || [[ -z "$WIFI_STATUS" ]]; then | |
# Fallback: try to get SSID using airport command | |
NETWORK_NAME=$(/System/Library/PrivateFrameworks/Apple80211.framework/Versions/Current/Resources/airport -I 2>/dev/null | awk -F': ' '/^\s*SSID:/ {print $2}') | |
if [[ -z "$NETWORK_NAME" ]]; then | |
NETWORK_NAME="Unknown Network" | |
fi | |
else | |
NETWORK_NAME=$(echo "$WIFI_STATUS" | sed 's/Current Wi-Fi Network: //') | |
fi | |
log_info "Connected to WiFi network: ${GREEN}$NETWORK_NAME${NC} (IP: ${GREEN}$WIFI_IP${NC})" | |
} | |
# Get local IP and subnet | |
get_network_info() { | |
log_verbose "Getting network information..." | |
# Get the active WiFi interface IP | |
LOCAL_IP=$(ifconfig "$WIFI_INTERFACE" | grep 'inet ' | awk '{print $2}' | head -1) | |
if [[ -z "$LOCAL_IP" ]]; then | |
log_error "Could not determine local IP address" | |
exit 1 | |
fi | |
# Get subnet mask and convert to decimal if needed | |
NETMASK_RAW=$(ifconfig "$WIFI_INTERFACE" | grep 'inet ' | awk '{print $4}' | head -1) | |
# Convert hex netmask to dotted decimal | |
if [[ "$NETMASK_RAW" == 0x* ]]; then | |
# Convert hex to decimal, then to dotted notation | |
NETMASK_HEX=${NETMASK_RAW#0x} | |
NETMASK=$(printf "%d.%d.%d.%d\n" \ | |
$((0x${NETMASK_HEX:0:2})) \ | |
$((0x${NETMASK_HEX:2:2})) \ | |
$((0x${NETMASK_HEX:4:2})) \ | |
$((0x${NETMASK_HEX:6:2}))) | |
else | |
NETMASK="$NETMASK_RAW" | |
fi | |
# Convert netmask to CIDR | |
CIDR=$(echo "$NETMASK" | awk -F. '{ | |
cidr = 0 | |
for (i = 1; i <= 4; i++) { | |
if ($i == 255) cidr += 8 | |
else if ($i == 254) cidr += 7 | |
else if ($i == 252) cidr += 6 | |
else if ($i == 248) cidr += 5 | |
else if ($i == 240) cidr += 4 | |
else if ($i == 224) cidr += 3 | |
else if ($i == 192) cidr += 2 | |
else if ($i == 128) cidr += 1 | |
else break | |
} | |
print cidr | |
}') | |
# Calculate network address (simplified for common cases) | |
NETWORK=$(echo "$LOCAL_IP" | awk -F. -v cidr="$CIDR" '{ | |
if (cidr >= 24) { | |
print $1 "." $2 "." $3 ".0" | |
} else if (cidr >= 16) { | |
print $1 "." $2 ".0.0" | |
} else { | |
print $1 ".0.0.0" | |
} | |
}') | |
SUBNET="$NETWORK/$CIDR" | |
log_info "Local IP: ${GREEN}$LOCAL_IP${NC}" | |
log_info "Subnet: ${GREEN}$SUBNET${NC}" | |
log_verbose "Netmask: $NETMASK" | |
} | |
# Ping scan function | |
ping_scan() { | |
local subnet=$1 | |
local found_hosts=() | |
log_info "Starting ping scan on $subnet..." | |
# Extract network portion and CIDR | |
local network=$(echo "$subnet" | cut -d'/' -f1) | |
local cidr=$(echo "$subnet" | cut -d'/' -f2) | |
# Calculate IP range based on common subnet sizes | |
local base_ip=$(echo "$network" | cut -d'.' -f1-3) | |
local start=1 | |
local end=254 | |
if [[ "$cidr" -eq 24 ]]; then | |
# /24 network - scan .1 to .254 | |
start=1 | |
end=254 | |
elif [[ "$cidr" -eq 16 ]]; then | |
# /16 network - limit scan to current /24 block for performance | |
local last_octet=$(echo "$LOCAL_IP" | cut -d'.' -f4) | |
log_warning "Large /16 network detected. Limiting scan to current /24 block for performance." | |
fi | |
log_verbose "Scanning IP range: $base_ip.$start to $base_ip.$end" | |
# Parallel ping scan | |
for i in $(seq $start $end); do | |
{ | |
local ip="$base_ip.$i" | |
if ping -c 1 -W $PING_TIMEOUT "$ip" >/dev/null 2>&1; then | |
echo "$ip" | |
fi | |
} & | |
# Limit concurrent processes | |
if (( $(jobs -r | wc -l) >= 50 )); then | |
wait | |
fi | |
done | |
# Wait for all background jobs to complete | |
wait | |
} | |
# Enhanced scan with nmap | |
nmap_scan() { | |
local subnet=$1 | |
log_info "Starting enhanced nmap scan on $subnet..." | |
log_verbose "Running: nmap -sn $subnet" | |
# Host discovery scan | |
nmap -sn "$subnet" 2>/dev/null | grep -E "Nmap scan report|MAC Address" | while read -r line; do | |
if [[ "$line" == *"Nmap scan report"* ]]; then | |
echo "$line" | awk '{print $5}' | |
elif [[ "$line" == *"MAC Address"* ]] && [[ "$VERBOSE" == true ]]; then | |
echo " └─ $line" | |
fi | |
done | |
} | |
# Get hostname and additional info | |
get_host_info() { | |
local ip=$1 | |
local hostname="" | |
local mac="" | |
local ports="" | |
# Try to get hostname | |
hostname=$(nslookup "$ip" 2>/dev/null | grep "name =" | awk '{print $4}' | sed 's/\.$//' | head -1) | |
if [[ -z "$hostname" ]]; then | |
hostname=$(dig +short -x "$ip" 2>/dev/null | sed 's/\.$//' | head -1) | |
fi | |
# Get MAC address if possible (only works for same subnet) | |
mac=$(arp -n "$ip" 2>/dev/null | awk '{print $4}' | head -1) | |
# Basic port scan if not fast mode and nmap available | |
if [[ "$FAST_SCAN" == false ]] && [[ "$NMAP_AVAILABLE" == true ]]; then | |
log_verbose "Port scanning $ip..." | |
ports=$(nmap -F --open "$ip" 2>/dev/null | grep "/tcp" | head -3 | awk '{print $1}' | tr '\n' ',' | sed 's/,$//') | |
fi | |
# Format output | |
local output="$ip" | |
if [[ -n "$hostname" ]]; then | |
output="$output (${GREEN}$hostname${NC})" | |
fi | |
if [[ -n "$mac" ]] && [[ "$mac" != "(incomplete)" ]]; then | |
output="$output [MAC: $mac]" | |
fi | |
if [[ -n "$ports" ]]; then | |
output="$output [Ports: $ports]" | |
fi | |
echo -e " $output" | |
} | |
# Main scanning function | |
scan_network() { | |
local hosts=() | |
echo "" | |
log_info "Scanning for active hosts..." | |
echo "" | |
if [[ "$NMAP_AVAILABLE" == true ]] && [[ "$FAST_SCAN" == false ]]; then | |
log_verbose "Using nmap for enhanced scanning" | |
while IFS= read -r host; do | |
if [[ -n "$host" ]]; then | |
hosts+=("$host") | |
fi | |
done < <(nmap_scan "$SUBNET") | |
else | |
if [[ "$NMAP_AVAILABLE" == false ]]; then | |
log_warning "nmap not found. Using basic ping scan. Install with: brew install nmap" | |
fi | |
log_verbose "Using ping scan" | |
while IFS= read -r host; do | |
if [[ -n "$host" ]]; then | |
hosts+=("$host") | |
fi | |
done < <(ping_scan "$SUBNET") | |
fi | |
# Sort hosts by IP | |
IFS=$'\n' hosts=($(sort -V <<<"${hosts[*]}")) | |
echo "" | |
if [[ ${#hosts[@]} -eq 0 ]]; then | |
log_warning "No active hosts found on the network" | |
return | |
fi | |
log_success "Found ${#hosts[@]} active host(s):" | |
echo "" | |
# Get detailed info for each host | |
for host in "${hosts[@]}"; do | |
if [[ "$host" == "$LOCAL_IP" ]]; then | |
echo -e " $host (${YELLOW}this device${NC})" | |
else | |
get_host_info "$host" | |
fi | |
done | |
echo "" | |
} | |
# Print summary | |
print_summary() { | |
echo "" | |
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" | |
echo "" | |
log_info "Scan completed!" | |
echo "" | |
if [[ "$NMAP_AVAILABLE" == false ]]; then | |
echo "💡 Tip: Install nmap for enhanced scanning capabilities:" | |
echo " ${CYAN}brew install nmap${NC}" | |
echo "" | |
fi | |
if [[ "$FAST_SCAN" == false ]] && [[ "$NMAP_AVAILABLE" == true ]]; then | |
echo "💡 Use ${CYAN}-f${NC} or ${CYAN}--fast${NC} for quicker scans (ping only)" | |
echo "" | |
fi | |
} | |
# Main execution | |
main() { | |
echo "" | |
echo "🔍 WiFi Peer Discovery Script" | |
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" | |
check_wifi_connection | |
get_network_info | |
scan_network | |
print_summary | |
} | |
# Run main function | |
main "$@" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment