Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 12 additions & 4 deletions pcapkit/toolkit/pcap_ct.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
"""
from typing import TYPE_CHECKING

from pcapkit.foundation.engines.pcap_ct import PCAP_CT
from pcapkit.utilities.exceptions import UnsupportedCall

if TYPE_CHECKING:
Expand All @@ -48,6 +49,13 @@
'ipv4_reassembly', 'ipv6_reassembly', 'tcp_reassembly', 'tcp_traceflow',
]

#: Message prefix shared by every adapter below, read off
#: :attr:`PCAP_CT.__engine_name__
#: <pcapkit.foundation.engines.pcap_ct.PCAP_CT.__engine_name__>` rather than
#: spelled out, so the engine cannot be renamed there and still be named the old
#: way here (:issue:`2304`).
_ENGINE = PCAP_CT.__engine_name__

#: Explanatory suffix shared by every unsupported adapter below.
_NO_DISSECTION = ("'pcap-ct' is a libpcap binding and performs no protocol "
"dissection, so there is no protocol layer to read")
Expand Down Expand Up @@ -109,7 +117,7 @@ def ipv4_reassembly(packet: 'bytes', *, count: 'int' = -1) -> 'IP_Packet[IPv4Add
UnsupportedCall: Always, as `pcap-ct`_ provides no IPv4 layer to read.

"""
raise UnsupportedCall(f'IPv4 reassembly is not supported by the pcap-ct engine: {_NO_DISSECTION}')
raise UnsupportedCall(f'{_ENGINE}: IPv4 reassembly is not supported: {_NO_DISSECTION}')


def ipv6_reassembly(packet: 'bytes', *, count: 'int' = -1) -> 'IP_Packet[IPv6Address] | None':
Expand All @@ -123,7 +131,7 @@ def ipv6_reassembly(packet: 'bytes', *, count: 'int' = -1) -> 'IP_Packet[IPv6Add
UnsupportedCall: Always, as `pcap-ct`_ provides no IPv6 layer to read.

"""
raise UnsupportedCall(f'IPv6 reassembly is not supported by the pcap-ct engine: {_NO_DISSECTION}')
raise UnsupportedCall(f'{_ENGINE}: IPv6 reassembly is not supported: {_NO_DISSECTION}')


def tcp_reassembly(packet: 'bytes', *, count: 'int' = -1) -> 'TCP_Packet | None':
Expand All @@ -137,7 +145,7 @@ def tcp_reassembly(packet: 'bytes', *, count: 'int' = -1) -> 'TCP_Packet | None'
UnsupportedCall: Always, as `pcap-ct`_ provides no TCP layer to read.

"""
raise UnsupportedCall(f'TCP reassembly is not supported by the pcap-ct engine: {_NO_DISSECTION}')
raise UnsupportedCall(f'{_ENGINE}: TCP reassembly is not supported: {_NO_DISSECTION}')


