class ArpPacketParser(PacketParserInterface):
    def __init__(self, config: ConfigurationData):
        self.config = config
        self.ip_utils = IpAddrUtils()
        self.mac_utils = MacAddressUtils()

    def extract_data(self, packet: ARP) -> Munch:
        data = Munch()
        try:
            data.arp_request_src = packet.op
            data.arp_src_mac = self.mac_utils.convert_hexadecimal_mac_to_readable_mac(
                packet.sha)
            data.arp_src_ip = self.ip_utils.inet_to_str(packet.spa)
            data.arp_dst_mac = self.mac_utils.convert_hexadecimal_mac_to_readable_mac(
                packet.tha)
            data.arp_dst_ip = self.ip_utils.inet_to_str(packet.tpa)

            if self.config.use_numeric_values is True:
                data.arp_src_mac = self.mac_utils.mac_to_int(data.arp_src_mac)
                data.arp_dst_mac = self.mac_utils.mac_to_int(data.arp_dst_mac)
                data.arc_src_ip = self.ip_utils.ip_to_int(data.arp_src_ip)
                data.arc_dst_ip = self.ip_utils.ip_to_int(data.arp_src_ip)

        except BaseException as ex:
            logging.warning('Unable to extract ARP from `%s`. Error: `%s`',
                            type(packet), ex)
            raise ex

        return data
    def validate(cls, value):
        mac_utils = MacAddressUtils()
        if mac_utils.is_valid_mac(value) is False:
            raise ValueError(
                'Invalid mac address format: expected format : or - separated, provided: {}'
                .format(value))

        return value
Exemplo n.º 3
0
class EthernetFrameParserTests(BasePacketParserTests):
    def __init__(self, *args, **kwargs):
        super(EthernetFrameParserTests, self).__init__(*args, **kwargs)
        self.eth_frame_parser = EthernetFrameParser(config=self.config)
        self.mac_utils = MacAddressUtils()

    def test_extract_data_works_as_expected(self):
        mock_src_mac = '01:23:45:67:89:ab'
        mock_dst_mac = 'ab:cf:ef:01:23:45'
        mock_data = b'1234'
        eth_frame = dpkt.ethernet.Ethernet()
        eth_frame.src = self.mac_utils.convert_string_mac_to_byte_array(
            mock_src_mac)
        eth_frame.dst = self.mac_utils.convert_string_mac_to_byte_array(
            mock_dst_mac)
        eth_frame.type = 2048
        eth_frame.data = mock_data

        eth_data = self.eth_frame_parser.extract_data(eth_frame)

        self.assertIsInstance(eth_data, Munch)
        self.assertEqual(eth_data.src_mac, mock_src_mac)
        self.assertEqual(eth_data.dst_mac, mock_dst_mac)
        self.assertEqual(eth_data.eth_type, 'ipv4')
        self.assertEqual(eth_data.eth_payload_size, len(mock_data))

    def test_get_eth_type_name_returns_protocol_abbrv(self):
        eth_frame = dpkt.ethernet.Ethernet()
        eth_frame.type = 2048

        self.assertEqual(self.eth_frame_parser.get_eth_type_name(eth_frame),
                         'ipv4')

    def test_get_eth_type_name_returns_protocol_hex_if_no_abbrv_found(self):
        eth_hex = '0x901'
        eth_frame = dpkt.ethernet.Ethernet()
        eth_frame.type = int(eth_hex, 0)

        self.assertEqual(self.eth_frame_parser.get_eth_type_name(eth_frame),
                         eth_hex[2:])

    def test_extract_src_dst_mac_from_eth_frame_works_as_expected(self):
        mock_src_mac = '01:23:45:67:89:ab'
        mock_dst_mac = 'ab:cf:ef:01:23:45'
        eth_frame = dpkt.ethernet.Ethernet()
        eth_frame.src = self.mac_utils.convert_string_mac_to_byte_array(
            mock_src_mac)
        eth_frame.dst = self.mac_utils.convert_string_mac_to_byte_array(
            mock_dst_mac)

        src_mac, dst_mac = self.eth_frame_parser.extract_src_dest_mac_from_eth_frame(
            eth_frame)

        self.assertEqual(src_mac, mock_src_mac)
        self.assertEqual(dst_mac, mock_dst_mac)
