Source code for pcapkit.protocols.link.ethernet.protocol

# -*- coding: utf-8 -*-
"""Ethernet Protocol
=======================

.. module:: pcapkit.protocols.link.ethernet.protocol

:mod:`pcapkit.protocols.link.ethernet.protocol` contains
:class:`~pcapkit.protocols.link.ethernet.protocol.Ethernet`
only, which implements the extractor for Ethernet
Protocol [*]_, whose structure is described as
below:

.. table::

   ====== ===== ================= =========================
   Octets Bits  Name              Description
   ====== ===== ================= =========================
   0          0 ``ethernet.dst``  Destination MAC Address
   ------ ----- ----------------- -------------------------
   6         48 ``ethernet.src``  Source MAC Address
   ------ ----- ----------------- -------------------------
   12        96 ``ethernet.type`` Protocol (Internet Layer)
   ====== ===== ================= =========================

.. [*] https://en.wikipedia.org/wiki/Ethernet

"""
from typing import TYPE_CHECKING

from pcapkit.const.reg.ethertype import EtherType as Enum_EtherType
from pcapkit.const.reg.linktype import LinkType as Enum_LinkType
from pcapkit.protocols.link.ethernet.data import Ethernet as Data_Ethernet
from pcapkit.protocols.link.ethernet.schema import Ethernet as Schema_Ethernet
from pcapkit.protocols.link.link import Link

if TYPE_CHECKING:
    from typing import Any, Optional

    from typing_extensions import Literal

    from pcapkit.protocols.protocol import ProtocolBase
    from pcapkit.protocols.schema import Schema

__all__ = ['Ethernet']


[docs] class Ethernet(Link[Data_Ethernet, Schema_Ethernet], schema=Schema_Ethernet, data=Data_Ethernet): """This class implements Ethernet Protocol. .. versionchanged:: 1.6.0 ``type`` of :meth:`make` takes a member or an :class:`int` code, resolved with the enumeration's ``get``; a name, a :obj:`bool`, or a code the field cannot carry raises :exc:`~pcapkit.utilities.exceptions.ProtocolError`, rather than resolving against an enumeration inferred from the caller's frame or writing a different value (:issue:`2594`). .. versionremoved:: 1.6.0 The ``type_default``, ``type_namespace`` and ``type_reversed`` arguments of :meth:`make`; resolve a name with :meth:`~pcapkit.protocols.protocol.Protocol.resolve_index` first (:issue:`2594`). """ ########################################################################## # Properties. ########################################################################## @property def name(self) -> 'Literal["Ethernet Protocol"]': """Name of current protocol.""" return 'Ethernet Protocol' @property def length(self) -> 'Literal[14]': """Header length of current protocol.""" return 14 @property def protocol(self) -> 'Enum_EtherType': """Name of next layer protocol.""" return self._info.type # source mac address @property def src(self) -> 'str': """Source mac address.""" return self._info.src # destination mac address @property def dst(self) -> 'str': """Destination mac address.""" return self._info.dst ########################################################################## # Methods. ##########################################################################
[docs] def read(self, length: 'Optional[int]' = None, **kwargs: 'Any') -> 'Data_Ethernet': # pylint: disable=unused-argument """Read Ethernet Protocol. Structure of Ethernet header [:rfc:`7042`]: .. code-block:: text 0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Dst MAC Addr | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Src MAC Addr | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Ether Type | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ Args: length: Length of packet data. **kwargs: Arbitrary keyword arguments. Returns: Parsed packet data. """ if length is None: length = len(self) schema = self.__header__ _dstm = self._read_mac_addr(schema.dst) _srcm = self._read_mac_addr(schema.src) _type = schema.type ethernet = Data_Ethernet( dst=_dstm, src=_srcm, type=_type, ) return self._decode_next_layer(ethernet, _type, length - self.length)
[docs] def make(self, dst: 'str | bytes | bytearray' = '00:00:00:00:00:00', src: 'str | bytes | bytearray' = '00:00:00:00:00:00', type: 'Enum_EtherType | int' = Enum_EtherType.Internet_Protocol_version_4, payload: 'bytes | ProtocolBase | Schema' = b'', **kwargs: 'Any') -> 'Schema_Ethernet': """Make (construct) packet data. Args: dst: Destination MAC address. src: Source MAC address. type: EtherType. payload: Payload data. **kwargs: Arbitrary keyword arguments. Returns: Constructed packet data. Raises: ProtocolError: If ``dst`` or ``src`` is rejected by :meth:`~pcapkit.protocols.protocol.Protocol._make_mac_addr`, or ``type`` is a name, a :obj:`bool`, or a member or code its field cannot carry. """ _type = self._make_index(type, Enum_EtherType, bits=16, name='EtherType') return Schema_Ethernet( dst=self._make_mac_addr(dst), src=self._make_mac_addr(src), type=_type, payload=payload, )
########################################################################## # Data models. ########################################################################## def __length_hint__(self) -> 'Literal[14]': """Return an estimated length for the object.""" return 14
[docs] @classmethod def __index__(cls) -> 'Enum_LinkType': # pylint: disable=invalid-index-returned """Numeral registry index of the protocol. Returns: Numeral registry index of the protocol in `tcpdump`_ link-layer header types. .. _tcpdump: https://www.tcpdump.org/linktypes.html """ return Enum_LinkType.ETHERNET # type: ignore[return-value]
########################################################################## # Utilities. ##########################################################################
[docs] @classmethod def _make_data(cls, data: 'Data_Ethernet') -> 'dict[str, Any]': # type: ignore[override] """Create key-value pairs from ``data`` for protocol construction. Args: data: protocol data Returns: Key-value pairs for protocol construction. """ return { 'dst': data.dst, 'src': data.src, 'type': data.type, 'payload': cls._make_payload(data), }