Beispiel #1
0
    def test_full_packet_parsing_default_stack(self):
        full_eii_packet_data = \
            [0x52, 0x54, 0x00, 0x12, 0x35, 0x02, 0x08, 0x00, 0x27, 0xc6, 0x25, 0x01, 0x08, 0x00, 0x45, 0x10,
             0x00, 0x5c, 0x93, 0x06, 0x40, 0x00, 0x40, 0x06, 0x8f, 0x75, 0x0a, 0x00, 0x02, 0x0f, 0x0a, 0x00,
             0x02, 0x02, 0x00, 0x16, 0xd1, 0xf4, 0x52, 0x1a, 0x58, 0x7c, 0x58, 0x25, 0x2e, 0x9b, 0x50, 0x18,
             0x9f, 0xb0, 0x18, 0x5f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0xb0, 0x2c, 0x08, 0xab, 0x7f, 0x98,
             0x3c, 0x58, 0x54, 0xeb, 0xde, 0x01, 0xd1, 0xc7, 0xbe, 0xf8, 0x85, 0xba, 0xe4, 0xb6, 0xea, 0x06,
             0x98, 0xf9, 0xc0, 0xd2, 0xac, 0x17, 0x19, 0x85, 0x54, 0xdb, 0xe1, 0x3b, 0x3e, 0x85, 0x61, 0xee,
             0x31, 0xaf, 0x36, 0xa6, 0x04, 0xd3, 0x51, 0x21, 0x09, 0x20]

        packet = PCAPPacket(full_eii_packet_data, '13:00')
        pmap = packet.parse()

        self.assertEqual('13:00', packet.timestamp)

        self.assertTrue('ethernet' in pmap)
        self.assertTrue('ip' in pmap)
        self.assertTrue('tcp' in pmap)

        self.assertEqual(PCAPEthernet, type(pmap['ethernet']))
        self.assertEqual(PCAPIP4, type(pmap['ip']))
        self.assertEqual(PCAPTCP, type(pmap['tcp']))

        self.assertEqual('08:00:27:c6:25:01', pmap['ethernet'].source_mac)
        self.assertEqual('52:54:00:12:35:02', pmap['ethernet'].dest_mac)
        self.assertEqual(PCAPIP4, pmap['ethernet'].next_parse_recommendation)
        self.assertEqual('10.0.2.15', pmap['ip'].source_ip)
        self.assertEqual('10.0.2.2', pmap['ip'].dest_ip)
        self.assertEqual(5, pmap['ip'].header_length)
        self.assertEqual(4, pmap['ip'].version)
        self.assertEqual(IP4_PROTOCOL_TCP, pmap['ip'].protocol)
        self.assertEqual(PCAPTCP, pmap['ip'].next_parse_recommendation)
        self.assertEqual(22, pmap['tcp'].source_port)
        self.assertEqual(53748, pmap['tcp'].dest_port)
        self.assertEqual(1377458300, pmap['tcp'].seq)
        self.assertEqual(1478831771, pmap['tcp'].ack)
        self.assertEqual(5, pmap['tcp'].data_offset)
        self.assertEqual(True, pmap['tcp'].is_flag_set(TCP_PROTOCOL_FLAG_ACK))
        self.assertEqual(True, pmap['tcp'].is_flag_set(TCP_PROTOCOL_FLAG_PUSH))
        self.assertEqual(False, pmap['tcp'].is_flag_set(TCP_PROTOCOL_FLAG_CWS))
        self.assertEqual(False, pmap['tcp'].is_flag_set(TCP_PROTOCOL_FLAG_ECE))
        self.assertEqual(False, pmap['tcp'].is_flag_set(TCP_PROTOCOL_FLAG_FINAL))
        self.assertEqual(False, pmap['tcp'].is_flag_set(TCP_PROTOCOL_FLAG_RESET))
        self.assertEqual(False, pmap['tcp'].is_flag_set(TCP_PROTOCOL_FLAG_NS))
        self.assertEqual(False, pmap['tcp'].is_flag_set(TCP_PROTOCOL_FLAG_SYN))
        self.assertEqual(False, pmap['tcp'].is_flag_set(TCP_PROTOCOL_FLAG_URGENT))
        self.assertEqual(40880, pmap['tcp'].window_size)
        self.assertEqual(None, pmap['tcp'].next_parse_recommendation)
