In [ ]:
import struct, socket
import numpy as np
import linecache, bisect
import csv
import operator
import json
import os
import pandas as pd
try:
    import ipywidgets as widgets # For jupyter/ipython >= 1.4
except ImportError:
    from IPython.html import widgets
from IPython.display import display, Javascript, clear_output

with open('/etc/spot.conf') as conf:
    for line in conf.readlines():            
        if "DBNAME=" in line: DBNAME = line.split("=")[1].strip('\n').replace("'","");      
        elif "IMPALA_DEM=" in line: IMPALA_DEM = line.split("=")[1].strip('\n').replace("'",""); 

spath = os.getcwd()
path = spath.split("/") 
date = path[len(path)-1]   
dpath = '/'.join(['data' if var == 'ipynb' else var for var in path]) + '/'
cpath = '/'.join(['context' if var == 'ipynb' else var for var in path][:len(path)-2]) + '/'

sconnect = dpath + 'flow_scores.csv'
threats_file = dpath + 'threats.csv'
iploc = cpath + 'iploc.csv'
nwloc = cpath + 'networkcontext_1.csv'
anchor = ''
ir_f = ''
threat_name = ''
iplist = ''
top_results = 20
details_limit = 1000
if os.path.isfile(iploc):
    iplist = np.loadtxt(iploc,dtype=np.uint32,delimiter=',',usecols={0}, converters={0: lambda s: np.uint32(s.replace('"',''))})
else:
    print "No iploc.csv file was found, Map View map won't be created"

In [ ]:
# Widget styles and initialization
topBox = widgets.Box()
bottomBox = widgets.Box()
mainBoxes_css = (
    (None, 'width', '90%'),
    (None, 'margin', '0 auto'),
)

topBox._css = mainBoxes_css
bottomBox._css = mainBoxes_css 

separator = widgets.HBox(width='100%', height='20px')
threatBox = widgets.HBox(width='100%', height='auto')
threat_title = widgets.HTML(height='25px', width='100%')
threat_list_container = widgets.Box(width='80%', height='100%')
threat_button_container = widgets.Box(width='20%', height='100%')
susp_select = widgets.Select(height='100%', width='99%')
search_btn = widgets.Button(description='Search',height='100%', width='65px')
search_btn.button_style = 'primary'
susp_select._css = (
    (None, 'height', '90%'),
    (None, 'width', '95%'),
    ('select', 'overflow-x', 'auto'),
    ('select', 'margin', 0)
)

resultSummaryBox = widgets.Box()
result_title = widgets.HTML(width='100%')
result_summary_box = widgets.HBox(width='100%')
result_summary_container = widgets.Box(width='80%')
result_button_container =  widgets.Box(width='20%')
result_summary_box.children = [result_title, result_summary_container, result_button_container]
 
resultTableBox = widgets.HBox()
result_box_css = (
    (None, 'overflow', 'hidden'),
    (None, 'width', '100%'),
)

resultSummaryBox._css = result_box_css
resultTableBox._css = result_box_css
 
result_content_box_css = (
    (None, 'overflow','auto'), 
    (None, 'width', '50%'),
)

threat_button_container._css = (
    (None, 'padding-top', '30px'), 
)  

topBox.children = [threatBox]
bottomBox.children = [resultSummaryBox,resultTableBox]

Functions Definition


In [ ]:
top_inbound_b='' 
top_outbound_b=''
top_twoway_b=''

inbound='' 
outbound=''
twoway=''

global src_per_conns
global src_per_bytes
global dst_per_conns
global dst_per_bytes

