Source code for pcapkit.foundation.registry.protocols.misc

# -*- coding: utf-8 -*-
"""Miscellaneous Protocol Registries
=======================================

.. module:: pcapkit.foundation.registry.protocols.misc

This module provides the registries of the protocols in
:mod:`pcapkit.protocols.misc`: the top-level registries of the PCAP and
PCAP-NG frames, and the PCAP-NG block, option, record and secrets
registries.

.. versionadded:: 1.6.0

   Moved here from the single :file:`pcapkit/foundation/registry/protocols.py`
   module. The :mod:`pcapkit.foundation.registry.protocols` package exports
   this module's functions (:issue:`2578`).

"""
from typing import TYPE_CHECKING, cast, overload

from pcapkit.const.pcapng.block_type import BlockType as PCAPNG_BlockType
from pcapkit.const.pcapng.option_type import OptionType as PCAPNG_OptionType
from pcapkit.const.pcapng.record_type import RecordType as PCAPNG_RecordType
from pcapkit.const.pcapng.secrets_type import SecretsType as PCAPNG_SecretsType
from pcapkit.const.reg.linktype import LinkType as Enum_LinkType
from pcapkit.corekit.module import ModuleDescriptor
from pcapkit.corekit.sentinels import NULL
from pcapkit.foundation.registry.protocols.protocol import _check_code, _register_name
from pcapkit.protocols.misc.pcap.frame.protocol import Frame
from pcapkit.protocols.misc.pcapng.protocol import PCAPNG
from pcapkit.protocols.misc.pcapng.schema import BlockType as Schema_PCAPNG_BlockType
from pcapkit.protocols.misc.pcapng.schema import DSBSecrets as Schema_PCAPNG_DSBSecrets
from pcapkit.protocols.misc.pcapng.schema import \
    NameResolutionRecord as Schema_PCAPNG_NameResolutionRecord
from pcapkit.protocols.misc.pcapng.schema import Option as Schema_PCAPNG_Option
from pcapkit.utilities.exceptions import RegistryError
from pcapkit.utilities.logging import get_logger

if TYPE_CHECKING:
    from typing import Optional, Type

    from pcapkit.const.reg.linktype import LinkType
    from pcapkit.corekit.sentinels import NullType
    from pcapkit.protocols.misc.pcapng.protocol import BlockConstructor as PCAPNG_BlockConstructor
    from pcapkit.protocols.misc.pcapng.protocol import BlockParser as PCAPNG_BlockParser
    from pcapkit.protocols.misc.pcapng.protocol import OptionConstructor as PCAPNG_OptionConstructor
    from pcapkit.protocols.misc.pcapng.protocol import OptionParser as PCAPNG_OptionParser
    from pcapkit.protocols.misc.pcapng.protocol import RecordConstructor as PCAPNG_RecordConstructor
    from pcapkit.protocols.misc.pcapng.protocol import RecordParser as PCAPNG_RecordParser
    from pcapkit.protocols.misc.pcapng.protocol import \
        SecretsConstructor as PCAPNG_SecretsConstructor
    from pcapkit.protocols.misc.pcapng.protocol import SecretsParser as PCAPNG_SecretsParser
    from pcapkit.protocols.protocol import ProtocolBase

__all__ = [
    'register_linktype',
    'register_pcap', 'register_pcapng',

    'register_pcapng_block', 'register_pcapng_option', 'register_pcapng_secrets',
    'register_pcapng_record',
]

#: logging.Logger: Module-level logger, a child of the package-wide
#: :data:`pcapkit.utilities.logging.logger`.
logger = get_logger(__name__)


###############################################################################
# Top-Level Registries
###############################################################################


@overload
def register_linktype(code: 'LinkType', module: 'ModuleDescriptor[ProtocolBase] | Type[ProtocolBase]') -> 'None': ...
@overload
def register_linktype(code: 'LinkType', module: 'str', class_: 'str') -> 'None': ...


