#! /usr/bin/env bash
#
# ipscan: little helper for ip/dns network scan
#
# run: `ipscan -h` to get help
#
# Release: 1.0 of 2023/03/10
# 2023, Joseph Maillardet
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU  General Public License
# along with this program.  If not, see <https://www.gnu.org/licenses/>.

### Changelog
# 1.0 - Initial release

set -euo pipefail

myself=$(basename "$0")

display() { printf "%s\n" "$1"; }

error() {
	display "Error: $1" >&2
	[ -z "${2-}" ] || exit "$2";
}

usage() {
	cat <<- EOF
		Usage: $myself [-f|-n] [-h] [-r DNS.IP] NETWORK/MASK
		Where:
			-f, scan network with fping
			-n, scan network with nmap (default)
			-h, show this help
			-r, use the specified DNS resolver
			
			DNS.IP: the IP address of the DNS resolver to use
			NETWORK: the IP address of the network to scan
			MASK: the mask of the network to scan (/8, /16, /24…)
	EOF
}

# Dash options checking
OPTS=$(getopt -o fnr:h -n "$myself" -- "$@") \
        || error "getopt failed with error code: $?" 1
eval set -- "$OPTS"

resolver=""
comm="nmap"

while true; do
        case "${1-}" in
                -f) comm="fping"; display "Using fping"; shift ;;
                -n) shift ;;
                -h|--help|h|help) usage; exit 0 ;;
                -r) resolver="$2"; display "Using resolver: $resolver"; shift 2 ;;
                --) shift; break ;;
                *) break ;;
        esac
done

if [[ "${1-}" =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}/[0-9]{1,2}$ ]]; then

	used_network="$1"

else

	used_interface=$(ip r | grep default | cut -d' ' -f5)
	used_network=$(ip r | grep "$used_interface" | grep -v default | cut -d' ' -f1)

fi

for network in $used_network; do

	printf "\nScanning network: %s\n\n" "$network"

	if [ "$comm" = "fping" ]; then

		[ -x $(which fping) ] || error "Need fping, try: sudo apt install fping" 1
		while read -r ip; do
			display "$ip - $(host "$ip" $resolver | grep pointer | awk '{print $5}')"
		done < <(fping -a -g "$network" 2>/dev/null)

	else # nmap par défaut

		[ -x $(which nmap) ] || error "Need nmap, try: sudo apt install nmap" 2
		nmap -sn "$network" | grep '^Nmap' | sed 's,Nmap scan report for ,,'
		# TODO
		# nmap -v -sn <- if -p like progress, with filtering :
		# cat nmap-10.2.log | grep -v -E '(\[host down\]|Host is up)' | sed 's,^Nmap scan report for \([^(]*\) (\([^)]*\))$,\2 - \1,'

	fi

done

exit 0
