#!/usr/bin/perl
#
# $Revision 1.50 $
# General network tests and logging.
#
#
# NOTES:
# 1) Add DNS or dig type testing.
# 6) Create a TUI interface ?
# 7) Create log file parser.. maybe create a graph output.
# 9) Change sub stats to except input ie; eth0, eth1, lo ect.
# 10) Scan network and log all active hosts with nmap and create network map ?.
# 12) Be able to send to multiple email address.
# 14) be able to list the address to be tested something like --list
#     that would show the address contained in @host_array.
# 15) Be able to add subtract above address from the command line.
# 17) Do ping test with and without DNS.
#
# 18) Add option to display test output instead of logging. maybe --disp.
# 19) Be able to set the "sleep" time from a command line parameter.
# 20) log packet loss.
#


use strict;
use warnings;
use Net::Ping;
use LWP::Simple;
use Time::HiRes qw(tv_interval gettimeofday);
use POSIX;
use Getopt::Long;
use File::Basename;
use Sys::Hostname;

my $progname = basename($0);
my $host;
my $count = 0;
my $speed = 0;
my $help = 0;
my $version = 0;
my $ver = "1.50";
my $wanip = 0;
my @host_array = ();
my $logmsg = "";
my $trace = "";
my $teleflora = "tws.teleflora.com";
my $nmap = "";
my $portlist = "";
my $sleep = 60;
my $stats = 0;
my $scan = "";
my $interface = "eth0";
my $email = "";
my $recipient = "";
my $message = "";
my $examples = 0;
my $path = "/tmp/";
my $today = strftime("%d", localtime());
my $tomorrow = strftime("%d", localtime());
my $file = "Network_Test-Day_$today.log";
my $hostname = hostname; 
my $subject = "Nettest Scan Results from $hostname";
my $ping = "";
my $disp = "";
my $pktloss = "";

#################################################################
# Add new addresses to scan.	
#
push (@host_array,"192.168.1.1");
#push (@host_array,"192.168.1.51");
push (@host_array,"192.168.1.21");
push (@host_array,"www.yahoo.com");
push (@host_array,"igusproda.globalpay.com");
push (@host_array,"igusprodb.globalpay.com");
#
##################################################################


GetOptions(
	"help" => \$help,
	"version" => \$version,
	"count=s" => \$count,
	"wanip" => \$wanip,
	"stats" => \$stats,
	"email=s" => \$email,
	"speed" => \$speed,
	"trace=s" => \$trace,
	"examples" => \$examples,
	"scan=s" => \$scan,
	"ping" => \$ping,
	"disp" => \$disp,
	"sleep=i" => \$sleep,
	"pktloss" => \$pktloss
);

if($help != 0) {
	usage();
	exit(0);
}

if($version != 0) {
	print("\n");
	print("$progname v$ver\n");
	print("\n");
	exit(0);
}

if($count != 0) {
	main($count);
	exit(0);
}

if($sleep == 0) {
	$sleep=60;
}

if($wanip !=0) {
	wanip();
	print("$wanip $hostname\n");
	exit(0);
}

if("$email" ne "") {
	if(-e "$path$file") { 
		loginfo("\n");
		loginfo("     -- Emailed results to $email\n");
		email();
		exit(0);
	} else {
		print("Error No File to Email\n");
		exit(1);
	}
}

if("$examples" != 0) {
	examples();
	exit(0);
}

usage();
exit(0);



######################################################################
######################################################################

sub main 
{
	my $time = $count*$sleep;
	
	loginfo("     -- Test Started Nettest v$ver\n");
	wanip();
	loginfo("info -- Test will run for $time seconds\n");
	while ($count >= 1 ) {
		loginfo("\n");
		if("$scan" ne "") {
			nmap();
		}		
		if("$trace" ne "") {
			trace();
		}
		if($stats != 0) {
			stats();
		}
		if("$ping" ne "") {
			ping();
		}
		if("$speed" ne "") {
			speed();
		}
		if("$pktloss" ne "") {
			pktloss();
		}
		if("$disp" ne "") {
			system('clear');
			system("tail -n20  $path$file"); 
		}


	$count --;
	sleep $sleep;
	}

	loginfo("\n");
	loginfo("     -- Test Complete\n");
	if("$email" ne "") {	
		if(-e "$path$file") {
		loginfo("\n");
		loginfo("     -- Emailed results to $email\n");
		email();
	} 
	exit(0);	
}
}

