예제 #1
0
class EnhancedPacket(BasePacketBlock, BlockWithTimestampMixin):
    """
    "An Enhanced Packet Block (EPB) is the standard container for storing the
    packets coming from the network."
    - pcapng spec, section 4.3. Other quoted citations are from this section
    unless otherwise noted.
    """
    magic_number = 0x00000006
    __slots__ = []
    schema = [
        ('interface_id', IntField(32, False), 0),
        ('timestamp_high', IntField(32, False), 0),
        ('timestamp_low', IntField(32, False), 0),
        ('captured_len', IntField(32, False), 0),
        ('packet_len', IntField(32, False), 0),
        ('packet_data', PacketBytes('captured_len'), b''),
        (
            'options',
            OptionsField([
                Option(2, 'epb_flags', 'epb_flags'),
                Option(3, 'epb_hash', 'type+bytes',
                       multiple=True),  # todo: process the hash value
                Option(4, 'epb_dropcount', 'u64'),
            ]),
            None)
    ]
예제 #2
0
class EnhancedPacket(BasePacketBlock, BlockWithTimestampMixin):
    """
    "An Enhanced Packet Block (EPB) is the standard container for storing the
    packets coming from the network."
    - pcapng spec, section 4.3. Other quoted citations are from this section
    unless otherwise noted.
    """

    magic_number = 0x00000006
    __slots__ = []
    schema = [
        ("interface_id", IntField(32, False), 0),
        ("timestamp_high", IntField(32, False), 0),
        ("timestamp_low", IntField(32, False), 0),
        ("captured_len", IntField(32, False), 0),
        ("packet_len", IntField(32, False), 0),
        ("packet_data", PacketBytes("captured_len"), b""),
        (
            "options",
            OptionsField(
                [
                    Option(2, "epb_flags", "epb_flags"),
                    Option(3, "epb_hash", "type+bytes", multiple=True),  # todo: process
                    Option(4, "epb_dropcount", "u64"),
                ]
            ),
            None,
        ),
    ]
예제 #3
0
class ObsoletePacket(BasePacketBlock, BlockWithTimestampMixin):
    """
    "The Packet Block is obsolete, and MUST NOT be used in new files. [...] A
    Packet Block was a container for storing packets coming from the network."
    - pcapng spec, Appendix A. Other quoted citations are from this appendix
    unless otherwise noted.
    """

    magic_number = 0x00000002
    __slots__ = []
    schema = [
        ("interface_id", IntField(16, False), 0),
        ("drops_count", IntField(16, False), 0),
        ("timestamp_high", IntField(32, False), 0),
        ("timestamp_low", IntField(32, False), 0),
        ("captured_len", IntField(32, False), 0),
        ("packet_len", IntField(32, False), 0),
        ("packet_data", PacketBytes("captured_len"), None),
        (
            # The options have the same definitions as their epb_ equivalents
            "options",
            OptionsField(
                [
                    Option(2, "pack_flags", "epb_flags"),
                    Option(3, "pack_hash", "type+bytes", multiple=True),
                ]
            ),
            None,
        ),
    ]

    def enhanced(self):
        """Return an EnhancedPacket with this block's attributes."""
        opts_dict = dict(self.options)
        opts_dict["epb_dropcount"] = self.drops_count
        for a in ("flags", "hash"):
            try:
                opts_dict["epb_" + a] = opts_dict.pop("pack_" + a)
            except KeyError:
                pass
        return self.section.new_member(
            EnhancedPacket,
            interface_id=self.interface_id,
            timestamp_high=self.timestamp_high,
            timestamp_low=self.timestamp_low,
            packet_len=self.packet_len,
            packet_data=self.packet_data,
            options=opts_dict,
        )

    # Do this check in _write() instead of _encode() to ensure the block gets written
    # with the correct magic number.
    def _write(self, outstream):
        strictness.problem("Packet Block is obsolete and must not be used")
        if strictness.should_fix():
            self.enhanced()._write(outstream)
        else:
            super(ObsoletePacket, self)._write(outstream)
