Exemple #1
0
class StatusReport(CborArray):
    ''' The Status Report of BPbis Section 6.1.1.
    '''
    @enum.unique
    class ReasonCode(enum.IntEnum):
        NO_INFO = 0  # "No additional information"
        LIFETIME_EXP = 1  # "Lifetime expired"
        FWD_UNI = 2  # "Forwarded over unidirectional link"
        TX_CANCEL = 3  # "Transmission canceled"
        DEPLETE_STORAGE = 4  # "Depleted storage"
        DEST_EID_UNINTEL = 5  # "Destination endpoint ID unintelligible"
        NO_ROUTE = 6  # "No known route to destination from here"
        NO_NEXT_CONTACT = 7  # "No timely contact with next node on route"
        BLOCK_UNINTEL = 8  # "Block unintelligible"
        HOP_LIMIT_EXC = 9  # "Hop limit exceeded"
        TRAFIC_PAIRED = 10  # "Traffic pared"

        UNKNOWN_SEC = 13  # "Unknown Security Operation"
        FAILED_SEC = 15  # "Failed Security Operation"

    fields_desc = (
        PacketField('status', default=StatusInfoArray(), cls=StatusInfoArray),
        EnumField('reason_code', default=ReasonCode.NO_INFO, enum=ReasonCode),
        EidField('subj_source'),
        PacketField('subj_ts', default=Timestamp(), cls=Timestamp),
        OptionalField(UintField('fragment_offset'), ),
        OptionalField(UintField('payload_len'), ),
    )
Exemple #2
0
class AbstractSecurityBlock(CborSequence):
    ''' Block data from 'draft-ietf-dtn-bpsec-22' Section 3.6.
    '''
    @enum.unique
    class Flag(enum.IntFlag):
        ''' Security flags.
        Flags must be in LSbit-first order.
        '''
        NONE = 0
        PARAMETERS_PRESENT = 2**0

    fields_desc = (
        ArrayWrapField(
            FieldListField('targets', default=[], fld=UintField('block_num'))),
        UintField('context_id'),
        FlagsField('context_flags', default=Flag.NONE, flags=Flag),
        EidField('source'),
        ConditionalField(
            ArrayWrapField(
                PacketListField('parameters', default=None,
                                cls=TypeValuePair), ),
            lambda block: block.getfieldval('context_flags') &
            AbstractSecurityBlock.Flag.PARAMETERS_PRESENT),
        ArrayWrapField(
            PacketListField('results', default=[], cls=TargetResultList), ),
    )
Exemple #3
0
class HopCountBlock(CborArray):
    ''' Block data from BPbis Section 4.3.3.
    '''
    fields_desc = (
        UintField('limit'),
        UintField('count'),
    )
Exemple #4
0
class PrimaryBlock(AbstractBlock):
    ''' The primary block definition '''

    @enum.unique
    class Flag(enum.IntFlag):
        ''' Bundle flags.
        '''
        NONE = 0
        #: bundle deletion status reports are requested.
        REQ_DELETION_REPORT = 0x040000
        #: bundle delivery status reports are requested.
        REQ_DELIVERY_REPORT = 0x020000
        #: bundle forwarding status reports are requested.
        REQ_FORWARDING_REPORT = 0x010000
        #: bundle reception status reports are requested.
        REQ_RECEPTION_REPORT = 0x004000
        #: status time is requested in all status reports.
        REQ_STATUS_TIME = 0x000040
        #: user application acknowledgement is requested.
        USER_APP_ACK = 0x000020
        #: bundle must not be fragmented.
        NO_FRAGMENT = 0x000004
        #: payload is an administrative record.
        PAYLOAD_ADMIN = 0x000002
        #: bundle is a fragment.
        IS_FRAGMENT = 0x000001

    fields_desc = (
        UintField('bp_version', default=7),
        FlagsField('bundle_flags', default=Flag.NONE, flags=Flag),
        EnumField('crc_type', default=AbstractBlock.CrcType.NONE, enum=AbstractBlock.CrcType),
        EidField('destination'),
        EidField('source'),
        EidField('report_to'),
        PacketField('create_ts', default=Timestamp(), cls=Timestamp),
        UintField('lifetime', default=0),
        ConditionalField(
            UintField('fragment_offset', default=0),
            lambda block: block.getfieldval('bundle_flags') & PrimaryBlock.Flag.IS_FRAGMENT
        ),
        ConditionalField(
            UintField('total_app_data_len', default=0),
            lambda block: block.getfieldval('bundle_flags') & PrimaryBlock.Flag.IS_FRAGMENT
        ),
        ConditionalField(
            BstrField('crc_value'),
            lambda block: block.getfieldval('crc_type') != 0
        ),
    )
    def testAddfield(self):
        fld = FieldListField('field', [], UintField('field'))

        s_init = [0, 'hi']
        val = [1, 2]
        s_final = fld.addfield(None, s_init, val)
        self.assertEqual(s_final, [0, 'hi', 1, 2])
    def testGetfield(self):
        fld = FieldListField('field', [], UintField('field'))

        s_init = [1, 2]
        (s_final, val) = fld.getfield(None, s_init)
        self.assertEqual(s_final, [])
        self.assertEqual(val, [1, 2])
Exemple #7
0
class TypeValuePair(CborArray):
    ''' A pattern for an array encoding which contains exactly two values.
    '''

    fields_desc = (
        UintField('type_code'),
        CborField('value'),
    )
