コード例 #1
0
ファイル: block.py プロジェクト: stoneslipper/pcapng
class CustomBlock:
    "Serialize & deserialze a PCAPNG Custom Block"
    head_encoding = '=LLL'
    tail_encoding = '=L'

    UNPACK_DISPATCH_TABLE = util.dict_merge_all([
        option.Comment.dispatch_entry(),
        option.CustomStringCopyable.dispatch_entry(),
        option.CustomBinaryCopyable.dispatch_entry(),
        option.CustomStringNonCopyable.dispatch_entry(),
        option.CustomBinaryNonCopyable.dispatch_entry()
    ])

    @staticmethod
    def is_custom_block_option(obj):
        "Internal method to validate legal custom block options"
        result = (isinstance(obj, option.Comment)
                  | isinstance(obj, option.CustomOption))
        return result

    def __init__(self, block_type, pen_val, content, options_lst=[]):
        "Creates a Custom Block object"
        pcapng.pen.assert_valid_pen(pen_val)
        for opt in options_lst:
            assert self.is_custom_block_option(opt)
        self.block_type = block_type
        self.pen_val = pen_val
        self.content = content
        self.options_lst = options_lst

    #todo define these for all blocks
    def to_map(self):
        "Converts a CB object to a map representation"
        return util.select_keys(
            self.__dict__, ['block_type', 'pen_val', 'content', 'options_lst'])

    def __repr__(self):
        return str(self.to_map())

    def __eq__(self, other):
        return self.to_map() == other.to_map()

    def __ne__(self, other):
        return (not __eq__(self, other))

    def pack(self):
        """Serialize an CB object into packed bytes. NOTE: We are required to use
        Length-Value (LV) encoding for the custom content so that any options may also be recovered."""
        content_bytes = util.block32_lv_bytes_pack(to_bytes(self.content))
        options_bytes = option.pack_all(self.options_lst)
        block_total_len = 16 + len(content_bytes) + len(options_bytes)

        packed_bytes = (struct.pack(self.head_encoding, self.block_type,
                                    block_total_len, self.pen_val) +
                        content_bytes + options_bytes +
                        struct.pack(self.tail_encoding, block_total_len))
        return packed_bytes
コード例 #2
0
def test_dict_merge():
    assert {"a": 1, 'b': 2} == util.dict_merge({'a': 1}, {'b': 2})
    assert {
        "a": 1,
        'b': 2,
        'c': 3
    } == util.dict_merge_all([{
        'a': 1
    }, {
        'b': 2
    }, {
        'c': 3
    }])
コード例 #3
0
ファイル: option_test.py プロジェクト: Ragnt/pcapng
def test_custom_option_value():
    #todo include standalone value pack/unpack
    #todo include pack/unpack  mixed with regular options
    def assert_custom_option_value_codec(pen, content):
        csc = option.CustomStringCopyable(pen, content)
        csc_unpacked = option.CustomStringCopyable.unpack(csc.pack())
        assert csc_unpacked == csc

        cbc = option.CustomBinaryCopyable(pen, content)
        cbc_unpacked = option.CustomBinaryCopyable.unpack(cbc.pack())
        assert cbc_unpacked == cbc

        csnc = option.CustomStringNonCopyable(pen, content)
        csnc_unpacked = option.CustomStringNonCopyable.unpack(csnc.pack())
        assert csnc_unpacked == csnc

        cbnc = option.CustomBinaryNonCopyable(pen, content)
        cbnc_unpacked = option.CustomBinaryNonCopyable.unpack(cbnc.pack())
        assert cbnc_unpacked == cbnc

    assert_custom_option_value_codec(pen.BROCADE_PEN, '')
    assert_custom_option_value_codec(pen.BROCADE_PEN, 'a')
    assert_custom_option_value_codec(pen.BROCADE_PEN, 'go')
    assert_custom_option_value_codec(pen.BROCADE_PEN, 'ray')
    assert_custom_option_value_codec(pen.BROCADE_PEN, 'Doh!')
    assert_custom_option_value_codec(pen.BROCADE_PEN,
                                     'How do you like me now?')

    unpack_dispatch_table = util.dict_merge_all([
        option.Comment.dispatch_entry(),
        option.CustomStringCopyable.dispatch_entry(),
        option.CustomBinaryCopyable.dispatch_entry(),
        option.CustomStringNonCopyable.dispatch_entry(),
        option.CustomBinaryNonCopyable.dispatch_entry()
    ])
    opts_lst = [
        option.Comment("five"),
        option.CustomStringCopyable(pen.BROCADE_PEN, "yo"),
        option.Comment("six"),
        option.CustomBinaryCopyable(pen.BROCADE_PEN, '10011010'),
        option.Comment("seventy-seven"),
        option.CustomStringNonCopyable(pen.BROCADE_PEN, "don't copy me"),
        option.Comment("eight"),
        option.CustomBinaryNonCopyable(pen.BROCADE_PEN, 'fin'),
        option.Comment("Agent 009")
    ]
    packed_bytes = option.pack_all(opts_lst)
    opts_lst_unpacked = option.unpack_all(unpack_dispatch_table, packed_bytes)
    assert opts_lst == opts_lst_unpacked