def tcp_traceflow(packet: 'bytes', timestamp: 'float', *, data_link: 'Enum_LinkType',
Expand All @@ -154,4 +162,4 @@ def tcp_traceflow(packet: 'bytes', timestamp: 'float', *, data_link: 'Enum_LinkT
UnsupportedCall: Always, as `pcap-ct`_ provides no TCP layer to read.

"""
raise UnsupportedCall(f'TCP flow tracing is not supported by the pcap-ct engine: {_NO_DISSECTION}')
raise UnsupportedCall(f'{_ENGINE}: TCP flow tracing is not supported: {_NO_DISSECTION}')
16 changes: 12 additions & 4 deletions pcapkit/toolkit/pypcap.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
"""
from typing import TYPE_CHECKING

from pcapkit.foundation.engines.pypcap import PyPCAP
from pcapkit.utilities.exceptions import UnsupportedCall

if TYPE_CHECKING:
Expand All @@ -47,6 +48,13 @@
'ipv4_reassembly', 'ipv6_reassembly', 'tcp_reassembly', 'tcp_traceflow',
]

#: Message prefix shared by every adapter below, read off
#: :attr:`PyPCAP.__engine_name__
#: <pcapkit.foundation.engines.pypcap.PyPCAP.__engine_name__>` rather than
#: spelled out, so the engine cannot be renamed there and still be named the old
#: way here (:issue:`2304`).
_ENGINE = PyPCAP.__engine_name__

#: Explanatory suffix shared by every unsupported adapter below.
_NO_DISSECTION = ("'pypcap' is a libpcap binding and performs no protocol "
"dissection, so there is no protocol layer to read")
Expand Down Expand Up @@ -108,7 +116,7 @@ def ipv4_reassembly(packet: 'bytes', *, count: 'int' = -1) -> 'IP_Packet[IPv4Add
UnsupportedCall: Always, as `PyPCAP`_ provides no IPv4 layer to read.

"""
raise UnsupportedCall(f'IPv4 reassembly is not supported by the PyPCAP engine: {_NO_DISSECTION}')
raise UnsupportedCall(f'{_ENGINE}: IPv4 reassembly is not supported: {_NO_DISSECTION}')


def ipv6_reassembly(packet: 'bytes', *, count: 'int' = -1) -> 'IP_Packet[IPv6Address] | None':
Expand All @@ -122,7 +130,7 @@ def ipv6_reassembly(packet: 'bytes', *, count: 'int' = -1) -> 'IP_Packet[IPv6Add
UnsupportedCall: Always, as `PyPCAP`_ provides no IPv6 layer to read.

"""
raise UnsupportedCall(f'IPv6 reassembly is not supported by the PyPCAP engine: {_NO_DISSECTION}')
raise UnsupportedCall(f'{_ENGINE}: IPv6 reassembly is not supported: {_NO_DISSECTION}')


def tcp_reassembly(packet: 'bytes', *, count: 'int' = -1) -> 'TCP_Packet | None':
Expand All @@ -136,7 +144,7 @@ def tcp_reassembly(packet: 'bytes', *, count: 'int' = -1) -> 'TCP_Packet | None'
UnsupportedCall: Always, as `PyPCAP`_ provides no TCP layer to read.

"""
raise UnsupportedCall(f'TCP reassembly is not supported by the PyPCAP engine: {_NO_DISSECTION}')
raise UnsupportedCall(f'{_ENGINE}: TCP reassembly is not supported: {_NO_DISSECTION}')


def tcp_traceflow(packet: 'bytes', timestamp: 'float', *, data_link: 'Enum_LinkType',
Expand All @@ -153,4 +161,4 @@ def tcp_traceflow(packet: 'bytes', timestamp: 'float', *, data_link: 'Enum_LinkT
UnsupportedCall: Always, as `PyPCAP`_ provides no TCP layer to read.

"""
raise UnsupportedCall(f'TCP flow tracing is not supported by the PyPCAP engine: {_NO_DISSECTION}')
raise UnsupportedCall(f'{_ENGINE}: TCP flow tracing is not supported: {_NO_DISSECTION}')
24 changes: 16 additions & 8 deletions pcapkit/toolkit/pypcapfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@

from pcapkit.const.reg.ethertype import EtherType as Enum_EtherType
from pcapkit.const.reg.transtype import TransType as Enum_TransType
from pcapkit.foundation.engines.pypcapfile import PyPCAPFile
from pcapkit.foundation.reassembly.data.ip import Packet as IP_Packet
from pcapkit.foundation.reassembly.data.tcp import Packet as TCP_Packet
from pcapkit.foundation.traceflow.data.tcp import Packet as TF_TCP_Packet
Expand Down Expand Up @@ -77,6 +78,13 @@
'ipv4_reassembly', 'ipv6_reassembly', 'tcp_reassembly', 'tcp_traceflow',
]

#: Message prefix shared by every message below, read off
#: :attr:`PyPCAPFile.__engine_name__
#: <pcapkit.foundation.engines.pypcapfile.PyPCAPFile.__engine_name__>` rather
#: than spelled out, so the engine cannot be renamed there and still be named
#: the old way here (:issue:`2304`).
_ENGINE = PyPCAPFile.__engine_name__

