#!/usr/bin/env python

import os
import sys
import argparse
import tempfile
import shlex
import datetime
import shutil
from subprocess import Popen, PIPE

#styles for use throughout the report
def html_styles(stylesheet=""):
    #use a stylesheet if one is specified
    if (stylesheet != ""):
        sspath = get_tempfile()
        shutil.copyfile(stylesheet, sspath)
        print "<link href=\"%s\" media=\"screen\" rel=\"stylesheet\" type=\"text/css\" />" % sspath
    else:
        #default styles
        print """
            <style>
                body {
                    font-size: 10pt;
                }
                td {
                    font-family: courier;
                    font-size: 8pt;
                }
            </style> 
        """
    
    #support for sortable tables -  see http://www.kryogenix.org/code/browser/sorttable/
    print "<script src=\"http://www.kryogenix.org/code/browser/sorttable/sorttable.js\"></script>"
    

#this is the html header
def html_head(sTitle, sStylesheet):
    print "<html><head><title>%s</title></head>" % sTitle
    html_styles(sStylesheet)
    print "<body>"

#this is the html footer
def html_foot():
    print "</body></html>"

#handle command line stuff
def handle_cmd_line():
    desc = """ra2html generates incident report and graphs from argus files.

"""
    
    parser = argparse.ArgumentParser(description=desc)
    parser.add_argument('-f, --file', required=True, dest="input_file", help="argus file to read", metavar="FILE")
    parser.add_argument("-t,--title", dest="title", help="set report title")
    parser.add_argument("--top-talkers", dest="top_talkers", help="calculate top talkers", type=int, default=0)
    parser.add_argument("--totals", action="store_true", dest="totals", help="calculate totals")
    parser.add_argument("--target", action="append", dest="target", help="perform individual analysis for specific addresses")
    parser.add_argument("-s", dest="stylesheet", help="use a custom css stylesheet", default="")
    (args) = parser.parse_args()
    
    #check preflight conditions
    if (args.input_file == None ):
        parser.print_help()
        sys.exit(0)

    #set a title of none exists
    if (args.title == None):
        args.title = "Report for %s" % args.input_file


    return ( args)
    
#generate top talker information
def get_top_talkers(file, num):
    cmd = "/usr/local/bin/racluster -r %s -w - -m daddr " % (file)
    clusterproc = Popen(shlex.split(cmd), stdout=PIPE)

    cmd = "/usr/local/bin/rasort -r - -nnn -m bytes -N%s -s daddr:128 bytes pkts" % num
    sortproc = Popen(shlex.split(cmd),stdin=clusterproc.stdout, stdout=PIPE)
    
    data = sortproc.communicate()[0]
    return data

#generate totals
def get_totals(file):
    cmd = "/usr/local/bin/racount -M proto -r %s " % file
    countproc = Popen(shlex.split(cmd), stdout=PIPE)
    data = countproc.communicate()[0]
    return data

def generate_flow_graph(file, target=""):
    tempfile = get_tempfile()
    
    title = "Network Flow History"
    sFilterPortion = ""
    if (target != ""):
        sFilterPortion = " - host %s" % target
    cmd = "/usr/local/bin/ragraph bytes -r %s -M 30s -fill -stack -w %s %s" % (file, tempfile, sFilterPortion)
    graphproc = Popen(shlex.split(cmd), stdout=PIPE)

    return tempfile

def history_analysis(file, target=""):
    #the primary argus query
    sFilterPortion = ""
    if (target != ""):
        sFilterPortion = " - host %s " % target
    cmd="/usr/local/bin/ra -u -nnn -r %s -s stime saddr:128 sport:16 daddr:128 dport:16 proto bytes pkts %s" % (file, sFilterPortion)
    p = Popen(shlex.split(cmd), stdout=PIPE)
    
    #get data from stdout
    data = p.stdout
    sFlowGraph = generate_flow_graph(file, target)
    print "<center><img src=\"%s\"></center><br>" % sFlowGraph
    print "<table id='flow_table' class='sortable'>"
    print "<tr><th>Timestamp</th><th>Source</th><th>Destination</th><th>Protocol</th><th>Packets</th><th>Bytes</th></tr>"
    
    for line in data:
        split = line.split()
        print "<tr>"
        for i in range(len(split)):
            if i == 0:
                print "<td>%s</td>" % datetime.datetime.fromtimestamp(int(split[i].split(".")[0])).strftime('%Y-%m-%d %H:%M:%S')
            else:
                print "<td>%s</td>" % split[i]
            
        print "</tr>"
        
    print "</table>"    


#generate temp file path
def get_tempfile():
    (tf, path) =  tempfile.mkstemp()
    return path

##########################
#entrypoint
##########################
(args) = handle_cmd_line()


#what time is it?
now = datetime.datetime.now()


#print header
html_head(args.title, args.stylesheet)
print "<div id=\"header\"><h1>%s</h1></div>" % args.title
print "Generated %s by ra2html" % now.strftime("%Y-%m-%d %H:%M")

#should we generate top talker statistics?
if (args.top_talkers > 0):
    print "<h2>Top Talkers</h2>"
    print "<table>"
    print "<tr><th>Destination Address</th><th>Bytes</th><th>Packets</th></tr>"
    ttl = get_top_talkers(args.input_file, args.top_talkers)
    for talker in ttl.split("\n"):
        split = talker.split()
        if (len(split) == 3):
            print "<tr><td>%s</td><td>%s</td><td>%s</td></tr>" % (split[0], split[1], split[2])
    print "</table>"
    
#should we generate totals?
if (args.totals == True):
    print "<h2>Totals</h2>"
    totals = get_totals(args.input_file)
    print "<pre>%s</pre>" % totals

if (args.target != None):
    targets = args.target
    if (len(targets) > 0):
        for target in targets:
            print "<h2>%s</h2>" % target
            history_analysis(args.input_file, target)

#do a history analysis for the entire file
print "<h2>All Flows</h2>"
history_analysis(args.input_file)
    
#print footer
html_foot()