def start_investigation(): 
    display(Javascript("$('.widget-area > .widget-subarea > *').remove();"))   
    external_ips = []
    c_ips=[]
    clear_output() 
    
    if os.path.isfile(threats_file) and not file_is_empty(threats_file):
        with open(threats_file, 'r') as th:
            t_read = csv.DictReader(th, delimiter='|') 
            for row in t_read: 
                if row['ip'] != '' : c_ips.append(row['ip']) 

    with open(sconnect, 'r') as f:
        reader = csv.DictReader(f, delimiter=',') 
        #Internal Netflows use case:
        for row in reader: 
            if row['sev'] == '1':
                srcIP = ''
                dstIP = '' 
                if row['srcIP'] not in external_ips and row['srcIP'] not in c_ips: 
                    external_ips.append(row['srcIP'])
                if row['dstIP'] not in external_ips and row['dstIP'] not in c_ips: 
                    external_ips.append(row['dstIP'])

    if len(external_ips) == 0:
        display(widgets.Box((widgets.HTML(value="There are no connections scored as High risk.\
            You can score some connections at the 'Suspicious' panel.", width='100%'),)))
    else:  
        sorted_dict = sorted(external_ips, key=operator.itemgetter(0))      
        display_controls(sorted_dict)   
        
        

def display_controls(threat_list):        
    threat_title.value ="<h4>Suspicious Connections</h4>"    
    susp_select.options = threat_list
    susp_select.height=150
    susp_select.selected_label = threat_list[0]
    threat_list_container.children = [threat_title,susp_select]
    threat_button_container.children = [search_btn]
    threatBox.children = [threat_list_container, threat_button_container]
    display(topBox) 
    
    def search_ip(b):
        global anchor 
        global top_inbound_b
        anchor = susp_select.value   
        if anchor != "":
            clear_output()        
            removeWidget(1)
            print "Searching for ip: " + anchor
            global ir_f 
            ir_f = dpath + "ir-" + anchor + ".tsv"

            if not os.path.isfile(ir_f) or (os.path.isfile(ir_f) and file_is_empty(ir_f)):  
                imp_query = (" \"SELECT min(treceived) as firstSeen, max(treceived) as lastSeen, sip as srcIP, dip as dstIP, " + 
                "sport as SPort, dport AS Dport, count(sip) as conns, max(ipkt) as maxPkts, avg(ipkt) " + 
                "as avgPkts, max(ibyt) as maxBytes, avg(ibyt) as avgBytes FROM "+DBNAME+".flow WHERE " + 
                "y="+ date[0:4] +" AND m="+ date[4:6] +" AND d="+ date[6:] +" " + 
                " AND (sip =\'" + anchor + "\'  OR dip=\'" + anchor + "\') GROUP BY sip, dip,sport,dport\" ") 
                !impala-shell -i $IMPALA_DEM --quiet -q "INVALIDATE METADATA"
                !impala-shell -i $IMPALA_DEM --quiet --print_header -B --output_delimiter='\t' -q $imp_query -o $ir_f
            clear_output()
            
            if not file_is_empty(ir_f):               
                print "\n Looking for additional details..."
                display_threat_box(anchor)

                get_in_out_and_twoway_conns() 
                add_geospatial_info()
                add_network_context() 
                
                display(bottomBox)     
            else:
                display(widgets.Box((widgets.HTML(value="Something went wrong. \
                    The expanded search couldn't be performed", width='100%'),)))
                        
    search_btn.on_click(search_ip)


def display_threat_box(ip):
    clear_output()
    result_title.value="<h4 class='spot-text-wrapper spot-text-xlg' data-toggle='tooltip'>Threat summary for " + anchor +"</h4>"
    tc_txt_title = widgets.Text(value='', placeholder='Threat Title', width='100%')
    tc_txa_summary = widgets.Textarea(value='', height=100, width='95%')
    tc_btn_save = widgets.Button(description='Save', width='65px', layout='width:100%')
    tc_btn_save.button_style = 'primary'
     
    tc_txt_title._css = (
        (None, 'width', '95%'),
    )
    
    result_summary_container.children = [tc_txt_title, tc_txa_summary]
    result_button_container.children=[tc_btn_save]
    result_summary_box.children = [result_summary_container, result_button_container]
    resultSummaryBox.children = [result_title,result_summary_box]
    
    def save_threat_summary(b):
        clear_output()        
        removeWidget(1) 
        response = ""
        response += generate_attack_map_file(anchor, top_inbound_b, top_outbound_b, top_twoway_b)
        response += generate_stats(anchor, inbound, outbound, twoway, threat_name)
        response += generate_dendro(anchor, inbound, outbound, twoway, date)
        response += details_inbound(anchor, top_inbound_b, top_outbound_b, top_twoway_b)
        response += add_threat(anchor, tc_txt_title.value, tc_txa_summary.value.replace('\n', '\\n'))
        response += "Story board successfully created for {0}".format(anchor)
        start_investigation()
        display(widgets.Box((widgets.HTML(value=response, width='100%'),)))
        
        
    tc_btn_save.on_click(save_threat_summary)