class EthernetFrameParser(PacketParserInterface):
    def __init__(self, config: ConfigurationData, static_data: StaticData = None):
        self.config = config
        self.mac_utils = MacAddressUtils()
        self.static_data = static_data or StaticData()

    def extract_data(self, packet: Ethernet) -> Munch:
        data = Munch()
        try:
            data.src_mac, data.dst_mac = self.extract_src_dest_mac_from_eth_frame(eth_frame=packet)
            data.eth_type = self.get_eth_type_name(packet)
            data.eth_payload_size = len(packet.data)

        except BaseException as ex:
            logging.warning('Unable to extract ETH from `%s`. Error: `%s`', type(packet), ex)
            raise ex

        return data

    def get_eth_type_name(self, eth_frame: Ethernet) -> Union[int, str]:
        eth_type = str(hex(eth_frame.type)[2:])
        if self.config.use_numeric_values is True:
            return hex_to_integer(eth_type)

        eth_type_str = self.static_data.ether_types_data.get(eth_type, {}).get('protocol_abbrv', '').lower()
        if not eth_type_str:
            eth_type_str = eth_type

        return eth_type_str

    def extract_src_dest_mac_from_eth_frame(self, eth_frame: Ethernet) -> Tuple:
        src_mac = self.mac_utils.convert_hexadecimal_mac_to_readable_mac(eth_frame.src)
        dst_mac = self.mac_utils.convert_hexadecimal_mac_to_readable_mac(eth_frame.dst)

        if self.config.use_numeric_values is True:
            return self.mac_utils.mac_to_int(src_mac), self.mac_utils.mac_to_int(dst_mac)

        return src_mac, dst_mac
 def __init__(self, config: ConfigurationData, static_data: StaticData = None):
     self.config = config
     self.mac_utils = MacAddressUtils()
     self.static_data = static_data or StaticData()
 def __init__(self, config: ConfigurationData):
     self.config = config
     self.ip_utils = IpAddrUtils()
     self.mac_utils = MacAddressUtils()
 def __init__(self, *args, **kwargs):
     super(MacUtilsTests, self).__init__(*args, **kwargs)
     self.mac_utils = MacAddressUtils()
class MacUtilsTests(unittest.TestCase):
    def __init__(self, *args, **kwargs):
        super(MacUtilsTests, self).__init__(*args, **kwargs)
        self.mac_utils = MacAddressUtils()

    def test_mac_regex_validation(self):
        for mac_addr in MAC_ADDRESSES:
            self.assertTrue(self.mac_utils.is_valid_mac(mac_addr))

    def test_int2mac_returns_valid_mac(self):
        for mac_addr in MAC_ADDRESSES:
            self.assertIsInstance(self.mac_utils.mac_to_int(mac_addr), int)

    def test_mac_to_int_to_mac_works_as_expected(self):
        for mac_addr in MAC_ADDRESSES:
            integer_mac = self.mac_utils.mac_to_int(mac_addr)
            self.assertEqual(mac_addr, self.mac_utils.int_to_mac(integer_mac))

    def test_convert_hexadecimal_mac_to_readable_mac_works_as_expected(self):
        for mac_addr in MAC_ADDRESSES:
            byte_mac = self.mac_utils.convert_string_mac_to_byte_array(mac_addr)
            self.assertIsInstance(byte_mac, bytearray)
            self.assertEqual(mac_addr, self.mac_utils.convert_hexadecimal_mac_to_readable_mac(byte_mac))

    def test_convert_hexadecimal_mac_to_readable_mac_as_expected(self):
        for mac_addr in MAC_ADDRESSES:
            byte_mac = self.mac_utils.convert_string_mac_to_byte_array(mac_addr)
            self.assertIsInstance(byte_mac, bytearray)
            self.assertEqual(mac_addr, self.mac_utils.convert_hexadecimal_mac_to_readable_mac(byte_mac))

    def test_get_mac_address_to_byte_str_returns_none_given_mac_is_invalid(self):
        self.assertIsNone(self.mac_utils.convert_string_mac_to_byte_array(mac_address=None))            # MAC is None
        self.assertIsNone(self.mac_utils.convert_string_mac_to_byte_array(mac_address=''))              # MAC is empty
        self.assertIsNone(self.mac_utils.convert_string_mac_to_byte_array(mac_address='invalidmac'))    # MAC is invalid
