#!/bin/bash 
#
CMD=$(basename $0)
CMDVER="1.0"
CMDSTR="$CMD v$CMDVER (2025-01-04)"

set -e -u

usage()
{
	echo "
== $CMDSTR = fast network scanner using nmap ==

usage: $CMD { network | --local }

. network must be in CIDR notation (eg: 192.160.1.0/24)
. CIDR default netmask is /24 if not present
" >&2
	exit 1
}



# (MAIN)

net=

case ${1:-} in
  "")
  	usage
	;;
  -l|--local)
	ip=$(ip address | grep 'inet ' | grep -v 127\.0\.0 | tail -1)
	ip=$(echo "$ip" | sed -e 's/.*inet //' -e 's/ .*//')
	net=$(ipcalc --nocolor --nobinary $ip | grep 'Network: ' \
		| sed -e 's/Network:  *//' -e 's/ .*//')
	;;
   */*)
   	net=$1
	;;
   *)
	net=$1/24
	;;
esac

script='
  @ip = ();
  @name = ();
  @mac = ();
  @brand = ();
  @latency = ();
  $idx = -1;
  $l_ip = 0;
  $l_name = 0;
  $l_lat = 0;

  while (<>) {
    chomp();

    #Nmap scan report for kelvin.core.klabs (1.2.3.4)		WITH FQDN
    #Host is up (0.00020s latency).
    #MAC Address: 70:85:C2:9C:68:A3 (ASRock Incorporation)	OPTIONAL

    # or
    #Nmap scan report for 1.2.3.4				NO FQDN
    #Host is up							NO LATENCY


    if ($_ =~ /scan report for/) {
    	$idx++;
    	$name[$idx]	= "";
    	$mac[$idx]	= "";
    	$brand[$idx]	= "";
    	$latency[$idx]	= "";

	s/.*report for //;
	if ($_ =~ /\(/) {
		s/[()]//g;

		@tmp	= split(/ +/);

		$ip[$idx]	= $tmp[1];
		$name[$idx]	= $tmp[0];
    		if (length($name[$idx]) > $l_name) {
    			$l_name = length($name[$idx]);
    		}
    	} else {
		$ip[$idx]	= $_;
	}
    	if (length($ip[$idx]) > $l_ip) {
    		$l_ip = length($ip[$idx]);
    	}

    }

    if ($_ =~ /MAC Addr/) {
    	s/MAC Address: //;
	if ($_ =~ /\(/) {
		@tmp	= split(/ +/);
		$mac[$idx]	= $tmp[0]; shift(@tmp);
		$mac[$idx]	= lc($mac[$idx]);
		$brand[$idx]	= join( " ", @tmp );
        	$brand[$idx]	=~ s/^\(//g;
        	$brand[$idx]	=~ s/\)$//g;
	} else {
		$mac[$idx]	= $_;
	}
    }
    if ($_ =~ /Host is up.*latency/) {
    	s/.*\(//;
	s/ .*//;
	$latency[$idx] = $_;
    	if (length($latency[$idx]) > $l_lat) {
    		$l_lat = length($latency[$idx]);
    	}
    }
  }

  $fmt	= "%-${l_ip}s";
  @out	= ();

  if ($l_name) {
  	$fmt .= " %-${l_name}.${l_name}s";
	push(@out,"FQDN");
  }
  if (l_lat) {
  	$fmt .= " %-${l_lat}.${l_lat}s";
	push(@out,"LATENCY");
  }

  $fmt	.= " %-17.17s %s\n";
  push(@out,"MAC");
  push(@out,"BRAND");

  printf( $fmt, "IP", @out );

  for ($idx=0; $idx<$#ip; $idx++) {
  	@out	= ();
	push(@out,$name[$idx])		if ($l_name);
	push(@out,$latency[$idx])	if ($l_lat);
	push(@out,$mac[$idx]);
	push(@out,$brand[$idx]);
	printf( $fmt, $ip[$idx], @out );
  }

'

echo -en " scanning network: $net ...\r" >&2
out=$(nmap -sn $net)
echo -en "                                                            \r" >&2

echo "$out" | perl -e "$script"
exit 0
