| | 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 | |
| | 65 | class 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 | |
| | 102 | INJ_FIN = 1 |
| | 103 | INJ_FWD = 2 |
| | 104 | |
| | 105 | class 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 | |
| | 112 | class IPIdent(object): |
| | 113 | magic = LL_TYPE_IP |
| | 114 | |
| | 115 | def __init__(self, l3src): |
| | 116 | self.l3_src = l3src |
| 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 | |
| | 244 | class 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 | |
| | 349 | class 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) |