def getfield(self, pkt, s): if pkt.tls_session.consider_read_padding(): return ByteField.getfield(self, pkt, s) return s, None
class RadioTap(Packet): name = "RadioTap dummy" deprecated_fields = { "Channel": ("ChannelFrequency", "2.4.3"), "ChannelFlags2": ("ChannelPlusFlags", "2.4.3"), "ChannelNumber": ("ChannelPlusNumber", "2.4.3"), } fields_desc = [ ByteField('version', 0), ByteField('pad', 0), LEShortField('len', None), FlagsField('present', None, -32, _rt_present), # noqa: E501 # Extended presence mask ConditionalField( PacketListField("Ext", [], next_cls_cb=_next_radiotap_extpm), lambda pkt: pkt.present and pkt.present.Ext), # noqa: E501 # RadioTap fields - each starts with a _RadiotapReversePadField # to handle padding # TSFT ConditionalField( _RadiotapReversePadField(LELongField("mac_timestamp", 0)), lambda pkt: pkt.present and pkt.present.TSFT), # Flags ConditionalField( _RadiotapReversePadField(FlagsField("Flags", None, -8, _rt_flags)), lambda pkt: pkt.present and pkt.present.Flags), # Rate ConditionalField(_RadiotapReversePadField(ByteField("Rate", 0)), lambda pkt: pkt.present and pkt.present.Rate), # Channel ConditionalField( _RadiotapReversePadField(LEShortField("ChannelFrequency", 0)), lambda pkt: pkt.present and pkt.present.Channel), ConditionalField( FlagsField("ChannelFlags", None, -16, _rt_channelflags), lambda pkt: pkt.present and pkt.present.Channel), # dBm_AntSignal ConditionalField( _RadiotapReversePadField(_dbmField("dBm_AntSignal", -256)), lambda pkt: pkt.present and pkt.present.dBm_AntSignal), # dBm_AntNoise ConditionalField( _RadiotapReversePadField(_dbmField("dBm_AntNoise", -256)), lambda pkt: pkt.present and pkt.present.dBm_AntNoise), # Lock_Quality ConditionalField( _RadiotapReversePadField(LEShortField("Lock_Quality", 0), ), lambda pkt: pkt.present and pkt.present.Lock_Quality), # Antenna ConditionalField(_RadiotapReversePadField(ByteField("Antenna", 0)), lambda pkt: pkt.present and pkt.present.Antenna), # RX Flags ConditionalField( _RadiotapReversePadField( FlagsField("RXFlags", None, -16, _rt_rxflags)), lambda pkt: pkt.present and pkt.present.RXFlags), # TX Flags ConditionalField( _RadiotapReversePadField( FlagsField("TXFlags", None, -16, _rt_txflags)), lambda pkt: pkt.present and pkt.present.TXFlags), # ChannelPlus ConditionalField( _RadiotapReversePadField( FlagsField("ChannelPlusFlags", None, -32, _rt_channelflags2)), lambda pkt: pkt.present and pkt.present.ChannelPlus), ConditionalField(LEShortField("ChannelPlusFrequency", 0), lambda pkt: pkt.present and pkt.present.ChannelPlus), ConditionalField(ByteField("ChannelPlusNumber", 0), lambda pkt: pkt.present and pkt.present.ChannelPlus), # MCS ConditionalField( _RadiotapReversePadField( FlagsField("knownMCS", None, -8, _rt_knownmcs)), lambda pkt: pkt.present and pkt.present.MCS), ConditionalField(BitField("Ness_LSB", 0, 1), lambda pkt: pkt.present and pkt.present.MCS), ConditionalField(BitField("STBC_streams", 0, 2), lambda pkt: pkt.present and pkt.present.MCS), ConditionalField(BitEnumField("FEC_type", 0, 1, { 0: "BCC", 1: "LDPC" }), lambda pkt: pkt.present and pkt.present.MCS), ConditionalField( BitEnumField("HT_format", 0, 1, { 0: "mixed", 1: "greenfield" }), lambda pkt: pkt.present and pkt.present.MCS), ConditionalField( BitEnumField("guard_interval", 0, 1, { 0: "Long_GI", 1: "Short_GI" }), # noqa: E501 lambda pkt: pkt.present and pkt.present.MCS), ConditionalField(BitEnumField("MCS_bandwidth", 0, 2, _rt_bandwidth), lambda pkt: pkt.present and pkt.present.MCS), ConditionalField(ByteField("MCS_index", 0), lambda pkt: pkt.present and pkt.present.MCS), # A_MPDU ConditionalField(_RadiotapReversePadField(LEIntField("A_MPDU_ref", 0)), lambda pkt: pkt.present and pkt.present.A_MPDU), ConditionalField( FlagsField("A_MPDU_flags", None, -32, _rt_a_mpdu_flags), lambda pkt: pkt.present and pkt.present.A_MPDU), # VHT ConditionalField( _RadiotapReversePadField( FlagsField("KnownVHT", None, -16, _rt_knownvht)), lambda pkt: pkt.present and pkt.present.VHT), ConditionalField(FlagsField("PresentVHT", None, -8, _rt_presentvht), lambda pkt: pkt.present and pkt.present.VHT), ConditionalField(ByteEnumField("VHT_bandwidth", 0, _rt_vhtbandwidth), lambda pkt: pkt.present and pkt.present.VHT), ConditionalField(StrFixedLenField("mcs_nss", 0, length=5), lambda pkt: pkt.present and pkt.present.VHT), ConditionalField(ByteField("GroupID", 0), lambda pkt: pkt.present and pkt.present.VHT), ConditionalField(ShortField("PartialAID", 0), lambda pkt: pkt.present and pkt.present.VHT), # timestamp ConditionalField(_RadiotapReversePadField(LELongField("timestamp", 0)), lambda pkt: pkt.present and pkt.present.timestamp), ConditionalField(LEShortField("ts_accuracy", 0), lambda pkt: pkt.present and pkt.present.timestamp), ConditionalField(ByteField("ts_position", 0), lambda pkt: pkt.present and pkt.present.timestamp), ConditionalField(ByteField("ts_flags", 0), lambda pkt: pkt.present and pkt.present.timestamp), # HE - XXX not complete ConditionalField(_RadiotapReversePadField(ShortField("he_data1", 0)), lambda pkt: pkt.present and pkt.present.HE), ConditionalField(ShortField("he_data2", 0), lambda pkt: pkt.present and pkt.present.HE), ConditionalField(ShortField("he_data3", 0), lambda pkt: pkt.present and pkt.present.HE), ConditionalField(ShortField("he_data4", 0), lambda pkt: pkt.present and pkt.present.HE), ConditionalField(ShortField("he_data5", 0), lambda pkt: pkt.present and pkt.present.HE), ConditionalField(ShortField("he_data6", 0), lambda pkt: pkt.present and pkt.present.HE), # HE_MU ConditionalField( _RadiotapReversePadField(LEShortField("hemu_flags1", 0)), lambda pkt: pkt.present and pkt.present.HE_MU), ConditionalField(LEShortField("hemu_flags2", 0), lambda pkt: pkt.present and pkt.present.HE_MU), ConditionalField( FieldListField("RU_channel1", [], ByteField, count_from=lambda x: 4), lambda pkt: pkt.present and pkt.present.HE_MU), ConditionalField( FieldListField("RU_channel2", [], ByteField, count_from=lambda x: 4), lambda pkt: pkt.present and pkt.present.HE_MU), # HE_MU_other_user ConditionalField( _RadiotapReversePadField(LEShortField("hemuou_per_user_1", 0x7fff)), lambda pkt: pkt.present and pkt.present.HE_MU_other_user), ConditionalField( LEShortField("hemuou_per_user_2", 0x003f), lambda pkt: pkt.present and pkt.present.HE_MU_other_user), ConditionalField( ByteField("hemuou_per_user_position", 0), lambda pkt: pkt.present and pkt.present.HE_MU_other_user), ConditionalField( FlagsField("hemuou_per_user_known", 0, -16, _rt_hemuother_per_user_known), lambda pkt: pkt.present and pkt.present.HE_MU_other_user), # L_SIG ConditionalField( _RadiotapReversePadField( FlagsField("lsig_data1", 0, -16, ["rate", "length"])), lambda pkt: pkt.present and pkt.present.L_SIG), ConditionalField(BitField("lsig_length", 0, 12), lambda pkt: pkt.present and pkt.present.L_SIG), ConditionalField(BitField("lsig_rate", 0, 4), lambda pkt: pkt.present and pkt.present.L_SIG), # Remaining StrLenField( 'notdecoded', "", length_from=lambda pkt: max(pkt.len - pkt._tmp_dissect_pos, 0)) ] def guess_payload_class(self, payload): if self.present and self.present.Flags and self.Flags.FCS: return Dot11FCS return Dot11 def post_build(self, p, pay): if self.len is None: p = p[:2] + struct.pack("!H", len(p))[::-1] + p[4:] return p + pay
class SAPDiagDyntAtomItem(PacketNoPadded): name = "SAP Diag Dynt Atom item" fields_desc = [ ShortField("atom_length", 0), ByteField("dlg_flag_1", 0), ByteField("dlg_flag_2", 0), ByteEnumKeysField("etype", 0, diag_atom_etypes), ByteField("area", 0), ByteField("block", 0), ByteField("group", 0), ShortField("row", 0), ShortField("col", 0), # Attr flags BitField("attr_DIAG_BSD_COMBOSTYLE", 0, 1), # 80 BitField("attr_DIAG_BSD_YES3D", 0, 1), # 40 BitField("attr_DIAG_BSD_PROPFONT", 0, 1), # 20 BitField("attr_DIAG_BSD_MATCHCODE", 0, 1), # 10 BitField("attr_DIAG_BSD_JUSTRIGHT", 0, 1), # 08 BitField("attr_DIAG_BSD_INTENSIFY", 0, 1), # 04 BitField("attr_DIAG_BSD_INVISIBLE", 0, 1), # 02 BitField("attr_DIAG_BSD_PROTECTED", 0, 1), # 01 # DIAG_DGOTYP_FNAME ConditionalField( StrLenField("name_text", "", length_from=lambda pkt: pkt.atom_length - 13), lambda pkt: pkt.etype == 114), # DIAG_DGOTYP_PUSHBUTTON_2 */ ConditionalField(ByteField("pushbutton_v_length", 0), lambda pkt: pkt.etype in [115]), ConditionalField(ByteField("pushbutton_v_height", 0), lambda pkt: pkt.etype in [115]), ConditionalField(ShortField("pushbutton_function_code_offset", 0), lambda pkt: pkt.etype in [115]), ConditionalField(ShortField("pushbutton_text_offset", 0), lambda pkt: pkt.etype in [115]), ConditionalField(StrField("pushbutton_text", ""), lambda pkt: pkt.etype in [115]), ConditionalField(StrField("pushbutton_function_code", ""), lambda pkt: pkt.etype in [115]), # DIAG_DGOTYP_TABSTRIP_BUTTON ConditionalField(ByteField("tabstripbutton_v_length", 0), lambda pkt: pkt.etype in [116]), ConditionalField(ByteField("tabstripbutton_v_height", 0), lambda pkt: pkt.etype in [116]), ConditionalField(ByteField("tabstripbutton_page_id", 0), lambda pkt: pkt.etype in [116]), ConditionalField(ShortField("tabstripbutton_function_code_offset", 0), lambda pkt: pkt.etype in [116]), ConditionalField(ShortField("tabstripbutton_text_offset", 0), lambda pkt: pkt.etype in [116]), ConditionalField(ShortField("tabstripbutton_id_offset", 0), lambda pkt: pkt.etype in [116]), ConditionalField(StrNullField("tabstripbutton_text", ""), lambda pkt: pkt.etype in [116]), ConditionalField(StrNullField("tabstripbutton_function_code", ""), lambda pkt: pkt.etype in [116]), ConditionalField(StrNullField("tabstripbutton_id", ""), lambda pkt: pkt.etype in [116]), # DIAG_DGOTYP_XMLPROP ConditionalField( StrLenField("xmlprop_text", "", length_from=lambda pkt: pkt.atom_length - 13), lambda pkt: pkt.etype == 120), # DIAG_DGOTYP_EFIELD_1 or DIAG_DGOTYP_OFIELD_1 or DIAG_DGOTYP_KEYWORD_1 ConditionalField(ByteField("field1_flag1", 0), lambda pkt: pkt.etype in [121, 122, 123]), ConditionalField( FieldLenField("field1_dlen", None, fmt="B", length_of="field1_text"), lambda pkt: pkt.etype in [121, 122, 123]), ConditionalField(ByteField("field1_mlen", 0), lambda pkt: pkt.etype in [121, 122, 123]), ConditionalField(ShortField("field1_maxnrchars", 0), lambda pkt: pkt.etype in [121, 122, 123]), ConditionalField( StrLenField("field1_text", "", length_from=lambda pkt: pkt.field1_dlen), lambda pkt: pkt.etype in [121, 122, 123]), # DIAG_DGOTYP_FRAME_1 ConditionalField(ShortField("frame_drows", 0), lambda pkt: pkt.etype in [127]), ConditionalField(ShortField("frame_dcols", 0), lambda pkt: pkt.etype in [127]), ConditionalField( StrLenField("frame_text", "", length_from=lambda pkt: pkt.atom_length - 17), lambda pkt: pkt.etype in [127]), # DIAG_DGOTYP_RADIOBUTTON_3 ConditionalField(ByteField("radiobutton_button", 0), lambda pkt: pkt.etype in [129]), ConditionalField(ShortField("radiobutton_visible_label_length", 0), lambda pkt: pkt.etype in [129]), ConditionalField(ShortField("radiobutton_event_id_off", 0), lambda pkt: pkt.etype in [129]), ConditionalField(ByteField("radiobutton_event_id_len", 0), lambda pkt: pkt.etype in [129]), ConditionalField(ShortField("radiobutton_text_off", 0), lambda pkt: pkt.etype in [129]), ConditionalField(ShortField("radiobutton_text_length", 0), lambda pkt: pkt.etype in [129]), ConditionalField( StrLenField("radiobutton_text", "", length_from=lambda pkt: pkt.radiobutton_event_id_len + pkt.radiobutton_text_length), lambda pkt: pkt.etype in [129]), # DIAG_DGOTYP_EFIELD_2 or DIAG_DGOTYP_OFIELD_2 or DIAG_DGOTYP_KEYWORD_2 ConditionalField(ShortField("field2_flag1", 0), lambda pkt: pkt.etype in [130, 131, 132]), ConditionalField( FieldLenField("field2_dlen", None, fmt="B", length_of="field2_text"), lambda pkt: pkt.etype in [130, 131, 132]), ConditionalField(ByteField("field2_mlen", 0), lambda pkt: pkt.etype in [130, 131, 132]), ConditionalField(ShortField("field2_maxnrchars", 0), lambda pkt: pkt.etype in [130, 131, 132]), ConditionalField( StrLenField("field2_text", "", length_from=lambda pkt: pkt.field2_dlen), lambda pkt: pkt.etype in [130, 131, 132]), # Remaining types ConditionalField( StrLenField("value", "", length_from=lambda pkt: pkt.atom_length - 13), lambda pkt: pkt.etype not in [114, 115, 116, 120, 121, 122, 123, 127, 129, 130, 131, 132]), ] def post_build(self, p, pay): if pay is None: pay = '' # Update the atom_length field (first 2 bytes) with the packet length p = pack("!H", len(p)) + p[2:] return p + pay
class LLTDAttributeSeesList(LLTDAttribute): name = "LLTD Attribute - Sees List Working Set" fields_desc = [ ByteField("len", 2), ShortField("max_entries", 0), ]
return min(14, max(1, (x - 2407) / 5)) class PresentFlagField(ConditionalField): """Utility field for use by RadioTap""" def __init__(self, field, flag_name): ConditionalField.__init__( self, field, lambda pkt: pkt.hasflag('present', flag_name)) # TODO(ivanlei): This fields_desc does not cover chained present flags decode will fail in this cases scapy.layers.dot11.RadioTap.name = '802.11 RadioTap' # Greatly improved fields_desc for RadioTap which parses known present flags scapy.layers.dot11.RadioTap.fields_desc = [ ByteField('version', 0), ByteField('pad', 0), LEShortField('RadioTap_len', 0), FlagsField('present', None, -32, [ 'TSFT', 'Flags', 'Rate', 'Channel', 'FHSS', 'dBm_AntSignal', 'dBm_AntNoise', 'Lock_Quality', 'TX_Attenuation', 'dB_TX_Attenuation', 'dBm_TX_Power', 'Antenna', 'dB_AntSignal', 'dB_AntNoise', 'b14', 'b15', 'b16', 'b17', 'b18', 'b19', 'b20', 'b21', 'b22', 'b23', 'b24', 'b25', 'b26', 'b27', 'b28', 'b29', 'b30', 'Ext' ]), PresentFlagField(LELongField('TSFT', 0), 'TSFT'), PresentFlagField(ByteField('Flags', 0), 'Flags'), PresentFlagField(ByteField('Rate', 0), 'Rate'), PresentFlagField(ChannelFromMhzField('Channel', 0), 'Channel'), PresentFlagField(LEShortField('Channel_flags', 0), 'Channel'), PresentFlagField(ByteField('FHSS_hop_set', 0), 'FHSS'),
class LLTDAttribute80211MaxRate(LLTDAttribute): name = "LLTD Attribute - 802.11 Max Rate" fields_desc = [ ByteField("len", 2), ShortField("rate", 0), ]
class LLTDAttributeLinkSpeed(LLTDAttribute): name = "LLTD Attribute - Link Speed" fields_desc = [ ByteField("len", 4), IntField("speed", 0), ]
class ISIS_BufferSizeTlv(ISIS_GenericTlv): name = "ISIS Buffer Size TLV" fields_desc = [ByteEnumField("type", 14, _isis_tlv_names), ByteField("len", 2), ShortField("lspbuffersize", 1497)]
class ISIS_ChecksumTlv(ISIS_GenericTlv): name = "ISIS Optional Checksum TLV" fields_desc = [ByteEnumField("type", 12, _isis_tlv_names), ByteField("len", 2), XShortField("checksum", None)]
class IE_QoS(IE_Base): name = "QoS" fields_desc = [ ByteEnumField("ietype", 135, IEType), ShortField("length", None), ByteField("allocation_retention_prioiry", 1), ConditionalField(XBitField("spare", 0x00, 2), lambda p: p.length and p.length > 1), ConditionalField(XBitField("delay_class", 0x000, 3), lambda p: p.length and p.length > 1), ConditionalField(XBitField("reliability_class", 0x000, 3), lambda p: p.length and p.length > 1), ConditionalField(XBitField("peak_troughput", 0x0000, 4), lambda p: p.length and p.length > 2), ConditionalField(BitField("spare", 0, 1), lambda p: p.length and p.length > 2), ConditionalField(XBitField("precedence_class", 0x000, 3), lambda p: p.length and p.length > 2), ConditionalField(XBitField("spare", 0x000, 3), lambda p: p.length and p.length > 3), ConditionalField(XBitField("mean_troughput", 0x00000, 5), lambda p: p.length and p.length > 3), ConditionalField(XBitField("traffic_class", 0x000, 3), lambda p: p.length and p.length > 4), ConditionalField(XBitField("delivery_order", 0x00, 2), lambda p: p.length and p.length > 4), ConditionalField(XBitField("delivery_of_err_sdu", 0x000, 3), lambda p: p.length and p.length > 4), ConditionalField(ByteField("max_sdu_size", None), lambda p: p.length and p.length > 5), ConditionalField(ByteField("max_bitrate_up", None), lambda p: p.length and p.length > 6), ConditionalField(ByteField("max_bitrate_down", None), lambda p: p.length and p.length > 7), ConditionalField(XBitField("redidual_ber", 0x0000, 4), lambda p: p.length and p.length > 8), ConditionalField(XBitField("sdu_err_ratio", 0x0000, 4), lambda p: p.length and p.length > 8), ConditionalField(XBitField("transfer_delay", 0x00000, 6), lambda p: p.length and p.length > 9), ConditionalField(XBitField("traffic_handling_prio", 0x000, 2), lambda p: p.length and p.length > 9), ConditionalField(ByteField("guaranteed_bit_rate_up", None), lambda p: p.length and p.length > 10), ConditionalField(ByteField("guaranteed_bit_rate_down", None), lambda p: p.length and p.length > 11), ConditionalField(XBitField("spare", 0x000, 3), lambda p: p.length and p.length > 12), ConditionalField(BitField("signaling_indication", 0, 1), lambda p: p.length and p.length > 12), ConditionalField(XBitField("source_stats_desc", 0x0000, 4), lambda p: p.length and p.length > 12), ConditionalField(ByteField("max_bitrate_down_ext", None), lambda p: p.length and p.length > 13), ConditionalField(ByteField("guaranteed_bitrate_down_ext", None), lambda p: p.length and p.length > 14), ConditionalField(ByteField("max_bitrate_up_ext", None), lambda p: p.length and p.length > 15), ConditionalField(ByteField("guaranteed_bitrate_up_ext", None), lambda p: p.length and p.length > 16), ConditionalField(ByteField("max_bitrate_down_ext2", None), lambda p: p.length and p.length > 17), ConditionalField(ByteField("guaranteed_bitrate_down_ext2", None), lambda p: p.length and p.length > 18), ConditionalField(ByteField("max_bitrate_up_ext2", None), lambda p: p.length and p.length > 19), ConditionalField(ByteField("guaranteed_bitrate_up_ext2", None), lambda p: p.length and p.length > 20) ]
class LL_MIN_USED_CHANNELS_IND(Packet): name = "LL_MIN_USED_CHANNELS_IND" fields_desc = [ BTLEPhysField('phys', 0), ByteField("min_used_channels", 2), ]
class IE_Recovery(IE_Base): name = "Recovery" fields_desc = [ ByteEnumField("ietype", 14, IEType), ByteField("restart_counter", 24) ]
class GTP_PDCP_PDU_ExtensionHeader(GTP_ExtensionHeader): fields_desc = [ ByteField("length", 0x01), ShortField("pdcp_pdu", None), ByteEnumField("next_ex", 0, ExtensionHeadersTypes), ]
class GTP_UDPPort_ExtensionHeader(GTP_ExtensionHeader): fields_desc = [ ByteField("length", 0x40), ShortField("udp_port", None), ByteEnumField("next_ex", 0, ExtensionHeadersTypes), ]
class HCI_Event_Number_Of_Completed_Packets(Packet): name = "Number Of Completed Packets" fields_desc = [ByteField("number", 0)]
class SAPRouter(Packet): """SAP Router packet This packet is used for general SAP Router packets. There are (at least) five types of SAP Router packets: 1. Route packets. For requesting the routing of a connection to a remote hosts. The packet contains some general information and a connection string with a list of routing hops (:class:`SAPRouterRouteHop`). 2. Administration packets. This packet is used for the SAP Router to send administrative commands. It's suppose to be used only from the hosts running the SAP Router or when an specific route is included in the routing table. Generally administration packets are not accepted from the external binding. 3. Error Information packets. Packets sent when an error occurred. 4. Control Message packets. Used to perform some control activities, like retrieving the current SAPRouter version or to perform the SNC handshake. They have the same structure that error information packets. 5. Route accepted packet. Used to acknowledge a route request ("NI_PONG"). Routed packets and some responses doesn't fill in these five packet types. For identifying those cases, you should check the type using the function :class:`router_is_known_type`. NI Versions found (unconfirmed): - 30: Release 40C - 36: Release <6.20 - 38: Release 7.00/7.10 - 39: Release 7.11 - 40: Release 7.20/7.21 """ # Default router version to use SAPROUTER_DEFAULT_VERSION = 40 # Constants for router types SAPROUTER_ROUTE = "NI_ROUTE" """ :cvar: Constant for route packets :type: C{string} """ SAPROUTER_ADMIN = "ROUTER_ADM" """ :cvar: Constant for administration packets :type: C{string} """ SAPROUTER_ERROR = "NI_RTERR" """ :cvar: Constant for error information packets :type: C{string} """ SAPROUTER_CONTROL = "NI_RTERR" """ :cvar: Constant for control messages packets :type: C{string} """ SAPROUTER_PONG = "NI_PONG" """ :cvar: Constant for route accepted packets :type: C{string} """ router_type_values = [ SAPROUTER_ADMIN, SAPROUTER_ERROR, SAPROUTER_CONTROL, SAPROUTER_ROUTE, SAPROUTER_PONG, ] """ :cvar: List of known packet types :type: ``list`` of C{string} """ name = "SAP Router" fields_desc = [ # General fields present in all SAP Router packets StrNullField("type", SAPROUTER_ROUTE), ConditionalField( ByteField("version", 2), lambda pkt: router_is_known_type(pkt) and not router_is_pong(pkt)), # Route packets ConditionalField( ByteField("route_ni_version", SAPROUTER_DEFAULT_VERSION), router_is_route), ConditionalField(ByteField("route_entries", 0), router_is_route), ConditionalField( ByteEnumKeysField("route_talk_mode", 0, router_ni_talk_mode_values), router_is_route), ConditionalField(ShortField("route_padd", 0), router_is_route), ConditionalField(ByteField("route_rest_nodes", 0), router_is_route), ConditionalField( FieldLenField("route_length", 0, length_of="route_string", fmt="I"), router_is_route), ConditionalField(IntField("route_offset", 0), router_is_route), ConditionalField( PacketListField("route_string", None, SAPRouterRouteHop, length_from=lambda pkt: pkt.route_length), router_is_route), # Admin packets ConditionalField( ByteEnumKeysField("adm_command", 0x02, router_adm_commands), router_is_admin), ConditionalField( ShortField("adm_unused", 0x00), lambda pkt: router_is_admin(pkt) and pkt.adm_command not in [10, 11, 12, 13]), # Info Request fields ConditionalField( StrNullFixedLenField("adm_password", "", 19), lambda pkt: router_is_admin(pkt) and pkt.adm_command in [2]), # Cancel Route fields ConditionalField( FieldLenField("adm_client_count", None, count_of="adm_client_ids", fmt="H"), lambda pkt: router_is_admin(pkt) and pkt.adm_command in [6]), # Trace Connection fields ConditionalField( FieldLenField("adm_client_count", None, count_of="adm_client_ids", fmt="I"), lambda pkt: router_is_admin(pkt) and pkt.adm_command in [12, 13]), # Cancel Route or Trace Connection fields ConditionalField( FieldListField("adm_client_ids", [0x00], IntField("", 0), count_from=lambda pkt: pkt.adm_client_count), lambda pkt: router_is_admin(pkt) and pkt.adm_command in [6, 12, 13]), # Set/Clear Peer Trace fields # TODO: Check whether this field should be a IPv6 address or another proper field ConditionalField( StrFixedLenField("adm_address_mask", "", 32), lambda pkt: router_is_admin(pkt) and pkt.adm_command in [10, 11]), # Error Information/Control Messages fields ConditionalField( ByteEnumKeysField("opcode", 0, router_control_opcodes), lambda pkt: router_is_error(pkt) or router_is_control(pkt)), ConditionalField( ByteField("opcode_padd", 0), lambda pkt: router_is_error(pkt) or router_is_control(pkt)), ConditionalField( SignedIntEnumField("return_code", 0, router_return_codes), lambda pkt: router_is_error(pkt) or router_is_control(pkt)), # Error Information fields ConditionalField( FieldLenField("err_text_length", None, length_of="err_text_value", fmt="!I"), lambda pkt: router_is_error(pkt) and pkt.opcode == 0), ConditionalField( PacketField("err_text_value", SAPRouterError(), SAPRouterError), lambda pkt: router_is_error(pkt) and pkt.opcode == 0 and pkt.err_text_length > 0), ConditionalField(IntField("err_text_unknown", 0), lambda pkt: router_is_error(pkt) and pkt.opcode == 0), # Control Message fields ConditionalField( IntField("control_text_length", 0), lambda pkt: router_is_control(pkt) and pkt.opcode != 0), ConditionalField( StrField("control_text_value", "*ERR"), lambda pkt: router_is_control(pkt) and pkt.opcode != 0), # SNC Frame fields ConditionalField( PacketField("snc_frame", None, SAPSNCFrame), lambda pkt: router_is_control(pkt) and pkt.opcode in [70, 71]) ]
class LLTDAttributeIPv6Address(LLTDAttribute): name = "LLTD Attribute - IPv6 Address" fields_desc = [ ByteField("len", 16), IP6Field("ipv6", "::"), ]
class PCO_SOF(PCO_Option): name = "PCO MS Support of Network Requested Bearer Control indicator" fields_desc = [ ShortEnumField("type", None, PCO_PROTOCOL_TYPES), ByteField("length", 0), ]
class LLTDAttributePerformanceCounterFrequency(LLTDAttribute): name = "LLTD Attribute - Performance Counter Frequency" fields_desc = [ ByteField("len", 8), LongField("freq", 0), ]
class PNIORealTime(Packet): """PROFINET cyclic real-time""" name = "PROFINET Real-Time" fields_desc = [ NotionalLenField("len", None, length_from=lambda p, s: len(s)), NotionalLenField( "dataLen", None, length_from=lambda p, s: len(s[:-4].rstrip(b"\0"))), # noqa: E501 LowerLayerBoundPacketListField( "data", [], _pnio_rtc_guess_payload_class, length_from=lambda p: p.dataLen), # noqa: E501 StrFixedLenField("padding", "", length_from=lambda p: p[PNIORealTime].padding_length( )), # noqa: E501 ShortField("cycleCounter", 0), FlagsField("dataStatus", 0x35, 8, _PNIO_DS_FLAGS), ByteField("transferStatus", 0) ] overload_fields = { ProfinetIO: { "frameID": 0x8000 }, # RT_CLASS_1 } def padding_length(self): """Compute the length of the padding need for the ethernet frame""" fld, val = self.getfield_and_val("data") # use the len field if available to define the padding length, eg for # dissected packets pkt_len = self.getfieldval("len") if pkt_len is not None: return max(0, pkt_len - len(fld.addfield(self, b"", val)) - 4) if isinstance(self.underlayer, ProfinetIO) and \ isinstance(self.underlayer.underlayer, UDP): return max(0, 12 - len(fld.addfield(self, b"", val))) else: return max(0, 40 - len(fld.addfield(self, b"", val))) @staticmethod def analyse_data(packets): """Analyse the data to find heuristical properties and determine location and type of data""" loc = PNIORealTime.find_data(packets) loc = PNIORealTime.analyse_profisafe(packets, loc) pnio_update_config(loc) return loc @staticmethod def find_data(packets): """Analyse a packet list to extract data offsets from packets data.""" # a dictionary to count data offsets (ie != 0x80) # It's formatted: {(src, dst): (total, [count for offset in len])} heuristic = {} # Counts possible data locations # 0x80 are mainly IOxS and trailling 0x00s are just padding for pkt in packets: if PNIORealTime in pkt: pdu = bytes(pkt[PNIORealTime])[:-4].rstrip(b"\0") if (pkt.src, pkt.dst) not in heuristic: heuristic[(pkt.src, pkt.dst)] = (0, []) total, counts = heuristic[(pkt.src, pkt.dst)] if len(counts) < len(pdu): counts.extend([0 for _ in range(len(pdu) - len(counts))]) for i in range(len(pdu)): if orb(pdu[i]) != 0x80: counts[i] += 1 comm = (pkt.src, pkt.dst) heuristic[comm] = (total + 1, counts) # Determine data locations locations = {} for comm in heuristic: total, counts = heuristic[comm] length = len(counts) loc = locations[comm] = [] start = None for i in range(length): if counts[ i] > total // 2: # Data if more than half is != 0x80 # noqa: E501 if start is None: start = i else: if start is not None: loc.append((start - length, PNIORealTimeRawData, { "length": i - start })) start = None return locations @staticmethod def analyse_profisafe(packets, locations=None): """Analyse a packet list to find possible PROFISafe profils. It's based on an heuristical analysis of each payload to try to find CRC and control/status byte. locations: possible data locations. If not provided, analyse_pn_rt will be called beforehand. If not given, it calls in the same time analyse_data which update the configuration of the data field""" # get data locations and entropy of bytes if not locations: locations = PNIORealTime.find_data(packets) entropies = PNIORealTime.data_entropy(packets, locations) # Try to find at least 3 high entropy successive bytes (the CRC) for comm in entropies: entropy = dict(entropies[comm]) # Convert tuples to key => value for i in range(len(locations[comm])): # update each location with its value after profisafe analysis locations[comm][i] = \ PNIORealTime.analyse_one_profisafe_location( locations[comm][i], entropy ) return locations @staticmethod def analyse_one_profisafe_location(location, entropy): """Analyse one PNIO RTC data location to find if its a PROFISafe :param location: location to analyse, a tuple (start, type, config) :param entropy: the entropy of each byte of the packet data :returns: the configuration associated with the data """ start, klass, conf = location if conf["length"] >= 4: # Minimal PROFISafe length succ_count = 0 for j in range(start, start + conf["length"]): # Limit for a CRC is set to 6 bit of entropy min if j in entropy and entropy[j] >= 6: succ_count += 1 else: succ_count = 0 # PROFISafe profiles must end with at least 3 bytes of high entropy if succ_count >= 3: # Possible profisafe CRC return (start, Profisafe, { "CRC": succ_count, "length": conf["length"] }) # Not a PROFISafe profile return (start, klass, conf) @staticmethod def data_entropy(packets, locations=None): """Analyse a packet list to find the entropy of each data byte locations: possible data locations. If not provided, analyse_pn_rt will be called beforehand. If not given, it calls in the same time analyse_data which update the configuration of the data field""" if not locations: locations = PNIORealTime.find_data(packets) # Retrieve the entropy of each data byte, for each communication entropies = {} for comm in locations: if len(locations[comm]) > 0: # Doesn't append empty data entropies[comm] = [] comm_packets = [] # fetch all packets from the communication for pkt in packets: if PNIORealTime in pkt and (pkt.src, pkt.dst) == comm: comm_packets.append( bytes(pkt[PNIORealTime])[:-4].rstrip(b"\0")) # Get the entropy for start, dummy, config in locations[comm]: for i in range(start, start + config["length"]): entropies[comm].append( (i, entropy_of_byte(comm_packets, i))) return entropies @staticmethod def draw_entropy(packets, locations=None): """Plot the entropy of each data byte of PN RT communication""" import matplotlib.pyplot as plt import matplotlib.cm as cm entropies = PNIORealTime.data_entropy(packets, locations) rows = len(entropies) cur_row = 1 for comm in entropies: index = [] vals = [] for i, ent in entropies[comm]: index.append(i) vals.append(ent) # Offsets the indexes to get the index from the beginning offset = -min(index) index = [i + offset for i in index] plt.subplot(rows, 1, cur_row) plt.bar(index, vals, 0.8, color="r") plt.xticks([i + 0.4 for i in index], index) plt.title("Entropy from %s to %s" % comm) cur_row += 1 plt.ylabel("Shannon Entropy") plt.xlabel("Byte offset") # x label only on the last row plt.legend() plt.tight_layout() plt.show()
class LLTDAttributeLargeTLV(LLTDAttribute): name = "LLTD Attribute - Large TLV" fields_desc = [ ByteField("len", 0), ]
class LACP(Packet): name = "LACP" deprecated_fields = { "actor_port_numer": ("actor_port_number", "2.4.4"), "partner_port_numer": ("partner_port_number", "2.4.4"), "colletctor_reserved": ("collector_reserved", "2.4.4"), } fields_desc = [ ByteField("version", 1), ByteField("actor_type", 1), ByteField("actor_length", 20), ShortField("actor_system_priority", 0), MACField("actor_system", None), ShortField("actor_key", 0), ShortField("actor_port_priority", 0), ShortField("actor_port_number", 0), ByteField("actor_state", 0), XStrFixedLenField("actor_reserved", "", 3), ByteField("partner_type", 2), ByteField("partner_length", 20), ShortField("partner_system_priority", 0), MACField("partner_system", None), ShortField("partner_key", 0), ShortField("partner_port_priority", 0), ShortField("partner_port_number", 0), ByteField("partner_state", 0), XStrFixedLenField("partner_reserved", "", 3), ByteField("collector_type", 3), ByteField("collector_length", 16), ShortField("collector_max_delay", 0), XStrFixedLenField("collector_reserved", "", 12), ByteField("terminator_type", 0), ByteField("terminator_length", 0), XStrFixedLenField("reserved", "", 50), ]
class SAPDiag(PacketNoPadded): """SAP Diag packet This packet holds the Diag Header and serve as a container for :class:`SAPDiagItem` items. It handles compression/decompression, adding the appropriate Compression Header when necessary. """ name = "SAP Diag" fields_desc = [ ByteField("mode", 0), # Communication flags BitField("com_flag_TERM_GRA", 0, 1), BitField("com_flag_TERM_NNM", 0, 1), BitField("com_flag_TERM_CAS", 0, 1), BitField("com_flag_TERM_INI", 0, 1), BitField("com_flag_TERM_EOP", 0, 1), BitField("com_flag_TERM_NOP", 0, 1), BitField("com_flag_TERM_EOC", 0, 1), BitField("com_flag_TERM_EOS", 0, 1), ByteField("mode_stat", 0), ByteField("err_no", 0), ByteField("msg_type", 0), ByteField("msg_info", 0), ByteField("msg_rc", 0), ByteEnumKeysField("compress", 0, diag_compress_values), # Compression Header ConditionalField(LEIntField("uncompress_length", None), lambda pkt: pkt.compress == 1), ConditionalField( ByteEnumField("algorithm", 0x12, { 0x12: "LZH", 0x10: "LZC" }), lambda pkt: pkt.compress == 1), ConditionalField(StrFixedLenField("magic_bytes", "\x1f\x9d", 2), lambda pkt: pkt.compress == 1), ConditionalField(ByteField("special", 2), lambda pkt: pkt.compress == 1), # SNC Frame ConditionalField(PacketField("snc_frame", None, SAPSNCFrame), lambda pkt: pkt.compress in [2, 3]), # Message info ConditionalField(StrEncodedPaddedField("info", None), lambda pkt: pkt.err_no != 0), # Payload PacketListField("message", None, SAPDiagItem) ] def do_compress(self, s): """Compress a string using SAP compression C++ extension. :param s: string to compress :type s: C{string} :return: string compression header plus the compressed string :rtype: C{string} :raise pysapcompress.Error: when a compression error is raised """ if len(s) > 0: # Compress the payload and return the output (_, _, outbuffer) = pysapcompress.compress(s, pysapcompress.ALG_LZH) return outbuffer def do_decompress(self, s, length): """Decompress a string using SAP compression C++ extension. :param s: compression header plus compressed string :type s: C{string} :param length: reported compressed length :type length: ``int`` :return: decompressed string :rtype: C{string} :raise pysapcompress.Error: when a decompression error is raised """ if len(s) > 0: # Decompress the payload and return the output (_, _, outbuffer) = pysapcompress.decompress(s, length) return outbuffer def pre_dissect(self, s): """Prepares the packet for dissection. If the compression flag is set, decompress the payload. """ # If the compression flag is set, decompress everything after the headers if s[7] == "\x01": # First need to get the reported decompressed length (reported_length, ) = unpack("<I", s[8:12]) # Then return the headers (Diag and Compression) and the payload (message field) try: return s[:16] + self.do_decompress(s[8:], reported_length) except DecompressError: return s # Uncompressed packet, just return them return s def post_build(self, p, pay): """Compress the payload. If the compression flag is set, compress both the message field and the payload. """ if pay is None: pay = '' if self.compress == 1: payload = "".join([str(item) for item in self.message]) + pay if len(payload) > 0: try: return p[:8] + self.do_compress(payload) except CompressError: return p + pay return p + pay def get_item(self, item_type=None, item_id=None, item_sid=None): """Get an item from the packet's message. Returns None if the message is not found, or a list if the item is found multiple times. :param item_type: item type byte or string value :type item_type: ``int`` or C{string} or ``list`` :param item_id: item ID byte or string value :type item_id: ``int`` or C{string} or ``list`` :param item_sid: item SID byte or string value :type item_sid: ``int`` or C{string} or ``list`` :return: list of items found on the packet or None :rtype: ``list`` of :class:`SAPDiagItem` """ # Expand list lookups items = [] if item_type is not None and type(item_type) == list: for itype in item_type: items.extend(self.get_item(itype, item_id, item_sid)) return items if item_id is not None and type(item_id) == list: for iid in item_id: items.extend(self.get_item(item_type, iid, item_sid)) return items if item_sid is not None and type(item_sid) == list: for isid in item_sid: items.extend(self.get_item(item_type, item_id, isid)) return items # Perform name lookups if item_type is not None and isinstance(item_type, str): item_type = list(diag_item_types.keys())[list( diag_item_types.values()).index(item_type)] if item_id is not None and isinstance(item_id, str): item_id = list(diag_appl_ids.keys())[list( diag_appl_ids.values()).index(item_id)] if item_sid is not None and isinstance(item_sid, str): item_sid = list(diag_appl_sids[item_id].keys())[list( diag_appl_sids[item_id].values()).index(item_sid)] # Filter and return items if item_sid is None and item_id is None: items = [ item for item in self.message if hasattr(item, "item_type") and item.item_type == item_type ] elif item_sid is None: items = [ item for item in self.message if hasattr(item, "item_type") and item.item_type == item_type and item.item_id == item_id ] else: items = [ item for item in self.message if hasattr(item, "item_type") and item.item_type == item_type and item.item_id == item_id and item.item_sid == item_sid ] return items
class SAPLPSCipher(Packet): """SAP LPS cipher packet. This is the data stored inside an LPS encrypted blob (credential or PSE file). It contains all the required data to decrypt and validate the stored context. Context length should be <28h Restriction length should be <400h """ name = "SAP LPS Cipher" LPS_FALLBACK = 0 LPS_DPAPI = 1 LPS_TPM = 2 lps_types = { LPS_FALLBACK: "FALLBACK", LPS_DPAPI: "DPAPI", LPS_TPM: "TPM", } """LPS types""" fields_desc = [ ByteField("version", 2), ByteEnumField("lps_type", 0, lps_types), ShortField("context_length", 0), StrLenField("context", None, length_from=lambda x: x.context_length), ShortField("restriction_length", 0), StrLenField("restriction", None, length_from=lambda x: x.restriction_length), ShortField("encrypted_key_length", 0), StrLenField("encrypted_key", None, length_from=lambda x: x.encrypted_key_length), ShortField("unknown_length", 0), StrLenField("unknown", None, length_from=lambda x: x.unknown_length), ShortField("encrypted_data_length", 0), StrLenField("encrypted_data", None, length_from=lambda x: x.encrypted_data_length), StrFixedLenField("hmac", None, 0x14), LEIntField("checksum", None), ] def decrypt(self): """Decrypt a blob using LPS. Implements FALLBACK and DP methods to derive or obtain the encryption key from the one stored in the PSE/credential file and then uses that encryption key to decrypt the credential using the AES cipher. LPS-protected PSEs/credentials are verified with both a CRC32 checksum and an HMAC. Validation of the checksum and HMAC is not implemented. :return: decrypted object :rtype: string :raise NotImplementedError: if the LPS method is not implemented :raise SAP_LPS_Decryption_Error: if there's an error decrypting the object """ # Validate supported version if self.version != 2: log_lps.error("Version not supported") raise SAPLPSDecryptionError("Version not supported") # TODO: Calculate and validate CRC32 # Decrypt the encryption key using the LPS method if self.lps_type in lps_encryption_key_decryptor: encryption_key = lps_encryption_key_decryptor[self.lps_type](self) else: log_lps.error("Invalid LPS decryption method") raise SAPLPSDecryptionError("Invalid LPS decryption method") # Decrypt the cipher text with the encryption key iv = "\x00" * 16 decryptor = Cipher(algorithms.AES(encryption_key), modes.CBC(iv), backend=default_backend()).decryptor() plain = decryptor.update(self.encrypted_data) + decryptor.finalize() # TODO: Calculate and validate HMAC return plain def decrypt_encryption_key_dpapi(self): """Decrypts the encryption key using the DP API. The key is encrypted using the DP API without any additional entropy. :return: Encryption key decrypted :rtype: string """ log_lps.debug("Obtaining encryption key with DPAPI LPS mode") return dpapi_decrypt_blob(self.encrypted_key) def decrypt_encryption_key_fallback(self): """Decrypts the encryption key using the FALLBACK method. In this method, the context string, usually "CredEncryption" or "PSEEncryption", is encrypted using a derivation of a fixed key hardcoded in CommonCryptoLib, and used as key to encrypt the actual encryption key used in the file with the AES cipher. :return: Encryption key decrypted :rtype: string """ log_lps.debug("Obtaining encryption key with FALLBACK LPS mode") digest = Hash(SHA1(), backend=default_backend()) digest.update(cred_key_lps_fallback) hashed_key = digest.finalize() hmac = HMAC(hashed_key, SHA1(), backend=default_backend()) hmac.update(self.context) default_key = hmac.finalize()[:16] iv = "\x00" * 16 decryptor = Cipher(algorithms.AES(default_key), modes.CBC(iv), backend=default_backend()).decryptor() encryption_key = decryptor.update( self.encrypted_key) + decryptor.finalize() return encryption_key def decrypt_encryption_key_tpm(self): """Decrypts the encryption key using the TPM method. :return: Encryption key decrypted :rtype: string """ log_lps.error("LPS TPM decryption not implemented") raise NotImplementedError("LPS TPM decryption not implemented")
class Dot11EltRSN(Packet): """The enc, cipher, and auth members contain the decoded 'security' details""" name = '802.11 RSN Information Element' cipher_suites = { '\x00\x0f\xac\x00': 'GROUP', '\x00\x0f\xac\x01': 'WEP', '\x00\x0f\xac\x02': 'TKIP', '\x00\x0f\xac\x04': 'CCMP', '\x00\x0f\xac\x05': 'WEP' } auth_suites = {'\x00\x0f\xac\x01': 'MGT', '\x00\x0f\xac\x02': 'PSK'} fields_desc = [ ByteField('ID', 0), FieldLenField("len", None, "info", "B"), LEShortField('version', 1), StrFixedLenField('group_cipher_suite', '', length=4), LEFieldLenField('pairwise_cipher_suite_count', 1, count_of='pairwise_cipher_suite'), FieldListField('pairwise_cipher_suite', None, StrFixedLenField('', '', length=4), count_from=lambda pkt: pkt.pairwise_cipher_suite_count), LEFieldLenField('auth_cipher_suite_count', 1, count_of='auth_cipher_suite'), FieldListField('auth_cipher_suite', None, StrFixedLenField('', '', length=4), count_from=lambda pkt: pkt.auth_cipher_suite_count), BitField('rsn_cap_pre_auth', 0, 1), BitField('rsn_cap_no_pairwise', 0, 1), BitField('rsn_cap_ptksa_replay_counter', 0, 2), BitField('rsn_cap_gtksa_replay_counter', 0, 2), BitField('rsn_cap_mgmt_frame_protect_required', 0, 1), BitField('rsn_cap_mgmt_frame_protect_capable', 0, 1), BitField('rsn_cap_reserved_1', 0, 1), BitField('rsn_cap_peer_key_enabled', 0, 1), BitField('rsn_cap_reserved_2', 0, 6), ] def post_dissection(self, pkt): """Parse cipher suites to determine encryption, cipher, and authentication methods""" self.enc = 'WPA2' # Everything is assumed to be WPA self.cipher = '' self.auth = '' ciphers = [ self.cipher_suites.get(pairwise_cipher) for pairwise_cipher in self.getfieldval('pairwise_cipher_suite') ] if 'GROUP' in ciphers: ciphers = [ self.cipher_suites.get(group_cipher, '') for group_cipher in self.getfieldval('group_cipher_suite') ] for cipher in ['CCMP', 'TKIP', 'WEP']: if cipher in ciphers: self.cipher = cipher break if 'WEP' == self.cipher: self.enc = 'WEP' for auth_cipher in self.getfieldval('auth_cipher_suite'): self.auth = self.auth_suites.get(auth_cipher, '') break
class LLTD(Packet): name = "LLTD" answer_hashret = { # (tos, function) tuple mapping (answer -> query), used by # .hashret() (1, 1): (0, 0), (0, 12): (0, 11), } fields_desc = [ ByteField("version", 1), ByteEnumField("tos", 0, { 0: "Topology discovery", 1: "Quick discovery", 2: "QoS diagnostics", }), ByteField("reserved", 0), MultiEnumField("function", 0, { 0: { 0: "Discover", 1: "Hello", 2: "Emit", 3: "Train", 4: "Probe", 5: "Ack", 6: "Query", 7: "QueryResp", 8: "Reset", 9: "Charge", 10: "Flat", 11: "QueryLargeTlv", 12: "QueryLargeTlvResp", }, 1: { 0: "Discover", 1: "Hello", 8: "Reset", }, 2: { 0: "QosInitializeSink", 1: "QosReady", 2: "QosProbe", 3: "QosQuery", 4: "QosQueryResp", 5: "QosReset", 6: "QosError", 7: "QosAck", 8: "QosCounterSnapshot", 9: "QosCounterResult", 10: "QosCounterLease", }, }, depends_on=lambda pkt: pkt.tos, fmt="B"), MACField("real_dst", None), MACField("real_src", None), ConditionalField(ShortField("xid", 0), lambda pkt: pkt.function in [0, 8]), ConditionalField(ShortField("seq", 0), lambda pkt: pkt.function not in [0, 8]), ] def post_build(self, pkt, pay): if (self.real_dst is None or self.real_src is None) and \ isinstance(self.underlayer, Ether): eth = self.underlayer if self.real_dst is None: pkt = (pkt[:4] + eth.fields_desc[0].i2m(eth, eth.dst) + pkt[10:]) if self.real_src is None: pkt = (pkt[:10] + eth.fields_desc[1].i2m(eth, eth.src) + pkt[16:]) return pkt + pay def mysummary(self): if isinstance(self.underlayer, Ether): return self.underlayer.sprintf( 'LLTD %src% > %dst% %LLTD.tos% - %LLTD.function%') else: return self.sprintf('LLTD %tos% - %function%') def hashret(self): tos, function = self.tos, self.function return b"%c%c" % self.answer_hashret.get((tos, function), (tos, function)) def answers(self, other): if not isinstance(other, LLTD): return False if self.tos == 0: if self.function == 0 and isinstance(self.payload, LLTDDiscover) \ and len(self[LLTDDiscover].stations_list) == 1: # "Topology discovery - Discover" with one MAC address # discovered answers a "Quick discovery - Hello" return other.tos == 1 and \ other.function == 1 and \ LLTDAttributeHostID in other and \ other[LLTDAttributeHostID].mac == \ self[LLTDDiscover].stations_list[0] elif self.function == 12: # "Topology discovery - QueryLargeTlvResp" answers # "Topology discovery - QueryLargeTlv" with same .seq # value return other.tos == 0 and other.function == 11 \ and other.seq == self.seq elif self.tos == 1: if self.function == 1 and isinstance(self.payload, LLTDHello): # "Quick discovery - Hello" answers a "Topology # discovery - Discover" return other.tos == 0 and other.function == 0 and \ other.real_src == self.current_mapper_address return False
class IGMP(Packet): """IGMP Message Class for v1 and v2. This class is derived from class Packet. You need call "igmpize()" so the packet is transformed according the RFC when sent. a=Ether(src="00:01:02:03:04:05") b=IP(src="1.2.3.4") c=IGMP(type=0x12, gaddr="224.2.3.4") x = a/b/c x[IGMP].igmpize() sendp(a/b/c, iface="en0") Parameters: type IGMP type field, 0x11, 0x12, 0x16 or 0x17 mrcode Maximum Response time (zero for v1) gaddr Multicast Group Address 224.x.x.x/4 See RFC2236, Section 2. Introduction for definitions of proper IGMPv2 message format http://www.faqs.org/rfcs/rfc2236.html """ name = "IGMP" igmptypes = { 0x11: "Group Membership Query", 0x12: "Version 1 - Membership Report", 0x16: "Version 2 - Membership Report", 0x17: "Leave Group" } fields_desc = [ ByteEnumField("type", 0x11, igmptypes), ByteField("mrcode", 20), XShortField("chksum", None), IPField("gaddr", "0.0.0.0") ] def post_build(self, p, pay): """Called implicitly before a packet is sent to compute and place IGMP checksum. Parameters: self The instantiation of an IGMP class p The IGMP message in hex in network byte order pay Additional payload for the IGMP message """ p += pay if self.chksum is None: ck = checksum(p) p = p[:2] + chb(ck >> 8) + chb(ck & 0xff) + p[4:] return p @classmethod def dispatch_hook(cls, _pkt=None, *args, **kargs): if _pkt and len(_pkt) >= 4: from scapy.contrib.igmpv3 import IGMPv3 if orb(_pkt[0]) in [0x22, 0x30, 0x31, 0x32]: return IGMPv3 if orb(_pkt[0]) == 0x11 and len(_pkt) >= 12: return IGMPv3 return IGMP def igmpize(self): """Called to explicitly fixup the packet according to the IGMP RFC The rules are: General: 1. the Max Response time is meaningful only in Membership Queries and should be zero IP: 1. Send General Group Query to 224.0.0.1 (all systems) 2. Send Leave Group to 224.0.0.2 (all routers) 3a.Otherwise send the packet to the group address 3b.Send reports/joins to the group address 4. ttl = 1 (RFC 2236, section 2) 5. send the packet with the router alert IP option (RFC 2236, section 2) Ether: 1. Recalculate destination Returns: True The tuple ether/ip/self passed all check and represents a proper IGMP packet. False One of more validation checks failed and no fields were adjusted. The function will examine the IGMP message to assure proper format. Corrections will be attempted if possible. The IP header is then properly adjusted to ensure correct formatting and assignment. The Ethernet header is then adjusted to the proper IGMP packet format. """ gaddr = self.gaddr if hasattr( self, "gaddr") and self.gaddr else "0.0.0.0" # noqa: E501 underlayer = self.underlayer if self.type not in [0x11, 0x30]: # General Rule 1 # noqa: E501 self.mrcode = 0 if isinstance(underlayer, IP): if (self.type == 0x11): if (gaddr == "0.0.0.0"): underlayer.dst = "224.0.0.1" # IP rule 1 # noqa: E501 elif isValidMCAddr(gaddr): underlayer.dst = gaddr # IP rule 3a # noqa: E501 else: warning("Invalid IGMP Group Address detected !") return False elif ((self.type == 0x17) and isValidMCAddr(gaddr)): underlayer.dst = "224.0.0.2" # IP rule 2 # noqa: E501 elif ( (self.type == 0x12) or (self.type == 0x16)) and (isValidMCAddr(gaddr)): # noqa: E501 underlayer.dst = gaddr # IP rule 3b # noqa: E501 else: warning("Invalid IGMP Type detected !") return False if not any( isinstance(x, IPOption_Router_Alert) for x in underlayer.options): # noqa: E501 underlayer.options.append(IPOption_Router_Alert()) _root = self.firstlayer() if _root.haslayer(Ether): # Force recalculate Ether dst _root[Ether].dst = getmacbyip( underlayer.dst) # Ether rule 1 # noqa: E501 from scapy.contrib.igmpv3 import IGMPv3 if isinstance(self, IGMPv3): self.encode_maxrespcode() return True def mysummary(self): """Display a summary of the IGMP object.""" if isinstance(self.underlayer, IP): return self.underlayer.sprintf( "IGMP: %IP.src% > %IP.dst% %IGMP.type% %IGMP.gaddr%" ) # noqa: E501 else: return self.sprintf("IGMP %IGMP.type% %IGMP.gaddr%")
class LLTDAttributePhysicalMedium(LLTDAttribute): name = "LLTD Attribute - Physical Medium" fields_desc = [ ByteField("len", 4), IntEnumField( "medium", 6, { # https://www.iana.org/assignments/ianaiftype-mib/ianaiftype-mib 1: "other", 2: "regular1822", 3: "hdh1822", 4: "ddnX25", 5: "rfc877x25", 6: "ethernetCsmacd", 7: "iso88023Csmacd", 8: "iso88024TokenBus", 9: "iso88025TokenRing", 10: "iso88026Man", 11: "starLan", 12: "proteon10Mbit", 13: "proteon80Mbit", 14: "hyperchannel", 15: "fddi", 16: "lapb", 17: "sdlc", 18: "ds1", 19: "e1", 20: "basicISDN", 21: "primaryISDN", 22: "propPointToPointSerial", 23: "ppp", 24: "softwareLoopback", 25: "eon", 26: "ethernet3Mbit", 27: "nsip", 28: "slip", 29: "ultra", 30: "ds3", 31: "sip", 32: "frameRelay", 33: "rs232", 34: "para", 35: "arcnet", 36: "arcnetPlus", 37: "atm", 38: "miox25", 39: "sonet", 40: "x25ple", 41: "iso88022llc", 42: "localTalk", 43: "smdsDxi", 44: "frameRelayService", 45: "v35", 46: "hssi", 47: "hippi", 48: "modem", 49: "aal5", 50: "sonetPath", 51: "sonetVT", 52: "smdsIcip", 53: "propVirtual", 54: "propMultiplexor", 55: "ieee80212", 56: "fibreChannel", 57: "hippiInterface", 58: "frameRelayInterconnect", 59: "aflane8023", 60: "aflane8025", 61: "cctEmul", 62: "fastEther", 63: "isdn", 64: "v11", 65: "v36", 66: "g703at64k", 67: "g703at2mb", 68: "qllc", 69: "fastEtherFX", 70: "channel", 71: "ieee80211", 72: "ibm370parChan", 73: "escon", 74: "dlsw", 75: "isdns", 76: "isdnu", 77: "lapd", 78: "ipSwitch", 79: "rsrb", 80: "atmLogical", 81: "ds0", 82: "ds0Bundle", 83: "bsc", 84: "async", 85: "cnr", 86: "iso88025Dtr", 87: "eplrs", 88: "arap", 89: "propCnls", 90: "hostPad", 91: "termPad", 92: "frameRelayMPI", 93: "x213", 94: "adsl", 95: "radsl", 96: "sdsl", 97: "vdsl", 98: "iso88025CRFPInt", 99: "myrinet", 100: "voiceEM", 101: "voiceFXO", 102: "voiceFXS", 103: "voiceEncap", 104: "voiceOverIp", 105: "atmDxi", 106: "atmFuni", 107: "atmIma", 108: "pppMultilinkBundle", 109: "ipOverCdlc", 110: "ipOverClaw", 111: "stackToStack", 112: "virtualIpAddress", 113: "mpc", 114: "ipOverAtm", 115: "iso88025Fiber", 116: "tdlc", 117: "gigabitEthernet", 118: "hdlc", 119: "lapf", 120: "v37", 121: "x25mlp", 122: "x25huntGroup", 123: "transpHdlc", 124: "interleave", 125: "fast", 126: "ip", 127: "docsCableMaclayer", 128: "docsCableDownstream", 129: "docsCableUpstream", 130: "a12MppSwitch", 131: "tunnel", 132: "coffee", 133: "ces", 134: "atmSubInterface", 135: "l2vlan", 136: "l3ipvlan", 137: "l3ipxvlan", 138: "digitalPowerline", 139: "mediaMailOverIp", 140: "dtm", 141: "dcn", 142: "ipForward", 143: "msdsl", 144: "ieee1394", 145: "if-gsn", 146: "dvbRccMacLayer", 147: "dvbRccDownstream", 148: "dvbRccUpstream", 149: "atmVirtual", 150: "mplsTunnel", 151: "srp", 152: "voiceOverAtm", 153: "voiceOverFrameRelay", 154: "idsl", 155: "compositeLink", 156: "ss7SigLink", 157: "propWirelessP2P", 158: "frForward", 159: "rfc1483", 160: "usb", 161: "ieee8023adLag", 162: "bgppolicyaccounting", 163: "frf16MfrBundle", 164: "h323Gatekeeper", 165: "h323Proxy", 166: "mpls", 167: "mfSigLink", 168: "hdsl2", 169: "shdsl", 170: "ds1FDL", 171: "pos", 172: "dvbAsiIn", 173: "dvbAsiOut", 174: "plc", 175: "nfas", 176: "tr008", 177: "gr303RDT", 178: "gr303IDT", 179: "isup", 180: "propDocsWirelessMaclayer", 181: "propDocsWirelessDownstream", 182: "propDocsWirelessUpstream", 183: "hiperlan2", 184: "propBWAp2Mp", 185: "sonetOverheadChannel", 186: "digitalWrapperOverheadChannel", 187: "aal2", 188: "radioMAC", 189: "atmRadio", 190: "imt", 191: "mvl", 192: "reachDSL", 193: "frDlciEndPt", 194: "atmVciEndPt", 195: "opticalChannel", 196: "opticalTransport", 197: "propAtm", 198: "voiceOverCable", 199: "infiniband", 200: "teLink", 201: "q2931", 202: "virtualTg", 203: "sipTg", 204: "sipSig", 205: "docsCableUpstreamChannel", 206: "econet", 207: "pon155", 208: "pon622", 209: "bridge", 210: "linegroup", 211: "voiceEMFGD", 212: "voiceFGDEANA", 213: "voiceDID", 214: "mpegTransport", 215: "sixToFour", 216: "gtp", 217: "pdnEtherLoop1", 218: "pdnEtherLoop2", 219: "opticalChannelGroup", 220: "homepna", 221: "gfp", 222: "ciscoISLvlan", 223: "actelisMetaLOOP", 224: "fcipLink", 225: "rpr", 226: "qam", 227: "lmp", 228: "cblVectaStar", 229: "docsCableMCmtsDownstream", 230: "adsl2", 231: "macSecControlledIF", 232: "macSecUncontrolledIF", 233: "aviciOpticalEther", 234: "atmbond", 235: "voiceFGDOS", 236: "mocaVersion1", 237: "ieee80216WMAN", 238: "adsl2plus", 239: "dvbRcsMacLayer", 240: "dvbTdm", 241: "dvbRcsTdma", 242: "x86Laps", 243: "wwanPP", 244: "wwanPP2", 245: "voiceEBS", 246: "ifPwType", 247: "ilan", 248: "pip", 249: "aluELP", 250: "gpon", 251: "vdsl2", 252: "capwapDot11Profile", 253: "capwapDot11Bss", 254: "capwapWtpVirtualRadio", 255: "bits", 256: "docsCableUpstreamRfPort", 257: "cableDownstreamRfPort", 258: "vmwareVirtualNic", 259: "ieee802154", 260: "otnOdu", 261: "otnOtu", 262: "ifVfiType", 263: "g9981", 264: "g9982", 265: "g9983", 266: "aluEpon", 267: "aluEponOnu", 268: "aluEponPhysicalUni", 269: "aluEponLogicalLink", 271: "aluGponPhysicalUni", 272: "vmwareNicTeam", 277: "docsOfdmDownstream", 278: "docsOfdmaUpstream", 279: "gfast", 280: "sdci", }), ]
class SAPDiagMenuEntry(PacketNoPadded): name = "SAP Diag Menu Entry" fields_desc = [ ShortField("length", 0), ByteField("position_1", 0), ByteField("position_2", 0), ByteField("position_3", 0), ByteField("position_4", 0), # Menu Entry Flags BitField("flag_TERM_??8", 0, 1), # 80 BitField("flag_TERM_??7", 0, 1), # 40 BitField("flag_TERM_??6", 0, 1), # 20 BitField("flag_TERM_VKEY", 0, 1), # 10 BitField("flag_TERM_SEP", 0, 1), # 8 BitField("flag_TERM_MEN", 0, 1), # 4 BitField("flag_TERM_SEL", 0, 1), # 2 BitField("flag_TERM_??1", 0, 1), # 1 ByteField("virtual_key", 0), ByteField("return_code_1", 0), ByteField("return_code_2", 0), ByteField("return_code_3", 0), ByteField("return_code_4", 0), ByteField("return_code_5", 0), ByteField("return_code_6", 0), ByteField("function_code_1", 0), ByteField("function_code_2", 0), ByteField("function_code_3", 0), ByteField("function_code_4", 0), ByteField("function_code_5", 0), ByteField("function_code_6", 0), StrNullField("text", ""), StrNullField("accelerator", ""), StrNullField("info", ""), ]
class LLTDAttributeIPv4Address(LLTDAttribute): name = "LLTD Attribute - IPv4 Address" fields_desc = [ ByteField("len", 4), IPField("ipv4", "0.0.0.0"), ]
def getfield(self, pkt, s): if pkt.with_padding: return ByteField.getfield(self, pkt, s) return s, None
class HCI_Event_Hdr(Packet): name = "HCI Event header" fields_desc = [ XByteField("code", 0), ByteField("length", 0), ]