DK 'Log


NTop session query script
Fri, 22 Aug 2008

While coding the session monitor a couple of weeks ago I developed a quick script which could query ntop for session information. Jaime started using it for graphing now, so I thought it might be useful to soembody. Please find the code below.


::start here

import sgmllib, re, sys
import socket
from sets import Set


class MyParser(sgmllib.SGMLParser):
    "A simple parser class."

    def parse(self, s):
        "Parse the given string 's'."
        self.feed(s)
        self.close()

    def __init__(self, verbose=0):
        "Initialise an object, passing 'verbose' to the superclass."

        sgmllib.SGMLParser.__init__(self, verbose)
        self.starting_description = 0
        self.inside_table_element = 0
        self.inside_table_row = 0
        self.in_session = 0
        self.td_count = 0
        self.seen  = 0

        self.sessions = []
        self.session_num = 0
        
        self.queried_ip = ""

        self.dst_port_group = {}
        self.src_port_group = {}

        self.source_ip = ""
        self.source_port = ""
        self.dest_ip = ""
        self.dest_port = ""
        self.data_sent = 0
        self.data_rcvd = 0
        self.active_since = ""
        self.last_seen = ""
        self.duration = 0
        self.inactive = 0

    def tosecs(self, data):

        # example: 27 sec
        if data.endswith('sec'):
            data = data.split(' ', 1)[0]

        # examples: 1 day  1:52:27
        #           2 days 4:56:23
        elif data.__contains__('day'):
            result = re.findall('(\d+) days? (\S+)', data)
            (days, time) = result[0]
            seconds = int(days) * 86400

            dt = time.split(':')
            seconds += int(dt.pop())
            try:
                seconds += seconds + int(dt.pop()) * 60
                seconds += seconds + int(dt.pop()) * 3600
            except IndexError:
                pass
            data = str(seconds)
    
        # example: 1:52:27
        else:
            dt = data.split(':')
            seconds = int(dt.pop())
            try:
                seconds += int(dt.pop()) * 60
                if len(dt) == 3:
                    seconds += int(dt.pop()) * 3600
            except IndexError:
                pass
            data = str(seconds)
    

        return data

    def start_td(self, attributes):
        self.td_count += 1
        self.inside_table_element = 1

    def end_td(self):
        self.inside_table_element = 0
        self.seen = 0

    def start_tr(self, attributes):
        self.inside_table_row = 1

    def end_tr(self):
        self.inside_table_row = 0
        self.td_count = 0
        if self.in_session and self.source_ip:
            self.session_num += 1
            tmp = "%s:%s --> %s:%s (%f %f) duration: %s" % \
(self.source_ip,self.source_port,self.dest_ip,self.dest_port, self.data_sent, self.data_rcvd, self.duration)
            self.sessions.append(tmp)

    def start_a(self, attributes):
        self.inside_table_row = 1
        for name, value in attributes:
            if name == "href" and self.in_session:
                matches = re.findall("\d+\.\d+\.\d+\.\d+",value)
                if len(matches) > 0:
                    if self.td_count is 1:
                        self.source_ip = matches[0]
                    elif self.td_count is 2:
                        self.dest_ip = matches[0]

    def handle_data(self, data):
        if self.queried_ip is "":
            matches = re.findall("(\d+\.\d+\.\d+\.\d+)",data)
            if len(matches) > 0:
                self.queried_ip = matches[0]

        if data.__contains__("Active TCP/UDP Sessions"):
            self.in_session = 1

        if data.__contains__("The color of the host"):
            self.sessions.append("NumSessions:%d" % int(self.session_num))
            self.in_session = 0
            source_sessions = 0
            dest_sessions = 0
            for sess in self.sessions:
                src_str = "^%s:.*" % self.queried_ip
                dst_str = "^\d+\.\d+\.\d+\.\d+:\d+\s+-->\s+%s:.*" % self.queried_ip
                src_sess = "^%s:\d+\s+-->\s+(\d+\.\d+\.\d+\.\d+):(\d+)" % self.queried_ip
                dst_sess = "^(\d+\.\d+\.\d+\.\d+):\d+\s+-->\s+%s:(\d+)" % self.queried_ip
                if re.findall(src_str, sess):
                    source_sessions += 1
                if re.findall(dst_str, sess):
                    dest_sessions += 1
                matches = re.findall(src_sess, sess)
                if len(matches) > 0:
                    if matches[0][1] in self.src_port_group:
                        self.src_port_group[matches[0][1]].add(matches[0][0])
                    else:
                        self.src_port_group[matches[0][1]] = Set()
                        self.src_port_group[matches[0][1]].add(matches[0][0])
                matches = re.findall(dst_sess, sess)
                if len(matches) > 0:
                    if matches[0][1] in self.dst_port_group:
                        self.dst_port_group[matches[0][1]].add(matches[0][0])
                    else:
                        self.dst_port_group[matches[0][1]] = Set()
                        self.dst_port_group[matches[0][1]].add(matches[0][0])



            self.sessions.append("SessionsAsSource:%s" % source_sessions)
            self.sessions.append("SessionsAsDest:%s" % dest_sessions)
            for port in self.src_port_group:
                self.sessions.append("UniqPort%sAsSourceSessions:%d" % (port, len(self.src_port_group[port])))
            for port in self.dst_port_group:
                self.sessions.append("UniqPort%sAsDestSessions:%d" % (port, len(self.dst_port_group[port])))



        if self.inside_table_element and self.in_session:
            if self.td_count <= 2:
                matches = re.findall(":(\w+)",data)
                if len(matches) > 0:
                    try:
                        port = socket.getservbyname(matches[0])
                    except:
                        port = matches[0]
                    if self.td_count is 1:
                        self.source_port = port
                    elif self.td_count is 2:
                        self.dest_port = port

            elif self.td_count is 3:
                if self.seen == 0:
                    self.data_sent = float(data)
                    self.seen = 1
                else:
                    if data.__contains__("KB"):
                        self.data_sent *= 1024
                    elif data.__contains__("MB"):
                        self.data_sent *= 1024 * 1024
                    elif data.__contains__("GB"):
                        self.data_sent *= 1024 * 1024 * 1024
                    self.seen = 0

            elif self.td_count is 4:
                if self.seen == 0:
                    self.data_rcvd = float(data)
                    self.seen = 1
                else:
                    if data.__contains__("KB"):
                        self.data_rcvd *= 1024
                    elif data.__contains__("MB"):
                        self.data_rcvd *= 1024 * 1024
                    elif data.__contains__("GB"):
                        self.data_rcvd *= 1024 * 1024 * 1024
                    self.seen = 0

            elif self.td_count is 5:
                self.active_since = data

            elif self.td_count is 6:
                self.last_seen = data

            elif self.td_count is 7:
                self.duration = self.tosecs(data)

            elif self.td_count is 8:
                self.inactive = self.tosecs(data)

    def get_sessions(self):
        return self.sessions

