def test_parses_valid_stream(self): stream = io.BytesIO(TESTDATA) pcap = PCAP(stream) header = pcap.global_header self.assertThat(header, Equals((2712847316, 2, 4, 0, 0, 64, 1))) pkt1 = pcap.read() self.assertThat(pkt1[0], Equals((1467058714, 931534, 60, 60))) self.assertThat( pkt1[1], Equals( b"\xff\xff\xff\xff\xff\xff\x00$\xa5\xaf$\x85\x08\x06\x00\x01\x08" b"\x00\x06\x04\x00\x01\x00$\xa5\xaf$\x85\xac\x10*\x01\x00\x00\x00" b"\x00\x00\x00\xac\x10*\xa7\x00\x00\x00\x00\x00\x00\x00\x00\x00" b"\x00\x00\x00\x00\x00\x00\x00\x00\x00"), ) pkt2 = pcap.read() self.assertThat(pkt2[0], Equals((1467058715, 380619, 60, 60))) self.assertThat( pkt2[1], Equals( b"\x80\xfa[\x0cFN\x00$\xa5\xaf$\x85\x08\x06\x00\x01\x08\x00\x06" b"\x04\x00\x01\x00$\xa5\xaf$\x85\xac\x10*\x01\x00\x00\x00\x00\x00" b"\x00\xac\x10*m\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" b"\x00\x00\x00\x00\x00\x00"), )
def test_raises_PCAPError_for_invalid_packet(self): stream = io.BytesIO(TESTDATA_INVALID_PACKET) pcap = PCAP(stream) header = pcap.global_header self.assertThat(header, Equals((2712847316, 2, 4, 0, 0, 64, 1))) with ExpectedException( PCAPError, "Unexpected end of PCAP stream: invalid packet."): pcap.read()
def test_gets_time_from_pcap_header(self): pcap_file = BytesIO(GOOD_ETHERNET_IPV4_UDP_PCAP) pcap = PCAP(pcap_file) for header, packet_bytes in pcap: packet = decode_ethernet_udp_packet(packet_bytes, header) self.expectThat(packet.timestamp, Equals(EXPECTED_PCAP_TIME)) self.expectThat(packet.payload, Equals(EXPECTED_PAYLOAD))
def test_iterator(self): stream = io.BytesIO(TESTDATA) pcap = PCAP(stream) count = 0 for _ in pcap: count += 1 # Expect no exception to have been thrown, and there are two packets. self.assertThat(count, Equals(2))
def observe_arp_packets(verbose=False, bindings=False, input=sys.stdin.buffer, output=sys.stdout): """Read stdin and look for tcpdump binary ARP output. :param verbose: Output text-based ARP packet details. :type verbose: bool :param bindings: Track (MAC, IP) bindings, and print new/update bindings. :type bindings: bool :param input: Stream to read PCAP data from. :type input: a file or stream supporting `read(int)` :param output: Stream to write JSON data to. :type input: a file or stream supporting `write(str)` and `flush()`. """ if bindings: bindings = dict() else: bindings = None try: pcap = PCAP(input) if pcap.global_header.data_link_type != 1: # Not an Ethernet interface. Need to exit here, because our # assumptions about the link layer header won't be correct. return 4 for header, packet in pcap: ethernet = Ethernet(packet, time=header.timestamp_seconds) if not ethernet.is_valid(): # Ignore packets with a truncated Ethernet header. continue if len(ethernet.payload) < SIZEOF_ARP_PACKET: # Ignore truncated ARP packets. continue if ethernet.ethertype != ETHERTYPE.ARP: # Ignore non-ARP packets. continue arp = ARP( ethernet.payload, src_mac=ethernet.src_mac, dst_mac=ethernet.dst_mac, vid=ethernet.vid, time=ethernet.time, ) if bindings is not None: update_and_print_bindings(bindings, arp, output) if verbose: arp.write() except EOFError: # Capture aborted before it could even begin. Note that this does not # occur if the end-of-stream occurs normally. (In that case, the # program will just exit.) return 3 except PCAPError: # Capture aborted due to an I/O error. return 2 return None
def test_raises_EOFError_for_end_of_stream(self): stream = io.BytesIO(TESTDATA) pcap = PCAP(stream) pcap.read() pcap.read() with ExpectedException(EOFError, "End of PCAP stream."): pcap.read()
def observe_beaconing_packets(input=sys.stdin.buffer, out=sys.stdout): """Read stdin and look for tcpdump binary beaconing output. :param input: Stream to read PCAP data from. :type input: a file or stream supporting `read(int)` :param out: Stream to write to. :type input: a file or stream supporting `write(str)` and `flush()`. """ err = sys.stderr try: pcap = PCAP(input) if pcap.global_header.data_link_type != 1: # Not an Ethernet interface. Need to exit here, because our # assumptions about the link layer header won't be correct. return 4 for pcap_header, packet_bytes in pcap: try: packet = decode_ethernet_udp_packet(packet_bytes, pcap_header) beacon = BeaconingPacket(packet.payload) if not beacon.valid: continue output_json = { "source_mac": format_eui(packet.l2.src_eui), "destination_mac": format_eui(packet.l2.dst_eui), "source_ip": str(packet.l3.src_ip), "destination_ip": str(packet.l3.dst_ip), "source_port": packet.l4.packet.src_port, "destination_port": packet.l4.packet.dst_port, "time": pcap_header.timestamp_seconds } if packet.l2.vid is not None: output_json["vid"] = packet.l2.vid if beacon.data is not None: output_json.update(beacon_to_json(beacon.data)) out.write(json.dumps(output_json)) out.write('\n') out.flush() except PacketProcessingError as e: err.write(e.error) err.write("\n") err.flush() except EOFError: # Capture aborted before it could even begin. Note that this does not # occur if the end-of-stream occurs normally. (In that case, the # program will just exit.) return 3 except PCAPError: # Capture aborted due to an I/O error. return 2 return None
def observe_dhcp_packets(input=sys.stdin.buffer, out=sys.stdout): """Read stdin and look for tcpdump binary DHCP output. :param input: Stream to read PCAP data from. :type input: a file or stream supporting `read(int)` :param out: Stream to write to. :type input: a file or stream supporting `write(str)` and `flush()`. """ try: pcap = PCAP(input) if pcap.global_header.data_link_type != 1: # Not an Ethernet interface. Need to exit here, because our # assumptions about the link layer header won't be correct. return 4 for pcap_header, packet_bytes in pcap: out.write(str(datetime.now())) out.write("\n") try: packet = decode_ethernet_udp_packet(packet_bytes, pcap_header) dhcp = DHCP(packet.payload) if not dhcp.is_valid(): out.write(dhcp.invalid_reason) out.write( " Source MAC address: %s\n" % format_eui(packet.l2.src_eui) ) out.write( "Destination MAC address: %s\n" % format_eui(packet.l2.dst_eui) ) if packet.l2.vid is not None: out.write(" Seen on 802.1Q VID: %s\n" % packet.l2.vid) out.write(" Source IP address: %s\n" % packet.l3.src_ip) out.write(" Destination IP address: %s\n" % packet.l3.dst_ip) dhcp.write(out=out) out.flush() except PacketProcessingError as e: out.write(e.error) out.write("\n\n") out.flush() except EOFError: # Capture aborted before it could even begin. Note that this does not # occur if the end-of-stream occurs normally. (In that case, the # program will just exit.) return 3 except PCAPError: # Capture aborted due to an I/O error. return 2 return None
def test_raises_PCAPError_for_invalid_PCAP_header(self): stream = io.BytesIO(b"\0" * 5) with ExpectedException( PCAPError, "Unexpected end of PCAP stream: invalid header."): PCAP(stream)
def test_raises_PCAPError_for_invalid_PCAP_stream(self): stream = io.BytesIO(b"\0" * 24) with ExpectedException(PCAPError, "Stream is not in native PCAP format."): PCAP(stream)
def test_raises_EOFError_for_empty_PCAP_stream(self): stream = io.BytesIO(b"") with ExpectedException(EOFError, "No PCAP output found."): PCAP(stream)