IPv4 Datagram Reassembly

pcapkit.foundation.reassembly.ipv4 contains IPv4 only, which reconstructs fragmented IPv4 packets back to origin. Please refer to Base Class for more information.

class pcapkit.foundation.reassembly.ipv4.IPv4(*, strict=True, store=True)[source]

Bases: IP

Reassembly for IPv4 payload.

Parameters:
  • strict (bool) – if return all datagrams (including those not implemented) when submit

  • store (bool) – if store reassembled datagram in memory, i.e., self._dtgram (if not, datagram will be discarded after callback)

Example

>>> from pcapkit.foundation.reassembly import IPv4
# Initialise instance:
>>> ipv4_reassembly = IPv4()
# Call reassembly:
>>> ipv4_reassembly(packet_dict)
# Fetch result:
>>> result = ipv4_reassembly.datagram
__protocol_name__: str = 'IPv4'

Protocol name of current reassembly object.

__protocol_type__: Type[ProtocolBase] = <class 'pcapkit.protocols.internet.ipv4.IPv4'>

Protocol of current reassembly object.

Terminology

reasm.ipv4.packet

Data structure for IPv4 datagram reassembly (IPv4.reassembly) is as following, with ipv4 the protocol instance (frame['IPv4']) and ipv4_info its info – the header fields come off the latter, the raw octets off the former:

packet_dict = dict(
  bufid = (
      ipv4_info.src,              # source IP address
      ipv4_info.dst,              # destination IP address
      ipv4_info.id,               # identification
      ipv4_info.protocol,         # payload protocol type
  ),
  num = frame.info.number,        # original packet range number
  fo = ipv4_info.offset,          # fragment offset, in octets
  ihl = ipv4_info.hdr_len,        # internet header length
  mf = ipv4_info.flags.mf,        # more fragment flag
  tl = ipv4_info.len,             # total length, header includes
  header = ipv4.packet.header,    # raw bytes type header
  payload = bytearray(
      ipv4.packet.payload),       # raw bytearray type payload
)
reasm.ipv4.datagram

Data structure for reassembled IPv4 datagram (element from IPv4.datagram tuple) is as following:

(tuple) datagram
 |--> (Info) data
 |     |--> 'completed' : (bool) True --> implemented
 |     |--> 'id' : (Info) original packet identifier
 |     |            |--> 'src' --> (IPv4Address) ipv4.src
 |     |            |--> 'dst' --> (IPv4Address) ipv4.dst
 |     |            |--> 'id' --> (int) ipv4.id
 |     |            |--> 'proto' --> (TransType) ipv4.protocol
 |     |--> 'index' : (tuple) packet numbers
 |     |               |--> (int) original packet range number
 |     |--> 'header' : (bytes) IPv4 header
 |     |--> 'payload' : (bytes) reassembled IPv4 payload
 |     |--> 'packet' : (Protocol) parsed reassembled payload
 |--> (Info) data
 |     |--> 'completed' : (bool) False --> not implemented
 |     |--> 'id' : (Info) original packet identifier
 |     |            |--> 'src' --> (IPv4Address) ipv4.src
 |     |            |--> 'dst' --> (IPv4Address) ipv4.dst
 |     |            |--> 'id' --> (int) ipv4.id
 |     |            |--> 'proto' --> (TransType) ipv4.protocol
 |     |--> 'index' : (tuple) packet numbers
 |     |               |--> (int) original packet range number
 |     |--> 'header' : (bytes) IPv4 header
 |     |--> 'payload' : (tuple) partially reassembled IPv4 payload
 |     |                 |--> (bytes) IPv4 payload fragment
 |     |                 |--> ...
 |     |--> 'packet' : (None)
 |--> (Info) data ...

Note

packet is analysed on the first read, not when the datagram is submitted. A datagram is submitted for every frame – an unfragmented one included, since nothing upstream filters it out – and the analysis is a second full parse of the payload, so running it eagerly charged every caller for a result most never read. Reading the attribute, or any mapping view of it (datagram['packet'], to_dict(), items(), repr()), runs it and keeps the result; see Deferred.

reasm.ipv4.buffer

Data structure for internal buffering when performing reassembly algorithms (IPv4._buffer) is as following:

(dict) buffer --> memory buffer for reassembly
 |--> (tuple) BUFID : (dict)
 |     |--> ipv4.src       |
 |     |--> ipv4.dst       |
 |     |--> ipv4.id        |
 |     |--> ipv4.protocol  |
 |                         |--> 'TDL' : (int) total data length
 |                         |--> 'RCVBT' : (bytearray) fragment received bit table
 |                         |               |--> (bytes) b'\\x00' -> not received
 |                         |               |--> (bytes) b'\\x01' -> received
 |                         |               |--> (bytes) ...
 |                         |--> 'index' : (list) list of reassembled packets
 |                         |               |--> (int) packet range number
 |                         |--> 'header' : (bytes) header buffer
 |                         |--> 'datagram' : (bytearray) data buffer, holes set to b'\\x00'
 |--> (tuple) BUFID ...