예제 #4
0
class ObsoletePacket(BasePacketBlock, BlockWithTimestampMixin):
    """
    "The Packet Block is obsolete, and MUST NOT be used in new files. [...] A
    Packet Block was a container for storing packets coming from the network."
    - pcapng spec, Appendix A. Other quoted citations are from this appendix
    unless otherwise noted.
    """
    magic_number = 0x00000002
    __slots__ = []
    schema = [
        ('interface_id', IntField(16, False), 0),
        ('drops_count', IntField(16, False), 0),
        ('timestamp_high', IntField(32, False), 0),
        ('timestamp_low', IntField(32, False), 0),
        ('captured_len', IntField(32, False), 0),
        ('packet_len', IntField(32, False), 0),
        ('packet_data', PacketBytes('captured_len'), b''),
        (
            'options',
            OptionsField([
                Option(2, 'pack_flags',
                       'epb_flags'),  # Same definition as epb_flags
                Option(3, 'pack_hash', 'type+bytes',
                       multiple=True),  # Same definition as epb_hash
            ]),
            None)
    ]

    def enhanced(self):
        """Return an EnhancedPacket with this block's attributes."""
        opts_dict = dict(self.options)
        opts_dict['epb_dropcount'] = self.drops_count
        for a in ('flags', 'hash'):
            try:
                opts_dict['epb_' + a] = opts_dict.pop('pack_' + a)
            except KeyError:
                pass
        return self.section.new_member(EnhancedPacket,
                                       interface_id=self.interface_id,
                                       timestamp_high=self.timestamp_high,
                                       timestamp_low=self.timestamp_low,
                                       packet_len=self.packet_len,
                                       packet_data=self.packet_data,
                                       options=opts_dict)

    def write(self, outstream):
        strictness.problem("Packet Block is obsolete and must not be used")
        if strictness.should_fix():
            self.enhanced().write(outstream)
        else:
            super(ObsoletePacket, self).write(outstream)
예제 #5
0
class SimplePacket(BasePacketBlock):
    """
    "The Simple Packet Block (SPB) is a lightweight container for storing the
    packets coming from the network."
    - pcapng spec, section 4.4. Other quoted citations are from this section
    unless otherwise noted.
    """
    magic_number = 0x00000003
    __slots__ = []
    schema = [
        ('packet_len', IntField(32, False), 0),  # NOT the captured length
        ('packet_data', PacketBytes('captured_len'),
         b''),  # we don't actually use this
    ]

    readonly_fields = set(('captured_len', 'interface_id'))

    def _decode(self):
        """Decodes the raw data of this block into its fields"""
        stream = six.BytesIO(self._raw)
        self._decoded = struct_decode(self.schema[:1], stream,
                                      self.section.endianness)
        # Now we can get our ``captured_len`` property which is required
        # to really know how much data we can load
        self._decoded['packet_data'] = RawBytes(self.captured_len).load(
            stream, self.section.endianness)
        del self._raw

    @property
    def interface_id(self):
        """
        "The Simple Packet Block does not contain the Interface ID field.
        Therefore, it MUST be assumed that all the Simple Packet Blocks have
        been captured on the interface previously specified in the first
        Interface Description Block."
        """
        return 0

    @property
    def captured_len(self):
        """
        "...the SnapLen value MUST be used to determine the size of the Packet
        Data field length."
        """
        snap_len = self.interface.snaplen
        if snap_len == 0:  # unlimited
            return self.packet_len
        else:
            return min(snap_len, self.packet_len)

    def _encode(self, outstream):
        fld_size = IntField(32, False)
        fld_data = RawBytes(0)
        if len(self.section.interfaces) > 1:
            # Spec is a bit ambiguous here. Section 4.4 says "it MUST
            # be assumed that all the Simple Packet Blocks have been captured
            # on the interface previously specified in the first Interface
            # Description Block." but later adds "A Simple Packet Block cannot
            # be present in a Section that has more than one interface because
            # of the impossibility to refer to the correct one (it does not
            # contain any Interface ID field)." Why would it say "the first"
            # IDB and not "the only" IDB if this was really forbidden?
            strictness.problem(
                "writing SimplePacket for section with multiple interfaces")
            if strictness.should_fix():
                # Can't fix this. The IDBs have already been written.
                pass
        snap_len = self.interface.snaplen
        if snap_len > 0 and snap_len < self.captured_len:
            # This isn't a strictness issue, it *will* break other readers
            # if we write more bytes than the snaplen says to expect.
            fld_size.encode(self.packet_len,
                            outstream,
                            endianness=self.section.endianness)
            fld_data.encode(self.packet_data[:snap_len], outstream)
        else:
            fld_size.encode(self.packet_len,
                            outstream,
                            endianness=self.section.endianness)
            fld_data.encode(self.packet_data, outstream)
