#!/usr/local/bin/perl
use warnings;
use strict;
#############################
# PBNJ Plugin: Grapher      #
# By: Ventz Petkov          #
# Email: ventz@ccs.neu.edu  #
# Date: 11-16-05            #
# License: Creative Commons #
#############################
use lib '/sw/lib/perl5/5.8.6/';     # place location of GD Graph stuff
use Getopt::Long;
use GD::Graph;
use LWP::Simple;

# Global Declares and command line arguments
my (%opt, $argc, $filein, $fileout, $htmlurl, $htmlout, @hours);

# Ports for which graphs should be generated
# Makre sure all the ports here are DEF in the bottom structure too!
my @list_of_html_ports = (22, 25, 80);

GetOptions (\%opt, 'about', 'help', 'info', 'filein=s', 'fileout=s', "htmlurl=s", "htmlout=s");
&main;


# Check for correct usage. If incorrect, show "help"
sub main {
    if ($opt{'htmlurl'}) {
        if($opt{'htmlout'}) {
            $htmlurl = $opt{'htmlurl'};
            $htmlout = $opt{'htmlout'};
            &grapher2html;
        }
        else {
            &help;
        }
    }
    elsif ( $opt{'filein'} and (-e $opt{'filein'}) and (-r $opt{'filein'}) ) {
        if($opt{'fileout'}) {
            $filein = $opt{'filein'};
            $fileout = $opt{'fileout'};
            &parse;
        }
        else {
            &help;
        }
    }
    elsif ( $opt{'about'} or $opt{'help'} or $opt{'info'} ) {
        &help;
    }
    else {
        &help;
    }
}





# Help sub. Shows Usage, Options, and About
sub help {
    print "\n";
    print "Usage:\n";
    print "\t plugin_grapher --filein /dir/ip_quick.csv --fileout graph.cgi\n";
    print "\t and then\n";
    print "\t plugin_grapher --htmlurl http://host/graph.cgi --htmlout grapher2html\n\n";
    print "Options:\n";
    print "\t CGI CREATION (from output file)\n"; 
    print "\t -------------------------------\n";
    print "\t --filein FILE \t\t File input to start parsing data for graph\n";
    print "\t --fileout FILE \t File output to write cgi code for graph\n\n\n";
    print "\t HTML GENERATOR (from cgi url)\n"; 
    print "\t -----------------------------\n";
    print "\t --htmlurl URL \t\t Web URL of the generated CGI\n";
    print "\t --htmlout FOLDER \t Output folder for the generated html page\n";
    print "\t --help \t\t Help (this screen), also: --about or --info\n\n";
    print "About:\n";
    print "\t Grapher Module (c) Ventz Petkov for the PBNJ (c) Joshua Abraham\n";
    print "\t So first and foremost, this plug-in is independent from\n";
    print "\t PBNJ (Ports Banners 'N Junk) (c) jabra\@ccs.neu.edu. Even\n";
    print "\t though it has been written for PBNJ, it could just as well\n";
    print "\t work with any other program if the input file is formated:\n";
    print "\t ('host_description','hostname','ip','port1:port2:etc','hour')\n";
    print "\t It has two main uses:\n";
    print "\t 1.) It will take this file that's a parsed out port scan in and\n";
    print "\t     the format specified above, and take an output filename, and\n";
    print "\t     it will generate a cgi script which can provide a graph for\n";
    print "\t     any port (being one at a time) given the p=PORTNUMBER parameter\n";
    print "\t 2.) The second use will take the url of the cgi created from the\n";
    print "\t     first step and take an output folder, and dump in it all of\n";
    print "\t     the images from the cgi script and generate an html file which\n";
    print "\t     loads all the pictures.\n";
    print "\t More features to come later... ~ Ventz\n";
    print "\t \n";
    print "\n\n";
    exit;
}


