Source code for pcapkit.protocols.link.ethernet

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

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

+========+=======+==============+===========================+
| Octets | Bits  | Name         | Description               |
+========+=======+==============+===========================+
| 0      |     0 | ``eth.dst``  | Destination MAC Address   |
+--------+-------+--------------+---------------------------+
| 1      |     8 | ``eth.src``  | Source MAC Address        |
+--------+-------+--------------+---------------------------+
| 2      |    16 | ``eth.type`` | Protocol (Internet Layer) |
+--------+-------+--------------+---------------------------+

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

"""
import sys
import textwrap
from typing import TYPE_CHECKING

from pcapkit.const.reg.linktype import LinkType as RegType_LinkType
from pcapkit.protocols.data.link.ethernet import Ethernet as DataType_Ethernet
from pcapkit.protocols.link.link import Link

if TYPE_CHECKING:
    from typing import Any, NoReturn, Optional

    from typing_extensions import Literal

    from pcapkit.const.reg.ethertype import EtherType as RegType_EtherType

__all__ = ['Ethernet']

# check Python version
py38 = ((version_info := sys.version_info).major >= 3 and version_info.minor >= 8)


[docs]class Ethernet(Link[DataType_Ethernet]): """This class implements Ethernet Protocol.""" ########################################################################## # 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) -> 'RegType_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') -> 'DataType_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) _dstm = self._read_mac_addr() _srcm = self._read_mac_addr() _type = self._read_protos(2) ethernet = DataType_Ethernet( dst=_dstm, src=_srcm, type=_type, ) return self._decode_next_layer(ethernet, _type, length - self.length)
[docs] def make(self, **kwargs: 'Any') -> 'NoReturn': """Make (construct) packet data. Args: **kwargs: Arbitrary keyword arguments. Returns: Constructed packet data. """ raise NotImplementedError
########################################################################## # Data models. ########################################################################## def __length_hint__(self) -> 'Literal[14]': """Return an estimated length for the object.""" return 14
[docs] @classmethod def __index__(cls) -> 'RegType_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 RegType_LinkType.ETHERNET # type: ignore[return-value]
########################################################################## # Utilities. ########################################################################## def _read_mac_addr(self) -> 'str': """Read MAC address. Returns: Colon (``:``) seperated *hex* encoded MAC address. """ _byte = self._read_fileng(6) if py38: _addr = _byte.hex(':') else: _addr = ':'.join(textwrap.wrap(_byte.hex(), 2)) return _addr