예제 #6
0
def test_unpack_dummy_packet():
    schema = [
        ("a_string", RawBytes(8), ""),
        ("a_number", IntField(32, False), 0),
        ("options", OptionsField([]), None),
        ("pb_captured_len", IntField(32, False), 0),
        ("pb_orig_len", IntField(32, False), 0),
        ("packet_data", PacketBytes("pb_captured_len"), b""),
        ("spb_orig_len", IntField(32, False), 0),
        ("simple_packet_data", PacketBytes("spb_orig_len"), b""),
        ("name_res", ListField(NameResolutionRecordField()), []),
        ("another_number", IntField(32, False), 0),
    ]

    # Note: NULLs are for padding!
    data = io.BytesIO(
        b"\x01\x23\x45\x67\x89\xab\xcd\xef"
        b"\x00\x00\x01\x00"
        # Options
        b"\x00\x01\x00\x0cHello world!"
        b"\x00\x01\x00\x0fSpam eggs bacon\x00"
        b"\x00\x02\x00\x0fSome other text\x00"
        b"\x00\x00\x00\x00"
        # Enhanced Packet data
        b"\x00\x00\x00\x12"
        b"\x00\x01\x00\x00"
        b"These are 18 bytes\x00\x00"
        # Simple packet data
        b"\x00\x00\x00\x0d"
        b"Simple packet\x00\x00\x00"
        # List of name resolution items
        b"\x00\x01"  # IPv4
        b"\x00\x13"  # Length: 19bytes
        b"\x0a\x22\x33\x44www.example.com\x00"  # 19 bytes (10.34.51.68)
        b"\x00\x01"  # IPv4
        b"\x00\x13"  # Length: 19bytes
        b"\xc0\xa8\x14\x01www.example.org\x00"  # 19 bytes (192.168.20.1)
        b"\x00\x02"  # IPv6
        b"\x00\x1e"  # 30 bytes
        b"\x00\x11\x22\x33\x44\x55\x66\x77"
        b"\x88\x99\xaa\xbb\xcc\xdd\xee\xff"
        b"v6.example.net\x00\x00"
        b"\x00\x00\x00\x00"  # End marker
        # Another number, to check end
        b"\xaa\xbb\xcc\xdd"
    )

    unpacked = struct_decode(schema, data, endianness=">")
    assert unpacked["a_string"] == b"\x01\x23\x45\x67\x89\xab\xcd\xef"
    assert unpacked["a_number"] == 0x100

    assert isinstance(unpacked["options"], Options)
    assert len(unpacked["options"]) == 2
    assert unpacked["options"]["opt_comment"] == "Hello world!"
    assert unpacked["options"][2] == b"Some other text"

    assert unpacked["pb_captured_len"] == 0x12
    assert unpacked["pb_orig_len"] == 0x10000
    assert unpacked["packet_data"] == b"These are 18 bytes"

    assert unpacked["spb_orig_len"] == 13
    assert unpacked["simple_packet_data"] == b"Simple packet"

    assert unpacked["name_res"] == [
        {"address": "10.34.51.68", "names": ["www.example.com"], "type": 1},
        {"address": "192.168.20.1", "names": ["www.example.org"], "type": 1},
        {
            "type": 2,
            "address": "11:2233:4455:6677:8899:aabb:ccdd:eeff",
            "names": ["v6.example.net"],
        },
    ]