Exemple #8
0
class Timestamp(CborArray):
    ''' A structured representation of an DTN Timestamp.
    The timestamp is a two-tuple of (time, sequence number)
    The creation time portion is automatically converted from a
    :py:cls:`datetime.datetime` object and text.
    '''
    fields_desc = (
        DtnTimeField('dtntime', default=0),
        UintField('seqno', default=0),
    )
    def testDecode(self):
        fld = UintField('field')

        self.assertEqual(fld.m2i(None, 0), 0)
        self.assertEqual(fld.m2i(None, 10), 10)
        with self.assertRaises(ValueError):
            fld.m2i(None, 'hi')
    def testAddfield(self):
        fld = OptionalField(UintField('field'))

        s_init = [0, 'hi']
        val = 10
        s_final = fld.addfield(None, s_init, val)
        self.assertEqual(s_final, [0, 'hi', 10])

        s_init = [0, 'hi']
        val = False
        s_final = fld.addfield(None, s_init, val)
        self.assertEqual(s_final, [0, 'hi', False])

        s_init = [0, 'hi']
        val = None
        s_final = fld.addfield(None, s_init, val)
        self.assertEqual(s_final, [0, 'hi'])
    def testGetfield(self):
        fld = OptionalField(UintField('field'))

        s_init = [10, 0, 'hi']
        (s_final, val) = fld.getfield(None, s_init)
        self.assertEqual(s_final, [0, 'hi'])
        self.assertEqual(val, 10)

        s_init = [None]
        (s_final, val) = fld.getfield(None, s_init)
        self.assertEqual(s_final, [])
        self.assertEqual(val, None)

        s_init = []
        (s_final, val) = fld.getfield(None, s_init)
        self.assertEqual(s_final, [])
        self.assertEqual(val, None)
    def testDecode(self):
        fld = OptionalField(UintField('field'))

        self.assertEqual(fld.m2i(None, 10), 10)
        self.assertEqual(fld.m2i(None, False), 0)
    def testDecode(self):
        fld = FieldListField('field', [], UintField('field'))

        self.assertEqual(fld.m2i(None, [0]), [0])
        self.assertEqual(fld.m2i(None, [1, 2]), [1, 2])
Exemple #14
0
class BundleAgeBlock(CborItem):
    ''' Block data from BPbis Section 4.3.2.
    '''
    fields_desc = (
        UintField('age'),
    )
Exemple #15
0
class CanonicalBlock(AbstractBlock):
    ''' The canonical block definition with a type-specific payload.

    Any payload of this block is encoded as the "data" field when building
    and decoded from the "data" field when dissecting.
    '''

    @enum.unique
    class Flag(enum.IntFlag):
        ''' Block flags.
        Flags must be in LSbit-first order.
        '''
        NONE = 0
        #: block must be removed from bundle if it can't be processed.
        REMOVE_IF_NO_PROCESS = 0x10
        #: bundle must be deleted if block can't be processed.
        DELETE_IF_NO_PROCESS = 0x04
        #: transmission of a status report is requested if block can't be processed.
        STATUS_IF_NO_PROCESS = 0x02
        #: block must be replicated in every fragment.
        REPLICATE_IN_FRAGMENT = 0x01

    fields_desc = (
        UintField('type_code', default=None),
        UintField('block_num', default=None),
        FlagsField('block_flags', default=Flag.NONE, flags=Flag),
        EnumField('crc_type', default=AbstractBlock.CrcType.NONE, enum=AbstractBlock.CrcType),
        BstrField('btsd', default=None),  # block-type-specific data here
        ConditionalField(
            BstrField('crc_value'),
            lambda block: block.crc_type != 0
        ),
    )

    def ensure_block_type_specific_data(self):
        ''' Embed payload as field data if not already present.
        '''
        if isinstance(self.payload, scapy.packet.NoPayload):
            return
        if self.fields.get('btsd') is not None:
            return
        if isinstance(self.payload, AbstractCborStruct):
            pay_data = bytes(self.payload)
        else:
            pay_data = self.payload.do_build()
        self.fields['btsd'] = pay_data

    def fill_fields(self):
        self.ensure_block_type_specific_data()
        super().fill_fields()

    def self_build(self, *args, **kwargs):
        self.ensure_block_type_specific_data()
        return super().self_build(*args, **kwargs)

    def do_build_payload(self):
        # Payload is handled by self_build()
        return b''

    def post_dissect(self, s):
        # Extract payload from fields
        pay_type = self.fields.get('type_code')
        pay_data = self.fields.get('btsd')
        if (pay_data is not None and pay_type is not None):
            try:
                cls = self.guess_payload_class(None)
                LOGGER.debug('CanonicalBlock.post_dissect with class %s from: %s', cls, encode_diagnostic(pay_data))
            except KeyError:
                cls = None

            if cls is not None:
                try:
                    pay = cls(pay_data)
                    self.add_payload(pay)
                except Exception as err:
                    if conf.debug_dissector:
                        raise
                    LOGGER.warning('CanonicalBlock failed to dissect payload: %s', err)

        return super().post_dissect(s)

    def default_payload_class(self, payload):
        return scapy.packet.Raw

    @classmethod
    def bind_type(cls, type_code):
        ''' Bind a block-type-specific packet-class handler.

        :param int type_code: The type to bind to the payload class.
        '''

        def func(othercls):
            scapy.packet.bind_layers(cls, othercls, type_code=type_code)
            return othercls

        return func