Last active
February 2, 2024 18:47
-
-
Save FlyingFathead/944ee5194eb1526d125aff5d06eb0cb8 to your computer and use it in GitHub Desktop.
scanlan / a quick LAN scanning script for diagnostics
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 | |
# | |
# >>> SCANLAN <<< | |
# | |
# this script can used for i.e. checking out what's on your LAN | |
# requires `nmap`, `xmlstarlet` and `lolcat` (just because) | |
# adjust to your own ip range as needed. | |
# NO WARRANTIES, use only for your own LAN diagnostics and at your own risk | |
# | |
# | |
# program info | |
scanlan_ver='v0.82 -- 02 Feb. 2024 (c) 2021-2024 FlyingFathead' | |
# set horizontal line | |
function viibla() { | |
printf '%*s\n' "${COLUMNS:-$(tput cols)}" '' | tr ' ' - ; | |
} | |
function viivo() { | |
printf '%*s\n' "${COLUMNS:-$(tput cols)}" '' | tr ' ' - | lolcat -f; | |
} | |
# set different echo modes | |
function ekho() { | |
echo -e "::: \e[0m$1" | |
} | |
function ekko() { | |
echo -e "::: \e[1m$1\e[0m" | |
} | |
function ekk0() { | |
echo -e "\e[1m$1\e[0m" | lolcat -f ; | |
} | |
# redefine terminal colors using octal escape | |
prn_pun="\033[31m" # red | |
prn_vih="\033[32m" # green | |
prn_kel="\033[93m" # yellow | |
prn_val="\033[97m" # white | |
prn_reset="\033[0m" # reset | |
# function to check for required dependencies | |
check_dependency() { | |
if ! command -v "$1" &> /dev/null | |
then | |
echo "Error: $1 is not installed." >&2 | |
echo "Please install $1 and try again." >&2 | |
exit 1 | |
fi | |
} | |
# check each dependency | |
check_dependency "nmap" | |
check_dependency "xmlstarlet" | |
check_dependency "lolcat" | |
# set our log files + their directory | |
scanlanlog_dir="$HOME/.logs/scanlan" | |
scanlanlog_file="$(date +"%Y_%m_%d___%H_%M-%S").log" | |
export scanlanlog_dir | |
export scanlanlog_file | |
# nmap in xml output mode | |
nmap_xml_output="$scanlanlog_dir/nmap_scan_$(date +"%Y_%m_%d___%H_%M-%S").xml" | |
export nmap_xml_output | |
# Define the IP range to scan | |
ip_range="192.168.100.0/24" | |
export ip_range | |
# define the scan command and its arguments as an array | |
scan_command=(sudo nmap -sS -O -v -oX "$nmap_xml_output" "$ip_range") | |
function set_log_dirs() { | |
# create logfile directory if it's not around | |
if [ ! -d "$scanlanlog_dir" ]; then | |
viibla && | |
echo "[INFO] $scanlanlog_dir -- directory doesn't exist, creating it." && | |
mkdir -p "$scanlanlog_dir" && | |
viibla | |
fi | |
## | |
if [ ! -d "$scanlanlog_dir" ]; then | |
viibla && | |
ekko "$prn_pun" '[ERROR!]' "$scanlanlog_dir -- unable to create directory!" && | |
ekko "$prn_pun" '[ERROR!]' "Exiting!" && | |
viibla && | |
exit 0 | |
fi | |
# file-friendly date = $(date +"%Y_%m_%d___%H_%M-%S").log | |
export scanlanlog_file | |
} | |
# function to highlight default gateway and _gateway entries | |
highlight() { | |
local default_gw="$1" | |
local red="${prn_pun}" | |
local yellow="${prn_kel}" | |
local reset="${prn_reset}" | |
awk -v default_gw="$default_gw" -v red="$red" -v yellow="$yellow" -v reset="$reset" ' | |
{ | |
# Check if the line contains the default gateway as a whole word | |
if ($0 ~ "\\<" default_gw "\\>") { | |
gsub("\\<" default_gw "\\>", red default_gw reset); | |
} | |
if (index($0, "_gateway") != 0) { | |
gsub("_gateway", yellow "_gateway" reset); | |
} | |
print; | |
}' | |
} | |
# function to list local ip's | |
function list_local_ips() { | |
ekko "Local Network Interfaces and IP Addresses:" && | |
viivo && | |
# Use `ip` command to list IPs for all interfaces | |
ip -br address | awk '$1 != "lo" {print $1, $3}' | while read -r interface ip_address; do | |
echo -e "Interface: \e[1m$interface\e[0m, IP Address: $ip_address" | |
done | |
viivo && | |
echo "" | |
} | |
# function to scan the LAN | |
function scanlan() { | |
echo "" && echo "" && | |
viivo && | |
ekk0 "::: SCANLAN - $scanlan_ver" && | |
viivo && | |
# run the sudo check | |
ekko "This tool must be run as 'sudo'. If prompted, enter your sudo password." && | |
viibla && | |
sudo echo "" && | |
echo "" && | |
# notes ... | |
# export output to log _with_ ANSI codes ===>>> | |
# exec > >(tee -i "$scanlanlog_dir/$scanlanlog_file") | |
# export output to log _without_ ANSI codes ===>>> | |
# | |
# logging ... | |
exec > >( tee >( sed 's/\x1B\[[0-9;]*[JKmsu]//g' >> "$scanlanlog_dir/$scanlanlog_file" ) ) | |
exec 2>&1 | |
viibla && | |
ekho "Log started into: $scanlanlog_dir/$scanlanlog_file" | |
viibla && | |
# Read default gateways into an array and remove duplicates | |
readarray -t defugateways < <(/sbin/ip route | awk '/default/ { print $3 }' | sort -u) | |
# Output the gateways and check for multiple gateways | |
if [ ${#defugateways[@]} -gt 1 ]; then | |
# Join the array elements into a comma-separated string | |
gateway_str=$(IFS=, ; echo "${defugateways[*]}") | |
# Display a warning message in red if multiple gateways are detected | |
ekko "$prn_pun[WARNING] Multiple default gateways detected with 'ip route': $gateway_str" | |
elif [ ${#defugateways[@]} -eq 1 ]; then | |
# Display the single gateway | |
ekko "Default gateway according to 'ip route': ${defugateways[0]}" | |
else | |
# No gateways found | |
ekko "No default gateway found" | |
fi | |
viibla && | |
ekko "Plain results from 'ip route':" && | |
viibla && | |
ip route && | |
viibla && | |
ekko "ARP check, from 'arp':" | |
viibla && | |
arp | highlight "$default_gateway" | |
viibla && | |
ekko "Note: Default gateway should be shown highlighted in red, other gateways (i.e. ones marked as '_gateway') in yellow." | |
viibla && | |
echo "(NOTE: The table shows the IP addresses in the left column, and MAC addresses in the middle. If the table contains two different IP addresses that share the same MAC address, then you are probably undergoing an ARP poisoning attack [unless you are using very special types of routings or setups, such as multiple NIC's etc.])" && | |
viibla && | |
ekko "Scanning the LAN with: $(printf '%s ' "${scan_command[@]}")" && | |
viibla && | |
"${scan_command[@]}" | |
echo "" && | |
echo "" && | |
viivo && | |
ekko "SCANLAN finished at: $(date)" | |
ekko "SCANLAN results log at: $scanlanlog_dir/$scanlanlog_file" | |
viivo && | |
# process the XML output to list active systems and their details | |
if command -v xmlstarlet >/dev/null; then | |
ekko "Active LAN IP's and their details:" | |
viivo && | |
xmlstarlet sel -t -m "//host[status/@state='up']" \ | |
-v "address[@addrtype='ipv4']/@addr" -o " " \ | |
-v "address[@addrtype='mac']/@addr" -o " (" \ | |
-v "address[@addrtype='mac']/@vendor" -o ")" -n \ | |
-m "ports/port" -o " Open Port: " -v "@portid" \ | |
-o " (" -v "state/@state" -o ", " -v "service/@name" -o ")" -n \ | |
-m "os/osmatch" -o " OS Estimate: " -v "@name" -n \ | |
"$nmap_xml_output" | while read -r line; do | |
if [[ $line =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+ ]]; then | |
echo -e "\e[1mIP: $line\e[0m" # Highlight IP in bold | |
else | |
echo "$line" # Normal output for other lines | |
fi | |
done | |
else | |
echo "xmlstarlet is not installed. Can't process the XML output. You can install xmlstarlet with: 'sudo apt-get install xmlstarlet'" | |
fi | |
# call the function to list local IPs | |
list_local_ips | |
viivo && | |
# done. | |
# query to read the scan log | |
while true | |
do | |
read -r -p "Read the log now (answering [n]o will quit)? [Y/n] " input | |
case $input in | |
[yY][eE][sS]|[yY]) | |
less "$scanlanlog_dir/$scanlanlog_file" && | |
echo "" && | |
viivo && | |
echo "" | |
break | |
;; | |
[nN][oO]|[nN]) | |
exit 0 | |
break | |
;; | |
*) | |
echo "Invalid input!" | |
;; | |
esac | |
done | |
echo "" | |
} | |
# run the main program => | |
# set the log file + directory | |
set_log_dirs | |
# run the scan | |
scanlan | |
# display results | |
viivo && | |
ekko "SCANLAN results log at: $scanlanlog_dir/$scanlanlog_file" | |
viivo && | |
# more reading | |
function info() { | |
printf " | |
More reading at: | |
https://nmap.org/book/osdetect-usage.html -- Usage. | |
" | |
viivo | |
} | |
# EOF |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment