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 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_fails_if_ipv6_udp_packet_truncated(self): with ExpectedException(PacketProcessingError, ".*UDP packet trunc.*"): decode_ethernet_udp_packet(BAD_ETHERNET_IPV6_TRUNCATED_UDP_PAYLOAD)
def test_fails_if_not_udp_protocol_ipv6(self): with ExpectedException(PacketProcessingError, ".*Invalid protocol*"): decode_ethernet_udp_packet(BAD_IPV6_NOT_UDP_PROTOCOL)
def test_fails_for_bad_ipv6_udp_header(self): with ExpectedException(PacketProcessingError, ".*Truncated UDP.*"): decode_ethernet_udp_packet(BAD_IPV6_TRUNCATED_UDP_HEADER)
def test_fails_for_bad_ethernet_packet(self): with ExpectedException(PacketProcessingError, ".*Invalid Ethernet.*"): decode_ethernet_udp_packet(BAD_ETHERNET_TRUNCATED_HEADER)
def test_fails_for_bad_ethertype(self): with ExpectedException(PacketProcessingError, ".*Invalid ethertype.*"): decode_ethernet_udp_packet(BAD_ETHERNET_ETHERTYPE)
def test_decodes_ipv4_from_bytes(self): expected_time = EXPECTED_PCAP_TIME + randint(1, 100) self.patch(time, "time").return_value = expected_time packet = decode_ethernet_udp_packet(GOOD_ETHERNET_IPV4_UDP_PACKET) self.expectThat(packet.timestamp, Equals(expected_time)) self.expectThat(packet.payload, Equals(EXPECTED_PAYLOAD))
def test__fails_if_udp_packet_truncated(self): self.patch(time, "time").return_value = EXPECTED_PCAP_TIME with ExpectedException(PacketProcessingError, '.*UDP packet trunc.*'): decode_ethernet_udp_packet(TRUNCATED_UDP_PAYLOAD)
def test__fails_if_not_udp_protocol(self): self.patch(time, "time").return_value = EXPECTED_PCAP_TIME with ExpectedException(PacketProcessingError, '.*Invalid protocol*'): decode_ethernet_udp_packet(NOT_UDP_PROTOCOL)
def test__fails_for_bad_udp_header(self): self.patch(time, "time").return_value = EXPECTED_PCAP_TIME with ExpectedException(PacketProcessingError, '.*Truncated UDP.*'): decode_ethernet_udp_packet(BAD_IPV4_UDP_HEADER)
def test__fails_for_bad_ethernet_packet(self): self.patch(time, "time").return_value = EXPECTED_PCAP_TIME with ExpectedException(PacketProcessingError, '.*Invalid Ethernet.*'): decode_ethernet_udp_packet(TRUNCATED_ETHERNET_HEADER)
def test__fails_for_bad_ethertype(self): self.patch(time, "time").return_value = EXPECTED_PCAP_TIME with ExpectedException(PacketProcessingError, '.*Invalid ethertype.*'): decode_ethernet_udp_packet(BAD_ETHERTYPE)