コード例 #4
0
ファイル: block.py プロジェクト: stoneslipper/pcapng
class SectionHeaderBlock:
    "Serialize & deserialze a PCAPNG Section Header Block"
    SPEC_CODE = 0x0A0D0D0A
    MAJOR_VERSION = 1
    MINOR_VERSION = 0
    block_head_encoding = '=LLLHHq'  #todo need determine endian on read
    block_tail_encoding = '=L'  #todo need determine endian on read

    UNPACK_DISPATCH_TABLE = util.dict_merge_all([
        option.Comment.dispatch_entry(),
        option.CustomStringCopyable.dispatch_entry(),
        option.CustomBinaryCopyable.dispatch_entry(),
        option.CustomStringNonCopyable.dispatch_entry(),
        option.CustomBinaryNonCopyable.dispatch_entry(),
        option.ShbHardware.dispatch_entry(),
        option.ShbOs.dispatch_entry(),
        option.ShbUserAppl.dispatch_entry()
    ])

    @staticmethod
    def is_shb_option(obj):
        "Internal method to validate legal SHB options"
        result = (isinstance(obj, option.Comment)
                  | isinstance(obj, option.CustomOption)
                  | isinstance(obj, option.ShbOption))
        return result

    def __init__(self, options_lst=[]):
        "Creates an SHB object with the specified options"
        for opt in options_lst:
            assert self.is_shb_option(opt)
        self.options_lst = options_lst

    def to_map(self):
        "Converts an SHB object to a map representation"
        base_map = {
            'SPEC_CODE': self.SPEC_CODE,
            'SHB_MAJOR_VERSION': self.MAJOR_VERSION,
            'SHB_MINOR_VERSION': self.MINOR_VERSION,
        }
        result = util.dict_merge(
            base_map, util.select_keys(self.__dict__, ['options_lst']))
        return result

    def __repr__(self):
        return str(self.to_map())

    def __eq__(self, other):
        return self.to_map() == other.to_map()

    def __ne__(self, other):
        return (not __eq__(self, other))

    @staticmethod
    def dispatch_entry():
        return {SectionHeaderBlock.SPEC_CODE: SectionHeaderBlock.unpack}

    def pack(self):  #todo data_len
        "Serialize a SHB object into packed bytes"
        options_bytes = option.pack_all(self.options_lst)
        section_len = -1  #todo unused at present; must pre-accum all blocks if want to use

        block_total_len = (
            4 +  # block type
            4 +  # block total length
            4 +  # byte order magic
            2 + 2 +  # major version + minor version
            8 +  # section length
            len(options_bytes) + 4)  # block total length
        packed_bytes = (
            struct.pack(self.block_head_encoding, self.SPEC_CODE,
                        block_total_len, BYTE_ORDER_MAGIC, self.MAJOR_VERSION,
                        self.MINOR_VERSION, section_len) + options_bytes +
            struct.pack(self.block_tail_encoding, block_total_len))
        return packed_bytes

    @staticmethod
    def unpack(block_bytes):  #todo verify block type & all fields
        "Deserialize a SHB object from packed bytes"
        util.assert_type_bytes(block_bytes)
        (block_type, block_total_len, byte_order_magic, major_version,
         minor_version,
         section_len) = struct.unpack(SectionHeaderBlock.block_head_encoding,
                                      block_bytes[:24])
        (block_total_len_end, ) = struct.unpack(
            SectionHeaderBlock.block_tail_encoding, block_bytes[-4:])
        assert block_type == SectionHeaderBlock.SPEC_CODE
        assert byte_order_magic == BYTE_ORDER_MAGIC
        assert major_version == SectionHeaderBlock.MAJOR_VERSION
        assert minor_version == SectionHeaderBlock.MINOR_VERSION
        assert block_total_len == block_total_len_end == len(block_bytes)
        # section_len currently ignored
        options_bytes = block_bytes[24:-4]
        options_lst = option.unpack_all(
            SectionHeaderBlock.UNPACK_DISPATCH_TABLE, options_bytes)
        result_obj = SectionHeaderBlock(options_lst)
        return result_obj