Exemplo n.º 9
0
 def __init__(self, *args, **kwargs):
     super(BasePacketParserTests, self).__init__(*args, **kwargs)
     self.ip_utils = IpAddrUtils()
     self.mac_utils = MacAddressUtils()
     self.config = CONFIGURATION_OBJ
     self.static_data = StaticData()
Exemplo n.º 10
0
 def __init__(self, config: ConfigurationData, static_data: StaticData = None):
     self.mac_utils = MacAddressUtils()
     self.ip_utils = IpAddrUtils()
     self.ether_type_data = StaticData.load_ether_types_data()
     self.config = config
     self.static_data = static_data or StaticData()
Exemplo n.º 11
0
class DpktUtils:
    def __init__(self, config: ConfigurationData, static_data: StaticData = None):
        self.mac_utils = MacAddressUtils()
        self.ip_utils = IpAddrUtils()
        self.ether_type_data = StaticData.load_ether_types_data()
        self.config = config
        self.static_data = static_data or StaticData()

    def extract_data_from_eth_frame(self, eth_frame: Ethernet, packet_data: PacketData) -> PacketData:
        eth_frame_parser = EthernetFrameParser(config=self.config, static_data=self.static_data)
        eth_data = eth_frame_parser.extract_data(packet=eth_frame)
        packet_data = self.load_protocol_data_to_packet_data(eth_data, packet_data)

        return packet_data

    def load_layer3_packet(self, eth_frame: Ethernet) -> Optional[Packet]:
        """
        Take an ethernet frame and parse its data as layer3 packet. Currently supported protocols are IPv4, IPv6, ARP,
        LLC, IEEE80211
        """
        if eth_frame.type == dpkt.ethernet.ETH_TYPE_IP:  # IPv4 Packet
            return IpPacketParser.load_ip_packet_from_ethernet_frame(eth_frame.data)

        if eth_frame.type == dpkt.ethernet.ETH_TYPE_IP6:  # IPv6 Packet
            return eth_frame.data

        if eth_frame.type == dpkt.ethernet.ETH_TYPE_ARP:  # ARP packet
            return eth_frame.data

        if isinstance(eth_frame.data, dpkt.llc.LLC):  # IEEE 802.3 Logical Link Control
            return eth_frame.data

        if eth_frame.type == IEEE80211_PROTOCOL_NUMBER:  # IEEE 802.1X Authentication
            return eth_frame.data

        # TODO: Handle other layer 3 packets, e.g. TDLS discovery requests
        _protocol = self.ether_type_data.get(str(hex(eth_frame.type)[2:]))
        if _protocol is None:
            logging.warning('Unable to get protocol from ether_type (int): `%s`', _protocol)

        return None

    def extract_data_from_layer3_packet(self, layer3_packet, packet_data: PacketData) -> PacketData:
        data = Munch()
        if isinstance(layer3_packet, IP):  # IPv4 Packet
            data = self.extract_data_from_ip4_packet(ip_packet=layer3_packet)

        if isinstance(layer3_packet, IP6):  # IPv6 Packet
            data = self.extract_data_from_ip6_packet(ip6_packet=layer3_packet)

        if isinstance(layer3_packet, ARP):  # ARP packet
            data = self.extract_data_from_arp_packet(arp_packet=layer3_packet)

        if isinstance(layer3_packet, LLC):  # IEEE 802.3 Logical Link Control
            data = self.extract_data_from_llc_packet(llc_packet=layer3_packet)

        if isinstance(layer3_packet, IEEE80211):  # IEEE 802.1X Authentication
            data = self.extract_data_from_80211_packet(layer3_packet)

        return self.load_protocol_data_to_packet_data(data, packet_data)

    def extract_data_from_ip4_packet(self, ip_packet: IP) -> Union[Munch, dict]:
        ip_packet_parser = IpPacketParser(config=self.config, static_data=self.static_data)
        return ip_packet_parser.extract_data(packet=ip_packet)

    def extract_data_from_ip6_packet(self, ip6_packet: IP6) -> Union[Munch, dict]:
        ip6_packet_parser = Ip6PacketParser(config=self.config)
        return ip6_packet_parser.extract_data(packet=ip6_packet)

    def extract_data_from_llc_packet(self, llc_packet: LLC) -> Union[Munch, dict]:
        llc_packet_parser = LlcPacketParser(config=self.config)
        return llc_packet_parser.extract_data(llc_packet)

    def extract_data_from_80211_packet(self, ieee80211_packet: IEEE80211) -> Union[Munch, dict]:
        ieee80211_packet_parser = IEEE80211PacketParser(config=self.config)
        return ieee80211_packet_parser.extract_data(ieee80211_packet)

    def extract_data_from_arp_packet(self, arp_packet: ARP) -> Union[Munch, dict]:
        arp_packet_parser = ArpPacketParser(config=self.config)
        return arp_packet_parser.extract_data(packet=arp_packet)

    def load_layer4_packet(self, layer3_packet: Packet) -> Optional[Packet]:
        if layer3_packet is None:
            return None

        packet_data = None
        if layer3_packet.p == dpkt.ip.IP_PROTO_TCP:  # TCP packet
            packet_data = layer3_packet.data

        elif layer3_packet.p == dpkt.ip.IP_PROTO_UDP:  # UDP packet
            packet_data = layer3_packet.data

        elif layer3_packet.p == dpkt.ip.IP_PROTO_ICMP:  # ICMP packet
            packet_data = layer3_packet.data

        elif layer3_packet.p == dpkt.ip.IP_PROTO_ICMP6:  # ICMPv6 packet
            packet_data = layer3_packet.data

        elif layer3_packet.p == dpkt.ip.IP_PROTO_IGMP:  # IGMP packet
            packet_data = layer3_packet.data

        else:
            logging.warning(
                'Unidentified Protocol. Proto Num: `%s`, Type: `%s`',
                layer3_packet.p,
                type(layer3_packet.data)
            )
        return packet_data

    def extract_data_from_layer4_packet(self, layer4_packet: Packet, packet_data: PacketData) -> PacketData:
        data = None
        if isinstance(layer4_packet, TCP):  # TCP packet
            data = self.extract_data_from_tcp_packet(layer4_packet)

        elif isinstance(layer4_packet, UDP):  # UDP packet
            data = self.extract_data_from_udp_packet(layer4_packet)

        elif isinstance(layer4_packet, ICMP):
            data = self.extract_data_from_icmp_packet(layer4_packet)

        elif isinstance(layer4_packet, ICMP6):
            data = self.extract_data_from_icmp6_packet(layer4_packet)

        elif isinstance(layer4_packet, IGMP):
            data = self.extract_data_from_igmp_packet(layer4_packet)

        return self.load_protocol_data_to_packet_data(data, packet_data)

    def extract_data_from_tcp_packet(self, tcp_packet: TCP) -> Union[Munch, dict]:
        tcp_packet_parser = TcpPacketParser(config=self.config, static_data=self.static_data)
        return tcp_packet_parser.extract_data(packet=tcp_packet)

    def extract_data_from_udp_packet(self, udp_packet: UDP) -> Union[Munch, dict]:
        udp_packet_parser = UDPPacketParser(config=self.config, static_data=self.static_data)
        return udp_packet_parser.extract_data(packet=udp_packet)

    def extract_data_from_icmp_packet(self, icmp_packet: ICMP) -> Union[Munch, dict]:
        icmp_packet_parser = IcmpPacketParser(config=self.config)
        return icmp_packet_parser.extract_data(icmp_packet)

    def extract_data_from_icmp6_packet(self, icmp6_packet: ICMP6) -> Union[Munch, dict]:
        icmp6_packet_parser = Icmp6PacketParser(config=self.config)
        return icmp6_packet_parser.extract_data(icmp6_packet)

    def extract_data_from_igmp_packet(self, igmp_packet: IGMP) -> Union[Munch, dict]:
        igmp_packet_parser = IgmpPacketParser(config=self.config)
        return igmp_packet_parser.extract_data(igmp_packet)

    def extract_tcp_syn_signature(self, ip_packet: IP, packet_data: PacketData) -> PacketData:
        syn_packet_parser = SynPacketParser(config=self.config)
        syn_packet_data = syn_packet_parser.extract_data(ip_packet)
        packet_data = self.load_protocol_data_to_packet_data(syn_packet_data, packet_data)

        return packet_data

    def load_layer7_packet(self, layer4_packet: Packet, packet_data: PacketData) -> Optional[Union[Natpmp, Packet]]:
        if not isinstance(layer4_packet, UDP):
            return None

        layer7_packet = None

        if packet_data.src_port == 5351 or packet_data.dst_port == 5351:  # This is a NAT-PMP packet.
            layer7_packet = Natpmp(buf=layer4_packet.data)

        elif packet_data.src_port == 53 or packet_data.dst_port == 53:  # DNS packet
            layer7_packet = DnsPacketParser.load_dns_packet_from_udp_packet(layer4_packet)

        elif packet_data.src_port == 123 or packet_data.dst_port == 123:  # NTP packet
            layer7_packet = NtpPacketParser.load_ntp_packet_from_udp_packet(layer4_packet)

        elif packet_data.src_port in UPNP_PORTS or packet_data.dst_port in UPNP_PORTS:  # UPnP packet
            layer7_packet = UpnpPacketParser.load_upnp_packet_from_udp_packet(layer4_packet)

        elif packet_data.src_port in MDNS_PORTS or packet_data.dst_port in MDNS_PORTS:  # mDNS packet
            layer7_packet = MdnsPacketParser.load_mdns_packet_from_udp_packet(layer4_packet)

        elif packet_data.src_port in DHCP_PORTS or packet_data.dst_port in DHCP_PORTS:  # DHCP packet
            layer7_packet = DhcpPacketParser.load_dhcp_from_udp_packet(layer4_packet)

        return layer7_packet

    def extract_data_from_layer7_packet(self, layer7_packet: Packet, packet_data: PacketData) -> PacketData:
        """Currently supported Layer 7 protocols are DHCP, UPNP, MDNS, DNS, NTP"""
        data = Munch()
        # This needs to be the first in order
        if isinstance(layer7_packet, Natpmp):  # NAT-PMP packet
            data = self.extract_data_from_natpmp_packet(layer7_packet)

        elif isinstance(layer7_packet, DNS):  # DNS packet
            data = self.extract_data_from_dns_packet(layer7_packet)

        elif isinstance(layer7_packet, Mdns):  # mDNS packet
            data = self.extract_data_from_mdns_packet(layer7_packet)

        elif isinstance(layer7_packet, NTP):  # NTP packet
            data = self.extract_data_from_ntp_packet(layer7_packet)

        elif isinstance(layer7_packet, (UpnpRequest, dpkt.http.Response)):  # UPnP packet
            data = self.extract_data_from_upnp_packet(layer7_packet)

        elif isinstance(layer7_packet, DHCP):  # DNS packet
            data = self.extract_data_from_dhcp_packet(layer7_packet)

        return self.load_protocol_data_to_packet_data(data, packet_data)

    def extract_data_from_ntp_packet(self, ntp_packet: NTP) -> Union[Munch, dict]:
        ntp_packet_parser = NtpPacketParser(config=self.config)
        return ntp_packet_parser.extract_data(ntp_packet)

    def extract_data_from_dns_packet(self, dns_packet: DNS) -> Union[Munch, dict]:
        dns_packet_parser = DnsPacketParser(config=self.config)
        return dns_packet_parser.extract_data(dns_packet)

    def extract_data_from_upnp_packet(self, upnp_packet: Union[UpnpRequest, dpkt.http.Response]) -> Union[Munch, dict]:
        upnp_packet_parser = UpnpPacketParser(config=self.config)
        return upnp_packet_parser.extract_data(upnp_packet)

    def extract_data_from_mdns_packet(self, mdns_packet: Mdns) -> Union[Munch, dict]:
        mdns_packet_parser = MdnsPacketParser(config=self.config)
        return mdns_packet_parser.extract_data(mdns_packet)

    def extract_data_from_dhcp_packet(self, dhcp_packet: DHCP) -> Union[Munch, dict]:
        dhcp_packet_parser = DhcpPacketParser(config=self.config)
        return dhcp_packet_parser.extract_data(dhcp_packet)

    def extract_data_from_natpmp_packet(self, natpmp_packet: Natpmp) -> Union[Munch, dict]:
        nat_packet_parser = NatpmpPacketParser(config=self.config)
        return nat_packet_parser.extract_data(natpmp_packet)

    def parse_byte_data_as_ethernet_headers(self, packet_data: bytes) -> Munch:
        data = Munch()

        decoded_data = binascii.hexlify(packet_data).decode('utf-8')
        data.src_mac = hex_to_integer(decoded_data[:12])
        data.dst_mac = hex_to_integer(decoded_data[12:24])
        data.eth_type = hex_to_integer(decoded_data[24:28])
        data.payload_size = len(decoded_data[28:])/2

        if self.config.use_numeric_values is False:
            data.src_mac = self.mac_utils.int_to_mac(data.src_mac)
            data.dst_mac = self.mac_utils.int_to_mac(data.dst_mac)
            data.eth_type = decoded_data[24:28]

        return data

    def load_protocol_data_to_packet_data(
            self,
            protocol_data: Optional[Union[dict, Munch]],
            packet_data: PacketData
    ) -> PacketData:
        if protocol_data is None or not isinstance(protocol_data, dict):
            logging.debug('Unable to load protocol data from `%s` object. <dict> expected', type(protocol_data))
            return packet_data

        for key, value in protocol_data.items():
            if packet_data.is_valid_value(value):  # If it is valid value, load it to packet data
                if hasattr(packet_data, key) and not callable(getattr(packet_data, key)):
                    setattr(packet_data, key, value)
                else:
                    logging.warning(
                        'Trying to set invalid or callable property `%s` in `%s` object',
                        key,
                        type(packet_data)
                    )

        return packet_data
