Changeset 5513

Show
Ignore:
Timestamp:
02/08/10 14:58:07 (6 months ago)
Author:
nopper
Message:

Adding missing constants to netconst.
Adding connection manager to track connections.

Location:
pm/trunk/umit/pm
Files:
2 modified

Legend:

Unmodified
Added
Removed
  • pm/trunk/umit/pm/core/netconst.py

    r5467 r5513  
    105105############################################################################### 
    106106 
    107 MPKT_IGNORE      = 1 
    108 MPKT_FORWARDABLE = 1 << 2 
    109 MPKT_FORWARDED   = 1 << 3 
    110 MPKT_FROMIFACE   = 1 << 4 
    111 MPKT_FROMBRIDGE  = 1 << 5 
     107MPKT_IGNORE       = 1 
     108MPKT_DONT_DISSECT = 1 << 1 
     109MPKT_FORWARDABLE  = 1 << 2 
     110MPKT_FORWARDED    = 1 << 3 
     111MPKT_FROMIFACE    = 1 << 4 
     112MPKT_FROMBRIDGE   = 1 << 5 
     113MPKT_MODIFIED     = 1 << 6 
     114MPKT_DROPPED      = 1 << 7 
    112115 
    113116############################################################################### 
     
    121124CONN_CLOSE            = 3 
    122125CONN_TIMED_OUT        = 4 
     126 
     127CN_IDLE      = 0 
     128CN_OPENING   = 1 
     129CN_OPEN      = 2 
     130CN_ACTIVE    = 3 
     131CN_CLOSING   = 4 
     132CN_CLOSED    = 5 
     133CN_KILLED    = 6 
     134 
     135CN_INJECTED  = 1 
     136CN_MODIFIED  = 2 
     137CN_VIEWING   = 4 
  • pm/trunk/umit/pm/manager/sessionmanager.py

    r5326 r5513  
    11#!/usr/bin/env python 
    22# -*- coding: utf-8 -*- 
    3 # Copyright (C) 2009 Adriano Monteiro Marques 
     3# Copyright (C) 2009, 2010 Adriano Monteiro Marques 
    44# 
    55# Author: Francesco Piccinno <stack.box@gmail.com> 
     
    2323""" 
    2424 
     25import time 
    2526from socket import inet_aton 
    2627 
    2728from umit.pm.core.logger import log 
    2829from umit.pm.core.atoms import Singleton, defaultdict 
    29 from umit.pm.core.netconst import TH_ACK, TH_SYN, TH_PSH 
     30from umit.pm.core.netconst import * 
    3031 
    3132class DissectIdent(object): 
    3233    magic = None 
    3334 
    34     def __init__(self, sip=None, dip=None, sport=None, dport=None, proto=None): 
    35         self.sip = sip 
    36         self.dip = dip 
    37         self.sport = sport 
    38         self.dport = dport 
     35    def __init__(self, l3src, l3dst, l4src, l4dst, proto): 
     36        self.l3_src = l3src 
     37        self.l3_dst = l3dst 
     38        self.l4_src = l4src 
     39        self.l4_dst = l4dst 
    3940        self.proto = proto 
     41 
     42    def __eq__(self, other): 
     43        if self.magic != other.magic or self.proto != other.proto: 
     44            return False 
     45 
     46        if self.l3_src == other.l3_src and \ 
     47           self.l3_dst == other.l3_dst and \ 
     48           self.l4_src == other.l4_src and \ 
     49           self.l4_dst == other.l4_dst: 
     50            return True 
     51 
     52        if self.l3_src == other.l3_dst and \ 
     53           self.l3_dst == other.l3_src and \ 
     54           self.l4_src == other.l4_dst and \ 
     55           self.l4_dst == other.l4_src: 
     56            return True 
     57 
     58        return False 
     59 
     60    @classmethod 
     61    def mkhash(self, ident): 
     62        return hash(ident.l3_src) ^ hash(ident.l3_dst) ^ \ 
     63               ident.l4_src ^ ident.l4_dst ^ hash(ident.proto) 
     64 
     65class TCPIdent(object): 
     66    magic = NL_TYPE_TCP 
     67 
     68    def __init__(self, l3src, l3dst, l4src, l4dst): 
     69        self.l3_src = l3src 
     70        self.l3_dst = l3dst 
     71        self.l4_src = l4src 
     72        self.l4_dst = l4dst 
     73 
     74    def __eq__(self, other): 
     75        if self.magic != other.magic: 
     76            return False 
     77 
     78        if self.l3_src == other.l3_src and \ 
     79           self.l3_dst == other.l3_dst and \ 
     80           self.l4_src == other.l4_src and \ 
     81           self.l4_dst == other.l4_dst: 
     82            return True 
     83 
     84        if self.l3_src == other.l3_dst and \ 
     85           self.l3_dst == other.l3_src and \ 
     86           self.l4_src == other.l4_dst and \ 
     87           self.l4_dst == other.l4_src: 
     88            return True 
     89 
     90        return False 
     91 
     92    @classmethod 
     93    def create(self, mpkt): 
     94        return TCPIdent(mpkt.l3_src, mpkt.l3_dst, 
     95                        mpkt.l4_src, mpkt.l4_dst) 
     96 
     97    @classmethod 
     98    def mkhash(self, ident): 
     99        return hash(ident.l3_src) ^ hash(ident.l3_dst) ^ \ 
     100               ident.l4_src ^ ident.l4_dst 
     101 
     102INJ_FIN = 1 
     103INJ_FWD = 2 
     104 
     105class TCPStatus(object): 
     106    def __init__(self): 
     107        self.last_seq = 0 
     108        self.last_ack = 0 
     109        self.seq_adj = 0 
     110        self.injectable = 0 
     111 
     112class IPIdent(object): 
     113    magic = LL_TYPE_IP 
     114 
     115    def __init__(self, l3src): 
     116        self.l3_src = l3src 
    40117 
    41118    def __eq__(self, other): 
    42119        if self.magic == other.magic and \ 
    43            self.proto == other.proto and \ 
    44            self.sport == other.sport and \ 
    45            self.dport == other.dport and \ 
    46            self.sip == other.sip and     \ 
    47            self.dip == other.dip: 
     120           self.l3_src == other.l3_src: 
    48121            return True 
    49122        return False 
    50123 
     124    @classmethod 
     125    def create(self, mpkt): 
     126        return IPIdent(mpkt.l3_src) 
     127 
     128    @classmethod 
     129    def mkhash(self, ident): 
     130        return hash(ident.l3_src) 
     131 
     132class IPStatus(object): 
     133    def __init__(self): 
     134        self.last_id = 0 
     135        self.id_adj = 0 
     136 
    51137class Session(object): 
    52     def __init__(self, data=None, ident=None, prev=None): 
    53         self.data = data 
     138    def __init__(self, ident): 
    54139        self.ident = ident 
    55         self.prev = prev 
     140        self.data = None 
     141        self.prev = None 
     142 
     143    def __str__(self): 
     144        return "%s -> %s" % (str(self.prev), str(self.ident)) 
    56145 
    57146class SessionManager(Singleton): 
     
    61150 
    62151    def __init__(self): 
    63         # The sessions are saved with ident magic as key 
    64         # and collision are handled by an overflow list 
    65         self._sessions = defaultdict(list) 
     152        self._sessions = defaultdict(dict) 
     153 
     154    # Dissectors methods 
    66155 
    67156    def create_session(self, mpkt, ports, dissector): 
     
    73162        """ 
    74163 
    75         tcpflags = mpkt.get_field('tcp.flags') 
     164        tcpflags = mpkt.l4_flags 
    76165 
    77166        if tcpflags & TH_SYN != 0 and tcpflags & TH_ACK != 0: 
    78             srcport = mpkt.get_field('tcp.sport') 
    79  
    80             if srcport in ports: 
     167            if mpkt.l4_src in ports: 
    81168                log.debug('Creating sessions for dissector %s' % dissector) 
    82                 ident = self.create_ident_from_mpkt(mpkt, hash(dissector)) 
    83  
    84                 sess = Session(ident=ident) 
     169                ident = self.create_ident_from_mpkt(mpkt, dissector) 
     170 
     171                sess = Session(ident) 
    85172                self.put_session(sess) 
    86173 
     
    89176        return None 
    90177 
    91     def create_ident_from_mpkt(self, mpkt, hashval): 
     178    def create_ident_from_mpkt(self, mpkt, magic): 
    92179        """ 
    93180        Create a session object starting from a mpkt instance 
    94181        """ 
    95         # CHECKME: inet_aton or ascii transformation? 
    96         # we prefer less space allocated so inet_aton 
    97         ident = DissectIdent(inet_aton(mpkt.get_field('ip.src')), 
    98                              inet_aton(mpkt.get_field('ip.dst')), 
    99                              mpkt.get_field('tcp.sport'), 
    100                              mpkt.get_field('tcp.dport'), 
    101                              mpkt.get_field('ip.proto')) 
    102         ident.magic = hashval 
     182        ident = DissectIdent(inet_aton(mpkt.l3_src), inet_aton(mpkt.l3_dst), 
     183                             mpkt.l4_src, mpkt.l4_dst, mpkt.l4_proto) 
     184        ident.magic = magic 
    103185 
    104186        return ident 
     187 
     188    def lookup_session(self, mpkt, ports, decoder, create_on_fail=False): 
     189        ident = self.create_ident_from_mpkt(mpkt, decoder) 
     190        sess = self.get_session(ident) 
     191 
     192        if create_on_fail and not sess: 
     193            sess = Session(ident) 
     194            self.put_session(sess) 
     195 
     196        return sess 
     197 
     198    def is_first_mpkt_from_server(self, mpkt, ports, decoder): 
     199        if mpkt.l4_src in ports and \ 
     200           mpkt.l4_flags & TH_PSH != 0: 
     201 
     202            ident = self.create_ident_from_mpkt(mpkt, decoder) 
     203            return self.get_session(ident) 
     204 
     205    # Standard methods 
    105206 
    106207    def put_session(self, sess): 
     
    109210        @param sess a Session object 
    110211        """ 
    111  
    112         self._sessions[sess.ident.magic].append(sess) 
     212        hv = sess.ident.mkhash(sess.ident) 
     213        sessions = self._sessions[sess.ident.magic] 
     214 
     215        try: 
     216            sessions[hv].append(sess) 
     217        except: 
     218            sessions[hv] = [sess] 
    113219 
    114220    def delete_session(self, sess): 
     
    116222        Delete the session 
    117223        """ 
    118         self._sessions[sess.ident.magic].remove(sess) 
     224        hv = sess.ident.mkhash(sess.ident) 
     225        sessions = self._sessions[sess.ident.magic] 
     226 
     227        sessions[hv].remove(sess) 
     228 
     229        if not sessions[hv]: 
     230            del sessions[hv] 
    119231 
    120232    def get_session(self, ident): 
    121         for sess in self._sessions[ident.magic]: 
    122             if sess.ident == ident: 
    123                 return sess 
    124  
    125     def lookup_session(self, mpkt, ports, decoder, create_on_fail=False): 
    126         ident = self.create_ident_from_mpkt(mpkt, hash(decoder)) 
    127         sess = self.get_session(ident) 
    128  
    129         if create_on_fail and not sess: 
    130             sess = Session(ident=ident) 
    131             self.put_session(sess) 
    132  
    133         return sess 
    134  
    135     # Useful functions 
    136  
    137     def is_first_mpkt_from_server(self, mpkt, ports, decoder): 
    138         if mpkt.get_field('tcp.sport') in ports and \ 
    139            mpkt.get_field('tcp.flags') & TH_PSH != 0: 
    140  
    141             ident = self.create_ident_from_mpkt(mpkt, hash(decoder)) 
    142             return self.get_session(ident) 
     233        hv = ident.mkhash(ident) 
     234 
     235        try: 
     236            sessions = self._sessions[ident.magic][hv] 
     237 
     238            for sess in sessions: 
     239                if sess.ident == ident: 
     240                    return sess 
     241        except: 
     242            return None 
     243 
     244class ConnectionManager(object): 
     245    """ 
     246    This class will track connections 
     247    """ 
     248    def __init__(self, conn_idle=5, conn_timeout=300): 
     249        self.conn_list = [] 
     250        self.connections = defaultdict(list) 
     251        self.conn_idle = conn_idle 
     252        self.conn_timeout = conn_timeout 
     253 
     254    def parse(self, mpkt): 
     255        if not mpkt.l4_src or not mpkt.l4_dst: 
     256            return 
     257 
     258        log.debug("Parsing new mpkt") 
     259        hv, conn = self.search(mpkt) 
     260 
     261        if conn: 
     262            self.update(conn, mpkt) 
     263        else: 
     264            self.add(mpkt, hv) 
     265 
     266    @classmethod 
     267    def mkhash(cls, mpkt): 
     268        return hash(mpkt.l3_src) ^ hash(mpkt.l3_dst) ^ \ 
     269               hash(mpkt.l4_src ^ mpkt.l4_dst)       ^ \ 
     270               hash(mpkt.l4_proto) 
     271 
     272    def search(self, mpkt): 
     273        hv = self.mkhash(mpkt) 
     274        for conn in self.connections.get(hv, []): 
     275            if conn.match(mpkt): 
     276                return hv, conn 
     277        return hv, None 
     278 
     279    def add(self, mpkt, hv): 
     280        conn = Connection(mpkt) 
     281 
     282        log.debug("Adding new connection %s" % conn) 
     283 
     284        self.connections[hv].append(conn) 
     285        self.update(conn, mpkt) 
     286        self.conn_list.append(conn) 
     287 
     288    def update(self, conn, mpkt): 
     289        log.debug("Updating connection %s" % conn) 
     290 
     291        conn.ts = time.time() 
     292 
     293        if mpkt.l4_flags & TH_SYN: 
     294            conn.status = CN_OPENING 
     295        elif mpkt.l4_flags & TH_FIN: 
     296            conn.status = CN_CLOSING 
     297        elif mpkt.l4_flags & TH_ACK: 
     298            if conn.status == CN_OPENING: 
     299                conn.status = CN_OPEN 
     300            elif conn.status == CN_CLOSING: 
     301                conn.status = CN_CLOSED 
     302 
     303        if mpkt.l4_flags & TH_PSH: 
     304            conn.status = CN_ACTIVE 
     305 
     306        if mpkt.l4_flags & TH_RST: 
     307            conn.status = CN_KILLED 
     308 
     309        conn.add_buf(mpkt) 
     310 
     311        if mpkt.l4_proto == NL_TYPE_UDP: 
     312            conn.status = CN_ACTIVE 
     313 
     314        if mpkt.flags & MPKT_MODIFIED or mpkt.flags & MPKT_DROPPED: 
     315            conn.flags |= CN_MODIFIED 
     316 
     317    def cleaner(self): 
     318        """ 
     319        Start this function in a external thread every tot sec 
     320        to collect garbage. 
     321        """ 
     322 
     323        ts = time.time() 
     324 
     325        idx = 0 
     326        while idx < len(self.conn_list): 
     327            conn = self.conn_list[idx] 
     328 
     329            if conn.flags & CN_VIEWING: 
     330                continue 
     331 
     332            diff = ts - conn.ts 
     333 
     334            if conn.status == CN_ACTIVE and \ 
     335               diff >= self.conn_idle: 
     336 
     337                conn.status = CN_IDLE 
     338 
     339            if diff >= self.conn_timeout: 
     340                self.delete(conn) 
     341                continue 
     342 
     343            idx += 1 
     344 
     345    def delete(self, conn): 
     346        self.conn_list.remove(conn) 
     347        self.connections[Connection.mkhash(conn)].remove(conn) 
     348 
     349class Connection(object): 
     350    def __init__(self, mpkt): 
     351        self.l2_addr1 = mpkt.l2_src 
     352        self.l2_addr2 = mpkt.l2_dst 
     353 
     354        self.l3_addr1 = mpkt.l3_src 
     355        self.l3_addr2 = mpkt.l3_dst 
     356 
     357        self.l4_addr1 = mpkt.l4_src 
     358        self.l4_addr2 = mpkt.l4_dst 
     359        self.l4_proto = mpkt.l4_proto 
     360 
     361        self.buffers = [] 
     362        self.xferred = 0 
     363        self.flags = 0 
     364        self.status = 0 
     365        self.ts = 0 
     366 
     367    @classmethod 
     368    def mkhash(cls, obj): 
     369        return hash(obj.l3_addr1) ^ hash(obj.l3_addr2) ^ \ 
     370               hash(obj.l4_addr1 ^ obj.l4_addr2)       ^ \ 
     371               hash(obj.l4_proto) 
     372 
     373    def match(self, mpkt): 
     374        if mpkt.l4_proto != self.l4_proto: 
     375            return False 
     376 
     377        if self.l3_addr1 == mpkt.l3_src and \ 
     378           self.l3_addr2 == mpkt.l3_dst and \ 
     379           self.l4_addr1 == mpkt.l4_src and \ 
     380           self.l4_addr2 == mpkt.l4_dst: 
     381            return True 
     382 
     383        if self.l3_addr1 == mpkt.l3_dst and \ 
     384           self.l3_addr2 == mpkt.l3_src and \ 
     385           self.l4_addr1 == mpkt.l4_dst and \ 
     386           self.l4_addr2 == mpkt.l4_src: 
     387            return True 
     388 
     389        return False 
     390 
     391    def add_buf(self, mpkt): 
     392        if mpkt.data: 
     393            self.xferred += len(mpkt.data) 
     394 
     395            if len(self.buffers) > 40: 
     396                log.debug('Removing old buffers') 
     397                self.buffers = [] 
     398 
     399            if mpkt.l4_dst == self.l4_addr2: 
     400                self.buffers.append((1, mpkt.data)) 
     401            else: 
     402                self.buffers.append((0, mpkt.data)) 
     403 
     404    def __str__(self): 
     405        return "%d - %s:%d <-> %s:%d" % ( 
     406            self.l4_proto, 
     407            self.l3_addr1, self.l4_addr1, 
     408            self.l3_addr2, self.l4_addr2)