예제 #7
0
def test_unpack_dummy_packet():
    schema = [
        ('a_string', RawBytes(8), ''),
        ('a_number', IntField(32, False), 0),
        ('options', OptionsField([]), None),
        ('pb_captured_len', IntField(32, False), 0),
        ('pb_orig_len', IntField(32, False), 0),
        ('packet_data', PacketBytes('pb_captured_len'), b''),
        ('spb_orig_len', IntField(32, False), 0),
        ('simple_packet_data', PacketBytes('spb_orig_len'), b''),
        ('name_res', ListField(NameResolutionRecordField()), []),
        ('another_number', IntField(32, False), 0),
    ]

    # Note: NULLs are for padding!
    data = io.BytesIO(
        b'\x01\x23\x45\x67\x89\xab\xcd\xef'
        b'\x00\x00\x01\x00'

        # Options
        b'\x00\x01\x00\x0cHello world!'
        b'\x00\x01\x00\x0fSpam eggs bacon\x00'
        b'\x00\x02\x00\x0fSome other text\x00'
        b'\x00\x00\x00\x00'

        # Enhanced Packet data
        b'\x00\x00\x00\x12'
        b'\x00\x01\x00\x00'
        b'These are 18 bytes\x00\x00'

        # Simple packet data
        b'\x00\x00\x00\x0d'
        b'Simple packet\x00\x00\x00'

        # List of name resolution items
        b'\x00\x01'  # IPv4
        b'\x00\x13'  # Length: 19bytes
        b'\x0a\x22\x33\x44www.example.com\x00'  # 19 bytes (10.34.51.68)

        b'\x00\x01'  # IPv4
        b'\x00\x13'  # Length: 19bytes
        b'\xc0\xa8\x14\x01www.example.org\x00'  # 19 bytes (192.168.20.1)

        b'\x00\x02'  # IPv6
        b'\x00\x1e'  # 30 bytes
        b'\x00\x11\x22\x33\x44\x55\x66\x77'
        b'\x88\x99\xaa\xbb\xcc\xdd\xee\xff'
        b'v6.example.net\x00\x00'

        b'\x00\x00\x00\x00'  # End marker

        # Another number, to check end
        b'\xaa\xbb\xcc\xdd'
    )

    unpacked = struct_decode(schema, data, endianness='>')
    assert unpacked['a_string'] == b'\x01\x23\x45\x67\x89\xab\xcd\xef'
    assert unpacked['a_number'] == 0x100

    assert isinstance(unpacked['options'], Options)
    assert len(unpacked['options']) == 2
    assert unpacked['options']['opt_comment'] == 'Hello world!'
    assert unpacked['options'][2] == b'Some other text'

    assert unpacked['pb_captured_len'] == 0x12
    assert unpacked['pb_orig_len'] == 0x10000
    assert unpacked['packet_data'] == b'These are 18 bytes'

    assert unpacked['spb_orig_len'] == 13
    assert unpacked['simple_packet_data'] == b'Simple packet'

    assert unpacked['name_res'] == [
        {'address': '10.34.51.68',
         'names': ['www.example.com'], 'type': 1},
        {'address': '192.168.20.1',
         'names': ['www.example.org'], 'type': 1},
        {'type': 2,
            'address': '11:2233:4455:6677:8899:aabb:ccdd:eeff',
         'names': ['v6.example.net']}]