In [ ]:
def details_inbound(anchor, inbound, outbound, twoway):
    top_keys = []
    if len(twoway) > 0: top_keys.extend(twoway.keys())
    if len(outbound) > 0: top_keys.extend(outbound.keys()) 
    if len(inbound) > 0: top_keys.extend(inbound.keys())
    sbdet_f = dpath + "sbdet-" + anchor + ".tsv"
    if not os.path.isfile(sbdet_f):
        imp_query = ("\"SELECT min(treceived) as tstart, max(treceived) as tend, sip as srcIP, "
            + "dip as dstIP, proto as Proto, sport as SPort, dport AS Dport,ipkt as "
            + "Pkts, ibyt as Bytes  FROM "+DBNAME+".flow WHERE "
            + "y="+ date[0:4] +" AND m="+ date[4:6] +" AND d="+ date[6:]
            + " AND ((dip IN({0}) AND sip ='{1}') OR "
            + "(sip IN({0}) "
            + "AND dip ='{1}')) GROUP BY sip, dip, proto, sport, dport, ipkt, ibyt ORDER BY tstart "
            + "LIMIT {2}\" ")  
        ips = "'" + "','".join(top_keys) + "'"
        imp_query = imp_query.format(ips,anchor,details_limit)
        !impala-shell -i $IMPALA_DEM --quiet -q "INVALIDATE METADATA"
        !impala-shell -i $IMPALA_DEM --quiet --print_header -B --output_delimiter='\t' -q $imp_query -o $sbdet_f

        clear_output()
        return "Timeline successfully created <br/>"
    else:
        return "Timeline file already existed <br/>"

        
def generate_dendro(ip, inbound, outbound, twoway, date):  
    dendro_fpath = dpath + 'threat-dendro-' + anchor + ".json"
    
    obj = {
        'name':ip,
        'children': [],
        'time': date        
    }
    
    #----- Add Inbound Connections-------#
    if len(inbound) > 0:
        obj["children"].append({'name': 'Inbound Only', 'children': [], 'impact': 0})    
        in_ctxs = {}
        for ip in inbound:
            if 'nwloc' in inbound[ip] and len(inbound[ip]['nwloc']) > 0:
                ctx = inbound[ip]['nwloc'][2] # get the machine type Only for vast Data
                if ctx not in in_ctxs:
                    in_ctxs[ctx] = 1
                else:
                    in_ctxs[ctx] += 1
        for ctx in in_ctxs:
            obj["children"][0]['children'].append({
                    'name': ctx,
                    'impact': in_ctxs[ctx]
                })         
    
    #------ Add Outbound ----------------#
    if len(outbound) > 0:
        obj["children"].append({'name': 'Outbound Only', 'children': [], 'impact': 0})
        out_ctxs = {}
        for ip in outbound:       
            if 'nwloc' in outbound[ip] and len(outbound[ip]['nwloc']) > 0:
                ctx = outbound[ip]['nwloc'][2] # get the machine type Only for vast Data
                if ctx not in out_ctxs:
                    out_ctxs[ctx] = 1
                else:
                    out_ctxs[ctx] += 1
        for ctx in out_ctxs:
            obj["children"][1]['children'].append({
                    'name': ctx,
                    'impact': out_ctxs[ctx]
                }) 
    
    #------ Add TwoWay ----------------#
    if len(twoway) > 0:
        obj["children"].append({'name': 'two way', 'children': [], 'impact': 0})
        tw_ctxs = {}
        for ip in twoway:
            if 'nwloc' in twoway[ip] and len(twoway[ip]['nwloc']) > 0:
                ctx = twoway[ip]['nwloc'][2] # get the machine type Only for vast Data
                if ctx not in tw_ctxs:
                    tw_ctxs[ctx] = 1
                else:
                    tw_ctxs[ctx] += 1

        for ctx in tw_ctxs:
            obj["children"][2]['children'].append({
                    'name': ctx,
                    'impact': tw_ctxs[ctx]
                })
    
    with open(dendro_fpath, 'w') as dendro_f:
        dendro_f.write(json.dumps(obj))
    return "Incident progression successfully created <br/>"

    
