Source code for pcapkit.protocols.internet.ah

# -*- coding: utf-8 -*-
"""authentication header

:mod:`pcapkit.protocols.internet.ah` contains
:class:`~pcapkit.protocols.internet.AH` only,
which implements extractor for Authentication
Header (AH) [*]_, whose structure is described
as below:

======= ========= ======================= ===================================
Octets      Bits        Name                    Description
======= ========= ======================= ===================================
  0           0   ``ah.next``               Next Header
  1           8   ``ah.length``             Payload Length
  2          16                             Reserved (must be zero)
  4          32   ``sah.spi``               Security Parameters Index (SPI)
  8          64   ``sah.seq``               Sequence Number Field
  12         96   ``sah.icv``               Integrity Check Value (ICV)
======= ========= ======================= ===================================

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

"""
from pcapkit.const.reg.transtype import TransType
from pcapkit.protocols.internet.ipsec import IPsec
from pcapkit.utilities.exceptions import (ProtocolError, UnsupportedCall,
                                          VersionError)

__all__ = ['AH']


[docs]class AH(IPsec): """This class implements Authentication Header.""" ########################################################################## # Properties. ########################################################################## @property def name(self): """Name of corresponding protocol. :rtype: Literal['Authentication Header'] """ return 'Authentication Header' @property def length(self): """Info dict of current instance. :rtype: int """ return self._info.length # pylint: disable=E1101 @property def payload(self): """Payload of current instance. Raises: UnsupportedCall: if the protocol is used as an IPv6 extension header :rtype: pcapkit.protocols.protocol.Protocol """ if self._extf: raise UnsupportedCall(f"'{self.__class__.__name__}' object has no attribute 'payload'") return self._next @property def protocol(self): """Name of next layer protocol. :rtype: pcapkit.const.reg.transtype.TransType """ return self._info.next # pylint: disable=E1101 ########################################################################## # Methods. ##########################################################################
[docs] def read(self, length=None, *, version=4, extension=False, **kwargs): # pylint: disable=arguments-differ,unused-argument """Read Authentication Header. Structure of AH header [:rfc:`4302`]:: 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 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Next Header | Payload Len | RESERVED | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Security Parameters Index (SPI) | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Sequence Number Field | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | | + Integrity Check Value-ICV (variable) | | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ Args: length (Optional[int]): Length of packet data. Keyword Args: version (Literal[4, 6]): IP protocol version. extension (bool): If the protocol is used as an IPv6 extension header. **kwargs: Arbitrary keyword arguments. Returns: DataType_AH: Parsed packet data. """ if length is None: length = len(self) _next = self._read_protos(1) _plen = self._read_unpack(1) _resv = self._read_fileng(2) _scpi = self._read_unpack(4) _dsnf = self._read_unpack(4) # ICV length & value _tlen = _plen * 4 - 2 _vlen = _tlen - 12 _chkv = self._read_fileng(_vlen) ah = dict( next=_next, length=_tlen, spi=_scpi, seq=_dsnf, icv=_chkv, ) if version == 6: _plen = 8 - (_tlen % 8) elif version == 4: _plen = 4 - (_tlen % 4) else: raise VersionError(f'Unknown IP version {version}') if _plen: # explicit padding in need padding = self._read_binary(_plen) if any((int(bit, base=2) for bit in padding)): raise ProtocolError(f'{self.alias}: invalid format') length -= ah['length'] ah['packet'] = self._read_packet(header=ah['length'], payload=length) if extension: self._protos = None return ah return self._decode_next_layer(ah, _next, length)
[docs] def make(self, **kwargs): """Make (construct) packet data. Keyword Args: **kwargs: Arbitrary keyword arguments. Returns: bytes: Constructed packet data. """ raise NotImplementedError
[docs] @classmethod def id(cls): """Index ID of the protocol. Returns: Literal['AH']: Index ID of the protocol. """ return cls.__name__
########################################################################## # Data models. ##########################################################################
[docs] def __post_init__(self, file, length=None, *, version=4, extension=False, **kwargs): # pylint: disable=arguments-differ """Post initialisation hook. Args: file (io.BytesIO): Source packet stream. length (Optional[int]): Length of packet data. Keyword Args: version (Literal[4, 6]): IP protocol version. extension (bool): If the protocol is used as an IPv6 extension header. **kwargs: Arbitrary keyword arguments. See Also: For construction argument, please refer to :meth:`make`. """ #: bool: If the protocol is used as an IPv6 extension header. self._extf = extension # call super __post_init__ super().__post_init__(file, length, version=version, extension=extension, **kwargs)
[docs] def __length_hint__(self): """Return an estimated length for the object. :rtype: Literal[20] """ return 20
[docs] @classmethod def __index__(cls): # pylint: disable=invalid-index-returned """Numeral registry index of the protocol. Returns: pcapkit.const.reg.transtype.TransType: Numeral registry index of the protocol in `IANA`_. .. _IANA: https://www.iana.org/assignments/protocol-numbers/protocol-numbers.xhtml """ return TransType(51)