コード例 #5
0
ファイル: block.py プロジェクト: stoneslipper/pcapng
class EnhancedPacketBlock:
    "Serialize & deserialze a PCAPNG Enhanced Packet Block"
    SPEC_CODE = 0x06
    head_encoding = '=LLLLLLL'
    tail_encoding = '=L'

    UNPACK_DISPATCH_TABLE = util.dict_merge_all([
        option.Comment.dispatch_entry(),
        option.CustomStringCopyable.dispatch_entry(),
        option.CustomBinaryCopyable.dispatch_entry(),
        option.CustomStringNonCopyable.dispatch_entry(),
        option.CustomBinaryNonCopyable.dispatch_entry(),
        option.EpbFlags.dispatch_entry(),
        option.EpbHash.dispatch_entry(),
        option.EpbDropCount.dispatch_entry()
    ])

    @staticmethod
    def is_epb_option(obj):
        "Internal method to validate legal EPB options"
        result = (isinstance(obj, option.Comment)
                  | isinstance(obj, option.CustomOption)
                  | isinstance(obj, option.EpbOption))
        return result

    def __init__(self,
                 interface_id,
                 pkt_data_captured,
                 pkt_data_orig_len=None,
                 options_lst=[],
                 timestamp=None):
        """Creates an EPB object. If 'timestamp' is not supplied, uses the current UTC time in the
        default format (uint64 microseconds since unix epoch). User-supplied timestamp must also be
        in this format unless IDB options uses option.IdbTsResol to specify alternate."""
        util.assert_uint32(interface_id)  #todo verify args in all fns
        pkt_data_captured = to_bytes(
            pkt_data_captured)  #todo is list & tuple & str ok?
        if pkt_data_orig_len is None:
            pkt_data_orig_len = len(pkt_data_captured)
        else:
            util.assert_uint32(pkt_data_orig_len)
            assert len(pkt_data_captured) <= pkt_data_orig_len
        util.assert_type_list(options_lst)  #todo check type on all fns
        for opt in options_lst:
            assert self.is_epb_option(opt)
        if timestamp is None:
            time_utc_micros = util.curr_time_utc_micros()
        else:
            time_utc_micros = timestamp

        self.interface_id = interface_id
        self.pkt_data_captured = pkt_data_captured
        self.pkt_data_orig_len = pkt_data_orig_len
        self.options_lst = options_lst
        self.time_utc_micros = time_utc_micros

    def to_map(self):
        "Converts an EPB object to a map representation"
        return util.select_keys(self.__dict__, [
            'interface_id', 'pkt_data_captured', 'pkt_data_orig_len',
            'options_lst', 'time_utc_micros'
        ])

    def __repr__(self):
        return str(self.to_map())

    def __eq__(self, other):
        return self.to_map() == other.to_map()

    def __ne__(self, other):
        return (not __eq__(self, other))

    @staticmethod
    def dispatch_entry():
        return {EnhancedPacketBlock.SPEC_CODE: EnhancedPacketBlock.unpack}

    def pack(self):
        "Serialize an EPB object into packed bytes"
        #todo make all arg validation look like this (in order, at top)
        pkt_data_pad = util.block32_pad_bytes(self.pkt_data_captured)
        pkt_data_captured_len = len(self.pkt_data_captured)
        pkt_data_captured_pad_len = len(pkt_data_pad)
        options_bytes = option.pack_all(self.options_lst)
        block_total_len = (
            4 +  # block type
            4 +  # block total length
            4 +  # interface id
            4 +  # timestamp - high
            4 +  # timestamp - low
            4 +  # captured packet length
            4 +  # original packet length
            pkt_data_captured_pad_len + len(options_bytes) + 4
        )  # block total length
        (timestamp_high,
         timestamp_low) = util.uint64_split32(self.time_utc_micros)
        packed_bytes = (
            struct.pack(self.head_encoding, self.SPEC_CODE, block_total_len,
                        self.interface_id, timestamp_high, timestamp_low,
                        pkt_data_captured_len, self.pkt_data_orig_len) +
            pkt_data_pad + options_bytes +
            struct.pack(self.tail_encoding, block_total_len))
        return packed_bytes

    @staticmethod
    def unpack(packed_bytes):
        "Deserialize an EPB object from packed bytes"
        util.assert_type_bytes(packed_bytes)
        (block_type, block_total_len, interface_id, timestamp_high,
         timestamp_low, pkt_data_captured_len,
         pkt_data_orig_len) = struct.unpack(EnhancedPacketBlock.head_encoding,
                                            packed_bytes[:28])
        (block_total_len_end, ) = struct.unpack(
            EnhancedPacketBlock.tail_encoding, packed_bytes[-4:])
        time_utc_micros = util.uint64_join32(timestamp_high, timestamp_low)
        assert block_type == EnhancedPacketBlock.SPEC_CODE  #todo verify block type & all fields, all fns
        assert block_total_len == block_total_len_end == len(packed_bytes)
        assert pkt_data_captured_len <= pkt_data_orig_len

        pkt_data_captured_pad_len = util.block32_ceil_num_bytes(
            pkt_data_captured_len)
        block_bytes_stripped = packed_bytes[28:-4]
        pkt_data = block_bytes_stripped[:pkt_data_captured_len]
        options_bytes = block_bytes_stripped[pkt_data_captured_pad_len:]
        options_lst = option.unpack_all(
            EnhancedPacketBlock.UNPACK_DISPATCH_TABLE, options_bytes)
        result_obj = EnhancedPacketBlock(interface_id,
                                         pkt_data,
                                         pkt_data_orig_len,
                                         options_lst,
                                         timestamp=time_utc_micros)
        return result_obj