def generate_stats(ip, inbound, outbound, twoway, threat_name):
    stats_fpath = dpath + 'stats-' + anchor + ".json"
    
    obj = {
        'name':threat_name,
        'children': [],
        'size': len(inbound) + len(outbound) + len(twoway)
    }
    
    #----- Add Inbound Connections-------#
    obj["children"].append({'name': 'Inbound Only', 'children': [], 'size': len(inbound)})    
    in_ctxs = {}
    for ip in inbound:
        full_ctx = ''
        if 'nwloc' in inbound[ip] and len(inbound[ip]['nwloc']) > 0:
            full_ctx = inbound[ip]['nwloc'][2].split('.')[0]
        ctx = get_ctx_name(full_ctx) # get the machine type Only for vast Data
        if ctx not in in_ctxs:
            in_ctxs[ctx] = 1
        else:
            in_ctxs[ctx] += 1
    for ctx in in_ctxs:
        obj["children"][0]['children'].append({
                'name': ctx,
                'size': in_ctxs[ctx]
            })        
        
    
    #------ Add Outbound ----------------#
    obj["children"].append({'name': 'Outbound Only', 'children': [], 'size': len(outbound)})
    out_ctxs = {}
    for ip in outbound:
        full_ctx = ''
        if 'nwloc' in outbound[ip] and len(outbound[ip]['nwloc']) > 0:
            full_ctx = outbound[ip]['nwloc'][2].split('.')[0]
        ctx = get_ctx_name(full_ctx) # get the machine type Only for vast Data
        if ctx not in out_ctxs:
            out_ctxs[ctx] = 1
        else:
            out_ctxs[ctx] += 1
    for ctx in out_ctxs:
        obj["children"][1]['children'].append({
                'name': ctx,
                'size': out_ctxs[ctx]
            }) 
    
    #------ Add Twoway ----------------#
    obj["children"].append({'name': 'two way', 'children': [], 'size': len(twoway)})
    tw_ctxs = {}
    for ip in twoway:
        full_ctx = ''
        if 'nwloc' in twoway[ip] and len(twoway[ip]['nwloc']) > 0:
            full_ctx = twoway[ip]['nwloc'][2].split('.')[0]
        ctx = get_ctx_name(full_ctx) # get the machine type Only for vast Data
        if ctx not in tw_ctxs:
            tw_ctxs[ctx] = 1
        else:
            tw_ctxs[ctx] += 1
    
    for ctx in tw_ctxs:
        obj["children"][2]['children'].append({
                'name': ctx,
                'size': tw_ctxs[ctx]
            })
    
    json_str = json.dumps(obj)
    with open(stats_fpath, 'w') as stats_f:
        stats_f.write(json_str)
    return "Stats file successfully created <br/>"

    
def get_ctx_name(full_context):    
    ctx= 'DMZ'
    if "VPN" in full_context:
        ctx = "VPN" 
    elif "DMZ" in full_context:
        ctx = "DMZ"
    elif "Proxy" in full_context:
        ctx = "Proxy" 
    elif "FW" in full_context:
        ctx = "FW"     
    return ctx


