Subnet Scan Bash Script
This file contains 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 | |
# Requires: ifconfig, ping, arp, date, wc, jq, and jc | |
if [[ $1 == "" ]]; then | |
echo "Please enter the interface name as command argument." | |
echo | |
echo "Options:" | |
# Only show interfaces with an assigned IP address | |
jc ifconfig | jq -r '.[] | select(.ipv4_addr != null) | .name' | |
exit 1 | |
fi | |
tempName=$(basename "$0") | |
tempFile=$(mktemp /tmp/"$tempName".XXXXXX) || exit 1 | |
# Grab interface IP and Subnet Mask | |
interfaceInfo=$(jc ifconfig "$1") || exit 1 | |
ip=$(jq -r '.[0].ipv4_addr' <<<"$interfaceInfo") | |
mask=$(jq -r '.[0].ipv4_mask' <<<"$interfaceInfo") | |
# Grab detailed subnet information for the IP/Mask | |
ipInfo=$(jc --ip-address <<<"$ip/$mask") | |
network=$(jq -r '.network' <<<"$ipInfo") | |
numHosts=$(jq -r '.hosts' <<<"$ipInfo") | |
cidrMask=$(jq -r '.cidr_netmask' <<<"$ipInfo") | |
firstHostIp=$(jq -r '.first_host' <<<"$ipInfo") | |
lastHostIp=$(jq -r '.last_host' <<<"$ipInfo") | |
firstHost=$(jq -r '.int.first_host' <<<"$ipInfo") | |
lastHost=$(jq -r '.int.last_host' <<<"$ipInfo") | |
if [[ $numHosts -gt 1022 ]]; then | |
echo "Subnet is too large ($numHosts IPs). Exiting." | |
exit 1 | |
fi | |
# Grab the start time in ISO and Unix Epoch format | |
startTime=$(jc date) | |
startTimeIso=$(jq -r '.iso' <<<"$startTime") | |
startTimeEpoch=$(jq -r '.epoch' <<<"$startTime") | |
echo "My IP: $ip/$cidrMask" | |
echo "Sending ICMP requests to $numHosts IPs: $firstHostIp - $lastHostIp" | |
echo "Start Time: $startTimeIso" | |
# Loop through each IP. Use decimal value to easily iterate and convert to | |
# standard notation when using the ping command | |
for (( ipDecimal=firstHost; ipDecimal<=lastHost; ipDecimal++ )); do | |
# Do each ping in the background for parallel processing | |
{ | |
# grab the packets received and rtt values from the ping output | |
thisIp=$(jc --ip-address <<<"$ipDecimal" | jq -r '.ip') | |
pingResult=$(ping -c1 "$thisIp" | jc --ping) | |
packetsReceived=$(jq -r '.packets_received' <<<"$pingResult") | |
rtTime=$(jq -r '.round_trip_ms_max' <<<"$pingResult") | |
if [[ $packetsReceived -gt 0 ]]; then | |
# Grab the MAC address and name for each alive host from the arp command | |
thisIpArpInfo=$(arp -a | jc --arp | jq --arg myip "$thisIp" '.[] | select(.address == $myip)') | |
thisIpMac=$(jq -r '.hwaddress // empty' <<<"$thisIpArpInfo") | |
thisIpName=$(jq -r '.name // empty' <<<"$thisIpArpInfo") | |
printf "%9.3f ms %-16s%-20s%s\n" "$rtTime" "$thisIp" "$thisIpMac" "$thisIpName" | tee -a "$tempFile" | |
fi | |
} & | |
done | |
wait | |
# Grab the end time in ISO and Unix Epoch format (for easy calculation) | |
endTime=$(jc date) | |
endTimeIso=$(jq -r '.iso' <<<"$endTime") | |
endTimeEpoch=$(jq -r '.epoch' <<<"$endTime") | |
totalTime=$((endTimeEpoch-startTimeEpoch)) | |
# Grab the total lines of the temp output file, which equals the | |
# number of alive hosts | |
totalAlive=$(jc wc "$tempFile" | jq '.[0].lines') | |
rm "$tempFile" | |
echo "Scanned $network/$cidrMask subnet in $totalTime seconds." | |
echo "$totalAlive alive hosts found." | |
echo "End Time: $endTimeIso" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment