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 textwrap
from pcapkit.protocols.link.link import Link
from pcapkit.utilities.exceptions import UnsupportedCall
__all__ = ['Ethernet']
[docs]class Ethernet(Link):
"""This class implements Ethernet Protocol."""
##########################################################################
# Properties.
##########################################################################
@property
def name(self):
"""Name of current protocol.
:rtype: Literal['Ethernet Protocol']
"""
return 'Ethernet Protocol'
@property
def length(self):
"""Header length of current protocol.
:rtype: Literal[14]
"""
return 14
@property
def protocol(self):
"""Name of next layer protocol.
:rtype: pcapkit.const.reg.ethertype.EtherType
"""
return self._info.type # pylint: disable=E1101
# source mac address
@property
def src(self):
"""Source mac address.
:rtype: str
"""
return self._info.src # pylint: disable=E1101
# destination mac address
@property
def dst(self):
"""Destination mac address.
:rtype: str
"""
return self._info.dst # pylint: disable=E1101
##########################################################################
# Methods.
##########################################################################
[docs] def read(self, length=None, **kwargs): # pylint: disable=unused-argument
"""Read Ethernet Protocol [:rfc:`7042`].
Args:
length (Optional[int]): Length of packet data.
Keyword Args:
**kwargs: Arbitrary keyword arguments.
Returns:
DataType_Ethernet: 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 = dict(
dst=_dstm,
src=_srcm,
type=_type,
)
length -= 14
ethernet['packet'] = self._read_packet(header=14, payload=length)
return self._decode_next_layer(ethernet, _type, length)
[docs] def make(self, **kwargs):
"""Make (construct) packet data.
Keyword Args:
**kwargs: Arbitrary keyword arguments.
Returns:
bytes: Constructed packet data.
"""
raise NotImplementedError
##########################################################################
# Data models.
##########################################################################
[docs] def __length_hint__(self):
"""Return an estimated length for the object.
:rtype: Literal[14]
"""
return 14
[docs] @classmethod
def __index__(cls): # pylint: disable=invalid-index-returned
"""Numeral registry index of the protocol.
Raises:
UnsupportedCall: This protocol has no registry entry.
"""
raise UnsupportedCall(f'{cls.__name__!r} object cannot be interpreted as an integer')
##########################################################################
# Utilities.
##########################################################################
[docs] def _read_mac_addr(self):
"""Read MAC address.
Returns:
str: Colon (``:``) seperated *hex* encoded MAC address.
"""
_byte = self._read_fileng(6)
_addr = ':'.join(textwrap.wrap(_byte.hex(), 2))
return _addr