sub parse {
    open(FP, $filein) || die "Could not open $filein for input because: $!\n";
    open(OUT, ">$fileout") || die "Could not open $fileout for output because: $!\n";

    # Start writing the CGI file!
    print OUT "#!/usr/local/bin/perl\n";
    print OUT "# AUTO GENERATED from Grapher Plugin for PBNJ\n";
    print OUT "use warnings;\n";
    print OUT "use strict;\n";
    print OUT "use lib '/sw/lib/perl5/5.8.6/';\n";
    print OUT "use CGI;\n";
    print OUT "use CGI::Carp qw(fatalsToBrowser);\n";
    print OUT "use GD::Graph::mixed;\n";
    print OUT "use GD::Text;\n";
    print OUT "my \$cgi = new CGI;\n";
    print OUT "our \$p = ''; my \@graphData;\n";
    print OUT "if(defined(\$cgi->param('p'))) { \$p = \$cgi->param('p'); }\n";

    ###################################
    ### NOTE: to add a new service: ###
    ###################################
    # 1. Add an array with it's service name to the my () part bellow
    # 2. Add a $found_servicename="no"; 
    # 3. Add a section to the if..elsif loop
    # 4. Add a if($found_servicename eq "no") { push(@servicename, 0); }
    # 5. Add the part of the array into the cgi file with a for loop.
    # 6.) Add a line so that the array can be added to the Graph Data! Done!!


    # Parse out the Log Data!
    # 1.)
    my ($global_host, $global_ip, @ssh, @smtp, @http);
    while(<FP>) {
        chomp;
        my($os, $host, $ip, $port, $date, $hour) = split(",", $_);
        my @ports = split(":", $port);
        $global_host = $host; $global_ip = $ip; 
        # 2.)
        my $found_ssh = "no"; my $found_smtp = "no"; my $found_http = "no";

        push(@hours, $hour);
        # 3.)
        for(@ports) {
            if($_ eq "22") {
                push(@ssh, 1);
                $found_ssh = "yes";
                last;
            }
            elsif($_ eq "25") {
                push(@smtp, 1);
                $found_smtp = "yes";
                last;
            }
            elsif($_ eq "80") {
                push(@http, 1);
                $found_http = "yes";
                last;
            }
        }
        # 4.)
        if($found_ssh eq "no") { push(@ssh, 0); }
        if($found_smtp eq "no") { push(@smtp, 0); }
        if($found_http eq "no") { push(@http, 0); }
    }

    # Add Graph sources to the CGI file!
    # the hours - this is defaultly needed for everything
    print OUT "my \@hours = (";
    for(@hours) { print OUT "'$_',"; }
    print OUT ");\n";
    
    #####################
    # ADD SERVICES HERE #
    #####################
    # 5.)
    # the ssh port
    print OUT "my \@ssh = ("; for(@ssh) { print OUT "$_,"; } print OUT ");\n";
    # the smtp port
    print OUT "my \@smtp = ("; for(@smtp) { print OUT "$_,"; } print OUT ");\n";
    # the http port
    print OUT "my \@http = ("; for(@http) { print OUT "$_,"; } print OUT ");\n";
    #####################


    # Add the Graph stuff to the CGI file!
    # 6.)
    print OUT "if(\$p eq '22') { \@graphData = ([\@hours], [\@ssh]); }\n";
    print OUT "elsif(\$p eq '25') { \@graphData = ([\@hours], [\@smtp]); }\n";
    print OUT "elsif(\$p eq '80') { \@graphData = ([\@hours], [\@http]); }\n";

    print OUT "else { print \$cgi->header; print \$cgi->h3('Please provide a specific port! For ex: <u>$fileout?p=22</u>'); exit; }\n";
    my $length = @hours; my $xSize = $length * 30; 
    print OUT "my \$graph = GD::Graph::mixed->new($xSize, 70);\n";
    print OUT "\$graph->set(\n";
    print OUT "title => \"Port Scan (\$p) for: $global_ip\",\n";
    print OUT "types => [ qw(linespoints) ],\n";
    print OUT "dclrs => [ qw(red) ],\n";
    print OUT "x_ticks => 1,\n";
    print OUT "y_tick_number => 2,\n";
    print OUT "y_label_skip => 1,\n";
    print OUT "y_min_value => 0,\n";
    print OUT "y_max_value => 2,\n";
#print OUT "long_ticks => 1,\n";
    print OUT "line_width => 2,\n";
    print OUT "markers => [ 5,5 ],\n";
    print OUT "marker_size => 3,\n";
    print OUT "legend_placement => 'BM'\n";
    print OUT ");\n";
    print OUT "\$graph->set_legend('1 = OPEN Port & 0 = CLOSED Port');\n";
    print OUT "my \$image = \$graph->plot(\\\@graphData) or die 'Error!';\n";
    print OUT "print \$cgi->header('image/png');";
    print OUT "print \$image->png;\n";
    
    chmod 0755, $fileout;
    close(FP);
    close(OUT);
}


# Generate a folder grapher2html and place images and html file.
sub grapher2html {
    # Get url, add the port parameter, and determine cgi script name 
    my $url = $htmlurl;; $url .= "?p=";
    my @url_parts = split("/", $url);
    my $cginame = pop(@url_parts);

    # Prepare the dir
    mkdir $htmlout; chdir $htmlout;

    # Go through the ports and grab the image for each
    for my $port (@list_of_html_ports) {
        print "Downloading Image for port: $port...";
        getstore("$url$port", "$port.png") || die "Could Not download $url$port because $!\n";
        print "Complete! Image Stored as: $port.png\n";
    }
    print "Done\n";

    print "Generating HTML page...";
    open(FP, ">index.html");
    print FP "<html>\n<head><title>Grapher2HTML Page</title></head>\n";
    print FP "<body>\n\n";
    for my $port (@list_of_html_ports) {
        print FP "<img src=\"$port.png\"><br><p>\n";
    }
    print FP "</body>\n</html>\n";
    close(FP);
    print "Complete!\n";
    exit;
}