sub email
{
        open(MUTT, "| mutt -s \"$subject\" $email < $path$file");
        print(MUTT $message);
        close(MUTT);
}

sub stats 
{
	my $loop = 1;
	my @RX = ();
	my @TX = ();
	my $rec = "";
	my $send = "";
	my $delay = 5;
	my $rx = "";
	my $tx = "";
	
	while ($loop <=2) {
	open(ETH, "/sbin/ethtool -S $interface |");
	while(<ETH>) {
		chomp;
		if(/(rx_bytes:)(\s+)/) {
			$rx =$_; 
			$rx =~ s/^\s+//;
			$rx =~ s/rx_bytes: //;
			$RX[$loop] = int($rx);
		}
		if(/(tx_bytes:)(\s+)/) {
			$tx =$_;
			$tx =~ s/^\s+//;
			$tx =~ s/tx_bytes: //;
			$TX[$loop] = int($tx);
		}
	}
	close(ETH);
	sleep 1;
	$loop ++;
	}
	$rec = int($RX[2]) - int($RX[1]);
	$send = int($TX[2]) - int($TX[1]);
	loginfo("ip   -- Traffic on interface $interface\n");
	loginfo("Tx   -- Tx Bytes/sec = $send\n");
	loginfo("Rx   -- Rx Bytes/sec = $rec\n");
}

sub usage
{
	print(<< "EOF");

$progname Usage:
$progname --version   -- Print version.
$progname --help      -- This output.
$progname --count     -- Number of tests to perform. Delay between tests is 60sec.
$progname --wanip     -- Print/Log Wan IP address.
$progname --stats     -- Print/Log tx/rx bytes on ethx. Requires --count.
$progname --scan      -- Performs Nmap scan. Requires --count.
$progname --ping      -- Performs Ping test. Requires --count.
$progname --disp      -- Displays output to screen. Requires --count.
$progname --email     -- Email test results.
   	                  You can receive an email of the test results
		          by adding the option --email=me\@somewhere.com.
		          Existing results can also be emailed without 
		          preforming a test first.
$progname --speed     -- Test download speed. Requires --count.
$progname --trace     -- Tcp traceroute. Requires --count.
			  --trace=IP/Host address.
$progname --examples  -- Show command examples.


EOF
}

sub examples
{
	print(<< "EOF");

Example: $progname --count=2 --ping --email=me\@somewhere.com
	 This will ping for 2 minutes and send an email when complete.

Example: $progname --email=me\@somewhere.com
	 This example will email an existing log.

Example: $progname --count=x --stats
	 This example will measure in bytes the traffic on $interface.

Example: $progname --count=x --trace=65.245.5.36 or
	 $progname --count=x --trace=yahoo.com
	 This example will perform a tcp traceroute to the target IP.

Example: $progname --count=x --scan=target:portlist
	 $progname --count=x --scan=tws.teleflora.com:80,81,22-25
	 $progname --count=x --scan=65.245.5.36:80,81,22-25
	 This example will use Nmap to perform a tcp scan of target IP or URL.
	 Followed by a : and ports to scan. Ports can be entered as 80,22 or
	 22-80 or 80,82,22-40.

Example: $progname --count=x --speed
         This example will test the download speed of your internet connection.
         A test file of 10meg is downloaded from a web site in Dallas Tx.

EOF
}

sub wanip
{
	open(PIPE, "curl -s http://www.ipchicken.com/ |");
	while(<PIPE>){
		chomp;
		if($_ =~ /([\d]+)\.([\d]+)\.([\d]+)\.([\d]+)/){
			$wanip = $_ ;
			$wanip =~ s/^\s+//;
			$wanip =~ s/\s+//;
			$wanip =~ y/[<br>]//d;
			$wanip =~ s/\r//g
		}
	}
	close(PIPE);
	loginfo("ip   -- $wanip $hostname\n");
}