# Real start

import urllib, sgmllib

argv = sys.argv
try:
    ntop = argv[1]
    ip = argv[2]
except:
    print "Prints out session information about a given host"
    print "Usage: " + argv[0] + " ntop_ip host_ip"
    sys.exit()

# Get something to work with.
f = None
try:
    f = urllib.urlopen("http://" + ntop + ":3000/" + ip + ".html")
except:
    print "Unable to connect to " + ntop
    sys.exit()
s = f.read()

# Try and process the page.
# The class should have been defined first, remember.
myparser = MyParser()
myparser.parse(s)

a = myparser.get_sessions()

print "Sessions for " + ip
print "--------------------------"

for b in a:
    print b

The output looks somewhat like this:

Gestalt:ntop dk$ python session_query.py 192.168.1.2 192.168.1.2
Sessions for 192.168.1.2
--------------------------
192.168.1.43:2409 --> 192.168.1.2:3000 (567.000000 2662.400000) duration: 0
192.168.1.2:39492 --> 195.77.186.178:33800 (74240.000000 75264.000000) duration: 406
192.168.1.2:45206 --> 195.55.170.126:33800 (140595.200000 143974.400000) duration: 644
192.168.1.2:54151 --> 207.158.15.208:443 (1153433.600000 1153433.600000) duration: 637
192.168.1.35:59334 --> 192.168.1.2:3000 (258.000000 112.000000) duration: 0
NumSessions:5
SessionsAsSource:3
SessionsAsDest:2
UniqPort443AsSourceSessions:1
UniqPort33800AsSourceSessions:2
UniqPort3000AsDestSessions:2
Gestalt:ntop dk$ 
Aaah, and with a little trick also the main session page can be parsed:
Gestalt:ntop dk$ python session_query.py 192.168.1.2 NetNetstat
Sessions for NetNetstat
--------------------------
192.168.1.43:2409 --> 192.168.1.2:3000 (567.000000 2662.400000) duration: 0
192.168.1.2:39492 --> 195.77.186.178:33800 (75366.400000 76288.000000) duration: 459
192.168.1.2:45206 --> 195.55.170.126:33800 (141721.600000 144896.000000) duration: 706
192.168.1.2:54151 --> 207.158.15.208:443 (1153433.600000 1153433.600000) duration: 695
192.168.1.35:59337 --> 192.168.1.2:3000 (257.000000 112.000000) duration: 0
NumSessions:5
SessionsAsSource:0
SessionsAsDest:1
UniqPort33800AsDestSessions:1
Gestalt:ntop dk$ 

As a finishing note, we did setup another blog with ossim-related info: Santi's blog. As an opener he features a demo video with a sample presentation done to a customer.

posted at: 08:42 | path: /code | permanent link to this entry | 0 comments |
Tags: ossim, ntop, sessions



Name:


E-mail:


URL:


Comment:


Categories

/ (66)
    code/ (1)
    feed/ (1)
    friends/ (1)
    ossim/ (41)
        installer/ (3)
        plugins/ (2)
        tuning/ (3)
        tutorials/ (8)
    personal/ (20)
        campus/ (2)
        opinion/ (1)
        travel/ (1)
    rants/ (1)



Dominique Karg
(feel free to get in touch)
  • Mail (gpg key)
  • Linkedin
  • Twitter
  • Forums

Friend's blogs:
  • /blog/jaime
  • /blog/juanma
  • /blog/santiago






Certified Application Security Specialist




RSS




< August 2008 >
MoTuWeThFrSaSu
     1 2 3
4 5 6 7 8 910
11121314151617
18192021222324
25262728293031




Archives

2010-Apr
2010-Mar
2010-Feb
2009-Dec
2009-Sep
2009-Aug
2009-Jul
2009-Jun
2009-May
2009-Apr
2009-Mar
2009-Feb
2009-Jan
2008-Dec
2008-Oct
2008-Aug
2008-Jul
2008-May
2008-Mar
2008-Feb
2008-Jan
2007-Dec
2007-Nov




Tags

installer ossim tutorial untagged




Made with PyBlosxom