# calculate number of inbound only, two-way, and outbound only
# build dict of IP addresses
# firstSeen,lastSeen,srcIP, dstIP, sport,dport,conns, maxPkts, avgPkts,maxBytes, avgBytes
def get_in_out_and_twoway_conns():
    global inbound
    inbound = {}
    global outbound
    outbound = {}
    global twoway
    twoway = {}
    srcdict = {}
    dstdict = {}
    conns_dict= {} 
    rowct = 0
    if os.path.isfile(ir_f):         
        df = pd.read_csv(ir_f,sep='\t') 
        with open(ir_f, 'r') as f:
            reader = csv.reader(f,delimiter='\t')
            reader.next() #skip headers 
            for row in reader:  
                if row != []:
                    srcdict[row[2]] = {
                        'ip_int': struct.unpack("!L", socket.inet_aton(row[2]))[0],
                        'dst_ip': row[3],
                        'dst_ip_int': struct.unpack("!L", socket.inet_aton(row[3]))[0],
                        'conns': int(row[6]),
                        'maxbytes': int(row[9])
                    }
                    dstdict[row[3]] = {
                         'ip_int': struct.unpack("!L", socket.inet_aton(row[3]))[0],
                         'src_ip': row[2],
                         'src_ip_int': struct.unpack("!L", socket.inet_aton(row[2]))[0],
                         'conns': int(row[6]),
                         'maxbytes': int(row[9])
                        }       
                    rowct +=1  
        
        src = df.loc[df['dstip'] == anchor]
        src_per_conns = src.sort_values('conns',0,False)
        src_per_bytes = src.sort_values('maxbytes',0,False)
        dst = df.loc[df['srcip'] == anchor]
        dst_per_conns = dst.sort_values('conns',0,False)
        dst_per_bytes = dst.sort_values('maxbytes',0,False)

        children = []
        children += (display_results(['srcip','conns','sport','dport'], src_per_conns, 
                                          top_results),)
        children += (display_results(['dstip','conns','sport','dport'], dst_per_conns, 
                                          top_results),)
        children += (display_results(['srcip','maxbytes','sport','dport'], src_per_bytes, 
                                           top_results),)
        children += (display_results(['dstip','maxbytes','sport','dport'], dst_per_bytes, 
                                           top_results),)

        result_tabs = widgets.Accordion(children=children, width='100%', selected_index=-1)
        result_tabs.set_title(0,"Top source IP per connections")
        result_tabs.set_title(1,"Top destination IP per connections")
        result_tabs.set_title(2,"Top source IP per bytes transferred")
        result_tabs.set_title(3,"Top destination IP per bytes transferred")
        
        result_tabs._css = (
            (None, 'margin-top', '10px'),
            (None, 'margin-bottom', '10px'),
        )

        resultTableBox.children = [result_tabs,]
         
    if rowct > 0:
        for result in srcdict:
            if result in dstdict:
                twoway[result] = srcdict[result]
            else:
                outbound[result] = srcdict[result]

        for result in dstdict:
            if result not in srcdict:
                inbound[result] = dstdict[result]   
                
    global top_inbound_b
    global top_outbound_b
    global top_twoway_b
    if len(inbound) > 0:
        top_inbound_b = get_top_bytes(inbound,top_results)
        top_inbound_conns = get_top_conns(inbound,top_results)
        top_inbound_b.update(top_inbound_conns) # merge the two dictionaries
    if len(outbound) > 0:
        top_outbound_b = get_top_bytes(outbound,top_results)
        top_outbound_conns = get_top_conns(outbound,top_results)
        top_outbound_b.update(top_outbound_conns) # merge the two dictionaries
    if len(twoway) > 0:        
        top_twoway_b = get_top_bytes(twoway,top_results)
        top_twoway_conns = get_top_conns(twoway,top_results)
        top_twoway_b.update(top_twoway_conns) # merge the two dictionaries

def display_results(cols, dataframe, top):    
    table = dataframe[:top].to_html(classes='table table-striped table-bordered table-hover', columns=cols, index=False)
    return widgets.HTML(value=table, width='100%')
            