sub loginfo
{
	my $timestamp = strftime("%Y-%m-%d %H:%M:%S", localtime());
	open(LOGFILE, ">> /tmp/Network_Test-Day_$today.log");
	print(LOGFILE "$timestamp -- @_");
	close(LOGFILE);
}

sub speed
{
#	my $start = gettimeofday();
#	get("http://rtihardware.homelinux.com/ostools/testfile.txt");
#	my $end = gettimeofday();
#	my $delta = ($end - $start);
	my $time = 0;
#	$time = sprintf("%.3f", $time);
	$time=`curl -w %{speed_download} -s -o /dev/null http://speedtest.wdc01.softlayer.com/downloads/test10.zip`;	
	
	$time = (($time*8)/1000000);
	loginfo("ip   -- Download speed = $time Megs/sec\n");
	loginfo("\n");
}

sub trace
{
	my $tracert = "";
	#
	# traceroute -n = don't resolve host names.
	# -T use tcp instead of udp.
	# -n don't resolve names.
	# -N 30 create 30 simultaneous connections.
	# -q 1 send only one test packet to each hop.
	# -w 1 wait a max of 1 sec for responces.
	#
	open(PIPE, "/bin/traceroute -nT -N30 -q1 -w1 $trace|grep -v traceroute |");
	loginfo("     -- \n");
	loginfo("ip   -- Starting traceroute to $trace\n");
	loginfo("ip   -- \n");
	while(<PIPE>){
		chomp;
		$tracert = $_ ;
		loginfo("ip   -- $tracert\n");
	}
	loginfo("     -- \n");
	loginfo("ip   -- End traceroute to $trace\n");
	close(PIPE);
}	

sub ping
{
	my $timeelapsed = "";
	my $timestart = "";
	my $pingtest = "";

	$pingtest = Net::Ping->new('icmp');
	foreach $host (@host_array) {
    		$timestart = [gettimeofday()];
  		if ($pingtest->ping($host, 2)) {
       		$timeelapsed = tv_interval($timestart, [gettimeofday()]);
		loginfo(sprintf("up   -- %s: %.3f msec\n", $host, $timeelapsed * 1000));
    		} else {
       		$timeelapsed = tv_interval($timestart, [gettimeofday()]);
       		loginfo(sprintf("down -- %s: %.3f\n", $host, $timeelapsed * 1000));
    		}
	}
	$pingtest->close();
}

sub nmap
{
	my $port = "";
	my $status = "";
	my $nmap_results = "";
	my @data = ();
	my $address = "";

	@data = split(/:/, $scan);
		if(( $data[0] !~ /([\d]+)\.([\d]+)\.([\d]+)\.([\d]+)/) && 
		( $data[0] !~ /^((http:\/\/|https:\/\/)?\w+\.\w+(\.\w{2,4})?\.\w{2,4}).+$/ )) {
			print ("Error ! Address $data[0] not in a valid format\n");
			print ("Address format must be xxx.xxx.xxx.xxx or www.yahoo.com, .net ect\n");
			exit(1);
		};
	$address = $data[0];
	if( "$data[1]" eq "" ) {
		print ("Error ! No ports to scan\n");
		print ("Correct format is address:ports\n");
		exit(1);
	}
 
	$portlist = $data[1];

	loginfo("     -- Nmap Scan Started\n");
	loginfo("\n");
	open(PIPE, "/usr/bin/nmap -P0 $address -p$portlist 2>/dev/null |");
	while(<PIPE>){
		chomp;
		$nmap_results = $_ ;
		if($nmap_results =~ /(open)|(closed)|(filtered)/){
			($port,$status,) = split(/ /);
                	$logmsg = "Nmap : \n";
                	$logmsg .= " \"$port\"\n";
			loginfo("$status -- $address port $port\n");
			
		} 
	}
	close(PIPE);
	loginfo("\n");
	loginfo("     -- Nmap Scan Complete\n");
}

sub pktloss
{

}
