Source code for pcapkit.foundation.analysis.ip

# -*- coding: utf-8 -*-
"""IP Datagram Analysis
==========================

.. module:: pcapkit.foundation.analysis.ip

:mod:`pcapkit.foundation.analysis.ip` contains
:func:`~pcapkit.foundation.analysis.ip.ip_datagram` only, which parses the
payload of an IPv4 or IPv6 datagram that
:class:`~pcapkit.foundation.reassembly.ipv4.IPv4` or
:class:`~pcapkit.foundation.reassembly.ipv6.IPv6` reassembled.

.. versionadded:: 1.6.0

"""
from ipaddress import IPv6Address
from typing import TYPE_CHECKING

from pcapkit.protocols.internet.ipv4 import IPv4
from pcapkit.protocols.internet.ipv6 import IPv6

if TYPE_CHECKING:
    from typing import Optional, Type

    from pcapkit.const.reg.transtype import TransType
    from pcapkit.foundation.reassembly.data.ip import Datagram as IP_Datagram
    from pcapkit.protocols.internet.ip import IP as IP_Protocol
    from pcapkit.protocols.protocol import ProtocolBase

__all__ = ['ip_datagram']


[docs] def ip_datagram(datagram: 'IP_Datagram') -> 'Optional[ProtocolBase]': """Parse the payload of an IP datagram reassembled by :class:`~pcapkit.foundation.reassembly.ipv4.IPv4` or :class:`~pcapkit.foundation.reassembly.ipv6.IPv6`. The payload is dispatched on the datagram's payload protocol type -- the **Protocol** field for IPv4, the Fragment header's **Next Header** for IPv6 -- by :meth:`Protocol.analyze <pcapkit.protocols.protocol.Protocol.analyze>` of :class:`~pcapkit.protocols.internet.ipv4.IPv4` or :class:`~pcapkit.protocols.internet.ipv6.IPv6`, whichever the datagram's addresses belong to. Args: datagram: Reassembled datagram (:term:`reasm.ipv4.datagram` or :term:`reasm.ipv6.datagram`). Returns: The parsed payload. A payload reported as one contiguous run is parsed whether or not ``datagram`` is complete, as ``strict=False`` reports an incomplete one. :data:`None` if the payload is the tuple of runs received, as ``strict=True`` reports an incomplete one. Note: :attr:`Datagram.packet <pcapkit.foundation.reassembly.data.ip.Datagram.packet>` holds the same result, parsed on its first read, unless the reassembly's ``__protocol_type__`` names another protocol, which then parses it instead. """ if isinstance(datagram.payload, tuple): return None protocol = IPv6 if isinstance(datagram.id.src, IPv6Address) else IPv4 return _analyze_payload(protocol, datagram.id.proto, datagram.payload)
def _analyze_payload(protocol: 'Type[IP_Protocol]', proto: 'TransType', payload: 'bytes') -> 'ProtocolBase': """Parse a reassembled payload by its payload protocol type. :func:`ip_datagram` runs this, and so does the :class:`~pcapkit.foundation.reassembly.data.data.Deferred` that :meth:`IP.submit <pcapkit.foundation.reassembly.ip.IP.submit>` stores as a datagram's ``packet``, with the reassembly's own protocol bound as ``protocol``. Args: protocol: The IP protocol whose ``analyze`` parses ``payload``. proto: The payload protocol type. payload: The reassembled payload. Returns: The parsed payload. """ return protocol.analyze(proto, payload)