コード例 #6
0
ファイル: block.py プロジェクト: stoneslipper/pcapng
class InterfaceDescBlock:
    "Serialize & deserialze a PCAPNG Interface Description Block"
    SPEC_CODE = 0x01
    block_head_encoding = '=LLHHL'
    block_tail_encoding = '=L'

    UNPACK_DISPATCH_TABLE = util.dict_merge_all([
        option.Comment.dispatch_entry(),
        option.CustomStringCopyable.dispatch_entry(),
        option.CustomBinaryCopyable.dispatch_entry(),
        option.CustomStringNonCopyable.dispatch_entry(),
        option.CustomBinaryNonCopyable.dispatch_entry(),
        option.IdbName.dispatch_entry(),
        option.IdbDescription.dispatch_entry(),
        option.IdbIpv4Addr.dispatch_entry(),
        option.IdbIpv6Addr.dispatch_entry(),
        option.IdbMacAddr.dispatch_entry(),
        option.IdbEuiAddr.dispatch_entry(),
        option.IdbSpeed.dispatch_entry(),
        option.IdbTsResol.dispatch_entry(),
        option.IdbTZone.dispatch_entry(),
        option.IdbFilter.dispatch_entry(),
        option.IdbOs.dispatch_entry(),
        option.IdbFcsLen.dispatch_entry(),
        option.IdbTsOffset.dispatch_entry(),
    ])

    @staticmethod
    def is_idb_option(obj):
        "Internal method to validate legal IDB options"
        result = (isinstance(obj, option.Comment)
                  | isinstance(obj, option.CustomOption)
                  | isinstance(obj, option.IdbOption))
        return result

    def __init__(
            self,
            link_type=linktype.LINKTYPE_ETHERNET,  #todo temp testing default
            options_lst=[]):
        "Creates an IDB object with the specified options"
        #todo need test valid linktype
        for opt in options_lst:
            assert self.is_idb_option(opt)
        self.options_lst = options_lst
        self.link_type = link_type
        self.reserved = 0  # spec req zeros
        self.snaplen = 0  # 0 => no limit

    def to_map(self):
        "Converts an IDB object to a map representation"
        return util.select_keys(self.__dict__,
                                ['link_type', 'options_lst', 'snaplen'])

    def __repr__(self):
        return str(self.to_map())

    def __eq__(self, other):
        return self.to_map() == other.to_map()

    def __ne__(self, other):
        return (not __eq__(self, other))

    @staticmethod
    def dispatch_entry():
        return {InterfaceDescBlock.SPEC_CODE: InterfaceDescBlock.unpack}

    def pack(self):
        "Serialize a IDB object into packed bytes"
        options_bytes = option.pack_all(self.options_lst)
        util.assert_type_bytes(options_bytes)
        util.assert_block32_length(options_bytes)
        block_total_len = (
            4 +  # block type
            4 +  # block total length
            2 + 2 +  # linktype + reserved
            4 +  # snaplen
            len(options_bytes) + 4)  # block total length
        packed_bytes = (struct.pack(
            self.block_head_encoding, self.SPEC_CODE, block_total_len,
            self.link_type, self.reserved, self.snaplen) + options_bytes +
                        struct.pack(self.block_tail_encoding, block_total_len))
        return packed_bytes

    @staticmethod
    def unpack(block_bytes):  #todo verify block type & all fields
        "Deserialize a IDB object from packed bytes"
        util.assert_type_bytes(block_bytes)
        (block_type, block_total_len, link_type, reserved,
         snaplen) = struct.unpack(InterfaceDescBlock.block_head_encoding,
                                  block_bytes[:16])
        (block_total_len_end, ) = struct.unpack(
            InterfaceDescBlock.block_tail_encoding, block_bytes[-4:])
        assert block_type == InterfaceDescBlock.SPEC_CODE
        assert block_total_len == block_total_len_end == len(block_bytes)
        assert reserved == 0
        assert snaplen == 0
        options_bytes = block_bytes[16:-4]
        options_lst = option.unpack_all(
            InterfaceDescBlock.UNPACK_DISPATCH_TABLE, options_bytes)
        result_obj = InterfaceDescBlock(link_type, options_lst)
        return result_obj