#: IPv4 **DF** (don't fragment) bit, within the three-bit flags field.
IPV4_FLAG_DF = 0b010

Expand Down Expand Up @@ -163,7 +171,7 @@ def _parse_ipv4_address(value: 'Any') -> 'IPv4Address':

"""
if not isinstance(value, bytes):
raise ProtocolError(f'invalid PyPCAPFile IPv4 address: {value!r}')
raise ProtocolError(f'{_ENGINE}: invalid IPv4 address: {value!r}')
try:
if len(value) != 4:
# Dotted-decimal ASCII text, the actual PyPCAPFile 0.12.0 form --
Expand All @@ -172,7 +180,7 @@ def _parse_ipv4_address(value: 'Any') -> 'IPv4Address':
return ipaddress.IPv4Address(value.decode('ascii'))
return ipaddress.IPv4Address(value)
except (ValueError, UnicodeDecodeError) as error:
raise ProtocolError(f'invalid PyPCAPFile IPv4 address: {value!r}') from error
raise ProtocolError(f'{_ENGINE}: invalid IPv4 address: {value!r}') from error


def _parse_mac_address(value: 'Any') -> 'str':
Expand Down Expand Up @@ -201,14 +209,14 @@ def _parse_mac_address(value: 'Any') -> 'str':

"""
if not isinstance(value, (bytes, bytearray)):
raise ProtocolError(f'invalid PyPCAPFile MAC address: {value!r}')
raise ProtocolError(f'{_ENGINE}: invalid MAC address: {value!r}')
raw = bytes(value)
if len(raw) == 6:
return raw.hex(':')
try:
return raw.decode('ascii')
except UnicodeDecodeError as error:
raise ProtocolError(f'invalid PyPCAPFile MAC address: {value!r}') from error
raise ProtocolError(f'{_ENGINE}: invalid MAC address: {value!r}') from error


def _maybe_unhex(value: 'bytes') -> 'bytes':
Expand Down Expand Up @@ -410,9 +418,9 @@ def _decline_ipv6_tcp(packet: 'Packet', count: 'int') -> 'None':
_ipv6_tcp_warned[key] = anchor
while config.IPV6_TCP_WARNED_LIMIT != -1 and len(_ipv6_tcp_warned) > config.IPV6_TCP_WARNED_LIMIT:
_ipv6_tcp_warned.popitem(last=False)
warn(f"Frame {count}: TCP over IPv6 is left out of TCP reassembly and flow tracing, as "
"'pypcapfile' has no IPv6 decoder; later such frames of this capture are left out "
'without another warning', AttributeWarning, stacklevel=stacklevel())
warn(f'{_ENGINE}: frame {count}: TCP over IPv6 is left out of TCP reassembly and flow '
"tracing, as 'pypcapfile' has no IPv6 decoder; later such frames of this capture are "
'left out without another warning', AttributeWarning, stacklevel=stacklevel())


def _transport(ipv4: 'IP') -> 'Optional[bytes]':
Expand Down Expand Up @@ -747,7 +755,7 @@ def ipv6_reassembly(packet: 'Packet', *, count: 'int' = -1) -> 'IP_Packet[IPv6Ad
UnsupportedCall: Always, as `PyPCAPFile`_ has no IPv6 decoder.