[docs] def register_linktype(code: 'LinkType', module: 'str | ModuleDescriptor[ProtocolBase] | Type[ProtocolBase]', class_: 'str | NullType' = NULL) -> 'None': r"""Register a new protocol class. Notes: The fully qualified class name of the new protocol class should be ``{module}.{class_}``. The function will register the given protocol class to the following registries: - :data:`pcapkit.protocols.misc.pcap.frame.protocol.Frame.__proto__` - :data:`pcapkit.protocols.misc.pcapng.protocol.PCAPNG.__proto__` Arguments: code: protocol code as in :class:`~pcapkit.const.reg.linktype.LinkType` module: module name or module descriptor or a :class:`~pcapkit.protocols.protocol.ProtocolBase` subclass class\_: class name See Also: * :func:`pcapkit.foundation.registry.protocols.misc.register_pcap` * :func:`pcapkit.foundation.registry.protocols.misc.register_pcapng` Raises: RegistryError: If ``code`` is not a :class:`~pcapkit.const.reg.linktype.LinkType` member, e.g. a member of another enum, or ``module`` is not a :class:`~pcapkit.protocols.protocol.ProtocolBase` subclass. """ # NOTE: Frame's and PCAP-NG's registries are keyed alike, so one key check # serves both and Frame names it. _check_code(code, Enum_LinkType, Frame) if isinstance(module, str): module = cast('ModuleDescriptor[ProtocolBase]', ModuleDescriptor(module, class_)) Frame.register(code, module) PCAPNG.register(code, module) logger.debug('registered linktype protocol: %s', code.name) # register protocol to protocol registry if isinstance(module, ModuleDescriptor): module = module.klass _register_name(module, (Frame, code), (PCAPNG, code))
@overload def register_pcap(code: 'LinkType', module: 'ModuleDescriptor[ProtocolBase] | Type[ProtocolBase]') -> 'None': ... @overload def register_pcap(code: 'LinkType', module: 'str', class_: 'str') -> 'None': ... # NOTE: pcapkit.protocols.misc.pcap.frame.protocol.Frame.__proto__
[docs] def register_pcap(code: 'LinkType', module: 'str | ModuleDescriptor[ProtocolBase] | Type[ProtocolBase]', class_: 'str | NullType' = NULL) -> 'None': r"""Register a new protocol class. Notes: The fully qualified class name of the new protocol class should be ``{module}.{class_}``. The function will register the given protocol class to the :data:`pcapkit.protocols.misc.pcap.frame.protocol.Frame.__proto__` registry. Arguments: code: protocol code as in :class:`~pcapkit.const.reg.linktype.LinkType` module: module name or module descriptor or a :class:`~pcapkit.protocols.protocol.ProtocolBase` subclass class\_: class name Raises: RegistryError: If ``code`` is not a :class:`~pcapkit.const.reg.linktype.LinkType` member, e.g. a member of another enum, or ``module`` is not a :class:`~pcapkit.protocols.protocol.ProtocolBase` subclass. """ _check_code(code, Enum_LinkType, Frame) if isinstance(module, str): module = cast('ModuleDescriptor[ProtocolBase]', ModuleDescriptor(module, class_)) Frame.register(code, module) logger.debug('registered PCAP linktype protocol: %s', code.name) # register protocol to protocol registry if isinstance(module, ModuleDescriptor): module = module.klass _register_name(module, (Frame, code))
@overload def register_pcapng(code: 'LinkType', module: 'ModuleDescriptor[ProtocolBase] | Type[ProtocolBase]') -> 'None': ... @overload def register_pcapng(code: 'LinkType', module: 'str', class_: 'str') -> 'None': ... # NOTE: pcapkit.protocols.misc.pcapng.protocol.PCAPNG.__proto__
[docs] def register_pcapng(code: 'LinkType', module: 'str | ModuleDescriptor[ProtocolBase] | Type[ProtocolBase]', class_: 'str | NullType' = NULL) -> 'None': r"""Register a new protocol class. Notes: The fully qualified class name of the new protocol class should be ``{module}.{class_}``. The function will register the given protocol class to the :data:`pcapkit.protocols.misc.pcapng.protocol.PCAPNG.__proto__` registry. Arguments: code: protocol code as in :class:`~pcapkit.const.reg.linktype.LinkType` module: module name or module descriptor or a :class:`~pcapkit.protocols.protocol.ProtocolBase` subclass class\_: class name Raises: RegistryError: If ``code`` is not a :class:`~pcapkit.const.reg.linktype.LinkType` member, e.g. a member of another enum, or ``module`` is not a :class:`~pcapkit.protocols.protocol.ProtocolBase` subclass. """ _check_code(code, Enum_LinkType, PCAPNG) if isinstance(module, str): module = cast('ModuleDescriptor[ProtocolBase]', ModuleDescriptor(module, class_)) PCAPNG.register(code, module) logger.debug('registered PCAP-NG linktype protocol: %s', code.name) # register protocol to protocol registry if isinstance(module, ModuleDescriptor): module = module.klass _register_name(module, (PCAPNG, code))
############################################################################### # Miscellaneous Protocol Registries ############################################################################### # NOTE: pcapkit.protocols.misc.pcapng.protocol.PCAPNG.__block__
[docs] def register_pcapng_block(code: 'PCAPNG_BlockType', meth: 'str | tuple[PCAPNG_BlockParser, PCAPNG_BlockConstructor]', *, schema: 'Optional[Type[Schema_PCAPNG_BlockType]]' = None) -> 'None': """Register a block parser. The function will register the given block parser to the :data:`pcapkit.protocols.misc.pcapng.protocol.PCAPNG.__block__` registry. Args: code: :class:`PCAPNG <pcapkit.protocols.misc.pcapng.protocol.PCAPNG>` block type code as in :class:`~pcapkit.const.pcapng.block_type.BlockType`. meth: Method name, or a ``(parser, constructor)`` pair of callables, to parse and construct the block. A name names the ``_read_block_*`` and ``_make_block_*`` methods, and has to name an existing ``_read_block_*`` one. schema: :class:`~pcapkit.protocols.schema.Schema` class for the block. It should be a subclass of :class:`pcapkit.protocols.misc.pcapng.schema.BlockType`. Raises: RegistryError: If ``code`` is not a :class:`~pcapkit.const.pcapng.block_type.BlockType` member, e.g. a member of another enum, or ``meth`` is a name with no matching ``_read_block_*`` method. """ _check_code(code, PCAPNG_BlockType, PCAPNG) if isinstance(meth, str) and not hasattr(PCAPNG, f'_read_block_{meth}'): raise RegistryError('method must be a block parser function') PCAPNG.register_block(code, meth) if schema is not None: Schema_PCAPNG_BlockType.register(code, schema) logger.debug('registered PCAP-NG block parser: %s', code.name)
# NOTE: pcapkit.protocols.misc.pcapng.protocol.PCAPNG.__option__
[docs] def register_pcapng_option(code: 'PCAPNG_OptionType', meth: 'str | tuple[PCAPNG_OptionParser, PCAPNG_OptionConstructor]', *, schema: 'Optional[Type[Schema_PCAPNG_Option]]' = None) -> 'None': """Register an option parser. The function will register the given option parser to the :data:`pcapkit.protocols.misc.pcapng.protocol.PCAPNG.__option__` registry. Args: code: :class:`PCAPNG <pcapkit.protocols.misc.pcapng.protocol.PCAPNG>` option type code as in :class:`~pcapkit.const.pcapng.option_type.OptionType`. meth: Method name, or a ``(parser, constructor)`` pair of callables, to parse and construct the option. A name names the ``_read_option_*`` and ``_make_option_*`` methods, and has to name an existing ``_read_option_*`` one. schema: :class:`~pcapkit.protocols.schema.Schema` class for the option. It should be a subclass of :class:`pcapkit.protocols.misc.pcapng.schema.Option`. Raises: RegistryError: If ``code`` is not a :class:`~pcapkit.const.pcapng.option_type.OptionType` member, e.g. a member of another enum, or ``meth`` is a name with no matching ``_read_option_*`` method. """ _check_code(code, PCAPNG_OptionType, PCAPNG) if isinstance(meth, str) and not hasattr(PCAPNG, f'_read_option_{meth}'): raise RegistryError('method must be a option parser function') PCAPNG.register_option(code, meth) if schema is not None: Schema_PCAPNG_Option.register(code, schema) logger.debug('registered PCAP-NG option parser: %s', code.name)
# NOTE: pcapkit.protocols.misc.pcapng.protocol.PCAPNG.__record__
[docs] def register_pcapng_record(code: 'PCAPNG_RecordType', meth: 'str | tuple[PCAPNG_RecordParser, PCAPNG_RecordConstructor]', *, schema: 'Optional[Type[Schema_PCAPNG_NameResolutionRecord]]' = None) -> 'None': """Register a name resolution record parser. The function will register the given name resolution record parser to the :data:`pcapkit.protocols.misc.pcapng.protocol.PCAPNG.__record__` registry. Args: code: :class:`PCAPNG <pcapkit.protocols.misc.pcapng.protocol.PCAPNG>` name resolution record type code as in :class:`~pcapkit.const.pcapng.record_type.RecordType`. meth: Method name, or a ``(parser, constructor)`` pair of callables, to parse and construct the name resolution record. A name names the ``_read_record_*`` and ``_make_record_*`` methods, and has to name an existing ``_read_record_*`` one. schema: :class:`~pcapkit.protocols.schema.Schema` class for the name resolution record. It should be a subclass of :class:`pcapkit.protocols.misc.pcapng.schema.NameResolutionRecord`. Raises: RegistryError: If ``code`` is not a :class:`~pcapkit.const.pcapng.record_type.RecordType` member, e.g. a member of another enum, or ``meth`` is a name with no matching ``_read_record_*`` method. """ _check_code(code, PCAPNG_RecordType, PCAPNG) if isinstance(meth, str) and not hasattr(PCAPNG, f'_read_record_{meth}'): raise RegistryError('method must be a name resolution record parser function') PCAPNG.register_record(code, meth) if schema is not None: Schema_PCAPNG_NameResolutionRecord.register(code, schema) logger.debug('registered PCAP-NG name resolution record parser: %s', code.name)
# NOTE: pcapkit.protocols.misc.pcapng.protocol.PCAPNG.__secrets__
[docs] def register_pcapng_secrets(code: 'PCAPNG_SecretsType', meth: 'str | tuple[PCAPNG_SecretsParser, PCAPNG_SecretsConstructor]', *, schema: 'Optional[Type[Schema_PCAPNG_DSBSecrets]]' = None) -> 'None': """Register a decryption secrets parser. The function will register the given decryption secrets parser to the :data:`pcapkit.protocols.misc.pcapng.protocol.PCAPNG.__secrets__` registry. Args: code: :class:`PCAPNG <pcapkit.protocols.misc.pcapng.protocol.PCAPNG>` decryption secrets type code as in :class:`~pcapkit.const.pcapng.secrets_type.SecretsType`. meth: Method name, or a ``(parser, constructor)`` pair of callables, to parse and construct the decryption secrets. A name names the ``_read_secrets_*`` and ``_make_secrets_*`` methods, and has to name an existing ``_read_secrets_*`` one. schema: :class:`~pcapkit.protocols.schema.Schema` class for the decryption secrets. It should be a subclass of :class:`pcapkit.protocols.misc.pcapng.schema.DSBSecrets`. Raises: RegistryError: If ``code`` is not a :class:`~pcapkit.const.pcapng.secrets_type.SecretsType` member, e.g. a member of another enum, or ``meth`` is a name with no matching ``_read_secrets_*`` method. """ _check_code(code, PCAPNG_SecretsType, PCAPNG) if isinstance(meth, str) and not hasattr(PCAPNG, f'_read_secrets_{meth}'): raise RegistryError('method must be a decryption secrets parser function') PCAPNG.register_secrets(code, meth) if schema is not None: Schema_PCAPNG_DSBSecrets.register(code, schema) logger.debug('registered PCAP-NG decryption secrets parser: %s', code.name)