Beispiel #2
0
    def _read_packet(cli=LinuxCLI(), flag_set=None, interface='any',
                     count=1, packet_type='', pcap_filter=None, max_size=0,
                     packet_queues=None, callback=None, callback_args=None,
                     save_dump_file=False, save_dump_filename=None):

        tmp_dump_filename = './.tcpdump.out.' + str(time.time())

        try:
            # If flag set provided, use them instead, for synch with external functions
            tcp_ready = threading.Event() if flag_set is None else flag_set[0]
            tcp_error = threading.Event() if flag_set is None else flag_set[1]
            tcp_stop = threading.Event() if flag_set is None else flag_set[2]
            tcp_finished = threading.Event() if flag_set is None else flag_set[3]

            # If queue set provided, use them instead for synch with external functions
            packet_queue = Queue.Queue() if packet_queues is None else packet_queues[0]
            status_queue = Queue.Queue() if packet_queues is None else packet_queues[1]

            count_str = ('-c ' + str(count) if count > 0 else '')
            iface_str = '-i ' + interface
            max_size_str = '-s ' + max_size if max_size != 0 else ''
            type_str = '-T ' + packet_type if packet_type != '' else ''

            cmd_str = 'tcpdump -n -xx -l ' + \
                      count_str + ' ' + iface_str + ' ' + \
                      max_size_str + ' ' + type_str + \
                      "'" + (pcap_filter.to_str() if pcap_filter is not None else '') + "'" + \
                      ' >> ' + tmp_dump_filename

            #cli.log_cmd = True

            # FLAG STATE: ready[clear], stop[clear], finished[clear]

            with open(tmp_dump_filename, 'w') as f:
                f.write("--START--\n")

            tcp_process = cli.cmd(cmd_line=cmd_str, blocking=False)

            flags_se = fcntl(tcp_process.stderr, F_GETFL) # get current p.stderr flags
            fcntl(tcp_process.stderr, F_SETFL, flags_se | os.O_NONBLOCK)

            err_out = ''
            while tcp_ready.is_set() is False:
                try:
                    line = os.read(tcp_process.stderr.fileno(), 256)
                    if line.find('listening on') != -1:
                        # TODO: Replace sleep after TCPDump starts with a real check
                        # This is dangerous, and might not actually be enough to signal the
                        # tcpdump is actually running.  Instead, let's create a Cython module that
                        # passes calls through to libpcap (there are 0 good libpcap implementations
                        # for Python that are maintained, documented, and simple).
                        time.sleep(1)
                        tcp_ready.set()
                    else:
                        err_out += line
                        if tcp_process.poll() is not None:
                            out, err = tcp_process.communicate()
                            status_queue.put({'error': 'tcpdump exited abnormally',
                                              'returncode': tcp_process.returncode,
                                              'stdout': out,
                                              'stderr': err_out})
                            print 'item on status queue'
                            tcp_error.set()

                            raise SubprocessFailedException('tcpdump exited abnormally with status: ' +
                                                            str(tcp_process.returncode))
                        time.sleep(0)

                except OSError:
                    pass

            # FLAG STATE: ready[set], stop[clear], finished[clear]

            # tcpdump return output format:
            # hh:mm:ss.tick L3Proto <Proto-specific fields>\n
            # \t0x<addr>:  FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF\n <- eight quads of hexadecimal numbers
            # \t0x<addr>:  FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF\n    representing 16 bytes or 4 32-bit words
            # hh:mm:ss.tick L3Proto <Proto-specific fields>\n        <- Next packet
            # \t0x<addr>:  FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF\n
            # \t0x<addr>:  FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF\n

            packet_data = []
            timestamp = ''
            with open(tmp_dump_filename, 'r+') as f:
                # Prepare for the first packet by reading the file until the first
                # packet's lines arrive (or until stopped by a stop_capture call)
                if f.readline().rstrip() != '--START--':
                    status_queue.put({'error': 'Expected --START-- tag at beginning of dumpfile',
                                      'returncode': tcp_process.returncode,
                                      'stdout': '',
                                      'stderr': ''})
                    tcp_error.set()
                    raise ArgMismatchException('Expected --START-- tag at beginning of dumpfile')

                while True:
                    # Read the lines and either append data, start a new packet, or finish
                    # Read the lines and either append data, start a new packet, or finish
                    line = f.readline()

                    if line == '':
                        #EOF

                        # Is the tcpdump process finished or signaled to finish?
                        if tcp_process.poll() is not None or tcp_stop.is_set():
                            if tcp_process.poll() is None:
                                # Kill the TCP subprocess if it is still running
                                common.Utils.terminate_process(tcp_process)

                            # If we finished with packet data buffered up, append that packet to the queue
                            if len(packet_data) > 0:
                                # Create and parse the packet and push it onto the return list, calling
                                # the callback function if one is set.
                                packet = PCAPPacket(packet_data, timestamp)
                                packet.parse()
                                packet_queue.put(packet)
                                if callback is not None:
                                    callback(packet, *(callback_args if callback_args is not None else ()))

                            # Stop packet collection and exit
                            break

                        # Otherwise, we need to wait for data
                        time.sleep(0)

                    elif line.startswith('\t'):
                        # Normal packet data: buffer into current packet
                        packet_data += parse_line_to_byte_array(line)
                    else:
                        # We hit the end of the packet and will start a new packet
                        # Only run if we had packet data buffered
                        if len(packet_data) > 0:
                            # Create and parse the packet and push it onto the return list, calling
                            # the callback function if one is set.
                            packet = PCAPPacket(packet_data, timestamp)
                            packet.parse()
                            packet_queue.put(packet)
                            if callback is not None:
                                callback(packet, *(callback_args if callback_args is not None else []))
                            packet_data = []

                        # Start the new packet by reading the timestamp
                        timestamp = line.split(' ', 2)[0]
        finally:
            # Save the tcpdump output (if requested) and delete the temporary file
            if save_dump_file is True:
                LinuxCLI().copy_file(tmp_dump_filename,
                                     save_dump_filename if save_dump_filename is not None
                                     else 'tcp.out.' + str(time.time()))

            LinuxCLI().rm(tmp_dump_filename)


        status_queue.put({'success': '',
                          'returncode' : tcp_process.returncode,
                          'stdout': tcp_process.stdout,
                          'stderr': tcp_process.stderr})

        # FLAG STATE: ready[set], stop[set], finished[clear]
        tcp_finished.set()

        # FLAG STATE: ready[set], stop[set], finished[set]
        return packet_queue