コード例 #7
0
ファイル: block.py プロジェクト: stoneslipper/pcapng
        util.assert_type_bytes(packed_bytes)
        cbc_obj = CustomBlockCopyable.unpack(packed_bytes)
        assert cbc_obj.block_type == CustomBlockCopyable.SPEC_CODE
        assert cbc_obj.pen_val == pcapng.pen.BROCADE_PEN
        assert cbc_obj.options_lst == CustomMrtIsisBlock.cmib_options
        mrt_info = mrt.mrt_isis_block_unpack(cbc_obj.content)
        return mrt_info


#-----------------------------------------------------------------------------
#todo make a BlockList class?

UNPACK_DISPATCH_TABLE = util.dict_merge_all([
    SectionHeaderBlock.dispatch_entry(),
    InterfaceDescBlock.dispatch_entry(),
    SimplePacketBlock.dispatch_entry(),
    EnhancedPacketBlock.dispatch_entry(),
    CustomBlockCopyable.dispatch_entry(),
    CustomBlockNonCopyable.dispatch_entry(),
])


def unpack_dispatch(packed_bytes):
    "Invokes the proper parsing function given the packed bytes for a PCAPNG block."
    (blk_type, blk_total_len, stripped_bytes) = strip_header(packed_bytes)
    dispatch_fn = UNPACK_DISPATCH_TABLE[blk_type]
    if (dispatch_fn != None):
        result = dispatch_fn(packed_bytes)
        return result
    else:
        #todo exception?
        # raise Exception( 'unpack_dispatch(): unrecognized block blk_type={}'.format(blk_type))