#=========== Adds GEO IP information to the outbound, inbound and twoway connections==============================# 
def add_geospatial_info():
    # get geospatial info, only when iplocation file is available
    if iplist != '':
        for srcip in outbound:
            reader = csv.reader([linecache.getline(iploc, bisect.bisect(iplist,outbound[srcip]['ip_int'])).replace('\n','')])
            outbound[srcip]['geo'] = reader.next()
            reader = csv.reader([linecache.getline(iploc, bisect.bisect(iplist,outbound[srcip]['dst_ip_int'])).replace('\n','')])
            outbound[srcip]['geo_dst'] = reader.next()

        for dstip in twoway:
            reader = csv.reader([linecache.getline(iploc, bisect.bisect(iplist,twoway[dstip]['ip_int'])).replace('\n','')])
            twoway[dstip]['geo'] = reader.next()

        for srcip in inbound:
            reader = csv.reader([linecache.getline(iploc, bisect.bisect(iplist,inbound[srcip]['ip_int'])).replace('\n','')])
            inbound[srcip]['geo'] = reader.next()
            reader = csv.reader([linecache.getline(iploc, bisect.bisect(iplist,inbound[srcip]['src_ip_int'])).replace('\n','')])
            inbound[srcip]['geo_src'] = reader.next()
     
             
              
# need some way to combine timelines of outbound and two-way with big picture inbound only
# get network context - get start and end ranges
def add_network_context():
    nwdict = {}
    if os.path.isfile(nwloc) : 
        with open(nwloc, 'r') as f:
            reader = csv.reader(f,delimiter=',')
            reader.next()
            #address range, description
            for row in reader:

                if '/' in row[0]: 
                    #Range in subnet
                    iprange = row[0].split('/')
                    if len(iprange) < 2:
                        ipend = 0
                    else:
                        ipend = int(iprange[1])
                    nwdict[row[0]] = [struct.unpack("!L", socket.inet_aton(iprange[0]))[0],
                                      struct.unpack("!L", socket.inet_aton(iprange[0]))[0]+2**(32-ipend)-1, row[1]]  
                elif '-' in row[0]: 
                    #IP Range 
                    iprange = row[0].split('-')   
                    nwdict[row[0]] = [struct.unpack("!L", socket.inet_aton(iprange[0].replace(" ", "")))[0],
                                      struct.unpack("!L", socket.inet_aton(iprange[1].replace(" ", "")))[0], row[1]]
                else:
                    #Exact match  
                    nwdict[row[0]] = [struct.unpack("!L", socket.inet_aton(row[0]))[0],
                                      struct.unpack("!L", socket.inet_aton(row[0]))[0], row[1]] 

        for srcip in outbound:  
            temp_ip = struct.unpack("!L", socket.inet_aton(srcip))[0]
            if srcip in nwdict:
                inbound[srcip]['nwloc'] = nwdict[srcip]
            else:
                matchingVals = [x for x in nwdict if nwdict[x][1] >= temp_ip and nwdict[x][0] <= temp_ip]
                outbound[srcip]['nwloc'] = nwdict[matchingVals[0]] if len(matchingVals) > 0 else ''      

        for dstip in twoway:  
            temp_ip = struct.unpack("!L", socket.inet_aton(dstip))[0]
            if dstip in nwdict:
                twoway[dstip]['nwloc'] = nwdict[dstip]
            else:
                matchingVals = [x for x in nwdict if nwdict[x][1] >= temp_ip and nwdict[x][0] <= temp_ip]
                twoway[dstip]['nwloc'] = nwdict[matchingVals[0]] if len(matchingVals) > 0 else ''

        for srcip in inbound:
            temp_ip = struct.unpack("!L", socket.inet_aton(srcip))[0]
            if srcip in nwdict:
                inbound[srcip]['nwloc'] = nwdict[srcip]
            else:
                matchingVals = [x for x in nwdict if nwdict[x][1] >= temp_ip and nwdict[x][0] <= temp_ip]
                inbound[srcip]['nwloc'] = nwdict[matchingVals[0]] if len(matchingVals) > 0 else ''

                
