1#!/usr/bin/env python 2# Copyright (c) 2003 CORE Security Technologies 3# 4# This software is provided under under a slightly modified version 5# of the Apache Software License. See the accompanying LICENSE file 6# for more information. 7# 8# Pcap dump splitter. 9# 10# This tools splits pcap capture files into smaller ones, one for each 11# different TCP/IP connection found in the original. 12# 13# Authors: 14# Alejandro D. Weil <aweil@coresecurity.com> 15# Javier Kohen <jkohen@coresecurity.com> 16# 17# Reference for: 18# pcapy: open_offline, pcapdumper. 19# ImpactDecoder. 20 21import sys 22from exceptions import Exception 23import pcapy 24from pcapy import open_offline 25 26from impacket.ImpactDecoder import EthDecoder, LinuxSLLDecoder 27 28 29class Connection: 30 """This class can be used as a key in a dictionary to select a connection 31 given a pair of peers. Two connections are considered the same if both 32 peers are equal, despite the order in which they were passed to the 33 class constructor. 34 """ 35 36 def __init__(self, p1, p2): 37 """This constructor takes two tuples, one for each peer. The first 38 element in each tuple is the IP address as a string, and the 39 second is the port as an integer. 40 """ 41 42 self.p1 = p1 43 self.p2 = p2 44 45 def getFilename(self): 46 """Utility function that returns a filename composed by the IP 47 addresses and ports of both peers. 48 """ 49 return '%s.%d-%s.%d.pcap'%(self.p1[0],self.p1[1],self.p2[0],self.p2[1]) 50 51 def __cmp__(self, other): 52 if ((self.p1 == other.p1 and self.p2 == other.p2) 53 or (self.p1 == other.p2 and self.p2 == other.p1)): 54 return 0 55 else: 56 return -1 57 58 def __hash__(self): 59 return (hash(self.p1[0]) ^ hash(self.p1[1]) 60 ^ hash(self.p2[0]) ^ hash(self.p2[1])) 61 62 63class Decoder: 64 def __init__(self, pcapObj): 65 # Query the type of the link and instantiate a decoder accordingly. 66 datalink = pcapObj.datalink() 67 if pcapy.DLT_EN10MB == datalink: 68 self.decoder = EthDecoder() 69 elif pcapy.DLT_LINUX_SLL == datalink: 70 self.decoder = LinuxSLLDecoder() 71 else: 72 raise Exception("Datalink type not supported: " % datalink) 73 74 self.pcap = pcapObj 75 self.connections = {} 76 77 def start(self): 78 # Sniff ad infinitum. 79 # PacketHandler shall be invoked by pcap for every packet. 80 self.pcap.loop(0, self.packetHandler) 81 82 def packetHandler(self, hdr, data): 83 """Handles an incoming pcap packet. This method only knows how 84 to recognize TCP/IP connections. 85 Be sure that only TCP packets are passed onto this handler (or 86 fix the code to ignore the others). 87 88 Setting r"ip proto \tcp" as part of the pcap filter expression 89 suffices, and there shouldn't be any problem combining that with 90 other expressions. 91 """ 92 93 # Use the ImpactDecoder to turn the rawpacket into a hierarchy 94 # of ImpactPacket instances. 95 p = self.decoder.decode(data) 96 ip = p.child() 97 tcp = ip.child() 98 99 # Build a distinctive key for this pair of peers. 100 src = (ip.get_ip_src(), tcp.get_th_sport() ) 101 dst = (ip.get_ip_dst(), tcp.get_th_dport() ) 102 con = Connection(src,dst) 103 104 # If there isn't an entry associated yetwith this connection, 105 # open a new pcapdumper and create an association. 106 if not self.connections.has_key(con): 107 fn = con.getFilename() 108 print "Found a new connection, storing into:", fn 109 try: 110 dumper = self.pcap.dump_open(fn) 111 except pcapy.PcapError, e: 112 print "Can't write packet to:", fn 113 return 114 self.connections[con] = dumper 115 116 # Write the packet to the corresponding file. 117 self.connections[con].dump(hdr, data) 118 119 120 121def main(filename): 122 # Open file 123 p = open_offline(filename) 124 125 # At the moment the callback only accepts TCP/IP packets. 126 p.setfilter(r'ip proto \tcp') 127 128 print "Reading from %s: linktype=%d" % (filename, p.datalink()) 129 130 # Start decoding process. 131 Decoder(p).start() 132 133 134# Process command-line arguments. 135if __name__ == '__main__': 136 if len(sys.argv) <= 1: 137 print "Usage: %s <filename>" % sys.argv[0] 138 sys.exit(1) 139 140 main(sys.argv[1]) 141