def decode_ethernet_udp_packet(packet, pcap_header=None): if pcap_header is None: timestamp = int(time.time()) else: timestamp = pcap_header.timestamp_seconds ethernet = Ethernet(packet, time=timestamp) if not ethernet.is_valid(): raise PacketProcessingError("Invalid Ethernet packet.") ethertype = ethernet.ethertype supported_ethertypes = (ETHERTYPE.IPV4, ETHERTYPE.IPV6) if ethertype not in supported_ethertypes: raise PacketProcessingError( "Invalid ethertype; expected one of %r, got %r." % (supported_ethertypes, ethertype)) # Interpret Layer 3 if ethertype == ETHERTYPE.IPV4: ip = IPv4(ethernet.payload) else: ip = IPv6(ethernet.payload) if not ip.is_valid(): raise PacketProcessingError(ip.invalid_reason) if ip.protocol != PROTOCOL.UDP: raise PacketProcessingError( "Invalid protocol; expected %d (UDP), got %d." % (PROTOCOL.UDP, ip.protocol)) # Interpret Layer 4 udp = UDP(ip.payload) if not udp.is_valid(): raise PacketProcessingError(udp.invalid_reason) return Packet(timestamp, ethernet, ip, udp, udp.payload)
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__is_valid_returns_false_for_truncated_non_vlan(self): src_mac = factory.make_mac_address() dst_mac = factory.make_mac_address() ethertype = ETHERTYPE.ARP payload = factory.make_bytes(48) packet = make_ethernet_packet(dst_mac=dst_mac, src_mac=src_mac, ethertype=ethertype, payload=payload) packet = packet[0:13] eth = Ethernet(packet) self.assertThat(eth.is_valid(), Equals(False))
def test__parses_non_vlan(self): src_mac = factory.make_mac_address() dst_mac = factory.make_mac_address() ethertype = ETHERTYPE.ARP payload = factory.make_bytes(48) eth = Ethernet( make_ethernet_packet(dst_mac=dst_mac, src_mac=src_mac, ethertype=ethertype, payload=payload)) self.assertThat(eth.dst_mac, Equals(hex_str_to_bytes(dst_mac))) self.assertThat(eth.src_mac, Equals(hex_str_to_bytes(src_mac))) self.assertThat(eth.ethertype, Equals(ethertype)) self.assertThat(eth.payload, Equals(payload)) self.assertThat(eth.is_valid(), Equals(True))