def generate_attack_map_file(ip, inbound, outbound, twoway): 
    if iplist != '':
        globe_fpath = dpath + 'globe-' + ip + ".json"
        globe_json = {}
        globe_json['type'] = "FeatureCollection"
        globe_json['sourceips'] = []
        globe_json['destips'] = [] 
        for srcip in twoway:
            try:
                row =  twoway[srcip]['geo']                
                globe_json['destips'].append({
                        'type': 'Feature',
                        'properties': {
                            'location':row[8],
                            'ip':srcip,
                            'type':1
                        },
                        'geometry': {
                            'type': 'Point',
                            'coordinates': [float(row[7]), float(row[6])]
                        }
                    })
            except ValueError:
                pass


        for dstip in outbound:
            try:
                row =  outbound[dstip]['geo']
                dst_geo = outbound[dstip]['geo_dst']
                globe_json['sourceips'].append({
                        'type': 'Feature',
                        'properties': {
                            'location':row[8],
                            'ip':dstip,
                            'type':3
                        },
                        'geometry': {
                            'type': 'Point',
                            'coordinates': [float(row[7]), float(row[6])]
                        }
                    })
                globe_json['destips'].append({
                        'type': 'Feature',
                        'properties': {
                            'location':row[8],
                            'ip':outbound[dstip]['dst_ip'],
                            'type':3
                        },
                        'geometry': {
                            'type': 'Point',
                            'coordinates': [float(dst_geo[7]), float(dst_geo[6])]
                        }
                    }) 

            except ValueError:
                pass

        for dstip in inbound:
            try:
                row =  inbound[dstip]['geo']
                dst_geo = inbound[dstip]['geo_src']
                globe_json['sourceips'].append({
                        'type': 'Feature',
                        'properties': {
                            'location':row[8],
                            'ip':dstip,
                            'type':2
                        },
                        'geometry': {
                            'type': 'Point',
                            'coordinates': [float(row[7]), float(row[6])]
                        }
                    })
                globe_json['destips'].append({
                        'type': 'Feature',
                        'properties': {
                            'location':row[8],
                            'ip':inbound[dstip]['src_ip'],
                            'type':2
                        },
                        'geometry': {
                            'type': 'Point',
                            'coordinates': [float(dst_geo[7]), float(dst_geo[6])]
                        }
                    })
            except ValueError:
                pass

        json_str = json.dumps(globe_json)
        with open(globe_fpath, 'w') as globe_f:
            globe_f.write(json_str)
        response = "Geolocation map successfully created <br/>"
    else:
        response = "The map can't be created without an iploc file <br/>"        
        
    return response

    
def add_threat(ip,threat_title, threat_comment):
    content = ''
    try:
        threat_f = open(threats_file, 'r')
        content = threat_f.read()
        if '{0}|{1}|{2}\n'.format(ip,threat_title,threat_comment) not in content:
            content += '{0}|{1}|{2}\n'.format(ip,threat_title,threat_comment)
        threat_f.close() 
    except:
        content = 'ip|title|summary\n'
        content += '{0}|{1}|{2}\n'.format(ip,threat_title,threat_comment)
    
    threat_fw = open(threats_file, 'w')
    threat_fw.write(content)
    threat_fw.close()
    return ""

    
def get_top_bytes(conns_dict, top):
    topbytes = sorted(conns_dict.iteritems(), key=lambda (x,y): y['maxbytes'], reverse=True)
    topbytes = topbytes[0:top]
    return dict(topbytes)


def get_top_conns(conns_dict, top):    
    topconns = sorted(conns_dict.iteritems(), key=lambda (x,y): y['conns'], reverse=True)
    topconns = topconns[0:top]
    return dict(topconns)
    
def file_is_empty(path):
    return os.stat(path).st_size==0

def removeWidget(index):
    js_command = "$('.widget-area > .widget-subarea > .widget-box:eq({0})').remove();".format(index)    
    display(Javascript(js_command))

In [ ]:
start_investigation()