"""
raise UnsupportedCall('IPv6 reassembly is not supported by the PyPCAPFile engine: '
raise UnsupportedCall(f'{_ENGINE}: IPv6 reassembly is not supported: '
"'pypcapfile' has no IPv6 decoder, so no IPv6 fragment header "
'can be read')

Expand Down
14 changes: 11 additions & 3 deletions pcapkit/toolkit/pyshark.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
from typing import TYPE_CHECKING, cast

from pcapkit.const.reg.linktype import LinkType as Enum_LinkType
from pcapkit.foundation.engines.pyshark import PyShark
from pcapkit.foundation.traceflow.data.tcp import Packet as TF_TCP_Packet
from pcapkit.utilities.exceptions import MissingKeyError, ProtocolError

Expand All @@ -29,6 +30,13 @@

__all__ = ['packet2dict', 'tcp_traceflow', 'ENCAP_TYPE_TO_LINKTYPE', 'FILTER_NAME_TO_LINKTYPE']

#: Message prefix shared by every message below, read off
#: :attr:`PyShark.__engine_name__
#: <pcapkit.foundation.engines.pyshark.PyShark.__engine_name__>` rather than
#: spelled out, so the engine cannot be renamed there and still be named the old
#: way here (:issue:`2304`).
_ENGINE = PyShark.__engine_name__

#: ``frame.encap_type`` -- Wireshark's internal ``WTAP_ENCAP_*`` number, which |pyshark|_
#: exposes as ``packet.frame_info.encap_type`` -- to the matching
#: :class:`~pcapkit.const.reg.linktype.LinkType` member. This is :func:`tcp_traceflow`'s primary
Expand Down Expand Up @@ -343,7 +351,7 @@ def _parse_flag(value: 'Any', name: 'str') -> 'bool':
flag = _BOOLEAN_FIELD.get(str(value))
if flag is not None:
return flag
raise ProtocolError(f'invalid PyShark boolean field {name}: {value!r}')
raise ProtocolError(f'{_ENGINE}: invalid boolean field {name}: {value!r}')


def _parse_epoch(value: 'Any') -> 'float':
Expand All @@ -362,7 +370,7 @@ def _parse_epoch(value: 'Any') -> 'float':
try:
return float(decimal.Decimal(str(value)))
except decimal.InvalidOperation:
raise ProtocolError(f'invalid PyShark frame.time_epoch: {value!r}') from None
raise ProtocolError(f'{_ENGINE}: invalid frame.time_epoch: {value!r}') from None


def _absolute(tcp: 'Any', name: 'str') -> 'int':
Expand Down Expand Up @@ -600,7 +608,7 @@ def tcp_traceflow(packet: 'Packet', *, count: 'int' = -1) -> 'TF_TCP_Packet | No
# first layer that is not the frame layer.
frame = _frame_layer(packet)
if frame is None:
raise ProtocolError(f'PyShark packet {packet.number} has no frame layer')
raise ProtocolError(f'{_ENGINE}: packet {packet.number} has no frame layer')
encap_type = getattr(frame, 'encap_type', None)
if encap_type is None:
name = [layer for layer in packet.layers if layer is not frame][0].layer_name
Expand Down
10 changes: 9 additions & 1 deletion pcapkit/toolkit/scapy.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@

from pcapkit.const.reg.linktype import LinkType as Enum_LinkType
from pcapkit.const.reg.transtype import TransType as Enum_TransType
from pcapkit.foundation.engines.scapy import Scapy
from pcapkit.foundation.reassembly.data.ip import Packet as IP_Packet
from pcapkit.foundation.reassembly.data.tcp import Packet as TCP_Packet
from pcapkit.foundation.traceflow.data.data import FrameRecord
Expand All @@ -55,11 +56,18 @@
from pcapkit.utilities.exceptions import MissingKeyError, ModuleNotFound, stacklevel
from pcapkit.utilities.warnings import ScapyWarning, warn

#: Message prefix shared by every message below, read off
#: :attr:`Scapy.__engine_name__
#: <pcapkit.foundation.engines.scapy.Scapy.__engine_name__>` rather than spelled
#: out, so the engine cannot be renamed there and still be named the old way
#: here (:issue:`2304`).
_ENGINE = Scapy.__engine_name__

try:
import scapy
except ModuleNotFoundError:
scapy = None
warn("dependency package 'Scapy' not found",
warn(f"{_ENGINE}: dependency package 'scapy' not found",
ScapyWarning, stacklevel=stacklevel())

if TYPE_CHECKING:
Expand Down
Loading
Loading