from pathlib import Path  # noqa
import os
import sys

sys.path.append(os.getcwd())

# pylint: disable=wrong-import-position
from core.lib.mac_utils import MacAddressUtils  # noqa
from core.lib.common import print_json  # noqa
from core.pandas_utils.split_csv_data import extract_data_as_separate_csv  # noqa

if __name__ == '__main__':
    scripts_dir_path = Path(os.path.abspath(__file__)).parent
    project_dir_path = scripts_dir_path.parent
    input_file_path = project_dir_path / 'fixtures/results/results.csv'
    result_dir_path = project_dir_path / 'fixtures/results/splitted/'
    summary = extract_data_as_separate_csv(
        file_path=input_file_path,
        result_folder=result_dir_path,
        filter_columns=['src_mac', 'dst_mac'],
        sort_by_columns=['timestamp'],
        transform_function=MacAddressUtils().int_to_mac)
    print_json(summary)
Exemplo n.º 13
0
 def __init__(self, *args, **kwargs):
     super(EthernetFrameParserTests, self).__init__(*args, **kwargs)
     self.eth_frame_parser = EthernetFrameParser(config=self.config)
     self.mac_utils = MacAddressUtils()
 def __init__(self, *args, **kwargs):
     super(DpktUtilsTest, self).__init__(*args, **kwargs)
     self.dpkt_utils = DpktUtils(config=CONFIGURATION_OBJ)
     self.mac_utils = MacAddressUtils()
