Source code for pcapkit.protocols.link.ospf
# -*- coding: utf-8 -*-
"""OSPF - Open Shortest Path First
=====================================
:mod:`pcapkit.protocols.link.ospf` contains
:class:`~pcapkit.protocols.link.ospf.OSPF` only,
which implements extractor for Open Shortest Path
First (OSPF) [*]_, whose structure is described
as below:
+========+=======+====================+=================================+
| Octets | Bits | Name | Description |
+========+=======+====================+=================================+
| 0 | 0 | ``ospf.version`` | Version Number |
+--------+-------+--------------------+---------------------------------+
| 0 | 0 | ``ospf.type`` | Type |
+--------+-------+--------------------+---------------------------------+
| 0 | 1 | ``ospf.len`` | Packet Length (header included) |
+--------+-------+--------------------+---------------------------------+
| 0 | 2 | ``ospf.router_id`` | Router ID |
+--------+-------+--------------------+---------------------------------+
| 0 | 4 | ``ospf.area_id`` | Area ID |
+--------+-------+--------------------+---------------------------------+
| 0 | 6 | ``ospf.chksum`` | Checksum |
+--------+-------+--------------------+---------------------------------+
| 0 | 7 | ``ospf.autype`` | Authentication Type |
+--------+-------+--------------------+---------------------------------+
| 1 | 8 | ``ospf.auth`` | Authentication |
+--------+-------+--------------------+---------------------------------+
.. [*] https://en.wikipedia.org/wiki/Open_Shortest_Path_First
"""
import ipaddress
from typing import TYPE_CHECKING
from pcapkit.const.ospf.authentication import Authentication as RegType_Authentication
from pcapkit.const.ospf.packet import Packet as RegType_Packet
from pcapkit.protocols.data.link.ospf import OSPF as DataType_OSPF
from pcapkit.protocols.data.link.ospf import \
CrytographicAuthentication as DataType_CrytographicAuthentication
from pcapkit.protocols.link.link import Link
from pcapkit.utilities.exceptions import UnsupportedCall
if TYPE_CHECKING:
from ipaddress import IPv4Address
from typing import Any, NoReturn, Optional
from typing_extensions import Literal
__all__ = ['OSPF']
[docs]class OSPF(Link[DataType_OSPF]):
"""This class implements Open Shortest Path First."""
##########################################################################
# Properties.
##########################################################################
@property
def name(self) -> 'str':
"""Name of current protocol."""
return f'Open Shortest Path First version {self._info.version}'
@property
def alias(self) -> 'str':
"""Acronym of current protocol."""
return f'OSPFv{self._info.version}'
@property
def length(self) -> 'Literal[24]':
"""Header length of current protocol."""
return 24
@property
def type(self) -> 'RegType_Packet':
"""OSPF packet type."""
return self._info.type
##########################################################################
# Methods.
##########################################################################
[docs] def read(self, length: 'Optional[int]' = None, **kwargs: 'Any') -> 'DataType_OSPF':
"""Read Open Shortest Path First.
Structure of OSPF header [:rfc:`2328`]:
.. 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
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Version # | Type | Packet length |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Router ID |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Area ID |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Checksum | AuType |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Authentication |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Authentication |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Args:
length: Length of packet data.
**kwargs: Arbitrary keyword arguments.
Returns:
Parsed packet data.
"""
if length is None:
length = len(self)
_vers = self._read_unpack(1)
_type = self._read_unpack(1)
_tlen = self._read_unpack(2)
_rtid = self._read_id_numbers()
_area = self._read_id_numbers()
_csum = self._read_fileng(2)
_autp = self._read_unpack(2)
ospf = DataType_OSPF(
version=_vers,
type=RegType_Packet.get(_type),
len=_tlen,
router_id=_rtid,
area_id=_area,
chksum=_csum,
autype=RegType_Authentication.get(_autp),
)
if ospf.autype == RegType_Authentication.Cryptographic_authentication:
ospf.__update__([
('auth', self._read_encrypt_auth()),
])
else:
ospf.__update__([
('auth', self._read_fileng(8)),
])
return self._decode_next_layer(ospf, length - self.length)
[docs] def make(self, **kwargs: 'Any') -> 'NoReturn':
"""Make (construct) packet data.
Args:
**kwargs: Arbitrary keyword arguments.
Returns:
bytes: Constructed packet data.
"""
raise NotImplementedError
##########################################################################
# Data models.
##########################################################################
def __length_hint__(self) -> 'Literal[24]':
"""Return an estimated length for the object."""
return 24
[docs] @classmethod
def __index__(cls) -> 'NoReturn': # 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.
##########################################################################
def _read_id_numbers(self) -> 'IPv4Address':
"""Read router and area IDs.
Returns:
Parsed IDs as an IPv4 address.
"""
#_byte = self._read_fileng(4)
#_addr = '.'.join(str(_) for _ in _byte)
return ipaddress.ip_address(self._read_fileng(4)) # type: ignore[return-value]
[docs] def _read_encrypt_auth(self) -> 'DataType_CrytographicAuthentication':
"""Read Authentication field when Cryptographic Authentication is employed,
i.e. :attr:`~OSPF.autype` is ``2``.
Structure of Cryptographic Authentication [:rfc:`2328`]:
.. 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
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 0 | Key ID | Auth Data Len |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Cryptographic sequence number |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Args:
length: packet length
Returns:
Parsed packet data.
"""
_resv = self._read_fileng(2)
_keys = self._read_unpack(1)
_alen = self._read_unpack(1)
_seqn = self._read_unpack(4)
auth = DataType_CrytographicAuthentication(
key_id=_keys,
len=_alen,
seq=_seqn,
)
return auth