class ReassocReq(pypacker.Packet): __hdr__ = ( ("dst", "6s", b"\x00" * 6), ("bssid", "6s", b"\x00" * 6), ("src", "6s", b"\x00" * 6), ("seq_frag", "H", 0), ("capa", "H", 0), ("interval", "H", 0), ("current_ap", "6s", b"\x00" * 6) ) dst_s = pypacker.get_property_mac("dst") bssid_s = pypacker.get_property_mac("bssid") src_s = pypacker.get_property_mac("src") def _get_seq(self): return (self.seq_frag & 0xFF) << 4 | (self.seq_frag >> 12) def _set_seq(self, val): self.seq_frag = (val & 0xF) << 12 | (val & 0xFF0) >> 4 | (self.seq_frag & 0x0F00) seq = property(_get_seq, _set_seq) def reverse_address(self): self.dst, self.src = self.src, self.dst
class Deauth(pypacker.Packet): __hdr__ = ( ("dst", "6s", b"\xFF" * 6), ("src", "6s", b"\x00" * 6), ("bssid", "6s", b"\xFF" * 6), ("seq_frag", "H", 0), ("reason", "H", 0x0700 ) # class 3 frame received from non associated client ) dst_s = pypacker.get_property_mac("dst") bssid_s = pypacker.get_property_mac("bssid") src_s = pypacker.get_property_mac("src") def _get_seq(self): return (self.seq_frag & 0xFF) << 4 | (self.seq_frag >> 12) def _set_seq(self, val): self.seq_frag = (val & 0xF) << 12 | (val & 0xFF0) >> 4 | ( self.seq_frag & 0x0F00) seq = property(_get_seq, _set_seq) def reverse_address(self): self.dst, self.src = self.src, self.dst
class AssocResp(pypacker.Packet): __hdr__ = ( ("dst", "6s", b"\x00" * 6), ("bssid", "6s", b"\x00" * 6), ("src", "6s", b"\x00" * 6), ("seq_frag", "H", 0), ("capa", "H", 0), ("status", "H", 0), ("aid", "H", 0), ("params", None, triggerlist.TriggerList) ) dst_s = pypacker.get_property_mac("dst") bssid_s = pypacker.get_property_mac("bssid") src_s = pypacker.get_property_mac("src") def _get_seq(self): return (self.seq_frag & 0xFF) << 4 | (self.seq_frag >> 12) def _set_seq(self, val): self.seq_frag = (val & 0xF) << 12 | (val & 0xFF0) >> 4 | (self.seq_frag & 0x0F00) seq = property(_get_seq, _set_seq) def _dissect(self, buf): self._init_triggerlist("params", buf[26:], IEEE80211._unpack_ies) return len(buf) def reverse_address(self): self.dst, self.src = self.src, self.dst
class Auth(pypacker.Packet): """Authentication request.""" __hdr__ = ( ("dst", "6s", b"\x00" * 6), ("src", "6s", b"\x00" * 6), ("bssid", "6s", b"\x00" * 6), ("seq_frag", "H", 0), ("algo", "H", 0), ("authseq", "H", 0x0100), ("status", "H", 0) ) dst_s = pypacker.get_property_mac("dst") bssid_s = pypacker.get_property_mac("bssid") src_s = pypacker.get_property_mac("src") def _get_seq(self): return (self.seq_frag & 0xFF) << 4 | (self.seq_frag >> 12) def _set_seq(self, val): self.seq_frag = (val & 0xF) << 12 | (val & 0xFF0) >> 4 | (self.seq_frag & 0x0F00) seq = property(_get_seq, _set_seq) def reverse_address(self): self.dst, self.src = self.src, self.dst
class RTS(pypacker.Packet): __hdr__ = (("dst", "6s", b"\x00" * 6), ("src", "6s", b"\x00" * 6)) dst_s = pypacker.get_property_mac("dst") src_s = pypacker.get_property_mac("src") def reverse_address(self): self.dst, self.src = self.src, self.dst
class BlockAck(pypacker.Packet): __hdr__ = (("dst", "6s", b"\x00" * 6), ("src", "6s", b"\x00" * 6), ("reqctrl", "H", 0), ("seq", "H", 0), ("bitmap", "Q", 0)) dst_s = pypacker.get_property_mac("dst") src_s = pypacker.get_property_mac("src") def reverse_address(self): self.dst, self.src = self.src, self.dst
class Action(pypacker.Packet): __hdr__ = ( ("dst", "6s", b"\x00" * 6), ("src", "6s", b"\x00" * 6), ("bssid", "6s", b"\x00" * 6), ("seq_frag", "H", 0), ("category", "B", 0), ("code", "B", 0) ) def _get_seq(self): return (self.seq_frag & 0xFF) << 4 | (self.seq_frag >> 12) def _set_seq(self, val): self.seq_frag = (val & 0xF) << 12 | (val & 0xFF0) >> 4 | (self.seq_frag & 0x0F00) seq = property(_get_seq, _set_seq) class BlockAckRequest(pypacker.Packet): __hdr__ = ( ("dialog", "B", 0), ("parameters", "H", 0), ("timeout", "H", 0), ("starting_seq", "H", 0), ) class BlockAckResponse(pypacker.Packet): __hdr__ = ( ("dialog", "B", 0), ("status_code", "H", 0), ("parameters", "H", 0), ("timeout", "H", 0), ) CATEGORY_BLOCK_ACK = 3 CODE_BLOCK_ACK_REQUEST = 0 CODE_BLOCK_ACK_RESPONSE = 1 dst_s = pypacker.get_property_mac("dst") src_s = pypacker.get_property_mac("src") bssid_s = pypacker.get_property_mac("bssid") def _dissect(self, buf): # logger.debug(">>>>>>>> ACTION!!!") # category: block ack, code: request or response self._init_handler(buf[20] * 4 + buf[21], buf[22:]) return 22 def reverse_address(self): self.dst, self.src = self.src, self.dst
class CMSlacParmCnf(Packet): __hdr__ = ( ("msoundtarget", "6s", b"\x00" * 6), ("numsounds", "B", 0), ("timeout", "B", 0), ("resptype", "B", 0), ("forwardingsta", "6s", b"\x00" * 6), ("apptype", "B", 0), ("sectype", "B", 0), ("runid", "Q", 0), # Only present if security type is 1 ("ciphersuite", "H", None)) msoundtarget_s = pypacker.get_property_mac("msoundtarget") forwardingsta_s = pypacker.get_property_mac("forwardingsta")
class CMSlacMatchReq(Packet): __hdr__ = (("apptype", "B", 0), ("sectype", "B", 0), ("mvflen", "H", 0), ("pevid", "17s", b"\x00" * 17), ("pevmac", "6s", b"\x00" * 6), ("evseid", "17s", b"\x00" * 17), ("evsemac", "6s", b"\x00" * 6), ("runid", "Q", 0), ("rsvd", "8s", b"\x00" * 8)) def _get_mvflen_be(self): return unpack_H(pack_H_le(self.mvflen))[0] def _set_mvflen_be(self, val): self.mvflen = unpack_H(pack_H_le(val))[0] mvflen_be = property(_get_mvflen_be, _set_mvflen_be) pevmac_s = pypacker.get_property_mac("pevmac") evsemac_s = pypacker.get_property_mac("evsemac")
class CMAttenCharRsp(Packet): __hdr__ = (("apptype", "B", 0), ("sectype", "B", 0), ("sourceaddr", "6s", b"\x00" * 6), ("runid", "Q", 0), ("sourceid", "17s", b"\x00" * 17), ("respid", "17s", b"\x00" * 17), ("result", "B", 0)) sourceaddr_s = pypacker.get_property_mac("sourceaddr")
class CMPKCSCertRsp(Packet): __hdr__ = ( ("targetmac", "6s", b"\x00" * 6), ("status", "B", 0), ("ciphersuitesize", "B", 0), # optional ("cipersuite", None, TriggerList)) targetmac_s = pypacker.get_property_mac("targetmac")
class ARP(pypacker.Packet): __hdr__ = ( ("hrd", "H", ARP_HRD_ETH), ("pro", "H", ARP_PRO_IP), ("hln", "B", 6), # hardware address length ("pln", "B", 4), # protocol address length ("op", "H", ARP_OP_REQUEST), ("sha", "6s", b"\x00" * 6), # sender mac ("spa", "4s", b"\x00" * 4), # sender ip ("tha", "6s", b"\x00" * 6), # target mac ("tpa", "4s", b"\x00" * 4) # target ip ) # convenient access sha_s = pypacker.get_property_mac("sha") spa_s = pypacker.get_property_ip4("spa") tha_s = pypacker.get_property_mac("tha") tpa_s = pypacker.get_property_ip4("tpa")
class CMSlacMatchCnf(Packet): __hdr__ = ( ("apptype", "B", 0), ("sectype", "B", 0), ("mvflen", "H", 0), ("pevid", "17s", b"\x00" * 17), ("pevmac", "6s", b"\x00" * 6), ("evseid", "17s", b"\x00" * 17), ("evsemac", "6s", b"\x00" * 6), ("runid", "Q", 0), ("rsvd1", "8s", b"\x00" * 8), ("nid", "7s", b"\x00" * 7), ("rsvd2", "B", 0), ("nmk", "16s", b"\x00" * 16), ) pevmac_s = pypacker.get_property_mac("pevmac") evsemac_s = pypacker.get_property_mac("evsemac")
class CMStartAttenCharInd(Packet): __hdr__ = ( ("apptype", "B", 0), ("sectype", "B", 0), ("numsounds", "B", 0), ("timeout", "B", 0), ("resptype", "B", 0), ("forwardingsta", "6s", b"\x00" * 6), ("runid", "Q", 0), ) forwardingsta_s = pypacker.get_property_mac("forwardingsta")
class Beacon(pypacker.Packet): __hdr__ = ( ("dst", "6s", b"\x00" * 6), ("src", "6s", b"\x00" * 6), ("bssid", "6s", b"\x00" * 6), # 12 Bits: 0->4095 | 4 Bits # SF SS (LE) ("seq_frag", "H", 0), # _ts (integer) is saved as LE ("_ts", "Q", 0), ("interval", "H", 0x6400), ("capa", "H", 0x0100), ("params", None, triggerlist.TriggerList) ) def _get_seq(self): return (self.seq_frag & 0xFF) << 4 | (self.seq_frag >> 12) def _set_seq(self, val): self.seq_frag = (val & 0xF) << 12 | (val & 0xFF0) >> 4 | (self.seq_frag & 0x0F00) def _get_ts(self): # LE->BE: dirty but simple return unpack_Q_le(pack_Q(self._ts))[0] def _set_ts(self, val): self._ts = unpack_Q_le(pack_Q(val))[0] seq = property(_get_seq, _set_seq) ts = property(_get_ts, _set_ts) dst_s = pypacker.get_property_mac("dst") bssid_s = pypacker.get_property_mac("bssid") src_s = pypacker.get_property_mac("src") def _dissect(self, buf): self._init_triggerlist("params", buf[32:], IEEE80211._unpack_ies) return len(buf) def reverse_address(self): self.dst, self.src = self.src, self.dst
class CMPKCSCertInd(Packet): """ When the CM_SLAC_PARM.CNF indicates that Secure SLAC is required, the PEV-HLE shall send a CM_PKCS_CERT.IND message. The Target MAC address for this message shall be set to MAC address of the PEV Green PHY station. To ensure reliable reception of this message at all EVSEs, it is recommended that this message be transmitted at least three times by the PEV-HLE. If the CM_PKCS_CERT.IND message is larger than 502 Octets, the message shall be fragmented by the HLE (refer to Section 11.1.7). """ __hdr__ = (("targetmac", "6s", b"\x00" * 6), ("cipersuite", "H", 0), ("certlen", "H", 0), ("certpackage", None, TriggerList)) targetmac_s = pypacker.get_property_mac("targetmac")
class LACPActorInfoTlv(pypacker.Packet): __hdr__ = ( ("type", "B", ACTOR_TYPE), ("len", "B", LACP_ACTOR_LEN), ("sysprio", "H", DEFAULT_PRIORITY), ("sys", "6s", b"\x00" * 6), ("key", "H", 0), ("portprio", "H", DEFAULT_PRIORITY), ("port", "H", 1), ("state", "B", 0), ("reserved", "3s", b"\x00" * 3), ) sys_s = pypacker.get_property_mac("sys") expired = get_property_of_state_field("expired") defaulted = get_property_of_state_field("defaulted") distribute = get_property_of_state_field("distribute") collect = get_property_of_state_field("collect") synch = get_property_of_state_field("synch") aggregate = get_property_of_state_field("aggregate") timeout = get_property_of_state_field("timeout") activity = get_property_of_state_field("activity")
class Ethernet(pypacker.Packet): __hdr__ = ( ("dst", "6s", b"\xff" * 6), ("src", "6s", b"\xff" * 6), ("vlan", None, triggerlist.TriggerList), # ("len", "H", None), ("type", "H", ETH_TYPE_IP) # type = Ethernet II, len = 802.3 ) dst_s = pypacker.get_property_mac("dst") src_s = pypacker.get_property_mac("src") def _dissect(self, buf): hlen = 14 # we need to check for VLAN TPID here (0x8100) to get correct header-length type_len = unpack_H(buf[12:14])[0] # based on the type field, following bytes can be intrepreted differently than standard Ethernet II # Examples: 802.3/802.2 LLC or 802.3/802.2 SNAP if type_len in bridge_types_set: #logger.debug(">>> got vlan tag") # support up to 2 tags (double tagging aka QinQ) # triggerlist can't be initiated using _init_triggerlist() as amount of needed bytes is not known # -> full parsing of Dot1Q-part needed for _ in range(2): vlan_tag = Dot1Q(buf[hlen - 2:hlen + 2]) if vlan_tag.type not in bridge_types_set: break # logger.debug("re-extracting field: %s" % self.vlan) self.vlan.append(vlan_tag) hlen += 4 self.type = vlan_tag.type # avoid calling unpack more than once eth_type = unpack_H(buf[hlen - 2:hlen])[0] # logger.debug("hlen is: %d" % eth_type) # handle ethernet-padding: remove it but save for later use # don't use headers for this because this is a rare situation dlen = len(buf) - hlen # data length [+ padding?] try: # this will only work on complete headers: Ethernet + IP + ... # handle padding using IPv4, IPv6 # TODO: check for other protocols # logger.debug(">>> checking for padding") if eth_type == ETH_TYPE_IP: dlen_ip = unpack_H(buf[hlen + 2:hlen + 4])[0] # real data length if dlen_ip < dlen: # padding found # logger.debug("got padding for IPv4") self._padding = buf[hlen + dlen_ip:] dlen = dlen_ip # handle padding using IPv6 # IPv6 is a piece of sh$§! payloadlength = exclusive standard header, INCLUSIVE options! elif eth_type == ETH_TYPE_IP6: dlen_ip = unpack_H(buf[hlen + 4:hlen + 6])[0] # real data length if 40 + dlen_ip < dlen: # padding found # logger.debug("got padding for IPv6") self._padding = buf[hlen + dlen_ip:] dlen = dlen_ip except struct.error: # logger.debug("could not extract padding info, assuming incomplete ethernet frame") pass except: logger.exception("could not extract padding info") self._init_handler(eth_type, buf[hlen:hlen + dlen]) return hlen def bin(self, update_auto_fields=True): """Custom bin(): handle padding for Ethernet.""" return pypacker.Packet.bin( self, update_auto_fields=update_auto_fields) + self.padding def __len__(self): return super().__len__() + len(self.padding) def direction(self, other): # logger.debug("checking direction: %s<->%s" % (self, other)) if self.dst == other.dst and self.src == other.src: # consider packet to itself: can be DIR_REV return pypacker.Packet.DIR_SAME | pypacker.Packet.DIR_REV elif (self.dst == other.src and self.src == other.dst) or\ (self.dst == b"\xff\xff\xff\xff\xff\xff" and other.dst == self.src): # broadcast return pypacker.Packet.DIR_REV else: return pypacker.Packet.DIR_UNKNOWN # handle padding attribute def __get_padding(self): try: return self._padding except AttributeError: return b"" def __set_padding(self, padding): self._padding = padding padding = property(__get_padding, __set_padding) def reverse_address(self): self.dst, self.src = self.src, self.dst
class CMLinkStatsReq(Packet): __hdr__ = (("reqtype", "B", 0), ("reqid", "B", 0), ("nid", "7s", b"\x00" * 7), ("lid", "B", 0), ("tlflag", "B", 0), ("mgmtflag", "B", 0), ("dasa", "6s", b"\x00" * 6)) dasa_s = pypacker.get_property_mac("dasa")
class CMPKCSCertCnf(Packet): __hdr__ = (("targetmac", "6s", b"\x00" * 6), ("status", "B", 0), ("cipersuite", "H", 0), ("certlen", "H", 0), ("certpackage", None, TriggerList)) targetmac_s = pypacker.get_property_mac("targetmac")
class ACK(pypacker.Packet): __hdr__ = ( ("dst", "6s", b"\x00" * 6), ) dst_s = pypacker.get_property_mac("dst")
class Ethernet(pypacker.Packet): __hdr__ = ( ("dst", "6s", b"\xff" * 6), ("src", "6s", b"\xff" * 6), ("vlan", None, triggerlist.TriggerList), # ("len", "H", None), # type = Ethernet II, len = 802.3 ("type", "H", ETH_TYPE_IP, FIELD_FLAG_AUTOUPDATE | FIELD_FLAG_IS_TYPEFIELD)) dst_s = pypacker.get_property_mac("dst") src_s = pypacker.get_property_mac("src") __handler__ = { ETH_TYPE_IP: ip.IP, ETH_TYPE_ARP: arp.ARP, ETH_TYPE_DTP: dtp.DTP, ETH_TYPE_IPX: ipx.IPX, ETH_TYPE_IP6: ip6.IP6, ETH_TYPE_PPOE_DISC: pppoe.PPPoE, ETH_TYPE_PPOE_SESS: pppoe.PPPoE, ETH_TYPE_LLC: llc.LLC, ETH_TYPE_PTPv2: ptpv2.PTPv2, ETH_TYPE_EFC: flow_control.FlowControl, ETH_TYPE_LLDP: lldp.LLDP, ETH_TYPE_SP: lacp.LACP, } def _dissect(self, buf): hlen = ETH_HDR_LEN # we need to check for VLAN TPID here (0x8100) to get correct header-length type_len = unpack_H(buf[hlen - 2:hlen])[0] # based on the type field, following bytes can be intrepreted differently # than standard Ethernet II # Examples: 802.3/802.2 LLC or 802.3/802.2 SNAP if type_len in bridge_types_set: # logger.debug(">>> got vlan tag") # support up to 2 tags (double tagging aka QinQ) # triggerlist can't be initiated using _init_triggerlist() as amount of needed bytes is not known # -> full parsing of Dot1Q-part needed for _ in range(2): vlan_tag = Dot1Q(buf[hlen - 2:hlen + 2]) if vlan_tag.type not in bridge_types_set: break # logger.debug("re-extracting field: %s" % self.vlan) self.vlan.append(vlan_tag) hlen += 4 self.type = vlan_tag.type # avoid calling unpack more than once if hlen == ETH_HDR_LEN: eth_type = type_len else: eth_type = unpack_H(buf[hlen - 2:hlen])[0] # logger.debug("eth type is: %d" % eth_type) # handle ethernet-padding: remove it but save for later use # don't use headers for this because this is a rare situation dlen = len(buf) - hlen # data length [+ padding?] try: # this will only work on complete headers: Ethernet + IP + ... # handle padding using IPv4, IPv6 etc (min size "eth + ..." = 60 bytes) # logger.debug(">>> checking for padding") if eth_type == ETH_TYPE_IP: dlen_ip = unpack_H(buf[hlen + 2:hlen + 4])[0] # real data length if dlen_ip < dlen: # padding found self._padding = buf[hlen + dlen_ip:] # logger.debug("got padding for IPv4: %r" % self._padding) dlen = dlen_ip # handle padding using IPv6 # IPv6 is a piece of sh$§! payloadlength (in header) = exclusive standard header # but INCLUSIVE options! elif eth_type == ETH_TYPE_IP6: dlen_ip = unpack_H(buf[hlen + 4:hlen + 6])[0] # real data length # logger.debug("eth.hlen=%d, data length based on header: %d" % (hlen, dlen_ip)) if 40 + dlen_ip < dlen: # padding found self._padding = buf[hlen + 40 + dlen_ip:] # logger.debug("got padding for IPv6: %r" % self._padding) dlen = 40 + dlen_ip elif eth_type == ETH_TYPE_LLDP: # this is a bit redundant as we re-parse TLV when accessing the LLDP layer dlen_lldp, _ = lldp.count_and_dissect_tlvs(buf[hlen:]) self._padding = buf[hlen + dlen_lldp:] dlen = dlen_lldp elif eth_type == ETH_TYPE_SP: lacppdu_len = 110 self._padding = buf[hlen + lacppdu_len:] dlen = lacppdu_len except Exception as ex: logger.exception( "could not extract padding info, assuming incomplete ethernet frame: %r", ex) # logger.debug("len(buf)=%d, len(upper)=%d" % (len(buf), dlen)) self._init_handler(eth_type, buf[hlen:hlen + dlen]) return hlen def bin(self, update_auto_fields=True): if update_auto_fields: self._update_bodyhandler_id() return pypacker.Packet.bin( self, update_auto_fields=update_auto_fields) + self.padding def __len__(self): return super().__len__() + len(self.padding) def direction(self, other): # logger.debug("checking direction: %s<->%s" % (self, other)) if self.dst == other.dst and self.src == other.src: # consider packet to itself: can be DIR_REV return pypacker.Packet.DIR_SAME | pypacker.Packet.DIR_REV if (self.dst == other.src and self.src == other.dst) or\ (self.dst == b"\xff\xff\xff\xff\xff\xff" and other.dst == self.src): # broadcast return pypacker.Packet.DIR_REV return pypacker.Packet.DIR_UNKNOWN # handle padding attribute def __get_padding(self): try: return self._padding except AttributeError: return b"" def __set_padding(self, padding): self._padding = padding padding = property(__get_padding, __set_padding) def reverse_address(self): self.dst, self.src = self.src, self.dst
class Ethernet(pypacker.Packet): __hdr__ = (("dst", "6s", b"\xff" * 6), ("src", "6s", b"\xff" * 6), ("vlan", None, triggerlist.TriggerList), ("type", "H", ETH_TYPE_IP, FIELD_FLAG_AUTOUPDATE | FIELD_FLAG_IS_TYPEFIELD)) dst_s = pypacker.get_property_mac("dst") src_s = pypacker.get_property_mac("src") __handler__ = { ETH_TYPE_IP: ip.IP, ETH_TYPE_ARP: arp.ARP, ETH_TYPE_DTP: dtp.DTP, ETH_TYPE_IPX: ipx.IPX, ETH_TYPE_IP6: ip6.IP6, ETH_TYPE_PPOE_DISC: pppoe.PPPoE, ETH_TYPE_PPOE_SESS: pppoe.PPPoE, ETH_TYPE_PTPv2: ptpv2.PTPv2, ETH_TYPE_EFC: flow_control.FlowControl, ETH_TYPE_LLDP: lldp.LLDP, ETH_TYPE_SP: lacp.LACP, } def _dissect(self, buf): hlen = 14 # Ethernet formats: # RFC 894 (Ethernet II) -> type = -> value >1500 # 802.[2,3] (LLC format) -> type = length field -> value <=1500, not supported eth_type = unpack_H(buf[hlen - 2:hlen])[0] # any VLAN tag present? in this case: type field is actually a vlan tag if eth_type in VLAN_TAG_START: # TODO: use _init_triggerlist() if eth_type == ETH_TYPE_8021Q: # logger.debug(">>> got vlan tag") vlan_tag = Dot1Q(buf[12:16]) self.vlan.append(vlan_tag) hlen += 4 # get real upper layer type eth_type = unpack_H(buf[16:18])[0] # 802.1ad: support up to 2 tags (double tagging aka QinQ) else: # logger.debug(">>> got vlan tag") vlan_tag1 = Dot1Q(buf[12:16]) vlan_tag2 = Dot1Q(buf[16:20]) self.vlan.extend([vlan_tag1, vlan_tag2]) hlen += 8 # get real upper layer type eth_type = unpack_H(buf[20:22])[0] # logger.debug("eth type is: %d" % eth_type) # handle ethernet-padding: remove it but save for later use # don't use headers for this because this is a rare situation dlen = len(buf) - hlen # data length [+ padding?] # assume padding only present if len(upper_layer.bin()) <= 46 if dlen <= 46: try: # this will only work on complete headers: Ethernet + IP + ... # handle padding using IPv4, IPv6 etc (min size "eth + ..." = 60 bytes) # logger.debug(">>> checking for padding") if eth_type == ETH_TYPE_IP: dlen_ip = unpack_H(buf[hlen + 2:hlen + 4])[0] # real data length if dlen_ip < dlen: # padding found self._padding = buf[hlen + dlen_ip:] # logger.debug("got padding for IPv4: %r" % self._padding) dlen = dlen_ip # handle padding using IPv6 # IPv6 is a piece of sh$§! payloadlength (in header) = exclusive standard header # but INCLUSIVE options! elif eth_type == ETH_TYPE_IP6: dlen_ip = unpack_H(buf[hlen + 4:hlen + 6])[0] # real data length # logger.debug("eth.hlen=%d, data length based on header: %d" % (hlen, dlen_ip)) if 40 + dlen_ip < dlen: # padding found self._padding = buf[hlen + 40 + dlen_ip:] # logger.debug("got padding for IPv6: %r" % self._padding) dlen = 40 + dlen_ip elif eth_type == ETH_TYPE_LLDP: # this is a bit redundant as we re-parse TLV when accessing the LLDP layer dlen_lldp, _ = lldp.count_and_dissect_tlvs(buf[hlen:]) self._padding = buf[hlen + dlen_lldp:] dlen = dlen_lldp elif eth_type == ETH_TYPE_SP: lacppdu_len = 110 self._padding = buf[hlen + lacppdu_len:] dlen = lacppdu_len except Exception as ex: logger.exception( "could not extract padding info, assuming incomplete ethernet frame: %r", ex) # logger.debug("len(buf)=%d, len(upper)=%d" % (len(buf), dlen)) self._init_handler(eth_type, buf[hlen:hlen + dlen]) return hlen def _update_fields(self): self._update_upperlayer_id() def bin(self, update_auto_fields=True): # padding needs to be placed at the very end return pypacker.Packet.bin( self, update_auto_fields=update_auto_fields) + self.padding def __len__(self): return super().__len__() + len(self.padding) def direction(self, other): # logger.debug("checking direction: %s<->%s" % (self, other)) if self.dst == other.dst and self.src == other.src: # consider packet to itself: can be DIR_REV return pypacker.Packet.DIR_SAME | pypacker.Packet.DIR_REV if (self.dst == other.src and self.src == other.dst) or\ (self.dst == b"\xff\xff\xff\xff\xff\xff" and other.dst == self.src): # broadcast return pypacker.Packet.DIR_REV return pypacker.Packet.DIR_UNKNOWN padding = pypacker.get_ondemand_property("padding", lambda: b"") def reverse_address(self): self.dst, self.src = self.src, self.dst
class Dataframe(pypacker.Packet): """ DataFrames need special care: there are too many types of field combinations to create classes for every one. Solution: initiate giving lower type "subType" via constructor. In order to use "src/dst/bssid" instead of addrX set from_to_ds of "subType" to one of the following values: [Bit 0: from DS][Bit 1: to DS] = [order of fields] 00 = 0 = dst, src, bssid 01 = 1 = bssid, src, dst 10 = 2 = dst, bssid, src 11 = 3 = RA, TA, DA, SA """ def __init__(self, *arg, **kwargs): if len(arg) > 1: # logger.debug("extracting lower layer type: %r" % arg[1]) self.dtype = arg[1] else: self.dtype = self self._from_to_ds_value = 0 #logger.debug("dstype: %r" % self.dtype.from_to_ds) super().__init__(*arg, **kwargs) __hdr__ = ( ("addr1", "6s", b"\x00" * 6), ("addr2", "6s", b"\x00" * 6), ("addr3", "6s", b"\x00" * 6), ("seq_frag", "H", 0), ("addr4", "6s", None), # to/from-DS = 1 ("qos_ctrl", "H", 0), # QoS ("sec_param", "Q", 0) # protected ) def _get_seq(self): return (self.seq_frag & 0xFF) << 4 | (self.seq_frag >> 12) def _set_seq(self, val): self.seq_frag = (val & 0xF) << 12 | (val & 0xFF0) >> 4 | (self.seq_frag & 0x0F00) seq = property(_get_seq, _set_seq) def reverse_address(self): if self.dtype.from_to_ds == 0: self.addr1, self.addr2 = self.addr2, self.addr1 elif self.dtype.from_to_ds == 1: self.addr2, self.addr3 = self.addr3, self.addr2 elif self.dtype.from_to_ds == 2: self.addr1, self.addr3 = self.addr3, self.addr1 def _get_from_to_ds(self): return self._from_to_ds_value # same property structure as in IEEE80211 class from_to_ds = property(_get_from_to_ds) # FromDs, ToDS # 00 = dst, src, bssid # 01 = bssid, src, dst # 10 = dst, bssid, src # 11 = RA, TA, DA, SA def __get_src(self): return self.addr2 if self.dtype.from_to_ds in [0, 1] else self.addr3 def __set_src(self, src): if self.dtype.from_to_ds in [0, 1]: self.addr2 = src else: self.addr3 = src def __get_dst(self): return self.addr1 if self.dtype.from_to_ds in [0, 2] else self.addr3 def __set_dst(self, dst): if self.dtype.from_to_ds in [0, 2]: self.addr1 = dst else: self.addr3 = dst def __get_bssid(self): dstype = self.dtype.from_to_ds if dstype == 0: return self.addr3 elif dstype == 1: return self.addr1 elif dstype == 2: return self.addr2 def __set_bssid(self, bssid): dstype = self.dtype.from_to_ds if dstype == 0: self.addr3 = bssid elif dstype == 1: self.addr1 = bssid elif dstype == 2: self.addr2 = bssid src = property(__get_src, __set_src) src_s = pypacker.get_property_mac("src") dst = property(__get_dst, __set_dst) dst_s = pypacker.get_property_mac("dst") bssid = property(__get_bssid, __set_bssid) bssid_s = pypacker.get_property_mac("bssid") __QOS_SUBTYPES = {8, 9, 10, 11, 12, 14, 15} def _dissect(self, buf): # logger.debug("starting dissecting, buflen: %r" % str(buf)) header_len = 30 try: is_qos = True if self.dtype.subtype in IEEE80211.Dataframe.__QOS_SUBTYPES else False is_protected = self.dtype.protected == 1 is_bridge = True if self.dtype.from_ds == 1 and self.dtype.to_ds == 1 else False except Exception: # logger.debug(e) # default is fromds is_qos = False is_protected = False is_bridge = False # logger.debug("switching fields1") if not is_qos: self.qos_ctrl = None header_len -= 2 # logger.debug("switching fields2") if not is_protected: self.sec_param = None header_len -= 8 # logger.debug("switching fields3") if is_bridge: self.addr4 = b"\x00" * 6 header_len += 6 # logger.debug("format/length/len(bin): %s/%d/%d" % (self._hdr_fmtstr, self.hdr_len, len(self.bin()))) # logger.debug("%r" % self) return header_len
class Ethernet(pypacker.Packet): __hdr__ = ( ("dst", "6s", b"\xff" * 6), ("src", "6s", b"\xff" * 6), ("vlan", "4s", None), # ("len", "H", None), ("type", "H", ETH_TYPE_IP) # type = Ethernet II, len = 802.3 ) dst_s = pypacker.get_property_mac("dst") src_s = pypacker.get_property_mac("src") def _dissect(self, buf): hlen = 14 # we need to check for VLAN TPID here (0x8100) to get correct header-length if buf[12:14] == b"\x81\x00": # logger.debug(">>> got vlan tag") self.vlan = buf[12:16] # logger.debug("re-extracting field: %s" % self.vlan) hlen = 18 # check for DSAP via length type_len = unpack(">H", buf[12:14])[0] if type_len < 1536: # assume DSAP is following (802.2 DSAP) # self.len = type_len # deactivate eth_type field # logger.debug(">>> deactivating type") self.type = None self._init_handler(ETH_TYPE_LLC, buf[12:14]) return # avoid calling unpack more than once eth_type = unpack(">H", buf[hlen - 2:hlen])[0] # logger.debug("hlen is: %d" % eth_type) # handle ethernet-padding: remove it but save for later use # don't use headers for this because this is a rare situation dlen = len(buf) - hlen # data length [+ padding?] try: # this will only work on complete headers: Ethernet + IP + ... # handle padding using IPv4, IPv6 # TODO: check for other protocols # logger.debug(">>> checking for padding") if eth_type == ETH_TYPE_IP: dlen_ip = unpack(">H", buf[hlen + 2:hlen + 4])[0] # real data length if dlen_ip < dlen: # padding found # logger.debug("got padding for IPv4") self._padding = buf[hlen + dlen_ip:] dlen = dlen_ip # handle padding using IPv6 # IPv6 is a piece of sh$§! payloadlength = exclusive standard header, INCLUSIVE options! elif eth_type == ETH_TYPE_IP6: dlen_ip = unpack(">H", buf[hlen + 4:hlen + 6])[0] # real data length if 40 + dlen_ip < dlen: # padding found # logger.debug("got padding for IPv6") self._padding = buf[hlen + dlen_ip:] dlen = dlen_ip except struct.error: # logger.debug("could not extract padding info, assuming incomplete ethernet frame") pass except: logger.exception("could not extract padding info") self._init_handler(eth_type, buf[hlen:hlen + dlen]) return hlen def bin(self, update_auto_fields=True): """Custom bin(): handle padding for Ethernet.""" return pypacker.Packet.bin( self, update_auto_fields=update_auto_fields) + self.padding def __len__(self): return super().__len__() + len(self.padding) def direction(self, other): # logger.debug("checking direction: %s<->%s" % (self, other)) if self.dst == other.dst and self.src == other.src: # consider packet to itself: can be DIR_REV return pypacker.Packet.DIR_SAME | pypacker.Packet.DIR_REV elif (self.dst == other.src and self.src == other.dst) or\ (self.dst == b"\xff\xff\xff\xff\xff\xff" and other.dst == self.src): # broadcast return pypacker.Packet.DIR_REV else: return pypacker.Packet.DIR_UNKNOWN # handle padding attribute def __get_padding(self): try: return self._padding except AttributeError: return b"" def __set_padding(self, padding): self._padding = padding padding = property(__get_padding, __set_padding) def reverse_address(self): self.dst, self.src = self.src, self.dst