class DpktUtilsTest(unittest.TestCase):
    def __init__(self, *args, **kwargs):
        super(DpktUtilsTest, self).__init__(*args, **kwargs)
        self.dpkt_utils = DpktUtils(config=CONFIGURATION_OBJ)
        self.mac_utils = MacAddressUtils()

    def test_extract_data_from_eth_frame_works_as_expected(self):
        src_mac = "3d:d5:31:0b:01:15"
        dst_mac = "9b:b0:7c:bb:f4:09"
        eth_frame = dpkt.ethernet.Ethernet()
        eth_frame.src = self.mac_utils.convert_string_mac_to_byte_array(
            src_mac)
        eth_frame.dst = self.mac_utils.convert_string_mac_to_byte_array(
            dst_mac)
        eth_frame.data = '1234'
        eth_frame.type = 2048

        packet_data = self.dpkt_utils.extract_data_from_eth_frame(
            eth_frame, PacketData())
        self.assertEqual(src_mac, packet_data.src_mac)
        self.assertEqual(dst_mac, packet_data.dst_mac)
        self.assertEqual('ipv4', packet_data.eth_type)
        self.assertNotEqual(0, packet_data.eth_payload_size)

    def test_extract_data_from_layer3_packet_works_as_expected_for_ip6_packets(
            self):
        mock_src_ip6 = '786b:a7d6:fc04:1d14:dfcd:5005:655e:f092'
        mock_dst_ip6 = '7112:76d5:8e4f:82d7:e384:eedd:20e0:a6ab'
        ip_packet = dpkt.ip6.IP6()
        ip_packet.src = socket.inet_pton(socket.AF_INET6, mock_src_ip6)
        ip_packet.dst = socket.inet_pton(socket.AF_INET6, mock_dst_ip6)
        ip_packet.p = 2048
        ip_packet.data = b'abcdef0123456789'
        ip_packet.all_extension_headers = []

        packet_data = self.dpkt_utils.extract_data_from_layer3_packet(
            ip_packet, PacketData())

        self.assertEqual(mock_src_ip6, packet_data.src_ip)
        self.assertEqual(mock_dst_ip6, packet_data.dst_ip)
        self.assertEqual(ip_packet.p, packet_data.ip_proto)
        self.assertEqual(len(ip_packet.data), packet_data.ip_payload_size)

    def test_extract_data_from_layer3_packet_works_as_expected_for_ip_packets(
            self):
        mock_src_ip = '192.168.100.1'
        mock_dst_ip = '192.168.100.2'

        ip_packet = dpkt.ip.IP()
        ip_packet.src = socket.inet_aton(mock_src_ip)
        ip_packet.dst = socket.inet_aton(mock_dst_ip)
        ip_packet.p = 2048
        ip_packet.data = b'abcdef0123456789'
        ip_packet.ttl = 60
        ip_packet.tos = 2

        packet_data = self.dpkt_utils.extract_data_from_layer3_packet(
            layer3_packet=ip_packet, packet_data=PacketData())

        self.assertEqual(mock_src_ip, packet_data.src_ip)
        self.assertEqual(mock_dst_ip, packet_data.dst_ip)
        self.assertEqual(str(ip_packet.p), packet_data.ip_proto)
        self.assertEqual(len(ip_packet.data), packet_data.ip_payload_size)
        self.assertEqual(ip_packet.ttl, packet_data.ip_ttl)
        self.assertIsInstance(packet_data.ip_more_fragment, bool)

    def test_extract_data_from_layer3_packet_works_as_expected_for_arp_packets(
            self):
        src_mac = "d3:d5:01:0b:31:15"
        dst_mac = "9b:b0:01:bb:7c:09"
        src_ip = '192.168.100.1'
        dst_ip = '192.168.100.2'

        arp_packet = dpkt.arp.ARP()
        arp_packet.sha = self.mac_utils.convert_string_mac_to_byte_array(
            src_mac)
        arp_packet.tha = self.mac_utils.convert_string_mac_to_byte_array(
            dst_mac)
        arp_packet.spa = socket.inet_aton(src_ip)
        arp_packet.tpa = socket.inet_aton(dst_ip)
        arp_packet.op = 2

        packet_data = self.dpkt_utils.extract_data_from_layer3_packet(
            layer3_packet=arp_packet, packet_data=PacketData())

        self.assertEqual(src_mac, packet_data.arp_src_mac)
        self.assertEqual(dst_mac, packet_data.arp_dst_mac)
        self.assertEqual(arp_packet.op, packet_data.arp_request_src)
        self.assertEqual(src_ip, packet_data.arp_src_ip)
        self.assertEqual(dst_ip, packet_data.arp_dst_ip)

    def test_extract_data_from_layer4_packet_works_as_expected_for_tcp_packet(
            self):
        tcp_packet = dpkt.tcp.TCP()
        tcp_packet.sport = 50000
        tcp_packet.dport = 80
        tcp_packet.flags = 0x100
        tcp_packet.data = 'dummy_data'
        packet_data = self.dpkt_utils.extract_data_from_layer4_packet(
            layer4_packet=tcp_packet, packet_data=PacketData())

        self.assertTrue(packet_data.outgoing)
        self.assertEqual(80, packet_data.dst_port)
        self.assertEqual(50000, packet_data.src_port)
        self.assertNotEqual(0, packet_data.layer4_payload_size)
        self.assertEqual('http', packet_data.layer7_proto)  # HTTP uses port 80

    def test_extract_data_from_layer4_packet_works_as_expected_for_udp_packet(
            self):
        udp_packet = dpkt.udp.UDP()
        udp_packet.sport = 50000
        udp_packet.dport = 800
        udp_packet.data = b'dummy_data'

        packet_data = self.dpkt_utils.extract_data_from_layer4_packet(
            layer4_packet=udp_packet, packet_data=PacketData())

        self.assertTrue(packet_data.outgoing)
        self.assertEqual(udp_packet.dport, packet_data.dst_port)
        self.assertEqual(udp_packet.sport, packet_data.src_port)
        self.assertNotEqual(0, packet_data.layer4_payload_size)
        self.assertEqual('mdbe',
                         packet_data.layer7_proto)  # mdbe uses port 800

    def test_extract_data_from_layer7_packet_works_for_dns_packet(self):
        mock_ans_1 = dpkt.dns.DNS.RR()
        mock_ans_1.type = dpkt.dns.DNS_CNAME
        mock_ans_1.ttl = 60
        mock_ans_1.name = 'mock_cname_ans'
        mock_dns_packet = DNS()
        mock_dns_packet.an = [mock_ans_1]
        mock_dns_packet.qr = dpkt.dns.DNS_R

        packet_data = self.dpkt_utils.extract_data_from_layer7_packet(
            mock_dns_packet, PacketData())

        self.assertEqual(mock_ans_1.name, packet_data.dns_ans_cname)
        self.assertEqual(mock_ans_1.ttl, packet_data.dns_ans_cname_ttl)
        self.assertIsNone(packet_data.dns_ans_name)
        self.assertIsNone(packet_data.dns_ans_ip)
        self.assertIsNone(packet_data.dns_ans_ttl)

    def test_extract_data_from_layer7_packet_works_for_ntp_packet(self):
        ntp_packet = NTP()
        mock_ntp_reference = '1.2.3.4'
        ntp_packet.id = socket.inet_aton(mock_ntp_reference)
        ntp_packet.mode = 1
        ntp_packet.stratum = 2
        ntp_packet.interval = 5

        packet_data = PacketData(dst_port=123)
        packet_data = self.dpkt_utils.extract_data_from_layer7_packet(
            ntp_packet, packet_data)

        self.assertEqual(mock_ntp_reference, packet_data.ntp_reference_id)
        self.assertEqual(ntp_packet.mode, packet_data.ntp_mode)
        self.assertEqual(ntp_packet.stratum, packet_data.ntp_stratum)
        self.assertEqual(ntp_packet.interval, packet_data.ntp_interval)

    def test_extract_data_from_ntp_packet_works_as_expected(self):
        ntp_packet = NTP()
        mock_ntp_reference = '1.2.3.4'
        ntp_packet.id = socket.inet_aton(mock_ntp_reference)
        ntp_packet.mode = 1
        ntp_packet.stratum = 2
        ntp_packet.interval = 5

        data = self.dpkt_utils.extract_data_from_ntp_packet(ntp_packet)

        self.assertEqual(mock_ntp_reference, data.ntp_reference_id)
        self.assertEqual(ntp_packet.mode, data.ntp_mode)
        self.assertEqual(ntp_packet.stratum, data.ntp_stratum)
        self.assertEqual(ntp_packet.interval, data.ntp_interval)

    def test_extract_data_from_dns_packet_works_as_expected(self):
        mock_ans_1 = dpkt.dns.DNS.RR()
        mock_ans_1.type = dpkt.dns.DNS_CNAME
        mock_ans_1.ttl = 60
        mock_ans_1.name = 'mock_cname_ans'
        mock_dns_packet = DNS()
        mock_dns_packet.an = [mock_ans_1]
        mock_dns_packet.qr = dpkt.dns.DNS_R

        data = self.dpkt_utils.extract_data_from_dns_packet(mock_dns_packet)

        self.assertEqual(mock_ans_1.name, data.dns_ans_cname)
        self.assertEqual(mock_ans_1.ttl, data.dns_ans_cname_ttl)
        self.assertEqual('', data.dns_ans_name)
        self.assertEqual('', data.dns_ans_ip)
        self.assertIsNone(data.dns_ans_ttl)