class OFPMatch(Packet): name = "OFP_MATCH" fields_desc = [ FlagsField("wildcards1", None, 12, ["DL_VLAN_PCP", "NW_TOS"]), BitField("nw_dst_mask", None, 6), BitField("nw_src_mask", None, 6), FlagsField("wildcards2", None, 8, [ "IN_PORT", "DL_VLAN", "DL_SRC", "DL_DST", "DL_TYPE", "NW_PROTO", "TP_SRC", "TP_DST" ]), ShortEnumField("in_port", None, ofp_port_no), MACField("dl_src", None), MACField("dl_dst", None), ShortField("dl_vlan", None), ByteField("dl_vlan_pcp", None), XByteField("pad1", None), ShortField("dl_type", None), ByteField("nw_tos", None), ByteField("nw_proto", None), XShortField("pad2", None), IPField("nw_src", "0"), IPField("nw_dst", "0"), ShortField("tp_src", None), ShortField("tp_dst", None) ] def extract_padding(self, s): return b"", s # with post_build we create the wildcards field bit by bit def post_build(self, p, pay): # first 10 bits of an ofp_match are always set to 0 lst_bits = "0" * 10 # when one field has not been declared, it is assumed to be wildcarded if self.wildcards1 is None: if self.nw_tos is None: lst_bits += "1" else: lst_bits += "0" if self.dl_vlan_pcp is None: lst_bits += "1" else: lst_bits += "0" else: w1 = binrepr(self.wildcards1) lst_bits += "0" * (2 - len(w1)) lst_bits += w1 # ip masks use 6 bits each if self.nw_dst_mask is None: if self.nw_dst is "0": lst_bits += "111111" # 0x100000 would be ok too (32-bit IP mask) else: lst_bits += "0" * 6 else: m1 = binrepr(self.nw_dst_mask) lst_bits += "0" * (6 - len(m1)) lst_bits += m1 if self.nw_src_mask is None: if self.nw_src is "0": lst_bits += "111111" else: lst_bits += "0" * 6 else: m2 = binrepr(self.nw_src_mask) lst_bits += "0" * (6 - len(m2)) lst_bits += m2 # wildcards2 works the same way as wildcards1 if self.wildcards2 is None: if self.tp_dst is None: lst_bits += "1" else: lst_bits += "0" if self.tp_src is None: lst_bits += "1" else: lst_bits += "0" if self.nw_proto is None: lst_bits += "1" else: lst_bits += "0" if self.dl_type is None: lst_bits += "1" else: lst_bits += "0" if self.dl_dst is None: lst_bits += "1" else: lst_bits += "0" if self.dl_src is None: lst_bits += "1" else: lst_bits += "0" if self.dl_vlan is None: lst_bits += "1" else: lst_bits += "0" if self.in_port is None: lst_bits += "1" else: lst_bits += "0" else: w2 = binrepr(self.wildcards2) lst_bits += "0" * (8 - len(w2)) lst_bits += w2 # In order to write OFPMatch compliant with the specifications, # if prereq_autocomplete has been set to True # we assume ethertype=IP or nwproto=TCP when appropriate subfields are provided. # noqa: E501 if conf.contribs['OPENFLOW']['prereq_autocomplete']: if self.dl_type is None: if self.nw_src is not "0" or self.nw_dst is not "0" or self.nw_proto is not None or self.nw_tos is not None: # noqa: E501 p = p[:22] + struct.pack("!H", 0x0800) + p[24:] lst_bits = lst_bits[:-5] + "0" + lst_bits[-4:] if self.nw_proto is None: if self.tp_src is not None or self.tp_dst is not None: p = p[:22] + struct.pack("!H", 0x0800) + p[24:] lst_bits = lst_bits[:-5] + "0" + lst_bits[-4:] p = p[:25] + struct.pack("!B", 0x06) + p[26:] lst_bits = lst_bits[:-6] + "0" + lst_bits[-5:] ins = b"".join( chb(int("".join(x), 2)) for x in zip(*[iter(lst_bits)] * 8)) # noqa: E501 p = ins + p[4:] return p + pay
class DNS(Packet): name = "DNS" fields_desc = [ ConditionalField(ShortField("length", None), lambda p: isinstance(p.underlayer, TCP)), ShortField("id", 0), BitField("qr", 0, 1), BitEnumField("opcode", 0, 4, {0: "QUERY", 1: "IQUERY", 2: "STATUS"}), BitField("aa", 0, 1), BitField("tc", 0, 1), BitField("rd", 1, 1), BitField("ra", 0, 1), BitField("z", 0, 1), # AD and CD bits are defined in RFC 2535 BitField("ad", 0, 1), # Authentic Data BitField("cd", 0, 1), # Checking Disabled BitEnumField("rcode", 0, 4, {0: "ok", 1: "format-error", 2: "server-failure", 3: "name-error", 4: "not-implemented", 5: "refused"}), DNSRRCountField("qdcount", None, "qd"), DNSRRCountField("ancount", None, "an"), DNSRRCountField("nscount", None, "ns"), DNSRRCountField("arcount", None, "ar"), DNSQRField("qd", "qdcount"), DNSRRField("an", "ancount"), DNSRRField("ns", "nscount"), DNSRRField("ar", "arcount", 0), ] def answers(self, other): return (isinstance(other, DNS) and self.id == other.id and self.qr == 1 and other.qr == 0) def mysummary(self): name = "" if self.qr: type = "Ans" if self.ancount > 0 and isinstance(self.an, DNSRR): name = ' "%s"' % self.an.rdata else: type = "Qry" if self.qdcount > 0 and isinstance(self.qd, DNSQR): name = ' "%s"' % self.qd.qname return 'DNS %s%s ' % (type, name) def post_build(self, pkt, pay): if isinstance(self.underlayer, TCP) and self.length is None: pkt = struct.pack("!H", len(pkt) - 2) + pkt[2:] return pkt + pay def compress(self): """Return the compressed DNS packet (using `dns_compress()`""" return dns_compress(self) def pre_dissect(self, s): """ Check that a valid DNS over TCP message can be decoded """ if isinstance(self.underlayer, TCP): # Compute the length of the DNS packet if len(s) >= 2: dns_len = struct.unpack("!H", s[:2])[0] else: message = "Malformed DNS message: too small!" log_runtime.info(message) raise Scapy_Exception(message) # Check if the length is valid if dns_len < 14 or len(s) < dns_len: message = "Malformed DNS message: invalid length!" log_runtime.info(message) raise Scapy_Exception(message) return s
def __init__(self, name, default, calculate_length=None): BitField.__init__(self, name, default, 0) self.length_f = calculate_length
def getfield(self, pkt, s): self.size = self.length_f(pkt) return BitField.getfield(self, pkt, s)
class LLDPDUManagementAddress(LLDPDU): """ ieee 802.1ab-2016 - sec. 8.5.9 / p. 32 currently only 0x00..0x1e are used by standards, no way to use anything > 0xff as management address subtype is only one octet wide see https://www.iana.org/assignments/ address-family-numbers/address-family-numbers.xhtml """ IANA_ADDRESS_FAMILY_NUMBERS = { 0x00: 'other', 0x01: 'IPv4', 0x02: 'IPv6', 0x03: 'NSAP', 0x04: 'HDLC', 0x05: 'BBN', 0x06: '802', 0x07: 'E.163', 0x08: 'E.164', 0x09: 'F.69', 0x0a: 'X.121', 0x0b: 'IPX', 0x0c: 'Appletalk', 0x0d: 'Decnet IV', 0x0e: 'Banyan Vines', 0x0f: 'E.164 with NSAP', 0x10: 'DNS', 0x11: 'Distinguished Name', 0x12: 'AS Number', 0x13: 'XTP over IPv4', 0x14: 'XTP over IPv6', 0x15: 'XTP native mode XTP', 0x16: 'Fiber Channel World-Wide Port Name', 0x17: 'Fiber Channel World-Wide Node Name', 0x18: 'GWID', 0x19: 'AFI for L2VPN', 0x1a: 'MPLS-TP Section Endpoint ID', 0x1b: 'MPLS-TP LSP Endpoint ID', 0x1c: 'MPLS-TP Pseudowire Endpoint ID', 0x1d: 'MT IP Multi-Topology IPv4', 0x1e: 'MT IP Multi-Topology IPv6' } SUBTYPE_MANAGEMENT_ADDRESS_OTHER = 0x00 SUBTYPE_MANAGEMENT_ADDRESS_IPV4 = 0x01 SUBTYPE_MANAGEMENT_ADDRESS_IPV6 = 0x02 SUBTYPE_MANAGEMENT_ADDRESS_NSAP = 0x03 SUBTYPE_MANAGEMENT_ADDRESS_HDLC = 0x04 SUBTYPE_MANAGEMENT_ADDRESS_BBN = 0x05 SUBTYPE_MANAGEMENT_ADDRESS_802 = 0x06 SUBTYPE_MANAGEMENT_ADDRESS_E_163 = 0x07 SUBTYPE_MANAGEMENT_ADDRESS_E_164 = 0x08 SUBTYPE_MANAGEMENT_ADDRESS_F_69 = 0x09 SUBTYPE_MANAGEMENT_ADDRESS_X_121 = 0x0A SUBTYPE_MANAGEMENT_ADDRESS_IPX = 0x0B SUBTYPE_MANAGEMENT_ADDRESS_APPLETALK = 0x0C SUBTYPE_MANAGEMENT_ADDRESS_DECNET_IV = 0x0D SUBTYPE_MANAGEMENT_ADDRESS_BANYAN_VINES = 0x0E SUBTYPE_MANAGEMENT_ADDRESS_E_164_WITH_NSAP = 0x0F SUBTYPE_MANAGEMENT_ADDRESS_DNS = 0x10 SUBTYPE_MANAGEMENT_ADDRESS_DISTINGUISHED_NAME = 0x11 SUBTYPE_MANAGEMENT_ADDRESS_AS_NUMBER = 0x12 SUBTYPE_MANAGEMENT_ADDRESS_XTP_OVER_IPV4 = 0x13 SUBTYPE_MANAGEMENT_ADDRESS_XTP_OVER_IPV6 = 0x14 SUBTYPE_MANAGEMENT_ADDRESS_XTP_NATIVE_MODE_XTP = 0x15 SUBTYPE_MANAGEMENT_ADDRESS_FIBER_CHANNEL_WORLD_WIDE_PORT_NAME = 0x16 SUBTYPE_MANAGEMENT_ADDRESS_FIBER_CHANNEL_WORLD_WIDE_NODE_NAME = 0x17 SUBTYPE_MANAGEMENT_ADDRESS_GWID = 0x18 SUBTYPE_MANAGEMENT_ADDRESS_AFI_FOR_L2VPN = 0x19 SUBTYPE_MANAGEMENT_ADDRESS_MPLS_TP_SECTION_ENDPOINT_ID = 0x1A SUBTYPE_MANAGEMENT_ADDRESS_MPLS_TP_LSP_ENDPOINT_ID = 0x1B SUBTYPE_MANAGEMENT_ADDRESS_MPLS_TP_PSEUDOWIRE_ENDPOINT_ID = 0x1C SUBTYPE_MANAGEMENT_ADDRESS_MT_IP_MULTI_TOPOLOGY_IPV4 = 0x1D SUBTYPE_MANAGEMENT_ADDRESS_MT_IP_MULTI_TOPOLOGY_IPV6 = 0x1E INTERFACE_NUMBERING_SUBTYPES = { 0x01: 'unknown', 0x02: 'ifIndex', 0x03: 'system port number' } SUBTYPE_INTERFACE_NUMBER_UNKNOWN = 0x01 SUBTYPE_INTERFACE_NUMBER_IF_INDEX = 0x02 SUBTYPE_INTERFACE_NUMBER_SYSTEM_PORT_NUMBER = 0x03 ''' Note - calculation of _length field: _length = 1@_management_address_string_length + 1@management_address_subtype + management_address.len + 1@interface_numbering_subtype + 4@interface_number + 1@_oid_string_length + object_id.len ''' fields_desc = [ BitEnumField('_type', 0x08, 7, LLDPDU.TYPES), BitFieldLenField('_length', None, 9, length_of='management_address', adjust=lambda pkt, x: 8 + len(pkt.management_address) + len(pkt.object_id)), BitFieldLenField( '_management_address_string_length', None, 8, length_of='management_address', adjust=lambda pkt, x: len(pkt.management_address) + 1), ByteEnumField('management_address_subtype', 0x00, IANA_ADDRESS_FAMILY_NUMBERS), XStrLenField( 'management_address', '', length_from=lambda pkt: pkt._management_address_string_length - 1), ByteEnumField('interface_numbering_subtype', SUBTYPE_INTERFACE_NUMBER_UNKNOWN, INTERFACE_NUMBERING_SUBTYPES), BitField('interface_number', 0, 32), BitFieldLenField('_oid_string_length', None, 8, length_of='object_id'), XStrLenField('object_id', '', length_from=lambda pkt: pkt._oid_string_length), ] def _check(self): """ run layer specific checks """ if conf.contribs['LLDP'].strict_mode(): management_address_len = len(self.management_address) if management_address_len == 0 or management_address_len > 31: raise LLDPInvalidLengthField( 'management address must be 1..31 characters long - ' 'got string of size {}'.format(management_address_len))
class ZigbeeNWKCommandPayload(Packet): name = "Zigbee Network Layer Command Payload" fields_desc = [ ByteEnumField("cmd_identifier", 1, { 1: "route request", 2: "route reply", 3: "network status", 4: "leave", 5: "route record", 6: "rejoin request", 7: "rejoin response", 8: "link status", 9: "network report", 10: "network update", 11: "end device timeout request", 12: "end device timeout response" # 0x0d - 0xff reserved }), # - Route Request Command - # # Command options (1 octet) ConditionalField(BitField("res1", 0, 1), lambda pkt: pkt.cmd_identifier in [1, 2]), ConditionalField(BitField("multicast", 0, 1), lambda pkt: pkt.cmd_identifier in [1, 2]), ConditionalField(BitField("dest_addr_bit", 0, 1), lambda pkt: pkt.cmd_identifier == 1), # noqa: E501 ConditionalField( BitEnumField("many_to_one", 0, 2, { 0: "not_m2one", 1: "m2one_support_rrt", 2: "m2one_no_support_rrt", 3: "reserved"} # noqa: E501 ), lambda pkt: pkt.cmd_identifier == 1), ConditionalField(BitField("res2", 0, 3), lambda pkt: pkt.cmd_identifier == 1), # noqa: E501 # - Route Reply Command - # # Command options (1 octet) ConditionalField(BitField("responder_addr_bit", 0, 1), lambda pkt: pkt.cmd_identifier == 2), # noqa: E501 ConditionalField(BitField("originator_addr_bit", 0, 1), lambda pkt: pkt.cmd_identifier == 2), # noqa: E501 ConditionalField(BitField("res3", 0, 4), lambda pkt: pkt.cmd_identifier == 2), # noqa: E501 # Route request identifier (1 octet) ConditionalField(ByteField("route_request_identifier", 0), lambda pkt: pkt.cmd_identifier in [1, 2]), # noqa: E501 # Originator address (2 octets) ConditionalField(XLEShortField("originator_address", 0x0000), lambda pkt: pkt.cmd_identifier == 2), # noqa: E501 # Responder address (2 octets) ConditionalField(XLEShortField("responder_address", 0x0000), lambda pkt: pkt.cmd_identifier == 2), # noqa: E501 # - Network Status Command - # # Status code (1 octet) ConditionalField(ByteEnumField("status_code", 0, { 0x00: "No route available", 0x01: "Tree link failure", 0x02: "Non-tree link failure", 0x03: "Low battery level", 0x04: "No routing capacity", 0x05: "No indirect capacity", 0x06: "Indirect transaction expiry", 0x07: "Target device unavailable", 0x08: "Target address unallocated", 0x09: "Parent link failure", 0x0a: "Validate route", 0x0b: "Source route failure", 0x0c: "Many-to-one route failure", 0x0d: "Address conflict", 0x0e: "Verify addresses", 0x0f: "PAN identifier update", 0x10: "Network address update", 0x11: "Bad frame counter", 0x12: "Bad key sequence number", # 0x13 - 0xff Reserved }), lambda pkt: pkt.cmd_identifier == 3), # Destination address (2 octets) ConditionalField(XLEShortField("destination_address", 0x0000), lambda pkt: pkt.cmd_identifier in [1, 3]), # Path cost (1 octet) ConditionalField(ByteField("path_cost", 0), lambda pkt: pkt.cmd_identifier in [1, 2]), # noqa: E501 # Destination IEEE Address (0/8 octets), only present when dest_addr_bit has a value of 1 # noqa: E501 ConditionalField(dot15d4AddressField("ext_dst", 0, adjust=lambda pkt, x: 8), # noqa: E501 lambda pkt: (pkt.cmd_identifier == 1 and pkt.dest_addr_bit == 1)), # noqa: E501 # Originator IEEE address (0/8 octets) ConditionalField(dot15d4AddressField("originator_addr", 0, adjust=lambda pkt, x: 8), # noqa: E501 lambda pkt: (pkt.cmd_identifier == 2 and pkt.originator_addr_bit == 1)), # noqa: E501 # Responder IEEE address (0/8 octets) ConditionalField(dot15d4AddressField("responder_addr", 0, adjust=lambda pkt, x: 8), # noqa: E501 lambda pkt: (pkt.cmd_identifier == 2 and pkt.responder_addr_bit == 1)), # noqa: E501 # - Leave Command - # # Command options (1 octet) # Bit 7: Remove children ConditionalField(BitField("remove_children", 0, 1), lambda pkt: pkt.cmd_identifier == 4), # noqa: E501 # Bit 6: Request ConditionalField(BitField("request", 0, 1), lambda pkt: pkt.cmd_identifier == 4), # noqa: E501 # Bit 5: Rejoin ConditionalField(BitField("rejoin", 0, 1), lambda pkt: pkt.cmd_identifier == 4), # noqa: E501 # Bit 0 - 4: Reserved ConditionalField(BitField("res4", 0, 5), lambda pkt: pkt.cmd_identifier == 4), # noqa: E501 # - Route Record Command - # # Relay count (1 octet) ConditionalField(ByteField("rr_relay_count", 0), lambda pkt: pkt.cmd_identifier == 5), # noqa: E501 # Relay list (variable in length) ConditionalField( FieldListField("rr_relay_list", [], XLEShortField("", 0x0000), count_from=lambda pkt:pkt.rr_relay_count), # noqa: E501 lambda pkt:pkt.cmd_identifier == 5), # - Rejoin Request Command - # # Capability Information (1 octet) ConditionalField(BitField("allocate_address", 0, 1), lambda pkt:pkt.cmd_identifier == 6), # Allocate Address # noqa: E501 ConditionalField(BitField("security_capability", 0, 1), lambda pkt:pkt.cmd_identifier == 6), # Security Capability # noqa: E501 ConditionalField(BitField("reserved2", 0, 1), lambda pkt:pkt.cmd_identifier == 6), # bit 5 is reserved # noqa: E501 ConditionalField(BitField("reserved1", 0, 1), lambda pkt:pkt.cmd_identifier == 6), # bit 4 is reserved # noqa: E501 ConditionalField(BitField("receiver_on_when_idle", 0, 1), lambda pkt:pkt.cmd_identifier == 6), # Receiver On When Idle # noqa: E501 ConditionalField(BitField("power_source", 0, 1), lambda pkt:pkt.cmd_identifier == 6), # Power Source # noqa: E501 ConditionalField(BitField("device_type", 0, 1), lambda pkt:pkt.cmd_identifier == 6), # Device Type # noqa: E501 ConditionalField(BitField("alternate_pan_coordinator", 0, 1), lambda pkt:pkt.cmd_identifier == 6), # Alternate PAN Coordinator # noqa: E501 # - Rejoin Response Command - # # Network address (2 octets) ConditionalField(XLEShortField("network_address", 0xFFFF), lambda pkt:pkt.cmd_identifier == 7), # noqa: E501 # Rejoin status (1 octet) ConditionalField(ByteField("rejoin_status", 0), lambda pkt:pkt.cmd_identifier == 7), # noqa: E501 # - Link Status Command - # # Command options (1 octet) ConditionalField(BitField("res5", 0, 1), lambda pkt:pkt.cmd_identifier == 8), # Reserved # noqa: E501 ConditionalField(BitField("last_frame", 0, 1), lambda pkt:pkt.cmd_identifier == 8), # Last frame # noqa: E501 ConditionalField(BitField("first_frame", 0, 1), lambda pkt:pkt.cmd_identifier == 8), # First frame # noqa: E501 ConditionalField(BitField("entry_count", 0, 5), lambda pkt:pkt.cmd_identifier == 8), # Entry count # noqa: E501 # Link status list (variable size) ConditionalField( PacketListField("link_status_list", [], LinkStatusEntry, count_from=lambda pkt:pkt.entry_count), # noqa: E501 lambda pkt:pkt.cmd_identifier == 8), # - Network Report Command - # # Command options (1 octet) ConditionalField( BitEnumField("report_command_identifier", 0, 3, {0: "PAN identifier conflict"}), # 0x01 - 0x07 Reserved # noqa: E501 lambda pkt: pkt.cmd_identifier == 9), ConditionalField(BitField("report_information_count", 0, 5), lambda pkt: pkt.cmd_identifier == 9), # noqa: E501 # Report information (variable length) # Only present if we have a PAN Identifier Conflict Report ConditionalField( FieldListField("PAN_ID_conflict_report", [], XLEShortField("", 0x0000), # noqa: E501 count_from=lambda pkt:pkt.report_information_count), lambda pkt:(pkt.cmd_identifier == 9 and pkt.report_command_identifier == 0) # noqa: E501 ), # - Network Update Command - # # Command options (1 octet) ConditionalField( BitEnumField("update_command_identifier", 0, 3, {0: "PAN Identifier Update"}), # 0x01 - 0x07 Reserved # noqa: E501 lambda pkt: pkt.cmd_identifier == 10), ConditionalField(BitField("update_information_count", 0, 5), lambda pkt: pkt.cmd_identifier == 10), # noqa: E501 # EPID: Extended PAN ID (8 octets) ConditionalField( dot15d4AddressField("epid", 0, adjust=lambda pkt, x: 8), lambda pkt: pkt.cmd_identifier in [9, 10] ), # Update Id (1 octet) ConditionalField(ByteField("update_id", 0), lambda pkt: pkt.cmd_identifier == 10), # noqa: E501 # Update Information (Variable) # Only present if we have a PAN Identifier Update # New PAN ID (2 octets) ConditionalField(XLEShortField("new_PAN_ID", 0x0000), lambda pkt: (pkt.cmd_identifier == 10 and pkt.update_command_identifier == 0)), # noqa: E501 # - End Device Timeout Request Command - # # Requested Timeout (1 octet) ConditionalField( ByteEnumField("req_timeout", 3, { 0: "10 seconds", 1: "2 minutes", 2: "4 minutes", 3: "8 minutes", 4: "16 minutes", 5: "32 minutes", 6: "64 minutes", 7: "128 minutes", 8: "256 minutes", 9: "512 minutes", 10: "1024 minutes", 11: "2048 minutes", 12: "4096 minutes", 13: "8192 minutes", 14: "16384 minutes" }), lambda pkt: pkt.cmd_identifier == 11), # End Device Configuration (1 octet) ConditionalField( ByteField("ed_conf", 0), lambda pkt: pkt.cmd_identifier == 11), # - End Device Timeout Response Command - # # Status (1 octet) ConditionalField( ByteEnumField("status", 0, { 0: "Success", 1: "Incorrect Value" }), lambda pkt: pkt.cmd_identifier == 12), # Parent Information (1 octet) ConditionalField( BitField("res6", 0, 6), lambda pkt: pkt.cmd_identifier == 12), ConditionalField( BitField("ed_timeout_req_keepalive", 0, 1), lambda pkt: pkt.cmd_identifier == 12), ConditionalField( BitField("mac_data_poll_keepalive", 0, 1), lambda pkt: pkt.cmd_identifier == 12) # StrField("data", ""), ]
class VlanTaggingOperation(Packet): name = "VlanTaggingOperation" fields_desc = [ BitField("filter_outer_priority", 0, 4), BitField("filter_outer_vid", 0, 13), BitField("filter_outer_tpid_de", 0, 3), BitField("pad1", 0, 12), BitField("filter_inner_priority", 0, 4), BitField("filter_inner_vid", 0, 13), BitField("filter_inner_tpid_de", 0, 3), BitField("pad2", 0, 8), BitField("filter_ether_type", 0, 4), BitField("treatment_tags_to_remove", 0, 2), BitField("pad3", 0, 10), BitField("treatment_outer_priority", 0, 4), BitField("treatment_outer_vid", 0, 13), BitField("treatment_outer_tpid_de", 0, 3), BitField("pad4", 0, 12), BitField("treatment_inner_priority", 0, 4), BitField("treatment_inner_vid", 0, 13), BitField("treatment_inner_tpid_de", 0, 3), ] def to_json(self): return json.dumps(self.fields, separators=(',', ':')) @staticmethod def json_from_value(value): bits = BitArray(hex=hexlify(value)) temp = VlanTaggingOperation( filter_outer_priority=bits[0:4].uint, # 4 <-size filter_outer_vid=bits[4:17].uint, # 13 filter_outer_tpid_de=bits[17:20].uint, # 3 # pad 12 filter_inner_priority=bits[32:36].uint, # 4 filter_inner_vid=bits[36:49].uint, # 13 filter_inner_tpid_de=bits[49:52].uint, # 3 # pad 8 filter_ether_type=bits[60:64].uint, # 4 treatment_tags_to_remove=bits[64:66].uint, # 2 # pad 10 treatment_outer_priority=bits[76:80].uint, # 4 treatment_outer_vid=bits[80:93].uint, # 13 treatment_outer_tpid_de=bits[93:96].uint, # 3 # pad 12 treatment_inner_priority=bits[108:112].uint, # 4 treatment_inner_vid=bits[112:125].uint, # 13 treatment_inner_tpid_de=bits[125:128].uint, # 3 ) return json.dumps(temp.fields, separators=(',', ':'))
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 DNS(Packet): name = "DNS" fields_desc = [ ConditionalField(ShortField("length", None), lambda p: isinstance(p.underlayer, TCP)), ShortField("id", 0), BitField("qr", 0, 1), BitEnumField("opcode", 0, 4, { 0: "QUERY", 1: "IQUERY", 2: "STATUS" }), BitField("aa", 0, 1), BitField("tc", 0, 1), BitField("rd", 1, 1), BitField("ra", 0, 1), BitField("z", 0, 1), # AD and CD bits are defined in RFC 2535 BitField("ad", 0, 1), # Authentic Data BitField("cd", 0, 1), # Checking Disabled BitEnumField( "rcode", 0, 4, { 0: "ok", 1: "format-error", 2: "server-failure", 3: "name-error", 4: "not-implemented", 5: "refused" }), DNSRRCountField("qdcount", None, "qd"), DNSRRCountField("ancount", None, "an"), DNSRRCountField("nscount", None, "ns"), DNSRRCountField("arcount", None, "ar"), DNSQRField("qd", "qdcount"), DNSRRField("an", "ancount"), DNSRRField("ns", "nscount"), DNSRRField("ar", "arcount", 0), ] def answers(self, other): return (isinstance(other, DNS) and self.id == other.id and self.qr == 1 and other.qr == 0) def mysummary(self): type = ["Qry", "Ans"][self.qr] name = "" if self.qr: type = "Ans" if self.ancount > 0 and isinstance(self.an, DNSRR): name = ' "%s"' % self.an.rdata else: type = "Qry" if self.qdcount > 0 and isinstance(self.qd, DNSQR): name = ' "%s"' % self.qd.qname return 'DNS %s%s ' % (type, name) def post_build(self, pkt, pay): if isinstance(self.underlayer, TCP) and self.length is None: pkt = struct.pack("!H", len(pkt) - 2) + pkt[2:] return pkt + pay def compress(self): """Return the compressed DNS packet (using `dns_compress()`""" return dns_compress(self)
class IEC104_IE_CP56TIME2A(IEC104_IE_CommonQualityFlags): """ CP56Time2a - dual time, 7 octets (milliseconds, valid flag, minutes, hours, summer-time-indicator, day of month, weekday, years) well, someone should have talked to them about the idea of the unix timestamp... EN 60870-5-101:2003, sec. 7.2.6.18 (p. 50) time representation format according IEC 60870-5-4:1993, sec. 6.8, p. 23 """ WEEK_DAY_FLAG_UNUSED = 0 WEEK_DAY_FLAG_MONDAY = 1 WEEK_DAY_FLAG_TUESDAY = 2 WEEK_DAY_FLAG_WEDNESDAY = 3 WEEK_DAY_FLAG_THURSDAY = 4 WEEK_DAY_FLAG_FRIDAY = 5 WEEK_DAY_FLAG_SATURDAY = 6 WEEK_DAY_FLAG_SUNDAY = 7 WEEK_DAY_FLAGS = { WEEK_DAY_FLAG_UNUSED: 'unused', WEEK_DAY_FLAG_MONDAY: 'Monday', WEEK_DAY_FLAG_TUESDAY: 'Tuesday', WEEK_DAY_FLAG_WEDNESDAY: 'Wednesday', WEEK_DAY_FLAG_THURSDAY: 'Thursday', WEEK_DAY_FLAG_FRIDAY: 'Friday', WEEK_DAY_FLAG_SATURDAY: 'Saturday', WEEK_DAY_FLAG_SUNDAY: 'Sunday' } GEN_FLAG_REALTIME = 0 GEN_FLAG_SUBSTITUTED_TIME = 1 GEN_FLAGS = { GEN_FLAG_REALTIME: 'real time', GEN_FLAG_SUBSTITUTED_TIME: 'substituted time' } SU_FLAG_NORMAL_TIME = 0 SU_FLAG_SUMMER_TIME = 1 SU_FLAGS = { SU_FLAG_NORMAL_TIME: 'normal time', SU_FLAG_SUMMER_TIME: 'summer time' } informantion_element_fields = [ LEShortField('sec_milli', 0), BitEnumField('iv', 0, 1, IEC104_IE_CommonQualityFlags.IV_FLAGS), BitEnumField('gen', 0, 1, GEN_FLAGS), # only valid in monitor direction ToDo: special treatment needed? BitField('minutes', 0, 6), BitEnumField('su', 0, 1, SU_FLAGS), BitField('reserved_2', 0, 2), BitField('hours', 0, 5), BitEnumField('weekday', 0, 3, WEEK_DAY_FLAGS), BitField('day-of-month', 0, 5), BitField('reserved_3', 0, 4), BitField('month', 0, 4), BitField('reserved_4', 0, 1), BitField('year', 0, 7), ]
class Dot11(Packet): name = "802.11" fields_desc = [ BitField("subtype", 0, 4), BitEnumField("type", 0, 2, ["Management", "Control", "Data", "Reserved"]), BitField("proto", 0, 2), FlagsField("FCfield", 0, 8, ["to-DS", "from-DS", "MF", "retry", "pw-mgt", "MD", "protected", "order"]), ShortField("ID", 0), MACField("addr1", ETHER_ANY), ConditionalField( MACField("addr2", ETHER_ANY), lambda pkt: (pkt.type != 1 or pkt.subtype in [0x8, 0x9, 0xa, 0xb, 0xe, 0xf]), ), ConditionalField( MACField("addr3", ETHER_ANY), lambda pkt: pkt.type in [0, 2], ), ConditionalField(LEShortField("SC", 0), lambda pkt: pkt.type != 1), ConditionalField( MACField("addr4", ETHER_ANY), lambda pkt: (pkt.type == 2 and pkt.FCfield & 3 == 3), # from-DS+to-DS ) ] def mysummary(self): # Supports both Dot11 and Dot11FCS return self.sprintf("802.11 %%%s.type%% %%%s.subtype%% %%%s.addr2%% > %%%s.addr1%%" % ((self.__class__.__name__,) * 4)) # noqa: E501 def guess_payload_class(self, payload): if self.type == 0x02 and (0x08 <= self.subtype <= 0xF and self.subtype != 0xD): # noqa: E501 return Dot11QoS elif self.FCfield.protected: # When a frame is handled by encryption, the Protected Frame bit # (previously called WEP bit) is set to 1, and the Frame Body # begins with the appropriate cryptographic header. return Dot11Encrypted else: return Packet.guess_payload_class(self, payload) def answers(self, other): if isinstance(other, Dot11): if self.type == 0: # management if self.addr1.lower() != other.addr2.lower(): # check resp DA w/ req SA # noqa: E501 return 0 if (other.subtype, self.subtype) in [(0, 1), (2, 3), (4, 5)]: return 1 if self.subtype == other.subtype == 11: # auth return self.payload.answers(other.payload) elif self.type == 1: # control return 0 elif self.type == 2: # data return self.payload.answers(other.payload) elif self.type == 3: # reserved return 0 return 0 def unwep(self, key=None, warn=1): if self.FCfield & 0x40 == 0: if warn: warning("No WEP to remove") return if isinstance(self.payload.payload, NoPayload): if key or conf.wepkey: self.payload.decrypt(key) if isinstance(self.payload.payload, NoPayload): if warn: warning("Dot11 can't be decrypted. Check conf.wepkey.") return self.FCfield &= ~0x40 self.payload = self.payload.payload
class RadioTap(Packet): name = "RadioTap" 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( ScalingField("dBm_AntSignal", 0, offset=-256, unit="dBm", fmt="B")), lambda pkt: pkt.present and pkt.present.dBm_AntSignal), # dBm_AntNoise ConditionalField( _RadiotapReversePadField( ScalingField("dBm_AntNoise", 0, offset=-256, unit="dBm", fmt="B")), 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: 0) ] def guess_payload_class(self, payload): if self.present and self.present.Flags and self.Flags.FCS: return Dot11FCS return Dot11 def post_dissect(self, s): length = max(self.len - len(self.original) + len(s), 0) self.notdecoded = s[:length] return s[length:] 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 Dot15d4Beacon(Packet): name = "802.15.4 Beacon" fields_desc = [ # Superframe spec field: BitField("sf_sforder", 15, 4), # not used by ZigBee BitField("sf_beaconorder", 15, 4), # not used by ZigBee BitEnumField("sf_assocpermit", 0, 1, [False, True]), BitEnumField("sf_pancoord", 0, 1, [False, True]), BitField("sf_reserved", 0, 1), # not used by ZigBee BitEnumField("sf_battlifeextend", 0, 1, [False, True]), # not used by ZigBee # noqa: E501 BitField("sf_finalcapslot", 15, 4), # not used by ZigBee # GTS Fields # GTS Specification (1 byte) BitEnumField("gts_spec_permit", 1, 1, [False, True]), # GTS spec bit 7, true=1 iff PAN cord is accepting GTS requests # noqa: E501 BitField("gts_spec_reserved", 0, 4), # GTS spec bits 3-6 BitField("gts_spec_desccount", 0, 3), # GTS spec bits 0-2 # GTS Directions (0 or 1 byte) ConditionalField(BitField("gts_dir_reserved", 0, 1), lambda pkt:pkt.getfieldval("gts_spec_desccount") != 0), # noqa: E501 ConditionalField(BitField("gts_dir_mask", 0, 7), lambda pkt:pkt.getfieldval("gts_spec_desccount") != 0), # noqa: E501 # GTS List (variable size) # TODO add a Packet/FieldListField tied to 3bytes per count in gts_spec_desccount # noqa: E501 # Pending Address Fields: # Pending Address Specification (1 byte) BitField("pa_reserved_1", 0, 1), BitField("pa_num_long", 0, 3), # number of long addresses pending BitField("pa_reserved_2", 0, 1), BitField("pa_num_short", 0, 3), # number of short addresses pending # Address List (var length) FieldListField("pa_short_addresses", [], XLEShortField("", 0x0000), count_from=lambda pkt: pkt.pa_num_short), FieldListField("pa_long_addresses", [], LEEUI64Field("", 0), count_from=lambda pkt: pkt.pa_num_long), # TODO beacon payload ] def mysummary(self): return self.sprintf( "802.15.4 Beacon " "( %Dot15d4Beacon.src_panid%:%Dot15d4Beacon.src_addr% " "assocPermit %Dot15d4Beacon.sf_assocpermit% " "panCoord %Dot15d4Beacon.sf_pancoord%)")
def addfield(self, pkt, s, val): self.size = self.length_f(pkt) return BitField.addfield(self, pkt, s, val)
class NBNSNodeStatusResponseEnd(Packet): name = "NBNS Node Status Response" fields_desc = [ SourceMACField("MAC_ADDRESS"), BitField("STATISTICS", 0, 57 * 8) ]
class Dot15d4(Packet): FRAME_TYPE = { 0b000: "Beacon", 0b001: "Data", 0b010: "Ack", 0b011: "Command", 0b101: "Multipurpose", 0b110: "Fragment", 0b111: "Extended" } FRAME_VERSION = { 0b00: "2003", 0b01: "2006", 0b10: "2015" } name = "802.15.4" fields_desc = [ # Frame control BitField("fcf_reserved_1", 0, 1), BitEnumField("fcf_panidcompress", 0, 1, [False, True]), BitEnumField("fcf_ackreq", 0, 1, [False, True]), BitEnumField("fcf_pending", 0, 1, [False, True]), BitEnumField("fcf_security", 0, 1, [False, True]), Emph(BitEnumField("fcf_frametype", 0, 3, FRAME_TYPE)), AddressingModeField("fcf_srcaddrmode", 0, "src_addr"), BitEnumField("fcf_framever", 0, 2, FRAME_VERSION), AddressingModeField("fcf_destaddrmode", 2, "dest_addr"), BitField("fcf_reserved_2", 0, 2), # Sequence number Emph(ByteField("seqnum", 1)), # Addressing fields ConditionalField( XLEShortField("dest_panid", 0xFFFF), lambda pkt: panids_present(pkt)[0]), MultipleTypeField( [(ShortAddressField("dest_addr", 0xFFFF), lambda pkt: pkt.fcf_destaddrmode == 0b10), (LEEUI64Field("dest_addr", 0xFFFFFFFFFFFFFFFF), lambda pkt: pkt.fcf_destaddrmode == 0b11)], NoneField("dest_addr", 0xFFFF)), ConditionalField( XLEShortField("src_panid", 0x0000), lambda pkt: panids_present(pkt)[1]), MultipleTypeField( [(ShortAddressField("src_addr", None), lambda pkt: pkt.fcf_srcaddrmode == 0b10), (LEEUI64Field("src_addr", None), lambda pkt: pkt.fcf_srcaddrmode == 0b11)], NoneField("src_addr", None)), # Security field ConditionalField( PacketField("aux_sec_header", Dot15d4AuxSecurityHeader(), Dot15d4AuxSecurityHeader), lambda pkt: pkt.fcf_security), ] def mysummary(self): return self.sprintf( "802.15.4 %Dot15d4.fcf_frametype% " "(ackreq=%Dot15d4.fcf_ackreq% " "%Dot15d4.fcf_destaddrmode% -> %Dot15d4.fcf_srcaddrmode% " "Seq#%Dot15d4.seqnum%)") def answers(self, other): if isinstance(other, Dot15d4): if self.fcf_frametype == 2: # ack # check for seqnum matching if self.seqnum != other.seqnum: return 0 # check that an ack was indeed requested elif other.fcf_ackreq == 1: return 1 return 0 def post_build(self, p, pay): # This just forces destaddrmode to None for Ack frames. if self.fcf_frametype == 2 and self.fcf_destaddrmode != 0: self.fcf_destaddrmode = 0 return p[:1] + \ chb((self.fcf_srcaddrmode << 6) + (self.fcf_framever << 4)) \ + p[2:] + pay else: return p + pay
class DutyCyclePL(Packet): name = "DutyCyclePL" fields_desc = [BitField("MaxDCycle", 0, 4)]
class LLDPDUSystemCapabilities(LLDPDU): """ ieee 802.1ab-2016 - sec. 8.5.8 / p. 31 """ fields_desc = [ BitEnumField('_type', 0x07, 7, LLDPDU.TYPES), BitFieldLenField('_length', 4, 9), BitField('reserved_5_available', 0, 1), BitField('reserved_4_available', 0, 1), BitField('reserved_3_available', 0, 1), BitField('reserved_2_available', 0, 1), BitField('reserved_1_available', 0, 1), BitField('two_port_mac_relay_available', 0, 1), BitField('s_vlan_component_available', 0, 1), BitField('c_vlan_component_available', 0, 1), BitField('station_only_available', 0, 1), BitField('docsis_cable_device_available', 0, 1), BitField('telephone_available', 0, 1), BitField('router_available', 0, 1), BitField('wlan_access_point_available', 0, 1), BitField('mac_bridge_available', 0, 1), BitField('repeater_available', 0, 1), BitField('other_available', 0, 1), BitField('reserved_5_enabled', 0, 1), BitField('reserved_4_enabled', 0, 1), BitField('reserved_3_enabled', 0, 1), BitField('reserved_2_enabled', 0, 1), BitField('reserved_1_enabled', 0, 1), BitField('two_port_mac_relay_enabled', 0, 1), BitField('s_vlan_component_enabled', 0, 1), BitField('c_vlan_component_enabled', 0, 1), BitField('station_only_enabled', 0, 1), BitField('docsis_cable_device_enabled', 0, 1), BitField('telephone_enabled', 0, 1), BitField('router_enabled', 0, 1), BitField('wlan_access_point_enabled', 0, 1), BitField('mac_bridge_enabled', 0, 1), BitField('repeater_enabled', 0, 1), BitField('other_enabled', 0, 1), ] def _check(self): """ run layer specific checks """ if conf.contribs['LLDP'].strict_mode() and self._length != 4: raise LLDPInvalidLengthField('length must be 4 - got ' '{}'.format(self._length))
class DevLoraWANversion(Packet): name = "DevLoraWANversion" fields_desc = [BitField("RFU", 0b0000, 4), BitField("Minor", 0b0001, 4)]
class ZCLPriceGetCurrentPrice(Packet): name = "Price Cluster: Get Current Price Command (Server: Received)" fields_desc = [ BitField("reserved", 0, 7), BitField("Requestor_Rx_On_When_Idle", 0, 1), ]
class ADRparam(Packet): name = "ADRparam" fields_desc = [ BitField("Limit_exp", 0b0000, 4), BitField("Delay_exp", 0b0000, 4) ]
class LoWPANUncompressedIPv6(Packet): name = "6LoWPAN Uncompressed IPv6" fields_desc = [BitField("_type", 0x0, 8)] def default_payload_class(self, pay): return IPv6
class RejoinParamSetupReq(Packet): name = "RejoinParamSetupReq" fields_desc = [BitField("MaxTimeN", 0, 4), BitField("MaxCountN", 0, 4)]
def addfield(self, pkt, s, val): self.size = self.length_f(pkt) return BitField.addfield(self, pkt, s, val)
class RejoinParamSetupAns(Packet): name = "RejoinParamSetupAns" fields_desc = [BitField("RFU", 0, 7), BitField("TimeOK", 0, 1)]
class LoWPAN_IPHC(Packet): """6LoWPAN IPv6 header compressed packets It follows the implementation of draft-ietf-6lowpan-hc-15. """ # the LOWPAN_IPHC encoding utilizes 13 bits, 5 dispatch type name = "LoWPAN IP Header Compression Packet" _address_modes = ["Unspecified", "1", "16-bits inline", "Compressed"] _state_mode = ["Stateless", "Stateful"] fields_desc = [ # dispatch BitField("_reserved", 0x03, 3), BitField("tf", 0x0, 2), BitEnumField("nh", 0x0, 1, ["Inline", "Compressed"]), BitField("hlim", 0x0, 2), BitEnumField("cid", 0x0, 1, [False, True]), BitEnumField("sac", 0x0, 1, _state_mode), BitEnumField("sam", 0x0, 2, _address_modes), BitEnumField("m", 0x0, 1, [False, True]), BitEnumField("dac", 0x0, 1, _state_mode), BitEnumField("dam", 0x0, 2, _address_modes), ConditionalField( ByteField("_contextIdentifierExtension", 0x0), lambda pkt: pkt.cid == 0x1 ), # TODO: THIS IS WRONG!!!!! BitVarSizeField("tc_ecn", 0, calculate_length=lambda pkt: _tf_last_attempt(pkt)[0]), # noqa: E501 BitVarSizeField("tc_dscp", 0, calculate_length=lambda pkt: _tf_last_attempt(pkt)[1]), # noqa: E501 BitVarSizeField("_padd", 0, calculate_length=lambda pkt: _tf_last_attempt(pkt)[2]), # noqa: E501 BitVarSizeField("flowlabel", 0, calculate_length=lambda pkt: _tf_last_attempt(pkt)[3]), # noqa: E501 # NH ConditionalField( ByteField("_nhField", 0x0), lambda pkt: not pkt.nh ), # HLIM: Hop Limit: if it's 0 ConditionalField( ByteField("_hopLimit", 0x0), lambda pkt: pkt.hlim == 0x0 ), IP6FieldLenField("sourceAddr", "::", 0, length_of=source_addr_mode2), IP6FieldLenField("destinyAddr", "::", 0, length_of=destiny_addr_mode), # problem when it's 0 # noqa: E501 # LoWPAN_UDP Header Compression ######################################## # noqa: E501 # TODO: IMPROVE!!!!! ConditionalField( FlagsField("header_compression", 0, 8, ["A", "B", "C", "D", "E", "C", "PS", "PD"]), # noqa: E501 lambda pkt: pkt.nh ), ConditionalField( BitFieldLenField("udpSourcePort", 0x0, 16, length_of=lambda pkt: nhc_port(pkt)[0]), # noqa: E501 # ShortField("udpSourcePort", 0x0), lambda pkt: pkt.nh and pkt.header_compression & 0x2 == 0x0 ), ConditionalField( BitFieldLenField("udpDestinyPort", 0x0, 16, length_of=lambda pkt: nhc_port(pkt)[1]), # noqa: E501 lambda pkt: pkt.nh and pkt.header_compression & 0x1 == 0x0 ), ConditionalField( XShortField("udpChecksum", 0x0), lambda pkt: pkt.nh and pkt.header_compression & 0x4 == 0x0 ), ] def post_dissect(self, data): """dissect the IPv6 package compressed into this IPHC packet. The packet payload needs to be decompressed and depending on the arguments, several conversions should be done. """ # uncompress payload packet = IPv6() packet.version = IPHC_DEFAULT_VERSION packet.tc, packet.fl = self._getTrafficClassAndFlowLabel() if not self.nh: packet.nh = self._nhField # HLIM: Hop Limit if self.hlim == 0: packet.hlim = self._hopLimit elif self.hlim == 0x1: packet.hlim = 1 elif self.hlim == 0x2: packet.hlim = 64 else: packet.hlim = 255 # TODO: Payload length can be inferred from lower layers from either the # noqa: E501 # 6LoWPAN Fragmentation header or the IEEE802.15.4 header packet.src = self.decompressSourceAddr(packet) packet.dst = self.decompressDestinyAddr(packet) if self.nh == 1: # The Next Header field is compressed and the next header is # encoded using LOWPAN_NHC packet.nh = 0x11 # UDP udp = UDP() if self.header_compression and \ self.header_compression & 0x4 == 0x0: udp.chksum = self.udpChecksum s, d = nhc_port(self) if s == 16: udp.sport = self.udpSourcePort elif s == 8: udp.sport = 0xF000 + s elif s == 4: udp.sport = 0xF0B0 + s if d == 16: udp.dport = self.udpDestinyPort elif d == 8: udp.dport = 0xF000 + d elif d == 4: udp.dport = 0xF0B0 + d packet.payload = udp / data data = raw(packet) # else self.nh == 0 not necessary elif self._nhField & 0xE0 == 0xE0: # IPv6 Extension Header Decompression # noqa: E501 warning('Unimplemented: IPv6 Extension Header decompression') # noqa: E501 packet.payload = conf.raw_layer(data) data = raw(packet) else: packet.payload = conf.raw_layer(data) data = raw(packet) return Packet.post_dissect(self, data) def decompressDestinyAddr(self, packet): try: tmp_ip = inet_pton(socket.AF_INET6, self.destinyAddr) except socket.error: tmp_ip = b"\x00" * 16 if self.m == 0 and self.dac == 0: if self.dam == 0: pass elif self.dam == 1: tmp_ip = LINK_LOCAL_PREFIX[0:8] + tmp_ip[-8:] elif self.dam == 2: tmp_ip = LINK_LOCAL_PREFIX[0:8] + b"\x00\x00\x00\xff\xfe\x00" + tmp_ip[-2:] # noqa: E501 elif self.dam == 3: # TODO May need some extra changes, we are copying # (self.m == 0 and self.dac == 1) tmp_ip = _extract_dot15d4address(self, source=False) elif self.m == 0 and self.dac == 1: if self.dam == 0: raise Exception('Reserved') elif self.dam == 0x3: tmp_ip = _extract_dot15d4address(self, source=False) elif self.dam not in [0x1, 0x2]: warning("Unknown destiny address compression mode !") elif self.m == 1 and self.dac == 0: if self.dam == 0: raise Exception("unimplemented") elif self.dam == 1: tmp = b"\xff" + chb(tmp_ip[16 - destiny_addr_mode(self)]) tmp_ip = tmp + b"\x00" * 9 + tmp_ip[-5:] elif self.dam == 2: tmp = b"\xff" + chb(tmp_ip[16 - destiny_addr_mode(self)]) tmp_ip = tmp + b"\x00" * 11 + tmp_ip[-3:] else: # self.dam == 3: tmp_ip = b"\xff\x02" + b"\x00" * 13 + tmp_ip[-1:] elif self.m == 1 and self.dac == 1: if self.dam == 0x0: raise Exception("Unimplemented: I didn't understand the 6lowpan specification") # noqa: E501 else: # all the others values raise Exception("Reserved value by specification.") self.destinyAddr = inet_ntop(socket.AF_INET6, tmp_ip) return self.destinyAddr def compressSourceAddr(self, ipv6): tmp_ip = inet_pton(socket.AF_INET6, ipv6.src) if self.sac == 0: if self.sam == 0x0: tmp_ip = tmp_ip elif self.sam == 0x1: tmp_ip = tmp_ip[8:16] elif self.sam == 0x2: tmp_ip = tmp_ip[14:16] else: # self.sam == 0x3: pass else: # self.sac == 1 if self.sam == 0x0: tmp_ip = b"\x00" * 16 elif self.sam == 0x1: tmp_ip = tmp_ip[8:16] elif self.sam == 0x2: tmp_ip = tmp_ip[14:16] self.sourceAddr = inet_ntop(socket.AF_INET6, b"\x00" * (16 - len(tmp_ip)) + tmp_ip) # noqa: E501 return self.sourceAddr def compressDestinyAddr(self, ipv6): tmp_ip = inet_pton(socket.AF_INET6, ipv6.dst) if self.m == 0 and self.dac == 0: if self.dam == 0x0: tmp_ip = tmp_ip elif self.dam == 0x1: tmp_ip = b"\x00" * 8 + tmp_ip[8:16] elif self.dam == 0x2: tmp_ip = b"\x00" * 14 + tmp_ip[14:16] elif self.m == 0 and self.dac == 1: if self.dam == 0x1: tmp_ip = b"\x00" * 8 + tmp_ip[8:16] elif self.dam == 0x2: tmp_ip = b"\x00" * 14 + tmp_ip[14:16] elif self.m == 1 and self.dac == 0: if self.dam == 0x1: tmp_ip = b"\x00" * 10 + tmp_ip[1:2] + tmp_ip[11:16] elif self.dam == 0x2: tmp_ip = b"\x00" * 12 + tmp_ip[1:2] + tmp_ip[13:16] elif self.dam == 0x3: tmp_ip = b"\x00" * 15 + tmp_ip[15:16] elif self.m == 1 and self.dac == 1: raise Exception('Unimplemented') self.destinyAddr = inet_ntop(socket.AF_INET6, tmp_ip) def decompressSourceAddr(self, packet): try: tmp_ip = inet_pton(socket.AF_INET6, self.sourceAddr) except socket.error: tmp_ip = b"\x00" * 16 if self.sac == 0: if self.sam == 0x0: pass elif self.sam == 0x1: tmp_ip = LINK_LOCAL_PREFIX[0:8] + tmp_ip[16 - source_addr_mode2(self):16] # noqa: E501 elif self.sam == 0x2: tmp = LINK_LOCAL_PREFIX[0:8] + b"\x00\x00\x00\xff\xfe\x00" tmp_ip = tmp + tmp_ip[16 - source_addr_mode2(self):16] elif self.sam == 0x3: # EXTRACT ADDRESS FROM Dot15d4 tmp_ip = _extract_dot15d4address(self, source=True) else: warning("Unknown source address compression mode !") else: # self.sac == 1: if self.sam == 0x0: pass elif self.sam == 0x2: # TODO: take context IID tmp = LINK_LOCAL_PREFIX[0:8] + b"\x00\x00\x00\xff\xfe\x00" tmp_ip = tmp + tmp_ip[16 - source_addr_mode2(self):16] elif self.sam == 0x3: tmp_ip = LINK_LOCAL_PREFIX[0:8] + b"\x00" * 8 # TODO: CONTEXT ID # noqa: E501 else: raise Exception('Unimplemented') self.sourceAddr = inet_ntop(socket.AF_INET6, tmp_ip) return self.sourceAddr def guess_payload_class(self, payload): if self.underlayer and isinstance(self.underlayer, (LoWPANFragmentationFirst, LoWPANFragmentationSubsequent)): # noqa: E501 return Raw return IPv6 def do_build(self): if not isinstance(self.payload, IPv6): return Packet.do_build(self) ipv6 = self.payload self._reserved = 0x03 # NEW COMPRESSION TECHNIQUE! # a ) Compression Techniques # 1. Set Traffic Class if self.tf == 0x0: self.tc_ecn = ipv6.tc >> 6 self.tc_dscp = ipv6.tc & 0x3F self.flowlabel = ipv6.fl elif self.tf == 0x1: self.tc_ecn = ipv6.tc >> 6 self.flowlabel = ipv6.fl elif self.tf == 0x2: self.tc_ecn = ipv6.tc >> 6 self.tc_dscp = ipv6.tc & 0x3F else: # self.tf == 0x3: pass # no field is set # 2. Next Header if self.nh == 0x0: self.nh = 0 # ipv6.nh elif self.nh == 0x1: self.nh = 0 # disable compression # The Next Header field is compressed and the next header is encoded using LOWPAN_NHC, which is discussed in Section 4.1. # noqa: E501 warning('Next header compression is not implemented yet ! Will be ignored') # noqa: E501 # 3. HLim if self.hlim == 0x0: self._hopLimit = ipv6.hlim else: # if hlim is 1, 2 or 3, there are nothing to do! pass # 4. Context (which context to use...) if self.cid == 0x0: pass else: # TODO: Context Unimplemented yet in my class self._contextIdentifierExtension = 0 # 5. Compress Source Addr self.compressSourceAddr(ipv6) self.compressDestinyAddr(ipv6) return Packet.do_build(self) def do_build_payload(self): if self.header_compression and\ self.header_compression & 240 == 240: # TODO: UDP header IMPROVE return raw(self.payload)[40 + 16:] else: return raw(self.payload)[40:] def _getTrafficClassAndFlowLabel(self): """Page 6, draft feb 2011 """ if self.tf == 0x0: return (self.tc_ecn << 6) + self.tc_dscp, self.flowlabel elif self.tf == 0x1: return (self.tc_ecn << 6), self.flowlabel elif self.tf == 0x2: return (self.tc_ecn << 6) + self.tc_dscp, 0 else: return 0, 0
class PPP_LCP_ACCM_Option(PPP_LCP_Option): fields_desc = [ ByteEnumField("type", 2, _PPP_lcp_optiontypes), FieldLenField("len", 6, fmt="B"), BitField("accm", 0x00000000, 32) ]
class MKASAKUseParamSet(MKAParamSet): """ SAK Use Parameter Set (802.1X-2010, section 11.11). """ #________________________________________________________________________ # # IEEE 802.1X-2010 standard # Section 11.11 #________________________________________________________________________ # name = "SAK Use Parameter Set" fields_desc = [ ByteEnumField("param_set_type", 3, _parameter_set_types), BitField("latest_key_an", 0, 2), BitField("latest_key_tx", 0, 1), BitField("latest_key_rx", 0, 1), BitField("old_key_an", 0, 2), BitField("old_key_tx", 0, 1), BitField("old_key_rx", 0, 1), BitField("plain_tx", 0, 1), BitField("plain_rx", 0, 1), BitField("X", 0, 1), BitField("delay_protect", 0, 1), BitField("param_set_body_len", 0, 12), XStrFixedLenField("latest_key_key_server_member_id", "", length=12), XStrFixedLenField("latest_key_key_number", "", length=4), XStrFixedLenField("latest_key_lowest_acceptable_pn", "", length=4), XStrFixedLenField("old_key_key_server_member_id", "", length=12), XStrFixedLenField("old_key_key_number", "", length=4), XStrFixedLenField("old_key_lowest_acceptable_pn", "", length=4) ]
class IE_Bearer_QoS(gtp.IE_Base): name = "IE Bearer Quality of Service" fields_desc = [ ByteEnumField("ietype", 80, IEType), ShortField("length", None), BitField("CR_flag", 0, 4), BitField("instance", 0, 4), BitField("SPARE", 0, 1), BitField("PCI", 0, 1), BitField("PriorityLevel", 0, 4), BitField("SPARE", 0, 1), BitField("PVI", 0, 1), ByteField("QCI", 0), BitField("MaxBitRateForUplink", 0, 40), BitField("MaxBitRateForDownlink", 0, 40), BitField("GuaranteedBitRateForUplink", 0, 40), BitField("GuaranteedBitRateForDownlink", 0, 40) ]
def __init__(self, name, default, calculate_length=None): BitField.__init__(self, name, default, 0) self.length_f = calculate_length
class IE_Indication(gtp.IE_Base): name = "IE Indication" fields_desc = [ ByteEnumField("ietype", 77, IEType), ShortField("length", None), BitField("CR_flag", 0, 4), BitField("instance", 0, 4), BitField("DAF", 0, 1), BitField("DTF", 0, 1), BitField("HI", 0, 1), BitField("DFI", 0, 1), BitField("OI", 0, 1), BitField("ISRSI", 0, 1), BitField("ISRAI", 0, 1), BitField("SGWCI", 0, 1), BitField("SQCI", 0, 1), BitField("UIMSI", 0, 1), BitField("CFSI", 0, 1), BitField("CRSI", 0, 1), BitField("PS", 0, 1), BitField("PT", 0, 1), BitField("SI", 0, 1), BitField("MSV", 0, 1), ConditionalField(BitField("RetLoc", 0, 1), lambda pkt: pkt.length > 2), ConditionalField(BitField("PBIC", 0, 1), lambda pkt: pkt.length > 2), ConditionalField(BitField("SRNI", 0, 1), lambda pkt: pkt.length > 2), ConditionalField(BitField("S6AF", 0, 1), lambda pkt: pkt.length > 2), ConditionalField(BitField("S4AF", 0, 1), lambda pkt: pkt.length > 2), ConditionalField(BitField("MBMDT", 0, 1), lambda pkt: pkt.length > 2), ConditionalField(BitField("ISRAU", 0, 1), lambda pkt: pkt.length > 2), ConditionalField(BitField("CCRSI", 0, 1), lambda pkt: pkt.length > 2), ConditionalField(BitField("CPRAI", 0, 1), lambda pkt: pkt.length > 3), ConditionalField(BitField("ARRL", 0, 1), lambda pkt: pkt.length > 3), ConditionalField(BitField("PPOFF", 0, 1), lambda pkt: pkt.length > 3), ConditionalField(BitField("PPON", 0, 1), lambda pkt: pkt.length > 3), ConditionalField(BitField("PPSI", 0, 1), lambda pkt: pkt.length > 3), ConditionalField(BitField("CSFBI", 0, 1), lambda pkt: pkt.length > 3), ConditionalField(BitField("CLII", 0, 1), lambda pkt: pkt.length > 3), ConditionalField(BitField("CPSR", 0, 1), lambda pkt: pkt.length > 3), ]
def getfield(self, pkt, s): self.size = self.length_f(pkt) return BitField.getfield(self, pkt, s)
class BFD(Packet): """ BFD protocol layer for scapy """ udp_dport = 3784 #: BFD destination port per RFC 5881 udp_dport_echo = 3785 # : BFD destination port for ECHO per RFC 5881 udp_sport_min = 49152 #: BFD source port min value per RFC 5881 udp_sport_max = 65535 #: BFD source port max value per RFC 5881 bfd_pkt_len = 24 # : length of BFD pkt without authentication section sha1_auth_len = 28 # : length of authentication section if SHA1 used name = "BFD" fields_desc = [ BitField("version", 1, 3), BitEnumField("diag", 0, 5, BFDDiagCode.desc_dict), BitEnumField("state", 0, 2, BFDState.desc_dict), FlagsField("flags", 0, 6, ['M', 'D', 'A', 'C', 'F', 'P']), XByteField("detect_mult", 0), BitField("length", bfd_pkt_len, 8), BitField("my_discriminator", 0, 32), BitField("your_discriminator", 0, 32), BitField("desired_min_tx_interval", 0, 32), BitField("required_min_rx_interval", 0, 32), BitField("required_min_echo_rx_interval", 0, 32), ConditionalField( BitEnumField("auth_type", 0, 8, BFDAuthType.desc_dict), bfd_is_auth_used), ConditionalField(BitField("auth_len", 0, 8), bfd_is_auth_used), ConditionalField(BitField("auth_key_id", 0, 8), bfd_is_auth_used), ConditionalField(BitField("auth_reserved", 0, 8), bfd_is_md5_or_sha1_used), ConditionalField(BitField("auth_seq_num", 0, 32), bfd_is_md5_or_sha1_used), ConditionalField(StrField("auth_key_hash", "0" * 16), bfd_is_md5_used), ConditionalField(StrField("auth_key_hash", "0" * 20), bfd_is_sha1_used), ] def mysummary(self): return self.sprintf("BFD(my_disc=%BFD.my_discriminator%," "your_disc=%BFD.your_discriminator%)")