class Dot1Q(pypacker.Packet): __hdr__ = ( ("type", "H", ETH_TYPE_8021Q), ("tci", "H", 0 ) # tag control information PCP(3 bits),CFI(1 bit), VID(12 bits) ) def __get_prio(self): return (self.tci & 0xE000) >> 13 def __set_prio(self, value): self.tci = (self.tci & ~0xE000) | (value << 13) prio = property(__get_prio, __set_prio) def __get_cfi(self): return (self.tci & 0x1000) >> 12 def __set_cfi(self, value): self.tci = (self.tci & ~0x1000) | (value << 12) cfi = property(__get_cfi, __set_cfi) def __get_vid(self): return self.tci & 0x0FFF def __set_vid(self, value): self.tci = self.tci & 0xF000 | value vid = property(__get_vid, __set_vid) type_t = pypacker.get_property_translator("type", "ETH_TYPE_")
class TCPOptMulti(pypacker.Packet): """ len = total length (header + data) """ __hdr__ = ( ("type", "B", 0), ("len", "B", 2, FIELD_FLAG_AUTOUPDATE) ) type_t = pypacker.get_property_translator("type", "TCP_OPT_") def _update_fields(self): if self.len_au_active: self.len = len(self)
class IP(pypacker.Packet): __hdr__ = ( ("v_hl", "B", 69, FIELD_FLAG_AUTOUPDATE), # = 0x45 ("tos", "B", 0), ("len", "H", 20, FIELD_FLAG_AUTOUPDATE), ("id", "H", 0), ("frag_off", "H", 0), ("ttl", "B", 64), ("p", "B", IP_PROTO_TCP, FIELD_FLAG_IS_TYPEFIELD), ("sum", "H", 0, FIELD_FLAG_AUTOUPDATE), ("src", "4s", b"\x00" * 4), ("dst", "4s", b"\x00" * 4), ("opts", None, triggerlist.TriggerList) ) __handler__ = { IP_PROTO_ICMP: icmp.ICMP, IP_PROTO_IGMP: igmp.IGMP, IP_PROTO_TCP: tcp.TCP, IP_PROTO_UDP: udp.UDP, IP_PROTO_IP6: ip6.IP6, IP_PROTO_ESP: esp.ESP, IP_PROTO_PIM: pim.PIM, IP_PROTO_IPXIP: ipx.IPX, IP_PROTO_SCTP: sctp.SCTP, IP_PROTO_OSPF: ospf.OSPF } UPDATE_DEPENDANTS = {tcp.TCP, udp.UDP} def __get_v(self): return self.v_hl >> 4 def __set_v(self, value): self.v_hl = (value << 4) | (self.v_hl & 0xF) # version v = property(__get_v, __set_v) def __get_hl(self): return self.v_hl & 0x0F def __set_hl(self, value): self.v_hl = (self.v_hl & 0xF0) | value # header length hl = property(__get_hl, __set_hl) def __get_flags(self): return (self.frag_off & 0xE000) >> 13 def __set_flags(self, value): self.frag_off = (self.frag_off & ~0xE000) | (value << 13) flags = property(__get_flags, __set_flags) def __get_offset(self): return self.frag_off & ~0xE000 def __set_offset(self, value): self.frag_off = (self.frag_off & 0xE000) | value offset = property(__get_offset, __set_offset) def create_fragments(self, fragment_len=1480): """ Create fragment packets from this IP packet with max fragment_len bytes each. This will set the flags and offset values accordingly (see header field off). fragment_len -- max length of a fragment (IP header + payload) return -- fragment IP packets created from this packet """ if fragment_len % 8 != 0: raise Exception("fragment_len not multipe of 8 bytes: %r" % fragment_len) fragments = [] length_ip_total = len(self.bin()) payload = self.body_bytes length_ip_header = length_ip_total - len(payload) length_payload = length_ip_total - length_ip_header off = 0 while off < length_payload: payload_sub = payload[off: off + fragment_len] ip_frag = IP(id=self.id, p=self.p, src=self.src, dst=self.dst) if length_payload - off > fragment_len: # more fragments follow ip_frag.flags = 0x1 else: # last fragment ip_frag.flags = 0x0 ip_frag.offset = int(off / 8) ip_frag.body_bytes = payload_sub fragments.append(ip_frag) off += fragment_len return fragments # Convenient access for: src[_s], dst[_s] src_s = pypacker.get_property_ip4("src") dst_s = pypacker.get_property_ip4("dst") p_t = pypacker.get_property_translator("p", "IP_PROTO_") def _dissect(self, buf): total_header_length = ((buf[0] & 0xF) << 2) options_length = total_header_length - 20 # total IHL - standard IP-len = options length if options_length > 0: # logger.debug("got some IP options: %s" % tl_opts) self._init_triggerlist("opts", buf[20: 20 + options_length], self._parse_opts) elif options_length < 0: # invalid header length: assume no options at all raise Exception() # TODO: extract real data length: # There are some cases where padding can not be identified on ethernet -> do it here (eg VSS shit trailer) self._init_handler(buf[9], buf[total_header_length:]) return total_header_length __IP_OPT_SINGLE = {IP_OPT_EOOL, IP_OPT_NOP} @staticmethod def _parse_opts(buf): """Parse IP options and return them as list.""" optlist = [] i = 0 p = None while i < len(buf): # logger.debug("got IP-option type %s" % buf[i]) if buf[i] in IP.__IP_OPT_SINGLE: p = IPOptSingle(type=buf[i]) i += 1 else: olen = buf[i + 1] # logger.debug("IPOptMulti") p = IPOptMulti(type=buf[i], len=olen, body_bytes=buf[i + 2: i + olen]) # logger.debug("body bytes: %s" % buf[i + 2: i + olen]) i += olen # typefield + lenfield + data-len # logger.debug("IPOptMulti 2") optlist.append(p) return optlist def _update_fields(self): self._update_higherlayer_id() if self.len_au_active: self.len = len(self) if self.v_hl_au_active: # Update header length. NOTE: needs to be a multiple of 4 Bytes. # logger.debug("updating: %r" % self._packet) # options length need to be multiple of 4 Bytes self.hl = int(self.header_len / 4) & 0xF if self.sum_au_active: # length changed so we have to recalculate checksum # logger.debug(">>> IP: calculating sum, current: %0X" % self.sum) # reset checksum for recalculation, mark as changed / clear cache self.sum = 0 # logger.debug(">>> IP: bytes for sum: %s" % self.header_bytes) self.sum = in_cksum(self._pack_header()) # logger.debug("IP: new hl: %d / %d" % (self._packet.hdr_len, hdr_len_off)) # logger.debug("new sum: %0X" % self.sum) def direction(self, other): # logger.debug("checking direction: %s<->%s" % (self, next)) direction = 0 if self.src == other.src and self.dst == other.dst: direction |= pypacker.Packet.DIR_SAME if self.src == other.dst and self.dst == other.src: direction |= pypacker.Packet.DIR_REV if direction == 0: direction = pypacker.Packet.DIR_UNKNOWN return direction def reverse_address(self): self.src, self.dst = self.dst, self.src
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_IS_TYPEFIELD)] dst_s = pypacker.get_property_mac("dst") src_s = pypacker.get_property_mac("src") type_t = pypacker.get_property_translator("type", "ETH_TYPE_") __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, ETH_TYPE_SLAC: slac.Slac } 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 higher 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 higher 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(higher_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: # Could not extract padding info, assuming incomplete ethernet frame. # Init of handler will take place after all. pass # logger.debug("len(buf)=%d, len(higher)=%d" % (len(buf), dlen)) self._init_handler(eth_type, buf[hlen:hlen + dlen]) return hlen def _update_fields(self): self._update_higherlayer_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 IP6(pypacker.Packet): __hdr__ = ( ("v_fc_flow", "I", 0x60000000), ("dlen", "H", 0, FIELD_FLAG_AUTOUPDATE ), # length of extension header (opts header) + body # body handler type OR type of first extension hedader (opts header) ("nxt", "B", 0), ("hlim", "B", 0), # hop limit ("src", "16s", b"\x00" * 16), ("dst", "16s", b"\x00" * 16), ("opts", None, triggerlist.TriggerList)) def __get_v(self): return self.v_fc_flow >> 28 def __set_v(self, v): self.v_fc_flow = (self.v_fc_flow & ~0xF0000000) | (v << 28) v = property(__get_v, __set_v) def __get_fc(self): return (self.v_fc_flow >> 20) & 0xFF def __set_fc(self, v): self.v_fc_flow = (self.v_fc_flow & ~0xFF00000) | (v << 20) fc = property(__get_fc, __set_fc) def __get_flow(self): return self.v_fc_flow & 0xFFFFF def __set_flow(self, v): self.v_fc_flow = (self.v_fc_flow & ~0xFFFFF) | (v & 0xFFFFF) flow = property(__get_flow, __set_flow) # Convenient access for: src[_s], dst[_s] src_s = pypacker.get_property_ip6("src") dst_s = pypacker.get_property_ip6("dst") nxt_t = pypacker.get_property_translator("nxt", "IP_PROTO_") __handler__ = { IP_PROTO_ICMP6: icmp6.ICMP6, IP_PROTO_IGMP: igmp.IGMP, IP_PROTO_TCP: tcp.TCP, IP_PROTO_UDP: udp.UDP, IP_PROTO_ESP: esp.ESP, IP_PROTO_PIM: pim.PIM, IP_PROTO_IPXIP: ipx.IPX, IP_PROTO_SCTP: sctp.SCTP, IP_PROTO_OSPF: ospf.OSPF } update_dependants = {tcp.TCP, udp.UDP} def _dissect(self, buf): type_nxt = buf[6] off = 40 opts = [] # logger.debug("type: %d buflen: %d" % (type_nxt, len(buf))) # logger.debug("parsing opts from bytes (dst: %s): (len: %d) %s" % # (buf[24:40], self.hdr_len, buf[off:])) # parse options until type is an upper layer one while type_nxt in ext_hdrs: length = 8 + buf[off + 1] * 8 # logger.debug("next type is: %s, len: %d, %r" % (type_nxt, length, buf[off:off + length])) opt = ext_hdrs_cls[type_nxt](buf[off:off + length]) opts.append(opt) type_nxt = buf[off] off += length # TODO: lazy dissect possible? self.opts.extend(opts) # IPv6 and IPv4 share same handler # There are some cases where padding can not be identified on ethernet -> do it here (eg VSS shit trailer) self._init_handler(type_nxt, buf[off:]) return off def _update_fields(self): if self.dlen_au_active: self.dlen = len(self.opts.bin()) + len(self.body_bytes) # Set type value in nxt OR in last opts element (if present) # Updating is a bit more complicated so we can't use FIELD_FLAG_IS_TYPEFIELD # idval is None if body handler is None # logger.debug("handler %r -> %r", self.__class__, self.higher_layer.__class__) idval = pypacker.Packet.get_id_for_handlerclass( self.__class__, self.higher_layer.__class__) #logger.debug("nxt will be %r", idval) if idval is not None: if len(self.opts) == 0: self.nxt = idval else: # problem if opts[-1] is immutable try: self.opts[-1].nxt = idval except: pass def direction(self, other): # logger.debug("checking direction: %s<->%s" % (self, next)) if self.src == other.src and self.dst == other.dst: # consider packet to itself: can be DIR_REV return pypacker.Packet.DIR_SAME | pypacker.Packet.DIR_REV if self.src == other.dst and self.dst == other.src: return pypacker.Packet.DIR_REV return pypacker.Packet.DIR_UNKNOWN def reverse_address(self): self.src, self.dst = self.dst, self.src
class TCPOptSingle(pypacker.Packet): __hdr__ = ( ("type", "B", 0), ) type_t = pypacker.get_property_translator("type", "TCP_OPT_")
class TCP(pypacker.Packet): __hdr__ = ( ("sport", "H", 0xDEAD), ("dport", "H", 0, FIELD_FLAG_IS_TYPEFIELD), ("seq", "I", 0xDEADBEEF), ("ack", "I", 0), ("off_x2", "B", ((5 << 4) | 0), FIELD_FLAG_AUTOUPDATE), # 10*4 Byte ("flags", "B", TH_SYN), # acces via (obj.flags & TH_XYZ) ("win", "H", TCP_WIN_MAX), ("sum", "H", 0, FIELD_FLAG_AUTOUPDATE), ("urp", "H", 0), ("opts", None, triggerlist.TriggerList) ) # 4 bits | 4 bits # offset | reserved # offset * 4 = header length def __get_off(self): return self.off_x2 >> 4 def __set_off(self, value): self.off_x2 = (value << 4) | (self.off_x2 & 0xF) off = property(__get_off, __set_off) # return real header length based on header info def __get_hlen(self): return self.off * 4 # set real header length based on header info (should be n*4) def __set_hlen(self, value): self.off = int(value / 4) hlen = property(__get_hlen, __set_hlen) flags_t = pypacker.get_property_translator("flags", "TH_", cb_get_description=cb_get_flag_description) __handler__ = { TCP_PROTO_BGP: bgp.BGP, TCP_PROTO_TELNET: telnet.Telnet, TCP_PROTO_TPKT: tpkt.TPKT, TCP_PROTO_PMAP: pmap.Pmap, TCP_PROTO_MQTT: mqtt.MQTTBase, TCP_PROTO_HTTP: http.HTTP, TCP_PROTO_SSL: ssl.SSL, TCP_PROTO_RTP: rtp.RTP, TCP_PROTO_SIP: sip.SIP } def _update_fields(self): # TCP-checksum needs to be updated on one of the following: # - this layer itself or any higher layer changed # - changes to the IP-pseudoheader update = True # update header length. NOTE: needs to be a multiple of 4 Bytes. # options length need to be multiple of 4 Bytes if self._header_changed and self.off_x2_au_active: self.off = int(self.header_len / 4) & 0xF # we need some IP as lower layer if self._lower_layer is None: return #self._update_higherlayer_id() try: # changes to IP-layer, don't mind if this isn't IP if not self._lower_layer._header_changed: # pseudoheader didn't change, further check for changes in layers update = self._changed() # logger.debug("lower layer found!") except: # Assume not an IP packet: we can't calculate the checksum # logger.debug("no lower layer found!") update = False if update and self.sum_au_active: # logger.debug(">>> updating checksum") self._calc_sum() def _dissect(self, buf): # update dynamic header parts. buf: 1010???? -clear reserved-> 1010 -> *4 ol = ((buf[12] >> 4) << 2) - 20 # dataoffset - TCP-standard length if ol > 0: # parse options, add offset-length to standard-length opts_bytes = buf[20: 20 + ol] self._init_triggerlist("opts", opts_bytes, self._parse_opts) elif ol < 0: raise Exception("invalid header length") ports = [unpack_H(buf[0:2])[0], unpack_H(buf[2:4])[0]] try: # source or destination port should match # logger.debug("TCP handler: %r" % self._id_handlerclass_dct[TCP]) htype = [x for x in ports if x in self._id_handlerclass_dct[TCP]][0] #logger.debug("TCP: trying to set handler, type: %d = %s" % #(type, self._id_handlerclass_dct[TCP][type])) self._init_handler(htype, buf[20 + ol:]) except: # no type found pass return 20 + ol __TCP_OPT_SINGLE = {TCP_OPT_EOL, TCP_OPT_NOP} @staticmethod def _parse_opts(buf): """Parse TCP options using buf and return them as List.""" optlist = [] i = 0 while i < len(buf): # logger.debug("got TCP-option type %s" % buf[i]) if buf[i] in TCP.__TCP_OPT_SINGLE: p = TCPOptSingle(type=buf[i]) i += 1 else: olen = buf[i + 1] # p = TCPOptMulti(type=buf[i], len=olen, body_bytes=buf[i + 2: i + olen]) p = TCPOptMulti(buf[i: i + olen]) i += olen # typefield + lenfield + data-len optlist.append(p) # logger.debug("tcp: parseopts finished, length: %d" % len(optlist)) return optlist def _calc_sum(self): """Recalculate the TCP-checksum. This won't reset changed state.""" # TCP and underwriting are freaky bitches: we need the IP pseudoheader # to calculate their checksum. try: # we need src/dst for checksum-calculation src, dst = self._lower_layer.src, self._lower_layer.dst self.sum = 0 # logger.debug("TCP sum recalc: IP=%d / %s / %s" % (len(src), src, dst)) tcp_bin = self.header_bytes + self.body_bytes # IP-pseudoheader, check if version 4 or 6 if len(src) == 4: s = pack_ipv4_header(src, dst, 6, len(tcp_bin)) # 6 = TCP else: s = pack_ipv6_header(src, dst, 6, len(tcp_bin)) # 6 = TCP # Get checksum of concatenated pseudoheader+TCP packet # logger.debug("pseudoheader: %r" % s) # logger.debug("tcp_bin: %r" % tcp_bin) # assign via non-shadowed variable to trigger re-packing self.sum = in_cksum(s + tcp_bin) # logger.debug(">>> new checksum: %0X" % self._sum) except: # Not an IP packet as lower layer (src, dst not present) or invalid src/dst # logger.debug("could not calculate checksum: %r" % e) pass def direction(self, other): direction = 0 # logger.debug("checking direction: %s<->%s" % (self, other)) if self.sport == other.sport and self.dport == other.dport: direction |= pypacker.Packet.DIR_SAME if self.sport == other.dport and self.dport == other.sport: direction |= pypacker.Packet.DIR_REV if direction == 0: direction = pypacker.Packet.DIR_UNKNOWN return direction def reverse_address(self): self.sport, self.dport = self.dport, self.sport ra_segments = pypacker.get_ondemand_property("ra_segments", lambda: {}) def ra_collect(self, pkt_list): """ Collect TCP segments which have the same direction as this packet. Concatenated segments can be retrieved via ra_bin(). Does not check for missing segments. return -- bytes_cnt, [True|False]: amount of bytes added (sum of body bytes), final packet found (RST or FIN). True indicates that ra_bin() can be called. """ if type(pkt_list) is not list: pkt_list = [pkt_list] bts_cnt = 0 for segment in pkt_list: if self.direction(segment) != pypacker.Packet.DIR_SAME or len(segment.body_bytes) == 0: continue seq_store = segment.seq # final packet found: connection is going to be terminated if (segment.flags & TH_FIN) != 0 or (segment.flags & TH_RST) != 0: return 0, True if seq_store < self.seq: logger.warning("seq of new segment is lower than start") seq_store += 0xFFFF #logger.debug("adding tcp segment: %r", segment.body_bytes) self.ra_segments[seq_store] = segment.body_bytes bts_cnt += len(segment.body_bytes) return bts_cnt, False def ra_bin(self): """ Assemble retrieved TCP segments in sorted order (body bytes of TCP segments). Does NOT flush the internal buffer; this is done via self.ra_segments.clear() """ self.ra_segments[self.seq] = self.body_bytes sorted_list = sorted(self.ra_segments.items(), key=lambda t: t[0]) bts_lst = [value for key, value in sorted_list] self.ra_segments.clear() return b"".join(bts_lst)
class ICMP(pypacker.Packet): __hdr__ = ( ("type", "B", ICMP_ECHO, FIELD_FLAG_IS_TYPEFIELD), ("code", "B", 0), ("sum", "H", 0, FIELD_FLAG_AUTOUPDATE) ) type_t = pypacker.get_property_translator("type", "ICMP_") def _update_fields(self): # logger.debug("sum is: %d" % self.sum) if self.sum_au_active and self._changed(): # logger.debug("sum is: %d" % self.sum) # logger.debug("header: %r", self.header_bytes) # logger.debug("body: %r", self.body_bytes) self.sum = 0 self.sum = checksum.in_cksum(self.header_bytes + self.body_bytes) # logger.debug("sum is: %d" % self.sum) def _dissect(self, buf): # logger.debug("ICMP: adding fields for type: %d" % buf[0]) self._init_handler(buf[0], buf[4:]) return 4 class Echo(pypacker.Packet): __hdr__ = ( ("id", "H", 0), ("seq", "H", 1), ("ts", "Q", 0) ) def _dissect(self, buf): hlen = 12 if len(buf) < 12: # not enough bytes for ts self.ts = None hlen = 4 return hlen class Unreach(pypacker.Packet): __hdr__ = ( ("pad", "I", 0), ) CODE_UNREACH_NET = 0 # bad net CODE_UNREACH_HOST = 1 # bad host CODE_UNREACH_PROTO = 2 # bad protocol CODE_UNREACH_PORT = 3 # bad port CODE_UNREACH_NEEDFRAG = 4 # IP_DF caused drop CODE_UNREACH_SRCFAIL = 5 # src route failed CODE_UNREACH_NET_UNKNOWN = 6 # unknown net CODE_UNREACH_HOST_UNKNOWN = 7 # unknown host CODE_UNREACH_ISOLATED = 8 # src host isolated CODE_UNREACH_NET_PROHIB = 9 # for crypto devs CODE_UNREACH_HOST_PROHIB = 10 # ditto CODE_UNREACH_TOSNET = 11 # bad tos for net CODE_UNREACH_TOSHOST = 12 # bad tos for host CODE_UNREACH_FILTER_PROHIB = 13 # prohibited access CODE_UNREACH_HOST_PRECEDENCE = 14 # precedence error CODE_UNREACH_PRECEDENCE_CUTOFF = 15 # precedence cutoff class Quench(pypacker.Packet): __hdr__ = ( ("pad", "I", 0), ) class Redirect(pypacker.Packet): __hdr__ = ( ("gw", "I", 0), ) CODE_REDIRECT_NET = 0 # for network CODE_REDIRECT_HOST = 1 # for host CODE_REDIRECT_TOSNET = 2 # for tos and net CODE_REDIRECT_TOSHOST = 3 # for tos and host class RouterAdvertisement(pypacker.Packet): __hdr__ = ( ("numaddr", "B", 0), ("addrsize", "B", 0), ("lifetime", "H", 0) ) CODE_RTRADVERT_NORMAL = 0 # normal CODE_RTRADVERT_NOROUTE_COMMON = 16 # selective routing CODE_RTRSOLICIT = 10 # router solicitation class RouterSelection(pypacker.Packet): __hdr__ = ( ("numaddr", "B", 0), ("addrsize", "B", 0), ("lifetime", "H", 0) ) class TimeExceed(pypacker.Packet): __hdr__ = ( ("pad", "I", 0), ) CODE_TIMEXCEED_INTRANS = 0 # ttl==0 in transit CODE_TIMEXCEED_REASS = 1 # ttl==0 in reass class ParamProblem(pypacker.Packet): __hdr__ = ( ("pointer", "B", 0), ("unused", "3s", b"\x00" * 3) ) CODE_PARAMPROB_ERRATPTR = 0 # req. opt. absent CODE_PARAMPROB_OPTABSENT = 1 # req. opt. absent CODE_PARAMPROB_LENGTH = 2 # bad length class Photuris(pypacker.Packet): class ParamProblem(pypacker.Packet): __hdr__ = ( ("reserved", "H", 0), ("pointer", "H", 0) ) CODE_PHOTURIS_UNKNOWN_INDEX = 0 # unknown sec index CODE_PHOTURIS_AUTH_FAILED = 1 # auth failed CODE_PHOTURIS_DECOMPRESS_FAILED = 2 # decompress failed CODE_PHOTURIS_DECRYPT_FAILED = 3 # decrypt failed CODE_PHOTURIS_NEED_AUTHN = 4 # no authentication CODE_PHOTURIS_NEED_AUTHZ = 5 # no authorization __handler__ = { (ICMP_ECHO, ICMP_ECHO_REPLY): Echo, ICMP_UNREACH: Unreach, ICMP_SRCQUENCH: Quench, ICMP_REDIRECT: Redirect, ICMP_RTRADVERT: RouterAdvertisement, ICMP_RTRSEL: RouterSelection, ICMP_TIMEXCEED: TimeExceed, ICMP_PARAMPROB: ParamProblem, ICMP_PHOTURIS: Photuris }